From 4fb499059d6afb3edeacdfc21a6ccd16f6fbf84c Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 11 Oct 2023 18:09:43 +0200 Subject: [PATCH] Buildable on RHEL 8. Passing tests on RHEL 9. --- kexdh.c | 65 ++++++++- kexecdh.c | 5 +- packet.c | 2 +- .../sshbuf/test_sshbuf_getput_crypto.c | 69 +++++++++- regress/unittests/sshkey/common.c | 43 ++++++ regress/unittests/sshkey/test_file.c | 16 +++ regress/unittests/sshkey/test_sshkey.c | 11 ++ ssh-dss.c | 15 ++ ssh-ecdsa.c | 83 +++++++++++- ssh-keygen.c | 128 ++++++++++++++++-- ssh-rsa.c | 49 ++++++- ssh-sk.c | 49 ++++++- sshbuf-getput-crypto.c | 74 +++++++++- sshbuf.h | 5 +- sshkey.c | 118 ++++++++++++++-- sshkey.h | 4 + 16 files changed, 690 insertions(+), 46 deletions(-) diff --git a/kexdh.c b/kexdh.c index a23d07b321c7..e7991080deef 100644 --- a/kexdh.c +++ b/kexdh.c @@ -85,6 +85,10 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) u_char *kbuf = NULL; size_t klen = 0; int r = 0; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + DH *dh_peer = NULL; + BIGNUM *copy_p = NULL, *copy_q = NULL, *copy_g = NULL, *copy_pub = NULL; +#endif #ifdef DEBUG_KEXDH fprintf(stderr, "dh_pub= "); @@ -100,6 +104,7 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) goto out; } +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) DH_get0_key(kex->dh, &pub, &priv); DH_get0_pqg(kex->dh, &p, &q, &g); /* import key */ @@ -109,7 +114,7 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) ERR_print_errors_fp(stderr); goto out; } - /* import peer key + /* import peer key * the parameters should be the same as with pkey */ r = kex_create_evp_dh(&dh_pkey, p, q, g, dh_pub, NULL); @@ -118,9 +123,62 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) ERR_print_errors_fp(stderr); goto out; } +#else + DH_get0_pqg(kex->dh, &p, &q, &g); + if ((pkey = EVP_PKEY_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + if (EVP_PKEY_set1_DH(pkey, kex->dh) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + if ((dh_peer = DH_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + copy_p = BN_dup(p); + copy_q = BN_dup(q); + copy_g = BN_dup(g); + if (DH_set0_pqg(dh_peer, copy_p, copy_q, copy_g) != 1) { + BN_free(copy_p); + BN_free(copy_q); + BN_free(copy_g); + DH_free(dh_peer); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + copy_p = copy_q = copy_g = NULL; + + copy_pub = BN_dup(dh_pub); + if (DH_set0_key(dh_peer, copy_pub, NULL) != 1) { + BN_free(copy_pub); + DH_free(dh_peer); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + copy_pub = NULL; + + if ((dh_pkey = EVP_PKEY_new()) == NULL) { + DH_free(dh_peer); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + if (EVP_PKEY_set1_DH(dh_pkey, dh_peer) != 1) { + DH_free(dh_peer); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + DH_free(dh_peer); +#endif if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) { error_f("Could not init EVP_PKEY_CTX for dh"); + ERR_print_errors_fp(stderr); r = SSH_ERR_ALLOC_FAIL; goto out; } @@ -244,6 +302,7 @@ kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob, sshbuf_free(buf); return r; } +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) /* * Creates an EVP_PKEY from the given parameters and keys. * The private key can be omitted. @@ -252,7 +311,6 @@ int kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) { -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) OSSL_PARAM_BLD *param_bld = NULL; EVP_PKEY_CTX *ctx = NULL; int r = 0; @@ -286,7 +344,6 @@ kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, OSSL_PARAM_BLD_free(param_bld); EVP_PKEY_CTX_free(ctx); return r; -#else -#endif } +#endif #endif /* WITH_OPENSSL */ diff --git a/kexecdh.c b/kexecdh.c index d16a425e18ae..8ae30aebabe9 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -194,9 +194,8 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, } if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) goto out; - #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - if ((r = sshbuf_get_ec(buf, &pub, &publen)) != 0) + if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) goto out; sshbuf_reset(buf); if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { @@ -233,7 +232,7 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_get_eckey(ec_blob, ec)) != 0) + if ((r = sshbuf_get_eckey(buf, ec)) != 0) goto out; if ((peer_key = EVP_PKEY_new()) == NULL) { diff --git a/packet.c b/packet.c index 3e102fbfc99e..ca4aa5b214c1 100644 --- a/packet.c +++ b/packet.c @@ -2605,7 +2605,7 @@ sshpkt_get_cstring(struct ssh *ssh, char **valp, size_t *lenp) int sshpkt_get_ec(struct ssh *ssh, u_char **pubkey, size_t *pubkey_len) { - return sshbuf_get_ec(ssh->state->incoming_packet, pubkey, pubkey_len); + return sshbuf_get_string(ssh->state->incoming_packet, pubkey, pubkey_len); } int diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c index ef348c67617b..509a24da5967 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c @@ -17,12 +17,17 @@ #include #include -#include #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" @@ -68,6 +73,7 @@ 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; @@ -75,6 +81,9 @@ sshbuf_getput_crypto_tests(void) EC_GROUP *g = NULL; u_char *pubkey = NULL; size_t pubkey_len; +#else + EC_KEY *eck; +#endif EC_POINT *ecp; #endif int r; @@ -232,19 +241,25 @@ sshbuf_getput_crypto_tests(void) #if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) TEST_START("sshbuf_put_ec"); +#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); - BN_free(bn_x); - BN_free(bn_y); pubkey_len = EC_POINT_point2oct(g, ecp, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); ASSERT_INT_NE(pubkey_len, 0); @@ -253,7 +268,15 @@ sshbuf_getput_crypto_tests(void) 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); @@ -265,15 +288,55 @@ sshbuf_getput_crypto_tests(void) 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); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) ASSERT_INT_EQ(sshbuf_put_ec(p1, eck), 0); +#else + ASSERT_INT_EQ(sshbuf_put_ecbuf(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); + p1 = sshbuf_new(); + ASSERT_PTR_NE(p1, NULL); + ASSERT_INT_EQ(sshbuf_put_string(p1, expec256, sizeof(expec256)), 0); + ASSERT_SIZE_T_EQ(sshbuf_len(p1), sizeof(expec256) + 4); + ASSERT_INT_EQ(sshbuf_put_u8(p1, 0x00), 0); + ASSERT_INT_EQ(sshbuf_get_eckey(p1, eck), 0); + bn_x = BN_new(); + bn_y = BN_new(); + ASSERT_PTR_NE(bn_x, NULL); + ASSERT_PTR_NE(bn_y, NULL); + ASSERT_INT_EQ(EC_POINT_get_affine_coordinates_GFp( + EC_KEY_get0_group(eck), EC_KEY_get0_public_key(eck), + bn_x, bn_y, NULL), 1); + MKBN(ec256_x, bn); + MKBN(ec256_y, bn2); + ASSERT_INT_EQ(BN_cmp(bn_x, bn), 0); + ASSERT_INT_EQ(BN_cmp(bn_y, bn2), 0); + ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1); + sshbuf_free(p1); + EC_KEY_free(eck); + BN_free(bn_x); + BN_free(bn_y); + BN_free(bn); + BN_free(bn2); + TEST_DONE(); +#endif #endif } diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c index c85fe646f918..8e1e48a6deae 100644 --- a/regress/unittests/sshkey/common.c +++ b/regress/unittests/sshkey/common.c @@ -21,6 +21,9 @@ #ifdef WITH_OPENSSL #include #include +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) +#include +#endif #include #include #ifdef OPENSSL_HAS_NISTP256 @@ -87,10 +90,20 @@ BIGNUM * rsa_n(struct sshkey *k) { BIGNUM *n = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; +#endif ASSERT_PTR_NE(k, 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); +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_key(rsa, &n, NULL, NULL); + RSA_free(rsa); +#endif return n; } @@ -98,10 +111,20 @@ BIGNUM * rsa_e(struct sshkey *k) { BIGNUM *e = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; +#endif ASSERT_PTR_NE(k, 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); +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_key(rsa, NULL, &e, NULL); + RSA_free(rsa); +#endif return e; } @@ -109,10 +132,20 @@ BIGNUM * rsa_p(struct sshkey *k) { BIGNUM *p = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; +#endif ASSERT_PTR_NE(k, 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); +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_factors(rsa, &p, NULL); + RSA_free(rsa); +#endif return p; } @@ -120,10 +153,20 @@ BIGNUM * rsa_q(struct sshkey *k) { BIGNUM *q = NULL; +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + RSA *rsa = NULL; +#endif ASSERT_PTR_NE(k, NULL); ASSERT_PTR_NE(k->pkey, NULL); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &q); +#else + rsa = EVP_PKEY_get1_RSA(k->pkey); + ASSERT_PTR_NE(rsa, NULL); + RSA_get0_factors(rsa, NULL, &q); + RSA_free(rsa); +#endif return q; } diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c index 2c5a0dd73e52..f4999563a852 100644 --- a/regress/unittests/sshkey/test_file.c +++ b/regress/unittests/sshkey/test_file.c @@ -49,6 +49,9 @@ sshkey_file_tests(void) BIGNUM *a, *b, *c; u_char *pubkey = NULL; size_t pubkey_len; +#ifdef OPENSSL_HAS_ECC + EC_KEY *ec = NULL; +#endif #endif char *cp; @@ -271,6 +274,12 @@ 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"); + ec = EVP_PKEY_get0_EC_KEY(k1->pkey); +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + 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); @@ -278,14 +287,21 @@ sshkey_file_tests(void) 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); +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) + 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 a9dd9796f0ac..3d2595847d35 100644 --- a/regress/unittests/sshkey/test_sshkey.c +++ b/regress/unittests/sshkey/test_sshkey.c @@ -292,6 +292,7 @@ sshkey_tests(void) TEST_START("generate KEY_ECDSA"); ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &ke), 0); ASSERT_PTR_NE(ke, 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); @@ -299,6 +300,11 @@ sshkey_tests(void) 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 */ @@ -356,11 +362,16 @@ sshkey_tests(void) ASSERT_PTR_NE(ke, k1); ASSERT_INT_EQ(k1->type, KEY_ECDSA); 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); TEST_DONE(); diff --git a/ssh-dss.c b/ssh-dss.c index 5ee0ad386931..a169b1baf271 100644 --- a/ssh-dss.c +++ b/ssh-dss.c @@ -32,8 +32,10 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include +#endif #include #include @@ -433,6 +435,7 @@ ssh_dss_verify(const struct sshkey *key, int ssh_create_evp_dss(const struct sshkey *k, EVP_PKEY **pkey) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) OSSL_PARAM_BLD *param_bld = NULL; EVP_PKEY_CTX *ctx = NULL; const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub = NULL, *priv = NULL; @@ -487,6 +490,18 @@ ssh_create_evp_dss(const struct sshkey *k, EVP_PKEY **pkey) OSSL_PARAM_BLD_free(param_bld); EVP_PKEY_CTX_free(ctx); return ret; +#else + EVP_PKEY * res = EVP_PKEY_new(); + if (res == NULL) + return SSH_ERR_ALLOC_FAIL; + + if (EVP_PKEY_set1_DSA(res, k->dsa) == 0) { + EVP_PKEY_free(res); + return SSH_ERR_LIBCRYPTO_ERROR; + } + *pkey = res; + return 0; +#endif } static const struct sshkey_impl_funcs sshkey_dss_funcs = { diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 65418f1b8f61..7b51c94a9d4f 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -33,8 +33,10 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include +#endif #include @@ -73,9 +75,13 @@ ssh_ecdsa_cleanup(struct sshkey *k) static int ssh_ecdsa_equal(const struct sshkey *a, const struct sshkey *b) { - /* FIXME OpenSSL 1.1.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; } @@ -101,13 +107,13 @@ 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; } - /* FIXME OpenSSL 1.1.1 */ 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); @@ -115,14 +121,24 @@ ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b, } 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(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_CTX *ctx = NULL; 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; @@ -138,6 +154,30 @@ ssh_ecdsa_generate(struct sshkey *k, int bits) } k->pkey = res; +#else + EC_KEY *private; + + 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) + return SSH_ERR_ALLOC_FAIL; + if (EC_KEY_generate_key(private) != 1) { + EC_KEY_free(private); + return SSH_ERR_LIBCRYPTO_ERROR; + } + EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); + + 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; } @@ -172,7 +212,6 @@ ssh_ecdsa_copy_public(const struct sshkey *from, struct sshkey *to) EC_KEY_free(ec_to); return 0; - } static int @@ -193,10 +232,42 @@ ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b, r = SSH_ERR_EC_CURVE_MISMATCH; goto out; } - if ((r = sshbuf_get_ec(b, &pub, &publen)) != 0) /*XXX*/ +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + if ((r = sshbuf_get_string(b, &pub, &publen)) != 0) /*XXX*/ goto out; 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; @@ -414,6 +485,7 @@ 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) @@ -461,6 +533,7 @@ ssh_create_evp_ec(u_char *pubkey, size_t pubkey_len, BIGNUM *privkey, EVP_PKEY_CTX_free(ctx); return ret; } +#endif /* NB. not static; used by ECDSA-SK */ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { diff --git a/ssh-keygen.c b/ssh-keygen.c index 4d7b327fe77a..455e07bb0b51 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -22,9 +22,11 @@ #include #include #include "openbsd-compat/openssl-compat.h" +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include #endif +#endif #ifdef HAVE_STDINT_H # include @@ -374,6 +376,7 @@ static void do_convert_to_pkcs8(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) case KEY_RSA: case KEY_ECDSA: OSSL_ENCODER_CTX *ctx = OSSL_ENCODER_CTX_new_for_pkey(k->pkey, @@ -389,6 +392,24 @@ do_convert_to_pkcs8(struct sshkey *k) } OSSL_ENCODER_CTX_free(ctx); break; +#else + case KEY_RSA: + { + RSA *rsa = EVP_PKEY_get0_RSA(k->pkey); + if (!PEM_write_RSA_PUBKEY(stdout, rsa)) + fatal("PEM_write_RSA_PUBKEY failed"); + } + break; +#ifdef OPENSSL_HAS_ECC + case KEY_ECDSA: + { + 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"); @@ -403,6 +424,7 @@ static void do_convert_to_pem(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) case KEY_RSA: case KEY_ECDSA: OSSL_ENCODER_CTX *ctx; @@ -417,6 +439,24 @@ do_convert_to_pem(struct sshkey *k) } OSSL_ENCODER_CTX_free(ctx); break; +#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: + { + 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"); @@ -494,6 +534,7 @@ do_convert_private_ssh2(struct sshbuf *b) 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"); @@ -587,11 +628,30 @@ do_convert_private_ssh2(struct sshbuf *b) 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 parameters"); + 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(rsa, rsa_p, rsa_q)) + fatal_f("RSA_set0_factors failed"); + rsa_p = rsa_q = NULL; /* transferred */ + 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); @@ -706,10 +766,13 @@ 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); @@ -720,6 +783,12 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) 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: @@ -754,6 +823,7 @@ 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; @@ -772,6 +842,26 @@ do_convert_from_pem(struct sshkey **k, int *private) fclose(fp); return; } +#else + FILE *fp; + RSA *rsa; + + if ((fp = fopen(identity_file, "r")) == NULL) + fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + 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; + 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,7 +871,6 @@ do_convert_from(struct passwd *pw) struct sshkey *k = NULL; int r, private = 0, ok = 0; struct stat st; - OSSL_ENCODER_CTX *ctx; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); @@ -813,18 +902,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: - 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); + { + 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, EVP_PKEY_get0_EC_KEY(k->pkey), NULL, + NULL, 0, NULL, NULL); break; +#endif + case KEY_RSA: + 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-rsa.c b/ssh-rsa.c index 3ab752d85568..fcfb0a87dcec 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -23,8 +23,10 @@ #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include +#endif #include #include @@ -66,10 +68,13 @@ ssh_rsa_cleanup(struct sshkey *k) static int ssh_rsa_equal(const struct sshkey *a, const struct sshkey *b) { - /* FIXME OpenSSL 1.1.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; } @@ -130,6 +135,7 @@ 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; @@ -175,6 +181,41 @@ ssh_rsa_generate(struct sshkey *k, int bits) 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 || + bits > SSHBUF_MAX_BIGNUM * 8) + return SSH_ERR_KEY_LENGTH; + if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (!BN_set_word(f4, RSA_F4) || + !RSA_generate_key_ex(private, bits, f4, NULL)) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + 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 @@ -580,7 +621,7 @@ openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, size_t rsasize = 0; int ret; - rsasize = EVP_PKEY_get_size(pkey); + rsasize = EVP_PKEY_size(pkey); if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || siglen == 0 || siglen > rsasize) { ret = SSH_ERR_INVALID_ARGUMENT; @@ -594,6 +635,7 @@ openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, 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, @@ -661,6 +703,7 @@ ssh_create_evp_rsa(const BIGNUM *n, const BIGNUM *e, const BIGNUM *d, 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 8e73abf15655..d68811206e06 100644 --- a/ssh-sk.c +++ b/ssh-sk.c @@ -207,6 +207,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; *keyp = NULL; @@ -216,12 +218,55 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp) goto out; } key->ecdsa_nid = NID_X9_62_prime256v1; +#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; } - if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key->pkey, NULL)) +#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; + goto out; + } + if ((r = sshbuf_put_string(b, + resp->public_key, resp->public_key_len)) != 0) { + error_fr(r, "sshbuf_put_string"); + goto out; + } + 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 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; + } +#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 + if ((ctx = EVP_PKEY_CTX_new(key->pkey, NULL)) == NULL || EVP_PKEY_public_check(ctx) != 1) { r = SSH_ERR_KEY_INVALID_EC_VALUE; @@ -234,6 +279,8 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp) out: sshkey_free(key); sshbuf_free(b); + EC_KEY_free(ecdsa); + EC_POINT_free(q); EVP_PKEY_CTX_free(ctx); return r; } diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c index 8b1a9232ec35..ac3d5d3c876a 100644 --- a/sshbuf-getput-crypto.c +++ b/sshbuf-getput-crypto.c @@ -27,7 +27,9 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include +#endif #include "ssherr.h" #include "sshbuf.h" @@ -55,14 +57,78 @@ sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp) return 0; } +#ifdef OPENSSL_HAS_ECC +static int +get_ec(const u_char *d, size_t len, EC_POINT *v, const EC_GROUP *g) +{ + /* Refuse overlong bignums */ + if (len == 0 || len > SSHBUF_MAX_ECPOINT) + return SSH_ERR_ECPOINT_TOO_LARGE; + /* Only handle uncompressed points */ + if (*d != POINT_CONVERSION_UNCOMPRESSED) + return SSH_ERR_INVALID_FORMAT; + if (v != NULL && EC_POINT_oct2point(g, v, d, len, NULL) != 1) + return SSH_ERR_INVALID_FORMAT; /* XXX assumption */ + return 0; +} + int -sshbuf_get_ec(struct sshbuf *buf, u_char **pub, size_t *publen) +sshbuf_get_ec(struct sshbuf *buf, EC_POINT *v, const EC_GROUP *g) { - /* the public key is in the buffer in octet string UNCOMPRESSED - * format. See sshbuf_put_ec */ - return sshbuf_get_string(buf, pub, publen); + const u_char *d; + size_t len; + int r; + + if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) + return r; + if ((r = get_ec(d, len, v, g)) != 0) + return r; + /* Skip string */ + if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { + /* Shouldn't happen */ + SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); + SSHBUF_ABORT(); + return SSH_ERR_INTERNAL_ERROR; + } + return 0; } +int +sshbuf_get_eckey(struct sshbuf *buf, EC_KEY *v) +{ + EC_POINT *pt = EC_POINT_new(EC_KEY_get0_group(v)); + int r; + const u_char *d; + size_t len; + + if (pt == NULL) { + SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL")); + return SSH_ERR_ALLOC_FAIL; + } + if ((r = sshbuf_peek_string_direct(buf, &d, &len)) < 0) { + EC_POINT_free(pt); + return r; + } + if ((r = get_ec(d, len, pt, EC_KEY_get0_group(v))) != 0) { + EC_POINT_free(pt); + return r; + } + if (EC_KEY_set_public_key(v, pt) != 1) { + EC_POINT_free(pt); + return SSH_ERR_ALLOC_FAIL; /* XXX assumption */ + } + EC_POINT_free(pt); + /* Skip string */ + if (sshbuf_get_string_direct(buf, NULL, NULL) != 0) { + /* Shouldn't happen */ + SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR")); + SSHBUF_ABORT(); + return SSH_ERR_INTERNAL_ERROR; + } + return 0; +} +#endif /* OPENSSL_HAS_ECC */ + int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) { diff --git a/sshbuf.h b/sshbuf.h index 7260cba350df..4404be2b94cb 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -23,6 +23,7 @@ #include #ifdef WITH_OPENSSL # include +# include #endif /* WITH_OPENSSL */ #define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */ @@ -215,7 +216,9 @@ int sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf, #ifdef WITH_OPENSSL int sshbuf_get_bignum2(struct sshbuf *buf, BIGNUM **valp); int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v); -int sshbuf_get_ec(struct sshbuf *buf, u_char **pub, size_t *publen); +/* FIXME beldmit should accept EVP_PKEY * */ +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, EVP_PKEY *pkey); #endif /* WITH_OPENSSL */ diff --git a/sshkey.c b/sshkey.c index 31e642382c60..e53cc307b691 100644 --- a/sshkey.c +++ b/sshkey.c @@ -34,10 +34,12 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include #include #endif +#endif #include "crypto_api.h" @@ -493,7 +495,7 @@ sshkey_calculate_signature(EVP_PKEY *pkey, int hash_alg, u_char **sigp, return SSH_ERR_INVALID_ARGUMENT; } - slen = EVP_PKEY_get_size(pkey); + slen = EVP_PKEY_size(pkey); if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) return SSH_ERR_INVALID_ARGUMENT; @@ -1415,7 +1417,7 @@ sshkey_check_rsa_length(const struct sshkey *k, int min_size) if (k == NULL || k->pkey == NULL || (k->type != KEY_RSA && k->type != KEY_RSA_CERT)) return 0; - nbits = EVP_PKEY_get_bits(k->pkey); + nbits = EVP_PKEY_bits(k->pkey); if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE || (min_size > 0 && nbits < min_size)) return SSH_ERR_KEY_LENGTH; @@ -1425,10 +1427,54 @@ sshkey_check_rsa_length(const struct sshkey *k, int min_size) #ifdef WITH_OPENSSL # ifdef OPENSSL_HAS_ECC +static int +sshkey_ec_key_to_nid(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 + }; + 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]; +} + int sshkey_ecdsa_key_to_nid(EVP_PKEY *pkey) { - /* FIXME OpenSSL 1.1.1*/ +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) char group_name[64] = {0}; int nid; if (EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, @@ -1440,6 +1486,16 @@ sshkey_ecdsa_key_to_nid(EVP_PKEY *pkey) (nid = OBJ_ln2nid(group_name)) != NID_undef) return nid; return -1; +#else + int nid; + EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey); + + 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 */ @@ -3130,6 +3186,7 @@ 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) { @@ -3162,10 +3219,40 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, OSSL_ENCODER_CTX_free(ctx); success = 1; } else { - pkey = EVP_PKEY_dup(key->pkey); - success = pkey == NULL ? 0 : 1; + EVP_PKEY_free(pkey); + pkey = key->pkey; + EVP_PKEY_up_ref(key->pkey); + success = 1; } break; +#else +#ifdef OPENSSL_HAS_ECC + case KEY_ECDSA: + if (format == SSHKEY_PRIVATE_PEM) { + success = PEM_write_bio_ECPrivateKey(bio, + EVP_PKEY_get0_EC_KEY(key->pkey), + cipher, passphrase, len, NULL, NULL); + } else { + 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, + EVP_PKEY_get0_RSA(key->pkey), + cipher, passphrase, len, NULL, NULL); + } else { + EVP_PKEY_free(pkey); + pkey = key->pkey; + EVP_PKEY_up_ref(key->pkey); + success = 1; + } + break; +#endif default: success = 0; break; @@ -3175,7 +3262,13 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, goto out; } if (format == SSHKEY_PRIVATE_PKCS8) { - /* for now only rsa keys */ + if ((success = PEM_write_bio_PrivateKey(bio, pkey, cipher, + passphrase, len, NULL, NULL)) == 0) { + 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; @@ -3209,6 +3302,7 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, goto out; } } +#endif } if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { r = SSH_ERR_INTERNAL_ERROR; @@ -3425,10 +3519,12 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, prv->type = KEY_ECDSA; prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->pkey); if (prv->ecdsa_nid == -1 || - (ctx = EVP_PKEY_CTX_new_from_pkey(NULL, prv->pkey, NULL)) - == NULL || - EVP_PKEY_public_check(ctx) != 1 || - EVP_PKEY_private_check(ctx) != 1) { + (ctx = EVP_PKEY_CTX_new(prv->pkey, NULL)) == NULL + || EVP_PKEY_public_check(ctx) != 1 +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + || EVP_PKEY_private_check(ctx) != 1 +#endif + ) { r = SSH_ERR_INVALID_FORMAT; goto out; } @@ -3607,6 +3703,7 @@ sshkey_set_filename(struct sshkey *k, const char *filename) #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) { @@ -3628,4 +3725,5 @@ sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) } return ret; } +#endif #endif /* WITH_OPENSSL */ diff --git a/sshkey.h b/sshkey.h index d510a1f59461..726f7aaa1fc2 100644 --- a/sshkey.h +++ b/sshkey.h @@ -31,8 +31,10 @@ #ifdef WITH_OPENSSL #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include +#endif # ifdef OPENSSL_HAS_ECC # include # else /* OPENSSL_HAS_ECC */ @@ -317,7 +319,9 @@ 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 *,