summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Scull <ascull@google.com>2023-02-17 17:34:58 +0000
committerAndrew Scull <ascull@google.com>2023-02-23 21:23:10 +0000
commitb1d26dda82a7f56f2907673d73d9525e32c6fec6 (patch)
treed440e2ad5f43a4c2d81760d054824896fc8324aa
parentc2c3ed21299a517d83c01f677b1ac9a473ad11bf (diff)
downloadkeymaster-b1d26dda82a7f56f2907673d73d9525e32c6fec6.tar.gz
Add support for P-384 CoseKeys
RKP allows P-384 to be used in the DICE chain and for signing CSRs. Add support for this algorithm so that the VTS tests will pass on devices that use P-384. Bug: 261647022 Test: atest VtsHalRemotelyProvisionedComponentTargetTest Change-Id: I2fb6f1ef1a111d7c6ee057217dcc1c4d36391a78
-rw-r--r--cppcose/cppcose.cpp124
-rw-r--r--include/keymaster/cppcose/cppcose.h22
2 files changed, 96 insertions, 50 deletions
diff --git a/cppcose/cppcose.cpp b/cppcose/cppcose.cpp
index 411dc01..2eb39de 100644
--- a/cppcose/cppcose.cpp
+++ b/cppcose/cppcose.cpp
@@ -27,6 +27,7 @@
namespace cppcose {
constexpr int kP256AffinePointSize = 32;
+constexpr int kP384AffinePointSize = 48;
using EVP_PKEY_Ptr = bssl::UniquePtr<EVP_PKEY>;
using EVP_PKEY_CTX_Ptr = bssl::UniquePtr<EVP_PKEY_CTX>;
@@ -58,7 +59,7 @@ ErrMsgOr<bssl::UniquePtr<EVP_CIPHER_CTX>> aesGcmInitAndProcessAad(const bytevec&
return std::move(ctx);
}
-ErrMsgOr<bytevec> signEcdsaDigest(const bytevec& key, const bytevec& data) {
+ErrMsgOr<bytevec> signP256Digest(const bytevec& key, const bytevec& data) {
auto bn = BIGNUM_Ptr(BN_bin2bn(key.data(), key.size(), nullptr));
if (bn.get() == nullptr) {
return "Error creating BIGNUM";
@@ -141,19 +142,17 @@ ErrMsgOr<bytevec> ecdh(const bytevec& publicKey, const bytevec& privateKey) {
return sharedSecret;
}
-} // namespace
-
-ErrMsgOr<bytevec> ecdsaCoseSignatureToDer(const bytevec& ecdsaCoseSignature) {
- if (ecdsaCoseSignature.size() != 64) {
+ErrMsgOr<bytevec> ecdsaCoseSignatureToDer(int point_size, const bytevec& ecdsaCoseSignature) {
+ if (ecdsaCoseSignature.size() != (size_t)(point_size * 2)) {
return "COSE signature wrong length";
}
- auto rBn = BIGNUM_Ptr(BN_bin2bn(ecdsaCoseSignature.data(), 32, nullptr));
+ auto rBn = BIGNUM_Ptr(BN_bin2bn(ecdsaCoseSignature.data(), point_size, nullptr));
if (rBn.get() == nullptr) {
return "Error creating BIGNUM for r";
}
- auto sBn = BIGNUM_Ptr(BN_bin2bn(ecdsaCoseSignature.data() + 32, 32, nullptr));
+ auto sBn = BIGNUM_Ptr(BN_bin2bn(ecdsaCoseSignature.data() + point_size, point_size, nullptr));
if (sBn.get() == nullptr) {
return "Error creating BIGNUM for s";
}
@@ -169,23 +168,58 @@ ErrMsgOr<bytevec> ecdsaCoseSignatureToDer(const bytevec& ecdsaCoseSignature) {
return derSignature;
}
-ErrMsgOr<bytevec> ecdsaDerSignatureToCose(const bytevec& ecdsaSignature) {
+ErrMsgOr<bytevec> ecdsaDerSignatureToCose(int point_size, const bytevec& ecdsaSignature) {
const unsigned char* p = ecdsaSignature.data();
auto sig = ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, ecdsaSignature.size()));
if (sig == nullptr) {
return "Error decoding DER signature";
}
- bytevec ecdsaCoseSignature(64, 0);
- if (BN_bn2binpad(ECDSA_SIG_get0_r(sig.get()), ecdsaCoseSignature.data(), 32) != 32) {
+ bytevec ecdsaCoseSignature(point_size * 2, 0);
+ if (BN_bn2binpad(ECDSA_SIG_get0_r(sig.get()), ecdsaCoseSignature.data(), point_size) !=
+ point_size) {
return "Error encoding r";
}
- if (BN_bn2binpad(ECDSA_SIG_get0_s(sig.get()), ecdsaCoseSignature.data() + 32, 32) != 32) {
+ if (BN_bn2binpad(ECDSA_SIG_get0_s(sig.get()), ecdsaCoseSignature.data() + point_size,
+ point_size) != point_size) {
return "Error encoding s";
}
return ecdsaCoseSignature;
}
+bool verifyEcdsaDigest(int curve_nid, const bytevec& key, const bytevec& digest,
+ const bytevec& signature) {
+ const unsigned char* p = (unsigned char*)signature.data();
+ auto sig = ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, signature.size()));
+ if (sig.get() == nullptr) {
+ return false;
+ }
+
+ auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(curve_nid));
+ auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+ if (EC_POINT_oct2point(group.get(), point.get(), key.data(), key.size(), nullptr) != 1) {
+ return false;
+ }
+ auto ecKey = EC_KEY_Ptr(EC_KEY_new());
+ if (ecKey.get() == nullptr) {
+ return false;
+ }
+ if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
+ return false;
+ }
+ if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
+ return false;
+ }
+
+ int rc = ECDSA_do_verify(digest.data(), digest.size(), sig.get(), ecKey.get());
+ if (rc != 1) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
ErrMsgOr<HmacSha256> generateHmacSha256(const bytevec& key, const bytevec& data) {
HmacSha256 digest;
unsigned int outLen;
@@ -275,10 +309,10 @@ ErrMsgOr<bytevec> createECDSACoseSign1Signature(const bytevec& key, const byteve
.add(aad)
.add(payload)
.encode();
- auto ecdsaSignature = signEcdsaDigest(key, sha256(signatureInput));
+ auto ecdsaSignature = signP256Digest(key, sha256(signatureInput));
if (!ecdsaSignature) return ecdsaSignature.moveMessage();
- return ecdsaDerSignatureToCose(*ecdsaSignature);
+ return ecdsaDerSignatureToCose(kP256AffinePointSize, *ecdsaSignature);
}
ErrMsgOr<bytevec> createCoseSign1Signature(const bytevec& key, const bytevec& protectedParams,
@@ -354,7 +388,8 @@ ErrMsgOr<bytevec> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
auto& algorithm = parsedProtParams->asMap()->get(ALGORITHM);
if (!algorithm || !algorithm->asInt() ||
- !(algorithm->asInt()->value() == EDDSA || algorithm->asInt()->value() == ES256)) {
+ !(algorithm->asInt()->value() == EDDSA || algorithm->asInt()->value() == ES256 ||
+ algorithm->asInt()->value() == ES384)) {
return "Unsupported signature algorithm";
}
@@ -376,7 +411,7 @@ ErrMsgOr<bytevec> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
key->getBstrValue(CoseKey::PUBKEY_X)->data())) {
return "Signature verification failed";
}
- } else { // P256
+ } else if (algorithm->asInt()->value() == ES256) {
auto key = CoseKey::parseP256(selfSigned ? payload->value() : signingCoseKey);
if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
@@ -385,13 +420,33 @@ ErrMsgOr<bytevec> verifyAndParseCoseSign1(const cppbor::Array* coseSign1,
auto publicKey = key->getEcPublicKey();
if (!publicKey) return publicKey.moveMessage();
- auto ecdsaDerSignature = ecdsaCoseSignatureToDer(signature->value());
+ auto ecdsaDerSignature = ecdsaCoseSignatureToDer(kP256AffinePointSize, signature->value());
+ if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();
+
+ // convert public key to uncompressed form by prepending 0x04 at begin.
+ publicKey->insert(publicKey->begin(), 0x04);
+
+ if (!verifyEcdsaDigest(NID_X9_62_prime256v1, publicKey.moveValue(), sha256(signatureInput),
+ *ecdsaDerSignature)) {
+ return "Signature verification failed";
+ }
+ } else { // ES384
+ auto key = CoseKey::parseP384(selfSigned ? payload->value() : signingCoseKey);
+ if (!key || key->getBstrValue(CoseKey::PUBKEY_X)->empty() ||
+ key->getBstrValue(CoseKey::PUBKEY_Y)->empty()) {
+ return "Bad signing key: " + key.moveMessage();
+ }
+ auto publicKey = key->getEcPublicKey();
+ if (!publicKey) return publicKey.moveMessage();
+
+ auto ecdsaDerSignature = ecdsaCoseSignatureToDer(kP384AffinePointSize, signature->value());
if (!ecdsaDerSignature) return ecdsaDerSignature.moveMessage();
// convert public key to uncompressed form by prepending 0x04 at begin.
publicKey->insert(publicKey->begin(), 0x04);
- if (!verifyEcdsaDigest(publicKey.moveValue(), sha256(signatureInput), *ecdsaDerSignature)) {
+ if (!verifyEcdsaDigest(NID_secp384r1, publicKey.moveValue(), sha384(signatureInput),
+ *ecdsaDerSignature)) {
return "Signature verification failed";
}
}
@@ -708,34 +763,13 @@ bytevec sha256(const bytevec& data) {
return ret;
}
-bool verifyEcdsaDigest(const bytevec& key, const bytevec& digest, const bytevec& signature) {
- const unsigned char* p = (unsigned char*)signature.data();
- auto sig = ECDSA_SIG_Ptr(d2i_ECDSA_SIG(nullptr, &p, signature.size()));
- if (sig.get() == nullptr) {
- return false;
- }
-
- auto group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- auto point = EC_POINT_Ptr(EC_POINT_new(group.get()));
- if (EC_POINT_oct2point(group.get(), point.get(), key.data(), key.size(), nullptr) != 1) {
- return false;
- }
- auto ecKey = EC_KEY_Ptr(EC_KEY_new());
- if (ecKey.get() == nullptr) {
- return false;
- }
- if (EC_KEY_set_group(ecKey.get(), group.get()) != 1) {
- return false;
- }
- if (EC_KEY_set_public_key(ecKey.get(), point.get()) != 1) {
- return false;
- }
-
- int rc = ECDSA_do_verify(digest.data(), digest.size(), sig.get(), ecKey.get());
- if (rc != 1) {
- return false;
- }
- return true;
+bytevec sha384(const bytevec& data) {
+ bytevec ret(SHA384_DIGEST_LENGTH);
+ SHA512_CTX ctx;
+ SHA384_Init(&ctx);
+ SHA384_Update(&ctx, data.data(), data.size());
+ SHA384_Final((unsigned char*)ret.data(), &ctx);
+ return ret;
}
} // namespace cppcose
diff --git a/include/keymaster/cppcose/cppcose.h b/include/keymaster/cppcose/cppcose.h
index c000ebe..fa5916f 100644
--- a/include/keymaster/cppcose/cppcose.h
+++ b/include/keymaster/cppcose/cppcose.h
@@ -81,9 +81,10 @@ enum CoseKeyAlgorithm : int {
ES256 = -7, // ECDSA with SHA-256
EDDSA = -8,
ECDH_ES_HKDF_256 = -25,
+ ES384 = -35, // ECDSA with SHA-384
};
-enum CoseKeyCurve : int { P256 = 1, X25519 = 4, ED25519 = 6 };
+enum CoseKeyCurve : int { P256 = 1, P384 = 2, X25519 = 4, ED25519 = 6 };
enum CoseKeyType : int { OCTET_KEY_PAIR = 1, EC2 = 2, SYMMETRIC_KEY = 4 };
enum CoseKeyOps : int { SIGN = 1, VERIFY = 2, ENCRYPT = 3, DECRYPT = 4 };
@@ -213,6 +214,20 @@ class CoseKey {
return key;
}
+ static ErrMsgOr<CoseKey> parseP384(const bytevec& coseKey) {
+ auto key = parse(coseKey, EC2, ES384, P384);
+ if (!key) return key;
+
+ auto& pubkey_x = key->getMap().get(PUBKEY_X);
+ auto& pubkey_y = key->getMap().get(PUBKEY_Y);
+ if (!pubkey_x || !pubkey_y || !pubkey_x->asBstr() || !pubkey_y->asBstr() ||
+ pubkey_x->asBstr()->value().size() != 48 || pubkey_y->asBstr()->value().size() != 48) {
+ return "Invalid P384 public key";
+ }
+
+ return key;
+ }
+
static ErrMsgOr<bytevec> getEcPublicKey(const bytevec& pubX, const bytevec& pubY) {
if (pubX.empty() || pubY.empty()) {
return "Missing input parameters";
@@ -285,9 +300,6 @@ ErrMsgOr<cppbor::Array> constructECDSACoseSign1(const bytevec& key,
cppbor::Map extraProtectedFields,
const bytevec& payload, const bytevec& aad);
-ErrMsgOr<bytevec> ecdsaCoseSignatureToDer(const bytevec& ecdsaCoseSignature);
-
-ErrMsgOr<bytevec> ecdsaDerSignatureToCose(const bytevec& ecdsaSignature);
/**
* Verify and parse a COSE_Sign1 message, returning the payload.
*
@@ -320,8 +332,8 @@ ErrMsgOr<bytevec> x25519_HKDF_DeriveKey(const bytevec& senderPubKey, const bytev
const bytevec& recipientPubKey, bool senderIsA);
ErrMsgOr<bytevec> ECDH_HKDF_DeriveKey(const bytevec& pubKeyA, const bytevec& privKeyA,
const bytevec& pubKeyB, bool senderIsA);
-bool verifyEcdsaDigest(const bytevec& key, const bytevec& digest, const bytevec& signature);
bytevec sha256(const bytevec& data);
+bytevec sha384(const bytevec& data);
ErrMsgOr<bytevec /* ciphertextWithTag */> aesGcmEncrypt(const bytevec& key, const bytevec& nonce,
const bytevec& aad,
const bytevec& plaintext);