From mboxrd@z Thu Jan 1 00:00:00 1970 From: Peter Seiderer Date: Tue, 17 Apr 2018 23:19:21 +0200 Subject: [Buildroot] [RFC v1 2/2] openssh: add patch to fix openssl-1.1.0h compile In-Reply-To: <20180417211921.18718-1-ps.report@gmx.net> References: <20180417211921.18718-1-ps.report@gmx.net> Message-ID: <20180417211921.18718-2-ps.report@gmx.net> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: buildroot@busybox.net Signed-off-by: Peter Seiderer --- ...penSSH-7.7p1-to-compile-with-OpenSSL-1.1..patch | 2003 ++++++++++++++++++++ 1 file changed, 2003 insertions(+) create mode 100644 package/openssh/0003-Patch-for-OpenSSH-7.7p1-to-compile-with-OpenSSL-1.1..patch diff --git a/package/openssh/0003-Patch-for-OpenSSH-7.7p1-to-compile-with-OpenSSL-1.1..patch b/package/openssh/0003-Patch-for-OpenSSH-7.7p1-to-compile-with-OpenSSL-1.1..patch new file mode 100644 index 0000000000..fa56168347 --- /dev/null +++ b/package/openssh/0003-Patch-for-OpenSSH-7.7p1-to-compile-with-OpenSSL-1.1..patch @@ -0,0 +1,2003 @@ +From 3dc11277f4d8164258bdf60bd87f3d5edf586d87 Mon Sep 17 00:00:00 2001 +From: Peter Seiderer +Date: Tue, 17 Apr 2018 20:19:24 +0200 +Subject: [PATCH] Patch for OpenSSH-7.7p1 to compile with OpenSSL-1.1.0 + +See [1] for more info and original source, concrete patch taken +from [2]. + +[1] http://vega.pgw.jp/~kabe/vsd/patch/openssh-7.7p1-openssl-1.1.0.patch.html +[2] https://git.archlinux.org/svntogit/packages.git/plain/trunk/openssl-1.1.0.patch?h=packages/openssh + +Signed-off-by: Peter Seiderer +--- + auth-pam.c | 4 + + cipher.c | 18 +- + cipher.h | 11 + + dh.c | 62 ++-- + dh.h | 2 +- + digest-openssl.c | 19 +- + kexdhc.c | 20 +- + kexdhs.c | 18 +- + kexgexc.c | 26 +- + kexgexs.c | 32 +- + monitor.c | 6 +- + openbsd-compat/openssl-compat.c | 1 - + regress/unittests/sshkey/test_file.c | 22 +- + regress/unittests/sshkey/test_sshkey.c | 82 +++-- + ssh-dss.c | 27 +- + ssh-ecdsa.c | 29 +- + ssh-keygen.c | 84 ++++- + ssh-pkcs11-client.c | 11 +- + ssh-pkcs11.c | 47 ++- + ssh-rsa.c | 30 +- + sshkey.c | 562 +++++++++++++++++++++++++++------ + 21 files changed, 877 insertions(+), 236 deletions(-) + +diff --git a/auth-pam.c b/auth-pam.c +index bd0c1b8..60ede8f 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -128,6 +128,10 @@ extern u_int utmp_len; + typedef pthread_t sp_pthread_t; + #else + typedef pid_t sp_pthread_t; ++# define pthread_create(a, b, c, d) _ssh_compat_pthread_create(a, b, c, d) ++# define pthread_exit(a) _ssh_compat_pthread_exit(a) ++# define pthread_cancel(a) _ssh_compat_pthread_cancel(a) ++# define pthread_join(a, b) _ssh_compat_pthread_join(a, b) + #endif + + struct pam_ctxt { +diff --git a/cipher.c b/cipher.c +index 5787636..c337331 100644 +--- a/cipher.c ++++ b/cipher.c +@@ -297,7 +297,10 @@ cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, + goto out; + } + } +- if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) { ++ /* in OpenSSL 1.1.0, EVP_CipherInit clears all previous setups; ++ use EVP_CipherInit_ex for augmenting */ ++ if (EVP_CipherInit_ex(cc->evp, NULL, NULL, (u_char *)key, NULL, -1) == 0) ++ { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -483,7 +486,7 @@ cipher_get_keyiv(struct sshcipher_ctx *cc, u_char *iv, u_int len) + len, iv)) + return SSH_ERR_LIBCRYPTO_ERROR; + } else +- memcpy(iv, cc->evp->iv, len); ++ memcpy(iv, EVP_CIPHER_CTX_iv(cc->evp), len); + #endif + return 0; + } +@@ -517,14 +520,19 @@ cipher_set_keyiv(struct sshcipher_ctx *cc, const u_char *iv) + EVP_CTRL_GCM_SET_IV_FIXED, -1, (void *)iv)) + return SSH_ERR_LIBCRYPTO_ERROR; + } else +- memcpy(cc->evp->iv, iv, evplen); ++ memcpy(EVP_CIPHER_CTX_iv(cc->evp), iv, evplen); + #endif + return 0; + } + + #ifdef WITH_OPENSSL +-#define EVP_X_STATE(evp) (evp)->cipher_data +-#define EVP_X_STATE_LEN(evp) (evp)->cipher->ctx_size ++# if OPENSSL_VERSION_NUMBER >= 0x10100000UL ++#define EVP_X_STATE(evp) EVP_CIPHER_CTX_get_cipher_data(evp) ++#define EVP_X_STATE_LEN(evp) EVP_CIPHER_impl_ctx_size(EVP_CIPHER_CTX_cipher(evp)) ++# else ++#define EVP_X_STATE(evp) (evp).cipher_data ++#define EVP_X_STATE_LEN(evp) (evp).cipher->ctx_size ++# endif + #endif + + int +diff --git a/cipher.h b/cipher.h +index dc7ecf1..268f60a 100644 +--- a/cipher.h ++++ b/cipher.h +@@ -46,7 +46,18 @@ + #define CIPHER_DECRYPT 0 + + struct sshcipher; ++#if 0 ++struct sshcipher_ctx { ++ int plaintext; ++ int encrypt; ++ EVP_CIPHER_CTX *evp; ++ struct chachapoly_ctx cp_ctx; /* XXX union with evp? */ ++ struct aesctr_ctx ac_ctx; /* XXX union with evp? */ ++ const struct sshcipher *cipher; ++}; ++#else + struct sshcipher_ctx; ++#endif + + const struct sshcipher *cipher_by_name(const char *); + const char *cipher_warning_message(const struct sshcipher_ctx *); +diff --git a/dh.c b/dh.c +index 46afba0..d3ae531 100644 +--- a/dh.c ++++ b/dh.c +@@ -211,14 +211,15 @@ choose_dh(int min, int wantbits, int max) + /* diffie-hellman-groupN-sha1 */ + + int +-dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) ++dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) + { + int i; + int n = BN_num_bits(dh_pub); + int bits_set = 0; + BIGNUM *tmp; ++ const BIGNUM *p; + +- if (dh_pub->neg) { ++ if (BN_is_negative(dh_pub)) { + logit("invalid public DH value: negative"); + return 0; + } +@@ -231,7 +232,8 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) + error("%s: BN_new failed", __func__); + return 0; + } +- if (!BN_sub(tmp, dh->p, BN_value_one()) || ++ DH_get0_pqg(dh, &p, NULL, NULL); ++ if (!BN_sub(tmp, p, BN_value_one()) || + BN_cmp(dh_pub, tmp) != -1) { /* pub_exp > p-2 */ + BN_clear_free(tmp); + logit("invalid public DH value: >= p-1"); +@@ -242,14 +244,14 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) + for (i = 0; i <= n; i++) + if (BN_is_bit_set(dh_pub, i)) + bits_set++; +- debug2("bits set: %d/%d", bits_set, BN_num_bits(dh->p)); ++ debug2("bits set: %d/%d", bits_set, BN_num_bits(p)); + + /* + * if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial + */ + if (bits_set < 4) { + logit("invalid public DH value (%d/%d)", +- bits_set, BN_num_bits(dh->p)); ++ bits_set, BN_num_bits(p)); + return 0; + } + return 1; +@@ -259,9 +261,13 @@ int + dh_gen_key(DH *dh, int need) + { + int pbits; ++ const BIGNUM *p, *pub_key; ++ BIGNUM *priv_key; + +- if (need < 0 || dh->p == NULL || +- (pbits = BN_num_bits(dh->p)) <= 0 || ++ DH_get0_pqg(dh, &p, NULL, NULL); ++ ++ if (need < 0 || p == NULL || ++ (pbits = BN_num_bits(p)) <= 0 || + need > INT_MAX / 2 || 2 * need > pbits) + return SSH_ERR_INVALID_ARGUMENT; + if (need < 256) +@@ -270,10 +276,13 @@ dh_gen_key(DH *dh, int need) + * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), + * so double requested need here. + */ +- dh->length = MINIMUM(need * 2, pbits - 1); +- if (DH_generate_key(dh) == 0 || +- !dh_pub_is_valid(dh, dh->pub_key)) { +- BN_clear_free(dh->priv_key); ++ DH_set_length(dh, MIN(need * 2, pbits - 1)); ++ if (DH_generate_key(dh) == 0) { ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ DH_get0_key(dh, &pub_key, &priv_key); ++ if (!dh_pub_is_valid(dh, pub_key)) { ++ BN_clear(priv_key); + return SSH_ERR_LIBCRYPTO_ERROR; + } + return 0; +@@ -282,16 +291,27 @@ dh_gen_key(DH *dh, int need) + DH * + dh_new_group_asc(const char *gen, const char *modulus) + { +- DH *dh; +- +- if ((dh = DH_new()) == NULL) +- return NULL; +- if (BN_hex2bn(&dh->p, modulus) == 0 || +- BN_hex2bn(&dh->g, gen) == 0) { +- DH_free(dh); +- return NULL; ++ DH *dh = NULL; ++ BIGNUM *p=NULL, *g=NULL; ++ ++ if ((dh = DH_new()) == NULL || ++ (p = BN_new()) == NULL || ++ (g = BN_new()) == NULL) ++ goto null; ++ if (BN_hex2bn(&p, modulus) == 0 || ++ BN_hex2bn(&g, gen) == 0) { ++ goto null; + } ++ if (DH_set0_pqg(dh, p, NULL, g) == 0) { ++ goto null; ++ } ++ p = g = NULL; + return (dh); ++null: ++ BN_free(p); ++ BN_free(g); ++ DH_free(dh); ++ return NULL; + } + + /* +@@ -306,8 +326,8 @@ dh_new_group(BIGNUM *gen, BIGNUM *modulus) + + if ((dh = DH_new()) == NULL) + return NULL; +- dh->p = modulus; +- dh->g = gen; ++ if (DH_set0_pqg(dh, modulus, NULL, gen) == 0) ++ return NULL; + + return (dh); + } +diff --git a/dh.h b/dh.h +index bcd485c..344b29e 100644 +--- a/dh.h ++++ b/dh.h +@@ -42,7 +42,7 @@ DH *dh_new_group18(void); + DH *dh_new_group_fallback(int); + + int dh_gen_key(DH *, int); +-int dh_pub_is_valid(DH *, BIGNUM *); ++int dh_pub_is_valid(const DH *, const BIGNUM *); + + u_int dh_estimate(int); + +diff --git a/digest-openssl.c b/digest-openssl.c +index 2770999..c24cf34 100644 +--- a/digest-openssl.c ++++ b/digest-openssl.c +@@ -43,7 +43,7 @@ + + struct ssh_digest_ctx { + int alg; +- EVP_MD_CTX mdctx; ++ EVP_MD_CTX *mdctx; + }; + + struct ssh_digest { +@@ -106,20 +106,21 @@ ssh_digest_bytes(int alg) + size_t + ssh_digest_blocksize(struct ssh_digest_ctx *ctx) + { +- return EVP_MD_CTX_block_size(&ctx->mdctx); ++ return EVP_MD_CTX_block_size(ctx->mdctx); + } + + struct ssh_digest_ctx * + ssh_digest_start(int alg) + { + const struct ssh_digest *digest = ssh_digest_by_alg(alg); +- struct ssh_digest_ctx *ret; ++ struct ssh_digest_ctx *ret = NULL; + + if (digest == NULL || ((ret = calloc(1, sizeof(*ret))) == NULL)) + return NULL; + ret->alg = alg; +- EVP_MD_CTX_init(&ret->mdctx); +- if (EVP_DigestInit_ex(&ret->mdctx, digest->mdfunc(), NULL) != 1) { ++ if ((ret->mdctx = EVP_MD_CTX_new()) == NULL || ++ EVP_DigestInit_ex(ret->mdctx, digest->mdfunc(), NULL) != 1) { ++ EVP_MD_CTX_free(ret->mdctx); + free(ret); + return NULL; + } +@@ -132,7 +133,7 @@ ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) + if (from->alg != to->alg) + return SSH_ERR_INVALID_ARGUMENT; + /* we have bcopy-style order while openssl has memcpy-style */ +- if (!EVP_MD_CTX_copy_ex(&to->mdctx, &from->mdctx)) ++ if (!EVP_MD_CTX_copy_ex(to->mdctx, from->mdctx)) + return SSH_ERR_LIBCRYPTO_ERROR; + return 0; + } +@@ -140,7 +141,7 @@ ssh_digest_copy_state(struct ssh_digest_ctx *from, struct ssh_digest_ctx *to) + int + ssh_digest_update(struct ssh_digest_ctx *ctx, const void *m, size_t mlen) + { +- if (EVP_DigestUpdate(&ctx->mdctx, m, mlen) != 1) ++ if (EVP_DigestUpdate(ctx->mdctx, m, mlen) != 1) + return SSH_ERR_LIBCRYPTO_ERROR; + return 0; + } +@@ -161,7 +162,7 @@ ssh_digest_final(struct ssh_digest_ctx *ctx, u_char *d, size_t dlen) + return SSH_ERR_INVALID_ARGUMENT; + if (dlen < digest->digest_len) /* No truncation allowed */ + return SSH_ERR_INVALID_ARGUMENT; +- if (EVP_DigestFinal_ex(&ctx->mdctx, d, &l) != 1) ++ if (EVP_DigestFinal_ex(ctx->mdctx, d, &l) != 1) + return SSH_ERR_LIBCRYPTO_ERROR; + if (l != digest->digest_len) /* sanity */ + return SSH_ERR_INTERNAL_ERROR; +@@ -172,7 +173,7 @@ void + ssh_digest_free(struct ssh_digest_ctx *ctx) + { + if (ctx != NULL) { +- EVP_MD_CTX_cleanup(&ctx->mdctx); ++ EVP_MD_CTX_free(ctx->mdctx); + explicit_bzero(ctx, sizeof(*ctx)); + free(ctx); + } +diff --git a/kexdhc.c b/kexdhc.c +index 9a9f1ea..e5ea825 100644 +--- a/kexdhc.c ++++ b/kexdhc.c +@@ -81,11 +81,16 @@ kexdh_client(struct ssh *ssh) + goto out; + } + debug("sending SSH2_MSG_KEXDH_INIT"); +- if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || +- (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 || +- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || ++ { ++ const BIGNUM *pub_key; ++ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) ++ goto out; ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || + (r = sshpkt_send(ssh)) != 0) + goto out; ++ } + #ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, kex->dh); + fprintf(stderr, "pub= "); +@@ -169,6 +174,9 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh) + + /* calc and verify H */ + hashlen = sizeof(hash); ++ { ++ const BIGNUM *pub_key; ++ DH_get0_key(kex->dh, &pub_key, NULL); + if ((r = kex_dh_hash( + kex->hash_alg, + kex->client_version_string, +@@ -176,11 +184,13 @@ input_kex_dh(int type, u_int32_t seq, struct ssh *ssh) + sshbuf_ptr(kex->my), sshbuf_len(kex->my), + sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), + server_host_key_blob, sbloblen, +- kex->dh->pub_key, ++ pub_key, + dh_server_pub, + shared_secret, +- hash, &hashlen)) != 0) ++ hash, &hashlen)) != 0) { + goto out; ++ } ++ } + + if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, + kex->hostkey_alg, ssh->compat)) != 0) +diff --git a/kexdhs.c b/kexdhs.c +index da8f4c4..d5b57b1 100644 +--- a/kexdhs.c ++++ b/kexdhs.c +@@ -163,6 +163,9 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh) + goto out; + /* calc H */ + hashlen = sizeof(hash); ++ { ++ const BIGNUM *pub_key; ++ DH_get0_key(kex->dh, &pub_key, NULL); + if ((r = kex_dh_hash( + kex->hash_alg, + kex->client_version_string, +@@ -171,10 +174,12 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh) + sshbuf_ptr(kex->my), sshbuf_len(kex->my), + server_host_key_blob, sbloblen, + dh_client_pub, +- kex->dh->pub_key, ++ pub_key, + shared_secret, +- hash, &hashlen)) != 0) ++ hash, &hashlen)) != 0) { + goto out; ++ } ++ } + + /* save session id := H */ + if (kex->session_id == NULL) { +@@ -195,12 +200,17 @@ input_kex_dh_init(int type, u_int32_t seq, struct ssh *ssh) + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ ++ { ++ const BIGNUM *pub_key; ++ DH_get0_key(kex->dh, &pub_key, NULL); + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 || + (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || +- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || /* f */ + (r = sshpkt_put_string(ssh, signature, slen)) != 0 || +- (r = sshpkt_send(ssh)) != 0) ++ (r = sshpkt_send(ssh)) != 0) { + goto out; ++ } ++ } + + if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); +diff --git a/kexgexc.c b/kexgexc.c +index 762a9a3..c30d8c3 100644 +--- a/kexgexc.c ++++ b/kexgexc.c +@@ -118,11 +118,17 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh) + p = g = NULL; /* belong to kex->dh now */ + + /* generate and send 'e', client DH public key */ +- if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || +- (r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 || +- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || +- (r = sshpkt_send(ssh)) != 0) ++ { ++ const BIGNUM *pub_key; ++ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) ++ goto out; ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) { + goto out; ++ } ++ } + debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); + #ifdef DEBUG_KEXDH + DHparams_print_fp(stderr, kex->dh); +@@ -212,6 +218,10 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) + + /* calc and verify H */ + hashlen = sizeof(hash); ++ { ++ const BIGNUM *p, *g, *pub_key; ++ DH_get0_pqg(kex->dh, &p, NULL, &g); ++ DH_get0_key(kex->dh, &pub_key, NULL); + if ((r = kexgex_hash( + kex->hash_alg, + kex->client_version_string, +@@ -220,12 +230,14 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) + sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), + server_host_key_blob, sbloblen, + kex->min, kex->nbits, kex->max, +- kex->dh->p, kex->dh->g, +- kex->dh->pub_key, ++ p, g, ++ pub_key, + dh_server_pub, + shared_secret, +- hash, &hashlen)) != 0) ++ hash, &hashlen)) != 0) { + goto out; ++ } ++ } + + if ((r = sshkey_verify(server_host_key, signature, slen, hash, + hashlen, kex->hostkey_alg, ssh->compat)) != 0) +diff --git a/kexgexs.c b/kexgexs.c +index d7b48ea..992a390 100644 +--- a/kexgexs.c ++++ b/kexgexs.c +@@ -101,11 +101,16 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh) + goto out; + } + debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); ++ { ++ const BIGNUM *p, *g; ++ DH_get0_pqg(kex->dh, &p, NULL, &g); + if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 || +- (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 || +- (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 || +- (r = sshpkt_send(ssh)) != 0) ++ (r = sshpkt_put_bignum2(ssh, p)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, g)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) { + goto out; ++ } ++ } + + /* Compute our exchange value in parallel with the client */ + if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) +@@ -191,6 +196,10 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh) + goto out; + /* calc H */ + hashlen = sizeof(hash); ++ { ++ const BIGNUM *p, *g, *pub_key; ++ DH_get0_pqg(kex->dh, &p, NULL, &g); ++ DH_get0_key(kex->dh, &pub_key, NULL); + if ((r = kexgex_hash( + kex->hash_alg, + kex->client_version_string, +@@ -199,12 +208,14 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh) + sshbuf_ptr(kex->my), sshbuf_len(kex->my), + server_host_key_blob, sbloblen, + kex->min, kex->nbits, kex->max, +- kex->dh->p, kex->dh->g, ++ p, g, + dh_client_pub, +- kex->dh->pub_key, ++ pub_key, + shared_secret, +- hash, &hashlen)) != 0) ++ hash, &hashlen)) != 0) { + goto out; ++ } ++ } + + /* save session id := H */ + if (kex->session_id == NULL) { +@@ -225,12 +236,17 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh) + /* destroy_sensitive_data(); */ + + /* send server hostkey, DH pubkey 'f' and singed H */ ++ { ++ const BIGNUM *pub_key; ++ DH_get0_key(kex->dh, &pub_key, NULL); + if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || + (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || +- (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || /* f */ + (r = sshpkt_put_string(ssh, signature, slen)) != 0 || +- (r = sshpkt_send(ssh)) != 0) ++ (r = sshpkt_send(ssh)) != 0) { + goto out; ++ } ++ } + + if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); +diff --git a/monitor.c b/monitor.c +index c68e1b0..64d5475 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -595,10 +595,12 @@ mm_answer_moduli(int sock, Buffer *m) + buffer_put_char(m, 0); + return (0); + } else { ++ const BIGNUM *p, *g; ++ DH_get0_pqg(dh, &p, NULL, &g); + /* Send first bignum */ + buffer_put_char(m, 1); +- buffer_put_bignum2(m, dh->p); +- buffer_put_bignum2(m, dh->g); ++ buffer_put_bignum2(m, p); ++ buffer_put_bignum2(m, g); + + DH_free(dh); + } +diff --git a/openbsd-compat/openssl-compat.c b/openbsd-compat/openssl-compat.c +index 259fccb..02bf3e1 100644 +--- a/openbsd-compat/openssl-compat.c ++++ b/openbsd-compat/openssl-compat.c +@@ -75,7 +75,6 @@ ssh_OpenSSL_add_all_algorithms(void) + /* Enable use of crypto hardware */ + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); +- OPENSSL_config(NULL); + } + #endif + +diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c +index 99b7e21..d4d7934 100644 +--- a/regress/unittests/sshkey/test_file.c ++++ b/regress/unittests/sshkey/test_file.c +@@ -60,9 +60,14 @@ sshkey_file_tests(void) + a = load_bignum("rsa_1.param.n"); + b = load_bignum("rsa_1.param.p"); + c = load_bignum("rsa_1.param.q"); +- ASSERT_BIGNUM_EQ(k1->rsa->n, a); +- ASSERT_BIGNUM_EQ(k1->rsa->p, b); +- ASSERT_BIGNUM_EQ(k1->rsa->q, c); ++ { ++ const BIGNUM *n, *p, *q; ++ RSA_get0_key(k1->rsa, &n, NULL, NULL); ++ RSA_get0_factors(k1->rsa, &p, &q); ++ ASSERT_BIGNUM_EQ(n, a); ++ ASSERT_BIGNUM_EQ(p, b); ++ ASSERT_BIGNUM_EQ(q, c); ++ } + BN_free(a); + BN_free(b); + BN_free(c); +@@ -151,9 +156,14 @@ sshkey_file_tests(void) + a = load_bignum("dsa_1.param.g"); + b = load_bignum("dsa_1.param.priv"); + c = load_bignum("dsa_1.param.pub"); +- ASSERT_BIGNUM_EQ(k1->dsa->g, a); +- ASSERT_BIGNUM_EQ(k1->dsa->priv_key, b); +- ASSERT_BIGNUM_EQ(k1->dsa->pub_key, c); ++ { ++ const BIGNUM *g, *priv_key, *pub_key; ++ DSA_get0_pqg(k1->dsa, NULL, NULL, &g); ++ DSA_get0_key(k1->dsa, &pub_key, &priv_key); ++ ASSERT_BIGNUM_EQ(g, a); ++ ASSERT_BIGNUM_EQ(priv_key, b); ++ ASSERT_BIGNUM_EQ(pub_key, c); ++ } + 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 1aa608f..6181d50 100644 +--- a/regress/unittests/sshkey/test_sshkey.c ++++ b/regress/unittests/sshkey/test_sshkey.c +@@ -197,9 +197,14 @@ sshkey_tests(void) + k1 = sshkey_new(KEY_RSA); + ASSERT_PTR_NE(k1, NULL); + ASSERT_PTR_NE(k1->rsa, NULL); +- ASSERT_PTR_NE(k1->rsa->n, NULL); +- ASSERT_PTR_NE(k1->rsa->e, NULL); +- ASSERT_PTR_EQ(k1->rsa->p, NULL); ++ { ++ const BIGNUM *n, *e, *p; ++ RSA_get0_key(k1->rsa, &n, &e, NULL); ++ RSA_get0_factors(k1->rsa, &p, NULL); ++ ASSERT_PTR_NE(n, NULL); ++ ASSERT_PTR_NE(e, NULL); ++ ASSERT_PTR_EQ(p, NULL); ++ } + sshkey_free(k1); + TEST_DONE(); + +@@ -207,8 +212,13 @@ sshkey_tests(void) + k1 = sshkey_new(KEY_DSA); + ASSERT_PTR_NE(k1, NULL); + ASSERT_PTR_NE(k1->dsa, NULL); +- ASSERT_PTR_NE(k1->dsa->g, NULL); +- ASSERT_PTR_EQ(k1->dsa->priv_key, NULL); ++ { ++ const BIGNUM *g, *priv_key; ++ DSA_get0_pqg(k1->dsa, NULL, NULL, &g); ++ DSA_get0_key(k1->dsa, NULL, &priv_key); ++ ASSERT_PTR_NE(g, NULL); ++ ASSERT_PTR_EQ(priv_key, NULL); ++ } + sshkey_free(k1); + TEST_DONE(); + +@@ -234,9 +244,14 @@ sshkey_tests(void) + k1 = sshkey_new_private(KEY_RSA); + ASSERT_PTR_NE(k1, NULL); + ASSERT_PTR_NE(k1->rsa, NULL); +- ASSERT_PTR_NE(k1->rsa->n, NULL); +- ASSERT_PTR_NE(k1->rsa->e, NULL); +- ASSERT_PTR_NE(k1->rsa->p, NULL); ++ { ++ const BIGNUM *n, *e, *p; ++ RSA_get0_key(k1->rsa, &n, &e, NULL); ++ RSA_get0_factors(k1->rsa, &p, NULL); ++ ASSERT_PTR_NE(n, NULL); ++ ASSERT_PTR_NE(e, NULL); ++ ASSERT_PTR_NE(p, NULL); ++ } + ASSERT_INT_EQ(sshkey_add_private(k1), 0); + sshkey_free(k1); + TEST_DONE(); +@@ -245,8 +260,13 @@ sshkey_tests(void) + k1 = sshkey_new_private(KEY_DSA); + ASSERT_PTR_NE(k1, NULL); + ASSERT_PTR_NE(k1->dsa, NULL); +- ASSERT_PTR_NE(k1->dsa->g, NULL); +- ASSERT_PTR_NE(k1->dsa->priv_key, NULL); ++ { ++ const BIGNUM *g, *priv_key; ++ DSA_get0_pqg(k1->dsa, NULL, NULL, &g); ++ DSA_get0_key(k1->dsa, NULL, &priv_key); ++ ASSERT_PTR_NE(g, NULL); ++ ASSERT_PTR_NE(priv_key, NULL); ++ } + ASSERT_INT_EQ(sshkey_add_private(k1), 0); + sshkey_free(k1); + TEST_DONE(); +@@ -285,18 +305,28 @@ sshkey_tests(void) + ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &kr), 0); + ASSERT_PTR_NE(kr, NULL); + ASSERT_PTR_NE(kr->rsa, NULL); +- ASSERT_PTR_NE(kr->rsa->n, NULL); +- ASSERT_PTR_NE(kr->rsa->e, NULL); +- ASSERT_PTR_NE(kr->rsa->p, NULL); +- ASSERT_INT_EQ(BN_num_bits(kr->rsa->n), 1024); ++ { ++ const BIGNUM *n, *e, *p; ++ RSA_get0_key(kr->rsa, &n, &e, NULL); ++ RSA_get0_factors(kr->rsa, &p, NULL); ++ ASSERT_PTR_NE(n, NULL); ++ ASSERT_PTR_NE(e, NULL); ++ ASSERT_PTR_NE(p, NULL); ++ ASSERT_INT_EQ(BN_num_bits(n), 1024); ++ } + TEST_DONE(); + + TEST_START("generate KEY_DSA"); + ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &kd), 0); + ASSERT_PTR_NE(kd, NULL); + ASSERT_PTR_NE(kd->dsa, NULL); +- ASSERT_PTR_NE(kd->dsa->g, NULL); +- ASSERT_PTR_NE(kd->dsa->priv_key, NULL); ++ { ++ const BIGNUM *g, *priv_key; ++ DSA_get0_pqg(kd->dsa, NULL, NULL, &g); ++ DSA_get0_key(kd->dsa, NULL, &priv_key); ++ ASSERT_PTR_NE(g, NULL); ++ ASSERT_PTR_NE(priv_key, NULL); ++ } + TEST_DONE(); + + #ifdef OPENSSL_HAS_ECC +@@ -323,9 +353,14 @@ sshkey_tests(void) + ASSERT_PTR_NE(kr, k1); + ASSERT_INT_EQ(k1->type, KEY_RSA); + ASSERT_PTR_NE(k1->rsa, NULL); +- ASSERT_PTR_NE(k1->rsa->n, NULL); +- ASSERT_PTR_NE(k1->rsa->e, NULL); +- ASSERT_PTR_EQ(k1->rsa->p, NULL); ++ { ++ const BIGNUM *n, *e, *p; ++ RSA_get0_key(k1->rsa, &n, &e, NULL); ++ RSA_get0_factors(k1->rsa, &p, NULL); ++ ASSERT_PTR_NE(n, NULL); ++ ASSERT_PTR_NE(e, NULL); ++ ASSERT_PTR_EQ(p, NULL); ++ } + TEST_DONE(); + + TEST_START("equal KEY_RSA/demoted KEY_RSA"); +@@ -339,8 +374,13 @@ sshkey_tests(void) + ASSERT_PTR_NE(kd, k1); + ASSERT_INT_EQ(k1->type, KEY_DSA); + ASSERT_PTR_NE(k1->dsa, NULL); +- ASSERT_PTR_NE(k1->dsa->g, NULL); +- ASSERT_PTR_EQ(k1->dsa->priv_key, NULL); ++ { ++ const BIGNUM *g, *priv_key; ++ DSA_get0_pqg(k1->dsa, NULL, NULL, &g); ++ DSA_get0_key(k1->dsa, NULL, &priv_key); ++ ASSERT_PTR_NE(g, NULL); ++ ASSERT_PTR_EQ(priv_key, NULL); ++ } + TEST_DONE(); + + TEST_START("equal KEY_DSA/demoted KEY_DSA"); +diff --git a/ssh-dss.c b/ssh-dss.c +index 9f832ee..f9e30a6 100644 +--- a/ssh-dss.c ++++ b/ssh-dss.c +@@ -53,6 +53,7 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, + DSA_SIG *sig = NULL; + u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; + size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); ++ const BIGNUM *r, *s; + struct sshbuf *b = NULL; + int ret = SSH_ERR_INVALID_ARGUMENT; + +@@ -76,15 +77,16 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, + goto out; + } + +- rlen = BN_num_bytes(sig->r); +- slen = BN_num_bytes(sig->s); ++ DSA_SIG_get0(sig, &r, &s); ++ rlen = BN_num_bytes(r); ++ slen = BN_num_bytes(s); + if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) { + ret = SSH_ERR_INTERNAL_ERROR; + goto out; + } + explicit_bzero(sigblob, SIGBLOB_LEN); +- BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); +- BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen); ++ BN_bn2bin(r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen); ++ BN_bn2bin(s, sigblob + SIGBLOB_LEN - slen); + + if ((b = sshbuf_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; +@@ -154,17 +156,26 @@ ssh_dss_verify(const struct sshkey *key, + } + + /* parse signature */ ++ { ++ BIGNUM *r=NULL, *s=NULL; + if ((sig = DSA_SIG_new()) == NULL || +- (sig->r = BN_new()) == NULL || +- (sig->s = BN_new()) == NULL) { ++ (r = BN_new()) == NULL || ++ (s = BN_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; ++ BN_free(r); ++ BN_free(s); + goto out; + } +- if ((BN_bin2bn(sigblob, INTBLOB_LEN, sig->r) == NULL) || +- (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s) == NULL)) { ++ if ((BN_bin2bn(sigblob, INTBLOB_LEN, r) == NULL) || ++ (BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, s) == NULL)) { + ret = SSH_ERR_LIBCRYPTO_ERROR; ++ BN_free(r); ++ BN_free(s); + goto out; + } ++ DSA_SIG_set0(sig, r, s); ++ r = s = NULL; ++ } + + /* sha1 the data */ + if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, +diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c +index 3d3b78d..893129b 100644 +--- a/ssh-ecdsa.c ++++ b/ssh-ecdsa.c +@@ -80,9 +80,14 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 || +- (ret = sshbuf_put_bignum2(bb, sig->s)) != 0) ++ { ++ const BIGNUM *r, *s; ++ ECDSA_SIG_get0(sig, &r, &s); ++ if ((ret = sshbuf_put_bignum2(bb, r)) != 0 || ++ (ret = sshbuf_put_bignum2(bb, s)) != 0) { + goto out; ++ } ++ } + if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 || + (ret = sshbuf_put_stringb(b, bb)) != 0) + goto out; +@@ -150,11 +155,27 @@ ssh_ecdsa_verify(const struct sshkey *key, + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 || +- sshbuf_get_bignum2(sigbuf, sig->s) != 0) { ++ { ++ BIGNUM *r=NULL, *s=NULL; ++ if ((r = BN_new()) == NULL || ++ (s = BN_new()) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto out_rs; ++ } ++ if (sshbuf_get_bignum2(sigbuf, r) != 0 || ++ sshbuf_get_bignum2(sigbuf, s) != 0) { + ret = SSH_ERR_INVALID_FORMAT; ++ goto out_rs; ++ } ++ if (ECDSA_SIG_set0(sig, r, s) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++out_rs: ++ BN_free(r); ++ BN_free(s); + goto out; + } ++ r = s = NULL; ++ } + if (sshbuf_len(sigbuf) != 0) { + ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; + goto out; +diff --git a/ssh-keygen.c b/ssh-keygen.c +index 9aac64f..7b71ff9 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -493,11 +493,33 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) + + switch (key->type) { + case KEY_DSA: +- buffer_get_bignum_bits(b, key->dsa->p); +- buffer_get_bignum_bits(b, key->dsa->g); +- buffer_get_bignum_bits(b, key->dsa->q); +- buffer_get_bignum_bits(b, key->dsa->pub_key); +- buffer_get_bignum_bits(b, key->dsa->priv_key); ++ { ++ BIGNUM *p=NULL, *g=NULL, *q=NULL, *pub_key=NULL, *priv_key=NULL; ++ if ((p=BN_new()) == NULL || ++ (g=BN_new()) == NULL || ++ (q=BN_new()) == NULL || ++ (pub_key=BN_new()) == NULL || ++ (priv_key=BN_new()) == NULL) { ++ BN_free(p); ++ BN_free(g); ++ BN_free(q); ++ BN_free(pub_key); ++ BN_free(priv_key); ++ return NULL; ++ } ++ buffer_get_bignum_bits(b, p); ++ buffer_get_bignum_bits(b, g); ++ buffer_get_bignum_bits(b, q); ++ buffer_get_bignum_bits(b, pub_key); ++ buffer_get_bignum_bits(b, priv_key); ++ if (DSA_set0_pqg(key->dsa, p, q, g) == 0 || ++ DSA_set0_key(key->dsa, pub_key, priv_key) == 0) { ++ fatal("failed to set DSA key"); ++ BN_free(p); BN_free(g); BN_free(q); ++ BN_free(pub_key); BN_free(priv_key); ++ return NULL; ++ } ++ } + break; + case KEY_RSA: + if ((r = sshbuf_get_u8(b, &e1)) != 0 || +@@ -514,16 +536,52 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) + e += e3; + debug("e %lx", e); + } +- if (!BN_set_word(key->rsa->e, e)) { ++ { ++ BIGNUM *rsa_e = NULL; ++ BIGNUM *d=NULL, *n=NULL, *iqmp=NULL, *q=NULL, *p=NULL; ++ BIGNUM *dmp1=NULL, *dmq1=NULL; /* dummy input to set in RSA_set0_crt_params */ ++ rsa_e = BN_new(); ++ if (!rsa_e || !BN_set_word(rsa_e, e)) { ++ if (rsa_e) BN_free(rsa_e); + sshbuf_free(b); + sshkey_free(key); + return NULL; + } +- buffer_get_bignum_bits(b, key->rsa->d); +- buffer_get_bignum_bits(b, key->rsa->n); +- buffer_get_bignum_bits(b, key->rsa->iqmp); +- buffer_get_bignum_bits(b, key->rsa->q); +- buffer_get_bignum_bits(b, key->rsa->p); ++ if ((d=BN_new()) == NULL || ++ (n=BN_new()) == NULL || ++ (iqmp=BN_new()) == NULL || ++ (q=BN_new()) == NULL || ++ (p=BN_new()) == NULL || ++ (dmp1=BN_new()) == NULL || ++ (dmq1=BN_new()) == NULL) { ++ BN_free(d); BN_free(n); BN_free(iqmp); ++ BN_free(q); BN_free(p); ++ BN_free(dmp1); BN_free(dmq1); ++ return NULL; ++ } ++ BN_clear(dmp1); BN_clear(dmq1); ++ buffer_get_bignum_bits(b, d); ++ buffer_get_bignum_bits(b, n); ++ buffer_get_bignum_bits(b, iqmp); ++ buffer_get_bignum_bits(b, q); ++ buffer_get_bignum_bits(b, p); ++ if (RSA_set0_key(key->rsa, n, rsa_e, d) == 0) ++ goto null; ++ n = d = NULL; ++ if (RSA_set0_factors(key->rsa, p, q) == 0) ++ goto null; ++ p = q = NULL; ++ /* dmp1, dmq1 should not be NULL for initial set0 */ ++ if (RSA_set0_crt_params(key->rsa, dmp1, dmq1, iqmp) == 0) { ++ null: ++ fatal("Failed to set RSA parameters"); ++ BN_free(d); BN_free(n); BN_free(iqmp); ++ BN_free(q); BN_free(p); ++ BN_free(dmp1); BN_free(dmq1); ++ return NULL; ++ } ++ dmp1 = dmq1 = iqmp = NULL; ++ } + if ((r = ssh_rsa_generate_additional_parameters(key)) != 0) + fatal("generate RSA parameters failed: %s", ssh_err(r)); + break; +@@ -633,7 +691,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) + identity_file); + } + fclose(fp); +- switch (EVP_PKEY_type(pubkey->type)) { ++ switch (EVP_PKEY_type(EVP_PKEY_id(pubkey))) { + case EVP_PKEY_RSA: + if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) + fatal("sshkey_new failed"); +@@ -657,7 +715,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private) + #endif + default: + fatal("%s: unsupported pubkey type %d", __func__, +- EVP_PKEY_type(pubkey->type)); ++ EVP_PKEY_type(EVP_PKEY_id(pubkey))); + } + EVP_PKEY_free(pubkey); + return; +diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c +index fc75828..48f9cbb 100644 +--- a/ssh-pkcs11-client.c ++++ b/ssh-pkcs11-client.c +@@ -144,12 +144,13 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, + static int + wrap_key(RSA *rsa) + { +- static RSA_METHOD helper_rsa; ++ static RSA_METHOD *helper_rsa; + +- memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa)); +- helper_rsa.name = "ssh-pkcs11-helper"; +- helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt; +- RSA_set_method(rsa, &helper_rsa); ++ if ((helper_rsa = RSA_meth_dup(RSA_get_default_method())) == NULL) ++ return (-1); /* XXX but caller isn't checking */ ++ RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper"); ++ RSA_meth_set_priv_enc(helper_rsa, pkcs11_rsa_private_encrypt); ++ RSA_set_method(rsa, helper_rsa); + return (0); + } + +diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c +index 65a7b58..a2358b5 100644 +--- a/ssh-pkcs11.c ++++ b/ssh-pkcs11.c +@@ -67,7 +67,7 @@ struct pkcs11_key { + struct pkcs11_provider *provider; + CK_ULONG slotidx; + int (*orig_finish)(RSA *rsa); +- RSA_METHOD rsa_method; ++ RSA_METHOD *rsa_method; + char *keyid; + int keyid_len; + }; +@@ -326,13 +326,15 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, + k11->keyid = xmalloc(k11->keyid_len); + memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); + } +- k11->orig_finish = def->finish; +- memcpy(&k11->rsa_method, def, sizeof(k11->rsa_method)); +- k11->rsa_method.name = "pkcs11"; +- k11->rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt; +- k11->rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt; +- k11->rsa_method.finish = pkcs11_rsa_finish; +- RSA_set_method(rsa, &k11->rsa_method); ++ k11->orig_finish = RSA_meth_get_finish(def); ++ ++ if ((k11->rsa_method = RSA_meth_new("pkcs11", RSA_meth_get_flags(def))) == NULL) ++ return -1; ++ RSA_meth_set_priv_enc(k11->rsa_method, pkcs11_rsa_private_encrypt); ++ RSA_meth_set_priv_dec(k11->rsa_method, pkcs11_rsa_private_decrypt); ++ RSA_meth_set_finish(k11->rsa_method, pkcs11_rsa_finish); ++ ++ RSA_set_method(rsa, k11->rsa_method); + RSA_set_app_data(rsa, k11); + return (0); + } +@@ -512,10 +514,19 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, + if ((rsa = RSA_new()) == NULL) { + error("RSA_new failed"); + } else { +- rsa->n = BN_bin2bn(attribs[1].pValue, +- attribs[1].ulValueLen, NULL); +- rsa->e = BN_bin2bn(attribs[2].pValue, +- attribs[2].ulValueLen, NULL); ++ BIGNUM *n=NULL, *e=NULL; ++ n = BN_new(); ++ e = BN_new(); ++ if (n == NULL || e == NULL) ++ error("BN_new alloc failed"); ++ if (BN_bin2bn(attribs[1].pValue, ++ attribs[1].ulValueLen, n) == NULL || ++ BN_bin2bn(attribs[2].pValue, ++ attribs[2].ulValueLen, e) == NULL) ++ error("BN_bin2bn failed"); ++ if (RSA_set0_key(rsa, n, e, NULL) == 0) ++ error("RSA_set0_key failed"); ++ n = e = NULL; + } + } else { + cp = attribs[2].pValue; +@@ -525,16 +536,19 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, + == NULL) { + error("d2i_X509 failed"); + } else if ((evp = X509_get_pubkey(x509)) == NULL || +- evp->type != EVP_PKEY_RSA || +- evp->pkey.rsa == NULL) { ++ EVP_PKEY_id(evp) != EVP_PKEY_RSA || ++ EVP_PKEY_get0_RSA(evp) == NULL) { + debug("X509_get_pubkey failed or no rsa"); +- } else if ((rsa = RSAPublicKey_dup(evp->pkey.rsa)) ++ } else if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp))) + == NULL) { + error("RSAPublicKey_dup"); + } + X509_free(x509); + } +- if (rsa && rsa->n && rsa->e && ++ { ++ const BIGNUM *n, *e; ++ RSA_get0_key(rsa, &n, &e, NULL); ++ if (rsa && n && e && + pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { + if ((key = sshkey_new(KEY_UNSPEC)) == NULL) + fatal("sshkey_new failed"); +@@ -554,6 +568,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, + } else if (rsa) { + RSA_free(rsa); + } ++ } + for (i = 0; i < 3; i++) + free(attribs[i].pValue); + } +diff --git a/ssh-rsa.c b/ssh-rsa.c +index 49e71c8..b7c2206 100644 +--- a/ssh-rsa.c ++++ b/ssh-rsa.c +@@ -84,7 +84,6 @@ ssh_rsa_generate_additional_parameters(struct sshkey *key) + { + BIGNUM *aux = NULL; + BN_CTX *ctx = NULL; +- BIGNUM d; + int r; + + if (key == NULL || key->rsa == NULL || +@@ -99,16 +98,27 @@ ssh_rsa_generate_additional_parameters(struct sshkey *key) + } + BN_set_flags(aux, BN_FLG_CONSTTIME); + +- BN_init(&d); +- BN_with_flags(&d, key->rsa->d, BN_FLG_CONSTTIME); +- +- if ((BN_sub(aux, key->rsa->q, BN_value_one()) == 0) || +- (BN_mod(key->rsa->dmq1, &d, aux, ctx) == 0) || +- (BN_sub(aux, key->rsa->p, BN_value_one()) == 0) || +- (BN_mod(key->rsa->dmp1, &d, aux, ctx) == 0)) { ++ { ++ const BIGNUM *q, *d, *p; ++ BIGNUM *dmq1=NULL, *dmp1=NULL; ++ if ((dmq1 = BN_new()) == NULL || ++ (dmp1 = BN_new()) == NULL ) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ RSA_get0_key(key->rsa, NULL, NULL, &d); ++ RSA_get0_factors(key->rsa, &p, &q); ++ if ((BN_sub(aux, q, BN_value_one()) == 0) || ++ (BN_mod(dmq1, d, aux, ctx) == 0) || ++ (BN_sub(aux, p, BN_value_one()) == 0) || ++ (BN_mod(dmp1, d, aux, ctx) == 0) || ++ RSA_set0_crt_params(key->rsa, dmp1, dmq1, NULL) == 0) { + r = SSH_ERR_LIBCRYPTO_ERROR; ++ BN_clear_free(dmp1); ++ BN_clear_free(dmq1); + goto out; + } ++ } + r = 0; + out: + BN_clear_free(aux); +@@ -139,7 +149,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, + if (key == NULL || key->rsa == NULL || hash_alg == -1 || + sshkey_type_plain(key->type) != KEY_RSA) + return SSH_ERR_INVALID_ARGUMENT; +- if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) ++ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) + return SSH_ERR_KEY_LENGTH; + slen = RSA_size(key->rsa); + if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) +@@ -211,7 +221,7 @@ ssh_rsa_verify(const struct sshkey *key, + sshkey_type_plain(key->type) != KEY_RSA || + sig == NULL || siglen == 0) + return SSH_ERR_INVALID_ARGUMENT; +- if (BN_num_bits(key->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) +diff --git a/sshkey.c b/sshkey.c +index 7712fba..1f65301 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -274,10 +274,18 @@ sshkey_size(const struct sshkey *k) + #ifdef WITH_OPENSSL + case KEY_RSA: + case KEY_RSA_CERT: +- return BN_num_bits(k->rsa->n); ++#if OPENSSL_VERSION_NUMBER >= 0x10100000UL ++ return RSA_bits(k->rsa); ++#else ++ return RSA_bits(key->rsa); ++#endif + case KEY_DSA: + case KEY_DSA_CERT: ++#if OPENSSL_VERSION_NUMBER >= 0x10100000UL ++ return DSA_bits(k->dsa); ++#else + return BN_num_bits(k->dsa->p); ++#endif + case KEY_ECDSA: + case KEY_ECDSA_CERT: + return sshkey_curve_nid_to_bits(k->ecdsa_nid); +@@ -482,26 +490,53 @@ sshkey_new(int type) + #ifdef WITH_OPENSSL + case KEY_RSA: + case KEY_RSA_CERT: ++ { ++ BIGNUM *n=NULL, *e=NULL; /* just allocate */ + if ((rsa = RSA_new()) == NULL || +- (rsa->n = BN_new()) == NULL || +- (rsa->e = BN_new()) == NULL) { ++ (n = BN_new()) == NULL || ++ (e = BN_new()) == NULL) { ++ BN_free(n); ++ BN_free(e); + RSA_free(rsa); + free(k); + return NULL; + } ++ BN_clear(n); BN_clear(e); ++ if (RSA_set0_key(rsa, n, e, NULL) == 0) ++ return NULL; ++ n = e = NULL; ++ } + k->rsa = rsa; + break; + case KEY_DSA: + case KEY_DSA_CERT: ++ { ++ BIGNUM *p=NULL, *q=NULL, *g=NULL, *pubkey=NULL; /* just allocate */ + if ((dsa = DSA_new()) == NULL || +- (dsa->p = BN_new()) == NULL || +- (dsa->q = BN_new()) == NULL || +- (dsa->g = BN_new()) == NULL || +- (dsa->pub_key = BN_new()) == NULL) { ++ (p = BN_new()) == NULL || ++ (q = BN_new()) == NULL || ++ (g = BN_new()) == NULL || ++ (pubkey = BN_new()) == NULL) { ++ BN_free(p); ++ BN_free(q); ++ BN_free(g); ++ BN_free(pubkey); + DSA_free(dsa); + free(k); + return NULL; + } ++ if (DSA_set0_pqg(dsa, p, q, g) == 0) { ++ BN_free(p); BN_free(q); BN_free(g); ++ BN_free(pubkey); ++ return NULL; ++ } ++ p = q = g = NULL; ++ if (DSA_set0_key(dsa, pubkey, NULL) == 0) { ++ BN_free(pubkey); ++ return NULL; ++ } ++ pubkey = NULL; ++ } + k->dsa = dsa; + break; + case KEY_ECDSA: +@@ -539,6 +574,51 @@ sshkey_add_private(struct sshkey *k) + #ifdef WITH_OPENSSL + case KEY_RSA: + case KEY_RSA_CERT: ++#if OPENSSL_VERSION_NUMBER >= 0x10100000UL ++ /* Allocate BIGNUM. This is a mess. ++ For OpenSSL 1.1.x API these shouldn't be mandatory, ++ but some regression tests for non-NULL pointer of ++ the data. */ ++#define new_or_dup(bn, nbn) \ ++ if (bn == NULL) { \ ++ if ((nbn = BN_new()) == NULL) \ ++ return SSH_ERR_ALLOC_FAIL; \ ++ } else { \ ++ /* otherwise use-after-free will occur */ \ ++ if ((nbn = BN_dup(bn)) == NULL) \ ++ return SSH_ERR_ALLOC_FAIL; \ ++ } ++ { ++ const BIGNUM *d, *iqmp, *q, *p, *dmq1, *dmp1; /* allocate if NULL */ ++ BIGNUM *nd, *niqmp, *nq, *np, *ndmq1, *ndmp1; ++ ++ RSA_get0_key(k->rsa, NULL, NULL, &d); ++ RSA_get0_factors(k->rsa, &p, &q); ++ RSA_get0_crt_params(k->rsa, &dmp1, &dmq1, &iqmp); ++ ++ new_or_dup(d, nd); ++ new_or_dup(iqmp, niqmp); ++ new_or_dup(q, nq); ++ new_or_dup(p, np); ++ new_or_dup(dmq1, ndmq1); ++ new_or_dup(dmp1, ndmp1); ++ ++ if (RSA_set0_key(k->rsa, NULL, NULL, nd) == 0) ++ goto error1; ++ nd = NULL; ++ if (RSA_set0_factors(k->rsa, np, nq) == 0) ++ goto error1; ++ np = nq = NULL; ++ if (RSA_set0_crt_params(k->rsa, ndmp1, ndmq1, niqmp) == 0) { ++error1: ++ BN_free(nd); ++ BN_free(np); BN_free(nq); ++ BN_free(ndmp1); BN_free(ndmq1); BN_free(niqmp); ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ ndmp1 = ndmq1 = niqmp = NULL; ++ } ++#else + #define bn_maybe_alloc_failed(p) (p == NULL && (p = BN_new()) == NULL) + if (bn_maybe_alloc_failed(k->rsa->d) || + bn_maybe_alloc_failed(k->rsa->iqmp) || +@@ -547,13 +627,28 @@ sshkey_add_private(struct sshkey *k) + bn_maybe_alloc_failed(k->rsa->dmq1) || + bn_maybe_alloc_failed(k->rsa->dmp1)) + return SSH_ERR_ALLOC_FAIL; ++#endif + break; + case KEY_DSA: + case KEY_DSA_CERT: ++#if OPENSSL_VERSION_NUMBER >= 0x10100000UL ++ { ++ const BIGNUM *priv_key; ++ BIGNUM *npriv_key; ++ DSA_get0_key(k->dsa, NULL, &priv_key); ++ new_or_dup(priv_key, npriv_key); ++ if (DSA_set0_key(k->dsa, NULL, npriv_key) == 0) { ++ BN_free(npriv_key); ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ } ++#else + if (bn_maybe_alloc_failed(k->dsa->priv_key)) + return SSH_ERR_ALLOC_FAIL; ++#endif + break; + #undef bn_maybe_alloc_failed ++#undef new_or_dup + case KEY_ECDSA: + case KEY_ECDSA_CERT: + /* Cannot do anything until we know the group */ +@@ -677,16 +772,34 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b) + #ifdef WITH_OPENSSL + case KEY_RSA_CERT: + case KEY_RSA: +- return a->rsa != NULL && b->rsa != NULL && +- BN_cmp(a->rsa->e, b->rsa->e) == 0 && +- BN_cmp(a->rsa->n, b->rsa->n) == 0; ++ { ++ const BIGNUM *a_e, *b_e, *a_n, *b_n; ++ const BIGNUM *a_d, *b_d; ++ if (a->rsa == NULL) return 0; ++ if (b->rsa == NULL) return 0; ++ RSA_get0_key(a->rsa, &a_n, &a_e, &a_d); ++ RSA_get0_key(b->rsa, &b_n, &b_e, &b_d); ++ return ++ BN_cmp(a_e, b_e) == 0 && ++ BN_cmp(a_n, b_n) == 0; ++ } + case KEY_DSA_CERT: + case KEY_DSA: +- return a->dsa != NULL && b->dsa != NULL && +- BN_cmp(a->dsa->p, b->dsa->p) == 0 && +- BN_cmp(a->dsa->q, b->dsa->q) == 0 && +- BN_cmp(a->dsa->g, b->dsa->g) == 0 && +- BN_cmp(a->dsa->pub_key, b->dsa->pub_key) == 0; ++ { ++ const BIGNUM *a_p, *a_q, *a_g, *a_pub_key; ++ const BIGNUM *b_p, *b_q, *b_g, *b_pub_key; ++ if (a->dsa == NULL) return 0; ++ if (b->dsa == NULL) return 0; ++ DSA_get0_pqg(a->dsa, &a_p, &a_q, &a_g); ++ DSA_get0_pqg(b->dsa, &b_p, &b_q, &b_g); ++ DSA_get0_key(a->dsa, &a_pub_key, NULL); ++ DSA_get0_key(b->dsa, &b_pub_key, NULL); ++ return ++ BN_cmp(a_p, b_p) == 0 && ++ BN_cmp(a_q, b_q) == 0 && ++ BN_cmp(a_g, b_g) == 0 && ++ BN_cmp(a_pub_key, b_pub_key) == 0; ++ } + # ifdef OPENSSL_HAS_ECC + case KEY_ECDSA_CERT: + case KEY_ECDSA: +@@ -775,12 +888,17 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain, + case KEY_DSA: + if (key->dsa == NULL) + return SSH_ERR_INVALID_ARGUMENT; ++ { ++ const BIGNUM *p, *q, *g, *pub_key; ++ DSA_get0_pqg(key->dsa, &p, &q, &g); ++ DSA_get0_key(key->dsa, &pub_key, NULL); + if ((ret = sshbuf_put_cstring(b, typename)) != 0 || +- (ret = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || +- (ret = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || +- (ret = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || +- (ret = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0) ++ (ret = sshbuf_put_bignum2(b, p)) != 0 || ++ (ret = sshbuf_put_bignum2(b, q)) != 0 || ++ (ret = sshbuf_put_bignum2(b, g)) != 0 || ++ (ret = sshbuf_put_bignum2(b, pub_key)) != 0) + return ret; ++ } + break; + # ifdef OPENSSL_HAS_ECC + case KEY_ECDSA: +@@ -796,10 +914,14 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain, + case KEY_RSA: + if (key->rsa == NULL) + return SSH_ERR_INVALID_ARGUMENT; ++ { ++ const BIGNUM *e, *n; ++ RSA_get0_key(key->rsa, &n, &e, NULL); + if ((ret = sshbuf_put_cstring(b, typename)) != 0 || +- (ret = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || +- (ret = sshbuf_put_bignum2(b, key->rsa->n)) != 0) ++ (ret = sshbuf_put_bignum2(b, e)) != 0 || ++ (ret = sshbuf_put_bignum2(b, n)) != 0) + return ret; ++ } + break; + #endif /* WITH_OPENSSL */ + case KEY_ED25519: +@@ -1740,13 +1862,32 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp) + case KEY_DSA_CERT: + if ((n = sshkey_new(k->type)) == NULL) + return SSH_ERR_ALLOC_FAIL; +- if ((BN_copy(n->dsa->p, k->dsa->p) == NULL) || +- (BN_copy(n->dsa->q, k->dsa->q) == NULL) || +- (BN_copy(n->dsa->g, k->dsa->g) == NULL) || +- (BN_copy(n->dsa->pub_key, k->dsa->pub_key) == NULL)) { ++ { ++ const BIGNUM *p, *q, *g, *pub_key, *priv_key; ++ BIGNUM *cp=NULL, *cq=NULL, *cg=NULL, *cpub_key=NULL; ++ DSA_get0_pqg(k->dsa, &p, &q, &g); ++ DSA_get0_key(k->dsa, &pub_key, &priv_key); ++ if ((cp = BN_dup(p)) == NULL || ++ (cq = BN_dup(q)) == NULL || ++ (cg = BN_dup(g)) == NULL || ++ (cpub_key = BN_dup(pub_key)) == NULL) { ++ BN_free(cp); BN_free(cq); BN_free(cg); ++ BN_free(cpub_key); + sshkey_free(n); + return SSH_ERR_ALLOC_FAIL; + } ++ if (DSA_set0_pqg(n->dsa, cp, cq, cg) == 0) ++ goto error1; ++ cp = cq = cg = NULL; ++ if (DSA_set0_key(n->dsa, cpub_key, NULL) == 0) { ++error1: ++ BN_free(cp); BN_free(cq); BN_free(cg); ++ BN_free(cpub_key); ++ sshkey_free(n); ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ cpub_key = NULL; ++ } + break; + # ifdef OPENSSL_HAS_ECC + case KEY_ECDSA: +@@ -1770,11 +1911,23 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp) + case KEY_RSA_CERT: + if ((n = sshkey_new(k->type)) == NULL) + return SSH_ERR_ALLOC_FAIL; +- if ((BN_copy(n->rsa->n, k->rsa->n) == NULL) || +- (BN_copy(n->rsa->e, k->rsa->e) == NULL)) { ++ { ++ const BIGNUM *nn, *e, *d; ++ BIGNUM *cn=NULL, *ce=NULL; ++ RSA_get0_key(k->rsa, &nn, &e, &d); ++ if ((cn = BN_dup(nn)) == NULL || ++ (ce = BN_dup(e)) == NULL ) { ++ BN_free(cn); BN_free(ce); + sshkey_free(n); + return SSH_ERR_ALLOC_FAIL; + } ++ if (RSA_set0_key(n->rsa, cn, ce, NULL) == 0) { ++ BN_free(cn); BN_free(ce); ++ sshkey_free(n); ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ cn = ce = NULL; ++ } + break; + #endif /* WITH_OPENSSL */ + case KEY_ED25519: +@@ -1995,12 +2148,27 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if (sshbuf_get_bignum2(b, key->rsa->e) != 0 || +- sshbuf_get_bignum2(b, key->rsa->n) != 0) { ++ { ++ BIGNUM *e=NULL, *n=NULL; ++ if ((e = BN_new()) == NULL || ++ (n = BN_new()) == NULL ) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ BN_free(e); BN_free(n); ++ goto out; ++ } ++ if (sshbuf_get_bignum2(b, e) != 0 || ++ sshbuf_get_bignum2(b, n) != 0) { + ret = SSH_ERR_INVALID_FORMAT; ++ BN_free(e); BN_free(n); + goto out; + } +- if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { ++ if (RSA_set0_key(key->rsa, n, e, NULL) == 0) { ++ BN_free(e); BN_free(n); ++ return SSH_ERR_LIBCRYPTO_ERROR; ++ } ++ n = e = NULL; ++ } ++ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + ret = SSH_ERR_KEY_LENGTH; + goto out; + } +@@ -2020,13 +2188,36 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, + ret = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if (sshbuf_get_bignum2(b, key->dsa->p) != 0 || +- sshbuf_get_bignum2(b, key->dsa->q) != 0 || +- sshbuf_get_bignum2(b, key->dsa->g) != 0 || +- sshbuf_get_bignum2(b, key->dsa->pub_key) != 0) { ++ { ++ BIGNUM *p=NULL, *q=NULL, *g=NULL, *pub_key=NULL; ++ if ((p = BN_new()) == NULL || ++ (q = BN_new()) == NULL || ++ (g = BN_new()) == NULL || ++ (pub_key = BN_new()) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto error1; ++ } ++ if (sshbuf_get_bignum2(b, p) != 0 || ++ sshbuf_get_bignum2(b, q) != 0 || ++ sshbuf_get_bignum2(b, g) != 0 || ++ sshbuf_get_bignum2(b, pub_key) != 0) { + ret = SSH_ERR_INVALID_FORMAT; ++ goto error1; ++ } ++ if (DSA_set0_pqg(key->dsa, p, q, g) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto error1; ++ } ++ p = q = g = NULL; ++ if (DSA_set0_key(key->dsa, pub_key, NULL) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++error1: ++ BN_free(p); BN_free(q); BN_free(g); ++ BN_free(pub_key); + goto out; + } ++ pub_key = NULL; ++ } + #ifdef DEBUG_PK + DSA_print_fp(stderr, key->dsa, 8); + #endif +@@ -2327,26 +2518,63 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp) + goto fail; + /* FALLTHROUGH */ + case KEY_RSA: +- if ((pk->rsa = RSA_new()) == NULL || +- (pk->rsa->e = BN_dup(k->rsa->e)) == NULL || +- (pk->rsa->n = BN_dup(k->rsa->n)) == NULL) { ++ if ((pk->rsa = RSA_new()) == NULL ){ ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto fail; ++ } ++ { ++ const BIGNUM *ke, *kn; ++ BIGNUM *pke=NULL, *pkn=NULL; ++ RSA_get0_key(k->rsa, &kn, &ke, NULL); ++ if ((pke = BN_dup(ke)) == NULL || ++ (pkn = BN_dup(kn)) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; ++ BN_free(pke); BN_free(pkn); + goto fail; + } ++ if (RSA_set0_key(pk->rsa, pkn, pke, NULL) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ BN_free(pke); BN_free(pkn); ++ goto fail; ++ } ++ pkn = pke = NULL; ++ } + break; + case KEY_DSA_CERT: + if ((ret = sshkey_cert_copy(k, pk)) != 0) + goto fail; + /* FALLTHROUGH */ + case KEY_DSA: +- if ((pk->dsa = DSA_new()) == NULL || +- (pk->dsa->p = BN_dup(k->dsa->p)) == NULL || +- (pk->dsa->q = BN_dup(k->dsa->q)) == NULL || +- (pk->dsa->g = BN_dup(k->dsa->g)) == NULL || +- (pk->dsa->pub_key = BN_dup(k->dsa->pub_key)) == NULL) { ++ if ((pk->dsa = DSA_new()) == NULL ) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto fail; ++ } ++ { ++ const BIGNUM *kp, *kq, *kg, *kpub_key; ++ BIGNUM *pkp=NULL, *pkq=NULL, *pkg=NULL, *pkpub_key=NULL; ++ DSA_get0_pqg(k->dsa, &kp, &kq, &kg); ++ DSA_get0_key(k->dsa, &kpub_key, NULL); ++ if ((pkp = BN_dup(kp)) == NULL || ++ (pkq = BN_dup(kq)) == NULL || ++ (pkg = BN_dup(kg)) == NULL || ++ (pkpub_key = BN_dup(kpub_key)) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; ++ goto error1; ++ } ++ if (DSA_set0_pqg(pk->dsa, pkp, pkq, pkg) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto error1; ++ } ++ pkp = pkq = pkg = NULL; ++ if (DSA_set0_key(pk->dsa, pkpub_key, NULL) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++error1: ++ BN_free(pkp); BN_free(pkq); BN_free(pkg); ++ BN_free(pkpub_key); + goto fail; + } ++ pkpub_key = NULL; ++ } + break; + case KEY_ECDSA_CERT: + if ((ret = sshkey_cert_copy(k, pk)) != 0) +@@ -2496,11 +2724,17 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, + switch (k->type) { + #ifdef WITH_OPENSSL + case KEY_DSA_CERT: +- if ((ret = sshbuf_put_bignum2(cert, k->dsa->p)) != 0 || +- (ret = sshbuf_put_bignum2(cert, k->dsa->q)) != 0 || +- (ret = sshbuf_put_bignum2(cert, k->dsa->g)) != 0 || +- (ret = sshbuf_put_bignum2(cert, k->dsa->pub_key)) != 0) ++ { ++ const BIGNUM *p, *q, *g, *pub_key; ++ DSA_get0_pqg(k->dsa, &p, &q, &g); ++ DSA_get0_key(k->dsa, &pub_key, NULL); ++ if ((ret = sshbuf_put_bignum2(cert, p)) != 0 || ++ (ret = sshbuf_put_bignum2(cert, q)) != 0 || ++ (ret = sshbuf_put_bignum2(cert, g)) != 0 || ++ (ret = sshbuf_put_bignum2(cert, pub_key)) != 0) { + goto out; ++ } ++ } + break; + # ifdef OPENSSL_HAS_ECC + case KEY_ECDSA_CERT: +@@ -2513,9 +2747,15 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, + break; + # endif /* OPENSSL_HAS_ECC */ + case KEY_RSA_CERT: +- if ((ret = sshbuf_put_bignum2(cert, k->rsa->e)) != 0 || +- (ret = sshbuf_put_bignum2(cert, k->rsa->n)) != 0) ++ { ++ const BIGNUM *e, *n; ++ RSA_get0_key(k->rsa, &n, &e, NULL); ++ if (n == NULL || e == NULL || ++ (ret = sshbuf_put_bignum2(cert, e)) != 0 || ++ (ret = sshbuf_put_bignum2(cert, n)) != 0) { + goto out; ++ } ++ } + break; + #endif /* WITH_OPENSSL */ + case KEY_ED25519_CERT: +@@ -2702,42 +2942,67 @@ sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b, + switch (key->type) { + #ifdef WITH_OPENSSL + case KEY_RSA: +- if ((r = sshbuf_put_bignum2(b, key->rsa->n)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->e)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) ++ { ++ const BIGNUM *n, *e, *d, *iqmp, *p, *q; ++ RSA_get0_key(key->rsa, &n, &e, &d); ++ RSA_get0_crt_params(key->rsa, NULL, NULL, &iqmp); ++ RSA_get0_factors(key->rsa, &p, &q); ++ if ((r = sshbuf_put_bignum2(b, n)) != 0 || ++ (r = sshbuf_put_bignum2(b, e)) != 0 || ++ (r = sshbuf_put_bignum2(b, d)) != 0 || ++ (r = sshbuf_put_bignum2(b, iqmp)) != 0 || ++ (r = sshbuf_put_bignum2(b, p)) != 0 || ++ (r = sshbuf_put_bignum2(b, q)) != 0) { + goto out; ++ } ++ } + break; + case KEY_RSA_CERT: + if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } ++ { ++ const BIGNUM *d, *iqmp, *p, *q; ++ RSA_get0_key(key->rsa, NULL, NULL, &d); ++ RSA_get0_crt_params(key->rsa, NULL, NULL, &iqmp); ++ RSA_get0_factors(key->rsa, &p, &q); + if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->d)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->iqmp)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->p)) != 0 || +- (r = sshbuf_put_bignum2(b, key->rsa->q)) != 0) ++ (r = sshbuf_put_bignum2(b, d)) != 0 || ++ (r = sshbuf_put_bignum2(b, iqmp)) != 0 || ++ (r = sshbuf_put_bignum2(b, p)) != 0 || ++ (r = sshbuf_put_bignum2(b, q)) != 0) { + goto out; ++ } ++ } + break; + case KEY_DSA: +- if ((r = sshbuf_put_bignum2(b, key->dsa->p)) != 0 || +- (r = sshbuf_put_bignum2(b, key->dsa->q)) != 0 || +- (r = sshbuf_put_bignum2(b, key->dsa->g)) != 0 || +- (r = sshbuf_put_bignum2(b, key->dsa->pub_key)) != 0 || +- (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) ++ { ++ const BIGNUM *p, *q, *g, *pub_key, *priv_key; ++ DSA_get0_pqg(key->dsa, &p, &q, &g); ++ DSA_get0_key(key->dsa, &pub_key, &priv_key); ++ if ((r = sshbuf_put_bignum2(b, p)) != 0 || ++ (r = sshbuf_put_bignum2(b, q)) != 0 || ++ (r = sshbuf_put_bignum2(b, g)) != 0 || ++ (r = sshbuf_put_bignum2(b, pub_key)) != 0 || ++ (r = sshbuf_put_bignum2(b, priv_key)) != 0) { + goto out; ++ } ++ } + break; + case KEY_DSA_CERT: + if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } ++ { ++ const BIGNUM *priv_key; ++ DSA_get0_key(key->dsa, NULL, &priv_key); + if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || +- (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) ++ (r = sshbuf_put_bignum2(b, priv_key)) != 0) { + goto out; ++ } ++ } + break; + # ifdef OPENSSL_HAS_ECC + case KEY_ECDSA: +@@ -2851,18 +3116,61 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((r = sshbuf_get_bignum2(buf, k->dsa->p)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->dsa->q)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->dsa->g)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->dsa->pub_key)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) ++ { ++ BIGNUM *p=NULL, *q=NULL, *g=NULL, *pub_key=NULL, *priv_key=NULL; ++ if ((p = BN_new()) == NULL || ++ (q = BN_new()) == NULL || ++ (g = BN_new()) == NULL || ++ (pub_key = BN_new()) == NULL || ++ (priv_key = BN_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto error1; ++ } ++ if (p == NULL || q == NULL || g == NULL || ++ pub_key == NULL || priv_key == NULL || ++ (r = sshbuf_get_bignum2(buf, p)) != 0 || ++ (r = sshbuf_get_bignum2(buf, q)) != 0 || ++ (r = sshbuf_get_bignum2(buf, g)) != 0 || ++ (r = sshbuf_get_bignum2(buf, pub_key)) != 0 || ++ (r = sshbuf_get_bignum2(buf, priv_key)) != 0) { ++ goto error1; ++ } ++ if (DSA_set0_pqg(k->dsa, p, q, g) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto error1; ++ } ++ p = q = g = NULL; ++ if (DSA_set0_key(k->dsa, pub_key, priv_key) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++error1: ++ BN_free(p); BN_free(q); BN_free(g); ++ BN_free(pub_key); BN_free(priv_key); + goto out; ++ } ++ pub_key = priv_key = NULL; ++ } + break; + case KEY_DSA_CERT: +- if ((r = sshkey_froms(buf, &k)) != 0 || ++ { ++ BIGNUM *priv_key=NULL; ++ if ((priv_key = BN_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (priv_key == NULL || ++ (r = sshkey_froms(buf, &k)) != 0 || + (r = sshkey_add_private(k)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) ++ (r = sshbuf_get_bignum2(buf, priv_key)) != 0) { ++ BN_free(priv_key); + goto out; ++ } ++ if (DSA_set0_key(k->dsa, NULL, priv_key) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ BN_free(priv_key); ++ goto out; ++ } ++ priv_key = NULL; ++ } + break; + # ifdef OPENSSL_HAS_ECC + case KEY_ECDSA: +@@ -2921,29 +3229,104 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((r = sshbuf_get_bignum2(buf, k->rsa->n)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->e)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 || +- (r = ssh_rsa_generate_additional_parameters(k)) != 0) ++ { ++ BIGNUM *n=NULL, *e=NULL, *d=NULL, *iqmp=NULL, *p=NULL, *q=NULL; ++ BIGNUM *dmp1=NULL, *dmq1=NULL; /* dummy for RSA_set0_crt_params */ ++ if ((n = BN_new()) == NULL || ++ (e = BN_new()) == NULL || ++ (d = BN_new()) == NULL || ++ (iqmp = BN_new()) == NULL || ++ (p = BN_new()) == NULL || ++ (q = BN_new()) == NULL || ++ (dmp1 = BN_new()) == NULL || ++ (dmq1 = BN_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto error2; ++ } ++ BN_clear(dmp1); BN_clear(dmq1); ++ if ((r = sshbuf_get_bignum2(buf, n)) != 0 || ++ (r = sshbuf_get_bignum2(buf, e)) != 0 || ++ (r = sshbuf_get_bignum2(buf, d)) != 0 || ++ (r = sshbuf_get_bignum2(buf, iqmp)) != 0 || ++ (r = sshbuf_get_bignum2(buf, p)) != 0 || ++ (r = sshbuf_get_bignum2(buf, q)) != 0) { ++ goto error2; ++ } ++ if (RSA_set0_key(k->rsa, n, e, d) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto error2; ++ } ++ n = e = d = NULL; ++ /* dmp1,dmpq1 should be non NULL to set iqmp value */ ++ if (RSA_set0_crt_params(k->rsa, dmp1, dmq1, iqmp) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto error2; ++ } ++ dmp1 = dmq1 = iqmp = NULL; ++ if (RSA_set0_factors(k->rsa, p, q) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ error2: ++ BN_free(n); BN_free(e); BN_free(d); ++ BN_free(iqmp); ++ BN_free(p); BN_free(q); ++ BN_free(dmp1); BN_free(dmq1); ++ goto out; ++ } ++ p = q = NULL; ++ if ((r = ssh_rsa_generate_additional_parameters(k)) != 0) { + goto out; +- if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { ++ } ++ } ++ if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + r = SSH_ERR_KEY_LENGTH; + goto out; + } + break; + case KEY_RSA_CERT: ++ { ++ BIGNUM *d=NULL, *iqmp=NULL, *p=NULL, *q=NULL; ++ BIGNUM *dmp1=NULL, *dmq1=NULL; /* dummy for RSA_set0_crt_params */ ++ if ((d = BN_new()) == NULL || ++ (iqmp = BN_new()) == NULL || ++ (p = BN_new()) == NULL || ++ (q = BN_new()) == NULL || ++ (dmp1 = BN_new()) == NULL || ++ (dmq1 = BN_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto error3; ++ } ++ BN_clear(dmp1); BN_clear(dmq1); + if ((r = sshkey_froms(buf, &k)) != 0 || + (r = sshkey_add_private(k)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->d)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->iqmp)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->p)) != 0 || +- (r = sshbuf_get_bignum2(buf, k->rsa->q)) != 0 || +- (r = ssh_rsa_generate_additional_parameters(k)) != 0) ++ (r = sshbuf_get_bignum2(buf, d)) != 0 || ++ (r = sshbuf_get_bignum2(buf, iqmp)) != 0 || ++ (r = sshbuf_get_bignum2(buf, p)) != 0 || ++ (r = sshbuf_get_bignum2(buf, q)) != 0) { ++ goto error3; ++ } ++ if (RSA_set0_key(k->rsa, NULL, NULL, d) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto error3; ++ } ++ /* dmp1,dmpq1 should be non NULL to set value */ ++ if (RSA_set0_crt_params(k->rsa, dmp1, dmq1, iqmp) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto error3; ++ } ++ dmp1 = dmq1 = iqmp = NULL; ++ if (RSA_set0_factors(k->rsa, p, q) == 0) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ error3: ++ BN_free(d); BN_free(iqmp); ++ BN_free(p); BN_free(q); ++ BN_free(dmp1); BN_free(dmq1); + goto out; +- if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { ++ } ++ p = q = NULL; ++ if ((r = ssh_rsa_generate_additional_parameters(k)) != 0) ++ goto out; ++ } ++ if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + r = SSH_ERR_KEY_LENGTH; + goto out; + } +@@ -3707,7 +4090,6 @@ translate_libcrypto_error(unsigned long pem_err) + switch (pem_reason) { + case EVP_R_BAD_DECRYPT: + return SSH_ERR_KEY_WRONG_PASSPHRASE; +- case EVP_R_BN_DECODE_ERROR: + case EVP_R_DECODE_ERROR: + #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR + case EVP_R_PRIVATE_KEY_DECODE_ERROR: +@@ -3772,7 +4154,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, + r = convert_libcrypto_error(); + goto out; + } +- if (pk->type == EVP_PKEY_RSA && ++ if (EVP_PKEY_id(pk) == EVP_PKEY_RSA && + (type == KEY_UNSPEC || type == KEY_RSA)) { + if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; +@@ -3787,11 +4169,11 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- if (BN_num_bits(prv->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { ++ if (RSA_bits(prv->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) { + r = SSH_ERR_KEY_LENGTH; + goto out; + } +- } else if (pk->type == EVP_PKEY_DSA && ++ } else if (EVP_PKEY_id(pk) == EVP_PKEY_DSA && + (type == KEY_UNSPEC || type == KEY_DSA)) { + if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; +@@ -3803,7 +4185,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, + DSA_print_fp(stderr, prv->dsa, 8); + #endif + #ifdef OPENSSL_HAS_ECC +- } else if (pk->type == EVP_PKEY_EC && ++ } else if (EVP_PKEY_id(pk) == EVP_PKEY_EC && + (type == KEY_UNSPEC || type == KEY_ECDSA)) { + if ((prv = sshkey_new(KEY_UNSPEC)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; +-- +2.16.3 + -- 2.16.3