Sync oemcrypto files from cdm udc-dev to Android
Changes included in this CL: 166806: Update OEMCrypto_GetDeviceInformation() | https://widevine-internal-review.googlesource.com/c/cdm/+/166806 166808: Update Android L3 after OEMCrypto_GetDeviceInformation() signature changes | https://widevine-internal-review.googlesource.com/c/cdm/+/166808 166809: Decode device info and write it to CSR payload | https://widevine-internal-review.googlesource.com/c/cdm/+/166809 167158: Fix Android include path and copy_files | https://widevine-internal-review.googlesource.com/c/cdm/+/167158 167159: Fix common typos and use inclusive language suggested by Android linter | https://widevine-internal-review.googlesource.com/c/cdm/+/167159 165618: Explicitly state python3 where needed. | https://widevine-internal-review.googlesource.com/c/cdm/+/165618 166757: Update Android.bp for Android | https://widevine-internal-review.googlesource.com/c/cdm/+/166757 164993: Refactor basic oemcrypto unit tests | https://widevine-internal-review.googlesource.com/c/cdm/+/164993 164978: Update OEMCrypto Unit Test Docs | https://widevine-internal-review.googlesource.com/c/cdm/+/164978 166941: Update make files for OEMCrypto | https://widevine-internal-review.googlesource.com/c/cdm/+/166941 165279: Refactor license unit tests | https://widevine-internal-review.googlesource.com/c/cdm/+/165279 165318: Refactor provisioning unit tests | https://widevine-internal-review.googlesource.com/c/cdm/+/165318 164800: Add extra check for renew on license load unit test | https://widevine-internal-review.googlesource.com/c/cdm/+/164800 165860: Remove duplicate definition of MaybeHex() | https://widevine-internal-review.googlesource.com/c/cdm/+/165860 164889: Updated CoreCommonRequestFromMessage and fix test | https://widevine-internal-review.googlesource.com/c/cdm/+/164889 164967: Add OPK pre-hook and post-hook error codes | https://widevine-internal-review.googlesource.com/c/cdm/+/164967 165140: Add hidden device_id_length to v18 provisioning message | https://widevine-internal-review.googlesource.com/c/cdm/+/165140 165204: Fix memory leak in oemcrypto test | https://widevine-internal-review.googlesource.com/c/cdm/+/165204 165958: Fix oemcrypto_generic_verify_fuzz mutator signature offset | https://widevine-internal-review.googlesource.com/c/cdm/+/165958 166037: Support SHA-256 in OEMCrypto Session Util | https://widevine-internal-review.googlesource.com/c/cdm/+/166037 Test: Run GtsMediaTests on Pixel 7 Bug: 270612144 Change-Id: Iff0820a2de7d043a820470a130af65b0dcadb759
This commit is contained in:
627
libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp
Normal file
627
libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp
Normal file
@@ -0,0 +1,627 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
//
|
||||
|
||||
#include "oemcrypto_provisioning_test.h"
|
||||
|
||||
#include "log.h"
|
||||
#include "oemcrypto_basic_test.h"
|
||||
#include "oemcrypto_resource_test.h"
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
#include "platform.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
/// @addtogroup provision
|
||||
/// @{
|
||||
|
||||
// This test is used to print the device ID to stdout.
|
||||
TEST_F(OEMCryptoKeyboxTest, NormalGetDeviceId) {
|
||||
OEMCryptoResult sts;
|
||||
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;
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoKeyboxTest, GetDeviceIdShortBuffer) {
|
||||
OEMCryptoResult sts;
|
||||
uint8_t dev_id[128];
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
dev_id[i] = 0x55;
|
||||
}
|
||||
dev_id[127] = '\0';
|
||||
size_t dev_id_len = 0;
|
||||
sts = OEMCrypto_GetDeviceID(dev_id, &dev_id_len);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||
// On short buffer error, function should return minimum buffer length
|
||||
ASSERT_GT(dev_id_len, 0u);
|
||||
// Should also return short buffer if passed a zero length and a null buffer.
|
||||
dev_id_len = 0;
|
||||
sts = OEMCrypto_GetDeviceID(nullptr, &dev_id_len);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||
// On short buffer error, function should return minimum buffer length
|
||||
ASSERT_GT(dev_id_len, 0u);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) {
|
||||
OEMCryptoResult sts;
|
||||
uint8_t key_data[256];
|
||||
size_t key_data_len = sizeof(key_data);
|
||||
sts = OEMCrypto_GetKeyData(key_data, &key_data_len);
|
||||
|
||||
uint32_t* data = reinterpret_cast<uint32_t*>(key_data);
|
||||
printf(" NormalGetKeyData: system_id = %u = 0x%04X, version=%u\n",
|
||||
htonl(data[1]), htonl(data[1]), htonl(data[0]));
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoKeyboxTest, GetKeyDataNullPointer) {
|
||||
OEMCryptoResult sts;
|
||||
uint8_t key_data[256];
|
||||
sts = OEMCrypto_GetKeyData(key_data, nullptr);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
|
||||
// This test makes sure the installed keybox is valid. It doesn't really check
|
||||
// that it is a production keybox. That must be done by an integration test.
|
||||
TEST_F(OEMCryptoKeyboxTest, ProductionKeyboxValid) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
|
||||
}
|
||||
|
||||
// This tests GenerateDerivedKeys with an 8k context.
|
||||
TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
const size_t max_size = GetResourceValue(kLargeMessageSize);
|
||||
vector<uint8_t> mac_context(max_size);
|
||||
vector<uint8_t> enc_context(max_size);
|
||||
// Stripe the data so the two vectors are not identical, and not all zeroes.
|
||||
for (size_t i = 0; i < max_size; i++) {
|
||||
mac_context[i] = i % 0x100;
|
||||
enc_context[i] = (3 * i) % 0x100;
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_GenerateDerivedKeys(
|
||||
s.session_id(), mac_context.data(), mac_context.size(),
|
||||
enc_context.data(), enc_context.size()));
|
||||
}
|
||||
|
||||
// This verifies that the device really does claim to have a certificate.
|
||||
// It should be filtered out for devices that have a keybox.
|
||||
TEST_F(OEMCryptoProv30Test, DeviceClaimsOEMCertificate) {
|
||||
ASSERT_EQ(OEMCrypto_OEMCertificate, OEMCrypto_GetProvisioningMethod());
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoProv30Test, GetDeviceId) {
|
||||
OEMCryptoResult sts;
|
||||
std::vector<uint8_t> dev_id(128, 0);
|
||||
size_t dev_id_len = dev_id.size();
|
||||
sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len);
|
||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
ASSERT_GT(dev_id_len, 0u);
|
||||
dev_id.resize(dev_id_len);
|
||||
sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len);
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
dev_id.resize(dev_id_len);
|
||||
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
||||
<< " len = " << dev_id_len << endl;
|
||||
}
|
||||
|
||||
// The OEM certificate must be valid.
|
||||
TEST_F(OEMCryptoProv30Test, CertValidAPI15) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxOrOEMCertValid());
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
// 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) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadOEMCert());
|
||||
OEMCryptoResult sts;
|
||||
// Sign a Message
|
||||
vector<uint8_t> data(500);
|
||||
GetRandBytes(data.data(), data.size());
|
||||
size_t signature_length = 0;
|
||||
// We need a size one vector to pass as a pointer.
|
||||
vector<uint8_t> signature(1, 0);
|
||||
vector<uint8_t> zero(1, 0);
|
||||
|
||||
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.
|
||||
}
|
||||
|
||||
// Calling OEMCrypto_GetOEMPublicCertificate should not change the session's
|
||||
// private key.
|
||||
TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) {
|
||||
if (wrapped_drm_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(CreateWrappedDRMKey());
|
||||
}
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
// Install the DRM Cert's RSA key.
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetTestRsaPublicKey());
|
||||
// Request the OEM Cert. -- This should NOT load the OEM Private key.
|
||||
vector<uint8_t> public_cert;
|
||||
size_t public_cert_length = 0;
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
|
||||
OEMCrypto_GetOEMPublicCertificate(nullptr, &public_cert_length));
|
||||
ASSERT_LT(0u, public_cert_length);
|
||||
public_cert.resize(public_cert_length);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_GetOEMPublicCertificate(
|
||||
public_cert.data(), &public_cert_length));
|
||||
// Derive keys from the session key -- this should use the DRM Cert's key.
|
||||
// It should NOT use the OEM Private key because that key should not have
|
||||
// been loaded.
|
||||
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromSessionKey());
|
||||
// Now fill a message and try to load it.
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
license_messages.set_control(0);
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(license_messages.EncryptAndSignResponse());
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse());
|
||||
}
|
||||
|
||||
// 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.
|
||||
TEST_F(OEMCryptoProv40Test, DeviceClaimsBootCertificateChain) {
|
||||
ASSERT_EQ(OEMCrypto_GetProvisioningMethod(), OEMCrypto_BootCertificateChain);
|
||||
}
|
||||
|
||||
// Verifies that short buffer error returns when the buffer is short.
|
||||
TEST_F(OEMCryptoProv40Test, GetBootCertificateChainShortBuffer) {
|
||||
std::vector<uint8_t> bcc;
|
||||
size_t bcc_size = 0;
|
||||
std::vector<uint8_t> additional_signature;
|
||||
size_t additional_signature_size = 0;
|
||||
ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size,
|
||||
additional_signature.data(),
|
||||
&additional_signature_size),
|
||||
OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
ASSERT_NE(bcc_size, 0uL);
|
||||
}
|
||||
|
||||
// Verifies BCC can be successfully returned.
|
||||
TEST_F(OEMCryptoProv40Test, GetBootCertificateChainSuccess) {
|
||||
std::vector<uint8_t> bcc;
|
||||
size_t bcc_size = 0;
|
||||
std::vector<uint8_t> additional_signature;
|
||||
size_t additional_signature_size = 0;
|
||||
ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size,
|
||||
additional_signature.data(),
|
||||
&additional_signature_size),
|
||||
OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
|
||||
bcc.resize(bcc_size);
|
||||
additional_signature.resize(additional_signature_size);
|
||||
ASSERT_EQ(OEMCrypto_GetBootCertificateChain(bcc.data(), &bcc_size,
|
||||
additional_signature.data(),
|
||||
&additional_signature_size),
|
||||
OEMCrypto_SUCCESS);
|
||||
}
|
||||
|
||||
// Verifies that short buffer error returns when the buffer is short.
|
||||
TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairShortBuffer) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
std::vector<uint8_t> public_key;
|
||||
size_t public_key_size = 0;
|
||||
std::vector<uint8_t> public_key_signature;
|
||||
size_t public_key_signature_size = 0;
|
||||
std::vector<uint8_t> wrapped_private_key;
|
||||
size_t wrapped_private_key_size = 0;
|
||||
OEMCrypto_PrivateKeyType key_type;
|
||||
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key.data(), &public_key_size,
|
||||
public_key_signature.data(), &public_key_signature_size,
|
||||
wrapped_private_key.data(), &wrapped_private_key_size, &key_type),
|
||||
OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
|
||||
ASSERT_NE(public_key_size, 0uL);
|
||||
ASSERT_NE(public_key_signature_size, 0uL);
|
||||
ASSERT_NE(wrapped_private_key_size, 0uL);
|
||||
}
|
||||
|
||||
// Verifies a pair of key can be successfully returned.
|
||||
TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairSuccess) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
std::vector<uint8_t> public_key;
|
||||
size_t public_key_size = 0;
|
||||
std::vector<uint8_t> public_key_signature;
|
||||
size_t public_key_signature_size = 0;
|
||||
std::vector<uint8_t> wrapped_private_key;
|
||||
size_t wrapped_private_key_size = 0;
|
||||
OEMCrypto_PrivateKeyType key_type;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key.data(), &public_key_size,
|
||||
public_key_signature.data(), &public_key_signature_size,
|
||||
wrapped_private_key.data(), &wrapped_private_key_size, &key_type),
|
||||
OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
public_key.resize(public_key_size);
|
||||
public_key_signature.resize(public_key_signature_size);
|
||||
wrapped_private_key.resize(wrapped_private_key_size);
|
||||
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key.data(), &public_key_size,
|
||||
public_key_signature.data(), &public_key_signature_size,
|
||||
wrapped_private_key.data(), &wrapped_private_key_size, &key_type),
|
||||
OEMCrypto_SUCCESS);
|
||||
public_key.resize(public_key_size);
|
||||
public_key_signature.resize(public_key_signature_size);
|
||||
wrapped_private_key.resize(wrapped_private_key_size);
|
||||
// Parse the public key generated to make sure it is correctly formatted.
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetPublicKeyFromSubjectPublicKey(
|
||||
key_type, public_key.data(), public_key_size));
|
||||
}
|
||||
|
||||
// Verifies the generated key pairs are different on each call.
|
||||
TEST_F(OEMCryptoProv40Test, GenerateCertificateKeyPairsAreDifferent) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
// Large buffer to make sure it is large enough.
|
||||
size_t public_key_size1 = 10000;
|
||||
std::vector<uint8_t> public_key1(public_key_size1);
|
||||
size_t public_key_signature_size1 = 10000;
|
||||
std::vector<uint8_t> public_key_signature1(public_key_signature_size1);
|
||||
size_t wrapped_private_key_size1 = 10000;
|
||||
std::vector<uint8_t> wrapped_private_key1(wrapped_private_key_size1);
|
||||
OEMCrypto_PrivateKeyType key_type1;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key1.data(), &public_key_size1,
|
||||
public_key_signature1.data(), &public_key_signature_size1,
|
||||
wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1),
|
||||
OEMCrypto_SUCCESS);
|
||||
EXPECT_NE(public_key_size1, 0UL);
|
||||
EXPECT_NE(public_key_signature_size1, 0UL);
|
||||
EXPECT_NE(wrapped_private_key_size1, 0UL);
|
||||
public_key1.resize(public_key_size1);
|
||||
public_key_signature1.resize(public_key_signature_size1);
|
||||
wrapped_private_key1.resize(wrapped_private_key_size1);
|
||||
|
||||
size_t public_key_size2 = 10000;
|
||||
std::vector<uint8_t> public_key2(public_key_size2);
|
||||
size_t public_key_signature_size2 = 10000;
|
||||
std::vector<uint8_t> public_key_signature2(public_key_signature_size2);
|
||||
size_t wrapped_private_key_size2 = 10000;
|
||||
std::vector<uint8_t> wrapped_private_key2(wrapped_private_key_size2);
|
||||
OEMCrypto_PrivateKeyType key_type2;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key2.data(), &public_key_size2,
|
||||
public_key_signature2.data(), &public_key_signature_size2,
|
||||
wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2),
|
||||
OEMCrypto_SUCCESS);
|
||||
EXPECT_NE(public_key_size2, 0UL);
|
||||
EXPECT_NE(public_key_signature_size2, 0UL);
|
||||
EXPECT_NE(wrapped_private_key_size2, 0UL);
|
||||
public_key2.resize(public_key_size2);
|
||||
public_key_signature2.resize(public_key_signature_size2);
|
||||
wrapped_private_key2.resize(wrapped_private_key_size2);
|
||||
|
||||
EXPECT_NE(public_key1, public_key2);
|
||||
EXPECT_NE(public_key_signature1, public_key_signature2);
|
||||
EXPECT_NE(wrapped_private_key1, wrapped_private_key2);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoProv40Test, GetDeviceInformationAPI18) {
|
||||
std::vector<uint8_t> device_info;
|
||||
size_t device_info_length = 0;
|
||||
OEMCryptoResult sts =
|
||||
OEMCrypto_GetDeviceInformation(device_info.data(), &device_info_length);
|
||||
ASSERT_EQ(sts, OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
ASSERT_NE(device_info_length, 0uL);
|
||||
device_info.resize(device_info_length);
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GetDeviceInformation(device_info.data(), &device_info_length),
|
||||
OEMCrypto_SUCCESS);
|
||||
EXPECT_NE(device_info_length, 0uL);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoProv40Test, GetDeviceSignedCsrPayloadAPI18) {
|
||||
std::vector<uint8_t> challenge(64, 0xaa);
|
||||
// TODO: add cppbor support for oemcrypto tests for all targets. Before that,
|
||||
// use hex values which are equivalent of the commented cppbor statement.
|
||||
// std::vector<uint8_t> device_info = cppbor::Map()
|
||||
// .add("manufacturer", "google")
|
||||
// .add("fused", 0)
|
||||
// .add("other", "ignored")
|
||||
// .canonicalize()
|
||||
// .encode();
|
||||
//
|
||||
std::vector<uint8_t> device_info = {
|
||||
0xa3, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x0, 0x65, 0x6f, 0x74,
|
||||
0x68, 0x65, 0x72, 0x67, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64,
|
||||
0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72,
|
||||
0x65, 0x72, 0x66, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65};
|
||||
std::vector<uint8_t> signed_csr_payload;
|
||||
size_t signed_csr_payload_length = 0;
|
||||
OEMCryptoResult sts = OEMCrypto_GetDeviceSignedCsrPayload(
|
||||
challenge.data(), challenge.size(), device_info.data(),
|
||||
device_info.size(), signed_csr_payload.data(),
|
||||
&signed_csr_payload_length);
|
||||
ASSERT_EQ(sts, OEMCrypto_ERROR_SHORT_BUFFER);
|
||||
ASSERT_NE(signed_csr_payload_length, 0uL);
|
||||
signed_csr_payload.resize(signed_csr_payload_length);
|
||||
ASSERT_EQ(OEMCrypto_GetDeviceSignedCsrPayload(
|
||||
challenge.data(), challenge.size(), device_info.data(),
|
||||
device_info.size(), signed_csr_payload.data(),
|
||||
&signed_csr_payload_length),
|
||||
OEMCrypto_SUCCESS);
|
||||
EXPECT_NE(signed_csr_payload_length, 0uL);
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoProv40Test, GetDeviceSignedCsrPayloadInvalid) {
|
||||
std::vector<uint8_t> signed_csr_payload;
|
||||
size_t signed_csr_payload_length = 0;
|
||||
std::vector<uint8_t> challenge(64, 0xaa);
|
||||
std::vector<uint8_t> device_info = {
|
||||
0xa3, 0x65, 0x66, 0x75, 0x73, 0x65, 0x64, 0x0, 0x65, 0x6f, 0x74,
|
||||
0x68, 0x65, 0x72, 0x67, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x64,
|
||||
0x6c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72,
|
||||
0x65, 0x72, 0x66, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65};
|
||||
std::vector<uint8_t> challenge_empty;
|
||||
OEMCryptoResult sts = OEMCrypto_GetDeviceSignedCsrPayload(
|
||||
challenge_empty.data(), challenge_empty.size(), device_info.data(),
|
||||
device_info.size(), signed_csr_payload.data(),
|
||||
&signed_csr_payload_length);
|
||||
if (sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) return;
|
||||
ASSERT_EQ(sts, OEMCrypto_ERROR_INVALID_CONTEXT);
|
||||
|
||||
// Oversized challenge
|
||||
std::vector<uint8_t> challenge_long(65, 0xaa);
|
||||
sts = OEMCrypto_GetDeviceSignedCsrPayload(
|
||||
challenge_long.data(), challenge_long.size(), device_info.data(),
|
||||
device_info.size(), signed_csr_payload.data(),
|
||||
&signed_csr_payload_length);
|
||||
ASSERT_EQ(sts, OEMCrypto_ERROR_INVALID_CONTEXT);
|
||||
|
||||
std::vector<uint8_t> device_empty;
|
||||
sts = OEMCrypto_GetDeviceSignedCsrPayload(
|
||||
challenge.data(), challenge.size(), device_empty.data(),
|
||||
device_empty.size(), signed_csr_payload.data(),
|
||||
&signed_csr_payload_length);
|
||||
ASSERT_EQ(sts, OEMCrypto_ERROR_INVALID_CONTEXT);
|
||||
}
|
||||
|
||||
// Verifies that an OEM private key can be installed.
|
||||
TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeySuccess) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
// First generate a key pair.
|
||||
// Large buffer to make sure it is large enough.
|
||||
size_t public_key_size = 10000;
|
||||
std::vector<uint8_t> public_key(public_key_size);
|
||||
size_t public_key_signature_size = 10000;
|
||||
std::vector<uint8_t> public_key_signature(public_key_signature_size);
|
||||
size_t wrapped_private_key_size = 10000;
|
||||
std::vector<uint8_t> wrapped_private_key(wrapped_private_key_size);
|
||||
OEMCrypto_PrivateKeyType key_type;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key.data(), &public_key_size,
|
||||
public_key_signature.data(), &public_key_signature_size,
|
||||
wrapped_private_key.data(), &wrapped_private_key_size, &key_type),
|
||||
OEMCrypto_SUCCESS);
|
||||
public_key.resize(public_key_size);
|
||||
public_key_signature.resize(public_key_signature_size);
|
||||
wrapped_private_key.resize(wrapped_private_key_size);
|
||||
|
||||
// Install the generated private key.
|
||||
ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type,
|
||||
wrapped_private_key.data(),
|
||||
wrapped_private_key_size),
|
||||
OEMCrypto_SUCCESS);
|
||||
}
|
||||
|
||||
// If data is empty or random, the API should return non-success status.
|
||||
TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyInvalidDataFail) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
|
||||
// Empty key fails.
|
||||
std::vector<uint8_t> wrapped_private_key;
|
||||
OEMCrypto_PrivateKeyType key_type = OEMCrypto_RSA_Private_Key;
|
||||
ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type,
|
||||
wrapped_private_key.data(),
|
||||
wrapped_private_key.size()),
|
||||
OEMCrypto_SUCCESS);
|
||||
|
||||
// Random key data fails.
|
||||
wrapped_private_key = {1, 2, 3};
|
||||
ASSERT_NE(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type,
|
||||
wrapped_private_key.data(),
|
||||
wrapped_private_key.size()),
|
||||
OEMCrypto_SUCCESS);
|
||||
}
|
||||
|
||||
// Verifies that an OEM private key can be installed, and used by
|
||||
// GenerateCertificateKeyPair call.
|
||||
TEST_F(OEMCryptoProv40Test, InstallOemPrivateKeyCanBeUsed) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
// First generate a key pair.
|
||||
size_t public_key_size1 = 10000;
|
||||
std::vector<uint8_t> public_key1(public_key_size1);
|
||||
size_t public_key_signature_size1 = 10000;
|
||||
std::vector<uint8_t> public_key_signature1(public_key_signature_size1);
|
||||
size_t wrapped_private_key_size1 = 10000;
|
||||
std::vector<uint8_t> wrapped_private_key1(wrapped_private_key_size1);
|
||||
OEMCrypto_PrivateKeyType key_type1;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key1.data(), &public_key_size1,
|
||||
public_key_signature1.data(), &public_key_signature_size1,
|
||||
wrapped_private_key1.data(), &wrapped_private_key_size1, &key_type1),
|
||||
OEMCrypto_SUCCESS);
|
||||
EXPECT_NE(public_key_size1, 0UL);
|
||||
EXPECT_NE(public_key_signature_size1, 0UL);
|
||||
EXPECT_NE(wrapped_private_key_size1, 0UL);
|
||||
public_key1.resize(public_key_size1);
|
||||
public_key_signature1.resize(public_key_signature_size1);
|
||||
wrapped_private_key1.resize(wrapped_private_key_size1);
|
||||
|
||||
// Install the generated private key.
|
||||
ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s.session_id(), key_type1,
|
||||
wrapped_private_key1.data(),
|
||||
wrapped_private_key_size1),
|
||||
OEMCrypto_SUCCESS);
|
||||
|
||||
// Now calling GenerateCertificateKeyPair should use wrapped_private_key to
|
||||
// sign the newly generated public key.
|
||||
size_t public_key_size2 = 10000;
|
||||
std::vector<uint8_t> public_key2(public_key_size2);
|
||||
size_t public_key_signature_size2 = 10000;
|
||||
std::vector<uint8_t> public_key_signature2(public_key_signature_size2);
|
||||
size_t wrapped_private_key_size2 = 10000;
|
||||
std::vector<uint8_t> wrapped_private_key2(wrapped_private_key_size2);
|
||||
OEMCrypto_PrivateKeyType key_type2;
|
||||
ASSERT_EQ(
|
||||
OEMCrypto_GenerateCertificateKeyPair(
|
||||
s.session_id(), public_key2.data(), &public_key_size2,
|
||||
public_key_signature2.data(), &public_key_signature_size2,
|
||||
wrapped_private_key2.data(), &wrapped_private_key_size2, &key_type2),
|
||||
OEMCrypto_SUCCESS);
|
||||
EXPECT_NE(public_key_size2, 0UL);
|
||||
EXPECT_NE(public_key_signature_size2, 0UL);
|
||||
EXPECT_NE(wrapped_private_key_size2, 0UL);
|
||||
public_key2.resize(public_key_size2);
|
||||
public_key_signature2.resize(public_key_signature_size2);
|
||||
wrapped_private_key2.resize(wrapped_private_key_size2);
|
||||
|
||||
// Verify public_key_signature2 with public_key1.
|
||||
if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_RSA_Private_Key) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromSubjectPublicKey(
|
||||
public_key1.data(), public_key1.size()));
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
s.VerifyRsaSignature(public_key2, public_key_signature2.data(),
|
||||
public_key_signature2.size(), kSign_RSASSA_PSS));
|
||||
} else if (key_type2 == OEMCrypto_PrivateKeyType::OEMCrypto_ECC_Private_Key) {
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetEccPublicKeyFromSubjectPublicKey(
|
||||
public_key1.data(), public_key1.size()));
|
||||
ASSERT_NO_FATAL_FAILURE(s.VerifyEccSignature(public_key2,
|
||||
public_key_signature2.data(),
|
||||
public_key_signature2.size()));
|
||||
}
|
||||
}
|
||||
|
||||
/** Verify that the private key from an OEM Cert cannot be loaded as a DRM
|
||||
* cert.
|
||||
*/
|
||||
TEST_F(OEMCryptoProv40Test, OEMPrivateKeyCannotBeDRMKey) {
|
||||
// Create an OEM Cert and save it for alter.
|
||||
Session s1;
|
||||
ASSERT_NO_FATAL_FAILURE(s1.open());
|
||||
ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s1));
|
||||
ASSERT_EQ(s1.IsPublicKeySet(), true);
|
||||
s1.close();
|
||||
const std::vector<uint8_t> wrapped_oem_key1 = wrapped_oem_key_;
|
||||
// Now create a new OEM cert, load the second key, and try to load key1
|
||||
// as the DRM key.
|
||||
Session s2;
|
||||
ASSERT_NO_FATAL_FAILURE(s2.open());
|
||||
ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s2));
|
||||
s2.close();
|
||||
// Load the current key as the OEM key in session 3.
|
||||
Session s3;
|
||||
ASSERT_NO_FATAL_FAILURE(s3.open());
|
||||
// Now try to load key 1 as a DRM key. That should fail.
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_KEY,
|
||||
OEMCrypto_LoadDRMPrivateKey(s3.session_id(), oem_key_type_,
|
||||
wrapped_oem_key1.data(),
|
||||
wrapped_oem_key1.size()));
|
||||
}
|
||||
|
||||
/** The private key for a DRM Cert cannot be loaded as an OEM Certificate. */
|
||||
TEST_F(OEMCryptoProv40Test, DRMPrivateKeyCannotBeOEMKey) {
|
||||
// Create a DRM cert and save it for later.
|
||||
Session s1;
|
||||
// Make sure the drm private key exists.
|
||||
ASSERT_NO_FATAL_FAILURE(s1.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s1));
|
||||
ASSERT_NE(wrapped_drm_key_.size(), 0u);
|
||||
// Now try to load the drm private key as an OEM key.
|
||||
Session s2;
|
||||
ASSERT_NO_FATAL_FAILURE(s2.open());
|
||||
ASSERT_EQ(OEMCrypto_ERROR_INVALID_KEY,
|
||||
OEMCrypto_InstallOemPrivateKey(
|
||||
s2.session_id(), drm_key_type_,
|
||||
reinterpret_cast<const uint8_t*>(wrapped_drm_key_.data()),
|
||||
wrapped_drm_key_.size()));
|
||||
}
|
||||
|
||||
TEST_F(OEMCryptoProv40Test, GetDeviceId) {
|
||||
OEMCryptoResult sts;
|
||||
std::vector<uint8_t> dev_id;
|
||||
size_t dev_id_len = dev_id.size();
|
||||
sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len);
|
||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
ASSERT_GT(dev_id_len, 0u);
|
||||
dev_id.resize(dev_id_len);
|
||||
sts = OEMCrypto_GetDeviceID(dev_id.data(), &dev_id_len);
|
||||
}
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
dev_id.resize(dev_id_len);
|
||||
cout << " NormalGetDeviceId: dev_id = " << MaybeHex(dev_id)
|
||||
<< " len = " << dev_id_len << endl;
|
||||
// Device id should be stable. Query again.
|
||||
std::vector<uint8_t> dev_id2(dev_id_len);
|
||||
sts = OEMCrypto_GetDeviceID(dev_id2.data(), &dev_id_len);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
ASSERT_EQ(dev_id2, dev_id);
|
||||
}
|
||||
|
||||
// Verifies provisioning stage 1 OEM cert provisioning round trip works
|
||||
TEST_F(OEMCryptoProv40Test, ProvisionOemCert) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s));
|
||||
ASSERT_EQ(s.IsPublicKeySet(), true);
|
||||
}
|
||||
|
||||
// Verifies both provisioning stages OEM and DRM cert provisioning round trip
|
||||
// works
|
||||
TEST_F(OEMCryptoProv40Test, ProvisionDrmCert) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s));
|
||||
ASSERT_EQ(s.IsPublicKeySet(), true);
|
||||
}
|
||||
|
||||
/// @}
|
||||
} // namespace wvoec
|
||||
Reference in New Issue
Block a user