diff --git a/whitebox/api/license_whitebox.h b/whitebox/api/license_whitebox.h index 31f553a..6f339bb 100644 --- a/whitebox/api/license_whitebox.h +++ b/whitebox/api/license_whitebox.h @@ -100,6 +100,20 @@ WB_Result WB_License_Create(const uint8_t* whitebox_init_data, // result in a no-op. void WB_License_Delete(WB_License_Whitebox* whitebox); +// Initializes tables and data needed for the WB_License_SignLicenseRequest() +// function. +// +// Only the first successfull call is processed. subsequent calls are no-op. Can +// be called on the same thread or on a different thread before, while or after +// WB_License_Create(), WB_License_Delete() are called, but must be called and +// completed before other whitebox methods are called, including +// WB_License_SignLicenseRequest(). +// +// Returns: +// WB_RESULT_OK if the initialization succeeded. +// WB_RESULT_INVALID_STATE otherwise. +WB_Result WB_License_SignLicenseRequest_Init(); + // Signs a license request using the CDM's private signing key. // // Args: @@ -126,12 +140,30 @@ void WB_License_Delete(WB_License_Whitebox* whitebox); // // WB_RESULT_BUFFER_TOO_SMALL if |signature_size| (as input) was less than the // required size. +// +// 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); +// Initializes tables and data needed for the +// WB_License_ProcessLicenseResponse() function. +// +// +// Only the first successfull call is processed. subsequent calls are no-op. Can +// be called on the same thread or on a different thread before, while or after +// WB_License_Create(), WB_License_Delete(), or WB_License_SignLicenseRequest() +// are called, but must be called and completed before other whitebox methods +// are called, including WB_License_ProcessLicenseResponse(). +// +// Returns: +// WB_RESULT_OK if the initialization succeeded. +// WB_RESULT_INVALID_STATE otherwise. +WB_Result WB_License_ProcessLicenseResponse_Init(); + // Verifies a license response using HMAC and the server signing key. // // Extracts and loads content and signing keys for use. Any content keys that @@ -194,7 +226,8 @@ WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox, // |signature| or if |session_key| could not be unwrapped correctly (and // interferes with verification). // -// WB_RESULT_INVALID_STATE if a license has already been loaded. +// WB_RESULT_INVALID_STATE if a license has already been loaded, or if +// WB_License_ProcessLicenseResponse_Init() has not been called and completed. // // Notes: // We allow a modified session key to be used. Using it will cause message diff --git a/whitebox/api/license_whitebox_decrypt_benchmark.cc b/whitebox/api/license_whitebox_decrypt_benchmark.cc index 92c46d1..5feaff5 100644 --- a/whitebox/api/license_whitebox_decrypt_benchmark.cc +++ b/whitebox/api/license_whitebox_decrypt_benchmark.cc @@ -51,6 +51,8 @@ class LicenseWhiteboxDecryptBenchmark const auto license = CreateLicense(WB_LICENSE_KEY_MODE_DUAL_KEY, 1, SecurityLevel::kSoftwareSecureCrypto, kNoProviderKeyId); + ASSERT_EQ(WB_License_SignLicenseRequest_Init(), WB_RESULT_OK); + ASSERT_EQ(WB_License_ProcessLicenseResponse_Init(), WB_RESULT_OK); ASSERT_EQ( WB_License_ProcessLicenseResponse( whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, diff --git a/whitebox/api/license_whitebox_sign_benchmark.cc b/whitebox/api/license_whitebox_sign_benchmark.cc index f54d61c..47dac91 100644 --- a/whitebox/api/license_whitebox_sign_benchmark.cc +++ b/whitebox/api/license_whitebox_sign_benchmark.cc @@ -39,6 +39,8 @@ class LicenseWhiteboxSignBenchmark auto init_data = GetLicenseWhiteboxProviderKeysInitData(); ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_), WB_RESULT_OK); + ASSERT_EQ(WB_License_SignLicenseRequest_Init(), WB_RESULT_OK); + ASSERT_EQ(WB_License_ProcessLicenseResponse_Init(), WB_RESULT_OK); const auto license = CreateLicense( key_mode_, 1, SecurityLevel::kSoftwareSecureCrypto, kNoProviderKeyId); diff --git a/whitebox/api/license_whitebox_sign_renewal_request_test.cc b/whitebox/api/license_whitebox_sign_renewal_request_test.cc index 5a92ade..3e9087c 100644 --- a/whitebox/api/license_whitebox_sign_renewal_request_test.cc +++ b/whitebox/api/license_whitebox_sign_renewal_request_test.cc @@ -46,6 +46,8 @@ class LicenseWhiteboxSignRenewalPstTest License license; builder.Build(*server, &license); + ASSERT_EQ(WB_License_SignLicenseRequest_Init(), WB_RESULT_OK); + ASSERT_EQ(WB_License_ProcessLicenseResponse_Init(), WB_RESULT_OK); ASSERT_EQ( WB_License_ProcessLicenseResponse( whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, @@ -283,6 +285,8 @@ TEST_P(LicenseWhiteboxSignRenewalPstTest, KeyUnavailableForNoSigningKey) { License license; builder.Build(*server, &license); + ASSERT_EQ(WB_License_SignLicenseRequest_Init(), WB_RESULT_OK); + ASSERT_EQ(WB_License_ProcessLicenseResponse_Init(), WB_RESULT_OK); ASSERT_EQ( WB_License_ProcessLicenseResponse( whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, license.core_message.data(), diff --git a/whitebox/api/license_whitebox_test_base.cc b/whitebox/api/license_whitebox_test_base.cc index 5479078..da5c67a 100644 --- a/whitebox/api/license_whitebox_test_base.cc +++ b/whitebox/api/license_whitebox_test_base.cc @@ -11,6 +11,8 @@ void LicenseWhiteboxTestBase::SetUp() { auto init_data = GetLicenseWhiteboxProviderKeysInitData(); ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_), WB_RESULT_OK); + ASSERT_EQ(WB_License_SignLicenseRequest_Init(), WB_RESULT_OK); + ASSERT_EQ(WB_License_ProcessLicenseResponse_Init(), WB_RESULT_OK); } void LicenseWhiteboxTestBase::TearDown() { diff --git a/whitebox/api/license_whitebox_verify_benchmark.cc b/whitebox/api/license_whitebox_verify_benchmark.cc index 284574b..16a5d09 100644 --- a/whitebox/api/license_whitebox_verify_benchmark.cc +++ b/whitebox/api/license_whitebox_verify_benchmark.cc @@ -31,6 +31,8 @@ class LicenseWhiteboxVerifyBenchmark : public LicenseWhiteboxBenchmark { auto init_data = GetLicenseWhiteboxProviderKeysInitData(); ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_), WB_RESULT_OK); + ASSERT_EQ(WB_License_SignLicenseRequest_Init(), WB_RESULT_OK); + ASSERT_EQ(WB_License_ProcessLicenseResponse_Init(), WB_RESULT_OK); const auto license = CreateLicense(WB_LICENSE_KEY_MODE_DUAL_KEY, 1, diff --git a/whitebox/reference/impl/license_whitebox_impl.cc b/whitebox/reference/impl/license_whitebox_impl.cc index e37b6c2..a46e8ce 100644 --- a/whitebox/reference/impl/license_whitebox_impl.cc +++ b/whitebox/reference/impl/license_whitebox_impl.cc @@ -3,6 +3,7 @@ #include "api/license_whitebox.h" #include +#include #include #include #include @@ -46,6 +47,9 @@ using AesCtrDecryptor = widevine::AesCtrEncryptor; using KeyContainer = video_widevine::License_KeyContainer; using RsaPrivateKey = widevine::RsaPrivateKey; +static std::atomic sign_license_request_initialized(false); +static std::atomic process_license_response_initialized(false); + bool IsOdkVersionSupported(uint16_t major_version, uint16_t minor_version) { // Only ODK v16.5 and later support the fields needed. constexpr uint16_t first_major_version_supported = 16; @@ -299,11 +303,22 @@ void WB_License_Delete(WB_License_Whitebox* whitebox) { delete whitebox; } +WB_Result 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) { + if (!sign_license_request_initialized) { + DVLOG(1) + << "Must successfully call WB_License_SignLicenseRequest_Init first."; + return WB_RESULT_INVALID_STATE; + } + if (!whitebox || !signature_size) { DVLOG(1) << "Invalid parameter: null pointer."; return WB_RESULT_INVALID_PARAMETER; @@ -338,6 +353,15 @@ WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox, return WB_RESULT_OK; } +WB_Result WB_License_ProcessLicenseResponse_Init() { + if (!sign_license_request_initialized) { + return WB_RESULT_INVALID_STATE; + } + + process_license_response_initialized = true; + return WB_RESULT_OK; +} + WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, WB_LicenseKeyMode license_key_mode, const uint8_t* core_message, @@ -351,6 +375,12 @@ WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, 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."; + return WB_RESULT_INVALID_STATE; + } + const size_t kSigningKeySizeBytes = widevine::crypto_util::kSigningKeySizeBytes;