Add signature verification to BCC validator
Each entry in BCC is signed by its parent. BCC validator should be able to validate the signature along the chain. In OPK reference, EdDSA is used. Also adding functions to support ECDSA in oemcrypto_ecc_key module. Test: opk_ta_p40 Bug: 300310163 Bug: 307968622 Change-Id: Ibed895933eeb71b18c467604588cca449cac1af9
This commit is contained in:
@@ -44,6 +44,7 @@ using ScopedEvpPkey = ScopedObject<EVP_PKEY, EVP_PKEY_free>;
|
||||
using ScopedPrivateKeyInfo =
|
||||
ScopedObject<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
||||
using ScopedSigPoint = ScopedObject<ECDSA_SIG, ECDSA_SIG_free>;
|
||||
using ScopedEcPoint = ScopedObject<EC_POINT, EC_POINT_free>;
|
||||
|
||||
const EC_GROUP* GetEcGroup(EccCurve curve) {
|
||||
// Creating a named EC_GROUP is an expensive operation, and they
|
||||
@@ -140,6 +141,45 @@ EccCurve GetCurveFromKeyGroup(const EC_KEY* key) {
|
||||
return kEccCurveUnknown;
|
||||
}
|
||||
|
||||
// Creates EC public key from |curve| and |key_point|, and sets the result in
|
||||
// *|public_key|.
|
||||
bool GetPublicKeyFromKeyPoint(EccCurve curve, const uint8_t* key_point,
|
||||
size_t key_point_length, EC_KEY** public_key) {
|
||||
if (key_point == nullptr || key_point_length == 0) {
|
||||
return false;
|
||||
}
|
||||
const EC_GROUP* group = GetEcGroup(curve);
|
||||
if (!group) {
|
||||
LOGE("Failed to get ECC group for curve %d", curve);
|
||||
return false;
|
||||
}
|
||||
ScopedEcPoint point(EC_POINT_new(group));
|
||||
if (!point) {
|
||||
LOGE("Failed to new EC_POINT");
|
||||
return false;
|
||||
}
|
||||
if (!EC_POINT_oct2point(group, point.get(), key_point, key_point_length,
|
||||
nullptr)) {
|
||||
LOGE("Failed to convert the serialized point to EC_POINT");
|
||||
return false;
|
||||
}
|
||||
ScopedEcKey key(EC_KEY_new());
|
||||
if (!key) {
|
||||
LOGE("Failed to allocate key");
|
||||
return false;
|
||||
}
|
||||
if (!EC_KEY_set_group(key.get(), group)) {
|
||||
LOGE("Failed to set group");
|
||||
return false;
|
||||
}
|
||||
if (EC_KEY_set_public_key(key.get(), point.get()) == 0) {
|
||||
LOGE("Failed to convert the EC_POINT to EC_KEY");
|
||||
return false;
|
||||
}
|
||||
*public_key = key.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compares the public EC points of both keys to see if they are the
|
||||
// equal.
|
||||
// Both |public_key| and |private_key| must be of the same group.
|
||||
@@ -457,6 +497,26 @@ std::unique_ptr<EccPublicKey> EccPublicKey::LoadPrivateKeyInfo(
|
||||
return LoadPrivateKeyInfo(buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<EccPublicKey> EccPublicKey::LoadKeyPoint(EccCurve curve,
|
||||
const uint8_t* buffer,
|
||||
size_t length) {
|
||||
if (buffer == nullptr) {
|
||||
LOGE("Provided key point buffer is null");
|
||||
return nullptr;
|
||||
}
|
||||
if (length == 0) {
|
||||
LOGE("Provided key point buffer is zero length");
|
||||
return nullptr;
|
||||
}
|
||||
std::unique_ptr<EccPublicKey> key(new EccPublicKey());
|
||||
if (!key->InitFromKeyPoint(curve, buffer, length)) {
|
||||
LOGE("Failed to initialize public key from KeyPoint");
|
||||
key.reset();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
bool EccPublicKey::IsMatchingPrivateKey(
|
||||
const EccPrivateKey& private_key) const {
|
||||
if (private_key.curve() != curve_) {
|
||||
@@ -486,7 +546,7 @@ OEMCryptoResult EccPublicKey::VerifySignature(const uint8_t* message,
|
||||
LOGE("Bad message data");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
// Step 1: Parse signature.
|
||||
// Parse signature.
|
||||
const uint8_t* tp = signature;
|
||||
ScopedSigPoint sig_point(d2i_ECDSA_SIG(nullptr, &tp, signature_length));
|
||||
if (!sig_point) {
|
||||
@@ -494,24 +554,7 @@ OEMCryptoResult EccPublicKey::VerifySignature(const uint8_t* message,
|
||||
// Most likely an invalid signature than an OpenSSL error.
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
// Step 2: Hash message
|
||||
std::vector<uint8_t> digest;
|
||||
if (!DigestMessage(curve_, message, message_length, &digest)) {
|
||||
LOGE("Failed to digest message");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
// Step 3: Verify signature
|
||||
const int res = ECDSA_do_verify(
|
||||
digest.data(), static_cast<int>(digest.size()), sig_point.get(), key_);
|
||||
if (res == -1) {
|
||||
LOGE("Error occurred checking signature");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (res == 0) {
|
||||
LOGD("Signature did not match");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
return DigestAndVerify(message, message_length, sig_point.get());
|
||||
}
|
||||
|
||||
OEMCryptoResult EccPublicKey::VerifySignature(
|
||||
@@ -536,6 +579,37 @@ OEMCryptoResult EccPublicKey::VerifySignature(
|
||||
signature.size());
|
||||
}
|
||||
|
||||
OEMCryptoResult EccPublicKey::VerifyRawSignature(
|
||||
const uint8_t* message, size_t message_length, const uint8_t* signature,
|
||||
size_t signature_length) const {
|
||||
if (signature == nullptr || signature_length == 0) {
|
||||
LOGE("Signature is missing");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (message == nullptr && message_length > 0) {
|
||||
LOGE("Bad message data");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (signature_length % 2 == 1) {
|
||||
LOGE("Bad signature size: %zu", signature_length);
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
// Parse signature.
|
||||
ScopedSigPoint sig_point(ECDSA_SIG_new());
|
||||
if (!sig_point) {
|
||||
LOGE("Error occurred in ECDSA_SIG_new()");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
const int r_s_size = static_cast<int>(signature_length) / 2;
|
||||
if (!ECDSA_SIG_set0(sig_point.get(), BN_bin2bn(signature, r_s_size, nullptr),
|
||||
BN_bin2bn(signature + r_s_size, r_s_size, nullptr))) {
|
||||
LOGE("Failed to parse signature");
|
||||
// Most likely an invalid signature than an OpenSSL error.
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
return DigestAndVerify(message, message_length, sig_point.get());
|
||||
}
|
||||
|
||||
EccPublicKey::~EccPublicKey() {
|
||||
if (key_ != nullptr) {
|
||||
EC_KEY_free(key_);
|
||||
@@ -608,6 +682,57 @@ bool EccPublicKey::InitFromPrivateKey(const EccPrivateKey& private_key) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EccPublicKey::InitFromKeyPoint(EccCurve curve, const uint8_t* buffer,
|
||||
size_t length) {
|
||||
if (buffer == nullptr || length == 0) {
|
||||
LOGE("Provided key point buffer is empty");
|
||||
return false;
|
||||
}
|
||||
EC_KEY* ec_key;
|
||||
if (!GetPublicKeyFromKeyPoint(curve, buffer, length, &ec_key)) {
|
||||
return false;
|
||||
}
|
||||
ScopedEcKey key(ec_key);
|
||||
if (EC_KEY_check_key(key.get()) != 1) {
|
||||
LOGE("Invalid public EC key");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Required flags for IETF compliance.
|
||||
EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE);
|
||||
EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED);
|
||||
key_ = key.release();
|
||||
curve_ = curve;
|
||||
return true;
|
||||
}
|
||||
|
||||
OEMCryptoResult EccPublicKey::DigestAndVerify(
|
||||
const uint8_t* message, size_t message_length,
|
||||
const ECDSA_SIG* sig_point) const {
|
||||
if (message == nullptr && message_length > 0) {
|
||||
LOGE("Bad message data");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
// Hash message.
|
||||
std::vector<uint8_t> digest;
|
||||
if (!DigestMessage(curve_, message, message_length, &digest)) {
|
||||
LOGE("Failed to digest message");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
// Verify signature.
|
||||
const int res = ECDSA_do_verify(
|
||||
digest.data(), static_cast<int>(digest.size()), sig_point, key_);
|
||||
if (res == -1) {
|
||||
LOGE("Error occurred checking signature");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (res == 0) {
|
||||
LOGD("Signature did not match");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<EccPrivateKey> EccPrivateKey::New(EccCurve curve) {
|
||||
std::unique_ptr<EccPrivateKey> key(new EccPrivateKey());
|
||||
|
||||
Reference in New Issue
Block a user