Fix AssetId overflow for classic WVM decryption

Javascript/JSON does not support int64_t or unsigned numbers. asset_id,
if greater than 0x80000000 will be converted to negative number. Use
double to represent asset_id instead as 32-bit integer can be lossless
represented using double.

Bug: 26309000

Change-Id: I3e800c396a1231375776295154fb0d96156e980b
This commit is contained in:
KongQun Yang 2016-01-05 15:17:32 -08:00 committed by Gerrit Code Review
parent a9b039c3f9
commit a4659c40dd
2 changed files with 39 additions and 8 deletions

View File

@ -184,7 +184,9 @@ Status WidevineKeySource::FetchKeys(const std::vector<uint8_t>& pssh_data) {
Status WidevineKeySource::FetchKeys(uint32_t asset_id) { Status WidevineKeySource::FetchKeys(uint32_t asset_id) {
base::AutoLock scoped_lock(lock_); base::AutoLock scoped_lock(lock_);
request_dict_.Clear(); request_dict_.Clear();
request_dict_.SetInteger("asset_id", asset_id); // Javascript/JSON does not support int64_t or unsigned numbers. Use double
// instead as 32-bit integer can be lossless represented using double.
request_dict_.SetDouble("asset_id", asset_id);
return FetchKeysInternal(!kEnableKeyRotation, 0, true); return FetchKeysInternal(!kEnableKeyRotation, 0, true);
} }
@ -381,12 +383,18 @@ void WidevineKeySource::FillRequest(bool enable_key_rotation,
// Build key rotation fields. // Build key rotation fields.
if (enable_key_rotation) { if (enable_key_rotation) {
request_dict_.SetInteger("first_crypto_period_index", // Javascript/JSON does not support int64_t or unsigned numbers. Use double
// instead as 32-bit integer can be lossless represented using double.
request_dict_.SetDouble("first_crypto_period_index",
first_crypto_period_index); first_crypto_period_index);
request_dict_.SetInteger("crypto_period_count", crypto_period_count_); request_dict_.SetInteger("crypto_period_count", crypto_period_count_);
} }
base::JSONWriter::Write(request_dict_, request); base::JSONWriter::WriteWithOptions(
request_dict_,
// Write doubles that have no fractional part as a normal integer, i.e.
// without using exponential notation or appending a '.0'.
base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION, request);
} }
Status WidevineKeySource::GenerateKeyMessage(const std::string& request, Status WidevineKeySource::GenerateKeyMessage(const std::string& request,

View File

@ -43,6 +43,12 @@ const char kLicenseStatusUnknownError[] = "UNKNOWN_ERROR";
const char kExpectedRequestMessageFormat[] = const char kExpectedRequestMessageFormat[] =
"{\"content_id\":\"%s\",\"drm_types\":[\"WIDEVINE\"],\"policy\":\"%s\"," "{\"content_id\":\"%s\",\"drm_types\":[\"WIDEVINE\"],\"policy\":\"%s\","
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}"; "\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
const char kExpectedRequestMessageWithAssetIdFormat[] =
"{\"asset_id\":%u,\"drm_types\":[\"WIDEVINE\"],"
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
const char kExpectedRequestMessageWithPsshFormat[] =
"{\"drm_types\":[\"WIDEVINE\"],\"pssh_data\":\"%s\","
"\"tracks\":[{\"type\":\"SD\"},{\"type\":\"HD\"},{\"type\":\"AUDIO\"}]}";
const char kExpectedSignedMessageFormat[] = const char kExpectedSignedMessageFormat[] =
"{\"request\":\"%s\",\"signature\":\"%s\",\"signer\":\"%s\"}"; "{\"request\":\"%s\",\"signature\":\"%s\",\"signer\":\"%s\"}";
const char kTrackFormat[] = const char kTrackFormat[] =
@ -52,7 +58,9 @@ const char kClassicTrackFormat[] = "{\"type\":\"%s\",\"key\":\"%s\"}";
const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}"; const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}";
const char kHttpResponseFormat[] = "{\"response\":\"%s\"}"; const char kHttpResponseFormat[] = "{\"response\":\"%s\"}";
const char kRequestPsshData[] = "PSSH data"; const char kRequestPsshData[] = "PSSH data";
const uint32_t kClassicAssetId = 1234; // 32-bit with leading bit set, to verify that big uint32_t can be handled
// correctly.
const uint32_t kClassicAssetId = 0x80038cd9;
std::string Base64Encode(const std::string& input) { std::string Base64Encode(const std::string& input) {
std::string output; std::string output;
@ -212,7 +220,8 @@ TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
TEST_F(WidevineKeySourceTest, HttpFetchFailure) { TEST_F(WidevineKeySourceTest, HttpFetchFailure) {
std::string expected_message = base::StringPrintf( std::string expected_message = base::StringPrintf(
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy); kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy);
EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _)) EXPECT_CALL(*mock_request_signer_,
GenerateSignature(StrEq(expected_message), _))
.WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true))); .WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true)));
std::string expected_post_data = std::string expected_post_data =
@ -258,29 +267,43 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) {
} }
TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) { TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) {
std::string expected_message =
base::StringPrintf(kExpectedRequestMessageWithPsshFormat,
Base64Encode(kRequestPsshData).c_str());
EXPECT_CALL(*mock_request_signer_,
GenerateSignature(StrEq(expected_message), _))
.WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true)));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str()); kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource();
widevine_key_source_->set_signer(mock_request_signer_.Pass());
std::vector<uint8_t> pssh_data( std::vector<uint8_t> pssh_data(
reinterpret_cast<const uint8_t*>(kRequestPsshData), reinterpret_cast<const uint8_t*>(kRequestPsshData),
reinterpret_cast<const uint8_t*>(kRequestPsshData) + strlen(kContentId)); reinterpret_cast<const uint8_t*>(kRequestPsshData) +
strlen(kRequestPsshData));
ASSERT_OK(widevine_key_source_->FetchKeys(pssh_data)); ASSERT_OK(widevine_key_source_->FetchKeys(pssh_data));
VerifyKeys(false); VerifyKeys(false);
} }
TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) { TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) {
std::string expected_message = base::StringPrintf(
kExpectedRequestMessageWithAssetIdFormat, kClassicAssetId);
EXPECT_CALL(*mock_request_signer_,
GenerateSignature(StrEq(expected_message), _))
.WillOnce(DoAll(SetArgPointee<1>(kMockSignature), Return(true)));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
kHttpResponseFormat, Base64Encode( kHttpResponseFormat, Base64Encode(
GenerateMockClassicLicenseResponse()).c_str()); GenerateMockClassicLicenseResponse()).c_str());
EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _)) EXPECT_CALL(*mock_key_fetcher_, FetchKeys(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineKeySource(); CreateWidevineKeySource();
widevine_key_source_->set_signer(mock_request_signer_.Pass());
ASSERT_OK(widevine_key_source_->FetchKeys(kClassicAssetId)); ASSERT_OK(widevine_key_source_->FetchKeys(kClassicAssetId));
VerifyKeys(true); VerifyKeys(true);
} }