OEMCrypto v15.2
See the file docs/Widevine_Modular_DRM_Version_15_Delta.pdf for changes since version 15.1.
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
158
oem_certificate_generator/oem_certificate_test_helper.py
Normal file
158
oem_certificate_generator/oem_certificate_test_helper.py
Normal file
@@ -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)
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
* Reference APIs needed to support Widevine's crypto algorithms.
|
* Reference APIs needed to support Widevine's crypto algorithms.
|
||||||
*
|
*
|
||||||
* See the document "WV Modular DRM Security Integration Guide for Common
|
* 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
|
* can find this document in the widevine repository as
|
||||||
* docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf
|
* docs/WidevineModularDRMSecurityIntegrationGuideforCENC_v15.pdf
|
||||||
* Changes between different versions of this API are documented in the files
|
* 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;
|
typedef uint8_t RSA_Padding_Scheme;
|
||||||
// RSASSA-PSS with SHA1.
|
// 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).
|
// 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
|
* 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.
|
* Flags indicating full decrypt path hash supported.
|
||||||
*/
|
*/
|
||||||
const uint32_t OEMCrypto_Hash_Not_Supported = 0;
|
#define OEMCrypto_Hash_Not_Supported 0
|
||||||
const uint32_t OEMCrypto_CRC_Clear_Buffer = 1;
|
#define OEMCrypto_CRC_Clear_Buffer 1
|
||||||
const uint32_t OEMCrypto_Partner_Defined_Hash = 2;
|
#define OEMCrypto_Partner_Defined_Hash 2
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return values from OEMCrypto_GetAnalogOutputFlags.
|
* Return values from OEMCrypto_GetAnalogOutputFlags.
|
||||||
@@ -800,13 +800,17 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
|
|||||||
* before requesting more nonces, then OEMCrypto will reset the error
|
* before requesting more nonces, then OEMCrypto will reset the error
|
||||||
* condition and generate valid nonces again.
|
* 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:
|
* Parameters:
|
||||||
* [in] session: handle for the session to be used.
|
* [in] session: handle for the session to be used.
|
||||||
* [out] nonce: pointer to memory to receive the computed nonce.
|
* [out] nonce: pointer to memory to receive the computed nonce.
|
||||||
*
|
*
|
||||||
* Results:
|
* Results:
|
||||||
* nonce: the nonce is also stored in secure memory. At least 4 nonces should
|
* nonce: the nonce is also stored in secure memory. Each session should
|
||||||
* be stored for each session.
|
* store 4 nonces.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* OEMCrypto_SUCCESS success
|
* OEMCrypto_SUCCESS success
|
||||||
@@ -817,11 +821,9 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
|
|||||||
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
* OEMCrypto_ERROR_SYSTEM_INVALIDATED
|
||||||
*
|
*
|
||||||
* Threading:
|
* Threading:
|
||||||
* This is a "Session Function" and may be called simultaneously with session
|
* This is a "Session Initialization Function" and will not be called
|
||||||
* functions for other sessions but not simultaneously with other functions
|
* simultaneously with any other function, as if the CDM holds a write lock
|
||||||
* for this session. It will not be called simultaneously with initialization
|
* on the OEMCrypto system.
|
||||||
* 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:
|
* Version:
|
||||||
* This method changed in API version 5.
|
* 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
|
* entry is marked as "inactive" (either kInactiveUsed or
|
||||||
* kInactiveUnused), then the keys are not loaded, and the error
|
* kInactiveUnused), then the keys are not loaded, and the error
|
||||||
* OEMCrypto_ERROR_LICENSE_INACTIVE is returned.
|
* 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)
|
* Usage Table and Provider Session Token (pst)
|
||||||
*
|
*
|
||||||
* If a key control block has a nonzero value for Replay_Control, then all
|
* 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
|
* 6. If the current session has an entry in the Usage Table, and the
|
||||||
* status of that entry is either kInactiveUsed or kInactiveUnused, then
|
* status of that entry is either kInactiveUsed or kInactiveUnused, then
|
||||||
* return the error OEMCrypto_ERROR_LICENSE_INACTIVE.
|
* return the error OEMCrypto_ERROR_LICENSE_INACTIVE.
|
||||||
* 7. If an Decrypt Hash has been initialized via OEMCrypto_SetDecryptHash,
|
* 7. If a Decrypt Hash has been initialized via OEMCrypto_SetDecryptHash,
|
||||||
* and the current key's control block does not have the
|
* and the current key's control block does not have the
|
||||||
* Allow_Hash_Verification bit set, then do not compute a hash and
|
* Allow_Hash_Verification bit set, then do not compute a hash and
|
||||||
* return OEMCrypto_ERROR_UNKNOWN_FAILURE.
|
* return OEMCrypto_ERROR_UNKNOWN_FAILURE.
|
||||||
* If the flag is_encrypted is false, then no verification is performed. This
|
* 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:
|
* Version:
|
||||||
* This method is new API version 12.
|
* This method is new API version 12.
|
||||||
*/
|
*/
|
||||||
OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod();
|
OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_IsKeyboxOrOEMCertValid
|
* OEMCrypto_IsKeyboxOrOEMCertValid
|
||||||
@@ -2257,7 +2262,7 @@ OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void);
|
|||||||
* system upgrade.
|
* system upgrade.
|
||||||
*
|
*
|
||||||
* This function is optional but recommended for Provisioning 3.0 in API v15.
|
* 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:
|
* Parameters:
|
||||||
* [out] deviceId - pointer to the buffer that receives the Device ID
|
* [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:
|
* Version:
|
||||||
* This method changed in each API version.
|
* This method changed in each API version.
|
||||||
*/
|
*/
|
||||||
uint32_t OEMCrypto_APIVersion();
|
uint32_t OEMCrypto_APIVersion(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_BuildInformation
|
* OEMCrypto_BuildInformation
|
||||||
@@ -2497,7 +2502,7 @@ uint32_t OEMCrypto_APIVersion();
|
|||||||
* Version:
|
* Version:
|
||||||
* This method changed in each API version.
|
* This method changed in each API version.
|
||||||
*/
|
*/
|
||||||
const char* OEMCrypto_BuildInformation();
|
const char* OEMCrypto_BuildInformation(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_Security_Patch_Level
|
* OEMCrypto_Security_Patch_Level
|
||||||
@@ -2524,7 +2529,7 @@ const char* OEMCrypto_BuildInformation();
|
|||||||
* Version:
|
* Version:
|
||||||
* This method was introduced in API version 11.
|
* This method was introduced in API version 11.
|
||||||
*/
|
*/
|
||||||
uint8_t OEMCrypto_Security_Patch_Level();
|
uint8_t OEMCrypto_Security_Patch_Level(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_SecurityLevel
|
* OEMCrypto_SecurityLevel
|
||||||
@@ -2550,7 +2555,7 @@ uint8_t OEMCrypto_Security_Patch_Level();
|
|||||||
* Version:
|
* Version:
|
||||||
* This method changed in API version 6.
|
* This method changed in API version 6.
|
||||||
*/
|
*/
|
||||||
const char* OEMCrypto_SecurityLevel();
|
const char* OEMCrypto_SecurityLevel(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_GetHDCPCapability
|
* OEMCrypto_GetHDCPCapability
|
||||||
@@ -2565,12 +2570,6 @@ const char* OEMCrypto_SecurityLevel();
|
|||||||
* instead of HDMI output. Notice that HDCP must use flag Type 1: all
|
* instead of HDMI output. Notice that HDCP must use flag Type 1: all
|
||||||
* downstream devices will also use the same version or higher.
|
* 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
|
* 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
|
* 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
|
* 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
|
* user intends to view the content on a local display. The user will want to
|
||||||
* download the higher quality content.
|
* 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
|
* 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
|
* connect to a display only if that protocol supports the version of HDCP as
|
||||||
* required by the license. Both WirelessHD (formerly WiFi Display) and
|
* required by the license. Both WirelessHD (formerly WiFi Display) and
|
||||||
@@ -2633,7 +2656,7 @@ OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability* current,
|
|||||||
* Version:
|
* Version:
|
||||||
* This method changed in API version 9.
|
* This method changed in API version 9.
|
||||||
*/
|
*/
|
||||||
bool OEMCrypto_SupportsUsageTable();
|
bool OEMCrypto_SupportsUsageTable(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_IsAntiRollbackHwPresent
|
* OEMCrypto_IsAntiRollbackHwPresent
|
||||||
@@ -2661,7 +2684,7 @@ bool OEMCrypto_SupportsUsageTable();
|
|||||||
* Version:
|
* Version:
|
||||||
* This method is new in API version 10.
|
* This method is new in API version 10.
|
||||||
*/
|
*/
|
||||||
bool OEMCrypto_IsAntiRollbackHwPresent();
|
bool OEMCrypto_IsAntiRollbackHwPresent(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_GetNumberOfOpenSessions
|
* OEMCrypto_GetNumberOfOpenSessions
|
||||||
@@ -2762,7 +2785,7 @@ OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max);
|
|||||||
* Version:
|
* Version:
|
||||||
* This method changed in API version 13.
|
* This method changed in API version 13.
|
||||||
*/
|
*/
|
||||||
uint32_t OEMCrypto_SupportedCertificates();
|
uint32_t OEMCrypto_SupportedCertificates(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_IsSRMUpdateSupported
|
* OEMCrypto_IsSRMUpdateSupported
|
||||||
@@ -2789,7 +2812,7 @@ uint32_t OEMCrypto_SupportedCertificates();
|
|||||||
* Version:
|
* Version:
|
||||||
* This method changed in API version 13.
|
* This method changed in API version 13.
|
||||||
*/
|
*/
|
||||||
bool OEMCrypto_IsSRMUpdateSupported();
|
bool OEMCrypto_IsSRMUpdateSupported(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_GetCurrentSRMVersion
|
* OEMCrypto_GetCurrentSRMVersion
|
||||||
@@ -2856,7 +2879,7 @@ OEMCryptoResult OEMCrypto_GetCurrentSRMVersion(uint16_t* version);
|
|||||||
* Version:
|
* Version:
|
||||||
* This method is new in API version 14.
|
* This method is new in API version 14.
|
||||||
*/
|
*/
|
||||||
uint32_t OEMCrypto_GetAnalogOutputFlags();
|
uint32_t OEMCrypto_GetAnalogOutputFlags(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_ResourceRatingTier
|
* OEMCrypto_ResourceRatingTier
|
||||||
@@ -2865,7 +2888,7 @@ uint32_t OEMCrypto_GetAnalogOutputFlags();
|
|||||||
* This function returns a positive number indicating which resource rating
|
* This function returns a positive number indicating which resource rating
|
||||||
* it supports. This value will bubble up to the application level as a
|
* it supports. This value will bubble up to the application level as a
|
||||||
* property. This will allow applications to estimate what resolution and
|
* 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
|
* OEMCrypto unit tests and Android GTS tests will verify that devices do
|
||||||
* support the resource values specified in the table below at the tier
|
* 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 |
|
* |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 |
|
* |Decrypted Frames per Second |30 fps SD |30 fps HD |60 fps HD |
|
||||||
* +-----------------------------------+-----------+------------+-----------+
|
* +-----------------------------------+-----------+------------+-----------+
|
||||||
*
|
*
|
||||||
@@ -2945,7 +2966,7 @@ uint32_t OEMCrypto_GetAnalogOutputFlags();
|
|||||||
* Version:
|
* Version:
|
||||||
* This method is new in API version 15.
|
* This method is new in API version 15.
|
||||||
*/
|
*/
|
||||||
uint32_t OEMCrypto_ResourceRatingTier();
|
uint32_t OEMCrypto_ResourceRatingTier(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_RewrapDeviceRSAKey30
|
* OEMCrypto_RewrapDeviceRSAKey30
|
||||||
@@ -3306,7 +3327,7 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
|
|||||||
* Version:
|
* Version:
|
||||||
* This method is new in API version 10.
|
* This method is new in API version 10.
|
||||||
*/
|
*/
|
||||||
OEMCryptoResult OEMCrypto_LoadTestRSAKey();
|
OEMCryptoResult OEMCrypto_LoadTestRSAKey(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_GenerateRSASignature
|
* 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
|
* 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
|
* 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 generation number, and the header's master generation number. The
|
||||||
* entry's flag ForbidReport will be set. This flag prevents an application
|
* corresponding generation number in the usage table header is also
|
||||||
* from generating a report of a deactivated license without first saving the
|
* 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.
|
* entry.
|
||||||
*
|
*
|
||||||
* It is allowed to call this function multiple times. If the state is
|
* It is allowed to call this function multiple times. If the state is
|
||||||
@@ -3954,14 +3977,14 @@ OEMCryptoResult OEMCrypto_CopyOldUsageEntry(OEMCrypto_SESSION session,
|
|||||||
* Version:
|
* Version:
|
||||||
* This method is new in API version 13.
|
* This method is new in API version 13.
|
||||||
*/
|
*/
|
||||||
OEMCryptoResult OEMCrypto_DeleteOldUsageTable();
|
OEMCryptoResult OEMCrypto_DeleteOldUsageTable(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_RemoveSRM
|
* OEMCrypto_RemoveSRM
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Delete the current SRM. Any valid SRM, regardless of version number, will
|
* Delete the current SRM. Any valid SRM, regardless of its version number,
|
||||||
* be installable after this via OEMCrypto_LoadSRM.
|
* will be installable after this via OEMCrypto_LoadSRM.
|
||||||
*
|
*
|
||||||
* This function should not be implemented on production devices, and will
|
* This function should not be implemented on production devices, and will
|
||||||
* only be used to verify unit tests on a test device.
|
* only be used to verify unit tests on a test device.
|
||||||
@@ -3981,7 +4004,7 @@ OEMCryptoResult OEMCrypto_DeleteOldUsageTable();
|
|||||||
* Version:
|
* Version:
|
||||||
* This method is new in API version 13.
|
* This method is new in API version 13.
|
||||||
*/
|
*/
|
||||||
OEMCryptoResult OEMCrypto_RemoveSRM();
|
OEMCryptoResult OEMCrypto_RemoveSRM(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_CreateOldUsageEntry
|
* 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,
|
* supported. OEMCrypto is not required by Google to support this feature,
|
||||||
* but support will greatly improve automated testing. A hash type of
|
* but support will greatly improve automated testing. A hash type of
|
||||||
* OEMCrypto_CRC_Clear_Buffer = 1 means the device will be able to compute
|
* 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
|
* call to OEMCrypto_DecryptCENC. Google intends to provide test applications
|
||||||
* on some platforms, such as Android, that will automate decryption testing
|
* on some platforms, such as Android, that will automate decryption testing
|
||||||
* using the CRC 32 checksum of all frames in some test content.
|
* 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:
|
* Version:
|
||||||
* This method is new in API version 15.
|
* This method is new in API version 15.
|
||||||
*/
|
*/
|
||||||
uint32_t OEMCrypto_SupportsDecryptHash();
|
uint32_t OEMCrypto_SupportsDecryptHash(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OEMCrypto_SetDecryptHash
|
* OEMCrypto_SetDecryptHash
|
||||||
|
|||||||
@@ -182,6 +182,14 @@ time_t CryptoEngine::RollbackCorrectedOfflineTime() {
|
|||||||
return current_time;
|
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() {
|
OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() {
|
||||||
return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1;
|
return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,10 @@ class CryptoEngine {
|
|||||||
|
|
||||||
time_t RollbackCorrectedOfflineTime();
|
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.
|
// Returns the HDCP version currently in use.
|
||||||
virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability();
|
virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability();
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ bool NonceTable::CheckNonce(uint32_t nonce) {
|
|||||||
return false;
|
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() {
|
void NonceTable::Flush() {
|
||||||
for (int i = 0; i < kTableSize; ++i) {
|
for (int i = 0; i < kTableSize; ++i) {
|
||||||
if (kNTStateFlushPending == state_[i]) {
|
if (kNTStateFlushPending == state_[i]) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace wvoec_ref {
|
|||||||
|
|
||||||
class NonceTable {
|
class NonceTable {
|
||||||
public:
|
public:
|
||||||
static const int kTableSize = 16;
|
static const int kTableSize = 4;
|
||||||
NonceTable() {
|
NonceTable() {
|
||||||
for (int i = 0; i < kTableSize; ++i) {
|
for (int i = 0; i < kTableSize; ++i) {
|
||||||
state_[i] = kNTStateInvalid;
|
state_[i] = kNTStateInvalid;
|
||||||
@@ -22,6 +22,8 @@ class NonceTable {
|
|||||||
~NonceTable() {}
|
~NonceTable() {}
|
||||||
void AddNonce(uint32_t nonce);
|
void AddNonce(uint32_t nonce);
|
||||||
bool CheckNonce(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();
|
void Flush();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -189,13 +189,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
|
|||||||
last_nonce_time = now;
|
last_nonce_time = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t nonce_value;
|
uint32_t nonce_value = 0;
|
||||||
uint8_t* nonce_string = reinterpret_cast<uint8_t*>(&nonce_value);
|
uint8_t* nonce_string = reinterpret_cast<uint8_t*>(&nonce_value);
|
||||||
|
|
||||||
// Generate 4 bytes of random data
|
while (nonce_value == 0 || crypto_engine->NonceCollision(nonce_value)) {
|
||||||
if (!RAND_bytes(nonce_string, 4)) {
|
// Generate 4 bytes of random data
|
||||||
LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]");
|
if (!RAND_bytes(nonce_string, 4)) {
|
||||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
LOGE("[OEMCrypto_GenerateNonce(): Random bytes failure]");
|
||||||
|
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
session_ctx->AddNonce(nonce_value);
|
session_ctx->AddNonce(nonce_value);
|
||||||
*nonce = nonce_value;
|
*nonce = nonce_value;
|
||||||
@@ -281,9 +283,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys(
|
|||||||
!RangeCheck(message_length, enc_mac_keys, true) ||
|
!RangeCheck(message_length, enc_mac_keys, true) ||
|
||||||
!RangeCheck(message_length, pst, true) ||
|
!RangeCheck(message_length, pst, true) ||
|
||||||
!RangeCheck(message_length, srm_restriction_data, true)) {
|
!RangeCheck(message_length, srm_restriction_data, true)) {
|
||||||
LOGE(
|
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - "
|
||||||
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - range "
|
"range check.]");
|
||||||
"check.]");
|
|
||||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
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_data_iv, false) ||
|
||||||
!RangeCheck(message_length, key_array[i].key_control, false) ||
|
!RangeCheck(message_length, key_array[i].key_control, false) ||
|
||||||
!RangeCheck(message_length, key_array[i].key_control_iv, false)) {
|
!RangeCheck(message_length, key_array[i].key_control_iv, false)) {
|
||||||
LOGE(
|
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - "
|
||||||
"[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT -range "
|
"range check %d]", i);
|
||||||
"check %d]",
|
|
||||||
i);
|
|
||||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
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,
|
return session_ctx->LoadKeys(message, message_length, signature,
|
||||||
signature_length, enc_mac_keys_iv, enc_mac_keys,
|
signature_length, enc_mac_keys_iv, enc_mac_keys,
|
||||||
num_keys, key_array, pst, srm_restriction_data,
|
num_keys, key_array, pst, srm_restriction_data,
|
||||||
|
|||||||
@@ -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 <stddef.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
|
|
||||||
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 <typename T>
|
|
||||||
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<T> ptr_;
|
|
||||||
};
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
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<T> ptr_;
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace wvoec_ref
|
|
||||||
|
|
||||||
#endif // OEMCRYPTO_SCOPED_PTR_H_
|
|
||||||
@@ -636,6 +636,7 @@ OEMCryptoResult SessionContext::LoadKeys(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
encryption_key_.clear();
|
||||||
return OEMCrypto_SUCCESS;
|
return OEMCrypto_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -173,6 +173,10 @@ class SessionContext {
|
|||||||
|
|
||||||
void AddNonce(uint32_t nonce);
|
void AddNonce(uint32_t nonce);
|
||||||
bool CheckNonce(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();
|
void FlushNonces();
|
||||||
|
|
||||||
virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
|
virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
|
||||||
|
|||||||
@@ -153,33 +153,12 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
|
|||||||
if (provisioning_method
|
if (provisioning_method
|
||||||
!= OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*");
|
!= OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*");
|
||||||
if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*");
|
if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*");
|
||||||
if (api_version < 14) {
|
if (api_version < 9) FilterOut(&filter, "*API09*");
|
||||||
// Because API 13 uses an old hard coded test keybox, none of these tests
|
if (api_version < 10) FilterOut(&filter, "*API10*");
|
||||||
// will pass. Partners who wish to test with a v13 OEMCrypto should use
|
if (api_version < 11) FilterOut(&filter, "*API11*");
|
||||||
// code on an older v13 branch.
|
if (api_version < 12) FilterOut(&filter, "*API12*");
|
||||||
printf("These unit tests are designed for OEMCrypto API 15 and above.\n");
|
if (api_version < 13) FilterOut(&filter, "*API13*");
|
||||||
printf("This device has an OEMCrypto with API version %d.\n", api_version);
|
if (api_version < 14) FilterOut(&filter, "*API14*");
|
||||||
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 < 15) FilterOut(&filter, "*API15*");
|
if (api_version < 15) FilterOut(&filter, "*API15*");
|
||||||
// Some tests may require root access. If user is not root, filter these tests
|
// Some tests may require root access. If user is not root, filter these tests
|
||||||
// out.
|
// out.
|
||||||
|
|||||||
@@ -539,6 +539,7 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
|
|||||||
uint32_t nonce, const std::string& pst) {
|
uint32_t nonce, const std::string& pst) {
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
1, GetRandBytes(license_.mac_key_iv, sizeof(license_.mac_key_iv)));
|
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)));
|
EXPECT_EQ(1, GetRandBytes(license_.mac_keys, sizeof(license_.mac_keys)));
|
||||||
for (unsigned int i = 0; i < num_keys_; i++) {
|
for (unsigned int i = 0; i < num_keys_; i++) {
|
||||||
memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength);
|
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);
|
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||||
}
|
}
|
||||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
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.
|
pst_report_buffer_.assign(length, 0xFF); // Fill with garbage values.
|
||||||
}
|
}
|
||||||
sts = OEMCrypto_ReportUsage(session_id(),
|
sts = OEMCrypto_ReportUsage(session_id(),
|
||||||
@@ -1278,7 +1278,7 @@ void Session::GenerateReport(const std::string& pst,
|
|||||||
if (expected_result != OEMCrypto_SUCCESS) {
|
if (expected_result != OEMCrypto_SUCCESS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASSERT_EQ(pst_report_buffer_.size(), length);
|
EXPECT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length);
|
||||||
vector<uint8_t> computed_signature(SHA_DIGEST_LENGTH);
|
vector<uint8_t> computed_signature(SHA_DIGEST_LENGTH);
|
||||||
unsigned int sig_len = SHA_DIGEST_LENGTH;
|
unsigned int sig_len = SHA_DIGEST_LENGTH;
|
||||||
HMAC(EVP_sha1(), mac_key_client_.data(), mac_key_client_.size(),
|
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);
|
Test_PST_Report expected(pst, status);
|
||||||
ASSERT_NO_FATAL_FAILURE(VerifyReport(expected, time_license_received,
|
ASSERT_NO_FATAL_FAILURE(VerifyReport(expected, time_license_received,
|
||||||
time_first_decrypt, time_last_decrypt));
|
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) {
|
void Session::CreateOldEntry(const Test_PST_Report& report) {
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ typedef struct {
|
|||||||
struct MessageData {
|
struct MessageData {
|
||||||
MessageKeyData keys[kMaxNumKeys];
|
MessageKeyData keys[kMaxNumKeys];
|
||||||
uint8_t mac_key_iv[KEY_IV_SIZE];
|
uint8_t mac_key_iv[KEY_IV_SIZE];
|
||||||
|
uint8_t padding[KEY_IV_SIZE];
|
||||||
uint8_t mac_keys[2 * MAC_KEY_SIZE];
|
uint8_t mac_keys[2 * MAC_KEY_SIZE];
|
||||||
uint8_t pst[kMaxPSTLength];
|
uint8_t pst[kMaxPSTLength];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,41 @@
|
|||||||
|
|
||||||
namespace wvoec {
|
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
|
// 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
|
// 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.
|
// to a test are predictable and can be compared to the actual results.
|
||||||
|
|||||||
@@ -105,6 +105,8 @@ void SessionUtil::EnsureTestKeys() {
|
|||||||
switch (global_features.derive_key_method) {
|
switch (global_features.derive_key_method) {
|
||||||
case DeviceFeatures::LOAD_TEST_KEYBOX:
|
case DeviceFeatures::LOAD_TEST_KEYBOX:
|
||||||
keybox_ = kTestKeybox;
|
keybox_ = kTestKeybox;
|
||||||
|
// TODO(fredgc, b/119316243): REMOVE FOLLOWING LINE:
|
||||||
|
if (global_features.api_version < 14) keybox_ = kTestKeyboxForV13;
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||||
OEMCrypto_LoadTestKeybox(
|
OEMCrypto_LoadTestKeybox(
|
||||||
reinterpret_cast<const uint8_t*>(&keybox_),
|
reinterpret_cast<const uint8_t*>(&keybox_),
|
||||||
|
|||||||
@@ -871,6 +871,24 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoNonce) {
|
|||||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
|
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.
|
// Verify that a license may be loaded with a nonce.
|
||||||
TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) {
|
TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) {
|
||||||
Session s;
|
Session s;
|
||||||
@@ -882,6 +900,24 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) {
|
|||||||
ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys());
|
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
|
// 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.
|
// lost. OEMCrypto is required to keep up to four nonce in the nonce table.
|
||||||
TEST_F(OEMCryptoSessionTests, LoadKeySeveralNonce) {
|
TEST_F(OEMCryptoSessionTests, LoadKeySeveralNonce) {
|
||||||
@@ -1179,6 +1215,27 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) {
|
|||||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
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 that LoadKeys fails when a key is loaded with no key control block.
|
||||||
TEST_F(OEMCryptoSessionTests, LoadKeyWithNullKeyControl) {
|
TEST_F(OEMCryptoSessionTests, LoadKeyWithNullKeyControl) {
|
||||||
Session s;
|
Session s;
|
||||||
@@ -5396,9 +5453,9 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithRefresh) {
|
|||||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that a license that has been we can still reload an offline license
|
// Verify that we can still reload an offline license after OEMCrypto_Terminate
|
||||||
// after OEMCrypto_Terminate and Initialize are called. This is as close to a
|
// and Initialize are called. This is as close to a reboot as we can do in a
|
||||||
// reboot as we can do in a unit test.
|
// unit test.
|
||||||
TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithTerminate) {
|
TEST_P(UsageTableTestWithMAC, ReloadOfflineLicenseWithTerminate) {
|
||||||
std::string pst = "my_pst";
|
std::string pst = "my_pst";
|
||||||
Session s;
|
Session s;
|
||||||
|
|||||||
@@ -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) {
|
TEST_F(OEMCryptoAndroidLMPTest, ValidKeyboxTest) {
|
||||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
|
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
|
||||||
}
|
}
|
||||||
@@ -108,6 +113,11 @@ TEST_F(OEMCryptoAndroidLMPTest, Level1Required) {
|
|||||||
// These tests are required for M Android devices.
|
// These tests are required for M Android devices.
|
||||||
class OEMCryptoAndroidMNCTest : public OEMCryptoAndroidLMPTest {};
|
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.
|
// 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.
|
// If they are not using Provisioning 2.0, then they must use Provisioning 3.0.
|
||||||
TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) {
|
TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) {
|
||||||
@@ -135,4 +145,28 @@ TEST_F(OEMCryptoAndroidMNCTest, QueryKeyControlImplemented) {
|
|||||||
OEMCrypto_QueryKeyControl(0, NULL, 0, NULL, NULL));
|
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
|
} // namespace wvoec
|
||||||
|
|||||||
@@ -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_
|
|
||||||
@@ -14,11 +14,15 @@ namespace wvcdm {
|
|||||||
// Simple logging class. The implementation is platform dependent.
|
// Simple logging class. The implementation is platform dependent.
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LOG_ERROR,
|
// This log level should only be used for |g_cutoff|, in order to silence all
|
||||||
LOG_WARN,
|
// logging. It should never be passed to |Log()| as a log level.
|
||||||
LOG_INFO,
|
LOG_SILENT = -1,
|
||||||
LOG_DEBUG,
|
|
||||||
LOG_VERBOSE
|
LOG_ERROR = 0,
|
||||||
|
LOG_WARN = 1,
|
||||||
|
LOG_INFO = 2,
|
||||||
|
LOG_DEBUG = 3,
|
||||||
|
LOG_VERBOSE = 4,
|
||||||
} LogPriority;
|
} LogPriority;
|
||||||
|
|
||||||
extern LogPriority g_cutoff;
|
extern LogPriority g_cutoff;
|
||||||
|
|||||||
Reference in New Issue
Block a user