diff --git a/whitebox/api/BUILD b/whitebox/api/BUILD index e457988..5876db0 100644 --- a/whitebox/api/BUILD +++ b/whitebox/api/BUILD @@ -19,6 +19,7 @@ cc_library( "ALWAYS_DECRYPT_TO_CLEAR", "HAS_GENERIC_CRYPTO", "HAS_SIGN_PST_REPORT", + "HAS_IMPORT_EXPORT", ], "//:is_old_api": [], "//:is_old_vmpra": [], @@ -36,6 +37,15 @@ cc_library( visibility = ["//visibility:public"], ) +cc_library( + name = "enums", + hdrs = [ + "enums.h", + ], + visibility = ["//visibility:public"], + deps = [":shared_settings"], +) + cc_library( name = "result", hdrs = [ @@ -52,6 +62,7 @@ cc_library( ], visibility = ["//visibility:public"], deps = [ + ":enums", ":result", ":shared_settings", ], @@ -61,9 +72,11 @@ cc_library( name = "license_whitebox", hdrs = [ "license_whitebox.h", + "license_whitebox_latest.h", ], visibility = ["//visibility:public"], deps = [ + ":enums", ":result", ":shared_settings", ], diff --git a/whitebox/api/enums.h b/whitebox/api/enums.h new file mode 100644 index 0000000..2483378 --- /dev/null +++ b/whitebox/api/enums.h @@ -0,0 +1,61 @@ +// Copyright 2024 Google LLC. All Rights Reserved. + +#ifndef WHITEBOX_API_ENUMS_H_ +#define WHITEBOX_API_ENUMS_H_ + +typedef enum { + WB_CIPHER_MODE_CTR, + WB_CIPHER_MODE_CBC, +} WB_CipherMode; + +typedef enum { + WB_KEY_QUERY_TYPE_SIGNING_KEY, + WB_KEY_QUERY_TYPE_CONTENT_KEY, + WB_KEY_QUERY_TYPE_GENERIC_KEY, +} WB_KeyQueryType; + +typedef enum { + WB_KCB_FLAGS_ALLOW_ENCRYPT = (1u << 8), + WB_KCB_FLAGS_ALLOW_DECRYPT = (1u << 7), + WB_KCB_FLAGS_ALLOW_SIGN = (1u << 6), + WB_KCB_FLAGS_ALLOW_VERIFY = (1u << 5), + + WB_KCB_FLAGS_GENERIC_MASK = 0x1e0, + WB_KCB_FLAGS_SECURITY_LEVEL_SHIFT = 26, + WB_KCB_FLAGS_SECURITY_LEVEL_MASK = 0x3 << WB_KCB_FLAGS_SECURITY_LEVEL_SHIFT, +} WB_KcbFlags; + +typedef enum { + // The key was found in the license but there was something wrong it and could + // not be loaded. + WB_KEY_STATUS_INVALID, + + // The key was found in the license and can be used with + // |WB_License_SignRenewalRequest()| and with + // |WB_License_VerifyRenewalResponse()|. + WB_KEY_STATUS_SIGNING_KEY_VALID, + + // The key was found in the license. However, the permisions of the key are + // different depending on its status. + // + // | DECRYPT | MASKED DECRYPT | + // ---------------+---------+----------------+ + // VALID | No | No | + // MASKED_DECRYPT | No | Yes | + // DECRYPT | Yes | Yes | + WB_KEY_STATUS_CONTENT_KEY_VALID, + WB_KEY_STATUS_CONTENT_KEY_MASKED_DECRYPT, + WB_KEY_STATUS_CONTENT_KEY_DECRYPT, +} WB_KeyStatus; + +typedef enum { + // The license response uses single key - the license signing and encryption + // key are the same. + WB_LICENSE_KEY_MODE_SINGLE_KEY, + + // The license response uses two keys - the license signing and encryption + // key are different. + WB_LICENSE_KEY_MODE_DUAL_KEY, +} WB_LicenseKeyMode; + +#endif // WHITEBOX_API_ENUMS_H_ diff --git a/whitebox/api/license_whitebox.h b/whitebox/api/license_whitebox.h index 6f339bb..2c19458 100644 --- a/whitebox/api/license_whitebox.h +++ b/whitebox/api/license_whitebox.h @@ -1,74 +1,48 @@ // Copyright 2020 Google LLC. All Rights Reserved. -#ifndef WHITEBOX_API_LICENSE_WHITEBOX_H_ -#define WHITEBOX_API_LICENSE_WHITEBOX_H_ +// #ifndef WHITEBOX_API_LICENSE_WHITEBOX_H_ +// Don't use header guards to allow including the same header with different +// versions. For example: +// +// #include "license_whitebox.h" // Adds WB_License_Create +// #define WB_VERSION 28 +// #include "license_whitebox.h" // Adds WB_License_Create_v28 +// #define WB_VERSION 29 +// #include "license_whitebox.h" // Adds WB_License_Create_v29 +// +// This file should only contain forward declarations. It cannot contain +// definitions like classes, enums, or typedefs. #include #include +#include "api/enums.h" #include "api/result.h" +// Define WB_VERSION to concat that version to the function names. If it isn't +// defined, we will define non-versioned function names. +// #define WB_VERSION 28 + +#ifdef WB_VERSION +// We do this triple-indirection here since the ## operator handles arguments +// a bit weird and we want to expand the WB_RESULT as a value, not an identifier +// +// WB_CONCAT_VERSION(Foo) -> Foo_v28 +# define WB_CONCAT_VERSION__(a, b) a ## b +# define WB_CONCAT_VERSION_(name, version) \ + WB_CONCAT_VERSION__(name ## _v, version) +# define WB_CONCAT_VERSION(name) WB_CONCAT_VERSION_(name, WB_VERSION) +#else +# define WB_CONCAT_VERSION(name) name +#endif + #ifdef __cplusplus extern "C" { #endif // The opaque type representing a single white-box instance. -typedef struct WB_License_Whitebox WB_License_Whitebox; - -typedef enum { - WB_CIPHER_MODE_CTR, - WB_CIPHER_MODE_CBC, -} WB_CipherMode; - -typedef enum { - WB_KEY_QUERY_TYPE_SIGNING_KEY, - WB_KEY_QUERY_TYPE_CONTENT_KEY, - WB_KEY_QUERY_TYPE_GENERIC_KEY, -} WB_KeyQueryType; - -typedef enum { - WB_KCB_FLAGS_ALLOW_ENCRYPT = (1u << 8), - WB_KCB_FLAGS_ALLOW_DECRYPT = (1u << 7), - WB_KCB_FLAGS_ALLOW_SIGN = (1u << 6), - WB_KCB_FLAGS_ALLOW_VERIFY = (1u << 5), - - WB_KCB_FLAGS_GENERIC_MASK = 0x1e0, - WB_KCB_FLAGS_SECURITY_LEVEL_SHIFT = 26, - WB_KCB_FLAGS_SECURITY_LEVEL_MASK = 0x3 << WB_KCB_FLAGS_SECURITY_LEVEL_SHIFT, -} WB_KcbFlags; - -typedef enum { - // The key was found in the license but there was something wrong it and could - // not be loaded. - WB_KEY_STATUS_INVALID, - - // The key was found in the license and can be used with - // |WB_License_SignRenewalRequest()| and with - // |WB_License_VerifyRenewalResponse()|. - WB_KEY_STATUS_SIGNING_KEY_VALID, - - // The key was found in the license. However, the permisions of the key are - // different depending on its status. - // - // | DECRYPT | MASKED DECRYPT | - // ---------------+---------+----------------+ - // VALID | No | No | - // MASKED_DECRYPT | No | Yes | - // DECRYPT | Yes | Yes | - WB_KEY_STATUS_CONTENT_KEY_VALID, - WB_KEY_STATUS_CONTENT_KEY_MASKED_DECRYPT, - WB_KEY_STATUS_CONTENT_KEY_DECRYPT, -} WB_KeyStatus; - -typedef enum { - // The license response uses single key - the license signing and encryption - // key are the same. - WB_LICENSE_KEY_MODE_SINGLE_KEY, - - // The license response uses two keys - the license signing and encryption - // key are different. - WB_LICENSE_KEY_MODE_DUAL_KEY, -} WB_LicenseKeyMode; +typedef struct WB_CONCAT_VERSION(WB_License_Whitebox) + WB_CONCAT_VERSION(WB_License_Whitebox); // Creates a new white-box instance using the implementation's internal private // key|. A pointer to the white-box instance will be returned via |whitebox|. @@ -88,17 +62,74 @@ typedef enum { // WB_RESULT_INVALID_PARAMETER if |whitebox| was null. // // WB_RESULT_OUT_OF_MEMORY if the necessary memory could not be allocated. -WB_Result WB_License_Create(const uint8_t* whitebox_init_data, - size_t whitebox_init_data_size, - WB_License_Whitebox** whitebox); +WB_Result WB_CONCAT_VERSION(WB_License_Create)( + const uint8_t* whitebox_init_data, + size_t whitebox_init_data_size, + WB_CONCAT_VERSION(WB_License_Whitebox)** whitebox); + +// Creates a new white-box instance by loading the exported keys from the given +// buffer. A pointer to the white-box instance will be returned via |whitebox|. +// +// This function can be used in the limited offline builds. +// +// Args: +// buffer (in): The exported key buffer. +// +// buffer_size (in): The number of bytes in buffer. +// +// whitebox (out) : The output parameter used to return the new white-box +// instance. +// +// Returns: +// WB_RESULT_OK if the white-box instance was successfully created. +// +// WB_RESULT_INVALID_PARAMETER if |whitebox| was null. +// +// WB_RESULT_OUT_OF_MEMORY if the necessary memory could not be allocated. +WB_Result WB_CONCAT_VERSION(WB_License_Import)( + const uint8_t* buffer, + size_t buffer_size, + WB_CONCAT_VERSION(WB_License_Whitebox)** whitebox); // Releases all resources used by the white-box instance pointed to by // |whitebox|. // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : A pointer to a white-box instance. Passing in null will // result in a no-op. -void WB_License_Delete(WB_License_Whitebox* whitebox); +void WB_CONCAT_VERSION(WB_License_Delete)( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox); + +// Exports the client MAC key, content keys, and generic keys in a persistent +// format. This format will be stored on disk as-is; it should be encrypted or +// otherwise protected against reading or usage. +// +// Args: +// whitebox (in) : The white-box containing the keys to export +// |input_data|. +// +// buffer(out) : The output buffer to write the data to. +// +// buffer_size(in/out) : On input, contains the maximum number of bytes in +// |buffer|. On output should contain the number of bytes used by the +// data. +// +// Returns: +// WB_RESULT_OK if the key was successfully exported. +// +// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |buffer| was null, +// if |buffer_size| was null. +// +// WB_RESULT_BUFFER_TOO_SMALL if |buffer_size| (as input) was less than the +// required size. +// +// WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. +WB_Result WB_CONCAT_VERSION(WB_License_ExportKeys)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + uint8_t* buffer, + size_t* buffer_size); // Initializes tables and data needed for the WB_License_SignLicenseRequest() // function. @@ -112,7 +143,7 @@ void WB_License_Delete(WB_License_Whitebox* whitebox); // Returns: // WB_RESULT_OK if the initialization succeeded. // WB_RESULT_INVALID_STATE otherwise. -WB_Result WB_License_SignLicenseRequest_Init(); +WB_Result WB_CONCAT_VERSION(WB_License_SignLicenseRequest_Init)(); // Signs a license request using the CDM's private signing key. // @@ -143,11 +174,12 @@ WB_Result WB_License_SignLicenseRequest_Init(); // // WB_RESULT_INVALID_STATE if WB_License_SignLicenseRequest_Init() has not been // called and completed. -WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox, - const uint8_t* license_request, - size_t license_request_size, - uint8_t* signature, - size_t* signature_size); +WB_Result WB_CONCAT_VERSION(WB_License_SignLicenseRequest)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* license_request, + size_t license_request_size, + uint8_t* signature, + size_t* signature_size); // Initializes tables and data needed for the // WB_License_ProcessLicenseResponse() function. @@ -162,7 +194,7 @@ WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox, // Returns: // WB_RESULT_OK if the initialization succeeded. // WB_RESULT_INVALID_STATE otherwise. -WB_Result WB_License_ProcessLicenseResponse_Init(); +WB_Result WB_CONCAT_VERSION(WB_License_ProcessLicenseResponse_Init)(); // Verifies a license response using HMAC and the server signing key. // @@ -239,19 +271,20 @@ WB_Result WB_License_ProcessLicenseResponse_Init(); // the behaviour is undefined. The two preferrable results are: // 1. The key is considered value and is loaded. // 2. The key is considered invalid and is not loaded. -WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, - WB_LicenseKeyMode license_key_mode, - const uint8_t* core_message, - size_t core_message_size, - const uint8_t* message, - size_t message_size, - const uint8_t* signature, - size_t signature_size, - const uint8_t* session_key, - size_t session_key_size, - size_t provider_key_id, - const uint8_t* license_request, - size_t license_request_size); +WB_Result WB_CONCAT_VERSION(WB_License_ProcessLicenseResponse)( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_LicenseKeyMode license_key_mode, + const uint8_t* core_message, + size_t core_message_size, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size, + const uint8_t* session_key, + size_t session_key_size, + size_t provider_key_id, + const uint8_t* license_request, + size_t license_request_size); // Loads a content key using a previously loaded entitlement key. The key data // is a normal 128-bit AES content key. The key data is encrypted with an @@ -287,15 +320,16 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, // license. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. -WB_Result WB_License_LoadEntitledContentKey(WB_License_Whitebox* whitebox, - const uint8_t* entitlement_key_id, - size_t entitlement_key_id_size, - const uint8_t* content_key_id, - size_t content_key_id_size, - const uint8_t* iv, - size_t iv_size, - const uint8_t* key_data, - size_t key_data_size); +WB_Result WB_CONCAT_VERSION(WB_License_LoadEntitledContentKey)( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* entitlement_key_id, + size_t entitlement_key_id_size, + const uint8_t* content_key_id, + size_t content_key_id_size, + const uint8_t* iv, + size_t iv_size, + const uint8_t* key_data, + size_t key_data_size); // Removes a content key that was previously loaded from an entitlement key. // @@ -314,13 +348,16 @@ WB_Result WB_License_LoadEntitledContentKey(WB_License_Whitebox* whitebox, // WB_RESULT_KEY_UNAVAILABLE if the requested key was not added. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. -WB_Result WB_License_RemoveEntitledContentKey(WB_License_Whitebox* whitebox, - const uint8_t* content_key_id, - size_t content_key_id_size); +WB_Result WB_CONCAT_VERSION(WB_License_RemoveEntitledContentKey)( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* content_key_id, + size_t content_key_id_size); // Queries the white-box to know whether or not the white-box loaded a specific // key and to know what operations can be performed with that key. // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : An initialized white-box instance. // @@ -353,15 +390,18 @@ WB_Result WB_License_RemoveEntitledContentKey(WB_License_Whitebox* whitebox, // Since the white-box can skip invalid/malformed content keys, // WB_License_QueryKeyState() provides a means to know which keys we // successfully loaded. -WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox, - WB_KeyQueryType type, - const uint8_t* key_id, - size_t key_id_size, - WB_KeyStatus* key_status); +WB_Result WB_CONCAT_VERSION(WB_License_QueryKeyStatus)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_KeyQueryType type, + const uint8_t* key_id, + size_t key_id_size, + WB_KeyStatus* key_status); // Signs |message| and return the signature via |signature| using HMAC-SHA256 // and the client renewal signing key // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : The white-box instance containing the signing key. // @@ -388,15 +428,18 @@ WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox, // required size. // // WB_RESULT_INVALID_STATE if |whitebox| had no signing keys. -WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox, - const uint8_t* message, - size_t message_size, - uint8_t* signature, - size_t* signature_size); +WB_Result WB_CONCAT_VERSION(WB_License_SignRenewalRequest)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* message, + size_t message_size, + uint8_t* signature, + size_t* signature_size); // Signs |message| and return the signature via |signature| using HMAC-SHA1 and // the client renewal signing key // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : The white-box instance containing the signing key. // @@ -423,11 +466,12 @@ WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox, // required size. // // WB_RESULT_INVALID_STATE if |whitebox| had no signing keys. -WB_Result WB_License_SignPstReport(const WB_License_Whitebox* whitebox, - const uint8_t* message, - size_t message_size, - uint8_t* signature, - size_t* signature_size); +WB_Result WB_CONCAT_VERSION(WB_License_SignPstReport)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* message, + size_t message_size, + uint8_t* signature, + size_t* signature_size); // Verifies the renewal response using HMAC and the server signing key. // @@ -453,11 +497,12 @@ WB_Result WB_License_SignPstReport(const WB_License_Whitebox* whitebox, // |signature|. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. -WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox, - const uint8_t* message, - size_t message_size, - const uint8_t* signature, - size_t signature_size); +WB_Result WB_CONCAT_VERSION(WB_License_VerifyRenewalResponse)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size); // Gets the secret string needed by WB_License_Unmask() in order to unmask the // masked decrypted content returned by WB_License_MaskedDecrypt(). @@ -503,12 +548,13 @@ WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox, // the required size. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. -WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox, - WB_CipherMode mode, - const uint8_t* key_id, - size_t key_id_size, - uint8_t* secret_string, - size_t* secret_string_size); +WB_Result WB_CONCAT_VERSION(WB_License_GetSecretString)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + uint8_t* secret_string, + size_t* secret_string_size); // Performs a generic crypto "encrypt" operation to encrypt |input_data| and // places the result in |output_data|. @@ -516,6 +562,8 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox, // This must support |input_data| and |output_data| pointing to the same buffer // (in-place operation). // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : The white-box containing the keys needed to decrypt // |input_data|. @@ -560,15 +608,16 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox, // // WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct // permission bit sets in the KCB to allow encrypt. -WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* output_data, - size_t* output_data_size); +WB_Result WB_CONCAT_VERSION(WB_License_GenericEncrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size); // Performs a generic crypto "decrypt" operation to decrypt |input_data| and // places the result in |output_data|. @@ -576,6 +625,8 @@ WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox, // This must support |input_data| and |output_data| pointing to the same buffer // (in-place operation). // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : The white-box containing the keys needed to decrypt // |input_data|. @@ -620,19 +671,22 @@ WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox, // // WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct // permission bit sets in the KCB to allow decrypt. -WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* output_data, - size_t* output_data_size); +WB_Result WB_CONCAT_VERSION(WB_License_GenericDecrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size); // Performs a generic crypto "sign" operation that takes the given message in // |input_data| and places the signature in |output_data|. // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : The white-box containing the keys needed to decrypt // |input_data|. @@ -672,17 +726,20 @@ WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox, // // WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct // permission bit sets in the KCB to allow sign. -WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* message, - size_t message_size, - uint8_t* output_data, - size_t* output_data_size); +WB_Result WB_CONCAT_VERSION(WB_License_GenericSign)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* message, + size_t message_size, + uint8_t* output_data, + size_t* output_data_size); // Performs a generic crypto "verify" operation that takes |message| and // verifies the signature matches |signature|. // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : The white-box containing the keys needed to decrypt // |input_data|. @@ -718,19 +775,22 @@ WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox, // // WB_RESULT_INSUFFICIENT_PERMISSIONS if the key doesn't have the correct // permission bit sets in the KCB to allow verify. -WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* message, - size_t message_size, - const uint8_t* signature, - size_t signature_size); +WB_Result WB_CONCAT_VERSION(WB_License_GenericVerify)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size); // Decrypts |input_data| and writes the plaintext to |output_data|. // // This must support |input_data| and |output_data| pointing to the same buffer // (in-place decrypt). // +// This function can be used in the limited offline builds. +// // Args: // whitebox (in) : The white-box containing the keys needed to decrypt // |input_data|. @@ -777,16 +837,17 @@ WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox, // the required size. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. -WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox, - WB_CipherMode mode, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* output_data, - size_t* output_data_size); +WB_Result WB_CONCAT_VERSION(WB_License_Decrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size); // Decrypts |input_data| and write the obfuscated plaintext to // |masked_output_data|. The obfuscated plaintext can be deobfuscated using @@ -844,16 +905,17 @@ WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox, // than the required size. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. -WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox, - WB_CipherMode mode, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* masked_output_data, - size_t* masked_output_data_size); +WB_Result WB_CONCAT_VERSION(WB_License_MaskedDecrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* masked_output_data, + size_t* masked_output_data_size); // Unmasks a subset of the data in |masked_data| using |secret_string| and // writes it to |unmasked_data|. @@ -881,15 +943,15 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox, // secret_string_size (in) : The number of bytes in |secret_string|. // // unmasked_data (out) : The output buffer to write the unmasked data to. -void WB_License_Unmask(const uint8_t* masked_data, - size_t offset, - size_t size, - const uint8_t* secret_string, - size_t secret_string_size, - uint8_t* unmasked_data); +void WB_CONCAT_VERSION(WB_License_Unmask)( + const uint8_t* masked_data, + size_t offset, + size_t size, + const uint8_t* secret_string, + size_t secret_string_size, + uint8_t* unmasked_data); #ifdef __cplusplus } #endif -#endif // WHITEBOX_API_LICENSE_WHITEBOX_H_ diff --git a/whitebox/api/license_whitebox_create_test.cc b/whitebox/api/license_whitebox_create_test.cc index 3a2bd46..ba7fadc 100644 --- a/whitebox/api/license_whitebox_create_test.cc +++ b/whitebox/api/license_whitebox_create_test.cc @@ -1,6 +1,6 @@ // Copyright 2020 Google LLC. All Rights Reserved. -#include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "api/license_whitebox_provider_keys_test_data.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/whitebox/api/license_whitebox_decrypt_benchmark.cc b/whitebox/api/license_whitebox_decrypt_benchmark.cc index 5feaff5..1b2c3b4 100644 --- a/whitebox/api/license_whitebox_decrypt_benchmark.cc +++ b/whitebox/api/license_whitebox_decrypt_benchmark.cc @@ -6,7 +6,7 @@ #include #include -#include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "api/license_whitebox_benchmark.h" #include "api/license_whitebox_provider_keys_test_data.h" #include "api/result.h" diff --git a/whitebox/api/license_whitebox_decrypt_test.cc b/whitebox/api/license_whitebox_decrypt_test.cc index 8d3e463..73d6317 100644 --- a/whitebox/api/license_whitebox_decrypt_test.cc +++ b/whitebox/api/license_whitebox_decrypt_test.cc @@ -26,7 +26,7 @@ const size_t kInvalidProviderKeyId = 0xfff; class LicenseWhiteboxDecryptTest : public LicenseWhiteboxTestBase, - public ::testing::WithParamInterface> { + public ::testing::WithParamInterface> { protected: void SetUp() override { LicenseWhiteboxTestBase::SetUp(); @@ -69,7 +69,7 @@ class LicenseWhiteboxDecryptTest License license; builder.Build(*server, &license); - const auto result = WB_License_ProcessLicenseResponse( + auto result = WB_License_ProcessLicenseResponse( whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license.core_message.data(), license.core_message.size(), license.message.data(), license.message.size(), license.signature.data(), @@ -83,6 +83,11 @@ class LicenseWhiteboxDecryptTest } #endif EXPECT_EQ(result, WB_RESULT_OK); + + if (std::get<2>(GetParam())) { + RecreateOffline(); + } + return true; } @@ -643,7 +648,8 @@ INSTANTIATE_TEST_SUITE_P( ::testing::Values(kNoProviderKeyId, kValidProviderKeyId1, kValidProviderKeyId2, - kInvalidProviderKeyId))); + kInvalidProviderKeyId), + ::testing::Values(false))); INSTANTIATE_TEST_SUITE_P( PKSC8, @@ -652,5 +658,14 @@ INSTANTIATE_TEST_SUITE_P( ::testing::Values(kNoProviderKeyId, kValidProviderKeyId1, kValidProviderKeyId2, - kInvalidProviderKeyId))); + kInvalidProviderKeyId), + ::testing::Values(false))); + +INSTANTIATE_TEST_SUITE_P( + Offline, + LicenseWhiteboxDecryptTest, + ::testing::Combine(::testing::Values(Padding::kNone, Padding::kPKSC8), + ::testing::Values(kNoProviderKeyId), + ::testing::Values(true))); + } // namespace widevine diff --git a/whitebox/api/license_whitebox_generic_crypto_test.cc b/whitebox/api/license_whitebox_generic_crypto_test.cc index 8a73f7b..a61c506 100644 --- a/whitebox/api/license_whitebox_generic_crypto_test.cc +++ b/whitebox/api/license_whitebox_generic_crypto_test.cc @@ -3,9 +3,11 @@ #include "api/license_whitebox.h" #include +#include #include #include "api/golden_data.h" +#include "api/license_whitebox_provider_keys_test_data.h" #include "api/license_whitebox_test_base.h" #include "api/test_license_builder.h" #include "testing/gmock/include/gmock/gmock-matchers.h" @@ -88,7 +90,7 @@ INSTANTIATE_TEST_SUITE_P(All, class LicenseWhiteboxGenericCryptoTest : public LicenseWhiteboxTestBase, - public testing::WithParamInterface { + public testing::WithParamInterface> { protected: void SetUp() { LicenseWhiteboxTestBase::SetUp(); @@ -97,7 +99,7 @@ class LicenseWhiteboxGenericCryptoTest TestLicenseBuilder builder; builder.GetSettings().odk_version = TestLicenseBuilder::OdkVersion::k16_5; builder.AddSigningKey(TestLicenseBuilder::DefaultSigningKey()); - if (GetParam()) { + if (std::get<0>(GetParam())) { builder.AddGenericKey(golden_data_.GenericContent().encrypt_decrypt_key); builder.AddGenericKey(golden_data_.GenericContent().sign_verify_key); } else { @@ -107,6 +109,23 @@ class LicenseWhiteboxGenericCryptoTest builder.AddGenericKey(golden_data_.GenericContent().verify_key); } builder.Build(*server_, &license_); + + auto result = WB_License_ProcessLicenseResponse( + whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), + license_.core_message.size(), license_.message.data(), + license_.message.size(), license_.signature.data(), + license_.signature.size(), license_.session_key.data(), + license_.session_key.size(), kNoProviderKeyId, license_.request.data(), + license_.request.size()); +#ifndef HAS_GENERIC_CRYPTO + ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); +#else + ASSERT_EQ(result, WB_RESULT_OK); + + if (std::get<1>(GetParam())) { + ASSERT_NO_FATAL_FAILURE(RecreateOffline()); + } +#endif } std::unique_ptr server_; @@ -114,28 +133,15 @@ class LicenseWhiteboxGenericCryptoTest }; TEST_P(LicenseWhiteboxGenericCryptoTest, NoContentDecrypt) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.decrypt_key.id; std::vector actual(content.plaintext.size()); size_t actual_size = actual.size(); - result = WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CTR, key_id.data(), - key_id.size(), content.encrypted.data(), - content.encrypted.size(), content.iv.data(), - content.iv.size(), actual.data(), &actual_size); + auto result = WB_License_Decrypt( + whitebox_, WB_CIPHER_MODE_CTR, key_id.data(), key_id.size(), + content.encrypted.data(), content.encrypted.size(), content.iv.data(), + content.iv.size(), actual.data(), &actual_size); #ifndef HAS_GENERIC_CRYPTO ASSERT_EQ(result, WB_RESULT_INVALID_STATE); #else @@ -144,6 +150,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, NoContentDecrypt) { } TEST_P(LicenseWhiteboxGenericCryptoTest, NoGenericWithContent) { + // Recreate whitebox since the SetUp already loaded a license. + WB_License_Delete(whitebox_); + const auto init_data = GetLicenseWhiteboxProviderKeysInitData(); + ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_), + WB_RESULT_OK); + auto& content = golden_data_.CTRContent(); auto& key = content.software_crypto_key; TestLicenseBuilder builder; @@ -162,6 +174,10 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, NoGenericWithContent) { // Content key, expecting success regardless of HAS_GENERIC_CRYPTO support. ASSERT_EQ(result, WB_RESULT_OK); + if (std::get<1>(GetParam())) { + ASSERT_NO_FATAL_FAILURE(RecreateOffline()); + } + std::vector actual(content.plaintext.size()); size_t actual_size = actual.size(); result = WB_License_GenericDecrypt( @@ -176,25 +192,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, NoGenericWithContent) { } TEST_P(LicenseWhiteboxGenericCryptoTest, Decrypt) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.decrypt_key.id; std::vector actual(content.plaintext.size()); size_t actual_size = actual.size(); - result = WB_License_GenericDecrypt( + auto result = WB_License_GenericDecrypt( whitebox_, key_id.data(), key_id.size(), content.encrypted.data(), content.encrypted.size(), content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -210,24 +213,11 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, Decrypt) { } TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptShortBuffer) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.decrypt_key.id; size_t actual_size = 0; - result = WB_License_GenericDecrypt( + auto result = WB_License_GenericDecrypt( whitebox_, key_id.data(), key_id.size(), content.encrypted.data(), content.encrypted.size(), content.iv.data(), content.iv.size(), nullptr, &actual_size); @@ -240,25 +230,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptShortBuffer) { } TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptMissingKey) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - !GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id; + auto& key_id = !std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.decrypt_key.id; std::vector actual(content.plaintext.size()); size_t actual_size = actual.size(); - result = WB_License_GenericDecrypt( + auto result = WB_License_GenericDecrypt( whitebox_, key_id.data(), key_id.size(), content.encrypted.data(), content.encrypted.size(), content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -270,24 +247,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptMissingKey) { } TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptKeyUsage) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = GetParam() ? content.sign_verify_key.id : content.sign_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.sign_verify_key.id + : content.sign_key.id; std::vector actual(content.plaintext.size()); size_t actual_size = actual.size(); - result = WB_License_GenericDecrypt( + auto result = WB_License_GenericDecrypt( whitebox_, key_id.data(), key_id.size(), content.encrypted.data(), content.encrypted.size(), content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -299,26 +264,13 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptKeyUsage) { } TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptDataSize) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.decrypt_key.id; std::vector actual(content.plaintext.size()); size_t actual_size = actual.size(); // Input size should be a multiple of 16 - result = WB_License_GenericDecrypt( + auto result = WB_License_GenericDecrypt( whitebox_, key_id.data(), key_id.size(), content.encrypted.data(), content.encrypted.size() - 5, content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -330,25 +282,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, DecryptDataSize) { } TEST_P(LicenseWhiteboxGenericCryptoTest, Encrypt) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.encrypt_key.id; std::vector actual(content.encrypted.size()); size_t actual_size = actual.size(); - result = WB_License_GenericEncrypt( + auto result = WB_License_GenericEncrypt( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -364,24 +303,11 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, Encrypt) { } TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptShortBuffer) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.encrypt_key.id; size_t actual_size = 0; - result = WB_License_GenericEncrypt( + auto result = WB_License_GenericEncrypt( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), content.iv.data(), content.iv.size(), nullptr, &actual_size); @@ -394,25 +320,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptShortBuffer) { } TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptMissingKey) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - !GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id; + auto& key_id = !std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.encrypt_key.id; std::vector actual(content.encrypted.size()); size_t actual_size = actual.size(); - result = WB_License_GenericEncrypt( + auto result = WB_License_GenericEncrypt( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -424,24 +337,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptMissingKey) { } TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptKeyUsage) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = GetParam() ? content.sign_verify_key.id : content.sign_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.sign_verify_key.id + : content.sign_key.id; std::vector actual(content.encrypted.size()); size_t actual_size = actual.size(); - result = WB_License_GenericEncrypt( + auto result = WB_License_GenericEncrypt( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -453,26 +354,13 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptKeyUsage) { } TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptDataSize) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.encrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.encrypt_key.id; std::vector actual(content.encrypted.size()); size_t actual_size = actual.size(); // Input size should be a multiple of 16 - result = WB_License_GenericEncrypt( + auto result = WB_License_GenericEncrypt( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size() - 5, content.iv.data(), content.iv.size(), actual.data(), &actual_size); @@ -484,24 +372,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, EncryptDataSize) { } TEST_P(LicenseWhiteboxGenericCryptoTest, Sign) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = GetParam() ? content.sign_verify_key.id : content.sign_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.sign_verify_key.id + : content.sign_key.id; std::vector actual(content.signature.size()); size_t actual_size = actual.size(); - result = WB_License_GenericSign( + auto result = WB_License_GenericSign( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), actual.data(), &actual_size); #ifndef HAS_GENERIC_CRYPTO @@ -516,23 +392,11 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, Sign) { } TEST_P(LicenseWhiteboxGenericCryptoTest, SignShortBuffer) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = GetParam() ? content.sign_verify_key.id : content.sign_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.sign_verify_key.id + : content.sign_key.id; size_t actual_size = 0; - result = WB_License_GenericSign( + auto result = WB_License_GenericSign( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), nullptr, &actual_size); #ifndef HAS_GENERIC_CRYPTO @@ -544,24 +408,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, SignShortBuffer) { } TEST_P(LicenseWhiteboxGenericCryptoTest, SignMissingKey) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = !GetParam() ? content.sign_verify_key.id : content.sign_key.id; + auto& key_id = !std::get<0>(GetParam()) ? content.sign_verify_key.id + : content.sign_key.id; std::vector actual(content.signature.size()); size_t actual_size = actual.size(); - result = WB_License_GenericSign( + auto result = WB_License_GenericSign( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), actual.data(), &actual_size); #ifndef HAS_GENERIC_CRYPTO @@ -572,25 +424,12 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, SignMissingKey) { } TEST_P(LicenseWhiteboxGenericCryptoTest, SignKeyUsage) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.decrypt_key.id; std::vector actual(content.signature.size()); size_t actual_size = actual.size(); - result = WB_License_GenericSign( + auto result = WB_License_GenericSign( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), actual.data(), &actual_size); #ifndef HAS_GENERIC_CRYPTO @@ -601,26 +440,13 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, SignKeyUsage) { } TEST_P(LicenseWhiteboxGenericCryptoTest, Verify) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.sign_verify_key.id : content.verify_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.sign_verify_key.id + : content.verify_key.id; auto temp_signature = content.signature; // Test once successfully, then make the signature invalid and test again. for (int i = 0; i < 2; i++) { - result = WB_License_GenericVerify( + auto result = WB_License_GenericVerify( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), temp_signature.data(), temp_signature.size()); #ifndef HAS_GENERIC_CRYPTO @@ -633,24 +459,11 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, Verify) { } TEST_P(LicenseWhiteboxGenericCryptoTest, VerifyMissingKey) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - !GetParam() ? content.sign_verify_key.id : content.verify_key.id; + auto& key_id = !std::get<0>(GetParam()) ? content.sign_verify_key.id + : content.verify_key.id; auto temp_signature = content.signature; - result = WB_License_GenericVerify( + auto result = WB_License_GenericVerify( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), temp_signature.data(), temp_signature.size()); #ifndef HAS_GENERIC_CRYPTO @@ -661,24 +474,11 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, VerifyMissingKey) { } TEST_P(LicenseWhiteboxGenericCryptoTest, VerifyKeyUsage) { - auto result = WB_License_ProcessLicenseResponse( - whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license_.core_message.data(), - license_.core_message.size(), license_.message.data(), - license_.message.size(), license_.signature.data(), - license_.signature.size(), license_.session_key.data(), - license_.session_key.size(), kNoProviderKeyId, license_.request.data(), - license_.request.size()); -#ifndef HAS_GENERIC_CRYPTO - ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); -#else - ASSERT_EQ(result, WB_RESULT_OK); -#endif - auto& content = golden_data_.GenericContent(); - auto& key_id = - GetParam() ? content.encrypt_decrypt_key.id : content.decrypt_key.id; + auto& key_id = std::get<0>(GetParam()) ? content.encrypt_decrypt_key.id + : content.decrypt_key.id; auto temp_signature = content.signature; - result = WB_License_GenericVerify( + auto result = WB_License_GenericVerify( whitebox_, key_id.data(), key_id.size(), content.plaintext.data(), content.plaintext.size(), temp_signature.data(), temp_signature.size()); #ifndef HAS_GENERIC_CRYPTO @@ -690,6 +490,7 @@ TEST_P(LicenseWhiteboxGenericCryptoTest, VerifyKeyUsage) { INSTANTIATE_TEST_SUITE_P(All, LicenseWhiteboxGenericCryptoTest, - testing::Bool()); + ::testing::Combine(::testing::Bool(), + ::testing::Bool())); } // namespace widevine diff --git a/whitebox/api/license_whitebox_latest.h b/whitebox/api/license_whitebox_latest.h new file mode 100644 index 0000000..5fdda54 --- /dev/null +++ b/whitebox/api/license_whitebox_latest.h @@ -0,0 +1,262 @@ +// Copyright 2024 Google LLC. All Rights Reserved. + +#ifndef WHITEBOX_API_LICENSE_WHITEBOX_LATEST_H_ +#define WHITEBOX_API_LICENSE_WHITEBOX_LATEST_H_ + +#include "api/license_whitebox.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WB_VERSION + +typedef WB_CONCAT_VERSION(WB_License_Whitebox) WB_License_Whitebox; + +inline WB_Result WB_License_Create( + const uint8_t* whitebox_init_data, + size_t whitebox_init_data_size, + WB_CONCAT_VERSION(WB_License_Whitebox)** whitebox) { + return WB_CONCAT_VERSION(WB_License_Create)( + whitebox_init_data, whitebox_init_data_size, whitebox); +} + +inline WB_Result WB_License_Import( + const uint8_t* buffer, + size_t buffer_size, + WB_CONCAT_VERSION(WB_License_Whitebox)** whitebox) { + return WB_CONCAT_VERSION(WB_License_Import)(buffer, buffer_size, whitebox); +} + +inline void WB_License_Delete( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox) { + return WB_CONCAT_VERSION(WB_License_Delete)(whitebox); +} + +inline WB_Result WB_License_ExportKeys( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + uint8_t* buffer, + size_t* buffer_size) { + return WB_CONCAT_VERSION(WB_License_ExportKeys)(whitebox, buffer, + buffer_size); +} + +inline WB_Result WB_License_SignLicenseRequest_Init() { + return WB_CONCAT_VERSION(WB_License_SignLicenseRequest_Init)(); +} + +inline WB_Result WB_License_SignLicenseRequest( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* license_request, + size_t license_request_size, + uint8_t* signature, + size_t* signature_size) { + return WB_CONCAT_VERSION(WB_License_SignLicenseRequest)( + whitebox, license_request, license_request_size, signature, + signature_size); +} + +inline WB_Result WB_License_ProcessLicenseResponse_Init() { + return WB_CONCAT_VERSION(WB_License_ProcessLicenseResponse_Init)(); +} + +inline WB_Result WB_License_ProcessLicenseResponse( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_LicenseKeyMode license_key_mode, + const uint8_t* core_message, + size_t core_message_size, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size, + const uint8_t* session_key, + size_t session_key_size, + size_t provider_key_id, + const uint8_t* license_request, + size_t license_request_size) { + return WB_CONCAT_VERSION(WB_License_ProcessLicenseResponse)( + whitebox, license_key_mode, core_message, core_message_size, message, + message_size, signature, signature_size, session_key, session_key_size, + provider_key_id, license_request, license_request_size); +} + +inline WB_Result WB_License_LoadEntitledContentKey( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* entitlement_key_id, + size_t entitlement_key_id_size, + const uint8_t* content_key_id, + size_t content_key_id_size, + const uint8_t* iv, + size_t iv_size, + const uint8_t* key_data, + size_t key_data_size) { + return WB_CONCAT_VERSION(WB_License_LoadEntitledContentKey)( + whitebox, entitlement_key_id, entitlement_key_id_size, content_key_id, + content_key_id_size, iv, iv_size, key_data, key_data_size); +} + +inline WB_Result WB_License_RemoveEntitledContentKey( + WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* content_key_id, + size_t content_key_id_size) { + return WB_CONCAT_VERSION(WB_License_RemoveEntitledContentKey)( + whitebox, content_key_id, content_key_id_size); +} + +inline WB_Result WB_License_QueryKeyStatus( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_KeyQueryType type, + const uint8_t* key_id, + size_t key_id_size, + WB_KeyStatus* key_status) { + return WB_CONCAT_VERSION(WB_License_QueryKeyStatus)(whitebox, type, key_id, + key_id_size, key_status); +} + +inline WB_Result WB_License_SignRenewalRequest( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* message, + size_t message_size, + uint8_t* signature, + size_t* signature_size) { + return WB_CONCAT_VERSION(WB_License_SignRenewalRequest)( + whitebox, message, message_size, signature, signature_size); +} + +inline WB_Result WB_License_SignPstReport( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* message, + size_t message_size, + uint8_t* signature, + size_t* signature_size) { + return WB_CONCAT_VERSION(WB_License_SignPstReport)( + whitebox, message, message_size, signature, signature_size); +} + +inline WB_Result WB_License_VerifyRenewalResponse( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size) { + return WB_CONCAT_VERSION(WB_License_VerifyRenewalResponse)( + whitebox, message, message_size, signature, signature_size); +} + +inline WB_Result WB_License_GetSecretString( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + uint8_t* secret_string, + size_t* secret_string_size) { + return WB_CONCAT_VERSION(WB_License_GetSecretString)( + whitebox, mode, key_id, key_id_size, secret_string, secret_string_size); +} + +inline WB_Result WB_License_GenericEncrypt( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size) { + return WB_CONCAT_VERSION(WB_License_GenericEncrypt)( + whitebox, key_id, key_id_size, input_data, input_data_size, iv, iv_size, + output_data, output_data_size); +} + +inline WB_Result WB_License_GenericDecrypt( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size) { + return WB_CONCAT_VERSION(WB_License_GenericDecrypt)( + whitebox, key_id, key_id_size, input_data, input_data_size, iv, iv_size, + output_data, output_data_size); +} + +inline WB_Result WB_License_GenericSign( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* message, + size_t message_size, + uint8_t* output_data, + size_t* output_data_size) { + return WB_CONCAT_VERSION(WB_License_GenericSign)( + whitebox, key_id, key_id_size, message, message_size, output_data, + output_data_size); +} + +inline WB_Result WB_License_GenericVerify( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size) { + return WB_CONCAT_VERSION(WB_License_GenericVerify)( + whitebox, key_id, key_id_size, message, message_size, signature, + signature_size); +} + +inline WB_Result WB_License_Decrypt( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size) { + return WB_CONCAT_VERSION(WB_License_Decrypt)( + whitebox, mode, key_id, key_id_size, input_data, input_data_size, iv, + iv_size, output_data, output_data_size); +} + +inline WB_Result WB_License_MaskedDecrypt( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* masked_output_data, + size_t* masked_output_data_size) { + return WB_CONCAT_VERSION(WB_License_MaskedDecrypt)( + whitebox, mode, key_id, key_id_size, input_data, input_data_size, iv, + iv_size, masked_output_data, masked_output_data_size); +} + +inline void WB_License_Unmask(const uint8_t* masked_data, + size_t offset, + size_t size, + const uint8_t* secret_string, + size_t secret_string_size, + uint8_t* unmasked_data) { + WB_CONCAT_VERSION(WB_License_Unmask)(masked_data, offset, size, secret_string, + secret_string_size, unmasked_data); +} + +#endif // defined(WB_VERSION) + +#ifdef __cplusplus +} +#endif + +#endif // WHITEBOX_API_LICENSE_WHITEBOX_LATEST_H_ + diff --git a/whitebox/api/license_whitebox_main.cc b/whitebox/api/license_whitebox_main.cc index a444c2f..bc5976c 100644 --- a/whitebox/api/license_whitebox_main.cc +++ b/whitebox/api/license_whitebox_main.cc @@ -6,7 +6,7 @@ #include #include "api/golden_data.h" -#include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "api/license_whitebox_provider_keys_test_data.h" #include "api/test_license_builder.h" #include "base/logging.h" diff --git a/whitebox/api/license_whitebox_process_license_response_benchmark.cc b/whitebox/api/license_whitebox_process_license_response_benchmark.cc index 0263c13..4624216 100644 --- a/whitebox/api/license_whitebox_process_license_response_benchmark.cc +++ b/whitebox/api/license_whitebox_process_license_response_benchmark.cc @@ -4,7 +4,7 @@ #include #include -#include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "api/license_whitebox_benchmark.h" #include "api/license_whitebox_provider_keys_test_data.h" #include "api/result.h" diff --git a/whitebox/api/license_whitebox_sign_benchmark.cc b/whitebox/api/license_whitebox_sign_benchmark.cc index 47dac91..b7fbd84 100644 --- a/whitebox/api/license_whitebox_sign_benchmark.cc +++ b/whitebox/api/license_whitebox_sign_benchmark.cc @@ -6,7 +6,7 @@ #include #include -#include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "api/license_whitebox_benchmark.h" #include "api/license_whitebox_provider_keys_test_data.h" #include "api/result.h" diff --git a/whitebox/api/license_whitebox_sign_renewal_request_test.cc b/whitebox/api/license_whitebox_sign_renewal_request_test.cc index 8150f93..f5deb46 100644 --- a/whitebox/api/license_whitebox_sign_renewal_request_test.cc +++ b/whitebox/api/license_whitebox_sign_renewal_request_test.cc @@ -4,6 +4,7 @@ #include #include +#include #include #include "api/license_whitebox_test_base.h" @@ -18,7 +19,7 @@ constexpr const bool kRenewal = true; class LicenseWhiteboxSignRenewalPstTest : public LicenseWhiteboxTestBase, - public testing::WithParamInterface { + public testing::WithParamInterface> { protected: void SetUp() override { LicenseWhiteboxTestBase::SetUp(); @@ -28,8 +29,9 @@ class LicenseWhiteboxSignRenewalPstTest signature_size_ = 256; signature_.resize(signature_size_); - sign_func_ = GetParam() == kRenewal ? &WB_License_SignRenewalRequest - : &WB_License_SignPstReport; + sign_func_ = std::get<0>(GetParam()) == kRenewal + ? &WB_License_SignRenewalRequest + : &WB_License_SignPstReport; } void LoadLicense(const TestLicenseBuilder::Settings& settings) { @@ -57,6 +59,10 @@ class LicenseWhiteboxSignRenewalPstTest license.session_key.data(), license.session_key.size(), kNoProviderKeyId, license.request.data(), license.request.size()), WB_RESULT_OK); + + if (std::get<1>(GetParam())) { + ASSERT_NO_FATAL_FAILURE(RecreateOffline()); + } } // Get the expected signature for |message|. By returning the message, this @@ -67,7 +73,7 @@ class LicenseWhiteboxSignRenewalPstTest std::string key_str(signing_key_.begin(), signing_key_.end()); key_str.erase(0, crypto_util::kSigningKeySizeBytes); - auto func = GetParam() == kRenewal + auto func = std::get<0>(GetParam()) == kRenewal ? &widevine::crypto_util::CreateSignatureHmacSha256 : &widevine::crypto_util::CreateSignatureHmacSha1; const std::string signature = @@ -100,13 +106,13 @@ class LicenseWhiteboxSignRenewalPstTest TEST_P(LicenseWhiteboxSignRenewalPstTest, SuccessWithInvalidRequest) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -120,13 +126,13 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, SuccessWithInvalidRequest) { TEST_P(LicenseWhiteboxSignRenewalPstTest, SuccessWithSigningKeyPKSC8Padding) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kPKSC8; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -140,13 +146,13 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, SuccessWithSigningKeyPKSC8Padding) { TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullWhitebox) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(nullptr, garbage_request_.data(), garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -157,12 +163,12 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullWhitebox) { TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullMessage) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(whitebox_, nullptr, garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -173,12 +179,12 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullMessage) { TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForZeroMessageSize) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(whitebox_, garbage_request_.data(), 0, signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -189,14 +195,14 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForZeroMessageSize) { TEST_P(LicenseWhiteboxSignRenewalPstTest, CanProbeSizeWithNullSignature) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); signature_size_ = 0; const auto result = sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), nullptr, &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -208,13 +214,13 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, CanProbeSizeWithNullSignature) { TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullSignature) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), nullptr, &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -226,13 +232,13 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullSignatureSize) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), signature_.data(), nullptr); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -243,7 +249,7 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, TEST_P(LicenseWhiteboxSignRenewalPstTest, BufferTooSmall) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); // We need the signature to be too small. While it would be possible to use // zero, using a non-zero value ensures that we are not combining "empty" and @@ -254,7 +260,7 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, BufferTooSmall) { sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -276,7 +282,7 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidStateForNoLicense) { sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -311,7 +317,7 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, KeyUnavailableForNoSigningKey) { sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -325,13 +331,13 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, KeyUnavailableForInvalidKey) { // just need an invalid key, so we use one way of invalidating the key. TestLicenseBuilder::Settings settings; settings.include_signing_key_iv = false; - LoadLicense(settings); + ASSERT_NO_FATAL_FAILURE(LoadLicense(settings)); const auto result = sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), signature_.data(), &signature_size_); #ifndef HAS_SIGN_PST_REPORT - if (GetParam() != kRenewal) { + if (std::get<0>(GetParam()) != kRenewal) { ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); GTEST_SKIP(); } @@ -339,11 +345,18 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, KeyUnavailableForInvalidKey) { ASSERT_EQ(result, WB_RESULT_KEY_UNAVAILABLE); } -INSTANTIATE_TEST_SUITE_P(TestAll, - LicenseWhiteboxSignRenewalPstTest, - testing::Bool(), - [](const testing::TestParamInfo& info) { - return info.param == kRenewal ? "Renewal" : "PST"; - }); +INSTANTIATE_TEST_SUITE_P( + TestAll, + LicenseWhiteboxSignRenewalPstTest, + testing::Combine(testing::Bool(), testing::Bool()), + [](const testing::TestParamInfo>& info) { + if (std::get<1>(info.param)) { + return std::get<0>(info.param) == kRenewal ? "Offline_Renewal" + : "Offline_PST"; + } else { + return std::get<0>(info.param) == kRenewal ? "Streaming_Renewal" + : "Streaming_PST"; + } + }); } // namespace widevine diff --git a/whitebox/api/license_whitebox_test_base.cc b/whitebox/api/license_whitebox_test_base.cc index da5c67a..1f2682d 100644 --- a/whitebox/api/license_whitebox_test_base.cc +++ b/whitebox/api/license_whitebox_test_base.cc @@ -19,6 +19,26 @@ void LicenseWhiteboxTestBase::TearDown() { WB_License_Delete(whitebox_); } +void LicenseWhiteboxTestBase::RecreateOffline() { + std::vector buffer; + size_t buffer_size = 0; + auto result = WB_License_ExportKeys(whitebox_, buffer.data(), &buffer_size); +#ifdef HAS_IMPORT_EXPORT + ASSERT_EQ(result, WB_RESULT_BUFFER_TOO_SMALL); + + buffer.resize(buffer_size); + result = WB_License_ExportKeys(whitebox_, buffer.data(), &buffer_size); + ASSERT_EQ(result, WB_RESULT_OK); + + WB_License_Delete(whitebox_); + result = WB_License_Import(buffer.data(), buffer_size, &whitebox_); + ASSERT_EQ(result, WB_RESULT_OK); +#else + ASSERT_EQ(result, WB_RESULT_NOT_IMPLEMENTED); + GTEST_SKIP(); +#endif +} + void LicenseWhiteboxTestBase::Modify(std::vector* data) const { ASSERT_TRUE(data); ASSERT_GT(data->size(), 0u); diff --git a/whitebox/api/license_whitebox_test_base.h b/whitebox/api/license_whitebox_test_base.h index 6b96ae2..2e40716 100644 --- a/whitebox/api/license_whitebox_test_base.h +++ b/whitebox/api/license_whitebox_test_base.h @@ -6,7 +6,7 @@ #include #include "api/golden_data.h" -#include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "crypto_utils/rsa_key.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,6 +18,9 @@ class LicenseWhiteboxTestBase : public ::testing::Test { void TearDown() override; + // Recreates the whitebox instance by exporting and importing the offline data + void RecreateOffline(); + // Modify a buffer so that it won't be the exact same as it was before. This // to make it easier to invalidate signatures. void Modify(std::vector* data) const; diff --git a/whitebox/api/license_whitebox_uat_test.cc b/whitebox/api/license_whitebox_uat_test.cc index 9df629c..a7a86b8 100644 --- a/whitebox/api/license_whitebox_uat_test.cc +++ b/whitebox/api/license_whitebox_uat_test.cc @@ -5,6 +5,7 @@ #include #include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "api/license_whitebox_provider_keys_test_data.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/whitebox/api/license_whitebox_verify_benchmark.cc b/whitebox/api/license_whitebox_verify_benchmark.cc index 16a5d09..9022f8c 100644 --- a/whitebox/api/license_whitebox_verify_benchmark.cc +++ b/whitebox/api/license_whitebox_verify_benchmark.cc @@ -6,7 +6,7 @@ #include #include -#include "api/license_whitebox.h" +#include "api/license_whitebox_latest.h" #include "api/license_whitebox_benchmark.h" #include "api/license_whitebox_provider_keys_test_data.h" #include "api/result.h" diff --git a/whitebox/reference/impl/BUILD b/whitebox/reference/impl/BUILD index 3e0c96d..5def575 100644 --- a/whitebox/reference/impl/BUILD +++ b/whitebox/reference/impl/BUILD @@ -27,6 +27,7 @@ cc_library( srcs = ["odk.cc"], hdrs = ["odk.h"], deps = [ + "//api:enums", "//api:result", "//api:shared_settings", "//chromium_deps/base:glog", @@ -67,6 +68,7 @@ cc_library( ":content_key", ":odk", ":renewal_key", + "//api:enums", "//api:result", "//api:shared_settings", "//api:trap_keys", @@ -144,6 +146,7 @@ cc_library( ":memory_util", "//api:aead_test_data", "//api:aead_whitebox", + "//api:enums", "//api:result", "//api:shared_settings", "//chromium_deps/third_party/boringssl", @@ -170,6 +173,7 @@ cc_library( ":private_keys", ":protobuf_license_parser", "//api:license_whitebox", + "//api:enums", "//api:result", "//api:shared_settings", "//api:trap_keys", diff --git a/whitebox/reference/impl/content_key.h b/whitebox/reference/impl/content_key.h index 7fbe46c..4396008 100644 --- a/whitebox/reference/impl/content_key.h +++ b/whitebox/reference/impl/content_key.h @@ -5,7 +5,6 @@ #include #include -#include #include "api/license_whitebox.h" #include "license_protocol.pb.h" diff --git a/whitebox/reference/impl/license_parser.cc b/whitebox/reference/impl/license_parser.cc index 1920b77..6daf421 100644 --- a/whitebox/reference/impl/license_parser.cc +++ b/whitebox/reference/impl/license_parser.cc @@ -84,7 +84,10 @@ bool LicenseParser::UnwrapKey( // |provider_key_id| is used, so decrypt the unwrapped key using the // appropriate provider key. std::string final_key; - const auto& provider_key = provider_keys[provider_key_id - 1].key; + const std::string provider_key{ + provider_keys[provider_key_id - 1].key.begin(), + provider_keys[provider_key_id - 1].key.end() + }; const std::string no_iv(16, 0); if (!Decrypt(provider_key, no_iv, intermediate_key, &final_key)) { DVLOG(1) << "Failed to decrypt content key using Provider Key."; diff --git a/whitebox/reference/impl/license_parser.h b/whitebox/reference/impl/license_parser.h index 8fd29df..40bfd5d 100644 --- a/whitebox/reference/impl/license_parser.h +++ b/whitebox/reference/impl/license_parser.h @@ -3,9 +3,11 @@ #ifndef WHITEBOX_REFERENCE_IMPL_LICENSE_PARSER_H_ #define WHITEBOX_REFERENCE_IMPL_LICENSE_PARSER_H_ +#include #include #include #include + #include "license_protocol.pb.h" #include "reference/impl/content_key.h" #include "reference/impl/odk.h" @@ -16,8 +18,8 @@ namespace widevine { class LicenseParser { public: struct ProviderKey { - std::vector mask; - std::string key; + std::array mask; + std::array key; }; LicenseParser() = default; diff --git a/whitebox/reference/impl/license_whitebox_impl.cc b/whitebox/reference/impl/license_whitebox_impl.cc index 88564b7..8a82367 100644 --- a/whitebox/reference/impl/license_whitebox_impl.cc +++ b/whitebox/reference/impl/license_whitebox_impl.cc @@ -110,10 +110,26 @@ std::string MakeString(const uint8_t* data, size_t size) { } #endif +struct WB_License_ExportedData_Key { + std::array key_id; + uint8_t key_id_size; + widevine::InternalKey key; +}; +struct WB_License_ExportedData { + uint8_t version; + bool has_renewal; + std::array renewal_client; + size_t num_content_keys; + size_t num_generic_keys; + WB_License_ExportedData_Key keys[0]; +}; + +constexpr const uint8_t kExportedVersion = 1; + } // namespace // The white-box type can't be in the namespace as it is declared in the header. -struct WB_License_Whitebox { +struct WB_CONCAT_VERSION(WB_License_Whitebox) { // A basic flag to track whether or not we have loaded a license. We do this // to avoid relying on signing keys and content keys to know if we loaded a // license. @@ -163,9 +179,10 @@ std::vector GetSecretStringFor(WB_CipherMode mode) { } #endif -const widevine::InternalKey* FindKey(const WB_License_Whitebox* whitebox, - const uint8_t* id, - size_t id_size) { +const widevine::InternalKey* FindKey( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* id, + size_t id_size) { CHECK(whitebox); CHECK(id); CHECK_GT(id_size, 0u); @@ -319,8 +336,8 @@ std::vector CreateProviderKeys( #ifdef HAS_PROVIDER_KEYS for (size_t i = 0; i < whitebox_init_data_size / 32; ++i) { widevine::LicenseParser::ProviderKey provider_key; - provider_key.mask.assign(whitebox_init_data, whitebox_init_data + 16); - provider_key.key.assign(whitebox_init_data + 16, whitebox_init_data + 32); + memcpy(provider_key.mask.data(), whitebox_init_data, 16); + memcpy(provider_key.key.data(), whitebox_init_data + 16, 16); result.emplace_back(provider_key); whitebox_init_data += 32; } @@ -330,9 +347,10 @@ std::vector CreateProviderKeys( } // namespace -WB_Result WB_License_Create(const uint8_t* whitebox_init_data, - size_t whitebox_init_data_size, - WB_License_Whitebox** whitebox) { +WB_Result WB_CONCAT_VERSION(WB_License_Create)( + const uint8_t* whitebox_init_data, + size_t whitebox_init_data_size, + WB_CONCAT_VERSION(WB_License_Whitebox) * *whitebox) { if (whitebox == nullptr) { DVLOG(1) << "Invalid parameter: null pointer."; return WB_RESULT_INVALID_PARAMETER; @@ -359,7 +377,7 @@ WB_Result WB_License_Create(const uint8_t* whitebox_init_data, // Should always be non-null on modern compilers // (https://isocpp.org/wiki/faq/freestore-mgmt). - *whitebox = new WB_License_Whitebox(); + *whitebox = new WB_CONCAT_VERSION(WB_License_Whitebox)(); (*whitebox)->signing_key.swap(signing_key); (*whitebox)->encryption_key.swap(encryption_key); (*whitebox)->provider_keys = @@ -368,21 +386,135 @@ WB_Result WB_License_Create(const uint8_t* whitebox_init_data, return WB_RESULT_OK; } -void WB_License_Delete(WB_License_Whitebox* whitebox) { +WB_Result WB_CONCAT_VERSION(WB_License_Import)( + const uint8_t* buffer, + size_t buffer_size, + WB_CONCAT_VERSION(WB_License_Whitebox)** whitebox) { +#ifdef HAS_IMPORT_EXPORT + if (whitebox == nullptr) { + DVLOG(1) << "Invalid parameter: null pointer."; + return WB_RESULT_INVALID_PARAMETER; + } + if (buffer_size == 0 || buffer == nullptr) { + DVLOG(1) << "Invalid parameter: Missing whitebox_init_data."; + return WB_RESULT_INVALID_PARAMETER; + } + if (buffer_size < sizeof(WB_License_ExportedData)) { + DVLOG(1) << "Invalid parameter: Buffer too small."; + return WB_RESULT_BUFFER_TOO_SMALL; + } + + auto* info = reinterpret_cast(buffer); + if (info->version != kExportedVersion) { + DVLOG(1) << "Unsupported version of exported data."; + return WB_RESULT_INVALID_PARAMETER; + } + if (buffer_size < sizeof(WB_License_ExportedData) + + (sizeof(WB_License_ExportedData_Key) * + (info->num_content_keys + info->num_generic_keys))) { + DVLOG(1) << "Invalid parameter: Buffer too small."; + return WB_RESULT_BUFFER_TOO_SMALL; + } + + *whitebox = new WB_CONCAT_VERSION(WB_License_Whitebox)(); + (*whitebox)->initialized = true; + + if (info->has_renewal) { + std::unique_ptr renewal_key{new widevine::RenewalKey}; + renewal_key->status = WB_KEY_STATUS_SIGNING_KEY_VALID; + renewal_key->client = info->renewal_client; + (*whitebox)->renewal_key = std::move(renewal_key); + } + + for (size_t i = 0; i < info->num_content_keys; i++) { + auto& key = info->keys[i]; + CHECK(key.key_id_size <= sizeof(key.key_id)); + + std::string key_id{key.key_id.begin(), + key.key_id.begin() + key.key_id_size}; + (*whitebox)->content_keys.emplace(key_id, key.key); + } + for (size_t i = 0; i < info->num_generic_keys; i++) { + const auto& key = info->keys[info->num_content_keys + i]; + CHECK(key.key_id_size <= sizeof(key.key_id)); + + std::string key_id{key.key_id.data(), key.key_id.data() + key.key_id_size}; + (*whitebox)->generic_keys.emplace(key_id, key.key); + } + + return WB_RESULT_OK; +#else + return WB_RESULT_NOT_IMPLEMENTED; +#endif +} + +void WB_CONCAT_VERSION(WB_License_Delete)( + WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox) { // Safe to delete nullptr (https://isocpp.org/wiki/faq/freestore-mgmt). delete whitebox; } -WB_Result WB_License_SignLicenseRequest_Init() { +WB_Result WB_CONCAT_VERSION(WB_License_ExportKeys)( + const WB_CONCAT_VERSION(WB_License_Whitebox)* whitebox, + uint8_t* buffer, + size_t* buffer_size) { +#ifdef HAS_IMPORT_EXPORT + if (!whitebox || !buffer_size) { + DVLOG(1) << "Invalid parameter: null pointer."; + return WB_RESULT_INVALID_PARAMETER; + } + if (!whitebox->initialized) { + DVLOG(1) << "Invalid state: no license loaded."; + return WB_RESULT_INVALID_STATE; + } + + const size_t required_size = + sizeof(WB_License_ExportedData) + + sizeof(WB_License_ExportedData_Key) * + (whitebox->content_keys.size() + whitebox->generic_keys.size()); + if (!CheckAndUpdateSize(required_size, buffer_size) || !buffer) { + return WB_RESULT_BUFFER_TOO_SMALL; + } + + auto* info = reinterpret_cast(buffer); + info->has_renewal = + whitebox->renewal_key && + whitebox->renewal_key->status == WB_KEY_STATUS_SIGNING_KEY_VALID; + if (info->has_renewal) { + info->renewal_client = whitebox->renewal_key->client; + } + info->version = kExportedVersion; + info->num_content_keys = whitebox->content_keys.size(); + info->num_generic_keys = whitebox->generic_keys.size(); + size_t i = 0; + for (const auto& dict : {whitebox->content_keys, whitebox->generic_keys}) { + for (const auto& pair : dict) { + auto& key = info->keys[i]; + CHECK(pair.first.size() <= sizeof(key.key_id)); + + memcpy(key.key_id.data(), pair.first.data(), pair.first.size()); + key.key_id_size = pair.first.size(); + key.key = pair.second; + i++; + } + } + return WB_RESULT_OK; +#else + return WB_RESULT_NOT_IMPLEMENTED; +#endif +} + +WB_Result WB_CONCAT_VERSION(WB_License_SignLicenseRequest_Init)() { sign_license_request_initialized = true; return WB_RESULT_OK; } -WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox, - const uint8_t* license_request, - size_t license_request_size, - uint8_t* signature, - size_t* signature_size) { +WB_Result WB_CONCAT_VERSION(WB_License_SignLicenseRequest)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* license_request, + size_t license_request_size, + uint8_t* signature, + size_t* signature_size) { if (!sign_license_request_initialized) { DVLOG(1) << "Must successfully call WB_License_SignLicenseRequest_Init first."; @@ -423,7 +555,7 @@ WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox, return WB_RESULT_OK; } -WB_Result WB_License_ProcessLicenseResponse_Init() { +WB_Result WB_CONCAT_VERSION(WB_License_ProcessLicenseResponse_Init)() { if (!sign_license_request_initialized) { return WB_RESULT_INVALID_STATE; } @@ -432,19 +564,20 @@ WB_Result WB_License_ProcessLicenseResponse_Init() { return WB_RESULT_OK; } -WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, - WB_LicenseKeyMode license_key_mode, - const uint8_t* core_message, - size_t core_message_size, - const uint8_t* message, - size_t message_size, - const uint8_t* signature, - size_t signature_size, - const uint8_t* session_key, - size_t session_key_size, - size_t provider_key_id, - const uint8_t* license_request, - size_t license_request_size) { +WB_Result WB_CONCAT_VERSION(WB_License_ProcessLicenseResponse)( + WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + WB_LicenseKeyMode license_key_mode, + const uint8_t* core_message, + size_t core_message_size, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size, + const uint8_t* session_key, + size_t session_key_size, + size_t provider_key_id, + const uint8_t* license_request, + size_t license_request_size) { if (!process_license_response_initialized) { DVLOG(1) << "Must successfully call WB_License_ProcessLicenseResponse_Init " "first."; @@ -583,6 +716,7 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, GetODKContext(combined_message_str, core_message_size, &odk_context); if (result != WB_RESULT_OK) { + DVLOG(1) << "Failed to get ODK context."; return result; } } @@ -604,6 +738,7 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, whitebox->provider_keys, provider_key_id); if (result != WB_RESULT_OK) { + DVLOG(1) << "Failed to parse license."; return result; } @@ -627,15 +762,16 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, return WB_RESULT_OK; } -WB_Result WB_License_LoadEntitledContentKey(WB_License_Whitebox* whitebox, - const uint8_t* entitlement_key_id, - size_t entitlement_key_id_size, - const uint8_t* content_key_id, - size_t content_key_id_size, - const uint8_t* iv, - size_t iv_size, - const uint8_t* key_data, - size_t key_data_size) { +WB_Result WB_CONCAT_VERSION(WB_License_LoadEntitledContentKey)( + WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* entitlement_key_id, + size_t entitlement_key_id_size, + const uint8_t* content_key_id, + size_t content_key_id_size, + const uint8_t* iv, + size_t iv_size, + const uint8_t* key_data, + size_t key_data_size) { #ifndef HAS_ENTITLEMENT return WB_RESULT_NOT_IMPLEMENTED; #else @@ -647,6 +783,10 @@ WB_Result WB_License_LoadEntitledContentKey(WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: key data too small."; return WB_RESULT_INVALID_PARAMETER; } + if (entitlement_key_id_size > 16 || content_key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } if (!whitebox->initialized) { DVLOG(1) << "Invalid state: no license loaded."; @@ -691,9 +831,10 @@ WB_Result WB_License_LoadEntitledContentKey(WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_RemoveEntitledContentKey(WB_License_Whitebox* whitebox, - const uint8_t* content_key_id, - size_t content_key_id_size) { +WB_Result WB_CONCAT_VERSION(WB_License_RemoveEntitledContentKey)( + WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* content_key_id, + size_t content_key_id_size) { #ifndef HAS_ENTITLEMENT return WB_RESULT_NOT_IMPLEMENTED; #else @@ -701,6 +842,10 @@ WB_Result WB_License_RemoveEntitledContentKey(WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: null pointer."; return WB_RESULT_INVALID_PARAMETER; } + if (content_key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } if (!whitebox->initialized) { DVLOG(1) << "Invalid state: no license loaded."; return WB_RESULT_INVALID_STATE; @@ -719,15 +864,20 @@ WB_Result WB_License_RemoveEntitledContentKey(WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox, - WB_KeyQueryType type, - const uint8_t* key_id, - size_t key_id_size, - WB_KeyStatus* key_status) { +WB_Result WB_CONCAT_VERSION(WB_License_QueryKeyStatus)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + WB_KeyQueryType type, + const uint8_t* key_id, + size_t key_id_size, + WB_KeyStatus* key_status) { if (!whitebox || !key_status) { DVLOG(1) << "Invalid parameter: null pointer."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } if (!whitebox->initialized) { DVLOG(1) << "Invalid state: no license loaded."; @@ -791,12 +941,13 @@ WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox, return WB_RESULT_INVALID_PARAMETER; // Unknown query type. } -static WB_Result WB_License_SignCommon(const WB_License_Whitebox* whitebox, - const uint8_t* message, - size_t message_size, - uint8_t* signature, - size_t* signature_size, - bool sha256) { +static WB_Result WB_License_SignCommon( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* message, + size_t message_size, + uint8_t* signature, + size_t* signature_size, + bool sha256) { if (!whitebox || !message || !signature_size) { DVLOG(1) << "Invalid parameter: null pointer."; return WB_RESULT_INVALID_PARAMETER; @@ -844,20 +995,22 @@ static WB_Result WB_License_SignCommon(const WB_License_Whitebox* whitebox, return WB_RESULT_OK; } -WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox, - const uint8_t* message, - size_t message_size, - uint8_t* signature, - size_t* signature_size) { +WB_Result WB_CONCAT_VERSION(WB_License_SignRenewalRequest)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* message, + size_t message_size, + uint8_t* signature, + size_t* signature_size) { return WB_License_SignCommon(whitebox, message, message_size, signature, signature_size, /* sha256= */ true); } -WB_Result WB_License_SignPstReport(const WB_License_Whitebox* whitebox, - const uint8_t* message, - size_t message_size, - uint8_t* signature, - size_t* signature_size) { +WB_Result WB_CONCAT_VERSION(WB_License_SignPstReport)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* message, + size_t message_size, + uint8_t* signature, + size_t* signature_size) { #ifndef HAS_SIGN_PST_REPORT return WB_RESULT_NOT_IMPLEMENTED; #else @@ -866,11 +1019,12 @@ WB_Result WB_License_SignPstReport(const WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox, - const uint8_t* message, - size_t message_size, - const uint8_t* signature, - size_t signature_size) { +WB_Result WB_CONCAT_VERSION(WB_License_VerifyRenewalResponse)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size) { if (!whitebox || !message || !signature) { DVLOG(1) << "Invalid parameter: null pointer"; return WB_RESULT_INVALID_PARAMETER; @@ -916,12 +1070,13 @@ WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox, return WB_RESULT_OK; } -WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox, - WB_CipherMode mode, - const uint8_t* key_id, - size_t key_id_size, - uint8_t* secret_string, - size_t* secret_string_size) { +WB_Result WB_CONCAT_VERSION(WB_License_GetSecretString)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + uint8_t* secret_string, + size_t* secret_string_size) { #ifdef ALWAYS_DECRYPT_TO_CLEAR return WB_RESULT_NOT_IMPLEMENTED; #else @@ -954,6 +1109,10 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: array size 0."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } // The secret string can differ between keys, so we need to make sure that // the key id is actually a content key. @@ -981,15 +1140,16 @@ WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* output_data, - size_t* output_data_size) { +WB_Result WB_CONCAT_VERSION(WB_License_GenericEncrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size) { #ifndef HAS_GENERIC_CRYPTO return WB_RESULT_NOT_IMPLEMENTED; #else @@ -1010,6 +1170,10 @@ WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: array size 0."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size}); if (it == whitebox->generic_keys.end()) { @@ -1038,15 +1202,16 @@ WB_Result WB_License_GenericEncrypt(const WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* output_data, - size_t* output_data_size) { +WB_Result WB_CONCAT_VERSION(WB_License_GenericDecrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size) { #ifndef HAS_GENERIC_CRYPTO return WB_RESULT_NOT_IMPLEMENTED; #else @@ -1067,6 +1232,10 @@ WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: array size 0."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size}); if (it == whitebox->generic_keys.end()) { @@ -1095,13 +1264,14 @@ WB_Result WB_License_GenericDecrypt(const WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* message, - size_t message_size, - uint8_t* output_data, - size_t* output_data_size) { +WB_Result WB_CONCAT_VERSION(WB_License_GenericSign)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* message, + size_t message_size, + uint8_t* output_data, + size_t* output_data_size) { #ifndef HAS_GENERIC_CRYPTO return WB_RESULT_NOT_IMPLEMENTED; #else @@ -1127,6 +1297,10 @@ WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: array size 0."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size}); if (it == whitebox->generic_keys.end()) { @@ -1149,13 +1323,14 @@ WB_Result WB_License_GenericSign(const WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* message, - size_t message_size, - const uint8_t* signature, - size_t signature_size) { +WB_Result WB_CONCAT_VERSION(WB_License_GenericVerify)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* message, + size_t message_size, + const uint8_t* signature, + size_t signature_size) { #ifndef HAS_GENERIC_CRYPTO return WB_RESULT_NOT_IMPLEMENTED; #else @@ -1173,6 +1348,10 @@ WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: array size 0."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } auto it = whitebox->generic_keys.find({key_id, key_id + key_id_size}); if (it == whitebox->generic_keys.end()) { @@ -1197,16 +1376,17 @@ WB_Result WB_License_GenericVerify(const WB_License_Whitebox* whitebox, #endif } -WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox, - WB_CipherMode mode, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* output_data, - size_t* output_data_size) { +WB_Result WB_CONCAT_VERSION(WB_License_Decrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* output_data, + size_t* output_data_size) { if (!whitebox || !key_id) { DVLOG(1) << "Invalid parameter: null pointer."; return WB_RESULT_INVALID_PARAMETER; @@ -1221,6 +1401,10 @@ WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: array size 0."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } const auto* content_key = FindKey(whitebox, key_id, key_id_size); @@ -1246,16 +1430,17 @@ WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox, output_data_size); } -WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox, - WB_CipherMode mode, - const uint8_t* key_id, - size_t key_id_size, - const uint8_t* input_data, - size_t input_data_size, - const uint8_t* iv, - size_t iv_size, - uint8_t* masked_output_data, - size_t* masked_output_data_size) { +WB_Result WB_CONCAT_VERSION(WB_License_MaskedDecrypt)( + const WB_CONCAT_VERSION(WB_License_Whitebox) * whitebox, + WB_CipherMode mode, + const uint8_t* key_id, + size_t key_id_size, + const uint8_t* input_data, + size_t input_data_size, + const uint8_t* iv, + size_t iv_size, + uint8_t* masked_output_data, + size_t* masked_output_data_size) { #ifdef ALWAYS_DECRYPT_TO_CLEAR return WB_RESULT_NOT_IMPLEMENTED; #else @@ -1273,6 +1458,10 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox, DVLOG(1) << "Invalid parameter: array size 0."; return WB_RESULT_INVALID_PARAMETER; } + if (key_id_size > 16) { + DVLOG(1) << "Invalid parameter: key id too big."; + return WB_RESULT_INVALID_PARAMETER; + } const auto* content_key = FindKey(whitebox, key_id, key_id_size); @@ -1322,12 +1511,12 @@ WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox, #endif } -void WB_License_Unmask(const uint8_t* masked_data, - size_t offset, - size_t size, - const uint8_t* secret_string, - size_t secret_string_size, - uint8_t* unmasked_data) { +void WB_CONCAT_VERSION(WB_License_Unmask)(const uint8_t* masked_data, + size_t offset, + size_t size, + const uint8_t* secret_string, + size_t secret_string_size, + uint8_t* unmasked_data) { // No return code, so only check if parameters are valid. CHECK(masked_data); CHECK(secret_string); diff --git a/whitebox/reference/impl/odk_license_parser.cc b/whitebox/reference/impl/odk_license_parser.cc index 90f2a9e..c22f81b 100644 --- a/whitebox/reference/impl/odk_license_parser.cc +++ b/whitebox/reference/impl/odk_license_parser.cc @@ -95,6 +95,10 @@ WB_Result OdkLicenseParser::Parse(const std::string& decryption_key, VLOG(3) << "Invalid key at index " << i << " : no key id."; continue; } + if (key_id.size() > 16) { + VLOG(3) << "Invalid key at index " << i << " : key id too big."; + continue; + } // Add the key right away. The key will be invalid, so if we fail to // parse the key, we'll already have an entry for the invalid key. diff --git a/whitebox/reference/impl/protobuf_license_parser.cc b/whitebox/reference/impl/protobuf_license_parser.cc index 15b02ee..960b0e8 100644 --- a/whitebox/reference/impl/protobuf_license_parser.cc +++ b/whitebox/reference/impl/protobuf_license_parser.cc @@ -87,6 +87,11 @@ WB_Result ProtobufLicenseParser::Parse( kEnableHwVerification && IsPlatformHardwareVerified(license); for (const auto& key : license.key()) { + if (key.id().size() > 16) { + VLOG(3) << "Skipping key : key id too big."; + continue; + } + // The default `type()` value will be SIGNING when not present in the // protobuf. switch (key.type()) {