Initial v17 Release

Headers and Unit tests have been updated to match the v17 spec.

Documentation can be found here:
https://developers.devsite.corp.google.com/widevine/drm/client/oemcrypto/v17
This commit is contained in:
Fred Gylys-Colwell
2021-12-04 01:13:15 +00:00
parent 8e55868e8a
commit 044a89ef55
131 changed files with 6072 additions and 9038 deletions

19
oem_certificate_generator/oem_certificate.py Normal file → Executable file
View File

@@ -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)

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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.

View File

@@ -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);

View File

@@ -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_

View File

@@ -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",
],

View File

@@ -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

View File

@@ -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

View File

@@ -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 <stdint.h>
#include <iostream>
#include <string>
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_

View File

@@ -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

View File

@@ -17,41 +17,46 @@
#include <cstdint>
#include <string>
#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);

View File

@@ -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);

View File

@@ -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_

View File

@@ -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 <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/*
* 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_

View File

@@ -5,17 +5,21 @@
#ifndef WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
#define WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#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_

View File

@@ -39,13 +39,11 @@ bool ParseRequest(uint32_t message_type,
reinterpret_cast<const uint8_t*>(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<Message*>(blk);
InitMessage(msg, const_cast<uint8_t*>(buf), buf_length);
SetSize(msg, buf_length);
ODK_Message msg = ODK_Message_Create(const_cast<uint8_t*>(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;
}

View File

@@ -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

View File

@@ -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 <typename T, typename S, typename P>
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 <typename T, typename S>
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 <typename T, typename S, typename P>
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<uint8_t> buf(BUF_CAPACITY, 0);
uint8_t blk[SIZE_OF_MESSAGE_STRUCT];
Message* msg = reinterpret_cast<Message*>(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<uint32_t>(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<const char*>(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<uint32_t>(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<ODK_ParsedLicense*>(&parsed_lic), {0}};
if (core_request_sha256.size() != sizeof(license_response.request_hash))
{}, const_cast<ODK_ParsedLicense*>(&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);

View File

@@ -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);
}

View File

@@ -7,6 +7,7 @@
{
'sources': [
'core_message_deserialize.cpp',
'core_message_features.cpp',
'core_message_serialize.cpp',
'core_message_serialize_proto.cpp',
],

View File

@@ -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,

View File

@@ -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 <endian.h> to work.
'_DEFAULT_SOURCE',
],
'direct_dependent_settings': {
'defines': [
# Needed for <endian.h> to work.
'_DEFAULT_SOURCE',
],
'include_dirs': [
'.',
'../include',
'../../include',
],
}
},

View File

@@ -7,6 +7,7 @@
{
'sources': [
'odk.c',
'odk_message.c',
'odk_overflow.c',
'odk_serialize.c',
'odk_timer.c',

View File

@@ -11,11 +11,23 @@ extern "C" {
#if defined(__linux__) || defined(__ANDROID__)
#include <endian.h>
#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 <libkern/OSByteOrder.h>
#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);

View File

@@ -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 <assert.h>
#include <stdio.h>
#include <string.h>
#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;
}

View File

@@ -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 <stddef.h>
#include <stdint.h>
#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_

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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"

View File

@@ -4,233 +4,197 @@
#include "serialization_base.h"
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#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); }

View File

@@ -13,74 +13,27 @@ extern "C" {
#include <stdint.h>
#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"

View File

@@ -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,
}
}

View File

@@ -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: [

View File

@@ -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',

View File

@@ -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<const char*>(in);
@@ -67,8 +68,8 @@ OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message,
return ODK_ParseLicense(message, SIZE_MAX, core_message_length,
static_cast<bool>(a->initial_license_load),
static_cast<bool>(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<Message*>(blk);
InitMessage(msg, const_cast<uint8_t*>(buf), len);
SetSize(msg, len);
Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg);
ODK_Message msg = ODK_Message_Create(const_cast<uint8_t*>(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<const char*>(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<const char*>(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

View File

@@ -7,6 +7,7 @@
#include <memory>
#include <string>
#include "core_message_features.h"
#include "core_message_serialize.h"
#include "fuzzing/odk_fuzz_structs.h"
#include "odk_attributes.h"

View File

@@ -6,13 +6,15 @@
#include <vector>
#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) {

View File

@@ -6,13 +6,15 @@
#include <vector>
#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;

View File

@@ -4,13 +4,12 @@
#include "odk.h"
#include <endian.h> // TODO(b/147944591): use this one? Or odk_endian.h?
#include <cstdlib>
#include <cstring>
#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 <typename T, typename F, typename G>
void ValidateRequest(uint32_t message_type,
const std::vector<ODK_Field>& extra_fields,
@@ -113,12 +134,13 @@ void ValidateRequest(uint32_t message_type,
* G: kdo serializer
*/
template <typename T, typename F, typename G>
void ValidateResponse(ODK_CoreMessage* core_message,
void ValidateResponse(const VersionParameters& versions,
ODK_CoreMessage* core_message,
const std::vector<ODK_Field>& 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<ODK_FieldType>(std::rand() %
static_cast<int>(ODK_NUMTYPES));
fields[i].type = static_cast<ODK_FieldType>(
std::rand() % static_cast<int>(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(&params);
ODK_SetDefaultLicenseResponseParams(&params, 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(&params);
ODK_SetDefaultLicenseResponseParams(&params, 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(&params);
ODK_SetDefaultLicenseResponseParams(&params, 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(&params, 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(&params, 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<VersionParameters> {
protected:
template <typename P>
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(&params);
// save a copy of params.request_hash as it will be zero out during the test
ODK_SetDefaultLicenseResponseParams(&params,
GetParam().response_major_version);
SetRequestVersion(&params);
// 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<ODK_LicenseRequest>(&(params.core_message),
ValidateResponse<ODK_LicenseRequest>(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(&params);
SetRequestVersion(&params);
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<ODK_RenewalRequest>(&(params.core_message),
ValidateResponse<ODK_RenewalRequest>(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(&params);
SetRequestVersion(&params);
// 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<char*>(device_id),
device_id_length);
return CreateCoreProvisioningResponse(params.parsed_provisioning,
return CreateCoreProvisioningResponse(features_, params.parsed_provisioning,
core_request, oemcrypto_core_message);
};
ValidateResponse<ODK_ProvisioningRequest>(&(params.core_message),
ValidateResponse<ODK_ProvisioningRequest>(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<VersionParameters> TestCases() {
std::vector<VersionParameters> 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) {

View File

@@ -4,8 +4,6 @@
#include "odk_test_helper.h"
#include <endian.h>
#include <cstdint>
#include <cstdlib>
#include <cstring>
@@ -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<uint16_t*>(field->value));
const uint16_t u16 =
oemcrypto_htobe16(*static_cast<uint16_t*>(field->value));
memcpy(buf, &u16, sizeof(u16));
break;
}
case ODK_UINT32: {
const uint32_t u32 = htobe32(*static_cast<uint32_t*>(field->value));
const uint32_t u32 =
oemcrypto_htobe32(*static_cast<uint32_t*>(field->value));
memcpy(buf, &u32, sizeof(u32));
break;
}
case ODK_UINT64: {
const uint64_t u64 = htobe64(*static_cast<uint64_t*>(field->value));
const uint64_t u64 =
oemcrypto_htobe64(*static_cast<uint64_t*>(field->value));
memcpy(buf, &u64, sizeof(u64));
break;
}
case ODK_BOOL: {
const bool value = *static_cast<bool*>(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<OEMCrypto_Substring*>(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<uint16_t*>(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<uint32_t*>(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<uint64_t*>(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<bool*>(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_Field> ODK_MakeTotalFields(
const std::vector<ODK_Field>& extra_fields, ODK_CoreMessage* core_message) {
std::vector<ODK_Field> 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<ODK_Field>& fields) {
if (memcmp(s1, s2, n) != 0) {
ODK_CoreMessage core_message;
std::vector<ODK_Field> 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<const char*>(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<uint8_t*>(reinterpret_cast<const uint8_t*>(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<ODK_Field> 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<ODK_Field> 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);
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -8,9 +8,9 @@
'privacy_crypto_impl%': 'boringssl',
'boringssl_libcrypto_path%': '<!(echo $PATH_TO_CDM_DIR)/third_party/boringssl/boringssl.gyp:crypto',
'boringssl_libssl_path%': '<!(echo $PATH_TO_CDM_DIR)/third_party/boringssl/boringssl.gyp:ssl',
'gtest_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gtest',
'gmock_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gmock',
'gmock_main_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/gmock.gyp:gmock_main',
'gtest_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/googletest.gyp:gtest',
'gmock_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/googletest.gyp:gmock',
'gmock_main_dependency': '<!(echo $PATH_TO_CDM_DIR)/third_party/googletest.gyp:gmock_main',
'oemcrypto_dir': '.',
'util_dir': '../util',
'platform_specific_dir': '<!(echo $PATH_TO_CDM_DIR)/linux/src',
@@ -22,9 +22,11 @@
'sources': [
'test/oemcrypto_test_main.cpp',
'odk/src/core_message_deserialize.cpp',
'odk/src/core_message_features.cpp',
'odk/src/core_message_serialize.cpp',
'<(platform_specific_dir)/file_store.cpp',
'<(platform_specific_dir)/log.cpp',
'<(util_dir)/src/cdm_random.cpp',
'<(util_dir)/src/platform.cpp',
'<(util_dir)/src/rw_lock.cpp',
'<(util_dir)/src/string_conversions.cpp',
@@ -35,6 +37,7 @@
'../util/libssl_dependency.gypi',
'test/oemcrypto_unittests.gypi',
'ref/oec_ref.gypi',
'ref/oec_ref_unittests.gypi',
],
'libraries': [
'-lpthread',

View File

@@ -1,5 +0,0 @@
# Reference OEMCrypto
This directory contains a testing-only implementation of OEMCrypto. **This
implementation is *NOT* suitable for production use and must *NOT* be released
on devices.**

View File

@@ -1,48 +0,0 @@
# Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
# source code may only be used and distributed under the Widevine
# License Agreement.
# Define oemcrypto_dir and include this in your target.
{
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/ref/src',
'<(oemcrypto_dir)/odk/include',
'<(util_dir)/include',
],
'direct_dependent_settings': {
'include_dirs': [
'<(oemcrypto_dir)/include',
'<(oemcrypto_dir)/odk/include',
'<(oemcrypto_dir)/../util/include',
],
},
'sources': [
'<(oemcrypto_dir)/ref/src/keys.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_auth_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_engine_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_key_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_keybox_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_ref.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_rsa_key_shared.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_session.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_session_key_table.cpp',
'<(oemcrypto_dir)/ref/src/oemcrypto_usage_table_ref.cpp',
'<(oemcrypto_dir)/ref/src/wvcrc.cpp',
# TODO(fredgc) remove these:
'<(oemcrypto_dir)/ref/src/oemcrypto_engine_device_properties.cpp',
],
'includes': [
'../../util/libcrypto_dependency.gypi',
'../odk/src/odk.gypi',
],
'cflags': [
# TODO(b/172518513): Remove this
'-Wno-error=cast-qual',
],
'cflags_c': [
# TODO(b/159354894): Remove this
'-Wno-error=bad-function-cast',
],
}

View File

@@ -1,10 +0,0 @@
// If you are using a baked-in certificate instead of supporting keyboxes,
// you should have received a keys.cpp from Widevine that replaces this file.
//
// If you are not using a baked-in certificate, then you may ignore this file,
// as it intentionally defines an empty key.
#include "keys.h"
const uint8_t kPrivateKey[] = { 0, };
const size_t kPrivateKeySize = 0;

View File

@@ -1,11 +0,0 @@
// This header is used to access the baked-in certificate if one is in use.
#ifndef KEYS_H_
#define KEYS_H_
#include <stddef.h>
#include <stdint.h>
extern const uint8_t kPrivateKey[];
extern const size_t kPrivateKeySize;
#endif // KEYS_H_

View File

@@ -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

View File

@@ -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 <stddef.h>
#include <stdint.h>
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_

View File

@@ -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 <vector>
#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

View File

@@ -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 <stdint.h>
#include <memory>
#include <vector>
#include <openssl/rsa.h>
#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<uint8_t>& DeviceKey(bool use_real_keybox = false) {
return use_real_keybox ? real_keybox().device_key() :
keybox().device_key();
}
const std::vector<uint8_t>& 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_

View File

@@ -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 <utility>
namespace wvoec_ref {
CryptoEngine* CryptoEngine::MakeCryptoEngine(
std::unique_ptr<wvcdm::FileSystem>&& file_system) {
return new CryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -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 <utility>
namespace wvoec_ref {
class L1CryptoEngine : public CryptoEngine {
public:
explicit L1CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& 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<wvcdm::FileSystem>&& file_system) {
return new L1CryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -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<wvcdm::FileSystem>&& 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<wvcdm::FileSystem>&& file_system) {
return new CertOnlyCryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -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 <string.h>
#include <utility>
#include "log.h"
#include "oem_cert.h"
namespace wvoec_ref {
class Prov30CryptoEngine : public CryptoEngine {
public:
explicit Prov30CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& 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<wvcdm::FileSystem>&& file_system) {
return new Prov30CryptoEngine(std::move(file_system));
}
} // namespace wvoec_ref

View File

@@ -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 <assert.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>
#include <openssl/aes.h>
#include <openssl/err.h>
#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<wvcdm::FileSystem>&& 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<std::mutex> 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<std::mutex> 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<std::mutex> lock(session_table_lock_);
if (sctx) {
sessions_.erase(sid);
delete sctx;
return true;
} else {
return false;
}
}
SessionContext* CryptoEngine::FindSession(SessionId sid) {
std::unique_lock<std::mutex> 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<wvcdm::File> 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<char*>(&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<wvcdm::File> 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<char*>(&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<uint8_t*>(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

View File

@@ -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 <stdint.h>
#include <time.h>
#include <map>
#include <memory>
#include <mutex>
#include <vector>
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h"
#include "file_store.h"
#include "oemcrypto_auth_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_session.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"
namespace wvoec_ref {
typedef std::map<SessionId, SessionContext*> ActiveSessions;
static const std::string kStoredUsageTimeFileName = "StoredUsageTime.dat";
typedef struct {
// The max time recorded
int64_t previous_time;
// If the wall time is rollbacked to before the previous_time, this member
// is updated to reflect the offset.
int64_t rollback_offset;
// Pad the struct so that TimeInfo is a multiple of 16.
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
} TimeInfo;
// Session types are higher (32 - kSessionIdTypeShift) bits in SessionId.
typedef enum SessionType {
kSessionTypeOEMCrypto = 0,
kSessionTypeEntitledKey = 1,
} SessionType;
class CryptoEngine {
public:
static const uint32_t kApiVersion = 16;
static const uint32_t kMinorApiVersion = 4;
static const int64_t kTimeInfoUpdateWindowInSeconds = 300;
// This is like a factory method, except we choose which version to use at
// compile time. It is defined in several source files. The build system
// should choose which one to use by only linking in the correct one.
// NOTE: The caller must instantiate a FileSystem object - ownership
// will be transferred to the new CryptoEngine object.
static CryptoEngine* MakeCryptoEngine(
std::unique_ptr<wvcdm::FileSystem>&& file_system);
virtual ~CryptoEngine();
virtual bool Initialize();
bool ValidRootOfTrust() { return root_of_trust_.Validate(); }
bool InstallKeybox(const uint8_t* keybox, size_t keybox_length) {
return root_of_trust_.InstallKeybox(keybox, keybox_length);
}
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) {
return root_of_trust_.UseTestKeybox(keybox_data, keybox_length);
}
bool LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); }
KeyboxError ValidateKeybox() { return root_of_trust_.ValidateKeybox(); }
const std::vector<uint8_t>& DeviceRootKey() {
return root_of_trust_.DeviceKey();
}
const std::vector<uint8_t>& DeviceRootId() {
return root_of_trust_.DeviceId();
}
size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); }
const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); }
virtual void Terminate();
virtual SessionId OpenSession();
virtual bool DestroySession(SessionId sid);
SessionContext* FindSession(SessionId sid);
size_t GetNumberOfOpenSessions() { return sessions_.size(); }
size_t GetMaxNumberOfSessions() {
// An arbitrary limit for ref implementation.
static const size_t kMaxSupportedOEMCryptoSessions = 64;
return kMaxSupportedOEMCryptoSessions;
}
// The OEMCrypto system time. Prevents time rollback.
int64_t SystemTime();
// Verify that this nonce does not collide with another nonce in any session.
virtual bool NonceCollision(uint32_t nonce);
// Returns the HDCP version currently in use.
virtual OEMCrypto_HDCP_Capability config_current_hdcp_capability();
// Returns the max HDCP version supported.
virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
// Return true if there might be analog video output enabled.
virtual bool analog_display_active() { return !config_local_display_only(); }
// Return true if there is an analog display, and CGMS A is turned on.
virtual bool cgms_a_active() { return false; }
// Return the analog output flags.
virtual uint32_t analog_output_flags() {
return config_local_display_only() ? OEMCrypto_No_Analog_Output
: OEMCrypto_Supports_Analog_Output;
}
UsageTable& usage_table() { return *(usage_table_.get()); }
wvcdm::FileSystem* file_system() { return file_system_.get(); }
// If config_local_display_only() returns true, we pretend we are using a
// built-in display, instead of HDMI or WiFi output.
virtual bool config_local_display_only() { return false; }
// A closed platform is permitted to use clear buffers.
virtual bool config_closed_platform() { return false; }
// Returns true if the client supports persistent storage of
// offline usage table information.
virtual bool config_supports_usage_table() { return true; }
virtual OEMCrypto_ProvisioningMethod config_provisioning_method() {
return OEMCrypto_Keybox;
}
virtual OEMCryptoResult get_oem_certificate(uint8_t* public_cert,
size_t* public_cert_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
virtual OEMCryptoResult load_oem_private_key(SessionContext* session) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
// Used for OEMCrypto_IsAntiRollbackHwPresent.
virtual bool config_is_anti_rollback_hw_present() { return false; }
// Returns "L3" for a software only library. L1 is for hardware protected
// data paths.
virtual const char* config_security_level() { return "L3"; }
// This should start at 0, and be incremented only when a security patch has
// been applied to the device that fixes a security bug.
virtual uint8_t config_security_patch_level() { return 0; }
// If 0 no restriction, otherwise it's the max subsample size for
// DecryptCENC. This is not the same as the max sample or buffer size.
virtual size_t max_subsample_size() { return 4 * 1024 * 1024; } // 4 MiB
// If 0 no restriction, otherwise it's the max sample size for DecryptCENC.
// This is the same as the max input and output buffer size for DecryptCENC
// and CopyBuffer. It is not the same as the max subsample size.
virtual size_t max_sample_size() { return 16 * 1024 * 1024; } // 16 MiB
virtual bool srm_update_supported() { return false; }
virtual OEMCryptoResult current_srm_version(uint16_t* version) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
virtual OEMCryptoResult load_srm(const uint8_t* buffer,
size_t buffer_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
virtual OEMCryptoResult remove_srm() {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
virtual bool srm_forbidden_device_attached() { return false; }
// Rate limit for nonce generation. Default to 200 nonce/second.
virtual int nonce_flood_count() { return 200; }
// Limit for size of usage table. If this is zero, then the
// size is unlimited -- or limited only by memory size.
virtual size_t max_usage_table_size() { return 0; }
virtual uint32_t resource_rating() { return 1; }
// Set destination pointer based on the output destination description.
OEMCryptoResult SetDestination(
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
uint8_t subsample_flags);
// The current destination.
uint8_t* destination() { return destination_; }
// Subclasses can adjust the destination -- for use in testing.
virtual void adjust_destination(
const OEMCrypto_DestBufferDesc& out_description, size_t data_length,
uint8_t subsample_flags) {}
// Push destination buffer to output -- used by subclasses for testing.
virtual OEMCryptoResult PushDestination(
const OEMCrypto_DestBufferDesc& out_description,
uint8_t subsample_flags) {
return OEMCrypto_SUCCESS;
}
// Get the session type bits from |sid|.
static uint32_t SessionTypeBits(SessionId sid);
protected:
// System clock, measuring time in seconds, including anti-rollback offset.
int64_t MonotonicTime();
bool LoadOfflineTimeInfo(const std::string& file_path);
bool SaveOfflineTimeInfo(const std::string& file_path);
std::string GetUsageTimeFileFullPath() const;
explicit CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system);
virtual SessionContext* MakeSession(SessionId sid);
virtual UsageTable* MakeUsageTable();
uint8_t* destination_;
ActiveSessions sessions_;
AuthenticationRoot root_of_trust_;
std::mutex session_table_lock_;
std::unique_ptr<wvcdm::FileSystem> file_system_;
std::unique_ptr<UsageTable> usage_table_;
TimeInfo offline_time_info_;
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
};
} // namespace wvoec_ref
#endif // REF_OEMCRYPTO_ENGINE_REF_H_

View File

@@ -1,71 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_key_ref.h"
#include "oemcrypto_types.h"
#include <string.h>
#include <vector>
#include "log.h"
namespace wvoec_ref {
bool KeyControlBlock::Validate() {
if (memcmp(verification_, "kctl", 4) && // original verification
memcmp(verification_, "kc09", 4) && // add in version 9 api
memcmp(verification_, "kc10", 4) && // add in version 10 api
memcmp(verification_, "kc11", 4) && // add in version 11 api
memcmp(verification_, "kc12", 4) && // add in version 12 api
memcmp(verification_, "kc13", 4) && // add in version 13 api
memcmp(verification_, "kc14", 4) && // add in version 14 api
memcmp(verification_, "kc15", 4) && // add in version 15 api
memcmp(verification_, "kc16", 4)) { // add in version 16 api
LOGE("KCB: BAD verification string: %4.4s", verification_);
valid_ = false;
} else {
valid_ = true;
}
return valid_;
}
// This extracts 4 bytes in network byte order to a 32 bit integer in
// host byte order.
uint32_t KeyControlBlock::ExtractField(const std::vector<uint8_t>& str,
int idx) {
int bidx = idx * 4;
uint32_t t = static_cast<unsigned char>(str[bidx]) << 24;
t |= static_cast<unsigned char>(str[bidx + 1]) << 16;
t |= static_cast<unsigned char>(str[bidx + 2]) << 8;
t |= static_cast<unsigned char>(str[bidx + 3]);
return t;
}
KeyControlBlock::KeyControlBlock(
const std::vector<uint8_t>& key_control_string) {
if (key_control_string.size() < wvoec::KEY_CONTROL_SIZE) {
LOGE("KCB: BAD Size: %zu (not %zu)", key_control_string.size(),
wvoec::KEY_CONTROL_SIZE);
return;
}
memcpy(verification_, &key_control_string[0], 4);
duration_ = ExtractField(key_control_string, 1);
nonce_ = ExtractField(key_control_string, 2);
control_bits_ = ExtractField(key_control_string, 3);
Validate();
}
void Key::UpdateDuration(const KeyControlBlock& control) {
control_.set_duration(control.duration());
}
void KeyControlBlock::RequireLocalDisplay() {
// Set all bits to require HDCP Local Display Only.
control_bits_ |= wvoec::kControlHDCPVersionMask;
}
} // namespace wvoec_ref

View File

@@ -1,87 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_KEY_REF_H_
#define OEMCRYPTO_KEY_REF_H_
#include <stdint.h>
#include <string>
#include <vector>
namespace wvoec_ref {
class KeyControlBlock {
public:
KeyControlBlock(const std::vector<uint8_t>& key_control_string);
~KeyControlBlock() {}
bool Validate();
void Invalidate() { valid_ = false; }
bool valid() const { return valid_; }
uint32_t duration() const { return duration_; }
void set_duration(uint32_t duration) { duration_ = duration; }
uint32_t nonce() const { return nonce_; }
const char* verification() const { return verification_; }
uint32_t control_bits() const { return control_bits_; }
void RequireLocalDisplay();
private:
uint32_t ExtractField(const std::vector<uint8_t>& str, int idx);
bool valid_;
char verification_[4];
uint32_t duration_;
uint32_t nonce_;
uint32_t control_bits_;
};
// AES-128 crypto key, or HMAC signing key.
class Key {
public:
Key(const Key& key)
: value_(key.value_), control_(key.control_), ctr_mode_(key.ctr_mode_) {}
Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control)
: value_(key_string), control_(control), ctr_mode_(true){};
virtual ~Key() {};
void UpdateDuration(const KeyControlBlock& control);
virtual const std::vector<uint8_t>& value() const { return value_; }
const KeyControlBlock& control() const { return control_; }
bool ctr_mode() const { return ctr_mode_; }
void set_ctr_mode(bool ctr_mode) { ctr_mode_ = ctr_mode; }
private:
std::vector<uint8_t> value_;
KeyControlBlock control_;
bool ctr_mode_;
};
// AES-256 entitlement key. |Key| holds the entitlement key. |EntitlementKey|
// holds the content key.
class EntitlementKey : public Key {
public:
EntitlementKey(const Key& key) : Key(key) {}
~EntitlementKey() override {}
const std::vector<uint8_t>& value() const override { return content_key_; }
const std::vector<uint8_t>& content_key() { return content_key_; }
const std::vector<uint8_t>& content_key_id() { return content_key_id_; }
const std::vector<uint8_t>& entitlement_key() { return Key::value(); }
bool SetContentKey(const std::vector<uint8_t>& content_key_id,
const std::vector<uint8_t>& content_key) {
content_key_.assign(content_key.begin(), content_key.end());
content_key_id_.assign(content_key_id.begin(), content_key_id.end());
return true;
}
private:
std::vector<uint8_t> content_key_;
std::vector<uint8_t> content_key_id_;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_KEY_REF_H_

View File

@@ -1,74 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_keybox_ref.h"
#include <string.h>
#include <cstdint>
#include <string>
#include "log.h"
#include "oemcrypto_types.h"
#include "platform.h"
#include "wvcrc32.h"
namespace wvoec_ref {
WvKeybox::WvKeybox() : loaded_(false) {
static std::string fake_device_id = "device_with_no_keybox";
device_id_.assign(fake_device_id.begin(), fake_device_id.end());
}
KeyboxError WvKeybox::Validate() {
if (!loaded_) {
LOGE("[KEYBOX NOT LOADED]");
return OTHER_ERROR;
}
if (strncmp(reinterpret_cast<char*>(magic_), "kbox", 4) != 0) {
LOGE("[KEYBOX HAS BAD MAGIC]");
return BAD_MAGIC;
}
uint32_t crc_computed;
uint32_t crc_stored;
uint8_t* crc_stored_bytes = (uint8_t*)&crc_stored;
memcpy(crc_stored_bytes, crc_, sizeof(crc_));
wvoec::WidevineKeybox keybox;
memset(&keybox, 0, sizeof(keybox));
memcpy(keybox.device_id_, &device_id_[0], device_id_.size());
memcpy(keybox.device_key_, &device_key_[0], sizeof(keybox.device_key_));
memcpy(keybox.data_, key_data_, sizeof(keybox.data_));
memcpy(keybox.magic_, magic_, sizeof(keybox.magic_));
crc_computed = ntohl(wvcrc32(reinterpret_cast<uint8_t*>(&keybox),
sizeof(keybox) - 4)); // Drop last 4 bytes.
if (crc_computed != crc_stored) {
LOGE("[KEYBOX CRC problem: computed = %08x, stored = %08x]\n",
crc_computed, crc_stored);
return BAD_CRC;
}
return NO_ERROR;
}
bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) {
if (keyBoxLength != 128) {
return false;
}
const wvoec::WidevineKeybox* keybox =
reinterpret_cast<const wvoec::WidevineKeybox*>(buffer);
size_t device_id_length =
strnlen(reinterpret_cast<const char*>(keybox->device_id_), 32);
device_id_.assign(keybox->device_id_, keybox->device_id_ + device_id_length);
device_key_.assign(keybox->device_key_,
keybox->device_key_ + sizeof(keybox->device_key_));
memcpy(key_data_, keybox->data_, sizeof(keybox->data_));
memcpy(magic_, keybox->magic_, sizeof(keybox->magic_));
memcpy(crc_, keybox->crc_, sizeof(keybox->crc_));
loaded_ = true;
return true;
}
} // namespace wvoec_ref

View File

@@ -1,46 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_KEYBOX_REF_H_
#define OEMCRYPTO_KEYBOX_REF_H_
#include "oemcrypto_key_ref.h"
namespace wvoec_ref {
const int DEVICE_KEY_LENGTH = 16;
typedef uint8_t WvKeyboxKey[DEVICE_KEY_LENGTH];
const int KEY_DATA_LENGTH = 72;
typedef uint8_t WvKeyboxKeyData[KEY_DATA_LENGTH];
enum KeyboxError { NO_ERROR, BAD_CRC, BAD_MAGIC, OTHER_ERROR };
// Widevine keybox
class WvKeybox {
public:
WvKeybox();
~WvKeybox() {}
KeyboxError Validate();
const std::vector<uint8_t>& device_id() { return device_id_; }
std::vector<uint8_t>& device_key() { return device_key_; }
const WvKeyboxKeyData& key_data() { return key_data_; }
size_t key_data_length() { return KEY_DATA_LENGTH; }
bool InstallKeybox(const uint8_t* keybox, size_t keyBoxLength);
private:
bool loaded_;
std::vector<uint8_t> device_id_;
std::vector<uint8_t> device_key_;
WvKeyboxKeyData key_data_;
uint8_t magic_[4];
uint8_t crc_[4];
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_KEYBOX_REF_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,101 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_rsa_key_shared.h"
#include <assert.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include "log.h"
namespace wvoec_ref {
void dump_boringssl_error() {
int count = 0;
while (unsigned long err = ERR_get_error()) {
count++;
char buffer[120];
ERR_error_string_n(err, buffer, sizeof(buffer));
LOGE("BoringSSL Error %d -- %lu -- %s", count, err, buffer);
}
LOGE("Reported %d BoringSSL Errors", count);
}
void RSA_shared_ptr::reset() {
if (rsa_key_ && key_owned_) {
RSA_free(rsa_key_);
}
key_owned_ = false;
rsa_key_ = nullptr;
}
bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
assert(buffer != nullptr);
reset();
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
if (bio == nullptr) {
LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]");
return false;
}
bool success = true;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
if (pkcs8_pki == nullptr) {
BIO_reset(bio);
pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
if (pkcs8_pki == nullptr) {
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned nullptr]");
dump_boringssl_error();
success = false;
}
}
EVP_PKEY* evp = nullptr;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == nullptr) {
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned nullptr]");
dump_boringssl_error();
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == nullptr) {
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
success = false;
}
key_owned_ = true;
}
if (evp != nullptr) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != nullptr) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
if (!success) {
return false;
}
switch (RSA_check_key(rsa_key_)) {
case 1: // valid.
return true;
case 0: // not valid.
LOGE("[LoadPkcs8RsaKey(): rsa key not valid]");
dump_boringssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
dump_boringssl_error();
return false;
}
}
} // namespace wvoec_ref

View File

@@ -1,42 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_RSA_KEY_SHARED_H_
#define OEMCRYPTO_RSA_KEY_SHARED_H_
#include <stdint.h>
#include <openssl/rsa.h>
namespace wvoec_ref {
// Shared pointer with specialized destructor. This pointer is only shared
// from a CryptoEngine to a Session -- so we don't have to use full reference
// counting.
class RSA_shared_ptr {
public:
RSA_shared_ptr() : rsa_key_(nullptr), key_owned_(false) {}
~RSA_shared_ptr() { reset(); };
// Explicitly allow copy as share.
explicit RSA_shared_ptr(const RSA_shared_ptr& other) :
rsa_key_(other.rsa_key_), key_owned_(false) {}
RSA* get() { return rsa_key_; }
void reset();
bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length);
private:
void operator=(const RSA_shared_ptr); // disallow assign.
RSA* rsa_key_;
bool key_owned_;
};
// Log errors from BoringSSL.
void dump_boringssl_error();
} // namespace wvoec_ref
#endif // OEMCRYPTO_RSA_KEY_SHARED_H_

File diff suppressed because it is too large Load Diff

View File

@@ -1,306 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef REF_OEMCRYPTO_SESSION_H_
#define REF_OEMCRYPTO_SESSION_H_
#include <stdint.h>
#include <time.h>
#include <map>
#include <vector>
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h"
#include "odk_structs.h"
#include "oemcrypto_auth_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_session_key_table.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"
namespace wvoec_ref {
class CryptoEngine;
typedef uint32_t SessionId;
enum SRMVersionStatus { NoSRMVersion, ValidSRMVersion, InvalidSRMVersion };
// TODO(jfore): Is there a better name?
class SessionContextKeys {
public:
virtual OEMCrypto_LicenseType type() = 0;
virtual size_t size() = 0;
virtual bool Insert(const KeyId& key_id, const Key& key_data) = 0;
virtual Key* Find(const KeyId& key_id) = 0;
virtual Key* FirstKey() = 0;
virtual void Remove(const KeyId& key_id) = 0;
virtual void UpdateDuration(const KeyControlBlock& control) = 0;
// Methods supported exclusively for entitlement keys. Returns false if
// entitlement keys are not found or not supported by the current key table.
// It is the caller's responsibility to check the context.
virtual bool SetContentKey(const KeyId& entitlement_id,
const KeyId& content_key_id,
const std::vector<uint8_t>& content_key) = 0;
virtual EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) = 0;
virtual ~SessionContextKeys() {}
protected:
SessionContextKeys() {}
private:
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContextKeys);
};
class SessionContext {
public:
SessionContext(CryptoEngine* ce, SessionId sid,
const RSA_shared_ptr& rsa_key);
SessionContext() = delete;
virtual ~SessionContext();
bool isValid() { return valid_; }
virtual bool DeriveKeys(const std::vector<uint8_t>& master_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual bool RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message,
size_t message_length,
size_t* core_message_length,
uint8_t* signature,
size_t* signature_length);
virtual OEMCryptoResult PrepAndSignRenewalRequest(uint8_t* message,
size_t message_length,
size_t* core_message_length,
uint8_t* signature,
size_t* signature_length);
virtual OEMCryptoResult PrepAndSignProvisioningRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
uint8_t* signature, size_t* signature_length);
// The size of an RSA signature. This is used when signing as a CAST
// receiver.
size_t RSASignatureSize();
virtual OEMCryptoResult GenerateRSASignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length, RSA_Padding_Scheme padding_scheme);
virtual bool ValidateMessage(const uint8_t* message, size_t message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult DecryptSamples(
const OEMCrypto_SampleDescription* samples, size_t samples_length,
const OEMCrypto_CENCEncryptPatternDesc* pattern);
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
size_t buffer_length, const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer);
OEMCryptoResult Generic_Decrypt(const uint8_t* in_buffer,
size_t buffer_length, const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer);
OEMCryptoResult Generic_Sign(const uint8_t* in_buffer, size_t buffer_length,
OEMCrypto_Algorithm algorithm,
uint8_t* signature, size_t* signature_length);
OEMCryptoResult Generic_Verify(const uint8_t* in_buffer, size_t buffer_length,
OEMCrypto_Algorithm algorithm,
const uint8_t* signature,
size_t signature_length);
virtual OEMCryptoResult LoadLicense(const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length);
virtual OEMCryptoResult LoadKeys(
const uint8_t* message, size_t message_length, const uint8_t* signature,
size_t signature_length, OEMCrypto_Substring enc_mac_keys_iv,
OEMCrypto_Substring enc_mac_keys, size_t num_keys,
const OEMCrypto_KeyObject* key_array, OEMCrypto_Substring pst,
OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type);
virtual OEMCryptoResult LoadKeysNoSignature(
const uint8_t* message, size_t message_length,
OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys,
size_t num_keys, const OEMCrypto_KeyObject* key_array,
OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data,
OEMCrypto_LicenseType license_type);
virtual OEMCryptoResult LoadEntitledContentKeys(
const uint8_t* message, size_t message_length, size_t key_array_length,
const OEMCrypto_EntitledContentKeyObject* key_array);
virtual OEMCryptoResult InstallKey(
const KeyId& key_id, const std::vector<uint8_t>& key_data,
const std::vector<uint8_t>& key_data_iv,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key,
size_t encrypted_message_key_length);
bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key);
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key);
bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
virtual OEMCryptoResult LoadRenewal(const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length);
virtual OEMCryptoResult RefreshKey(
const KeyId& key_id, const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
virtual bool UpdateMacKeys(const std::vector<uint8_t>& mac_keys,
const std::vector<uint8_t>& iv);
virtual bool QueryKeyControlBlock(const KeyId& key_id, uint32_t* data);
virtual OEMCryptoResult SelectContentKey(const KeyId& key_id,
OEMCryptoCipherMode cipher_mode);
virtual OEMCryptoResult SetDecryptHash(uint32_t frame_number,
const uint8_t* hash,
size_t hash_length);
virtual OEMCryptoResult GetHashErrorCode(uint32_t* failed_frame_number);
const Key* current_content_key(void) { return current_content_key_; }
void set_mac_key_server(const std::vector<uint8_t>& mac_key_server) {
mac_key_server_ = mac_key_server;
}
const std::vector<uint8_t>& mac_key_server() { return mac_key_server_; }
void set_mac_key_client(const std::vector<uint8_t>& mac_key_client) {
mac_key_client_ = mac_key_client;
}
const std::vector<uint8_t>& mac_key_client() { return mac_key_client_; }
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
encryption_key_ = enc_key;
}
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
uint32_t allowed_schemes() const { return allowed_schemes_; }
// Return true if nonce was set.
bool set_nonce(uint32_t nonce);
uint32_t nonce() const { return nonce_values_.nonce; }
ODK_NonceValues& nonce_values() { return nonce_values_; }
bool CheckNonce(uint32_t nonce) const {
return nonce != 0 && nonce == nonce_values_.nonce;
};
virtual OEMCryptoResult CreateNewUsageEntry(uint32_t* usage_entry_number);
virtual OEMCryptoResult LoadUsageEntry(uint32_t index,
const std::vector<uint8_t>& buffer);
virtual OEMCryptoResult UpdateUsageEntry(uint8_t* header_buffer,
size_t* header_buffer_length,
uint8_t* entry_buffer,
size_t* entry_buffer_length);
virtual OEMCryptoResult DeactivateUsageEntry(const std::vector<uint8_t>& pst);
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
uint8_t* buffer, size_t* buffer_length);
OEMCryptoResult MoveEntry(uint32_t new_index);
bool usage_entry_present() const { return usage_entry_ != nullptr; }
protected:
// Signature size of the currently loaded private key.
size_t CertSignatureSize();
// Signature size when using a keybox or OEM Cert's private key.
size_t ROTSignatureSize();
virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
virtual OEMCryptoResult GenerateSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
bool DeriveKey(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& context, int counter,
std::vector<uint8_t>* out);
bool DecryptMessage(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* decrypted,
uint32_t key_size); // AES key size, in bits.
// Either verify the nonce or usage entry, as required by the key control
// block.
OEMCryptoResult CheckNonceOrEntry(const KeyControlBlock& key_control_block);
// If there is a usage entry, check that it is not inactive.
// It also updates the status of the entry if needed.
bool CheckUsageEntry();
// Check that the usage entry status is valid for online use.
OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control);
// Check that the usage entry status is valid for offline use.
OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control);
OEMCryptoResult DecryptSubsample(
const OEMCrypto_SubSampleDescription& subsample,
const uint8_t* cipher_data, uint8_t* clear_data,
OEMCryptoBufferType buffer_type, const uint8_t (&iv)[wvoec::KEY_IV_SIZE],
const OEMCrypto_CENCEncryptPatternDesc* pattern);
OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
const uint8_t* cipher_data,
size_t cipher_data_length, uint8_t* clear_data,
OEMCryptoBufferType buffer_type);
OEMCryptoResult PatternDecryptCBC(
const uint8_t* key, const uint8_t* iv,
const OEMCrypto_CENCEncryptPatternDesc* pattern,
const uint8_t* cipher_data, size_t cipher_data_length,
uint8_t* clear_data);
OEMCryptoResult DecryptCTR(const uint8_t* key_u8, const uint8_t* iv,
size_t block_offset, const uint8_t* cipher_data,
size_t cipher_data_length, uint8_t* clear_data);
// Checks if the key is allowed for the specified type. If there is a usage
// entry, it also checks the usage entry.
OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type,
OEMCryptoBufferType buffer_type);
RSA* rsa_key() { return rsa_key_.get(); }
bool valid_;
CryptoEngine* ce_;
SessionId id_;
std::vector<uint8_t> mac_key_server_;
std::vector<uint8_t> mac_key_client_;
std::vector<uint8_t> encryption_key_;
std::vector<uint8_t> session_key_;
const Key* current_content_key_;
std::unique_ptr<SessionContextKeys> session_keys_;
ODK_NonceValues nonce_values_;
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
RSA_shared_ptr rsa_key_;
uint32_t allowed_schemes_; // for RSA signatures.
bool decrypt_started_; // If the license has been used in this session.
ODK_TimerLimits timer_limits_;
ODK_ClockValues clock_values_;
std::unique_ptr<UsageTableEntry> usage_entry_;
SRMVersionStatus srm_requirements_status_;
enum UsageEntryStatus {
kNoUsageEntry, // No entry loaded for this session.
kUsageEntryNew, // After entry was created.
kUsageEntryLoaded, // After loading entry or loading keys.
};
UsageEntryStatus usage_entry_status_;
// These are used when doing full decrypt path testing.
bool compute_hash_; // True if the current frame needs a hash.
uint32_t current_hash_; // Running CRC hash of frame.
uint32_t given_hash_; // True CRC hash of frame.
uint32_t current_frame_number_; // Current frame for CRC hash.
uint32_t bad_frame_number_; // Frame number with bad hash.
OEMCryptoResult hash_error_; // Error code for first bad frame.
// The bare minimum state machine is to only call each of these function
// categories at most once.
bool state_nonce_created_;
bool state_request_signed_;
bool state_response_loaded_;
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
};
} // namespace wvoec_ref
#endif // REF_OEMCRYPTO_SESSION_H_

View File

@@ -1,105 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_session_key_table.h"
#include "keys.h"
#include "log.h"
namespace wvoec_ref {
bool SessionKeyTable::Insert(const KeyId key_id, const Key& key_data) {
if (keys_.find(key_id) != keys_.end()) return false;
keys_[key_id] = std::unique_ptr<Key>(new Key(key_data));
return true;
}
Key* SessionKeyTable::Find(const KeyId key_id) {
if (keys_.find(key_id) == keys_.end()) {
return nullptr;
}
return keys_[key_id].get();
}
void SessionKeyTable::Remove(const KeyId key_id) {
if (keys_.find(key_id) != keys_.end()) {
keys_.erase(key_id);
}
}
void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
for (KeyMap::iterator it = keys_.begin(); it != keys_.end(); ++it) {
it->second->UpdateDuration(control);
}
}
bool EntitlementKeyTable::Insert(const KeyId key_id, const Key& key_data) {
// |key_id| and |key_data| are for an entitlement key. Insert a new
// entitlement key entry.
if (keys_.find(key_id) != keys_.end()) return false;
keys_[key_id] = std::unique_ptr<EntitlementKey>(new EntitlementKey(key_data));
// If this is a new insertion, we don't have a content key assigned yet.
return true;
}
Key* EntitlementKeyTable::Find(const KeyId key_id) {
// |key_id| refers to a content key.
ContentIdToEntitlementIdMap::iterator it =
contentid_to_entitlementid_.find(key_id);
if (it == contentid_to_entitlementid_.end()) {
return nullptr;
}
if (keys_.find(it->second) == keys_.end()) {
return nullptr;
}
return keys_[it->second].get();
}
void EntitlementKeyTable::Remove(const KeyId key_id) {
// |key_id| refers to a content key. No one currently calls Remove so this
// method is free to change if needed.
ContentIdToEntitlementIdMap::iterator it =
contentid_to_entitlementid_.find(key_id);
if (it == contentid_to_entitlementid_.end()) {
return;
}
keys_.erase(it->second);
contentid_to_entitlementid_.erase(key_id);
}
void EntitlementKeyTable::UpdateDuration(const KeyControlBlock& control) {
for (EntitlementKeyMap::iterator it = keys_.begin(); it != keys_.end();
++it) {
it->second->UpdateDuration(control);
}
}
bool EntitlementKeyTable::SetContentKey(
const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t> content_key) {
EntitlementKeyMap::iterator it = keys_.find(entitlement_id);
if (it == keys_.end()) {
return false;
}
contentid_to_entitlementid_.erase(it->second->content_key_id());
if (!it->second->SetContentKey(content_key_id, content_key)) {
return false;
}
contentid_to_entitlementid_[content_key_id] = entitlement_id;
return true;
}
EntitlementKey* EntitlementKeyTable::GetEntitlementKey(
const KeyId& entitlement_id) {
EntitlementKeyMap::iterator it = keys_.find(entitlement_id);
if (it == keys_.end()) {
return nullptr;
}
return it->second.get();
}
} // namespace wvoec_ref

View File

@@ -1,73 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef REF_OEMCRYPTO_SESSION_KEY_TABLE_H_
#define REF_OEMCRYPTO_SESSION_KEY_TABLE_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <vector>
#include "disallow_copy_and_assign.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_types.h"
namespace wvoec_ref {
class SessionContext;
class CryptoEngine;
class UsageTable;
class UsageTableEntry;
typedef std::vector<uint8_t> KeyId;
typedef std::map<KeyId, std::unique_ptr<Key>> KeyMap;
typedef std::map<KeyId, std::unique_ptr<EntitlementKey>> EntitlementKeyMap;
// SessionKeyTable holds the keys for the current session
class SessionKeyTable {
public:
SessionKeyTable() {}
~SessionKeyTable() {}
bool Insert(const KeyId key_id, const Key& key_data);
Key* Find(const KeyId key_id);
Key* FirstKey() { return keys_.begin()->second.get(); }
void Remove(const KeyId key_id);
void UpdateDuration(const KeyControlBlock& control);
size_t size() const { return keys_.size(); }
private:
KeyMap keys_;
CORE_DISALLOW_COPY_AND_ASSIGN(SessionKeyTable);
};
class EntitlementKeyTable {
typedef std::map<KeyId, KeyId> ContentIdToEntitlementIdMap;
public:
EntitlementKeyTable() {}
~EntitlementKeyTable() {}
bool Insert(const KeyId key_id, const Key& key_data);
Key* Find(const KeyId key_id);
Key* FirstKey() { return keys_.begin()->second.get(); }
void Remove(const KeyId key_id);
void UpdateDuration(const KeyControlBlock& control);
size_t size() const { return contentid_to_entitlementid_.size(); }
bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t> content_key);
EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id);
private:
EntitlementKeyMap keys_;
ContentIdToEntitlementIdMap contentid_to_entitlementid_;
CORE_DISALLOW_COPY_AND_ASSIGN(EntitlementKeyTable);
};
} // namespace wvoec_ref
#endif // REF_OEMCRYPTO_SESSION_KEY_TABLE_H_

View File

@@ -1,710 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_usage_table_ref.h"
#include <string.h>
#include <time.h>
#include <string>
#include <vector>
#include <openssl/aes.h>
#include <openssl/crypto.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include "file_store.h"
#include "log.h"
#include "odk.h"
#include "oemcrypto_engine_ref.h"
// TODO(fredgc): Setting the device files base bath is currently broken as
// wvcdm::Properties is no longer used by the reference code.
//#include "properties.h"
#include "pst_report.h"
#include "string_conversions.h"
namespace wvoec_ref {
namespace {
const size_t kMagicLength = 8;
const char* kEntryVerification = "USEENTRY";
const char* kHeaderVerification = "USEHEADR";
// Offset into a signed block where we start encrypting. We need to
// skip the signature and the iv.
const size_t kEncryptionOffset = SHA256_DIGEST_LENGTH + SHA256_DIGEST_LENGTH;
// A structure that holds an usage entry and its signature.
struct SignedEntryBlock {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t iv[SHA256_DIGEST_LENGTH];
uint8_t verification[kMagicLength];
StoredUsageEntry data;
};
// This has the data in the header of constant size. There is also an array
// of generation numbers.
struct SignedHeaderBlock {
uint8_t signature[SHA256_DIGEST_LENGTH];
uint8_t iv[SHA256_DIGEST_LENGTH];
uint8_t verification[kMagicLength];
int64_t master_generation;
uint64_t count;
};
} // namespace
UsageTableEntry::UsageTableEntry(UsageTable* table, uint32_t index,
int64_t generation)
: usage_table_(table), recent_decrypt_(false), forbid_report_(true) {
memset(&data_, 0, sizeof(data_));
data_.generation_number = generation;
data_.index = index;
}
UsageTableEntry::~UsageTableEntry() { usage_table_->ReleaseEntry(data_.index); }
OEMCryptoResult UsageTableEntry::SetPST(const uint8_t* pst, size_t pst_length) {
if (pst_length > kMaxPSTLength) return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
data_.pst_length = pst_length;
if (!pst || !pst_length) return OEMCrypto_ERROR_INVALID_CONTEXT;
memcpy(data_.pst, pst, pst_length);
data_.time_of_license_received = usage_table_->ce_->SystemTime();
return OEMCrypto_SUCCESS;
}
bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) {
if (pst_length > kMaxPSTLength) return false;
if (data_.pst_length != pst_length) return false;
if (!pst || !pst_length) return false;
return 0 == CRYPTO_memcmp(pst, data_.pst, pst_length);
}
bool UsageTableEntry::VerifyMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client) {
return (server.size() == wvoec::MAC_KEY_SIZE) &&
(client.size() == wvoec::MAC_KEY_SIZE) &&
(0 == CRYPTO_memcmp(&server[0], data_.mac_key_server,
wvoec::MAC_KEY_SIZE)) &&
(0 ==
CRYPTO_memcmp(&client[0], data_.mac_key_client, wvoec::MAC_KEY_SIZE));
}
bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client) {
if ((server.size() != wvoec::MAC_KEY_SIZE) ||
(client.size() != wvoec::MAC_KEY_SIZE))
return false;
memcpy(data_.mac_key_server, &server[0], wvoec::MAC_KEY_SIZE);
memcpy(data_.mac_key_client, &client[0], wvoec::MAC_KEY_SIZE);
return true;
}
void UsageTableEntry::ForbidReport() {
forbid_report_ = true;
data_.generation_number++;
usage_table_->IncrementGeneration();
}
OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
uint8_t* buffer,
size_t* buffer_length) {
if (forbid_report_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
if (recent_decrypt_) return OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE;
if (pst.size() == 0 || pst.size() > kMaxPSTLength ||
pst.size() != data_.pst_length) {
LOGE("ReportUsage: bad pst length = %zu, should be %u.", pst.size(),
data_.pst_length);
return OEMCrypto_ERROR_WRONG_PST;
}
if (CRYPTO_memcmp(&pst[0], data_.pst, data_.pst_length)) {
LOGE("ReportUsage: wrong pst %s, should be %s.",
wvcdm::b2a_hex(pst).c_str(),
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
return OEMCrypto_ERROR_WRONG_PST;
}
const size_t length_needed =
wvcdm::Unpacked_PST_Report::report_size(pst.size());
if (*buffer_length < length_needed) {
*buffer_length = length_needed;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (!buffer) {
LOGE("ReportUsage: buffer was null pointer.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
wvcdm::Unpacked_PST_Report pst_report(buffer);
const int64_t now = usage_table_->ce_->SystemTime();
pst_report.set_seconds_since_license_received(now -
data_.time_of_license_received);
pst_report.set_seconds_since_first_decrypt(now - data_.time_of_first_decrypt);
pst_report.set_seconds_since_last_decrypt(now - data_.time_of_last_decrypt);
pst_report.set_status(data_.status);
pst_report.set_clock_security_level(kSecureTimer);
pst_report.set_pst_length(data_.pst_length);
memcpy(pst_report.pst(), data_.pst, data_.pst_length);
unsigned int md_len = SHA_DIGEST_LENGTH;
if (!HMAC(EVP_sha1(), data_.mac_key_client, wvoec::MAC_KEY_SIZE,
buffer + SHA_DIGEST_LENGTH, length_needed - SHA_DIGEST_LENGTH,
pst_report.signature(), &md_len)) {
LOGE("ReportUsage: could not compute signature.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
void UsageTableEntry::UpdateAndIncrement(ODK_ClockValues* clock_values) {
if (recent_decrypt_) {
data_.time_of_last_decrypt = usage_table_->ce_->SystemTime();
recent_decrypt_ = false;
}
data_.time_of_license_received = clock_values->time_of_license_signed;
data_.time_of_first_decrypt = clock_values->time_of_first_decrypt;
// Use the most recent time_of_last_decrypt.
if (static_cast<uint64_t>(data_.time_of_last_decrypt) <
clock_values->time_of_last_decrypt) {
// For the reference implementation, we update the clock_values on every
// decrypt.
data_.time_of_last_decrypt = clock_values->time_of_last_decrypt;
} else {
// For this reference implementation of OEMCrypto, we regularly update
// clock_values->time_of_last_decrypt and we could just update
// data_.time_of_last_decrypt here. However, I'm including the line below to
// make it clear that you could do it the other way around. When this
// function is called, the two values should be synced so that the usage
// entry can be saved with the correct value.
clock_values->time_of_last_decrypt = data_.time_of_last_decrypt;
}
data_.status = clock_values->status;
data_.generation_number++;
usage_table_->IncrementGeneration();
forbid_report_ = false;
}
OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce,
SessionContext* session,
uint8_t* signed_buffer,
size_t buffer_size) {
// buffer_size was determined by calling function.
if (buffer_size != SignedEntrySize()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
std::vector<uint8_t> clear_buffer(buffer_size);
memset(&clear_buffer[0], 0, buffer_size);
memset(signed_buffer, 0, buffer_size);
SignedEntryBlock* clear =
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
SignedEntryBlock* encrypted =
reinterpret_cast<SignedEntryBlock*>(signed_buffer);
clear->data = data_; // Copy the current data.
memcpy(clear->verification, kEntryVerification, kMagicLength);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce->DeviceRootKey();
if (key.empty()) {
LOGE("SaveUsageEntry: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Encrypt the entry.
if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) {
LOGE("SaveUsageEntry: Could not generate iv.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
// Sign the entry.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(),
&signed_buffer[SHA256_DIGEST_LENGTH],
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
&sig_length)) {
LOGE("SaveUsageEntry: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values) {
if (buffer.size() < SignedEntrySize()) return OEMCrypto_ERROR_SHORT_BUFFER;
if (buffer.size() > SignedEntrySize())
LOGW("LoadUsageTableEntry: buffer is large. %zu > %zu", buffer.size(),
SignedEntrySize());
std::vector<uint8_t> clear_buffer(buffer.size());
SignedEntryBlock* clear =
reinterpret_cast<SignedEntryBlock*>(&clear_buffer[0]);
const SignedEntryBlock* encrypted =
reinterpret_cast<const SignedEntryBlock*>(&buffer[0]);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce->DeviceRootKey();
if (key.empty()) {
LOGE("LoadUsageEntry: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
&sig_length)) {
LOGE("LoadUsageEntry: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (CRYPTO_memcmp(clear->signature, encrypted->signature,
SHA256_DIGEST_LENGTH)) {
LOGE("LoadUsageEntry: Signature did not match.");
LOGE("LoadUsageEntry: Invalid signature given: %s",
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
LOGE("LoadUsageEntry: Invalid signature computed: %s",
wvcdm::HexEncode(clear->signature, sig_length).c_str());
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Next, decrypt the entry.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
AES_DECRYPT);
// Check the verification string is correct.
if (memcmp(kEntryVerification, clear->verification, kMagicLength)) {
LOGE("LoadUsageEntry: Invalid magic: %s=%8.8s expected: %s=%8.8s",
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kEntryVerification),
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kEntryVerification));
return OEMCrypto_ERROR_BAD_MAGIC;
}
// Check that the index is correct.
if (index != clear->data.index) {
LOGE("LoadUsageEntry: entry says index is %u, not %u", clear->data.index,
index);
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (clear->data.status > kInactiveUnused) {
LOGE("LoadUsageEntry: entry has bad status %d", clear->data.status);
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
data_ = clear->data;
return ODK_ReloadClockValues(
clock_values, data_.time_of_license_received, data_.time_of_first_decrypt,
data_.time_of_last_decrypt, data_.status, ce->SystemTime());
}
size_t UsageTableEntry::SignedEntrySize() {
size_t base = sizeof(SignedEntryBlock);
// round up to make even number of blocks:
size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1;
return blocks * wvoec::KEY_IV_SIZE;
}
UsageTable::~UsageTable() {}
size_t UsageTable::SignedHeaderSize(size_t count) {
size_t base = sizeof(SignedHeaderBlock) + count * sizeof(int64_t);
// round up to make even number of blocks:
size_t blocks = (base - 1) / wvoec::KEY_IV_SIZE + 1;
return blocks * wvoec::KEY_IV_SIZE;
}
OEMCryptoResult UsageTable::UpdateUsageEntry(
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
size_t* header_buffer_length, uint8_t* entry_buffer,
size_t* entry_buffer_length, ODK_ClockValues* clock_values) {
size_t signed_header_size = SignedHeaderSize(generation_numbers_.size());
if (*entry_buffer_length < UsageTableEntry::SignedEntrySize() ||
*header_buffer_length < signed_header_size) {
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
*header_buffer_length = signed_header_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*entry_buffer_length = UsageTableEntry::SignedEntrySize();
*header_buffer_length = signed_header_size;
if ((!header_buffer) || (!entry_buffer))
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
entry->UpdateAndIncrement(clock_values);
generation_numbers_[entry->index()] = entry->generation_number();
OEMCryptoResult result =
entry->SaveData(ce_, session, entry_buffer, *entry_buffer_length);
if (result != OEMCrypto_SUCCESS) return result;
result = SaveUsageTableHeader(header_buffer, *header_buffer_length);
return result;
}
UsageTableEntry* UsageTable::MakeEntry(uint32_t index) {
return new UsageTableEntry(this, index, master_generation_number_);
}
OEMCryptoResult UsageTable::CreateNewUsageEntry(
SessionContext* session, std::unique_ptr<UsageTableEntry>* entry,
uint32_t* usage_entry_number) {
if (!header_loaded_) {
LOGE("CreateNewUsageEntry: Header not loaded.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const size_t index = generation_numbers_.size();
const size_t max = ce_->max_usage_table_size();
if (max > 0 && index >= max) {
LOGE("Too many usage entries: %zu/%zu", index, max);
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
UsageTableEntry* new_entry = MakeEntry(index);
generation_numbers_.push_back(master_generation_number_);
sessions_.push_back(session);
master_generation_number_++;
entry->reset(new_entry);
*usage_entry_number = index;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult UsageTable::LoadUsageEntry(
SessionContext* session, std::unique_ptr<UsageTableEntry>* entry,
uint32_t index, const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values) {
if (!header_loaded_) {
LOGE("LoadUsageEntry: Header not loaded.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (index >= generation_numbers_.size())
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (sessions_[index]) {
LOGE("LoadUsageEntry: index %u used by other session.", index);
return OEMCrypto_ERROR_INVALID_SESSION;
}
const size_t max = ce_->max_usage_table_size();
if (max > 0 && index >= max) {
LOGE("Too many usage entries: %u/%zu", index, max);
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::unique_ptr<UsageTableEntry> new_entry(MakeEntry(index));
OEMCryptoResult status =
new_entry->LoadData(ce_, index, buffer, clock_values);
if (status != OEMCrypto_SUCCESS) {
return status;
}
if (new_entry->generation_number() != generation_numbers_[index]) {
LOGE("Generation SKEW: %ld -> %ld", new_entry->generation_number(),
generation_numbers_[index]);
if ((new_entry->generation_number() + 1 < generation_numbers_[index]) ||
(new_entry->generation_number() - 1 > generation_numbers_[index])) {
return OEMCrypto_ERROR_GENERATION_SKEW;
}
status = OEMCrypto_WARNING_GENERATION_SKEW;
}
sessions_[index] = session;
*entry = std::move(new_entry);
return status;
}
OEMCryptoResult UsageTable::ShrinkUsageTableHeader(
uint32_t new_table_size, uint8_t* header_buffer,
size_t* header_buffer_length) {
if (new_table_size > generation_numbers_.size()) {
LOGE("OEMCrypto_ShrinkUsageTableHeader: %u > %zu", new_table_size,
generation_numbers_.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
size_t signed_header_size = SignedHeaderSize(new_table_size);
if (*header_buffer_length < signed_header_size) {
*header_buffer_length = signed_header_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*header_buffer_length = signed_header_size;
if (!header_buffer) {
LOGE("OEMCrypto_ShrinkUsageTableHeader: buffer null.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
for (size_t i = new_table_size; i < sessions_.size(); ++i) {
if (sessions_[i]) {
LOGE("ShrinkUsageTableHeader: session open for %zu", i);
return OEMCrypto_ERROR_ENTRY_IN_USE;
}
}
generation_numbers_.resize(new_table_size);
sessions_.resize(new_table_size);
master_generation_number_++;
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
}
OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer,
size_t buffer_size) {
if (!SaveGenerationNumber()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
size_t count = generation_numbers_.size();
// buffer_size was determined by calling function.
if (buffer_size != SignedHeaderSize(count))
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
std::vector<uint8_t> clear_buffer(buffer_size);
memset(&clear_buffer[0], 0, buffer_size);
memset(signed_buffer, 0, buffer_size);
SignedHeaderBlock* clear =
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
SignedHeaderBlock* encrypted =
reinterpret_cast<SignedHeaderBlock*>(signed_buffer);
// Pack the clear data into the clear buffer.
memcpy(clear->verification, kHeaderVerification, kMagicLength);
clear->master_generation = master_generation_number_;
clear->count = count;
// This points to the variable size part of the buffer.
int64_t* stored_generations =
reinterpret_cast<int64_t*>(&clear_buffer[sizeof(SignedHeaderBlock)]);
std::copy(generation_numbers_.begin(), generation_numbers_.begin() + count,
stored_generations);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce_->DeviceRootKey();
if (key.empty()) {
LOGE("SaveUsageTableHeader: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Encrypt the entry.
if (RAND_bytes(encrypted->iv, wvoec::KEY_IV_SIZE) != 1) {
LOGE("SaveUsageHeader: Could not generate iv entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; // working iv buffer.
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(
&clear_buffer[kEncryptionOffset], &signed_buffer[kEncryptionOffset],
buffer_size - kEncryptionOffset, &aes_key, iv_buffer, AES_ENCRYPT);
// Sign the entry.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(),
&signed_buffer[SHA256_DIGEST_LENGTH],
buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature,
&sig_length)) {
LOGE("SaveUsageHeader: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult UsageTable::LoadUsageTableHeader(
const std::vector<uint8_t>& buffer) {
if (!LoadGenerationNumber(false)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (buffer.size() < SignedHeaderSize(0)) return OEMCrypto_ERROR_SHORT_BUFFER;
size_t max = ce_->max_usage_table_size();
if (max > 0 && buffer.size() > SignedHeaderSize(max)) {
LOGE("Header too big: %zu bytes/%zu bytes", buffer.size(),
SignedHeaderSize(max));
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
std::vector<uint8_t> clear_buffer(buffer.size());
SignedHeaderBlock* clear =
reinterpret_cast<SignedHeaderBlock*>(&clear_buffer[0]);
const SignedHeaderBlock* encrypted =
reinterpret_cast<const SignedHeaderBlock*>(&buffer[0]);
// This should be encrypted and signed with a device specific key.
// For the reference implementation, I'm just going to use the keybox key.
const std::vector<uint8_t>& key = ce_->DeviceRootKey();
if (key.empty()) {
LOGE("LoadUsageTableHeader: DeviceRootKey is unexpectedly empty.");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Verify the signature of the usage entry. Sign encrypted into clear buffer.
unsigned int sig_length = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH],
buffer.size() - SHA256_DIGEST_LENGTH, clear->signature,
&sig_length)) {
LOGE("LoadUsageTableHeader: Could not sign entry.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (CRYPTO_memcmp(clear->signature, encrypted->signature,
SHA256_DIGEST_LENGTH)) {
LOGE("LoadUsageTableHeader: Signature did not match.");
LOGE("LoadUsageTableHeader: Invalid signature given: %s",
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
LOGE("LoadUsageTableHeader: Invalid signature computed: %s",
wvcdm::HexEncode(clear->signature, sig_length).c_str());
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
// Next, decrypt the entry.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, encrypted->iv, wvoec::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&key[0], 128, &aes_key);
AES_cbc_encrypt(&buffer[kEncryptionOffset], &clear_buffer[kEncryptionOffset],
buffer.size() - kEncryptionOffset, &aes_key, iv_buffer,
AES_DECRYPT);
// Check the verification string is correct.
if (memcmp(kHeaderVerification, clear->verification, kMagicLength)) {
LOGE("LoadUsageTableHeader: Invalid magic: %s=%8.8s expected: %s=%8.8s",
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kHeaderVerification),
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kHeaderVerification));
return OEMCrypto_ERROR_BAD_MAGIC;
}
// Check that size is correct, now that we know what it should be.
if (buffer.size() < SignedHeaderSize(clear->count)) {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (buffer.size() > SignedHeaderSize(clear->count)) {
LOGW("LoadUsageTableHeader: buffer is large. %zu > %zu", buffer.size(),
SignedHeaderSize(clear->count));
}
OEMCryptoResult status = OEMCrypto_SUCCESS;
if (clear->master_generation != master_generation_number_) {
LOGE("Generation SKEW: %ld -> %ld", clear->master_generation,
master_generation_number_);
if ((clear->master_generation + 1 < master_generation_number_) ||
(clear->master_generation - 1 > master_generation_number_)) {
return OEMCrypto_ERROR_GENERATION_SKEW;
}
status = OEMCrypto_WARNING_GENERATION_SKEW;
}
int64_t* stored_generations =
reinterpret_cast<int64_t*>(&clear_buffer[0] + sizeof(SignedHeaderBlock));
generation_numbers_.assign(stored_generations,
stored_generations + clear->count);
sessions_.clear();
sessions_.resize(clear->count);
header_loaded_ = true;
return status;
}
OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry,
uint32_t new_index) {
if (new_index >= generation_numbers_.size()) {
LOGE("MoveEntry: index beyond end of usage table %u >= %zu", new_index,
generation_numbers_.size());
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (sessions_[new_index]) {
LOGE("MoveEntry: session open for %u", new_index);
return OEMCrypto_ERROR_ENTRY_IN_USE;
}
if (!entry) {
LOGE("MoveEntry: null entry");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
sessions_[new_index] = sessions_[entry->index()];
sessions_[entry->index()] = 0;
entry->set_index(new_index);
generation_numbers_[new_index] = master_generation_number_;
entry->set_generation_number(master_generation_number_);
master_generation_number_++;
return OEMCrypto_SUCCESS;
}
void UsageTable::IncrementGeneration() {
master_generation_number_++;
SaveGenerationNumber();
}
bool UsageTable::SaveGenerationNumber() {
wvcdm::FileSystem* file_system = ce_->file_system();
std::string path;
// Note: this path is OK for a real implementation, but using security level 1
// would be better.
// TODO(jfore, rfrias): Address how this property is presented to the ref.
// For now, the path is empty.
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
&path)) {
LOGE("UsageTable: Unable to get base path");
return false;
}*/
// On a real implementation, you should NOT put the generation number in
// a file in user space. It should be stored in secure memory.
std::string filename = path + "GenerationNumber.dat";
auto file = file_system->Open(
filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
if (!file) {
LOGE("UsageTable: File open failed: %s", path.c_str());
return false;
}
file->Write(reinterpret_cast<char*>(&master_generation_number_),
sizeof(int64_t));
return true;
}
bool UsageTable::LoadGenerationNumber(bool or_make_new_one) {
wvcdm::FileSystem* file_system = ce_->file_system();
std::string path;
// Note: this path is OK for a real implementation, but using security level 1
// would be better.
// TODO(jfore, rfrias): Address how this property is presented to the ref.
// For now, the path is empty.
/*if (!Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
&path)) {
LOGE("UsageTable: Unable to get base path");
return false;
}*/
// On a real implementation, you should NOT put the generation number in
// a file in user space. It should be stored in secure memory.
std::string filename = path + "GenerationNumber.dat";
auto file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
if (!file) {
if (or_make_new_one) {
return RAND_bytes(reinterpret_cast<uint8_t*>(&master_generation_number_),
sizeof(int64_t)) == 1;
}
LOGE("UsageTable: File open failed: %s (clearing table)", path.c_str());
master_generation_number_ = 0;
return false;
}
file->Read(reinterpret_cast<char*>(&master_generation_number_),
sizeof(int64_t));
return true;
}
OEMCryptoResult UsageTable::CreateUsageTableHeader(
uint8_t* header_buffer, size_t* header_buffer_length) {
size_t signed_header_size = SignedHeaderSize(0);
if (*header_buffer_length < signed_header_size) {
*header_buffer_length = signed_header_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*header_buffer_length = signed_header_size;
if (!LoadGenerationNumber(true)) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
// Make sure there are no entries that are currently tied to an open session.
for (size_t i = 0; i < sessions_.size(); ++i) {
if (sessions_[i] != nullptr) {
LOGE("CreateUsageTableHeader: index %zu used by session.", i);
return OEMCrypto_ERROR_INVALID_SESSION;
}
}
sessions_.clear();
generation_numbers_.clear();
header_loaded_ = true;
return SaveUsageTableHeader(header_buffer, *header_buffer_length);
}
} // namespace wvoec_ref

View File

@@ -1,132 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_USAGE_TABLE_REF_H_
#define OEMCRYPTO_USAGE_TABLE_REF_H_
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "OEMCryptoCENC.h"
#include "odk_structs.h"
#include "oemcrypto_types.h"
#include "openssl/sha.h"
namespace wvoec_ref {
class SessionContext;
class CryptoEngine;
class UsageTable;
const size_t kMaxPSTLength = 255;
// This is the data we store offline.
struct StoredUsageEntry {
int64_t generation_number;
int64_t time_of_license_received;
int64_t time_of_first_decrypt;
int64_t time_of_last_decrypt;
enum OEMCrypto_Usage_Entry_Status status;
uint8_t mac_key_server[wvoec::MAC_KEY_SIZE];
uint8_t mac_key_client[wvoec::MAC_KEY_SIZE];
uint32_t index;
uint8_t pst[kMaxPSTLength+1]; // add 1 for padding.
uint8_t pst_length;
};
class UsageTableEntry {
public:
UsageTableEntry(UsageTable* table, uint32_t index, int64_t generation);
virtual ~UsageTableEntry(); // Free memory, remove reference in header.
bool Inactive() { return data_.status >= kInactive; }
// Mark this entry as modified and forbid a usage report until the data has
// been saved. This is done on important events like first decrypt and
// deactivation.
void ForbidReport();
OEMCryptoResult SetPST(const uint8_t* pst, size_t pst_length);
bool VerifyPST(const uint8_t* pst, size_t pst_length);
bool VerifyMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client);
bool SetMacKeys(const std::vector<uint8_t>& server,
const std::vector<uint8_t>& client);
virtual OEMCryptoResult ReportUsage(const std::vector<uint8_t>& pst,
uint8_t* buffer, size_t* buffer_length);
virtual void UpdateAndIncrement(ODK_ClockValues* clock_values);
// Save all data to the given buffer. This should be called after updating the
// data.
OEMCryptoResult SaveData(CryptoEngine* ce, SessionContext* session,
uint8_t* signed_buffer, size_t buffer_size);
// Load all data from the buffer, and then update clock_values.
OEMCryptoResult LoadData(CryptoEngine* ce, uint32_t index,
const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values);
int64_t generation_number() { return data_.generation_number; }
void set_generation_number(int64_t value) { data_.generation_number = value; }
void set_index(int32_t index) { data_.index = index; }
uint32_t index() { return data_.index; }
void set_recent_decrypt(bool recent_decrypt) {
recent_decrypt_ = recent_decrypt;
}
static size_t SignedEntrySize();
const uint8_t* mac_key_server() const { return data_.mac_key_server; }
const uint8_t* mac_key_client() const { return data_.mac_key_client; }
protected:
UsageTable* usage_table_; // Owner of this object.
bool recent_decrypt_;
bool forbid_report_;
StoredUsageEntry data_;
};
class UsageTable {
public:
explicit UsageTable(CryptoEngine* ce) : ce_(ce), header_loaded_(false){};
virtual ~UsageTable();
OEMCryptoResult CreateNewUsageEntry(SessionContext* session,
std::unique_ptr<UsageTableEntry>* entry,
uint32_t* usage_entry_number);
OEMCryptoResult LoadUsageEntry(SessionContext* session,
std::unique_ptr<UsageTableEntry>* entry,
uint32_t index,
const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values);
OEMCryptoResult UpdateUsageEntry(
SessionContext* session, UsageTableEntry* entry, uint8_t* header_buffer,
size_t* header_buffer_length, uint8_t* entry_buffer,
size_t* entry_buffer_length, ODK_ClockValues* clock_values);
OEMCryptoResult MoveEntry(UsageTableEntry* entry, uint32_t new_index);
OEMCryptoResult CreateUsageTableHeader(uint8_t* header_buffer,
size_t* header_buffer_length);
OEMCryptoResult LoadUsageTableHeader(const std::vector<uint8_t>& buffer);
OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size,
uint8_t* header_buffer,
size_t* header_buffer_length);
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
void IncrementGeneration();
static size_t SignedHeaderSize(size_t count);
protected:
virtual UsageTableEntry* MakeEntry(uint32_t index);
virtual OEMCryptoResult SaveUsageTableHeader(uint8_t* signed_buffer,
size_t buffer_size);
virtual bool SaveGenerationNumber();
virtual bool LoadGenerationNumber(bool or_make_new_one);
CryptoEngine* ce_;
bool header_loaded_;
int64_t master_generation_number_;
std::vector<int64_t> generation_numbers_;
std::vector<SessionContext*> sessions_;
friend class UsageTableEntry;
};
} // namespace wvoec_ref
#endif // OEMCRYPTO_USAGE_TABLE_REF_H_

View File

@@ -1,88 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
//
#include "platform.h"
#include "wvcrc32.h"
namespace wvoec_ref {
#define INIT_CRC32 0xffffffff
uint32_t wvrunningcrc32(const uint8_t* p_begin, size_t i_count,
uint32_t i_crc) {
constexpr uint32_t CRC32[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
/* Calculate the CRC */
while (i_count > 0) {
i_crc = (i_crc << 8) ^ CRC32[(i_crc >> 24) ^ ((uint32_t) * p_begin)];
p_begin++;
i_count--;
}
return(i_crc);
}
uint32_t wvcrc32(const uint8_t* p_begin, size_t i_count) {
return(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
uint32_t wvcrc32Init() {
return INIT_CRC32;
}
uint32_t wvcrc32Cont(const uint8_t* p_begin, size_t i_count,
uint32_t prev_crc) {
return(wvrunningcrc32(p_begin, i_count, prev_crc));
}
uint32_t wvcrc32n(const uint8_t* p_begin, size_t i_count) {
return htonl(wvrunningcrc32(p_begin, i_count, INIT_CRC32));
}
} // namespace wvoec_ref

View File

@@ -1,23 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
//
#ifndef WVCRC32_H_
#define WVCRC32_H_
#include <stdint.h>
namespace wvoec_ref {
uint32_t wvcrc32(const uint8_t* p_begin, size_t i_count);
uint32_t wvcrc32Init();
uint32_t wvcrc32Cont(const uint8_t* p_begin, size_t i_count, uint32_t prev_crc);
// Convert to network byte order
uint32_t wvcrc32n(const uint8_t* p_begin, size_t i_count);
} // namespace wvoec_ref
#endif // WVCRC32_H_

View File

@@ -85,12 +85,12 @@ OEMCrypto implementations on linux.
$ ./out/Default/oemcrypto_unittests --generate_corpus \
--gtest_filter=-"*Huge*"
```
* There can be lot of duplicate corpus files that are generated from unit
tests. We can minimize the corpus files to only a subset of files that
cover unique paths within the API when run using fuzzer. Run following
command to minimize corpus.
```shell
$ cd /path/to/cdm/repo
# build fuzzer binaries
@@ -128,7 +128,7 @@ OEMCrypto implementations on linux.
* Build and test fuzz scripts locally using following commands. The build
script builds fuzz binaries for both oemcrypto reference implementation
as well as odkitee implementation.
as well as opk implementation.
```shell
$ cd PATH_TO_CDM_DIR

View File

@@ -1,4 +1,16 @@
#!/bin/bash
echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX"
echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX"
echo "TODO(b/192560463): The OPK does not build because it expects an"
echo "older version of the ODK library. The ipc_ref tests do not work because"
echo "the reference code is v17 but OPK is v16."
# Also, if you are fixing this script, it should probably be moved to the jenkins
# directory, so that it is next to all the other scripts that Luci runs.
echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX"
echo "XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX---XXX"
exit 0
set -ex
export CXX=clang++
@@ -9,4 +21,11 @@ export PYTHONPATH="$PYTHONPATH:$PATH_TO_CDM_DIR/third_party"
python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \
--depth=$(pwd) oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp
ninja -C out/Default
ninja -C out/Default
# oemcrypto_opk_fuzztests.gypi has flags to instrument all the gyp targets
# with fuzzer flags.
python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \
--depth=$(pwd) \
--include=oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi \
oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp
ninja -C out/Default

View File

View File

@@ -0,0 +1,94 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oemcrypto_fuzz_helper.h"
#include "oemcrypto_fuzz_structs.h"
namespace wvoec {
// Free dynamic memory allocated by fuzzer script.
void FreeOutputBuffers(OEMCrypto_SESSION session_id,
OEMCrypto_DestBufferDesc& output_descriptor,
int* secure_fd) {
switch (output_descriptor.type) {
case OEMCrypto_BufferType_Clear: {
delete[] output_descriptor.buffer.clear.address;
break;
}
case OEMCrypto_BufferType_Secure: {
OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, *secure_fd);
break;
}
case OEMCrypto_BufferType_Direct: {
break;
}
}
}
bool InitializeOutputBuffers(OEMCrypto_SESSION session_id,
OEMCrypto_DestBufferDesc& output_descriptor,
int* secure_fd, size_t input_buffer_size) {
switch (output_descriptor.type) {
case OEMCrypto_BufferType_Clear: {
output_descriptor.buffer.clear.address =
new OEMCrypto_SharedMemory[input_buffer_size];
return true;
}
case OEMCrypto_BufferType_Secure: {
OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer(
session_id, input_buffer_size, &output_descriptor, secure_fd);
return sts == OEMCrypto_SUCCESS;
}
case OEMCrypto_BufferType_Direct: {
return true;
}
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Redirect printf and log statements from oemcrypto functions to a file to
// reduce noise
RedirectStdoutToFile();
uint8_t subsample_flags;
// OEMCrypto_DestBufferDesc and a buffer from which data needs to be copied
// are expected as inputs to copy buffer API.
// Input fuzzed data is interpreted as
// (OEMCrypto_DestBufferDesc | subsample_flags | input_buffer)
if (size <= sizeof(OEMCrypto_Copy_Buffer_Fuzz)) {
return 0;
}
OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure;
// Fuzz dest_buffer_desc.
memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure));
ConvertDataToValidEnum(OEMCrypto_BufferType_MaxValue,
&fuzzed_structure.dest_buffer_desc.type);
OEMCryptoLicenseAPIFuzz license_api_fuzz;
Session* session = license_api_fuzz.session();
// Fuzz input buffer to be copied.
size_t input_buffer_size = size - sizeof(fuzzed_structure);
int secure_fd = 0;
// Create output buffer pointers. If secure buffer is not supported, we
// explicitly convert to clear buffer and fuzz.
if (!InitializeOutputBuffers(session->session_id(),
fuzzed_structure.dest_buffer_desc, &secure_fd,
input_buffer_size)) {
LOGI(
"[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use "
"clear buffer instead.");
fuzzed_structure.dest_buffer_desc.type = OEMCrypto_BufferType_Clear;
InitializeOutputBuffers(session->session_id(),
fuzzed_structure.dest_buffer_desc, &secure_fd,
input_buffer_size);
}
OEMCrypto_CopyBuffer(session->session_id(), data + sizeof(fuzzed_structure),
input_buffer_size, &fuzzed_structure.dest_buffer_desc,
subsample_flags);
FreeOutputBuffers(session->session_id(), fuzzed_structure.dest_buffer_desc,
&secure_fd);
return 0;
}
} // namespace wvoec

View File

@@ -1,5 +1,5 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "oemcrypto_fuzz_helper.h"

View File

@@ -5,9 +5,9 @@
#include "FuzzedDataProvider.h"
#include "OEMCryptoCENC.h"
#include "log.h"
#include "odk_overflow.h"
#include "oemcrypto_fuzz_helper.h"
#include "oemcrypto_fuzz_structs.h"
#include "oemcrypto_overflow.h"
namespace wvoec {
const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB;
@@ -20,7 +20,7 @@ void FreeOutputBuffers(OEMCrypto_SESSION session_id,
sample_description[i].buffers.output_descriptor;
switch (fuzzed_output_descriptor.type) {
case OEMCrypto_BufferType_Clear: {
delete[] fuzzed_output_descriptor.buffer.clear.address;
delete[] fuzzed_output_descriptor.buffer.clear.clear_buffer;
break;
}
case OEMCrypto_BufferType_Secure: {
@@ -44,9 +44,10 @@ bool InitializeOutputBuffers(OEMCrypto_SESSION session_id,
vector<int>& secure_fd_array) {
switch (output_descriptor.type) {
case OEMCrypto_BufferType_Clear: {
output_descriptor.buffer.clear
.address = new OEMCrypto_SharedMemory[std::min(
MAX_FUZZ_SAMPLE_SIZE, output_descriptor.buffer.clear.address_length)];
output_descriptor.buffer.clear.clear_buffer =
new OEMCrypto_SharedMemory[std::min(
MAX_FUZZ_SAMPLE_SIZE,
output_descriptor.buffer.clear.clear_buffer_length)];
return true;
}
case OEMCrypto_BufferType_Secure: {
@@ -54,7 +55,7 @@ bool InitializeOutputBuffers(OEMCrypto_SESSION session_id,
OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer(
session_id,
std::min(MAX_FUZZ_SAMPLE_SIZE,
output_descriptor.buffer.secure.handle_length),
output_descriptor.buffer.secure.secure_buffer_length),
&output_descriptor, secure_fd);
if (sts == OEMCrypto_SUCCESS) secure_fd_array[sample_index] = *secure_fd;
return sts == OEMCrypto_SUCCESS;
@@ -138,9 +139,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
// Copy sub sample data.
sample_descriptions[i].subsamples = &subsamples[input_subsample_index];
if (odk_add_overflow_ux(input_subsample_index,
sample_descriptions[i].subsamples_length,
&input_subsample_index)) {
if (OPK_AddOverflowUX(input_subsample_index,
sample_descriptions[i].subsamples_length,
&input_subsample_index)) {
return 0;
}
if (input_subsample_index > subsamples.size()) return 0;

View File

@@ -68,6 +68,14 @@ struct OEMCrypto_Generate_RSA_Signature_Fuzz {
// input buffer data is of variable length and not included in
// this structure.
};
struct OEMCrypto_Copy_Buffer_Fuzz {
// Corpus format is as below.
// dest_buffer_desc + subsample_flags + input buffer
OEMCrypto_DestBufferDesc dest_buffer_desc;
uint8_t subsample_flags;
// Input buffer of variable length is not included in this structure.
};
} // namespace wvoec
#endif // OEMCRYPTO_FUZZ_STRUCTS_H_

View File

@@ -119,5 +119,11 @@
'oemcrypto_report_usage_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_copy_buffer_fuzz',
'sources': [
'oemcrypto_copy_buffer_fuzz.cc',
],
},
],
}

View File

@@ -15,6 +15,7 @@
},
'sources': [
'../../odk/src/core_message_deserialize.cpp',
'../../odk/src/core_message_features.cpp',
'../../odk/src/core_message_serialize.cpp',
'../oec_device_features.cpp',
'../oec_key_deriver.cpp',
@@ -40,14 +41,14 @@
'<(oemcrypto_dir)/test/fuzz_tests',
'<(oemcrypto_dir)/odk/include',
'<(oemcrypto_dir)/odk/src',
'<(oemcrypto_dir)/odkitee/oemcrypto_ta',
'<(oemcrypto_dir)/opk/oemcrypto_ta',
],
'includes': [
'../../../util/libssl_dependency.gypi',
],
'dependencies': [
'../../../third_party/gmock.gyp:gtest',
'../../../third_party/gmock.gyp:gmock',
'../../../third_party/googletest.gyp:gtest',
'../../../third_party/googletest.gyp:gmock',
],
'defines': [
'OEMCRYPTO_FUZZ_TESTS',
@@ -95,6 +96,7 @@
'-fcoverage-mapping',
],
'ldflags': [
'-fsanitize=fuzzer',
'-fprofile-instr-generate',
'-fcoverage-mapping',
],
@@ -106,11 +108,11 @@
'../../ref/oec_ref.gypi',
],
}],
['oemcrypto_implementation_version=="odkitee"', {
# Include oemcrypto odkitee implementation code for building odkitee
['oemcrypto_implementation_version=="opk"', {
# Include oemcrypto opk implementation code for building opk
# implementation fuzz binaries.
'dependencies': [
'../../odkitee/oemcrypto_ta/oemcrypto_ta.gyp:oemcrypto_ta',
'../../opk/oemcrypto_ta/wtpi_test_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_no_ipc',
],
}],
], # conditions

View File

@@ -10,7 +10,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (!is_init) {
wvoec::global_features.Initialize();
wvoec::global_features.RestrictFilter("*");
wvcdm::Properties::Init();
wvutil::Properties::Init();
is_init = true;
}

View File

@@ -1,5 +1,5 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "OEMCryptoCENC.h"

View File

@@ -1,85 +0,0 @@
# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
# source code may only be used and distributed under the Widevine
# License Agreement.
{
'target_defaults': {
'type': 'executable',
'includes': [
'oemcrypto_fuzztests.gypi',
],
},
'variables': {
# Flag to select appropriate underlying oemcrypto implementation when
# buiding fuzz binaries.
'oemcrypto_implementation_version%': 'odkitee',
'oemcrypto_dir': '../..',
},
'targets': [
{
'target_name': 'oemcrypto_odkitee_load_license_fuzz',
'sources': [
'oemcrypto_load_license_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_load_provisioning_fuzz',
'sources': [
'oemcrypto_load_provisioning_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_load_renewal_fuzz',
'sources': [
'oemcrypto_load_renewal_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_license_request_fuzz',
'sources': [
'oemcrypto_license_request_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_provisioning_request_fuzz',
'sources': [
'oemcrypto_provisioning_request_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_renewal_request_fuzz',
'sources': [
'oemcrypto_renewal_request_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_decrypt_cenc_fuzz',
'sources': [
'oemcrypto_decrypt_cenc_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_load_entitled_content_keys_fuzz',
'sources': [
'oemcrypto_load_entitled_content_keys_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_odkitee_dispatcher_fuzz',
'include_dirs': [
'<(oemcrypto_dir)/odkitee/serialization/common',
'<(oemcrypto_dir)/odkitee/serialization/os_interfaces',
'<(oemcrypto_dir)/odkitee/serialization/tee',
'<(oemcrypto_dir)/odkitee/serialization/tee/include',
'<(oemcrypto_dir)/odkitee/serialization/ports/trusty/include/',
],
'dependencies': [
'<(oemcrypto_dir)/odkitee/serialization/tee/tee.gyp:odkitee_tee',
],
'sources': [
'oemcrypto_odkitee_dispatcher_fuzz.cc',
'<(oemcrypto_dir)/odkitee/serialization/test/transport_interface.c',
'<(oemcrypto_dir)/odkitee/serialization/ports/trusty/serialization_adapter/shared_memory.c',
],
},
],
}

View File

@@ -1,23 +1,15 @@
#include <stdio.h>
#include <string.h>
#include "dispatcher.h"
#include "marshaller_base.h"
#include "transport_interface.h"
#include "opk_dispatcher.h"
#include "opk_init.h"
#include "tos_transport_interface.h"
namespace wvoec {
void InitializeODKMessage(ODK_Message* message, uint8_t* data, size_t size) {
ODK_Message_Impl* impl = (ODK_Message_Impl*)message;
impl->base = data;
impl->size = size;
impl->capacity = size;
impl->read_offset = 0;
impl->status = MESSAGE_STATUS_OK;
}
void OpenOEMCryptoTASession() {
ODK_Message request;
ODK_Message* response = NULL;
ODK_Message response;
uint8_t response_buffer[0x1000];
uint8_t request_body[] = {
0x06, // TAG_UINT32
@@ -26,16 +18,13 @@ void OpenOEMCryptoTASession() {
0x00, // value (false)
0x0a // TAG_EOM
};
InitializeODKMessage(&request, request_body, sizeof(request_body));
ODK_DispatchMessage(&request, &response);
if (response != NULL) ODK_Transport_DeallocateMessage(response);
request = ODK_Message_Create(request_body, sizeof(request_body));
OPK_DispatchMessage(&request, &response);
}
void InitializeOEMCryptoTA() {
ODK_Message init_request;
ODK_Message* init_response = NULL;
ODK_Message init_response;
uint8_t response_buffer[0x1000];
uint8_t init_request_body[] = {
0x06, // TAG_UINT32
@@ -43,15 +32,13 @@ void InitializeOEMCryptoTA() {
0x0a // TAG_EOM
};
InitializeODKMessage(&init_request, init_request_body,
sizeof(init_request_body));
ODK_DispatchMessage(&init_request, &init_response);
if (init_response != NULL) ODK_Transport_DeallocateMessage(init_response);
init_request =
ODK_Message_Create(init_request_body, sizeof(init_request_body));
OPK_DispatchMessage(&init_request, &init_response);
}
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
ODK_InitializeDispatcher();
OPK_Initialize();
InitializeOEMCryptoTA();
OpenOEMCryptoTASession();
return 0;
@@ -59,16 +46,14 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
ODK_Message request;
ODK_Message* response = NULL;
ODK_Message response;
unsigned char response_buffer[0x1000];
uint8_t* input = new uint8_t[size];
memcpy(input, data, size);
InitializeODKMessage(&request, input, size);
ODK_DispatchMessage(&request, &response);
if (response != NULL) ODK_Transport_DeallocateMessage(response);
request = ODK_Message_Create(input, size);
OPK_DispatchMessage(&request, &response);
delete[] input;
return 0;

View File

@@ -0,0 +1,148 @@
# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
# source code may only be used and distributed under the Widevine
# License Agreement.
{
'target_defaults': {
'type': 'executable',
'includes': [
'oemcrypto_fuzztests.gypi',
],
},
'variables': {
# Flag to select appropriate underlying oemcrypto implementation when
# buiding fuzz binaries.
'oemcrypto_implementation_version%': 'opk',
'oemcrypto_dir': '../..',
},
'targets': [
{
'target_name': 'oemcrypto_opk_load_license_fuzz',
'sources': [
'oemcrypto_load_license_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_load_provisioning_fuzz',
'sources': [
'oemcrypto_load_provisioning_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_load_renewal_fuzz',
'sources': [
'oemcrypto_load_renewal_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_license_request_fuzz',
'sources': [
'oemcrypto_license_request_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_provisioning_request_fuzz',
'sources': [
'oemcrypto_provisioning_request_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_renewal_request_fuzz',
'sources': [
'oemcrypto_renewal_request_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_decrypt_cenc_fuzz',
'sources': [
'oemcrypto_decrypt_cenc_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_load_entitled_content_keys_fuzz',
'sources': [
'oemcrypto_load_entitled_content_keys_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_generic_encrypt_fuzz',
'sources': [
'oemcrypto_generic_encrypt_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_generic_decrypt_fuzz',
'sources': [
'oemcrypto_generic_decrypt_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_generic_sign_fuzz',
'sources': [
'oemcrypto_generic_sign_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_generic_verify_fuzz',
'sources': [
'oemcrypto_generic_verify_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_generate_rsa_signature_fuzz',
'sources': [
'oemcrypto_generate_rsa_signature_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_load_usage_table_header_fuzz',
'sources': [
'oemcrypto_load_usage_table_header_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_load_usage_entry_fuzz',
'sources': [
'oemcrypto_load_usage_entry_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_deactivate_usage_entry_fuzz',
'sources': [
'oemcrypto_deactivate_usage_entry_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_report_usage_fuzz',
'sources': [
'oemcrypto_report_usage_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_copy_buffer_fuzz',
'sources': [
'oemcrypto_copy_buffer_fuzz.cc',
],
},
{
'target_name': 'oemcrypto_opk_dispatcher_fuzz',
'include_dirs': [
'<(oemcrypto_dir)/opk/serialization/common',
'<(oemcrypto_dir)/opk/serialization/common/include',
'<(oemcrypto_dir)/opk/serialization/os_interfaces',
'<(oemcrypto_dir)/opk/serialization/tee',
'<(oemcrypto_dir)/opk/serialization/tee/include',
'<(oemcrypto_dir)/opk/ports/trusty/include/',
],
'dependencies': [
'<(oemcrypto_dir)/opk/serialization/tee/tee.gyp:opk_tee',
],
'sources': [
'oemcrypto_opk_dispatcher_fuzz.cc',
'<(oemcrypto_dir)/opk/serialization/test/tos_secure_buffers.c',
'<(oemcrypto_dir)/opk/serialization/test/tos_transport_interface.c',
'<(oemcrypto_dir)/opk/serialization/test/tos_logging.c',
'<(oemcrypto_dir)/opk/ports/trusty/serialization_adapter/shared_memory.c',
],
},
],
}

View File

@@ -3,7 +3,7 @@
# License Agreement.
# gypi file to be included using --includes option while building oemcrypto
# odkitee fuzz binaries. Odkitee classes needs to be instrumented with fuzzer
# opk fuzz binaries. OPK classes needs to be instrumented with fuzzer
# but only when being built for fuzzing. Instead of directly updating
# oemcrypto_ta.gyp target, we use gypi in build_oemcrypto_fuzztests script.
{
@@ -45,6 +45,9 @@
'libraries': [
'-lpthread',
],
'defines': [
'OPK_LOG_LEVEL=LOG_NONE',
],
'conditions': [
['generate_code_coverage_report=="true"', {
# Include flags to build fuzzer binaries to generate source based code coverage reports.

View File

@@ -1,5 +1,5 @@
// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#include "oemcrypto_fuzz_helper.h"

View File

@@ -45,8 +45,8 @@
'../../../util/libssl_dependency.gypi',
],
'dependencies': [
'../../../third_party/gmock.gyp:gtest',
'../../../third_party/gmock.gyp:gmock',
'../../../third_party/googletest.gyp:gtest',
'../../../third_party/googletest.gyp:gmock',
],
'defines': [
'OEMCRYPTO_FUZZ_TESTS',

View File

@@ -16,8 +16,8 @@ namespace {
void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
switch (dest_buffer->type) {
case OEMCrypto_BufferType_Clear:
dest_buffer->buffer.clear.address += bytes;
dest_buffer->buffer.clear.address_length -= bytes;
dest_buffer->buffer.clear.clear_buffer += bytes;
dest_buffer->buffer.clear.clear_buffer_length -= bytes;
break;
case OEMCrypto_BufferType_Secure:
@@ -37,7 +37,7 @@ void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) {
const size_t increment =
bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional
counter = wvcdm::htonll64(wvcdm::ntohll64(counter) + increment);
counter = wvutil::htonll64(wvutil::ntohll64(counter) + increment);
memcpy(&(*subsample_iv)[half_iv_size], &counter, half_iv_size);
}
@@ -104,7 +104,7 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample(
fake_sample.buffers.input_data += length;
advance_dest_buffer(&fake_sample.buffers.output_descriptor, length);
if (cipher_mode == OEMCrypto_CipherMode_CTR) {
if (cipher_mode == OEMCrypto_CipherMode_CENC) {
advance_iv_ctr(&fake_sample.iv,
subsample.block_offset + subsample.num_bytes_encrypted);
}
@@ -205,13 +205,13 @@ void WriteDecryptCencCorpus(
const OEMCrypto_CENCEncryptPatternDesc* pattern, size_t samples_length) {
const std::string file_name =
GetFileName("oemcrypto_decrypt_cenc_fuzz_seed_corpus");
// Cipher mode.
AppendToFile(file_name, reinterpret_cast<const char*>(&cipher_mode),
sizeof(OEMCryptoCipherMode));
// Pattern.
AppendToFile(file_name, reinterpret_cast<const char*>(pattern),
sizeof(OEMCrypto_CENCEncryptPatternDesc));
OEMCrypto_Decrypt_Cenc_Fuzz decrypt_cenc_fuzz_struct;
decrypt_cenc_fuzz_struct.cipher_mode = cipher_mode;
decrypt_cenc_fuzz_struct.pattern = *pattern;
// Cipher mode and Pattern.
AppendToFile(file_name,
reinterpret_cast<const char*>(&decrypt_cenc_fuzz_struct),
sizeof(OEMCrypto_Decrypt_Cenc_Fuzz));
// Sample data for all samples.
for (size_t i = 0; i < samples_length; i++) {

View File

@@ -7,6 +7,7 @@
#include "OEMCryptoCENC.h"
#include "disallow_copy_and_assign.h"
#include "oemcrypto_fuzz_structs.h"
namespace wvoec {

View File

@@ -48,7 +48,8 @@ void DeviceFeatures::Initialize() {
// If the device uses a keybox, check to see if loading a certificate is
// installed.
if (provisioning_method == OEMCrypto_Keybox ||
provisioning_method == OEMCrypto_OEMCertificate) {
provisioning_method == OEMCrypto_OEMCertificate ||
provisioning_method == OEMCrypto_BootCertificateChain) {
// Devices with a keybox or OEM Certificate are required to support loading
// a DRM certificate.
loads_certificate = true;
@@ -81,8 +82,8 @@ void DeviceFeatures::Initialize() {
}
printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false");
resource_rating = OEMCrypto_ResourceRatingTier();
printf("resource_rating = %u, security level %s.\n", resource_rating,
OEMCrypto_SecurityLevel());
printf("resource_rating = %u, security level %u.\n", resource_rating,
static_cast<unsigned int>(OEMCrypto_SecurityLevel()));
uint32_t decrypt_hash_type = OEMCrypto_SupportsDecryptHash();
supports_crc = (decrypt_hash_type == OEMCrypto_CRC_Clear_Buffer);
if (supports_crc) {
@@ -109,13 +110,17 @@ void DeviceFeatures::Initialize() {
printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n");
break;
case TEST_PROVISION_30:
printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n");
printf("TEST_PROVISION_30: Device provisioned with OEM Cert.\n");
break;
case TEST_PROVISION_40:
printf("TEST_PROVISION_40: Device has boot certificate chain.\n");
break;
}
std::string security_level = OEMCrypto_SecurityLevel();
supports_level_1 = (security_level == "L1");
printf("SecurityLevel is %s (%s)\n",
supports_level_1 ? "Level 1" : "Not Level 1", security_level.c_str());
OEMCrypto_Security_Level security_level = OEMCrypto_SecurityLevel();
supports_level_1 = (security_level == OEMCrypto_Level1);
printf("SecurityLevel is %s (L%u)\n",
supports_level_1 ? "Level 1" : "Not Level 1",
static_cast<unsigned int>(security_level));
CheckSecureBuffers();
OEMCrypto_Terminate();
initialized_ = true;
@@ -125,14 +130,18 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
std::string filter = initial_filter;
// clang-format off
if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*");
if (!loads_certificate) FilterOut(&filter, "OEMCryptoLoadsCert*");
// TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for
// provisioning 4. Disabled here temporarily.
if (!loads_certificate ||
provisioning_method == OEMCrypto_BootCertificateChain)
FilterOut(&filter, "OEMCryptoLoadsCert*");
if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*");
if (!cast_receiver) FilterOut(&filter, "*CastReceiver*");
if (!usage_table) FilterOut(&filter, "*UsageTable*");
if (!usage_table) FilterOut(&filter, "*BadRange_pst*");
if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*");
if (provisioning_method
!= OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*");
if (provisioning_method != OEMCrypto_BootCertificateChain)
FilterOut(&filter, "*Prov40*");
if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*");
if (api_version < 9) FilterOut(&filter, "*API09*");
if (api_version < 10) FilterOut(&filter, "*API10*");
@@ -142,10 +151,11 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
if (api_version < 14) FilterOut(&filter, "*API14*");
if (api_version < 15) FilterOut(&filter, "*API15*");
if (api_version < 16) FilterOut(&filter, "*API16*");
if (api_version < 17) FilterOut(&filter, "*API17*");
// clang-format on
// Some tests may require root access. If user is not root, filter these tests
// out.
if (!wvcdm::TestSleep::CanChangeSystemTime()) {
if (!wvutil::TestSleep::CanChangeSystemTime()) {
printf("Filtering out TimeRollbackPrevention.\n");
FilterOut(&filter, "*TimeRollbackPrevention*");
} else {
@@ -173,6 +183,9 @@ void DeviceFeatures::PickDerivedKey() {
case OEMCrypto_Keybox:
// Fall through to api_version < 12 case.
break;
case OEMCrypto_BootCertificateChain:
derive_key_method = TEST_PROVISION_40;
return;
case OEMCrypto_ProvisioningError:
printf(
"ERROR: OEMCrypto_GetProvisioningMethod() returns "
@@ -252,6 +265,8 @@ const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method) {
return "OEMCrypto_Keybox";
case OEMCrypto_OEMCertificate:
return "OEMCrypto_OEMCertificate";
case OEMCrypto_BootCertificateChain:
return "OEMCrypto_BootCertificateChain";
}
// Not reachable
return "";

View File

@@ -10,9 +10,12 @@
namespace wvoec {
// These tests are designed to work for this version:
constexpr unsigned int kCurrentAPI = 16;
constexpr unsigned int kCurrentAPI = 17;
// The API version when Core Messages were introduced.
constexpr unsigned int kCoreMessagesAPI = 16;
// The API version when we stopped encrypting key control blocks.
constexpr unsigned int kClearControlBlockAPIMajor = 16;
constexpr unsigned int kClearControlBlockAPIMinor = 5;
// An output type for testing. The type field is secure, clear, or direct. If
// the type is clear, then decrypt_inplace could be true. Otherwise,
@@ -29,23 +32,24 @@ class DeviceFeatures {
// There are several possible methods used to derive a set of known session
// keys. For example, the test can install a known test keybox, or it can
// parse the OEM certificate.
enum DeriveMethod { // Method to use derive session keys.
NO_METHOD, // Cannot derive known session keys.
LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys.
LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys.
TEST_PROVISION_30, // Device has OEM Certificate installed.
enum DeriveMethod { // Method to use derive session keys.
NO_METHOD, // Cannot derive known session keys.
LOAD_TEST_KEYBOX, // Call LoadTestKeybox before deriving keys.
LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys.
TEST_PROVISION_30, // Device has OEM Certificate installed.
TEST_PROVISION_40, // Device has Boot Certificate Chain installed.
};
enum DeriveMethod derive_key_method;
bool uses_keybox; // Device uses a keybox to derive session keys.
bool loads_certificate; // Device can load a certificate from the server.
bool generic_crypto; // Device supports generic crypto.
bool cast_receiver; // Device supports alternate rsa signature padding.
bool usage_table; // Device saves usage information.
bool supports_rsa_3072; // Device supports 3072 bit RSA keys.
bool supports_level_1; // Device supports Level 1 security.
uint32_t resource_rating; // Device's resource rating tier.
bool supports_crc; // Supported decrypt hash type CRC.
bool uses_keybox; // Device uses a keybox to derive session keys.
bool loads_certificate; // Device can load a certificate from the server.
bool generic_crypto; // Device supports generic crypto.
bool cast_receiver; // Device supports alternate rsa signature padding.
bool usage_table; // Device saves usage information.
bool supports_rsa_3072; // Device supports 3072 bit RSA keys.
bool supports_level_1; // Device supports Level 1 security.
uint32_t resource_rating; // Device's resource rating tier.
bool supports_crc; // Supported decrypt hash type CRC.
bool test_secure_buffers; // If we can create a secure buffer for testing.
uint32_t api_version;
OEMCrypto_ProvisioningMethod provisioning_method;

View File

@@ -5,7 +5,7 @@
// OEMCrypto unit tests
//
#include "oec_session_util.h"
#include "oec_key_deriver.h"
#include <openssl/aes.h>
#include <openssl/bio.h>
@@ -58,7 +58,7 @@ void Encryptor::CBCEncrypt(const uint8_t* data, uint8_t* encrypted_data,
void Encryptor::PadAndEncryptProvisioningMessage(
RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted) const {
EXPECT_EQ(1, GetRandBytes(data->rsa_key_iv, KEY_IV_SIZE));
EXPECT_EQ(1, RAND_bytes(data->rsa_key_iv, KEY_IV_SIZE));
ASSERT_EQ(enc_key_.size(), KEY_SIZE);
*encrypted = *data;
if (data->rsa_key_length > sizeof(data->rsa_key)) {
@@ -147,8 +147,9 @@ void KeyDeriver::ServerSignBuffer(const uint8_t* data, size_t data_length,
ASSERT_EQ(mac_key_server_.size(), MAC_KEY_SIZE);
signature->assign(SHA256_DIGEST_LENGTH, 0);
unsigned int sig_len = SHA256_DIGEST_LENGTH;
ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_server_.data(), mac_key_server_.size(),
data, data_length, signature->data(), &sig_len));
ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_server_.data(),
static_cast<int>(mac_key_server_.size()), data, data_length,
signature->data(), &sig_len));
}
void KeyDeriver::ClientSignBuffer(const vector<uint8_t>& buffer,
@@ -156,8 +157,9 @@ void KeyDeriver::ClientSignBuffer(const vector<uint8_t>& buffer,
ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE);
signature->assign(SHA256_DIGEST_LENGTH, 0);
unsigned int sig_len = SHA256_DIGEST_LENGTH;
ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_client_.data(), mac_key_client_.size(),
buffer.data(), buffer.size(), signature->data(), &sig_len));
ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_client_.data(),
static_cast<int>(mac_key_client_.size()), buffer.data(),
buffer.size(), signature->data(), &sig_len));
}
void KeyDeriver::ClientSignPstReport(const vector<uint8_t>& pst_report_buffer,
@@ -165,7 +167,8 @@ void KeyDeriver::ClientSignPstReport(const vector<uint8_t>& pst_report_buffer,
ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE);
signature->assign(SHA_DIGEST_LENGTH, 0);
unsigned int sig_len = SHA_DIGEST_LENGTH;
ASSERT_TRUE(HMAC(EVP_sha1(), mac_key_client_.data(), mac_key_client_.size(),
ASSERT_TRUE(HMAC(EVP_sha1(), mac_key_client_.data(),
static_cast<int>(mac_key_client_.size()),
&pst_report_buffer[SHA_DIGEST_LENGTH],
pst_report_buffer.size() - SHA_DIGEST_LENGTH,
signature->data(), &sig_len));

Some files were not shown because too many files have changed in this diff Show More