Updated OEMCrypto tests to use DRM key objects.
[ Merge of http://go/wvgerrit/147275 ] Swapped out use of OpenSSL/BoringSSL RSA and EC_KEY to use OEMCrypto reference utility classes RsaPublicKey/EccPublicKey. This enables further test development with ECC keys, and removes duplicate OpenSSL/ BoringSSL code. For Android makefiles, only the minimally required files have been added. Bug: 205902021 Bug: 236317198 Test: run_prov30_test run_prov40_test oemcrypto_test Change-Id: I64491018e8ffb69bf986083e3aae446eb9e5cf39
This commit is contained in:
@@ -310,12 +310,12 @@ void ProvisioningRoundTrip::PrepareSession(
|
||||
OEMCrypto_BootCertificateChain) {
|
||||
// TODO(chelu): change this to CSR provisioning.
|
||||
session_->LoadOEMCert(true);
|
||||
session_->GenerateRSASessionKey(&message_key_, &encrypted_message_key_);
|
||||
session_->GenerateRsaSessionKey(&message_key_, &encrypted_message_key_);
|
||||
encryptor_.set_enc_key(message_key_);
|
||||
} else {
|
||||
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_OEMCertificate);
|
||||
session_->LoadOEMCert(true);
|
||||
session_->GenerateRSASessionKey(&message_key_, &encrypted_message_key_);
|
||||
session_->GenerateRsaSessionKey(&message_key_, &encrypted_message_key_);
|
||||
encryptor_.set_enc_key(message_key_);
|
||||
}
|
||||
}
|
||||
@@ -324,7 +324,7 @@ void ProvisioningRoundTrip::VerifyRequestSignature(
|
||||
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
|
||||
size_t /* core_message_length */) {
|
||||
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
|
||||
session()->VerifyRSASignature(data, generated_signature.data(),
|
||||
session()->VerifyRsaSignature(data, generated_signature.data(),
|
||||
generated_signature.size(), kSign_RSASSA_PSS);
|
||||
} else {
|
||||
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox);
|
||||
@@ -565,11 +565,11 @@ void LicenseRoundTrip::VerifyRequestSignature(
|
||||
if (global_features.api_version < 17) {
|
||||
const std::vector<uint8_t> subdata(data.begin() + core_message_length,
|
||||
data.end());
|
||||
session()->VerifyRSASignature(subdata, generated_signature.data(),
|
||||
session()->VerifyRsaSignature(subdata, generated_signature.data(),
|
||||
generated_signature.size(), kSign_RSASSA_PSS);
|
||||
SHA256(data.data(), core_message_length, request_hash_);
|
||||
} else {
|
||||
session()->VerifyRSASignature(data, generated_signature.data(),
|
||||
session()->VerifyRsaSignature(data, generated_signature.data(),
|
||||
generated_signature.size(), kSign_RSASSA_PSS);
|
||||
SHA256(data.data(), core_message_length, request_hash_);
|
||||
}
|
||||
@@ -1403,17 +1403,10 @@ OEMCryptoResult RenewalRoundTrip::LoadResponse(Session* session) {
|
||||
}
|
||||
}
|
||||
|
||||
Session::Session()
|
||||
: open_(false),
|
||||
forced_session_id_(false),
|
||||
session_id_(0),
|
||||
nonce_(0),
|
||||
public_rsa_(nullptr) {}
|
||||
Session::Session() {}
|
||||
|
||||
Session::~Session() {
|
||||
if (!forced_session_id_ && open_) close();
|
||||
if (public_rsa_) RSA_free(public_rsa_);
|
||||
if (public_ec_) EC_KEY_free(public_ec_);
|
||||
}
|
||||
|
||||
void Session::open() {
|
||||
@@ -1493,10 +1486,11 @@ void Session::GenerateDerivedKeysFromSessionKey() {
|
||||
// Uses test certificate.
|
||||
vector<uint8_t> session_key;
|
||||
vector<uint8_t> enc_session_key;
|
||||
ASSERT_NE(public_rsa_, nullptr) << "No public RSA key loaded in test code.";
|
||||
ASSERT_TRUE(public_rsa_ || public_ec_)
|
||||
<< "No public RSA/ECC key loaded in test code";
|
||||
// A failure here probably indicates that there is something wrong with the
|
||||
// test program and its dependency on BoringSSL.
|
||||
ASSERT_TRUE(GenerateRSASessionKey(&session_key, &enc_session_key));
|
||||
ASSERT_TRUE(GenerateRsaSessionKey(&session_key, &enc_session_key));
|
||||
vector<uint8_t> mac_context;
|
||||
vector<uint8_t> enc_context;
|
||||
FillDefaultContext(&mac_context, &enc_context);
|
||||
@@ -1621,12 +1615,11 @@ void Session::LoadOEMCert(bool verify_cert) {
|
||||
boringssl_ptr<EVP_PKEY, EVP_PKEY_free> pubkey(X509_get_pubkey(x509_cert));
|
||||
ASSERT_TRUE(pubkey.NotNull());
|
||||
if (i == 0) {
|
||||
public_rsa_ = EVP_PKEY_get1_RSA(pubkey.get());
|
||||
if (!public_rsa_) {
|
||||
cerr << "d2i_RSAPrivateKey failed.\n";
|
||||
dump_boringssl_error();
|
||||
ASSERT_TRUE(nullptr != public_rsa_);
|
||||
}
|
||||
public_rsa_ =
|
||||
util::RsaPublicKey::FromSslHandle(EVP_PKEY_get0_RSA(pubkey.get()));
|
||||
ASSERT_TRUE(public_rsa_)
|
||||
<< "Failed to extract public RSA key from OEM certificate";
|
||||
return;
|
||||
}
|
||||
if (verify_cert) {
|
||||
vector<char> buffer(80);
|
||||
@@ -1658,199 +1651,152 @@ void Session::LoadOEMCert(bool verify_cert) {
|
||||
}
|
||||
}
|
||||
|
||||
void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) {
|
||||
if (rsa_key == nullptr) {
|
||||
rsa_key = kTestRSAPKCS8PrivateKeyInfo2_2048;
|
||||
rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048);
|
||||
}
|
||||
uint8_t* p = const_cast<uint8_t*>(rsa_key);
|
||||
boringssl_ptr<BIO, BIO_vfree> bio(
|
||||
BIO_new_mem_buf(p, static_cast<int>(rsa_key_length)));
|
||||
ASSERT_TRUE(bio.NotNull());
|
||||
boringssl_ptr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8_pki(
|
||||
d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr));
|
||||
ASSERT_TRUE(pkcs8_pki.NotNull());
|
||||
boringssl_ptr<EVP_PKEY, EVP_PKEY_free> evp(EVP_PKCS82PKEY(pkcs8_pki.get()));
|
||||
ASSERT_TRUE(evp.NotNull());
|
||||
if (public_rsa_) RSA_free(public_rsa_);
|
||||
public_rsa_ = EVP_PKEY_get1_RSA(evp.get());
|
||||
if (!public_rsa_) {
|
||||
cerr << "d2i_RSAPrivateKey failed. ";
|
||||
dump_boringssl_error();
|
||||
FAIL() << "Could not parse public RSA key.";
|
||||
}
|
||||
switch (RSA_check_key(public_rsa_)) {
|
||||
case 1: // valid.
|
||||
void Session::SetTestRsaPublicKey() {
|
||||
public_ec_.reset();
|
||||
public_rsa_ = util::RsaPublicKey::LoadPrivateKeyInfo(
|
||||
kTestRSAPKCS8PrivateKeyInfo2_2048,
|
||||
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
|
||||
ASSERT_TRUE(public_rsa_) << "Could not parse test RSA public key #2";
|
||||
}
|
||||
|
||||
void Session::SetPublicKeyFromPrivateKeyInfo(OEMCrypto_PrivateKeyType key_type,
|
||||
const uint8_t* buffer,
|
||||
size_t length) {
|
||||
switch (key_type) {
|
||||
case OEMCrypto_RSA_Private_Key:
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
SetRsaPublicKeyFromPrivateKeyInfo(buffer, length));
|
||||
return;
|
||||
case 0: // not valid.
|
||||
dump_boringssl_error();
|
||||
FAIL() << "[rsa key not valid] ";
|
||||
default: // -1 == check failed.
|
||||
dump_boringssl_error();
|
||||
FAIL() << "[error checking rsa key] ";
|
||||
}
|
||||
}
|
||||
|
||||
void Session::SetRsaPublicKey(const uint8_t* buffer, size_t length) {
|
||||
if (public_rsa_) {
|
||||
RSA_free(public_rsa_);
|
||||
public_rsa_ = nullptr;
|
||||
}
|
||||
if (public_ec_) {
|
||||
EC_KEY_free(public_ec_);
|
||||
public_ec_ = nullptr;
|
||||
}
|
||||
public_rsa_ = d2i_RSA_PUBKEY(nullptr, &buffer, length);
|
||||
if (!public_rsa_) {
|
||||
cout << "d2i_RSAPrivateKey failed. ";
|
||||
dump_boringssl_error();
|
||||
FAIL() << "Could not parse public RSA key.";
|
||||
}
|
||||
switch (RSA_check_key(public_rsa_)) {
|
||||
case 1: // valid.
|
||||
case OEMCrypto_ECC_Private_Key:
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
SetEccPublicKeyFromPrivateKeyInfo(buffer, length));
|
||||
return;
|
||||
case 0: // not valid.
|
||||
dump_boringssl_error();
|
||||
FAIL() << "[rsa key not valid] ";
|
||||
default: // -1 == check failed.
|
||||
dump_boringssl_error();
|
||||
FAIL() << "[error checking rsa key] ";
|
||||
}
|
||||
FAIL() << "Unknown key type: " << static_cast<int>(key_type);
|
||||
}
|
||||
|
||||
void Session::SetEcPublicKey(const uint8_t* buffer, size_t length) {
|
||||
if (public_rsa_) {
|
||||
RSA_free(public_rsa_);
|
||||
public_rsa_ = nullptr;
|
||||
}
|
||||
if (public_ec_) {
|
||||
EC_KEY_free(public_ec_);
|
||||
public_ec_ = nullptr;
|
||||
}
|
||||
public_ec_ = d2i_EC_PUBKEY(nullptr, &buffer, length);
|
||||
if (!public_ec_) {
|
||||
cout << "d2i_RSAPrivateKey failed. ";
|
||||
dump_boringssl_error();
|
||||
FAIL() << "Could not parse public RSA key.";
|
||||
}
|
||||
switch (EC_KEY_check_key(public_ec_)) {
|
||||
case 1: // valid.
|
||||
void Session::SetRsaPublicKeyFromPrivateKeyInfo(const uint8_t* buffer,
|
||||
size_t length) {
|
||||
public_ec_.reset();
|
||||
public_rsa_ = util::RsaPublicKey::LoadPrivateKeyInfo(buffer, length);
|
||||
ASSERT_TRUE(public_rsa_) << "Could not parse RSA public key";
|
||||
}
|
||||
|
||||
void Session::SetEccPublicKeyFromPrivateKeyInfo(const uint8_t* buffer,
|
||||
size_t length) {
|
||||
public_rsa_.reset();
|
||||
public_ec_ = util::EccPublicKey::LoadPrivateKeyInfo(buffer, length);
|
||||
ASSERT_TRUE(public_ec_) << "Could not parse ECC public key";
|
||||
}
|
||||
|
||||
void Session::SetPublicKeyFromSubjectPublicKey(
|
||||
OEMCrypto_PrivateKeyType key_type, const uint8_t* buffer, size_t length) {
|
||||
switch (key_type) {
|
||||
case OEMCrypto_RSA_Private_Key:
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
SetRsaPublicKeyFromSubjectPublicKey(buffer, length));
|
||||
return;
|
||||
case OEMCrypto_ECC_Private_Key:
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
SetEccPublicKeyFromSubjectPublicKey(buffer, length));
|
||||
return;
|
||||
case 0: // not valid.
|
||||
default:
|
||||
dump_boringssl_error();
|
||||
FAIL() << "[ec key not valid] ";
|
||||
}
|
||||
FAIL() << "Unknown key type: " << static_cast<int>(key_type);
|
||||
}
|
||||
|
||||
bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
|
||||
size_t message_length,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) {
|
||||
boringssl_ptr<EVP_MD_CTX, EVP_MD_CTX_free> md_ctx(EVP_MD_CTX_new());
|
||||
EVP_PKEY_CTX* pkey_ctx = nullptr;
|
||||
|
||||
if (EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, EVP_sha1(),
|
||||
nullptr /* no ENGINE */, pkey) != 1) {
|
||||
LOGE("EVP_DigestVerifyInit failed in VerifyPSSSignature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_signature_md(pkey_ctx,
|
||||
const_cast<EVP_MD*>(EVP_sha1())) != 1) {
|
||||
LOGE("EVP_PKEY_CTX_set_signature_md failed in VerifyPSSSignature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) {
|
||||
LOGE("EVP_PKEY_CTX_set_rsa_padding failed in VerifyPSSSignature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, SHA_DIGEST_LENGTH) != 1) {
|
||||
LOGE("EVP_PKEY_CTX_set_rsa_pss_saltlen failed in VerifyPSSSignature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_DigestVerifyUpdate(md_ctx.get(), message, message_length) != 1) {
|
||||
LOGE("EVP_DigestVerifyUpdate failed in VerifyPSSSignature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_DigestVerifyFinal(md_ctx.get(), const_cast<uint8_t*>(signature),
|
||||
signature_length) != 1) {
|
||||
LOGE(
|
||||
"EVP_DigestVerifyFinal failed in VerifyPSSSignature. (Probably a bad "
|
||||
"signature.)");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
err:
|
||||
dump_boringssl_error();
|
||||
return false;
|
||||
void Session::SetRsaPublicKeyFromSubjectPublicKey(const uint8_t* buffer,
|
||||
size_t length) {
|
||||
public_ec_.reset();
|
||||
public_rsa_ = util::RsaPublicKey::Load(buffer, length);
|
||||
ASSERT_TRUE(public_rsa_) << "Could not parse RSA public key";
|
||||
}
|
||||
|
||||
void Session::VerifyRSASignature(const vector<uint8_t>& message,
|
||||
void Session::SetEccPublicKeyFromSubjectPublicKey(const uint8_t* buffer,
|
||||
size_t length) {
|
||||
public_rsa_.reset();
|
||||
public_ec_ = util::EccPublicKey::Load(buffer, length);
|
||||
ASSERT_TRUE(public_ec_) << "Could not parse ECC public key";
|
||||
}
|
||||
|
||||
void Session::VerifyRsaSignature(const vector<uint8_t>& message,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length,
|
||||
RSA_Padding_Scheme padding_scheme) {
|
||||
ASSERT_NE(public_rsa_, nullptr) << "No public RSA key loaded in test code.";
|
||||
|
||||
ASSERT_EQ(static_cast<size_t>(RSA_size(public_rsa_)), signature_length)
|
||||
<< "Signature size is wrong. " << signature_length << ", should be "
|
||||
<< RSA_size(public_rsa_);
|
||||
|
||||
if (padding_scheme == kSign_RSASSA_PSS) {
|
||||
boringssl_ptr<EVP_PKEY, EVP_PKEY_free> pkey(EVP_PKEY_new());
|
||||
ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), public_rsa_));
|
||||
|
||||
const bool ok =
|
||||
VerifyPSSSignature(pkey.get(), message.data(), message.size(),
|
||||
signature, signature_length);
|
||||
EXPECT_TRUE(ok) << "PSS signature check failed.";
|
||||
} else if (padding_scheme == kSign_PKCS1_Block1) {
|
||||
vector<uint8_t> padded_digest(signature_length);
|
||||
int size;
|
||||
// RSA_public_decrypt decrypts the signature, and then verifies that
|
||||
// it was padded with RSA PKCS1 padding.
|
||||
size = RSA_public_decrypt(static_cast<int>(signature_length), signature,
|
||||
padded_digest.data(), public_rsa_,
|
||||
RSA_PKCS1_PADDING);
|
||||
EXPECT_GT(size, 0);
|
||||
padded_digest.resize(size);
|
||||
EXPECT_EQ(message, padded_digest);
|
||||
} else {
|
||||
EXPECT_TRUE(false) << "Padding scheme not supported.";
|
||||
ASSERT_TRUE(public_rsa_) << "No public RSA key loaded in test code";
|
||||
if (padding_scheme != kSign_RSASSA_PSS &&
|
||||
padding_scheme != kSign_PKCS1_Block1) {
|
||||
FAIL() << "Padding scheme not supported: " << padding_scheme;
|
||||
return;
|
||||
}
|
||||
const util::RsaSignatureAlgorithm algorithm =
|
||||
padding_scheme == kSign_RSASSA_PSS ? util::kRsaPssDefault
|
||||
: util::kRsaPkcs1Cast;
|
||||
const OEMCryptoResult result = public_rsa_->VerifySignature(
|
||||
message.data(), message.size(), signature, signature_length, algorithm);
|
||||
ASSERT_EQ(result, OEMCrypto_SUCCESS) << "RSA signature check failed";
|
||||
}
|
||||
|
||||
bool Session::GenerateRSASessionKey(vector<uint8_t>* session_key,
|
||||
void Session::VerifyEccSignature(const vector<uint8_t>& message,
|
||||
const uint8_t* signature,
|
||||
size_t signature_length) {
|
||||
ASSERT_TRUE(public_ec_) << "No public ECC key loaded in test code";
|
||||
const OEMCryptoResult result = public_ec_->VerifySignature(
|
||||
message.data(), message.size(), signature, signature_length);
|
||||
ASSERT_EQ(result, OEMCrypto_SUCCESS) << "ECC signature check failed";
|
||||
}
|
||||
|
||||
bool Session::GenerateRsaSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* enc_session_key) {
|
||||
if (!public_rsa_) {
|
||||
cerr << "No public RSA key loaded in test code.\n";
|
||||
cerr << "No public RSA key loaded in test code\n";
|
||||
return false;
|
||||
}
|
||||
*session_key = wvutil::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
|
||||
enc_session_key->assign(RSA_size(public_rsa_), 0);
|
||||
int status = RSA_public_encrypt(
|
||||
static_cast<int>(session_key->size()), &(session_key->front()),
|
||||
&(enc_session_key->front()), public_rsa_, RSA_PKCS1_OAEP_PADDING);
|
||||
int size = static_cast<int>(RSA_size(public_rsa_));
|
||||
if (status != size) {
|
||||
cerr << "GenerateRSASessionKey error encrypting session key.\n";
|
||||
dump_boringssl_error();
|
||||
*enc_session_key = public_rsa_->EncryptSessionKey(*session_key);
|
||||
if (enc_session_key->empty()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key) {
|
||||
bool Session::GenerateEccSessionKey(vector<uint8_t>* session_key,
|
||||
vector<uint8_t>* ecdh_public_key_data) {
|
||||
if (!public_ec_) {
|
||||
cerr << "No public ECC key loaded in test code\n";
|
||||
return false;
|
||||
}
|
||||
auto ephemeral_key = util::EccPrivateKey::New(public_ec_->curve());
|
||||
if (!ephemeral_key) {
|
||||
return false;
|
||||
}
|
||||
*session_key = ephemeral_key->DeriveSessionKey(*public_ec_);
|
||||
if (session_key->empty()) {
|
||||
return false;
|
||||
}
|
||||
*ecdh_public_key_data = ephemeral_key->SerializeAsPublicKey();
|
||||
if (ecdh_public_key_data->empty()) {
|
||||
session_key->clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::LoadWrappedDrmKey(OEMCrypto_PrivateKeyType key_type,
|
||||
const vector<uint8_t>& wrapped_drm_key) {
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS,
|
||||
OEMCrypto_LoadDRMPrivateKey(session_id(), OEMCrypto_RSA_Private_Key,
|
||||
wrapped_rsa_key.data(),
|
||||
wrapped_rsa_key.size()));
|
||||
OEMCrypto_LoadDRMPrivateKey(session_id(), key_type,
|
||||
wrapped_drm_key.data(),
|
||||
wrapped_drm_key.size()));
|
||||
}
|
||||
|
||||
void Session::LoadWrappedRsaDrmKey(const vector<uint8_t>& wrapped_rsa_key) {
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
LoadWrappedDrmKey(OEMCrypto_RSA_Private_Key, wrapped_rsa_key));
|
||||
}
|
||||
|
||||
void Session::LoadWrappedEccDrmKey(const vector<uint8_t>& wrapped_ecc_key) {
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
LoadWrappedDrmKey(OEMCrypto_ECC_Private_Key, wrapped_ecc_key));
|
||||
}
|
||||
|
||||
void Session::CreateNewUsageEntry(OEMCryptoResult* status) {
|
||||
|
||||
Reference in New Issue
Block a user