Convert RSA and ECDSA key to the libcrypto EVP_PKEY API. DSA remains
authordjm <djm@openbsd.org>
Thu, 15 Aug 2024 00:51:51 +0000 (00:51 +0000)
committerdjm <djm@openbsd.org>
Thu, 15 Aug 2024 00:51:51 +0000 (00:51 +0000)
unconverted as it will be removed within six months.

Based on patches originally from Dmitry Belyavskiy, but significantly
reworked based on feedback from Bob Beck, Joel Sing and especially
Theo Buehler (apologies to anyone I've missed).

ok tb@

14 files changed:
usr.bin/ssh/packet.c
usr.bin/ssh/packet.h
usr.bin/ssh/ssh-ecdsa-sk.c
usr.bin/ssh/ssh-ecdsa.c
usr.bin/ssh/ssh-keygen.c
usr.bin/ssh/ssh-pkcs11-client.c
usr.bin/ssh/ssh-pkcs11-helper.c
usr.bin/ssh/ssh-pkcs11.c
usr.bin/ssh/ssh-rsa.c
usr.bin/ssh/ssh-sk.c
usr.bin/ssh/sshbuf-getput-crypto.c
usr.bin/ssh/sshbuf.h
usr.bin/ssh/sshkey.c
usr.bin/ssh/sshkey.h

index 70c98dd..07e7e1d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.315 2024/05/31 08:49:35 djm Exp $ */
+/* $OpenBSD: packet.c,v 1.316 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -2617,6 +2617,11 @@ sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g)
        return sshbuf_put_ec(ssh->state->outgoing_packet, v, g);
 }
 
+int
+sshpkt_put_ec_pkey(struct ssh *ssh, EVP_PKEY *pkey)
+{
+       return sshbuf_put_ec_pkey(ssh->state->outgoing_packet, pkey);
+}
 
 int
 sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v)
index fc2c327..db61136 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.h,v 1.98 2024/05/17 06:42:04 jsg Exp $ */
+/* $OpenBSD: packet.h,v 1.99 2024/08/15 00:51:51 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
 #include <openssl/bn.h>
 #include <openssl/ec.h>
 #include <openssl/ecdsa.h>
+#include <openssl/evp.h>
 #else /* OPENSSL */
 #define BIGNUM         void
 #define EC_GROUP       void
 #define EC_POINT       void
+#define EVP_PKEY       void
 #endif /* WITH_OPENSSL */
 
 struct kex;
@@ -185,6 +187,7 @@ int sshpkt_put_string(struct ssh *ssh, const void *v, size_t len);
 int    sshpkt_put_cstring(struct ssh *ssh, const void *v);
 int    sshpkt_put_stringb(struct ssh *ssh, const struct sshbuf *v);
 int    sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g);
+int    sshpkt_put_ec_pkey(struct ssh *ssh, EVP_PKEY *pkey);
 int    sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v);
 
 int    sshpkt_get(struct ssh *ssh, void *valp, size_t len);
index 15e993c..0502a49 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa-sk.c,v 1.18 2023/03/08 04:43:12 guenther Exp $ */
+/* $OpenBSD: ssh-ecdsa-sk.c,v 1.19 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -219,11 +219,13 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
     struct sshkey_sig_details **detailsp)
 {
        ECDSA_SIG *esig = NULL;
+       EVP_MD_CTX *md_ctx = NULL;
        BIGNUM *sig_r = NULL, *sig_s = NULL;
        u_char sig_flags;
-       u_char msghash[32], apphash[32], sighash[32];
+       u_char msghash[32], apphash[32];
        u_int sig_counter;
-       int is_webauthn = 0, ret = SSH_ERR_INTERNAL_ERROR;
+       u_char *sigb = NULL, *cp;
+       int is_webauthn = 0, ret = SSH_ERR_INTERNAL_ERROR, len = 0;
        struct sshbuf *b = NULL, *sigbuf = NULL, *original_signed = NULL;
        struct sshbuf *webauthn_wrapper = NULL, *webauthn_exts = NULL;
        char *ktype = NULL, *webauthn_origin = NULL;
@@ -234,7 +236,7 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
 
        if (detailsp != NULL)
                *detailsp = NULL;
-       if (key == NULL || key->ecdsa == NULL ||
+       if (key == NULL || key->pkey == NULL ||
            sshkey_type_plain(key->type) != KEY_ECDSA_SK ||
            sig == NULL || siglen == 0)
                return SSH_ERR_INVALID_ARGUMENT;
@@ -345,21 +347,43 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
            (ret = sshbuf_putb(original_signed, webauthn_exts)) != 0 ||
            (ret = sshbuf_put(original_signed, msghash, sizeof(msghash))) != 0)
                goto out;
-       /* Signature is over H(original_signed) */
-       if ((ret = ssh_digest_buffer(SSH_DIGEST_SHA256, original_signed,
-           sighash, sizeof(sighash))) != 0)
-               goto out;
        details->sk_counter = sig_counter;
        details->sk_flags = sig_flags;
 #ifdef DEBUG_SK
        fprintf(stderr, "%s: signed buf:\n", __func__);
        sshbuf_dump(original_signed, stderr);
-       fprintf(stderr, "%s: signed hash:\n", __func__);
-       sshbuf_dump_data(sighash, sizeof(sighash), stderr);
 #endif
 
+       if ((md_ctx = EVP_MD_CTX_new()) == NULL) {
+               ret = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if ((len = i2d_ECDSA_SIG(esig, NULL)) <= 0) {
+               len = 0;
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       if ((sigb = calloc(1, len)) == NULL) {
+               ret = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       cp = sigb; /* ASN1_item_i2d increments the pointer past the object */
+       if (i2d_ECDSA_SIG(esig, &cp) != len) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+#ifdef DEBUG_SK
+       fprintf(stderr, "%s: signed hash:\n", __func__);
+       sshbuf_dump_data(sigb, len, stderr);
+#endif
        /* Verify it */
-       switch (ECDSA_do_verify(sighash, sizeof(sighash), esig, key->ecdsa)) {
+       if (EVP_DigestVerifyInit(md_ctx, NULL, EVP_sha256(), NULL,
+           key->pkey) != 1) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       switch (EVP_DigestVerify(md_ctx, sigb, len,
+           sshbuf_ptr(original_signed), sshbuf_len(original_signed))) {
        case 1:
                ret = 0;
                break;
@@ -379,7 +403,6 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
        explicit_bzero(&sig_flags, sizeof(sig_flags));
        explicit_bzero(&sig_counter, sizeof(sig_counter));
        explicit_bzero(msghash, sizeof(msghash));
-       explicit_bzero(sighash, sizeof(msghash));
        explicit_bzero(apphash, sizeof(apphash));
        sshkey_sig_details_free(details);
        sshbuf_free(webauthn_wrapper);
@@ -392,6 +415,8 @@ ssh_ecdsa_sk_verify(const struct sshkey *key,
        BN_clear_free(sig_r);
        BN_clear_free(sig_s);
        free(ktype);
+       freezero(sigb, len);
+       EVP_MD_CTX_free(md_ctx);
        return ret;
 }
 
index 59ed0c8..aa59b33 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-ecdsa.c,v 1.26 2023/03/08 04:43:12 guenther Exp $ */
+/* $OpenBSD: ssh-ecdsa.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
 #define SSHKEY_INTERNAL
 #include "sshkey.h"
 
+int
+sshkey_ecdsa_fixup_group(EVP_PKEY *k)
+{
+       int nids[] = {
+               NID_X9_62_prime256v1,
+               NID_secp384r1,
+               NID_secp521r1,
+               -1
+       };
+       int nid = -1;
+       u_int i;
+       const EC_GROUP *g;
+       EC_KEY *ec = NULL;
+       EC_GROUP *eg = NULL;
+
+       if ((ec = EVP_PKEY_get1_EC_KEY(k)) == NULL ||
+           (g = EC_KEY_get0_group(ec)) == NULL)
+               goto out;
+       /*
+        * The group may be stored in a ASN.1 encoded private key in one of two
+        * ways: as a "named group", which is reconstituted by ASN.1 object ID
+        * or explicit group parameters encoded into the key blob. Only the
+        * "named group" case sets the group NID for us, but we can figure
+        * it out for the other case by comparing against all the groups that
+        * are supported.
+        */
+       if ((nid = EC_GROUP_get_curve_name(g)) > 0)
+               goto out;
+       nid = -1;
+       for (i = 0; nids[i] != -1; i++) {
+               if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
+                       goto out;
+               if (EC_GROUP_cmp(g, eg, NULL) == 0)
+                       break;
+               EC_GROUP_free(eg);
+               eg = NULL;
+       }
+       if (nids[i] == -1)
+               goto out;
+
+       /* Use the group with the NID attached */
+       EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
+       if (EC_KEY_set_group(ec, eg) != 1 ||
+           EVP_PKEY_set1_EC_KEY(k, ec) != 1)
+               goto out;
+       /* success */
+       nid = nids[i];
+ out:
+       EC_KEY_free(ec);
+       EC_GROUP_free(eg);
+       return nid;
+}
+
 static u_int
 ssh_ecdsa_size(const struct sshkey *key)
 {
@@ -57,30 +110,16 @@ ssh_ecdsa_size(const struct sshkey *key)
 static void
 ssh_ecdsa_cleanup(struct sshkey *k)
 {
-       EC_KEY_free(k->ecdsa);
-       k->ecdsa = NULL;
+       EVP_PKEY_free(k->pkey);
+       k->pkey = NULL;
 }
 
 static int
 ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b)
 {
-       const EC_GROUP *grp_a, *grp_b;
-       const EC_POINT *pub_a, *pub_b;
-
-       if (a->ecdsa == NULL || b->ecdsa == NULL)
-               return 0;
-       if ((grp_a = EC_KEY_get0_group(a->ecdsa)) == NULL ||
-           (grp_b = EC_KEY_get0_group(b->ecdsa)) == NULL)
-               return 0;
-       if ((pub_a = EC_KEY_get0_public_key(a->ecdsa)) == NULL ||
-           (pub_b = EC_KEY_get0_public_key(b->ecdsa)) == NULL)
+       if (a->pkey == NULL || b->pkey == NULL)
                return 0;
-       if (EC_GROUP_cmp(grp_a, grp_b, NULL) != 0)
-               return 0;
-       if (EC_POINT_cmp(grp_a, pub_a, pub_b, NULL) != 0)
-               return 0;
-
-       return 1;
+       return EVP_PKEY_cmp(a->pkey, b->pkey) == 1;
 }
 
 static int
@@ -89,11 +128,11 @@ ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
 {
        int r;
 
-       if (key->ecdsa == NULL)
+       if (key->pkey == NULL)
                return SSH_ERR_INVALID_ARGUMENT;
        if ((r = sshbuf_put_cstring(b,
            sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 ||
-           (r = sshbuf_put_eckey(b, key->ecdsa)) != 0)
+           (r = sshbuf_put_ec_pkey(b, key->pkey)) != 0)
                return r;
 
        return 0;
@@ -110,7 +149,7 @@ ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
                        return r;
        }
        if ((r = sshbuf_put_bignum2(b,
-           EC_KEY_get0_private_key(key->ecdsa))) != 0)
+           EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(key->pkey)))) != 0)
                return r;
        return 0;
 }
