Add import/export and version API

This commit is contained in:
Jacob Trimble
2024-11-22 00:03:38 +00:00
parent c0f0fb3ff8
commit 77a33b906a
23 changed files with 1105 additions and 648 deletions

View File

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

61
whitebox/api/enums.h Normal file
View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
#include <memory>
#include <vector>
#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"

View File

@@ -26,7 +26,7 @@ const size_t kInvalidProviderKeyId = 0xfff;
class LicenseWhiteboxDecryptTest
: public LicenseWhiteboxTestBase,
public ::testing::WithParamInterface<std::tuple<Padding, size_t>> {
public ::testing::WithParamInterface<std::tuple<Padding, size_t, bool>> {
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

View File

@@ -3,9 +3,11 @@
#include "api/license_whitebox.h"
#include <string>
#include <tuple>
#include <vector>
#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<bool> {
public testing::WithParamInterface<std::tuple<bool, bool>> {
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<TestServer> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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<uint8_t> 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

View File

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

View File

@@ -6,7 +6,7 @@
#include <vector>
#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"

View File

@@ -4,7 +4,7 @@
#include <stdint.h>
#include <tuple>
#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"

View File

@@ -6,7 +6,7 @@
#include <memory>
#include <vector>
#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"

View File

@@ -4,6 +4,7 @@
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "api/license_whitebox_test_base.h"
@@ -18,7 +19,7 @@ constexpr const bool kRenewal = true;
class LicenseWhiteboxSignRenewalPstTest
: public LicenseWhiteboxTestBase,
public testing::WithParamInterface<bool> {
public testing::WithParamInterface<std::tuple<bool, bool>> {
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<bool>& info) {
return info.param == kRenewal ? "Renewal" : "PST";
});
INSTANTIATE_TEST_SUITE_P(
TestAll,
LicenseWhiteboxSignRenewalPstTest,
testing::Combine(testing::Bool(), testing::Bool()),
[](const testing::TestParamInfo<std::tuple<bool, bool>>& 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

View File

@@ -19,6 +19,26 @@ void LicenseWhiteboxTestBase::TearDown() {
WB_License_Delete(whitebox_);
}
void LicenseWhiteboxTestBase::RecreateOffline() {
std::vector<uint8_t> 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<uint8_t>* data) const {
ASSERT_TRUE(data);
ASSERT_GT(data->size(), 0u);

View File

@@ -6,7 +6,7 @@
#include <memory>
#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<uint8_t>* data) const;

View File

@@ -5,6 +5,7 @@
#include <vector>
#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"

View File

@@ -6,7 +6,7 @@
#include <memory>
#include <vector>
#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"

View File

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

View File

@@ -5,7 +5,6 @@
#include <array>
#include <cstdint>
#include <string>
#include "api/license_whitebox.h"
#include "license_protocol.pb.h"

View File

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

View File

@@ -3,9 +3,11 @@
#ifndef WHITEBOX_REFERENCE_IMPL_LICENSE_PARSER_H_
#define WHITEBOX_REFERENCE_IMPL_LICENSE_PARSER_H_
#include <array>
#include <map>
#include <string>
#include <vector>
#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<uint8_t> mask;
std::string key;
std::array<uint8_t, 16> mask;
std::array<uint8_t, 16> key;
};
LicenseParser() = default;

View File

@@ -110,10 +110,26 @@ std::string MakeString(const uint8_t* data, size_t size) {
}
#endif
struct WB_License_ExportedData_Key {
std::array<uint8_t, 16> key_id;
uint8_t key_id_size;
widevine::InternalKey key;
};
struct WB_License_ExportedData {
uint8_t version;
bool has_renewal;
std::array<uint8_t, 32> 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<uint8_t> 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<widevine::LicenseParser::ProviderKey> 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<widevine::LicenseParser::ProviderKey> 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<const WB_License_ExportedData*>(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<widevine::RenewalKey> 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<WB_License_ExportedData*>(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);

View File

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

View File

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