OEMCrypto v16.1 -- update ODK
This CL updates the ODK library to address review comments.
This commit is contained in:
@@ -1407,7 +1407,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(
|
||||
* Message Serialization".
|
||||
*
|
||||
* Below, all fields are found in the struct ODK_ParsedLicense parsed_license
|
||||
* returend by ODK_ParseLicense.
|
||||
* returned by ODK_ParseLicense.
|
||||
*
|
||||
* The keys will be decrypted using the current encrypt_key (AES-128-CBC) and
|
||||
* the IV given in the KeyObject. Each key control block will be decrypted
|
||||
@@ -1722,7 +1722,7 @@ OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
|
||||
* timer 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_STALE_RENEWAL: This renewal is not the most recently signed. It is
|
||||
* rejected. Return this error
|
||||
* - Any other error - OEMCrypto shall pass any other error up to the
|
||||
@@ -3861,7 +3861,7 @@ uint32_t OEMCrypto_ResourceRatingTier(void);
|
||||
* Message Serialization".
|
||||
*
|
||||
* Below, all fields are found in the struct ODK_ParsedLicense parsed_license
|
||||
* returend by ODK_ParsedProvisioning.
|
||||
* returned by ODK_ParsedProvisioning.
|
||||
*
|
||||
* After decrypting enc_rsa_key, If the first four bytes of the buffer are
|
||||
* the string "SIGN", then the actual RSA key begins on the 9th byte of the
|
||||
|
||||
84
oemcrypto/odk/Android.bp
Normal file
84
oemcrypto/odk/Android.bp
Normal file
@@ -0,0 +1,84 @@
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Builds libwv_odk.a, The ODK Library (libwv_odk) is used by
|
||||
// the CDM and by oemcrypto implementations.
|
||||
cc_library_static {
|
||||
name: "libwv_odk",
|
||||
include_dirs: [
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/include",
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/odk/include",
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/odk/src",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/odk.c",
|
||||
"src/odk_overflow.c",
|
||||
"src/odk_serialize.c",
|
||||
"src/odk_timer.c",
|
||||
"src/serialization_base.c",
|
||||
],
|
||||
proprietary: true,
|
||||
|
||||
owner: "widevine",
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Builds libwv_kdo.a, The ODK Library companion (libwv_kdo) is used by
|
||||
// the CDM and by oemcrypto tests, but not by oemcrypto implementations.
|
||||
cc_library_static {
|
||||
name: "libwv_kdo",
|
||||
include_dirs: [
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/include",
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/odk/include",
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/odk/src",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"src/core_message_deserialize.cpp",
|
||||
"src/core_message_serialize.cpp",
|
||||
"src/core_message_serialize_proto.cpp",
|
||||
],
|
||||
|
||||
static_libs: [
|
||||
"libcdm_protos",
|
||||
"libwv_odk",
|
||||
],
|
||||
|
||||
proprietary: true,
|
||||
|
||||
owner: "widevine",
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Builds odk_test executable, which tests the ODK library.
|
||||
cc_test {
|
||||
name: "odk_test",
|
||||
include_dirs: [
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/include",
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/odk/include",
|
||||
"vendor/widevine/libwvdrmengine/oemcrypto/odk/src",
|
||||
],
|
||||
|
||||
// WARNING: Module tags are not supported in Soong.
|
||||
// For native test binaries, use the "cc_test" module type. Some differences:
|
||||
// - If you don't use gtest, set "gtest: false"
|
||||
// - Binaries will be installed into /data/nativetest[64]/<name>/<name>
|
||||
// - Both 32 & 64 bit versions will be built (as appropriate)
|
||||
|
||||
owner: "widevine",
|
||||
proprietary: true,
|
||||
|
||||
static_libs: [
|
||||
"libcdm_protos",
|
||||
"libcdm",
|
||||
"libwv_odk",
|
||||
"libwv_kdo",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"test/odk_test.cpp",
|
||||
"test/odk_timer_test.cpp",
|
||||
],
|
||||
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_
|
||||
#ifndef WIDEVINE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_
|
||||
#define WIDEVINE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
@@ -152,4 +152,4 @@ typedef struct {
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ...ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_ */
|
||||
#endif /* WIDEVINE_ODK_INCLUDE_OEMCRYPTOCENCCOMMON_H_ */
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#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_
|
||||
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_
|
||||
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_
|
||||
|
||||
#include "core_message_types.h"
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace deserialize {
|
||||
* [in] oemcrypto_core_message
|
||||
* [out] core_license_request
|
||||
*/
|
||||
bool CoreLicenseRequestFromMessage(const string& oemcrypto_core_message,
|
||||
bool CoreLicenseRequestFromMessage(const std::string& oemcrypto_core_message,
|
||||
ODK_LicenseRequest* core_license_request);
|
||||
|
||||
/**
|
||||
@@ -39,7 +39,7 @@ bool CoreLicenseRequestFromMessage(const string& oemcrypto_core_message,
|
||||
* [in] oemcrypto_core_message
|
||||
* [out] core_renewal_request
|
||||
*/
|
||||
bool CoreRenewalRequestFromMessage(const string& oemcrypto_core_message,
|
||||
bool CoreRenewalRequestFromMessage(const std::string& oemcrypto_core_message,
|
||||
ODK_RenewalRequest* core_renewal_request);
|
||||
|
||||
/**
|
||||
@@ -50,10 +50,10 @@ bool CoreRenewalRequestFromMessage(const string& oemcrypto_core_message,
|
||||
* [out] core_provisioning_request
|
||||
*/
|
||||
bool CoreProvisioningRequestFromMessage(
|
||||
const string& oemcrypto_core_message,
|
||||
const std::string& oemcrypto_core_message,
|
||||
ODK_ProvisioningRequest* core_provisioning_request);
|
||||
|
||||
} /* namespace deserialize */
|
||||
} /* namespace oemcrypto_core_message */
|
||||
|
||||
#endif /* ...ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ */
|
||||
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_DESERIALIZE_H_ */
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#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_
|
||||
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_
|
||||
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_
|
||||
|
||||
#include "core_message_types.h"
|
||||
#include "odk_structs.h"
|
||||
@@ -34,7 +34,7 @@ namespace serialize {
|
||||
*/
|
||||
bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
|
||||
const ODK_LicenseRequest& core_request,
|
||||
string* oemcrypto_core_message);
|
||||
std::string* oemcrypto_core_message);
|
||||
|
||||
/**
|
||||
* Counterpart (serializer) of ODK_ParseRenewal (deserializer)
|
||||
@@ -44,7 +44,7 @@ bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
|
||||
* [out] oemcrypto_core_message
|
||||
*/
|
||||
bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
|
||||
string* oemcrypto_core_message);
|
||||
std::string* oemcrypto_core_message);
|
||||
|
||||
/**
|
||||
* Counterpart (serializer) of ODK_ParseProvisioning (deserializer)
|
||||
@@ -57,8 +57,8 @@ bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
|
||||
*/
|
||||
bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
|
||||
const ODK_ProvisioningRequest& core_request,
|
||||
string* oemcrypto_core_message);
|
||||
std::string* oemcrypto_core_message);
|
||||
} /* namespace serialize */
|
||||
} /* namespace oemcrypto_core_message */
|
||||
|
||||
#endif /* ...ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ */
|
||||
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_H_ */
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
* 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_
|
||||
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_
|
||||
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
@@ -56,4 +56,4 @@ bool CreateCoreProvisioningResponseFromProto(
|
||||
} /* namespace serialize */
|
||||
} /* namespace oemcrypto_core_message */
|
||||
|
||||
#endif /* ...ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_ */
|
||||
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_SERIALIZE_PROTO_H_ */
|
||||
|
||||
@@ -49,16 +49,14 @@
|
||||
*********************************************************************/
|
||||
/* 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_
|
||||
#ifndef WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_
|
||||
#define WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace oemcrypto_core_message {
|
||||
|
||||
using std::string;
|
||||
|
||||
/* @ input/output structs */
|
||||
|
||||
/**
|
||||
@@ -90,9 +88,9 @@ struct ODK_ProvisioningRequest {
|
||||
uint32_t api_version;
|
||||
uint32_t nonce;
|
||||
uint32_t session_id;
|
||||
string device_id;
|
||||
std::string device_id;
|
||||
};
|
||||
|
||||
} /* namespace oemcrypto_core_message */
|
||||
|
||||
#endif /* ...ODK_INCLUDE_CORE_MESSAGE_TYPES_H_ */
|
||||
#endif /* WIDEVINE_ODK_INCLUDE_CORE_MESSAGE_TYPES_H_ */
|
||||
|
||||
@@ -42,8 +42,8 @@
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_ODK_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_INCLUDE_ODK_H_
|
||||
#ifndef WIDEVINE_ODK_INCLUDE_ODK_H_
|
||||
#define WIDEVINE_ODK_INCLUDE_ODK_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -304,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/out] clock_values: the session's clock values.
|
||||
* [in] clock_values: the session's clock values.
|
||||
* [in] system_time_seconds: the current time on OEMCrypto's clock, in
|
||||
* seconds.
|
||||
*
|
||||
@@ -590,4 +590,4 @@ OEMCryptoResult ODK_ParseProvisioning(
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ...ODK_INCLUDE_ODK_H_ */
|
||||
#endif /* WIDEVINE_ODK_INCLUDE_ODK_H_ */
|
||||
|
||||
27
oemcrypto/odk/include/odk_assert.h
Normal file
27
oemcrypto/odk/include/odk_assert.h
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
/*
|
||||
* 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_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (__STDC_VERSION__ >= 201112L)
|
||||
# include <assert.h>
|
||||
# define odk_static_assert static_assert
|
||||
#else
|
||||
# define odk_static_assert(msg, e) \
|
||||
enum { odk_static_assert = 1 / (!!((msg) && (e))) };
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ODK_ASSERT_H_ */
|
||||
33
oemcrypto/odk/include/odk_overflow.h
Normal file
33
oemcrypto/odk/include/odk_overflow.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
# define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ >= 5) || \
|
||||
__has_builtin(__builtin_add_overflow)
|
||||
# define odk_sub_overflow_u64 __builtin_sub_overflow
|
||||
# define odk_add_overflow_u64 __builtin_add_overflow
|
||||
# define odk_add_overflow_ux __builtin_add_overflow
|
||||
#else
|
||||
int odk_sub_overflow_u64(uint64_t a, uint64_t b, uint64_t* c);
|
||||
int odk_add_overflow_u64(uint64_t a, uint64_t b, uint64_t* c);
|
||||
int odk_add_overflow_ux(size_t a, size_t b, size_t* c);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ODK_OVERFLOW_H_ */
|
||||
44
oemcrypto/odk/include/odk_serialize.h
Normal file
44
oemcrypto/odk/include/odk_serialize.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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_
|
||||
|
||||
#include "odk_structs_priv.h"
|
||||
#include "serialization_base.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* odk pack */
|
||||
void Pack_ODK_PreparedLicense(Message* msg, ODK_PreparedLicense const* obj);
|
||||
void Pack_ODK_RenewalMessage(Message* msg, ODK_RenewalMessage const* obj);
|
||||
void Pack_ODK_ProvisioningMessage(Message* msg,
|
||||
ODK_ProvisioningMessage const* obj);
|
||||
|
||||
/* odk unpack */
|
||||
void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj);
|
||||
void Unpack_ODK_RenewalMessage(Message* msg, ODK_RenewalMessage* obj);
|
||||
void Unpack_ODK_ProvisioningResponse(Message* msg,
|
||||
ODK_ProvisioningResponse* obj);
|
||||
|
||||
/* kdo pack */
|
||||
void Pack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse const* obj);
|
||||
void Pack_ODK_ProvisioningResponse(Message* msg,
|
||||
ODK_ProvisioningResponse const* obj);
|
||||
|
||||
/* kdo unpack */
|
||||
void Unpack_ODK_PreparedLicense(Message* msg, ODK_PreparedLicense* obj);
|
||||
void Unpack_ODK_ProvisioningMessage(Message* msg, ODK_ProvisioningMessage* obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
#endif /* ODKITEE_SERIALIZER_H_ */
|
||||
@@ -2,8 +2,8 @@
|
||||
/* source code may only be used and distributed under the Widevine Master */
|
||||
/* License Agreement. */
|
||||
|
||||
#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_
|
||||
#ifndef WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
|
||||
#define WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -93,4 +93,4 @@ typedef struct {
|
||||
uint32_t session_id;
|
||||
} ODK_NonceValues;
|
||||
|
||||
#endif /* ...ODK_INCLUDE_ODK_STRUCTS_H_ */
|
||||
#endif /* WIDEVINE_ODK_INCLUDE_ODK_STRUCTS_H_ */
|
||||
|
||||
54
oemcrypto/odk/include/odk_structs_priv.h
Normal file
54
oemcrypto/odk/include/odk_structs_priv.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
#include "odk_structs.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 struct {
|
||||
uint32_t message_type;
|
||||
uint32_t message_length;
|
||||
ODK_NonceValues nonce_values;
|
||||
} ODK_CoreMessage;
|
||||
|
||||
typedef struct {
|
||||
ODK_CoreMessage core_message;
|
||||
} ODK_PreparedLicense;
|
||||
|
||||
typedef struct {
|
||||
ODK_CoreMessage core_message;
|
||||
uint64_t playback_time;
|
||||
} ODK_RenewalMessage;
|
||||
|
||||
typedef struct {
|
||||
ODK_CoreMessage core_message;
|
||||
uint32_t device_id_length;
|
||||
uint8_t device_id[ODK_DEVICE_ID_LEN_MAX];
|
||||
} ODK_ProvisioningMessage;
|
||||
|
||||
typedef struct {
|
||||
ODK_CoreMessage core_message;
|
||||
ODK_ParsedLicense* parsed_license;
|
||||
} ODK_LicenseResponse;
|
||||
|
||||
typedef struct {
|
||||
ODK_ProvisioningMessage core_provisioning;
|
||||
ODK_ParsedProvisioning* parsed_provisioning;
|
||||
} ODK_ProvisioningResponse;
|
||||
|
||||
#endif // ODK_STRUCTS_PRIV_H_
|
||||
91
oemcrypto/odk/include/serialization_base.h
Normal file
91
oemcrypto/odk/include/serialization_base.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "OEMCryptoCENCCommon.h"
|
||||
|
||||
#define SIZE_OF_MESSAGE_STRUCT 64
|
||||
|
||||
/*
|
||||
* Description:
|
||||
* Point |msg| to stack-array |blk|.
|
||||
* |blk| is guaranteed large enough to hold a |Message| struct.
|
||||
* |blk| cannot be used in the same scope as a variable name.
|
||||
* |msg| points to valid memory in the same scope |AllocateMessage| is used.
|
||||
* Parameters:
|
||||
* msg: pointer to pointer to |Message| struct
|
||||
* blk: variable name for stack-array
|
||||
*/
|
||||
#define AllocateMessage(msg, blk) \
|
||||
uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; \
|
||||
*(msg) = (Message*)(blk);
|
||||
|
||||
typedef struct _Message Message;
|
||||
|
||||
bool ValidMessage(Message* message);
|
||||
|
||||
void Pack_uint32_t(Message* message, const uint32_t* value);
|
||||
void Pack_uint64_t(Message* message, const uint64_t* value);
|
||||
void PackArray(Message* message, const uint8_t* base, size_t size);
|
||||
void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj);
|
||||
|
||||
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 Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj);
|
||||
|
||||
typedef enum {
|
||||
MESSAGE_STATUS_OK,
|
||||
MESSAGE_STATUS_UNKNOWN_ERROR,
|
||||
MESSAGE_STATUS_OVERFLOW_ERROR,
|
||||
MESSAGE_STATUS_UNDERFLOW_ERROR,
|
||||
MESSAGE_STATUS_PARSE_ERROR,
|
||||
MESSAGE_STATUS_NULL_POINTER_ERROR,
|
||||
MESSAGE_STATUS_API_VALUE_ERROR
|
||||
} MessageStatus;
|
||||
|
||||
/*
|
||||
* Create a message from a buffer. The message structure consumes the first
|
||||
* sizeof(Message) bytes of the buffer. The caller is responsible for ensuring
|
||||
* that the buffer remains allocated for the lifetime of the message.
|
||||
*/
|
||||
Message* CreateMessage(uint8_t* buffer, size_t buffer_size);
|
||||
|
||||
/*
|
||||
* Initialize a message structure to reference a separate buffer. The caller
|
||||
* is responsible for ensuring that the buffer remains allocated for the
|
||||
* lifetime of the message.
|
||||
*/
|
||||
void InitMessage(Message* message, uint8_t* buffer, size_t capacity);
|
||||
|
||||
/*
|
||||
* Reset an existing the message to an empty state
|
||||
*/
|
||||
void ResetMessage(Message* message);
|
||||
uint8_t* GetBase(Message* message);
|
||||
size_t GetCapacity(Message* message);
|
||||
size_t GetSize(Message* message);
|
||||
void SetSize(Message* message, size_t size);
|
||||
MessageStatus GetStatus(Message* message);
|
||||
void SetStatus(Message* message, MessageStatus status);
|
||||
size_t GetOffset(Message* message);
|
||||
|
||||
size_t SizeOfMessageStruct();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // ODKITEE_SERIALIZATION_BASE_H_
|
||||
172
oemcrypto/odk/kdo/include/oec_util.h
Normal file
172
oemcrypto/odk/kdo/include/oec_util.h
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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_
|
||||
59
oemcrypto/odk/kdo/include/oec_util_proto.h
Normal file
59
oemcrypto/odk/kdo/include/oec_util_proto.h
Normal 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.
|
||||
*/
|
||||
|
||||
/*********************************************************************
|
||||
* 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_
|
||||
@@ -31,8 +31,9 @@ const int LATEST_OEMCRYPTO_VERSION = 16;
|
||||
* 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) {
|
||||
bool ParseRequest(uint32_t message_type,
|
||||
const std::string& oemcrypto_core_message, S* core_request,
|
||||
T* prepared, const U unpacker) {
|
||||
if (core_request == nullptr || prepared == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -63,7 +64,7 @@ bool ParseRequest(uint32_t message_type, const string& oemcrypto_core_message,
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CoreLicenseRequestFromMessage(const string& oemcrypto_core_message,
|
||||
bool CoreLicenseRequestFromMessage(const std::string& oemcrypto_core_message,
|
||||
ODK_LicenseRequest* core_license_request) {
|
||||
const auto unpacker = Unpack_ODK_PreparedLicense;
|
||||
ODK_PreparedLicense prepared_license = {};
|
||||
@@ -71,7 +72,7 @@ bool CoreLicenseRequestFromMessage(const string& oemcrypto_core_message,
|
||||
core_license_request, &prepared_license, unpacker);
|
||||
}
|
||||
|
||||
bool CoreRenewalRequestFromMessage(const string& oemcrypto_core_message,
|
||||
bool CoreRenewalRequestFromMessage(const std::string& oemcrypto_core_message,
|
||||
ODK_RenewalRequest* core_renewal_request) {
|
||||
const auto unpacker = Unpack_ODK_RenewalMessage;
|
||||
ODK_RenewalMessage prepared_renewal = {};
|
||||
@@ -84,7 +85,7 @@ bool CoreRenewalRequestFromMessage(const string& oemcrypto_core_message,
|
||||
}
|
||||
|
||||
bool CoreProvisioningRequestFromMessage(
|
||||
const string& oemcrypto_core_message,
|
||||
const std::string& oemcrypto_core_message,
|
||||
ODK_ProvisioningRequest* core_provisioning_request) {
|
||||
const auto unpacker = Unpack_ODK_ProvisioningMessage;
|
||||
ODK_ProvisioningMessage prepared_provision = {};
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace {
|
||||
*/
|
||||
template <typename T, typename S, typename P>
|
||||
bool CreateResponse(uint32_t message_type, const S& core_request,
|
||||
string* oemcrypto_core_message, T& response,
|
||||
std::string* oemcrypto_core_message, T& response,
|
||||
const P& packer) {
|
||||
if (!oemcrypto_core_message) {
|
||||
return false;
|
||||
@@ -64,7 +64,7 @@ bool CreateResponse(uint32_t message_type, const S& core_request,
|
||||
bool CopyDeviceId(const ODK_ProvisioningRequest& src,
|
||||
ODK_ProvisioningResponse* dest) {
|
||||
auto& core_provisioning = dest->core_provisioning;
|
||||
const string& device_id = src.device_id;
|
||||
const std::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)) {
|
||||
@@ -80,7 +80,7 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src,
|
||||
|
||||
bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
|
||||
const ODK_LicenseRequest& core_request,
|
||||
string* oemcrypto_core_message) {
|
||||
std::string* oemcrypto_core_message) {
|
||||
ODK_LicenseResponse license_response{
|
||||
{}, const_cast<ODK_ParsedLicense*>(&parsed_lic)};
|
||||
return CreateResponse(ODK_License_Response_Type, core_request,
|
||||
@@ -89,7 +89,7 @@ bool CreateCoreLicenseResponse(const ODK_ParsedLicense& parsed_lic,
|
||||
}
|
||||
|
||||
bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
|
||||
string* oemcrypto_core_message) {
|
||||
std::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,
|
||||
@@ -99,7 +99,7 @@ bool CreateCoreRenewalResponse(const ODK_RenewalRequest& core_request,
|
||||
|
||||
bool CreateCoreProvisioningResponse(const ODK_ParsedProvisioning& parsed_prov,
|
||||
const ODK_ProvisioningRequest& core_request,
|
||||
string* oemcrypto_core_message) {
|
||||
std::string* oemcrypto_core_message) {
|
||||
ODK_ProvisioningResponse prov_response{
|
||||
{}, const_cast<ODK_ParsedProvisioning*>(&parsed_prov)};
|
||||
if (!CopyDeviceId(core_request, &prov_response)) {
|
||||
|
||||
@@ -192,7 +192,8 @@ OEMCryptoResult ODK_ParseLicense(
|
||||
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) {
|
||||
if (!message || !request_hash || !timer_limits || !clock_values ||
|
||||
!nonce_values || !parsed_license) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -238,8 +239,6 @@ OEMCryptoResult ODK_ParseLicense(
|
||||
if (usage_entry_present && parsed_license->pst.length == 0) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
/* If the license loaded OK, then we should save off the timer limits. */
|
||||
if (!timer_limits) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
*timer_limits = parsed_license->timer_limits;
|
||||
return err;
|
||||
}
|
||||
@@ -251,7 +250,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
const ODK_TimerLimits* timer_limits,
|
||||
ODK_ClockValues* clock_values,
|
||||
uint64_t* timer_value) {
|
||||
if (!nonce_values || !timer_limits || !clock_values) {
|
||||
if (!message || !nonce_values || !timer_limits || !clock_values) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -301,7 +300,7 @@ 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,
|
||||
size_t device_id_length, ODK_ParsedProvisioning* parsed_response) {
|
||||
if (!nonce_values || !device_id || !parsed_response) {
|
||||
if (!message || !nonce_values || !device_id || !parsed_response) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -313,7 +312,7 @@ OEMCryptoResult ODK_ParseProvisioning(
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
OEMCryptoResult err =
|
||||
const OEMCryptoResult err =
|
||||
ODK_ParseResponse(message, message_length, core_message_length,
|
||||
ODK_Provisioning_Response_Type, nonce_values,
|
||||
&provisioning_response.core_provisioning.core_message);
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/* 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_ASSERT_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_ASSERT_H_
|
||||
#ifndef WIDEVINE_ODK_SRC_ODK_ASSERT_H_
|
||||
#define WIDEVINE_ODK_SRC_ODK_ASSERT_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -21,4 +21,4 @@ extern "C" {
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ...ODK_SRC_ODK_ASSERT_H_ */
|
||||
#endif /* WIDEVINE_ODK_SRC_ODK_ASSERT_H_ */
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/* 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_
|
||||
#ifndef WIDEVINE_ODK_SRC_ODK_ENDIAN_H_
|
||||
#define WIDEVINE_ODK_SRC_ODK_ENDIAN_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -26,4 +26,4 @@ uint64_t oemcrypto_be64toh(uint64_t u64);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ...ODK_SRC_ODK_ENDIAN_H_ */
|
||||
#endif /* WIDEVINE_ODK_SRC_ODK_ENDIAN_H_ */
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/* 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_OVERFLOW_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_OVERFLOW_H_
|
||||
#ifndef WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_
|
||||
#define WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -28,4 +28,4 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ...ODK_SRC_ODK_OVERFLOW_H_ */
|
||||
#endif /* WIDEVINE_ODK_SRC_ODK_OVERFLOW_H_ */
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
/*
|
||||
* This code is auto-generated, do not edit
|
||||
*/
|
||||
#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_
|
||||
#ifndef WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_
|
||||
#define WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_
|
||||
|
||||
#include "odk_structs_priv.h"
|
||||
#include "serialization_base.h"
|
||||
@@ -39,4 +39,4 @@ void Unpack_ODK_ProvisioningMessage(Message* msg, ODK_ProvisioningMessage* obj);
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
#endif /* ...ODK_SRC_ODK_SERIALIZE_H_ */
|
||||
#endif /* WIDEVINE_ODK_SRC_ODK_SERIALIZE_H_ */
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/* 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_STRUCTS_PRIV_H_
|
||||
#define VIDEO_WIDEVINE_EXPORT_COMMON_OEMCRYPTO_CORE_MESSAGE_ODK_SRC_ODK_STRUCTS_PRIV_H_
|
||||
#ifndef WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_
|
||||
#define WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -50,4 +50,4 @@ typedef struct {
|
||||
ODK_ParsedProvisioning* parsed_provisioning;
|
||||
} ODK_ProvisioningResponse;
|
||||
|
||||
#endif /* ...ODK_SRC_ODK_STRUCTS_PRIV_H_ */
|
||||
#endif /* WIDEVINE_ODK_SRC_ODK_STRUCTS_PRIV_H_ */
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
/* source code may only be used and distributed under the Widevine Master */
|
||||
/* License Agreement. */
|
||||
|
||||
#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_
|
||||
#ifndef WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_
|
||||
#define WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -87,4 +87,4 @@ size_t SizeOfMessageStruct();
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* ...ODK_SRC_SERIALIZATION_BASE_H_ */
|
||||
#endif /* WIDEVINE_ODK_SRC_SERIALIZATION_BASE_H_ */
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include "odk_structs.h"
|
||||
#include "odk_structs_priv.h"
|
||||
|
||||
// TODO: remove this: using namespace std;
|
||||
// TODO: remove this: using namespace oec_util;
|
||||
// TODO(b/147297226): remove this: using namespace std;
|
||||
// TODO(b/147297226): remove this: using namespace oec_util;
|
||||
|
||||
typedef std::function<size_t(const uint8_t*, uint8_t*, size_t)> roundtrip_fun;
|
||||
|
||||
@@ -46,7 +46,7 @@ static OEMCryptoResult odk_fun_RenewalRequest(
|
||||
static OEMCryptoResult odk_fun_ProvisioningRequest(
|
||||
uint8_t* out, size_t* size, uint32_t api_version, uint32_t nonce,
|
||||
uint32_t session_id, const ODK_ProvisioningRequest& core_provisioning) {
|
||||
const string& device_id = core_provisioning.device_id;
|
||||
const std::string& device_id = core_provisioning.device_id;
|
||||
return ODK_PrepareCoreProvisioningRequest(
|
||||
out, SIZE_MAX, size, api_version, nonce, session_id,
|
||||
reinterpret_cast<const uint8_t*>(device_id.data()), device_id.size());
|
||||
@@ -55,7 +55,7 @@ static OEMCryptoResult odk_fun_ProvisioningRequest(
|
||||
template <typename T, typename F, typename G>
|
||||
static roundtrip_fun kdo_odk(const F& kdo_fun, const G& odk_fun) {
|
||||
auto roundtrip = [&](const uint8_t* in, uint8_t* out, size_t size) -> size_t {
|
||||
string input(reinterpret_cast<const char*>(in), size);
|
||||
std::string input(reinterpret_cast<const char*>(in), size);
|
||||
T t = {};
|
||||
if (!kdo_fun(input, &t)) {
|
||||
return 0;
|
||||
@@ -104,7 +104,7 @@ static OEMCryptoResult odk_fun_LicenseResponse(
|
||||
|
||||
static bool kdo_fun_LicenseResponse(const ODK_ParseLicense_Args* args,
|
||||
const ODK_ParsedLicense& parsed_lic,
|
||||
string* oemcrypto_core_message) {
|
||||
std::string* oemcrypto_core_message) {
|
||||
const auto& common = args->common;
|
||||
ODK_LicenseRequest core_request{common.api_version, common.nonce,
|
||||
common.session_id};
|
||||
@@ -133,7 +133,7 @@ static OEMCryptoResult odk_fun_RenewalResponse(
|
||||
|
||||
static bool kdo_fun_RenewalResponse(const ODK_ParseRenewal_Args* args,
|
||||
const ODK_RenewalMessage& renewal_msg,
|
||||
string* oemcrypto_core_message) {
|
||||
std::string* oemcrypto_core_message) {
|
||||
const auto& common = args->common;
|
||||
ODK_RenewalRequest core_request{common.api_version, common.nonce,
|
||||
common.session_id, renewal_msg.playback_time};
|
||||
@@ -150,13 +150,14 @@ static OEMCryptoResult odk_fun_ProvisioningResponse(
|
||||
|
||||
static bool kdo_fun_ProvisioningResponse(
|
||||
const ODK_ParseProvisioning_Args* args,
|
||||
const ODK_ParsedProvisioning& parsed_prov, string* oemcrypto_core_message) {
|
||||
const ODK_ParsedProvisioning& parsed_prov,
|
||||
std::string* oemcrypto_core_message) {
|
||||
const auto& common = args->common;
|
||||
assert(args->device_id_length <= sizeof(args->device_id));
|
||||
ODK_ProvisioningRequest core_request{
|
||||
common.api_version, common.nonce, common.session_id,
|
||||
string(reinterpret_cast<const char*>(args->device_id),
|
||||
args->device_id_length)};
|
||||
std::string(reinterpret_cast<const char*>(args->device_id),
|
||||
args->device_id_length)};
|
||||
return CreateCoreProvisioningResponse(parsed_prov, core_request,
|
||||
oemcrypto_core_message);
|
||||
}
|
||||
@@ -181,7 +182,7 @@ static roundtrip_fun odk_kdo(const F& odk_fun, const G& kdo_fun) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
string oemcrypto_core_message;
|
||||
std::string oemcrypto_core_message;
|
||||
if (!kdo_fun(args, t, &oemcrypto_core_message)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,12 @@
|
||||
|
||||
#include "odk.h"
|
||||
|
||||
#include <endian.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -260,7 +254,13 @@ void expect_eq_buf(const void* s1, const void* s2, size_t n,
|
||||
const void* buffers[] = {s1, s2};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
char _tmp[] = "/tmp/fileXXXXXX";
|
||||
mkstemp(_tmp);
|
||||
const int temp_fd = mkstemp(_tmp);
|
||||
if (temp_fd >= 0) {
|
||||
close(temp_fd);
|
||||
} else {
|
||||
std::cerr << "Failed to open temp file." << std::endl;
|
||||
break;
|
||||
}
|
||||
std::string tmp(_tmp);
|
||||
std::fstream out(tmp, std::ios::out | std::ios::binary);
|
||||
out.write(static_cast<const char*>(buffers[i]), n);
|
||||
@@ -465,9 +465,9 @@ TEST(OdkTest, LicenseRequest) {
|
||||
}
|
||||
|
||||
TEST(OdkTest, RenewalRequest) {
|
||||
uint64_t system_time_seconds = 0xBADDCAFE000FF1CE;
|
||||
const uint64_t system_time_seconds = 0xBADDCAFE000FF1CE;
|
||||
uint64_t playback_time = 0xCAFE00000000;
|
||||
uint64_t playback_start = system_time_seconds - playback_time;
|
||||
const uint64_t playback_start = system_time_seconds - playback_time;
|
||||
std::vector<ODK_Field> extra_fields = {
|
||||
{ODK_UINT64, &playback_time, "playback_time"},
|
||||
};
|
||||
@@ -617,8 +617,9 @@ TEST(OdkTest, LicenseResponse) {
|
||||
auto odk_parse_func = [&](const uint8_t* buf, size_t size,
|
||||
ODK_NonceValues* nonce_values) {
|
||||
ODK_TimerLimits timer_limits;
|
||||
ODK_ClockValues clock_values;
|
||||
return ODK_ParseLicense(buf, size + 128, size, true, false, request_hash,
|
||||
&timer_limits, nullptr, nonce_values,
|
||||
&timer_limits, &clock_values, nonce_values,
|
||||
&parsed_license);
|
||||
};
|
||||
auto kdo_prepare_func = [&](const ODK_LicenseRequest& core_request,
|
||||
|
||||
64
oemcrypto/odk/test/odk_test.h
Normal file
64
oemcrypto/odk/test/odk_test.h
Normal 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.
|
||||
*/
|
||||
|
||||
#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_
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <stddef.h>
|
||||
@@ -356,8 +357,9 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadKeys(
|
||||
"range check iv]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
} else {
|
||||
if (memcmp(message + enc_mac_keys.offset - wvoec::KEY_IV_SIZE,
|
||||
message + enc_mac_keys_iv.offset, wvoec::KEY_IV_SIZE) == 0) {
|
||||
if (CRYPTO_memcmp(message + enc_mac_keys.offset - wvoec::KEY_IV_SIZE,
|
||||
message + enc_mac_keys_iv.offset,
|
||||
wvoec::KEY_IV_SIZE) == 0) {
|
||||
LOGE("[OEMCrypto_LoadKeys(): OEMCrypto_ERROR_INVALID_CONTEXT - "
|
||||
"suspicious iv]");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/sha.h>
|
||||
@@ -643,7 +644,7 @@ bool SessionContext::ValidateMessage(const uint8_t* given_message,
|
||||
LOGE("ValidateMessage: Could not compute signature");
|
||||
return false;
|
||||
}
|
||||
if (memcmp(given_signature, computed_signature, signature_length)) {
|
||||
if (CRYPTO_memcmp(given_signature, computed_signature, signature_length)) {
|
||||
LOGE("Invalid signature given: %s",
|
||||
wvcdm::HexEncode(given_signature, signature_length).c_str());
|
||||
LOGE("Invalid signature computed: %s",
|
||||
@@ -1375,7 +1376,8 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
|
||||
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
|
||||
if (HMAC(EVP_sha256(), &key[0], key.size(), in_buffer, buffer_length,
|
||||
computed_signature, &md_len)) {
|
||||
if (0 == memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH)) {
|
||||
if (0 ==
|
||||
CRYPTO_memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH)) {
|
||||
return OEMCrypto_SUCCESS;
|
||||
} else {
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/mem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
@@ -79,15 +80,17 @@ bool UsageTableEntry::VerifyPST(const uint8_t* pst, size_t pst_length) {
|
||||
if (pst_length > kMaxPSTLength) return false;
|
||||
if (data_.pst_length != pst_length) return false;
|
||||
if (!pst || !pst_length) return false;
|
||||
return 0 == memcmp(pst, data_.pst, pst_length);
|
||||
return 0 == CRYPTO_memcmp(pst, data_.pst, pst_length);
|
||||
}
|
||||
|
||||
bool UsageTableEntry::VerifyMacKeys(const std::vector<uint8_t>& server,
|
||||
const std::vector<uint8_t>& client) {
|
||||
return (server.size() == wvoec::MAC_KEY_SIZE) &&
|
||||
(client.size() == wvoec::MAC_KEY_SIZE) &&
|
||||
(0 == memcmp(&server[0], data_.mac_key_server, wvoec::MAC_KEY_SIZE)) &&
|
||||
(0 == memcmp(&client[0], data_.mac_key_client, wvoec::MAC_KEY_SIZE));
|
||||
(0 == CRYPTO_memcmp(&server[0], data_.mac_key_server,
|
||||
wvoec::MAC_KEY_SIZE)) &&
|
||||
(0 ==
|
||||
CRYPTO_memcmp(&client[0], data_.mac_key_client, wvoec::MAC_KEY_SIZE));
|
||||
}
|
||||
|
||||
bool UsageTableEntry::SetMacKeys(const std::vector<uint8_t>& server,
|
||||
@@ -117,7 +120,7 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
|
||||
data_.pst_length);
|
||||
return OEMCrypto_ERROR_WRONG_PST;
|
||||
}
|
||||
if (memcmp(&pst[0], data_.pst, data_.pst_length)) {
|
||||
if (CRYPTO_memcmp(&pst[0], data_.pst, data_.pst_length)) {
|
||||
LOGE("ReportUsage: wrong pst %s, should be %s.", wvcdm::b2a_hex(pst).c_str(),
|
||||
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
|
||||
return OEMCrypto_ERROR_WRONG_PST;
|
||||
@@ -254,7 +257,8 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
|
||||
LOGE("LoadUsageEntry: Could not sign entry.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (memcmp(clear->signature, encrypted->signature, SHA256_DIGEST_LENGTH)) {
|
||||
if (CRYPTO_memcmp(clear->signature, encrypted->signature,
|
||||
SHA256_DIGEST_LENGTH)) {
|
||||
LOGE("LoadUsageEntry: Signature did not match.");
|
||||
LOGE("LoadUsageEntry: Invalid signature given: %s",
|
||||
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
|
||||
@@ -530,7 +534,8 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
|
||||
LOGE("LoadUsageTableHeader: Could not sign entry.");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (memcmp(clear->signature, encrypted->signature, SHA256_DIGEST_LENGTH)) {
|
||||
if (CRYPTO_memcmp(clear->signature, encrypted->signature,
|
||||
SHA256_DIGEST_LENGTH)) {
|
||||
LOGE("LoadUsageTableHeader: Signature did not match.");
|
||||
LOGE("LoadUsageTableHeader: Invalid signature given: %s",
|
||||
wvcdm::HexEncode(encrypted->signature, sig_length).c_str());
|
||||
|
||||
176
oemcrypto/renewal/derive_key.cpp
Normal file
176
oemcrypto/renewal/derive_key.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
// 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 <assert.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
// clang-format off
|
||||
|
||||
// This is a test keybox. It will not be accepted by production systems.
|
||||
static std::vector<uint8_t> test_keybox = {
|
||||
// sample keybox used for test vectors
|
||||
// deviceID = WidevineTestOnlyKeybox000
|
||||
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
|
||||
0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79,
|
||||
0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, 0x30, 0x30,
|
||||
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
|
||||
// key
|
||||
0xe4, 0xff, 0x57, 0x4c, 0x32, 0x2e, 0xf5, 0x34,
|
||||
0x26, 0x21, 0x2c, 0xb3, 0xed, 0x37, 0xf3, 0x5e,
|
||||
|
||||
// data (system ID 7912 = 1EE8).
|
||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1e, 0xe8,
|
||||
0xca, 0x1e, 0x71, 0x7c, 0xfb, 0xe8, 0xa3, 0x94,
|
||||
0x52, 0x0a, 0x6b, 0x71, 0x37, 0xd2, 0x69, 0xfa,
|
||||
0x5a, 0xc6, 0xb5, 0x4c, 0x6b, 0x46, 0x63, 0x9b,
|
||||
0xbe, 0x80, 0x3d, 0xbb, 0x4f, 0xf7, 0x4c, 0x5f,
|
||||
0x6f, 0x55, 0x0e, 0x3d, 0x3d, 0x9a, 0xcf, 0x81,
|
||||
0x12, 0x5d, 0x52, 0xe0, 0x47, 0x8c, 0xda, 0x0b,
|
||||
0xf4, 0x31, 0x41, 0x13, 0xd0, 0xd5, 0x2d, 0xa0,
|
||||
0x5b, 0x20, 0x9a, 0xed, 0x51, 0x5d, 0x13, 0xd6,
|
||||
|
||||
// magic
|
||||
0x6b, 0x62, 0x6f, 0x78,
|
||||
|
||||
// Crc
|
||||
0x39, 0xf2, 0x94, 0xa7,
|
||||
};
|
||||
|
||||
const size_t DEVICE_KEY_OFFSET = 0x20;
|
||||
const size_t CA_TOKEN_OFFSET = 0x30;
|
||||
const size_t KEYBOX_VERSION_OFFSET = CA_TOKEN_OFFSET;
|
||||
const size_t SYSTEM_ID_OFFSET = CA_TOKEN_OFFSET + sizeof(uint32_t);
|
||||
const size_t CA_TOKEN_SIZE = 0x48;
|
||||
const size_t CA_TOKEN_END = CA_TOKEN_OFFSET + CA_TOKEN_SIZE;
|
||||
|
||||
// sample renewal key for testing
|
||||
static const std::vector<uint8_t> renewal_key = {
|
||||
0xfa, 0xfd, 0xc1, 0x1b, 0x55, 0x6f, 0xac, 0xd3,
|
||||
0x14, 0x62, 0x50, 0xa0, 0xf7, 0xa5, 0x1a, 0x0e
|
||||
};
|
||||
|
||||
static const std::string label = "Keyboxv3";
|
||||
static const std::vector<uint8_t> new_system_id = {0x00, 0x00, 0x23, 0x45};
|
||||
static const std::vector<uint8_t> new_keybox_version = {0x00, 0x00, 0x00, 0x03};
|
||||
|
||||
// clang-format on
|
||||
|
||||
static std::string GetSSLError() {
|
||||
char error_buffer[128];
|
||||
ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
|
||||
return error_buffer;
|
||||
}
|
||||
|
||||
// Derive the new device key from renewal key and context using
|
||||
// NIST 800-108 key derivation with 128-bit AES-128-CMAC as the pseudorandom
|
||||
// function in counter mode:
|
||||
//
|
||||
// New Device Key := PRF(renewal_key, 1 || label || 0x00 || context || L)
|
||||
// PRF := AES-128-CMAC
|
||||
// label := “Keyboxv3”
|
||||
// L=(unsigned long)0x80: 0x00|0x00|0x00|0x80
|
||||
static bool DeriveKey(const std::vector<uint8_t>& key,
|
||||
const std::vector<uint8_t>& context,
|
||||
std::vector<uint8_t>* out) {
|
||||
if (key.empty() || context.empty() || out == NULL) {
|
||||
std::cerr << "DeriveKey(): Invalid inputs" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> cmac_input;
|
||||
cmac_input.push_back(1);
|
||||
std::copy(label.begin(), label.end(), std::back_inserter(cmac_input));
|
||||
cmac_input.push_back(0x00);
|
||||
std::copy(context.begin(), context.end(), std::back_inserter(cmac_input));
|
||||
cmac_input.push_back(0x00);
|
||||
cmac_input.push_back(0x00);
|
||||
cmac_input.push_back(0x00);
|
||||
cmac_input.push_back(0x80);
|
||||
|
||||
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
|
||||
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
|
||||
|
||||
if (!cmac_ctx) {
|
||||
std::cerr << "DeriveKey(): Failed to create context: " << GetSSLError()
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, 0)) {
|
||||
std::cerr << "DeriveKey(): Failed to initialize: " << GetSSLError()
|
||||
<< std::endl;
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMAC_Update(cmac_ctx, &cmac_input[0], cmac_input.size())) {
|
||||
std::cerr << "DeriveKey(): Failed to update: " << GetSSLError()
|
||||
<< std::endl;
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t reslen;
|
||||
uint8_t res[128];
|
||||
if (!CMAC_Final(cmac_ctx, res, &reslen)) {
|
||||
std::cerr << "DeriveKey(): Failed to finalize: " << GetSSLError()
|
||||
<< std::endl;
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
out->assign(res, res + reslen);
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "usage: " << argv[0] << " <new_key_filename>" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
std::string filename = argv[1];
|
||||
std::ofstream new_key_file;
|
||||
new_key_file.open(filename, std::ios::binary);
|
||||
if (!new_key_file) {
|
||||
std::cerr << "unable to open " << filename << " for writing" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// patch the keybox with version 3 and system ID
|
||||
std::copy(new_keybox_version.begin(), new_keybox_version.end(),
|
||||
test_keybox.begin() + KEYBOX_VERSION_OFFSET);
|
||||
std::copy(new_system_id.begin(), new_system_id.end(),
|
||||
test_keybox.begin() + SYSTEM_ID_OFFSET);
|
||||
|
||||
// context is Device Key || CA token
|
||||
std::vector<uint8_t> context(test_keybox.begin() + DEVICE_KEY_OFFSET,
|
||||
test_keybox.begin() + CA_TOKEN_END);
|
||||
|
||||
// derive the new device key
|
||||
std::vector<uint8_t> new_device_key;
|
||||
if (!DeriveKey(renewal_key, context, &new_device_key)) {
|
||||
std::cerr << "Failed to derive new renewal key" << std::endl;
|
||||
exit(-1);
|
||||
} else {
|
||||
std::ostream_iterator<uint8_t> output_iterator(new_key_file);
|
||||
std::copy(new_device_key.begin(), new_device_key.end(), output_iterator);
|
||||
new_key_file.close();
|
||||
std::cout << "New key written to " << filename << std::endl;
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -981,15 +981,12 @@ void Session::EncryptCTR(const vector<uint8_t>& in_buffer, const uint8_t* key,
|
||||
|
||||
void Session::TestDecryptCTR(bool select_key_first,
|
||||
OEMCryptoResult expected_result, int key_index) {
|
||||
OEMCryptoResult sts;
|
||||
OEMCryptoResult select_result = OEMCrypto_SUCCESS;
|
||||
if (select_key_first) {
|
||||
// Select the key (from FillSimpleMessage)
|
||||
sts = OEMCrypto_SelectKey(session_id(), license_.keys[key_index].key_id,
|
||||
license_.keys[key_index].key_id_length,
|
||||
OEMCrypto_CipherMode_CTR);
|
||||
if (expected_result == OEMCrypto_SUCCESS) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
select_result = OEMCrypto_SelectKey(
|
||||
session_id(), license_.keys[key_index].key_id,
|
||||
license_.keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR);
|
||||
}
|
||||
|
||||
// Create test sample description
|
||||
@@ -1012,43 +1009,50 @@ void Session::TestDecryptCTR(bool select_key_first,
|
||||
OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0};
|
||||
|
||||
// Decrypt the data
|
||||
sts = OEMCrypto_DecryptCENC(session_id(), &sample_description, 1, &pattern);
|
||||
|
||||
const OEMCryptoResult decrypt_result =
|
||||
OEMCrypto_DecryptCENC(session_id(), &sample_description, 1, &pattern);
|
||||
// We only have a few errors that we test are reported.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
TestDecryptResult(expected_result, select_result, decrypt_result))
|
||||
<< "Either SelectKey or DecryptCENC should return " << expected_result
|
||||
<< ", but they returned " << select_result << " and " << decrypt_result
|
||||
<< ", respectively.";
|
||||
if (expected_result == OEMCrypto_SUCCESS) { // No error.
|
||||
ASSERT_EQ(sts, OEMCrypto_SUCCESS);
|
||||
ASSERT_EQ(output_buffer, unencrypted_data);
|
||||
ASSERT_EQ(unencrypted_data, output_buffer);
|
||||
} else {
|
||||
ASSERT_NO_FATAL_FAILURE(TestDecryptResult(expected_result, sts));
|
||||
ASSERT_NE(output_buffer, unencrypted_data);
|
||||
ASSERT_NE(unencrypted_data, output_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Session::TestDecryptResult(OEMCryptoResult expected_result,
|
||||
OEMCryptoResult actual_result) {
|
||||
|
||||
OEMCryptoResult actual_select_result,
|
||||
OEMCryptoResult actual_decrypt_result) {
|
||||
// In most cases, we expect the result to come from either the select key or
|
||||
// from the decrypt call.
|
||||
if (expected_result == OEMCrypto_SUCCESS) { // No error.
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, actual_result);
|
||||
} else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED &&
|
||||
global_features.api_version >= 9) {
|
||||
// Report stale keys, required in v9 and beyond.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, actual_result);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, actual_select_result);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, actual_decrypt_result);
|
||||
} else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED ||
|
||||
expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP ||
|
||||
expected_result == OEMCrypto_ERROR_ANALOG_OUTPUT) {
|
||||
// Key expired or output problems may be reported from select key or
|
||||
// decrypt, but must be reported.
|
||||
ASSERT_TRUE(actual_select_result == expected_result ||
|
||||
actual_decrypt_result == expected_result);
|
||||
} else if (expected_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION &&
|
||||
global_features.api_version >= kCoreMessagesAPI) {
|
||||
// OEMCrypto is allowed to report either this warning or
|
||||
// OEMCrypto_ERROR_INSUFFICIENT_HDCP depending on if it can disable
|
||||
// restricted displays.
|
||||
ASSERT_TRUE(actual_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION ||
|
||||
actual_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP);
|
||||
} else if (expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP) {
|
||||
// Report HDCP errors.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INSUFFICIENT_HDCP, actual_result);
|
||||
} else if (expected_result == OEMCrypto_ERROR_ANALOG_OUTPUT) {
|
||||
// Report analog errors.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_ANALOG_OUTPUT, actual_result);
|
||||
ASSERT_TRUE(
|
||||
actual_select_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION ||
|
||||
actual_select_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP ||
|
||||
actual_decrypt_result == OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION ||
|
||||
actual_decrypt_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP);
|
||||
} else {
|
||||
// OEM's can fine tune other error codes for debugging.
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, actual_result);
|
||||
ASSERT_TRUE(actual_select_result != OEMCrypto_SUCCESS ||
|
||||
actual_decrypt_result != OEMCrypto_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1398,25 +1402,20 @@ void Session::VerifyPST(const Test_PST_Report& expected) {
|
||||
SHA_DIGEST_LENGTH));
|
||||
}
|
||||
|
||||
// This might adjust t to be "seconds since now". If t is small, we assume it
|
||||
// is "seconds since now", but if the value of t is large, assume it is
|
||||
// "absolute time" and convert to "seconds since now".
|
||||
static int64_t MaybeAdjustTime(int64_t t, int64_t now) {
|
||||
int64_t k10Minutes = 60 * 10; // in seconds.
|
||||
if (t > k10Minutes) return now - t;
|
||||
return t;
|
||||
}
|
||||
|
||||
void Session::VerifyReport(Test_PST_Report expected,
|
||||
int64_t time_license_received,
|
||||
int64_t time_first_decrypt,
|
||||
int64_t time_last_decrypt) {
|
||||
const int64_t now = wvcdm::Clock().GetCurrentTime();
|
||||
expected.seconds_since_license_received =
|
||||
MaybeAdjustTime(time_license_received, now);
|
||||
expected.seconds_since_license_received = now - time_license_received;
|
||||
expected.seconds_since_first_decrypt =
|
||||
MaybeAdjustTime(time_first_decrypt, now);
|
||||
expected.seconds_since_last_decrypt = MaybeAdjustTime(time_last_decrypt, now);
|
||||
(time_first_decrypt > 0 && time_first_decrypt < now)
|
||||
? now - time_first_decrypt
|
||||
: 0;
|
||||
expected.seconds_since_last_decrypt =
|
||||
(time_last_decrypt > 0 && time_last_decrypt < now)
|
||||
? now - time_last_decrypt
|
||||
: 0;
|
||||
ASSERT_NO_FATAL_FAILURE(VerifyPST(expected));
|
||||
}
|
||||
} // namespace wvoec
|
||||
|
||||
@@ -167,8 +167,8 @@ class RoundTrip {
|
||||
virtual void SignAndVerifyRequest();
|
||||
// Create a default |response_data| and |core_response|.
|
||||
virtual void CreateDefaultResponse() = 0;
|
||||
// Copy fields from |reponse_data| to |padded_response_data|, encrypting those
|
||||
// that should be encrypted. Serialize the core message. Then sign the
|
||||
// Copy fields from |response_data| to |padded_response_data|, encrypting
|
||||
// those that should be encrypted. Serialize the core message. Then sign the
|
||||
// response.
|
||||
virtual void EncryptAndSignResponse() = 0;
|
||||
// Attempt to load the response and return the error. Short buffer errors are
|
||||
@@ -460,10 +460,6 @@ class Session {
|
||||
void TestDecryptCTR(bool select_key_first = true,
|
||||
OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
|
||||
int key_index = 0);
|
||||
// This compares the actual result with the expected result. If OEMCrypto is
|
||||
// an older version, we allow it to report an equivalent error code.
|
||||
void TestDecryptResult(OEMCryptoResult expected_result,
|
||||
OEMCryptoResult actual_result);
|
||||
// Verify that an attempt to select an expired key either succeeds, or gives
|
||||
// an actionable error code.
|
||||
void TestSelectExpired(unsigned int key_index);
|
||||
@@ -572,6 +568,12 @@ class Session {
|
||||
}
|
||||
|
||||
private:
|
||||
// This compares the actual result with the expected result. If OEMCrypto is
|
||||
// an older version, we allow it to report an equivalent error code.
|
||||
void TestDecryptResult(OEMCryptoResult expected_result,
|
||||
OEMCryptoResult actual_select_result,
|
||||
OEMCryptoResult actual_decryt_result);
|
||||
|
||||
bool open_;
|
||||
bool forced_session_id_;
|
||||
OEMCrypto_SESSION session_id_;
|
||||
|
||||
@@ -816,7 +816,7 @@ class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16,
|
||||
public WithParamInterface<uint32_t> {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
// The only difference between this class and it's parent is that we use a
|
||||
// The only difference between this class and its parent is that we use a
|
||||
// different license api:
|
||||
license_api_version_ = GetParam();
|
||||
license_messages_.set_api_version(license_api_version_);
|
||||
@@ -827,7 +827,7 @@ class OEMCryptoLicenseTest : public OEMCryptoLicenseTestAPI16,
|
||||
// This class is used to test a license that is only for v15 license.
|
||||
class OEMCryptoLicenseTestAPI15 : public OEMCryptoLicenseTestAPI16 {
|
||||
void SetUp() override {
|
||||
// The only difference between this class and it's parent is that we use a
|
||||
// The only difference between this class and its parent is that we use a
|
||||
// different license api:
|
||||
license_api_version_ = 15;
|
||||
license_messages_.set_api_version(license_api_version_);
|
||||
@@ -2037,6 +2037,9 @@ class OEMCryptoSessionTestsDecryptTests
|
||||
switch (output_descriptor.type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
if (decrypt_inplace_) {
|
||||
// Add some padding to verify there is no overrun.
|
||||
sample.encrypted_buffer.resize(total_size + kBufferOverrunPadding,
|
||||
0xaa);
|
||||
output_descriptor.buffer.clear.address =
|
||||
sample.encrypted_buffer.data();
|
||||
} else {
|
||||
@@ -2227,15 +2230,20 @@ class OEMCryptoSessionTestsDecryptTests
|
||||
for (TestSample& sample : samples_) {
|
||||
if (sample.description.buffers.output_descriptor.type ==
|
||||
OEMCrypto_BufferType_Clear) {
|
||||
const size_t total_size = sample.description.buffers.input_data_length;
|
||||
// To verify there is no buffer overrun after decrypting, look at the
|
||||
// padded bytes just after the data buffer that was written. It should
|
||||
// not have changed from the original 0xaa that we set in MakeBuffer
|
||||
// function.
|
||||
if (decrypt_inplace_) {
|
||||
EXPECT_EQ(std::count(sample.encrypted_buffer.begin() + total_size,
|
||||
sample.encrypted_buffer.end(), 0xaa),
|
||||
static_cast<int32_t>(kBufferOverrunPadding))
|
||||
<< "Buffer overrun.";
|
||||
sample.encrypted_buffer.resize(total_size); // Remove padding.
|
||||
// We expect encrypted buffer to have been changed by OEMCrypto.
|
||||
EXPECT_EQ(sample.encrypted_buffer, sample.truth_buffer);
|
||||
} else {
|
||||
// If we are not decrypting in place, then look at the one byte just
|
||||
// after the data that was written. It should not have changed from
|
||||
// the original 0xaa that we set in MakeBuffersession_.
|
||||
const size_t total_size =
|
||||
sample.description.buffers.input_data_length;
|
||||
EXPECT_EQ(std::count(sample.clear_buffer.begin() + total_size,
|
||||
sample.clear_buffer.end(), 0xaa),
|
||||
static_cast<int32_t>(kBufferOverrunPadding))
|
||||
@@ -2337,8 +2345,17 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, EvenOffset) {
|
||||
TestSample& sample = samples_[0]; // There is only one sample in this test
|
||||
sample.truth_buffer.assign(sample.description.buffers.input_data_length, 0);
|
||||
ASSERT_NO_FATAL_FAILURE(EncryptData());
|
||||
sample.truth_buffer =
|
||||
sample.encrypted_buffer; // truth_buffer_ = encrypted zero buffer.
|
||||
if (decrypt_inplace_) {
|
||||
const size_t total_size = sample.description.buffers.input_data_length;
|
||||
// In case of decrypt_inplace_, encrypted_buffer contains padded bytes
|
||||
// which is used for buffer overrun validation. Do not copy the padded
|
||||
// bytes to truth_buffer.
|
||||
sample.truth_buffer.assign(sample.encrypted_buffer.begin(),
|
||||
sample.encrypted_buffer.begin() + total_size);
|
||||
} else {
|
||||
sample.truth_buffer =
|
||||
sample.encrypted_buffer; // truth_buffer_ = encrypted zero buffer.
|
||||
}
|
||||
// Run EncryptData to re-encrypt this buffer. For CTR mode, we should get
|
||||
// back to zeros.
|
||||
ASSERT_NO_FATAL_FAILURE(EncryptData());
|
||||
@@ -2536,7 +2553,9 @@ INSTANTIATE_TEST_CASE_P(
|
||||
Combine(
|
||||
Values(MakePattern(3, 7), MakePattern(9, 1),
|
||||
// HLS edge cases. We should follow the CENC spec, not HLS spec.
|
||||
MakePattern(1, 9), MakePattern(1, 0)),
|
||||
MakePattern(1, 9), MakePattern(1, 0),
|
||||
// AV1 patterns not already covered above.
|
||||
MakePattern(5, 5), MakePattern(10, 0)),
|
||||
Values(OEMCrypto_CipherMode_CBC),
|
||||
::testing::ValuesIn(global_features.GetOutputTypes())));
|
||||
|
||||
@@ -4596,8 +4615,7 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationEncrypt) {
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Encrypt(
|
||||
session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data());
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status));
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(encrypted, expected_encrypted);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index));
|
||||
}
|
||||
@@ -4631,8 +4649,7 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationDecrypt) {
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Decrypt(
|
||||
session_.session_id(), encrypted.data(), encrypted.size(), iv_,
|
||||
OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data());
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status));
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(clear_buffer_, resultant);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index));
|
||||
}
|
||||
@@ -4668,8 +4685,7 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationSign) {
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Sign(
|
||||
session_.session_id(), clear_buffer_.data(), clear_buffer_.size(),
|
||||
OEMCrypto_HMAC_SHA256, signature.data(), &signature_length);
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status));
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NE(expected_signature, signature);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index));
|
||||
}
|
||||
@@ -4702,8 +4718,7 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) {
|
||||
OEMCryptoResult status = OEMCrypto_Generic_Verify(
|
||||
session_.session_id(), clear_buffer_.data(), clear_buffer_.size(),
|
||||
OEMCrypto_HMAC_SHA256, signature.data(), signature.size());
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status));
|
||||
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
|
||||
ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index));
|
||||
}
|
||||
|
||||
@@ -4803,11 +4818,15 @@ INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest,
|
||||
Range<uint32_t>(kCurrentAPI - 1, kCurrentAPI + 1));
|
||||
|
||||
// Test usage table functionality.
|
||||
|
||||
class LicenseWithUsageEntry {
|
||||
public:
|
||||
LicenseWithUsageEntry(const std::string& pst = "my_pst")
|
||||
: session_(), license_messages_(&session_), generic_crypto_(false) {
|
||||
: session_(),
|
||||
license_messages_(&session_),
|
||||
generic_crypto_(false),
|
||||
time_license_received_(0),
|
||||
time_first_decrypt_(0),
|
||||
time_last_decrypt_(0) {
|
||||
license_messages_.set_pst(pst);
|
||||
}
|
||||
|
||||
@@ -4850,6 +4869,7 @@ class LicenseWithUsageEntry {
|
||||
ASSERT_NO_FATAL_FAILURE(session_.CreateNewUsageEntry(status));
|
||||
if (status != nullptr && *status != OEMCrypto_SUCCESS) return;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
time_license_received_ = wvcdm::Clock().GetCurrentTime();
|
||||
}
|
||||
|
||||
void OpenAndReload(SessionUtil* util) {
|
||||
@@ -4859,15 +4879,20 @@ class LicenseWithUsageEntry {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages_.LoadResponse());
|
||||
}
|
||||
|
||||
void GenerateVerifyReport(OEMCrypto_Usage_Entry_Status status,
|
||||
int64_t time_license_received = 0,
|
||||
int64_t time_first_decrypt = 0,
|
||||
int64_t time_last_decrypt = 0) {
|
||||
// Test decrypt, and update the decrypt times for the pst report.
|
||||
void TestDecryptCTR(bool select_key_first = true,
|
||||
OEMCryptoResult expected_result = OEMCrypto_SUCCESS) {
|
||||
session_.TestDecryptCTR(select_key_first, expected_result);
|
||||
time_last_decrypt_ = wvcdm::Clock().GetCurrentTime();
|
||||
if (time_first_decrypt_ == 0) time_first_decrypt_ = time_last_decrypt_;
|
||||
}
|
||||
|
||||
void GenerateVerifyReport(OEMCrypto_Usage_Entry_Status status) {
|
||||
ASSERT_NO_FATAL_FAILURE(session_.GenerateReport(pst()));
|
||||
Test_PST_Report expected(pst(), status);
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
session_.VerifyReport(expected, time_license_received,
|
||||
time_first_decrypt, time_last_decrypt));
|
||||
session_.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.
|
||||
RenewalRoundTrip renewal_messages(&license_messages_);
|
||||
@@ -4892,6 +4917,9 @@ class LicenseWithUsageEntry {
|
||||
Session session_;
|
||||
LicenseRoundTrip license_messages_;
|
||||
bool generic_crypto_;
|
||||
int64_t time_license_received_;
|
||||
int64_t time_first_decrypt_;
|
||||
int64_t time_last_decrypt_;
|
||||
};
|
||||
|
||||
class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest {
|
||||
@@ -4940,7 +4968,7 @@ TEST_P(OEMCryptoUsageTableTest, OnlineLicense) {
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
// Flag the entry as inactive.
|
||||
@@ -4950,7 +4978,7 @@ TEST_P(OEMCryptoUsageTableTest, OnlineLicense) {
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed));
|
||||
// Decrypt should fail.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
// We could call DeactivateUsageEntry multiple times. The state should not
|
||||
// change.
|
||||
ASSERT_NO_FATAL_FAILURE(s.DeactivateUsageEntry(entry.pst()));
|
||||
@@ -4976,7 +5004,7 @@ TEST_P(OEMCryptoUsageTableTest, OnlineLicenseUnused) {
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused));
|
||||
// Decrypt should fail.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
// We could call DeactivateUsageEntry multiple times. The state should not
|
||||
// change.
|
||||
ASSERT_NO_FATAL_FAILURE(s.DeactivateUsageEntry(entry.pst()));
|
||||
@@ -4994,7 +5022,7 @@ TEST_P(OEMCryptoUsageTableTest, ForbidReportWithNoUpdate) {
|
||||
Session& s = entry.session();
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
// Cannot generate a report without first updating the file.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.GenerateReport(entry.pst(), OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE));
|
||||
@@ -5008,7 +5036,7 @@ TEST_P(OEMCryptoUsageTableTest, ForbidReportWithNoUpdate) {
|
||||
s.GenerateReport(entry.pst(), OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE));
|
||||
// Decrypt should fail.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
}
|
||||
|
||||
// Test an online license with a license renewal.
|
||||
@@ -5017,18 +5045,13 @@ TEST_P(OEMCryptoUsageTableTest, OnlineLicenseWithRefreshAPI16) {
|
||||
entry.license_messages().set_api_version(license_api_version_);
|
||||
entry.MakeAndLoadOnline(this);
|
||||
Session& s = entry.session();
|
||||
const int64_t loaded = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
|
||||
RenewalRoundTrip renewal_messages(&entry.license_messages());
|
||||
MakeRenewalRequest(&renewal_messages);
|
||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(
|
||||
kActive,
|
||||
loaded, // when license loaded. (not refreshed)
|
||||
loaded, // first decrypt.
|
||||
0)); // last decrypt is now.
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
}
|
||||
|
||||
// Verify that a streaming license cannot be reloaded.
|
||||
@@ -5314,19 +5337,14 @@ TEST_P(OEMCryptoUsageTableTest, OfflineLicenseRefresh) {
|
||||
entry.MakeAndLoad(this, wvoec::kControlNonceOrEntry);
|
||||
Session& s = entry.session();
|
||||
|
||||
const int64_t loaded = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
// License renewal message is signed by client and verified by the server.
|
||||
RenewalRoundTrip renewal_messages(&entry.license_messages());
|
||||
MakeRenewalRequest(&renewal_messages);
|
||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(
|
||||
kActive,
|
||||
loaded, // license received.
|
||||
loaded, // First decrypt when loaded, not refresh.
|
||||
0)); // last decrypt now.
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
}
|
||||
|
||||
// Test that an offline license can be reloaded in a new session.
|
||||
@@ -5338,7 +5356,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicense) {
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
}
|
||||
@@ -5350,24 +5368,18 @@ TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithRefresh) {
|
||||
entry.license_messages().set_api_version(license_api_version_);
|
||||
entry.MakeOfflineAndClose(this);
|
||||
Session& s = entry.session();
|
||||
const int64_t loaded = wvcdm::Clock().GetCurrentTime();
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused, loaded, 0, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
const int64_t decrypt_time = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
RenewalRoundTrip renewal_messages(&entry.license_messages());
|
||||
MakeRenewalRequest(&renewal_messages);
|
||||
LoadRenewal(&renewal_messages, OEMCrypto_SUCCESS);
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
entry.GenerateVerifyReport(kActive,
|
||||
loaded, // license loaded.
|
||||
decrypt_time, // first decrypt
|
||||
0)); // last decrypt
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
}
|
||||
|
||||
// Verify that we can still reload an offline license after OEMCrypto_Terminate
|
||||
@@ -5387,7 +5399,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithTerminate) {
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
}
|
||||
@@ -5400,7 +5412,6 @@ TEST_P(OEMCryptoUsageTableTest, BadReloadOfflineLicense) {
|
||||
entry.license_messages().set_api_version(license_api_version_);
|
||||
entry.MakeOfflineAndClose(this);
|
||||
Session& s = entry.session();
|
||||
const int64_t loaded = wvcdm::Clock().GetCurrentTime();
|
||||
|
||||
// Offline license with new mac keys should fail.
|
||||
Session s2;
|
||||
@@ -5421,11 +5432,7 @@ TEST_P(OEMCryptoUsageTableTest, BadReloadOfflineLicense) {
|
||||
// Now we go back to the original license response. It should load OK.
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
entry.GenerateVerifyReport(kUnused,
|
||||
loaded, // license loaded.
|
||||
0,
|
||||
0)); // first and last decrypt
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
}
|
||||
|
||||
// An offline license should not load on the first call if the nonce is bad.
|
||||
@@ -5495,12 +5502,13 @@ TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicense) {
|
||||
Session& s = entry.session();
|
||||
// Reload the offline license.
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); // Should be able to decrypt.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
entry.TestDecryptCTR()); // Should be able to decrypt.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.DeactivateUsageEntry(entry.pst())); // Then deactivate.
|
||||
// After deactivate, should not be able to decrypt.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
@@ -5540,7 +5548,7 @@ TEST_P(OEMCryptoUsageTableTest, DeactivateOfflineLicenseUnused) {
|
||||
s.DeactivateUsageEntry(entry.pst())); // Then deactivate.
|
||||
// After deactivate, should not be able to decrypt.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
@@ -5591,14 +5599,13 @@ TEST_P(OEMCryptoUsageTableTest, UpdateFailsWithNullPtr) {
|
||||
// Class used to test usage table defragmentation.
|
||||
class OEMCryptoUsageTableDefragTest : public OEMCryptoUsageTableTest {
|
||||
protected:
|
||||
void ReloadLicense(LicenseWithUsageEntry* entry, int64_t start) {
|
||||
void ReloadLicense(LicenseWithUsageEntry* entry) {
|
||||
Session& s = entry->session();
|
||||
ASSERT_NO_FATAL_FAILURE(entry->OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry->TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
entry->GenerateVerifyReport(kActive, start, start, 0));
|
||||
ASSERT_NO_FATAL_FAILURE(entry->GenerateVerifyReport(kActive));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
|
||||
@@ -5640,13 +5647,11 @@ class OEMCryptoUsageTableDefragTest : public OEMCryptoUsageTableTest {
|
||||
TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) {
|
||||
const size_t ENTRY_COUNT = 10;
|
||||
vector<LicenseWithUsageEntry> entries(ENTRY_COUNT);
|
||||
vector<int64_t> start(ENTRY_COUNT);
|
||||
for (size_t i = 0; i < ENTRY_COUNT; i++) {
|
||||
entries[i].set_pst("pst " + std::to_string(i));
|
||||
ASSERT_NO_FATAL_FAILURE(entries[i].MakeOfflineAndClose(this))
|
||||
<< "On license " << i << " pst=" << entries[i].pst();
|
||||
wvcdm::TestSleep::SyncFakeClock();
|
||||
start[i] = wvcdm::Clock().GetCurrentTime();
|
||||
}
|
||||
for (size_t i = 0; i < ENTRY_COUNT; i++) {
|
||||
ASSERT_NO_FATAL_FAILURE(entries[i].OpenAndReload(this))
|
||||
@@ -5665,10 +5670,10 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) {
|
||||
OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(),
|
||||
encrypted_usage_header_.size()));
|
||||
wvcdm::TestSleep::SyncFakeClock();
|
||||
ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[0], start[0]));
|
||||
ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[0]));
|
||||
// Now has index 1.
|
||||
ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[4], start[4]));
|
||||
ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[2], start[2]));
|
||||
ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[4]));
|
||||
ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[2]));
|
||||
// When 4 was moved to 1, it increased the gen. number in the header.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
FailReloadLicense(&entries[1], OEMCrypto_ERROR_GENERATION_SKEW));
|
||||
@@ -5853,11 +5858,12 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) {
|
||||
}
|
||||
// Make sure that all of the licenses can be reloaded.
|
||||
for (size_t i = 0; i < entries.size(); i++) {
|
||||
wvcdm::TestSleep::SyncFakeClock();
|
||||
Session& s = entries[i]->session();
|
||||
ASSERT_NO_FATAL_FAILURE(entries[i]->OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kUnused));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entries[i]->TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entries[i]->GenerateVerifyReport(kActive));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
@@ -5970,25 +5976,19 @@ TEST_P(OEMCryptoUsageTableTest, TimingTest) {
|
||||
ASSERT_NO_FATAL_FAILURE(entry3.MakeOfflineAndClose(this));
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entry1.MakeOfflineAndClose(this));
|
||||
const int64_t loaded1 = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.MakeOfflineAndClose(this));
|
||||
const int64_t loaded2 = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(entry3.MakeOfflineAndClose(this));
|
||||
const int64_t loaded3 = wvcdm::Clock().GetCurrentTime();
|
||||
|
||||
wvcdm::TestSleep::Sleep(kLongSleep);
|
||||
ASSERT_NO_FATAL_FAILURE(entry1.OpenAndReload(this));
|
||||
const int64_t first_decrypt1 = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR());
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this));
|
||||
const int64_t first_decrypt2 = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR());
|
||||
|
||||
wvcdm::TestSleep::Sleep(kLongSleep);
|
||||
const int64_t second_decrypt = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry1.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR());
|
||||
|
||||
wvcdm::TestSleep::Sleep(kLongSleep);
|
||||
ASSERT_NO_FATAL_FAILURE(s1.DeactivateUsageEntry(entry1.pst()));
|
||||
@@ -6008,9 +6008,8 @@ TEST_P(OEMCryptoUsageTableTest, TimingTest) {
|
||||
|
||||
// After a reboot, we should be able to reload keys, and generate reports.
|
||||
wvcdm::TestSleep::Sleep(kLongSleep);
|
||||
const int64_t third_decrypt = wvcdm::Clock().GetCurrentTime();
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.close());
|
||||
|
||||
@@ -6028,13 +6027,11 @@ TEST_P(OEMCryptoUsageTableTest, TimingTest) {
|
||||
entry3.license_messages().set_api_version(global_features.api_version);
|
||||
wvcdm::TestSleep::Sleep(kLongSleep);
|
||||
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry1.GenerateVerifyReport(
|
||||
kInactiveUsed, loaded1, first_decrypt1, second_decrypt));
|
||||
ASSERT_NO_FATAL_FAILURE(entry1.GenerateVerifyReport(kInactiveUsed));
|
||||
ASSERT_NO_FATAL_FAILURE(s2.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.GenerateVerifyReport(
|
||||
kActive, loaded2, first_decrypt2, third_decrypt));
|
||||
ASSERT_NO_FATAL_FAILURE(entry2.GenerateVerifyReport(kActive));
|
||||
ASSERT_NO_FATAL_FAILURE(s3.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry3.GenerateVerifyReport(kUnused, loaded3));
|
||||
ASSERT_NO_FATAL_FAILURE(entry3.GenerateVerifyReport(kUnused));
|
||||
}
|
||||
|
||||
// Verify the times in the usage report. For performance reasons, we allow the
|
||||
@@ -6047,7 +6044,6 @@ TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) {
|
||||
entry.license_messages().set_api_version(license_api_version_);
|
||||
entry.MakeAndLoadOnline(this);
|
||||
Session& s = entry.session();
|
||||
const int64_t load_time = wvcdm::Clock().GetCurrentTime();
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
@@ -6067,18 +6063,16 @@ TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) {
|
||||
PrintDotsWhileSleep(kIdleInSeconds, kDotIntervalInSeconds);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused, load_time));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kUnused));
|
||||
cout << "Start simulated playback..." << endl;
|
||||
|
||||
int64_t dot_time = kDotIntervalInSeconds;
|
||||
int64_t playback_time = 0;
|
||||
const int64_t start_time = wvcdm::Clock().GetCurrentTime();
|
||||
do {
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
entry.GenerateVerifyReport(kActive, load_time, start_time,
|
||||
0)); // last decrypt = now.
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
wvcdm::TestSleep::Sleep(kShortSleep);
|
||||
playback_time = wvcdm::Clock().GetCurrentTime() - start_time;
|
||||
ASSERT_LE(0, playback_time);
|
||||
@@ -6091,9 +6085,7 @@ TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) {
|
||||
cout << "\nSimulated playback time = " << playback_time << " seconds.\n";
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
entry.GenerateVerifyReport(kActive, load_time, start_time,
|
||||
0)); // last decrypt = now.
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
EXPECT_NEAR(s.pst_report().seconds_since_first_decrypt() -
|
||||
s.pst_report().seconds_since_last_decrypt(),
|
||||
playback_time, kUsageTableTimeTolerance);
|
||||
@@ -6111,14 +6103,12 @@ TEST_P(OEMCryptoUsageTableTest, VerifyUsageTimes) {
|
||||
// |<----------------------------->| = seconds_since_first_decrypt
|
||||
// |<------------------------------------| = seconds_since_license_received
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(
|
||||
kActive, load_time, start_time, kIdleInSeconds));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kActive));
|
||||
ASSERT_NO_FATAL_FAILURE(s.DeactivateUsageEntry(entry.pst()));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(
|
||||
kInactiveUsed, load_time, start_time, kIdleInSeconds));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
}
|
||||
|
||||
// This test class is only used to roll back the wall clock. It is used to
|
||||
@@ -6190,7 +6180,7 @@ TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) {
|
||||
// Monotonic clock can't be changed. We use this since system clock will be
|
||||
// unreliable.
|
||||
const auto first_decrypt_monotonic = monotonic_clock.now();
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
|
||||
@@ -6198,7 +6188,7 @@ TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) {
|
||||
wvcdm::TestSleep::Sleep(kLongDuration * 2);
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
|
||||
@@ -6210,7 +6200,7 @@ TEST_P(OEMCryptoUsageTableTestWallClock, TimeRollbackPrevention) {
|
||||
// Try to playback again.
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
const auto third_decrypt_monotonic = monotonic_clock.now();
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(entry.TestDecryptCTR());
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
Test_PST_Report expected(entry.pst(), kActive);
|
||||
@@ -6239,12 +6229,13 @@ TEST_P(OEMCryptoUsageTableTest, PSTLargeBuffer) {
|
||||
Session& s = entry.session();
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this));
|
||||
ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); // Should be able to decrypt.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
entry.TestDecryptCTR()); // Should be able to decrypt.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.DeactivateUsageEntry(entry.pst())); // Then deactivate.
|
||||
// After deactivate, should not be able to decrypt.
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
entry.TestDecryptCTR(false, OEMCrypto_ERROR_UNKNOWN_FAILURE));
|
||||
ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_));
|
||||
ASSERT_NO_FATAL_FAILURE(entry.GenerateVerifyReport(kInactiveUsed));
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
|
||||
Reference in New Issue
Block a user