From 858fa33cd771f20b9455cb0b6a0d631ef69f015a Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Mon, 13 Jan 2020 21:28:54 -0800 Subject: [PATCH] Updates for 16.1 unit tests and code This patch has the full v16.1 reference code and unit tests. --- oemcrypto/include/OEMCryptoCENC.h | 1 + oemcrypto/include/oemcrypto_types.h | 20 +- oemcrypto/odk/README | 9 + oemcrypto/odk/include/OEMCryptoCENCCommon.h | 35 +- .../odk/include/core_message_deserialize.h | 59 ++ .../odk/include/core_message_serialize.h | 64 ++ .../include/core_message_serialize_proto.h | 59 ++ oemcrypto/odk/include/core_message_types.h | 98 +++ oemcrypto/odk/include/odk.h | 89 +-- oemcrypto/odk/include/odk_structs.h | 25 +- oemcrypto/odk/kdo/include/oec_util.h | 172 ----- oemcrypto/odk/kdo/include/oec_util_proto.h | 59 -- oemcrypto/odk/kdo/oec_util.gypi | 16 - oemcrypto/odk/kdo/src/oec_util.cpp | 209 ------ .../odk/src/core_message_deserialize.cpp | 111 ++++ oemcrypto/odk/src/core_message_serialize.cpp | 114 ++++ .../core_message_serialize_proto.cpp} | 92 +-- oemcrypto/odk/src/kdo.gypi | 18 + oemcrypto/odk/src/odk.c | 114 ++-- oemcrypto/odk/src/odk.gyp | 2 +- oemcrypto/odk/src/odk.gypi | 4 +- oemcrypto/odk/src/odk_assert.h | 15 +- oemcrypto/odk/src/odk_endian.h | 29 + oemcrypto/odk/src/odk_overflow.c | 8 +- oemcrypto/odk/src/odk_overflow.h | 14 +- oemcrypto/odk/src/odk_serialize.c | 158 ++--- oemcrypto/odk/src/odk_serialize.h | 16 +- oemcrypto/odk/src/odk_structs_priv.h | 15 +- oemcrypto/odk/src/odk_timer.c | 18 +- oemcrypto/odk/src/serialization_base.c | 21 +- oemcrypto/odk/src/serialization_base.h | 19 +- oemcrypto/odk/test/odk_fuzz.cpp | 20 +- oemcrypto/odk/test/odk_fuzz.gyp | 2 +- oemcrypto/odk/test/odk_test.cpp | 299 ++++++--- oemcrypto/odk/test/odk_test.gypi | 2 +- oemcrypto/odk/test/odk_test.h | 64 -- oemcrypto/odk/test/odk_timer_test.cpp | 26 +- oemcrypto/oemcrypto_unittests.gyp | 3 +- oemcrypto/ref/src/oemcrypto_engine_ref.cpp | 2 +- oemcrypto/ref/src/oemcrypto_engine_ref.h | 1 + oemcrypto/ref/src/oemcrypto_ref.cpp | 113 +--- oemcrypto/ref/src/oemcrypto_session.cpp | 117 +++- oemcrypto/ref/src/oemcrypto_session.h | 12 +- oemcrypto/test/oec_decrypt_fallback_chain.cpp | 5 +- oemcrypto/test/oec_session_util.cpp | 621 +----------------- oemcrypto/test/oec_session_util.h | 194 +----- oemcrypto/test/oemcrypto_test.cpp | 578 ++++++++-------- oemcrypto/test/oemcrypto_unittests.gypi | 1 - 48 files changed, 1608 insertions(+), 2135 deletions(-) create mode 100644 oemcrypto/odk/README create mode 100644 oemcrypto/odk/include/core_message_deserialize.h create mode 100644 oemcrypto/odk/include/core_message_serialize.h create mode 100644 oemcrypto/odk/include/core_message_serialize_proto.h create mode 100644 oemcrypto/odk/include/core_message_types.h delete mode 100644 oemcrypto/odk/kdo/include/oec_util.h delete mode 100644 oemcrypto/odk/kdo/include/oec_util_proto.h delete mode 100644 oemcrypto/odk/kdo/oec_util.gypi delete mode 100644 oemcrypto/odk/kdo/src/oec_util.cpp create mode 100644 oemcrypto/odk/src/core_message_deserialize.cpp create mode 100644 oemcrypto/odk/src/core_message_serialize.cpp rename oemcrypto/odk/{kdo/src/oec_util_proto.cpp => src/core_message_serialize_proto.cpp} (56%) create mode 100644 oemcrypto/odk/src/kdo.gypi create mode 100644 oemcrypto/odk/src/odk_endian.h delete mode 100644 oemcrypto/odk/test/odk_test.h diff --git a/oemcrypto/include/OEMCryptoCENC.h b/oemcrypto/include/OEMCryptoCENC.h index ddee0a1..80584bb 100644 --- a/oemcrypto/include/OEMCryptoCENC.h +++ b/oemcrypto/include/OEMCryptoCENC.h @@ -499,6 +499,7 @@ typedef enum OEMCrypto_PrivateKeyType { #define OEMCrypto_GetOEMPublicCertificate _oecc104 #define OEMCrypto_DecryptCENC _oecc105 #define OEMCrypto_LoadDRMPrivateKey _oecc107 +#define OEMCrypto_MinorAPIVersion _oecc108 // clang-format on /* diff --git a/oemcrypto/include/oemcrypto_types.h b/oemcrypto/include/oemcrypto_types.h index 673e745..bf2158f 100644 --- a/oemcrypto/include/oemcrypto_types.h +++ b/oemcrypto/include/oemcrypto_types.h @@ -66,16 +66,16 @@ const uint32_t kControlCGMSCopyNever = (0x03); // clang-format on // Various constants and sizes: -static const size_t KEY_CONTROL_SIZE = 16; -static const size_t KEY_ID_SIZE = 16; -static const size_t KEY_IV_SIZE = 16; -static const size_t KEY_PAD_SIZE = 16; -static const size_t KEY_SIZE = 16; -static const size_t AES_128_BLOCK_SIZE = 16; -static const size_t MAC_KEY_SIZE = 32; -static const size_t KEYBOX_KEY_DATA_SIZE = 72; -static const size_t SRM_REQUIREMENT_SIZE = 12; -static const size_t HMAC_SHA256_SIGNATURE_SIZE = 32; +constexpr size_t KEY_CONTROL_SIZE = 16; +constexpr size_t KEY_ID_SIZE = 16; +constexpr size_t KEY_IV_SIZE = 16; +constexpr size_t KEY_PAD_SIZE = 16; +constexpr size_t KEY_SIZE = 16; +constexpr size_t AES_128_BLOCK_SIZE = 16; +constexpr size_t MAC_KEY_SIZE = 32; +constexpr size_t KEYBOX_KEY_DATA_SIZE = 72; +constexpr size_t SRM_REQUIREMENT_SIZE = 12; +constexpr size_t HMAC_SHA256_SIGNATURE_SIZE = 32; } // namespace wvoec diff --git a/oemcrypto/odk/README b/oemcrypto/odk/README new file mode 100644 index 0000000..b92f5d7 --- /dev/null +++ b/oemcrypto/odk/README @@ -0,0 +1,9 @@ +The ODK Library is used to generate and parse core OEMCrypto messages. + +This library is used by both OEMcrypto on a device, and by Widvine license and +provisioning servers. + +The source of truth for these files is in the server code base on piper. Do not +edit these files in the Android directory tree or in the Widevine Git +repository. If you need to edit these files and are not sure how to procede, +please ask for help from an engineer on the Widevine server or device teams. diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h index d9a29ce..0172309 100644 --- a/oemcrypto/odk/include/OEMCryptoCENCCommon.h +++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h @@ -1,6 +1,6 @@ -// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine Master -// License Agreement. +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ /********************************************************************* * OEMCryptoCENCCommon.h @@ -9,8 +9,8 @@ * *********************************************************************/ -#ifndef OEMCRYPTO_CENC_COMMON_H_ -#define OEMCRYPTO_CENC_COMMON_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_ #include #include @@ -20,19 +20,17 @@ extern "C" { #endif -typedef uint32_t OEMCrypto_SESSION; - -// clang-format off +/* clang-format off */ typedef enum OEMCryptoResult { OEMCrypto_SUCCESS = 0, OEMCrypto_ERROR_INIT_FAILED = 1, OEMCrypto_ERROR_TERMINATE_FAILED = 2, OEMCrypto_ERROR_OPEN_FAILURE = 3, OEMCrypto_ERROR_CLOSE_FAILURE = 4, - OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED = 5, // deprecated - OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED = 6, // deprecated + OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED = 5, /* deprecated */ + OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED = 6, /* deprecated */ OEMCrypto_ERROR_SHORT_BUFFER = 7, - OEMCrypto_ERROR_NO_DEVICE_KEY = 8, // no keybox device key. + OEMCrypto_ERROR_NO_DEVICE_KEY = 8, /* no keybox device key. */ OEMCrypto_ERROR_NO_ASSET_KEY = 9, OEMCrypto_ERROR_KEYBOX_INVALID = 10, OEMCrypto_ERROR_NO_KEYDATA = 11, @@ -64,9 +62,9 @@ typedef enum OEMCryptoResult { OEMCrypto_ERROR_INSUFFICIENT_RESOURCES = 37, OEMCrypto_ERROR_INSUFFICIENT_HDCP = 38, OEMCrypto_ERROR_BUFFER_TOO_LARGE = 39, - OEMCrypto_WARNING_GENERATION_SKEW = 40, // Warning, not an error. + OEMCrypto_WARNING_GENERATION_SKEW = 40, /* Warning, not error. */ OEMCrypto_ERROR_GENERATION_SKEW = 41, - OEMCrypto_LOCAL_DISPLAY_ONLY = 42, // Info, not an error. + OEMCrypto_LOCAL_DISPLAY_ONLY = 42, /* Info, not an error. */ OEMCrypto_ERROR_ANALOG_OUTPUT = 43, OEMCrypto_ERROR_WRONG_PST = 44, OEMCrypto_ERROR_WRONG_KEYS = 45, @@ -74,8 +72,9 @@ typedef enum OEMCryptoResult { OEMCrypto_ERROR_LICENSE_INACTIVE = 47, OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE = 48, OEMCrypto_ERROR_ENTRY_IN_USE = 49, - OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE = 50, // Reserved. Do not use. - OEMCrypto_KEY_NOT_LOADED = 51, // obsolete. use error 26. + OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE = 50, /* Obsolete. Don't use. */ + /* Use OEMCrypto_ERROR_NO_CONTENT_KEY instead of KEY_NOT_LOADED. */ + OEMCrypto_KEY_NOT_LOADED = 51, /* Obsolete. */ OEMCrypto_KEY_NOT_ENTITLED = 52, OEMCrypto_ERROR_BAD_HASH = 53, OEMCrypto_ERROR_OUTPUT_TOO_LARGE = 54, @@ -93,7 +92,7 @@ typedef enum OEMCryptoResult { ODK_UNSUPPORTED_API = ODK_ERROR_BASE + 4, ODK_STALE_RENEWAL = ODK_ERROR_BASE + 5, } OEMCryptoResult; -// clang-format on +/* clang-format on */ /* * OEMCrypto_Usage_Entry_Status. @@ -102,7 +101,7 @@ typedef enum OEMCryptoResult { typedef enum OEMCrypto_Usage_Entry_Status { kUnused = 0, kActive = 1, - kInactive = 2, // Deprecated. Used kInactiveUsed or kInactiveUnused. + kInactive = 2, /* Deprecated. Use kInactiveUsed or kInactiveUnused. */ kInactiveUsed = 3, kInactiveUnused = 4, } OEMCrypto_Usage_Entry_Status; @@ -153,4 +152,4 @@ typedef struct { } #endif -#endif // OEMCRYPTO_CENC_COMMON_H_ +#endif /* ...ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_ */ diff --git a/oemcrypto/odk/include/core_message_deserialize.h b/oemcrypto/odk/include/core_message_deserialize.h new file mode 100644 index 0000000..a248652 --- /dev/null +++ b/oemcrypto/odk/include/core_message_deserialize.h @@ -0,0 +1,59 @@ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ + +/********************************************************************* + * core_message_deserialize.h + * + * OEMCrypto v16 Core Message Serialization library counterpart (a.k.a. KDO) + * + * This file declares functions to deserialize request messages prepared by + * Widevine clients (OEMCrypto/ODK). + * + * Please refer to core_message_types.h for details. + * + *********************************************************************/ + +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ + +#include "core_message_types.h" + +namespace oemcrypto_core_message { +namespace deserialize { + +/** + * Counterpart (deserializer) of ODK_PrepareCoreLicenseRequest (serializer) + * + * Parameters: + * [in] oemcrypto_core_message + * [out] core_license_request + */ +bool CoreLicenseRequestFromMessage(const string& oemcrypto_core_message, + ODK_LicenseRequest* core_license_request); + +/** + * Counterpart (deserializer) of ODK_PrepareCoreRenewalRequest (serializer) + * + * Parameters: + * [in] oemcrypto_core_message + * [out] core_renewal_request + */ +bool CoreRenewalRequestFromMessage(const string& oemcrypto_core_message, + ODK_RenewalRequest* core_renewal_request); + +/** + * Counterpart (deserializer) of ODK_PrepareCoreProvisioningRequest (serializer) + * + * Parameters: + * [in] oemcrypto_core_message + * [out] core_provisioning_request + */ +bool CoreProvisioningRequestFromMessage( + const string& oemcrypto_core_message, + ODK_ProvisioningRequest* core_provisioning_request); + +} /* namespace deserialize */ +} /* namespace oemcrypto_core_message */ + +#endif /* ...ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ */ diff --git a/oemcrypto/odk/include/core_message_serialize.h b/oemcrypto/odk/include/core_message_serialize.h new file mode 100644 index 0000000..0e4ee9d --- /dev/null +++ b/oemcrypto/odk/include/core_message_serialize.h @@ -0,0 +1,64 @@ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ + +/********************************************************************* + * core_message_serialize.h + * + * OEMCrypto v16 Core Message Serialization library counterpart (a.k.a. KDO) + * + * This file declares functions to serialize response messages that will be + * parsed by Widevine clients (OEMCrypto/ODK). + * + * Please refer to core_message_types.h for details. + * + *********************************************************************/ + +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ + +#include "core_message_types.h" +#include "odk_structs.h" + +namespace oemcrypto_core_message { +namespace serialize { + +/** + * Counterpart (serializer) of ODK_ParseLicense (deserializer) + * struct-input variant + * + * Parameters: + * [in] parsed_lic + * [in] core_request + * [out] oemcrypto_core_message + */ +bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, + const ODK_LicenseRequest& core_request, + string* oemcrypto_core_message); + +/** + * Counterpart (serializer) of ODK_ParseRenewal (deserializer) + * + * Parameters: + * [in] core_request + * [out] oemcrypto_core_message + */ +bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, + string* oemcrypto_core_message); + +/** + * Counterpart (serializer) of ODK_ParseProvisioning (deserializer) + * struct-input variant + * + * Parameters: + * [in] parsed_prov + * [in] core_request + * [out] oemcrypto_core_message + */ +bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, + const ODK_ProvisioningRequest& core_request, + string* oemcrypto_core_message); +} /* namespace serialize */ +} /* namespace oemcrypto_core_message */ + +#endif /* ...ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ */ diff --git a/oemcrypto/odk/include/core_message_serialize_proto.h b/oemcrypto/odk/include/core_message_serialize_proto.h new file mode 100644 index 0000000..594569d --- /dev/null +++ b/oemcrypto/odk/include/core_message_serialize_proto.h @@ -0,0 +1,59 @@ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ + +/********************************************************************* + * core_message_serialize_proto.h + * + * These functions are an extension of those found in + * core_message_serialize.h. The difference is that these use the + * license and provisioning messages in protobuf format to create the core + * message. + *********************************************************************/ + +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_ + +#include +#include + +#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] serialized_license + * serialized video_widevine::License + * [in] core_request + * [out] oemcrypto_core_message + */ +bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, + const ODK_LicenseRequest& core_request, + const std::string& core_request_sha256, + std::string* oemcrypto_core_message); + +/** + * Counterpart (serializer) of ODK_ParseProvisioning (deserializer) + * + * Parameters: + * [in] serialized_provisioning_response + * serialized video_widevine::ProvisioningResponse + * [in] core_request + * [out] oemcrypto_core_message + */ +bool CreateCoreProvisioningResponseFromProto( + const std::string& serialized_provisioning_response, + const ODK_ProvisioningRequest& core_request, + std::string* oemcrypto_core_message); + +} /* namespace serialize */ +} /* namespace oemcrypto_core_message */ + +#endif /* ...ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_ */ diff --git a/oemcrypto/odk/include/core_message_types.h b/oemcrypto/odk/include/core_message_types.h new file mode 100644 index 0000000..fd4a1d3 --- /dev/null +++ b/oemcrypto/odk/include/core_message_types.h @@ -0,0 +1,98 @@ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ + +/* clang-format off */ +/********************************************************************* + * core_message_types.h + * + * OEMCrypto v16 Core Message Serialization library counterpart (a.k.a. KDO) + * + * For Widevine Modular DRM, there are six message types between a server and + * a client device: license request and response, provisioning request and + * response, and renewal request and response. + * + * In OEMCrypto v15 and earlier, messages from the server were parsed by the + * CDM layer above OEMCrypto; the CDM in turn gave OEMCrypto a collection of + * pointers to protected data within the message. However, the pointers + * themselves were not signed by the server. + * + * Starting from OEMCrypto v16, all fields used by OEMCrypto in each of these + * messages have been identified in the document "Widevine Core Message + * Serialization". These fields are called the core of the message. Core + * message fields are (de)serialized using the ODK, a C library provided by + * Widevine. OEMCrypto will parse and verify the core of the message with + * help from the ODK. + * + * The KDO library is the counterpart of ODK used in the CDM & Widevine + * servers. For each message type generated by the ODK, KDO provides a + * corresponding parser. For each message type to be parsed by the ODK, + * KDO provides a corresponding writer. + * + * Table: ODK vs KDO (s: serialize; d: deserialize) + * +----------------------------------------+---------------------------------------+ + * | ODK | KDO | + * +---+------------------------------------+---+-----------------------------------+ + * | s | ODK_PrepareCoreLicenseRequest | d | CoreLicenseRequestFromMessage | + * | +------------------------------------+ +-----------------------------------+ + * | | ODK_PrepareCoreRenewalRequest | | CoreRenewalRequestFromMessage | + * | +------------------------------------+ +-----------------------------------+ + * | | ODK_PrepareCoreProvisioningRequest | | CoreProvisioningRequestFromMessage| + * +---+------------------------------------+---+-----------------------------------+ + * | d | ODK_ParseLicense | s | CreateCoreLicenseResponse | + * | +------------------------------------+ +-----------------------------------+ + * | | ODK_ParseRenewal | | CreateCoreRenewalResponse | + * | +------------------------------------+ +-----------------------------------+ + * | | ODK_ParseProvisioning | | CreateCoreProvisioningResponse | + * +---+------------------------------------+---+-----------------------------------+ + * + *********************************************************************/ +/* clang-format on */ + +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_ + +#include +#include + +namespace oemcrypto_core_message { + +using std::string; + +/* @ input/output structs */ + +/** + * Output structure for CoreLicenseRequestFromMessage + * Input structure for CreateCoreLicenseResponse + */ +struct ODK_LicenseRequest { + uint32_t api_version; + uint32_t nonce; + uint32_t session_id; +}; + +/** + * Output structure for CoreRenewalRequestFromMessage + * Input structure for CreateCoreRenewalResponse + */ +struct ODK_RenewalRequest { + uint32_t api_version; + uint32_t nonce; + uint32_t session_id; + uint64_t playback_time_seconds; +}; + +/** + * Output structure for CoreProvisioningRequestFromMessage + * Input structure for CreateCoreProvisioningResponse + */ +struct ODK_ProvisioningRequest { + uint32_t api_version; + uint32_t nonce; + uint32_t session_id; + string device_id; +}; + +} /* namespace oemcrypto_core_message */ + +#endif /* ...ODK_INCLUDE_CORE_MESSAGE_TYPES_H_ */ diff --git a/oemcrypto/odk/include/odk.h b/oemcrypto/odk/include/odk.h index 391fef6..c2a2961 100644 --- a/oemcrypto/odk/include/odk.h +++ b/oemcrypto/odk/include/odk.h @@ -1,8 +1,6 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ /********************************************************************* * odk.h @@ -44,10 +42,11 @@ * *********************************************************************/ -#ifndef ODK_H_ -#define ODK_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_ODK_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_ODK_H_ #include + #include "OEMCryptoCENCCommon.h" #include "odk_structs.h" @@ -305,7 +304,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest( * the message. (in) size of buffer reserved for the core message, in * bytes. (out) actual length of the core message, in bytes. * [in] nonce_values: pointer to the session's nonce data. - * [in] clock_values: the session's clock values. + * [in/out] clock_values: the session's clock values. * [in] system_time_seconds: the current time on OEMCrypto's clock, in * seconds. * @@ -327,8 +326,8 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest( * * Description: * Modifies the message to include a core provisioning request at the - * beginning of the message buffer. The values in nonce_values are used to - * populate the message. + * beginning of the message buffer. The values in nonce_values, clock_values + * and system_time_seconds are used to populate the message. * * This shall be called by OEMCrypto from * OEMCrypto_PrepAndSignProvisioningRequest. @@ -439,35 +438,21 @@ OEMCryptoResult ODK_RefreshV15Values(const ODK_TimerLimits* timer_limits, * ODK_ParseLicense * * Description: - * The function ODK_ParseLicense will parse the message and verify fields in - * the message. + * The function ODK_ParseLicense will parse the message and verify + * + * 1. Either the nonce matches the one passed in or the license does not + * require a nonce. + * 2. The API version of the message matches. + * 3. The session id matches. + * The function ODK_ParseLicense will parse the message and set each + * substring pointer to point to a location in the message body. The message + * body is the buffer starting at message + core_message_length with size + * message_length - core_message_length. * * If the message does not parse correctly, ODK_VerifyAndParseLicense will * return ODK_ERROR_CORE_MESSAGE that OEMCrypto should return to the CDM - * layer above. - * - * If the api in the message is not 16, then ODK_UNSUPPORTED_API is returned. - * - * If initial_license_load is true, and nonce_required in the license is - * true, then the ODK library shall verify that nonce_values->nonce and - * nonce_values->session_id are the same as those in the message. If - * verification fails, then it shall return OEMCrypto_ERROR_INVALID_NONCE. - * - * If initial_license_load is false, and nonce_required is true, then - * ODK_ParseLicense will set the values in nonce_values from those in the - * message. - * - * The function ODK_ParseLicense will verify each substring points to a - * location in the message body. The message body is the buffer starting at - * message + core_message_length with size message_length - - * core_message_length. - * - * If initial_license_load is true, then ODK_ParseLicense shall verify that - * hash matches request_hash in the parsed license. If verification fails, - * then it shall return ODK_ERROR_CORE_MESSAGE. - * - * If usage_entry_present is true, then ODK_ParseLicense shall verify that - * the pst in the license has a nonzero length. + * layer above. If the api in the message is larger than 16, then + * ODK_UNSUPPORTED_API is returned. * * Parameters: * [in] message: pointer to the message buffer. @@ -505,12 +490,9 @@ OEMCryptoResult ODK_ParseLicense( * ODK_ParseRenewal * * Description: - * The function ODK_ParseRenewal will parse the message and verify. If the - * message does not parse correctly, an error of ODK_ERROR_CORE_MESSAGE is - * returned. - * - * ODK_ParseRenewal shall verify that all fields in nonce_values match those - * in the license. Otherwise it shall return OEMCrypto_ERROR_INVALID_NONCE. + * The function ODK_ParseRenewal will parse the message and verify that the + * nonce values match those in the license. If the message does not parse + * correctly, an error of ODK_ERROR_CORE_MESSAGE is returned. * * After parsing the message, this function updates the clock_values based on * the timer_limits and the current system time. If playback may not @@ -547,10 +529,8 @@ OEMCryptoResult ODK_ParseLicense( * value. * ODK_DISABLE_TIMER: Success, but disable timer. Unlimited playback is * allowed. - * ODK_TIMER_EXPIRED: Set timer as diabled. Playback is not allowed. + * ODK_TIMER_EXPIRED: Set timer as disabled. Playback is not allowed. * ODK_UNSUPPORTED_API - * ODK_STALE_RENEWAL: This renewal is not the most recently signed. It is - * rejected. * OEMCrypto_ERROR_INVALID_NONCE * * Version: @@ -571,21 +551,14 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, * The function ODK_ParseProvisioning will parse the message and verify the * nonce values match those in the license. * + * The function ODK_ParseProvisioning will parse the message and set each + * substring pointer to point to a location in the message body. The message + * body is the buffer starting at message + core_message_length with size + * message_length - core_message_length. + * * If the message does not parse correctly, ODK_ParseProvisioning will return * an error that OEMCrypto should return to the CDM layer above. * - * If the api in the message is larger than 16, then ODK_UNSUPPORTED_API is - * returned. - * - * ODK_ParseProvisioning shall verify that nonce_values->nonce and - * nonce_values->session_id are the same as those in the message. Otherwise - * it shall return OEMCrypto_ERROR_INVALID_NONCE. - * - * The function ODK_ParseProvisioning will verify each substring points to a - * location in the message body. The message body is the buffer starting at - * message + core_message_length with size message_length - - * core_message_length. - * * Parameters: * [in] message: pointer to the message buffer. * [in] message_length: length of the entire message buffer. @@ -617,4 +590,4 @@ OEMCryptoResult ODK_ParseProvisioning( } #endif -#endif // ODK_H_ +#endif /* ...ODK_INCLUDE_ODK_H_ */ diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index 8085a47..fb07f6f 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -1,13 +1,12 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ -#ifndef ODK_STRUCTS_H_ -#define ODK_STRUCTS_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_ODK_STRUCTS_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_ODK_STRUCTS_H_ #include + #include "OEMCryptoCENCCommon.h" #define ODK_MAX_NUM_KEYS 32 @@ -24,11 +23,11 @@ */ typedef struct { uint32_t /*boolean*/ soft_expiry; - uint64_t earliest_playback_start_seconds; // seconds since license signed. - uint64_t latest_playback_start_seconds; // seconds since license signed. - uint64_t initial_playback_duration_seconds; // seconds since playback start. - uint64_t renewal_playback_duration_seconds; // seconds since renewal signed. - uint64_t license_duration_seconds; // seconds since license signed. + uint64_t earliest_playback_start_seconds; /* since license signed. */ + uint64_t latest_playback_start_seconds; /* since license signed. */ + uint64_t initial_playback_duration_seconds; /* since playback start. */ + uint64_t renewal_playback_duration_seconds; /* since renewal signed. */ + uint64_t license_duration_seconds; /* since license signed. */ } ODK_TimerLimits; /* @@ -94,4 +93,4 @@ typedef struct { uint32_t session_id; } ODK_NonceValues; -#endif // ODK_STRUCTS_H_ +#endif /* ...ODK_INCLUDE_ODK_STRUCTS_H_ */ diff --git a/oemcrypto/odk/kdo/include/oec_util.h b/oemcrypto/odk/kdo/include/oec_util.h deleted file mode 100644 index 20bee97..0000000 --- a/oemcrypto/odk/kdo/include/oec_util.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ - -// clang-format off -/********************************************************************* - * oec_util.h - * - * OEMCrypto v16 Core Message Serialization library counterpart (a.k.a. KDO) - * - * For Widevine Modular DRM, there are six message types between a server and - * a client device: license request and response, provisioning request and - * response, and renewal request and response. - * - * In OEMCrypto v15 and earlier, messages from the server were parsed by the - * CDM layer above OEMCrypto; the CDM in turn gave OEMCrypto a collection of - * pointers to protected data within the message. However, the pointers - * themselves were not signed by the server. - * - * Starting from OEMCrypto v16, all fields used by OEMCrypto in each of these - * messages have been identified in the document "Widevine Core Message - * Serialization". These fields are called the core of the message. Core - * message fields are (de)serialized using the ODK, a C library provided by - * Widevine. OEMCrypto will parse and verify the core of the message with - * help from the ODK. - * - * The KDO library is the counterpart of ODK used in the CDM & Widevine - * servers. For each message type generated by the ODK, KDO provides a - * corresponding parser. For each message type to be parsed by the ODK, - * KDO provides a corresponding writer. - * - * Table: ODK vs KDO (s: serialize; d: deserialize) - * +----------------------------------------+------------------------------------+ - * | ODK | KDO | - * +---+------------------------------------+---+--------------------------------+ - * | s | ODK_PrepareCoreLicenseRequest | d | ParseLicenseRequest | - * | +------------------------------------+ +--------------------------------+ - * | | ODK_PrepareCoreRenewalRequest | | ParseRenewalRequest | - * | +------------------------------------+ +--------------------------------+ - * | | ODK_PrepareCoreProvisioningRequest | | ParseProvisioningRequest | - * +---+------------------------------------+---+--------------------------------+ - * | d | ODK_ParseLicense | s | CreateCoreLicenseResponse | - * | +------------------------------------+ +--------------------------------+ - * | | ODK_ParseRenewal | | CreateCoreRenewalResponse | - * | +------------------------------------+ +--------------------------------+ - * | | ODK_ParseProvisioning | | CreateCoreProvisioningResponse | - * +---+------------------------------------+---+--------------------------------+ - * - *********************************************************************/ -// clang-format on - -#ifndef OEC_UTIL_H_ -#define OEC_UTIL_H_ - -#include -#include - -#include "odk_structs.h" - -using namespace std; - -namespace oec_util { - -// @ input/output structs - -/** - * Output structure for ParseLicenseRequest - * Input structure for CreateCoreLicenseResponse - */ -struct ODK_LicenseRequest { - uint32_t api_version; - uint32_t nonce; - uint32_t session_id; -}; - -/** - * Output structure for ParseRenewalRequest - * Input structure for CreateCoreRenewalResponse - */ -struct ODK_RenewalRequest { - uint32_t api_version; - uint32_t nonce; - uint32_t session_id; - uint64_t playback_time; -}; - -/** - * Output structure for ParseProvisioningRequest - * Input structure for CreateCoreProvisioningResponse - */ -struct ODK_ProvisioningRequest { - uint32_t api_version; - uint32_t nonce; - uint32_t session_id; - string device_id; -}; - -// @ public parse request (deserializer) functions - -/** - * Counterpart (deserializer) of ODK_PrepareCoreLicenseRequest (serializer) - * - * Parameters: - * [in] oemcrypto_core_message - * [out] core_license_request - */ -bool ParseLicenseRequest(const string& oemcrypto_core_message, - ODK_LicenseRequest* core_license_request); - -/** - * Counterpart (deserializer) of ODK_PrepareCoreRenewalRequest (serializer) - * - * Parameters: - * [in] oemcrypto_core_message - * [out] core_renewal_request - */ -bool ParseRenewalRequest(const string& oemcrypto_core_message, - ODK_RenewalRequest* core_renewal_request); - -/** - * Counterpart (deserializer) of ODK_PrepareCoreProvisioningRequest (serializer) - * - * Parameters: - * [in] oemcrypto_core_message - * [out] core_provisioning_request - */ -bool ParseProvisioningRequest( - const string& oemcrypto_core_message, - ODK_ProvisioningRequest* core_provisioning_request); - -// @ public create response (serializer) functions - -/** - * Counterpart (serializer) of ODK_ParseLicense (deserializer) - * struct-input variant - * - * Parameters: - * [in] parsed_lic - * [in] core_request - * [out] oemcrypto_core_message - */ -bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, - const ODK_LicenseRequest& core_request, - string* oemcrypto_core_message); - -/** - * Counterpart (serializer) of ODK_ParseRenewal (deserializer) - * - * Parameters: - * [in] core_request - * [out] oemcrypto_core_message - */ -bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, - string* oemcrypto_core_message); - -/** - * Counterpart (serializer) of ODK_ParseProvisioning (deserializer) - * struct-input variant - * - * Parameters: - * [in] parsed_prov - * [in] core_request - * [out] oemcrypto_core_message - */ -bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, - const ODK_ProvisioningRequest& core_request, - string* oemcrypto_core_message); -} // namespace oec_util - -#endif // OEC_UTIL_H_ diff --git a/oemcrypto/odk/kdo/include/oec_util_proto.h b/oemcrypto/odk/kdo/include/oec_util_proto.h deleted file mode 100644 index f9d8017..0000000 --- a/oemcrypto/odk/kdo/include/oec_util_proto.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ - -/********************************************************************* - * oec_util_proto.h - * - * These functions are an extension of those found in oec_util.h. The - * difference is that these use the license and provisioning messages - * in protobuf format to create the core message. - *********************************************************************/ - -#ifndef OEC_UTIL_PROTO_H_ -#define OEC_UTIL_PROTO_H_ - -#include -#include - -#include "license_protocol.pb.h" -#include "oec_util.h" - -using namespace std; -using video_widevine::License; -using video_widevine::License_KeyContainer; - -namespace oec_util { - -// @ public create response (serializer) functions - -/** - * Counterpart (serializer) of ODK_ParseLicense (deserializer) - * - * Parameters: - * [in] license - * [in] core_request - * [out] oemcrypto_core_message - */ -bool CreateCoreLicenseResponse(const video_widevine::License& license, - const ODK_LicenseRequest& core_request, - string* oemcrypto_core_message); - -/** - * Counterpart (serializer) of ODK_ParseProvisioning (deserializer) - * - * Parameters: - * [in] provisioning_response - * [in] core_request - * [out] oemcrypto_core_message - */ -bool CreateCoreProvisioningResponse( - const video_widevine::ProvisioningResponse& provisioning_response, - const ODK_ProvisioningRequest& core_request, - string* oemcrypto_core_message); - -} // namespace oec_util - -#endif // OEC_UTIL_PROTO_H_ diff --git a/oemcrypto/odk/kdo/oec_util.gypi b/oemcrypto/odk/kdo/oec_util.gypi deleted file mode 100644 index 19805f1..0000000 --- a/oemcrypto/odk/kdo/oec_util.gypi +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary -# source code may only be used and distributed under the Widevine Master License -# Agreement. - -{ - 'sources': [ - 'src/oec_util.cpp', - 'src/oec_util_proto.cpp', - ], - 'include_dirs': [ - '../src', - '../include', - 'include', - ], -} - diff --git a/oemcrypto/odk/kdo/src/oec_util.cpp b/oemcrypto/odk/kdo/src/oec_util.cpp deleted file mode 100644 index affd979..0000000 --- a/oemcrypto/odk/kdo/src/oec_util.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ - -#include "oec_util.h" - -#include -#include -#include -#include -#include -#include - -#include "odk_overflow.h" -#include "odk_serialize.h" -#include "odk_structs.h" -#include "odk_structs_priv.h" -#include "oemcrypto_types.h" -#include "serialization_base.h" - -using namespace oec_util; - -namespace oec_util { - -namespace { - -/* @ private functions */ - -const int CURRENT_OEC_VERSION = 16; - -/** - * Template for parsing requests - * - * Template arguments: - * S: kdo output struct - * T: struct serialized by odk - * U: auto-generated deserializing function for |T| - */ -template -bool ParseRequest(uint32_t message_type, const string& oemcrypto_core_message, - S* core_request, T* prepared, const U unpacker) { - if (!core_request) { - return false; - } - - const uint8_t* buf = - reinterpret_cast(oemcrypto_core_message.c_str()); - size_t buf_length = oemcrypto_core_message.size(); - - Message* msg = NULL; - AllocateMessage(&msg, message_block); - InitMessage(msg, const_cast(buf), buf_length); - SetSize(msg, buf_length); - - unpacker(msg, prepared); - if (!ValidMessage(msg)) { - return false; - } - - const auto& core_message = prepared->core_message; - core_request->api_version = core_message.nonce_values.api_version; - core_request->nonce = core_message.nonce_values.nonce; - core_request->session_id = core_message.nonce_values.session_id; - return core_message.message_type == message_type && - core_message.message_length == GetOffset(msg) && - core_request->api_version == CURRENT_OEC_VERSION; -} - -/** - * Template for parsing requests - * - * Template arguments: - * T: struct to be deserialized by odk - * S: kdo input struct - * P: auto-generated serializing function for |T| - */ -template -bool CreateResponse(uint32_t message_type, const S& core_request, - string* oemcrypto_core_message, T& response, - const P& packer) { - if (!oemcrypto_core_message) { - return false; - } - - auto* header = reinterpret_cast(&response); - header->message_type = message_type; - header->nonce_values.api_version = core_request.api_version; - header->nonce_values.nonce = core_request.nonce; - header->nonce_values.session_id = core_request.session_id; - - uint8_t buf[2048] = {0}; - Message* msg = NULL; - AllocateMessage(&msg, message_block); - InitMessage(msg, buf, sizeof(buf)); - packer(msg, &response); - if (!ValidMessage(msg)) { - return false; - } - - uint32_t message_length = GetSize(msg); - InitMessage(msg, buf + sizeof(header->message_type), - sizeof(header->message_length)); - Pack_uint32_t(msg, &message_length); - oemcrypto_core_message->assign(reinterpret_cast(buf), - message_length); - return true; -} - -bool CopyDeviceId(ODK_ProvisioningResponse& dest, - const ODK_ProvisioningRequest& src) { - auto& core_provisioning = dest.core_provisioning; - const string& device_id = src.device_id; - core_provisioning.device_id_length = device_id.size(); - if (core_provisioning.device_id_length > - sizeof(core_provisioning.device_id)) { - return false; - } - memset(core_provisioning.device_id, 0, sizeof(core_provisioning.device_id)); - memcpy(core_provisioning.device_id, device_id.data(), - core_provisioning.device_id_length); - return true; -} - -} // namespace - -// @ public parse request (deserializer) functions - -bool ParseLicenseRequest(const string& oemcrypto_core_message, - ODK_LicenseRequest* core_license_request) { - const auto unpacker = Unpack_ODK_PreparedLicense; - ODK_PreparedLicense prepared_license = {}; - return ParseRequest(ODK_License_Request_Type, oemcrypto_core_message, - core_license_request, &prepared_license, unpacker); -} - -bool ParseRenewalRequest(const string& oemcrypto_core_message, - ODK_RenewalRequest* core_renewal_request) { - const auto unpacker = Unpack_ODK_RenewalMessage; - ODK_RenewalMessage prepared_renewal = {}; - if (!ParseRequest(ODK_Renewal_Request_Type, oemcrypto_core_message, - core_renewal_request, &prepared_renewal, unpacker)) { - return false; - } - core_renewal_request->playback_time = prepared_renewal.playback_time; - return true; -} - -bool ParseProvisioningRequest( - const string& oemcrypto_core_message, - ODK_ProvisioningRequest* core_provisioning_request) { - const auto unpacker = Unpack_ODK_ProvisioningMessage; - ODK_ProvisioningMessage prepared_provision = {}; - if (!ParseRequest(ODK_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); - return true; -} - -// @ public create response functions - -bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, - const ODK_LicenseRequest& core_request, - string* oemcrypto_core_message) { - ODK_LicenseResponse license_response{ - {}, const_cast(&parsed_lic)}; - return CreateResponse(ODK_License_Response_Type, core_request, - oemcrypto_core_message, license_response, - Pack_ODK_LicenseResponse); -} - -bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, - string* oemcrypto_core_message) { - ODK_RenewalMessage renewal{{}, core_request.playback_time}; - renewal.playback_time = core_request.playback_time; - return CreateResponse(ODK_Renewal_Response_Type, core_request, - oemcrypto_core_message, renewal, - Pack_ODK_RenewalMessage); -} - -bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, - const ODK_ProvisioningRequest& core_request, - string* oemcrypto_core_message) { - ODK_ProvisioningResponse prov_response{ - {}, const_cast(&parsed_prov)}; - if (!CopyDeviceId(prov_response, core_request)) { - return false; - } - - return CreateResponse(ODK_Provisioning_Response_Type, core_request, - oemcrypto_core_message, prov_response, - Pack_ODK_ProvisioningResponse); -} - -} // namespace oec_util diff --git a/oemcrypto/odk/src/core_message_deserialize.cpp b/oemcrypto/odk/src/core_message_deserialize.cpp new file mode 100644 index 0000000..8a2952d --- /dev/null +++ b/oemcrypto/odk/src/core_message_deserialize.cpp @@ -0,0 +1,111 @@ +// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "core_message_deserialize.h" + +#include +#include +#include +#include +#include + +#include "odk_serialize.h" +#include "odk_structs.h" +#include "odk_structs_priv.h" +#include "serialization_base.h" + +namespace oemcrypto_core_message { +namespace deserialize { +namespace { + +const int EARLIEST_OEMCRYPTO_VERSION_WITH_ODK = 16; +const int LATEST_OEMCRYPTO_VERSION = 16; + +/** + * Template for parsing requests + * + * Template arguments: + * S: kdo output struct + * T: struct serialized by odk + * U: auto-generated deserializing function for |T| + */ +template +bool ParseRequest(uint32_t message_type, const string& oemcrypto_core_message, + S* core_request, T* prepared, const U unpacker) { + if (core_request == nullptr || prepared == nullptr) { + return false; + } + + const uint8_t* buf = + reinterpret_cast(oemcrypto_core_message.c_str()); + const size_t buf_length = oemcrypto_core_message.size(); + + Message* msg = nullptr; + AllocateMessage(&msg, message_block); + InitMessage(msg, const_cast(buf), buf_length); + SetSize(msg, buf_length); + + unpacker(msg, prepared); + if (!ValidMessage(msg)) { + return false; + } + + const auto& core_message = prepared->core_message; + core_request->api_version = core_message.nonce_values.api_version; + core_request->nonce = core_message.nonce_values.nonce; + core_request->session_id = core_message.nonce_values.session_id; + return core_message.message_type == message_type && + core_message.message_length == GetOffset(msg) && + core_request->api_version >= EARLIEST_OEMCRYPTO_VERSION_WITH_ODK && + core_request->api_version <= LATEST_OEMCRYPTO_VERSION; +} + +} // namespace + +bool CoreLicenseRequestFromMessage(const string& oemcrypto_core_message, + ODK_LicenseRequest* core_license_request) { + const auto unpacker = Unpack_ODK_PreparedLicense; + ODK_PreparedLicense prepared_license = {}; + return ParseRequest(ODK_License_Request_Type, oemcrypto_core_message, + core_license_request, &prepared_license, unpacker); +} + +bool CoreRenewalRequestFromMessage(const string& oemcrypto_core_message, + ODK_RenewalRequest* core_renewal_request) { + const auto unpacker = Unpack_ODK_RenewalMessage; + ODK_RenewalMessage prepared_renewal = {}; + if (!ParseRequest(ODK_Renewal_Request_Type, oemcrypto_core_message, + core_renewal_request, &prepared_renewal, unpacker)) { + return false; + } + core_renewal_request->playback_time_seconds = prepared_renewal.playback_time; + return true; +} + +bool CoreProvisioningRequestFromMessage( + const string& oemcrypto_core_message, + ODK_ProvisioningRequest* core_provisioning_request) { + const auto unpacker = Unpack_ODK_ProvisioningMessage; + ODK_ProvisioningMessage prepared_provision = {}; + if (!ParseRequest(ODK_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); + return true; +} + +} // namespace deserialize +} // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/src/core_message_serialize.cpp b/oemcrypto/odk/src/core_message_serialize.cpp new file mode 100644 index 0000000..6f95e9c --- /dev/null +++ b/oemcrypto/odk/src/core_message_serialize.cpp @@ -0,0 +1,114 @@ +// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "core_message_serialize.h" + +#include +#include +#include +#include +#include +#include + +#include "odk_serialize.h" +#include "odk_structs.h" +#include "odk_structs_priv.h" +#include "serialization_base.h" + +namespace oemcrypto_core_message { +namespace serialize { +namespace { + +/** + * Template for parsing requests + * + * Template arguments: + * T: struct to be deserialized by odk + * S: kdo input struct + * P: auto-generated serializing function for |T| + */ +template +bool CreateResponse(uint32_t message_type, const S& core_request, + string* oemcrypto_core_message, T& response, + const P& packer) { + if (!oemcrypto_core_message) { + return false; + } + + auto* header = reinterpret_cast(&response); + header->message_type = message_type; + header->nonce_values.api_version = core_request.api_version; + header->nonce_values.nonce = core_request.nonce; + header->nonce_values.session_id = core_request.session_id; + + const size_t BUF_CAPACITY = 2048; + std::vector buf(BUF_CAPACITY, 0); + Message* msg = nullptr; + AllocateMessage(&msg, message_block); + InitMessage(msg, buf.data(), buf.capacity()); + packer(msg, &response); + if (!ValidMessage(msg)) { + return false; + } + + uint32_t message_length = GetSize(msg); + InitMessage(msg, buf.data() + sizeof(header->message_type), + sizeof(header->message_length)); + Pack_uint32_t(msg, &message_length); + oemcrypto_core_message->assign(reinterpret_cast(buf.data()), + message_length); + return true; +} + +bool CopyDeviceId(const ODK_ProvisioningRequest& src, + ODK_ProvisioningResponse* dest) { + auto& core_provisioning = dest->core_provisioning; + const string& device_id = src.device_id; + core_provisioning.device_id_length = device_id.size(); + if (core_provisioning.device_id_length > + sizeof(core_provisioning.device_id)) { + return false; + } + memset(core_provisioning.device_id, 0, sizeof(core_provisioning.device_id)); + memcpy(core_provisioning.device_id, device_id.data(), + core_provisioning.device_id_length); + return true; +} + +} // namespace + +bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic, + const ODK_LicenseRequest& core_request, + string* oemcrypto_core_message) { + ODK_LicenseResponse license_response{ + {}, const_cast(&parsed_lic)}; + return CreateResponse(ODK_License_Response_Type, core_request, + oemcrypto_core_message, license_response, + Pack_ODK_LicenseResponse); +} + +bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request, + string* oemcrypto_core_message) { + ODK_RenewalMessage renewal{{}, core_request.playback_time_seconds}; + renewal.playback_time = core_request.playback_time_seconds; + return CreateResponse(ODK_Renewal_Response_Type, core_request, + oemcrypto_core_message, renewal, + Pack_ODK_RenewalMessage); +} + +bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov, + const ODK_ProvisioningRequest& core_request, + string* oemcrypto_core_message) { + ODK_ProvisioningResponse prov_response{ + {}, const_cast(&parsed_prov)}; + if (!CopyDeviceId(core_request, &prov_response)) { + return false; + } + return CreateResponse(ODK_Provisioning_Response_Type, core_request, + oemcrypto_core_message, prov_response, + Pack_ODK_ProvisioningResponse); +} + +} // namespace serialize +} // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/kdo/src/oec_util_proto.cpp b/oemcrypto/odk/src/core_message_serialize_proto.cpp similarity index 56% rename from oemcrypto/odk/kdo/src/oec_util_proto.cpp rename to oemcrypto/odk/src/core_message_serialize_proto.cpp index 02474d2..8520cd5 100644 --- a/oemcrypto/odk/kdo/src/oec_util_proto.cpp +++ b/oemcrypto/odk/src/core_message_serialize_proto.cpp @@ -1,29 +1,24 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. -#include "oec_util_proto.h" +#include "core_message_serialize_proto.h" -#include #include #include #include #include #include -#include "odk_overflow.h" +#include "core_message_serialize.h" +#include "license_protocol.pb.h" #include "odk_serialize.h" #include "odk_structs.h" #include "odk_structs_priv.h" -#include "oemcrypto_types.h" #include "serialization_base.h" -using namespace oec_util; - -namespace oec_util { - +namespace oemcrypto_core_message { +namespace serialize { namespace { /* @ private functions */ @@ -45,14 +40,14 @@ OEMCrypto_Substring GetOecSubstring(const std::string& message, return substring; } -OEMCrypto_KeyObject KeyContainerToOecKey(const string& proto, - const License::KeyContainer& k) { +OEMCrypto_KeyObject KeyContainerToOecKey( + const std::string& proto, const video_widevine::License::KeyContainer& k) { OEMCrypto_KeyObject obj = {}; obj.key_id = GetOecSubstring(proto, k.id()); obj.key_data_iv = GetOecSubstring(proto, k.iv()); // Strip off PKCS#5 padding - since we know the key is 16 or 32 bytes, // the padding will always be 16 bytes. - const string& key_data = k.key(); + const std::string& key_data = k.key(); const size_t PKCS5_PADDING_SIZE = 16; obj.key_data = GetOecSubstring( proto, key_data.substr(0, std::max(PKCS5_PADDING_SIZE, key_data.size()) - @@ -69,31 +64,40 @@ OEMCrypto_KeyObject KeyContainerToOecKey(const string& proto, // @ public create response functions -bool CreateCoreLicenseResponse(const video_widevine::License& lic, - const ODK_LicenseRequest& core_request, - string* oemcrypto_core_message) { - string proto; - if (!lic.SerializeToString(&proto)) { +bool CreateCoreLicenseResponseFromProto(const std::string& serialized_license, + const ODK_LicenseRequest& core_request, + const std::string& core_request_sha256, + std::string* oemcrypto_core_message) { + video_widevine::License lic; + if (!lic.ParseFromString(serialized_license)) { return false; } + ODK_ParsedLicense parsed_lic{}; + if (core_request_sha256.size() != ODK_SHA256_HASH_SIZE) { + return false; + } + std::memcpy(parsed_lic.request_hash, core_request_sha256.data(), + ODK_SHA256_HASH_SIZE); for (int i = 0; i < lic.key_size(); ++i) { const auto& k = lic.key(i); switch (k.type()) { - case License_KeyContainer::SIGNING: { - parsed_lic.enc_mac_keys_iv = GetOecSubstring(proto, k.iv()); + case video_widevine::License_KeyContainer::SIGNING: { + parsed_lic.enc_mac_keys_iv = + GetOecSubstring(serialized_license, k.iv()); // Strip off PKCS#5 padding - string mac_keys(k.key(), 2 * wvoec::MAC_KEY_SIZE); - parsed_lic.enc_mac_keys = GetOecSubstring(proto, mac_keys); + const size_t MAC_KEY_SIZE = 32; + std::string mac_keys(k.key(), 2 * MAC_KEY_SIZE); + parsed_lic.enc_mac_keys = GetOecSubstring(serialized_license, mac_keys); break; } - case License_KeyContainer::CONTENT: { + case video_widevine::License_KeyContainer::CONTENT: { if (parsed_lic.key_array_length >= ODK_MAX_NUM_KEYS) { return false; } uint32_t& n = parsed_lic.key_array_length; - parsed_lic.key_array[n++] = KeyContainerToOecKey(proto, k); + parsed_lic.key_array[n++] = KeyContainerToOecKey(serialized_license, k); break; } default: { @@ -102,19 +106,19 @@ bool CreateCoreLicenseResponse(const video_widevine::License& lic, } } - const auto& license_id = lic.id(); - if (license_id.has_provider_session_token()) { + const auto& lid = lic.id(); + if (lid.has_provider_session_token()) { parsed_lic.pst = - GetOecSubstring(proto, license_id.provider_session_token()); + GetOecSubstring(serialized_license, lid.provider_session_token()); } if (lic.has_srm_requirement()) { parsed_lic.srm_restriction_data = - GetOecSubstring(proto, lic.srm_requirement()); + GetOecSubstring(serialized_license, lic.srm_requirement()); } - parsed_lic.license_type = license_id.type(); - // todo: nonce_required + parsed_lic.license_type = lid.type(); + // todo(robertshih): nonce_required const auto& policy = lic.policy(); ODK_TimerLimits& timer_limits = parsed_lic.timer_limits; timer_limits.soft_expiry = policy.soft_enforce_playback_duration(); @@ -131,31 +135,33 @@ bool CreateCoreLicenseResponse(const video_widevine::License& lic, oemcrypto_core_message); } -bool CreateCoreProvisioningResponse( - const video_widevine::ProvisioningResponse& prov, +bool CreateCoreProvisioningResponseFromProto( + const std::string& serialized_provisioning_resp, const ODK_ProvisioningRequest& core_request, - string* oemcrypto_core_message) { + std::string* oemcrypto_core_message) { ODK_ParsedProvisioning parsed_prov{}; - string proto; - if (!prov.SerializeToString(&proto)) { + video_widevine::ProvisioningResponse prov; + if (!prov.ParseFromString(serialized_provisioning_resp)) { return false; } - parsed_prov.key_type = 0; // todo: ECC or RSA + parsed_prov.key_type = 0; // todo(robertshih): ECC or RSA if (prov.has_device_rsa_key()) { - parsed_prov.enc_private_key = GetOecSubstring(proto, prov.device_rsa_key()); + parsed_prov.enc_private_key = + GetOecSubstring(serialized_provisioning_resp, prov.device_rsa_key()); } if (prov.has_device_rsa_key_iv()) { parsed_prov.enc_private_key_iv = - GetOecSubstring(proto, prov.device_rsa_key_iv()); + GetOecSubstring(serialized_provisioning_resp, prov.device_rsa_key_iv()); } if (prov.has_wrapping_key()) { parsed_prov.encrypted_message_key = - GetOecSubstring(proto, prov.wrapping_key()); + GetOecSubstring(serialized_provisioning_resp, prov.wrapping_key()); } return CreateCoreProvisioningResponse(parsed_prov, core_request, oemcrypto_core_message); } -} // namespace oec_util +} // namespace serialize +} // namespace oemcrypto_core_message diff --git a/oemcrypto/odk/src/kdo.gypi b/oemcrypto/odk/src/kdo.gypi new file mode 100644 index 0000000..555a8f0 --- /dev/null +++ b/oemcrypto/odk/src/kdo.gypi @@ -0,0 +1,18 @@ +# Copyright 2019 Google LLC. All rights reserved. This file and proprietary +# source code may only be used and distributed under the Widevine Master License +# Agreement. + +# These files are used by the server and by some ODK test code. These files are +# not built into the ODK library on the device. +{ + 'sources': [ + 'core_message_deserialize.cpp', + 'core_message_serialize.cpp', + 'core_message_serialize_proto.cpp', + ], + 'include_dirs': [ + 'src', + '../include', + ], +} + diff --git a/oemcrypto/odk/src/odk.c b/oemcrypto/odk/src/odk.c index 80471bf..08e2e81 100644 --- a/oemcrypto/odk/src/odk.c +++ b/oemcrypto/odk/src/odk.c @@ -1,14 +1,13 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ + +#include "odk.h" #include #include #include -#include "odk.h" #include "odk_overflow.h" #include "odk_serialize.h" #include "odk_structs.h" @@ -18,6 +17,7 @@ #define ODK_LICENSE_REQUEST_SIZE 20 #define ODK_RENEWAL_REQUEST_SIZE 28 #define ODK_PROVISIONING_REQUEST_SIZE 88 +#define OEC_API_VERSION 16 /* @ private odk functions */ @@ -35,7 +35,9 @@ static OEMCryptoResult ODK_PrepareRequest(uint8_t* buffer, size_t buffer_length, AllocateMessage(&msg, message_block); InitMessage(msg, buffer, *core_message_length); *core_message = (ODK_CoreMessage){ - message_type, 0, *nonce_values, + message_type, + 0, + *nonce_values, }; switch (message_type) { @@ -69,13 +71,21 @@ static OEMCryptoResult ODK_PrepareRequest(uint8_t* buffer, size_t buffer_length, static OEMCryptoResult ODK_ParseResponse(const uint8_t* buf, size_t message_length, + size_t core_message_length, uint32_t message_type, const ODK_NonceValues* nonce_values, ODK_CoreMessage* const core_message) { + if (core_message_length > message_length) { + return ODK_ERROR_CORE_MESSAGE; + } Message* msg = NULL; AllocateMessage(&msg, message_block); + /* We initialize the message buffer with a size of the entire message + * length. */ InitMessage(msg, (uint8_t*)buf, message_length); - SetSize(msg, 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. */ + SetSize(msg, core_message_length); switch (message_type) { case ODK_License_Response_Type: { @@ -121,16 +131,18 @@ static OEMCryptoResult ODK_ParseResponse(const uint8_t* buf, OEMCryptoResult ODK_PrepareCoreLicenseRequest( uint8_t* message, size_t message_length, size_t* core_message_length, const ODK_NonceValues* nonce_values) { - ODK_PreparedLicense license_request = {0}; + ODK_PreparedLicense license_request = { + {0}, + }; return ODK_PrepareRequest(message, message_length, core_message_length, ODK_License_Request_Type, nonce_values, &license_request.core_message); } OEMCryptoResult ODK_PrepareCoreRenewalRequest( - uint8_t* message, size_t message_length, size_t* core_message_length, - const ODK_NonceValues* nonce_values, - ODK_ClockValues* clock_values, uint64_t system_time_seconds) { + uint8_t* message, size_t message_length, size_t* core_message_size, + const ODK_NonceValues* nonce_values, ODK_ClockValues* clock_values, + uint64_t system_time_seconds) { ODK_RenewalMessage renewal_request = { {0}, }; @@ -148,15 +160,15 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest( } /* Save time for this request so that we can verify the response. */ clock_values->time_of_renewal_request = renewal_request.playback_time; - return ODK_PrepareRequest(message, message_length, core_message_length, + return ODK_PrepareRequest(message, message_length, core_message_size, ODK_Renewal_Request_Type, nonce_values, &renewal_request.core_message); } OEMCryptoResult ODK_PrepareCoreProvisioningRequest( 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) { + const ODK_NonceValues* nonce_values, const uint8_t* device_id, + size_t device_id_length) { ODK_ProvisioningMessage provisioning_request = { {0}, }; @@ -174,30 +186,28 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( /* @@ parse request 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) { - +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 (!nonce_values || !parsed_license) { return ODK_ERROR_CORE_MESSAGE; } ODK_LicenseResponse license_response = {{0}, parsed_license}; OEMCryptoResult err = ODK_ParseResponse( - message, message_length, ODK_License_Response_Type, NULL, - &license_response.core_message); + message, message_length, core_message_length, ODK_License_Response_Type, + NULL, &license_response.core_message); if (err != OEMCrypto_SUCCESS) { return err; } + /* This function should not be used for legacy licenses. */ - if (license_response.core_message.nonce_values.api_version != 16) { + if (license_response.core_message.nonce_values.api_version != + OEC_API_VERSION) { return ODK_UNSUPPORTED_API; } @@ -249,8 +259,8 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, {0}, }; OEMCryptoResult err = ODK_ParseResponse( - message, message_length, ODK_Renewal_Response_Type, nonce_values, - &renewal_response.core_message); + message, message_length, core_message_length, ODK_Renewal_Response_Type, + nonce_values, &renewal_response.core_message); if (err) { return err; @@ -268,41 +278,28 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, return ODK_STALE_RENEWAL; } - uint64_t playback_timer = 0; - if (odk_sub_overflow_u64(clock_values->time_when_timer_expires, system_time, - &playback_timer)) { - return ODK_TIMER_EXPIRED; + /* The timer value should be set to the renewal duration. */ + if (timer_value) { + *timer_value = timer_limits->renewal_playback_duration_seconds; } - uint64_t time_since_playback_began = 0; - uint64_t time_since_reset = 0; - uint64_t time_since_message_signed = 0; - /* ... or use clock_values->time_of_license_signed ? */ - if (odk_sub_overflow_u64(system_time, clock_values->time_of_first_decrypt, - &time_since_playback_began) || - odk_sub_overflow_u64(timer_limits->renewal_playback_duration_seconds, - playback_timer, &time_since_reset) || - odk_sub_overflow_u64(time_since_playback_began, - renewal_response.playback_time, - &time_since_message_signed) || - time_since_message_signed >= time_since_reset || - odk_add_overflow_u64(system_time, + if (timer_limits->renewal_playback_duration_seconds == 0) { + clock_values->time_when_timer_expires = 0; + clock_values->timer_status = ODK_DISABLE_TIMER; + return ODK_DISABLE_TIMER; + } + if (odk_add_overflow_u64(system_time, timer_limits->renewal_playback_duration_seconds, &clock_values->time_when_timer_expires)) { return ODK_ERROR_CORE_MESSAGE; } - - /* todo: when to return ODK_DISABLE_TIMER */ - if (timer_value) - *timer_value = timer_limits->renewal_playback_duration_seconds; + clock_values->timer_status = ODK_SET_TIMER; return ODK_SET_TIMER; } OEMCryptoResult ODK_ParseProvisioning( - const uint8_t* message, size_t message_length, - size_t core_message_length, - const ODK_NonceValues* nonce_values, - const uint8_t* device_id, + const 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, ODK_ParsedProvisioning* parsed_response) { if (!nonce_values || !device_id || !parsed_response) { return ODK_ERROR_CORE_MESSAGE; @@ -316,9 +313,10 @@ OEMCryptoResult ODK_ParseProvisioning( return ODK_ERROR_CORE_MESSAGE; } - OEMCryptoResult err = ODK_ParseResponse( - message, message_length, ODK_Provisioning_Response_Type, - nonce_values, &provisioning_response.core_provisioning.core_message); + OEMCryptoResult err = + ODK_ParseResponse(message, message_length, core_message_length, + ODK_Provisioning_Response_Type, nonce_values, + &provisioning_response.core_provisioning.core_message); if (err) { return err; diff --git a/oemcrypto/odk/src/odk.gyp b/oemcrypto/odk/src/odk.gyp index 0b68fdc..a16dec6 100644 --- a/oemcrypto/odk/src/odk.gyp +++ b/oemcrypto/odk/src/odk.gyp @@ -1,4 +1,4 @@ -# Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +# Copyright 2019 Google LLC. All rights reserved. This file and proprietary # source code may only be used and distributed under the Widevine Master License # Agreement. diff --git a/oemcrypto/odk/src/odk.gypi b/oemcrypto/odk/src/odk.gypi index f8b5fb3..6488b68 100644 --- a/oemcrypto/odk/src/odk.gypi +++ b/oemcrypto/odk/src/odk.gypi @@ -1,7 +1,9 @@ -# Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +# Copyright 2019 Google LLC. All rights reserved. This file and proprietary # source code may only be used and distributed under the Widevine Master License # Agreement. +# These files are built into the ODK library on the device. They are also used +# by the server and by test cocde. These files should compile on C98 compilers. { 'sources': [ 'odk.c', diff --git a/oemcrypto/odk/src/odk_assert.h b/oemcrypto/odk/src/odk_assert.h index e1a21fd..7f1e952 100644 --- a/oemcrypto/odk/src/odk_assert.h +++ b/oemcrypto/odk/src/odk_assert.h @@ -1,12 +1,9 @@ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ - -#ifndef ODK_ASSERT_H_ -#define ODK_ASSERT_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_ASSERT_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_ASSERT_H_ #ifdef __cplusplus extern "C" { @@ -24,4 +21,4 @@ extern "C" { } #endif -#endif /* ODK_ASSERT_H_ */ +#endif /* ...ODK_SRC_ODK_ASSERT_H_ */ diff --git a/oemcrypto/odk/src/odk_endian.h b/oemcrypto/odk/src/odk_endian.h new file mode 100644 index 0000000..f3a813e --- /dev/null +++ b/oemcrypto/odk/src/odk_endian.h @@ -0,0 +1,29 @@ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ + +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_ENDIAN_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_ENDIAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(__linux__) || defined(__ANDROID__) +# include +# define oemcrypto_htobe32 htobe32 +# define oemcrypto_be32toh be32toh +# define oemcrypto_htobe64 htobe64 +# define oemcrypto_be64toh be64toh +#else /* defined(__linux__) || defined(__ANDROID__) */ +uint32_t oemcrypto_htobe32(uint32_t u32); +uint32_t oemcrypto_be32toh(uint32_t u32); +uint64_t oemcrypto_htobe64(uint64_t u64); +uint64_t oemcrypto_be64toh(uint64_t u64); +#endif /* defined(__linux__) || defined(__ANDROID__) */ + +#ifdef __cplusplus +} +#endif + +#endif /* ...ODK_SRC_ODK_ENDIAN_H_ */ diff --git a/oemcrypto/odk/src/odk_overflow.c b/oemcrypto/odk/src/odk_overflow.c index 3a05f22..76c685f 100644 --- a/oemcrypto/odk/src/odk_overflow.c +++ b/oemcrypto/odk/src/odk_overflow.c @@ -1,8 +1,6 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ #include #include diff --git a/oemcrypto/odk/src/odk_overflow.h b/oemcrypto/odk/src/odk_overflow.h index 32aebe7..b4c5923 100644 --- a/oemcrypto/odk/src/odk_overflow.h +++ b/oemcrypto/odk/src/odk_overflow.h @@ -1,11 +1,9 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ -#ifndef ODK_OVERFLOW_H_ -#define ODK_OVERFLOW_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_OVERFLOW_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_OVERFLOW_H_ #ifdef __cplusplus extern "C" { @@ -30,4 +28,4 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c); } #endif -#endif /* ODK_OVERFLOW_H_ */ +#endif /* ...ODK_SRC_ODK_OVERFLOW_H_ */ diff --git a/oemcrypto/odk/src/odk_serialize.c b/oemcrypto/odk/src/odk_serialize.c index dab42be..5f77aee 100644 --- a/oemcrypto/odk/src/odk_serialize.c +++ b/oemcrypto/odk/src/odk_serialize.c @@ -1,8 +1,6 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ /* * This code is auto-generated, do not edit @@ -29,21 +27,20 @@ static void Pack_ODK_CoreMessage(Message* msg, ODK_CoreMessage const* obj) { static void Pack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject const* obj) { - Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_id); - Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_data_iv); - Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_data); - Pack_OEMCrypto_Substring(msg, - (const OEMCrypto_Substring*)&obj->key_control_iv); - Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->key_control); + Pack_OEMCrypto_Substring(msg, &obj->key_id); + Pack_OEMCrypto_Substring(msg, &obj->key_data_iv); + Pack_OEMCrypto_Substring(msg, &obj->key_data); + Pack_OEMCrypto_Substring(msg, &obj->key_control_iv); + Pack_OEMCrypto_Substring(msg, &obj->key_control); } static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) { - Pack_uint32_t(msg, (const uint32_t*)&obj->soft_expiry); - Pack_uint64_t(msg, (const uint64_t*)&obj->earliest_playback_start_seconds); - Pack_uint64_t(msg, (const uint64_t*)&obj->latest_playback_start_seconds); - Pack_uint64_t(msg, (const uint64_t*)&obj->initial_playback_duration_seconds); - Pack_uint64_t(msg, (const uint64_t*)&obj->renewal_playback_duration_seconds); - Pack_uint64_t(msg, (const uint64_t*)&obj->license_duration_seconds); + Pack_uint32_t(msg, &obj->soft_expiry); + Pack_uint64_t(msg, &obj->earliest_playback_start_seconds); + Pack_uint64_t(msg, &obj->latest_playback_start_seconds); + Pack_uint64_t(msg, &obj->initial_playback_duration_seconds); + Pack_uint64_t(msg, &obj->renewal_playback_duration_seconds); + Pack_uint64_t(msg, &obj->license_duration_seconds); } static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) { @@ -52,62 +49,57 @@ static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) { SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); return; } - Pack_OEMCrypto_Substring(msg, - (const OEMCrypto_Substring*)&obj->enc_mac_keys_iv); - Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->enc_mac_keys); - Pack_OEMCrypto_Substring(msg, (const OEMCrypto_Substring*)&obj->pst); - Pack_OEMCrypto_Substring( - msg, (const OEMCrypto_Substring*)&obj->srm_restriction_data); - Pack_uint32_t(msg, (const uint32_t*)&obj->license_type); - Pack_uint32_t(msg, (const uint32_t*)&obj->nonce_required); - Pack_ODK_TimerLimits(msg, (const ODK_TimerLimits*)&obj->timer_limits); - PackArray(msg, (const uint8_t*)&obj->request_hash[0], sizeof(obj->request_hash)); - Pack_uint32_t(msg, (const uint32_t*)&obj->key_array_length); - for (size_t i = 0; i < (size_t)obj->key_array_length; i++) { + 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_uint32_t(msg, &obj->license_type); + Pack_uint32_t(msg, &obj->nonce_required); + Pack_ODK_TimerLimits(msg, &obj->timer_limits); + PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); + 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_ParsedProvisioning(Message* msg, ODK_ParsedProvisioning const* obj) { - Pack_uint32_t(msg, (const uint32_t*)&obj->key_type); - Pack_OEMCrypto_Substring(msg, - (const OEMCrypto_Substring*)&obj->enc_private_key); - Pack_OEMCrypto_Substring( - msg, (const OEMCrypto_Substring*)&obj->enc_private_key_iv); - Pack_OEMCrypto_Substring( - msg, (const OEMCrypto_Substring*)&obj->encrypted_message_key); + Pack_uint32_t(msg, &obj->key_type); + Pack_OEMCrypto_Substring(msg, &obj->enc_private_key); + Pack_OEMCrypto_Substring(msg, &obj->enc_private_key_iv); + Pack_OEMCrypto_Substring(msg, &obj->encrypted_message_key); } /* @@ odk serialize */ void Pack_ODK_PreparedLicense(Message* msg, ODK_PreparedLicense const* obj) { - Pack_ODK_CoreMessage(msg, (const ODK_CoreMessage*)&obj->core_message); + Pack_ODK_CoreMessage(msg, &obj->core_message); } void Pack_ODK_RenewalMessage(Message* msg, ODK_RenewalMessage const* obj) { - Pack_ODK_CoreMessage(msg, (const ODK_CoreMessage*)&obj->core_message); - Pack_uint64_t(msg, (const uint64_t*)&obj->playback_time); + Pack_ODK_CoreMessage(msg, &obj->core_message); + Pack_uint64_t(msg, &obj->playback_time); } void Pack_ODK_ProvisioningMessage(Message* msg, ODK_ProvisioningMessage const* obj) { - Pack_ODK_CoreMessage(msg, (const ODK_CoreMessage*)&obj->core_message); - Pack_uint32_t(msg, (const uint32_t*)&obj->device_id_length); - PackArray(msg, (const uint8_t*)&obj->device_id[0], sizeof(obj->device_id)); + 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)); } /* @@ kdo serialize */ void Pack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse const* obj) { - Pack_ODK_CoreMessage(msg, (const ODK_CoreMessage*)&obj->core_message); + Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_ODK_ParsedLicense(msg, (const ODK_ParsedLicense*)obj->parsed_license); } void Pack_ODK_ProvisioningResponse(Message* msg, ODK_ProvisioningResponse const* obj) { - Pack_ODK_ProvisioningMessage( - msg, (const ODK_ProvisioningMessage*)&obj->core_provisioning); + Pack_ODK_ProvisioningMessage(msg, &obj->core_provisioning); Pack_ODK_ParsedProvisioning( msg, (const ODK_ParsedProvisioning*)obj->parsed_provisioning); } @@ -129,81 +121,77 @@ static void Unpack_ODK_CoreMessage(Message* msg, ODK_CoreMessage* obj) { } static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) { - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_id); - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_data_iv); - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_data); - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_control_iv); - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->key_control); + Unpack_OEMCrypto_Substring(msg, &obj->key_id); + Unpack_OEMCrypto_Substring(msg, &obj->key_data_iv); + Unpack_OEMCrypto_Substring(msg, &obj->key_data); + Unpack_OEMCrypto_Substring(msg, &obj->key_control_iv); + Unpack_OEMCrypto_Substring(msg, &obj->key_control); } static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) { - Unpack_uint32_t(msg, (uint32_t*)&obj->soft_expiry); - Unpack_uint64_t(msg, (uint64_t*)&obj->earliest_playback_start_seconds); - Unpack_uint64_t(msg, (uint64_t*)&obj->latest_playback_start_seconds); - Unpack_uint64_t(msg, (uint64_t*)&obj->initial_playback_duration_seconds); - Unpack_uint64_t(msg, (uint64_t*)&obj->renewal_playback_duration_seconds); - Unpack_uint64_t(msg, (uint64_t*)&obj->license_duration_seconds); + Unpack_uint32_t(msg, &obj->soft_expiry); + Unpack_uint64_t(msg, &obj->earliest_playback_start_seconds); + Unpack_uint64_t(msg, &obj->latest_playback_start_seconds); + Unpack_uint64_t(msg, &obj->initial_playback_duration_seconds); + Unpack_uint64_t(msg, &obj->renewal_playback_duration_seconds); + Unpack_uint64_t(msg, &obj->license_duration_seconds); } static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) { - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->enc_mac_keys_iv); - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->enc_mac_keys); - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->pst); - Unpack_OEMCrypto_Substring(msg, - (OEMCrypto_Substring*)&obj->srm_restriction_data); - Unpack_uint32_t(msg, (uint32_t*)&obj->license_type); - Unpack_uint32_t(msg, (uint32_t*)&obj->nonce_required); - Unpack_ODK_TimerLimits(msg, (ODK_TimerLimits*)&obj->timer_limits); - UnpackArray(msg, (uint8_t*)&obj->request_hash[0], sizeof(obj->request_hash)); - Unpack_uint32_t(msg, (uint32_t*)&obj->key_array_length); + 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); + Unpack_uint32_t(msg, &obj->license_type); + Unpack_uint32_t(msg, &obj->nonce_required); + Unpack_ODK_TimerLimits(msg, &obj->timer_limits); + UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); + Unpack_uint32_t(msg, &obj->key_array_length); if (obj->key_array_length > ODK_MAX_NUM_KEYS) { SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); return; } - for (uint32_t i = 0; i < obj->key_array_length; i++) { + uint32_t i; + for (i = 0; i < obj->key_array_length; i++) { Unpack_OEMCrypto_KeyObject(msg, &obj->key_array[i]); } } static void Unpack_ODK_ParsedProvisioning(Message* msg, ODK_ParsedProvisioning* obj) { - Unpack_uint32_t(msg, (uint32_t*)&obj->key_type); - Unpack_OEMCrypto_Substring(msg, (OEMCrypto_Substring*)&obj->enc_private_key); - Unpack_OEMCrypto_Substring(msg, - (OEMCrypto_Substring*)&obj->enc_private_key_iv); - Unpack_OEMCrypto_Substring(msg, - (OEMCrypto_Substring*)&obj->encrypted_message_key); + Unpack_uint32_t(msg, &obj->key_type); + Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key); + Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key_iv); + Unpack_OEMCrypto_Substring(msg, &obj->encrypted_message_key); } /* @ kdo deserialize */ void Unpack_ODK_PreparedLicense(Message* msg, ODK_PreparedLicense* obj) { - Unpack_ODK_CoreMessage(msg, (ODK_CoreMessage*)&obj->core_message); + Unpack_ODK_CoreMessage(msg, &obj->core_message); } void Unpack_ODK_ProvisioningMessage(Message* msg, ODK_ProvisioningMessage* obj) { - Unpack_ODK_CoreMessage(msg, (ODK_CoreMessage*)&obj->core_message); - Unpack_uint32_t(msg, (uint32_t*)&obj->device_id_length); - UnpackArray(msg, (uint8_t*)&obj->device_id[0], sizeof(obj->device_id)); + 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)); } /* @@ odk deserialize */ void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj) { - Unpack_ODK_CoreMessage(msg, (ODK_CoreMessage*)&obj->core_message); - Unpack_ODK_ParsedLicense(msg, (ODK_ParsedLicense*)obj->parsed_license); + Unpack_ODK_CoreMessage(msg, &obj->core_message); + Unpack_ODK_ParsedLicense(msg, obj->parsed_license); } void Unpack_ODK_RenewalMessage(Message* msg, ODK_RenewalMessage* obj) { - Unpack_ODK_CoreMessage(msg, (ODK_CoreMessage*)&obj->core_message); - Unpack_uint64_t(msg, (uint64_t*)&obj->playback_time); + Unpack_ODK_CoreMessage(msg, &obj->core_message); + Unpack_uint64_t(msg, &obj->playback_time); } void Unpack_ODK_ProvisioningResponse(Message* msg, ODK_ProvisioningResponse* obj) { - Unpack_ODK_ProvisioningMessage( - msg, (ODK_ProvisioningMessage*)&obj->core_provisioning); - Unpack_ODK_ParsedProvisioning( - msg, (ODK_ParsedProvisioning*)obj->parsed_provisioning); + Unpack_ODK_ProvisioningMessage(msg, &obj->core_provisioning); + Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning); } diff --git a/oemcrypto/odk/src/odk_serialize.h b/oemcrypto/odk/src/odk_serialize.h index c9488d7..b2e7c7a 100644 --- a/oemcrypto/odk/src/odk_serialize.h +++ b/oemcrypto/odk/src/odk_serialize.h @@ -1,14 +1,12 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ /* * This code is auto-generated, do not edit */ -#ifndef ODKITEE_SERIALIZER_H_ -#define ODKITEE_SERIALIZER_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_SERIALIZE_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_SERIALIZE_H_ #include "odk_structs_priv.h" #include "serialization_base.h" @@ -39,6 +37,6 @@ void Unpack_ODK_PreparedLicense(Message* msg, ODK_PreparedLicense* obj); void Unpack_ODK_ProvisioningMessage(Message* msg, ODK_ProvisioningMessage* obj); #ifdef __cplusplus -} // extern "C" +} /* extern "C" */ #endif -#endif /* ODKITEE_SERIALIZER_H_ */ +#endif /* ...ODK_SRC_ODK_SERIALIZE_H_ */ diff --git a/oemcrypto/odk/src/odk_structs_priv.h b/oemcrypto/odk/src/odk_structs_priv.h index 8b3ee35..630e66e 100644 --- a/oemcrypto/odk/src/odk_structs_priv.h +++ b/oemcrypto/odk/src/odk_structs_priv.h @@ -1,13 +1,12 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ -#ifndef ODK_STRUCTS_PRIV_H_ -#define ODK_STRUCTS_PRIV_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_STRUCTS_PRIV_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_STRUCTS_PRIV_H_ #include + #include "OEMCryptoCENCCommon.h" #include "odk_structs.h" @@ -51,4 +50,4 @@ typedef struct { ODK_ParsedProvisioning* parsed_provisioning; } ODK_ProvisioningResponse; -#endif // ODK_STRUCTS_PRIV_H_ +#endif /* ...ODK_SRC_ODK_STRUCTS_PRIV_H_ */ diff --git a/oemcrypto/odk/src/odk_timer.c b/oemcrypto/odk/src/odk_timer.c index 38da1ef..a28547d 100644 --- a/oemcrypto/odk/src/odk_timer.c +++ b/oemcrypto/odk/src/odk_timer.c @@ -1,8 +1,6 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ #include #include @@ -57,11 +55,11 @@ OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values, } OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values, - uint64_t time_of_license_signed, - uint64_t time_of_first_decrypt, - uint64_t time_of_last_decrypt, - enum OEMCrypto_Usage_Entry_Status status, - uint64_t system_time_seconds) { + uint64_t time_of_license_signed, + uint64_t time_of_first_decrypt, + uint64_t time_of_last_decrypt, + enum OEMCrypto_Usage_Entry_Status status, + uint64_t system_time_seconds) { if (clock_values == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; clock_values->time_of_license_signed = time_of_license_signed; clock_values->time_of_first_decrypt = time_of_first_decrypt; diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c index 60cc473..3aff38b 100644 --- a/oemcrypto/odk/src/serialization_base.c +++ b/oemcrypto/odk/src/serialization_base.c @@ -1,8 +1,6 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ #include "serialization_base.h" @@ -117,8 +115,16 @@ void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj) { Unpack_uint32_t(msg, &offset); Unpack_uint32_t(msg, &length); if (!ValidMessage(msg)) return; - size_t end = 0; - if (offset > msg->capacity || odk_add_overflow_ux(offset, length, &end) || + /* Each substring should be contained within the message body, which is in the + * total message, just after the core message. The offset of a substring is + * relative to the message body. So we need to verify: + * 0 < offset and offset + length < message->capacity - message->size + * or offset + length + message->size < message->capacity + */ + size_t substring_end = 0; /* = offset + length; */ + size_t end = 0; /* = substring_end + message->size; */ + if (odk_add_overflow_ux(offset, length, &substring_end) || + odk_add_overflow_ux(substring_end, msg->size, &end) || end > msg->capacity) { msg->status = MESSAGE_STATUS_OVERFLOW_ERROR; return; @@ -188,6 +194,7 @@ size_t GetSize(Message* message) { void SetSize(Message* message, size_t size) { if (message == NULL) return; + if (size > message->capacity) message->status = MESSAGE_STATUS_OVERFLOW_ERROR; message->size = size; } diff --git a/oemcrypto/odk/src/serialization_base.h b/oemcrypto/odk/src/serialization_base.h index cc1a3d1..eb3b3d7 100644 --- a/oemcrypto/odk/src/serialization_base.h +++ b/oemcrypto/odk/src/serialization_base.h @@ -1,11 +1,9 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */ +/* source code may only be used and distributed under the Widevine Master */ +/* License Agreement. */ -#ifndef ODKITEE_SERIALIZATION_BASE_H_ -#define ODKITEE_SERIALIZATION_BASE_H_ +#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_SERIALIZATION_BASE_H_ +#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_SERIALIZATION_BASE_H_ #ifdef __cplusplus extern "C" { @@ -43,7 +41,8 @@ void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj); void Unpack_uint32_t(Message* message, uint32_t* value); void Unpack_uint64_t(Message* message, uint64_t* value); -void UnpackArray(Message* message, uint8_t* base, size_t size); /* copy out */ +void UnpackArray(Message* message, uint8_t* address, + size_t size); /* copy out */ void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj); typedef enum { @@ -85,7 +84,7 @@ size_t GetOffset(Message* message); size_t SizeOfMessageStruct(); #ifdef __cplusplus -} // extern "C" +} /* extern "C" */ #endif -#endif // ODKITEE_SERIALIZATION_BASE_H_ +#endif /* ...ODK_SRC_SERIALIZATION_BASE_H_ */ diff --git a/oemcrypto/odk/test/odk_fuzz.cpp b/oemcrypto/odk/test/odk_fuzz.cpp index 1ad80b7..ac72955 100644 --- a/oemcrypto/odk/test/odk_fuzz.cpp +++ b/oemcrypto/odk/test/odk_fuzz.cpp @@ -1,5 +1,4 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary * source code may only be used and distributed under the Widevine Master * License Agreement. */ @@ -13,12 +12,16 @@ #include #include "OEMCryptoCENCCommon.h" +#include "core_message_deserialize.h" +#include "core_message_serialize.h" +#include "core_message_types.h" #include "odk.h" #include "odk_serialize.h" -#include "oec_util.h" +#include "odk_structs.h" +#include "odk_structs_priv.h" -using namespace std; -using namespace oec_util; +// TODO: remove this: using namespace std; +// TODO: remove this: using namespace oec_util; typedef std::function roundtrip_fun; @@ -93,9 +96,10 @@ static OEMCryptoResult odk_fun_LicenseResponse( const uint8_t* message, size_t message_length, uint32_t api_version, uint32_t nonce, uint32_t session_id, const ODK_ParseLicense_Args* a, ODK_ParsedLicense& parsed_lic) { - return ODK_ParseLicense(message, message_length, api_version, nonce, - session_id, bool(a->initial_license_load), - bool(a->usage_entry_present), &parsed_lic); + return ODK_ParseLicense( + message, message_length, api_version, nonce, session_id, + static_cast(a->initial_license_load), + static_cast(a->usage_entry_present), &parsed_lic); } static bool kdo_fun_LicenseResponse(const ODK_ParseLicense_Args* args, diff --git a/oemcrypto/odk/test/odk_fuzz.gyp b/oemcrypto/odk/test/odk_fuzz.gyp index f8e4454..69473be 100644 --- a/oemcrypto/odk/test/odk_fuzz.gyp +++ b/oemcrypto/odk/test/odk_fuzz.gyp @@ -1,4 +1,4 @@ -# Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +# Copyright 2019 Google LLC. All rights reserved. This file and proprietary # source code may only be used and distributed under the Widevine Master License # Agreement. diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index f515d79..f63edbb 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -1,8 +1,11 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ +// Copyright 2019 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "odk.h" + +#include +#include #include #include @@ -17,15 +20,48 @@ #include #include -#include +#include "OEMCryptoCENCCommon.h" +#include "core_message_deserialize.h" +#include "core_message_serialize.h" +#include "core_message_types.h" +#include "gtest/gtest.h" +#include "odk_structs.h" +#include "odk_structs_priv.h" -#include +namespace { -#include "odk.h" -#include "odk_test.h" -#include "oec_util.h" +using oemcrypto_core_message::ODK_LicenseRequest; +using oemcrypto_core_message::ODK_ProvisioningRequest; +using oemcrypto_core_message::ODK_RenewalRequest; -using namespace oec_util; +using oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage; +using oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage; +using oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage; + +using oemcrypto_core_message::serialize::CreateCoreLicenseResponse; +using oemcrypto_core_message::serialize::CreateCoreProvisioningResponse; +using oemcrypto_core_message::serialize::CreateCoreRenewalResponse; + +enum ODK_FieldType { + ODK_UINT32, + ODK_UINT64, + ODK_SUBSTRING, + ODK_DEVICEID, + ODK_HASH, + ODK_NUMTYPES, +}; + +enum ODK_FieldMode { + ODK_READ, + ODK_WRITE, + ODK_DUMP, +}; + +struct ODK_Field { + ODK_FieldType type; + void* value; + std::string name; +}; size_t ODK_FieldLength(ODK_FieldType type) { switch (type) { @@ -130,6 +166,54 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* const buf, return OEMCrypto_SUCCESS; } +OEMCryptoResult ODK_DumpSingleField(const uint8_t* const buf, + const ODK_Field* const field) { + if (!field || !field->value) { + return ODK_ERROR_CORE_MESSAGE; + } + switch (field->type) { + case ODK_UINT32: { + uint32_t val; + memcpy(&val, buf, sizeof(uint32_t)); + val = be32toh(val); + std::cerr << field->name << ": " << val << " = 0x" << std::hex << val + << "\n"; + break; + } + case ODK_UINT64: { + uint64_t val; + memcpy(&val, buf, sizeof(uint64_t)); + val = be64toh(val); + std::cerr << field->name << ": " << val << " = 0x" << std::hex << val + << "\n"; + break; + } + case ODK_SUBSTRING: { + uint32_t off = 0; + uint32_t len = 0; + memcpy(&off, buf, sizeof(off)); + memcpy(&len, buf + sizeof(off), sizeof(len)); + std::cerr << field->name << ": (off=" << off << ", len=" << len << ")\n"; + break; + } + case ODK_DEVICEID: + case ODK_HASH: { + const size_t field_len = ODK_FieldLength(field->type); + std::cerr << field->name << ": "; + for (size_t i = 0; i < field_len; i++) { + std::cerr << std::hex << std::setfill('0') << std::setw(2) << buf[i] + << "\n"; + } + std::cerr << "\n"; + break; + } + default: + return ODK_ERROR_CORE_MESSAGE; + } + std::cerr << std::dec; // Return to normal. + return OEMCrypto_SUCCESS; +} + /* * Parameters: * [in] size_in: buffer size @@ -137,7 +221,7 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* const buf, */ OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* const buf, const size_t size_in, size_t* size_out, - std::vector& fields) { + const std::vector& fields) { if (!buf || !size_out) { return ODK_ERROR_CORE_MESSAGE; } @@ -156,6 +240,8 @@ OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* const buf, ODK_WriteSingleField(buf_off, &fields[i]); } else if (mode == ODK_READ) { ODK_ReadSingleField(buf_off, &fields[i]); + } else if (mode == ODK_DUMP) { + ODK_DumpSingleField(buf_off, &fields[i]); } else { return ODK_ERROR_CORE_MESSAGE; } @@ -168,20 +254,8 @@ OEMCryptoResult ODK_IterFields(ODK_FieldMode mode, uint8_t* const buf, return OEMCrypto_SUCCESS; } -OEMCryptoResult ODK_ReadFields(const uint8_t* const buf, const size_t size_in, - size_t* size_out, - std::vector& fields) { - return ODK_IterFields(ODK_READ, const_cast(buf), size_in, size_out, - fields); -} - -OEMCryptoResult ODK_WriteFields(uint8_t* const buf, const size_t size_in, - size_t* size_out, - std::vector& fields) { - return ODK_IterFields(ODK_WRITE, buf, size_in, size_out, fields); -} - -void expect_eq_buf(const void* s1, const void* s2, size_t n) { +void expect_eq_buf(const void* s1, const void* s2, size_t n, + const std::vector& fields) { if (memcmp(s1, s2, n)) { const void* buffers[] = {s1, s2}; for (int i = 0; i < 2; i++) { @@ -189,9 +263,13 @@ void expect_eq_buf(const void* s1, const void* s2, size_t n) { mkstemp(_tmp); std::string tmp(_tmp); std::fstream out(tmp, std::ios::out | std::ios::binary); - out.write((char*)buffers[i], n); + out.write(static_cast(buffers[i]), n); out.close(); std::cerr << "buffer " << i << " dumped to " << tmp << std::endl; + size_t bytes_written; + uint8_t* buf = + const_cast(reinterpret_cast(buffers[i])); + ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, fields); } FAIL(); } @@ -199,7 +277,7 @@ void expect_eq_buf(const void* s1, const void* s2, size_t n) { template void ValidateRequest(uint32_t message_type, - std::vector& extra_fields, + const std::vector& extra_fields, const F& odk_prepare_func, const G& kdo_parse_func) { uint32_t message_size = 0; uint32_t api_version = 16; @@ -207,9 +285,11 @@ void ValidateRequest(uint32_t message_type, uint32_t session_id = 0xcafebabe; ODK_NonceValues nonce_values{api_version, nonce, session_id}; std::vector total_fields = { - {ODK_UINT32, &message_type}, {ODK_UINT32, &message_size}, - {ODK_UINT32, &api_version}, {ODK_UINT32, &nonce}, - {ODK_UINT32, &session_id}, + {ODK_UINT32, &message_type, "message_type"}, + {ODK_UINT32, &message_size, "message_size"}, + {ODK_UINT32, &api_version, "api_version"}, + {ODK_UINT32, &nonce, "nonce"}, + {ODK_UINT32, &session_id, "session_id"}, }; total_fields.insert(total_fields.end(), extra_fields.begin(), @@ -230,7 +310,7 @@ void ValidateRequest(uint32_t message_type, &bytes_written, total_fields)); EXPECT_EQ(bytes_written, message_size); - expect_eq_buf(buf, buf2, message_size); + EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, buf2, message_size, total_fields)); // odk kdo roundtrip T t = {}; @@ -243,7 +323,7 @@ void ValidateRequest(uint32_t message_type, EXPECT_EQ(OEMCrypto_SUCCESS, odk_prepare_func(buf2, &bytes_written, &nonce_values)); EXPECT_EQ(bytes_written, message_size); - expect_eq_buf(buf, buf2, message_size); + EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, buf2, message_size, total_fields)); delete[] buf; delete[] buf2; @@ -257,16 +337,18 @@ void ValidateRequest(uint32_t message_type, */ template void ValidateResponse(uint32_t message_type, - std::vector& extra_fields, + const std::vector& extra_fields, const F& odk_parse_func, const G& kdo_prepare_func) { uint32_t message_size = 0; uint32_t api_version = 16; uint32_t nonce = 0xdeadbeef; uint32_t session_id = 0xcafebabe; std::vector total_fields = { - {ODK_UINT32, &message_type}, {ODK_UINT32, &message_size}, - {ODK_UINT32, &api_version}, {ODK_UINT32, &nonce}, - {ODK_UINT32, &session_id}, + {ODK_UINT32, &message_type, "message_type"}, + {ODK_UINT32, &message_size, "message_size"}, + {ODK_UINT32, &api_version, "api_version"}, + {ODK_UINT32, &nonce, "nonce"}, + {ODK_UINT32, &session_id, "session_id"}, }; uint32_t header_size = 0; @@ -310,7 +392,8 @@ void ValidateResponse(uint32_t message_type, EXPECT_TRUE(kdo_prepare_func(t, &oemcrypto_core_message)); EXPECT_EQ(bytes_written, message_size); - expect_eq_buf(buf, oemcrypto_core_message.data(), message_size); + EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, oemcrypto_core_message.data(), + message_size, total_fields)); delete[] buf; delete[] zero; } @@ -320,9 +403,10 @@ TEST(OdkTest, SerializeFields) { uint64_t y[] = {3ll << 32, 4ll << 32, 5ll << 32}; OEMCrypto_Substring s = {.offset = 6, .length = 7}; std::vector fields = { - {ODK_UINT32, &x[0]}, {ODK_UINT32, &x[1]}, {ODK_UINT32, &x[2]}, - {ODK_UINT64, &y[0]}, {ODK_UINT64, &y[1]}, {ODK_UINT64, &y[2]}, - {ODK_SUBSTRING, &s}, + {ODK_UINT32, &x[0], "x[0]"}, {ODK_UINT32, &x[1], "x[1]"}, + {ODK_UINT32, &x[2], "x[2]"}, {ODK_UINT64, &y[0], "y[0]"}, + {ODK_UINT64, &y[1], "y[1]"}, {ODK_UINT64, &y[2], "y[2]"}, + {ODK_SUBSTRING, &s, "s"}, }; uint8_t buf[1024] = {0}; uint8_t buf2[1024] = {0}; @@ -331,7 +415,7 @@ TEST(OdkTest, SerializeFields) { ODK_IterFields(ODK_READ, buf, bytes_read, &bytes_written, fields); ODK_IterFields(ODK_WRITE, buf2, SIZE_MAX, &bytes_read, fields); - expect_eq_buf(buf, buf2, bytes_read); + EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, buf2, bytes_read, fields)); } TEST(OdkTest, SerializeFieldsStress) { @@ -342,8 +426,8 @@ TEST(OdkTest, SerializeFieldsStress) { for (int i = 0; i < n; i++) { fields[i].type = static_cast(std::rand() % static_cast(ODK_NUMTYPES)); - size_t field_size = ODK_AllocSize(fields[i].type); fields[i].value = malloc(ODK_AllocSize(fields[i].type)); + fields[i].name = "stress"; total_size += ODK_FieldLength(fields[i].type); } @@ -359,7 +443,7 @@ TEST(OdkTest, SerializeFieldsStress) { ODK_IterFields(ODK_WRITE, buf2, total_size, &bytes_written, fields); EXPECT_EQ(bytes_written, total_size); - expect_eq_buf(buf, buf2, total_size); + EXPECT_NO_FATAL_FAILURE(expect_eq_buf(buf, buf2, total_size, fields)); // cleanup for (int i = 0; i < n; i++) { @@ -375,17 +459,20 @@ TEST(OdkTest, LicenseRequest) { ODK_NonceValues* nonce_values) { return ODK_PrepareCoreLicenseRequest(buf, SIZE_MAX, size, nonce_values); }; - auto kdo_parse_func = ParseLicenseRequest; + auto kdo_parse_func = CoreLicenseRequestFromMessage; ValidateRequest(ODK_License_Request_Type, empty, odk_prepare_func, kdo_parse_func); } TEST(OdkTest, RenewalRequest) { uint64_t system_time_seconds = 0xBADDCAFE000FF1CE; + uint64_t playback_time = 0xCAFE00000000; + uint64_t playback_start = system_time_seconds - playback_time; std::vector extra_fields = { - {ODK_UINT64, &system_time_seconds}, + {ODK_UINT64, &playback_time, "playback_time"}, }; ODK_ClockValues clock_values = {0}; + clock_values.time_of_first_decrypt = playback_start; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, const ODK_NonceValues* nonce_values) { return ODK_PrepareCoreRenewalRequest(buf, SIZE_MAX, size, nonce_values, @@ -393,9 +480,10 @@ TEST(OdkTest, RenewalRequest) { }; auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, ODK_RenewalRequest* core_renewal_request) { - bool ok = ParseRenewalRequest(oemcrypto_core_message, core_renewal_request); + bool ok = CoreRenewalRequestFromMessage(oemcrypto_core_message, + core_renewal_request); if (ok) { - system_time_seconds = core_renewal_request->playback_time; + playback_time = core_renewal_request->playback_time_seconds; } return ok; }; @@ -404,12 +492,12 @@ TEST(OdkTest, RenewalRequest) { } TEST(OdkTest, ProvisionRequest) { - uint32_t device_id_length = DEVICE_ID_MAX / 2; - uint8_t device_id[DEVICE_ID_MAX] = {0}; + 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); std::vector extra_fields = { - {ODK_UINT32, &device_id_length}, - {ODK_DEVICEID, device_id}, + {ODK_UINT32, &device_id_length, "device_id_length"}, + {ODK_DEVICEID, device_id, "device_id"}, }; auto odk_prepare_func = [&](uint8_t* const buf, size_t* size, const ODK_NonceValues* nonce_values) { @@ -419,8 +507,8 @@ TEST(OdkTest, ProvisionRequest) { auto kdo_parse_func = [&](const std::string& oemcrypto_core_message, ODK_ProvisioningRequest* core_provisioning_request) { - bool ok = ParseProvisioningRequest(oemcrypto_core_message, - core_provisioning_request); + bool ok = CoreProvisioningRequestFromMessage(oemcrypto_core_message, + core_provisioning_request); if (ok) { const std::string& device_id_str = core_provisioning_request->device_id; @@ -481,48 +569,57 @@ TEST(OdkTest, LicenseResponse) { }, }; - uint32_t message_type = ODK_License_Response_Type; std::vector extra_fields = { - {ODK_SUBSTRING, &parsed_license.enc_mac_keys_iv}, - {ODK_SUBSTRING, &parsed_license.enc_mac_keys}, - {ODK_SUBSTRING, &parsed_license.pst}, - {ODK_SUBSTRING, &parsed_license.srm_restriction_data}, - {ODK_UINT32, &parsed_license.license_type}, - {ODK_UINT32, &parsed_license.nonce_required}, - {ODK_UINT32, &parsed_license.timer_limits.soft_expiry}, + {ODK_SUBSTRING, &parsed_license.enc_mac_keys_iv, ".enc_mac_keys_iv"}, + {ODK_SUBSTRING, &parsed_license.enc_mac_keys, ".enc_mac_keys"}, + {ODK_SUBSTRING, &parsed_license.pst, ".pst"}, + {ODK_SUBSTRING, &parsed_license.srm_restriction_data, + ".srm_restriction_data"}, + {ODK_UINT32, &parsed_license.license_type, ".license_type"}, + {ODK_UINT32, &parsed_license.nonce_required, ".nonce_required"}, + {ODK_UINT32, &parsed_license.timer_limits.soft_expiry, ".soft_expiry"}, + {ODK_UINT64, &parsed_license.timer_limits.earliest_playback_start_seconds, + ".earliest_playback_start_seconds"}, + {ODK_UINT64, &parsed_license.timer_limits.latest_playback_start_seconds, + ".latest_playback_start_seconds"}, {ODK_UINT64, - &parsed_license.timer_limits.earliest_playback_start_seconds}, - {ODK_UINT64, &parsed_license.timer_limits.latest_playback_start_seconds}, + &parsed_license.timer_limits.initial_playback_duration_seconds, + ".initial_playback_duration_seconds"}, {ODK_UINT64, - &parsed_license.timer_limits.initial_playback_duration_seconds}, - {ODK_UINT64, - &parsed_license.timer_limits.renewal_playback_duration_seconds}, - {ODK_UINT64, &parsed_license.timer_limits.license_duration_seconds}, - {ODK_HASH, &parsed_license.request_hash}, - {ODK_UINT32, &parsed_license.key_array_length}, - {ODK_SUBSTRING, &parsed_license.key_array[0].key_id}, - {ODK_SUBSTRING, &parsed_license.key_array[0].key_data_iv}, - {ODK_SUBSTRING, &parsed_license.key_array[0].key_data}, - {ODK_SUBSTRING, &parsed_license.key_array[0].key_control_iv}, - {ODK_SUBSTRING, &parsed_license.key_array[0].key_control}, - {ODK_SUBSTRING, &parsed_license.key_array[1].key_id}, - {ODK_SUBSTRING, &parsed_license.key_array[1].key_data_iv}, - {ODK_SUBSTRING, &parsed_license.key_array[1].key_data}, - {ODK_SUBSTRING, &parsed_license.key_array[1].key_control_iv}, - {ODK_SUBSTRING, &parsed_license.key_array[1].key_control}, - {ODK_SUBSTRING, &parsed_license.key_array[2].key_id}, - {ODK_SUBSTRING, &parsed_license.key_array[2].key_data_iv}, - {ODK_SUBSTRING, &parsed_license.key_array[2].key_data}, - {ODK_SUBSTRING, &parsed_license.key_array[2].key_control_iv}, - {ODK_SUBSTRING, &parsed_license.key_array[2].key_control}, + &parsed_license.timer_limits.renewal_playback_duration_seconds, + ".renewal_playback_duration_seconds"}, + {ODK_UINT64, &parsed_license.timer_limits.license_duration_seconds, + ".license_duration_seconds"}, + {ODK_HASH, &parsed_license.request_hash, ".request_hash"}, + {ODK_UINT32, &parsed_license.key_array_length, ".key_array_length"}, + {ODK_SUBSTRING, &parsed_license.key_array[0].key_id, ".key_id"}, + {ODK_SUBSTRING, &parsed_license.key_array[0].key_data_iv, ".key_data_iv"}, + {ODK_SUBSTRING, &parsed_license.key_array[0].key_data, ".key_data"}, + {ODK_SUBSTRING, &parsed_license.key_array[0].key_control_iv, + ".key_control_iv"}, + {ODK_SUBSTRING, &parsed_license.key_array[0].key_control, ".key_control"}, + {ODK_SUBSTRING, &parsed_license.key_array[1].key_id, ".key_id"}, + {ODK_SUBSTRING, &parsed_license.key_array[1].key_data_iv, ".key_data_iv"}, + {ODK_SUBSTRING, &parsed_license.key_array[1].key_data, ".key_data"}, + {ODK_SUBSTRING, &parsed_license.key_array[1].key_control_iv, + ".key_control_iv"}, + {ODK_SUBSTRING, &parsed_license.key_array[1].key_control, ".key_control"}, + {ODK_SUBSTRING, &parsed_license.key_array[2].key_id, ".key_id"}, + {ODK_SUBSTRING, &parsed_license.key_array[2].key_data_iv, ".key_data_iv"}, + {ODK_SUBSTRING, &parsed_license.key_array[2].key_data, ".key_data"}, + {ODK_SUBSTRING, &parsed_license.key_array[2].key_control_iv, + ".key_control_iv"}, + {ODK_SUBSTRING, &parsed_license.key_array[2].key_control, ".key_control"}, }; uint8_t request_hash[ODK_SHA256_HASH_SIZE] = {}; memcpy(request_hash, parsed_license.request_hash, ODK_SHA256_HASH_SIZE); auto odk_parse_func = [&](const uint8_t* buf, size_t size, ODK_NonceValues* nonce_values) { - return ODK_ParseLicense(buf, size + 128, size, 1, 0, request_hash, nullptr, - nullptr, nonce_values, &parsed_license); + ODK_TimerLimits timer_limits; + return ODK_ParseLicense(buf, size + 128, size, true, false, request_hash, + &timer_limits, nullptr, nonce_values, + &parsed_license); }; auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request, std::string* oemcrypto_core_message) { @@ -539,7 +636,7 @@ TEST(OdkTest, RenewalResponse) { uint64_t playback_timer = 12; uint64_t message_playback_clock = 10; std::vector extra_fields = { - {ODK_UINT64, &message_playback_clock}, + {ODK_UINT64, &message_playback_clock, "message_playback_clock"}, }; ODK_TimerLimits timer_limits = { @@ -555,6 +652,7 @@ TEST(OdkTest, RenewalResponse) { .time_of_license_signed = 0, .time_of_first_decrypt = system_time - playback_clock, .time_of_last_decrypt = 0, + .time_of_renewal_request = message_playback_clock, .time_when_timer_expires = system_time + playback_timer, .timer_status = 0, .status = kUnused, @@ -578,7 +676,7 @@ TEST(OdkTest, RenewalResponse) { }; auto kdo_prepare_func = [&](ODK_RenewalRequest& core_request, std::string* oemcrypto_core_message) { - core_request.playback_time = message_playback_clock; + core_request.playback_time_seconds = message_playback_clock; return CreateCoreRenewalResponse(core_request, oemcrypto_core_message); }; ValidateResponse(ODK_Renewal_Response_Type, extra_fields, @@ -586,8 +684,8 @@ TEST(OdkTest, RenewalResponse) { } TEST(OdkTest, ProvisionResponse) { - uint32_t device_id_length = DEVICE_ID_MAX / 2; - uint8_t device_id[DEVICE_ID_MAX] = {0}; + 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); ODK_ParsedProvisioning parsed_response = { @@ -597,18 +695,20 @@ TEST(OdkTest, ProvisionResponse) { }; std::vector extra_fields = { - {ODK_UINT32, &device_id_length}, - {ODK_DEVICEID, device_id}, - {ODK_UINT32, &parsed_response.key_type}, - {ODK_SUBSTRING, &parsed_response.enc_private_key}, - {ODK_SUBSTRING, &parsed_response.enc_private_key_iv}, - {ODK_SUBSTRING, &parsed_response.encrypted_message_key}, + {ODK_UINT32, &device_id_length, "device_id_length"}, + {ODK_DEVICEID, device_id, "device_id"}, + {ODK_UINT32, &parsed_response.key_type, "key_type"}, + {ODK_SUBSTRING, &parsed_response.enc_private_key, "enc_private_key"}, + {ODK_SUBSTRING, &parsed_response.enc_private_key_iv, + "enc_private_key_iv"}, + {ODK_SUBSTRING, &parsed_response.encrypted_message_key, + "encrypted_message_key"}, }; auto odk_parse_func = [&](const uint8_t* buf, size_t size, ODK_NonceValues* nonce_values) { // restore device id because it is not part of parsed_response - device_id_length = DEVICE_ID_MAX / 2; + device_id_length = ODK_DEVICE_ID_LEN_MAX / 2; memset(device_id, 0xff, device_id_length); OEMCryptoResult err = ODK_ParseProvisioning(buf, size + 16, size, nonce_values, device_id, @@ -670,7 +770,6 @@ TEST(OdkSizeTest, ProvisioningRequest) { uint32_t api_version = 0; uint32_t nonce = 0; uint32_t session_id = 0; - uint8_t* device_id = nullptr; uint32_t device_id_length = 0; ODK_NonceValues nonce_values{api_version, nonce, session_id}; EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, @@ -681,3 +780,5 @@ TEST(OdkSizeTest, ProvisioningRequest) { size_t minimum_message_size = 5 * 4; EXPECT_GE(core_message_length, minimum_message_size); } + +} // namespace diff --git a/oemcrypto/odk/test/odk_test.gypi b/oemcrypto/odk/test/odk_test.gypi index 54035bb..80ed8b7 100644 --- a/oemcrypto/odk/test/odk_test.gypi +++ b/oemcrypto/odk/test/odk_test.gypi @@ -1,4 +1,4 @@ -# Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +# Copyright 2019 Google LLC. All rights reserved. This file and proprietary # source code may only be used and distributed under the Widevine Master License # Agreement. diff --git a/oemcrypto/odk/test/odk_test.h b/oemcrypto/odk/test/odk_test.h deleted file mode 100644 index a8114a1..0000000 --- a/oemcrypto/odk/test/odk_test.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary - * source code may only be used and distributed under the Widevine Master - * License Agreement. - */ - -#ifndef ODK_TEST_H_ -#define ODK_TEST_H_ - -#include "OEMCryptoCENCCommon.h" - -typedef enum { - ODK_License_Request_Type = 1, - ODK_License_Response_Type = 2, - ODK_Renewal_Request_Type = 3, - ODK_Renewal_Response_Type = 4, - ODK_Provisioning_Request_Type = 5, - ODK_Provisioning_Response_Type = 6, -} ODK_MessageType; - -typedef enum { - ODK_UINT32, - ODK_UINT64, - ODK_SUBSTRING, - ODK_DEVICEID, - ODK_HASH, - ODK_NUMTYPES, -} ODK_FieldType; - -typedef enum { - ODK_READ, - ODK_WRITE, -} ODK_FieldMode; - -typedef struct { - ODK_FieldType type; - void* value; -} ODK_Field; - -#define DEVICE_ID_MAX (64) - -#ifdef __cplusplus -extern "C" { -#endif - -size_t ODK_FieldLength(ODK_FieldType type); -OEMCryptoResult ODK_WriteSingleField(uint8_t* const buf, - const ODK_Field* const field); -OEMCryptoResult ODK_ReadSingleField(const uint8_t* const buf, - const ODK_Field* const field); - -OEMCryptoResult ODK_ReadFields(const uint8_t* const buf, const size_t size_in, - size_t* size_out, const size_t n, - const ODK_Field* const fields); - -OEMCryptoResult ODK_WriteFields(uint8_t* const buf, const size_t size_in, - size_t* size_out, const size_t n, - const ODK_Field* const fields); - -#ifdef __cplusplus -} -#endif - -#endif // ODK_TEST_H_ diff --git a/oemcrypto/odk/test/odk_timer_test.cpp b/oemcrypto/odk/test/odk_timer_test.cpp index e941cf6..9259220 100644 --- a/oemcrypto/odk/test/odk_timer_test.cpp +++ b/oemcrypto/odk/test/odk_timer_test.cpp @@ -1,22 +1,18 @@ -/* - * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary * source code may only be used and distributed under the Widevine Master * License Agreement. */ -#include - +#include "OEMCryptoCENCCommon.h" +#include "gtest/gtest.h" #include "odk.h" -using ::testing::tuple; using ::testing::Values; using ::testing::WithParamInterface; namespace { constexpr uint64_t kTolerance = 1; // Allow 1 second of roundoff. -} // namespace -namespace odk_test { struct ServerExpiry { bool soft_rental; bool soft_playback; @@ -391,8 +387,6 @@ TEST_F(OdkTimerSoftTest, EarlyTest) { // Starting playback within the window should work. const uint64_t start_time = system_time(timer_limits_.earliest_playback_start_seconds); - const uint64_t cutoff_time = - system_time(timer_limits_.license_duration_seconds); // For a soft_expiry = true, we should not set a timer. EXPECT_EQ(ODK_DISABLE_TIMER, ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_, @@ -550,7 +544,7 @@ TEST_F(OdkTimerSoftTest, ReloadLate) { // OEMCrypto's point of view, there is only playback duration. A soft or hard // rental duration is translated into different rental and license durations. // The four test classes below all have a 700 rental window and a 200 playback -// duration. We'll use the server descritpion, and then set the OEMCrypto +// duration. We'll use the server description, and then set the OEMCrypto // restraints in the test SetUp() function. Note, it's easier to use the word // "day" but really the rental window is 700 seconds, not 7 days. These tests // have some coverage overlap with the ones above, but it is better to have @@ -863,7 +857,6 @@ TEST_P(Odk7DayTest, StartDay6ReloadDay7) { uint64_t timer_value = 0; // Starting playback within the window should work. const uint64_t six_days = 600u; - const uint64_t seven_days = 700u; const uint64_t start_time = system_time(rental_window_start_ + six_days); EXPECT_NE(ODK_TIMER_EXPIRED, ODK_AttemptFirstPlayback(start_time, &timer_limits_, &clock_values_, @@ -924,13 +917,4 @@ INSTANTIATE_TEST_CASE_P(OdkSoftHard, Odk7DayTest, ServerExpiry({false, true}), ServerExpiry({false, false}))); -// ************************************************************************ - -// ************************************************************************ -// TODO(b/140765031): Cover all tests in Use Cases document. -// Limited Duration License -// 7 day with renewal. -// Streaming with renewal -// Persistent with renewal - -} // namespace odk_test +} // namespace diff --git a/oemcrypto/oemcrypto_unittests.gyp b/oemcrypto/oemcrypto_unittests.gyp index d62921a..0ef948e 100644 --- a/oemcrypto/oemcrypto_unittests.gyp +++ b/oemcrypto/oemcrypto_unittests.gyp @@ -19,7 +19,8 @@ 'type': 'executable', 'sources': [ 'test/oemcrypto_test_main.cpp', - 'odk/kdo/src/oec_util.cpp', + 'odk/src/core_message_deserialize.cpp', + 'odk/src/core_message_serialize.cpp', '<(platform_specific_dir)/file_store.cpp', '<(platform_specific_dir)/log.cpp', '<(util_dir)/src/platform.cpp', diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp index 61bdeb0..b313fb4 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp @@ -226,7 +226,7 @@ OEMCryptoResult CryptoEngine::SetDestination( default: return OEMCrypto_ERROR_INVALID_CONTEXT; } - size_t max_allowed = max_sample_size(); + const size_t max_allowed = max_sample_size(); if (max_allowed > 0 && (max_allowed < max_length || max_allowed < data_length)) { LOGE("Output too large (or buffer too small)."); diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.h b/oemcrypto/ref/src/oemcrypto_engine_ref.h index e447ebf..d111b73 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -32,6 +32,7 @@ typedef std::map ActiveSessions; class CryptoEngine { public: static const uint32_t kApiVersion = 16; + static const uint32_t kMinorApiVersion = 0; // This is like a factory method, except we choose which version to use at // compile time. It is defined in several source files. The build system diff --git a/oemcrypto/ref/src/oemcrypto_ref.cpp b/oemcrypto/ref/src/oemcrypto_ref.cpp index 57be77b..05e6f26 100644 --- a/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -52,41 +52,6 @@ uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) { return value; } -void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { - switch (dest_buffer->type) { - case OEMCrypto_BufferType_Clear: - dest_buffer->buffer.clear.address += bytes; - dest_buffer->buffer.clear.address_length -= bytes; - break; - - case OEMCrypto_BufferType_Secure: - dest_buffer->buffer.secure.offset += bytes; - break; - - case OEMCrypto_BufferType_Direct: - // Nothing to do for this buffer type. - break; - } -} - -// Advance an IV according to ISO-CENC's CTR modes. The lower half of the IV is -// split off and treated as an unsigned 64-bit integer, then incremented by the -// number of complete crypto blocks decrypted. The resulting value is then -// copied back into the IV over the previous lower half. -void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) { - uint64_t counter; - assert(sizeof(*subsample_iv) == wvoec::KEY_IV_SIZE); - assert(sizeof(counter) * 2 == sizeof(*subsample_iv)); - static const size_t half_iv_size = wvoec::KEY_IV_SIZE / 2; - memcpy(&counter, &(*subsample_iv)[half_iv_size], half_iv_size); - - size_t increment = - bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional - counter = wvcdm::htonll64(wvcdm::ntohll64(counter) + increment); - - memcpy(&(*subsample_iv)[half_iv_size], &counter, half_iv_size); -} - } // namespace namespace wvoec_ref { @@ -637,6 +602,13 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( return OEMCrypto_ERROR_INVALID_SESSION; } +#ifndef NDEBUG + if (!crypto_engine->ValidRootOfTrust()) { + LOGE("[OEMCrypto_DecryptCENC(): ERROR_KEYBOX_INVALID]"); + return OEMCrypto_ERROR_KEYBOX_INVALID; + } +#endif + // Iterate through all the samples and validate them before doing any decrypt for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { const OEMCrypto_SampleDescription& sample = samples[sample_index]; @@ -679,65 +651,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( } } - // Iterate through all the samples and decrypt each one - for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { - const OEMCrypto_SampleDescription& sample = samples[sample_index]; - - // Iterate through all the subsamples and decrypt each one - const uint8_t* subsample_source = sample.buffers.input_data; - OEMCrypto_DestBufferDesc subsample_dest = sample.buffers.output_descriptor; - uint8_t subsample_iv[wvoec::KEY_IV_SIZE]; - assert(sizeof(sample.iv) == wvoec::KEY_IV_SIZE); - assert(sizeof(subsample_iv) == wvoec::KEY_IV_SIZE); - memcpy(&subsample_iv[0], &sample.iv[0], wvoec::KEY_IV_SIZE); - for (size_t subsample_index = 0; subsample_index < sample.subsamples_length; - ++subsample_index) { - const OEMCrypto_SubSampleDescription& subsample = - sample.subsamples[subsample_index]; - const size_t subsample_length = - subsample.num_bytes_clear + subsample.num_bytes_encrypted; - - OEMCryptoResult result = crypto_engine->SetDestination( - subsample_dest, subsample_length, subsample.subsample_flags); - if (result != OEMCrypto_SUCCESS) { - LOGE("[OEMCrypto_DecryptCENC(): SetDestination status: %d]", result); - return result; - } - -#ifndef NDEBUG - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_DecryptCENC(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } -#endif - - result = session_ctx->DecryptSubsample( - subsample, subsample_source, crypto_engine->destination(), - subsample_dest.type, subsample_iv, pattern); - if (result != OEMCrypto_SUCCESS) { - LOGE("[OEMCrypto_DecryptCENC(): DecryptSubsample status: %d]", result); - return result; - } - - result = crypto_engine->PushDestination(subsample_dest, - subsample.subsample_flags); - if (result != OEMCrypto_SUCCESS) { - LOGE("[OEMCrypto_DecryptCENC(): PushDestination status: %d]", result); - return result; - } - - // Advance the source buffer, the dest buffer, and (if necessary) the IV - subsample_source += subsample_length; - advance_dest_buffer(&subsample_dest, subsample_length); - if (subsample.num_bytes_encrypted > 0 && - session_ctx->current_content_key()->ctr_mode()) { - advance_iv_ctr(&subsample_iv, - subsample.block_offset + subsample.num_bytes_encrypted); - } - } // Subsample loop - } // Sample loop - - return OEMCrypto_SUCCESS; + return session_ctx->DecryptSamples(samples, samples_length, pattern); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer( @@ -752,8 +666,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_CopyBuffer( LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } - if (crypto_engine->max_sample_size() > 0 && - data_length > crypto_engine->max_sample_size()) { + if (crypto_engine->max_subsample_size() > 0 && + data_length > crypto_engine->max_subsample_size()) { // For testing reasons only, pretend that this integration only supports // the minimum possible buffer size. LOGE("[OEMCrypto_CopyBuffer(): OEMCrypto_ERROR_BUFFER_TOO_LARGE]"); @@ -1415,6 +1329,10 @@ OEMCRYPTO_API uint32_t OEMCrypto_APIVersion() { return CryptoEngine::kApiVersion; } +OEMCRYPTO_API uint32_t OEMCrypto_MinorAPIVersion() { + return CryptoEngine::kMinorApiVersion; +} + OEMCRYPTO_API uint8_t OEMCrypto_Security_Patch_Level() { uint8_t security_patch_level = crypto_engine->config_security_patch_level(); return security_patch_level; @@ -1468,12 +1386,11 @@ OEMCRYPTO_API bool OEMCrypto_SupportsUsageTable() { } OEMCRYPTO_API size_t OEMCrypto_MaximumUsageTableHeaderSize() { - // TOOD(b/140080305): fill in a real value. if (crypto_engine == nullptr) { LOGE("OEMCrypto_MaximumUsageTableHeaderSize: OEMCrypto Not Initialized."); return 0; } - return 200; + return crypto_engine->max_usage_table_size(); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(size_t* count) { diff --git a/oemcrypto/ref/src/oemcrypto_session.cpp b/oemcrypto/ref/src/oemcrypto_session.cpp index 025f7dd..ece666b 100644 --- a/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/oemcrypto/ref/src/oemcrypto_session.cpp @@ -47,6 +47,43 @@ void ctr128_inc64(uint8_t* counter) { if (++counter[--n] != 0) return; } while (n > 8); } + +void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { + switch (dest_buffer->type) { + case OEMCrypto_BufferType_Clear: + dest_buffer->buffer.clear.address += bytes; + dest_buffer->buffer.clear.address_length -= bytes; + break; + + case OEMCrypto_BufferType_Secure: + dest_buffer->buffer.secure.offset += bytes; + break; + + case OEMCrypto_BufferType_Direct: + // Nothing to do for this buffer type. + break; + } +} + +// Advance an IV according to ISO-CENC's CTR modes. The lower half of the IV is +// split off and treated as an unsigned 64-bit integer, then incremented by the +// number of complete crypto blocks decrypted. The resulting value is then +// copied back into the IV over the previous lower half. +void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) { + uint64_t counter; + // Per its type, sizeof(*subsample_iv) == wvoec::KEY_IV_SIZE + static_assert(sizeof(counter) * 2 == wvoec::KEY_IV_SIZE, + "A uint64_t failed to be half the size of an AES-128 IV."); + constexpr size_t half_iv_size = wvoec::KEY_IV_SIZE / 2; + memcpy(&counter, &(*subsample_iv)[half_iv_size], half_iv_size); + + const size_t increment = + bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional + counter = wvcdm::htonll64(wvcdm::ntohll64(counter) + increment); + + memcpy(&(*subsample_iv)[half_iv_size], &counter, half_iv_size); +} + } // namespace namespace wvoec_ref { @@ -366,7 +403,7 @@ OEMCryptoResult SessionContext::PrepAndSignRenewalRequest( } // If we have signed a request, but have not loaded it, something is wrong. // On the other hand, we can sign a license release using the mac keys from - // the usage table. + // the usage table. So it is OK if we have never signed a license request. if (state_request_signed_ && !state_response_loaded_) { LOGE("Attempt to sign renewal before load"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -1418,7 +1455,9 @@ OEMCryptoResult SessionContext::LoadUsageEntry( } const OEMCryptoResult result = ce_->usage_table().LoadUsageEntry( this, &usage_entry_, index, buffer, &clock_values_); - if (result != OEMCrypto_SUCCESS) return result; + if ((result != OEMCrypto_SUCCESS) && + (result != OEMCrypto_WARNING_GENERATION_SKEW)) + return result; if (!usage_entry_) return OEMCrypto_ERROR_UNKNOWN_FAILURE; usage_entry_status_ = kUsageEntryLoaded; @@ -1429,7 +1468,7 @@ OEMCryptoResult SessionContext::LoadUsageEntry( mac_key_client_ = std::vector( usage_entry_->mac_key_client(), usage_entry_->mac_key_client() + wvoec::MAC_KEY_SIZE); - return OEMCrypto_SUCCESS; + return result; } OEMCryptoResult SessionContext::UpdateUsageEntry(uint8_t* header_buffer, @@ -1484,10 +1523,68 @@ bool SessionContext::DecryptMessage(const std::vector& key, return true; } +OEMCryptoResult SessionContext::DecryptSamples( + const OEMCrypto_SampleDescription* samples, size_t samples_length, + const OEMCrypto_CENCEncryptPatternDesc* pattern) { + // Iterate through all the samples and decrypt each one + for (size_t sample_index = 0; sample_index < samples_length; ++sample_index) { + const OEMCrypto_SampleDescription& sample = samples[sample_index]; + + // Iterate through all the subsamples and decrypt each one. A production + // implementation may be able to do something more efficient, like + // decrypting all the encrypted portions in one pass. + const uint8_t* subsample_source = sample.buffers.input_data; + OEMCrypto_DestBufferDesc subsample_dest = sample.buffers.output_descriptor; + uint8_t subsample_iv[wvoec::KEY_IV_SIZE]; + static_assert(sizeof(sample.iv) == wvoec::KEY_IV_SIZE, + "The IV in OEMCrypto_SampleDescription is the wrong length."); + // Per its type, sizeof(subsample_iv) == wvoec::KEY_IV_SIZE + memcpy(subsample_iv, sample.iv, wvoec::KEY_IV_SIZE); + for (size_t subsample_index = 0; subsample_index < sample.subsamples_length; + ++subsample_index) { + const OEMCrypto_SubSampleDescription& subsample = + sample.subsamples[subsample_index]; + const size_t subsample_length = + subsample.num_bytes_clear + subsample.num_bytes_encrypted; + + OEMCryptoResult result = ce_->SetDestination( + subsample_dest, subsample_length, subsample.subsample_flags); + if (result != OEMCrypto_SUCCESS) { + LOGE("SetDestination status: %d", result); + return result; + } + + result = DecryptSubsample(subsample, subsample_source, ce_->destination(), + subsample_dest.type, subsample_iv, pattern); + if (result != OEMCrypto_SUCCESS) { + LOGE("DecryptSubsample status: %d", result); + return result; + } + + result = ce_->PushDestination(subsample_dest, subsample.subsample_flags); + if (result != OEMCrypto_SUCCESS) { + LOGE("PushDestination status: %d", result); + return result; + } + + // Advance the source buffer, the dest buffer, and (if necessary) the IV + subsample_source += subsample_length; + advance_dest_buffer(&subsample_dest, subsample_length); + if (subsample.num_bytes_encrypted > 0 && + current_content_key()->ctr_mode()) { + advance_iv_ctr(&subsample_iv, + subsample.block_offset + subsample.num_bytes_encrypted); + } + } // Subsample loop + } // Sample loop + + return OEMCrypto_SUCCESS; +} + OEMCryptoResult SessionContext::DecryptSubsample( const OEMCrypto_SubSampleDescription& subsample, const uint8_t* cipher_data, uint8_t* clear_data, OEMCryptoBufferType buffer_type, - const uint8_t iv[wvoec::KEY_IV_SIZE], + const uint8_t (&iv)[wvoec::KEY_IV_SIZE], const OEMCrypto_CENCEncryptPatternDesc* pattern) { // Handle the clear portion of the subsample. if (subsample.num_bytes_clear > 0) { @@ -1602,14 +1699,16 @@ OEMCryptoResult SessionContext::PatternDecryptCBC( size_t l = 0; size_t pattern_offset = 0; while (l < cipher_data_length) { - size_t size = + const size_t size = std::min(cipher_data_length - l, static_cast(AES_BLOCK_SIZE)); - bool skip_block = (pattern_offset >= pattern->encrypt); + const bool skip_block = (pattern_offset >= pattern->encrypt); pattern_offset = (pattern_offset + 1) % pattern_length; - // TODO(b/140503351): The (size < AES_BLOCK_SIZE) check is not correct for - // patterns where (pattern.encrypt > 1). if (skip_block || (size < AES_BLOCK_SIZE)) { - memmove(&clear_data[l], &cipher_data[l], size); + // If we are decrypting in-place, then this byte is already correct and + // can be skipped. + if (clear_data != cipher_data) { + memcpy(&clear_data[l], &cipher_data[l], size); + } } else { uint8_t aes_output[AES_BLOCK_SIZE]; // Save the iv for the next block, in case cipher_data is in the same diff --git a/oemcrypto/ref/src/oemcrypto_session.h b/oemcrypto/ref/src/oemcrypto_session.h index 34ad0f6..f092d63 100644 --- a/oemcrypto/ref/src/oemcrypto_session.h +++ b/oemcrypto/ref/src/oemcrypto_session.h @@ -96,10 +96,8 @@ class SessionContext { virtual bool ValidateMessage(const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length); - OEMCryptoResult DecryptSubsample( - const OEMCrypto_SubSampleDescription& subsample, - const uint8_t* cipher_data, uint8_t* clear_data, - OEMCryptoBufferType buffer_type, const uint8_t iv[wvoec::KEY_IV_SIZE], + OEMCryptoResult DecryptSamples( + const OEMCrypto_SampleDescription* samples, size_t samples_length, const OEMCrypto_CENCEncryptPatternDesc* pattern); OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer, @@ -236,6 +234,12 @@ class SessionContext { OEMCryptoResult CheckStatusOnline(uint32_t nonce, uint32_t control); // Check that the usage entry status is valid for offline use. OEMCryptoResult CheckStatusOffline(uint32_t nonce, uint32_t control); + + OEMCryptoResult DecryptSubsample( + const OEMCrypto_SubSampleDescription& subsample, + const uint8_t* cipher_data, uint8_t* clear_data, + OEMCryptoBufferType buffer_type, const uint8_t (&iv)[wvoec::KEY_IV_SIZE], + const OEMCrypto_CENCEncryptPatternDesc* pattern); OEMCryptoResult ChooseDecrypt(const uint8_t* iv, size_t block_offset, const OEMCrypto_CENCEncryptPatternDesc* pattern, const uint8_t* cipher_data, diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/oemcrypto/test/oec_decrypt_fallback_chain.cpp index 85c437e..e8d8247 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -34,7 +34,7 @@ void advance_iv_ctr(uint8_t (*subsample_iv)[wvoec::KEY_IV_SIZE], size_t bytes) { constexpr size_t half_iv_size = wvoec::KEY_IV_SIZE / 2; memcpy(&counter, &(*subsample_iv)[half_iv_size], half_iv_size); - size_t increment = + const size_t increment = bytes / wvoec::AES_128_BLOCK_SIZE; // The truncation here is intentional counter = wvcdm::htonll64(wvcdm::ntohll64(counter) + increment); @@ -82,7 +82,8 @@ OEMCryptoResult DecryptFallbackChain::DecryptSample( for (size_t i = 0; i < sample.subsamples_length; ++i) { const OEMCrypto_SubSampleDescription& subsample = sample.subsamples[i]; - size_t length = subsample.num_bytes_clear + subsample.num_bytes_encrypted; + const size_t length = + subsample.num_bytes_clear + subsample.num_bytes_encrypted; fake_sample.buffers.input_data_length = length; fake_sample.subsamples = &subsample; fake_sample.subsamples_length = 1; diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 376cdea..4e2ec1b 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -26,11 +26,12 @@ #include "OEMCryptoCENC.h" #include "clock.h" +#include "core_message_deserialize.h" +#include "core_message_serialize.h" #include "disallow_copy_and_assign.h" #include "log.h" #include "oec_device_features.h" #include "oec_test_data.h" -#include "oec_util.h" #include "oemcrypto_types.h" #include "platform.h" #include "string_conversions.h" @@ -67,20 +68,20 @@ int GetRandBytes(unsigned char* buf, int num) { // is a common operation for tests. Generates a random IV which can be used to // encrypt the input buffer. void GenerateSimpleSampleDescription( - const uint8_t* input_data, size_t input_data_length, uint8_t* output_buffer, - size_t output_buffer_length, OEMCrypto_SampleDescription* sample, + const std::vector& in, std::vector& out, + OEMCrypto_SampleDescription* sample, OEMCrypto_SubSampleDescription* subsample) { - ASSERT_NE(nullptr, sample); - ASSERT_NE(nullptr, subsample); + ASSERT_NE(sample, nullptr); + ASSERT_NE(subsample, nullptr); // Generate test data - EXPECT_EQ(1, GetRandBytes(&sample->iv[0], KEY_IV_SIZE)); + EXPECT_EQ(GetRandBytes(&sample->iv[0], KEY_IV_SIZE), 1); // Describe the test data - sample->buffers.input_data = input_data; - sample->buffers.input_data_length = input_data_length; + sample->buffers.input_data = in.data(); + sample->buffers.input_data_length = in.size(); subsample->num_bytes_clear = 0; - subsample->num_bytes_encrypted = input_data_length; + subsample->num_bytes_encrypted = sample->buffers.input_data_length; subsample->subsample_flags = OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample; subsample->block_offset = 0; @@ -91,8 +92,8 @@ void GenerateSimpleSampleDescription( OEMCrypto_DestBufferDesc& out_buffer_descriptor = sample->buffers.output_descriptor; out_buffer_descriptor.type = OEMCrypto_BufferType_Clear; - out_buffer_descriptor.buffer.clear.address = output_buffer; - out_buffer_descriptor.buffer.clear.address_length = output_buffer_length; + out_buffer_descriptor.buffer.clear.address = out.data(); + out_buffer_descriptor.buffer.clear.address_length = out.size(); } // Increment counter for AES-CTR. The CENC spec specifies we increment only @@ -244,7 +245,8 @@ void ProvisioningRoundTrip::VerifyRequestSignature( void ProvisioningRoundTrip::FillAndVerifyCoreRequest( const std::string& core_message_string) { EXPECT_TRUE( - oec_util::ParseProvisioningRequest(core_message_string, &core_request_)); + oemcrypto_core_message::deserialize::CoreProvisioningRequestFromMessage( + core_message_string, &core_request_)); EXPECT_EQ(global_features.api_version, core_request_.api_version); EXPECT_EQ(session()->nonce(), core_request_.nonce); EXPECT_EQ(session()->session_id(), core_request_.session_id); @@ -294,8 +296,8 @@ void ProvisioningRoundTrip::EncryptAndSignResponse() { &encrypted_response_data_); core_response_.enc_private_key.length = encrypted_response_data_.rsa_key_length; - ASSERT_TRUE(CreateCoreProvisioningResponse(core_response_, core_request_, - &serialized_core_message_)); + ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreProvisioningResponse( + core_response_, core_request_, &serialized_core_message_)); // Stripe the encrypted message. encrypted_response_.resize(message_size_); for (size_t i = 0; i < encrypted_response_.size(); i++) { @@ -318,6 +320,7 @@ void ProvisioningRoundTrip::EncryptAndSignResponse() { } OEMCryptoResult ProvisioningRoundTrip::LoadResponse(Session* session) { + EXPECT_NE(session, nullptr); size_t wrapped_key_length = 0; const OEMCryptoResult sts = OEMCrypto_LoadProvisioning( session->session_id(), encrypted_response_.data(), @@ -352,7 +355,8 @@ void LicenseRoundTrip::VerifyRequestSignature( void LicenseRoundTrip::FillAndVerifyCoreRequest( const std::string& core_message_string) { EXPECT_TRUE( - oec_util::ParseLicenseRequest(core_message_string, &core_request_)); + oemcrypto_core_message::deserialize::CoreLicenseRequestFromMessage( + core_message_string, &core_request_)); EXPECT_EQ(global_features.api_version, core_request_.api_version); if (expect_request_has_correct_nonce_) { EXPECT_EQ(session()->nonce(), core_request_.nonce); @@ -489,8 +493,8 @@ void LicenseRoundTrip::EncryptAndSignResponse() { if (api_version_ < kCoreMessagesAPI) { serialized_core_message_.resize(0); } else { - ASSERT_TRUE(CreateCoreLicenseResponse(core_response_, core_request_, - &serialized_core_message_)); + ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreLicenseResponse( + core_response_, core_request_, &serialized_core_message_)); } // Stripe the encrypted message. @@ -516,6 +520,7 @@ void LicenseRoundTrip::EncryptAndSignResponse() { } OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session) { + EXPECT_NE(session, nullptr); // Some tests adjust the offset to be beyond the length of the message. Here, // we create a duplicate of the message buffer so that these offsets do not // point to garbage data. The goal is to make sure OEMCrypto is verifying that @@ -747,14 +752,16 @@ void RenewalRoundTrip::FillAndVerifyCoreRequest( if (license_messages_->api_version() < kCoreMessagesAPI) { // For v15, we expect that no core request was created. EXPECT_FALSE( - oec_util::ParseRenewalRequest(core_message_string, &core_request_)); + oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage( + core_message_string, &core_request_)); } else { EXPECT_TRUE( - oec_util::ParseRenewalRequest(core_message_string, &core_request_)); + oemcrypto_core_message::deserialize::CoreRenewalRequestFromMessage( + core_message_string, &core_request_)); EXPECT_EQ(license_messages_->core_request().api_version, core_request_.api_version); if (!is_release_) { - // For a license release, we don not expect the nonce to be correct. That + // For a license release, we do not expect the nonce to be correct. That // is because a release might be sent without loading the license first. EXPECT_EQ(license_messages_->core_request().nonce, core_request_.nonce); EXPECT_EQ(license_messages_->core_request().session_id, @@ -810,8 +817,8 @@ void RenewalRoundTrip::EncryptAndSignResponse() { sizeof(response_data_.keys[0].control)); serialized_core_message_.resize(0); } else { - ASSERT_TRUE( - CreateCoreRenewalResponse(core_request_, &serialized_core_message_)); + ASSERT_TRUE(oemcrypto_core_message::serialize::CreateCoreRenewalResponse( + core_request_, &serialized_core_message_)); } // Concatenate the core message and the response. ASSERT_GE(kMaxCoreMessage, serialized_core_message_.size()); @@ -847,12 +854,7 @@ Session::Session() forced_session_id_(false), session_id_(0), nonce_(0), - public_rsa_(0), - message_size_(sizeof(MessageData)), - // Most tests only use 4 keys. Other tests will explicitly call - // set_num_keys. - num_keys_(4) { -} + public_rsa_(0) {} Session::~Session() { if (!forced_session_id_ && open_) close(); @@ -953,524 +955,6 @@ void Session::GenerateDerivedKeysFromSessionKey() { key_deriver_.DeriveKeys(session_key.data(), mac_context, enc_context); } -void Session::LoadTestKeys(const std::string& provider_session_token, - bool new_mac_keys) { - std::string message = - wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); - OEMCrypto_Substring pst = GetSubstring(message, provider_session_token); - OEMCrypto_Substring enc_mac_keys_iv = GetSubstring( - message, wvcdm::BytesToString(encrypted_license().mac_key_iv, - sizeof(encrypted_license().mac_key_iv))); - OEMCrypto_Substring enc_mac_keys = GetSubstring( - message, wvcdm::BytesToString(encrypted_license().mac_keys, - sizeof(encrypted_license().mac_keys))); - if (new_mac_keys) { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys( - session_id(), message_ptr(), message_size_, signature_.data(), - signature_.size(), enc_mac_keys_iv, enc_mac_keys, num_keys_, - key_array_, pst, GetSubstring(), OEMCrypto_ContentLicense)); - // Update new generated keys. - key_deriver_.set_mac_keys(license_.mac_keys); - } else { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadKeys( - session_id(), message_ptr(), message_size_, signature_.data(), - signature_.size(), GetSubstring(), GetSubstring(), num_keys_, - key_array_, pst, GetSubstring(), OEMCrypto_ContentLicense)); - } - VerifyTestKeys(); -} - -void Session::LoadEntitlementTestKeys(const std::string& provider_session_token, - bool new_mac_keys, - OEMCryptoResult expected_sts) { - std::string message = - wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); - OEMCrypto_Substring pst = GetSubstring(message, provider_session_token); - OEMCrypto_Substring enc_mac_keys_iv = GetSubstring( - message, wvcdm::BytesToString(encrypted_license().mac_key_iv, - sizeof(encrypted_license().mac_key_iv))); - OEMCrypto_Substring enc_mac_keys = GetSubstring( - message, wvcdm::BytesToString(encrypted_license().mac_keys, - sizeof(encrypted_license().mac_keys))); - if (new_mac_keys) { - ASSERT_EQ( - expected_sts, - OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, - signature_.data(), signature_.size(), - enc_mac_keys_iv, enc_mac_keys, num_keys_, - key_array_, pst, GetSubstring(), - OEMCrypto_EntitlementLicense)); - // Update new generated keys. - key_deriver_.set_mac_keys(license_.mac_keys); - } else { - ASSERT_EQ( - expected_sts, - OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_, - signature_.data(), signature_.size(), GetSubstring(), - GetSubstring(), num_keys_, key_array_, pst, - GetSubstring(), OEMCrypto_EntitlementLicense)); - } -} - -void Session::FillEntitledKeyArray() { - int offset = 0; - entitled_message_.clear(); - for (size_t i = 0; i < num_keys_; ++i) { - EntitledContentKeyData* key_data = &entitled_key_data_[i]; - - entitled_key_array_[i].entitlement_key_id.offset = offset; - entitled_key_array_[i].entitlement_key_id.length = - key_array_[i].key_id.length; - offset += key_array_[i].key_id.length; - entitled_message_ += - wvcdm::BytesToString(message_ptr() + key_array_[i].key_id.offset, - key_array_[i].key_id.length); - - EXPECT_EQ(1, GetRandBytes(key_data->content_key_id, - sizeof(key_data->content_key_id))); - entitled_key_array_[i].content_key_id.offset = offset; - entitled_key_array_[i].content_key_id.length = - sizeof(key_data->content_key_id); - offset += sizeof(key_data->content_key_id); - entitled_message_ += wvcdm::BytesToString(key_data->content_key_id, - sizeof(key_data->content_key_id)); - - EXPECT_EQ(1, GetRandBytes(key_data->content_key_data, - sizeof(key_data->content_key_data))); - entitled_key_array_[i].content_key_data.offset = offset; - entitled_key_array_[i].content_key_data.length = - sizeof(key_data->content_key_data); - offset += sizeof(key_data->content_key_data); - entitled_message_ += wvcdm::BytesToString( - key_data->content_key_data, sizeof(key_data->content_key_data)); - - EXPECT_EQ(1, GetRandBytes(key_data[i].content_key_data_iv, - sizeof(key_data[i].content_key_data_iv))); - entitled_key_array_[i].content_key_data_iv.offset = offset; - entitled_key_array_[i].content_key_data_iv.length = - sizeof(key_data->content_key_data_iv); - offset += sizeof(key_data->content_key_data_iv); - entitled_message_ += wvcdm::BytesToString( - key_data->content_key_data_iv, sizeof(key_data->content_key_data_iv)); - } -} - -void Session::LoadEntitledContentKeys(OEMCryptoResult expected_sts) { - encrypted_entitled_message_ = entitled_message_; - std::vector encrypted_entitled_key_array( - entitled_key_array_, entitled_key_array_ + num_keys_); - - for (size_t i = 0; i < num_keys_; ++i) { - // Load the entitlement key from |key_array_|. - AES_KEY aes_key; - AES_set_encrypt_key(message_ptr() + key_array_[i].key_data.offset, 256, - &aes_key); - - // Encrypt the content key with the entitlement key. - uint8_t iv[16]; - const uint8_t* content_key_data = reinterpret_cast( - entitled_message_.data() + - entitled_key_array_[i].content_key_data.offset); - const uint8_t* encrypted_content_key_data = - reinterpret_cast( - encrypted_entitled_message_.data() + - encrypted_entitled_key_array[i].content_key_data.offset); - memcpy(&iv[0], - message_ptr() + - encrypted_entitled_key_array[i].content_key_data_iv.offset, - 16); - AES_cbc_encrypt(content_key_data, - const_cast(encrypted_content_key_data), - encrypted_entitled_key_array[i].content_key_data.length, - &aes_key, iv, AES_ENCRYPT); - } - ASSERT_EQ( - expected_sts, - OEMCrypto_LoadEntitledContentKeys( - session_id(), - reinterpret_cast(encrypted_entitled_message_.data()), - encrypted_entitled_message_.size(), - encrypted_entitled_key_array.size(), - encrypted_entitled_key_array.data())); - if (expected_sts != OEMCrypto_SUCCESS) { - return; - } - VerifyEntitlementTestKeys(); -} - -// This function verifies that the key control block reported by OEMCrypto agree -// with the truth key control block. Failures in this function probably -// indicate the OEMCrypto_LoadKeys did not correctly process the key control -// block. -void Session::VerifyTestKeys() { - for (unsigned int i = 0; i < num_keys_; i++) { - KeyControlBlock block; - size_t size = sizeof(block); - OEMCryptoResult sts = OEMCrypto_QueryKeyControl( - session_id(), license_.keys[i].key_id, license_.keys[i].key_id_length, - reinterpret_cast(&block), &size); - if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_EQ(sizeof(block), size); - // control duration and bits stored in network byte order. For printing - // we change to host byte order. - ASSERT_EQ((htonl_fnc(license_.keys[i].control.duration)), - (htonl_fnc(block.duration))) - << "For key " << i; - ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits), - htonl_fnc(block.control_bits)) - << "For key " << i; - } - } -} - -// This function verifies that the key control block reported by OEMCrypto agree -// with the truth key control block. Failures in this function probably -// indicate the OEMCrypto_LoadEntitledKeys did not correctly process the key -// control block. -void Session::VerifyEntitlementTestKeys() { - for (unsigned int i = 0; i < num_keys_; i++) { - KeyControlBlock block; - size_t size = sizeof(block); - const uint8_t* content_key_id = - reinterpret_cast(entitled_message_.data()); - OEMCryptoResult sts = OEMCrypto_QueryKeyControl( - session_id(), - content_key_id + entitled_key_array_[i].content_key_id.offset, - entitled_key_array_[i].content_key_id.length, - reinterpret_cast(&block), &size); - if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_EQ(sizeof(block), size); - // control duration and bits stored in network byte order. For printing - // we change to host byte order. - ASSERT_EQ((htonl_fnc(license_.keys[i].control.duration)), - (htonl_fnc(block.duration))) - << "For key " << i; - ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits), - htonl_fnc(block.control_bits)) - << "For key " << i; - } - } -} - -void Session::RefreshTestKeys(const size_t key_count, uint32_t control_bits, - uint32_t nonce, OEMCryptoResult expected_result) { - // Note: we store the message in encrypted_license_, but the refresh key - // message is not actually encrypted. It is, however, signed. - // FillRefreshMessage fills the message with a duration of kLongDuration. - FillRefreshMessage(key_count, control_bits, nonce); - key_deriver_.ServerSignBuffer( - reinterpret_cast(&padded_message_), message_size_, - &signature_); - std::vector key_array(key_count); - FillRefreshArray(key_array.data(), key_count); - OEMCryptoResult sts = OEMCrypto_RefreshKeys( - session_id(), message_ptr(), message_size_, signature_.data(), - signature_.size(), key_count, key_array.data()); - ASSERT_EQ(expected_result, sts); - - ASSERT_NO_FATAL_FAILURE(TestDecryptCTR()); - // This should still be valid key, even if the refresh failed, because this - // is before the original license duration. - wvcdm::TestSleep::Sleep(kShortSleep); - ASSERT_NO_FATAL_FAILURE(TestDecryptCTR(false)); - // This should be after duration of the original license, but before the - // expiration of the refresh message. This should succeed if and only if the - // refresh succeeded. - wvcdm::TestSleep::Sleep(kShortSleep + kLongSleep); - if (expected_result == OEMCrypto_SUCCESS) { - ASSERT_NO_FATAL_FAILURE(TestDecryptCTR(false, OEMCrypto_SUCCESS)); - } else { - ASSERT_NO_FATAL_FAILURE( - TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE)); - } -} - -void Session::FillSimpleMessage(uint32_t duration, uint32_t control, - uint32_t nonce, const std::string& pst) { - EXPECT_EQ( - 1, GetRandBytes(license_.mac_key_iv, sizeof(license_.mac_key_iv))); - memset(license_.padding, 0, sizeof(license_.padding)); - EXPECT_EQ(1, GetRandBytes(license_.mac_keys, sizeof(license_.mac_keys))); - for (unsigned int i = 0; i < num_keys_; i++) { - memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength); - license_.keys[i].key_id_length = kDefaultKeyIdLength; - memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length); - EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_data, - sizeof(license_.keys[i].key_data))); - license_.keys[i].key_data_length = KEY_SIZE; - EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_iv, - sizeof(license_.keys[i].key_iv))); - EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, - sizeof(license_.keys[i].control_iv))); - if (global_features.api_version >= 12) { - // For version 12 and above, we require OEMCrypto to handle kcNN for all - // licenses. - std::string kcVersion = - "kc" + std::to_string(global_features.api_version); - memcpy(license_.keys[i].control.verification, kcVersion.c_str(), 4); - } else if (control & wvoec::kControlSecurityPatchLevelMask) { - // For versions before 12, we require the special key control block only - // when there are newer features present. - memcpy(license_.keys[i].control.verification, "kc11", 4); - } else if (control & wvoec::kControlRequireAntiRollbackHardware) { - memcpy(license_.keys[i].control.verification, "kc10", 4); - } else if (control & (wvoec::kControlHDCPVersionMask | - wvoec::kControlReplayMask)) { - memcpy(license_.keys[i].control.verification, "kc09", 4); - } else { - memcpy(license_.keys[i].control.verification, "kctl", 4); - } - license_.keys[i].control.duration = htonl(duration); - license_.keys[i].control.nonce = htonl(nonce); - license_.keys[i].control.control_bits = htonl(control); - license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR; - } - memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length())); - pst_ = pst; -} - -void Session::FillSimpleEntitlementMessage( - uint32_t duration, uint32_t control, uint32_t nonce, - const std::string& pst) { - EXPECT_EQ( - 1, GetRandBytes(license_.mac_key_iv, sizeof(license_.mac_key_iv))); - EXPECT_EQ(1, GetRandBytes(license_.mac_keys, sizeof(license_.mac_keys))); - for (unsigned int i = 0; i < num_keys_; i++) { - memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength); - license_.keys[i].key_id_length = kDefaultKeyIdLength; - memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length); - EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_data, - sizeof(license_.keys[i].key_data))); - license_.keys[i].key_data_length = KEY_SIZE * 2; // AES-256 keys - EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_iv, - sizeof(license_.keys[i].key_iv))); - EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv, - sizeof(license_.keys[i].control_iv))); - if (global_features.api_version >= 12) { - // For version 12 and above, we require OEMCrypto to handle kcNN for all - // licenses. - std::string kcVersion = - "kc" + std::to_string(global_features.api_version); - memcpy(license_.keys[i].control.verification, kcVersion.c_str(), 4); - } else if (control & wvoec::kControlSecurityPatchLevelMask) { - // For versions before 12, we require the special key control block only - // when there are newer features present. - memcpy(license_.keys[i].control.verification, "kc11", 4); - } else if (control & wvoec::kControlRequireAntiRollbackHardware) { - memcpy(license_.keys[i].control.verification, "kc10", 4); - } else if (control & (wvoec::kControlHDCPVersionMask | - wvoec::kControlReplayMask)) { - memcpy(license_.keys[i].control.verification, "kc09", 4); - } else { - memcpy(license_.keys[i].control.verification, "kctl", 4); - } - license_.keys[i].control.duration = htonl(duration); - license_.keys[i].control.nonce = htonl(nonce); - license_.keys[i].control.control_bits = htonl(control); - license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR; - } - memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length())); - pst_ = pst; -} - -void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits, - uint32_t nonce) { - for (unsigned int i = 0; i < key_count; i++) { - encrypted_license().keys[i].key_id_length = license_.keys[i].key_id_length; - memcpy(encrypted_license().keys[i].key_id, license_.keys[i].key_id, - encrypted_license().keys[i].key_id_length); - if (global_features.api_version >= 12) { - // For version 12 and above, we require OEMCrypto to handle kcNN for all - // licenses. - std::string kcVersion = - "kc" + std::to_string(global_features.api_version); - memcpy(encrypted_license().keys[i].control.verification, - kcVersion.c_str(), 4); - } else { - // For versions before 12, we require the special key control block only - // when there are newer features present. - memcpy(encrypted_license().keys[i].control.verification, "kctl", 4); - } - encrypted_license().keys[i].control.duration = htonl(kLongDuration); - encrypted_license().keys[i].control.nonce = htonl(nonce); - encrypted_license().keys[i].control.control_bits = htonl(control_bits); - } -} - -void Session::SetLoadKeysSubstringParams() { - load_keys_params_.resize(4); - std::string message = - wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); - OEMCrypto_Substring* enc_mac_keys_iv = load_keys_params_.data(); - *enc_mac_keys_iv = GetSubstring( - message, wvcdm::BytesToString(encrypted_license().mac_key_iv, - sizeof(encrypted_license().mac_key_iv))); - OEMCrypto_Substring* enc_mac_keys = &load_keys_params_[1]; - *enc_mac_keys = GetSubstring( - message, wvcdm::BytesToString(encrypted_license().mac_keys, - sizeof(encrypted_license().mac_keys))); - OEMCrypto_Substring* pst = &load_keys_params_[2]; - size_t pst_length = - strlen(reinterpret_cast(encrypted_license().pst)); - *pst = GetSubstring( - message, wvcdm::BytesToString(encrypted_license().pst, pst_length)); - OEMCrypto_Substring* srm_req = &load_keys_params_[3]; - *srm_req = GetSubstring(); -} - -void Session::EncryptAndSign() { - ASSERT_NO_FATAL_FAILURE(GenerateDerivedKeysFromSessionKey()); - encrypted_license() = license_; - - uint8_t iv_buffer[16]; - memcpy(iv_buffer, &license_.mac_key_iv[0], KEY_IV_SIZE); - key_deriver_.CBCEncrypt(&license_.mac_keys[0], - &encrypted_license().mac_keys[0], 2 * MAC_KEY_SIZE, - license_.mac_key_iv); - - for (unsigned int i = 0; i < num_keys_; i++) { - memcpy(iv_buffer, &license_.keys[i].control_iv[0], KEY_IV_SIZE); - AES_KEY aes_key; - AES_set_encrypt_key(&license_.keys[i].key_data[0], 128, &aes_key); - AES_cbc_encrypt( - reinterpret_cast(&license_.keys[i].control), - reinterpret_cast(&encrypted_license().keys[i].control), - KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT); - key_deriver_.CBCEncrypt( - &license_.keys[i].key_data[0], &encrypted_license().keys[i].key_data[0], - license_.keys[i].key_data_length, license_.keys[i].key_iv); - } - memcpy(encrypted_license().pst, license_.pst, sizeof(license_.pst)); - key_deriver_.ServerSignBuffer( - reinterpret_cast(&padded_message_), message_size_, - &signature_); - FillKeyArray(encrypted_license(), key_array_); - SetLoadKeysSubstringParams(); -} - -void Session::VerifyLicenseRequestSignature(size_t data_length) { - // In the real world, a message should be signed by the client and - // verified by the server. This simulates that. - vector data(data_length); - for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; - OEMCryptoResult sts; - size_t gen_signature_length = 0; - size_t core_message_length = 0; - sts = OEMCrypto_PrepAndSignLicenseRequest(session_id(), data.data(), - data.size(), &core_message_length, - nullptr, &gen_signature_length); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - vector gen_signature(gen_signature_length); - sts = OEMCrypto_PrepAndSignLicenseRequest( - session_id(), data.data(), data.size(), &core_message_length, - gen_signature.data(), &gen_signature_length); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - if (global_features.api_version >= kCoreMessagesAPI) { - ASSERT_GT(data.size(), core_message_length); - std::string core_message(reinterpret_cast(data.data()), - core_message_length); - VerifyCoreLicenseRequest(core_message); - } - VerifyRSASignature(data, gen_signature.data(), gen_signature.size(), - kSign_RSASSA_PSS); -} - -void Session::VerifyRenewalRequestSignature(size_t data_length) { - // In the real world, a message should be signed by the client and - // verified by the server. This simulates that. - vector data(data_length); - for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; - OEMCryptoResult sts; - size_t gen_signature_length = 0; - size_t core_message_length = 0; - sts = OEMCrypto_PrepAndSignRenewalRequest(session_id(), data.data(), - data.size(), &core_message_length, - nullptr, &gen_signature_length); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - ASSERT_EQ(HMAC_SHA256_SIGNATURE_SIZE, gen_signature_length); - vector gen_signature(gen_signature_length); - sts = OEMCrypto_PrepAndSignRenewalRequest( - session_id(), data.data(), data.size(), &core_message_length, - gen_signature.data(), &gen_signature_length); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - if (global_features.api_version >= kCoreMessagesAPI) { - ASSERT_GT(data.size(), core_message_length); - std::string core_message(reinterpret_cast(data.data()), - core_message_length); - VerifyCoreRenewalRequest(core_message); - } - std::vector expected_signature; - key_deriver_.ClientSignBuffer(data, &expected_signature); - ASSERT_EQ(expected_signature, gen_signature); -} - -void Session::VerifyCoreLicenseRequest(const std::string& core_message) { - oec_util::ODK_LicenseRequest core_license_request; - EXPECT_TRUE( - oec_util::ParseLicenseRequest(core_message, &core_license_request)); - EXPECT_EQ(global_features.api_version, core_license_request.api_version); - if (nonce_) EXPECT_EQ(nonce_, core_license_request.nonce); - EXPECT_EQ(session_id_, core_license_request.session_id); -} - -void Session::VerifyCoreRenewalRequest(const std::string& core_message) { - oec_util::ODK_RenewalRequest core_renewal_request; - EXPECT_TRUE( - oec_util::ParseRenewalRequest(core_message, &core_renewal_request)); - EXPECT_EQ(global_features.api_version, core_renewal_request.api_version); - // We do not check the nonce, because we don't know it if it comes from a - // previous session. - EXPECT_EQ(session_id_, core_renewal_request.session_id); -} - -void Session::FillKeyArray(const MessageData& data, - OEMCrypto_KeyObject* key_array) { - const uint8_t* data_ptr = reinterpret_cast(&data); - std::string message = wvcdm::BytesToString(data_ptr, sizeof(MessageData)); - for (unsigned int i = 0; i < num_keys_; i++) { - key_array[i].key_id = GetSubstring( - message, - wvcdm::BytesToString(data.keys[i].key_id, data.keys[i].key_id_length)); - key_array[i].key_data_iv = GetSubstring( - message, - wvcdm::BytesToString(data.keys[i].key_iv, sizeof(data.keys[i].key_iv))); - key_array[i].key_data = GetSubstring( - message, wvcdm::BytesToString(data.keys[i].key_data, - data.keys[i].key_data_length)); - key_array[i].key_control_iv = GetSubstring( - message, wvcdm::BytesToString(data.keys[i].control_iv, - sizeof(data.keys[i].control_iv))); - const uint8_t* key_control_ptr = - reinterpret_cast(&data.keys[i].control); - key_array[i].key_control = GetSubstring( - message, - wvcdm::BytesToString(key_control_ptr, sizeof(data.keys[i].control))); - } -} - -void Session::FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array, - size_t key_count) { - std::string message = - wvcdm::BytesToString(message_ptr(), sizeof(MessageData)); - for (size_t i = 0; i < key_count; i++) { - key_array[i].key_id = GetSubstring( - message, - wvcdm::BytesToString(encrypted_license().keys[i].key_id, - sizeof(encrypted_license().keys[i].key_id)), - key_count <= 1); - key_array[i].key_control_iv = GetSubstring(); - key_array[i].key_control = GetSubstring( - message, - wvcdm::BytesToString(reinterpret_cast( - &encrypted_license().keys[i].control), - sizeof(encrypted_license().keys[i].control))); - } -} - void Session::EncryptCTR(const vector& in_buffer, const uint8_t* key, const uint8_t* starting_iv, vector* out_buffer) { @@ -1516,11 +1000,11 @@ void Session::TestDecryptCTR(bool select_key_first, OEMCrypto_SubSampleDescription subsample_description; ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( - encrypted_data.data(), encrypted_data.size(), output_buffer.data(), - output_buffer.size(), &sample_description, &subsample_description)); + encrypted_data, output_buffer, &sample_description, + &subsample_description)); // Generate test data - EXPECT_EQ(1, GetRandBytes(unencrypted_data.data(), unencrypted_data.size())); + EXPECT_EQ(GetRandBytes(unencrypted_data.data(), unencrypted_data.size()), 1); EncryptCTR(unencrypted_data, license_.keys[key_index].key_data, &sample_description.iv[0], &encrypted_data); @@ -1532,11 +1016,11 @@ void Session::TestDecryptCTR(bool select_key_first, // We only have a few errors that we test are reported. if (expected_result == OEMCrypto_SUCCESS) { // No error. - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - ASSERT_EQ(unencrypted_data, output_buffer); + ASSERT_EQ(sts, OEMCrypto_SUCCESS); + ASSERT_EQ(output_buffer, unencrypted_data); } else { ASSERT_NO_FATAL_FAILURE(TestDecryptResult(expected_result, sts)); - ASSERT_NE(unencrypted_data, output_buffer); + ASSERT_NE(output_buffer, unencrypted_data); } } @@ -1886,10 +1370,6 @@ void Session::GenerateReport(const std::string& pst, EXPECT_GE(kHardwareSecureClock, pst_report().clock_security_level()); EXPECT_EQ(pst.length(), pst_report().pst_length()); EXPECT_EQ(0, memcmp(pst.c_str(), pst_report().pst(), pst.length())); - // Also, we the session to be able to sign the release message with the - // correct mac keys from the usage table entry. Note that we sign both the PST - // report above with ClientSignPstReport, and we sign the renewal request. - ASSERT_NO_FATAL_FAILURE(VerifyRenewalRequestSignature()); } void Session::VerifyPST(const Test_PST_Report& expected) { @@ -1939,33 +1419,4 @@ void Session::VerifyReport(Test_PST_Report expected, expected.seconds_since_last_decrypt = MaybeAdjustTime(time_last_decrypt, now); ASSERT_NO_FATAL_FAILURE(VerifyPST(expected)); } - -void Session::GenerateVerifyReport(const std::string& pst, - OEMCrypto_Usage_Entry_Status status, - int64_t time_license_received, - int64_t time_first_decrypt, - int64_t time_last_decrypt) { - ASSERT_NO_FATAL_FAILURE(GenerateReport(pst)); - Test_PST_Report expected(pst, status); - ASSERT_NO_FATAL_FAILURE(VerifyReport(expected, time_license_received, - time_first_decrypt, time_last_decrypt)); - // The PST report was signed above. Below we verify that the entire message - // that is sent to the server will be signed by the right mac keys. - ASSERT_NO_FATAL_FAILURE(VerifyRenewalRequestSignature()); -} - -const uint8_t* Session::message_ptr() { - return reinterpret_cast(&encrypted_license()); -} - -void Session::set_message_size(size_t size) { - message_size_ = size; - ASSERT_GE(message_size_, sizeof(MessageData)); - ASSERT_LE(message_size_, kMaxMessageSize); -} - -const uint8_t* Session::encrypted_entitled_message_ptr() { - return reinterpret_cast(encrypted_entitled_message_.data()); -} - } // namespace wvoec diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index f31db7c..7924205 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -13,10 +13,11 @@ #include #include +#include "core_message_deserialize.h" +#include "core_message_serialize.h" #include "odk.h" #include "oec_device_features.h" #include "oec_key_deriver.h" -#include "oec_util.h" #include "oemcrypto_types.h" #include "pst_report.h" @@ -63,10 +64,8 @@ constexpr size_t kTestKeyIdMaxLength = 16; // Most content will use a key id that is 16 bytes long. constexpr int kDefaultKeyIdLength = 16; - -constexpr size_t kMaxPSTLength = 255; // In specification. -constexpr size_t kMaxMessageSize = 8 * 1024; // In specification. -constexpr size_t kMaxCoreMessage = 200 * kMaxNumKeys + 200; // Rough estimate. +constexpr size_t kMaxPSTLength = 255; // In specification. +constexpr size_t kMaxCoreMessage = 200 * kMaxNumKeys + 200; // Rough estimate. typedef struct { uint8_t key_id[kTestKeyIdMaxLength]; @@ -117,10 +116,8 @@ struct EntitledContentKeyData { // returns 1 on success, -1 if not supported, or 0 if other failure. int GetRandBytes(unsigned char* buf, int num); -void GenerateSimpleSampleDescription(const uint8_t* input_data, - size_t input_data_length, - uint8_t* output_buffer, - size_t output_buffer_length, +void GenerateSimpleSampleDescription(const std::vector& in, + std::vector& out, OEMCrypto_SampleDescription* sample, OEMCrypto_SubSampleDescription* subsample); @@ -183,6 +180,7 @@ class RoundTrip { // Accessors are all read/write because tests modify default values. Session* session() { return session_; } + void set_session(Session* session) { session_ = session; } CoreRequest& core_request() { return core_request_; } CoreResponse& core_response() { return core_response_; } ResponseData& response_data() { return response_data_; } @@ -190,7 +188,6 @@ class RoundTrip { std::vector& encrypted_response_buffer() { return encrypted_response_; } - void set_session(Session* session) { session_ = session; } // Set the size of the buffer used the encrypted license. void set_message_size(size_t size) { message_size_ = size; } @@ -228,10 +225,11 @@ class RoundTrip { }; class ProvisioningRoundTrip - : public RoundTrip { + : public RoundTrip< + /* CoreRequest */ oemcrypto_core_message::ODK_ProvisioningRequest, + OEMCrypto_PrepAndSignProvisioningRequest, + /* CoreResponse */ ODK_ParsedProvisioning, + /* ResponseData */ RSAPrivateKeyMessage> { public: ProvisioningRoundTrip(Session* session, const std::vector& encoded_rsa_key) @@ -269,10 +267,11 @@ class ProvisioningRoundTrip }; class LicenseRoundTrip - : public RoundTrip { + : public RoundTrip< + /* CoreRequest */ oemcrypto_core_message::ODK_LicenseRequest, + OEMCrypto_PrepAndSignLicenseRequest, + /* CoreResponse */ ODK_ParsedLicense, + /* ResponseData */ MessageData> { public: LicenseRoundTrip(Session* session) : RoundTrip(session), @@ -285,8 +284,9 @@ class LicenseRoundTrip expect_request_has_correct_nonce_(true), license_type_(OEMCrypto_ContentLicense) {} void CreateDefaultResponse() override; - // Create a license with four keys, one each that is allowed to do generic - // encrypt, decrypt, sign and verify. + // Create a license with four keys. Each key is responsible for one of generic + // encrypt (key 0), decrypt (key 1), sign (key 2) and verify (key 3). Each key + // is allowed only one type of operation. void CreateResponseWithGenericCryptoKeys(); // Fill the |core_response| substrings. virtual void FillCoreResponseSubstrings(); @@ -308,7 +308,8 @@ class LicenseRoundTrip // Set the number of keys to use in the license. void set_num_keys(uint32_t num_keys) { num_keys_ = num_keys; } uint32_t num_keys() const { return num_keys_; } - // Set the pst for the license. + // Get/Set the pst for the license and usage table entry. + const std::string& pst() const { return pst_; } void set_pst(const std::string& pst) { pst_ = pst; } // Set the minimum SRM version for the license. void set_minimum_srm_version(uint32_t minimum_srm_version) { @@ -364,12 +365,13 @@ class LicenseRoundTrip OEMCrypto_LicenseType license_type_; }; -class RenewalRoundTrip : public RoundTrip< - /* CoreRequest */ oec_util::ODK_RenewalRequest, - OEMCrypto_PrepAndSignRenewalRequest, - // Renewal response info is same as request: - /* CoreResponse */ oec_util::ODK_RenewalRequest, - /* ResponseData */ MessageData> { +class RenewalRoundTrip + : public RoundTrip< + /* CoreRequest */ oemcrypto_core_message::ODK_RenewalRequest, + OEMCrypto_PrepAndSignRenewalRequest, + // Renewal response info is same as request: + /* CoreResponse */ oemcrypto_core_message::ODK_RenewalRequest, + /* ResponseData */ MessageData> { public: RenewalRoundTrip(LicenseRoundTrip* license_messages) : RoundTrip(license_messages->session()), @@ -451,79 +453,6 @@ class Session { // Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey // and also fill out enc_key_, mac_key_server_, and mac_key_client_. void GenerateDerivedKeysFromSessionKey(); - // Loads and verifies the keys in the message pointed to by message_ptr() - // using OEMCrypto_LoadKeys. This message should have already been created - // by FillSimpleMessage, modified if needed, and then encrypted and signed by - // the server's mac key in EncryptAndSign. - void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true); - // Loads the entitlement keys in the message pointed to by message_ptr() - // using OEMCrypto_LoadKeys. This message should have already been created - // by FillSimpleEntitlementMessage, modified if needed, and then encrypted - // and signed by the server's mac key in EncryptAndSign. - void LoadEntitlementTestKeys(const std::string& pst = "", - bool new_mac_keys = true, - OEMCryptoResult expected_sts = OEMCrypto_SUCCESS); - // Fills an OEMCrypto_EntitledContentKeyObject using the information from - // the license_ and randomly generated content keys. This method should be - // called after LoadEntitlementTestKeys. - void FillEntitledKeyArray(); - // Encrypts and loads the entitled content keys via - // OEMCrypto_LoadEntitledContentKeys. - void LoadEntitledContentKeys( - OEMCryptoResult expected_sts = OEMCrypto_SUCCESS); - // This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto - // have the correct key control data. - void VerifyTestKeys(); - // This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto - // have the correct key control data. - void VerifyEntitlementTestKeys(); - // This creates a refresh key or license renewal message, signs it with the - // server's mac key, and calls OEMCrypto_RefreshKeys. - void RefreshTestKeys(const size_t key_count, uint32_t control_bits, - uint32_t nonce, OEMCryptoResult expected_result); - // This fills the data structure license_ with key information. This data - // can be modified, and then should be encrypted and signed in EncryptAndSign - // before being loaded in LoadTestKeys. - void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce, - const std::string& pst = ""); - // This fills the data structure license_ with entitlement key information. - // This data can be modified, and then should be encrypted and signed in - // EncryptAndSign before being loaded in LoadEntitlementTestKeys. - void FillSimpleEntitlementMessage( - uint32_t duration, uint32_t control, - uint32_t nonce, const std::string& pst = ""); - // Like FillSimpleMessage, this fills encrypted_license_ with data. The name - // is a little misleading: the license renewal message is not encrypted, it - // is just signed. The signature is computed in RefreshTestKeys, above. - void FillRefreshMessage(size_t key_count, uint32_t control_bits, - uint32_t nonce); - // Sets the OEMCrypto_Substring parameters of the LoadKeys method. - // Specifically, it sets the |enc_mac_keys_iv|, |enc_mac_keys|, |pst|, and - // |srm_restriction_data| in that order. For testing purposes, - // |srm_restriction_data| will always be nullptr. - void SetLoadKeysSubstringParams(); - // This copies data from license_ to encrypted_license_, and then encrypts - // each field in the key array appropriately. It then signes the buffer with - // the server mac keys. It then fills out the key_array_ so that pointers in - // that array point to the locations in the encrypted message. - void EncryptAndSign(); - // This checks the signature generated by OEMCrypto_PrepAndSignLicenseRequest - // against that generaged by ClientSignBuffer. - void VerifyLicenseRequestSignature(size_t data_length = 400); - // This checks the signature generated by OEMCrypto_PrepAndSignRenewalRequest - // against that generaged by ClientSignBuffer. - void VerifyRenewalRequestSignature(size_t data_length = 400); - // Verify the core message matches data from this session. - void VerifyCoreLicenseRequest(const std::string& core_message); - // Verify the core message matches data from this session. - void VerifyCoreRenewalRequest(const std::string& core_message); - // Set the pointers in key_array[*] to point values inside data. This is - // needed to satisfy range checks in OEMCrypto_LoadKeys. - void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array); - // As in FillKeyArray but for the license renewal message passed to - // OEMCrypto_RefreshKeys. - void FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array, - size_t key_count); // Encrypt a block of data using CTR mode. void EncryptCTR(const vector& in_buffer, const uint8_t* key, const uint8_t* starting_iv, vector* out_buffer); @@ -625,12 +554,6 @@ class Session { int64_t time_license_received = 0, int64_t time_first_decrypt = 0, int64_t time_last_decrypt = 0); - // Same as above, but generates the report with the given status. - void GenerateVerifyReport(const std::string& pst, - OEMCrypto_Usage_Entry_Status status, - int64_t time_license_received = 0, - int64_t time_first_decrypt = 0, - int64_t time_last_decrypt = 0); // Create an entry in the old usage table based on the given report. void CreateOldEntry(const Test_PST_Report &report); // Create a new entry and copy the old entry into it. Then very the report @@ -640,50 +563,9 @@ class Session { // The unencrypted license response or license renewal response. MessageData& license() { return license_; } - // The encrypted license response or license renewal response. - MessageData& encrypted_license() { return padded_message_; } - - // A pointer to the buffer holding encrypted_license. - const uint8_t* message_ptr(); - - // An array of key objects for use in LoadKeys. - OEMCrypto_KeyObject* key_array() { return key_array_; } - - // An array of key objects for LoadEntitledContentKeys. - OEMCrypto_EntitledContentKeyObject* entitled_key_array() { - return entitled_key_array_; - } - - // The last signature generated with the server's mac key. - std::vector& signature() { return signature_; } - - // Set the number of keys to use in the license(), encrypted_license() - // and key_array(). - void set_num_keys(int num_keys) { num_keys_ = num_keys; } - // The current number of keys to use in the license(), encrypted_license() - // and key_array(). - unsigned int num_keys() const { return num_keys_; } - - // Set the size of the buffer used the encrypted license. - // Must be between sizeof(MessageData) and kMaxMessageSize. - void set_message_size(size_t size); - // The size of the encrypted message. - size_t message_size() { return message_size_; } void set_license(const MessageData& license) { license_ = license; } - // The OEMCrypto_Substrings associated with the encrypted license that are - // passed to LoadKeys. - vector load_keys_params() { return load_keys_params_; } - OEMCrypto_Substring enc_mac_keys_iv_substr() { return load_keys_params_[0]; } - OEMCrypto_Substring enc_mac_keys_substr() { return load_keys_params_[1]; } - OEMCrypto_Substring pst_substr() { return load_keys_params_[2]; } - OEMCrypto_Substring srm_restriction_data_substr() { - return load_keys_params_[3]; - } - - // Pointer to buffer holding |encrypted_entitled_message_| - const uint8_t* encrypted_entitled_message_ptr(); const KeyDeriver& key_deriver() const { return key_deriver_; } void set_mac_keys(const uint8_t* mac_keys) { key_deriver_.set_mac_keys(mac_keys); @@ -698,26 +580,10 @@ class Session { RSA* public_rsa_; vector pst_report_buffer_; MessageData license_; - struct PaddedMessageData : public MessageData { - uint8_t padding[kMaxMessageSize - sizeof(MessageData)]; - } padded_message_; - size_t message_size_; // How much of the padded message to use. - OEMCrypto_KeyObject key_array_[kMaxNumKeys]; - vector load_keys_params_; - std::vector signature_; - unsigned int num_keys_; + vector encrypted_usage_entry_; uint32_t usage_entry_number_; string pst_; - - // Clear Entitlement key data. This is the backing data for - // |entitled_key_array_|. - EntitledContentKeyData entitled_key_data_[kMaxNumKeys]; - // Message containing data from |key_array| and |entitled_key_data_|. - std::string entitled_message_; - // Entitled key object. Pointers are backed by |entitled_key_data_|. - OEMCrypto_EntitledContentKeyObject entitled_key_array_[kMaxNumKeys]; - std::string encrypted_entitled_message_; }; } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 96496d1..50ca22e 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -83,9 +83,11 @@ void PrintTo(const tuple N) return resource_values[N-1]; return resource_values[global_features.resource_rating-1]; } -// clang-format off -const size_t kMaxSampleSize[] = { 1*MiB, 2*MiB, 4*MiB}; -const size_t kMaxNumberSubsamples[] = { 10, 16, 32}; -const size_t kMaxSubsampleSize[] = { 100*KiB, 500*KiB, 1*MiB}; -const size_t kMaxGenericBuffer[] = { 10*KiB, 100*KiB, 500*KiB}; -const size_t kMaxConcurrentSession[] = { 10, 20, 20}; -const size_t kMaxKeysPerSession[] = { 4, 20, 20}; -const size_t kLargeMessageSize[] = { 8 * KiB, 8 * KiB, 16 * KiB, 32 * KiB}; -// clang-format on +// After API 16, we require 300 entries in the usage table. Before API 16, we +// required 200. +size_t RequiredUsageSize() { + return global_features.api_version < 16 ? 200 : 300; +} + +// These are the maximum sizes we test. That means it is the minimum size that +// OEMCrypto must support. +// clang-format off +const size_t kMaxSampleSize[] = { 1*MiB, 2*MiB, 4*MiB, 16*MiB}; +const size_t kMaxNumberSubsamples[] = { 10, 16, 32, 64}; +const size_t kMaxSubsampleSize[] = { 100*KiB, 500*KiB, 1*MiB, 4*MiB}; +const size_t kMaxGenericBuffer[] = { 10*KiB, 100*KiB, 500*KiB, 1*MiB}; +const size_t kMaxConcurrentSession[] = { 10, 20, 20, 30}; +const size_t kMaxKeysPerSession[] = { 4, 20, 20, 30}; +const size_t kMaxTotalKeys[] = { 16, 40, 80, 90}; +const size_t kLargeMessageSize[] = { 8*KiB, 8*KiB, 16*KiB, 32*KiB}; // Note: Frame rate and simultaneous playback are specified by resource rating, // but are tested at the system level, so there are no unit tests for frame -// rate. +// rate. Similarly, number of subsamples for AV1 +// const size_t kAV1NumberSubsamples[] = { 72, 144, 288, 576}; +// clang-format on /** @return The Unix time of the given time point. */ template @@ -284,10 +296,10 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { } TEST_F(OEMCryptoClientTest, CheckUsageTableSizeAPI16) { - size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize(); + const size_t maximum = OEMCrypto_MaximumUsageTableHeaderSize(); printf(" Max Usage Table Size: %zu.\n", maximum); - const size_t minimum_capacity = 200u; - ASSERT_GE(maximum, minimum_capacity); + // A maximum of 0 means the table is constrained my dynamic memory allocation. + if (maximum > 0) ASSERT_GE(maximum, RequiredUsageSize()); } // @@ -959,15 +971,6 @@ TEST_F(OEMCryptoLicenseTestAPI16, UseWrongLoadAPI16) { ASSERT_NE(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); } -// Returns a string containing two times the original message in continuous -// memory. Used as part of the BadRange tests. -std::string DuplicateMessage(MessageData& message) { - std::string single_message = wvcdm::BytesToString( - reinterpret_cast(&message), sizeof(message)); - std::string double_message = single_message + single_message; - return double_message; -} - //---------------------------------------------------------------------------// //---------------------------------------------------------------------------// // Each of the following LoadKeyWithBadRange_* tests is similar. They verify @@ -1374,8 +1377,7 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyNotThereAPI15) { OEMCrypto_SubSampleDescription subsample_description; ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( - in_buffer.data(), in_buffer.size(), out_buffer.data(), - out_buffer.size(), &sample_description, &subsample_description)); + in_buffer, out_buffer, &sample_description, &subsample_description)); // Generate test data for (size_t i = 0; i < in_buffer.size(); i++) in_buffer[i] = i % 256; @@ -1386,23 +1388,22 @@ TEST_P(OEMCryptoLicenseTest, SelectKeyNotThereAPI15) { // Try to decrypt the data sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, &pattern); - EXPECT_EQ(OEMCrypto_ERROR_NO_CONTENT_KEY, sts); + EXPECT_EQ(sts, OEMCrypto_ERROR_NO_CONTENT_KEY); } } // 'cens' mode is no longer supported in v16 -TEST_F(OEMCryptoSessionTests, RejectCensAPI16) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); +TEST_P(OEMCryptoLicenseTest, RejectCensAPI16) { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); OEMCryptoResult sts; - sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, - s.license().keys[0].key_id_length, - OEMCrypto_CipherMode_CTR); + sts = OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector in_buffer(256); @@ -1411,30 +1412,29 @@ TEST_F(OEMCryptoSessionTests, RejectCensAPI16) { OEMCrypto_SubSampleDescription subsample_description; ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( - in_buffer.data(), in_buffer.size(), out_buffer.data(), out_buffer.size(), - &sample_description, &subsample_description)); + in_buffer, out_buffer, &sample_description, &subsample_description)); // Create a non-zero pattern to indicate this is 'cens' OEMCrypto_CENCEncryptPatternDesc pattern = {1, 9}; // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(s.session_id(), &sample_description, 1, &pattern); + sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern); EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); } // 'cbc1' mode is no longer supported in v16 -TEST_F(OEMCryptoSessionTests, RejectCbc1API16) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); +TEST_P(OEMCryptoLicenseTest, RejectCbc1API16) { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); OEMCryptoResult sts; - sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, - s.license().keys[0].key_id_length, - OEMCrypto_CipherMode_CBC); + sts = OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector in_buffer(256); @@ -1443,29 +1443,28 @@ TEST_F(OEMCryptoSessionTests, RejectCbc1API16) { OEMCrypto_SubSampleDescription subsample_description; ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( - in_buffer.data(), in_buffer.size(), out_buffer.data(), out_buffer.size(), - &sample_description, &subsample_description)); + in_buffer, out_buffer, &sample_description, &subsample_description)); // Create a zero pattern to indicate this is 'cbc1' OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(s.session_id(), &sample_description, 1, &pattern); + sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern); EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); } -TEST_F(OEMCryptoSessionTests, RejectCbcWithBlockOffset) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); - ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); - ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); - ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); +TEST_P(OEMCryptoLicenseTest, RejectCbcsWithBlockOffset) { + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); OEMCryptoResult sts; - sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, - s.license().keys[0].key_id_length, - OEMCrypto_CipherMode_CBC); + sts = OEMCrypto_SelectKey( + session_.session_id(), session_.license().keys[0].key_id, + session_.license().keys[0].key_id_length, OEMCrypto_CipherMode_CBC); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector in_buffer(256); @@ -1474,15 +1473,15 @@ TEST_F(OEMCryptoSessionTests, RejectCbcWithBlockOffset) { OEMCrypto_SubSampleDescription subsample_description; ASSERT_NO_FATAL_FAILURE(GenerateSimpleSampleDescription( - in_buffer.data(), in_buffer.size(), out_buffer.data(), out_buffer.size(), - &sample_description, &subsample_description)); + in_buffer, out_buffer, &sample_description, &subsample_description)); subsample_description.block_offset = 5; // Any value 1-15 will do. // Create a non-zero pattern to indicate this is 'cbcs'. OEMCrypto_CENCEncryptPatternDesc pattern = {1, 9}; // Try to decrypt the data - sts = OEMCrypto_DecryptCENC(s.session_id(), &sample_description, 1, &pattern); + sts = OEMCrypto_DecryptCENC(session_.session_id(), &sample_description, 1, + &pattern); EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, sts); } @@ -1534,7 +1533,7 @@ TEST_P(OEMCryptoLicenseTest, AntiRollbackHardwareRequired) { // This test verifies that OEMCrypto can load the number of keys required for // the reported resource level. -TEST_P(OEMCryptoLicenseTest, MinimumKeysAPI12) { +TEST_P(OEMCryptoLicenseTest, MinimumKeys) { const size_t num_keys = GetResourceValue(kMaxKeysPerSession); ASSERT_LE(num_keys, kMaxNumKeys) << "Test constants need updating."; license_messages_.set_num_keys(num_keys); @@ -1544,13 +1543,73 @@ TEST_P(OEMCryptoLicenseTest, MinimumKeysAPI12) { ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + constexpr bool kSelectKeyFirst = true; for (size_t key_index = 0; key_index < num_keys; key_index++) { - constexpr bool kSelectKeyFirst = true; ASSERT_NO_FATAL_FAILURE( session_.TestDecryptCTR(kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); } } +// This test verifies that OEMCrypto can load the total number of keys required +// for the reported resource level. +void TestMaxKeys(SessionUtil* util, size_t num_keys_per_session) { + const size_t max_total_keys = GetResourceValue(kMaxTotalKeys); + ASSERT_LE(num_keys_per_session, kMaxNumKeys) << "Update test constants."; + std::vector> sessions; + std::vector> licenses; + size_t total_keys = 0; + for (size_t i = 0; total_keys < max_total_keys; i++) { + sessions.push_back(std::unique_ptr(new Session())); + licenses.push_back(std::unique_ptr( + new LicenseRoundTrip(sessions[i].get()))); + const size_t num_keys = + std::min(max_total_keys - total_keys, num_keys_per_session); + licenses[i]->set_num_keys(num_keys); + total_keys += num_keys; + ASSERT_NO_FATAL_FAILURE(sessions[i]->open()); + ASSERT_NO_FATAL_FAILURE(util->InstallTestRSAKey(sessions[i].get())); + ASSERT_NO_FATAL_FAILURE(sessions[i]->GenerateNonce()); + ASSERT_NO_FATAL_FAILURE(licenses[i]->SignAndVerifyRequest()); + } + for (size_t i = 0; i < licenses.size(); i++) { + ASSERT_NO_FATAL_FAILURE(licenses[i]->CreateDefaultResponse()); + ASSERT_NO_FATAL_FAILURE(licenses[i]->EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, licenses[i]->LoadResponse()); + } + constexpr bool kSelectKeyFirst = true; + for (size_t i = 0; i < licenses.size(); i++) { + for (size_t key_index = 0; key_index < licenses[i]->num_keys(); + key_index++) { + ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR( + kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); + } + } + // Second call to decrypt for each session. + for (size_t i = 0; i < licenses.size(); i++) { + for (size_t key_index = 0; key_index < licenses[i]->num_keys(); + key_index++) { + ASSERT_NO_FATAL_FAILURE(sessions[i]->TestDecryptCTR( + kSelectKeyFirst, OEMCrypto_SUCCESS, key_index)); + } + } +} + +// This test verifies that OEMCrypto can load the total number of keys required +// for the reported resource level. This maximizes keys per session. +TEST_P(OEMCryptoLicenseTest, MaxTotalKeysPerSession) { + const size_t max_num_keys = GetResourceValue(kMaxKeysPerSession); + TestMaxKeys(this, max_num_keys); +} + +// This test verifies that OEMCrypto can load the total number of keys required +// for the reported resource level. This maximizes number of sessions. +TEST_P(OEMCryptoLicenseTest, MaxTotalKeysManySessions) { + const size_t max_total_keys = GetResourceValue(kMaxTotalKeys); + const size_t max_sessions = GetResourceValue(kMaxConcurrentSession); + const size_t max_num_keys = max_total_keys / max_sessions + 1; + TestMaxKeys(this, max_num_keys); +} + // This test verifies that the minimum patch level can be required. The device // should accept a key control block with the current patch level, and it should // reject any key control blocks with a future patch level. @@ -1666,8 +1725,13 @@ class OEMCryptoRefreshTest : public OEMCryptoLicenseTest { timer_limits_.initial_playback_duration_seconds = kDuration; // Playback may continue for four seconds after a renewal is loaded. timer_limits_.renewal_playback_duration_seconds = 2 * kDuration; - // Total playback is not limited. - timer_limits_.license_duration_seconds = 0; + if (license_api_version_ < kCoreMessagesAPI) { + // For legacy licenses, only license duration is enforced. + timer_limits_.license_duration_seconds = kDuration; + } else { + // Total playback is not limited. + timer_limits_.license_duration_seconds = 0; + } } void LoadLicense() { @@ -1723,7 +1787,7 @@ TEST_P(OEMCryptoRefreshTest, RefreshNoNonce) { TEST_P(OEMCryptoRefreshTestAPI16, RefreshNoLicense) { Session s; s.open(); - constexpr size_t message_size = kMaxCoreMessage; + constexpr size_t message_size = kMaxCoreMessage + 42; std::vector data(message_size); for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF; size_t gen_signature_length = 0; @@ -1731,6 +1795,7 @@ TEST_P(OEMCryptoRefreshTestAPI16, RefreshNoLicense) { OEMCryptoResult sts = OEMCrypto_PrepAndSignRenewalRequest( s.session_id(), data.data(), data.size(), &core_message_length, nullptr, &gen_signature_length); + ASSERT_LT(core_message_length, message_size); if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { vector gen_signature(gen_signature_length); sts = OEMCrypto_PrepAndSignRenewalRequest( @@ -1883,27 +1948,26 @@ struct TestSample { // output buffer is clear, it should be possible for the input and output // buffers to be the same. class OEMCryptoSessionTestsDecryptTests - : public OEMCryptoSessionTests, + : public OEMCryptoLicenseTestAPI16, public WithParamInterface > { + OEMCryptoCipherMode, OutputType>> { protected: void SetUp() override { - OEMCryptoSessionTests::SetUp(); + OEMCryptoLicenseTestAPI16::SetUp(); pattern_ = ::testing::get<0>(GetParam()); cipher_mode_ = ::testing::get<1>(GetParam()); decrypt_inplace_ = ::testing::get<2>(GetParam()).decrypt_inplace; output_buffer_type_ = ::testing::get<2>(GetParam()).type; verify_crc_ = global_features.supports_crc; // Pick a random key. - EXPECT_EQ(1, GetRandBytes(&key_[0], sizeof(key_))); + EXPECT_EQ(GetRandBytes(key_, sizeof(key_)), 1); // Pick a random starting iv. Some tests override this before using it. - EXPECT_EQ(1, GetRandBytes(&initial_iv_[0], sizeof(initial_iv_))); + EXPECT_EQ(GetRandBytes(initial_iv_, sizeof(initial_iv_)), 1); } void TearDown() override { - FreeBuffers(); - ASSERT_NO_FATAL_FAILURE(session_.close()); - OEMCryptoSessionTests::TearDown(); + FreeSecureBuffers(); + OEMCryptoLicenseTestAPI16::TearDown(); } void SetSubsampleSizes(std::vector subsample_sizes) { @@ -1913,6 +1977,7 @@ class OEMCryptoSessionTestsDecryptTests void SetSampleSizes(std::vector> sample_sizes) { ASSERT_GT(sample_sizes.size(), 0u); + samples_.clear(); samples_.reserve(sample_sizes.size()); // Convert all the size arrays to TestSample structs @@ -1925,8 +1990,8 @@ class OEMCryptoSessionTestsDecryptTests sample.subsamples.reserve(subsample_sizes.size()); // Convert all the sizes to subsample descriptions and tally the total - // size - size_t total_size = 0; + // sample size + size_t sample_size = 0; size_t current_block_offset = 0; for (const SubsampleSize& size : subsample_sizes) { sample.subsamples.push_back(OEMCrypto_SubSampleDescription{ @@ -1935,7 +2000,7 @@ class OEMCryptoSessionTestsDecryptTests current_block_offset}); // Update the rolling variables - total_size += size.clear_size + size.encrypted_size; + sample_size += size.clear_size + size.encrypted_size; if (cipher_mode_ == OEMCrypto_CipherMode_CTR) { current_block_offset = (current_block_offset + size.encrypted_size) % AES_BLOCK_SIZE; @@ -1949,7 +2014,7 @@ class OEMCryptoSessionTestsDecryptTests // Set related information on the sample description sample.description.subsamples = sample.subsamples.data(); sample.description.subsamples_length = sample.subsamples.size(); - sample.description.buffers.input_data_length = total_size; + sample.description.buffers.input_data_length = sample_size; } } @@ -1959,6 +2024,9 @@ class OEMCryptoSessionTestsDecryptTests for (TestSample& sample : samples_) { const size_t total_size = sample.description.buffers.input_data_length; ASSERT_GT(total_size, 0u); + sample.encrypted_buffer.clear(); + sample.truth_buffer.clear(); + sample.clear_buffer.clear(); sample.encrypted_buffer.resize(total_size); sample.truth_buffer.resize(total_size); for (size_t i = 0; i < total_size; i++) sample.truth_buffer[i] = i % 256; @@ -1973,7 +2041,8 @@ class OEMCryptoSessionTestsDecryptTests sample.encrypted_buffer.data(); } else { // Add some padding to verify there is no overrun. - sample.clear_buffer.resize(total_size + 16, 0xaa); + sample.clear_buffer.resize(total_size + kBufferOverrunPadding, + 0xaa); output_descriptor.buffer.clear.address = sample.clear_buffer.data(); } output_descriptor.buffer.clear.address_length = total_size; @@ -1981,11 +2050,11 @@ class OEMCryptoSessionTestsDecryptTests case OEMCrypto_BufferType_Secure: output_descriptor.buffer.secure.handle_length = total_size; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_AllocateSecureBuffer( + ASSERT_EQ(OEMCrypto_AllocateSecureBuffer( session_.session_id(), total_size, &output_descriptor, - &sample.secure_buffer_fid)); - ASSERT_NE(nullptr, output_descriptor.buffer.secure.handle); + &sample.secure_buffer_fid), + OEMCrypto_SUCCESS); + ASSERT_NE(output_descriptor.buffer.secure.handle, nullptr); // It is OK if OEMCrypto changes the maximum size, but there must // still be enough room for our data. ASSERT_GE(output_descriptor.buffer.secure.handle_length, total_size); @@ -1999,15 +2068,15 @@ class OEMCryptoSessionTestsDecryptTests } // sample loop } - void FreeBuffers() { + void FreeSecureBuffers() { for (TestSample& sample : samples_) { OEMCrypto_DestBufferDesc& output_descriptor = sample.description.buffers.output_descriptor; if (output_descriptor.type == OEMCrypto_BufferType_Secure) { - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_FreeSecureBuffer(session_.session_id(), + ASSERT_EQ(OEMCrypto_FreeSecureBuffer(session_.session_id(), &output_descriptor, - sample.secure_buffer_fid)); + sample.secure_buffer_fid), + OEMCrypto_SUCCESS); } } } @@ -2018,8 +2087,8 @@ class OEMCryptoSessionTestsDecryptTests for (TestSample& sample : samples_) { uint8_t iv[KEY_IV_SIZE]; // Current IV - memcpy(&iv[0], &initial_iv_[0], KEY_IV_SIZE); - memcpy(&sample.description.iv[0], &initial_iv_[0], KEY_IV_SIZE); + memcpy(iv, initial_iv_, KEY_IV_SIZE); + memcpy(sample.description.iv, initial_iv_, KEY_IV_SIZE); size_t buffer_index = 0; // byte index into in and out. size_t block_offset = 0; // byte index into current block. @@ -2034,16 +2103,17 @@ class OEMCryptoSessionTestsDecryptTests // The IV resets at the start of each subsample in the 'cbcs' schema. if (cipher_mode_ == OEMCrypto_CipherMode_CBC) { - memcpy(&iv[0], &initial_iv_[0], KEY_IV_SIZE); + memcpy(iv, initial_iv_, KEY_IV_SIZE); } size_t pattern_offset = 0; - size_t subsample_end = buffer_index + subsample.num_bytes_encrypted; + const size_t subsample_end = + buffer_index + subsample.num_bytes_encrypted; while (buffer_index < subsample_end) { - size_t size = + const size_t size = min(subsample_end - buffer_index, AES_BLOCK_SIZE - block_offset); - size_t pattern_length = pattern_.encrypt + pattern_.skip; - bool skip_block = + const size_t pattern_length = pattern_.encrypt + pattern_.skip; + const bool skip_block = (pattern_offset >= pattern_.encrypt) && (pattern_length > 0); if (pattern_length > 0) { pattern_offset = (pattern_offset + 1) % pattern_length; @@ -2051,9 +2121,6 @@ class OEMCryptoSessionTestsDecryptTests // CBC mode should just copy a partial block at the end. If there // is a partial block at the beginning, an error is returned, so we // can put whatever we want in the output buffer. - // - // TODO(b/140503351): The (size < AES_BLOCK_SIZE) check is not correct - // for patterns where (pattern.encrypt > 1). if (skip_block || ((cipher_mode_ == OEMCrypto_CipherMode_CBC) && (size < AES_BLOCK_SIZE))) { memcpy(&sample.encrypted_buffer[buffer_index], @@ -2073,8 +2140,8 @@ class OEMCryptoSessionTestsDecryptTests // offset. block_offset = block_offset + size; } else { - EXPECT_EQ(static_cast(AES_BLOCK_SIZE), - block_offset + size); + EXPECT_EQ(block_offset + size, + static_cast(AES_BLOCK_SIZE)); // Full block. Increment iv, and set offset to 0 for next // block. ctr128_inc64(1, iv); @@ -2100,22 +2167,26 @@ class OEMCryptoSessionTestsDecryptTests } void LoadLicense() { - // First we open a session and load a license. - ASSERT_NO_FATAL_FAILURE(session_.open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&session_)); - uint32_t control = 0; + ASSERT_NO_FATAL_FAILURE(session_.GenerateNonce()); + uint32_t control = wvoec::kControlNonceEnabled; if (verify_crc_) control |= kControlAllowHashVerification; if (output_buffer_type_ == OEMCrypto_BufferType_Secure) control |= kControlObserveDataPath | kControlDataPathSecure; - ASSERT_NO_FATAL_FAILURE(session_.FillSimpleMessage(kDuration, control, 0)); - memcpy(session_.license().keys[0].key_data, key_, sizeof(key_)); - session_.license().keys[0].cipher_mode = cipher_mode_; - ASSERT_NO_FATAL_FAILURE(session_.EncryptAndSign()); - ASSERT_NO_FATAL_FAILURE(session_.LoadTestKeys()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_SelectKey( + license_messages_.set_control(control); + ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); + + ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); + license_messages_.core_response().timer_limits.license_duration_seconds = + kDuration; + memcpy(license_messages_.response_data().keys[0].key_data, key_, + sizeof(key_)); + license_messages_.response_data().keys[0].cipher_mode = cipher_mode_; + ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); + ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); + ASSERT_EQ(OEMCrypto_SelectKey( session_.session_id(), session_.license().keys[0].key_id, - session_.license().keys[0].key_id_length, cipher_mode_)); + session_.license().keys[0].key_id_length, cipher_mode_), + OEMCrypto_SUCCESS); } void TestDecryptCENC() { @@ -2129,10 +2200,10 @@ class OEMCryptoSessionTestsDecryptTests uint32_t hash = wvcrc32(sample.truth_buffer.data(), sample.truth_buffer.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_SetDecryptHash( + ASSERT_EQ(OEMCrypto_SetDecryptHash( session_.session_id(), 1, - reinterpret_cast(&hash), sizeof(hash))); + reinterpret_cast(&hash), sizeof(hash)), + OEMCrypto_SUCCESS); } // Build an array of just the sample descriptions. @@ -2150,7 +2221,7 @@ class OEMCryptoSessionTestsDecryptTests sts = DecryptFallbackChain::Decrypt( session_.session_id(), sample_descriptions.data(), sample_descriptions.size(), cipher_mode_, &pattern_); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(sts, OEMCrypto_SUCCESS); // Validate the decrypted data. for (TestSample& sample : samples_) { @@ -2165,7 +2236,10 @@ class OEMCryptoSessionTestsDecryptTests // the original 0xaa that we set in MakeBuffersession_. const size_t total_size = sample.description.buffers.input_data_length; - EXPECT_EQ(0xaa, sample.clear_buffer[total_size]) << "Buffer overrun."; + EXPECT_EQ(std::count(sample.clear_buffer.begin() + total_size, + sample.clear_buffer.end(), 0xaa), + static_cast(kBufferOverrunPadding)) + << "Buffer overrun."; sample.clear_buffer.resize(total_size); // Remove padding. EXPECT_EQ(sample.clear_buffer, sample.truth_buffer); } @@ -2173,8 +2247,8 @@ class OEMCryptoSessionTestsDecryptTests } if (global_features.supports_crc) { uint32_t frame; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GetHashErrorCode(session_.session_id(), &frame)); + ASSERT_EQ(OEMCrypto_GetHashErrorCode(session_.session_id(), &frame), + OEMCrypto_SUCCESS); } } @@ -2188,7 +2262,6 @@ class OEMCryptoSessionTestsDecryptTests uint8_t key_[AES_BLOCK_SIZE]; // Encryption Key. uint8_t initial_iv_[KEY_IV_SIZE]; // Starting IV for every sample. std::vector samples_; - Session session_; }; TEST_P(OEMCryptoSessionTestsDecryptTests, SingleLargeSubsample) { @@ -2260,7 +2333,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, EvenOffset) { // compute the unencrypted data. By picking the encrypted data to be all 0, // it is easier to re-encrypt the data and debug problems. Similarly, we // pick an iv = 0. - memset(&initial_iv_[0], 0, KEY_IV_SIZE); + memset(initial_iv_, 0, KEY_IV_SIZE); TestSample& sample = samples_[0]; // There is only one sample in this test sample.truth_buffer.assign(sample.description.buffers.input_data_length, 0); ASSERT_NO_FATAL_FAILURE(EncryptData()); @@ -2302,8 +2375,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, OddOffset) { // If you start with an IV of 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE, after you // increment twice, you should get 0xFFFFFFFFFFFFFFFF0000000000000000. TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptWithNearWrap) { - memcpy(&initial_iv_[0], - wvcdm::a2b_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE").data(), + memcpy(initial_iv_, wvcdm::a2b_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE").data(), KEY_IV_SIZE); ASSERT_NO_FATAL_FAILURE(SetSubsampleSizes({ {0, 256}, @@ -2344,16 +2416,14 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptMaxSample) { // not evenly divisible by max_num_subsamples and thus the division gets // truncated, (max_num_subsamples * subsample_size) will be greater than // max_sample_size. - size_t subsample_size = max_sample_size / max_num_subsamples + 1; - if (subsample_size > max_subsample_size) { - subsample_size = max_subsample_size; - } + const size_t subsample_size = + std::min(max_sample_size / max_num_subsamples + 1, max_subsample_size); size_t bytes_remaining = max_sample_size; std::vector subsample_sizes; while (bytes_remaining > 0 && subsample_sizes.size() < max_num_subsamples) { const size_t this_subsample_size = - (subsample_size <= bytes_remaining) ? subsample_size : bytes_remaining; + std::min(subsample_size, bytes_remaining); const size_t clear_size = this_subsample_size / 2; const size_t encrypted_size = this_subsample_size - clear_size; @@ -2409,7 +2479,6 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptUnencrypted) { } TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptUnencryptedNoKey) { - ASSERT_NO_FATAL_FAILURE(session_.open()); // Do not try to compute the CRC because we have not loaded a license. verify_crc_ = false; // Single clear subsample @@ -2451,7 +2520,8 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, MultipleSamples) { } // Used to construct a specific pattern. -OEMCrypto_CENCEncryptPatternDesc MakePattern(size_t encrypt, size_t skip) { +constexpr OEMCrypto_CENCEncryptPatternDesc MakePattern(size_t encrypt, + size_t skip) { return {encrypt, skip}; } @@ -2466,9 +2536,7 @@ INSTANTIATE_TEST_CASE_P( Combine( Values(MakePattern(3, 7), MakePattern(9, 1), // HLS edge cases. We should follow the CENC spec, not HLS spec. - MakePattern(1, 9), MakePattern(1, 0), - // Pattern length should be 10, but that is not guaranteed. - MakePattern(1, 3), MakePattern(2, 1)), + MakePattern(1, 9), MakePattern(1, 0)), Values(OEMCrypto_CipherMode_CBC), ::testing::ValuesIn(global_features.GetOutputTypes()))); @@ -2856,7 +2924,7 @@ class OEMCryptoUsesCertificate : public OEMCryptoLoadsCertificate { } void TearDown() override { - session_.close(); + ASSERT_NO_FATAL_FAILURE(session_.close()); OEMCryptoLoadsCertificate::TearDown(); } @@ -4630,8 +4698,7 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) { clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), signature.size())); - wvcdm::TestSleep::Sleep(kLongSleep); // Should be expired key. - + wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. OEMCryptoResult status = OEMCrypto_Generic_Verify( session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), signature.size()); @@ -4739,12 +4806,9 @@ INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest, class LicenseWithUsageEntry { public: - LicenseWithUsageEntry() - : pst_("my_pst"), - session_(), - license_messages_(&session_), - generic_crypto_(false) { - license_messages_.set_pst(pst_); + LicenseWithUsageEntry(const std::string& pst = "my_pst") + : session_(), license_messages_(&session_), generic_crypto_(false) { + license_messages_.set_pst(pst); } void MakeAndLoadOnline(OEMCryptoSessionTests* test) { @@ -4752,15 +4816,25 @@ class LicenseWithUsageEntry { wvoec::kControlNonceEnabled | wvoec::kControlNonceRequired); } - void MakeOfflineAndClose(OEMCryptoSessionTests* test) { - MakeAndLoad(test, wvoec::kControlNonceOrEntry); + // If status in not a nullptr, then creating a new entry is allowed to fail, + // and its error code is stored in status. + void MakeOfflineAndClose(OEMCryptoSessionTests* test, + OEMCryptoResult* status = nullptr) { + MakeAndLoad(test, wvoec::kControlNonceOrEntry, status); + if (status != nullptr && *status != OEMCrypto_SUCCESS) { + ASSERT_NO_FATAL_FAILURE(session_.close()); + return; + } ASSERT_NO_FATAL_FAILURE( session_.UpdateUsageEntry(&(test->encrypted_usage_header_))); ASSERT_NO_FATAL_FAILURE(GenerateVerifyReport(kUnused)); ASSERT_NO_FATAL_FAILURE(session_.close()); } - void MakeAndLoad(SessionUtil* util, uint32_t control) { + // If status in not a nullptr, then creating a new entry is allowed to fail, + // and its error code is stored in status. + void MakeAndLoad(SessionUtil* util, uint32_t control, + OEMCryptoResult* status = nullptr) { license_messages_.set_control(control); ASSERT_NO_FATAL_FAILURE(session_.open()); ASSERT_NO_FATAL_FAILURE(util->InstallTestRSAKey(&session_)); @@ -4773,7 +4847,8 @@ class LicenseWithUsageEntry { ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); } ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); - ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry()); + ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry(status)); + if (status != nullptr && *status != OEMCrypto_SUCCESS) return; ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse()); } @@ -4788,8 +4863,8 @@ class LicenseWithUsageEntry { int64_t time_license_received = 0, int64_t time_first_decrypt = 0, int64_t time_last_decrypt = 0) { - ASSERT_NO_FATAL_FAILURE(session_.GenerateReport(pst_)); - Test_PST_Report expected(pst_, status); + ASSERT_NO_FATAL_FAILURE(session_.GenerateReport(pst())); + Test_PST_Report expected(pst(), status); ASSERT_NO_FATAL_FAILURE( session_.VerifyReport(expected, time_license_received, time_first_decrypt, time_last_decrypt)); @@ -4805,11 +4880,8 @@ class LicenseWithUsageEntry { session_.set_mac_keys(license_messages_.response_data().mac_keys); } - const std::string& pst() const { return pst_; } - void set_pst(const std::string& pst) { - pst_ = pst; - license_messages_.set_pst(pst); - } + const std::string& pst() const { return license_messages_.pst(); } + void set_pst(const std::string& pst) { license_messages_.set_pst(pst); } LicenseRoundTrip& license_messages() { return license_messages_; } Session& session() { return session_; } void set_generic_crypto(bool generic_crypto) { @@ -4817,7 +4889,6 @@ class LicenseWithUsageEntry { } private: - std::string pst_; Session session_; LicenseRoundTrip license_messages_; bool generic_crypto_; @@ -4972,7 +5043,6 @@ TEST_P(OEMCryptoUsageTableTest, RepeatOnlineLicense) { ASSERT_NO_FATAL_FAILURE(s2.open()); ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s2)); s2.LoadUsageEntry(s); // Use the same entry. - // key expired error. ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s2)); } @@ -4990,14 +5060,14 @@ TEST_P(OEMCryptoUsageTableTest, OnlineBadNonce) { ASSERT_NO_FATAL_FAILURE(s.GenerateNonce()); ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - for (unsigned int i = 0; i < license_messages.num_keys(); i++) + for (uint32_t i = 0; i < license_messages.num_keys(); i++) license_messages.response_data().keys[i].control.nonce ^= 42; ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages.LoadResponse()); } // A license with non-zero replay control bits needs a valid pst. -TEST_F(OEMCryptoUsageTableTest, OnlineEmptyPST) { +TEST_P(OEMCryptoUsageTableTest, OnlineEmptyPST) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); @@ -5083,7 +5153,6 @@ TEST_P(OEMCryptoUsageTableTest, CreateAndLoadMultipleEntries) { OEMCrypto_CreateNewUsageEntry(s2.session_id(), &usage_entry_number)); } -// XXX -- maybe this should be a generic test that also does usage table stuff? // Test generic encrypt when the license uses a PST. TEST_P(OEMCryptoUsageTableTest, GenericCryptoEncrypt) { LicenseWithUsageEntry entry; @@ -5234,7 +5303,7 @@ TEST_P(OEMCryptoUsageTableTest, GenericCryptoVerify) { TEST_P(OEMCryptoUsageTableTest, OfflineLicense) { LicenseWithUsageEntry entry; entry.license_messages().set_api_version(license_api_version_); - entry.MakeOfflineAndClose(this); + ASSERT_NO_FATAL_FAILURE(entry.MakeOfflineAndClose(this)); } // Test that an offline license can be loaded and that the license can be @@ -5372,7 +5441,7 @@ TEST_P(OEMCryptoUsageTableTest, OfflineBadNonce) { ASSERT_NO_FATAL_FAILURE(s.GenerateNonce()); ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse()); - for (unsigned int i = 0; i < license_messages.num_keys(); i++) + for (size_t i = 0; i < license_messages.num_keys(); i++) license_messages.response_data().keys[i].control.nonce ^= 42; ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse()); ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, license_messages.LoadResponse()); @@ -5436,7 +5505,7 @@ TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicense) { ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed)); ASSERT_NO_FATAL_FAILURE(s.close()); - // Offile license can not be reused if it has been deactivated. + // Offline license can not be reused if it has been deactivated. ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s)); @@ -5476,7 +5545,7 @@ TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicenseUnused) { ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused)); ASSERT_NO_FATAL_FAILURE(s.close()); - // Offile license can not be reused if it has been deactivated. + // Offline license can not be reused if it has been deactivated. ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&s)); ASSERT_NE(OEMCrypto_SUCCESS, entry.license_messages().LoadResponse(&s)); @@ -5519,29 +5588,9 @@ TEST_P(OEMCryptoUsageTableTest, UpdateFailsWithNullPtr) { &header_buffer_length, nullptr, &entry_buffer_length)); } -// XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -// XXX separate these tests out. // Class used to test usage table defragmentation. class OEMCryptoUsageTableDefragTest : public OEMCryptoUsageTableTest { protected: -#if 0 - void LoadFirstLicense(Session* s, uint32_t index) { make offline. - ASSERT_NO_FATAL_FAILURE(s->open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(s)); - std::string pst = "pst " + std::to_string(index); - ASSERT_NO_FATAL_FAILURE(s->GenerateNonce()); - ASSERT_NO_FATAL_FAILURE( - s->FillSimpleMessage(0, wvoec::kControlNonceOrEntry, s->nonce(), pst)); - ASSERT_NO_FATAL_FAILURE(s->EncryptAndSign()); - ASSERT_NO_FATAL_FAILURE(s->CreateNewUsageEntry()); - ASSERT_EQ(s->usage_entry_number(), index); - ASSERT_NO_FATAL_FAILURE(s->LoadTestKeys(pst, new_mac_keys_)); - ASSERT_NO_FATAL_FAILURE(s->TestDecryptCTR()); - ASSERT_NO_FATAL_FAILURE(s->UpdateUsageEntry(&encrypted_usage_header_)); - ASSERT_NO_FATAL_FAILURE(s->close()); - } -#endif - void ReloadLicense(LicenseWithUsageEntry* entry, int64_t start) { Session& s = entry->session(); ASSERT_NO_FATAL_FAILURE(entry->OpenAndReload(this)); @@ -5724,97 +5773,96 @@ TEST_P(OEMCryptoUsageTableDefragTest, ReloadUsageEntryBadData) { data.data(), data.size())); } -// XXX --- This is ugly. It takes too long. Fix it. -#if 0 -// This verifies we can actually create two hundered usage table entries. -TEST_P(OEMCryptoUsageTableDefragTest, TwoHundredEntries) { - ASSERT_TRUE(false); - // OEMCrypto is required to store at least 200 entries in the usage table +// This verifies we can actually create the required number of usage table +// entries. +TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { + // OEMCrypto is required to store at least 300 entries in the usage table // header, but it is allowed to store more. This test verifies that if we keep // adding entries, the error indicates a resource limit. It then verifies // that all of the successful entries are still valid after we throw out the // last invalid entry. - const size_t ENTRY_COUNT = 2000; - vector sessions(ENTRY_COUNT); + + // After API 16, we require 300 entries in the usage table. Before API 16, we + // required 200. + const size_t required_capacity = RequiredUsageSize(); + + // We try to make a much large header, and assume there is an error at some + // point. + const size_t attempt_count = required_capacity * 5; + // Count of how many entries we successfully create. size_t successful_count = 0; - for (size_t i = 0; i < ENTRY_COUNT; i++) { + + // These entries have licenses tied to them. + std::vector> entries; + // Store the status of the last attempt to create an entry. + OEMCryptoResult status = OEMCrypto_SUCCESS; + while (successful_count < attempt_count && status == OEMCrypto_SUCCESS) { wvcdm::TestSleep::SyncFakeClock(); - if (i % 50 == 0) LOGD("Creating license %zd", i); - ASSERT_NO_FATAL_FAILURE(sessions[i].open()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&sessions[i])); - std::string pst = MakePST(i); - ASSERT_NO_FATAL_FAILURE(sessions[i].GenerateNonce()); - ASSERT_NO_FATAL_FAILURE(sessions[i].FillSimpleMessage( - 0, wvoec::kControlNonceOrEntry, sessions[i].nonce(), pst)); - ASSERT_NO_FATAL_FAILURE(sessions[i].EncryptAndSign()); - // We attempt to create a new usage table entry for this session. - OEMCryptoResult status; - ASSERT_NO_FATAL_FAILURE(sessions[i].CreateNewUsageEntry(&status)); - if (status == OEMCrypto_SUCCESS) { - ASSERT_EQ(sessions[i].usage_entry_number(), i); - ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_)); - ASSERT_NO_FATAL_FAILURE( - sessions[i].UpdateUsageEntry(&encrypted_usage_header_)); - successful_count++; - } else { - // If we failed to create this many entries because of limited resources, - // then the error returned should be insufficient resources. - EXPECT_EQ(OEMCrypto_ERROR_INSUFFICIENT_RESOURCES, status) - << "Failed to create license " << i << " with pst = " << pst; + LOGD("Creating license for entry %zd", successful_count); + entries.push_back( + std::unique_ptr(new LicenseWithUsageEntry())); + entries.back()->set_pst("pst " + std::to_string(successful_count)); + ASSERT_NO_FATAL_FAILURE(entries.back()->MakeOfflineAndClose(this, &status)) + << "Failed creating license for entry " << successful_count; + if (status != OEMCrypto_SUCCESS) { + // Remove the failed session. + entries.resize(entries.size() - 1); break; } - ASSERT_NO_FATAL_FAILURE(sessions[i].close()); + EXPECT_EQ(entries.back()->session().usage_entry_number(), successful_count); + successful_count++; + // We don't create a license for each entry. For every license, we'll + // create 10 empty entries. + constexpr size_t filler_count = 10; + for (size_t i = 0; i < filler_count; i++) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.CreateNewUsageEntry(&status)) + << "Failed creating entry " << successful_count; + if (status != OEMCrypto_SUCCESS) break; + EXPECT_EQ(s.usage_entry_number(), successful_count); + successful_count++; + } } LOGD("successful_count = %d", successful_count); - EXPECT_GE(successful_count, 200u); - wvcdm::TestSleep::Sleep(kShortSleep); - // Now we will loop through each valid entry, and verify that we can still - // reload the license and perform a decrypt. - for (size_t i = 0; i < successful_count; i++) { - wvcdm::TestSleep::SyncFakeClock(); - if (i % 50 == 0) LOGD("Reloading license %zd", i); - ASSERT_NO_FATAL_FAILURE(sessions[i].open()); - std::string pst = MakePST(i); - // Reuse license message created above. - ASSERT_NO_FATAL_FAILURE(sessions[i].ReloadUsageEntry()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&sessions[i])); - ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_)) - << "Failed to reload license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE( - sessions[i].UpdateUsageEntry(&encrypted_usage_header_)) - << "Failed to update license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE(sessions[i].TestDecryptCTR()) - << "Failed to use license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE( - sessions[i].UpdateUsageEntry(&encrypted_usage_header_)) - << "Failed to update license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE(sessions[i].close()); + if (status != OEMCrypto_SUCCESS) { + // If we failed to create this many entries because of limited resources, + // then the error returned should be insufficient resources. + EXPECT_EQ(OEMCrypto_ERROR_INSUFFICIENT_RESOURCES, status) + << "Failed to create license " << successful_count + << ", with wrong error code."; } - // We also need to verify that a full table can be shrunk, and the remaining - // licenses still work. - size_t smaller_size = 10u; // 10 is smaller than 200. + EXPECT_GE(successful_count, required_capacity); + wvcdm::TestSleep::SyncFakeClock(); + // Shrink the table a little. + constexpr size_t small_number = 5; + size_t smaller_size = successful_count - small_number; ASSERT_NO_FATAL_FAILURE(ShrinkHeader(smaller_size)); - for (size_t i = 0; i < smaller_size; i++) { + // Throw out the last license if it was in the part of the table that was + // shrunk. + if (entries.back()->session().usage_entry_number() >= smaller_size) { + entries.pop_back(); + } + // Create a few more license + for (size_t i = 0; i < small_number; i++) { wvcdm::TestSleep::SyncFakeClock(); - ASSERT_NO_FATAL_FAILURE(sessions[i].open()); - std::string pst = MakePST(i); - // Reuse license message created above. - ASSERT_NO_FATAL_FAILURE(sessions[i].ReloadUsageEntry()); - ASSERT_NO_FATAL_FAILURE(InstallTestRSAKey(&sessions[i])); - ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_)) - << "Failed to reload license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE( - sessions[i].UpdateUsageEntry(&encrypted_usage_header_)) - << "Failed to update license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE(sessions[i].TestDecryptCTR()) - << "Failed to use license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE( - sessions[i].UpdateUsageEntry(&encrypted_usage_header_)) - << "Failed to update license " << i << " with pst = " << pst; - ASSERT_NO_FATAL_FAILURE(sessions[i].close()); + entries.push_back( + std::unique_ptr(new LicenseWithUsageEntry())); + entries.back()->set_pst("new pst " + std::to_string(smaller_size + i)); + entries.back()->MakeOfflineAndClose(this); + } + // Make sure that all of the licenses can be reloaded. + for (size_t i = 0; i < entries.size(); i++) { + Session& s = entries[i]->session(); + ASSERT_NO_FATAL_FAILURE(entries[i]->OpenAndReload(this)); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kUnused)); + ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); + ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); + ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kActive)); + ASSERT_NO_FATAL_FAILURE(s.close()); } } -#endif // This verifies that the usage table header can be loaded if the generation // number is off by one, but not off by two. @@ -5902,7 +5950,6 @@ TEST_P(OEMCryptoUsageTableTest, GenerateReportWrongPST) { } // Test usage table timing. -// XXX broken. TEST_P(OEMCryptoUsageTableTest, TimingTest) { LicenseWithUsageEntry entry1; entry1.license_messages().set_api_version(license_api_version_); @@ -5990,7 +6037,6 @@ TEST_P(OEMCryptoUsageTableTest, TimingTest) { ASSERT_NO_FATAL_FAILURE(entry3.GenerateVerifyReport(kUnused, loaded3)); } -// XXX -- review this with the renewal stuff. // Verify the times in the usage report. For performance reasons, we allow the // times in the usage report to be off by as much as kUsageTimeTolerance, which // is 10 seconds. This acceptable error is called slop. This test needs to run @@ -6128,7 +6174,6 @@ class OEMCryptoUsageTableTestWallClock : public OEMCryptoUsageTableTest { // We don't test roll-forward protection or instances where the user rolls back // the time to the last decrypt call since this requires hardware-secure clocks // to guarantee. -// XXX broken. TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) { cout << "This test temporarily rolls back the system time in order to verify " << "that the usage report accounts for the change. It then rolls " @@ -6188,9 +6233,8 @@ TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) { // Verify that a large PST can be used with usage table entries. TEST_P(OEMCryptoUsageTableTest, PSTLargeBuffer) { - LicenseWithUsageEntry entry; std::string pst(kMaxPSTLength, 'a'); // A large PST. - entry.set_pst(pst); + LicenseWithUsageEntry entry(pst); entry.MakeOfflineAndClose(this); Session& s = entry.session(); diff --git a/oemcrypto/test/oemcrypto_unittests.gypi b/oemcrypto/test/oemcrypto_unittests.gypi index 502214a..4482b20 100644 --- a/oemcrypto/test/oemcrypto_unittests.gypi +++ b/oemcrypto/test/oemcrypto_unittests.gypi @@ -21,7 +21,6 @@ '<(oemcrypto_dir)/ref/src', '<(oemcrypto_dir)/test', '<(oemcrypto_dir)/odk/include', - '<(oemcrypto_dir)/util/include', ], 'defines': [ 'OEMCRYPTO_TESTS',