@@ -118,31 +157,64 @@ ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
 static int
 ssh_ecdsa_generate(struct sshkey *k, int bits)
 {
-       EC_KEY *private;
+       EVP_PKEY *res = NULL;
+       EVP_PKEY_CTX *ctx = NULL;
+       int ret = SSH_ERR_INTERNAL_ERROR;
 
        if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
                return SSH_ERR_KEY_LENGTH;
-       if ((private = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL)
+
+       if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL)
                return SSH_ERR_ALLOC_FAIL;
-       if (EC_KEY_generate_key(private) != 1) {
-               EC_KEY_free(private);
-               return SSH_ERR_LIBCRYPTO_ERROR;
+
+       if (EVP_PKEY_keygen_init(ctx) <= 0 ||
+           EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, k->ecdsa_nid) <= 0 ||
+           EVP_PKEY_keygen(ctx, &res) <= 0) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
        }
-       EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
-       k->ecdsa = private;
-       return 0;
+       /* success */
+       k->pkey = res;
+       res = NULL;
+       ret = 0;
+ out:
+       EVP_PKEY_free(res);
+       EVP_PKEY_CTX_free(ctx);
+       return ret;
 }
 
 static int
 ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to)
 {
+       const EC_KEY *ec_from;
+       EC_KEY *ec_to = NULL;
+       int ret = SSH_ERR_INTERNAL_ERROR;
+
+       ec_from = EVP_PKEY_get0_EC_KEY(from->pkey);
+       if (ec_from == NULL)
+               return SSH_ERR_LIBCRYPTO_ERROR;
+
        to->ecdsa_nid = from->ecdsa_nid;
-       if ((to->ecdsa = EC_KEY_new_by_curve_name(from->ecdsa_nid)) == NULL)
+       if ((ec_to = EC_KEY_new_by_curve_name(from->ecdsa_nid)) == NULL)
                return SSH_ERR_ALLOC_FAIL;
-       if (EC_KEY_set_public_key(to->ecdsa,
-           EC_KEY_get0_public_key(from->ecdsa)) != 1)
-               return SSH_ERR_LIBCRYPTO_ERROR; /* caller will free k->ecdsa */
-       return 0;
+       if (EC_KEY_set_public_key(ec_to,
+           EC_KEY_get0_public_key(ec_from)) != 1) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       EVP_PKEY_free(to->pkey);
+       if ((to->pkey = EVP_PKEY_new()) == NULL) {
+               ret = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if (EVP_PKEY_set1_EC_KEY(to->pkey, ec_to) != 1) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       ret = 0;
+ out:
+       EC_KEY_free(ec_to);
+       return ret;
 }
 
 static int
@@ -151,6 +223,8 @@ ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b,
 {
        int r;
        char *curve = NULL;
+       EVP_PKEY *pkey = NULL;
+       EC_KEY *ec = NULL;
 
        if ((key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype)) == -1)
                return SSH_ERR_INVALID_ARGUMENT;
@@ -160,31 +234,39 @@ ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b,
                r = SSH_ERR_EC_CURVE_MISMATCH;
                goto out;
        }
-       EC_KEY_free(key->ecdsa);
-       key->ecdsa = NULL;
-       if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) {
+       if ((ec = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) {
                r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-       if ((r = sshbuf_get_eckey(b, key->ecdsa)) != 0)
+       if ((r = sshbuf_get_eckey(b, ec)) != 0)
                goto out;
-       if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa),
-           EC_KEY_get0_public_key(key->ecdsa)) != 0) {
+       if (sshkey_ec_validate_public(EC_KEY_get0_group(ec),
+           EC_KEY_get0_public_key(ec)) != 0) {
                r = SSH_ERR_KEY_INVALID_EC_VALUE;
                goto out;
        }
+       if ((pkey = EVP_PKEY_new()) == NULL) {
+               r = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if (EVP_PKEY_set1_EC_KEY(pkey, ec) != 1) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       EVP_PKEY_free(key->pkey);
+       key->pkey = pkey;
+       pkey = NULL;
        /* success */
        r = 0;
 #ifdef DEBUG_PK
-       sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa),
-           EC_KEY_get0_public_key(key->ecdsa));
+       sshkey_dump_ec_point(
+           EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(key->pkey)),
+           EC_KEY_get0_public_key(EVP_PKEY_get0_EC_KEY(key->pkey)));
 #endif
  out:
+       EC_KEY_free(ec);
+       EVP_PKEY_free(pkey);
        free(curve);
-       if (r != 0) {
-               EC_KEY_free(key->ecdsa);
-               key->ecdsa = NULL;
-       }
        return r;
 }
 
