diff --git a/libwvdrmengine/oemcrypto/util/include/bcc_validator.h b/libwvdrmengine/oemcrypto/util/include/bcc_validator.h index 9ed9cfac..94f07862 100644 --- a/libwvdrmengine/oemcrypto/util/include/bcc_validator.h +++ b/libwvdrmengine/oemcrypto/util/include/bcc_validator.h @@ -16,6 +16,28 @@ namespace wvoec { namespace util { +// Enums and struct to hold EC public key info +enum BccSignatureAlgorithm { + kBccDefaultSignature = 0, + kBccEdDsa = 1, + kBccEcdsaSha256 = 2, + kBccEcdsaSha384 = 3 +}; + +enum BccCurve { + kBccDefaultCurve = 0, + kBccEd25519 = 1, + kBccP256 = 2, + kBccP384 = 3 +}; + +struct BccPublicKeyInfo { + BccSignatureAlgorithm signature_algorithm; + BccCurve curve; + // Raw EC key bytes extracted from BCC + std::vector key_bytes; +}; + // BccValidator processes a Provisioning 4.0 device root of trust. It extracts // and validates relevant pieces of information of BCC. // Relevant documents: @@ -37,15 +59,20 @@ class BccValidator : public CborValidator { private: // Processes CoseKey PubKeyEd25519 / PubKeyECDSA256, prints into |fmt_msgs|, - // and extracts the PubKey string to *|public_key_bytes|. + // and extracts the PubKey to *|public_key_info|. CborMessageStatus ProcessSubjectPublicKeyInfo( const cppbor::Map& public_key_info_map, - std::vector& fmt_msgs, std::string* public_key_bytes); + std::vector& fmt_msgs, BccPublicKeyInfo* public_key_info); // Processes DiceChainEntryPayload, which contains subject public key, prints - // into |fmt_msgs|, and extracts the PubKey string to *|public_key_bytes|. + // into |fmt_msgs|, and extracts the PubKey to *|public_key_info|. CborMessageStatus ProcessDiceChainEntryPayload( const std::vector& payload, std::vector& fmt_msgs, - std::string* public_key_bytes); + BccPublicKeyInfo* public_key_info); + // Verifies the raw EC signature |signature| with the public key + // |signing_key|. |signature| extracted from BCC is not ASN.1 DER encoded. + bool VerifySignature(const BccPublicKeyInfo& signing_key, + const std::vector& message, + const std::vector& signature); // Used to generate formatted message. std::stringstream msg_ss_; }; diff --git a/libwvdrmengine/oemcrypto/util/include/oemcrypto_ecc_key.h b/libwvdrmengine/oemcrypto/util/include/oemcrypto_ecc_key.h index 62df66da..079da6ec 100644 --- a/libwvdrmengine/oemcrypto/util/include/oemcrypto_ecc_key.h +++ b/libwvdrmengine/oemcrypto/util/include/oemcrypto_ecc_key.h @@ -60,6 +60,13 @@ class EccPublicKey { size_t length); static std::unique_ptr Load(const std::string& buffer); static std::unique_ptr Load(const std::vector& buffer); + // Loads EC public key from the |curve| and |buffer|. + // The provided |buffer| must contain an EC point serialized from raw X9.62 + // format. For uncompressed form, it is a 1-byte prefix plus two 32-byte + // integers representing X, Y coordinates. + static std::unique_ptr LoadKeyPoint(EccCurve curve, + const uint8_t* buffer, + size_t length); // Loads a serialized ECC private key, but only converting the public key. static std::unique_ptr LoadPrivateKeyInfo(const uint8_t* buffer, @@ -107,6 +114,15 @@ class EccPublicKey { const std::string& signature) const; OEMCryptoResult VerifySignature(const std::vector& message, const std::vector& signature) const; + // Verifies the raw |signature| matches the provided |message| by the + // private equivalent of this public key. + // A raw ECDSA signature consists of a pair of integers (r,s). The |signature| + // is a concatenation of two octet strings resulting from the integer-to-octet + // encoding of the values of r and s, in the order of (r||s). + OEMCryptoResult VerifyRawSignature(const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length) const; ~EccPublicKey(); @@ -125,6 +141,13 @@ class EccPublicKey { bool InitFromPrivateKeyInfo(const uint8_t* buffer, size_t length); // Initializes the public key object from a private. bool InitFromPrivateKey(const EccPrivateKey& private_key); + // Initializes the public key object from the provided curve and key point + // |buffer|. + bool InitFromKeyPoint(EccCurve curve, const uint8_t* buffer, size_t length); + // Digests the |message| and verifies signature against the provided signature + // point. + OEMCryptoResult DigestAndVerify(const uint8_t* message, size_t message_length, + const ECDSA_SIG* sig_point) const; // OpenSSL/BoringSSL implementation of an ECC key. // As a public key, this will only have key point initialized. diff --git a/libwvdrmengine/oemcrypto/util/src/bcc_validator.cpp b/libwvdrmengine/oemcrypto/util/src/bcc_validator.cpp index fc3b439d..e74354f8 100644 --- a/libwvdrmengine/oemcrypto/util/src/bcc_validator.cpp +++ b/libwvdrmengine/oemcrypto/util/src/bcc_validator.cpp @@ -14,6 +14,9 @@ #include #include +#include + +#include "oemcrypto_ecc_key.h" #include "string_conversions.h" namespace wvoec { @@ -69,8 +72,8 @@ constexpr int kP256KeyComponentSize = 256 / 8; // The key is formatted in an Z/X/Y format in which Z == 0x04 and X and Y are // the public key coordinates. X and Y are each 48 bytes. constexpr int kP384KeyComponentSize = 384 / 8; +constexpr int kMarshaledP256KeySize = kP256KeyComponentSize * 2 + 1; constexpr int kMarshaledP384KeySize = kP384KeyComponentSize * 2 + 1; -constexpr int kMaxMarshaledECKeySize = kMarshaledP384KeySize; constexpr char kMarshaledECKeyZValue = 0x04; constexpr int kED25519KeyDataItemSize = 32; // The Issuer field key in BccEntryPayload. @@ -79,6 +82,8 @@ constexpr int64_t kIssuer = 1; constexpr int64_t kSubject = 2; // The SubjectPublicKey field key in BccEntryPayload. constexpr int64_t kSubjectPublicKey = -4670552; +// This signature context is defined by COSE SIGN1. +constexpr char kSignatureContextString[] = "Signature1"; struct IssuerSubject { std::string issuer; @@ -135,6 +140,60 @@ void AddMessages(std::stringstream& ss, } } // namespace +bool BccValidator::VerifySignature(const BccPublicKeyInfo& signing_key, + const std::vector& message, + const std::vector& signature) { + if (signing_key.signature_algorithm == kBccEdDsa) { + constexpr size_t kEd25519SignatureLength = 64; + // ED25519 incorporates SHA512 into the signing algorithm. + if (signature.size() != kEd25519SignatureLength) { + AddValidationMessage( + kCborValidateError, + "Signature has unexpected size: " + std::to_string(signature.size())); + return false; + } + EVP_PKEY* pkey = nullptr; + if ((pkey = EVP_PKEY_new_raw_public_key( + EVP_PKEY_ED25519, nullptr, + reinterpret_cast(signing_key.key_bytes.data()), + signing_key.key_bytes.size())) == nullptr) { + AddValidationMessage( + kCborValidateError, + "Can not create EVP_PKEY_ED25519 from the public key info."); + return false; + } + EVP_MD_CTX* md_ctx = EVP_MD_CTX_new(); + const bool res = + EVP_DigestVerifyInit(md_ctx, nullptr, nullptr, nullptr, pkey) && + EVP_DigestVerify(md_ctx, signature.data(), signature.size(), + message.data(), message.size()) == 1; + EVP_MD_CTX_free(md_ctx); + EVP_PKEY_free(pkey); + return res; + } + if (signing_key.signature_algorithm == kBccEcdsaSha256 || + signing_key.signature_algorithm == kBccEcdsaSha384) { + const EccCurve curve = (signing_key.signature_algorithm == kBccEcdsaSha256) + ? EccCurve::kEccSecp256r1 + : EccCurve::kEccSecp384r1; + std::unique_ptr key = EccPublicKey::LoadKeyPoint( + curve, reinterpret_cast(signing_key.key_bytes.data()), + signing_key.key_bytes.size()); + if (!key) { + AddValidationMessage(kCborValidateError, + "Can not create ECPublicKey from raw EC KeyPoint."); + return false; + } + const OEMCryptoResult res = key->VerifyRawSignature( + message.data(), message.size(), signature.data(), signature.size()); + return (res == OEMCrypto_SUCCESS); + } + AddValidationMessage(kCborValidateError, + "Unknown signature algorithm: " + + std::to_string(signing_key.signature_algorithm)); + return false; +} + CborMessageStatus BccValidator::Validate() { if (message_status_ != kCborParseOk) return message_status_; const cppbor::Item* parsed_bcc = std::get<0>(parse_result()).get(); @@ -164,24 +223,26 @@ CborMessageStatus BccValidator::Validate() { // The first element in the array contains the root device public key // definition. - const cppbor::Map* device_public_key_info = (*bcc_array)[0]->asMap(); - if (device_public_key_info == nullptr) { + const cppbor::Map* device_public_key_map = (*bcc_array)[0]->asMap(); + if (device_public_key_map == nullptr) { AddValidationMessage( kCborValidateFatal, "Device public key info is not a CBOR map. Actual type: " + CppborMajorTypeToString((*bcc_array)[0]->type())); return message_status_; } - std::vector key_value_texts; - std::string device_public_key_bytes; + BccPublicKeyInfo root_pub_key; + std::vector key_value_texts; // for pretty print CborMessageStatus status = ProcessSubjectPublicKeyInfo( - *device_public_key_info, key_value_texts, &device_public_key_bytes); + *device_public_key_map, key_value_texts, &root_pub_key); AddMessages(msg_ss_, key_value_texts, 1); if (status == kCborValidateFatal) return status; + BccPublicKeyInfo leaf_pub_key = root_pub_key; msg_ss_ << "BCC ENTRY:\n"; - // Parse each certificate in the chain. The structure of thr entries are - // COSE_Sign1 (untagged). + // Parse and verify each certificate in the chain. The structure of thr + // entries are COSE_Sign1 (untagged). leaf_pub_key is being updated while we + // process the chain. for (size_t i = 1; i < bcc_array->size(); ++i) { msg_ss_ << "- CDI PUBLIC KEY INDEX: " << i << "\n"; const cppbor::Array* bcc_entry = (*bcc_array)[i]->asArray(); @@ -205,25 +266,48 @@ CborMessageStatus BccValidator::Validate() { return message_status_; } - const std::vector& key_payload = - (*bcc_entry)[2]->asBstr()->value(); + // Signature verification Step 1: construct and encode signature input + const std::vector& protected_bytes = + (*bcc_entry)[0]->asBstr()->value(); + // Index 1 is unprotected parameters, which is ignored. + const std::vector& payload = (*bcc_entry)[2]->asBstr()->value(); + const std::vector& actual_signature = + (*bcc_entry)[3]->asBstr()->value(); + + const std::vector signature_input = + cppbor::Array() + .add(kSignatureContextString) + .add(protected_bytes) + .add(/* AAD */ std::vector()) + .add(payload) + .encode(); + + // Signature verification Step 2: verify + if (!VerifySignature(leaf_pub_key, signature_input, actual_signature)) { + AddValidationMessage( + kCborValidateError, + "Failed to verify the signature for BCC entry index: " + + std::to_string(i)); + } + key_value_texts.clear(); - std::string entry_public_key_bytes; - status = ProcessDiceChainEntryPayload(key_payload, key_value_texts, - &entry_public_key_bytes); + BccPublicKeyInfo entry_pub_key; + status = + ProcessDiceChainEntryPayload(payload, key_value_texts, &entry_pub_key); AddMessages(msg_ss_, key_value_texts, 1); if (status == kCborValidateFatal) return status; - // If the size of the BCC array (including device pub key) is 2, then it - // must be a de-generated BCC, which means the second element in the array - // is a self-signed entry. The entry's public key should be identical to the - // device's public key. - if (bcc_array->size() == 2 && i == 1) { - // self-signed BCC entry - if (entry_public_key_bytes != device_public_key_bytes) { - AddValidationMessage(kCborValidateError, - "The public key of a self-signed entry should be " - "identical to its device public key."); - } + leaf_pub_key = std::move(entry_pub_key); + } + // If the size of the BCC array (including device pub key) is 2, then it + // must be a de-generated BCC, which means the second element in the array + // is a self-signed entry. The entry's public key should be identical to the + // device's public key. + if (bcc_array->size() == 2) { + // self-signed BCC entry + if (leaf_pub_key.key_bytes != root_pub_key.key_bytes) { + AddValidationMessage(kCborValidateError, + "The public key of a self-signed entry should be " + "identical to its device public key."); } } msg_ss_ << "...\n"; @@ -233,10 +317,10 @@ CborMessageStatus BccValidator::Validate() { CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( const cppbor::Map& public_key_info_map, std::vector& fmt_msgs, - std::string* public_key_bytes) { + BccPublicKeyInfo* public_key_info) { int key_encoding_format = DEVICE_KEY_ENCODING_UNKNOWN; - std::string device_key_bytes_0; - std::string device_key_bytes_1; + std::vector device_key_bytes_0; + std::vector device_key_bytes_1; std::unordered_set key_set; for (size_t index = 0; index < public_key_info_map.size(); ++index) { std::pair&, @@ -289,10 +373,13 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( const int64_t value = entry.second->asNint()->value(); if (value == DEVICE_KEY_ALGORITHM_ES256) { kv += "ECDSA_SHA256"; + public_key_info->signature_algorithm = kBccEcdsaSha256; } else if (value == DEVICE_KEY_ALGORITHM_ES384) { kv += "ECDSA_SHA384"; + public_key_info->signature_algorithm = kBccEcdsaSha384; } else if (value == DEVICE_KEY_ALGORITHM_EDDSA) { kv += "EDDSA"; + public_key_info->signature_algorithm = kBccEdDsa; } else { AddValidationMessage(kCborValidateError, "Invalid value in public key info map for key " @@ -316,10 +403,13 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( std::string kv = "curve: "; const int64_t value = entry.second->asUint()->value(); if (value == DEVICE_KEY_CURVE_P256) { + public_key_info->curve = kBccP256; kv += "P256"; } else if (value == DEVICE_KEY_CURVE_P384) { + public_key_info->curve = kBccP384; kv += "P384"; } else if (value == DEVICE_KEY_CURVE_ED25519) { + public_key_info->curve = kBccEd25519; kv += "ED25519"; } else { AddValidationMessage(kCborValidateError, @@ -351,10 +441,11 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( std::to_string(key_bytes.size())); return kCborValidateFatal; } - std::string& key_bytes_str = map_key == MAP_KEY_DEVICE_KEY_BYTES_0 - ? device_key_bytes_0 - : device_key_bytes_1; - key_bytes_str.assign(key_bytes.begin(), key_bytes.end()); + if (map_key == MAP_KEY_DEVICE_KEY_BYTES_0) { + device_key_bytes_0 = key_bytes; + } else { + device_key_bytes_1 = key_bytes; + } } key_set.insert(map_key); } @@ -378,28 +469,34 @@ CborMessageStatus BccValidator::ProcessSubjectPublicKeyInfo( "Malformed public key definition. Missing device public key bytes."); return kCborValidateFatal; } - std::string device_key_bytes; + std::vector device_key_bytes; if (key_encoding_format == DEVICE_KEY_OCTET_PAIR) { // Key is an ECDSA elliptic key. We need to return the ANSI X9.62 // marshaled public key. Generate the marshaled key if needed. The // marshaled key is needed to create an ECPublicKey object. - // std::string* device_key_bytes = public_key_info.mutable_key_bytes(); - device_key_bytes.reserve(kMaxMarshaledECKeySize); - device_key_bytes.resize(1); - device_key_bytes[0] = kMarshaledECKeyZValue; - device_key_bytes.append(device_key_bytes_0); - device_key_bytes.append(device_key_bytes_1); + device_key_bytes.push_back(kMarshaledECKeyZValue); + device_key_bytes.insert(device_key_bytes.end(), device_key_bytes_0.begin(), + device_key_bytes_0.end()); + device_key_bytes.insert(device_key_bytes.end(), device_key_bytes_1.begin(), + device_key_bytes_1.end()); + if (device_key_bytes.size() != kMarshaledP384KeySize && + device_key_bytes.size() != kMarshaledP256KeySize) { + AddValidationMessage(kCborValidateFatal, + "Invalid ECDSA public key size: " + + std::to_string(device_key_bytes.size())); + return kCborValidateFatal; + } } else { - device_key_bytes = device_key_bytes_0; + device_key_bytes = std::move(device_key_bytes_0); } fmt_msgs.push_back("public key bytes: " + wvutil::b2a_hex(device_key_bytes)); - *public_key_bytes = device_key_bytes; + public_key_info->key_bytes = std::move(device_key_bytes); return message_status_; } CborMessageStatus BccValidator::ProcessDiceChainEntryPayload( const std::vector& payload, std::vector& fmt_msgs, - std::string* entry_public_key_bytes) { + BccPublicKeyInfo* entry_public_key_info) { if (payload.empty()) { AddValidationMessage(kCborValidateFatal, "Empty bcc entry payload."); return kCborValidateFatal; @@ -449,7 +546,7 @@ CborMessageStatus BccValidator::ProcessDiceChainEntryPayload( return kCborValidateFatal; } return ProcessSubjectPublicKeyInfo(*subject_public_key_info, fmt_msgs, - entry_public_key_bytes); + entry_public_key_info); } std::string BccValidator::GetFormattedMessage() const { diff --git a/libwvdrmengine/oemcrypto/util/src/oemcrypto_ecc_key.cpp b/libwvdrmengine/oemcrypto/util/src/oemcrypto_ecc_key.cpp index e226ed3a..47a4655d 100644 --- a/libwvdrmengine/oemcrypto/util/src/oemcrypto_ecc_key.cpp +++ b/libwvdrmengine/oemcrypto/util/src/oemcrypto_ecc_key.cpp @@ -44,6 +44,7 @@ using ScopedEvpPkey = ScopedObject; using ScopedPrivateKeyInfo = ScopedObject; using ScopedSigPoint = ScopedObject; +using ScopedEcPoint = ScopedObject; 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::LoadPrivateKeyInfo( return LoadPrivateKeyInfo(buffer.data(), buffer.size()); } +// static +std::unique_ptr 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 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 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(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(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 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(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::New(EccCurve curve) { std::unique_ptr key(new EccPrivateKey());