diff --git a/configure.ac b/configure.ac index 0581a2c5a75..ac2e9603d80 100644 --- a/configure.ac +++ b/configure.ac @@ -2974,6 +2974,12 @@ if test "x$openssl" = "xyes" ; then EVP_CIPHER_CTX_set_iv \ ]) + # Misc versions of LibreSSL/BoringSSL API differences + AC_CHECK_FUNCS([ \ + EVP_PKEY_public_check \ + EVP_PKEY_private_check \ + ]) + if test "x$openssl_engine" = "xyes" ; then AC_MSG_CHECKING([for OpenSSL ENGINE support]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/digest-openssl.c b/digest-openssl.c index e073a807b14..94730e93360 100644 --- a/digest-openssl.c +++ b/digest-openssl.c @@ -64,6 +64,22 @@ const struct ssh_digest digests[] = { { -1, NULL, 0, NULL }, }; +const EVP_MD * +ssh_digest_to_md(int digest_type) +{ + switch (digest_type) { + 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; +} + static const struct ssh_digest * ssh_digest_by_alg(int alg) { diff --git a/digest.h b/digest.h index 274574d0e54..c7ceeb36f72 100644 --- a/digest.h +++ b/digest.h @@ -32,6 +32,12 @@ struct sshbuf; struct ssh_digest_ctx; +#ifdef WITH_OPENSSL +#include +/* Converts internal digest representation to the OpenSSL one */ +const EVP_MD *ssh_digest_to_md(int digest_type); +#endif + /* Looks up a digest algorithm by name */ int ssh_digest_alg_by_name(const char *name); diff --git a/packet.c b/packet.c index 52017defb64..e628d091a85 100644 --- a/packet.c +++ b/packet.c @@ -71,9 +71,6 @@ #ifdef WITH_OPENSSL # include # include -# ifdef OPENSSL_HAS_ECC -# include -# endif #endif #ifdef WITH_ZLIB @@ -2540,9 +2537,9 @@ sshpkt_getb_froms(struct ssh *ssh, struct sshbuf **valp) #ifdef WITH_OPENSSL #ifdef OPENSSL_HAS_ECC int -sshpkt_put_ec(struct ssh *ssh, const EC_POINT *v, const EC_GROUP *g) +sshpkt_put_ec(struct ssh *ssh, EVP_PKEY *pkey) { - return sshbuf_put_ec(ssh->state->outgoing_packet, v, g); + return sshbuf_put_ecpkey(ssh->state->outgoing_packet, pkey); } #endif /* OPENSSL_HAS_ECC */ @@ -2605,13 +2602,11 @@ sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp) } #ifdef WITH_OPENSSL -#ifdef OPENSSL_HAS_ECC int -sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g) +sshpkt_get_ec(struct ssh *ssh, u_char **pubkey, size_t *pubkey_len) { - return sshbuf_get_ec(ssh->state->incoming_packet, v, g); + return sshbuf_get_string(ssh->state->incoming_packet, pubkey, pubkey_len); } -#endif /* OPENSSL_HAS_ECC */ int sshpkt_get_bignum2(struct ssh *ssh, BIGNUM **valp) diff --git a/packet.h b/packet.h index 11925a27d43..6ca1943f015 100644 --- a/packet.h +++ b/packet.h @@ -20,18 +20,9 @@ #ifdef WITH_OPENSSL # include -# ifdef OPENSSL_HAS_ECC -# include -# else /* OPENSSL_HAS_ECC */ -# define EC_KEY void -# define EC_GROUP void -# define EC_POINT void -# endif /* OPENSSL_HAS_ECC */ +# include #else /* WITH_OPENSSL */ # define BIGNUM void -# define EC_KEY void -# define EC_GROUP void -# define EC_POINT void #endif /* WITH_OPENSSL */ #include @@ -192,7 +183,9 @@ int sshpkt_put_u64(struct ssh *ssh, u_int64_t val); 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); +#ifdef WITH_OPENSSL +int sshpkt_put_ec(struct ssh *ssh, EVP_PKEY *pkey); +#endif int sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v); int sshpkt_get(struct ssh *ssh, void *valp, size_t len); @@ -204,7 +197,7 @@ int sshpkt_get_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp) int sshpkt_peek_string_direct(struct ssh *ssh, const u_char **valp, size_t *lenp); int sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp); int sshpkt_getb_froms(struct ssh *ssh, struct sshbuf **valp); -int sshpkt_get_ec(struct ssh *ssh, EC_POINT *v, const EC_GROUP *g); +int sshpkt_get_ec(struct ssh *ssh, u_char **pub, size_t *publen); int sshpkt_get_bignum2(struct ssh *ssh, BIGNUM **valp); int sshpkt_get_end(struct ssh *ssh); void sshpkt_fmt_connection_id(struct ssh *ssh, char *s, size_t l); @@ -212,13 +205,6 @@ const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); #if !defined(WITH_OPENSSL) # undef BIGNUM -# undef EC_KEY -# undef EC_GROUP -# undef EC_POINT -#elif !defined(OPENSSL_HAS_ECC) -# undef EC_KEY -# undef EC_GROUP -# undef EC_POINT #endif #endif /* PACKET_H */ diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c index e3620e97fe9..7b4cb3cb42c 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c @@ -19,9 +19,15 @@ #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#include +#include +#include +#else #ifdef OPENSSL_HAS_NISTP256 # include #endif +#endif #include "../test_helper/test_helper.h" #include "ssherr.h" @@ -51,6 +57,7 @@ sshbuf_getput_crypto_tests(void) size_t s; BIGNUM *bn_x, *bn_y; int ec256_nid = NID_X9_62_prime256v1; + const char *ec256_sn = "prime256v1"; char *ec256_x = "0C828004839D0106AA59575216191357" "34B451459DADB586677EF9DF55784999"; char *ec256_y = "4D196B50F0B4E94B3C73E3A9D4CD9DF2" @@ -66,7 +73,17 @@ sshbuf_getput_crypto_tests(void) 0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47, 0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4 }; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY *eck = NULL; + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM_BLD *param_bld = NULL; + OSSL_PARAM *params = NULL; + EC_GROUP *g = NULL; + u_char *pubkey = NULL; + size_t pubkey_len; +#else EC_KEY *eck; +#endif EC_POINT *ecp; #endif int r; @@ -223,29 +240,74 @@ sshbuf_getput_crypto_tests(void) TEST_DONE(); #if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) - TEST_START("sshbuf_put_ec"); + TEST_START("sshbuf_put_ecpkey"); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + param_bld = OSSL_PARAM_BLD_new(); + ASSERT_PTR_NE(param_bld, NULL); + ASSERT_INT_EQ(OSSL_PARAM_BLD_push_utf8_string(param_bld, + OSSL_PKEY_PARAM_GROUP_NAME, ec256_sn, strlen(ec256_sn)), 1); +#else eck = EC_KEY_new_by_curve_name(ec256_nid); ASSERT_PTR_NE(eck, NULL); ecp = EC_POINT_new(EC_KEY_get0_group(eck)); ASSERT_PTR_NE(ecp, NULL); +#endif MKBN(ec256_x, bn_x); MKBN(ec256_y, bn_y); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + g = EC_GROUP_new_by_curve_name(ec256_nid); + ecp = EC_POINT_new(g); + ASSERT_PTR_NE(g, NULL); + ASSERT_INT_EQ(EC_POINT_set_affine_coordinates( + g, ecp, bn_x, bn_y, NULL), 1); + pubkey_len = EC_POINT_point2oct(g, ecp, + POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + ASSERT_INT_NE(pubkey_len, 0); + pubkey = malloc(pubkey_len); + ASSERT_PTR_NE(pubkey, NULL); + ASSERT_INT_NE(EC_POINT_point2oct(g, ecp, POINT_CONVERSION_UNCOMPRESSED, + pubkey, pubkey_len, NULL), 0); + EC_GROUP_free(g); +#else ASSERT_INT_EQ(EC_POINT_set_affine_coordinates_GFp( EC_KEY_get0_group(eck), ecp, bn_x, bn_y, NULL), 1); ASSERT_INT_EQ(EC_KEY_set_public_key(eck, ecp), 1); +#endif BN_free(bn_x); BN_free(bn_y); EC_POINT_free(ecp); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + ASSERT_INT_EQ(OSSL_PARAM_BLD_push_octet_string(param_bld, + OSSL_PKEY_PARAM_PUB_KEY, pubkey, pubkey_len), 1); + params = OSSL_PARAM_BLD_to_param(param_bld); + ASSERT_PTR_NE(params, NULL); + OSSL_PARAM_BLD_free(param_bld); + ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); + ASSERT_PTR_NE(ctx, NULL); + ASSERT_INT_EQ(EVP_PKEY_fromdata_init(ctx), 1); + ASSERT_INT_EQ(EVP_PKEY_fromdata(ctx, &eck, EVP_PKEY_PUBLIC_KEY, + params), 1); + free(pubkey); +#endif p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); - ASSERT_INT_EQ(sshbuf_put_eckey(p1, eck), 0); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + ASSERT_INT_EQ(sshbuf_put_ecpkey(p1, eck), 0); +#else + ASSERT_INT_EQ(sshbuf_put_ec(p1, EC_KEY_get0_public_key(eck), + EC_KEY_get0_group(eck)), 0); +#endif ASSERT_INT_EQ(sshbuf_get_string_direct(p1, &d, &s), 0); ASSERT_SIZE_T_EQ(s, sizeof(expec256)); ASSERT_MEM_EQ(d, expec256, sizeof(expec256)); sshbuf_free(p1); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY_free(eck); +#else EC_KEY_free(eck); +#endif TEST_DONE(); - +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) TEST_START("sshbuf_get_ec"); eck = EC_KEY_new_by_curve_name(ec256_nid); ASSERT_PTR_NE(eck, NULL); @@ -275,6 +337,7 @@ sshbuf_getput_crypto_tests(void) BN_free(bn2); TEST_DONE(); #endif +#endif } #endif /* WITH_OPENSSL */ diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c b/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c index 3b4895895ef..1d7495c14af 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_fuzz.c @@ -35,9 +35,6 @@ attempt_parse_blob(u_char *blob, size_t len) struct sshbuf *p1; #ifdef WITH_OPENSSL BIGNUM *bn; -#if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) - EC_KEY *eck; -#endif /* defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) */ #endif /* WITH_OPENSSL */ u_char *s; size_t l; @@ -61,12 +58,6 @@ attempt_parse_blob(u_char *blob, size_t len) bn = NULL; sshbuf_get_bignum2(p1, &bn); BN_clear_free(bn); -#if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) - eck = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - ASSERT_PTR_NE(eck, NULL); - sshbuf_get_eckey(p1, eck); - EC_KEY_free(eck); -#endif /* defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) */ #endif /* WITH_OPENSSL */ sshbuf_free(p1); } diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c index 51b0d92e1d0..9f95880235b 100644 --- a/regress/unittests/sshkey/common.c +++ b/regress/unittests/sshkey/common.c @@ -20,7 +20,10 @@ #ifdef WITH_OPENSSL #include +#include +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) #include +#endif #include #include #ifdef OPENSSL_HAS_NISTP256 @@ -83,48 +86,100 @@ load_bignum(const char *name) return ret; } -const BIGNUM * +BIGNUM * rsa_n(struct sshkey *k) { - const BIGNUM *n = NULL; + BIGNUM *n = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; + BIGNUM *res = NULL; +#endif ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->rsa, NULL); - RSA_get0_key(k->rsa, &n, NULL, NULL); + ASSERT_PTR_NE(k->pkey, NULL); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_N, &n); return n; +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_key(rsa, &n, NULL, NULL); + RSA_free(rsa); + res = BN_dup(n); + return res; +#endif } -const BIGNUM * +BIGNUM * rsa_e(struct sshkey *k) { - const BIGNUM *e = NULL; + BIGNUM *e = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; + BIGNUM *res = NULL; +#endif ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->rsa, NULL); - RSA_get0_key(k->rsa, NULL, &e, NULL); + ASSERT_PTR_NE(k->pkey, NULL); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_E, &e); return e; +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_key(rsa, NULL, &e, NULL); + RSA_free(rsa); + res = BN_dup(e); + return res; +#endif } -const BIGNUM * +BIGNUM * rsa_p(struct sshkey *k) { - const BIGNUM *p = NULL; + BIGNUM *p = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; + BIGNUM *res = NULL; +#endif ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->rsa, NULL); - RSA_get0_factors(k->rsa, &p, NULL); + ASSERT_PTR_NE(k->pkey, NULL); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &p); return p; +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_factors(rsa, &p, NULL); + RSA_free(rsa); + res = BN_dup(p); + return res; +#endif } -const BIGNUM * +BIGNUM * rsa_q(struct sshkey *k) { - const BIGNUM *q = NULL; + BIGNUM *q = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; + BIGNUM *res = NULL; +#endif ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->rsa, NULL); - RSA_get0_factors(k->rsa, NULL, &q); + ASSERT_PTR_NE(k->pkey, NULL); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &q); return q; +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_factors(rsa, NULL, &q); + RSA_free(rsa); + res = BN_dup(q); + return res; +#endif } const BIGNUM * diff --git a/regress/unittests/sshkey/common.h b/regress/unittests/sshkey/common.h index 7a514fdc8fe..73cd047f2cf 100644 --- a/regress/unittests/sshkey/common.h +++ b/regress/unittests/sshkey/common.h @@ -15,10 +15,10 @@ struct sshbuf *load_text_file(const char *name); BIGNUM *load_bignum(const char *name); /* Accessors for key components */ -const BIGNUM *rsa_n(struct sshkey *k); -const BIGNUM *rsa_e(struct sshkey *k); -const BIGNUM *rsa_p(struct sshkey *k); -const BIGNUM *rsa_q(struct sshkey *k); +BIGNUM *rsa_n(struct sshkey *k); +BIGNUM *rsa_e(struct sshkey *k); +BIGNUM *rsa_p(struct sshkey *k); +BIGNUM *rsa_q(struct sshkey *k); const BIGNUM *dsa_g(struct sshkey *k); const BIGNUM *dsa_pub_key(struct sshkey *k); const BIGNUM *dsa_priv_key(struct sshkey *k); diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c index 488944c3b76..46f9650daf1 100644 --- a/regress/unittests/sshkey/test_file.c +++ b/regress/unittests/sshkey/test_file.c @@ -47,6 +47,11 @@ sshkey_file_tests(void) struct sshbuf *buf, *pw; #ifdef WITH_OPENSSL BIGNUM *a, *b, *c; + u_char *pubkey = NULL; + size_t pubkey_len; +#ifdef OPENSSL_HAS_ECC + EC_KEY *ec = NULL; +#endif #endif char *cp; @@ -269,12 +274,36 @@ sshkey_file_tests(void) #ifndef OPENSSL_IS_BORINGSSL /* lacks EC_POINT_point2bn() */ a = load_bignum("ecdsa_1.param.priv"); b = load_bignum("ecdsa_1.param.pub"); - c = EC_POINT_point2bn(EC_KEY_get0_group(k1->ecdsa), - EC_KEY_get0_public_key(k1->ecdsa), POINT_CONVERSION_UNCOMPRESSED, + ec = EVP_PKEY_get1_EC_KEY(k1->pkey); + ASSERT_PTR_NE(ec, NULL); +/* OpenSSL 3.0.7 and below export EC pub key in compressed form */ +#if (OPENSSL_VERSION_NUMBER < 0x30000080L) + c = EC_POINT_point2bn(EC_KEY_get0_group(ec), + EC_KEY_get0_public_key(ec), POINT_CONVERSION_UNCOMPRESSED, NULL, NULL); +#else + ASSERT_INT_EQ(EVP_PKEY_get_octet_string_param(k1->pkey, + OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pubkey_len), 1); + pubkey = malloc(pubkey_len); + ASSERT_PTR_NE(pubkey, NULL); + ASSERT_INT_EQ(EVP_PKEY_get_octet_string_param(k1->pkey, + OSSL_PKEY_PARAM_PUB_KEY, pubkey, pubkey_len, NULL), 1); + c = BN_new(); +#endif ASSERT_PTR_NE(c, NULL); - ASSERT_BIGNUM_EQ(EC_KEY_get0_private_key(k1->ecdsa), a); +#if (OPENSSL_VERSION_NUMBER < 0x30000080L) + ASSERT_BIGNUM_EQ(EC_KEY_get0_private_key(ec), a); +#else + ASSERT_PTR_NE(BN_bin2bn(pubkey, pubkey_len, c), NULL); +#endif ASSERT_BIGNUM_EQ(b, c); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + BN_clear_free(c); + c = NULL; + ASSERT_INT_EQ(EVP_PKEY_get_bn_param(k1->pkey, OSSL_PKEY_PARAM_PRIV_KEY, + &c), 1); + ASSERT_BIGNUM_EQ(c, a); +#endif BN_free(a); BN_free(b); BN_free(c); diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c index cc359aea506..3d2595847d3 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -17,7 +17,7 @@ #ifdef WITH_OPENSSL #include -#include +#include #include #if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) # include @@ -186,8 +186,10 @@ sshkey_tests(void) #ifdef OPENSSL_HAS_ECC struct sshkey *ke; #endif /* OPENSSL_HAS_ECC */ + size_t pubkey_len; #endif /* WITH_OPENSSL */ struct sshbuf *b; + BIGNUM *n = NULL, *e = NULL, *p = NULL; TEST_START("new invalid"); k1 = sshkey_new(-42); @@ -204,7 +206,6 @@ sshkey_tests(void) TEST_START("new/free KEY_RSA"); k1 = sshkey_new(KEY_RSA); ASSERT_PTR_NE(k1, NULL); - ASSERT_PTR_NE(k1->rsa, NULL); sshkey_free(k1); TEST_DONE(); @@ -219,7 +220,6 @@ sshkey_tests(void) TEST_START("new/free KEY_ECDSA"); k1 = sshkey_new(KEY_ECDSA); ASSERT_PTR_NE(k1, NULL); - ASSERT_PTR_EQ(k1->ecdsa, NULL); /* Can't allocate without NID */ sshkey_free(k1); TEST_DONE(); #endif @@ -266,11 +266,18 @@ sshkey_tests(void) SSH_ERR_KEY_LENGTH); ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &kr), 0); ASSERT_PTR_NE(kr, NULL); - ASSERT_PTR_NE(kr->rsa, NULL); - ASSERT_PTR_NE(rsa_n(kr), NULL); - ASSERT_PTR_NE(rsa_e(kr), NULL); - ASSERT_PTR_NE(rsa_p(kr), NULL); - ASSERT_INT_EQ(BN_num_bits(rsa_n(kr)), 1024); + ASSERT_PTR_NE(kr->pkey, NULL); + + n = rsa_n(kr); + ASSERT_PTR_NE(n, NULL); + ASSERT_INT_EQ(BN_num_bits(n), 1024); + BN_clear_free(n); + e = rsa_e(kr); + ASSERT_PTR_NE(e, NULL); + BN_clear_free(e); + p = rsa_p(kr); + ASSERT_PTR_NE(p, NULL); + BN_clear_free(p); TEST_DONE(); TEST_START("generate KEY_DSA"); @@ -285,9 +292,19 @@ sshkey_tests(void) TEST_START("generate KEY_ECDSA"); ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &ke), 0); ASSERT_PTR_NE(ke, NULL); - ASSERT_PTR_NE(ke->ecdsa, NULL); - ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL); - ASSERT_PTR_NE(EC_KEY_get0_private_key(ke->ecdsa), NULL); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + ASSERT_PTR_NE(ke->pkey, NULL); + ASSERT_INT_EQ(EVP_PKEY_get_octet_string_param(ke->pkey, + OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pubkey_len), 1); + p = NULL; + ASSERT_INT_EQ(EVP_PKEY_get_bn_param(ke->pkey, + OSSL_PKEY_PARAM_PRIV_KEY, &p), 1); + BN_clear_free(p); +#else + ASSERT_PTR_NE(EVP_PKEY_get0_EC_KEY(ke->pkey), NULL); + ASSERT_PTR_NE(EC_KEY_get0_public_key(EVP_PKEY_get0_EC_KEY(ke->pkey)), NULL); + ASSERT_PTR_NE(EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(ke->pkey)), NULL); +#endif TEST_DONE(); #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ @@ -306,10 +323,16 @@ sshkey_tests(void) ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(kr, k1); ASSERT_INT_EQ(k1->type, KEY_RSA); - ASSERT_PTR_NE(k1->rsa, NULL); - ASSERT_PTR_NE(rsa_n(k1), NULL); - ASSERT_PTR_NE(rsa_e(k1), NULL); - ASSERT_PTR_EQ(rsa_p(k1), NULL); + ASSERT_PTR_NE(k1->pkey, NULL); + n = rsa_n(k1); + ASSERT_PTR_NE(n, NULL); + BN_clear_free(n); + e = rsa_e(k1); + ASSERT_PTR_NE(e, NULL); + BN_clear_free(e); + p = rsa_p(k1); + ASSERT_PTR_EQ(p, NULL); + BN_clear_free(p); TEST_DONE(); TEST_START("equal KEY_RSA/demoted KEY_RSA"); @@ -338,10 +361,18 @@ sshkey_tests(void) ASSERT_PTR_NE(k1, NULL); ASSERT_PTR_NE(ke, k1); ASSERT_INT_EQ(k1->type, KEY_ECDSA); - ASSERT_PTR_NE(k1->ecdsa, NULL); + ASSERT_PTR_NE(k1->pkey, NULL); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + ASSERT_INT_EQ(EVP_PKEY_get_octet_string_param(ke->pkey, + OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pubkey_len), 1); + ASSERT_INT_EQ(EVP_PKEY_get_bn_param(k1->pkey, + OSSL_PKEY_PARAM_PRIV_KEY, &p), 1); + BN_clear_free(p); +#else + ASSERT_PTR_NE(EC_KEY_get0_public_key(EVP_PKEY_get0_EC_KEY(ke->pkey)), NULL); + ASSERT_PTR_EQ(EC_KEY_get0_private_key(EVP_PKEY_get0_EC_KEY(k1->pkey)), NULL); +#endif ASSERT_INT_EQ(k1->ecdsa_nid, ke->ecdsa_nid); - ASSERT_PTR_NE(EC_KEY_get0_public_key(ke->ecdsa), NULL); - ASSERT_PTR_EQ(EC_KEY_get0_private_key(k1->ecdsa), NULL); TEST_DONE(); TEST_START("equal KEY_ECDSA/demoted KEY_ECDSA"); diff --git a/sk-usbhid.c b/sk-usbhid.c index 812b28d83e9..f966260d319 100644 --- a/sk-usbhid.c +++ b/sk-usbhid.c @@ -46,9 +46,11 @@ #include #include #include -#include #include #include +#ifdef OPENSSL_HAS_ECC +#include +#endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ #include diff --git a/ssh-ecdsa-sk.c b/ssh-ecdsa-sk.c index 5dcd3c13d34..ce1195ee20a 100644 --- a/ssh-ecdsa-sk.c +++ b/ssh-ecdsa-sk.c @@ -33,7 +33,6 @@ #ifdef WITH_OPENSSL #include -#include #include #include #endif @@ -239,9 +238,10 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, ECDSA_SIG *esig = 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, *psig = NULL; + int is_webauthn = 0, ret = SSH_ERR_INTERNAL_ERROR, len; 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 +252,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,31 +363,34 @@ 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 /* Verify it */ - switch (ECDSA_do_verify(sighash, sizeof(sighash), esig, key->ecdsa)) { - case 1: - ret = 0; - break; - case 0: - ret = SSH_ERR_SIGNATURE_INVALID; + if ((len = i2d_ECDSA_SIG(esig, NULL)) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((sigb = malloc(len)) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; goto out; - default: + } + psig = sigb; + if ((len = i2d_ECDSA_SIG(esig, &psig)) == 0) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + ret = sshkey_verify_signature(key->pkey, SSH_DIGEST_SHA256, + sshbuf_ptr(original_signed), sshbuf_len(original_signed), + sigb, len); + + if (ret != 0) + goto out; + /* success */ if (detailsp != NULL) { *detailsp = details; @@ -397,7 +400,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 +412,7 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, BN_clear_free(sig_r); BN_clear_free(sig_s); free(ktype); + free(sigb); return ret; } diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 341c32409bc..9e55cb8950c 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -31,9 +31,12 @@ #include #include -#include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#include +#include +#endif #include @@ -65,30 +68,22 @@ 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) - 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; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if (EVP_PKEY_eq(a->pkey, b->pkey) == 1) + return 1; +#else + if (EVP_PKEY_cmp(a->pkey, b->pkey) == 1) + return 1; +#endif - return 1; + return 0; } static int @@ -97,11 +92,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_ecpkey(b, key->pkey)) != 0) return r; return 0; @@ -112,20 +107,54 @@ ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b, enum sshkey_serialize_rep opts) { int r; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + BIGNUM *priv = NULL; + if (!sshkey_is_cert(key)) { + if ((r = ssh_ecdsa_serialize_public(key, b, opts)) != 0) + return r; + } + if (EVP_PKEY_get_bn_param(key->pkey, OSSL_PKEY_PARAM_PRIV_KEY, &priv) != 1 || + (r = sshbuf_put_bignum2(b, priv) != 0)) { + BN_clear_free(priv); + return r; + } + + BN_clear_free(priv); +#else if (!sshkey_is_cert(key)) { if ((r = ssh_ecdsa_serialize_public(key, b, opts)) != 0) 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; +#endif return 0; } static int ssh_ecdsa_generate(struct sshkey *k, int bits) { + EVP_PKEY *res = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY_CTX *ctx = NULL; + + if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) + return SSH_ERR_KEY_LENGTH; + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) + return SSH_ERR_ALLOC_FAIL; + + if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_group_name(ctx, OBJ_nid2sn(k->ecdsa_nid)) <= 0 + || EVP_PKEY_keygen(ctx, &res) <= 0) { + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(res); + return SSH_ERR_LIBCRYPTO_ERROR; + } + + k->pkey = res; +#else EC_KEY *private; if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) @@ -137,19 +166,51 @@ ssh_ecdsa_generate(struct sshkey *k, int bits) return SSH_ERR_LIBCRYPTO_ERROR; } EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); - k->ecdsa = private; - return 0; + + if ((res = EVP_PKEY_new()) == NULL) { + EC_KEY_free(private); + return SSH_ERR_ALLOC_FAIL; + } + if (EVP_PKEY_set1_EC_KEY(res, private) != 1) { + EC_KEY_free(private); + EVP_PKEY_free(res); + return SSH_ERR_LIBCRYPTO_ERROR; + } + k->pkey = res; +#endif + return 0; } static int ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to) { + const EC_KEY *ec_from; + EC_KEY *ec_to = NULL; + + 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 */ + if (EC_KEY_set_public_key(ec_to, + EC_KEY_get0_public_key(ec_from)) != 1) { + EC_KEY_free(ec_to); + return SSH_ERR_LIBCRYPTO_ERROR; + } + EVP_PKEY_free(to->pkey); + to->pkey = NULL; + if ((to->pkey = EVP_PKEY_new()) == NULL) { + EC_KEY_free(ec_to); + return SSH_ERR_ALLOC_FAIL; + } + if (EVP_PKEY_set1_EC_KEY(to->pkey, ec_to) != 1) { + EC_KEY_free(ec_to); + return SSH_ERR_LIBCRYPTO_ERROR; + } + + EC_KEY_free(ec_to); return 0; } @@ -159,6 +220,11 @@ ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b, { int r; char *curve = NULL; + unsigned char *pub = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + size_t publen = 0; +#endif + EVP_PKEY *pkey = NULL; if ((key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype)) == -1) return SSH_ERR_INVALID_ARGUMENT; @@ -168,30 +234,61 @@ 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) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if ((r = sshbuf_get_eckey(b, key->ecdsa)) != 0) +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if ((r = sshbuf_get_string(b, &pub, &publen)) != 0) goto out; - if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), - EC_KEY_get0_public_key(key->ecdsa)) != 0) { - r = SSH_ERR_KEY_INVALID_EC_VALUE; + if ((r = ssh_create_evp_ec(pub, publen, NULL, key->ecdsa_nid, &pkey) != 0)) goto out; +#else + { + EC_KEY *tmp = NULL; + + if ((tmp = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((r = sshbuf_get_eckey(b, tmp)) != 0) + goto out; +#if 0 /* FIXME beldmit */ + if (sshkey_ec_validate_public(EC_KEY_get0_group(tmp), + EC_KEY_get0_public_key(tmp)) != 0) { + r = SSH_ERR_KEY_INVALID_EC_VALUE; + goto out; + } +#endif + + if ((pkey = EVP_PKEY_new()) == NULL) { + EC_KEY_free(tmp); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (EVP_PKEY_set1_EC_KEY(pkey, tmp) != 1) { + EC_KEY_free(tmp); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + EC_KEY_free(tmp); } +#endif + 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)); + { + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(key->pkey); + shkey_dump_ec_point(EC_KEY_get0_group(ec), + EC_KEY_get0_public_key(ec)); + } #endif out: + EVP_PKEY_free(pkey); free(curve); + free(pub); if (r != 0) { - EC_KEY_free(key->ecdsa); - key->ecdsa = NULL; + EVP_PKEY_free(key->pkey); + key->pkey = NULL; } return r; } @@ -202,6 +299,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 +307,28 @@ 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 0 + /* FIXME open question */ + if ((r = sshkey_ec_validate_private(ec)) != 0) + goto out; +#endif + 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,10 +339,11 @@ 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; + int len; struct sshbuf *b = NULL, *bb = NULL; int ret = SSH_ERR_INTERNAL_ERROR; @@ -241,22 +352,24 @@ ssh_ecdsa_sign(struct sshkey *key, 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) + + ret = sshkey_calculate_signature(key->pkey, hash_alg, &sigb, &len, data, + dlen); + if (ret < 0) { goto out; + } - if ((esig = ECDSA_do_sign(digest, hlen, key->ecdsa)) == NULL) { + psig = sigb; + if (d2i_ECDSA_SIG(&esig, &psig, len) == 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 +393,7 @@ ssh_ecdsa_sign(struct sshkey *key, *lenp = len; ret = 0; out: - explicit_bzero(digest, sizeof(digest)); + free(sigb); sshbuf_free(b); sshbuf_free(bb); ECDSA_SIG_free(esig); @@ -295,20 +408,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; int ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL, *sigbuf = NULL; char *ktype = NULL; + unsigned char *sigb = NULL, *psig = NULL; - 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 */ @@ -344,28 +455,29 @@ ssh_ecdsa_verify(const struct sshkey *key, } sig_r = sig_s = NULL; /* transferred */ - if (sshbuf_len(sigbuf) != 0) { - ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; + /* Figure out the length */ + if ((len = i2d_ECDSA_SIG(esig, NULL)) == 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 = malloc(len)) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; goto out; - default: + } + psig = sigb; + if ((len = i2d_ECDSA_SIG(esig, &psig)) == 0) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + if (sshbuf_len(sigbuf) != 0) { + ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; + goto out; + } + + ret = sshkey_verify_signature(key->pkey, hash_alg, data, dlen, sigb, len); out: - explicit_bzero(digest, sizeof(digest)); + free(sigb); sshbuf_free(sigbuf); sshbuf_free(b); ECDSA_SIG_free(esig); @@ -375,6 +487,56 @@ ssh_ecdsa_verify(const struct sshkey *key, return ret; } +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +int +ssh_create_evp_ec(u_char *pubkey, size_t pubkey_len, BIGNUM *privkey, + int ecdsa_nid, EVP_PKEY **pkey) +{ + OSSL_PARAM_BLD *param_bld = NULL; + EVP_PKEY_CTX *ctx = NULL; + const char *group_name; + int ret = 0; + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + + if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL || + OSSL_PARAM_BLD_push_utf8_string(param_bld, + OSSL_PKEY_PARAM_GROUP_NAME, + group_name, + strlen(group_name)) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (pubkey != NULL && + OSSL_PARAM_BLD_push_octet_string(param_bld, + OSSL_PKEY_PARAM_PUB_KEY, + pubkey, + pubkey_len) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (privkey != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_PRIV_KEY, + privkey) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + +out: + OSSL_PARAM_BLD_free(param_bld); + EVP_PKEY_CTX_free(ctx); + return ret; +} +#endif + /* NB. not static; used by ECDSA-SK */ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { /* .size = */ ssh_ecdsa_size, diff --git a/ssh-keygen.c b/ssh-keygen.c index 5b945a84920..99c414cbe4a 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -22,6 +22,10 @@ #include #include #include "openbsd-compat/openssl-compat.h" +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#include +#include +#endif #endif #ifdef HAVE_STDINT_H @@ -371,22 +375,13 @@ do_convert_to_ssh2(struct passwd *pw, struct sshkey *k) static void do_convert_to_pkcs8(struct sshkey *k) { - switch (sshkey_type_plain(k->type)) { - case KEY_RSA: - if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) - fatal("PEM_write_RSA_PUBKEY failed"); - break; - case KEY_DSA: + if (k->pkey != NULL) { + if (!PEM_write_PUBKEY(stdout, k->pkey)) + fatal("PEM_write_PUBKEY failed"); + } else if (sshkey_type_plain(k->type) == KEY_DSA) { if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) fatal("PEM_write_DSA_PUBKEY failed"); - break; -#ifdef OPENSSL_HAS_ECC - case KEY_ECDSA: - if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) - fatal("PEM_write_EC_PUBKEY failed"); - break; -#endif - default: + } else { fatal_f("unsupported key type %s", sshkey_type(k)); } exit(0); @@ -396,20 +391,43 @@ static void do_convert_to_pem(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) case KEY_RSA: - if (!PEM_write_RSAPublicKey(stdout, k->rsa)) - fatal("PEM_write_RSAPublicKey failed"); + case KEY_ECDSA: + OSSL_ENCODER_CTX *ctx; + ctx = OSSL_ENCODER_CTX_new_for_pkey(k->pkey, + EVP_PKEY_PUBLIC_KEY, + "PEM", NULL, NULL); + if (!ctx) + fatal("OSSL_ENCODER_CTX_new_for_pkey failed"); + if (OSSL_ENCODER_to_fp(ctx, stdout) != 1) { + OSSL_ENCODER_CTX_free(ctx); + fatal("OSSL_ENCODER_to_fp failed"); + } + OSSL_ENCODER_CTX_free(ctx); break; - case KEY_DSA: - if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) - fatal("PEM_write_DSA_PUBKEY failed"); +#else + case KEY_RSA: + { + RSA *rsa = EVP_PKEY_get0_RSA(k->pkey); + if (!PEM_write_RSAPublicKey(stdout, rsa)) + fatal("PEM_write_RSAPublicKey failed"); + } break; #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: - if (!PEM_write_EC_PUBKEY(stdout, k->ecdsa)) - fatal("PEM_write_EC_PUBKEY failed"); + { + EC_KEY *ec = EVP_PKEY_get0_EC_KEY(k->pkey); + if (!PEM_write_EC_PUBKEY(stdout, ec)) + fatal("PEM_write_EC_PUBKEY failed"); + } break; #endif +#endif + case KEY_DSA: + if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) + fatal("PEM_write_DSA_PUBKEY failed"); + break; default: fatal_f("unsupported key type %s", sshkey_type(k)); } @@ -482,6 +500,8 @@ do_convert_private_ssh2(struct sshbuf *b) BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL; 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"); @@ -572,14 +592,40 @@ 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 (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if (ssh_create_evp_rsa(rsa_n, rsa_e, rsa_d, rsa_p, rsa_q, + rsa_dmp1, rsa_dmq1, rsa_iqmp, + &key->pkey) != 0) + fatal_f("ssh_create_evp_rsa failed"); +#else + 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"); + 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"); +#endif + 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_dmp1); + BN_clear_free(rsa_dmq1); BN_clear_free(rsa_iqmp); alg = "rsa-sha2-256"; break; @@ -687,20 +733,37 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) { EVP_PKEY *pubkey; FILE *fp; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + OSSL_DECODER_CTX *ctx; +#endif if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + ctx = OSSL_DECODER_CTX_new_for_pkey(&pubkey, "PEM", "PublicKeyInfo", + "RSA", EVP_PKEY_PUBLIC_KEY, NULL, + NULL); + if (!ctx) + fatal_f("OSSL_DECODER_CTX failed"); + if (OSSL_DECODER_from_fp(ctx, fp) != 1) { + fatal_f("%s is not a recognised public key format", + identity_file); + } + OSSL_DECODER_CTX_free(ctx); +#else if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { fatal_f("%s is not a recognised public key format", identity_file); } +#endif fclose(fp); switch (EVP_PKEY_base_id(pubkey)) { case EVP_PKEY_RSA: 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; case EVP_PKEY_DSA: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) @@ -713,8 +776,9 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new 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; + (*k)->ecdsa_nid = sshkey_ecdsa_key_to_nid((*k)->pkey); break; #endif default: @@ -728,6 +792,26 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) static void do_convert_from_pem(struct sshkey **k, int *private) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + FILE *fp; + EVP_PKEY *pkey = NULL; + OSSL_DECODER_CTX *ctx; + + if ((fp = fopen(identity_file, "r")) == NULL) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + ctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, + "PEM", NULL, "RSA", EVP_PKEY_PUBLIC_KEY, NULL, NULL); + if (!ctx) + fatal_f("OSSL_DECODER_CTX failed"); + if (OSSL_DECODER_from_fp(ctx, fp) == 1) { + if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) + fatal("sshkey_new failed"); + (*k)->type = KEY_RSA; + (*k)->pkey = pkey; + fclose(fp); + return; + } +#else FILE *fp; RSA *rsa; @@ -736,11 +820,17 @@ 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; } +#endif fatal_f("unrecognised raw private key format"); } @@ -781,16 +871,35 @@ do_convert_from(struct passwd *pw) ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL); break; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + case KEY_ECDSA: + case KEY_RSA: + { + OSSL_ENCODER_CTX *ctx; + ctx = OSSL_ENCODER_CTX_new_for_pkey(k->pkey, + EVP_PKEY_KEYPAIR, + "PEM", + "type-specific", + NULL); + if (!ctx) + fatal("OSSL_ENCODER_CTX_new_for_pkey failed"); + ok = OSSL_ENCODER_to_fp(ctx, stdout); + OSSL_ENCODER_CTX_free(ctx); + } + break; +#else #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: - ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, 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, + ok = PEM_write_RSAPrivateKey(stdout, EVP_PKEY_get0_RSA(k->pkey), NULL, NULL, 0, NULL, NULL); break; + +#endif default: fatal_f("unsupported key type %s", sshkey_type(k)); } diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 061b0681e43..157d0dc74f7 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -269,9 +269,21 @@ rsa_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) error_f("sshkey_new failed"); goto fail; } + key->pkey = EVP_PKEY_new(); + if (key->pkey == NULL) { + error("EVP_PKEY_new failed"); + sshkey_free(key); + key = NULL; + goto fail; + } + if (EVP_PKEY_set1_RSA(key->pkey, rsa) <= 0) { + error("EVP_PKEY_set1_RSA failed"); + sshkey_free(key); + key = NULL; + 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 +351,37 @@ 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) { error_f("sshkey_new failed"); goto fail; } - key->ecdsa = ec; + key->pkey = EVP_PKEY_new(); + if (key->pkey == NULL) { + error("EVP_PKEY_new failed"); + sshkey_free(key); + key = NULL; + goto fail; + } + + if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) <= 0) { + error("EVP_PKEY_set1_EC_KEY failed"); + sshkey_free(key); + key = NULL; + goto fail; + } + + nid = sshkey_ecdsa_key_to_nid(key->pkey); + if (nid < 0) { + error("couldn't get curve nid"); + sshkey_free(key); + key = NULL; + 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"); @@ -410,14 +438,20 @@ wrap_key(struct helper *helper, struct sshkey *k) { 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); + RSA *rsa = EVP_PKEY_get1_RSA(k->pkey); + RSA_set_method(rsa, helper->rsa_meth); if (helper->nrsa++ >= INT_MAX) fatal_f("RSA refcount error"); + EVP_PKEY_set1_RSA(k->pkey, rsa); + 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); + EC_KEY *ecdsa = EVP_PKEY_get1_EC_KEY(k->pkey); + EC_KEY_set_method(ecdsa, helper->ec_meth); if (helper->nec++ >= INT_MAX) fatal_f("EC refcount error"); + EVP_PKEY_set1_EC_KEY(k->pkey, ecdsa); + EC_KEY_free(ecdsa); #endif } else fatal_f("unknown key type"); diff --git a/ssh-pkcs11-helper.c b/ssh-pkcs11-helper.c index 5c3eaaeb019..3fde5509de8 100644 --- a/ssh-pkcs11-helper.c +++ b/ssh-pkcs11-helper.c @@ -45,6 +45,8 @@ #ifdef ENABLE_PKCS11 #ifdef WITH_OPENSSL +#include +#include /* borrows code from sftp-server and ssh-agent */ @@ -204,27 +206,33 @@ process_sign(void) int ret; if (key->type == KEY_RSA) { - slen = RSA_size(key->rsa); + /* FIXME OpenSSL 3.0 */ + RSA *rsa = EVP_PKEY_get1_RSA(found->pkey); + slen = RSA_size(rsa); signature = xmalloc(slen); ret = RSA_private_encrypt(dlen, data, signature, - found->rsa, RSA_PKCS1_PADDING); + rsa, RSA_PKCS1_PADDING); if (ret != -1) { slen = ret; ok = 0; } + RSA_free(rsa); #ifdef OPENSSL_HAS_ECC } else if (key->type == KEY_ECDSA) { - u_int xslen = ECDSA_size(key->ecdsa); + /* FIXME OpenSSL 3.0 */ + EC_KEY *ecdsa = EVP_PKEY_get1_EC_KEY(found->pkey); + u_int xslen = ECDSA_size(ecdsa); signature = xmalloc(xslen); /* "The parameter type is ignored." */ ret = ECDSA_sign(-1, data, dlen, signature, - &xslen, found->ecdsa); + &xslen, ecdsa); if (ret != 0) ok = 0; else error_f("ECDSA_sign returned %d", ret); slen = xslen; + EC_KEY_free(ecdsa); #endif /* OPENSSL_HAS_ECC */ } else error_f("don't know how to sign with key " diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 35e98be7230..dea5e5b5e28 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -788,12 +788,6 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto fail; } - nid = sshkey_ecdsa_key_to_nid(ec); - if (nid < 0) { - error("couldn't get curve nid"); - goto fail; - } - if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec)) goto fail; @@ -802,12 +796,33 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, error("sshkey_new failed"); goto fail; } + key->pkey = EVP_PKEY_new(); + if (key->pkey == NULL) { + error("EVP_PKEY_new failed"); + sshkey_free(key); + key = NULL; + goto fail; + } + + if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) <= 0) { + error("EVP_PKEY_set1_EC_KEY failed"); + sshkey_free(key); + key = NULL; + goto fail; + } + + nid = sshkey_ecdsa_key_to_nid(key->pkey); + if (nid < 0) { + error("couldn't get curve nid"); + sshkey_free(key); + key = NULL; + goto fail; + } + - key->ecdsa = ec; 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 +914,22 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto fail; } - key->rsa = rsa; + key->pkey = EVP_PKEY_new(); + if (key->pkey == NULL) { + error("EVP_PKEY_new failed"); + sshkey_free(key); + key = NULL; + goto fail; + } + if (EVP_PKEY_set1_RSA(key->pkey, rsa) <= 0) { + error("EVP_PKEY_set1_RSA failed"); + sshkey_free(key); + key = NULL; + goto fail; + } + key->type = KEY_RSA; key->flags |= SSHKEY_FLAG_EXT; - rsa = NULL; /* now owned by key */ fail: for (i = 0; i < 3; i++) @@ -1014,10 +1041,22 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; } - key->rsa = rsa; + key->pkey = EVP_PKEY_new(); + if (key->pkey == NULL) { + error("EVP_PKEY_new failed"); + sshkey_free(key); + key = NULL; + goto out; + } + if (EVP_PKEY_set1_RSA(key->pkey, rsa) <= 0) { + error("EVP_PKEY_set1_RSA failed"); + sshkey_free(key); + key = NULL; + goto out; + } + 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) { @@ -1029,7 +1068,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; } - nid = sshkey_ecdsa_key_to_nid(ec); + nid = sshkey_ecdsa_key_to_nid(evp); if (nid < 0) { error("couldn't get curve nid"); goto out; @@ -1044,11 +1083,25 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, goto out; } - key->ecdsa = ec; + key->pkey = EVP_PKEY_new(); + if (key->pkey == NULL) { + error("EVP_PKEY_new failed"); + sshkey_free(key); + key = NULL; + goto out; + } + + if (EVP_PKEY_set1_EC_KEY(key->pkey, ec) <= 0) { + error("EVP_PKEY_set1_EC_KEY failed"); + sshkey_free(key); + key = NULL; + goto out; + } + 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 be8f51e7576..a7aeb658eec 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -23,6 +23,10 @@ #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#include +#include +#endif #include #include @@ -36,23 +40,23 @@ #include "openbsd-compat/openssl-compat.h" -static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); +static int openssh_RSA_verify(int, const u_char *, size_t, u_char *, size_t, EVP_PKEY *); 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 (sshkey_type_plain(k->type) != KEY_RSA) + return 0; + 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 +64,21 @@ 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) - 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; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if (EVP_PKEY_eq(a->pkey, b->pkey) == 1) + return 1; +#else + if (EVP_PKEY_cmp(a->pkey, b->pkey) == 1) + return 1; +#endif + return 0; } static int @@ -91,10 +87,16 @@ 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); + + rsa = EVP_PKEY_get0_RSA(key->pkey); + if (rsa == 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 +110,15 @@ 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); + rsa = EVP_PKEY_get0_RSA(key->pkey); + if (rsa == 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,8 +138,56 @@ ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b, static int ssh_rsa_generate(struct sshkey *k, int bits) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *res = NULL; + BIGNUM *f4 = 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 ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL + || (f4 = BN_new()) == NULL || !BN_set_word(f4, RSA_F4)) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + + 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_CTX_set1_rsa_keygen_pubexp(ctx, f4) <= 0) + goto out; + + if (EVP_PKEY_keygen(ctx, &res) <= 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ + k->pkey = res; + if (k->pkey) { + ret = 0; + } else { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + out: + EVP_PKEY_CTX_free(ctx); + BN_free(f4); + return ret; +#else RSA *private = NULL; BIGNUM *f4 = NULL; + EVP_PKEY *res = NULL; int ret = SSH_ERR_INTERNAL_ERROR; if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE || @@ -147,13 +202,23 @@ ssh_rsa_generate(struct sshkey *k, int bits) ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - k->rsa = private; - private = NULL; + + if ((res = EVP_PKEY_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (EVP_PKEY_set1_RSA(res, private) != 1) { + EVP_PKEY_free(res); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + k->pkey = res; ret = 0; out: RSA_free(private); BN_free(f4); return ret; +#endif } static int @@ -162,21 +227,37 @@ 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); + rsa_from = EVP_PKEY_get0_RSA(from->pkey); + if (rsa_from == NULL) + return SSH_ERR_LIBCRYPTO_ERROR; + + rsa_to = RSA_new(); + if (rsa_to == 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 +269,35 @@ 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; + + rsa = RSA_new(); + if (rsa == 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 +310,22 @@ 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; + + if (sshkey_is_cert(key)) + rsa = EVP_PKEY_get1_RSA(key->pkey); + else + rsa = RSA_new(); + if (rsa == NULL) + return SSH_ERR_LIBCRYPTO_ERROR; /* Note: can't reuse ssh_rsa_deserialize_public: e, n vs. n, e */ if (!sshkey_is_cert(key)) { 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 +336,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; } @@ -317,45 +430,22 @@ 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); - 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 +453,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)) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) { + (BN_mod(*rsa_dmp1, d_consttime, aux, ctx) == 0)) { 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 +475,9 @@ 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; + int len, slen = 0; + int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; if (lenp != NULL) @@ -409,33 +489,20 @@ 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) + slen = EVP_PKEY_size(key->pkey); + if (EVP_PKEY_bits(key->pkey) < SSH_RSA_MINIMUM_MODULUS_SIZE) return SSH_ERR_KEY_LENGTH; - slen = RSA_size(key->rsa); - if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) - return SSH_ERR_INVALID_ARGUMENT; - /* 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; + ret = sshkey_calculate_signature(key->pkey, hash_alg, &sig, &len, data, + datalen); + if (ret < 0) { 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; memmove(sig + diff, sig, len); @@ -444,6 +511,7 @@ ssh_rsa_sign(struct sshkey *key, ret = SSH_ERR_INTERNAL_ERROR; goto out; } + /* encode signature */ if ((b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; @@ -464,7 +532,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 +543,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; 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 +589,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 +605,10 @@ 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; - goto out; - } - if ((ret = ssh_digest_memory(hash_alg, data, dlen, - digest, sizeof(digest))) != 0) - goto out; - ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len, - key->rsa); + ret = openssh_RSA_verify(hash_alg, data, dlen, sigblob, len, + key->pkey); + out: freezero(sigblob, len); free(sigtype); @@ -558,124 +617,96 @@ 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) +openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, + u_char *sigbuf, size_t siglen, EVP_PKEY *pkey) { - 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; -} + size_t rsasize = 0; + int ret; -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); + rsasize = EVP_PKEY_size(pkey); 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 = sshkey_verify_signature(pkey, hash_alg, data, datalen, + sigbuf, siglen); + +done: + return ret; +} + +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +int +ssh_create_evp_rsa(const BIGNUM *n, const BIGNUM *e, const BIGNUM *d, + const BIGNUM *p, const BIGNUM *q, const BIGNUM *dmp1, + const BIGNUM *dmq1, const BIGNUM *iqmp, EVP_PKEY **pkey) +{ + OSSL_PARAM_BLD *param_bld = NULL; + EVP_PKEY_CTX *ctx = NULL; + int ret = 0; + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + + if (n != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_N, n) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (e != NULL) { + if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; - goto done; - } - if (len < 0 || (size_t)len != hlen + oidlen) { - ret = SSH_ERR_INVALID_FORMAT; - goto done; + goto out; + } + } else { /* e can not be empty, assume 65537 */ + if (OSSL_PARAM_BLD_push_uint(param_bld, OSSL_PKEY_PARAM_RSA_E, 65537) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } } - 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; + if (d != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_D, d) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + /* these parameters have to be set together, otherwise openssl will fail */ + if (p != NULL && + q != NULL && + dmp1 != NULL && + dmq1 != NULL && + iqmp != NULL) { + if (OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_RSA_FACTOR1, p) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_RSA_FACTOR2, q) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp) != 1) { + debug2_f("failed to add crt params"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } } - ret = 0; -done: - freezero(decrypted, rsasize); - return ret; + + if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + +out: + OSSL_PARAM_BLD_free(param_bld); + EVP_PKEY_CTX_free(ctx); + return ret; } +#endif static const struct sshkey_impl_funcs sshkey_rsa_funcs = { /* .size = */ ssh_rsa_size, diff --git a/ssh-sk.c b/ssh-sk.c index d1c18803ff8..944b02d07e6 100644 --- a/ssh-sk.c +++ b/ssh-sk.c @@ -31,7 +31,6 @@ #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) #include -#include #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ #include "log.h" @@ -207,6 +206,8 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp) { struct sshkey *key = NULL; struct sshbuf *b = NULL; + EVP_PKEY_CTX *ctx = NULL; + EC_KEY *ecdsa = NULL; EC_POINT *q = NULL; int r; @@ -217,8 +218,15 @@ 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 (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if ((r = ssh_create_evp_ec(resp->public_key, resp->public_key_len, + NULL, key->ecdsa_nid, &key->pkey)) != 0) { + error_f("key creation failed"); + goto out; + } +#else + if ((ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL || + (q = EC_POINT_new(EC_KEY_get0_group(ecdsa))) == NULL || (b = sshbuf_new()) == NULL) { error_f("allocation failed"); r = SSH_ERR_ALLOC_FAIL; @@ -229,30 +237,53 @@ 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, EC_KEY_get0_group(ecdsa))) != 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 0 /* FIXME beldmit */ + if (sshkey_ec_validate_public(EC_KEY_get0_group(ecdsa), 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) { +#endif + 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; + } +#endif +#ifdef HAVE_EVP_PKEY_PUBLIC_CHECK + if ((ctx = EVP_PKEY_CTX_new(key->pkey, NULL)) + == NULL || + EVP_PKEY_public_check(ctx) != 1) { + r = SSH_ERR_KEY_INVALID_EC_VALUE; + goto out; + } +#endif /* 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); + EVP_PKEY_CTX_free(ctx); return r; } #endif /* WITH_OPENSSL */ diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c index 56ffdd86156..798012f9065 100644 --- a/sshbuf-getput-crypto.c +++ b/sshbuf-getput-crypto.c @@ -25,9 +25,11 @@ #ifdef WITH_OPENSSL #include -#ifdef OPENSSL_HAS_ECC -# include -#endif /* OPENSSL_HAS_ECC */ +#include +#include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#include +#endif #include "ssherr.h" #include "sshbuf.h" @@ -123,7 +125,7 @@ sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v) SSHBUF_ABORT(); return SSH_ERR_INTERNAL_ERROR; } - return 0; + return 0; } #endif /* OPENSSL_HAS_ECC */ @@ -171,10 +173,30 @@ 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) +sshbuf_put_ecpkey(struct sshbuf *buf, EVP_PKEY *pkey) { - return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v), - EC_KEY_get0_group(v)); + const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + + if (ec == NULL) + return SSH_ERR_LIBCRYPTO_ERROR; + + return sshbuf_put_ec(buf, EC_KEY_get0_public_key(ec), + EC_KEY_get0_group(ec)); +/* FIXME beldmit */ +#if 0 + u_char d[SSHBUF_MAX_ECPOINT]; + size_t len; + int ret; + + /* this works since openssl version of 3.0.8 */ + if (EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + d, SSHBUF_MAX_ECPOINT, &len) != 1) + return len > SSHBUF_MAX_ECPOINT ? SSH_ERR_INVALID_ARGUMENT : + SSH_ERR_LIBCRYPTO_ERROR; + ret = sshbuf_put_string(buf, d, len); + explicit_bzero(d, len); + return ret; +#endif } #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ diff --git a/sshbuf.h b/sshbuf.h index e2155f9a4d7..aaed8fc43fb 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -221,9 +221,9 @@ int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v); # ifdef OPENSSL_HAS_ECC 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_ecpkey(struct sshbuf *buf, EVP_PKEY *pkey); 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); -# endif /* OPENSSL_HAS_ECC */ +# endif #endif /* WITH_OPENSSL */ /* Dump the contents of the buffer in a human-readable format */ diff --git a/sshkey.c b/sshkey.c index 06db9b5da34..cfa51b70c3b 100644 --- a/sshkey.c +++ b/sshkey.c @@ -34,7 +34,12 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#include +#include +#include #endif +#endif /* WITH_OPENSSL */ #include "crypto_api.h" @@ -477,6 +482,86 @@ sshkey_type_certified(int type) } #ifdef WITH_OPENSSL +int +sshkey_calculate_signature(EVP_PKEY *pkey, int hash_alg, u_char **sigp, + int *lenp, const u_char *data, size_t datalen) +{ + EVP_MD_CTX *ctx = NULL; + u_char *sig = NULL; + int ret, slen; + size_t len; + + if (sigp == NULL || lenp == NULL) { + return SSH_ERR_INVALID_ARGUMENT; + } + + slen = EVP_PKEY_size(pkey); + if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) + return SSH_ERR_INVALID_ARGUMENT; + + len = slen; + if ((sig = malloc(slen)) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + + if ((ctx = EVP_MD_CTX_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto error; + } + if (EVP_DigestSignInit(ctx, NULL, ssh_digest_to_md(hash_alg), + NULL, pkey) != 1 || + EVP_DigestSignUpdate(ctx, data, datalen) != 1 || + EVP_DigestSignFinal(ctx, sig, &len) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto error; + } + + *sigp = sig; + *lenp = len; + /* Now owned by the caller */ + sig = NULL; + ret = 0; + +error: + EVP_MD_CTX_free(ctx); + free(sig); + return ret; +} + +int +sshkey_verify_signature(EVP_PKEY *pkey, int hash_alg, const u_char *data, + size_t datalen, u_char *sigbuf, int siglen) +{ + EVP_MD_CTX *ctx = NULL; + int ret; + + if ((ctx = EVP_MD_CTX_new()) == NULL) { + return SSH_ERR_ALLOC_FAIL; + } + if (EVP_DigestVerifyInit(ctx, NULL, ssh_digest_to_md(hash_alg), + NULL, pkey) != 1 || + EVP_DigestVerifyUpdate(ctx, data, datalen) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto done; + } + ret = EVP_DigestVerifyFinal(ctx, sigbuf, siglen); + switch (ret) { + case 1: + ret = 0; + break; + case 0: + ret = SSH_ERR_SIGNATURE_INVALID; + break; + default: + ret = SSH_ERR_LIBCRYPTO_ERROR; + break; + } + +done: + 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) @@ -1327,14 +1412,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; @@ -1344,52 +1427,80 @@ sshkey_check_rsa_length(const struct sshkey *k, int min_size) #ifdef WITH_OPENSSL # ifdef OPENSSL_HAS_ECC -int -sshkey_ecdsa_key_to_nid(EC_KEY *k) +# if OPENSSL_VERSION_NUMBER < 0x30000000L +static int +sshkey_ec_key_to_nid(EC_KEY *k) { - EC_GROUP *eg; - int nids[] = { - NID_X9_62_prime256v1, - NID_secp384r1, + EC_GROUP *eg; + int nids[] = { + NID_X9_62_prime256v1, + NID_secp384r1, # ifdef OPENSSL_HAS_NISTP521 - NID_secp521r1, + NID_secp521r1, # endif /* OPENSSL_HAS_NISTP521 */ - -1 - }; + -1 + }; + 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]; +} +#endif + +int +sshkey_ecdsa_key_to_nid(EVP_PKEY *pkey) +{ +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + char group_name[64] = {0}; int nid; - u_int i; - const EC_GROUP *g = EC_KEY_get0_group(k); + if (EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, + group_name, 64, NULL) != 1) + return -1; + /* try both short and long versions as the documentation does not + * state which one is internally saved */ + if ((nid = OBJ_sn2nid(group_name)) != NID_undef || + (nid = OBJ_ln2nid(group_name)) != NID_undef) + return nid; + return -1; +#else + int nid; + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); - /* - * 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 (ec == NULL) return -1; + + nid = sshkey_ec_key_to_nid(ec); + EC_KEY_free(ec); + return nid; +#endif } # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ - int sshkey_generate(int type, u_int bits, struct sshkey **keyp) { @@ -1604,7 +1715,6 @@ sshkey_shield_private(struct sshkey *k) fprintf(stderr, "%s: encrypted\n", __func__); sshbuf_dump_data(enc, enclen, stderr); #endif - /* Make a scrubbed, public-only copy of our private key argument */ if ((r = sshkey_from_private(k, &kswap)) != 0) goto out; @@ -3238,24 +3348,74 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, success = EVP_PKEY_set1_DSA(pkey, key->dsa); } break; +/* #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + case KEY_ECDSA: + case KEY_RSA: + if (format == SSHKEY_PRIVATE_PEM) { + OSSL_ENCODER_CTX *ctx; + ctx = OSSL_ENCODER_CTX_new_for_pkey(key->pkey, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + "PEM", + "PrivateKeyInfo", + NULL); + if (!ctx) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((cipher != NULL && + OSSL_ENCODER_CTX_set_cipher(ctx, + EVP_CIPHER_get0_name(cipher), + NULL) != 1) || + (passphrase != NULL && + OSSL_ENCODER_CTX_set_passphrase(ctx, passphrase, + len) != 1)) { + OSSL_ENCODER_CTX_free(ctx); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (OSSL_ENCODER_to_bio(ctx, bio) != 1) { + OSSL_ENCODER_CTX_free(ctx); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + OSSL_ENCODER_CTX_free(ctx); + success = 1; + } else { + EVP_PKEY_free(pkey); + pkey = key->pkey; + EVP_PKEY_up_ref(key->pkey); + success = 1; + } + break; +#else FIXME beldmit */ #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); + EVP_PKEY_free(pkey); + 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); + EVP_PKEY_free(pkey); + pkey = key->pkey; + EVP_PKEY_up_ref(key->pkey); + success = 1; } break; +/* #endif FIXME beldmit */ default: success = 0; break; @@ -3270,6 +3430,42 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } +#if 0 + /* beldmit: Don't understand why Norbert implemented it, PEM_write_bio_PrivateKey is not deprecated */ + if (key->type == KEY_RSA) { + OSSL_ENCODER_CTX *ctx; + success = 0; + ctx = OSSL_ENCODER_CTX_new_for_pkey(key->pkey, + EVP_PKEY_KEYPAIR, + "PEM", "type-specific", NULL); + if (!ctx) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((cipher != NULL && + OSSL_ENCODER_CTX_set_cipher(ctx, + EVP_CIPHER_get0_name(cipher), NULL) != 1) || + (passphrase != NULL && + OSSL_ENCODER_CTX_set_passphrase(ctx, passphrase, len) != 1)) { + OSSL_ENCODER_CTX_free(ctx); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (OSSL_ENCODER_to_bio(ctx, bio) != 1) { + OSSL_ENCODER_CTX_free(ctx); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + OSSL_ENCODER_CTX_free(ctx); + success = 1; + } else { + if ((success = PEM_write_bio_PrivateKey(bio, pkey, cipher, + passphrase, len, NULL, NULL)) == 0) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + } +#endif } if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { r = SSH_ERR_INTERNAL_ERROR; @@ -3419,6 +3615,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, const char *passphrase, struct sshkey **keyp) { EVP_PKEY *pk = NULL; + EVP_PKEY_CTX *ctx = NULL; struct sshkey *prv = NULL; BIO *bio = NULL; int r; @@ -3455,15 +3652,12 @@ 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->pkey = pk; + pk = NULL; prv->type = KEY_RSA; #ifdef DEBUG_PK - RSA_print_fp(stderr, prv->rsa, 8); + EVP_PKEY_print_fp(stderr, prv->pkey, 0, NULL); #endif - if (RSA_blinding_on(prv->rsa, NULL) != 1) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } if ((r = sshkey_check_rsa_length(prv, 0)) != 0) goto out; } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA && @@ -3484,20 +3678,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); + prv->pkey = pk; + pk = NULL; prv->type = KEY_ECDSA; - prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->ecdsa); + prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->pkey); 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) { + (ctx = EVP_PKEY_CTX_new(prv->pkey, NULL)) == NULL +#ifdef HAVE_EVP_PKEY_PUBLIC_CHECK + || EVP_PKEY_public_check(ctx) != 1 +#endif +#ifdef HAVE_EVP_PKEY_PRIVATE_CHECK + || EVP_PKEY_private_check(ctx) != 1 +#endif + ) { r = SSH_ERR_INVALID_FORMAT; goto out; } # ifdef DEBUG_PK - if (prv != NULL && prv->ecdsa != NULL) - sshkey_dump_ec_key(prv->ecdsa); + if (prv != NULL && prv->pkey != NULL) + EVP_PKEY_print_public_fp(stderr, prv->pkey, 0, NULL); # endif #endif /* OPENSSL_HAS_ECC */ #ifdef OPENSSL_HAS_ED25519 @@ -3549,6 +3748,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, out: BIO_free(bio); EVP_PKEY_free(pk); + EVP_PKEY_CTX_free(ctx); sshkey_free(prv); return r; } @@ -3704,3 +3904,29 @@ sshkey_set_filename(struct sshkey *k, const char *filename) return 0; } #endif /* WITH_XMSS */ + +#ifdef WITH_OPENSSL +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +EVP_PKEY * +sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) +{ + EVP_PKEY *ret = NULL; + OSSL_PARAM *params = NULL; + if (param_bld == NULL || ctx == NULL) { + /* debug2_f("param_bld or ctx is NULL"); */ + return NULL; + } + if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { + /* debug2_f("Could not build param list"); */ + return NULL; + } + if (EVP_PKEY_fromdata_init(ctx) != 1 || + EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) { + /* debug2_f("EVP_PKEY_fromdata failed"); */ + OSSL_PARAM_free(params); + return NULL; + } + return ret; +} +#endif +#endif /* WITH_OPENSSL */ diff --git a/sshkey.h b/sshkey.h index 708f2da8677..b030e50c3de 100644 --- a/sshkey.h +++ b/sshkey.h @@ -29,10 +29,13 @@ #include #ifdef WITH_OPENSSL -#include #include +#include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#include +#include +#endif # ifdef OPENSSL_HAS_ECC -# include # include # else /* OPENSSL_HAS_ECC */ # define EC_KEY void @@ -42,9 +45,9 @@ #define SSH_OPENSSL_VERSION OpenSSL_version(OPENSSL_VERSION) #else /* WITH_OPENSSL */ # define BIGNUM void -# define RSA void +# define EVP_PKEY void # define DSA void -# define EC_KEY void +# define EC_KEY void # define EC_GROUP void # define EC_POINT void #define SSH_OPENSSL_VERSION "without OpenSSL" @@ -126,12 +129,11 @@ struct sshkey { int type; int flags; /* KEY_RSA */ - RSA *rsa; + EVP_PKEY *pkey; /* KEY_DSA */ DSA *dsa; /* KEY_ECDSA and KEY_ECDSA_SK */ int ecdsa_nid; /* NID of curve */ - EC_KEY *ecdsa; /* KEY_ED25519 and KEY_ED25519_SK */ u_char *ed25519_sk; u_char *ed25519_pk; @@ -258,7 +260,7 @@ 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(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 *); @@ -266,6 +268,10 @@ const char *sshkey_ssh_name(const struct sshkey *); const char *sshkey_ssh_name_plain(const struct sshkey *); int sshkey_names_valid2(const char *, int, int); char *sshkey_alg_list(int, int, int, char); +int sshkey_calculate_signature(EVP_PKEY*, int, u_char **, + int *, const u_char *, size_t); +int sshkey_verify_signature(EVP_PKEY *, int, const u_char *, + size_t, u_char *, int); int sshkey_from_blob(const u_char *, size_t, struct sshkey **); int sshkey_fromb(struct sshbuf *, struct sshkey **); @@ -287,10 +293,6 @@ 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 **); -/* for debug */ -void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *); -void sshkey_dump_ec_key(const EC_KEY *); - /* private key parsing and serialisation */ int sshkey_private_serialize(struct sshkey *key, struct sshbuf *buf); int sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf, @@ -310,7 +312,9 @@ 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 *); @@ -322,6 +326,17 @@ int sshkey_private_serialize_maxsign(struct sshkey *key, void sshkey_sig_details_free(struct sshkey_sig_details *); +#ifdef WITH_OPENSSL +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +EVP_PKEY *sshkey_create_evp(OSSL_PARAM_BLD *, EVP_PKEY_CTX *); +#endif +int ssh_create_evp_dss(const struct sshkey *, EVP_PKEY **); +int ssh_create_evp_rsa(const BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, const BIGNUM *, const BIGNUM *, + const BIGNUM *, const BIGNUM *, EVP_PKEY **); +int ssh_create_evp_ec(u_char *, size_t, BIGNUM *, int, EVP_PKEY **); +#endif /* WITH_OPENSSL */ + #ifdef SSHKEY_INTERNAL int sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b); void sshkey_sk_cleanup(struct sshkey *k); @@ -336,8 +351,12 @@ int check_rsa_length(const RSA *rsa); /* XXX remove */ #endif #endif +#ifdef ENABLE_PKCS11 +int pkcs11_get_ecdsa_idx(void); +#endif + #if !defined(WITH_OPENSSL) -# undef RSA +# undef EVP_PKEY # undef DSA # undef EC_KEY # undef EC_GROUP