From 2bfd670424232fbff4e38f25d06cb28ee4c88b61 Mon Sep 17 00:00:00 2001 From: Jacob Trimble Date: Tue, 13 Dec 2022 11:36:17 -0800 Subject: [PATCH] Update ODK to v17.1 --- oemcrypto/odk/Android.bp | 16 +- oemcrypto/odk/include/OEMCryptoCENCCommon.h | 77 ++++- .../odk/include/core_message_deserialize.h | 16 +- oemcrypto/odk/include/core_message_features.h | 44 +++ .../odk/include/core_message_serialize.h | 18 +- .../include/core_message_serialize_proto.h | 19 +- oemcrypto/odk/include/core_message_types.h | 7 +- oemcrypto/odk/include/odk.h | 77 ++++- oemcrypto/odk/include/odk_attributes.h | 2 +- oemcrypto/odk/include/odk_message.h | 47 +-- oemcrypto/odk/include/odk_structs.h | 34 +- oemcrypto/odk/include/odk_target.h | 2 +- .../odk/src/core_message_deserialize.cpp | 45 ++- oemcrypto/odk/src/core_message_features.cpp | 41 +++ oemcrypto/odk/src/core_message_serialize.cpp | 128 +++++-- .../odk/src/core_message_serialize_proto.cpp | 21 +- oemcrypto/odk/src/kdo.gypi | 3 +- oemcrypto/odk/src/odk.c | 324 ++++++++++++------ oemcrypto/odk/src/odk.gyp | 18 +- oemcrypto/odk/src/odk.gypi | 2 +- oemcrypto/odk/src/odk_assert.h | 2 +- oemcrypto/odk/src/odk_endian.h | 14 +- oemcrypto/odk/src/odk_message.c | 43 ++- oemcrypto/odk/src/odk_message_priv.h | 2 +- oemcrypto/odk/src/odk_overflow.c | 12 +- oemcrypto/odk/src/odk_overflow.h | 3 +- oemcrypto/odk/src/odk_serialize.c | 139 +++++++- oemcrypto/odk/src/odk_serialize.h | 11 +- oemcrypto/odk/src/odk_structs_priv.h | 58 +++- oemcrypto/odk/src/odk_timer.c | 14 +- oemcrypto/odk/src/odk_util.c | 9 +- oemcrypto/odk/src/odk_util.h | 5 +- oemcrypto/odk/src/serialization_base.c | 35 +- oemcrypto/odk/src/serialization_base.h | 4 +- oemcrypto/odk/test/fuzzing/Android.bp | 16 +- .../test/fuzzing/corpus_generator/Android.bp | 14 +- .../corpus_generator/odk_corpus_generator.c | 2 +- .../odk_corpus_generator_helper.c | 2 +- .../odk_corpus_generator_helper.h | 2 +- .../odk_fuzz_corpus_generator.gyp | 2 +- oemcrypto/odk/test/fuzzing/odk_fuzz.gyp | 6 +- .../odk/test/fuzzing/odk_fuzz_helper.cpp | 20 +- oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h | 3 +- oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h | 2 +- .../test/fuzzing/odk_license_request_fuzz.cpp | 2 +- .../fuzzing/odk_license_response_fuzz.cpp | 2 +- ...odk_license_response_fuzz_with_mutator.cpp | 2 +- .../fuzzing/odk_provisioning_request_fuzz.cpp | 2 +- .../odk_provisioning_response_fuzz.cpp | 2 +- ...rovisioning_response_fuzz_with_mutator.cpp | 6 +- .../test/fuzzing/odk_renewal_request_fuzz.cpp | 2 +- .../fuzzing/odk_renewal_response_fuzz.cpp | 2 +- ...odk_renewal_response_fuzz_with_mutator.cpp | 6 +- oemcrypto/odk/test/odk_core_message_test.cpp | 4 +- oemcrypto/odk/test/odk_test.cpp | 297 ++++++++++++---- oemcrypto/odk/test/odk_test.gypi | 2 +- oemcrypto/odk/test/odk_test_helper.cpp | 270 ++++++++++++--- oemcrypto/odk/test/odk_test_helper.h | 16 +- oemcrypto/odk/test/odk_timer_test.cpp | 22 +- 59 files changed, 1557 insertions(+), 441 deletions(-) create mode 100644 oemcrypto/odk/include/core_message_features.h create mode 100644 oemcrypto/odk/src/core_message_features.cpp diff --git a/oemcrypto/odk/Android.bp b/oemcrypto/odk/Android.bp index 41aa3e3..3b7d807 100644 --- a/oemcrypto/odk/Android.bp +++ b/oemcrypto/odk/Android.bp @@ -1,10 +1,22 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. // ---------------------------------------------------------------- // Builds libwv_odk.a, The ODK Library (libwv_odk) is used by // the CDM and by oemcrypto implementations. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_library_static { name: "libwv_odk", include_dirs: [ @@ -15,6 +27,7 @@ cc_library_static { srcs: [ "src/odk.c", + "src/odk_message.c", "src/odk_overflow.c", "src/odk_serialize.c", "src/odk_timer.c", @@ -39,6 +52,7 @@ cc_library_static { srcs: [ "src/core_message_deserialize.cpp", + "src/core_message_features.cpp", "src/core_message_serialize.cpp", "src/core_message_serialize_proto.cpp", ], diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h index 69ba2ad..ce51b8d 100644 --- a/oemcrypto/odk/include/OEMCryptoCENCCommon.h +++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. /********************************************************************* @@ -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, @@ -88,6 +88,11 @@ typedef enum OEMCryptoResult { 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, @@ -96,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 */ @@ -110,6 +120,11 @@ typedef enum OEMCrypto_Usage_Entry_Status { kInactiveUnused = 4, } OEMCrypto_Usage_Entry_Status; +typedef enum OEMCrypto_ProvisioningRenewalType { + OEMCrypto_NoRenewal = 0, + OEMCrypto_RenewalACert = 1, +} OEMCrypto_ProvisioningRenewalType; + /** * OEMCrypto_LicenseType is used in the license message to indicate if the key * objects are for content keys, or for entitlement keys. @@ -117,7 +132,7 @@ typedef enum OEMCrypto_Usage_Entry_Status { typedef enum OEMCrypto_LicenseType { OEMCrypto_ContentLicense = 0, OEMCrypto_EntitlementLicense = 1, - OEMCrypto_LicenstType_MaxValue = OEMCrypto_EntitlementLicense, + OEMCrypto_LicenseType_MaxValue = OEMCrypto_EntitlementLicense, } OEMCrypto_LicenseType; /* Private key type used in the provisioning response. */ @@ -136,6 +151,62 @@ typedef struct { size_t length; } OEMCrypto_Substring; +/** + * Used to specify information about CMI Descriptor 0. + * @param id: ID value of CMI Descriptor assigned by DTLA. + * @param length: byte length of the usage rules field. + * @param data: usage rules data. + */ +typedef struct { + uint8_t id; // 0x00 + uint8_t extension; // 0x00 + uint16_t length; // 0x01 + uint8_t data; +} OEMCrypto_DTCP2_CMI_Descriptor_0; + +/** + * Used to specify information about CMI Descriptor 1. + * @param id: ID value of CMI Descriptor assigned by DTLA. + * @param extension: specified by the CMI descriptor + * @param length: byte length of the usage rules field. + * @param data: usage rules data. + */ +typedef struct { + uint8_t id; // 0x01 + uint8_t extension; // 0x00 + uint16_t length; // 0x03 + uint8_t data[3]; +} OEMCrypto_DTCP2_CMI_Descriptor_1; + +/** + * Used to specify information about CMI Descriptor 2. + * @param id: ID value of CMI Descriptor assigned by DTLA. + * @param extension: specified by the CMI descriptor + * @param length: byte length of the usage rules field. + * @param data: usage rules data. + */ +typedef struct { + uint8_t id; // 0x02 + uint8_t extension; // 0x00 + uint16_t length; // 0x03 + uint8_t data[3]; +} OEMCrypto_DTCP2_CMI_Descriptor_2; + +/** + * Used to specify the required DTCP2 level. If dtcp2_required is 0, there are + * no requirements on any of the keys. If dtcp2_required is 1, any key with the + * kControlHDCPRequired bit set requires DTCP2 in its output. + * @param dtcp2_required: specifies whether dtcp2 is required. 0 = not required, + * 1 = DTCP2 required. + * @param cmi_descriptor_1: three bytes of CMI descriptor 1 + */ +typedef struct { + uint8_t dtcp2_required; // 0 = not required. 1 = DTCP2 v1 required. + OEMCrypto_DTCP2_CMI_Descriptor_0 cmi_descriptor_0; + OEMCrypto_DTCP2_CMI_Descriptor_1 cmi_descriptor_1; + OEMCrypto_DTCP2_CMI_Descriptor_2 cmi_descriptor_2; +} OEMCrypto_DTCP2_CMI_Packet; + /** * Points to the relevant fields for a content key. The fields are extracted * from the License Response message offered to OEMCrypto_LoadKeys(). Each diff --git a/oemcrypto/odk/include/core_message_deserialize.h b/oemcrypto/odk/include/core_message_deserialize.h index 93cf800..545a806 100644 --- a/oemcrypto/odk/include/core_message_deserialize.h +++ b/oemcrypto/odk/include/core_message_deserialize.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. /********************************************************************* @@ -17,6 +17,8 @@ #ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ #define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ +#include + #include "core_message_types.h" namespace oemcrypto_core_message { @@ -53,6 +55,18 @@ bool CoreProvisioningRequestFromMessage( const std::string& oemcrypto_core_message, ODK_ProvisioningRequest* core_provisioning_request); +/** + * Counterpart (deserializer) of ODK_PrepareCoreRenewedProvisioningRequest + * (serializer) + * + * Parameters: + * [in] oemcrypto_core_message + * [out] core_provisioning_request + */ +bool CoreRenewedProvisioningRequestFromMessage( + const std::string& oemcrypto_core_message, + ODK_ProvisioningRequest* core_provisioning_request); + /** * Serializer counterpart is not used and is therefore not implemented. * diff --git a/oemcrypto/odk/include/core_message_features.h b/oemcrypto/odk/include/core_message_features.h new file mode 100644 index 0000000..16289c6 --- /dev/null +++ b/oemcrypto/odk/include/core_message_features.h @@ -0,0 +1,44 @@ +// Copyright 2021 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_ +#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_ + +#include + +#include +#include + +namespace oemcrypto_core_message { +namespace features { + +// Features that may be supported by core messages. By restricting values in +// this structure, we can turn off features at runtime. This is plain data, and +// is essentially a version number. +struct CoreMessageFeatures { + // A default set of features. + static const CoreMessageFeatures kDefaultFeatures; + + // Create the default feature set for the given major version number. + static CoreMessageFeatures DefaultFeatures(uint32_t maximum_major_version); + + // This is the published version of the ODK Core Message library. The default + // behavior is for the server to restrict messages to at most this version + // number. The default is 16.5, the last version used by Chrome. This will + // change to 17.0 when v17 has been released. + uint32_t maximum_major_version = 17; + uint32_t maximum_minor_version = 0; + + bool operator==(const CoreMessageFeatures &other) const; + bool operator!=(const CoreMessageFeatures &other) const { + return !(*this == other); + } +}; + +std::ostream &operator<<(std::ostream &os, const CoreMessageFeatures &features); + +} // namespace features +} // namespace oemcrypto_core_message + +#endif // WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_FEATURES_H_ diff --git a/oemcrypto/odk/include/core_message_serialize.h b/oemcrypto/odk/include/core_message_serialize.h index 619a085..bd6d635 100644 --- a/oemcrypto/odk/include/core_message_serialize.h +++ b/oemcrypto/odk/include/core_message_serialize.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. /********************************************************************* @@ -17,23 +17,29 @@ #ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ #define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ +#include + +#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 +48,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 +63,13 @@ bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, * struct-input variant * * Parameters: + * [in] features feature support for response message. * [in] parsed_prov * [in] core_request * [out] oemcrypto_core_message */ -bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, +bool CreateCoreProvisioningResponse(const CoreMessageFeatures& features, + const ODK_ParsedProvisioning& parsed_prov, const ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message); } // namespace serialize diff --git a/oemcrypto/odk/include/core_message_serialize_proto.h b/oemcrypto/odk/include/core_message_serialize_proto.h index ee6cd32..de75362 100644 --- a/oemcrypto/odk/include/core_message_serialize_proto.h +++ b/oemcrypto/odk/include/core_message_serialize_proto.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. /********************************************************************* @@ -17,18 +17,19 @@ #include #include +#include "core_message_features.h" #include "core_message_types.h" #include "license_protocol.pb.h" namespace oemcrypto_core_message { namespace serialize { - // @ public create response (serializer) functions accepting proto input /** * Counterpart (serializer) of ODK_ParseLicense (deserializer) * * Parameters: + * [in] features feature support for response message. * [in] serialized_license serialized video_widevine::License * [in] core_request oemcrypto core message from request. @@ -37,23 +38,25 @@ namespace serialize { * [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, - const bool uses_padding, - std::string* oemcrypto_core_message); +bool CreateCoreLicenseResponseFromProto( + const oemcrypto_core_message::features::CoreMessageFeatures& features, + const std::string& serialized_license, + const ODK_LicenseRequest& core_request, + const std::string& core_request_sha256, const bool nonce_required, + const bool uses_padding, std::string* oemcrypto_core_message); /** * Counterpart (serializer) of ODK_ParseProvisioning (deserializer) * * Parameters: + * [in] features feature support for response message. * [in] serialized_provisioning_response * serialized video_widevine::ProvisioningResponse * [in] core_request * [out] oemcrypto_core_message */ bool CreateCoreProvisioningResponseFromProto( + const oemcrypto_core_message::features::CoreMessageFeatures& features, const std::string& serialized_provisioning_response, const ODK_ProvisioningRequest& core_request, std::string* oemcrypto_core_message); diff --git a/oemcrypto/odk/include/core_message_types.h b/oemcrypto/odk/include/core_message_types.h index 0f45f00..5315913 100644 --- a/oemcrypto/odk/include/core_message_types.h +++ b/oemcrypto/odk/include/core_message_types.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. // clang-format off @@ -96,7 +96,8 @@ struct ODK_RenewalRequest { }; /** - * Output structure for CoreProvisioningRequestFromMessage + * Output structure for CoreProvisioningRequestFromMessage and + * CoreRenewedProvisioningRequestFromMessage * Input structure for CreateCoreProvisioningResponse */ struct ODK_ProvisioningRequest { @@ -105,6 +106,8 @@ struct ODK_ProvisioningRequest { uint32_t nonce; uint32_t session_id; std::string device_id; + uint16_t renewal_type; + std::string renewal_data; }; } // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/include/odk.h b/oemcrypto/odk/include/odk.h index 588f185..e3499da 100644 --- a/oemcrypto/odk/include/odk.h +++ b/oemcrypto/odk/include/odk.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. /** @@ -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, @@ -326,7 +326,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, * OEMCrypto_GetDeviceID. The device ID shall be unique to the device, and * stable across reboots and factory resets for an L1 device. * - * NOTE: if the message pointer is null and/or input core_message_size is + * NOTE: if the message pointer is null and/or input core_message_length is * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output * core_message_size to the size needed. * @@ -351,10 +351,56 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, * This method is new in version 16 of the API. */ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( - uint8_t* message, size_t message_length, size_t* core_message_size, + uint8_t* message, size_t message_length, size_t* core_message_length, const ODK_NonceValues* nonce_values, const uint8_t* device_id, size_t device_id_length); +/** + * Modifies the message to include a core renewal provisioning request at the + * beginning of the message buffer. The values in nonce_values are used to + * populate the message. + * + * This shall be called by OEMCrypto from + * OEMCrypto_PrepAndSignProvisioningRequest. + * + * The buffer device_id shall be the same string returned by + * OEMCrypto_GetDeviceID. The device ID shall be unique to the device, and + * stable across reboots and factory resets for an L1 device. + * + * NOTE: if the message pointer is null and/or input core_message_length is + * zero, this function returns OEMCrypto_ERROR_SHORT_BUFFER and sets output + * core_message_size to the size needed. + * + * @param[in,out] message: pointer to memory for the entire message. Modified by + * the ODK library. + * @param[in] message_length: length of the entire message buffer. + * @param[in,out] core_message_size: length of the core message at the beginning + * of the message. (in) size of buffer reserved for the core message, in + * bytes. (out) actual length of the core message, in bytes. + * @param[in] nonce_values: pointer to the session's nonce data. + * @param[in] device_id: For devices with a keybox, this is the device ID from + * the keybox. For devices with an OEM Certificate, this is a device + * unique id string. + * @param[in] device_id_length: length of device_id. The device ID can be at + * most 64 bytes. + * @param[in] renewal_type: type of renewal used + * @param[in] renewal_data: renewal data used. For renewal_type = 1, + * renewal_data is the Android attestation batch certificate. + * @param[in] renewal_data_length: length of renewal_data + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_SHORT_BUFFER: core_message_size is too small + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * + * @version + * This method is new in version 17 of the API. + */ +OEMCryptoResult ODK_PrepareCoreRenewedProvisioningRequest( + uint8_t* message, size_t message_length, size_t* core_message_length, + const ODK_NonceValues* nonce_values, const uint8_t* device_id, + size_t device_id_length, uint16_t renewal_type, const uint8_t* renewal_data, + size_t renewal_data_length); + /// @} /// @addtogroup odk_timer @@ -469,8 +515,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 +536,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); @@ -598,6 +641,20 @@ OEMCryptoResult ODK_ParseProvisioning( const ODK_NonceValues* nonce_values, const uint8_t* device_id, size_t device_id_length, ODK_ParsedProvisioning* parsed_response); +/** + * The function ODK_ParseProvisioning will parse the message and verify the + * API version is at most the version passed in. + * + * @param[in] nonce_values: pointer to the session's nonce data. + * @param[in] major_versioh: current API major version. + * @param[in] minor_version: current API minor version. + * + * @version + * This method is new in version 17 of the API. + */ +bool CheckApiVersionAtMost(const ODK_NonceValues* nonce_values, + uint16_t major_version, uint16_t minor_version); + /// @} #ifdef __cplusplus diff --git a/oemcrypto/odk/include/odk_attributes.h b/oemcrypto/odk/include/odk_attributes.h index 623a057..72321b1 100644 --- a/oemcrypto/odk/include/odk_attributes.h +++ b/oemcrypto/odk/include/odk_attributes.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_ diff --git a/oemcrypto/odk/include/odk_message.h b/oemcrypto/odk/include/odk_message.h index 76853b5..075f28c 100644 --- a/oemcrypto/odk/include/odk_message.h +++ b/oemcrypto/odk/include/odk_message.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ @@ -17,21 +17,21 @@ extern "C" { * 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, arbitrary modification to the message fields - * by code that is not privy to the message definition can be prevented. By - * restricting message modification it is possible to enforce message validity - * and integrity with a small set of primitives that can be careful reviewed. - * This is important because it allows the assertion to be made that a message's - * fields are internally consistent after every operation. As an example, it - * can be guaranteed that the message status be checked prior to accessing any - * field, and that the status be set to the proper state when any parse error is - * detected. If the message definition was exposed, there could be fundamental - * yet subtle errors in message manipulation anywhere in the code base. It 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 simplies maintentance by localizing changes to - * the message to a few files. + * 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__) @@ -48,17 +48,20 @@ typedef struct { } ALIGNED ODK_Message; typedef enum { - MESSAGE_STATUS_OK = 0xe937fcf7, - MESSAGE_STATUS_UNKNOWN_ERROR = 0xe06c1190, - MESSAGE_STATUS_OVERFLOW_ERROR = 0xc43ae4bc, + MESSAGE_STATUS_OK = 0x7937fcf7, + MESSAGE_STATUS_UNKNOWN_ERROR = 0x706c1190, + MESSAGE_STATUS_OVERFLOW_ERROR = 0x543ae4bc, 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_END_OF_MESSAGE_ERROR = 0x798db72a, + MESSAGE_STATUS_INVALID_ENUM_VALUE = 0x7db88197, MESSAGE_STATUS_INVALID_TAG_ERROR = 0x14dce06a, - MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6 + MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6, + MESSAGE_STATUS_OUT_OF_MEMORY = 0x7c5c64cc, + MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0x7afecacf, + MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873 } ODK_MessageStatus; /* diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index b373233..fba3c3a 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -1,24 +1,25 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ #define WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ +#ifdef __cplusplus +extern "C" { +#endif + #include #include "OEMCryptoCENCCommon.h" #include "odk_target.h" /* The version of this library. */ -#define ODK_MAJOR_VERSION 16 -#define ODK_MINOR_VERSION 5 +#define ODK_MAJOR_VERSION 17 +#define ODK_MINOR_VERSION 1 /* ODK Version string. Date changed automatically on each release. */ -// TODO(b/163416999): Remove the following line when we upgrade to v17. -// The version 16.5 should not be used by any CE CDM release. -#define ODK_RELEASE_DATE "ODK v16.5 (ALCATRAZ ONLY) 2021-01-22" -// #define ODK_RELEASE_DATE "ODK v17.0 2021-01-22" +#define ODK_RELEASE_DATE "ODK v17.1 2022-06-17" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 @@ -26,6 +27,7 @@ /* Some useful constants. */ #define ODK_DEVICE_ID_LEN_MAX 64 #define ODK_SHA256_HASH_SIZE 32 +#define ODK_KEYBOX_RENEWAL_DATA_SIZE 1600 /// @addtogroup odk_timer /// @{ @@ -88,9 +90,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 @@ -113,7 +115,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; @@ -174,11 +176,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; @@ -188,6 +192,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; @@ -215,4 +221,8 @@ typedef struct { /// @} +#ifdef __cplusplus +} // extern "C" +#endif + #endif // WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ diff --git a/oemcrypto/odk/include/odk_target.h b/oemcrypto/odk/include/odk_target.h index cb2774f..d1c0652 100644 --- a/oemcrypto/odk/include/odk_target.h +++ b/oemcrypto/odk/include/odk_target.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file is distributed -// under the Widevine Master License Agreement. +// under the Widevine License Agreement. // Partners are expected to edit this file to support target specific code // and limits. diff --git a/oemcrypto/odk/src/core_message_deserialize.cpp b/oemcrypto/odk/src/core_message_deserialize.cpp index c05fecb..2e69641 100644 --- a/oemcrypto/odk/src/core_message_deserialize.cpp +++ b/oemcrypto/odk/src/core_message_deserialize.cpp @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "core_message_deserialize.h" @@ -10,6 +10,7 @@ #include #include +#include "OEMCryptoCENCCommon.h" #include "odk_serialize.h" #include "odk_structs.h" #include "odk_structs_priv.h" @@ -52,6 +53,7 @@ bool ParseRequest(uint32_t message_type, core_request->api_minor_version = core_message.nonce_values.api_minor_version; core_request->nonce = core_message.nonce_values.nonce; core_request->session_id = core_message.nonce_values.session_id; + // Verify that the minor version matches the released version for the given // major version. if (core_request->api_major_version < ODK_FIRST_VERSION) { @@ -68,10 +70,13 @@ bool ParseRequest(uint32_t message_type, // For v16, a release and a renewal use the same message structure. // However, for future API versions, the release might be a separate // message. Otherwise, we expect an exact match of message types. + // A provisioning request may contain a renewed provisioning message. if (message_type != ODK_Common_Request_Type && core_message.message_type != message_type && !(message_type == ODK_Renewal_Request_Type && - core_message.message_type == ODK_Release_Request_Type)) { + core_message.message_type == ODK_Release_Request_Type) && + !(message_type == ODK_Provisioning_Request_Type && + core_message.message_type == ODK_Renewed_Provisioning_Request_Type)) { return false; } // Verify that the amount of buffer we read, which is GetOffset, is not more @@ -125,6 +130,42 @@ bool CoreProvisioningRequestFromMessage( } core_provisioning_request->device_id.assign( reinterpret_cast(device_id), device_id_length); + core_provisioning_request->renewal_type = OEMCrypto_NoRenewal; + core_provisioning_request->renewal_data.clear(); + return true; +} + +bool CoreRenewedProvisioningRequestFromMessage( + const std::string& oemcrypto_core_message, + ODK_ProvisioningRequest* core_provisioning_request) { + const auto unpacker = Unpack_ODK_PreparedRenewedProvisioningRequest; + ODK_PreparedRenewedProvisioningRequest prepared_provision = {}; + if (!ParseRequest(ODK_Renewed_Provisioning_Request_Type, + oemcrypto_core_message, core_provisioning_request, + &prepared_provision, unpacker)) { + return false; + } + const uint8_t* device_id = prepared_provision.device_id; + const uint32_t device_id_length = prepared_provision.device_id_length; + if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { + return false; + } + uint8_t zero[ODK_DEVICE_ID_LEN_MAX] = {}; + if (memcmp(zero, device_id + device_id_length, + ODK_DEVICE_ID_LEN_MAX - device_id_length)) { + return false; + } + core_provisioning_request->device_id.assign( + reinterpret_cast(device_id), device_id_length); + + if (prepared_provision.renewal_data_length > + sizeof(prepared_provision.renewal_data)) { + return false; + } + core_provisioning_request->renewal_type = OEMCrypto_RenewalACert; + core_provisioning_request->renewal_data.assign( + reinterpret_cast(prepared_provision.renewal_data), + prepared_provision.renewal_data_length); return true; } diff --git a/oemcrypto/odk/src/core_message_features.cpp b/oemcrypto/odk/src/core_message_features.cpp new file mode 100644 index 0000000..615e477 --- /dev/null +++ b/oemcrypto/odk/src/core_message_features.cpp @@ -0,0 +1,41 @@ +// Copyright 2021 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#include "core_message_features.h" + +namespace oemcrypto_core_message { +namespace features { +const CoreMessageFeatures CoreMessageFeatures::kDefaultFeatures; + +bool CoreMessageFeatures::operator==(const CoreMessageFeatures &other) const { + return maximum_major_version == other.maximum_major_version && + maximum_minor_version == other.maximum_minor_version; +} + +CoreMessageFeatures CoreMessageFeatures::DefaultFeatures( + uint32_t maximum_major_version) { + CoreMessageFeatures features; + features.maximum_major_version = maximum_major_version; + // The default minor version is the highest for each major version. + switch (maximum_major_version) { + case 16: + features.maximum_minor_version = 5; // 16.5 + break; + case 17: + features.maximum_minor_version = 1; // 17.1 + break; + default: + features.maximum_minor_version = 0; + } + return features; +} + +std::ostream &operator<<(std::ostream &os, + const CoreMessageFeatures &features) { + return os << "v" << features.maximum_major_version << "." + << features.maximum_minor_version; +} + +} // namespace features +} // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/src/core_message_serialize.cpp b/oemcrypto/odk/src/core_message_serialize.cpp index 0d15d2b..3c3590e 100644 --- a/oemcrypto/odk/src/core_message_serialize.cpp +++ b/oemcrypto/odk/src/core_message_serialize.cpp @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "core_message_serialize.h" @@ -13,6 +13,7 @@ #include "odk_serialize.h" #include "odk_structs.h" #include "odk_structs_priv.h" +#include "odk_target.h" #include "serialization_base.h" namespace oemcrypto_core_message { @@ -20,7 +21,45 @@ 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 + */ +template +bool CreateResponseHeader(const CoreMessageFeatures& features, + ODK_MessageType message_type, const S& core_request, + T& response) { + // Bad major version. + if ((features.maximum_major_version > ODK_MAJOR_VERSION) || + (features.maximum_major_version == ODK_MAJOR_VERSION && + features.maximum_minor_version > ODK_MINOR_VERSION)) { + // TODO(b/147513335): this should be logged. + return false; + } + + auto* header = &response.request.core_message; + header->message_type = message_type; + header->nonce_values.api_major_version = core_request.api_major_version; + header->nonce_values.api_minor_version = core_request.api_minor_version; + header->nonce_values.nonce = core_request.nonce; + 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 > 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 @@ -34,21 +73,11 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request, if (!oemcrypto_core_message) { return false; } - auto* header = &response.request.core_message; - header->message_type = message_type; - header->nonce_values.api_major_version = core_request.api_major_version; - header->nonce_values.api_minor_version = core_request.api_minor_version; - header->nonce_values.nonce = core_request.nonce; - 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; - } else if (core_request.api_major_version == ODK_MAJOR_VERSION && - core_request.api_minor_version > ODK_MINOR_VERSION) { - header->nonce_values.api_minor_version = ODK_MINOR_VERSION; + 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; @@ -59,7 +88,7 @@ bool CreateResponse(ODK_MessageType message_type, const S& core_request, return false; } - uint32_t message_length = ODK_Message_GetSize(&msg); + uint32_t message_length = static_cast(ODK_Message_GetSize(&msg)); msg = ODK_Message_Create(buf.data() + sizeof(header->message_type), sizeof(header->message_length)); Pack_uint32_t(&msg, &message_length); @@ -75,7 +104,7 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src, if (request.device_id_length > sizeof(request.device_id)) { return false; } - request.device_id_length = device_id.size(); + request.device_id_length = static_cast(device_id.size()); memset(request.device_id, 0, sizeof(request.device_id)); memcpy(request.device_id, device_id.data(), request.device_id_length); return true; @@ -83,33 +112,78 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src, } // namespace -bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, +bool CreateCoreLicenseResponse(const CoreMessageFeatures& features, + const ODK_ParsedLicense& parsed_lic, const ODK_LicenseRequest& core_request, const std::string& core_request_sha256, std::string* oemcrypto_core_message) { ODK_LicenseResponse license_response{ - {}, const_cast(&parsed_lic), {0}}; - if (core_request_sha256.size() != sizeof(license_response.request_hash)) + {}, const_cast(&parsed_lic)}; + if (!CreateResponseHeader(features, ODK_License_Response_Type, core_request, + license_response)) { return false; - memcpy(license_response.request_hash, core_request_sha256.data(), - sizeof(license_response.request_hash)); + } + if (ODK_MAX_NUM_KEYS < license_response.parsed_license->key_array_length) { + return false; + } + 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.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{ @@ -117,6 +191,10 @@ bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, if (!CopyDeviceId(core_request, &prov_response)) { return false; } + if (!CreateResponseHeader(features, ODK_Provisioning_Response_Type, + core_request, prov_response)) { + return false; + } return CreateResponse(ODK_Provisioning_Response_Type, core_request, oemcrypto_core_message, prov_response, Pack_ODK_ProvisioningResponse); diff --git a/oemcrypto/odk/src/core_message_serialize_proto.cpp b/oemcrypto/odk/src/core_message_serialize_proto.cpp index 00a5e5e..5132bda 100644 --- a/oemcrypto/odk/src/core_message_serialize_proto.cpp +++ b/oemcrypto/odk/src/core_message_serialize_proto.cpp @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "core_message_serialize_proto.h" @@ -20,6 +20,7 @@ namespace oemcrypto_core_message { namespace serialize { namespace { +using oemcrypto_core_message::features::CoreMessageFeatures; /* @ private functions */ @@ -70,7 +71,8 @@ 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, @@ -99,8 +101,11 @@ bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, } case video_widevine::License_KeyContainer::CONTENT: case video_widevine::License_KeyContainer::OPERATOR_SESSION: + case video_widevine::License_KeyContainer::OEM_CONTENT: + case video_widevine::License_KeyContainer::OEM_ENTITLEMENT: case video_widevine::License_KeyContainer::ENTITLEMENT: { - if (k.type() == video_widevine::License_KeyContainer::ENTITLEMENT) { + if (k.type() == video_widevine::License_KeyContainer::ENTITLEMENT || + k.type() == video_widevine::License_KeyContainer::OEM_ENTITLEMENT) { any_entitlement = true; } else { any_content = true; @@ -133,12 +138,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; @@ -154,11 +160,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) { @@ -183,7 +190,7 @@ bool CreateCoreProvisioningResponseFromProto( GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key()); } - return CreateCoreProvisioningResponse(parsed_prov, core_request, + return CreateCoreProvisioningResponse(features, parsed_prov, core_request, oemcrypto_core_message); } diff --git a/oemcrypto/odk/src/kdo.gypi b/oemcrypto/odk/src/kdo.gypi index 555a8f0..6e77b45 100644 --- a/oemcrypto/odk/src/kdo.gypi +++ b/oemcrypto/odk/src/kdo.gypi @@ -1,5 +1,5 @@ # Copyright 2019 Google LLC. All rights reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master License +# source code may only be used and distributed under the Widevine License # Agreement. # These files are used by the server and by some ODK test code. These files are @@ -7,6 +7,7 @@ { 'sources': [ 'core_message_deserialize.cpp', + 'core_message_features.cpp', 'core_message_serialize.cpp', 'core_message_serialize_proto.cpp', ], diff --git a/oemcrypto/odk/src/odk.c b/oemcrypto/odk/src/odk.c index f0ec34e..4f28389 100644 --- a/oemcrypto/odk/src/odk.c +++ b/oemcrypto/odk/src/odk.c @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "odk.h" @@ -72,6 +72,17 @@ static OEMCryptoResult ODK_PrepareRequest( &msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer); break; } + case ODK_Renewed_Provisioning_Request_Type: { + core_message->message_length = ODK_RENEWED_PROVISIONING_REQUEST_SIZE; + if (sizeof(ODK_PreparedRenewedProvisioningRequest) > + prepared_request_buffer_length) { + return ODK_ERROR_CORE_MESSAGE; + } + Pack_ODK_PreparedRenewedProvisioningRequest( + &msg, + (ODK_PreparedRenewedProvisioningRequest*)prepared_request_buffer); + break; + } default: { return ODK_ERROR_CORE_MESSAGE; } @@ -91,64 +102,65 @@ static OEMCryptoResult ODK_PrepareRequest( 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 response'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); - /* 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. */ + /* 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); - /* 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 (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || - message_type != core_message->message_type || - ODK_Message_GetOffset(&msg) != core_message->message_length) { + 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; } @@ -162,9 +174,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest( if (core_message_length == NULL || nonce_values == NULL) { return ODK_ERROR_CORE_MESSAGE; } - ODK_PreparedLicenseRequest license_request = { - {0, 0, {}}, - }; + ODK_PreparedLicenseRequest license_request = {0}; return ODK_PrepareRequest( message, message_length, core_message_length, ODK_License_Request_Type, nonce_values, &license_request, sizeof(ODK_PreparedLicenseRequest)); @@ -192,7 +202,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, return OEMCrypto_SUCCESS; } - ODK_PreparedRenewalRequest renewal_request = {{0, 0, {}}, 0}; + ODK_PreparedRenewalRequest renewal_request = {0}; /* First, we compute the time this request was made relative to the playback * clock. */ if (clock_values->time_of_first_decrypt == 0) { @@ -225,11 +235,7 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( if (core_message_length == NULL || nonce_values == NULL) { return ODK_ERROR_CORE_MESSAGE; } - ODK_PreparedProvisioningRequest provisioning_request = { - {0, 0, {}}, - 0, - {0}, - }; + ODK_PreparedProvisioningRequest provisioning_request = {0}; if (device_id_length > sizeof(provisioning_request.device_id)) { return ODK_ERROR_CORE_MESSAGE; } @@ -243,52 +249,124 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( sizeof(ODK_PreparedProvisioningRequest)); } +OEMCryptoResult ODK_PrepareCoreRenewedProvisioningRequest( + uint8_t* message, size_t message_length, size_t* core_message_length, + const ODK_NonceValues* nonce_values, const uint8_t* device_id, + size_t device_id_length, uint16_t renewal_type, const uint8_t* renewal_data, + size_t renewal_data_length) { + if (core_message_length == NULL || nonce_values == NULL) { + return ODK_ERROR_CORE_MESSAGE; + } + ODK_PreparedRenewedProvisioningRequest provisioning_request = {0}; + if (device_id_length > sizeof(provisioning_request.device_id)) { + return ODK_ERROR_CORE_MESSAGE; + } + provisioning_request.device_id_length = (uint32_t)device_id_length; + if (device_id) { + memcpy(provisioning_request.device_id, device_id, device_id_length); + } + if (renewal_data_length > sizeof(provisioning_request.renewal_data)) { + return ODK_ERROR_CORE_MESSAGE; + } + provisioning_request.renewal_type = renewal_type; + provisioning_request.renewal_data_length = (uint32_t)renewal_data_length; + if (renewal_data) { + memcpy(provisioning_request.renewal_data, renewal_data, + renewal_data_length); + } + return ODK_PrepareRequest(message, message_length, core_message_length, + ODK_Renewed_Provisioning_Request_Type, nonce_values, + &provisioning_request, + sizeof(provisioning_request)); +} + /* @@ parse response functions */ 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}; + 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}; + 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) || @@ -315,15 +393,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; @@ -342,17 +411,27 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, return ODK_ERROR_CORE_MESSAGE; } - 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)); - + 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}; + 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 (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: * Doc: License Duration and Renewal (Changes for OEMCrypto v16) @@ -381,21 +460,31 @@ OEMCryptoResult ODK_ParseProvisioning( parsed_response == NULL) { return ODK_ERROR_CORE_MESSAGE; } - - ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL}; + 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}; provisioning_response.parsed_provisioning = parsed_response; if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { 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, @@ -413,3 +502,10 @@ OEMCryptoResult ODK_ParseProvisioning( return OEMCrypto_SUCCESS; } + +bool CheckApiVersionAtMost(const ODK_NonceValues* nonce_values, + uint16_t major_version, uint16_t minor_version) { + return nonce_values->api_major_version < major_version || + (nonce_values->api_major_version == major_version && + nonce_values->api_minor_version <= minor_version); +} diff --git a/oemcrypto/odk/src/odk.gyp b/oemcrypto/odk/src/odk.gyp index a16dec6..b874247 100644 --- a/oemcrypto/odk/src/odk.gyp +++ b/oemcrypto/odk/src/odk.gyp @@ -1,12 +1,14 @@ # Copyright 2019 Google LLC. All rights reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master License +# source code may only be used and distributed under the Widevine License # Agreement. { 'targets': [ { + 'toolsets' : [ 'target' ], 'target_name': 'odk', 'type': 'static_library', + 'standalone_static_library' : 1, 'include_dirs': [ '../include', '../../include', @@ -14,9 +16,23 @@ 'includes' : [ 'odk.gypi', ], + 'cflags': [ + # TODO(b/172518513): Remove this + '-Wno-error=cast-qual', + ], + 'defines': [ + # Needed for to work. + '_DEFAULT_SOURCE', + ], 'direct_dependent_settings': { + 'defines': [ + # Needed for to work. + '_DEFAULT_SOURCE', + ], 'include_dirs': [ + '.', '../include', + '../../include', ], } }, diff --git a/oemcrypto/odk/src/odk.gypi b/oemcrypto/odk/src/odk.gypi index 0d194da..1867605 100644 --- a/oemcrypto/odk/src/odk.gypi +++ b/oemcrypto/odk/src/odk.gypi @@ -1,5 +1,5 @@ # Copyright 2019 Google LLC. All rights reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master License +# source code may only be used and distributed under the Widevine License # Agreement. # These files are built into the ODK library on the device. They are also used diff --git a/oemcrypto/odk/src/odk_assert.h b/oemcrypto/odk/src/odk_assert.h index 149021f..0517818 100644 --- a/oemcrypto/odk/src/odk_assert.h +++ b/oemcrypto/odk/src/odk_assert.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_SRC_ODK_ASSERT_H_ diff --git a/oemcrypto/odk/src/odk_endian.h b/oemcrypto/odk/src/odk_endian.h index 3968f9c..1e9f50d 100644 --- a/oemcrypto/odk/src/odk_endian.h +++ b/oemcrypto/odk/src/odk_endian.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_SRC_ODK_ENDIAN_H_ @@ -11,11 +11,23 @@ extern "C" { #if defined(__linux__) || defined(__ANDROID__) #include +#define oemcrypto_htobe16 htobe16 +#define oemcrypto_be16toh be16toh #define oemcrypto_htobe32 htobe32 #define oemcrypto_be32toh be32toh #define oemcrypto_htobe64 htobe64 #define oemcrypto_be64toh be64toh +#elif defined(__APPLE__) +#include +#define oemcrypto_htobe16 OSSwapHostToBigInt16 +#define oemcrypto_be16toh OSSwapBigToHostInt16 +#define oemcrypto_htobe32 OSSwapHostToBigInt32 +#define oemcrypto_be32toh OSSwapBigToHostInt32 +#define oemcrypto_htobe64 OSSwapHostToBigInt64 +#define oemcrypto_be64toh OSSwapBigToHostInt64 #else /* defined(__linux__) || defined(__ANDROID__) */ +uint32_t oemcrypto_htobe16(uint16_t u16); +uint32_t oemcrypto_be16toh(uint16_t u16); uint32_t oemcrypto_htobe32(uint32_t u32); uint32_t oemcrypto_be32toh(uint32_t u32); uint64_t oemcrypto_htobe64(uint64_t u64); diff --git a/oemcrypto/odk/src/odk_message.c b/oemcrypto/odk/src/odk_message.c index 97dcf3c..df29d23 100644 --- a/oemcrypto/odk/src/odk_message.c +++ b/oemcrypto/odk/src/odk_message.c @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "odk_message.h" @@ -26,9 +26,12 @@ static_assert( /* * 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. + * 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)); @@ -36,25 +39,28 @@ ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message; message_impl->base = buffer; message_impl->capacity = capacity; - ODK_Message_Clear(&message); - if (buffer == NULL || capacity == 0) { - message_impl->status = MESSAGE_STATUS_NOT_INITIALIZED; - } + 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 status is reset to - * MESSAGE_STATUS_OK. + * 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); - ODK_Message_Reset(message); + 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); + } } /* @@ -122,7 +128,10 @@ ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message) { void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) { ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; assert(message_impl != NULL); - message_impl->status = status; + /* preserve the first error */ + if (message_impl->status == MESSAGE_STATUS_OK) { + message_impl->status = status; + } } /* @@ -132,13 +141,15 @@ void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) { 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. + * 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); @@ -149,10 +160,6 @@ bool ODK_Message_IsValid(ODK_Message* message) { if (message_impl->status != MESSAGE_STATUS_OK) { return false; } - if (message_impl->base == NULL) { - message_impl->status = MESSAGE_STATUS_NULL_POINTER_ERROR; - return false; - } if (message_impl->read_offset > message_impl->capacity || message_impl->size > message_impl->capacity || message_impl->read_offset > message_impl->size) { diff --git a/oemcrypto/odk/src/odk_message_priv.h b/oemcrypto/odk/src/odk_message_priv.h index 21d1f5d..8ad5f03 100644 --- a/oemcrypto/odk/src/odk_message_priv.h +++ b/oemcrypto/odk/src/odk_message_priv.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_SRC_ODK_MESSAGE_PRIV_H_ diff --git a/oemcrypto/odk/src/odk_overflow.c b/oemcrypto/odk/src/odk_overflow.c index a03f0f6..0ebc084 100644 --- a/oemcrypto/odk/src/odk_overflow.c +++ b/oemcrypto/odk/src/odk_overflow.c @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include @@ -34,3 +34,13 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c) { } return 1; } + +int odk_mul_overflow_ux(size_t a, size_t b, size_t* c) { + if (b > 0 && a > SIZE_MAX / b) { + return 1; + } + if (c) { + *c = a * b; + } + return 0; +} diff --git a/oemcrypto/odk/src/odk_overflow.h b/oemcrypto/odk/src/odk_overflow.h index 6f3f994..e725705 100644 --- a/oemcrypto/odk/src/odk_overflow.h +++ b/oemcrypto/odk/src/odk_overflow.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_ @@ -15,6 +15,7 @@ extern "C" { int odk_sub_overflow_u64(uint64_t a, uint64_t b, uint64_t* c); int odk_add_overflow_u64(uint64_t a, uint64_t b, uint64_t* c); int odk_add_overflow_ux(size_t a, size_t b, size_t* c); +int odk_mul_overflow_ux(size_t a, size_t b, size_t* c); #ifdef __cplusplus } diff --git a/oemcrypto/odk/src/odk_serialize.c b/oemcrypto/odk/src/odk_serialize.c index d881e3d..5c58200 100644 --- a/oemcrypto/odk/src/odk_serialize.c +++ b/oemcrypto/odk/src/odk_serialize.c @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. /* @@ -58,6 +58,47 @@ static void Pack_ODK_ParsedLicense(ODK_Message* msg, 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); + 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->key_array_length); size_t i; for (i = 0; i < (size_t)obj->key_array_length; i++) { @@ -87,18 +128,34 @@ void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, } void Pack_ODK_PreparedProvisioningRequest( - ODK_Message* msg, ODK_PreparedProvisioningRequest const* obj) { + ODK_Message* msg, const ODK_PreparedProvisioningRequest* 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)); } +void Pack_ODK_PreparedRenewedProvisioningRequest( + ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* 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)); + Pack_uint16_t(msg, &obj->renewal_type); + Pack_uint32_t(msg, &obj->renewal_data_length); + PackArray(msg, &obj->renewal_data[0], sizeof(obj->renewal_data)); +} + /* @@ kdo serialize */ 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)); } @@ -109,7 +166,7 @@ void Pack_ODK_RenewalResponse(ODK_Message* msg, } void Pack_ODK_ProvisioningResponse(ODK_Message* msg, - ODK_ProvisioningResponse const* obj) { + const ODK_ProvisioningResponse* obj) { Pack_ODK_PreparedProvisioningRequest(msg, &obj->request); Pack_ODK_ParsedProvisioning( msg, (const ODK_ParsedProvisioning*)obj->parsed_provisioning); @@ -126,7 +183,7 @@ static void Unpack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues* obj) { Unpack_uint32_t(msg, &obj->session_id); } -static void Unpack_ODK_CoreMessage(ODK_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); @@ -158,6 +215,64 @@ static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) { 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); + 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->key_array_length); if (obj->key_array_length > ODK_MAX_NUM_KEYS) { ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); @@ -197,6 +312,16 @@ void Unpack_ODK_PreparedProvisioningRequest( UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id)); } +void Unpack_ODK_PreparedRenewedProvisioningRequest( + ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* 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)); + Unpack_uint16_t(msg, &obj->renewal_type); + Unpack_uint32_t(msg, &obj->renewal_data_length); + UnpackArray(msg, &obj->renewal_data[0], obj->renewal_data_length); +} + void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, ODK_PreparedCommonRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); @@ -206,6 +331,12 @@ void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, 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)); } diff --git a/oemcrypto/odk/src/odk_serialize.h b/oemcrypto/odk/src/odk_serialize.h index 33944b5..0904700 100644 --- a/oemcrypto/odk/src/odk_serialize.h +++ b/oemcrypto/odk/src/odk_serialize.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. /* @@ -22,15 +22,22 @@ void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, const ODK_PreparedRenewalRequest* obj); void Pack_ODK_PreparedProvisioningRequest( ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj); +void Pack_ODK_PreparedRenewedProvisioningRequest( + ODK_Message* msg, const ODK_PreparedRenewedProvisioningRequest* obj); /* odk unpack */ +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(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); @@ -42,6 +49,8 @@ void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest* obj); void Unpack_ODK_PreparedProvisioningRequest( ODK_Message* msg, ODK_PreparedProvisioningRequest* obj); +void Unpack_ODK_PreparedRenewedProvisioningRequest( + ODK_Message* msg, ODK_PreparedRenewedProvisioningRequest* obj); void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, ODK_PreparedCommonRequest* obj); diff --git a/oemcrypto/odk/src/odk_structs_priv.h b/oemcrypto/odk/src/odk_structs_priv.h index a9a5fdc..3fe73ee 100644 --- a/oemcrypto/odk/src/odk_structs_priv.h +++ b/oemcrypto/odk/src/odk_structs_priv.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_ @@ -24,6 +24,7 @@ typedef uint32_t ODK_MessageType; #define ODK_Renewal_Response_Type ((ODK_MessageType)4u) #define ODK_Provisioning_Request_Type ((ODK_MessageType)5u) #define ODK_Provisioning_Response_Type ((ODK_MessageType)6u) +#define ODK_Renewed_Provisioning_Request_Type ((ODK_MessageType)11u) // Reserve future message types to support forward compatibility. #define ODK_Release_Request_Type ((ODK_MessageType)7u) @@ -32,8 +33,8 @@ typedef uint32_t ODK_MessageType; #define ODK_Common_Response_Type ((ODK_MessageType)10u) typedef struct { - ODK_MessageType 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; @@ -52,16 +53,42 @@ typedef struct { uint8_t device_id[ODK_DEVICE_ID_LEN_MAX]; } ODK_PreparedProvisioningRequest; +typedef struct { + ODK_CoreMessage core_message; + uint32_t device_id_length; + uint8_t device_id[ODK_DEVICE_ID_LEN_MAX]; + uint16_t renewal_type; + uint32_t renewal_data_length; + uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE]; +} ODK_PreparedRenewedProvisioningRequest; + 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; @@ -76,26 +103,27 @@ 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 +#define ODK_RENEWED_PROVISIONING_REQUEST_SIZE 1694u // These are the possible timer status values. -#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0 // Should not happen. +#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0u // Should not happen. // When the structure has been initialized, but no license is loaded. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1u // After the license is loaded, before a successful decrypt. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2u // After the license is loaded, if a renewal has also been loaded. -#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3 +#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3u // The first decrypt has occurred and the timer is active. -#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4 +#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4u // The first decrypt has occurred and the timer is unlimited. -#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5 +#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5u // The timer has transitioned from active to expired. -#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6 +#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6u // The license has been marked as inactive. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7u // A helper function for computing timer limits when a renewal is loaded. OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits, diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index 67c3470..1b09551 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include @@ -71,7 +71,7 @@ static OEMCryptoResult ODK_CheckRentalWindow( /* rental_clock = time since license signed. */ uint64_t rental_clock = 0; if (odk_sub_overflow_u64(system_time_seconds, - clock_values->time_of_license_signed, + clock_values->time_of_license_request_signed, &rental_clock)) { return OEMCrypto_ERROR_INVALID_CONTEXT; } @@ -180,7 +180,7 @@ OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits, } /* If this is before the license was signed, something is odd. Return an * error. */ - if (system_time_seconds < clock_values->time_of_license_signed) { + if (system_time_seconds < clock_values->time_of_license_request_signed) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -297,7 +297,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, if (clock_values == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - clock_values->time_of_license_signed = system_time_seconds; + clock_values->time_of_license_request_signed = system_time_seconds; clock_values->time_of_first_decrypt = 0; clock_values->time_of_last_decrypt = 0; clock_values->time_when_timer_expires = 0; @@ -308,7 +308,7 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, /* This is called when OEMCrypto reloads a usage entry. */ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values, - uint64_t time_of_license_signed, + uint64_t time_of_license_request_signed, uint64_t time_of_first_decrypt, uint64_t time_of_last_decrypt, enum OEMCrypto_Usage_Entry_Status status, @@ -316,7 +316,7 @@ OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values, if (clock_values == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; } - clock_values->time_of_license_signed = time_of_license_signed; + clock_values->time_of_license_request_signed = time_of_license_request_signed; clock_values->time_of_first_decrypt = time_of_first_decrypt; clock_values->time_of_last_decrypt = time_of_last_decrypt; clock_values->time_when_timer_expires = 0; @@ -336,7 +336,7 @@ OEMCryptoResult ODK_AttemptFirstPlayback(uint64_t system_time_seconds, /* All times are relative to when the license was signed. */ uint64_t rental_time = 0; if (odk_sub_overflow_u64(system_time_seconds, - clock_values->time_of_license_signed, + clock_values->time_of_license_request_signed, &rental_time)) { return OEMCrypto_ERROR_INVALID_CONTEXT; } diff --git a/oemcrypto/odk/src/odk_util.c b/oemcrypto/odk/src/odk_util.c index 682bf8e..a6669a4 100644 --- a/oemcrypto/odk/src/odk_util.c +++ b/oemcrypto/odk/src/odk_util.c @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "odk_util.h" @@ -24,11 +24,10 @@ int crypto_memcmp(const void* in_a, const void* in_b, size_t len) { return x; } -bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b) { +bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a, + const ODK_NonceValues* b) { if (a == NULL || b == NULL) { return (a == b); } - return (a->api_major_version == b->api_major_version && - a->api_minor_version == b->api_minor_version && - a->nonce == b->nonce && a->session_id == b->session_id); + return (a->nonce == b->nonce && a->session_id == b->session_id); } diff --git a/oemcrypto/odk/src/odk_util.h b/oemcrypto/odk/src/odk_util.h index 138791f..ab932dd 100644 --- a/oemcrypto/odk/src/odk_util.h +++ b/oemcrypto/odk/src/odk_util.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_SRC_ODK_UTIL_H_ @@ -20,7 +20,8 @@ extern "C" { * return value when a != b is undefined, other than being non-zero. */ int crypto_memcmp(const void* a, const void* b, size_t len); -bool ODK_NonceValuesEqual(const ODK_NonceValues* a, const ODK_NonceValues* b); +bool ODK_NonceValuesEqualExcludingVersion(const ODK_NonceValues* a, + const ODK_NonceValues* b); #ifdef __cplusplus } // extern "C" diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c index b54ea79..30af34c 100644 --- a/oemcrypto/odk/src/serialization_base.c +++ b/oemcrypto/odk/src/serialization_base.c @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "serialization_base.h" @@ -29,7 +29,8 @@ 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), (void*)ptr, count); + memcpy((void*)(message_impl->base + message_impl->size), (const void*)ptr, + count); message_impl->size += count; } else { message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; @@ -37,7 +38,7 @@ static void PackBytes(ODK_Message* message, const uint8_t* ptr, size_t count) { } void Pack_enum(ODK_Message* message, int value) { - uint32_t v32 = value; + uint32_t v32 = (uint32_t)value; Pack_uint32_t(message, &v32); } @@ -48,6 +49,13 @@ void Pack_bool(ODK_Message* message, const bool* value) { PackBytes(message, data, sizeof(data)); } +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}; @@ -113,6 +121,13 @@ void Unpack_bool(ODK_Message* message, bool* value) { *value = (0 != data[3]); } +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}; @@ -154,10 +169,18 @@ void Unpack_OEMCrypto_Substring(ODK_Message* message, /* 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_impl->capacity - - * message_impl->size or offset + length + message_impl->size < - * message_impl->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 */ + 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) || diff --git a/oemcrypto/odk/src/serialization_base.h b/oemcrypto/odk/src/serialization_base.h index fdcc91a..7b69e11 100644 --- a/oemcrypto/odk/src/serialization_base.h +++ b/oemcrypto/odk/src/serialization_base.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_ @@ -17,6 +17,7 @@ extern "C" { 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); @@ -26,6 +27,7 @@ void Pack_OEMCrypto_Substring(ODK_Message* message, 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); diff --git a/oemcrypto/odk/test/fuzzing/Android.bp b/oemcrypto/odk/test/fuzzing/Android.bp index f0093f4..3b8fe6d 100644 --- a/oemcrypto/odk/test/fuzzing/Android.bp +++ b/oemcrypto/odk/test/fuzzing/Android.bp @@ -1,7 +1,19 @@ // Copyright 2020 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_defaults { name: "odk_fuzz_library_defaults", srcs: [ @@ -165,4 +177,4 @@ cc_fuzz { ], defaults: ["odk_fuzz_library_defaults"], proprietary: true, -} \ No newline at end of file +} diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp index e993971..78519cb 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp @@ -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 Master +// source code may only be used and distributed under the Widevine // License Agreement. // ---------------------------------------------------------------- @@ -9,6 +9,18 @@ // ---------------------------------------------------------------- // Builds libwv_odk.so, The ODK shared Library (libwv_odk) is used // by the OEMCrypto unit tests to generate corpus for ODK fuzz scrips. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_library_shared { name: "libwv_odk_corpus_generator", include_dirs: [ diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c index 9a3e985..0a2d074 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator.c @@ -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 Master +// source code may only be used and distributed under the Widevine // License Agreement. // We must define this macro to get RTLD_NEXT definition from diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.c b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.c index 3a720d2..534b245 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.c +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.c @@ -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 Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "fuzzing/corpus_generator/odk_corpus_generator_helper.h" diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.h b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.h index c2f164a..d6c1e99 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.h +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_corpus_generator_helper.h @@ -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 Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_ #define WIDEVINE_ODK_TEST_FUZZING_CORPUS_GENERATOR_ODK_CORPUS_GENERATOR_HELPER_H_ diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_fuzz_corpus_generator.gyp b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_fuzz_corpus_generator.gyp index 8acf1ac..8329984 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/odk_fuzz_corpus_generator.gyp +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/odk_fuzz_corpus_generator.gyp @@ -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 Master License +# source code may only be used and distributed under the Widevine License # Agreement. # Reference Link explaining flags for LD_PRELOAD: https://catonmat.net/simple-ld-preload-tutorial-part-two diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp index 58f00b0..7602e0a 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp @@ -1,5 +1,5 @@ # Copyright 2019 Google LLC. All rights reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master License +# source code may only be used and distributed under the Widevine License # Agreement. #TODO(b/151858867): Fix File paths @@ -18,6 +18,10 @@ '../src', '../kdo/include', ], + 'cflags': [ + # TODO(b/172518513): Remove this + '-Wno-error=cast-qual', + ], 'cflags_cc': [ '-std=c++11', '-g3', diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp index 5ea04c1..1f3b230 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp @@ -1,11 +1,14 @@ // Copyright 2020 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "fuzzing/odk_fuzz_helper.h" +#include + #include "odk.h" namespace oemcrypto_core_message { +using features::CoreMessageFeatures; bool convert_byte_to_valid_boolean(const bool* in) { const char* buf = reinterpret_cast(in); @@ -67,8 +70,8 @@ OEMCryptoResult odk_deserialize_LicenseResponse(const uint8_t* message, return ODK_ParseLicense(message, SIZE_MAX, core_message_length, static_cast(a->initial_license_load), static_cast(a->usage_entry_present), - a->request_hash, &a->timer_limits, &a->clock_values, - nonce_values, parsed_lic); + &a->timer_limits, &a->clock_values, nonce_values, + parsed_lic); } OEMCryptoResult odk_deserialize_RenewalResponse( @@ -122,7 +125,8 @@ bool kdo_serialize_LicenseResponse(const ODK_ParseLicense_Args* args, std::string core_request_sha_256( reinterpret_cast(args->request_hash), ODK_SHA256_HASH_SIZE); return serialize::CreateCoreLicenseResponse( - parsed_lic, core_request, core_request_sha_256, oemcrypto_core_message); + CoreMessageFeatures::kDefaultFeatures, parsed_lic, core_request, + core_request_sha_256, oemcrypto_core_message); } bool kdo_serialize_RenewalResponse( @@ -134,7 +138,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); } @@ -151,7 +156,8 @@ bool kdo_serialize_ProvisioningResponse( nonce_values.nonce, nonce_values.session_id, std::string(reinterpret_cast(args->device_id), args->device_id_length)}; - return serialize::CreateCoreProvisioningResponse(parsed_prov, core_request, - oemcrypto_core_message); + return serialize::CreateCoreProvisioningResponse( + CoreMessageFeatures::kDefaultFeatures, parsed_prov, core_request, + oemcrypto_core_message); } } // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h index fe90657..0f45467 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.h @@ -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 Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_ #define WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_HELPER_H_ @@ -7,6 +7,7 @@ #include #include +#include "core_message_features.h" #include "core_message_serialize.h" #include "fuzzing/odk_fuzz_structs.h" #include "odk_attributes.h" diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h b/oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h index 37d1b23..b35c56a 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_structs.h @@ -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 Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_ #define WIDEVINE_ODK_TEST_FUZZING_ODK_FUZZ_STRUCTS_H_ diff --git a/oemcrypto/odk/test/fuzzing/odk_license_request_fuzz.cpp b/oemcrypto/odk/test/fuzzing/odk_license_request_fuzz.cpp index 463c604..d089c4a 100644 --- a/oemcrypto/odk/test/fuzzing/odk_license_request_fuzz.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_license_request_fuzz.cpp @@ -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 Master + * source code may only be used and distributed under the Widevine * License Agreement. */ diff --git a/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz.cpp b/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz.cpp index 12398fd..f365524 100644 --- a/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz.cpp @@ -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 Master + * source code may only be used and distributed under the Widevine * License Agreement. */ diff --git a/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz_with_mutator.cpp index 42472fb..880e1d8 100644 --- a/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz_with_mutator.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_license_response_fuzz_with_mutator.cpp @@ -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 Master + * source code may only be used and distributed under the Widevine * License Agreement. */ diff --git a/oemcrypto/odk/test/fuzzing/odk_provisioning_request_fuzz.cpp b/oemcrypto/odk/test/fuzzing/odk_provisioning_request_fuzz.cpp index 984534e..deac024 100644 --- a/oemcrypto/odk/test/fuzzing/odk_provisioning_request_fuzz.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_provisioning_request_fuzz.cpp @@ -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 Master + * source code may only be used and distributed under the Widevine * License Agreement. */ diff --git a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz.cpp b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz.cpp index 90dc017..3a0457d 100644 --- a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz.cpp @@ -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 Master + * source code may only be used and distributed under the Widevine * License Agreement. */ diff --git a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp index 17787a4..4ad8ca4 100644 --- a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp @@ -1,18 +1,20 @@ /* Copyright 2020 Google LLC. All rights reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master + * source code may only be used and distributed under the Widevine * License Agreement. */ #include #include "fuzzing/odk_fuzz_helper.h" +#include "odk_attributes.h" namespace oemcrypto_core_message { // The custom mutator: Ensure that each input can be deserialized properly // by ODK function after mutation. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, - size_t max_size, unsigned int seed) { + size_t max_size, + unsigned int seed UNUSED) { const size_t kProvisioningResponseArgsSize = sizeof(ODK_ParseProvisioning_Args); if (size < kProvisioningResponseArgsSize) { diff --git a/oemcrypto/odk/test/fuzzing/odk_renewal_request_fuzz.cpp b/oemcrypto/odk/test/fuzzing/odk_renewal_request_fuzz.cpp index 602b37a..d715eeb 100644 --- a/oemcrypto/odk/test/fuzzing/odk_renewal_request_fuzz.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_renewal_request_fuzz.cpp @@ -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 Master + * source code may only be used and distributed under the Widevine * License Agreement. */ diff --git a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz.cpp b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz.cpp index 8d66908..c090375 100644 --- a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz.cpp @@ -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 Master + * source code may only be used and distributed under the Widevine * License Agreement. */ diff --git a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp index 0073c4e..2502ab8 100644 --- a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp @@ -1,18 +1,20 @@ /* Copyright 2020 Google LLC. All rights reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master + * source code may only be used and distributed under the Widevine * License Agreement. */ #include #include "fuzzing/odk_fuzz_helper.h" +#include "odk_attributes.h" namespace oemcrypto_core_message { // The custom mutator: Ensure that each input can be deserialized properly // by ODK function after mutation. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, - size_t max_size, unsigned int seed) { + size_t max_size, + unsigned int seed UNUSED) { const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args); if (size < kRenewalResponseArgsSize) { return 0; diff --git a/oemcrypto/odk/test/odk_core_message_test.cpp b/oemcrypto/odk/test/odk_core_message_test.cpp index c824759..22051b2 100644 --- a/oemcrypto/odk/test/odk_core_message_test.cpp +++ b/oemcrypto/odk/test/odk_core_message_test.cpp @@ -1,7 +1,9 @@ // Copyright 2020 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. +#include + #include "OEMCryptoCENCCommon.h" #include "gtest/gtest.h" #include "odk.h" diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index 52639d0..a244d25 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -1,16 +1,16 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "odk.h" -#include // TODO(b/147944591): use this one? Or odk_endian.h? - #include #include +#include #include "OEMCryptoCENCCommon.h" #include "core_message_deserialize.h" +#include "core_message_features.h" #include "core_message_serialize.h" #include "core_message_types.h" #include "gtest/gtest.h" @@ -28,6 +28,10 @@ using oemcrypto_core_message::ODK_RenewalRequest; using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage; using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage; +using oemcrypto_core_message::deserialize:: + CoreRenewedProvisioningRequestFromMessage; + +using oemcrypto_core_message::features::CoreMessageFeatures; using oemcrypto_core_message::serialize::CreateCoreLicenseResponse; using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse; @@ -39,12 +43,22 @@ constexpr uint32_t kExtraPayloadSize = 128u; * version number, and we will expect the response to have another version * number. */ struct VersionParameters { + uint32_t maximum_major_version; uint16_t request_major_version; uint16_t request_minor_version; uint16_t response_major_version; uint16_t response_minor_version; }; +// This function is called by GTest when a parameterized test fails in order +// to log the parameter used for the failing test. +void PrintTo(const VersionParameters& p, std::ostream* os) { + *os << "max=v" << p.maximum_major_version << ", request = v" + << p.request_major_version << "." << p.request_minor_version + << ", response = v" << p.response_major_version << "." + << p.response_minor_version; +} + template void ValidateRequest(uint32_t message_type, const std::vector& extra_fields, @@ -144,11 +158,14 @@ void ValidateResponse(const VersionParameters& versions, &bytes_read, extra_fields)); // Parse buf with odk - EXPECT_EQ(OEMCrypto_SUCCESS, odk_parse_func(buf, buf_size)); + 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; @@ -189,15 +206,15 @@ TEST(OdkTest, SerializeFieldsStress) { std::srand(0); size_t total_size = 0; for (int i = 0; i < n; i++) { - fields[i].type = static_cast(std::rand() % - static_cast(ODK_NUMTYPES)); + fields[i].type = static_cast( + std::rand() % static_cast(ODK_LAST_STRESSABLE_TYPE)); fields[i].value = malloc(ODK_AllocSize(fields[i].type)); fields[i].name = "stress"; total_size += ODK_FieldLength(fields[i].type); } uint8_t* buf = new uint8_t[total_size]{}; - for (int i = 0; i < total_size; i++) { + for (size_t i = 0; i < total_size; i++) { buf[i] = std::rand() & 0xff; } @@ -256,13 +273,41 @@ TEST(OdkTest, NullRequestTest) { ODK_PrepareCoreProvisioningRequest( message, ODK_PROVISIONING_REQUEST_SIZE, &core_message_length, &nonce_values, nullptr, 0uL)); + + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_PrepareCoreRenewedProvisioningRequest( + nullptr, 0uL, &core_message_length, nullptr, nullptr, 0uL, + OEMCrypto_RenewalACert, nullptr, 0uL)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_PrepareCoreRenewedProvisioningRequest( + nullptr, 0uL, nullptr, &nonce_values, nullptr, 0uL, + OEMCrypto_RenewalACert, nullptr, 0uL)); + + // Null device id in renewed provisioning request is ok + uint8_t renewed_message[ODK_RENEWED_PROVISIONING_REQUEST_SIZE] = {0}; + uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0}; + uint32_t renewal_data_length = ODK_KEYBOX_RENEWAL_DATA_SIZE; + core_message_length = ODK_RENEWED_PROVISIONING_REQUEST_SIZE; + EXPECT_EQ(OEMCrypto_SUCCESS, + ODK_PrepareCoreRenewedProvisioningRequest( + renewed_message, ODK_RENEWED_PROVISIONING_REQUEST_SIZE, + &core_message_length, &nonce_values, nullptr, 0uL, + OEMCrypto_RenewalACert, renewal_data, renewal_data_length)); + + // Null renewal data in renewed provisioning request is ok + uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; + uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX; + core_message_length = ODK_RENEWED_PROVISIONING_REQUEST_SIZE; + ODK_PrepareCoreRenewedProvisioningRequest( + renewed_message, ODK_RENEWED_PROVISIONING_REQUEST_SIZE, + &core_message_length, &nonce_values, device_id, device_id_length, + OEMCrypto_RenewalACert, nullptr, 0uL); } 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; @@ -271,30 +316,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; @@ -413,6 +454,21 @@ TEST(OdkTest, PrepareCoreProvisioningRequest) { &core_message_length, &nonce_values, device_id, sizeof(device_id))); } +TEST(OdkTest, PrepareCoreRenewedProvisioningRequest) { + uint8_t provisioning_message[ODK_RENEWED_PROVISIONING_REQUEST_SIZE] = {0}; + size_t core_message_length = sizeof(provisioning_message); + ODK_NonceValues nonce_values; + memset(&nonce_values, 0, sizeof(nonce_values)); + uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; + uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0}; + EXPECT_EQ( + OEMCrypto_SUCCESS, + ODK_PrepareCoreRenewedProvisioningRequest( + provisioning_message, sizeof(provisioning_message), + &core_message_length, &nonce_values, device_id, sizeof(device_id), + OEMCrypto_RenewalACert, renewal_data, sizeof(renewal_data))); +} + TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) { uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; size_t core_message_length = sizeof(provisioning_message); @@ -426,6 +482,36 @@ TEST(OdkTest, PrepareCoreProvisioningRequestDeviceId) { sizeof(device_id_invalid))); } +TEST(OdkTest, PrepareCoreRenewedProvisioningRequestDeviceId) { + uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; + size_t core_message_length = sizeof(provisioning_message); + ODK_NonceValues nonce_values; + memset(&nonce_values, 0, sizeof(nonce_values)); + uint8_t device_id_invalid[ODK_DEVICE_ID_LEN_MAX + 1] = {0}; + uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0}; + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_PrepareCoreRenewedProvisioningRequest( + provisioning_message, sizeof(provisioning_message), + &core_message_length, &nonce_values, device_id_invalid, + sizeof(device_id_invalid), OEMCrypto_RenewalACert, renewal_data, + sizeof(renewal_data))); +} + +TEST(OdkTest, PrepareCoreRenewedProvisioningRequestRenewalDataInvalid) { + uint8_t provisioning_message[ODK_PROVISIONING_REQUEST_SIZE] = {0}; + size_t core_message_length = sizeof(provisioning_message); + ODK_NonceValues nonce_values; + memset(&nonce_values, 0, sizeof(nonce_values)); + uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; + uint8_t renewal_data_invalid[ODK_KEYBOX_RENEWAL_DATA_SIZE + 1] = {0}; + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, + ODK_PrepareCoreRenewedProvisioningRequest( + provisioning_message, sizeof(provisioning_message), + &core_message_length, &nonce_values, device_id, + sizeof(device_id), OEMCrypto_RenewalACert, renewal_data_invalid, + sizeof(renewal_data_invalid))); +} + // Serialize and de-serialize license request TEST(OdkTest, LicenseRequestRoundtrip) { std::vector empty; @@ -488,9 +574,42 @@ TEST(OdkTest, ProvisionRequestRoundtrip) { kdo_parse_func); } +TEST(OdkTest, RenewedProvisionRequestRoundtrip) { + uint32_t device_id_length = ODK_DEVICE_ID_LEN_MAX / 2; + uint8_t device_id[ODK_DEVICE_ID_LEN_MAX] = {0}; + memset(device_id, 0xff, device_id_length); + uint16_t renewal_type = OEMCrypto_RenewalACert; + uint32_t renewal_data_length = ODK_KEYBOX_RENEWAL_DATA_SIZE / 2; + uint8_t renewal_data[ODK_KEYBOX_RENEWAL_DATA_SIZE] = {0}; + memset(renewal_data, 0xff, renewal_data_length); + std::vector extra_fields = { + {ODK_UINT32, &device_id_length, "device_id_length"}, + {ODK_DEVICEID, device_id, "device_id"}, + {ODK_UINT16, &renewal_type, "renewal_type"}, + {ODK_UINT32, &renewal_data_length, "renewal_data_length"}, + {ODK_RENEWALDATA, renewal_data, "renewal_data"}, + }; + auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, + const ODK_NonceValues* nonce_values) { + return ODK_PrepareCoreRenewedProvisioningRequest( + buf, SIZE_MAX, size, nonce_values, device_id, device_id_length, + renewal_type, renewal_data, renewal_data_length); + }; + auto kdo_parse_func = + [&](const std::string& oemcrypto_core_message, + ODK_ProvisioningRequest* core_provisioning_request) { + bool ok = CoreRenewedProvisioningRequestFromMessage( + oemcrypto_core_message, core_provisioning_request); + return ok; + }; + ValidateRequest( + ODK_Renewed_Provisioning_Request_Type, extra_fields, odk_prepare_func, + kdo_parse_func); +} + TEST(OdkTest, ParseLicenseErrorNonce) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); uint8_t* buf = nullptr; uint32_t buf_size = 0; ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, @@ -499,7 +618,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); @@ -508,7 +627,7 @@ TEST(OdkTest, ParseLicenseErrorNonce) { TEST(OdkTest, ParseLicenseErrorUsageEntry) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); uint8_t* buf = nullptr; uint32_t buf_size = 0; ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, @@ -516,25 +635,59 @@ TEST(OdkTest, ParseLicenseErrorUsageEntry) { params.usage_entry_present = false; OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, params.request_hash, &(params.timer_limits), + params.usage_entry_present, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); delete[] buf; } -TEST(OdkTest, ParseLicenseErrorRequestHash) { +TEST(OdkTest, ParseLicenseNullSubstring) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.srm_restriction_data.offset = 0; + params.parsed_license.srm_restriction_data.length = 0; + uint8_t* buf = nullptr; + uint32_t buf_size = 0; + ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, + &buf_size); + OEMCryptoResult result = ODK_ParseLicense( + buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, + params.usage_entry_present, &(params.timer_limits), + &(params.clock_values), &(params.core_message.nonce_values), + &(params.parsed_license)); + EXPECT_EQ(OEMCrypto_SUCCESS, result); + delete[] buf; +} + +TEST(OdkTest, ParseLicenseErrorSubstringOffset) { + // offset out of range + ODK_LicenseResponseParams params; + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.enc_mac_keys_iv.offset = 1024; uint8_t* buf = nullptr; uint32_t buf_size = 0; ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, &buf_size); - // temporarily mess up with request hash - params.request_hash[0] = 0xff; OEMCryptoResult err = ODK_ParseLicense( buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, - params.usage_entry_present, params.request_hash, &(params.timer_limits), + params.usage_entry_present, &(params.timer_limits), + &(params.clock_values), &(params.core_message.nonce_values), + &(params.parsed_license)); + EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); + delete[] buf; + + // offset + length out of range + err = OEMCrypto_SUCCESS; + ODK_SetDefaultLicenseResponseParams(¶ms, ODK_MAJOR_VERSION); + params.parsed_license.enc_mac_keys_iv.length = buf_size; + buf = nullptr; + buf_size = 0; + ODK_BuildMessageBuffer(&(params.core_message), params.extra_fields, &buf, + &buf_size); + err = ODK_ParseLicense( + buf, buf_size + kExtraPayloadSize, buf_size, params.initial_license_load, + params.usage_entry_present, &(params.timer_limits), &(params.clock_values), &(params.core_message.nonce_values), &(params.parsed_license)); EXPECT_EQ(ODK_ERROR_CORE_MESSAGE, err); @@ -582,21 +735,28 @@ class OdkVersionTest : public ::testing::Test, 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_P(OdkVersionTest, LicenseResponseRoundtrip) { ODK_LicenseResponseParams params; - ODK_SetDefaultLicenseResponseParams(¶ms); + ODK_SetDefaultLicenseResponseParams(¶ms, + GetParam().response_major_version); SetRequestVersion(¶ms); - // save a copy of params.request_hash as it will be zero out during the test + // 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)); }; @@ -605,8 +765,8 @@ TEST_P(OdkVersionTest, 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(GetParam(), &(params.core_message), @@ -636,7 +796,7 @@ TEST_P(OdkVersionTest, 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(GetParam(), &(params.core_message), @@ -663,7 +823,7 @@ TEST_P(OdkVersionTest, ProvisionResponseRoundtrip) { std::string* oemcrypto_core_message) { core_request.device_id.assign(reinterpret_cast(device_id), device_id_length); - return CreateCoreProvisioningResponse(params.parsed_provisioning, + return CreateCoreProvisioningResponse(features_, params.parsed_provisioning, core_request, oemcrypto_core_message); }; ValidateResponse(GetParam(), &(params.core_message), @@ -687,26 +847,37 @@ const uint16_t kOldMajorMinor = ODK_MAJOR_VERSION > ODK_FIRST_VERSION ? 42 : 0; // List of major and minor versions to test. std::vector TestCases() { std::vector test_cases{ - // Fields: request major, request minor, response major, response minor - {ODK_MAJOR_VERSION, ODK_MINOR_VERSION, ODK_MAJOR_VERSION, + // 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, ODK_MINOR_VERSION + 1, ODK_MAJOR_VERSION, - ODK_MINOR_VERSION}, - {ODK_MAJOR_VERSION, kOldMinor, ODK_MAJOR_VERSION, kOldMinor}, - {ODK_MAJOR_VERSION, 0, ODK_MAJOR_VERSION, 0}, - {ODK_MAJOR_VERSION + 1, 42, ODK_MAJOR_VERSION, ODK_MINOR_VERSION}, - {kOldMajor, 0, kOldMajor, 0}, - {kOldMajor, kOldMajorMinor, kOldMajor, kOldMajorMinor}, + {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, 3, 16, 3}, - {16, 4, 16, 4}, - {16, 5, 16, 5}, + {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}, + {17, 17, 1, 17, 1}, }; return test_cases; } -INSTANTIATE_TEST_CASE_P(OdkVersionTests, OdkVersionTest, - ::testing::ValuesIn(TestCases())); +INSTANTIATE_TEST_SUITE_P(OdkVersionTests, OdkVersionTest, + ::testing::ValuesIn(TestCases())); TEST(OdkSizeTest, LicenseRequest) { uint8_t* message = nullptr; @@ -766,7 +937,7 @@ TEST(OdkSizeTest, ReleaseRequest) { &core_message_length, &nonce_values, &clock_values, system_time_seconds)); // Release requests do not have a core message. - EXPECT_GE(core_message_length, 0); + EXPECT_GE(core_message_length, 0u); } TEST(OdkSizeTest, ProvisioningRequest) { diff --git a/oemcrypto/odk/test/odk_test.gypi b/oemcrypto/odk/test/odk_test.gypi index ecd720a..0cb8a00 100644 --- a/oemcrypto/odk/test/odk_test.gypi +++ b/oemcrypto/odk/test/odk_test.gypi @@ -1,5 +1,5 @@ # Copyright 2019 Google LLC. All rights reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master License +# source code may only be used and distributed under the Widevine License # Agreement. { diff --git a/oemcrypto/odk/test/odk_test_helper.cpp b/oemcrypto/odk/test/odk_test_helper.cpp index a7002cc..dab9afa 100644 --- a/oemcrypto/odk/test/odk_test_helper.cpp +++ b/oemcrypto/odk/test/odk_test_helper.cpp @@ -1,20 +1,20 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #include "odk_test_helper.h" -#include - #include #include #include #include #include +#include #include #include "OEMCryptoCENCCommon.h" #include "gtest/gtest.h" +#include "odk_endian.h" #include "odk_structs.h" #include "odk_structs_priv.h" @@ -31,7 +31,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 +52,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 +111,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 +129,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 +276,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, @@ -177,6 +296,7 @@ void ODK_SetDefaultProvisioningResponseParams( memset(params->device_id + params->device_id_length, 0, ODK_DEVICE_ID_LEN_MAX - params->device_id_length); params->parsed_provisioning = { + .key_type = OEMCrypto_RSA_Private_Key, .enc_private_key = {.offset = 0, .length = 1}, .enc_private_key_iv = {.offset = 2, .length = 3}, .encrypted_message_key = {.offset = 4, .length = 5}, @@ -196,16 +316,22 @@ 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: return ODK_DEVICE_ID_LEN_MAX; + case ODK_RENEWALDATA: + return ODK_KEYBOX_RENEWAL_DATA_SIZE; case ODK_HASH: return ODK_SHA256_HASH_SIZE; default: @@ -225,30 +351,44 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) { return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { + case ODK_UINT8: { + memcpy(buf, field->value, sizeof(uint8_t)); + break; + } case ODK_UINT16: { - const uint16_t u16 = htobe16(*static_cast(field->value)); + const uint16_t u16 = + oemcrypto_htobe16(*static_cast(field->value)); memcpy(buf, &u16, sizeof(u16)); break; } case ODK_UINT32: { - const uint32_t u32 = htobe32(*static_cast(field->value)); + const uint32_t u32 = + oemcrypto_htobe32(*static_cast(field->value)); memcpy(buf, &u32, sizeof(u32)); break; } case ODK_UINT64: { - const uint64_t u64 = htobe64(*static_cast(field->value)); + const uint64_t u64 = + oemcrypto_htobe64(*static_cast(field->value)); memcpy(buf, &u64, sizeof(u64)); break; } + case ODK_BOOL: { + const bool value = *static_cast(field->value); + const uint32_t u32 = oemcrypto_htobe32(value ? 1 : 0); + memcpy(buf, &u32, sizeof(u32)); + break; + } case ODK_SUBSTRING: { OEMCrypto_Substring* s = static_cast(field->value); - const uint32_t off = htobe32(s->offset); - const uint32_t len = htobe32(s->length); + const uint32_t off = oemcrypto_htobe32(s->offset); + const uint32_t len = oemcrypto_htobe32(s->length); memcpy(buf, &off, sizeof(off)); memcpy(buf + sizeof(off), &len, sizeof(len)); break; } case ODK_DEVICEID: + case ODK_RENEWALDATA: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); const uint8_t* const id = static_cast(field->value); @@ -268,22 +408,33 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, return ODK_ERROR_CORE_MESSAGE; } switch (field->type) { + case ODK_UINT8: { + memcpy(field->value, buf, sizeof(uint8_t)); + break; + } case ODK_UINT16: { memcpy(field->value, buf, sizeof(uint16_t)); uint16_t* u16p = static_cast(field->value); - *u16p = be16toh(*u16p); + *u16p = oemcrypto_be16toh(*u16p); break; } case ODK_UINT32: { memcpy(field->value, buf, sizeof(uint32_t)); uint32_t* u32p = static_cast(field->value); - *u32p = be32toh(*u32p); + *u32p = oemcrypto_be32toh(*u32p); break; } case ODK_UINT64: { memcpy(field->value, buf, sizeof(uint64_t)); uint64_t* u64p = static_cast(field->value); - *u64p = be64toh(*u64p); + *u64p = oemcrypto_be64toh(*u64p); + break; + } + case ODK_BOOL: { + uint32_t value; + memcpy(&value, buf, sizeof(uint32_t)); + value = oemcrypto_be32toh(value); + *static_cast(field->value) = (value != 0); break; } case ODK_SUBSTRING: { @@ -292,11 +443,12 @@ 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: + case ODK_RENEWALDATA: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); uint8_t* const id = static_cast(field->value); @@ -315,18 +467,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; @@ -334,7 +494,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; @@ -348,6 +508,7 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, break; } case ODK_DEVICEID: + case ODK_RENEWALDATA: case ODK_HASH: { const size_t field_len = ODK_FieldLength(field->type); std::cerr << field->name << ": "; @@ -447,7 +608,8 @@ void ODK_ExpectEqualBuf(const void* s1, const void* s2, size_t n, std::fstream out(tmp, std::ios::out | std::ios::binary); out.write(static_cast(buffers[i]), n); out.close(); - std::cerr << "buffer " << i << " dumped to " << tmp << std::endl; + std::cerr << std::endl + << "Message buffer " << i << " dumped to " << tmp << std::endl; size_t bytes_written; uint8_t* buf = const_cast(reinterpret_cast(buffers[i])); diff --git a/oemcrypto/odk/test/odk_test_helper.h b/oemcrypto/odk/test/odk_test_helper.h index 7d739e4..f825af1 100644 --- a/oemcrypto/odk/test/odk_test_helper.h +++ b/oemcrypto/odk/test/odk_test_helper.h @@ -1,5 +1,5 @@ // Copyright 2019 Google LLC. All rights reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master +// source code may only be used and distributed under the Widevine // License Agreement. #ifndef WIDEVINE_ODK_TEST_ODK_TEST_HELPER_H_ @@ -15,13 +15,20 @@ namespace wvodk_test { enum ODK_FieldType { + ODK_UINT8, ODK_UINT16, ODK_UINT32, ODK_UINT64, ODK_SUBSTRING, ODK_DEVICEID, + ODK_RENEWALDATA, 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 +43,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; @@ -69,7 +78,8 @@ struct ODK_ProvisioningResponseParams { // Default values in core_message for testing void ODK_SetDefaultCoreFields(ODK_CoreMessage* core_message, ODK_MessageType message_type); -void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params); +void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params, + uint32_t odk_major_version); void ODK_SetDefaultRenewalResponseParams(ODK_RenewalResponseParams* params); void ODK_SetDefaultProvisioningResponseParams( ODK_ProvisioningResponseParams* params); diff --git a/oemcrypto/odk/test/odk_timer_test.cpp b/oemcrypto/odk/test/odk_timer_test.cpp index 15a6f78..8413960 100644 --- a/oemcrypto/odk/test/odk_timer_test.cpp +++ b/oemcrypto/odk/test/odk_timer_test.cpp @@ -1,5 +1,5 @@ /* Copyright 2019 Google LLC. All rights reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master + * source code may only be used and distributed under the Widevine * License Agreement. */ @@ -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,