diff --git a/whitebox/api/license_whitebox.h b/whitebox/api/license_whitebox.h index b82d14b..1e507f0 100644 --- a/whitebox/api/license_whitebox.h +++ b/whitebox/api/license_whitebox.h @@ -237,8 +237,8 @@ WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox, size_t key_id_size, WB_KeyStatus* key_status); -// Signs |message| and return the signature via |signature| using HMAC and the -// client renewal signing key +// Signs |message| and return the signature via |signature| using HMAC-SHA256 +// and the client renewal signing key // // Args: // whitebox (in) : The white-box instance containing the signing key. @@ -272,6 +272,41 @@ WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox, uint8_t* signature, size_t* signature_size); +// Signs |message| and return the signature via |signature| using HMAC-SHA1 and +// the client renewal signing key +// +// Args: +// whitebox (in) : The white-box instance containing the signing key. +// +// message (in) : The message that should be signed. +// +// message_size (in) : The number of bytes in |message|. +// +// signature (out) : The output parameter used to return the signature. This +// can be null if |*signature_size| is 0; this should return +// WB_RESULT_BUFFER_TOO_SMALL and fill |signature_size|. +// +// signature_size (in/out) : As input, this contains the max number of bytes +// that can be written to |signature|. As output, |signature_size| is set to +// the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL. +// +// Returns: +// WB_RESULT_OK if |message| was successfully signed. +// +// WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |message| was null, +// if |message_size| was zero, if |signature| was null, or if |signature_size| +// was null. +// +// WB_RESULT_BUFFER_TOO_SMALL if |signature_size| (as input) was less than the +// 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); + // Verifies the renewal response using HMAC and the server signing key. // // Args: diff --git a/whitebox/api/license_whitebox_sign_renewal_request_test.cc b/whitebox/api/license_whitebox_sign_renewal_request_test.cc index d0803db..a9ace5e 100644 --- a/whitebox/api/license_whitebox_sign_renewal_request_test.cc +++ b/whitebox/api/license_whitebox_sign_renewal_request_test.cc @@ -14,7 +14,9 @@ namespace widevine { -class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase { +class LicenseWhiteboxSignRenewalPstTest + : public LicenseWhiteboxTestBase, + public testing::WithParamInterface { protected: void SetUp() override { LicenseWhiteboxTestBase::SetUp(); @@ -23,6 +25,9 @@ class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase { // that it should accomidate any change in signature size. signature_size_ = 256; signature_.resize(signature_size_); + + sign_func_ = + GetParam() ? &WB_License_SignRenewalRequest : &WB_License_SignPstReport; } void LoadLicense(const TestLicenseBuilder::Settings& settings) { @@ -57,8 +62,10 @@ class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase { std::string key_str(signing_key_.begin(), signing_key_.end()); key_str.erase(0, crypto_util::kSigningKeySizeBytes); - const std::string signature = crypto_util::CreateSignatureHmacSha256( - key_str, std::string(message.begin(), message.end())); + auto func = GetParam() ? &widevine::crypto_util::CreateSignatureHmacSha256 + : &widevine::crypto_util::CreateSignatureHmacSha1; + const std::string signature = + func(key_str, std::string(message.begin(), message.end())); return std::vector(signature.begin(), signature.end()); } @@ -78,108 +85,105 @@ class LicenseWhiteboxSignRenewalRequestTest : public LicenseWhiteboxTestBase { 0x06, 0xbd, 0x2c, 0x66, 0x10, 0x42, 0x73, 0x8d, 0x88, 0x9b, 0x18, 0xcc, 0xcb, 0x7e, 0x43, 0x23, 0x06, 0xe9, 0x8f, 0x8f, }; + + // Both functions have the same signature; store a pointer to which function + // to call. + decltype(&WB_License_SignRenewalRequest) sign_func_; }; -TEST_F(LicenseWhiteboxSignRenewalRequestTest, SuccessWithInvalidRequest) { - TestLicenseBuilder::Settings settings; - settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); - - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_OK); - - signature_.resize(signature_size_); - ASSERT_EQ(signature_, GetSignature(garbage_request_)); -} - -TEST_F(LicenseWhiteboxSignRenewalRequestTest, - SuccessWithSigningKeyPKSC8Padding) { - TestLicenseBuilder::Settings settings; - settings.padding = TestLicenseBuilder::Padding::kPKSC8; - LoadLicense(settings); - - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_OK); - - signature_.resize(signature_size_); - ASSERT_EQ(signature_, GetSignature(garbage_request_)); -} - -TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidParameterForNullWhitebox) { - TestLicenseBuilder::Settings settings; - settings.padding = TestLicenseBuilder::Padding::kNone; - LoadLicense(settings); - - ASSERT_EQ(WB_License_SignRenewalRequest(nullptr, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_INVALID_PARAMETER); -} - -TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidParameterForNullMessage) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, SuccessWithInvalidRequest) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; LoadLicense(settings); ASSERT_EQ( - WB_License_SignRenewalRequest(whitebox_, nullptr, garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_INVALID_PARAMETER); + sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), + signature_.data(), &signature_size_), + WB_RESULT_OK); + + signature_.resize(signature_size_); + ASSERT_EQ(signature_, GetSignature(garbage_request_)); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, - InvalidParameterForZeroMessageSize) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, SuccessWithSigningKeyPKSC8Padding) { + TestLicenseBuilder::Settings settings; + settings.padding = TestLicenseBuilder::Padding::kPKSC8; + LoadLicense(settings); + + ASSERT_EQ( + sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), + signature_.data(), &signature_size_), + WB_RESULT_OK); + + signature_.resize(signature_size_); + ASSERT_EQ(signature_, GetSignature(garbage_request_)); +} + +TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullWhitebox) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; LoadLicense(settings); - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), 0, - signature_.data(), &signature_size_), + ASSERT_EQ( + sign_func_(nullptr, garbage_request_.data(), garbage_request_.size(), + signature_.data(), &signature_size_), + WB_RESULT_INVALID_PARAMETER); +} + +TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullMessage) { + TestLicenseBuilder::Settings settings; + settings.padding = TestLicenseBuilder::Padding::kNone; + LoadLicense(settings); + + ASSERT_EQ(sign_func_(whitebox_, nullptr, garbage_request_.size(), + signature_.data(), &signature_size_), WB_RESULT_INVALID_PARAMETER); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, CanProbeSizeWithNullSignature) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForZeroMessageSize) { + TestLicenseBuilder::Settings settings; + settings.padding = TestLicenseBuilder::Padding::kNone; + LoadLicense(settings); + + ASSERT_EQ(sign_func_(whitebox_, garbage_request_.data(), 0, signature_.data(), + &signature_size_), + WB_RESULT_INVALID_PARAMETER); +} + +TEST_P(LicenseWhiteboxSignRenewalPstTest, CanProbeSizeWithNullSignature) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; LoadLicense(settings); signature_size_ = 0; - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), nullptr, - &signature_size_), + ASSERT_EQ(sign_func_(whitebox_, garbage_request_.data(), + garbage_request_.size(), nullptr, &signature_size_), WB_RESULT_BUFFER_TOO_SMALL); ASSERT_GT(signature_size_, 0); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, - InvalidParameterForNullSignature) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullSignature) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; LoadLicense(settings); - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), nullptr, - &signature_size_), + ASSERT_EQ(sign_func_(whitebox_, garbage_request_.data(), + garbage_request_.size(), nullptr, &signature_size_), WB_RESULT_INVALID_PARAMETER); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, +TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidParameterForNullSignatureSize) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; LoadLicense(settings); - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), nullptr), + ASSERT_EQ(sign_func_(whitebox_, garbage_request_.data(), + garbage_request_.size(), signature_.data(), nullptr), WB_RESULT_INVALID_PARAMETER); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, BufferTooSmall) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, BufferTooSmall) { TestLicenseBuilder::Settings settings; settings.padding = TestLicenseBuilder::Padding::kNone; LoadLicense(settings); @@ -189,10 +193,10 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, BufferTooSmall) { // "too small". signature_size_ = 1; - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_BUFFER_TOO_SMALL); + ASSERT_EQ( + sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), + signature_.data(), &signature_size_), + WB_RESULT_BUFFER_TOO_SMALL); // Since the API does not limit the signature size, we can't specify the // actual expected size, however, it should at least be greater than our "too @@ -200,18 +204,18 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, BufferTooSmall) { ASSERT_GT(signature_size_, 1u); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, InvalidStateForNoLicense) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, InvalidStateForNoLicense) { // Unlike the other tests, we do not call LoadLicense() because we need to // have no license loaded in order to have no renewal key, which is the // criteria WB_RESULT_INVALID_STATE. - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_INVALID_STATE); + ASSERT_EQ( + sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), + signature_.data(), &signature_size_), + WB_RESULT_INVALID_STATE); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, KeyUnavailableForNoSigningKey) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, KeyUnavailableForNoSigningKey) { // Make a license with no signing key but has a content key. Every license // must have a content key. TestLicenseBuilder builder; @@ -231,13 +235,13 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, KeyUnavailableForNoSigningKey) { license.request.data(), license.request.size()), WB_RESULT_OK); - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_KEY_UNAVAILABLE); + ASSERT_EQ( + sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), + signature_.data(), &signature_size_), + WB_RESULT_KEY_UNAVAILABLE); } -TEST_F(LicenseWhiteboxSignRenewalRequestTest, KeyUnavailableForInvalidKey) { +TEST_P(LicenseWhiteboxSignRenewalPstTest, KeyUnavailableForInvalidKey) { // There are multiple ways for us to invalid a signing key. We have tests that // test invalid keys (see the query signing key status tests). But here, we // just need an invalid key, so we use one way of invalidating the key. @@ -245,10 +249,17 @@ TEST_F(LicenseWhiteboxSignRenewalRequestTest, KeyUnavailableForInvalidKey) { settings.include_signing_key_iv = false; LoadLicense(settings); - ASSERT_EQ(WB_License_SignRenewalRequest(whitebox_, garbage_request_.data(), - garbage_request_.size(), - signature_.data(), &signature_size_), - WB_RESULT_KEY_UNAVAILABLE); + ASSERT_EQ( + sign_func_(whitebox_, garbage_request_.data(), garbage_request_.size(), + signature_.data(), &signature_size_), + WB_RESULT_KEY_UNAVAILABLE); } +INSTANTIATE_TEST_SUITE_P(TestAll, + LicenseWhiteboxSignRenewalPstTest, + testing::Bool(), + [](const testing::TestParamInfo& info) { + return info.param ? "Renewal" : "PST"; + }); + } // namespace widevine diff --git a/whitebox/reference/impl/license_whitebox_impl.cc b/whitebox/reference/impl/license_whitebox_impl.cc index 0ec269b..64df28e 100644 --- a/whitebox/reference/impl/license_whitebox_impl.cc +++ b/whitebox/reference/impl/license_whitebox_impl.cc @@ -511,17 +511,19 @@ WB_Result WB_License_QueryKeyStatus(const WB_License_Whitebox* whitebox, return WB_RESULT_INVALID_PARAMETER; // Unknown query type. } -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) { +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) { if (!whitebox || !message || !signature_size) { DVLOG(1) << "Invalid parameter: null pointer."; return WB_RESULT_INVALID_PARAMETER; } - if (!CheckAndUpdateSize(SHA256_DIGEST_LENGTH, signature_size)) { + if (!CheckAndUpdateSize(sha256 ? SHA256_DIGEST_LENGTH : SHA_DIGEST_LENGTH, + signature_size)) { return WB_RESULT_BUFFER_TOO_SMALL; } @@ -550,17 +552,36 @@ WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox, return WB_RESULT_KEY_UNAVAILABLE; } + auto func = sha256 ? &widevine::crypto_util::CreateSignatureHmacSha256 + : &widevine::crypto_util::CreateSignatureHmacSha1; const std::string computed_signature = - widevine::crypto_util::CreateSignatureHmacSha256( - std::string(whitebox->renewal_key->client.begin(), - whitebox->renewal_key->client.end()), - std::string(message, message + message_size)); + func(std::string(whitebox->renewal_key->client.begin(), + whitebox->renewal_key->client.end()), + std::string(message, message + message_size)); CHECK(widevine::MemCopy(computed_signature.data(), computed_signature.size(), signature, *signature_size)); 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) { + 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) { + return WB_License_SignCommon(whitebox, message, message_size, signature, + signature_size, /* sha256= */ false); +} + WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox, const uint8_t* message, size_t message_size,