Source release 18.1.0
This commit is contained in:
228
oemcrypto/test/oemcrypto_cast_test.h
Normal file
228
oemcrypto/test/oemcrypto_cast_test.h
Normal file
@@ -0,0 +1,228 @@
|
||||
// Copyright 2023 Google LLC. All Rights Reserved. This file and proprietary
|
||||
// source code may only be used and distributed under the Widevine
|
||||
// License Agreement.
|
||||
//
|
||||
// Test data for OEMCrypto unit tests.
|
||||
//
|
||||
#ifndef CDM_OEMCRYPTO_CAST_TEST_
|
||||
#define CDM_OEMCRYPTO_CAST_TEST_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "oemcrypto_provisioning_test.h"
|
||||
#include "oemcrypto_session_tests_helper.h"
|
||||
|
||||
namespace wvoec {
|
||||
|
||||
const char* HDCPCapabilityAsString(OEMCrypto_HDCP_Capability value);
|
||||
|
||||
std::string MaybeHex(const uint8_t* data, size_t length);
|
||||
std::string MaybeHex(const std::vector<uint8_t>& data);
|
||||
|
||||
// This test attempts to use alternate algorithms for loaded device certs.
|
||||
class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
|
||||
protected:
|
||||
void DisallowForbiddenPadding(RSA_Padding_Scheme scheme, size_t size) {
|
||||
OEMCryptoResult sts;
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||
|
||||
// Sign a Message
|
||||
vector<uint8_t> licenseRequest(size);
|
||||
GetRandBytes(licenseRequest.data(), licenseRequest.size());
|
||||
size_t signature_length = 256;
|
||||
vector<uint8_t> signature(signature_length);
|
||||
sts = OEMCrypto_GenerateRSASignature(
|
||||
s.session_id(), licenseRequest.data(), licenseRequest.size(),
|
||||
signature.data(), &signature_length, scheme);
|
||||
// Allow OEMCrypto to request a full buffer.
|
||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
ASSERT_NE(static_cast<size_t>(0), signature_length);
|
||||
signature.assign(signature_length, 0);
|
||||
sts = OEMCrypto_GenerateRSASignature(
|
||||
s.session_id(), licenseRequest.data(), licenseRequest.size(),
|
||||
signature.data(), &signature_length, scheme);
|
||||
}
|
||||
|
||||
EXPECT_NE(OEMCrypto_SUCCESS, sts)
|
||||
<< "Signed with forbidden padding scheme=" << (int)scheme
|
||||
<< ", size=" << (int)size;
|
||||
const vector<uint8_t> zero(signature.size(), 0);
|
||||
ASSERT_EQ(zero, signature); // signature should not be computed.
|
||||
}
|
||||
|
||||
void TestSignature(RSA_Padding_Scheme scheme, size_t size) {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||
|
||||
vector<uint8_t> licenseRequest(size);
|
||||
GetRandBytes(licenseRequest.data(), licenseRequest.size());
|
||||
size_t signature_length = 0;
|
||||
OEMCryptoResult sts = OEMCrypto_GenerateRSASignature(
|
||||
s.session_id(), licenseRequest.data(), licenseRequest.size(), nullptr,
|
||||
&signature_length, scheme);
|
||||
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
|
||||
ASSERT_NE(static_cast<size_t>(0), signature_length);
|
||||
|
||||
std::vector<uint8_t> 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=" << size;
|
||||
signature.resize(signature_length);
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||
ASSERT_NO_FATAL_FAILURE(s.VerifyRsaSignature(
|
||||
licenseRequest, signature.data(), signature_length, scheme));
|
||||
}
|
||||
|
||||
void DisallowDeriveKeys() {
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
|
||||
s.GenerateNonce();
|
||||
vector<uint8_t> session_key;
|
||||
vector<uint8_t> enc_session_key;
|
||||
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
|
||||
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
|
||||
ASSERT_TRUE(s.GenerateRsaSessionKey(&session_key, &enc_session_key));
|
||||
vector<uint8_t> mac_context;
|
||||
vector<uint8_t> enc_context;
|
||||
s.FillDefaultContext(&mac_context, &enc_context);
|
||||
ASSERT_NE(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_DeriveKeysFromSessionKey(
|
||||
s.session_id(), enc_session_key.data(),
|
||||
enc_session_key.size(), mac_context.data(),
|
||||
mac_context.size(), enc_context.data(), enc_context.size()));
|
||||
}
|
||||
|
||||
// If force is true, we assert that the key loads successfully.
|
||||
void LoadWithAllowedSchemes(uint32_t schemes, bool force) {
|
||||
// prov 2 or prov 3
|
||||
if (global_features.provisioning_method == OEMCrypto_Keybox ||
|
||||
global_features.provisioning_method == OEMCrypto_OEMCertificate) {
|
||||
Session s;
|
||||
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
|
||||
provisioning_messages.set_allowed_schemes(schemes);
|
||||
provisioning_messages.PrepareSession(keybox_);
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
|
||||
OEMCryptoResult sts = provisioning_messages.LoadResponse();
|
||||
key_loaded_ = (OEMCrypto_SUCCESS == sts);
|
||||
if (key_loaded_) {
|
||||
uint8_t* ptr = provisioning_messages.response_data().rsa_key;
|
||||
size_t len = provisioning_messages.response_data().rsa_key_length;
|
||||
encoded_rsa_key_ = std::vector<uint8_t>(ptr, ptr + len);
|
||||
wrapped_drm_key_ = provisioning_messages.wrapped_rsa_key();
|
||||
drm_key_type_ = OEMCrypto_RSA_Private_Key;
|
||||
EXPECT_GT(wrapped_drm_key_.size(), 0u);
|
||||
EXPECT_EQ(nullptr, find(wrapped_drm_key_, encoded_rsa_key_));
|
||||
}
|
||||
if (force) {
|
||||
EXPECT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
} else if (global_features.provisioning_method ==
|
||||
OEMCrypto_BootCertificateChain) {
|
||||
Session s1;
|
||||
ASSERT_NO_FATAL_FAILURE(s1.open());
|
||||
ASSERT_NO_FATAL_FAILURE(CreateProv4OEMKey(&s1));
|
||||
|
||||
Session s2;
|
||||
ASSERT_NO_FATAL_FAILURE(s2.open());
|
||||
ASSERT_EQ(OEMCrypto_InstallOemPrivateKey(s2.session_id(), oem_key_type_,
|
||||
wrapped_oem_key_.data(),
|
||||
wrapped_oem_key_.size()),
|
||||
OEMCrypto_SUCCESS);
|
||||
Provisioning40CastRoundTrip prov_cast(&s2, encoded_rsa_key_);
|
||||
prov_cast.set_allowed_schemes(schemes);
|
||||
ASSERT_NO_FATAL_FAILURE(prov_cast.PrepareSession());
|
||||
ASSERT_NO_FATAL_FAILURE(prov_cast.LoadDRMPrivateKey());
|
||||
|
||||
ASSERT_NO_FATAL_FAILURE(s2.SetPublicKeyFromSubjectPublicKey(
|
||||
prov_cast.drm_key_type(), prov_cast.drm_public_key().data(),
|
||||
prov_cast.drm_public_key().size()));
|
||||
ASSERT_NO_FATAL_FAILURE(prov_cast.SignAndVerifyRequest());
|
||||
ASSERT_NO_FATAL_FAILURE(s2.GenerateDerivedKeysFromSessionKey());
|
||||
ASSERT_NO_FATAL_FAILURE(prov_cast.CreateDefaultResponse());
|
||||
ASSERT_NO_FATAL_FAILURE(prov_cast.EncryptAndSignResponse());
|
||||
OEMCryptoResult sts = prov_cast.LoadResponse();
|
||||
key_loaded_ = (OEMCrypto_SUCCESS == sts);
|
||||
if (key_loaded_) {
|
||||
uint8_t* ptr = prov_cast.response_data().rsa_key;
|
||||
size_t len = prov_cast.response_data().rsa_key_length;
|
||||
encoded_rsa_key_ = std::vector<uint8_t>(ptr, ptr + len);
|
||||
wrapped_drm_key_ = prov_cast.wrapped_rsa_key();
|
||||
drm_key_type_ = OEMCrypto_RSA_Private_Key;
|
||||
EXPECT_GT(wrapped_drm_key_.size(), 0u);
|
||||
EXPECT_EQ(nullptr, find(wrapped_drm_key_, encoded_rsa_key_));
|
||||
}
|
||||
if (force) {
|
||||
EXPECT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
}
|
||||
} else {
|
||||
FAIL() << "Unsupported provisioning method";
|
||||
}
|
||||
}
|
||||
|
||||
bool key_loaded_ = false;
|
||||
};
|
||||
|
||||
// Used to test the different HDCP versions. This test is parameterized by the
|
||||
// required HDCP version in the key control block.
|
||||
class OEMCryptoSessionTestLoadCasKeysWithHDCP : public OEMCryptoSessionTests,
|
||||
public WithParamInterface<int> {
|
||||
protected:
|
||||
void LoadCasKeysWithHDCP(OEMCrypto_HDCP_Capability version) {
|
||||
OEMCryptoResult sts;
|
||||
OEMCrypto_HDCP_Capability current, maximum;
|
||||
sts = OEMCrypto_GetHDCPCapability(¤t, &maximum);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(InstallTestDrmKey(&s));
|
||||
LicenseRoundTrip license_messages(&s);
|
||||
license_messages.set_control((version << wvoec::kControlHDCPVersionShift) |
|
||||
wvoec::kControlObserveHDCP |
|
||||
wvoec::kControlHDCPRequired);
|
||||
license_messages.set_license_type(OEMCrypto_EntitlementLicense);
|
||||
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());
|
||||
|
||||
uint32_t key_session_id;
|
||||
sts = OEMCrypto_CreateEntitledKeySession(s.session_id(), &key_session_id);
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
EntitledMessage entitled_message_1(&license_messages);
|
||||
entitled_message_1.FillKeyArray();
|
||||
entitled_message_1.SetEntitledKeySession(key_session_id);
|
||||
|
||||
if (((version <= HDCP_V2_3 || current >= HDCP_V1_0) && version > current) ||
|
||||
(current == HDCP_V1 && version >= HDCP_V1_0)) {
|
||||
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
|
||||
/*load_even=*/true, /*load_odd=*/true,
|
||||
OEMCrypto_ERROR_INSUFFICIENT_HDCP))
|
||||
<< "Failed when current HDCP = " << HDCPCapabilityAsString(current)
|
||||
<< ", maximum HDCP = " << HDCPCapabilityAsString(maximum)
|
||||
<< ", license HDCP = " << HDCPCapabilityAsString(version);
|
||||
} else {
|
||||
ASSERT_NO_FATAL_FAILURE(entitled_message_1.LoadCasKeys(
|
||||
/*load_even=*/true, /*load_odd=*/true, OEMCrypto_SUCCESS))
|
||||
<< "Failed when current HDCP = " << HDCPCapabilityAsString(current)
|
||||
<< ", maximum HDCP = " << HDCPCapabilityAsString(maximum)
|
||||
<< ", license HDCP = " << HDCPCapabilityAsString(version);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace wvoec
|
||||
|
||||
#endif // CDM_OEMCRYPTO_CAST_TEST_
|
||||
Reference in New Issue
Block a user