diff --git a/example/example_data/provisioning_message_generator b/example/example_data/provisioning_message_generator index d0c227d..8de43d6 100755 Binary files a/example/example_data/provisioning_message_generator and b/example/example_data/provisioning_message_generator differ diff --git a/libprovisioning_sdk.so b/libprovisioning_sdk.so index 8ad3e95..5a2a549 100755 Binary files a/libprovisioning_sdk.so and b/libprovisioning_sdk.so differ diff --git a/protos/public/client_identification.proto b/protos/public/client_identification.proto index 01680b2..00a9b39 100644 --- a/protos/public/client_identification.proto +++ b/protos/public/client_identification.proto @@ -61,6 +61,8 @@ message ClientIdentification { optional uint32 license_counter = 5; // List of non-baseline client capabilities. optional ClientCapabilities client_capabilities = 6; + // Serialized VmpData message. Optional. + optional bytes vmp_data = 7; } // EncryptedClientIdentification message used to hold ClientIdentification diff --git a/provisioning_sdk/public/provisioning_status.h b/provisioning_sdk/public/provisioning_status.h index 857a99a..40ae323 100644 --- a/provisioning_sdk/public/provisioning_status.h +++ b/provisioning_sdk/public/provisioning_status.h @@ -16,20 +16,21 @@ enum ProvisioningStatus { // Invalid provisioning private key or private key passphrase. INVALID_PROVISIONING_PRIVATE_KEY = 6, INVALID_INTERMEDIATE_DRM_CERTIFICATE = 7, + INVALID_INTERMEDIATE_PUBLIC_KEY = 8, // Invalid intermediate private key or private key passphrase. - INVALID_INTERMEDIATE_PRIVATE_KEY = 8, - INVALID_STATUS_LIST = 9, - STATUS_LIST_EXPIRED = 10, - UNKNOWN_SYSTEM_ID = 11, - INVALID_DEVICE_PUBLIC_KEY = 12, - INVALID_DEVICE_PRIVATE_KEY = 13, - INVALID_REQUEST_MESSAGE = 14, - INVALID_MAC = 15, - MISSING_DRM_INTERMEDIATE_CERT = 16, - DRM_DEVICE_CERTIFICATE_NOT_SET = 17, - DEVICE_REVOKED = 18, - INVALID_SERIAL_NUMBER = 19, - INTERNAL_ERROR = 20, + INVALID_INTERMEDIATE_PRIVATE_KEY = 9, + INVALID_STATUS_LIST = 10, + STATUS_LIST_EXPIRED = 11, + UNKNOWN_SYSTEM_ID = 12, + INVALID_DEVICE_PUBLIC_KEY = 13, + INVALID_DEVICE_PRIVATE_KEY = 14, + INVALID_REQUEST_MESSAGE = 15, + INVALID_MAC = 16, + MISSING_DRM_INTERMEDIATE_CERT = 17, + DRM_DEVICE_CERTIFICATE_NOT_SET = 18, + DEVICE_REVOKED = 19, + INVALID_SERIAL_NUMBER = 20, + INTERNAL_ERROR = 21, NUM_PROVISIONING_STATUS, }; diff --git a/provisioning_sdk/public/python/crypto_utility.py b/provisioning_sdk/public/python/crypto_utility.py new file mode 100644 index 0000000..b337121 --- /dev/null +++ b/provisioning_sdk/public/python/crypto_utility.py @@ -0,0 +1,17 @@ +"""Utility functions for cryptography.""" + +from cryptography.hazmat import backends +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import padding + + +def VerifySignature(public_key, signature, data): + hash_algorithm = hashes.SHA1() + salt_len = 20 + + key = serialization.load_der_public_key( + public_key, backend=backends.default_backend()) + key.verify(signature, data, + padding.PSS(padding.MGF1(hash_algorithm), salt_len), + hash_algorithm) diff --git a/provisioning_sdk/public/python/engine_generate_certificate_test.py b/provisioning_sdk/public/python/engine_generate_certificate_test.py new file mode 100644 index 0000000..fb1fddf --- /dev/null +++ b/provisioning_sdk/public/python/engine_generate_certificate_test.py @@ -0,0 +1,56 @@ +import unittest + +import crypto_utility +import pywrapprovisioning_engine +import pywrapprovisioning_status +import test_data_utility +from protos.public import signed_device_certificate_pb2 + + +class EngineGenerateCertificateTest(unittest.TestCase): + + def setUp(self): + self._engine = pywrapprovisioning_engine.ProvisioningEngine() + test_data_utility.InitProvisionEngineWithTestData( + self._engine, verify_success=True) + test_data_utility.SetCertificateStatusListWithTestData( + self._engine, 0, verify_success=True) + test_data_utility.AddDrmIntermediateCertificateWithTestData( + self._engine, 2001, verify_success=True) + + def testSuccess(self): + status, signed_cert_string = self._engine.GenerateDeviceDrmCertificate( + 2001, test_data_utility.DEVICE_PUBLIC_KEY, 'DEVICE_SERIAL_NUMBER') + self.assertEqual(pywrapprovisioning_status.OK, status) + + signed_cert = signed_device_certificate_pb2.SignedDrmDeviceCertificate() + signed_cert.ParseFromString(signed_cert_string) + crypto_utility.VerifySignature(test_data_utility.CA_PUBLIC_KEY, + signed_cert.signature, + signed_cert.drm_certificate) + + def testEmptySerialNumber(self): + status, _ = self._engine.GenerateDeviceDrmCertificate( + 2001, test_data_utility.DEVICE_PUBLIC_KEY, '') + self.assertEqual(pywrapprovisioning_status.INVALID_SERIAL_NUMBER, status) + + def testEmptyPublicKey(self): + status, _ = self._engine.GenerateDeviceDrmCertificate( + 2001, '', 'DEVICE_SERIAL_NUMBER') + self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY, + status) + + def testInvalidPublicKey(self): + status, _ = self._engine.GenerateDeviceDrmCertificate( + 2001, 'PUBLIC_KEY_MUST_BE_IN_DER_ENCODED_PKCS1_FORMAT', + 'DEVICE_SERIAL_NUMBER') + self.assertEqual(pywrapprovisioning_status.INVALID_DEVICE_PUBLIC_KEY, + status) + + def testMissingIntermediateCertificate(self): + status, _ = self._engine.GenerateDeviceDrmCertificate( + 2002, test_data_utility.DEVICE_PUBLIC_KEY, 'DEVICE_SERIAL_NUMBER') + self.assertEqual(pywrapprovisioning_status.DEVICE_REVOKED, status) + +if __name__ == '__main__': + unittest.main() diff --git a/provisioning_sdk/public/python/new_session_test.py b/provisioning_sdk/public/python/new_session_test.py index f8eab05..c1e1106 100644 --- a/provisioning_sdk/public/python/new_session_test.py +++ b/provisioning_sdk/public/python/new_session_test.py @@ -1,9 +1,6 @@ import unittest -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import padding -from cryptography.hazmat.primitives.serialization import load_der_public_key - +import crypto_utility import pywrapprovisioning_engine import pywrapprovisioning_status import test_data_utility @@ -79,12 +76,12 @@ class NewSessionTest(unittest.TestCase): session_status) def _VerifyMessageSignature(self, public_key, signed_response): - self._VerifySignature(public_key, signed_response.signature, - signed_response.message) + crypto_utility.VerifySignature(public_key, signed_response.signature, + signed_response.message) def _VerifyCertSignature(self, public_key, signed_cert): - self._VerifySignature(public_key, signed_cert.signature, - signed_cert.drm_certificate) + crypto_utility.VerifySignature(public_key, signed_cert.signature, + signed_cert.drm_certificate) def _VerifyProvisioningResponse(self, request, response): self.assertEqual(request.nonce, response.nonce) @@ -94,14 +91,5 @@ class NewSessionTest(unittest.TestCase): self._VerifyCertSignature(test_data_utility.CA_PUBLIC_KEY, signed_cert) - def _VerifySignature(self, public_key, signature, data): - key = load_der_public_key(public_key, backend=default_backend()) - key.verify(signature, data, - padding.PSS( - padding.MGF1(test_data_utility.HASH_ALGORITHM), - test_data_utility.SALT_LEN), - test_data_utility.HASH_ALGORITHM) - - if __name__ == '__main__': unittest.main() diff --git a/provisioning_sdk/public/python/provisioning_status.i b/provisioning_sdk/public/python/provisioning_status.i index e110d28..ede3558 100644 --- a/provisioning_sdk/public/python/provisioning_status.i +++ b/provisioning_sdk/public/python/provisioning_status.i @@ -27,6 +27,7 @@ %unignore widevine::INVALID_REQUEST_MESSAGE; %unignore widevine::MISSING_DRM_INTERMEDIATE_CERT; %unignore widevine::DEVICE_REVOKED; +%unignore widevine::INVALID_SERIAL_NUMBER; %unignore widevine::GetProvisioningStatusMessage; %include "provisioning_sdk/public/provisioning_status.h" diff --git a/provisioning_sdk/public/python/setup.py b/provisioning_sdk/public/python/setup.py index 84b2ed9..c3ccb17 100644 --- a/provisioning_sdk/public/python/setup.py +++ b/provisioning_sdk/public/python/setup.py @@ -2,8 +2,7 @@ import os -from distutils.core import Extension -from distutils.core import setup +from distutils import core OUT_DIRNAME = 'test_genfiles' @@ -26,7 +25,7 @@ SDK_LIBRARY_DIR = os.path.join(SDK_ROOT_DIR, 'bazel-bin', 'provisioning_sdk', def ProvisioningSwigExtension(extension_name): - return Extension( + return core.Extension( name=SWIG_CONFIG_MODULE_PATH % ('_pywrap' + extension_name), sources=[SWIG_CONFIG_FILE % extension_name], include_dirs=[SDK_ROOT_DIR], @@ -39,7 +38,7 @@ def ProvisioningSwigExtension(extension_name): if __name__ == '__main__': os.chdir(SDK_ROOT_DIR) - setup( + core.setup( name='provisioning_sdk', ext_modules=[ ProvisioningSwigExtension('certificate_type'), diff --git a/provisioning_sdk/public/python/test_data_utility.py b/provisioning_sdk/public/python/test_data_utility.py index 89f9124..5203ae7 100644 --- a/provisioning_sdk/public/python/test_data_utility.py +++ b/provisioning_sdk/public/python/test_data_utility.py @@ -2,15 +2,10 @@ import os -from cryptography.hazmat.primitives import hashes - import pywrapcertificate_type import pywrapprovisioning_status from protos.public import certificate_provisioning_pb2 -HASH_ALGORITHM = hashes.SHA1() -SALT_LEN = 20 - TEST_DATA_FOLDER = os.path.join('example', 'example_data') diff --git a/run_tests.sh b/run_tests.sh index 57670b6..34003ec 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -26,7 +26,7 @@ protoc -I="$(pwd)" --python_out="$(pwd)/test_genfiles" "$(pwd)/protos/public/pro protoc -I="$(pwd)" --python_out="$(pwd)/test_genfiles" "$(pwd)/protos/public/certificate_provisioning.proto" protoc -I="$(pwd)" --python_out="$(pwd)/test_genfiles" "$(pwd)/protos/public/signed_device_certificate.proto" -cp provisioning_sdk/public/python/* test_genfiles/ +cp -a provisioning_sdk/public/python/* test_genfiles/ cd test_genfiles python setup.py build_ext --inplace @@ -38,4 +38,5 @@ done; python init_engine_test.py python set_certificate_status_list_test.py python drm_intermediate_certificate_test.py +python engine_generate_certificate_test.py python new_session_test.py