diff --git a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp index e84b5d02..84444760 100644 --- a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp @@ -71,7 +71,9 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, OEMCrypto_CloseSession(session); api_version = OEMCrypto_APIVersion(); printf("api_version = %d.\n", api_version); - usage_table = OEMCrypto_SupportsUsageTable(); + // These unit tests only work with new usage tables. We do not test v12 + // usage tables. + if (api_version > 12) usage_table = OEMCrypto_SupportsUsageTable(); printf("usage_table = %s.\n", usage_table ? "true" : "false"); if (force_load_test_keybox) { derive_key_method = FORCE_TEST_KEYBOX; @@ -131,6 +133,7 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { if (provisioning_method != OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*"); if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*"); + if (api_version < 9) FilterOut(&filter, "*API09*"); if (api_version < 10) FilterOut(&filter, "*API10*"); if (api_version < 11) FilterOut(&filter, "*API11*"); if (api_version < 12) FilterOut(&filter, "*API12*"); diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp index f806ddb8..074dbb8c 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -534,22 +534,43 @@ void Session::TestDecryptCTR(bool select_key_first, if (expected_result == OEMCrypto_SUCCESS) { // No error. ASSERT_EQ(OEMCrypto_SUCCESS, sts); ASSERT_EQ(unencryptedData, outputBuffer); - } else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED) { - // Report stale keys. - ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, sts); + } else { + ASSERT_NO_FATAL_FAILURE(TestDecryptResult(expected_result, sts)); ASSERT_NE(unencryptedData, outputBuffer); + } +} + +void Session::TestDecryptResult(OEMCryptoResult expected_result, + OEMCryptoResult actual_result) { + + if (expected_result == OEMCrypto_SUCCESS) { // No error. + ASSERT_EQ(OEMCrypto_SUCCESS, actual_result); + } else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED && + global_features.api_version >= 9) { + // Report stale keys, required in v9 and beyond. + ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, actual_result); } else if (expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP) { // Report HDCP errors. - ASSERT_EQ(OEMCrypto_ERROR_INSUFFICIENT_HDCP, sts); - ASSERT_NE(unencryptedData, outputBuffer); + ASSERT_EQ(OEMCrypto_ERROR_INSUFFICIENT_HDCP, actual_result); } else if (expected_result == OEMCrypto_ERROR_ANALOG_OUTPUT) { // Report analog errors. - ASSERT_EQ(OEMCrypto_ERROR_ANALOG_OUTPUT, sts); - ASSERT_NE(unencryptedData, outputBuffer); + ASSERT_EQ(OEMCrypto_ERROR_ANALOG_OUTPUT, actual_result); } else { // OEM's can fine tune other error codes for debugging. - ASSERT_NE(OEMCrypto_SUCCESS, sts); - ASSERT_NE(unencryptedData, outputBuffer); + ASSERT_NE(OEMCrypto_SUCCESS, actual_result); + } +} + +void Session::TestSelectExpired(unsigned int key_index) { + if (global_features.api_version >= 13) { + OEMCryptoResult status = + OEMCrypto_SelectKey(session_id(), license().keys[key_index].key_id, + license().keys[key_index].key_id_length); + // It is OK for SelectKey to succeed with an expired key, but if there is + // an error, it must be OEMCrypto_ERROR_KEY_EXIRED. + if (status != OEMCrypto_SUCCESS) { + ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); + } } } @@ -985,7 +1006,10 @@ void Session::CopyAndVerifyOldEntry(const Test_PST_Report& report, OEMCryptoResult result = OEMCrypto_CopyOldUsageEntry( session_id(), reinterpret_cast(report.pst.c_str()), report.pst.length()); - if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) return; + if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) { + cout << "WARNING: OEMCrypto CANNOT copy old usage table to new." << endl; + return; + } ASSERT_NO_FATAL_FAILURE(UpdateUsageEntry(header_buffer)); ASSERT_NO_FATAL_FAILURE(GenerateReport(report.pst)); ASSERT_NO_FATAL_FAILURE(VerifyPST(report)); diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h index 926f21dd..8bfc4e36 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.h +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -203,6 +203,13 @@ class Session { void TestDecryptCTR(bool select_key_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS, int key_index = 0); + // This compares the actual result with the expected result. If OEMCrypto is + // an older version, we allow it to report an equivalent error code. + void TestDecryptResult(OEMCryptoResult expected_result, + OEMCryptoResult actual_result); + // Verify that an attempt to select an expired key either succeeds, or gives + // an actionable error code. + void TestSelectExpired(unsigned int key_index); // Calls OEMCrypto_GetOEMPublicCertificate and loads the OEM cert's public // rsa key into public_rsa_. void LoadOEMCert(bool verify_cert = false); diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index 42eb0bb5..391318a3 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -136,7 +136,7 @@ const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { } } -TEST_F(OEMCryptoClientTest, CheckHDCPCapability) { +TEST_F(OEMCryptoClientTest, CheckHDCPCapabilityAPI09) { OEMCryptoResult sts; OEMCrypto_HDCP_Capability current, maximum; sts = OEMCrypto_GetHDCPCapability(¤t, &maximum); @@ -299,7 +299,7 @@ TEST_F(OEMCryptoClientTest, GenerateTwoNonces) { ASSERT_TRUE(nonce1 != nonce2); // Very unlikely to be equal. } -TEST_F(OEMCryptoClientTest, PreventNonceFlood) { +TEST_F(OEMCryptoClientTest, PreventNonceFloodAPI09) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); int error_counter = 0; @@ -324,7 +324,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood) { } // Prevent a nonce flood even if each nonce is in a different session. -TEST_F(OEMCryptoClientTest, PreventNonceFlood2) { +TEST_F(OEMCryptoClientTest, PreventNonceFlood2API09) { int error_counter = 0; time_t test_start = time(NULL); // More than 20 nonces per second should generate an error. @@ -354,7 +354,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2) { // is different from the test above because there are several session open at // the same time. We want to make sure you can't get a flood of nonces by // opening a flood of sessions. -TEST_F(OEMCryptoClientTest, PreventNonceFlood3) { +TEST_F(OEMCryptoClientTest, PreventNonceFlood3API09) { int request_counter = 0; int error_counter = 0; time_t test_start = time(NULL); @@ -416,7 +416,7 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) { OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); } -TEST_F(OEMCryptoClientTest, ClearCopyTestLargeBuffer) { +TEST_F(OEMCryptoClientTest, ClearCopyTestLargeBufferAPI10) { vector input_buffer(kMaxDecryptSize); RAND_pseudo_bytes(&input_buffer[0], input_buffer.size()); vector output_buffer(kMaxDecryptSize); @@ -1378,7 +1378,7 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { } } -TEST_F(OEMCryptoSessionTests, Minimum20Keys) { +TEST_F(OEMCryptoSessionTests, Minimum20KeysAPI12) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); @@ -1421,7 +1421,7 @@ class SessionTestDecryptWithHDCP : public OEMCryptoSessionTests, } }; -TEST_P(SessionTestDecryptWithHDCP, Decrypt) { +TEST_P(SessionTestDecryptWithHDCP, DecryptAPI09) { // Test parameterized by HDCP version. DecryptWithHDCP(static_cast(GetParam())); } @@ -1475,7 +1475,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshNoNonce) { s.RefreshTestKeys(num_keys_, 0, 0, OEMCrypto_SUCCESS)); } -TEST_P(SessionTestRefreshKeyTest, RefreshOldNonce) { +TEST_P(SessionTestRefreshKeyTest, RefreshOldNonceAPI11) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); @@ -1492,7 +1492,7 @@ TEST_P(SessionTestRefreshKeyTest, RefreshOldNonce) { OEMCrypto_ERROR_INVALID_NONCE)); } -TEST_P(SessionTestRefreshKeyTest, RefreshBadNonce) { +TEST_P(SessionTestRefreshKeyTest, RefreshBadNonceAPI11) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); @@ -2068,8 +2068,10 @@ INSTANTIATE_TEST_CASE_P(CTRTests, OEMCryptoSessionTestsPartialBlockTests, Combine(Values(MakePattern(0,0)), Values(OEMCrypto_CipherMode_CTR), Bool())); + +// Decrypt in place for CBC tests was only required in v13. INSTANTIATE_TEST_CASE_P( - CBCTests, OEMCryptoSessionTestsPartialBlockTests, + CBCTestsAPI13, OEMCryptoSessionTestsPartialBlockTests, Combine( Values(MakePattern(0, 0), MakePattern(3, 7), @@ -2079,8 +2081,9 @@ INSTANTIATE_TEST_CASE_P( MakePattern(1, 3), MakePattern(2, 1)), Values(OEMCrypto_CipherMode_CBC), Bool())); + INSTANTIATE_TEST_CASE_P( - CTRTests, OEMCryptoSessionTestsDecryptTests, + CTRTestsAPI11, OEMCryptoSessionTestsDecryptTests, Combine( Values(MakePattern(0, 0), MakePattern(3, 7), @@ -2088,8 +2091,10 @@ INSTANTIATE_TEST_CASE_P( MakePattern(1, 3), MakePattern(2, 1)), Values(OEMCrypto_CipherMode_CTR), Bool())); + +// Decrypt in place for CBC tests was only required in v13. INSTANTIATE_TEST_CASE_P( - CBCTests, OEMCryptoSessionTestsDecryptTests, + CBCTestsAPI13, OEMCryptoSessionTestsDecryptTests, Combine( Values(MakePattern(0, 0), MakePattern(3, 7), @@ -2115,7 +2120,7 @@ TEST_F(OEMCryptoSessionTests, DecryptSecureToClear) { s.TestDecryptCTR(true, OEMCrypto_ERROR_UNKNOWN_FAILURE)); } -TEST_F(OEMCryptoSessionTests, DecryptNoAnalogToClear) { +TEST_F(OEMCryptoSessionTests, DecryptNoAnalogToClearAPI13) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); @@ -2140,9 +2145,7 @@ TEST_F(OEMCryptoSessionTests, KeyDuration) { ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR(false, OEMCrypto_SUCCESS)); sleep(kLongSleep); // Should be expired key. ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR(false, OEMCrypto_ERROR_KEY_EXPIRED)); - ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_SelectKey(s.session_id(), s.license().keys[0].key_id, - s.license().keys[0].key_id_length)); + ASSERT_NO_FATAL_FAILURE(s.TestSelectExpired(0)); } // @@ -2796,7 +2799,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { // The alternate padding is only required for cast receivers, but all devices // should forbid the alternate padding for regular certificates. -TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPadding) { +TEST_F(OEMCryptoLoadsCertificateAlternates, DisallowForbiddenPaddingAPI09) { LoadWithAllowedSchemes(kSign_RSASSA_PSS, true); // Use default padding scheme DisallowForbiddenPadding(kSign_PKCS1_Block1, 50); } @@ -4189,16 +4192,13 @@ TEST_F(GenericCryptoTest, KeyDurationEncrypt) { sleep(kLongSleep); // Should be expired key. encrypted.assign(clear_buffer_.size(), 0); - ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_Generic_Encrypt( - session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, &encrypted[0])); + OEMCryptoResult status = OEMCrypto_Generic_Encrypt( + session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, &encrypted[0]); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status)); ASSERT_NE(encrypted, expected_encrypted); - ASSERT_EQ( - OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); } TEST_F(GenericCryptoTest, KeyDurationDecrypt) { @@ -4225,16 +4225,13 @@ TEST_F(GenericCryptoTest, KeyDurationDecrypt) { sleep(kLongSleep); // Should be expired key. resultant.assign(encrypted.size(), 0); - ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_Generic_Decrypt( - session_.session_id(), &encrypted[0], encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, &resultant[0])); + OEMCryptoResult status = OEMCrypto_Generic_Decrypt( + session_.session_id(), &encrypted[0], encrypted.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, &resultant[0]); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status)); ASSERT_NE(clear_buffer_, resultant); - ASSERT_EQ( - OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); } TEST_F(GenericCryptoTest, KeyDurationSign) { @@ -4263,16 +4260,13 @@ TEST_F(GenericCryptoTest, KeyDurationSign) { sleep(kLongSleep); // Should be expired key. signature.assign(SHA256_DIGEST_LENGTH, 0); - ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_Generic_Sign(session_.session_id(), &clear_buffer_[0], - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - &signature[0], &signature_length)); + OEMCryptoResult status = OEMCrypto_Generic_Sign( + session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, &signature[0], &signature_length); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status)); ASSERT_NE(expected_signature, signature); - ASSERT_EQ( - OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); } TEST_F(GenericCryptoTest, KeyDurationVerify) { @@ -4297,15 +4291,12 @@ TEST_F(GenericCryptoTest, KeyDurationVerify) { sleep(kLongSleep); // Should be expired key. - ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_Generic_Verify( - session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), - OEMCrypto_HMAC_SHA256, &signature[0], signature.size())); - ASSERT_EQ( - OEMCrypto_ERROR_KEY_EXPIRED, - OEMCrypto_SelectKey(session_.session_id(), - session_.license().keys[key_index].key_id, - session_.license().keys[key_index].key_id_length)); + OEMCryptoResult status = OEMCrypto_Generic_Verify( + session_.session_id(), &clear_buffer_[0], clear_buffer_.size(), + OEMCrypto_HMAC_SHA256, &signature[0], signature.size()); + ASSERT_NO_FATAL_FAILURE( + session_.TestDecryptResult(OEMCrypto_ERROR_KEY_EXPIRED, status)); + ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); } const unsigned int kLongKeyId = 2; @@ -5334,7 +5325,7 @@ TEST_F(UsageTableTest, CopyOldEntries) { s3.CopyAndVerifyOldEntry(report3, &encrypted_usage_header_)); } -TEST_F(UsageTableTest, ReloadUsageTableWIthSkew) { +TEST_F(UsageTableTest, ReloadUsageTableWithSkew) { // This also tests a few other error conditions with usage table headers. std::string pst = "my_pst"; Session s;