From 77752a9600ad90879cc292dfd298bfef9b1b4fc6 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Mon, 2 May 2022 11:39:16 -0700 Subject: [PATCH] Resize OEMCrypto buffer-based results on success. [ Merge of http://go/wvgerrit/152772 ] [ Cherry-pick of http://ag/18126088 ] Within the CDM and OEMCrypto tests, there were a few OEMCrypto function calls where the final size of the output buffers were not being resized. For several of these functions, an initial call is made with zero-length output buffers, expecting OEMCrypto to return ERROR_SHORT_BUFFER; followed by a call with buffers at least as large as specified by OEMCrypto. However, for some operations, OEMCrypto makes an estimate on the final size on the first call, specifying the exact size only after performing the operations. This is the case for the wrapped key returned by OEMCrypto_LoadProvisioning(). The provisioning response contains a padded + encrypted DRM key. OEMCrypto does not know the actual size of the key until decrypted, and the actual DRM key might be smaller. There was a OEMCrypto test for OEMCrypto_BuildInformation() which was enforcing the wrong behaviour. This has been updated. Bug: 230661565 Test: oemcrypto_test Change-Id: Iad297d56ffbb085894641fdf8698ce5fd18edbf2 --- .../cdm/core/src/crypto_session.cpp | 16 +++++--- .../oemcrypto/test/oec_session_util.cpp | 16 ++++++-- .../oemcrypto/test/oemcrypto_test.cpp | 39 ++++++++++--------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index db53e6b2..a2f8c05e 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -1965,6 +1965,11 @@ CdmResponseType CryptoSession::LoadProvisioning( metrics_, oemcrypto_load_provisioning_, status); }); + if (status == OEMCrypto_SUCCESS) { + wrapped_private_key->resize(wrapped_private_key_length); + return NO_ERROR; + } + wrapped_private_key->clear(); return MapOEMCryptoResult(status, LOAD_PROVISIONING_ERROR, "LoadProvisioning"); } @@ -2172,17 +2177,16 @@ bool CryptoSession::GetBuildInformation(SecurityLevel security_level, SecurityLevelToString(security_level)); RETURN_IF_UNINITIALIZED(false); RETURN_IF_NULL(info, false); - - const char* build_information; - WithOecReadLock("GetBuildInformation", [&] { - build_information = OEMCrypto_BuildInformation(security_level); + const char* build_information = WithOecReadLock("GetBuildInformation", [&] { + return OEMCrypto_BuildInformation(security_level); }); if (build_information == nullptr) { LOGE("OEMCrypto_BuildInformation failed: Returned null"); return false; } - - info->assign(build_information); + constexpr size_t kMaxBuildInfoLength = 255; + const size_t info_length = strnlen(build_information, kMaxBuildInfoLength); + info->assign(build_information, info_length); return true; } diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp index 76fea1de..86a36e9c 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -234,6 +234,9 @@ RoundTrip:: // We need to fill in core request and verify signature only for calls other // than OEMCryptoMemory buffer overflow test. Any test other than buffer // overflow will pass true. + if (result == OEMCrypto_SUCCESS) { + gen_signature.resize(gen_signature_length); + } if (!verify_request || result != OEMCrypto_SUCCESS) return result; if (global_features.api_version >= kCoreMessagesAPI) { std::string core_message(reinterpret_cast(data.data()), @@ -454,11 +457,14 @@ OEMCryptoResult ProvisioningRoundTrip::LoadResponse(Session* session) { sizeof(response_data_)); } size_t wrapped_key_length = 0; - const OEMCryptoResult sts = LoadResponseNoRetry(session, &wrapped_key_length); + OEMCryptoResult sts = LoadResponseNoRetry(session, &wrapped_key_length); if (sts != OEMCrypto_ERROR_SHORT_BUFFER) return sts; - wrapped_rsa_key_.clear(); wrapped_rsa_key_.assign(wrapped_key_length, 0); - return LoadResponseNoRetry(session, &wrapped_key_length); + sts = LoadResponseNoRetry(session, &wrapped_key_length); + if (sts == OEMCrypto_SUCCESS) { + wrapped_rsa_key_.resize(wrapped_key_length); + } + return sts; } #ifdef TEST_OEMCRYPTO_V15 @@ -1458,6 +1464,7 @@ void Session::LoadOEMCert(bool verify_cert) { public_cert.resize(public_cert_length); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetOEMPublicCertificate( public_cert.data(), &public_cert_length)); + public_cert.resize(public_cert_length); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadOEMPrivateKey(session_id())); // The cert is a PKCS7 signed data type. First, parse it into an OpenSSL @@ -1685,6 +1692,8 @@ void Session::UpdateUsageEntry(std::vector* header_buffer) { OEMCrypto_UpdateUsageEntry( session_id(), header_buffer->data(), &header_buffer_length, encrypted_usage_entry_.data(), &entry_buffer_length)); + header_buffer->resize(header_buffer_length); + encrypted_usage_entry_.resize(entry_buffer_length); } void Session::LoadUsageEntry(uint32_t index, const vector& buffer) { @@ -1731,6 +1740,7 @@ void Session::GenerateReport(const std::string& pst, if (expected_result != OEMCrypto_SUCCESS) { return; } + pst_report_buffer_.resize(length); EXPECT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length); vector computed_signature(SHA_DIGEST_LENGTH); key_deriver_.ClientSignPstReport(pst_report_buffer_, &computed_signature); diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index fbb5a7d0..ec8d8aa1 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -275,7 +275,7 @@ TEST_F(OEMCryptoClientTest, VersionNumber) { cout << " Resource Rating Tier: " << tier << endl; const char* build_info = OEMCrypto_BuildInformation(); ASSERT_NE(nullptr, build_info); - ASSERT_TRUE(strnlen(build_info, 256) <= 256) + ASSERT_TRUE(strnlen(build_info, 256) < 256) << "BuildInformation should be a short printable string."; cout << " BuildInformation: " << build_info << endl; } @@ -933,9 +933,9 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) { uint8_t dev_id[128] = {0}; size_t dev_id_len = 128; sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len); + ASSERT_EQ(OEMCrypto_SUCCESS, sts); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id, dev_id_len) << " len = " << dev_id_len << endl; - ASSERT_EQ(OEMCrypto_SUCCESS, sts); } TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetDeviceIdForHugeIdLength) { @@ -1078,7 +1078,6 @@ TEST_F(OEMCryptoProv30Test, GetDeviceId) { dev_id.resize(dev_id_len); cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id) << " len = " << dev_id_len << endl; - ASSERT_EQ(OEMCrypto_SUCCESS, sts); } // The OEM certificate must be valid. @@ -1221,6 +1220,7 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { &header_buffer_length); if (expect_success) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); + encrypted_usage_header_.resize(header_buffer_length); } else { ASSERT_NE(OEMCrypto_SUCCESS, sts); } @@ -5127,11 +5127,10 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { &signature_length, kSign_RSASSA_PSS); ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_NE(static_cast(0), signature_length); - uint8_t* signature = new uint8_t[signature_length]; - sts = OEMCrypto_GenerateRSASignature(s.session_id(), licenseRequest.data(), - licenseRequest.size(), signature, - &signature_length, kSign_RSASSA_PSS); - delete[] signature; + std::vector signature(signature_length, 0); + sts = OEMCrypto_GenerateRSASignature( + s.session_id(), licenseRequest.data(), licenseRequest.size(), + signature.data(), &signature_length, kSign_RSASSA_PSS); ASSERT_EQ(OEMCrypto_SUCCESS, sts); count++; } @@ -5312,7 +5311,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { EXPECT_NE(OEMCrypto_SUCCESS, sts) << "Signed with forbidden padding scheme=" << (int)scheme << ", size=" << (int)size; - vector zero(signature_length, 0); + const vector zero(signature.size(), 0); ASSERT_EQ(zero, signature); // signature should not be computed. } @@ -5334,19 +5333,19 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_NE(static_cast(0), signature_length); - uint8_t* signature = new uint8_t[signature_length]; - sts = OEMCrypto_GenerateRSASignature(s.session_id(), licenseRequest.data(), - licenseRequest.size(), signature, - &signature_length, scheme); + std::vector signature(signature_length, 0); + sts = OEMCrypto_GenerateRSASignature( + s.session_id(), licenseRequest.data(), licenseRequest.size(), + signature.data(), &signature_length, scheme); ASSERT_EQ(OEMCrypto_SUCCESS, sts) << "Failed to sign with padding scheme=" << (int)scheme - << ", size=" << (int)size; + << ", size=" << size; + signature.resize(signature_length); ASSERT_NO_FATAL_FAILURE( s.PreparePublicKey(encoded_rsa_key_.data(), encoded_rsa_key_.size())); - ASSERT_NO_FATAL_FAILURE(s.VerifyRSASignature(licenseRequest, signature, - signature_length, scheme)); - delete[] signature; + ASSERT_NO_FATAL_FAILURE(s.VerifyRSASignature( + licenseRequest, signature.data(), signature_length, scheme)); } void DisallowDeriveKeys() { @@ -5691,7 +5690,8 @@ class OEMCryptoCastReceiverTest : public OEMCryptoLoadsCertificateAlternates { ASSERT_EQ(OEMCrypto_SUCCESS, sts) << "Failed to sign with padding scheme=" << (int)scheme - << ", size=" << (int)message.size(); + << ", size=" << message.size(); + signature.resize(signature_length); ASSERT_NO_FATAL_FAILURE( s.PreparePublicKey(encoded_rsa_key_.data(), encoded_rsa_key_.size())); @@ -8360,6 +8360,9 @@ class OEMCryptoUsageTableDefragTest : public OEMCryptoUsageTableTest { new_size, encrypted_usage_header_.data(), &header_buffer_length); // For the second call, we always demand the expected result. ASSERT_EQ(expected_result, sts); + if (sts == OEMCrypto_SUCCESS) { + encrypted_usage_header_.resize(header_buffer_length); + } } };