@@ -194,6 +276,7 @@ ssh_ecdsa_deserialize_private(const char *ktype, struct sshbuf *b,
 {
        int r;
        BIGNUM *exponent = NULL;
+       EC_KEY *ec = NULL;
 
        if (!sshkey_is_cert(key)) {
                if ((r = ssh_ecdsa_deserialize_public(ktype, b, key)) != 0)
@@ -201,16 +284,25 @@ ssh_ecdsa_deserialize_private(const char *ktype, struct sshbuf *b,
        }
        if ((r = sshbuf_get_bignum2(b, &exponent)) != 0)
                goto out;
-       if (EC_KEY_set_private_key(key->ecdsa, exponent) != 1) {
+       if ((ec = EVP_PKEY_get1_EC_KEY(key->pkey)) == NULL) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       if (EC_KEY_set_private_key(ec, exponent) != 1) {
                r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-       if ((r = sshkey_ec_validate_private(key->ecdsa)) != 0)
+       if ((r = sshkey_ec_validate_private(ec)) != 0)
+               goto out;
+       if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
+       }
        /* success */
        r = 0;
  out:
        BN_clear_free(exponent);
+       EC_KEY_free(ec);
        return r;
 }
 
@@ -221,34 +313,35 @@ ssh_ecdsa_sign(struct sshkey *key,
     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
 {
        ECDSA_SIG *esig = NULL;
+       unsigned char *sigb = NULL;
+       const unsigned char *psig;
        const BIGNUM *sig_r, *sig_s;
        int hash_alg;
-       u_char digest[SSH_DIGEST_MAX_LENGTH];
-       size_t len, hlen;
+       size_t slen = 0;
        struct sshbuf *b = NULL, *bb = NULL;
-       int ret = SSH_ERR_INTERNAL_ERROR;
+       int len = 0, ret = SSH_ERR_INTERNAL_ERROR;
 
        if (lenp != NULL)
                *lenp = 0;
        if (sigp != NULL)
                *sigp = NULL;
 
-       if (key == NULL || key->ecdsa == NULL ||
+       if (key == NULL || key->pkey == NULL ||
            sshkey_type_plain(key->type) != KEY_ECDSA)
                return SSH_ERR_INVALID_ARGUMENT;
 
-       if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
-           (hlen = ssh_digest_bytes(hash_alg)) == 0)
+       if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
                return SSH_ERR_INTERNAL_ERROR;
-       if ((ret = ssh_digest_memory(hash_alg, data, dlen,
-           digest, sizeof(digest))) != 0)
+
+       if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sigb, &slen,
+           data, dlen)) != 0)
                goto out;
 
-       if ((esig = ECDSA_do_sign(digest, hlen, key->ecdsa)) == NULL) {
+       psig = sigb;
+       if ((esig = d2i_ECDSA_SIG(NULL, &psig, slen)) == NULL) {
                ret = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-
        if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) {
                ret = SSH_ERR_ALLOC_FAIL;
                goto out;
@@ -272,7 +365,7 @@ ssh_ecdsa_sign(struct sshkey *key,
                *lenp = len;
        ret = 0;
  out:
-       explicit_bzero(digest, sizeof(digest));
+       freezero(sigb, slen);
        sshbuf_free(b);
        sshbuf_free(bb);
        ECDSA_SIG_free(esig);
@@ -287,20 +380,18 @@ ssh_ecdsa_verify(const struct sshkey *key,
 {
        ECDSA_SIG *esig = NULL;
        BIGNUM *sig_r = NULL, *sig_s = NULL;
-       int hash_alg;
-       u_char digest[SSH_DIGEST_MAX_LENGTH];
-       size_t hlen;
+       int hash_alg, len = 0;
        int ret = SSH_ERR_INTERNAL_ERROR;
        struct sshbuf *b = NULL, *sigbuf = NULL;
        char *ktype = NULL;
+       unsigned char *sigb = NULL, *cp;
 
-       if (key == NULL || key->ecdsa == NULL ||
+       if (key == NULL || key->pkey == NULL ||
            sshkey_type_plain(key->type) != KEY_ECDSA ||
            sig == NULL || siglen == 0)
                return SSH_ERR_INVALID_ARGUMENT;
 
-       if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 ||
-           (hlen = ssh_digest_bytes(hash_alg)) == 0)
+       if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1)
                return SSH_ERR_INTERNAL_ERROR;
 
        /* fetch signature */
@@ -326,6 +417,11 @@ ssh_ecdsa_verify(const struct sshkey *key,
                ret = SSH_ERR_INVALID_FORMAT;
                goto out;
        }
+       if (sshbuf_len(sigbuf) != 0) {
+               ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
+               goto out;
+       }
+
        if ((esig = ECDSA_SIG_new()) == NULL) {
                ret = SSH_ERR_ALLOC_FAIL;
                goto out;
@@ -336,28 +432,26 @@ ssh_ecdsa_verify(const struct sshkey *key,
        }
        sig_r = sig_s = NULL; /* transferred */
 
-       if (sshbuf_len(sigbuf) != 0) {
-               ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
+       if ((len = i2d_ECDSA_SIG(esig, NULL)) <= 0) {
+               len = 0;
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-       if ((ret = ssh_digest_memory(hash_alg, data, dlen,
-           digest, sizeof(digest))) != 0)
-               goto out;
-
-       switch (ECDSA_do_verify(digest, hlen, esig, key->ecdsa)) {
-       case 1:
-               ret = 0;
-               break;
-       case 0:
-               ret = SSH_ERR_SIGNATURE_INVALID;
+       if ((sigb = calloc(1, len)) == NULL) {
+               ret = SSH_ERR_ALLOC_FAIL;
                goto out;
-       default:
+       }
+       cp = sigb; /* ASN1_item_i2d increments the pointer past the object */
+       if (i2d_ECDSA_SIG(esig, &cp) != len) {
                ret = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-
+       if ((ret = sshkey_pkey_digest_verify(key->pkey, hash_alg,
+           data, dlen, sigb, len)) != 0)
+               goto out;
+       /* success */
  out:
-       explicit_bzero(digest, sizeof(digest));
+       freezero(sigb, len);
        sshbuf_free(sigbuf);
        sshbuf_free(b);
        ECDSA_SIG_free(esig);
index 8448026..4a95c55 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.472 2024/01/11 01:45:36 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.473 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -362,7 +362,8 @@ do_convert_to_pkcs8(struct sshkey *k)
 {
        switch (sshkey_type_plain(k->type)) {
        case KEY_RSA:
-               if (!PEM_write_RSA_PUBKEY(stdout, k->rsa))
+               if (!PEM_write_RSA_PUBKEY(stdout,
+                   EVP_PKEY_get0_RSA(k->pkey)))
                        fatal("PEM_write_RSA_PUBKEY failed");
                break;
 #ifdef WITH_DSA
@@ -372,7 +373,8 @@ do_convert_to_pkcs8(struct sshkey *k)
                break;
 #endif
        case KEY_ECDSA:
-               if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
+               if (!PEM_write_EC_PUBKEY(stdout,
+                   EVP_PKEY_get0_EC_KEY(k->pkey)))
                        fatal("PEM_write_EC_PUBKEY failed");
                break;
        default:
@@ -386,7 +388,8 @@ do_convert_to_pem(struct sshkey *k)
 {
        switch (sshkey_type_plain(k->type)) {
        case KEY_RSA:
-               if (!PEM_write_RSAPublicKey(stdout, k->rsa))
+               if (!PEM_write_RSAPublicKey(stdout,
+                   EVP_PKEY_get0_RSA(k->pkey)))
                        fatal("PEM_write_RSAPublicKey failed");
                break;
 #ifdef WITH_DSA
@@ -396,7 +399,8 @@ do_convert_to_pem(struct sshkey *k)
                break;
 #endif
        case KEY_ECDSA:
-               if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa))
+               if (!PEM_write_EC_PUBKEY(stdout,
+                   EVP_PKEY_get0_EC_KEY(k->pkey)))
                        fatal("PEM_write_EC_PUBKEY failed");
                break;
        default:
@@ -473,6 +477,8 @@ do_convert_private_ssh2(struct sshbuf *b)
 #endif
        BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
        BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL;
+       BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL;
+       RSA *rsa = NULL;
 
        if ((r = sshbuf_get_u32(b, &magic)) != 0)
                fatal_fr(r, "parse magic");
@@ -567,15 +573,25 @@ do_convert_private_ssh2(struct sshbuf *b)
                buffer_get_bignum_bits(b, rsa_iqmp);
                buffer_get_bignum_bits(b, rsa_q);
                buffer_get_bignum_bits(b, rsa_p);
-               if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, rsa_d))
+               if ((r = ssh_rsa_complete_crt_parameters(rsa_d, rsa_p, rsa_q,
+                   rsa_iqmp, &rsa_dmp1, &rsa_dmq1)) != 0)
+                       fatal_fr(r, "generate RSA CRT parameters");
+               if ((key->pkey = EVP_PKEY_new()) == NULL)
+                       fatal_f("EVP_PKEY_new failed");
+               if ((rsa = RSA_new()) == NULL)
+                       fatal_f("RSA_new failed");
+               if (!RSA_set0_key(rsa, rsa_n, rsa_e, rsa_d))
                        fatal_f("RSA_set0_key failed");
                rsa_n = rsa_e = rsa_d = NULL; /* transferred */
-               if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q))
+               if (!RSA_set0_factors(rsa, rsa_p, rsa_q))
                        fatal_f("RSA_set0_factors failed");
                rsa_p = rsa_q = NULL; /* transferred */
-               if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0)
-                       fatal_fr(r, "generate RSA parameters");
-               BN_clear_free(rsa_iqmp);
+               if (RSA_set0_crt_params(rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp) != 1)
+                       fatal_f("RSA_set0_crt_params failed");
+               rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL;
+               if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
+                       fatal_f("EVP_PKEY_set1_RSA failed");
+               RSA_free(rsa);
                alg = "rsa-sha2-256";
                break;
        }
@@ -695,7 +711,8 @@ do_convert_from_pkcs8(struct sshkey **k, int *private)
                if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
                        fatal("sshkey_new failed");
                (*k)->type = KEY_RSA;
-               (*k)->rsa = EVP_PKEY_get1_RSA(pubkey);
+               (*k)->pkey = pubkey;
+               pubkey = NULL;
                break;
 #ifdef WITH_DSA
        case EVP_PKEY_DSA:
@@ -708,9 +725,11 @@ do_convert_from_pkcs8(struct sshkey **k, int *private)
        case EVP_PKEY_EC:
                if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
                        fatal("sshkey_new failed");
+               if (((*k)->ecdsa_nid = sshkey_ecdsa_fixup_group(pubkey)) == -1)
+                       fatal("sshkey_ecdsa_fixup_group failed");
                (*k)->type = KEY_ECDSA;
-               (*k)->ecdsa = EVP_PKEY_get1_EC_KEY(pubkey);
-               (*k)->ecdsa_nid = sshkey_ecdsa_key_to_nid((*k)->ecdsa);
+               (*k)->pkey = pubkey;
+               pubkey = NULL;
                break;
        default:
                fatal_f("unsupported pubkey type %d",
@@ -731,8 +750,12 @@ do_convert_from_pem(struct sshkey **k, int *private)
        if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) {
                if ((*k = sshkey_new(KEY_UNSPEC)) == NULL)
                        fatal("sshkey_new failed");
+               if (((*k)->pkey = EVP_PKEY_new()) == NULL)
+                       fatal("EVP_PKEY_new failed");
                (*k)->type = KEY_RSA;
-               (*k)->rsa = rsa;
+               if (EVP_PKEY_set1_RSA((*k)->pkey, rsa) != 1)
+                       fatal("EVP_PKEY_set1_RSA failed");
+               RSA_free(rsa);
                fclose(fp);
                return;
        }
@@ -779,12 +802,14 @@ do_convert_from(struct passwd *pw)
                        break;
 #endif
                case KEY_ECDSA:
-                       ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL,
-                           NULL, 0, NULL, NULL);
+                       ok = PEM_write_ECPrivateKey(stdout,
+                           EVP_PKEY_get0_EC_KEY(k->pkey), NULL, NULL, 0,
+                           NULL, NULL);
                        break;
                case KEY_RSA:
-                       ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL,
-                           NULL, 0, NULL, NULL);
+                       ok = PEM_write_RSAPrivateKey(stdout,
+                           EVP_PKEY_get0_RSA(k->pkey), NULL, NULL, 0,
+                           NULL, NULL);
                        break;
                default:
                        fatal_f("unsupported key type %s", sshkey_type(k));
index af9ad1b..205139f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11-client.c,v 1.19 2023/12/18 14:46:56 djm Exp $ */
+/* $OpenBSD: ssh-pkcs11-client.c,v 1.20 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
@@ -247,14 +247,17 @@ rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding)
        debug3_f("signing with PKCS11 provider %s", helper->path);
        if (padding != RSA_PKCS1_PADDING)
                goto fail;
-       key = sshkey_new(KEY_UNSPEC);
-       if (key == NULL) {
+       if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
                error_f("sshkey_new failed");
                goto fail;
        }
+       if ((key->pkey = EVP_PKEY_new()) == NULL ||
+          EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
+               error_f("pkey setup failed");
+               goto fail;
+       }
+
        key->type = KEY_RSA;
-       RSA_up_ref(rsa);
-       key->rsa = rsa;
        if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
                error_fr(r, "encode key");
                goto fail;
@@ -321,21 +324,22 @@ ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv,
        if ((helper = helper_by_ec(ec)) == NULL || helper->fd == -1)
                fatal_f("no helper for PKCS11 key");
        debug3_f("signing with PKCS11 provider %s", helper->path);
-       nid = sshkey_ecdsa_key_to_nid(ec);
-       if (nid < 0) {
-               error_f("couldn't get curve nid");
-               goto fail;
-       }
 
-       key = sshkey_new(KEY_UNSPEC);
-       if (key == NULL) {
+       if ((key = sshkey_new(KEY_UNSPEC)) == NULL) {
                error_f("sshkey_new failed");
                goto fail;
        }
-       key->ecdsa = ec;
+       if ((key->pkey = EVP_PKEY_new()) == NULL ||
+           EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1) {
+               error("pkey setup failed");
+               goto fail;
+       }
+       if ((nid = sshkey_ecdsa_pkey_to_nid(key->pkey)) < 0) {
+               error("couldn't get curve nid");
+               goto fail;
+       }
        key->ecdsa_nid = nid;
        key->type = KEY_ECDSA;
-       EC_KEY_up_ref(ec);
 
        if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) {
                error_fr(r, "encode key");
@@ -389,15 +393,30 @@ ecdsa_do_finish(EC_KEY *ec)
 static void
 wrap_key(struct helper *helper, struct sshkey *k)
 {
+       RSA *rsa = NULL;
+       EC_KEY *ecdsa = NULL;
+
        debug3_f("wrap %s for provider %s", sshkey_type(k), helper->path);
        if (k->type == KEY_RSA) {
-               RSA_set_method(k->rsa, helper->rsa_meth);
+               if ((rsa = EVP_PKEY_get1_RSA(k->pkey)) == NULL)
+                       fatal_f("no RSA key");
+               if (RSA_set_method(rsa, helper->rsa_meth) != 1)
+                       fatal_f("RSA_set_method failed");
                if (helper->nrsa++ >= INT_MAX)
                        fatal_f("RSA refcount error");
+               if (EVP_PKEY_set1_RSA(k->pkey, rsa) != 1)
+                       fatal_f("EVP_PKEY_set1_RSA failed");
+               RSA_free(rsa);
        } else if (k->type == KEY_ECDSA) {
-               EC_KEY_set_method(k->ecdsa, helper->ec_meth);
+               if ((ecdsa = EVP_PKEY_get1_EC_KEY(k->pkey)) == NULL)
+                       fatal_f("no ECDSA key");
+               if (EC_KEY_set_method(ecdsa, helper->ec_meth) != 1)
+                       fatal_f("EC_KEY_set_method failed");
                if (helper->nec++ >= INT_MAX)
                        fatal_f("EC refcount error");
+               if (EVP_PKEY_set1_EC_KEY(k->pkey, ecdsa) != 1)
+                       fatal_f("EVP_PKEY_set1_EC_KEY failed");
+               EC_KEY_free(ecdsa);
        } else
                fatal_f("unknown key type");
        k->flags |= SSHKEY_FLAG_EXT;
@@ -416,6 +435,8 @@ pkcs11_make_cert(const struct sshkey *priv,
        struct helper *helper = NULL;
        struct sshkey *ret;
        int r;
+       RSA *rsa_priv = NULL, *rsa_cert = NULL;
+       EC_KEY *ec_priv = NULL, *ec_cert = NULL;
 
        debug3_f("private key type %s cert type %s", sshkey_type(priv),
            sshkey_type(certpub));
@@ -428,23 +449,41 @@ pkcs11_make_cert(const struct sshkey *priv,
        }
        *certprivp = NULL;
        if (priv->type == KEY_RSA) {
-               if ((helper = helper_by_rsa(priv->rsa)) == NULL ||
+               if ((rsa_priv = EVP_PKEY_get1_RSA(priv->pkey)) == NULL)
+                       fatal_f("no RSA pkey");
+               if ((helper = helper_by_rsa(rsa_priv)) == NULL ||
                    helper->fd == -1)
                        fatal_f("no helper for PKCS11 RSA key");
                if ((r = sshkey_from_private(priv, &ret)) != 0)
                        fatal_fr(r, "copy key");
-               RSA_set_method(ret->rsa, helper->rsa_meth);
+               if ((rsa_cert = EVP_PKEY_get1_RSA(ret->pkey)) == NULL)
+                       fatal_f("no RSA cert pkey");
+               if (RSA_set_method(rsa_cert, helper->rsa_meth) != 1)
+                       fatal_f("RSA_set_method failed");
                if (helper->nrsa++ >= INT_MAX)
                        fatal_f("RSA refcount error");
+               if (EVP_PKEY_set1_RSA(ret->pkey, rsa_cert) != 1)
+                       fatal_f("EVP_PKEY_set1_RSA failed");
+               RSA_free(rsa_priv);
+               RSA_free(rsa_cert);
        } else if (priv->type == KEY_ECDSA) {
-               if ((helper = helper_by_ec(priv->ecdsa)) == NULL ||
+               if ((ec_priv = EVP_PKEY_get1_EC_KEY(priv->pkey)) == NULL)
+                       fatal_f("no EC pkey");
+               if ((helper = helper_by_ec(ec_priv)) == NULL ||
                    helper->fd == -1)
                        fatal_f("no helper for PKCS11 EC key");
                if ((r = sshkey_from_private(priv, &ret)) != 0)
                        fatal_fr(r, "copy key");
-               EC_KEY_set_method(ret->ecdsa, helper->ec_meth);
+               if ((ec_cert = EVP_PKEY_get1_EC_KEY(ret->pkey)) == NULL)
+                       fatal_f("no EC cert pkey");
+               if (EC_KEY_set_method(ec_cert, helper->ec_meth) != 1)
+                       fatal_f("EC_KEY_set_method failed");
                if (helper->nec++ >= INT_MAX)
                        fatal_f("EC refcount error");
+               if (EVP_PKEY_set1_EC_KEY(ret->pkey, ec_cert) != 1)
+                       fatal_f("EVP_PKEY_set1_EC_KEY failed");
+               EC_KEY_free(ec_priv);
+               EC_KEY_free(ec_cert);
        } else
                fatal_f("unknown key type %s", sshkey_type(priv));
 
index 1a62757..3f79a00 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11-helper.c,v 1.26 2021/11/18 03:31:44 djm Exp $ */
+/* $OpenBSD: ssh-pkcs11-helper.c,v 1.27 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  *
@@ -36,6 +36,8 @@
 #include "ssherr.h"
 
 #ifdef WITH_OPENSSL
+#include <openssl/ec.h>
+#include <openssl/rsa.h>
 
 /* borrows code from sftp-server and ssh-agent */
 
@@ -176,10 +178,13 @@ static void
 process_sign(void)
 {
        u_char *blob, *data, *signature = NULL;
-       size_t blen, dlen, slen = 0;
-       int r, ok = -1;
-       struct sshkey *key, *found;
+       size_t blen, dlen;
+       u_int slen = 0;
+       int len, r, ok = -1;
+       struct sshkey *key = NULL, *found;
        struct sshbuf *msg;
+       RSA *rsa = NULL;
+       EC_KEY *ecdsa = NULL;
 
        /* XXX support SHA2 signature flags */
        if ((r = sshbuf_get_string(iqueue, &blob, &blen)) != 0 ||
@@ -189,39 +194,43 @@ process_sign(void)
 
        if ((r = sshkey_from_blob(blob, blen, &key)) != 0)
                fatal_fr(r, "decode key");
-       else {
-               if ((found = lookup_key(key)) != NULL) {
-#ifdef WITH_OPENSSL
-                       int ret;
-
-                       if (key->type == KEY_RSA) {
-                               slen = RSA_size(key->rsa);
-                               signature = xmalloc(slen);
-                               ret = RSA_private_encrypt(dlen, data, signature,
-                                   found->rsa, RSA_PKCS1_PADDING);
-                               if (ret != -1) {
-                                       slen = ret;
-                                       ok = 0;
-                               }
-                       } else if (key->type == KEY_ECDSA) {
-                               u_int xslen = ECDSA_size(key->ecdsa);
-
-                               signature = xmalloc(xslen);
-                               /* "The parameter type is ignored." */
-                               ret = ECDSA_sign(-1, data, dlen, signature,
-                                   &xslen, found->ecdsa);
-                               if (ret != 0)
-                                       ok = 0;
-                               else
-                                       error_f("ECDSA_sign returned %d", ret);
-                               slen = xslen;
-                       } else
-                               error_f("don't know how to sign with key "
-                                   "type %d", (int)key->type);
-#endif /* WITH_OPENSSL */
+       if ((found = lookup_key(key)) == NULL)
+               goto reply;
+
+       /* XXX use pkey API properly for signing */
+       switch (key->type) {
+       case KEY_RSA:
+               if ((rsa = EVP_PKEY_get1_RSA(found->pkey)) == NULL)
+                       fatal_f("no RSA in pkey");
+               if ((len = RSA_size(rsa)) < 0)
+                       fatal_f("bad RSA length");
+               signature = xmalloc(len);
+               if ((len = RSA_private_encrypt(dlen, data, signature,
+                   rsa, RSA_PKCS1_PADDING)) < 0) {
+                       error_f("RSA_private_encrypt failed");
+                       goto reply;
+               }
+               slen = (u_int)len;
+               break;
+       case KEY_ECDSA:
+               if ((ecdsa = EVP_PKEY_get1_EC_KEY(found->pkey)) == NULL)
+                       fatal_f("no ECDSA in pkey");
+               if ((len = ECDSA_size(ecdsa)) < 0)
+                       fatal_f("bad ECDSA length");
+               slen = (u_int)len;
+               signature = xmalloc(slen);
+               /* "The parameter type is ignored." */
+               if (!ECDSA_sign(-1, data, dlen, signature, &slen, ecdsa)) {
+                       error_f("ECDSA_sign failed");
+                       goto reply;
                }
-               sshkey_free(key);
+               break;
+       default:
+               fatal_f("unsupported key type %d", key->type);
        }
+       /* success */
+       ok = 0;
+ reply:
        if ((msg = sshbuf_new()) == NULL)
                fatal_f("sshbuf_new failed");
        if (ok == 0) {
@@ -232,6 +241,9 @@ process_sign(void)
                if ((r = sshbuf_put_u8(msg, SSH2_AGENT_FAILURE)) != 0)
                        fatal_fr(r, "compose failure response");
        }
+       sshkey_free(key);
+       RSA_free(rsa);
+       EC_KEY_free(ecdsa);
        free(data);
        free(blob);
        free(signature);
index e6c53f0..97c98cc 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-pkcs11.c,v 1.62 2024/04/02 12:22:38 deraadt Exp $ */
+/* $OpenBSD: ssh-pkcs11.c,v 1.63 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2010 Markus Friedl.  All rights reserved.
  * Copyright (c) 2014 Pedro Martelletto. All rights reserved.
@@ -493,8 +493,10 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
                memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
        }
 
-       RSA_set_method(rsa, rsa_method);
-       RSA_set_ex_data(rsa, rsa_idx, k11);
+       if (RSA_set_method(rsa, rsa_method) != 1)
+               fatal_f("RSA_set_method failed");
+       if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1)
+               fatal_f("RSA_set_ex_data failed");
        return (0);
 }
 
@@ -605,8 +607,10 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
                k11->keyid = xmalloc(k11->keyid_len);
                memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
        }
-       EC_KEY_set_method(ec, ec_key_method);
-       EC_KEY_set_ex_data(ec, ec_key_idx, k11);
+       if (EC_KEY_set_method(ec, ec_key_method) != 1)
+               fatal_f("EC_KEY_set_method failed");
+       if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1)
+               fatal_f("EC_KEY_set_ex_data failed");
 
        return (0);
 }
@@ -791,11 +795,14 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                goto fail;
        }
 
-       key->ecdsa = ec;
+       EVP_PKEY_free(key->pkey);
+       if ((key->pkey = EVP_PKEY_new()) == NULL)
+               fatal("EVP_PKEY_new failed");
+       if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
+               fatal("EVP_PKEY_set1_EC_KEY failed");
        key->ecdsa_nid = nid;
        key->type = KEY_ECDSA;
        key->flags |= SSHKEY_FLAG_EXT;
-       ec = NULL;      /* now owned by key */
 
 fail:
        for (i = 0; i < 3; i++)
@@ -886,10 +893,13 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                goto fail;
        }
 
-       key->rsa = rsa;
+       EVP_PKEY_free(key->pkey);
+       if ((key->pkey = EVP_PKEY_new()) == NULL)
+               fatal("EVP_PKEY_new failed");
+       if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
+               fatal("EVP_PKEY_set1_RSA failed");
        key->type = KEY_RSA;
        key->flags |= SSHKEY_FLAG_EXT;
-       rsa = NULL;     /* now owned by key */
 
 fail:
        for (i = 0; i < 3; i++)
@@ -997,10 +1007,13 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                        goto out;
                }
 
-               key->rsa = rsa;
+               EVP_PKEY_free(key->pkey);
+               if ((key->pkey = EVP_PKEY_new()) == NULL)
+                       fatal("EVP_PKEY_new failed");
+               if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1)
+                       fatal("EVP_PKEY_set1_RSA failed");
                key->type = KEY_RSA;
                key->flags |= SSHKEY_FLAG_EXT;
-               rsa = NULL;     /* now owned by key */
        } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
                if (EVP_PKEY_get0_EC_KEY(evp) == NULL) {
                        error("invalid x509; no ec key");
@@ -1026,11 +1039,14 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
                        goto out;
                }
 
-               key->ecdsa = ec;
+               EVP_PKEY_free(key->pkey);
+               if ((key->pkey = EVP_PKEY_new()) == NULL)
+                       fatal("EVP_PKEY_new failed");
+               if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) != 1)
+                       fatal("EVP_PKEY_set1_EC_KEY failed");
                key->ecdsa_nid = nid;
                key->type = KEY_ECDSA;
                key->flags |= SSHKEY_FLAG_EXT;
-               ec = NULL;      /* now owned by key */
        } else {
                error("unknown certificate key type");
                goto out;
index 59f7cd2..6492e60 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-rsa.c,v 1.79 2023/03/05 05:34:09 dtucker Exp $ */
+/* $OpenBSD: ssh-rsa.c,v 1.80 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org>
  *
 #include "digest.h"
 #include "log.h"
 
-static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *);
-
 static u_int
-ssh_rsa_size(const struct sshkey *key)
+ssh_rsa_size(const struct sshkey *k)
 {
-       const BIGNUM *rsa_n;
-
-       if (key->rsa == NULL)
+       if (k->pkey == NULL)
                return 0;
-       RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
-       return BN_num_bits(rsa_n);
+       return EVP_PKEY_bits(k->pkey);
 }
 
 static int
 ssh_rsa_alloc(struct sshkey *k)
 {
-       if ((k->rsa = RSA_new()) == NULL)
+       if ((k->pkey = EVP_PKEY_new()) == NULL)
                return SSH_ERR_ALLOC_FAIL;
        return 0;
 }
@@ -53,29 +48,16 @@ ssh_rsa_alloc(struct sshkey *k)
 static void
 ssh_rsa_cleanup(struct sshkey *k)
 {
-       RSA_free(k->rsa);
-       k->rsa = NULL;
+       EVP_PKEY_free(k->pkey);
+       k->pkey = NULL;
 }
 
 static int
 ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b)
 {
-       const BIGNUM *rsa_e_a, *rsa_n_a;
-       const BIGNUM *rsa_e_b, *rsa_n_b;
-
-       if (a->rsa == NULL || b->rsa == NULL)
-               return 0;
-       RSA_get0_key(a->rsa, &rsa_n_a, &rsa_e_a, NULL);
-       RSA_get0_key(b->rsa, &rsa_n_b, &rsa_e_b, NULL);
-       if (rsa_e_a == NULL || rsa_e_b == NULL)
+       if (a->pkey == NULL || b->pkey == NULL)
                return 0;
-       if (rsa_n_a == NULL || rsa_n_b == NULL)
-               return 0;
-       if (BN_cmp(rsa_e_a, rsa_e_b) != 0)
-               return 0;
-       if (BN_cmp(rsa_n_a, rsa_n_b) != 0)
-               return 0;
-       return 1;
+       return EVP_PKEY_cmp(a->pkey, b->pkey) == 1;
 }
 
 static int
@@ -84,10 +66,14 @@ ssh_rsa_serialize_public(const struct sshkey *key, struct sshbuf *b,
 {
        int r;
        const BIGNUM *rsa_n, *rsa_e;
+       const RSA *rsa;
 
-       if (key->rsa == NULL)
+       if (key->pkey == NULL)
                return SSH_ERR_INVALID_ARGUMENT;
-       RSA_get0_key(key->rsa, &rsa_n, &rsa_e, NULL);
+       if ((rsa = EVP_PKEY_get0_RSA(key->pkey)) == NULL)
+               return SSH_ERR_LIBCRYPTO_ERROR;
+
+       RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
        if ((r = sshbuf_put_bignum2(b, rsa_e)) != 0 ||
            (r = sshbuf_put_bignum2(b, rsa_n)) != 0)
                return r;
@@ -101,10 +87,13 @@ ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
 {
        int r;
        const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q;
+       const RSA *rsa;
 
-       RSA_get0_key(key->rsa, &rsa_n, &rsa_e, &rsa_d);
-       RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
-       RSA_get0_crt_params(key->rsa, NULL, NULL, &rsa_iqmp);
+       if ((rsa = EVP_PKEY_get0_RSA(key->pkey)) == NULL)
+               return SSH_ERR_LIBCRYPTO_ERROR;
+       RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
+       RSA_get0_factors(rsa, &rsa_p, &rsa_q);
+       RSA_get0_crt_params(rsa, NULL, NULL, &rsa_iqmp);
 
        if (!sshkey_is_cert(key)) {
                /* Note: can't reuse ssh_rsa_serialize_public: e, n vs. n, e */
@@ -124,28 +113,36 @@ ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b,
 static int
 ssh_rsa_generate(struct sshkey *k, int bits)
 {
-       RSA *private = NULL;
-       BIGNUM *f4 = NULL;
+       EVP_PKEY_CTX *ctx = NULL;
+       EVP_PKEY *res = NULL;
+
        int ret = SSH_ERR_INTERNAL_ERROR;
 
        if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
            bits > SSHBUF_MAX_BIGNUM * 8)
                return SSH_ERR_KEY_LENGTH;
-       if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
+
+       if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL) {
                ret = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if (!BN_set_word(f4, RSA_F4) ||
-           !RSA_generate_key_ex(private, bits, f4, NULL)) {
+       if (EVP_PKEY_keygen_init(ctx) <= 0) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) {
+               ret = SSH_ERR_KEY_LENGTH;
+               goto out;
+       }
+       if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) {
                ret = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-       k->rsa = private;
-       private = NULL;
+       /* success */
+       k->pkey = res;
        ret = 0;
  out:
-       RSA_free(private);
-       BN_free(f4);
+       EVP_PKEY_CTX_free(ctx);
        return ret;
 }
 
@@ -155,21 +152,33 @@ ssh_rsa_copy_public(const struct sshkey *from, struct sshkey *to)
        const BIGNUM *rsa_n, *rsa_e;
        BIGNUM *rsa_n_dup = NULL, *rsa_e_dup = NULL;
        int r = SSH_ERR_INTERNAL_ERROR;
+       const RSA *rsa_from;
+       RSA *rsa_to = NULL;
 
-       RSA_get0_key(from->rsa, &rsa_n, &rsa_e, NULL);
+       if ((rsa_from = EVP_PKEY_get0_RSA(from->pkey)) == NULL ||
+           (rsa_to = RSA_new()) == NULL)
+               return SSH_ERR_LIBCRYPTO_ERROR;
+
+       RSA_get0_key(rsa_from, &rsa_n, &rsa_e, NULL);
        if ((rsa_n_dup = BN_dup(rsa_n)) == NULL ||
            (rsa_e_dup = BN_dup(rsa_e)) == NULL) {
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if (!RSA_set0_key(to->rsa, rsa_n_dup, rsa_e_dup, NULL)) {
+       if (!RSA_set0_key(rsa_to, rsa_n_dup, rsa_e_dup, NULL)) {
                r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
        rsa_n_dup = rsa_e_dup = NULL; /* transferred */
+
+       if (EVP_PKEY_set1_RSA(to->pkey, rsa_to) != 1) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
        /* success */
        r = 0;
  out:
+       RSA_free(rsa_to);
        BN_clear_free(rsa_n_dup);
        BN_clear_free(rsa_e_dup);
        return r;
@@ -181,25 +190,34 @@ ssh_rsa_deserialize_public(const char *ktype, struct sshbuf *b,
 {
        int ret = SSH_ERR_INTERNAL_ERROR;
        BIGNUM *rsa_n = NULL, *rsa_e = NULL;
+       RSA *rsa = NULL;
+
+       if ((rsa = RSA_new()) == NULL)
+               return SSH_ERR_LIBCRYPTO_ERROR;
 
        if (sshbuf_get_bignum2(b, &rsa_e) != 0 ||
            sshbuf_get_bignum2(b, &rsa_n) != 0) {
                ret = SSH_ERR_INVALID_FORMAT;
                goto out;
        }
-       if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
+       if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
                ret = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
        rsa_n = rsa_e = NULL; /* transferred */
+       if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
        if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
                goto out;
 #ifdef DEBUG_PK
-       RSA_print_fp(stderr, key->rsa, 8);
+       RSA_print_fp(stderr, rsa, 8);
 #endif
        /* success */
        ret = 0;
  out:
+       RSA_free(rsa);
        BN_clear_free(rsa_n);
        BN_clear_free(rsa_e);
        return ret;
@@ -212,13 +230,25 @@ ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
        int r;
        BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL;
        BIGNUM *rsa_iqmp = NULL, *rsa_p = NULL, *rsa_q = NULL;
+       BIGNUM *rsa_dmp1 = NULL, *rsa_dmq1 = NULL;
+       RSA *rsa = NULL;
 
-       /* Note: can't reuse ssh_rsa_deserialize_public: e, n vs. n, e */
-       if (!sshkey_is_cert(key)) {
+       if (sshkey_is_cert(key)) {
+               /* sshkey_private_deserialize already has pubkey from cert */
+               if ((rsa = EVP_PKEY_get1_RSA(key->pkey)) == NULL) {
+                       r = SSH_ERR_LIBCRYPTO_ERROR;
+                       goto out;
+               }
+       } else {
+               if ((rsa = RSA_new()) == NULL) {
+                       r = SSH_ERR_LIBCRYPTO_ERROR;
+                       goto out;
+               }
+               /* Note: can't reuse ssh_rsa_deserialize_public: e,n vs. n,e */
                if ((r = sshbuf_get_bignum2(b, &rsa_n)) != 0 ||
                    (r = sshbuf_get_bignum2(b, &rsa_e)) != 0)
                        goto out;
-               if (!RSA_set0_key(key->rsa, rsa_n, rsa_e, NULL)) {
+               if (!RSA_set0_key(rsa, rsa_n, rsa_e, NULL)) {
                        r = SSH_ERR_LIBCRYPTO_ERROR;
                        goto out;
                }
@@ -229,33 +259,46 @@ ssh_rsa_deserialize_private(const char *ktype, struct sshbuf *b,
            (r = sshbuf_get_bignum2(b, &rsa_p)) != 0 ||
            (r = sshbuf_get_bignum2(b, &rsa_q)) != 0)
                goto out;
-       if (!RSA_set0_key(key->rsa, NULL, NULL, rsa_d)) {
+       if ((r = ssh_rsa_complete_crt_parameters(rsa_d, rsa_p, rsa_q,
+           rsa_iqmp, &rsa_dmp1, &rsa_dmq1)) != 0)
+               goto out;
+       if (!RSA_set0_key(rsa, NULL, NULL, rsa_d)) {
                r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
        rsa_d = NULL; /* transferred */
-       if (!RSA_set0_factors(key->rsa, rsa_p, rsa_q)) {
+       if (!RSA_set0_factors(rsa, rsa_p, rsa_q)) {
                r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
        rsa_p = rsa_q = NULL; /* transferred */
-       if ((r = sshkey_check_rsa_length(key, 0)) != 0)
+       if (!RSA_set0_crt_params(rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
-       if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0)
+       }
+       rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL;
+       if (RSA_blinding_on(rsa, NULL) != 1) {
+               r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
-       if (RSA_blinding_on(key->rsa, NULL) != 1) {
+       }
+       if (EVP_PKEY_set1_RSA(key->pkey, rsa) != 1) {
                r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
+       if ((r = sshkey_check_rsa_length(key, 0)) != 0)
+               goto out;
        /* success */
        r = 0;
  out:
+       RSA_free(rsa);
        BN_clear_free(rsa_n);
        BN_clear_free(rsa_e);
        BN_clear_free(rsa_d);
        BN_clear_free(rsa_p);
        BN_clear_free(rsa_q);
        BN_clear_free(rsa_iqmp);
+       BN_clear_free(rsa_dmp1);
+       BN_clear_free(rsa_dmq1);
        return r;
 }
 
@@ -310,45 +353,23 @@ rsa_hash_id_from_keyname(const char *alg)
        return -1;
 }
 
-static int
-rsa_hash_alg_nid(int type)
-{
-       switch (type) {
-       case SSH_DIGEST_SHA1:
-               return NID_sha1;
-       case SSH_DIGEST_SHA256:
-               return NID_sha256;
-       case SSH_DIGEST_SHA512:
-               return NID_sha512;
-       default:
-               return -1;
-       }
-}
-
 int
-ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
+ssh_rsa_complete_crt_parameters(const BIGNUM *rsa_d, const BIGNUM *rsa_p,
+    const BIGNUM *rsa_q, const BIGNUM *rsa_iqmp, BIGNUM **rsa_dmp1,
+    BIGNUM **rsa_dmq1)
 {
-       const BIGNUM *rsa_p, *rsa_q, *rsa_d;
        BIGNUM *aux = NULL, *d_consttime = NULL;
-       BIGNUM *rsa_dmq1 = NULL, *rsa_dmp1 = NULL, *rsa_iqmp = NULL;
        BN_CTX *ctx = NULL;
        int r;
 
-       if (key == NULL || key->rsa == NULL ||
-           sshkey_type_plain(key->type) != KEY_RSA)
-               return SSH_ERR_INVALID_ARGUMENT;
-
-       RSA_get0_key(key->rsa, NULL, NULL, &rsa_d);
-       RSA_get0_factors(key->rsa, &rsa_p, &rsa_q);
-
+       *rsa_dmq1 = *rsa_dmp1 = NULL;
        if ((ctx = BN_CTX_new()) == NULL)
                return SSH_ERR_ALLOC_FAIL;
        if ((aux = BN_new()) == NULL ||
-           (rsa_dmq1 = BN_new()) == NULL ||
-           (rsa_dmp1 = BN_new()) == NULL)
+           (*rsa_dmq1 = BN_new()) == NULL ||
+           (*rsa_dmp1 = BN_new()) == NULL)
                return SSH_ERR_ALLOC_FAIL;
-       if ((d_consttime = BN_dup(rsa_d)) == NULL ||
-           (rsa_iqmp = BN_dup(iqmp)) == NULL) {
+       if ((d_consttime = BN_dup(rsa_d)) == NULL) {
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
@@ -356,25 +377,17 @@ ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp)
        BN_set_flags(d_consttime, BN_FLG_CONSTTIME);
 
        if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) ||
-           (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) ||
+           (BN_mod(*rsa_dmq1, d_consttime, aux, ctx) == 0) ||
            (BN_sub(aux, rsa_p, BN_value_one()) == 0) ||
-           (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) {
+           (BN_mod(*rsa_dmp1, d_consttime, aux, ctx) == 0)) {
                r = SSH_ERR_LIBCRYPTO_ERROR;
                goto out;
        }
-       if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) {
-               r = SSH_ERR_LIBCRYPTO_ERROR;
-               goto out;
-       }
-       rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */
        /* success */
        r = 0;
  out:
        BN_clear_free(aux);
        BN_clear_free(d_consttime);
-       BN_clear_free(rsa_dmp1);
-       BN_clear_free(rsa_dmq1);
-       BN_clear_free(rsa_iqmp);
        BN_CTX_free(ctx);
        return r;
 }
@@ -386,11 +399,10 @@ ssh_rsa_sign(struct sshkey *key,
     const u_char *data, size_t datalen,
     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
 {
-       const BIGNUM *rsa_n;
-       u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL;
-       size_t slen = 0;
-       u_int hlen, len;
-       int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
+       u_char *sig = NULL;
+       size_t diff, len = 0;
+       int slen = 0;
+       int hash_alg, ret = SSH_ERR_INTERNAL_ERROR;
        struct sshbuf *b = NULL;
 
        if (lenp != NULL)
@@ -402,41 +414,28 @@ ssh_rsa_sign(struct sshkey *key,
                hash_alg = SSH_DIGEST_SHA1;
        else
                hash_alg = rsa_hash_id_from_keyname(alg);
-       if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
+
+       if (key == NULL || key->pkey == NULL || hash_alg == -1 ||
            sshkey_type_plain(key->type) != KEY_RSA)
                return SSH_ERR_INVALID_ARGUMENT;
-       RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
-       if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
-               return SSH_ERR_KEY_LENGTH;
-       slen = RSA_size(key->rsa);
+       slen = EVP_PKEY_size(key->pkey);
        if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
                return SSH_ERR_INVALID_ARGUMENT;
+       if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+               return SSH_ERR_KEY_LENGTH;
 
-       /* hash the data */
-       nid = rsa_hash_alg_nid(hash_alg);
-       if ((hlen = ssh_digest_bytes(hash_alg)) == 0)
-               return SSH_ERR_INTERNAL_ERROR;
-       if ((ret = ssh_digest_memory(hash_alg, data, datalen,
-           digest, sizeof(digest))) != 0)
-               goto out;
-
-       if ((sig = malloc(slen)) == NULL) {
-               ret = SSH_ERR_ALLOC_FAIL;
-               goto out;
-       }
-
-       if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) {
-               ret = SSH_ERR_LIBCRYPTO_ERROR;
+       if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sig, &len,
+           data, datalen)) < 0)
                goto out;
-       }
-       if (len < slen) {
-               size_t diff = slen - len;
+       if (len < (size_t)slen) {
+               diff = slen - len;
                memmove(sig + diff, sig, len);
                explicit_bzero(sig, diff);
-       } else if (len > slen) {
+       } else if (len > (size_t)slen) {
                ret = SSH_ERR_INTERNAL_ERROR;
                goto out;
        }
+
        /* encode signature */
        if ((b = sshbuf_new()) == NULL) {
                ret = SSH_ERR_ALLOC_FAIL;
@@ -457,7 +456,6 @@ ssh_rsa_sign(struct sshkey *key,
                *lenp = len;
        ret = 0;
  out:
-       explicit_bzero(digest, sizeof(digest));
        freezero(sig, slen);
        sshbuf_free(b);
        return ret;
@@ -469,19 +467,17 @@ ssh_rsa_verify(const struct sshkey *key,
     const u_char *data, size_t dlen, const char *alg, u_int compat,
     struct sshkey_sig_details **detailsp)
 {
-       const BIGNUM *rsa_n;
        char *sigtype = NULL;
        int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR;
-       size_t len = 0, diff, modlen, hlen;
+       size_t len = 0, diff, modlen, rsasize;
        struct sshbuf *b = NULL;
        u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL;
 
-       if (key == NULL || key->rsa == NULL ||
+       if (key == NULL || key->pkey == NULL ||
            sshkey_type_plain(key->type) != KEY_RSA ||
            sig == NULL || siglen == 0)
                return SSH_ERR_INVALID_ARGUMENT;
-       RSA_get0_key(key->rsa, &rsa_n, NULL, NULL);
-       if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+       if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE)
                return SSH_ERR_KEY_LENGTH;
 
        if ((b = sshbuf_from(sig, siglen)) == NULL)
@@ -517,7 +513,7 @@ ssh_rsa_verify(const struct sshkey *key,
                goto out;
        }
        /* RSA_verify expects a signature of RSA_size */
-       modlen = RSA_size(key->rsa);
+       modlen = EVP_PKEY_size(key->pkey);
        if (len > modlen) {
                ret = SSH_ERR_KEY_BITS_MISMATCH;
                goto out;
@@ -533,16 +529,16 @@ ssh_rsa_verify(const struct sshkey *key,
                explicit_bzero(sigblob, diff);
                len = modlen;
        }
-       if ((hlen = ssh_digest_bytes(hash_alg)) == 0) {
-               ret = SSH_ERR_INTERNAL_ERROR;
+
+       rsasize = EVP_PKEY_size(key->pkey);
+       if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
+           len == 0 || len > rsasize) {
+               ret = SSH_ERR_INVALID_ARGUMENT;
                goto out;
        }
-       if ((ret = ssh_digest_memory(hash_alg, data, dlen,
-           digest, sizeof(digest))) != 0)
-               goto out;
+       ret = sshkey_pkey_digest_verify(key->pkey, hash_alg, data, dlen,
+           sigblob, len);
 
-       ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len,
-           key->rsa);
  out:
        freezero(sigblob, len);
        free(sigtype);
@@ -551,125 +547,6 @@ ssh_rsa_verify(const struct sshkey *key,
        return ret;
 }
 
-/*
- * See:
- * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
- * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn
- */
-
-/*
- * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
- *     oiw(14) secsig(3) algorithms(2) 26 }
- */
-static const u_char id_sha1[] = {
-       0x30, 0x21, /* type Sequence, length 0x21 (33) */
-       0x30, 0x09, /* type Sequence, length 0x09 */
-       0x06, 0x05, /* type OID, length 0x05 */
-       0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */
-       0x05, 0x00, /* NULL */
-       0x04, 0x14  /* Octet string, length 0x14 (20), followed by sha1 hash */
-};
-
-/*
- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
- * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
- *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
- *      id-sha256(1) }
- */
-static const u_char id_sha256[] = {
-       0x30, 0x31, /* type Sequence, length 0x31 (49) */
-       0x30, 0x0d, /* type Sequence, length 0x0d (13) */
-       0x06, 0x09, /* type OID, length 0x09 */
-       0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */
-       0x05, 0x00, /* NULL */
-       0x04, 0x20  /* Octet string, length 0x20 (32), followed by sha256 hash */
-};
-
-/*
- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html
- * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
- *      organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2)
- *      id-sha256(3) }
- */
-static const u_char id_sha512[] = {
-       0x30, 0x51, /* type Sequence, length 0x51 (81) */
-       0x30, 0x0d, /* type Sequence, length 0x0d (13) */
-       0x06, 0x09, /* type OID, length 0x09 */
-       0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */
-       0x05, 0x00, /* NULL */
-       0x04, 0x40  /* Octet string, length 0x40 (64), followed by sha512 hash */
-};
-
-static int
-rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp)
-{
-       switch (hash_alg) {
-       case SSH_DIGEST_SHA1:
-               *oidp = id_sha1;
-               *oidlenp = sizeof(id_sha1);
-               break;
-       case SSH_DIGEST_SHA256:
-               *oidp = id_sha256;
-               *oidlenp = sizeof(id_sha256);
-               break;
-       case SSH_DIGEST_SHA512:
-               *oidp = id_sha512;
-               *oidlenp = sizeof(id_sha512);
-               break;
-       default:
-               return SSH_ERR_INVALID_ARGUMENT;
-       }
-       return 0;
-}
-
-static int
-openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen,
-    u_char *sigbuf, size_t siglen, RSA *rsa)
-{
-       size_t rsasize = 0, oidlen = 0, hlen = 0;
-       int ret, len, oidmatch, hashmatch;
-       const u_char *oid = NULL;
-       u_char *decrypted = NULL;
-
-       if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0)
-               return ret;
-       ret = SSH_ERR_INTERNAL_ERROR;
-       hlen = ssh_digest_bytes(hash_alg);
-       if (hashlen != hlen) {
-               ret = SSH_ERR_INVALID_ARGUMENT;
-               goto done;
-       }
-       rsasize = RSA_size(rsa);
-       if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM ||
-           siglen == 0 || siglen > rsasize) {
-               ret = SSH_ERR_INVALID_ARGUMENT;
-               goto done;
-       }
-       if ((decrypted = malloc(rsasize)) == NULL) {
-               ret = SSH_ERR_ALLOC_FAIL;
-               goto done;
-       }
-       if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa,
-           RSA_PKCS1_PADDING)) < 0) {
-               ret = SSH_ERR_LIBCRYPTO_ERROR;
-               goto done;
-       }
-       if (len < 0 || (size_t)len != hlen + oidlen) {
-               ret = SSH_ERR_INVALID_FORMAT;
-               goto done;
-       }
-       oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0;
-       hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0;
-       if (!oidmatch || !hashmatch) {
-               ret = SSH_ERR_SIGNATURE_INVALID;
-               goto done;
-       }
-       ret = 0;
-done:
-       freezero(decrypted, rsasize);
-       return ret;
-}
-
 static const struct sshkey_impl_funcs sshkey_rsa_funcs = {
        /* .size = */           ssh_rsa_size,
        /* .alloc = */          ssh_rsa_alloc,
index d6eea2e..2b36b3f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-sk.c,v 1.40 2023/07/19 14:02:27 djm Exp $ */
+/* $OpenBSD: ssh-sk.c,v 1.41 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2019 Google LLC
  *
@@ -26,6 +26,7 @@
 #ifdef WITH_OPENSSL
 #include <openssl/objects.h>
 #include <openssl/ec.h>
+#include <openssl/evp.h>
 #endif /* WITH_OPENSSL */
 
 #include "log.h"
@@ -188,7 +189,9 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
 {
        struct sshkey *key = NULL;
        struct sshbuf *b = NULL;
+       EC_KEY *ecdsa = NULL;
        EC_POINT *q = NULL;
+       const EC_GROUP *g = NULL;
        int r;
 
        *keyp = NULL;
@@ -198,8 +201,9 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
                goto out;
        }
        key->ecdsa_nid = NID_X9_62_prime256v1;
-       if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL ||
-           (q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL ||
+       if ((ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL ||
+           (g = EC_KEY_get0_group(ecdsa)) == NULL ||
+           (q = EC_POINT_new(g)) == NULL ||
            (b = sshbuf_new()) == NULL) {
                error_f("allocation failed");
                r = SSH_ERR_ALLOC_FAIL;
@@ -210,30 +214,41 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
                error_fr(r, "sshbuf_put_string");
                goto out;
        }
-       if ((r = sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa))) != 0) {
+       if ((r = sshbuf_get_ec(b, q, g)) != 0) {
                error_fr(r, "parse");
                r = SSH_ERR_INVALID_FORMAT;
                goto out;
        }
-       if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), q) != 0) {
+       if (sshkey_ec_validate_public(g, q) != 0) {
                error("Authenticator returned invalid ECDSA key");
                r = SSH_ERR_KEY_INVALID_EC_VALUE;
                goto out;
        }
-       if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
+       if (EC_KEY_set_public_key(ecdsa, q) != 1) {
                /* XXX assume it is a allocation error */
                error_f("allocation failed");
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
+       if ((key->pkey = EVP_PKEY_new()) == NULL) {
+               error_f("allocation failed");
+               r = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if (EVP_PKEY_set1_EC_KEY(key->pkey, ecdsa) != 1) {
+               error_f("Assigning EC_KEY failed");
+               r = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
        /* success */
        *keyp = key;
        key = NULL; /* transferred */
        r = 0;
  out:
-       EC_POINT_free(q);
        sshkey_free(key);
        sshbuf_free(b);
+       EC_KEY_free(ecdsa);
+       EC_POINT_free(q);
        return r;
 }
 #endif /* WITH_OPENSSL */
index 02daaa1..dad46c9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sshbuf-getput-crypto.c,v 1.11 2024/02/01 02:37:33 djm Exp $   */
+/*     $OpenBSD: sshbuf-getput-crypto.c,v 1.12 2024/08/15 00:51:51 djm Exp $   */
 /*
  * Copyright (c) 2011 Damien Miller
  *
@@ -169,3 +169,12 @@ sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v)
            EC_KEY_get0_group(v));
 }
 
+int
+sshbuf_put_ec_pkey(struct sshbuf *buf, EVP_PKEY *pkey)
+{
+       const EC_KEY *ec;
+
+       if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL)
+               return SSH_ERR_LIBCRYPTO_ERROR;
+       return sshbuf_put_eckey(buf, ec);
+}
index 37c28a1..b159e88 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sshbuf.h,v 1.28 2022/12/02 04:40:27 djm Exp $ */
+/*     $OpenBSD: sshbuf.h,v 1.29 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2011 Damien Miller
  *
 #include <openssl/bn.h>
 #include <openssl/ec.h>
 #include <openssl/ecdsa.h>
+#include <openssl/evp.h>
 #else /* OPENSSL */
 #define BIGNUM         void
 #define EC_KEY         void
 #define EC_GROUP       void
 #define EC_POINT       void
+#define EVP_PKEY       void
 #endif /* WITH_OPENSSL */
 
 #define SSHBUF_SIZE_MAX                0x8000000       /* Hard maximum size */
@@ -226,6 +228,7 @@ int sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g);
 int    sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v);
 int    sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g);
 int    sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v);
+int    sshbuf_put_ec_pkey(struct sshbuf *buf, EVP_PKEY *pkey);
 
 /* Dump the contents of the buffer in a human-readable format */
 void   sshbuf_dump(const struct sshbuf *buf, FILE *f);
index 5203cc6..ef9c858 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.142 2024/01/11 01:45:36 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.143 2024/08/15 00:51:51 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -460,6 +460,98 @@ sshkey_type_certified(int type)
 }
 
 #ifdef WITH_OPENSSL
+static const EVP_MD *
+ssh_digest_to_md(int hash_alg)
+{
+       switch (hash_alg) {
+       case SSH_DIGEST_SHA1:
+               return EVP_sha1();
+       case SSH_DIGEST_SHA256:
+               return EVP_sha256();
+       case SSH_DIGEST_SHA384:
+               return EVP_sha384();
+       case SSH_DIGEST_SHA512:
+               return EVP_sha512();
+       }
+       return NULL;
+}
+
+int
+sshkey_pkey_digest_sign(EVP_PKEY *pkey, int hash_alg, u_char **sigp,
+    size_t *lenp, const u_char *data, size_t datalen)
+{
+       EVP_MD_CTX *ctx = NULL;
+       u_char *sig = NULL;
+       int ret;
+       size_t slen;
+       const EVP_MD *evpmd;
+
+       *sigp = NULL;
+       *lenp = 0;
+
+       slen = EVP_PKEY_size(pkey);
+       if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM ||
+          (evpmd = ssh_digest_to_md(hash_alg)) == NULL)
+               return SSH_ERR_INVALID_ARGUMENT;
+
+       if ((sig = malloc(slen)) == NULL)
+               return SSH_ERR_ALLOC_FAIL;
+
+       if ((ctx = EVP_MD_CTX_new()) == NULL) {
+               ret = SSH_ERR_ALLOC_FAIL;
+               goto out;
+       }
+       if (EVP_DigestSignInit(ctx, NULL, evpmd, NULL, pkey) != 1 ||
+           EVP_DigestSign(ctx, sig, &slen, data, datalen) != 1) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+
+       *sigp = sig;
+       *lenp = slen;
+       /* Now owned by the caller */
+       sig = NULL;
+       ret = 0;
+
+ out:
+       EVP_MD_CTX_free(ctx);
+       free(sig);
+       return ret;
+}
+
+int
+sshkey_pkey_digest_verify(EVP_PKEY *pkey, int hash_alg, const u_char *data,
+    size_t datalen, u_char *sigbuf, size_t siglen)
+{
+       EVP_MD_CTX *ctx = NULL;
+       int ret = SSH_ERR_INTERNAL_ERROR;
+       const EVP_MD *evpmd;
+
+       if ((evpmd = ssh_digest_to_md(hash_alg)) == NULL)
+               return SSH_ERR_INVALID_ARGUMENT;
+       if ((ctx = EVP_MD_CTX_new()) == NULL)
+               return SSH_ERR_ALLOC_FAIL;
+       if (EVP_DigestVerifyInit(ctx, NULL, evpmd, NULL, pkey) != 1) {
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               goto out;
+       }
+       switch (EVP_DigestVerify(ctx, sigbuf, siglen, data, datalen)) {
+       case 1:
+               ret = 0;
+               break;
+       case 0:
+               ret = SSH_ERR_SIGNATURE_INVALID;
+               break;
+       default:
+               ret = SSH_ERR_LIBCRYPTO_ERROR;
+               break;
+       }
+
+ out:
+       EVP_MD_CTX_free(ctx);
+       return ret;
+}
+
 /* XXX: these are really begging for a table-driven approach */
 int
 sshkey_curve_name_to_nid(const char *name)
@@ -1302,14 +1394,12 @@ int
 sshkey_check_rsa_length(const struct sshkey *k, int min_size)
 {
 #ifdef WITH_OPENSSL
-       const BIGNUM *rsa_n;
        int nbits;
 
-       if (k == NULL || k->rsa == NULL ||
+       if (k == NULL || k->pkey == NULL ||
            (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
                return 0;
-       RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
-       nbits = BN_num_bits(rsa_n);
+       nbits = EVP_PKEY_bits(k->pkey);
        if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
            (min_size > 0 && nbits < min_size))
                return SSH_ERR_KEY_LENGTH;
@@ -1319,45 +1409,22 @@ sshkey_check_rsa_length(const struct sshkey *k, int min_size)
 
 #ifdef WITH_OPENSSL
 int
-sshkey_ecdsa_key_to_nid(EC_KEY *k)
+sshkey_ecdsa_key_to_nid(const EC_KEY *k)
 {
-       EC_GROUP *eg;
-       int nids[] = {
-               NID_X9_62_prime256v1,
-               NID_secp384r1,
-               NID_secp521r1,
-               -1
-       };
+       const EC_GROUP *g;
        int nid;
-       u_int i;
-       const EC_GROUP *g = EC_KEY_get0_group(k);
 
-       /*
-        * The group may be stored in a ASN.1 encoded private key in one of two
-        * ways: as a "named group", which is reconstituted by ASN.1 object ID
-        * or explicit group parameters encoded into the key blob. Only the
-        * "named group" case sets the group NID for us, but we can figure
-        * it out for the other case by comparing against all the groups that
-        * are supported.
-        */
-       if ((nid = EC_GROUP_get_curve_name(g)) > 0)
-               return nid;
-       for (i = 0; nids[i] != -1; i++) {
-               if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL)
-                       return -1;
-               if (EC_GROUP_cmp(g, eg, NULL) == 0)
-                       break;
-               EC_GROUP_free(eg);
-       }
-       if (nids[i] != -1) {
-               /* Use the group with the NID attached */
-               EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE);
-               if (EC_KEY_set_group(k, eg) != 1) {
-                       EC_GROUP_free(eg);
-                       return -1;
-               }
-       }
-       return nids[i];
+       if (k == NULL || (g = EC_KEY_get0_group(k)) == NULL)
+               return -1;
+       if ((nid = EC_GROUP_get_curve_name(g)) <= 0)
+               return -1;
+       return nid;
+}
+
+int
+sshkey_ecdsa_pkey_to_nid(EVP_PKEY *pkey)
+{
+       return sshkey_ecdsa_key_to_nid(EVP_PKEY_get0_EC_KEY(pkey));
 }
 #endif /* WITH_OPENSSL */
 
@@ -3193,10 +3260,6 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf,
                r = SSH_ERR_ALLOC_FAIL;
                goto out;
        }
-       if (format == SSHKEY_PRIVATE_PKCS8 && (pkey = EVP_PKEY_new()) == NULL) {
-               r = SSH_ERR_ALLOC_FAIL;
-               goto out;
-       }
        if ((r = sshkey_unshield_private(key)) != 0)
                goto out;
 
@@ -3207,24 +3270,34 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf,
                        success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
                            cipher, passphrase, len, NULL, NULL);
                } else {
+                       if ((pkey = EVP_PKEY_new()) == NULL) {
+                               r = SSH_ERR_ALLOC_FAIL;
+                               goto out;
+                       }
                        success = EVP_PKEY_set1_DSA(pkey, key->dsa);
                }
                break;
 #endif
        case KEY_ECDSA:
                if (format == SSHKEY_PRIVATE_PEM) {
-                       success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
+                       success = PEM_write_bio_ECPrivateKey(bio,
+                           EVP_PKEY_get0_EC_KEY(key->pkey),
                            cipher, passphrase, len, NULL, NULL);
                } else {
-                       success = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa);
+                       pkey = key->pkey;
+                       EVP_PKEY_up_ref(key->pkey);
+                       success = 1;
                }
                break;
        case KEY_RSA:
                if (format == SSHKEY_PRIVATE_PEM) {
-                       success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
+                       success = PEM_write_bio_RSAPrivateKey(bio,
+                           EVP_PKEY_get0_RSA(key->pkey),
                            cipher, passphrase, len, NULL, NULL);
                } else {
-                       success = EVP_PKEY_set1_RSA(pkey, key->rsa);
+                       pkey = key->pkey;
+                       EVP_PKEY_up_ref(key->pkey);
+                       success = 1;
                }
                break;
        default:
@@ -3373,6 +3446,8 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
        struct sshkey *prv = NULL;
        BIO *bio = NULL;
        int r;
+       RSA *rsa = NULL;
+       EC_KEY *ecdsa = NULL;
 
        if (keyp != NULL)
                *keyp = NULL;
@@ -3406,15 +3481,21 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
                        r = SSH_ERR_ALLOC_FAIL;
                        goto out;
                }
