diff --git a/oem_certificate_generator/oem_certificate.py b/oem_certificate_generator/oem_certificate.py
old mode 100644
new mode 100755
index 8d17c98..71e7789
--- a/oem_certificate_generator/oem_certificate.py
+++ b/oem_certificate_generator/oem_certificate.py
@@ -1,3 +1,4 @@
+#!/usr/bin/python3
# Copyright 2017 Google LLC. All Rights Reserved.
"""OEM certificate generation tool.
@@ -110,7 +111,7 @@ class X509CertificateChain(object):
x509_stack = pkcs7.d.sign.cert
certificates = []
- for i in xrange(backend._lib.sk_X509_num(x509_stack)):
+ for i in range(backend._lib.sk_X509_num(x509_stack)):
x509_value = backend._ffi.gc(
backend._lib.X509_dup(backend._lib.sk_X509_value(x509_stack, i)),
backend._lib.X509_free)
@@ -134,6 +135,10 @@ class X509CertificateChain(object):
return backend._read_mem_bio(bio)
+# Type for argparse to accept byte buffers on the command line
+def utf8_bytes(utf8_str):
+ return utf8_str.encode('utf-8')
+
def _multiple_of_1024(key_size_str):
"""argparse custom type function for key size."""
key_size = int(key_size_str)
@@ -299,9 +304,9 @@ def generate_leaf_certificate(args):
def secure_erase(args):
"""Subparser handler for secure erasing of a file."""
length = args.file.tell()
- for _ in xrange(args.passes):
+ for _ in range(args.passes):
args.file.seek(0)
- for _ in xrange(length):
+ for _ in range(length):
args.file.write(os.urandom(1))
args.file.close()
os.remove(args.file.name)
@@ -403,6 +408,7 @@ def create_parser():
'--output_private_key_file', type=argparse.FileType('wb'), required=True)
parser_csr.add_argument(
'--passphrase',
+ type=utf8_bytes,
help=('specify an optional passphrase to encrypt the private key. The '
'private key is not encrypted if omitted.'))
parser_csr.set_defaults(func=generate_csr)
@@ -429,7 +435,7 @@ def create_parser():
'--root_certificate_file', type=argparse.FileType('rb'), required=True)
parser_intermediate_cert.add_argument(
'--root_private_key_file', type=argparse.FileType('rb'), required=True)
- parser_intermediate_cert.add_argument('--root_private_key_passphrase')
+ parser_intermediate_cert.add_argument('--root_private_key_passphrase', type=utf8_bytes)
parser_intermediate_cert.add_argument(
'--output_certificate_file', type=argparse.FileType('wb'), required=True)
parser_intermediate_cert.set_defaults(func=generate_intermediate_certificate)
@@ -460,13 +466,14 @@ def create_parser():
'--intermediate_private_key_file',
type=argparse.FileType('rb'),
required=True)
- parser_leaf_cert.add_argument('--intermediate_private_key_passphrase')
+ parser_leaf_cert.add_argument('--intermediate_private_key_passphrase', type=utf8_bytes)
parser_leaf_cert.add_argument(
'--output_certificate_file', type=argparse.FileType('wb'), required=True)
parser_leaf_cert.add_argument(
'--output_private_key_file', type=argparse.FileType('wb'), required=True)
parser_leaf_cert.add_argument(
'--passphrase',
+ type=utf8_bytes,
help=('specify an optional passphrase to encrypt the private key. The '
'private key is not encrypted if omitted.'))
parser_leaf_cert.set_defaults(func=generate_leaf_certificate)
@@ -497,7 +504,7 @@ def main():
args = sys.argv[1:]
config_file_name = 'oem_certificate.cfg'
if os.path.isfile(config_file_name):
- print 'Load from args default configuration file: ', config_file_name
+ print('Load from args default configuration file: ', config_file_name)
args.append('@' + config_file_name)
parser_args = create_parser().parse_args(args)
parser_args.func(parser_args)
diff --git a/oem_certificate_generator/oem_certificate_test_helper.py b/oem_certificate_generator/oem_certificate_test_helper.py
index eccb125..75de4ae 100644
--- a/oem_certificate_generator/oem_certificate_test_helper.py
+++ b/oem_certificate_generator/oem_certificate_test_helper.py
@@ -1,9 +1,10 @@
+#!/usr/bin/python3
# Copyright 2017 Google LLC. All Rights Reserved.
"""Common test utility functions for OEM certificate generation."""
import datetime
-import StringIO
+import io
from cryptography import x509
from cryptography.hazmat import backends
@@ -24,7 +25,7 @@ _NOT_VALID_BEFORE = datetime.datetime(2001, 8, 9)
_VALID_DURATION = 100
_LEAF_CERT_VALID_DURATION = 8000
_SYSTEM_ID = 2001
-_ROOT_PRIVATE_KEY_PASSPHRASE = 'root_passphrase'
+_ROOT_PRIVATE_KEY_PASSPHRASE = b'root_passphrase'
class ArgParseObject(object):
@@ -67,11 +68,11 @@ def setup_csr_args(country_name=_COUNTRY_NAME,
if output_csr_file:
args.output_csr_file = output_csr_file
else:
- args.output_csr_file = StringIO.StringIO()
+ args.output_csr_file = io.BytesIO()
if output_private_key_file:
args.output_private_key_file = output_private_key_file
else:
- args.output_private_key_file = StringIO.StringIO()
+ args.output_private_key_file = io.BytesIO()
args.passphrase = passphrase
return args
@@ -86,12 +87,12 @@ def setup_intermediate_cert_args(
args.not_valid_before = not_valid_before
args.valid_duration = valid_duration
args.system_id = system_id
- args.csr_file = StringIO.StringIO(csr_bytes)
+ args.csr_file = io.BytesIO(csr_bytes)
args.root_private_key_passphrase = root_private_key_passphrase
if output_certificate_file:
args.output_certificate_file = output_certificate_file
else:
- args.output_certificate_file = StringIO.StringIO()
+ args.output_certificate_file = io.BytesIO()
serialized_private_key = root_key.private_bytes(
serialization.Encoding.DER,
@@ -100,8 +101,8 @@ def setup_intermediate_cert_args(
args.root_private_key_passphrase))
serialized_certificate = root_certificate.public_bytes(
serialization.Encoding.DER)
- args.root_certificate_file = StringIO.StringIO(serialized_certificate)
- args.root_private_key_file = StringIO.StringIO(serialized_private_key)
+ args.root_certificate_file = io.BytesIO(serialized_certificate)
+ args.root_private_key_file = io.BytesIO(serialized_private_key)
return args
@@ -122,16 +123,16 @@ def setup_leaf_cert_args(intermediate_key_bytes,
if output_certificate_file:
args.output_certificate_file = output_certificate_file
else:
- args.output_certificate_file = StringIO.StringIO()
+ args.output_certificate_file = io.BytesIO()
if output_private_key_file:
args.output_private_key_file = output_private_key_file
else:
- args.output_private_key_file = StringIO.StringIO()
+ args.output_private_key_file = io.BytesIO()
args.passphrase = passphrase
- args.intermediate_private_key_file = StringIO.StringIO(
+ args.intermediate_private_key_file = io.BytesIO(
intermediate_key_bytes)
- args.intermediate_certificate_file = StringIO.StringIO(
+ args.intermediate_certificate_file = io.BytesIO(
intermediate_certificate_bytes)
return args
diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h
index 36ccaae..b933ce1 100644
--- a/oemcrypto/include/OEMCryptoCENC.h
+++ b/oemcrypto/include/OEMCryptoCENC.h
@@ -3,7 +3,7 @@
// License Agreement.
/**
- * @mainpage OEMCrypto API
+ * @mainpage OEMCrypto API v17
*
* OEMCrypto is the low level library implemented by the OEM to provide key and
* content protection, usually in a separate secure memory or process space. The
@@ -103,6 +103,17 @@
* provisioning procedure and implemented in the library, but are not called
* from the Widevine DRM Plugin during normal operation.
*
+ * @defgroup prov40 OEM Certificate and Provisioning 4.0 API
+ * Functions that are needed process a boot chain certificate.
+ *
+ * The OEMCrypto API allows for a device to be initially provisioned with a
+ * keybox or with an OEM certificate in the factory, or to use a boot chain
+ * derived by the device using a device specific key.
+ * See the section Provisioning
+ * in the integration guide.
+ * The functions in this section are for devices that are provisioned with a
+ * boot chain, i.e. Provisioning 4.0.
+ *
* @defgroup validation Validation and Feature Support API
* The OEMCrypto API is flexible enough to allow different devices to support
* different features. This section has functions that specify the level of
@@ -126,10 +137,9 @@
*
* @defgroup test_verify Test and Verification API
* Functions that are designed to help test OEMCrypto and the device. They are
- * not used during normal operation. Some functions, like OEMCrypto_RemoveSRM()
- * should only be implemented on test devices. Other functions, like those that
- * test the full decrypt data path may be supported on a production device with
- * no added risk of security loss.
+ * not used during normal operation. Some functions, like those that test the
+ * full decrypt data path may be supported on a production device with no added
+ * risk of security loss.
*
* The following functions are used just for testing and verification of
* OEMCrypto and the CDM code.
@@ -210,17 +220,17 @@ typedef enum OEMCryptoBufferType {
* this instance of the structure. [variant] clear: This variant is valid
* when the type is OEMCrypto_BufferType_Clear. This OEMCrypto_DestBufferDesc
* indicates output should be written to a clear buffer.
- * @param[in] address: A pointer to the address in memory to begin writing
+ * @param[in] clear_buffer: A pointer to the address in memory to begin writing
* output.
- * @param[in] address_length: The length of the buffer that is available to
+ * @param[in] clear_buffer_length: The length of the buffer that is available to
* contain output. [variant] secure: This variant is valid when the type is
* OEMCrypto_BufferType_Secure. This OEMCrypto_DestBufferDesc indicates
* output should be written to a secure buffer. The decrypted output must
* never leave the secure area until it is output from the device.
- * @param[in] handle: An opaque handle to a secure buffer. The meaning of this
- * handle is platform-specific.
- * @param[in] handle_length: The length of the data contained in the secure
- * buffer.
+ * @param[in] secure_buffer: An opaque handle to a secure buffer. The meaning of
+ * this handle is platform-specific.
+ * @param[in] secure_buffer_length: The length of the data contained in the
+ * secure buffer.
* @param[in] offset: An offset indicating where in the secure buffer to start
* writing data. [variant] direct: This variant is valid when the type is
* OEMCrypto_BufferType_Direct. This OEMCrypto_DestBufferDesc indicates
@@ -236,12 +246,12 @@ typedef struct {
OEMCryptoBufferType type;
union {
struct { // type == OEMCrypto_BufferType_Clear
- OEMCrypto_SharedMemory* address;
- size_t address_length;
+ OEMCrypto_SharedMemory* clear_buffer;
+ size_t clear_buffer_length;
} clear;
struct { // type == OEMCrypto_BufferType_Secure
- void* handle;
- size_t handle_length;
+ void* secure_buffer;
+ size_t secure_buffer_length;
size_t offset;
} secure;
struct { // type == OEMCrypto_BufferType_Direct
@@ -349,13 +359,21 @@ typedef struct {
} OEMCrypto_CENCEncryptPatternDesc;
/**
- * OEMCryptoCipherMode is used in SelectKey to prepare a key for either CTR
- * decryption or CBC decryption.
+ * OEMCryptoCipherMode is used in SelectKey to prepare a key for decryption.
*/
typedef enum OEMCryptoCipherMode {
+ // explicit cipher modes used for modular DRM
+ OEMCrypto_CipherMode_CENC,
+ OEMCrypto_CipherMode_CBCS,
+ // cipher modes used for CAS
OEMCrypto_CipherMode_CTR,
OEMCrypto_CipherMode_CBC,
- OEMCrypto_CipherMode_MaxValue = OEMCrypto_CipherMode_CBC,
+ OEMCrypto_CipherMode_CSA2,
+ OEMCrypto_CipherMode_CSA3,
+ OEMCrypto_CipherMode_OFB,
+ OEMCrypto_CipherMode_SCTE,
+ OEMCrypto_CipherMode_ECB,
+ OEMCrypto_CipherMode_MaxValue = OEMCrypto_CipherMode_ECB,
} OEMCryptoCipherMode;
/**
@@ -364,21 +382,21 @@ typedef enum OEMCryptoCipherMode {
* padding.
* @param entitlement_key_id: entitlement key id to be matched to key table.
- * @param entitlement_key_id_length: length of entitlment_key_id in bytes (1 to
- * 16).
* @param content_key_id: content key id to be loaded into key table.
- * @param content_key_id_length: length of content key id in bytes (1 to 16).
* @param key_data_iv: the IV for performing AES-256-CBC decryption of the key
* data.
* @param key_data: encrypted content key data.
- * @param key_data_length: length of key_data: 16 or 32 depending on intended us
- e.
+ * @param content_iv: the IV for decrypting media content. Used by CAS only.
+ * @param cipher_mode: the encryption mode of the media content. Used by CAS
+ * only.
*/
typedef struct {
OEMCrypto_Substring entitlement_key_id;
OEMCrypto_Substring content_key_id;
OEMCrypto_Substring content_key_data_iv;
OEMCrypto_Substring content_key_data;
+ OEMCrypto_Substring content_iv;
+ OEMCryptoCipherMode cipher_mode;
} OEMCrypto_EntitledContentKeyObject;
/**
@@ -454,7 +472,8 @@ typedef struct {
*/
typedef enum OEMCrypto_Clock_Security_Level {
kInsecureClock = 0,
- kSecureTimer = 1,
+ kMonotonicClock = 1,
+ kSecureTimer = 1, // DEPRECATED. Do not use.
kSecureClock = 2,
kHardwareSecureClock = 3
} OEMCrypto_Clock_Security_Level;
@@ -474,26 +493,56 @@ typedef uint8_t RSA_Padding_Scheme;
* level, and in GetHDCPCapability for reporting.
*/
typedef enum OEMCrypto_HDCP_Capability {
- HDCP_NONE = 0, // No HDCP supported, no secure data path.
- HDCP_V1 = 1, // HDCP version 1.x
- HDCP_V2 = 2, // HDCP version 2.0 Type 1.
- HDCP_V2_1 = 3, // HDCP version 2.1 Type 1.
- HDCP_V2_2 = 4, // HDCP version 2.2 Type 1.
- HDCP_V2_3 = 5, // HDCP version 2.3 Type 1.
+ HDCP_NONE = 0, // No HDCP supported, no secure data path.
+ HDCP_V1 = 1, // HDCP version 1.x
+ HDCP_V2 = 2, // HDCP version 2.0 Type 1.
+ HDCP_V2_1 = 3, // HDCP version 2.1 Type 1.
+ HDCP_V2_2 = 4, // HDCP version 2.2 Type 1.
+ HDCP_V2_3 = 5, // HDCP version 2.3 Type 1.
+ // For backwards compatibility, these values are added after the V2 fields.
+ // However, it is optional for devices and they can still report HDCP_V1.
+ HDCP_V1_0 = 6,
+ HDCP_V1_1 = 7,
+ HDCP_V1_2 = 8,
+ HDCP_V1_3 = 9,
+ HDCP_V1_4 = 10,
HDCP_NO_DIGITAL_OUTPUT = 0xff // No digital output.
} OEMCrypto_HDCP_Capability;
+/**
+ * OEMCrypto_DTCP2_Capability is used in OEMCrypto_GetDTCP2Capability
+ * for reporting the level of DTCP2 support for a device.
+ */
+typedef enum OEMCrypto_DTCP2_Capability {
+ OEMCrypto_NO_DTCP2 = 0, // DTCP2 is not supported.
+ OEMCrypto_DTCP2_V1 = 1, // At least v1 of DTCP2 is supported.
+} OEMCrypto_DTCP2_Capability;
+
/**
Return value for OEMCrypto_GetProvisioningMethod().
*/
typedef enum OEMCrypto_ProvisioningMethod {
OEMCrypto_ProvisioningError = 0, // Device cannot be provisioned.
- OEMCrypto_DrmCertificate = 1, // Device has baked in DRM certificate
- // (level 3 only)
- OEMCrypto_Keybox = 2, // Device has factory installed unique keybox.
- OEMCrypto_OEMCertificate = 3 // Device has factory installed OEM certificate.
+ // Device has baked in DRM certificate (level 3 only).
+ OEMCrypto_DrmCertificate = 1,
+ // Device has factory installed unique keybox.
+ OEMCrypto_Keybox = 2,
+ // Device has factory installed OEM certificate.
+ OEMCrypto_OEMCertificate = 3,
+ // Device has Boot Certificate Chain (BCC).
+ OEMCrypto_BootCertificateChain = 4
} OEMCrypto_ProvisioningMethod;
+/**
+ Return value for OEMCrypto_GetWatermarkingSupport().
+ */
+typedef enum OEMCrypto_WatermarkingSupport {
+ OEMCrypto_WatermarkingError = 0,
+ OEMCrypto_WatermarkingNotSupported = 1,
+ OEMCrypto_WatermarkingConfigurable = 2,
+ OEMCrypto_WatermarkingAlwaysOn = 3,
+} OEMCrypto_WatermarkingSupport;
+
/**
* Flags indicating public/private key types supported.
*/
@@ -558,7 +607,7 @@ typedef enum OEMCrypto_ProvisioningMethod {
#define OEMCrypto_GenerateRSASignature_V8 _oecc20
#define OEMCrypto_DeriveKeysFromSessionKey _oecc21
#define OEMCrypto_APIVersion _oecc22
-#define OEMCrypto_SecurityLevel _oecc23
+#define OEMCrypto_SecurityLevel_V16 _oecc23
#define OEMCrypto_Generic_Encrypt _oecc24
#define OEMCrypto_Generic_Decrypt _oecc25
#define OEMCrypto_Generic_Sign _oecc26
@@ -615,9 +664,9 @@ typedef enum OEMCrypto_ProvisioningMethod {
#define OEMCrypto_InitializeDecryptHash _oecc87
#define OEMCrypto_SetDecryptHash _oecc88
#define OEMCrypto_GetHashErrorCode _oecc89
-#define OEMCrypto_BuildInformation _oecc90
+#define OEMCrypto_BuildInformation_V16 _oecc90
#define OEMCrypto_RefreshKeys _oecc91
-#define OEMCrypto_LoadEntitledContentKeys _oecc92
+#define OEMCrypto_LoadEntitledContentKeys_V16 _oecc92
#define OEMCrypto_CopyBuffer _oecc93
#define OEMCrypto_MaximumUsageTableHeaderSize _oecc94
#define OEMCrypto_GenerateDerivedKeys _oecc95
@@ -644,11 +693,25 @@ typedef enum OEMCrypto_ProvisioningMethod {
#define OEMCrypto_InstallOemPrivateKey _oecc118
#define OEMCrypto_ReassociateEntitledKeySession _oecc119
#define OEMCrypto_LoadCasECMKeys _oecc120
-#define OEMCrypto_LoadEntitledContentKeys_v17 _oecc121 // place holder for v17.
+#define OEMCrypto_LoadEntitledContentKeys _oecc121
+#define OEMCrypto_ProductionReady _oecc122
+#define OEMCrypto_Idle _oecc123
+#define OEMCrypto_Wake _oecc124
+#define OEMCrypto_BuildInformation _oecc125
+#define OEMCrypto_SecurityLevel _oecc126
+#define OEMCrypto_ReuseUsageEntry _oecc127
+#define OEMCrypto_GetDTCP2Capability _oecc128
+#define OEMCrypto_GetWatermarkingSupport _oecc129
// clang-format on
/// @addtogroup initcontrol
/// @{
+/** Specifies whether system is in idle mode.
+ */
+typedef enum OEMCrypto_IdleState {
+ OEMCrypto_NoCryptoActivity = 0, // The system is not idle, but OEMCrypto is.
+ OEMCrypto_CpuSuspend = 1,
+} OEMCrypto_IdleState;
/**
* This tells OEMCrypto which sandbox the current process belongs to. Any
@@ -722,6 +785,76 @@ OEMCryptoResult OEMCrypto_Initialize(void);
*/
OEMCryptoResult OEMCrypto_Terminate(void);
+/**
+ * If possible, OEMCrypto may reduce power consumption or other resources. For
+ * example, it may be possible to reduce the CPU clock rates. When the system
+ * is in idle mode, then the CDM will not call OEMCrypto_GetHDCPCapability.
+ *
+ * This function is not required -- OEMCrypto may ignore this function. It is
+ * only used to improve performance. This function may return
+ * OEMCrypto_ERROR_NOT_IMPLEMENTED to indicate it is not supported.
+ *
+ * OEMCrypto_Idle may be called multiple times with no call to OEMCrypto_Wake
+ * in between. A call to OEMCrypto_Idle with different values of
+ * OEMCrypto_IdleState or os_specific_code may happen in any order. It is
+ * OEMCrypto’s responsibility to choose the appropriate behavior for improving
+ * power consumption. In particular, OEMCrypto may be notified of the
+ * OEMCrypto_NoCryptoActivity state before or after a notification of the
+ * OEMCrypto_CpuSuspend state, or OEMCrypto_NoCryptoActivity may not be notified
+ * at all. On some platforms, a call with OEMCrypto_CpuSuspend may never
+ * happen.
+ *
+ * The acceptable values of `os_specific_code` must be coordinated between the
+ * OS and the OEMCrypto vendor. On some platforms, for example Android, only
+ * the value of 0 will be used. For other platforms, it is the responsibility
+ * of the OEM device maker to coordinate with the SOC to define acceptable
+ * values of `os_specific_code`.
+ *
+ * @param[in] state: The idle state. This indicates if the call came from
+ * the OS or the CDM.
+ * @param[in] os_specific_code: Specified by the platform or OS for extra
+ * sleep information.
+ *
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ *
+ * @threading
+ * This is an "Initialization and Termination Function" and will not be
+ * called simultaneously with any other function, as if the CDM holds a write
+ * lock on the OEMCrypto system. No other functions will be called before the
+ * system is re-initialized.
+ *
+ * @version
+ * This method is supported by all API versions.
+ */
+OEMCryptoResult OEMCrypto_Idle(OEMCrypto_IdleState state,
+ uint32_t os_specific_code);
+
+/**
+ * The new function OEMCrypto_Wake will be called to indicate that crypto
+ * operations will resume. A call to OEMCrypto_Wake after the system is already
+ * awake shall have no effect. If OEMCrypto cannot recover from being idle, it
+ * may return OEMCrypto_ERROR_SESSION_LOST_STATE or
+ * OEMCrypto_ERROR_SYSTEM_INVALIDATED.
+ *
+ * The CDM layer may postpone a call to OEMCrypto_Wake until Widevine activity
+ * is starting. This may happen long after the CPU wakes up.
+ *
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_SESSION_LOST_STATE
+ * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ *
+ * @threading
+ * This is an "Initialization and Termination Function" and will not be
+ * called simultaneously with any other function, as if the CDM holds a write
+ * lock on the OEMCrypto system. No other functions will be called before the
+ * system is re-initialized.
+ *
+ * @version
+ * This method is supported by all API versions.
+ */
+OEMCryptoResult OEMCrypto_Wake(void);
+
/// @}
/// @addtogroup keyladder
@@ -782,6 +915,39 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session);
*/
OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session);
+/**
+ * This method creates an entitled key session.
+ *
+ * @param[in] oec_session: handle for the OEMCrypto session to be associated
+ * with the created entitled key session.
+ * @param[out] key_session: id of the created entitled key session.
+ *
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_INVALID_SESSION
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_CreateEntitledKeySession(
+ OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session);
+
+/**
+ * This method which removes an entitled key session.
+ *
+ * @param[in] key_session: id of the entitled key session to be removed.
+ *
+ * Returns:
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_RemoveEntitledKeySession(
+ OEMCrypto_SESSION key_session);
+
/**
* Generates three secondary keys, mac_key[server], mac_key[client], and
* encrypt_key, for handling signing and content key decryption under the
@@ -995,11 +1161,6 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
* it must be 0x1 (RSASSA-PSS with SHA1). If not, then an error of
* OEMCrypto_ERROR_SIGNATURE_FAILURE shall be returned.
*
- * OEMCrypto shall compute a hash of the core license request. The core
- * license request is the buffer starting at message and with length
- * core_message_size. The hash will be saved with the session and verified
- * that it matches a hash in the license response.
- *
* OEMCrypto shall also call the function ODK_InitializeClockValues,
* described in the document "License Duration and Renewal", to initialize
* the session's clock values.
@@ -1135,105 +1296,6 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
size_t* core_message_size, uint8_t* signature, size_t* signature_length);
-/**
- * OEMCrypto will use OEMCrypto_PrepAndSignProvisioningRequest(), as described
- * in the document "Widevine Core Message Serialization", to prepare the core
- * message. If it returns an error, the error should be returned by OEMCrypto
- * to the CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall
- * compute the signature of the entire message. The entire message is the
- * buffer starting at message with length message_length.
- *
- * For a device that has a keybox, i.e. Provisioning 2.0, OEMCrypto will sign
- * the request with the session's derived client mac key from the previous
- * call to OEMCrypto_GenerateDerivedKeys().
- *
- * For a device that has an OEM Certificate, i.e. Provisioning 3.0, OEMCrypto
- * will sign the request with the private key associated with the OEM
- * Certificate. The key shall have been loaded by a previous call to
- * OEMCrypto_LoadDRMPrivateKey().
- *
- * Refer to the Signing Messages Sent to a Server section above for more
- * details.
- *
- * NOTE: if signature pointer is null and/or input signature_length is zero,
- * this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output
- * signature_length to the size needed to receive the output signature.
- *
- * @param[in] session: handle for the session to be used.
- * @param[in,out] message: Pointer to memory for the entire message. Modified by
- * OEMCrypto via the ODK library.
- * @param[in] message_length: length of the entire message buffer.
- * @param[in,out] core_message_size: length of the core message at the beginning
- * of the message. (in) size of buffer reserved for the core message, in
- * bytes. (out) actual length of the core message, in bytes.
- * @param[out] signature: pointer to memory to receive the computed signature.
- * @param[in,out] signature_length: (in) length of the signature buffer, in
- * bytes. (out) actual length of the signature, in bytes.
- *
- * @retval OEMCrypto_SUCCESS success
- * @retval OEMCrypto_ERROR_INVALID_SESSION
- * @retval OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough
- * to hold the signature.
- * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
- * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
- * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE
- * @retval OEMCrypto_ERROR_SESSION_LOST_STATE
- * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
- *
- * @buffer_size
- * OEMCrypto shall support message sizes as described in the section
- * OEMCrypto_ResourceRatingTier().
- * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
- * larger than the supported size.
- *
- * @threading
- * This is a "Session Function" and may be called simultaneously with session
- * functions for other sessions but not simultaneously with other functions
- * for this session. It will not be called simultaneously with initialization
- * or usage table functions. It is as if the CDM holds a write lock for this
- * session, and a read lock on the OEMCrypto system.
- *
- * @version
- * This method changed in API version 16.
- */
-OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest(
- OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
- size_t* core_message_size, uint8_t* signature, size_t* signature_length);
-
-/**
- * Verify and install a new SRM file. The device shall install the new file only
- * if verification passes. If verification fails, the existing SRM will be left
- * in place. Verification is defined by DCP, and includes verification of the
- * SRM's signature and verification that the SRM version number will not be
- * decreased. See the section [HDCP SRM Update](../../index#hdcp_srm_update) for
- * more details about the SRM. This function is for devices that support HDCP
- * v2.2 or higher and wish to receive 4k content.
- *
- * @param[in] buffer: buffer containing the SRM
- * @param[in] buffer_length: length of the SRM, in bytes.
- *
- * @retval OEMCrypto_SUCCESS if the file was valid and was installed.
- * @retval OEMCrypto_ERROR_INVALID_CONTEXT if the SRM version is too low, or
- * the file is corrupted.
- * @retval OEMCrypto_ERROR_SIGNATURE_FAILURE If the signature is invalid.
- * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is too large for the
- * device.
- * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
- * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
- *
- * @buffer_size
- * The size of the buffer is determined by the HDCP specification.
- *
- * @threading
- * This is an "Initialization and Termination Function" and will not be
- * called simultaneously with any other function, as if the CDM holds a write
- * lock on the OEMCrypto system.
- *
- * @version
- * This method changed in API version 13.
- */
-OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length);
-
/**
* Install a set of keys for performing decryption in the current session.
* This function will be deprecated and will only be used for legacy license
@@ -1508,9 +1570,10 @@ OEMCryptoResult OEMCrypto_LoadKeys(
* returned by ODK_ParseLicense.
*
* The keys will be decrypted using the current encrypt_key (AES-128-CBC) and
- * the IV given in the KeyObject. Each key control block will be decrypted
- * using the first 128 bits of the corresponding content key (AES-128-CBC)
- * and the IV given in the KeyObject.
+ * the IV given in the KeyObject. If the API version of the license is less
+ * than 17, each key control block will be decrypted using the first 128 bits
+ * of the corresponding content key (AES-128-CBC) and the IV given in the
+ * KeyObject. In v17 licenses, the key control block is not decrypted.
*
* If its length is not zero, enc_mac_keys will be used to create new
* mac_keys. After all keys have been decrypted and validated, the new
@@ -1762,7 +1825,7 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session,
* store the encrypted content key data in the key table, and decrypt it when
* the function SelectKey is called.
*
- * @param[in] session: handle for the session to be used.
+ * @param[in] session: handle for the entitled key session to be used.
* @param[in] message: pointer to memory containing message to be verified.
* @param[in] message_length: length of the message, in bytes.
* @param[in] key_array_length: number of keys present.
@@ -1776,6 +1839,7 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session,
* @retval OEMCrypto_KEY_NOT_ENTITLED
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
@@ -1785,7 +1849,7 @@ OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session,
* session, and a read lock on the OEMCrypto system.
*
* @version
- * This method is new in API version 14.
+ * This method changed in API version 17.
*/
OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
@@ -1793,6 +1857,10 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
const OEMCrypto_EntitledContentKeyObject* key_array);
/**
+ * NOTE: OEMCrypto_RefreshKeys() is only used to load a v15 license or renewal.
+ * Because there are no longer any active v15 servers, this function is only
+ * needed for devices that are upgraded to v17, not new devices.
+ *
* Updates the license clock values to allow playback to continue. This
* function is being deprecated and is only used for version v15 licenses --
* i.e. offline license saved before an update or licenses from a server that
@@ -1989,7 +2057,7 @@ OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session,
* 5. If the specified key has not been loaded, return
* OEMCrypto_ERROR_NO_CONTENT_KEY.
*
- * @param[in] session: handle for the session to be used.
+ * @param[in] session: handle for the crypto or entitled key session to be used.
* @param[in] content_key_id: The unique id of the key of interest.
* @param[in] content_key_id_length: The length of key_id, in bytes. From 1 to
* 16, inclusive.
@@ -2003,6 +2071,7 @@ OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session,
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
@@ -2012,7 +2081,7 @@ OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session,
* session, and a read lock on the OEMCrypto system.
*
* @version
- * This method is new in API version 10.
+ * This method is changed in API version 17.
*/
OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
const uint8_t* content_key_id,
@@ -2070,7 +2139,7 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
* the device cannot enforce at least that version of HDCP, then the key
* is not selected, and OEMCrypto_ERROR_INSUFFICIENT_HDCP is returned.
*
- * @param[in] session: crypto session identifier.
+ * @param[in] session: handle for the crypto or entitled key session to be used.
* @param[in] content_key_id: pointer to the content Key ID.
* @param[in] content_key_id_length: length of the content Key ID, in bytes.
* From 1 to 16, inclusive.
@@ -2091,6 +2160,7 @@ OEMCryptoResult OEMCrypto_QueryKeyControl(OEMCrypto_SESSION session,
* @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
@@ -2435,8 +2505,8 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* In either case, a call to OEMCrypto_GetHDCPCapability() shall return the
* current HDCP level.
*
- * @param[in] session: Crypto session identifier. The crypto session in which
- * decrypt is to be performed.
+ * @param[in] session: Crypto or entitled session identifier. The crypto session
+ * in which decrypt is to be performed.
* @param[in] samples: A caller-owned array of OEMCrypto_SampleDescription
* structures. Each entry in this array contains one sample of the content.
* @param[in] samples_length: The length of the array pointed to by the samples
@@ -2454,10 +2524,15 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* @retval OEMCrypto_ERROR_ANALOG_OUTPUT
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
- * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE
+ * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if the input buffer is too large,
+ * and should be partitioned.
+ * @retval OEMCrypto_ERROR_SHORT_BUFFER if the destination buffer is shorter
+ * than the source
* @retval OEMCrypto_ERROR_OUTPUT_TOO_LARGE
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
+ * @retval OEMCrypto_ERROR_UNSUPPORTED_CIPHER
*
* @buffer_size
* OEMCrypto shall support subsample sizes and total input buffer sizes as
@@ -2482,7 +2557,7 @@ OEMCryptoResult OEMCrypto_SelectKey(OEMCrypto_SESSION session,
* session, and a read lock on the OEMCrypto system.
*
* @version
- * This method changed in API version 16. This method changed its name in API
+ * This method changed in API version 17. This method changed its name in API
* version 11.
*/
OEMCryptoResult OEMCrypto_DecryptCENC(
@@ -2536,7 +2611,10 @@ OEMCryptoResult OEMCrypto_DecryptCENC(
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
- * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE
+ * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE if the input buffer is too large,
+ * and should be partitioned.
+ * @retval OEMCrypto_ERROR_SHORT_BUFFER if the destination buffer is shorter
+ * than the source
* @retval OEMCrypto_ERROR_OUTPUT_TOO_LARGE
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
@@ -2597,7 +2675,7 @@ OEMCryptoResult OEMCrypto_CopyBuffer(
* status of that entry is either kInactiveUsed or kInactiveUnused, then
* return the error OEMCrypto_ERROR_LICENSE_INACTIVE.
*
- * @param[in] session: crypto session identifier.
+ * @param[in] session: crypto or entitled key session identifier.
* @param[in] in_buffer: pointer to memory containing data to be encrypted.
* @param[in] in_buffer_length: length of the buffer, in bytes. The algorithm
* may restrict in_buffer_length to be a multiple of block size.
@@ -2617,9 +2695,10 @@ OEMCryptoResult OEMCrypto_CopyBuffer(
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
*
* @buffer_size
- * OEMCrypto shall support buffers sizes of at least 100 KiB for generic
+ * OEMCrypto shall support buffers sizes of at least 100 KiB for generic
* crypto operations.
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
* larger than the supported size.
@@ -2632,7 +2711,7 @@ OEMCryptoResult OEMCrypto_CopyBuffer(
* session, and a read lock on the OEMCrypto system.
*
* @version
- * This method changed in API version 16.
+ * This method changed in API version 17.
*/
OEMCryptoResult OEMCrypto_Generic_Encrypt(
OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer,
@@ -2666,7 +2745,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt(
* status of that entry is either kInactiveUsed or kInactiveUnused, then
* return the error OEMCrypto_ERROR_LICENSE_INACTIVE.
*
- * @param[in] session: crypto session identifier.
+ * @param[in] session: crypto or entitled key session identifier.
* @param[in] in_buffer: pointer to memory containing data to be encrypted.
* @param[in] in_buffer_length: length of the buffer, in bytes. The algorithm
* may restrict in_buffer_length to be a multiple of block size.
@@ -2687,6 +2766,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt(
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
*
* @buffer_size
* OEMCrypto shall support buffers sizes of at least 100 KiB for generic
@@ -2702,7 +2782,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt(
* session, and a read lock on the OEMCrypto system.
*
* @version
- * This method changed in API version 16.
+ * This method changed in API version 17.
*/
OEMCryptoResult OEMCrypto_Generic_Decrypt(
OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* in_buffer,
@@ -2731,7 +2811,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt(
* status of that entry is either kInactiveUsed or kInactiveUnused, then
* return the error OEMCrypto_ERROR_LICENSE_INACTIVE.
*
- * @param[in] session: crypto session identifier.
+ * @param[in] session: crypto or entitled key session identifier.
* @param[in] buffer: pointer to memory containing data to be encrypted.
* @param[in] buffer_length: length of the buffer, in bytes.
* @param[in] algorithm: Specifies which algorithm to use.
@@ -2753,6 +2833,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt(
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
*
* @buffer_size
* OEMCrypto shall support buffers sizes of at least 100 KiB for generic
@@ -2768,7 +2849,7 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt(
* session, and a read lock on the OEMCrypto system.
*
* @version
- * This method changed in API version 16.
+ * This method changed in API version 17.
*/
OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,
const OEMCrypto_SharedMemory* buffer,
@@ -2806,7 +2887,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,
* status of that entry is either kInactiveUsed or kInactiveUnused, then
* return the error OEMCrypto_ERROR_LICENSE_INACTIVE.
*
- * @param[in] session: crypto session identifier.
+ * @param[in] session: crypto or entitled key session identifier.
* @param[in] buffer: pointer to memory containing data to be encrypted.
* @param[in] buffer_length: length of the buffer, in bytes.
* @param[in] algorithm: Specifies which algorithm to use.
@@ -2824,6 +2905,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
*
* @buffer_size
* OEMCrypto shall support buffers sizes of at least 100 KiB for generic
@@ -2839,7 +2921,7 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,
* session, and a read lock on the OEMCrypto system.
*
* @version
- * This method changed in API version 16.
+ * This method changed in API version 17.
*/
OEMCryptoResult OEMCrypto_Generic_Verify(
OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* buffer,
@@ -3172,6 +3254,14 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(uint8_t* public_cert,
/// @addtogroup validation
/// @{
+/** Specifies OEMCrypto security level.
+ */
+typedef enum OEMCrypto_Security_Level {
+ OEMCrypto_Level_Unknown = 0,
+ OEMCrypto_Level1 = 1,
+ OEMCrypto_Level2 = 2,
+ OEMCrypto_Level3 = 3,
+} OEMCrypto_Security_Level;
/**
* Returns a buffer filled with hardware-generated random bytes, if supported
@@ -3258,9 +3348,13 @@ uint32_t OEMCrypto_APIVersion(void);
uint32_t OEMCrypto_MinorAPIVersion(void);
/**
- * Report the build information of the OEMCrypto library as a short null
- * terminated C string. The string should be at most 128 characters long.
- * This string should be updated with each release or OEMCrypto build.
+ * Stores the build information of the OEMCrypto library in a buffer. This
+ * string should be updated with each release or OEMCrypto build. If
+ * buffer_length is not enough, the function will return
+ * OEMCrypto_ERROR_SHORT_BUFFER. Before returning OEMCrypto_ERROR_SHORT_BUFFER,
+ * the function should set buffer_length to the length of buffer needed. If the
+ * write is successful, buffer_length will be set to the number of bytes
+ * written.
*
* Some SOC vendors deliver a binary OEMCrypto library to a device
* manufacturer. This means the OEMCrypto version may not be exactly in sync
@@ -3275,9 +3369,11 @@ uint32_t OEMCrypto_MinorAPIVersion(void);
* number in this string, e.g. "15.1" or "15.2" if those minor versions are
* released.
*
- * @return
- * A printable null terminated C string, suitable for a single line in a
- * log.
+ * @param[out] buffer: pointer to the buffer that receives build information
+ * @param[in,out] buffer_length: length of the data buffer in bytes
+ *
+ * @retval OEMCrypto_SUCCESS
+ * @retval OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small.
*
* @threading
* This is a "Property Function" and may be called simultaneously with any
@@ -3288,7 +3384,7 @@ uint32_t OEMCrypto_MinorAPIVersion(void);
* @version
* This method changed in each API version.
*/
-const char* OEMCrypto_BuildInformation(void);
+OEMCryptoResult OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length);
/**
* This function returns the current patch level of the software running in
@@ -3318,8 +3414,8 @@ uint8_t OEMCrypto_Security_Patch_Level(void);
* Since this function is spoofable, it is not relied on for security
* purposes. It is for information only.
*
- * @return
- * A null terminated string. Useful value are "L1", "L2" and "L3".
+ * @return A security level enum. Values are OEMCrypto_Level_Unknown,
+ * OEMCrypto_Level1, OEMCrypto_Level2 and OEMCrypto_Level3.
*
* @threading
* This is a "Property Function" and may be called simultaneously with any
@@ -3328,9 +3424,9 @@ uint8_t OEMCrypto_Security_Patch_Level(void);
* system.
*
* @version
- * This method changed in API version 6.
+ * This method changed in API version 17.
*/
-const char* OEMCrypto_SecurityLevel(void);
+OEMCrypto_Security_Level OEMCrypto_SecurityLevel(void);
/**
* Returns the maximum HDCP version supported by the device, and the HDCP
@@ -3403,6 +3499,27 @@ const char* OEMCrypto_SecurityLevel(void);
OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability* current,
OEMCrypto_HDCP_Capability* maximum);
+/**
+ * Returns the DTCP2 support for a device.
+ *
+ * @param[out] capability: this will be set to 0 if DTCP2 is not supported,
+ * and 1 if the device supports at least v1 of DTCO2.
+ *
+ * @retval OEMCrypto_SUCCESS
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ *
+ * @threading
+ * This is a "Property Function" and may be called simultaneously with any
+ * other property function or session function, but not any initialization or
+ * usage table function, as if the CDM holds a read lock on the OEMCrypto
+ * system.
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_GetDTCP2Capability(
+ OEMCrypto_DTCP2_Capability* capability);
+
/**
* This is used to determine if the device can support a usage table. Since
* this function is spoofable, it is not relied on for security purposes. It
@@ -3553,26 +3670,6 @@ OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* max);
*/
uint32_t OEMCrypto_SupportedCertificates(void);
-/**
- * Returns true if the device supports SRM files and the file can be updated
- * via the function OEMCrypto_LoadSRM(). This also returns false for devices
- * that do not support an SRM file, devices that do not support HDCP, and
- * devices that have no external display support.
- *
- * @retval true if LoadSRM is supported.
- * @retval false otherwise.
- *
- * @threading
- * This is a "Property Function" and may be called simultaneously with any
- * other property function or session function, but not any initialization or
- * usage table function, as if the CDM holds a read lock on the OEMCrypto
- * system.
- *
- * @version
- * This method changed in API version 13.
- */
-bool OEMCrypto_IsSRMUpdateSupported(void);
-
/**
* Returns the version number of the current SRM file. If the device does not
* support SRM files, this will return OEMCrypto_ERROR_NOT_IMPLEMENTED. If
@@ -3688,6 +3785,77 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(void);
*/
uint32_t OEMCrypto_ResourceRatingTier(void);
+/**
+ * Returns OEMCrypto_SUCCESS if the device is production ready. This is a
+ * new reporting mechanism that reports that OEMCrypto is production ready.
+ * For example, the SOC delivers OEMCrypto to the OEM which functions
+ * correctly whether debugging or antirollback is turned on or not. The OEM
+ * has the option to turn on TEE software antirollback if they wish. If anti
+ * rollback is off, or if debugging is enabled, then this function will
+ * return failure.
+ *
+ * The OEMCrypto implementer may choose any other error code if the device
+ * is not production ready. The motivation for this new feature is to allow
+ * SOCs to signal to OEMs that hardening has not been done on a system.
+ * During development of a device, it is fine for this function to return an
+ * error. During development, we expect devices to have debugging turned on.
+ * However, once the device is ready for production, all hardening should be
+ * turned on.
+ *
+ * The intention is that certification tests, such as Android’s GTS test suite,
+ * will verify that a device is production ready. Being production ready will
+ * not be a requirement to pass OEMCrypto unit tests, but the status will be
+ * logged as part of the tests.
+ *
+ * @retval OEMCrypto_SUCCESS
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ *
+ * @threading
+ * This is a "Property Function" and may be called simultaneously with any
+ * other property function or session function, but not any initialization or
+ * usage table function, as if the CDM holds a read lock on the OEMCrypto
+ * system.
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_ProductionReady(void);
+
+/**
+ * Returns OEMCrypto_WatermarkingAlwaysOn or OEMCrypto_WatermarkingConfigurable
+ * if the device supports watermarking. If the device does not support
+ * watermarking but the license has watermarking set to accept it,
+ * OEMCrypto_LoadLicense should return the error
+ * OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE, which is a new error code in v17.
+ *
+ * If watermarking can be turned on or off for individual streams, then
+ * OEMCrypto should honor the settings for each license individually.
+ *
+ * If watermarking can only be turned on or off on a system wide level, then
+ * the most recent license should be honored. The watermarking feature should
+ * be turned on or off when a license is loaded. If this conflicts with a
+ * license that had been loaded earlier, then keys from the earlier license may
+ * not be used. In this case, either OEMCrypto_SelectKey or
+ * OEMCrypto_DecryptCENC will return OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE to
+ * indicate that the watermarking status has changed and the license is no
+ * longer usable.
+ *
+ * @retval OEMCrypto_WatermarkingError
+ * @retval OEMCrypto_WatermarkingNotSupported
+ * @retval OEMCrypto_WatermarkingConfigurable
+ * @retval OEMCrypto_WatermarkingAlwaysOn
+ *
+ * @threading
+ * This is a "Property Function" and may be called simultaneously with any
+ * other property function or session function, but not any initialization or
+ * usage table function, as if the CDM holds a read lock on the OEMCrypto
+ * system.
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport(void);
+
/// @}
/// @addtogroup drm_cert
@@ -3987,6 +4155,71 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(
uint8_t* signature, size_t* signature_length,
RSA_Padding_Scheme padding_scheme);
+/**
+ * OEMCrypto will use OEMCrypto_PrepAndSignProvisioningRequest(), as described
+ * in the document "Widevine Core Message Serialization", to prepare the core
+ * message. If it returns an error, the error should be returned by OEMCrypto
+ * to the CDM layer. If it returns OEMCrypto_SUCCESS, then OEMCrypto shall
+ * compute the signature of the entire message. The entire message is the
+ * buffer starting at message with length message_length.
+ *
+ * For a device that has a keybox, i.e. Provisioning 2.0, OEMCrypto will sign
+ * the request with the session's derived client mac key from the previous
+ * call to OEMCrypto_GenerateDerivedKeys().
+ *
+ * For a device that has an OEM Certificate, i.e. Provisioning 3.0, OEMCrypto
+ * will sign the request with the private key associated with the OEM
+ * Certificate. The key shall have been loaded by a previous call to
+ * OEMCrypto_LoadDRMPrivateKey().
+ *
+ * Refer to the Signing Messages Sent to a Server section above for more
+ * details.
+ *
+ * NOTE: if signature pointer is null and/or input signature_length is zero,
+ * this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output
+ * signature_length to the size needed to receive the output signature.
+ *
+ * @param[in] session: handle for the session to be used.
+ * @param[in,out] message: Pointer to memory for the entire message. Modified by
+ * OEMCrypto via the ODK library.
+ * @param[in] message_length: length of the entire message buffer.
+ * @param[in,out] core_message_size: length of the core message at the beginning
+ * of the message. (in) size of buffer reserved for the core message, in
+ * bytes. (out) actual length of the core message, in bytes.
+ * @param[out] signature: pointer to memory to receive the computed signature.
+ * @param[in,out] signature_length: (in) length of the signature buffer, in
+ * bytes. (out) actual length of the signature, in bytes.
+ *
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_INVALID_SESSION
+ * @retval OEMCrypto_ERROR_SHORT_BUFFER if signature buffer is not large enough
+ * to hold the signature.
+ * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE
+ * @retval OEMCrypto_ERROR_SESSION_LOST_STATE
+ * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ *
+ * @buffer_size
+ * OEMCrypto shall support message sizes as described in the section
+ * OEMCrypto_ResourceRatingTier().
+ * OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
+ * larger than the supported size.
+ *
+ * @threading
+ * This is a "Session Function" and may be called simultaneously with session
+ * functions for other sessions but not simultaneously with other functions
+ * for this session. It will not be called simultaneously with initialization
+ * or usage table functions. It is as if the CDM holds a write lock for this
+ * session, and a read lock on the OEMCrypto system.
+ *
+ * @version
+ * This method changed in API version 16.
+ */
+OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest(
+ OEMCrypto_SESSION session, uint8_t* message, size_t message_length,
+ size_t* core_message_size, uint8_t* signature, size_t* signature_length);
+
/// @}
/// @addtogroup usage_table
@@ -4112,6 +4345,44 @@ OEMCryptoResult OEMCrypto_LoadUsageTableHeader(const uint8_t* buffer,
OEMCryptoResult OEMCrypto_CreateNewUsageEntry(OEMCrypto_SESSION session,
uint32_t* usage_entry_number);
+/**
+ * This allows a session to take an existing usage entry. The effect of this
+ * call is identical to that of creating an entry via
+ * OEMCrypto_CreateUsageEntry(), except that the usage table header does not
+ * change size. All information related to the previous entry should be cleared
+ * from the header. The new entry will be initialized with a generation number
+ * equal to the master generation number, which will also be stored in the
+ * header’s existing slot. Then the master generation number will be
+ * incremented.
+ *
+ * If the session already has a usage entry associated with it, the error
+ * OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES is returned.
+ *
+ * @param[in] session: handle for the session to be used.
+ * @param[in] usage_entry_number: index of new usage entry.
+ *
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED some devices do not implement usage
+ * tables.
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ * @retval OEMCrypto_ERROR_SESSION_LOST_STATE
+ * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ * @retval OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES if there already is a usage
+ * entry loaded into this session
+ * @retval OEMCrypto_ERROR_INVALID_SESSION when entry number is in use by
+ * another session
+ *
+ * @threading
+ * This is a "Usage Table Function" and will not be called simultaneously
+ * with any other function, as if the CDM holds a write lock on the OEMCrypto
+ * system.
+ *
+ * @version
+ * This method changed in API version 17.
+ */
+OEMCryptoResult OEMCrypto_ReuseUsageEntry(OEMCrypto_SESSION session,
+ uint32_t usage_entry_number);
+
/**
* This loads a usage entry saved previously by UpdateUsageEntry. The
* signature at the beginning of the buffer is verified and the buffer will
@@ -4483,28 +4754,101 @@ OEMCryptoResult OEMCrypto_ShrinkUsageTableHeader(uint32_t new_entry_count,
/// @}
-/// @addtogroup test_verify
+/// @addtogroup prov40
/// @{
/**
- * Delete the current SRM. Any valid SRM, regardless of its version number,
- * will be installable after this via OEMCrypto_LoadSRM().
+ * Get the serialized boot certificate chain in CBOR format used in
+ * provisioning 4.
*
- * This function should not be implemented on production devices, and will
- * only be used to verify unit tests on a test device.
+ * @param[out] bcc: pointer to the buffer that receives the serialized boot
+ * certificate chain in CBOR format.
+ * @param[in,out] bcc_size - on input, size of the caller's bcc buffer. On
+ * output, the number of bytes written into the buffer.
+ * @param[out] additional_signature: pointer to the buffer that receives
+ * additional device key signature (certificate chain). This field is only
+ * used by the signing model where a vendor certificate is available on the
+ * device.
+ * @param[in,out] additional_signature_size - on input, size of the caller's
+ * additional_signature buffer. On output, the number of bytes written into
+ * the buffer.
*
- * @retval OEMCrypto_SUCCESS if the SRM file was deleted.
- * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED always on production devices.
+ * @retval OEMCrypto_SUCCESS
+ * @retval OEMCrypto_ERROR_SHORT_BUFFER if any of the buffers is too small to
+ * return the bcc or additional_signature.
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED if provisioning 4 is not supported.
*
* @threading
- * This is an "Initialization and Termination Function" and will not be
- * called simultaneously with any other function, as if the CDM holds a write
- * lock on the OEMCrypto system.
+ * This is a "Property Function" and may be called simultaneously with any
+ * other property function or session function, but not any initialization or
+ * usage table function, as if the CDM holds a read lock on the OEMCrypto
+ * system.
*
* @version
- * This method is new in API version 13.
+ * This method is new in API version 17.
*/
-OEMCryptoResult OEMCrypto_RemoveSRM(void);
+OEMCryptoResult OEMCrypto_GetBootCertificateChain(
+ uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature,
+ size_t* additional_signature_size);
+
+/**
+ * Generates a key pair used in OEM and DRM certificate provisioning. The public
+ * key is supposed to be certified by the server. The private key is wrapped
+ * with the encryption key so it can be stored in the file system.
+ *
+ * If an OEM private key is unavailable, the request is assumed for OEM
+ * certificate provisioning. In this case, the public key is signed by the
+ * device private key. If an OEM private key is available, the request is
+ * assumed for DRM certificate provisioning and the public key is signed by the
+ * OEM private key.
+ *
+ * @param[in] session: session id.
+ * @param[out] public_key: pointer to the buffer that receives the public key
+ * that is to be certified by the server. The key must be an ASN.1
+ * DER-encoded SubjectPublicKeyInfo as specified in RFC 5280.
+ * @param[in,out] public_key_size: on input, size of the caller's public_key
+ * buffer. On output, the number of bytes written into the buffer.
+ * @param[out] public_key_signature: pointer to the buffer that receives the
+ * signature of the public key. If an OEM private key is unavailable, it is
+ * signed by the device private key; otherwise is signed by the OEM private
+ * key.
+ * @param[in,out] public_key_signature_size: on input, size of the caller's
+ * public_key_signature buffer. On output, the number of bytes written into
+ * the buffer.
+ * @param[out] wrapped_private_key: pointer to the buffer that receives the
+ * encrypted private key. It is encrypted by the device encryption key.
+ * @param[in,out] wrapped_private_key_size: on input, size of the caller's
+ * wrapped_private_key buffer. On output, the number of bytes written into
+ * the buffer.
+ * @param[out] key_type: the type of the generated key pair (RSA or ECC).
+ *
+ * @retval OEMCrypto_SUCCESS
+ * @retval OEMCrypto_ERROR_INVALID_SESSION
+ * @retval OEMCrypto_ERROR_SHORT_BUFFER if any of the buffer |public_key|,
+ * |public_key_signature| or |wrapped_private_key_size| is too small.
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ *
+ * @threading
+ * This is a "Session Function" and may be called simultaneously with session
+ * functions for other sessions but not simultaneously with other functions
+ * for this session. It will not be called simultaneously with initialization
+ * or usage table functions. It is as if the CDM holds a write lock for this
+ * session, and a read lock on the OEMCrypto system.
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair(
+ OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_size,
+ uint8_t* public_key_signature, size_t* public_key_signature_size,
+ uint8_t* wrapped_private_key, size_t* wrapped_private_key_size,
+ OEMCrypto_PrivateKeyType* key_type);
+
+/// @}
+
+/// @addtogroup test_verify
+/// @{
/**
* Returns the type of hash function supported for Full Decrypt Path Testing.
@@ -4711,8 +5055,138 @@ OEMCryptoResult OEMCrypto_FreeSecureBuffer(
OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor,
int secure_fd);
+/**
+ * Loads an OEM private key to a session. The key will be used in signing DRM
+ * certificate request, or the public key generated by calling
+ * OEMCrypto_GenerateCertificateKeyPair.
+ *
+ * @param[in] session: session id.
+ * @param[in] key_type: type of the leaf key (RSA or ECC).
+ * @param[in] wrapped_private_key: the encrypted private key. This is the
+ * wrapped key generated by OEMCrypto_GenerateCertificateKeyPair.
+ * @param[in] wrapped_private_key_length: length of |wrapped_private_key| in
+ * bytes.
+ *
+ * @retval OEMCrypto_SUCCESS
+ * @retval OEMCrypto_ERROR_INVALID_CONTEXT
+ * @retval OEMCrypto_ERROR_NO_DEVICE_KEY
+ * @retval OEMCrypto_ERROR_INVALID_SESSION
+ * @retval OEMCrypto_ERROR_INVALID_RSA_KEY
+ * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ * @retval OEMCrypto_ERROR_SESSION_LOST_STATE
+ * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ *
+ * @threading
+ * This is a "Session Function" and may be called simultaneously with session
+ * functions for other sessions but not simultaneously with other functions
+ * for this session. It will not be called simultaneously with initialization
+ * or usage table functions. It is as if the CDM holds a write lock for this
+ * session, and a read lock on the OEMCrypto system.
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_InstallOemPrivateKey(
+ OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type,
+ const uint8_t* wrapped_private_key, size_t wrapped_private_key_length);
+
/// @}
+/**
+ * This method associates an existing entitled key session to the specified
+ * OEMCrypto session.
+ *
+ * @param[in] key_session: id of the entitled key session.
+ * @param[in] oec_session: handle for the OEMCrypto session to be associated
+ * with the entitled key session.
+ *
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
+ * @retval OEMCrypto_ERROR_INVALID_SESSION
+ *
+ * @threading
+ * This is a "Session Function" and may be called simultaneously with session
+ * functions for other sessions but not simultaneously with other functions
+ * for this session. It will not be called simultaneously with initialization
+ * or usage table functions. It is as if the CDM holds a write lock for this
+ * session, and a read lock on the OEMCrypto system.
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession(
+ OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session);
+
+/**
+ * The OEMCrypto_LoadCasECMKeys method is added to load content keys into an
+ * entitled key session, which already has entitlement keys loaded. Used only by
+ * CAS.
+ *
+ * This function will only be called for a session after a call to
+ * OEMCrypto_LoadKeys with the license_type equal to
+ * OEMCrypto_EntitlementLicense, and a call to
+ * OEMCrypto_CreateEntitledKeySession initializing the entitled key session.
+ * This function may be called multiple times for the same session.
+ *
+ * For each key object, odd and even, OEMCrypto shall look up the entry in the
+ * key table with the corresponding entitlement_key_id. Before the
+ * entitlement_key is used:
+ * 1) If no entry is found, return OEMCrypto_KEY_NOT_ENTITLED.
+ * 2) Check the entitlement key’s key control block use. If failed, return
+ * corresponding error code such as OEMCrypto_ERROR_ANALOG_OUTPUT,
+ * OEMCrypto_ERROR_INSUFFICIENT_HDCP.
+ * 3) If the entitlement key’s control block has a nonzero Duration field,
+ * then the API shall verify that the duration is greater than the
+ * session’s elapsed time clock before the key is used. OEMCrypto will
+ * return OEMCrypto_ERROR_KEY_EXPIRED.
+ * 4) The content_key_data decrypted using the entitlement_key_data as a key
+ * for AES-256-CBC with an IV of content_key_data_iv. Wrapped content is
+ * padded using PKCS#7 padding. Notice that the entitlement key will be an
+ * AES 256 bit key. The clear content key data will be stored in the
+ * entry’s content_key_data.
+ * 5) The decrypted content key data may be set in a hardware KeySlot,
+ * together with content iv and cipher mode information, which can be used
+ * by the Descrambler in TunerHal. The entitled key session ID may be used
+ * as the key token to uniquely identify the content key in KeySlot.
+ *
+ * @param[in] session: handle for the entitled key session to be used.
+ * @param[in] message: pointer to memory containing message to be verified.
+ * @param[in] message_length: length of the message, in bytes.
+ * @param[in] even_key: key update for the even ecm key. May be null if the key
+ * does not change.
+ * @param[in] odd_key: key update for the odd ecm key. May be null if the key
+ * does not change.
+ *
+ * @retval OEMCrypto_SUCCESS success
+ * @retval OEMCrypto_ERROR_INVALID_SESSION
+ * @retval OEMCrypto_ERROR_INVALID_CONTEXT
+ * @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
+ * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
+ * @retval OEMCrypto_KEY_NOT_ENTITLED
+ * @retval OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION
+ * @retval OEMCrypto_ERROR_KEY_EXPIRED
+ * @retval OEMCrypto_ERROR_ANALOG_OUTPUT
+ * @retval OEMCrypto_ERROR_INSUFFICIENT_HDCP
+ *
+ * @threading
+ * This is a "Session Function" and may be called simultaneously with session
+ * functions for other sessions but not simultaneously with other functions
+ * for this session. It will not be called simultaneously with initialization
+ * or usage table functions. It is as if the CDM holds a write lock for this
+ * session, and a read lock on the OEMCrypto system.
+ *
+ * @version
+ * This method is new in API version 17.
+ */
+OEMCryptoResult OEMCrypto_LoadCasECMKeys(
+ OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
+ const OEMCrypto_EntitledContentKeyObject* even_key,
+ const OEMCrypto_EntitledContentKeyObject* odd_key);
+
/*
* OEMCrypto_OPK_SerializationVersion
* Check the serialization protocol version used by the OEMCrypto Porting Kit
@@ -4981,6 +5455,64 @@ OEMCryptoResult OEMCrypto_GetOEMPublicCertificate_V15(
OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
const uint8_t* wrapped_rsa_key,
size_t wrapped_rsa_key_length);
+
+/*
+ * OEMCrypto_BuildInformation_V16
+ * @deprecated
+ * Not required for the current version of OEMCrypto. Declared here to
+ * help with backward compatibility.
+ */
+const char* OEMCrypto_BuildInformation_V16(void);
+
+/*
+ * OEMCrypto_SecurityLevel_V16
+ * @deprecated
+ * Not required for the current version of OEMCrypto. Declared here to
+ * help with backward compatibility.
+ */
+const char* OEMCrypto_SecurityLevel_V16(void);
+
+typedef struct {
+ OEMCrypto_Substring entitlement_key_id;
+ OEMCrypto_Substring content_key_id;
+ OEMCrypto_Substring content_key_data_iv;
+ OEMCrypto_Substring content_key_data;
+} OEMCrypto_EntitledContentKeyObject_V16;
+
+/*
+ * OEMCrypto_LoadEntitledContentKeys_V16
+ * @deprecated
+ * Not required for the current version of OEMCrypto. Declared here to
+ * help with backward compatibility.
+ */
+OEMCryptoResult OEMCrypto_LoadEntitledContentKeys_V16(
+ OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
+ size_t key_array_length,
+ const OEMCrypto_EntitledContentKeyObject_V16* key_array);
+
+/**
+ * OEmCrypto_IsSRIMUpdateSupported
+ * @deprecated
+ * Not required for the current version of OEMCrypto. Declared here to
+ * help with backward compatibility.
+ */
+bool OEMCrypto_IsSRMUpdateSupported(void);
+
+/**
+ * OEMCrypto_LoadSRM
+ * @deprecated
+ * Not required for the current version of OEMCrypto. Declared here to
+ * help with backward compatibility.
+ */
+OEMCryptoResult OEMCrypto_LoadSRM(const uint8_t* buffer, size_t buffer_length);
+
+/**
+ * OEMCrypto_RemoveSRM
+ * @deprecated
+ * Not required for the current version of OEMCrypto. Declared here to
+ * help with backward compatibility.
+ */
+OEMCryptoResult OEMCrypto_RemoveSRM(void);
/****************************************************************************/
/****************************************************************************/
diff --git a/oemcrypto/include/level3.h b/oemcrypto/include/level3.h
index c4e7c43..014b8cc 100644
--- a/oemcrypto/include/level3.h
+++ b/oemcrypto/include/level3.h
@@ -39,7 +39,6 @@ namespace wvoec3 {
#define Level3_LoadDeviceRSAKey _lcc19
#define Level3_DeriveKeysFromSessionKey _lcc21
#define Level3_APIVersion _lcc22
-#define Level3_SecurityLevel _lcc23
#define Level3_Generic_Encrypt _lcc24
#define Level3_Generic_Decrypt _lcc25
#define Level3_Generic_Sign _lcc26
@@ -76,9 +75,8 @@ namespace wvoec3 {
#define Level3_SupportsDecryptHash _lcc86
#define Level3_SetDecryptHash _lcc88
#define Level3_GetHashErrorCode _lcc89
-#define Level3_BuildInformation _lcc90
#define Level3_RefreshKeys _lcc91
-#define Level3_LoadEntitledContentKeys _lcc92
+#define Level3_LoadEntitledContentKeys_V16 _lcc92
#define Level3_CopyBuffer _lcc93
#define Level3_MaximumUsageTableHeaderSize _lcc94
#define Level3_GenerateDerivedKeys _lcc95
@@ -93,8 +91,24 @@ namespace wvoec3 {
#define Level3_DecryptCENC _lcc105
#define Level3_LoadDRMPrivateKey _lcc107
#define Level3_MinorAPIVersion _lcc108
-#define Level3_AllocateSecureBuffer _lcc111
-#define Level3_FreeSecureBuffer _lcc112
+#define Level3_AllocateSecureBuffer _lcc109
+#define Level3_FreeSecureBuffer _lcc110
+#define Level3_CreateEntitledKeySession _lcc111
+#define Level3_RemoveEntitledKeySession _lcc112
+#define Level3_GetBootCertificateChain _lcc116
+#define Level3_GenerateCertificateKeyPair _lcc117
+#define Level3_InstallOemPrivateKey _lcc118
+#define Level3_ReassociateEntitledKeySession _lcc119
+#define Level3_LoadCasECMKeys _lcc120
+#define Level3_LoadEntitledContentKeys _lcc121 // place holder for v17.
+#define Level3_ProductionReady _lcc122
+#define Level3_Idle _lcc123
+#define Level3_Wake _lcc124
+#define Level3_BuildInformation _lcc125
+#define Level3_SecurityLevel _lcc126
+#define Level3_ReuseUsageEntry _lcc127
+#define Level3_GetDTCP2Capability _lcc128
+#define Level3_GetWatermarkingSupport _lcc129
#else
#define Level3_Initialize _oecc01
#define Level3_Terminate _oecc02
@@ -112,7 +126,6 @@ namespace wvoec3 {
#define Level3_LoadDeviceRSAKey _oecc19
#define Level3_DeriveKeysFromSessionKey _oecc21
#define Level3_APIVersion _oecc22
-#define Level3_SecurityLevel _oecc23
#define Level3_Generic_Encrypt _oecc24
#define Level3_Generic_Decrypt _oecc25
#define Level3_Generic_Sign _oecc26
@@ -151,9 +164,8 @@ namespace wvoec3 {
#define Level3_SupportsDecryptHash _oecc86
#define Level3_SetDecryptHash _oecc88
#define Level3_GetHashErrorCode _oecc89
-#define Level3_BuildInformation _oecc90
#define Level3_RefreshKeys _oecc91
-#define Level3_LoadEntitledContentKeys _oecc92
+#define Level3_LoadEntitledContentKeys_V16 _oecc92
#define Level3_CopyBuffer _oecc93
#define Level3_MaximumUsageTableHeaderSize _oecc94
#define Level3_GenerateDerivedKeys _oecc95
@@ -168,12 +180,24 @@ namespace wvoec3 {
#define Level3_DecryptCENC _oecc105
#define Level3_LoadDRMPrivateKey _oecc107
#define Level3_MinorAPIVersion _oecc108
-// TODO(b/171121061): Renaming for oemcrypto_test to find the L3 implementation
-// of the two functions below. This is to be fixed when
-// OEMCrypto_AllocateSecureBuffer and OEMCrypto_FreeSecureBuffer are added to
-// OEMCryptoCENC.h
-#define Level3_AllocateSecureBuffer OEMCrypto_AllocateSecureBuffer
-#define Level3_FreeSecureBuffer OEMCrypto_FreeSecureBuffer
+#define Level3_AllocateSecureBuffer _oecc109
+#define Level3_FreeSecureBuffer _oecc110
+#define Level3_CreateEntitledKeySession _oecc111
+#define Level3_RemoveEntitledKeySession _oecc112
+#define Level3_GetBootCertificateChain _oecc116
+#define Level3_GenerateCertificateKeyPair _oecc117
+#define Level3_InstallOemPrivateKey _oecc118
+#define Level3_ReassociateEntitledKeySession _oecc119
+#define Level3_LoadCasECMKeys _oecc120
+#define Level3_LoadEntitledContentKeys _oecc121 // place holder for v17.
+#define Level3_ProductionReady _oecc122
+#define Level3_Idle _oecc123
+#define Level3_Wake _oecc124
+#define Level3_BuildInformation _oecc125
+#define Level3_SecurityLevel _oecc126
+#define Level3_ReuseUsageEntry _oecc127
+#define Level3_GetDTCP2Capability _oecc128
+#define Level3_GetWatermarkingSupport _oecc129
#endif
#define Level3_GetInitializationState _oecl3o01
@@ -248,7 +272,7 @@ OEMCryptoResult Level3_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
uint32_t Level3_APIVersion();
uint32_t Level3_MinorAPIVersion();
uint8_t Level3_SecurityPatchLevel();
-const char* Level3_SecurityLevel();
+OEMCrypto_Security_Level Level3_SecurityLevel();
OEMCryptoResult Level3_GetHDCPCapability(OEMCrypto_HDCP_Capability* current,
OEMCrypto_HDCP_Capability* maximum);
bool Level3_SupportsUsageTable();
@@ -334,7 +358,7 @@ OEMCryptoResult Level3_SetDecryptHash(OEMCrypto_SESSION session,
const uint8_t* hash, size_t hash_length);
OEMCryptoResult Level3_GetHashErrorCode(OEMCrypto_SESSION session,
uint32_t* failed_frame_number);
-const char* Level3_BuildInformation();
+OEMCryptoResult Level3_BuildInformation(char* buffer, size_t* buffer_length);
OEMCryptoResult Level3_LoadRenewal(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
@@ -370,6 +394,37 @@ OEMCryptoResult Level3_AllocateSecureBuffer(
OEMCryptoResult Level3_FreeSecureBuffer(
OEMCrypto_SESSION session, OEMCrypto_DestBufferDesc* output_descriptor,
int secure_fd);
+OEMCryptoResult Level3_CreateEntitledKeySession(OEMCrypto_SESSION oec_session,
+ OEMCrypto_SESSION* key_session);
+OEMCryptoResult Level3_RemoveEntitledKeySession(OEMCrypto_SESSION key_session);
+OEMCryptoResult Level3_GetBootCertificateChain(
+ uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature,
+ size_t* additional_signature_size);
+OEMCryptoResult Level3_GenerateCertificateKeyPair(
+ OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_size,
+ uint8_t* public_key_signature, size_t* public_key_signature_size,
+ uint8_t* wrapped_private_key, size_t* wrapped_private_key_size,
+ OEMCrypto_PrivateKeyType* key_type);
+OEMCryptoResult Level3_InstallOemPrivateKey(OEMCrypto_SESSION session,
+ OEMCrypto_PrivateKeyType key_type,
+ const uint8_t* wrapped_private_key,
+ size_t wrapped_private_key_length);
+OEMCryptoResult Level3_ReassociateEntitledKeySession(
+ OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session);
+OEMCryptoResult Level3_LoadCasECMKeys(
+ OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
+ const OEMCrypto_EntitledContentKeyObject* even_key,
+ const OEMCrypto_EntitledContentKeyObject* odd_key);
+OEMCryptoResult Level3_ProductionReady();
+OEMCryptoResult Level3_Idle(OEMCrypto_IdleState state,
+ uint32_t os_specific_code);
+OEMCryptoResult Level3_Wake();
+OEMCryptoResult Level3_ReuseUsageEntry(OEMCrypto_SESSION session,
+ uint32_t usage_entry_number);
+OEMCryptoResult Level3_GetDTCP2Capability(
+ OEMCrypto_DTCP2_Capability* capability);
+OEMCrypto_WatermarkingSupport Level3_GetWatermarkingSupport();
+
// The following are specific to Google's Level 3 implementation and are not
// required.
diff --git a/oemcrypto/include/oemcrypto_types.h b/oemcrypto/include/oemcrypto_types.h
index 4a5728c..02edc98 100644
--- a/oemcrypto/include/oemcrypto_types.h
+++ b/oemcrypto/include/oemcrypto_types.h
@@ -23,6 +23,14 @@ typedef struct WidevineKeybox { // 128 bytes total.
uint8_t crc_[4];
} WidevineKeybox;
+// This is the format for a key control block.
+typedef struct {
+ uint8_t verification[4];
+ uint32_t duration;
+ uint32_t nonce;
+ uint32_t control_bits;
+} KeyControlBlock;
+
/*
* SRM_Restriction_Data
*
@@ -39,6 +47,12 @@ const uint32_t kControlObserveDataPath = (1u << 31);
const uint32_t kControlObserveHDCP = (1u << 30);
const uint32_t kControlObserveCGMS = (1u << 29);
const uint32_t kControlRequireAntiRollbackHardware = (1u << 28);
+// The two bits kControlWhiteboxSecurityLevelMask are not used in
+// OEMCrypto; they are only used for whitebox testing.
+const uint32_t kControlWhiteboxSecurityLevelShift = 26;
+const uint32_t kControlWhiteboxSecurityLevelMask =
+ (0x03u << kControlWhiteboxSecurityLevelShift);
+const uint32_t kControlAllowDVRRecording = (1u << 25);
const uint32_t kControlAllowHashVerification = (1u << 24);
const uint32_t kSharedLicense = (1u << 23);
const uint32_t kControlSRMVersionRequired = (1u << 22);
diff --git a/oemcrypto/include/pst_report.h b/oemcrypto/include/pst_report.h
index 251ac52..33a1288 100644
--- a/oemcrypto/include/pst_report.h
+++ b/oemcrypto/include/pst_report.h
@@ -18,7 +18,7 @@
#include "OEMCryptoCENC.h"
#include "string_conversions.h" // needed for htonll64.
-namespace wvcdm {
+namespace wvutil {
class Unpacked_PST_Report {
public:
@@ -84,12 +84,12 @@ class Unpacked_PST_Report {
int64_t time;
memcpy(&time, buffer_ + kseconds_since_license_received_offset,
sizeof(int64_t));
- return ntohll64(time);
+ return wvutil::ntohll64(time);
}
// Parameter time is in host byte order.
void set_seconds_since_license_received(int64_t time) const {
- time = ntohll64(time);
+ time = wvutil::ntohll64(time);
memcpy(buffer_ + kseconds_since_license_received_offset, &time,
sizeof(int64_t));
}
@@ -143,6 +143,6 @@ class Unpacked_PST_Report {
static const size_t kseconds_since_last_decrypt_offset = 40;
static const size_t kpst_offset = 48;
};
-} // namespace wvcdm
+} // namespace wvutil
#endif // PST_REPORT_H_
diff --git a/oemcrypto/odk/Android.bp b/oemcrypto/odk/Android.bp
index 66cf0f0..3b7d807 100644
--- a/oemcrypto/odk/Android.bp
+++ b/oemcrypto/odk/Android.bp
@@ -5,6 +5,18 @@
// ----------------------------------------------------------------
// Builds libwv_odk.a, The ODK Library (libwv_odk) is used by
// the CDM and by oemcrypto implementations.
+// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
+// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+// DEPENDING ON IT IN YOUR PROJECT. ***
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "vendor_widevine_license"
+ // to get the below license kinds:
+ // legacy_by_exception_only (by exception only)
+ default_applicable_licenses: ["vendor_widevine_license"],
+}
+
cc_library_static {
name: "libwv_odk",
include_dirs: [
@@ -15,6 +27,7 @@ cc_library_static {
srcs: [
"src/odk.c",
+ "src/odk_message.c",
"src/odk_overflow.c",
"src/odk_serialize.c",
"src/odk_timer.c",
@@ -39,6 +52,7 @@ cc_library_static {
srcs: [
"src/core_message_deserialize.cpp",
+ "src/core_message_features.cpp",
"src/core_message_serialize.cpp",
"src/core_message_serialize_proto.cpp",
],
diff --git a/oemcrypto/odk/README b/oemcrypto/odk/README
index ba8c8c7..408fc44 100644
--- a/oemcrypto/odk/README
+++ b/oemcrypto/odk/README
@@ -1,8 +1,6 @@
This ODK Library is used to generate and parse core OEMCrypto messages for
-OEMCrypto v16 and above.
-
-This library is used by both OEMCrypto on a device, and by Widevine license and
-provisioning servers.
+OEMCrypto v16 and above. This library is used by both OEMCrypto on a device
+and by Widevine license and provisioning servers.
The source of truth for these files is in the server code base on piper. Do not
edit these files in the Android directory tree or in the Widevine Git
diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h
index 7a2a529..cb343ab 100644
--- a/oemcrypto/odk/include/OEMCryptoCENCCommon.h
+++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h
@@ -61,7 +61,7 @@ typedef enum OEMCryptoResult {
OEMCrypto_ERROR_INVALID_NONCE = 32,
OEMCrypto_ERROR_TOO_MANY_KEYS = 33,
OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED = 34,
- OEMCrypto_ERROR_INVALID_RSA_KEY = 35,
+ OEMCrypto_ERROR_INVALID_RSA_KEY = 35, /* deprecated */
OEMCrypto_ERROR_KEY_EXPIRED = 36,
OEMCrypto_ERROR_INSUFFICIENT_RESOURCES = 37,
OEMCrypto_ERROR_INSUFFICIENT_HDCP = 38,
@@ -87,6 +87,12 @@ typedef enum OEMCryptoResult {
OEMCrypto_ERROR_LICENSE_RELOAD = 57,
OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES = 58,
OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION = 59,
+ OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION = 60,
+ OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING = 61,
+ OEMCrypto_ERROR_UNSUPPORTED_CIPHER = 62,
+ OEMCrypto_ERROR_DVR_FORBIDDEN = 63,
+ OEMCrypto_ERROR_INSUFFICIENT_PRIVILEGE = 64,
+ OEMCrypto_ERROR_INVALID_KEY = 65,
/* ODK return values */
ODK_ERROR_BASE = 1000,
ODK_ERROR_CORE_MESSAGE = ODK_ERROR_BASE,
@@ -95,6 +101,11 @@ typedef enum OEMCryptoResult {
ODK_TIMER_EXPIRED = ODK_ERROR_BASE + 3,
ODK_UNSUPPORTED_API = ODK_ERROR_BASE + 4,
ODK_STALE_RENEWAL = ODK_ERROR_BASE + 5,
+ /* OPK return values */
+ OPK_ERROR_BASE = 2000,
+ OPK_ERROR_REMOTE_CALL = OPK_ERROR_BASE,
+ OPK_ERROR_INCOMPATIBLE_VERSION = OPK_ERROR_BASE + 1,
+ OPK_ERROR_NO_PERSISTENT_DATA = OPK_ERROR_BASE + 2,
} OEMCryptoResult;
/* clang-format on */
@@ -135,6 +146,62 @@ typedef struct {
size_t length;
} OEMCrypto_Substring;
+/**
+ * Used to specify information about CMI Descriptor 0.
+ * @param id: ID value of CMI Descriptor assigned by DTLA.
+ * @param length: byte length of the usage rules field.
+ * @param data: usage rules data.
+ */
+typedef struct {
+ uint8_t id; // 0x00
+ uint8_t extension; // 0x00
+ uint16_t length; // 0x01
+ uint8_t data;
+} OEMCrypto_DTCP2_CMI_Descriptor_0;
+
+/**
+ * Used to specify information about CMI Descriptor 1.
+ * @param id: ID value of CMI Descriptor assigned by DTLA.
+ * @param extension: specified by the CMI descriptor
+ * @param length: byte length of the usage rules field.
+ * @param data: usage rules data.
+ */
+typedef struct {
+ uint8_t id; // 0x01
+ uint8_t extension; // 0x00
+ uint16_t length; // 0x03
+ uint8_t data[3];
+} OEMCrypto_DTCP2_CMI_Descriptor_1;
+
+/**
+ * Used to specify information about CMI Descriptor 2.
+ * @param id: ID value of CMI Descriptor assigned by DTLA.
+ * @param extension: specified by the CMI descriptor
+ * @param length: byte length of the usage rules field.
+ * @param data: usage rules data.
+ */
+typedef struct {
+ uint8_t id; // 0x02
+ uint8_t extension; // 0x00
+ uint16_t length; // 0x03
+ uint8_t data[3];
+} OEMCrypto_DTCP2_CMI_Descriptor_2;
+
+/**
+ * Used to specify the required DTCP2 level. If dtcp2_required is 0, there are
+ * no requirements on any of the keys. If dtcp2_required is 1, any key with the
+ * kControlHDCPRequired bit set requires DTCP2 in its output.
+ * @param dtcp2_required: specifies whether dtcp2 is required. 0 = not required,
+ * 1 = DTCP2 required.
+ * @param cmi_descriptor_1: three bytes of CMI descriptor 1
+ */
+typedef struct {
+ uint8_t dtcp2_required; // 0 = not required. 1 = DTCP2 v1 required.
+ OEMCrypto_DTCP2_CMI_Descriptor_0 cmi_descriptor_0;
+ OEMCrypto_DTCP2_CMI_Descriptor_1 cmi_descriptor_1;
+ OEMCrypto_DTCP2_CMI_Descriptor_2 cmi_descriptor_2;
+} OEMCrypto_DTCP2_CMI_Packet;
+
/**
* Points to the relevant fields for a content key. The fields are extracted
* from the License Response message offered to OEMCrypto_LoadKeys(). Each
diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h
new file mode 100644
index 0000000..d66b95e
--- /dev/null
+++ b/oemcrypto/odk/include/core_message_features.h
@@ -0,0 +1,44 @@
+// Copyright 2021 Google LLC. All rights reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine
+// License Agreement.
+
+#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_
+#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_
+
+#include
+
+#include
+#include
+
+namespace oemcrypto_core_message {
+namespace features {
+
+// Features that may be supported by core messages. By restricting values in
+// this structure, we can turn off features at runtime. This is plain data, and
+// is essentially a version number.
+struct CoreMessageFeatures {
+ // A default set of features.
+ static const CoreMessageFeatures kDefaultFeatures;
+
+ // Create the default feature set for the given major version number.
+ static CoreMessageFeatures DefaultFeatures(uint32_t maximum_major_version);
+
+ // This is the published version of the ODK Core Message library. The default
+ // behavior is for the server to restrict messages to at most this version
+ // number. The default is 16.5, the last version used by Chrome. This will
+ // change to 17.0 when v17 has been released.
+ uint32_t maximum_major_version = 16;
+ uint32_t maximum_minor_version = 5;
+
+ bool operator==(const CoreMessageFeatures &other) const;
+ bool operator!=(const CoreMessageFeatures &other) const {
+ return !(*this == other);
+ }
+};
+
+std::ostream &operator<<(std::ostream &os, const CoreMessageFeatures &features);
+
+} // namespace features
+} // namespace oemcrypto_core_message
+
+#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_
diff --git a/oemcrypto/odk/include/core_message_serialize.h b/oemcrypto/odk/include/core_message_serialize.h
index 781259a..0e1c287 100644
--- a/oemcrypto/odk/include/core_message_serialize.h
+++ b/oemcrypto/odk/include/core_message_serialize.h
@@ -17,23 +17,27 @@
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_
+#include "core_message_features.h"
#include "core_message_types.h"
#include "odk_structs.h"
namespace oemcrypto_core_message {
namespace serialize {
+using oemcrypto_core_message::features::CoreMessageFeatures;
/**
* Counterpart (serializer) of ODK_ParseLicense (deserializer)
* struct-input variant
*
* Parameters:
+ * [in] features feature support for response message.
* [in] parsed_lic
* [in] core_request
* [in] core_request_sha256
* [out] oemcrypto_core_message
*/
-bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
+bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
+ const ODK_ParsedLicense& parsed_lic,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
std::string* oemcrypto_core_message);
@@ -42,11 +46,13 @@ bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
* Counterpart (serializer) of ODK_ParseRenewal (deserializer)
*
* Parameters:
+ * [in] features feature support for response message.
* [in] core_request
* [in] renewal_duration_seconds
* [out] oemcrypto_core_message
*/
-bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
+bool CreateCoreRenewalResponse(const CoreMessageFeatures& features,
+ const ODK_RenewalRequest& core_request,
uint64_t renewal_duration_seconds,
std::string* oemcrypto_core_message);
@@ -55,11 +61,13 @@ bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
* struct-input variant
*
* Parameters:
+ * [in] features feature support for response message.
* [in] parsed_prov
* [in] core_request
* [out] oemcrypto_core_message
*/
-bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
+bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
+ const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message);
} // namespace serialize
diff --git a/oemcrypto/odk/include/core_message_serialize_proto.h b/oemcrypto/odk/include/core_message_serialize_proto.h
index ce5df09..de75362 100644
--- a/oemcrypto/odk/include/core_message_serialize_proto.h
+++ b/oemcrypto/odk/include/core_message_serialize_proto.h
@@ -17,41 +17,46 @@
#include
#include
+#include "core_message_features.h"
#include "core_message_types.h"
#include "license_protocol.pb.h"
namespace oemcrypto_core_message {
namespace serialize {
-
// @ public create response (serializer) functions accepting proto input
/**
* Counterpart (serializer) of ODK_ParseLicense (deserializer)
*
* Parameters:
+ * [in] features feature support for response message.
* [in] serialized_license
serialized video_widevine::License
* [in] core_request oemcrypto core message from request.
* [in] core_request_sha256 - hash of serialized core request.
* [in] nonce_required - if the device should require a nonce match.
+ * [in] uses_padding - if the keys use padding.
* [out] oemcrypto_core_message - the serialized oemcrypto core response.
*/
-bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
- const ODK_LicenseRequest& core_request,
- const std::string& core_request_sha256,
- const bool nonce_required,
- std::string* oemcrypto_core_message);
+bool CreateCoreLicenseResponseFromProto(
+ const oemcrypto_core_message::features::CoreMessageFeatures& features,
+ const std::string& serialized_license,
+ const ODK_LicenseRequest& core_request,
+ const std::string& core_request_sha256, const bool nonce_required,
+ const bool uses_padding, std::string* oemcrypto_core_message);
/**
* Counterpart (serializer) of ODK_ParseProvisioning (deserializer)
*
* Parameters:
+ * [in] features feature support for response message.
* [in] serialized_provisioning_response
* serialized video_widevine::ProvisioningResponse
* [in] core_request
* [out] oemcrypto_core_message
*/
bool CreateCoreProvisioningResponseFromProto(
+ const oemcrypto_core_message::features::CoreMessageFeatures& features,
const std::string& serialized_provisioning_response,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message);
diff --git a/oemcrypto/odk/include/odk.h b/oemcrypto/odk/include/odk.h
index 4f0c9f6..b412a7d 100644
--- a/oemcrypto/odk/include/odk.h
+++ b/oemcrypto/odk/include/odk.h
@@ -132,11 +132,11 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
* This function sets the values in the clock_values structure. It shall be
* called from OEMCrypto_LoadUsageEntry. When a usage entry from a v15 or
* earlier license is loaded, the value time_of_license_loaded shall be used
- * in place of time_of_license_signed.
+ * in place of time_of_license_request_signed.
*
* @param[in,out] clock_values: the session's clock data.
- * @param[in] time_of_license_signed: the value time_license_received from the
- * loaded usage entry.
+ * @param[in] time_of_license_request_signed: the value time_license_received
+ * from the loaded usage entry.
* @param[in] time_of_first_decrypt: the value time_of_first_decrypt from the
* loaded usage entry.
* @param[in] time_of_last_decrypt: the value time_of_last_decrypt from the
@@ -152,7 +152,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
* This method is new in version 16 of the API.
*/
OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
- uint64_t time_of_license_signed,
+ uint64_t time_of_license_request_signed,
uint64_t time_of_first_decrypt,
uint64_t time_of_last_decrypt,
enum OEMCrypto_Usage_Entry_Status status,
@@ -469,8 +469,6 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
* and false when called for OEMCrypto_ReloadLicense.
* @param[in] usage_entry_present: true if the session has a new usage entry
* associated with it created via OEMCrypto_CreateNewUsageEntry.
- * @param[in] request_hash: the hash of the license request core message. This
- * was computed by OEMCrypto when the license request was signed.
* @param[in,out] timer_limits: The session's timer limits. These will be
* updated.
* @param[in,out] clock_values: The session's clock values. These will be
@@ -492,7 +490,6 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits,
OEMCryptoResult ODK_ParseLicense(
const uint8_t* message, size_t message_length, size_t core_message_length,
bool initial_license_load, bool usage_entry_present,
- const uint8_t request_hash[ODK_SHA256_HASH_SIZE],
ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license);
diff --git a/oemcrypto/odk/include/odk_attributes.h b/oemcrypto/odk/include/odk_attributes.h
index bbb81d8..72321b1 100644
--- a/oemcrypto/odk/include/odk_attributes.h
+++ b/oemcrypto/odk/include/odk_attributes.h
@@ -6,9 +6,9 @@
#define WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_
#if defined(__GNUC__) || defined(__clang__)
-# define UNUSED __attribute__((__unused__))
+#define UNUSED __attribute__((__unused__))
#else
-# define UNUSED
+#define UNUSED
#endif
#endif // WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_
diff --git a/oemcrypto/odk/include/odk_message.h b/oemcrypto/odk/include/odk_message.h
new file mode 100644
index 0000000..94ce2ae
--- /dev/null
+++ b/oemcrypto/odk/include/odk_message.h
@@ -0,0 +1,141 @@
+// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine
+// License Agreement.
+
+#ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_
+#define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+
+/*
+ * ODK_Message is the structure that defines the serialized messages passed
+ * between the REE and TEE. ODK_Message is an abstract data type that represents
+ * the concept of a message without disclosing the implementation details. By
+ * hiding the internal structure, modification of the message fields by code
+ * that is not privy to the message definition can be prevented. If the message
+ * definition was exposed, there could be serious yet subtle errors in message
+ * manipulation anywhere in the code base. By restricting message modification
+ * it is possible to enforce validity and integrity with a small set of
+ * primitives that can be carefully reviewed. Checks can be added to verify that
+ * a message's fields are internally consistent before every operation. As an
+ * example, it can be guaranteed that the message status will be checked prior
+ * to accessing any field so parsing will be stopped when the message status is
+ * set after any parse error is detected. This also makes development easier
+ * since any access to the message structure can be tracked through a single
+ * point so, for example, it becomes possible to add trace statements globally
+ * to all message operations by only changing the field accessors. Finally it
+ * simplifies maintenance by localizing changes to the message structure to a
+ * few files.
+ */
+
+#if defined(__GNUC__) || defined(__clang__)
+#define ALIGNED __attribute__((aligned))
+#else
+#define ALIGNED
+#error ODK_Message must be aligned to the maximum useful alignment of the \
+ machine you are compiling for. Define the ALIGNED macro accordingly.
+#endif
+
+typedef struct {
+#define SIZE_OF_ODK_MESSAGE_IMPL 64
+ uint8_t opaque_data[SIZE_OF_ODK_MESSAGE_IMPL];
+} ALIGNED ODK_Message;
+
+typedef enum {
+ MESSAGE_STATUS_OK = 0xe937fcf7,
+ MESSAGE_STATUS_UNKNOWN_ERROR = 0xe06c1190,
+ MESSAGE_STATUS_OVERFLOW_ERROR = 0xc43ae4bc,
+ MESSAGE_STATUS_UNDERFLOW_ERROR = 0x7123cd0b,
+ MESSAGE_STATUS_PARSE_ERROR = 0x0b9f6189,
+ MESSAGE_STATUS_NULL_POINTER_ERROR = 0x2d66837a,
+ MESSAGE_STATUS_API_VALUE_ERROR = 0x6ba34f47,
+ MESSAGE_STATUS_END_OF_MESSAGE_ERROR = 0x998db72a,
+ MESSAGE_STATUS_INVALID_ENUM_VALUE = 0xedb88197,
+ MESSAGE_STATUS_INVALID_TAG_ERROR = 0x14dce06a,
+ MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6,
+ MESSAGE_STATUS_OUT_OF_MEMORY = 0xfc5c64cc,
+ MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0xfafecacf,
+ MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873
+} ODK_MessageStatus;
+
+/*
+ * Create a message structure that references a separate data buffer. An
+ * initialized message is returned. The caller is responsible for ensuring that
+ * the buffer remains allocated for the lifetime of the message. If |buffer|
+ * is NULL or |capacity| is zero, the message is invalid and the status
+ * will be set to MESSAGE_STATUS_NOT_INITIALIZED.
+ */
+ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity);
+
+/*
+ * Erase the contents of the message, set it to an empty state by setting the
+ * message size and read offset to 0, effectively erasing the contents of the
+ * message. The message data buffer pointer remains unchanged, i.e. the message
+ * retains ownership of the buffer. The message status is reset to
+ * MESSAGE_STATUS_OK.
+ */
+void ODK_Message_Clear(ODK_Message* message);
+
+/*
+ * Reset read pointer to the beginning of the message and clear status
+ * so that parsing of the message will restart at the beginning of the
+ * message. The message status is reset to MESSAGE_STATUS_OK.
+ */
+void ODK_Message_Reset(ODK_Message* message);
+
+/*
+ * Return a pointer to the message data buffer, i.e. the message payload.
+ * This is the buffer address that was passed into ODK_Message_Create.
+ */
+uint8_t* ODK_Message_GetBase(ODK_Message* message);
+
+/*
+ * Get the maximum number of bytes the message can hold.
+ */
+size_t ODK_Message_GetCapacity(ODK_Message* message);
+
+/*
+ * Get the number of bytes currently in the message
+ */
+size_t ODK_Message_GetSize(ODK_Message* message);
+
+/*
+ * Get the offset of where the next bytes will be read from the message data
+ * buffer.
+ */
+size_t ODK_Message_GetOffset(ODK_Message* message);
+
+/*
+ * Return the status of the message
+ */
+ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message);
+
+/*
+ * Set the message status to a specific value
+ */
+void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status);
+
+/*
+ * Set the size of the message to a value. This may be needed after writing data
+ * into the message data buffer.
+ */
+void ODK_Message_SetSize(ODK_Message* message, size_t size);
+
+/*
+ * Test if the integrity of a message. This means that the status must be
+ * MESSAGE_STATUS_OK and that the internal fields of the message are
+ * within the range of valid values.
+ */
+bool ODK_Message_IsValid(ODK_Message* message);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_
diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h
index 34eb332..9c41fc7 100644
--- a/oemcrypto/odk/include/odk_structs.h
+++ b/oemcrypto/odk/include/odk_structs.h
@@ -5,17 +5,21 @@
#ifndef WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
#define WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#include
#include "OEMCryptoCENCCommon.h"
#include "odk_target.h"
/* The version of this library. */
-#define ODK_MAJOR_VERSION 16
-#define ODK_MINOR_VERSION 4
+#define ODK_MAJOR_VERSION 17
+#define ODK_MINOR_VERSION 0
/* ODK Version string. Date changed automatically on each release. */
-#define ODK_RELEASE_DATE "ODK v16.4 2020-10-07"
+#define ODK_RELEASE_DATE "ODK v17.0 2021-11-15"
/* The lowest version number for an ODK message. */
#define ODK_FIRST_VERSION 16
@@ -85,9 +89,9 @@ typedef struct {
* on OEMCrypto's system clock, as described in the document "License
* Duration and Renewal".
*
- * @param time_of_license_signed: Time that the license request was signed,
- * based on OEMCrypto's system clock. This value shall be stored and
- * reloaded with usage entry as time_of_license_received.
+ * @param time_of_license_request_signed: Time that the license request was
+ * signed, based on OEMCrypto's system clock. This value shall be stored
+ * and reloaded with usage entry as time_of_license_received.
* @param time_of_first_decrypt: Time of the first decrypt or call select key,
* based on OEMCrypto's system clock. This is 0 if the license has not
* been used to decrypt any data. This value shall be stored and reloaded
@@ -110,7 +114,7 @@ typedef struct {
* This struct changed in API version 16.2.
*/
typedef struct {
- uint64_t time_of_license_signed;
+ uint64_t time_of_license_request_signed;
uint64_t time_of_first_decrypt;
uint64_t time_of_last_decrypt;
uint64_t time_of_renewal_request;
@@ -171,11 +175,13 @@ typedef struct {
* entitlement keys.
* @param nonce_required: indicates if the license requires a nonce.
* @param timer_limits: time limits of the for the license.
+ * @param watermarking: specifies if device supports watermarking.
+ * @param dtcp2_required: specifies if device supports DTCP.
* @param key_array_length: number of keys present.
* @param key_array: set of keys to be installed.
*
* @version
- * This struct changed in API version 16.2.
+ * This struct changed in API version 17.
*/
typedef struct {
OEMCrypto_Substring enc_mac_keys_iv;
@@ -185,6 +191,8 @@ typedef struct {
OEMCrypto_LicenseType license_type;
bool nonce_required;
ODK_TimerLimits timer_limits;
+ uint32_t watermarking;
+ OEMCrypto_DTCP2_CMI_Packet dtcp2_required;
uint32_t key_array_length;
OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS];
} ODK_ParsedLicense;
@@ -212,4 +220,8 @@ typedef struct {
/// @}
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
#endif // WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
diff --git a/oemcrypto/odk/src/core_message_deserialize.cpp b/oemcrypto/odk/src/core_message_deserialize.cpp
index ebf0add..9f485d5 100644
--- a/oemcrypto/odk/src/core_message_deserialize.cpp
+++ b/oemcrypto/odk/src/core_message_deserialize.cpp
@@ -39,13 +39,11 @@ bool ParseRequest(uint32_t message_type,
reinterpret_cast(oemcrypto_core_message.c_str());
const size_t buf_length = oemcrypto_core_message.size();
- uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
- Message* msg = reinterpret_cast(blk);
- InitMessage(msg, const_cast(buf), buf_length);
- SetSize(msg, buf_length);
+ ODK_Message msg = ODK_Message_Create(const_cast(buf), buf_length);
+ ODK_Message_SetSize(&msg, buf_length);
- unpacker(msg, prepared);
- if (!ValidMessage(msg)) {
+ unpacker(&msg, prepared);
+ if (!ODK_Message_IsValid(&msg)) {
return false;
}
@@ -62,7 +60,7 @@ bool ParseRequest(uint32_t message_type,
} else if (core_request->api_major_version == 16) {
// For version 16, we demand a minor version of at least 2.
// We accept 16.2, 16.3, or higher.
- if (core_request->api_major_version < 2) return false;
+ if (core_request->api_minor_version < 2) return false;
} else {
// Other versions do not (yet) have a restriction on minor number.
// In particular, future versions are accepted for forward compatibility.
@@ -80,7 +78,7 @@ bool ParseRequest(uint32_t message_type,
// than the total message size. We allow the total message size to be larger
// for forward compatibility because future messages might have extra fields
// that we can ignore.
- if (core_message.message_length < GetOffset(msg)) return false;
+ if (core_message.message_length < ODK_Message_GetOffset(&msg)) return false;
return true;
}
diff --git a/oemcrypto/odk/src/core_message_features.cpp b/oemcrypto/odk/src/core_message_features.cpp
new file mode 100644
index 0000000..c28622c
--- /dev/null
+++ b/oemcrypto/odk/src/core_message_features.cpp
@@ -0,0 +1,41 @@
+// Copyright 2021 Google LLC. All rights reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine
+// License Agreement.
+
+#include "core_message_features.h"
+
+namespace oemcrypto_core_message {
+namespace features {
+const CoreMessageFeatures CoreMessageFeatures::kDefaultFeatures;
+
+bool CoreMessageFeatures::operator==(const CoreMessageFeatures &other) const {
+ return maximum_major_version == other.maximum_major_version &&
+ maximum_minor_version == other.maximum_minor_version;
+}
+
+CoreMessageFeatures CoreMessageFeatures::DefaultFeatures(
+ uint32_t maximum_major_version) {
+ CoreMessageFeatures features;
+ features.maximum_major_version = maximum_major_version;
+ // The default minor version is the highest for each major version.
+ switch (maximum_major_version) {
+ case 16:
+ features.maximum_minor_version = 5; // 16.5
+ break;
+ case 17:
+ features.maximum_minor_version = 0; // 17.0
+ break;
+ default:
+ features.maximum_minor_version = 0;
+ }
+ return features;
+}
+
+std::ostream &operator<<(std::ostream &os,
+ const CoreMessageFeatures &features) {
+ return os << "v" << features.maximum_major_version << "."
+ << features.maximum_minor_version;
+}
+
+} // namespace features
+} // namespace oemcrypto_core_message
diff --git a/oemcrypto/odk/src/core_message_serialize.cpp b/oemcrypto/odk/src/core_message_serialize.cpp
index 6003d71..334f442 100644
--- a/oemcrypto/odk/src/core_message_serialize.cpp
+++ b/oemcrypto/odk/src/core_message_serialize.cpp
@@ -20,18 +20,22 @@ namespace serialize {
namespace {
/**
- * Template for parsing requests
+ * Template for copying nonce values from request to response, and also
+ * computing the API version of the response.
*
* Template arguments:
* T: struct to be deserialized by odk
* S: kdo input struct
- * P: auto-generated serializing function for |T|
*/
-template
-bool CreateResponse(uint32_t message_type, const S& core_request,
- std::string* oemcrypto_core_message, T& response,
- const P& packer) {
- if (!oemcrypto_core_message) {
+template
+bool CreateResponseHeader(const CoreMessageFeatures& features,
+ ODK_MessageType message_type, const S& core_request,
+ T& response) {
+ // Bad major version.
+ if ((features.maximum_major_version > ODK_MAJOR_VERSION) ||
+ (features.maximum_major_version == ODK_MAJOR_VERSION &&
+ features.maximum_minor_version > ODK_MINOR_VERSION)) {
+ // TODO(b/147513335): this should be logged.
return false;
}
@@ -43,25 +47,50 @@ bool CreateResponse(uint32_t message_type, const S& core_request,
header->nonce_values.session_id = core_request.session_id;
// The message API version for the response is the minimum of our version and
// the request's version.
- if (core_request.api_major_version > ODK_MAJOR_VERSION) {
- header->nonce_values.api_major_version = ODK_MAJOR_VERSION;
- header->nonce_values.api_minor_version = ODK_MINOR_VERSION;
+ if (core_request.api_major_version > features.maximum_major_version) {
+ header->nonce_values.api_major_version = features.maximum_major_version;
+ header->nonce_values.api_minor_version = features.maximum_minor_version;
+ } else if (core_request.api_major_version == features.maximum_major_version &&
+ core_request.api_minor_version > features.maximum_minor_version) {
+ header->nonce_values.api_minor_version = features.maximum_minor_version;
+ }
+ return true;
+}
+
+/**
+ * Template for parsing requests and packing response
+ *
+ * Template arguments:
+ * T: struct to be deserialized by odk
+ * S: kdo input struct
+ * P: auto-generated serializing function for |T|
+ */
+template
+bool CreateResponse(ODK_MessageType message_type, const S& core_request,
+ std::string* oemcrypto_core_message, T& response,
+ const P& packer) {
+ if (!oemcrypto_core_message) {
+ return false;
+ }
+ auto* header = &response.request.core_message;
+ if (header->message_type != message_type ||
+ header->nonce_values.api_major_version < ODK_FIRST_VERSION) {
+ // This indicates CreateResponseHeader was not called.
+ return false;
}
static constexpr size_t BUF_CAPACITY = 2048;
std::vector buf(BUF_CAPACITY, 0);
- uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
- Message* msg = reinterpret_cast(blk);
- InitMessage(msg, buf.data(), buf.capacity());
- packer(msg, &response);
- if (!ValidMessage(msg)) {
+ ODK_Message msg = ODK_Message_Create(buf.data(), buf.capacity());
+ packer(&msg, &response);
+ if (!ODK_Message_IsValid(&msg)) {
return false;
}
- uint32_t message_length = GetSize(msg);
- InitMessage(msg, buf.data() + sizeof(header->message_type),
- sizeof(header->message_length));
- Pack_uint32_t(msg, &message_length);
+ uint32_t message_length = static_cast(ODK_Message_GetSize(&msg));
+ msg = ODK_Message_Create(buf.data() + sizeof(header->message_type),
+ sizeof(header->message_length));
+ Pack_uint32_t(&msg, &message_length);
oemcrypto_core_message->assign(reinterpret_cast(buf.data()),
message_length);
return true;
@@ -74,7 +103,7 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src,
if (request.device_id_length > sizeof(request.device_id)) {
return false;
}
- request.device_id_length = device_id.size();
+ request.device_id_length = static_cast(device_id.size());
memset(request.device_id, 0, sizeof(request.device_id));
memcpy(request.device_id, device_id.data(), request.device_id_length);
return true;
@@ -82,33 +111,73 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src,
} // namespace
-bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
+bool CreateCoreLicenseResponse(const CoreMessageFeatures& features,
+ const ODK_ParsedLicense& parsed_lic,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
std::string* oemcrypto_core_message) {
ODK_LicenseResponse license_response{
- {}, const_cast(&parsed_lic), {0}};
- if (core_request_sha256.size() != sizeof(license_response.request_hash))
+ {}, const_cast(&parsed_lic)};
+ if (!CreateResponseHeader(features, ODK_License_Response_Type, core_request,
+ license_response)) {
return false;
- memcpy(license_response.request_hash, core_request_sha256.data(),
- sizeof(license_response.request_hash));
+ }
+ if (license_response.request.core_message.nonce_values.api_major_version ==
+ 16) {
+ ODK_LicenseResponseV16 license_response_v16;
+ license_response_v16.request = license_response.request;
+ license_response_v16.parsed_license.enc_mac_keys_iv =
+ license_response.parsed_license->enc_mac_keys_iv;
+ license_response_v16.parsed_license.enc_mac_keys =
+ license_response.parsed_license->enc_mac_keys;
+ license_response_v16.parsed_license.pst =
+ license_response.parsed_license->pst;
+ license_response_v16.parsed_license.srm_restriction_data =
+ license_response.parsed_license->srm_restriction_data;
+ license_response_v16.parsed_license.license_type =
+ license_response.parsed_license->license_type;
+ license_response_v16.parsed_license.nonce_required =
+ license_response.parsed_license->nonce_required;
+ license_response_v16.parsed_license.timer_limits =
+ license_response.parsed_license->timer_limits;
+ license_response_v16.parsed_license.key_array_length =
+ license_response.parsed_license->key_array_length;
+ uint32_t i;
+ for (i = 0; i < license_response_v16.parsed_license.key_array_length; i++) {
+ license_response_v16.parsed_license.key_array[i] =
+ license_response.parsed_license->key_array[i];
+ }
+ if (core_request_sha256.size() != sizeof(license_response_v16.request_hash))
+ return false;
+ memcpy(license_response_v16.request_hash, core_request_sha256.data(),
+ sizeof(license_response_v16.request_hash));
+ return CreateResponse(ODK_License_Response_Type, core_request,
+ oemcrypto_core_message, license_response_v16,
+ Pack_ODK_LicenseResponseV16);
+ }
return CreateResponse(ODK_License_Response_Type, core_request,
oemcrypto_core_message, license_response,
Pack_ODK_LicenseResponse);
}
-bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
+bool CreateCoreRenewalResponse(const CoreMessageFeatures& features,
+ const ODK_RenewalRequest& core_request,
uint64_t renewal_duration_seconds,
std::string* oemcrypto_core_message) {
ODK_RenewalResponse renewal_response{{}, core_request.playback_time_seconds};
renewal_response.request.playback_time = core_request.playback_time_seconds;
renewal_response.renewal_duration_seconds = renewal_duration_seconds;
+ if (!CreateResponseHeader(features, ODK_Renewal_Response_Type, core_request,
+ renewal_response)) {
+ return false;
+ }
return CreateResponse(ODK_Renewal_Response_Type, core_request,
oemcrypto_core_message, renewal_response,
Pack_ODK_RenewalResponse);
}
-bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
+bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features,
+ const ODK_ParsedProvisioning& parsed_prov,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
ODK_ProvisioningResponse prov_response{
@@ -116,6 +185,10 @@ bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
if (!CopyDeviceId(core_request, &prov_response)) {
return false;
}
+ if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type,
+ core_request, prov_response)) {
+ return false;
+ }
return CreateResponse(ODK_Provisioning_Response_Type, core_request,
oemcrypto_core_message, prov_response,
Pack_ODK_ProvisioningResponse);
diff --git a/oemcrypto/odk/src/core_message_serialize_proto.cpp b/oemcrypto/odk/src/core_message_serialize_proto.cpp
index 224f817..860ea26 100644
--- a/oemcrypto/odk/src/core_message_serialize_proto.cpp
+++ b/oemcrypto/odk/src/core_message_serialize_proto.cpp
@@ -20,6 +20,7 @@
namespace oemcrypto_core_message {
namespace serialize {
namespace {
+using oemcrypto_core_message::features::CoreMessageFeatures;
/* @ private functions */
@@ -41,17 +42,23 @@ OEMCrypto_Substring GetOecSubstring(const std::string& message,
}
OEMCrypto_KeyObject KeyContainerToOecKey(
- const std::string& proto, const video_widevine::License::KeyContainer& k) {
+ const std::string& proto, const video_widevine::License::KeyContainer& k,
+ const bool uses_padding) {
OEMCrypto_KeyObject obj = {};
obj.key_id = GetOecSubstring(proto, k.id());
obj.key_data_iv = GetOecSubstring(proto, k.iv());
- // Strip off PKCS#5 padding - since we know the key is 16 or 32 bytes,
- // the padding will always be 16 bytes.
- const std::string& key_data = k.key();
- const size_t PKCS5_PADDING_SIZE = 16;
- obj.key_data = GetOecSubstring(
- proto, key_data.substr(0, std::max(PKCS5_PADDING_SIZE, key_data.size()) -
- PKCS5_PADDING_SIZE));
+
+ OEMCrypto_Substring key_data = GetOecSubstring(proto, k.key());
+
+ // Strip off PKCS#5 padding. A key can either be 16 of 32 bytes, but that
+ // makes it hard to know if a key (when 32 bytes) is a 16 byte key with
+ // padding or a 32 byte key without padding.
+ if (uses_padding) {
+ const size_t PKCS5_PADDING_SIZE = 16;
+ key_data.length -= PKCS5_PADDING_SIZE;
+ }
+ obj.key_data = key_data;
+
if (k.has_key_control()) {
const auto& key_control = k.key_control();
obj.key_control_iv = GetOecSubstring(proto, key_control.iv());
@@ -64,10 +71,12 @@ OEMCrypto_KeyObject KeyContainerToOecKey(
// @ public create response functions
-bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
+bool CreateCoreLicenseResponseFromProto(const CoreMessageFeatures& features,
+ const std::string& serialized_license,
const ODK_LicenseRequest& core_request,
const std::string& core_request_sha256,
const bool nonce_required,
+ const bool uses_padding,
std::string* oemcrypto_core_message) {
video_widevine::License lic;
if (!lic.ParseFromString(serialized_license)) {
@@ -102,7 +111,8 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
return false;
}
uint32_t& n = parsed_lic.key_array_length;
- parsed_lic.key_array[n++] = KeyContainerToOecKey(serialized_license, k);
+ parsed_lic.key_array[n++] =
+ KeyContainerToOecKey(serialized_license, k, uses_padding);
break;
}
default: {
@@ -125,12 +135,13 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
parsed_lic.pst =
GetOecSubstring(serialized_license, lid.provider_session_token());
}
-
if (lic.has_srm_requirement()) {
parsed_lic.srm_restriction_data =
GetOecSubstring(serialized_license, lic.srm_requirement());
}
-
+ if (lic.policy().has_watermarking_control()) {
+ parsed_lic.watermarking = lic.policy().watermarking_control();
+ }
parsed_lic.nonce_required = nonce_required;
const auto& policy = lic.policy();
ODK_TimerLimits& timer_limits = parsed_lic.timer_limits;
@@ -146,11 +157,12 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license,
policy.renewal_delay_seconds() +
policy.renewal_recovery_duration_seconds();
- return CreateCoreLicenseResponse(parsed_lic, core_request,
+ return CreateCoreLicenseResponse(features, parsed_lic, core_request,
core_request_sha256, oemcrypto_core_message);
}
bool CreateCoreProvisioningResponseFromProto(
+ const CoreMessageFeatures& features,
const std::string& serialized_provisioning_resp,
const ODK_ProvisioningRequest& core_request,
std::string* oemcrypto_core_message) {
@@ -175,7 +187,7 @@ bool CreateCoreProvisioningResponseFromProto(
GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key());
}
- return CreateCoreProvisioningResponse(parsed_prov, core_request,
+ return CreateCoreProvisioningResponse(features, parsed_prov, core_request,
oemcrypto_core_message);
}
diff --git a/oemcrypto/odk/src/kdo.gypi b/oemcrypto/odk/src/kdo.gypi
index 6e9fb46..6e77b45 100644
--- a/oemcrypto/odk/src/kdo.gypi
+++ b/oemcrypto/odk/src/kdo.gypi
@@ -7,6 +7,7 @@
{
'sources': [
'core_message_deserialize.cpp',
+ 'core_message_features.cpp',
'core_message_serialize.cpp',
'core_message_serialize_proto.cpp',
],
diff --git a/oemcrypto/odk/src/odk.c b/oemcrypto/odk/src/odk.c
index b404d48..6cb476e 100644
--- a/oemcrypto/odk/src/odk.c
+++ b/oemcrypto/odk/src/odk.c
@@ -27,9 +27,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
- uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
- Message* msg = (Message*)blk;
- InitMessage(msg, message, *core_message_length);
+ ODK_Message msg = ODK_Message_Create(message, *core_message_length);
/* The core message should be at the beginning of the buffer, and with a
* shorter length. */
@@ -52,7 +50,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedLicenseRequest(
- msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer);
+ &msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer);
break;
}
case ODK_Renewal_Request_Type: {
@@ -61,7 +59,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedRenewalRequest(
- msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer);
+ &msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer);
break;
}
case ODK_Provisioning_Request_Type: {
@@ -71,7 +69,7 @@ static OEMCryptoResult ODK_PrepareRequest(
return ODK_ERROR_CORE_MESSAGE;
}
Pack_ODK_PreparedProvisioningRequest(
- msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer);
+ &msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer);
break;
}
default: {
@@ -80,86 +78,78 @@ static OEMCryptoResult ODK_PrepareRequest(
}
*core_message_length = core_message->message_length;
- if (GetStatus(msg) != MESSAGE_STATUS_OK) {
+ if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK) {
/* This is to indicate the caller that the core_message_length has been
* appropriately set, but the message buffer is either empty or too small,
* which needs to be initialized and filled in the subsequent call. */
return OEMCrypto_ERROR_SHORT_BUFFER;
}
- if (GetSize(msg) != *core_message_length) {
+ if (ODK_Message_GetSize(&msg) != *core_message_length) {
/* This should not happen. Something is wrong. */
return ODK_ERROR_CORE_MESSAGE;
}
return OEMCrypto_SUCCESS;
}
-static OEMCryptoResult ODK_ParseResponse(
- const uint8_t* message, size_t message_length, size_t core_message_length,
- ODK_MessageType message_type, const ODK_NonceValues* nonce_values,
- void* response_buffer, uint32_t response_buffer_length) {
- if (message == NULL || response_buffer == NULL ||
- core_message_length > message_length) {
+/* Parse the core message and verify that it has the right type. The nonce
+ * values are updated to hold the resposne's API version.
+ */
+static OEMCryptoResult ODK_ParseCoreHeader(const uint8_t* message,
+ size_t message_length,
+ size_t core_message_length,
+ ODK_MessageType message_type,
+ ODK_NonceValues* nonce_values) {
+ // The core_message_length is the length of the core message, which is a
+ // substring of the complete message.
+ if (message == NULL || core_message_length > message_length) {
return ODK_ERROR_CORE_MESSAGE;
}
+ ODK_CoreMessage core_message;
+ ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
- uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
- Message* msg = (Message*)blk;
+ /* The core message should be at the beginning of the buffer. The core message
+ * is the part we are parsing. */
+ ODK_Message_SetSize(&msg, core_message_length);
+ Unpack_ODK_CoreMessage(&msg, &core_message);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-qual"
- /* We initialize the message buffer with a size of the entire message
- * length. */
- /* TODO(b/164486737): Fix the cast-qual warning */
- InitMessage(msg, (uint8_t*)message, message_length);
-#pragma GCC diagnostic pop
-
- /* The core message should be at the beginning of the buffer, and with a
- * shorter length. The core message is the part we are parsing. */
- SetSize(msg, core_message_length);
-
- /* Parse message and unpack it into response buffer. */
- switch (message_type) {
- case ODK_License_Response_Type: {
- if (sizeof(ODK_LicenseResponse) > response_buffer_length) {
- return ODK_ERROR_CORE_MESSAGE;
- }
- Unpack_ODK_LicenseResponse(msg, (ODK_LicenseResponse*)response_buffer);
- break;
- }
- case ODK_Renewal_Response_Type: {
- if (sizeof(ODK_RenewalResponse) > response_buffer_length) {
- return ODK_ERROR_CORE_MESSAGE;
- }
- Unpack_ODK_RenewalResponse(msg, (ODK_RenewalResponse*)response_buffer);
- break;
- }
- case ODK_Provisioning_Response_Type: {
- if (sizeof(ODK_ProvisioningResponse) > response_buffer_length) {
- return ODK_ERROR_CORE_MESSAGE;
- }
- Unpack_ODK_ProvisioningResponse(
- msg, (ODK_ProvisioningResponse*)response_buffer);
- break;
- }
- default: {
- return ODK_ERROR_CORE_MESSAGE;
- }
- }
-
- ODK_CoreMessage* core_message = (ODK_CoreMessage*)response_buffer;
- if (GetStatus(msg) != MESSAGE_STATUS_OK ||
- message_type != core_message->message_type ||
- GetOffset(msg) != core_message->message_length) {
+ if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
+ message_type != core_message.message_type) {
return ODK_ERROR_CORE_MESSAGE;
}
-
+ // The current offset should be the end of the header, which is the message
+ // type, message length, api version, and nonce fields. The header can't be
+ // larger than the whole core message. Also, the core message specifies its
+ // length, which should be exactly the length of the core message buffer.
+ if (ODK_Message_GetOffset(&msg) > core_message.message_length ||
+ core_message.message_length != core_message_length) {
+ return ODK_ERROR_CORE_MESSAGE;
+ }
+ /* We do not support future API version. Also, this function should not be
+ * used for legacy licenses without a core message. */
+ if (core_message.nonce_values.api_major_version > ODK_MAJOR_VERSION ||
+ core_message.nonce_values.api_major_version < ODK_FIRST_VERSION) {
+ return ODK_UNSUPPORTED_API;
+ }
if (nonce_values) {
- /* always verify nonce_values for Renewal and Provisioning responses */
- if (!ODK_NonceValuesEqual(nonce_values, &(core_message->nonce_values))) {
- return OEMCrypto_ERROR_INVALID_NONCE;
+ /* If the server sent us an older format, record the message's API version.
+ */
+ if (nonce_values->api_major_version >
+ core_message.nonce_values.api_major_version) {
+ // If the major version is smaller, use both values from the server.
+ nonce_values->api_major_version =
+ core_message.nonce_values.api_major_version;
+ nonce_values->api_minor_version =
+ core_message.nonce_values.api_minor_version;
+ } else if (nonce_values->api_major_version ==
+ core_message.nonce_values.api_major_version &&
+ nonce_values->api_minor_version >
+ core_message.nonce_values.api_minor_version) {
+ // Otherwise, if the major versions are equal, but the minor is smaller,
+ // then we should lower the minor version.
+ nonce_values->api_minor_version =
+ core_message.nonce_values.api_minor_version;
}
}
-
return OEMCrypto_SUCCESS;
}
@@ -259,47 +249,88 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
OEMCryptoResult ODK_ParseLicense(
const uint8_t* message, size_t message_length, size_t core_message_length,
bool initial_license_load, bool usage_entry_present,
- const uint8_t* request_hash, ODK_TimerLimits* timer_limits,
- ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values,
- ODK_ParsedLicense* parsed_license) {
- if (message == NULL || request_hash == NULL || timer_limits == NULL ||
- clock_values == NULL || nonce_values == NULL || parsed_license == NULL) {
+ ODK_TimerLimits* timer_limits, ODK_ClockValues* clock_values,
+ ODK_NonceValues* nonce_values, ODK_ParsedLicense* parsed_license) {
+ if (message == NULL || timer_limits == NULL || clock_values == NULL ||
+ nonce_values == NULL || parsed_license == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
- ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL, {0}};
- license_response.parsed_license = parsed_license;
-
- const OEMCryptoResult err = ODK_ParseResponse(
- message, message_length, core_message_length, ODK_License_Response_Type,
- NULL, &license_response, sizeof(ODK_LicenseResponse));
-
+ const OEMCryptoResult err =
+ ODK_ParseCoreHeader(message, message_length, core_message_length,
+ ODK_License_Response_Type, nonce_values);
if (err != OEMCrypto_SUCCESS) {
return err;
}
- /* We do not support future API version. Also, this function should not be
- * used for legacy licenses. */
- if (license_response.request.core_message.nonce_values.api_major_version >
- ODK_MAJOR_VERSION ||
- license_response.request.core_message.nonce_values.api_major_version <
- ODK_FIRST_VERSION) {
- return ODK_UNSUPPORTED_API;
+ ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL};
+ license_response.parsed_license = parsed_license;
+
+ ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
+ ODK_Message_SetSize(&msg, core_message_length);
+ if (nonce_values->api_major_version == 16) {
+ ODK_LicenseResponseV16 license_response_v16 = {{{0, 0, {}}}, {}, {0}};
+ Unpack_ODK_LicenseResponseV16(&msg, &license_response_v16);
+
+ if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
+ ODK_Message_GetOffset(&msg) != core_message_length) {
+ return ODK_ERROR_CORE_MESSAGE;
+ }
+
+ // Need to manually set parsed_license fields to
+ // license_response_v16.parsed_license field values since
+ // license_response_v16 is no longer a pointer so parsed_license doesn't get
+ // updated during the unpacking.
+ parsed_license->enc_mac_keys_iv =
+ license_response_v16.parsed_license.enc_mac_keys_iv;
+ parsed_license->enc_mac_keys =
+ license_response_v16.parsed_license.enc_mac_keys;
+ parsed_license->pst = license_response_v16.parsed_license.pst;
+ parsed_license->srm_restriction_data =
+ license_response_v16.parsed_license.srm_restriction_data;
+ parsed_license->license_type =
+ license_response_v16.parsed_license.license_type;
+ parsed_license->nonce_required =
+ license_response_v16.parsed_license.nonce_required;
+ parsed_license->timer_limits =
+ license_response_v16.parsed_license.timer_limits;
+ parsed_license->key_array_length =
+ license_response_v16.parsed_license.key_array_length;
+ uint32_t i;
+ for (i = 0; i < parsed_license->key_array_length; i++) {
+ parsed_license->key_array[i] =
+ license_response_v16.parsed_license.key_array[i];
+ }
+ // Set fields not used in V16 to default values.
+ parsed_license->watermarking = 0;
+ // Set fields not used in V16 to default values.
+ parsed_license->dtcp2_required.dtcp2_required = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_0.id = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_0.extension = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_0.length = 1;
+ parsed_license->dtcp2_required.cmi_descriptor_0.data = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_1.id = 1;
+ parsed_license->dtcp2_required.cmi_descriptor_1.extension = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_1.length = 3;
+ parsed_license->dtcp2_required.cmi_descriptor_1.data[0] = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_1.data[1] = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_1.data[2] = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_2.id = 2;
+ parsed_license->dtcp2_required.cmi_descriptor_2.extension = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_2.length = 3;
+ parsed_license->dtcp2_required.cmi_descriptor_2.data[0] = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_2.data[1] = 0;
+ parsed_license->dtcp2_required.cmi_descriptor_2.data[2] = 0;
+ license_response.request = license_response_v16.request;
+ } else {
+ Unpack_ODK_LicenseResponse(&msg, &license_response);
+
+ if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
+ ODK_Message_GetOffset(&msg) != core_message_length) {
+ return ODK_ERROR_CORE_MESSAGE;
+ }
}
- /* If the server sent us an older format, record the license's API version. */
- if (nonce_values->api_major_version >
- license_response.request.core_message.nonce_values.api_major_version) {
- nonce_values->api_major_version =
- license_response.request.core_message.nonce_values.api_major_version;
- nonce_values->api_minor_version =
- license_response.request.core_message.nonce_values.api_minor_version;
- } else if (nonce_values->api_minor_version >
- license_response.request.core_message.nonce_values
- .api_minor_version) {
- nonce_values->api_minor_version =
- license_response.request.core_message.nonce_values.api_minor_version;
- }
/* If the license has a provider session token (pst), then OEMCrypto should
* have a usage entry loaded. The opposite is also an error. */
if ((usage_entry_present && parsed_license->pst.length == 0) ||
@@ -326,15 +357,6 @@ OEMCryptoResult ODK_ParseLicense(
nonce_values->session_id =
license_response.request.core_message.nonce_values.session_id;
}
- /* For v16, in order to be backwards compatible with a v15 license server,
- * OEMCrypto stores a hash of the core license request and only signs the
- * message body. Here, when we process the license response, we verify that
- * the server has the same hash of the core request. */
- if (initial_license_load && parsed_license->nonce_required &&
- crypto_memcmp(request_hash, license_response.request_hash,
- ODK_SHA256_HASH_SIZE)) {
- return ODK_ERROR_CORE_MESSAGE;
- }
*timer_limits = parsed_license->timer_limits;
/* And update the clock values state. */
clock_values->timer_status = ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED;
@@ -353,16 +375,29 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
return ODK_ERROR_CORE_MESSAGE;
}
+ const OEMCryptoResult err =
+ ODK_ParseCoreHeader(message, message_length, core_message_length,
+ ODK_Renewal_Response_Type, NULL);
+ if (err != OEMCrypto_SUCCESS) {
+ return err;
+ }
ODK_RenewalResponse renewal_response = {
{{0, 0, {}}, 0},
0,
};
- const OEMCryptoResult err = ODK_ParseResponse(
- message, message_length, core_message_length, ODK_Renewal_Response_Type,
- nonce_values, &renewal_response, sizeof(ODK_RenewalResponse));
+ ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
+ ODK_Message_SetSize(&msg, core_message_length);
+ Unpack_ODK_RenewalResponse(&msg, &renewal_response);
- if (err != OEMCrypto_SUCCESS) {
- return err;
+ if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
+ ODK_Message_GetOffset(&msg) != core_message_length) {
+ return ODK_ERROR_CORE_MESSAGE;
+ }
+ /* always verify nonce_values for Renewal and Provisioning responses */
+ if (!ODK_NonceValuesEqualExcludingVersion(
+ nonce_values,
+ &(renewal_response.request.core_message.nonce_values))) {
+ return OEMCrypto_ERROR_INVALID_NONCE;
}
/* Reference:
@@ -392,7 +427,12 @@ OEMCryptoResult ODK_ParseProvisioning(
parsed_response == NULL) {
return ODK_ERROR_CORE_MESSAGE;
}
-
+ const OEMCryptoResult err =
+ ODK_ParseCoreHeader(message, message_length, core_message_length,
+ ODK_Provisioning_Response_Type, NULL);
+ if (err != OEMCrypto_SUCCESS) {
+ return err;
+ }
ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL};
provisioning_response.parsed_provisioning = parsed_response;
@@ -400,13 +440,18 @@ OEMCryptoResult ODK_ParseProvisioning(
return ODK_ERROR_CORE_MESSAGE;
}
- const OEMCryptoResult err = ODK_ParseResponse(
- message, message_length, core_message_length,
- ODK_Provisioning_Response_Type, nonce_values, &provisioning_response,
- sizeof(ODK_ProvisioningResponse));
-
- if (err != OEMCrypto_SUCCESS) {
- return err;
+ ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length);
+ ODK_Message_SetSize(&msg, core_message_length);
+ Unpack_ODK_ProvisioningResponse(&msg, &provisioning_response);
+ if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK ||
+ ODK_Message_GetOffset(&msg) != core_message_length) {
+ return ODK_ERROR_CORE_MESSAGE;
+ }
+ /* always verify nonce_values for Renewal and Provisioning responses */
+ if (!ODK_NonceValuesEqualExcludingVersion(
+ nonce_values,
+ &(provisioning_response.request.core_message.nonce_values))) {
+ return OEMCrypto_ERROR_INVALID_NONCE;
}
if (crypto_memcmp(device_id, provisioning_response.request.device_id,
diff --git a/oemcrypto/odk/src/odk.gyp b/oemcrypto/odk/src/odk.gyp
index d1c5a19..1bdd05c 100644
--- a/oemcrypto/odk/src/odk.gyp
+++ b/oemcrypto/odk/src/odk.gyp
@@ -14,9 +14,27 @@
'includes' : [
'odk.gypi',
],
+ 'cflags': [
+ # TODO(b/172518513): Remove this
+ '-Wno-error=cast-qual',
+ ],
+ 'cflags_c': [
+ # TODO(b/159354894): Remove this
+ '-Wno-error=bad-function-cast',
+ ],
+ 'defines': [
+ # Needed for to work.
+ '_DEFAULT_SOURCE',
+ ],
'direct_dependent_settings': {
+ 'defines': [
+ # Needed for to work.
+ '_DEFAULT_SOURCE',
+ ],
'include_dirs': [
+ '.',
'../include',
+ '../../include',
],
}
},
diff --git a/oemcrypto/odk/src/odk.gypi b/oemcrypto/odk/src/odk.gypi
index 7c33d95..1867605 100644
--- a/oemcrypto/odk/src/odk.gypi
+++ b/oemcrypto/odk/src/odk.gypi
@@ -7,6 +7,7 @@
{
'sources': [
'odk.c',
+ 'odk_message.c',
'odk_overflow.c',
'odk_serialize.c',
'odk_timer.c',
diff --git a/oemcrypto/odk/src/odk_endian.h b/oemcrypto/odk/src/odk_endian.h
index 459a095..1e9f50d 100644
--- a/oemcrypto/odk/src/odk_endian.h
+++ b/oemcrypto/odk/src/odk_endian.h
@@ -11,11 +11,23 @@ extern "C" {
#if defined(__linux__) || defined(__ANDROID__)
#include
+#define oemcrypto_htobe16 htobe16
+#define oemcrypto_be16toh be16toh
#define oemcrypto_htobe32 htobe32
#define oemcrypto_be32toh be32toh
#define oemcrypto_htobe64 htobe64
#define oemcrypto_be64toh be64toh
-#else /* defined(__linux__) || defined(__ANDROID__) */
+#elif defined(__APPLE__)
+#include
+#define oemcrypto_htobe16 OSSwapHostToBigInt16
+#define oemcrypto_be16toh OSSwapBigToHostInt16
+#define oemcrypto_htobe32 OSSwapHostToBigInt32
+#define oemcrypto_be32toh OSSwapBigToHostInt32
+#define oemcrypto_htobe64 OSSwapHostToBigInt64
+#define oemcrypto_be64toh OSSwapBigToHostInt64
+#else /* defined(__linux__) || defined(__ANDROID__) */
+uint32_t oemcrypto_htobe16(uint16_t u16);
+uint32_t oemcrypto_be16toh(uint16_t u16);
uint32_t oemcrypto_htobe32(uint32_t u32);
uint32_t oemcrypto_be32toh(uint32_t u32);
uint64_t oemcrypto_htobe64(uint64_t u64);
diff --git a/oemcrypto/odk/src/odk_message.c b/oemcrypto/odk/src/odk_message.c
new file mode 100644
index 0000000..df29d23
--- /dev/null
+++ b/oemcrypto/odk/src/odk_message.c
@@ -0,0 +1,170 @@
+// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine
+// License Agreement.
+
+#include "odk_message.h"
+
+#include
+#include
+#include
+
+#include "odk_message_priv.h"
+
+/*
+ * C11 defines static_assert in assert.h. If it is available, force a compile
+ * time error if the abstract ODK_Message struct size does not match its
+ * implementation. If static_assert is not available, the runtime assert in
+ * InitMessage will catch the mismatch at the time a message is initialized.
+ */
+#ifdef static_assert
+static_assert(
+ sizeof(ODK_Message) >= sizeof(ODK_Message_Impl),
+ "sizeof(ODK_Message) is too small. You can increase "
+ "SIZE_OF_ODK_MESSAGE_IMPL in odk_message.h to make it large enough.");
+#endif
+
+/*
+ * Create a message structure that references a separate data buffer. An
+ * initialized message is returned. The caller is responsible for ensuring that
+ * the buffer remains allocated for the lifetime of the message. |buffer| may be
+ * NULL. Serialization into a message with a NULL buffer will cause the message
+ * size to be incremented, but no data will be written into the message
+ * buffer. This is useful for calculating the amount of space a message will
+ * need, prior to doing the actual serialization. The buffer contents are
+ * unchanged by this function.
+ */
+ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) {
+ assert(sizeof(ODK_Message) >= sizeof(ODK_Message_Impl));
+ ODK_Message message;
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message;
+ message_impl->base = buffer;
+ message_impl->capacity = capacity;
+ message_impl->size = 0;
+ message_impl->read_offset = 0;
+ message_impl->status = MESSAGE_STATUS_OK;
+ return message;
+}
+
+/*
+ * Erase the contents of the message, set it to an empty state by setting the
+ * message size and read offset to 0, effectively erasing the contents of the
+ * message. The message data buffer pointer remains unchanged, i.e. the message
+ * retains ownership of the buffer. The message buffer is zero-filled. The
+ * message status is reset to MESSAGE_STATUS_OK.
+ */
+void ODK_Message_Clear(ODK_Message* message) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ message_impl->read_offset = 0;
+ message_impl->size = 0;
+ message_impl->status = MESSAGE_STATUS_OK;
+ if (message_impl->base) {
+ memset(message_impl->base, 0, message_impl->capacity);
+ }
+}
+
+/*
+ * Reset read pointer to the beginning of the message and clear status
+ * so that parsing of the message will restart at the beginning of the
+ * message. The message status is reset to MESSAGE_STATUS_OK.
+ */
+void ODK_Message_Reset(ODK_Message* message) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ message_impl->read_offset = 0;
+ message_impl->status = MESSAGE_STATUS_OK;
+}
+
+/*
+ * Return a pointer to the message data buffer, i.e. the message payload.
+ * This is the buffer address that was passed into ODK_Message_Create.
+ */
+uint8_t* ODK_Message_GetBase(ODK_Message* message) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ return message_impl->base;
+}
+
+/*
+ * Get the maximum number of bytes the message can hold.
+ */
+size_t ODK_Message_GetCapacity(ODK_Message* message) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ return message_impl->capacity;
+}
+
+/*
+ * Get the number of bytes currently in the message
+ */
+size_t ODK_Message_GetSize(ODK_Message* message) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ return message_impl->size;
+}
+
+/*
+ * Get the offset of where the next bytes will be read from the message data
+ * buffer.
+ */
+size_t ODK_Message_GetOffset(ODK_Message* message) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ return message_impl->read_offset;
+}
+
+/*
+ * Return the status of the message
+ */
+ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ return message_impl->status;
+}
+
+/*
+ * Set the message status to a specific value
+ */
+void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ /* preserve the first error */
+ if (message_impl->status == MESSAGE_STATUS_OK) {
+ message_impl->status = status;
+ }
+}
+
+/*
+ * Set the size of the message to a value. This may be needed after writing data
+ * into the message data buffer.
+ */
+void ODK_Message_SetSize(ODK_Message* message, size_t size) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ assert(message_impl != NULL);
+ assert(size <= message_impl->capacity);
+ message_impl->size = size;
+}
+
+/*
+ * Test if the integrity of a message. This means that the status must be
+ * MESSAGE_STATUS_OK and that the base, read_offset, size and capacity of the
+ * message are within the range of valid values. The message's base pointer
+ * may be NULL if the buffer has not been assigned yet, that is not invalid.
+ */
+bool ODK_Message_IsValid(ODK_Message* message) {
+ assert(message);
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ if (message_impl == NULL) {
+ return false;
+ }
+ if (message_impl->status != MESSAGE_STATUS_OK) {
+ return false;
+ }
+ if (message_impl->read_offset > message_impl->capacity ||
+ message_impl->size > message_impl->capacity ||
+ message_impl->read_offset > message_impl->size) {
+ message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR;
+ return false;
+ }
+ return true;
+}
diff --git a/oemcrypto/odk/src/odk_message_priv.h b/oemcrypto/odk/src/odk_message_priv.h
new file mode 100644
index 0000000..8ad5f03
--- /dev/null
+++ b/oemcrypto/odk/src/odk_message_priv.h
@@ -0,0 +1,41 @@
+// Copyright 2019 Google LLC. All rights reserved. This file and proprietary
+// source code may only be used and distributed under the Widevine
+// License Agreement.
+
+#ifndef WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_
+#define WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This file must only be included by odk_message.c and serialization_base.c.
+ */
+
+#include
+#include
+
+#include "odk_message.h"
+
+/*
+ * This is the implementation of a message. This structure is private, i.e. it
+ * should only be included by files that are allowed to modify the internals of
+ * a message, that being odk_message.c and serialization_base.c. To ensure
+ * proper alignment and message size, an ODK_Message_Impl should never be
+ * allocated directly, instead allocate ODK_Message and cast to ODK_Message_Impl
+ * because ODK_Message_Impl may be smaller than ODK_Message.
+ */
+typedef struct {
+ uint8_t* base;
+ size_t capacity;
+ size_t size;
+ size_t read_offset;
+ ODK_MessageStatus status;
+} ODK_Message_Impl;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_
diff --git a/oemcrypto/odk/src/odk_overflow.c b/oemcrypto/odk/src/odk_overflow.c
index b679e01..0ebc084 100644
--- a/oemcrypto/odk/src/odk_overflow.c
+++ b/oemcrypto/odk/src/odk_overflow.c
@@ -34,3 +34,13 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c) {
}
return 1;
}
+
+int odk_mul_overflow_ux(size_t a, size_t b, size_t* c) {
+ if (b > 0 && a > SIZE_MAX / b) {
+ return 1;
+ }
+ if (c) {
+ *c = a * b;
+ }
+ return 0;
+}
diff --git a/oemcrypto/odk/src/odk_overflow.h b/oemcrypto/odk/src/odk_overflow.h
index 75cd52b..e725705 100644
--- a/oemcrypto/odk/src/odk_overflow.h
+++ b/oemcrypto/odk/src/odk_overflow.h
@@ -15,6 +15,7 @@ extern "C" {
int odk_sub_overflow_u64(uint64_t a, uint64_t b, uint64_t* c);
int odk_add_overflow_u64(uint64_t a, uint64_t b, uint64_t* c);
int odk_add_overflow_ux(size_t a, size_t b, size_t* c);
+int odk_mul_overflow_ux(size_t a, size_t b, size_t* c);
#ifdef __cplusplus
}
diff --git a/oemcrypto/odk/src/odk_serialize.c b/oemcrypto/odk/src/odk_serialize.c
index c35e9b5..55ea3a4 100644
--- a/oemcrypto/odk/src/odk_serialize.c
+++ b/oemcrypto/odk/src/odk_serialize.c
@@ -13,20 +13,20 @@
/* @@ private serialize */
-static void Pack_ODK_NonceValues(Message* msg, ODK_NonceValues const* obj) {
+static void Pack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues const* obj) {
Pack_uint16_t(msg, &obj->api_minor_version);
Pack_uint16_t(msg, &obj->api_major_version);
Pack_uint32_t(msg, &obj->nonce);
Pack_uint32_t(msg, &obj->session_id);
}
-static void Pack_ODK_CoreMessage(Message* msg, ODK_CoreMessage const* obj) {
+static void Pack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage const* obj) {
Pack_uint32_t(msg, &obj->message_type);
Pack_uint32_t(msg, &obj->message_length);
Pack_ODK_NonceValues(msg, &obj->nonce_values);
}
-static void Pack_OEMCrypto_KeyObject(Message* msg,
+static void Pack_OEMCrypto_KeyObject(ODK_Message* msg,
OEMCrypto_KeyObject const* obj) {
Pack_OEMCrypto_Substring(msg, &obj->key_id);
Pack_OEMCrypto_Substring(msg, &obj->key_data_iv);
@@ -35,7 +35,7 @@ static void Pack_OEMCrypto_KeyObject(Message* msg,
Pack_OEMCrypto_Substring(msg, &obj->key_control);
}
-static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) {
+static void Pack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits const* obj) {
Pack_bool(msg, &obj->soft_enforce_rental_duration);
Pack_bool(msg, &obj->soft_enforce_playback_duration);
Pack_uint64_t(msg, &obj->earliest_playback_start_seconds);
@@ -44,10 +44,52 @@ static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) {
Pack_uint64_t(msg, &obj->initial_renewal_duration_seconds);
}
-static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) {
+static void Pack_ODK_ParsedLicense(ODK_Message* msg,
+ ODK_ParsedLicense const* obj) {
/* hand-coded */
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
- SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
+ ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
+ return;
+ }
+ Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
+ Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys);
+ Pack_OEMCrypto_Substring(msg, &obj->pst);
+ Pack_OEMCrypto_Substring(msg, &obj->srm_restriction_data);
+ Pack_enum(msg, obj->license_type);
+ Pack_bool(msg, &obj->nonce_required);
+ Pack_ODK_TimerLimits(msg, &obj->timer_limits);
+ Pack_uint32_t(msg, &obj->watermarking);
+ Pack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required);
+ if (obj->dtcp2_required.dtcp2_required) {
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension);
+ Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension);
+ Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension);
+ Pack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]);
+ Pack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]);
+ }
+ Pack_uint32_t(msg, &obj->key_array_length);
+ size_t i;
+ for (i = 0; i < (size_t)obj->key_array_length; i++) {
+ Pack_OEMCrypto_KeyObject(msg, &obj->key_array[i]);
+ }
+}
+
+static void Pack_ODK_ParsedLicenseV16(ODK_Message* msg,
+ ODK_ParsedLicenseV16 const* obj) {
+ /* hand-coded */
+ if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
+ ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
return;
}
Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
@@ -64,7 +106,7 @@ static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) {
}
}
-static void Pack_ODK_ParsedProvisioning(Message* msg,
+static void Pack_ODK_ParsedProvisioning(ODK_Message* msg,
ODK_ParsedProvisioning const* obj) {
Pack_enum(msg, obj->key_type);
Pack_OEMCrypto_Substring(msg, &obj->enc_private_key);
@@ -74,19 +116,19 @@ static void Pack_ODK_ParsedProvisioning(Message* msg,
/* @@ odk serialize */
-void Pack_ODK_PreparedLicenseRequest(Message* msg,
+void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
}
-void Pack_ODK_PreparedRenewalRequest(Message* msg,
+void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_uint64_t(msg, &obj->playback_time);
}
void Pack_ODK_PreparedProvisioningRequest(
- Message* msg, ODK_PreparedProvisioningRequest const* obj) {
+ ODK_Message* msg, ODK_PreparedProvisioningRequest const* obj) {
Pack_ODK_CoreMessage(msg, &obj->core_message);
Pack_uint32_t(msg, &obj->device_id_length);
PackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
@@ -94,18 +136,26 @@ void Pack_ODK_PreparedProvisioningRequest(
/* @@ kdo serialize */
-void Pack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse const* obj) {
+void Pack_ODK_LicenseResponse(ODK_Message* msg,
+ ODK_LicenseResponse const* obj) {
Pack_ODK_PreparedLicenseRequest(msg, &obj->request);
Pack_ODK_ParsedLicense(msg, (const ODK_ParsedLicense*)obj->parsed_license);
+}
+
+void Pack_ODK_LicenseResponseV16(ODK_Message* msg,
+ ODK_LicenseResponseV16 const* obj) {
+ Pack_ODK_PreparedLicenseRequest(msg, &obj->request);
+ Pack_ODK_ParsedLicenseV16(msg, &obj->parsed_license);
PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}
-void Pack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse const* obj) {
+void Pack_ODK_RenewalResponse(ODK_Message* msg,
+ ODK_RenewalResponse const* obj) {
Pack_ODK_PreparedRenewalRequest(msg, &obj->request);
Pack_uint64_t(msg, &obj->renewal_duration_seconds);
}
-void Pack_ODK_ProvisioningResponse(Message* msg,
+void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse const* obj) {
Pack_ODK_PreparedProvisioningRequest(msg, &obj->request);
Pack_ODK_ParsedProvisioning(
@@ -116,20 +166,21 @@ void Pack_ODK_ProvisioningResponse(Message* msg,
/* @@ private deserialize */
-static void Unpack_ODK_NonceValues(Message* msg, ODK_NonceValues* obj) {
+static void Unpack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues* obj) {
Unpack_uint16_t(msg, &obj->api_minor_version);
Unpack_uint16_t(msg, &obj->api_major_version);
Unpack_uint32_t(msg, &obj->nonce);
Unpack_uint32_t(msg, &obj->session_id);
}
-static void Unpack_ODK_CoreMessage(Message* msg, ODK_CoreMessage* obj) {
+void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj) {
Unpack_uint32_t(msg, &obj->message_type);
Unpack_uint32_t(msg, &obj->message_length);
Unpack_ODK_NonceValues(msg, &obj->nonce_values);
}
-static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) {
+static void Unpack_OEMCrypto_KeyObject(ODK_Message* msg,
+ OEMCrypto_KeyObject* obj) {
Unpack_OEMCrypto_Substring(msg, &obj->key_id);
Unpack_OEMCrypto_Substring(msg, &obj->key_data_iv);
Unpack_OEMCrypto_Substring(msg, &obj->key_data);
@@ -137,7 +188,7 @@ static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) {
Unpack_OEMCrypto_Substring(msg, &obj->key_control);
}
-static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) {
+static void Unpack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits* obj) {
Unpack_bool(msg, &obj->soft_enforce_rental_duration);
Unpack_bool(msg, &obj->soft_enforce_playback_duration);
Unpack_uint64_t(msg, &obj->earliest_playback_start_seconds);
@@ -146,7 +197,65 @@ static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) {
Unpack_uint64_t(msg, &obj->initial_renewal_duration_seconds);
}
-static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) {
+static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) {
+ Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
+ Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys);
+ Unpack_OEMCrypto_Substring(msg, &obj->pst);
+ Unpack_OEMCrypto_Substring(msg, &obj->srm_restriction_data);
+ obj->license_type = (OEMCrypto_LicenseType)Unpack_enum(msg);
+ Unpack_bool(msg, &obj->nonce_required);
+ Unpack_ODK_TimerLimits(msg, &obj->timer_limits);
+ Unpack_uint32_t(msg, &obj->watermarking);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.dtcp2_required);
+ if (obj->dtcp2_required.dtcp2_required) {
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.id);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.extension);
+ Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_0.length);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_0.data);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.id);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.extension);
+ Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_1.length);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[0]);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[1]);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_1.data[2]);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.id);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.extension);
+ Unpack_uint16_t(msg, &obj->dtcp2_required.cmi_descriptor_2.length);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[0]);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[1]);
+ Unpack_uint8_t(msg, &obj->dtcp2_required.cmi_descriptor_2.data[2]);
+ } else {
+ obj->dtcp2_required.dtcp2_required = 0;
+ obj->dtcp2_required.cmi_descriptor_0.id = 0;
+ obj->dtcp2_required.cmi_descriptor_0.extension = 0;
+ obj->dtcp2_required.cmi_descriptor_0.length = 0;
+ obj->dtcp2_required.cmi_descriptor_0.data = 0;
+ obj->dtcp2_required.cmi_descriptor_1.id = 0;
+ obj->dtcp2_required.cmi_descriptor_1.extension = 0;
+ obj->dtcp2_required.cmi_descriptor_1.length = 0;
+ obj->dtcp2_required.cmi_descriptor_1.data[0] = 0;
+ obj->dtcp2_required.cmi_descriptor_1.data[1] = 0;
+ obj->dtcp2_required.cmi_descriptor_1.data[2] = 0;
+ obj->dtcp2_required.cmi_descriptor_2.id = 0;
+ obj->dtcp2_required.cmi_descriptor_2.extension = 0;
+ obj->dtcp2_required.cmi_descriptor_2.length = 0;
+ obj->dtcp2_required.cmi_descriptor_2.data[0] = 0;
+ obj->dtcp2_required.cmi_descriptor_2.data[1] = 0;
+ obj->dtcp2_required.cmi_descriptor_2.data[2] = 0;
+ }
+ Unpack_uint32_t(msg, &obj->key_array_length);
+ if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
+ ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
+ return;
+ }
+ uint32_t i;
+ for (i = 0; i < obj->key_array_length; i++) {
+ Unpack_OEMCrypto_KeyObject(msg, &obj->key_array[i]);
+ }
+}
+
+static void Unpack_ODK_ParsedLicenseV16(ODK_Message* msg,
+ ODK_ParsedLicenseV16* obj) {
Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv);
Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys);
Unpack_OEMCrypto_Substring(msg, &obj->pst);
@@ -156,7 +265,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) {
Unpack_ODK_TimerLimits(msg, &obj->timer_limits);
Unpack_uint32_t(msg, &obj->key_array_length);
if (obj->key_array_length > ODK_MAX_NUM_KEYS) {
- SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
+ ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR);
return;
}
uint32_t i;
@@ -165,7 +274,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) {
}
}
-static void Unpack_ODK_ParsedProvisioning(Message* msg,
+static void Unpack_ODK_ParsedProvisioning(ODK_Message* msg,
ODK_ParsedProvisioning* obj) {
obj->key_type = (OEMCrypto_PrivateKeyType)Unpack_enum(msg);
Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key);
@@ -175,42 +284,48 @@ static void Unpack_ODK_ParsedProvisioning(Message* msg,
/* @ kdo deserialize */
-void Unpack_ODK_PreparedLicenseRequest(Message* msg,
+void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
}
-void Unpack_ODK_PreparedRenewalRequest(Message* msg,
+void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_uint64_t(msg, &obj->playback_time);
}
void Unpack_ODK_PreparedProvisioningRequest(
- Message* msg, ODK_PreparedProvisioningRequest* obj) {
+ ODK_Message* msg, ODK_PreparedProvisioningRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
Unpack_uint32_t(msg, &obj->device_id_length);
UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id));
}
-void Unpack_ODK_PreparedCommonRequest(Message* msg,
+void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
ODK_PreparedCommonRequest* obj) {
Unpack_ODK_CoreMessage(msg, &obj->core_message);
}
/* @@ odk deserialize */
-void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj) {
+void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj) {
Unpack_ODK_PreparedLicenseRequest(msg, &obj->request);
Unpack_ODK_ParsedLicense(msg, obj->parsed_license);
+}
+
+void Unpack_ODK_LicenseResponseV16(ODK_Message* msg,
+ ODK_LicenseResponseV16* obj) {
+ Unpack_ODK_PreparedLicenseRequest(msg, &obj->request);
+ Unpack_ODK_ParsedLicenseV16(msg, &obj->parsed_license);
UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash));
}
-void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj) {
+void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj) {
Unpack_ODK_PreparedRenewalRequest(msg, &obj->request);
Unpack_uint64_t(msg, &obj->renewal_duration_seconds);
}
-void Unpack_ODK_ProvisioningResponse(Message* msg,
+void Unpack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse* obj) {
Unpack_ODK_PreparedProvisioningRequest(msg, &obj->request);
Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning);
diff --git a/oemcrypto/odk/src/odk_serialize.h b/oemcrypto/odk/src/odk_serialize.h
index 0816bf7..c08b4d5 100644
--- a/oemcrypto/odk/src/odk_serialize.h
+++ b/oemcrypto/odk/src/odk_serialize.h
@@ -16,34 +16,39 @@ extern "C" {
#endif
/* odk pack */
-void Pack_ODK_PreparedLicenseRequest(Message* msg,
+void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg,
const ODK_PreparedLicenseRequest* obj);
-void Pack_ODK_PreparedRenewalRequest(Message* msg,
+void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg,
const ODK_PreparedRenewalRequest* obj);
void Pack_ODK_PreparedProvisioningRequest(
- Message* msg, const ODK_PreparedProvisioningRequest* obj);
+ ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj);
/* odk unpack */
-void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj);
-void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj);
-void Unpack_ODK_ProvisioningResponse(Message* msg,
+void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj);
+void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj);
+void Unpack_ODK_LicenseResponseV16(ODK_Message* msg,
+ ODK_LicenseResponseV16* obj);
+void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj);
+void Unpack_ODK_ProvisioningResponse(ODK_Message* msg,
ODK_ProvisioningResponse* obj);
/* kdo pack */
-void Pack_ODK_LicenseResponse(Message* msg, const ODK_LicenseResponse* obj);
-void Pack_ODK_RenewalResponse(Message* msg, const ODK_RenewalResponse* obj);
-void Pack_ODK_ProvisioningResponse(Message* msg,
+void Pack_ODK_LicenseResponse(ODK_Message* msg, const ODK_LicenseResponse* obj);
+void Pack_ODK_LicenseResponseV16(ODK_Message* msg,
+ const ODK_LicenseResponseV16* obj);
+void Pack_ODK_RenewalResponse(ODK_Message* msg, const ODK_RenewalResponse* obj);
+void Pack_ODK_ProvisioningResponse(ODK_Message* msg,
const ODK_ProvisioningResponse* obj);
/* kdo unpack */
-void Unpack_ODK_PreparedLicenseRequest(Message* msg,
+void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg,
ODK_PreparedLicenseRequest* obj);
-void Unpack_ODK_PreparedRenewalRequest(Message* msg,
+void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg,
ODK_PreparedRenewalRequest* obj);
void Unpack_ODK_PreparedProvisioningRequest(
- Message* msg, ODK_PreparedProvisioningRequest* obj);
+ ODK_Message* msg, ODK_PreparedProvisioningRequest* obj);
-void Unpack_ODK_PreparedCommonRequest(Message* msg,
+void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg,
ODK_PreparedCommonRequest* obj);
#ifdef __cplusplus
diff --git a/oemcrypto/odk/src/odk_structs_priv.h b/oemcrypto/odk/src/odk_structs_priv.h
index 6b138f4..1bfc597 100644
--- a/oemcrypto/odk/src/odk_structs_priv.h
+++ b/oemcrypto/odk/src/odk_structs_priv.h
@@ -14,24 +14,26 @@
extern "C" {
#endif
-typedef enum {
- ODK_License_Request_Type = 1,
- ODK_License_Response_Type = 2,
- ODK_Renewal_Request_Type = 3,
- ODK_Renewal_Response_Type = 4,
- ODK_Provisioning_Request_Type = 5,
- ODK_Provisioning_Response_Type = 6,
+// We use a typedef here so `ODK_CoreMessage` will contain "simple types" which
+// should work better with the auto code generator.
+typedef uint32_t ODK_MessageType;
- // Reserve future message types to support forward compatibility.
- ODK_Release_Request_Type = 7,
- ODK_Release_Response_Type = 8,
- ODK_Common_Request_Type = 9,
- ODK_Common_Response_Type = 10,
-} ODK_MessageType;
+#define ODK_License_Request_Type ((ODK_MessageType)1u)
+#define ODK_License_Response_Type ((ODK_MessageType)2u)
+#define ODK_Renewal_Request_Type ((ODK_MessageType)3u)
+#define ODK_Renewal_Response_Type ((ODK_MessageType)4u)
+#define ODK_Provisioning_Request_Type ((ODK_MessageType)5u)
+#define ODK_Provisioning_Response_Type ((ODK_MessageType)6u)
+
+// Reserve future message types to support forward compatibility.
+#define ODK_Release_Request_Type ((ODK_MessageType)7u)
+#define ODK_Release_Response_Type ((ODK_MessageType)8u)
+#define ODK_Common_Request_Type ((ODK_MessageType)9u)
+#define ODK_Common_Response_Type ((ODK_MessageType)10u)
typedef struct {
- uint32_t message_type;
- uint32_t message_length;
+ ODK_MessageType message_type; // Type of core message (defined above)
+ uint32_t message_length; // Length of core message.
ODK_NonceValues nonce_values;
} ODK_CoreMessage;
@@ -54,12 +56,29 @@ typedef struct {
ODK_CoreMessage core_message;
} ODK_PreparedCommonRequest;
+typedef struct {
+ OEMCrypto_Substring enc_mac_keys_iv;
+ OEMCrypto_Substring enc_mac_keys;
+ OEMCrypto_Substring pst;
+ OEMCrypto_Substring srm_restriction_data;
+ OEMCrypto_LicenseType license_type;
+ bool nonce_required;
+ ODK_TimerLimits timer_limits;
+ uint32_t key_array_length;
+ OEMCrypto_KeyObject key_array[ODK_MAX_NUM_KEYS];
+} ODK_ParsedLicenseV16;
+
typedef struct {
ODK_PreparedLicenseRequest request;
ODK_ParsedLicense* parsed_license;
- uint8_t request_hash[ODK_SHA256_HASH_SIZE];
} ODK_LicenseResponse;
+typedef struct {
+ ODK_PreparedLicenseRequest request;
+ ODK_ParsedLicenseV16 parsed_license;
+ uint8_t request_hash[ODK_SHA256_HASH_SIZE];
+} ODK_LicenseResponseV16;
+
typedef struct {
ODK_PreparedRenewalRequest request;
uint64_t renewal_duration_seconds;
@@ -74,26 +93,26 @@ typedef struct {
// without any padding added by the compiler. Make sure they get updated when
// request structs change. Refer to test suite OdkSizeTest in
// ../test/odk_test.cpp for validations of each of the defined request sizes.
-#define ODK_LICENSE_REQUEST_SIZE 20
-#define ODK_RENEWAL_REQUEST_SIZE 28
-#define ODK_PROVISIONING_REQUEST_SIZE 88
+#define ODK_LICENSE_REQUEST_SIZE 20u
+#define ODK_RENEWAL_REQUEST_SIZE 28u
+#define ODK_PROVISIONING_REQUEST_SIZE 88u
// These are the possible timer status values.
-#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0 // Should not happen.
+#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0u // Should not happen.
// When the structure has been initialized, but no license is loaded.
-#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1
+#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1u
// After the license is loaded, before a successful decrypt.
-#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2
+#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2u
// After the license is loaded, if a renewal has also been loaded.
-#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3
+#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3u
// The first decrypt has occurred and the timer is active.
-#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4
+#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4u
// The first decrypt has occurred and the timer is unlimited.
-#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5
+#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5u
// The timer has transitioned from active to expired.
-#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6
+#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6u
// The license has been marked as inactive.
-#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7
+#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7u
// A helper function for computing timer limits when a renewal is loaded.
OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits,
diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c
index c817bbb..1b09551 100644
--- a/oemcrypto/odk/src/odk_timer.c
+++ b/oemcrypto/odk/src/odk_timer.c
@@ -71,7 +71,7 @@ static OEMCryptoResult ODK_CheckRentalWindow(
/* rental_clock = time since license signed. */
uint64_t rental_clock = 0;
if (odk_sub_overflow_u64(system_time_seconds,
- clock_values->time_of_license_signed,
+ clock_values->time_of_license_request_signed,
&rental_clock)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -180,7 +180,7 @@ OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits,
}
/* If this is before the license was signed, something is odd. Return an
* error. */
- if (system_time_seconds < clock_values->time_of_license_signed) {
+ if (system_time_seconds < clock_values->time_of_license_request_signed) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -297,7 +297,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
if (clock_values == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
- clock_values->time_of_license_signed = system_time_seconds;
+ clock_values->time_of_license_request_signed = system_time_seconds;
clock_values->time_of_first_decrypt = 0;
clock_values->time_of_last_decrypt = 0;
clock_values->time_when_timer_expires = 0;
@@ -308,7 +308,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
/* This is called when OEMCrypto reloads a usage entry. */
OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
- uint64_t time_of_license_signed,
+ uint64_t time_of_license_request_signed,
uint64_t time_of_first_decrypt,
uint64_t time_of_last_decrypt,
enum OEMCrypto_Usage_Entry_Status status,
@@ -316,7 +316,7 @@ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
if (clock_values == NULL) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
- clock_values->time_of_license_signed = time_of_license_signed;
+ clock_values->time_of_license_request_signed = time_of_license_request_signed;
clock_values->time_of_first_decrypt = time_of_first_decrypt;
clock_values->time_of_last_decrypt = time_of_last_decrypt;
clock_values->time_when_timer_expires = 0;
@@ -336,7 +336,7 @@ OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds,
/* All times are relative to when the license was signed. */
uint64_t rental_time = 0;
if (odk_sub_overflow_u64(system_time_seconds,
- clock_values->time_of_license_signed,
+ clock_values->time_of_license_request_signed,
&rental_time)) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
diff --git a/oemcrypto/odk/src/odk_util.c b/oemcrypto/odk/src/odk_util.c
index 76ee242..a6669a4 100644
--- a/oemcrypto/odk/src/odk_util.c
+++ b/oemcrypto/odk/src/odk_util.c
@@ -24,11 +24,10 @@ int crypto_memcmp(const void* in_a, const void* in_b, size_t len) {
return x;
}
-bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b) {
+bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a,
+ const ODK_NonceValues* b) {
if (a == NULL || b == NULL) {
return (a == b);
}
- return (a->api_major_version == b->api_major_version &&
- a->api_minor_version == b->api_minor_version &&
- a->nonce == b->nonce && a->session_id == b->session_id);
+ return (a->nonce == b->nonce && a->session_id == b->session_id);
}
diff --git a/oemcrypto/odk/src/odk_util.h b/oemcrypto/odk/src/odk_util.h
index def0865..ab932dd 100644
--- a/oemcrypto/odk/src/odk_util.h
+++ b/oemcrypto/odk/src/odk_util.h
@@ -20,7 +20,8 @@ extern "C" {
* return value when a != b is undefined, other than being non-zero. */
int crypto_memcmp(const void* a, const void* b, size_t len);
-bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b);
+bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a,
+ const ODK_NonceValues* b);
#ifdef __cplusplus
} // extern "C"
diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c
index 6e6674c..90b84b3 100644
--- a/oemcrypto/odk/src/serialization_base.c
+++ b/oemcrypto/odk/src/serialization_base.c
@@ -4,233 +4,197 @@
#include "serialization_base.h"
+#include
#include
#include
#include
#include "OEMCryptoCENCCommon.h"
+#include "odk_message.h"
+#include "odk_message_priv.h"
#include "odk_overflow.h"
-struct _Message {
- uint8_t* base;
- size_t capacity;
- size_t size; /* bytes written */
- size_t read_offset; /* bytes read */
- MessageStatus status;
-};
-
-bool ValidMessage(Message* message) {
- if (message == NULL) {
- return false;
- }
- if (message->status != MESSAGE_STATUS_OK) {
- return false;
- }
- if (message->base == NULL) {
- message->status = MESSAGE_STATUS_NULL_POINTER_ERROR;
- return false;
- }
- if (message->size > message->capacity ||
- message->read_offset > message->size) {
- message->status = MESSAGE_STATUS_OVERFLOW_ERROR;
- return false;
- }
- return true;
+/*
+ * An ODK_Message_Impl pointer must only be obtained by calling GetMessageImpl.
+ * This forces any message to pass the validity check before being operated on,
+ * which means that no function can modify or access the internals of a message
+ * without having it be validated first.
+ */
+static ODK_Message_Impl* GetMessageImpl(ODK_Message* message) {
+ if (!ODK_Message_IsValid(message)) return NULL;
+ return (ODK_Message_Impl*)message;
}
-static void PackBytes(Message* message, const uint8_t* ptr, size_t count) {
- if (count <= message->capacity - message->size) {
- memcpy((void*)(message->base + message->size), (void*)ptr, count);
- message->size += count;
+static void PackBytes(ODK_Message* message, const uint8_t* ptr, size_t count) {
+ ODK_Message_Impl* message_impl = GetMessageImpl(message);
+ if (!message_impl) return;
+ if (count <= message_impl->capacity - message_impl->size) {
+ memcpy((void*)(message_impl->base + message_impl->size), (const void*)ptr,
+ count);
+ message_impl->size += count;
} else {
- message->status = MESSAGE_STATUS_OVERFLOW_ERROR;
+ message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR;
}
}
-void Pack_enum(Message* message, int value) {
+void Pack_enum(ODK_Message* message, int value) {
uint32_t v32 = value;
Pack_uint32_t(message, &v32);
}
-void Pack_bool(Message* message, const bool* value) {
- if (!ValidMessage(message)) return;
+void Pack_bool(ODK_Message* message, const bool* value) {
+ assert(value);
uint8_t data[4] = {0};
data[3] = *value ? 1 : 0;
PackBytes(message, data, sizeof(data));
}
-void Pack_uint16_t(Message* message, const uint16_t* value) {
- if (!ValidMessage(message)) return;
+void Pack_uint8_t(ODK_Message* message, const uint8_t* value) {
+ assert(value);
+ uint8_t data[1] = {0};
+ data[0] = (uint8_t)(*value >> 0);
+ PackBytes(message, data, sizeof(data));
+}
+
+void Pack_uint16_t(ODK_Message* message, const uint16_t* value) {
+ assert(value);
uint8_t data[2] = {0};
- data[0] = *value >> 8;
- data[1] = *value >> 0;
+ data[0] = (uint8_t)(*value >> 8);
+ data[1] = (uint8_t)(*value >> 0);
PackBytes(message, data, sizeof(data));
}
-void Pack_uint32_t(Message* message, const uint32_t* value) {
- if (!ValidMessage(message)) return;
+void Pack_uint32_t(ODK_Message* message, const uint32_t* value) {
+ assert(value);
uint8_t data[4] = {0};
- data[0] = *value >> 24;
- data[1] = *value >> 16;
- data[2] = *value >> 8;
- data[3] = *value >> 0;
+ data[0] = (uint8_t)(*value >> 24);
+ data[1] = (uint8_t)(*value >> 16);
+ data[2] = (uint8_t)(*value >> 8);
+ data[3] = (uint8_t)(*value >> 0);
PackBytes(message, data, sizeof(data));
}
-void Pack_uint64_t(Message* message, const uint64_t* value) {
- if (!ValidMessage(message)) return;
- uint32_t hi = *value >> 32;
- uint32_t lo = *value;
+void Pack_uint64_t(ODK_Message* message, const uint64_t* value) {
+ assert(value);
+ uint32_t hi = (uint32_t)(*value >> 32);
+ uint32_t lo = (uint32_t)(*value);
Pack_uint32_t(message, &hi);
Pack_uint32_t(message, &lo);
}
-void PackArray(Message* message, const uint8_t* base, size_t size) {
- if (!ValidMessage(message)) return;
+void PackArray(ODK_Message* message, const uint8_t* base, size_t size) {
PackBytes(message, base, size);
}
-void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj) {
+void Pack_OEMCrypto_Substring(ODK_Message* message,
+ const OEMCrypto_Substring* obj) {
+ assert(obj);
uint32_t offset = (uint32_t)obj->offset;
uint32_t length = (uint32_t)obj->length;
- Pack_uint32_t(msg, &offset);
- Pack_uint32_t(msg, &length);
+ Pack_uint32_t(message, &offset);
+ Pack_uint32_t(message, &length);
}
-static void UnpackBytes(Message* message, uint8_t* ptr, size_t count) {
- if (count <= message->size - message->read_offset) {
- memcpy((void*)ptr, (void*)(message->base + message->read_offset), count);
- message->read_offset += count;
+static void UnpackBytes(ODK_Message* message, uint8_t* ptr, size_t count) {
+ assert(ptr);
+ ODK_Message_Impl* message_impl = GetMessageImpl(message);
+ if (!message_impl) return;
+ if (count <= message_impl->size - message_impl->read_offset) {
+ memcpy((void*)ptr, (void*)(message_impl->base + message_impl->read_offset),
+ count);
+ message_impl->read_offset += count;
} else {
- message->status = MESSAGE_STATUS_UNDERFLOW_ERROR;
+ message_impl->status = MESSAGE_STATUS_UNDERFLOW_ERROR;
}
}
-int Unpack_enum(Message* message) {
+int Unpack_enum(ODK_Message* message) {
uint32_t v32;
Unpack_uint32_t(message, &v32);
- return v32;
+ return (int)v32;
}
-void Unpack_bool(Message* message, bool* value) {
- if (!ValidMessage(message)) return;
+void Unpack_bool(ODK_Message* message, bool* value) {
uint8_t data[4] = {0};
UnpackBytes(message, data, sizeof(data));
+ assert(value);
*value = (0 != data[3]);
}
-void Unpack_uint16_t(Message* message, uint16_t* value) {
- if (!ValidMessage(message)) return;
+void Unpack_uint8_t(ODK_Message* message, uint8_t* value) {
+ assert(value);
+ uint8_t data[1] = {0};
+ UnpackBytes(message, data, sizeof(data));
+ *value = data[0];
+}
+
+void Unpack_uint16_t(ODK_Message* message, uint16_t* value) {
+ assert(value);
uint8_t data[2] = {0};
UnpackBytes(message, data, sizeof(data));
*value = data[0];
*value = *value << 8 | data[1];
}
-void Unpack_uint32_t(Message* message, uint32_t* value) {
- if (!ValidMessage(message)) return;
+void Unpack_uint32_t(ODK_Message* message, uint32_t* value) {
+ ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message;
+ if (!message_impl) return;
uint8_t data[4] = {0};
UnpackBytes(message, data, sizeof(data));
+ assert(value);
*value = data[0];
*value = *value << 8 | data[1];
*value = *value << 8 | data[2];
*value = *value << 8 | data[3];
}
-void Unpack_uint64_t(Message* message, uint64_t* value) {
- if (!ValidMessage(message)) return;
+void Unpack_uint64_t(ODK_Message* message, uint64_t* value) {
uint32_t hi = 0;
uint32_t lo = 0;
Unpack_uint32_t(message, &hi);
Unpack_uint32_t(message, &lo);
+ assert(value);
*value = hi;
*value = *value << 32 | lo;
}
-void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj) {
+void Unpack_OEMCrypto_Substring(ODK_Message* message,
+ OEMCrypto_Substring* obj) {
uint32_t offset = 0, length = 0;
- Unpack_uint32_t(msg, &offset);
- Unpack_uint32_t(msg, &length);
- if (!ValidMessage(msg)) return;
+ Unpack_uint32_t(message, &offset);
+ Unpack_uint32_t(message, &length);
+ ODK_Message_Impl* message_impl = GetMessageImpl(message);
+ if (!message_impl) return;
+
/* Each substring should be contained within the message body, which is in the
* total message, just after the core message. The offset of a substring is
* relative to the message body. So we need to verify:
- * 0 < offset and offset + length < message->capacity - message->size
- * or offset + length + message->size < message->capacity
+ *
+ * For non-empty substring:
+ * offset + length < message_impl->capacity - message_impl->size or
+ * offset + length + message_impl->size < message_impl->capacity
+ *
+ * For empty substring (length is 0):
+ * offset must be 0
*/
- size_t substring_end = 0; /* = offset + length; */
- size_t end = 0; /* = substring_end + message->size; */
- if (odk_add_overflow_ux(offset, length, &substring_end) ||
- odk_add_overflow_ux(substring_end, msg->size, &end) ||
- end > msg->capacity) {
- msg->status = MESSAGE_STATUS_OVERFLOW_ERROR;
+ if (length == 0 && offset != 0) {
+ message_impl->status = MESSAGE_STATUS_UNKNOWN_ERROR;
return;
}
+ size_t substring_end = 0; /* = offset + length; */
+ size_t end = 0; /* = substring_end + message_impl->size; */
+ if (odk_add_overflow_ux(offset, length, &substring_end) ||
+ odk_add_overflow_ux(substring_end, message_impl->size, &end) ||
+ end > message_impl->capacity) {
+ message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR;
+ return;
+ }
+ assert(obj);
obj->offset = offset;
obj->length = length;
}
/* copy out */
-void UnpackArray(Message* message, uint8_t* address, size_t size) {
- if (!ValidMessage(message)) return;
+void UnpackArray(ODK_Message* message, uint8_t* address, size_t size) {
UnpackBytes(message, address, size);
}
-
-/*
- * The message structure, which is separate from the buffer,
- * is initialized to reference the buffer
- */
-void InitMessage(Message* message, uint8_t* buffer, size_t capacity) {
- if (message == NULL) return;
- memset(message, 0, sizeof(Message));
- message->base = buffer;
- message->capacity = capacity;
- message->size = 0;
- message->read_offset = 0;
- message->status = MESSAGE_STATUS_OK;
-}
-
-/*
- * Set the message to an empty state
- */
-void ResetMessage(Message* message) {
- message->size = 0;
- message->read_offset = 0;
- message->status = MESSAGE_STATUS_OK;
-}
-
-uint8_t* GetBase(Message* message) {
- if (message == NULL) return NULL;
- return message->base;
-}
-
-size_t GetCapacity(Message* message) {
- if (message == NULL) return 0;
- return message->capacity;
-}
-
-size_t GetSize(Message* message) {
- if (message == NULL) return 0;
- return message->size;
-}
-
-void SetSize(Message* message, size_t size) {
- if (message == NULL) return;
- if (size > message->capacity)
- message->status = MESSAGE_STATUS_OVERFLOW_ERROR;
- else
- message->size = size;
-}
-
-MessageStatus GetStatus(Message* message) { return message->status; }
-
-void SetStatus(Message* message, MessageStatus status) {
- message->status = status;
-}
-
-size_t GetOffset(Message* message) {
- if (message == NULL) return 0;
- return message->read_offset;
-}
-
-size_t SizeOfMessageStruct() { return sizeof(Message); }
diff --git a/oemcrypto/odk/src/serialization_base.h b/oemcrypto/odk/src/serialization_base.h
index e1f3969..7b69e11 100644
--- a/oemcrypto/odk/src/serialization_base.h
+++ b/oemcrypto/odk/src/serialization_base.h
@@ -13,74 +13,27 @@ extern "C" {
#include
#include "OEMCryptoCENCCommon.h"
+#include "odk_message.h"
-#define SIZE_OF_MESSAGE_STRUCT 64
+void Pack_enum(ODK_Message* message, int value);
+void Pack_bool(ODK_Message* message, const bool* value);
+void Pack_uint8_t(ODK_Message* message, const uint8_t* value);
+void Pack_uint16_t(ODK_Message* message, const uint16_t* value);
+void Pack_uint32_t(ODK_Message* message, const uint32_t* value);
+void Pack_uint64_t(ODK_Message* message, const uint64_t* value);
+void PackArray(ODK_Message* message, const uint8_t* base, size_t size);
+void Pack_OEMCrypto_Substring(ODK_Message* message,
+ const OEMCrypto_Substring* obj);
-/*
- * Description:
- * Point |msg| to stack-array |blk|.
- * |blk| is guaranteed large enough to hold a |Message| struct.
- * |blk| cannot be used in the same scope as a variable name.
- * |msg| points to valid memory in the same scope |AllocateMessage| is used.
- * Parameters:
- * msg: pointer to pointer to |Message| struct
- * blk: variable name for stack-array
- */
-#define AllocateMessage(msg, blk) \
- uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; \
- *(msg) = (Message*)(blk)
-
-typedef struct _Message Message;
-
-typedef enum {
- MESSAGE_STATUS_OK,
- MESSAGE_STATUS_UNKNOWN_ERROR,
- MESSAGE_STATUS_OVERFLOW_ERROR,
- MESSAGE_STATUS_UNDERFLOW_ERROR,
- MESSAGE_STATUS_PARSE_ERROR,
- MESSAGE_STATUS_NULL_POINTER_ERROR,
- MESSAGE_STATUS_API_VALUE_ERROR
-} MessageStatus;
-
-bool ValidMessage(Message* message);
-
-void Pack_enum(Message* message, int value);
-void Pack_bool(Message* message, const bool* value);
-void Pack_uint16_t(Message* message, const uint16_t* value);
-void Pack_uint32_t(Message* message, const uint32_t* value);
-void Pack_uint64_t(Message* message, const uint64_t* value);
-void PackArray(Message* message, const uint8_t* base, size_t size);
-void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj);
-
-int Unpack_enum(Message* message);
-void Unpack_bool(Message* message, bool* value);
-void Unpack_uint16_t(Message* message, uint16_t* value);
-void Unpack_uint32_t(Message* message, uint32_t* value);
-void Unpack_uint64_t(Message* message, uint64_t* value);
-void UnpackArray(Message* message, uint8_t* address,
+int Unpack_enum(ODK_Message* message);
+void Unpack_bool(ODK_Message* message, bool* value);
+void Unpack_uint8_t(ODK_Message* message, uint8_t* value);
+void Unpack_uint16_t(ODK_Message* message, uint16_t* value);
+void Unpack_uint32_t(ODK_Message* message, uint32_t* value);
+void Unpack_uint64_t(ODK_Message* message, uint64_t* value);
+void UnpackArray(ODK_Message* message, uint8_t* address,
size_t size); /* copy out */
-void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj);
-
-/*
- * Initialize a message structure to reference a separate buffer. The caller
- * is responsible for ensuring that the buffer remains allocated for the
- * lifetime of the message.
- */
-void InitMessage(Message* message, uint8_t* buffer, size_t capacity);
-
-/*
- * Reset an existing the message to an empty state
- */
-void ResetMessage(Message* message);
-uint8_t* GetBase(Message* message);
-size_t GetCapacity(Message* message);
-size_t GetSize(Message* message);
-void SetSize(Message* message, size_t size);
-MessageStatus GetStatus(Message* message);
-void SetStatus(Message* message, MessageStatus status);
-size_t GetOffset(Message* message);
-
-size_t SizeOfMessageStruct();
+void Unpack_OEMCrypto_Substring(ODK_Message* message, OEMCrypto_Substring* obj);
#ifdef __cplusplus
} // extern "C"
diff --git a/oemcrypto/odk/test/fuzzing/Android.bp b/oemcrypto/odk/test/fuzzing/Android.bp
index d7390f9..3b8fe6d 100644
--- a/oemcrypto/odk/test/fuzzing/Android.bp
+++ b/oemcrypto/odk/test/fuzzing/Android.bp
@@ -2,6 +2,18 @@
// source code may only be used and distributed under the Widevine
// License Agreement.
+// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
+// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+// DEPENDING ON IT IN YOUR PROJECT. ***
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "vendor_widevine_license"
+ // to get the below license kinds:
+ // legacy_by_exception_only (by exception only)
+ default_applicable_licenses: ["vendor_widevine_license"],
+}
+
cc_defaults {
name: "odk_fuzz_library_defaults",
srcs: [
@@ -165,4 +177,4 @@ cc_fuzz {
],
defaults: ["odk_fuzz_library_defaults"],
proprietary: true,
-}
\ No newline at end of file
+}
diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp
index 522c2b8..78519cb 100644
--- a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp
+++ b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp
@@ -9,6 +9,18 @@
// ----------------------------------------------------------------
// Builds libwv_odk.so, The ODK shared Library (libwv_odk) is used
// by the OEMCrypto unit tests to generate corpus for ODK fuzz scrips.
+// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE
+// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE
+// DEPENDING ON IT IN YOUR PROJECT. ***
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "vendor_widevine_license"
+ // to get the below license kinds:
+ // legacy_by_exception_only (by exception only)
+ default_applicable_licenses: ["vendor_widevine_license"],
+}
+
cc_library_shared {
name: "libwv_odk_corpus_generator",
include_dirs: [
diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp
index 548d38a..dea3674 100644
--- a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp
+++ b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp
@@ -18,6 +18,14 @@
'../src',
'../kdo/include',
],
+ 'cflags': [
+ # TODO(b/172518513): Remove this
+ '-Wno-error=cast-qual',
+ ],
+ 'cflags_c': [
+ # TODO(b/159354894): Remove this
+ '-Wno-error=bad-function-cast',
+ ],
'cflags_cc': [
'-std=c++11',
'-g3',
diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp
index 7f6187c..cf1be5f 100644
--- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp
+++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp
@@ -6,6 +6,7 @@
#include "odk.h"
namespace oemcrypto_core_message {
+using features::CoreMessageFeatures;
bool convert_byte_to_valid_boolean(const bool* in) {
const char* buf = reinterpret_cast(in);
@@ -67,8 +68,8 @@ OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message,
return ODK_ParseLicense(message, SIZE_MAX, core_message_length,
static_cast(a->initial_license_load),
static_cast(a->usage_entry_present),
- a->request_hash, &a->timer_limits, &a->clock_values,
- nonce_values, parsed_lic);
+ &a->timer_limits, &a->clock_values, nonce_values,
+ parsed_lic);
}
OEMCryptoResult odk_deserialize_RenewalResponse(
@@ -99,11 +100,9 @@ OEMCryptoResult odk_deserialize_RenewalResponse(
// odk_kdo method, we call Unpack_ODK_PreparedRenewalRequest private method.
// playback_time cannot be captured from publicly exposed API
// ODK_ParseRenewal.
- uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
- Message* msg = reinterpret_cast(blk);
- InitMessage(msg, const_cast(buf), len);
- SetSize(msg, len);
- Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg);
+ ODK_Message msg = ODK_Message_Create(const_cast(buf), len);
+ ODK_Message_SetSize(&msg, len);
+ Unpack_ODK_PreparedRenewalRequest(&msg, renewal_msg);
return OEMCrypto_SUCCESS;
}
@@ -124,7 +123,8 @@ bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args,
std::string core_request_sha_256(
reinterpret_cast(args->request_hash), ODK_SHA256_HASH_SIZE);
return serialize::CreateCoreLicenseResponse(
- parsed_lic, core_request, core_request_sha_256, oemcrypto_core_message);
+ CoreMessageFeatures::kDefaultFeatures, parsed_lic, core_request,
+ core_request_sha_256, oemcrypto_core_message);
}
bool kdo_serialize_RenewalResponse(
@@ -136,7 +136,8 @@ bool kdo_serialize_RenewalResponse(
nonce_values.api_minor_version, nonce_values.api_major_version,
nonce_values.nonce, nonce_values.session_id, renewal_msg.playback_time};
return serialize::CreateCoreRenewalResponse(
- core_request, args->timer_limits.initial_renewal_duration_seconds,
+ CoreMessageFeatures::kDefaultFeatures, core_request,
+ args->timer_limits.initial_renewal_duration_seconds,
oemcrypto_core_message);
}
@@ -153,7 +154,8 @@ bool kdo_serialize_ProvisioningResponse(
nonce_values.nonce, nonce_values.session_id,
std::string(reinterpret_cast(args->device_id),
args->device_id_length)};
- return serialize::CreateCoreProvisioningResponse(parsed_prov, core_request,
- oemcrypto_core_message);
+ return serialize::CreateCoreProvisioningResponse(
+ CoreMessageFeatures::kDefaultFeatures, parsed_prov, core_request,
+ oemcrypto_core_message);
}
} // namespace oemcrypto_core_message
diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h
index 34fe8fc..0f45467 100644
--- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h
+++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h
@@ -7,6 +7,7 @@
#include
#include
+#include "core_message_features.h"
#include "core_message_serialize.h"
#include "fuzzing/odk_fuzz_structs.h"
#include "odk_attributes.h"
diff --git a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp
index 5249253..4ad8ca4 100644
--- a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp
+++ b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp
@@ -6,13 +6,15 @@
#include
#include "fuzzing/odk_fuzz_helper.h"
+#include "odk_attributes.h"
namespace oemcrypto_core_message {
// The custom mutator: Ensure that each input can be deserialized properly
// by ODK function after mutation.
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
- size_t max_size, unsigned int seed) {
+ size_t max_size,
+ unsigned int seed UNUSED) {
const size_t kProvisioningResponseArgsSize =
sizeof(ODK_ParseProvisioning_Args);
if (size < kProvisioningResponseArgsSize) {
diff --git a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp
index d6a9dd4..2502ab8 100644
--- a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp
+++ b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp
@@ -6,13 +6,15 @@
#include
#include "fuzzing/odk_fuzz_helper.h"
+#include "odk_attributes.h"
namespace oemcrypto_core_message {
// The custom mutator: Ensure that each input can be deserialized properly
// by ODK function after mutation.
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size,
- size_t max_size, unsigned int seed) {
+ size_t max_size,
+ unsigned int seed UNUSED) {
const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args);
if (size < kRenewalResponseArgsSize) {
return 0;
diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp
index 93e9230..d1a817d 100644
--- a/oemcrypto/odk/test/odk_test.cpp
+++ b/oemcrypto/odk/test/odk_test.cpp
@@ -4,13 +4,12 @@
#include "odk.h"
-#include // TODO(b/147944591): use this one? Or odk_endian.h?
-
#include
#include
#include "OEMCryptoCENCCommon.h"
#include "core_message_deserialize.h"
+#include "core_message_features.h"
#include "core_message_serialize.h"
#include "core_message_types.h"
#include "gtest/gtest.h"
@@ -29,12 +28,34 @@ using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage;
using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage;
+using oemcrypto_core_message::features::CoreMessageFeatures;
+
using oemcrypto_core_message::serialize::CreateCoreLicenseResponse;
using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse;
using oemcrypto_core_message::serialize::CreateCoreRenewalResponse;
constexpr uint32_t kExtraPayloadSize = 128u;
+/* Used to parameterize tests by version number. The request is given one
+ * version number, and we will expect the response to have another version
+ * number. */
+struct VersionParameters {
+ uint32_t maximum_major_version;
+ uint16_t request_major_version;
+ uint16_t request_minor_version;
+ uint16_t response_major_version;
+ uint16_t response_minor_version;
+};
+
+// This function is called by GTest when a parameterized test fails in order
+// to log the parameter used for the failing test.
+void PrintTo(const VersionParameters& p, std::ostream* os) {
+ *os << "max=v" << p.maximum_major_version << ", request = v"
+ << p.request_major_version << "." << p.request_minor_version
+ << ", response = v" << p.response_major_version << "."
+ << p.response_minor_version;
+}
+
template
void ValidateRequest(uint32_t message_type,
const std::vector& extra_fields,
@@ -113,12 +134,13 @@ void ValidateRequest(uint32_t message_type,
* G: kdo serializer
*/
template
-void ValidateResponse(ODK_CoreMessage* core_message,
+void ValidateResponse(const VersionParameters& versions,
+ ODK_CoreMessage* core_message,
const std::vector& extra_fields,
const F& odk_parse_func, const G& kdo_prepare_func) {
T t = {};
- t.api_minor_version = core_message->nonce_values.api_minor_version;
- t.api_major_version = core_message->nonce_values.api_major_version;
+ t.api_major_version = versions.request_major_version;
+ t.api_minor_version = versions.request_minor_version;
t.nonce = core_message->nonce_values.nonce;
t.session_id = core_message->nonce_values.session_id;
@@ -132,12 +154,15 @@ void ValidateResponse(ODK_CoreMessage* core_message,
EXPECT_EQ(OEMCrypto_SUCCESS, ODK_IterFields(ODK_READ, zero, buf_size,
&bytes_read, extra_fields));
- // parse buf with odk
- EXPECT_EQ(OEMCrypto_SUCCESS, odk_parse_func(buf, buf_size));
+ // Parse buf with odk
+ const OEMCryptoResult parse_result = odk_parse_func(buf, buf_size);
+ EXPECT_EQ(OEMCrypto_SUCCESS, parse_result);
size_t size_out = 0;
- ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out,
- extra_fields);
+ if (parse_result != OEMCrypto_SUCCESS) {
+ ODK_IterFields(ODK_FieldMode::ODK_DUMP, buf, buf_size, &size_out,
+ extra_fields);
+ }
// serialize odk output to oemcrypto_core_message
std::string oemcrypto_core_message;
@@ -178,15 +203,15 @@ TEST(OdkTest, SerializeFieldsStress) {
std::srand(0);
size_t total_size = 0;
for (int i = 0; i < n; i++) {
- fields[i].type = static_cast(std::rand() %
- static_cast(ODK_NUMTYPES));
+ fields[i].type = static_cast(
+ std::rand() % static_cast(ODK_LAST_STRESSABLE_TYPE));
fields[i].value = malloc(ODK_AllocSize(fields[i].type));
fields[i].name = "stress";
total_size += ODK_FieldLength(fields[i].type);
}
uint8_t* buf = new uint8_t[total_size]{};
- for (int i = 0; i < total_size; i++) {
+ for (size_t i = 0; i < total_size; i++) {
buf[i] = std::rand() & 0xff;
}
@@ -251,7 +276,6 @@ TEST(OdkTest, NullResponseTest) {
constexpr size_t message_size = 64;
uint8_t message[message_size] = {0};
size_t core_message_length = message_size;
- uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {0};
ODK_TimerLimits timer_limits;
ODK_ParsedLicense parsed_license;
ODK_NonceValues nonce_values;
@@ -260,30 +284,26 @@ TEST(OdkTest, NullResponseTest) {
memset(&clock_values, 0, sizeof(clock_values));
// Assert that nullptr does not cause a core dump.
- EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
- ODK_ParseLicense(message, message_size, core_message_length, true,
- true, request_hash, &timer_limits, &clock_values,
- &nonce_values, nullptr));
- EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
- ODK_ParseLicense(message, message_size, core_message_length, true,
- true, request_hash, &timer_limits, &clock_values,
- nullptr, &parsed_license));
- EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
- ODK_ParseLicense(message, message_size, core_message_length, true,
- true, request_hash, &timer_limits, nullptr,
- &nonce_values, &parsed_license));
- EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
- ODK_ParseLicense(message, message_size, core_message_length, true,
- true, request_hash, nullptr, &clock_values,
- &nonce_values, &parsed_license));
- EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
- ODK_ParseLicense(message, message_size, core_message_length, true,
- true, nullptr, &timer_limits, &clock_values,
- &nonce_values, &parsed_license));
+ EXPECT_EQ(
+ ODK_ERROR_CORE_MESSAGE,
+ ODK_ParseLicense(message, message_size, core_message_length, true, true,
+ &timer_limits, &clock_values, &nonce_values, nullptr));
+ EXPECT_EQ(
+ ODK_ERROR_CORE_MESSAGE,
+ ODK_ParseLicense(message, message_size, core_message_length, true, true,
+ &timer_limits, &clock_values, nullptr, &parsed_license));
+ EXPECT_EQ(
+ ODK_ERROR_CORE_MESSAGE,
+ ODK_ParseLicense(message, message_size, core_message_length, true, true,
+ &timer_limits, nullptr, &nonce_values, &parsed_license));
+ EXPECT_EQ(
+ ODK_ERROR_CORE_MESSAGE,
+ ODK_ParseLicense(message, message_size, core_message_length, true, true,
+ nullptr, &clock_values, &nonce_values, &parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE,
ODK_ParseLicense(nullptr, message_size, core_message_length, true,
- true, request_hash, &timer_limits, &clock_values,
- &nonce_values, &parsed_license));
+ true, &timer_limits, &clock_values, &nonce_values,
+ &parsed_license));
constexpr uint64_t system_time = 0;
uint64_t timer_value = 0;
@@ -479,7 +499,7 @@ TEST(OdkTest, ProvisionRequestRoundtrip) {
TEST(OdkTest, ParseLicenseErrorNonce) {
ODK_LicenseResponseParams params;
- ODK_SetDefaultLicenseResponseParams(¶ms);
+ ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
@@ -488,7 +508,7 @@ TEST(OdkTest, ParseLicenseErrorNonce) {
params.core_message.nonce_values.nonce = 0;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
- params.usage_entry_present, params.request_hash, &(params.timer_limits),
+ params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(OEMCrypto_ERROR_INVALID_NONCE, err);
@@ -497,7 +517,7 @@ TEST(OdkTest, ParseLicenseErrorNonce) {
TEST(OdkTest, ParseLicenseErrorUsageEntry) {
ODK_LicenseResponseParams params;
- ODK_SetDefaultLicenseResponseParams(¶ms);
+ ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION);
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
@@ -505,25 +525,59 @@ TEST(OdkTest, ParseLicenseErrorUsageEntry) {
params.usage_entry_present = false;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
- params.usage_entry_present, params.request_hash, &(params.timer_limits),
+ params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
delete[] buf;
}
-TEST(OdkTest, ParseLicenseErrorRequestHash) {
+TEST(OdkTest, ParseLicenseNullSubstring) {
ODK_LicenseResponseParams params;
- ODK_SetDefaultLicenseResponseParams(¶ms);
+ ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION);
+ params.parsed_license.srm_restriction_data.offset = 0;
+ params.parsed_license.srm_restriction_data.length = 0;
+ uint8_t* buf = nullptr;
+ uint32_t buf_size = 0;
+ ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
+ &buf_size);
+ OEMCryptoResult result = ODK_ParseLicense(
+ buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
+ params.usage_entry_present, &(params.timer_limits),
+ &(params.clock_values), &(params.core_message.nonce_values),
+ &(params.parsed_license));
+ EXPECT_EQ(OEMCrypto_SUCCESS, result);
+ delete[] buf;
+}
+
+TEST(OdkTest, ParseLicenseErrorSubstringOffset) {
+ // offset out of range
+ ODK_LicenseResponseParams params;
+ ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION);
+ params.parsed_license.enc_mac_keys_iv.offset = 1024;
uint8_t* buf = nullptr;
uint32_t buf_size = 0;
ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
&buf_size);
- // temporarily mess up with request hash
- params.request_hash[0] = 0xff;
OEMCryptoResult err = ODK_ParseLicense(
buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
- params.usage_entry_present, params.request_hash, &(params.timer_limits),
+ params.usage_entry_present, &(params.timer_limits),
+ &(params.clock_values), &(params.core_message.nonce_values),
+ &(params.parsed_license));
+ EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
+ delete[] buf;
+
+ // offset + length out of range
+ err = OEMCrypto_SUCCESS;
+ ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION);
+ params.parsed_license.enc_mac_keys_iv.length = buf_size;
+ buf = nullptr;
+ buf_size = 0;
+ ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf,
+ &buf_size);
+ err = ODK_ParseLicense(
+ buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load,
+ params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err);
@@ -562,17 +616,37 @@ TEST(OdkTest, ParsePrivisioningErrorDeviceId) {
delete[] buf;
}
+class OdkVersionTest : public ::testing::Test,
+ public ::testing::WithParamInterface {
+ protected:
+ template
+ void SetRequestVersion(P* params) {
+ params->core_message.nonce_values.api_major_version =
+ GetParam().response_major_version;
+ params->core_message.nonce_values.api_minor_version =
+ GetParam().response_minor_version;
+ features_ =
+ CoreMessageFeatures::DefaultFeatures(GetParam().maximum_major_version);
+ }
+ CoreMessageFeatures features_;
+};
+
// Serialize and de-serialize license response
-TEST(OdkTest, LicenseResponseRoundtrip) {
+TEST_P(OdkVersionTest, LicenseResponseRoundtrip) {
ODK_LicenseResponseParams params;
- ODK_SetDefaultLicenseResponseParams(¶ms);
- // save a copy of params.request_hash as it will be zero out during the test
+ ODK_SetDefaultLicenseResponseParams(¶ms,
+ GetParam().response_major_version);
+ SetRequestVersion(¶ms);
+ // For v17, we do not use the hash to verify the request. However, the server
+ // needs to be backwards compatible, so it still needs to pass the hash into
+ // CreateCoreLiceseseResponse below. Save a copy of params.request_hash as it
+ // will be zero out during the test
uint8_t request_hash_read[ODK_SHA256_HASH_SIZE];
memcpy(request_hash_read, params.request_hash, sizeof(request_hash_read));
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
return ODK_ParseLicense(
buf, size + kExtraPayloadSize, size, params.initial_license_load,
- params.usage_entry_present, request_hash_read, &(params.timer_limits),
+ params.usage_entry_present, &(params.timer_limits),
&(params.clock_values), &(params.core_message.nonce_values),
&(params.parsed_license));
};
@@ -581,18 +655,19 @@ TEST(OdkTest, LicenseResponseRoundtrip) {
sizeof(request_hash_read));
auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request,
std::string* oemcrypto_core_message) {
- return CreateCoreLicenseResponse(params.parsed_license, core_request,
- request_hash_string,
+ return CreateCoreLicenseResponse(features_, params.parsed_license,
+ core_request, request_hash_string,
oemcrypto_core_message);
};
- ValidateResponse(&(params.core_message),
+ ValidateResponse(GetParam(), &(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
-TEST(OdkTest, RenewalResponseRoundtrip) {
+TEST_P(OdkVersionTest, RenewalResponseRoundtrip) {
ODK_RenewalResponseParams params;
ODK_SetDefaultRenewalResponseParams(¶ms);
+ SetRequestVersion(¶ms);
const uint64_t playback_clock = params.playback_clock;
const uint64_t renewal_duration = params.renewal_duration;
auto odk_parse_func = [&](const uint8_t* buf, size_t size) {
@@ -611,17 +686,18 @@ TEST(OdkTest, RenewalResponseRoundtrip) {
auto kdo_prepare_func = [&](ODK_RenewalRequest& core_request,
std::string* oemcrypto_core_message) {
core_request.playback_time_seconds = playback_clock;
- return CreateCoreRenewalResponse(core_request, renewal_duration,
+ return CreateCoreRenewalResponse(features_, core_request, renewal_duration,
oemcrypto_core_message);
};
- ValidateResponse(&(params.core_message),
+ ValidateResponse(GetParam(), &(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
-TEST(OdkTest, ProvisionResponseRoundtrip) {
+TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) {
ODK_ProvisioningResponseParams params;
ODK_SetDefaultProvisioningResponseParams(¶ms);
+ SetRequestVersion(¶ms);
// save a copy of params.device_id as it will be zero out during the test
const uint32_t device_id_length = params.device_id_length;
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0};
@@ -637,14 +713,61 @@ TEST(OdkTest, ProvisionResponseRoundtrip) {
std::string* oemcrypto_core_message) {
core_request.device_id.assign(reinterpret_cast(device_id),
device_id_length);
- return CreateCoreProvisioningResponse(params.parsed_provisioning,
+ return CreateCoreProvisioningResponse(features_, params.parsed_provisioning,
core_request, oemcrypto_core_message);
};
- ValidateResponse(&(params.core_message),
+ ValidateResponse(GetParam(), &(params.core_message),
params.extra_fields, odk_parse_func,
kdo_prepare_func);
}
+// If the minor version is positive, we can test an older minor version.
+const uint16_t kOldMinor = ODK_MINOR_VERSION > 0 ? ODK_MINOR_VERSION - 1 : 0;
+// Similarly, if this isn't the first major version, we can test an older major
+// version.
+// TODO(b/163416999): Remove it in the future. This will be unecessarily
+// complicated after we upgrade to version 17.
+const uint16_t kOldMajor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION
+ ? ODK_MAJOR_VERSION - 1
+ : ODK_FIRST_VERSION;
+// If there is an older major, then we should accept any minor version.
+// Otherwise, this test won't make sense and we should just use a minor of 0.
+const uint16_t kOldMajorMinor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? 42 : 0;
+
+// List of major and minor versions to test.
+std::vector TestCases() {
+ std::vector test_cases{
+ // Fields: maximum major version,
+ // request major, request minor, response major, response minor,
+ {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION,
+ ODK_MAJOR_VERSION, ODK_MINOR_VERSION},
+ {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, ODK_MINOR_VERSION + 1,
+ ODK_MAJOR_VERSION, ODK_MINOR_VERSION},
+ {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, kOldMinor, ODK_MAJOR_VERSION,
+ kOldMinor},
+ {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION, 0, ODK_MAJOR_VERSION, 0},
+ {ODK_MAJOR_VERSION, ODK_MAJOR_VERSION + 1, 42, ODK_MAJOR_VERSION,
+ ODK_MINOR_VERSION},
+ {ODK_MAJOR_VERSION, kOldMajor, 0, kOldMajor, 0},
+ {ODK_MAJOR_VERSION, kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor},
+ // If the server is restricted to v16, then the response can be at
+ // most 16.5
+ {16, ODK_MAJOR_VERSION, ODK_MINOR_VERSION, 16, 5},
+ // Here are some known good versions. Make extra sure they work.
+ {16, 16, 3, 16, 3},
+ {16, 16, 4, 16, 4},
+ {16, 16, 5, 16, 5},
+ {17, 16, 3, 16, 3},
+ {17, 16, 4, 16, 4},
+ {17, 16, 5, 16, 5},
+ {17, 17, 0, 17, 0},
+ };
+ return test_cases;
+}
+
+INSTANTIATE_TEST_SUITE_P(OdkVersionTests, OdkVersionTest,
+ ::testing::ValuesIn(TestCases()));
+
TEST(OdkSizeTest, LicenseRequest) {
uint8_t* message = nullptr;
size_t message_length = 0;
@@ -703,7 +826,7 @@ TEST(OdkSizeTest, ReleaseRequest) {
&core_message_length, &nonce_values,
&clock_values, system_time_seconds));
// Release requests do not have a core message.
- EXPECT_GE(core_message_length, 0);
+ EXPECT_GE(core_message_length, 0u);
}
TEST(OdkSizeTest, ProvisioningRequest) {
diff --git a/oemcrypto/odk/test/odk_test_helper.cpp b/oemcrypto/odk/test/odk_test_helper.cpp
index 50f3a1a..c1cf465 100644
--- a/oemcrypto/odk/test/odk_test_helper.cpp
+++ b/oemcrypto/odk/test/odk_test_helper.cpp
@@ -4,8 +4,6 @@
#include "odk_test_helper.h"
-#include
-
#include
#include
#include
@@ -15,13 +13,14 @@
#include "OEMCryptoCENCCommon.h"
#include "gtest/gtest.h"
+#include "odk_endian.h"
#include "odk_structs.h"
#include "odk_structs_priv.h"
namespace wvodk_test {
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
- uint32_t message_type) {
+ ODK_MessageType message_type) {
ASSERT_TRUE(core_message != nullptr);
core_message->message_type = message_type;
core_message->message_length = 0;
@@ -31,7 +30,8 @@ void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
core_message->nonce_values.session_id = 0xcafebabe;
}
-void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) {
+void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
+ uint32_t odk_major_version) {
ODK_SetDefaultCoreFields(&(params->core_message), ODK_License_Response_Type);
params->initial_license_load = true;
params->usage_entry_present = true;
@@ -51,6 +51,29 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) {
.total_playback_duration_seconds = 12,
.initial_renewal_duration_seconds = 13,
},
+ .watermarking = 0,
+ .dtcp2_required = {.dtcp2_required = 0,
+ .cmi_descriptor_0 =
+ {
+ .id = 0,
+ .extension = 0,
+ .length = 1,
+ .data = 0,
+ },
+ .cmi_descriptor_1 =
+ {
+ .id = 1,
+ .extension = 0,
+ .length = 3,
+ .data = {0, 0, 0},
+ },
+ .cmi_descriptor_2 =
+ {
+ .id = 2,
+ .extension = 0,
+ .length = 3,
+ .data = {0, 0, 0},
+ }},
.key_array_length = 3,
.key_array =
{
@@ -87,10 +110,10 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) {
".srm_restriction_data"},
{ODK_UINT32, &(params->parsed_license.license_type), ".license_type"},
{ODK_UINT32, &(params->parsed_license.nonce_required), ".nonce_required"},
- {ODK_UINT32,
+ {ODK_BOOL,
&(params->parsed_license.timer_limits.soft_enforce_rental_duration),
".soft_enforce_rental_duration"},
- {ODK_UINT32,
+ {ODK_BOOL,
&(params->parsed_license.timer_limits.soft_enforce_playback_duration),
".soft_enforce_playback_duration"},
{ODK_UINT64,
@@ -105,37 +128,132 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) {
{ODK_UINT64,
&(params->parsed_license.timer_limits.initial_renewal_duration_seconds),
".initial_renewal_duration_seconds"},
- {ODK_UINT32, &(params->parsed_license.key_array_length),
- ".key_array_length"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_id), ".key_id"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data_iv),
- ".key_data_iv"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data),
- ".key_data"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control_iv),
- ".key_control_iv"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control),
- ".key_control"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_id), ".key_id"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data_iv),
- ".key_data_iv"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data),
- ".key_data"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control_iv),
- ".key_control_iv"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control),
- ".key_control"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_id), ".key_id"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data_iv),
- ".key_data_iv"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data),
- ".key_data"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control_iv),
- ".key_control_iv"},
- {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control),
- ".key_control"},
- {ODK_HASH, params->request_hash, ".request_hash"},
};
+ if (odk_major_version >= 17) {
+ params->extra_fields.push_back(
+ {ODK_UINT32, &(params->parsed_license.watermarking), ".watermarking"});
+ params->extra_fields.push_back(
+ {ODK_UINT8, &(params->parsed_license.dtcp2_required.dtcp2_required),
+ ".dtcp2_required"});
+ if (params->parsed_license.dtcp2_required.dtcp2_required) {
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_0.id),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_0.extension),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT16,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_0.length),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_0.data),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_1.id),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_1.extension),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT16,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_1.length),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[0]),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[1]),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_1.data[2]),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_2.id),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_2.extension),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT16,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_2.length),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[0]),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[1]),
+ ".cmi_descriptor_data"});
+ params->extra_fields.push_back(
+ {ODK_UINT8,
+ &(params->parsed_license.dtcp2_required.cmi_descriptor_2.data[2]),
+ ".cmi_descriptor_data"});
+ }
+ }
+ params->extra_fields.push_back({ODK_UINT32,
+ &(params->parsed_license.key_array_length),
+ ".key_array_length"});
+ params->extra_fields.push_back({ODK_SUBSTRING,
+ &(params->parsed_license.key_array[0].key_id),
+ ".key_id"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data_iv),
+ ".key_data_iv"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_data),
+ ".key_data"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control_iv),
+ ".key_control_iv"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[0].key_control),
+ ".key_control"});
+ params->extra_fields.push_back({ODK_SUBSTRING,
+ &(params->parsed_license.key_array[1].key_id),
+ ".key_id"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data_iv),
+ ".key_data_iv"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_data),
+ ".key_data"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control_iv),
+ ".key_control_iv"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[1].key_control),
+ ".key_control"});
+ params->extra_fields.push_back({ODK_SUBSTRING,
+ &(params->parsed_license.key_array[2].key_id),
+ ".key_id"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data_iv),
+ ".key_data_iv"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_data),
+ ".key_data"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control_iv),
+ ".key_control_iv"});
+ params->extra_fields.push_back(
+ {ODK_SUBSTRING, &(params->parsed_license.key_array[2].key_control),
+ ".key_control"});
+ if (odk_major_version == 16) {
+ params->extra_fields.push_back(
+ {ODK_HASH, params->request_hash, ".request_hash"});
+ }
}
void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) {
@@ -157,7 +275,7 @@ void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params) {
.initial_renewal_duration_seconds = 300,
};
params->clock_values = {
- .time_of_license_signed =
+ .time_of_license_request_signed =
params->system_time - params->playback_clock - 42,
.time_of_first_decrypt = params->system_time - params->playback_clock,
.time_of_last_decrypt = params->system_time - params->playback_clock,
@@ -197,12 +315,16 @@ void ODK_SetDefaultProvisioningResponseParams(
size_t ODK_FieldLength(ODK_FieldType type) {
switch (type) {
+ case ODK_UINT8:
+ return sizeof(uint8_t);
case ODK_UINT16:
return sizeof(uint16_t);
case ODK_UINT32:
return sizeof(uint32_t);
case ODK_UINT64:
return sizeof(uint64_t);
+ case ODK_BOOL: // Booleans are stored in the message as 32 bit ints.
+ return sizeof(uint32_t);
case ODK_SUBSTRING:
return sizeof(uint32_t) + sizeof(uint32_t);
case ODK_DEVICEID:
@@ -226,25 +348,38 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) {
return ODK_ERROR_CORE_MESSAGE;
}
switch (field->type) {
+ case ODK_UINT8: {
+ memcpy(buf, field->value, sizeof(uint8_t));
+ break;
+ }
case ODK_UINT16: {
- const uint16_t u16 = htobe16(*static_cast(field->value));
+ const uint16_t u16 =
+ oemcrypto_htobe16(*static_cast(field->value));
memcpy(buf, &u16, sizeof(u16));
break;
}
case ODK_UINT32: {
- const uint32_t u32 = htobe32(*static_cast(field->value));
+ const uint32_t u32 =
+ oemcrypto_htobe32(*static_cast(field->value));
memcpy(buf, &u32, sizeof(u32));
break;
}
case ODK_UINT64: {
- const uint64_t u64 = htobe64(*static_cast(field->value));
+ const uint64_t u64 =
+ oemcrypto_htobe64(*static_cast(field->value));
memcpy(buf, &u64, sizeof(u64));
break;
}
+ case ODK_BOOL: {
+ const bool value = *static_cast(field->value);
+ const uint32_t u32 = oemcrypto_htobe32(value ? 1 : 0);
+ memcpy(buf, &u32, sizeof(u32));
+ break;
+ }
case ODK_SUBSTRING: {
OEMCrypto_Substring* s = static_cast(field->value);
- const uint32_t off = htobe32(s->offset);
- const uint32_t len = htobe32(s->length);
+ const uint32_t off = oemcrypto_htobe32(s->offset);
+ const uint32_t len = oemcrypto_htobe32(s->length);
memcpy(buf, &off, sizeof(off));
memcpy(buf + sizeof(off), &len, sizeof(len));
break;
@@ -269,22 +404,33 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf,
return ODK_ERROR_CORE_MESSAGE;
}
switch (field->type) {
+ case ODK_UINT8: {
+ memcpy(field->value, buf, sizeof(uint8_t));
+ break;
+ }
case ODK_UINT16: {
memcpy(field->value, buf, sizeof(uint16_t));
uint16_t* u16p = static_cast(field->value);
- *u16p = be16toh(*u16p);
+ *u16p = oemcrypto_be16toh(*u16p);
break;
}
case ODK_UINT32: {
memcpy(field->value, buf, sizeof(uint32_t));
uint32_t* u32p = static_cast(field->value);
- *u32p = be32toh(*u32p);
+ *u32p = oemcrypto_be32toh(*u32p);
break;
}
case ODK_UINT64: {
memcpy(field->value, buf, sizeof(uint64_t));
uint64_t* u64p = static_cast(field->value);
- *u64p = be64toh(*u64p);
+ *u64p = oemcrypto_be64toh(*u64p);
+ break;
+ }
+ case ODK_BOOL: {
+ uint32_t value;
+ memcpy(&value, buf, sizeof(uint32_t));
+ value = oemcrypto_be32toh(value);
+ *static_cast(field->value) = (value != 0);
break;
}
case ODK_SUBSTRING: {
@@ -293,8 +439,8 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf,
uint32_t len = 0;
memcpy(&off, buf, sizeof(off));
memcpy(&len, buf + sizeof(off), sizeof(len));
- s->offset = be32toh(off);
- s->length = be32toh(len);
+ s->offset = oemcrypto_be32toh(off);
+ s->length = oemcrypto_be32toh(len);
break;
}
case ODK_DEVICEID:
@@ -316,18 +462,26 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf,
return ODK_ERROR_CORE_MESSAGE;
}
switch (field->type) {
- case ODK_UINT16: {
- uint16_t val;
- memcpy(&val, buf, sizeof(uint16_t));
- val = be16toh(val);
+ case ODK_UINT8: {
+ uint8_t val;
+ memcpy(&val, buf, sizeof(uint8_t));
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
<< "\n";
break;
}
+ case ODK_UINT16: {
+ uint16_t val;
+ memcpy(&val, buf, sizeof(uint16_t));
+ val = oemcrypto_be16toh(val);
+ std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
+ << "\n";
+ break;
+ }
+ case ODK_BOOL:
case ODK_UINT32: {
uint32_t val;
memcpy(&val, buf, sizeof(uint32_t));
- val = be32toh(val);
+ val = oemcrypto_be32toh(val);
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
<< "\n";
break;
@@ -335,7 +489,7 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf,
case ODK_UINT64: {
uint64_t val;
memcpy(&val, buf, sizeof(uint64_t));
- val = be64toh(val);
+ val = oemcrypto_be64toh(val);
std::cerr << field->name << ": " << val << " = 0x" << std::hex << val
<< "\n";
break;
@@ -410,9 +564,30 @@ OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* buf,
return OEMCrypto_SUCCESS;
}
+std::vector ODK_MakeTotalFields(
+ const std::vector& extra_fields, ODK_CoreMessage* core_message) {
+ std::vector total_fields = {
+ {ODK_UINT32, &(core_message->message_type), "message_type"},
+ {ODK_UINT32, &(core_message->message_length), "message_size"},
+ {ODK_UINT16, &(core_message->nonce_values.api_minor_version),
+ "api_minor_version"},
+ {ODK_UINT16, &(core_message->nonce_values.api_major_version),
+ "api_major_version"},
+ {ODK_UINT32, &(core_message->nonce_values.nonce), "nonce"},
+ {ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"},
+ };
+ total_fields.insert(total_fields.end(), extra_fields.begin(),
+ extra_fields.end());
+ return total_fields;
+}
+
+// Expect the two buffers of size n to be equal. If not, dump the messages.
void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
const std::vector& fields) {
if (memcmp(s1, s2, n) != 0) {
+ ODK_CoreMessage core_message;
+ std::vector total_fields =
+ ODK_MakeTotalFields(fields, &core_message);
const void* buffers[] = {s1, s2};
for (int i = 0; i < 2; i++) {
char _tmp[] = "/tmp/fileXXXXXX";
@@ -427,11 +602,12 @@ void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n,
std::fstream out(tmp, std::ios::out | std::ios::binary);
out.write(static_cast(buffers[i]), n);
out.close();
- std::cerr << "buffer " << i << " dumped to " << tmp << std::endl;
+ std::cerr << std::endl
+ << "Message buffer " << i << " dumped to " << tmp << std::endl;
size_t bytes_written;
uint8_t* buf =
const_cast(reinterpret_cast(buffers[i]));
- ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, fields);
+ ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, total_fields);
}
FAIL();
}
@@ -454,24 +630,9 @@ void ODK_BuildMessageBuffer(ODK_CoreMessage* core_message,
uint8_t** buf, uint32_t* buf_size) {
ASSERT_TRUE(core_message != nullptr);
ASSERT_TRUE(buf_size != nullptr);
- std::vector total_fields = {
- {ODK_UINT32, &(core_message->message_type), "message_type"},
- {ODK_UINT32, &(core_message->message_length), "message_size"},
- {ODK_UINT16, &(core_message->nonce_values.api_minor_version),
- "api_minor_version"},
- {ODK_UINT16, &(core_message->nonce_values.api_major_version),
- "api_major_version"},
- {ODK_UINT32, &(core_message->nonce_values.nonce), "nonce"},
- {ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"},
- };
+ std::vector total_fields =
+ ODK_MakeTotalFields(extra_fields, core_message);
- uint32_t header_size = 0;
- for (auto& field : total_fields) {
- header_size += ODK_FieldLength(field.type);
- }
-
- total_fields.insert(total_fields.end(), extra_fields.begin(),
- extra_fields.end());
for (auto& field : total_fields) {
*buf_size += ODK_FieldLength(field.type);
}
diff --git a/oemcrypto/odk/test/odk_test_helper.h b/oemcrypto/odk/test/odk_test_helper.h
index c32318e..650950b 100644
--- a/oemcrypto/odk/test/odk_test_helper.h
+++ b/oemcrypto/odk/test/odk_test_helper.h
@@ -15,13 +15,19 @@
namespace wvodk_test {
enum ODK_FieldType {
+ ODK_UINT8,
ODK_UINT16,
ODK_UINT32,
ODK_UINT64,
ODK_SUBSTRING,
ODK_DEVICEID,
ODK_HASH,
- ODK_NUMTYPES,
+ // The "stressable" types are the ones we can put in a stress test that packs
+ // and unpacks random data and can expect to get back the same thing.
+ ODK_LAST_STRESSABLE_TYPE,
+ // Put boolean after ODK_LAST_STRESSABLE_TYPE, so that we skip boolean type in
+ // SerializeFieldsStress because we unpack any nonzero to 'true'.
+ ODK_BOOL,
};
enum ODK_FieldMode {
@@ -36,6 +42,8 @@ struct ODK_Field {
std::string name;
};
+// This structure contains all parameters available in message version v16
+// through the current version.
struct ODK_LicenseResponseParams {
ODK_CoreMessage core_message;
bool initial_license_load;
@@ -68,8 +76,9 @@ struct ODK_ProvisioningResponseParams {
// Default values in core_message for testing
void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message,
- uint32_t message_type);
-void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params);
+ ODK_MessageType message_type);
+void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params,
+ uint32_t odk_major_version);
void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params);
void ODK_SetDefaultProvisioningResponseParams(
ODK_ProvisioningResponseParams* params);
diff --git a/oemcrypto/odk/test/odk_timer_test.cpp b/oemcrypto/odk/test/odk_timer_test.cpp
index 9bb0b54..8413960 100644
--- a/oemcrypto/odk/test/odk_timer_test.cpp
+++ b/oemcrypto/odk/test/odk_timer_test.cpp
@@ -38,7 +38,7 @@ TEST(OdkTimerBasicTest, Init) {
memset(&clock_values, 0, sizeof(clock_values));
uint64_t time = 42;
ODK_InitializeClockValues(&clock_values, time);
- EXPECT_EQ(clock_values.time_of_license_signed, time);
+ EXPECT_EQ(clock_values.time_of_license_request_signed, time);
EXPECT_EQ(clock_values.time_of_first_decrypt, 0u);
EXPECT_EQ(clock_values.time_of_last_decrypt, 0u);
EXPECT_EQ(clock_values.time_when_timer_expires, 0u);
@@ -59,7 +59,7 @@ TEST(OdkTimerBasicTest, Reload) {
enum OEMCrypto_Usage_Entry_Status status = kInactiveUsed;
ODK_ReloadClockValues(&clock_values, lic_signed, first_decrypt, last_decrypt,
status, time);
- EXPECT_EQ(clock_values.time_of_license_signed, lic_signed);
+ EXPECT_EQ(clock_values.time_of_license_request_signed, lic_signed);
EXPECT_EQ(clock_values.time_of_first_decrypt, first_decrypt);
EXPECT_EQ(clock_values.time_of_last_decrypt, last_decrypt);
EXPECT_EQ(clock_values.time_when_timer_expires, 0u);
@@ -95,7 +95,7 @@ class ODKTimerTest : public ::testing::Test {
// Start rental clock at kRentalClockStart. This happens when the license
// request is signed.
ODK_InitializeClockValues(&clock_values_, kRentalClockStart);
- EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart);
+ EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart);
}
// Simulate loading or reloading a license in a new session. An offline
@@ -113,14 +113,14 @@ class ODKTimerTest : public ::testing::Test {
ODK_InitializeClockValues(&clock_values_, 0);
// When the usage entry is reloaded, the clock values are reloaded.
ODK_ReloadClockValues(&clock_values_,
- old_clock_values.time_of_license_signed,
+ old_clock_values.time_of_license_request_signed,
old_clock_values.time_of_first_decrypt,
old_clock_values.time_of_last_decrypt,
old_clock_values.status, system_time);
EXPECT_EQ(clock_values_.timer_status,
ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED);
// These shall not change:
- EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart);
+ EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_first_decrypt,
old_clock_values.time_of_first_decrypt);
EXPECT_EQ(clock_values_.time_of_last_decrypt,
@@ -215,8 +215,8 @@ class ODKTimerTest : public ::testing::Test {
ODK_TIMER_EXPIRED);
// These should not have changed. In particular, if the license was unused
// before, it should reamin unused.
- EXPECT_EQ(clock_values_.time_of_license_signed,
- old_clock_values.time_of_license_signed);
+ EXPECT_EQ(clock_values_.time_of_license_request_signed,
+ old_clock_values.time_of_license_request_signed);
EXPECT_EQ(clock_values_.time_of_first_decrypt,
old_clock_values.time_of_first_decrypt);
EXPECT_EQ(clock_values_.time_of_last_decrypt,
@@ -226,7 +226,7 @@ class ODKTimerTest : public ::testing::Test {
// Verify that the clock values are correct.
void CheckClockValues(uint64_t time_of_last_decrypt) {
- EXPECT_EQ(clock_values_.time_of_license_signed, kRentalClockStart);
+ EXPECT_EQ(clock_values_.time_of_license_request_signed, kRentalClockStart);
EXPECT_EQ(clock_values_.time_of_first_decrypt, start_of_playback_);
EXPECT_EQ(clock_values_.time_of_last_decrypt, time_of_last_decrypt);
EXPECT_EQ(clock_values_.status, kActive);
@@ -1133,8 +1133,8 @@ TEST_P(ODKUseCase_LicenseWithRenewal, NullPointerTest) {
timer_value_pointer);
}
-INSTANTIATE_TEST_CASE_P(RestrictRenewal, ODKUseCase_LicenseWithRenewal,
- ::testing::Values(0, 1));
+INSTANTIATE_TEST_SUITE_P(RestrictRenewal, ODKUseCase_LicenseWithRenewal,
+ ::testing::Values(0, 1));
// Limited Duration License. (See above for notes on Use Case tests). The user
// has 15 minutes to begin watching the movie. If a renewal is not received,
diff --git a/oemcrypto/oemcrypto_unittests.gyp b/oemcrypto/oemcrypto_unittests.gyp
index 6d66e97..ffbe1d5 100644
--- a/oemcrypto/oemcrypto_unittests.gyp
+++ b/oemcrypto/oemcrypto_unittests.gyp
@@ -8,9 +8,9 @@
'privacy_crypto_impl%': 'boringssl',
'boringssl_libcrypto_path%': '
-#include
-
-extern const uint8_t kPrivateKey[];
-extern const size_t kPrivateKeySize;
-
-#endif // KEYS_H_
diff --git a/oemcrypto/ref/src/oem_cert.cpp b/oemcrypto/ref/src/oem_cert.cpp
deleted file mode 100644
index 0b7ab7f..0000000
--- a/oemcrypto/ref/src/oem_cert.cpp
+++ /dev/null
@@ -1,334 +0,0 @@
-// This file contains the test OEM cert.
-
-#include "oem_cert.h"
-
-namespace wvoec_ref {
-
-const uint32_t kOEMSystemId_Prod = 7913;
-
-// From file test_rsa_key_2_carmichael.pk8 in team shared drive.
-// Size is 1216.
-const uint8_t kOEMPrivateKey_Prod[] = {
- 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
- 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01,
- 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
- 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde,
- 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
- 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4,
- 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
- 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce,
- 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
- 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e,
- 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
- 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b,
- 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
- 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54,
- 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
- 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51,
- 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
- 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12,
- 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
- 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a,
- 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
- 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb,
- 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
- 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02,
- 0x82, 0x01, 0x00, 0x0a, 0xf9, 0x4a, 0x19, 0x72, 0x88, 0x1b, 0x4e, 0xd8,
- 0x2f, 0xef, 0x99, 0x93, 0x32, 0xda, 0x51, 0x21, 0x2e, 0x14, 0x06, 0xf4,
- 0xe9, 0x65, 0x1c, 0xf9, 0xd4, 0xcf, 0x1a, 0x51, 0x53, 0xcd, 0x48, 0x33,
- 0x8c, 0x30, 0xed, 0xdd, 0x53, 0x6f, 0x29, 0x82, 0xf9, 0xe0, 0x74, 0xde,
- 0xb1, 0x13, 0x01, 0x88, 0x8f, 0xce, 0x14, 0xc1, 0x3b, 0x90, 0xb7, 0xcc,
- 0x6c, 0xdf, 0x35, 0xa1, 0xf2, 0x1a, 0x3d, 0xbe, 0x19, 0xd7, 0x0a, 0xe4,
- 0x67, 0x75, 0xbb, 0xfa, 0x87, 0xf4, 0x03, 0xb5, 0x7f, 0x69, 0xe4, 0x0b,
- 0x6a, 0xdc, 0x92, 0x82, 0x54, 0x64, 0x1a, 0x94, 0x2d, 0xe4, 0x63, 0x40,
- 0xb2, 0xb4, 0x85, 0x6b, 0xc8, 0x34, 0xba, 0xa2, 0x14, 0x30, 0x47, 0x1a,
- 0xeb, 0x90, 0x62, 0x30, 0x43, 0x44, 0x02, 0xc7, 0x0c, 0x30, 0xc0, 0x7f,
- 0xa9, 0x47, 0xae, 0xde, 0x68, 0x27, 0x92, 0xaa, 0x11, 0x95, 0xf5, 0x6f,
- 0xfc, 0x19, 0x8b, 0x49, 0xa0, 0x77, 0x9d, 0xc6, 0x13, 0x5d, 0x73, 0xff,
- 0x45, 0xa2, 0x4c, 0x3b, 0xf3, 0xe1, 0x2d, 0xd7, 0xc4, 0x70, 0xe2, 0x6c,
- 0x37, 0x99, 0x4c, 0x7a, 0xa9, 0x27, 0xf8, 0x3a, 0xd6, 0xfd, 0xc5, 0xd8,
- 0xfa, 0x2d, 0x0e, 0x71, 0x4b, 0x85, 0x7e, 0xce, 0xcb, 0x1c, 0x79, 0x71,
- 0xbd, 0xff, 0x63, 0x03, 0x6b, 0x58, 0x68, 0xe0, 0x14, 0xca, 0x5e, 0x85,
- 0xfd, 0xd0, 0xb7, 0xe0, 0x68, 0x14, 0xff, 0x2c, 0x82, 0x22, 0x26, 0x8a,
- 0x3f, 0xbf, 0xb0, 0x2a, 0x90, 0xff, 0xc7, 0x72, 0xfc, 0x66, 0x51, 0x3e,
- 0x51, 0x9f, 0x82, 0x68, 0x0e, 0xf3, 0x65, 0x74, 0x88, 0xab, 0xb7, 0xe5,
- 0x97, 0x5f, 0x0f, 0x3e, 0xe5, 0x3a, 0xbc, 0xa4, 0xa1, 0x50, 0xdd, 0x5c,
- 0x94, 0x4b, 0x0c, 0x70, 0x71, 0x48, 0x4e, 0xd0, 0xec, 0x46, 0x8f, 0xdf,
- 0xa2, 0x9a, 0xfe, 0xd8, 0x35, 0x1a, 0x2f, 0x02, 0x81, 0x81, 0x00, 0xcf,
- 0x73, 0x8c, 0xbe, 0x6d, 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
- 0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9, 0x64, 0x60, 0x8c, 0x43,
- 0xeb, 0x85, 0xab, 0x04, 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
- 0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4, 0xde, 0x51, 0x4b, 0xb6,
- 0x51, 0x86, 0x7b, 0xd0, 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
- 0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13, 0x93, 0xd7, 0x9c, 0x27,
- 0x80, 0xb7, 0x1e, 0x64, 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
- 0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96, 0x90, 0x8f, 0xa2, 0x16,
- 0x22, 0x6a, 0xcc, 0x48, 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
- 0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27, 0x33, 0x85, 0x26, 0x60,
- 0x48, 0x16, 0xcb, 0xef, 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
- 0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87, 0xc3, 0x41, 0x45, 0x97,
- 0xb1, 0x49, 0xc2, 0x19, 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
- 0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb, 0xbb, 0xdb, 0xfd, 0x11,
- 0x9d, 0x17, 0x68, 0x78, 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
- 0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54, 0x91, 0x99, 0xe5, 0x91,
- 0x32, 0x2d, 0xeb, 0x3f, 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
- 0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42, 0x58, 0xf4, 0xd0, 0xb2,
- 0x74, 0x1d, 0x8e, 0x87, 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
- 0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53, 0xda, 0xfb, 0xed, 0x83,
- 0x51, 0x67, 0xa9, 0x55, 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
- 0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02, 0x81, 0x80, 0x67, 0x9c,
- 0x32, 0x83, 0x39, 0x57, 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
- 0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97, 0xf3, 0x90, 0x9a, 0xab,
- 0x9b, 0x0b, 0x1b, 0x43, 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
- 0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80, 0xb8, 0xe1, 0xb3, 0xa1,
- 0x6c, 0x25, 0x92, 0xe4, 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
- 0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81, 0x20, 0x82, 0xa1, 0x48,
- 0x2c, 0x2d, 0x45, 0xdc, 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
- 0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54, 0xc8, 0x28, 0x10, 0x1e,
- 0x08, 0x71, 0x16, 0xd8, 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
- 0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf, 0x35, 0x95, 0x41, 0x29,
- 0x40, 0x19, 0x83, 0x35, 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
- 0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae, 0x50, 0x76, 0x63, 0x94,
- 0x49, 0x4c, 0xad, 0x10, 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
- 0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b, 0x8a, 0xa2, 0xb9, 0x8f,
- 0xce, 0xec, 0x5e, 0x61, 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
- 0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69, 0xe4, 0x8b, 0x01, 0x06,
- 0x59, 0x22, 0xfa, 0x34, 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
- 0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26, 0x6c, 0xfa, 0x2b, 0xd9,
- 0x83, 0x5a, 0x2d, 0x0c, 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
- 0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3, 0x66, 0xff, 0x1c, 0x1b,
- 0xc8, 0x96, 0x76, 0xe8, 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
- 0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80, 0x2c, 0x7c, 0xad, 0x1e,
- 0x75, 0xf6, 0x69, 0x1d, 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
- 0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57, 0xae, 0xb7, 0x65, 0x2c,
- 0x52, 0xf9, 0xe4, 0xc7, 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
- 0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50, 0x75, 0x61, 0x96, 0x86,
- 0x4b, 0xb6, 0x2b, 0xad, 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
- 0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a, 0xd3, 0x29, 0x23, 0x02,
- 0x60, 0xf7, 0xab, 0x30, 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
- 0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18, 0xf4, 0xd4, 0x52, 0x95,
- 0x00, 0xae, 0x84, 0x6b, 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
- 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28,
- 0x33, 0xe0, 0xdb, 0x03
-};
-
-const size_t kOEMPrivateKeySize_Prod = sizeof(kOEMPrivateKey_Prod);
-
-// From the team shared drive file
-// oem-7913-leaf-and-intermediate-certs-test-key-2-carmichael.p7b, size 2353.
-const uint8_t kOEMPublicCert_Prod[] = {
- 0x30, 0x82, 0x09, 0x2d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x1e, 0x30, 0x82, 0x09, 0x1a, 0x02,
- 0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
- 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x08,
- 0xfe, 0x30, 0x82, 0x03, 0x71, 0x30, 0x82, 0x02, 0x59, 0xa0, 0x03, 0x02,
- 0x01, 0x02, 0x02, 0x11, 0x00, 0xc2, 0x8d, 0x20, 0x22, 0x82, 0x8b, 0x9e,
- 0x63, 0x9d, 0x15, 0x89, 0x2c, 0xa9, 0x8f, 0xd9, 0x5d, 0x30, 0x0d, 0x06,
- 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
- 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
- 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
- 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
- 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
- 0x33, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x38, 0x30, 0x31, 0x31, 0x31, 0x31,
- 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x17, 0x0d, 0x33, 0x38, 0x30, 0x31,
- 0x30, 0x36, 0x31, 0x33, 0x32, 0x36, 0x32, 0x32, 0x5a, 0x30, 0x65, 0x31,
- 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39,
- 0x31, 0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06,
- 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09,
- 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b,
- 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
- 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30,
- 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65,
- 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09,
- 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03,
- 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01,
- 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a, 0x40,
- 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58, 0xdd, 0xde, 0xa7,
- 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e, 0x56,
- 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa, 0x9d, 0xb4, 0x4e,
- 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3, 0x34,
- 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda, 0x3f, 0xce, 0x31,
- 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb, 0x3e,
- 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2, 0x73, 0x9e, 0x39,
- 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4, 0xf2,
- 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a, 0x13, 0x8b, 0x54,
- 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda, 0xb3,
- 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56, 0x57, 0x54, 0x71,
- 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03, 0x96,
- 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83, 0x06, 0x51, 0x5a,
- 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b, 0x4c,
- 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f, 0xf8, 0x12, 0x7f,
- 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01, 0xca,
- 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46, 0x0b, 0x3a, 0x77,
- 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed, 0x27,
- 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b, 0x3d, 0xdb, 0x9c,
- 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb, 0x2c,
- 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16,
- 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6,
- 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d,
- 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05,
- 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x88, 0x95, 0xec, 0xcd, 0x8b, 0xa7,
- 0x51, 0xda, 0x74, 0x81, 0xa5, 0x39, 0x62, 0x1a, 0x0e, 0x2e, 0xde, 0x3c,
- 0x37, 0xea, 0xad, 0x7c, 0xee, 0x9b, 0x26, 0x8e, 0xe2, 0xd6, 0x34, 0xcd,
- 0xb7, 0x70, 0xba, 0xbf, 0xa0, 0xa3, 0xfe, 0xb3, 0x4b, 0xbc, 0xf4, 0x1c,
- 0x72, 0x66, 0x81, 0xd5, 0x09, 0x33, 0x78, 0x0c, 0x61, 0x21, 0xa8, 0xf1,
- 0xe2, 0xc9, 0xe2, 0x83, 0xc2, 0x19, 0x02, 0xf2, 0xe8, 0xab, 0x17, 0x36,
- 0x3a, 0x0b, 0x20, 0xaf, 0x0f, 0xae, 0x2e, 0x73, 0x68, 0xac, 0x15, 0xee,
- 0x9c, 0xc0, 0x92, 0x03, 0x7e, 0x95, 0x63, 0xaa, 0xad, 0x15, 0x96, 0x43,
- 0x20, 0x3b, 0xe5, 0x9b, 0x1f, 0xca, 0x02, 0xba, 0xf0, 0x07, 0x76, 0x80,
- 0xd7, 0xa3, 0x1a, 0xeb, 0xc8, 0xdb, 0x03, 0x7b, 0x43, 0x56, 0xe5, 0x96,
- 0x6b, 0x86, 0xfe, 0x08, 0x58, 0x8a, 0x84, 0xbd, 0xe9, 0x47, 0x18, 0xee,
- 0xb2, 0xa8, 0x05, 0x7b, 0xf0, 0xfd, 0xaa, 0xb9, 0x85, 0xcd, 0x7a, 0x0e,
- 0x6b, 0x6c, 0x9f, 0xc6, 0x75, 0xd2, 0x2a, 0xfe, 0x5b, 0xf3, 0xb7, 0x31,
- 0x6c, 0xac, 0xe3, 0x00, 0x9f, 0xe7, 0xdd, 0xe3, 0x81, 0xc1, 0x36, 0xc3,
- 0x1c, 0x5f, 0xdf, 0xf2, 0xc3, 0x5e, 0xfa, 0x55, 0x32, 0xd8, 0x5c, 0xa8,
- 0xe5, 0xcc, 0xb6, 0x4a, 0xe9, 0xe2, 0xcc, 0x38, 0x44, 0x07, 0x46, 0x59,
- 0x34, 0x84, 0x79, 0xf9, 0xee, 0x3c, 0x4b, 0x48, 0x90, 0xab, 0x73, 0xb0,
- 0xa1, 0x92, 0xc3, 0xd6, 0x83, 0x87, 0x81, 0xca, 0x12, 0x81, 0xd6, 0x5d,
- 0xf7, 0x6f, 0x7a, 0x35, 0x5e, 0x4f, 0x02, 0x66, 0x8a, 0x47, 0x88, 0x82,
- 0xab, 0xf0, 0x12, 0x1d, 0xb9, 0x75, 0x3b, 0x7b, 0xa8, 0x36, 0x15, 0xef,
- 0xa8, 0x12, 0x0e, 0x53, 0xb4, 0x83, 0x78, 0x53, 0xc0, 0x52, 0xae, 0xa6,
- 0x0a, 0xa0, 0x53, 0xdc, 0x1c, 0x15, 0x22, 0xdd, 0x17, 0x98, 0x30, 0x82,
- 0x05, 0x85, 0x30, 0x82, 0x03, 0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
- 0x10, 0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25, 0x00, 0x0b, 0x10,
- 0x3d, 0xd5, 0xe6, 0xe4, 0x64, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x0b,
- 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
- 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61,
- 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f,
- 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c,
- 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
- 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f,
- 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76,
- 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03,
- 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63,
- 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d,
- 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31,
- 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a, 0x17, 0x0d, 0x32,
- 0x37, 0x31, 0x31, 0x31, 0x38, 0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a,
- 0x30, 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
- 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
- 0x0c, 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
- 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
- 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79,
- 0x73, 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31,
- 0x33, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
- 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f,
- 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8,
- 0x71, 0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c, 0xa9, 0x8b, 0xb3,
- 0xd6, 0x66, 0xe4, 0xf6, 0x08, 0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a,
- 0x88, 0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19, 0x6c, 0x60, 0xc9,
- 0xad, 0x91, 0x1c, 0xbf, 0x04, 0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58,
- 0xc2, 0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14, 0xa8, 0xc2, 0x01,
- 0xcd, 0xe8, 0x46, 0x60, 0x53, 0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d,
- 0x0e, 0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43, 0xe3, 0xb0, 0x00,
- 0x12, 0xb4, 0x05, 0x82, 0x4a, 0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12,
- 0xaa, 0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c, 0x6c, 0x73, 0xae,
- 0x56, 0xf8, 0xab, 0xf7, 0x51, 0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01,
- 0x2c, 0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37, 0x89, 0x05, 0xa9,
- 0x51, 0x57, 0x72, 0x98, 0x9e, 0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b,
- 0x2f, 0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf, 0xf5, 0xd6, 0x9c,
- 0xd5, 0x8c, 0xb8, 0x66, 0x42, 0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e,
- 0x3e, 0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d, 0xf4, 0x57, 0x7c,
- 0x6c, 0x33, 0x34, 0x24, 0x45, 0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c,
- 0x03, 0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87, 0x74, 0x82, 0x1a,
- 0xbc, 0x0f, 0x76, 0x69, 0xab, 0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8,
- 0x2c, 0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90, 0xb5, 0x2d, 0x64,
- 0xba, 0xf7, 0xd2, 0x8a, 0xb4, 0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c,
- 0x52, 0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70, 0x7e, 0x47, 0x59,
- 0x94, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30,
- 0x82, 0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01,
- 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30,
- 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03,
- 0x02, 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
- 0x04, 0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d, 0xc3, 0xe7, 0xe5,
- 0x85, 0xdb, 0x2e, 0x8a, 0xbe, 0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81,
- 0xb2, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7,
- 0x80, 0x14, 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5,
- 0xf7, 0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81,
- 0x83, 0xa4, 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
- 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
- 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e,
- 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31,
- 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f,
- 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04,
- 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31,
- 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69,
- 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f,
- 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64,
- 0x82, 0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30,
- 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01,
- 0x01, 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82,
- 0x02, 0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe, 0x66, 0x34, 0xef,
- 0x92, 0x06, 0xe9, 0x88, 0xba, 0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1,
- 0x75, 0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36, 0xfd, 0x55, 0xa9,
- 0x21, 0x0b, 0xdc, 0xf6, 0xae, 0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04,
- 0x1d, 0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba, 0xe6, 0xdd, 0x19,
- 0xdd, 0x56, 0xfd, 0xce, 0x06, 0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb,
- 0x3d, 0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d, 0x4d, 0xcf, 0x7e,
- 0xf0, 0x91, 0x29, 0xc1, 0x77, 0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8,
- 0xce, 0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5, 0x9f, 0x9c, 0x1b,
- 0xc9, 0x4b, 0x58, 0xdf, 0x96, 0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9,
- 0x14, 0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75, 0x2c, 0x2b, 0xbf,
- 0x63, 0x7d, 0xc7, 0x4e, 0x7e, 0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5,
- 0x5a, 0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2, 0x9c, 0x3c, 0x32,
- 0xed, 0x9d, 0x4b, 0x49, 0x05, 0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82,
- 0x79, 0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa, 0x4f, 0xef, 0x14,
- 0x3c, 0x21, 0xf6, 0x72, 0xb2, 0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70,
- 0xbd, 0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59, 0x0c, 0x0f, 0x11,
- 0x75, 0xd4, 0xbb, 0xb1, 0xdf, 0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43,
- 0x17, 0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83, 0x51, 0xfb, 0x16,
- 0xfb, 0x64, 0xb6, 0x46, 0xda, 0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a,
- 0x84, 0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde, 0xa5, 0x97, 0x66,
- 0x79, 0x02, 0xf8, 0x97, 0x17, 0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae,
- 0x99, 0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5, 0x80, 0xba, 0xbf,
- 0xdd, 0x24, 0xe5, 0xe6, 0x1e, 0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60,
- 0x81, 0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c, 0x1a, 0x63, 0xb0,
- 0xeb, 0xe6, 0x95, 0x86, 0x0d, 0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0,
- 0xbe, 0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec, 0xf9, 0xcd, 0x49,
- 0xc6, 0xfe, 0x4d, 0x7f, 0x44, 0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98,
- 0xe2, 0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc, 0x76, 0x69, 0x51,
- 0x10, 0x01, 0x46, 0x7d, 0x33, 0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c,
- 0xc6, 0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a, 0x58, 0x6a, 0xf1,
- 0x75, 0x9e, 0xea, 0x1b, 0x4c, 0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32,
- 0x44, 0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2, 0xfa, 0xa1, 0x5f,
- 0x2e, 0x66, 0xe9, 0x97, 0xcb, 0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86,
- 0x2c, 0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1, 0xc9, 0x8b, 0x05,
- 0x92, 0x6f, 0x47, 0x96, 0xce, 0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b,
- 0xd7, 0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a, 0xf9, 0xb9, 0xb0,
- 0x93, 0xf0, 0x81, 0x78, 0x10, 0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf,
- 0xbc, 0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8, 0x13, 0x77, 0x4f,
- 0x78, 0x9e, 0x40, 0x8d, 0xe6, 0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25,
- 0x49, 0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd, 0xf5, 0xb1, 0x54,
- 0x74, 0x1b, 0x67, 0x3c, 0x46, 0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83,
- 0x30, 0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d, 0xd0, 0x68, 0x31,
- 0x00
-};
-
-const size_t kOEMPublicCertSize_Prod = sizeof(kOEMPublicCert_Prod);
-
-// Refer to the following in main modules.
-// This level of indirection is present so new OEM Certificates can be
-// added and then selected for use at compile time or run time.
-
-const uint32_t kOEMSystemId = kOEMSystemId_Prod;
-
-const uint8_t* kOEMPrivateKey = kOEMPrivateKey_Prod;
-const uint8_t* kOEMPublicCert = kOEMPublicCert_Prod;
-
-const size_t kOEMPrivateKeySize = kOEMPrivateKeySize_Prod;
-const size_t kOEMPublicCertSize = kOEMPublicCertSize_Prod;
-
-} // namespace wvoec_ref
diff --git a/oemcrypto/ref/src/oem_cert.h b/oemcrypto/ref/src/oem_cert.h
deleted file mode 100644
index 3d0476b..0000000
--- a/oemcrypto/ref/src/oem_cert.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// This header is used to access the OEM certificate if one is in use.
-#ifndef OEM_CERT_H_
-#define OEM_CERT_H_
-
-#include
-#include
-
-namespace wvoec_ref {
-
-// Refer to the following in main modules
-extern const uint32_t kOEMSystemId;
-
-extern const uint8_t* kOEMPrivateKey;
-extern const uint8_t* kOEMPublicCert;
-
-extern const size_t kOEMPrivateKeySize;
-extern const size_t kOEMPublicCertSize;
-
-} // namespace wvoec_ref
-
-#endif // OEM_CERT_H_
diff --git a/oemcrypto/ref/src/oemcrypto_auth_ref.cpp b/oemcrypto/ref/src/oemcrypto_auth_ref.cpp
deleted file mode 100644
index f3d9a45..0000000
--- a/oemcrypto/ref/src/oemcrypto_auth_ref.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-#include "oemcrypto_auth_ref.h"
-
-#include
-
-#include "keys.h"
-#include "log.h"
-#include "oemcrypto_rsa_key_shared.h"
-
-namespace {
-
-// A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format
-// This is the RSA Test Key. This key is not derived
-// from any Widevine authentication root.
-static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
- 0x30, 0x82, 0x04, 0xbc, 0x02, 0x01, 0x00, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
- 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
- 0x04, 0xa6, 0x30, 0x82, 0x04, 0xa2, 0x02, 0x01,
- 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa7, 0x00,
- 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54, 0x5a, 0x2a,
- 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f,
- 0x94, 0x58, 0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c,
- 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57, 0x67, 0x5e,
- 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a,
- 0x2a, 0xaa, 0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a,
- 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e, 0x9f, 0xe3,
- 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f,
- 0x28, 0xda, 0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06,
- 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9, 0xaf, 0xfb,
- 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3,
- 0x29, 0xf2, 0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f,
- 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e, 0xb5, 0xa4,
- 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04,
- 0xcd, 0x9a, 0x13, 0x8b, 0x54, 0x73, 0x54, 0x25,
- 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67, 0xad, 0xda,
- 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67,
- 0x98, 0x56, 0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f,
- 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b, 0x24, 0x03,
- 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53,
- 0xc9, 0x83, 0x06, 0x51, 0x5a, 0x88, 0x65, 0x13,
- 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1, 0x61, 0x5b,
- 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e,
- 0x2d, 0x5f, 0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb,
- 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40, 0xfb, 0x01,
- 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87,
- 0x82, 0x46, 0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72,
- 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86, 0x5b, 0xed,
- 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44,
- 0xd3, 0x5b, 0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b,
- 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b, 0xbb, 0xbb,
- 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03,
- 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x00, 0x5e,
- 0x79, 0x65, 0x49, 0xa5, 0x76, 0x79, 0xf9, 0x05,
- 0x45, 0x0f, 0xf4, 0x03, 0xbd, 0xa4, 0x7d, 0x29,
- 0xd5, 0xde, 0x33, 0x63, 0xd8, 0xb8, 0xac, 0x97,
- 0xeb, 0x3f, 0x5e, 0x55, 0xe8, 0x7d, 0xf3, 0xe7,
- 0x3b, 0x5c, 0x2d, 0x54, 0x67, 0x36, 0xd6, 0x1d,
- 0x46, 0xf5, 0xca, 0x2d, 0x8b, 0x3a, 0x7e, 0xdc,
- 0x45, 0x38, 0x79, 0x7e, 0x65, 0x71, 0x5f, 0x1c,
- 0x5e, 0x79, 0xb1, 0x40, 0xcd, 0xfe, 0xc5, 0xe1,
- 0xc1, 0x6b, 0x78, 0x04, 0x4e, 0x8e, 0x79, 0xf9,
- 0x0a, 0xfc, 0x79, 0xb1, 0x5e, 0xb3, 0x60, 0xe3,
- 0x68, 0x7b, 0xc6, 0xef, 0xcb, 0x71, 0x4c, 0xba,
- 0xa7, 0x79, 0x5c, 0x7a, 0x81, 0xd1, 0x71, 0xe7,
- 0x00, 0x21, 0x13, 0xe2, 0x55, 0x69, 0x0e, 0x75,
- 0xbe, 0x09, 0xc3, 0x4f, 0xa9, 0xc9, 0x68, 0x22,
- 0x0e, 0x97, 0x8d, 0x89, 0x6e, 0xf1, 0xe8, 0x88,
- 0x7a, 0xd1, 0xd9, 0x09, 0x5d, 0xd3, 0x28, 0x78,
- 0x25, 0x0b, 0x1c, 0x47, 0x73, 0x25, 0xcc, 0x21,
- 0xb6, 0xda, 0xc6, 0x24, 0x5a, 0xd0, 0x37, 0x14,
- 0x46, 0xc7, 0x94, 0x69, 0xe4, 0x43, 0x6f, 0x47,
- 0xde, 0x00, 0x33, 0x4d, 0x8f, 0x95, 0x72, 0xfa,
- 0x68, 0x71, 0x17, 0x66, 0x12, 0x1a, 0x87, 0x27,
- 0xf7, 0xef, 0x7e, 0xe0, 0x35, 0x58, 0xf2, 0x4d,
- 0x6f, 0x35, 0x01, 0xaa, 0x96, 0xe2, 0x3d, 0x51,
- 0x13, 0x86, 0x9c, 0x79, 0xd0, 0xb7, 0xb6, 0x64,
- 0xe8, 0x86, 0x65, 0x50, 0xbf, 0xcc, 0x27, 0x53,
- 0x1f, 0x51, 0xd4, 0xca, 0xbe, 0xf5, 0xdd, 0x77,
- 0x70, 0x98, 0x0f, 0xee, 0xa8, 0x96, 0x07, 0x5f,
- 0x45, 0x6a, 0x7a, 0x0d, 0x03, 0x9c, 0x4f, 0x29,
- 0xf6, 0x06, 0xf3, 0x5d, 0x58, 0x6c, 0x47, 0xd0,
- 0x96, 0xa9, 0x03, 0x17, 0xbb, 0x4e, 0xc9, 0x21,
- 0xe0, 0xac, 0xcd, 0x78, 0x78, 0xb2, 0xfe, 0x81,
- 0xb2, 0x51, 0x53, 0xa6, 0x1f, 0x98, 0x45, 0x02,
- 0x81, 0x81, 0x00, 0xcf, 0x73, 0x8c, 0xbe, 0x6d,
- 0x45, 0x2d, 0x0c, 0x0b, 0x5d, 0x5c, 0x6c, 0x75,
- 0x78, 0xcc, 0x35, 0x48, 0xb6, 0x98, 0xf1, 0xb9,
- 0x64, 0x60, 0x8c, 0x43, 0xeb, 0x85, 0xab, 0x04,
- 0xb6, 0x7d, 0x1b, 0x71, 0x75, 0x06, 0xe2, 0xda,
- 0x84, 0x68, 0x2e, 0x7f, 0x4c, 0xe3, 0x73, 0xb4,
- 0xde, 0x51, 0x4b, 0xb6, 0x51, 0x86, 0x7b, 0xd0,
- 0xe6, 0x4d, 0xf3, 0xd1, 0xcf, 0x1a, 0xfe, 0x7f,
- 0x3a, 0x83, 0xba, 0xb3, 0xe1, 0xff, 0x54, 0x13,
- 0x93, 0xd7, 0x9c, 0x27, 0x80, 0xb7, 0x1e, 0x64,
- 0x9e, 0xf7, 0x32, 0x2b, 0x46, 0x29, 0xf7, 0xf8,
- 0x18, 0x6c, 0xf7, 0x4a, 0xbe, 0x4b, 0xee, 0x96,
- 0x90, 0x8f, 0xa2, 0x16, 0x22, 0x6a, 0xcc, 0x48,
- 0x06, 0x74, 0x63, 0x43, 0x7f, 0x27, 0x22, 0x44,
- 0x3c, 0x2d, 0x3b, 0x62, 0xf1, 0x1c, 0xb4, 0x27,
- 0x33, 0x85, 0x26, 0x60, 0x48, 0x16, 0xcb, 0xef,
- 0xf8, 0xcd, 0x37, 0x02, 0x81, 0x81, 0x00, 0xce,
- 0x15, 0x43, 0x6e, 0x4b, 0x0f, 0xf9, 0x3f, 0x87,
- 0xc3, 0x41, 0x45, 0x97, 0xb1, 0x49, 0xc2, 0x19,
- 0x23, 0x87, 0xe4, 0x24, 0x1c, 0x64, 0xe5, 0x28,
- 0xcb, 0x43, 0x10, 0x14, 0x14, 0x0e, 0x19, 0xcb,
- 0xbb, 0xdb, 0xfd, 0x11, 0x9d, 0x17, 0x68, 0x78,
- 0x6d, 0x61, 0x70, 0x63, 0x3a, 0xa1, 0xb3, 0xf3,
- 0xa7, 0x5b, 0x0e, 0xff, 0xb7, 0x61, 0x11, 0x54,
- 0x91, 0x99, 0xe5, 0x91, 0x32, 0x2d, 0xeb, 0x3f,
- 0xd8, 0x3e, 0xf7, 0xd4, 0xcb, 0xd2, 0xa3, 0x41,
- 0xc1, 0xee, 0xc6, 0x92, 0x13, 0xeb, 0x7f, 0x42,
- 0x58, 0xf4, 0xd0, 0xb2, 0x74, 0x1d, 0x8e, 0x87,
- 0x46, 0xcd, 0x14, 0xb8, 0x16, 0xad, 0xb5, 0xbd,
- 0x0d, 0x6c, 0x95, 0x5a, 0x16, 0xbf, 0xe9, 0x53,
- 0xda, 0xfb, 0xed, 0x83, 0x51, 0x67, 0xa9, 0x55,
- 0xab, 0x54, 0x02, 0x95, 0x20, 0xa6, 0x68, 0x17,
- 0x53, 0xa8, 0xea, 0x43, 0xe5, 0xb0, 0xa3, 0x02,
- 0x81, 0x80, 0x67, 0x9c, 0x32, 0x83, 0x39, 0x57,
- 0xff, 0x73, 0xb0, 0x89, 0x64, 0x8b, 0xd6, 0xf0,
- 0x0a, 0x2d, 0xe2, 0xaf, 0x30, 0x1c, 0x2a, 0x97,
- 0xf3, 0x90, 0x9a, 0xab, 0x9b, 0x0b, 0x1b, 0x43,
- 0x79, 0xa0, 0xa7, 0x3d, 0xe7, 0xbe, 0x8d, 0x9c,
- 0xeb, 0xdb, 0xad, 0x40, 0xdd, 0xa9, 0x00, 0x80,
- 0xb8, 0xe1, 0xb3, 0xa1, 0x6c, 0x25, 0x92, 0xe4,
- 0x33, 0xb2, 0xbe, 0xeb, 0x4d, 0x74, 0x26, 0x5f,
- 0x37, 0x43, 0x9c, 0x6c, 0x17, 0x76, 0x0a, 0x81,
- 0x20, 0x82, 0xa1, 0x48, 0x2c, 0x2d, 0x45, 0xdc,
- 0x0f, 0x62, 0x43, 0x32, 0xbb, 0xeb, 0x59, 0x41,
- 0xf9, 0xca, 0x58, 0xce, 0x4a, 0x66, 0x53, 0x54,
- 0xc8, 0x28, 0x10, 0x1e, 0x08, 0x71, 0x16, 0xd8,
- 0x02, 0x71, 0x41, 0x58, 0xd4, 0x56, 0xcc, 0xf5,
- 0xb1, 0x31, 0xa3, 0xed, 0x00, 0x85, 0x09, 0xbf,
- 0x35, 0x95, 0x41, 0x29, 0x40, 0x19, 0x83, 0x35,
- 0x24, 0x69, 0x02, 0x81, 0x80, 0x55, 0x10, 0x0b,
- 0xcc, 0x3b, 0xa9, 0x75, 0x3d, 0x16, 0xe1, 0xae,
- 0x50, 0x76, 0x63, 0x94, 0x49, 0x4c, 0xad, 0x10,
- 0xcb, 0x47, 0x68, 0x7c, 0xf0, 0xe5, 0xdc, 0xb8,
- 0x6a, 0xab, 0x8e, 0xf7, 0x9f, 0x08, 0x2c, 0x1b,
- 0x8a, 0xa2, 0xb9, 0x8f, 0xce, 0xec, 0x5e, 0x61,
- 0xa8, 0xcd, 0x1c, 0x87, 0x60, 0x4a, 0xc3, 0x1a,
- 0x5f, 0xdf, 0x87, 0x26, 0xc6, 0xcb, 0x7c, 0x69,
- 0xe4, 0x8b, 0x01, 0x06, 0x59, 0x22, 0xfa, 0x34,
- 0x4b, 0x81, 0x87, 0x3c, 0x03, 0x6d, 0x02, 0x0a,
- 0x77, 0xe6, 0x15, 0xd8, 0xcf, 0xa7, 0x68, 0x26,
- 0x6c, 0xfa, 0x2b, 0xd9, 0x83, 0x5a, 0x2d, 0x0c,
- 0x3b, 0x70, 0x1c, 0xd4, 0x48, 0xbe, 0xa7, 0x0a,
- 0xd9, 0xbe, 0xdc, 0xc3, 0x0c, 0x21, 0x33, 0xb3,
- 0x66, 0xff, 0x1c, 0x1b, 0xc8, 0x96, 0x76, 0xe8,
- 0x6f, 0x44, 0x74, 0xbc, 0x9b, 0x1c, 0x7d, 0xc8,
- 0xac, 0x21, 0xa8, 0x6e, 0x37, 0x02, 0x81, 0x80,
- 0x2c, 0x7c, 0xad, 0x1e, 0x75, 0xf6, 0x69, 0x1d,
- 0xe7, 0xa6, 0xca, 0x74, 0x7d, 0x67, 0xc8, 0x65,
- 0x28, 0x66, 0xc4, 0x43, 0xa6, 0xbd, 0x40, 0x57,
- 0xae, 0xb7, 0x65, 0x2c, 0x52, 0xf9, 0xe4, 0xc7,
- 0x81, 0x7b, 0x56, 0xa3, 0xd2, 0x0d, 0xe8, 0x33,
- 0x70, 0xcf, 0x06, 0x84, 0xb3, 0x4e, 0x44, 0x50,
- 0x75, 0x61, 0x96, 0x86, 0x4b, 0xb6, 0x2b, 0xad,
- 0xf0, 0xad, 0x57, 0xd0, 0x37, 0x0d, 0x1d, 0x35,
- 0x50, 0xcb, 0x69, 0x22, 0x39, 0x29, 0xb9, 0x3a,
- 0xd3, 0x29, 0x23, 0x02, 0x60, 0xf7, 0xab, 0x30,
- 0x40, 0xda, 0x8e, 0x4d, 0x45, 0x70, 0x26, 0xf4,
- 0xa2, 0x0d, 0xd0, 0x64, 0x5d, 0x47, 0x3c, 0x18,
- 0xf4, 0xd4, 0x52, 0x95, 0x00, 0xae, 0x84, 0x6b,
- 0x47, 0xb2, 0x3c, 0x82, 0xd3, 0x72, 0x53, 0xde,
- 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18,
- 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03
-};
-
-} // namespace
-
-namespace wvoec_ref {
-
-AuthenticationRoot::AuthenticationRoot(OEMCrypto_ProvisioningMethod method) :
- provisioning_method_(method),
- use_test_keybox_(false) {
- if ((provisioning_method_ == OEMCrypto_DrmCertificate) &&
- !rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) {
- // This error message is OK in unit tests which use test certificate.
- LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a "
- "keybox, but the certificate could not be loaded.");
- }
-}
-
-KeyboxError AuthenticationRoot::ValidateKeybox() {
- return keybox().Validate();
-}
-
-bool AuthenticationRoot::LoadTestRsaKey() {
- return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048,
- sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
-}
-
-bool AuthenticationRoot::Validate() {
- return NO_ERROR == ValidateKeybox();
-}
-
-} // namespace wvoec_ref
diff --git a/oemcrypto/ref/src/oemcrypto_auth_ref.h b/oemcrypto/ref/src/oemcrypto_auth_ref.h
deleted file mode 100644
index 4e8ede7..0000000
--- a/oemcrypto/ref/src/oemcrypto_auth_ref.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-#ifndef OEMCRYPTO_AUTH_REF_H_
-#define OEMCRYPTO_AUTH_REF_H_
-
-#include
-#include
-#include
-
-#include
-
-#include "OEMCryptoCENC.h" // Needed for enums only.
-#include "disallow_copy_and_assign.h"
-#include "oemcrypto_key_ref.h"
-#include "oemcrypto_keybox_ref.h"
-#include "oemcrypto_rsa_key_shared.h"
-#include "oemcrypto_types.h"
-
-namespace wvoec_ref {
-
-class AuthenticationRoot {
- public:
- explicit AuthenticationRoot(OEMCrypto_ProvisioningMethod method);
- ~AuthenticationRoot() {}
-
- bool Validate();
-
- KeyboxError ValidateKeybox();
-
- bool InstallKeybox(const uint8_t* keybox_data, size_t keybox_length) {
- return keybox().InstallKeybox(keybox_data, keybox_length);
- }
-
- const std::vector& DeviceKey(bool use_real_keybox = false) {
- return use_real_keybox ? real_keybox().device_key() :
- keybox().device_key();
- }
-
- const std::vector& DeviceId() {
- return keybox().device_id();
- }
-
- size_t DeviceTokenLength() {
- return keybox().key_data_length();
- }
-
- const uint8_t* DeviceToken() {
- return keybox().key_data();
- }
-
- WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; }
- bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) {
- use_test_keybox_ = true;
- return test_keybox_.InstallKeybox(keybox_data, keybox_length);
- }
-
- RSA_shared_ptr& SharedRsaKey() { return rsa_key_; }
- RSA* rsa_key() { return rsa_key_.get(); }
- bool LoadTestRsaKey();
- void Clear() { use_test_keybox_ = false; }
-
- private:
- OEMCrypto_ProvisioningMethod provisioning_method_;
- WvKeybox& real_keybox() { return keybox_; }
-
- WvKeybox keybox_;
- WvKeybox test_keybox_;
- bool use_test_keybox_;
-
- RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate.
-
- CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot);
-};
-
-} // namespace wvoec_ref
-
-#endif // OEMCRYPTO_AUTH_REF_H_
diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties.cpp
deleted file mode 100644
index 8c4bd22..0000000
--- a/oemcrypto/ref/src/oemcrypto_engine_device_properties.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-
-#include "oemcrypto_engine_ref.h"
-
-#include
-
-namespace wvoec_ref {
-
-CryptoEngine* CryptoEngine::MakeCryptoEngine(
- std::unique_ptr&& file_system) {
- return new CryptoEngine(std::move(file_system));
-}
-
-} // namespace wvoec_ref
diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties_L1.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties_L1.cpp
deleted file mode 100644
index 9e9b7c5..0000000
--- a/oemcrypto/ref/src/oemcrypto_engine_device_properties_L1.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-// This file contains oemcrypto engine properties that would be for a
-// level 1 device.
-#include "oemcrypto_engine_ref.h"
-
-#include
-
-namespace wvoec_ref {
-
-class L1CryptoEngine : public CryptoEngine {
- public:
- explicit L1CryptoEngine(std::unique_ptr&& file_system)
- : CryptoEngine(std::move(file_system)) {}
-
- bool config_local_display_only() { return true; }
-
- OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
- return HDCP_V2;
- }
-
- bool config_is_anti_rollback_hw_present() { return true; }
-
- const char* config_security_level() { return "L1"; }
-
- // This should start at 0, and be incremented only when a security patch has
- // been applied to the device that fixes a security bug.
- uint8_t config_security_patch_level() { return 3; }
-};
-
-CryptoEngine* CryptoEngine::MakeCryptoEngine(
- std::unique_ptr&& file_system) {
- return new L1CryptoEngine(std::move(file_system));
-}
-
-} // namespace wvoec_ref
diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties_cert.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties_cert.cpp
deleted file mode 100644
index 146a829..0000000
--- a/oemcrypto/ref/src/oemcrypto_engine_device_properties_cert.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-// This file contains oemcrypto engine properties that would be for a device
-// that does not have persistant storage or a keybox.
-//
-// Note: We also define it to be L2 for illustration only. Production devices
-// are rarely level 2.
-#include "oemcrypto_engine_ref.h"
-
-namespace wvoec_ref {
-
-class CertOnlyCryptoEngine : public CryptoEngine {
- public:
- explicit CertOnlyCryptoEngine(std::unique_ptr&& file_system)
- : CryptoEngine(std::move(file_system)) {}
-
- bool config_local_display_only() { return true; }
-
- bool config_supports_usage_table() { return false; }
-
- OEMCrypto_ProvisioningMethod config_provisioning_method() {
- return OEMCrypto_DrmCertificate;
- }
-
- const char* config_security_level() { return "L2"; }
-};
-
-CryptoEngine* CryptoEngine::MakeCryptoEngine(
- std::unique_ptr&& file_system) {
- return new CertOnlyCryptoEngine(std::move(file_system));
-}
-
-} // namespace wvoec_ref
diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp
deleted file mode 100644
index 7e3c2eb..0000000
--- a/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-// This file contains oemcrypto engine properties that would be for a
-// level 2 device that does not have persistant storage or a keybox.
-// Note: this is for illustration only. Production devices are rarely level 2.
-
-#include "oemcrypto_engine_ref.h"
-
-#include
-
-#include
-
-#include "log.h"
-#include "oem_cert.h"
-
-namespace wvoec_ref {
-
-class Prov30CryptoEngine : public CryptoEngine {
- public:
- explicit Prov30CryptoEngine(std::unique_ptr&& file_system)
- : CryptoEngine(std::move(file_system)) {}
-
- bool config_local_display_only() { return true; }
-
- // Returns the max HDCP version supported.
- OEMCrypto_HDCP_Capability config_maximum_hdcp_capability() {
- return HDCP_NO_DIGITAL_OUTPUT;
- }
-
- // Returns true if the client supports persistent storage of
- // offline usage table information.
- bool config_supports_usage_table() {
- return false;
- }
-
- // Returns true if the client uses a keybox as the root of trust.
- bool config_supports_keybox() {
- return false;
- }
-
- // This version uses an OEM Certificate.
- OEMCrypto_ProvisioningMethod config_provisioning_method() {
- return OEMCrypto_OEMCertificate;
- }
-
- OEMCryptoResult get_oem_certificate(SessionContext* session,
- uint8_t* public_cert,
- size_t* public_cert_length) {
- if (kOEMPublicCertSize == 0) {
- return OEMCrypto_ERROR_NOT_IMPLEMENTED;
- }
- if (public_cert_length == nullptr) {
- return OEMCrypto_ERROR_UNKNOWN_FAILURE;
- }
- if (*public_cert_length < kOEMPublicCertSize) {
- *public_cert_length = kOEMPublicCertSize;
- return OEMCrypto_ERROR_SHORT_BUFFER;
- }
- *public_cert_length = kOEMPublicCertSize;
- if (public_cert == nullptr) {
- return OEMCrypto_ERROR_SHORT_BUFFER;
- }
- memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize);
- if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) {
- LOGE("Private RSA Key did not load correctly.");
- return OEMCrypto_ERROR_INVALID_RSA_KEY;
- }
- return OEMCrypto_SUCCESS;
- }
-
- // Returns "L3" for a software only library. L1 is for hardware protected
- // keys and data paths. L2 is for hardware protected keys but no data path
- // protection.
- const char* config_security_level() { return "L2"; }
-};
-
-CryptoEngine* CryptoEngine::MakeCryptoEngine(
- std::unique_ptr&& file_system) {
- return new Prov30CryptoEngine(std::move(file_system));
-}
-
-} // namespace wvoec_ref
diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp
deleted file mode 100644
index 9195617..0000000
--- a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-#include "oemcrypto_engine_ref.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "clock.h"
-#include "keys.h"
-#include "log.h"
-#include "oemcrypto_key_ref.h"
-#include "oemcrypto_rsa_key_shared.h"
-#include "string_conversions.h"
-
-namespace {
-
-// Lower bits in SessionId are actual session id. The rest higher bits are
-// session type.
-const uint32_t kSessionIdTypeShift = 28;
-const uint32_t kSessionIdMask = (1u << kSessionIdTypeShift) - 1u;
-} // namespace
-
-namespace wvoec_ref {
-
-// Note: The class CryptoEngine is configured at compile time by compiling in
-// different device property files. The methods in this file are generic to
-// all configurations. See the files oemcrypto_engine_device_properties*.cpp
-// for methods that are configured for specific configurations.
-
-CryptoEngine::CryptoEngine(std::unique_ptr&& file_system)
- : root_of_trust_(config_provisioning_method()),
- file_system_(std::move(file_system)),
- usage_table_() {
- ERR_load_crypto_strings();
-}
-
-CryptoEngine::~CryptoEngine() {
- ERR_free_strings();
-}
-
-bool CryptoEngine::Initialize() {
- std::string file_path = GetUsageTimeFileFullPath();
- LoadOfflineTimeInfo(file_path);
- usage_table_.reset(MakeUsageTable());
- return true;
-}
-
-void CryptoEngine::Terminate() {
- std::string file_path = GetUsageTimeFileFullPath();
- SaveOfflineTimeInfo(file_path);
- std::unique_lock lock(session_table_lock_);
- ActiveSessions::iterator it;
- for (it = sessions_.begin(); it != sessions_.end(); ++it) {
- delete it->second;
- }
- sessions_.clear();
- root_of_trust_.Clear();
-}
-
-SessionId CryptoEngine::OpenSession() {
- std::unique_lock lock(session_table_lock_);
- static OEMCrypto_SESSION unique_id = 1;
- SessionId id = ++unique_id;
- // Check if too many sessions have been opened.
- if (SessionTypeBits(id) != 0) {
- return 0;
- }
- // Apply session type to higher bits.
- id = (kSessionTypeOEMCrypto << kSessionIdTypeShift) | (id & kSessionIdMask);
- sessions_[id] = MakeSession(id);
- return id;
-}
-
-SessionContext* CryptoEngine::MakeSession(SessionId sid) {
- return new SessionContext(this, sid, root_of_trust_.SharedRsaKey());
-}
-
-UsageTable* CryptoEngine::MakeUsageTable() { return new UsageTable(this); }
-
-bool CryptoEngine::DestroySession(SessionId sid) {
- SessionContext* sctx = FindSession(sid);
- std::unique_lock lock(session_table_lock_);
- if (sctx) {
- sessions_.erase(sid);
- delete sctx;
- return true;
- } else {
- return false;
- }
-}
-
-SessionContext* CryptoEngine::FindSession(SessionId sid) {
- std::unique_lock lock(session_table_lock_);
- ActiveSessions::iterator it = sessions_.find(sid);
- if (it != sessions_.end()) {
- return it->second;
- }
- return nullptr;
-}
-
-int64_t CryptoEngine::MonotonicTime() {
- // Use the monotonic clock for times that don't have to be stable across
- // device boots.
- int64_t now =
- wvcdm::Clock().GetCurrentTime() + offline_time_info_.rollback_offset;
- static int64_t then = now;
- if (now < then) {
- LOGW("Clock rollback detected: %ld seconds", then - now);
- offline_time_info_.rollback_offset += then - now;
- now = then;
- }
- then = now;
- return now;
-}
-
-int64_t CryptoEngine::SystemTime() {
- const int64_t current_time = MonotonicTime();
- // Write time info to disk if kTimeInfoUpdateWindowInSeconds has elapsed since
- // last write.
- if (current_time - offline_time_info_.previous_time >
- kTimeInfoUpdateWindowInSeconds) {
- std::string file_path = GetUsageTimeFileFullPath();
- SaveOfflineTimeInfo(file_path);
- }
- return current_time;
-}
-
-std::string CryptoEngine::GetUsageTimeFileFullPath() const {
- std::string file_path;
- // Note: file path is OK for a real implementation, but using security
- // level 1 would be better.
- // TODO(fredgc, jfore): Address how this property is presented to the ref.
- // For now, the file path is empty.
- /*if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
- &file_path)) {
- LOGE("Unable to get base path");
- }*/
- return file_path + kStoredUsageTimeFileName;
-}
-
-bool CryptoEngine::LoadOfflineTimeInfo(const std::string& file_path) {
- memset(&offline_time_info_, 0, sizeof(TimeInfo));
- wvcdm::FileSystem* file_system = file_system_.get();
- if (file_system->Exists(file_path)) {
- std::unique_ptr file =
- file_system->Open(file_path, wvcdm::FileSystem::kReadOnly);
- if (!file) {
- // This error is expected at first initialization.
- LOGE("File open failed (this is expected on first initialization): %s",
- file_path.c_str());
- return false;
- }
- // Load time info from previous call.
- file->Read(reinterpret_cast(&offline_time_info_), sizeof(TimeInfo));
-
- // Detect offline time rollback after loading from disk.
- // Add any time offsets in the past to the current time.
- int64_t current_time = MonotonicTime();
- if (offline_time_info_.previous_time > current_time) {
- // Current time is earlier than the previously saved time. Time has been
- // rolled back. Update the rollback offset.
- offline_time_info_.rollback_offset +=
- offline_time_info_.previous_time - current_time;
- // Keep current time at previous recorded time.
- current_time = offline_time_info_.previous_time;
- }
- // The new previous_time will either stay the same or move forward.
- offline_time_info_.previous_time = current_time;
- }
- return true;
-}
-
-bool CryptoEngine::SaveOfflineTimeInfo(const std::string& file_path) {
- // Add any time offsets in the past to the current time. If there was an
- // earlier offline rollback, the rollback offset will be updated in
- // LoadOfflineTimeInfo(). It guarantees that the current time to be saved
- // will never go back.
- const int64_t current_time = MonotonicTime();
- // The new previous_time will either stay the same or move forward.
- if (current_time > offline_time_info_.previous_time)
- offline_time_info_.previous_time = current_time;
-
- std::unique_ptr file;
- wvcdm::FileSystem* file_system = file_system_.get();
- // Write the current time and offset to disk.
- file = file_system->Open(
- file_path, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
- if (!file) {
- LOGE("File open failed: %s", file_path.c_str());
- return false;
- }
- file->Write(reinterpret_cast(&offline_time_info_), sizeof(TimeInfo));
- return true;
-}
-
-bool CryptoEngine::NonceCollision(uint32_t nonce) {
- for (const auto& session_pair : sessions_) {
- const SessionContext* session = session_pair.second;
- if (nonce == session->nonce()) return true;
- }
- return false;
-}
-
-OEMCrypto_HDCP_Capability CryptoEngine::config_current_hdcp_capability() {
- return config_local_display_only() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1;
-}
-
-OEMCrypto_HDCP_Capability CryptoEngine::config_maximum_hdcp_capability() {
- return HDCP_NO_DIGITAL_OUTPUT;
-}
-
-OEMCryptoResult CryptoEngine::SetDestination(
- const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
- uint8_t subsample_flags) {
- size_t max_length = 0;
- switch (out_description.type) {
- case OEMCrypto_BufferType_Clear:
- destination_ = out_description.buffer.clear.address;
- max_length = out_description.buffer.clear.address_length;
- break;
- case OEMCrypto_BufferType_Secure:
- if (out_description.buffer.secure.handle_length <
- out_description.buffer.secure.offset) {
- LOGE("Secure buffer offset too large: %zu < %zu",
- out_description.buffer.secure.handle_length,
- out_description.buffer.secure.offset);
- return OEMCrypto_ERROR_SHORT_BUFFER;
- }
- destination_ =
- reinterpret_cast(out_description.buffer.secure.handle) +
- out_description.buffer.secure.offset;
- max_length = out_description.buffer.secure.handle_length -
- out_description.buffer.secure.offset;
- break;
- case OEMCrypto_BufferType_Direct:
- // Direct buffer type is only used on some specialized devices where
- // oemcrypto has a direct connection to the screen buffer. It is not,
- // for example, supported on Android.
- destination_ = nullptr;
- break;
- default:
- return OEMCrypto_ERROR_INVALID_CONTEXT;
- }
- const size_t max_allowed = max_sample_size();
- if (max_allowed > 0 &&
- (max_allowed < max_length || max_allowed < data_length)) {
- LOGE("Output too large (or buffer too small).");
- return OEMCrypto_ERROR_OUTPUT_TOO_LARGE;
- }
-
- if (out_description.type != OEMCrypto_BufferType_Direct &&
- max_length < data_length) {
- LOGE("[SetDestination(): OEMCrypto_ERROR_SHORT_BUFFER]");
- return OEMCrypto_ERROR_SHORT_BUFFER;
- }
- adjust_destination(out_description, data_length, subsample_flags);
- if ((out_description.type != OEMCrypto_BufferType_Direct) &&
- (destination_ == nullptr)) {
- return OEMCrypto_ERROR_INVALID_CONTEXT;
- }
- return OEMCrypto_SUCCESS;
-}
-
-uint32_t CryptoEngine::SessionTypeBits(SessionId sid) {
- return sid >> kSessionIdTypeShift;
-}
-
-} // namespace wvoec_ref
diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.h b/oemcrypto/ref/src/oemcrypto_engine_ref.h
deleted file mode 100644
index aadb512..0000000
--- a/oemcrypto/ref/src/oemcrypto_engine_ref.h
+++ /dev/null
@@ -1,254 +0,0 @@
-// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
-// source code may only be used and distributed under the Widevine
-// License Agreement.
-//
-// Reference implementation of OEMCrypto APIs
-//
-#ifndef REF_OEMCRYPTO_ENGINE_REF_H_
-#define REF_OEMCRYPTO_ENGINE_REF_H_
-
-#include
-#include
-#include