Updates for 16.1 unit tests and code

This patch has the full v16.1 reference code and unit tests.
This commit is contained in:
Fred Gylys-Colwell
2020-01-13 21:28:54 -08:00
parent dc346cf70a
commit 858fa33cd7
48 changed files with 1608 additions and 2135 deletions

View File

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

View File

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

9
oemcrypto/odk/README Normal file
View File

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

View File

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

View File

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

View File

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

View File

@@ -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 <cstdint>
#include <string>
#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_ */

View File

@@ -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 <cstdint>
#include <string>
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_ */

View File

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

View File

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

View File

@@ -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 <cstdint>
#include <string>
#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_

View File

@@ -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 <cstdint>
#include <string>
#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_

View File

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

View File

@@ -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 <stdint.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#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 <typename S, typename T, typename U>
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<const uint8_t*>(oemcrypto_core_message.c_str());
size_t buf_length = oemcrypto_core_message.size();
Message* msg = NULL;
AllocateMessage(&msg, message_block);
InitMessage(msg, const_cast<uint8_t*>(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 <typename T, typename S, typename P>
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<ODK_CoreMessage*>(&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<const char*>(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<const char*>(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<ODK_ParsedLicense*>(&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<ODK_ParsedProvisioning*>(&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

View File

@@ -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 <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#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 <typename S, typename T, typename U>
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<const uint8_t*>(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<uint8_t*>(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<const char*>(device_id), device_id_length);
return true;
}
} // namespace deserialize
} // namespace oemcrypto_core_message

View File

@@ -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 <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include <vector>
#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 <typename T, typename S, typename P>
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<ODK_CoreMessage*>(&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<uint8_t> 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<const char*>(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<ODK_ParsedLicense*>(&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<ODK_ParsedProvisioning*>(&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

View File

@@ -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 <stdint.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 <endian.h>
# 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_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 <string>
#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<size_t(const uint8_t*, uint8_t*, size_t)> 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<bool>(a->initial_license_load),
static_cast<bool>(a->usage_entry_present), &parsed_lic);
}
static bool kdo_fun_LicenseResponse(const ODK_ParseLicense_Args* args,

View File

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

View File

@@ -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 <endian.h>
#include <unistd.h>
#include <algorithm>
#include <cstddef>
@@ -17,15 +20,48 @@
#include <string>
#include <vector>
#include <unistd.h>
#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 <gtest/gtest.h>
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<ODK_Field>& fields) {
const std::vector<ODK_Field>& 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<ODK_Field>& fields) {
return ODK_IterFields(ODK_READ, const_cast<uint8_t*>(buf), size_in, size_out,
fields);
}
OEMCryptoResult ODK_WriteFields(uint8_t* const buf, const size_t size_in,
size_t* size_out,
std::vector<ODK_Field>& 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<ODK_Field>& 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<const char*>(buffers[i]), n);
out.close();
std::cerr << "buffer " << i << " dumped to " << tmp << std::endl;
size_t bytes_written;
uint8_t* buf =
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(buffers[i]));
ODK_IterFields(ODK_DUMP, buf, n, &bytes_written, fields);
}
FAIL();
}
@@ -199,7 +277,7 @@ void expect_eq_buf(const void* s1, const void* s2, size_t n) {
template <typename T, typename F, typename G>
void ValidateRequest(uint32_t message_type,
std::vector<ODK_Field>& extra_fields,
const std::vector<ODK_Field>& 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<ODK_Field> 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 <typename T, typename F, typename G>
void ValidateResponse(uint32_t message_type,
std::vector<ODK_Field>& extra_fields,
const std::vector<ODK_Field>& 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<ODK_Field> 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<ODK_Field> 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<ODK_FieldType>(std::rand() %
static_cast<int>(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_LicenseRequest>(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<ODK_Field> 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<ODK_Field> 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<ODK_Field> 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<ODK_Field> 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_RenewalRequest>(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<ODK_Field> 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

View File

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

View File

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

View File

@@ -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 <gtest/gtest.h>
#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

View File

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

View File

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

View File

@@ -32,6 +32,7 @@ typedef std::map<SessionId, SessionContext*> 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

View File

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

View File

@@ -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<uint8_t>(
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<uint8_t>& 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<size_t>(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

View File

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

View File

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

View File

@@ -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<uint8_t>& in, std::vector<uint8_t>& 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<OEMCrypto_EntitledContentKeyObject> 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<const uint8_t*>(
entitled_message_.data() +
entitled_key_array_[i].content_key_data.offset);
const uint8_t* encrypted_content_key_data =
reinterpret_cast<const uint8_t*>(
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<uint8_t*>(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<const uint8_t*>(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<uint8_t*>(&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<const uint8_t*>(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<uint8_t*>(&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<const uint8_t*>(&padded_message_), message_size_,
&signature_);
std::vector<OEMCrypto_KeyRefreshObject> 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<const char*>(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<const uint8_t*>(&license_.keys[i].control),
reinterpret_cast<uint8_t*>(&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<const uint8_t*>(&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<uint8_t> 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<uint8_t> 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<char*>(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<uint8_t> 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<uint8_t> 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<char*>(data.data()),
core_message_length);
VerifyCoreRenewalRequest(core_message);
}
std::vector<uint8_t> 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<const uint8_t*>(&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<const uint8_t*>(&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<const uint8_t*>(
&encrypted_license().keys[i].control),
sizeof(encrypted_license().keys[i].control)));
}
}
void Session::EncryptCTR(const vector<uint8_t>& in_buffer, const uint8_t* key,
const uint8_t* starting_iv,
vector<uint8_t>* 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<const uint8_t*>(&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<const uint8_t*>(encrypted_entitled_message_.data());
}
} // namespace wvoec

View File

@@ -13,10 +13,11 @@
#include <string>
#include <vector>
#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<uint8_t>& in,
std::vector<uint8_t>& 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<uint8_t>& 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</* CoreRequest */ oec_util::ODK_ProvisioningRequest,
OEMCrypto_PrepAndSignProvisioningRequest,
/* CoreResponse */ ODK_ParsedProvisioning,
/* ResponseData */ RSAPrivateKeyMessage> {
: public RoundTrip<
/* CoreRequest */ oemcrypto_core_message::ODK_ProvisioningRequest,
OEMCrypto_PrepAndSignProvisioningRequest,
/* CoreResponse */ ODK_ParsedProvisioning,
/* ResponseData */ RSAPrivateKeyMessage> {
public:
ProvisioningRoundTrip(Session* session,
const std::vector<uint8_t>& encoded_rsa_key)
@@ -269,10 +267,11 @@ class ProvisioningRoundTrip
};
class LicenseRoundTrip
: public RoundTrip</* CoreRequest */ oec_util::ODK_LicenseRequest,
OEMCrypto_PrepAndSignLicenseRequest,
/* CoreResponse */ ODK_ParsedLicense,
/* ResponseData */ MessageData> {
: 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<uint8_t>& in_buffer, const uint8_t* key,
const uint8_t* starting_iv, vector<uint8_t>* 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<uint8_t>& 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<OEMCrypto_Substring> 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<uint8_t> 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<OEMCrypto_Substring> load_keys_params_;
std::vector<uint8_t> signature_;
unsigned int num_keys_;
vector<uint8_t> 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

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,6 @@
'<(oemcrypto_dir)/ref/src',
'<(oemcrypto_dir)/test',
'<(oemcrypto_dir)/odk/include',
'<(oemcrypto_dir)/util/include',
],
'defines': [
'OEMCRYPTO_TESTS',