diff --git a/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h b/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h index 944cb66d..cbff211d 100644 --- a/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h +++ b/libwvdrmengine/cdm/core/include/oemcrypto_adapter.h @@ -35,6 +35,8 @@ OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(SecurityLevel level, OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(SecurityLevel level, size_t* maximum); uint8_t OEMCrypto_Security_Patch_Level(SecurityLevel level); +OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod( + SecurityLevel level); } // namespace wvcdm #endif // WVCDM_CORE_OEMCRYPTO_ADAPTER_H_ diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 06c716a8..12ec36be 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -188,6 +188,21 @@ typedef OEMCryptoResult (*L1_DeleteUsageEntry_t)( typedef OEMCryptoResult (*L1_ForceDeleteUsageEntry_t)(const uint8_t* pst, size_t pst_length); typedef OEMCryptoResult (*L1_DeleteUsageTable_t)(); +typedef OEMCrypto_ProvisioningMethod (*L1_GetProvisioningMethod_t)(); +typedef OEMCryptoResult (*L1_GetOEMPublicCertificate_t)( + OEMCrypto_SESSION session, + uint8_t *public_cert, + size_t *public_cert_length); +typedef OEMCryptoResult (*L1_RewrapDeviceRSAKey30_t)( + OEMCrypto_SESSION session, + const uint32_t *nonce, + const uint8_t* encrypted_message_key, + size_t encrypted_message_key_length, + const uint8_t* enc_rsa_key, + size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, + uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length); struct FunctionPointers { uint32_t version; @@ -235,6 +250,9 @@ struct FunctionPointers { L1_DeleteUsageEntry_t DeleteUsageEntry; L1_ForceDeleteUsageEntry_t ForceDeleteUsageEntry; L1_DeleteUsageTable_t DeleteUsageTable; + L1_GetProvisioningMethod_t GetProvisioningMethod; + L1_GetOEMPublicCertificate_t GetOEMPublicCertificate; + L1_RewrapDeviceRSAKey30_t RewrapDeviceRSAKey30; L1_LoadKeys_V8_t LoadKeys_V8; L1_GenerateRSASignature_V8_t GenerateRSASignature_V8; @@ -245,7 +263,7 @@ struct FunctionPointers { // The Cache Flush function is very processor dependent, but is needed by the // haystack code. The haystack code is delivered as a static prebuilt library. // For that reason, we pass a function pointer for cache_flush into the -// haystack. The function is combiled outside of the haystack and may use +// haystack. The function is compiled outside of the haystack and may use // target (processor) specific compiler flags. void clear_cache_function(void *page, size_t len) { @@ -309,7 +327,7 @@ struct LevelSession { level1_.Name = (L1_##Name##_t)dlsym(level1_library_, QUOTE(Function)); \ if (!level1_.Name) { \ LOGW("Could not load L1 %s. Falling Back to L3.", \ - QUOTE(OEMCrypto_##Name)); \ + QUOTE(Function)); \ return false; \ } @@ -331,7 +349,14 @@ class Adapter { OEMCryptoResult Initialize() { LoadLevel3(); + std::string base_path; + wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3, + &base_path); + bool is_in_app = Level3_IsInApp(base_path.c_str()); OEMCryptoResult result = Level3_Initialize(clear_cache_function); + if (is_in_app) { + return result; + } if (force_level3()) { LOGW("Test code. User requested falling back to L3"); return result; @@ -350,6 +375,7 @@ class Adapter { if (LoadLevel1()) { LOGD("OEMCrypto_Initialize Level 1 success. I will use level 1."); } else { + level1_ = FunctionPointers(); // revert to all null pointers. dlclose(level1_library_); level1_library_ = NULL; level1_valid_ = false; @@ -402,7 +428,7 @@ class Adapter { if (level1_.version == 8) { LOOKUP(LoadKeys_V8, OEMCrypto_LoadKeys_V8); LOOKUP(GenerateRSASignature_V8, OEMCrypto_GenerateRSASignature_V8); - } else { + } else { // version >= 9 LOOKUP(GenerateRSASignature, OEMCrypto_GenerateRSASignature); LOOKUP(SupportsUsageTable, OEMCrypto_SupportsUsageTable); LOOKUP(UpdateUsageTable, OEMCrypto_UpdateUsageTable); @@ -413,7 +439,7 @@ class Adapter { if (level1_.version == 9) { LOOKUP(LoadKeys_V9_or_V10, OEMCrypto_LoadKeys_V9_or_V10); LOOKUP(GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9); - } else { + } else { // version >= 10. LOOKUP(LoadTestKeybox, OEMCrypto_LoadTestKeybox); LOOKUP(LoadTestRSAKey, OEMCrypto_LoadTestRSAKey); LOOKUP(QueryKeyControl, OEMCrypto_QueryKeyControl); @@ -426,16 +452,29 @@ class Adapter { if (level1_.version == 10) { LOOKUP(LoadKeys_V9_or_V10, OEMCrypto_LoadKeys_V9_or_V10); LOOKUP(DecryptCTR_V10, OEMCrypto_DecryptCTR_V10); - } else { // version 11. + } else { // version >= 11. LOOKUP(LoadKeys, OEMCrypto_LoadKeys); LOOKUP(DecryptCENC, OEMCrypto_DecryptCENC); LOOKUP(SecurityPatchLevel, OEMCrypto_Security_Patch_Level); + if (level1_.version >= 12) { + LOOKUP(GetProvisioningMethod, OEMCrypto_GetProvisioningMethod); + LOOKUP(GetOEMPublicCertificate, OEMCrypto_GetOEMPublicCertificate); + LOOKUP(RewrapDeviceRSAKey30, OEMCrypto_RewrapDeviceRSAKey30); + } } } } + // If we have a valid keybox, initialization is done. We're good. if (OEMCrypto_SUCCESS == level1_.IsKeyboxValid()) { return true; } + // If we use provisioning 3.0, initialization is done. We may not + // be good, but there's no reason to try loading a keybox. Any errors + // will have to be caught in the future when provisioning fails. + if (level1_.version > 11 && + (level1_.GetProvisioningMethod() == OEMCrypto_OEMCertificate)) { + return true; + } uint8_t buffer[1]; size_t buffer_size = 0; if (OEMCrypto_ERROR_NOT_IMPLEMENTED == level1_.GetKeyData(buffer, @@ -522,6 +561,9 @@ class Adapter { level3_.DeleteUsageEntry = Level3_DeleteUsageEntry; level3_.ForceDeleteUsageEntry = Level3_ForceDeleteUsageEntry; level3_.DeleteUsageTable = Level3_DeleteUsageTable; + level3_.GetProvisioningMethod = Level3_GetProvisioningMethod; + level3_.GetOEMPublicCertificate = Level3_GetOEMPublicCertificate; + level3_.RewrapDeviceRSAKey30 = Level3_RewrapDeviceRSAKey30; level3_.version = Level3_APIVersion(); } @@ -658,6 +700,17 @@ OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, return fcn->InstallKeybox(keybox, keyBoxLength); } +OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod( + SecurityLevel level) { + oemprofiler::ProfiledScope ps( + oemprofiler::OEM_FUNCTION_GET_PROVISIONING_METHOD); + if (!kAdapter) return OEMCrypto_ProvisioningError; + const FunctionPointers* fcn = kAdapter->get(level); + if (!fcn) return OEMCrypto_ProvisioningError; + if (fcn->version < 12) return OEMCrypto_Keybox; + return fcn->GetProvisioningMethod(); +} + OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) { oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_IS_KEYBOX_VALID); @@ -1024,6 +1077,24 @@ extern "C" OEMCryptoResult OEMCrypto_IsKeyboxValid() { return OEMCrypto_IsKeyboxValid(kLevelDefault); } +extern "C" OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod() { + return OEMCrypto_GetProvisioningMethod(kLevelDefault); +} + +extern "C" OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( + OEMCrypto_SESSION session, + uint8_t *public_cert, + size_t *public_cert_length) { + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_GET_OEM_PUBLIC_CERTIFICATE); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + LevelSession pair = kAdapter->get(session); + if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; + if (pair.fcn->version < 12) return OEMCrypto_ERROR_NOT_IMPLEMENTED; + return pair.fcn->GetOEMPublicCertificate(pair.session, public_cert, + public_cert_length); +} + extern "C" OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength) { return OEMCrypto_GetDeviceID(deviceID, idLength, kLevelDefault); @@ -1046,6 +1117,30 @@ extern "C" OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, return fcn->GetRandom(randomData, dataLength); } +extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( + OEMCrypto_SESSION session, + const uint32_t *nonce, + const uint8_t* encrypted_message_key, + size_t encrypted_message_key_length, + const uint8_t* enc_rsa_key, + size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, + uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length) { + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_REWRAP_DEVICE_RSA_KEY_30); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + LevelSession pair = kAdapter->get(session); + if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; + if (pair.fcn->version < 12) return OEMCrypto_ERROR_NOT_IMPLEMENTED; + return pair.fcn->RewrapDeviceRSAKey30(session, nonce, encrypted_message_key, + encrypted_message_key_length, + enc_rsa_key, enc_rsa_key_length, + enc_rsa_key_iv, wrapped_rsa_key, + wrapped_rsa_key_length); +} + + extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, const uint32_t* nonce, diff --git a/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp b/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp index 571a2af4..ebf54879 100644 --- a/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp @@ -33,6 +33,7 @@ class WvGenericOperationsTest : public testing::Test { virtual void SetUp() { ::testing::Test::SetUp(); + // TODO(fredgc or gmorgan): This should be updated for provisioning 3.0 // Load test keybox. This keybox will be used by any CryptoSession // created by the CDM under test. ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox()); @@ -72,7 +73,8 @@ class WvGenericOperationsTest : public testing::Test { void OecSessionSetup(uint32_t oec_session_id) { buffer_size_ = 160; oec_util_session_.SetSessionId(oec_session_id); - oec_util_session_.GenerateTestSessionKeys(); + // TODO(fredgc or gmorgan): This should be updated for provisioning 3.0 + oec_util_session_.GenerateDerivedKeysFromKeybox(); MakeFourKeys(); } @@ -202,7 +204,8 @@ TEST_F(WvGenericOperationsTest, NormalSessionOpenClose) { TEST_F(WvGenericOperationsTest, GenerateSessionKeys) { wvoec::Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + // TODO(fredgc or gmorgan): This should be updated for provisioning 3.0 + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); ASSERT_NO_FATAL_FAILURE(s.close()); } diff --git a/libwvdrmengine/cdm/profiler/include/oem_functions.h b/libwvdrmengine/cdm/profiler/include/oem_functions.h index 18f6fb7b..f071c296 100644 --- a/libwvdrmengine/cdm/profiler/include/oem_functions.h +++ b/libwvdrmengine/cdm/profiler/include/oem_functions.h @@ -48,6 +48,9 @@ enum OEM_FUNCTION { OEM_FUNCTION_DELETE_USAGE_ENTRY, OEM_FUNCTION_FORCE_DELETE_USAGE_ENTRY, OEM_FUNCTION_DELETE_USAGE_TABLE, + OEM_FUNCTION_GET_PROVISIONING_METHOD, + OEM_FUNCTION_GET_OEM_PUBLIC_CERTIFICATE, + OEM_FUNCTION_REWRAP_DEVICE_RSA_KEY_30, OEM_FUNCTION_TESTING, // dummy value for testing purposes OEM_FUNCTION_COUNT diff --git a/libwvdrmengine/level3/arm/libwvlevel3.a b/libwvdrmengine/level3/arm/libwvlevel3.a index 5cd58c0e..caffe61f 100644 Binary files a/libwvdrmengine/level3/arm/libwvlevel3.a and b/libwvdrmengine/level3/arm/libwvlevel3.a differ diff --git a/libwvdrmengine/level3/mips/libwvlevel3.a b/libwvdrmengine/level3/mips/libwvlevel3.a index c7e977d5..f57b94d1 100644 Binary files a/libwvdrmengine/level3/mips/libwvlevel3.a and b/libwvdrmengine/level3/mips/libwvlevel3.a differ diff --git a/libwvdrmengine/level3/x86/libwvlevel3.a b/libwvdrmengine/level3/x86/libwvlevel3.a index d16ca564..ddbeec1f 100644 Binary files a/libwvdrmengine/level3/x86/libwvlevel3.a and b/libwvdrmengine/level3/x86/libwvlevel3.a differ diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index 48acd4d5..6c224320 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -87,7 +87,9 @@ typedef enum OEMCryptoResult { * 2. Place the decrypted data into protected memory (SecureBuffer). The * caller uses a platform-specific method to acquire the protected buffer * and a user-memory handle that references it. The handle is supplied - * to the decrypt call in the descriptor. + * to the decrypt call in the descriptor. If the buffer is filled with + * several OEMCrypto calls, the same handle will be used, and the offset + * will be incremented to indicate where the next write should take place. * 3. Place the decrypted data directly into the audio or video decoder fifo * (Direct). The caller will use platform-specific methods to initialize * the fifo and the decoders. The decrypted stream data is not accessible @@ -101,6 +103,7 @@ typedef enum OEMCryptoResult { * (type == OEMCrypto_BufferType_Secure) * buffer - handle to a platform-specific secure buffer. * max_length - Size of platform-specific secure buffer. + * offset - offset from beginning of buffer to which OEMCrypto should write. * (type == OEMCrypto_BufferType_Direct) * is_video - If true, decrypted bytes are routed to the video * decoder. If false, decrypted bytes are routed to the diff --git a/libwvdrmengine/oemcrypto/include/level3.h b/libwvdrmengine/oemcrypto/include/level3.h index 79e96907..e3509ac4 100644 --- a/libwvdrmengine/oemcrypto/include/level3.h +++ b/libwvdrmengine/oemcrypto/include/level3.h @@ -16,7 +16,7 @@ namespace wvoec3 { -#define Level3_PreInitialize _lcc00 +#define Level3_IsInApp _lcc00 #define Level3_Initialize _lcc01 #define Level3_Terminate _lcc02 #define Level3_InstallKeybox _lcc03 @@ -60,10 +60,13 @@ namespace wvoec3 { #define Level3_ForceDeleteUsageEntry _lcc43 #define Level3_LoadTestRSAKey _lcc45 #define Level3_SecurityPatchLevel _lcc46 +#define Level3_GetProvisioningMethod _lcc49 +#define Level3_GetOEMPublicCertificate _lcc50 +#define Level3_RewrapDeviceRSAKey30 _lcc51 extern "C" { -bool Level3_PreInitialize(const char* path); +bool Level3_IsInApp(const char* path); OEMCryptoResult Level3_Initialize(void (*ClearCache)(void *, size_t)); OEMCryptoResult Level3_Terminate(void); OEMCryptoResult Level3_OpenSession(OEMCrypto_SESSION *session); @@ -107,14 +110,14 @@ OEMCryptoResult Level3_SelectKey(const OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length); OEMCryptoResult Level3_DecryptCENC(OEMCrypto_SESSION session, - const uint8_t *data_addr, - size_t data_length, - bool is_encrypted, - const uint8_t *iv, - size_t block_offset, - const OEMCrypto_DestBufferDesc* out_buffer, + const uint8_t *data_addr, + size_t data_length, + bool is_encrypted, + const uint8_t *iv, + size_t block_offset, + const OEMCrypto_DestBufferDesc* out_buffer, const OEMCrypto_CENCEncryptPatternDesc* pattern, - uint8_t subsample_flags); + uint8_t subsample_flags); OEMCryptoResult Level3_CopyBuffer(const uint8_t *data_addr, size_t data_length, OEMCrypto_DestBufferDesc* out_buffer, @@ -127,6 +130,10 @@ OEMCryptoResult Level3_WrapKeybox(const uint8_t *keybox, size_t transportKeyLength); OEMCryptoResult Level3_InstallKeybox(const uint8_t *keybox, size_t keyBoxLength); +OEMCrypto_ProvisioningMethod Level3_GetProvisioningMethod(); +OEMCryptoResult Level3_GetOEMPublicCertificate(OEMCrypto_SESSION session, + uint8_t *public_cert, + size_t *public_cert_length); OEMCryptoResult Level3_LoadTestKeybox(); OEMCryptoResult Level3_IsKeyboxValid(void); OEMCryptoResult Level3_GetDeviceID(uint8_t* deviceID, @@ -135,6 +142,15 @@ OEMCryptoResult Level3_GetKeyData(uint8_t* keyData, size_t *keyDataLength); OEMCryptoResult Level3_GetRandom(uint8_t* randomData, size_t dataLength); +OEMCryptoResult Level3_RewrapDeviceRSAKey30(OEMCrypto_SESSION session, + const uint32_t *nonce, + const uint8_t* encrypted_message_key, + size_t encrypted_message_key_length, + const uint8_t* enc_rsa_key, + size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, + uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length); OEMCryptoResult Level3_RewrapDeviceRSAKey(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, diff --git a/libwvdrmengine/oemcrypto/mock/src/oem_cert.cpp b/libwvdrmengine/oemcrypto/mock/src/oem_cert.cpp new file mode 100644 index 00000000..8e111f82 --- /dev/null +++ b/libwvdrmengine/oemcrypto/mock/src/oem_cert.cpp @@ -0,0 +1,141 @@ +// This file contains the test OEM cert. + +#include "oem_cert.h" + +// TODO(fredgc, b/30141311): get a real certificate from server gang. +// TODO(fredgc): This is in PEM format. Is that what we want? +const uint8_t kOEMPublicCert[] = "-----BEGIN CERTIFICATE-----\n" + "MIIEOTCCAyGgAwIBAgIJAJNm87hSM9ZIMA0GCSqGSIb3DQEBCwUAMIGyMQswCQYD\n" + "VQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjERMA8GA1UEBwwIS2lya2xhbmQx\n" + "GDAWBgNVBAoMD0dvb2dsZSBXaWRldmluZTEXMBUGA1UECwwOVGVzdCBhbmQgRGVi\n" + "dWcxJjAkBgNVBAMMHU9FTUNyeXB0byBNb2NrIFJlZmVyZW5jZSBDb2RlMSAwHgYJ\n" + "KoZIhvcNAQkBFhFmcmVkZ2NAZ29vZ2xlLmNvbTAeFw0xNjEwMDYxODUzNDZaFw0x\n" + "NjEwMTYxODUzNDZaMIGyMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3Rv\n" + "bjERMA8GA1UEBwwIS2lya2xhbmQxGDAWBgNVBAoMD0dvb2dsZSBXaWRldmluZTEX\n" + "MBUGA1UECwwOVGVzdCBhbmQgRGVidWcxJjAkBgNVBAMMHU9FTUNyeXB0byBNb2Nr\n" + "IFJlZmVyZW5jZSBDb2RlMSAwHgYJKoZIhvcNAQkBFhFmcmVkZ2NAZ29vZ2xlLmNv\n" + "bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMuQQOqS9Q6K/Di8G4xl\n" + "8pz6Ea90D1FLYzIZXd98Ybd94qwWHYaaNuTfTXvZH07fWxrc8HG44N51ArzZGEaT\n" + "h1O7Jt39qLGMirocCgQLxNI3SP7l/pXmsZBM20tYKOoSq7E68eFbXWp39LDOVElS\n" + "/Lib0QkcwmJd55Fnxk6PIscBqYQilLIglQheoDLcljmOd9Rcr59JTtDENfBJE+SC\n" + "ZD0Kckc2e6lBvy/VGKUqE2hmt00pFBugWsN+SkasLGst5/pTVZfTKOBd1E3OvfL3\n" + "qtli4bRyPVX23zSk/bCzxQO47pXe6nVna9m4Yk/LfwJfDIb+r1ErNwyZ4SmZLw6T\n" + "LrkCAwEAAaNQME4wHQYDVR0OBBYEFNx/l/kMs1AY9IhIphtjzR7cwIVBMB8GA1Ud\n" + "IwQYMBaAFNx/l/kMs1AY9IhIphtjzR7cwIVBMAwGA1UdEwQFMAMBAf8wDQYJKoZI\n" + "hvcNAQELBQADggEBAFSaXoWtFU/895lD1Sh/u6pdJcGuCJS0/s2scs95T1sglpfn\n" + "7pdTNtC1aniGuN0T+Aa2O95rJnS0W6RBGdKt1umFOcC7NfRBq1h7a1rn5wYicE5z\n" + "6rIumCSU4oniKMnQ5J+6LpKUFDVJt2W2o8LCKrHWgvcomo8B4ffdKrg+IKpS9Lxc\n" + "U3wyi27rRCyH004YpyE48hPXB3et6OmP2/Aw01d9LxTXieDh0HkhptEllV5EyGM2\n" + "nnRkbd21nHMkVUDzXYWDibxQj6PXw57smnjx7vTiZ1GoE72g2ENSwT1MQhoI59hy\n" + "WCKO91GNxZnyblSTrjLvzAY2hlVCauo7NmLG/yM=\n" + "-----END CERTIFICATE-----\n"; + +const size_t kOEMPublicCertSize = sizeof(kOEMPublicCert); + +// TODO(fredgc): get the private key that goes with the certificat above. +const uint8_t kOEMPrivateKey[] = { + 0x30, 0x82, 0x04, 0xbd, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xcb, 0x90, 0x40, 0xea, 0x92, 0xf5, 0x0e, 0x8a, 0xfc, 0x38, + 0xbc, 0x1b, 0x8c, 0x65, 0xf2, 0x9c, 0xfa, 0x11, 0xaf, 0x74, 0x0f, 0x51, + 0x4b, 0x63, 0x32, 0x19, 0x5d, 0xdf, 0x7c, 0x61, 0xb7, 0x7d, 0xe2, 0xac, + 0x16, 0x1d, 0x86, 0x9a, 0x36, 0xe4, 0xdf, 0x4d, 0x7b, 0xd9, 0x1f, 0x4e, + 0xdf, 0x5b, 0x1a, 0xdc, 0xf0, 0x71, 0xb8, 0xe0, 0xde, 0x75, 0x02, 0xbc, + 0xd9, 0x18, 0x46, 0x93, 0x87, 0x53, 0xbb, 0x26, 0xdd, 0xfd, 0xa8, 0xb1, + 0x8c, 0x8a, 0xba, 0x1c, 0x0a, 0x04, 0x0b, 0xc4, 0xd2, 0x37, 0x48, 0xfe, + 0xe5, 0xfe, 0x95, 0xe6, 0xb1, 0x90, 0x4c, 0xdb, 0x4b, 0x58, 0x28, 0xea, + 0x12, 0xab, 0xb1, 0x3a, 0xf1, 0xe1, 0x5b, 0x5d, 0x6a, 0x77, 0xf4, 0xb0, + 0xce, 0x54, 0x49, 0x52, 0xfc, 0xb8, 0x9b, 0xd1, 0x09, 0x1c, 0xc2, 0x62, + 0x5d, 0xe7, 0x91, 0x67, 0xc6, 0x4e, 0x8f, 0x22, 0xc7, 0x01, 0xa9, 0x84, + 0x22, 0x94, 0xb2, 0x20, 0x95, 0x08, 0x5e, 0xa0, 0x32, 0xdc, 0x96, 0x39, + 0x8e, 0x77, 0xd4, 0x5c, 0xaf, 0x9f, 0x49, 0x4e, 0xd0, 0xc4, 0x35, 0xf0, + 0x49, 0x13, 0xe4, 0x82, 0x64, 0x3d, 0x0a, 0x72, 0x47, 0x36, 0x7b, 0xa9, + 0x41, 0xbf, 0x2f, 0xd5, 0x18, 0xa5, 0x2a, 0x13, 0x68, 0x66, 0xb7, 0x4d, + 0x29, 0x14, 0x1b, 0xa0, 0x5a, 0xc3, 0x7e, 0x4a, 0x46, 0xac, 0x2c, 0x6b, + 0x2d, 0xe7, 0xfa, 0x53, 0x55, 0x97, 0xd3, 0x28, 0xe0, 0x5d, 0xd4, 0x4d, + 0xce, 0xbd, 0xf2, 0xf7, 0xaa, 0xd9, 0x62, 0xe1, 0xb4, 0x72, 0x3d, 0x55, + 0xf6, 0xdf, 0x34, 0xa4, 0xfd, 0xb0, 0xb3, 0xc5, 0x03, 0xb8, 0xee, 0x95, + 0xde, 0xea, 0x75, 0x67, 0x6b, 0xd9, 0xb8, 0x62, 0x4f, 0xcb, 0x7f, 0x02, + 0x5f, 0x0c, 0x86, 0xfe, 0xaf, 0x51, 0x2b, 0x37, 0x0c, 0x99, 0xe1, 0x29, + 0x99, 0x2f, 0x0e, 0x93, 0x2e, 0xb9, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x82, 0x01, 0x00, 0x5d, 0xc7, 0x67, 0x20, 0xa9, 0xf3, 0x1b, 0x70, 0x0c, + 0x22, 0x57, 0x06, 0x99, 0xf7, 0x9d, 0x7d, 0x93, 0xf6, 0xf1, 0xcd, 0x96, + 0x00, 0xed, 0xaa, 0x15, 0x3a, 0x7a, 0x74, 0xaa, 0xe8, 0x99, 0x8f, 0xf5, + 0x0d, 0x32, 0x63, 0x07, 0xcf, 0xa3, 0xda, 0x6c, 0xc5, 0x55, 0x79, 0x01, + 0x63, 0x64, 0xa2, 0xa4, 0x0d, 0x84, 0xf7, 0xdf, 0x24, 0x39, 0x57, 0xce, + 0x9b, 0x11, 0xa8, 0x8d, 0x5b, 0x09, 0xcd, 0x19, 0x3b, 0x1e, 0xa9, 0xed, + 0x3d, 0x5e, 0x71, 0xca, 0xab, 0x80, 0x31, 0xbc, 0xfa, 0x3f, 0x9e, 0x18, + 0x92, 0xd5, 0x82, 0x23, 0xac, 0xd3, 0xc0, 0x96, 0xa7, 0xb0, 0x5e, 0x3c, + 0xfb, 0x18, 0xfe, 0xdf, 0xf7, 0x37, 0xd7, 0x8a, 0x2f, 0xcf, 0x0c, 0xd4, + 0x3d, 0x5f, 0xd0, 0x94, 0xb7, 0x16, 0x96, 0x35, 0xb2, 0x67, 0x70, 0x48, + 0x5c, 0xe8, 0xc5, 0xf5, 0xc6, 0xc9, 0x25, 0x07, 0xec, 0x0d, 0xa1, 0x74, + 0x09, 0x9d, 0xcd, 0x25, 0xa5, 0x7a, 0x2f, 0xa6, 0x4c, 0xba, 0x7d, 0x55, + 0x4f, 0x79, 0x83, 0xaa, 0xfa, 0x3a, 0xc0, 0xaf, 0xc2, 0x33, 0xb2, 0x9a, + 0x68, 0x89, 0x72, 0x2f, 0x86, 0x69, 0x28, 0x1b, 0xdc, 0xa2, 0x05, 0xe3, + 0xfc, 0x24, 0x4c, 0xe0, 0x02, 0xb7, 0x06, 0x4b, 0xe0, 0x88, 0xe9, 0x79, + 0x72, 0x46, 0x1c, 0x49, 0x5e, 0xfa, 0x2d, 0x29, 0xe5, 0xbf, 0x29, 0xfe, + 0xf2, 0xee, 0xeb, 0xe8, 0x4a, 0x8d, 0xdd, 0xfa, 0x8e, 0xb0, 0x65, 0x68, + 0x38, 0xa5, 0xb4, 0xd7, 0x75, 0xd7, 0x8c, 0x32, 0x51, 0xe3, 0x97, 0x00, + 0x91, 0x19, 0x87, 0xaa, 0xeb, 0x4b, 0xcf, 0xf9, 0x6b, 0xf2, 0x87, 0xb9, + 0x93, 0x4e, 0xd7, 0x5c, 0x27, 0xbb, 0x92, 0x29, 0x5e, 0xb8, 0xe9, 0x75, + 0xc0, 0xc6, 0xa3, 0x8a, 0xb7, 0x1e, 0x19, 0xce, 0xd9, 0x5a, 0xc1, 0x0f, + 0x6d, 0xa6, 0x4a, 0x56, 0x24, 0x10, 0x01, 0x02, 0x81, 0x81, 0x00, 0xe8, + 0x1b, 0x99, 0x55, 0x0e, 0x19, 0x8b, 0x48, 0x46, 0xb1, 0x36, 0xb0, 0xe8, + 0x15, 0x5f, 0x45, 0x8b, 0x09, 0xac, 0x82, 0xd1, 0x93, 0x6f, 0x8d, 0xed, + 0xe8, 0x80, 0x82, 0xe4, 0xbc, 0x33, 0x40, 0x50, 0x71, 0x3f, 0x2c, 0x20, + 0x46, 0x34, 0x3f, 0x27, 0xc3, 0x98, 0x66, 0x34, 0x99, 0x05, 0x06, 0x53, + 0x43, 0xdf, 0x52, 0x0b, 0x56, 0x1a, 0xde, 0x3f, 0xbf, 0xba, 0x61, 0xd3, + 0xcf, 0xfd, 0xee, 0x34, 0x71, 0x75, 0x9f, 0xfd, 0xc4, 0xb0, 0x8b, 0x26, + 0xb1, 0x77, 0x83, 0xd4, 0x90, 0x28, 0xc2, 0xb7, 0x52, 0x98, 0xa0, 0x6b, + 0x4b, 0x19, 0x8b, 0x28, 0xbb, 0x18, 0x3e, 0x29, 0x14, 0x7e, 0xa3, 0x87, + 0xf8, 0x4d, 0x8a, 0x67, 0x3a, 0xf6, 0xec, 0x04, 0x7b, 0xfb, 0x3e, 0xa5, + 0xe3, 0xbb, 0xb2, 0x35, 0xf2, 0xd1, 0x63, 0x55, 0xb6, 0x87, 0x07, 0xea, + 0xbb, 0x06, 0x62, 0xbf, 0xaa, 0xbb, 0x19, 0x02, 0x81, 0x81, 0x00, 0xe0, + 0x84, 0x77, 0xb0, 0xc1, 0x94, 0x89, 0xc6, 0x54, 0x78, 0x8a, 0xf0, 0xcd, + 0xa4, 0x88, 0x92, 0xb4, 0xc9, 0xf1, 0x1c, 0x60, 0xea, 0x6d, 0x1c, 0x1d, + 0x33, 0x92, 0x12, 0xe3, 0xe3, 0xd4, 0x11, 0xb6, 0x4d, 0x05, 0x93, 0xbc, + 0x19, 0x50, 0xfc, 0x20, 0xe6, 0x07, 0x4a, 0xbc, 0xb6, 0x4f, 0xc1, 0x81, + 0xc8, 0x71, 0xa7, 0xe2, 0x79, 0xb3, 0xc9, 0x43, 0x43, 0xca, 0x27, 0xe7, + 0x37, 0x5b, 0x20, 0x83, 0x14, 0x8f, 0xb7, 0xba, 0x6c, 0x19, 0x21, 0xd5, + 0x60, 0x87, 0xae, 0x45, 0xa8, 0x17, 0xd8, 0x73, 0xae, 0x65, 0xae, 0x83, + 0x26, 0xff, 0x4e, 0x4f, 0x95, 0xdc, 0xce, 0x12, 0x40, 0xe6, 0xdd, 0xf2, + 0x64, 0x84, 0x65, 0x86, 0x3e, 0xb4, 0xbe, 0x2d, 0x95, 0x74, 0x5c, 0xb2, + 0xc6, 0x7c, 0x84, 0x17, 0x06, 0xe8, 0x80, 0xc8, 0xfe, 0x79, 0x22, 0xe6, + 0xfa, 0x1f, 0xd2, 0x71, 0x84, 0x24, 0xa1, 0x02, 0x81, 0x80, 0x1d, 0x33, + 0x63, 0xad, 0xfc, 0xb1, 0x20, 0x01, 0xbe, 0xcb, 0x0a, 0xbb, 0x64, 0xe7, + 0x53, 0x6e, 0x17, 0x58, 0xe7, 0x38, 0x2a, 0x0f, 0xa7, 0x68, 0x2e, 0xb7, + 0x22, 0x7b, 0xd5, 0x35, 0x0c, 0x29, 0x9a, 0x35, 0x35, 0x22, 0x63, 0x09, + 0x12, 0x07, 0xa4, 0x04, 0x0a, 0x87, 0x49, 0x34, 0xbb, 0x1a, 0x19, 0x9d, + 0x9f, 0x59, 0xde, 0x0d, 0x3e, 0x22, 0x19, 0xd9, 0x10, 0x24, 0xc0, 0x96, + 0x19, 0x37, 0x3f, 0xa7, 0xca, 0x89, 0x8f, 0x4e, 0x90, 0x7b, 0x61, 0x29, + 0xd0, 0x84, 0x68, 0x58, 0x9e, 0x98, 0x28, 0xa2, 0x1e, 0x8b, 0x88, 0x14, + 0x11, 0xa9, 0x9d, 0x3d, 0x34, 0x86, 0x95, 0x7a, 0x7b, 0x98, 0x2d, 0x42, + 0x02, 0xd7, 0x57, 0xb7, 0x66, 0x5b, 0x39, 0x11, 0x34, 0x01, 0xa4, 0xb3, + 0x2a, 0xe8, 0xf7, 0xba, 0x8d, 0xb7, 0x36, 0x90, 0x59, 0x1a, 0x98, 0xe0, + 0x60, 0xa4, 0x49, 0xc2, 0xbb, 0xf9, 0x02, 0x81, 0x80, 0x06, 0x01, 0x65, + 0x16, 0x34, 0x47, 0x5d, 0xdc, 0x11, 0x3c, 0x5c, 0x33, 0x0e, 0xbd, 0x1c, + 0xee, 0x17, 0xa9, 0xe3, 0x2a, 0x28, 0x29, 0x7d, 0x1b, 0xa8, 0x68, 0x4d, + 0xba, 0xf5, 0x9f, 0x8d, 0x77, 0x9f, 0xd1, 0xb5, 0x99, 0x7b, 0x09, 0x8e, + 0x52, 0x00, 0x2b, 0x46, 0xfc, 0xa7, 0xc9, 0x94, 0x9e, 0x8f, 0x73, 0x26, + 0x1f, 0x20, 0x7e, 0xb2, 0xe1, 0x6a, 0x4c, 0x30, 0xe7, 0x1a, 0x57, 0x2f, + 0xb7, 0xd1, 0xe9, 0xc5, 0xe2, 0x5b, 0x39, 0x32, 0xfe, 0xe5, 0xaf, 0x3c, + 0x51, 0xdc, 0x09, 0x20, 0x02, 0x29, 0x2d, 0xfc, 0x08, 0x4b, 0xf7, 0xca, + 0x12, 0x75, 0x2c, 0x84, 0x08, 0x7b, 0x12, 0x83, 0x5a, 0x62, 0x76, 0x6f, + 0xd8, 0x2b, 0x5c, 0x18, 0x07, 0x92, 0x3e, 0x92, 0x2b, 0x3c, 0x98, 0xf4, + 0x91, 0xaf, 0xef, 0xfe, 0x5e, 0x1b, 0x82, 0x3b, 0x09, 0x44, 0xf6, 0x61, + 0xcd, 0x86, 0x3d, 0xcb, 0xa1, 0x02, 0x81, 0x81, 0x00, 0xe5, 0x81, 0xf6, + 0x6f, 0x37, 0xf4, 0xef, 0xc7, 0x0e, 0xdf, 0x39, 0xd0, 0x97, 0x68, 0x1c, + 0xd5, 0x12, 0x42, 0x00, 0x0e, 0xd1, 0x89, 0xdc, 0xf5, 0x24, 0x30, 0xb3, + 0xeb, 0xea, 0x64, 0x3c, 0x9e, 0xa2, 0xc3, 0x49, 0x3c, 0xed, 0x2d, 0x4e, + 0x9a, 0x00, 0x23, 0x71, 0xcc, 0x15, 0xda, 0x49, 0xdc, 0xab, 0xd1, 0x36, + 0xe1, 0x8c, 0x91, 0x6c, 0x5b, 0x47, 0x43, 0x34, 0xec, 0xcd, 0x0c, 0xd0, + 0x88, 0x7c, 0x5a, 0xd4, 0x91, 0x79, 0xe5, 0xe6, 0xd2, 0x5d, 0x2e, 0x14, + 0x26, 0x81, 0x94, 0x9f, 0x29, 0x2b, 0x3e, 0xd6, 0x2f, 0x2d, 0xd9, 0xec, + 0x88, 0x6a, 0xd3, 0x35, 0x71, 0x8a, 0xb2, 0xef, 0x22, 0xdc, 0xab, 0x26, + 0xf9, 0x4d, 0x4c, 0x08, 0x8e, 0x16, 0x5b, 0x56, 0xb6, 0x76, 0x61, 0x89, + 0x8a, 0x3a, 0xdb, 0xbb, 0x42, 0xe3, 0x50, 0x3f, 0xa1, 0x08, 0x82, 0xc2, + 0x92, 0xef, 0x8c, 0xc2, 0xca +}; + +const size_t kOEMPrivateKeySize = sizeof(kOEMPrivateKey); diff --git a/libwvdrmengine/oemcrypto/mock/src/oem_cert.h b/libwvdrmengine/oemcrypto/mock/src/oem_cert.h new file mode 100644 index 00000000..8dd846c2 --- /dev/null +++ b/libwvdrmengine/oemcrypto/mock/src/oem_cert.h @@ -0,0 +1,14 @@ +// This header is used to access the OEM certificate if one is in use. +#ifndef OEM_CERT_H_ +#define OEM_CERT_H_ + +#include +#include + +extern const uint8_t kOEMPrivateKey[]; +extern const size_t kOEMPrivateKeySize; + +extern const uint8_t kOEMPublicCert[]; +extern const size_t kOEMPublicCertSize; + +#endif // OEM_CERT_H_ diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp index 7965ab64..6f9c67db 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties.cpp @@ -38,6 +38,17 @@ bool CryptoEngine::supports_keybox() { return true; } +// This version uses a keybox. +OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() { + return OEMCrypto_Keybox; +} + +OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session, + uint8_t *public_cert, + size_t *public_cert_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + // Returns false for mock library to indicate the client does not support // anti-rollback hardware. bool CryptoEngine::is_anti_rollback_hw_present() { diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp index 62db4319..5ffc068a 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_L1.cpp @@ -40,6 +40,17 @@ bool CryptoEngine::supports_keybox() { return true; } +// This version uses a keybox. +OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() { + return OEMCrypto_Keybox; +} + +OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session, + uint8_t *public_cert, + size_t *public_cert_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + // Returns true to indicate the client does support anti-rollback hardware. bool CryptoEngine::is_anti_rollback_hw_present() { return true; diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp index 352e2eeb..2a4dec2b 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_cert.cpp @@ -41,6 +41,17 @@ bool CryptoEngine::supports_keybox() { return false; } +// This version uses a baked in DRM certificate. +OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() { + return OEMCrypto_DrmCertificate; +} + +OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session, + uint8_t *public_cert, + size_t *public_cert_length) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + // Returns true to indicate the client does support anti-rollback hardware. bool CryptoEngine::is_anti_rollback_hw_present() { return false; diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_prov30.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_prov30.cpp new file mode 100644 index 00000000..1d783f80 --- /dev/null +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_device_properties_prov30.cpp @@ -0,0 +1,97 @@ +// Copyright 2016 Google Inc. All Rights Reserved. +// +// Mock implementation of OEMCrypto APIs +// +// This file contains oemcrypto engine properties that would be for a +// level 2 device that does not have persistant storage or a keybox. +// Note: this is for illustration only. Production devices are rarely level 2. +#include "oemcrypto_engine_mock.h" + +#include + +#include "log.h" +#include "oem_cert.h" + +namespace wvoec_mock { + +// If local_display() returns true, we pretend we are using a built-in display, +// instead of HDMI or WiFi output. +bool CryptoEngine::local_display() { + return true; +} + +// A closed platform is permitted to use clear buffers. +bool CryptoEngine::closed_platform() { + return false; +} + +// Returns the HDCP version currently in use. +OEMCrypto_HDCP_Capability CryptoEngine::current_hdcp_capability() { + return local_display() ? HDCP_NO_DIGITAL_OUTPUT : HDCP_V1; +} + +// Returns the max HDCP version supported. +OEMCrypto_HDCP_Capability CryptoEngine::maximum_hdcp_capability() { + return HDCP_NO_DIGITAL_OUTPUT; +} + +// Returns true if the client supports persistent storage of +// offline usage table information. +bool CryptoEngine::supports_storage() { + return false; +} + +// Returns true if the client uses a keybox as the root of trust. +bool CryptoEngine::supports_keybox() { + return false; +} + +// This version uses a keybox. +OEMCrypto_ProvisioningMethod CryptoEngine::provisioning_method() { + return OEMCrypto_OEMCertificate; +} + +OEMCryptoResult CryptoEngine::get_oem_certificate(SessionContext *session, + uint8_t *public_cert, + size_t *public_cert_length) { + if (kOEMPublicCertSize == 0) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (public_cert_length == NULL) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (*public_cert_length < kOEMPublicCertSize) { + *public_cert_length = kOEMPublicCertSize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *public_cert_length = kOEMPublicCertSize; + if (public_cert == NULL) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize); + if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) { + LOGE("Private RSA Key did not load correctly."); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + return OEMCrypto_SUCCESS; +} + +// Returns true to indicate the client does support anti-rollback hardware. +bool CryptoEngine::is_anti_rollback_hw_present() { + return false; +} + +// Returns "L3" for a software only library. L1 is for hardware protected keys +// and data paths. L2 is for hardware protected keys but no data path +// protection. +const char* CryptoEngine::security_level() { + return "L2"; +} + +// This should start at 0, and be incremented only when a security patch has +// been applied to the device that fixes a security bug. +uint8_t CryptoEngine::security_patch_level() { + return 0; +} + +} // namespace wvoec_mock diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp index 9d7ff559..e87bfe92 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp @@ -242,12 +242,71 @@ void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) { } } +void RSA_shared_ptr::reset() { + if (rsa_key_ && key_owned_) { + RSA_free(rsa_key_); + } + key_owned_ = false; + rsa_key_ = NULL; +} + +bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) { + assert(buffer != NULL); + reset(); + key_owned_ = true; + uint8_t* pkcs8_rsa_key = const_cast(buffer); + BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length); + if (bio == NULL) { + LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]"); + return false; + } + bool success = true; + PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); + if (pkcs8_pki == NULL) { + LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]"); + success = false; + } + EVP_PKEY* evp = NULL; + if (success) { + evp = EVP_PKCS82PKEY(pkcs8_pki); + if (evp == NULL) { + LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]"); + success = false; + } + } + if (success) { + rsa_key_ = EVP_PKEY_get1_RSA(evp); + if (rsa_key_ == NULL) { + LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]"); + success = false; + } + } + if (evp != NULL) { + EVP_PKEY_free(evp); + } + if (pkcs8_pki != NULL) { + PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); + } + BIO_free(bio); + if (!success) { + return false; + } + switch (RSA_check_key(rsa_key_)) { + case 1: // valid. + return true; + case 0: // not valid. + LOGE("[LoadPkcs8RsaKey(): rsa key not valid]"); + dump_openssl_error(); + return false; + default: // -1 == check failed. + LOGE("[LoadPkcs8RsaKey(): error checking rsa key]"); + dump_openssl_error(); + return false; + } +} + SessionContext::~SessionContext() { if (usage_entry_) usage_entry_->set_session(NULL); - if (rsa_key_ && rsa_key_ != ce_->rsa_key()) { - RSA_free(rsa_key_); - rsa_key_ = NULL; - } } // Internal utility function to derive key using CMAC-128 @@ -339,20 +398,20 @@ bool SessionContext::DeriveKeys(const std::vector& master_key, bool SessionContext::RSADeriveKeys(const std::vector& enc_session_key, const std::vector& mac_key_context, const std::vector& enc_key_context) { - if (!rsa_key_) { + if (!rsa_key()) { LOGE("[RSADeriveKeys(): no RSA key set]"); return false; } - if (enc_session_key.size() != static_cast(RSA_size(rsa_key_))) { + if (enc_session_key.size() != static_cast(RSA_size(rsa_key()))) { LOGE("[RSADeriveKeys(): encrypted session key wrong size:%zu, expected %d]", - enc_session_key.size(), RSA_size(rsa_key_)); + enc_session_key.size(), RSA_size(rsa_key())); dump_openssl_error(); return false; } - session_key_.resize(RSA_size(rsa_key_)); + session_key_.resize(RSA_size(rsa_key())); int decrypted_size = RSA_private_decrypt(enc_session_key.size(), &enc_session_key[0], - &session_key_[0], rsa_key_, + &session_key_[0], rsa_key(), RSA_PKCS1_OAEP_PADDING); if (-1 == decrypted_size) { LOGE("[RSADeriveKeys(): error decrypting session key.]"); @@ -402,11 +461,11 @@ bool SessionContext::GenerateSignature(const uint8_t* message, } size_t SessionContext::RSASignatureSize() { - if (!rsa_key_) { + if (!rsa_key()) { LOGE("[GenerateRSASignature(): no RSA key set]"); return 0; } - return static_cast(RSA_size(rsa_key_)); + return static_cast(RSA_size(rsa_key())); } OEMCryptoResult SessionContext::GenerateRSASignature( @@ -417,19 +476,18 @@ OEMCryptoResult SessionContext::GenerateRSASignature( LOGE("[GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } - if (!rsa_key_) { + if (!rsa_key()) { LOGE("[GenerateRSASignature(): no RSA key set]"); return OEMCrypto_ERROR_INVALID_RSA_KEY; } - if (*signature_length < static_cast(RSA_size(rsa_key_))) { - *signature_length = RSA_size(rsa_key_); + if (*signature_length < static_cast(RSA_size(rsa_key()))) { + *signature_length = RSA_size(rsa_key()); return OEMCrypto_ERROR_SHORT_BUFFER; } if ((padding_scheme & allowed_schemes_) != padding_scheme) { LOGE("[GenerateRSASignature(): padding_scheme not allowed]"); return OEMCrypto_ERROR_INVALID_RSA_KEY; } - // This is the standard padding scheme used for license requests. if (padding_scheme == kSign_RSASSA_PSS) { // Hash the message using SHA1. @@ -442,7 +500,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature( // Add PSS padding. std::vector padded_digest(*signature_length); - int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa_key_, &padded_digest[0], + int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa_key(), &padded_digest[0], hash, EVP_sha1(), NULL, kPssSaltLength); if (status == -1) { @@ -453,7 +511,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature( // Encrypt PSS padded digest. status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature, - rsa_key_, RSA_NO_PADDING); + rsa_key(), RSA_NO_PADDING); if (status == -1) { LOGE("[GeneratRSASignature(): error in private encrypt.]"); dump_openssl_error(); @@ -467,7 +525,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature( } // Pad the message with PKCS1 padding, and then encrypt. size_t status = RSA_private_encrypt(message_length, message, signature, - rsa_key_, RSA_PKCS1_PADDING); + rsa_key(), RSA_PKCS1_PADDING); if (status != *signature_length) { LOGE("[GeneratRSASignature(): error in RSA private encrypt. status=%d]", status); dump_openssl_error(); @@ -711,6 +769,29 @@ bool SessionContext::InstallKey(const KeyId& key_id, return true; } +bool SessionContext::InstallRSAEncryptedKey(const uint8_t *encrypted_message_key, + size_t encrypted_message_key_length) { + encryption_key_.resize(RSA_size(rsa_key())); + int decrypted_size = RSA_private_decrypt( encrypted_message_key_length, + encrypted_message_key, + &encryption_key_[0], rsa_key(), + RSA_PKCS1_OAEP_PADDING); + if (-1 == decrypted_size) { + LOGE("[RSADeriveKeys(): error decrypting session key.]"); + dump_openssl_error(); + return false; + } + encryption_key_.resize(decrypted_size); + if (decrypted_size != static_cast(wvcdm::KEY_SIZE)) { + LOGE("[RSADeriveKeys(): error. session key is wrong size: %d.]", + decrypted_size); + dump_openssl_error(); + encryption_key_.clear(); + return false; + } + return true; +} + OEMCryptoResult SessionContext::RefreshKey( const KeyId& key_id, const std::vector& key_control, const std::vector& key_control_iv) { @@ -790,7 +871,7 @@ bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key, const uint8_t* enc_rsa_key_iv, uint8_t* pkcs8_rsa_key) { // Decrypt rsa key with keybox. - uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE]; + uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE); AES_KEY aes_key; AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key); @@ -804,7 +885,7 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key, const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key) { // Encrypt rsa key with keybox. - uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE]; + uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE); AES_KEY aes_key; AES_set_encrypt_key(&encryption_key_[0], 128, &aes_key); @@ -813,79 +894,22 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key, return true; } -bool SessionContext::LoadRSAKey(uint8_t* pkcs8_rsa_key, - size_t rsa_key_length, - const uint8_t* message, - size_t message_length, - const uint8_t* signature, - size_t signature_length) { - // Validate message signature - if (!ValidateMessage(message, message_length, signature, signature_length)) { - LOGE("[LoadRSAKey(): Could not verify signature]"); - return false; - } - if (rsa_key_) { - RSA_free(rsa_key_); - rsa_key_ = NULL; - } +bool SessionContext::LoadRSAKey(const uint8_t* pkcs8_rsa_key, + size_t rsa_key_length) { + rsa_key_.reset(); if (rsa_key_length < 8) { LOGE("[LoadRSAKey(): Very Short Buffer]"); return false; } - if( (memcmp(pkcs8_rsa_key, "SIGN", 4) == 0) ) { - uint32_t *schemes_n = (uint32_t *)(pkcs8_rsa_key + 4); + if ((memcmp(pkcs8_rsa_key, "SIGN", 4) == 0)) { + uint32_t* schemes_n = (uint32_t*)(pkcs8_rsa_key + 4); allowed_schemes_ = htonl(*schemes_n); pkcs8_rsa_key += 8; rsa_key_length -= 8; + } else { + allowed_schemes_ = kSign_RSASSA_PSS; } - BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length); - if ( bio == NULL ) { - LOGE("[LoadRSAKey(): Could not allocate bio buffer]"); - return false; - } - bool success = true; - PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); - if (pkcs8_pki == NULL) { - LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL."); - success = false; - } - EVP_PKEY *evp = NULL; - if (success) { - evp = EVP_PKCS82PKEY(pkcs8_pki); - if (evp == NULL) { - LOGE("EVP_PKCS82PKEY returned NULL."); - success = false; - } - } - if (success) { - rsa_key_ = EVP_PKEY_get1_RSA(evp); - if (rsa_key_ == NULL) { - LOGE("PrivateKeyInfo did not contain an RSA key."); - success = false; - } - } - if (evp != NULL) { - EVP_PKEY_free(evp); - } - if (pkcs8_pki != NULL) { - PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); - } - BIO_free(bio); - if (!success) { - return false; - } - switch (RSA_check_key(rsa_key_)) { - case 1: // valid. - return true; - case 0: // not valid. - LOGE("[LoadRSAKey(): rsa key not valid]"); - dump_openssl_error(); - return false; - default: // -1 == check failed. - LOGE("[LoadRSAKey(): error checking rsa key]"); - dump_openssl_error(); - return false; - } + return rsa_key_.LoadPkcs8RsaKey(pkcs8_rsa_key, rsa_key_length); } OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer, @@ -921,11 +945,11 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } } - if ( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) { + if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { LOGE("[Generic_Encrypt(): algorithm bad."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if ( buffer_length % AES_BLOCK_SIZE != 0 ) { + if (buffer_length % AES_BLOCK_SIZE != 0) { LOGE("[Generic_Encrypt(): buffers size bad."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -935,7 +959,7 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer, LOGE("[Generic_Encrypt(): FAILURE]"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE]; + uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE); AES_cbc_encrypt(in_buffer, out_buffer, buffer_length, &aes_key, iv_buffer, AES_ENCRYPT); @@ -981,11 +1005,11 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } } - if ( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) { + if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) { LOGE("[Generic_Decrypt(): bad algorithm."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if ( buffer_length % AES_BLOCK_SIZE != 0 ) { + if (buffer_length % AES_BLOCK_SIZE != 0) { LOGE("[Generic_Decrypt(): bad buffer size."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -995,7 +1019,7 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer, LOGE("[Generic_Decrypt(): FAILURE]"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE]; + uint8_t iv_buffer[wvcdm::KEY_IV_SIZE]; memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE); AES_cbc_encrypt(in_buffer, out_buffer, buffer_length, &aes_key, iv_buffer, AES_DECRYPT); @@ -1039,7 +1063,7 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } } - if( algorithm != OEMCrypto_HMAC_SHA256 ) { + if (algorithm != OEMCrypto_HMAC_SHA256) { LOGE("[Generic_Sign(): bad algorithm."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -1089,7 +1113,7 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } } - if ( algorithm != OEMCrypto_HMAC_SHA256 ) { + if (algorithm != OEMCrypto_HMAC_SHA256) { LOGE("[Generic_Verify(): bad algorithm."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -1190,21 +1214,20 @@ bool SessionContext::IsUsageEntryValid() { void SessionContext::ReleaseUsageEntry() { usage_entry_ = NULL; } CryptoEngine::CryptoEngine(wvcdm::FileSystem* file_system) - : current_session_(NULL), - use_test_keybox_(false), + : use_test_keybox_(false), file_system_(file_system), - usage_table_(new UsageTable(this)), - rsa_key_(NULL) { + usage_table_(new UsageTable(this)) { ERR_load_crypto_strings(); - if (!supports_keybox() && !LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) { + if ((provisioning_method() == OEMCrypto_DrmCertificate) && + !rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) { + // This error message is OK in unit tests which use test certificate. LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a " "keybox, but the certificate could not be loaded."); } } CryptoEngine::~CryptoEngine() { - current_session_ = NULL; sessions_.clear(); if (usage_table_) delete usage_table_; } @@ -1214,19 +1237,15 @@ void CryptoEngine::Terminate() {} KeyboxError CryptoEngine::ValidateKeybox() { return keybox().Validate(); } bool CryptoEngine::LoadTestRSAKey() { - if (rsa_key_) { - RSA_free(rsa_key_); - rsa_key_ = NULL; - } - return LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048, - sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); + return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048, + sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); } SessionId CryptoEngine::CreateSession() { wvcdm::AutoLock lock(session_table_lock_); static int unique_id = 1; SessionId sid = (SessionId)++unique_id; - SessionContext* sctx = new SessionContext(this, sid, this->rsa_key_); + SessionContext* sctx = new SessionContext(this, sid, rsa_key_); sessions_[sid] = sctx; return sid; } @@ -1252,59 +1271,6 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) { return NULL; } -bool CryptoEngine::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) { - assert(buffer != NULL); - uint8_t* pkcs8_rsa_key = const_cast(buffer); - BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length); - if (bio == NULL) { - LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]"); - return false; - } - bool success = true; - PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); - if (pkcs8_pki == NULL) { - LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]"); - success = false; - } - EVP_PKEY* evp = NULL; - if (success) { - evp = EVP_PKCS82PKEY(pkcs8_pki); - if (evp == NULL) { - LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]"); - success = false; - } - } - if (success) { - rsa_key_ = EVP_PKEY_get1_RSA(evp); - if (rsa_key_ == NULL) { - LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]"); - success = false; - } - } - if (evp != NULL) { - EVP_PKEY_free(evp); - } - if (pkcs8_pki != NULL) { - PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); - } - BIO_free(bio); - if (!success) { - return false; - } - switch (RSA_check_key(rsa_key_)) { - case 1: // valid. - return true; - case 0: // not valid. - LOGE("[LoadPkcs8RsaKey(): rsa key not valid]"); - dump_openssl_error(); - return false; - default: // -1 == check failed. - LOGE("[LoadPkcs8RsaKey(): error checking rsa key]"); - dump_openssl_error(); - return false; - } -} - // Internal utility function to decrypt the message bool SessionContext::DecryptMessage(const std::vector& key, const std::vector& iv, diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h index 1f263f0c..684a04d4 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h @@ -12,11 +12,11 @@ #include +#include "OEMCryptoCENC.h" // Needed for enums only. #include "file_store.h" #include "lock.h" #include "oemcrypto_key_mock.h" #include "oemcrypto_keybox_mock.h" -#include "OEMCryptoCENC.h" // Needed for enums only. #include "wv_cdm_types.h" namespace wvoec_mock { @@ -61,6 +61,7 @@ class NonceTable { void AddNonce(uint32_t nonce); bool CheckNonce(uint32_t nonce); void Flush(); + private: enum NonceTableState { kNTStateInvalid, @@ -72,12 +73,34 @@ class NonceTable { uint32_t nonces_[kTableSize]; }; +// Shared pointer with specialized destructor. This pointer is only shared +// from a CryptoEngine to a Session -- so we don't have to use full reference +// counting. +class RSA_shared_ptr { + public: + RSA_shared_ptr() : rsa_key_(NULL), key_owned_(false) {} + ~RSA_shared_ptr() { reset(); }; + // Explicitly allow copy as share. + explicit RSA_shared_ptr(const RSA_shared_ptr& other) : + rsa_key_(other.rsa_key_), key_owned_(false) {} + RSA* get() { return rsa_key_; } + void reset(); + bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length); + + private: + void operator=(const RSA_shared_ptr); // disallow assign. + + RSA* rsa_key_; + bool key_owned_; +}; + class SessionContext { private: SessionContext() {} public: - explicit SessionContext(CryptoEngine* ce, SessionId sid, RSA* rsa_key) + SessionContext(CryptoEngine* ce, SessionId sid, + const RSA_shared_ptr& rsa_key) : valid_(true), ce_(ce), id_(sid), @@ -132,7 +155,7 @@ class SessionContext { const uint8_t* signature, size_t signature_length); void StartTimer(); - uint32_t CurrentTimer(); // (seconds). + uint32_t CurrentTimer(); // (seconds). OEMCryptoResult LoadKeys(const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, const uint8_t* enc_mac_key_iv, @@ -146,6 +169,8 @@ class SessionContext { const std::vector& key_control_iv, const std::vector& pst, bool ctr_mode); + bool InstallRSAEncryptedKey(const uint8_t *encrypted_message_key, + size_t encrypted_message_key_length); bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, const uint8_t* wrapped_rsa_key_iv, @@ -154,12 +179,8 @@ class SessionContext { size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key); - bool LoadRSAKey(uint8_t* pkcs8_rsa_key, - size_t rsa_key_length, - const uint8_t* message, - size_t message_length, - const uint8_t* signature, - size_t signature_length); + bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, + size_t rsa_key_length); OEMCryptoResult RefreshKey(const KeyId& key_id, const std::vector& key_control, const std::vector& key_control_iv); @@ -212,6 +233,8 @@ class SessionContext { size_t block_offset, const uint8_t* cipher_data, size_t cipher_data_length, uint8_t* clear_data); + RSA* rsa_key() { return rsa_key_.get(); } + bool valid_; CryptoEngine* ce_; SessionId id_; @@ -222,7 +245,7 @@ class SessionContext { const Key* current_content_key_; SessionKeyTable session_keys_; NonceTable nonce_table_; - RSA* rsa_key_; + RSA_shared_ptr rsa_key_; uint32_t allowed_schemes_; // for RSA signatures. time_t timer_start_; UsageTableEntry* usage_entry_; @@ -243,7 +266,7 @@ class CryptoEngine { WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; } WvKeybox& real_keybox() { return keybox_; } void UseTestKeybox() { use_test_keybox_ = true; } - RSA* rsa_key() { return rsa_key_; } + RSA* rsa_key() { return rsa_key_.get(); } bool LoadTestRSAKey(); SessionId CreateSession(); @@ -260,10 +283,6 @@ class CryptoEngine { return kMaxSupportedOEMCryptoSessions; } - void set_current_session_(SessionContext* current) { - current_session_ = current; - } - OEMCrypto_HDCP_Capability current_hdcp_capability(); OEMCrypto_HDCP_Capability maximum_hdcp_capability(); @@ -273,14 +292,15 @@ class CryptoEngine { bool closed_platform(); bool supports_storage(); bool supports_keybox(); + OEMCrypto_ProvisioningMethod provisioning_method(); + OEMCryptoResult get_oem_certificate(SessionContext* session, + uint8_t* public_cert, + size_t* public_cert_length); bool is_anti_rollback_hw_present(); const char* security_level(); uint8_t security_patch_level(); private: - bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length); - - SessionContext* current_session_; ActiveSessions sessions_; WvKeybox keybox_; WvTestKeybox test_keybox_; @@ -288,7 +308,7 @@ class CryptoEngine { wvcdm::Lock session_table_lock_; wvcdm::FileSystem* file_system_; UsageTable* usage_table_; - RSA* rsa_key_; // If no keybox, this is baked in certificate. + RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate. CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine); }; diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.cpp index 4fc1ae6c..b163b392 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_key_mock.cpp @@ -17,7 +17,8 @@ bool KeyControlBlock::Validate() { if (memcmp(verification_, "kctl", 4) && // original verification memcmp(verification_, "kc09", 4) && // add in version 9 api memcmp(verification_, "kc10", 4) && // add in version 10 api - memcmp(verification_, "kc11", 4)) { // add in version 11 api + memcmp(verification_, "kc11", 4) && // add in version 11 api + memcmp(verification_, "kc12", 4)) { // add in version 12 api LOGE("KCB: BAD verification string: %4.4s", verification_); valid_ = false; } else { diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp index a41dead1..b2908627 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp @@ -747,6 +747,45 @@ OEMCryptoResult OEMCrypto_IsKeyboxValid(void) { } } +extern "C" +OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod() { + if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { + LOGI("-- OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(void) {\n"); + } + if (!crypto_engine) { + LOGE("OEMCrypto_GetProvisioningMethod: OEMCrypto Not Initialized."); + return OEMCrypto_ProvisioningError; + } + return crypto_engine->provisioning_method(); +} + +extern "C" +OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(OEMCrypto_SESSION session, + uint8_t *public_cert, + size_t *public_cert_length) { + if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { + LOGI("-- OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(%d) {\n", + session); + } + if (!crypto_engine) { + LOGE("OEMCrypto_GetOEMPublicCertificate: OEMCrypto Not Initialized."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (crypto_engine->provisioning_method() != OEMCrypto_OEMCertificate) { + LOGE("OEMCrypto_GetOEMPublicCertificate: Provisioning method = %d.", + crypto_engine->provisioning_method() + ); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + SessionContext* session_ctx = crypto_engine->FindSession(session); + if (!session_ctx || !session_ctx->isValid()) { + LOGE("[OEMCrypto_GetOEMPublicCertificate(): ERROR_INVALID_SESSION]"); + return OEMCrypto_ERROR_INVALID_SESSION; + } + return crypto_engine->get_oem_certificate(session_ctx, + public_cert, public_cert_length); +} + extern "C" OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength) { @@ -831,6 +870,135 @@ OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } +extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( + OEMCrypto_SESSION session, const uint32_t* nonce, + const uint8_t* encrypted_message_key, size_t encrypted_message_key_length, + const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, + const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, + size_t* wrapped_rsa_key_length) { + if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls | kLoggingTraceNonce)) { + LOGI("-- OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(%d)\n", session); + LOGI("nonce = %08X;\n", *nonce); + if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) { + dump_hex("encrypted_message_key", encrypted_message_key, + encrypted_message_key_length); + dump_hex("enc_rsa_key", enc_rsa_key, enc_rsa_key_length); + dump_hex("enc_rsa_key_iv", enc_rsa_key_iv, wvcdm::KEY_IV_SIZE); + } + } + if (!crypto_engine) { + LOGE("OEMCrypto_RewrapDeviceRSAKey30: OEMCrypto Not Initialized."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (wrapped_rsa_key_length == NULL) { + LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // For the reference implementation, the wrapped key and the encrypted + // key are the same size -- just encrypted with different keys. + // We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature. + // Important: This layout must match OEMCrypto_LoadDeviceRSAKey below. + size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey); + + if (wrapped_rsa_key == NULL || *wrapped_rsa_key_length < buffer_size) { + if (LogCategoryEnabled(kLoggingDumpDerivedKeys)) { + LOGW("[OEMCrypto_RewrapDeviceRSAKey30(): Wrapped Keybox Short Buffer]"); + } + *wrapped_rsa_key_length = buffer_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used. + if (NO_ERROR != crypto_engine->ValidateKeybox()) { + LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_KEYBOX_INVALID]"); + return OEMCrypto_ERROR_KEYBOX_INVALID; + } + SessionContext* session_ctx = crypto_engine->FindSession(session); + if (!session_ctx || !session_ctx->isValid()) { + LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_INVALID_SESSION]"); + return OEMCrypto_ERROR_INVALID_SESSION; + } + if (encrypted_message_key == NULL || encrypted_message_key_length == 0 + || enc_rsa_key == NULL || enc_rsa_key_iv == NULL) { + LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // Validate nonce + if (!session_ctx->CheckNonce(*nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + session_ctx->FlushNonces(); + + if(!session_ctx->InstallRSAEncryptedKey(encrypted_message_key, + encrypted_message_key_length)) { + LOGE("OEMCrypto_RewrapDeviceRSAKey30: Error loading encrypted_message_key."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Decrypt RSA key. + std::vector pkcs8_rsa_key(enc_rsa_key_length); + if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, + enc_rsa_key_iv, &pkcs8_rsa_key[0])) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; + if (padding > 16) { + LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Encrypted RSA has bad padding: %d]", + padding); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + size_t rsa_key_length = enc_rsa_key_length - padding; + if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) { + LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey."); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + + // Now we generate a wrapped keybox. + WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); + // Pick a random context and IV for generating keys. + if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { + LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { + LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // TODO(fredgc): Don't use the keybox to encrypt the wrapped RSA key. + const std::vector + context(wrapped->context, wrapped->context + sizeof(wrapped->context)); + // Generate mac and encryption keys for encrypting the signature. + if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context, + context)) { + LOGE("[_RewrapDeviceRSAKey30(): DeriveKeys failed."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Encrypt rsa key with keybox. + if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length, + wrapped->iv, wrapped->enc_rsa_key)) { + LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed."); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // The wrapped keybox must be signed with the same key we verify with. I'll + // pick the server key, so I don't have to modify LoadRSAKey. + unsigned int sig_length = sizeof(wrapped->signature); + if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], + session_ctx->mac_key_server().size(), wrapped->context, + buffer_size - sizeof(wrapped->signature), wrapped->signature, + &sig_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { + if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) { + dump_hex("wrapped_rsa_key", wrapped_rsa_key, *wrapped_rsa_key_length); + dump_hex("context", wrapped->context, sizeof(wrapped->context)); + dump_hex("iv", wrapped->iv, sizeof(wrapped->iv)); + } + } + return OEMCrypto_SUCCESS; +} + extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session, const uint8_t* message, @@ -844,7 +1012,7 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session, uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) { if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls | kLoggingTraceNonce)) { - LOGI("-- OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey()\n"); + LOGI("-- OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(%d)\n", session); if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) { dump_hex("message", message, message_length); dump_hex("signature", signature, signature_length); @@ -914,70 +1082,58 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session, session_ctx->FlushNonces(); // Decrypt RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[enc_rsa_key_length]; - OEMCryptoResult result = OEMCrypto_SUCCESS; + std::vector pkcs8_rsa_key(enc_rsa_key_length); if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; + enc_rsa_key_iv, &pkcs8_rsa_key[0])) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; } size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if (result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[RewrapRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } + if (padding > 16) { + LOGE("[RewrapDeviceRSAKey(): Encrypted RSA has bad padding: %d]", + padding); + return OEMCrypto_ERROR_INVALID_RSA_KEY; } size_t rsa_key_length = enc_rsa_key_length - padding; // verify signature, verify RSA key, and load it. - if (result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey(pkcs8_rsa_key, rsa_key_length, - message, message_length, - signature, signature_length)) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } + if (!session_ctx->ValidateMessage(message, message_length, signature, + signature_length)) { + LOGE("[RewrapDeviceRSAKey(): Could not verify signature]"); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; } // Now we generate a wrapped keybox. WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); // Pick a random context and IV for generating keys. - if (result == OEMCrypto_SUCCESS) { - if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } + if (!RAND_bytes(wrapped->context, sizeof(wrapped->context))) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!RAND_bytes(wrapped->iv, sizeof(wrapped->iv))) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } const std::vector context(wrapped->context, wrapped->context + sizeof(wrapped->context)); // Generate mac and encryption keys for encrypting the signature. - if (result == OEMCrypto_SUCCESS) { - if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context, - context)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } + if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context, + context)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } // Encrypt rsa key with keybox. - if (result == OEMCrypto_SUCCESS) { - if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key, enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } + if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length, + wrapped->iv, wrapped->enc_rsa_key)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - delete[] pkcs8_rsa_key; - // The wrapped keybox must be signed with the same key we verify with. I'll // pick the server key, so I don't have to modify LoadRSAKey. - if (result == OEMCrypto_SUCCESS) { - unsigned int sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - session_ctx->mac_key_server().size(), wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - result = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } + unsigned int sig_length = sizeof(wrapped->signature); + if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], + session_ctx->mac_key_server().size(), wrapped->context, + buffer_size - sizeof(wrapped->signature), wrapped->signature, + &sig_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } if (LogCategoryEnabled(kLoggingTraceOEMCryptoCalls)) { if (wvcdm::g_cutoff >= wvcdm::LOG_VERBOSE) { @@ -987,7 +1143,7 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session, dump_hex("iv", wrapped->iv, sizeof(wrapped->iv)); } } - return result; + return OEMCrypto_SUCCESS; } extern "C" @@ -1002,12 +1158,13 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, LOGE("OEMCrypto_LoadDeviceRSAKey: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (!crypto_engine->supports_keybox()) { - // If we are not using keyboxes, the "wrapped RSA key" should actually be + if (crypto_engine->provisioning_method() == OEMCrypto_DrmCertificate) { + // If we are using a baked in cert, the "wrapped RSA key" should actually be // the magic value for baked-in certificates. if (wrapped_rsa_key_length != sizeof(kBakedInCertificateMagicBytes) || memcmp(kBakedInCertificateMagicBytes, wrapped_rsa_key, wrapped_rsa_key_length) != 0) { + LOGE("OEMCrypto_LoadDeviceRSAKey: Baked in Cert has wrong size."); return OEMCrypto_ERROR_INVALID_RSA_KEY; } else { return OEMCrypto_SUCCESS; @@ -1024,6 +1181,7 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, dump_hex("iv", wrapped->iv, sizeof(wrapped->iv)); } } + // TODO(fredgc): Don't use the keybox to encrypt the wrapped RSA key. if (NO_ERROR != crypto_engine->ValidateKeybox()) { LOGE("[OEMCrypto_LoadDeviceRSAKey(): ERROR_KEYBOX_INVALID]"); return OEMCrypto_ERROR_KEYBOX_INVALID; @@ -1042,34 +1200,31 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } // Decrypt RSA key. - uint8_t* pkcs8_rsa_key = new uint8_t[wrapped_rsa_key_length - - sizeof(wrapped->signature)]; + std::vector pkcs8_rsa_key(wrapped_rsa_key_length + - sizeof(wrapped->signature)); size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey); - OEMCryptoResult result = OEMCrypto_SUCCESS; if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length, - wrapped->iv, pkcs8_rsa_key)) { - result = OEMCrypto_ERROR_INVALID_RSA_KEY; + wrapped->iv, &pkcs8_rsa_key[0])) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; } size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if (result == OEMCrypto_SUCCESS) { - if (padding > 16) { - LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding); - result = OEMCrypto_ERROR_INVALID_RSA_KEY; - } + if (padding > 16) { + LOGE("[LoadDeviceRSAKey(): Encrypted RSA has bad padding: %d]", padding); + return OEMCrypto_ERROR_INVALID_RSA_KEY; } size_t rsa_key_length = enc_rsa_key_length - padding; // verify signature. - if (result == OEMCrypto_SUCCESS) { - if (!session_ctx->LoadRSAKey( - pkcs8_rsa_key, rsa_key_length, wrapped->context, - wrapped_rsa_key_length - sizeof(wrapped->signature), - wrapped->signature, sizeof(wrapped->signature))) { - result = OEMCrypto_ERROR_SIGNATURE_FAILURE; - // return OEMCrypto_ERROR_INVALID_RSA_KEY; - } + if (!session_ctx->ValidateMessage( + wrapped->context, + wrapped_rsa_key_length - sizeof(wrapped->signature), + wrapped->signature, sizeof(wrapped->signature))) { + LOGE("[LoadDeviceRSAKey(): Could not verify signature]"); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; } - delete[] pkcs8_rsa_key; - return result; + if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + return OEMCrypto_SUCCESS; } extern "C" @@ -1208,8 +1363,7 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( extern "C" uint32_t OEMCrypto_APIVersion() { - // TODO(fredgc): Implement new API. - return 11; + return 12; } extern "C" @@ -1319,7 +1473,7 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt(OEMCrypto_SESSION session, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } if (NO_ERROR != crypto_engine->ValidateKeybox()) { - LOGE("[OEMCrypto_Generic_Enrcypt(): ERROR_KEYBOX_INVALID]"); + LOGE("[OEMCrypto_Generic_Encrypt(): ERROR_KEYBOX_INVALID]"); return OEMCrypto_ERROR_KEYBOX_INVALID; } SessionContext* session_ctx = crypto_engine->FindSession(session); diff --git a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp index a5cc1a5f..2308d5cc 100644 --- a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp @@ -31,23 +31,43 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, uint32_t nonce = 0; uint8_t buffer[1]; size_t size = 0; + provisioning_method = OEMCrypto_GetProvisioningMethod(); + printf("provisioning_method = %s\n", + ProvisioningMethodName(provisioning_method)); uses_keybox = (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_GetKeyData(buffer, &size)); printf("uses_keybox = %s.\n", uses_keybox ? "true" : "false"); - loads_certificate = uses_keybox && (OEMCrypto_ERROR_NOT_IMPLEMENTED != - OEMCrypto_RewrapDeviceRSAKey( - 0, buffer, 0, buffer, 0, &nonce, - buffer, 0, buffer, buffer, &size)); + OEMCrypto_SESSION session; + OEMCryptoResult result = OEMCrypto_OpenSession(&session); + if (result != OEMCrypto_SUCCESS) { + printf("--- ERROR: Could not open session: %d ----\n", result); + } + // If the device uses a keybox, check to see if loading a certificate is + // installed. + if (provisioning_method == OEMCrypto_Keybox) { + loads_certificate = + (OEMCrypto_ERROR_NOT_IMPLEMENTED != + OEMCrypto_RewrapDeviceRSAKey(session, buffer, 0, buffer, 0, &nonce, + buffer, 0, buffer, buffer, &size)); + } else if (provisioning_method == OEMCrypto_OEMCertificate) { + // If the device says it uses Provisioning 3.0, then it should be able to + // load a DRM certificate. These devices must support RewrapDeviceRSAKey30. + loads_certificate = true; + } else { + // Other devices are either broken, or they have a baked in certificate. + loads_certificate = false; + } printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false"); uses_certificate = (OEMCrypto_ERROR_NOT_IMPLEMENTED != - OEMCrypto_GenerateRSASignature(0, buffer, 0, buffer, + OEMCrypto_GenerateRSASignature(session, buffer, 0, buffer, &size, kSign_RSASSA_PSS)); printf("uses_certificate = %s.\n", uses_certificate ? "true" : "false"); generic_crypto = (OEMCrypto_ERROR_NOT_IMPLEMENTED != - OEMCrypto_Generic_Encrypt(0, buffer, 0, buffer, + OEMCrypto_Generic_Encrypt(session, buffer, 0, buffer, OEMCrypto_AES_CBC_128_NO_PADDING, buffer)); printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false"); + OEMCrypto_CloseSession(session); api_version = OEMCrypto_APIVersion(); printf("api_version = %d.\n", api_version); usage_table = OEMCrypto_SupportsUsageTable(); @@ -80,6 +100,9 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, case FORCE_TEST_KEYBOX: printf("FORCE_TEST_KEYBOX: User requested calling InstallKeybox.\n"); break; + case TEST_PROVISION_30: + printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n"); + break; } OEMCrypto_Terminate(); } @@ -95,8 +118,11 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { if (!cast_receiver) FilterOut(&filter, "*CastReceiver*"); if (!usage_table) FilterOut(&filter, "*UsageTable*"); if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*"); + if (provisioning_method + != OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*"); if (api_version < 10) FilterOut(&filter, "*API10*"); if (api_version < 11) FilterOut(&filter, "*API11*"); + if (api_version < 12) FilterOut(&filter, "*API12*"); // Performance tests take a long time. Filter them out if they are not // specifically requested. if (filter.find("Performance") == std::string::npos) { @@ -106,6 +132,27 @@ std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { } void DeviceFeatures::PickDerivedKey() { + if (api_version >= 12) { + switch (provisioning_method) { + case OEMCrypto_OEMCertificate: + derive_key_method = TEST_PROVISION_30; + return; + case OEMCrypto_DrmCertificate: + if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { + derive_key_method = LOAD_TEST_RSA_KEY; + } + return; + case OEMCrypto_Keybox: + // Fall through to api_version < 12 case. + break; + case OEMCrypto_ProvisioningError: + printf( + "ERROR: OEMCrypto_GetProvisioningMethod() returns " + "OEMCrypto_ProvisioningError\n"); + // Then fall through to api_version < 12 case. + break; + } + } if (uses_keybox) { // If device uses a keybox, try to load the test keybox. if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox()) { @@ -145,4 +192,17 @@ void DeviceFeatures::FilterOut(std::string* current_filter, } } +const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method) { + switch (method) { + case OEMCrypto_ProvisioningError: + return "OEMCrypto_ProvisioningError"; + case OEMCrypto_DrmCertificate: + return "OEMCrypto_DrmCertificate"; + case OEMCrypto_Keybox: + return "OEMCrypto_Keybox"; + case OEMCrypto_OEMCertificate: + return "OEMCrypto_OEMCertificate"; + } +} + } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/oec_device_features.h b/libwvdrmengine/oemcrypto/test/oec_device_features.h index 76a3fc03..c1fd2d2d 100644 --- a/libwvdrmengine/oemcrypto/test/oec_device_features.h +++ b/libwvdrmengine/oemcrypto/test/oec_device_features.h @@ -16,6 +16,7 @@ class DeviceFeatures { LOAD_TEST_RSA_KEY, // Call LoadTestRSAKey before deriving keys. EXISTING_TEST_KEYBOX, // Keybox is already the test keybox. FORCE_TEST_KEYBOX, // User requested calling InstallKeybox. + TEST_PROVISION_30, // Device has OEM Certificate installed. }; enum DeriveMethod derive_key_method; @@ -26,6 +27,7 @@ class DeviceFeatures { bool cast_receiver; // Device supports alternate rsa signature padding. bool usage_table; // Device saves usage information. uint32_t api_version; + OEMCrypto_ProvisioningMethod provisioning_method; void Initialize(bool is_cast_receiver, bool force_load_test_keybox); std::string RestrictFilter(const std::string& initial_filter); @@ -37,6 +39,7 @@ class DeviceFeatures { }; extern DeviceFeatures global_features; +const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method); } // namespace wvoec diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp index 26e239b2..f6c0f72f 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -9,8 +9,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -18,13 +20,14 @@ #include #include +#include "OEMCryptoCENC.h" #include "log.h" #include "oec_device_features.h" #include "oec_test_data.h" #include "oemcrypto_key_mock.h" -#include "OEMCryptoCENC.h" #include "string_conversions.h" #include "wv_cdm_constants.h" +#include "wv_cdm_types.h" #include "wv_keybox.h" using namespace std; @@ -69,6 +72,23 @@ void dump_openssl_error() { } } +template +class openssl_ptr { + public: + explicit openssl_ptr(T* p = NULL) : ptr_(p) {} + ~openssl_ptr() { + if (ptr_) func(ptr_); + } + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + bool NotNull() { return ptr_; } + + private: + T* ptr_; + CORE_DISALLOW_COPY_AND_ASSIGN(openssl_ptr); +}; + Session::Session() : open_(false), forced_session_id_(false), @@ -113,8 +133,8 @@ void Session::close() { open_ = false; } -void Session::GenerateNonce(uint32_t* nonce, int* error_counter) { - if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), nonce)) { +void Session::GenerateNonce(int* error_counter) { + if (OEMCrypto_SUCCESS == OEMCrypto_GenerateNonce(session_id(), &nonce_)) { return; } if (error_counter) { @@ -122,7 +142,7 @@ void Session::GenerateNonce(uint32_t* nonce, int* error_counter) { } else { sleep(1); // wait a second, then try again. ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_GenerateNonce(session_id(), nonce)); + OEMCrypto_GenerateNonce(session_id(), &nonce_)); } } @@ -148,7 +168,7 @@ void Session::FillDefaultContext(vector* mac_context, } void Session::GenerateDerivedKeysFromKeybox() { - GenerateNonce(&nonce_); + GenerateNonce(); vector mac_context; vector enc_context; FillDefaultContext(&mac_context, &enc_context); @@ -168,10 +188,11 @@ void Session::GenerateDerivedKeysFromKeybox() { void Session::GenerateDerivedKeysFromSessionKey() { // Uses test certificate. - GenerateNonce(&nonce_); + GenerateNonce(); + vector session_key; vector enc_session_key; PreparePublicKey(); - ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); + ASSERT_TRUE(GenerateRSASessionKey(&session_key, &enc_session_key)); vector mac_context; vector enc_context; FillDefaultContext(&mac_context, &enc_context); @@ -190,14 +211,6 @@ void Session::GenerateDerivedKeysFromSessionKey() { enc_key_ = wvcdm::a2b_hex("CB477D09014D72C9B8DCE76C33EA43B3"); } -void Session::GenerateTestSessionKeys() { - if (global_features.derive_key_method == DeviceFeatures::LOAD_TEST_RSA_KEY) { - GenerateDerivedKeysFromSessionKey(); - } else { - GenerateDerivedKeysFromKeybox(); - } -} - void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) { uint8_t* pst_ptr = NULL; if (pst.length() > 0) { @@ -236,9 +249,11 @@ void Session::VerifyTestKeys() { // control duration and bits stored in network byte order. For printing // we change to host byte order. ASSERT_EQ((htonl_fnc(license_.keys[i].control.duration)), - (htonl_fnc(block.duration))) << "For key " << i; + (htonl_fnc(block.duration))) + << "For key " << i; ASSERT_EQ(htonl_fnc(license_.keys[i].control.control_bits), - htonl_fnc(block.control_bits)) << "For key " << i; + htonl_fnc(block.control_bits)) + << "For key " << i; } } } @@ -278,8 +293,8 @@ void Session::SetKeyId(int index, const string& key_id) { void Session::FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce, const std::string& pst) { - EXPECT_EQ(1, RAND_pseudo_bytes(license_.mac_key_iv, - sizeof(license_.mac_key_iv))); + EXPECT_EQ( + 1, RAND_pseudo_bytes(license_.mac_key_iv, sizeof(license_.mac_key_iv))); EXPECT_EQ(1, RAND_pseudo_bytes(license_.mac_keys, sizeof(license_.mac_keys))); for (unsigned int i = 0; i < num_keys_; i++) { memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength); @@ -292,7 +307,12 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control, sizeof(license_.keys[i].key_iv))); EXPECT_EQ(1, RAND_pseudo_bytes(license_.keys[i].control_iv, sizeof(license_.keys[i].control_iv))); - if (control & wvoec_mock::kControlSecurityPatchLevelMask) { + // For version 12, we require OEMCrypto to handle kc12 for all licenses. + if (global_features.api_version == 12) { + memcpy(license_.keys[i].control.verification, "kc12", 4); + } else if (control & wvoec_mock::kControlSecurityPatchLevelMask) { + // For versions before 12, we require the special key control block only + // when there are newer features present. memcpy(license_.keys[i].control.verification, "kc11", 4); } else if (control & wvoec_mock::kControlRequireAntiRollbackHardware) { memcpy(license_.keys[i].control.verification, "kc10", 4); @@ -316,7 +336,14 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits, 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); + if (global_features.api_version == 12) { + // For version 12, we require OEMCrypto to handle kc12 for all licenses. + memcpy(encrypted_license().keys[i].control.verification, "kc12", 4); + } else { + // For versions before 12, we require the special key control block only + // when there are newer features present. + 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); encrypted_license().keys[i].control.control_bits = htonl(control_bits); @@ -353,8 +380,10 @@ void Session::EncryptAndSign() { FillKeyArray(encrypted_license(), key_array_); } -void Session::EncryptMessage(RSAPrivateKeyMessage* data, - RSAPrivateKeyMessage* encrypted) { +void Session::EncryptProvisioningMessage( + RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted, + const vector& encryption_key) { + ASSERT_EQ(encryption_key.size(), wvcdm::KEY_SIZE); *encrypted = *data; size_t padding = wvcdm::KEY_SIZE - (data->rsa_key_length % wvcdm::KEY_SIZE); memset(data->rsa_key + data->rsa_key_length, static_cast(padding), @@ -363,7 +392,7 @@ void Session::EncryptMessage(RSAPrivateKeyMessage* data, uint8_t iv_buffer[16]; memcpy(iv_buffer, &data->rsa_key_iv[0], wvcdm::KEY_IV_SIZE); AES_KEY aes_key; - AES_set_encrypt_key(&enc_key_[0], 128, &aes_key); + AES_set_encrypt_key(&encryption_key[0], 128, &aes_key); AES_cbc_encrypt(&data->rsa_key[0], &encrypted->rsa_key[0], encrypted->rsa_key_length, &aes_key, iv_buffer, AES_ENCRYPT); } @@ -385,17 +414,15 @@ void Session::ClientSignMessage(const vector& data, &(data.front()), data.size(), &(signature->front()), &md_len); } -// This verifies the signature computed by OEMCrypto using the client mac keys. -// This is used when a device requests a license renewal. It is also used for -// a license request authenticated by a keybox. The first use case is needed -// for devices with a keybox or without. void Session::VerifyClientSignature(size_t data_length) { + // In the real world, a message should be signed by the client and + // verified by the server. This simulates that. vector data(data_length); - for(int i=0; i < data.size(); i++) data[i] = i % 0xFF; + for (int i = 0; i < data.size(); i++) data[i] = i % 0xFF; OEMCryptoResult sts; size_t gen_signature_length = 0; - sts = OEMCrypto_GenerateSignature(session_id(), &data[0], data.size(), - NULL, &gen_signature_length); + sts = OEMCrypto_GenerateSignature(session_id(), &data[0], data.size(), NULL, + &gen_signature_length); ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_EQ(static_cast(32), gen_signature_length); vector gen_signature(gen_signature_length); @@ -516,40 +543,61 @@ void Session::TestDecryptCTR(bool select_key_first, } } +void Session::LoadOEMCert(bool verify_cert) { + vector public_cert; + size_t public_cert_length = 0; + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + OEMCrypto_GetOEMPublicCertificate(session_id(), NULL, + &public_cert_length)); + ASSERT_GT(public_cert_length, 0); + public_cert.resize(public_cert_length); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GetOEMPublicCertificate(session_id(), &public_cert[0], + &public_cert_length)); + // load the cert into rsa_key_. + openssl_ptr bio( + BIO_new_mem_buf(&public_cert[0], public_cert_length)); + ASSERT_TRUE(bio.NotNull()); + openssl_ptr cert( + PEM_read_bio_X509(bio.get(), NULL, 0, NULL)); + ASSERT_TRUE(cert.NotNull()); + openssl_ptr pubkey(X509_get_pubkey(cert.get())); + ASSERT_TRUE(pubkey.NotNull()); + public_rsa_ = EVP_PKEY_get1_RSA(pubkey.get()); + if (!public_rsa_) { + cout << "d2i_RSAPrivateKey failed.\n"; + dump_openssl_error(); + ASSERT_TRUE(NULL != public_rsa_); + } + if (verify_cert) { + vector buffer(80); + X509_NAME* name = X509_get_subject_name(cert.get()); + printf(" OEM Certificate Name: %s\n", + X509_NAME_oneline(name, &buffer[0], buffer.size())); + openssl_ptr store(X509_STORE_new()); + ASSERT_TRUE(store.NotNull()); + openssl_ptr store_ctx( + X509_STORE_CTX_new()); + ASSERT_TRUE(store_ctx.NotNull()); + X509_STORE_CTX_init(store_ctx.get(), store.get(), cert.get(), NULL); + // TODO(fredgc): Verify cert is signed by Google. + int result = X509_verify_cert(store_ctx.get()); + ASSERT_GE(0, result) << " OEM Cert not valid. " + << X509_verify_cert_error_string(store_ctx->error); + if (result == 0) { + printf("Cert not verified: %s.\n", + X509_verify_cert_error_string(store_ctx->error)); + } + } +} + void Session::MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted, size_t message_size, std::vector* signature, uint32_t allowed_schemes, - const vector& rsa_key) { - // Dummy context for testing signature generation. - vector context = wvcdm::a2b_hex( - "0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840" - "8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202" - "fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931" - "b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637" - "38373430350000"); - - OEMCryptoResult sts; - - // Generate signature - size_t gen_signature_length = 0; - sts = OEMCrypto_GenerateSignature(session_id(), &context[0], context.size(), - NULL, &gen_signature_length); - ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); - ASSERT_EQ(static_cast(32), gen_signature_length); - vector gen_signature(gen_signature_length); - sts = OEMCrypto_GenerateSignature(session_id(), &context[0], context.size(), - &gen_signature[0], &gen_signature_length); - ASSERT_EQ(OEMCrypto_SUCCESS, sts); - std::vector expected_signature; - ClientSignMessage(context, &expected_signature); - ASSERT_EQ(expected_signature, gen_signature); - - // Rewrap Canned Response - - // In the real world, the signature above would just have been used to - // contact the certificate provisioning server to get this response. - + const vector& rsa_key, + const vector* encryption_key) { + if (encryption_key == NULL) encryption_key = &enc_key_; struct RSAPrivateKeyMessage message; if (allowed_schemes != kSign_RSASSA_PSS) { uint32_t algorithm_n = htonl(allowed_schemes); @@ -564,7 +612,7 @@ void Session::MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted, EXPECT_EQ(1, RAND_pseudo_bytes(message.rsa_key_iv, wvcdm::KEY_IV_SIZE)); message.nonce = nonce_; - EncryptMessage(&message, encrypted); + EncryptProvisioningMessage(&message, encrypted, *encryption_key); ServerSignBuffer(reinterpret_cast(encrypted), message_size, signature); } @@ -594,6 +642,30 @@ void Session::RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted, wrapped_key->clear(); } } +void Session::RewrapRSAKey30(const struct RSAPrivateKeyMessage& encrypted, + size_t message_size, + const std::vector& encrypted_message_key, + vector* wrapped_key, bool force) { + size_t wrapped_key_length = 0; + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + OEMCrypto_RewrapDeviceRSAKey30( + session_id(), &nonce_, &encrypted_message_key[0], + encrypted_message_key.size(), encrypted.rsa_key, + encrypted.rsa_key_length, encrypted.rsa_key_iv, NULL, + &wrapped_key_length)); + wrapped_key->clear(); + wrapped_key->assign(wrapped_key_length, 0); + OEMCryptoResult sts = OEMCrypto_RewrapDeviceRSAKey30( + session_id(), &nonce_, &encrypted_message_key[0], + encrypted_message_key.size(), encrypted.rsa_key, encrypted.rsa_key_length, + encrypted.rsa_key_iv, &(wrapped_key->front()), &wrapped_key_length); + if (force) { + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + } + if (OEMCrypto_SUCCESS != sts) { + wrapped_key->clear(); + } +} void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) { if (rsa_key == NULL) { @@ -601,35 +673,29 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) { rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048); } uint8_t* p = const_cast(rsa_key); - BIO* bio = BIO_new_mem_buf(p, rsa_key_length); - ASSERT_TRUE(NULL != bio); - PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); - ASSERT_TRUE(NULL != pkcs8_pki); - EVP_PKEY* evp = NULL; - evp = EVP_PKCS82PKEY(pkcs8_pki); - ASSERT_TRUE(NULL != evp); + openssl_ptr bio(BIO_new_mem_buf(p, rsa_key_length)); + ASSERT_TRUE(bio.NotNull()); + openssl_ptr pkcs8_pki( + d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL)); + ASSERT_TRUE(pkcs8_pki.NotNull()); + openssl_ptr evp(EVP_PKCS82PKEY(pkcs8_pki.get())); + ASSERT_TRUE(evp.NotNull()); if (public_rsa_) RSA_free(public_rsa_); - public_rsa_ = EVP_PKEY_get1_RSA(evp); - EVP_PKEY_free(evp); - PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); - BIO_free(bio); + public_rsa_ = EVP_PKEY_get1_RSA(evp.get()); if (!public_rsa_) { cout << "d2i_RSAPrivateKey failed. "; dump_openssl_error(); - ASSERT_TRUE(false); + FAIL() << "Could not parse public RSA key."; } switch (RSA_check_key(public_rsa_)) { case 1: // valid. - ASSERT_TRUE(true); return; case 0: // not valid. - cout << "[rsa key not valid] "; dump_openssl_error(); - ASSERT_TRUE(false); + FAIL() << "[rsa key not valid] "; default: // -1 == check failed. - cout << "[error checking rsa key] "; dump_openssl_error(); - ASSERT_TRUE(false); + FAIL() << "[error checking rsa key] "; } } @@ -693,14 +759,12 @@ void Session::VerifyRSASignature(const vector& message, EXPECT_EQ(static_cast(RSA_size(public_rsa_)), signature_length) << "Signature size is wrong. " << signature_length << ", should be " << RSA_size(public_rsa_) << "\n"; - if (padding_scheme == kSign_RSASSA_PSS) { - EVP_PKEY* pkey = EVP_PKEY_new(); - ASSERT_TRUE(EVP_PKEY_set1_RSA(pkey, public_rsa_) == 1); + openssl_ptr pkey(EVP_PKEY_new()); + ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), public_rsa_)); - const bool ok = VerifyPSSSignature(pkey, &message[0], message.size(), + const bool ok = VerifyPSSSignature(pkey.get(), &message[0], message.size(), signature, signature_length); - EVP_PKEY_free(pkey); EXPECT_TRUE(ok) << "PSS signature check failed."; } else if (padding_scheme == kSign_PKCS1_Block1) { vector padded_digest(signature_length); @@ -717,20 +781,20 @@ void Session::VerifyRSASignature(const vector& message, } } -bool Session::GenerateRSASessionKey(vector* enc_session_key) { +bool Session::GenerateRSASessionKey(vector* session_key, + vector* enc_session_key) { if (!public_rsa_) { cout << "No public RSA key loaded in test code.\n"; return false; } - vector session_key = - wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1"); + *session_key = wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1"); enc_session_key->assign(RSA_size(public_rsa_), 0); - int status = RSA_public_encrypt(session_key.size(), &session_key[0], + int status = RSA_public_encrypt(session_key->size(), &(session_key->front()), &(enc_session_key->front()), public_rsa_, RSA_PKCS1_OAEP_PADDING); int size = static_cast(RSA_size(public_rsa_)); if (status != size) { - cout << "GenerateRSASessionKey error encrypting session key. "; + cout << "GenerateRSASessionKey error encrypting session key.\n"; dump_openssl_error(); return false; } @@ -744,21 +808,6 @@ void Session::InstallRSASessionTestKey(const vector& wrapped_rsa_key) { GenerateDerivedKeysFromSessionKey(); } -void Session::DisallowDeriveKeys() { - GenerateNonce(&nonce_); - vector enc_session_key; - PreparePublicKey(); - ASSERT_TRUE(GenerateRSASessionKey(&enc_session_key)); - vector mac_context; - vector enc_context; - FillDefaultContext(&mac_context, &enc_context); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_DeriveKeysFromSessionKey( - session_id(), &enc_session_key[0], enc_session_key.size(), - &mac_context[0], mac_context.size(), &enc_context[0], - enc_context.size())); -} - void Session::GenerateReport(const std::string& pst, bool expect_success, Session* other) { if (other) { // If other is specified, copy mac keys. diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h index b4ed6c85..2b5fc720 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.h +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -66,10 +66,10 @@ const size_t kTestKeyIdMaxLength = 16; // Most content will use a key id that is 16 bytes long. const int kDefaultKeyIdLength = 16; -const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. -const size_t kMaxPSTLength = 255; // In specification. -const size_t kMaxMessageSize = 8 * 1024; // In specification. -const size_t kMaxDecryptSize = 100 * 1024; // In specification. +const size_t kMaxTestRSAKeyLength = 2000; // Rough estimate. +const size_t kMaxPSTLength = 255; // In specification. +const size_t kMaxMessageSize = 8 * 1024; // In specification. +const size_t kMaxDecryptSize = 100 * 1024; // In specification. typedef struct { uint8_t key_id[kTestKeyIdMaxLength]; @@ -92,6 +92,8 @@ struct MessageData { uint8_t pst[kMaxPSTLength]; }; +// This structure will be signed to simulate a provisioning response from the +// server. struct RSAPrivateKeyMessage { uint8_t rsa_key[kMaxTestRSAKeyLength]; uint8_t rsa_key_iv[wvcdm::KEY_IV_SIZE]; @@ -116,84 +118,175 @@ class Session { Session(); ~Session(); + // Returns the most recently generated nonce. + // Valid after call to GenerateNonce. uint32_t get_nonce() { return nonce_; } - + // Valid after call to open(). uint32_t session_id() { return (uint32_t)session_id_; } - + // Call OEMCrypto_OpenSession, with GTest ASSERTs. void open(); + // Call OEMCrypto_CloseSession, with GTest ASSERTs. void close(); + // Artifically set session id without calling OEMCrypto_OpenSession. This is + // used in core/test/generic_crypto_unittest.cpp. void SetSessionId(uint32_t session_id); - uint32_t GetOecSessionId() { return session_id_; } - void GenerateNonce(uint32_t* nonce, int* error_counter = NULL); + // Generates one nonce. If error_counter is null, this will sleep 1 second + // and try again if a nonce flood has been detected. If error_counter is + // not null, it will be incremented when a nonce flood is detected. + void GenerateNonce(int* error_counter = NULL); + // Fill the vectors with test context which generate known mac and enc keys. void FillDefaultContext(vector* mac_context, vector* enc_context); + // Generate known mac and enc keys using OEMCrypto_GenerateDerivedKeys and + // also fill out enc_key_, mac_key_server_, and mac_key_client_. void GenerateDerivedKeysFromKeybox(); + // Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey + // and also fill out enc_key_, mac_key_server_, and mac_key_client_. void GenerateDerivedKeysFromSessionKey(); - void GenerateTestSessionKeys(); + // Loads and verifies the keys in the message pointed to by message_ptr() + // using OEMCrypto_LoadKeys. This message should have already been created + // by FillSimpleMessage, modified if needed, and then encrypted and signed by + // the server's mac key in EncryptAndSign. void LoadTestKeys(const std::string& pst = "", bool new_mac_keys = true); + // This uses OEMCrypto_QueryKeyControl to check that the keys in OEMCrypto + // have the correct key control data. void VerifyTestKeys(); + // This creates a refresh key or license renewal message, signs it with the + // server's mac key, and calls OEMCrypto_RefreshKeys. void RefreshTestKeys(const size_t key_count, uint32_t control_bits, uint32_t nonce, OEMCryptoResult expected_result); + // This sets the key id in the current message data to the specified string. + // This is used to test with different key id lengths. void SetKeyId(int index, const string& key_id); + // This fills the data structure license_ with key information. This data + // can be modified, and then should be encrypted and signed in EncryptAndSign + // before being loaded in LoadTestKeys. void FillSimpleMessage(uint32_t duration, uint32_t control, uint32_t nonce, const std::string& pst = ""); - + // Like FillSimpleMessage, this fills encrypted_license_ with data. The name + // is a little misleading: the license renewal message is not encrypted, it + // is just signed. The signature is computed in RefreshTestKeys, above. void FillRefreshMessage(size_t key_count, uint32_t control_bits, uint32_t nonce); + // This copies data from license_ to encrypted_license_, and then encrypts + // each field in the key array appropriately. It then signes the buffer with + // the server mac keys. It then fills out the key_array_ so that pointers in + // that array point to the locations in the encrypted message. void EncryptAndSign(); - void EncryptMessage(RSAPrivateKeyMessage* data, - RSAPrivateKeyMessage* encrypted); + // This encrypts an RSAPrivateKeyMessage with encryption_key so that it may be + // loaded with OEMCrypto_RewrapDeviceRSAKey. + void EncryptProvisioningMessage(RSAPrivateKeyMessage* data, + RSAPrivateKeyMessage* encrypted, + const vector& encryption_key); + // Sign the buffer with server's mac key. void ServerSignBuffer(const uint8_t* data, size_t data_length, std::vector* signature); + // Sign the buffer with client's known mac key. Known test keys must be + // installed first. void ClientSignMessage(const vector& data, std::vector* signature); + // This checks the signature generated by OEMCrypto_GenerateSignature against + // that generaged by ClientSignMessage. void VerifyClientSignature(size_t data_length = 400); + // Set the pointers in key_array[*] to point values inside data. This is + // needed to satisfy range checks in OEMCrypto_LoadKeys. void FillKeyArray(const MessageData& data, OEMCrypto_KeyObject* key_array); + // As in FillKeyArray but for the license renewal message passed to + // OEMCrypto_RefreshKeys. void FillRefreshArray(OEMCrypto_KeyRefreshObject* key_array, size_t key_count); + // Encrypt a block of data using CTR mode. void EncryptCTR(const vector& in_buffer, const uint8_t* key, const uint8_t* starting_iv, vector* out_buffer); + // Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption. void TestDecryptCTR(bool select_key_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS, int key_index = 0); + // Calls OEMCrypto_GetOEMPublicCertificate and loads the OEM cert's public + // rsa key into public_rsa_. + void LoadOEMCert(bool verify_cert = false); + // Creates RSAPrivateKeyMessage for the specified rsa_key, encrypts it with + // the specified encryption key, and then signs it with the server's mac key. + // If encryption_key is null, use the session's enc_key_. void MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted, size_t message_size, std::vector* signature, uint32_t allowed_schemes, - const vector& rsa_key); + const vector& rsa_key, + const vector* encryption_key = NULL); + // Calls OEMCrypto_RewrapDeviceRSAKey with the given provisioning response + // message. If force is true, we assert that the key loads successfully. void RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted, size_t message_size, const std::vector& signature, vector* wrapped_key, bool force); + // Loads the specified RSA public key into public_rsa_. If rsa_key is null, + // the default test key is loaded. void PreparePublicKey(const uint8_t* rsa_key = NULL, size_t rsa_key_length = 0); + // Verifies the given signature is from the given message and RSA key, pkey. static bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length); + // Verify that the message was signed by the private key associated with + // |public_rsa_| using the specified padding scheme. void VerifyRSASignature(const vector& message, const uint8_t* signature, size_t signature_length, RSA_Padding_Scheme padding_scheme); - bool GenerateRSASessionKey(vector* enc_session_key); + // Encrypts a known session key with public_rsa_ for use in future calls to + // OEMCrypto_DeriveKeysFromSessionKey or OEMCrypto_RewrapDeviceRSAKey30. + // The unencrypted session key is stored in session_key. + bool GenerateRSASessionKey(vector* session_key, + vector* enc_session_key); + // Calls OEMCrypto_RewrapDeviceRSAKey30 with the given provisioning response + // message. If force is true, we assert that the key loads successfully. + void RewrapRSAKey30(const struct RSAPrivateKeyMessage& encrypted, + size_t message_size, + const std::vector& encrypted_message_key, + vector* wrapped_key, bool force); + // Loads the specified wrapped_rsa_key into OEMCrypto, and then runs + // GenerateDerivedKeysFromSessionKey to install known encryption and mac keys. void InstallRSASessionTestKey(const vector& wrapped_rsa_key); - void DisallowDeriveKeys(); + // Generates a usage report for the specified pst. If expect_success is true, + // the report's signature is verified, and several fields are given sanity + // checks. If other is not null, then the mac keys are copied from other in + // order to verify signatures. void GenerateReport(const std::string& pst, bool expect_success = true, Session* other = 0); + // Returns a pointer to the usage report generated by the previous call to + // GenerateReport. OEMCrypto_PST_Report* pst_report(); + // Creates a signed delete usage table entry message and calls + // OEMCrypto_DeleteUsageEntry on it. void DeleteEntry(const std::string& pst); + // Calls OEMCrypto_ForceDeleteUsageEntry to delete a usage table entry without + // a signed message. void ForceDeleteEntry(const std::string& pst); + // The unencrypted license response or license renewal response. MessageData& license() { return license_; } + // The encrypted license response or license renewal response. MessageData& encrypted_license() { return padded_message_; } + // A pointer to the buffer holding encrypted_license. const uint8_t* message_ptr(); + // An array of key objects for use in LoadKeys. OEMCrypto_KeyObject* key_array() { return key_array_; } + // The last signature generated with the server's mac key. std::vector& signature() { return signature_; } + // Set the number of keys to use in the license(), encrypted_license() + // and key_array(). void set_num_keys(int num_keys) { num_keys_ = num_keys; } + // The current number of keys to use in the license(), encrypted_license() + // and key_array(). int num_keys() const { return num_keys_; } + // Set the size of the buffer used the encrypted license. + // Must be between sizeof(MessageData) and kMaxMessageSize. void set_message_size(size_t size); + // The size of the encrypted message. size_t message_size() { return message_size_; } private: diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index 4e4ba63a..374e54d2 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -90,7 +90,15 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { cout << " OEMCrypto does not support usage tables." << endl; } ASSERT_GE(version, 8u); - ASSERT_LE(version, 11u); + ASSERT_LE(version, 12u); +} + +TEST_F(OEMCryptoClientTest, ProvisioningDeclaredAPI12) { + OEMCrypto_ProvisioningMethod provisioning_method = + OEMCrypto_GetProvisioningMethod(); + cout << " Provisioning method = " + << ProvisioningMethodName(provisioning_method) << endl; + ASSERT_NE(OEMCrypto_ProvisioningError, provisioning_method); } const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value) { @@ -275,31 +283,29 @@ TEST_F(OEMCryptoClientTest, GetRandomLargeBuffer) { TEST_F(OEMCryptoClientTest, GenerateNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - uint32_t nonce; - s.GenerateNonce(&nonce); + s.GenerateNonce(); } TEST_F(OEMCryptoClientTest, GenerateTwoNonces) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - uint32_t nonce1; - uint32_t nonce2; - s.GenerateNonce(&nonce1); - s.GenerateNonce(&nonce2); - ASSERT_TRUE(nonce1 != nonce2); + s.GenerateNonce(); + uint32_t nonce1 = s.get_nonce(); + s.GenerateNonce(); + uint32_t nonce2 = s.get_nonce(); + ASSERT_TRUE(nonce1 != nonce2); // Very unlikely to be equal. } TEST_F(OEMCryptoClientTest, PreventNonceFlood) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); int error_counter = 0; - uint32_t nonce; time_t test_start = time(NULL); // More than 20 nonces per second should generate an error. // To allow for some slop, we actually test for more. const int kFloodCount = 80; for (int i = 0; i < kFloodCount; i++) { - s.GenerateNonce(&nonce, &error_counter); + s.GenerateNonce(&error_counter); } time_t test_end = time(NULL); int valid_counter = kFloodCount - error_counter; @@ -310,14 +316,13 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood) { EXPECT_LE(valid_counter, 20 * (test_end - test_start + 2)); error_counter = 0; sleep(2); // After a pause, we should be able to regenerate nonces. - s.GenerateNonce(&nonce, &error_counter); + s.GenerateNonce(&error_counter); EXPECT_EQ(0, error_counter); } // Prevent a nonce flood even if each nonce is in a different session. TEST_F(OEMCryptoClientTest, PreventNonceFlood2) { int error_counter = 0; - uint32_t nonce; time_t test_start = time(NULL); // More than 20 nonces per second should generate an error. // To allow for some slop, we actually test for more. @@ -325,7 +330,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2) { for (int i = 0; i < kFloodCount; i++) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateNonce(&nonce, &error_counter); + s.GenerateNonce(&error_counter); } time_t test_end = time(NULL); int valid_counter = kFloodCount - error_counter; @@ -338,7 +343,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2) { sleep(2); // After a pause, we should be able to regenerate nonces. Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateNonce(&nonce, &error_counter); + s.GenerateNonce(&error_counter); EXPECT_EQ(0, error_counter); } @@ -349,7 +354,6 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2) { TEST_F(OEMCryptoClientTest, PreventNonceFlood3) { int request_counter = 0; int error_counter = 0; - uint32_t nonce; time_t test_start = time(NULL); // More than 20 nonces per second should generate an error. // To allow for some slop, we actually test for more. @@ -358,7 +362,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3) { ASSERT_NO_FATAL_FAILURE(s[i].open()); for (int j = 0; j < 10; j++) { request_counter++; - s[i].GenerateNonce(&nonce, &error_counter); + s[i].GenerateNonce(&error_counter); } } time_t test_end = time(NULL); @@ -370,7 +374,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3) { EXPECT_LE(valid_counter, 20 * (test_end - test_start + 2)); error_counter = 0; sleep(2); // After a pause, we should be able to regenerate nonces. - s[0].GenerateNonce(&nonce, &error_counter); + s[0].GenerateNonce(&error_counter); EXPECT_EQ(0, error_counter); } @@ -467,7 +471,7 @@ TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) { vector mac_context(kMaxMessageSize); vector enc_context(kMaxMessageSize); // Stripe the data so the two vectors are not identical, and not all zeroes. - for(int i=0; i < kMaxMessageSize; i++) { + for (int i = 0; i < kMaxMessageSize; i++) { mac_context[i] = i % 0x100; enc_context[i] = (3 * i) % 0x100; } @@ -477,6 +481,102 @@ TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) { enc_context.size())); } +class OEMCryptoProv30Test : public OEMCryptoClientTest {}; + +TEST_F(OEMCryptoProv30Test, DeviceClaimsOEMCertificate) { + ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod()); +} + +TEST_F(OEMCryptoProv30Test, OEMCertValid) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + bool kVerify = true; + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert(kVerify)); // Load and verify. +} + +TEST_F(OEMCryptoProv30Test, OEMCertSignature) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + OEMCryptoResult sts; + // Sign a Message + vector data(500); + RAND_pseudo_bytes(&data[0], data.size()); + size_t signature_length = 0; + vector signature(1); + + sts = OEMCrypto_GenerateRSASignature(s.session_id(), &data[0], data.size(), + &signature[0], &signature_length, + kSign_RSASSA_PSS); + + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + ASSERT_NE(static_cast(0), signature_length); + signature.resize(signature_length, 0); + + sts = OEMCrypto_GenerateRSASignature(s.session_id(), &data[0], data.size(), + &signature[0], &signature_length, + kSign_RSASSA_PSS); + + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_NO_FATAL_FAILURE(s.VerifyRSASignature( + data, &signature[0], signature_length, kSign_RSASSA_PSS)); +} + +TEST_F(OEMCryptoProv30Test, OEMCertForbiddenPaddingScheme) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + OEMCryptoResult sts; + // Sign a Message + vector data(500); + RAND_pseudo_bytes(&data[0], data.size()); + size_t signature_length = 0; + vector signature(1); + + sts = OEMCrypto_GenerateRSASignature(s.session_id(), &data[0], data.size(), + &signature[0], &signature_length, + kSign_PKCS1_Block1); + if (OEMCrypto_ERROR_SHORT_BUFFER == sts) { + signature.resize(signature_length, 0); + sts = OEMCrypto_GenerateRSASignature(s.session_id(), &data[0], data.size(), + &signature[0], &signature_length, + kSign_PKCS1_Block1); + } + EXPECT_NE(OEMCrypto_SUCCESS, sts) + << "OEM Cert Signed with forbidden kSign_PKCS1_Block1."; + vector zero(signature_length, 0); + ASSERT_EQ(zero, signature); // signature should not be computed. +} + +TEST_F(OEMCryptoProv30Test, OEMCertSignatureLargeBuffer) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + OEMCryptoResult sts; + // Sign a Message + static size_t kMaxMessageSize = 8 * 1024; + vector data(kMaxMessageSize); + RAND_pseudo_bytes(&data[0], data.size()); + size_t signature_length = 0; + vector signature(1); + + sts = OEMCrypto_GenerateRSASignature(s.session_id(), &data[0], data.size(), + &signature[0], &signature_length, + kSign_RSASSA_PSS); + + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); + ASSERT_NE(static_cast(0), signature_length); + signature.resize(signature_length); + + sts = OEMCrypto_GenerateRSASignature(s.session_id(), &data[0], data.size(), + &signature[0], &signature_length, + kSign_RSASSA_PSS); + + ASSERT_EQ(OEMCrypto_SUCCESS, sts); + ASSERT_NO_FATAL_FAILURE(s.VerifyRSASignature( + data, &signature[0], signature_length, kSign_RSASSA_PSS)); +} + // // AddKey Tests // @@ -484,7 +584,10 @@ TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) { // session keys. class OEMCryptoSessionTests : public OEMCryptoClientTest { protected: - OEMCryptoSessionTests() {} + OEMCryptoSessionTests() + : encoded_rsa_key_(kTestRSAPKCS8PrivateKeyInfo2_2048, + kTestRSAPKCS8PrivateKeyInfo2_2048 + + sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)) {} virtual void SetUp() { OEMCryptoClientTest::SetUp(); @@ -506,6 +609,9 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { case DeviceFeatures::FORCE_TEST_KEYBOX: InstallKeybox(kTestKeybox, true); break; + case DeviceFeatures::TEST_PROVISION_30: + // Can use oem certificate to install test rsa key. + break; default: FAIL() << "Cannot run test without test keybox or RSA key installed."; } @@ -531,6 +637,87 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { // Can return error now, or return error on IsKeyboxValid. } } + + // This makes sure that the derived keys (encryption key and two mac keys) + // are installed in OEMCrypto and in the test session. + void InstallTestSessionKeys(Session* s) { + if (global_features.uses_certificate) { + if (global_features.loads_certificate) { + if (wrapped_rsa_key_.size() == 0) { + // If we don't have a wrapped key yet, create one. + // This wrapped key will be shared by all sessions in the test. + ASSERT_NO_FATAL_FAILURE(CreateWrappedRSAKey(kSign_RSASSA_PSS, true)); + } + // Load the wrapped rsa test key. + ASSERT_NO_FATAL_FAILURE(s->InstallRSASessionTestKey(wrapped_rsa_key_)); + } + // Test RSA key should be loaded. + ASSERT_NO_FATAL_FAILURE(s->GenerateDerivedKeysFromSessionKey()); + } else { // Just uses keybox. Test keybox should already be installed. + ASSERT_NO_FATAL_FAILURE(s->GenerateDerivedKeysFromKeybox()); + } + } + + // If force is true, we assert that the key loads successfully. + void CreateWrappedRSAKey(uint32_t allowed_schemes, bool force) { + switch (global_features.provisioning_method) { + case OEMCrypto_OEMCertificate: + CreateWrappedRSAKeyFromOEMCert(allowed_schemes, force); + break; + case OEMCrypto_Keybox: + CreateWrappedRSAKeyFromKeybox(allowed_schemes, force); + break; + default: + FAIL() << "Cannot generate wrapped RSA key if provision method = " + << wvoec::ProvisioningMethodName( + global_features.provisioning_method); + } + } + + // If force is true, we assert that the key loads successfully. + void CreateWrappedRSAKeyFromKeybox(uint32_t allowed_schemes, bool force) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + // Provisioning request would be signed by the client and verified by the + // server. + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); + struct RSAPrivateKeyMessage encrypted; + std::vector signature; + ASSERT_NO_FATAL_FAILURE(s.MakeRSACertificate(&encrypted, sizeof(encrypted), + &signature, allowed_schemes, + encoded_rsa_key_)); + ASSERT_NO_FATAL_FAILURE(s.RewrapRSAKey( + encrypted, sizeof(encrypted), signature, &wrapped_rsa_key_, force)); + // Verify that the clear key is not contained in the wrapped key. + // It should be encrypted. + ASSERT_EQ(NULL, find(wrapped_rsa_key_, encoded_rsa_key_)); + } + + // If force is true, we assert that the key loads successfully. + void CreateWrappedRSAKeyFromOEMCert(uint32_t allowed_schemes, bool force) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + s.GenerateNonce(); + struct RSAPrivateKeyMessage encrypted; + std::vector signature; + std::vector message_key; + std::vector encrypted_message_key; + s.GenerateRSASessionKey(&message_key, &encrypted_message_key); + ASSERT_NO_FATAL_FAILURE( + s.MakeRSACertificate(&encrypted, sizeof(encrypted), &signature, + allowed_schemes, encoded_rsa_key_, &message_key)); + ASSERT_NO_FATAL_FAILURE(s.RewrapRSAKey30(encrypted, sizeof(encrypted), + encrypted_message_key, + &wrapped_rsa_key_, force)); + // Verify that the clear key is not contained in the wrapped key. + // It should be encrypted. + ASSERT_EQ(NULL, find(wrapped_rsa_key_, encoded_rsa_key_)); + } + + std::vector encoded_rsa_key_; + std::vector wrapped_rsa_key_; }; class OEMCryptoSessionTestKeyboxTest : public OEMCryptoSessionTests {}; @@ -594,7 +781,6 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, BadDataForceKeybox) { TEST_F(OEMCryptoSessionTestKeyboxTest, GenerateSignature) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); // Dummy context for testing signature generation. @@ -626,7 +812,7 @@ TEST_F(OEMCryptoSessionTestKeyboxTest, GenerateSignature) { TEST_F(OEMCryptoSessionTests, LoadKeyNoNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 42)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); @@ -635,17 +821,34 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoNonce) { TEST_F(OEMCryptoSessionTests, LoadKeyWithNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE( s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); } +// This asks for several nonce. This simulates several license requests being +// lost. OEMCrypto is required to keep up to four nonce in the nonce table. +TEST_F(OEMCryptoSessionTests, LoadKeySeveralNonce) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + uint32_t first_nonce = + s.get_nonce(); // Nonce generated when installing keys. + s.GenerateNonce(); // two. + s.GenerateNonce(); // three. + s.GenerateNonce(); // four. + ASSERT_NO_FATAL_FAILURE( + s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, first_nonce)); + ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); + ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); +} + TEST_F(OEMCryptoSessionTests, LoadKeyWithNoMAC) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", false)); @@ -680,7 +883,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithNoMAC) { TEST_F(OEMCryptoSessionTests, ClientSignatureLargeBuffer) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", false)); @@ -711,8 +914,8 @@ TEST_F(OEMCryptoSessionTests, ClientSignatureLargeBuffer) { TEST_F(OEMCryptoSessionTests, LoadKeyLargeBuffer) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); s.set_message_size(kMaxMessageSize); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); @@ -724,7 +927,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyLargeBuffer) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange1) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); vector mac_keys( @@ -742,7 +945,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange1) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange2) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); vector mac_key_iv(s.encrypted_license().mac_key_iv, @@ -760,7 +963,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange2) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange3) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); vector bad_buffer(s.encrypted_license().keys[0].key_id, @@ -778,7 +981,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange3) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange4) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -797,7 +1000,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange4) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange5) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); vector bad_buffer(s.encrypted_license().keys[1].key_iv, @@ -814,8 +1017,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange5) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange6) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -834,8 +1036,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange6) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); vector bad_buffer( @@ -854,7 +1055,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadRange7) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, 42)); // bad nonce. @@ -870,7 +1071,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadNonce) { TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); uint32_t nonce = s.get_nonce(); ASSERT_NO_FATAL_FAILURE( s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, nonce)); @@ -879,7 +1080,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) { ASSERT_NO_FATAL_FAILURE(s.close()); ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, nonce)); // same old nonce. @@ -895,8 +1096,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithRepeatNonce) { TEST_F(OEMCryptoSessionTests, LoadKeyWithBadVerification) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); s.license().keys[1].control.verification[2] = 'Z'; ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -911,11 +1111,10 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithBadVerification) { TEST_F(OEMCryptoSessionTests, LoadKeyWithFutureVerification) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); - // OEMCrypto should reject API12 until the spec has been defined. - memcpy(s.license().keys[1].control.verification, "kc12", 4); + // OEMCrypto should reject API13 until the spec has been defined. + memcpy(s.license().keys[1].control.verification, "kc13", 4); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( s.session_id(), s.message_ptr(), s.message_size(), &s.signature()[0], @@ -927,7 +1126,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyWithFutureVerification) { TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); s.signature()[0] ^= 42; // Bad signature. @@ -941,7 +1140,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeysBadSignature) { TEST_F(OEMCryptoSessionTests, LoadKeysWithNoDerivedKeys) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - // ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys())); + // don't do this: InstallTestSessionKeys(&s). ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); OEMCryptoResult sts = OEMCrypto_LoadKeys( @@ -956,7 +1155,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeysWithNoDerivedKeys) { TEST_F(OEMCryptoSessionTests, LoadKeyNoKeys) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 42)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); int kNoKeys = 0; @@ -970,7 +1169,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeys) { TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE( s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -985,7 +1184,7 @@ TEST_F(OEMCryptoSessionTests, LoadKeyNoKeyWithNonce) { TEST_F(OEMCryptoSessionTests, QueryKeyControl) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE( s.FillSimpleMessage(0, wvoec_mock::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -1012,7 +1211,7 @@ TEST_F(OEMCryptoSessionTests, QueryKeyControl) { TEST_F(OEMCryptoSessionTests, AntiRollbackHardwareRequired) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlRequireAntiRollbackHardware, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -1032,7 +1231,7 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { printf(" Current Patch Level: %u.\n", patch_level); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, patch_level << wvoec_mock::kControlSecurityPatchLevelShift, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -1046,7 +1245,7 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { if (patch_level < 0x3F) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, (patch_level + 1) << wvoec_mock::kControlSecurityPatchLevelShift, 0)); @@ -1062,7 +1261,7 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { if (patch_level > 0) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, (patch_level - 1) << wvoec_mock::kControlSecurityPatchLevelShift, 0)); @@ -1080,8 +1279,8 @@ TEST_F(OEMCryptoSessionTests, CheckMinimumPatchLevel) { TEST_F(OEMCryptoSessionTests, Minimum20Keys) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); s.set_num_keys(kMaxNumKeys); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); @@ -1102,7 +1301,7 @@ class SessionTestDecryptWithHDCP : public OEMCryptoSessionTests, ASSERT_EQ(OEMCrypto_SUCCESS, sts); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, (version << wvoec_mock::kControlHDCPVersionShift) | @@ -1148,27 +1347,27 @@ class SessionTestRefreshKeyTest TEST_P(SessionTestRefreshKeyTest, RefreshWithNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_)); - uint32_t nonce; - s.GenerateNonce(&nonce); + s.GenerateNonce(); + // License renewal message is signed by client and verified by the server. ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); - ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys( - num_keys_, wvoec_mock::kControlNonceEnabled, nonce, OEMCrypto_SUCCESS)); + ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys(num_keys_, + wvoec_mock::kControlNonceEnabled, + s.get_nonce(), OEMCrypto_SUCCESS)); } TEST_P(SessionTestRefreshKeyTest, RefreshNoNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_)); - uint32_t nonce; - s.GenerateNonce(&nonce); + // License renewal message is signed by client and verified by the server. ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); ASSERT_NO_FATAL_FAILURE( s.RefreshTestKeys(num_keys_, 0, 0, OEMCrypto_SUCCESS)); @@ -1177,13 +1376,15 @@ TEST_P(SessionTestRefreshKeyTest, RefreshNoNonce) { TEST_P(SessionTestRefreshKeyTest, RefreshOldNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); - ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( - kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce())); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); + uint32_t nonce = s.get_nonce(); + ASSERT_NO_FATAL_FAILURE( + s.FillSimpleMessage(kDuration, wvoec_mock::kControlNonceEnabled, nonce)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_)); - uint32_t nonce = s.get_nonce(); + // License renewal message is signed by client and verified by the server. ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); + // Tryinng to reuse the same nonce. ASSERT_NO_FATAL_FAILURE( s.RefreshTestKeys(num_keys_, wvoec_mock::kControlNonceEnabled, nonce, OEMCrypto_ERROR_INVALID_NONCE)); @@ -1192,15 +1393,15 @@ TEST_P(SessionTestRefreshKeyTest, RefreshOldNonce) { TEST_P(SessionTestRefreshKeyTest, RefreshBadNonce) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_)); - uint32_t nonce; - s.GenerateNonce(&nonce); + s.GenerateNonce(); + // License renewal message is signed by client and verified by the server. ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); - nonce ^= 42; + uint32_t nonce = s.get_nonce() ^ 42; ASSERT_NO_FATAL_FAILURE( s.RefreshTestKeys(num_keys_, wvoec_mock::kControlNonceEnabled, nonce, OEMCrypto_ERROR_INVALID_NONCE)); @@ -1210,16 +1411,18 @@ TEST_P(SessionTestRefreshKeyTest, RefreshLargeBuffer) { Session s; s.set_message_size(kMaxMessageSize); ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys("", new_mac_keys_)); - uint32_t nonce; - s.GenerateNonce(&nonce); + s.GenerateNonce(); + // License renewal message is signed by client and verified by the server. + // This uses a large buffer for the renewal message. ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature(kMaxMessageSize)); - ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys( - num_keys_, wvoec_mock::kControlNonceEnabled, nonce, OEMCrypto_SUCCESS)); + ASSERT_NO_FATAL_FAILURE(s.RefreshTestKeys(num_keys_, + wvoec_mock::kControlNonceEnabled, + s.get_nonce(), OEMCrypto_SUCCESS)); } // Of only one key control block in the refesh, we update all the keys. @@ -1238,7 +1441,7 @@ INSTANTIATE_TEST_CASE_P(TestRefreshEachKeys, SessionTestRefreshKeyTest, TEST_F(OEMCryptoSessionTests, Decrypt) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); @@ -1248,7 +1451,7 @@ TEST_F(OEMCryptoSessionTests, Decrypt) { TEST_F(OEMCryptoSessionTests, DecryptZeroDuration) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); @@ -1259,9 +1462,9 @@ TEST_F(OEMCryptoSessionTests, SimultaneousDecrypt) { vector s(8); for (int i = 0; i < 8; i++) { ASSERT_NO_FATAL_FAILURE(s[i].open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s[i])); } for (int i = 0; i < 8; i++) { - ASSERT_NO_FATAL_FAILURE(s[i].GenerateTestSessionKeys()); ASSERT_NO_FATAL_FAILURE( s[i].FillSimpleMessage(kLongDuration, 0, s[i].get_nonce())); ASSERT_NO_FATAL_FAILURE(s[i].EncryptAndSign()); @@ -1278,20 +1481,24 @@ TEST_F(OEMCryptoSessionTests, SimultaneousDecrypt) { } } -TEST_F(OEMCryptoSessionTests, SimultaneousDecryptWithLostMessage) { +// This test generates several test keys, as if a license request was lost. +// This is only valid for (obsolete) devices that use a keybox to talk to a +// license server. +TEST_F(OEMCryptoSessionTests, SimultaneousDecryptWithLostMessageKeyboxTest) { vector s(8); for (int i = 0; i < 8; i++) { ASSERT_NO_FATAL_FAILURE(s[i].open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s[i])); } for (int i = 0; i < 8; i++) { - ASSERT_NO_FATAL_FAILURE(s[i].GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(s[i].GenerateDerivedKeysFromKeybox()); ASSERT_NO_FATAL_FAILURE( s[i].FillSimpleMessage(kLongDuration, 0, s[i].get_nonce())); ASSERT_NO_FATAL_FAILURE(s[i].EncryptAndSign()); } // First set of messages are lost. Generate second set. for (int i = 0; i < 8; i++) { - ASSERT_NO_FATAL_FAILURE(s[i].GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(s[i].GenerateDerivedKeysFromKeybox()); ASSERT_NO_FATAL_FAILURE( s[i].FillSimpleMessage(kLongDuration, 0, s[i].get_nonce())); ASSERT_NO_FATAL_FAILURE(s[i].EncryptAndSign()); @@ -1369,8 +1576,8 @@ class OEMCryptoSessionTestsDecryptTests size_t subsample_end = buffer_index + subsample_size_[i].encrypted_size; while (buffer_index < subsample_end) { - size_t size = min(subsample_end - buffer_index, - AES_BLOCK_SIZE - block_offset); + size_t size = + min(subsample_end - buffer_index, AES_BLOCK_SIZE - block_offset); size_t pattern_length = pattern_.encrypt + pattern_.skip; bool skip_block = (pattern_offset >= pattern_.encrypt) && (pattern_length > 0); @@ -1424,7 +1631,7 @@ class OEMCryptoSessionTestsDecryptTests OEMCryptoResult sts; Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0)); memcpy(s.license().keys[0].key_data, &key[0], key.size()); s.license().keys[0].cipher_mode = cipher_mode_; @@ -1525,7 +1732,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, SingleLargeSubsample) { TEST_P(OEMCryptoSessionTestsDecryptTests, PatternPlusOneBlock) { // When the pattern length is 10 blocks, there is a discrepancy between the - // HLS and the CENC standards for samples of size 160*N+16, for N = 1, 2, 3 ... + // HLS and the CENC standards for samples of size 160*N+16, for N = 1, 2, 3... // We require the CENC standard for OEMCrypto, and let a layer above us break // samples into pieces if they wish to use the HLS standard. subsample_size_.push_back(SampleSize(0, 160 + 16)); @@ -1740,7 +1947,7 @@ TEST_P(OEMCryptoSessionTestsDecryptTests, DecryptCENCPerformance) { OEMCryptoResult sts; Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); const time_t TestDuration = 5; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(600, 0, 0)); s.license().keys[0].cipher_mode = GetParam().mode; @@ -1838,7 +2045,7 @@ INSTANTIATE_TEST_CASE_P( TEST_F(OEMCryptoSessionTests, DecryptSecureToClear) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( kDuration, wvoec_mock::kControlObserveDataPath | wvoec_mock::kControlDataPathSecure, @@ -1852,7 +2059,7 @@ TEST_F(OEMCryptoSessionTests, DecryptSecureToClear) { TEST_F(OEMCryptoSessionTests, KeyDuration) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( kDuration, wvoec_mock::kControlNonceEnabled, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -1870,53 +2077,27 @@ TEST_F(OEMCryptoSessionTests, KeyDuration) { // // Certificate Root of Trust Tests // -class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest { - protected: - OEMCryptoLoadsCertificate() - : encoded_rsa_key_(kTestRSAPKCS8PrivateKeyInfo2_2048, - kTestRSAPKCS8PrivateKeyInfo2_2048 + - sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)) {} - - void CreateWrappedRSAKey(vector* wrapped_key, - uint32_t allowed_schemes, bool force) { - Session s; - ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); - struct RSAPrivateKeyMessage encrypted; - std::vector signature; - ASSERT_NO_FATAL_FAILURE(s.MakeRSACertificate(&encrypted, sizeof(encrypted), - &signature, allowed_schemes, - encoded_rsa_key_)); - ASSERT_NO_FATAL_FAILURE(s.RewrapRSAKey(encrypted, sizeof(encrypted), - signature, wrapped_key, force)); - // Verify that the clear key is not contained in the wrapped key. - // It should be encrypted. - ASSERT_EQ(NULL, find(*wrapped_key, encoded_rsa_key_)); - } - - std::vector encoded_rsa_key_; -}; +class OEMCryptoLoadsCertificate : public OEMCryptoSessionTestKeyboxTest {}; TEST_F(OEMCryptoLoadsCertificate, LoadRSASessionKey) { - std::vector wrapped_rsa_key; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); + CreateWrappedRSAKey(kSign_RSASSA_PSS, true); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.InstallRSASessionTestKey(wrapped_rsa_key)); + ASSERT_NO_FATAL_FAILURE(s.InstallRSASessionTestKey(wrapped_rsa_key_)); } TEST_F(OEMCryptoLoadsCertificate, CertificateProvision) { - std::vector wrapped_rsa_key; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); + CreateWrappedRSAKey(kSign_RSASSA_PSS, true); // We should not be able to find the rsa key in the wrapped key. It should // be encrypted. - ASSERT_EQ(NULL, find(wrapped_rsa_key, encoded_rsa_key_)); + ASSERT_EQ(NULL, find(wrapped_rsa_key_, encoded_rsa_key_)); } -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1KeyboxTest) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); struct RSAPrivateKeyMessage encrypted; std::vector signature; ASSERT_NO_FATAL_FAILURE(s.MakeRSACertificate(&encrypted, sizeof(encrypted), @@ -1942,10 +2123,12 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange1) { encrypted.rsa_key_iv, &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2KeyboxTest) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + // Provisioning request would be signed by client and verified by server. + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, sizeof(encrypted), &signature, @@ -1972,10 +2155,12 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange2) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3KeyboxTest) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + // Provisioning request would be signed by client and verified by server. + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, sizeof(encrypted), &signature, @@ -2003,10 +2188,12 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRange3) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadSignature) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadSignatureKeyboxTest) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + // Provisioning request would be signed by client and verified by server. + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, sizeof(encrypted), &signature, @@ -2032,10 +2219,12 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadSignature) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonce) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonceKeyboxTest) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + // Provisioning request would be signed by client and verified by server. + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, sizeof(encrypted), &signature, @@ -2053,7 +2242,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonce) { wrapped_key.clear(); wrapped_key.assign(wrapped_key_length, 0); encrypted.nonce ^= 42; // Almost surely a bad nonce. - ASSERT_NE(OEMCrypto_SUCCESS, + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, OEMCrypto_RewrapDeviceRSAKey( s.session_id(), message_ptr, sizeof(encrypted), &signature[0], signature.size(), &encrypted.nonce, encrypted.rsa_key, @@ -2061,10 +2250,12 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonce) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKey) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKeyKeyboxTest) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + // Provisioning request would be signed by client and verified by server. + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); struct RSAPrivateKeyMessage encrypted; std::vector signature; s.MakeRSACertificate(&encrypted, sizeof(encrypted), &signature, @@ -2090,10 +2281,12 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKey) { &(wrapped_key.front()), &wrapped_key_length)); } -TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBuffer) { +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBufferKeyboxTest) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - s.GenerateDerivedKeysFromKeybox(); + ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromKeybox()); + // Provisioning request would be signed by client and verified by server. + ASSERT_NO_FATAL_FAILURE(s.VerifyClientSignature()); struct LargeRSAPrivateKeyMessage : public RSAPrivateKeyMessage { uint8_t padding[kMaxMessageSize - sizeof(RSAPrivateKeyMessage)]; } encrypted; @@ -2108,26 +2301,85 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBuffer) { ASSERT_EQ(NULL, find(wrapped_key, encoded_rsa_key_)); } +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonceProv30Test) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + s.GenerateNonce(); + uint32_t bad_nonce = s.get_nonce() ^ 42; + struct RSAPrivateKeyMessage encrypted; + std::vector signature; + std::vector message_key; + std::vector encrypted_message_key; + s.GenerateRSASessionKey(&message_key, &encrypted_message_key); + ASSERT_NO_FATAL_FAILURE(s.MakeRSACertificate(&encrypted, sizeof(encrypted), + &signature, kSign_RSASSA_PSS, + encoded_rsa_key_, &message_key)); + size_t wrapped_key_length = 0; + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + OEMCrypto_RewrapDeviceRSAKey30( + s.session_id(), &bad_nonce, &encrypted_message_key[0], + encrypted_message_key.size(), encrypted.rsa_key, + encrypted.rsa_key_length, encrypted.rsa_key_iv, NULL, + &wrapped_key_length)); + vector wrapped_key(wrapped_key_length, 0); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_NONCE, + OEMCrypto_RewrapDeviceRSAKey30( + s.session_id(), &bad_nonce, &encrypted_message_key[0], + encrypted_message_key.size(), encrypted.rsa_key, + encrypted.rsa_key_length, encrypted.rsa_key_iv, &wrapped_key[0], + &wrapped_key_length)); +} + +TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadRSAKeyProv30Test) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + s.GenerateNonce(); + struct RSAPrivateKeyMessage encrypted; + std::vector signature; + std::vector message_key; + std::vector encrypted_message_key; + s.GenerateRSASessionKey(&message_key, &encrypted_message_key); + ASSERT_NO_FATAL_FAILURE(s.MakeRSACertificate(&encrypted, sizeof(encrypted), + &signature, kSign_RSASSA_PSS, + encoded_rsa_key_, &message_key)); + size_t wrapped_key_length = 0; + uint32_t nonce = s.get_nonce(); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + OEMCrypto_RewrapDeviceRSAKey30( + s.session_id(), &nonce, &encrypted_message_key[0], + encrypted_message_key.size(), encrypted.rsa_key, + encrypted.rsa_key_length, encrypted.rsa_key_iv, NULL, + &wrapped_key_length)); + vector wrapped_key(wrapped_key_length, 0); + encrypted.rsa_key[1] ^= 42; // Almost surely a bad key. + ASSERT_EQ(OEMCrypto_ERROR_INVALID_RSA_KEY, + OEMCrypto_RewrapDeviceRSAKey30( + s.session_id(), &nonce, &encrypted_message_key[0], + encrypted_message_key.size(), encrypted.rsa_key, + encrypted.rsa_key_length, encrypted.rsa_key_iv, &wrapped_key[0], + &wrapped_key_length)); +} + TEST_F(OEMCryptoLoadsCertificate, LoadWrappedRSAKey) { OEMCryptoResult sts; - std::vector wrapped_rsa_key; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); + CreateWrappedRSAKey(kSign_RSASSA_PSS, true); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key[0], - wrapped_rsa_key.size()); + sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key_[0], + wrapped_rsa_key_.size()); ASSERT_EQ(OEMCrypto_SUCCESS, sts); } // This tests that a device with a keybox can also decrypt with a cert. // Decrypt for devices that only use a cert are tested in the session tests. TEST_F(OEMCryptoLoadsCertificate, CertificateDecrypt) { - std::vector wrapped_rsa_key; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); + CreateWrappedRSAKey(kSign_RSASSA_PSS, true); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.InstallRSASessionTestKey(wrapped_rsa_key)); + ASSERT_NO_FATAL_FAILURE(s.InstallRSASessionTestKey(wrapped_rsa_key_)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(kDuration, 0, 0)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys()); @@ -2141,12 +2393,11 @@ class OEMCryptoUsesCertificate : public OEMCryptoLoadsCertificate { ASSERT_NO_FATAL_FAILURE(session_.open()); if (global_features.derive_key_method != DeviceFeatures::LOAD_TEST_RSA_KEY) { - std::vector wrapped_rsa_key; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_LoadDeviceRSAKey(session_.session_id(), &wrapped_rsa_key[0], - wrapped_rsa_key.size())); + CreateWrappedRSAKey(kSign_RSASSA_PSS, true); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_LoadDeviceRSAKey(session_.session_id(), + &wrapped_rsa_key_[0], + wrapped_rsa_key_.size())); } } @@ -2171,8 +2422,7 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { double mtime = 0; long count = 0; for (int i = 0; i < 15; i++) { // Only 20 nonce available. - vector wrapped_key; - CreateWrappedRSAKey(&wrapped_key, kSign_RSASSA_PSS, true); + CreateWrappedRSAKey(kSign_RSASSA_PSS, true); count++; gettimeofday(&end_time, NULL); long seconds = end_time.tv_sec - start_time.tv_sec; @@ -2181,9 +2431,8 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { } double provision_time = mtime / count; - std::vector wrapped_rsa_key; Session session; - CreateWrappedRSAKey(&wrapped_rsa_key, kSign_RSASSA_PSS, true); + CreateWrappedRSAKey(kSign_RSASSA_PSS, true); gettimeofday(&start_time, NULL); gettimeofday(&end_time, NULL); mtime = 0; @@ -2191,8 +2440,8 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { do { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key[0], - wrapped_rsa_key.size()); + sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key_[0], + wrapped_rsa_key_.size()); ASSERT_EQ(OEMCrypto_SUCCESS, sts); const size_t size = 50; vector licenseRequest(size); @@ -2219,11 +2468,12 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key[0], - wrapped_rsa_key.size())); + OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key_[0], + wrapped_rsa_key_.size())); + vector session_key; vector enc_session_key; s.PreparePublicKey(); - ASSERT_TRUE(s.GenerateRSASessionKey(&enc_session_key)); + ASSERT_TRUE(s.GenerateRSASessionKey(&session_key, &enc_session_key)); vector mac_context; vector enc_context; s.FillDefaultContext(&mac_context, &enc_context); @@ -2327,9 +2577,10 @@ TEST_F(OEMCryptoUsesCertificate, RSASignatureLargeBuffer) { } TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) { + vector session_key; vector enc_session_key; session_.PreparePublicKey(); - ASSERT_TRUE(session_.GenerateRSASessionKey(&enc_session_key)); + ASSERT_TRUE(session_.GenerateRSASessionKey(&session_key, &enc_session_key)); vector mac_context(kMaxMessageSize); vector enc_context(kMaxMessageSize); // Stripe the data so the two vectors are not identical, and not all zeroes. @@ -2417,16 +2668,28 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { sts = OEMCrypto_LoadDeviceRSAKey(s.session_id(), &wrapped_rsa_key_[0], wrapped_rsa_key_.size()); ASSERT_EQ(OEMCrypto_SUCCESS, sts); - s.DisallowDeriveKeys(); + s.GenerateNonce(); + vector session_key; + vector enc_session_key; + s.PreparePublicKey(); + ASSERT_TRUE(s.GenerateRSASessionKey(&session_key, &enc_session_key)); + vector mac_context; + vector enc_context; + s.FillDefaultContext(&mac_context, &enc_context); + ASSERT_NE(OEMCrypto_SUCCESS, + OEMCrypto_DeriveKeysFromSessionKey( + s.session_id(), &enc_session_key[0], enc_session_key.size(), + &mac_context[0], mac_context.size(), &enc_context[0], + enc_context.size())); } + // If force is true, we assert that the key loads successfully. void LoadWithAllowedSchemes(uint32_t schemes, bool force) { - CreateWrappedRSAKey(&wrapped_rsa_key_, schemes, force); + CreateWrappedRSAKey(schemes, force); key_loaded_ = (wrapped_rsa_key_.size() > 0); if (force) ASSERT_TRUE(key_loaded_); } - std::vector wrapped_rsa_key_; bool key_loaded_; }; @@ -2651,7 +2914,7 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { uint8_t hash[SHA_DIGEST_LENGTH]; if (!SHA1(&message[0], message.size(), hash)) { dump_openssl_error(); - ASSERT_TRUE(false) << "openssl error creating SHA1 hash."; + FAIL() << "openssl error creating SHA1 hash."; } // The application will prepend the digest info to the hash. @@ -3393,7 +3656,7 @@ class GenericCryptoTest : public OEMCryptoSessionTests { virtual void SetUp() { OEMCryptoSessionTests::SetUp(); ASSERT_NO_FATAL_FAILURE(session_.open()); - ASSERT_NO_FATAL_FAILURE(session_.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&session_)); ASSERT_NO_FATAL_FAILURE(MakeFourKeys()); } @@ -3993,7 +4256,7 @@ class UsageTableTest : public GenericCryptoTest { void LoadOfflineLicense(Session& s, const std::string& pst) { ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -4066,7 +4329,7 @@ TEST_P(UsageTableTestWithMAC, OnlineLicense) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, s.get_nonce(), pst)); @@ -4107,7 +4370,7 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, s.get_nonce(), pst)); @@ -4117,7 +4380,7 @@ TEST_F(UsageTableTest, RepeatOnlineLicense) { ASSERT_NO_FATAL_FAILURE(s.close()); Session s2; ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s2.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); uint8_t* pst_ptr = s.encrypted_license().pst; // Trying to reuse a PST is bad. We use session ID for s2, everything else // reused from s. @@ -4136,7 +4399,7 @@ TEST_F(UsageTableTest, OnlineEmptyPST) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, s.get_nonce())); @@ -4153,7 +4416,7 @@ TEST_F(UsageTableTest, EmptyTable) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "no_pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4173,7 +4436,7 @@ TEST_F(UsageTableTest, FiftyEntries) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s1; ASSERT_NO_FATAL_FAILURE(s1.open()); - ASSERT_NO_FATAL_FAILURE(s1.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1)); std::string pst1 = "pst saved"; ASSERT_NO_FATAL_FAILURE(s1.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4186,7 +4449,7 @@ TEST_F(UsageTableTest, FiftyEntries) { vector sessions(ENTRY_COUNT); for (size_t i = 0; i < ENTRY_COUNT; i++) { ASSERT_NO_FATAL_FAILURE(sessions[i].open()); - ASSERT_NO_FATAL_FAILURE(sessions[i].GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i])); std::string pst = "pst "; char c = 'A' + i; pst = pst + c; @@ -4213,7 +4476,7 @@ TEST_F(UsageTableTest, FiftyEntries) { // it shouldn't delete the one attached to an open session. (s1) for (size_t i = 0; i < ENTRY_COUNT; i++) { ASSERT_NO_FATAL_FAILURE(sessions[i].open()); - ASSERT_NO_FATAL_FAILURE(sessions[i].GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i])); std::string pst = "newer pst "; char c = 'A' + i; pst = pst + c; @@ -4247,7 +4510,7 @@ TEST_P(UsageTableTestWithMAC, DeleteUnusedEntry) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "my pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4276,7 +4539,7 @@ TEST_P(UsageTableTestWithMAC, DeleteActiveEntry) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "my pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4306,7 +4569,7 @@ TEST_P(UsageTableTestWithMAC, ForceDeleteActiveEntry) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "my pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4330,7 +4593,7 @@ TEST_P(UsageTableTestWithMAC, DeleteInactiveEntry) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "my pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4361,7 +4624,7 @@ TEST_P(UsageTableTestWithMAC, DeleteEntryBadSignature) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "my pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4398,7 +4661,7 @@ TEST_P(UsageTableTestWithMAC, DeleteEntryWrongSession) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "my pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4436,7 +4699,7 @@ TEST_P(UsageTableTestWithMAC, DeleteEntryBadRange) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); std::string pst = "my pst"; ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, @@ -4698,8 +4961,8 @@ TEST_P(UsageTableTestWithMAC, ReloadOfflineLicense) { Session s; ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst)); - ASSERT_NO_FATAL_FAILURE(s.open()); // Offline license can be reused. - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); // We will reuse the encrypted and signed message, so we don't call // FillSimpleMessage again. ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_)); @@ -4731,7 +4994,7 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) { // Offline license with new mac keys should fail. Session s2; ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s2.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); ASSERT_NO_FATAL_FAILURE(s2.FillSimpleMessage( 0, wvoec_mock::kControlNonceOrEntry, s2.get_nonce(), pst)); ASSERT_NO_FATAL_FAILURE(s2.EncryptAndSign()); @@ -4747,7 +5010,7 @@ TEST_P(UsageTableTestWithMAC, BadReloadOfflineLicense) { // Offline license with same mac keys should still be OK. ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, new_mac_keys_)); s.GenerateReport(pst); EXPECT_EQ(kUnused, s.pst_report()->status); @@ -4759,7 +5022,7 @@ TEST_P(UsageTableTestWithMAC, OfflineBadNonce) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE( s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, 42, pst)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -4778,7 +5041,7 @@ TEST_P(UsageTableTestWithMAC, OfflineEmptyPST) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE( s.FillSimpleMessage(0, wvoec_mock::kControlNonceOrEntry, s.get_nonce())); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -4797,7 +5060,7 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) { ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst)); ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE( s.LoadTestKeys(pst, new_mac_keys_)); // Reload the license ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); // Should be able to decrypt. @@ -4814,7 +5077,7 @@ TEST_P(UsageTableTestWithMAC, DeactivateOfflineLicense) { Session s2; ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s2.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); // Offile license can not be reused if it has been deactivated. uint8_t* pst_ptr = s.encrypted_license().pst; EXPECT_NE( @@ -4836,7 +5099,7 @@ TEST_P(UsageTableTestWithMAC, BadRange) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceOrEntry, s.get_nonce(), pst)); ASSERT_NO_FATAL_FAILURE(s.EncryptAndSign()); @@ -4867,13 +5130,13 @@ TEST_F(UsageTableTest, TimingTest) { sleep(kLongSleep); ASSERT_NO_FATAL_FAILURE(s1.open()); - ASSERT_NO_FATAL_FAILURE(s1.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1)); ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst1, new_mac_keys_)); time_t first_decrypt1 = time(NULL); ASSERT_NO_FATAL_FAILURE(s1.TestDecryptCTR()); ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s2.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); ASSERT_NO_FATAL_FAILURE(s2.LoadTestKeys(pst2, new_mac_keys_)); time_t first_decrypt2 = time(NULL); ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR()); @@ -4903,7 +5166,7 @@ TEST_F(UsageTableTest, TimingTest) { sleep(kLongSleep); time_t third_decrypt = time(NULL); ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s2.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); ASSERT_NO_FATAL_FAILURE(s2.LoadTestKeys(pst2, new_mac_keys_)); ASSERT_NO_FATAL_FAILURE(s2.TestDecryptCTR()); ASSERT_NO_FATAL_FAILURE(s2.close()); @@ -4953,7 +5216,7 @@ TEST_F(UsageTableTest, VerifyUsageTimes) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, s.get_nonce(), pst)); @@ -5063,7 +5326,7 @@ TEST_F(UsageTableTest, LoadSharedLicense) { ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst)); ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.LoadTestKeys(pst, true)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage(0, 0, 0)); // The second set of keys are not loaded. @@ -5086,7 +5349,7 @@ TEST_F(UsageTableTest, PSTLargeBuffer) { ASSERT_NO_FATAL_FAILURE(LoadOfflineLicense(s, pst)); ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE( s.LoadTestKeys(pst, new_mac_keys_)); // Reload the license ASSERT_NO_FATAL_FAILURE(s.TestDecryptCTR()); // Should be able to decrypt. @@ -5103,7 +5366,7 @@ TEST_F(UsageTableTest, PSTLargeBuffer) { Session s2; ASSERT_NO_FATAL_FAILURE(s2.open()); - ASSERT_NO_FATAL_FAILURE(s2.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s2)); // Offile license can not be reused if it has been deactivated. uint8_t* pst_ptr = s.encrypted_license().pst; EXPECT_NE( @@ -5125,7 +5388,7 @@ TEST_F(UsageTableTest, DeleteEntryLargeBuffer) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, s.get_nonce(), pst)); @@ -5155,7 +5418,7 @@ TEST_F(UsageTableTest, ForceDeleteLargeBuffer) { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_UpdateUsageTable()); Session s; ASSERT_NO_FATAL_FAILURE(s.open()); - ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys()); + ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s)); ASSERT_NO_FATAL_FAILURE(s.FillSimpleMessage( 0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired, s.get_nonce(), pst)); diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp index d08f3eb6..58c9ede1 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp @@ -21,21 +21,21 @@ namespace wvoec { // These tests are required for LollyPop Android devices. class OEMCryptoAndroidLMPTest : public ::testing::Test { protected: - virtual void SetUp() { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); - } + virtual void SetUp() { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } - virtual void TearDown() { - OEMCrypto_Terminate(); - } + virtual void TearDown() { OEMCrypto_Terminate(); } }; -// Android devices must have a keybox. +// Android devices must have a keybox, or use provisioning 3.0. TEST_F(OEMCryptoAndroidLMPTest, GetKeyDataImplemented) { uint8_t key_data[256]; size_t key_data_len = sizeof(key_data); - ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_GetKeyData(key_data, &key_data_len)); + if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) { + ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, + OEMCrypto_GetKeyData(key_data, &key_data_len)); + } else { + ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod()); + } } TEST_F(OEMCryptoAndroidLMPTest, MinVersionNumber9) { @@ -48,15 +48,21 @@ TEST_F(OEMCryptoAndroidLMPTest, ValidKeyboxTest) { } TEST_F(OEMCryptoAndroidLMPTest, RewrapDeviceRSAKeyImplemented) { - ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_RewrapDeviceRSAKey(0, NULL, 0, NULL, 0, NULL, - NULL, 0, NULL, NULL, NULL)); + if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) { + ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, + OEMCrypto_RewrapDeviceRSAKey(0, NULL, 0, NULL, 0, NULL, NULL, 0, + NULL, NULL, NULL)); + } else { + ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, + OEMCrypto_RewrapDeviceRSAKey30(0, NULL, NULL, 0, NULL, 0, NULL, + NULL, NULL)); + } } TEST_F(OEMCryptoAndroidLMPTest, RSASignatureImplemented) { - ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_GenerateRSASignature(0, NULL, 0, NULL, NULL, - kSign_RSASSA_PSS)); + ASSERT_NE( + OEMCrypto_ERROR_NOT_IMPLEMENTED, + OEMCrypto_GenerateRSASignature(0, NULL, 0, NULL, NULL, kSign_RSASSA_PSS)); } TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) { @@ -66,12 +72,12 @@ TEST_F(OEMCryptoAndroidLMPTest, GenericCryptoImplemented) { ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, OEMCrypto_Generic_Decrypt(0, NULL, 0, NULL, OEMCrypto_AES_CBC_128_NO_PADDING, NULL)); - ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_Generic_Sign(0, NULL, 0, - OEMCrypto_HMAC_SHA256, NULL, NULL)); - ASSERT_NE(OEMCrypto_ERROR_NOT_IMPLEMENTED, - OEMCrypto_Generic_Verify(0, NULL, 0, - OEMCrypto_HMAC_SHA256, NULL, 0)); + ASSERT_NE( + OEMCrypto_ERROR_NOT_IMPLEMENTED, + OEMCrypto_Generic_Sign(0, NULL, 0, OEMCrypto_HMAC_SHA256, NULL, NULL)); + ASSERT_NE( + OEMCrypto_ERROR_NOT_IMPLEMENTED, + OEMCrypto_Generic_Verify(0, NULL, 0, OEMCrypto_HMAC_SHA256, NULL, 0)); } TEST_F(OEMCryptoAndroidLMPTest, SupportsUsageTable) { @@ -96,7 +102,12 @@ TEST_F(OEMCryptoAndroidMNCTest, MinVersionNumber10) { } TEST_F(OEMCryptoAndroidMNCTest, LoadsTestKeyboxImplemented) { - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox()); + if (OEMCrypto_Keybox == OEMCrypto_GetProvisioningMethod()) { + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox()); + } else { + // Android should use keybox or provisioning 3.0. + ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod()); + } } TEST_F(OEMCryptoAndroidMNCTest, NumberOfSessionsImplemented) { diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp index e989bd90..631fbfc7 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test_main.cpp @@ -1,9 +1,9 @@ #include #include +#include "OEMCryptoCENC.h" #include "log.h" #include "oec_device_features.h" -#include "OEMCryptoCENC.h" #include "properties.h" static void acknowledge_cast() { @@ -20,7 +20,7 @@ int main(int argc, char** argv) { bool is_cast_receiver = false; bool force_load_test_keybox = false; bool filter_tests = true; - for(int i=0; i < argc; i++) { + for (int i = 0; i < argc; i++) { if (!strcmp(argv[i], "--cast")) { acknowledge_cast(); is_cast_receiver = true; @@ -29,15 +29,15 @@ int main(int argc, char** argv) { force_load_test_keybox = true; } if (!strcmp(argv[i], "--no_filter")) { - filter_tests = false; + filter_tests = false; } } wvoec::global_features.Initialize(is_cast_receiver, force_load_test_keybox); // If the user requests --no_filter, we don't change the filter, otherwise, we // filter out features that are not supported. if (filter_tests) { - ::testing::GTEST_FLAG(filter) - = wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter)); + ::testing::GTEST_FLAG(filter) = + wvoec::global_features.RestrictFilter(::testing::GTEST_FLAG(filter)); } return RUN_ALL_TESTS(); }