-               prv->rsa = EVP_PKEY_get1_RSA(pk);
+               if ((rsa = EVP_PKEY_get1_RSA(pk)) == NULL) {
+                       r = SSH_ERR_LIBCRYPTO_ERROR;
+                       goto out;
+               }
                prv->type = KEY_RSA;
 #ifdef DEBUG_PK
-               RSA_print_fp(stderr, prv->rsa, 8);
+               RSA_print_fp(stderr, rsa, 8);
 #endif
-               if (RSA_blinding_on(prv->rsa, NULL) != 1) {
+               if (RSA_blinding_on(rsa, NULL) != 1 ||
+                   EVP_PKEY_set1_RSA(pk, rsa) != 1) {
                        r = SSH_ERR_LIBCRYPTO_ERROR;
                        goto out;
                }
+               EVP_PKEY_up_ref(pk);
+               prv->pkey = pk;
                if ((r = sshkey_check_rsa_length(prv, 0)) != 0)
                        goto out;
 #ifdef WITH_DSA
@@ -3436,20 +3517,24 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
                        r = SSH_ERR_ALLOC_FAIL;
                        goto out;
                }
-               prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
+               if ((prv->ecdsa_nid = sshkey_ecdsa_fixup_group(pk)) == -1 ||
+                   (ecdsa = EVP_PKEY_get1_EC_KEY(pk)) == NULL) {
+                       r = SSH_ERR_LIBCRYPTO_ERROR;
+                       goto out;
+               }
                prv->type = KEY_ECDSA;
