From c56e886d597f9cbb0e9c6c2370ac7e002910da43 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 27 Sep 2023 11:04:18 +0200 Subject: [PATCH 01/21] Applying Fedora patch openssh-9.3p1-merged-openssl-evp.patch --- digest-openssl.c | 16 +++ digest.h | 6 + ssh-dss.c | 122 +++++++++++++---- ssh-ecdsa.c | 176 +++++++++++++++++++----- ssh-pkcs11-client.c | 28 ++++ ssh-pkcs11.c | 16 +++ ssh-pkcs11.h | 5 + ssh-rsa.c | 326 +++++++++++++++++++++----------------------- sshkey.c | 106 ++++++++++++++ sshkey.h | 18 +++ 10 files changed, 592 insertions(+), 227 deletions(-) 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/ssh-dss.c b/ssh-dss.c index 3174ef146dc..5ee0ad38693 100644 --- a/ssh-dss.c +++ b/ssh-dss.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include #include @@ -261,11 +263,15 @@ ssh_dss_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) { + EVP_PKEY *pkey = NULL; DSA_SIG *sig = NULL; const BIGNUM *sig_r, *sig_s; - u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; - size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); + u_char sigblob[SIGBLOB_LEN]; + size_t rlen, slen; + int len; struct sshbuf *b = NULL; + u_char *sigb = NULL; + const u_char *psig = NULL; int ret = SSH_ERR_INVALID_ARGUMENT; if (lenp != NULL) @@ -276,17 +282,23 @@ ssh_dss_sign(struct sshkey *key, if (key == NULL || key->dsa == NULL || sshkey_type_plain(key->type) != KEY_DSA) return SSH_ERR_INVALID_ARGUMENT; - if (dlen == 0) - return SSH_ERR_INTERNAL_ERROR; - if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, - digest, sizeof(digest))) != 0) + if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) + return ret; + ret = sshkey_calculate_signature(pkey, SSH_DIGEST_SHA1, &sigb, &len, + data, datalen); + EVP_PKEY_free(pkey); + if (ret < 0) { goto out; + } - if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { + psig = sigb; + if ((sig = d2i_DSA_SIG(NULL, &psig, len)) == NULL) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + free(sigb); + sigb = NULL; DSA_SIG_get0(sig, &sig_r, &sig_s); rlen = BN_num_bytes(sig_r); @@ -319,7 +331,7 @@ ssh_dss_sign(struct sshkey *key, *lenp = len; ret = 0; out: - explicit_bzero(digest, sizeof(digest)); + free(sigb); DSA_SIG_free(sig); sshbuf_free(b); return ret; @@ -331,20 +343,20 @@ ssh_dss_verify(const struct sshkey *key, const u_char *data, size_t dlen, const char *alg, u_int compat, struct sshkey_sig_details **detailsp) { + EVP_PKEY *pkey = NULL; DSA_SIG *dsig = NULL; BIGNUM *sig_r = NULL, *sig_s = NULL; - u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; - size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); + u_char *sigblob = NULL; + size_t len, slen; int ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; char *ktype = NULL; + u_char *sigb = NULL, *psig = NULL; if (key == NULL || key->dsa == NULL || sshkey_type_plain(key->type) != KEY_DSA || sig == NULL || siglen == 0) return SSH_ERR_INVALID_ARGUMENT; - if (hlen == 0) - return SSH_ERR_INTERNAL_ERROR; /* fetch signature */ if ((b = sshbuf_from(sig, siglen)) == NULL) @@ -386,25 +398,28 @@ ssh_dss_verify(const struct sshkey *key, } sig_r = sig_s = NULL; /* transferred */ - /* sha1 the data */ - if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, - digest, sizeof(digest))) != 0) + if ((slen = i2d_DSA_SIG(dsig, NULL)) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; - - switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { - case 1: - ret = 0; - break; - case 0: - ret = SSH_ERR_SIGNATURE_INVALID; + } + if ((sigb = malloc(slen)) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; goto out; - default: + } + psig = sigb; + if ((slen = i2d_DSA_SIG(dsig, &psig)) == 0) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) + goto out; + ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, dlen, + sigb, slen); + EVP_PKEY_free(pkey); + out: - explicit_bzero(digest, sizeof(digest)); + free(sigb); DSA_SIG_free(dsig); BN_clear_free(sig_r); BN_clear_free(sig_s); @@ -415,6 +430,65 @@ ssh_dss_verify(const struct sshkey *key, return ret; } +int +ssh_create_evp_dss(const struct sshkey *k, EVP_PKEY **pkey) +{ + OSSL_PARAM_BLD *param_bld = NULL; + EVP_PKEY_CTX *ctx = NULL; + const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub = NULL, *priv = NULL; + int ret = 0; + + if (k == NULL) + return SSH_ERR_INVALID_ARGUMENT; + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + + DSA_get0_pqg(k->dsa, &p, &q, &g); + DSA_get0_key(k->dsa, &pub, &priv); + + if (p != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (q != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (g != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (pub != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_PUB_KEY, + pub) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (priv != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_PRIV_KEY, + priv) != 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; +} + static const struct sshkey_impl_funcs sshkey_dss_funcs = { /* .size = */ ssh_dss_size, /* .alloc = */ ssh_dss_alloc, diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 341c32409bc..b705157befb 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include @@ -126,19 +128,29 @@ ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b, static int ssh_ecdsa_generate(struct sshkey *k, int bits) { - EC_KEY *private; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *res = NULL; if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) return SSH_ERR_KEY_LENGTH; - if ((private = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL) + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) return SSH_ERR_ALLOC_FAIL; - if (EC_KEY_generate_key(private) != 1) { - EC_KEY_free(private); + + 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; } - EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); - k->ecdsa = private; - return 0; + /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ + k->ecdsa = EVP_PKEY_get1_EC_KEY(res); + if (k->ecdsa) + EC_KEY_set_asn1_flag(k->ecdsa, OPENSSL_EC_NAMED_CURVE); + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(res); + return (k->ecdsa) ? 0 : SSH_ERR_LIBCRYPTO_ERROR; } static int @@ -228,11 +240,13 @@ ssh_ecdsa_sign(struct sshkey *key, const u_char *data, size_t dlen, const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) { + EVP_PKEY *pkey = NULL; 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; @@ -245,18 +259,33 @@ ssh_ecdsa_sign(struct sshkey *key, 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) + +#ifdef ENABLE_PKCS11 + if (is_ecdsa_pkcs11(key->ecdsa)) { + if ((pkey = EVP_PKEY_new()) == NULL || + EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) + return SSH_ERR_ALLOC_FAIL; + } else { +#endif + if ((ret = ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey)) != 0) + return ret; +#ifdef ENABLE_PKCS11 + } +#endif + ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, + dlen); + EVP_PKEY_free(pkey); + 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 +309,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); @@ -293,22 +322,21 @@ ssh_ecdsa_verify(const struct sshkey *key, const u_char *data, size_t dlen, const char *alg, u_int compat, struct sshkey_sig_details **detailsp) { + EVP_PKEY *pkey = NULL; 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 || 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 +372,33 @@ 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; + } + + if (ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey) != 0) + goto out; + ret = sshkey_verify_signature(pkey, hash_alg, data, dlen, sigb, len); + EVP_PKEY_free(pkey); + out: - explicit_bzero(digest, sizeof(digest)); + free(sigb); sshbuf_free(sigbuf); sshbuf_free(b); ECDSA_SIG_free(esig); @@ -375,6 +408,79 @@ ssh_ecdsa_verify(const struct sshkey *key, return ret; } +int +ssh_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) +{ + OSSL_PARAM_BLD *param_bld = NULL; + EVP_PKEY_CTX *ctx = NULL; + BN_CTX *bn_ctx = NULL; + uint8_t *pub_ser = NULL; + const char *group_name; + const EC_POINT *pub = NULL; + const BIGNUM *priv = NULL; + int ret = 0; + + if (k == NULL) + return SSH_ERR_INVALID_ARGUMENT; + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL || + (bn_ctx = BN_CTX_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 ((pub = EC_KEY_get0_public_key(k)) != NULL) { + const EC_GROUP *group; + size_t len; + + group = EC_KEY_get0_group(k); + len = EC_POINT_point2oct(group, pub, + POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); + if ((pub_ser = malloc(len)) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + EC_POINT_point2oct(group, + pub, + POINT_CONVERSION_UNCOMPRESSED, + pub_ser, + len, + bn_ctx); + if (OSSL_PARAM_BLD_push_octet_string(param_bld, + OSSL_PKEY_PARAM_PUB_KEY, + pub_ser, + len) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + } + if ((priv = EC_KEY_get0_private_key(k)) != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_PRIV_KEY, priv) != 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); + BN_CTX_free(bn_ctx); + free(pub_ser); + return ret; +} + /* NB. not static; used by ECDSA-SK */ const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { /* .size = */ ssh_ecdsa_size, diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 061b0681e43..f71f5078839 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -402,8 +402,36 @@ ecdsa_do_finish(EC_KEY *ec) if (helper->nrsa == 0 && helper->nec == 0) helper_terminate(helper); } + +int +is_ecdsa_pkcs11(EC_KEY *ecdsa) +{ + const EC_KEY_METHOD *meth; + ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, int dgstlen, + const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey) = NULL; + + meth = EC_KEY_get_method(ecdsa); + EC_KEY_METHOD_get_sign(meth, NULL, NULL, &sign_sig); + if (sign_sig == ecdsa_do_sign) + return 1; + return 0; +} #endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */ +int +is_rsa_pkcs11(RSA *rsa) +{ + const RSA_METHOD *meth; + int (*priv_enc)(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) = NULL; + + meth = RSA_get_method(rsa); + priv_enc = RSA_meth_get_priv_enc(meth); + if (priv_enc == rsa_encrypt) + return 1; + return 0; +} + /* redirect private key crypto operations to the ssh-pkcs11-helper */ static void wrap_key(struct helper *helper, struct sshkey *k) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 35e98be7230..fdf2548c7a7 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -620,6 +620,14 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, return (0); } + +int +is_ecdsa_pkcs11(EC_KEY *ecdsa) +{ + if (EC_KEY_get_ex_data(ecdsa, ec_key_idx) != NULL) + return 1; + return 0; +} #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ /* remove trailing spaces */ @@ -823,6 +831,14 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, } #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ +int +is_rsa_pkcs11(RSA *rsa) +{ + if (RSA_get_ex_data(rsa, rsa_idx) != NULL) + return 1; + return 0; +} + static struct sshkey * pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj) diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h index 81f1d7c5d39..620d1e314eb 100644 --- a/ssh-pkcs11.h +++ b/ssh-pkcs11.h @@ -35,6 +35,11 @@ struct sshkey * u_int32_t *); #endif +#ifdef HAVE_EC_KEY_METHOD_NEW +int is_ecdsa_pkcs11(EC_KEY *ecdsa); +#endif +int is_rsa_pkcs11(RSA *rsa); + #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) #undef ENABLE_PKCS11 #endif diff --git a/ssh-rsa.c b/ssh-rsa.c index be8f51e7576..88a98fd381f 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include @@ -36,7 +38,7 @@ #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) @@ -131,27 +133,50 @@ ssh_rsa_serialize_private(const struct sshkey *key, struct sshbuf *b, static int ssh_rsa_generate(struct sshkey *k, int bits) { - RSA *private = NULL; + 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 ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { + + 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 (!BN_set_word(f4, RSA_F4) || - !RSA_generate_key_ex(private, bits, f4, NULL)) { + + if (EVP_PKEY_keygen_init(ctx) <= 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) { + ret = SSH_ERR_KEY_LENGTH; + goto out; + } + + if (EVP_PKEY_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->rsa = EVP_PKEY_get1_RSA(res); + if (k->rsa) { + ret = 0; + } else { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - k->rsa = private; - private = NULL; - ret = 0; out: - RSA_free(private); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(res); BN_free(f4); return ret; } @@ -317,21 +342,6 @@ 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) { @@ -393,11 +403,10 @@ ssh_rsa_sign(struct sshkey *key, const u_char *data, size_t datalen, const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) { - const BIGNUM *rsa_n; - u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; - size_t slen = 0; - u_int hlen, len; - int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; + EVP_PKEY *pkey = NULL; + 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 +418,33 @@ 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 || sshkey_type_plain(key->type) != KEY_RSA) return SSH_ERR_INVALID_ARGUMENT; - RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); - if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) - return SSH_ERR_KEY_LENGTH; slen = RSA_size(key->rsa); - 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 (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) + return SSH_ERR_KEY_LENGTH; - if ((sig = malloc(slen)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; +#ifdef ENABLE_PKCS11 + if (is_rsa_pkcs11(key->rsa)) { + if ((pkey = EVP_PKEY_new()) == NULL || + EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) + return SSH_ERR_ALLOC_FAIL; + } else { +#endif + if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) + return ret; +#ifdef ENABLE_PKCS11 } - - if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; +#endif + ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, + datalen); + EVP_PKEY_free(pkey); + if (ret < 0) { goto out; } + if (len < slen) { size_t diff = slen - len; memmove(sig + diff, sig, len); @@ -444,6 +453,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 +474,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,10 +485,10 @@ 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; + EVP_PKEY *pkey = NULL; 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; @@ -487,8 +496,7 @@ ssh_rsa_verify(const struct sshkey *key, 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 (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) return SSH_ERR_KEY_LENGTH; if ((b = sshbuf_from(sig, siglen)) == NULL) @@ -540,16 +548,13 @@ 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) + + if ((ret = ssh_create_evp_rsa(key, &pkey)) != 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, pkey); + EVP_PKEY_free(pkey); + out: freezero(sigblob, len); free(sigtype); @@ -558,125 +563,110 @@ 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_get_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 = SSH_ERR_LIBCRYPTO_ERROR; - goto done; - } - if (len < 0 || (size_t)len != hlen + oidlen) { - ret = SSH_ERR_INVALID_FORMAT; - goto done; - } - oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; - hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; - if (!oidmatch || !hashmatch) { - ret = SSH_ERR_SIGNATURE_INVALID; - goto done; - } - ret = 0; + + ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, + sigbuf, siglen); + done: - freezero(decrypted, rsasize); return ret; } +int +ssh_create_evp_rsa(const struct sshkey *k, EVP_PKEY **pkey) +{ + OSSL_PARAM_BLD *param_bld = NULL; + EVP_PKEY_CTX *ctx = NULL; + int ret = 0; + const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; + const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; + + if (k == NULL) + return SSH_ERR_INVALID_ARGUMENT; + 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; + } + + RSA_get0_key(k->rsa, &n, &e, &d); + RSA_get0_factors(k->rsa, &p, &q); + RSA_get0_crt_params(k->rsa, &dmp1, &dmq1, &iqmp); + + 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 && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (d != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_D, d) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + /* setting this to param_build makes the creation process fail */ + if (p != NULL && + EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, p) != 1) { + debug2_f("failed to add 'p' param"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (q != NULL && + EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, q) != 1) { + debug2_f("failed to add 'q' param"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (dmp1 != NULL && + EVP_PKEY_set_bn_param(*pkey, + OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) != 1) { + debug2_f("failed to add 'dmp1' param"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (dmq1 != NULL && + EVP_PKEY_set_bn_param(*pkey, + OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) != 1) { + debug2_f("failed to add 'dmq1' param"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (iqmp != NULL && + EVP_PKEY_set_bn_param(*pkey, + OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp) != 1) { + debug2_f("failed to add 'iqmp' param"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + +out: + OSSL_PARAM_BLD_free(param_bld); + EVP_PKEY_CTX_free(ctx); + return ret; +} + static const struct sshkey_impl_funcs sshkey_rsa_funcs = { /* .size = */ ssh_rsa_size, /* .alloc = */ ssh_rsa_alloc, diff --git a/sshkey.c b/sshkey.c index 06db9b5da34..baef42cd5a5 100644 --- a/sshkey.c +++ b/sshkey.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #endif #include "crypto_api.h" @@ -477,6 +479,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_get_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) @@ -3704,3 +3786,27 @@ sshkey_set_filename(struct sshkey *k, const char *filename) return 0; } #endif /* WITH_XMSS */ + +#ifdef WITH_OPENSSL +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 /* WITH_OPENSSL */ diff --git a/sshkey.h b/sshkey.h index 708f2da8677..12eba8336bf 100644 --- a/sshkey.h +++ b/sshkey.h @@ -31,6 +31,9 @@ #ifdef WITH_OPENSSL #include #include +#include +#include +#include # ifdef OPENSSL_HAS_ECC # include # include @@ -266,6 +269,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 **); @@ -322,6 +329,13 @@ int sshkey_private_serialize_maxsign(struct sshkey *key, void sshkey_sig_details_free(struct sshkey_sig_details *); +#ifdef WITH_OPENSSL +EVP_PKEY *sshkey_create_evp(OSSL_PARAM_BLD *, EVP_PKEY_CTX *); +int ssh_create_evp_dss(const struct sshkey *, EVP_PKEY **); +int ssh_create_evp_rsa(const struct sshkey *, EVP_PKEY **); +int ssh_create_evp_ec(EC_KEY *, 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,6 +350,10 @@ 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 DSA From 760a5da77a0c6f6aa7b542bfd25e55675793041f Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 27 Sep 2023 11:46:01 +0200 Subject: [PATCH 02/21] Applying Fedora patch openssh-9.0p1-evp-fips-dh.patch --- dh.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++------- kex.c | 44 ++++++++++++++++++++++++++ kex.h | 5 +++ kexdh.c | 52 +++++++++++++++++++++++++++--- 4 files changed, 182 insertions(+), 17 deletions(-) diff --git a/dh.c b/dh.c index ce2eb4725e6..e64c249ade2 100644 --- a/dh.c +++ b/dh.c @@ -36,6 +36,9 @@ #include #include +#include +#include +#include #include "dh.h" #include "pathnames.h" @@ -283,10 +286,15 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) int dh_gen_key(DH *dh, int need) { - int pbits; - const BIGNUM *dh_p, *pub_key; + const BIGNUM *dh_p, *dh_g; + BIGNUM *pub_key = NULL, *priv_key = NULL; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM_BLD *param_bld = NULL; + OSSL_PARAM *params = NULL; + int pbits, r = 0; - DH_get0_pqg(dh, &dh_p, NULL, NULL); + DH_get0_pqg(dh, &dh_p, NULL, &dh_g); if (need < 0 || dh_p == NULL || (pbits = BN_num_bits(dh_p)) <= 0 || @@ -294,19 +302,85 @@ dh_gen_key(DH *dh, int need) return SSH_ERR_INVALID_ARGUMENT; if (need < 256) need = 256; + + if ((param_bld = OSSL_PARAM_BLD_new()) == NULL || + (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) { + OSSL_PARAM_BLD_free(param_bld); + return SSH_ERR_ALLOC_FAIL; + } + + if (OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) { + error_f("Could not set p,q,g parameters"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } /* * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), * so double requested need here. */ - if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1))) - return SSH_ERR_LIBCRYPTO_ERROR; - - if (DH_generate_key(dh) == 0) - return SSH_ERR_LIBCRYPTO_ERROR; - DH_get0_key(dh, &pub_key, NULL); - if (!dh_pub_is_valid(dh, pub_key)) - return SSH_ERR_INVALID_FORMAT; - return 0; + if (OSSL_PARAM_BLD_push_int(param_bld, + OSSL_PKEY_PARAM_DH_PRIV_LEN, + MINIMUM(need * 2, pbits - 1)) != 1 || + (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (EVP_PKEY_fromdata_init(ctx) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (EVP_PKEY_fromdata(ctx, &pkey, + EVP_PKEY_KEY_PARAMETERS, params) != 1) { + error_f("Failed key generation"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + /* reuse context for key generation */ + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + + if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || + EVP_PKEY_keygen_init(ctx) != 1) { + error_f("Could not create or init context"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (EVP_PKEY_generate(ctx, &pkey) != 1) { + error_f("Could not generate keys"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (EVP_PKEY_public_check(ctx) != 1) { + error_f("The public key is incorrect"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, + &pub_key) != 1 || + EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, + &priv_key) != 1 || + DH_set0_key(dh, pub_key, priv_key) != 1) { + error_f("Could not set pub/priv keys to DH struct"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + + /* transferred */ + pub_key = NULL; + priv_key = NULL; +out: + OSSL_PARAM_free(params); + OSSL_PARAM_BLD_free(param_bld); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + BN_clear_free(pub_key); + BN_clear_free(priv_key); + return r; } DH * diff --git a/kex.c b/kex.c index aa5e792ddc5..0e9368e53c8 100644 --- a/kex.c +++ b/kex.c @@ -1496,3 +1496,47 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms, return r; } +#ifdef WITH_OPENSSL +/* + * Creates an EVP_PKEY from the given parameters and keys. + * The private key can be omitted. + */ +int +kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, + const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) +{ + OSSL_PARAM_BLD *param_bld = NULL; + EVP_PKEY_CTX *ctx = NULL; + int r = 0; + + /* create EVP_PKEY-DH key */ + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { + error_f("Failed pushing params to OSSL_PARAM_BLD"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (priv != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { + error_f("Failed pushing private key to OSSL_PARAM_BLD"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) + r = SSH_ERR_LIBCRYPTO_ERROR; +out: + OSSL_PARAM_BLD_free(param_bld); + EVP_PKEY_CTX_free(ctx); + return r; +} +#endif /* WITH_OPENSSL */ diff --git a/kex.h b/kex.h index 5f7ef784eec..69210eb07f3 100644 --- a/kex.h +++ b/kex.h @@ -33,6 +33,9 @@ # include # include # include +# include +# include +# include # ifdef OPENSSL_HAS_ECC # include # else /* OPENSSL_HAS_ECC */ @@ -256,6 +259,8 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); +int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, + const BIGNUM *, const BIGNUM *, const BIGNUM *); #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) void dump_digest(const char *, const u_char *, int); diff --git a/kexdh.c b/kexdh.c index c1084f2146e..e49486b5df7 100644 --- a/kexdh.c +++ b/kexdh.c @@ -35,6 +35,10 @@ #include "openbsd-compat/openssl-compat.h" #include +#include +#include +#include +#include #include "sshkey.h" #include "kex.h" @@ -73,9 +77,12 @@ int kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) { BIGNUM *shared_secret = NULL; + const BIGNUM *pub, *priv, *p, *q, *g; + EVP_PKEY *pkey = NULL, *dh_pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; u_char *kbuf = NULL; size_t klen = 0; - int kout, r; + int kout, r = 0; #ifdef DEBUG_KEXDH fprintf(stderr, "dh_pub= "); @@ -90,24 +97,59 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) r = SSH_ERR_MESSAGE_INCOMPLETE; goto out; } - klen = DH_size(kex->dh); + + DH_get0_key(kex->dh, &pub, &priv); + DH_get0_pqg(kex->dh, &p, &q, &g); + /* import key */ + r = kex_create_evp_dh(&pkey, p, q, g, pub, priv); + if (r != 0) { + error_f("Could not create EVP_PKEY for dh"); + ERR_print_errors_fp(stderr); + goto out; + } + /* 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); + if (r != 0) { + error_f("Could not import peer key for dh"); + ERR_print_errors_fp(stderr); + goto out; + } + + if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) { + error_f("Could not init EVP_PKEY_CTX for dh"); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (EVP_PKEY_derive_init(ctx) != 1 || + EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || + EVP_PKEY_derive(ctx, NULL, &klen) != 1) { + error_f("Could not get key size"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } if ((kbuf = malloc(klen)) == NULL || (shared_secret = BN_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || - BN_bin2bn(kbuf, kout, shared_secret) == NULL) { + if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 || + BN_bin2bn(kbuf, klen, shared_secret) == NULL) { + error_f("Could not derive key"); r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } #ifdef DEBUG_KEXDH - dump_digest("shared secret", kbuf, kout); + dump_digest("shared secret", kbuf, klen); #endif r = sshbuf_put_bignum2(out, shared_secret); out: freezero(kbuf, klen); BN_clear_free(shared_secret); + EVP_PKEY_free(pkey); + EVP_PKEY_free(dh_pkey); + EVP_PKEY_CTX_free(ctx); return r; } From a09be89cfdf381d8fdf302557ac0e4c1fb818708 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 27 Sep 2023 11:47:38 +0200 Subject: [PATCH 03/21] Applying Fedora patch openssh-9.0p1-evp-fips-ecdh.patch --- kexecdh.c | 129 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 104 insertions(+), 25 deletions(-) diff --git a/kexecdh.c b/kexecdh.c index efb2e55a6d4..45559e9ff91 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -35,17 +35,57 @@ #include #include +#include +#include +#include +#include #include "sshkey.h" #include "kex.h" #include "sshbuf.h" #include "digest.h" #include "ssherr.h" +#include "log.h" static int kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, const EC_GROUP *, struct sshbuf **); +static EC_KEY * +generate_ec_keys(int ec_nid) +{ + EC_KEY *client_key = NULL; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + OSSL_PARAM_BLD *param_bld = NULL; + OSSL_PARAM *params = NULL; + const char *group_name; + + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL) + goto out; + if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL || + OSSL_PARAM_BLD_push_utf8_string(param_bld, + OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || + (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { + error_f("Could not create OSSL_PARAM"); + goto out; + } + if (EVP_PKEY_keygen_init(ctx) != 1 || + EVP_PKEY_CTX_set_params(ctx, params) != 1 || + EVP_PKEY_generate(ctx, &pkey) != 1 || + (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { + error_f("Could not generate ec keys"); + goto out; + } +out: + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + OSSL_PARAM_BLD_free(param_bld); + OSSL_PARAM_free(params); + return client_key; +} + int kex_ecdh_keypair(struct kex *kex) { @@ -55,11 +95,7 @@ kex_ecdh_keypair(struct kex *kex) struct sshbuf *buf = NULL; int r; - if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if (EC_KEY_generate_key(client_key) != 1) { + if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } @@ -101,11 +137,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, *server_blobp = NULL; *shared_secretp = NULL; - if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if (EC_KEY_generate_key(server_key) != 1) { + if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } @@ -140,11 +172,21 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, { struct sshbuf *buf = NULL; BIGNUM *shared_secret = NULL; - EC_POINT *dh_pub = NULL; - u_char *kbuf = NULL; - size_t klen = 0; + EVP_PKEY_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL, *dh_pkey = NULL; + OSSL_PARAM_BLD *param_bld = NULL; + OSSL_PARAM *params = NULL; + u_char *kbuf = NULL, *pub = NULL; + size_t klen = 0, publen; + const char *group_name; int r; + /* import EC_KEY to EVP_PKEY */ + if ((r = ssh_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) { + error_f("Could not create EVP_PKEY"); + goto out; + } + *shared_secretp = NULL; if ((buf = sshbuf_new()) == NULL) { @@ -153,45 +195,82 @@ 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 ((dh_pub = EC_POINT_new(group)) == NULL) { + + /* the public key is in the buffer in octet string UNCOMPRESSED + * format. See sshbuf_put_ec */ + if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) + goto out; + sshbuf_reset(buf); + if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { + if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (OSSL_PARAM_BLD_push_octet_string(param_bld, + OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 || + OSSL_PARAM_BLD_push_utf8_string(param_bld, + OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || + (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { + error_f("Failed to set params for dh_pkey"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (EVP_PKEY_fromdata_init(ctx) != 1 || + EVP_PKEY_fromdata(ctx, &dh_pkey, + EVP_PKEY_PUBLIC_KEY, params) != 1 || + EVP_PKEY_public_check(ctx) != 1) { + error_f("Peer public key import failed"); + r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - sshbuf_reset(buf); #ifdef DEBUG_KEXECDH fputs("public key:\n", stderr); - sshkey_dump_ec_point(group, dh_pub); + EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL); #endif - if (sshkey_ec_validate_public(group, dh_pub) != 0) { - r = SSH_ERR_MESSAGE_INCOMPLETE; + EVP_PKEY_CTX_free(ctx); + ctx = NULL; + if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || + EVP_PKEY_derive_init(ctx) != 1 || + EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || + EVP_PKEY_derive(ctx, NULL, &klen) != 1) { + error_f("Failed to get derive information"); + r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - klen = (EC_GROUP_get_degree(group) + 7) / 8; - if ((kbuf = malloc(klen)) == NULL || - (shared_secret = BN_new()) == NULL) { + if ((kbuf = malloc(klen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || - BN_bin2bn(kbuf, klen, shared_secret) == NULL) { + if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } #ifdef DEBUG_KEXECDH dump_digest("shared secret", kbuf, klen); #endif + if ((shared_secret = BN_new()) == NULL || + (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) goto out; *shared_secretp = buf; buf = NULL; out: - EC_POINT_clear_free(dh_pub); + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + EVP_PKEY_free(dh_pkey); + OSSL_PARAM_BLD_free(param_bld); + OSSL_PARAM_free(params); BN_clear_free(shared_secret); freezero(kbuf, klen); + freezero(pub, publen); sshbuf_free(buf); return r; } From 0b732c098da742d9352df7ab37ef9b2fcb02f5f1 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Mon, 2 Oct 2023 11:42:09 +0200 Subject: [PATCH 04/21] Using EVP_PKEY instead of RSA/EC_KEY in sshkey --- configure.ac | 2 +- kex.c | 4 +- kex.h | 19 +- kexecdh.c | 66 ++-- packet.c | 13 +- packet.h | 22 +- .../sshbuf/test_sshbuf_getput_crypto.c | 84 ++--- .../sshbuf/test_sshbuf_getput_fuzz.c | 9 - regress/unittests/sshkey/common.c | 34 +- regress/unittests/sshkey/common.h | 8 +- regress/unittests/sshkey/test_file.c | 19 +- regress/unittests/sshkey/test_sshkey.c | 56 ++- sk-usbhid.c | 4 +- ssh-ecdsa-sk.c | 39 +- ssh-ecdsa.c | 211 +++++------ ssh-keygen.c | 114 +++--- ssh-pkcs11-client.c | 56 ++- ssh-pkcs11-helper.c | 16 +- ssh-pkcs11.c | 83 ++++- ssh-rsa.c | 277 +++++++-------- ssh-sk.c | 34 +- sshbuf-getput-crypto.c | 105 ++---- sshbuf.h | 11 +- sshkey.c | 332 ++++++------------ sshkey.h | 42 +-- 25 files changed, 760 insertions(+), 900 deletions(-) diff --git a/configure.ac b/configure.ac index 0581a2c5a75..b253cf3e0fe 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org]) +AC_INIT([OpenSSH],[Portable],[openssh-unix-dev@mindrot.org]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([ssh.c]) diff --git a/kex.c b/kex.c index 0e9368e53c8..882d9183fc6 100644 --- a/kex.c +++ b/kex.c @@ -784,9 +784,7 @@ kex_free(struct kex *kex) #ifdef WITH_OPENSSL DH_free(kex->dh); -#ifdef OPENSSL_HAS_ECC - EC_KEY_free(kex->ec_client_key); -#endif /* OPENSSL_HAS_ECC */ + EVP_PKEY_free(kex->pkey); #endif /* WITH_OPENSSL */ for (mode = 0; mode < MODE_MAX; mode++) { kex_free_newkeys(kex->newkeys[mode]); diff --git a/kex.h b/kex.h index 69210eb07f3..46852c8f207 100644 --- a/kex.h +++ b/kex.h @@ -36,19 +36,9 @@ # include # include # 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 */ #else /* WITH_OPENSSL */ # define DH void # define BIGNUM void -# define EC_KEY void -# define EC_GROUP void -# define EC_POINT void #endif /* WITH_OPENSSL */ #define KEX_COOKIE_LEN 16 @@ -174,8 +164,7 @@ struct kex { /* kex specific state */ DH *dh; /* DH */ u_int min, max, nbits; /* GEX */ - EC_KEY *ec_client_key; /* ECDH */ - const EC_GROUP *ec_group; /* ECDH */ + EVP_PKEY *pkey; u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 + KEM */ u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */ u_char sntrup761_client_key[crypto_kem_sntrup761_SECRETKEYBYTES]; /* KEM */ @@ -266,10 +255,4 @@ int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, void dump_digest(const char *, const u_char *, int); #endif -#if !defined(WITH_OPENSSL) || !defined(OPENSSL_HAS_ECC) -# undef EC_KEY -# undef EC_GROUP -# undef EC_POINT -#endif - #endif diff --git a/kexecdh.c b/kexecdh.c index 45559e9ff91..62f3f8f6ec7 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -34,7 +34,6 @@ #include #include -#include #include #include #include @@ -48,13 +47,12 @@ #include "log.h" static int -kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, - const EC_GROUP *, struct sshbuf **); +kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, + EVP_PKEY *pkey, struct sshbuf **shared_secretp); -static EC_KEY * +static EVP_PKEY * generate_ec_keys(int ec_nid) { - EC_KEY *client_key = NULL; EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; OSSL_PARAM_BLD *param_bld = NULL; @@ -73,25 +71,21 @@ generate_ec_keys(int ec_nid) } if (EVP_PKEY_keygen_init(ctx) != 1 || EVP_PKEY_CTX_set_params(ctx, params) != 1 || - EVP_PKEY_generate(ctx, &pkey) != 1 || - (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { + EVP_PKEY_generate(ctx, &pkey) != 1) { error_f("Could not generate ec keys"); goto out; } out: - EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(ctx); OSSL_PARAM_BLD_free(param_bld); OSSL_PARAM_free(params); - return client_key; + return pkey; } int kex_ecdh_keypair(struct kex *kex) { - EC_KEY *client_key = NULL; - const EC_GROUP *group; - const EC_POINT *public_key; + EVP_PKEY *client_key = NULL; struct sshbuf *buf = NULL; int r; @@ -99,27 +93,24 @@ kex_ecdh_keypair(struct kex *kex) r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - group = EC_KEY_get0_group(client_key); - public_key = EC_KEY_get0_public_key(client_key); if ((buf = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 || + if ((r = sshbuf_put_ec(buf, client_key)) != 0 || (r = sshbuf_get_u32(buf, NULL)) != 0) goto out; #ifdef DEBUG_KEXECDH fputs("client private key:\n", stderr); sshkey_dump_ec_key(client_key); #endif - kex->ec_client_key = client_key; - kex->ec_group = group; + kex->pkey = client_key; client_key = NULL; /* owned by the kex */ kex->client_pub = buf; buf = NULL; - out: - EC_KEY_free(client_key); +out: + EVP_PKEY_free(client_key); sshbuf_free(buf); return r; } @@ -128,9 +119,7 @@ int kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, struct sshbuf **server_blobp, struct sshbuf **shared_secretp) { - const EC_GROUP *group; - const EC_POINT *pub_key; - EC_KEY *server_key = NULL; + EVP_PKEY *server_key = NULL; struct sshbuf *server_blob = NULL; int r; @@ -141,39 +130,37 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - group = EC_KEY_get0_group(server_key); #ifdef DEBUG_KEXECDH fputs("server private key:\n", stderr); sshkey_dump_ec_key(server_key); #endif - pub_key = EC_KEY_get0_public_key(server_key); if ((server_blob = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_put_ec(server_blob, pub_key, group)) != 0 || + if ((r = sshbuf_put_ec(server_blob, server_key)) != 0 || (r = sshbuf_get_u32(server_blob, NULL)) != 0) goto out; - if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group, + if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, shared_secretp)) != 0) goto out; *server_blobp = server_blob; server_blob = NULL; - out: - EC_KEY_free(server_key); +out: + EVP_PKEY_free(server_key); sshbuf_free(server_blob); return r; } static int kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, - EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp) + EVP_PKEY *pkey, struct sshbuf **shared_secretp) { struct sshbuf *buf = NULL; BIGNUM *shared_secret = NULL; EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *pkey = NULL, *dh_pkey = NULL; + EVP_PKEY *dh_pkey = NULL; OSSL_PARAM_BLD *param_bld = NULL; OSSL_PARAM *params = NULL; u_char *kbuf = NULL, *pub = NULL; @@ -181,12 +168,6 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, const char *group_name; int r; - /* import EC_KEY to EVP_PKEY */ - if ((r = ssh_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) { - error_f("Could not create EVP_PKEY"); - goto out; - } - *shared_secretp = NULL; if ((buf = sshbuf_new()) == NULL) { @@ -196,9 +177,7 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) goto out; - /* the public key is in the buffer in octet string UNCOMPRESSED - * format. See sshbuf_put_ec */ - if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) + if ((r = sshbuf_get_ec(buf, &pub, &publen)) != 0) goto out; sshbuf_reset(buf); if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || @@ -264,7 +243,6 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, buf = NULL; out: EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(pkey); EVP_PKEY_free(dh_pkey); OSSL_PARAM_BLD_free(param_bld); OSSL_PARAM_free(params); @@ -281,10 +259,10 @@ kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob, { int r; - r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key, - kex->ec_group, shared_secretp); - EC_KEY_free(kex->ec_client_key); - kex->ec_client_key = NULL; + r = kex_ecdh_dec_key_group(kex, server_blob, kex->pkey, + shared_secretp); + EVP_PKEY_free(kex->pkey); + kex->pkey = NULL; return r; } diff --git a/packet.c b/packet.c index 52017defb64..3e102fbfc99 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_ec(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_ec(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..16670beaf4a 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,7 @@ 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); +int sshpkt_put_ec(struct ssh *ssh, EVP_PKEY *pkey); int sshpkt_put_bignum2(struct ssh *ssh, const BIGNUM *v); int sshpkt_get(struct ssh *ssh, void *valp, size_t len); @@ -204,7 +195,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 +203,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..ef348c67617 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c @@ -17,11 +17,12 @@ #include #include +#include #include #include -#ifdef OPENSSL_HAS_NISTP256 -# include -#endif +#include +#include +#include #include "../test_helper/test_helper.h" #include "ssherr.h" @@ -51,6 +52,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 +68,13 @@ sshbuf_getput_crypto_tests(void) 0xc8, 0xf9, 0xa3, 0x5e, 0x42, 0xbd, 0xd0, 0x47, 0x55, 0x0f, 0x69, 0xd8, 0x0e, 0xc2, 0x3c, 0xd4 }; - EC_KEY *eck; + 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; EC_POINT *ecp; #endif int r; @@ -224,55 +232,47 @@ sshbuf_getput_crypto_tests(void) #if defined(OPENSSL_HAS_ECC) && defined(OPENSSL_HAS_NISTP256) TEST_START("sshbuf_put_ec"); - 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); + 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); MKBN(ec256_x, bn_x); MKBN(ec256_y, bn_y); - 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); + 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); + 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); EC_POINT_free(ecp); + 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); p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); - ASSERT_INT_EQ(sshbuf_put_eckey(p1, eck), 0); + ASSERT_INT_EQ(sshbuf_put_ec(p1, eck), 0); 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); - EC_KEY_free(eck); - TEST_DONE(); - - 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); + EVP_PKEY_free(eck); TEST_DONE(); #endif } 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..c85fe646f91 100644 --- a/regress/unittests/sshkey/common.c +++ b/regress/unittests/sshkey/common.c @@ -20,7 +20,7 @@ #ifdef WITH_OPENSSL #include -#include +#include #include #include #ifdef OPENSSL_HAS_NISTP256 @@ -83,47 +83,47 @@ load_bignum(const char *name) return ret; } -const BIGNUM * +BIGNUM * rsa_n(struct sshkey *k) { - const BIGNUM *n = NULL; + BIGNUM *n = NULL; 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); + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_N, &n); return n; } -const BIGNUM * +BIGNUM * rsa_e(struct sshkey *k) { - const BIGNUM *e = NULL; + BIGNUM *e = NULL; 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); + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_E, &e); return e; } -const BIGNUM * +BIGNUM * rsa_p(struct sshkey *k) { - const BIGNUM *p = NULL; + BIGNUM *p = NULL; ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->rsa, NULL); - RSA_get0_factors(k->rsa, &p, NULL); + ASSERT_PTR_NE(k->pkey, NULL); + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &p); return p; } -const BIGNUM * +BIGNUM * rsa_q(struct sshkey *k) { - const BIGNUM *q = NULL; + BIGNUM *q = NULL; ASSERT_PTR_NE(k, NULL); - ASSERT_PTR_NE(k->rsa, NULL); - RSA_get0_factors(k->rsa, NULL, &q); + ASSERT_PTR_NE(k->pkey, NULL); + EVP_PKEY_get_bn_param(k->pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &q); return q; } 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..2c5a0dd73e5 100644 --- a/regress/unittests/sshkey/test_file.c +++ b/regress/unittests/sshkey/test_file.c @@ -47,6 +47,8 @@ sshkey_file_tests(void) struct sshbuf *buf, *pw; #ifdef WITH_OPENSSL BIGNUM *a, *b, *c; + u_char *pubkey = NULL; + size_t pubkey_len; #endif char *cp; @@ -269,12 +271,21 @@ 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, - NULL, NULL); + 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(); ASSERT_PTR_NE(c, NULL); - ASSERT_BIGNUM_EQ(EC_KEY_get0_private_key(k1->ecdsa), a); + ASSERT_PTR_NE(BN_bin2bn(pubkey, pubkey_len, c), NULL); ASSERT_BIGNUM_EQ(b, c); + 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); 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..a9dd9796f0a 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,13 @@ 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); + 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); TEST_DONE(); #endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ @@ -306,10 +317,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 +355,13 @@ 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); + 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); 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..484621cdbd8 100644 --- a/ssh-ecdsa-sk.c +++ b/ssh-ecdsa-sk.c @@ -33,7 +33,6 @@ #ifdef WITH_OPENSSL #include -#include #include #include #endif @@ -237,11 +236,13 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, struct sshkey_sig_details **detailsp) { ECDSA_SIG *esig = NULL; + EVP_MD_CTX *md_ctx = NULL; BIGNUM *sig_r = NULL, *sig_s = NULL; u_char sig_flags; - u_char msghash[32], apphash[32], sighash[32]; + u_char msghash[32], apphash[32]; u_int sig_counter; - int is_webauthn = 0, ret = SSH_ERR_INTERNAL_ERROR; + u_char *sigb = NULL, *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 +253,7 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, if (detailsp != NULL) *detailsp = NULL; - if (key == NULL || key->ecdsa == NULL || + if (key == NULL || key->pkey == NULL || sshkey_type_plain(key->type) != KEY_ECDSA_SK || sig == NULL || siglen == 0) return SSH_ERR_INVALID_ARGUMENT; @@ -363,21 +364,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)) { + if ((len = i2d_ECDSA_SIG(esig, NULL)) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((sigb = malloc(len)) == NULL || + (md_ctx = EVP_MD_CTX_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + psig = sigb; + if ((len = i2d_ECDSA_SIG(esig, &psig)) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (EVP_DigestVerifyInit(md_ctx, NULL, EVP_sha256(), NULL, + key->pkey) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + switch(EVP_DigestVerify(md_ctx, sigb, len, sshbuf_ptr(original_signed), sshbuf_len(original_signed))) { case 1: ret = 0; break; @@ -397,7 +411,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 +423,8 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, BN_clear_free(sig_r); BN_clear_free(sig_s); free(ktype); + free(sigb); + EVP_MD_CTX_free(md_ctx); return ret; } diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index b705157befb..65418f1b8f6 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include @@ -67,30 +66,18 @@ 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; + /* FIXME OpenSSL 1.1.1 */ + if (EVP_PKEY_eq(a->pkey, b->pkey) == 1) + return 1; - 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; - - return 1; + return 0; } static int @@ -99,11 +86,11 @@ ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b, { int r; - if (key->ecdsa == NULL) + if (key->pkey == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((r = sshbuf_put_cstring(b, sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || - (r = sshbuf_put_eckey(b, key->ecdsa)) != 0) + (r = sshbuf_put_ec(b, key->pkey)) != 0) return r; return 0; @@ -114,14 +101,20 @@ ssh_ecdsa_serialize_private(const struct sshkey *key, struct sshbuf *b, enum sshkey_serialize_rep opts) { int r; + BIGNUM *priv = NULL; 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) - 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); + return r; + } + + BN_clear_free(priv); return 0; } @@ -143,26 +136,43 @@ ssh_ecdsa_generate(struct sshkey *k, int bits) EVP_PKEY_free(res); return SSH_ERR_LIBCRYPTO_ERROR; } - /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ - k->ecdsa = EVP_PKEY_get1_EC_KEY(res); - if (k->ecdsa) - EC_KEY_set_asn1_flag(k->ecdsa, OPENSSL_EC_NAMED_CURVE); - - EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(res); - return (k->ecdsa) ? 0 : SSH_ERR_LIBCRYPTO_ERROR; + + k->pkey = res; + 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; + } static int @@ -171,6 +181,9 @@ ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b, { int r; char *curve = NULL; + unsigned char *pub = NULL; + size_t publen = 0; + EVP_PKEY *pkey = NULL; if ((key->ecdsa_nid = sshkey_ecdsa_nid_from_name(ktype)) == -1) return SSH_ERR_INVALID_ARGUMENT; @@ -180,30 +193,29 @@ 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 ((r = sshbuf_get_ec(b, &pub, &publen)) != 0) /*XXX*/ 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; - } + 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; } @@ -214,6 +226,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) @@ -221,16 +234,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 ((r = sshkey_ec_validate_private(key->ecdsa)) != 0) + if (EC_KEY_set_private_key(ec, exponent) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +#if 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; } @@ -240,7 +265,6 @@ ssh_ecdsa_sign(struct sshkey *key, const u_char *data, size_t dlen, const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) { - EVP_PKEY *pkey = NULL; ECDSA_SIG *esig = NULL; unsigned char *sigb = NULL; const unsigned char *psig; @@ -255,28 +279,15 @@ 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) return SSH_ERR_INTERNAL_ERROR; -#ifdef ENABLE_PKCS11 - if (is_ecdsa_pkcs11(key->ecdsa)) { - if ((pkey = EVP_PKEY_new()) == NULL || - EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) - return SSH_ERR_ALLOC_FAIL; - } else { -#endif - if ((ret = ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey)) != 0) - return ret; -#ifdef ENABLE_PKCS11 - } -#endif - ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, + ret = sshkey_calculate_signature(key->pkey, hash_alg, &sigb, &len, data, dlen); - EVP_PKEY_free(pkey); if (ret < 0) { goto out; } @@ -322,7 +333,6 @@ ssh_ecdsa_verify(const struct sshkey *key, const u_char *data, size_t dlen, const char *alg, u_int compat, struct sshkey_sig_details **detailsp) { - EVP_PKEY *pkey = NULL; ECDSA_SIG *esig = NULL; BIGNUM *sig_r = NULL, *sig_s = NULL; int hash_alg, len; @@ -331,7 +341,7 @@ ssh_ecdsa_verify(const struct sshkey *key, 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; @@ -392,11 +402,7 @@ ssh_ecdsa_verify(const struct sshkey *key, goto out; } - if (ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey) != 0) - goto out; - ret = sshkey_verify_signature(pkey, hash_alg, data, dlen, sigb, len); - EVP_PKEY_free(pkey); - + ret = sshkey_verify_signature(key->pkey, hash_alg, data, dlen, sigb, len); out: free(sigb); sshbuf_free(sigbuf); @@ -409,22 +415,16 @@ ssh_ecdsa_verify(const struct sshkey *key, } int -ssh_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) +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; - BN_CTX *bn_ctx = NULL; - uint8_t *pub_ser = NULL; const char *group_name; - const EC_POINT *pub = NULL; - const BIGNUM *priv = NULL; int ret = 0; - if (k == NULL) - return SSH_ERR_INVALID_ARGUMENT; if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || - (param_bld = OSSL_PARAM_BLD_new()) == NULL || - (bn_ctx = BN_CTX_new()) == NULL) { + (param_bld = OSSL_PARAM_BLD_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } @@ -437,37 +437,20 @@ ssh_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - if ((pub = EC_KEY_get0_public_key(k)) != NULL) { - const EC_GROUP *group; - size_t len; - - group = EC_KEY_get0_group(k); - len = EC_POINT_point2oct(group, pub, - POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); - if ((pub_ser = malloc(len)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - EC_POINT_point2oct(group, - pub, - POINT_CONVERSION_UNCOMPRESSED, - pub_ser, - len, - bn_ctx); - if (OSSL_PARAM_BLD_push_octet_string(param_bld, - OSSL_PKEY_PARAM_PUB_KEY, - pub_ser, - len) != 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 ((priv = EC_KEY_get0_private_key(k)) != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { + 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; @@ -476,8 +459,6 @@ ssh_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) out: OSSL_PARAM_BLD_free(param_bld); EVP_PKEY_CTX_free(ctx); - BN_CTX_free(bn_ctx); - free(pub_ser); return ret; } diff --git a/ssh-keygen.c b/ssh-keygen.c index 5b945a84920..4d7b327fe77 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -22,6 +22,8 @@ #include #include #include "openbsd-compat/openssl-compat.h" +#include +#include #endif #ifdef HAVE_STDINT_H @@ -373,19 +375,24 @@ 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"); + case KEY_ECDSA: + OSSL_ENCODER_CTX *ctx = OSSL_ENCODER_CTX_new_for_pkey(k->pkey, + EVP_PKEY_PUBLIC_KEY, + "PEM", + "type-specific", + 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"); 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: fatal_f("unsupported key type %s", sshkey_type(k)); } @@ -397,19 +404,23 @@ do_convert_to_pem(struct sshkey *k) { switch (sshkey_type_plain(k->type)) { 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"); 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: fatal_f("unsupported key type %s", sshkey_type(k)); } @@ -482,6 +493,7 @@ 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; if ((r = sshbuf_get_u32(b, &magic)) != 0) fatal_fr(r, "parse magic"); @@ -572,14 +584,21 @@ 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)) - fatal_f("RSA_set0_key failed"); - rsa_n = rsa_e = rsa_d = NULL; /* transferred */ - if (!RSA_set0_factors(key->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) + 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"); + 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"); + 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 +706,28 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) { EVP_PKEY *pubkey; FILE *fp; + OSSL_DECODER_CTX *ctx; if ((fp = fopen(identity_file, "r")) == NULL) fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); - if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { + 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); + identity_file); } + OSSL_DECODER_CTX_free(ctx); 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) @@ -708,15 +735,14 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) (*k)->type = KEY_DSA; (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); break; -#ifdef OPENSSL_HAS_ECC case EVP_PKEY_EC: 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: fatal_f("unsupported pubkey type %d", EVP_PKEY_base_id(pubkey)); @@ -729,15 +755,20 @@ static void do_convert_from_pem(struct sshkey **k, int *private) { FILE *fp; - RSA *rsa; + EVP_PKEY *pkey = NULL; + OSSL_DECODER_CTX *ctx; 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) { + 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)->rsa = rsa; + (*k)->pkey = pkey; fclose(fp); return; } @@ -750,6 +781,7 @@ 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"); @@ -781,15 +813,17 @@ do_convert_from(struct passwd *pw) ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL); break; -#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: - ok = PEM_write_ECPrivateKey(stdout, k->ecdsa, NULL, - NULL, 0, NULL, NULL); - break; -#endif case KEY_RSA: - ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, - NULL, 0, NULL, NULL); + 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; default: fatal_f("unsupported key type %s", sshkey_type(k)); diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index f71f5078839..41269a63e76 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"); @@ -438,14 +466,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 fdf2548c7a7..3693da82a80 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -796,12 +796,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; @@ -810,12 +804,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++) @@ -915,10 +930,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++) @@ -1030,10 +1057,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) { @@ -1045,7 +1084,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; @@ -1060,11 +1099,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 88a98fd381f..3ab752d8556 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -41,20 +41,17 @@ 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 (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; } @@ -62,29 +59,18 @@ 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; + /* FIXME OpenSSL 1.1.1 */ + if (EVP_PKEY_eq(a->pkey, b->pkey) == 1) + return 1; - 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; + return 0; } static int @@ -93,10 +79,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; @@ -110,10 +102,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 = EVP_PKEY_get0_RSA(key->pkey); + if (rsa == NULL) + return SSH_ERR_LIBCRYPTO_ERROR; - 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_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 */ @@ -167,8 +164,8 @@ ssh_rsa_generate(struct sshkey *k, int bits) } /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ - k->rsa = EVP_PKEY_get1_RSA(res); - if (k->rsa) { + k->pkey = res; + if (k->pkey) { ret = 0; } else { ret = SSH_ERR_LIBCRYPTO_ERROR; @@ -176,7 +173,6 @@ ssh_rsa_generate(struct sshkey *k, int bits) } out: EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(res); BN_free(f4); return ret; } @@ -187,21 +183,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; @@ -213,25 +225,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; @@ -244,13 +266,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; } @@ -261,33 +292,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; } @@ -343,29 +387,21 @@ rsa_hash_id_from_keyname(const char *alg) } 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; } @@ -373,25 +409,17 @@ ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) BN_set_flags(d_consttime, BN_FLG_CONSTTIME); if ((BN_sub(aux, rsa_q, BN_value_one()) == 0) || - (BN_mod(rsa_dmq1, d_consttime, aux, ctx) == 0) || + (BN_mod(*rsa_dmq1, d_consttime, aux, ctx) == 0) || (BN_sub(aux, rsa_p, BN_value_one()) == 0) || - (BN_mod(rsa_dmp1, d_consttime, aux, ctx) == 0)) { + (BN_mod(*rsa_dmp1, d_consttime, aux, ctx) == 0)) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - if (!RSA_set0_crt_params(key->rsa, rsa_dmp1, rsa_dmq1, rsa_iqmp)) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - rsa_dmp1 = rsa_dmq1 = rsa_iqmp = NULL; /* transferred */ /* success */ r = 0; out: BN_clear_free(aux); BN_clear_free(d_consttime); - BN_clear_free(rsa_dmp1); - BN_clear_free(rsa_dmq1); - BN_clear_free(rsa_iqmp); BN_CTX_free(ctx); return r; } @@ -403,7 +431,6 @@ 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) { - EVP_PKEY *pkey = NULL; u_char *sig = NULL; int len, slen = 0; int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; @@ -419,28 +446,15 @@ ssh_rsa_sign(struct sshkey *key, 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; - slen = RSA_size(key->rsa); - if (RSA_bits(key->rsa) < 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; -#ifdef ENABLE_PKCS11 - if (is_rsa_pkcs11(key->rsa)) { - if ((pkey = EVP_PKEY_new()) == NULL || - EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) - return SSH_ERR_ALLOC_FAIL; - } else { -#endif - if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) - return ret; -#ifdef ENABLE_PKCS11 - } -#endif - ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, + ret = sshkey_calculate_signature(key->pkey, hash_alg, &sig, &len, data, datalen); - EVP_PKEY_free(pkey); if (ret < 0) { goto out; } @@ -485,18 +499,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) { - EVP_PKEY *pkey = NULL; char *sigtype = NULL; int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; 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; - if (RSA_bits(key->rsa) < 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) @@ -532,7 +545,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; @@ -549,11 +562,8 @@ ssh_rsa_verify(const struct sshkey *key, len = modlen; } - if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) - goto out; - - ret = openssh_RSA_verify(hash_alg, data, dlen, sigblob, len, pkey); - EVP_PKEY_free(pkey); + ret = openssh_RSA_verify(hash_alg, data, dlen, sigblob, len, + key->pkey); out: freezero(sigblob, len); @@ -585,82 +595,67 @@ openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, } int -ssh_create_evp_rsa(const struct sshkey *k, EVP_PKEY **pkey) +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; - const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; - const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; - - if (k == NULL) - return SSH_ERR_INVALID_ARGUMENT; 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; } - RSA_get0_key(k->rsa, &n, &e, &d); - RSA_get0_factors(k->rsa, &p, &q); - RSA_get0_crt_params(k->rsa, &dmp1, &dmq1, &iqmp); - 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 && - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e) != 1) { + if (e != NULL) { + if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e) != 1) { ret = SSH_ERR_LIBCRYPTO_ERROR; 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; + } + } 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; + } + } if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - /* setting this to param_build makes the creation process fail */ - if (p != NULL && - EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, p) != 1) { - debug2_f("failed to add 'p' param"); - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (q != NULL && - EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, q) != 1) { - debug2_f("failed to add 'q' param"); - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (dmp1 != NULL && - EVP_PKEY_set_bn_param(*pkey, - OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) != 1) { - debug2_f("failed to add 'dmp1' param"); - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (dmq1 != NULL && - EVP_PKEY_set_bn_param(*pkey, - OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) != 1) { - debug2_f("failed to add 'dmq1' param"); - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (iqmp != NULL && - EVP_PKEY_set_bn_param(*pkey, - OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp) != 1) { - debug2_f("failed to add 'iqmp' param"); - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - out: OSSL_PARAM_BLD_free(param_bld); EVP_PKEY_CTX_free(ctx); diff --git a/ssh-sk.c b/ssh-sk.c index d1c18803ff8..8e73abf1565 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,7 +206,7 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp) { struct sshkey *key = NULL; struct sshbuf *b = NULL; - EC_POINT *q = NULL; + EVP_PKEY_CTX *ctx = NULL; int r; *keyp = NULL; @@ -217,42 +216,25 @@ 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 || - (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"); + 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 ((r = sshbuf_get_ec(b, q, EC_KEY_get0_group(key->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) { - error("Authenticator returned invalid ECDSA key"); + if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, key->pkey, NULL)) + == NULL || + EVP_PKEY_public_check(ctx) != 1) { r = SSH_ERR_KEY_INVALID_EC_VALUE; goto out; } - if (EC_KEY_set_public_key(key->ecdsa, q) != 1) { - /* XXX assume it is a allocation error */ - error_f("allocation failed"); - r = SSH_ERR_ALLOC_FAIL; - goto out; - } /* success */ *keyp = key; key = NULL; /* transferred */ r = 0; out: - EC_POINT_free(q); sshkey_free(key); sshbuf_free(b); + EVP_PKEY_CTX_free(ctx); return r; } #endif /* WITH_OPENSSL */ diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c index 56ffdd86156..38addf6b67f 100644 --- a/sshbuf-getput-crypto.c +++ b/sshbuf-getput-crypto.c @@ -25,9 +25,9 @@ #ifdef WITH_OPENSSL #include -#ifdef OPENSSL_HAS_ECC -# include -#endif /* OPENSSL_HAS_ECC */ +#include +#include +#include #include "ssherr.h" #include "sshbuf.h" @@ -55,78 +55,14 @@ 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, EC_POINT *v, const EC_GROUP *g) +sshbuf_get_ec(struct sshbuf *buf, u_char **pub, size_t *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; + /* the public key is in the buffer in octet string UNCOMPRESSED + * format. See sshbuf_put_ec */ + return sshbuf_get_string(buf, pub, publen); } -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) { @@ -151,7 +87,7 @@ sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) #ifdef OPENSSL_HAS_ECC int -sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) +sshbuf_put_ecbuf(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) { u_char d[SSHBUF_MAX_ECPOINT]; size_t len; @@ -171,10 +107,29 @@ 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_ec(struct sshbuf *buf, EVP_PKEY *pkey) { - return sshbuf_put_ec(buf, EC_KEY_get0_public_key(v), - EC_KEY_get0_group(v)); + u_char d[SSHBUF_MAX_ECPOINT]; + size_t len; + int ret; + const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); + + if (ec == NULL) + return SSH_ERR_LIBCRYPTO_ERROR; + + return sshbuf_put_ecbuf(buf, EC_KEY_get0_public_key(ec), + EC_KEY_get0_group(ec)); +/* FIXME beldmit */ +#if 0 + /* 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..7260cba350d 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -23,9 +23,6 @@ #include #ifdef WITH_OPENSSL # include -# ifdef OPENSSL_HAS_ECC -# include -# endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ #define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */ @@ -218,12 +215,8 @@ 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); -# 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_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 */ +int sshbuf_get_ec(struct sshbuf *buf, u_char **pub, size_t *publen); +int sshbuf_put_ec(struct sshbuf *buf, EVP_PKEY *pkey); #endif /* WITH_OPENSSL */ /* Dump the contents of the buffer in a human-readable format */ diff --git a/sshkey.c b/sshkey.c index baef42cd5a5..6d5182968ba 100644 --- a/sshkey.c +++ b/sshkey.c @@ -36,7 +36,9 @@ #include #include #include +#include #endif +#endif /* WITH_OPENSSL */ #include "crypto_api.h" @@ -1409,14 +1411,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_get_bits(k->pkey); if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE || (min_size > 0 && nbits < min_size)) return SSH_ERR_KEY_LENGTH; @@ -1427,50 +1427,25 @@ 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) +sshkey_ecdsa_key_to_nid(EVP_PKEY *pkey) { - EC_GROUP *eg; - int nids[] = { - NID_X9_62_prime256v1, - NID_secp384r1, -# ifdef OPENSSL_HAS_NISTP521 - NID_secp521r1, -# endif /* OPENSSL_HAS_NISTP521 */ - -1 - }; + /* FIXME OpenSSL 1.1.1*/ + char group_name[64] = {0}; int nid; - u_int i; - const EC_GROUP *g = EC_KEY_get0_group(k); - - /* - * The group may be stored in a ASN.1 encoded private key in one of two - * ways: as a "named group", which is reconstituted by ASN.1 object ID - * or explicit group parameters encoded into the key blob. Only the - * "named group" case sets the group NID for us, but we can figure - * it out for the other case by comparing against all the groups that - * are supported. - */ - if ((nid = EC_GROUP_get_curve_name(g)) > 0) - return nid; - for (i = 0; nids[i] != -1; i++) { - if ((eg = EC_GROUP_new_by_curve_name(nids[i])) == NULL) - return -1; - if (EC_GROUP_cmp(g, eg, NULL) == 0) - break; - EC_GROUP_free(eg); - } - if (nids[i] != -1) { - /* Use the group with the NID attached */ - EC_GROUP_set_asn1_flag(eg, OPENSSL_EC_NAMED_CURVE); - if (EC_KEY_set_group(k, eg) != 1) { - EC_GROUP_free(eg); - return -1; - } - } - return nids[i]; + if (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; } # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ + OSSL_PARAM *params = NULL; + EVP_PKEY_CTX *ctx = NULL; int sshkey_generate(int type, u_int bits, struct sshkey **keyp) @@ -1686,6 +1661,8 @@ sshkey_shield_private(struct sshkey *k) fprintf(stderr, "%s: encrypted\n", __func__); sshbuf_dump_data(enc, enclen, stderr); #endif + OSSL_PARAM_free(params); + EVP_PKEY_CTX_free(ctx); /* Make a scrubbed, public-only copy of our private key argument */ if ((r = sshkey_from_private(k, &kswap)) != 0) @@ -2659,169 +2636,10 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) sshkey_free(k); free(expect_sk_application); free(expect_ed25519_pk); + EVP_PKEY_CTX_free(ctx); return r; } -#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) -int -sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) -{ - EC_POINT *nq = NULL; - BIGNUM *order = NULL, *x = NULL, *y = NULL, *tmp = NULL; - int ret = SSH_ERR_KEY_INVALID_EC_VALUE; - - /* - * NB. This assumes OpenSSL has already verified that the public - * point lies on the curve. This is done by EC_POINT_oct2point() - * implicitly calling EC_POINT_is_on_curve(). If this code is ever - * reachable with public points not unmarshalled using - * EC_POINT_oct2point then the caller will need to explicitly check. - */ - - /* - * We shouldn't ever hit this case because bignum_get_ecpoint() - * refuses to load GF2m points. - */ - if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != - NID_X9_62_prime_field) - goto out; - - /* Q != infinity */ - if (EC_POINT_is_at_infinity(group, public)) - goto out; - - if ((x = BN_new()) == NULL || - (y = BN_new()) == NULL || - (order = BN_new()) == NULL || - (tmp = BN_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - - /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ - if (EC_GROUP_get_order(group, order, NULL) != 1 || - EC_POINT_get_affine_coordinates_GFp(group, public, - x, y, NULL) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (BN_num_bits(x) <= BN_num_bits(order) / 2 || - BN_num_bits(y) <= BN_num_bits(order) / 2) - goto out; - - /* nQ == infinity (n == order of subgroup) */ - if ((nq = EC_POINT_new(group)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - if (EC_POINT_mul(group, nq, NULL, public, order, NULL) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (EC_POINT_is_at_infinity(group, nq) != 1) - goto out; - - /* x < order - 1, y < order - 1 */ - if (!BN_sub(tmp, order, BN_value_one())) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0) - goto out; - ret = 0; - out: - BN_clear_free(x); - BN_clear_free(y); - BN_clear_free(order); - BN_clear_free(tmp); - EC_POINT_free(nq); - return ret; -} - -int -sshkey_ec_validate_private(const EC_KEY *key) -{ - BIGNUM *order = NULL, *tmp = NULL; - int ret = SSH_ERR_KEY_INVALID_EC_VALUE; - - if ((order = BN_new()) == NULL || (tmp = BN_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - - /* log2(private) > log2(order)/2 */ - if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, NULL) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (BN_num_bits(EC_KEY_get0_private_key(key)) <= - BN_num_bits(order) / 2) - goto out; - - /* private < order - 1 */ - if (!BN_sub(tmp, order, BN_value_one())) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) - goto out; - ret = 0; - out: - BN_clear_free(order); - BN_clear_free(tmp); - return ret; -} - -void -sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) -{ - BIGNUM *x = NULL, *y = NULL; - - if (point == NULL) { - fputs("point=(NULL)\n", stderr); - return; - } - if ((x = BN_new()) == NULL || (y = BN_new()) == NULL) { - fprintf(stderr, "%s: BN_new failed\n", __func__); - goto out; - } - if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != - NID_X9_62_prime_field) { - fprintf(stderr, "%s: group is not a prime field\n", __func__); - goto out; - } - if (EC_POINT_get_affine_coordinates_GFp(group, point, - x, y, NULL) != 1) { - fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n", - __func__); - goto out; - } - fputs("x=", stderr); - BN_print_fp(stderr, x); - fputs("\ny=", stderr); - BN_print_fp(stderr, y); - fputs("\n", stderr); - out: - BN_clear_free(x); - BN_clear_free(y); -} - -void -sshkey_dump_ec_key(const EC_KEY *key) -{ - const BIGNUM *exponent; - - sshkey_dump_ec_point(EC_KEY_get0_group(key), - EC_KEY_get0_public_key(key)); - fputs("exponent=", stderr); - if ((exponent = EC_KEY_get0_private_key(key)) == NULL) - fputs("(NULL)", stderr); - else - BN_print_fp(stderr, EC_KEY_get0_private_key(key)); - fputs("\n", stderr); -} -#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ - static int sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob, const char *passphrase, const char *comment, const char *ciphername, @@ -3320,22 +3138,40 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, success = EVP_PKEY_set1_DSA(pkey, key->dsa); } break; -#ifdef OPENSSL_HAS_ECC case KEY_ECDSA: - if (format == SSHKEY_PRIVATE_PEM) { - success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, - cipher, passphrase, len, NULL, NULL); - } else { - success = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa); - } - break; -#endif case KEY_RSA: if (format == SSHKEY_PRIVATE_PEM) { - success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, - cipher, passphrase, len, NULL, NULL); + OSSL_ENCODER_CTX *ctx; + 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 { - success = EVP_PKEY_set1_RSA(pkey, key->rsa); + pkey = EVP_PKEY_dup(key->pkey); + success = pkey == NULL ? 0 : 1; } break; default: @@ -3347,10 +3183,39 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, goto out; } if (format == SSHKEY_PRIVATE_PKCS8) { - if ((success = PEM_write_bio_PrivateKey(bio, pkey, cipher, - passphrase, len, NULL, NULL)) == 0) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; + /* for now only rsa keys */ + 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; + } } } if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { @@ -3501,6 +3366,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; @@ -3537,15 +3403,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 && @@ -3566,20 +3429,21 @@ 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_from_pkey(NULL, prv->pkey, NULL)) + == NULL || + EVP_PKEY_public_check(ctx) != 1 || + EVP_PKEY_private_check(ctx) != 1) { 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 @@ -3631,6 +3495,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; } @@ -3793,6 +3658,7 @@ sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) { EVP_PKEY *ret = NULL; OSSL_PARAM *params = NULL; + int rc; if (param_bld == NULL || ctx == NULL) { /* debug2_f("param_bld or ctx is NULL"); */ return NULL; diff --git a/sshkey.h b/sshkey.h index 12eba8336bf..d510a1f5946 100644 --- a/sshkey.h +++ b/sshkey.h @@ -29,27 +29,19 @@ #include #ifdef WITH_OPENSSL -#include #include #include #include #include # ifdef OPENSSL_HAS_ECC -# include # include # else /* OPENSSL_HAS_ECC */ -# define EC_KEY void -# define EC_GROUP void -# define EC_POINT void # endif /* OPENSSL_HAS_ECC */ #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_GROUP void -# define EC_POINT void #define SSH_OPENSSL_VERSION "without OpenSSL" #endif /* WITH_OPENSSL */ @@ -129,12 +121,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; @@ -261,10 +252,8 @@ int sshkey_curve_name_to_nid(const char *); const char * sshkey_curve_nid_to_name(int); u_int sshkey_curve_nid_to_bits(int); int sshkey_ecdsa_bits_to_nid(int); -int sshkey_ecdsa_key_to_nid(EC_KEY *); +int sshkey_ecdsa_key_to_nid(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 *); 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); @@ -294,10 +283,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, @@ -317,7 +302,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 *); @@ -331,9 +318,11 @@ void sshkey_sig_details_free(struct sshkey_sig_details *); #ifdef WITH_OPENSSL EVP_PKEY *sshkey_create_evp(OSSL_PARAM_BLD *, EVP_PKEY_CTX *); -int ssh_create_evp_dss(const struct sshkey *, EVP_PKEY **); -int ssh_create_evp_rsa(const struct sshkey *, EVP_PKEY **); -int ssh_create_evp_ec(EC_KEY *, int, EVP_PKEY **); +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 @@ -355,15 +344,8 @@ int pkcs11_get_ecdsa_idx(void); #endif #if !defined(WITH_OPENSSL) -# undef RSA +# undef EVP_PKEY # undef DSA -# 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 /* SSHKEY_H */ From c2d5735dc5651031ff9ddcf492730d5c15130c52 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 6 Oct 2023 11:33:47 +0200 Subject: [PATCH 05/21] Useless variables --- kexdh.c | 2 +- sshbuf-getput-crypto.c | 7 ++++--- sshkey.c | 1 - 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/kexdh.c b/kexdh.c index e49486b5df7..de61612efec 100644 --- a/kexdh.c +++ b/kexdh.c @@ -82,7 +82,7 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) EVP_PKEY_CTX *ctx = NULL; u_char *kbuf = NULL; size_t klen = 0; - int kout, r = 0; + int r = 0; #ifdef DEBUG_KEXDH fprintf(stderr, "dh_pub= "); diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c index 38addf6b67f..8b1a9232ec3 100644 --- a/sshbuf-getput-crypto.c +++ b/sshbuf-getput-crypto.c @@ -109,9 +109,6 @@ sshbuf_put_ecbuf(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) int sshbuf_put_ec(struct sshbuf *buf, EVP_PKEY *pkey) { - u_char d[SSHBUF_MAX_ECPOINT]; - size_t len; - int ret; const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); if (ec == NULL) @@ -121,6 +118,10 @@ sshbuf_put_ec(struct sshbuf *buf, EVP_PKEY *pkey) 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) diff --git a/sshkey.c b/sshkey.c index 6d5182968ba..fe8ee9a7d1f 100644 --- a/sshkey.c +++ b/sshkey.c @@ -3658,7 +3658,6 @@ sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) { EVP_PKEY *ret = NULL; OSSL_PARAM *params = NULL; - int rc; if (param_bld == NULL || ctx == NULL) { /* debug2_f("param_bld or ctx is NULL"); */ return NULL; From 9d7a11e8db996c615c47b3028e82971b0d47dad7 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 6 Oct 2023 13:48:40 +0200 Subject: [PATCH 06/21] Build --without-openssl --- kex.h | 1 + packet.h | 2 ++ ssh-pkcs11.h | 2 ++ sshkey.c | 7 ------- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/kex.h b/kex.h index 46852c8f207..21dd0071a44 100644 --- a/kex.h +++ b/kex.h @@ -39,6 +39,7 @@ #else /* WITH_OPENSSL */ # define DH void # define BIGNUM void +# define EVP_PKEY void #endif /* WITH_OPENSSL */ #define KEX_COOKIE_LEN 16 diff --git a/packet.h b/packet.h index 16670beaf4a..6ca1943f015 100644 --- a/packet.h +++ b/packet.h @@ -183,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); +#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); diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h index 620d1e314eb..4b5e35f37ea 100644 --- a/ssh-pkcs11.h +++ b/ssh-pkcs11.h @@ -35,10 +35,12 @@ struct sshkey * u_int32_t *); #endif +#if defined WITH_OPENSSL #ifdef HAVE_EC_KEY_METHOD_NEW int is_ecdsa_pkcs11(EC_KEY *ecdsa); #endif int is_rsa_pkcs11(RSA *rsa); +#endif #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) #undef ENABLE_PKCS11 diff --git a/sshkey.c b/sshkey.c index fe8ee9a7d1f..6ed38bb2951 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1444,9 +1444,6 @@ sshkey_ecdsa_key_to_nid(EVP_PKEY *pkey) } # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ - OSSL_PARAM *params = NULL; - EVP_PKEY_CTX *ctx = NULL; - int sshkey_generate(int type, u_int bits, struct sshkey **keyp) { @@ -1661,9 +1658,6 @@ sshkey_shield_private(struct sshkey *k) fprintf(stderr, "%s: encrypted\n", __func__); sshbuf_dump_data(enc, enclen, stderr); #endif - OSSL_PARAM_free(params); - EVP_PKEY_CTX_free(ctx); - /* Make a scrubbed, public-only copy of our private key argument */ if ((r = sshkey_from_private(k, &kswap)) != 0) goto out; @@ -2636,7 +2630,6 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) sshkey_free(k); free(expect_sk_application); free(expect_ed25519_pk); - EVP_PKEY_CTX_free(ctx); return r; } From f5d8d0eaef2897edfa8c2cfc45b642aec9ff1bdd Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Tue, 10 Oct 2023 09:28:10 +0200 Subject: [PATCH 07/21] Make DH/ECDH KEX buildable on RHEL8 --- dh.c | 29 +++++++++++++++++++++++ kex.c | 44 ---------------------------------- kex.h | 6 ++--- kexdh.c | 49 +++++++++++++++++++++++++++++++++++++- kexecdh.c | 70 ++++++++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 137 insertions(+), 61 deletions(-) diff --git a/dh.c b/dh.c index e64c249ade2..fd6614abae3 100644 --- a/dh.c +++ b/dh.c @@ -37,8 +37,10 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include +#endif #include "dh.h" #include "pathnames.h" @@ -286,6 +288,7 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) int dh_gen_key(DH *dh, int need) { +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) const BIGNUM *dh_p, *dh_g; BIGNUM *pub_key = NULL, *priv_key = NULL; EVP_PKEY *pkey = NULL; @@ -381,6 +384,32 @@ dh_gen_key(DH *dh, int need) BN_clear_free(pub_key); BN_clear_free(priv_key); return r; +#else + int pbits; + const BIGNUM *dh_p, *pub_key; + + DH_get0_pqg(dh, &dh_p, NULL, NULL); + + if (need < 0 || dh_p == NULL || + (pbits = BN_num_bits(dh_p)) <= 0 || + need > INT_MAX / 2 || 2 * need > pbits) + return SSH_ERR_INVALID_ARGUMENT; + if (need < 256) + need = 256; + /* + * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), + * so double requested need here. + */ + if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1))) + return SSH_ERR_LIBCRYPTO_ERROR; + + if (DH_generate_key(dh) == 0) + return SSH_ERR_LIBCRYPTO_ERROR; + DH_get0_key(dh, &pub_key, NULL); + if (!dh_pub_is_valid(dh, pub_key)) + return SSH_ERR_INVALID_FORMAT; + return 0; +#endif } DH * diff --git a/kex.c b/kex.c index 882d9183fc6..ece7b93e044 100644 --- a/kex.c +++ b/kex.c @@ -1494,47 +1494,3 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms, return r; } -#ifdef WITH_OPENSSL -/* - * Creates an EVP_PKEY from the given parameters and keys. - * The private key can be omitted. - */ -int -kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, - const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) -{ - OSSL_PARAM_BLD *param_bld = NULL; - EVP_PKEY_CTX *ctx = NULL; - int r = 0; - - /* create EVP_PKEY-DH key */ - if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || - (param_bld = OSSL_PARAM_BLD_new()) == NULL) { - error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { - error_f("Failed pushing params to OSSL_PARAM_BLD"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (priv != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { - error_f("Failed pushing private key to OSSL_PARAM_BLD"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) - r = SSH_ERR_LIBCRYPTO_ERROR; -out: - OSSL_PARAM_BLD_free(param_bld); - EVP_PKEY_CTX_free(ctx); - return r; -} -#endif /* WITH_OPENSSL */ diff --git a/kex.h b/kex.h index 21dd0071a44..fdb3651af61 100644 --- a/kex.h +++ b/kex.h @@ -34,8 +34,10 @@ # include # include # include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) # include # include +#endif #else /* WITH_OPENSSL */ # define DH void # define BIGNUM void @@ -165,7 +167,7 @@ struct kex { /* kex specific state */ DH *dh; /* DH */ u_int min, max, nbits; /* GEX */ - EVP_PKEY *pkey; + EVP_PKEY *pkey; /* ECDH */ u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 + KEM */ u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */ u_char sntrup761_client_key[crypto_kem_sntrup761_SECRETKEYBYTES]; /* KEM */ @@ -249,8 +251,6 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); -int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, - const BIGNUM *, const BIGNUM *, const BIGNUM *); #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) void dump_digest(const char *, const u_char *, int); diff --git a/kexdh.c b/kexdh.c index de61612efec..a23d07b321c 100644 --- a/kexdh.c +++ b/kexdh.c @@ -37,8 +37,10 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include +#endif #include "sshkey.h" #include "kex.h" @@ -117,7 +119,7 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) goto out; } - if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) { + if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) { error_f("Could not init EVP_PKEY_CTX for dh"); r = SSH_ERR_ALLOC_FAIL; goto out; @@ -242,4 +244,49 @@ kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob, sshbuf_free(buf); return r; } +/* + * Creates an EVP_PKEY from the given parameters and keys. + * The private key can be omitted. + */ +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; + + /* create EVP_PKEY-DH key */ + if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || + (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { + error_f("Failed pushing params to OSSL_PARAM_BLD"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (priv != NULL && + OSSL_PARAM_BLD_push_BN(param_bld, + OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { + error_f("Failed pushing private key to OSSL_PARAM_BLD"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) + r = SSH_ERR_LIBCRYPTO_ERROR; +out: + OSSL_PARAM_BLD_free(param_bld); + EVP_PKEY_CTX_free(ctx); + return r; +#else +#endif +} #endif /* WITH_OPENSSL */ diff --git a/kexecdh.c b/kexecdh.c index 62f3f8f6ec7..d16a425e18a 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -35,9 +35,11 @@ #include #include +#include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include -#include +#endif #include "sshkey.h" #include "kex.h" @@ -55,6 +57,7 @@ generate_ec_keys(int ec_nid) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) OSSL_PARAM_BLD *param_bld = NULL; OSSL_PARAM *params = NULL; const char *group_name; @@ -75,10 +78,21 @@ generate_ec_keys(int ec_nid) error_f("Could not generate ec keys"); goto out; } +#else + if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || + EVP_PKEY_keygen_init(ctx) != 1 || + EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, ec_nid) <= 0 || + EVP_PKEY_keygen(ctx, &pkey) != 1) { + error_f("Could not generate ec keys"); + goto out; + } +#endif out: EVP_PKEY_CTX_free(ctx); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) OSSL_PARAM_BLD_free(param_bld); OSSL_PARAM_free(params); +#endif return pkey; } @@ -160,12 +174,16 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, struct sshbuf *buf = NULL; BIGNUM *shared_secret = NULL; EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *dh_pkey = NULL; + EVP_PKEY *peer_key = NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) OSSL_PARAM_BLD *param_bld = NULL; OSSL_PARAM *params = NULL; + const char *group_name; +#else + EC_KEY *ec = NULL; +#endif u_char *kbuf = NULL, *pub = NULL; size_t klen = 0, publen; - const char *group_name; int r; *shared_secretp = NULL; @@ -177,16 +195,20 @@ 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) goto out; sshbuf_reset(buf); - if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || - (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; + if ((param_bld = OSSL_PARAM_BLD_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; goto out; } if (OSSL_PARAM_BLD_push_octet_string(param_bld, @@ -194,28 +216,46 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { - error_f("Failed to set params for dh_pkey"); + error_f("Failed to set params for peer_key"); r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if (EVP_PKEY_fromdata_init(ctx) != 1 || - EVP_PKEY_fromdata(ctx, &dh_pkey, + EVP_PKEY_fromdata(ctx, &peer_key, EVP_PKEY_PUBLIC_KEY, params) != 1 || EVP_PKEY_public_check(ctx) != 1) { error_f("Peer public key import failed"); r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } +#else + if ((ec = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((r = sshbuf_get_eckey(ec_blob, ec)) != 0) + goto out; + + if ((peer_key = EVP_PKEY_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + if (EVP_PKEY_set1_EC_KEY(peer_key, ec) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +#endif #ifdef DEBUG_KEXECDH fputs("public key:\n", stderr); - EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL); + EVP_PKEY_print_public_fp(stderr, peer_key, 0, NULL); #endif EVP_PKEY_CTX_free(ctx); ctx = NULL; - if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || + if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || EVP_PKEY_derive_init(ctx) != 1 || - EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || + EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 || EVP_PKEY_derive(ctx, NULL, &klen) != 1) { error_f("Failed to get derive information"); r = SSH_ERR_LIBCRYPTO_ERROR; @@ -243,9 +283,13 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, buf = NULL; out: EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(dh_pkey); + EVP_PKEY_free(peer_key); +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) OSSL_PARAM_BLD_free(param_bld); OSSL_PARAM_free(params); +#else + EC_KEY_free(ec); +#endif BN_clear_free(shared_secret); freezero(kbuf, klen); freezero(pub, publen); From 723ede2d0eaabf7a357f32003a4ce97147bccfeb Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 11 Oct 2023 18:09:43 +0200 Subject: [PATCH 08/21] 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 | 117 ++++++++++++++-- sshkey.h | 4 + 16 files changed, 689 insertions(+), 46 deletions(-) diff --git a/kexdh.c b/kexdh.c index a23d07b321c..e7991080dee 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 d16a425e18a..8ae30aebabe 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 3e102fbfc99..ca4aa5b214c 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 ef348c67617..509a24da596 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 c85fe646f91..8e1e48a6dea 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 2c5a0dd73e5..f4999563a85 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 a9dd9796f0a..3d2595847d3 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 5ee0ad38693..a169b1baf27 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 65418f1b8f6..7b51c94a9d4 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 4d7b327fe77..455e07bb0b5 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 3ab752d8556..fcfb0a87dce 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 8e73abf1565..d68811206e0 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 8b1a9232ec3..ac3d5d3c876 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 7260cba350d..4404be2b94c 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 6ed38bb2951..03978d00aa2 100644 --- a/sshkey.c +++ b/sshkey.c @@ -34,6 +34,7 @@ #include #include #include +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) #include #include #include @@ -494,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; @@ -1416,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; @@ -1426,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, @@ -1441,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 */ @@ -3131,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) { @@ -3163,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; @@ -3176,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; @@ -3210,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; @@ -3427,10 +3520,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; } @@ -3646,6 +3741,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) { @@ -3667,4 +3763,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 d510a1f5946..726f7aaa1fc 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 *, From af8978a6d24f3a54721349b5e14d922ee645c7ca Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 11 Oct 2023 20:22:39 +0200 Subject: [PATCH 09/21] Adjust tests for OpenSSL 1.1.1 --- regress/unittests/sshkey/common.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/regress/unittests/sshkey/common.c b/regress/unittests/sshkey/common.c index 8e1e48a6dea..9f95880235b 100644 --- a/regress/unittests/sshkey/common.c +++ b/regress/unittests/sshkey/common.c @@ -92,19 +92,22 @@ rsa_n(struct sshkey *k) BIGNUM *n = NULL; #if (OPENSSL_VERSION_NUMBER < 0x30000000L) RSA *rsa = NULL; + BIGNUM *res = 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); + 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 - return n; } BIGNUM * @@ -113,19 +116,22 @@ rsa_e(struct sshkey *k) BIGNUM *e = NULL; #if (OPENSSL_VERSION_NUMBER < 0x30000000L) RSA *rsa = NULL; + BIGNUM *res = 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); + 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 - return e; } BIGNUM * @@ -134,19 +140,22 @@ rsa_p(struct sshkey *k) BIGNUM *p = NULL; #if (OPENSSL_VERSION_NUMBER < 0x30000000L) RSA *rsa = NULL; + BIGNUM *res = 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); + 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 - return p; } BIGNUM * @@ -155,19 +164,22 @@ rsa_q(struct sshkey *k) BIGNUM *q = NULL; #if (OPENSSL_VERSION_NUMBER < 0x30000000L) RSA *rsa = NULL; + BIGNUM *res = 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); + 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 - return q; } const BIGNUM * From 3e395c14c3ce033f875f2b956890b3efe5b09872 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 18 Oct 2023 17:47:13 +0200 Subject: [PATCH 10/21] Revert KEX rewriting A truncated part of #445 --- configure.ac | 2 +- dh.c | 103 -------------------------- kex.c | 4 +- kex.h | 25 +++++-- kexdh.c | 156 ++------------------------------------- kexecdh.c | 204 +++++++++++++-------------------------------------- sshbuf.h | 1 + sshkey.c | 160 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 240 insertions(+), 415 deletions(-) diff --git a/configure.ac b/configure.ac index b253cf3e0fe..0581a2c5a75 100644 --- a/configure.ac +++ b/configure.ac @@ -13,7 +13,7 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -AC_INIT([OpenSSH],[Portable],[openssh-unix-dev@mindrot.org]) +AC_INIT([OpenSSH], [Portable], [openssh-unix-dev@mindrot.org]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([ssh.c]) diff --git a/dh.c b/dh.c index fd6614abae3..ce2eb4725e6 100644 --- a/dh.c +++ b/dh.c @@ -36,11 +36,6 @@ #include #include -#include -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) -#include -#include -#endif #include "dh.h" #include "pathnames.h" @@ -288,103 +283,6 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) int dh_gen_key(DH *dh, int need) { -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - const BIGNUM *dh_p, *dh_g; - BIGNUM *pub_key = NULL, *priv_key = NULL; - EVP_PKEY *pkey = NULL; - EVP_PKEY_CTX *ctx = NULL; - OSSL_PARAM_BLD *param_bld = NULL; - OSSL_PARAM *params = NULL; - int pbits, r = 0; - - DH_get0_pqg(dh, &dh_p, NULL, &dh_g); - - if (need < 0 || dh_p == NULL || - (pbits = BN_num_bits(dh_p)) <= 0 || - need > INT_MAX / 2 || 2 * need > pbits) - return SSH_ERR_INVALID_ARGUMENT; - if (need < 256) - need = 256; - - if ((param_bld = OSSL_PARAM_BLD_new()) == NULL || - (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) { - OSSL_PARAM_BLD_free(param_bld); - return SSH_ERR_ALLOC_FAIL; - } - - if (OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 || - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) { - error_f("Could not set p,q,g parameters"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - /* - * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), - * so double requested need here. - */ - if (OSSL_PARAM_BLD_push_int(param_bld, - OSSL_PKEY_PARAM_DH_PRIV_LEN, - MINIMUM(need * 2, pbits - 1)) != 1 || - (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (EVP_PKEY_fromdata_init(ctx) != 1) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (EVP_PKEY_fromdata(ctx, &pkey, - EVP_PKEY_KEY_PARAMETERS, params) != 1) { - error_f("Failed key generation"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - - /* reuse context for key generation */ - EVP_PKEY_CTX_free(ctx); - ctx = NULL; - - if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || - EVP_PKEY_keygen_init(ctx) != 1) { - error_f("Could not create or init context"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (EVP_PKEY_generate(ctx, &pkey) != 1) { - error_f("Could not generate keys"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (EVP_PKEY_public_check(ctx) != 1) { - error_f("The public key is incorrect"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - - if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, - &pub_key) != 1 || - EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, - &priv_key) != 1 || - DH_set0_key(dh, pub_key, priv_key) != 1) { - error_f("Could not set pub/priv keys to DH struct"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - - /* transferred */ - pub_key = NULL; - priv_key = NULL; -out: - OSSL_PARAM_free(params); - OSSL_PARAM_BLD_free(param_bld); - EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(pkey); - BN_clear_free(pub_key); - BN_clear_free(priv_key); - return r; -#else int pbits; const BIGNUM *dh_p, *pub_key; @@ -409,7 +307,6 @@ dh_gen_key(DH *dh, int need) if (!dh_pub_is_valid(dh, pub_key)) return SSH_ERR_INVALID_FORMAT; return 0; -#endif } DH * diff --git a/kex.c b/kex.c index ece7b93e044..aa5e792ddc5 100644 --- a/kex.c +++ b/kex.c @@ -784,7 +784,9 @@ kex_free(struct kex *kex) #ifdef WITH_OPENSSL DH_free(kex->dh); - EVP_PKEY_free(kex->pkey); +#ifdef OPENSSL_HAS_ECC + EC_KEY_free(kex->ec_client_key); +#endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ for (mode = 0; mode < MODE_MAX; mode++) { kex_free_newkeys(kex->newkeys[mode]); diff --git a/kex.h b/kex.h index fdb3651af61..5f7ef784eec 100644 --- a/kex.h +++ b/kex.h @@ -33,15 +33,19 @@ # include # include # include -# include -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) -# include -# include -#endif +# 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 */ #else /* WITH_OPENSSL */ # define DH void # define BIGNUM void -# define EVP_PKEY void +# define EC_KEY void +# define EC_GROUP void +# define EC_POINT void #endif /* WITH_OPENSSL */ #define KEX_COOKIE_LEN 16 @@ -167,7 +171,8 @@ struct kex { /* kex specific state */ DH *dh; /* DH */ u_int min, max, nbits; /* GEX */ - EVP_PKEY *pkey; /* ECDH */ + EC_KEY *ec_client_key; /* ECDH */ + const EC_GROUP *ec_group; /* ECDH */ u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 + KEM */ u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */ u_char sntrup761_client_key[crypto_kem_sntrup761_SECRETKEYBYTES]; /* KEM */ @@ -256,4 +261,10 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], void dump_digest(const char *, const u_char *, int); #endif +#if !defined(WITH_OPENSSL) || !defined(OPENSSL_HAS_ECC) +# undef EC_KEY +# undef EC_GROUP +# undef EC_POINT +#endif + #endif diff --git a/kexdh.c b/kexdh.c index e7991080dee..c1084f2146e 100644 --- a/kexdh.c +++ b/kexdh.c @@ -35,12 +35,6 @@ #include "openbsd-compat/openssl-compat.h" #include -#include -#include -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) -#include -#include -#endif #include "sshkey.h" #include "kex.h" @@ -79,16 +73,9 @@ int kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) { BIGNUM *shared_secret = NULL; - const BIGNUM *pub, *priv, *p, *q, *g; - EVP_PKEY *pkey = NULL, *dh_pkey = NULL; - EVP_PKEY_CTX *ctx = NULL; 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 + int kout, r; #ifdef DEBUG_KEXDH fprintf(stderr, "dh_pub= "); @@ -103,113 +90,24 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) r = SSH_ERR_MESSAGE_INCOMPLETE; goto out; } - -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - DH_get0_key(kex->dh, &pub, &priv); - DH_get0_pqg(kex->dh, &p, &q, &g); - /* import key */ - r = kex_create_evp_dh(&pkey, p, q, g, pub, priv); - if (r != 0) { - error_f("Could not create EVP_PKEY for dh"); - ERR_print_errors_fp(stderr); - goto out; - } - /* 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); - if (r != 0) { - error_f("Could not import peer key for dh"); - 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; - } - if (EVP_PKEY_derive_init(ctx) != 1 || - EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || - EVP_PKEY_derive(ctx, NULL, &klen) != 1) { - error_f("Could not get key size"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } + klen = DH_size(kex->dh); if ((kbuf = malloc(klen)) == NULL || (shared_secret = BN_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 || - BN_bin2bn(kbuf, klen, shared_secret) == NULL) { - error_f("Could not derive key"); + if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || + BN_bin2bn(kbuf, kout, shared_secret) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } #ifdef DEBUG_KEXDH - dump_digest("shared secret", kbuf, klen); + dump_digest("shared secret", kbuf, kout); #endif r = sshbuf_put_bignum2(out, shared_secret); out: freezero(kbuf, klen); BN_clear_free(shared_secret); - EVP_PKEY_free(pkey); - EVP_PKEY_free(dh_pkey); - EVP_PKEY_CTX_free(ctx); return r; } @@ -302,48 +200,4 @@ 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. - */ -int -kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, - const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) -{ - OSSL_PARAM_BLD *param_bld = NULL; - EVP_PKEY_CTX *ctx = NULL; - int r = 0; - - /* create EVP_PKEY-DH key */ - if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || - (param_bld = OSSL_PARAM_BLD_new()) == NULL) { - error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { - error_f("Failed pushing params to OSSL_PARAM_BLD"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (priv != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { - error_f("Failed pushing private key to OSSL_PARAM_BLD"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) - r = SSH_ERR_LIBCRYPTO_ERROR; -out: - OSSL_PARAM_BLD_free(param_bld); - EVP_PKEY_CTX_free(ctx); - return r; -} -#endif #endif /* WITH_OPENSSL */ diff --git a/kexecdh.c b/kexecdh.c index 8ae30aebabe..d451b07a20a 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -34,97 +34,56 @@ #include #include -#include -#include -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) -#include -#include -#endif +#include #include "sshkey.h" #include "kex.h" #include "sshbuf.h" #include "digest.h" #include "ssherr.h" -#include "log.h" static int -kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, - EVP_PKEY *pkey, struct sshbuf **shared_secretp); - -static EVP_PKEY * -generate_ec_keys(int ec_nid) -{ - EVP_PKEY *pkey = NULL; - EVP_PKEY_CTX *ctx = NULL; -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - OSSL_PARAM_BLD *param_bld = NULL; - OSSL_PARAM *params = NULL; - const char *group_name; - - if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || - (param_bld = OSSL_PARAM_BLD_new()) == NULL) - goto out; - if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL || - OSSL_PARAM_BLD_push_utf8_string(param_bld, - OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || - (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { - error_f("Could not create OSSL_PARAM"); - goto out; - } - if (EVP_PKEY_keygen_init(ctx) != 1 || - EVP_PKEY_CTX_set_params(ctx, params) != 1 || - EVP_PKEY_generate(ctx, &pkey) != 1) { - error_f("Could not generate ec keys"); - goto out; - } -#else - if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL || - EVP_PKEY_keygen_init(ctx) != 1 || - EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, ec_nid) <= 0 || - EVP_PKEY_keygen(ctx, &pkey) != 1) { - error_f("Could not generate ec keys"); - goto out; - } -#endif -out: - EVP_PKEY_CTX_free(ctx); -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - OSSL_PARAM_BLD_free(param_bld); - OSSL_PARAM_free(params); -#endif - return pkey; -} +kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, + const EC_GROUP *, struct sshbuf **); int kex_ecdh_keypair(struct kex *kex) { - EVP_PKEY *client_key = NULL; + EC_KEY *client_key = NULL; + const EC_GROUP *group; + const EC_POINT *public_key; struct sshbuf *buf = NULL; int r; - if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) { + if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (EC_KEY_generate_key(client_key) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + group = EC_KEY_get0_group(client_key); + public_key = EC_KEY_get0_public_key(client_key); if ((buf = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_put_ec(buf, client_key)) != 0 || + if ((r = sshbuf_put_ecbuf(buf, public_key, group)) != 0 || (r = sshbuf_get_u32(buf, NULL)) != 0) goto out; #ifdef DEBUG_KEXECDH fputs("client private key:\n", stderr); sshkey_dump_ec_key(client_key); #endif - kex->pkey = client_key; + kex->ec_client_key = client_key; + kex->ec_group = group; client_key = NULL; /* owned by the kex */ kex->client_pub = buf; buf = NULL; -out: - EVP_PKEY_free(client_key); + out: + EC_KEY_free(client_key); sshbuf_free(buf); return r; } @@ -133,57 +92,57 @@ int kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, struct sshbuf **server_blobp, struct sshbuf **shared_secretp) { - EVP_PKEY *server_key = NULL; + const EC_GROUP *group; + const EC_POINT *pub_key; + EC_KEY *server_key = NULL; struct sshbuf *server_blob = NULL; int r; *server_blobp = NULL; *shared_secretp = NULL; - if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) { + if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (EC_KEY_generate_key(server_key) != 1) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + group = EC_KEY_get0_group(server_key); #ifdef DEBUG_KEXECDH fputs("server private key:\n", stderr); sshkey_dump_ec_key(server_key); #endif + pub_key = EC_KEY_get0_public_key(server_key); if ((server_blob = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_put_ec(server_blob, server_key)) != 0 || + if ((r = sshbuf_put_ecbuf(server_blob, pub_key, group)) != 0 || (r = sshbuf_get_u32(server_blob, NULL)) != 0) goto out; - if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, + if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group, shared_secretp)) != 0) goto out; *server_blobp = server_blob; server_blob = NULL; -out: - EVP_PKEY_free(server_key); + out: + EC_KEY_free(server_key); sshbuf_free(server_blob); return r; } static int kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, - EVP_PKEY *pkey, struct sshbuf **shared_secretp) + EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp) { struct sshbuf *buf = NULL; BIGNUM *shared_secret = NULL; - EVP_PKEY_CTX *ctx = NULL; - EVP_PKEY *peer_key = NULL; -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - OSSL_PARAM_BLD *param_bld = NULL; - OSSL_PARAM *params = NULL; - const char *group_name; -#else - EC_KEY *ec = NULL; -#endif - u_char *kbuf = NULL, *pub = NULL; - size_t klen = 0, publen; + EC_POINT *dh_pub = NULL; + u_char *kbuf = NULL; + size_t klen = 0; int r; *shared_secretp = NULL; @@ -194,104 +153,45 @@ 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_string(buf, &pub, &publen)) != 0) - goto out; - sshbuf_reset(buf); - if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if ((param_bld = OSSL_PARAM_BLD_new()) == NULL) { + if ((dh_pub = EC_POINT_new(group)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if (OSSL_PARAM_BLD_push_octet_string(param_bld, - OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 || - OSSL_PARAM_BLD_push_utf8_string(param_bld, - OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || - (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { - error_f("Failed to set params for peer_key"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (EVP_PKEY_fromdata_init(ctx) != 1 || - EVP_PKEY_fromdata(ctx, &peer_key, - EVP_PKEY_PUBLIC_KEY, params) != 1 || - EVP_PKEY_public_check(ctx) != 1) { - error_f("Peer public key import failed"); - r = SSH_ERR_LIBCRYPTO_ERROR; + if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { goto out; } -#else - if ((ec = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - if ((r = sshbuf_get_eckey(buf, ec)) != 0) - goto out; - - if ((peer_key = EVP_PKEY_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - - if (EVP_PKEY_set1_EC_KEY(peer_key, ec) != 1) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -#endif + sshbuf_reset(buf); #ifdef DEBUG_KEXECDH fputs("public key:\n", stderr); - EVP_PKEY_print_public_fp(stderr, peer_key, 0, NULL); + sshkey_dump_ec_point(group, dh_pub); #endif - EVP_PKEY_CTX_free(ctx); - ctx = NULL; - if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL || - EVP_PKEY_derive_init(ctx) != 1 || - EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 || - EVP_PKEY_derive(ctx, NULL, &klen) != 1) { - error_f("Failed to get derive information"); - r = SSH_ERR_LIBCRYPTO_ERROR; + if (sshkey_ec_validate_public(group, dh_pub) != 0) { + r = SSH_ERR_MESSAGE_INCOMPLETE; goto out; } - if ((kbuf = malloc(klen)) == NULL) { + klen = (EC_GROUP_get_degree(group) + 7) / 8; + if ((kbuf = malloc(klen)) == NULL || + (shared_secret = BN_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } - if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) { + if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || + BN_bin2bn(kbuf, klen, shared_secret) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } #ifdef DEBUG_KEXECDH dump_digest("shared secret", kbuf, klen); #endif - if ((shared_secret = BN_new()) == NULL || - (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) goto out; *shared_secretp = buf; buf = NULL; out: - EVP_PKEY_CTX_free(ctx); - EVP_PKEY_free(peer_key); -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - OSSL_PARAM_BLD_free(param_bld); - OSSL_PARAM_free(params); -#else - EC_KEY_free(ec); -#endif + EC_POINT_clear_free(dh_pub); BN_clear_free(shared_secret); freezero(kbuf, klen); - freezero(pub, publen); sshbuf_free(buf); return r; } @@ -302,10 +202,10 @@ kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob, { int r; - r = kex_ecdh_dec_key_group(kex, server_blob, kex->pkey, - shared_secretp); - EVP_PKEY_free(kex->pkey); - kex->pkey = NULL; + r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key, + kex->ec_group, shared_secretp); + EC_KEY_free(kex->ec_client_key); + kex->ec_client_key = NULL; return r; } diff --git a/sshbuf.h b/sshbuf.h index 4404be2b94c..29b0f25a0e5 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -220,6 +220,7 @@ int sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v); 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); +int sshbuf_put_ecbuf(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g); #endif /* WITH_OPENSSL */ /* Dump the contents of the buffer in a human-readable format */ diff --git a/sshkey.c b/sshkey.c index 03978d00aa2..ffc857a9530 100644 --- a/sshkey.c +++ b/sshkey.c @@ -2688,6 +2688,166 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) return r; } +#if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) +int +sshkey_ec_validate_public(const EC_GROUP *group, const EC_POINT *public) +{ + EC_POINT *nq = NULL; + BIGNUM *order = NULL, *x = NULL, *y = NULL, *tmp = NULL; + int ret = SSH_ERR_KEY_INVALID_EC_VALUE; + + /* + * NB. This assumes OpenSSL has already verified that the public + * point lies on the curve. This is done by EC_POINT_oct2point() + * implicitly calling EC_POINT_is_on_curve(). If this code is ever + * reachable with public points not unmarshalled using + * EC_POINT_oct2point then the caller will need to explicitly check. + */ + + /* + * We shouldn't ever hit this case because bignum_get_ecpoint() + * refuses to load GF2m points. + */ + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != + NID_X9_62_prime_field) + goto out; + + /* Q != infinity */ + if (EC_POINT_is_at_infinity(group, public)) + goto out; + + if ((x = BN_new()) == NULL || + (y = BN_new()) == NULL || + (order = BN_new()) == NULL || + (tmp = BN_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + + /* log2(x) > log2(order)/2, log2(y) > log2(order)/2 */ + if (EC_GROUP_get_order(group, order, NULL) != 1 || + EC_POINT_get_affine_coordinates_GFp(group, public, + x, y, NULL) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (BN_num_bits(x) <= BN_num_bits(order) / 2 || + BN_num_bits(y) <= BN_num_bits(order) / 2) + goto out; + + /* nQ == infinity (n == order of subgroup) */ + if ((nq = EC_POINT_new(group)) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + if (EC_POINT_mul(group, nq, NULL, public, order, NULL) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (EC_POINT_is_at_infinity(group, nq) != 1) + goto out; + + /* x < order - 1, y < order - 1 */ + if (!BN_sub(tmp, order, BN_value_one())) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (BN_cmp(x, tmp) >= 0 || BN_cmp(y, tmp) >= 0) + goto out; + ret = 0; + out: + BN_clear_free(x); + BN_clear_free(y); + BN_clear_free(order); + BN_clear_free(tmp); + EC_POINT_free(nq); + return ret; +} + +int +sshkey_ec_validate_private(const EC_KEY *key) +{ + BIGNUM *order = NULL, *tmp = NULL; + int ret = SSH_ERR_KEY_INVALID_EC_VALUE; + + if ((order = BN_new()) == NULL || (tmp = BN_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } + + /* log2(private) > log2(order)/2 */ + if (EC_GROUP_get_order(EC_KEY_get0_group(key), order, NULL) != 1) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (BN_num_bits(EC_KEY_get0_private_key(key)) <= + BN_num_bits(order) / 2) + goto out; + + /* private < order - 1 */ + if (!BN_sub(tmp, order, BN_value_one())) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if (BN_cmp(EC_KEY_get0_private_key(key), tmp) >= 0) + goto out; + ret = 0; + out: + BN_clear_free(order); + BN_clear_free(tmp); + return ret; +} + +void +sshkey_dump_ec_point(const EC_GROUP *group, const EC_POINT *point) +{ + BIGNUM *x = NULL, *y = NULL; + + if (point == NULL) { + fputs("point=(NULL)\n", stderr); + return; + } + if ((x = BN_new()) == NULL || (y = BN_new()) == NULL) { + fprintf(stderr, "%s: BN_new failed\n", __func__); + goto out; + } + if (EC_METHOD_get_field_type(EC_GROUP_method_of(group)) != + NID_X9_62_prime_field) { + fprintf(stderr, "%s: group is not a prime field\n", __func__); + goto out; + } + if (EC_POINT_get_affine_coordinates_GFp(group, point, + x, y, NULL) != 1) { + fprintf(stderr, "%s: EC_POINT_get_affine_coordinates_GFp\n", + __func__); + goto out; + } + fputs("x=", stderr); + BN_print_fp(stderr, x); + fputs("\ny=", stderr); + BN_print_fp(stderr, y); + fputs("\n", stderr); + out: + BN_clear_free(x); + BN_clear_free(y); +} + +void +sshkey_dump_ec_key(const EC_KEY *key) +{ + const BIGNUM *exponent; + + sshkey_dump_ec_point(EC_KEY_get0_group(key), + EC_KEY_get0_public_key(key)); + fputs("exponent=", stderr); + if ((exponent = EC_KEY_get0_private_key(key)) == NULL) + fputs("(NULL)", stderr); + else + BN_print_fp(stderr, EC_KEY_get0_private_key(key)); + fputs("\n", stderr); +} +#endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ + static int sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob, const char *passphrase, const char *comment, const char *ciphername, From a2960c630de311c9703ee5899c7066170cfce1be Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Wed, 18 Oct 2023 19:05:21 +0200 Subject: [PATCH 11/21] Remove DSS changes --- ssh-dss.c | 137 ++++++++++-------------------------------------------- 1 file changed, 24 insertions(+), 113 deletions(-) diff --git a/ssh-dss.c b/ssh-dss.c index a169b1baf27..3174ef146dc 100644 --- a/ssh-dss.c +++ b/ssh-dss.c @@ -32,10 +32,6 @@ #include #include #include -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) -#include -#include -#endif #include #include @@ -265,15 +261,11 @@ ssh_dss_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) { - EVP_PKEY *pkey = NULL; DSA_SIG *sig = NULL; const BIGNUM *sig_r, *sig_s; - u_char sigblob[SIGBLOB_LEN]; - size_t rlen, slen; - int len; + u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; + size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); struct sshbuf *b = NULL; - u_char *sigb = NULL; - const u_char *psig = NULL; int ret = SSH_ERR_INVALID_ARGUMENT; if (lenp != NULL) @@ -284,23 +276,17 @@ ssh_dss_sign(struct sshkey *key, if (key == NULL || key->dsa == NULL || sshkey_type_plain(key->type) != KEY_DSA) return SSH_ERR_INVALID_ARGUMENT; + if (dlen == 0) + return SSH_ERR_INTERNAL_ERROR; - if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) - return ret; - ret = sshkey_calculate_signature(pkey, SSH_DIGEST_SHA1, &sigb, &len, - data, datalen); - EVP_PKEY_free(pkey); - if (ret < 0) { + if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, + digest, sizeof(digest))) != 0) goto out; - } - psig = sigb; - if ((sig = d2i_DSA_SIG(NULL, &psig, len)) == NULL) { + if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - free(sigb); - sigb = NULL; DSA_SIG_get0(sig, &sig_r, &sig_s); rlen = BN_num_bytes(sig_r); @@ -333,7 +319,7 @@ ssh_dss_sign(struct sshkey *key, *lenp = len; ret = 0; out: - free(sigb); + explicit_bzero(digest, sizeof(digest)); DSA_SIG_free(sig); sshbuf_free(b); return ret; @@ -345,20 +331,20 @@ ssh_dss_verify(const struct sshkey *key, const u_char *data, size_t dlen, const char *alg, u_int compat, struct sshkey_sig_details **detailsp) { - EVP_PKEY *pkey = NULL; DSA_SIG *dsig = NULL; BIGNUM *sig_r = NULL, *sig_s = NULL; - u_char *sigblob = NULL; - size_t len, slen; + u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; + size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); int ret = SSH_ERR_INTERNAL_ERROR; struct sshbuf *b = NULL; char *ktype = NULL; - u_char *sigb = NULL, *psig = NULL; if (key == NULL || key->dsa == NULL || sshkey_type_plain(key->type) != KEY_DSA || sig == NULL || siglen == 0) return SSH_ERR_INVALID_ARGUMENT; + if (hlen == 0) + return SSH_ERR_INTERNAL_ERROR; /* fetch signature */ if ((b = sshbuf_from(sig, siglen)) == NULL) @@ -400,28 +386,25 @@ ssh_dss_verify(const struct sshkey *key, } sig_r = sig_s = NULL; /* transferred */ - if ((slen = i2d_DSA_SIG(dsig, NULL)) == 0) { - ret = SSH_ERR_LIBCRYPTO_ERROR; + /* sha1 the data */ + if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, + digest, sizeof(digest))) != 0) goto out; - } - if ((sigb = malloc(slen)) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; + + switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { + case 1: + ret = 0; + break; + case 0: + ret = SSH_ERR_SIGNATURE_INVALID; goto out; - } - psig = sigb; - if ((slen = i2d_DSA_SIG(dsig, &psig)) == 0) { + default: ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) - goto out; - ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, dlen, - sigb, slen); - EVP_PKEY_free(pkey); - out: - free(sigb); + explicit_bzero(digest, sizeof(digest)); DSA_SIG_free(dsig); BN_clear_free(sig_r); BN_clear_free(sig_s); @@ -432,78 +415,6 @@ ssh_dss_verify(const struct sshkey *key, return ret; } -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; - int ret = 0; - - if (k == NULL) - return SSH_ERR_INVALID_ARGUMENT; - if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL)) == NULL || - (param_bld = OSSL_PARAM_BLD_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } - - DSA_get0_pqg(k->dsa, &p, &q, &g); - DSA_get0_key(k->dsa, &pub, &priv); - - if (p != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (q != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (g != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (pub != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_PUB_KEY, - pub) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - if (priv != NULL && - OSSL_PARAM_BLD_push_BN(param_bld, - OSSL_PKEY_PARAM_PRIV_KEY, - priv) != 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; -#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 = { /* .size = */ ssh_dss_size, /* .alloc = */ ssh_dss_alloc, From eb330fd8bf92de3300751d279e32d98f5984baa7 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Thu, 19 Oct 2023 14:08:50 +0200 Subject: [PATCH 12/21] Reduce diff, avoid extra function renaming --- kexecdh.c | 4 ++-- packet.c | 2 +- regress/unittests/sshbuf/test_sshbuf_getput_crypto.c | 6 +++--- ssh-ecdsa.c | 2 +- sshbuf-getput-crypto.c | 6 +++--- sshbuf.h | 7 ++++--- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/kexecdh.c b/kexecdh.c index d451b07a20a..efb2e55a6d4 100644 --- a/kexecdh.c +++ b/kexecdh.c @@ -70,7 +70,7 @@ kex_ecdh_keypair(struct kex *kex) r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_put_ecbuf(buf, public_key, group)) != 0 || + if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 || (r = sshbuf_get_u32(buf, NULL)) != 0) goto out; #ifdef DEBUG_KEXECDH @@ -120,7 +120,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_put_ecbuf(server_blob, pub_key, group)) != 0 || + if ((r = sshbuf_put_ec(server_blob, pub_key, group)) != 0 || (r = sshbuf_get_u32(server_blob, NULL)) != 0) goto out; if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group, diff --git a/packet.c b/packet.c index ca4aa5b214c..e628d091a85 100644 --- a/packet.c +++ b/packet.c @@ -2539,7 +2539,7 @@ sshpkt_getb_froms(struct ssh *ssh, struct sshbuf **valp) int sshpkt_put_ec(struct ssh *ssh, EVP_PKEY *pkey) { - return sshbuf_put_ec(ssh->state->outgoing_packet, pkey); + return sshbuf_put_ecpkey(ssh->state->outgoing_packet, pkey); } #endif /* OPENSSL_HAS_ECC */ diff --git a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c index 509a24da596..7b4cb3cb42c 100644 --- a/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c +++ b/regress/unittests/sshbuf/test_sshbuf_getput_crypto.c @@ -240,7 +240,7 @@ 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); @@ -292,9 +292,9 @@ sshbuf_getput_crypto_tests(void) p1 = sshbuf_new(); ASSERT_PTR_NE(p1, NULL); #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - ASSERT_INT_EQ(sshbuf_put_ec(p1, eck), 0); + ASSERT_INT_EQ(sshbuf_put_ecpkey(p1, eck), 0); #else - ASSERT_INT_EQ(sshbuf_put_ecbuf(p1, EC_KEY_get0_public_key(eck), + 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); diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index 7b51c94a9d4..a218b0237ed 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -96,7 +96,7 @@ ssh_ecdsa_serialize_public(const struct sshkey *key, struct sshbuf *b, return SSH_ERR_INVALID_ARGUMENT; if ((r = sshbuf_put_cstring(b, sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || - (r = sshbuf_put_ec(b, key->pkey)) != 0) + (r = sshbuf_put_ecpkey(b, key->pkey)) != 0) return r; return 0; diff --git a/sshbuf-getput-crypto.c b/sshbuf-getput-crypto.c index ac3d5d3c876..798012f9065 100644 --- a/sshbuf-getput-crypto.c +++ b/sshbuf-getput-crypto.c @@ -153,7 +153,7 @@ sshbuf_put_bignum2(struct sshbuf *buf, const BIGNUM *v) #ifdef OPENSSL_HAS_ECC int -sshbuf_put_ecbuf(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) +sshbuf_put_ec(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) { u_char d[SSHBUF_MAX_ECPOINT]; size_t len; @@ -173,14 +173,14 @@ sshbuf_put_ecbuf(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g) } int -sshbuf_put_ec(struct sshbuf *buf, EVP_PKEY *pkey) +sshbuf_put_ecpkey(struct sshbuf *buf, EVP_PKEY *pkey) { const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey); if (ec == NULL) return SSH_ERR_LIBCRYPTO_ERROR; - return sshbuf_put_ecbuf(buf, EC_KEY_get0_public_key(ec), + return sshbuf_put_ec(buf, EC_KEY_get0_public_key(ec), EC_KEY_get0_group(ec)); /* FIXME beldmit */ #if 0 diff --git a/sshbuf.h b/sshbuf.h index 29b0f25a0e5..e9d14848355 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -216,11 +216,12 @@ 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); -/* FIXME beldmit should accept EVP_PKEY * */ +# 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_ec(struct sshbuf *buf, EVP_PKEY *pkey); -int sshbuf_put_ecbuf(struct sshbuf *buf, const EC_POINT *v, const EC_GROUP *g); +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); +# endif #endif /* WITH_OPENSSL */ /* Dump the contents of the buffer in a human-readable format */ From 4a19faa521ae8de8cb184500ce3735843a5d2164 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Thu, 19 Oct 2023 14:47:19 +0200 Subject: [PATCH 13/21] Attempt to fix tests against OpenSSL <= 3.0.7 --- regress/unittests/sshkey/test_file.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c index f4999563a85..46f9650daf1 100644 --- a/regress/unittests/sshkey/test_file.c +++ b/regress/unittests/sshkey/test_file.c @@ -274,8 +274,10 @@ 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) + 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); @@ -289,7 +291,7 @@ sshkey_file_tests(void) c = BN_new(); #endif ASSERT_PTR_NE(c, NULL); -#if (OPENSSL_VERSION_NUMBER < 0x30000000L) +#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); From faf7296ef9a0982a8d7aeb8a54855fb31222621f Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Thu, 19 Oct 2023 14:50:27 +0200 Subject: [PATCH 14/21] Attempt to fix no-ecc --- sshbuf.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sshbuf.h b/sshbuf.h index e9d14848355..aaed8fc43fb 100644 --- a/sshbuf.h +++ b/sshbuf.h @@ -23,7 +23,9 @@ #include #ifdef WITH_OPENSSL # include -# include +# ifdef OPENSSL_HAS_ECC +# include +# endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ #define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */ From dfc005599c129c72c8a2b9243fdf0ec51eb2d6af Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 20 Oct 2023 11:15:17 +0200 Subject: [PATCH 15/21] Fix gcc-11 -Werror, partially --- ssh-ecdsa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c index a218b0237ed..9e55cb8950c 100644 --- a/ssh-ecdsa.c +++ b/ssh-ecdsa.c @@ -221,7 +221,9 @@ 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) @@ -233,7 +235,7 @@ ssh_ecdsa_deserialize_public(const char *ktype, struct sshbuf *b, goto out; } #if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - if ((r = sshbuf_get_string(b, &pub, &publen)) != 0) /*XXX*/ + if ((r = sshbuf_get_string(b, &pub, &publen)) != 0) goto out; if ((r = ssh_create_evp_ec(pub, publen, NULL, key->ecdsa_nid, &pkey) != 0)) goto out; From 5c69e3e108dc7c9a7d9d5cab65bd08728974d462 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 20 Oct 2023 11:20:44 +0200 Subject: [PATCH 16/21] BoringSSL compatibility --- configure.ac | 6 ++++++ ssh-sk.c | 2 ++ sshkey.c | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) 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/ssh-sk.c b/ssh-sk.c index d68811206e0..944b02d07e6 100644 --- a/ssh-sk.c +++ b/ssh-sk.c @@ -266,12 +266,14 @@ sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp) 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 */ diff --git a/sshkey.c b/sshkey.c index ffc857a9530..38503220b29 100644 --- a/sshkey.c +++ b/sshkey.c @@ -3681,8 +3681,10 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, prv->ecdsa_nid = sshkey_ecdsa_key_to_nid(prv->pkey); if (prv->ecdsa_nid == -1 || (ctx = EVP_PKEY_CTX_new(prv->pkey, NULL)) == NULL +#ifdef HAVE_EVP_PKEY_PUBLIC_CHECK || EVP_PKEY_public_check(ctx) != 1 -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#endif +#ifdef HAVE_EVP_PKEY_PRIVATE_CHECK || EVP_PKEY_private_check(ctx) != 1 #endif ) { From 0aa9381202a4d4252545198b70dd3b2914cc3244 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 20 Oct 2023 12:46:59 +0200 Subject: [PATCH 17/21] Various warning fixes --- ssh-ecdsa-sk.c | 26 +++++++------------------- ssh-keygen.c | 2 ++ sshkey.c | 2 ++ sshkey.h | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/ssh-ecdsa-sk.c b/ssh-ecdsa-sk.c index 484621cdbd8..ce1195ee20a 100644 --- a/ssh-ecdsa-sk.c +++ b/ssh-ecdsa-sk.c @@ -236,7 +236,6 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, struct sshkey_sig_details **detailsp) { ECDSA_SIG *esig = NULL; - EVP_MD_CTX *md_ctx = NULL; BIGNUM *sig_r = NULL, *sig_s = NULL; u_char sig_flags; u_char msghash[32], apphash[32]; @@ -376,8 +375,7 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - if ((sigb = malloc(len)) == NULL || - (md_ctx = EVP_MD_CTX_new()) == NULL) { + if ((sigb = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } @@ -386,22 +384,13 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } - if (EVP_DigestVerifyInit(md_ctx, NULL, EVP_sha256(), NULL, - key->pkey) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - switch(EVP_DigestVerify(md_ctx, sigb, len, sshbuf_ptr(original_signed), sshbuf_len(original_signed))) { - case 1: - ret = 0; - break; - case 0: - ret = SSH_ERR_SIGNATURE_INVALID; - goto out; - default: - ret = SSH_ERR_LIBCRYPTO_ERROR; + 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; @@ -424,7 +413,6 @@ ssh_ecdsa_sk_verify(const struct sshkey *key, BN_clear_free(sig_s); free(ktype); free(sigb); - EVP_MD_CTX_free(md_ctx); return ret; } diff --git a/ssh-keygen.c b/ssh-keygen.c index 455e07bb0b5..3eb88bd0b21 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -804,6 +804,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) (*k)->type = KEY_DSA; (*k)->dsa = EVP_PKEY_get1_DSA(pubkey); break; +#ifdef OPENSSL_HAS_ECC case EVP_PKEY_EC: if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) fatal("sshkey_new failed"); @@ -812,6 +813,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) pubkey = NULL; (*k)->ecdsa_nid = sshkey_ecdsa_key_to_nid((*k)->pkey); break; +#endif default: fatal_f("unsupported pubkey type %d", EVP_PKEY_base_id(pubkey)); diff --git a/sshkey.c b/sshkey.c index 38503220b29..2f7a8d7208f 100644 --- a/sshkey.c +++ b/sshkey.c @@ -1427,6 +1427,7 @@ sshkey_check_rsa_length(const struct sshkey *k, int min_size) #ifdef WITH_OPENSSL # ifdef OPENSSL_HAS_ECC +# if OPENSSL_VERSION_NUMBER < 0x30000000L static int sshkey_ec_key_to_nid(EC_KEY *k) { @@ -1470,6 +1471,7 @@ sshkey_ec_key_to_nid(EC_KEY *k) } return nids[i]; } +#endif int sshkey_ecdsa_key_to_nid(EVP_PKEY *pkey) diff --git a/sshkey.h b/sshkey.h index 726f7aaa1fc..b030e50c3de 100644 --- a/sshkey.h +++ b/sshkey.h @@ -38,12 +38,18 @@ # 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 */ #define SSH_OPENSSL_VERSION OpenSSL_version(OPENSSL_VERSION) #else /* WITH_OPENSSL */ # define BIGNUM void # define EVP_PKEY void # define DSA void +# define EC_KEY void +# define EC_GROUP void +# define EC_POINT void #define SSH_OPENSSL_VERSION "without OpenSSL" #endif /* WITH_OPENSSL */ @@ -256,6 +262,8 @@ u_int sshkey_curve_nid_to_bits(int); int sshkey_ecdsa_bits_to_nid(int); 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 *); 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); @@ -350,6 +358,13 @@ int pkcs11_get_ecdsa_idx(void); #if !defined(WITH_OPENSSL) # undef EVP_PKEY # undef DSA +# 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 /* SSHKEY_H */ From 2c2ad17619f3e0178dde3ece5e9ab1be1780363f Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 20 Oct 2023 12:52:20 +0200 Subject: [PATCH 18/21] RSA type check --- ssh-rsa.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ssh-rsa.c b/ssh-rsa.c index fcfb0a87dce..a7aeb658eec 100644 --- a/ssh-rsa.c +++ b/ssh-rsa.c @@ -45,8 +45,11 @@ static int openssh_RSA_verify(int, const u_char *, size_t, u_char *, size_t, EVP static u_int ssh_rsa_size(const struct sshkey *k) { + if (sshkey_type_plain(k->type) != KEY_RSA) + return 0; if (k->pkey == NULL) return 0; + return EVP_PKEY_bits(k->pkey); } From 5b360418cf727fc3821a2236f1c5a8c0f5aaa362 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 20 Oct 2023 15:05:55 +0200 Subject: [PATCH 19/21] Dropme! Temporary unbreak interop tests --- sshkey.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sshkey.c b/sshkey.c index 2f7a8d7208f..cfa51b70c3b 100644 --- a/sshkey.c +++ b/sshkey.c @@ -3348,15 +3348,16 @@ 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) +/* #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, - EVP_PKEY_KEYPAIR, + OSSL_KEYMGMT_SELECT_KEYPAIR + | OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, "PEM", - "type-specific", + "PrivateKeyInfo", NULL); if (!ctx) { r = SSH_ERR_LIBCRYPTO_ERROR; @@ -3387,7 +3388,7 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, success = 1; } break; -#else +#else FIXME beldmit */ #ifdef OPENSSL_HAS_ECC case KEY_ECDSA: if (format == SSHKEY_PRIVATE_PEM) { @@ -3414,7 +3415,7 @@ sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, success = 1; } break; -#endif +/* #endif FIXME beldmit */ default: success = 0; break; From 97b792d28740d54e5df41a117fd48a775232c735 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Fri, 20 Oct 2023 22:09:38 +0200 Subject: [PATCH 20/21] We don't use these functions --- ssh-pkcs11-client.c | 28 ---------------------------- ssh-pkcs11.c | 16 ---------------- ssh-pkcs11.h | 7 ------- 3 files changed, 51 deletions(-) diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c index 41269a63e76..157d0dc74f7 100644 --- a/ssh-pkcs11-client.c +++ b/ssh-pkcs11-client.c @@ -430,36 +430,8 @@ ecdsa_do_finish(EC_KEY *ec) if (helper->nrsa == 0 && helper->nec == 0) helper_terminate(helper); } - -int -is_ecdsa_pkcs11(EC_KEY *ecdsa) -{ - const EC_KEY_METHOD *meth; - ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, int dgstlen, - const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey) = NULL; - - meth = EC_KEY_get_method(ecdsa); - EC_KEY_METHOD_get_sign(meth, NULL, NULL, &sign_sig); - if (sign_sig == ecdsa_do_sign) - return 1; - return 0; -} #endif /* defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) */ -int -is_rsa_pkcs11(RSA *rsa) -{ - const RSA_METHOD *meth; - int (*priv_enc)(int flen, const unsigned char *from, - unsigned char *to, RSA *rsa, int padding) = NULL; - - meth = RSA_get_method(rsa); - priv_enc = RSA_meth_get_priv_enc(meth); - if (priv_enc == rsa_encrypt) - return 1; - return 0; -} - /* redirect private key crypto operations to the ssh-pkcs11-helper */ static void wrap_key(struct helper *helper, struct sshkey *k) diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c index 3693da82a80..dea5e5b5e28 100644 --- a/ssh-pkcs11.c +++ b/ssh-pkcs11.c @@ -620,14 +620,6 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, return (0); } - -int -is_ecdsa_pkcs11(EC_KEY *ecdsa) -{ - if (EC_KEY_get_ex_data(ecdsa, ec_key_idx) != NULL) - return 1; - return 0; -} #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ /* remove trailing spaces */ @@ -846,14 +838,6 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, } #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ -int -is_rsa_pkcs11(RSA *rsa) -{ - if (RSA_get_ex_data(rsa, rsa_idx) != NULL) - return 1; - return 0; -} - static struct sshkey * pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj) diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h index 4b5e35f37ea..81f1d7c5d39 100644 --- a/ssh-pkcs11.h +++ b/ssh-pkcs11.h @@ -35,13 +35,6 @@ struct sshkey * u_int32_t *); #endif -#if defined WITH_OPENSSL -#ifdef HAVE_EC_KEY_METHOD_NEW -int is_ecdsa_pkcs11(EC_KEY *ecdsa); -#endif -int is_rsa_pkcs11(RSA *rsa); -#endif - #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) #undef ENABLE_PKCS11 #endif From 6daa8e2d35743c7dd56ec3a49e45dab8674f25b3 Mon Sep 17 00:00:00 2001 From: Dmitry Belyavskiy Date: Thu, 26 Oct 2023 17:46:50 +0200 Subject: [PATCH 21/21] Try to shrink the pubkey dump code --- ssh-keygen.c | 43 +++++-------------------------------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/ssh-keygen.c b/ssh-keygen.c index 3eb88bd0b21..99c414cbe4a 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -375,46 +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)) { -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) - case KEY_RSA: - case KEY_ECDSA: - OSSL_ENCODER_CTX *ctx = OSSL_ENCODER_CTX_new_for_pkey(k->pkey, - EVP_PKEY_PUBLIC_KEY, - "PEM", - "type-specific", - 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; -#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 (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; - default: + } else { fatal_f("unsupported key type %s", sshkey_type(k)); } exit(0);