summaryrefslogtreecommitdiff
path: root/cppcose/cppcose.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cppcose/cppcose.cpp')
-rw-r--r--cppcose/cppcose.cpp124
1 files changed, 79 insertions, 45 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