-               prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa);
-               if (prv->ecdsa_nid == -1 ||
-                   sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
-                   sshkey_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
-                   EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
-                   sshkey_ec_validate_private(prv->ecdsa) != 0) {
+               if (sshkey_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
+                   sshkey_ec_validate_public(EC_KEY_get0_group(ecdsa),
+                   EC_KEY_get0_public_key(ecdsa)) != 0 ||
+                   sshkey_ec_validate_private(ecdsa) != 0) {
                        r = SSH_ERR_INVALID_FORMAT;
                        goto out;
                }
+               EVP_PKEY_up_ref(pk);
+               prv->pkey = pk;
 #ifdef DEBUG_PK
-               if (prv != NULL && prv->ecdsa != NULL)
-                       sshkey_dump_ec_key(prv->ecdsa);
+               if (prv != NULL && prv->pkey != NULL)
+                       sshkey_dump_ec_key(EVP_PKEY_get0_EC_KEY(prv->pkey));
 #endif
        } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_ED25519 &&
            (type == KEY_UNSPEC || type == KEY_ED25519)) {
@@ -3498,6 +3583,8 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
  out:
        BIO_free(bio);
        EVP_PKEY_free(pk);
+       RSA_free(rsa);
+       EC_KEY_free(ecdsa);
        sshkey_free(prv);
        return r;
 }
