diff --git a/oem_certificate_generator/oem_certificate.py b/oem_certificate_generator/oem_certificate.py old mode 100644 new mode 100755 index 8d17c98..71e7789 --- a/oem_certificate_generator/oem_certificate.py +++ b/oem_certificate_generator/oem_certificate.py @@ -1,3 +1,4 @@ +#!/usr/bin/python3 # Copyright 2017 Google LLC. All Rights Reserved. """OEM certificate generation tool. @@ -110,7 +111,7 @@ class X509CertificateChain(object): x509_stack = pkcs7.d.sign.cert certificates = [] - for i in xrange(backend._lib.sk_X509_num(x509_stack)): + for i in range(backend._lib.sk_X509_num(x509_stack)): x509_value = backend._ffi.gc( backend._lib.X509_dup(backend._lib.sk_X509_value(x509_stack, i)), backend._lib.X509_free) @@ -134,6 +135,10 @@ class X509CertificateChain(object): return backend._read_mem_bio(bio) +# Type for argparse to accept byte buffers on the command line +def utf8_bytes(utf8_str): + return utf8_str.encode('utf-8') + def _multiple_of_1024(key_size_str): """argparse custom type function for key size.""" key_size = int(key_size_str) @@ -299,9 +304,9 @@ def generate_leaf_certificate(args): def secure_erase(args): """Subparser handler for secure erasing of a file.""" length = args.file.tell() - for _ in xrange(args.passes): + for _ in range(args.passes): args.file.seek(0) - for _ in xrange(length): + for _ in range(length): args.file.write(os.urandom(1)) args.file.close() os.remove(args.file.name) @@ -403,6 +408,7 @@ def create_parser(): '--output_private_key_file', type=argparse.FileType('wb'), required=True) parser_csr.add_argument( '--passphrase', + type=utf8_bytes, help=('specify an optional passphrase to encrypt the private key. The ' 'private key is not encrypted if omitted.')) parser_csr.set_defaults(func=generate_csr) @@ -429,7 +435,7 @@ def create_parser(): '--root_certificate_file', type=argparse.FileType('rb'), required=True) parser_intermediate_cert.add_argument( '--root_private_key_file', type=argparse.FileType('rb'), required=True) - parser_intermediate_cert.add_argument('--root_private_key_passphrase') + parser_intermediate_cert.add_argument('--root_private_key_passphrase', type=utf8_bytes) parser_intermediate_cert.add_argument( '--output_certificate_file', type=argparse.FileType('wb'), required=True) parser_intermediate_cert.set_defaults(func=generate_intermediate_certificate) @@ -460,13 +466,14 @@ def create_parser(): '--intermediate_private_key_file', type=argparse.FileType('rb'), required=True) - parser_leaf_cert.add_argument('--intermediate_private_key_passphrase') + parser_leaf_cert.add_argument('--intermediate_private_key_passphrase', type=utf8_bytes) parser_leaf_cert.add_argument( '--output_certificate_file', type=argparse.FileType('wb'), required=True) parser_leaf_cert.add_argument( '--output_private_key_file', type=argparse.FileType('wb'), required=True) parser_leaf_cert.add_argument( '--passphrase', + type=utf8_bytes, help=('specify an optional passphrase to encrypt the private key. The ' 'private key is not encrypted if omitted.')) parser_leaf_cert.set_defaults(func=generate_leaf_certificate) @@ -497,7 +504,7 @@ def main(): args = sys.argv[1:] config_file_name = 'oem_certificate.cfg' if os.path.isfile(config_file_name): - print 'Load from args default configuration file: ', config_file_name + print('Load from args default configuration file: ', config_file_name) args.append('@' + config_file_name) parser_args = create_parser().parse_args(args) parser_args.func(parser_args) diff --git a/oem_certificate_generator/oem_certificate_test_helper.py b/oem_certificate_generator/oem_certificate_test_helper.py index eccb125..75de4ae 100644 --- a/oem_certificate_generator/oem_certificate_test_helper.py +++ b/oem_certificate_generator/oem_certificate_test_helper.py @@ -1,9 +1,10 @@ +#!/usr/bin/python3 # Copyright 2017 Google LLC. All Rights Reserved. """Common test utility functions for OEM certificate generation.""" import datetime -import StringIO +import io from cryptography import x509 from cryptography.hazmat import backends @@ -24,7 +25,7 @@ _NOT_VALID_BEFORE = datetime.datetime(2001, 8, 9) _VALID_DURATION = 100 _LEAF_CERT_VALID_DURATION = 8000 _SYSTEM_ID = 2001 -_ROOT_PRIVATE_KEY_PASSPHRASE = 'root_passphrase' +_ROOT_PRIVATE_KEY_PASSPHRASE = b'root_passphrase' class ArgParseObject(object): @@ -67,11 +68,11 @@ def setup_csr_args(country_name=_COUNTRY_NAME, if output_csr_file: args.output_csr_file = output_csr_file else: - args.output_csr_file = StringIO.StringIO() + args.output_csr_file = io.BytesIO() if output_private_key_file: args.output_private_key_file = output_private_key_file else: - args.output_private_key_file = StringIO.StringIO() + args.output_private_key_file = io.BytesIO() args.passphrase = passphrase return args @@ -86,12 +87,12 @@ def setup_intermediate_cert_args( args.not_valid_before = not_valid_before args.valid_duration = valid_duration args.system_id = system_id - args.csr_file = StringIO.StringIO(csr_bytes) + args.csr_file = io.BytesIO(csr_bytes) args.root_private_key_passphrase = root_private_key_passphrase if output_certificate_file: args.output_certificate_file = output_certificate_file else: - args.output_certificate_file = StringIO.StringIO() + args.output_certificate_file = io.BytesIO() serialized_private_key = root_key.private_bytes( serialization.Encoding.DER, @@ -100,8 +101,8 @@ def setup_intermediate_cert_args( args.root_private_key_passphrase)) serialized_certificate = root_certificate.public_bytes( serialization.Encoding.DER) - args.root_certificate_file = StringIO.StringIO(serialized_certificate) - args.root_private_key_file = StringIO.StringIO(serialized_private_key) + args.root_certificate_file = io.BytesIO(serialized_certificate) + args.root_private_key_file = io.BytesIO(serialized_private_key) return args @@ -122,16 +123,16 @@ def setup_leaf_cert_args(intermediate_key_bytes, if output_certificate_file: args.output_certificate_file = output_certificate_file else: - args.output_certificate_file = StringIO.StringIO() + args.output_certificate_file = io.BytesIO() if output_private_key_file: args.output_private_key_file = output_private_key_file else: - args.output_private_key_file = StringIO.StringIO() + args.output_private_key_file = io.BytesIO() args.passphrase = passphrase - args.intermediate_private_key_file = StringIO.StringIO( + args.intermediate_private_key_file = io.BytesIO( intermediate_key_bytes) - args.intermediate_certificate_file = StringIO.StringIO( + args.intermediate_certificate_file = io.BytesIO( intermediate_certificate_bytes) return args diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index 36ccaae..b933ce1 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -3,7 +3,7 @@ // License Agreement. /** - * @mainpage OEMCrypto API + * @mainpage OEMCrypto API v17 * * OEMCrypto is the low level library implemented by the OEM to provide key and * content protection, usually in a separate secure memory or process space. The @@ -103,6 +103,17 @@ * provisioning procedure and implemented in the library, but are not called * from the Widevine DRM Plugin during normal operation. * + * @defgroup prov40 OEM Certificate and Provisioning 4.0 API + * Functions that are needed process a boot chain certificate. + * + * The OEMCrypto API allows for a device to be initially provisioned with a + * keybox or with an OEM certificate in the factory, or to use a boot chain + * derived by the device using a device specific key. + * See the section Provisioning + * in the integration guide. + * The functions in this section are for devices that are provisioned with a + * boot chain, i.e. Provisioning 4.0. + * * @defgroup validation Validation and Feature Support API * The OEMCrypto API is flexible enough to allow different devices to support * different features. This section has functions that specify the level of @@ -126,10 +137,9 @@ * * @defgroup test_verify Test and Verification API * Functions that are designed to help test OEMCrypto and the device. They are - * not used during normal operation. Some functions, like OEMCrypto_RemoveSRM() - * should only be implemented on test devices. Other functions, like those that - * test the full decrypt data path may be supported on a production device with - * no added risk of security loss. + * not used during normal operation. Some functions, like those that test the + * full decrypt data path may be supported on a production device with no added + * risk of security loss. * * The following functions are used just for testing and verification of * OEMCrypto and the CDM code. @@ -210,17 +220,17 @@ typedef enum OEMCryptoBufferType { * this instance of the structure. [variant] clear: This variant is valid * when the type is OEMCrypto_BufferType_Clear. This OEMCrypto_DestBufferDesc * indicates output should be written to a clear buffer. - * @param[in] address: A pointer to the address in memory to begin writing + * @param[in] clear_buffer: A pointer to the address in memory to begin writing * output. - * @param[in] address_length: The length of the buffer that is available to + * @param[in] clear_buffer_length: The length of the buffer that is available to * contain output. [variant] secure: This variant is valid when the type is * OEMCrypto_BufferType_Secure. This OEMCrypto_DestBufferDesc indicates * output should be written to a secure buffer. The decrypted output must * never leave the secure area until it is output from the device. - * @param[in] handle: An opaque handle to a secure buffer. The meaning of this - * handle is platform-specific. - * @param[in] handle_length: The length of the data contained in the secure - * buffer. + * @param[in] secure_buffer: An opaque handle to a secure buffer. The meaning of + * this handle is platform-specific. + * @param[in] secure_buffer_length: The length of the data contained in the + * secure buffer. * @param[in] offset: An offset indicating where in the secure buffer to start * writing data. [variant] direct: This variant is valid when the type is * OEMCrypto_BufferType_Direct. This OEMCrypto_DestBufferDesc indicates @@ -236,12 +246,12 @@ typedef struct { OEMCryptoBufferType type; union { struct { // type == OEMCrypto_BufferType_Clear - OEMCrypto_SharedMemory* address; - size_t address_length; + OEMCrypto_SharedMemory* clear_buffer; + size_t clear_buffer_length; } clear; struct { // type == OEMCrypto_BufferType_Secure - void* handle; - size_t handle_length; + void* secure_buffer; + size_t secure_buffer_length; size_t offset; } secure; struct { // type == OEMCrypto_BufferType_Direct @@ -349,13 +359,21 @@ typedef struct { } OEMCrypto_CENCEncryptPatternDesc; /** - * OEMCryptoCipherMode is used in SelectKey to prepare a key for either CTR - * decryption or CBC decryption. + * OEMCryptoCipherMode is used in SelectKey to prepare a key for decryption. */ typedef enum OEMCryptoCipherMode { + // explicit cipher modes used for modular DRM + OEMCrypto_CipherMode_CENC, + OEMCrypto_CipherMode_CBCS, + // cipher modes used for CAS OEMCrypto_CipherMode_CTR, OEMCrypto_CipherMode_CBC, - OEMCrypto_CipherMode_MaxValue = OEMCrypto_CipherMode_CBC, + OEMCrypto_CipherMode_CSA2, + OEMCrypto_CipherMode_CSA3, + OEMCrypto_CipherMode_OFB, + OEMCrypto_CipherMode_SCTE, + OEMCrypto_CipherMode_ECB, + OEMCrypto_CipherMode_MaxValue = OEMCrypto_CipherMode_ECB, } OEMCryptoCipherMode; /** @@ -364,21 +382,21 @@ typedef enum OEMCryptoCipherMode { * padding. * @param entitlement_key_id: entitlement key id to be matched to key table. - * @param entitlement_key_id_length: length of entitlment_key_id in bytes (1 to - * 16). * @param content_key_id: content key id to be loaded into key table. - * @param content_key_id_length: length of content key id in bytes (1 to 16). * @param key_data_iv: the IV for performing AES-256-CBC decryption of the key * data. * @param key_data: encrypted content key data. - * @param key_data_length: length of key_data: 16 or 32 depending on intended us - e. + * @param content_iv: the IV for decrypting media content. Used by CAS only. + * @param cipher_mode: the encryption mode of the media content. Used by CAS + * only. */ typedef struct { OEMCrypto_Substring entitlement_key_id; OEMCrypto_Substring content_key_id; OEMCrypto_Substring content_key_data_iv; OEMCrypto_Substring content_key_data; + OEMCrypto_Substring content_iv; + OEMCryptoCipherMode cipher_mode; } OEMCrypto_EntitledContentKeyObject; /** @@ -454,7 +472,8 @@ typedef struct { */ typedef enum OEMCrypto_Clock_Security_Level { kInsecureClock = 0, - kSecureTimer = 1, + kMonotonicClock = 1, + kSecureTimer = 1, // DEPRECATED. Do not use. kSecureClock = 2, kHardwareSecureClock = 3 } OEMCrypto_Clock_Security_Level; @@ -474,26 +493,56 @@ typedef uint8_t RSA_Padding_Scheme; * level, and in GetHDCPCapability for reporting. */ typedef enum OEMCrypto_HDCP_Capability { - HDCP_NONE = 0, // No HDCP supported, no secure data path. - HDCP_V1 = 1, // HDCP version 1.x - HDCP_V2 = 2, // HDCP version 2.0 Type 1. - HDCP_V2_1 = 3, // HDCP version 2.1 Type 1. - HDCP_V2_2 = 4, // HDCP version 2.2 Type 1. - HDCP_V2_3 = 5, // HDCP version 2.3 Type 1. + HDCP_NONE = 0, // No HDCP supported, no secure data path. + HDCP_V1 = 1, // HDCP version 1.x + HDCP_V2 = 2, // HDCP version 2.0 Type 1. + HDCP_V2_1 = 3, // HDCP version 2.1 Type 1. + HDCP_V2_2 = 4, // HDCP version 2.2 Type 1. + HDCP_V2_3 = 5, // HDCP version 2.3 Type 1. + // For backwards compatibility, these values are added after the V2 fields. + // However, it is optional for devices and they can still report HDCP_V1. + HDCP_V1_0 = 6, + HDCP_V1_1 = 7, + HDCP_V1_2 = 8, + HDCP_V1_3 = 9, + HDCP_V1_4 = 10, HDCP_NO_DIGITAL_OUTPUT = 0xff // No digital output. } OEMCrypto_HDCP_Capability; +/** + * OEMCrypto_DTCP2_Capability is used in OEMCrypto_GetDTCP2Capability + * for reporting the level of DTCP2 support for a device. + */ +typedef enum OEMCrypto_DTCP2_Capability { + OEMCrypto_NO_DTCP2 = 0, // DTCP2 is not supported. + OEMCrypto_DTCP2_V1 = 1, // At least v1 of DTCP2 is supported. +} OEMCrypto_DTCP2_Capability; + /** Return value for OEMCrypto_GetProvisioningMethod(). */ typedef enum OEMCrypto_ProvisioningMethod { OEMCrypto_ProvisioningError = 0, // Device cannot be provisioned. - OEMCrypto_DrmCertificate = 1, // Device has baked in DRM certificate - // (level 3 only) - OEMCrypto_Keybox = 2, // Device has factory installed unique keybox. - OEMCrypto_OEMCertificate = 3 // Device has factory installed OEM certificate. + // Device has baked in DRM certificate (level 3 only). + OEMCrypto_DrmCertificate = 1, + // Device has factory installed unique keybox. + OEMCrypto_Keybox = 2, + // Device has factory installed OEM certificate. + OEMCrypto_OEMCertificate = 3, + // Device has Boot Certificate Chain (BCC). + OEMCrypto_BootCertificateChain = 4 } OEMCrypto_ProvisioningMethod; +/** + Return value for OEMCrypto_GetWatermarkingSupport(). + */ +typedef enum OEMCrypto_WatermarkingSupport { + OEMCrypto_WatermarkingError = 0, + OEMCrypto_WatermarkingNotSupported = 1, + OEMCrypto_WatermarkingConfigurable = 2, + OEMCrypto_WatermarkingAlwaysOn = 3, +} OEMCrypto_WatermarkingSupport; + /** * Flags indicating public/private key types supported. */ @@ -558,7 +607,7 @@ typedef enum OEMCrypto_ProvisioningMethod { #define OEMCrypto_GenerateRSASignature_V8 _oecc20 #define OEMCrypto_DeriveKeysFromSessionKey _oecc21 #define OEMCrypto_APIVersion _oecc22 -#define OEMCrypto_SecurityLevel _oecc23 +#define OEMCrypto_SecurityLevel_V16 _oecc23 #define OEMCrypto_Generic_Encrypt _oecc24 #define OEMCrypto_Generic_Decrypt _oecc25 #define OEMCrypto_Generic_Sign _oecc26 @@ -615,9 +664,9 @@ typedef enum OEMCrypto_ProvisioningMethod { #define OEMCrypto_InitializeDecryptHash _oecc87 #define OEMCrypto_SetDecryptHash _oecc88 #define OEMCrypto_GetHashErrorCode _oecc89 -#define OEMCrypto_BuildInformation _oecc90 +#define OEMCrypto_BuildInformation_V16 _oecc90 #define OEMCrypto_RefreshKeys _oecc91 -#define OEMCrypto_LoadEntitledContentKeys _oecc92 +#define OEMCrypto_LoadEntitledContentKeys_V16 _oecc92 #define OEMCrypto_CopyBuffer _oecc93 #define OEMCrypto_MaximumUsageTableHeaderSize _oecc94 #define OEMCrypto_GenerateDerivedKeys _oecc95 @@ -644,11 +693,25 @@ typedef enum OEMCrypto_ProvisioningMethod { #define OEMCrypto_InstallOemPrivateKey _oecc118 #define OEMCrypto_ReassociateEntitledKeySession _oecc119 #define OEMCrypto_LoadCasECMKeys _oecc120 -#define OEMCrypto_LoadEntitledContentKeys_v17 _oecc121 // place holder for v17. +#define OEMCrypto_LoadEntitledContentKeys _oecc121 +#define OEMCrypto_ProductionReady _oecc122 +#define OEMCrypto_Idle _oecc123 +#define OEMCrypto_Wake _oecc124 +#define OEMCrypto_BuildInformation _oecc125 +#define OEMCrypto_SecurityLevel _oecc126 +#define OEMCrypto_ReuseUsageEntry _oecc127 +#define OEMCrypto_GetDTCP2Capability _oecc128 +#define OEMCrypto_GetWatermarkingSupport _oecc129 // clang-format on /// @addtogroup initcontrol /// @{ +/** Specifies whether system is in idle mode. + */ +typedef enum OEMCrypto_IdleState { + OEMCrypto_NoCryptoActivity = 0, // The system is not idle, but OEMCrypto is. + OEMCrypto_CpuSuspend = 1, +} OEMCrypto_IdleState; /** * This tells OEMCrypto which sandbox the current process belongs to. Any @@ -722,6 +785,76 @@ OEMCryptoResult OEMCrypto_Initialize(void); */ OEMCryptoResult OEMCrypto_Terminate(void); +/** + * If possible, OEMCrypto may reduce power consumption or other resources. For + * example, it may be possible to reduce the CPU clock rates. When the system + * is in idle mode, then the CDM will not call OEMCrypto_GetHDCPCapability. + * + * This function is not required -- OEMCrypto may ignore this function. It is + * only used to improve performance. This function may return + * OEMCrypto_ERROR_NOT_IMPLEMENTED to indicate it is not supported. + * + * OEMCrypto_Idle may be called multiple times with no call to OEMCrypto_Wake + * in between. A call to OEMCrypto_Idle with different values of + * OEMCrypto_IdleState or os_specific_code may happen in any order. It is + * OEMCrypto’s responsibility to choose the appropriate behavior for improving + * power consumption. In particular, OEMCrypto may be notified of the + * OEMCrypto_NoCryptoActivity state before or after a notification of the + * OEMCrypto_CpuSuspend state, or OEMCrypto_NoCryptoActivity may not be notified + * at all. On some platforms, a call with OEMCrypto_CpuSuspend may never + * happen. + * + * The acceptable values of `os_specific_code` must be coordinated between the + * OS and the OEMCrypto vendor. On some platforms, for example Android, only + * the value of 0 will be used. For other platforms, it is the responsibility + * of the OEM device maker to coordinate with the SOC to define acceptable + * values of `os_specific_code`. + * + * @param[in] state: The idle state. This indicates if the call came from + * the OS or the CDM. + * @param[in] os_specific_code: Specified by the platform or OS for extra + * sleep information. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * + * @threading + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. No other functions will be called before the + * system is re-initialized. + * + * @version + * This method is supported by all API versions. + */ +OEMCryptoResult OEMCrypto_Idle(OEMCrypto_IdleState state, + uint32_t os_specific_code); + +/** + * The new function OEMCrypto_Wake will be called to indicate that crypto + * operations will resume. A call to OEMCrypto_Wake after the system is already + * awake shall have no effect. If OEMCrypto cannot recover from being idle, it + * may return OEMCrypto_ERROR_SESSION_LOST_STATE or + * OEMCrypto_ERROR_SYSTEM_INVALIDATED. + * + * The CDM layer may postpone a call to OEMCrypto_Wake until Widevine activity + * is starting. This may happen long after the CPU wakes up. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * @threading + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. No other functions will be called before the + * system is re-initialized. + * + * @version + * This method is supported by all API versions. + */ +OEMCryptoResult OEMCrypto_Wake(void); + /// @} /// @addtogroup keyladder @@ -782,6 +915,39 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session); */ OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); +/** + * This method creates an entitled key session. + * + * @param[in] oec_session: handle for the OEMCrypto session to be associated + * with the created entitled key session. + * @param[out] key_session: id of the created entitled key session. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_SESSION + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_CreateEntitledKeySession( + OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session); + +/** + * This method which removes an entitled key session. + * + * @param[in] key_session: id of the entitled key session to be removed. + * + * Returns: + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( + OEMCrypto_SESSION key_session); + /** * Generates three secondary keys, mac_key[server], mac_key[client], and * encrypt_key, for handling signing and content key decryption under the @@ -995,11 +1161,6 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, * it must be 0x1 (RSASSA-PSS with SHA1). If not, then an error of * OEMCrypto_ERROR_SIGNATURE_FAILURE shall be returned. * - * OEMCrypto shall compute a hash of the core license request. The core - * license request is the buffer starting at message and with length - * core_message_size. The hash will be saved with the session and verified - * that it matches a hash in the license response. - * * OEMCrypto shall also call the function ODK_InitializeClockValues, * described in the document "License Duration and Renewal", to initialize * the session's clock values. @@ -1135,105 +1296,6 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_size, uint8_t* signature, size_t* signature_length); -/** - * OEMCrypto will use OEMCrypto_PrepAndSignProvisioningRequest(), as described - * in the document "Widevine Core Message Serialization", to prepare the core - * message. If it returns an error, the error should be returned by OEMCrypto - * to the CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall - * compute the signature of the entire message. The entire message is the - * buffer starting at message with length message_length. - * - * For a device that has a keybox, i.e. Provisioning 2.0, OEMCrypto will sign - * the request with the session's derived client mac key from the previous - * call to OEMCrypto_GenerateDerivedKeys(). - * - * For a device that has an OEM Certificate, i.e. Provisioning 3.0, OEMCrypto - * will sign the request with the private key associated with the OEM - * Certificate. The key shall have been loaded by a previous call to - * OEMCrypto_LoadDRMPrivateKey(). - * - * Refer to the Signing Messages Sent to a Server section above for more - * details. - * - * NOTE: if signature pointer is null and/or input signature_length is zero, - * this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output - * signature_length to the size needed to receive the output signature. - * - * @param[in] session: handle for the session to be used. - * @param[in,out] message: Pointer to memory for the entire message. Modified by - * OEMCrypto via the ODK library. - * @param[in] message_length: length of the entire message buffer. - * @param[in,out] core_message_size: length of the core message at the beginning - * of the message. (in) size of buffer reserved for the core message, in - * bytes. (out) actual length of the core message, in bytes. - * @param[out] signature: pointer to memory to receive the computed signature. - * @param[in,out] signature_length: (in) length of the signature buffer, in - * bytes. (out) actual length of the signature, in bytes. - * - * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_INVALID_SESSION - * @retval OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough - * to hold the signature. - * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE - * @retval OEMCrypto_ERROR_SESSION_LOST_STATE - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * - * @buffer_size - * OEMCrypto shall support message sizes as described in the section - * OEMCrypto_ResourceRatingTier(). - * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is - * larger than the supported size. - * - * @threading - * This is a "Session Function" and may be called simultaneously with session - * functions for other sessions but not simultaneously with other functions - * for this session. It will not be called simultaneously with initialization - * or usage table functions. It is as if the CDM holds a write lock for this - * session, and a read lock on the OEMCrypto system. - * - * @version - * This method changed in API version 16. - */ -OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( - OEMCrypto_SESSION session, uint8_t* message, size_t message_length, - size_t* core_message_size, uint8_t* signature, size_t* signature_length); - -/** - * Verify and install a new SRM file. The device shall install the new file only - * if verification passes. If verification fails, the existing SRM will be left - * in place. Verification is defined by DCP, and includes verification of the - * SRM's signature and verification that the SRM version number will not be - * decreased. See the section [HDCP SRM Update](../../index#hdcp_srm_update) for - * more details about the SRM. This function is for devices that support HDCP - * v2.2 or higher and wish to receive 4k content. - * - * @param[in] buffer: buffer containing the SRM - * @param[in] buffer_length: length of the SRM, in bytes. - * - * @retval OEMCrypto_SUCCESS if the file was valid and was installed. - * @retval OEMCrypto_ERROR_INVALID_CONTEXT if the SRM version is too low, or - * the file is corrupted. - * @retval OEMCrypto_ERROR_SIGNATURE_FAILURE If the signature is invalid. - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is too large for the - * device. - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED - * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED - * - * @buffer_size - * The size of the buffer is determined by the HDCP specification. - * - * @threading - * This is an "Initialization and Termination Function" and will not be - * called simultaneously with any other function, as if the CDM holds a write - * lock on the OEMCrypto system. - * - * @version - * This method changed in API version 13. - */ -OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length); - /** * Install a set of keys for performing decryption in the current session. * This function will be deprecated and will only be used for legacy license @@ -1508,9 +1570,10 @@ OEMCryptoResult OEMCrypto_LoadKeys( * returned by ODK_ParseLicense. * * The keys will be decrypted using the current encrypt_key (AES-128-CBC) and - * the IV given in the KeyObject. Each key control block will be decrypted - * using the first 128 bits of the corresponding content key (AES-128-CBC) - * and the IV given in the KeyObject. + * the IV given in the KeyObject. If the API version of the license is less + * than 17, each key control block will be decrypted using the first 128 bits + * of the corresponding content key (AES-128-CBC) and the IV given in the + * KeyObject. In v17 licenses, the key control block is not decrypted. * * If its length is not zero, enc_mac_keys will be used to create new * mac_keys. After all keys have been decrypted and validated, the new @@ -1762,7 +1825,7 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, * store the encrypted content key data in the key table, and decrypt it when * the function SelectKey is called. * - * @param[in] session: handle for the session to be used. + * @param[in] session: handle for the entitled key session to be used. * @param[in] message: pointer to memory containing message to be verified. * @param[in] message_length: length of the message, in bytes. * @param[in] key_array_length: number of keys present. @@ -1776,6 +1839,7 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, * @retval OEMCrypto_KEY_NOT_ENTITLED * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @threading * This is a "Session Function" and may be called simultaneously with session @@ -1785,7 +1849,7 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, * session, and a read lock on the OEMCrypto system. * * @version - * This method is new in API version 14. + * This method changed in API version 17. */ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -1793,6 +1857,10 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( const OEMCrypto_EntitledContentKeyObject* key_array); /** + * NOTE: OEMCrypto_RefreshKeys() is only used to load a v15 license or renewal. + * Because there are no longer any active v15 servers, this function is only + * needed for devices that are upgraded to v17, not new devices. + * * Updates the license clock values to allow playback to continue. This * function is being deprecated and is only used for version v15 licenses -- * i.e. offline license saved before an update or licenses from a server that @@ -1989,7 +2057,7 @@ OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, * 5. If the specified key has not been loaded, return * OEMCrypto_ERROR_NO_CONTENT_KEY. * - * @param[in] session: handle for the session to be used. + * @param[in] session: handle for the crypto or entitled key session to be used. * @param[in] content_key_id: The unique id of the key of interest. * @param[in] content_key_id_length: The length of key_id, in bytes. From 1 to * 16, inclusive. @@ -2003,6 +2071,7 @@ OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @threading * This is a "Session Function" and may be called simultaneously with session @@ -2012,7 +2081,7 @@ OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, * session, and a read lock on the OEMCrypto system. * * @version - * This method is new in API version 10. + * This method is changed in API version 17. */ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, const uint8_t* content_key_id, @@ -2070,7 +2139,7 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, * the device cannot enforce at least that version of HDCP, then the key * is not selected, and OEMCrypto_ERROR_INSUFFICIENT_HDCP is returned. * - * @param[in] session: crypto session identifier. + * @param[in] session: handle for the crypto or entitled key session to be used. * @param[in] content_key_id: pointer to the content Key ID. * @param[in] content_key_id_length: length of the content Key ID, in bytes. * From 1 to 16, inclusive. @@ -2091,6 +2160,7 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session, * @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @threading * This is a "Session Function" and may be called simultaneously with session @@ -2435,8 +2505,8 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * In either case, a call to OEMCrypto_GetHDCPCapability() shall return the * current HDCP level. * - * @param[in] session: Crypto session identifier. The crypto session in which - * decrypt is to be performed. + * @param[in] session: Crypto or entitled session identifier. The crypto session + * in which decrypt is to be performed. * @param[in] samples: A caller-owned array of OEMCrypto_SampleDescription * structures. Each entry in this array contains one sample of the content. * @param[in] samples_length: The length of the array pointed to by the samples @@ -2454,10 +2524,15 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * @retval OEMCrypto_ERROR_ANALOG_OUTPUT * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE + * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if the input buffer is too large, + * and should be partitioned. + * @retval OEMCrypto_ERROR_SHORT_BUFFER if the destination buffer is shorter + * than the source * @retval OEMCrypto_ERROR_OUTPUT_TOO_LARGE * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * @retval OEMCrypto_ERROR_UNSUPPORTED_CIPHER * * @buffer_size * OEMCrypto shall support subsample sizes and total input buffer sizes as @@ -2482,7 +2557,7 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 16. This method changed its name in API + * This method changed in API version 17. This method changed its name in API * version 11. */ OEMCryptoResult OEMCrypto_DecryptCENC( @@ -2536,7 +2611,10 @@ OEMCryptoResult OEMCrypto_DecryptCENC( * @retval OEMCrypto_ERROR_INVALID_CONTEXT * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE - * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE + * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if the input buffer is too large, + * and should be partitioned. + * @retval OEMCrypto_ERROR_SHORT_BUFFER if the destination buffer is shorter + * than the source * @retval OEMCrypto_ERROR_OUTPUT_TOO_LARGE * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED @@ -2597,7 +2675,7 @@ OEMCryptoResult OEMCrypto_CopyBuffer( * status of that entry is either kInactiveUsed or kInactiveUnused, then * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto session identifier. + * @param[in] session: crypto or entitled key session identifier. * @param[in] in_buffer: pointer to memory containing data to be encrypted. * @param[in] in_buffer_length: length of the buffer, in bytes. The algorithm * may restrict in_buffer_length to be a multiple of block size. @@ -2617,9 +2695,10 @@ OEMCryptoResult OEMCrypto_CopyBuffer( * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size - * OEMCrypto shall support buffers sizes of at least 100 KiB for generic + * OEMCrypto shall support buffers sizes of at least 100 KiB for generic * crypto operations. * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is * larger than the supported size. @@ -2632,7 +2711,7 @@ OEMCryptoResult OEMCrypto_CopyBuffer( * session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 16. + * This method changed in API version 17. */ OEMCryptoResult OEMCrypto_Generic_Encrypt( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, @@ -2666,7 +2745,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( * status of that entry is either kInactiveUsed or kInactiveUnused, then * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto session identifier. + * @param[in] session: crypto or entitled key session identifier. * @param[in] in_buffer: pointer to memory containing data to be encrypted. * @param[in] in_buffer_length: length of the buffer, in bytes. The algorithm * may restrict in_buffer_length to be a multiple of block size. @@ -2687,6 +2766,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size * OEMCrypto shall support buffers sizes of at least 100 KiB for generic @@ -2702,7 +2782,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt( * session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 16. + * This method changed in API version 17. */ OEMCryptoResult OEMCrypto_Generic_Decrypt( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer, @@ -2731,7 +2811,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( * status of that entry is either kInactiveUsed or kInactiveUnused, then * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto session identifier. + * @param[in] session: crypto or entitled key session identifier. * @param[in] buffer: pointer to memory containing data to be encrypted. * @param[in] buffer_length: length of the buffer, in bytes. * @param[in] algorithm: Specifies which algorithm to use. @@ -2753,6 +2833,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size * OEMCrypto shall support buffers sizes of at least 100 KiB for generic @@ -2768,7 +2849,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt( * session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 16. + * This method changed in API version 17. */ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, @@ -2806,7 +2887,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, * status of that entry is either kInactiveUsed or kInactiveUnused, then * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. * - * @param[in] session: crypto session identifier. + * @param[in] session: crypto or entitled key session identifier. * @param[in] buffer: pointer to memory containing data to be encrypted. * @param[in] buffer_length: length of the buffer, in bytes. * @param[in] algorithm: Specifies which algorithm to use. @@ -2824,6 +2905,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION * * @buffer_size * OEMCrypto shall support buffers sizes of at least 100 KiB for generic @@ -2839,7 +2921,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, * session, and a read lock on the OEMCrypto system. * * @version - * This method changed in API version 16. + * This method changed in API version 17. */ OEMCryptoResult OEMCrypto_Generic_Verify( OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer, @@ -3172,6 +3254,14 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(uint8_t* public_cert, /// @addtogroup validation /// @{ +/** Specifies OEMCrypto security level. + */ +typedef enum OEMCrypto_Security_Level { + OEMCrypto_Level_Unknown = 0, + OEMCrypto_Level1 = 1, + OEMCrypto_Level2 = 2, + OEMCrypto_Level3 = 3, +} OEMCrypto_Security_Level; /** * Returns a buffer filled with hardware-generated random bytes, if supported @@ -3258,9 +3348,13 @@ uint32_t OEMCrypto_APIVersion(void); uint32_t OEMCrypto_MinorAPIVersion(void); /** - * Report the build information of the OEMCrypto library as a short null - * terminated C string. The string should be at most 128 characters long. - * This string should be updated with each release or OEMCrypto build. + * Stores the build information of the OEMCrypto library in a buffer. This + * string should be updated with each release or OEMCrypto build. If + * buffer_length is not enough, the function will return + * OEMCrypto_ERROR_SHORT_BUFFER. Before returning OEMCrypto_ERROR_SHORT_BUFFER, + * the function should set buffer_length to the length of buffer needed. If the + * write is successful, buffer_length will be set to the number of bytes + * written. * * Some SOC vendors deliver a binary OEMCrypto library to a device * manufacturer. This means the OEMCrypto version may not be exactly in sync @@ -3275,9 +3369,11 @@ uint32_t OEMCrypto_MinorAPIVersion(void); * number in this string, e.g. "15.1" or "15.2" if those minor versions are * released. * - * @return - * A printable null terminated C string, suitable for a single line in a - * log. + * @param[out] buffer: pointer to the buffer that receives build information + * @param[in,out] buffer_length: length of the data buffer in bytes + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small. * * @threading * This is a "Property Function" and may be called simultaneously with any @@ -3288,7 +3384,7 @@ uint32_t OEMCrypto_MinorAPIVersion(void); * @version * This method changed in each API version. */ -const char* OEMCrypto_BuildInformation(void); +OEMCryptoResult OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length); /** * This function returns the current patch level of the software running in @@ -3318,8 +3414,8 @@ uint8_t OEMCrypto_Security_Patch_Level(void); * Since this function is spoofable, it is not relied on for security * purposes. It is for information only. * - * @return - * A null terminated string. Useful value are "L1", "L2" and "L3". + * @return A security level enum. Values are OEMCrypto_Level_Unknown, + * OEMCrypto_Level1, OEMCrypto_Level2 and OEMCrypto_Level3. * * @threading * This is a "Property Function" and may be called simultaneously with any @@ -3328,9 +3424,9 @@ uint8_t OEMCrypto_Security_Patch_Level(void); * system. * * @version - * This method changed in API version 6. + * This method changed in API version 17. */ -const char* OEMCrypto_SecurityLevel(void); +OEMCrypto_Security_Level OEMCrypto_SecurityLevel(void); /** * Returns the maximum HDCP version supported by the device, and the HDCP @@ -3403,6 +3499,27 @@ const char* OEMCrypto_SecurityLevel(void); OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum); +/** + * Returns the DTCP2 support for a device. + * + * @param[out] capability: this will be set to 0 if DTCP2 is not supported, + * and 1 if the device supports at least v1 of DTCO2. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_GetDTCP2Capability( + OEMCrypto_DTCP2_Capability* capability); + /** * This is used to determine if the device can support a usage table. Since * this function is spoofable, it is not relied on for security purposes. It @@ -3553,26 +3670,6 @@ OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max); */ uint32_t OEMCrypto_SupportedCertificates(void); -/** - * Returns true if the device supports SRM files and the file can be updated - * via the function OEMCrypto_LoadSRM(). This also returns false for devices - * that do not support an SRM file, devices that do not support HDCP, and - * devices that have no external display support. - * - * @retval true if LoadSRM is supported. - * @retval false otherwise. - * - * @threading - * This is a "Property Function" and may be called simultaneously with any - * other property function or session function, but not any initialization or - * usage table function, as if the CDM holds a read lock on the OEMCrypto - * system. - * - * @version - * This method changed in API version 13. - */ -bool OEMCrypto_IsSRMUpdateSupported(void); - /** * Returns the version number of the current SRM file. If the device does not * support SRM files, this will return OEMCrypto_ERROR_NOT_IMPLEMENTED. If @@ -3688,6 +3785,77 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(void); */ uint32_t OEMCrypto_ResourceRatingTier(void); +/** + * Returns OEMCrypto_SUCCESS if the device is production ready. This is a + * new reporting mechanism that reports that OEMCrypto is production ready. + * For example, the SOC delivers OEMCrypto to the OEM which functions + * correctly whether debugging or antirollback is turned on or not. The OEM + * has the option to turn on TEE software antirollback if they wish. If anti + * rollback is off, or if debugging is enabled, then this function will + * return failure. + * + * The OEMCrypto implementer may choose any other error code if the device + * is not production ready. The motivation for this new feature is to allow + * SOCs to signal to OEMs that hardening has not been done on a system. + * During development of a device, it is fine for this function to return an + * error. During development, we expect devices to have debugging turned on. + * However, once the device is ready for production, all hardening should be + * turned on. + * + * The intention is that certification tests, such as Android’s GTS test suite, + * will verify that a device is production ready. Being production ready will + * not be a requirement to pass OEMCrypto unit tests, but the status will be + * logged as part of the tests. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_ProductionReady(void); + +/** + * Returns OEMCrypto_WatermarkingAlwaysOn or OEMCrypto_WatermarkingConfigurable + * if the device supports watermarking. If the device does not support + * watermarking but the license has watermarking set to accept it, + * OEMCrypto_LoadLicense should return the error + * OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE, which is a new error code in v17. + * + * If watermarking can be turned on or off for individual streams, then + * OEMCrypto should honor the settings for each license individually. + * + * If watermarking can only be turned on or off on a system wide level, then + * the most recent license should be honored. The watermarking feature should + * be turned on or off when a license is loaded. If this conflicts with a + * license that had been loaded earlier, then keys from the earlier license may + * not be used. In this case, either OEMCrypto_SelectKey or + * OEMCrypto_DecryptCENC will return OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE to + * indicate that the watermarking status has changed and the license is no + * longer usable. + * + * @retval OEMCrypto_WatermarkingError + * @retval OEMCrypto_WatermarkingNotSupported + * @retval OEMCrypto_WatermarkingConfigurable + * @retval OEMCrypto_WatermarkingAlwaysOn + * + * @threading + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. + * + * @version + * This method is new in API version 17. + */ +OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void); + /// @} /// @addtogroup drm_cert @@ -3987,6 +4155,71 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature( uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme); +/** + * OEMCrypto will use OEMCrypto_PrepAndSignProvisioningRequest(), as described + * in the document "Widevine Core Message Serialization", to prepare the core + * message. If it returns an error, the error should be returned by OEMCrypto + * to the CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall + * compute the signature of the entire message. The entire message is the + * buffer starting at message with length message_length. + * + * For a device that has a keybox, i.e. Provisioning 2.0, OEMCrypto will sign + * the request with the session's derived client mac key from the previous + * call to OEMCrypto_GenerateDerivedKeys(). + * + * For a device that has an OEM Certificate, i.e. Provisioning 3.0, OEMCrypto + * will sign the request with the private key associated with the OEM + * Certificate. The key shall have been loaded by a previous call to + * OEMCrypto_LoadDRMPrivateKey(). + * + * Refer to the Signing Messages Sent to a Server section above for more + * details. + * + * NOTE: if signature pointer is null and/or input signature_length is zero, + * this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output + * signature_length to the size needed to receive the output signature. + * + * @param[in] session: handle for the session to be used. + * @param[in,out] message: Pointer to memory for the entire message. Modified by + * OEMCrypto via the ODK library. + * @param[in] message_length: length of the entire message buffer. + * @param[in,out] core_message_size: length of the core message at the beginning + * of the message. (in) size of buffer reserved for the core message, in + * bytes. (out) actual length of the core message, in bytes. + * @param[out] signature: pointer to memory to receive the computed signature. + * @param[in,out] signature_length: (in) length of the signature buffer, in + * bytes. (out) actual length of the signature, in bytes. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough + * to hold the signature. + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * + * @buffer_size + * OEMCrypto shall support message sizes as described in the section + * OEMCrypto_ResourceRatingTier(). + * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is + * larger than the supported size. + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method changed in API version 16. + */ +OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( + OEMCrypto_SESSION session, uint8_t* message, size_t message_length, + size_t* core_message_size, uint8_t* signature, size_t* signature_length); + /// @} /// @addtogroup usage_table @@ -4112,6 +4345,44 @@ OEMCryptoResult OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, OEMCryptoResult OEMCrypto_CreateNewUsageEntry(OEMCrypto_SESSION session, uint32_t* usage_entry_number); +/** + * This allows a session to take an existing usage entry. The effect of this + * call is identical to that of creating an entry via + * OEMCrypto_CreateUsageEntry(), except that the usage table header does not + * change size. All information related to the previous entry should be cleared + * from the header. The new entry will be initialized with a generation number + * equal to the master generation number, which will also be stored in the + * header’s existing slot. Then the master generation number will be + * incremented. + * + * If the session already has a usage entry associated with it, the error + * OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES is returned. + * + * @param[in] session: handle for the session to be used. + * @param[in] usage_entry_number: index of new usage entry. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED some devices do not implement usage + * tables. + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES if there already is a usage + * entry loaded into this session + * @retval OEMCrypto_ERROR_INVALID_SESSION when entry number is in use by + * another session + * + * @threading + * This is a "Usage Table Function" and will not be called simultaneously + * with any other function, as if the CDM holds a write lock on the OEMCrypto + * system. + * + * @version + * This method changed in API version 17. + */ +OEMCryptoResult OEMCrypto_ReuseUsageEntry(OEMCrypto_SESSION session, + uint32_t usage_entry_number); + /** * This loads a usage entry saved previously by UpdateUsageEntry. The * signature at the beginning of the buffer is verified and the buffer will @@ -4483,28 +4754,101 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(uint32_t new_entry_count, /// @} -/// @addtogroup test_verify +/// @addtogroup prov40 /// @{ /** - * Delete the current SRM. Any valid SRM, regardless of its version number, - * will be installable after this via OEMCrypto_LoadSRM(). + * Get the serialized boot certificate chain in CBOR format used in + * provisioning 4. * - * This function should not be implemented on production devices, and will - * only be used to verify unit tests on a test device. + * @param[out] bcc: pointer to the buffer that receives the serialized boot + * certificate chain in CBOR format. + * @param[in,out] bcc_size - on input, size of the caller's bcc buffer. On + * output, the number of bytes written into the buffer. + * @param[out] additional_signature: pointer to the buffer that receives + * additional device key signature (certificate chain). This field is only + * used by the signing model where a vendor certificate is available on the + * device. + * @param[in,out] additional_signature_size - on input, size of the caller's + * additional_signature buffer. On output, the number of bytes written into + * the buffer. * - * @retval OEMCrypto_SUCCESS if the SRM file was deleted. - * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED always on production devices. + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_SHORT_BUFFER if any of the buffers is too small to + * return the bcc or additional_signature. + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4 is not supported. * * @threading - * This is an "Initialization and Termination Function" and will not be - * called simultaneously with any other function, as if the CDM holds a write - * lock on the OEMCrypto system. + * This is a "Property Function" and may be called simultaneously with any + * other property function or session function, but not any initialization or + * usage table function, as if the CDM holds a read lock on the OEMCrypto + * system. * * @version - * This method is new in API version 13. + * This method is new in API version 17. */ -OEMCryptoResult OEMCrypto_RemoveSRM(void); +OEMCryptoResult OEMCrypto_GetBootCertificateChain( + uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature, + size_t* additional_signature_size); + +/** + * Generates a key pair used in OEM and DRM certificate provisioning. The public + * key is supposed to be certified by the server. The private key is wrapped + * with the encryption key so it can be stored in the file system. + * + * If an OEM private key is unavailable, the request is assumed for OEM + * certificate provisioning. In this case, the public key is signed by the + * device private key. If an OEM private key is available, the request is + * assumed for DRM certificate provisioning and the public key is signed by the + * OEM private key. + * + * @param[in] session: session id. + * @param[out] public_key: pointer to the buffer that receives the public key + * that is to be certified by the server. The key must be an ASN.1 + * DER-encoded SubjectPublicKeyInfo as specified in RFC 5280. + * @param[in,out] public_key_size: on input, size of the caller's public_key + * buffer. On output, the number of bytes written into the buffer. + * @param[out] public_key_signature: pointer to the buffer that receives the + * signature of the public key. If an OEM private key is unavailable, it is + * signed by the device private key; otherwise is signed by the OEM private + * key. + * @param[in,out] public_key_signature_size: on input, size of the caller's + * public_key_signature buffer. On output, the number of bytes written into + * the buffer. + * @param[out] wrapped_private_key: pointer to the buffer that receives the + * encrypted private key. It is encrypted by the device encryption key. + * @param[in,out] wrapped_private_key_size: on input, size of the caller's + * wrapped_private_key buffer. On output, the number of bytes written into + * the buffer. + * @param[out] key_type: the type of the generated key pair (RSA or ECC). + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_SHORT_BUFFER if any of the buffer |public_key|, + * |public_key_signature| or |wrapped_private_key_size| is too small. + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( + OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_size, + uint8_t* public_key_signature, size_t* public_key_signature_size, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_size, + OEMCrypto_PrivateKeyType* key_type); + +/// @} + +/// @addtogroup test_verify +/// @{ /** * Returns the type of hash function supported for Full Decrypt Path Testing. @@ -4711,8 +5055,138 @@ OEMCryptoResult OEMCrypto_FreeSecureBuffer( OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor, int secure_fd); +/** + * Loads an OEM private key to a session. The key will be used in signing DRM + * certificate request, or the public key generated by calling + * OEMCrypto_GenerateCertificateKeyPair. + * + * @param[in] session: session id. + * @param[in] key_type: type of the leaf key (RSA or ECC). + * @param[in] wrapped_private_key: the encrypted private key. This is the + * wrapped key generated by OEMCrypto_GenerateCertificateKeyPair. + * @param[in] wrapped_private_key_length: length of |wrapped_private_key| in + * bytes. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_NO_DEVICE_KEY + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_RSA_KEY + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_ERROR_SESSION_LOST_STATE + * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_InstallOemPrivateKey( + OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); + /// @} +/** + * This method associates an existing entitled key session to the specified + * OEMCrypto session. + * + * @param[in] key_session: id of the entitled key session. + * @param[in] oec_session: handle for the OEMCrypto session to be associated + * with the entitled key session. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * @retval OEMCrypto_ERROR_INVALID_SESSION + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); + +/** + * The OEMCrypto_LoadCasECMKeys method is added to load content keys into an + * entitled key session, which already has entitlement keys loaded. Used only by + * CAS. + * + * This function will only be called for a session after a call to + * OEMCrypto_LoadKeys with the license_type equal to + * OEMCrypto_EntitlementLicense, and a call to + * OEMCrypto_CreateEntitledKeySession initializing the entitled key session. + * This function may be called multiple times for the same session. + * + * For each key object, odd and even, OEMCrypto shall look up the entry in the + * key table with the corresponding entitlement_key_id. Before the + * entitlement_key is used: + * 1) If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED. + * 2) Check the entitlement key’s key control block use. If failed, return + * corresponding error code such as OEMCrypto_ERROR_ANALOG_OUTPUT, + * OEMCrypto_ERROR_INSUFFICIENT_HDCP. + * 3) If the entitlement key’s control block has a nonzero Duration field, + * then the API shall verify that the duration is greater than the + * session’s elapsed time clock before the key is used. OEMCrypto will + * return OEMCrypto_ERROR_KEY_EXPIRED. + * 4) The content_key_data decrypted using the entitlement_key_data as a key + * for AES-256-CBC with an IV of content_key_data_iv. Wrapped content is + * padded using PKCS#7 padding. Notice that the entitlement key will be an + * AES 256 bit key. The clear content key data will be stored in the + * entry’s content_key_data. + * 5) The decrypted content key data may be set in a hardware KeySlot, + * together with content iv and cipher mode information, which can be used + * by the Descrambler in TunerHal. The entitled key session ID may be used + * as the key token to uniquely identify the content key in KeySlot. + * + * @param[in] session: handle for the entitled key session to be used. + * @param[in] message: pointer to memory containing message to be verified. + * @param[in] message_length: length of the message, in bytes. + * @param[in] even_key: key update for the even ecm key. May be null if the key + * does not change. + * @param[in] odd_key: key update for the odd ecm key. May be null if the key + * does not change. + * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_SESSION + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE + * @retval OEMCrypto_KEY_NOT_ENTITLED + * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION + * @retval OEMCrypto_ERROR_KEY_EXPIRED + * @retval OEMCrypto_ERROR_ANALOG_OUTPUT + * @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP + * + * @threading + * This is a "Session Function" and may be called simultaneously with session + * functions for other sessions but not simultaneously with other functions + * for this session. It will not be called simultaneously with initialization + * or usage table functions. It is as if the CDM holds a write lock for this + * session, and a read lock on the OEMCrypto system. + * + * @version + * This method is new in API version 17. + */ +OEMCryptoResult OEMCrypto_LoadCasECMKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); + /* * OEMCrypto_OPK_SerializationVersion * Check the serialization protocol version used by the OEMCrypto Porting Kit @@ -4981,6 +5455,64 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate_V15( OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length); + +/* + * OEMCrypto_BuildInformation_V16 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +const char* OEMCrypto_BuildInformation_V16(void); + +/* + * OEMCrypto_SecurityLevel_V16 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +const char* OEMCrypto_SecurityLevel_V16(void); + +typedef struct { + OEMCrypto_Substring entitlement_key_id; + OEMCrypto_Substring content_key_id; + OEMCrypto_Substring content_key_data_iv; + OEMCrypto_Substring content_key_data; +} OEMCrypto_EntitledContentKeyObject_V16; + +/* + * OEMCrypto_LoadEntitledContentKeys_V16 + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_LoadEntitledContentKeys_V16( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject_V16* key_array); + +/** + * OEmCrypto_IsSRIMUpdateSupported + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +bool OEMCrypto_IsSRMUpdateSupported(void); + +/** + * OEMCrypto_LoadSRM + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length); + +/** + * OEMCrypto_RemoveSRM + * @deprecated + * Not required for the current version of OEMCrypto. Declared here to + * help with backward compatibility. + */ +OEMCryptoResult OEMCrypto_RemoveSRM(void); /****************************************************************************/ /****************************************************************************/ diff --git a/oemcrypto/include/level3.h b/oemcrypto/include/level3.h index c4e7c43..014b8cc 100644 --- a/oemcrypto/include/level3.h +++ b/oemcrypto/include/level3.h @@ -39,7 +39,6 @@ namespace wvoec3 { #define Level3_LoadDeviceRSAKey _lcc19 #define Level3_DeriveKeysFromSessionKey _lcc21 #define Level3_APIVersion _lcc22 -#define Level3_SecurityLevel _lcc23 #define Level3_Generic_Encrypt _lcc24 #define Level3_Generic_Decrypt _lcc25 #define Level3_Generic_Sign _lcc26 @@ -76,9 +75,8 @@ namespace wvoec3 { #define Level3_SupportsDecryptHash _lcc86 #define Level3_SetDecryptHash _lcc88 #define Level3_GetHashErrorCode _lcc89 -#define Level3_BuildInformation _lcc90 #define Level3_RefreshKeys _lcc91 -#define Level3_LoadEntitledContentKeys _lcc92 +#define Level3_LoadEntitledContentKeys_V16 _lcc92 #define Level3_CopyBuffer _lcc93 #define Level3_MaximumUsageTableHeaderSize _lcc94 #define Level3_GenerateDerivedKeys _lcc95 @@ -93,8 +91,24 @@ namespace wvoec3 { #define Level3_DecryptCENC _lcc105 #define Level3_LoadDRMPrivateKey _lcc107 #define Level3_MinorAPIVersion _lcc108 -#define Level3_AllocateSecureBuffer _lcc111 -#define Level3_FreeSecureBuffer _lcc112 +#define Level3_AllocateSecureBuffer _lcc109 +#define Level3_FreeSecureBuffer _lcc110 +#define Level3_CreateEntitledKeySession _lcc111 +#define Level3_RemoveEntitledKeySession _lcc112 +#define Level3_GetBootCertificateChain _lcc116 +#define Level3_GenerateCertificateKeyPair _lcc117 +#define Level3_InstallOemPrivateKey _lcc118 +#define Level3_ReassociateEntitledKeySession _lcc119 +#define Level3_LoadCasECMKeys _lcc120 +#define Level3_LoadEntitledContentKeys _lcc121 // place holder for v17. +#define Level3_ProductionReady _lcc122 +#define Level3_Idle _lcc123 +#define Level3_Wake _lcc124 +#define Level3_BuildInformation _lcc125 +#define Level3_SecurityLevel _lcc126 +#define Level3_ReuseUsageEntry _lcc127 +#define Level3_GetDTCP2Capability _lcc128 +#define Level3_GetWatermarkingSupport _lcc129 #else #define Level3_Initialize _oecc01 #define Level3_Terminate _oecc02 @@ -112,7 +126,6 @@ namespace wvoec3 { #define Level3_LoadDeviceRSAKey _oecc19 #define Level3_DeriveKeysFromSessionKey _oecc21 #define Level3_APIVersion _oecc22 -#define Level3_SecurityLevel _oecc23 #define Level3_Generic_Encrypt _oecc24 #define Level3_Generic_Decrypt _oecc25 #define Level3_Generic_Sign _oecc26 @@ -151,9 +164,8 @@ namespace wvoec3 { #define Level3_SupportsDecryptHash _oecc86 #define Level3_SetDecryptHash _oecc88 #define Level3_GetHashErrorCode _oecc89 -#define Level3_BuildInformation _oecc90 #define Level3_RefreshKeys _oecc91 -#define Level3_LoadEntitledContentKeys _oecc92 +#define Level3_LoadEntitledContentKeys_V16 _oecc92 #define Level3_CopyBuffer _oecc93 #define Level3_MaximumUsageTableHeaderSize _oecc94 #define Level3_GenerateDerivedKeys _oecc95 @@ -168,12 +180,24 @@ namespace wvoec3 { #define Level3_DecryptCENC _oecc105 #define Level3_LoadDRMPrivateKey _oecc107 #define Level3_MinorAPIVersion _oecc108 -// TODO(b/171121061): Renaming for oemcrypto_test to find the L3 implementation -// of the two functions below. This is to be fixed when -// OEMCrypto_AllocateSecureBuffer and OEMCrypto_FreeSecureBuffer are added to -// OEMCryptoCENC.h -#define Level3_AllocateSecureBuffer OEMCrypto_AllocateSecureBuffer -#define Level3_FreeSecureBuffer OEMCrypto_FreeSecureBuffer +#define Level3_AllocateSecureBuffer _oecc109 +#define Level3_FreeSecureBuffer _oecc110 +#define Level3_CreateEntitledKeySession _oecc111 +#define Level3_RemoveEntitledKeySession _oecc112 +#define Level3_GetBootCertificateChain _oecc116 +#define Level3_GenerateCertificateKeyPair _oecc117 +#define Level3_InstallOemPrivateKey _oecc118 +#define Level3_ReassociateEntitledKeySession _oecc119 +#define Level3_LoadCasECMKeys _oecc120 +#define Level3_LoadEntitledContentKeys _oecc121 // place holder for v17. +#define Level3_ProductionReady _oecc122 +#define Level3_Idle _oecc123 +#define Level3_Wake _oecc124 +#define Level3_BuildInformation _oecc125 +#define Level3_SecurityLevel _oecc126 +#define Level3_ReuseUsageEntry _oecc127 +#define Level3_GetDTCP2Capability _oecc128 +#define Level3_GetWatermarkingSupport _oecc129 #endif #define Level3_GetInitializationState _oecl3o01 @@ -248,7 +272,7 @@ OEMCryptoResult Level3_DeriveKeysFromSessionKey(OEMCrypto_SESSION session, uint32_t Level3_APIVersion(); uint32_t Level3_MinorAPIVersion(); uint8_t Level3_SecurityPatchLevel(); -const char* Level3_SecurityLevel(); +OEMCrypto_Security_Level Level3_SecurityLevel(); OEMCryptoResult Level3_GetHDCPCapability(OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum); bool Level3_SupportsUsageTable(); @@ -334,7 +358,7 @@ OEMCryptoResult Level3_SetDecryptHash(OEMCrypto_SESSION session, const uint8_t* hash, size_t hash_length); OEMCryptoResult Level3_GetHashErrorCode(OEMCrypto_SESSION session, uint32_t* failed_frame_number); -const char* Level3_BuildInformation(); +OEMCryptoResult Level3_BuildInformation(char* buffer, size_t* buffer_length); OEMCryptoResult Level3_LoadRenewal(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, @@ -370,6 +394,37 @@ OEMCryptoResult Level3_AllocateSecureBuffer( OEMCryptoResult Level3_FreeSecureBuffer( OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor, int secure_fd); +OEMCryptoResult Level3_CreateEntitledKeySession(OEMCrypto_SESSION oec_session, + OEMCrypto_SESSION* key_session); +OEMCryptoResult Level3_RemoveEntitledKeySession(OEMCrypto_SESSION key_session); +OEMCryptoResult Level3_GetBootCertificateChain( + uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature, + size_t* additional_signature_size); +OEMCryptoResult Level3_GenerateCertificateKeyPair( + OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_size, + uint8_t* public_key_signature, size_t* public_key_signature_size, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_size, + OEMCrypto_PrivateKeyType* key_type); +OEMCryptoResult Level3_InstallOemPrivateKey(OEMCrypto_SESSION session, + OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, + size_t wrapped_private_key_length); +OEMCryptoResult Level3_ReassociateEntitledKeySession( + OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session); +OEMCryptoResult Level3_LoadCasECMKeys( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); +OEMCryptoResult Level3_ProductionReady(); +OEMCryptoResult Level3_Idle(OEMCrypto_IdleState state, + uint32_t os_specific_code); +OEMCryptoResult Level3_Wake(); +OEMCryptoResult Level3_ReuseUsageEntry(OEMCrypto_SESSION session, + uint32_t usage_entry_number); +OEMCryptoResult Level3_GetDTCP2Capability( + OEMCrypto_DTCP2_Capability* capability); +OEMCrypto_WatermarkingSupport Level3_GetWatermarkingSupport(); + // The following are specific to Google's Level 3 implementation and are not // required. diff --git a/oemcrypto/include/oemcrypto_types.h b/oemcrypto/include/oemcrypto_types.h index 4a5728c..02edc98 100644 --- a/oemcrypto/include/oemcrypto_types.h +++ b/oemcrypto/include/oemcrypto_types.h @@ -23,6 +23,14 @@ typedef struct WidevineKeybox { // 128 bytes total. uint8_t crc_[4]; } WidevineKeybox; +// This is the format for a key control block. +typedef struct { + uint8_t verification[4]; + uint32_t duration; + uint32_t nonce; + uint32_t control_bits; +} KeyControlBlock; + /* * SRM_Restriction_Data * @@ -39,6 +47,12 @@ const uint32_t kControlObserveDataPath = (1u << 31); const uint32_t kControlObserveHDCP = (1u << 30); const uint32_t kControlObserveCGMS = (1u << 29); const uint32_t kControlRequireAntiRollbackHardware = (1u << 28); +// The two bits kControlWhiteboxSecurityLevelMask are not used in +// OEMCrypto; they are only used for whitebox testing. +const uint32_t kControlWhiteboxSecurityLevelShift = 26; +const uint32_t kControlWhiteboxSecurityLevelMask = + (0x03u << kControlWhiteboxSecurityLevelShift); +const uint32_t kControlAllowDVRRecording = (1u << 25); const uint32_t kControlAllowHashVerification = (1u << 24); const uint32_t kSharedLicense = (1u << 23); const uint32_t kControlSRMVersionRequired = (1u << 22); diff --git a/oemcrypto/include/pst_report.h b/oemcrypto/include/pst_report.h index 251ac52..33a1288 100644 --- a/oemcrypto/include/pst_report.h +++ b/oemcrypto/include/pst_report.h @@ -18,7 +18,7 @@ #include "OEMCryptoCENC.h" #include "string_conversions.h" // needed for htonll64. -namespace wvcdm { +namespace wvutil { class Unpacked_PST_Report { public: @@ -84,12 +84,12 @@ class Unpacked_PST_Report { int64_t time; memcpy(&time, buffer_ + kseconds_since_license_received_offset, sizeof(int64_t)); - return ntohll64(time); + return wvutil::ntohll64(time); } // Parameter time is in host byte order. void set_seconds_since_license_received(int64_t time) const { - time = ntohll64(time); + time = wvutil::ntohll64(time); memcpy(buffer_ + kseconds_since_license_received_offset, &time, sizeof(int64_t)); } @@ -143,6 +143,6 @@ class Unpacked_PST_Report { static const size_t kseconds_since_last_decrypt_offset = 40; static const size_t kpst_offset = 48; }; -} // namespace wvcdm +} // namespace wvutil #endif // PST_REPORT_H_ diff --git a/oemcrypto/odk/Android.bp b/oemcrypto/odk/Android.bp index 66cf0f0..3b7d807 100644 --- a/oemcrypto/odk/Android.bp +++ b/oemcrypto/odk/Android.bp @@ -5,6 +5,18 @@ // ---------------------------------------------------------------- // Builds libwv_odk.a, The ODK Library (libwv_odk) is used by // the CDM and by oemcrypto implementations. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_library_static { name: "libwv_odk", include_dirs: [ @@ -15,6 +27,7 @@ cc_library_static { srcs: [ "src/odk.c", + "src/odk_message.c", "src/odk_overflow.c", "src/odk_serialize.c", "src/odk_timer.c", @@ -39,6 +52,7 @@ cc_library_static { srcs: [ "src/core_message_deserialize.cpp", + "src/core_message_features.cpp", "src/core_message_serialize.cpp", "src/core_message_serialize_proto.cpp", ], diff --git a/oemcrypto/odk/README b/oemcrypto/odk/README index ba8c8c7..408fc44 100644 --- a/oemcrypto/odk/README +++ b/oemcrypto/odk/README @@ -1,8 +1,6 @@ This ODK Library is used to generate and parse core OEMCrypto messages for -OEMCrypto v16 and above. - -This library is used by both OEMCrypto on a device, and by Widevine license and -provisioning servers. +OEMCrypto v16 and above. This library is used by both OEMCrypto on a device +and by Widevine license and provisioning servers. The source of truth for these files is in the server code base on piper. Do not edit these files in the Android directory tree or in the Widevine Git diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h index 7a2a529..cb343ab 100644 --- a/oemcrypto/odk/include/OEMCryptoCENCCommon.h +++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h @@ -61,7 +61,7 @@ typedef enum OEMCryptoResult { OEMCrypto_ERROR_INVALID_NONCE = 32, OEMCrypto_ERROR_TOO_MANY_KEYS = 33, OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED = 34, - OEMCrypto_ERROR_INVALID_RSA_KEY = 35, + OEMCrypto_ERROR_INVALID_RSA_KEY = 35, /* deprecated */ OEMCrypto_ERROR_KEY_EXPIRED = 36, OEMCrypto_ERROR_INSUFFICIENT_RESOURCES = 37, OEMCrypto_ERROR_INSUFFICIENT_HDCP = 38, @@ -87,6 +87,12 @@ typedef enum OEMCryptoResult { OEMCrypto_ERROR_LICENSE_RELOAD = 57, OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES = 58, OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION = 59, + OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION = 60, + OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING = 61, + OEMCrypto_ERROR_UNSUPPORTED_CIPHER = 62, + OEMCrypto_ERROR_DVR_FORBIDDEN = 63, + OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE = 64, + OEMCrypto_ERROR_INVALID_KEY = 65, /* ODK return values */ ODK_ERROR_BASE = 1000, ODK_ERROR_CORE_MESSAGE = ODK_ERROR_BASE, @@ -95,6 +101,11 @@ typedef enum OEMCryptoResult { ODK_TIMER_EXPIRED = ODK_ERROR_BASE + 3, ODK_UNSUPPORTED_API = ODK_ERROR_BASE + 4, ODK_STALE_RENEWAL = ODK_ERROR_BASE + 5, + /* OPK return values */ + OPK_ERROR_BASE = 2000, + OPK_ERROR_REMOTE_CALL = OPK_ERROR_BASE, + OPK_ERROR_INCOMPATIBLE_VERSION = OPK_ERROR_BASE + 1, + OPK_ERROR_NO_PERSISTENT_DATA = OPK_ERROR_BASE + 2, } OEMCryptoResult; /* clang-format on */ @@ -135,6 +146,62 @@ typedef struct { size_t length; } OEMCrypto_Substring; +/** + * Used to specify information about CMI Descriptor 0. + * @param id: ID value of CMI Descriptor assigned by DTLA. + * @param length: byte length of the usage rules field. + * @param data: usage rules data. + */ +typedef struct { + uint8_t id; // 0x00 + uint8_t extension; // 0x00 + uint16_t length; // 0x01 + uint8_t data; +} OEMCrypto_DTCP2_CMI_Descriptor_0; + +/** + * Used to specify information about CMI Descriptor 1. + * @param id: ID value of CMI Descriptor assigned by DTLA. + * @param extension: specified by the CMI descriptor + * @param length: byte length of the usage rules field. + * @param data: usage rules data. + */ +typedef struct { + uint8_t id; // 0x01 + uint8_t extension; // 0x00 + uint16_t length; // 0x03 + uint8_t data[3]; +} OEMCrypto_DTCP2_CMI_Descriptor_1; + +/** + * Used to specify information about CMI Descriptor 2. + * @param id: ID value of CMI Descriptor assigned by DTLA. + * @param extension: specified by the CMI descriptor + * @param length: byte length of the usage rules field. + * @param data: usage rules data. + */ +typedef struct { + uint8_t id; // 0x02 + uint8_t extension; // 0x00 + uint16_t length; // 0x03 + uint8_t data[3]; +} OEMCrypto_DTCP2_CMI_Descriptor_2; + +/** + * Used to specify the required DTCP2 level. If dtcp2_required is 0, there are + * no requirements on any of the keys. If dtcp2_required is 1, any key with the + * kControlHDCPRequired bit set requires DTCP2 in its output. + * @param dtcp2_required: specifies whether dtcp2 is required. 0 = not required, + * 1 = DTCP2 required. + * @param cmi_descriptor_1: three bytes of CMI descriptor 1 + */ +typedef struct { + uint8_t dtcp2_required; // 0 = not required. 1 = DTCP2 v1 required. + OEMCrypto_DTCP2_CMI_Descriptor_0 cmi_descriptor_0; + OEMCrypto_DTCP2_CMI_Descriptor_1 cmi_descriptor_1; + OEMCrypto_DTCP2_CMI_Descriptor_2 cmi_descriptor_2; +} OEMCrypto_DTCP2_CMI_Packet; + /** * Points to the relevant fields for a content key. The fields are extracted * from the License Response message offered to OEMCrypto_LoadKeys(). Each diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h new file mode 100644 index 0000000..d66b95e --- /dev/null +++ b/oemcrypto/odk/include/core_message_features.h @@ -0,0 +1,44 @@ +// Copyright 2021 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_ +#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_ + +#include + +#include +#include + +namespace oemcrypto_core_message { +namespace features { + +// Features that may be supported by core messages. By restricting values in +// this structure, we can turn off features at runtime. This is plain data, and +// is essentially a version number. +struct CoreMessageFeatures { + // A default set of features. + static const CoreMessageFeatures kDefaultFeatures; + + // Create the default feature set for the given major version number. + static CoreMessageFeatures DefaultFeatures(uint32_t maximum_major_version); + + // This is the published version of the ODK Core Message library. The default + // behavior is for the server to restrict messages to at most this version + // number. The default is 16.5, the last version used by Chrome. This will + // change to 17.0 when v17 has been released. + uint32_t maximum_major_version = 16; + uint32_t maximum_minor_version = 5; + + bool operator==(const CoreMessageFeatures &other) const; + bool operator!=(const CoreMessageFeatures &other) const { + return !(*this == other); + } +}; + +std::ostream &operator<<(std::ostream &os, const CoreMessageFeatures &features); + +} // namespace features +} // namespace oemcrypto_core_message + +#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_ diff --git a/oemcrypto/odk/include/core_message_serialize.h b/oemcrypto/odk/include/core_message_serialize.h index 781259a..0e1c287 100644 --- a/oemcrypto/odk/include/core_message_serialize.h +++ b/oemcrypto/odk/include/core_message_serialize.h @@ -17,23 +17,27 @@ #ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ #define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ +#include "core_message_features.h" #include "core_message_types.h" #include "odk_structs.h" namespace oemcrypto_core_message { namespace serialize { +using oemcrypto_core_message::features::CoreMessageFeatures; /** * Counterpart (serializer) of ODK_ParseLicense (deserializer) * struct-input variant * * Parameters: + * [in] features feature support for response message. * [in] parsed_lic * [in] core_request * [in] core_request_sha256 * [out] oemcrypto_core_message */ -bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, +bool CreateCoreLicenseResponse(const CoreMessageFeatures& features, + const ODK_ParsedLicense& parsed_lic, const ODK_LicenseRequest& core_request, const std::string& core_request_sha256, std::string* oemcrypto_core_message); @@ -42,11 +46,13 @@ bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, * Counterpart (serializer) of ODK_ParseRenewal (deserializer) * * Parameters: + * [in] features feature support for response message. * [in] core_request * [in] renewal_duration_seconds * [out] oemcrypto_core_message */ -bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, +bool CreateCoreRenewalResponse(const CoreMessageFeatures& features, + const ODK_RenewalRequest& core_request, uint64_t renewal_duration_seconds, std::string* oemcrypto_core_message); @@ -55,11 +61,13 @@ bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, * struct-input variant * * Parameters: + * [in] features feature support for response message. * [in] parsed_prov * [in] core_request * [out] oemcrypto_core_message */ -bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, +bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features, + const ODK_ParsedProvisioning& parsed_prov, const ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message); } // namespace serialize diff --git a/oemcrypto/odk/include/core_message_serialize_proto.h b/oemcrypto/odk/include/core_message_serialize_proto.h index ce5df09..de75362 100644 --- a/oemcrypto/odk/include/core_message_serialize_proto.h +++ b/oemcrypto/odk/include/core_message_serialize_proto.h @@ -17,41 +17,46 @@ #include #include +#include "core_message_features.h" #include "core_message_types.h" #include "license_protocol.pb.h" namespace oemcrypto_core_message { namespace serialize { - // @ public create response (serializer) functions accepting proto input /** * Counterpart (serializer) of ODK_ParseLicense (deserializer) * * Parameters: + * [in] features feature support for response message. * [in] serialized_license serialized video_widevine::License * [in] core_request oemcrypto core message from request. * [in] core_request_sha256 - hash of serialized core request. * [in] nonce_required - if the device should require a nonce match. + * [in] uses_padding - if the keys use padding. * [out] oemcrypto_core_message - the serialized oemcrypto core response. */ -bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, - const ODK_LicenseRequest& core_request, - const std::string& core_request_sha256, - const bool nonce_required, - std::string* oemcrypto_core_message); +bool CreateCoreLicenseResponseFromProto( + const oemcrypto_core_message::features::CoreMessageFeatures& features, + const std::string& serialized_license, + const ODK_LicenseRequest& core_request, + const std::string& core_request_sha256, const bool nonce_required, + const bool uses_padding, std::string* oemcrypto_core_message); /** * Counterpart (serializer) of ODK_ParseProvisioning (deserializer) * * Parameters: + * [in] features feature support for response message. * [in] serialized_provisioning_response * serialized video_widevine::ProvisioningResponse * [in] core_request * [out] oemcrypto_core_message */ bool CreateCoreProvisioningResponseFromProto( + const oemcrypto_core_message::features::CoreMessageFeatures& features, const std::string& serialized_provisioning_response, const ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message); diff --git a/oemcrypto/odk/include/odk.h b/oemcrypto/odk/include/odk.h index 4f0c9f6..b412a7d 100644 --- a/oemcrypto/odk/include/odk.h +++ b/oemcrypto/odk/include/odk.h @@ -132,11 +132,11 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, * This function sets the values in the clock_values structure. It shall be * called from OEMCrypto_LoadUsageEntry. When a usage entry from a v15 or * earlier license is loaded, the value time_of_license_loaded shall be used - * in place of time_of_license_signed. + * in place of time_of_license_request_signed. * * @param[in,out] clock_values: the session's clock data. - * @param[in] time_of_license_signed: the value time_license_received from the - * loaded usage entry. + * @param[in] time_of_license_request_signed: the value time_license_received + * from the loaded usage entry. * @param[in] time_of_first_decrypt: the value time_of_first_decrypt from the * loaded usage entry. * @param[in] time_of_last_decrypt: the value time_of_last_decrypt from the @@ -152,7 +152,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, * This method is new in version 16 of the API. */ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values, - uint64_t time_of_license_signed, + uint64_t time_of_license_request_signed, uint64_t time_of_first_decrypt, uint64_t time_of_last_decrypt, enum OEMCrypto_Usage_Entry_Status status, @@ -469,8 +469,6 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, * and false when called for OEMCrypto_ReloadLicense. * @param[in] usage_entry_present: true if the session has a new usage entry * associated with it created via OEMCrypto_CreateNewUsageEntry. - * @param[in] request_hash: the hash of the license request core message. This - * was computed by OEMCrypto when the license request was signed. * @param[in,out] timer_limits: The session's timer limits. These will be * updated. * @param[in,out] clock_values: The session's clock values. These will be @@ -492,7 +490,6 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, OEMCryptoResult ODK_ParseLicense( const uint8_t* message, size_t message_length, size_t core_message_length, bool initial_license_load, bool usage_entry_present, - const uint8_t request_hash[ODK_SHA256_HASH_SIZE], ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license); diff --git a/oemcrypto/odk/include/odk_attributes.h b/oemcrypto/odk/include/odk_attributes.h index bbb81d8..72321b1 100644 --- a/oemcrypto/odk/include/odk_attributes.h +++ b/oemcrypto/odk/include/odk_attributes.h @@ -6,9 +6,9 @@ #define WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_ #if defined(__GNUC__) || defined(__clang__) -# define UNUSED __attribute__((__unused__)) +#define UNUSED __attribute__((__unused__)) #else -# define UNUSED +#define UNUSED #endif #endif // WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_ diff --git a/oemcrypto/odk/include/odk_message.h b/oemcrypto/odk/include/odk_message.h new file mode 100644 index 0000000..94ce2ae --- /dev/null +++ b/oemcrypto/odk/include/odk_message.h @@ -0,0 +1,141 @@ +// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ +#define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* + * ODK_Message is the structure that defines the serialized messages passed + * between the REE and TEE. ODK_Message is an abstract data type that represents + * the concept of a message without disclosing the implementation details. By + * hiding the internal structure, modification of the message fields by code + * that is not privy to the message definition can be prevented. If the message + * definition was exposed, there could be serious yet subtle errors in message + * manipulation anywhere in the code base. By restricting message modification + * it is possible to enforce validity and integrity with a small set of + * primitives that can be carefully reviewed. Checks can be added to verify that + * a message's fields are internally consistent before every operation. As an + * example, it can be guaranteed that the message status will be checked prior + * to accessing any field so parsing will be stopped when the message status is + * set after any parse error is detected. This also makes development easier + * since any access to the message structure can be tracked through a single + * point so, for example, it becomes possible to add trace statements globally + * to all message operations by only changing the field accessors. Finally it + * simplifies maintenance by localizing changes to the message structure to a + * few files. + */ + +#if defined(__GNUC__) || defined(__clang__) +#define ALIGNED __attribute__((aligned)) +#else +#define ALIGNED +#error ODK_Message must be aligned to the maximum useful alignment of the \ + machine you are compiling for. Define the ALIGNED macro accordingly. +#endif + +typedef struct { +#define SIZE_OF_ODK_MESSAGE_IMPL 64 + uint8_t opaque_data[SIZE_OF_ODK_MESSAGE_IMPL]; +} ALIGNED ODK_Message; + +typedef enum { + MESSAGE_STATUS_OK = 0xe937fcf7, + MESSAGE_STATUS_UNKNOWN_ERROR = 0xe06c1190, + MESSAGE_STATUS_OVERFLOW_ERROR = 0xc43ae4bc, + MESSAGE_STATUS_UNDERFLOW_ERROR = 0x7123cd0b, + MESSAGE_STATUS_PARSE_ERROR = 0x0b9f6189, + MESSAGE_STATUS_NULL_POINTER_ERROR = 0x2d66837a, + MESSAGE_STATUS_API_VALUE_ERROR = 0x6ba34f47, + MESSAGE_STATUS_END_OF_MESSAGE_ERROR = 0x998db72a, + MESSAGE_STATUS_INVALID_ENUM_VALUE = 0xedb88197, + MESSAGE_STATUS_INVALID_TAG_ERROR = 0x14dce06a, + MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6, + MESSAGE_STATUS_OUT_OF_MEMORY = 0xfc5c64cc, + MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0xfafecacf, + MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873 +} ODK_MessageStatus; + +/* + * Create a message structure that references a separate data buffer. An + * initialized message is returned. The caller is responsible for ensuring that + * the buffer remains allocated for the lifetime of the message. If |buffer| + * is NULL or |capacity| is zero, the message is invalid and the status + * will be set to MESSAGE_STATUS_NOT_INITIALIZED. + */ +ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity); + +/* + * Erase the contents of the message, set it to an empty state by setting the + * message size and read offset to 0, effectively erasing the contents of the + * message. The message data buffer pointer remains unchanged, i.e. the message + * retains ownership of the buffer. The message status is reset to + * MESSAGE_STATUS_OK. + */ +void ODK_Message_Clear(ODK_Message* message); + +/* + * Reset read pointer to the beginning of the message and clear status + * so that parsing of the message will restart at the beginning of the + * message. The message status is reset to MESSAGE_STATUS_OK. + */ +void ODK_Message_Reset(ODK_Message* message); + +/* + * Return a pointer to the message data buffer, i.e. the message payload. + * This is the buffer address that was passed into ODK_Message_Create. + */ +uint8_t* ODK_Message_GetBase(ODK_Message* message); + +/* + * Get the maximum number of bytes the message can hold. + */ +size_t ODK_Message_GetCapacity(ODK_Message* message); + +/* + * Get the number of bytes currently in the message + */ +size_t ODK_Message_GetSize(ODK_Message* message); + +/* + * Get the offset of where the next bytes will be read from the message data + * buffer. + */ +size_t ODK_Message_GetOffset(ODK_Message* message); + +/* + * Return the status of the message + */ +ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message); + +/* + * Set the message status to a specific value + */ +void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status); + +/* + * Set the size of the message to a value. This may be needed after writing data + * into the message data buffer. + */ +void ODK_Message_SetSize(ODK_Message* message, size_t size); + +/* + * Test if the integrity of a message. This means that the status must be + * MESSAGE_STATUS_OK and that the internal fields of the message are + * within the range of valid values. + */ +bool ODK_Message_IsValid(ODK_Message* message); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index 34eb332..9c41fc7 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -5,17 +5,21 @@ #ifndef WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ #define WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ +#ifdef __cplusplus +extern "C" { +#endif + #include #include "OEMCryptoCENCCommon.h" #include "odk_target.h" /* The version of this library. */ -#define ODK_MAJOR_VERSION 16 -#define ODK_MINOR_VERSION 4 +#define ODK_MAJOR_VERSION 17 +#define ODK_MINOR_VERSION 0 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v16.4 2020-10-07" +#define ODK_RELEASE_DATE "ODK v17.0 2021-11-15" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 @@ -85,9 +89,9 @@ typedef struct { * on OEMCrypto's system clock, as described in the document "License * Duration and Renewal". * - * @param time_of_license_signed: Time that the license request was signed, - * based on OEMCrypto's system clock. This value shall be stored and - * reloaded with usage entry as time_of_license_received. + * @param time_of_license_request_signed: Time that the license request was + * signed, based on OEMCrypto's system clock. This value shall be stored + * and reloaded with usage entry as time_of_license_received. * @param time_of_first_decrypt: Time of the first decrypt or call select key, * based on OEMCrypto's system clock. This is 0 if the license has not * been used to decrypt any data. This value shall be stored and reloaded @@ -110,7 +114,7 @@ typedef struct { * This struct changed in API version 16.2. */ typedef struct { - uint64_t time_of_license_signed; + uint64_t time_of_license_request_signed; uint64_t time_of_first_decrypt; uint64_t time_of_last_decrypt; uint64_t time_of_renewal_request; @@ -171,11 +175,13 @@ typedef struct { * entitlement keys. * @param nonce_required: indicates if the license requires a nonce. * @param timer_limits: time limits of the for the license. + * @param watermarking: specifies if device supports watermarking. + * @param dtcp2_required: specifies if device supports DTCP. * @param key_array_length: number of keys present. * @param key_array: set of keys to be installed. * * @version - * This struct changed in API version 16.2. + * This struct changed in API version 17. */ typedef struct { OEMCrypto_Substring enc_mac_keys_iv; @@ -185,6 +191,8 @@ typedef struct { OEMCrypto_LicenseType license_type; bool nonce_required; ODK_TimerLimits timer_limits; + uint32_t watermarking; + OEMCrypto_DTCP2_CMI_Packet dtcp2_required; uint32_t key_array_length; OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS]; } ODK_ParsedLicense; @@ -212,4 +220,8 @@ typedef struct { /// @} +#ifdef __cplusplus +} // extern "C" +#endif + #endif // WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ diff --git a/oemcrypto/odk/src/core_message_deserialize.cpp b/oemcrypto/odk/src/core_message_deserialize.cpp index ebf0add..9f485d5 100644 --- a/oemcrypto/odk/src/core_message_deserialize.cpp +++ b/oemcrypto/odk/src/core_message_deserialize.cpp @@ -39,13 +39,11 @@ bool ParseRequest(uint32_t message_type, reinterpret_cast(oemcrypto_core_message.c_str()); const size_t buf_length = oemcrypto_core_message.size(); - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = reinterpret_cast(blk); - InitMessage(msg, const_cast(buf), buf_length); - SetSize(msg, buf_length); + ODK_Message msg = ODK_Message_Create(const_cast(buf), buf_length); + ODK_Message_SetSize(&msg, buf_length); - unpacker(msg, prepared); - if (!ValidMessage(msg)) { + unpacker(&msg, prepared); + if (!ODK_Message_IsValid(&msg)) { return false; } @@ -62,7 +60,7 @@ bool ParseRequest(uint32_t message_type, } else if (core_request->api_major_version == 16) { // For version 16, we demand a minor version of at least 2. // We accept 16.2, 16.3, or higher. - if (core_request->api_major_version < 2) return false; + if (core_request->api_minor_version < 2) return false; } else { // Other versions do not (yet) have a restriction on minor number. // In particular, future versions are accepted for forward compatibility. @@ -80,7 +78,7 @@ bool ParseRequest(uint32_t message_type, // than the total message size. We allow the total message size to be larger // for forward compatibility because future messages might have extra fields // that we can ignore. - if (core_message.message_length < GetOffset(msg)) return false; + if (core_message.message_length < ODK_Message_GetOffset(&msg)) return false; return true; } diff --git a/oemcrypto/odk/src/core_message_features.cpp b/oemcrypto/odk/src/core_message_features.cpp new file mode 100644 index 0000000..c28622c --- /dev/null +++ b/oemcrypto/odk/src/core_message_features.cpp @@ -0,0 +1,41 @@ +// Copyright 2021 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#include "core_message_features.h" + +namespace oemcrypto_core_message { +namespace features { +const CoreMessageFeatures CoreMessageFeatures::kDefaultFeatures; + +bool CoreMessageFeatures::operator==(const CoreMessageFeatures &other) const { + return maximum_major_version == other.maximum_major_version && + maximum_minor_version == other.maximum_minor_version; +} + +CoreMessageFeatures CoreMessageFeatures::DefaultFeatures( + uint32_t maximum_major_version) { + CoreMessageFeatures features; + features.maximum_major_version = maximum_major_version; + // The default minor version is the highest for each major version. + switch (maximum_major_version) { + case 16: + features.maximum_minor_version = 5; // 16.5 + break; + case 17: + features.maximum_minor_version = 0; // 17.0 + break; + default: + features.maximum_minor_version = 0; + } + return features; +} + +std::ostream &operator<<(std::ostream &os, + const CoreMessageFeatures &features) { + return os << "v" << features.maximum_major_version << "." + << features.maximum_minor_version; +} + +} // namespace features +} // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/src/core_message_serialize.cpp b/oemcrypto/odk/src/core_message_serialize.cpp index 6003d71..334f442 100644 --- a/oemcrypto/odk/src/core_message_serialize.cpp +++ b/oemcrypto/odk/src/core_message_serialize.cpp @@ -20,18 +20,22 @@ namespace serialize { namespace { /** - * Template for parsing requests + * Template for copying nonce values from request to response, and also + * computing the API version of the response. * * Template arguments: * T: struct to be deserialized by odk * S: kdo input struct - * P: auto-generated serializing function for |T| */ -template -bool CreateResponse(uint32_t message_type, const S& core_request, - std::string* oemcrypto_core_message, T& response, - const P& packer) { - if (!oemcrypto_core_message) { +template +bool CreateResponseHeader(const CoreMessageFeatures& features, + ODK_MessageType message_type, const S& core_request, + T& response) { + // Bad major version. + if ((features.maximum_major_version > ODK_MAJOR_VERSION) || + (features.maximum_major_version == ODK_MAJOR_VERSION && + features.maximum_minor_version > ODK_MINOR_VERSION)) { + // TODO(b/147513335): this should be logged. return false; } @@ -43,25 +47,50 @@ bool CreateResponse(uint32_t message_type, const S& core_request, header->nonce_values.session_id = core_request.session_id; // The message API version for the response is the minimum of our version and // the request's version. - if (core_request.api_major_version > ODK_MAJOR_VERSION) { - header->nonce_values.api_major_version = ODK_MAJOR_VERSION; - header->nonce_values.api_minor_version = ODK_MINOR_VERSION; + if (core_request.api_major_version > features.maximum_major_version) { + header->nonce_values.api_major_version = features.maximum_major_version; + header->nonce_values.api_minor_version = features.maximum_minor_version; + } else if (core_request.api_major_version == features.maximum_major_version && + core_request.api_minor_version > features.maximum_minor_version) { + header->nonce_values.api_minor_version = features.maximum_minor_version; + } + return true; +} + +/** + * Template for parsing requests and packing response + * + * Template arguments: + * T: struct to be deserialized by odk + * S: kdo input struct + * P: auto-generated serializing function for |T| + */ +template +bool CreateResponse(ODK_MessageType message_type, const S& core_request, + std::string* oemcrypto_core_message, T& response, + const P& packer) { + if (!oemcrypto_core_message) { + return false; + } + auto* header = &response.request.core_message; + if (header->message_type != message_type || + header->nonce_values.api_major_version < ODK_FIRST_VERSION) { + // This indicates CreateResponseHeader was not called. + return false; } static constexpr size_t BUF_CAPACITY = 2048; std::vector buf(BUF_CAPACITY, 0); - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = reinterpret_cast(blk); - InitMessage(msg, buf.data(), buf.capacity()); - packer(msg, &response); - if (!ValidMessage(msg)) { + ODK_Message msg = ODK_Message_Create(buf.data(), buf.capacity()); + packer(&msg, &response); + if (!ODK_Message_IsValid(&msg)) { return false; } - uint32_t message_length = GetSize(msg); - InitMessage(msg, buf.data() + sizeof(header->message_type), - sizeof(header->message_length)); - Pack_uint32_t(msg, &message_length); + uint32_t message_length = static_cast(ODK_Message_GetSize(&msg)); + msg = ODK_Message_Create(buf.data() + sizeof(header->message_type), + sizeof(header->message_length)); + Pack_uint32_t(&msg, &message_length); oemcrypto_core_message->assign(reinterpret_cast(buf.data()), message_length); return true; @@ -74,7 +103,7 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src, if (request.device_id_length > sizeof(request.device_id)) { return false; } - request.device_id_length = device_id.size(); + request.device_id_length = static_cast(device_id.size()); memset(request.device_id, 0, sizeof(request.device_id)); memcpy(request.device_id, device_id.data(), request.device_id_length); return true; @@ -82,33 +111,73 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src, } // namespace -bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, +bool CreateCoreLicenseResponse(const CoreMessageFeatures& features, + const ODK_ParsedLicense& parsed_lic, const ODK_LicenseRequest& core_request, const std::string& core_request_sha256, std::string* oemcrypto_core_message) { ODK_LicenseResponse license_response{ - {}, const_cast(&parsed_lic), {0}}; - if (core_request_sha256.size() != sizeof(license_response.request_hash)) + {}, const_cast(&parsed_lic)}; + if (!CreateResponseHeader(features, ODK_License_Response_Type, core_request, + license_response)) { return false; - memcpy(license_response.request_hash, core_request_sha256.data(), - sizeof(license_response.request_hash)); + } + if (license_response.request.core_message.nonce_values.api_major_version == + 16) { + ODK_LicenseResponseV16 license_response_v16; + license_response_v16.request = license_response.request; + license_response_v16.parsed_license.enc_mac_keys_iv = + license_response.parsed_license->enc_mac_keys_iv; + license_response_v16.parsed_license.enc_mac_keys = + license_response.parsed_license->enc_mac_keys; + license_response_v16.parsed_license.pst = + license_response.parsed_license->pst; + license_response_v16.parsed_license.srm_restriction_data = + license_response.parsed_license->srm_restriction_data; + license_response_v16.parsed_license.license_type = + license_response.parsed_license->license_type; + license_response_v16.parsed_license.nonce_required = + license_response.parsed_license->nonce_required; + license_response_v16.parsed_license.timer_limits = + license_response.parsed_license->timer_limits; + license_response_v16.parsed_license.key_array_length = + license_response.parsed_license->key_array_length; + uint32_t i; + for (i = 0; i < license_response_v16.parsed_license.key_array_length; i++) { + license_response_v16.parsed_license.key_array[i] = + license_response.parsed_license->key_array[i]; + } + if (core_request_sha256.size() != sizeof(license_response_v16.request_hash)) + return false; + memcpy(license_response_v16.request_hash, core_request_sha256.data(), + sizeof(license_response_v16.request_hash)); + return CreateResponse(ODK_License_Response_Type, core_request, + oemcrypto_core_message, license_response_v16, + Pack_ODK_LicenseResponseV16); + } return CreateResponse(ODK_License_Response_Type, core_request, oemcrypto_core_message, license_response, Pack_ODK_LicenseResponse); } -bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, +bool CreateCoreRenewalResponse(const CoreMessageFeatures& features, + const ODK_RenewalRequest& core_request, uint64_t renewal_duration_seconds, std::string* oemcrypto_core_message) { ODK_RenewalResponse renewal_response{{}, core_request.playback_time_seconds}; renewal_response.request.playback_time = core_request.playback_time_seconds; renewal_response.renewal_duration_seconds = renewal_duration_seconds; + if (!CreateResponseHeader(features, ODK_Renewal_Response_Type, core_request, + renewal_response)) { + return false; + } return CreateResponse(ODK_Renewal_Response_Type, core_request, oemcrypto_core_message, renewal_response, Pack_ODK_RenewalResponse); } -bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, +bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features, + const ODK_ParsedProvisioning& parsed_prov, const ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message) { ODK_ProvisioningResponse prov_response{ @@ -116,6 +185,10 @@ bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, if (!CopyDeviceId(core_request, &prov_response)) { return false; } + if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type, + core_request, prov_response)) { + return false; + } return CreateResponse(ODK_Provisioning_Response_Type, core_request, oemcrypto_core_message, prov_response, Pack_ODK_ProvisioningResponse); diff --git a/oemcrypto/odk/src/core_message_serialize_proto.cpp b/oemcrypto/odk/src/core_message_serialize_proto.cpp index 224f817..860ea26 100644 --- a/oemcrypto/odk/src/core_message_serialize_proto.cpp +++ b/oemcrypto/odk/src/core_message_serialize_proto.cpp @@ -20,6 +20,7 @@ namespace oemcrypto_core_message { namespace serialize { namespace { +using oemcrypto_core_message::features::CoreMessageFeatures; /* @ private functions */ @@ -41,17 +42,23 @@ OEMCrypto_Substring GetOecSubstring(const std::string& message, } OEMCrypto_KeyObject KeyContainerToOecKey( - const std::string& proto, const video_widevine::License::KeyContainer& k) { + const std::string& proto, const video_widevine::License::KeyContainer& k, + const bool uses_padding) { OEMCrypto_KeyObject obj = {}; obj.key_id = GetOecSubstring(proto, k.id()); obj.key_data_iv = GetOecSubstring(proto, k.iv()); - // Strip off PKCS#5 padding - since we know the key is 16 or 32 bytes, - // the padding will always be 16 bytes. - const std::string& key_data = k.key(); - const size_t PKCS5_PADDING_SIZE = 16; - obj.key_data = GetOecSubstring( - proto, key_data.substr(0, std::max(PKCS5_PADDING_SIZE, key_data.size()) - - PKCS5_PADDING_SIZE)); + + OEMCrypto_Substring key_data = GetOecSubstring(proto, k.key()); + + // Strip off PKCS#5 padding. A key can either be 16 of 32 bytes, but that + // makes it hard to know if a key (when 32 bytes) is a 16 byte key with + // padding or a 32 byte key without padding. + if (uses_padding) { + const size_t PKCS5_PADDING_SIZE = 16; + key_data.length -= PKCS5_PADDING_SIZE; + } + obj.key_data = key_data; + if (k.has_key_control()) { const auto& key_control = k.key_control(); obj.key_control_iv = GetOecSubstring(proto, key_control.iv()); @@ -64,10 +71,12 @@ OEMCrypto_KeyObject KeyContainerToOecKey( // @ public create response functions -bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, +bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features, + const std::string& serialized_license, const ODK_LicenseRequest& core_request, const std::string& core_request_sha256, const bool nonce_required, + const bool uses_padding, std::string* oemcrypto_core_message) { video_widevine::License lic; if (!lic.ParseFromString(serialized_license)) { @@ -102,7 +111,8 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, return false; } uint32_t& n = parsed_lic.key_array_length; - parsed_lic.key_array[n++] = KeyContainerToOecKey(serialized_license, k); + parsed_lic.key_array[n++] = + KeyContainerToOecKey(serialized_license, k, uses_padding); break; } default: { @@ -125,12 +135,13 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, parsed_lic.pst = GetOecSubstring(serialized_license, lid.provider_session_token()); } - if (lic.has_srm_requirement()) { parsed_lic.srm_restriction_data = GetOecSubstring(serialized_license, lic.srm_requirement()); } - + if (lic.policy().has_watermarking_control()) { + parsed_lic.watermarking = lic.policy().watermarking_control(); + } parsed_lic.nonce_required = nonce_required; const auto& policy = lic.policy(); ODK_TimerLimits& timer_limits = parsed_lic.timer_limits; @@ -146,11 +157,12 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, policy.renewal_delay_seconds() + policy.renewal_recovery_duration_seconds(); - return CreateCoreLicenseResponse(parsed_lic, core_request, + return CreateCoreLicenseResponse(features, parsed_lic, core_request, core_request_sha256, oemcrypto_core_message); } bool CreateCoreProvisioningResponseFromProto( + const CoreMessageFeatures& features, const std::string& serialized_provisioning_resp, const ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message) { @@ -175,7 +187,7 @@ bool CreateCoreProvisioningResponseFromProto( GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key()); } - return CreateCoreProvisioningResponse(parsed_prov, core_request, + return CreateCoreProvisioningResponse(features, parsed_prov, core_request, oemcrypto_core_message); } diff --git a/oemcrypto/odk/src/kdo.gypi b/oemcrypto/odk/src/kdo.gypi index 6e9fb46..6e77b45 100644 --- a/oemcrypto/odk/src/kdo.gypi +++ b/oemcrypto/odk/src/kdo.gypi @@ -7,6 +7,7 @@ { 'sources': [ 'core_message_deserialize.cpp', + 'core_message_features.cpp', 'core_message_serialize.cpp', 'core_message_serialize_proto.cpp', ], diff --git a/oemcrypto/odk/src/odk.c b/oemcrypto/odk/src/odk.c index b404d48..6cb476e 100644 --- a/oemcrypto/odk/src/odk.c +++ b/oemcrypto/odk/src/odk.c @@ -27,9 +27,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = (Message*)blk; - InitMessage(msg, message, *core_message_length); + ODK_Message msg = ODK_Message_Create(message, *core_message_length); /* The core message should be at the beginning of the buffer, and with a * shorter length. */ @@ -52,7 +50,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } Pack_ODK_PreparedLicenseRequest( - msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer); + &msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer); break; } case ODK_Renewal_Request_Type: { @@ -61,7 +59,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } Pack_ODK_PreparedRenewalRequest( - msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer); + &msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer); break; } case ODK_Provisioning_Request_Type: { @@ -71,7 +69,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } Pack_ODK_PreparedProvisioningRequest( - msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer); + &msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer); break; } default: { @@ -80,86 +78,78 @@ static OEMCryptoResult ODK_PrepareRequest( } *core_message_length = core_message->message_length; - if (GetStatus(msg) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK) { /* This is to indicate the caller that the core_message_length has been * appropriately set, but the message buffer is either empty or too small, * which needs to be initialized and filled in the subsequent call. */ return OEMCrypto_ERROR_SHORT_BUFFER; } - if (GetSize(msg) != *core_message_length) { + if (ODK_Message_GetSize(&msg) != *core_message_length) { /* This should not happen. Something is wrong. */ return ODK_ERROR_CORE_MESSAGE; } return OEMCrypto_SUCCESS; } -static OEMCryptoResult ODK_ParseResponse( - const uint8_t* message, size_t message_length, size_t core_message_length, - ODK_MessageType message_type, const ODK_NonceValues* nonce_values, - void* response_buffer, uint32_t response_buffer_length) { - if (message == NULL || response_buffer == NULL || - core_message_length > message_length) { +/* Parse the core message and verify that it has the right type. The nonce + * values are updated to hold the resposne's API version. + */ +static OEMCryptoResult ODK_ParseCoreHeader(const uint8_t* message, + size_t message_length, + size_t core_message_length, + ODK_MessageType message_type, + ODK_NonceValues* nonce_values) { + // The core_message_length is the length of the core message, which is a + // substring of the complete message. + if (message == NULL || core_message_length > message_length) { return ODK_ERROR_CORE_MESSAGE; } + ODK_CoreMessage core_message; + ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = (Message*)blk; + /* The core message should be at the beginning of the buffer. The core message + * is the part we are parsing. */ + ODK_Message_SetSize(&msg, core_message_length); + Unpack_ODK_CoreMessage(&msg, &core_message); -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" - /* We initialize the message buffer with a size of the entire message - * length. */ - /* TODO(b/164486737): Fix the cast-qual warning */ - InitMessage(msg, (uint8_t*)message, message_length); -#pragma GCC diagnostic pop - - /* The core message should be at the beginning of the buffer, and with a - * shorter length. The core message is the part we are parsing. */ - SetSize(msg, core_message_length); - - /* Parse message and unpack it into response buffer. */ - switch (message_type) { - case ODK_License_Response_Type: { - if (sizeof(ODK_LicenseResponse) > response_buffer_length) { - return ODK_ERROR_CORE_MESSAGE; - } - Unpack_ODK_LicenseResponse(msg, (ODK_LicenseResponse*)response_buffer); - break; - } - case ODK_Renewal_Response_Type: { - if (sizeof(ODK_RenewalResponse) > response_buffer_length) { - return ODK_ERROR_CORE_MESSAGE; - } - Unpack_ODK_RenewalResponse(msg, (ODK_RenewalResponse*)response_buffer); - break; - } - case ODK_Provisioning_Response_Type: { - if (sizeof(ODK_ProvisioningResponse) > response_buffer_length) { - return ODK_ERROR_CORE_MESSAGE; - } - Unpack_ODK_ProvisioningResponse( - msg, (ODK_ProvisioningResponse*)response_buffer); - break; - } - default: { - return ODK_ERROR_CORE_MESSAGE; - } - } - - ODK_CoreMessage* core_message = (ODK_CoreMessage*)response_buffer; - if (GetStatus(msg) != MESSAGE_STATUS_OK || - message_type != core_message->message_type || - GetOffset(msg) != core_message->message_length) { + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + message_type != core_message.message_type) { return ODK_ERROR_CORE_MESSAGE; } - + // The current offset should be the end of the header, which is the message + // type, message length, api version, and nonce fields. The header can't be + // larger than the whole core message. Also, the core message specifies its + // length, which should be exactly the length of the core message buffer. + if (ODK_Message_GetOffset(&msg) > core_message.message_length || + core_message.message_length != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } + /* We do not support future API version. Also, this function should not be + * used for legacy licenses without a core message. */ + if (core_message.nonce_values.api_major_version > ODK_MAJOR_VERSION || + core_message.nonce_values.api_major_version < ODK_FIRST_VERSION) { + return ODK_UNSUPPORTED_API; + } if (nonce_values) { - /* always verify nonce_values for Renewal and Provisioning responses */ - if (!ODK_NonceValuesEqual(nonce_values, &(core_message->nonce_values))) { - return OEMCrypto_ERROR_INVALID_NONCE; + /* If the server sent us an older format, record the message's API version. + */ + if (nonce_values->api_major_version > + core_message.nonce_values.api_major_version) { + // If the major version is smaller, use both values from the server. + nonce_values->api_major_version = + core_message.nonce_values.api_major_version; + nonce_values->api_minor_version = + core_message.nonce_values.api_minor_version; + } else if (nonce_values->api_major_version == + core_message.nonce_values.api_major_version && + nonce_values->api_minor_version > + core_message.nonce_values.api_minor_version) { + // Otherwise, if the major versions are equal, but the minor is smaller, + // then we should lower the minor version. + nonce_values->api_minor_version = + core_message.nonce_values.api_minor_version; } } - return OEMCrypto_SUCCESS; } @@ -259,47 +249,88 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( OEMCryptoResult ODK_ParseLicense( const uint8_t* message, size_t message_length, size_t core_message_length, bool initial_license_load, bool usage_entry_present, - const uint8_t* request_hash, ODK_TimerLimits* timer_limits, - ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values, - ODK_ParsedLicense* parsed_license) { - if (message == NULL || request_hash == NULL || timer_limits == NULL || - clock_values == NULL || nonce_values == NULL || parsed_license == NULL) { + ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values, + ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license) { + if (message == NULL || timer_limits == NULL || clock_values == NULL || + nonce_values == NULL || parsed_license == NULL) { return ODK_ERROR_CORE_MESSAGE; } - ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL, {0}}; - license_response.parsed_license = parsed_license; - - const OEMCryptoResult err = ODK_ParseResponse( - message, message_length, core_message_length, ODK_License_Response_Type, - NULL, &license_response, sizeof(ODK_LicenseResponse)); - + const OEMCryptoResult err = + ODK_ParseCoreHeader(message, message_length, core_message_length, + ODK_License_Response_Type, nonce_values); if (err != OEMCrypto_SUCCESS) { return err; } - /* We do not support future API version. Also, this function should not be - * used for legacy licenses. */ - if (license_response.request.core_message.nonce_values.api_major_version > - ODK_MAJOR_VERSION || - license_response.request.core_message.nonce_values.api_major_version < - ODK_FIRST_VERSION) { - return ODK_UNSUPPORTED_API; + ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL}; + license_response.parsed_license = parsed_license; + + ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); + ODK_Message_SetSize(&msg, core_message_length); + if (nonce_values->api_major_version == 16) { + ODK_LicenseResponseV16 license_response_v16 = {{{0, 0, {}}}, {}, {0}}; + Unpack_ODK_LicenseResponseV16(&msg, &license_response_v16); + + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + ODK_Message_GetOffset(&msg) != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } + + // Need to manually set parsed_license fields to + // license_response_v16.parsed_license field values since + // license_response_v16 is no longer a pointer so parsed_license doesn't get + // updated during the unpacking. + parsed_license->enc_mac_keys_iv = + license_response_v16.parsed_license.enc_mac_keys_iv; + parsed_license->enc_mac_keys = + license_response_v16.parsed_license.enc_mac_keys; + parsed_license->pst = license_response_v16.parsed_license.pst; + parsed_license->srm_restriction_data = + license_response_v16.parsed_license.srm_restriction_data; + parsed_license->license_type = + license_response_v16.parsed_license.license_type; + parsed_license->nonce_required = + license_response_v16.parsed_license.nonce_required; + parsed_license->timer_limits = + license_response_v16.parsed_license.timer_limits; + parsed_license->key_array_length = + license_response_v16.parsed_license.key_array_length; + uint32_t i; + for (i = 0; i < parsed_license->key_array_length; i++) { + parsed_license->key_array[i] = + license_response_v16.parsed_license.key_array[i]; + } + // Set fields not used in V16 to default values. + parsed_license->watermarking = 0; + // Set fields not used in V16 to default values. + parsed_license->dtcp2_required.dtcp2_required = 0; + parsed_license->dtcp2_required.cmi_descriptor_0.id = 0; + parsed_license->dtcp2_required.cmi_descriptor_0.extension = 0; + parsed_license->dtcp2_required.cmi_descriptor_0.length = 1; + parsed_license->dtcp2_required.cmi_descriptor_0.data = 0; + parsed_license->dtcp2_required.cmi_descriptor_1.id = 1; + parsed_license->dtcp2_required.cmi_descriptor_1.extension = 0; + parsed_license->dtcp2_required.cmi_descriptor_1.length = 3; + parsed_license->dtcp2_required.cmi_descriptor_1.data[0] = 0; + parsed_license->dtcp2_required.cmi_descriptor_1.data[1] = 0; + parsed_license->dtcp2_required.cmi_descriptor_1.data[2] = 0; + parsed_license->dtcp2_required.cmi_descriptor_2.id = 2; + parsed_license->dtcp2_required.cmi_descriptor_2.extension = 0; + parsed_license->dtcp2_required.cmi_descriptor_2.length = 3; + parsed_license->dtcp2_required.cmi_descriptor_2.data[0] = 0; + parsed_license->dtcp2_required.cmi_descriptor_2.data[1] = 0; + parsed_license->dtcp2_required.cmi_descriptor_2.data[2] = 0; + license_response.request = license_response_v16.request; + } else { + Unpack_ODK_LicenseResponse(&msg, &license_response); + + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + ODK_Message_GetOffset(&msg) != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } } - /* If the server sent us an older format, record the license's API version. */ - if (nonce_values->api_major_version > - license_response.request.core_message.nonce_values.api_major_version) { - nonce_values->api_major_version = - license_response.request.core_message.nonce_values.api_major_version; - nonce_values->api_minor_version = - license_response.request.core_message.nonce_values.api_minor_version; - } else if (nonce_values->api_minor_version > - license_response.request.core_message.nonce_values - .api_minor_version) { - nonce_values->api_minor_version = - license_response.request.core_message.nonce_values.api_minor_version; - } /* If the license has a provider session token (pst), then OEMCrypto should * have a usage entry loaded. The opposite is also an error. */ if ((usage_entry_present && parsed_license->pst.length == 0) || @@ -326,15 +357,6 @@ OEMCryptoResult ODK_ParseLicense( nonce_values->session_id = license_response.request.core_message.nonce_values.session_id; } - /* For v16, in order to be backwards compatible with a v15 license server, - * OEMCrypto stores a hash of the core license request and only signs the - * message body. Here, when we process the license response, we verify that - * the server has the same hash of the core request. */ - if (initial_license_load && parsed_license->nonce_required && - crypto_memcmp(request_hash, license_response.request_hash, - ODK_SHA256_HASH_SIZE)) { - return ODK_ERROR_CORE_MESSAGE; - } *timer_limits = parsed_license->timer_limits; /* And update the clock values state. */ clock_values->timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED; @@ -353,16 +375,29 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, return ODK_ERROR_CORE_MESSAGE; } + const OEMCryptoResult err = + ODK_ParseCoreHeader(message, message_length, core_message_length, + ODK_Renewal_Response_Type, NULL); + if (err != OEMCrypto_SUCCESS) { + return err; + } ODK_RenewalResponse renewal_response = { {{0, 0, {}}, 0}, 0, }; - const OEMCryptoResult err = ODK_ParseResponse( - message, message_length, core_message_length, ODK_Renewal_Response_Type, - nonce_values, &renewal_response, sizeof(ODK_RenewalResponse)); + ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); + ODK_Message_SetSize(&msg, core_message_length); + Unpack_ODK_RenewalResponse(&msg, &renewal_response); - if (err != OEMCrypto_SUCCESS) { - return err; + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + ODK_Message_GetOffset(&msg) != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } + /* always verify nonce_values for Renewal and Provisioning responses */ + if (!ODK_NonceValuesEqualExcludingVersion( + nonce_values, + &(renewal_response.request.core_message.nonce_values))) { + return OEMCrypto_ERROR_INVALID_NONCE; } /* Reference: @@ -392,7 +427,12 @@ OEMCryptoResult ODK_ParseProvisioning( parsed_response == NULL) { return ODK_ERROR_CORE_MESSAGE; } - + const OEMCryptoResult err = + ODK_ParseCoreHeader(message, message_length, core_message_length, + ODK_Provisioning_Response_Type, NULL); + if (err != OEMCrypto_SUCCESS) { + return err; + } ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL}; provisioning_response.parsed_provisioning = parsed_response; @@ -400,13 +440,18 @@ OEMCryptoResult ODK_ParseProvisioning( return ODK_ERROR_CORE_MESSAGE; } - const OEMCryptoResult err = ODK_ParseResponse( - message, message_length, core_message_length, - ODK_Provisioning_Response_Type, nonce_values, &provisioning_response, - sizeof(ODK_ProvisioningResponse)); - - if (err != OEMCrypto_SUCCESS) { - return err; + ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); + ODK_Message_SetSize(&msg, core_message_length); + Unpack_ODK_ProvisioningResponse(&msg, &provisioning_response); + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || + ODK_Message_GetOffset(&msg) != core_message_length) { + return ODK_ERROR_CORE_MESSAGE; + } + /* always verify nonce_values for Renewal and Provisioning responses */ + if (!ODK_NonceValuesEqualExcludingVersion( + nonce_values, + &(provisioning_response.request.core_message.nonce_values))) { + return OEMCrypto_ERROR_INVALID_NONCE; } if (crypto_memcmp(device_id, provisioning_response.request.device_id, diff --git a/oemcrypto/odk/src/odk.gyp b/oemcrypto/odk/src/odk.gyp index d1c5a19..1bdd05c 100644 --- a/oemcrypto/odk/src/odk.gyp +++ b/oemcrypto/odk/src/odk.gyp @@ -14,9 +14,27 @@ 'includes' : [ 'odk.gypi', ], + 'cflags': [ + # TODO(b/172518513): Remove this + '-Wno-error=cast-qual', + ], + 'cflags_c': [ + # TODO(b/159354894): Remove this + '-Wno-error=bad-function-cast', + ], + 'defines': [ + # Needed for to work. + '_DEFAULT_SOURCE', + ], 'direct_dependent_settings': { + 'defines': [ + # Needed for to work. + '_DEFAULT_SOURCE', + ], 'include_dirs': [ + '.', '../include', + '../../include', ], } }, diff --git a/oemcrypto/odk/src/odk.gypi b/oemcrypto/odk/src/odk.gypi index 7c33d95..1867605 100644 --- a/oemcrypto/odk/src/odk.gypi +++ b/oemcrypto/odk/src/odk.gypi @@ -7,6 +7,7 @@ { 'sources': [ 'odk.c', + 'odk_message.c', 'odk_overflow.c', 'odk_serialize.c', 'odk_timer.c', diff --git a/oemcrypto/odk/src/odk_endian.h b/oemcrypto/odk/src/odk_endian.h index 459a095..1e9f50d 100644 --- a/oemcrypto/odk/src/odk_endian.h +++ b/oemcrypto/odk/src/odk_endian.h @@ -11,11 +11,23 @@ extern "C" { #if defined(__linux__) || defined(__ANDROID__) #include +#define oemcrypto_htobe16 htobe16 +#define oemcrypto_be16toh be16toh #define oemcrypto_htobe32 htobe32 #define oemcrypto_be32toh be32toh #define oemcrypto_htobe64 htobe64 #define oemcrypto_be64toh be64toh -#else /* defined(__linux__) || defined(__ANDROID__) */ +#elif defined(__APPLE__) +#include +#define oemcrypto_htobe16 OSSwapHostToBigInt16 +#define oemcrypto_be16toh OSSwapBigToHostInt16 +#define oemcrypto_htobe32 OSSwapHostToBigInt32 +#define oemcrypto_be32toh OSSwapBigToHostInt32 +#define oemcrypto_htobe64 OSSwapHostToBigInt64 +#define oemcrypto_be64toh OSSwapBigToHostInt64 +#else /* defined(__linux__) || defined(__ANDROID__) */ +uint32_t oemcrypto_htobe16(uint16_t u16); +uint32_t oemcrypto_be16toh(uint16_t u16); uint32_t oemcrypto_htobe32(uint32_t u32); uint32_t oemcrypto_be32toh(uint32_t u32); uint64_t oemcrypto_htobe64(uint64_t u64); diff --git a/oemcrypto/odk/src/odk_message.c b/oemcrypto/odk/src/odk_message.c new file mode 100644 index 0000000..df29d23 --- /dev/null +++ b/oemcrypto/odk/src/odk_message.c @@ -0,0 +1,170 @@ +// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#include "odk_message.h" + +#include +#include +#include + +#include "odk_message_priv.h" + +/* + * C11 defines static_assert in assert.h. If it is available, force a compile + * time error if the abstract ODK_Message struct size does not match its + * implementation. If static_assert is not available, the runtime assert in + * InitMessage will catch the mismatch at the time a message is initialized. + */ +#ifdef static_assert +static_assert( + sizeof(ODK_Message) >= sizeof(ODK_Message_Impl), + "sizeof(ODK_Message) is too small. You can increase " + "SIZE_OF_ODK_MESSAGE_IMPL in odk_message.h to make it large enough."); +#endif + +/* + * Create a message structure that references a separate data buffer. An + * initialized message is returned. The caller is responsible for ensuring that + * the buffer remains allocated for the lifetime of the message. |buffer| may be + * NULL. Serialization into a message with a NULL buffer will cause the message + * size to be incremented, but no data will be written into the message + * buffer. This is useful for calculating the amount of space a message will + * need, prior to doing the actual serialization. The buffer contents are + * unchanged by this function. + */ +ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) { + assert(sizeof(ODK_Message) >= sizeof(ODK_Message_Impl)); + ODK_Message message; + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message; + message_impl->base = buffer; + message_impl->capacity = capacity; + message_impl->size = 0; + message_impl->read_offset = 0; + message_impl->status = MESSAGE_STATUS_OK; + return message; +} + +/* + * Erase the contents of the message, set it to an empty state by setting the + * message size and read offset to 0, effectively erasing the contents of the + * message. The message data buffer pointer remains unchanged, i.e. the message + * retains ownership of the buffer. The message buffer is zero-filled. The + * message status is reset to MESSAGE_STATUS_OK. + */ +void ODK_Message_Clear(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + message_impl->read_offset = 0; + message_impl->size = 0; + message_impl->status = MESSAGE_STATUS_OK; + if (message_impl->base) { + memset(message_impl->base, 0, message_impl->capacity); + } +} + +/* + * Reset read pointer to the beginning of the message and clear status + * so that parsing of the message will restart at the beginning of the + * message. The message status is reset to MESSAGE_STATUS_OK. + */ +void ODK_Message_Reset(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + message_impl->read_offset = 0; + message_impl->status = MESSAGE_STATUS_OK; +} + +/* + * Return a pointer to the message data buffer, i.e. the message payload. + * This is the buffer address that was passed into ODK_Message_Create. + */ +uint8_t* ODK_Message_GetBase(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->base; +} + +/* + * Get the maximum number of bytes the message can hold. + */ +size_t ODK_Message_GetCapacity(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->capacity; +} + +/* + * Get the number of bytes currently in the message + */ +size_t ODK_Message_GetSize(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->size; +} + +/* + * Get the offset of where the next bytes will be read from the message data + * buffer. + */ +size_t ODK_Message_GetOffset(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->read_offset; +} + +/* + * Return the status of the message + */ +ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->status; +} + +/* + * Set the message status to a specific value + */ +void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + /* preserve the first error */ + if (message_impl->status == MESSAGE_STATUS_OK) { + message_impl->status = status; + } +} + +/* + * Set the size of the message to a value. This may be needed after writing data + * into the message data buffer. + */ +void ODK_Message_SetSize(ODK_Message* message, size_t size) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + assert(size <= message_impl->capacity); + message_impl->size = size; +} + +/* + * Test if the integrity of a message. This means that the status must be + * MESSAGE_STATUS_OK and that the base, read_offset, size and capacity of the + * message are within the range of valid values. The message's base pointer + * may be NULL if the buffer has not been assigned yet, that is not invalid. + */ +bool ODK_Message_IsValid(ODK_Message* message) { + assert(message); + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + if (message_impl == NULL) { + return false; + } + if (message_impl->status != MESSAGE_STATUS_OK) { + return false; + } + if (message_impl->read_offset > message_impl->capacity || + message_impl->size > message_impl->capacity || + message_impl->read_offset > message_impl->size) { + message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; + return false; + } + return true; +} diff --git a/oemcrypto/odk/src/odk_message_priv.h b/oemcrypto/odk/src/odk_message_priv.h new file mode 100644 index 0000000..8ad5f03 --- /dev/null +++ b/oemcrypto/odk/src/odk_message_priv.h @@ -0,0 +1,41 @@ +// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_ +#define WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file must only be included by odk_message.c and serialization_base.c. + */ + +#include +#include + +#include "odk_message.h" + +/* + * This is the implementation of a message. This structure is private, i.e. it + * should only be included by files that are allowed to modify the internals of + * a message, that being odk_message.c and serialization_base.c. To ensure + * proper alignment and message size, an ODK_Message_Impl should never be + * allocated directly, instead allocate ODK_Message and cast to ODK_Message_Impl + * because ODK_Message_Impl may be smaller than ODK_Message. + */ +typedef struct { + uint8_t* base; + size_t capacity; + size_t size; + size_t read_offset; + ODK_MessageStatus status; +} ODK_Message_Impl; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_ diff --git a/oemcrypto/odk/src/odk_overflow.c b/oemcrypto/odk/src/odk_overflow.c index b679e01..0ebc084 100644 --- a/oemcrypto/odk/src/odk_overflow.c +++ b/oemcrypto/odk/src/odk_overflow.c @@ -34,3 +34,13 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c) { } return 1; } + +int odk_mul_overflow_ux(size_t a, size_t b, size_t* c) { + if (b > 0 && a > SIZE_MAX / b) { + return 1; + } + if (c) { + *c = a * b; + } + return 0; +} diff --git a/oemcrypto/odk/src/odk_overflow.h b/oemcrypto/odk/src/odk_overflow.h index 75cd52b..e725705 100644 --- a/oemcrypto/odk/src/odk_overflow.h +++ b/oemcrypto/odk/src/odk_overflow.h @@ -15,6 +15,7 @@ extern "C" { int odk_sub_overflow_u64(uint64_t a, uint64_t b, uint64_t* c); int odk_add_overflow_u64(uint64_t a, uint64_t b, uint64_t* c); int odk_add_overflow_ux(size_t a, size_t b, size_t* c); +int odk_mul_overflow_ux(size_t a, size_t b, size_t* c); #ifdef __cplusplus } diff --git a/oemcrypto/odk/src/odk_serialize.c b/oemcrypto/odk/src/odk_serialize.c index c35e9b5..55ea3a4 100644 --- a/oemcrypto/odk/src/odk_serialize.c +++ b/oemcrypto/odk/src/odk_serialize.c @@ -13,20 +13,20 @@ /* @@ private serialize */ -static void Pack_ODK_NonceValues(Message* msg, ODK_NonceValues const* obj) { +static void Pack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues const* obj) { Pack_uint16_t(msg, &obj->api_minor_version); Pack_uint16_t(msg, &obj->api_major_version); Pack_uint32_t(msg, &obj->nonce); Pack_uint32_t(msg, &obj->session_id); } -static void Pack_ODK_CoreMessage(Message* msg, ODK_CoreMessage const* obj) { +static void Pack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage const* obj) { Pack_uint32_t(msg, &obj->message_type); Pack_uint32_t(msg, &obj->message_length); Pack_ODK_NonceValues(msg, &obj->nonce_values); } -static void Pack_OEMCrypto_KeyObject(Message* msg, +static void Pack_OEMCrypto_KeyObject(ODK_Message* msg, OEMCrypto_KeyObject const* obj) { Pack_OEMCrypto_Substring(msg, &obj->key_id); Pack_OEMCrypto_Substring(msg, &obj->key_data_iv); @@ -35,7 +35,7 @@ static void Pack_OEMCrypto_KeyObject(Message* msg, Pack_OEMCrypto_Substring(msg, &obj->key_control); } -static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) { +static void Pack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits const* obj) { Pack_bool(msg, &obj->soft_enforce_rental_duration); Pack_bool(msg, &obj->soft_enforce_playback_duration); Pack_uint64_t(msg, &obj->earliest_playback_start_seconds); @@ -44,10 +44,52 @@ static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) { Pack_uint64_t(msg, &obj->initial_renewal_duration_seconds); } -static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) { +static void Pack_ODK_ParsedLicense(ODK_Message* msg, + ODK_ParsedLicense const* obj) { /* hand-coded */ if (obj->key_array_length > ODK_MAX_NUM_KEYS) { - SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + return; + } + Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); + Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); + Pack_OEMCrypto_Substring(msg, &obj->pst); + Pack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); + Pack_enum(msg, obj->license_type); + Pack_bool(msg, &obj->nonce_required); + Pack_ODK_TimerLimits(msg, &obj->timer_limits); + Pack_uint32_t(msg, &obj->watermarking); + Pack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required); + if (obj->dtcp2_required.dtcp2_required) { + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension); + Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension); + Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension); + Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]); + Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]); + } + Pack_uint32_t(msg, &obj->key_array_length); + size_t i; + for (i = 0; i < (size_t)obj->key_array_length; i++) { + Pack_OEMCrypto_KeyObject(msg, &obj->key_array[i]); + } +} + +static void Pack_ODK_ParsedLicenseV16(ODK_Message* msg, + ODK_ParsedLicenseV16 const* obj) { + /* hand-coded */ + if (obj->key_array_length > ODK_MAX_NUM_KEYS) { + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); return; } Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); @@ -64,7 +106,7 @@ static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) { } } -static void Pack_ODK_ParsedProvisioning(Message* msg, +static void Pack_ODK_ParsedProvisioning(ODK_Message* msg, ODK_ParsedProvisioning const* obj) { Pack_enum(msg, obj->key_type); Pack_OEMCrypto_Substring(msg, &obj->enc_private_key); @@ -74,19 +116,19 @@ static void Pack_ODK_ParsedProvisioning(Message* msg, /* @@ odk serialize */ -void Pack_ODK_PreparedLicenseRequest(Message* msg, +void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest const* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); } -void Pack_ODK_PreparedRenewalRequest(Message* msg, +void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest const* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_uint64_t(msg, &obj->playback_time); } void Pack_ODK_PreparedProvisioningRequest( - Message* msg, ODK_PreparedProvisioningRequest const* obj) { + ODK_Message* msg, ODK_PreparedProvisioningRequest const* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_uint32_t(msg, &obj->device_id_length); PackArray(msg, &obj->device_id[0], sizeof(obj->device_id)); @@ -94,18 +136,26 @@ void Pack_ODK_PreparedProvisioningRequest( /* @@ kdo serialize */ -void Pack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse const* obj) { +void Pack_ODK_LicenseResponse(ODK_Message* msg, + ODK_LicenseResponse const* obj) { Pack_ODK_PreparedLicenseRequest(msg, &obj->request); Pack_ODK_ParsedLicense(msg, (const ODK_ParsedLicense*)obj->parsed_license); +} + +void Pack_ODK_LicenseResponseV16(ODK_Message* msg, + ODK_LicenseResponseV16 const* obj) { + Pack_ODK_PreparedLicenseRequest(msg, &obj->request); + Pack_ODK_ParsedLicenseV16(msg, &obj->parsed_license); PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); } -void Pack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse const* obj) { +void Pack_ODK_RenewalResponse(ODK_Message* msg, + ODK_RenewalResponse const* obj) { Pack_ODK_PreparedRenewalRequest(msg, &obj->request); Pack_uint64_t(msg, &obj->renewal_duration_seconds); } -void Pack_ODK_ProvisioningResponse(Message* msg, +void Pack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse const* obj) { Pack_ODK_PreparedProvisioningRequest(msg, &obj->request); Pack_ODK_ParsedProvisioning( @@ -116,20 +166,21 @@ void Pack_ODK_ProvisioningResponse(Message* msg, /* @@ private deserialize */ -static void Unpack_ODK_NonceValues(Message* msg, ODK_NonceValues* obj) { +static void Unpack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues* obj) { Unpack_uint16_t(msg, &obj->api_minor_version); Unpack_uint16_t(msg, &obj->api_major_version); Unpack_uint32_t(msg, &obj->nonce); Unpack_uint32_t(msg, &obj->session_id); } -static void Unpack_ODK_CoreMessage(Message* msg, ODK_CoreMessage* obj) { +void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj) { Unpack_uint32_t(msg, &obj->message_type); Unpack_uint32_t(msg, &obj->message_length); Unpack_ODK_NonceValues(msg, &obj->nonce_values); } -static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) { +static void Unpack_OEMCrypto_KeyObject(ODK_Message* msg, + OEMCrypto_KeyObject* obj) { Unpack_OEMCrypto_Substring(msg, &obj->key_id); Unpack_OEMCrypto_Substring(msg, &obj->key_data_iv); Unpack_OEMCrypto_Substring(msg, &obj->key_data); @@ -137,7 +188,7 @@ static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) { Unpack_OEMCrypto_Substring(msg, &obj->key_control); } -static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) { +static void Unpack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits* obj) { Unpack_bool(msg, &obj->soft_enforce_rental_duration); Unpack_bool(msg, &obj->soft_enforce_playback_duration); Unpack_uint64_t(msg, &obj->earliest_playback_start_seconds); @@ -146,7 +197,65 @@ static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) { Unpack_uint64_t(msg, &obj->initial_renewal_duration_seconds); } -static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) { +static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) { + Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); + Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); + Unpack_OEMCrypto_Substring(msg, &obj->pst); + Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data); + obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg); + Unpack_bool(msg, &obj->nonce_required); + Unpack_ODK_TimerLimits(msg, &obj->timer_limits); + Unpack_uint32_t(msg, &obj->watermarking); + Unpack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required); + if (obj->dtcp2_required.dtcp2_required) { + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension); + Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension); + Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension); + Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]); + Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]); + } else { + obj->dtcp2_required.dtcp2_required = 0; + obj->dtcp2_required.cmi_descriptor_0.id = 0; + obj->dtcp2_required.cmi_descriptor_0.extension = 0; + obj->dtcp2_required.cmi_descriptor_0.length = 0; + obj->dtcp2_required.cmi_descriptor_0.data = 0; + obj->dtcp2_required.cmi_descriptor_1.id = 0; + obj->dtcp2_required.cmi_descriptor_1.extension = 0; + obj->dtcp2_required.cmi_descriptor_1.length = 0; + obj->dtcp2_required.cmi_descriptor_1.data[0] = 0; + obj->dtcp2_required.cmi_descriptor_1.data[1] = 0; + obj->dtcp2_required.cmi_descriptor_1.data[2] = 0; + obj->dtcp2_required.cmi_descriptor_2.id = 0; + obj->dtcp2_required.cmi_descriptor_2.extension = 0; + obj->dtcp2_required.cmi_descriptor_2.length = 0; + obj->dtcp2_required.cmi_descriptor_2.data[0] = 0; + obj->dtcp2_required.cmi_descriptor_2.data[1] = 0; + obj->dtcp2_required.cmi_descriptor_2.data[2] = 0; + } + Unpack_uint32_t(msg, &obj->key_array_length); + if (obj->key_array_length > ODK_MAX_NUM_KEYS) { + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + return; + } + uint32_t i; + for (i = 0; i < obj->key_array_length; i++) { + Unpack_OEMCrypto_KeyObject(msg, &obj->key_array[i]); + } +} + +static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg, + ODK_ParsedLicenseV16* obj) { Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); Unpack_OEMCrypto_Substring(msg, &obj->pst); @@ -156,7 +265,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) { Unpack_ODK_TimerLimits(msg, &obj->timer_limits); Unpack_uint32_t(msg, &obj->key_array_length); if (obj->key_array_length > ODK_MAX_NUM_KEYS) { - SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); return; } uint32_t i; @@ -165,7 +274,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) { } } -static void Unpack_ODK_ParsedProvisioning(Message* msg, +static void Unpack_ODK_ParsedProvisioning(ODK_Message* msg, ODK_ParsedProvisioning* obj) { obj->key_type = (OEMCrypto_PrivateKeyType)Unpack_enum(msg); Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key); @@ -175,42 +284,48 @@ static void Unpack_ODK_ParsedProvisioning(Message* msg, /* @ kdo deserialize */ -void Unpack_ODK_PreparedLicenseRequest(Message* msg, +void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); } -void Unpack_ODK_PreparedRenewalRequest(Message* msg, +void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); Unpack_uint64_t(msg, &obj->playback_time); } void Unpack_ODK_PreparedProvisioningRequest( - Message* msg, ODK_PreparedProvisioningRequest* obj) { + ODK_Message* msg, ODK_PreparedProvisioningRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); Unpack_uint32_t(msg, &obj->device_id_length); UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id)); } -void Unpack_ODK_PreparedCommonRequest(Message* msg, +void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, ODK_PreparedCommonRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); } /* @@ odk deserialize */ -void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj) { +void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj) { Unpack_ODK_PreparedLicenseRequest(msg, &obj->request); Unpack_ODK_ParsedLicense(msg, obj->parsed_license); +} + +void Unpack_ODK_LicenseResponseV16(ODK_Message* msg, + ODK_LicenseResponseV16* obj) { + Unpack_ODK_PreparedLicenseRequest(msg, &obj->request); + Unpack_ODK_ParsedLicenseV16(msg, &obj->parsed_license); UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); } -void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj) { +void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj) { Unpack_ODK_PreparedRenewalRequest(msg, &obj->request); Unpack_uint64_t(msg, &obj->renewal_duration_seconds); } -void Unpack_ODK_ProvisioningResponse(Message* msg, +void Unpack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse* obj) { Unpack_ODK_PreparedProvisioningRequest(msg, &obj->request); Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning); diff --git a/oemcrypto/odk/src/odk_serialize.h b/oemcrypto/odk/src/odk_serialize.h index 0816bf7..c08b4d5 100644 --- a/oemcrypto/odk/src/odk_serialize.h +++ b/oemcrypto/odk/src/odk_serialize.h @@ -16,34 +16,39 @@ extern "C" { #endif /* odk pack */ -void Pack_ODK_PreparedLicenseRequest(Message* msg, +void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg, const ODK_PreparedLicenseRequest* obj); -void Pack_ODK_PreparedRenewalRequest(Message* msg, +void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, const ODK_PreparedRenewalRequest* obj); void Pack_ODK_PreparedProvisioningRequest( - Message* msg, const ODK_PreparedProvisioningRequest* obj); + ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj); /* odk unpack */ -void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj); -void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj); -void Unpack_ODK_ProvisioningResponse(Message* msg, +void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj); +void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj); +void Unpack_ODK_LicenseResponseV16(ODK_Message* msg, + ODK_LicenseResponseV16* obj); +void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj); +void Unpack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse* obj); /* kdo pack */ -void Pack_ODK_LicenseResponse(Message* msg, const ODK_LicenseResponse* obj); -void Pack_ODK_RenewalResponse(Message* msg, const ODK_RenewalResponse* obj); -void Pack_ODK_ProvisioningResponse(Message* msg, +void Pack_ODK_LicenseResponse(ODK_Message* msg, const ODK_LicenseResponse* obj); +void Pack_ODK_LicenseResponseV16(ODK_Message* msg, + const ODK_LicenseResponseV16* obj); +void Pack_ODK_RenewalResponse(ODK_Message* msg, const ODK_RenewalResponse* obj); +void Pack_ODK_ProvisioningResponse(ODK_Message* msg, const ODK_ProvisioningResponse* obj); /* kdo unpack */ -void Unpack_ODK_PreparedLicenseRequest(Message* msg, +void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest* obj); -void Unpack_ODK_PreparedRenewalRequest(Message* msg, +void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest* obj); void Unpack_ODK_PreparedProvisioningRequest( - Message* msg, ODK_PreparedProvisioningRequest* obj); + ODK_Message* msg, ODK_PreparedProvisioningRequest* obj); -void Unpack_ODK_PreparedCommonRequest(Message* msg, +void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, ODK_PreparedCommonRequest* obj); #ifdef __cplusplus diff --git a/oemcrypto/odk/src/odk_structs_priv.h b/oemcrypto/odk/src/odk_structs_priv.h index 6b138f4..1bfc597 100644 --- a/oemcrypto/odk/src/odk_structs_priv.h +++ b/oemcrypto/odk/src/odk_structs_priv.h @@ -14,24 +14,26 @@ extern "C" { #endif -typedef enum { - ODK_License_Request_Type = 1, - ODK_License_Response_Type = 2, - ODK_Renewal_Request_Type = 3, - ODK_Renewal_Response_Type = 4, - ODK_Provisioning_Request_Type = 5, - ODK_Provisioning_Response_Type = 6, +// We use a typedef here so `ODK_CoreMessage` will contain "simple types" which +// should work better with the auto code generator. +typedef uint32_t ODK_MessageType; - // Reserve future message types to support forward compatibility. - ODK_Release_Request_Type = 7, - ODK_Release_Response_Type = 8, - ODK_Common_Request_Type = 9, - ODK_Common_Response_Type = 10, -} ODK_MessageType; +#define ODK_License_Request_Type ((ODK_MessageType)1u) +#define ODK_License_Response_Type ((ODK_MessageType)2u) +#define ODK_Renewal_Request_Type ((ODK_MessageType)3u) +#define ODK_Renewal_Response_Type ((ODK_MessageType)4u) +#define ODK_Provisioning_Request_Type ((ODK_MessageType)5u) +#define ODK_Provisioning_Response_Type ((ODK_MessageType)6u) + +// Reserve future message types to support forward compatibility. +#define ODK_Release_Request_Type ((ODK_MessageType)7u) +#define ODK_Release_Response_Type ((ODK_MessageType)8u) +#define ODK_Common_Request_Type ((ODK_MessageType)9u) +#define ODK_Common_Response_Type ((ODK_MessageType)10u) typedef struct { - uint32_t message_type; - uint32_t message_length; + ODK_MessageType message_type; // Type of core message (defined above) + uint32_t message_length; // Length of core message. ODK_NonceValues nonce_values; } ODK_CoreMessage; @@ -54,12 +56,29 @@ typedef struct { ODK_CoreMessage core_message; } ODK_PreparedCommonRequest; +typedef struct { + OEMCrypto_Substring enc_mac_keys_iv; + OEMCrypto_Substring enc_mac_keys; + OEMCrypto_Substring pst; + OEMCrypto_Substring srm_restriction_data; + OEMCrypto_LicenseType license_type; + bool nonce_required; + ODK_TimerLimits timer_limits; + uint32_t key_array_length; + OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS]; +} ODK_ParsedLicenseV16; + typedef struct { ODK_PreparedLicenseRequest request; ODK_ParsedLicense* parsed_license; - uint8_t request_hash[ODK_SHA256_HASH_SIZE]; } ODK_LicenseResponse; +typedef struct { + ODK_PreparedLicenseRequest request; + ODK_ParsedLicenseV16 parsed_license; + uint8_t request_hash[ODK_SHA256_HASH_SIZE]; +} ODK_LicenseResponseV16; + typedef struct { ODK_PreparedRenewalRequest request; uint64_t renewal_duration_seconds; @@ -74,26 +93,26 @@ typedef struct { // without any padding added by the compiler. Make sure they get updated when // request structs change. Refer to test suite OdkSizeTest in // ../test/odk_test.cpp for validations of each of the defined request sizes. -#define ODK_LICENSE_REQUEST_SIZE 20 -#define ODK_RENEWAL_REQUEST_SIZE 28 -#define ODK_PROVISIONING_REQUEST_SIZE 88 +#define ODK_LICENSE_REQUEST_SIZE 20u +#define ODK_RENEWAL_REQUEST_SIZE 28u +#define ODK_PROVISIONING_REQUEST_SIZE 88u // These are the possible timer status values. -#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0 // Should not happen. +#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0u // Should not happen. // When the structure has been initialized, but no license is loaded. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1u // After the license is loaded, before a successful decrypt. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2u // After the license is loaded, if a renewal has also been loaded. -#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3 +#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3u // The first decrypt has occurred and the timer is active. -#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4 +#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4u // The first decrypt has occurred and the timer is unlimited. -#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5 +#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5u // The timer has transitioned from active to expired. -#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6 +#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6u // The license has been marked as inactive. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7u // A helper function for computing timer limits when a renewal is loaded. OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits, diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index c817bbb..1b09551 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -71,7 +71,7 @@ static OEMCryptoResult ODK_CheckRentalWindow( /* rental_clock = time since license signed. */ uint64_t rental_clock = 0; if (odk_sub_overflow_u64(system_time_seconds, - clock_values->time_of_license_signed, + clock_values->time_of_license_request_signed, &rental_clock)) { return OEMCrypto_ERROR_INVALID_CONTEXT; } @@ -180,7 +180,7 @@ OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits, } /* If this is before the license was signed, something is odd. Return an * error. */ - if (system_time_seconds < clock_values->time_of_license_signed) { + if (system_time_seconds < clock_values->time_of_license_request_signed) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -297,7 +297,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, if (clock_values == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - clock_values->time_of_license_signed = system_time_seconds; + clock_values->time_of_license_request_signed = system_time_seconds; clock_values->time_of_first_decrypt = 0; clock_values->time_of_last_decrypt = 0; clock_values->time_when_timer_expires = 0; @@ -308,7 +308,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, /* This is called when OEMCrypto reloads a usage entry. */ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values, - uint64_t time_of_license_signed, + uint64_t time_of_license_request_signed, uint64_t time_of_first_decrypt, uint64_t time_of_last_decrypt, enum OEMCrypto_Usage_Entry_Status status, @@ -316,7 +316,7 @@ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values, if (clock_values == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - clock_values->time_of_license_signed = time_of_license_signed; + clock_values->time_of_license_request_signed = time_of_license_request_signed; clock_values->time_of_first_decrypt = time_of_first_decrypt; clock_values->time_of_last_decrypt = time_of_last_decrypt; clock_values->time_when_timer_expires = 0; @@ -336,7 +336,7 @@ OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds, /* All times are relative to when the license was signed. */ uint64_t rental_time = 0; if (odk_sub_overflow_u64(system_time_seconds, - clock_values->time_of_license_signed, + clock_values->time_of_license_request_signed, &rental_time)) { return OEMCrypto_ERROR_INVALID_CONTEXT; } diff --git a/oemcrypto/odk/src/odk_util.c b/oemcrypto/odk/src/odk_util.c index 76ee242..a6669a4 100644 --- a/oemcrypto/odk/src/odk_util.c +++ b/oemcrypto/odk/src/odk_util.c @@ -24,11 +24,10 @@ int crypto_memcmp(const void* in_a, const void* in_b, size_t len) { return x; } -bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b) { +bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a, + const ODK_NonceValues* b) { if (a == NULL || b == NULL) { return (a == b); } - return (a->api_major_version == b->api_major_version && - a->api_minor_version == b->api_minor_version && - a->nonce == b->nonce && a->session_id == b->session_id); + return (a->nonce == b->nonce && a->session_id == b->session_id); } diff --git a/oemcrypto/odk/src/odk_util.h b/oemcrypto/odk/src/odk_util.h index def0865..ab932dd 100644 --- a/oemcrypto/odk/src/odk_util.h +++ b/oemcrypto/odk/src/odk_util.h @@ -20,7 +20,8 @@ extern "C" { * return value when a != b is undefined, other than being non-zero. */ int crypto_memcmp(const void* a, const void* b, size_t len); -bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b); +bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a, + const ODK_NonceValues* b); #ifdef __cplusplus } // extern "C" diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c index 6e6674c..90b84b3 100644 --- a/oemcrypto/odk/src/serialization_base.c +++ b/oemcrypto/odk/src/serialization_base.c @@ -4,233 +4,197 @@ #include "serialization_base.h" +#include #include #include #include #include "OEMCryptoCENCCommon.h" +#include "odk_message.h" +#include "odk_message_priv.h" #include "odk_overflow.h" -struct _Message { - uint8_t* base; - size_t capacity; - size_t size; /* bytes written */ - size_t read_offset; /* bytes read */ - MessageStatus status; -}; - -bool ValidMessage(Message* message) { - if (message == NULL) { - return false; - } - if (message->status != MESSAGE_STATUS_OK) { - return false; - } - if (message->base == NULL) { - message->status = MESSAGE_STATUS_NULL_POINTER_ERROR; - return false; - } - if (message->size > message->capacity || - message->read_offset > message->size) { - message->status = MESSAGE_STATUS_OVERFLOW_ERROR; - return false; - } - return true; +/* + * An ODK_Message_Impl pointer must only be obtained by calling GetMessageImpl. + * This forces any message to pass the validity check before being operated on, + * which means that no function can modify or access the internals of a message + * without having it be validated first. + */ +static ODK_Message_Impl* GetMessageImpl(ODK_Message* message) { + if (!ODK_Message_IsValid(message)) return NULL; + return (ODK_Message_Impl*)message; } -static void PackBytes(Message* message, const uint8_t* ptr, size_t count) { - if (count <= message->capacity - message->size) { - memcpy((void*)(message->base + message->size), (void*)ptr, count); - message->size += count; +static void PackBytes(ODK_Message* message, const uint8_t* ptr, size_t count) { + ODK_Message_Impl* message_impl = GetMessageImpl(message); + if (!message_impl) return; + if (count <= message_impl->capacity - message_impl->size) { + memcpy((void*)(message_impl->base + message_impl->size), (const void*)ptr, + count); + message_impl->size += count; } else { - message->status = MESSAGE_STATUS_OVERFLOW_ERROR; + message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; } } -void Pack_enum(Message* message, int value) { +void Pack_enum(ODK_Message* message, int value) { uint32_t v32 = value; Pack_uint32_t(message, &v32); } -void Pack_bool(Message* message, const bool* value) { - if (!ValidMessage(message)) return; +void Pack_bool(ODK_Message* message, const bool* value) { + assert(value); uint8_t data[4] = {0}; data[3] = *value ? 1 : 0; PackBytes(message, data, sizeof(data)); } -void Pack_uint16_t(Message* message, const uint16_t* value) { - if (!ValidMessage(message)) return; +void Pack_uint8_t(ODK_Message* message, const uint8_t* value) { + assert(value); + uint8_t data[1] = {0}; + data[0] = (uint8_t)(*value >> 0); + PackBytes(message, data, sizeof(data)); +} + +void Pack_uint16_t(ODK_Message* message, const uint16_t* value) { + assert(value); uint8_t data[2] = {0}; - data[0] = *value >> 8; - data[1] = *value >> 0; + data[0] = (uint8_t)(*value >> 8); + data[1] = (uint8_t)(*value >> 0); PackBytes(message, data, sizeof(data)); } -void Pack_uint32_t(Message* message, const uint32_t* value) { - if (!ValidMessage(message)) return; +void Pack_uint32_t(ODK_Message* message, const uint32_t* value) { + assert(value); uint8_t data[4] = {0}; - data[0] = *value >> 24; - data[1] = *value >> 16; - data[2] = *value >> 8; - data[3] = *value >> 0; + data[0] = (uint8_t)(*value >> 24); + data[1] = (uint8_t)(*value >> 16); + data[2] = (uint8_t)(*value >> 8); + data[3] = (uint8_t)(*value >> 0); PackBytes(message, data, sizeof(data)); } -void Pack_uint64_t(Message* message, const uint64_t* value) { - if (!ValidMessage(message)) return; - uint32_t hi = *value >> 32; - uint32_t lo = *value; +void Pack_uint64_t(ODK_Message* message, const uint64_t* value) { + assert(value); + uint32_t hi = (uint32_t)(*value >> 32); + uint32_t lo = (uint32_t)(*value); Pack_uint32_t(message, &hi); Pack_uint32_t(message, &lo); } -void PackArray(Message* message, const uint8_t* base, size_t size) { - if (!ValidMessage(message)) return; +void PackArray(ODK_Message* message, const uint8_t* base, size_t size) { PackBytes(message, base, size); } -void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj) { +void Pack_OEMCrypto_Substring(ODK_Message* message, + const OEMCrypto_Substring* obj) { + assert(obj); uint32_t offset = (uint32_t)obj->offset; uint32_t length = (uint32_t)obj->length; - Pack_uint32_t(msg, &offset); - Pack_uint32_t(msg, &length); + Pack_uint32_t(message, &offset); + Pack_uint32_t(message, &length); } -static void UnpackBytes(Message* message, uint8_t* ptr, size_t count) { - if (count <= message->size - message->read_offset) { - memcpy((void*)ptr, (void*)(message->base + message->read_offset), count); - message->read_offset += count; +static void UnpackBytes(ODK_Message* message, uint8_t* ptr, size_t count) { + assert(ptr); + ODK_Message_Impl* message_impl = GetMessageImpl(message); + if (!message_impl) return; + if (count <= message_impl->size - message_impl->read_offset) { + memcpy((void*)ptr, (void*)(message_impl->base + message_impl->read_offset), + count); + message_impl->read_offset += count; } else { - message->status = MESSAGE_STATUS_UNDERFLOW_ERROR; + message_impl->status = MESSAGE_STATUS_UNDERFLOW_ERROR; } } -int Unpack_enum(Message* message) { +int Unpack_enum(ODK_Message* message) { uint32_t v32; Unpack_uint32_t(message, &v32); - return v32; + return (int)v32; } -void Unpack_bool(Message* message, bool* value) { - if (!ValidMessage(message)) return; +void Unpack_bool(ODK_Message* message, bool* value) { uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); + assert(value); *value = (0 != data[3]); } -void Unpack_uint16_t(Message* message, uint16_t* value) { - if (!ValidMessage(message)) return; +void Unpack_uint8_t(ODK_Message* message, uint8_t* value) { + assert(value); + uint8_t data[1] = {0}; + UnpackBytes(message, data, sizeof(data)); + *value = data[0]; +} + +void Unpack_uint16_t(ODK_Message* message, uint16_t* value) { + assert(value); uint8_t data[2] = {0}; UnpackBytes(message, data, sizeof(data)); *value = data[0]; *value = *value << 8 | data[1]; } -void Unpack_uint32_t(Message* message, uint32_t* value) { - if (!ValidMessage(message)) return; +void Unpack_uint32_t(ODK_Message* message, uint32_t* value) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + if (!message_impl) return; uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); + assert(value); *value = data[0]; *value = *value << 8 | data[1]; *value = *value << 8 | data[2]; *value = *value << 8 | data[3]; } -void Unpack_uint64_t(Message* message, uint64_t* value) { - if (!ValidMessage(message)) return; +void Unpack_uint64_t(ODK_Message* message, uint64_t* value) { uint32_t hi = 0; uint32_t lo = 0; Unpack_uint32_t(message, &hi); Unpack_uint32_t(message, &lo); + assert(value); *value = hi; *value = *value << 32 | lo; } -void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj) { +void Unpack_OEMCrypto_Substring(ODK_Message* message, + OEMCrypto_Substring* obj) { uint32_t offset = 0, length = 0; - Unpack_uint32_t(msg, &offset); - Unpack_uint32_t(msg, &length); - if (!ValidMessage(msg)) return; + Unpack_uint32_t(message, &offset); + Unpack_uint32_t(message, &length); + ODK_Message_Impl* message_impl = GetMessageImpl(message); + if (!message_impl) return; + /* Each substring should be contained within the message body, which is in the * total message, just after the core message. The offset of a substring is * relative to the message body. So we need to verify: - * 0 < offset and offset + length < message->capacity - message->size - * or offset + length + message->size < message->capacity + * + * For non-empty substring: + * offset + length < message_impl->capacity - message_impl->size or + * offset + length + message_impl->size < message_impl->capacity + * + * For empty substring (length is 0): + * offset must be 0 */ - size_t substring_end = 0; /* = offset + length; */ - size_t end = 0; /* = substring_end + message->size; */ - if (odk_add_overflow_ux(offset, length, &substring_end) || - odk_add_overflow_ux(substring_end, msg->size, &end) || - end > msg->capacity) { - msg->status = MESSAGE_STATUS_OVERFLOW_ERROR; + if (length == 0 && offset != 0) { + message_impl->status = MESSAGE_STATUS_UNKNOWN_ERROR; return; } + size_t substring_end = 0; /* = offset + length; */ + size_t end = 0; /* = substring_end + message_impl->size; */ + if (odk_add_overflow_ux(offset, length, &substring_end) || + odk_add_overflow_ux(substring_end, message_impl->size, &end) || + end > message_impl->capacity) { + message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; + return; + } + assert(obj); obj->offset = offset; obj->length = length; } /* copy out */ -void UnpackArray(Message* message, uint8_t* address, size_t size) { - if (!ValidMessage(message)) return; +void UnpackArray(ODK_Message* message, uint8_t* address, size_t size) { UnpackBytes(message, address, size); } - -/* - * The message structure, which is separate from the buffer, - * is initialized to reference the buffer - */ -void InitMessage(Message* message, uint8_t* buffer, size_t capacity) { - if (message == NULL) return; - memset(message, 0, sizeof(Message)); - message->base = buffer; - message->capacity = capacity; - message->size = 0; - message->read_offset = 0; - message->status = MESSAGE_STATUS_OK; -} - -/* - * Set the message to an empty state - */ -void ResetMessage(Message* message) { - message->size = 0; - message->read_offset = 0; - message->status = MESSAGE_STATUS_OK; -} - -uint8_t* GetBase(Message* message) { - if (message == NULL) return NULL; - return message->base; -} - -size_t GetCapacity(Message* message) { - if (message == NULL) return 0; - return message->capacity; -} - -size_t GetSize(Message* message) { - if (message == NULL) return 0; - return message->size; -} - -void SetSize(Message* message, size_t size) { - if (message == NULL) return; - if (size > message->capacity) - message->status = MESSAGE_STATUS_OVERFLOW_ERROR; - else - message->size = size; -} - -MessageStatus GetStatus(Message* message) { return message->status; } - -void SetStatus(Message* message, MessageStatus status) { - message->status = status; -} - -size_t GetOffset(Message* message) { - if (message == NULL) return 0; - return message->read_offset; -} - -size_t SizeOfMessageStruct() { return sizeof(Message); } diff --git a/oemcrypto/odk/src/serialization_base.h b/oemcrypto/odk/src/serialization_base.h index e1f3969..7b69e11 100644 --- a/oemcrypto/odk/src/serialization_base.h +++ b/oemcrypto/odk/src/serialization_base.h @@ -13,74 +13,27 @@ extern "C" { #include #include "OEMCryptoCENCCommon.h" +#include "odk_message.h" -#define SIZE_OF_MESSAGE_STRUCT 64 +void Pack_enum(ODK_Message* message, int value); +void Pack_bool(ODK_Message* message, const bool* value); +void Pack_uint8_t(ODK_Message* message, const uint8_t* value); +void Pack_uint16_t(ODK_Message* message, const uint16_t* value); +void Pack_uint32_t(ODK_Message* message, const uint32_t* value); +void Pack_uint64_t(ODK_Message* message, const uint64_t* value); +void PackArray(ODK_Message* message, const uint8_t* base, size_t size); +void Pack_OEMCrypto_Substring(ODK_Message* message, + const OEMCrypto_Substring* obj); -/* - * Description: - * Point |msg| to stack-array |blk|. - * |blk| is guaranteed large enough to hold a |Message| struct. - * |blk| cannot be used in the same scope as a variable name. - * |msg| points to valid memory in the same scope |AllocateMessage| is used. - * Parameters: - * msg: pointer to pointer to |Message| struct - * blk: variable name for stack-array - */ -#define AllocateMessage(msg, blk) \ - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; \ - *(msg) = (Message*)(blk) - -typedef struct _Message Message; - -typedef enum { - MESSAGE_STATUS_OK, - MESSAGE_STATUS_UNKNOWN_ERROR, - MESSAGE_STATUS_OVERFLOW_ERROR, - MESSAGE_STATUS_UNDERFLOW_ERROR, - MESSAGE_STATUS_PARSE_ERROR, - MESSAGE_STATUS_NULL_POINTER_ERROR, - MESSAGE_STATUS_API_VALUE_ERROR -} MessageStatus; - -bool ValidMessage(Message* message); - -void Pack_enum(Message* message, int value); -void Pack_bool(Message* message, const bool* value); -void Pack_uint16_t(Message* message, const uint16_t* value); -void Pack_uint32_t(Message* message, const uint32_t* value); -void Pack_uint64_t(Message* message, const uint64_t* value); -void PackArray(Message* message, const uint8_t* base, size_t size); -void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj); - -int Unpack_enum(Message* message); -void Unpack_bool(Message* message, bool* value); -void Unpack_uint16_t(Message* message, uint16_t* value); -void Unpack_uint32_t(Message* message, uint32_t* value); -void Unpack_uint64_t(Message* message, uint64_t* value); -void UnpackArray(Message* message, uint8_t* address, +int Unpack_enum(ODK_Message* message); +void Unpack_bool(ODK_Message* message, bool* value); +void Unpack_uint8_t(ODK_Message* message, uint8_t* value); +void Unpack_uint16_t(ODK_Message* message, uint16_t* value); +void Unpack_uint32_t(ODK_Message* message, uint32_t* value); +void Unpack_uint64_t(ODK_Message* message, uint64_t* value); +void UnpackArray(ODK_Message* message, uint8_t* address, size_t size); /* copy out */ -void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj); - -/* - * Initialize a message structure to reference a separate buffer. The caller - * is responsible for ensuring that the buffer remains allocated for the - * lifetime of the message. - */ -void InitMessage(Message* message, uint8_t* buffer, size_t capacity); - -/* - * Reset an existing the message to an empty state - */ -void ResetMessage(Message* message); -uint8_t* GetBase(Message* message); -size_t GetCapacity(Message* message); -size_t GetSize(Message* message); -void SetSize(Message* message, size_t size); -MessageStatus GetStatus(Message* message); -void SetStatus(Message* message, MessageStatus status); -size_t GetOffset(Message* message); - -size_t SizeOfMessageStruct(); +void Unpack_OEMCrypto_Substring(ODK_Message* message, OEMCrypto_Substring* obj); #ifdef __cplusplus } // extern "C" diff --git a/oemcrypto/odk/test/fuzzing/Android.bp b/oemcrypto/odk/test/fuzzing/Android.bp index d7390f9..3b8fe6d 100644 --- a/oemcrypto/odk/test/fuzzing/Android.bp +++ b/oemcrypto/odk/test/fuzzing/Android.bp @@ -2,6 +2,18 @@ // source code may only be used and distributed under the Widevine // License Agreement. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_defaults { name: "odk_fuzz_library_defaults", srcs: [ @@ -165,4 +177,4 @@ cc_fuzz { ], defaults: ["odk_fuzz_library_defaults"], proprietary: true, -} \ No newline at end of file +} diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp index 522c2b8..78519cb 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp @@ -9,6 +9,18 @@ // ---------------------------------------------------------------- // Builds libwv_odk.so, The ODK shared Library (libwv_odk) is used // by the OEMCrypto unit tests to generate corpus for ODK fuzz scrips. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_library_shared { name: "libwv_odk_corpus_generator", include_dirs: [ diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp index 548d38a..dea3674 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp @@ -18,6 +18,14 @@ '../src', '../kdo/include', ], + 'cflags': [ + # TODO(b/172518513): Remove this + '-Wno-error=cast-qual', + ], + 'cflags_c': [ + # TODO(b/159354894): Remove this + '-Wno-error=bad-function-cast', + ], 'cflags_cc': [ '-std=c++11', '-g3', diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp index 7f6187c..cf1be5f 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp @@ -6,6 +6,7 @@ #include "odk.h" namespace oemcrypto_core_message { +using features::CoreMessageFeatures; bool convert_byte_to_valid_boolean(const bool* in) { const char* buf = reinterpret_cast(in); @@ -67,8 +68,8 @@ OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message, return ODK_ParseLicense(message, SIZE_MAX, core_message_length, static_cast(a->initial_license_load), static_cast(a->usage_entry_present), - a->request_hash, &a->timer_limits, &a->clock_values, - nonce_values, parsed_lic); + &a->timer_limits, &a->clock_values, nonce_values, + parsed_lic); } OEMCryptoResult odk_deserialize_RenewalResponse( @@ -99,11 +100,9 @@ OEMCryptoResult odk_deserialize_RenewalResponse( // odk_kdo method, we call Unpack_ODK_PreparedRenewalRequest private method. // playback_time cannot be captured from publicly exposed API // ODK_ParseRenewal. - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = reinterpret_cast(blk); - InitMessage(msg, const_cast(buf), len); - SetSize(msg, len); - Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg); + ODK_Message msg = ODK_Message_Create(const_cast(buf), len); + ODK_Message_SetSize(&msg, len); + Unpack_ODK_PreparedRenewalRequest(&msg, renewal_msg); return OEMCrypto_SUCCESS; } @@ -124,7 +123,8 @@ bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args, std::string core_request_sha_256( reinterpret_cast(args->request_hash), ODK_SHA256_HASH_SIZE); return serialize::CreateCoreLicenseResponse( - parsed_lic, core_request, core_request_sha_256, oemcrypto_core_message); + CoreMessageFeatures::kDefaultFeatures, parsed_lic, core_request, + core_request_sha_256, oemcrypto_core_message); } bool kdo_serialize_RenewalResponse( @@ -136,7 +136,8 @@ bool kdo_serialize_RenewalResponse( nonce_values.api_minor_version, nonce_values.api_major_version, nonce_values.nonce, nonce_values.session_id, renewal_msg.playback_time}; return serialize::CreateCoreRenewalResponse( - core_request, args->timer_limits.initial_renewal_duration_seconds, + CoreMessageFeatures::kDefaultFeatures, core_request, + args->timer_limits.initial_renewal_duration_seconds, oemcrypto_core_message); } @@ -153,7 +154,8 @@ bool kdo_serialize_ProvisioningResponse( nonce_values.nonce, nonce_values.session_id, std::string(reinterpret_cast(args->device_id), args->device_id_length)}; - return serialize::CreateCoreProvisioningResponse(parsed_prov, core_request, - oemcrypto_core_message); + return serialize::CreateCoreProvisioningResponse( + CoreMessageFeatures::kDefaultFeatures, parsed_prov, core_request, + oemcrypto_core_message); } } // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h index 34fe8fc..0f45467 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h @@ -7,6 +7,7 @@ #include #include +#include "core_message_features.h" #include "core_message_serialize.h" #include "fuzzing/odk_fuzz_structs.h" #include "odk_attributes.h" diff --git a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp index 5249253..4ad8ca4 100644 --- a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp @@ -6,13 +6,15 @@ #include #include "fuzzing/odk_fuzz_helper.h" +#include "odk_attributes.h" namespace oemcrypto_core_message { // The custom mutator: Ensure that each input can be deserialized properly // by ODK function after mutation. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, - size_t max_size, unsigned int seed) { + size_t max_size, + unsigned int seed UNUSED) { const size_t kProvisioningResponseArgsSize = sizeof(ODK_ParseProvisioning_Args); if (size < kProvisioningResponseArgsSize) { diff --git a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp index d6a9dd4..2502ab8 100644 --- a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp @@ -6,13 +6,15 @@ #include #include "fuzzing/odk_fuzz_helper.h" +#include "odk_attributes.h" namespace oemcrypto_core_message { // The custom mutator: Ensure that each input can be deserialized properly // by ODK function after mutation. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, - size_t max_size, unsigned int seed) { + size_t max_size, + unsigned int seed UNUSED) { const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args); if (size < kRenewalResponseArgsSize) { return 0; diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index 93e9230..d1a817d 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -4,13 +4,12 @@ #include "odk.h" -#include // TODO(b/147944591): use this one? Or odk_endian.h? - #include #include #include "OEMCryptoCENCCommon.h" #include "core_message_deserialize.h" +#include "core_message_features.h" #include "core_message_serialize.h" #include "core_message_types.h" #include "gtest/gtest.h" @@ -29,12 +28,34 @@ using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage; using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage; +using oemcrypto_core_message::features::CoreMessageFeatures; + using oemcrypto_core_message::serialize::CreateCoreLicenseResponse; using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse; using oemcrypto_core_message::serialize::CreateCoreRenewalResponse; constexpr uint32_t kExtraPayloadSize = 128u; +/* Used to parameterize tests by version number. The request is given one + * version number, and we will expect the response to have another version + * number. */ +struct VersionParameters { + uint32_t maximum_major_version; + uint16_t request_major_version; + uint16_t request_minor_version; + uint16_t response_major_version; + uint16_t response_minor_version; +}; + +// This function is called by GTest when a parameterized test fails in order +// to log the parameter used for the failing test. +void PrintTo(const VersionParameters& p, std::ostream* os) { + *os << "max=v" << p.maximum_major_version << ", request = v" + << p.request_major_version << "." << p.request_minor_version + << ", response = v" << p.response_major_version << "." + << p.response_minor_version; +} + template void ValidateRequest(uint32_t message_type, const std::vector& extra_fields, @@ -113,12 +134,13 @@ void ValidateRequest(uint32_t message_type, * G: kdo serializer */ template -void ValidateResponse(ODK_CoreMessage* core_message, +void ValidateResponse(const VersionParameters& versions, + ODK_CoreMessage* core_message, const std::vector& extra_fields, const F& odk_parse_func, const G& kdo_prepare_func) { T t = {}; - t.api_minor_version = core_message->nonce_values.api_minor_version; - t.api_major_version = core_message->nonce_values.api_major_version; + t.api_major_version = versions.request_major_version; + t.api_minor_version = versions.request_minor_version; t.nonce = core_message->nonce_values.nonce; t.session_id = core_message->nonce_values.session_id; @@ -132,12 +154,15 @@ void ValidateResponse(ODK_CoreMessage* core_message, EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_READ, zero, buf_size, &bytes_read, extra_fields)); - // parse buf with odk - EXPECT_EQ(OEMCrypto_SUCCESS, odk_parse_func(buf, buf_size)); + // Parse buf with odk + const OEMCryptoResult parse_result = odk_parse_func(buf, buf_size); + EXPECT_EQ(OEMCrypto_SUCCESS, parse_result); size_t size_out = 0; - ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out, - extra_fields); + if (parse_result != OEMCrypto_SUCCESS) { + ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out, + extra_fields); + } // serialize odk output to oemcrypto_core_message std::string oemcrypto_core_message; @@ -178,15 +203,15 @@ TEST(OdkTest, SerializeFieldsStress) { std::srand(0); size_t total_size = 0; for (int i = 0; i < n; i++) { - fields[i].type = static_cast(std::rand() % - static_cast(ODK_NUMTYPES)); + fields[i].type = static_cast( + std::rand() % static_cast(ODK_LAST_STRESSABLE_TYPE)); fields[i].value = malloc(ODK_AllocSize(fields[i].type)); fields[i].name = "stress"; total_size += ODK_FieldLength(fields[i].type); } uint8_t* buf = new uint8_t[total_size]{}; - for (int i = 0; i < total_size; i++) { + for (size_t i = 0; i < total_size; i++) { buf[i] = std::rand() & 0xff; } @@ -251,7 +276,6 @@ TEST(OdkTest, NullResponseTest) { constexpr size_t message_size = 64; uint8_t message[message_size] = {0}; size_t core_message_length = message_size; - uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {0}; ODK_TimerLimits timer_limits; ODK_ParsedLicense parsed_license; ODK_NonceValues nonce_values; @@ -260,30 +284,26 @@ TEST(OdkTest, NullResponseTest) { memset(&clock_values, 0, sizeof(clock_values)); // Assert that nullptr does not cause a core dump. - EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, - true, request_hash, &timer_limits, &clock_values, - &nonce_values, nullptr)); - EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, - true, request_hash, &timer_limits, &clock_values, - nullptr, &parsed_license)); - EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, - true, request_hash, &timer_limits, nullptr, - &nonce_values, &parsed_license)); - EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, - true, request_hash, nullptr, &clock_values, - &nonce_values, &parsed_license)); - EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, - ODK_ParseLicense(message, message_size, core_message_length, true, - true, nullptr, &timer_limits, &clock_values, - &nonce_values, &parsed_license)); + EXPECT_EQ( + ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, true, + &timer_limits, &clock_values, &nonce_values, nullptr)); + EXPECT_EQ( + ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, true, + &timer_limits, &clock_values, nullptr, &parsed_license)); + EXPECT_EQ( + ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, true, + &timer_limits, nullptr, &nonce_values, &parsed_license)); + EXPECT_EQ( + ODK_ERROR_CORE_MESSAGE, + ODK_ParseLicense(message, message_size, core_message_length, true, true, + nullptr, &clock_values, &nonce_values, &parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, ODK_ParseLicense(nullptr, message_size, core_message_length, true, - true, request_hash, &timer_limits, &clock_values, - &nonce_values, &parsed_license)); + true, &timer_limits, &clock_values, &nonce_values, + &parsed_license)); constexpr uint64_t system_time = 0; uint64_t timer_value = 0; @@ -479,7 +499,7 @@ TEST(OdkTest, ProvisionRequestRoundtrip) { TEST(OdkTest, ParseLicenseErrorNonce) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); uint8_t* buf = nullptr; uint32_t buf_size = 0; ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, @@ -488,7 +508,7 @@ TEST(OdkTest, ParseLicenseErrorNonce) { params.core_message.nonce_values.nonce = 0; OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, params.request_hash, &(params.timer_limits), + params.usage_entry_present, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err); @@ -497,7 +517,7 @@ TEST(OdkTest, ParseLicenseErrorNonce) { TEST(OdkTest, ParseLicenseErrorUsageEntry) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); uint8_t* buf = nullptr; uint32_t buf_size = 0; ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, @@ -505,25 +525,59 @@ TEST(OdkTest, ParseLicenseErrorUsageEntry) { params.usage_entry_present = false; OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, params.request_hash, &(params.timer_limits), + params.usage_entry_present, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; } -TEST(OdkTest, ParseLicenseErrorRequestHash) { +TEST(OdkTest, ParseLicenseNullSubstring) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.srm_restriction_data.offset = 0; + params.parsed_license.srm_restriction_data.length = 0; + uint8_t* buf = nullptr; + uint32_t buf_size = 0; + ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, + &buf_size); + OEMCryptoResult result = ODK_ParseLicense( + buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, + params.usage_entry_present, &(params.timer_limits), + &(params.clock_values), &(params.core_message.nonce_values), + &(params.parsed_license)); + EXPECT_EQ(OEMCrypto_SUCCESS, result); + delete[] buf; +} + +TEST(OdkTest, ParseLicenseErrorSubstringOffset) { + // offset out of range + ODK_LicenseResponseParams params; + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.enc_mac_keys_iv.offset = 1024; uint8_t* buf = nullptr; uint32_t buf_size = 0; ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, &buf_size); - // temporarily mess up with request hash - params.request_hash[0] = 0xff; OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, params.request_hash, &(params.timer_limits), + params.usage_entry_present, &(params.timer_limits), + &(params.clock_values), &(params.core_message.nonce_values), + &(params.parsed_license)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); + delete[] buf; + + // offset + length out of range + err = OEMCrypto_SUCCESS; + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.enc_mac_keys_iv.length = buf_size; + buf = nullptr; + buf_size = 0; + ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, + &buf_size); + err = ODK_ParseLicense( + buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, + params.usage_entry_present, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); @@ -562,17 +616,37 @@ TEST(OdkTest, ParsePrivisioningErrorDeviceId) { delete[] buf; } +class OdkVersionTest : public ::testing::Test, + public ::testing::WithParamInterface { + protected: + template + void SetRequestVersion(P* params) { + params->core_message.nonce_values.api_major_version = + GetParam().response_major_version; + params->core_message.nonce_values.api_minor_version = + GetParam().response_minor_version; + features_ = + CoreMessageFeatures::DefaultFeatures(GetParam().maximum_major_version); + } + CoreMessageFeatures features_; +}; + // Serialize and de-serialize license response -TEST(OdkTest, LicenseResponseRoundtrip) { +TEST_P(OdkVersionTest, LicenseResponseRoundtrip) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); - // save a copy of params.request_hash as it will be zero out during the test + ODK_SetDefaultLicenseResponseParams(¶ms, + GetParam().response_major_version); + SetRequestVersion(¶ms); + // For v17, we do not use the hash to verify the request. However, the server + // needs to be backwards compatible, so it still needs to pass the hash into + // CreateCoreLiceseseResponse below. Save a copy of params.request_hash as it + // will be zero out during the test uint8_t request_hash_read[ODK_SHA256_HASH_SIZE]; memcpy(request_hash_read, params.request_hash, sizeof(request_hash_read)); auto odk_parse_func = [&](const uint8_t* buf, size_t size) { return ODK_ParseLicense( buf, size + kExtraPayloadSize, size, params.initial_license_load, - params.usage_entry_present, request_hash_read, &(params.timer_limits), + params.usage_entry_present, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); }; @@ -581,18 +655,19 @@ TEST(OdkTest, LicenseResponseRoundtrip) { sizeof(request_hash_read)); auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request, std::string* oemcrypto_core_message) { - return CreateCoreLicenseResponse(params.parsed_license, core_request, - request_hash_string, + return CreateCoreLicenseResponse(features_, params.parsed_license, + core_request, request_hash_string, oemcrypto_core_message); }; - ValidateResponse(&(params.core_message), + ValidateResponse(GetParam(), &(params.core_message), params.extra_fields, odk_parse_func, kdo_prepare_func); } -TEST(OdkTest, RenewalResponseRoundtrip) { +TEST_P(OdkVersionTest, RenewalResponseRoundtrip) { ODK_RenewalResponseParams params; ODK_SetDefaultRenewalResponseParams(¶ms); + SetRequestVersion(¶ms); const uint64_t playback_clock = params.playback_clock; const uint64_t renewal_duration = params.renewal_duration; auto odk_parse_func = [&](const uint8_t* buf, size_t size) { @@ -611,17 +686,18 @@ TEST(OdkTest, RenewalResponseRoundtrip) { auto kdo_prepare_func = [&](ODK_RenewalRequest& core_request, std::string* oemcrypto_core_message) { core_request.playback_time_seconds = playback_clock; - return CreateCoreRenewalResponse(core_request, renewal_duration, + return CreateCoreRenewalResponse(features_, core_request, renewal_duration, oemcrypto_core_message); }; - ValidateResponse(&(params.core_message), + ValidateResponse(GetParam(), &(params.core_message), params.extra_fields, odk_parse_func, kdo_prepare_func); } -TEST(OdkTest, ProvisionResponseRoundtrip) { +TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) { ODK_ProvisioningResponseParams params; ODK_SetDefaultProvisioningResponseParams(¶ms); + SetRequestVersion(¶ms); // save a copy of params.device_id as it will be zero out during the test const uint32_t device_id_length = params.device_id_length; uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; @@ -637,14 +713,61 @@ TEST(OdkTest, ProvisionResponseRoundtrip) { std::string* oemcrypto_core_message) { core_request.device_id.assign(reinterpret_cast(device_id), device_id_length); - return CreateCoreProvisioningResponse(params.parsed_provisioning, + return CreateCoreProvisioningResponse(features_, params.parsed_provisioning, core_request, oemcrypto_core_message); }; - ValidateResponse(&(params.core_message), + ValidateResponse(GetParam(), &(params.core_message), params.extra_fields, odk_parse_func, kdo_prepare_func); } +// If the minor version is positive, we can test an older minor version. +const uint16_t kOldMinor = ODK_MINOR_VERSION > 0 ? ODK_MINOR_VERSION - 1 : 0; +// Similarly, if this isn't the first major version, we can test an older major +// version. +// TODO(b/163416999): Remove it in the future. This will be unecessarily +// complicated after we upgrade to version 17. +const uint16_t kOldMajor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION + ? ODK_MAJOR_VERSION - 1 + : ODK_FIRST_VERSION; +// If there is an older major, then we should accept any minor version. +// Otherwise, this test won't make sense and we should just use a minor of 0. +const uint16_t kOldMajorMinor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? 42 : 0; + +// List of major and minor versions to test. +std::vector TestCases() { + std::vector test_cases{ + // Fields: maximum major version, + // request major, request minor, response major, response minor, + {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, + ODK_MAJOR_VERSION, ODK_MINOR_VERSION}, + {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION + 1, + ODK_MAJOR_VERSION, ODK_MINOR_VERSION}, + {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, kOldMinor, ODK_MAJOR_VERSION, + kOldMinor}, + {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, 0, ODK_MAJOR_VERSION, 0}, + {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION + 1, 42, ODK_MAJOR_VERSION, + ODK_MINOR_VERSION}, + {ODK_MAJOR_VERSION, kOldMajor, 0, kOldMajor, 0}, + {ODK_MAJOR_VERSION, kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor}, + // If the server is restricted to v16, then the response can be at + // most 16.5 + {16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5}, + // Here are some known good versions. Make extra sure they work. + {16, 16, 3, 16, 3}, + {16, 16, 4, 16, 4}, + {16, 16, 5, 16, 5}, + {17, 16, 3, 16, 3}, + {17, 16, 4, 16, 4}, + {17, 16, 5, 16, 5}, + {17, 17, 0, 17, 0}, + }; + return test_cases; +} + +INSTANTIATE_TEST_SUITE_P(OdkVersionTests, OdkVersionTest, + ::testing::ValuesIn(TestCases())); + TEST(OdkSizeTest, LicenseRequest) { uint8_t* message = nullptr; size_t message_length = 0; @@ -703,7 +826,7 @@ TEST(OdkSizeTest, ReleaseRequest) { &core_message_length, &nonce_values, &clock_values, system_time_seconds)); // Release requests do not have a core message. - EXPECT_GE(core_message_length, 0); + EXPECT_GE(core_message_length, 0u); } TEST(OdkSizeTest, ProvisioningRequest) { diff --git a/oemcrypto/odk/test/odk_test_helper.cpp b/oemcrypto/odk/test/odk_test_helper.cpp index 50f3a1a..c1cf465 100644 --- a/oemcrypto/odk/test/odk_test_helper.cpp +++ b/oemcrypto/odk/test/odk_test_helper.cpp @@ -4,8 +4,6 @@ #include "odk_test_helper.h" -#include - #include #include #include @@ -15,13 +13,14 @@ #include "OEMCryptoCENCCommon.h" #include "gtest/gtest.h" +#include "odk_endian.h" #include "odk_structs.h" #include "odk_structs_priv.h" namespace wvodk_test { void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message, - uint32_t message_type) { + ODK_MessageType message_type) { ASSERT_TRUE(core_message != nullptr); core_message->message_type = message_type; core_message->message_length = 0; @@ -31,7 +30,8 @@ void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message, core_message->nonce_values.session_id = 0xcafebabe; } -void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) { +void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params, + uint32_t odk_major_version) { ODK_SetDefaultCoreFields(&(params->core_message), ODK_License_Response_Type); params->initial_license_load = true; params->usage_entry_present = true; @@ -51,6 +51,29 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) { .total_playback_duration_seconds = 12, .initial_renewal_duration_seconds = 13, }, + .watermarking = 0, + .dtcp2_required = {.dtcp2_required = 0, + .cmi_descriptor_0 = + { + .id = 0, + .extension = 0, + .length = 1, + .data = 0, + }, + .cmi_descriptor_1 = + { + .id = 1, + .extension = 0, + .length = 3, + .data = {0, 0, 0}, + }, + .cmi_descriptor_2 = + { + .id = 2, + .extension = 0, + .length = 3, + .data = {0, 0, 0}, + }}, .key_array_length = 3, .key_array = { @@ -87,10 +110,10 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) { ".srm_restriction_data"}, {ODK_UINT32, &(params->parsed_license.license_type), ".license_type"}, {ODK_UINT32, &(params->parsed_license.nonce_required), ".nonce_required"}, - {ODK_UINT32, + {ODK_BOOL, &(params->parsed_license.timer_limits.soft_enforce_rental_duration), ".soft_enforce_rental_duration"}, - {ODK_UINT32, + {ODK_BOOL, &(params->parsed_license.timer_limits.soft_enforce_playback_duration), ".soft_enforce_playback_duration"}, {ODK_UINT64, @@ -105,37 +128,132 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) { {ODK_UINT64, &(params->parsed_license.timer_limits.initial_renewal_duration_seconds), ".initial_renewal_duration_seconds"}, - {ODK_UINT32, &(params->parsed_license.key_array_length), - ".key_array_length"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_id), ".key_id"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data_iv), - ".key_data_iv"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data), - ".key_data"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control_iv), - ".key_control_iv"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control), - ".key_control"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_id), ".key_id"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data_iv), - ".key_data_iv"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data), - ".key_data"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control_iv), - ".key_control_iv"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control), - ".key_control"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_id), ".key_id"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data_iv), - ".key_data_iv"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data), - ".key_data"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control_iv), - ".key_control_iv"}, - {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control), - ".key_control"}, - {ODK_HASH, params->request_hash, ".request_hash"}, }; + if (odk_major_version >= 17) { + params->extra_fields.push_back( + {ODK_UINT32, &(params->parsed_license.watermarking), ".watermarking"}); + params->extra_fields.push_back( + {ODK_UINT8, &(params->parsed_license.dtcp2_required.dtcp2_required), + ".dtcp2_required"}); + if (params->parsed_license.dtcp2_required.dtcp2_required) { + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_0.id), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_0.extension), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT16, + &(params->parsed_license.dtcp2_required.cmi_descriptor_0.length), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_0.data), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_1.id), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_1.extension), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT16, + &(params->parsed_license.dtcp2_required.cmi_descriptor_1.length), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[0]), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[1]), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[2]), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_2.id), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_2.extension), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT16, + &(params->parsed_license.dtcp2_required.cmi_descriptor_2.length), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[0]), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[1]), + ".cmi_descriptor_data"}); + params->extra_fields.push_back( + {ODK_UINT8, + &(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[2]), + ".cmi_descriptor_data"}); + } + } + params->extra_fields.push_back({ODK_UINT32, + &(params->parsed_license.key_array_length), + ".key_array_length"}); + params->extra_fields.push_back({ODK_SUBSTRING, + &(params->parsed_license.key_array[0].key_id), + ".key_id"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data_iv), + ".key_data_iv"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data), + ".key_data"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control_iv), + ".key_control_iv"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control), + ".key_control"}); + params->extra_fields.push_back({ODK_SUBSTRING, + &(params->parsed_license.key_array[1].key_id), + ".key_id"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data_iv), + ".key_data_iv"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data), + ".key_data"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control_iv), + ".key_control_iv"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control), + ".key_control"}); + params->extra_fields.push_back({ODK_SUBSTRING, + &(params->parsed_license.key_array[2].key_id), + ".key_id"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data_iv), + ".key_data_iv"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data), + ".key_data"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control_iv), + ".key_control_iv"}); + params->extra_fields.push_back( + {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control), + ".key_control"}); + if (odk_major_version == 16) { + params->extra_fields.push_back( + {ODK_HASH, params->request_hash, ".request_hash"}); + } } void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) { @@ -157,7 +275,7 @@ void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) { .initial_renewal_duration_seconds = 300, }; params->clock_values = { - .time_of_license_signed = + .time_of_license_request_signed = params->system_time - params->playback_clock - 42, .time_of_first_decrypt = params->system_time - params->playback_clock, .time_of_last_decrypt = params->system_time - params->playback_clock, @@ -197,12 +315,16 @@ void ODK_SetDefaultProvisioningResponseParams( size_t ODK_FieldLength(ODK_FieldType type) { switch (type) { + case ODK_UINT8: + return sizeof(uint8_t); case ODK_UINT16: return sizeof(uint16_t); case ODK_UINT32: return sizeof(uint32_t); case ODK_UINT64: return sizeof(uint64_t); + case ODK_BOOL: // Booleans are stored in the message as 32 bit ints. + return sizeof(uint32_t); case ODK_SUBSTRING: return sizeof(uint32_t) + sizeof(uint32_t); case ODK_DEVICEID: @@ -226,25 +348,38 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) { return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { + case ODK_UINT8: { + memcpy(buf, field->value, sizeof(uint8_t)); + break; + } case ODK_UINT16: { - const uint16_t u16 = htobe16(*static_cast(field->value)); + const uint16_t u16 = + oemcrypto_htobe16(*static_cast(field->value)); memcpy(buf, &u16, sizeof(u16)); break; } case ODK_UINT32: { - const uint32_t u32 = htobe32(*static_cast(field->value)); + const uint32_t u32 = + oemcrypto_htobe32(*static_cast(field->value)); memcpy(buf, &u32, sizeof(u32)); break; } case ODK_UINT64: { - const uint64_t u64 = htobe64(*static_cast(field->value)); + const uint64_t u64 = + oemcrypto_htobe64(*static_cast(field->value)); memcpy(buf, &u64, sizeof(u64)); break; } + case ODK_BOOL: { + const bool value = *static_cast(field->value); + const uint32_t u32 = oemcrypto_htobe32(value ? 1 : 0); + memcpy(buf, &u32, sizeof(u32)); + break; + } case ODK_SUBSTRING: { OEMCrypto_Substring* s = static_cast(field->value); - const uint32_t off = htobe32(s->offset); - const uint32_t len = htobe32(s->length); + const uint32_t off = oemcrypto_htobe32(s->offset); + const uint32_t len = oemcrypto_htobe32(s->length); memcpy(buf, &off, sizeof(off)); memcpy(buf + sizeof(off), &len, sizeof(len)); break; @@ -269,22 +404,33 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { + case ODK_UINT8: { + memcpy(field->value, buf, sizeof(uint8_t)); + break; + } case ODK_UINT16: { memcpy(field->value, buf, sizeof(uint16_t)); uint16_t* u16p = static_cast(field->value); - *u16p = be16toh(*u16p); + *u16p = oemcrypto_be16toh(*u16p); break; } case ODK_UINT32: { memcpy(field->value, buf, sizeof(uint32_t)); uint32_t* u32p = static_cast(field->value); - *u32p = be32toh(*u32p); + *u32p = oemcrypto_be32toh(*u32p); break; } case ODK_UINT64: { memcpy(field->value, buf, sizeof(uint64_t)); uint64_t* u64p = static_cast(field->value); - *u64p = be64toh(*u64p); + *u64p = oemcrypto_be64toh(*u64p); + break; + } + case ODK_BOOL: { + uint32_t value; + memcpy(&value, buf, sizeof(uint32_t)); + value = oemcrypto_be32toh(value); + *static_cast(field->value) = (value != 0); break; } case ODK_SUBSTRING: { @@ -293,8 +439,8 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, uint32_t len = 0; memcpy(&off, buf, sizeof(off)); memcpy(&len, buf + sizeof(off), sizeof(len)); - s->offset = be32toh(off); - s->length = be32toh(len); + s->offset = oemcrypto_be32toh(off); + s->length = oemcrypto_be32toh(len); break; } case ODK_DEVICEID: @@ -316,18 +462,26 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { - case ODK_UINT16: { - uint16_t val; - memcpy(&val, buf, sizeof(uint16_t)); - val = be16toh(val); + case ODK_UINT8: { + uint8_t val; + memcpy(&val, buf, sizeof(uint8_t)); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; } + case ODK_UINT16: { + uint16_t val; + memcpy(&val, buf, sizeof(uint16_t)); + val = oemcrypto_be16toh(val); + std::cerr << field->name << ": " << val << " = 0x" << std::hex << val + << "\n"; + break; + } + case ODK_BOOL: case ODK_UINT32: { uint32_t val; memcpy(&val, buf, sizeof(uint32_t)); - val = be32toh(val); + val = oemcrypto_be32toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; @@ -335,7 +489,7 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, case ODK_UINT64: { uint64_t val; memcpy(&val, buf, sizeof(uint64_t)); - val = be64toh(val); + val = oemcrypto_be64toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; @@ -410,9 +564,30 @@ OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf, return OEMCrypto_SUCCESS; } +std::vector ODK_MakeTotalFields( + const std::vector& extra_fields, ODK_CoreMessage* core_message) { + std::vector total_fields = { + {ODK_UINT32, &(core_message->message_type), "message_type"}, + {ODK_UINT32, &(core_message->message_length), "message_size"}, + {ODK_UINT16, &(core_message->nonce_values.api_minor_version), + "api_minor_version"}, + {ODK_UINT16, &(core_message->nonce_values.api_major_version), + "api_major_version"}, + {ODK_UINT32, &(core_message->nonce_values.nonce), "nonce"}, + {ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"}, + }; + total_fields.insert(total_fields.end(), extra_fields.begin(), + extra_fields.end()); + return total_fields; +} + +// Expect the two buffers of size n to be equal. If not, dump the messages. void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n, const std::vector& fields) { if (memcmp(s1, s2, n) != 0) { + ODK_CoreMessage core_message; + std::vector total_fields = + ODK_MakeTotalFields(fields, &core_message); const void* buffers[] = {s1, s2}; for (int i = 0; i < 2; i++) { char _tmp[] = "/tmp/fileXXXXXX"; @@ -427,11 +602,12 @@ void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n, std::fstream out(tmp, std::ios::out | std::ios::binary); out.write(static_cast(buffers[i]), n); out.close(); - std::cerr << "buffer " << i << " dumped to " << tmp << std::endl; + std::cerr << std::endl + << "Message buffer " << i << " dumped to " << tmp << std::endl; size_t bytes_written; uint8_t* buf = const_cast(reinterpret_cast(buffers[i])); - ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, fields); + ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, total_fields); } FAIL(); } @@ -454,24 +630,9 @@ void ODK_BuildMessageBuffer(ODK_CoreMessage* core_message, uint8_t** buf, uint32_t* buf_size) { ASSERT_TRUE(core_message != nullptr); ASSERT_TRUE(buf_size != nullptr); - std::vector total_fields = { - {ODK_UINT32, &(core_message->message_type), "message_type"}, - {ODK_UINT32, &(core_message->message_length), "message_size"}, - {ODK_UINT16, &(core_message->nonce_values.api_minor_version), - "api_minor_version"}, - {ODK_UINT16, &(core_message->nonce_values.api_major_version), - "api_major_version"}, - {ODK_UINT32, &(core_message->nonce_values.nonce), "nonce"}, - {ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"}, - }; + std::vector total_fields = + ODK_MakeTotalFields(extra_fields, core_message); - uint32_t header_size = 0; - for (auto& field : total_fields) { - header_size += ODK_FieldLength(field.type); - } - - total_fields.insert(total_fields.end(), extra_fields.begin(), - extra_fields.end()); for (auto& field : total_fields) { *buf_size += ODK_FieldLength(field.type); } diff --git a/oemcrypto/odk/test/odk_test_helper.h b/oemcrypto/odk/test/odk_test_helper.h index c32318e..650950b 100644 --- a/oemcrypto/odk/test/odk_test_helper.h +++ b/oemcrypto/odk/test/odk_test_helper.h @@ -15,13 +15,19 @@ namespace wvodk_test { enum ODK_FieldType { + ODK_UINT8, ODK_UINT16, ODK_UINT32, ODK_UINT64, ODK_SUBSTRING, ODK_DEVICEID, ODK_HASH, - ODK_NUMTYPES, + // The "stressable" types are the ones we can put in a stress test that packs + // and unpacks random data and can expect to get back the same thing. + ODK_LAST_STRESSABLE_TYPE, + // Put boolean after ODK_LAST_STRESSABLE_TYPE, so that we skip boolean type in + // SerializeFieldsStress because we unpack any nonzero to 'true'. + ODK_BOOL, }; enum ODK_FieldMode { @@ -36,6 +42,8 @@ struct ODK_Field { std::string name; }; +// This structure contains all parameters available in message version v16 +// through the current version. struct ODK_LicenseResponseParams { ODK_CoreMessage core_message; bool initial_license_load; @@ -68,8 +76,9 @@ struct ODK_ProvisioningResponseParams { // Default values in core_message for testing void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message, - uint32_t message_type); -void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params); + ODK_MessageType message_type); +void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params, + uint32_t odk_major_version); void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params); void ODK_SetDefaultProvisioningResponseParams( ODK_ProvisioningResponseParams* params); diff --git a/oemcrypto/odk/test/odk_timer_test.cpp b/oemcrypto/odk/test/odk_timer_test.cpp index 9bb0b54..8413960 100644 --- a/oemcrypto/odk/test/odk_timer_test.cpp +++ b/oemcrypto/odk/test/odk_timer_test.cpp @@ -38,7 +38,7 @@ TEST(OdkTimerBasicTest, Init) { memset(&clock_values, 0, sizeof(clock_values)); uint64_t time = 42; ODK_InitializeClockValues(&clock_values, time); - EXPECT_EQ(clock_values.time_of_license_signed, time); + EXPECT_EQ(clock_values.time_of_license_request_signed, time); EXPECT_EQ(clock_values.time_of_first_decrypt, 0u); EXPECT_EQ(clock_values.time_of_last_decrypt, 0u); EXPECT_EQ(clock_values.time_when_timer_expires, 0u); @@ -59,7 +59,7 @@ TEST(OdkTimerBasicTest, Reload) { enum OEMCrypto_Usage_Entry_Status status = kInactiveUsed; ODK_ReloadClockValues(&clock_values, lic_signed, first_decrypt, last_decrypt, status, time); - EXPECT_EQ(clock_values.time_of_license_signed, lic_signed); + EXPECT_EQ(clock_values.time_of_license_request_signed, lic_signed); EXPECT_EQ(clock_values.time_of_first_decrypt, first_decrypt); EXPECT_EQ(clock_values.time_of_last_decrypt, last_decrypt); EXPECT_EQ(clock_values.time_when_timer_expires, 0u); @@ -95,7 +95,7 @@ class ODKTimerTest : public ::testing::Test { // Start rental clock at kRentalClockStart. This happens when the license // request is signed. ODK_InitializeClockValues(&clock_values_, kRentalClockStart); - EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart); + EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart); } // Simulate loading or reloading a license in a new session. An offline @@ -113,14 +113,14 @@ class ODKTimerTest : public ::testing::Test { ODK_InitializeClockValues(&clock_values_, 0); // When the usage entry is reloaded, the clock values are reloaded. ODK_ReloadClockValues(&clock_values_, - old_clock_values.time_of_license_signed, + old_clock_values.time_of_license_request_signed, old_clock_values.time_of_first_decrypt, old_clock_values.time_of_last_decrypt, old_clock_values.status, system_time); EXPECT_EQ(clock_values_.timer_status, ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED); // These shall not change: - EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart); + EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart); EXPECT_EQ(clock_values_.time_of_first_decrypt, old_clock_values.time_of_first_decrypt); EXPECT_EQ(clock_values_.time_of_last_decrypt, @@ -215,8 +215,8 @@ class ODKTimerTest : public ::testing::Test { ODK_TIMER_EXPIRED); // These should not have changed. In particular, if the license was unused // before, it should reamin unused. - EXPECT_EQ(clock_values_.time_of_license_signed, - old_clock_values.time_of_license_signed); + EXPECT_EQ(clock_values_.time_of_license_request_signed, + old_clock_values.time_of_license_request_signed); EXPECT_EQ(clock_values_.time_of_first_decrypt, old_clock_values.time_of_first_decrypt); EXPECT_EQ(clock_values_.time_of_last_decrypt, @@ -226,7 +226,7 @@ class ODKTimerTest : public ::testing::Test { // Verify that the clock values are correct. void CheckClockValues(uint64_t time_of_last_decrypt) { - EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart); + EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart); EXPECT_EQ(clock_values_.time_of_first_decrypt, start_of_playback_); EXPECT_EQ(clock_values_.time_of_last_decrypt, time_of_last_decrypt); EXPECT_EQ(clock_values_.status, kActive); @@ -1133,8 +1133,8 @@ TEST_P(ODKUseCase_LicenseWithRenewal, NullPointerTest) { timer_value_pointer); } -INSTANTIATE_TEST_CASE_P(RestrictRenewal, ODKUseCase_LicenseWithRenewal, - ::testing::Values(0, 1)); +INSTANTIATE_TEST_SUITE_P(RestrictRenewal, ODKUseCase_LicenseWithRenewal, + ::testing::Values(0, 1)); // Limited Duration License. (See above for notes on Use Case tests). The user // has 15 minutes to begin watching the movie. If a renewal is not received, diff --git a/oemcrypto/oemcrypto_unittests.gyp b/oemcrypto/oemcrypto_unittests.gyp index 6d66e97..ffbe1d5 100644 --- a/oemcrypto/oemcrypto_unittests.gyp +++ b/oemcrypto/oemcrypto_unittests.gyp @@ -8,9 +8,9 @@ 'privacy_crypto_impl%': 'boringssl', 'boringssl_libcrypto_path%': ' -#include - -extern const uint8_t kPrivateKey[]; -extern const size_t kPrivateKeySize; - -#endif // KEYS_H_ diff --git a/oemcrypto/ref/src/oem_cert.cpp b/oemcrypto/ref/src/oem_cert.cpp deleted file mode 100644 index 0b7ab7f..0000000 --- a/oemcrypto/ref/src/oem_cert.cpp +++ /dev/null @@ -1,334 +0,0 @@ -// This file contains the test OEM cert. - -#include "oem_cert.h" - -namespace wvoec_ref { - -const uint32_t kOEMSystemId_Prod = 7913; - -// From file test_rsa_key_2_carmichael.pk8 in team shared drive. -// Size is 1216. -const uint8_t kOEMPrivateKey_Prod[] = { - 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, - 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, - 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, - 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, - 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, - 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, - 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, - 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, - 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, - 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, - 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, - 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, - 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, - 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, - 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, - 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, - 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, - 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, - 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, - 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, - 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, - 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, - 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, - 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, - 0x82, 0x01, 0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8, - 0x2f, 0xef, 0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4, - 0xe9, 0x65, 0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33, - 0x8c, 0x30, 0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde, - 0xb1, 0x13, 0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc, - 0x6c, 0xdf, 0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4, - 0x67, 0x75, 0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b, - 0x6a, 0xdc, 0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40, - 0xb2, 0xb4, 0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a, - 0xeb, 0x90, 0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f, - 0xa9, 0x47, 0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f, - 0xfc, 0x19, 0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff, - 0x45, 0xa2, 0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c, - 0x37, 0x99, 0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8, - 0xfa, 0x2d, 0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71, - 0xbd, 0xff, 0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85, - 0xfd, 0xd0, 0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a, - 0x3f, 0xbf, 0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e, - 0x51, 0x9f, 0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5, - 0x97, 0x5f, 0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c, - 0x94, 0x4b, 0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf, - 0xa2, 0x9a, 0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf, - 0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, - 0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43, - 0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, - 0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6, - 0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, - 0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27, - 0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, - 0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16, - 0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, - 0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60, - 0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, - 0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97, - 0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, - 0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11, - 0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, - 0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91, - 0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, - 0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2, - 0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, - 0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83, - 0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, - 0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c, - 0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, - 0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab, - 0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, - 0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1, - 0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, - 0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48, - 0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, - 0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e, - 0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, - 0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29, - 0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, - 0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94, - 0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, - 0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f, - 0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, - 0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06, - 0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, - 0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9, - 0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, - 0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b, - 0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, - 0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e, - 0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, - 0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c, - 0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, - 0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86, - 0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, - 0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02, - 0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, - 0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95, - 0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, - 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, - 0x33, 0xe0, 0xdb, 0x03 -}; - -const size_t kOEMPrivateKeySize_Prod = sizeof(kOEMPrivateKey_Prod); - -// From the team shared drive file -// oem-7913-leaf-and-intermediate-certs-test-key-2-carmichael.p7b, size 2353. -const uint8_t kOEMPublicCert_Prod[] = { - 0x30, 0x82, 0x09, 0x2d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x1e, 0x30, 0x82, 0x09, 0x1a, 0x02, - 0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x08, - 0xfe, 0x30, 0x82, 0x03, 0x71, 0x30, 0x82, 0x02, 0x59, 0xa0, 0x03, 0x02, - 0x01, 0x02, 0x02, 0x11, 0x00, 0xc2, 0x8d, 0x20, 0x22, 0x82, 0x8b, 0x9e, - 0x63, 0x9d, 0x15, 0x89, 0x2c, 0xa9, 0x8f, 0xd9, 0x5d, 0x30, 0x0d, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, - 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, - 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, - 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, - 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31, - 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x31, 0x31, 0x31, 0x31, - 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31, - 0x30, 0x36, 0x31, 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x30, 0x65, 0x31, - 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39, - 0x31, 0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, - 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, - 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, - 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, - 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, - 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, - 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, - 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, - 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, - 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, - 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40, - 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7, - 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56, - 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, - 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34, - 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31, - 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e, - 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39, - 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2, - 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54, - 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3, - 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71, - 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96, - 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a, - 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c, - 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f, - 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca, - 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77, - 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27, - 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, - 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c, - 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16, - 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, - 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, - 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x88, 0x95, 0xec, 0xcd, 0x8b, 0xa7, - 0x51, 0xda, 0x74, 0x81, 0xa5, 0x39, 0x62, 0x1a, 0x0e, 0x2e, 0xde, 0x3c, - 0x37, 0xea, 0xad, 0x7c, 0xee, 0x9b, 0x26, 0x8e, 0xe2, 0xd6, 0x34, 0xcd, - 0xb7, 0x70, 0xba, 0xbf, 0xa0, 0xa3, 0xfe, 0xb3, 0x4b, 0xbc, 0xf4, 0x1c, - 0x72, 0x66, 0x81, 0xd5, 0x09, 0x33, 0x78, 0x0c, 0x61, 0x21, 0xa8, 0xf1, - 0xe2, 0xc9, 0xe2, 0x83, 0xc2, 0x19, 0x02, 0xf2, 0xe8, 0xab, 0x17, 0x36, - 0x3a, 0x0b, 0x20, 0xaf, 0x0f, 0xae, 0x2e, 0x73, 0x68, 0xac, 0x15, 0xee, - 0x9c, 0xc0, 0x92, 0x03, 0x7e, 0x95, 0x63, 0xaa, 0xad, 0x15, 0x96, 0x43, - 0x20, 0x3b, 0xe5, 0x9b, 0x1f, 0xca, 0x02, 0xba, 0xf0, 0x07, 0x76, 0x80, - 0xd7, 0xa3, 0x1a, 0xeb, 0xc8, 0xdb, 0x03, 0x7b, 0x43, 0x56, 0xe5, 0x96, - 0x6b, 0x86, 0xfe, 0x08, 0x58, 0x8a, 0x84, 0xbd, 0xe9, 0x47, 0x18, 0xee, - 0xb2, 0xa8, 0x05, 0x7b, 0xf0, 0xfd, 0xaa, 0xb9, 0x85, 0xcd, 0x7a, 0x0e, - 0x6b, 0x6c, 0x9f, 0xc6, 0x75, 0xd2, 0x2a, 0xfe, 0x5b, 0xf3, 0xb7, 0x31, - 0x6c, 0xac, 0xe3, 0x00, 0x9f, 0xe7, 0xdd, 0xe3, 0x81, 0xc1, 0x36, 0xc3, - 0x1c, 0x5f, 0xdf, 0xf2, 0xc3, 0x5e, 0xfa, 0x55, 0x32, 0xd8, 0x5c, 0xa8, - 0xe5, 0xcc, 0xb6, 0x4a, 0xe9, 0xe2, 0xcc, 0x38, 0x44, 0x07, 0x46, 0x59, - 0x34, 0x84, 0x79, 0xf9, 0xee, 0x3c, 0x4b, 0x48, 0x90, 0xab, 0x73, 0xb0, - 0xa1, 0x92, 0xc3, 0xd6, 0x83, 0x87, 0x81, 0xca, 0x12, 0x81, 0xd6, 0x5d, - 0xf7, 0x6f, 0x7a, 0x35, 0x5e, 0x4f, 0x02, 0x66, 0x8a, 0x47, 0x88, 0x82, - 0xab, 0xf0, 0x12, 0x1d, 0xb9, 0x75, 0x3b, 0x7b, 0xa8, 0x36, 0x15, 0xef, - 0xa8, 0x12, 0x0e, 0x53, 0xb4, 0x83, 0x78, 0x53, 0xc0, 0x52, 0xae, 0xa6, - 0x0a, 0xa0, 0x53, 0xdc, 0x1c, 0x15, 0x22, 0xdd, 0x17, 0x98, 0x30, 0x82, - 0x05, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, - 0x10, 0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25, 0x00, 0x0b, 0x10, - 0x3d, 0xd5, 0xe6, 0xe4, 0x64, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x0b, - 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, - 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, - 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, - 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, - 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, - 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, - 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, - 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, - 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, - 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, - 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, - 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x32, - 0x37, 0x31, 0x31, 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a, - 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, - 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, - 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, - 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, - 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31, - 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, - 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8, - 0x71, 0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c, 0xa9, 0x8b, 0xb3, - 0xd6, 0x66, 0xe4, 0xf6, 0x08, 0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a, - 0x88, 0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19, 0x6c, 0x60, 0xc9, - 0xad, 0x91, 0x1c, 0xbf, 0x04, 0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58, - 0xc2, 0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14, 0xa8, 0xc2, 0x01, - 0xcd, 0xe8, 0x46, 0x60, 0x53, 0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d, - 0x0e, 0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43, 0xe3, 0xb0, 0x00, - 0x12, 0xb4, 0x05, 0x82, 0x4a, 0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12, - 0xaa, 0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c, 0x6c, 0x73, 0xae, - 0x56, 0xf8, 0xab, 0xf7, 0x51, 0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01, - 0x2c, 0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37, 0x89, 0x05, 0xa9, - 0x51, 0x57, 0x72, 0x98, 0x9e, 0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b, - 0x2f, 0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf, 0xf5, 0xd6, 0x9c, - 0xd5, 0x8c, 0xb8, 0x66, 0x42, 0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e, - 0x3e, 0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d, 0xf4, 0x57, 0x7c, - 0x6c, 0x33, 0x34, 0x24, 0x45, 0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c, - 0x03, 0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87, 0x74, 0x82, 0x1a, - 0xbc, 0x0f, 0x76, 0x69, 0xab, 0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8, - 0x2c, 0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90, 0xb5, 0x2d, 0x64, - 0xba, 0xf7, 0xd2, 0x8a, 0xb4, 0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c, - 0x52, 0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70, 0x7e, 0x47, 0x59, - 0x94, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, - 0x82, 0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, - 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, - 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, - 0x02, 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, - 0x04, 0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d, 0xc3, 0xe7, 0xe5, - 0x85, 0xdb, 0x2e, 0x8a, 0xbe, 0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81, - 0xb2, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, - 0x80, 0x14, 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, - 0xf7, 0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, - 0x83, 0xa4, 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, - 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, - 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, - 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, - 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, - 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, - 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, - 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, - 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, - 0x82, 0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, - 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, - 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a, - 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, - 0x02, 0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe, 0x66, 0x34, 0xef, - 0x92, 0x06, 0xe9, 0x88, 0xba, 0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1, - 0x75, 0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36, 0xfd, 0x55, 0xa9, - 0x21, 0x0b, 0xdc, 0xf6, 0xae, 0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04, - 0x1d, 0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba, 0xe6, 0xdd, 0x19, - 0xdd, 0x56, 0xfd, 0xce, 0x06, 0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb, - 0x3d, 0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d, 0x4d, 0xcf, 0x7e, - 0xf0, 0x91, 0x29, 0xc1, 0x77, 0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8, - 0xce, 0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5, 0x9f, 0x9c, 0x1b, - 0xc9, 0x4b, 0x58, 0xdf, 0x96, 0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9, - 0x14, 0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75, 0x2c, 0x2b, 0xbf, - 0x63, 0x7d, 0xc7, 0x4e, 0x7e, 0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5, - 0x5a, 0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2, 0x9c, 0x3c, 0x32, - 0xed, 0x9d, 0x4b, 0x49, 0x05, 0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82, - 0x79, 0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa, 0x4f, 0xef, 0x14, - 0x3c, 0x21, 0xf6, 0x72, 0xb2, 0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70, - 0xbd, 0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59, 0x0c, 0x0f, 0x11, - 0x75, 0xd4, 0xbb, 0xb1, 0xdf, 0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43, - 0x17, 0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83, 0x51, 0xfb, 0x16, - 0xfb, 0x64, 0xb6, 0x46, 0xda, 0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a, - 0x84, 0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde, 0xa5, 0x97, 0x66, - 0x79, 0x02, 0xf8, 0x97, 0x17, 0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae, - 0x99, 0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5, 0x80, 0xba, 0xbf, - 0xdd, 0x24, 0xe5, 0xe6, 0x1e, 0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60, - 0x81, 0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c, 0x1a, 0x63, 0xb0, - 0xeb, 0xe6, 0x95, 0x86, 0x0d, 0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0, - 0xbe, 0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec, 0xf9, 0xcd, 0x49, - 0xc6, 0xfe, 0x4d, 0x7f, 0x44, 0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98, - 0xe2, 0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc, 0x76, 0x69, 0x51, - 0x10, 0x01, 0x46, 0x7d, 0x33, 0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c, - 0xc6, 0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a, 0x58, 0x6a, 0xf1, - 0x75, 0x9e, 0xea, 0x1b, 0x4c, 0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32, - 0x44, 0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2, 0xfa, 0xa1, 0x5f, - 0x2e, 0x66, 0xe9, 0x97, 0xcb, 0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86, - 0x2c, 0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1, 0xc9, 0x8b, 0x05, - 0x92, 0x6f, 0x47, 0x96, 0xce, 0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b, - 0xd7, 0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a, 0xf9, 0xb9, 0xb0, - 0x93, 0xf0, 0x81, 0x78, 0x10, 0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf, - 0xbc, 0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8, 0x13, 0x77, 0x4f, - 0x78, 0x9e, 0x40, 0x8d, 0xe6, 0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25, - 0x49, 0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd, 0xf5, 0xb1, 0x54, - 0x74, 0x1b, 0x67, 0x3c, 0x46, 0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83, - 0x30, 0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d, 0xd0, 0x68, 0x31, - 0x00 -}; - -const size_t kOEMPublicCertSize_Prod = sizeof(kOEMPublicCert_Prod); - -// Refer to the following in main modules. -// This level of indirection is present so new OEM Certificates can be -// added and then selected for use at compile time or run time. - -const uint32_t kOEMSystemId = kOEMSystemId_Prod; - -const uint8_t* kOEMPrivateKey = kOEMPrivateKey_Prod; -const uint8_t* kOEMPublicCert = kOEMPublicCert_Prod; - -const size_t kOEMPrivateKeySize = kOEMPrivateKeySize_Prod; -const size_t kOEMPublicCertSize = kOEMPublicCertSize_Prod; - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oem_cert.h b/oemcrypto/ref/src/oem_cert.h deleted file mode 100644 index 3d0476b..0000000 --- a/oemcrypto/ref/src/oem_cert.h +++ /dev/null @@ -1,21 +0,0 @@ -// This header is used to access the OEM certificate if one is in use. -#ifndef OEM_CERT_H_ -#define OEM_CERT_H_ - -#include -#include - -namespace wvoec_ref { - -// Refer to the following in main modules -extern const uint32_t kOEMSystemId; - -extern const uint8_t* kOEMPrivateKey; -extern const uint8_t* kOEMPublicCert; - -extern const size_t kOEMPrivateKeySize; -extern const size_t kOEMPublicCertSize; - -} // namespace wvoec_ref - -#endif // OEM_CERT_H_ diff --git a/oemcrypto/ref/src/oemcrypto_auth_ref.cpp b/oemcrypto/ref/src/oemcrypto_auth_ref.cpp deleted file mode 100644 index f3d9a45..0000000 --- a/oemcrypto/ref/src/oemcrypto_auth_ref.cpp +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_auth_ref.h" - -#include - -#include "keys.h" -#include "log.h" -#include "oemcrypto_rsa_key_shared.h" - -namespace { - -// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format -// This is the RSA Test Key. This key is not derived -// from any Widevine authentication root. -static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = { - 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, - 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, - 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, - 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, - 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, - 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, - 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, - 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, - 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, - 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, - 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, - 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, - 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, - 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, - 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, - 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, - 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, - 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, - 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, - 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, - 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, - 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, - 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, - 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, - 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, - 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, - 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, - 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, - 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, - 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, - 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, - 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, - 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, - 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, - 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, - 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, - 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x5e, - 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05, - 0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29, - 0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, 0xac, 0x97, - 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7, - 0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d, - 0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, 0x7e, 0xdc, - 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c, - 0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1, - 0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, 0x79, 0xf9, - 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3, - 0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba, - 0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, 0x71, 0xe7, - 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75, - 0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22, - 0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, 0xe8, 0x88, - 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78, - 0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21, - 0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, 0x37, 0x14, - 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47, - 0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa, - 0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, 0x87, 0x27, - 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d, - 0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51, - 0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, 0xb6, 0x64, - 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53, - 0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77, - 0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, 0x07, 0x5f, - 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29, - 0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0, - 0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, 0xc9, 0x21, - 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81, - 0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02, - 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c, 0xbe, 0x6d, - 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75, - 0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, - 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85, 0xab, 0x04, - 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda, - 0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, - 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86, 0x7b, 0xd0, - 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f, - 0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, - 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7, 0x1e, 0x64, - 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8, - 0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, - 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a, 0xcc, 0x48, - 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44, - 0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, - 0x33, 0x85, 0x26, 0x60, 0x48, 0x16, 0xcb, 0xef, - 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce, - 0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, - 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49, 0xc2, 0x19, - 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28, - 0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, - 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17, 0x68, 0x78, - 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3, - 0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, - 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d, 0xeb, 0x3f, - 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41, - 0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, - 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d, 0x8e, 0x87, - 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd, - 0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, - 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67, 0xa9, 0x55, - 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17, - 0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, - 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83, 0x39, 0x57, - 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0, - 0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, - 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b, 0x1b, 0x43, - 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c, - 0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, - 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25, 0x92, 0xe4, - 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f, - 0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, - 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d, 0x45, 0xdc, - 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41, - 0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, - 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71, 0x16, 0xd8, - 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5, - 0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, - 0x35, 0x95, 0x41, 0x29, 0x40, 0x19, 0x83, 0x35, - 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b, - 0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, - 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c, 0xad, 0x10, - 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8, - 0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, - 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec, 0x5e, 0x61, - 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a, - 0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, - 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22, 0xfa, 0x34, - 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a, - 0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, - 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a, 0x2d, 0x0c, - 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a, - 0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, - 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96, 0x76, 0xe8, - 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8, - 0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, - 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6, 0x69, 0x1d, - 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65, - 0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, - 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9, 0xe4, 0xc7, - 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33, - 0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, - 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6, 0x2b, 0xad, - 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35, - 0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, - 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7, 0xab, 0x30, - 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4, - 0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, - 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae, 0x84, 0x6b, - 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde, - 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, - 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03 -}; - -} // namespace - -namespace wvoec_ref { - -AuthenticationRoot::AuthenticationRoot(OEMCrypto_ProvisioningMethod method) : - provisioning_method_(method), - use_test_keybox_(false) { - if ((provisioning_method_ == OEMCrypto_DrmCertificate) && - !rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) { - // This error message is OK in unit tests which use test certificate. - LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a " - "keybox, but the certificate could not be loaded."); - } -} - -KeyboxError AuthenticationRoot::ValidateKeybox() { - return keybox().Validate(); -} - -bool AuthenticationRoot::LoadTestRsaKey() { - return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048, - sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); -} - -bool AuthenticationRoot::Validate() { - return NO_ERROR == ValidateKeybox(); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_auth_ref.h b/oemcrypto/ref/src/oemcrypto_auth_ref.h deleted file mode 100644 index 4e8ede7..0000000 --- a/oemcrypto/ref/src/oemcrypto_auth_ref.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef OEMCRYPTO_AUTH_REF_H_ -#define OEMCRYPTO_AUTH_REF_H_ - -#include -#include -#include - -#include - -#include "OEMCryptoCENC.h" // Needed for enums only. -#include "disallow_copy_and_assign.h" -#include "oemcrypto_key_ref.h" -#include "oemcrypto_keybox_ref.h" -#include "oemcrypto_rsa_key_shared.h" -#include "oemcrypto_types.h" - -namespace wvoec_ref { - -class AuthenticationRoot { - public: - explicit AuthenticationRoot(OEMCrypto_ProvisioningMethod method); - ~AuthenticationRoot() {} - - bool Validate(); - - KeyboxError ValidateKeybox(); - - bool InstallKeybox(const uint8_t* keybox_data, size_t keybox_length) { - return keybox().InstallKeybox(keybox_data, keybox_length); - } - - const std::vector& DeviceKey(bool use_real_keybox = false) { - return use_real_keybox ? real_keybox().device_key() : - keybox().device_key(); - } - - const std::vector& DeviceId() { - return keybox().device_id(); - } - - size_t DeviceTokenLength() { - return keybox().key_data_length(); - } - - const uint8_t* DeviceToken() { - return keybox().key_data(); - } - - WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; } - bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) { - use_test_keybox_ = true; - return test_keybox_.InstallKeybox(keybox_data, keybox_length); - } - - RSA_shared_ptr& SharedRsaKey() { return rsa_key_; } - RSA* rsa_key() { return rsa_key_.get(); } - bool LoadTestRsaKey(); - void Clear() { use_test_keybox_ = false; } - - private: - OEMCrypto_ProvisioningMethod provisioning_method_; - WvKeybox& real_keybox() { return keybox_; } - - WvKeybox keybox_; - WvKeybox test_keybox_; - bool use_test_keybox_; - - RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate. - - CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot); -}; - -} // namespace wvoec_ref - -#endif // OEMCRYPTO_AUTH_REF_H_ diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties.cpp deleted file mode 100644 index 8c4bd22..0000000 --- a/oemcrypto/ref/src/oemcrypto_engine_device_properties.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// - -#include "oemcrypto_engine_ref.h" - -#include - -namespace wvoec_ref { - -CryptoEngine* CryptoEngine::MakeCryptoEngine( - std::unique_ptr&& file_system) { - return new CryptoEngine(std::move(file_system)); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties_L1.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties_L1.cpp deleted file mode 100644 index 9e9b7c5..0000000 --- a/oemcrypto/ref/src/oemcrypto_engine_device_properties_L1.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -// This file contains oemcrypto engine properties that would be for a -// level 1 device. -#include "oemcrypto_engine_ref.h" - -#include - -namespace wvoec_ref { - -class L1CryptoEngine : public CryptoEngine { - public: - explicit L1CryptoEngine(std::unique_ptr&& file_system) - : CryptoEngine(std::move(file_system)) {} - - bool config_local_display_only() { return true; } - - OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() { - return HDCP_V2; - } - - bool config_is_anti_rollback_hw_present() { return true; } - - const char* config_security_level() { return "L1"; } - - // This should start at 0, and be incremented only when a security patch has - // been applied to the device that fixes a security bug. - uint8_t config_security_patch_level() { return 3; } -}; - -CryptoEngine* CryptoEngine::MakeCryptoEngine( - std::unique_ptr&& file_system) { - return new L1CryptoEngine(std::move(file_system)); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties_cert.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties_cert.cpp deleted file mode 100644 index 146a829..0000000 --- a/oemcrypto/ref/src/oemcrypto_engine_device_properties_cert.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -// This file contains oemcrypto engine properties that would be for a device -// that does not have persistant storage or a keybox. -// -// Note: We also define it to be L2 for illustration only. Production devices -// are rarely level 2. -#include "oemcrypto_engine_ref.h" - -namespace wvoec_ref { - -class CertOnlyCryptoEngine : public CryptoEngine { - public: - explicit CertOnlyCryptoEngine(std::unique_ptr&& file_system) - : CryptoEngine(std::move(file_system)) {} - - bool config_local_display_only() { return true; } - - bool config_supports_usage_table() { return false; } - - OEMCrypto_ProvisioningMethod config_provisioning_method() { - return OEMCrypto_DrmCertificate; - } - - const char* config_security_level() { return "L2"; } -}; - -CryptoEngine* CryptoEngine::MakeCryptoEngine( - std::unique_ptr&& file_system) { - return new CertOnlyCryptoEngine(std::move(file_system)); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp deleted file mode 100644 index 7e3c2eb..0000000 --- a/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -// This file contains oemcrypto engine properties that would be for a -// level 2 device that does not have persistant storage or a keybox. -// Note: this is for illustration only. Production devices are rarely level 2. - -#include "oemcrypto_engine_ref.h" - -#include - -#include - -#include "log.h" -#include "oem_cert.h" - -namespace wvoec_ref { - -class Prov30CryptoEngine : public CryptoEngine { - public: - explicit Prov30CryptoEngine(std::unique_ptr&& file_system) - : CryptoEngine(std::move(file_system)) {} - - bool config_local_display_only() { return true; } - - // Returns the max HDCP version supported. - OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() { - return HDCP_NO_DIGITAL_OUTPUT; - } - - // Returns true if the client supports persistent storage of - // offline usage table information. - bool config_supports_usage_table() { - return false; - } - - // Returns true if the client uses a keybox as the root of trust. - bool config_supports_keybox() { - return false; - } - - // This version uses an OEM Certificate. - OEMCrypto_ProvisioningMethod config_provisioning_method() { - return OEMCrypto_OEMCertificate; - } - - OEMCryptoResult get_oem_certificate(SessionContext* session, - uint8_t* public_cert, - size_t* public_cert_length) { - if (kOEMPublicCertSize == 0) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (public_cert_length == nullptr) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (*public_cert_length < kOEMPublicCertSize) { - *public_cert_length = kOEMPublicCertSize; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *public_cert_length = kOEMPublicCertSize; - if (public_cert == nullptr) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize); - if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) { - LOGE("Private RSA Key did not load correctly."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - return OEMCrypto_SUCCESS; - } - - // Returns "L3" for a software only library. L1 is for hardware protected - // keys and data paths. L2 is for hardware protected keys but no data path - // protection. - const char* config_security_level() { return "L2"; } -}; - -CryptoEngine* CryptoEngine::MakeCryptoEngine( - std::unique_ptr&& file_system) { - return new Prov30CryptoEngine(std::move(file_system)); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp deleted file mode 100644 index 9195617..0000000 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_engine_ref.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "clock.h" -#include "keys.h" -#include "log.h" -#include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" -#include "string_conversions.h" - -namespace { - -// Lower bits in SessionId are actual session id. The rest higher bits are -// session type. -const uint32_t kSessionIdTypeShift = 28; -const uint32_t kSessionIdMask = (1u << kSessionIdTypeShift) - 1u; -} // namespace - -namespace wvoec_ref { - -// Note: The class CryptoEngine is configured at compile time by compiling in -// different device property files. The methods in this file are generic to -// all configurations. See the files oemcrypto_engine_device_properties*.cpp -// for methods that are configured for specific configurations. - -CryptoEngine::CryptoEngine(std::unique_ptr&& file_system) - : root_of_trust_(config_provisioning_method()), - file_system_(std::move(file_system)), - usage_table_() { - ERR_load_crypto_strings(); -} - -CryptoEngine::~CryptoEngine() { - ERR_free_strings(); -} - -bool CryptoEngine::Initialize() { - std::string file_path = GetUsageTimeFileFullPath(); - LoadOfflineTimeInfo(file_path); - usage_table_.reset(MakeUsageTable()); - return true; -} - -void CryptoEngine::Terminate() { - std::string file_path = GetUsageTimeFileFullPath(); - SaveOfflineTimeInfo(file_path); - std::unique_lock lock(session_table_lock_); - ActiveSessions::iterator it; - for (it = sessions_.begin(); it != sessions_.end(); ++it) { - delete it->second; - } - sessions_.clear(); - root_of_trust_.Clear(); -} - -SessionId CryptoEngine::OpenSession() { - std::unique_lock lock(session_table_lock_); - static OEMCrypto_SESSION unique_id = 1; - SessionId id = ++unique_id; - // Check if too many sessions have been opened. - if (SessionTypeBits(id) != 0) { - return 0; - } - // Apply session type to higher bits. - id = (kSessionTypeOEMCrypto << kSessionIdTypeShift) | (id & kSessionIdMask); - sessions_[id] = MakeSession(id); - return id; -} - -SessionContext* CryptoEngine::MakeSession(SessionId sid) { - return new SessionContext(this, sid, root_of_trust_.SharedRsaKey()); -} - -UsageTable* CryptoEngine::MakeUsageTable() { return new UsageTable(this); } - -bool CryptoEngine::DestroySession(SessionId sid) { - SessionContext* sctx = FindSession(sid); - std::unique_lock lock(session_table_lock_); - if (sctx) { - sessions_.erase(sid); - delete sctx; - return true; - } else { - return false; - } -} - -SessionContext* CryptoEngine::FindSession(SessionId sid) { - std::unique_lock lock(session_table_lock_); - ActiveSessions::iterator it = sessions_.find(sid); - if (it != sessions_.end()) { - return it->second; - } - return nullptr; -} - -int64_t CryptoEngine::MonotonicTime() { - // Use the monotonic clock for times that don't have to be stable across - // device boots. - int64_t now = - wvcdm::Clock().GetCurrentTime() + offline_time_info_.rollback_offset; - static int64_t then = now; - if (now < then) { - LOGW("Clock rollback detected: %ld seconds", then - now); - offline_time_info_.rollback_offset += then - now; - now = then; - } - then = now; - return now; -} - -int64_t CryptoEngine::SystemTime() { - const int64_t current_time = MonotonicTime(); - // Write time info to disk if kTimeInfoUpdateWindowInSeconds has elapsed since - // last write. - if (current_time - offline_time_info_.previous_time > - kTimeInfoUpdateWindowInSeconds) { - std::string file_path = GetUsageTimeFileFullPath(); - SaveOfflineTimeInfo(file_path); - } - return current_time; -} - -std::string CryptoEngine::GetUsageTimeFileFullPath() const { - std::string file_path; - // Note: file path is OK for a real implementation, but using security - // level 1 would be better. - // TODO(fredgc, jfore): Address how this property is presented to the ref. - // For now, the file path is empty. - /*if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3, - &file_path)) { - LOGE("Unable to get base path"); - }*/ - return file_path + kStoredUsageTimeFileName; -} - -bool CryptoEngine::LoadOfflineTimeInfo(const std::string& file_path) { - memset(&offline_time_info_, 0, sizeof(TimeInfo)); - wvcdm::FileSystem* file_system = file_system_.get(); - if (file_system->Exists(file_path)) { - std::unique_ptr file = - file_system->Open(file_path, wvcdm::FileSystem::kReadOnly); - if (!file) { - // This error is expected at first initialization. - LOGE("File open failed (this is expected on first initialization): %s", - file_path.c_str()); - return false; - } - // Load time info from previous call. - file->Read(reinterpret_cast(&offline_time_info_), sizeof(TimeInfo)); - - // Detect offline time rollback after loading from disk. - // Add any time offsets in the past to the current time. - int64_t current_time = MonotonicTime(); - if (offline_time_info_.previous_time > current_time) { - // Current time is earlier than the previously saved time. Time has been - // rolled back. Update the rollback offset. - offline_time_info_.rollback_offset += - offline_time_info_.previous_time - current_time; - // Keep current time at previous recorded time. - current_time = offline_time_info_.previous_time; - } - // The new previous_time will either stay the same or move forward. - offline_time_info_.previous_time = current_time; - } - return true; -} - -bool CryptoEngine::SaveOfflineTimeInfo(const std::string& file_path) { - // Add any time offsets in the past to the current time. If there was an - // earlier offline rollback, the rollback offset will be updated in - // LoadOfflineTimeInfo(). It guarantees that the current time to be saved - // will never go back. - const int64_t current_time = MonotonicTime(); - // The new previous_time will either stay the same or move forward. - if (current_time > offline_time_info_.previous_time) - offline_time_info_.previous_time = current_time; - - std::unique_ptr file; - wvcdm::FileSystem* file_system = file_system_.get(); - // Write the current time and offset to disk. - file = file_system->Open( - file_path, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate); - if (!file) { - LOGE("File open failed: %s", file_path.c_str()); - return false; - } - file->Write(reinterpret_cast(&offline_time_info_), sizeof(TimeInfo)); - return true; -} - -bool CryptoEngine::NonceCollision(uint32_t nonce) { - for (const auto& session_pair : sessions_) { - const SessionContext* session = session_pair.second; - if (nonce == session->nonce()) return true; - } - return false; -} - -OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() { - return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; -} - -OEMCrypto_HDCP_Capability CryptoEngine::config_maximum_hdcp_capability() { - return HDCP_NO_DIGITAL_OUTPUT; -} - -OEMCryptoResult CryptoEngine::SetDestination( - const OEMCrypto_DestBufferDesc& out_description, size_t data_length, - uint8_t subsample_flags) { - size_t max_length = 0; - switch (out_description.type) { - case OEMCrypto_BufferType_Clear: - destination_ = out_description.buffer.clear.address; - max_length = out_description.buffer.clear.address_length; - break; - case OEMCrypto_BufferType_Secure: - if (out_description.buffer.secure.handle_length < - out_description.buffer.secure.offset) { - LOGE("Secure buffer offset too large: %zu < %zu", - out_description.buffer.secure.handle_length, - out_description.buffer.secure.offset); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - destination_ = - reinterpret_cast(out_description.buffer.secure.handle) + - out_description.buffer.secure.offset; - max_length = out_description.buffer.secure.handle_length - - out_description.buffer.secure.offset; - break; - case OEMCrypto_BufferType_Direct: - // Direct buffer type is only used on some specialized devices where - // oemcrypto has a direct connection to the screen buffer. It is not, - // for example, supported on Android. - destination_ = nullptr; - break; - default: - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const size_t max_allowed = max_sample_size(); - if (max_allowed > 0 && - (max_allowed < max_length || max_allowed < data_length)) { - LOGE("Output too large (or buffer too small)."); - return OEMCrypto_ERROR_OUTPUT_TOO_LARGE; - } - - if (out_description.type != OEMCrypto_BufferType_Direct && - max_length < data_length) { - LOGE("[SetDestination(): OEMCrypto_ERROR_SHORT_BUFFER]"); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - adjust_destination(out_description, data_length, subsample_flags); - if ((out_description.type != OEMCrypto_BufferType_Direct) && - (destination_ == nullptr)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return OEMCrypto_SUCCESS; -} - -uint32_t CryptoEngine::SessionTypeBits(SessionId sid) { - return sid >> kSessionIdTypeShift; -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.h b/oemcrypto/ref/src/oemcrypto_engine_ref.h deleted file mode 100644 index aadb512..0000000 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef REF_OEMCRYPTO_ENGINE_REF_H_ -#define REF_OEMCRYPTO_ENGINE_REF_H_ - -#include -#include -#include -#include -#include -#include - -#include - -#include "OEMCryptoCENC.h" -#include "file_store.h" -#include "oemcrypto_auth_ref.h" -#include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" -#include "oemcrypto_session.h" -#include "oemcrypto_types.h" -#include "oemcrypto_usage_table_ref.h" - -namespace wvoec_ref { - -typedef std::map ActiveSessions; - -static const std::string kStoredUsageTimeFileName = "StoredUsageTime.dat"; - -typedef struct { - // The max time recorded - int64_t previous_time; - // If the wall time is rollbacked to before the previous_time, this member - // is updated to reflect the offset. - int64_t rollback_offset; - // Pad the struct so that TimeInfo is a multiple of 16. - uint8_t padding[16 - (2 * sizeof(time_t)) % 16]; -} TimeInfo; - -// Session types are higher (32 - kSessionIdTypeShift) bits in SessionId. -typedef enum SessionType { - kSessionTypeOEMCrypto = 0, - kSessionTypeEntitledKey = 1, -} SessionType; - -class CryptoEngine { - public: - static const uint32_t kApiVersion = 16; - static const uint32_t kMinorApiVersion = 4; - static const int64_t kTimeInfoUpdateWindowInSeconds = 300; - - // This is like a factory method, except we choose which version to use at - // compile time. It is defined in several source files. The build system - // should choose which one to use by only linking in the correct one. - // NOTE: The caller must instantiate a FileSystem object - ownership - // will be transferred to the new CryptoEngine object. - static CryptoEngine* MakeCryptoEngine( - std::unique_ptr&& file_system); - - virtual ~CryptoEngine(); - - virtual bool Initialize(); - - bool ValidRootOfTrust() { return root_of_trust_.Validate(); } - - bool InstallKeybox(const uint8_t* keybox, size_t keybox_length) { - return root_of_trust_.InstallKeybox(keybox, keybox_length); - } - - bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) { - return root_of_trust_.UseTestKeybox(keybox_data, keybox_length); - } - - bool LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); } - - KeyboxError ValidateKeybox() { return root_of_trust_.ValidateKeybox(); } - - const std::vector& DeviceRootKey() { - return root_of_trust_.DeviceKey(); - } - - const std::vector& DeviceRootId() { - return root_of_trust_.DeviceId(); - } - - size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); } - - const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); } - - virtual void Terminate(); - - virtual SessionId OpenSession(); - - virtual bool DestroySession(SessionId sid); - - SessionContext* FindSession(SessionId sid); - - size_t GetNumberOfOpenSessions() { return sessions_.size(); } - - size_t GetMaxNumberOfSessions() { - // An arbitrary limit for ref implementation. - static const size_t kMaxSupportedOEMCryptoSessions = 64; - return kMaxSupportedOEMCryptoSessions; - } - - // The OEMCrypto system time. Prevents time rollback. - int64_t SystemTime(); - - // Verify that this nonce does not collide with another nonce in any session. - virtual bool NonceCollision(uint32_t nonce); - - // Returns the HDCP version currently in use. - virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability(); - - // Returns the max HDCP version supported. - virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability(); - - // Return true if there might be analog video output enabled. - virtual bool analog_display_active() { return !config_local_display_only(); } - - // Return true if there is an analog display, and CGMS A is turned on. - virtual bool cgms_a_active() { return false; } - - // Return the analog output flags. - virtual uint32_t analog_output_flags() { - return config_local_display_only() ? OEMCrypto_No_Analog_Output - : OEMCrypto_Supports_Analog_Output; - } - - UsageTable& usage_table() { return *(usage_table_.get()); } - wvcdm::FileSystem* file_system() { return file_system_.get(); } - - // If config_local_display_only() returns true, we pretend we are using a - // built-in display, instead of HDMI or WiFi output. - virtual bool config_local_display_only() { return false; } - - // A closed platform is permitted to use clear buffers. - virtual bool config_closed_platform() { return false; } - - // Returns true if the client supports persistent storage of - // offline usage table information. - virtual bool config_supports_usage_table() { return true; } - - virtual OEMCrypto_ProvisioningMethod config_provisioning_method() { - return OEMCrypto_Keybox; - } - - virtual OEMCryptoResult get_oem_certificate(uint8_t* public_cert, - size_t* public_cert_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - virtual OEMCryptoResult load_oem_private_key(SessionContext* session) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - // Used for OEMCrypto_IsAntiRollbackHwPresent. - virtual bool config_is_anti_rollback_hw_present() { return false; } - - // Returns "L3" for a software only library. L1 is for hardware protected - // data paths. - virtual const char* config_security_level() { return "L3"; } - - // This should start at 0, and be incremented only when a security patch has - // been applied to the device that fixes a security bug. - virtual uint8_t config_security_patch_level() { return 0; } - - // If 0 no restriction, otherwise it's the max subsample size for - // DecryptCENC. This is not the same as the max sample or buffer size. - virtual size_t max_subsample_size() { return 4 * 1024 * 1024; } // 4 MiB - - // If 0 no restriction, otherwise it's the max sample size for DecryptCENC. - // This is the same as the max input and output buffer size for DecryptCENC - // and CopyBuffer. It is not the same as the max subsample size. - virtual size_t max_sample_size() { return 16 * 1024 * 1024; } // 16 MiB - - virtual bool srm_update_supported() { return false; } - - virtual OEMCryptoResult current_srm_version(uint16_t* version) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - virtual OEMCryptoResult load_srm(const uint8_t* buffer, - size_t buffer_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - virtual OEMCryptoResult remove_srm() { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - virtual bool srm_forbidden_device_attached() { return false; } - - // Rate limit for nonce generation. Default to 200 nonce/second. - virtual int nonce_flood_count() { return 200; } - - // Limit for size of usage table. If this is zero, then the - // size is unlimited -- or limited only by memory size. - virtual size_t max_usage_table_size() { return 0; } - - virtual uint32_t resource_rating() { return 1; } - - // Set destination pointer based on the output destination description. - OEMCryptoResult SetDestination( - const OEMCrypto_DestBufferDesc& out_description, size_t data_length, - uint8_t subsample_flags); - - // The current destination. - uint8_t* destination() { return destination_; } - - // Subclasses can adjust the destination -- for use in testing. - virtual void adjust_destination( - const OEMCrypto_DestBufferDesc& out_description, size_t data_length, - uint8_t subsample_flags) {} - - // Push destination buffer to output -- used by subclasses for testing. - virtual OEMCryptoResult PushDestination( - const OEMCrypto_DestBufferDesc& out_description, - uint8_t subsample_flags) { - return OEMCrypto_SUCCESS; - } - - // Get the session type bits from |sid|. - static uint32_t SessionTypeBits(SessionId sid); - - protected: - // System clock, measuring time in seconds, including anti-rollback offset. - int64_t MonotonicTime(); - - bool LoadOfflineTimeInfo(const std::string& file_path); - bool SaveOfflineTimeInfo(const std::string& file_path); - std::string GetUsageTimeFileFullPath() const; - - explicit CryptoEngine(std::unique_ptr&& file_system); - virtual SessionContext* MakeSession(SessionId sid); - virtual UsageTable* MakeUsageTable(); - uint8_t* destination_; - ActiveSessions sessions_; - AuthenticationRoot root_of_trust_; - std::mutex session_table_lock_; - std::unique_ptr file_system_; - std::unique_ptr usage_table_; - TimeInfo offline_time_info_; - - CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine); -}; - -} // namespace wvoec_ref - -#endif // REF_OEMCRYPTO_ENGINE_REF_H_ diff --git a/oemcrypto/ref/src/oemcrypto_key_ref.cpp b/oemcrypto/ref/src/oemcrypto_key_ref.cpp deleted file mode 100644 index 19a80f2..0000000 --- a/oemcrypto/ref/src/oemcrypto_key_ref.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_key_ref.h" -#include "oemcrypto_types.h" - -#include -#include - -#include "log.h" - -namespace wvoec_ref { - -bool KeyControlBlock::Validate() { - if (memcmp(verification_, "kctl", 4) && // original verification - memcmp(verification_, "kc09", 4) && // add in version 9 api - memcmp(verification_, "kc10", 4) && // add in version 10 api - memcmp(verification_, "kc11", 4) && // add in version 11 api - memcmp(verification_, "kc12", 4) && // add in version 12 api - memcmp(verification_, "kc13", 4) && // add in version 13 api - memcmp(verification_, "kc14", 4) && // add in version 14 api - memcmp(verification_, "kc15", 4) && // add in version 15 api - memcmp(verification_, "kc16", 4)) { // add in version 16 api - LOGE("KCB: BAD verification string: %4.4s", verification_); - valid_ = false; - } else { - valid_ = true; - } - return valid_; -} - -// This extracts 4 bytes in network byte order to a 32 bit integer in -// host byte order. -uint32_t KeyControlBlock::ExtractField(const std::vector& str, - int idx) { - int bidx = idx * 4; - uint32_t t = static_cast(str[bidx]) << 24; - t |= static_cast(str[bidx + 1]) << 16; - t |= static_cast(str[bidx + 2]) << 8; - t |= static_cast(str[bidx + 3]); - return t; -} - -KeyControlBlock::KeyControlBlock( - const std::vector& key_control_string) { - if (key_control_string.size() < wvoec::KEY_CONTROL_SIZE) { - LOGE("KCB: BAD Size: %zu (not %zu)", key_control_string.size(), - wvoec::KEY_CONTROL_SIZE); - return; - } - - memcpy(verification_, &key_control_string[0], 4); - duration_ = ExtractField(key_control_string, 1); - nonce_ = ExtractField(key_control_string, 2); - control_bits_ = ExtractField(key_control_string, 3); - Validate(); -} - -void Key::UpdateDuration(const KeyControlBlock& control) { - control_.set_duration(control.duration()); -} - -void KeyControlBlock::RequireLocalDisplay() { - // Set all bits to require HDCP Local Display Only. - control_bits_ |= wvoec::kControlHDCPVersionMask; -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_key_ref.h b/oemcrypto/ref/src/oemcrypto_key_ref.h deleted file mode 100644 index a94f24f..0000000 --- a/oemcrypto/ref/src/oemcrypto_key_ref.h +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef OEMCRYPTO_KEY_REF_H_ -#define OEMCRYPTO_KEY_REF_H_ - -#include -#include -#include - -namespace wvoec_ref { - -class KeyControlBlock { - public: - KeyControlBlock(const std::vector& key_control_string); - ~KeyControlBlock() {} - - bool Validate(); - void Invalidate() { valid_ = false; } - - bool valid() const { return valid_; } - uint32_t duration() const { return duration_; } - void set_duration(uint32_t duration) { duration_ = duration; } - uint32_t nonce() const { return nonce_; } - const char* verification() const { return verification_; } - uint32_t control_bits() const { return control_bits_; } - void RequireLocalDisplay(); - - private: - uint32_t ExtractField(const std::vector& str, int idx); - - bool valid_; - char verification_[4]; - uint32_t duration_; - uint32_t nonce_; - uint32_t control_bits_; -}; - -// AES-128 crypto key, or HMAC signing key. -class Key { - public: - Key(const Key& key) - : value_(key.value_), control_(key.control_), ctr_mode_(key.ctr_mode_) {} - Key(const std::vector& key_string, const KeyControlBlock& control) - : value_(key_string), control_(control), ctr_mode_(true){}; - - virtual ~Key() {}; - void UpdateDuration(const KeyControlBlock& control); - virtual const std::vector& value() const { return value_; } - const KeyControlBlock& control() const { return control_; } - bool ctr_mode() const { return ctr_mode_; } - void set_ctr_mode(bool ctr_mode) { ctr_mode_ = ctr_mode; } - - private: - std::vector value_; - KeyControlBlock control_; - bool ctr_mode_; -}; - -// AES-256 entitlement key. |Key| holds the entitlement key. |EntitlementKey| -// holds the content key. -class EntitlementKey : public Key { - public: - EntitlementKey(const Key& key) : Key(key) {} - ~EntitlementKey() override {} - const std::vector& value() const override { return content_key_; } - const std::vector& content_key() { return content_key_; } - const std::vector& content_key_id() { return content_key_id_; } - const std::vector& entitlement_key() { return Key::value(); } - bool SetContentKey(const std::vector& content_key_id, - const std::vector& content_key) { - content_key_.assign(content_key.begin(), content_key.end()); - content_key_id_.assign(content_key_id.begin(), content_key_id.end()); - return true; - } - - private: - std::vector content_key_; - std::vector content_key_id_; -}; - -} // namespace wvoec_ref - -#endif // OEMCRYPTO_KEY_REF_H_ diff --git a/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp b/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp deleted file mode 100644 index e1cc4bc..0000000 --- a/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_keybox_ref.h" - -#include - -#include -#include - -#include "log.h" -#include "oemcrypto_types.h" -#include "platform.h" -#include "wvcrc32.h" - -namespace wvoec_ref { - -WvKeybox::WvKeybox() : loaded_(false) { - static std::string fake_device_id = "device_with_no_keybox"; - device_id_.assign(fake_device_id.begin(), fake_device_id.end()); -} - -KeyboxError WvKeybox::Validate() { - if (!loaded_) { - LOGE("[KEYBOX NOT LOADED]"); - return OTHER_ERROR; - } - if (strncmp(reinterpret_cast(magic_), "kbox", 4) != 0) { - LOGE("[KEYBOX HAS BAD MAGIC]"); - return BAD_MAGIC; - } - uint32_t crc_computed; - uint32_t crc_stored; - uint8_t* crc_stored_bytes = (uint8_t*)&crc_stored; - memcpy(crc_stored_bytes, crc_, sizeof(crc_)); - wvoec::WidevineKeybox keybox; - memset(&keybox, 0, sizeof(keybox)); - memcpy(keybox.device_id_, &device_id_[0], device_id_.size()); - memcpy(keybox.device_key_, &device_key_[0], sizeof(keybox.device_key_)); - memcpy(keybox.data_, key_data_, sizeof(keybox.data_)); - memcpy(keybox.magic_, magic_, sizeof(keybox.magic_)); - - crc_computed = ntohl(wvcrc32(reinterpret_cast(&keybox), - sizeof(keybox) - 4)); // Drop last 4 bytes. - if (crc_computed != crc_stored) { - LOGE("[KEYBOX CRC problem: computed = %08x, stored = %08x]\n", - crc_computed, crc_stored); - return BAD_CRC; - } - return NO_ERROR; -} - -bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) { - if (keyBoxLength != 128) { - return false; - } - const wvoec::WidevineKeybox* keybox = - reinterpret_cast(buffer); - size_t device_id_length = - strnlen(reinterpret_cast(keybox->device_id_), 32); - device_id_.assign(keybox->device_id_, keybox->device_id_ + device_id_length); - device_key_.assign(keybox->device_key_, - keybox->device_key_ + sizeof(keybox->device_key_)); - memcpy(key_data_, keybox->data_, sizeof(keybox->data_)); - memcpy(magic_, keybox->magic_, sizeof(keybox->magic_)); - memcpy(crc_, keybox->crc_, sizeof(keybox->crc_)); - loaded_ = true; - return true; -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_keybox_ref.h b/oemcrypto/ref/src/oemcrypto_keybox_ref.h deleted file mode 100644 index bb543fc..0000000 --- a/oemcrypto/ref/src/oemcrypto_keybox_ref.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef OEMCRYPTO_KEYBOX_REF_H_ -#define OEMCRYPTO_KEYBOX_REF_H_ - -#include "oemcrypto_key_ref.h" - -namespace wvoec_ref { - -const int DEVICE_KEY_LENGTH = 16; -typedef uint8_t WvKeyboxKey[DEVICE_KEY_LENGTH]; - -const int KEY_DATA_LENGTH = 72; -typedef uint8_t WvKeyboxKeyData[KEY_DATA_LENGTH]; - -enum KeyboxError { NO_ERROR, BAD_CRC, BAD_MAGIC, OTHER_ERROR }; - -// Widevine keybox -class WvKeybox { - public: - WvKeybox(); - ~WvKeybox() {} - - KeyboxError Validate(); - const std::vector& device_id() { return device_id_; } - std::vector& device_key() { return device_key_; } - const WvKeyboxKeyData& key_data() { return key_data_; } - size_t key_data_length() { return KEY_DATA_LENGTH; } - bool InstallKeybox(const uint8_t* keybox, size_t keyBoxLength); - - private: - bool loaded_; - std::vector device_id_; - std::vector device_key_; - WvKeyboxKeyData key_data_; - uint8_t magic_[4]; - uint8_t crc_[4]; -}; - -} // namespace wvoec_ref - -#endif // OEMCRYPTO_KEYBOX_REF_H_ diff --git a/oemcrypto/ref/src/oemcrypto_ref.cpp b/oemcrypto/ref/src/oemcrypto_ref.cpp deleted file mode 100644 index d974422..0000000 --- a/oemcrypto/ref/src/oemcrypto_ref.cpp +++ /dev/null @@ -1,1835 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "OEMCryptoCENC.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "file_store.h" -#include "log.h" -#include "odk.h" -#include "oemcrypto_engine_ref.h" -#include "oemcrypto_session.h" -#include "oemcrypto_usage_table_ref.h" -#include "string_conversions.h" - -#if defined(_WIN32) -# define OEMCRYPTO_API extern "C" __declspec(dllexport) -#else // defined(_WIN32) -# define OEMCRYPTO_API extern "C" __attribute__((visibility("default"))) -#endif // defined(_WIN32) - -namespace { -const uint8_t kBakedInCertificateMagicBytes[] = {0xDE, 0xAD, 0xBE, 0xEF}; -// Maximum context key length used for performance reasons, not mandated by -// specification. -const size_t kMaxContextKeyLength = 1024 * 1024; -// Maximum buffer length used by reference implementation for performance -// reasons. This is not mandated by specification. -const size_t kMaxInputMessageBuferLength = 1024 * 1024; -// Maximum signature length used by reference implementation for performance -// reasons. This is not mandated by specification. -const size_t kMaxInputSignatureLength = 10 * 1024; - -// Return uint32 referenced through a potentially unaligned pointer. -// If the pointer is nullptr, return 0. -uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) { - if (unaligned_ptr == nullptr) return 0; - uint32_t value; - const uint8_t* src = reinterpret_cast(unaligned_ptr); - uint8_t* dest = reinterpret_cast(&value); - for (unsigned long i = 0; i < sizeof(value); i++) { - dest[i] = src[i]; - } - return value; -} - -} // namespace - -namespace wvoec_ref { - -static std::unique_ptr crypto_engine; - -typedef struct { - uint8_t signature[wvoec::MAC_KEY_SIZE]; - uint8_t context[wvoec::MAC_KEY_SIZE]; - uint8_t iv[wvoec::KEY_IV_SIZE]; - uint8_t enc_rsa_key[]; -} WrappedRSAKey; - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_Initialize(void) { - if (crypto_engine != nullptr) { - LOGE("------------------------- Calling Initialize without Terminate\n"); - crypto_engine.reset(); - } - // NOTE: This requires a compatible Filesystem implementation. - // NOTE: Ownership of the FileSystem object is transferred to CryptoEngine - std::unique_ptr fs(new wvcdm::FileSystem()); - crypto_engine.reset(CryptoEngine::MakeCryptoEngine(std::move(fs))); - if (crypto_engine == nullptr || !crypto_engine->Initialize()) { - LOGE("[OEMCrypto_Initialize(): failed]"); - return OEMCrypto_ERROR_INIT_FAILED; - } - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_SetSandbox( - const uint8_t* /*sandbox_id*/, size_t /*sandbox_id_length*/) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_Terminate(void) { - if (crypto_engine == nullptr) { - LOGE("[OEMCrypto_Terminate(): not initialized]"); - return OEMCrypto_ERROR_TERMINATE_FAILED; - } - crypto_engine->Terminate(); - crypto_engine.reset(); - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_OpenSession(OEMCrypto_SESSION* session) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_OpenSession: OEMCrypto not initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->GetNumberOfOpenSessions() >= - crypto_engine->GetMaxNumberOfSessions()) { - LOGE("[OEMCrypto_OpenSession(): failed due to too many sessions]"); - return OEMCrypto_ERROR_TOO_MANY_SESSIONS; - } - SessionId sid = crypto_engine->OpenSession(); - if (sid == 0) { - LOGE("OEMCrypto_OpenSession: invalid session id returned."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - *session = (OEMCrypto_SESSION)sid; - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_CloseSession(OEMCrypto_SESSION session) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_CloseSession: OEMCrypto not initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->DestroySession((SessionId)session)) { - return OEMCrypto_ERROR_CLOSE_SESSION_FAILED; - } else { - return OEMCrypto_SUCCESS; - } -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys( - OEMCrypto_SESSION session, const uint8_t* mac_key_context, - size_t mac_key_context_length, const uint8_t* enc_key_context, - size_t enc_key_context_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GenerateDerivedKeys: OEMCrypto not initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - if (mac_key_context_length > kMaxContextKeyLength || - enc_key_context_length > kMaxContextKeyLength) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - - const std::vector mac_ctx_str( - mac_key_context, mac_key_context + mac_key_context_length); - const std::vector enc_ctx_str( - enc_key_context, enc_key_context + enc_key_context_length); - - // Generate mac and encryption keys for current session context - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), mac_ctx_str, - enc_ctx_str)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, - uint32_t* nonce) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GenerateNonce: OEMCrypto not initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_GenerateNonce(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - - // Prevent nonce flood. - static std::chrono::steady_clock clock; - const auto now = clock.now().time_since_epoch(); - static auto last_nonce_time = now; - // For testing, we set nonce_flood_count to 1. Since count is initialized to - // 1, the very first nonce after initialization is counted as a flood. - static int nonce_count = 1; - - if (now - last_nonce_time < std::chrono::seconds(1)) { - nonce_count++; - if (nonce_count > crypto_engine->nonce_flood_count()) { - LOGE("[OEMCrypto_GenerateNonce(): Nonce Flood detected]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } else { - nonce_count = 1; - last_nonce_time = now; - } - - uint32_t nonce_value = 0; - uint8_t* nonce_string = reinterpret_cast(&nonce_value); - - while (nonce_value == 0 || crypto_engine->NonceCollision(nonce_value)) { - // Generate 4 bytes of random data - if (RAND_bytes(nonce_string, 4) != 1) { - LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - if (!session_ctx->set_nonce(nonce_value)) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - *nonce = nonce_value; - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( - OEMCrypto_SESSION session, uint8_t* message, size_t message_length, - size_t* core_message_length, uint8_t* signature, size_t* signature_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("OEMCrypto_ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->PrepAndSignLicenseRequest(message, message_length, - core_message_length, signature, - signature_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest( - OEMCrypto_SESSION session, uint8_t* message, size_t message_length, - size_t* core_message_length, uint8_t* signature, size_t* signature_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("OEMCrypto_ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->PrepAndSignRenewalRequest(message, message_length, - core_message_length, signature, - signature_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( - OEMCrypto_SESSION session, uint8_t* message, size_t message_length, - size_t* core_message_length, uint8_t* signature, size_t* signature_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("OEMCrypto_ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->PrepAndSignProvisioningRequest( - message, message_length, core_message_length, signature, - signature_length); -} - -bool RangeCheck(const uint8_t* message, uint32_t message_length, - const uint8_t* field, uint32_t field_length, bool allow_null) { - if (field == nullptr) return allow_null; - if (field < message) return false; - if (field + field_length > message + message_length) return false; - return true; -} - -bool RangeCheck(uint32_t message_length, const OEMCrypto_Substring& substring, - bool allow_null) { - if (!substring.length) return allow_null; - if (substring.offset > message_length) return false; - if (substring.offset + substring.length > message_length) return false; - return true; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session, - const uint8_t* message, - size_t message_length, - size_t core_message_length, - const uint8_t* signature, - size_t signature_length) { - if (crypto_engine == nullptr) { - LOGE("not initialized"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("ERROR_KEYBOX_INVALID"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("ERROR_INVALID_SESSION sid=%u", session); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->LoadLicense(message, message_length, core_message_length, - signature, signature_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, - size_t num_keys, const OEMCrypto_KeyObject* key_array, - OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_LoadKeys: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("ERROR_KEYBOX_INVALID"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("ERROR_INVALID_SESSION sid=%u", session); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0 || key_array == nullptr || num_keys == 0) { - LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Range check - if (!RangeCheck(message_length, enc_mac_keys_iv, true) || - !RangeCheck(message_length, enc_mac_keys, true) || - !RangeCheck(message_length, pst, true) || - !RangeCheck(message_length, srm_restriction_data, true)) { - LOGE( - "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " - "range check.]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - for (size_t i = 0; i < num_keys; i++) { - if (!RangeCheck(message_length, key_array[i].key_id, false) || - !RangeCheck(message_length, key_array[i].key_data, false) || - !RangeCheck(message_length, key_array[i].key_data_iv, false) || - !RangeCheck(message_length, key_array[i].key_control, false) || - !RangeCheck(message_length, key_array[i].key_control_iv, false)) { - LOGE( - "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range " - "check %zu]", - i); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - } - if (enc_mac_keys.offset >= wvoec::KEY_IV_SIZE && enc_mac_keys.length > 0) { - if (enc_mac_keys_iv.offset + wvoec::KEY_IV_SIZE == enc_mac_keys.offset) { - LOGE( - "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " - "range check iv]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } else { - if (CRYPTO_memcmp(message + enc_mac_keys.offset - wvoec::KEY_IV_SIZE, - message + enc_mac_keys_iv.offset, - wvoec::KEY_IV_SIZE) == 0) { - LOGE( - "[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " - "suspicious iv]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - } - } - return session_ctx->LoadKeys(message, message_length, signature, - signature_length, enc_mac_keys_iv, enc_mac_keys, - num_keys, key_array, pst, srm_restriction_data, - license_type); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadEntitledContentKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array) { - if (key_array_length == 0) { - LOGE("[OEMCrypto_LoadEntitledContentKeys(): key_array is empty."); - return OEMCrypto_SUCCESS; - } - if (key_array == nullptr) { - LOGE("[OEMCrypto_LoadEntitledContentKeys(): missing key_array."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_LoadEntitledContentKeys: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_LoadEntitledContentKeys(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - for (size_t i = 0; i < key_array_length; i++) { - if (!RangeCheck(message_length, key_array[i].entitlement_key_id, false) || - !RangeCheck(message_length, key_array[i].content_key_id, false) || - !RangeCheck(message_length, key_array[i].content_key_data_iv, false) || - !RangeCheck(message_length, key_array[i].content_key_data, false)) { - LOGE( - "[OEMCrypto_LoadEntitledContentKeys(): " - "OEMCrypto_ERROR_INVALID_CONTEXT -range " - "check %zu]", - i); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - } - return session_ctx->LoadEntitledContentKeys(message, message_length, - key_array_length, key_array); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, - const uint8_t* message, - size_t message_length, - size_t core_message_length, - const uint8_t* signature, - size_t signature_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("ERROR_KEYBOX_INVALID"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return session_ctx->LoadRenewal(message, message_length, core_message_length, - signature, signature_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_RefreshKeys( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, size_t num_keys, - const OEMCrypto_KeyRefreshObject* key_array) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("ERROR_KEYBOX_INVALID"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0 || num_keys == 0) { - LOGE("ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // We only use the first key object to update the entire license. Since we - // know num_keys > 0 after the last if statement, we can assume index is not - // out of bounds. - constexpr size_t kIndex = 0; - - // Range check. - if (!RangeCheck(message_length, key_array[kIndex].key_id, true) || - !RangeCheck(message_length, key_array[kIndex].key_control, false) || - !RangeCheck(message_length, key_array[kIndex].key_control_iv, true)) { - LOGE("Range Check %zu", kIndex); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Validate message signature - if (!session_ctx->ValidateMessage(message, message_length, signature, - signature_length)) { - LOGE("Signature was invalid"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Decrypt and refresh keys in key refresh object - OEMCryptoResult status = OEMCrypto_SUCCESS; - std::vector key_id; - std::vector key_control; - std::vector key_control_iv; - if (key_array[kIndex].key_id.length != 0) { - key_id.assign(message + key_array[kIndex].key_id.offset, - message + key_array[kIndex].key_id.offset + - key_array[kIndex].key_id.length); - key_control.assign(message + key_array[kIndex].key_control.offset, - message + key_array[kIndex].key_control.offset + - wvoec::KEY_CONTROL_SIZE); - if (key_array[kIndex].key_control_iv.length == 0) { - key_control_iv.clear(); - } else { - key_control_iv.assign(message + key_array[kIndex].key_control_iv.offset, - message + key_array[kIndex].key_control_iv.offset + - wvoec::KEY_IV_SIZE); - } - } else { - // key_id could be null if special control key type - // key_control is not encrypted in this case - key_id.clear(); - key_control_iv.clear(); - key_control.assign(message + key_array[kIndex].key_control.offset, - message + key_array[kIndex].key_control.offset + - wvoec::KEY_CONTROL_SIZE); - } - - status = session_ctx->RefreshKey(key_id, key_control, key_control_iv); - if (status != OEMCrypto_SUCCESS) { - return status; - } - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl( - OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length, - uint8_t* key_control_block, size_t* key_control_block_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_QueryKeyControl: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - uint32_t* block = reinterpret_cast(key_control_block); - if ((key_control_block_length == nullptr) || - (*key_control_block_length < wvoec::KEY_CONTROL_SIZE)) { - LOGE("[OEMCrypto_QueryKeyControl(): OEMCrypto_ERROR_SHORT_BUFFER]"); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *key_control_block_length = wvoec::KEY_CONTROL_SIZE; - if (key_id == nullptr) { - LOGE( - "[OEMCrypto_QueryKeyControl(): key_id null. " - "OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_QueryKeyControl(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - const std::vector key_id_str = - std::vector(key_id, key_id + key_id_length); - if (!session_ctx->QueryKeyControlBlock(key_id_str, block)) { - LOGE("[OEMCrypto_QueryKeyControl(): FAIL]"); - return OEMCrypto_ERROR_NO_CONTENT_KEY; - } - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_SelectKey(const OEMCrypto_SESSION session, const uint8_t* key_id, - size_t key_id_length, OEMCryptoCipherMode cipher_mode) { -#ifndef NDEBUG - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_SelectKey(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } -#endif - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_SelectKey(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - - const std::vector key_id_str = - std::vector(key_id, key_id + key_id_length); - return session_ctx->SelectContentKey(key_id_str, cipher_mode); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( - OEMCrypto_SESSION session, const OEMCrypto_SampleDescription* samples, - size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_DecryptCENC: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (samples == nullptr || samples_length == 0) { - LOGE("[OEMCrypto_DecryptCENC(): No samples]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (pattern == nullptr) { - LOGE("[OEMCrypto_DecryptCENC(): No pattern]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_DecryptCENC(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - -#ifndef NDEBUG - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_DecryptCENC(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } -#endif - // The maximum subsample and sample sizes we use -- if 0, we just pick a - // very large size for a sanity check. - const size_t max_subsample_size = crypto_engine->max_subsample_size() > 0 - ? crypto_engine->max_subsample_size() - : 100 * 1024 * 1024; - const size_t max_sample_size = crypto_engine->max_subsample_size() > 0 - ? crypto_engine->max_subsample_size() - : 1000 * 1024 * 1024; - // Iterate through all the samples and validate them before doing any decrypt - for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { - const OEMCrypto_SampleDescription& sample = samples[sample_index]; - - if (sample.buffers.input_data == nullptr || - sample.buffers.input_data_length == 0) { - LOGE("[OEMCrypto_DecryptCENC(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (crypto_engine->max_sample_size() > 0 && - sample.buffers.input_data_length > crypto_engine->max_sample_size()) { - // For testing reasons only, pretend that this integration only supports - // the given buffer size. - LOGE("[OEMCrypto_DecryptCENC(): Sample too large]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - // Iterate through all the subsamples and sum their lengths - size_t subsample_length_tally = 0; - for (size_t subsample_index = 0; subsample_index < sample.subsamples_length; - ++subsample_index) { - const OEMCrypto_SubSampleDescription& subsample = - sample.subsamples[subsample_index]; - // Compute the length now, but we check for possible overflow in the next - // if statement. - const size_t length = - subsample.num_bytes_clear + subsample.num_bytes_encrypted; - if (subsample.num_bytes_clear > max_subsample_size || - subsample.num_bytes_encrypted > max_subsample_size || - length > max_subsample_size || - subsample_length_tally > max_sample_size) { - // For testing reasons only, pretend that this integration only supports - // the given buffer size. - LOGE("[OEMCrypto_DecryptCENC(): Subsample too large]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - subsample_length_tally += length; - } - if (subsample_length_tally != sample.buffers.input_data_length) { - LOGE( - "[OEMCrypto_DecryptCENC(): Sample and subsample lengths do not " - "match.]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - } - - return session_ctx->DecryptSamples(samples, samples_length, pattern); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer( - OEMCrypto_SESSION session, const uint8_t* data_addr, size_t data_length, - const OEMCrypto_DestBufferDesc* out_buffer_descriptor, - uint8_t subsample_flags) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_CopyBuffer: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (data_addr == nullptr || out_buffer_descriptor == nullptr) { - LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (crypto_engine->max_subsample_size() > 0 && - data_length > crypto_engine->max_subsample_size()) { - // For testing reasons only, pretend that this integration only supports - // the minimum possible buffer size. - LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_BUFFER_TOO_LARGE]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - OEMCryptoResult status = crypto_engine->SetDestination( - *out_buffer_descriptor, data_length, subsample_flags); - if (status != OEMCrypto_SUCCESS) return status; - if (crypto_engine->destination() != nullptr) { - memmove(crypto_engine->destination(), data_addr, data_length); - } - return crypto_engine->PushDestination(*out_buffer_descriptor, - subsample_flags); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert( - const uint8_t* keybox, size_t keyBoxLength, uint8_t* wrappedKeybox, - size_t* wrappedKeyBoxLength, const uint8_t* transportKey, - size_t transportKeyLength) { - if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (!keybox || !wrappedKeybox || !wrappedKeyBoxLength || - (keyBoxLength != *wrappedKeyBoxLength)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // This implementation ignores the transport key. For test keys, we - // don't need to encrypt the keybox. - memcpy(wrappedKeybox, keybox, keyBoxLength); - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* keybox, size_t keyBoxLength) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_InstallKeyboxOrOEMCert: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (crypto_engine->InstallKeybox(keybox, keyBoxLength)) { - return OEMCrypto_SUCCESS; - } - return OEMCrypto_ERROR_WRITE_KEYBOX; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, - size_t length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_LoadTestKeybox: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (crypto_engine->UseTestKeybox(buffer, length)) { - return OEMCrypto_SUCCESS; - } - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_IsKeyboxOrOEMCertValid: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - switch (crypto_engine->config_provisioning_method()) { - case OEMCrypto_DrmCertificate: - return OEMCrypto_SUCCESS; - case OEMCrypto_Keybox: - switch (crypto_engine->ValidateKeybox()) { - case NO_ERROR: - return OEMCrypto_SUCCESS; - case BAD_CRC: - return OEMCrypto_ERROR_BAD_CRC; - case BAD_MAGIC: - return OEMCrypto_ERROR_BAD_MAGIC; - default: - case OTHER_ERROR: - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - break; - case OEMCrypto_OEMCertificate: - // TODO(fredgc): verify that the certificate exists and is valid. - return OEMCrypto_SUCCESS; - break; - default: - LOGE("Invalid provisioning method: %d.", - crypto_engine->config_provisioning_method()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -} - -OEMCRYPTO_API OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized."); - return OEMCrypto_ProvisioningError; - } - return crypto_engine->config_provisioning_method(); -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_LoadOEMPrivateKey(OEMCrypto_SESSION session) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_OEMCertificate) { - LOGE("Unexpected provisioning method = %d.", - crypto_engine->config_provisioning_method()); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("OEMCrypto_ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return crypto_engine->load_oem_private_key(session_ctx); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( - uint8_t* public_cert, size_t* public_cert_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_OEMCertificate) { - LOGE("Unexpected provisioning method = %d.", - crypto_engine->config_provisioning_method()); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - return crypto_engine->get_oem_certificate(public_cert, public_cert_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, - size_t* idLength) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetDeviceID: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const std::vector& dev_id_string = crypto_engine->DeviceRootId(); - if (dev_id_string.empty()) { - LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - size_t dev_id_len = dev_id_string.size(); - if (*idLength < dev_id_len) { - *idLength = dev_id_len; - LOGE("[OEMCrypto_GetDeviceId(): ERROR_SHORT_BUFFER]"); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - memset(deviceID, 0, *idLength); - memcpy(deviceID, &dev_id_string[0], dev_id_len); - *idLength = dev_id_len; - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, - size_t* keyDataLength) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetKeyData: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - size_t length = crypto_engine->DeviceRootTokenLength(); - if (keyDataLength == nullptr) { - LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (*keyDataLength < length) { - *keyDataLength = length; - LOGE("[OEMCrypto_GetKeyData(): ERROR_SHORT_BUFFER]"); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (keyData == nullptr) { - LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - memset(keyData, 0, *keyDataLength); - memcpy(keyData, crypto_engine->DeviceRootToken(), length); - *keyDataLength = length; - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, - size_t dataLength) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetRandom: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!randomData) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (RAND_bytes(randomData, dataLength) == 1) { - return OEMCrypto_SUCCESS; - } - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -// This function is no longer exported -- it is only used by LoadProvisioning. -static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( - OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, - const uint8_t* encrypted_message_key, size_t encrypted_message_key_length, - const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, - size_t* wrapped_rsa_key_length) { - uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce); - if (unaligned_nonce == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_RewrapDeviceRSAKey30: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (wrapped_rsa_key_length == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (encrypted_message_key == nullptr || encrypted_message_key_length == 0 || - enc_rsa_key == nullptr || enc_rsa_key_iv == nullptr || - unaligned_nonce == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Validate nonce - if (!session_ctx->CheckNonce(nonce)) { - return OEMCrypto_ERROR_INVALID_NONCE; - } - - if (!session_ctx->InstallRSAEncryptedKey(encrypted_message_key, - encrypted_message_key_length)) { - LOGE( - "OEMCrypto_RewrapDeviceRSAKey30: " - "Error loading encrypted_message_key."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Decrypt RSA key. - std::vector pkcs8_rsa_key(enc_rsa_key_length); - if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, &pkcs8_rsa_key[0])) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - // Now we generate a wrapped keybox. - WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); - // Pick a random context and IV for generating keys. - if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) { - LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) { - LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const std::vector context( - wrapped->context, wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, - context)) { - LOGE("[_RewrapDeviceRSAKey30(): DeriveKeys failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Encrypt rsa key with keybox. - if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey); - // The wrapped keybox must be signed with the same key we verify with. I'll - // pick the server key, so I don't have to modify LoadRSAKey. - unsigned int sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - session_ctx->mac_key_server().size(), wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -// This function is no longer exported -- it is only used by LoadProvisioning. -static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - const uint32_t* unaligned_nonce, const uint8_t* enc_rsa_key, - size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, - uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) { - uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce); - if (unaligned_nonce == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_RewrapDeviceRSAKey: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (wrapped_rsa_key_length == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0 || unaligned_nonce == nullptr || - enc_rsa_key == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // verify signature. - if (!session_ctx->ValidateMessage(message, message_length, signature, - signature_length)) { - LOGE("[RewrapDeviceRSAKey(): Could not verify signature]"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Range check performed by ODK library. - - // Validate nonce - if (!session_ctx->CheckNonce(nonce)) { - return OEMCrypto_ERROR_INVALID_NONCE; - } - - // Decrypt RSA key and verify it. - std::vector pkcs8_rsa_key(enc_rsa_key_length); - if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, &pkcs8_rsa_key[0])) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - // Now we generate a wrapped keybox. - WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); - // Pick a random context and IV for generating keys. - if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const std::vector context( - wrapped->context, wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, - context)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Encrypt rsa key with keybox. - if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey); - // The wrapped keybox must be signed with the same key we verify with. I'll - // pick the server key, so I don't have to modify LoadRSAKey. - unsigned int sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - session_ctx->mac_key_server().size(), wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - size_t core_message_length, const uint8_t* signature, - size_t signature_length, uint8_t* wrapped_private_key, - size_t* wrapped_private_key_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (wrapped_private_key_length == nullptr || message == nullptr || - message_length == 0 || signature == nullptr || signature_length == 0) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("OEMCrypto_ERROR_KEYBOX_INVALID"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("OEMCrypto_ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - std::vector device_id = crypto_engine->DeviceRootId(); - ODK_ParsedProvisioning parsed_response; - const uint32_t nonce = session_ctx->nonce(); - const OEMCryptoResult result = - ODK_ParseProvisioning(message, message_length, core_message_length, - &(session_ctx->nonce_values()), device_id.data(), - device_id.size(), &parsed_response); - if (result != OEMCrypto_SUCCESS) { - LOGE("ODK Error %d", result); - return result; - } - - // For the reference implementation, the wrapped key and the encrypted - // key are the same size -- just encrypted with different keys. - // We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature. - // Important: This layout must match OEMCrypto_LoadDRMPrivateKey below. - const size_t buffer_size = - parsed_response.enc_private_key.length + sizeof(WrappedRSAKey); - - if (wrapped_private_key == nullptr || - *wrapped_private_key_length < buffer_size) { - *wrapped_private_key_length = buffer_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *wrapped_private_key_length = - buffer_size; // Tell caller how much space we used. - const uint8_t* message_body = message + core_message_length; - if (crypto_engine->config_provisioning_method() == OEMCrypto_Keybox) { - return OEMCrypto_RewrapDeviceRSAKey( - session, message, message_length, signature, signature_length, &nonce, - message_body + parsed_response.enc_private_key.offset, - parsed_response.enc_private_key.length, - message_body + parsed_response.enc_private_key_iv.offset, - wrapped_private_key, wrapped_private_key_length); - } else if (crypto_engine->config_provisioning_method() == - OEMCrypto_OEMCertificate) { - return OEMCrypto_RewrapDeviceRSAKey30( - session, &nonce, - message_body + parsed_response.encrypted_message_key.offset, - parsed_response.encrypted_message_key.length, - message_body + parsed_response.enc_private_key.offset, - parsed_response.enc_private_key.length, - message_body + parsed_response.enc_private_key_iv.offset, - wrapped_private_key, wrapped_private_key_length); - } else { - LOGE("Invalid provisioning method: %d.", - crypto_engine->config_provisioning_method()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey( - OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length) { - if (wrapped_rsa_key == nullptr) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT nullptr"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (key_type != OEMCrypto_RSA_Private_Key) { - LOGE("ECC keys not yet supported in reference code."); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (crypto_engine->config_provisioning_method() == OEMCrypto_DrmCertificate) { - // If we are using a baked in cert, the "wrapped RSA key" should actually be - // the magic value for baked-in certificates. - if (wrapped_rsa_key_length != sizeof(kBakedInCertificateMagicBytes) || - memcmp(kBakedInCertificateMagicBytes, wrapped_rsa_key, - wrapped_rsa_key_length) != 0) { - LOGE("Baked in Cert has wrong size."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } else { - return OEMCrypto_SUCCESS; - } - } - if (wrapped_rsa_key_length < sizeof(WrappedRSAKey)) { - LOGE("RSA Key has wrong size."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - const WrappedRSAKey* wrapped = - reinterpret_cast(wrapped_rsa_key); - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("ERROR_KEYBOX_INVALID"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("ERROR_INVALID_SESSION"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - const std::vector context( - wrapped->context, wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, - context)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // verify signature. - if (!session_ctx->ValidateMessage( - wrapped->context, wrapped_rsa_key_length - sizeof(wrapped->signature), - wrapped->signature, sizeof(wrapped->signature))) { - LOGE("Could not verify signature"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - // Decrypt RSA key. - std::vector pkcs8_rsa_key(wrapped_rsa_key_length - - sizeof(wrapped->signature)); - size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey); - if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length, - wrapped->iv, &pkcs8_rsa_key[0])) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if (padding > 16) { - // Do not return an error at this point, to avoid a padding oracle attack. - padding = 0; - } - size_t rsa_key_length = enc_rsa_key_length - padding; - if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_LoadTestRSAKey: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->LoadTestRsaKey()) return OEMCrypto_SUCCESS; - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - uint8_t* signature, size_t* signature_length, - RSA_Padding_Scheme padding_scheme) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GenerateRSASignature: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - if (signature_length == 0) { - LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_GenerateRSASignature(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - - size_t required_size = session_ctx->RSASignatureSize(); - if (*signature_length < required_size) { - *signature_length = required_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - OEMCryptoResult sts = session_ctx->GenerateRSASignature( - message, message_length, signature, signature_length, padding_scheme); - return sts; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( - OEMCrypto_SESSION session, const uint8_t* enc_session_key, - size_t enc_session_key_length, const uint8_t* mac_key_context, - size_t mac_key_context_length, const uint8_t* enc_key_context, - size_t enc_key_context_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_DeriveKeysFromSessionKey: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - if (mac_key_context_length > kMaxContextKeyLength || - enc_key_context_length > kMaxContextKeyLength || - enc_session_key_length > kMaxContextKeyLength) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - - if (session_ctx->allowed_schemes() != kSign_RSASSA_PSS) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): x509 key used to derive keys]"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - const std::vector ssn_key_str( - enc_session_key, enc_session_key + enc_session_key_length); - const std::vector mac_ctx_str( - mac_key_context, mac_key_context + mac_key_context_length); - const std::vector enc_ctx_str( - enc_key_context, enc_key_context + enc_key_context_length); - - // Generate mac and encryption keys for current session context - if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API uint32_t OEMCrypto_APIVersion() { - return CryptoEngine::kApiVersion; -} - -OEMCRYPTO_API uint32_t OEMCrypto_MinorAPIVersion() { - return CryptoEngine::kMinorApiVersion; -} - -OEMCRYPTO_API uint8_t OEMCrypto_Security_Patch_Level() { - uint8_t security_patch_level = crypto_engine->config_security_patch_level(); - return security_patch_level; -} - -OEMCRYPTO_API const char* OEMCrypto_SecurityLevel() { - const char* security_level = crypto_engine->config_security_level(); - return security_level; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHDCPCapability( - OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetHDCPCapability: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (current == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - if (maximum == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - *current = crypto_engine->config_current_hdcp_capability(); - *maximum = crypto_engine->config_maximum_hdcp_capability(); - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API uint32_t OEMCrypto_GetAnalogOutputFlags() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetAnalogOutputFlags: OEMCrypto Not Initialized."); - return 0; - } - return crypto_engine->analog_output_flags(); -} - -OEMCRYPTO_API const char* OEMCrypto_BuildInformation() { - return "OEMCrypto Ref Code " __DATE__ " " __TIME__; -} - -OEMCRYPTO_API uint32_t OEMCrypto_ResourceRatingTier() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_ResourceRatingTier: OEMCrypto Not Initialized."); - return 0; - } - return crypto_engine->resource_rating(); -} - -OEMCRYPTO_API bool OEMCrypto_SupportsUsageTable() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_SupportsUsageTable: OEMCrypto Not Initialized."); - return 0; - } - bool supports_usage = crypto_engine->config_supports_usage_table(); - return supports_usage; -} - -OEMCRYPTO_API size_t OEMCrypto_MaximumUsageTableHeaderSize() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_MaximumUsageTableHeaderSize: OEMCrypto Not Initialized."); - return 0; - } - return crypto_engine->max_usage_table_size(); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetNumberOfOpenSessions: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (count == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - *count = crypto_engine->GetNumberOfOpenSessions(); - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_GetMaxNumberOfSessions(size_t* maximum) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetMaxNumberOfSessions: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (maximum == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - *maximum = crypto_engine->GetMaxNumberOfSessions(); - return OEMCrypto_SUCCESS; -} - -OEMCRYPTO_API bool OEMCrypto_IsAntiRollbackHwPresent() { - bool anti_rollback_hw_present = - crypto_engine->config_is_anti_rollback_hw_present(); - - return anti_rollback_hw_present; -} - -OEMCRYPTO_API uint32_t OEMCrypto_SupportedCertificates() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized."); - return 0; - } - if (crypto_engine->config_provisioning_method() == OEMCrypto_DrmCertificate) { - return 0; - } - return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit | - OEMCrypto_Supports_RSA_CAST; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Encrypt( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_Generic_Encrypt: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (in_buffer == nullptr || buffer_length == 0 || iv == nullptr || - out_buffer == nullptr) { - LOGE("[OEMCrypto_Generic_Encrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (buffer_length > kMaxInputMessageBuferLength) { - LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_BUFFER_TOO_LARGE]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - - OEMCryptoResult sts = session_ctx->Generic_Encrypt(in_buffer, buffer_length, - iv, algorithm, out_buffer); - return sts; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Decrypt( - OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, - const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_Generic_Decrypt: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (in_buffer == nullptr || buffer_length == 0 || iv == nullptr || - out_buffer == nullptr) { - LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (buffer_length > kMaxInputMessageBuferLength) { - LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_BUFFER_TOO_LARGE]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - OEMCryptoResult sts = session_ctx->Generic_Decrypt(in_buffer, buffer_length, - iv, algorithm, out_buffer); - return sts; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, const uint8_t* in_buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - uint8_t* signature, size_t* signature_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_Generic_Sign: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (*signature_length < SHA256_DIGEST_LENGTH) { - *signature_length = SHA256_DIGEST_LENGTH; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (in_buffer == nullptr || buffer_length == 0 || signature == nullptr) { - LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (buffer_length > kMaxInputMessageBuferLength) { - LOGE("[OEMCrypto_Generic_Sign(): ERROR_BUFFER_TOO_LARGE]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - OEMCryptoResult sts = session_ctx->Generic_Sign( - in_buffer, buffer_length, algorithm, signature, signature_length); - return sts; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_Generic_Verify(OEMCrypto_SESSION session, const uint8_t* in_buffer, - size_t buffer_length, OEMCrypto_Algorithm algorithm, - const uint8_t* signature, size_t signature_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_Generic_Verify: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (signature_length != SHA256_DIGEST_LENGTH) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (in_buffer == nullptr || buffer_length == 0 || signature == nullptr || - signature_length > kMaxInputSignatureLength) { - LOGE("[OEMCrypto_Generic_Verify(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (buffer_length > kMaxInputMessageBuferLength) { - LOGE("[OEMCrypto_Generic_Verify(): ERROR_BUFFER_TOO_LARGE]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - return session_ctx->Generic_Verify(in_buffer, buffer_length, algorithm, - signature, signature_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeactivateUsageEntry( - OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_DeactivateUsageEntry: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_DeactivateUsageEntry(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - std::vector pstv(pst, pst + pst_length); - return session_ctx->DeactivateUsageEntry(pstv); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, - const uint8_t* pst, - size_t pst_length, - uint8_t* buffer, - size_t* buffer_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_ReportUsage: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (!buffer_length) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_ReportUsage(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - std::vector pstv(pst, pst + pst_length); - OEMCryptoResult sts = session_ctx->ReportUsage(pstv, buffer, buffer_length); - return sts; -} - -OEMCRYPTO_API bool OEMCrypto_IsSRMUpdateSupported() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_IsSRMUpdateSupported: OEMCrypto Not Initialized."); - return false; - } - bool result = crypto_engine->srm_update_supported(); - return result; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_GetCurrentSRMVersion(uint16_t* version) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetCurrentSRMVersion: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_local_display_only()) { - return OEMCrypto_LOCAL_DISPLAY_ONLY; - } - OEMCryptoResult result = crypto_engine->current_srm_version(version); - return result; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, - size_t buffer_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_LoadSRM: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return crypto_engine->load_srm(buffer, buffer_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_RemoveSRM() { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_RemoveSRM: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return crypto_engine->remove_srm(); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateUsageTableHeader( - uint8_t* header_buffer, size_t* header_buffer_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_CreateUsageTableHeader: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - LOGE("OEMCrypto_CreateUsageTableHeader: Configured without Usage Tables."); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - return crypto_engine->usage_table().CreateUsageTableHeader( - header_buffer, header_buffer_length); -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer, size_t buffer_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_LoadUsageTableHeader: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (!buffer) { - LOGE("OEMCrypto_LoadUsageTableHeader: buffer null."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - std::vector bufferv(buffer, buffer + buffer_length); - return crypto_engine->usage_table().LoadUsageTableHeader(bufferv); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_CreateNewUsageEntry( - OEMCrypto_SESSION session, uint32_t* usage_entry_number) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_CreateNewUsageEntry: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_CreateNewUsageEntry(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (!usage_entry_number) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - OEMCryptoResult sts = session_ctx->CreateNewUsageEntry(usage_entry_number); - return sts; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_LoadUsageEntry(OEMCrypto_SESSION session, uint32_t index, - const uint8_t* buffer, size_t buffer_size) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_LoadUsageEntry: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_LoadUsageEntry(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (!buffer) { - LOGE("[OEMCrypto_LoadUsageEntry(): buffer null]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - std::vector bufferv(buffer, buffer + buffer_size); - return session_ctx->LoadUsageEntry(index, bufferv); -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, uint8_t* header_buffer, - size_t* header_buffer_length, uint8_t* entry_buffer, - size_t* entry_buffer_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_UpdateUsageEntry: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (!header_buffer_length || !entry_buffer_length) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_UpdateUsageEntry(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->UpdateUsageEntry(header_buffer, header_buffer_length, - entry_buffer, entry_buffer_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader( - uint32_t new_table_size, uint8_t* header_buffer, - size_t* header_buffer_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_ShrinkUsageTableHeader: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - return crypto_engine->usage_table().ShrinkUsageTableHeader( - new_table_size, header_buffer, header_buffer_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_MoveEntry(OEMCrypto_SESSION session, - uint32_t new_index) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_MoveEntry: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!crypto_engine->config_supports_usage_table()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_MoveEntry(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->MoveEntry(new_index); -} - -OEMCRYPTO_API uint32_t OEMCrypto_SupportsDecryptHash() { - return OEMCrypto_CRC_Clear_Buffer; -} - -OEMCRYPTO_API OEMCryptoResult -OEMCrypto_SetDecryptHash(OEMCrypto_SESSION session, uint32_t frame_number, - const uint8_t* hash, size_t hash_length) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_SetDecryptHash: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_SetDecryptHash(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->SetDecryptHash(frame_number, hash, hash_length); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHashErrorCode( - OEMCrypto_SESSION session, uint32_t* failed_frame_number) { - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_GetHashErrorCode: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_GetHashErrorCode(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - return session_ctx->GetHashErrorCode(failed_frame_number); -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_AllocateSecureBuffer( - OEMCrypto_SESSION session, size_t buffer_size, - OEMCrypto_DestBufferDesc* output_descriptor, int* secure_fd) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -OEMCRYPTO_API OEMCryptoResult OEMCrypto_FreeSecureBuffer( - OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor, - int secure_fd) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.cpp b/oemcrypto/ref/src/oemcrypto_rsa_key_shared.cpp deleted file mode 100644 index 83cd52f..0000000 --- a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_rsa_key_shared.h" - -#include - -#include -#include -#include -#include -#include - -#include "log.h" - -namespace wvoec_ref { - -void dump_boringssl_error() { - int count = 0; - while (unsigned long err = ERR_get_error()) { - count++; - char buffer[120]; - ERR_error_string_n(err, buffer, sizeof(buffer)); - LOGE("BoringSSL Error %d -- %lu -- %s", count, err, buffer); - } - LOGE("Reported %d BoringSSL Errors", count); -} - -void RSA_shared_ptr::reset() { - if (rsa_key_ && key_owned_) { - RSA_free(rsa_key_); - } - key_owned_ = false; - rsa_key_ = nullptr; -} - -bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) { - assert(buffer != nullptr); - reset(); - uint8_t* pkcs8_rsa_key = const_cast(buffer); - BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length); - if (bio == nullptr) { - LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]"); - return false; - } - bool success = true; - PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr); - if (pkcs8_pki == nullptr) { - BIO_reset(bio); - pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr); - if (pkcs8_pki == nullptr) { - LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned nullptr]"); - dump_boringssl_error(); - success = false; - } - } - EVP_PKEY* evp = nullptr; - if (success) { - evp = EVP_PKCS82PKEY(pkcs8_pki); - if (evp == nullptr) { - LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned nullptr]"); - dump_boringssl_error(); - success = false; - } - } - if (success) { - rsa_key_ = EVP_PKEY_get1_RSA(evp); - if (rsa_key_ == nullptr) { - LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]"); - success = false; - } - key_owned_ = true; - } - if (evp != nullptr) { - EVP_PKEY_free(evp); - } - if (pkcs8_pki != nullptr) { - PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); - } - BIO_free(bio); - if (!success) { - return false; - } - switch (RSA_check_key(rsa_key_)) { - case 1: // valid. - return true; - case 0: // not valid. - LOGE("[LoadPkcs8RsaKey(): rsa key not valid]"); - dump_boringssl_error(); - return false; - default: // -1 == check failed. - LOGE("[LoadPkcs8RsaKey(): error checking rsa key]"); - dump_boringssl_error(); - return false; - } -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.h b/oemcrypto/ref/src/oemcrypto_rsa_key_shared.h deleted file mode 100644 index 5f832cd..0000000 --- a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef OEMCRYPTO_RSA_KEY_SHARED_H_ -#define OEMCRYPTO_RSA_KEY_SHARED_H_ - -#include - -#include - -namespace wvoec_ref { - -// Shared pointer with specialized destructor. This pointer is only shared -// from a CryptoEngine to a Session -- so we don't have to use full reference -// counting. -class RSA_shared_ptr { - public: - RSA_shared_ptr() : rsa_key_(nullptr), key_owned_(false) {} - ~RSA_shared_ptr() { reset(); }; - // Explicitly allow copy as share. - explicit RSA_shared_ptr(const RSA_shared_ptr& other) : - rsa_key_(other.rsa_key_), key_owned_(false) {} - RSA* get() { return rsa_key_; } - void reset(); - bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length); - - private: - void operator=(const RSA_shared_ptr); // disallow assign. - - RSA* rsa_key_; - bool key_owned_; -}; - -// Log errors from BoringSSL. -void dump_boringssl_error(); - -} // namespace wvoec_ref - -#endif // OEMCRYPTO_RSA_KEY_SHARED_H_ diff --git a/oemcrypto/ref/src/oemcrypto_session.cpp b/oemcrypto/ref/src/oemcrypto_session.cpp deleted file mode 100644 index 9a1ab8e..0000000 --- a/oemcrypto/ref/src/oemcrypto_session.cpp +++ /dev/null @@ -1,1881 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_session.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "advance_iv_ctr.h" -#include "disallow_copy_and_assign.h" -#include "keys.h" -#include "log.h" -#include "odk.h" -#include "oemcrypto_engine_ref.h" -#include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" -#include "oemcrypto_types.h" -#include "platform.h" -#include "string_conversions.h" -#include "wvcrc32.h" - -static const int kPssSaltLength = 20; - -namespace { - -// Increment counter for AES-CTR. The CENC spec specifies we increment only -// the low 64 bits of the IV counter, and leave the high 64 bits alone. -void ctr128_inc64(uint8_t* counter) { - uint32_t n = 16; - do { - if (++counter[--n] != 0) return; - } while (n > 8); -} - -void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { - switch (dest_buffer->type) { - case OEMCrypto_BufferType_Clear: - dest_buffer->buffer.clear.address += bytes; - dest_buffer->buffer.clear.address_length -= bytes; - break; - - case OEMCrypto_BufferType_Secure: - dest_buffer->buffer.secure.offset += bytes; - break; - - case OEMCrypto_BufferType_Direct: - // Nothing to do for this buffer type. - break; - } -} - -} // namespace - -namespace wvoec_ref { - -/***************************************/ - -class ContentKeysContext : public SessionContextKeys { - public: - explicit ContentKeysContext() {} - ~ContentKeysContext() override {} - size_t size() override { return session_keys_.size(); } - bool Insert(const KeyId& key_id, const Key& key_data) override; - Key* Find(const KeyId& key_id) override; - Key* FirstKey() override; - void Remove(const KeyId& key_id) override; - void UpdateDuration(const KeyControlBlock& control) override; - - OEMCrypto_LicenseType type() override { return OEMCrypto_ContentLicense; } - - bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id, - const std::vector& content_key) override; - EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) override; - - private: - SessionKeyTable session_keys_; - CORE_DISALLOW_COPY_AND_ASSIGN(ContentKeysContext); -}; - -bool ContentKeysContext::Insert(const KeyId& key_id, const Key& key_data) { - return session_keys_.Insert(key_id, key_data); -} - -Key* ContentKeysContext::Find(const KeyId& key_id) { - return session_keys_.Find(key_id); -} - -Key* ContentKeysContext::FirstKey() { return session_keys_.FirstKey(); } - -void ContentKeysContext::Remove(const KeyId& key_id) { - session_keys_.Remove(key_id); -} - -void ContentKeysContext::UpdateDuration(const KeyControlBlock& control) { - session_keys_.UpdateDuration(control); -} - -bool ContentKeysContext::SetContentKey( - const KeyId& entitlement_id, const KeyId& content_key_id, - const std::vector& content_key) { - // Unsupported action for this type. - return false; -} - -EntitlementKey* ContentKeysContext::GetEntitlementKey( - const KeyId& entitlement_id) { - // Unsupported action for this type. - return nullptr; -} - -/***************************************/ - -class EntitlementKeysContext : public SessionContextKeys { - public: - EntitlementKeysContext() {} - ~EntitlementKeysContext() override {} - size_t size() override { return session_keys_.size(); } - bool Insert(const KeyId& key_id, const Key& key_data) override; - Key* Find(const KeyId& key_id) override; - Key* FirstKey() override; - void Remove(const KeyId& key_id) override; - void UpdateDuration(const KeyControlBlock& control) override; - bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id, - const std::vector& content_key) override; - EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) override; - - OEMCrypto_LicenseType type() override { return OEMCrypto_EntitlementLicense; } - - private: - EntitlementKeyTable session_keys_; - CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeysContext); -}; - -bool EntitlementKeysContext::Insert(const KeyId& key_id, const Key& key_data) { - return session_keys_.Insert(key_id, key_data); -} - -Key* EntitlementKeysContext::Find(const KeyId& key_id) { - return session_keys_.Find(key_id); -} - -Key* EntitlementKeysContext::FirstKey() { return session_keys_.FirstKey(); } - -void EntitlementKeysContext::Remove(const KeyId& key_id) { - session_keys_.Remove(key_id); -} - -void EntitlementKeysContext::UpdateDuration(const KeyControlBlock& control) { - session_keys_.UpdateDuration(control); -} - -bool EntitlementKeysContext::SetContentKey( - const KeyId& entitlement_id, const KeyId& content_key_id, - const std::vector& content_key) { - return session_keys_.SetContentKey(entitlement_id, content_key_id, - content_key); -} - -EntitlementKey* EntitlementKeysContext::GetEntitlementKey( - const KeyId& entitlement_id) { - return session_keys_.GetEntitlementKey(entitlement_id); -} - -/***************************************/ - -SessionContext::SessionContext(CryptoEngine* ce, SessionId sid, - const RSA_shared_ptr& rsa_key) - : valid_(true), - ce_(ce), - id_(sid), - current_content_key_(nullptr), - session_keys_(nullptr), - license_request_hash_(), - rsa_key_(rsa_key), - allowed_schemes_(kSign_RSASSA_PSS), - decrypt_started_(false), - timer_limits_(), - clock_values_(), - usage_entry_(nullptr), - srm_requirements_status_(NoSRMVersion), - usage_entry_status_(kNoUsageEntry), - compute_hash_(false), - current_hash_(0), - bad_frame_number_(0), - hash_error_(OEMCrypto_SUCCESS), - state_nonce_created_(false), - state_request_signed_(false), - state_response_loaded_(false) { - ODK_InitializeSessionValues(&timer_limits_, &clock_values_, &nonce_values_, - CryptoEngine::kApiVersion, sid); -} - -SessionContext::~SessionContext() {} - -// Internal utility function to derive key using CMAC-128 -bool SessionContext::DeriveKey(const std::vector& key, - const std::vector& context, int counter, - std::vector* out) { - if (key.empty() || counter > 4 || context.empty() || out == nullptr) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return false; - } - - const EVP_CIPHER* cipher = EVP_aes_128_cbc(); - CMAC_CTX* cmac_ctx = CMAC_CTX_new(); - - if (!cmac_ctx) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - return false; - } - - if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, 0)) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - CMAC_CTX_free(cmac_ctx); - return false; - } - - std::vector message; - message.push_back(counter); - message.insert(message.end(), context.begin(), context.end()); - - if (!CMAC_Update(cmac_ctx, &message[0], message.size())) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - CMAC_CTX_free(cmac_ctx); - return false; - } - - size_t reslen; - uint8_t res[128]; - if (!CMAC_Final(cmac_ctx, res, &reslen)) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - CMAC_CTX_free(cmac_ctx); - return false; - } - - out->assign(res, res + reslen); - - CMAC_CTX_free(cmac_ctx); - - return true; -} - -bool SessionContext::DeriveKeys(const std::vector& master_key, - const std::vector& mac_key_context, - const std::vector& enc_key_context) { - // Generate derived key for mac key - std::vector mac_key_server; - std::vector mac_key_client; - std::vector mac_key_part2; - if (!DeriveKey(master_key, mac_key_context, 1, &mac_key_server)) { - return false; - } - if (!DeriveKey(master_key, mac_key_context, 2, &mac_key_part2)) { - return false; - } - mac_key_server.insert(mac_key_server.end(), mac_key_part2.begin(), - mac_key_part2.end()); - - if (!DeriveKey(master_key, mac_key_context, 3, &mac_key_client)) { - return false; - } - if (!DeriveKey(master_key, mac_key_context, 4, &mac_key_part2)) { - return false; - } - mac_key_client.insert(mac_key_client.end(), mac_key_part2.begin(), - mac_key_part2.end()); - - // Generate derived key for encryption key - std::vector enc_key; - if (!DeriveKey(master_key, enc_key_context, 1, &enc_key)) { - return false; - } - - set_mac_key_server(mac_key_server); - set_mac_key_client(mac_key_client); - set_encryption_key(enc_key); - return true; -} - -bool SessionContext::RSADeriveKeys( - const std::vector& enc_session_key, - const std::vector& mac_key_context, - const std::vector& enc_key_context) { - if (!rsa_key()) { - LOGE("[RSADeriveKeys(): no RSA key set]"); - return false; - } - const size_t actual_key_size = static_cast(RSA_size(rsa_key())); - if (enc_session_key.size() != actual_key_size) { - LOGE( - "[RSADeriveKeys(): encrypted session key wrong size: %zu, expected " - "%zu]", - enc_session_key.size(), actual_key_size); - dump_boringssl_error(); - return false; - } - session_key_.resize(RSA_size(rsa_key())); - const int decrypted_size = - RSA_private_decrypt(enc_session_key.size(), &enc_session_key[0], - &session_key_[0], rsa_key(), RSA_PKCS1_OAEP_PADDING); - if (-1 == decrypted_size) { - LOGE("[RSADeriveKeys(): error decrypting session key.]"); - dump_boringssl_error(); - return false; - } - session_key_.resize(decrypted_size); - if (decrypted_size != static_cast(wvoec::KEY_SIZE)) { - LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]", - decrypted_size); - dump_boringssl_error(); - session_key_.clear(); - return false; - } - return DeriveKeys(session_key_, mac_key_context, enc_key_context); -} - -OEMCryptoResult SessionContext::PrepAndSignLicenseRequest( - uint8_t* message, size_t message_length, size_t* core_message_length, - uint8_t* signature, size_t* signature_length) { - if (signature_length == nullptr || core_message_length == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const size_t required_signature_size = CertSignatureSize(); - OEMCryptoResult result = ODK_PrepareCoreLicenseRequest( - message, message_length, core_message_length, &nonce_values_); - if (*signature_length < required_signature_size || - result == OEMCrypto_ERROR_SHORT_BUFFER) { - *signature_length = required_signature_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (result != OEMCrypto_SUCCESS) { - LOGE("ODK error: %d", static_cast(result)); - return result; - } - if (message == nullptr || message_length < *core_message_length || - signature == nullptr) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (state_request_signed_) { - LOGE("Attempt to sign two license requests"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // For backwards compatibility, we only sign the message body, and we compute - // a SHA256 of the core message. - SHA256(message, *core_message_length, license_request_hash_); - const uint8_t* message_body = message + *core_message_length; - const size_t message_body_length = message_length - *core_message_length; - result = GenerateCertSignature(message_body, message_body_length, signature, - signature_length); - if (result == OEMCrypto_SUCCESS) { - state_request_signed_ = true; - result = ODK_InitializeClockValues(&clock_values_, ce_->SystemTime()); - } - return result; -} - -OEMCryptoResult SessionContext::PrepAndSignRenewalRequest( - uint8_t* message, size_t message_length, size_t* core_message_length, - uint8_t* signature, size_t* signature_length) { - if (signature_length == nullptr || core_message_length == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - // If we have signed a request, but have not loaded it, something is wrong. - // On the other hand, we can sign a license release using the mac keys from - // the usage table. So it is OK if we have never signed a license request. - if (state_request_signed_ && !state_response_loaded_) { - LOGE("Attempt to sign renewal before load"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const size_t required_signature_size = SHA256_DIGEST_LENGTH; - const uint64_t now = ce_->SystemTime(); - const OEMCryptoResult result = ODK_PrepareCoreRenewalRequest( - message, message_length, core_message_length, &nonce_values_, - &clock_values_, now); - if (*signature_length < required_signature_size || - result == OEMCrypto_ERROR_SHORT_BUFFER) { - *signature_length = required_signature_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (result != OEMCrypto_SUCCESS) { - LOGE("ODK error: %d", static_cast(result)); - return result; - } - if (message == nullptr || message_length < *core_message_length || - signature == nullptr) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - // If we are talking to an old license server, then we only sign the message - // body. - if (nonce_values_.api_major_version < 16) { - const uint8_t* message_body = message + *core_message_length; - const size_t message_body_length = message_length - *core_message_length; - return GenerateSignature(message_body, message_body_length, signature, - signature_length); - } else { - return GenerateSignature(message, message_length, signature, - signature_length); - } -} - -OEMCryptoResult SessionContext::PrepAndSignProvisioningRequest( - uint8_t* message, size_t message_length, size_t* core_message_length, - uint8_t* signature, size_t* signature_length) { - if (signature_length == nullptr || core_message_length == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (state_request_signed_) { - LOGE("Attempt to sign prov request after license request"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const size_t required_signature_size = ROTSignatureSize(); - if (required_signature_size == 0) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - const std::vector& device_id = ce_->DeviceRootId(); - OEMCryptoResult result = ODK_PrepareCoreProvisioningRequest( - message, message_length, core_message_length, &nonce_values_, - device_id.data(), device_id.size()); - if (*signature_length < required_signature_size || - result == OEMCrypto_ERROR_SHORT_BUFFER) { - *signature_length = required_signature_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (result != OEMCrypto_SUCCESS) { - LOGE("ODK error: %d", static_cast(result)); - return result; - } - if (message == nullptr || message_length == 0 || signature == nullptr) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (ce_->config_provisioning_method() == OEMCrypto_Keybox) { - result = - GenerateSignature(message, message_length, signature, signature_length); - } else if (ce_->config_provisioning_method() == OEMCrypto_OEMCertificate) { - result = GenerateCertSignature(message, message_length, signature, - signature_length); - } else { - LOGE("Bad prov method = %d", - static_cast(ce_->config_provisioning_method())); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (result == OEMCrypto_SUCCESS) state_request_signed_ = true; - return result; -} - -// Utility function to generate a message signature -OEMCryptoResult SessionContext::GenerateSignature(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length) { - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == nullptr) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (mac_key_client_.size() != wvoec::MAC_KEY_SIZE) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (*signature_length != SHA256_DIGEST_LENGTH) { - *signature_length = SHA256_DIGEST_LENGTH; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - unsigned int md_len = *signature_length; - if (HMAC(EVP_sha256(), &mac_key_client_[0], wvoec::MAC_KEY_SIZE, message, - message_length, signature, &md_len)) { - *signature_length = md_len; - return OEMCrypto_SUCCESS; - } - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -// This is ussd when the device is a cast receiver. -size_t SessionContext::RSASignatureSize() { - if (!rsa_key()) { - LOGE("no RSA key set"); - return 0; - } - return static_cast(RSA_size(rsa_key())); -} - -size_t SessionContext::CertSignatureSize() { - // TODO(b/67735947): Add ECC cert support. - if (!rsa_key()) { - LOGE("No private key set"); - return 0; - } - return static_cast(RSA_size(rsa_key())); -} - -size_t SessionContext::ROTSignatureSize() { - if (ce_->config_provisioning_method() == OEMCrypto_Keybox) - return SHA256_DIGEST_LENGTH; - if (ce_->config_provisioning_method() == OEMCrypto_OEMCertificate) - return CertSignatureSize(); - LOGE("Bad prov method = %d", - static_cast(ce_->config_provisioning_method())); - return 0; -} - -OEMCryptoResult SessionContext::GenerateCertSignature( - const uint8_t* message, size_t message_length, uint8_t* signature, - size_t* signature_length) { - // TODO(b/67735947): Add ECC cert support. - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!rsa_key()) { - LOGE("No RSA key set"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - if (*signature_length < static_cast(RSA_size(rsa_key()))) { - *signature_length = CertSignatureSize(); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (allowed_schemes_ != kSign_RSASSA_PSS) { - LOGE("Message signing not allowed"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - // Hash the message using SHA1. - uint8_t hash[SHA_DIGEST_LENGTH]; - if (!SHA1(message, message_length, hash)) { - LOGE("Error creating signature hash"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Add PSS padding. - std::vector padded_digest(*signature_length); - int status = RSA_padding_add_PKCS1_PSS_mgf1( - rsa_key(), &padded_digest[0], hash, EVP_sha1(), nullptr, kPssSaltLength); - if (status == -1) { - LOGE("Error padding hash"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Encrypt PSS padded digest. - status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature, - rsa_key(), RSA_NO_PADDING); - if (status == -1) { - LOGE("Error in private encrypt"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::GenerateRSASignature( - const uint8_t* message, size_t message_length, uint8_t* signature, - size_t* signature_length, RSA_Padding_Scheme padding_scheme) { - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!rsa_key()) { - LOGE("No RSA key set"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - if (*signature_length < static_cast(RSA_size(rsa_key()))) { - *signature_length = RSA_size(rsa_key()); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (((padding_scheme & allowed_schemes_) != padding_scheme) || - (padding_scheme != kSign_PKCS1_Block1)) { - LOGE("padding_scheme not allowed"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - // This is the maximum digest size possible for PKCS1 block type 1, - // as used for a CAST receiver. - const size_t max_digest_size = 83u; - if (message_length > max_digest_size) { - LOGE("RSA digest too large"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - // Pad the message with PKCS1 padding, and then encrypt. - const int status = RSA_private_encrypt(message_length, message, signature, - rsa_key(), RSA_PKCS1_PADDING); - if (status < 0) { - LOGE("Error in RSA private encrypt. status = %d", status); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - *signature_length = static_cast(RSA_size(rsa_key())); - return OEMCrypto_SUCCESS; -} - -// Validate message signature -bool SessionContext::ValidateMessage(const uint8_t* given_message, - size_t message_length, - const uint8_t* given_signature, - size_t signature_length) { - if (signature_length != SHA256_DIGEST_LENGTH) { - return false; - } - uint8_t computed_signature[SHA256_DIGEST_LENGTH]; - memset(computed_signature, 0, SHA256_DIGEST_LENGTH); - unsigned int md_len = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), mac_key_server_.data(), mac_key_server_.size(), - given_message, message_length, computed_signature, &md_len)) { - LOGE("ValidateMessage: Could not compute signature"); - return false; - } - if (CRYPTO_memcmp(given_signature, computed_signature, signature_length)) { - LOGE("Invalid signature given: %s", - wvcdm::HexEncode(given_signature, signature_length).c_str()); - LOGE("Invalid signature computed: %s", - wvcdm::HexEncode(computed_signature, signature_length).c_str()); - return false; - } - return true; -} - -OEMCryptoResult SessionContext::CheckStatusOnline(uint32_t nonce, - uint32_t control) { - if (!(control & wvoec::kControlNonceEnabled)) { - LOGE("LoadKeys: Server provided Nonce_Required but Nonce_Enabled = 0"); - // Server error. Continue, and assume nonce required. - } - if (!CheckNonce(nonce)) return OEMCrypto_ERROR_INVALID_NONCE; - switch (usage_entry_status_) { - case kNoUsageEntry: - LOGE("LoadKeys: Session did not create usage entry"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - case kUsageEntryLoaded: - LOGE("LoadKeys: Session reloaded existing entry"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - case kUsageEntryNew: - return OEMCrypto_SUCCESS; - default: // invalid status. - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -} - -OEMCryptoResult SessionContext::CheckStatusOffline(uint32_t nonce, - uint32_t control) { - if (control & wvoec::kControlNonceEnabled) { - LOGE("KCB: Server provided NonceOrEntry but Nonce_Enabled = 1"); - // Server error. Continue, and assume nonce required. - } - switch (usage_entry_status_) { - case kNoUsageEntry: - LOGE("LoadKeys: Session did not create or load usage entry"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - case kUsageEntryLoaded: - // Repeat load. Calling function will verify pst and keys. - return OEMCrypto_SUCCESS; - case kUsageEntryNew: - // First load. Verify nonce. - if (!CheckNonce(nonce)) return OEMCrypto_ERROR_INVALID_NONCE; - return OEMCrypto_SUCCESS; - default: // invalid status. - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } -} - -OEMCryptoResult SessionContext::CheckNonceOrEntry( - const KeyControlBlock& key_control_block) { - switch (key_control_block.control_bits() & wvoec::kControlReplayMask) { - case wvoec::kControlNonceRequired: // Online license. Nonce always - // required. - return CheckStatusOnline(key_control_block.nonce(), - key_control_block.control_bits()); - break; - case wvoec::kControlNonceOrEntry: // Offline license. Nonce required on - // first use. - return CheckStatusOffline(key_control_block.nonce(), - key_control_block.control_bits()); - break; - default: - if ((key_control_block.control_bits() & wvoec::kControlNonceEnabled) && - (!CheckNonce(key_control_block.nonce()))) { - LOGE("LoadKeys: BAD Nonce"); - return OEMCrypto_ERROR_INVALID_NONCE; - } - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::LoadLicense(const uint8_t* message, - size_t message_length, - size_t core_message_length, - const uint8_t* signature, - size_t signature_length) { - // Check state before we check signature. State is change in - // LoadKeysNoSignature. - if (state_response_loaded_) { - return OEMCrypto_ERROR_LICENSE_RELOAD; - } - ODK_ParsedLicense parsed_response; - const bool initial_license_load = (usage_entry_status_ != kUsageEntryLoaded); - const OEMCryptoResult result = ODK_ParseLicense( - message, message_length, core_message_length, initial_license_load, - usage_entry_present(), license_request_hash_, &timer_limits_, - &clock_values_, &nonce_values_, &parsed_response); - if (result != OEMCrypto_SUCCESS) { - LOGE("ODK Error %d", static_cast(result)); - return result; - } - // Validate message signature - if (!ValidateMessage(message, message_length, signature, signature_length)) { - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - const uint8_t* message_body = message + core_message_length; - const size_t message_body_length = message_length - core_message_length; - return LoadKeysNoSignature( - message_body, message_body_length, parsed_response.enc_mac_keys_iv, - parsed_response.enc_mac_keys, parsed_response.key_array_length, - parsed_response.key_array, parsed_response.pst, - parsed_response.srm_restriction_data, - static_cast(parsed_response.license_type)); -} - -OEMCryptoResult SessionContext::LoadKeys( - const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, - OEMCrypto_Substring enc_mac_keys, size_t num_keys, - const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, - OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type) { - // Check state before we check signature. State is change in - // LoadKeysNoSignature. - if (state_response_loaded_) { - return OEMCrypto_ERROR_LICENSE_RELOAD; - } - // Validate message signature - if (!ValidateMessage(message, message_length, signature, signature_length)) { - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - OEMCryptoResult result = LoadKeysNoSignature( - message, message_length, enc_mac_keys_iv, enc_mac_keys, num_keys, - key_array, pst, srm_restriction_data, license_type); - if (result != OEMCrypto_SUCCESS) return result; - Key* key = session_keys_->FirstKey(); - uint32_t duration = key ? key->control().duration() : 0; - result = ODK_InitializeV15Values(&timer_limits_, &clock_values_, - &nonce_values_, duration, ce_->SystemTime()); - // TODO(b/140765227): clear session on errors - return result; -} - -OEMCryptoResult SessionContext::LoadKeysNoSignature( - const uint8_t* message, size_t message_length, - OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, - size_t num_keys, const OEMCrypto_KeyObject* key_array, - OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type) { - if (state_response_loaded_) { - return OEMCrypto_ERROR_LICENSE_RELOAD; - } - state_response_loaded_ = true; - if (num_keys < 1) return OEMCrypto_ERROR_INVALID_CONTEXT; - - if (session_keys_ == nullptr) { - switch (license_type) { - case OEMCrypto_ContentLicense: - session_keys_.reset(new ContentKeysContext()); - break; - - case OEMCrypto_EntitlementLicense: - session_keys_.reset(new EntitlementKeysContext()); - break; - - default: - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - } else { - if (session_keys_->type() != license_type) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - } - if (srm_restriction_data.length != 0) { - const std::string kSRMVerificationString = "HDCPDATA"; - if (memcmp(message + srm_restriction_data.offset, - kSRMVerificationString.c_str(), kSRMVerificationString.size())) { - LOGE("SRM Requirement Data has bad verification string: %8s", - message + srm_restriction_data.offset); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - const uint32_t minimum_version = htonl(*reinterpret_cast( - message + srm_restriction_data.offset + 8)); - uint16_t current_version = 0; - if (OEMCrypto_SUCCESS != ce_->current_srm_version(¤t_version)) { - LOGW("[LoadKeys: SRM Version not available"); - srm_requirements_status_ = InvalidSRMVersion; - } else if (current_version < minimum_version) { - LOGW("[LoadKeys: SRM Version is too small %u, required: %u", - current_version, minimum_version); - srm_requirements_status_ = InvalidSRMVersion; - } else if (ce_->srm_forbidden_device_attached()) { - LOGW("[LoadKeys: SRM forbidden device attached]"); - srm_requirements_status_ = InvalidSRMVersion; - } else { - LOGI("[LoadKeys: SRM Versions is %u, required: %u]", current_version, - minimum_version); - srm_requirements_status_ = ValidSRMVersion; - } - } - - // Decrypt and install keys in key object - // Each key will have a key control block. They will all have the same nonce. - OEMCryptoResult status = OEMCrypto_SUCCESS; - std::vector key_id; - std::vector enc_key_data; - std::vector key_data_iv; - std::vector key_control; - std::vector key_control_iv; - for (unsigned int i = 0; i < num_keys; i++) { - key_id.assign( - message + key_array[i].key_id.offset, - message + key_array[i].key_id.offset + key_array[i].key_id.length); - enc_key_data.assign( - message + key_array[i].key_data.offset, - message + key_array[i].key_data.offset + key_array[i].key_data.length); - key_data_iv.assign( - message + key_array[i].key_data_iv.offset, - message + key_array[i].key_data_iv.offset + wvoec::KEY_IV_SIZE); - if (key_array[i].key_control.length == 0) { - status = OEMCrypto_ERROR_UNKNOWN_FAILURE; - break; - } - key_control.assign( - message + key_array[i].key_control.offset, - message + key_array[i].key_control.offset + wvoec::KEY_CONTROL_SIZE); - key_control_iv.assign( - message + key_array[i].key_control_iv.offset, - message + key_array[i].key_control_iv.offset + wvoec::KEY_IV_SIZE); - - OEMCryptoResult result = InstallKey(key_id, enc_key_data, key_data_iv, - key_control, key_control_iv); - if (result != OEMCrypto_SUCCESS) { - status = result; - break; - } - } - if (status != OEMCrypto_SUCCESS) return status; - - // enc_mac_key can be nullptr if license renewal is not supported - if (enc_mac_keys.length != 0) { - // V2.1 license protocol: update mac keys after processing license response - const std::vector enc_mac_keys_str = std::vector( - message + enc_mac_keys.offset, - message + enc_mac_keys.offset + 2 * wvoec::MAC_KEY_SIZE); - const std::vector enc_mac_key_iv_str = std::vector( - message + enc_mac_keys_iv.offset, - message + enc_mac_keys_iv.offset + wvoec::KEY_IV_SIZE); - - if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) { - LOGE("Failed to update mac keys."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } else { - // If the mac keys are not updated, we will not need them again. - mac_key_server_.resize(0); - mac_key_client_.resize(0); - } - - if (usage_entry_) { - OEMCryptoResult result = OEMCrypto_SUCCESS; - switch (usage_entry_status_) { - case kNoUsageEntry: - if (pst.length > 0) { - LOGE("LoadKeys: PST specified but no usage entry loaded"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - break; // no extra check. - case kUsageEntryNew: - result = usage_entry_->SetPST(message + pst.offset, pst.length); - if (result != OEMCrypto_SUCCESS) { - return result; - } - if (!usage_entry_->SetMacKeys(mac_key_server_, mac_key_client_)) { - LOGE("LoadKeys: Usage table can't set keys."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - break; - case kUsageEntryLoaded: - if (!usage_entry_->VerifyPST(message + pst.offset, pst.length)) { - return OEMCrypto_ERROR_WRONG_PST; - } - if (!usage_entry_->VerifyMacKeys(mac_key_server_, mac_key_client_)) { - LOGE("LoadKeys: Usage table entry mac keys do not match."); - return OEMCrypto_ERROR_WRONG_KEYS; - } - if (usage_entry_->Inactive()) return OEMCrypto_ERROR_LICENSE_INACTIVE; - break; - } - } - encryption_key_.clear(); - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::LoadEntitledContentKeys( - const uint8_t* message, size_t message_length, size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array) { - if (!key_array) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (session_keys_ == nullptr || - session_keys_->type() != OEMCrypto_EntitlementLicense) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - for (size_t i = 0; i < key_array_length; ++i) { - const OEMCrypto_EntitledContentKeyObject* key_data = &key_array[i]; - std::vector entitlement_key_id; - entitlement_key_id.assign(message + key_data->entitlement_key_id.offset, - message + key_data->entitlement_key_id.offset + - key_data->entitlement_key_id.length); - - EntitlementKey* entitlement_key = - session_keys_->GetEntitlementKey(entitlement_key_id); - if (entitlement_key == nullptr) { - return OEMCrypto_KEY_NOT_ENTITLED; - } - std::vector content_key; - std::vector iv; - std::vector encrypted_content_key; - std::vector content_key_id; - - iv.assign(message + key_data->content_key_data_iv.offset, - message + key_data->content_key_data_iv.offset + 16); - encrypted_content_key.assign(message + key_data->content_key_data.offset, - message + key_data->content_key_data.offset + - key_data->content_key_data.length); - content_key_id.assign(message + key_data->content_key_id.offset, - message + key_data->content_key_id.offset + - key_data->content_key_id.length); - if (!DecryptMessage(entitlement_key->entitlement_key(), iv, - encrypted_content_key, &content_key, - 256 /* key size */)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!session_keys_->SetContentKey(entitlement_key_id, content_key_id, - content_key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::InstallKey( - const KeyId& key_id, const std::vector& key_data, - const std::vector& key_data_iv, - const std::vector& key_control, - const std::vector& key_control_iv) { - // Decrypt encrypted key_data using derived encryption key and offered iv - std::vector content_key; - std::vector key_control_str; - - if (!DecryptMessage(encryption_key_, key_data_iv, key_data, &content_key, - 128 /* key size */)) { - LOGE("[Installkey(): Could not decrypt key data]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Key control must be supplied by license server - if (key_control.empty()) { - LOGE("[Installkey(): WARNING: No Key Control]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (key_control_iv.empty()) { - LOGE("[Installkey(): ERROR: No Key Control IV]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!DecryptMessage(content_key, key_control_iv, key_control, - &key_control_str, 128 /* key size */)) { - LOGE("[Installkey(): ERROR: Could not decrypt content key]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - KeyControlBlock key_control_block(key_control_str); - if (!key_control_block.valid()) { - LOGE("Error parsing key control"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if ((key_control_block.control_bits() & - wvoec::kControlRequireAntiRollbackHardware) && - !ce_->config_is_anti_rollback_hw_present()) { - LOGE("Anti-rollback hardware is required but hardware not present"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const uint8_t minimum_patch_level = (key_control_block.control_bits() & - wvoec::kControlSecurityPatchLevelMask) >> - wvoec::kControlSecurityPatchLevelShift; - if (minimum_patch_level > OEMCrypto_Security_Patch_Level()) { - LOGE("[InstallKey(): security_patch_level = %u, minimum_patch_level = %u]", - OEMCrypto_Security_Patch_Level(), minimum_patch_level); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - OEMCryptoResult result = CheckNonceOrEntry(key_control_block); - if (result != OEMCrypto_SUCCESS) { - LOGE("LoadKeys: Failed Nonce/PST check"); - return result; - } - if (key_control_block.control_bits() & wvoec::kControlSRMVersionRequired) { - if (srm_requirements_status_ == NoSRMVersion) { - LOGE("[LoadKeys: control bit says SRM version required]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (srm_requirements_status_ == InvalidSRMVersion) { - // If the SRM version is too small, treat this key as local display only. - key_control_block.RequireLocalDisplay(); - } - } - - Key key(content_key, key_control_block); - if (session_keys_ == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - session_keys_->Insert(key_id, key); - return OEMCrypto_SUCCESS; -} - -bool SessionContext::InstallRSAEncryptedKey( - const uint8_t* encrypted_message_key, size_t encrypted_message_key_length) { - encryption_key_.resize(RSA_size(rsa_key())); - const int decrypted_size = RSA_private_decrypt( - encrypted_message_key_length, encrypted_message_key, &encryption_key_[0], - rsa_key(), RSA_PKCS1_OAEP_PADDING); - if (-1 == decrypted_size) { - LOGE("[RSADeriveKeys(): error decrypting session key.]"); - dump_boringssl_error(); - return false; - } - encryption_key_.resize(decrypted_size); - if (decrypted_size != static_cast(wvoec::KEY_SIZE)) { - LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]", - decrypted_size); - dump_boringssl_error(); - encryption_key_.clear(); - return false; - } - return true; -} - -OEMCryptoResult SessionContext::LoadRenewal(const uint8_t* message, - size_t message_length, - size_t core_message_length, - const uint8_t* signature, - size_t signature_length) { - if (session_keys_ == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!ValidateMessage(message, message_length, signature, signature_length)) { - LOGE("Signature was invalid"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // The reference implementation does not use a hardware timer. - uint64_t* timer_value = nullptr; - const OEMCryptoResult result = ODK_ParseRenewal( - message, message_length, core_message_length, &nonce_values_, - ce_->SystemTime(), &timer_limits_, &clock_values_, timer_value); - if (result == ODK_SET_TIMER || result == ODK_DISABLE_TIMER) - return OEMCrypto_SUCCESS; - if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED; - // All other errors are returned to the caller. - return result; -} - -OEMCryptoResult SessionContext::RefreshKey( - const KeyId& key_id, const std::vector& key_control, - const std::vector& key_control_iv) { - if (session_keys_ == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (key_control.empty()) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - std::vector decrypted_key_control; - if (key_id.empty()) { - // Key control is not encrypted if key id is NULL - decrypted_key_control = key_control; - } else { - Key* content_key = session_keys_->Find(key_id); - if (nullptr == content_key) { - LOGE("Key ID not found."); - return OEMCrypto_ERROR_NO_CONTENT_KEY; - } - const std::vector content_key_value = content_key->value(); - // Decrypt encrypted key control block - if (key_control_iv.empty()) { - decrypted_key_control = key_control; - } else { - if (!DecryptMessage(content_key_value, key_control_iv, key_control, - &decrypted_key_control, 128 /* key size */)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - } - KeyControlBlock key_control_block(decrypted_key_control); - if (!key_control_block.valid()) { - LOGE("Parse key control error."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - uint32_t new_key_duration = key_control_block.duration(); - uint64_t* timer_value = nullptr; - const OEMCryptoResult result = - ODK_RefreshV15Values(&timer_limits_, &clock_values_, &nonce_values_, - ce_->SystemTime(), new_key_duration, timer_value); - if (result == ODK_SET_TIMER || result == ODK_DISABLE_TIMER) - return OEMCrypto_SUCCESS; - if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED; - return result; -} - -bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key, - size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, - uint8_t* pkcs8_rsa_key) { - if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) { - LOGE("[DecryptRSAKey(): bad buffer size]"); - return false; - } - // Decrypt rsa key with keybox. - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key); - AES_cbc_encrypt(enc_rsa_key, pkcs8_rsa_key, enc_rsa_key_length, &aes_key, - iv_buffer, AES_DECRYPT); - return true; -} - -bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key, - size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, - uint8_t* enc_rsa_key) { - if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) { - LOGE("[EncryptRSAKey(): bad buffer size]"); - return false; - } - // Encrypt rsa key with keybox. - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_encrypt_key(&encryption_key_[0], 128, &aes_key); - AES_cbc_encrypt(pkcs8_rsa_key, enc_rsa_key, enc_rsa_key_length, &aes_key, - iv_buffer, AES_ENCRYPT); - return true; -} - -bool SessionContext::LoadRSAKey(const uint8_t* pkcs8_rsa_key, - size_t rsa_key_length) { - rsa_key_.reset(); - if (rsa_key_length < 8) { - LOGE("[LoadRSAKey(): Very Short Buffer]"); - return false; - } - if ((memcmp(pkcs8_rsa_key, "SIGN", 4) == 0)) { - uint32_t schemes_n; - memcpy((uint8_t*)&schemes_n, pkcs8_rsa_key + 4, sizeof(uint32_t)); - allowed_schemes_ = htonl(schemes_n); - pkcs8_rsa_key += 8; - rsa_key_length -= 8; - } else { - allowed_schemes_ = kSign_RSASSA_PSS; - } - return rsa_key_.LoadPkcs8RsaKey(pkcs8_rsa_key, rsa_key_length); -} - -OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string, - uint32_t use_type, - OEMCryptoBufferType buffer_type) { - const KeyControlBlock& control = current_content_key()->control(); - if (use_type && (!(control.control_bits() & use_type))) { - LOGE("[%s(): control bit says not allowed", log_string.c_str()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (control.control_bits() & wvoec::kControlDataPathSecure) { - if (!ce_->config_closed_platform() && - buffer_type == OEMCrypto_BufferType_Clear) { - LOGE("[%s(): Secure key with insecure buffer]", log_string.c_str()); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - } - if (!ce_->config_local_display_only()) { - // Only look at HDCP restrictions if the display can be non-local. - if (control.control_bits() & wvoec::kControlHDCPRequired) { - uint8_t required_hdcp = - (control.control_bits() & wvoec::kControlHDCPVersionMask) >> - wvoec::kControlHDCPVersionShift; - if (ce_->srm_forbidden_device_attached()) { - required_hdcp = HDCP_NO_DIGITAL_OUTPUT; - } - // For reference implementation, we pretend we can handle the current - // HDCP version. - if (required_hdcp > ce_->config_current_hdcp_capability() || - ce_->config_current_hdcp_capability() == 0) { - return OEMCrypto_ERROR_INSUFFICIENT_HDCP; - } - } - } - // Return an error if analog displays should be disabled. - if ((control.control_bits() & wvoec::kControlDisableAnalogOutput) && - ce_->analog_display_active()) { - LOGE("[%s(): control bit says disable analog", log_string.c_str()); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - // Check if CGMS is required. - if (control.control_bits() & wvoec::kControlCGMSMask) { - if (ce_->analog_display_active() && !ce_->cgms_a_active()) { - LOGE("[%s(): control bit says CGMS required", log_string.c_str()); - return OEMCrypto_ERROR_ANALOG_OUTPUT; - } - } - if (!decrypt_started_) { - // The reference implementation does not have a hardware timer. - uint64_t* timer_expiration = nullptr; - const OEMCryptoResult result = ODK_AttemptFirstPlayback( - ce_->SystemTime(), &timer_limits_, &clock_values_, timer_expiration); - if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED; - if (usage_entry_ != nullptr) usage_entry_->ForbidReport(); - } else { - // Continued playback. - const OEMCryptoResult result = ODK_UpdateLastPlaybackTime( - ce_->SystemTime(), &timer_limits_, &clock_values_); - if (result == ODK_TIMER_EXPIRED) return OEMCrypto_ERROR_KEY_EXPIRED; - if (usage_entry_ != nullptr) usage_entry_->set_recent_decrypt(true); - } - decrypt_started_ = true; // First playback for session. - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer, - size_t buffer_length, - const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - // Check there is a content key - if (current_content_key() == nullptr) { - LOGE("[Generic_Encrypt(): OEMCrypto_ERROR_NO_CONTENT_KEY]"); - return OEMCrypto_ERROR_NO_CONTENT_KEY; - } - const std::vector& key = current_content_key()->value(); - // Set the AES key. - if (static_cast(key.size()) != AES_BLOCK_SIZE) { - LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size: %zu", key.size()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - OEMCryptoResult result = - CheckKeyUse("Generic_Encrypt", wvoec::kControlAllowEncrypt, - OEMCrypto_BufferType_Clear); - if (result != OEMCrypto_SUCCESS) return result; - if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { - LOGE("[Generic_Encrypt(): algorithm bad"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (buffer_length % AES_BLOCK_SIZE != 0) { - LOGE("[Generic_Encrypt(): buffers size bad"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const uint8_t* key_u8 = &key[0]; - AES_KEY aes_key; - if (AES_set_encrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) { - LOGE("[Generic_Encrypt(): FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, iv, wvoec::KEY_IV_SIZE); - AES_cbc_encrypt(in_buffer, out_buffer, buffer_length, &aes_key, iv_buffer, - AES_ENCRYPT); - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer, - size_t buffer_length, - const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - // Check there is a content key - if (current_content_key() == nullptr) { - LOGE("[Generic_Decrypt(): OEMCrypto_ERROR_NO_CONTENT_KEY]"); - return OEMCrypto_ERROR_NO_CONTENT_KEY; - } - const std::vector& key = current_content_key()->value(); - // Set the AES key. - if (static_cast(key.size()) != AES_BLOCK_SIZE) { - LOGE("[Generic_Decrypt(): CONTENT_KEY has wrong size"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - OEMCryptoResult result = - CheckKeyUse("Generic_Decrypt", wvoec::kControlAllowDecrypt, - OEMCrypto_BufferType_Clear); - if (result != OEMCrypto_SUCCESS) return result; - - if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { - LOGE("[Generic_Decrypt(): bad algorithm"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (buffer_length % AES_BLOCK_SIZE != 0) { - LOGE("[Generic_Decrypt(): bad buffer size"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const uint8_t* key_u8 = &key[0]; - AES_KEY aes_key; - if (AES_set_decrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) { - LOGE("[Generic_Decrypt(): FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, iv, wvoec::KEY_IV_SIZE); - AES_cbc_encrypt(in_buffer, out_buffer, buffer_length, &aes_key, iv_buffer, - AES_DECRYPT); - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer, - size_t buffer_length, - OEMCrypto_Algorithm algorithm, - uint8_t* signature, - size_t* signature_length) { - // Check there is a content key - if (current_content_key() == nullptr) { - LOGE("[Generic_Sign(): OEMCrypto_ERROR_NO_CONTENT_KEY]"); - return OEMCrypto_ERROR_NO_CONTENT_KEY; - } - if (*signature_length < SHA256_DIGEST_LENGTH) { - *signature_length = SHA256_DIGEST_LENGTH; - LOGE("[Generic_Sign(): bad signature length"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const std::vector& key = current_content_key()->value(); - if (static_cast(key.size()) != SHA256_DIGEST_LENGTH) { - LOGE("[Generic_Sign(): CONTENT_KEY has wrong size: %zu", key.size()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - OEMCryptoResult result = CheckKeyUse("Generic_Sign", wvoec::kControlAllowSign, - OEMCrypto_BufferType_Clear); - if (result != OEMCrypto_SUCCESS) return result; - if (algorithm != OEMCrypto_HMAC_SHA256) { - LOGE("[Generic_Sign(): bad algorithm"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - unsigned int md_len = *signature_length; - if (HMAC(EVP_sha256(), &key[0], key.size(), in_buffer, buffer_length, - signature, &md_len)) { - *signature_length = md_len; - return OEMCrypto_SUCCESS; - } - LOGE("[Generic_Sign(): hmac failed"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer, - size_t buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length) { - // Check there is a content key - if (current_content_key() == nullptr) { - LOGE("[Decrypt_Verify(): OEMCrypto_ERROR_NO_CONTENT_KEY]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (signature_length < SHA256_DIGEST_LENGTH) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const std::vector& key = current_content_key()->value(); - if (static_cast(key.size()) != SHA256_DIGEST_LENGTH) { - LOGE("[Generic_Verify(): CONTENT_KEY has wrong size: %zu", key.size()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - OEMCryptoResult result = CheckKeyUse( - "Generic_Verify", wvoec::kControlAllowVerify, OEMCrypto_BufferType_Clear); - if (result != OEMCrypto_SUCCESS) return result; - if (algorithm != OEMCrypto_HMAC_SHA256) { - LOGE("[Generic_Verify(): bad algorithm"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - unsigned int md_len = signature_length; - uint8_t computed_signature[SHA256_DIGEST_LENGTH]; - if (HMAC(EVP_sha256(), &key[0], key.size(), in_buffer, buffer_length, - computed_signature, &md_len)) { - if (0 == - CRYPTO_memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH)) { - return OEMCrypto_SUCCESS; - } else { - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - } - LOGE("[Generic_Verify(): HMAC failed"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; -} - -bool SessionContext::UpdateMacKeys(const std::vector& enc_mac_keys, - const std::vector& iv) { - // Decrypt mac key from enc_mac_key using device_keya - std::vector mac_keys; - if (!DecryptMessage(encryption_key_, iv, enc_mac_keys, &mac_keys, - 128 /* key size */)) { - return false; - } - mac_key_server_ = std::vector( - mac_keys.begin(), mac_keys.begin() + wvoec::MAC_KEY_SIZE); - mac_key_client_ = std::vector(mac_keys.begin() + wvoec::MAC_KEY_SIZE, - mac_keys.end()); - return true; -} - -bool SessionContext::QueryKeyControlBlock(const KeyId& key_id, uint32_t* data) { - if (session_keys_ == nullptr) { - return false; - } - const Key* content_key = session_keys_->Find(key_id); - if (content_key == nullptr) { - LOGE("[QueryKeyControlBlock(): No key matches key id]"); - return false; - } - data[0] = 0; // verification optional. - data[1] = htonl(content_key->control().duration()); - data[2] = 0; // nonce optional. - data[3] = htonl(content_key->control().control_bits()); - return true; -} - -OEMCryptoResult SessionContext::SelectContentKey( - const KeyId& key_id, OEMCryptoCipherMode cipher_mode) { - if (session_keys_ == nullptr) { - LOGE("Select Key: no session keys"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - Key* content_key = session_keys_->Find(key_id); - if (content_key == nullptr) { - LOGE("No key matches key id"); - return OEMCrypto_ERROR_NO_CONTENT_KEY; - } - content_key->set_ctr_mode(cipher_mode == OEMCrypto_CipherMode_CTR); - current_content_key_ = content_key; - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::CreateNewUsageEntry( - uint32_t* usage_entry_number) { - if (usage_entry_) { - // Can only load one entry per session. - return OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES; - } - OEMCryptoResult result = ce_->usage_table().CreateNewUsageEntry( - this, &usage_entry_, usage_entry_number); - if (usage_entry_) { - usage_entry_status_ = kUsageEntryNew; - } - return result; -} - -OEMCryptoResult SessionContext::LoadUsageEntry( - uint32_t index, const std::vector& buffer) { - if (usage_entry_) { - // Can only load one entry per session. - return OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES; - } - const OEMCryptoResult result = ce_->usage_table().LoadUsageEntry( - this, &usage_entry_, index, buffer, &clock_values_); - if ((result != OEMCrypto_SUCCESS) && - (result != OEMCrypto_WARNING_GENERATION_SKEW)) - return result; - if (!usage_entry_) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - - usage_entry_status_ = kUsageEntryLoaded; - // Copy the mac keys to the current session. - mac_key_server_ = std::vector( - usage_entry_->mac_key_server(), - usage_entry_->mac_key_server() + wvoec::MAC_KEY_SIZE); - mac_key_client_ = std::vector( - usage_entry_->mac_key_client(), - usage_entry_->mac_key_client() + wvoec::MAC_KEY_SIZE); - return result; -} - -OEMCryptoResult SessionContext::UpdateUsageEntry(uint8_t* header_buffer, - size_t* header_buffer_length, - uint8_t* entry_buffer, - size_t* entry_buffer_length) { - if (!usage_entry_) { - LOGE("UpdateUsageEntry: Session has no entry"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return ce_->usage_table().UpdateUsageEntry( - this, usage_entry_.get(), header_buffer, header_buffer_length, - entry_buffer, entry_buffer_length, &clock_values_); -} - -OEMCryptoResult SessionContext::DeactivateUsageEntry( - const std::vector& pst) { - if (!usage_entry_) return OEMCrypto_ERROR_INVALID_CONTEXT; - usage_entry_->ForbidReport(); - return ODK_DeactivateUsageEntry(&clock_values_); -} - -OEMCryptoResult SessionContext::ReportUsage(const std::vector& pst, - uint8_t* buffer, - size_t* buffer_length) { - if (!usage_entry_) return OEMCrypto_ERROR_INVALID_CONTEXT; - return usage_entry_->ReportUsage(pst, buffer, buffer_length); -} - -OEMCryptoResult SessionContext::MoveEntry(uint32_t new_index) { - if (!usage_entry_) return OEMCrypto_ERROR_INVALID_CONTEXT; - return ce_->usage_table().MoveEntry(usage_entry_.get(), new_index); -} - -// Internal utility function to decrypt the message -bool SessionContext::DecryptMessage(const std::vector& key, - const std::vector& iv, - const std::vector& message, - std::vector* decrypted, - uint32_t key_size) { - if (key.empty() || iv.empty() || message.empty() || !decrypted) { - LOGE("[DecryptMessage(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return false; - } - if (message.size() % AES_BLOCK_SIZE != 0) { - LOGE("[DecryptMessage(): bad buffer size]"); - return false; - } - - decrypted->resize(message.size()); - uint8_t iv_buffer[16]; - memcpy(iv_buffer, &iv[0], 16); - AES_KEY aes_key; - AES_set_decrypt_key(&key[0], key_size, &aes_key); - AES_cbc_encrypt(&message[0], &(decrypted->front()), message.size(), &aes_key, - iv_buffer, AES_DECRYPT); - return true; -} - -OEMCryptoResult SessionContext::DecryptSamples( - const OEMCrypto_SampleDescription* samples, size_t samples_length, - const OEMCrypto_CENCEncryptPatternDesc* pattern) { - // Iterate through all the samples and decrypt each one - for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { - const OEMCrypto_SampleDescription& sample = samples[sample_index]; - - // Iterate through all the subsamples and decrypt each one. A production - // implementation may be able to do something more efficient, like - // decrypting all the encrypted portions in one pass. - const uint8_t* subsample_source = sample.buffers.input_data; - OEMCrypto_DestBufferDesc subsample_dest = sample.buffers.output_descriptor; - uint8_t subsample_iv[wvoec::KEY_IV_SIZE]; - static_assert(sizeof(sample.iv) == wvoec::KEY_IV_SIZE, - "The IV in OEMCrypto_SampleDescription is the wrong length."); - // Per its type, sizeof(subsample_iv) == wvoec::KEY_IV_SIZE - memcpy(subsample_iv, sample.iv, wvoec::KEY_IV_SIZE); - for (size_t subsample_index = 0; subsample_index < sample.subsamples_length; - ++subsample_index) { - const OEMCrypto_SubSampleDescription& subsample = - sample.subsamples[subsample_index]; - const size_t subsample_length = - subsample.num_bytes_clear + subsample.num_bytes_encrypted; - - OEMCryptoResult result = ce_->SetDestination( - subsample_dest, subsample_length, subsample.subsample_flags); - if (result != OEMCrypto_SUCCESS) { - LOGE("SetDestination status: %d", static_cast(result)); - return result; - } - - result = DecryptSubsample(subsample, subsample_source, ce_->destination(), - subsample_dest.type, subsample_iv, pattern); - if (result != OEMCrypto_SUCCESS) { - LOGE("DecryptSubsample status: %d", static_cast(result)); - return result; - } - - result = ce_->PushDestination(subsample_dest, subsample.subsample_flags); - if (result != OEMCrypto_SUCCESS) { - LOGE("PushDestination status: %d", static_cast(result)); - return result; - } - - // Advance the source buffer, the dest buffer, and (if necessary) the IV - subsample_source += subsample_length; - advance_dest_buffer(&subsample_dest, subsample_length); - if (subsample.num_bytes_encrypted > 0 && - current_content_key()->ctr_mode()) { - wvcdm::AdvanceIvCtr(&subsample_iv, subsample.block_offset + - subsample.num_bytes_encrypted); - } - } // Subsample loop - } // Sample loop - - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::DecryptSubsample( - const OEMCrypto_SubSampleDescription& subsample, const uint8_t* cipher_data, - uint8_t* clear_data, OEMCryptoBufferType buffer_type, - const uint8_t (&iv)[wvoec::KEY_IV_SIZE], - const OEMCrypto_CENCEncryptPatternDesc* pattern) { - // Handle the clear portion of the subsample. - if (subsample.num_bytes_clear > 0) { - if (buffer_type != OEMCrypto_BufferType_Direct) { - memmove(clear_data, cipher_data, subsample.num_bytes_clear); - } - // For the reference implementation, we quietly drop the clear direct video. - } - - // Handle the encrypted portion of the subsample. - OEMCryptoResult result = OEMCrypto_SUCCESS; - if (subsample.num_bytes_encrypted > 0) { - const uint8_t* source = cipher_data + subsample.num_bytes_clear; - uint8_t* dest = clear_data + subsample.num_bytes_clear; - result = ChooseDecrypt(iv, subsample.block_offset, pattern, source, - subsample.num_bytes_encrypted, dest, buffer_type); - } - - // Compute hash for FDPT. - if (compute_hash_) { - if (current_content_key() == nullptr || - (current_content_key()->control().control_bits() & - wvoec::kControlAllowHashVerification) == 0) { - LOGE("[DecryptCENC(): OEMCrypto_ERROR_UNKNOWN_FAILURE]"); - hash_error_ = OEMCrypto_ERROR_UNKNOWN_FAILURE; - compute_hash_ = false; - current_hash_ = 0; - current_frame_number_ = 0; - } else { - if (OEMCrypto_FirstSubsample & subsample.subsample_flags) { - current_hash_ = wvcrc32Init(); - } - current_hash_ = wvcrc32Cont( - clear_data, subsample.num_bytes_clear + subsample.num_bytes_encrypted, - current_hash_); - if (OEMCrypto_LastSubsample & subsample.subsample_flags) { - if (current_hash_ != given_hash_) { - LOGE("CRC for frame %u is %08x, should be %08x\n", - current_frame_number_, current_hash_, given_hash_); - // Update bad_frame_number_ only if this is the first bad frame. - if (hash_error_ == OEMCrypto_SUCCESS) { - bad_frame_number_ = current_frame_number_; - hash_error_ = OEMCrypto_ERROR_BAD_HASH; - } - } - compute_hash_ = false; - } - } - } - - // Return the result of the previous ChooseDecrypt() call after computing the - // hash. - return result; -} - -OEMCryptoResult SessionContext::ChooseDecrypt( - const uint8_t* iv, size_t block_offset, - const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, - size_t cipher_data_length, uint8_t* clear_data, - OEMCryptoBufferType buffer_type) { - // Check there is a content key - if (current_content_key() == nullptr) { - LOGE("[DecryptCTR(): OEMCrypto_ERROR_NO_CONTENT_KEY]"); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - - OEMCryptoResult result = CheckKeyUse("DecryptCENC", 0, buffer_type); - if (result != OEMCrypto_SUCCESS) return result; - - const std::vector& content_key = current_content_key()->value(); - - // Set the AES key. - if (static_cast(content_key.size()) != AES_BLOCK_SIZE) { - LOGE("[DecryptCTR(): CONTENT_KEY has wrong size: %zu", content_key.size()); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - const uint8_t* key_u8 = &content_key[0]; - - if (buffer_type == OEMCrypto_BufferType_Direct) { - // For reference implementation, we quietly drop the decrypted direct video. - return OEMCrypto_SUCCESS; - } - - if (!current_content_key()->ctr_mode()) { - if (block_offset > 0 || pattern->encrypt == 0) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return PatternDecryptCBC(key_u8, iv, pattern, cipher_data, - cipher_data_length, clear_data); - } else { - if (pattern->skip != 0 || pattern->encrypt != 0) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - return DecryptCTR(key_u8, iv, block_offset, cipher_data, cipher_data_length, - clear_data); - } -} - -OEMCryptoResult SessionContext::PatternDecryptCBC( - const uint8_t* key, const uint8_t* initial_iv, - const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, - size_t cipher_data_length, uint8_t* clear_data) { - AES_KEY aes_key; - AES_set_decrypt_key(&key[0], AES_BLOCK_SIZE * 8, &aes_key); - uint8_t iv[AES_BLOCK_SIZE]; - uint8_t next_iv[AES_BLOCK_SIZE]; - memcpy(iv, &initial_iv[0], AES_BLOCK_SIZE); - - const size_t pattern_length = pattern->encrypt + pattern->skip; - if (pattern_length <= 0) return OEMCrypto_ERROR_INVALID_CONTEXT; - - size_t l = 0; - size_t pattern_offset = 0; - while (l < cipher_data_length) { - const size_t size = - std::min(cipher_data_length - l, static_cast(AES_BLOCK_SIZE)); - const bool skip_block = (pattern_offset >= pattern->encrypt); - pattern_offset = (pattern_offset + 1) % pattern_length; - if (skip_block || (size < AES_BLOCK_SIZE)) { - // If we are decrypting in-place, then this block is already correct and - // can be skipped. - if (clear_data != cipher_data) { - memcpy(&clear_data[l], &cipher_data[l], size); - } - } else { - uint8_t aes_output[AES_BLOCK_SIZE]; - // Save the iv for the next block, in case cipher_data is in the same - // buffer as clear_data. - memcpy(next_iv, &cipher_data[l], AES_BLOCK_SIZE); - AES_decrypt(&cipher_data[l], aes_output, &aes_key); - for (size_t n = 0; n < AES_BLOCK_SIZE; n++) { - clear_data[l + n] = aes_output[n] ^ iv[n]; - } - memcpy(iv, next_iv, AES_BLOCK_SIZE); - } - l += size; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8, - const uint8_t* iv, - size_t block_offset, - const uint8_t* cipher_data, - size_t cipher_data_length, - uint8_t* clear_data) { - if (block_offset >= AES_BLOCK_SIZE) return OEMCrypto_ERROR_INVALID_CONTEXT; - - // Local copy (will be modified). - // Allocated as 64-bit ints to enforce 64-bit alignment for later access as a - // 64-bit value. - uint64_t aes_iv[2]; - assert(sizeof(aes_iv) == AES_BLOCK_SIZE); - // The double-cast is needed to comply with strict aliasing rules. - uint8_t* aes_iv_u8 = - reinterpret_cast(reinterpret_cast(aes_iv)); - memcpy(aes_iv_u8, &iv[0], AES_BLOCK_SIZE); - - // The CENC spec specifies we increment only the low 64 bits of the IV - // counter, and leave the high 64 bits alone. This is different from the - // OpenSSL implementation, which increments the entire 128 bit iv. That is - // why we implement the CTR loop ourselves. - size_t l = 0; - if (block_offset > 0 && l < cipher_data_length) { - // Encrypt the IV. - uint8_t ecount_buf[AES_BLOCK_SIZE]; - - AES_KEY aes_key; - if (AES_set_encrypt_key(key_u8, AES_BLOCK_SIZE * 8, &aes_key) != 0) { - LOGE("[DecryptCTR(): FAILURE]"); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - AES_encrypt(aes_iv_u8, ecount_buf, &aes_key); - for (int n = block_offset; n < AES_BLOCK_SIZE && l < cipher_data_length; - ++n, ++l) { - clear_data[l] = cipher_data[l] ^ ecount_buf[n]; - } - ctr128_inc64(aes_iv_u8); - block_offset = 0; - } - - uint64_t remaining = cipher_data_length - l; - int out_len = 0; - - while (remaining) { - EVP_CIPHER_CTX* evp_cipher_ctx = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_set_padding(evp_cipher_ctx, 0); - if (!EVP_DecryptInit_ex(evp_cipher_ctx, EVP_aes_128_ctr(), nullptr, key_u8, - aes_iv_u8)) { - LOGE("[DecryptCTR(): EVP_INIT ERROR]"); - EVP_CIPHER_CTX_free(evp_cipher_ctx); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - - // Test the MSB of the counter portion of the initialization vector. If the - // value is 0xFF the counter is near wrapping. In this case we calculate - // the number of bytes we can safely decrypt before the counter wraps. - uint64_t decrypt_length = 0; - if (aes_iv_u8[8] == 0xFF) { - uint64_t bottom_64_bits = wvcdm::ntohll64(aes_iv[1]); - uint64_t bytes_before_iv_wrap = (~bottom_64_bits + 1) * AES_BLOCK_SIZE; - decrypt_length = - bytes_before_iv_wrap < remaining ? bytes_before_iv_wrap : remaining; - } else { - decrypt_length = remaining; - } - - if (!EVP_DecryptUpdate(evp_cipher_ctx, &clear_data[l], &out_len, - &cipher_data[l], decrypt_length)) { - LOGE("[DecryptCTR(): EVP_UPDATE_ERROR]"); - EVP_CIPHER_CTX_free(evp_cipher_ctx); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - l += decrypt_length; - remaining = cipher_data_length - l; - - int final; - if (!EVP_DecryptFinal_ex(evp_cipher_ctx, - &clear_data[cipher_data_length - remaining], - &final)) { - LOGE("[DecryptCTR(): EVP_FINAL_ERROR]"); - EVP_CIPHER_CTX_free(evp_cipher_ctx); - return OEMCrypto_ERROR_DECRYPT_FAILED; - } - EVP_CIPHER_CTX_free(evp_cipher_ctx); - - // If remaining is not zero, reset the iv before the second pass. - if (remaining) { - memcpy(aes_iv_u8, &iv[0], AES_BLOCK_SIZE); - memset(&aes_iv_u8[8], 0, AES_BLOCK_SIZE / 2); - } - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::SetDecryptHash(uint32_t frame_number, - const uint8_t* hash, - size_t hash_length) { - if (hash_length < sizeof(uint32_t)) { - LOGE("[SetDecryptHash(): short buffer]"); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (hash_length > sizeof(uint32_t)) { - LOGE("[SetDecryptHash(): long buffer]"); - return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - } - compute_hash_ = true; - current_frame_number_ = frame_number; - given_hash_ = *reinterpret_cast(hash); - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult SessionContext::GetHashErrorCode( - uint32_t* failed_frame_number) { - if (failed_frame_number == nullptr) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - if (hash_error_ != OEMCrypto_SUCCESS) - *failed_frame_number = bad_frame_number_; - return hash_error_; -} - -bool SessionContext::set_nonce(uint32_t nonce) { - if (state_nonce_created_) return false; - if (nonce == 0) return false; - state_nonce_created_ = true; - ODK_SetNonceValues(&nonce_values_, nonce); - return true; -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_session.h b/oemcrypto/ref/src/oemcrypto_session.h deleted file mode 100644 index cd768b9..0000000 --- a/oemcrypto/ref/src/oemcrypto_session.h +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef REF_OEMCRYPTO_SESSION_H_ -#define REF_OEMCRYPTO_SESSION_H_ - -#include -#include -#include -#include - -#include - -#include "OEMCryptoCENC.h" -#include "odk_structs.h" -#include "oemcrypto_auth_ref.h" -#include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" -#include "oemcrypto_session_key_table.h" -#include "oemcrypto_types.h" -#include "oemcrypto_usage_table_ref.h" - -namespace wvoec_ref { - -class CryptoEngine; -typedef uint32_t SessionId; - -enum SRMVersionStatus { NoSRMVersion, ValidSRMVersion, InvalidSRMVersion }; - -// TODO(jfore): Is there a better name? -class SessionContextKeys { - public: - virtual OEMCrypto_LicenseType type() = 0; - virtual size_t size() = 0; - virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0; - virtual Key* Find(const KeyId& key_id) = 0; - virtual Key* FirstKey() = 0; - virtual void Remove(const KeyId& key_id) = 0; - virtual void UpdateDuration(const KeyControlBlock& control) = 0; - - // Methods supported exclusively for entitlement keys. Returns false if - // entitlement keys are not found or not supported by the current key table. - // It is the caller's responsibility to check the context. - virtual bool SetContentKey(const KeyId& entitlement_id, - const KeyId& content_key_id, - const std::vector& content_key) = 0; - virtual EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) = 0; - - virtual ~SessionContextKeys() {} - - protected: - SessionContextKeys() {} - - private: - CORE_DISALLOW_COPY_AND_ASSIGN(SessionContextKeys); -}; - -class SessionContext { - - public: - SessionContext(CryptoEngine* ce, SessionId sid, - const RSA_shared_ptr& rsa_key); - SessionContext() = delete; - virtual ~SessionContext(); - - bool isValid() { return valid_; } - - virtual bool DeriveKeys(const std::vector& master_key, - const std::vector& mac_context, - const std::vector& enc_context); - virtual bool RSADeriveKeys(const std::vector& enc_session_key, - const std::vector& mac_context, - const std::vector& enc_context); - virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message, - size_t message_length, - size_t* core_message_length, - uint8_t* signature, - size_t* signature_length); - virtual OEMCryptoResult PrepAndSignRenewalRequest(uint8_t* message, - size_t message_length, - size_t* core_message_length, - uint8_t* signature, - size_t* signature_length); - virtual OEMCryptoResult PrepAndSignProvisioningRequest( - uint8_t* message, size_t message_length, size_t* core_message_length, - uint8_t* signature, size_t* signature_length); - // The size of an RSA signature. This is used when signing as a CAST - // receiver. - size_t RSASignatureSize(); - virtual OEMCryptoResult GenerateRSASignature( - const uint8_t* message, size_t message_length, uint8_t* signature, - size_t* signature_length, RSA_Padding_Scheme padding_scheme); - virtual bool ValidateMessage(const uint8_t* message, size_t message_length, - const uint8_t* signature, - size_t signature_length); - OEMCryptoResult DecryptSamples( - const OEMCrypto_SampleDescription* samples, size_t samples_length, - const OEMCrypto_CENCEncryptPatternDesc* pattern); - - OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer); - OEMCryptoResult Generic_Decrypt(const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer); - OEMCryptoResult Generic_Sign(const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, - uint8_t* signature, size_t* signature_length); - OEMCryptoResult Generic_Verify(const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length); - virtual OEMCryptoResult LoadLicense(const uint8_t* message, - size_t message_length, - size_t core_message_length, - const uint8_t* signature, - size_t signature_length); - virtual OEMCryptoResult LoadKeys( - const uint8_t* message, size_t message_length, const uint8_t* signature, - size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv, - OEMCrypto_Substring enc_mac_keys, size_t num_keys, - const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst, - OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type); - virtual OEMCryptoResult LoadKeysNoSignature( - const uint8_t* message, size_t message_length, - OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, - size_t num_keys, const OEMCrypto_KeyObject* key_array, - OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, - OEMCrypto_LicenseType license_type); - virtual OEMCryptoResult LoadEntitledContentKeys( - const uint8_t* message, size_t message_length, size_t key_array_length, - const OEMCrypto_EntitledContentKeyObject* key_array); - virtual OEMCryptoResult InstallKey( - const KeyId& key_id, const std::vector& key_data, - const std::vector& key_data_iv, - const std::vector& key_control, - const std::vector& key_control_iv); - bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key, - size_t encrypted_message_key_length); - bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, - const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key); - bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key); - bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length); - virtual OEMCryptoResult LoadRenewal(const uint8_t* message, - size_t message_length, - size_t core_message_length, - const uint8_t* signature, - size_t signature_length); - virtual OEMCryptoResult RefreshKey( - const KeyId& key_id, const std::vector& key_control, - const std::vector& key_control_iv); - virtual bool UpdateMacKeys(const std::vector& mac_keys, - const std::vector& iv); - virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data); - virtual OEMCryptoResult SelectContentKey(const KeyId& key_id, - OEMCryptoCipherMode cipher_mode); - virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number, - const uint8_t* hash, - size_t hash_length); - virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number); - const Key* current_content_key(void) { return current_content_key_; } - void set_mac_key_server(const std::vector& mac_key_server) { - mac_key_server_ = mac_key_server; - } - const std::vector& mac_key_server() { return mac_key_server_; } - void set_mac_key_client(const std::vector& mac_key_client) { - mac_key_client_ = mac_key_client; - } - const std::vector& mac_key_client() { return mac_key_client_; } - - void set_encryption_key(const std::vector& enc_key) { - encryption_key_ = enc_key; - } - const std::vector& encryption_key() { return encryption_key_; } - uint32_t allowed_schemes() const { return allowed_schemes_; } - - // Return true if nonce was set. - bool set_nonce(uint32_t nonce); - uint32_t nonce() const { return nonce_values_.nonce; } - ODK_NonceValues& nonce_values() { return nonce_values_; } - - bool CheckNonce(uint32_t nonce) const { - return nonce != 0 && nonce == nonce_values_.nonce; - }; - - virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number); - virtual OEMCryptoResult LoadUsageEntry(uint32_t index, - const std::vector& buffer); - virtual OEMCryptoResult UpdateUsageEntry(uint8_t* header_buffer, - size_t* header_buffer_length, - uint8_t* entry_buffer, - size_t* entry_buffer_length); - virtual OEMCryptoResult DeactivateUsageEntry(const std::vector& pst); - virtual OEMCryptoResult ReportUsage(const std::vector& pst, - uint8_t* buffer, size_t* buffer_length); - OEMCryptoResult MoveEntry(uint32_t new_index); - bool usage_entry_present() const { return usage_entry_ != nullptr; } - - protected: - // Signature size of the currently loaded private key. - size_t CertSignatureSize(); - // Signature size when using a keybox or OEM Cert's private key. - size_t ROTSignatureSize(); - virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length); - virtual OEMCryptoResult GenerateSignature(const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length); - bool DeriveKey(const std::vector& key, - const std::vector& context, int counter, - std::vector* out); - bool DecryptMessage(const std::vector& key, - const std::vector& iv, - const std::vector& message, - std::vector* decrypted, - uint32_t key_size); // AES key size, in bits. - // Either verify the nonce or usage entry, as required by the key control - // block. - OEMCryptoResult CheckNonceOrEntry(const KeyControlBlock& key_control_block); - // If there is a usage entry, check that it is not inactive. - // It also updates the status of the entry if needed. - bool CheckUsageEntry(); - // Check that the usage entry status is valid for online use. - OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control); - // Check that the usage entry status is valid for offline use. - OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control); - - OEMCryptoResult DecryptSubsample( - const OEMCrypto_SubSampleDescription& subsample, - const uint8_t* cipher_data, uint8_t* clear_data, - OEMCryptoBufferType buffer_type, const uint8_t (&iv)[wvoec::KEY_IV_SIZE], - const OEMCrypto_CENCEncryptPatternDesc* pattern); - OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset, - const OEMCrypto_CENCEncryptPatternDesc* pattern, - const uint8_t* cipher_data, - size_t cipher_data_length, uint8_t* clear_data, - OEMCryptoBufferType buffer_type); - OEMCryptoResult PatternDecryptCBC( - const uint8_t* key, const uint8_t* iv, - const OEMCrypto_CENCEncryptPatternDesc* pattern, - const uint8_t* cipher_data, size_t cipher_data_length, - uint8_t* clear_data); - OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv, - size_t block_offset, const uint8_t* cipher_data, - size_t cipher_data_length, uint8_t* clear_data); - // Checks if the key is allowed for the specified type. If there is a usage - // entry, it also checks the usage entry. - OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type, - OEMCryptoBufferType buffer_type); - RSA* rsa_key() { return rsa_key_.get(); } - - bool valid_; - CryptoEngine* ce_; - SessionId id_; - std::vector mac_key_server_; - std::vector mac_key_client_; - std::vector encryption_key_; - std::vector session_key_; - const Key* current_content_key_; - std::unique_ptr session_keys_; - ODK_NonceValues nonce_values_; - uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE]; - RSA_shared_ptr rsa_key_; - uint32_t allowed_schemes_; // for RSA signatures. - bool decrypt_started_; // If the license has been used in this session. - ODK_TimerLimits timer_limits_; - ODK_ClockValues clock_values_; - std::unique_ptr usage_entry_; - SRMVersionStatus srm_requirements_status_; - enum UsageEntryStatus { - kNoUsageEntry, // No entry loaded for this session. - kUsageEntryNew, // After entry was created. - kUsageEntryLoaded, // After loading entry or loading keys. - }; - UsageEntryStatus usage_entry_status_; - - // These are used when doing full decrypt path testing. - bool compute_hash_; // True if the current frame needs a hash. - uint32_t current_hash_; // Running CRC hash of frame. - uint32_t given_hash_; // True CRC hash of frame. - uint32_t current_frame_number_; // Current frame for CRC hash. - uint32_t bad_frame_number_; // Frame number with bad hash. - OEMCryptoResult hash_error_; // Error code for first bad frame. - - // The bare minimum state machine is to only call each of these function - // categories at most once. - bool state_nonce_created_; - bool state_request_signed_; - bool state_response_loaded_; - - CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext); -}; - -} // namespace wvoec_ref - -#endif // REF_OEMCRYPTO_SESSION_H_ diff --git a/oemcrypto/ref/src/oemcrypto_session_key_table.cpp b/oemcrypto/ref/src/oemcrypto_session_key_table.cpp deleted file mode 100644 index 0247bec..0000000 --- a/oemcrypto/ref/src/oemcrypto_session_key_table.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_session_key_table.h" - -#include "keys.h" -#include "log.h" - -namespace wvoec_ref { - -bool SessionKeyTable::Insert(const KeyId key_id, const Key& key_data) { - if (keys_.find(key_id) != keys_.end()) return false; - keys_[key_id] = std::unique_ptr(new Key(key_data)); - return true; -} - -Key* SessionKeyTable::Find(const KeyId key_id) { - if (keys_.find(key_id) == keys_.end()) { - return nullptr; - } - return keys_[key_id].get(); -} - -void SessionKeyTable::Remove(const KeyId key_id) { - if (keys_.find(key_id) != keys_.end()) { - keys_.erase(key_id); - } -} - -void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) { - for (KeyMap::iterator it = keys_.begin(); it != keys_.end(); ++it) { - it->second->UpdateDuration(control); - } -} - -bool EntitlementKeyTable::Insert(const KeyId key_id, const Key& key_data) { - // |key_id| and |key_data| are for an entitlement key. Insert a new - // entitlement key entry. - if (keys_.find(key_id) != keys_.end()) return false; - keys_[key_id] = std::unique_ptr(new EntitlementKey(key_data)); - // If this is a new insertion, we don't have a content key assigned yet. - return true; -} - -Key* EntitlementKeyTable::Find(const KeyId key_id) { - // |key_id| refers to a content key. - ContentIdToEntitlementIdMap::iterator it = - contentid_to_entitlementid_.find(key_id); - if (it == contentid_to_entitlementid_.end()) { - return nullptr; - } - - if (keys_.find(it->second) == keys_.end()) { - return nullptr; - } - return keys_[it->second].get(); -} - -void EntitlementKeyTable::Remove(const KeyId key_id) { - // |key_id| refers to a content key. No one currently calls Remove so this - // method is free to change if needed. - ContentIdToEntitlementIdMap::iterator it = - contentid_to_entitlementid_.find(key_id); - if (it == contentid_to_entitlementid_.end()) { - return; - } - keys_.erase(it->second); - contentid_to_entitlementid_.erase(key_id); -} - -void EntitlementKeyTable::UpdateDuration(const KeyControlBlock& control) { - for (EntitlementKeyMap::iterator it = keys_.begin(); it != keys_.end(); - ++it) { - it->second->UpdateDuration(control); - } -} - -bool EntitlementKeyTable::SetContentKey( - const KeyId& entitlement_id, const KeyId& content_key_id, - const std::vector content_key) { - EntitlementKeyMap::iterator it = keys_.find(entitlement_id); - if (it == keys_.end()) { - return false; - } - contentid_to_entitlementid_.erase(it->second->content_key_id()); - if (!it->second->SetContentKey(content_key_id, content_key)) { - return false; - } - contentid_to_entitlementid_[content_key_id] = entitlement_id; - return true; -} - -EntitlementKey* EntitlementKeyTable::GetEntitlementKey( - const KeyId& entitlement_id) { - EntitlementKeyMap::iterator it = keys_.find(entitlement_id); - if (it == keys_.end()) { - return nullptr; - } - return it->second.get(); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_session_key_table.h b/oemcrypto/ref/src/oemcrypto_session_key_table.h deleted file mode 100644 index d534510..0000000 --- a/oemcrypto/ref/src/oemcrypto_session_key_table.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef REF_OEMCRYPTO_SESSION_KEY_TABLE_H_ -#define REF_OEMCRYPTO_SESSION_KEY_TABLE_H_ - -#include -#include -#include -#include - -#include "disallow_copy_and_assign.h" -#include "oemcrypto_key_ref.h" -#include "oemcrypto_types.h" - -namespace wvoec_ref { - -class SessionContext; -class CryptoEngine; -class UsageTable; -class UsageTableEntry; - -typedef std::vector KeyId; -typedef std::map> KeyMap; -typedef std::map> EntitlementKeyMap; - -// SessionKeyTable holds the keys for the current session -class SessionKeyTable { - public: - SessionKeyTable() {} - ~SessionKeyTable() {} - - bool Insert(const KeyId key_id, const Key& key_data); - Key* Find(const KeyId key_id); - Key* FirstKey() { return keys_.begin()->second.get(); } - void Remove(const KeyId key_id); - void UpdateDuration(const KeyControlBlock& control); - size_t size() const { return keys_.size(); } - - private: - KeyMap keys_; - - CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable); -}; - -class EntitlementKeyTable { - typedef std::map ContentIdToEntitlementIdMap; - - public: - EntitlementKeyTable() {} - ~EntitlementKeyTable() {} - bool Insert(const KeyId key_id, const Key& key_data); - Key* Find(const KeyId key_id); - Key* FirstKey() { return keys_.begin()->second.get(); } - void Remove(const KeyId key_id); - void UpdateDuration(const KeyControlBlock& control); - size_t size() const { return contentid_to_entitlementid_.size(); } - bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id, - const std::vector content_key); - EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id); - - private: - EntitlementKeyMap keys_; - ContentIdToEntitlementIdMap contentid_to_entitlementid_; - CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeyTable); -}; - -} // namespace wvoec_ref - -#endif // REF_OEMCRYPTO_SESSION_KEY_TABLE_H_ diff --git a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp b/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp deleted file mode 100644 index b3750c1..0000000 --- a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp +++ /dev/null @@ -1,710 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_usage_table_ref.h" - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "file_store.h" -#include "log.h" -#include "odk.h" -#include "oemcrypto_engine_ref.h" -// TODO(fredgc): Setting the device files base bath is currently broken as -// wvcdm::Properties is no longer used by the reference code. -//#include "properties.h" -#include "pst_report.h" -#include "string_conversions.h" - -namespace wvoec_ref { -namespace { -const size_t kMagicLength = 8; -const char* kEntryVerification = "USEENTRY"; -const char* kHeaderVerification = "USEHEADR"; -// Offset into a signed block where we start encrypting. We need to -// skip the signature and the iv. -const size_t kEncryptionOffset = SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH; - -// A structure that holds an usage entry and its signature. -struct SignedEntryBlock { - uint8_t signature[SHA256_DIGEST_LENGTH]; - uint8_t iv[SHA256_DIGEST_LENGTH]; - uint8_t verification[kMagicLength]; - StoredUsageEntry data; -}; - -// This has the data in the header of constant size. There is also an array -// of generation numbers. -struct SignedHeaderBlock { - uint8_t signature[SHA256_DIGEST_LENGTH]; - uint8_t iv[SHA256_DIGEST_LENGTH]; - uint8_t verification[kMagicLength]; - int64_t master_generation; - uint64_t count; -}; - -} // namespace - -UsageTableEntry::UsageTableEntry(UsageTable* table, uint32_t index, - int64_t generation) - : usage_table_(table), recent_decrypt_(false), forbid_report_(true) { - memset(&data_, 0, sizeof(data_)); - data_.generation_number = generation; - data_.index = index; -} - -UsageTableEntry::~UsageTableEntry() { usage_table_->ReleaseEntry(data_.index); } - -OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) { - if (pst_length > kMaxPSTLength) return OEMCrypto_ERROR_BUFFER_TOO_LARGE; - data_.pst_length = pst_length; - if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT; - memcpy(data_.pst, pst, pst_length); - data_.time_of_license_received = usage_table_->ce_->SystemTime(); - return OEMCrypto_SUCCESS; -} - -bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) { - if (pst_length > kMaxPSTLength) return false; - if (data_.pst_length != pst_length) return false; - if (!pst || !pst_length) return false; - return 0 == CRYPTO_memcmp(pst, data_.pst, pst_length); -} - -bool UsageTableEntry::VerifyMacKeys(const std::vector& server, - const std::vector& client) { - return (server.size() == wvoec::MAC_KEY_SIZE) && - (client.size() == wvoec::MAC_KEY_SIZE) && - (0 == CRYPTO_memcmp(&server[0], data_.mac_key_server, - wvoec::MAC_KEY_SIZE)) && - (0 == - CRYPTO_memcmp(&client[0], data_.mac_key_client, wvoec::MAC_KEY_SIZE)); -} - -bool UsageTableEntry::SetMacKeys(const std::vector& server, - const std::vector& client) { - if ((server.size() != wvoec::MAC_KEY_SIZE) || - (client.size() != wvoec::MAC_KEY_SIZE)) - return false; - memcpy(data_.mac_key_server, &server[0], wvoec::MAC_KEY_SIZE); - memcpy(data_.mac_key_client, &client[0], wvoec::MAC_KEY_SIZE); - return true; -} - -void UsageTableEntry::ForbidReport() { - forbid_report_ = true; - data_.generation_number++; - usage_table_->IncrementGeneration(); -} - -OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector& pst, - uint8_t* buffer, - size_t* buffer_length) { - if (forbid_report_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE; - if (recent_decrypt_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE; - if (pst.size() == 0 || pst.size() > kMaxPSTLength || - pst.size() != data_.pst_length) { - LOGE("ReportUsage: bad pst length = %zu, should be %u.", pst.size(), - data_.pst_length); - return OEMCrypto_ERROR_WRONG_PST; - } - if (CRYPTO_memcmp(&pst[0], data_.pst, data_.pst_length)) { - LOGE("ReportUsage: wrong pst %s, should be %s.", - wvcdm::b2a_hex(pst).c_str(), - wvcdm::HexEncode(data_.pst, data_.pst_length).c_str()); - return OEMCrypto_ERROR_WRONG_PST; - } - const size_t length_needed = - wvcdm::Unpacked_PST_Report::report_size(pst.size()); - if (*buffer_length < length_needed) { - *buffer_length = length_needed; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (!buffer) { - LOGE("ReportUsage: buffer was null pointer."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - wvcdm::Unpacked_PST_Report pst_report(buffer); - const int64_t now = usage_table_->ce_->SystemTime(); - pst_report.set_seconds_since_license_received(now - - data_.time_of_license_received); - pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt); - pst_report.set_seconds_since_last_decrypt(now - data_.time_of_last_decrypt); - pst_report.set_status(data_.status); - pst_report.set_clock_security_level(kSecureTimer); - pst_report.set_pst_length(data_.pst_length); - memcpy(pst_report.pst(), data_.pst, data_.pst_length); - unsigned int md_len = SHA_DIGEST_LENGTH; - if (!HMAC(EVP_sha1(), data_.mac_key_client, wvoec::MAC_KEY_SIZE, - buffer + SHA_DIGEST_LENGTH, length_needed - SHA_DIGEST_LENGTH, - pst_report.signature(), &md_len)) { - LOGE("ReportUsage: could not compute signature."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -void UsageTableEntry::UpdateAndIncrement(ODK_ClockValues* clock_values) { - if (recent_decrypt_) { - data_.time_of_last_decrypt = usage_table_->ce_->SystemTime(); - recent_decrypt_ = false; - } - data_.time_of_license_received = clock_values->time_of_license_signed; - data_.time_of_first_decrypt = clock_values->time_of_first_decrypt; - // Use the most recent time_of_last_decrypt. - if (static_cast(data_.time_of_last_decrypt) < - clock_values->time_of_last_decrypt) { - // For the reference implementation, we update the clock_values on every - // decrypt. - data_.time_of_last_decrypt = clock_values->time_of_last_decrypt; - } else { - // For this reference implementation of OEMCrypto, we regularly update - // clock_values->time_of_last_decrypt and we could just update - // data_.time_of_last_decrypt here. However, I'm including the line below to - // make it clear that you could do it the other way around. When this - // function is called, the two values should be synced so that the usage - // entry can be saved with the correct value. - clock_values->time_of_last_decrypt = data_.time_of_last_decrypt; - } - data_.status = clock_values->status; - data_.generation_number++; - usage_table_->IncrementGeneration(); - forbid_report_ = false; -} - -OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce, - SessionContext* session, - uint8_t* signed_buffer, - size_t buffer_size) { - // buffer_size was determined by calling function. - if (buffer_size != SignedEntrySize()) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - std::vector clear_buffer(buffer_size); - memset(&clear_buffer[0], 0, buffer_size); - memset(signed_buffer, 0, buffer_size); - SignedEntryBlock* clear = - reinterpret_cast(&clear_buffer[0]); - SignedEntryBlock* encrypted = - reinterpret_cast(signed_buffer); - clear->data = data_; // Copy the current data. - memcpy(clear->verification, kEntryVerification, kMagicLength); - - // This should be encrypted and signed with a device specific key. - // For the reference implementation, I'm just going to use the keybox key. - const std::vector& key = ce->DeviceRootKey(); - if (key.empty()) { - LOGE("SaveUsageEntry: DeviceRootKey is unexpectedly empty."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Encrypt the entry. - if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) { - LOGE("SaveUsageEntry: Could not generate iv."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer. - memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_encrypt_key(&key[0], 128, &aes_key); - AES_cbc_encrypt( - &clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset], - buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT); - - // Sign the entry. - unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), - &signed_buffer[SHA256_DIGEST_LENGTH], - buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature, - &sig_length)) { - LOGE("SaveUsageEntry: Could not sign entry."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index, - const std::vector& buffer, - ODK_ClockValues* clock_values) { - if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER; - if (buffer.size() > SignedEntrySize()) - LOGW("LoadUsageTableEntry: buffer is large. %zu > %zu", buffer.size(), - SignedEntrySize()); - std::vector clear_buffer(buffer.size()); - SignedEntryBlock* clear = - reinterpret_cast(&clear_buffer[0]); - const SignedEntryBlock* encrypted = - reinterpret_cast(&buffer[0]); - - // This should be encrypted and signed with a device specific key. - // For the reference implementation, I'm just going to use the keybox key. - const std::vector& key = ce->DeviceRootKey(); - if (key.empty()) { - LOGE("LoadUsageEntry: DeviceRootKey is unexpectedly empty."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Verify the signature of the usage entry. Sign encrypted into clear buffer. - unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH], - buffer.size() - SHA256_DIGEST_LENGTH, clear->signature, - &sig_length)) { - LOGE("LoadUsageEntry: Could not sign entry."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (CRYPTO_memcmp(clear->signature, encrypted->signature, - SHA256_DIGEST_LENGTH)) { - LOGE("LoadUsageEntry: Signature did not match."); - LOGE("LoadUsageEntry: Invalid signature given: %s", - wvcdm::HexEncode(encrypted->signature, sig_length).c_str()); - LOGE("LoadUsageEntry: Invalid signature computed: %s", - wvcdm::HexEncode(clear->signature, sig_length).c_str()); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Next, decrypt the entry. - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_decrypt_key(&key[0], 128, &aes_key); - AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset], - buffer.size() - kEncryptionOffset, &aes_key, iv_buffer, - AES_DECRYPT); - - // Check the verification string is correct. - if (memcmp(kEntryVerification, clear->verification, kMagicLength)) { - LOGE("LoadUsageEntry: Invalid magic: %s=%8.8s expected: %s=%8.8s", - wvcdm::HexEncode(clear->verification, kMagicLength).c_str(), - clear->verification, - wvcdm::HexEncode(reinterpret_cast(kEntryVerification), - kMagicLength) - .c_str(), - reinterpret_cast(kEntryVerification)); - return OEMCrypto_ERROR_BAD_MAGIC; - } - - // Check that the index is correct. - if (index != clear->data.index) { - LOGE("LoadUsageEntry: entry says index is %u, not %u", clear->data.index, - index); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (clear->data.status > kInactiveUnused) { - LOGE("LoadUsageEntry: entry has bad status %d", clear->data.status); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - data_ = clear->data; - return ODK_ReloadClockValues( - clock_values, data_.time_of_license_received, data_.time_of_first_decrypt, - data_.time_of_last_decrypt, data_.status, ce->SystemTime()); -} - -size_t UsageTableEntry::SignedEntrySize() { - size_t base = sizeof(SignedEntryBlock); - // round up to make even number of blocks: - size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1; - return blocks * wvoec::KEY_IV_SIZE; -} - -UsageTable::~UsageTable() {} - -size_t UsageTable::SignedHeaderSize(size_t count) { - size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t); - // round up to make even number of blocks: - size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1; - return blocks * wvoec::KEY_IV_SIZE; -} - -OEMCryptoResult UsageTable::UpdateUsageEntry( - SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer, - size_t* header_buffer_length, uint8_t* entry_buffer, - size_t* entry_buffer_length, ODK_ClockValues* clock_values) { - size_t signed_header_size = SignedHeaderSize(generation_numbers_.size()); - if (*entry_buffer_length < UsageTableEntry::SignedEntrySize() || - *header_buffer_length < signed_header_size) { - *entry_buffer_length = UsageTableEntry::SignedEntrySize(); - *header_buffer_length = signed_header_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *entry_buffer_length = UsageTableEntry::SignedEntrySize(); - *header_buffer_length = signed_header_size; - if ((!header_buffer) || (!entry_buffer)) - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - entry->UpdateAndIncrement(clock_values); - generation_numbers_[entry->index()] = entry->generation_number(); - OEMCryptoResult result = - entry->SaveData(ce_, session, entry_buffer, *entry_buffer_length); - if (result != OEMCrypto_SUCCESS) return result; - result = SaveUsageTableHeader(header_buffer, *header_buffer_length); - return result; -} - -UsageTableEntry* UsageTable::MakeEntry(uint32_t index) { - return new UsageTableEntry(this, index, master_generation_number_); -} - -OEMCryptoResult UsageTable::CreateNewUsageEntry( - SessionContext* session, std::unique_ptr* entry, - uint32_t* usage_entry_number) { - if (!header_loaded_) { - LOGE("CreateNewUsageEntry: Header not loaded."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - const size_t index = generation_numbers_.size(); - const size_t max = ce_->max_usage_table_size(); - if (max > 0 && index >= max) { - LOGE("Too many usage entries: %zu/%zu", index, max); - return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; - } - UsageTableEntry* new_entry = MakeEntry(index); - generation_numbers_.push_back(master_generation_number_); - sessions_.push_back(session); - master_generation_number_++; - entry->reset(new_entry); - *usage_entry_number = index; - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult UsageTable::LoadUsageEntry( - SessionContext* session, std::unique_ptr* entry, - uint32_t index, const std::vector& buffer, - ODK_ClockValues* clock_values) { - if (!header_loaded_) { - LOGE("LoadUsageEntry: Header not loaded."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - if (index >= generation_numbers_.size()) - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - if (sessions_[index]) { - LOGE("LoadUsageEntry: index %u used by other session.", index); - return OEMCrypto_ERROR_INVALID_SESSION; - } - const size_t max = ce_->max_usage_table_size(); - if (max > 0 && index >= max) { - LOGE("Too many usage entries: %u/%zu", index, max); - return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; - } - std::unique_ptr new_entry(MakeEntry(index)); - - OEMCryptoResult status = - new_entry->LoadData(ce_, index, buffer, clock_values); - if (status != OEMCrypto_SUCCESS) { - return status; - } - if (new_entry->generation_number() != generation_numbers_[index]) { - LOGE("Generation SKEW: %ld -> %ld", new_entry->generation_number(), - generation_numbers_[index]); - if ((new_entry->generation_number() + 1 < generation_numbers_[index]) || - (new_entry->generation_number() - 1 > generation_numbers_[index])) { - return OEMCrypto_ERROR_GENERATION_SKEW; - } - status = OEMCrypto_WARNING_GENERATION_SKEW; - } - sessions_[index] = session; - *entry = std::move(new_entry); - return status; -} - -OEMCryptoResult UsageTable::ShrinkUsageTableHeader( - uint32_t new_table_size, uint8_t* header_buffer, - size_t* header_buffer_length) { - if (new_table_size > generation_numbers_.size()) { - LOGE("OEMCrypto_ShrinkUsageTableHeader: %u > %zu", new_table_size, - generation_numbers_.size()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - size_t signed_header_size = SignedHeaderSize(new_table_size); - if (*header_buffer_length < signed_header_size) { - *header_buffer_length = signed_header_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *header_buffer_length = signed_header_size; - if (!header_buffer) { - LOGE("OEMCrypto_ShrinkUsageTableHeader: buffer null."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - for (size_t i = new_table_size; i < sessions_.size(); ++i) { - if (sessions_[i]) { - LOGE("ShrinkUsageTableHeader: session open for %zu", i); - return OEMCrypto_ERROR_ENTRY_IN_USE; - } - } - generation_numbers_.resize(new_table_size); - sessions_.resize(new_table_size); - master_generation_number_++; - return SaveUsageTableHeader(header_buffer, *header_buffer_length); -} - -OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer, - size_t buffer_size) { - if (!SaveGenerationNumber()) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - size_t count = generation_numbers_.size(); - // buffer_size was determined by calling function. - if (buffer_size != SignedHeaderSize(count)) - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - std::vector clear_buffer(buffer_size); - memset(&clear_buffer[0], 0, buffer_size); - memset(signed_buffer, 0, buffer_size); - SignedHeaderBlock* clear = - reinterpret_cast(&clear_buffer[0]); - SignedHeaderBlock* encrypted = - reinterpret_cast(signed_buffer); - - // Pack the clear data into the clear buffer. - memcpy(clear->verification, kHeaderVerification, kMagicLength); - clear->master_generation = master_generation_number_; - clear->count = count; - // This points to the variable size part of the buffer. - int64_t* stored_generations = - reinterpret_cast(&clear_buffer[sizeof(SignedHeaderBlock)]); - std::copy(generation_numbers_.begin(), generation_numbers_.begin() + count, - stored_generations); - - // This should be encrypted and signed with a device specific key. - // For the reference implementation, I'm just going to use the keybox key. - const std::vector& key = ce_->DeviceRootKey(); - if (key.empty()) { - LOGE("SaveUsageTableHeader: DeviceRootKey is unexpectedly empty."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Encrypt the entry. - if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) { - LOGE("SaveUsageHeader: Could not generate iv entry."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer. - memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_encrypt_key(&key[0], 128, &aes_key); - AES_cbc_encrypt( - &clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset], - buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT); - - // Sign the entry. - unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), - &signed_buffer[SHA256_DIGEST_LENGTH], - buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature, - &sig_length)) { - LOGE("SaveUsageHeader: Could not sign entry."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -OEMCryptoResult UsageTable::LoadUsageTableHeader( - const std::vector& buffer) { - if (!LoadGenerationNumber(false)) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - - if (buffer.size() < SignedHeaderSize(0)) return OEMCrypto_ERROR_SHORT_BUFFER; - size_t max = ce_->max_usage_table_size(); - if (max > 0 && buffer.size() > SignedHeaderSize(max)) { - LOGE("Header too big: %zu bytes/%zu bytes", buffer.size(), - SignedHeaderSize(max)); - return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; - } - std::vector clear_buffer(buffer.size()); - SignedHeaderBlock* clear = - reinterpret_cast(&clear_buffer[0]); - const SignedHeaderBlock* encrypted = - reinterpret_cast(&buffer[0]); - - // This should be encrypted and signed with a device specific key. - // For the reference implementation, I'm just going to use the keybox key. - const std::vector& key = ce_->DeviceRootKey(); - if (key.empty()) { - LOGE("LoadUsageTableHeader: DeviceRootKey is unexpectedly empty."); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Verify the signature of the usage entry. Sign encrypted into clear buffer. - unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH], - buffer.size() - SHA256_DIGEST_LENGTH, clear->signature, - &sig_length)) { - LOGE("LoadUsageTableHeader: Could not sign entry."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (CRYPTO_memcmp(clear->signature, encrypted->signature, - SHA256_DIGEST_LENGTH)) { - LOGE("LoadUsageTableHeader: Signature did not match."); - LOGE("LoadUsageTableHeader: Invalid signature given: %s", - wvcdm::HexEncode(encrypted->signature, sig_length).c_str()); - LOGE("LoadUsageTableHeader: Invalid signature computed: %s", - wvcdm::HexEncode(clear->signature, sig_length).c_str()); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Next, decrypt the entry. - uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_decrypt_key(&key[0], 128, &aes_key); - AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset], - buffer.size() - kEncryptionOffset, &aes_key, iv_buffer, - AES_DECRYPT); - - // Check the verification string is correct. - if (memcmp(kHeaderVerification, clear->verification, kMagicLength)) { - LOGE("LoadUsageTableHeader: Invalid magic: %s=%8.8s expected: %s=%8.8s", - wvcdm::HexEncode(clear->verification, kMagicLength).c_str(), - clear->verification, - wvcdm::HexEncode(reinterpret_cast(kHeaderVerification), - kMagicLength) - .c_str(), - reinterpret_cast(kHeaderVerification)); - return OEMCrypto_ERROR_BAD_MAGIC; - } - - // Check that size is correct, now that we know what it should be. - if (buffer.size() < SignedHeaderSize(clear->count)) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (buffer.size() > SignedHeaderSize(clear->count)) { - LOGW("LoadUsageTableHeader: buffer is large. %zu > %zu", buffer.size(), - SignedHeaderSize(clear->count)); - } - - OEMCryptoResult status = OEMCrypto_SUCCESS; - if (clear->master_generation != master_generation_number_) { - LOGE("Generation SKEW: %ld -> %ld", clear->master_generation, - master_generation_number_); - if ((clear->master_generation + 1 < master_generation_number_) || - (clear->master_generation - 1 > master_generation_number_)) { - return OEMCrypto_ERROR_GENERATION_SKEW; - } - status = OEMCrypto_WARNING_GENERATION_SKEW; - } - int64_t* stored_generations = - reinterpret_cast(&clear_buffer[0] + sizeof(SignedHeaderBlock)); - generation_numbers_.assign(stored_generations, - stored_generations + clear->count); - sessions_.clear(); - sessions_.resize(clear->count); - header_loaded_ = true; - return status; -} - -OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry, - uint32_t new_index) { - if (new_index >= generation_numbers_.size()) { - LOGE("MoveEntry: index beyond end of usage table %u >= %zu", new_index, - generation_numbers_.size()); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (sessions_[new_index]) { - LOGE("MoveEntry: session open for %u", new_index); - return OEMCrypto_ERROR_ENTRY_IN_USE; - } - if (!entry) { - LOGE("MoveEntry: null entry"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - sessions_[new_index] = sessions_[entry->index()]; - sessions_[entry->index()] = 0; - - entry->set_index(new_index); - generation_numbers_[new_index] = master_generation_number_; - entry->set_generation_number(master_generation_number_); - master_generation_number_++; - return OEMCrypto_SUCCESS; -} - -void UsageTable::IncrementGeneration() { - master_generation_number_++; - SaveGenerationNumber(); -} - -bool UsageTable::SaveGenerationNumber() { - wvcdm::FileSystem* file_system = ce_->file_system(); - std::string path; - // Note: this path is OK for a real implementation, but using security level 1 - // would be better. - // TODO(jfore, rfrias): Address how this property is presented to the ref. - // For now, the path is empty. - /*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3, - &path)) { - LOGE("UsageTable: Unable to get base path"); - return false; - }*/ - // On a real implementation, you should NOT put the generation number in - // a file in user space. It should be stored in secure memory. - std::string filename = path + "GenerationNumber.dat"; - auto file = file_system->Open( - filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate); - if (!file) { - LOGE("UsageTable: File open failed: %s", path.c_str()); - return false; - } - file->Write(reinterpret_cast(&master_generation_number_), - sizeof(int64_t)); - return true; -} - -bool UsageTable::LoadGenerationNumber(bool or_make_new_one) { - wvcdm::FileSystem* file_system = ce_->file_system(); - std::string path; - // Note: this path is OK for a real implementation, but using security level 1 - // would be better. - // TODO(jfore, rfrias): Address how this property is presented to the ref. - // For now, the path is empty. - /*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3, - &path)) { - LOGE("UsageTable: Unable to get base path"); - return false; - }*/ - // On a real implementation, you should NOT put the generation number in - // a file in user space. It should be stored in secure memory. - std::string filename = path + "GenerationNumber.dat"; - auto file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly); - if (!file) { - if (or_make_new_one) { - return RAND_bytes(reinterpret_cast(&master_generation_number_), - sizeof(int64_t)) == 1; - } - LOGE("UsageTable: File open failed: %s (clearing table)", path.c_str()); - master_generation_number_ = 0; - return false; - } - file->Read(reinterpret_cast(&master_generation_number_), - sizeof(int64_t)); - return true; -} - -OEMCryptoResult UsageTable::CreateUsageTableHeader( - uint8_t* header_buffer, size_t* header_buffer_length) { - size_t signed_header_size = SignedHeaderSize(0); - if (*header_buffer_length < signed_header_size) { - *header_buffer_length = signed_header_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *header_buffer_length = signed_header_size; - if (!LoadGenerationNumber(true)) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - // Make sure there are no entries that are currently tied to an open session. - for (size_t i = 0; i < sessions_.size(); ++i) { - if (sessions_[i] != nullptr) { - LOGE("CreateUsageTableHeader: index %zu used by session.", i); - return OEMCrypto_ERROR_INVALID_SESSION; - } - } - sessions_.clear(); - generation_numbers_.clear(); - header_loaded_ = true; - return SaveUsageTableHeader(header_buffer, *header_buffer_length); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_usage_table_ref.h b/oemcrypto/ref/src/oemcrypto_usage_table_ref.h deleted file mode 100644 index 7fdd178..0000000 --- a/oemcrypto/ref/src/oemcrypto_usage_table_ref.h +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef OEMCRYPTO_USAGE_TABLE_REF_H_ -#define OEMCRYPTO_USAGE_TABLE_REF_H_ - -#include -#include -#include -#include -#include - -#include "OEMCryptoCENC.h" -#include "odk_structs.h" -#include "oemcrypto_types.h" -#include "openssl/sha.h" - -namespace wvoec_ref { - -class SessionContext; -class CryptoEngine; -class UsageTable; - -const size_t kMaxPSTLength = 255; -// This is the data we store offline. -struct StoredUsageEntry { - int64_t generation_number; - int64_t time_of_license_received; - int64_t time_of_first_decrypt; - int64_t time_of_last_decrypt; - enum OEMCrypto_Usage_Entry_Status status; - uint8_t mac_key_server[wvoec::MAC_KEY_SIZE]; - uint8_t mac_key_client[wvoec::MAC_KEY_SIZE]; - uint32_t index; - uint8_t pst[kMaxPSTLength+1]; // add 1 for padding. - uint8_t pst_length; -}; - -class UsageTableEntry { - public: - UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation); - virtual ~UsageTableEntry(); // Free memory, remove reference in header. - bool Inactive() { return data_.status >= kInactive; } - // Mark this entry as modified and forbid a usage report until the data has - // been saved. This is done on important events like first decrypt and - // deactivation. - void ForbidReport(); - OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length); - bool VerifyPST(const uint8_t* pst, size_t pst_length); - bool VerifyMacKeys(const std::vector& server, - const std::vector& client); - bool SetMacKeys(const std::vector& server, - const std::vector& client); - virtual OEMCryptoResult ReportUsage(const std::vector& pst, - uint8_t* buffer, size_t* buffer_length); - virtual void UpdateAndIncrement(ODK_ClockValues* clock_values); - // Save all data to the given buffer. This should be called after updating the - // data. - OEMCryptoResult SaveData(CryptoEngine* ce, SessionContext* session, - uint8_t* signed_buffer, size_t buffer_size); - // Load all data from the buffer, and then update clock_values. - OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index, - const std::vector& buffer, - ODK_ClockValues* clock_values); - int64_t generation_number() { return data_.generation_number; } - void set_generation_number(int64_t value) { data_.generation_number = value; } - void set_index(int32_t index) { data_.index = index; } - uint32_t index() { return data_.index; } - void set_recent_decrypt(bool recent_decrypt) { - recent_decrypt_ = recent_decrypt; - } - static size_t SignedEntrySize(); - const uint8_t* mac_key_server() const { return data_.mac_key_server; } - const uint8_t* mac_key_client() const { return data_.mac_key_client; } - - protected: - UsageTable* usage_table_; // Owner of this object. - bool recent_decrypt_; - bool forbid_report_; - StoredUsageEntry data_; -}; - -class UsageTable { - public: - explicit UsageTable(CryptoEngine* ce) : ce_(ce), header_loaded_(false){}; - virtual ~UsageTable(); - - OEMCryptoResult CreateNewUsageEntry(SessionContext* session, - std::unique_ptr* entry, - uint32_t* usage_entry_number); - OEMCryptoResult LoadUsageEntry(SessionContext* session, - std::unique_ptr* entry, - uint32_t index, - const std::vector& buffer, - ODK_ClockValues* clock_values); - OEMCryptoResult UpdateUsageEntry( - SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer, - size_t* header_buffer_length, uint8_t* entry_buffer, - size_t* entry_buffer_length, ODK_ClockValues* clock_values); - OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index); - OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer, - size_t* header_buffer_length); - OEMCryptoResult LoadUsageTableHeader(const std::vector& buffer); - OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size, - uint8_t* header_buffer, - size_t* header_buffer_length); - void ReleaseEntry(uint32_t index) { sessions_[index] = 0; } - void IncrementGeneration(); - static size_t SignedHeaderSize(size_t count); - - protected: - virtual UsageTableEntry* MakeEntry(uint32_t index); - virtual OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer, - size_t buffer_size); - virtual bool SaveGenerationNumber(); - virtual bool LoadGenerationNumber(bool or_make_new_one); - - CryptoEngine* ce_; - bool header_loaded_; - int64_t master_generation_number_; - std::vector generation_numbers_; - std::vector sessions_; - - friend class UsageTableEntry; -}; - -} // namespace wvoec_ref - -#endif // OEMCRYPTO_USAGE_TABLE_REF_H_ diff --git a/oemcrypto/ref/src/wvcrc.cpp b/oemcrypto/ref/src/wvcrc.cpp deleted file mode 100644 index f357ad8..0000000 --- a/oemcrypto/ref/src/wvcrc.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Compute CRC32 Checksum. Needed for verification of WV Keybox. -// -#include "platform.h" -#include "wvcrc32.h" - -namespace wvoec_ref { - -#define INIT_CRC32 0xffffffff - -uint32_t wvrunningcrc32(const uint8_t* p_begin, size_t i_count, - uint32_t i_crc) { - constexpr uint32_t CRC32[256] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, - 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, - 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, - 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, - 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, - 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, - 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, - 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, - 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, - 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, - 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, - 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, - 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, - 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, - 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, - 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, - 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, - 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, - 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, - 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, - 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, - 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4}; - - /* Calculate the CRC */ - while (i_count > 0) { - i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin)]; - p_begin++; - i_count--; - } - - return(i_crc); -} - -uint32_t wvcrc32(const uint8_t* p_begin, size_t i_count) { - return(wvrunningcrc32(p_begin, i_count, INIT_CRC32)); -} - -uint32_t wvcrc32Init() { - return INIT_CRC32; -} - -uint32_t wvcrc32Cont(const uint8_t* p_begin, size_t i_count, - uint32_t prev_crc) { - return(wvrunningcrc32(p_begin, i_count, prev_crc)); -} - -uint32_t wvcrc32n(const uint8_t* p_begin, size_t i_count) { - return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32)); -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/wvcrc32.h b/oemcrypto/ref/src/wvcrc32.h deleted file mode 100644 index 56df9d3..0000000 --- a/oemcrypto/ref/src/wvcrc32.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Compute CRC32 Checksum. Needed for verification of WV Keybox. -// -#ifndef WVCRC32_H_ -#define WVCRC32_H_ - -#include - -namespace wvoec_ref { - -uint32_t wvcrc32(const uint8_t* p_begin, size_t i_count); -uint32_t wvcrc32Init(); -uint32_t wvcrc32Cont(const uint8_t* p_begin, size_t i_count, uint32_t prev_crc); - -// Convert to network byte order -uint32_t wvcrc32n(const uint8_t* p_begin, size_t i_count); - -} // namespace wvoec_ref - -#endif // WVCRC32_H_ diff --git a/oemcrypto/test/fuzz_tests/README.md b/oemcrypto/test/fuzz_tests/README.md index 3550994..3f66444 100644 --- a/oemcrypto/test/fuzz_tests/README.md +++ b/oemcrypto/test/fuzz_tests/README.md @@ -85,12 +85,12 @@ OEMCrypto implementations on linux. $ ./out/Default/oemcrypto_unittests --generate_corpus \ --gtest_filter=-"*Huge*" ``` - + * There can be lot of duplicate corpus files that are generated from unit tests. We can minimize the corpus files to only a subset of files that cover unique paths within the API when run using fuzzer. Run following command to minimize corpus. - + ```shell $ cd /path/to/cdm/repo # build fuzzer binaries @@ -128,7 +128,7 @@ OEMCrypto implementations on linux. * Build and test fuzz scripts locally using following commands. The build script builds fuzz binaries for both oemcrypto reference implementation - as well as odkitee implementation. + as well as opk implementation. ```shell $ cd PATH_TO_CDM_DIR diff --git a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests index a32f5a3..2ebcc9d 100755 --- a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests +++ b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests @@ -1,4 +1,16 @@ #!/bin/bash + +echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX" +echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX" +echo "TODO(b/192560463): The OPK does not build because it expects an" +echo "older version of the ODK library. The ipc_ref tests do not work because" +echo "the reference code is v17 but OPK is v16." +# Also, if you are fixing this script, it should probably be moved to the jenkins +# directory, so that it is next to all the other scripts that Luci runs. +echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX" +echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX" +exit 0 + set -ex export CXX=clang++ @@ -9,4 +21,11 @@ export PYTHONPATH="$PYTHONPATH:$PATH_TO_CDM_DIR/third_party" python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ --depth=$(pwd) oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp -ninja -C out/Default \ No newline at end of file +ninja -C out/Default +# oemcrypto_opk_fuzztests.gypi has flags to instrument all the gyp targets +# with fuzzer flags. +python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ + --depth=$(pwd) \ + --include=oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi \ + oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp +ninja -C out/Default diff --git a/oemcrypto/test/fuzz_tests/build_partner_oemcrypto_fuzztests b/oemcrypto/test/fuzz_tests/build_partner_oemcrypto_fuzztests old mode 100644 new mode 100755 diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc new file mode 100644 index 0000000..46e3e19 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc @@ -0,0 +1,94 @@ +// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oemcrypto_fuzz_helper.h" +#include "oemcrypto_fuzz_structs.h" + +namespace wvoec { +// Free dynamic memory allocated by fuzzer script. +void FreeOutputBuffers(OEMCrypto_SESSION session_id, + OEMCrypto_DestBufferDesc& output_descriptor, + int* secure_fd) { + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: { + delete[] output_descriptor.buffer.clear.address; + break; + } + case OEMCrypto_BufferType_Secure: { + OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, *secure_fd); + break; + } + case OEMCrypto_BufferType_Direct: { + break; + } + } +} + +bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, + OEMCrypto_DestBufferDesc& output_descriptor, + int* secure_fd, size_t input_buffer_size) { + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: { + output_descriptor.buffer.clear.address = + new OEMCrypto_SharedMemory[input_buffer_size]; + return true; + } + case OEMCrypto_BufferType_Secure: { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_id, input_buffer_size, &output_descriptor, secure_fd); + return sts == OEMCrypto_SUCCESS; + } + case OEMCrypto_BufferType_Direct: { + return true; + } + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Redirect printf and log statements from oemcrypto functions to a file to + // reduce noise + RedirectStdoutToFile(); + uint8_t subsample_flags; + + // OEMCrypto_DestBufferDesc and a buffer from which data needs to be copied + // are expected as inputs to copy buffer API. + // Input fuzzed data is interpreted as + // (OEMCrypto_DestBufferDesc | subsample_flags | input_buffer) + if (size <= sizeof(OEMCrypto_Copy_Buffer_Fuzz)) { + return 0; + } + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + // Fuzz dest_buffer_desc. + memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + ConvertDataToValidEnum(OEMCrypto_BufferType_MaxValue, + &fuzzed_structure.dest_buffer_desc.type); + + OEMCryptoLicenseAPIFuzz license_api_fuzz; + Session* session = license_api_fuzz.session(); + // Fuzz input buffer to be copied. + size_t input_buffer_size = size - sizeof(fuzzed_structure); + int secure_fd = 0; + // Create output buffer pointers. If secure buffer is not supported, we + // explicitly convert to clear buffer and fuzz. + if (!InitializeOutputBuffers(session->session_id(), + fuzzed_structure.dest_buffer_desc, &secure_fd, + input_buffer_size)) { + LOGI( + "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " + "clear buffer instead."); + fuzzed_structure.dest_buffer_desc.type = OEMCrypto_BufferType_Clear; + InitializeOutputBuffers(session->session_id(), + fuzzed_structure.dest_buffer_desc, &secure_fd, + input_buffer_size); + } + OEMCrypto_CopyBuffer(session->session_id(), data + sizeof(fuzzed_structure), + input_buffer_size, &fuzzed_structure.dest_buffer_desc, + subsample_flags); + FreeOutputBuffers(session->session_id(), fuzzed_structure.dest_buffer_desc, + &secure_fd); + return 0; +} +} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc index b3d0582..560a172 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc @@ -1,5 +1,5 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine +// source code may only be used and distributed under the Widevine Master // License Agreement. #include "oemcrypto_fuzz_helper.h" diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc index 6ff69a9..eb1465e 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc @@ -5,9 +5,9 @@ #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "log.h" -#include "odk_overflow.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" +#include "oemcrypto_overflow.h" namespace wvoec { const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB; @@ -20,7 +20,7 @@ void FreeOutputBuffers(OEMCrypto_SESSION session_id, sample_description[i].buffers.output_descriptor; switch (fuzzed_output_descriptor.type) { case OEMCrypto_BufferType_Clear: { - delete[] fuzzed_output_descriptor.buffer.clear.address; + delete[] fuzzed_output_descriptor.buffer.clear.clear_buffer; break; } case OEMCrypto_BufferType_Secure: { @@ -44,9 +44,10 @@ bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, vector& secure_fd_array) { switch (output_descriptor.type) { case OEMCrypto_BufferType_Clear: { - output_descriptor.buffer.clear - .address = new OEMCrypto_SharedMemory[std::min( - MAX_FUZZ_SAMPLE_SIZE, output_descriptor.buffer.clear.address_length)]; + output_descriptor.buffer.clear.clear_buffer = + new OEMCrypto_SharedMemory[std::min( + MAX_FUZZ_SAMPLE_SIZE, + output_descriptor.buffer.clear.clear_buffer_length)]; return true; } case OEMCrypto_BufferType_Secure: { @@ -54,7 +55,7 @@ bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( session_id, std::min(MAX_FUZZ_SAMPLE_SIZE, - output_descriptor.buffer.secure.handle_length), + output_descriptor.buffer.secure.secure_buffer_length), &output_descriptor, secure_fd); if (sts == OEMCrypto_SUCCESS) secure_fd_array[sample_index] = *secure_fd; return sts == OEMCrypto_SUCCESS; @@ -138,9 +139,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Copy sub sample data. sample_descriptions[i].subsamples = &subsamples[input_subsample_index]; - if (odk_add_overflow_ux(input_subsample_index, - sample_descriptions[i].subsamples_length, - &input_subsample_index)) { + if (OPK_AddOverflowUX(input_subsample_index, + sample_descriptions[i].subsamples_length, + &input_subsample_index)) { return 0; } if (input_subsample_index > subsamples.size()) return 0; diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h index 5a5febb..37b3daf 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h @@ -68,6 +68,14 @@ struct OEMCrypto_Generate_RSA_Signature_Fuzz { // input buffer data is of variable length and not included in // this structure. }; + +struct OEMCrypto_Copy_Buffer_Fuzz { + // Corpus format is as below. + // dest_buffer_desc + subsample_flags + input buffer + OEMCrypto_DestBufferDesc dest_buffer_desc; + uint8_t subsample_flags; + // Input buffer of variable length is not included in this structure. +}; } // namespace wvoec #endif // OEMCRYPTO_FUZZ_STRUCTS_H_ \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp index 6192f29..458e3b8 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp @@ -119,5 +119,11 @@ 'oemcrypto_report_usage_fuzz.cc', ], }, + { + 'target_name': 'oemcrypto_copy_buffer_fuzz', + 'sources': [ + 'oemcrypto_copy_buffer_fuzz.cc', + ], + }, ], } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi index 6d43e37..eaa88cc 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi @@ -15,6 +15,7 @@ }, 'sources': [ '../../odk/src/core_message_deserialize.cpp', + '../../odk/src/core_message_features.cpp', '../../odk/src/core_message_serialize.cpp', '../oec_device_features.cpp', '../oec_key_deriver.cpp', @@ -40,14 +41,14 @@ '<(oemcrypto_dir)/test/fuzz_tests', '<(oemcrypto_dir)/odk/include', '<(oemcrypto_dir)/odk/src', - '<(oemcrypto_dir)/odkitee/oemcrypto_ta', + '<(oemcrypto_dir)/opk/oemcrypto_ta', ], 'includes': [ '../../../util/libssl_dependency.gypi', ], 'dependencies': [ - '../../../third_party/gmock.gyp:gtest', - '../../../third_party/gmock.gyp:gmock', + '../../../third_party/googletest.gyp:gtest', + '../../../third_party/googletest.gyp:gmock', ], 'defines': [ 'OEMCRYPTO_FUZZ_TESTS', @@ -95,6 +96,7 @@ '-fcoverage-mapping', ], 'ldflags': [ + '-fsanitize=fuzzer', '-fprofile-instr-generate', '-fcoverage-mapping', ], @@ -106,11 +108,11 @@ '../../ref/oec_ref.gypi', ], }], - ['oemcrypto_implementation_version=="odkitee"', { - # Include oemcrypto odkitee implementation code for building odkitee + ['oemcrypto_implementation_version=="opk"', { + # Include oemcrypto opk implementation code for building opk # implementation fuzz binaries. 'dependencies': [ - '../../odkitee/oemcrypto_ta/oemcrypto_ta.gyp:oemcrypto_ta', + '../../opk/oemcrypto_ta/wtpi_test_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_no_ipc', ], }], ], # conditions diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc b/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc index 202351e..19b60b7 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_generate_signature.cc @@ -10,7 +10,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (!is_init) { wvoec::global_features.Initialize(); wvoec::global_features.RestrictFilter("*"); - wvcdm::Properties::Init(); + wvutil::Properties::Init(); is_init = true; } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc index da6ed6a..ed47b0b 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc @@ -1,5 +1,5 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine +// source code may only be used and distributed under the Widevine Master // License Agreement. #include "OEMCryptoCENC.h" diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp deleted file mode 100644 index e5eb71a..0000000 --- a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -# source code may only be used and distributed under the Widevine -# License Agreement. -{ - 'target_defaults': { - 'type': 'executable', - 'includes': [ - 'oemcrypto_fuzztests.gypi', - ], - }, - 'variables': { - # Flag to select appropriate underlying oemcrypto implementation when - # buiding fuzz binaries. - 'oemcrypto_implementation_version%': 'odkitee', - 'oemcrypto_dir': '../..', - }, - 'targets': [ - { - 'target_name': 'oemcrypto_odkitee_load_license_fuzz', - 'sources': [ - 'oemcrypto_load_license_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_load_provisioning_fuzz', - 'sources': [ - 'oemcrypto_load_provisioning_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_load_renewal_fuzz', - 'sources': [ - 'oemcrypto_load_renewal_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_license_request_fuzz', - 'sources': [ - 'oemcrypto_license_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_provisioning_request_fuzz', - 'sources': [ - 'oemcrypto_provisioning_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_renewal_request_fuzz', - 'sources': [ - 'oemcrypto_renewal_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_decrypt_cenc_fuzz', - 'sources': [ - 'oemcrypto_decrypt_cenc_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_load_entitled_content_keys_fuzz', - 'sources': [ - 'oemcrypto_load_entitled_content_keys_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_dispatcher_fuzz', - 'include_dirs': [ - '<(oemcrypto_dir)/odkitee/serialization/common', - '<(oemcrypto_dir)/odkitee/serialization/os_interfaces', - '<(oemcrypto_dir)/odkitee/serialization/tee', - '<(oemcrypto_dir)/odkitee/serialization/tee/include', - '<(oemcrypto_dir)/odkitee/serialization/ports/trusty/include/', - ], - 'dependencies': [ - '<(oemcrypto_dir)/odkitee/serialization/tee/tee.gyp:odkitee_tee', - ], - 'sources': [ - 'oemcrypto_odkitee_dispatcher_fuzz.cc', - '<(oemcrypto_dir)/odkitee/serialization/test/transport_interface.c', - '<(oemcrypto_dir)/odkitee/serialization/ports/trusty/serialization_adapter/shared_memory.c', - ], - }, - ], -} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc similarity index 50% rename from oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc rename to oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc index 1a3c770..3fae8e6 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc @@ -1,23 +1,15 @@ #include +#include -#include "dispatcher.h" -#include "marshaller_base.h" -#include "transport_interface.h" +#include "opk_dispatcher.h" +#include "opk_init.h" +#include "tos_transport_interface.h" namespace wvoec { -void InitializeODKMessage(ODK_Message* message, uint8_t* data, size_t size) { - ODK_Message_Impl* impl = (ODK_Message_Impl*)message; - impl->base = data; - impl->size = size; - impl->capacity = size; - impl->read_offset = 0; - impl->status = MESSAGE_STATUS_OK; -} - void OpenOEMCryptoTASession() { ODK_Message request; - ODK_Message* response = NULL; + ODK_Message response; uint8_t response_buffer[0x1000]; uint8_t request_body[] = { 0x06, // TAG_UINT32 @@ -26,16 +18,13 @@ void OpenOEMCryptoTASession() { 0x00, // value (false) 0x0a // TAG_EOM }; - - InitializeODKMessage(&request, request_body, sizeof(request_body)); - - ODK_DispatchMessage(&request, &response); - if (response != NULL) ODK_Transport_DeallocateMessage(response); + request = ODK_Message_Create(request_body, sizeof(request_body)); + OPK_DispatchMessage(&request, &response); } void InitializeOEMCryptoTA() { ODK_Message init_request; - ODK_Message* init_response = NULL; + ODK_Message init_response; uint8_t response_buffer[0x1000]; uint8_t init_request_body[] = { 0x06, // TAG_UINT32 @@ -43,15 +32,13 @@ void InitializeOEMCryptoTA() { 0x0a // TAG_EOM }; - InitializeODKMessage(&init_request, init_request_body, - sizeof(init_request_body)); - - ODK_DispatchMessage(&init_request, &init_response); - if (init_response != NULL) ODK_Transport_DeallocateMessage(init_response); + init_request = + ODK_Message_Create(init_request_body, sizeof(init_request_body)); + OPK_DispatchMessage(&init_request, &init_response); } extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { - ODK_InitializeDispatcher(); + OPK_Initialize(); InitializeOEMCryptoTA(); OpenOEMCryptoTASession(); return 0; @@ -59,16 +46,14 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ODK_Message request; - ODK_Message* response = NULL; + ODK_Message response; unsigned char response_buffer[0x1000]; uint8_t* input = new uint8_t[size]; memcpy(input, data, size); - InitializeODKMessage(&request, input, size); - - ODK_DispatchMessage(&request, &response); - if (response != NULL) ODK_Transport_DeallocateMessage(response); + request = ODK_Message_Create(input, size); + OPK_DispatchMessage(&request, &response); delete[] input; return 0; diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp new file mode 100644 index 0000000..b5a73a1 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp @@ -0,0 +1,148 @@ +# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +{ + 'target_defaults': { + 'type': 'executable', + 'includes': [ + 'oemcrypto_fuzztests.gypi', + ], + }, + 'variables': { + # Flag to select appropriate underlying oemcrypto implementation when + # buiding fuzz binaries. + 'oemcrypto_implementation_version%': 'opk', + 'oemcrypto_dir': '../..', + }, + 'targets': [ + { + 'target_name': 'oemcrypto_opk_load_license_fuzz', + 'sources': [ + 'oemcrypto_load_license_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_provisioning_fuzz', + 'sources': [ + 'oemcrypto_load_provisioning_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_renewal_fuzz', + 'sources': [ + 'oemcrypto_load_renewal_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_license_request_fuzz', + 'sources': [ + 'oemcrypto_license_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_provisioning_request_fuzz', + 'sources': [ + 'oemcrypto_provisioning_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_renewal_request_fuzz', + 'sources': [ + 'oemcrypto_renewal_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_decrypt_cenc_fuzz', + 'sources': [ + 'oemcrypto_decrypt_cenc_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_entitled_content_keys_fuzz', + 'sources': [ + 'oemcrypto_load_entitled_content_keys_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_encrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_encrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_decrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_decrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_sign_fuzz', + 'sources': [ + 'oemcrypto_generic_sign_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_verify_fuzz', + 'sources': [ + 'oemcrypto_generic_verify_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generate_rsa_signature_fuzz', + 'sources': [ + 'oemcrypto_generate_rsa_signature_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_usage_table_header_fuzz', + 'sources': [ + 'oemcrypto_load_usage_table_header_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_load_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_deactivate_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_deactivate_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_report_usage_fuzz', + 'sources': [ + 'oemcrypto_report_usage_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_copy_buffer_fuzz', + 'sources': [ + 'oemcrypto_copy_buffer_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_dispatcher_fuzz', + 'include_dirs': [ + '<(oemcrypto_dir)/opk/serialization/common', + '<(oemcrypto_dir)/opk/serialization/common/include', + '<(oemcrypto_dir)/opk/serialization/os_interfaces', + '<(oemcrypto_dir)/opk/serialization/tee', + '<(oemcrypto_dir)/opk/serialization/tee/include', + '<(oemcrypto_dir)/opk/ports/trusty/include/', + ], + 'dependencies': [ + '<(oemcrypto_dir)/opk/serialization/tee/tee.gyp:opk_tee', + ], + 'sources': [ + 'oemcrypto_opk_dispatcher_fuzz.cc', + '<(oemcrypto_dir)/opk/serialization/test/tos_secure_buffers.c', + '<(oemcrypto_dir)/opk/serialization/test/tos_transport_interface.c', + '<(oemcrypto_dir)/opk/serialization/test/tos_logging.c', + '<(oemcrypto_dir)/opk/ports/trusty/serialization_adapter/shared_memory.c', + ], + }, + ], +} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi similarity index 94% rename from oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi rename to oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi index 574c8b0..0a655fc 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi @@ -3,7 +3,7 @@ # License Agreement. # gypi file to be included using --includes option while building oemcrypto -# odkitee fuzz binaries. Odkitee classes needs to be instrumented with fuzzer +# opk fuzz binaries. OPK classes needs to be instrumented with fuzzer # but only when being built for fuzzing. Instead of directly updating # oemcrypto_ta.gyp target, we use gypi in build_oemcrypto_fuzztests script. { @@ -45,6 +45,9 @@ 'libraries': [ '-lpthread', ], + 'defines': [ + 'OPK_LOG_LEVEL=LOG_NONE', + ], 'conditions': [ ['generate_code_coverage_report=="true"', { # Include flags to build fuzzer binaries to generate source based code coverage reports. diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc index 65c1a9f..3b3813a 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc @@ -1,5 +1,5 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine +// source code may only be used and distributed under the Widevine Master // License Agreement. #include "oemcrypto_fuzz_helper.h" diff --git a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi index 16af1a8..581727d 100644 --- a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi @@ -45,8 +45,8 @@ '../../../util/libssl_dependency.gypi', ], 'dependencies': [ - '../../../third_party/gmock.gyp:gtest', - '../../../third_party/gmock.gyp:gmock', + '../../../third_party/googletest.gyp:gtest', + '../../../third_party/googletest.gyp:gmock', ], 'defines': [ 'OEMCRYPTO_FUZZ_TESTS', diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/oemcrypto/test/oec_decrypt_fallback_chain.cpp index b3d36dc..8eebf9b 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -16,8 +16,8 @@ namespace { void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { switch (dest_buffer->type) { case OEMCrypto_BufferType_Clear: - dest_buffer->buffer.clear.address += bytes; - dest_buffer->buffer.clear.address_length -= bytes; + dest_buffer->buffer.clear.clear_buffer += bytes; + dest_buffer->buffer.clear.clear_buffer_length -= bytes; break; case OEMCrypto_BufferType_Secure: @@ -37,7 +37,7 @@ void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) { const size_t increment = bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional - counter = wvcdm::htonll64(wvcdm::ntohll64(counter) + increment); + counter = wvutil::htonll64(wvutil::ntohll64(counter) + increment); memcpy(&(*subsample_iv)[half_iv_size], &counter, half_iv_size); } @@ -104,7 +104,7 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample( fake_sample.buffers.input_data += length; advance_dest_buffer(&fake_sample.buffers.output_descriptor, length); - if (cipher_mode == OEMCrypto_CipherMode_CTR) { + if (cipher_mode == OEMCrypto_CipherMode_CENC) { advance_iv_ctr(&fake_sample.iv, subsample.block_offset + subsample.num_bytes_encrypted); } @@ -205,13 +205,13 @@ void WriteDecryptCencCorpus( const OEMCrypto_CENCEncryptPatternDesc* pattern, size_t samples_length) { const std::string file_name = GetFileName("oemcrypto_decrypt_cenc_fuzz_seed_corpus"); - // Cipher mode. - AppendToFile(file_name, reinterpret_cast(&cipher_mode), - sizeof(OEMCryptoCipherMode)); - - // Pattern. - AppendToFile(file_name, reinterpret_cast(pattern), - sizeof(OEMCrypto_CENCEncryptPatternDesc)); + OEMCrypto_Decrypt_Cenc_Fuzz decrypt_cenc_fuzz_struct; + decrypt_cenc_fuzz_struct.cipher_mode = cipher_mode; + decrypt_cenc_fuzz_struct.pattern = *pattern; + // Cipher mode and Pattern. + AppendToFile(file_name, + reinterpret_cast(&decrypt_cenc_fuzz_struct), + sizeof(OEMCrypto_Decrypt_Cenc_Fuzz)); // Sample data for all samples. for (size_t i = 0; i < samples_length; i++) { diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.h b/oemcrypto/test/oec_decrypt_fallback_chain.h index 06ca62f..aafbb07 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.h +++ b/oemcrypto/test/oec_decrypt_fallback_chain.h @@ -7,6 +7,7 @@ #include "OEMCryptoCENC.h" #include "disallow_copy_and_assign.h" +#include "oemcrypto_fuzz_structs.h" namespace wvoec { diff --git a/oemcrypto/test/oec_device_features.cpp b/oemcrypto/test/oec_device_features.cpp index 1fab63f..4023081 100644 --- a/oemcrypto/test/oec_device_features.cpp +++ b/oemcrypto/test/oec_device_features.cpp @@ -48,7 +48,8 @@ void DeviceFeatures::Initialize() { // If the device uses a keybox, check to see if loading a certificate is // installed. if (provisioning_method == OEMCrypto_Keybox || - provisioning_method == OEMCrypto_OEMCertificate) { + provisioning_method == OEMCrypto_OEMCertificate || + provisioning_method == OEMCrypto_BootCertificateChain) { // Devices with a keybox or OEM Certificate are required to support loading // a DRM certificate. loads_certificate = true; @@ -81,8 +82,8 @@ void DeviceFeatures::Initialize() { } printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false"); resource_rating = OEMCrypto_ResourceRatingTier(); - printf("resource_rating = %u, security level %s.\n", resource_rating, - OEMCrypto_SecurityLevel()); + printf("resource_rating = %u, security level %u.\n", resource_rating, + static_cast(OEMCrypto_SecurityLevel())); uint32_t decrypt_hash_type = OEMCrypto_SupportsDecryptHash(); supports_crc = (decrypt_hash_type == OEMCrypto_CRC_Clear_Buffer); if (supports_crc) { @@ -109,13 +110,17 @@ void DeviceFeatures::Initialize() { printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n"); break; case TEST_PROVISION_30: - printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n"); + printf("TEST_PROVISION_30: Device provisioned with OEM Cert.\n"); + break; + case TEST_PROVISION_40: + printf("TEST_PROVISION_40: Device has boot certificate chain.\n"); break; } - std::string security_level = OEMCrypto_SecurityLevel(); - supports_level_1 = (security_level == "L1"); - printf("SecurityLevel is %s (%s)\n", - supports_level_1 ? "Level 1" : "Not Level 1", security_level.c_str()); + OEMCrypto_Security_Level security_level = OEMCrypto_SecurityLevel(); + supports_level_1 = (security_level == OEMCrypto_Level1); + printf("SecurityLevel is %s (L%u)\n", + supports_level_1 ? "Level 1" : "Not Level 1", + static_cast(security_level)); CheckSecureBuffers(); OEMCrypto_Terminate(); initialized_ = true; @@ -125,14 +130,18 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { std::string filter = initial_filter; // clang-format off if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*"); - if (!loads_certificate) FilterOut(&filter, "OEMCryptoLoadsCert*"); + // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for + // provisioning 4. Disabled here temporarily. + if (!loads_certificate || + provisioning_method == OEMCrypto_BootCertificateChain) + FilterOut(&filter, "OEMCryptoLoadsCert*"); if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*"); if (!cast_receiver) FilterOut(&filter, "*CastReceiver*"); - if (!usage_table) FilterOut(&filter, "*UsageTable*"); - if (!usage_table) FilterOut(&filter, "*BadRange_pst*"); if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*"); if (provisioning_method != OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*"); + if (provisioning_method != OEMCrypto_BootCertificateChain) + FilterOut(&filter, "*Prov40*"); if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*"); if (api_version < 9) FilterOut(&filter, "*API09*"); if (api_version < 10) FilterOut(&filter, "*API10*"); @@ -142,10 +151,11 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { if (api_version < 14) FilterOut(&filter, "*API14*"); if (api_version < 15) FilterOut(&filter, "*API15*"); if (api_version < 16) FilterOut(&filter, "*API16*"); + if (api_version < 17) FilterOut(&filter, "*API17*"); // clang-format on // Some tests may require root access. If user is not root, filter these tests // out. - if (!wvcdm::TestSleep::CanChangeSystemTime()) { + if (!wvutil::TestSleep::CanChangeSystemTime()) { printf("Filtering out TimeRollbackPrevention.\n"); FilterOut(&filter, "*TimeRollbackPrevention*"); } else { @@ -173,6 +183,9 @@ void DeviceFeatures::PickDerivedKey() { case OEMCrypto_Keybox: // Fall through to api_version < 12 case. break; + case OEMCrypto_BootCertificateChain: + derive_key_method = TEST_PROVISION_40; + return; case OEMCrypto_ProvisioningError: printf( "ERROR: OEMCrypto_GetProvisioningMethod() returns " @@ -252,6 +265,8 @@ const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method) { return "OEMCrypto_Keybox"; case OEMCrypto_OEMCertificate: return "OEMCrypto_OEMCertificate"; + case OEMCrypto_BootCertificateChain: + return "OEMCrypto_BootCertificateChain"; } // Not reachable return ""; diff --git a/oemcrypto/test/oec_device_features.h b/oemcrypto/test/oec_device_features.h index 9cef66f..06c7b58 100644 --- a/oemcrypto/test/oec_device_features.h +++ b/oemcrypto/test/oec_device_features.h @@ -10,9 +10,12 @@ namespace wvoec { // These tests are designed to work for this version: -constexpr unsigned int kCurrentAPI = 16; +constexpr unsigned int kCurrentAPI = 17; // The API version when Core Messages were introduced. constexpr unsigned int kCoreMessagesAPI = 16; +// The API version when we stopped encrypting key control blocks. +constexpr unsigned int kClearControlBlockAPIMajor = 16; +constexpr unsigned int kClearControlBlockAPIMinor = 5; // An output type for testing. The type field is secure, clear, or direct. If // the type is clear, then decrypt_inplace could be true. Otherwise, @@ -29,23 +32,24 @@ class DeviceFeatures { // There are several possible methods used to derive a set of known session // keys. For example, the test can install a known test keybox, or it can // parse the OEM certificate. - enum DeriveMethod { // Method to use derive session keys. - NO_METHOD, // Cannot derive known session keys. - LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys. - LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys. - TEST_PROVISION_30, // Device has OEM Certificate installed. + enum DeriveMethod { // Method to use derive session keys. + NO_METHOD, // Cannot derive known session keys. + LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys. + LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys. + TEST_PROVISION_30, // Device has OEM Certificate installed. + TEST_PROVISION_40, // Device has Boot Certificate Chain installed. }; enum DeriveMethod derive_key_method; - bool uses_keybox; // Device uses a keybox to derive session keys. - bool loads_certificate; // Device can load a certificate from the server. - bool generic_crypto; // Device supports generic crypto. - bool cast_receiver; // Device supports alternate rsa signature padding. - bool usage_table; // Device saves usage information. - bool supports_rsa_3072; // Device supports 3072 bit RSA keys. - bool supports_level_1; // Device supports Level 1 security. - uint32_t resource_rating; // Device's resource rating tier. - bool supports_crc; // Supported decrypt hash type CRC. + bool uses_keybox; // Device uses a keybox to derive session keys. + bool loads_certificate; // Device can load a certificate from the server. + bool generic_crypto; // Device supports generic crypto. + bool cast_receiver; // Device supports alternate rsa signature padding. + bool usage_table; // Device saves usage information. + bool supports_rsa_3072; // Device supports 3072 bit RSA keys. + bool supports_level_1; // Device supports Level 1 security. + uint32_t resource_rating; // Device's resource rating tier. + bool supports_crc; // Supported decrypt hash type CRC. bool test_secure_buffers; // If we can create a secure buffer for testing. uint32_t api_version; OEMCrypto_ProvisioningMethod provisioning_method; diff --git a/oemcrypto/test/oec_key_deriver.cpp b/oemcrypto/test/oec_key_deriver.cpp index f6abdb6..7a24b35 100644 --- a/oemcrypto/test/oec_key_deriver.cpp +++ b/oemcrypto/test/oec_key_deriver.cpp @@ -5,7 +5,7 @@ // OEMCrypto unit tests // -#include "oec_session_util.h" +#include "oec_key_deriver.h" #include #include @@ -58,7 +58,7 @@ void Encryptor::CBCEncrypt(const uint8_t* data, uint8_t* encrypted_data, void Encryptor::PadAndEncryptProvisioningMessage( RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted) const { - EXPECT_EQ(1, GetRandBytes(data->rsa_key_iv, KEY_IV_SIZE)); + EXPECT_EQ(1, RAND_bytes(data->rsa_key_iv, KEY_IV_SIZE)); ASSERT_EQ(enc_key_.size(), KEY_SIZE); *encrypted = *data; if (data->rsa_key_length > sizeof(data->rsa_key)) { @@ -147,8 +147,9 @@ void KeyDeriver::ServerSignBuffer(const uint8_t* data, size_t data_length, ASSERT_EQ(mac_key_server_.size(), MAC_KEY_SIZE); signature->assign(SHA256_DIGEST_LENGTH, 0); unsigned int sig_len = SHA256_DIGEST_LENGTH; - ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_server_.data(), mac_key_server_.size(), - data, data_length, signature->data(), &sig_len)); + ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_server_.data(), + static_cast(mac_key_server_.size()), data, data_length, + signature->data(), &sig_len)); } void KeyDeriver::ClientSignBuffer(const vector& buffer, @@ -156,8 +157,9 @@ void KeyDeriver::ClientSignBuffer(const vector& buffer, ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE); signature->assign(SHA256_DIGEST_LENGTH, 0); unsigned int sig_len = SHA256_DIGEST_LENGTH; - ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_client_.data(), mac_key_client_.size(), - buffer.data(), buffer.size(), signature->data(), &sig_len)); + ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_client_.data(), + static_cast(mac_key_client_.size()), buffer.data(), + buffer.size(), signature->data(), &sig_len)); } void KeyDeriver::ClientSignPstReport(const vector& pst_report_buffer, @@ -165,7 +167,8 @@ void KeyDeriver::ClientSignPstReport(const vector& pst_report_buffer, ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE); signature->assign(SHA_DIGEST_LENGTH, 0); unsigned int sig_len = SHA_DIGEST_LENGTH; - ASSERT_TRUE(HMAC(EVP_sha1(), mac_key_client_.data(), mac_key_client_.size(), + ASSERT_TRUE(HMAC(EVP_sha1(), mac_key_client_.data(), + static_cast(mac_key_client_.size()), &pst_report_buffer[SHA_DIGEST_LENGTH], pst_report_buffer.size() - SHA_DIGEST_LENGTH, signature->data(), &sig_len)); diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 76fea1d..bd7dd21 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -7,6 +7,7 @@ #include "oec_session_util.h" +#include #include #include #include @@ -18,7 +19,6 @@ #include #include -#include #include #include #include @@ -28,6 +28,7 @@ #include "OEMCryptoCENC.h" #include "clock.h" #include "core_message_deserialize.h" +#include "core_message_features.h" #include "core_message_serialize.h" #include "disallow_copy_and_assign.h" #include "log.h" @@ -47,13 +48,13 @@ using namespace std; // which is std::vector in this case. namespace std { void PrintTo(const vector& value, ostream* os) { - *os << wvcdm::b2a_hex(value); + *os << wvutil::b2a_hex(value); } } // namespace std namespace wvoec { - namespace { +using oemcrypto_core_message::features::CoreMessageFeatures; constexpr size_t kTestSubsampleSectionSize = 256; @@ -112,9 +113,9 @@ OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key, } // namespace -int GetRandBytes(unsigned char* buf, int num) { +int GetRandBytes(unsigned char* buf, size_t num) { // returns 1 on success, -1 if not supported, or 0 if other failure. - return RAND_bytes(buf, num); + return RAND_bytes(buf, static_cast(num)); } // Does the boilerplate to fill out sample and subsample descriptions for @@ -143,8 +144,8 @@ void GenerateSimpleSampleDescription( OEMCrypto_DestBufferDesc& out_buffer_descriptor = sample->buffers.output_descriptor; out_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - out_buffer_descriptor.buffer.clear.address = out.data(); - out_buffer_descriptor.buffer.clear.address_length = out.size(); + out_buffer_descriptor.buffer.clear.clear_buffer = out.data(); + out_buffer_descriptor.buffer.clear.clear_buffer_length = out.size(); } // Increment counter for AES-CTR. The CENC spec specifies we increment only @@ -155,17 +156,19 @@ void ctr128_inc64(int64_t increaseBy, uint8_t* iv) { ASSERT_NE(nullptr, iv); uint64_t* counterBuffer = reinterpret_cast(&iv[8]); (*counterBuffer) = - wvcdm::htonll64(wvcdm::ntohll64(*counterBuffer) + increaseBy); + wvutil::htonll64(wvutil::ntohll64(*counterBuffer) + increaseBy); } // Some compilers don't like the macro htonl within an ASSERT_EQ. uint32_t htonl_fnc(uint32_t x) { return htonl(x); } void dump_boringssl_error() { - while (unsigned long err = ERR_get_error()) { + // BoringSSL and OpenSSL disagree about what the type of an error code is, so + // we must use "auto" here. + while (auto err = ERR_get_error()) { char buffer[120]; ERR_error_string_n(err, buffer, sizeof(buffer)); - cout << "BoringSSL Error -- " << buffer << "\n"; + cerr << "BoringSSL Error -- " << buffer << "\n"; } } @@ -191,7 +194,7 @@ class boringssl_ptr { Test_PST_Report::Test_PST_Report(const std::string& pst_in, OEMCrypto_Usage_Entry_Status status_in) : status(status_in), pst(pst_in) { - time_created = wvcdm::Clock().GetCurrentTime(); + time_created = wvutil::Clock().GetCurrentTime(); } template GenerateDerivedKeysFromKeybox(keybox); encryptor_ = session_->key_deriver(); + } else if (global_features.provisioning_method == + OEMCrypto_BootCertificateChain) { + // TODO(chelu): change this to CSR provisioning. + session_->LoadOEMCert(true); + session_->GenerateRSASessionKey(&message_key_, &encrypted_message_key_); + encryptor_.set_enc_key(message_key_); } else { EXPECT_EQ(global_features.provisioning_method, OEMCrypto_OEMCertificate); session_->LoadOEMCert(true); @@ -391,9 +400,12 @@ void ProvisioningRoundTrip:: void ProvisioningRoundTrip::SignResponse() { if (global_features.api_version >= kCoreMessagesAPI) { + CoreMessageFeatures features = + CoreMessageFeatures::DefaultFeatures(ODK_MAJOR_VERSION); ASSERT_TRUE( oemcrypto_core_message::serialize::CreateCoreProvisioningResponse( - core_response_, core_request_, &serialized_core_message_)); + features, core_response_, core_request_, + &serialized_core_message_)); // Resizing for huge core message length unit tests. serialized_core_message_.resize( std::max(required_core_message_size_, serialized_core_message_.size())); @@ -537,17 +549,24 @@ void ProvisioningRoundTrip::VerifyLoadFailed() { void LicenseRoundTrip::VerifyRequestSignature( const vector& data, const vector& generated_signature, size_t core_message_length) { - const std::vector subdata(data.begin() + core_message_length, - data.end()); - session()->VerifyRSASignature(subdata, generated_signature.data(), - generated_signature.size(), kSign_RSASSA_PSS); - SHA256(data.data(), core_message_length, request_hash_); // If the api version was not set by the test, then we record the api version // from the request. Also, if the api was set to be higher than oemcrypto // supports, then we lower it. This version will be used in the response. if (api_version_ == 0) api_version_ = core_request_.api_major_version; if (api_version_ > global_features.api_version) api_version_ = global_features.api_version; + + if (global_features.api_version < 17) { + const std::vector subdata(data.begin() + core_message_length, + data.end()); + session()->VerifyRSASignature(subdata, generated_signature.data(), + generated_signature.size(), kSign_RSASSA_PSS); + SHA256(data.data(), core_message_length, request_hash_); + } else { + session()->VerifyRSASignature(data, generated_signature.data(), + generated_signature.size(), kSign_RSASSA_PSS); + SHA256(data.data(), core_message_length, request_hash_); + } } void LicenseRoundTrip::FillAndVerifyCoreRequest( @@ -557,13 +576,13 @@ void LicenseRoundTrip::FillAndVerifyCoreRequest( core_message_string, &core_request_)); EXPECT_EQ(global_features.api_version, core_request_.api_major_version); if (global_features.api_version == 16) { - // We support either 16.3 or 16.4 for OEMCrypto 16. + // We support either 16.3-16.4 for OEMCrypto 16 public release, and v16.5 + // for L3 release only. EXPECT_LE(3, core_request_.api_minor_version); - EXPECT_GE(4, core_request_.api_minor_version); + EXPECT_GE(5, core_request_.api_minor_version); } else if (global_features.api_version == ODK_MAJOR_VERSION) { - // If we are testing the latest OEMCrypto version, make sure it is built - // with the latest ODK version, too: - EXPECT_EQ(ODK_MINOR_VERSION, core_request_.api_minor_version); + // We do not expect older tests to work with a newer OEMCrypto. + EXPECT_GE(ODK_MINOR_VERSION, core_request_.api_minor_version); } if (expect_request_has_correct_nonce_) { EXPECT_EQ(session()->nonce(), core_request_.nonce); @@ -604,7 +623,7 @@ void LicenseRoundTrip::CreateDefaultResponse() { response_data_.keys[i].control.duration = htonl(key_duration); response_data_.keys[i].control.nonce = htonl(session_->nonce()); response_data_.keys[i].control.control_bits = htonl(control_); - response_data_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR; + response_data_.keys[i].cipher_mode = OEMCrypto_CipherMode_CENC; } // Fill in the default core_response_ fields, except the substrings, which are // filled in the next function. @@ -759,12 +778,20 @@ void LicenseRoundTrip::EncryptAndSignResponse() { sizeof(response_data_.keys[i].key_data) && response_data_.keys[i].key_data_length % 16 == 0) { memcpy(iv_buffer, &response_data_.keys[i].control_iv[0], KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_encrypt_key(&response_data_.keys[i].key_data[0], 128, &aes_key); - AES_cbc_encrypt( - reinterpret_cast(&response_data_.keys[i].control), - reinterpret_cast(&encrypted_response_data_.keys[i].control), - KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT); + if (core_request_.api_major_version < kClearControlBlockAPIMajor || + (core_request_.api_major_version == kClearControlBlockAPIMajor && + core_request_.api_minor_version < kClearControlBlockAPIMinor)) { + AES_KEY aes_key; + AES_set_encrypt_key(&response_data_.keys[i].key_data[0], 128, &aes_key); + AES_cbc_encrypt( + reinterpret_cast(&response_data_.keys[i].control), + reinterpret_cast( + &encrypted_response_data_.keys[i].control), + KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT); + } else { + encrypted_response_data_.keys[i].control = + response_data_.keys[i].control; + } session_->key_deriver().CBCEncrypt( &response_data_.keys[i].key_data[0], &encrypted_response_data_.keys[i].key_data[0], @@ -775,10 +802,22 @@ void LicenseRoundTrip::EncryptAndSignResponse() { if (api_version_ < kCoreMessagesAPI) { serialized_core_message_.resize(0); } else { + if (core_request_.api_major_version == 0) { + // If we don't have a valid request, then we should at least set the + // version number of the request so that CreateCoreLicenseResponse can + // compute the version number of the response. + core_request_.api_major_version = ODK_MAJOR_VERSION; + core_request_.api_minor_version = ODK_MINOR_VERSION; + } std::string request_hash_string( reinterpret_cast(request_hash_), sizeof(request_hash_)); + // We might try to test a future api_version_, but we can only make a core + // message with at most the current ODK version. This is only done to verify + // that OEMCrypto does not attempt to load a future version. + CoreMessageFeatures features = CoreMessageFeatures::DefaultFeatures( + std::min(api_version_, static_cast(ODK_MAJOR_VERSION))); ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse( - core_response_, core_request_, request_hash_string, + features, core_response_, core_request_, request_hash_string, &serialized_core_message_)); // Resize serialize core message to be just big enough or required core // message size, whichever is larger. @@ -983,6 +1022,17 @@ void EntitledMessage::SetEntitlementKeyId(unsigned int index, entitled_key_data_[index].entitlement_key_id, key_id.length()); } +void EntitledMessage::SetContentKeyId(unsigned int index, + const std::string& key_id) { + ASSERT_LT(index, num_keys_); + ASSERT_LE(key_id.size(), kTestKeyIdMaxLength); + entitled_key_data_[index].content_key_id_length = key_id.size(); + memcpy(entitled_key_data_[index].content_key_id, + reinterpret_cast(key_id.c_str()), key_id.length()); + entitled_key_array_[index].content_key_id = + FindSubstring(entitled_key_data_[index].content_key_id, key_id.length()); +} + OEMCrypto_Substring EntitledMessage::FindSubstring(const void* ptr, size_t size) { OEMCrypto_Substring substring{0, 0}; @@ -998,7 +1048,7 @@ void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) { EncryptContentKey(); ASSERT_EQ(expected_sts, OEMCrypto_LoadEntitledContentKeys( - license_messages_->session()->session_id(), + entitled_key_session_, reinterpret_cast(entitled_key_data_), sizeof(entitled_key_data_), num_keys_, entitled_key_array_)); if (expected_sts != OEMCrypto_SUCCESS) { @@ -1009,14 +1059,14 @@ void EntitledMessage::LoadKeys(OEMCryptoResult expected_sts) { } OEMCryptoResult EntitledMessage::LoadKeys(const vector& message) { - return OEMCrypto_LoadEntitledContentKeys( - license_messages_->session()->session_id(), message.data(), - message.size(), num_keys_, entitled_key_array_); + return OEMCrypto_LoadEntitledContentKeys(entitled_key_session_, + message.data(), message.size(), + num_keys_, entitled_key_array_); } OEMCryptoResult EntitledMessage::LoadKeys() { return OEMCrypto_LoadEntitledContentKeys( - license_messages_->session()->session_id(), + entitled_key_session_, reinterpret_cast(entitled_key_data_), sizeof(entitled_key_data_), num_keys_, entitled_key_array_); } @@ -1045,10 +1095,69 @@ void EntitledMessage::EncryptContentKey() { // Corpus for load entitled keys fuzzer should be in the format: // message buffer to be verified | entitled content key object array. AppendToFile(file_name, reinterpret_cast(entitled_key_data_), - sizeof(entitled_key_data_)); + num_keys_ * sizeof(EntitledContentKeyData)); AppendSeparator(file_name); AppendToFile(file_name, reinterpret_cast(entitled_key_array_), - num_keys_); + num_keys_ * sizeof(OEMCrypto_EntitledContentKeyObject)); + } +} + +void EntitledMessage::LoadCasKeys(bool load_even, bool load_odd, + OEMCryptoResult expected_sts) { + for (size_t i = 0; i < num_keys_; ++i) { + EntitledContentKeyData* key_data = &entitled_key_data_[i]; + const size_t entitlement_key_index = key_data->key_index; + MessageKeyData* entitlement_key = + &license_messages_->response_data().keys[entitlement_key_index]; + + // Load the entitlement key from |key_array_|. + AES_KEY aes_key; + AES_set_encrypt_key(entitlement_key->key_data, 256, &aes_key); + + // Encrypt the content key with the entitlement key. + uint8_t iv[16]; + memcpy(&iv[0], key_data->content_key_data_iv, KEY_IV_SIZE); + AES_cbc_encrypt(key_data->content_key_data, + key_data->encrypted_content_key_data, KEY_SIZE, &aes_key, + iv, AES_ENCRYPT); + } + + // Convert the OEMCrypto_EntitledContentKeyObject to + // OEMCrypto_EntitledCasKeyObject. Only the first two key object is used. + OEMCrypto_EntitledContentKeyObject even_key; + OEMCrypto_EntitledContentKeyObject odd_key; + bool has_even = load_even && num_keys_ >= 1; + bool has_odd = load_odd && num_keys_ >= 2; + if (has_even) { + even_key.entitlement_key_id = entitled_key_array_[0].entitlement_key_id; + even_key.content_key_id = entitled_key_array_[0].content_key_id; + even_key.content_key_data_iv = entitled_key_array_[0].content_key_data_iv; + even_key.content_key_data = entitled_key_array_[0].content_key_data; + even_key.content_iv.length = 0; + } + if (has_odd) { + odd_key.entitlement_key_id = entitled_key_array_[1].entitlement_key_id; + odd_key.content_key_id = entitled_key_array_[1].content_key_id; + odd_key.content_key_data_iv = entitled_key_array_[1].content_key_data_iv; + odd_key.content_key_data = entitled_key_array_[1].content_key_data; + odd_key.content_iv.length = 0; + } + + OEMCryptoResult sts = OEMCrypto_LoadCasECMKeys( + entitled_key_session_, + reinterpret_cast(entitled_key_data_), + sizeof(entitled_key_data_), has_even ? &even_key : nullptr, + has_odd ? &odd_key : nullptr); + ASSERT_EQ(expected_sts, sts); + if (expected_sts != OEMCrypto_SUCCESS) { + return; + } + + if (has_even) { + VerifyEntitlementTestKey(0); + } + if (has_odd) { + VerifyEntitlementTestKey(1); } } @@ -1058,48 +1167,51 @@ void EntitledMessage::EncryptContentKey() { // control block. void EntitledMessage::VerifyKCBs() { for (unsigned int i = 0; i < num_keys_; i++) { - EntitledContentKeyData* key_data = &entitled_key_data_[i]; - const size_t entitlement_key_index = key_data->key_index; - MessageKeyData* entitlement_key = - &license_messages_->response_data().keys[entitlement_key_index]; - KeyControlBlock block; - size_t size = sizeof(block); - OEMCryptoResult sts = OEMCrypto_QueryKeyControl( - license_messages_->session()->session_id(), key_data->content_key_id, - key_data->content_key_id_length, reinterpret_cast(&block), - &size); - if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_EQ(sizeof(block), size); - // control duration and bits stored in network byte order. For printing - // we change to host byte order. - ASSERT_EQ((htonl_fnc(entitlement_key->control.duration)), - (htonl_fnc(block.duration))) - << "For key " << i; - ASSERT_EQ(htonl_fnc(entitlement_key->control.control_bits), - htonl_fnc(block.control_bits)) - << "For key " << i; - } + VerifyEntitlementTestKey(i); + } +} + +void EntitledMessage::VerifyEntitlementTestKey(size_t index) { + ASSERT_GE(num_keys_, index); + + EntitledContentKeyData* key_data = &entitled_key_data_[index]; + const size_t entitlement_key_index = key_data->key_index; + MessageKeyData* entitlement_key = + &license_messages_->response_data().keys[entitlement_key_index]; + KeyControlBlock block; + size_t size = sizeof(block); + OEMCryptoResult sts = + OEMCrypto_QueryKeyControl(entitled_key_session_, key_data->content_key_id, + key_data->content_key_id_length, + reinterpret_cast(&block), &size); + if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(sizeof(block), size); + // control duration and bits stored in network byte order. For printing + // we change to host byte order. + ASSERT_EQ((htonl_fnc(entitlement_key->control.duration)), + (htonl_fnc(block.duration))) + << "For key " << index; + ASSERT_EQ(htonl_fnc(entitlement_key->control.control_bits), + htonl_fnc(block.control_bits)) + << "For key " << index; } } void EntitledMessage::VerifyDecrypt() { - const OEMCrypto_SESSION session_id = - license_messages_->session()->session_id(); - // Loop through all the keys and try decrypt with each one. for (unsigned int i = 0; i < num_keys_; i++) { const EntitledContentKeyData* const key_data = &entitled_key_data_[i]; OEMCryptoResult result = OEMCrypto_SelectKey( - session_id, key_data->content_key_id, key_data->content_key_id_length, - OEMCrypto_CipherMode_CTR); + entitled_key_session_, key_data->content_key_id, + key_data->content_key_id_length, OEMCrypto_CipherMode_CENC); ASSERT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i; vector expected_data; vector actual_data; - result = DecryptCTR(session_id, key_data->content_key_data, &expected_data, - &actual_data); + result = DecryptCTR(entitled_key_session_, key_data->content_key_data, + &expected_data, &actual_data); EXPECT_EQ(result, OEMCrypto_SUCCESS) << "For key " << i; EXPECT_EQ(actual_data, expected_data) << "For key " << i; } @@ -1133,7 +1245,7 @@ void RenewalRoundTrip::FillAndVerifyCoreRequest( EXPECT_TRUE( oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage( core_message_string, &core_request_)); - EXPECT_EQ(license_messages_->core_request().api_major_version, + EXPECT_EQ(license_messages_->api_version(), core_request_.api_major_version); EXPECT_EQ(license_messages_->core_request().nonce, core_request_.nonce); EXPECT_EQ(license_messages_->core_request().session_id, @@ -1184,8 +1296,14 @@ void RenewalRoundTrip::EncryptAndSignResponse() { sizeof(response_data_.keys[0].control)); serialized_core_message_.resize(0); } else { + // TODO(b/191724203): Test renewal server has different version from license + // server. + ASSERT_NE(license_messages_, nullptr); + CoreMessageFeatures features = + CoreMessageFeatures::DefaultFeatures(license_messages_->api_version()); ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse( - core_request_, renewal_duration_seconds_, &serialized_core_message_)); + features, core_request_, renewal_duration_seconds_, + &serialized_core_message_)); // Resize serialize core message to be just big enough or required core // message size, whichever is larger. serialized_core_message_.resize( @@ -1218,15 +1336,20 @@ void RenewalRoundTrip::EncryptAndSignResponse() { void RenewalRoundTrip::InjectFuzzedResponseData( OEMCrypto_Renewal_Response_Fuzz& fuzzed_data, const uint8_t* renewal_response, const size_t renewal_response_size) { + // TODO(b/191724203): Test renewal server has different version from license + // server. + ASSERT_NE(license_messages_, nullptr); + CoreMessageFeatures features = + CoreMessageFeatures::DefaultFeatures(license_messages_->api_version()); // Serializing core message. // This call also sets nonce in core response to match with session nonce. oemcrypto_core_message::serialize::CreateCoreRenewalResponse( - fuzzed_data.core_request, fuzzed_data.renewal_duration_seconds, + features, fuzzed_data.core_request, fuzzed_data.renewal_duration_seconds, &serialized_core_message_); // Copy serialized core message and encrypted response from data and - // calculate signature. Now we will have a valid signature for data generated - // by fuzzer. + // calculate signature. Now we will have a valid signature for data + // generated by fuzzer. encrypted_response_.assign(serialized_core_message_.begin(), serialized_core_message_.end()); encrypted_response_.insert(encrypted_response_.end(), renewal_response, @@ -1310,7 +1433,7 @@ void Session::GenerateNonce(int* error_counter) { if (error_counter) { (*error_counter)++; } else { - wvcdm::TestSleep::Sleep(1); // wait a second, then try again. + wvutil::TestSleep::Sleep(1); // wait a second, then try again. // The following is after a 1 second pause, so it cannot be from a nonce // flood. ASSERT_EQ(OEMCrypto_SUCCESS, @@ -1325,13 +1448,13 @@ void Session::FillDefaultContext(vector* mac_context, * from a license request message. * They are used to test MAC and ENC key generation. */ - *mac_context = wvcdm::a2b_hex( + *mac_context = wvutil::a2b_hex( "41555448454e5449434154494f4e000a4c08001248000000020000101907d9ff" "de13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e5873" "4930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a" "230a14080112100915007caa9b5931b76a3a85f046523e10011a093938373635" "34333231180120002a0c31383836373837343035000000000200"); - *enc_context = wvcdm::a2b_hex( + *enc_context = wvutil::a2b_hex( "454e4352595054494f4e000a4c08001248000000020000101907d9ffde13aa95" "c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930aceb" "e899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a1408" @@ -1375,13 +1498,14 @@ void Session::GenerateDerivedKeysFromSessionKey() { } void Session::TestDecryptCTR(bool select_key_first, - OEMCryptoResult expected_result, int key_index) { + OEMCryptoResult expected_result, + size_t key_index) { OEMCryptoResult select_result = OEMCrypto_SUCCESS; if (select_key_first) { // Select the key (from FillSimpleMessage) select_result = OEMCrypto_SelectKey( session_id(), license_.keys[key_index].key_id, - license_.keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR); + license_.keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC); } vector unencrypted_data; @@ -1435,11 +1559,11 @@ void Session::TestDecryptResult(OEMCryptoResult expected_result, } } -void Session::TestSelectExpired(unsigned int key_index) { +void Session::TestSelectExpired(size_t key_index) { if (global_features.api_version >= 13) { OEMCryptoResult status = OEMCrypto_SelectKey( session_id(), license().keys[key_index].key_id, - license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR); + license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CENC); // It is OK for SelectKey to succeed with an expired key, but if there is // an error, it must be OEMCrypto_ERROR_KEY_EXIRED. if (status != OEMCrypto_SUCCESS) { @@ -1479,13 +1603,13 @@ void Session::LoadOEMCert(bool verify_cert) { // Load the public cert's key into public_rsa_ and verify, if requested for (size_t i = 0; certs && i < static_cast(sk_X509_num(certs)); ++i) { - X509* x509_cert = sk_X509_value(certs, i); + X509* x509_cert = sk_X509_value(certs, static_cast(i)); boringssl_ptr pubkey(X509_get_pubkey(x509_cert)); ASSERT_TRUE(pubkey.NotNull()); if (i == 0) { public_rsa_ = EVP_PKEY_get1_RSA(pubkey.get()); if (!public_rsa_) { - cout << "d2i_RSAPrivateKey failed.\n"; + cerr << "d2i_RSAPrivateKey failed.\n"; dump_boringssl_error(); ASSERT_TRUE(nullptr != public_rsa_); } @@ -1495,7 +1619,8 @@ void Session::LoadOEMCert(bool verify_cert) { X509_NAME* name = X509_get_subject_name(x509_cert); printf(" OEM Certificate Name: %s\n", - X509_NAME_oneline(name, buffer.data(), buffer.size())); + X509_NAME_oneline(name, buffer.data(), + static_cast(buffer.size()))); boringssl_ptr store(X509_STORE_new()); ASSERT_TRUE(store.NotNull()); boringssl_ptr store_ctx( @@ -1525,7 +1650,8 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) { rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048); } uint8_t* p = const_cast(rsa_key); - boringssl_ptr bio(BIO_new_mem_buf(p, rsa_key_length)); + boringssl_ptr bio( + BIO_new_mem_buf(p, static_cast(rsa_key_length))); ASSERT_TRUE(bio.NotNull()); boringssl_ptr pkcs8_pki( d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); @@ -1534,6 +1660,33 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) { ASSERT_TRUE(evp.NotNull()); if (public_rsa_) RSA_free(public_rsa_); public_rsa_ = EVP_PKEY_get1_RSA(evp.get()); + if (!public_rsa_) { + cerr << "d2i_RSAPrivateKey failed. "; + dump_boringssl_error(); + FAIL() << "Could not parse public RSA key."; + } + switch (RSA_check_key(public_rsa_)) { + case 1: // valid. + return; + case 0: // not valid. + dump_boringssl_error(); + FAIL() << "[rsa key not valid] "; + default: // -1 == check failed. + dump_boringssl_error(); + FAIL() << "[error checking rsa key] "; + } +} + +void Session::SetRsaPublicKey(const uint8_t* buffer, size_t length) { + if (public_rsa_) { + RSA_free(public_rsa_); + public_rsa_ = nullptr; + } + if (public_ec_) { + EC_KEY_free(public_ec_); + public_ec_ = nullptr; + } + public_rsa_ = d2i_RSA_PUBKEY(nullptr, &buffer, length); if (!public_rsa_) { cout << "d2i_RSAPrivateKey failed. "; dump_boringssl_error(); @@ -1551,6 +1704,31 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) { } } +void Session::SetEcPublicKey(const uint8_t* buffer, size_t length) { + if (public_rsa_) { + RSA_free(public_rsa_); + public_rsa_ = nullptr; + } + if (public_ec_) { + EC_KEY_free(public_ec_); + public_ec_ = nullptr; + } + public_ec_ = d2i_EC_PUBKEY(nullptr, &buffer, length); + if (!public_ec_) { + cout << "d2i_RSAPrivateKey failed. "; + dump_boringssl_error(); + FAIL() << "Could not parse public RSA key."; + } + switch (EC_KEY_check_key(public_ec_)) { + case 1: // valid. + return; + case 0: // not valid. + default: + dump_boringssl_error(); + FAIL() << "[ec key not valid] "; + } +} + bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, size_t message_length, const uint8_t* signature, @@ -1623,8 +1801,9 @@ void Session::VerifyRSASignature(const vector& message, int size; // RSA_public_decrypt decrypts the signature, and then verifies that // it was padded with RSA PKCS1 padding. - size = RSA_public_decrypt(signature_length, signature, padded_digest.data(), - public_rsa_, RSA_PKCS1_PADDING); + size = RSA_public_decrypt(static_cast(signature_length), signature, + padded_digest.data(), public_rsa_, + RSA_PKCS1_PADDING); EXPECT_GT(size, 0); padded_digest.resize(size); EXPECT_EQ(message, padded_digest); @@ -1636,17 +1815,17 @@ void Session::VerifyRSASignature(const vector& message, bool Session::GenerateRSASessionKey(vector* session_key, vector* enc_session_key) { if (!public_rsa_) { - cout << "No public RSA key loaded in test code.\n"; + cerr << "No public RSA key loaded in test code.\n"; return false; } - *session_key = wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1"); + *session_key = wvutil::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1"); enc_session_key->assign(RSA_size(public_rsa_), 0); - int status = RSA_public_encrypt(session_key->size(), &(session_key->front()), - &(enc_session_key->front()), public_rsa_, - RSA_PKCS1_OAEP_PADDING); + int status = RSA_public_encrypt( + static_cast(session_key->size()), &(session_key->front()), + &(enc_session_key->front()), public_rsa_, RSA_PKCS1_OAEP_PADDING); int size = static_cast(RSA_size(public_rsa_)); if (status != size) { - cout << "GenerateRSASessionKey error encrypting session key.\n"; + cerr << "GenerateRSASessionKey error encrypting session key.\n"; dump_boringssl_error(); return false; } @@ -1688,8 +1867,6 @@ void Session::UpdateUsageEntry(std::vector* header_buffer) { } void Session::LoadUsageEntry(uint32_t index, const vector& buffer) { - usage_entry_number_ = index; - encrypted_usage_entry_ = buffer; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageEntry(session_id(), index, buffer.data(), buffer.size())); @@ -1731,7 +1908,7 @@ void Session::GenerateReport(const std::string& pst, if (expected_result != OEMCrypto_SUCCESS) { return; } - EXPECT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length); + EXPECT_EQ(wvutil::Unpacked_PST_Report::report_size(pst.length()), length); vector computed_signature(SHA_DIGEST_LENGTH); key_deriver_.ClientSignPstReport(pst_report_buffer_, &computed_signature); EXPECT_EQ(0, memcmp(computed_signature.data(), pst_report().signature(), @@ -1743,12 +1920,12 @@ void Session::GenerateReport(const std::string& pst, } void Session::VerifyPST(const Test_PST_Report& expected) { - wvcdm::Unpacked_PST_Report computed = pst_report(); + wvutil::Unpacked_PST_Report computed = pst_report(); EXPECT_EQ(expected.status, computed.status()); char* pst_ptr = reinterpret_cast(computed.pst()); std::string computed_pst(pst_ptr, pst_ptr + computed.pst_length()); ASSERT_EQ(expected.pst, computed_pst); - int64_t now = wvcdm::Clock().GetCurrentTime(); + int64_t now = wvutil::Clock().GetCurrentTime(); int64_t age = now - expected.time_created; // How old is this report. EXPECT_NEAR(expected.seconds_since_license_received + age, computed.seconds_since_license_received(), kTimeTolerance); @@ -1771,7 +1948,7 @@ void Session::VerifyReport(Test_PST_Report expected, int64_t time_license_received, int64_t time_first_decrypt, int64_t time_last_decrypt) { - const int64_t now = wvcdm::Clock().GetCurrentTime(); + const int64_t now = wvutil::Clock().GetCurrentTime(); expected.seconds_since_license_received = (time_license_received > 0 && time_license_received < now) ? now - time_license_received @@ -1816,10 +1993,11 @@ void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length, } // Corpus for request APIs should be signature_length + core_message_length + // data pointer. - AppendToFile(file_name, reinterpret_cast(&signature_length), - sizeof(signature_length)); - AppendToFile(file_name, reinterpret_cast(&core_message_length), - sizeof(core_message_length)); + OEMCrypto_Request_Fuzz request_fuzz_struct; + request_fuzz_struct.core_message_length = core_message_length; + request_fuzz_struct.signature_length = signature_length; + AppendToFile(file_name, reinterpret_cast(&request_fuzz_struct), + sizeof(OEMCrypto_Request_Fuzz)); AppendToFile(file_name, reinterpret_cast(data.data()), data.size()); } diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index 38766cf..9587cde 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -8,8 +8,10 @@ // OEMCrypto unit tests // #include +#include #include #include + #include #include @@ -54,13 +56,6 @@ constexpr int32_t kTimeTolerance = 3 * kSpeedMultiplier; constexpr int64_t kUsageTableTimeTolerance = 10 * kSpeedMultiplier; } // namespace -typedef struct { - uint8_t verification[4]; - uint32_t duration; - uint32_t nonce; - uint32_t control_bits; -} KeyControlBlock; - // Note: The API does not specify a maximum key id length. We specify a // maximum just for these tests, so that we have a fixed message size. constexpr size_t kTestKeyIdMaxLength = 16; @@ -117,7 +112,7 @@ struct EntitledContentKeyData { }; // returns 1 on success, -1 if not supported, or 0 if other failure. -int GetRandBytes(unsigned char* buf, int num); +int GetRandBytes(unsigned char* buf, size_t num); void GenerateSimpleSampleDescription(const std::vector& in, std::vector& out, @@ -475,18 +470,26 @@ class EntitledMessage { : license_messages_(license_messages), num_keys_() {} void FillKeyArray(); void MakeOneKey(size_t entitlement_key_index); + void SetEntitledKeySession(uint32_t key_session) { + entitled_key_session_ = key_session; + } void LoadKeys(OEMCryptoResult expected_sts); OEMCryptoResult LoadKeys(const vector& message); OEMCryptoResult LoadKeys(); void EncryptContentKey(); + void LoadCasKeys(bool load_even, bool load_odd, OEMCryptoResult expected_sts); void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; } uint32_t num_keys() const { return num_keys_; } void SetEntitlementKeyId(unsigned int index, const std::string& key_id); + void SetContentKeyId(unsigned int index, const std::string& key_id); OEMCrypto_EntitledContentKeyObject* entitled_key_array(); // Returns entitled_key_data_ which is used as input message buffer to // load entitled content keys API. EntitledContentKeyData* entitled_key_data(); size_t entitled_key_data_size(); + // Verify that key control blocks of the loaded keys. + void VerifyEntitlementTestKeys(); + void VerifyEntitlementTestKey(size_t index); private: // Find the offset of the give pointer, relative to |entitled_key_data_|. @@ -504,6 +507,7 @@ class EntitledMessage { EntitledContentKeyData entitled_key_data_[kMaxNumKeys]; // Entitled key object. Pointers are backed by |entitled_key_data_|. OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys]; + uint32_t entitled_key_session_; }; class Session { @@ -542,10 +546,10 @@ class Session { // Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption. void TestDecryptCTR(bool select_key_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS, - int key_index = 0); + size_t key_index = 0); // Verify that an attempt to select an expired key either succeeds, or gives // an actionable error code. - void TestSelectExpired(unsigned int key_index); + void TestSelectExpired(size_t key_index); // Calls OEMCrypto_GetOEMPublicCertificate and OEMCrypto_LoadOEMPrivateKey and // loads the OEM cert's public rsa key into public_rsa_. void LoadOEMCert(bool verify_cert = false); @@ -558,6 +562,11 @@ class Session { // the default test key is loaded. void PreparePublicKey(const uint8_t* rsa_key = nullptr, size_t rsa_key_length = 0); + // Loads the specified RSA public key into public_rsa_. + void SetRsaPublicKey(const uint8_t* buffer, size_t length); + // Loads the specified EC public key into public_ec_. + void SetEcPublicKey(const uint8_t* buffer, size_t length); + // Verifies the given signature is from the given message and RSA key, pkey. static bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, size_t message_length, @@ -618,8 +627,8 @@ class Session { string pst() const { return pst_; } // Returns a pointer-like thing to the usage report generated by the previous // call to GenerateReport. - wvcdm::Unpacked_PST_Report pst_report() { - return wvcdm::Unpacked_PST_Report(&pst_report_buffer_[0]); + wvutil::Unpacked_PST_Report pst_report() { + return wvutil::Unpacked_PST_Report(&pst_report_buffer_[0]); } // Verify the values in the PST report. The signature should have been // verified in GenerateReport, above. @@ -659,7 +668,9 @@ class Session { OEMCrypto_SESSION session_id_; KeyDeriver key_deriver_; uint32_t nonce_; - RSA* public_rsa_; + // Only one of RSA or EC should be set. + RSA* public_rsa_ = nullptr; + EC_KEY* public_ec_ = nullptr; vector pst_report_buffer_; MessageData license_; diff --git a/oemcrypto/test/oec_test_data.h b/oemcrypto/test/oec_test_data.h index fbd202d..453847b 100644 --- a/oemcrypto/test/oec_test_data.h +++ b/oemcrypto/test/oec_test_data.h @@ -18,6 +18,7 @@ namespace wvoec { // This is a test keybox. It will not be accepted by production systems. By // using a known keybox for these tests, the results for a given set of inputs // to a test are predictable and can be compared to the actual results. +// clang-format off static const WidevineKeybox kTestKeybox = { // Sample keybox used for test vectors { @@ -49,6 +50,43 @@ static const WidevineKeybox kTestKeybox = { 0x39, 0xf2, 0x94, 0xa7, } }; +// clang-format on + +// This test keybox is only accepted by the QA provisioning server. +// It is not valid with the production provisioning server. +// clang-format off +static const WidevineKeybox kQATestKeybox = { + // Sample keybox used for test vectors + { + // deviceID = WidevineQATestOnlyKeybox000 + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, + 0x51, 0x41, 0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, + 0x6c, 0x79, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, + 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + }, { + // key + 0x03, 0x77, 0x0f, 0x4e, 0x29, 0x77, 0x4b, 0x43, + 0x9e, 0xd2, 0x8a, 0x94, 0x73, 0xb3, 0x26, 0x65, + }, { + // data (system ID 2000000 = 0x1E8480). + 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x84, 0x80, + 0x90, 0x46, 0x8a, 0x1d, 0x27, 0x52, 0xca, 0xdb, + 0x5b, 0xf4, 0x67, 0xcb, 0xd3, 0x5e, 0x9e, 0xe9, + 0xb1, 0xcf, 0x89, 0x74, 0x08, 0x26, 0x96, 0x5b, + 0x43, 0x02, 0x7c, 0xb6, 0x4a, 0x9d, 0xf6, 0x7e, + 0x24, 0x82, 0x1d, 0xe2, 0x89, 0x52, 0x8e, 0xac, + 0xf2, 0x98, 0xac, 0x92, 0xa9, 0x40, 0x11, 0x9f, + 0x9f, 0xf8, 0x55, 0x84, 0x42, 0x04, 0x34, 0xbc, + 0x53, 0x14, 0x3d, 0x44, 0x97, 0x5c, 0xd9, 0xb4, + }, { + // magic + 0x6b, 0x62, 0x6f, 0x78, + }, { + // Crc + 0x43, 0xa2, 0x67, 0x63, + } +}; +// clang-format on // A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format // Used to verify the functions that manipulate RSA keys. diff --git a/oemcrypto/test/oemcrypto_serialization_version_test.cpp b/oemcrypto/test/oemcrypto_serialization_version_test.cpp new file mode 100644 index 0000000..31bfacb --- /dev/null +++ b/oemcrypto/test/oemcrypto_serialization_version_test.cpp @@ -0,0 +1,107 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include + +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oec_test_data.h" + +using namespace std; + +namespace wvoec { + +class OEMCryptoTest : public ::testing::Test { + protected: + OEMCryptoTest() {} + + void SetUp() override { + ::testing::Test::SetUp(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } + + void TearDown() override { + OEMCrypto_Terminate(); + ::testing::Test::TearDown(); + } +}; + +TEST_F(OEMCryptoTest, OPK_SerializationVersion) { + uint32_t ree_major = 0; + uint32_t ree_minor = 0; + uint32_t tee_major = 0; + uint32_t tee_minor = 0; + OEMCryptoResult sts = OEMCrypto_OPK_SerializationVersion( + &ree_major, &ree_minor, &tee_major, &tee_minor); + if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + cout << "OPK REE serialization version is " << ree_major << "." << ree_minor + << "\n"; + cout << "OPK TEE serialization version is " << tee_major << "." << tee_minor + << "\n"; + EXPECT_NE(ree_major, 0u); + EXPECT_NE(tee_major, 0u); + + const uint32_t orig_ree_major = ree_major; + const uint32_t orig_ree_minor = ree_minor; + const uint32_t orig_tee_major = tee_major; + const uint32_t orig_tee_minor = tee_minor; + + /* test requiring a specific version, should create incompatibility */ + ree_major = 100; + ree_minor = 1; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OPK_ERROR_INCOMPATIBLE_VERSION, sts); + EXPECT_EQ(ree_major, 100u); + EXPECT_EQ(ree_minor, 1u); + + /* now OEMCrypto_Initialize should fail with incompatible version */ + OEMCrypto_Terminate(); + EXPECT_EQ(OPK_ERROR_INCOMPATIBLE_VERSION, OEMCrypto_Initialize()); + + /* restore the default versions */ + ree_major = 0; + ree_minor = 0; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(ree_major, orig_ree_major); + EXPECT_EQ(ree_minor, orig_ree_minor); + EXPECT_EQ(tee_major, orig_tee_major); + EXPECT_EQ(tee_minor, orig_tee_minor); + + /* OEMCrypto_Initialize should work now */ + OEMCrypto_Terminate(); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + + /* changing minor version shouldn't create incompatibility */ + ree_minor++; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(ree_minor, orig_ree_minor + 1); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + + /* OEMCrypto_Initialize should still work */ + OEMCrypto_Terminate(); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + + /* remove the REE version override so subsequent tests work */ + ree_major = 0; + ree_minor = 0; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } +} + +} // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_session_tests_helper.cpp b/oemcrypto/test/oemcrypto_session_tests_helper.cpp index da8d5ec..f91a39a 100644 --- a/oemcrypto/test/oemcrypto_session_tests_helper.cpp +++ b/oemcrypto/test/oemcrypto_session_tests_helper.cpp @@ -63,6 +63,9 @@ void SessionUtil::EnsureTestKeys() { case DeviceFeatures::TEST_PROVISION_30: // Can use oem certificate to install test rsa key. break; + case wvoec::DeviceFeatures::TEST_PROVISION_40: + // OEM certificate is retrieved from the server. + break; default: FAIL() << "Cannot run test without test keybox or RSA key installed."; } @@ -71,6 +74,33 @@ void SessionUtil::EnsureTestKeys() { // This makes sure that the derived keys (encryption key and two mac keys) // are installed in OEMCrypto and in the test session. void SessionUtil::InstallTestRSAKey(Session* s) { + if (global_features.provisioning_method == OEMCrypto_BootCertificateChain) { + const size_t buffer_size = 5000; // Make sure it is large enough. + std::vector public_key(buffer_size); + size_t public_key_size = buffer_size; + std::vector public_key_signature(buffer_size); + size_t public_key_signature_size = buffer_size; + std::vector wrapped_private_key(buffer_size); + size_t wrapped_private_key_size = buffer_size; + OEMCrypto_PrivateKeyType key_type; + // Assume OEM cert has been loaded. + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_GenerateCertificateKeyPair( + s->session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type)); + // Assume the public key has been verified by the server and the DRM cert is + // returned. + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_LoadDRMPrivateKey(s->session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key_size)); + ASSERT_NO_FATAL_FAILURE( + s->SetRsaPublicKey(public_key.data(), public_key_size)); + return; + } + if (global_features.loads_certificate) { if (wrapped_rsa_key_.size() == 0) { // If we don't have a wrapped key yet, create one. @@ -83,4 +113,5 @@ void SessionUtil::InstallTestRSAKey(Session* s) { // Test RSA key should be loaded. ASSERT_NO_FATAL_FAILURE(s->PreparePublicKey()); } + } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 10d4fa0..c791c15 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -26,6 +26,7 @@ */ #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include -#include #include #include #include @@ -53,6 +53,8 @@ #include "oec_extra_test_keys.h" #include "oec_session_util.h" #include "oec_test_data.h" +#include "oemcrypto_corpus_generator_helper.h" +#include "oemcrypto_fuzz_structs.h" #include "oemcrypto_session_tests_helper.h" #include "oemcrypto_types.h" #include "platform.h" @@ -77,7 +79,7 @@ void PrintTo(const tuple(param); bool decrypt_inplace = output.decrypt_inplace; OEMCryptoBufferType type = output.type; - *os << ((mode == OEMCrypto_CipherMode_CTR) ? "CTR mode" : "CBC mode") + *os << ((mode == OEMCrypto_CipherMode_CENC) ? "CENC mode" : "CBCS mode") << ", pattern=(encrypt:" << pattern.encrypt << ", skip:" << pattern.skip << ")"; switch (type) { @@ -166,7 +168,7 @@ const size_t kMaxSampleSize[] = { 1*MiB, 2*MiB, 4*MiB, 16*MiB}; const size_t kMaxNumberSubsamples[] = { 10, 16, 32, 64}; const size_t kMaxSubsampleSize[] = { 100*KiB, 500*KiB, 1*MiB, 4*MiB}; const size_t kMaxGenericBuffer[] = { 10*KiB, 100*KiB, 500*KiB, 1*MiB}; -const size_t kMaxConcurrentSession[] = { 10, 20, 20, 30}; +const size_t kMaxConcurrentSession[] = { 10, 20, 30, 40}; const size_t kMaxKeysPerSession[] = { 4, 20, 20, 30}; const size_t kMaxTotalKeys[] = { 16, 40, 80, 90}; const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB}; @@ -180,7 +182,7 @@ const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB}; // then just use the string. Otherwise, convert to hex. std::string MaybeHex(const uint8_t* data, size_t length) { for (size_t i = 0; i < length; i++) { - if (!isprint(data[i])) return "0x" + wvcdm::HexEncode(data, length); + if (!isprint(data[i])) return "0x" + wvutil::HexEncode(data, length); } return std::string(reinterpret_cast(data), length); } @@ -195,7 +197,7 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { void SetUp() override { ::testing::Test::SetUp(); - wvcdm::TestSleep::SyncFakeClock(); + wvutil::TestSleep::SyncFakeClock(); const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); @@ -217,6 +219,29 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { } return &(*pos); } + + OEMCryptoResult CopyBuffer( + OEMCrypto_SESSION session, OEMCrypto_SharedMemory* input_buffer, + size_t input_buffer_size, + const OEMCrypto_DestBufferDesc* dest_buffer_descriptor, + uint8_t subsample_flags) { + if (ShouldGenerateCorpus() && input_buffer != nullptr && + dest_buffer_descriptor != nullptr) { + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + fuzzed_structure.dest_buffer_desc = *dest_buffer_descriptor; + fuzzed_structure.subsample_flags = subsample_flags; + const std::string file_name = + GetFileName("oemcrypto_copy_buffer_fuzz_seed_corpus"); + // Corpus for copy buffer fuzzer should be in the format: + // (dest_buffer_descriptor | subsample_flags | input_buffer). + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(&input_buffer), + input_buffer_size); + } + return OEMCrypto_CopyBuffer(session, input_buffer, input_buffer_size, + dest_buffer_descriptor, subsample_flags); + } }; TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { @@ -240,27 +265,21 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { */ TEST_F(OEMCryptoClientTest, VersionNumber) { const std::string log_message = - "OEMCrypto unit tests for API 16.3 or 4. Tests last updated 2021-12-01"; + "OEMCrypto unit tests for API 17.0. Tests last updated 2021-12-03"; cout << " " << log_message << "\n"; cout << " " - << "These tests are part of Android S." + << "These tests are part of Android T." << "\n"; LOGI("%s", log_message.c_str()); // If any of the following fail, then it is time to update the log message // above. - EXPECT_EQ(ODK_MAJOR_VERSION, 16); - // Note on minor versions. Widevine requires version 16.3 or greater for CE - // CDM and Android devices. For CE CDM devices that do not support usage - // tables, we strongly recommend 16.4. Note: This is the version of the ODK - // library built into the tests, which might be different from the version - // that is pre-compiled into liboemcrypto.so. - EXPECT_GE(ODK_MINOR_VERSION, 3); - EXPECT_LE(ODK_MINOR_VERSION, 4); - EXPECT_EQ(kCurrentAPI, 16u); - const char* level = OEMCrypto_SecurityLevel(); - ASSERT_NE(nullptr, level); - ASSERT_EQ('L', level[0]); - cout << " OEMCrypto Security Level is " << level << endl; + EXPECT_EQ(ODK_MAJOR_VERSION, 17); + EXPECT_EQ(ODK_MINOR_VERSION, 0); + EXPECT_EQ(kCurrentAPI, 17u); + OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel(); + ASSERT_GT(level, OEMCrypto_Level_Unknown); + ASSERT_LE(level, OEMCrypto_Level3); + cout << " OEMCrypto Security Level is L" << level << endl; uint32_t version = OEMCrypto_APIVersion(); uint32_t minor_version = OEMCrypto_MinorAPIVersion(); cout << " OEMCrypto API version is " << version << "." @@ -273,11 +292,24 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { if (version >= 15) { const uint32_t tier = OEMCrypto_ResourceRatingTier(); cout << " Resource Rating Tier: " << tier << endl; - const char* build_info = OEMCrypto_BuildInformation(); - ASSERT_NE(nullptr, build_info); - ASSERT_TRUE(strnlen(build_info, 256) <= 256) - << "BuildInformation should be a short printable string."; + } + if (version >= 17) { + OEMCryptoResult sts = OEMCrypto_ProductionReady(); + if (sts != OEMCrypto_SUCCESS) { + LOGW("Device is not production ready, returns %d", sts); + } + sts = OEMCrypto_SUCCESS; + std::string build_info; + size_t buf_length = 0; + sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); + if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { + build_info.resize(buf_length); + sts = OEMCrypto_BuildInformation(&build_info[0], &buf_length); + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); cout << " BuildInformation: " << build_info << endl; + OEMCrypto_WatermarkingSupport support = OEMCrypto_GetWatermarkingSupport(); + cout << " WatermarkingSupport: " << support << endl; } ASSERT_GE(version, 8u); ASSERT_LE(version, kCurrentAPI); @@ -393,7 +425,17 @@ const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { case HDCP_NONE: return "No HDCP supported, no secure data path"; case HDCP_V1: + return "HDCP version 1.x"; + case HDCP_V1_0: return "HDCP version 1.0"; + case HDCP_V1_1: + return "HDCP version 1.1"; + case HDCP_V1_2: + return "HDCP version 1.2"; + case HDCP_V1_3: + return "HDCP version 1.3"; + case HDCP_V1_4: + return "HDCP version 1.4"; case HDCP_V2: return "HDCP version 2.0"; case HDCP_V2_1: @@ -441,7 +483,17 @@ TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { OEMCrypto_LoadSRM(bad_srm.data(), bad_srm.size())); } -TEST_F(OEMCryptoClientTest, OEMCryptoMemoryLoadSrmForLargeSrm) { +TEST_F(OEMCryptoClientTest, CheckNullBuildInformationAPI17) { + OEMCryptoResult sts; + std::string build_info; + sts = OEMCrypto_BuildInformation(&build_info[0], nullptr); + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, sts); + size_t buf_length = 0; + sts = OEMCrypto_BuildInformation(nullptr, &buf_length); + ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, sts); +} + +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryLoadSrmHugeLargeSrm) { auto oemcrypto_function = [](size_t buffer_length) { vector srm_buffer(buffer_length); return OEMCrypto_LoadSRM(srm_buffer.data(), srm_buffer.size()); @@ -482,7 +534,7 @@ TEST_F(OEMCryptoClientTest, NormalInitTermination) { } // Test that set sandbox doesn't crash for a large sandbox id leangth. -TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForLargeSandboxIdLength) { +TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForHugeSandboxIdLength) { auto oemcrypto_function = [](size_t buffer_length) { vector buffer(buffer_length); return OEMCrypto_SetSandbox(buffer.data(), buffer.size()); @@ -490,6 +542,23 @@ TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForLargeSandboxIdLength) { TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } +TEST_F(OEMCryptoClientTest, CheckDTCP2CapabilityAPI17) { + OEMCryptoResult sts; + OEMCrypto_DTCP2_Capability capability; + sts = OEMCrypto_GetDTCP2Capability(&capability); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + switch (capability) { + case OEMCrypto_NO_DTCP2: + printf(" Current DTCP Support: DTCP2 not supported.\n"); + break; + case OEMCrypto_DTCP2_V1: + printf( + " Current DTCP Support: Version 1 (or higher) of " + "DTCP2 is supported.\n"); + break; + } +} + // // Session Tests // @@ -577,11 +646,11 @@ TEST_F(OEMCryptoClientTest, GetRandomLargeBuffer) { for (size_t i = 0; i < size; i++) { if (data1[i] == data2[i]) count++; } - ASSERT_LE(count, 3); // P(count > 3) = 1/256^3 = 6e-8. + ASSERT_LE(count, 6); // P(count > 6) = 4.3e-11 } // Verify that GetRandom doesn't crash for large input lengths. -TEST_F(OEMCryptoClientTest, OEMCryptoMemoryGetRandomForLargeBuffer) { +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryGetRandomForHugeBuffer) { auto oemcrypto_function = [](size_t buffer_length) { vector buffer(buffer_length); // TODO(ellurubharath, fredgc): Need to re-evaluate this on a real device @@ -600,7 +669,7 @@ TEST_F(OEMCryptoClientTest, GenerateNonce) { // Prevent a nonce flood even if each nonce is in a different session. TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { int error_counter = 0; - const int64_t test_start = wvcdm::Clock().GetCurrentTime(); + const int64_t test_start = wvutil::Clock().GetCurrentTime(); // More than 200 nonces per second should generate an error. // To allow for some slop, we actually test for more. const int flood_cutoff = 200; @@ -610,7 +679,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { ASSERT_NO_FATAL_FAILURE(s.open()); s.GenerateNonce(&error_counter); } - const int64_t test_end = wvcdm::Clock().GetCurrentTime(); + const int64_t test_end = wvutil::Clock().GetCurrentTime(); int valid_counter = loop_count - error_counter; // Either oemcrypto should enforce a delay, or it should return an error from // GenerateNonce -- in either case the number of valid nonces is rate @@ -619,7 +688,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2)); error_counter = 0; // After a pause, we should be able to regenerate nonces. - wvcdm::TestSleep::Sleep(2); + wvutil::TestSleep::Sleep(2); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); s.GenerateNonce(&error_counter); @@ -633,7 +702,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) { int request_counter = 0; int error_counter = 0; - const int64_t test_start = wvcdm::Clock().GetCurrentTime(); + const int64_t test_start = wvutil::Clock().GetCurrentTime(); // More than 200 nonces per second should generate an error. // To allow for some slop, we actually test for more. const int flood_cutoff = 200; @@ -647,7 +716,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) { s[j].GenerateNonce(&error_counter); } } - const int64_t test_end = wvcdm::Clock().GetCurrentTime(); + const int64_t test_end = wvutil::Clock().GetCurrentTime(); int valid_counter = request_counter - error_counter; // Either oemcrypto should enforce a delay, or it should return an error from // GenerateNonce -- in either case the number of valid nonces is rate @@ -656,7 +725,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) { EXPECT_LE(valid_counter, flood_cutoff * (test_end - test_start + 2)); error_counter = 0; // After a pause, we should be able to regenerate nonces. - wvcdm::TestSleep::Sleep(2); + wvutil::TestSleep::Sleep(2); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); s.GenerateNonce(&error_counter); @@ -673,36 +742,34 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) { vector output_buffer(kDataSize); OEMCrypto_DestBufferDesc dest_buffer_descriptor; dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size(); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size(); + ASSERT_EQ(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(input_buffer, output_buffer); - ASSERT_EQ( - OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer(s.session_id(), nullptr, input_buffer.size(), - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer( - s.session_id(), input_buffer.data(), input_buffer.size(), - nullptr, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - dest_buffer_descriptor.buffer.clear.address = nullptr; + CopyBuffer(s.session_id(), nullptr, input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ( OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size() - 1; - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + nullptr, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + dest_buffer_descriptor.buffer.clear.clear_buffer = nullptr; + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size() - 1; + ASSERT_NE(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); } // This verifies that CopyBuffer works on the maximum required buffer size. @@ -715,13 +782,13 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) { vector output_buffer(max_size); OEMCrypto_DestBufferDesc dest_buffer_descriptor; dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size(); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size(); + ASSERT_EQ(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(input_buffer, output_buffer); } @@ -743,7 +810,7 @@ TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForHugeBufferLengths) { return sts; } - dest_buffer_descriptor.buffer.secure.handle_length = buffer_length; + dest_buffer_descriptor.buffer.secure.secure_buffer_length = buffer_length; OEMCryptoResult status = OEMCrypto_CopyBuffer( s.session_id(), input_buffer.data(), buffer_length, &dest_buffer_descriptor, @@ -793,7 +860,7 @@ TEST_F(OEMCryptoClientTest, OEMCryptoMemoryCopyBufferForOutOfRangeOffset) { return; } - dest_buffer_descriptor.buffer.secure.handle_length = buffer_length; + dest_buffer_descriptor.buffer.secure.secure_buffer_length = buffer_length; auto oemcrypto_function = [&s, &dest_buffer_descriptor, &input_buffer, &buffer_length](size_t offset) { dest_buffer_descriptor.buffer.secure.offset = offset; @@ -825,7 +892,8 @@ TEST_F(OEMCryptoClientTest, return; } - dest_buffer_descriptor.buffer.secure.handle_length = kHugeInputBufferLength; + dest_buffer_descriptor.buffer.secure.secure_buffer_length = + kHugeInputBufferLength; ASSERT_NO_FATAL_FAILURE( OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), buffer_length, &dest_buffer_descriptor, @@ -844,11 +912,12 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestInvalidSubsampleFlag) { vector output_buffer(max_size); OEMCrypto_DestBufferDesc dest_buffer_descriptor; dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); - dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size(); - ASSERT_NO_FATAL_FAILURE(OEMCrypto_CopyBuffer( - s.session_id(), input_buffer.data(), input_buffer.size(), - &dest_buffer_descriptor, oemcrypto_invalid_subsample_flag)); + dest_buffer_descriptor.buffer.clear.clear_buffer = output_buffer.data(); + dest_buffer_descriptor.buffer.clear.clear_buffer_length = + output_buffer.size(); + ASSERT_NO_FATAL_FAILURE( + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, oemcrypto_invalid_subsample_flag)); } TEST_F(OEMCryptoClientTest, CanLoadTestKeys) { @@ -979,7 +1048,7 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } -TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForLargeIdLength) { +TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForHugeIdLength) { auto oemcrypto_function = [](size_t input_length) { size_t key_data_length = input_length; vector key_data(key_data_length); @@ -1020,7 +1089,7 @@ TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) { } TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryGenerateDerivedKeysForLargeMacContextLength) { + OEMCryptoMemoryGenerateDerivedKeysForHugeMacContextLength) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); vector mac_context; @@ -1038,7 +1107,7 @@ TEST_F(OEMCryptoKeyboxTest, } TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryGenerateDerivedKeysForLargeEncContextLength) { + OEMCryptoMemoryGenerateDerivedKeysForHugeEncContextLength) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); vector mac_context; @@ -1165,7 +1234,7 @@ TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) { ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); } -TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForLargeCertLength) { +TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { if (wrapped_rsa_key_.size() == 0) { // If we don't have a wrapped key yet, create one. // This wrapped key will be shared by all sessions in the test. @@ -1186,6 +1255,271 @@ TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForLargeCertLength) { TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } +// This class is for tests that have boot certificate chain instead of a keybox. +class OEMCryptoProv40Test : public OEMCryptoClientTest {}; + +// This verifies that the device really does claim to have BCC. +// It should be filtered out for devices that have a keybox or factory OEM cert. +TEST_F(OEMCryptoProv40Test, DeviceClaimsBootCertificateChain) { + ASSERT_EQ(OEMCrypto_GetProvisioningMethod(), OEMCrypto_BootCertificateChain); +} + +// Verifies that short buffer error returns when the buffer is short. +TEST_F(OEMCryptoProv40Test, GetBootCertificateChainShortBuffer) { + std::vector bcc; + size_t bcc_size = 0; + std::vector additional_signature; + size_t additional_signature_size = 0; + ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size, + additional_signature.data(), + &additional_signature_size), + OEMCrypto_ERROR_SHORT_BUFFER); + ASSERT_NE(bcc_size, 0uL); +} + +// Verifies BCC can be successfully returned. +TEST_F(OEMCryptoProv40Test, GetBootCertificateChainSuccess) { + std::vector bcc; + size_t bcc_size = 0; + std::vector additional_signature; + size_t additional_signature_size = 0; + ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size, + additional_signature.data(), + &additional_signature_size), + OEMCrypto_ERROR_SHORT_BUFFER); + + bcc.resize(bcc_size); + additional_signature.resize(additional_signature_size); + ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size, + additional_signature.data(), + &additional_signature_size), + OEMCrypto_SUCCESS); +} + +// Verifies that short buffer error returns when the buffer is short. +TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairShortBuffer) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + std::vector public_key; + size_t public_key_size = 0; + std::vector public_key_signature; + size_t public_key_signature_size = 0; + std::vector wrapped_private_key; + size_t wrapped_private_key_size = 0; + OEMCrypto_PrivateKeyType key_type; + + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_ERROR_SHORT_BUFFER); + + ASSERT_NE(public_key_size, 0uL); + ASSERT_NE(public_key_signature_size, 0uL); + ASSERT_NE(wrapped_private_key_size, 0uL); +} + +// Verifies a pair of key can be successfully returned. +TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairSuccess) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + std::vector public_key; + size_t public_key_size = 0; + std::vector public_key_signature; + size_t public_key_signature_size = 0; + std::vector wrapped_private_key; + size_t wrapped_private_key_size = 0; + OEMCrypto_PrivateKeyType key_type; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_ERROR_SHORT_BUFFER); + public_key.resize(public_key_size); + public_key_signature.resize(public_key_signature_size); + wrapped_private_key.resize(wrapped_private_key_size); + + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_SUCCESS); + // Parse the public key generated to make sure it is correctly formatted. + if (key_type == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) { + ASSERT_NO_FATAL_FAILURE( + s.SetRsaPublicKey(public_key.data(), public_key_size)); + } else if (key_type == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) { + ASSERT_NO_FATAL_FAILURE( + s.SetEcPublicKey(public_key.data(), public_key_size)); + } +} + +// Verifies the generated key pairs are different on each call. +TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairsAreDifferent) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + // Large buffer to make sure it is large enough. + size_t public_key_size1 = 10000; + std::vector public_key1(public_key_size1); + size_t public_key_signature_size1 = 10000; + std::vector public_key_signature1(public_key_signature_size1); + size_t wrapped_private_key_size1 = 10000; + std::vector wrapped_private_key1(wrapped_private_key_size1); + OEMCrypto_PrivateKeyType key_type1; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key1.data(), &public_key_size1, + public_key_signature1.data(), &public_key_signature_size1, + wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size1, 0UL); + EXPECT_NE(public_key_signature_size1, 0UL); + EXPECT_NE(wrapped_private_key_size1, 0UL); + public_key1.resize(public_key_size1); + public_key_signature1.resize(public_key_signature_size1); + wrapped_private_key1.resize(wrapped_private_key_size1); + + size_t public_key_size2 = 10000; + std::vector public_key2(public_key_size2); + size_t public_key_signature_size2 = 10000; + std::vector public_key_signature2(public_key_signature_size2); + size_t wrapped_private_key_size2 = 10000; + std::vector wrapped_private_key2(wrapped_private_key_size2); + OEMCrypto_PrivateKeyType key_type2; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key2.data(), &public_key_size2, + public_key_signature2.data(), &public_key_signature_size2, + wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size2, 0UL); + EXPECT_NE(public_key_signature_size2, 0UL); + EXPECT_NE(wrapped_private_key_size2, 0UL); + public_key2.resize(public_key_size2); + public_key_signature2.resize(public_key_signature_size2); + wrapped_private_key2.resize(wrapped_private_key_size2); + + EXPECT_NE(public_key1, public_key2); + EXPECT_NE(public_key_signature1, public_key_signature2); + EXPECT_NE(wrapped_private_key1, wrapped_private_key2); +} + +// Verifies the an OEM private key can be installed. +TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeySuccess) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + // First generate a key pair. + // Large buffer to make sure it is large enough. + size_t public_key_size = 10000; + std::vector public_key(public_key_size); + size_t public_key_signature_size = 10000; + std::vector public_key_signature(public_key_signature_size); + size_t wrapped_private_key_size = 10000; + std::vector wrapped_private_key(wrapped_private_key_size); + OEMCrypto_PrivateKeyType key_type; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key.data(), &public_key_size, + public_key_signature.data(), &public_key_signature_size, + wrapped_private_key.data(), &wrapped_private_key_size, &key_type), + OEMCrypto_SUCCESS); + public_key.resize(public_key_size); + public_key_signature.resize(public_key_signature_size); + wrapped_private_key.resize(wrapped_private_key_size); + + // Install the generated private key. + ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key_size), + OEMCrypto_SUCCESS); +} + +// If data is empty or random, the API should return non-success status. +TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyInvalidDataFail) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + + // Empty key fails. + std::vector wrapped_private_key; + OEMCrypto_PrivateKeyType key_type = OEMCrypto_RSA_Private_Key; + ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key.size()), + OEMCrypto_SUCCESS); + + // Random key data fails. + wrapped_private_key = {1, 2, 3}; + ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type, + wrapped_private_key.data(), + wrapped_private_key.size()), + OEMCrypto_SUCCESS); +} + +// Verifies the an OEM private key can be installed, and used by +// GenerateCertificateKeyPair call. +TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyCanBeUsed) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + // First generate a key pair. + size_t public_key_size1 = 10000; + std::vector public_key1(public_key_size1); + size_t public_key_signature_size1 = 10000; + std::vector public_key_signature1(public_key_signature_size1); + size_t wrapped_private_key_size1 = 10000; + std::vector wrapped_private_key1(wrapped_private_key_size1); + OEMCrypto_PrivateKeyType key_type1; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key1.data(), &public_key_size1, + public_key_signature1.data(), &public_key_signature_size1, + wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size1, 0UL); + EXPECT_NE(public_key_signature_size1, 0UL); + EXPECT_NE(wrapped_private_key_size1, 0UL); + public_key1.resize(public_key_size1); + public_key_signature1.resize(public_key_signature_size1); + wrapped_private_key1.resize(wrapped_private_key_size1); + + // Install the generated private key. + ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type1, + wrapped_private_key1.data(), + wrapped_private_key_size1), + OEMCrypto_SUCCESS); + + // Now calling GenerateCertificateKeyPair should use wrapped_private_key to + // sign the newly generated public key. + size_t public_key_size2 = 10000; + std::vector public_key2(public_key_size2); + size_t public_key_signature_size2 = 10000; + std::vector public_key_signature2(public_key_signature_size2); + size_t wrapped_private_key_size2 = 10000; + std::vector wrapped_private_key2(wrapped_private_key_size2); + OEMCrypto_PrivateKeyType key_type2; + ASSERT_EQ( + OEMCrypto_GenerateCertificateKeyPair( + s.session_id(), public_key2.data(), &public_key_size2, + public_key_signature2.data(), &public_key_signature_size2, + wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2), + OEMCrypto_SUCCESS); + EXPECT_NE(public_key_size2, 0UL); + EXPECT_NE(public_key_signature_size2, 0UL); + EXPECT_NE(wrapped_private_key_size2, 0UL); + public_key2.resize(public_key_size2); + public_key_signature2.resize(public_key_signature_size2); + wrapped_private_key2.resize(wrapped_private_key_size2); + + // Verify public_key_signature2 with public_key1. + ASSERT_NO_FATAL_FAILURE( + s.SetRsaPublicKey(public_key1.data(), public_key1.size())); + ASSERT_NO_FATAL_FAILURE( + s.VerifyRSASignature(public_key2, public_key_signature2.data(), + public_key_signature2.size(), kSign_RSASSA_PSS)); +} + // // AddKey Tests // @@ -1400,6 +1734,14 @@ class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { LoadLicense(); entitled_message_.FillKeyArray(); entitled_message_.EncryptContentKey(); + uint32_t key_session_id = 0; + OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id); + if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + return; + } + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + entitled_message_.SetEntitledKeySession(key_session_id); } void TearDown() override { OEMCryptoLicenseTestAPI16::TearDown(); } @@ -1408,7 +1750,7 @@ class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { EntitledMessage entitled_message_; size_t entitlement_response_length_; - void TestLoadEntitlementKeysForHugeBufferLengths( + void TestLoadEntitledKeysForHugeBufferLengths( const std::function f, bool check_status) { size_t entitled_key_data_size = entitled_message_.entitled_key_data_size(); @@ -1454,7 +1796,7 @@ class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, auto oemcrypto_function = [&](size_t message_length) { OEMCrypto_SelectKey( session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); size_t input_buffer_size = 1; vector in_buffer(input_buffer_size + message_length); @@ -1507,7 +1849,7 @@ class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16, LoadLicense(); OEMCrypto_SelectKey( session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); vector in_buffer(256); vector out_buffer(in_buffer.size()); @@ -1594,8 +1936,9 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNoRequest) { // Notice that we do not call SignAndVerifyRequest -- we do not need a request // in order to generate a response for a preloaded license. // The test code uses the core request to create the core response. - license_messages_.core_request().api_major_version = ODK_MAJOR_VERSION; - license_messages_.core_request().api_minor_version = ODK_MINOR_VERSION; + license_messages_.core_request().api_major_version = + global_features.api_version; + license_messages_.core_request().api_minor_version = 0; ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); @@ -1666,51 +2009,201 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonceTwiceAPI16) { ASSERT_EQ(OEMCrypto_ERROR_LICENSE_RELOAD, license_messages_.LoadResponse()); } +class OEMCryptoEntitlementLicenseTest : public OEMCryptoLicenseTest { + protected: + void LoadEntitlementLicense() { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + } +}; + // This verifies that entitlement keys and entitled content keys can be loaded. -TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysAPI14) { - license_messages_.set_license_type(OEMCrypto_EntitlementLicense); - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); +TEST_P(OEMCryptoEntitlementLicenseTest, LoadEntitlementKeysAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(OEMCrypto_SUCCESS)); EntitledMessage entitled_message_2(&license_messages_); entitled_message_2.FillKeyArray(); + entitled_message_2.SetEntitledKeySession(key_session_id); ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadKeys(OEMCrypto_SUCCESS)); } +TEST_P(OEMCryptoEntitlementLicenseTest, CasOnlyLoadCasKeysAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/true, OEMCrypto_SUCCESS)); + EntitledMessage entitled_message_2(&license_messages_); + entitled_message_2.FillKeyArray(); + entitled_message_2.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/false, OEMCrypto_SUCCESS)); + EntitledMessage entitled_message_3(&license_messages_); + entitled_message_3.FillKeyArray(); + entitled_message_3.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_3.LoadCasKeys( + /*load_even=*/false, /*load_odd=*/true, OEMCrypto_SUCCESS)); + ASSERT_NO_FATAL_FAILURE(entitled_message_3.LoadCasKeys( + /*load_even=*/false, /*load_odd=*/false, OEMCrypto_SUCCESS)); +} + // This verifies that entitled content keys cannot be loaded if we have not yet // loaded the entitlement keys. -TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysNoEntitlementKeysAPI14) { +TEST_P(OEMCryptoEntitlementLicenseTest, + LoadEntitlementKeysNoEntitlementKeysAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); ASSERT_NO_FATAL_FAILURE( entitled_message_1.LoadKeys(OEMCrypto_ERROR_INVALID_CONTEXT)); } -// This verifies that entitled content keys cannot be loaded if we have loaded -// the wrong entitlement keys. -TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysWrongEntitlementKeysAPI14) { +TEST_P(OEMCryptoEntitlementLicenseTest, + CasOnlyLoadCasKeysNoEntitlementKeysAPI17) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/true, OEMCrypto_ERROR_INVALID_CONTEXT)); +} + +// This verifies that entitled content keys cannot be loaded if we have loaded +// the wrong entitlement keys. +TEST_P(OEMCryptoEntitlementLicenseTest, + LoadEntitlementKeysWrongEntitlementKeysAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + EntitledMessage entitled_message_1(&license_messages_); entitled_message_1.FillKeyArray(); const std::string key_id = "no_key"; entitled_message_1.SetEntitlementKeyId(0, key_id); - + entitled_message_1.SetEntitledKeySession(key_session_id); ASSERT_NO_FATAL_FAILURE( entitled_message_1.LoadKeys(OEMCrypto_KEY_NOT_ENTITLED)); } +TEST_P(OEMCryptoEntitlementLicenseTest, + CasOnlyLoadCasKeysWrongEntitlementKeysAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + const std::string key_id = "no_key"; + entitled_message_1.SetEntitlementKeyId(0, key_id); + entitled_message_1.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/true, OEMCrypto_KEY_NOT_ENTITLED)); +} + +// This verifies that entitled content keys cannot be loaded if we specify an +// entitled key session that has not been created. +TEST_P(OEMCryptoEntitlementLicenseTest, + LoadEntitlementKeysWrongEntitledKeySessionAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(0); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys( + OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION)); +} + +TEST_P(OEMCryptoEntitlementLicenseTest, + CasOnlyLoadCasKeysWrongEntitledKeySessionAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(0); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/true, + OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION)); +} + +// This verifies that entitled content keys cannot be loaded if we specify an +// entitled key session that is actually an oemcrypto session. +TEST_P(OEMCryptoEntitlementLicenseTest, + LoadEntitlementKeysOemcryptoSessionAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(session_.session_id()); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys( + OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION)); +} + +TEST_P(OEMCryptoEntitlementLicenseTest, + CasOnlyLoadCasKeysOemcryptoSessionAPI17) { + LoadEntitlementLicense(); + uint32_t key_session_id = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + ASSERT_NE(key_session_id, 0u); + + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(session_.session_id()); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/true, + OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION)); +} + TEST_F(OEMCryptoMemoryLicenseTest, OEMCryptoMemoryPrepareRenewalRequestForHugeBufferLength) { RenewalRoundTrip renewal_messages(&license_messages_); @@ -1742,8 +2235,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_id.length = key_id_length; @@ -1752,8 +2245,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_id.offset = key_id_offset; @@ -1763,7 +2256,7 @@ TEST_F(OEMCryptoMemoryLicenseTest, TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdLength) { auto& content_key_id = entitled_message_.entitled_key_array()[0].content_key_id; content_key_id.length = @@ -1773,7 +2266,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdOffset) { auto& content_key_id = entitled_message_.entitled_key_array()[0].content_key_id; content_key_id.offset = @@ -1781,10 +2274,9 @@ TEST_F( ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].entitlement_key_id.length = key_id_length; @@ -1792,10 +2284,9 @@ TEST_F( !kCheckStatus); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].entitlement_key_id.offset = key_id_offset; @@ -1805,7 +2296,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdLength) { auto& entitlement_key_id = entitled_message_.entitled_key_array()[0].entitlement_key_id; entitlement_key_id.length = @@ -1815,7 +2306,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { auto& entitlement_key_id = entitled_message_.entitled_key_array()[0].entitlement_key_id; entitlement_key_id.offset = @@ -1823,10 +2314,9 @@ TEST_F( ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvLength) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_iv_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data_iv.length = content_key_data_iv_length; @@ -1834,10 +2324,9 @@ TEST_F( !kCheckStatus); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_iv_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data_iv.offset = content_key_data_iv_offset; @@ -1847,7 +2336,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvLength) { auto& content_key_data_iv = entitled_message_.entitled_key_array()[0].content_key_data_iv; content_key_data_iv.length = @@ -1857,7 +2346,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvOffset) { auto& content_key_data_iv = entitled_message_.entitled_key_array()[0].content_key_data_iv; content_key_data_iv.offset = @@ -1866,8 +2355,8 @@ TEST_F( } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data.length = content_key_data_length; @@ -1876,8 +2365,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data.offset = content_key_data_offset; @@ -1887,7 +2376,7 @@ TEST_F(OEMCryptoMemoryLicenseTest, TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataLength) { auto& content_key_data = entitled_message_.entitled_key_array()[0].content_key_data; content_key_data.length = @@ -1897,7 +2386,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataOffset) { auto& content_key_data = entitled_message_.entitled_key_array()[0].content_key_data; content_key_data.offset = @@ -1906,8 +2395,8 @@ TEST_F( } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeEntitlementKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_data()->entitlement_key_id_length = key_id_length; @@ -1916,8 +2405,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeContentKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_data()->content_key_id_length = key_id_length; @@ -1928,7 +2417,7 @@ TEST_F(OEMCryptoMemoryLicenseTest, // This verifies that entitled content keys API does not crash for unreasonable // input message buffer lengths. TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeBufferLength) { + OEMCryptoMemoryLoadEntitledKeysForHugeBufferLength) { auto oemcrypto_function = [&](size_t buffer_length) { size_t entitled_key_data_length = entitled_message_.entitled_key_data_size(); @@ -2097,16 +2586,6 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNullKeyControl) { ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); } -// Test that LoadKeys fails when the key control block encryption has a null IV. -TEST_P(OEMCryptoLicenseTest, LoadKeyWithNullKeyControlIv) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.core_response().key_array[2].key_control_iv.offset = 0; - license_messages_.core_response().key_array[2].key_control_iv.length = 0; - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} - // Verify that LoadKeys fails when a key's nonce is wrong. TEST_P(OEMCryptoLicenseTest, LoadKeyWithBadNonce) { ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -2295,8 +2774,8 @@ TEST_P(OEMCryptoLicenseTestRangeAPI, LoadKeys) { // Range of API versions to test. This should start several versions old, and // go to the current API + 2. We use +2 because we want to test at least 1 // future API, and the ::testing::Range is not inclusive. -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoLicenseTestRangeAPI, - Range(10, kCurrentAPI + 2)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTestRangeAPI, + Range(10, kCurrentAPI + 2)); TEST_P(OEMCryptoLicenseTest, LoadKeysBadSignatureAPI16) { ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -2306,14 +2785,6 @@ TEST_P(OEMCryptoLicenseTest, LoadKeysBadSignatureAPI16) { ASSERT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, license_messages_.LoadResponse()); } - -TEST_F(OEMCryptoLicenseTestAPI16, BadCoreHashAPI16) { - ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); - ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); - license_messages_.BreakRequestHash(); - ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); -} /// @} /// @addtogroup decrypt @@ -2358,7 +2829,7 @@ TEST_P(OEMCryptoLicenseTest, LoadLicense(); OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[0].key_id, session_.license().keys[0].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); size_t input_buffer_size = 1; vector in_buffer(input_buffer_size); @@ -2376,7 +2847,7 @@ TEST_P(OEMCryptoLicenseTest, // addition operation. This will result in 1 which will match with input data // length, which causes validation to pass. sub_samples[0].num_bytes_clear = 2; - sub_samples[0].num_bytes_encrypted = 0xFFFFFFFFFFFFFFFF; + sub_samples[0].num_bytes_encrypted = ~0; // Create the pattern description (always 0,0 for CTR) OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; @@ -2449,12 +2920,22 @@ TEST_P(OEMCryptoLicenseTest, OEMCrypto_BufferType_Secure; sample_description->buffers.output_descriptor.buffer.secure.offset = sample_description->buffers.output_descriptor.buffer.secure - .handle_length + + .secure_buffer_length + 1; }, kDecryptCENCSecureBuffer); } +// Cannot decrypt without first selecting a key. +TEST_P(OEMCryptoLicenseTest, FailDecryptWithoutSelect) { + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); +} + // SelectKey should fail if we attempt to select a key that has not been loaded. // Also, the error should be NO_CONTENT_KEY. // This test should pass for v15 devices, except that the exact error code was @@ -2468,7 +2949,7 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyNotThereAPI16) { const char* key_id = "no_key"; OEMCryptoResult sts = OEMCrypto_SelectKey( session_.session_id(), reinterpret_cast(key_id), - strlen(key_id), OEMCrypto_CipherMode_CTR); + strlen(key_id), OEMCrypto_CipherMode_CENC); if (sts != OEMCrypto_SUCCESS) { EXPECT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, sts); } else { @@ -2495,6 +2976,289 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyNotThereAPI16) { } } +TEST_P(OEMCryptoLicenseTest, SelectKeyEntitledKeyAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); + const char* content_key_id = "content_key_id"; + entitled_message_1.SetContentKeyId(0, content_key_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(OEMCrypto_SUCCESS)); + + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(key_session_id, + reinterpret_cast(content_key_id), + strlen(content_key_id), OEMCrypto_CipherMode_CENC)); +} + +// SelectEntitledKey should fail if we attempt to select a key that has not been +// loaded. Also, the error should be NO_CONTENT_KEY. +TEST_P(OEMCryptoLicenseTest, SelectKeyEntitledKeyNotThereAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(OEMCrypto_SUCCESS)); + + const char* content_key_id = "no_key"; + ASSERT_EQ( + OEMCrypto_ERROR_NO_CONTENT_KEY, + OEMCrypto_SelectKey(key_session_id, + reinterpret_cast(content_key_id), + strlen(content_key_id), OEMCrypto_CipherMode_CENC)); +} + +// Select key with entitlement license fails if the key id is entitilement key +// id. +TEST_P(OEMCryptoLicenseTest, SelectKeyEntitlementKeyAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(OEMCrypto_SUCCESS)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + OEMCrypto_SelectKey(session_.session_id(), + session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, + OEMCrypto_CipherMode_CENC)); +} + +// This verifies that entitled key sessions can be created and removed. +TEST_P(OEMCryptoLicenseTest, EntitledKeySessionsAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id_1; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_1)); + ASSERT_NE(key_session_id_1, 0u); // 0 is a reserved id number. + + uint32_t key_session_id_2; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_2)); + ASSERT_NE(key_session_id_2, 0u); // 0 is a reserved id number. + // Entitled key sessions should have unique ids. + ASSERT_NE(key_session_id_1, key_session_id_2); + + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_RemoveEntitledKeySession(key_session_id_1)); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_RemoveEntitledKeySession(key_session_id_2)); +} + +// This verifies that multiple entitled key sessions can be created. They can +// load and select keys independently. +TEST_P(OEMCryptoLicenseTest, EntitledKeySessionMultipleKeySessionsAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id_1; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_1)); + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id_1); + const char* content_key_id_1 = "content_key_id_1"; + entitled_message_1.SetContentKeyId(0, content_key_id_1); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(OEMCrypto_SUCCESS)); + // We can select content key 1 in entitled key session 1. + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(key_session_id_1, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + // Create another entitled key session. + uint32_t key_session_id_2; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id_2)); + // Entitled key sessions should have unique ids. + ASSERT_NE(key_session_id_1, key_session_id_2); + + EntitledMessage entitled_message_2(&license_messages_); + entitled_message_2.FillKeyArray(); + entitled_message_2.SetEntitledKeySession(key_session_id_2); + const char* content_key_id_2 = "content_key_id_2"; + entitled_message_2.SetContentKeyId(0, content_key_id_2); + ASSERT_NO_FATAL_FAILURE(entitled_message_2.LoadKeys(OEMCrypto_SUCCESS)); + // We can select content key 2 in entitled key session 2. + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(key_session_id_2, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + // Content key id 1 is not in entitled key session 2. + ASSERT_EQ( + OEMCrypto_ERROR_NO_CONTENT_KEY, + OEMCrypto_SelectKey(key_session_id_2, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + // Content key id 2 is not in entitled key session 1. + ASSERT_EQ( + OEMCrypto_ERROR_NO_CONTENT_KEY, + OEMCrypto_SelectKey(key_session_id_1, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); +} + +// This verifies that within an entitled key session, each entitlement key can +// corresponds to only one content key at most. +TEST_P(OEMCryptoLicenseTest, + EntitledKeySessionOneContentKeyPerEntitlementAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + // Construct and load content keys to entitled key session. + EntitledMessage entitled_message_1(&license_messages_); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); + const char* content_key_id_1 = "content_key_id_1"; + entitled_message_1.SetContentKeyId(0, content_key_id_1); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(OEMCrypto_SUCCESS)); + // We can select content key 1 in entitled key session. + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(key_session_id, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); + // Load content key with new content id. + const char* content_key_id_2 = "content_key_id_2"; + entitled_message_1.SetContentKeyId(0, content_key_id_2); + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadKeys(OEMCrypto_SUCCESS)); + // We can select content key 2 in entitled key session. + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(key_session_id, + reinterpret_cast(content_key_id_2), + strlen(content_key_id_2), OEMCrypto_CipherMode_CENC)); + // Content key one is no longer in the entitled key session as they use the + // same entitlement key. + ASSERT_EQ( + OEMCrypto_ERROR_NO_CONTENT_KEY, + OEMCrypto_SelectKey(key_session_id, + reinterpret_cast(content_key_id_1), + strlen(content_key_id_1), OEMCrypto_CipherMode_CENC)); +} + +// Decrypt should fail if the license is entitlement license, and the decrypt +// call is made with oemcrypto session id (should use entitled key session id +// instead). +TEST_P(OEMCryptoLicenseTest, + RejectOecSessionDecryptWithEntitlementLicenseAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + + uint32_t key_session_id; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id)); + // Construct and load content keys to entitled key session. + EntitledMessage entitled_message(&license_messages_); + entitled_message.FillKeyArray(); + entitled_message.SetEntitledKeySession(key_session_id); + const char* content_key_id = "content_key_id"; + entitled_message.SetContentKeyId(0, content_key_id); + ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(OEMCrypto_SUCCESS)); + ASSERT_EQ( + OEMCrypto_SUCCESS, + OEMCrypto_SelectKey(key_session_id, + reinterpret_cast(content_key_id), + strlen(content_key_id), OEMCrypto_CipherMode_CENC)); + + vector in_buffer(256); + vector out_buffer(in_buffer.size()); + OEMCrypto_SampleDescription sample_description; + OEMCrypto_SubSampleDescription subsample_description; + ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( + in_buffer, out_buffer, &sample_description, &subsample_description)); + OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; + + // Try to decrypt the data with oemcrypto session id. + EXPECT_EQ(OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern), + OEMCrypto_ERROR_INVALID_CONTEXT); + // Decrypt the data with entitled key session id succeed. + EXPECT_EQ( + OEMCrypto_DecryptCENC(key_session_id, &sample_description, 1, &pattern), + OEMCrypto_SUCCESS); +} + +// This verifies that an entitled key session can be reassociated to an +// OEMCrypto session. +TEST_P(OEMCryptoLicenseTest, ReassociateEntitledKeySessionAPI17) { + license_messages_.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + // Setup another session. + Session session2; + ASSERT_NO_FATAL_FAILURE(session2.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session2)); + ASSERT_NO_FATAL_FAILURE(session2.GenerateDerivedKeysFromSessionKey()); + // Setup an entitled key session in the first OEMCrypto session. + uint32_t key_session_id; + OEMCryptoResult sts = OEMCrypto_CreateEntitledKeySession( + session_.session_id(), &key_session_id); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + EntitledMessage entitled_message(&license_messages_); + entitled_message.FillKeyArray(); + entitled_message.SetEntitledKeySession(key_session_id); + ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(OEMCrypto_SUCCESS)); + + // Now reassociate the entitled key session to the second OEMCrypto session. + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_ReassociateEntitledKeySession( + key_session_id, session2.session_id())); + // session2 does not have entitlement keys. + ASSERT_NO_FATAL_FAILURE( + entitled_message.LoadKeys(OEMCrypto_ERROR_INVALID_CONTEXT)); + + // Now reassociate the entitled key session back to the first OEMCrypto + // session. + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_ReassociateEntitledKeySession( + key_session_id, session_.session_id())); + ASSERT_NO_FATAL_FAILURE(entitled_message.LoadKeys(OEMCrypto_SUCCESS)); +} + // 'cens' mode is no longer supported in v16 TEST_P(OEMCryptoLicenseTest, RejectCensAPI16) { ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -2505,7 +3269,7 @@ TEST_P(OEMCryptoLicenseTest, RejectCensAPI16) { OEMCryptoResult sts; sts = OEMCrypto_SelectKey( session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector in_buffer(256); @@ -2535,7 +3299,7 @@ TEST_P(OEMCryptoLicenseTest, RejectCbc1API16) { OEMCryptoResult sts; sts = OEMCrypto_SelectKey( session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBC); + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBCS); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector in_buffer(256); @@ -2564,7 +3328,7 @@ TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) { OEMCryptoResult sts; sts = OEMCrypto_SelectKey( session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBC); + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBCS); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector in_buffer(256); @@ -2594,7 +3358,7 @@ TEST_P(OEMCryptoLicenseTest, RejectOversizedBlockOffset) { OEMCryptoResult sts; sts = OEMCrypto_SelectKey( session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector in_buffer(256); @@ -3187,7 +3951,7 @@ TEST_P(OEMCryptoLicenseTest, AntiRollbackHardwareRequired) { TEST_P(OEMCryptoLicenseTest, MinimumKeys) { const size_t num_keys = GetResourceValue(kMaxKeysPerSession); ASSERT_LE(num_keys, kMaxNumKeys) << "Test constants need updating."; - license_messages_.set_num_keys(num_keys); + license_messages_.set_num_keys(static_cast(num_keys)); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); @@ -3214,7 +3978,7 @@ void TestMaxKeys(SessionUtil* util, size_t num_keys_per_session) { new LicenseRoundTrip(sessions[i].get()))); const size_t num_keys = std::min(max_total_keys - total_keys, num_keys_per_session); - licenses[i]->set_num_keys(num_keys); + licenses[i]->set_num_keys(static_cast(num_keys)); total_keys += num_keys; ASSERT_NO_FATAL_FAILURE(sessions[i]->open()); ASSERT_NO_FATAL_FAILURE(util->InstallTestRSAKey(sessions[i].get())); @@ -3328,7 +4092,8 @@ class OEMCryptoSessionTestDecryptWithHDCP : public OEMCryptoSessionTests, ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); - if (version > current) { + if (((version <= HDCP_V2_3 || current >= HDCP_V1_0) && version > current) || + (current == HDCP_V1 && version >= HDCP_V1_0)) { if (global_features.api_version >= 16) { // Can provide either OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION or // OEMCrypto_ERROR_INSUFFICIENT_HDCP. TestDecryptCTR allows either to be @@ -3358,9 +4123,63 @@ TEST_P(OEMCryptoSessionTestDecryptWithHDCP, DecryptAPI09) { // Test parameterized by HDCP version. DecryptWithHDCP(static_cast(GetParam())); } -INSTANTIATE_TEST_CASE_P(TestHDCP, OEMCryptoSessionTestDecryptWithHDCP, - Range(1, 6)); +INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestDecryptWithHDCP, + Range(1, 6)); +// Used to test the different HDCP versions. This test is parameterized by the +// required HDCP version in the key control block. +class OEMCryptoSessionTestLoadCasKeysWithHDCP : public OEMCryptoSessionTests, + public WithParamInterface { + protected: + void LoadCasKeysWithHDCP(OEMCrypto_HDCP_Capability version) { + OEMCryptoResult sts; + OEMCrypto_HDCP_Capability current, maximum; + sts = OEMCrypto_GetHDCPCapability(¤t, &maximum); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); + LicenseRoundTrip license_messages(&s); + license_messages.set_control((version << wvoec::kControlHDCPVersionShift) | + wvoec::kControlObserveHDCP | + wvoec::kControlHDCPRequired); + license_messages.set_license_type(OEMCrypto_EntitlementLicense); + ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); + + uint32_t key_session_id; + sts = OEMCrypto_CreateEntitledKeySession(s.session_id(), &key_session_id); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + EntitledMessage entitled_message_1(&license_messages); + entitled_message_1.FillKeyArray(); + entitled_message_1.SetEntitledKeySession(key_session_id); + + if (((version <= HDCP_V2_3 || current >= HDCP_V1_0) && version > current) || + (current == HDCP_V1 && version >= HDCP_V1_0)) { + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/true, + OEMCrypto_ERROR_INSUFFICIENT_HDCP)) + << "Failed when current HDCP = " << HDCPCapabilityAsString(current) + << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) + << ", license HDCP = " << HDCPCapabilityAsString(version); + } else { + ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys( + /*load_even=*/true, /*load_odd=*/true, OEMCrypto_SUCCESS)) + << "Failed when current HDCP = " << HDCPCapabilityAsString(current) + << ", maximum HDCP = " << HDCPCapabilityAsString(maximum) + << ", license HDCP = " << HDCPCapabilityAsString(version); + } + } +}; + +TEST_P(OEMCryptoSessionTestLoadCasKeysWithHDCP, CasOnlyLoadCasKeysAPI17) { + // Test parameterized by HDCP version. + LoadCasKeysWithHDCP(static_cast(GetParam())); +} +INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestLoadCasKeysWithHDCP, + Range(1, 6)); /// @} /// @addtogroup renewal @@ -3494,13 +4313,13 @@ TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) { // This should still be valid key, even if the refresh failed, because this // is before the original license duration. - wvcdm::TestSleep::Sleep(kShortSleep); + wvutil::TestSleep::Sleep(kShortSleep); ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false)); // This should be after duration of the original license, but before the // expiration of the refresh message. This should fail until we have loaded // the renewal. - wvcdm::TestSleep::Sleep(kShortSleep + kLongSleep); + wvutil::TestSleep::Sleep(kShortSleep + kLongSleep); ASSERT_NO_FATAL_FAILURE( session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); @@ -3512,12 +4331,12 @@ TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) { ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false)); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoRefreshTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); // These tests only work when the license has a core message. -INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoRefreshTestAPI16, - Range(kCoreMessagesAPI, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoRefreshTestAPI16, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); // If the license does not allow a hash, then we should not compute one. TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { @@ -3547,7 +4366,7 @@ TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { // This test verifies that OEMCrypto_SetDecryptHash doesn't crash for a very // large hash buffer. TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryDecryptHashForLargeHashBuffer) { + OEMCryptoMemoryDecryptHashForHugeHashBuffer) { uint32_t session_id = session_.session_id(); auto f = [session_id](size_t hash_length) { uint32_t frame_number = 1; @@ -3670,7 +4489,7 @@ class OEMCryptoSessionTestsDecryptTests // Update the rolling variables sample_size += size.clear_size + size.encrypted_size; - if (cipher_mode_ == OEMCrypto_CipherMode_CTR) { + if (cipher_mode_ == OEMCrypto_CipherMode_CENC) { current_block_offset = (current_block_offset + size.encrypted_size) % AES_BLOCK_SIZE; } @@ -3709,27 +4528,29 @@ class OEMCryptoSessionTestsDecryptTests // Add some padding to verify there is no overrun. sample.encrypted_buffer.resize(total_size + kBufferOverrunPadding, 0xaa); - output_descriptor.buffer.clear.address = + output_descriptor.buffer.clear.clear_buffer = sample.encrypted_buffer.data(); } else { // Add some padding to verify there is no overrun. sample.clear_buffer.resize(total_size + kBufferOverrunPadding, 0xaa); - output_descriptor.buffer.clear.address = sample.clear_buffer.data(); + output_descriptor.buffer.clear.clear_buffer = + sample.clear_buffer.data(); } - output_descriptor.buffer.clear.address_length = total_size; + output_descriptor.buffer.clear.clear_buffer_length = total_size; break; case OEMCrypto_BufferType_Secure: - output_descriptor.buffer.secure.handle_length = total_size; + output_descriptor.buffer.secure.secure_buffer_length = total_size; ASSERT_EQ(OEMCrypto_AllocateSecureBuffer( session_.session_id(), total_size, &output_descriptor, &sample.secure_buffer_fid), OEMCrypto_SUCCESS); - ASSERT_NE(output_descriptor.buffer.secure.handle, nullptr); + ASSERT_NE(output_descriptor.buffer.secure.secure_buffer, nullptr); // It is OK if OEMCrypto changes the maximum size, but there must // still be enough room for our data. - ASSERT_GE(output_descriptor.buffer.secure.handle_length, total_size); + ASSERT_GE(output_descriptor.buffer.secure.secure_buffer_length, + total_size); output_descriptor.buffer.secure.offset = 0; break; @@ -3774,7 +4595,7 @@ class OEMCryptoSessionTestsDecryptTests } // The IV resets at the start of each subsample in the 'cbcs' schema. - if (cipher_mode_ == OEMCrypto_CipherMode_CBC) { + if (cipher_mode_ == OEMCrypto_CipherMode_CBCS) { memcpy(iv, initial_iv_, KEY_IV_SIZE); } @@ -3793,13 +4614,13 @@ class OEMCryptoSessionTestsDecryptTests // CBC mode should just copy a partial block at the end. If there // is a partial block at the beginning, an error is returned, so we // can put whatever we want in the output buffer. - if (skip_block || ((cipher_mode_ == OEMCrypto_CipherMode_CBC) && + if (skip_block || ((cipher_mode_ == OEMCrypto_CipherMode_CBCS) && (size < AES_BLOCK_SIZE))) { memcpy(&sample.encrypted_buffer[buffer_index], &sample.truth_buffer[buffer_index], size); block_offset = 0; // Next block should be complete. } else { - if (cipher_mode_ == OEMCrypto_CipherMode_CTR) { + if (cipher_mode_ == OEMCrypto_CipherMode_CENC) { uint8_t aes_output[AES_BLOCK_SIZE]; AES_encrypt(iv, aes_output, &aes_key); for (size_t n = 0; n < size; n++) { @@ -4063,7 +4884,8 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, OddOffset) { // If you start with an IV of 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, after you // increment twice, you should get 0xFFFFFFFFFFFFFFFF0000000000000000. TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptWithNearWrap) { - memcpy(initial_iv_, wvcdm::a2b_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE").data(), + memcpy(initial_iv_, + wvutil::a2b_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE").data(), KEY_IV_SIZE); ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ {0, 256}, @@ -4303,19 +5125,55 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, MultipleSamples) { ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); } +// This tests that calling OEMCrypto_Idle and OEMCrypto_Wake once or multiple +// times doesn't break anything. +TEST_P(OEMCryptoSessionTestsDecryptTests, IdleAndWake) { + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); +} + +// This tests that after an idle and a wake, decryption can continue in an +// open session. +TEST_P(OEMCryptoSessionTestsDecryptTests, ContinueDecryptionAfterIdleAndWake) { + // This subsample size is larger than a few encrypt/skip patterns. Most + // test cases use a pattern length of 160, so we'll run through at least two + // full patterns if we have more than 320 -- round up to 400. + ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ + {0, 400}, + })); + ASSERT_NO_FATAL_FAILURE(LoadLicense()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); + // Set state to idle then wake again and try to reencrypt/decrypt + ASSERT_NO_FATAL_FAILURE( + OEMCrypto_Idle(OEMCrypto_IdleState::OEMCrypto_CpuSuspend, 0)); + ASSERT_NO_FATAL_FAILURE(OEMCrypto_Wake()); + ASSERT_NO_FATAL_FAILURE(MakeBuffers()); + ASSERT_NO_FATAL_FAILURE(EncryptData()); + ASSERT_NO_FATAL_FAILURE(TestDecryptCENC()); +} + // Used to construct a specific pattern. constexpr OEMCrypto_CENCEncryptPatternDesc MakePattern(size_t encrypt, size_t skip) { return {encrypt, skip}; } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CTRTests, OEMCryptoSessionTestsDecryptTests, - Combine(Values(MakePattern(0, 0)), Values(OEMCrypto_CipherMode_CTR), + Combine(Values(MakePattern(0, 0)), Values(OEMCrypto_CipherMode_CENC), ::testing::ValuesIn(global_features.GetOutputTypes()))); // Decrypt in place for CBC tests was only required in v13. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CBCTestsAPI14, OEMCryptoSessionTestsDecryptTests, Combine( Values(MakePattern(3, 7), MakePattern(9, 1), @@ -4323,7 +5181,7 @@ INSTANTIATE_TEST_CASE_P( MakePattern(1, 9), MakePattern(1, 0), // AV1 patterns not already covered above. MakePattern(5, 5), MakePattern(10, 0)), - Values(OEMCrypto_CipherMode_CBC), + Values(OEMCrypto_CipherMode_CBCS), ::testing::ValuesIn(global_features.GetOutputTypes()))); // A request to decrypt data to a clear buffer when the key control block @@ -4349,16 +5207,16 @@ TEST_P(OEMCryptoLicenseTest, KeyDuration) { ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(true, OEMCrypto_SUCCESS)); - wvcdm::TestSleep::Sleep(kShortSleep); // Should still be valid key. + wvutil::TestSleep::Sleep(kShortSleep); // Should still be valid key. ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false, OEMCrypto_SUCCESS)); - wvcdm::TestSleep::Sleep(kLongSleep); // Should be expired key. + wvutil::TestSleep::Sleep(kLongSleep); // Should be expired key. ASSERT_NO_FATAL_FAILURE( session_.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(0)); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoLicenseTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); // // Certificate Root of Trust Tests @@ -5075,8 +5933,11 @@ class OEMCryptoUsesCertificate : public OEMCryptoLoadsCertificate { void SetUp() override { OEMCryptoLoadsCertificate::SetUp(); ASSERT_NO_FATAL_FAILURE(session_.open()); - if (global_features.derive_key_method != + if (global_features.derive_key_method == DeviceFeatures::LOAD_TEST_RSA_KEY) { + ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey( + encoded_rsa_key_.data(), encoded_rsa_key_.size())); + } else { InstallTestRSAKey(&session_); } } @@ -5095,7 +5956,7 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { const std::chrono::milliseconds kTestDuration(5000); OEMCryptoResult sts; std::chrono::steady_clock clock; - wvcdm::TestSleep::Sleep(kShortSleep); // Make sure we are not nonce limited. + wvutil::TestSleep::Sleep(kShortSleep); // Make sure we are not nonce limited. auto start_time = clock.now(); int count = 15; @@ -5126,6 +5987,21 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { &signature_length, kSign_RSASSA_PSS); ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_NE(static_cast(0), signature_length); + + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generate_rsa_signature_fuzz_seed_corpus"); + OEMCrypto_Generate_RSA_Signature_Fuzz fuzzed_structure; + fuzzed_structure.padding_scheme = kSign_RSASSA_PSS; + fuzzed_structure.signature_length = signature_length; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, + reinterpret_cast(licenseRequest.data()), + licenseRequest.size()); + } + uint8_t* signature = new uint8_t[signature_length]; sts = OEMCrypto_GenerateRSASignature(s.session_id(), licenseRequest.data(), licenseRequest.size(), signature, @@ -5153,7 +6029,7 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { vector enc_context; s.FillDefaultContext(&mac_context, &enc_context); - enc_session_key = wvcdm::a2b_hex( + enc_session_key = wvutil::a2b_hex( "7789c619aa3b9fa3c0a53f57a4abc6" "02157c8aa57e3c6fb450b0bea22667fb" "0c3200f9d9d618e397837c720dc2dadf" @@ -5184,18 +6060,17 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { const double derive_keys_time = delta_time / std::chrono::milliseconds(1) / count; - const char* level = OEMCrypto_SecurityLevel(); + OEMCrypto_Security_Level level = OEMCrypto_SecurityLevel(); printf("PERF:head, security, provision (ms), lic req(ms), derive keys(ms)\n"); - printf("PERF:stat, %s, %8.3f, %8.3f, %8.3f\n", level, provision_time, - license_request_time, derive_keys_time); + printf("PERF:stat, %u, %8.3f, %8.3f, %8.3f\n", + static_cast(level), provision_time, license_request_time, + derive_keys_time); } // Test DeriveKeysFromSessionKey using the maximum size for the HMAC context. TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) { vector session_key; vector enc_session_key; - ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), - encoded_rsa_key_.size())); ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key)); const size_t max_size = GetResourceValue(kLargeMessageSize); vector mac_context(max_size); @@ -5216,8 +6091,6 @@ TEST_F(OEMCryptoUsesCertificate, OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeMacContext) { vector session_key; vector enc_session_key; - ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), - encoded_rsa_key_.size())); ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key)); vector mac_context; vector enc_context; @@ -5238,8 +6111,6 @@ TEST_F(OEMCryptoUsesCertificate, OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncContext) { vector session_key; vector enc_session_key; - ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), - encoded_rsa_key_.size())); ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key)); vector mac_context; vector enc_context; @@ -5260,8 +6131,6 @@ TEST_F(OEMCryptoUsesCertificate, OEMCryptoMemoryDeriveKeysFromSessionKeyForHugeEncSessionKey) { vector session_key; vector enc_session_key; - ASSERT_NO_FATAL_FAILURE(session_.PreparePublicKey(encoded_rsa_key_.data(), - encoded_rsa_key_.size())); ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key)); vector mac_context; vector enc_context; @@ -5394,11 +6263,11 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { } } - bool key_loaded_; + bool key_loaded_ = false; }; TEST_F(OEMCryptoLoadsCertificateAlternates, - OEMCryptoMemoryGenerateRSASignatureForLargeBuffer) { + OEMCryptoMemoryGenerateRSASignatureForHugeBuffer) { OEMCryptoResult sts; LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); // If the device is a cast receiver, then this scheme is required. @@ -5434,7 +6303,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, } TEST_F(OEMCryptoLoadsCertificateAlternates, - OEMCryptoMemoryGenerateRSASignatureForLargeSignatureLength) { + OEMCryptoMemoryGenerateRSASignatureForHugeSignatureLength) { OEMCryptoResult sts; LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); // If the device is a cast receiver, then this scheme is required. @@ -5530,92 +6399,92 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { // This encodes the RSA key used in the PKCS#1 signing tests below. void BuildRSAKey() { vector field_n = - encode(0x02, wvcdm::a2b_hex("00" - "df271fd25f8644496b0c81be4bd50297" - "ef099b002a6fd67727eb449cea566ed6" - "a3981a71312a141cabc9815c1209e320" - "a25b32464e9999f18ca13a9fd3892558" - "f9e0adefdd3650dd23a3f036d60fe398" - "843706a40b0b8462c8bee3bce12f1f28" - "60c2444cdc6a44476a75ff4aa24273cc" - "be3bf80248465f8ff8c3a7f3367dfc0d" - "f5b6509a4f82811cedd81cdaaa73c491" - "da412170d544d4ba96b97f0afc806549" - "8d3a49fd910992a1f0725be24f465cfe" - "7e0eabf678996c50bc5e7524abf73f15" - "e5bef7d518394e3138ce4944506aaaaf" - "3f9b236dcab8fc00f87af596fdc3d9d6" - "c75cd508362fae2cbeddcc4c7450b17b" - "776c079ecca1f256351a43b97dbe2153")); - vector field_e = encode(0x02, wvcdm::a2b_hex("010001")); + encode(0x02, wvutil::a2b_hex("00" + "df271fd25f8644496b0c81be4bd50297" + "ef099b002a6fd67727eb449cea566ed6" + "a3981a71312a141cabc9815c1209e320" + "a25b32464e9999f18ca13a9fd3892558" + "f9e0adefdd3650dd23a3f036d60fe398" + "843706a40b0b8462c8bee3bce12f1f28" + "60c2444cdc6a44476a75ff4aa24273cc" + "be3bf80248465f8ff8c3a7f3367dfc0d" + "f5b6509a4f82811cedd81cdaaa73c491" + "da412170d544d4ba96b97f0afc806549" + "8d3a49fd910992a1f0725be24f465cfe" + "7e0eabf678996c50bc5e7524abf73f15" + "e5bef7d518394e3138ce4944506aaaaf" + "3f9b236dcab8fc00f87af596fdc3d9d6" + "c75cd508362fae2cbeddcc4c7450b17b" + "776c079ecca1f256351a43b97dbe2153")); + vector field_e = encode(0x02, wvutil::a2b_hex("010001")); vector field_d = - encode(0x02, wvcdm::a2b_hex("5bd910257830dce17520b03441a51a8c" - "ab94020ac6ecc252c808f3743c95b7c8" - "3b8c8af1a5014346ebc4242cdfb5d718" - "e30a733e71f291e4d473b61bfba6daca" - "ed0a77bd1f0950ae3c91a8f901118825" - "89e1d62765ee671e7baeea309f64d447" - "bbcfa9ea12dce05e9ea8939bc5fe6108" - "581279c982b308794b3448e7f7b95229" - "2df88c80cb40142c4b5cf5f8ddaa0891" - "678d610e582fcb880f0d707caf47d09a" - "84e14ca65841e5a3abc5e9dba94075a9" - "084341f0edad9b68e3b8e082b80b6e6e" - "8a0547b44fb5061b6a9131603a5537dd" - "abd01d8e863d8922e9aa3e4bfaea0b39" - "d79283ad2cbc8a59cce7a6ecf4e4c81e" - "d4c6591c807defd71ab06866bb5e7745")); + encode(0x02, wvutil::a2b_hex("5bd910257830dce17520b03441a51a8c" + "ab94020ac6ecc252c808f3743c95b7c8" + "3b8c8af1a5014346ebc4242cdfb5d718" + "e30a733e71f291e4d473b61bfba6daca" + "ed0a77bd1f0950ae3c91a8f901118825" + "89e1d62765ee671e7baeea309f64d447" + "bbcfa9ea12dce05e9ea8939bc5fe6108" + "581279c982b308794b3448e7f7b95229" + "2df88c80cb40142c4b5cf5f8ddaa0891" + "678d610e582fcb880f0d707caf47d09a" + "84e14ca65841e5a3abc5e9dba94075a9" + "084341f0edad9b68e3b8e082b80b6e6e" + "8a0547b44fb5061b6a9131603a5537dd" + "abd01d8e863d8922e9aa3e4bfaea0b39" + "d79283ad2cbc8a59cce7a6ecf4e4c81e" + "d4c6591c807defd71ab06866bb5e7745")); vector field_p = - encode(0x02, wvcdm::a2b_hex("00" - "f44f5e4246391f482b2f5296e3602eb3" - "4aa136427710f7c0416d403fd69d4b29" - "130cfebef34e885abdb1a8a0a5f0e9b5" - "c33e1fc3bfc285b1ae17e40cc67a1913" - "dd563719815ebaf8514c2a7aa0018e63" - "b6c631dc315a46235716423d11ff5803" - "4e610645703606919f5c7ce2660cd148" - "bd9efc123d9c54b6705590d006cfcf3f")); + encode(0x02, wvutil::a2b_hex("00" + "f44f5e4246391f482b2f5296e3602eb3" + "4aa136427710f7c0416d403fd69d4b29" + "130cfebef34e885abdb1a8a0a5f0e9b5" + "c33e1fc3bfc285b1ae17e40cc67a1913" + "dd563719815ebaf8514c2a7aa0018e63" + "b6c631dc315a46235716423d11ff5803" + "4e610645703606919f5c7ce2660cd148" + "bd9efc123d9c54b6705590d006cfcf3f")); vector field_q = - encode(0x02, wvcdm::a2b_hex("00" - "e9d49841e0e0a6ad0d517857133e36dc" - "72c1bdd90f9174b52e26570f373640f1" - "c185e7ea8e2ed7f1e4ebb951f70a5802" - "3633b0097aec67c6dcb800fc1a67f9bb" - "0563610f08ebc8746ad129772136eb1d" - "daf46436450d318332a84982fe5d28db" - "e5b3e912407c3e0e03100d87d436ee40" - "9eec1cf85e80aba079b2e6106b97bced")); + encode(0x02, wvutil::a2b_hex("00" + "e9d49841e0e0a6ad0d517857133e36dc" + "72c1bdd90f9174b52e26570f373640f1" + "c185e7ea8e2ed7f1e4ebb951f70a5802" + "3633b0097aec67c6dcb800fc1a67f9bb" + "0563610f08ebc8746ad129772136eb1d" + "daf46436450d318332a84982fe5d28db" + "e5b3e912407c3e0e03100d87d436ee40" + "9eec1cf85e80aba079b2e6106b97bced")); vector field_exp1 = - encode(0x02, wvcdm::a2b_hex("00" - "ed102acdb26871534d1c414ecad9a4d7" - "32fe95b10eea370da62f05de2c393b1a" - "633303ea741b6b3269c97f704b352702" - "c9ae79922f7be8d10db67f026a8145de" - "41b30c0a42bf923bac5f7504c248604b" - "9faa57ed6b3246c6ba158e36c644f8b9" - "548fcf4f07e054a56f768674054440bc" - "0dcbbc9b528f64a01706e05b0b91106f")); + encode(0x02, wvutil::a2b_hex("00" + "ed102acdb26871534d1c414ecad9a4d7" + "32fe95b10eea370da62f05de2c393b1a" + "633303ea741b6b3269c97f704b352702" + "c9ae79922f7be8d10db67f026a8145de" + "41b30c0a42bf923bac5f7504c248604b" + "9faa57ed6b3246c6ba158e36c644f8b9" + "548fcf4f07e054a56f768674054440bc" + "0dcbbc9b528f64a01706e05b0b91106f")); vector field_exp2 = - encode(0x02, wvcdm::a2b_hex("6827924a85e88b55ba00f8219128bd37" - "24c6b7d1dfe5629ef197925fecaff5ed" - "b9cdf3a7befd8ea2e8dd3707138b3ff8" - "7c3c39c57f439e562e2aa805a39d7cd7" - "9966d2ece7845f1dbc16bee99999e4d0" - "bf9eeca45fcda8a8500035fe6b5f03bc" - "2f6d1bfc4d4d0a3723961af0cdce4a01" - "eec82d7f5458ec19e71b90eeef7dff61")); + encode(0x02, wvutil::a2b_hex("6827924a85e88b55ba00f8219128bd37" + "24c6b7d1dfe5629ef197925fecaff5ed" + "b9cdf3a7befd8ea2e8dd3707138b3ff8" + "7c3c39c57f439e562e2aa805a39d7cd7" + "9966d2ece7845f1dbc16bee99999e4d0" + "bf9eeca45fcda8a8500035fe6b5f03bc" + "2f6d1bfc4d4d0a3723961af0cdce4a01" + "eec82d7f5458ec19e71b90eeef7dff61")); vector field_invq = - encode(0x02, wvcdm::a2b_hex("57b73888d183a99a6307422277551a3d" - "9e18adf06a91e8b55ceffef9077c8496" - "948ecb3b16b78155cb2a3a57c119d379" - "951c010aa635edcf62d84c5a122a8d67" - "ab5fa9e5a4a8772a1e943bafc70ae3a4" - "c1f0f3a4ddffaefd1892c8cb33bb0d0b" - "9590e963a69110fb34db7b906fc4ba28" - "36995aac7e527490ac952a02268a4f18")); + encode(0x02, wvutil::a2b_hex("57b73888d183a99a6307422277551a3d" + "9e18adf06a91e8b55ceffef9077c8496" + "948ecb3b16b78155cb2a3a57c119d379" + "951c010aa635edcf62d84c5a122a8d67" + "ab5fa9e5a4a8772a1e943bafc70ae3a4" + "c1f0f3a4ddffaefd1892c8cb33bb0d0b" + "9590e963a69110fb34db7b906fc4ba28" + "36995aac7e527490ac952a02268a4f18")); // Header of rsa key is constant. - encoded_rsa_key_ = wvcdm::a2b_hex( + encoded_rsa_key_ = wvutil::a2b_hex( // 0x02 0x01 0x00 == integer, size 1 byte, value = 0 (field=version) "020100" // 0x30, sequence, size = d = 13 (field=pkeyalg) AlgorithmIdentifier @@ -5635,7 +6504,7 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { "00" // size of null object ); - vector pkey = wvcdm::a2b_hex("020100"); // integer, version = 0. + vector pkey = wvutil::a2b_hex("020100"); // integer, version = 0. pkey = concat(pkey, field_n); pkey = concat(pkey, field_e); pkey = concat(pkey, field_d); @@ -5672,7 +6541,7 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { // The application will prepend the digest info to the hash. // SHA-1 digest info prefix = 0x30 0x21 0x30 ... - vector digest = wvcdm::a2b_hex("3021300906052b0e03021a05000414"); + vector digest = wvutil::a2b_hex("3021300906052b0e03021a05000414"); digest.insert(digest.end(), hash, hash + SHA_DIGEST_LENGTH); // OEMCrypto will apply the padding, and encrypt to generate the signature. @@ -5718,7 +6587,7 @@ TEST_F(OEMCryptoCastReceiverTest, SupportsCertificatesAPI13) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_1) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "f45d55f35551e975d6a8dc7ea9f48859" "3940cc75694a278f27e578a163d839b3" "4040841808cf9c58c9b8728bf5f9ce8e" @@ -5734,7 +6603,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_1) { "1024cd395958a2dfeb4816a6e8adedb5" "0b1f6b56d0b3060ff0f1c4cb0d0e001d" "d59d73be12"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "b75a5466b65d0f300ef53833f2175c8a" "347a3804fc63451dc902f0b71f908345" "9ed37a5179a3b723a53f1051642d7737" @@ -5757,7 +6626,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_1) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_2) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "c14b4c6075b2f9aad661def4ecfd3cb9" "33c623f4e63bf53410d2f016d1ab98e2" "729eccf8006cd8e08050737d95fdbf29" @@ -5768,7 +6637,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_2) { "88cde7c97f8a66cd66301281dac3f3a4" "33248c75d6c2dcd708b6a97b0a3f325e" "0b2964f8a5819e479b"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "afa7343462bea122cc149fca70abdae7" "9446677db5373666af7dc313015f4de7" "86e6e394946fad3cc0e2b02bedba5047" @@ -5792,7 +6661,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_2) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_3) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "d02371ad7ee48bbfdb2763de7a843b94" "08ce5eb5abf847ca3d735986df84e906" "0bdbcdd3a55ba55dde20d4761e1a21d2" @@ -5809,7 +6678,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_3) { "d2676797817f7c337b5ac824ba93143b" "3381fa3dce0e6aebd38e67735187b1eb" "d95c02"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "3bac63f86e3b70271203106b9c79aabd" "9f477c56e4ee58a4fce5baf2cab4960f" "88391c9c23698be75c99aedf9e1abf17" @@ -5833,12 +6702,12 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_3) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_4) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "29035584ab7e0226a9ec4b02e8dcf127" "2dc9a41d73e2820007b0f6e21feccd5b" "d9dbb9ef88cd6758769ee1f956da7ad1" "8441de6fab8386dbc693"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "28d8e3fcd5dddb21ffbd8df1630d7377" "aa2651e14cad1c0e43ccc52f907f946d" "66de7254e27a6c190eb022ee89ecf622" @@ -5862,8 +6731,8 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_4) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_5) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex("bda3a1c79059eae598308d3df609"); - vector signature = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex("bda3a1c79059eae598308d3df609"); + vector signature = wvutil::a2b_hex( "a156176cb96777c7fb96105dbd913bc4" "f74054f6807c6008a1a956ea92c1f81c" "b897dc4b92ef9f4e40668dc7c556901a" @@ -5887,7 +6756,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_5) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_6) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "c187915e4e87da81c08ed4356a0cceac" "1c4fb5c046b45281b387ec28f1abfd56" "7e546b236b37d01ae71d3b2834365d3d" @@ -5895,7 +6764,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_6) { "6d12166361b613dbc47dfaeb4ca74645" "6c2e888385525cca9dd1c3c7a9ada76d" "6c"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "9cab74163608669f7555a333cf196fe3" "a0e9e5eb1a32d34bb5c85ff689aaab0e" "3e65668ed3b1153f94eb3d8be379b8ee" @@ -5919,7 +6788,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_6) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_7) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "abfa2ecb7d29bd5bcb9931ce2bad2f74" "383e95683cee11022f08e8e7d0b8fa05" "8bf9eb7eb5f98868b5bb1fb5c31ceda3" @@ -5928,7 +6797,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_7) { "8eabf5cd2a560fca75fe96e07d859def" "b2564f3a34f16f11e91b3a717b41af53" "f6605323001aa406c6"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "c4b437bcf703f352e1faf74eb9622039" "426b5672caf2a7b381c6c4f0191e7e4a" "98f0eebcd6f41784c2537ff0f99e7498" @@ -5952,7 +6821,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_7) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_8) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "df4044a89a83e9fcbf1262540ae3038b" "bc90f2b2628bf2a4467ac67722d8546b" "3a71cb0ea41669d5b4d61859c1b4e47c" @@ -5967,7 +6836,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_8) { "b4d87f3ef131296c53a308e0331dac8b" "af3b63422266ecef2b90781535dbda41" "cbd0cf22a8cbfb532ec68fc6afb2ac06"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "1414b38567ae6d973ede4a06842dcc0e" "0559b19e65a4889bdbabd0fd02806829" "13bacd5dc2f01b30bb19eb810b7d9ded" @@ -5991,7 +6860,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_8) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_9) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "ea941ff06f86c226927fcf0e3b11b087" "2676170c1bfc33bda8e265c77771f9d0" "850164a5eecbcc5ce827fbfa07c85214" @@ -6004,7 +6873,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_9) { "da83a2a5c9152f837cb07812bd5ba7d3" "a07985de88113c1796e9b466ec299c5a" "c1059e27f09415"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "ceeb84ccb4e9099265650721eea0e8ec" "89ca25bd354d4f64564967be9d4b08b3" "f1c018539c9d371cf8961f2291fbe0dc" @@ -6028,13 +6897,13 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_9) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_10) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "d8b81645c13cd7ecf5d00ed2c91b9acd" "46c15568e5303c4a9775ede76b48403d" "6be56c05b6b1cf77c6e75de096c5cb35" "51cb6fa964f3c879cf589d28e1da2f9d" "ec"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "2745074ca97175d992e2b44791c323c5" "7167165cdd8da579cdef4686b9bb404b" "d36a56504eb1fd770f60bfa188a7b24b" @@ -6058,7 +6927,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_10) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_11) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "e5739b6c14c92d510d95b826933337ff" "0d24ef721ac4ef64c2bad264be8b44ef" "a1516e08a27eb6b611d3301df0062dae" @@ -6068,7 +6937,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_11) { "2b46a5407719197d2e958e3531fd54ae" "f903aabb4355f88318994ed3c3dd62f4" "20a7"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "be40a5fb94f113e1b3eff6b6a33986f2" "02e363f07483b792e68dfa5554df0466" "cc32150950783b4d968b639a04fd2fb9" @@ -6092,7 +6961,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_11) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_12) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "7af42835917a88d6b3c6716ba2f5b0d5" "b20bd4e2e6e574e06af1eef7c81131be" "22bf8128b9cbc6ec00275ba80294a5d1" @@ -6109,7 +6978,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_12) { "182a7d9ccabe7b0795f5c655e9acc4e3" "ec185140d10cef053464ab175c83bd83" "935e3dabaf3462eebe63d15f573d269a"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "4e78c5902b807914d12fa537ae6871c8" "6db8021e55d1adb8eb0ccf1b8f36ab7d" "ad1f682e947a627072f03e627371781d" @@ -6133,12 +7002,12 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_12) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_13) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "ebaef3f9f23bdfe5fa6b8af4c208c189" "f2251bf32f5f137b9de4406378686b3f" "0721f62d24cb8688d6fc41a27cbae21d" "30e429feacc7111941c277"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "c48dbef507114f03c95fafbeb4df1bfa" "88e0184a33cc4f8a9a1035ff7f822a5e" "38cda18723915ff078244429e0f6081c" @@ -6162,7 +7031,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_13) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_14) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "c5a2711278761dfcdd4f0c99e6f5619d" "6c48b5d4c1a80982faa6b4cf1cf7a60f" "f327abef93c801429efde08640858146" @@ -6174,7 +7043,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_14) { "3983596eb385844f8528cc9a9865835d" "c5113c02b80d0fca68aa25e72bcaaeb3" "cf9d79d84f984fd417"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "6bd5257aa06611fb4660087cb4bc4a9e" "449159d31652bd980844daf3b1c7b353" "f8e56142f7ea9857433b18573b4deede" @@ -6198,7 +7067,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_14) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_15) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "9bf8aa253b872ea77a7e23476be26b23" "29578cf6ac9ea2805b357f6fc3ad130d" "baeb3d869a13cce7a808bbbbc969857e" @@ -6213,7 +7082,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_15) { "396baac112252dd5c5346adb2004a2f7" "101ccc899cc7fafae8bbe295738896a5" "b2012285014ef6"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "27f7f4da9bd610106ef57d32383a448a" "8a6245c83dc1309c6d770d357ba89e73" "f2ad0832062eb0fe0ac915575bcd6b8b" @@ -6237,7 +7106,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_15) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_16) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "32474830e2203754c8bf0681dc4f842a" "fe360930378616c108e833656e5640c8" "6856885bb05d1eb9438efede679263de" @@ -6254,7 +7123,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_16) { "53ca6b7dce6098451a2f8c0da9bfecf1" "fdf391bbaa4e2a91ca18a1121a7523a2" "abd42514f489e8"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "6917437257c22ccb5403290c3dee82d9" "cf7550b31bd31c51bd57bfd35d452ab4" "db7c4be6b2e25ac9a59a1d2a7feb627f" @@ -6278,12 +7147,12 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_16) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_17) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "008e59505eafb550aae5e845584cebb0" "0b6de1733e9f95d42c882a5bbeb5ce1c" "57e119e7c0d4daca9f1ff7870217f7cf" "d8a6b373977cac9cab8e71e420"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "922503b673ee5f3e691e1ca85e9ff417" "3cf72b05ac2c131da5603593e3bc259c" "94c1f7d3a06a5b9891bf113fa39e59ff" @@ -6307,13 +7176,13 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_17) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_18) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "6abc54cf8d1dff1f53b17d8160368878" "a8788cc6d22fa5c2258c88e660b09a89" "33f9f2c0504ddadc21f6e75e0b833beb" "555229dee656b9047b92f62e76b8ffcc" "60dab06b80"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "0b6daf42f7a862147e417493c2c401ef" "ae32636ab4cbd44192bbf5f195b50ae0" "96a475a1614f0a9fa8f7a026cb46c650" @@ -6337,7 +7206,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_18) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_19) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "af2d78152cf10efe01d274f217b177f6" "b01b5e749f1567715da324859cd3dd88" "db848ec79f48dbba7b6f1d33111ef31b" @@ -6350,7 +7219,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_19) { "a1d946cf4fbe758d9276f08563449d67" "414a2c030f4251cfe2213d04a5410637" "87"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "209c61157857387b71e24bf3dd564145" "50503bec180ff53bdd9bac062a2d4995" "09bf991281b79527df9136615b7a6d9d" @@ -6374,7 +7243,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_19) { TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_20) { BuildRSAKey(); LoadWithAllowedSchemes(kSign_PKCS1_Block1, true); - vector message = wvcdm::a2b_hex( + vector message = wvutil::a2b_hex( "40ee992458d6f61486d25676a96dd2cb" "93a37f04b178482f2b186cf88215270d" "ba29d786d774b0c5e78c7f6e56a956e7" @@ -6387,7 +7256,7 @@ TEST_F(OEMCryptoCastReceiverTest, TestSignaturePKCS1_15_20) { "31ede1ef68cb6398d7911684fec0babc" "3a781a66660783506974d0e14825101c" "3bfaea"); - vector signature = wvcdm::a2b_hex( + vector signature = wvutil::a2b_hex( "927502b824afc42513ca6570de338b8a" "64c3a85eb828d3193624f27e8b1029c5" "5c119c9733b18f5849b3500918bcc005" @@ -6482,6 +7351,100 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { in_buffer.size(), signature->data(), &md_len); } + OEMCryptoResult GenericEncrypt(OEMCrypto_SESSION session, + const uint8_t* clear_buffer, + size_t clear_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_encrypt_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(iv), + wvoec::KEY_IV_SIZE); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Encrypt(session, clear_buffer, clear_buffer_length, + iv, algorithm, out_buffer); + } + + OEMCryptoResult GenericDecrypt(OEMCrypto_SESSION session, + const uint8_t* encrypted_buffer, + size_t encrypted_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_decrypt_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(iv), + wvoec::KEY_IV_SIZE); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(encrypted_buffer), + encrypted_buffer_length); + } + return OEMCrypto_Generic_Decrypt(session, encrypted_buffer, + encrypted_buffer_length, iv, algorithm, + out_buffer); + } + + OEMCryptoResult GenericVerify(OEMCrypto_SESSION session, + const uint8_t* clear_buffer, + size_t clear_buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + size_t signature_length) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_verify_fuzz_seed_corpus"); + OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + fuzzed_structure.signature_length = signature_length; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Verify(session, clear_buffer, clear_buffer_length, + algorithm, signature, signature_length); + } + + OEMCryptoResult GenericSign(OEMCrypto_SESSION session, + const uint8_t* clear_buffer, + size_t clear_buffer_length, + OEMCrypto_Algorithm algorithm, uint8_t* signature, + size_t* signature_length) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_sign_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CENC; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Sign(session, clear_buffer, clear_buffer_length, + algorithm, signature, signature_length); + } + // This asks OEMCrypto to encrypt with the specified key, and expects a // failure. void BadEncrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm, @@ -6492,12 +7455,11 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(buffer_length); - sts = OEMCrypto_Generic_Encrypt(session_.session_id(), clear_buffer_.data(), - buffer_length, iv_, algorithm, - encrypted.data()); + sts = GenericEncrypt(session_.session_id(), clear_buffer_.data(), + buffer_length, iv_, algorithm, encrypted.data()); EXPECT_NE(OEMCrypto_SUCCESS, sts); expected_encrypted.resize(buffer_length); EXPECT_NE(encrypted, expected_encrypted); @@ -6513,12 +7475,11 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); - sts = OEMCrypto_Generic_Decrypt(session_.session_id(), encrypted.data(), - buffer_length, iv_, algorithm, - resultant.data()); + sts = GenericDecrypt(session_.session_id(), encrypted.data(), buffer_length, + iv_, algorithm, resultant.data()); EXPECT_NE(OEMCrypto_SUCCESS, sts); EXPECT_NE(clear_buffer_, resultant); } @@ -6533,13 +7494,13 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t signature_length = (size_t)SHA256_DIGEST_LENGTH; vector signature(SHA256_DIGEST_LENGTH); - sts = OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), algorithm, - signature.data(), &signature_length); + sts = GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), algorithm, signature.data(), + &signature_length); EXPECT_NE(OEMCrypto_SUCCESS, sts); EXPECT_NE(signature, expected_signature); } @@ -6561,11 +7522,11 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { sts = OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); - sts = OEMCrypto_Generic_Verify(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), algorithm, - signature.data(), signature_size); + sts = GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), algorithm, signature.data(), + signature_size); EXPECT_NE(OEMCrypto_SUCCESS, sts); } @@ -6589,13 +7550,12 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncrypt) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector encrypted(clear_buffer_.size()); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); } @@ -6622,13 +7582,13 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptSameBufferAPI12) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); // Input and output are same buffer: vector buffer = clear_buffer_; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), buffer.data(), buffer.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), buffer.data(), buffer.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); ASSERT_EQ(expected_encrypted, buffer); } @@ -6638,7 +7598,7 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemorySelectKeyForHugeKeyIdLength) { auto oemcrypto_function = [session_id](size_t key_id_length) { vector key_id(key_id_length); return OEMCrypto_SelectKey(session_id, key_id.data(), key_id.size(), - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } @@ -6653,7 +7613,7 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); OEMCrypto_SESSION session_id = session_.session_id(); auto& iv = iv_; auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) mutable { @@ -6677,7 +7637,7 @@ TEST_P( OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); OEMCrypto_SESSION session_id = session_.session_id(); vector buffer(17); ASSERT_NO_FATAL_FAILURE(OEMCrypto_Generic_Encrypt( @@ -6696,12 +7656,12 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector resultant(encrypted.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); } @@ -6712,7 +7672,7 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); OEMCrypto_SESSION session_id = session_.session_id(); auto iv = iv_; auto oemcrypto_function = [&session_id, &iv](size_t buffer_length) { @@ -6740,12 +7700,12 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector buffer = encrypted; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), buffer.data(), buffer.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), buffer.data(), buffer.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); ASSERT_EQ(clear_buffer_, buffer); } @@ -6764,12 +7724,12 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericSecureToClear) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector resultant(encrypted.size()); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_NE( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_NE(clear_buffer_, resultant); } @@ -6795,18 +7755,18 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - nullptr, &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, nullptr, + &gen_signature_length)); ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); vector signature(SHA256_DIGEST_LENGTH); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &gen_signature_length)); ASSERT_EQ(expected_signature, signature); } @@ -6818,7 +7778,7 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCryptoMemoryGenericKeySignForHugeBuffer) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector signature(SHA256_DIGEST_LENGTH); size_t signature_length = signature.size(); OEMCrypto_SESSION session_id = session_.session_id(); @@ -6841,7 +7801,7 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); OEMCrypto_SESSION session_id = session_.session_id(); auto clear_buffer = clear_buffer_; auto oemcrypto_function = [&session_id, @@ -6875,11 +7835,11 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( - session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + OEMCrypto_CipherMode_CENC)); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); } TEST_P(OEMCryptoGenericCryptoTest, @@ -6891,14 +7851,14 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); auto oemcrypto_function = [&](size_t buffer_length) { vector buffer(buffer_length); vector signature; SignBuffer(key_index, buffer, &signature); - return OEMCrypto_Generic_Verify(session_.session_id(), buffer.data(), - buffer.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size()); + return GenericVerify(session_.session_id(), buffer.data(), buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + signature.size()); }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } @@ -6915,7 +7875,7 @@ TEST_P(OEMCryptoGenericCryptoTest, OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); OEMCrypto_SESSION session_id = session_.session_id(); auto clear_buffer = clear_buffer_; auto oemcrypto_function = [&session_id, &clear_buffer, @@ -6951,13 +7911,12 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptLargeBuffer) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector encrypted(clear_buffer_.size()); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); } @@ -6974,12 +7933,12 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptLargeBuffer) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector resultant(encrypted.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); } @@ -6996,18 +7955,18 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySignLargeBuffer) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - nullptr, &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, nullptr, + &gen_signature_length)); ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); vector signature(SHA256_DIGEST_LENGTH); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &gen_signature_length)); ASSERT_EQ(expected_signature, signature); } @@ -7024,11 +7983,11 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerifyLargeBuffer) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( - session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + OEMCrypto_CipherMode_CENC)); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); } // Test Generic_Encrypt when the key duration has expired. @@ -7048,15 +8007,14 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationEncrypt) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); + OEMCrypto_CipherMode_CENC)); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); - wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. + wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. encrypted.assign(clear_buffer_.size(), 0); OEMCryptoResult status = OEMCrypto_Generic_Encrypt( session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), iv_, @@ -7082,19 +8040,19 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationDecrypt) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector resultant(encrypted.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); - wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. + wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. resultant.assign(encrypted.size(), 0); - OEMCryptoResult status = OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); + OEMCryptoResult status = + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); ASSERT_NE(clear_buffer_, resultant); ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); @@ -7119,16 +8077,16 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationSign) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &signature_length)); ASSERT_EQ(expected_signature, signature); - wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. + wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. signature.assign(SHA256_DIGEST_LENGTH, 0); - OEMCryptoResult status = OEMCrypto_Generic_Sign( + OEMCryptoResult status = GenericSign( session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), &signature_length); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); @@ -7153,13 +8111,13 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) { OEMCrypto_SelectKey(session_.session_id(), session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( - session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + OEMCrypto_CipherMode_CENC)); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); - wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. + wvutil::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. OEMCryptoResult status = OEMCrypto_Generic_Verify( session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), signature.size()); @@ -7222,7 +8180,7 @@ class OEMCryptoGenericCryptoKeyIdLengthTest OEMCrypto_SUCCESS, OEMCrypto_SelectKey(session_.session_id(), key_id_buffer.data(), session_.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR)); + OEMCrypto_CipherMode_CENC)); vector resultant(encrypted.size()); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Decrypt( @@ -7256,12 +8214,11 @@ TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformLongKeyId) { TestWithKey(2); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); - -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoTest, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); /// @} /// @addtogroup usage_table @@ -7319,7 +8276,7 @@ class LicenseWithUsageEntry { ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry(status)); if (status != nullptr && *status != OEMCrypto_SUCCESS) return; ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); - time_license_received_ = wvcdm::Clock().GetCurrentTime(); + time_license_received_ = wvutil::Clock().GetCurrentTime(); } void OpenAndReload(SessionUtil* util) { @@ -7334,12 +8291,17 @@ class LicenseWithUsageEntry { void TestDecryptCTR(bool select_key_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS) { session_.TestDecryptCTR(select_key_first, expected_result); - time_last_decrypt_ = wvcdm::Clock().GetCurrentTime(); + time_last_decrypt_ = wvutil::Clock().GetCurrentTime(); if (time_first_decrypt_ == 0) time_first_decrypt_ = time_last_decrypt_; } void DeactivateUsageEntry() { active_ = false; + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_deactivate_usage_entry_fuzz_seed_corpus"); + AppendToFile(file_name, pst().c_str(), pst().length()); + } ASSERT_EQ( OEMCrypto_SUCCESS, OEMCrypto_DeactivateUsageEntry( @@ -7402,10 +8364,10 @@ class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { void PrintDotsWhileSleep(int64_t total_seconds, int64_t interval_seconds) { int64_t dot_time = interval_seconds; int64_t elapsed_time = 0; - const int64_t start_time = wvcdm::Clock().GetCurrentTime(); + const int64_t start_time = wvutil::Clock().GetCurrentTime(); do { - wvcdm::TestSleep::Sleep(1); - elapsed_time = wvcdm::Clock().GetCurrentTime() - start_time; + wvutil::TestSleep::Sleep(1); + elapsed_time = wvutil::Clock().GetCurrentTime() - start_time; if (elapsed_time >= dot_time) { cout << "."; cout.flush(); @@ -7414,6 +8376,12 @@ class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { } while (elapsed_time < total_seconds); cout << endl; } + + OEMCryptoResult LoadUsageTableHeader( + const vector& encrypted_usage_header) { + return OEMCrypto_LoadUsageTableHeader(encrypted_usage_header.data(), + encrypted_usage_header.size()); + } }; TEST_P(OEMCryptoUsageTableTest, @@ -7580,6 +8548,13 @@ TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { OEMCrypto_ReportUsage(s.session_id(), reinterpret_cast(entry.pst().c_str()), entry.pst().length(), nullptr, &length); + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_report_usage_fuzz_seed_corpus"); + AppendToFile(file_name, reinterpret_cast(&length), + sizeof(length)); + AppendToFile(file_name, entry.pst().c_str(), entry.pst().length()); + } vector pst_report_buffer(buffer_length); return OEMCrypto_ReportUsage( s.session_id(), reinterpret_cast(entry.pst().c_str()), @@ -7675,7 +8650,7 @@ TEST_P(OEMCryptoUsageTableTest, OnlineLicenseUnused) { ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); // Decrypt should fail. ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); // We could call DeactivateUsageEntry multiple times. The state should not // change. ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); @@ -7707,7 +8682,7 @@ TEST_P(OEMCryptoUsageTableTest, ForbidReportWithNoUpdate) { s.GenerateReport(entry.pst(), OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE)); // Decrypt should fail. ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); } // Test an online license with a license renewal. @@ -7883,7 +8858,7 @@ TEST_P(OEMCryptoUsageTableTest, GenericCryptoEncrypt) { &expected_encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(clear_buffer_.size()); sts = OEMCrypto_Generic_Encrypt( @@ -7918,7 +8893,7 @@ TEST_P(OEMCryptoUsageTableTest, GenericCryptoDecrypt) { &encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); sts = OEMCrypto_Generic_Decrypt( @@ -7954,7 +8929,7 @@ TEST_P(OEMCryptoUsageTableTest, GenericCryptoSign) { sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t gen_signature_length = 0; sts = OEMCrypto_Generic_Sign(s.session_id(), clear_buffer_.data(), @@ -7998,7 +8973,7 @@ TEST_P(OEMCryptoUsageTableTest, GenericCryptoVerify) { sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, s.license().keys[key_index].key_id_length, - OEMCrypto_CipherMode_CTR); + OEMCrypto_CipherMode_CENC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_Generic_Verify(s.session_id(), clear_buffer_.data(), clear_buffer_.size(), OEMCrypto_HMAC_SHA256, @@ -8085,9 +9060,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithTerminate) { Session& s = entry.session(); ShutDown(); // This calls OEMCrypto_Terminate. Restart(); // This calls OEMCrypto_Initialize. - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(), - encrypted_usage_header_.size())); + ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); @@ -8237,7 +9210,7 @@ TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicenseUnused) { ASSERT_NO_FATAL_FAILURE(entry.DeactivateUsageEntry()); // Then deactivate. // After deactivate, should not be able to decrypt. ASSERT_NO_FATAL_FAILURE( - entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); + entry.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); ASSERT_NO_FATAL_FAILURE(s.close()); @@ -8368,7 +9341,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) { entries[i].set_pst("pst " + std::to_string(i)); ASSERT_NO_FATAL_FAILURE(entries[i].MakeOfflineAndClose(this)) << "On license " << i << " pst=" << entries[i].pst(); - wvcdm::TestSleep::SyncFakeClock(); + wvutil::TestSleep::SyncFakeClock(); } for (size_t i = 0; i < ENTRY_COUNT; i++) { ASSERT_NO_FATAL_FAILURE(entries[i].OpenAndReload(this)) @@ -8383,10 +9356,8 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) { ASSERT_NO_FATAL_FAILURE(ShrinkHeader(3)); ShutDown(); Restart(); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(), - encrypted_usage_header_.size())); - wvcdm::TestSleep::SyncFakeClock(); + ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); + wvutil::TestSleep::SyncFakeClock(); ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[0])); // Now has index 1. ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[4])); @@ -8529,7 +9500,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { // Store the status of the last attempt to create an entry. OEMCryptoResult status = OEMCrypto_SUCCESS; while (successful_count < attempt_count && status == OEMCrypto_SUCCESS) { - wvcdm::TestSleep::SyncFakeClock(); + wvutil::TestSleep::SyncFakeClock(); LOGD("Creating license for entry %zu", successful_count); entries.push_back( std::unique_ptr(new LicenseWithUsageEntry())); @@ -8565,11 +9536,11 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { << ", with wrong error code."; } EXPECT_GE(successful_count, required_capacity); - wvcdm::TestSleep::SyncFakeClock(); + wvutil::TestSleep::SyncFakeClock(); // Shrink the table a little. constexpr size_t small_number = 5; size_t smaller_size = successful_count - small_number; - ASSERT_NO_FATAL_FAILURE(ShrinkHeader(smaller_size)); + ASSERT_NO_FATAL_FAILURE(ShrinkHeader(static_cast(smaller_size))); // Throw out the last license if it was in the part of the table that was // shrunk. if (entries.back()->session().usage_entry_number() >= smaller_size) { @@ -8577,7 +9548,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { } // Create a few more license for (size_t i = 0; i < small_number; i++) { - wvcdm::TestSleep::SyncFakeClock(); + wvutil::TestSleep::SyncFakeClock(); entries.push_back( std::unique_ptr(new LicenseWithUsageEntry())); entries.back()->set_pst("new pst " + std::to_string(smaller_size + i)); @@ -8585,7 +9556,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { } // Make sure that all of the licenses can be reloaded. for (size_t i = 0; i < entries.size(); i++) { - wvcdm::TestSleep::SyncFakeClock(); + wvutil::TestSleep::SyncFakeClock(); Session& s = entries[i]->session(); ASSERT_NO_FATAL_FAILURE(entries[i]->OpenAndReload(this)); ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); @@ -8597,6 +9568,78 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { } } +// Verify that usage entries can be created in the position of existing entry +// indexes. +TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryAPI17) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); + const uint32_t number = entry0.session().usage_entry_number(); + entry0.session().close(); + entry1.session().open(); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number)); +} + +// Verify that usage entries cannot replace an entry that is currently in +// use by a session. +TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryIndexInUseAPI17) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); + const uint32_t number = entry0.session().usage_entry_number(); + entry1.session().open(); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_SESSION, + OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number)); +} + +// Verify that usage entries cannot be created if the usage entry index is +// too large. +TEST_P(OEMCryptoUsageTableDefragTest, ReuseUsageEntryWithInvalidIndexAPI17) { + LicenseWithUsageEntry entry0; + entry0.set_pst("pst 0"); + LicenseWithUsageEntry entry1; + entry1.set_pst("pst 1"); + + entry0.session().open(); + ASSERT_NO_FATAL_FAILURE(entry0.session().CreateNewUsageEntry()); + const uint32_t number = entry0.session().usage_entry_number(); + entry0.session().close(); + entry1.session().open(); + ASSERT_EQ( + OEMCrypto_ERROR_UNKNOWN_FAILURE, + OEMCrypto_ReuseUsageEntry(entry1.session().session_id(), number + 42)); +} + +// Verify that usage entries cannot be created if the session already has an +// entry. +TEST_P(OEMCryptoUsageTableDefragTest, + ReuseUsageEntrySessionAlreadyHasEntryAPI17) { + LicenseWithUsageEntry entry; + entry.set_pst("pst 0"); + + // Create 5 entries in the table. + for (int i = 0; i < 5; i++) { + entry.session().open(); + ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); + entry.session().close(); + } + entry.session().open(); + ASSERT_NO_FATAL_FAILURE(entry.session().CreateNewUsageEntry()); + const uint32_t number = entry.session().usage_entry_number(); + ASSERT_EQ( + OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES, + OEMCrypto_ReuseUsageEntry(entry.session().session_id(), number - 3)); +} + // This verifies that the usage table header can be loaded if the generation // number is off by one, but not off by two. TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { @@ -8631,8 +9674,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { // Modified header generates error. vector bad_header = encrypted_usage_header_; bad_header[3] ^= 42; - ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageTableHeader( - bad_header.data(), bad_header.size())); + ASSERT_NE(OEMCrypto_SUCCESS, LoadUsageTableHeader(bad_header)); ASSERT_NO_FATAL_FAILURE(s.open()); // Cannot load an entry if header didn't load. ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, @@ -8643,8 +9685,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { // Old by 2 generation numbers is error. ASSERT_EQ(OEMCrypto_ERROR_GENERATION_SKEW, - OEMCrypto_LoadUsageTableHeader(old_usage_header_2_.data(), - old_usage_header_2_.size())); + LoadUsageTableHeader(old_usage_header_2_)); ASSERT_NO_FATAL_FAILURE(s.open()); // Cannot load an entry if header didn't load. ASSERT_NE(OEMCrypto_SUCCESS, @@ -8655,8 +9696,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { // Old by 1 generation numbers is just warning. ASSERT_EQ(OEMCrypto_WARNING_GENERATION_SKEW, - OEMCrypto_LoadUsageTableHeader(old_usage_header_1_.data(), - old_usage_header_1_.size())); + LoadUsageTableHeader(old_usage_header_1_)); // Everything else should still work. The old entry goes with the old header. ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_EQ(OEMCrypto_SUCCESS, @@ -8735,35 +9775,35 @@ TEST_P(OEMCryptoUsageTableTest, TimingTest) { ASSERT_NO_FATAL_FAILURE(entry2.MakeOfflineAndClose(this)); ASSERT_NO_FATAL_FAILURE(entry3.MakeOfflineAndClose(this)); - wvcdm::TestSleep::Sleep(kLongSleep); + wvutil::TestSleep::Sleep(kLongSleep); ASSERT_NO_FATAL_FAILURE(entry1.OpenAndReload(this)); ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); - wvcdm::TestSleep::Sleep(kLongSleep); + wvutil::TestSleep::Sleep(kLongSleep); ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); - wvcdm::TestSleep::Sleep(kLongSleep); + wvutil::TestSleep::Sleep(kLongSleep); ASSERT_NO_FATAL_FAILURE(entry1.DeactivateUsageEntry()); ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(s1.close()); ASSERT_NO_FATAL_FAILURE(s2.close()); - wvcdm::TestSleep::Sleep(kLongSleep); + wvutil::TestSleep::Sleep(kLongSleep); // This is as close to reboot as we can simulate in code. ShutDown(); - wvcdm::TestSleep::Sleep(kShortSleep); + wvutil::TestSleep::Sleep(kShortSleep); Restart(); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(), encrypted_usage_header_.size())); // After a reboot, we should be able to reload keys, and generate reports. - wvcdm::TestSleep::Sleep(kLongSleep); + wvutil::TestSleep::Sleep(kLongSleep); ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR()); ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); @@ -8774,7 +9814,7 @@ TEST_P(OEMCryptoUsageTableTest, TimingTest) { ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this)); ASSERT_NO_FATAL_FAILURE(entry3.OpenAndReload(this)); - wvcdm::TestSleep::Sleep(kLongSleep); + wvutil::TestSleep::Sleep(kLongSleep); ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(entry1.GenerateVerifyReport(kInactiveUsed)); ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); @@ -8817,13 +9857,13 @@ TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) { int64_t dot_time = kDotIntervalInSeconds; int64_t playback_time = 0; - const int64_t start_time = wvcdm::Clock().GetCurrentTime(); + const int64_t start_time = wvutil::Clock().GetCurrentTime(); do { ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR()); ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive)); - wvcdm::TestSleep::Sleep(kShortSleep); - playback_time = wvcdm::Clock().GetCurrentTime() - start_time; + wvutil::TestSleep::Sleep(kShortSleep); + playback_time = wvutil::Clock().GetCurrentTime() - start_time; ASSERT_LE(0, playback_time); if (playback_time >= dot_time) { cout << "."; @@ -8870,7 +9910,7 @@ class OEMCryptoUsageTableTestWallClock : public OEMCryptoUsageTableTest { void SetUp() override { OEMCryptoUsageTableTest::SetUp(); } void TearDown() override { - wvcdm::TestSleep::ResetRollback(); + wvutil::TestSleep::ResetRollback(); OEMCryptoUsageTableTest::TearDown(); } }; @@ -8941,22 +9981,22 @@ TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) { // Start with three short intervals of playback for entry1. for (int i = 0; i < kPlaybackCount; i++) { ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - wvcdm::TestSleep::Sleep(kShortSleep); + wvutil::TestSleep::Sleep(kShortSleep); ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); } cout << "Rolling the system time back..." << endl; - ASSERT_TRUE(wvcdm::TestSleep::RollbackSystemTime(kRollBackTime)); + ASSERT_TRUE(wvutil::TestSleep::RollbackSystemTime(kRollBackTime)); // Three more short intervals of playback after the rollback. for (int i = 0; i < kPlaybackCount; i++) { ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); - wvcdm::TestSleep::Sleep(kShortSleep); + wvutil::TestSleep::Sleep(kShortSleep); ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR()); } // One short interval of sleep to push us past the 6 interval duration. - wvcdm::TestSleep::Sleep(2 * kShortSleep); + wvutil::TestSleep::Sleep(2 * kShortSleep); // Should not be able to continue playback in entry1. ASSERT_NO_FATAL_FAILURE( @@ -8970,13 +10010,13 @@ TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) { ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(s1.GenerateReport(entry1.pst())); - wvcdm::Unpacked_PST_Report report1 = s1.pst_report(); + wvutil::Unpacked_PST_Report report1 = s1.pst_report(); EXPECT_EQ(report1.status(), kActive); EXPECT_GE(report1.seconds_since_license_received(), kTotalTime); EXPECT_GE(report1.seconds_since_first_decrypt(), kTotalTime); ASSERT_NO_FATAL_FAILURE(s2.GenerateReport(entry2.pst())); - wvcdm::Unpacked_PST_Report report2 = s2.pst_report(); + wvutil::Unpacked_PST_Report report2 = s2.pst_report(); EXPECT_EQ(report2.status(), kUnused); EXPECT_GE(report2.seconds_since_license_received(), kTotalTime); } @@ -9000,16 +10040,16 @@ TEST_P(OEMCryptoUsageTableTest, PSTLargeBuffer) { ASSERT_NO_FATAL_FAILURE(s.close()); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoUsageTableTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoUsageTableTest, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); // These tests only work when the license has a core message. -INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoUsageTableDefragTest, - Values(kCurrentAPI)); +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableDefragTest, + Values(kCurrentAPI)); // These tests only work when the license has a core message. -INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, - Values(kCurrentAPI)); +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, + Values(kCurrentAPI)); /// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test_android.cpp b/oemcrypto/test/oemcrypto_test_android.cpp index 647017b..afaebdc 100644 --- a/oemcrypto/test/oemcrypto_test_android.cpp +++ b/oemcrypto/test/oemcrypto_test_android.cpp @@ -91,9 +91,8 @@ TEST_F(OEMCryptoAndroidLMPTest, SupportsUsageTable) { // Android devices require L1 OEMCrypto. TEST_F(OEMCryptoAndroidLMPTest, Level1Required) { - const char* char_level = OEMCrypto_SecurityLevel(); - std::string security_level(char_level ? char_level : ""); - EXPECT_EQ("L1", security_level) + OEMCrypto_Security_Level security_level = OEMCrypto_SecurityLevel(); + EXPECT_EQ(OEMCrypto_Level1, security_level) << "The security level is " << security_level << ". but we expect L1.\n" << "If you are testing a device that should be L3 or L2, please\n" << "repeat the tests with the flag --gtest_filter=\"*-*Level1Required\""; diff --git a/oemcrypto/test/oemcrypto_test_main.cpp b/oemcrypto/test/oemcrypto_test_main.cpp index 5815fd4..8a702cf 100644 --- a/oemcrypto/test/oemcrypto_test_main.cpp +++ b/oemcrypto/test/oemcrypto_test_main.cpp @@ -41,10 +41,10 @@ int main(int argc, char** argv) { filter_tests = false; } if (arg == "--fake_sleep") { - wvcdm::TestSleep::set_real_sleep(false); + wvutil::TestSleep::set_real_sleep(false); } } - wvcdm::g_cutoff = static_cast(verbosity); + wvutil::g_cutoff = static_cast(verbosity); wvoec::global_features.Initialize(); wvoec::global_features.set_cast_receiver(is_cast_receiver); // Init GTest after device properties has been initialized. diff --git a/oemcrypto/test/oemcrypto_unittests.gypi b/oemcrypto/test/oemcrypto_unittests.gypi index 9051a11..ec9de14 100644 --- a/oemcrypto/test/oemcrypto_unittests.gypi +++ b/oemcrypto/test/oemcrypto_unittests.gypi @@ -1,10 +1,14 @@ # Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -#source code may only be used and distributed under the Widevine License -#Agreement. +# source code may only be used and distributed under the Widevine License +# Agreement. # # Include this in any custom unit test targets. # Does not include the test runner main. { + 'variables': { + 'test_opk_serialization_version%' : 'false', + 'static_libcpp%' : 'false', + }, 'sources': [ 'oec_device_features.cpp', 'oec_decrypt_fallback_chain.cpp', @@ -15,6 +19,18 @@ 'oemcrypto_test.cpp', 'wvcrc.cpp', ], + 'conditions': [ + ['test_opk_serialization_version=="true"', { + 'sources+' : [ + 'oemcrypto_serialization_version_test.cpp', + ], + }], + ['static_libcpp=="true"', { + 'ldflags+':[ + '-static-libstdc++', + ], + }], + ], 'include_dirs': [ '<(util_dir)/include', '<(util_dir)/test', @@ -27,6 +43,13 @@ 'defines': [ 'OEMCRYPTO_TESTS', ], + 'conditions': [ + ['support_ota_keybox_functions=="true"', { + 'sources': [ + '<(oemcrypto_dir)/test/ota_keybox_test.cpp', + ], + }], + ], 'dependencies': [ '<(oemcrypto_dir)/odk/src/odk.gyp:odk', ], diff --git a/oemcrypto/test/ota_keybox_test.cpp b/oemcrypto/test/ota_keybox_test.cpp new file mode 100644 index 0000000..ce527fb --- /dev/null +++ b/oemcrypto/test/ota_keybox_test.cpp @@ -0,0 +1,295 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// + +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "arraysize.h" +#include "log.h" +#include "oec_key_deriver.h" +#include "oec_session_util.h" +#include "oec_test_data.h" +#include "oemcrypto_session_tests_helper.h" +#include "oemcrypto_types.h" +#include "platform.h" +#include "string_conversions.h" + +using namespace std; + +namespace wvoec { +namespace { +const std::string kOption2Label = "WV_KB_REPROV_V02"; +constexpr size_t kLabelLength = 16u; +constexpr size_t kDeviceIdLength = 32u; +constexpr size_t kMinimumRequestLength = + kLabelLength // Start with a label. + + kDeviceIdLength // Fixed length device id. + + sizeof(uint32_t) // cert length. + // variable cert length. + + HMAC_SHA256_SIGNATURE_SIZE; // signature. +static const uint8_t TestKeyPKCS8[] = { + 0x30, 0x82, 0x04, 0xbf, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x04, 0xa9, 0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xa6, 0x33, 0x7f, 0x22, 0x05, 0xae, 0xcf, 0xae, 0x29, 0x67, + 0xa9, 0x3a, 0xe7, 0x08, 0xbf, 0x61, 0x92, 0x62, 0x4a, 0xd4, 0x82, 0x37, + 0x4d, 0x08, 0xa1, 0x77, 0x9f, 0x31, 0xa8, 0x92, 0xc5, 0x8b, 0x85, 0x84, + 0x12, 0x66, 0x52, 0xe6, 0x4b, 0x4c, 0xde, 0xdd, 0x43, 0x85, 0x53, 0xd1, + 0x0c, 0x79, 0x2c, 0xcf, 0x38, 0x4b, 0x72, 0x50, 0xf4, 0x34, 0x15, 0x0b, + 0xbe, 0x06, 0xf7, 0x60, 0x66, 0xda, 0xea, 0x40, 0x25, 0x38, 0x3e, 0xeb, + 0x6e, 0x13, 0x1b, 0xd0, 0x04, 0xd9, 0x4a, 0xa0, 0x7c, 0x7a, 0xb8, 0x64, + 0xde, 0xdb, 0x55, 0x93, 0xed, 0xb9, 0x93, 0x89, 0x83, 0x61, 0x2f, 0x23, + 0x15, 0x91, 0x28, 0xd2, 0x7a, 0x02, 0x69, 0x12, 0x70, 0x19, 0xea, 0xfc, + 0x31, 0xd5, 0xdd, 0x85, 0xeb, 0x81, 0x2f, 0xae, 0xb3, 0x48, 0x94, 0xbe, + 0x57, 0x3b, 0xac, 0x0a, 0x4f, 0x9e, 0x24, 0x2e, 0xae, 0x4e, 0x13, 0x53, + 0x34, 0xe1, 0xcd, 0x66, 0xcc, 0xa6, 0x3a, 0x89, 0x8c, 0x43, 0xef, 0x65, + 0xe7, 0x40, 0xc5, 0x09, 0xb8, 0x36, 0xd6, 0xcd, 0x41, 0xdf, 0x29, 0xbb, + 0x23, 0xa2, 0x54, 0xa5, 0x9f, 0x37, 0x6c, 0xbd, 0x8d, 0xd6, 0x8c, 0x33, + 0xa5, 0xd8, 0x4a, 0xc9, 0x08, 0x35, 0x41, 0xfb, 0xb0, 0x8f, 0x74, 0xdc, + 0xbd, 0x35, 0x01, 0x65, 0xe1, 0x06, 0x6d, 0x41, 0xf4, 0x81, 0x4a, 0xfc, + 0xc3, 0xb3, 0x1c, 0xb7, 0x18, 0xdc, 0x29, 0x4e, 0xea, 0x1b, 0x98, 0xd5, + 0x7d, 0x51, 0x60, 0xcd, 0xfd, 0xdb, 0x74, 0x39, 0x43, 0xa7, 0xc7, 0x0d, + 0xe8, 0x8c, 0xd9, 0xc7, 0xb9, 0xdc, 0x42, 0x08, 0x34, 0x43, 0x2f, 0xf2, + 0x5b, 0xb6, 0x3e, 0x6a, 0x37, 0xb9, 0x08, 0x6a, 0xdf, 0x43, 0x32, 0x0e, + 0x38, 0xd3, 0x3a, 0xeb, 0x13, 0x74, 0xd2, 0x02, 0x36, 0xed, 0xa0, 0x7c, + 0xc8, 0x55, 0xc5, 0xbf, 0x58, 0xbd, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x82, 0x01, 0x01, 0x00, 0x85, 0x0f, 0x93, 0x88, 0x34, 0x8e, 0x89, 0x3d, + 0x01, 0x6f, 0x39, 0xa0, 0xab, 0xd9, 0x68, 0x07, 0x80, 0xff, 0xea, 0xb3, + 0x0a, 0x71, 0xa5, 0xdd, 0xf4, 0x0f, 0xe6, 0x47, 0x06, 0x94, 0x43, 0x4d, + 0xf9, 0x9e, 0x0c, 0x71, 0x19, 0x8b, 0xc0, 0xdb, 0x91, 0x4e, 0x0a, 0x41, + 0xd3, 0x21, 0xf9, 0xdf, 0x85, 0xcd, 0x7d, 0x5f, 0x81, 0xed, 0x68, 0x25, + 0xce, 0x77, 0xb1, 0x32, 0xb8, 0x98, 0xd8, 0xa0, 0x09, 0x8d, 0x43, 0x7f, + 0x2d, 0x78, 0xa5, 0x8e, 0xec, 0xe4, 0x75, 0x0d, 0x56, 0x5e, 0xf8, 0x69, + 0xf3, 0xf8, 0xe6, 0x27, 0x29, 0xf3, 0x9e, 0x0e, 0xc6, 0x1d, 0x01, 0x2f, + 0x2c, 0x62, 0xe5, 0x60, 0x6b, 0x13, 0x5f, 0x95, 0x50, 0x73, 0xef, 0x86, + 0x00, 0x88, 0xda, 0x89, 0x43, 0xaa, 0x75, 0x2a, 0xdf, 0x76, 0xf9, 0x98, + 0x71, 0x65, 0x96, 0x47, 0x72, 0xec, 0x6a, 0x63, 0xcc, 0xca, 0x06, 0xc7, + 0xb6, 0x58, 0x8d, 0x3e, 0x8a, 0x87, 0x4f, 0x5a, 0x5c, 0x1d, 0x82, 0x40, + 0x61, 0x13, 0xed, 0x6d, 0x21, 0x88, 0x1d, 0xb7, 0x70, 0xda, 0xc9, 0x9d, + 0xb2, 0x29, 0x44, 0x0a, 0xf2, 0xdb, 0xaa, 0x1e, 0xdb, 0x0a, 0x92, 0xf8, + 0x42, 0x1d, 0xe6, 0x75, 0x6a, 0xce, 0x2f, 0xd2, 0xea, 0x9d, 0x71, 0x98, + 0x27, 0x0d, 0xf2, 0xc9, 0x60, 0x85, 0x31, 0x88, 0x1c, 0x91, 0x55, 0xe3, + 0xf8, 0x7e, 0xe6, 0xcf, 0x7b, 0x66, 0x27, 0x45, 0x1e, 0xaa, 0x0a, 0x5a, + 0xfe, 0x07, 0x0a, 0x3a, 0xfd, 0x04, 0xdc, 0xae, 0x5a, 0xf3, 0xc5, 0x3d, + 0x18, 0x36, 0x49, 0x97, 0x5c, 0x42, 0xef, 0x9e, 0x4a, 0xcd, 0xa7, 0x23, + 0xca, 0x17, 0xc4, 0x09, 0x55, 0x15, 0xd4, 0x23, 0x7c, 0x19, 0xb2, 0x24, + 0x87, 0x8f, 0x75, 0x70, 0xca, 0xb4, 0x98, 0x33, 0x8a, 0xf2, 0xdd, 0x15, + 0x8d, 0x27, 0x76, 0xe4, 0xbb, 0xbb, 0x23, 0x2d, 0x02, 0x81, 0x81, 0x00, + 0xdc, 0x3b, 0x21, 0x8d, 0xf2, 0x17, 0xff, 0xc1, 0xc6, 0xfb, 0xe2, 0xdb, + 0x29, 0xed, 0x9e, 0xfd, 0xb6, 0xd5, 0xe7, 0x23, 0x29, 0x86, 0xdc, 0x65, + 0xfc, 0x8b, 0x86, 0x39, 0x52, 0x1e, 0xa4, 0x30, 0x72, 0x14, 0x12, 0x24, + 0x72, 0xb4, 0x97, 0x77, 0x61, 0x7c, 0x34, 0x5a, 0x0a, 0x1d, 0x12, 0xfe, + 0xc7, 0x1f, 0x06, 0x79, 0x8c, 0xf5, 0x41, 0xdd, 0x79, 0x8f, 0xeb, 0x17, + 0xf3, 0x32, 0x32, 0x13, 0x37, 0xee, 0x73, 0xeb, 0x82, 0xfa, 0x7b, 0x55, + 0x16, 0xb0, 0x3e, 0x2f, 0x6f, 0xb6, 0xa6, 0x38, 0x99, 0xaf, 0xde, 0xfd, + 0x3a, 0x48, 0xa2, 0x95, 0x70, 0x14, 0x06, 0xf9, 0x10, 0x0f, 0x48, 0x72, + 0x0d, 0x48, 0x69, 0xfc, 0x81, 0xf1, 0x07, 0x5c, 0x99, 0x44, 0xe9, 0x02, + 0xd5, 0x61, 0x36, 0x31, 0x64, 0x02, 0x5a, 0x1d, 0x3e, 0xae, 0xde, 0x08, + 0xd2, 0xde, 0x42, 0xac, 0xf1, 0xe1, 0x38, 0x9f, 0x02, 0x81, 0x81, 0x00, + 0xc1, 0x31, 0xe3, 0x45, 0xec, 0x53, 0xa5, 0x56, 0xe0, 0xc1, 0xe3, 0xf2, + 0xeb, 0xb0, 0xe5, 0x84, 0xdd, 0x56, 0x59, 0x7c, 0xf4, 0x65, 0x66, 0x8c, + 0x9c, 0x66, 0x55, 0x2a, 0x2c, 0x3c, 0x46, 0xf7, 0xac, 0x36, 0xd8, 0x2f, + 0x27, 0x97, 0x57, 0x64, 0x6e, 0xc7, 0x5f, 0x43, 0xf9, 0x82, 0x27, 0xf3, + 0xc4, 0xfa, 0xc6, 0xb1, 0xea, 0x2d, 0xcc, 0x36, 0x3a, 0x37, 0x22, 0xb6, + 0x7e, 0x6a, 0x25, 0xab, 0x1a, 0xd2, 0x3e, 0x38, 0x38, 0x9d, 0x04, 0xc0, + 0xc7, 0x4a, 0xa2, 0x38, 0xb4, 0xcf, 0x9c, 0x97, 0x4c, 0x03, 0x76, 0x37, + 0x86, 0x09, 0x1e, 0x25, 0x2b, 0x67, 0x8e, 0x7b, 0xce, 0x3d, 0x50, 0xf6, + 0x7a, 0x8b, 0x00, 0x23, 0x48, 0xda, 0x6e, 0xbe, 0x4c, 0x23, 0xdb, 0x9c, + 0x4f, 0x3f, 0xa9, 0x18, 0x59, 0xf6, 0xc4, 0x33, 0xc5, 0xaa, 0x75, 0x40, + 0xf7, 0xba, 0xfc, 0x83, 0x40, 0x36, 0x85, 0x23, 0x02, 0x81, 0x80, 0x68, + 0xd9, 0xf6, 0x35, 0xc0, 0x87, 0x50, 0x8b, 0x0f, 0x93, 0xa9, 0x04, 0x33, + 0x48, 0x20, 0xa4, 0x26, 0xc2, 0x5c, 0x53, 0x4f, 0x58, 0x17, 0xe2, 0xae, + 0x84, 0x37, 0x19, 0x5f, 0x51, 0x9b, 0x56, 0x3d, 0x59, 0xf4, 0xf1, 0x49, + 0x73, 0x55, 0x91, 0xce, 0xe5, 0xf5, 0x7e, 0xd0, 0xc5, 0xda, 0xdf, 0x56, + 0x2a, 0x1d, 0x49, 0x0d, 0xa5, 0x4f, 0x00, 0x84, 0xf9, 0xd2, 0x32, 0x0a, + 0xe5, 0x61, 0x15, 0xe9, 0x51, 0x2b, 0xfb, 0x7a, 0xd6, 0x8a, 0x95, 0x8e, + 0x41, 0xc6, 0xb9, 0x8a, 0xf4, 0x68, 0xdb, 0x15, 0xc0, 0xb7, 0xe7, 0xd4, + 0x31, 0xf4, 0xc6, 0x35, 0x20, 0x33, 0xd9, 0xac, 0x9d, 0xba, 0x1e, 0x22, + 0xd8, 0xd1, 0x2d, 0x19, 0x28, 0x8a, 0x1a, 0xba, 0x16, 0x26, 0xe1, 0xe4, + 0x79, 0x6d, 0xf5, 0xc1, 0xe9, 0xa4, 0xc1, 0xbb, 0xb0, 0x41, 0xa1, 0xed, + 0xd3, 0x47, 0xe7, 0x53, 0x19, 0xa9, 0x7d, 0x02, 0x81, 0x81, 0x00, 0xb4, + 0xd6, 0x5e, 0xb7, 0xd7, 0xe3, 0xe0, 0x13, 0x37, 0x65, 0x26, 0x5a, 0xff, + 0x75, 0x61, 0x12, 0x02, 0x20, 0xce, 0xb9, 0x21, 0x07, 0x3d, 0x7b, 0x86, + 0xf6, 0x5e, 0xe7, 0x8f, 0xea, 0x88, 0x3f, 0x53, 0x4b, 0x2f, 0x06, 0xcc, + 0x97, 0x64, 0x2d, 0x55, 0x68, 0x77, 0xea, 0xe7, 0xc5, 0x86, 0x62, 0x2e, + 0xd2, 0xd2, 0x64, 0x3d, 0x20, 0xcb, 0x53, 0x43, 0x20, 0xd2, 0xf4, 0x61, + 0xd6, 0x38, 0x16, 0x36, 0x8f, 0xef, 0xbf, 0xae, 0x76, 0x83, 0xb9, 0x73, + 0x92, 0x8f, 0xd0, 0x66, 0xa7, 0x23, 0x1b, 0x98, 0x02, 0x71, 0x88, 0xbd, + 0x85, 0x11, 0x5b, 0x97, 0x8a, 0x62, 0x9b, 0xce, 0xcc, 0x24, 0x59, 0xe3, + 0x10, 0xf3, 0x7b, 0x13, 0xb9, 0xab, 0x09, 0xa3, 0xb9, 0xb8, 0xda, 0x52, + 0x6f, 0xf3, 0x77, 0x20, 0xd6, 0xd4, 0x86, 0xe5, 0x92, 0x8e, 0x18, 0xd7, + 0x0a, 0x87, 0x4c, 0xd0, 0x31, 0x78, 0x63, 0x02, 0x81, 0x81, 0x00, 0xc2, + 0x8c, 0xea, 0xa2, 0x9b, 0xfa, 0x42, 0x98, 0x70, 0x5a, 0xf9, 0x73, 0x78, + 0xee, 0xd6, 0x2b, 0x3e, 0x5b, 0xf4, 0x2f, 0x84, 0x60, 0x71, 0x9b, 0xce, + 0xf4, 0x9b, 0x88, 0x25, 0x0a, 0x29, 0x41, 0x4b, 0x4d, 0x36, 0xcf, 0xd9, + 0x86, 0xac, 0x75, 0xa2, 0xed, 0x56, 0x5b, 0x6e, 0x87, 0x1e, 0x32, 0x04, + 0x13, 0xaf, 0xa5, 0x1e, 0xf5, 0x0f, 0x9d, 0x93, 0x4a, 0x29, 0x90, 0x23, + 0x0e, 0xf9, 0x8e, 0xfd, 0x2d, 0xfe, 0x2b, 0x79, 0xa6, 0x03, 0x6c, 0xcd, + 0x01, 0xee, 0xba, 0x69, 0xb3, 0xb9, 0xd4, 0xc8, 0x99, 0x0f, 0x72, 0xba, + 0x59, 0x22, 0xdc, 0x2d, 0xc3, 0x97, 0x8c, 0xa7, 0xb3, 0xbf, 0x60, 0xe1, + 0x61, 0xe5, 0xd4, 0x51, 0x6f, 0x36, 0x9c, 0x9a, 0xb8, 0x1b, 0x52, 0xec, + 0x13, 0xf3, 0xa7, 0xdb, 0xdb, 0x5d, 0x89, 0x2d, 0xd7, 0x02, 0x96, 0xaf, + 0xeb, 0x72, 0x8d, 0xd5, 0x56, 0x3b, 0x3a}; + +// TODO(fredgc): duplicate code. Move to common util package. +// Return a printable string from data. If all the characters are printable, +// then just use the string. Otherwise, convert to hex. +std::string MaybeHex(const uint8_t* data, size_t length) { + for (size_t i = 0; i < length; i++) { + if (!isprint(data[i])) return "0x" + wvutil::HexEncode(data, length); + } + return std::string(reinterpret_cast(data), length); +} +std::string MaybeHex(const std::vector& data) { + return MaybeHex(data.data(), data.size()); +} + +std::vector GetModelKey(const std::vector& device_id) { + std::vector keymint_key( + TestKeyPKCS8, TestKeyPKCS8 + wvutil::ArraySize(TestKeyPKCS8)); + keymint_key.insert(keymint_key.end(), device_id.begin(), device_id.end()); + std::vector key(SHA256_DIGEST_LENGTH); + SHA256(keymint_key.data(), keymint_key.size(), key.data()); + key.resize(wvoec::KEY_SIZE); // Truncate to standard AES 128 key. + return key; +} + +} // namespace + +class OTAKeyboxProvisioningTest : public ::testing::Test, public SessionUtil { + protected: + void SetUp() override { + ::testing::Test::SetUp(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } + + void TearDown() override { + OEMCrypto_Terminate(); + ::testing::Test::TearDown(); + } +}; + +TEST_F(OTAKeyboxProvisioningTest, BasicTest) { + OEMCryptoResult result = OEMCrypto_IsKeyboxValid(); + if (result == OEMCrypto_SUCCESS) { + cout << " " + << "Keybox valid after initialization. Skipping rest of test." << endl; + return; + } + ASSERT_EQ(result, OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING); + cout << " " + << "OTA Keybox functions supported. Device needs provisioning." << endl; + // TODO(fredgc): Make sure that partners can use a test cert when use_test_key + // is true. + constexpr uint32_t use_test_key = 1; + size_t request_length = 0; + std::vector request; + + OEMCrypto_SESSION session_id; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session_id)); + + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + OEMCrypto_GenerateOTARequest(session_id, nullptr, &request_length, + use_test_key)); + ASSERT_NE(request_length, 0u); + request.resize(request_length); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GenerateOTARequest(session_id, request.data(), + &request_length, use_test_key)); + ASSERT_GT(request_length, kMinimumRequestLength); + request.resize(request_length); + // First 16 bytes should match the label for Option 1 or 2. + // TODO(fredgc): Write tests for Option 1 -- only Option 2 is tested now. + EXPECT_EQ(kOption2Label.length(), kLabelLength); + const uint8_t* label_ptr = request.data(); + EXPECT_EQ(kOption2Label, std::string(label_ptr, label_ptr + kLabelLength)); + // Next 32 bytes are the device id. + const uint8_t* device_id_ptr = label_ptr + kLabelLength; + const std::vector device_id(device_id_ptr, + device_id_ptr + kDeviceIdLength); + LOGD("Device id is %s", MaybeHex(device_id).c_str()); + // Next 4 bytes say that this is a cert. + uint32_t cert_length; + const uint8_t* cert_length_ptr = device_id_ptr + kDeviceIdLength; + memcpy(&cert_length, cert_length_ptr, sizeof(uint32_t)); + cert_length = ntohl(cert_length); + LOGD("Cert Length is 0x%x = %u", cert_length, cert_length); + ASSERT_EQ(request_length, kMinimumRequestLength + cert_length); + const uint8_t* cert_ptr = cert_length_ptr + sizeof(uint32_t); + const std::vector cert(cert_ptr, cert_ptr + cert_length); + LOGD("x509 attestation cert = %s", MaybeHex(cert).c_str()); + const uint8_t* signature_ptr = cert_ptr + cert_length; + const std::vector signature( + signature_ptr, signature_ptr + HMAC_SHA256_SIGNATURE_SIZE); + +#if 0 + // This unit test only works with the test model key. + const std::vector model_key = + wvcdm::a2b_hex("0102030405060708090a0b0c0d0e0f10"); +#else + // This unit test only works with the test cert's private key. + const std::vector model_key = GetModelKey(device_id); +#endif + // The server should derive the same set of keys as the client. + const std::string mac_label = "WV_SIGN"; + std::vector mac_context(mac_label.begin(), mac_label.end()); + mac_context.push_back(0); + std::copy(cert.begin(), cert.end(), std::back_inserter(mac_context)); + std::copy(device_id.begin(), device_id.end(), + std::back_inserter(mac_context)); + uint32_t bit_size = MAC_KEY_SIZE * 8 * 2; + std::string bit_size_string = wvutil::EncodeUint32(bit_size); + std::copy(bit_size_string.begin(), bit_size_string.end(), + std::back_inserter(mac_context)); + std::string enc_label = "WV_ENCRYPT"; + std::vector enc_context(enc_label.begin(), enc_label.end()); + enc_context.push_back(0); + std::copy(cert.begin(), cert.end(), std::back_inserter(enc_context)); + std::copy(device_id.begin(), device_id.end(), + std::back_inserter(enc_context)); + bit_size = KEY_SIZE * 8; + bit_size_string = wvutil::EncodeUint32(bit_size); + std::copy(bit_size_string.begin(), bit_size_string.end(), + std::back_inserter(enc_context)); + KeyDeriver keys; + keys.DeriveKeys(model_key.data(), mac_context, enc_context); + const std::vector message( + request.data(), + request.data() + request.size() - HMAC_SHA256_SIGNATURE_SIZE); + // Once the keys have been derived, the server should verify the signature. + std::vector computed_signature; + keys.ClientSignBuffer(message, &computed_signature); + ASSERT_EQ(signature, computed_signature); + + // The server should randomly pick an iv. + uint8_t iv[wvoec::KEY_IV_SIZE]; + EXPECT_EQ(GetRandBytes(iv, KEY_IV_SIZE), 1); + // Encrypt the keybox. + std::vector encrypted_keybox(sizeof(WidevineKeybox)); + keys.CBCEncrypt(reinterpret_cast(&kTestKeybox), + encrypted_keybox.data(), sizeof(WidevineKeybox), iv); + std::vector response(iv, iv + wvoec::KEY_IV_SIZE); + std::copy(encrypted_keybox.begin(), encrypted_keybox.end(), + std::back_inserter(response)); + std::vector response_signature; + // Sign the iv + encrypted keybox. + keys.ServerSignBuffer(response.data(), response.size(), &response_signature); + std::copy(response_signature.begin(), response_signature.end(), + std::back_inserter(response)); + // Finally, send the response back to the device. + EXPECT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_ProcessOTAKeybox(session_id, response.data(), + response.size(), use_test_key)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session_id)); + // After installation, the keybox should be valid. + EXPECT_EQ(OEMCrypto_IsKeyboxValid(), OEMCrypto_SUCCESS); +} +} // namespace wvoec diff --git a/oemcrypto/test/test_rsa_key.der b/oemcrypto/test/test_rsa_key.der new file mode 100644 index 0000000..b6752ee Binary files /dev/null and b/oemcrypto/test/test_rsa_key.der differ diff --git a/util/include/advance_iv_ctr.h b/util/include/advance_iv_ctr.h index db69414..a8a6c60 100644 --- a/util/include/advance_iv_ctr.h +++ b/util/include/advance_iv_ctr.h @@ -10,7 +10,7 @@ #include "string_conversions.h" -namespace wvcdm { +namespace wvutil { // Advance an IV according to ISO-CENC's CTR modes. The lower half of the IV is // split off and treated as an unsigned 64-bit integer, then incremented by the @@ -41,6 +41,6 @@ inline void AdvanceIvCtr(uint8_t (*subsample_iv)[16], size_t bytes) { memcpy(&(*subsample_iv)[kCounterIndex], &counter, kCounterSize); } -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_ADVANCE_IV_CTR_H_ diff --git a/util/include/arraysize.h b/util/include/arraysize.h index 5b5c843..0750fc0 100644 --- a/util/include/arraysize.h +++ b/util/include/arraysize.h @@ -7,7 +7,7 @@ #include -namespace wvcdm { +namespace wvutil { // Returns the size of a fixed-length array. template @@ -15,6 +15,6 @@ constexpr size_t ArraySize(const T (&)[N]) { return N; } -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_ARRAYSIZE_H_ diff --git a/util/include/cdm_random.h b/util/include/cdm_random.h index 744b10e..ba2f2f5 100644 --- a/util/include/cdm_random.h +++ b/util/include/cdm_random.h @@ -8,7 +8,7 @@ #include #include -namespace wvcdm { +namespace wvutil { // CdmRandomGenerator is a thread safe, pseudo-random number generator. // It's purpose is to simplified interface for C++11's library. @@ -112,6 +112,6 @@ class CdmRandom { static CdmRandomGenerator* GetInstance(); }; -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_CORE_CDM_RANDOM_H_ diff --git a/util/include/clock.h b/util/include/clock.h index 4ec5905..98e7ab6 100644 --- a/util/include/clock.h +++ b/util/include/clock.h @@ -9,7 +9,7 @@ #include -namespace wvcdm { +namespace wvutil { // Provides time related information. The implementation is platform dependent. class Clock { @@ -21,6 +21,6 @@ class Clock { virtual int64_t GetCurrentTime(); }; -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_CLOCK_H_ diff --git a/util/include/disallow_copy_and_assign.h b/util/include/disallow_copy_and_assign.h index 9d38907..451b72a 100644 --- a/util/include/disallow_copy_and_assign.h +++ b/util/include/disallow_copy_and_assign.h @@ -5,12 +5,12 @@ #ifndef WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_ #define WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_ -namespace wvcdm { +namespace wvutil { #define CORE_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_DISALLOW_COPY_AND_ASSIGN_H_ diff --git a/util/include/file_store.h b/util/include/file_store.h index 94dded6..8594356 100644 --- a/util/include/file_store.h +++ b/util/include/file_store.h @@ -16,7 +16,16 @@ #include "platform.h" #include "util_common.h" -namespace wvcdm { +namespace wvutil { + +static const std::string kAtscCertificateFileName = "atsccert.bin"; +static const std::string kCertificateFileName = "cert1.bin"; +static const std::string kCertificateFileNameExt = ".bin"; +static const std::string kCertificateFileNamePrefix = "cert1_"; +static const std::string kLegacyCertificateFileName = "cert.bin"; +static const std::string kLegacyCertificateFileNamePrefix = "cert"; +static const std::string kOemCertificateFileName = "oemcert.bin"; +static const std::string kOemCertificateFileNamePrefix = "oemcert_"; // File class. The implementation is platform dependent. class CORE_UTIL_EXPORT File { @@ -72,6 +81,6 @@ class CORE_UTIL_EXPORT FileSystem { CORE_DISALLOW_COPY_AND_ASSIGN(FileSystem); }; -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_FILE_STORE_H_ diff --git a/util/include/log.h b/util/include/log.h index 5d945e4..bff7205 100644 --- a/util/include/log.h +++ b/util/include/log.h @@ -7,9 +7,15 @@ #ifndef WVCDM_UTIL_LOG_H_ #define WVCDM_UTIL_LOG_H_ +#include +#include +#include +#include +#include + #include "util_common.h" -namespace wvcdm { +namespace wvutil { // Simple logging class. The implementation is platform dependent. @@ -27,15 +33,53 @@ typedef enum { extern LogPriority g_cutoff; +struct LogMessage { + uint32_t uid_; + int64_t time_ms_; + LogPriority priority_; + std::string message_; +}; + +class LogBuffer { + public: + static const int MAX_CAPACITY = 100; + void addLog(const LogMessage& log); + std::vector getLogs(); + + private: + std::deque buffer_; + std::mutex mutex_; +}; + +extern LogBuffer g_logbuf; + +static const uint32_t UNKNOWN_UID = ~0; + +#ifdef __ANDROID__ +void SetLoggingUid(const uint32_t); +void ClearLoggingUid(); +uint32_t GetLoggingUid(); +uint32_t GetIpcCallingUid(); +#else +static inline void SetLoggingUid(const uint32_t) {} +static inline void ClearLoggingUid() {} +static inline uint32_t GetLoggingUid() { return UNKNOWN_UID; } +static inline uint32_t GetIpcCallingUid() { return UNKNOWN_UID; } +#endif + +struct LoggingUidSetter { + LoggingUidSetter() {} + LoggingUidSetter(uint32_t uid) { SetLoggingUid(uid); } + virtual ~LoggingUidSetter() { ClearLoggingUid(); } +}; + // Enable/disable verbose logging (LOGV). // This function is supplied for cases where the system layer does not // initialize logging. This is also needed to initialize logging in // unit tests. CORE_UTIL_EXPORT void InitLogging(); -// Only enable format specifier warnings on LP64 systems. There is -// no easy portable method to handle format specifiers for int64_t. -#if (defined(__GNUC__) || defined(__clang__)) && defined(__LP64__) +#ifdef __GNUC__ [[gnu::format(printf, 5, 6)]] CORE_UTIL_EXPORT void Log(const char* file, const char* function, int line, @@ -49,16 +93,16 @@ CORE_UTIL_EXPORT void Log(const char* file, const char* function, int line, // Log APIs #ifndef LOGE # define LOGE(...) \ - Log(__FILE__, __func__, __LINE__, wvcdm::LOG_ERROR, __VA_ARGS__) + Log(__FILE__, __func__, __LINE__, wvutil::LOG_ERROR, __VA_ARGS__) # define LOGW(...) \ - Log(__FILE__, __func__, __LINE__, wvcdm::LOG_WARN, __VA_ARGS__) + Log(__FILE__, __func__, __LINE__, wvutil::LOG_WARN, __VA_ARGS__) # define LOGI(...) \ - Log(__FILE__, __func__, __LINE__, wvcdm::LOG_INFO, __VA_ARGS__) + Log(__FILE__, __func__, __LINE__, wvutil::LOG_INFO, __VA_ARGS__) # define LOGD(...) \ - Log(__FILE__, __func__, __LINE__, wvcdm::LOG_DEBUG, __VA_ARGS__) + Log(__FILE__, __func__, __LINE__, wvutil::LOG_DEBUG, __VA_ARGS__) # define LOGV(...) \ - Log(__FILE__, __func__, __LINE__, wvcdm::LOG_VERBOSE, __VA_ARGS__) + Log(__FILE__, __func__, __LINE__, wvutil::LOG_VERBOSE, __VA_ARGS__) #endif -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_LOG_H_ diff --git a/util/include/rw_lock.h b/util/include/rw_lock.h index 6082443..5ea3a97 100644 --- a/util/include/rw_lock.h +++ b/util/include/rw_lock.h @@ -13,7 +13,7 @@ #include "disallow_copy_and_assign.h" #include "util_common.h" -namespace wvcdm { +namespace wvutil { // A simple reader-writer mutex implementation that mimics the one from C++17 class CORE_UTIL_EXPORT shared_mutex { @@ -60,6 +60,6 @@ class shared_lock { CORE_DISALLOW_COPY_AND_ASSIGN(shared_lock); }; -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_RW_LOCK_H_ diff --git a/util/include/string_conversions.h b/util/include/string_conversions.h index feff9dc..471d2fe 100644 --- a/util/include/string_conversions.h +++ b/util/include/string_conversions.h @@ -1,7 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. - #ifndef WVCDM_UTIL_STRING_CONVERSIONS_H_ #define WVCDM_UTIL_STRING_CONVERSIONS_H_ @@ -13,32 +12,52 @@ #include "util_common.h" -namespace wvcdm { +namespace wvutil { +// ASCII hex to Binary conversion. CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& b); CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& label, const std::string& b); CORE_UTIL_EXPORT std::string a2bs_hex(const std::string& b); + +// Binary to ASCII hex conversion. CORE_UTIL_EXPORT std::string b2a_hex(const std::vector& b); CORE_UTIL_EXPORT std::string b2a_hex(const std::string& b); +CORE_UTIL_EXPORT std::string HexEncode(const uint8_t* bytes, size_t size); + +// Base64 encoding/decoding. +// Converts binary data into the ASCII Base64 character set and vice +// versa using the encoding rules defined in RFC4648 section 4. CORE_UTIL_EXPORT std::string Base64Encode( const std::vector& bin_input); +CORE_UTIL_EXPORT std::string Base64Encode(const std::string& bin_input); CORE_UTIL_EXPORT std::vector Base64Decode( const std::string& bin_input); + +// URL-Safe Base64 encoding/decoding. +// Converts binary data into the URL/Filename safe ASCII Base64 +// character set and vice versa using the encoding rules defined in +// RFC4648 section 5. CORE_UTIL_EXPORT std::string Base64SafeEncode( const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( - const std::vector& bin_input); +CORE_UTIL_EXPORT std::string Base64SafeEncode(const std::string& bin_input); CORE_UTIL_EXPORT std::vector Base64SafeDecode( const std::string& bin_input); -CORE_UTIL_EXPORT std::string HexEncode(const uint8_t* bytes, unsigned size); -CORE_UTIL_EXPORT std::string IntToString(int value); +// URL-Safe Base64 encoding without padding. +// Similar to Base64SafeEncode(), without any padding character '=' +// at the end. +CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( + const std::vector& bin_input); +CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( + const std::string& bin_input); + +// Host to Network/Network to Host conversion. CORE_UTIL_EXPORT int64_t htonll64(int64_t x); CORE_UTIL_EXPORT inline int64_t ntohll64(int64_t x) { return htonll64(x); } -CORE_UTIL_EXPORT std::string BytesToString(const uint8_t* bytes, unsigned size); -// Encode unsigned integer into a big endian formatted string -CORE_UTIL_EXPORT std::string EncodeUint32(unsigned int u); -} // namespace wvcdm +// Encode unsigned integer into a big endian formatted string. +CORE_UTIL_EXPORT std::string EncodeUint32(uint32_t u); + +} // namespace wvutil #endif // WVCDM_UTIL_STRING_CONVERSIONS_H_ diff --git a/util/include/util_common.h b/util/include/util_common.h index 4477ca1..7b28c48 100644 --- a/util/include/util_common.h +++ b/util/include/util_common.h @@ -5,18 +5,53 @@ #ifndef WVCDM_UTIL_UTIL_COMMON_H_ #define WVCDM_UTIL_UTIL_COMMON_H_ +// This section deals with defines that are platform-specific. + #ifdef _WIN32 + # ifdef CORE_UTIL_IMPLEMENTATION # define CORE_UTIL_EXPORT __declspec(dllexport) # else # define CORE_UTIL_EXPORT __declspec(dllimport) # endif + +# define CORE_UTIL_IGNORE_DEPRECATED +# define CORE_UTIL_RESTORE_WARNINGS + #else + # ifdef CORE_UTIL_IMPLEMENTATION # define CORE_UTIL_EXPORT __attribute__((visibility("default"))) # else # define CORE_UTIL_EXPORT # endif + +# ifdef __GNUC__ +# define CORE_UTIL_IGNORE_DEPRECATED \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define CORE_UTIL_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") +# else +# define CORE_UTIL_IGNORE_DEPRECATED +# define CORE_UTIL_RESTORE_WARNINGS +# endif + +#endif + +// This section deals with attribute-detection and is platform-agnostic. + +#if !defined(__has_cpp_attribute) +# define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(fallthrough) +# define CORE_UTIL_FALLTHROUGH [[fallthrough]] +#elif __has_cpp_attribute(clang::fallthrough) +# define CORE_UTIL_FALLTHROUGH [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +# define CORE_UTIL_FALLTHROUGH [[gnu::fallthrough]] +#else +# define CORE_UTIL_FALLTHROUGH #endif #endif // WVCDM_UTIL_UTIL_COMMON_H_ diff --git a/util/include/wv_attributes.h b/util/include/wv_attributes.h new file mode 100644 index 0000000..c817f1c --- /dev/null +++ b/util/include/wv_attributes.h @@ -0,0 +1,16 @@ +// Copyright 2021 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef WVCDM_UTIL_WV_ATTRIBUTES_H_ +#define WVCDM_UTIL_WV_ATTRIBUTES_H_ + +#ifndef UNUSED +# if defined(__GNUC__) || defined(__clang__) +# define UNUSED __attribute__((__unused__)) +# else +# define UNUSED +# endif +#endif + +#endif // WVCDM_UTIL_WV_ATTRIBUTES_H_ diff --git a/util/src/cdm_random.cpp b/util/src/cdm_random.cpp index ca4020a..b8dce14 100644 --- a/util/src/cdm_random.cpp +++ b/util/src/cdm_random.cpp @@ -13,7 +13,7 @@ // This type alias is for convenience. using CdmRandomLock = std::unique_lock; -namespace wvcdm { +namespace wvutil { namespace { // More information about C++11's random number generators can be found @@ -104,4 +104,4 @@ CdmRandomGenerator* CdmRandom::GetInstance() { return g_instance; } -} // namespace wvcdm +} // namespace wvutil diff --git a/util/src/rw_lock.cpp b/util/src/rw_lock.cpp index f962017..96218a2 100644 --- a/util/src/rw_lock.cpp +++ b/util/src/rw_lock.cpp @@ -6,7 +6,7 @@ #include "log.h" -namespace wvcdm { +namespace wvutil { shared_mutex::~shared_mutex() { if (reader_count_ > 0) { @@ -57,4 +57,4 @@ void shared_mutex::unlock() { condition_variable_.notify_all(); } -} // namespace wvcdm +} // namespace wvutil diff --git a/util/src/string_conversions.cpp b/util/src/string_conversions.cpp index e40e6f7..9fd3251 100644 --- a/util/src/string_conversions.cpp +++ b/util/src/string_conversions.cpp @@ -10,15 +10,18 @@ #include #include -#include #include "log.h" #include "platform.h" -namespace wvcdm { - -static const char kBase64Codes[] = +namespace wvutil { +namespace { +// Base64 character set, indexed for their 6-bit mapping, plus '='. +const char kBase64Codes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +// URL safe Base64 character set. +const char kBase64SafeCodes[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; // Gets the low |n| bits of |in|. #define GET_LOW_BITS(in, n) ((in) & ((1 << (n)) - 1)) @@ -27,32 +30,139 @@ static const char kBase64Codes[] = // Calculates a/b using round-up division (only works for positive numbers). #define CEIL_DIVIDE(a, b) ((((a)-1) / (b)) + 1) -int DecodeBase64Char(char c) { - const char* it = strchr(kBase64Codes, c); - if (it == nullptr) return -1; - return it - kBase64Codes; +// Decodes a single Base64 encoded character into its 6-bit value. +// The provided |codes| must be a Base64 character map. +int DecodeBase64Char(char c, const char* codes) { + const char* c_in_codes = strchr(codes, c); + if (c_in_codes == nullptr) return -1; + const uintptr_t c_in_codes_int = reinterpret_cast(c_in_codes); + const uintptr_t codes_int = reinterpret_cast(codes); + return static_cast(c_in_codes_int - codes_int); } -bool DecodeHexChar(char ch, unsigned char* digit) { +bool DecodeHexChar(char ch, uint8_t* digit) { if (ch >= '0' && ch <= '9') { *digit = ch - '0'; - } else { - ch = tolower(ch); - if ((ch >= 'a') && (ch <= 'f')) { - *digit = ch - 'a' + 10; - } else { - return false; + return true; + } + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) { + *digit = ch - 'a' + 10; + return true; + } + return false; +} + +// Encode for standard base64 encoding (RFC4648). +// https://en.wikipedia.org/wiki/Base64 +// Text | M | a | n | +// ASCI | 77 (0x4d) | 97 (0x61) | 110 (0x6e) | +// Bits | 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0 | +// Index | 19 | 22 | 5 | 46 | +// Base64 | T | W | F | u | +// | <----------------- 24-bits -----------------> | + +// The provided |codes| must be a Base64 character map. +std::string Base64EncodeInternal(const uint8_t* data, size_t length, + const char* codes) { + // |temp| stores a 24-bit block that is treated as an array where insertions + // occur from high to low. + uint32_t temp = 0; + size_t out_index = 0; + const size_t out_size = CEIL_DIVIDE(length, 3) * 4; + std::string result(out_size, '\0'); + for (size_t i = 0; i < length; i++) { + // "insert" 8-bits of data + temp |= (data[i] << ((2 - (i % 3)) * 8)); + if (i % 3 == 2) { + result[out_index++] = codes[GET_BITS(temp, 18, 24)]; + result[out_index++] = codes[GET_BITS(temp, 12, 18)]; + result[out_index++] = codes[GET_BITS(temp, 6, 12)]; + result[out_index++] = codes[GET_BITS(temp, 0, 6)]; + temp = 0; } } - return true; + if (length % 3 == 1) { + result[out_index++] = codes[GET_BITS(temp, 18, 24)]; + result[out_index++] = codes[GET_BITS(temp, 12, 18)]; + result[out_index++] = '='; + result[out_index++] = '='; + } else if (length % 3 == 2) { + result[out_index++] = codes[GET_BITS(temp, 18, 24)]; + result[out_index++] = codes[GET_BITS(temp, 12, 18)]; + result[out_index++] = codes[GET_BITS(temp, 6, 12)]; + result[out_index++] = '='; + } + return result; } +std::vector Base64DecodeInternal(const char* encoded, size_t length, + const char* codes) { + const size_t out_size_max = CEIL_DIVIDE(length * 3, 4); + std::vector result(out_size_max, '\0'); + // |temp| stores 24-bits of data that is treated as an array where insertions + // occur from high to low. + uint32_t temp = 0; + size_t out_index = 0; + size_t i; + for (i = 0; i < length; i++) { + if (encoded[i] == '=') { + // Verify an '=' only appears at the end. We want i to remain at the + // first '=', so we need an inner loop. + for (size_t j = i; j < length; j++) { + if (encoded[j] != '=') { + LOGE("base64Decode failed"); + return std::vector(); + } + } + if (length % 4 != 0) { + // If padded, then the length must be a multiple of 4. + // Unpadded messages are OK. + LOGE("base64Decode failed"); + return std::vector(); + } + break; + } + + const int decoded = DecodeBase64Char(encoded[i], codes); + if (decoded < 0) { + LOGE("base64Decode failed"); + return std::vector(); + } + // "insert" 6-bits of data + temp |= (decoded << ((3 - (i % 4)) * 6)); + + if (i % 4 == 3) { + result[out_index++] = GET_BITS(temp, 16, 24); + result[out_index++] = GET_BITS(temp, 8, 16); + result[out_index++] = GET_BITS(temp, 0, 8); + temp = 0; + } + } + + switch (i % 4) { + case 1: + LOGE("base64Decode failed"); + return std::vector(); + case 2: + result[out_index++] = GET_BITS(temp, 16, 24); + break; + case 3: + result[out_index++] = GET_BITS(temp, 16, 24); + result[out_index++] = GET_BITS(temp, 8, 16); + break; + } + result.resize(out_index); + return result; +} +} // namespace + // converts an ascii hex string(2 bytes per digit) into a decimal byte string std::vector a2b_hex(const std::string& byte) { std::vector array; - unsigned int count = byte.size(); + size_t count = byte.size(); if (count == 0 || (count % 2) != 0) { - LOGE("Invalid input size %u for string %s", count, byte.c_str()); + LOGE("Invalid input size %zu for string %s", count, byte.c_str()); return array; } @@ -97,161 +207,7 @@ std::string b2a_hex(const std::string& byte) { byte.length()); } -// Encode for standard base64 encoding (RFC4648). -// https://en.wikipedia.org/wiki/Base64 -// Text | M | a | n | -// ASCI | 77 (0x4d) | 97 (0x61) | 110 (0x6e) | -// Bits | 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0 | -// Index | 19 | 22 | 5 | 46 | -// Base64 | T | W | F | u | -// | <----------------- 24-bits -----------------> | -std::string Base64Encode(const std::vector& bin_input) { - if (bin_input.empty()) { - return std::string(); - } - - // |temp| stores a 24-bit block that is treated as an array where insertions - // occur from high to low. - uint32_t temp = 0; - size_t out_index = 0; - const size_t out_size = CEIL_DIVIDE(bin_input.size(), 3) * 4; - std::string result(out_size, '\0'); - for (size_t i = 0; i < bin_input.size(); i++) { - // "insert" 8-bits of data - temp |= (bin_input[i] << ((2 - (i % 3)) * 8)); - - if (i % 3 == 2) { - result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 6, 12)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 0, 6)]; - temp = 0; - } - } - - if (bin_input.size() % 3 == 1) { - result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)]; - result[out_index++] = '='; - result[out_index++] = '='; - } else if (bin_input.size() % 3 == 2) { - result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 6, 12)]; - result[out_index++] = '='; - } - - return result; -} - -// Filename-friendly base64 encoding (RFC4648), commonly referred to -// as Base64WebSafeEncode. -// -// This is the encoding required to interface with the provisioning server, as -// well as for certain license server transactions. It is also used for logging -// certain strings. The difference between web safe encoding vs regular encoding -// is that the web safe version replaces '+' with '-' and '/' with '_'. -std::string Base64SafeEncode(const std::vector& bin_input) { - if (bin_input.empty()) { - return std::string(); - } - - std::string ret = Base64Encode(bin_input); - for (size_t i = 0; i < ret.size(); i++) { - if (ret[i] == '+') - ret[i] = '-'; - else if (ret[i] == '/') - ret[i] = '_'; - } - return ret; -} - -std::string Base64SafeEncodeNoPad(const std::vector& bin_input) { - std::string b64_output = Base64SafeEncode(bin_input); - // Output size: ceiling [ bin_input.size() * 4 / 3 ]. - b64_output.resize((bin_input.size() * 4 + 2) / 3); - return b64_output; -} - -// Decode for standard base64 encoding (RFC4648). -std::vector Base64Decode(const std::string& b64_input) { - if (b64_input.empty()) { - return std::vector(); - } - - const size_t out_size_max = CEIL_DIVIDE(b64_input.size() * 3, 4); - std::vector result(out_size_max, '\0'); - - // |temp| stores 24-bits of data that is treated as an array where insertions - // occur from high to low. - uint32_t temp = 0; - size_t out_index = 0; - size_t i; - for (i = 0; i < b64_input.size(); i++) { - if (b64_input[i] == '=') { - // Verify an '=' only appears at the end. We want i to remain at the - // first '=', so we need an inner loop. - for (size_t j = i; j < b64_input.size(); j++) { - if (b64_input[j] != '=') { - LOGE("base64Decode failed"); - return std::vector(); - } - } - break; - } - - const int decoded = DecodeBase64Char(b64_input[i]); - if (decoded < 0) { - LOGE("base64Decode failed"); - return std::vector(); - } - // "insert" 6-bits of data - temp |= (decoded << ((3 - (i % 4)) * 6)); - - if (i % 4 == 3) { - result[out_index++] = GET_BITS(temp, 16, 24); - result[out_index++] = GET_BITS(temp, 8, 16); - result[out_index++] = GET_BITS(temp, 0, 8); - temp = 0; - } - } - - switch (i % 4) { - case 1: - LOGE("base64Decode failed"); - return std::vector(); - case 2: - result[out_index++] = GET_BITS(temp, 16, 24); - break; - case 3: - result[out_index++] = GET_BITS(temp, 16, 24); - result[out_index++] = GET_BITS(temp, 8, 16); - break; - } - result.resize(out_index); - return result; -} - -// Decode for Filename-friendly base64 encoding (RFC4648), commonly referred -// as Base64WebSafeDecode. Add padding if needed. -std::vector Base64SafeDecode(const std::string& b64_input) { - if (b64_input.empty()) { - return std::vector(); - } - - // Make a copy so we can modify it to replace the web-safe special characters - // with the normal ones. - std::string input_copy = b64_input; - for (size_t i = 0; i < input_copy.size(); i++) { - if (input_copy[i] == '-') - input_copy[i] = '+'; - else if (input_copy[i] == '_') - input_copy[i] = '/'; - } - return Base64Decode(input_copy); -} - -std::string HexEncode(const uint8_t* in_buffer, unsigned int size) { +std::string HexEncode(const uint8_t* in_buffer, size_t size) { static const char kHexChars[] = "0123456789ABCDEF"; if (size == 0) return ""; constexpr unsigned int kMaxSafeSize = 2048; @@ -267,19 +223,83 @@ std::string HexEncode(const uint8_t* in_buffer, unsigned int size) { return out_buffer; } -std::string IntToString(int value) { - // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. - // So round up to allocate 3 output characters per byte, plus 1 for '-'. - const int kOutputBufSize = 3 * sizeof(int) + 1; - char buffer[kOutputBufSize]; - memset(buffer, 0, kOutputBufSize); - snprintf(buffer, kOutputBufSize, "%d", value); +// Standard Base64 encoding and decoding. - std::string out_string(buffer); - return out_string; +std::string Base64Encode(const std::vector& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal(bin_input.data(), bin_input.size(), kBase64Codes); } -int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order) +std::string Base64Encode(const std::string& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal( + reinterpret_cast(bin_input.data()), bin_input.size(), + kBase64Codes); +} + +// Decode for standard base64 encoding (RFC4648). +std::vector Base64Decode(const std::string& b64_input) { + if (b64_input.empty()) { + return std::vector(); + } + return Base64DecodeInternal(b64_input.data(), b64_input.size(), kBase64Codes); +} + +// URL/Filename Safe Base64 encoding and decoding. + +// This is the encoding required to interface with the provisioning server, as +// well as for certain license server transactions. It is also used for logging +// certain strings. The difference between web safe encoding vs regular encoding +// is that the web safe version replaces '+' with '-' and '/' with '_'. +std::string Base64SafeEncode(const std::vector& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal(bin_input.data(), bin_input.size(), + kBase64SafeCodes); +} + +std::string Base64SafeEncode(const std::string& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal( + reinterpret_cast(bin_input.data()), bin_input.size(), + kBase64SafeCodes); +} + +std::vector Base64SafeDecode(const std::string& b64_input) { + if (b64_input.empty()) { + return std::vector(); + } + return Base64DecodeInternal(b64_input.data(), b64_input.size(), + kBase64SafeCodes); +} + +// URL/Filename Safe Base64 encoding without padding. + +std::string Base64SafeEncodeNoPad(const std::vector& bin_input) { + std::string b64_output = Base64SafeEncode(bin_input); + // Output size: ceiling [ bin_input.size() * 4 / 3 ]. + b64_output.resize((bin_input.size() * 4 + 2) / 3); + return b64_output; +} + +std::string Base64SafeEncodeNoPad(const std::string& bin_input) { + std::string b64_output = Base64SafeEncode(bin_input); + // Output size: ceiling [ bin_input.size() * 4 / 3 ]. + b64_output.resize((bin_input.size() * 4 + 2) / 3); + return b64_output; +} + +// Host to Network/Network to Host conversion. + +// Convert to big endian (network-byte-order) +int64_t htonll64(int64_t x) { union { uint32_t array[2]; int64_t number; @@ -296,20 +316,14 @@ int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order) } } -std::string BytesToString(const uint8_t* bytes, unsigned size) { - if (!bytes || !size) return ""; - const char* char_bytes = reinterpret_cast(bytes); - return std::string(char_bytes, char_bytes + size); -} - // Encode unsigned integer into a big endian formatted string std::string EncodeUint32(unsigned int u) { std::string s; - s.append(1, (u >> 24) & 0xFF); - s.append(1, (u >> 16) & 0xFF); - s.append(1, (u >> 8) & 0xFF); - s.append(1, (u >> 0) & 0xFF); + s.push_back((u >> 24) & 0xFF); + s.push_back((u >> 16) & 0xFF); + s.push_back((u >> 8) & 0xFF); + s.push_back(u & 0xFF); return s; } -} // namespace wvcdm +} // namespace wvutil diff --git a/util/test/base64_test.cpp b/util/test/base64_test.cpp index 81d32a9..d96b076 100644 --- a/util/test/base64_test.cpp +++ b/util/test/base64_test.cpp @@ -2,14 +2,14 @@ // source code may only be used and distributed under the Widevine License // Agreement. -#include - #include +#include + #include "log.h" #include "string_conversions.h" -namespace wvcdm { +namespace wvutil { namespace { @@ -55,8 +55,14 @@ const std::pair kBase64TestVectors[] = { make_pair(&kTwoBytesOverData, &kTwoBytesOverB64Data), make_pair(&kTestData, &kB64TestData)}; -const std::string kBase64ErrorVectors[] = {"Foo$sa", "Foo\x99\x23\xfa\02", - "Foo==Foo", "FooBa"}; +// Arbitrary invalid base64 test vectors +const std::string kBase64ErrorVectors[] = {"Foo$sa", + "Foo\x99\x23\xfa\02", + "Foo==Foo", + "FooBa", + "SGVsbG8sIFdvcmxkI===", + "SGVsbG8sIFdvcmxkI======", + "SGVsbG8sIFdvcmxkIQp=="}; std::string ConvertToBase64WebSafe(const std::string& std_base64_string) { std::string str(std_base64_string); @@ -77,35 +83,97 @@ class Base64EncodeDecodeTest TEST_P(Base64EncodeDecodeTest, EncodeDecodeTest) { std::pair values = GetParam(); - std::vector decoded_vector = Base64Decode(values.second->data()); - std::string decoded_string(decoded_vector.begin(), decoded_vector.end()); - EXPECT_STREQ(values.first->data(), decoded_string.data()); - std::string b64_string = Base64Encode(decoded_vector); - EXPECT_STREQ(values.second->data(), b64_string.data()); + const std::string& plain_text_string = *(values.first); + const std::string& expected_encoded = *(values.second); + + // Encode from string. + const std::string b64_string_encoded = Base64Encode(plain_text_string); + EXPECT_EQ(b64_string_encoded, expected_encoded); + + // Encode from vector. + const std::vector plain_text_vector(plain_text_string.begin(), + plain_text_string.end()); + const std::string b64_vector_encoded = Base64Encode(plain_text_vector); + EXPECT_EQ(b64_vector_encoded, expected_encoded); + + // Decode from string. + const std::vector decoded_vector = Base64Decode(expected_encoded); + EXPECT_EQ(decoded_vector, plain_text_vector); } TEST_P(Base64EncodeDecodeTest, WebSafeEncodeDecodeTest) { std::pair values = GetParam(); - std::string encoded_string = ConvertToBase64WebSafe(*(values.second)); - std::vector decoded_vector = Base64SafeDecode(encoded_string); - std::string decoded_string(decoded_vector.begin(), decoded_vector.end()); - EXPECT_STREQ(values.first->data(), decoded_string.data()); - std::string b64_string = Base64SafeEncode(decoded_vector); - EXPECT_STREQ(encoded_string.data(), b64_string.data()); + const std::string& plain_text_string = *(values.first); + const std::string& expected_encoded = + ConvertToBase64WebSafe(*(values.second)); + + // Encode from string. + const std::string b64_string_encoded = Base64SafeEncode(plain_text_string); + EXPECT_EQ(b64_string_encoded, expected_encoded); + + // Encode from vector. + const std::vector plain_text_vector(plain_text_string.begin(), + plain_text_string.end()); + const std::string b64_vector_encoded = Base64SafeEncode(plain_text_vector); + EXPECT_EQ(b64_vector_encoded, expected_encoded); + + // Decode from string. + const std::vector decoded_vector = + Base64SafeDecode(expected_encoded); + EXPECT_EQ(decoded_vector, plain_text_vector); +} + +TEST_P(Base64EncodeDecodeTest, WebSafeEncodeNoPad) { + std::pair values = GetParam(); + const std::string& plain_text_string = *(values.first); + const std::string& padded_encoded = ConvertToBase64WebSafe(*(values.second)); + + // Encode from string. + const std::string b64_string_encoded = + Base64SafeEncodeNoPad(plain_text_string); + + // If input is empty, output will be empty. + if (plain_text_string.empty()) { + EXPECT_TRUE(b64_string_encoded.empty()); + return; + } + + if (padded_encoded.back() == '=') { + // If padding is present in the regular encoding, then it should be + // striped from the result. + EXPECT_NE(b64_string_encoded.back(), '='); + const std::string expected_encoded = + padded_encoded.substr(0, b64_string_encoded.size()); + EXPECT_EQ(b64_string_encoded, expected_encoded); + } else { + // If no padding is present, then results should be equal. + EXPECT_EQ(b64_string_encoded, padded_encoded); + } + + // Encode from vector. + const std::vector plain_text_vector(plain_text_string.begin(), + plain_text_string.end()); + const std::string b64_vector_encoded = + Base64SafeEncodeNoPad(plain_text_vector); + // Assuming the above has passed, the results should be the same as + // a result encoded from a string. + EXPECT_EQ(b64_vector_encoded, b64_string_encoded); } class Base64ErrorDecodeTest : public ::testing::TestWithParam {}; TEST_P(Base64ErrorDecodeTest, EncoderErrors) { - std::vector result = Base64Decode(GetParam()); - EXPECT_EQ(0u, result.size()); + const std::vector standard_result = Base64Decode(GetParam()); + EXPECT_TRUE(standard_result.empty()); + const std::vector safe_result = Base64SafeDecode(GetParam()); + EXPECT_TRUE(safe_result.empty()); } -INSTANTIATE_TEST_CASE_P(ExecutesBase64Test, Base64EncodeDecodeTest, - ::testing::ValuesIn(kBase64TestVectors)); +INSTANTIATE_TEST_SUITE_P(ExecutesBase64Test, Base64EncodeDecodeTest, + ::testing::ValuesIn(kBase64TestVectors)); -INSTANTIATE_TEST_CASE_P(ExecutesBase64Test, Base64ErrorDecodeTest, - ::testing::ValuesIn(kBase64ErrorVectors)); +INSTANTIATE_TEST_SUITE_P(ExecutesBase64Test, Base64ErrorDecodeTest, + ::testing::ValuesIn(kBase64ErrorVectors)); class HtoNLL64Test : public ::testing::Test {}; @@ -121,4 +189,4 @@ TEST_F(HtoNLL64Test, NegativeNumber) { int64_t host_byte_order = htonll64(*network_byte_order); EXPECT_EQ(-0x01FdFcFbFaF9F8F8, host_byte_order); } -} // namespace wvcdm +} // namespace wvutil diff --git a/util/test/cdm_random_unittest.cpp b/util/test/cdm_random_unittest.cpp index 097a698..33def7c 100644 --- a/util/test/cdm_random_unittest.cpp +++ b/util/test/cdm_random_unittest.cpp @@ -2,6 +2,10 @@ // source code may only be used and distributed under the Widevine License // Agreement. +#include "cdm_random.h" + +#include +#include #include #include @@ -12,12 +16,7 @@ #include #include -#include -#include - -#include "cdm_random.h" - -namespace wvcdm { +namespace wvutil { namespace { // Random data vector lengths. @@ -173,8 +172,8 @@ TEST_P(CdmRandomGeneratorTest, ThreadSafety) { } } -INSTANTIATE_TEST_CASE_P(VariousSeeds, CdmRandomGeneratorTest, - testing::ValuesIn(kSeeds)); +INSTANTIATE_TEST_SUITE_P(VariousSeeds, CdmRandomGeneratorTest, + testing::ValuesIn(kSeeds)); TEST(CdmRandomTest, AllMethods) { CdmRandom::Rand(); @@ -184,4 +183,4 @@ TEST(CdmRandomTest, AllMethods) { CdmRandom::RandomBool(); } -} // namespace wvcdm +} // namespace wvutil diff --git a/util/test/file_store_unittest.cpp b/util/test/file_store_unittest.cpp index c89fe6e..340a621 100644 --- a/util/test/file_store_unittest.cpp +++ b/util/test/file_store_unittest.cpp @@ -2,14 +2,15 @@ // source code may only be used and distributed under the Widevine License // Agreement. +#include "file_store.h" + #include #include #include "cdm_random.h" -#include "file_store.h" #include "test_vectors.h" -namespace wvcdm { +namespace wvutil { namespace { const std::string kTestDirName = "test_dir"; @@ -18,7 +19,10 @@ const std::string kTestFileName2 = "test2.txt"; const std::string kTestFileName3 = "test3.other"; const std::string kTestFileNameExt = ".txt"; const std::string kTestFileNameExt3 = ".other"; +const std::string kTestIdentifier1 = "some_identifier"; +const std::string kTestIdentifier2 = "some_other_identifier"; const std::string kWildcard = "*"; +const std::string kUnderscore = "_"; } // namespace class FileTest : public testing::Test { @@ -28,100 +32,100 @@ class FileTest : public testing::Test { void TearDown() override { RemoveTestDir(); } void RemoveTestDir() { - EXPECT_TRUE(file_system.Remove(test_vectors::kTestDir)); + EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); } - FileSystem file_system; + FileSystem file_system_; }; TEST_F(FileTest, FileExists) { - EXPECT_TRUE(file_system.Exists(test_vectors::kExistentFile)); - EXPECT_TRUE(file_system.Exists(test_vectors::kExistentDir)); - EXPECT_FALSE(file_system.Exists(test_vectors::kNonExistentFile)); - EXPECT_FALSE(file_system.Exists(test_vectors::kNonExistentDir)); + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentFile)); + EXPECT_TRUE(file_system_.Exists(wvcdm::test_vectors::kExistentDir)); + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentFile)); + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kNonExistentDir)); } TEST_F(FileTest, RemoveDir) { - EXPECT_TRUE(file_system.Remove(test_vectors::kTestDir)); - EXPECT_FALSE(file_system.Exists(test_vectors::kTestDir)); + EXPECT_TRUE(file_system_.Remove(wvcdm::test_vectors::kTestDir)); + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); } TEST_F(FileTest, OpenFile) { - std::string path = test_vectors::kTestDir + kTestFileName; - EXPECT_TRUE(file_system.Remove(path)); + std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + EXPECT_TRUE(file_system_.Remove(path)); - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); } TEST_F(FileTest, RemoveDirAndFile) { - std::string path = test_vectors::kTestDir + kTestFileName; + std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path)); - EXPECT_TRUE(file_system.Remove(path)); - EXPECT_FALSE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Remove(path)); + EXPECT_FALSE(file_system_.Exists(path)); - file = file_system.Open(path, FileSystem::kCreate); + file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); RemoveTestDir(); - EXPECT_FALSE(file_system.Exists(test_vectors::kTestDir)); - EXPECT_FALSE(file_system.Exists(path)); + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir)); + EXPECT_FALSE(file_system_.Exists(path)); } TEST_F(FileTest, RemoveWildcardFiles) { - std::string path1 = test_vectors::kTestDir + kTestFileName; - std::string path2 = test_vectors::kTestDir + kTestFileName2; + std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; + std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; std::string wildcard_path = - test_vectors::kTestDir + kWildcard + kTestFileNameExt; + wvcdm::test_vectors::kTestDir + kWildcard + kTestFileNameExt; - std::unique_ptr file = file_system.Open(path1, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); ASSERT_TRUE(file); - file = file_system.Open(path2, FileSystem::kCreate); + file = file_system_.Open(path2, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path1)); - EXPECT_TRUE(file_system.Exists(path2)); - EXPECT_TRUE(file_system.Remove(wildcard_path)); - EXPECT_FALSE(file_system.Exists(path1)); - EXPECT_FALSE(file_system.Exists(path2)); + EXPECT_TRUE(file_system_.Exists(path1)); + EXPECT_TRUE(file_system_.Exists(path2)); + EXPECT_TRUE(file_system_.Remove(wildcard_path)); + EXPECT_FALSE(file_system_.Exists(path1)); + EXPECT_FALSE(file_system_.Exists(path2)); } TEST_F(FileTest, FileSize) { - std::string path = test_vectors::kTestDir + kTestFileName; - file_system.Remove(path); + std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + file_system_.Remove(path); std::string write_data = CdmRandom::RandomData(600); size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); - EXPECT_EQ(static_cast(write_data_size), file_system.FileSize(path)); + EXPECT_EQ(static_cast(write_data_size), file_system_.FileSize(path)); } TEST_F(FileTest, WriteReadBinaryFile) { - std::string path = test_vectors::kTestDir + kTestFileName; - file_system.Remove(path); + std::string path = wvcdm::test_vectors::kTestDir + kTestFileName; + file_system_.Remove(path); std::string write_data = CdmRandom::RandomData(600); size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); std::string read_data; - read_data.resize(file_system.FileSize(path)); + read_data.resize(file_system_.FileSize(path)); size_t read_data_size = read_data.size(); - file = file_system.Open(path, FileSystem::kReadOnly); + file = file_system_.Open(path, FileSystem::kReadOnly); ASSERT_TRUE(file); EXPECT_EQ(file->Read(&read_data[0], read_data_size), read_data_size); EXPECT_EQ(write_data, read_data); @@ -131,30 +135,30 @@ TEST_F(FileTest, ListFiles) { std::vector names; std::string not_path("zzz"); - std::string path1 = test_vectors::kTestDir + kTestFileName; - std::string path2 = test_vectors::kTestDir + kTestFileName2; - std::string path3 = test_vectors::kTestDir + kTestFileName3; - std::string path_dir = test_vectors::kTestDir; + std::string path1 = wvcdm::test_vectors::kTestDir + kTestFileName; + std::string path2 = wvcdm::test_vectors::kTestDir + kTestFileName2; + std::string path3 = wvcdm::test_vectors::kTestDir + kTestFileName3; + std::string path_dir = wvcdm::test_vectors::kTestDir; - std::unique_ptr file = file_system.Open(path1, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); ASSERT_TRUE(file); - file = file_system.Open(path2, FileSystem::kCreate); + file = file_system_.Open(path2, FileSystem::kCreate); ASSERT_TRUE(file); - file = file_system.Open(path3, FileSystem::kCreate); + file = file_system_.Open(path3, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path1)); - EXPECT_TRUE(file_system.Exists(path2)); - EXPECT_TRUE(file_system.Exists(path3)); + EXPECT_TRUE(file_system_.Exists(path1)); + EXPECT_TRUE(file_system_.Exists(path2)); + EXPECT_TRUE(file_system_.Exists(path3)); // Ask for non-existent path. - EXPECT_FALSE(file_system.List(not_path, &names)); + EXPECT_FALSE(file_system_.List(not_path, &names)); // Valid path, but no way to return names. - EXPECT_FALSE(file_system.List(path_dir, nullptr)); + EXPECT_FALSE(file_system_.List(path_dir, nullptr)); // Valid path, valid return. - EXPECT_TRUE(file_system.List(path_dir, &names)); + EXPECT_TRUE(file_system_.List(path_dir, &names)); // Should find three files. Order not important. EXPECT_EQ(3u, names.size()); @@ -162,17 +166,202 @@ TEST_F(FileTest, ListFiles) { kTestFileName, kTestFileName2, kTestFileName3)); std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt; - EXPECT_TRUE(file_system.Remove(wild_card_path)); - EXPECT_TRUE(file_system.List(path_dir, &names)); + EXPECT_TRUE(file_system_.Remove(wild_card_path)); + EXPECT_TRUE(file_system_.List(path_dir, &names)); EXPECT_EQ(1u, names.size()); EXPECT_TRUE(names[0].compare(kTestFileName3) == 0); std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3; - EXPECT_TRUE(file_system.Remove(wild_card_path2)); - EXPECT_TRUE(file_system.List(path_dir, &names)); + EXPECT_TRUE(file_system_.Remove(wild_card_path2)); + EXPECT_TRUE(file_system_.List(path_dir, &names)); EXPECT_EQ(0u, names.size()); } -} // namespace wvcdm +TEST_F(FileTest, CreateGlobalCertificates) { + // Clear directory + std::vector names; + std::string path_dir = wvcdm::test_vectors::kTestDir; + std::string wild_card_path = path_dir + kWildcard; + file_system_.Remove(wild_card_path); + if (file_system_.List(path_dir, &names)) { + EXPECT_EQ(0u, names.size()); + } + + // Create certificates and verify that they exist + std::string certificate_path = + wvcdm::test_vectors::kTestDir + kCertificateFileName; + std::string legacy_certificate_path = + wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + + std::unique_ptr file = + file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(file_system_.IsGlobal()); + + EXPECT_TRUE(file_system_.Exists(certificate_path)); + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + + EXPECT_TRUE(file_system_.List(path_dir, &names)); + + // Should find two files. Order not important. + EXPECT_EQ(2u, names.size()); + EXPECT_THAT(names, ::testing::UnorderedElementsAre( + kCertificateFileName, kLegacyCertificateFileName)); +} + +TEST_F(FileTest, CreateCertificates) { + // Clear directory + std::vector names; + std::string path_dir = wvcdm::test_vectors::kTestDir; + std::string wild_card_path = path_dir + kWildcard; + file_system_.Remove(wild_card_path); + if (file_system_.List(path_dir, &names)) { + EXPECT_EQ(0u, names.size()); + } + + std::string certificate_path = + wvcdm::test_vectors::kTestDir + kCertificateFileName; + std::string legacy_certificate_path = + wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + + // Create Global certificates + std::unique_ptr file = + file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(file_system_.IsGlobal()); + + // Create certificates with first identifier + file_system_.set_identifier(kTestIdentifier1); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + // Create certificates with second identifier + file_system_.set_identifier(kTestIdentifier2); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + EXPECT_TRUE(file_system_.Exists(certificate_path)); + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + + EXPECT_TRUE(file_system_.List(path_dir, &names)); + + // Should find six files. Order not important. + bool is_global_certificate_present = false; + bool is_global_legacy_certificate_present = false; + size_t certificate_count = 0; + size_t legacy_certificate_count = 0; + EXPECT_EQ(6u, names.size()); + for (size_t i = 0; i < names.size(); ++i) { + if (names[i].size() > kCertificateFileName.size()) { + if (names[i].compare(0, kCertificateFileNamePrefix.size(), + kCertificateFileNamePrefix) == 0) + ++certificate_count; + else if (names[i].compare(0, kLegacyCertificateFileNamePrefix.size(), + kLegacyCertificateFileNamePrefix) == 0) + ++legacy_certificate_count; + } else if (names[i].compare(kCertificateFileName) == 0) { + is_global_certificate_present = true; + } else if (names[i].compare(kLegacyCertificateFileName) == 0) { + is_global_legacy_certificate_present = true; + } else { + EXPECT_TRUE(false); + } + } + EXPECT_EQ(2, certificate_count); + EXPECT_EQ(2, legacy_certificate_count); + EXPECT_TRUE(is_global_certificate_present); + EXPECT_TRUE(is_global_legacy_certificate_present); +} + +TEST_F(FileTest, RemoveCertificates) { + // Clear directory + std::vector names; + std::string path_dir = wvcdm::test_vectors::kTestDir; + std::string wild_card_path = path_dir + kWildcard; + file_system_.Remove(wild_card_path); + if (file_system_.List(path_dir, &names)) { + EXPECT_EQ(0u, names.size()); + } + + std::string certificate_path = + wvcdm::test_vectors::kTestDir + kCertificateFileName; + std::string legacy_certificate_path = + wvcdm::test_vectors::kTestDir + kLegacyCertificateFileName; + + // Create Global certificates + std::unique_ptr file = + file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(file_system_.IsGlobal()); + + // Create certificates with first identifier + file_system_.set_identifier(kTestIdentifier1); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + // Create certificates with second identifier + file_system_.set_identifier(kTestIdentifier2); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + EXPECT_TRUE(file_system_.Exists(certificate_path)); + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + + EXPECT_TRUE(file_system_.List(path_dir, &names)); + + EXPECT_EQ(6u, names.size()); + + // Remove all even number listed files + for (size_t i = 0; i < names.size(); ++i) { + if (i % 2 == 0) { + EXPECT_TRUE( + file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); + } + } + + // Verify that they have been removed + for (size_t i = 0; i < names.size(); ++i) { + if (i % 2 == 1) { + EXPECT_TRUE( + file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + } else { + EXPECT_FALSE( + file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + } + } + + // Remove all odd number listed files + for (size_t i = 0; i < names.size(); ++i) { + if (i % 2 == 1) { + EXPECT_TRUE( + file_system_.Remove(wvcdm::test_vectors::kTestDir + names[i])); + } + } + + // Verify that all have been removed + for (size_t i = 0; i < names.size(); ++i) { + EXPECT_FALSE(file_system_.Exists(wvcdm::test_vectors::kTestDir + names[i])); + } +} + +} // namespace wvutil diff --git a/util/test/test_clock.cpp b/util/test/test_clock.cpp index 5c2df32..29b964d 100644 --- a/util/test/test_clock.cpp +++ b/util/test/test_clock.cpp @@ -4,20 +4,19 @@ // // Clock - A fake clock just for running tests. -#include "clock.h" - #include +#include "clock.h" #include "test_sleep.h" -namespace wvcdm { +namespace wvutil { namespace { // A fake clock that only advances when TestSleep::Sleep is called. class FakeClock : public wvcdm::TestSleep::CallBack { public: FakeClock() { - auto now = std::chrono::steady_clock().now(); + auto now = std::chrono::system_clock().now(); now_ = now.time_since_epoch() / std::chrono::milliseconds(1); TestSleep::set_callback(this); } @@ -40,4 +39,4 @@ int64_t Clock::GetCurrentTime() { return g_fake_clock->now() / 1000; } -} // namespace wvcdm +} // namespace wvutil diff --git a/util/test/test_sleep.cpp b/util/test/test_sleep.cpp index f3f219c..4ca4b87 100644 --- a/util/test/test_sleep.cpp +++ b/util/test/test_sleep.cpp @@ -9,6 +9,9 @@ #else # include #endif +#ifdef __APPLE__ +# include +#endif #include #include @@ -19,7 +22,7 @@ #include "clock.h" #include "log.h" -namespace wvcdm { +namespace wvutil { bool TestSleep::real_sleep_ = true; TestSleep::CallBack* TestSleep::callback_ = nullptr; @@ -73,10 +76,13 @@ bool TestSleep::RollbackSystemTime(int seconds) { file_time.dwHighDateTime = long_time >> 32; if (!FileTimeToSystemTime(&file_time, &time)) return false; if (!SetSystemTime(&time)) return false; +#elif TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE + LOGE("iOS time rollback: cannot set system time."); + return false; #else auto time = std::chrono::system_clock::now(); auto modified_time = time - std::chrono::seconds(seconds); - ; + timespec time_spec; time_spec.tv_sec = std::chrono::duration_cast( modified_time.time_since_epoch()) @@ -140,6 +146,9 @@ bool TestSleep::CanChangeSystemTime() { } LOGE("Win32 time rollback: cannot set system time."); return false; +#elif TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE + LOGE("iOS time rollback: cannot set system time."); + return false; #else // Otherwise, the test needs to be run as root. const uid_t uid = getuid(); @@ -148,4 +157,4 @@ bool TestSleep::CanChangeSystemTime() { return false; #endif } -} // namespace wvcdm +} // namespace wvutil diff --git a/util/test/test_sleep.h b/util/test/test_sleep.h index 9658ca3..28db0b0 100644 --- a/util/test/test_sleep.h +++ b/util/test/test_sleep.h @@ -9,7 +9,7 @@ #include -namespace wvcdm { +namespace wvutil { class TestSleep { public: @@ -70,6 +70,6 @@ class TestSleep { static int total_clock_rollback_seconds_; }; -} // namespace wvcdm +} // namespace wvutil #endif // WVCDM_UTIL_TEST_SLEEP_H_