diff --git a/packet.c b/packet.c index 4fca8d660..d29b3ad31 100644 --- a/packet.c +++ b/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 * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -2650,8 +2650,13 @@ sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g) { return sshbuf_put_ec(ssh->state->outgoing_packet, v, g); } -#endif /* OPENSSL_HAS_ECC */ +int +sshpkt_put_ec_pkey(struct ssh *ssh, EVP_PKEY *pkey) +{ + return sshbuf_put_ec_pkey(ssh->state->outgoing_packet, pkey); +} +#endif /* OPENSSL_HAS_ECC */ int sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v) diff --git a/packet.h b/packet.h index 5ab1f409a..49bb87f07 100644 --- a/packet.h +++ b/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 @@ -20,6 +20,7 @@ #ifdef WITH_OPENSSL # include +# include # ifdef OPENSSL_HAS_ECC # include # else /* OPENSSL_HAS_ECC */ @@ -32,6 +33,7 @@ # define EC_KEY void # define EC_GROUP void # define EC_POINT void +# define EVP_PKEY void #endif /* WITH_OPENSSL */ #include @@ -191,6 +193,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); @@ -213,6 +216,7 @@ const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); # undef EC_KEY # undef EC_GROUP # undef EC_POINT +# undef EVP_PKEY #elif !defined(OPENSSL_HAS_ECC) # undef EC_KEY # undef EC_GROUP diff --git a/ssh-ecdsa-sk.c b/ssh-ecdsa-sk.c index 5dcd3c13d..27ddf904b 100644 --- a/ssh-ecdsa-sk.c +++ b/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. @@ -237,11 +237,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; @@ -252,7 +254,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; @@ -363,21 +365,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; @@ -397,7 +421,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); @@ -410,6 +433,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/ssh-ecdsa.c b/ssh-ecdsa.c index 341c32409..695ed451e 100644 --- a/ssh-ecdsa.c +++ b/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. @@ -45,6 +45,61 @@ #include "openbsd-compat/openssl-compat.h" +int +sshkey_ecdsa_fixup_group(EVP_PKEY *k) +{ + int nids[] = { + NID_X9_62_prime256v1, + NID_secp384r1, +#ifdef OPENSSL_HAS_NISTP521 + NID_secp521r1, +#endif + -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) { @@ -65,30 +120,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) + if (a->pkey == NULL || b->pkey == 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) - 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 @@ -97,11 +138,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; @@ -118,7 +159,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; } @@ -126,31 +167,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 @@ -159,6 +233,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; @@ -168,31 +244,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; } @@ -202,6 +286,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) @@ -209,16 +294,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 ((r = sshkey_ec_validate_private(key->ecdsa)) != 0) + if (EC_KEY_set_private_key(ec, exponent) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; goto out; + } + 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; } @@ -229,34 +323,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; @@ -280,7 +375,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); @@ -295,20 +390,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 */ @@ -334,6 +427,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; @@ -344,28 +442,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; - 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; - goto out; - default: + 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; + } + 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/ssh-keygen.c b/ssh-keygen.c index 97c6d134a..122d0e539 100644 --- a/ssh-keygen.c +++ b/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 * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland @@ -375,7 +375,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 @@ -386,7 +387,8 @@ do_convert_to_pkcs8(struct sshkey *k) #endif #ifdef OPENSSL_HAS_ECC 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; #endif @@ -401,7 +403,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 @@ -412,7 +415,8 @@ do_convert_to_pem(struct sshkey *k) #endif #ifdef OPENSSL_HAS_ECC 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; #endif @@ -490,6 +494,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"); @@ -584,15 +590,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; } @@ -712,7 +728,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: @@ -726,9 +743,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; #endif default: @@ -750,8 +769,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; } @@ -799,13 +822,15 @@ do_convert_from(struct passwd *pw) #endif #ifdef OPENSSL_HAS_ECC 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; #endif 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/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 5fa8bf02b..b8d1700f0 100644 --- a/ssh-pkcs11-client.c +++ b/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. @@ -264,14 +264,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; @@ -339,21 +342,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"); @@ -408,16 +412,31 @@ 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); #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) } 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); #endif } else fatal_f("unknown key type"); @@ -437,6 +456,10 @@ pkcs11_make_cert(const struct sshkey *priv, struct helper *helper = NULL; struct sshkey *ret; int r; + RSA *rsa_priv = NULL, *rsa_cert = NULL; +#if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) + EC_KEY *ec_priv = NULL, *ec_cert = NULL; +#endif debug3_f("private key type %s cert type %s", sshkey_type(priv), sshkey_type(certpub)); @@ -449,24 +472,42 @@ 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); #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) } 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); #endif } else fatal_f("unknown key type %s", sshkey_type(priv)); @@ -485,7 +526,7 @@ pkcs11_make_cert(const struct sshkey *priv, static int pkcs11_start_helper_methods(struct helper *helper) { - RSA_METHOD *rsa_meth; + RSA_METHOD *rsa_meth = NULL; EC_KEY_METHOD *ec_meth = NULL; #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) int (*ec_init)(EC_KEY *key); diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index 5c3eaaeb0..9e1a0ab72 100644 --- a/ssh-pkcs11-helper.c +++ b/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. * @@ -45,6 +45,9 @@ #ifdef ENABLE_PKCS11 #ifdef WITH_OPENSSL +#include +#include +#include /* borrows code from sftp-server and ssh-agent */ @@ -185,10 +188,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 || @@ -198,41 +204,47 @@ process_sign(void) if ((r = sshkey_from_blob(blob, blen, &key)) != 0) fatal_fr(r, "decode key"); - else { - if ((found = lookup_key(key)) != NULL) { + if ((found = lookup_key(key)) == NULL) + goto reply; + + /* XXX use pkey API properly for signing */ + switch (key->type) { #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; - } -#ifdef OPENSSL_HAS_ECC - } 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; -#endif /* OPENSSL_HAS_ECC */ - } else - error_f("don't know how to sign with key " - "type %d", (int)key->type); -#endif /* WITH_OPENSSL */ + 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; } - sshkey_free(key); + slen = (u_int)len; + break; +#ifdef OPENSSL_HAS_ECC + 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; + } + break; +#endif /* OPENSSL_HAS_ECC */ +#endif /* WITH_OPENSSL */ + 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) { @@ -243,6 +255,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/ssh-pkcs11.c b/ssh-pkcs11.c index 1e76e8b2b..fadf9c9c6 100644 --- a/ssh-pkcs11.c +++ b/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. @@ -502,8 +502,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); } @@ -615,8 +617,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); } @@ -803,11 +807,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++) @@ -899,10 +906,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++) @@ -1014,10 +1024,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 */ #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) } else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) { if (EVP_PKEY_get0_EC_KEY(evp) == NULL) { @@ -1044,11 +1057,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 */ #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ } else { error("unknown certificate key type"); diff --git a/ssh-rsa.c b/ssh-rsa.c index be8f51e75..3ad1fddc4 100644 --- a/ssh-rsa.c +++ b/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 * @@ -36,23 +36,18 @@ #include "openbsd-compat/openssl-compat.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; } @@ -60,29 +55,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) + if (a->pkey == NULL || b->pkey == 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) - 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 @@ -91,10 +73,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; @@ -108,10 +94,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 */ @@ -131,28 +120,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; } - k->rsa = private; - private = NULL; + 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; + } + /* success */ + k->pkey = res; ret = 0; out: - RSA_free(private); - BN_free(f4); + EVP_PKEY_CTX_free(ctx); return ret; } @@ -162,21 +159,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; @@ -188,25 +197,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; @@ -219,13 +237,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; } @@ -236,33 +266,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) - goto out; - if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0) - goto out; - if (RSA_blinding_on(key->rsa, NULL) != 1) { + if (!RSA_set0_crt_params(rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; + if (RSA_blinding_on(rsa, NULL) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + 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; } @@ -317,45 +360,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; } @@ -363,25 +384,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; } @@ -393,11 +406,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) @@ -409,41 +421,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) + if ((ret = sshkey_pkey_digest_sign(key->pkey, hash_alg, &sig, &len, + data, datalen)) < 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; - 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; @@ -464,7 +463,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; @@ -476,19 +474,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) @@ -524,7 +520,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; @@ -540,16 +536,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); @@ -558,125 +554,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/ssh-sk.c b/ssh-sk.c index d1c18803f..a2a7d7206 100644 --- a/ssh-sk.c +++ b/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 * @@ -32,6 +32,7 @@ #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) #include #include +#include #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ #include "log.h" @@ -207,7 +208,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; @@ -217,8 +220,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; @@ -229,30 +233,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/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c index af3f39795..b710a9e0b 100644 --- a/sshbuf-getput-crypto.c +++ b/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 * @@ -177,4 +177,13 @@ sshbuf_put_eckey(struct sshbuf *buf, const EC_KEY *v) EC_KEY_get0_group(v)); } #endif /* OPENSSL_HAS_ECC */ +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); +} #endif /* WITH_OPENSSL */ diff --git a/sshbuf.h b/sshbuf.h index e2155f9a4..49c32af8f 100644 --- a/sshbuf.h +++ b/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 * @@ -23,6 +23,7 @@ #include #ifdef WITH_OPENSSL # include +# include # ifdef OPENSSL_HAS_ECC # include # endif /* OPENSSL_HAS_ECC */ @@ -223,6 +224,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); # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ diff --git a/sshkey.c b/sshkey.c index d4356e72c..be94e8748 100644 --- a/sshkey.c +++ b/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. @@ -481,6 +481,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) @@ -1331,14 +1423,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; @@ -1346,53 +1436,26 @@ sshkey_check_rsa_length(const struct sshkey *k, int min_size) return 0; } -#ifdef WITH_OPENSSL -# ifdef OPENSSL_HAS_ECC +#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) 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, -# ifdef OPENSSL_HAS_NISTP521 - NID_secp521r1, -# endif /* OPENSSL_HAS_NISTP521 */ - -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; } -# endif /* OPENSSL_HAS_ECC */ -#endif /* WITH_OPENSSL */ + +int +sshkey_ecdsa_pkey_to_nid(EVP_PKEY *pkey) +{ + return sshkey_ecdsa_key_to_nid(EVP_PKEY_get0_EC_KEY(pkey)); +} +#endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ int sshkey_generate(int type, u_int bits, struct sshkey **keyp) @@ -3226,10 +3289,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; @@ -3240,6 +3299,10 @@ 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; @@ -3247,19 +3310,25 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, #ifdef OPENSSL_HAS_ECC 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; #endif 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: @@ -3428,6 +3497,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; @@ -3461,15 +3532,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); - prv->type = KEY_RSA; -#ifdef DEBUG_PK - RSA_print_fp(stderr, prv->rsa, 8); -#endif - if (RSA_blinding_on(prv->rsa, NULL) != 1) { + 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, rsa, 8); +#endif + 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 @@ -3492,21 +3569,25 @@ 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; } -# ifdef DEBUG_PK - if (prv != NULL && prv->ecdsa != NULL) - sshkey_dump_ec_key(prv->ecdsa); -# endif + EVP_PKEY_up_ref(pk); + prv->pkey = pk; +#ifdef DEBUG_PK + if (prv != NULL && prv->pkey != NULL) + sshkey_dump_ec_key(EVP_PKEY_get0_EC_KEY(prv->pkey)); +#endif #endif /* OPENSSL_HAS_ECC */ #ifdef OPENSSL_HAS_ED25519 } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_ED25519 && @@ -3541,9 +3622,9 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, /* Append the public key to our private key */ memcpy(prv->ed25519_sk + (ED25519_SK_SZ - ED25519_PK_SZ), prv->ed25519_pk, ED25519_PK_SZ); -# ifdef DEBUG_PK +#ifdef DEBUG_PK sshbuf_dump_data(prv->ed25519_sk, ED25519_SK_SZ, stderr); -# endif +#endif #endif /* OPENSSL_HAS_ED25519 */ } else { r = SSH_ERR_INVALID_FORMAT; @@ -3557,6 +3638,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/sshkey.h b/sshkey.h index 32933bbbd..cb142d7e2 100644 --- a/sshkey.h +++ b/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. @@ -31,6 +31,7 @@ #ifdef WITH_OPENSSL #include #include +#include # ifdef OPENSSL_HAS_ECC # include # include @@ -47,6 +48,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 */ @@ -125,13 +127,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; @@ -258,7 +259,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 *); @@ -287,6 +289,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 *); @@ -310,7 +318,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 *); @@ -321,6 +330,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); @@ -341,6 +354,7 @@ int check_rsa_length(const RSA *rsa); /* XXX remove */ # undef EC_KEY # undef EC_GROUP # undef EC_POINT +# undef EVP_PKEY #elif !defined(OPENSSL_HAS_ECC) # undef EC_KEY # undef EC_GROUP