summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/ssh/packet.c7
-rw-r--r--usr.bin/ssh/packet.h5
-rw-r--r--usr.bin/ssh/ssh-ecdsa-sk.c49
-rw-r--r--usr.bin/ssh/ssh-ecdsa.c256
-rw-r--r--usr.bin/ssh/ssh-keygen.c61
-rw-r--r--usr.bin/ssh/ssh-pkcs11-client.c79
-rw-r--r--usr.bin/ssh/ssh-pkcs11-helper.c82
-rw-r--r--usr.bin/ssh/ssh-pkcs11.c42
-rw-r--r--usr.bin/ssh/ssh-rsa.c385
-rw-r--r--usr.bin/ssh/ssh-sk.c29
-rw-r--r--usr.bin/ssh/sshbuf-getput-crypto.c11
-rw-r--r--usr.bin/ssh/sshbuf.h5
-rw-r--r--usr.bin/ssh/sshkey.c209
-rw-r--r--usr.bin/ssh/sshkey.h26
14 files changed, 735 insertions, 511 deletions
diff --git a/usr.bin/ssh/packet.c b/usr.bin/ssh/packet.c
index 70c98dd0f03..07e7e1d99c2 100644
--- a/usr.bin/ssh/packet.c
+++ b/usr.bin/ssh/packet.c
@@ -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)
diff --git a/usr.bin/ssh/packet.h b/usr.bin/ssh/packet.h
index fc2c3278b87..db61136664c 100644
--- a/usr.bin/ssh/packet.h
+++ b/usr.bin/ssh/packet.h
@@ -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>
@@ -25,10 +25,12 @@
#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);
diff --git a/usr.bin/ssh/ssh-ecdsa-sk.c b/usr.bin/ssh/ssh-ecdsa-sk.c
index 15e993c440b..0502a499944 100644
--- a/usr.bin/ssh/ssh-ecdsa-sk.c
+++ b/usr.bin/ssh/ssh-ecdsa-sk.c
@@ -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;
}
diff --git a/usr.bin/ssh/ssh-ecdsa.c b/usr.bin/ssh/ssh-ecdsa.c
index 59ed0c84dcb..aa59b33cded 100644
--- a/usr.bin/ssh/ssh-ecdsa.c
+++ b/usr.bin/ssh/ssh-ecdsa.c
@@ -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.
@@ -39,6 +39,59 @@
#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);
diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c
index 844802650ef..4a95c5515ac 100644
--- a/usr.bin/ssh/ssh-keygen.c
+++ b/usr.bin/ssh/ssh-keygen.c
@@ -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));
diff --git a/usr.bin/ssh/ssh-pkcs11-client.c b/usr.bin/ssh/ssh-pkcs11-client.c
index af9ad1b887f..205139f43b5 100644
--- a/usr.bin/ssh/ssh-pkcs11-client.c
+++ b/usr.bin/ssh/ssh-pkcs11-client.c
@@ -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));
diff --git a/usr.bin/ssh/ssh-pkcs11-helper.c b/usr.bin/ssh/ssh-pkcs11-helper.c
index 1a62757c19d..3f79a0061d6 100644
--- a/usr.bin/ssh/ssh-pkcs11-helper.c
+++ b/usr.bin/ssh/ssh-pkcs11-helper.c
@@ -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);
diff --git a/usr.bin/ssh/ssh-pkcs11.c b/usr.bin/ssh/ssh-pkcs11.c
index e6c53f00e02..97c98cc9472 100644
--- a/usr.bin/ssh/ssh-pkcs11.c
+++ b/usr.bin/ssh/ssh-pkcs11.c
@@ -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;
diff --git a/usr.bin/ssh/ssh-rsa.c b/usr.bin/ssh/ssh-rsa.c
index 59f7cd28a9f..6492e607bd7 100644
--- a/usr.bin/ssh/ssh-rsa.c
+++ b/usr.bin/ssh/ssh-rsa.c
@@ -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>
*
@@ -29,23 +29,18 @@
#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,
diff --git a/usr.bin/ssh/ssh-sk.c b/usr.bin/ssh/ssh-sk.c
index d6eea2e054b..2b36b3ff92e 100644
--- a/usr.bin/ssh/ssh-sk.c
+++ b/usr.bin/ssh/ssh-sk.c
@@ -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 */
diff --git a/usr.bin/ssh/sshbuf-getput-crypto.c b/usr.bin/ssh/sshbuf-getput-crypto.c
index 02daaa11bb6..dad46c95612 100644
--- a/usr.bin/ssh/sshbuf-getput-crypto.c
+++ b/usr.bin/ssh/sshbuf-getput-crypto.c
@@ -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);
+}
diff --git a/usr.bin/ssh/sshbuf.h b/usr.bin/ssh/sshbuf.h
index 37c28a12767..b159e88996d 100644
--- a/usr.bin/ssh/sshbuf.h
+++ b/usr.bin/ssh/sshbuf.h
@@ -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
*
@@ -26,11 +26,13 @@
#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);
diff --git a/usr.bin/ssh/sshkey.c b/usr.bin/ssh/sshkey.c
index 5203cc66356..ef9c8584519 100644
--- a/usr.bin/ssh/sshkey.c
+++ b/usr.bin/ssh/sshkey.c
@@ -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;
}
diff --git a/usr.bin/ssh/sshkey.h b/usr.bin/ssh/sshkey.h
index e6877becdaf..21298c6f2ef 100644
--- a/usr.bin/ssh/sshkey.h
+++ b/usr.bin/ssh/sshkey.h
@@ -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 */