From 3e525dfdd3604fdeddf8babe702578fc061c51b6 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Tue, 29 Nov 2016 15:18:19 -0800 Subject: [PATCH] OEMCrypto rewrap rsa key 3.0 unit tests Merge from widevine repo of http://go/wvgerrit/21683 This CL adds unit tests for OEMCrypto_RewrapDeviceRSAKey30 for devices that use provisioning 3.0. Change-Id: Ib1a5566de343365b2ae3531f375ac2cc6d86ee53 --- .../oemcrypto/test/oec_session_util.cpp | 24 ++++ .../oemcrypto/test/oec_session_util.h | 8 +- .../oemcrypto/test/oemcrypto_test.cpp | 113 +++++++++++++++++- 3 files changed, 139 insertions(+), 6 deletions(-) diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp index a4103e3f..7359f332 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -630,6 +630,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) { diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h index 652f8359..2b5fc720 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.h +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -215,7 +215,7 @@ class Session { const vector& rsa_key, const vector* encryption_key = NULL); // Calls OEMCrypto_RewrapDeviceRSAKey with the given provisioning response - // message. + // 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); @@ -238,6 +238,12 @@ class Session { // 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); diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index e460bcc7..374e54d2 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -609,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."; } @@ -655,8 +658,24 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { } } - // TODO(fredgc): CreateWrappedRSAKeyFromOEMCert in next CL. + // 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()); @@ -668,8 +687,30 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { 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)); + 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_)); @@ -1691,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)); @@ -2201,7 +2242,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionBadNonceKeyboxTest) { 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, @@ -2260,6 +2301,67 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvisionLargeBufferKeyboxTest) { 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; CreateWrappedRSAKey(kSign_RSASSA_PSS, true); @@ -2581,6 +2683,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { enc_context.size())); } + // If force is true, we assert that the key loads successfully. void LoadWithAllowedSchemes(uint32_t schemes, bool force) { CreateWrappedRSAKey(schemes, force); key_loaded_ = (wrapped_rsa_key_.size() > 0);