diff --git a/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf b/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf index b611c7e..248663f 100644 Binary files a/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf and b/docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf differ diff --git a/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement_v14.pdf b/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement_v14.pdf deleted file mode 100644 index ab217b5..0000000 Binary files a/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement_v14.pdf and /dev/null differ diff --git a/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement_v15.pdf b/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement_v15.pdf new file mode 100644 index 0000000..0ce9aa6 Binary files /dev/null and b/docs/WidevineSecurityIntegrationGuideforCENCAndroidSupplement_v15.pdf differ diff --git a/docs/Widevine_Modular_DRM_Version_15_Delta.pdf b/docs/Widevine_Modular_DRM_Version_15_Delta.pdf index 038ad2c..fe668bf 100644 Binary files a/docs/Widevine_Modular_DRM_Version_15_Delta.pdf and b/docs/Widevine_Modular_DRM_Version_15_Delta.pdf differ diff --git a/docs/Widevine_OEMCrypto_Version_Compatibility.pdf b/docs/Widevine_OEMCrypto_Version_Compatibility.pdf index 17a3a2b..301fb66 100644 Binary files a/docs/Widevine_OEMCrypto_Version_Compatibility.pdf and b/docs/Widevine_OEMCrypto_Version_Compatibility.pdf differ diff --git a/oem_certificate_generator/oem_certificate_test_helper.py b/oem_certificate_generator/oem_certificate_test_helper.py new file mode 100644 index 0000000..eccb125 --- /dev/null +++ b/oem_certificate_generator/oem_certificate_test_helper.py @@ -0,0 +1,158 @@ +# Copyright 2017 Google LLC. All Rights Reserved. + +"""Common test utility functions for OEM certificate generation.""" + +import datetime +import StringIO + +from cryptography import x509 +from cryptography.hazmat import backends +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.x509 import oid + +import oem_certificate + +_COUNTRY_NAME = 'US' +_STATE_OR_PROVINCE_NAME = 'WA' +_LOCALITY_NAME = 'Kirkland' +_ORGANIZATION_NAME = 'CompanyXYZ' +_ORGANIZATIONAL_UNIT_NAME = 'ContentProtection' + + +_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' + + +class ArgParseObject(object): + """A convenient object to allow adding arbitrary attribute to it.""" + + +def create_root_certificate_and_key(): + """Creates a root certificate and key.""" + key = rsa.generate_private_key( + public_exponent=65537, + key_size=3072, + backend=backends.default_backend()) + subject_name = x509.Name( + [x509.NameAttribute(oid.NameOID.COMMON_NAME, u'root_cert')]) + certificate = oem_certificate.build_certificate( + subject_name, subject_name, None, + datetime.datetime(2001, 8, 9), 1000, key.public_key(), key, True) + return (key, certificate) + + +def setup_csr_args(country_name=_COUNTRY_NAME, + state_or_province_name=_STATE_OR_PROVINCE_NAME, + locality_name=_LOCALITY_NAME, + organization_name=_ORGANIZATION_NAME, + organizational_unit_name=_ORGANIZATIONAL_UNIT_NAME, + key_size=4096, + output_csr_file=None, + output_private_key_file=None, + passphrase=None, + common_name=None): + """Sets up arguments to OEM Certificate generator for generating csr.""" + args = ArgParseObject() + args.key_size = key_size + args.country_name = country_name + args.state_or_province_name = state_or_province_name + args.locality_name = locality_name + args.organization_name = organization_name + args.organizational_unit_name = organizational_unit_name + args.common_name = common_name + if output_csr_file: + args.output_csr_file = output_csr_file + else: + args.output_csr_file = StringIO.StringIO() + if output_private_key_file: + args.output_private_key_file = output_private_key_file + else: + args.output_private_key_file = StringIO.StringIO() + args.passphrase = passphrase + return args + + +def setup_intermediate_cert_args( + csr_bytes, root_key, root_certificate, not_valid_before=_NOT_VALID_BEFORE, + valid_duration=_VALID_DURATION, system_id=_SYSTEM_ID, + root_private_key_passphrase=_ROOT_PRIVATE_KEY_PASSPHRASE, + output_certificate_file=None): + """Sets up args to OEM Cert generator for generating intermediate cert.""" + args = ArgParseObject() + 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.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() + + serialized_private_key = root_key.private_bytes( + serialization.Encoding.DER, + format=serialization.PrivateFormat.PKCS8, + encryption_algorithm=serialization.BestAvailableEncryption( + 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) + return args + + +def setup_leaf_cert_args(intermediate_key_bytes, + intermediate_certificate_bytes, + key_size=1024, + passphrase=None, + not_valid_before=_NOT_VALID_BEFORE, + valid_duration=_LEAF_CERT_VALID_DURATION, + output_certificate_file=None, + output_private_key_file=None): + """Sets up args to OEM Certificate generator for generating leaf cert.""" + args = ArgParseObject() + args.key_size = key_size + args.not_valid_before = not_valid_before + args.valid_duration = valid_duration + args.intermediate_private_key_passphrase = None + if output_certificate_file: + args.output_certificate_file = output_certificate_file + else: + args.output_certificate_file = StringIO.StringIO() + if output_private_key_file: + args.output_private_key_file = output_private_key_file + else: + args.output_private_key_file = StringIO.StringIO() + args.passphrase = passphrase + + args.intermediate_private_key_file = StringIO.StringIO( + intermediate_key_bytes) + args.intermediate_certificate_file = StringIO.StringIO( + intermediate_certificate_bytes) + return args + + +def create_intermediate_certificate_and_key_bytes(key_size=4096, + passphrase=None, + pem_format=True): + """Creates an intermediate certificate and key.""" + csr_args = setup_csr_args(key_size=key_size, passphrase=passphrase) + oem_certificate.generate_csr(csr_args) + csr_bytes = csr_args.output_csr_file.getvalue() + + root_key, root_certificate = create_root_certificate_and_key() + args = setup_intermediate_cert_args(csr_bytes, root_key, root_certificate) + + oem_certificate.generate_intermediate_certificate(args) + + cert_bytes = args.output_certificate_file.getvalue() + if pem_format: + cert = x509.load_der_x509_certificate(cert_bytes, + backends.default_backend()) + cert_bytes = cert.public_bytes(serialization.Encoding.PEM) + + return (csr_args.output_private_key_file.getvalue(), cert_bytes) diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index f7a560c..fffb93a 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -8,7 +8,7 @@ * Reference APIs needed to support Widevine's crypto algorithms. * * See the document "WV Modular DRM Security Integration Guide for Common - * Encryption (CENC) -- version 15" for a description of this API. You + * Encryption (CENC) -- version 15.2" for a description of this API. You * can find this document in the widevine repository as * docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf * Changes between different versions of this API are documented in the files @@ -339,9 +339,9 @@ typedef enum OEMCrypto_Clock_Security_Level { typedef uint8_t RSA_Padding_Scheme; // RSASSA-PSS with SHA1. -const RSA_Padding_Scheme kSign_RSASSA_PSS = 0x1; +#define kSign_RSASSA_PSS ((RSA_Padding_Scheme)0x1) // PKCS1 with block type 1 padding (only). -const RSA_Padding_Scheme kSign_PKCS1_Block1 = 0x2; +#define kSign_PKCS1_Block1 ((RSA_Padding_Scheme)0x2) /* * OEMCrypto_HDCP_Capability is used in the key control block to enforce HDCP @@ -376,9 +376,9 @@ typedef enum OEMCrypto_ProvisioningMethod { /* * Flags indicating full decrypt path hash supported. */ -const uint32_t OEMCrypto_Hash_Not_Supported = 0; -const uint32_t OEMCrypto_CRC_Clear_Buffer = 1; -const uint32_t OEMCrypto_Partner_Defined_Hash = 2; +#define OEMCrypto_Hash_Not_Supported 0 +#define OEMCrypto_CRC_Clear_Buffer 1 +#define OEMCrypto_Partner_Defined_Hash 2 /* * Return values from OEMCrypto_GetAnalogOutputFlags. @@ -800,13 +800,17 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( * before requesting more nonces, then OEMCrypto will reset the error * condition and generate valid nonces again. * + * To prevent Birthday Paradox attacks, OEMCrypto shall verify that the value + * generated is not in this session's nonce table, and that it is not in the + * nonce table of any other session. + * * Parameters: * [in] session: handle for the session to be used. * [out] nonce: pointer to memory to receive the computed nonce. * * Results: - * nonce: the nonce is also stored in secure memory. At least 4 nonces should - * be stored for each session. + * nonce: the nonce is also stored in secure memory. Each session should + * store 4 nonces. * * Returns: * OEMCrypto_SUCCESS success @@ -817,11 +821,9 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( * OEMCrypto_ERROR_SYSTEM_INVALIDATED * * 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. + * This is a "Session Initialization 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 5. @@ -1049,6 +1051,9 @@ OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length); * entry is marked as "inactive" (either kInactiveUsed or * kInactiveUnused), then the keys are not loaded, and the error * OEMCrypto_ERROR_LICENSE_INACTIVE is returned. + * 12. The data in enc_mac_keys_iv is not identical to the 16 bytes before + * enc_mac_keys. If it is, return OEMCrypto_ERROR_INVALID_CONTEXT. + * * Usage Table and Provider Session Token (pst) * * If a key control block has a nonzero value for Replay_Control, then all @@ -1627,8 +1632,8 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session, * 6. If the current session has an entry in the Usage Table, and the * status of that entry is either kInactiveUsed or kInactiveUnused, then * return the error OEMCrypto_ERROR_LICENSE_INACTIVE. - * 7. If an Decrypt Hash has been initialized via OEMCrypto_SetDecryptHash, - * and the current key's control block does not have the + * 7. If a Decrypt Hash has been initialized via OEMCrypto_SetDecryptHash, + * and the current key's control block does not have the * Allow_Hash_Verification bit set, then do not compute a hash and * return OEMCrypto_ERROR_UNKNOWN_FAILURE. * If the flag is_encrypted is false, then no verification is performed. This @@ -2201,7 +2206,7 @@ OEMCryptoResult OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* rot, * Version: * This method is new API version 12. */ -OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(); +OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(void); /* * OEMCrypto_IsKeyboxOrOEMCertValid @@ -2257,7 +2262,7 @@ OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void); * system upgrade. * * This function is optional but recommended for Provisioning 3.0 in API v15. - * It may be required for future version of this API. + * It may be required for a future version of this API. * * Parameters: * [out] deviceId - pointer to the buffer that receives the Device ID @@ -2459,7 +2464,7 @@ OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength); * Version: * This method changed in each API version. */ -uint32_t OEMCrypto_APIVersion(); +uint32_t OEMCrypto_APIVersion(void); /* * OEMCrypto_BuildInformation @@ -2497,7 +2502,7 @@ uint32_t OEMCrypto_APIVersion(); * Version: * This method changed in each API version. */ -const char* OEMCrypto_BuildInformation(); +const char* OEMCrypto_BuildInformation(void); /* * OEMCrypto_Security_Patch_Level @@ -2524,7 +2529,7 @@ const char* OEMCrypto_BuildInformation(); * Version: * This method was introduced in API version 11. */ -uint8_t OEMCrypto_Security_Patch_Level(); +uint8_t OEMCrypto_Security_Patch_Level(void); /* * OEMCrypto_SecurityLevel @@ -2550,7 +2555,7 @@ uint8_t OEMCrypto_Security_Patch_Level(); * Version: * This method changed in API version 6. */ -const char* OEMCrypto_SecurityLevel(); +const char* OEMCrypto_SecurityLevel(void); /* * OEMCrypto_GetHDCPCapability @@ -2565,12 +2570,6 @@ const char* OEMCrypto_SecurityLevel(); * instead of HDMI output. Notice that HDCP must use flag Type 1: all * downstream devices will also use the same version or higher. * - * The current HDCP should be the minimum value of any display currently - * connected through any channel, either through HDMI or a supported wireless - * format. The current value can be used by the application or server to - * decide which license can currently be used. If the key control block - * requires the current HDCP level, we expect the key to be usable. - * * The maximum HDCP level should be the maximum value that the device can * enforce. For example, if the device has an HDCP 1.0 port and an HDCP 2.0 * port, and the first port can be disabled, then the maximum is HDCP 2.0. If @@ -2581,6 +2580,30 @@ const char* OEMCrypto_SecurityLevel(); * user intends to view the content on a local display. The user will want to * download the higher quality content. * + * The current HDCP level should be the level of HDCP currently negotiated + * with any connected receivers or repeaters either through HDMI or a + * supported wireless format. If multiple ports are connected, the current + * level should be the minimum HDCP level of all ports. If the key control + * block requires an HDCP level equal to or lower than the current HDCP + * level, the key is expected to be usable. If the key control block requires + * a higher HDCP level, the key is expected to be forbidden. + * + * When a key has version HDCP_V2_3 required in the key control block, the + * transmitter must have HDCP version 2.3 and have negotiated a connection + * with a version 2.3 receiver or repeater. The transmitter must configure + * the content stream to be Type 1. Since the transmitter cannot distinguish + * between 2.2 and 2.3 downstream receivers when connected to a repeater, it + * may transmit to both 2.2 and 2.3 receivers, but not 2.1 receivers. + * + * For example, if the transmitter is 2.3, and is connected to a receiver + * that supports 2.3 then the current level is HDCP_V2_3. If the transmitter + * is 2.3 and is connected to a 2.3 repeater, the current level is HDCP_V2_3 + * even though the repeater can negotiate a connection with a 2.2 downstream + * receiver for a Type 1 Content Stream. + * + * As another example, if the transmitter can support 2.3, but a receiver + * supports 2.0, then the current level is HDCP_V2. + * * When a license requires HDCP, a device may use a wireless protocol to * connect to a display only if that protocol supports the version of HDCP as * required by the license. Both WirelessHD (formerly WiFi Display) and @@ -2633,7 +2656,7 @@ OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability* current, * Version: * This method changed in API version 9. */ -bool OEMCrypto_SupportsUsageTable(); +bool OEMCrypto_SupportsUsageTable(void); /* * OEMCrypto_IsAntiRollbackHwPresent @@ -2661,7 +2684,7 @@ bool OEMCrypto_SupportsUsageTable(); * Version: * This method is new in API version 10. */ -bool OEMCrypto_IsAntiRollbackHwPresent(); +bool OEMCrypto_IsAntiRollbackHwPresent(void); /* * OEMCrypto_GetNumberOfOpenSessions @@ -2762,7 +2785,7 @@ OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max); * Version: * This method changed in API version 13. */ -uint32_t OEMCrypto_SupportedCertificates(); +uint32_t OEMCrypto_SupportedCertificates(void); /* * OEMCrypto_IsSRMUpdateSupported @@ -2789,7 +2812,7 @@ uint32_t OEMCrypto_SupportedCertificates(); * Version: * This method changed in API version 13. */ -bool OEMCrypto_IsSRMUpdateSupported(); +bool OEMCrypto_IsSRMUpdateSupported(void); /* * OEMCrypto_GetCurrentSRMVersion @@ -2856,7 +2879,7 @@ OEMCryptoResult OEMCrypto_GetCurrentSRMVersion(uint16_t* version); * Version: * This method is new in API version 14. */ -uint32_t OEMCrypto_GetAnalogOutputFlags(); +uint32_t OEMCrypto_GetAnalogOutputFlags(void); /* * OEMCrypto_ResourceRatingTier @@ -2865,7 +2888,7 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(); * This function returns a positive number indicating which resource rating * it supports. This value will bubble up to the application level as a * property. This will allow applications to estimate what resolution and - * bandwidth the device expects to support. + * bandwidth the device is expected to support. * * OEMCrypto unit tests and Android GTS tests will verify that devices do * support the resource values specified in the table below at the tier @@ -2925,8 +2948,6 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(); * +-----------------------------------+-----------+------------+-----------+ * |Number of keys per session |4 |20 |20 | * +-----------------------------------+-----------+------------+-----------+ - * |Simultaneous secure playback |1 |2 |2 | - * +-----------------------------------+-----------+------------+-----------+ * |Decrypted Frames per Second |30 fps SD |30 fps HD |60 fps HD | * +-----------------------------------+-----------+------------+-----------+ * @@ -2945,7 +2966,7 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(); * Version: * This method is new in API version 15. */ -uint32_t OEMCrypto_ResourceRatingTier(); +uint32_t OEMCrypto_ResourceRatingTier(void); /* * OEMCrypto_RewrapDeviceRSAKey30 @@ -3306,7 +3327,7 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, * Version: * This method is new in API version 10. */ -OEMCryptoResult OEMCrypto_LoadTestRSAKey(); +OEMCryptoResult OEMCrypto_LoadTestRSAKey(void); /* * OEMCrypto_GenerateRSASignature @@ -3648,8 +3669,10 @@ OEMCryptoResult OEMCrypto_UpdateUsageEntry(OEMCrypto_SESSION session, * means that the state of the usage entry is changed to InactiveUsed if it * was Active, or InactiveUnused if it was Unused. This also increments the * entry's generation number, and the header's master generation number. The - * entry's flag ForbidReport will be set. This flag prevents an application - * from generating a report of a deactivated license without first saving the + * corresponding generation number in the usage table header is also + * incremented so that it matches the one in the entry. The entry's flag + * ForbidReport will be set. This flag prevents an application from + * generating a report of a deactivated license without first saving the * entry. * * It is allowed to call this function multiple times. If the state is @@ -3954,14 +3977,14 @@ OEMCryptoResult OEMCrypto_CopyOldUsageEntry(OEMCrypto_SESSION session, * Version: * This method is new in API version 13. */ -OEMCryptoResult OEMCrypto_DeleteOldUsageTable(); +OEMCryptoResult OEMCrypto_DeleteOldUsageTable(void); /* * OEMCrypto_RemoveSRM * * Description: - * Delete the current SRM. Any valid SRM, regardless of version number, will - * be installable after this via OEMCrypto_LoadSRM. + * Delete the current SRM. Any valid SRM, regardless of its version number, + * will be installable after this via OEMCrypto_LoadSRM. * * This function should not be implemented on production devices, and will * only be used to verify unit tests on a test device. @@ -3981,7 +4004,7 @@ OEMCryptoResult OEMCrypto_DeleteOldUsageTable(); * Version: * This method is new in API version 13. */ -OEMCryptoResult OEMCrypto_RemoveSRM(); +OEMCryptoResult OEMCrypto_RemoveSRM(void); /* * OEMCrypto_CreateOldUsageEntry @@ -4027,7 +4050,7 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry(uint64_t time_since_license_receiv * supported. OEMCrypto is not required by Google to support this feature, * but support will greatly improve automated testing. A hash type of * OEMCrypto_CRC_Clear_Buffer = 1 means the device will be able to compute - * the CRC32 checksum of the decrypted content in the secure buffer after a + * the CRC 32 checksum of the decrypted content in the secure buffer after a * call to OEMCrypto_DecryptCENC. Google intends to provide test applications * on some platforms, such as Android, that will automate decryption testing * using the CRC 32 checksum of all frames in some test content. @@ -4055,7 +4078,7 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry(uint64_t time_since_license_receiv * Version: * This method is new in API version 15. */ -uint32_t OEMCrypto_SupportsDecryptHash(); +uint32_t OEMCrypto_SupportsDecryptHash(void); /* * OEMCrypto_SetDecryptHash diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp index 2c6e6b5..82b88de 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp @@ -182,6 +182,14 @@ time_t CryptoEngine::RollbackCorrectedOfflineTime() { return current_time; } +bool CryptoEngine::NonceCollision(uint32_t nonce) { + for (const auto & session_pair : sessions_) { + const SessionContext* session = session_pair.second; + if (session->NonceCollision(nonce)) return true; + } + return false; +} + OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() { return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; } diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.h b/oemcrypto/ref/src/oemcrypto_engine_ref.h index 6ad5cd2..cc132aa 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -91,6 +91,10 @@ class CryptoEngine { time_t RollbackCorrectedOfflineTime(); + // Verify that this nonce does not collide with another nonce in any session's + // nonce table. + virtual bool NonceCollision(uint32_t nonce); + // Returns the HDCP version currently in use. virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability(); diff --git a/oemcrypto/ref/src/oemcrypto_nonce_table.cpp b/oemcrypto/ref/src/oemcrypto_nonce_table.cpp index 19c7613..65d9269 100644 --- a/oemcrypto/ref/src/oemcrypto_nonce_table.cpp +++ b/oemcrypto/ref/src/oemcrypto_nonce_table.cpp @@ -58,6 +58,13 @@ bool NonceTable::CheckNonce(uint32_t nonce) { return false; } +bool NonceTable::NonceCollision(uint32_t nonce) const { + for (int i = 0; i < kTableSize; ++i) { + if (nonce == nonces_[i]) return true; + } + return false; +} + void NonceTable::Flush() { for (int i = 0; i < kTableSize; ++i) { if (kNTStateFlushPending == state_[i]) { diff --git a/oemcrypto/ref/src/oemcrypto_nonce_table.h b/oemcrypto/ref/src/oemcrypto_nonce_table.h index 90175e2..409e7fc 100644 --- a/oemcrypto/ref/src/oemcrypto_nonce_table.h +++ b/oemcrypto/ref/src/oemcrypto_nonce_table.h @@ -13,7 +13,7 @@ namespace wvoec_ref { class NonceTable { public: - static const int kTableSize = 16; + static const int kTableSize = 4; NonceTable() { for (int i = 0; i < kTableSize; ++i) { state_[i] = kNTStateInvalid; @@ -22,6 +22,8 @@ class NonceTable { ~NonceTable() {} void AddNonce(uint32_t nonce); bool CheckNonce(uint32_t nonce); + // Verify that the nonce is not the same as any in this table. + bool NonceCollision(uint32_t nonce) const; void Flush(); private: diff --git a/oemcrypto/ref/src/oemcrypto_ref.cpp b/oemcrypto/ref/src/oemcrypto_ref.cpp index 67d3e12..355fbf7 100644 --- a/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -189,13 +189,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, last_nonce_time = now; } - uint32_t nonce_value; + uint32_t nonce_value = 0; uint8_t* nonce_string = reinterpret_cast(&nonce_value); - // Generate 4 bytes of random data - if (!RAND_bytes(nonce_string, 4)) { - LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; + while (nonce_value == 0 || crypto_engine->NonceCollision(nonce_value)) { + // Generate 4 bytes of random data + if (!RAND_bytes(nonce_string, 4)) { + LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } } session_ctx->AddNonce(nonce_value); *nonce = nonce_value; @@ -281,9 +283,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( !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.]"); + LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " + "range check.]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } @@ -293,13 +294,25 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys( !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 %d]", - i); + LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - " + "range check %d]", 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 (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, diff --git a/oemcrypto/ref/src/oemcrypto_scoped_ptr.h b/oemcrypto/ref/src/oemcrypto_scoped_ptr.h deleted file mode 100644 index 8e56fa0..0000000 --- a/oemcrypto/ref/src/oemcrypto_scoped_ptr.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. -#ifndef OEMCRYPTO_SCOPED_PTR_H_ -#define OEMCRYPTO_SCOPED_PTR_H_ - -#include -#include - -#include - -namespace wvoec_ref { - -// TODO(fredgc, jfore): scoped_ptr may not be the best name for this smart -// pointer type. It basically works like auto_ptr which is deprecated. -#if __cplusplus < 201103L - -template -class scoped_ptr { - public: - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - T* get() const { return ptr_.get(); } - void reset(T* p = NULL) { ptr_.reset(p); } - - private: - std::auto_ptr ptr_; -}; - -#else - -template -class scoped_ptr { - public: - explicit scoped_ptr(T* p = nullptr) : ptr_(p) {} - scoped_ptr(scoped_ptr& r) { ptr_ = std::move(r.ptr_); } - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_.get(); } - T* get() const { return ptr_.get(); } - void reset(T* p = NULL) { ptr_.reset(p); } - - private: - std::unique_ptr ptr_; -}; -#endif - -} // namespace wvoec_ref - -#endif // OEMCRYPTO_SCOPED_PTR_H_ diff --git a/oemcrypto/ref/src/oemcrypto_session.cpp b/oemcrypto/ref/src/oemcrypto_session.cpp index 714b252..eb70320 100644 --- a/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/oemcrypto/ref/src/oemcrypto_session.cpp @@ -636,6 +636,7 @@ OEMCryptoResult SessionContext::LoadKeys( break; } } + encryption_key_.clear(); return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/ref/src/oemcrypto_session.h b/oemcrypto/ref/src/oemcrypto_session.h index bfd81a6..0956056 100644 --- a/oemcrypto/ref/src/oemcrypto_session.h +++ b/oemcrypto/ref/src/oemcrypto_session.h @@ -173,6 +173,10 @@ class SessionContext { void AddNonce(uint32_t nonce); bool CheckNonce(uint32_t nonce); + // Verify that the nonce does not match any in this session's nonce table. + bool NonceCollision(uint32_t nonce) const { + return nonce_table_.NonceCollision(nonce); + } void FlushNonces(); virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number); diff --git a/oemcrypto/test/oec_device_features.cpp b/oemcrypto/test/oec_device_features.cpp index bad4c55..2e18ca1 100644 --- a/oemcrypto/test/oec_device_features.cpp +++ b/oemcrypto/test/oec_device_features.cpp @@ -153,33 +153,12 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { if (provisioning_method != OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*"); if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*"); - if (api_version < 14) { - // Because API 13 uses an old hard coded test keybox, none of these tests - // will pass. Partners who wish to test with a v13 OEMCrypto should use - // code on an older v13 branch. - printf("These unit tests are designed for OEMCrypto API 15 and above.\n"); - printf("This device has an OEMCrypto with API version %d.\n", api_version); - printf("To verify correctness, please build unit tests from a " - "compatible branch.\n"); - FilterOut(&filter, "*API09*"); - FilterOut(&filter, "*API10*"); - FilterOut(&filter, "*API11*"); - FilterOut(&filter, "*API12*"); - FilterOut(&filter, "*API13*"); - FilterOut(&filter, "*API14*"); - FilterOut(&filter, "*TestKeyboxTest*"); - FilterOut(&filter, "*SessionTest*"); - FilterOut(&filter, "*UsageTable*"); - FilterOut(&filter, "*GenericCrypto*"); - FilterOut(&filter, "*LoadsCertificate*"); - FilterOut(&filter, "*UsesCertificate*"); - // We also expect some CDM tests to fail without a new test keybox: - FilterOut(&filter, "*WvCdmRequestLicenseTest*"); - FilterOut(&filter, "*WvGenericOperations*"); - FilterOut(&filter, "*WvCdmEngine*"); - FilterOut(&filter, "*Cdm/WvCdm*"); - FilterOut(&filter, "*Cdm/WvHls*"); - } + if (api_version < 9) FilterOut(&filter, "*API09*"); + if (api_version < 10) FilterOut(&filter, "*API10*"); + if (api_version < 11) FilterOut(&filter, "*API11*"); + if (api_version < 12) FilterOut(&filter, "*API12*"); + if (api_version < 13) FilterOut(&filter, "*API13*"); + if (api_version < 14) FilterOut(&filter, "*API14*"); if (api_version < 15) FilterOut(&filter, "*API15*"); // Some tests may require root access. If user is not root, filter these tests // out. diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 4ed98c5..737f473 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -539,6 +539,7 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce, const std::string& pst) { EXPECT_EQ( 1, GetRandBytes(license_.mac_key_iv, sizeof(license_.mac_key_iv))); + memset(license_.padding, 0, sizeof(license_.padding)); EXPECT_EQ(1, GetRandBytes(license_.mac_keys, sizeof(license_.mac_keys))); for (unsigned int i = 0; i < num_keys_; i++) { memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength); @@ -1268,7 +1269,6 @@ void Session::GenerateReport(const std::string& pst, ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); } if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { - ASSERT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length); pst_report_buffer_.assign(length, 0xFF); // Fill with garbage values. } sts = OEMCrypto_ReportUsage(session_id(), @@ -1278,7 +1278,7 @@ void Session::GenerateReport(const std::string& pst, if (expected_result != OEMCrypto_SUCCESS) { return; } - ASSERT_EQ(pst_report_buffer_.size(), length); + EXPECT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length); vector computed_signature(SHA_DIGEST_LENGTH); unsigned int sig_len = SHA_DIGEST_LENGTH; HMAC(EVP_sha1(), mac_key_client_.data(), mac_key_client_.size(), @@ -1359,6 +1359,9 @@ void Session::GenerateVerifyReport(const std::string& pst, Test_PST_Report expected(pst, status); ASSERT_NO_FATAL_FAILURE(VerifyReport(expected, time_license_received, time_first_decrypt, time_last_decrypt)); + // The PST report was signed above. Below we verify that the entire message + // that is sent to the server will be signed by the right mac keys. + ASSERT_NO_FATAL_FAILURE(VerifyClientSignature()); } void Session::CreateOldEntry(const Test_PST_Report& report) { diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index 4f1ab1b..f162760 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -81,6 +81,7 @@ typedef struct { struct MessageData { MessageKeyData keys[kMaxNumKeys]; uint8_t mac_key_iv[KEY_IV_SIZE]; + uint8_t padding[KEY_IV_SIZE]; uint8_t mac_keys[2 * MAC_KEY_SIZE]; uint8_t pst[kMaxPSTLength]; }; diff --git a/oemcrypto/test/oec_test_data.h b/oemcrypto/test/oec_test_data.h index 144c4d3..9739144 100644 --- a/oemcrypto/test/oec_test_data.h +++ b/oemcrypto/test/oec_test_data.h @@ -15,6 +15,41 @@ namespace wvoec { +// TODO(fredgc, b/119316243): REMOVE THIS KEYBOX! +// This test keybox is used for testing with OEMCrypto v13. +// It should be removed before release! +static const WidevineKeybox kTestKeyboxForV13 = { + // Sample keybox used for test vectors + { + // deviceID + 0x54, 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x30, // TestKey01 + 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........ + }, { + // key + 0xfb, 0xda, 0x04, 0x89, 0xa1, 0x58, 0x16, 0x0e, + 0xa4, 0x02, 0xe9, 0x29, 0xe3, 0xb6, 0x8f, 0x04, + }, { + // data + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x19, + 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1, + 0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd, + 0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, 0xd8, + 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64, + 0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8, + 0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, 0xa8, + 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64, + 0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39, + }, { + // magic + 0x6b, 0x62, 0x6f, 0x78, + }, { + // Crc + 0x0a, 0x7a, 0x2c, 0x35, + } +}; + // 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. diff --git a/oemcrypto/test/oemcrypto_session_tests_helper.cpp b/oemcrypto/test/oemcrypto_session_tests_helper.cpp index 60eb36a..c9643b8 100644 --- a/oemcrypto/test/oemcrypto_session_tests_helper.cpp +++ b/oemcrypto/test/oemcrypto_session_tests_helper.cpp @@ -105,6 +105,8 @@ void SessionUtil::EnsureTestKeys() { switch (global_features.derive_key_method) { case DeviceFeatures::LOAD_TEST_KEYBOX: keybox_ = kTestKeybox; + // TODO(fredgc, b/119316243): REMOVE FOLLOWING LINE: + if (global_features.api_version < 14) keybox_ = kTestKeyboxForV13; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox( reinterpret_cast(&keybox_), diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 21da261..3df68bf 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -871,6 +871,24 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoNonce) { ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); } +// Verify that a second license may be not be loaded in a session. +TEST_F(OEMCryptoSessionTests, LoadKeyNoNonceTwice) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 42)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NE( + OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), + s.signature().data(), s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); +} + // Verify that a license may be loaded with a nonce. TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) { Session s; @@ -882,6 +900,24 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) { ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); } +// Verify that a second license may be not be loaded in a session. +TEST_F(OEMCryptoSessionTests, LoadKeyWithNonceTwice) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE( + s.FillSimpleMessage(0, wvoec::kControlNonceEnabled, s.get_nonce())); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); + ASSERT_NE( + OEMCrypto_SUCCESS, + OEMCrypto_LoadKeys(s.session_id(), s.message_ptr(), s.message_size(), + s.signature().data(), s.signature().size(), + s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), s.pst_substr(), + GetSubstring(), OEMCrypto_ContentLicense)); +} + // This asks for several nonce. This simulates several license requests being // lost. OEMCrypto is required to keep up to four nonce in the nonce table. TEST_F(OEMCryptoSessionTests, LoadKeySeveralNonce) { @@ -1179,6 +1215,27 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) { ASSERT_NE(OEMCrypto_SUCCESS, sts); } +// The IV should not be identical to the data right before the encrypted mac +// keys. +TEST_F(OEMCryptoSessionTests, LoadKeyWithSuspiciousIV) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); + // This is suspicious: the data right before the mac keys is identical to the + // iv. + memcpy(s.license().padding, s.license().mac_key_iv, + sizeof(s.license().padding)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + + OEMCryptoResult sts = OEMCrypto_LoadKeys( + s.session_id(), s.message_ptr(), s.message_size(), s.signature().data(), + s.signature().size(), s.enc_mac_keys_iv_substr(), s.enc_mac_keys_substr(), + s.num_keys(), s.key_array(), GetSubstring(), GetSubstring(), + OEMCrypto_ContentLicense); + ASSERT_NE(OEMCrypto_SUCCESS, sts); +} + // Test that LoadKeys fails when a key is loaded with no key control block. TEST_F(OEMCryptoSessionTests, LoadKeyWithNullKeyControl) { Session s; @@ -5396,9 +5453,9 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithRefresh) { ASSERT_NO_FATAL_FAILURE(s.close()); } -// Verify that a license that has been we can still reload an offline license -// after OEMCrypto_Terminate and Initialize are called. This is as close to a -// reboot as we can do in a unit test. +// Verify that we can still reload an offline license after OEMCrypto_Terminate +// and Initialize are called. This is as close to a reboot as we can do in a +// unit test. TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithTerminate) { std::string pst = "my_pst"; Session s; diff --git a/oemcrypto/test/oemcrypto_test_android.cpp b/oemcrypto/test/oemcrypto_test_android.cpp index 7dd3384..e0739ea 100644 --- a/oemcrypto/test/oemcrypto_test_android.cpp +++ b/oemcrypto/test/oemcrypto_test_android.cpp @@ -50,6 +50,11 @@ TEST_F(OEMCryptoAndroidLMPTest, ValidKeybox) { } } +TEST_F(OEMCryptoAndroidLMPTest, MinVersionNumber9) { + uint32_t version = OEMCrypto_APIVersion(); + ASSERT_LE(9u, version); +} + TEST_F(OEMCryptoAndroidLMPTest, ValidKeyboxTest) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid()); } @@ -108,6 +113,11 @@ TEST_F(OEMCryptoAndroidLMPTest, Level1Required) { // These tests are required for M Android devices. class OEMCryptoAndroidMNCTest : public OEMCryptoAndroidLMPTest {}; +TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) { + uint32_t version = OEMCrypto_APIVersion(); + ASSERT_GE(version, 10u); +} + // Android devices using Provisioning 2.0 must be able to load a test keybox. // If they are not using Provisioning 2.0, then they must use Provisioning 3.0. TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) { @@ -135,4 +145,28 @@ TEST_F(OEMCryptoAndroidMNCTest, QueryKeyControlImplemented) { OEMCrypto_QueryKeyControl(0, NULL, 0, NULL, NULL)); } +// These tests are required for N Android devices. +class OEMCryptoAndroidNYCTest : public OEMCryptoAndroidMNCTest {}; + +TEST_F(OEMCryptoAndroidNYCTest, MinVersionNumber11) { + uint32_t version = OEMCrypto_APIVersion(); + ASSERT_GE(version, 11u); +} + +// These tests are required for O MR1 Android devices. +class OEMCryptoAndroidOCTest : public OEMCryptoAndroidNYCTest {}; + +TEST_F(OEMCryptoAndroidOCTest, MinVersionNumber13) { + uint32_t version = OEMCrypto_APIVersion(); + ASSERT_GE(version, 13u); +} + +// These tests are required for Q Android devices. +class OEMCryptoAndroidQTest : public OEMCryptoAndroidOCTest {}; + +TEST_F(OEMCryptoAndroidQTest, MinVersionNumber14) { + uint32_t version = OEMCrypto_APIVersion(); + ASSERT_GE(version, 15u); +} + } // namespace wvoec diff --git a/util/include/lock.h b/util/include/lock.h deleted file mode 100644 index 3eb288f..0000000 --- a/util/include/lock.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. -// -// Lock - Platform independent interface for a Mutex class -// -#ifndef WVCDM_UTIL_LOCK_H_ -#define WVCDM_UTIL_LOCK_H_ - -#include "disallow_copy_and_assign.h" - -namespace wvcdm { - -// Simple lock class. The implementation is platform dependent. -// -// The lock must be unlocked by the thread that locked it. -// The lock is also not recursive (ie. cannot be taken multiple times). -class Lock { - public: - Lock(); - ~Lock(); - - void Acquire(); - void Release(); - - friend class AutoLock; - - private: - class Impl; - Impl* impl_; - - CORE_DISALLOW_COPY_AND_ASSIGN(Lock); -}; - -// Manages the lock automatically. It will be locked when AutoLock -// is constructed and release when AutoLock goes out of scope. -class AutoLock { - public: - explicit AutoLock(Lock& lock) : lock_(&lock) { lock_->Acquire(); } - - explicit AutoLock(Lock* lock) : lock_(lock) { lock_->Acquire(); } - - ~AutoLock() { lock_->Release(); } - - private: - Lock* lock_; - - CORE_DISALLOW_COPY_AND_ASSIGN(AutoLock); -}; - -} // namespace wvcdm - -#endif // WVCDM_UTIL_LOCK_H_ diff --git a/util/include/log.h b/util/include/log.h index ce390a0..d79ff00 100644 --- a/util/include/log.h +++ b/util/include/log.h @@ -14,11 +14,15 @@ namespace wvcdm { // Simple logging class. The implementation is platform dependent. typedef enum { - LOG_ERROR, - LOG_WARN, - LOG_INFO, - LOG_DEBUG, - LOG_VERBOSE + // This log level should only be used for |g_cutoff|, in order to silence all + // logging. It should never be passed to |Log()| as a log level. + LOG_SILENT = -1, + + LOG_ERROR = 0, + LOG_WARN = 1, + LOG_INFO = 2, + LOG_DEBUG = 3, + LOG_VERBOSE = 4, } LogPriority; extern LogPriority g_cutoff;