index e6877be..21298c6 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.63 2024/05/17 06:42:04 jsg Exp $ */
+/* $OpenBSD: sshkey.h,v 1.64 2024/08/15 00:51:51 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -33,6 +33,7 @@
 #include <openssl/dsa.h>
 #include <openssl/ec.h>
 #include <openssl/ecdsa.h>
+#include <openssl/evp.h>
 #define SSH_OPENSSL_VERSION OpenSSL_version(OPENSSL_VERSION)
 #else /* OPENSSL */
 #define BIGNUM         void
@@ -41,6 +42,7 @@
 #define EC_KEY         void
 #define EC_GROUP       void
 #define EC_POINT       void
+#define EVP_PKEY       void
 #define SSH_OPENSSL_VERSION "without OpenSSL"
 #endif /* WITH_OPENSSL */
 
@@ -119,13 +121,12 @@ struct sshkey_cert {
 struct sshkey {
        int      type;
        int      flags;
-       /* KEY_RSA */
-       RSA     *rsa;
        /* KEY_DSA */
        DSA     *dsa;
        /* KEY_ECDSA and KEY_ECDSA_SK */
        int      ecdsa_nid;     /* NID of curve */
-       EC_KEY  *ecdsa;
+       /* libcrypto-backed keys */
+       EVP_PKEY *pkey;
        /* KEY_ED25519 and KEY_ED25519_SK */
        u_char  *ed25519_sk;
        u_char  *ed25519_pk;
@@ -252,7 +253,8 @@ int          sshkey_curve_name_to_nid(const char *);
 const char *    sshkey_curve_nid_to_name(int);
 u_int           sshkey_curve_nid_to_bits(int);
 int             sshkey_ecdsa_bits_to_nid(int);
-int             sshkey_ecdsa_key_to_nid(EC_KEY *);
+int             sshkey_ecdsa_key_to_nid(const EC_KEY *);
+int             sshkey_ecdsa_pkey_to_nid(EVP_PKEY *);
 int             sshkey_ec_nid_to_hash_alg(int nid);
 int             sshkey_ec_validate_public(const EC_GROUP *, const EC_POINT *);
 int             sshkey_ec_validate_private(const EC_KEY *);
@@ -281,6 +283,12 @@ int         sshkey_check_sigtype(const u_char *, size_t, const char *);
 const char *sshkey_sigalg_by_name(const char *);
 int     sshkey_get_sigtype(const u_char *, size_t, char **);
 
+/* Signing and verification backend for libcrypto-backed keys */
+int    sshkey_pkey_digest_sign(EVP_PKEY*, int, u_char **,
+    size_t *, const u_char *, size_t);
+int    sshkey_pkey_digest_verify(EVP_PKEY *, int, const u_char *,
+    size_t, u_char *, size_t);
+
 /* for debug */
 void   sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *);
 void   sshkey_dump_ec_key(const EC_KEY *);
@@ -304,7 +312,8 @@ int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob,
 
 int sshkey_check_rsa_length(const struct sshkey *, int);
 /* XXX should be internal, but used by ssh-keygen */
-int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *);
+int ssh_rsa_complete_crt_parameters(const BIGNUM *, const BIGNUM *,
+    const BIGNUM *, const BIGNUM *, BIGNUM **, BIGNUM **);
 
 /* stateful keys (e.g. XMSS) */
 int     sshkey_set_filename(struct sshkey *, const char *);
@@ -315,6 +324,10 @@ int         sshkey_private_serialize_maxsign(struct sshkey *key,
 
 void    sshkey_sig_details_free(struct sshkey_sig_details *);
 
+#ifdef WITH_OPENSSL
+int    sshkey_ecdsa_fixup_group(EVP_PKEY *k); /* ssh-ecdsa.c */
+#endif
+
 #ifdef SSHKEY_INTERNAL
 int    sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b);
 void   sshkey_sk_cleanup(struct sshkey *k);
@@ -335,6 +348,7 @@ int check_rsa_length(const RSA *rsa); /* XXX remove */
 #undef EC_KEY
 #undef EC_GROUP
 #undef EC_POINT
+#undef EVP_PKEY
 #endif /* WITH_OPENSSL */
 
 #endif /* SSHKEY_H */