blob: 494708d6a214ebfd71cd911bfd0204533636225a [file] [log] [blame]
// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "hwsec-test-utils/fake_pca_agent/tpm2_struct_utils.h"
#include <string>
#include <crypto/scoped_openssl_types.h>
#include <crypto/sha2.h>
#include <trunks/error_codes.h>
#include <trunks/tpm_generated.h>
#include "hwsec-test-utils/common/openssl_utility.h"
namespace hwsec_test_utils {
namespace fake_pca_agent {
namespace {
constexpr int kWellKnownExponent = 65537;
crypto::ScopedBIGNUM StringToBignum(const std::string& s) {
crypto::ScopedBIGNUM bn(BN_bin2bn(
reinterpret_cast<const unsigned char*>(s.data()), s.length(), nullptr));
if (!bn) {
LOG(ERROR) << __func__
<< ": Failed to call BN_bin2bn: " << GetOpenSSLError();
return nullptr;
}
return bn;
}
crypto::ScopedEVP_PKEY TpmtPublicToRsaKey(
const trunks::TPMT_PUBLIC& tpmt_public) {
CHECK_EQ(tpmt_public.type, trunks::TPM_ALG_RSA);
crypto::ScopedRSA rsa(RSA_new());
crypto::ScopedBIGNUM e(BN_new());
if (!rsa || !e) {
LOG(ERROR) << __func__
<< ": Failed to allocate RSA or BIGNUMs: " << GetOpenSSLError();
return nullptr;
}
if (BN_set_word(e.get(), kWellKnownExponent) != 1) {
LOG(ERROR) << __func__ << ": Failed to create BIGNUM of exponent: "
<< GetOpenSSLError();
return nullptr;
}
crypto::ScopedBIGNUM n = StringToBignum(
trunks::StringFrom_TPM2B_PUBLIC_KEY_RSA(tpmt_public.unique.rsa));
if (!n) {
LOG(ERROR) << __func__ << ": Failed to create BIGNUM of modulus.";
return nullptr;
}
if (RSA_set0_key(rsa.get(), n.release(), e.release(), nullptr) != 1) {
LOG(ERROR) << __func__ << ": Failed to set exponent or modulus.";
return nullptr;
}
crypto::ScopedEVP_PKEY key(EVP_PKEY_new());
if (!key) {
LOG(ERROR) << __func__
<< ": Failed to call EVP_PKEY_new: " << GetOpenSSLError();
return nullptr;
}
if (EVP_PKEY_set1_RSA(key.get(), rsa.get()) != 1) {
LOG(ERROR) << __func__
<< ": Failed to call EVP_PKEY_set1_RSA: " << GetOpenSSLError();
return nullptr;
}
return key;
}
crypto::ScopedEVP_PKEY TpmtPublicToECCKey(
const trunks::TPMT_PUBLIC& tpmt_public) {
CHECK_EQ(tpmt_public.type, trunks::TPM_ALG_ECC);
const trunks::TPMS_ECC_PARMS& ecc_params = tpmt_public.parameters.ecc_detail;
if (ecc_params.curve_id != trunks::TPM_ECC_NIST_P256) {
LOG(ERROR) << __func__ << ": Unsupported curve id.";
return nullptr;
}
crypto::ScopedEC_KEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
if (!ec_key) {
LOG(ERROR) << __func__ << ": Failed to call EC_KEY_new_by_curve_name: "
<< GetOpenSSLError();
return nullptr;
}
EC_KEY_set_asn1_flag(ec_key.get(), OPENSSL_EC_NAMED_CURVE);
crypto::ScopedBIGNUM x_point = StringToBignum(
trunks::StringFrom_TPM2B_ECC_PARAMETER(tpmt_public.unique.ecc.x));
if (!x_point) {
LOG(ERROR) << __func__ << ": Failed to create X point.";
return nullptr;
}
crypto::ScopedBIGNUM y_point = StringToBignum(
trunks::StringFrom_TPM2B_ECC_PARAMETER(tpmt_public.unique.ecc.y));
if (!y_point) {
LOG(ERROR) << __func__ << ": Failed to create Y point.";
return nullptr;
}
if (EC_KEY_set_public_key_affine_coordinates(ec_key.get(), x_point.get(),
y_point.get()) != 1) {
LOG(ERROR) << __func__
<< ": Failed to call EC_KEY_set_public_key_affine_coordinates: "
<< GetOpenSSLError();
return nullptr;
}
if (EC_KEY_check_key(ec_key.get()) != 1) {
LOG(ERROR) << __func__ << ": Bad ECC key (EC_KEY_check_key failed): "
<< GetOpenSSLError();
return nullptr;
}
crypto::ScopedEVP_PKEY key(EVP_PKEY_new());
if (!key) {
LOG(ERROR) << __func__
<< ": Failed to call EVP_PKEY_new: " << GetOpenSSLError();
return nullptr;
}
if (EVP_PKEY_set1_EC_KEY(key.get(), ec_key.get()) != 1) {
LOG(ERROR) << __func__ << ": Failed to call EVP_PKEY_set1_EC_KEY: "
<< GetOpenSSLError();
return nullptr;
}
return key;
}
} // namespace
crypto::ScopedEVP_PKEY TpmtPublicToEVP(std::string serialized,
std::string* name) {
trunks::TPMT_PUBLIC parsed{};
trunks::TPM_RC result;
std::string value_bytes;
if ((result = Parse_TPMT_PUBLIC(&serialized, &parsed, &value_bytes)) !=
trunks::TPM_RC_SUCCESS) {
LOG(ERROR) << __func__ << ":Failed to call Parse_TPMT_PUBLIC: "
<< trunks::GetErrorString(result);
return nullptr;
}
crypto::ScopedEVP_PKEY key;
switch (parsed.type) {
case trunks::TPM_ALG_RSA:
key = TpmtPublicToRsaKey(parsed);
break;
case trunks::TPM_ALG_ECC:
key = TpmtPublicToECCKey(parsed);
break;
default:
LOG(ERROR) << __func__ << ": Unknown key type: " << parsed.type;
return nullptr;
}
if (!key) {
LOG(ERROR) << __func__ << ": Failed to create EVP_PKEY.";
return nullptr;
}
// Compute the key's name (TPM2.0 spec Part I 16 Names) if needed.
if (name != nullptr) {
if (parsed.name_alg != trunks::TPM_ALG_SHA256) {
LOG(ERROR) << __func__
<< ": Unsupported name algorithm: " << parsed.name_alg;
return nullptr;
}
std::string prefix;
// Serialize_UINT16 should always succeed.
CHECK_EQ(trunks::Serialize_UINT16(parsed.name_alg, &prefix),
trunks::TPM_RC_SUCCESS);
*name = prefix + crypto::SHA256HashString(value_bytes);
}
return key;
}
} // namespace fake_pca_agent
} // namespace hwsec_test_utils