diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index ca9c3c94..c70ec259 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -1201,6 +1201,8 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, * @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE * @retval OEMCrypto_ERROR_SESSION_LOST_STATE * @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED + * @retval OEMCrypto_ERROR_INVALID_KEY if the session's private key is not a + * DRM key. * * @buffer_size * OEMCrypto shall support message sizes as described in the section diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp index 7a131d83..fb62985c 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp @@ -11,16 +11,32 @@ using ::testing::Range; namespace wvoec { -// The alternate padding is only required for cast receivers, but if a device -// does load an alternate certificate, it should NOT use it for generating -// a license request signature. +/** If a device can load a private key with the alternate padding schemes, it + * should support signing with the alternate scheme. */ TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) { - // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for - // provisioning 4. Disabled here temporarily. - if (!global_features.loads_certificate || - global_features.provisioning_method == OEMCrypto_BootCertificateChain) { - GTEST_SKIP() << "Test for non Prov 4.0 devices only."; + // Try to load an RSA key with alternative padding schemes. This signing + // scheme is used by cast receivers. + LoadCastCertificateKey(false); + // If the device is a cast receiver, then this scheme is required. + if (global_features.cast_receiver) { + ASSERT_TRUE(key_loaded_); + // A signature with a valid size should succeed. + TestSignature(kSign_PKCS1_Block1, 83); + TestSignature(kSign_PKCS1_Block1, 50); } + // If the key loaded with no error, then we will verify that it is not used + // for forbidden padding schemes. This should be tested for both devices that + // are cast receivers and devices that are not. + if (key_loaded_) { + // A signature with padding that is too big should fail. + DisallowForbiddenPaddingDRMKey(kSign_PKCS1_Block1, 84); // too big. + } +} + +/** The alternate padding is only required for cast receivers, but if a device + * does load an alternate certificate, it should NOT be used to as a DRM cert + * key. */ +TEST_F(OEMCryptoLoadsCertificateAlternates, ForbidUseAsDRMCert) { // Try to load an RSA key with alternative padding schemes. This signing // scheme is used by cast receivers. LoadCastCertificateKey(false); @@ -34,13 +50,39 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, TestSignaturePKCS1) { // The other padding scheme should fail. DisallowForbiddenPaddingDRMKey(kSign_RSASSA_PSS, 83); DisallowDeriveKeys(); - if (global_features.cast_receiver) { - // A signature with a valid size should succeed. - TestSignature(kSign_PKCS1_Block1, 83); - TestSignature(kSign_PKCS1_Block1, 50); - } - // A signature with padding that is too big should fail. - DisallowForbiddenPaddingDRMKey(kSign_PKCS1_Block1, 84); // too big. + } +} + +/** A Cast receiver certificate private key cannot be used with the function + * PrepAndSignLicenseRequest. + */ +TEST_F(OEMCryptoLoadsCertificateAlternates, ForbidPrepAndSign) { + // Try to load an RSA key with alternative padding schemes. This signing + // scheme is used by cast receivers. + LoadCastCertificateKey(false); + // If the device is a cast receiver, then this scheme is required. + if (global_features.cast_receiver) { + ASSERT_TRUE(key_loaded_); + } + // If the key loaded with no error, then we will verify that it is not used + // for forbidden padding schemes. + if (key_loaded_) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_)); + s.GenerateNonce(); + + size_t core_message_length = 100; + std::vector message(128, 0); + std::vector signature(256, 0); + size_t signature_length = signature.size(); + + OEMCryptoResult result = OEMCrypto_PrepAndSignLicenseRequest( + s.session_id(), message.data(), message.size(), &core_message_length, + signature.data(), &signature_length); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_KEY, result); + const vector zero(signature.size(), 0); + ASSERT_EQ(signature, zero); // Signature should not have been computed. } } diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp index 2763c3c2..2cdab5a9 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp @@ -119,36 +119,24 @@ TEST_F(OEMCryptoProv30Test, OEMCertValid) { ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert(kVerify)); // Load and verify. } -// This verifies that the OEM Certificate cannot be used for other RSA padding -// schemes. Those schemes should only be used by cast receiver certificates. -TEST_F(OEMCryptoProv30Test, OEMCertForbiddenPaddingScheme) { +/** This verifies that the OEM Certificate cannot be used with + * GenerateRSASignature. + */ +TEST_F(OEMCryptoProv30Test, OEMCertForbidGenerateRSASignature1) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); - OEMCryptoResult sts; - // Sign a Message - vector data(500); - GetRandBytes(data.data(), data.size()); - size_t signature_length = 0; - // We need a size one vector to pass as a pointer. - vector signature(1, 0); - vector zero(1, 0); + DisallowForbiddenPadding(s.session_id(), kSign_PKCS1_Block1, 80); +} - sts = OEMCrypto_GenerateRSASignature(s.session_id(), data.data(), data.size(), - signature.data(), &signature_length, - kSign_PKCS1_Block1); - if (OEMCrypto_ERROR_SHORT_BUFFER == sts) { - // The OEMCrypto could complain about buffer length first, so let's - // resize and check if it's writing to the signature again. - signature.resize(signature_length, 0); - zero.resize(signature_length, 0); - sts = OEMCrypto_GenerateRSASignature(s.session_id(), data.data(), - data.size(), signature.data(), - &signature_length, kSign_PKCS1_Block1); - } - EXPECT_NE(OEMCrypto_SUCCESS, sts) - << "OEM Cert Signed with forbidden kSign_PKCS1_Block1."; - ASSERT_EQ(zero, signature); // signature should not be computed. +/** This verifies that the OEM Certificate cannot be used with + * GenerateRSASignature. + */ +TEST_F(OEMCryptoProv30Test, OEMCertForbidGenerateRSASignature2) { + Session s; + ASSERT_NO_FATAL_FAILURE(s.open()); + ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert()); + DisallowForbiddenPadding(s.session_id(), kSign_RSASSA_PSS, 80); } // Calling OEMCrypto_GetOEMPublicCertificate should not change the session's @@ -186,6 +174,46 @@ TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) { ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); } +/** This verifies that the OEM Certificate cannot be used with + * GenerateRSASignature. + */ +TEST_F(OEMCryptoProv40Test, OEMCertForbidGenerateRSASignature1) { + // Create an OEM Cert and save it for later. + Session s1; + ASSERT_NO_FATAL_FAILURE(s1.open()); + ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s1)); + ASSERT_EQ(s1.IsPublicKeySet(), true); + s1.close(); + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_InstallOemPrivateKey( + s2.session_id(), oem_key_type_, + reinterpret_cast(wrapped_oem_key_.data()), + wrapped_oem_key_.size())); + DisallowForbiddenPadding(s2.session_id(), kSign_PKCS1_Block1, 80); +} + +/** This verifies that the OEM Certificate cannot be used with + * GenerateRSASignature. + */ +TEST_F(OEMCryptoProv40Test, OEMCertForbidGenerateRSASignature2) { + // Create an OEM Cert and save it for later. + Session s1; + ASSERT_NO_FATAL_FAILURE(s1.open()); + ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s1)); + ASSERT_EQ(s1.IsPublicKeySet(), true); + s1.close(); + Session s2; + ASSERT_NO_FATAL_FAILURE(s2.open()); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_InstallOemPrivateKey( + s2.session_id(), oem_key_type_, + reinterpret_cast(wrapped_oem_key_.data()), + wrapped_oem_key_.size())); + DisallowForbiddenPadding(s2.session_id(), kSign_RSASSA_PSS, 80); +} + // This verifies that the device really does claim to have BCC. // It should be filtered out for devices that have a keybox or factory OEM // cert. @@ -654,6 +682,16 @@ TEST_P(OEMCryptoProv40CastTest, ProvisionCastWorks) { INSTANTIATE_TEST_SUITE_P(Prov4CastProvisioningBasic, OEMCryptoProv40CastTest, testing::Values(true, false)); +// Verify that you cannot use GenerateRSASignature with a normal DRM Cert. +// that function needs a cast cert. +TEST_F(OEMCryptoLoadsCertificate, ForbidRSASignatureForDRMKey1) { + DisallowForbiddenPadding(session_.session_id(), kSign_RSASSA_PSS, 80); +} + +TEST_F(OEMCryptoLoadsCertificate, ForbidRSASignatureForDRMKey2) { + DisallowForbiddenPadding(session_.session_id(), kSign_PKCS1_Block1, 80); +} + TEST_F(OEMCryptoLoadsCertificate, PrepAndSignLicenseRequestCounterAPI18) { // TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for // provisioning 4. Disabled here temporarily. diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_security_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_security_test.cpp index 4b34be39..48cd73b1 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_security_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_security_test.cpp @@ -812,6 +812,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, sts = OEMCrypto_GenerateRSASignature(s.session_id(), message_buffer.data(), message_buffer.size(), nullptr, &signature_length, kSign_PKCS1_Block1); + if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) return; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_NE(static_cast(0), signature_length); vector signature(signature_length);