264 lines
7.0 KiB
Diff
264 lines
7.0 KiB
Diff
|
|
From d2d35d1acb89d4113647a9aad2d049808112b935 Mon Sep 17 00:00:00 2001
|
||
|
|
From: Michael Schroeder <mls@suse.de>
|
||
|
|
Date: Wed, 17 Apr 2024 14:07:53 +0200
|
||
|
|
Subject: [PATCH] Add ECDSA support to digest_openssl
|
||
|
|
|
||
|
|
Conflict:modify digest_openssl.c in rpmio; adapt context
|
||
|
|
Reference:https://github.com/rpm-software-management/rpmpgp_legacy/commit/783a5ea3851b8509eb11a4998d6e4ea41cc7ba38
|
||
|
|
---
|
||
|
|
rpmio/digest_openssl.c | 208 ++++++++++++++++++++++++++++++++++++++++-
|
||
|
|
1 file changed, 207 insertions(+), 1 deletion(-)
|
||
|
|
|
||
|
|
diff --git a/rpmio/digest_openssl.c b/rpmio/digest_openssl.c
|
||
|
|
index 4d930c9..c8eb15f 100644
|
||
|
|
--- a/rpmio/digest_openssl.c
|
||
|
|
+++ b/rpmio/digest_openssl.c
|
||
|
|
@@ -6,6 +6,7 @@
|
||
|
|
#endif
|
||
|
|
#include <openssl/rsa.h>
|
||
|
|
#include <openssl/dsa.h>
|
||
|
|
+#include <openssl/ec.h>
|
||
|
|
|
||
|
|
#include <rpm/rpmcrypto.h>
|
||
|
|
#include "rpmio/rpmpgp_internal.h"
|
||
|
|
@@ -801,6 +802,181 @@ done:
|
||
|
|
return rc;
|
||
|
|
}
|
||
|
|
|
||
|
|
+/****************************** ECDSA ***************************************/
|
||
|
|
+
|
||
|
|
+struct pgpDigKeyECDSA_s {
|
||
|
|
+ EVP_PKEY *evp_pkey; /* Fully constructed key */
|
||
|
|
+ unsigned char *q; /* compressed point */
|
||
|
|
+ int qlen;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static int constructECDSASigningKey(struct pgpDigKeyECDSA_s *key, int curve)
|
||
|
|
+{
|
||
|
|
+ if (key->evp_pkey)
|
||
|
|
+ return 1; /* We've already constructed it, so just reuse it */
|
||
|
|
+
|
||
|
|
+#if OPENSSL_VERSION_MAJOR >= 3
|
||
|
|
+ if (curve == PGPCURVE_NIST_P_256) {
|
||
|
|
+ OSSL_PARAM params[] = {
|
||
|
|
+ OSSL_PARAM_utf8_string("group", "P-256", 5),
|
||
|
|
+ OSSL_PARAM_octet_string("pub", key->q, key->qlen),
|
||
|
|
+ OSSL_PARAM_END
|
||
|
|
+ };
|
||
|
|
+ key->evp_pkey = construct_pkey_from_param(EVP_PKEY_EC, params);
|
||
|
|
+ } else if (curve == PGPCURVE_NIST_P_384) {
|
||
|
|
+ OSSL_PARAM params[] = {
|
||
|
|
+ OSSL_PARAM_utf8_string("group", "P-384", 5),
|
||
|
|
+ OSSL_PARAM_octet_string("pub", key->q, key->qlen),
|
||
|
|
+ OSSL_PARAM_END
|
||
|
|
+ };
|
||
|
|
+ key->evp_pkey = construct_pkey_from_param(EVP_PKEY_EC, params);
|
||
|
|
+ }
|
||
|
|
+ return key->evp_pkey ? 1 : 0;
|
||
|
|
+#else
|
||
|
|
+ /* Create the EC key */
|
||
|
|
+ EC_KEY *ec = NULL;
|
||
|
|
+ if (curve == PGPCURVE_NIST_P_256)
|
||
|
|
+ ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||
|
|
+ else if (curve == PGPCURVE_NIST_P_384)
|
||
|
|
+ ec = EC_KEY_new_by_curve_name(NID_secp384r1);
|
||
|
|
+ if (!ec)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ if (!EC_KEY_oct2key(ec, key->q, key->qlen, NULL))
|
||
|
|
+ goto exit;
|
||
|
|
+
|
||
|
|
+ /* Create an EVP_PKEY container to abstract the key-type. */
|
||
|
|
+ if (!(key->evp_pkey = EVP_PKEY_new()))
|
||
|
|
+ goto exit;
|
||
|
|
+
|
||
|
|
+ /* Assign the EC key to the EVP_PKEY structure.
|
||
|
|
+ This will take over memory management of the RSA key */
|
||
|
|
+ if (!EVP_PKEY_assign_EC_KEY(key->evp_pkey, ec)) {
|
||
|
|
+ EVP_PKEY_free(key->evp_pkey);
|
||
|
|
+ key->evp_pkey = NULL;
|
||
|
|
+ goto exit;
|
||
|
|
+ }
|
||
|
|
+ return 1;
|
||
|
|
+
|
||
|
|
+exit:
|
||
|
|
+ EC_KEY_free(ec);
|
||
|
|
+ return 0;
|
||
|
|
+#endif
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int pgpSetKeyMpiECDSA(pgpDigAlg pgpkey, int num, const uint8_t *p)
|
||
|
|
+{
|
||
|
|
+ size_t mlen = pgpMpiLen(p) - 2;
|
||
|
|
+ struct pgpDigKeyECDSA_s *key = pgpkey->data;
|
||
|
|
+ int rc = 1;
|
||
|
|
+
|
||
|
|
+ if (!key)
|
||
|
|
+ key = pgpkey->data = xcalloc(1, sizeof(*key));
|
||
|
|
+ if (num == 0 && !key->q && mlen > 1 && p[2] == 0x04) {
|
||
|
|
+ key->qlen = mlen;
|
||
|
|
+ key->q = xmalloc(key->qlen);
|
||
|
|
+ memcpy(key->q, p + 2, key->qlen),
|
||
|
|
+ rc = 0;
|
||
|
|
+ }
|
||
|
|
+ return rc;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void pgpFreeKeyECDSA(pgpDigAlg pgpkey)
|
||
|
|
+{
|
||
|
|
+ struct pgpDigKeyECDSA_s *key = pgpkey->data;
|
||
|
|
+ if (key) {
|
||
|
|
+ if (key->q)
|
||
|
|
+ free(key->q);
|
||
|
|
+ if (key->evp_pkey)
|
||
|
|
+ EVP_PKEY_free(key->evp_pkey);
|
||
|
|
+ free(key);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+struct pgpDigSigECDSA_s {
|
||
|
|
+ unsigned char *r;
|
||
|
|
+ int rlen;
|
||
|
|
+ unsigned char *s;
|
||
|
|
+ int slen;
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static int pgpSetSigMpiECDSA(pgpDigAlg pgpsig, int num, const uint8_t *p)
|
||
|
|
+{
|
||
|
|
+ int mlen = pgpMpiLen(p) - 2;
|
||
|
|
+ int rc = 1;
|
||
|
|
+
|
||
|
|
+ struct pgpDigSigECDSA_s *sig = pgpsig->data;
|
||
|
|
+ if (!sig) {
|
||
|
|
+ sig = xcalloc(1, sizeof(*sig));
|
||
|
|
+ pgpsig->data = sig;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ switch (num) {
|
||
|
|
+ case 0:
|
||
|
|
+ if (sig->r)
|
||
|
|
+ return 1; /* This should only ever happen once per signature */
|
||
|
|
+ sig->rlen = mlen;
|
||
|
|
+ sig->r = memcpy(xmalloc(mlen), p + 2, mlen);
|
||
|
|
+ rc = 0;
|
||
|
|
+ break;
|
||
|
|
+ case 1:
|
||
|
|
+ if (sig->s)
|
||
|
|
+ return 1; /* This should only ever happen once per signature */
|
||
|
|
+ sig->slen = mlen;
|
||
|
|
+ sig->s = memcpy(xmalloc(mlen), p + 2, mlen);
|
||
|
|
+ rc = 0;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return rc;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static void pgpFreeSigECDSA(pgpDigAlg pgpsig)
|
||
|
|
+{
|
||
|
|
+ struct pgpDigSigECDSA_s *sig = pgpsig->data;
|
||
|
|
+ if (sig) {
|
||
|
|
+ free(sig->r);
|
||
|
|
+ free(sig->s);
|
||
|
|
+ }
|
||
|
|
+ free(pgpsig->data);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static int pgpVerifySigECDSA(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||
|
|
+ uint8_t *hash, size_t hashlen, int hash_algo)
|
||
|
|
+{
|
||
|
|
+ int rc = 1; /* assume failure */
|
||
|
|
+ struct pgpDigSigECDSA_s *sig = pgpsig->data;
|
||
|
|
+ struct pgpDigKeyECDSA_s *key = pgpkey->data;
|
||
|
|
+ unsigned char *xsig = NULL; /* signature encoded for X509 */
|
||
|
|
+ size_t xsig_len = 0;
|
||
|
|
+ EVP_PKEY_CTX *pkey_ctx = NULL;
|
||
|
|
+
|
||
|
|
+ if (!constructECDSASigningKey(key, pgpkey->curve))
|
||
|
|
+ goto done;
|
||
|
|
+
|
||
|
|
+ xsig = constructDSASignature(sig->r, sig->rlen, sig->s, sig->slen, &xsig_len);
|
||
|
|
+ if (!xsig)
|
||
|
|
+ goto done;
|
||
|
|
+
|
||
|
|
+ pkey_ctx = EVP_PKEY_CTX_new(key->evp_pkey, NULL);
|
||
|
|
+ if (!pkey_ctx)
|
||
|
|
+ goto done;
|
||
|
|
+
|
||
|
|
+ if (EVP_PKEY_verify_init(pkey_ctx) != 1)
|
||
|
|
+ goto done;
|
||
|
|
+
|
||
|
|
+ if (EVP_PKEY_verify(pkey_ctx, xsig, xsig_len, hash, hashlen) == 1)
|
||
|
|
+ {
|
||
|
|
+ /* Success */
|
||
|
|
+ rc = 0;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+done:
|
||
|
|
+ if (pkey_ctx)
|
||
|
|
+ EVP_PKEY_CTX_free(pkey_ctx);
|
||
|
|
+ free(xsig);
|
||
|
|
+ return rc;
|
||
|
|
+}
|
||
|
|
|
||
|
|
/****************************** EDDSA ***************************************/
|
||
|
|
|
||
|
|
@@ -912,6 +1088,19 @@ static int pgpVerifyNULL(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
+static int pgpSupportedCurve(int algo, int curve)
|
||
|
|
+{
|
||
|
|
+#ifdef EVP_PKEY_ED25519
|
||
|
|
+ if (algo == PGPPUBKEYALGO_EDDSA && curve == PGPCURVE_ED25519)
|
||
|
|
+ return 1;
|
||
|
|
+#endif
|
||
|
|
+ if (algo == PGPPUBKEYALGO_ECDSA && curve == PGPCURVE_NIST_P_256)
|
||
|
|
+ return 1;
|
||
|
|
+ if (algo == PGPPUBKEYALGO_ECDSA && curve == PGPCURVE_NIST_P_384)
|
||
|
|
+ return 1;
|
||
|
|
+ return 0;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
/****************************** PGP **************************************/
|
||
|
|
pgpDigAlg pgpPubkeyNew(int algo, int curve)
|
||
|
|
{
|
||
|
|
@@ -928,9 +1117,20 @@ pgpDigAlg pgpPubkeyNew(int algo, int curve)
|
||
|
|
ka->free = pgpFreeKeyDSA;
|
||
|
|
ka->mpis = 4;
|
||
|
|
break;
|
||
|
|
+ case PGPPUBKEYALGO_ECDSA:
|
||
|
|
+ if (!pgpSupportedCurve(algo, curve)) {
|
||
|
|
+ ka->setmpi = pgpSetMpiNULL;
|
||
|
|
+ ka->mpis = -1;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ ka->setmpi = pgpSetKeyMpiECDSA;
|
||
|
|
+ ka->free = pgpFreeKeyECDSA;
|
||
|
|
+ ka->mpis = 1;
|
||
|
|
+ ka->curve = curve;
|
||
|
|
+ break;
|
||
|
|
#ifdef EVP_PKEY_ED25519
|
||
|
|
case PGPPUBKEYALGO_EDDSA:
|
||
|
|
- if (curve != PGPCURVE_ED25519) {
|
||
|
|
+ if (!pgpSupportedCurve(algo, curve)) {
|
||
|
|
ka->setmpi = pgpSetMpiNULL; /* unsupported curve */
|
||
|
|
ka->mpis = -1;
|
||
|
|
break;
|
||
|
|
@@ -969,6 +1169,12 @@ pgpDigAlg pgpSignatureNew(int algo)
|
||
|
|
sa->verify = pgpVerifySigDSA;
|
||
|
|
sa->mpis = 2;
|
||
|
|
break;
|
||
|
|
+ case PGPPUBKEYALGO_ECDSA:
|
||
|
|
+ sa->setmpi = pgpSetSigMpiECDSA;
|
||
|
|
+ sa->free = pgpFreeSigECDSA;
|
||
|
|
+ sa->verify = pgpVerifySigECDSA;
|
||
|
|
+ sa->mpis = 2;
|
||
|
|
+ break;
|
||
|
|
#ifdef EVP_PKEY_ED25519
|
||
|
|
case PGPPUBKEYALGO_EDDSA:
|
||
|
|
sa->setmpi = pgpSetSigMpiEDDSA;
|
||
|
|
--
|
||
|
|
2.23.0
|
||
|
|
|