diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index abe82cd3..481a3dac 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -69,9 +69,10 @@ typedef struct { uint32_t control_bits; } KeyControlBlock; -const size_t kTestKeyIdLength = 12; // pick a length. any length. +const size_t kTestKeyIdMaxLength = 48; // pick a length. any length. typedef struct { - uint8_t key_id[kTestKeyIdLength]; + uint8_t key_id[kTestKeyIdMaxLength]; + size_t key_id_length; uint8_t key_data[wvcdm::MAC_KEY_SIZE]; size_t key_data_length; uint8_t key_iv[wvcdm::KEY_IV_SIZE]; @@ -79,11 +80,12 @@ typedef struct { KeyControlBlock control; } MessageKeyData; +// This structure will be signed to simulate a message from the server. struct MessageData { MessageKeyData keys[kNumKeys]; uint8_t mac_key_iv[wvcdm::KEY_IV_SIZE]; uint8_t mac_keys[2 * wvcdm::MAC_KEY_SIZE]; - uint8_t pst[kTestKeyIdLength]; + uint8_t pst[kTestKeyIdMaxLength]; }; const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. @@ -888,8 +890,7 @@ class Session { KeyControlBlock block; size_t size = sizeof(block); OEMCryptoResult sts = OEMCrypto_QueryKeyControl( - session_id(), license_.keys[i].key_id, - sizeof(license_.keys[i].key_id), + session_id(), license_.keys[i].key_id, license_.keys[i].key_id_length, reinterpret_cast(&block), &size); if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); @@ -932,12 +933,21 @@ class Session { } } + void SetKeyId(int index, const string& key_id) { + MessageKeyData &key = license_.keys[index]; + key.key_id_length = key_id.length(); + ASSERT_LE(key.key_id_length, kTestKeyIdMaxLength); + memcpy(key.key_id, key_id.data(), key.key_id_length); + } + void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce, const std::string& pst = "") { OEMCrypto_GetRandom(license_.mac_key_iv, sizeof(license_.mac_key_iv)); OEMCrypto_GetRandom(license_.mac_keys, sizeof(license_.mac_keys)); for (unsigned int i = 0; i < kNumKeys; i++) { - memset(license_.keys[i].key_id, i, kTestKeyIdLength); + memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength); + license_.keys[i].key_id_length = 12; + memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length); OEMCrypto_GetRandom(license_.keys[i].key_data, sizeof(license_.keys[i].key_data)); license_.keys[i].key_data_length = wvcdm::KEY_SIZE; @@ -967,7 +977,9 @@ class Session { void FillRefreshMessage(size_t key_count, uint32_t control_bits, uint32_t nonce) { for (unsigned int i = 0; i < key_count; i++) { - memset(encrypted_license_.keys[i].key_id, i, kTestKeyIdLength); + encrypted_license_.keys[i].key_id_length = license_.keys[i].key_id_length; + memcpy(encrypted_license_.keys[i].key_id, license_.keys[i].key_id, + encrypted_license_.keys[i].key_id_length); memcpy(encrypted_license_.keys[i].control.verification, "kctl", 4); encrypted_license_.keys[i].control.duration = htonl(kLongDuration); encrypted_license_.keys[i].control.nonce = htonl(nonce); @@ -1041,7 +1053,7 @@ class Session { void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array) { for (unsigned int i = 0; i < kNumKeys; i++) { key_array[i].key_id = data.keys[i].key_id; - key_array[i].key_id_length = kTestKeyIdLength; + key_array[i].key_id_length = data.keys[i].key_id_length; key_array[i].key_data_iv = data.keys[i].key_iv; key_array[i].key_data = data.keys[i].key_data; key_array[i].key_data_length = data.keys[i].key_data_length; @@ -1056,7 +1068,7 @@ class Session { for (size_t i = 0; i < key_count; i++) { if (key_count > 1) { key_array[i].key_id = encrypted_license_.keys[i].key_id; - key_array[i].key_id_length = kTestKeyIdLength; + key_array[i].key_id_length = encrypted_license_.keys[i].key_id_length; } else { key_array[i].key_id = NULL; key_array[i].key_id_length = 0; @@ -1072,8 +1084,8 @@ class Session { OEMCryptoResult sts; if (select_key_first) { // Select the key (from FillSimpleMessage) - vector keyId = wvcdm::a2b_hex("000000000000000000000000"); - sts = OEMCrypto_SelectKey(session_id(), &keyId[0], keyId.size()); + sts = OEMCrypto_SelectKey(session_id(), license_.keys[0].key_id, + license_.keys[0].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); } @@ -2099,9 +2111,9 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange3) { s.GenerateTestSessionKeys(); s.FillSimpleMessage(0, 0, 0); s.EncryptAndSign(); - vector bad_buffer( - s.encrypted_license().keys[0].key_id, - s.encrypted_license().keys[0].key_id + kTestKeyIdLength); + vector bad_buffer(s.encrypted_license().keys[0].key_id, + s.encrypted_license().keys[0].key_id + + s.encrypted_license().keys[0].key_id_length); s.key_array()[0].key_id = &bad_buffer[0]; OEMCryptoResult sts = OEMCrypto_LoadKeys( @@ -2630,8 +2642,8 @@ TEST_F(OEMCryptoSessionTests, DecryptUnencrypted) { s.LoadTestKeys(); // Select the key (from FillSimpleMessage) - vector keyId = wvcdm::a2b_hex("000000000000000000000000"); - sts = OEMCrypto_SelectKey(s.session_id(), &keyId[0], keyId.size()); + sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, + s.license().keys[0].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); // Set up our expected input and output @@ -4177,7 +4189,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { vector expected_encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &expected_encrypted); sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(buffer_length); sts = OEMCrypto_Generic_Encrypt(s.session_id(), &clear_buffer_[0], @@ -4199,7 +4212,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { vector encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); sts = OEMCrypto_Generic_Decrypt(s.session_id(), &encrypted[0], buffer_length, @@ -4220,7 +4234,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { SignBuffer(&s, key_index, clear_buffer_, &expected_signature); sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t signature_length = (size_t)SHA256_DIGEST_LENGTH; vector signature(SHA256_DIGEST_LENGTH); @@ -4247,7 +4262,8 @@ class GenericCryptoTest : public OEMCryptoSessionTests { } sts = OEMCrypto_SelectKey( - s.session_id(), s.license().keys[key_index].key_id, kTestKeyIdLength); + s.session_id(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_Generic_Verify(s.session_id(), &clear_buffer_[0], clear_buffer_.size(), algorithm, @@ -4277,7 +4293,7 @@ TEST_F(GenericCryptoTest, GenericKeyEncrypt) { vector expected_encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &expected_encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(clear_buffer_.size()); sts = OEMCrypto_Generic_Encrypt(s.session_id(), &clear_buffer_[0], @@ -4307,7 +4323,7 @@ TEST_F(GenericCryptoTest, GenericKeyDecrypt) { vector encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); sts = OEMCrypto_Generic_Decrypt(s.session_id(), &encrypted[0], encrypted.size(), @@ -4331,7 +4347,7 @@ TEST_F(GenericCryptoTest, GenericSecureToClear) { vector encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); sts = OEMCrypto_Generic_Decrypt(s.session_id(), &encrypted[0], encrypted.size(), @@ -4362,7 +4378,7 @@ TEST_F(GenericCryptoTest, GenericKeySign) { SignBuffer(&s, key_index, clear_buffer_, &expected_signature); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t gen_signature_length = 0; sts = OEMCrypto_Generic_Sign(s.session_id(), &clear_buffer_[0], @@ -4398,7 +4414,7 @@ TEST_F(GenericCryptoTest, GenericKeyVerify) { SignBuffer(&s, key_index, clear_buffer_, &signature); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_Generic_Verify(s.session_id(), &clear_buffer_[0], clear_buffer_.size(), OEMCrypto_HMAC_SHA256, @@ -4433,7 +4449,7 @@ TEST_F(GenericCryptoTest, KeyDurationEncrypt) { sleep(kShortSleep); // Should still be valid key. sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_Generic_Encrypt(s.session_id(), &clear_buffer_[0], @@ -4466,7 +4482,7 @@ TEST_F(GenericCryptoTest, KeyDurationDecrypt) { vector encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sleep(kShortSleep); // Should still be valid key. @@ -4506,7 +4522,7 @@ TEST_F(GenericCryptoTest, KeyDurationSign) { SignBuffer(&s, key_index, clear_buffer_, &expected_signature); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sleep(kShortSleep); // Should still be valid key. @@ -4541,7 +4557,7 @@ TEST_F(GenericCryptoTest, KeyDurationVerify) { SignBuffer(&s, key_index, clear_buffer_, &signature); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sleep(kShortSleep); // Should still be valid key. @@ -4559,6 +4575,109 @@ TEST_F(GenericCryptoTest, KeyDurationVerify) { ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, sts); } +TEST_F(GenericCryptoTest, ShortKeyId) { + OEMCryptoResult sts; + Session s; + s.open(); + s.GenerateTestSessionKeys(); + MakeFourKeys(&s); + // We are testing that the key ids do not have to have the same length. + s.SetKeyId(0, "123456789012"); // 12 bytes. + s.SetKeyId(1, "12345"); // short key id. + s.SetKeyId(2, "123456789012-very-long-key-id"); + s.EncryptAndSign(); + s.LoadTestKeys(); + unsigned int key_index = 1; + vector encrypted; + + // To make sure OEMCrypto is not expecting the key_id to be zero padded, we + // will create a buffer that is padded with 'Z'. + vector key_id_buffer(s.license().keys[key_index].key_id_length + 5, + 'Z'); // Fill a bigger buffer with letter 'Z'. + memcpy(key_id_buffer.data(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length); + EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); + sts = OEMCrypto_SelectKey(s.session_id(), key_id_buffer.data(), + s.license().keys[key_index].key_id_length); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector resultant(encrypted.size()); + sts = OEMCrypto_Generic_Decrypt(s.session_id(), &encrypted[0], encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + &resultant[0]); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(clear_buffer_, resultant); +} + +TEST_F(GenericCryptoTest, LongKeyId) { + OEMCryptoResult sts; + Session s; + s.open(); + s.GenerateTestSessionKeys(); + MakeFourKeys(&s); + // We are testing that the key ids do not have to have the same length. + s.SetKeyId(0, "123456789012"); // 12 bytes. + s.SetKeyId(1, "123456789012-very-long-key-id"); // long key id. + s.SetKeyId(2, "12345"); + s.EncryptAndSign(); + s.LoadTestKeys(); + unsigned int key_index = 1; + vector encrypted; + + // To make sure OEMCrypto is not expecting the key_id to be zero padded, we + // will create a buffer that is padded with 'Z'. + vector key_id_buffer(s.license().keys[key_index].key_id_length + 5, + 'Z'); // Fill a bigger buffer with letter 'Z'. + memcpy(key_id_buffer.data(), s.license().keys[key_index].key_id, + s.license().keys[key_index].key_id_length); + EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); + sts = OEMCrypto_SelectKey(s.session_id(), key_id_buffer.data(), + s.license().keys[key_index].key_id_length); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector resultant(encrypted.size()); + sts = OEMCrypto_Generic_Decrypt(s.session_id(), &encrypted[0], encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + &resultant[0]); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(clear_buffer_, resultant); +} + +TEST_F(GenericCryptoTest, CommonPrefixKeyId) { + OEMCryptoResult sts; + Session s; + s.open(); + s.GenerateTestSessionKeys(); + MakeFourKeys(&s); + // We are testing that the key ids do not have to have the same length. + // Worse, they may have a common prefix. + // This test is more diabolical. We put the long key id in the buffer, but + // the length is for the shorter key. If OEMCrypto is paying attention to the + // key id length, it should see key 1. If it looks beyond the whole buffer, + // it will see key 0. + s.SetKeyId(0, "123456789012"); // 12 bytes. + s.SetKeyId(1, "12345"); // short key id, with common prefix with key 0. + s.SetKeyId(2, "123456789012-very-long-key-id"); + s.EncryptAndSign(); + s.LoadTestKeys(); + unsigned int key_index = 1; + unsigned int other_key_index = 0; // Key with shared prefix. + vector encrypted; + + EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); + // Note: we pass in a buffer pointer to key id 0, because it starts off the + // same as key id 1. Since the length is for key id 1, oemcrypto should + // select key 1. + sts = OEMCrypto_SelectKey(s.session_id(), + s.license().keys[other_key_index].key_id, + s.license().keys[key_index].key_id_length); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + vector resultant(encrypted.size()); + sts = OEMCrypto_Generic_Decrypt(s.session_id(), &encrypted[0], encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, + &resultant[0]); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_EQ(clear_buffer_, resultant); +} + TEST_F(OEMCryptoClientTest, UpdateUsageTableTest) { EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); } @@ -5076,7 +5195,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoEncrypt) { vector expected_encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &expected_encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(clear_buffer_.size()); sts = OEMCrypto_Generic_Encrypt(s.session_id(), &clear_buffer_[0], @@ -5122,7 +5241,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoDecrypt) { vector encrypted; EncryptBuffer(&s, key_index, clear_buffer_, &encrypted); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); sts = OEMCrypto_Generic_Decrypt(s.session_id(), &encrypted[0], @@ -5170,7 +5289,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoSign) { SignBuffer(&s, key_index, clear_buffer_, &expected_signature); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t gen_signature_length = 0; sts = OEMCrypto_Generic_Sign(s.session_id(), &clear_buffer_[0], @@ -5227,7 +5346,7 @@ TEST_P(UsageTableTestWithMAC, GenericCryptoVerify) { SignBuffer(&s, key_index, clear_buffer_, &signature); sts = OEMCrypto_SelectKey(s.session_id(), s.license().keys[key_index].key_id, - kTestKeyIdLength); + s.license().keys[key_index].key_id_length); ASSERT_EQ(OEMCrypto_SUCCESS, sts); sts = OEMCrypto_Generic_Verify(s.session_id(), &clear_buffer_[0], clear_buffer_.size(), OEMCrypto_HMAC_SHA256,