From eaa7af2e41b1806a4cdaf24679f38b588c168e77 Mon Sep 17 00:00:00 2001 From: Jakub Jelen Date: Fri, 12 Oct 2018 15:54:56 +0200 Subject: [PATCH] rebase patches to openssh-7.9p1 --- .gitignore | 2 + openssh-6.6.1p1-selinux-contexts.patch | 8 - openssh-6.6p1-ctr-cavstest.patch | 2 +- openssh-6.6p1-force_krb.patch | 4 +- openssh-7.0p1-gssKexAlgorithms.patch | 6 +- openssh-7.3p1-openssl-1.1.0.patch | 2688 ------------------------ openssh-7.5p1-sandbox.patch | 4 +- openssh-7.6p1-audit.patch | 28 +- openssh-7.6p1-pkcs11-ecdsa.patch | 199 +- openssh-7.6p1-pkcs11-uri.patch | 2400 +++++++++++---------- openssh-7.7p1-fips.patch | 30 +- openssh-7.8p1-gsskex.patch | 58 +- openssh.spec | 14 +- sources | 4 +- 14 files changed, 1361 insertions(+), 4086 deletions(-) delete mode 100644 openssh-7.3p1-openssl-1.1.0.patch diff --git a/.gitignore b/.gitignore index ec4bb26..8244f14 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,5 @@ pam_ssh_agent_auth-0.9.2.tar.bz2 /DJM-GPG-KEY.gpg /openssh-7.8p1.tar.gz /openssh-7.8p1.tar.gz.asc +/openssh-7.9p1.tar.gz +/openssh-7.9p1.tar.gz.asc diff --git a/openssh-6.6.1p1-selinux-contexts.patch b/openssh-6.6.1p1-selinux-contexts.patch index 8bf6c78..f26f343 100644 --- a/openssh-6.6.1p1-selinux-contexts.patch +++ b/openssh-6.6.1p1-selinux-contexts.patch @@ -82,14 +82,6 @@ diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c index 22ea8ef..1fc963d 100644 --- a/openbsd-compat/port-linux.c +++ b/openbsd-compat/port-linux.c -@@ -26,6 +26,7 @@ - #include - #include - #include -+#include - - #include "log.h" - #include "xmalloc.h" @@ -179,7 +179,7 @@ ssh_selinux_change_context(const char *newname) strlcpy(newctx + len, newname, newlen - len); if ((cx = index(cx + 1, ':'))) diff --git a/openssh-6.6p1-ctr-cavstest.patch b/openssh-6.6p1-ctr-cavstest.patch index c56313d..2e31fbf 100644 --- a/openssh-6.6p1-ctr-cavstest.patch +++ b/openssh-6.6p1-ctr-cavstest.patch @@ -187,7 +187,7 @@ diff -up openssh-6.8p1/ctr-cavstest.c.ctr-cavs openssh-6.8p1/ctr-cavstest.c + usage(); + } + -+ SSLeay_add_all_algorithms(); ++ OpenSSL_add_all_algorithms(); + + c = cipher_by_name(algo); + if (c == NULL) { diff --git a/openssh-6.6p1-force_krb.patch b/openssh-6.6p1-force_krb.patch index aeee77f..90f8322 100644 --- a/openssh-6.6p1-force_krb.patch +++ b/openssh-6.6p1-force_krb.patch @@ -235,9 +235,9 @@ index 28659ec..9c94d8e 100644 +#endif +#endif + + s->forced = 0; if (forced != NULL) { - if (IS_INTERNAL_SFTP(command)) { - s->is_subsystem = s->is_subsystem ? + s->forced = 1; diff --git a/ssh-gss.h b/ssh-gss.h index 0374c88..509109a 100644 --- a/ssh-gss.h diff --git a/openssh-7.0p1-gssKexAlgorithms.patch b/openssh-7.0p1-gssKexAlgorithms.patch index 2ba360e..1497049 100644 --- a/openssh-7.0p1-gssKexAlgorithms.patch +++ b/openssh-7.0p1-gssKexAlgorithms.patch @@ -29,14 +29,14 @@ diff -up openssh-7.0p1/gss-genr.c.gsskexalg openssh-7.0p1/gss-genr.c @@ -100,6 +101,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup char deroid[2]; const EVP_MD *evp_md = EVP_md5(); - EVP_MD_CTX md; + EVP_MD_CTX *md; + char *s, *cp, *p; if (gss_enc2oid != NULL) { for (i = 0; gss_enc2oid[i].encoded != NULL; i++) @@ -113,6 +115,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - fatal("%s: sshbuf_new failed", __func__); + md = EVP_MD_CTX_new(); oidpos = 0; + s = cp = xstrdup(kex); for (i = 0; i < gss_supported->count; i++) { @@ -81,9 +81,9 @@ diff -up openssh-7.0p1/gss-genr.c.gsskexalg openssh-7.0p1/gss-genr.c } } + free(s); + EVP_MD_CTX_free(md); gss_enc2oid[oidpos].oid = NULL; gss_enc2oid[oidpos].encoded = NULL; - diff -up openssh-7.0p1/gss-serv.c.gsskexalg openssh-7.0p1/gss-serv.c --- openssh-7.0p1/gss-serv.c.gsskexalg 2015-08-19 12:28:38.024518959 +0200 +++ openssh-7.0p1/gss-serv.c 2015-08-19 12:28:38.078518839 +0200 diff --git a/openssh-7.3p1-openssl-1.1.0.patch b/openssh-7.3p1-openssl-1.1.0.patch deleted file mode 100644 index 42ede48..0000000 --- a/openssh-7.3p1-openssl-1.1.0.patch +++ /dev/null @@ -1,2688 +0,0 @@ -diff -up openssh/auth-pam.c.openssl openssh/auth-pam.c ---- openssh/auth-pam.c.openssl 2017-09-26 13:19:31.662248869 +0200 -+++ openssh/auth-pam.c 2017-09-26 13:19:31.793249672 +0200 -@@ -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 -up openssh/cipher.c.openssl openssh/cipher.c ---- openssh/cipher.c.openssl 2017-09-26 13:19:31.782249605 +0200 -+++ openssh/cipher.c 2017-09-26 13:27:37.424040367 +0200 -@@ -283,7 +283,7 @@ cipher_init(struct sshcipher_ctx **ccp, - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv, -+ if (EVP_CipherInit(cc->evp, type, (u_char *)key, (u_char *)iv, - (do_encrypt == CIPHER_ENCRYPT)) == 0) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; -@@ -301,10 +301,6 @@ cipher_init(struct sshcipher_ctx **ccp, - goto out; - } - } -- if (EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1) == 0) { -- ret = SSH_ERR_LIBCRYPTO_ERROR; -- goto out; -- } - ret = 0; - #endif /* WITH_OPENSSL */ - out: -@@ -490,7 +486,7 @@ cipher_get_keyiv(struct sshcipher_ctx *c - 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; - } -@@ -524,14 +520,14 @@ cipher_set_keyiv(struct sshcipher_ctx *c - 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_noconst(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 -+#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)) - #endif - - int -diff -up openssh/ctr-cavstest.c.openssl openssh/ctr-cavstest.c ---- openssh/ctr-cavstest.c.openssl 2017-09-26 13:19:31.707249145 +0200 -+++ openssh/ctr-cavstest.c 2017-09-26 13:19:31.794249679 +0200 -@@ -144,7 +144,7 @@ int main (int argc, char *argv[]) - usage(); - } - -- SSLeay_add_all_algorithms(); -+ OpenSSL_add_all_algorithms(); - - c = cipher_by_name(algo); - if (c == NULL) { -diff -up openssh/dh.c.openssl openssh/dh.c ---- openssh/dh.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/dh.c 2017-09-26 13:19:31.794249679 +0200 -@@ -212,14 +212,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; - } -@@ -232,7 +233,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"); -@@ -243,14 +245,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; -@@ -260,9 +262,11 @@ int - dh_gen_key(DH *dh, int need) - { - int pbits; -+ const BIGNUM *p, *pub_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) -@@ -271,11 +275,11 @@ 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->priv_key = NULL; -+ DH_set_length(dh, MINIMUM(need * 2, pbits - 1)); -+ 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_LIBCRYPTO_ERROR; - } - return 0; -@@ -284,15 +289,22 @@ DH * - dh_new_group_asc(const char *gen, const char *modulus) - { - DH *dh; -+ BIGNUM *p = NULL, *g = NULL; - -- 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; -- } -+ if ((dh = DH_new()) == NULL || -+ (p = BN_new()) == NULL || -+ (g = BN_new()) == NULL) -+ goto err; -+ if (BN_hex2bn(&p, modulus) == 0 || -+ BN_hex2bn(&g, gen) == 0 || -+ DH_set0_pqg(dh, p, NULL, g) == 0) -+ goto err; - return (dh); -+err: -+ DH_free(dh); -+ BN_free(p); -+ BN_free(g); -+ return NULL; - } - - /* -@@ -307,8 +319,7 @@ dh_new_group(BIGNUM *gen, BIGNUM *modulu - - if ((dh = DH_new()) == NULL) - return NULL; -- dh->p = modulus; -- dh->g = gen; -+ DH_set0_pqg(dh, modulus, NULL, gen); - - return (dh); - } -diff -up openssh/dh.h.openssl openssh/dh.h ---- openssh/dh.h.openssl 2017-09-26 13:19:31.783249611 +0200 -+++ openssh/dh.h 2017-09-26 13:19:31.794249679 +0200 -@@ -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 -up openssh/digest-openssl.c.openssl openssh/digest-openssl.c ---- openssh/digest-openssl.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/digest-openssl.c 2017-09-26 13:19:31.795249685 +0200 -@@ -43,7 +43,7 @@ - - struct ssh_digest_ctx { - int alg; -- EVP_MD_CTX mdctx; -+ EVP_MD_CTX *mdctx; - }; - - struct ssh_digest { -@@ -106,7 +106,7 @@ 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 * -@@ -118,8 +118,10 @@ ssh_digest_start(int alg) - 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) { -+ ret->mdctx = EVP_MD_CTX_new(); -+ if (ret->mdctx == 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_ - 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_ - 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 * - 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 -up openssh/entropy.c.openssl openssh/entropy.c ---- openssh/entropy.c.openssl 2017-09-26 13:19:31.783249611 +0200 -+++ openssh/entropy.c 2017-09-26 13:19:31.795249685 +0200 -@@ -218,7 +218,9 @@ seed_rng(void) - "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); - - /* clean the PRNG status when exiting the program */ -+#if OPENSSL_VERSION_NUMBER < 0x10100000L - atexit(RAND_cleanup); -+#endif - - #ifndef OPENSSL_PRNG_ONLY - if (RAND_status() == 1) { -diff -up openssh/gss-genr.c.openssl openssh/gss-genr.c ---- openssh/gss-genr.c.openssl 2017-09-26 13:19:31.773249550 +0200 -+++ openssh/gss-genr.c 2017-09-26 13:19:31.796249691 +0200 -@@ -99,7 +99,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - u_char digest[EVP_MAX_MD_SIZE]; - char deroid[2]; - const EVP_MD *evp_md = EVP_md5(); -- EVP_MD_CTX md; -+ EVP_MD_CTX *md; - char *s, *cp, *p; - - if (gss_enc2oid != NULL) { -@@ -113,6 +113,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - if ((buf = sshbuf_new()) == NULL) - fatal("%s: sshbuf_new failed", __func__); - -+ md = EVP_MD_CTX_new(); - oidpos = 0; - s = cp = xstrdup(kex); - for (i = 0; i < gss_supported->count; i++) { -@@ -122,12 +123,13 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - deroid[0] = SSH_GSS_OIDTYPE; - deroid[1] = gss_supported->elements[i].length; - -- EVP_DigestInit(&md, evp_md); -- EVP_DigestUpdate(&md, deroid, 2); -- EVP_DigestUpdate(&md, -+ EVP_MD_CTX_reset(md); -+ EVP_DigestInit(md, evp_md); -+ EVP_DigestUpdate(md, deroid, 2); -+ EVP_DigestUpdate(md, - gss_supported->elements[i].elements, - gss_supported->elements[i].length); -- EVP_DigestFinal(&md, digest, NULL); -+ EVP_DigestFinal(md, digest, NULL); - - encoded = xmalloc(EVP_MD_size(evp_md) * 2); - enclen = __b64_ntop(digest, EVP_MD_size(evp_md), -@@ -149,6 +151,7 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - } - } - free(s); -+ EVP_MD_CTX_free(md); - gss_enc2oid[oidpos].oid = NULL; - gss_enc2oid[oidpos].encoded = NULL; - -diff -up openssh/includes.h.openssl openssh/includes.h ---- openssh/includes.h.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/includes.h 2017-09-26 13:19:31.796249691 +0200 -@@ -166,6 +166,7 @@ - - #ifdef WITH_OPENSSL - #include /* For OPENSSL_VERSION_NUMBER */ -+#include "libcrypto-compat.h" - #endif - - #include "defines.h" -diff -up openssh/kexdhc.c.openssl openssh/kexdhc.c ---- openssh/kexdhc.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/kexdhc.c 2017-09-26 13:19:31.797249697 +0200 -@@ -56,6 +56,7 @@ kexdh_client(struct ssh *ssh) - { - struct kex *kex = ssh->kex; - int r; -+ const BIGNUM *pub_key; - - /* generate and send 'e', client DH public key */ - switch (kex->kex_type) { -@@ -81,21 +82,27 @@ 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 || -+ 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= "); -- BN_print_fp(stderr, kex->dh->pub_key); -+ BN_print_fp(stderr, pub_key); - fprintf(stderr, "\n"); - #endif - debug("expecting SSH2_MSG_KEXDH_REPLY"); - ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh); - r = 0; - out: -+ if (r != 0) { -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ } - return r; - } - -@@ -109,6 +116,7 @@ input_kex_dh(int type, u_int32_t seq, st - u_char hash[SSH_DIGEST_MAX_LENGTH]; - size_t klen = 0, slen, sbloblen, hashlen; - int kout, r; -+ const BIGNUM *pub_key; - - if (kex->verify_host_key == NULL) { - r = SSH_ERR_INVALID_ARGUMENT; -@@ -168,6 +176,7 @@ input_kex_dh(int type, u_int32_t seq, st - #endif - - /* calc and verify H */ -+ DH_get0_key(kex->dh, &pub_key, NULL); - hashlen = sizeof(hash); - if ((r = kex_dh_hash( - kex->hash_alg, -@@ -176,7 +185,7 @@ input_kex_dh(int type, u_int32_t seq, st - 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) -diff -up openssh/kexdhs.c.openssl openssh/kexdhs.c ---- openssh/kexdhs.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/kexdhs.c 2017-09-26 13:19:31.797249697 +0200 -@@ -87,6 +87,10 @@ kexdh_server(struct ssh *ssh) - ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init); - r = 0; - out: -+ if (r != 0) { -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ } - return r; - } - -@@ -101,6 +105,7 @@ input_kex_dh_init(int type, u_int32_t se - size_t sbloblen, slen; - size_t klen = 0, hashlen; - int kout, r; -+ const BIGNUM *pub_key; - - if (kex->load_host_public_key == NULL || - kex->load_host_private_key == NULL) { -@@ -163,6 +168,7 @@ input_kex_dh_init(int type, u_int32_t se - goto out; - /* calc H */ - hashlen = sizeof(hash); -+ DH_get0_key(kex->dh, &pub_key, NULL); - if ((r = kex_dh_hash( - kex->hash_alg, - kex->client_version_string, -@@ -171,7 +177,7 @@ input_kex_dh_init(int type, u_int32_t se - 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) - goto out; -@@ -197,7 +203,7 @@ input_kex_dh_init(int type, u_int32_t se - /* send server hostkey, DH pubkey 'f' and signed H */ - 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) - goto out; -diff -up openssh/kexgexc.c.openssl openssh/kexgexc.c ---- openssh/kexgexc.c.openssl 2017-09-26 13:19:31.783249611 +0200 -+++ openssh/kexgexc.c 2017-09-26 13:19:31.797249697 +0200 -@@ -95,6 +95,7 @@ input_kex_dh_gex_group(int type, u_int32 - struct kex *kex = ssh->kex; - BIGNUM *p = NULL, *g = NULL; - int r, bits; -+ const BIGNUM *pub_key; - - debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); - -@@ -119,24 +120,30 @@ input_kex_dh_gex_group(int type, u_int32 - 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 || -+ 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); - fprintf(stderr, "pub= "); -- BN_print_fp(stderr, kex->dh->pub_key); -+ BN_print_fp(stderr, pub_key); - fprintf(stderr, "\n"); - #endif - ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL); - ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply); - r = 0; - out: - BN_clear_free(p); - BN_clear_free(g); -+ if (r != 0) { -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ } - return r; - } - -@@ -152,6 +157,7 @@ input_kex_dh_gex_reply(int type, u_int32 - u_char hash[SSH_DIGEST_MAX_LENGTH]; - size_t klen = 0, slen, sbloblen, hashlen; - int kout, r; -+ const BIGNUM *p, *g, *pub_key; - - debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); - if (kex->verify_host_key == NULL) { -@@ -214,6 +220,8 @@ input_kex_dh_gex_reply(int type, u_int32 - kex->min = kex->max = -1; - - /* calc and verify H */ -+ DH_get0_pqg(kex->dh, &p, NULL, &g); -+ DH_get0_key(kex->dh, &pub_key, NULL); - hashlen = sizeof(hash); - if ((r = kexgex_hash( - kex->hash_alg, -@@ -223,8 +231,8 @@ input_kex_dh_gex_reply(int type, u_int32 - 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) -diff -up openssh/kexgexs.c.openssl openssh/kexgexs.c ---- openssh/kexgexs.c.openssl 2017-09-26 13:19:31.783249611 +0200 -+++ openssh/kexgexs.c 2017-09-26 13:19:31.797249697 +0200 -@@ -72,6 +72,7 @@ input_kex_dh_gex_request(int type, u_int - struct kex *kex = ssh->kex; - int r; - u_int min = 0, max = 0, nbits = 0; -+ const BIGNUM *p, *g; - - debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); - if ((r = sshpkt_get_u32(ssh, &min)) != 0 || -@@ -101,9 +102,10 @@ input_kex_dh_gex_request(int type, u_int - goto out; - } - debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); -+ 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_put_bignum2(ssh, p)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, g)) != 0 || - (r = sshpkt_send(ssh)) != 0) - goto out; - -@@ -115,6 +117,10 @@ input_kex_dh_gex_request(int type, u_int - ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init); - r = 0; - out: -+ if (r != 0) { -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ } - return r; - } - -@@ -129,6 +135,7 @@ input_kex_dh_gex_init(int type, u_int32_ - size_t sbloblen, slen; - size_t klen = 0, hashlen; - int kout, r; -+ const BIGNUM *p, *g, *pub_key; - - if (kex->load_host_public_key == NULL || - kex->load_host_private_key == NULL) { -@@ -191,6 +198,8 @@ input_kex_dh_gex_init(int type, u_int32_ - goto out; - /* calc H */ - hashlen = sizeof(hash); -+ 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,9 +208,9 @@ input_kex_dh_gex_init(int type, u_int32_ - 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) - goto out; -@@ -227,7 +236,7 @@ input_kex_dh_gex_init(int type, u_int32_ - /* send server hostkey, DH pubkey 'f' and signed H */ - 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) - goto out; -diff -up openssh/kexgssc.c.openssl openssh/kexgssc.c ---- openssh/kexgssc.c.openssl 2017-09-26 13:19:31.771249537 +0200 -+++ openssh/kexgssc.c 2017-09-26 13:19:31.797249697 +0200 -@@ -59,6 +59,7 @@ kexgss_client(struct ssh *ssh) { - BIGNUM *shared_secret = NULL; - BIGNUM *p = NULL; - BIGNUM *g = NULL; -+ const BIGNUM *pub_key, *p1, *g1; - u_char *kbuf; - u_char *serverhostkey = NULL; - u_char *empty = ""; -@@ -126,6 +127,7 @@ kexgss_client(struct ssh *ssh) { - - /* Step 1 - e is dh->pub_key */ - dh_gen_key(dh, ssh->kex->we_need * 8); -+ DH_get0_key(dh, &pub_key, NULL); - - /* This is f, we initialise it now to make life easier */ - dh_server_pub = BN_new(); -@@ -173,7 +175,7 @@ kexgss_client(struct ssh *ssh) { - packet_start(SSH2_MSG_KEXGSS_INIT); - packet_put_string(send_tok.value, - send_tok.length); -- packet_put_bignum2(dh->pub_key); -+ packet_put_bignum2((BIGNUM *)pub_key); - first = 0; - } else { - packet_start(SSH2_MSG_KEXGSS_CONTINUE); -@@ -282,13 +284,14 @@ kexgss_client(struct ssh *ssh) { - sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), - sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), - (serverhostkey ? serverhostkey : empty), slen, -- dh->pub_key, /* e */ -+ pub_key, /* e */ - dh_server_pub, /* f */ - shared_secret, /* K */ - hash, &hashlen - ); - break; - case KEX_GSS_GEX_SHA1: -+ DH_get0_pqg(dh, &p1, NULL, &g1); - kexgex_hash( - ssh->kex->hash_alg, - ssh->kex->client_version_string, -@@ -297,8 +300,8 @@ kexgss_client(struct ssh *ssh) { - sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), - (serverhostkey ? serverhostkey : empty), slen, - min, nbits, max, -- dh->p, dh->g, -- dh->pub_key, -+ p1, g1, -+ pub_key, - dh_server_pub, - shared_secret, - hash, &hashlen -diff -up openssh/kexgsss.c.openssl openssh/kexgsss.c ---- openssh/kexgsss.c.openssl 2017-09-26 13:19:31.771249537 +0200 -+++ openssh/kexgsss.c 2017-09-26 13:19:31.798249703 +0200 -@@ -78,6 +78,7 @@ kexgss_server(struct ssh *ssh) - char *mechs; - u_char hash[SSH_DIGEST_MAX_LENGTH]; - size_t hashlen; -+ const BIGNUM *p, *g, *pub_key; - - /* Initialise GSSAPI */ - -@@ -127,9 +128,10 @@ kexgss_server(struct ssh *ssh) - if (dh == NULL) - packet_disconnect("Protocol error: no matching group found"); - -+ DH_get0_pqg(dh, &p, NULL, &g); - packet_start(SSH2_MSG_KEXGSS_GROUP); -- packet_put_bignum2(dh->p); -- packet_put_bignum2(dh->g); -+ packet_put_bignum2((BIGNUM *)p); -+ packet_put_bignum2((BIGNUM *)g); - packet_send(); - - packet_write_wait(); -@@ -221,6 +223,7 @@ kexgss_server(struct ssh *ssh) - memset(kbuf, 0, klen); - free(kbuf); - -+ DH_get0_key(dh, &pub_key, NULL); - hashlen = sizeof(hash); - switch (ssh->kex->kex_type) { - case KEX_GSS_GRP1_SHA1: -@@ -232,7 +235,7 @@ kexgss_server(struct ssh *ssh) - sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), - sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), - NULL, 0, /* Change this if we start sending host keys */ -- dh_client_pub, dh->pub_key, shared_secret, -+ dh_client_pub, pub_key, shared_secret, - hash, &hashlen - ); - break; -@@ -244,9 +247,9 @@ kexgss_server(struct ssh *ssh) - sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), - NULL, 0, - cmin, nbits, cmax, -- dh->p, dh->g, -+ p, g, - dh_client_pub, -- dh->pub_key, -+ pub_key, - shared_secret, - hash, &hashlen - ); -@@ -270,7 +273,7 @@ kexgss_server(struct ssh *ssh) - fatal("Couldn't get MIC"); - - packet_start(SSH2_MSG_KEXGSS_COMPLETE); -- packet_put_bignum2(dh->pub_key); -+ packet_put_bignum2((BIGNUM *)pub_key); - packet_put_string(msg_tok.value,msg_tok.length); - - if (send_tok.length != 0) { -diff -up openssh/libcrypto-compat.c.openssl openssh/libcrypto-compat.c ---- openssh/libcrypto-compat.c.openssl 2017-09-26 13:19:31.798249703 +0200 -+++ openssh/libcrypto-compat.c 2017-09-26 13:19:31.798249703 +0200 -@@ -0,0 +1,428 @@ -+/* -+ * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. -+ * -+ * Licensed under the OpenSSL license (the "License"). You may not use -+ * this file except in compliance with the License. You can obtain a copy -+ * in the file LICENSE in the source distribution or at -+ * https://www.openssl.org/source/license.html -+ */ -+ -+#include "includes.h" -+ -+#if OPENSSL_VERSION_NUMBER < 0x10100000L -+ -+#include -+#include -+ -+static void *OPENSSL_zalloc(size_t num) -+{ -+ void *ret = OPENSSL_malloc(num); -+ -+ if (ret != NULL) -+ memset(ret, 0, num); -+ return ret; -+} -+ -+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d) -+{ -+ /* If the fields n and e in r are NULL, the corresponding input -+ * parameters MUST be non-NULL for n and e. d may be -+ * left NULL (in case only the public key is used). -+ */ -+ if ((r->n == NULL && n == NULL) -+ || (r->e == NULL && e == NULL)) -+ return 0; -+ -+ if (n != NULL) { -+ BN_free(r->n); -+ r->n = n; -+ } -+ if (e != NULL) { -+ BN_free(r->e); -+ r->e = e; -+ } -+ if (d != NULL) { -+ BN_free(r->d); -+ r->d = d; -+ } -+ -+ return 1; -+} -+ -+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q) -+{ -+ /* If the fields p and q in r are NULL, the corresponding input -+ * parameters MUST be non-NULL. -+ */ -+ if ((r->p == NULL && p == NULL) -+ || (r->q == NULL && q == NULL)) -+ return 0; -+ -+ if (p != NULL) { -+ BN_free(r->p); -+ r->p = p; -+ } -+ if (q != NULL) { -+ BN_free(r->q); -+ r->q = q; -+ } -+ -+ return 1; -+} -+ -+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp) -+{ -+ /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input -+ * parameters MUST be non-NULL. -+ */ -+ if ((r->dmp1 == NULL && dmp1 == NULL) -+ || (r->dmq1 == NULL && dmq1 == NULL) -+ || (r->iqmp == NULL && iqmp == NULL)) -+ return 0; -+ -+ if (dmp1 != NULL) { -+ BN_free(r->dmp1); -+ r->dmp1 = dmp1; -+ } -+ if (dmq1 != NULL) { -+ BN_free(r->dmq1); -+ r->dmq1 = dmq1; -+ } -+ if (iqmp != NULL) { -+ BN_free(r->iqmp); -+ r->iqmp = iqmp; -+ } -+ -+ return 1; -+} -+ -+void RSA_get0_key(const RSA *r, -+ const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) -+{ -+ if (n != NULL) -+ *n = r->n; -+ if (e != NULL) -+ *e = r->e; -+ if (d != NULL) -+ *d = r->d; -+} -+ -+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q) -+{ -+ if (p != NULL) -+ *p = r->p; -+ if (q != NULL) -+ *q = r->q; -+} -+ -+void RSA_get0_crt_params(const RSA *r, -+ const BIGNUM **dmp1, const BIGNUM **dmq1, -+ const BIGNUM **iqmp) -+{ -+ if (dmp1 != NULL) -+ *dmp1 = r->dmp1; -+ if (dmq1 != NULL) -+ *dmq1 = r->dmq1; -+ if (iqmp != NULL) -+ *iqmp = r->iqmp; -+} -+ -+void DSA_get0_pqg(const DSA *d, -+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) -+{ -+ if (p != NULL) -+ *p = d->p; -+ if (q != NULL) -+ *q = d->q; -+ if (g != NULL) -+ *g = d->g; -+} -+ -+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g) -+{ -+ /* If the fields p, q and g in d are NULL, the corresponding input -+ * parameters MUST be non-NULL. -+ */ -+ if ((d->p == NULL && p == NULL) -+ || (d->q == NULL && q == NULL) -+ || (d->g == NULL && g == NULL)) -+ return 0; -+ -+ if (p != NULL) { -+ BN_free(d->p); -+ d->p = p; -+ } -+ if (q != NULL) { -+ BN_free(d->q); -+ d->q = q; -+ } -+ if (g != NULL) { -+ BN_free(d->g); -+ d->g = g; -+ } -+ -+ return 1; -+} -+ -+void DSA_get0_key(const DSA *d, -+ const BIGNUM **pub_key, const BIGNUM **priv_key) -+{ -+ if (pub_key != NULL) -+ *pub_key = d->pub_key; -+ if (priv_key != NULL) -+ *priv_key = d->priv_key; -+} -+ -+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key) -+{ -+ /* If the field pub_key in d is NULL, the corresponding input -+ * parameters MUST be non-NULL. The priv_key field may -+ * be left NULL. -+ */ -+ if (d->pub_key == NULL && pub_key == NULL) -+ return 0; -+ -+ if (pub_key != NULL) { -+ BN_free(d->pub_key); -+ d->pub_key = pub_key; -+ } -+ if (priv_key != NULL) { -+ BN_free(d->priv_key); -+ d->priv_key = priv_key; -+ } -+ -+ return 1; -+} -+ -+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) -+{ -+ if (pr != NULL) -+ *pr = sig->r; -+ if (ps != NULL) -+ *ps = sig->s; -+} -+ -+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s) -+{ -+ if (r == NULL || s == NULL) -+ return 0; -+ BN_clear_free(sig->r); -+ BN_clear_free(sig->s); -+ sig->r = r; -+ sig->s = s; -+ return 1; -+} -+ -+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps) -+{ -+ if (pr != NULL) -+ *pr = sig->r; -+ if (ps != NULL) -+ *ps = sig->s; -+} -+ -+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) -+{ -+ if (r == NULL || s == NULL) -+ return 0; -+ BN_clear_free(sig->r); -+ BN_clear_free(sig->s); -+ sig->r = r; -+ sig->s = s; -+ return 1; -+} -+ -+void DH_get0_pqg(const DH *dh, -+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g) -+{ -+ if (p != NULL) -+ *p = dh->p; -+ if (q != NULL) -+ *q = dh->q; -+ if (g != NULL) -+ *g = dh->g; -+} -+ -+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) -+{ -+ /* If the fields p and g in d are NULL, the corresponding input -+ * parameters MUST be non-NULL. q may remain NULL. -+ */ -+ if ((dh->p == NULL && p == NULL) -+ || (dh->g == NULL && g == NULL)) -+ return 0; -+ -+ if (p != NULL) { -+ BN_free(dh->p); -+ dh->p = p; -+ } -+ if (q != NULL) { -+ BN_free(dh->q); -+ dh->q = q; -+ } -+ if (g != NULL) { -+ BN_free(dh->g); -+ dh->g = g; -+ } -+ -+ if (q != NULL) { -+ dh->length = BN_num_bits(q); -+ } -+ -+ return 1; -+} -+ -+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) -+{ -+ if (pub_key != NULL) -+ *pub_key = dh->pub_key; -+ if (priv_key != NULL) -+ *priv_key = dh->priv_key; -+} -+ -+int DH_set_length(DH *dh, long length) -+{ -+ dh->length = length; -+ return 1; -+} -+ -+const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx) -+{ -+ return ctx->iv; -+} -+ -+unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx) -+{ -+ return ctx->iv; -+} -+ -+EVP_MD_CTX *EVP_MD_CTX_new(void) -+{ -+ return OPENSSL_zalloc(sizeof(EVP_MD_CTX)); -+} -+ -+static void OPENSSL_clear_free(void *str, size_t num) -+{ -+ if (str == NULL) -+ return; -+ if (num) -+ OPENSSL_cleanse(str, num); -+ OPENSSL_free(str); -+} -+ -+/* This call frees resources associated with the context */ -+int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) -+{ -+ if (ctx == NULL) -+ return 1; -+ -+ /* -+ * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because -+ * sometimes only copies of the context are ever finalised. -+ */ -+ if (ctx->digest && ctx->digest->cleanup -+ && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED)) -+ ctx->digest->cleanup(ctx); -+ if (ctx->digest && ctx->digest->ctx_size && ctx->md_data -+ && !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) { -+ OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size); -+ } -+ EVP_PKEY_CTX_free(ctx->pctx); -+#ifndef OPENSSL_NO_ENGINE -+ ENGINE_finish(ctx->engine); -+#endif -+ OPENSSL_cleanse(ctx, sizeof(*ctx)); -+ -+ return 1; -+} -+ -+void EVP_MD_CTX_free(EVP_MD_CTX *ctx) -+{ -+ EVP_MD_CTX_reset(ctx); -+ OPENSSL_free(ctx); -+} -+ -+RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth) -+{ -+ RSA_METHOD *ret; -+ -+ ret = OPENSSL_malloc(sizeof(RSA_METHOD)); -+ -+ if (ret != NULL) { -+ memcpy(ret, meth, sizeof(*meth)); -+ ret->name = OPENSSL_strdup(meth->name); -+ if (ret->name == NULL) { -+ OPENSSL_free(ret); -+ return NULL; -+ } -+ } -+ -+ return ret; -+} -+ -+int RSA_meth_set1_name(RSA_METHOD *meth, const char *name) -+{ -+ char *tmpname; -+ -+ tmpname = OPENSSL_strdup(name); -+ if (tmpname == NULL) { -+ return 0; -+ } -+ -+ OPENSSL_free((char *)meth->name); -+ meth->name = tmpname; -+ -+ return 1; -+} -+ -+int RSA_meth_set_priv_enc(RSA_METHOD *meth, -+ int (*priv_enc) (int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, -+ int padding)) -+{ -+ meth->rsa_priv_enc = priv_enc; -+ return 1; -+} -+ -+int RSA_meth_set_priv_dec(RSA_METHOD *meth, -+ int (*priv_dec) (int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, -+ int padding)) -+{ -+ meth->rsa_priv_dec = priv_dec; -+ return 1; -+} -+ -+int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)) -+{ -+ meth->finish = finish; -+ return 1; -+} -+ -+void RSA_meth_free(RSA_METHOD *meth) -+{ -+ if (meth != NULL) { -+ OPENSSL_free((char *)meth->name); -+ OPENSSL_free(meth); -+ } -+} -+ -+int RSA_bits(const RSA *r) -+{ -+ return (BN_num_bits(r->n)); -+} -+ -+int DSA_bits(const DSA *dsa) -+{ -+ return BN_num_bits(dsa->p); -+} -+ -+RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) -+{ -+ if (pkey->type != EVP_PKEY_RSA) { -+ return NULL; -+ } -+ return pkey->pkey.rsa; -+} -+ -+#endif /* OPENSSL_VERSION_NUMBER */ -diff -up openssh/libcrypto-compat.h.openssl openssh/libcrypto-compat.h ---- openssh/libcrypto-compat.h.openssl 2017-09-26 13:19:31.798249703 +0200 -+++ openssh/libcrypto-compat.h 2017-09-26 13:19:31.798249703 +0200 -@@ -0,0 +1,59 @@ -+#ifndef LIBCRYPTO_COMPAT_H -+#define LIBCRYPTO_COMPAT_H -+ -+#if OPENSSL_VERSION_NUMBER < 0x10100000L -+ -+#include -+#include -+#include -+#include -+#include -+ -+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d); -+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q); -+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp); -+void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d); -+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q); -+void RSA_get0_crt_params(const RSA *r, const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp); -+ -+void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); -+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g); -+void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key); -+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key); -+ -+void DSA_SIG_get0(const DSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); -+int DSA_SIG_set0(DSA_SIG *sig, BIGNUM *r, BIGNUM *s); -+ -+void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, const BIGNUM **ps); -+int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s); -+ -+void DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g); -+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g); -+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key); -+int DH_set_length(DH *dh, long length); -+ -+const unsigned char *EVP_CIPHER_CTX_iv(const EVP_CIPHER_CTX *ctx); -+unsigned char *EVP_CIPHER_CTX_iv_noconst(EVP_CIPHER_CTX *ctx); -+int EVP_MD_CTX_reset(EVP_MD_CTX *ctx); -+EVP_MD_CTX *EVP_MD_CTX_new(void); -+void EVP_MD_CTX_free(EVP_MD_CTX *ctx); -+#define EVP_CIPHER_impl_ctx_size(e) e->ctx_size -+#define EVP_CIPHER_CTX_get_cipher_data(ctx) ctx->cipher_data -+ -+RSA_METHOD *RSA_meth_dup(const RSA_METHOD *meth); -+int RSA_meth_set1_name(RSA_METHOD *meth, const char *name); -+#define RSA_meth_get_finish(meth) meth->finish -+int RSA_meth_set_priv_enc(RSA_METHOD *meth, int (*priv_enc) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); -+int RSA_meth_set_priv_dec(RSA_METHOD *meth, int (*priv_dec) (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding)); -+int RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa)); -+void RSA_meth_free(RSA_METHOD *meth); -+ -+int RSA_bits(const RSA *r); -+int DSA_bits(const DSA *d); -+ -+RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey); -+ -+#endif /* OPENSSL_VERSION_NUMBER */ -+ -+#endif /* LIBCRYPTO_COMPAT_H */ -+ -diff -up openssh/Makefile.in.openssl openssh/Makefile.in ---- openssh/Makefile.in.openssl 2017-09-26 13:19:31.784249617 +0200 -+++ openssh/Makefile.in 2017-09-26 13:19:31.798249703 +0200 -@@ -101,7 +101,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kexdhc.o kexgexc.o kexecdhc.o kexc25519c.o \ - kexdhs.o kexgexs.o kexecdhs.o kexc25519s.o \ - platform-pledge.o platform-tracing.o platform-misc.o \ -- auditstub.o -+ auditstub.o libcrypto-compat.o - - SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ - sshconnect.o sshconnect2.o mux.o -diff -up openssh/monitor.c.openssl openssh/monitor.c ---- openssh/monitor.c.openssl 2017-09-26 13:19:31.789249648 +0200 -+++ openssh/monitor.c 2017-09-26 13:19:31.799249709 +0200 -@@ -631,9 +631,12 @@ mm_answer_moduli(int sock, Buffer *m) - return (0); - } else { - /* Send first bignum */ -+ const BIGNUM *p, *g; -+ -+ DH_get0_pqg(dh, &p, NULL, &g); - if ((r = sshbuf_put_u8(m, 1)) != 0 || -- (r = sshbuf_put_bignum2(m, dh->p)) != 0 || -- (r = sshbuf_put_bignum2(m, dh->g)) != 0) -+ (r = sshbuf_put_bignum2(m, p)) != 0 || -+ (r = sshbuf_put_bignum2(m, g)) != 0) - fatal("%s: buffer error: %s", __func__, ssh_err(r)); - - DH_free(dh); -diff -up openssh/openbsd-compat/openssl-compat.c.openssl openssh/openbsd-compat/openssl-compat.c ---- openssh/openbsd-compat/openssl-compat.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/openbsd-compat/openssl-compat.c 2017-09-26 13:19:31.799249709 +0200 -@@ -70,12 +70,19 @@ ssh_compatible_openssl(long headerver, l - void - ssh_OpenSSL_add_all_algorithms(void) - { -+#if OPENSSL_VERSION_NUMBER < 0x10100000L - OpenSSL_add_all_algorithms(); - - /* Enable use of crypto hardware */ - ENGINE_load_builtin_engines(); -+#if OPENSSL_VERSION_NUMBER < 0x10001000L - ENGINE_register_all_complete(); -+#endif - OPENSSL_config(NULL); -+#else -+ OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_DIGESTS | -+ OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CONFIG, NULL); -+#endif - } - #endif - -diff -up openssh/pam_ssh_agent_auth-0.10.3/configure.ac.openssl openssh/pam_ssh_agent_auth-0.10.3/configure.ac ---- openssh/pam_ssh_agent_auth-0.10.3/configure.ac.openssl 2016-11-13 04:24:32.000000000 +0100 -+++ openssh/pam_ssh_agent_auth-0.10.3/configure.ac 2017-09-26 13:19:31.799249709 +0200 -@@ -1829,6 +1829,7 @@ AC_RUN_IFELSE( - [AC_LANG_SOURCE([[ - #include - #include -+#include - int main(void) { exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); } - ]])], - [ -diff -up openssh/regress/unittests/sshkey/test_file.c.openssl openssh/regress/unittests/sshkey/test_file.c ---- openssh/regress/unittests/sshkey/test_file.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/regress/unittests/sshkey/test_file.c 2017-09-26 13:19:31.799249709 +0200 -@@ -46,6 +46,7 @@ sshkey_file_tests(void) - struct sshbuf *buf, *pw; - BIGNUM *a, *b, *c; - char *cp; -+ const BIGNUM *n, *p, *q, *g, *pub_key, *priv_key; - - TEST_START("load passphrase"); - pw = load_text_file("pw"); -@@ -60,9 +61,11 @@ 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); -+ 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 +154,11 @@ 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); -+ 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 -up openssh/regress/unittests/sshkey/test_sshkey.c.openssl openssh/regress/unittests/sshkey/test_sshkey.c ---- openssh/regress/unittests/sshkey/test_sshkey.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/regress/unittests/sshkey/test_sshkey.c 2017-09-26 13:19:31.800249715 +0200 -@@ -197,9 +197,6 @@ 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); - sshkey_free(k1); - TEST_DONE(); - -@@ -207,8 +204,6 @@ 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); - sshkey_free(k1); - TEST_DONE(); - -@@ -234,9 +229,6 @@ 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); - ASSERT_INT_EQ(sshkey_add_private(k1), 0); - sshkey_free(k1); - TEST_DONE(); -@@ -245,8 +237,6 @@ 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); - ASSERT_INT_EQ(sshkey_add_private(k1), 0); - sshkey_free(k1); - TEST_DONE(); -@@ -285,18 +275,13 @@ 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); -+ ASSERT_INT_EQ(RSA_bits(kr->rsa), 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); - TEST_DONE(); - - #ifdef OPENSSL_HAS_ECC -@@ -323,9 +308,6 @@ 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); - TEST_DONE(); - - TEST_START("equal KEY_RSA/demoted KEY_RSA"); -@@ -339,8 +321,6 @@ 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); - TEST_DONE(); - - TEST_START("equal KEY_DSA/demoted KEY_DSA"); -diff -up openssh/ssh.c.openssl openssh/ssh.c ---- openssh/ssh.c.openssl 2017-09-26 13:19:31.786249629 +0200 -+++ openssh/ssh.c 2017-09-26 13:19:31.800249715 +0200 -@@ -530,7 +530,9 @@ main(int ac, char **av) - sanitise_stdfd(); - - __progname = ssh_get_progname(av[0]); -+#if OPENSSL_VERSION_NUMBER < 0x10100000L - SSLeay_add_all_algorithms(); -+#endif - if (access("/etc/system-fips", F_OK) == 0) - if (! FIPSCHECK_verify(NULL, NULL)){ - if (FIPS_mode()) -diff -up openssh/sshd.c.openssl openssh/sshd.c ---- openssh/sshd.c.openssl 2017-09-26 13:19:31.792249666 +0200 -+++ openssh/sshd.c 2017-09-26 13:19:31.801249721 +0200 -@@ -1485,7 +1485,7 @@ main(int ac, char **av) - #endif - __progname = ssh_get_progname(av[0]); - -- SSLeay_add_all_algorithms(); -+ OpenSSL_add_all_algorithms(); - if (access("/etc/system-fips", F_OK) == 0) - if (! FIPSCHECK_verify(NULL, NULL)) { - openlog(__progname, LOG_PID, LOG_AUTHPRIV); -diff -up openssh/ssh-dss.c.openssl openssh/ssh-dss.c ---- openssh/ssh-dss.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/ssh-dss.c 2017-09-26 13:19:31.801249721 +0200 -@@ -55,6 +55,7 @@ ssh_dss_sign(const struct sshkey *key, u - size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); - struct sshbuf *b = NULL; - int ret = SSH_ERR_INVALID_ARGUMENT; -+ const BIGNUM *r, *s; - - if (lenp != NULL) - *lenp = 0; -@@ -76,15 +77,16 @@ ssh_dss_sign(const struct sshkey *key, u - 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; -@@ -137,6 +139,7 @@ ssh_dss_verify(const struct sshkey *key, - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - char *ktype = NULL; -+ BIGNUM *r = NULL, *s = NULL; - - if (key == NULL || key->dsa == NULL || - sshkey_type_plain(key->type) != KEY_DSA || -@@ -177,16 +180,19 @@ ssh_dss_verify(const struct sshkey *key, - - /* parse signature */ - 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; - 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) || -+ (DSA_SIG_set0(sig, r, s) == 0)) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -+ r = NULL; -+ s = NULL; - - /* sha1 the data */ - if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, -@@ -207,7 +213,9 @@ ssh_dss_verify(const struct sshkey *key, - - out: - explicit_bzero(digest, sizeof(digest)); -+ BN_free(r); -+ BN_free(s); - DSA_SIG_free(sig); - sshbuf_free(b); - free(ktype); - if (sigblob != NULL) { -diff -up openssh/ssh-ecdsa.c.openssl openssh/ssh-ecdsa.c ---- openssh/ssh-ecdsa.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/ssh-ecdsa.c 2017-09-26 13:19:31.801249721 +0200 -@@ -54,6 +54,7 @@ ssh_ecdsa_sign(const struct sshkey *key, - size_t len, dlen; - struct sshbuf *b = NULL, *bb = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; -+ const BIGNUM *r, *s; - - if (lenp != NULL) - *lenp = 0; -@@ -80,8 +81,9 @@ ssh_ecdsa_sign(const struct sshkey *key, - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 || -- (ret = sshbuf_put_bignum2(bb, sig->s)) != 0) -+ 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) -@@ -119,6 +121,7 @@ ssh_ecdsa_verify(const struct sshkey *ke - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL, *sigbuf = NULL; - char *ktype = NULL; -+ BIGNUM *r = NULL, *s = NULL; - - if (key == NULL || key->ecdsa == NULL || - sshkey_type_plain(key->type) != KEY_ECDSA || -@@ -147,15 +150,23 @@ ssh_ecdsa_verify(const struct sshkey *ke - } - - /* parse signature */ -- if ((sig = ECDSA_SIG_new()) == NULL) { -+ if ((sig = ECDSA_SIG_new()) == NULL || -+ (r = BN_new()) == NULL || -+ (s = BN_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 || -- sshbuf_get_bignum2(sigbuf, sig->s) != 0) { -+ if (sshbuf_get_bignum2(sigbuf, r) != 0 || -+ sshbuf_get_bignum2(sigbuf, s) != 0) { - ret = SSH_ERR_INVALID_FORMAT; - goto out; - } -+ if (ECDSA_SIG_set0(sig, r, s) == 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ r = NULL; -+ s = NULL; - if (sshbuf_len(sigbuf) != 0) { - ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; - goto out; -@@ -180,7 +191,9 @@ ssh_ecdsa_verify(const struct sshkey *ke - explicit_bzero(digest, sizeof(digest)); - sshbuf_free(sigbuf); - sshbuf_free(b); -+ BN_free(r); -+ BN_free(s); - ECDSA_SIG_free(sig); - free(ktype); - return ret; - } -diff -up openssh/sshkey.c.openssl openssh/sshkey.c ---- openssh/sshkey.c.openssl 2017-09-26 13:19:31.786249629 +0200 -+++ openssh/sshkey.c 2017-09-26 13:19:31.802249728 +0200 -@@ -267,10 +267,10 @@ sshkey_size(const struct sshkey *k) - #ifdef WITH_OPENSSL - case KEY_RSA: - case KEY_RSA_CERT: -- return BN_num_bits(k->rsa->n); -+ return RSA_bits(k->rsa); - case KEY_DSA: - case KEY_DSA_CERT: -- return BN_num_bits(k->dsa->p); -+ return DSA_bits(k->dsa); - case KEY_ECDSA: - case KEY_ECDSA_CERT: - return sshkey_curve_nid_to_bits(k->ecdsa_nid); -@@ -302,11 +302,17 @@ sshkey_is_private(const struct sshkey *k - switch (k->type) { - #ifdef WITH_OPENSSL - case KEY_RSA_CERT: -- case KEY_RSA: -- return k->rsa->d != NULL; -+ case KEY_RSA: { -+ const BIGNUM *d; -+ RSA_get0_key(k->rsa, NULL, NULL, &d); -+ return d != NULL; -+ } - case KEY_DSA_CERT: -- case KEY_DSA: -- return k->dsa->priv_key != NULL; -+ case KEY_DSA: { -+ const BIGNUM *priv_key; -+ DSA_get0_key(k->dsa, NULL, &priv_key); -+ return priv_key != NULL; -+ } - #ifdef OPENSSL_HAS_ECC - case KEY_ECDSA_CERT: - case KEY_ECDSA: -@@ -496,10 +501,7 @@ sshkey_new(int type) - #ifdef WITH_OPENSSL - case KEY_RSA: - case KEY_RSA_CERT: -- if ((rsa = RSA_new()) == NULL || -- (rsa->n = BN_new()) == NULL || -- (rsa->e = BN_new()) == NULL) { -- RSA_free(rsa); -+ if ((rsa = RSA_new()) == NULL) { - free(k); - return NULL; - } -@@ -508,12 +509,7 @@ sshkey_new(int type) - break; - case KEY_DSA: - case KEY_DSA_CERT: -- 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) { -- DSA_free(dsa); -+ if ((dsa = DSA_new()) == NULL) { - free(k); - return NULL; - } -@@ -553,21 +548,10 @@ sshkey_add_private(struct sshkey *k) - #ifdef WITH_OPENSSL - case KEY_RSA: - case KEY_RSA_CERT: --#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) || -- bn_maybe_alloc_failed(k->rsa->q) || -- bn_maybe_alloc_failed(k->rsa->p) || -- bn_maybe_alloc_failed(k->rsa->dmq1) || -- bn_maybe_alloc_failed(k->rsa->dmp1)) -- return SSH_ERR_ALLOC_FAIL; - break; - case KEY_DSA: - case KEY_DSA_CERT: -- if (bn_maybe_alloc_failed(k->dsa->priv_key)) -- return SSH_ERR_ALLOC_FAIL; - break; --#undef bn_maybe_alloc_failed - case KEY_ECDSA: - case KEY_ECDSA_CERT: - /* Cannot do anything until we know the group */ -@@ -684,17 +668,31 @@ sshkey_equal_public(const struct sshkey - switch (a->type) { - #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; -+ case KEY_RSA: { -+ const BIGNUM *a_e, *a_n, *b_e, *b_n; -+ -+ if (a->rsa == NULL || b->rsa == NULL) -+ return 0; -+ RSA_get0_key(a->rsa, &a_n, &a_e, NULL); -+ RSA_get0_key(b->rsa, &b_n, &b_e, NULL); -+ 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; -+ case KEY_DSA: { -+ 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 || b->dsa == NULL) -+ return 0; -+ DSA_get0_pqg(a->dsa, &a_p, &a_q, &a_g); -+ DSA_get0_key(a->dsa, &a_pub_key, NULL); -+ DSA_get0_pqg(b->dsa, &b_p, &b_q, &b_g); -+ 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: -@@ -769,15 +767,21 @@ to_blob_buf(const struct sshkey *key, st - return ret; - break; - #ifdef WITH_OPENSSL -- case KEY_DSA: -- if (key->dsa == NULL) -- return SSH_ERR_INVALID_ARGUMENT; -- 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) -- return ret; -+ case KEY_DSA: { -+ const BIGNUM *p, *q, *g, *pub_key; -+ -+ if (key->dsa == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ -+ 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, 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: -@@ -790,13 +794,18 @@ to_blob_buf(const struct sshkey *key, st - return ret; - break; - # endif -- case KEY_RSA: -- if (key->rsa == NULL) -- return SSH_ERR_INVALID_ARGUMENT; -- 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) -- return ret; -+ case KEY_RSA: { -+ const BIGNUM *e, *n; -+ -+ if (key->rsa == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ -+ RSA_get0_key(key->rsa, &n, &e, NULL); -+ if ((ret = sshbuf_put_cstring(b, typename)) != 0 || -+ (ret = sshbuf_put_bignum2(b, e)) != 0 || -+ (ret = sshbuf_put_bignum2(b, n)) != 0) -+ return ret; -+ } - break; - #endif /* WITH_OPENSSL */ - case KEY_ED25519: -@@ -1672,15 +1681,32 @@ sshkey_from_private(const struct sshkey - switch (k->type) { - #ifdef WITH_OPENSSL - case KEY_DSA: -- 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)) { -- sshkey_free(n); -- return SSH_ERR_ALLOC_FAIL; -+ case KEY_DSA_CERT: { -+ const BIGNUM *k_p, *k_q, *k_g, *k_pub_key; -+ BIGNUM *n_p = NULL, *n_q = NULL, *n_g = NULL, *n_pub_key = NULL; -+ -+ if ((n = sshkey_new(k->type)) == NULL) -+ return SSH_ERR_ALLOC_FAIL; -+ -+ DSA_get0_pqg(k->dsa, &k_p, &k_q, &k_g); -+ DSA_get0_key(k->dsa, &k_pub_key, NULL); -+ -+ if (((n_p = BN_dup(k_p)) == NULL) || -+ ((n_q = BN_dup(k_q)) == NULL) || -+ ((n_g = BN_dup(k_g)) == NULL) || -+ (DSA_set0_pqg(n->dsa, n_p, n_q, n_g) == 0)) { -+ sshkey_free(n); -+ BN_free(n_p); -+ BN_free(n_q); -+ BN_free(n_g); -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ if (((n_pub_key = BN_dup(k_pub_key)) == NULL) || -+ (DSA_set0_key(n->dsa, n_pub_key, NULL) == 0)) { -+ sshkey_free(n); -+ BN_free(n_pub_key); -+ return SSH_ERR_ALLOC_FAIL; -+ } - } - break; - # ifdef OPENSSL_HAS_ECC -@@ -1702,13 +1728,22 @@ sshkey_from_private(const struct sshkey - break; - # endif /* OPENSSL_HAS_ECC */ - case KEY_RSA: -- 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)) { -- sshkey_free(n); -- return SSH_ERR_ALLOC_FAIL; -+ case KEY_RSA_CERT: { -+ const BIGNUM *k_n, *k_e; -+ BIGNUM *n_n = NULL, *n_e = NULL; -+ -+ if ((n = sshkey_new(k->type)) == NULL) -+ return SSH_ERR_ALLOC_FAIL; -+ -+ RSA_get0_key(k->rsa, &k_n, &k_e, NULL); -+ if (((n_n = BN_dup(k_n)) == NULL) || -+ ((n_e = BN_dup(k_e)) == NULL) || -+ RSA_set0_key(n->rsa, n_n, n_e, NULL) == 0) { -+ sshkey_free(n); -+ BN_free(n_n); -+ BN_free(n_e); -+ return SSH_ERR_ALLOC_FAIL; -+ } - } - break; - #endif /* WITH_OPENSSL */ -@@ -1907,12 +1942,22 @@ sshkey_from_blob_internal(struct sshbuf - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if (sshbuf_get_bignum2(b, key->rsa->e) != 0 || -- sshbuf_get_bignum2(b, key->rsa->n) != 0) { -- ret = SSH_ERR_INVALID_FORMAT; -- goto out; -+ { -+ BIGNUM *e, *n; -+ -+ e = BN_new(); -+ n = BN_new(); -+ if (e == NULL || n == NULL || -+ sshbuf_get_bignum2(b, e) != 0 || -+ sshbuf_get_bignum2(b, n) != 0 || -+ RSA_set0_key(key->rsa, n, e, NULL) == 0) { -+ BN_free(e); -+ BN_free(n); -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } - } -- if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { -+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) { - ret = SSH_ERR_KEY_LENGTH; - goto out; - } -@@ -1932,12 +1977,34 @@ sshkey_from_blob_internal(struct sshbuf - 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) { -- ret = SSH_ERR_INVALID_FORMAT; -- goto out; -+ { -+ BIGNUM *p, *q, *g, *pub_key; -+ -+ p = BN_new(); -+ q = BN_new(); -+ g = BN_new(); -+ pub_key = BN_new(); -+ -+ if (p == NULL || q == NULL || g == NULL || -+ pub_key == NULL || -+ 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 || -+ DSA_set0_pqg(key->dsa, p, q, g) == 0) { -+ BN_free(p); -+ BN_free(q); -+ BN_free(g); -+ BN_free(pub_key); -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ if (DSA_set0_key(key->dsa, pub_key, NULL) == 0) { -+ BN_free(pub_key); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } - } - #ifdef DEBUG_PK - DSA_print_fp(stderr, key->dsa, 8); -@@ -2171,26 +2238,53 @@ sshkey_demote(const struct sshkey *k, st - if ((ret = sshkey_cert_copy(k, pk)) != 0) - 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) { -- ret = SSH_ERR_ALLOC_FAIL; -- goto fail; -+ case KEY_RSA: { -+ const BIGNUM *k_e, *k_n; -+ BIGNUM *pk_e = NULL, *pk_n = NULL; -+ -+ RSA_get0_key(k->rsa, &k_n, &k_e, NULL); -+ if ((pk->rsa = RSA_new()) == NULL || -+ (pk_e = BN_dup(k_e)) == NULL || -+ (pk_n = BN_dup(k_n)) == NULL || -+ RSA_set0_key(pk->rsa, pk_n, pk_e, NULL) == 0) { -+ BN_free(pk_e); -+ BN_free(pk_n); -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto fail; - } -+ } - 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) { -- ret = SSH_ERR_ALLOC_FAIL; -- goto fail; -+ case KEY_DSA: { -+ const BIGNUM *k_p, *k_q, *k_g, *k_pub_key; -+ BIGNUM *pk_p = NULL, *pk_q = NULL, *pk_g = NULL; -+ BIGNUM *pk_pub_key = NULL; -+ -+ DSA_get0_pqg(k->dsa, &k_p, &k_q, &k_g); -+ DSA_get0_key(k->dsa, &k_pub_key, NULL); -+ -+ if ((pk->dsa = DSA_new()) == NULL || -+ (pk_p = BN_dup(k_p)) == NULL || -+ (pk_q = BN_dup(k_q)) == NULL || -+ (pk_g = BN_dup(k_g)) == NULL || -+ (pk_pub_key = BN_dup(k_pub_key)) == NULL || -+ DSA_set0_pqg(pk->dsa, pk_p, pk_q, pk_g) == 0) { -+ BN_free(pk_p); -+ BN_free(pk_q); -+ BN_free(pk_g); -+ BN_free(pk_pub_key); -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto fail; -+ } -+ -+ if (DSA_set0_key(pk->dsa, pk_pub_key, NULL) == 0) { -+ BN_free(pk_pub_key); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto fail; -+ } - } - break; - case KEY_ECDSA_CERT: -@@ -2312,12 +2406,17 @@ sshkey_certify_custom(struct sshkey *k, - /* XXX this substantially duplicates to_blob(); refactor */ - 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) -- goto out; -+ case KEY_DSA_CERT: { -+ 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: -@@ -2329,10 +2428,15 @@ sshkey_certify_custom(struct sshkey *k, - goto out; - 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) -- goto out; -+ case KEY_RSA_CERT: { -+ const BIGNUM *e, *n; -+ -+ RSA_get0_key(k->rsa, &n, &e, NULL); -+ if (e == NULL || n == 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: -@@ -2505,43 +2609,65 @@ sshkey_private_serialize(const struct ss - goto out; - 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) -- goto out; -+ case KEY_RSA: { -+ 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; - } -- 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) -- goto out; -+ { -+ const BIGNUM *d, *iqmp, *p, *q; -+ -+ RSA_get0_key(key->rsa, NULL, NULL, &d); -+ RSA_get0_factors(key->rsa, &p, &q); -+ RSA_get0_crt_params(key->rsa, NULL, NULL, &iqmp); -+ if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 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) -- goto out; -+ case KEY_DSA: { -+ 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; - } -- if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || -- (r = sshbuf_put_bignum2(b, key->dsa->priv_key)) != 0) -- 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, priv_key)) != 0) -+ goto out; -+ } - break; - # ifdef OPENSSL_HAS_ECC - case KEY_ECDSA: -@@ -2617,18 +2743,51 @@ sshkey_private_deserialize(struct sshbuf - 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) -- goto out; -+ { -+ BIGNUM *p, *q, *g, *pub_key, *priv_key; -+ -+ p = BN_new(); -+ q = BN_new(); -+ g = BN_new(); -+ pub_key = BN_new(); -+ priv_key = BN_new(); -+ 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 || -+ (r = ((DSA_set0_pqg(k->dsa, p, q, g) == 0) -+ ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) { -+ BN_free(p); -+ BN_free(q); -+ BN_free(g); -+ BN_free(pub_key); -+ BN_free(priv_key); -+ goto out; -+ } -+ if (DSA_set0_key(k->dsa, pub_key, priv_key) == 0) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ BN_free(pub_key); -+ BN_free(priv_key); -+ goto out; -+ } -+ } - break; -- case KEY_DSA_CERT: -- if ((r = sshkey_froms(buf, &k)) != 0 || -- (r = sshkey_add_private(k)) != 0 || -- (r = sshbuf_get_bignum2(buf, k->dsa->priv_key)) != 0) -- goto out; -+ case KEY_DSA_CERT: { -+ BIGNUM *priv_key = BN_new(); -+ -+ if (priv_key == NULL || -+ (r = sshkey_froms(buf, &k)) != 0 || -+ (r = sshkey_add_private(k)) != 0 || -+ (r = sshbuf_get_bignum2(buf, priv_key)) != 0 || -+ (r = ((DSA_set0_key(k->dsa, NULL, priv_key) == 0) -+ ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) { -+ BN_free(priv_key); -+ goto out; -+ } -+ } - break; - # ifdef OPENSSL_HAS_ECC - case KEY_ECDSA: -@@ -2687,29 +2846,89 @@ sshkey_private_deserialize(struct sshbuf - 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) -- goto out; -- if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { -+ { -+ BIGNUM *n, *e, *d, *iqmp, *p, *q; -+ -+ n = BN_new(); -+ e = BN_new(); -+ d = BN_new(); -+ iqmp = BN_new(); -+ p = BN_new(); -+ q = BN_new(); -+ -+ if (n == NULL || e == NULL || d == NULL || -+ iqmp == NULL || p == NULL || q == NULL || -+ (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 || -+ (r = ((RSA_set0_key(k->rsa, n, e, d) == 0) -+ ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) { -+ BN_free(n); -+ BN_free(e); -+ BN_free(d); -+ BN_free(iqmp); -+ BN_free(p); -+ BN_free(q); -+ goto out; -+ } -+ if (RSA_set0_factors(k->rsa, p, q) == 0) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ BN_free(iqmp); -+ BN_free(p); -+ BN_free(q); -+ goto out; -+ } -+ if ((r = ssh_rsa_generate_additional_parameters(k, iqmp)) != 0) { -+ BN_free(iqmp); -+ goto out; -+ } -+ } -+ if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) { - r = SSH_ERR_KEY_LENGTH; - goto out; - } - break; -- case KEY_RSA_CERT: -- 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) -- goto out; -- if (BN_num_bits(k->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { -+ case KEY_RSA_CERT: { -+ BIGNUM *d, *iqmp, *p, *q; -+ -+ /* N and E are already set so make sure we will not overwrite them */ -+ d = BN_new(); -+ iqmp = BN_new(); -+ p = BN_new(); -+ q = BN_new(); -+ -+ if (d == NULL || iqmp == NULL || p == NULL || -+ q == NULL || -+ (r = sshkey_froms(buf, &k)) != 0 || -+ (r = sshkey_add_private(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 || -+ (r = ((RSA_set0_key(k->rsa, NULL, NULL, d) == 0) -+ ? SSH_ERR_LIBCRYPTO_ERROR : 0)) != 0) { -+ BN_free(d); -+ BN_free(iqmp); -+ BN_free(p); -+ BN_free(q); -+ goto out; -+ } -+ if (RSA_set0_factors(k->rsa, p, q) == 0) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ BN_free(p); -+ BN_free(q); -+ goto out; -+ } -+ if (ssh_rsa_generate_additional_parameters(k, iqmp) != 0) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ free(iqmp); -+ goto out; -+ } -+ } -+ if (RSA_bits(k->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) { - r = SSH_ERR_KEY_LENGTH; - goto out; - } -@@ -3427,7 +3646,9 @@ translate_libcrypto_error(unsigned long - switch (pem_reason) { - case EVP_R_BAD_DECRYPT: - return SSH_ERR_KEY_WRONG_PASSPHRASE; -+#ifdef EVP_R_BN_DECODE_ERROR - case EVP_R_BN_DECODE_ERROR: -+#endif - case EVP_R_DECODE_ERROR: - #ifdef EVP_R_PRIVATE_KEY_DECODE_ERROR - case EVP_R_PRIVATE_KEY_DECODE_ERROR: -@@ -3492,7 +3713,7 @@ sshkey_parse_private_pem_fileblob(struct - 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; -@@ -3507,11 +3728,11 @@ sshkey_parse_private_pem_fileblob(struct - 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; -@@ -3523,7 +3744,7 @@ sshkey_parse_private_pem_fileblob(struct - 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; -diff -up openssh/ssh-keygen.c.openssl openssh/ssh-keygen.c ---- openssh/ssh-keygen.c.openssl 2017-09-26 13:19:31.787249636 +0200 -+++ openssh/ssh-keygen.c 2017-09-26 13:19:31.802249728 +0200 -@@ -501,40 +501,67 @@ do_convert_private_ssh2_from_blob(u_char - free(type); - - 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); -+ case KEY_DSA: { -+ 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) -+ fatal("BN_new() failed"); -+ 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"); -+ } -+ } - break; -- case KEY_RSA: -- if ((r = sshbuf_get_u8(b, &e1)) != 0 || -- (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) || -- (e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0)) -- fatal("%s: buffer error: %s", __func__, ssh_err(r)); -- e = e1; -- debug("e %lx", e); -- if (e < 30) { -- e <<= 8; -- e += e2; -- debug("e %lx", e); -- e <<= 8; -- e += e3; -+ case KEY_RSA: { -+ BIGNUM *bn_e = NULL, *bn_d = NULL, *bn_n = NULL, *bn_iqmp = NULL, *bn_p = NULL, *bn_q = NULL; -+ -+ if ((bn_e = BN_new()) == NULL || -+ (bn_d = BN_new()) == NULL || -+ (bn_n = BN_new()) == NULL || -+ (bn_iqmp = BN_new()) == NULL || -+ (bn_p = BN_new()) == NULL || -+ (bn_q = BN_new()) == NULL) -+ fatal("BN_new() failed"); -+ -+ if ((r = sshbuf_get_u8(b, &e1)) != 0 || -+ (e1 < 30 && (r = sshbuf_get_u8(b, &e2)) != 0) || -+ (e1 < 30 && (r = sshbuf_get_u8(b, &e3)) != 0)) -+ fatal("%s: buffer error: %s", __func__, ssh_err(r)); -+ e = e1; - debug("e %lx", e); -+ if (e < 30) { -+ e <<= 8; -+ e += e2; -+ debug("e %lx", e); -+ e <<= 8; -+ e += e3; -+ debug("e %lx", e); -+ } -+ if (!BN_set_word(bn_e, e)) { -+ sshbuf_free(b); -+ sshkey_free(key); -+ return NULL; -+ } -+ buffer_get_bignum_bits(b, bn_d); -+ buffer_get_bignum_bits(b, bn_n); -+ buffer_get_bignum_bits(b, bn_iqmp); -+ buffer_get_bignum_bits(b, bn_q); -+ buffer_get_bignum_bits(b, bn_p); -+ if (RSA_set0_key(key->rsa, bn_n, bn_e, bn_d) == 0 || -+ RSA_set0_factors(key->rsa, bn_p, bn_q) == 0) -+ fatal("Failed to set RSA parameters"); -+ if ((r = ssh_rsa_generate_additional_parameters(key, bn_iqmp)) != 0) -+ fatal("generate RSA parameters failed: %s", ssh_err(r)); - } -- if (!BN_set_word(key->rsa->e, 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 ((r = ssh_rsa_generate_additional_parameters(key)) != 0) -- fatal("generate RSA parameters failed: %s", ssh_err(r)); - break; - } - rlen = sshbuf_len(b); -@@ -642,7 +669,7 @@ do_convert_from_pkcs8(struct sshkey **k, - identity_file); - } - fclose(fp); -- switch (EVP_PKEY_type(pubkey->type)) { -+ switch (EVP_PKEY_base_id(pubkey)) { - case EVP_PKEY_RSA: - if ((*k = sshkey_new(KEY_UNSPEC)) == NULL) - fatal("sshkey_new failed"); -@@ -666,7 +693,7 @@ do_convert_from_pkcs8(struct sshkey **k, - #endif - default: - fatal("%s: unsupported pubkey type %d", __func__, -- EVP_PKEY_type(pubkey->type)); -+ EVP_PKEY_base_id(pubkey)); - } - EVP_PKEY_free(pubkey); - return; -@@ -1798,6 +1825,7 @@ do_ca_sign(struct passwd *pw, int argc, - #ifdef ENABLE_PKCS11 - pkcs11_terminate(); - #endif -+ free(ca); - exit(0); - } - -diff -up openssh/sshkey.h.openssl openssh/sshkey.h ---- openssh/sshkey.h.openssl 2017-09-26 13:19:31.780249593 +0200 -+++ openssh/sshkey.h 2017-09-26 13:19:31.803249734 +0200 -@@ -199,7 +199,7 @@ int sshkey_parse_private_fileblob_type(s - const char *passphrase, struct sshkey **keyp, char **commentp); - - /* XXX should be internal, but used by ssh-keygen */ --int ssh_rsa_generate_additional_parameters(struct sshkey *); -+int ssh_rsa_generate_additional_parameters(struct sshkey *, BIGNUM *iqmp); - - /* stateful keys (e.g. XMSS) */ - #ifdef NO_ATTRIBUTE_ON_PROTOTYPE_ARGS -diff -up openssh/ssh-pkcs11-client.c.openssl openssh/ssh-pkcs11-client.c ---- openssh/ssh-pkcs11-client.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/ssh-pkcs11-client.c 2017-09-26 13:19:31.803249734 +0200 -@@ -143,12 +143,16 @@ pkcs11_rsa_private_encrypt(int flen, con - static int - wrap_rsa_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 == NULL) { -+ helper_rsa = RSA_meth_dup(RSA_get_default_method()); -+ if (helper_rsa == NULL) -+ error("RSA_meth_dup failed"); -+ 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 -up openssh/ssh-pkcs11.c.openssl openssh/ssh-pkcs11.c ---- openssh/ssh-pkcs11.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/ssh-pkcs11.c 2017-09-26 13:19:31.803249734 +0200 -@@ -67,7 +67,7 @@ struct pkcs11_key { - CK_ULONG slotidx; - CK_ULONG key_type; - int (*orig_finish)(RSA *rsa); -- RSA_METHOD rsa_method; -+ RSA_METHOD *rsa_method; - char *keyid; - int keyid_len; - char *label; -@@ -183,6 +183,7 @@ pkcs11_rsa_finish(RSA *rsa) - pkcs11_provider_unref(k11->provider); - free(k11->keyid); - free(k11->label); -+ RSA_meth_free(k11->rsa_method); - free(k11); - } - return (rv); -@@ -326,13 +326,21 @@ pkcs11_rsa_wrap(struct pkcs11_provider * - memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen); - k11->label[label_attrib->ulValueLen] = 0; - } -- 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_dup(def)) == NULL || -+ RSA_meth_set1_name(k11->rsa_method, "pkcs11") == 0 || -+ RSA_meth_set_priv_enc(k11->rsa_method, pkcs11_rsa_private_encrypt) == 0 || -+ RSA_meth_set_priv_dec(k11->rsa_method, pkcs11_rsa_private_decrypt) == 0 || -+ RSA_meth_set_finish(k11->rsa_method, pkcs11_rsa_finish) == 0) { -+ RSA_meth_free(k11->rsa_method); -+ k11->rsa_method = NULL; -+ pkcs11_provider_unref(k11->provider); -+ free(k11->keyid); -+ free(k11); -+ return (-1); -+ } -+ -+ RSA_set_method(rsa, k11->rsa_method); - RSA_set_app_data(rsa, k11); - return (0); - } -@@ -460,6 +468,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_p - CK_ULONG nfound; - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f; -+ const BIGNUM *n, *e; - - f = p->module->function_list; - session = p->module->slotinfo[slotidx].session; -@@ -512,10 +521,16 @@ pkcs11_fetch_keys_filter(struct pkcs11_p - if ((rsa = RSA_new()) == NULL) { - error("RSA_new failed"); - } else { -- rsa->n = BN_bin2bn(attribs[2].pValue, -+ BIGNUM *rsa_n, *rsa_e; -+ -+ rsa_n = BN_bin2bn(attribs[2].pValue, - attribs[2].ulValueLen, NULL); -- rsa->e = BN_bin2bn(attribs[3].pValue, -+ rsa_e = BN_bin2bn(attribs[3].pValue, - attribs[3].ulValueLen, NULL); -+ if (rsa_n == NULL || rsa_e == NULL) -+ error("BN_bin2bn failed"); -+ if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0) -+ error("RSA_set0_key failed"); - } - #ifdef ENABLE_PKCS11_ECDSA - } else if (attribs[2].type == CKA_EC_PARAMS ) { -@@ -920,19 +936,19 @@ pkcs11_fetch_keys_filter(struct pkcs11_p - } else if ((evp = X509_get_pubkey(x509)) == NULL) { - debug("X509_get_pubkey failed"); - } else { -- switch (evp->type) { -+ switch (EVP_PKEY_id(evp)) { - case EVP_PKEY_RSA: -- if (evp->pkey.rsa == NULL) -+ if (EVP_PKEY_get0_RSA(evp) == NULL) - debug("Missing RSA key"); -- else if ((rsa = RSAPublicKey_dup( -- evp->pkey.rsa)) == NULL) -+ else if ((rsa = RSAPublicKey_dup( -+ EVP_PKEY_get0_RSA(evp))) == NULL) - error("RSAPublicKey_dup failed"); - break; - case EVP_PKEY_EC: -- if (evp->pkey.ecdsa == NULL) -+ if (EVP_PKEY_get0_EC_KEY(evp) == NULL) - debug("Missing ECDSA key"); -- else if ((ecdsa = EC_KEY_dup( -- evp->pkey.ecdsa)) == NULL) -+ else if ((ecdsa = EC_KEY_dup( -+ EVP_PKEY_get0_EC_KEY(evp))) == NULL) - error("EC_KEY_dup failed"); - break; - default: -@@ -538,7 +551,9 @@ pkcs11_fetch_keys_filter(struct pkcs11_p - } - key = NULL; - if (rsa || ecdsa) { -- if (rsa && rsa->n && rsa->e && -+ if (rsa) -+ RSA_get0_key(rsa, &n, &e, NULL); -+ if (rsa && n && e && - pkcs11_rsa_wrap(p, slotidx, &attribs[0], &attribs[1], rsa) == 0) { - if ((key = sshkey_new(KEY_UNSPEC)) == NULL) - fatal("sshkey_new failed"); -diff -up openssh/ssh-rsa.c.openssl openssh/ssh-rsa.c ---- openssh/ssh-rsa.c.openssl 2017-09-19 06:26:43.000000000 +0200 -+++ openssh/ssh-rsa.c 2017-09-26 13:19:31.803249734 +0200 -@@ -78,38 +78,50 @@ rsa_hash_alg_nid(int type) - } - - int --ssh_rsa_generate_additional_parameters(struct sshkey *key) -+ssh_rsa_generate_additional_parameters(struct sshkey *key, BIGNUM *iqmp) - { - BIGNUM *aux = NULL; - BN_CTX *ctx = NULL; -- BIGNUM d; -+ BIGNUM *d = NULL; - int r; -+ const BIGNUM *p, *q, *rsa_d; -+ BIGNUM *dmp1 = NULL, *dmq1 = NULL; - - if (key == NULL || key->rsa == NULL || - sshkey_type_plain(key->type) != KEY_RSA) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((ctx = BN_CTX_new()) == NULL) -- return SSH_ERR_ALLOC_FAIL; -- if ((aux = BN_new()) == NULL) { -+ RSA_get0_factors(key->rsa, &p, &q); -+ RSA_get0_key(key->rsa, NULL, NULL, &rsa_d); -+ -+ if ((ctx = BN_CTX_new()) == NULL || -+ (aux = BN_new()) == NULL || -+ (d = BN_new()) == NULL || -+ (dmp1 = BN_new()) == NULL || -+ (dmq1 = BN_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - BN_set_flags(aux, BN_FLG_CONSTTIME); - -- BN_init(&d); -- BN_with_flags(&d, key->rsa->d, BN_FLG_CONSTTIME); -+ BN_with_flags(d, 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)) { -+ 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, iqmp) == 0)) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -+ dmp1 = NULL; -+ dmq1 = NULL; - r = 0; - out: -+ BN_free(d); - BN_clear_free(aux); -+ BN_clear_free(dmp1); -+ BN_clear_free(dmq1); - BN_CTX_free(ctx); - return r; - } -@@ -136,7 +145,7 @@ ssh_rsa_sign(const struct sshkey *key, u - 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) -@@ -210,7 +219,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) ---- openssh-7.6p1/configure.ac.openssl 2017-10-04 15:47:48.440672023 +0200 -+++ openssh-7.6p1/configure.ac 2017-10-04 15:47:23.327531495 +0200 -@@ -2730,6 +2730,7 @@ - AC_MSG_ERROR([OpenSSL >= 1.0.1 required (have "$ssl_library_ver")]) - ;; - 100*) ;; # 1.0.x -+ 101*) ;; # 1.1.x is supported by this patch too - 200*) ;; # LibreSSL - *) - AC_MSG_ERROR([OpenSSL >= 1.1.0 is not yet supported (have "$ssl_library_ver")]) diff --git a/openssh-7.5p1-sandbox.patch b/openssh-7.5p1-sandbox.patch index b761962..85a4b0f 100644 --- a/openssh-7.5p1-sandbox.patch +++ b/openssh-7.5p1-sandbox.patch @@ -20,8 +20,8 @@ index ca75cc7..6e7de31 100644 +#if defined(__NR_flock) && defined(__s390__) + SC_ALLOW(__NR_flock), +#endif - #ifdef __NR_geteuid - SC_ALLOW(__NR_geteuid), + #ifdef __NR_futex + SC_ALLOW(__NR_futex), #endif @@ -178,6 +181,9 @@ static const struct sock_filter preauth_insns[] = { #ifdef __NR_gettimeofday diff --git a/openssh-7.6p1-audit.patch b/openssh-7.6p1-audit.patch index e184894..299d632 100644 --- a/openssh-7.6p1-audit.patch +++ b/openssh-7.6p1-audit.patch @@ -2048,12 +2048,12 @@ diff -up openssh-7.6p1/sshd.c.audit openssh-7.6p1/sshd.c + fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX); + else + fp = NULL; - if ((r = sshkey_demote(sensitive_data.host_keys[i], - &tmp)) != 0) - fatal("could not demote host %s key: %s", - sshkey_type(sensitive_data.host_keys[i]), - ssh_err(r)); - sshkey_free(sensitive_data.host_keys[i]); + if ((r = sshkey_from_private( + sensitive_data.host_keys[i], &tmp)) != 0) + fatal("could not demote host %s key: %s", + sshkey_type(sensitive_data.host_keys[i]), + ssh_err(r)); + sshkey_free(sensitive_data.host_keys[i]); sensitive_data.host_keys[i] = tmp; + if (fp != NULL) { +#ifdef SSH_AUDIT_EVENTS @@ -2126,7 +2126,7 @@ diff -up openssh-7.6p1/sshd.c.audit openssh-7.6p1/sshd.c diff -up openssh-7.6p1/sshkey.c.audit openssh-7.6p1/sshkey.c --- openssh-7.6p1/sshkey.c.audit 2017-10-04 17:18:32.758504660 +0200 +++ openssh-7.6p1/sshkey.c 2017-10-04 17:18:32.839505074 +0200 -@@ -295,6 +295,32 @@ sshkey_type_is_valid_ca(int type) +@@ -295,6 +295,38 @@ sshkey_type_is_valid_ca(int type) } int @@ -2135,11 +2135,17 @@ diff -up openssh-7.6p1/sshkey.c.audit openssh-7.6p1/sshkey.c + switch (k->type) { +#ifdef WITH_OPENSSL + case KEY_RSA_CERT: -+ case KEY_RSA: -+ return k->rsa->d != NULL; ++ case KEY_RSA: { ++ const BIGNUM *d; ++ RSA_get0_key(k->rsa, NULL, NULL, &d); ++ return d != NULL; ++ } + case KEY_DSA_CERT: -+ case KEY_DSA: -+ return k->dsa->priv_key != NULL; ++ case KEY_DSA: { ++ const BIGNUM *priv_key; ++ DSA_get0_key(k->dsa, NULL, &priv_key); ++ return priv_key != NULL; ++ } +#ifdef OPENSSL_HAS_ECC + case KEY_ECDSA_CERT: + case KEY_ECDSA: diff --git a/openssh-7.6p1-pkcs11-ecdsa.patch b/openssh-7.6p1-pkcs11-ecdsa.patch index 2e73d45..7f5f130 100644 --- a/openssh-7.6p1-pkcs11-ecdsa.patch +++ b/openssh-7.6p1-pkcs11-ecdsa.patch @@ -1,6 +1,6 @@ -diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11-client.c ---- openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa 2018-02-16 13:25:59.426469253 +0100 -+++ openssh-7.6p1/ssh-pkcs11-client.c 2018-02-16 13:25:59.428469265 +0100 +diff -up openssh/ssh-pkcs11-client.c.pkcs11-ecdsa openssh/ssh-pkcs11-client.c +--- openssh/ssh-pkcs11-client.c.pkcs11-ecdsa 2018-10-12 14:05:55.020656974 +0200 ++++ openssh/ssh-pkcs11-client.c 2018-10-12 14:05:55.023656999 +0200 @@ -31,6 +31,15 @@ #include @@ -15,9 +15,9 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 +#endif +#endif - #include "pathnames.h" - #include "xmalloc.h" -@@ -139,9 +147,9 @@ pkcs11_rsa_private_encrypt(int flen, con + #include "openbsd-compat/openssl-compat.h" + +@@ -155,9 +164,9 @@ pkcs11_rsa_private_encrypt(int flen, con return (ret); } @@ -27,9 +27,9 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 -wrap_key(RSA *rsa) +wrap_rsa_key(RSA *rsa) { - static RSA_METHOD helper_rsa; + static RSA_METHOD *helper_rsa; -@@ -152,6 +160,88 @@ wrap_key(RSA *rsa) +@@ -170,6 +179,88 @@ wrap_key(RSA *rsa) return (0); } @@ -118,7 +118,7 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 static int pkcs11_start_helper(void) { -@@ -212,7 +281,15 @@ pkcs11_add_provider(char *name, char *pi +@@ -238,7 +329,15 @@ pkcs11_add_provider(char *name, char *pi __func__, ssh_err(r)); if ((r = sshkey_from_blob(blob, blen, &k)) != 0) fatal("%s: bad key: %s", __func__, ssh_err(r)); @@ -135,11 +135,11 @@ diff -up openssh-7.6p1/ssh-pkcs11-client.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 (*keysp)[i] = k; free(blob); } -diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c ---- openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa 2018-02-16 13:25:59.427469259 +0100 -+++ openssh-7.6p1/ssh-pkcs11.c 2018-02-16 13:44:51.270554797 +0100 -@@ -32,6 +32,16 @@ - #include "openbsd-compat/sys-queue.h" +diff -up openssh/ssh-pkcs11.c.pkcs11-ecdsa openssh/ssh-pkcs11.c +--- openssh/ssh-pkcs11.c.pkcs11-ecdsa 2018-10-12 14:05:55.021656982 +0200 ++++ openssh/ssh-pkcs11.c 2018-10-12 14:11:54.292636679 +0200 +@@ -33,6 +33,16 @@ + #include "openbsd-compat/openssl-compat.h" #include +#include @@ -155,15 +155,15 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c #define CRYPTOKI_COMPAT #include "pkcs11.h" -@@ -67,6 +76,7 @@ TAILQ_HEAD(, pkcs11_provider) pkcs11_pro +@@ -74,6 +84,7 @@ TAILQ_HEAD(, pkcs11_provider) pkcs11_pro struct pkcs11_key { struct pkcs11_provider *provider; CK_ULONG slotidx; + CK_ULONG key_type; int (*orig_finish)(RSA *rsa); - RSA_METHOD rsa_method; + RSA_METHOD *rsa_method; char *keyid; -@@ -75,6 +85,9 @@ struct pkcs11_key { +@@ -82,6 +93,9 @@ struct pkcs11_key { }; int pkcs11_interactive = 0; @@ -173,7 +173,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c /* * This can't be in the ssh-pkcs11-uri, becase we can not depend on -@@ -289,6 +302,40 @@ pkcs11_find(struct pkcs11_provider *p, C +@@ -345,6 +359,40 @@ pkcs11_find(struct pkcs11_provider *p, C return (ret); } @@ -214,7 +214,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c /* openssl callback doing the actual signing operation */ static int pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, -@@ -310,7 +357,6 @@ pkcs11_rsa_private_encrypt(int flen, con +@@ -366,7 +414,6 @@ pkcs11_rsa_private_encrypt(int flen, con {CKA_ID, NULL, 0}, {CKA_SIGN, NULL, sizeof(true_val) } }; @@ -222,7 +222,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c int rval = -1; key_filter[0].pValue = &private_key_class; -@@ -326,33 +372,8 @@ pkcs11_rsa_private_encrypt(int flen, con +@@ -383,33 +430,8 @@ pkcs11_rsa_private_encrypt(int flen, con } f = k11->provider->module->function_list; si = &k11->provider->module->slotinfo[k11->slotidx]; @@ -258,7 +258,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c } key_filter[1].pValue = k11->keyid; key_filter[1].ulValueLen = k11->keyid_len; -@@ -390,6 +411,7 @@ pkcs11_rsa_wrap(struct pkcs11_provider * +@@ -447,6 +469,7 @@ pkcs11_rsa_wrap(struct pkcs11_provider * const RSA_METHOD *def = RSA_get_default_method(); k11 = xcalloc(1, sizeof(*k11)); @@ -266,7 +266,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c k11->provider = provider; provider->refcount++; /* provider referenced by RSA key */ k11->slotidx = slotidx; -@@ -415,6 +437,184 @@ pkcs11_rsa_wrap(struct pkcs11_provider * +@@ -477,6 +500,184 @@ pkcs11_rsa_wrap(struct pkcs11_provider * return (0); } @@ -451,7 +451,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c /* remove trailing spaces */ static void rmspace(u_char *buf, size_t len) -@@ -482,11 +646,13 @@ static int +@@ -544,11 +745,13 @@ static int pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, struct sshkey ***keysp, int *nkeys, struct pkcs11_uri *uri) { @@ -466,7 +466,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c { CKA_ID, NULL, 0 }, { CKA_LABEL, NULL, 0 } }; -@@ -507,29 +673,60 @@ pkcs11_fetch_keys(struct pkcs11_provider +@@ -569,29 +772,60 @@ pkcs11_fetch_keys(struct pkcs11_provider { CKA_SUBJECT, NULL, 0 }, { CKA_VALUE, NULL, 0 } }; @@ -533,9 +533,12 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c cert_attribs, keysp, nkeys) < 0) return (-1); return (0); -@@ -553,6 +746,11 @@ pkcs11_fetch_keys_filter(struct pkcs11_p +@@ -624,8 +858,13 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + CK_ATTRIBUTE filter[], size_t filter_size, CK_ATTRIBUTE attribs[4], + struct sshkey ***keysp, int *nkeys) { - struct sshkey *key; +- struct sshkey *key; ++ struct sshkey *key = NULL; RSA *rsa; +#ifdef ENABLE_PKCS11_ECDSA + EC_KEY *ecdsa; @@ -545,7 +548,7 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c X509 *x509; EVP_PKEY *evp = NULL; int i; -@@ -608,6 +806,9 @@ pkcs11_fetch_keys_filter(struct pkcs11_p +@@ -678,6 +917,9 @@ pkcs11_fetch_keys_filter(struct pkcs11_p * or ID, label, subject and value for certificates. */ rsa = NULL; @@ -555,9 +558,9 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs)) != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); -@@ -620,6 +821,45 @@ pkcs11_fetch_keys_filter(struct pkcs11_p - rsa->e = BN_bin2bn(attribs[3].pValue, - attribs[3].ulValueLen, NULL); +@@ -700,6 +942,45 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + BN_free(rsa_n); + BN_free(rsa_e); } +#ifdef ENABLE_PKCS11_ECDSA + } else if (attribs[2].type == CKA_EC_PARAMS ) { @@ -601,43 +604,61 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c } else { cp = attribs[3].pValue; if ((x509 = X509_new()) == NULL) { -@@ -639,13 +879,28 @@ pkcs11_fetch_keys_filter(struct pkcs11_p +@@ -707,13 +988,28 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + } else if (d2i_X509(&x509, &cp, attribs[3].ulValueLen) + == NULL) { + error("d2i_X509 failed"); +- } else if ((evp = X509_get_pubkey(x509)) == NULL || +- EVP_PKEY_base_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_get0_RSA(evp))) == NULL) { +- error("RSAPublicKey_dup"); ++ } else if ((evp = X509_get_pubkey(x509)) == NULL) { ++ debug("X509_get_pubkey failed"); ++ } else { ++ switch (EVP_PKEY_base_id(evp)) { ++ case EVP_PKEY_RSA: ++ if (EVP_PKEY_get0_RSA(evp) == NULL) ++ debug("Missing RSA key"); ++ else if ((rsa = RSAPublicKey_dup( ++ EVP_PKEY_get0_RSA(evp))) == NULL) ++ error("RSAPublicKey_dup failed"); ++ break; ++ case EVP_PKEY_EC: ++ if (EVP_PKEY_get0_EC_KEY(evp) == NULL) ++ debug("Missing ECDSA key"); ++ else if ((ecdsa = EC_KEY_dup( ++ EVP_PKEY_get0_EC_KEY(evp))) == NULL) ++ error("EC_KEY_dup failed"); ++ break; ++ default: ++ debug("not a RSA or ECDSA key"); ++ break; ++ } + } X509_free(x509); EVP_PKEY_free(evp); - } -- if (rsa && rsa->n && rsa->e && -- pkcs11_rsa_wrap(p, slotidx, &attribs[0], &attribs[1], rsa) == 0) { -- if ((key = sshkey_new(KEY_UNSPEC)) == NULL) -- fatal("sshkey_new failed"); -- key->rsa = rsa; -- key->type = KEY_RSA; -- key->flags |= SSHKEY_FLAG_EXT; -+ key = NULL; -+ if (rsa || ecdsa) { -+ if (rsa && rsa->n && rsa->e && -+ pkcs11_rsa_wrap(p, slotidx, &attribs[0], &attribs[1], rsa) == 0) { -+ if ((key = sshkey_new(KEY_UNSPEC)) == NULL) -+ fatal("sshkey_new failed"); -+ key->rsa = rsa; -+ key->type = KEY_RSA; -+ key->flags |= SSHKEY_FLAG_EXT; +@@ -725,6 +1021,17 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + key->rsa = rsa; + key->type = KEY_RSA; + key->flags |= SSHKEY_FLAG_EXT; +#ifdef ENABLE_PKCS11_ECDSA -+ } else if(ecdsa && pkcs11_ecdsa_wrap(p, slotidx, &attribs[0], &attribs[1], ecdsa) == 0) { -+ if ((key = sshkey_new(KEY_UNSPEC)) == NULL) -+ fatal("sshkey_new failed"); -+ key->ecdsa = ecdsa; -+ key->ecdsa_nid = sshkey_ecdsa_key_to_nid(ecdsa); -+ key->type = KEY_ECDSA; -+ key->flags |= SSHKEY_FLAG_EXT; ++ } else if (ecdsa && ++ pkcs11_ecdsa_wrap(p, slotidx, &attribs[0], &attribs[1], ecdsa) == 0) { ++ if ((key = sshkey_new(KEY_UNSPEC)) == NULL) ++ fatal("sshkey_new failed"); ++ key->ecdsa = ecdsa; ++ key->type = KEY_ECDSA; ++ key->flags |= SSHKEY_FLAG_EXT; +#endif /* ENABLE_PKCS11_ECDSA */ -+ } + } -+ -+ if(key) { ++ if (key) { if (pkcs11_key_included(keysp, nkeys, key)) { sshkey_free(key); } else { -@@ -658,6 +913,10 @@ pkcs11_fetch_keys_filter(struct pkcs11_p +@@ -737,6 +1044,10 @@ pkcs11_fetch_keys_filter(struct pkcs11_p } } else if (rsa) { RSA_free(rsa); @@ -648,9 +669,9 @@ diff -up openssh-7.6p1/ssh-pkcs11.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.c } for (i = 0; i < nattribs; i++) free(attribs[i].pValue); -diff -up openssh-7.6p1/ssh-pkcs11-helper.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11-helper.c ---- openssh-7.6p1/ssh-pkcs11-helper.c.pkcs11-ecdsa 2017-10-02 21:34:26.000000000 +0200 -+++ openssh-7.6p1/ssh-pkcs11-helper.c 2018-02-16 13:25:59.428469265 +0100 +diff -up openssh/ssh-pkcs11-helper.c.pkcs11-ecdsa openssh/ssh-pkcs11-helper.c +--- openssh/ssh-pkcs11-helper.c.pkcs11-ecdsa 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh-pkcs11-helper.c 2018-10-12 14:05:55.023656999 +0200 @@ -24,6 +24,17 @@ #include "openbsd-compat/sys-queue.h" @@ -669,7 +690,7 @@ diff -up openssh-7.6p1/ssh-pkcs11-helper.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 #include #include #include -@@ -80,7 +90,7 @@ del_keys_by_name(char *name) +@@ -77,7 +88,7 @@ del_keys_by_name(char *name) if (!strcmp(ki->providername, name)) { TAILQ_REMOVE(&pkcs11_keylist, ki, next); free(ki->providername); @@ -678,7 +699,7 @@ diff -up openssh-7.6p1/ssh-pkcs11-helper.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 free(ki); } } -@@ -164,6 +174,20 @@ process_del(void) +@@ -172,6 +183,20 @@ process_del(void) sshbuf_free(msg); } @@ -699,7 +720,7 @@ diff -up openssh-7.6p1/ssh-pkcs11-helper.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 static void process_sign(void) { -@@ -180,14 +204,38 @@ process_sign(void) +@@ -192,14 +217,38 @@ process_sign(void) else { if ((found = lookup_key(key)) != NULL) { #ifdef WITH_OPENSSL @@ -746,9 +767,9 @@ diff -up openssh-7.6p1/ssh-pkcs11-helper.c.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11 } #endif /* WITH_OPENSSL */ } -diff -up openssh-7.6p1/ssh-pkcs11.h.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.h ---- openssh-7.6p1/ssh-pkcs11.h.pkcs11-ecdsa 2018-02-16 13:25:59.429469272 +0100 -+++ openssh-7.6p1/ssh-pkcs11.h 2018-02-16 13:45:29.623800048 +0100 +diff -up openssh/ssh-pkcs11.h.pkcs11-ecdsa openssh/ssh-pkcs11.h +--- openssh/ssh-pkcs11.h.pkcs11-ecdsa 2018-10-12 14:05:55.021656982 +0200 ++++ openssh/ssh-pkcs11.h 2018-10-12 14:05:55.023656999 +0200 @@ -20,6 +20,7 @@ int pkcs11_init(int); void pkcs11_terminate(void); @@ -757,45 +778,3 @@ diff -up openssh-7.6p1/ssh-pkcs11.h.pkcs11-ecdsa openssh-7.6p1/ssh-pkcs11.h int pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***); int pkcs11_del_provider(char *); int pkcs11_uri_write(const struct sshkey *, FILE *); - - - -diff -up openssh-7.6p1/ssh-pkcs11.c.old openssh-7.6p1/ssh-pkcs11.c ---- openssh-7.6p1/ssh-pkcs11.c.old 2018-02-16 16:43:08.861520255 +0100 -+++ openssh-7.6p1/ssh-pkcs11.c 2018-02-16 16:56:35.312601451 +0100 -@@ -917,13 +917,28 @@ pkcs11_fetch_keys_filter(struct pkcs11_p - } else if (d2i_X509(&x509, &cp, attribs[3].ulValueLen) - == NULL) { - error("d2i_X509 failed"); -- } else if ((evp = X509_get_pubkey(x509)) == NULL || -- evp->type != EVP_PKEY_RSA || -- evp->pkey.rsa == NULL) { -- debug("X509_get_pubkey failed or no rsa"); -- } else if ((rsa = RSAPublicKey_dup(evp->pkey.rsa)) -- == NULL) { -- error("RSAPublicKey_dup"); -+ } else if ((evp = X509_get_pubkey(x509)) == NULL) { -+ debug("X509_get_pubkey failed"); -+ } else { -+ switch (evp->type) { -+ case EVP_PKEY_RSA: -+ if (evp->pkey.rsa == NULL) -+ debug("Missing RSA key"); -+ else if ((rsa = RSAPublicKey_dup( -+ evp->pkey.rsa)) == NULL) -+ error("RSAPublicKey_dup failed"); -+ break; -+ case EVP_PKEY_EC: -+ if (evp->pkey.ecdsa == NULL) -+ debug("Missing ECDSA key"); -+ else if ((ecdsa = EC_KEY_dup( -+ evp->pkey.ecdsa)) == NULL) -+ error("EC_KEY_dup failed"); -+ break; -+ default: -+ debug("not a RSA or ECDSA key"); -+ break; -+ } - } - X509_free(x509); - EVP_PKEY_free(evp); diff --git a/openssh-7.6p1-pkcs11-uri.patch b/openssh-7.6p1-pkcs11-uri.patch index 6fd463e..3343730 100644 --- a/openssh-7.6p1-pkcs11-uri.patch +++ b/openssh-7.6p1-pkcs11-uri.patch @@ -1,92 +1,7 @@ -diff --git a/Makefile.in b/Makefile.in -index ac959c1f..f8ed1781 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -93,7 +93,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ - kexgssc.o \ - msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ -- ssh-pkcs11.o smult_curve25519_ref.o \ -+ ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \ - poly1305.o chacha.o cipher-chachapoly.o \ - ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \ - sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \ -@@ -248,6 +248,8 @@ clean: regressclean - rm -f regress/unittests/match/test_match$(EXEEXT) - rm -f regress/unittests/utf8/*.o - rm -f regress/unittests/utf8/test_utf8$(EXEEXT) -+ rm -f regress/unittests/pkcs11/*.o -+ rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT) - rm -f regress/misc/kexfuzz/*.o - rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT) - (cd openbsd-compat && $(MAKE) clean) -@@ -276,6 +278,8 @@ distclean: regressclean - rm -f regress/unittests/match/test_match - rm -f regress/unittests/utf8/*.o - rm -f regress/unittests/utf8/test_utf8 -+ rm -f regress/unittests/pkcs11/*.o -+ rm -f regress/unittests/pkcs11/test_pkcs11 - rm -f regress/misc/kexfuzz/*.o - rm -f regress/misc/kexfuzz - (cd openbsd-compat && $(MAKE) distclean) -@@ -437,6 +441,7 @@ regress-prep: - $(MKDIR_P) `pwd`/regress/unittests/kex - $(MKDIR_P) `pwd`/regress/unittests/match - $(MKDIR_P) `pwd`/regress/unittests/utf8 -+ $(MKDIR_P) `pwd`/regress/unittests/pkcs11 - $(MKDIR_P) `pwd`/regress/misc/kexfuzz - [ -f `pwd`/regress/Makefile ] || \ - ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile -@@ -455,6 +460,11 @@ regress/netcat$(EXEEXT): $(srcdir)/regress/netcat.c $(REGRESSLIBS) - $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \ - $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) - -+regress/soft-pkcs11.so: $(srcdir)/regress/soft-pkcs11.c $(REGRESSLIBS) -+ $(CC) $(CFLAGS) $(CPPFLAGS) -fpic -c $(srcdir)/regress/soft-pkcs11.c \ -+ -o $(srcdir)/regress/soft-pkcs11.o -+ $(CC) -shared -o $@ $(srcdir)/regress/soft-pkcs11.o -+ - regress/check-perm$(EXEEXT): $(srcdir)/regress/check-perm.c $(REGRESSLIBS) - $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/check-perm.c \ - $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) -@@ -556,6 +566,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT): \ - regress/unittests/test_helper/libtest_helper.a \ - -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) - -+UNITTESTS_TEST_PKCS11_OBJS=\ -+ regress/unittests/pkcs11/tests.o -+ -+regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \ -+ ${UNITTESTS_TEST_PKCS11_OBJS} \ -+ regress/unittests/test_helper/libtest_helper.a libssh.a -+ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \ -+ regress/unittests/test_helper/libtest_helper.a \ -+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) -+ - MISC_KEX_FUZZ_OBJS=\ - regress/misc/kexfuzz/kexfuzz.o - -@@ -566,6 +586,7 @@ regress/misc/kexfuzz/kexfuzz$(EXEEXT): ${MISC_KEX_FUZZ_OBJS} libssh.a - regress-binaries: regress/modpipe$(EXEEXT) \ - regress/setuid-allowed$(EXEEXT) \ - regress/netcat$(EXEEXT) \ -+ regress/soft-pkcs11.so \ - regress/check-perm$(EXEEXT) \ - regress/mkdtemp$(EXEEXT) \ - regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ -@@ -575,6 +596,7 @@ regress-binaries: regress/modpipe$(EXEEXT) \ - regress/unittests/kex/test_kex$(EXEEXT) \ - regress/unittests/match/test_match$(EXEEXT) \ - regress/unittests/utf8/test_utf8$(EXEEXT) \ -+ regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ - regress/misc/kexfuzz/kexfuzz$(EXEEXT) - - tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS) -diff --git a/authfd.c b/authfd.c -index 1eff7ba9..35153f47 100644 ---- a/authfd.c -+++ b/authfd.c -@@ -312,6 +312,8 @@ ssh_free_identitylist(struct ssh_identitylist *idl) +diff -up openssh/authfd.c.pkcs11-uri openssh/authfd.c +--- openssh/authfd.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/authfd.c 2018-10-12 13:52:55.450191401 +0200 +@@ -312,6 +312,8 @@ ssh_free_identitylist(struct ssh_identit if (idl->comments != NULL) free(idl->comments[i]); } @@ -95,11 +10,10 @@ index 1eff7ba9..35153f47 100644 free(idl); } -diff --git a/configure.ac b/configure.ac -index d7bcaf01..171a8597 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1895,12 +1895,14 @@ AC_LINK_IFELSE( +diff -up openssh/configure.ac.pkcs11-uri openssh/configure.ac +--- openssh/configure.ac.pkcs11-uri 2018-10-12 13:52:55.430191235 +0200 ++++ openssh/configure.ac 2018-10-12 13:52:55.451191409 +0200 +@@ -1987,12 +1987,14 @@ AC_LINK_IFELSE( [AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).]) ]) @@ -114,7 +28,7 @@ index d7bcaf01..171a8597 100644 fi ] ) -@@ -1916,6 +1918,40 @@ if test "x$openssl" = "xyes" && test "x$disable_pkcs11" = "x"; then +@@ -2008,6 +2010,40 @@ if test "x$openssl" = "xyes" && test "x$ ) fi @@ -155,7 +69,7 @@ index d7bcaf01..171a8597 100644 # IRIX has a const char return value for gai_strerror() AC_CHECK_FUNCS([gai_strerror], [ AC_DEFINE([HAVE_GAI_STRERROR]) -@@ -5226,6 +5262,7 @@ echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" +@@ -5458,6 +5494,7 @@ echo " BSD Auth support echo " Random number source: $RAND_MSG" echo " Privsep sandbox style: $SANDBOX_STYLE" echo " Vendor patch level: $SSH_VENDOR_PATCHLEVEL" @@ -163,36 +77,92 @@ index d7bcaf01..171a8597 100644 echo "" -diff --git a/regress/Makefile b/regress/Makefile -index d15898ad..9c15afa4 100644 ---- a/regress/Makefile -+++ b/regress/Makefile -@@ -108,9 +110,11 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \ - known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \ - modpipe netcat no_identity_config \ - pidfile putty.rsa2 ready regress.log \ -- remote_pid revoked-* rsa rsa-agent rsa-agent.pub rsa.pub \ -+ remote_pid revoked-* rsa rsa-agent rsa-agent.pub \ -+ rsa-agent-cert.pub rsa.pub \ - rsa1 rsa1-agent rsa1-agent.pub rsa1.pub rsa_ssh2_cr.prv \ -- rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \ -+ soft-pkcs11.so soft-pkcs11.o pkcs11*.crt pkcs11*.key \ -+ pkcs11.info rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \ - scp-ssh-wrapper.scp setuid-allowed sftp-server.log \ - sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \ - ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \ -@@ -225,6 +229,7 @@ unit: - V="" ; \ - test "x${USE_VALGRIND}" = "x" || \ - V=${.CURDIR}/valgrind-unit.sh ; \ -+ $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \ - $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ - $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ - -d ${.CURDIR}/unittests/sshkey/testdata ; \ -diff --git a/regress/agent-pkcs11.sh b/regress/agent-pkcs11.sh -index db3018b8..4991d0bc 100644 ---- a/regress/agent-pkcs11.sh -+++ b/regress/agent-pkcs11.sh +diff -up openssh/Makefile.in.pkcs11-uri openssh/Makefile.in +--- openssh/Makefile.in.pkcs11-uri 2018-10-12 13:52:55.366190704 +0200 ++++ openssh/Makefile.in 2018-10-12 13:52:55.450191401 +0200 +@@ -102,7 +102,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \ + kexgssc.o \ + msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ +- ssh-pkcs11.o smult_curve25519_ref.o \ ++ ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \ + poly1305.o chacha.o cipher-chachapoly.o \ + ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \ + sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \ +@@ -270,6 +270,8 @@ clean: regressclean + rm -f regress/unittests/match/test_match$(EXEEXT) + rm -f regress/unittests/utf8/*.o + rm -f regress/unittests/utf8/test_utf8$(EXEEXT) ++ rm -f regress/unittests/pkcs11/*.o ++ rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT) + rm -f regress/misc/kexfuzz/*.o + rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT) + (cd openbsd-compat && $(MAKE) clean) +@@ -300,6 +302,8 @@ distclean: regressclean + rm -f regress/unittests/match/test_match + rm -f regress/unittests/utf8/*.o + rm -f regress/unittests/utf8/test_utf8 ++ rm -f regress/unittests/pkcs11/*.o ++ rm -f regress/unittests/pkcs11/test_pkcs11 + rm -f regress/misc/kexfuzz/*.o + rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT) + (cd openbsd-compat && $(MAKE) distclean) +@@ -484,6 +488,7 @@ regress-prep: + $(MKDIR_P) `pwd`/regress/unittests/kex + $(MKDIR_P) `pwd`/regress/unittests/match + $(MKDIR_P) `pwd`/regress/unittests/utf8 ++ $(MKDIR_P) `pwd`/regress/unittests/pkcs11 + $(MKDIR_P) `pwd`/regress/misc/kexfuzz + [ -f `pwd`/regress/Makefile ] || \ + ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile +@@ -502,6 +507,11 @@ regress/netcat$(EXEEXT): $(srcdir)/regre + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \ + $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + ++regress/soft-pkcs11.so: $(srcdir)/regress/soft-pkcs11.c $(REGRESSLIBS) ++ $(CC) $(CFLAGS) $(CPPFLAGS) -fpic -c $(srcdir)/regress/soft-pkcs11.c \ ++ -o $(srcdir)/regress/soft-pkcs11.o ++ $(CC) -shared -o $@ $(srcdir)/regress/soft-pkcs11.o ++ + regress/check-perm$(EXEEXT): $(srcdir)/regress/check-perm.c $(REGRESSLIBS) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/check-perm.c \ + $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) +@@ -607,6 +617,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT + regress/unittests/test_helper/libtest_helper.a \ + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + ++UNITTESTS_TEST_PKCS11_OBJS=\ ++ regress/unittests/pkcs11/tests.o ++ ++regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \ ++ ${UNITTESTS_TEST_PKCS11_OBJS} \ ++ regress/unittests/test_helper/libtest_helper.a libssh.a ++ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \ ++ regress/unittests/test_helper/libtest_helper.a \ ++ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) ++ + MISC_KEX_FUZZ_OBJS=\ + regress/misc/kexfuzz/kexfuzz.o + +@@ -617,6 +637,7 @@ regress/misc/kexfuzz/kexfuzz$(EXEEXT): $ + regress-binaries: regress/modpipe$(EXEEXT) \ + regress/setuid-allowed$(EXEEXT) \ + regress/netcat$(EXEEXT) \ ++ regress/soft-pkcs11.so \ + regress/check-perm$(EXEEXT) \ + regress/mkdtemp$(EXEEXT) \ + regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ +@@ -627,6 +648,7 @@ regress-binaries: regress/modpipe$(EXEEX + regress/unittests/kex/test_kex$(EXEEXT) \ + regress/unittests/match/test_match$(EXEEXT) \ + regress/unittests/utf8/test_utf8$(EXEEXT) \ ++ regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ + regress/misc/kexfuzz/kexfuzz$(EXEEXT) + + tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS) +diff -up openssh/regress/agent-pkcs11.sh.pkcs11-uri openssh/regress/agent-pkcs11.sh +--- openssh/regress/agent-pkcs11.sh.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/regress/agent-pkcs11.sh 2018-10-12 13:52:55.451191409 +0200 @@ -4,10 +4,17 @@ tid="pkcs11 agent test" @@ -230,12 +200,10 @@ index db3018b8..4991d0bc 100644 r=$? if [ $r -ne 0 ]; then fail "ssh-add -e failed: exit code $r" -diff --git a/regress/locl.h b/regress/locl.h -new file mode 100644 -index 00000000..afefe27d ---- /dev/null -+++ b/regress/locl.h -@@ -0,0 +1,79 @@ +diff -up openssh/regress/locl.h.pkcs11-uri openssh/regress/locl.h +--- openssh/regress/locl.h.pkcs11-uri 2018-10-12 13:52:55.451191409 +0200 ++++ openssh/regress/locl.h 2018-10-12 13:52:55.451191409 +0200 +@@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004, Stockholms universitet + * (Stockholm University, Stockholm Sweden) @@ -280,7 +248,6 @@ index 00000000..afefe27d +#include +#include +#include -+#include "../libcrypto-compat.h" + +#include +#include @@ -315,11 +282,34 @@ index 00000000..afefe27d + } \ + } \ +} -diff --git a/regress/pkcs11.sh b/regress/pkcs11.sh -new file mode 100644 -index 00000000..cf98e379 ---- /dev/null -+++ b/regress/pkcs11.sh +diff -up openssh/regress/Makefile.pkcs11-uri openssh/regress/Makefile +--- openssh/regress/Makefile.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/regress/Makefile 2018-10-12 13:52:55.451191409 +0200 +@@ -109,9 +109,11 @@ CLEANFILES= *.core actual agent-key.* au + known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \ + modpipe netcat no_identity_config \ + pidfile putty.rsa2 ready regress.log \ +- remote_pid revoked-* rsa rsa-agent rsa-agent.pub rsa.pub \ ++ remote_pid revoked-* rsa rsa-agent rsa-agent.pub \ ++ rsa-agent-cert.pub rsa.pub \ + rsa1 rsa1-agent rsa1-agent.pub rsa1.pub rsa_ssh2_cr.prv \ +- rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \ ++ soft-pkcs11.so soft-pkcs11.o pkcs11*.crt pkcs11*.key \ ++ pkcs11.info rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \ + scp-ssh-wrapper.scp setuid-allowed sftp-server.log \ + sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \ + ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \ +@@ -226,6 +228,7 @@ unit: + V="" ; \ + test "x${USE_VALGRIND}" = "x" || \ + V=${.CURDIR}/valgrind-unit.sh ; \ ++ $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \ + $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ + $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ + -d ${.CURDIR}/unittests/sshkey/testdata ; \ +diff -up openssh/regress/pkcs11.sh.pkcs11-uri openssh/regress/pkcs11.sh +--- openssh/regress/pkcs11.sh.pkcs11-uri 2018-10-12 13:52:55.451191409 +0200 ++++ openssh/regress/pkcs11.sh 2018-10-12 13:52:55.451191409 +0200 @@ -0,0 +1,300 @@ +# +# Copyright (c) 2017 Red Hat @@ -621,11 +611,9 @@ index 00000000..cf98e379 +fi + +rm -rf $OBJ/.tokens $OBJ/token_keys -diff --git a/regress/soft-pkcs11.c b/regress/soft-pkcs11.c -new file mode 100644 -index 00000000..8b4981bd ---- /dev/null -+++ b/regress/soft-pkcs11.c +diff -up openssh/regress/soft-pkcs11.c.pkcs11-uri openssh/regress/soft-pkcs11.c +--- openssh/regress/soft-pkcs11.c.pkcs11-uri 2018-10-12 13:52:55.452191417 +0200 ++++ openssh/regress/soft-pkcs11.c 2018-10-12 13:52:55.452191417 +0200 @@ -0,0 +1,2058 @@ +/* + * Copyright (c) 2004-2006, Stockholms universitet @@ -2685,10 +2673,9 @@ index 00000000..8b4981bd + (void *)func_not_supported, /* C_CancelFunction */ + (void *)func_not_supported /* C_WaitForSlotEvent */ +}; -diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile -index e464b085..a0e5a37c 100644 ---- a/regress/unittests/Makefile -+++ b/regress/unittests/Makefile +diff -up openssh/regress/unittests/Makefile.pkcs11-uri openssh/regress/unittests/Makefile +--- openssh/regress/unittests/Makefile.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/regress/unittests/Makefile 2018-10-12 13:52:55.453191425 +0200 @@ -2,6 +2,6 @@ REGRESS_FAIL_EARLY?= yes @@ -2697,11 +2684,9 @@ index e464b085..a0e5a37c 100644 +SUBDIR+=pkcs11 authopt .include -diff --git a/regress/unittests/pkcs11/Makefile b/regress/unittests/pkcs11/Makefile -new file mode 100644 -index 00000000..481b13d0 ---- /dev/null -+++ b/regress/unittests/pkcs11/Makefile +diff -up openssh/regress/unittests/pkcs11/Makefile.pkcs11-uri openssh/regress/unittests/pkcs11/Makefile +--- openssh/regress/unittests/pkcs11/Makefile.pkcs11-uri 2018-10-12 13:52:55.453191425 +0200 ++++ openssh/regress/unittests/pkcs11/Makefile 2018-10-12 13:52:55.453191425 +0200 @@ -0,0 +1,9 @@ + +PROG=test_pkcs11 @@ -2712,11 +2697,9 @@ index 00000000..481b13d0 + env ${TEST_ENV} ./${PROG} + +.include -diff --git a/regress/unittests/pkcs11/tests.c b/regress/unittests/pkcs11/tests.c -new file mode 100644 -index 00000000..e83aca54 ---- /dev/null -+++ b/regress/unittests/pkcs11/tests.c +diff -up openssh/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh/regress/unittests/pkcs11/tests.c +--- openssh/regress/unittests/pkcs11/tests.c.pkcs11-uri 2018-10-12 13:52:55.453191425 +0200 ++++ openssh/regress/unittests/pkcs11/tests.c 2018-10-12 13:52:55.453191425 +0200 @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2017 Red Hat @@ -2884,8 +2867,8 @@ index 00000000..e83aca54 + compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL)); + /* MUST NOT contain duplicate attributes of the same name */ + check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1); -+ /* Unrecognized attribute in path SHOULD be error */ -+ check_parse_rv("pkcs11:key_name=SSH", EMPTY_URI, -1); ++ /* Unrecognized attribute in path are ignored with log message */ ++ check_parse("pkcs11:key_name=SSH", EMPTY_URI); + /* Unrecognized attribute in query SHOULD be ignored */ + check_parse("pkcs11:?key_name=SSH", EMPTY_URI); +} @@ -3048,10 +3031,9 @@ index 00000000..e83aca54 + test_parse_invalid(); + test_generate_valid(); +} -diff --git a/ssh-add.c b/ssh-add.c -index adcc4599..e4fd5623 100644 ---- a/ssh-add.c -+++ b/ssh-add.c +diff -up openssh/ssh-add.c.pkcs11-uri openssh/ssh-add.c +--- openssh/ssh-add.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh-add.c 2018-10-12 13:52:55.454191434 +0200 @@ -64,6 +64,7 @@ #include "misc.h" #include "ssherr.h" @@ -3060,15 +3042,15 @@ index adcc4599..e4fd5623 100644 /* argv0 */ extern char *__progname; -@@ -188,6 +189,24 @@ delete_all(int agent_fd) +@@ -188,6 +189,24 @@ delete_all(int agent_fd, int qflag) return ret; } +#ifdef ENABLE_PKCS11 -+static int update_card(int, int, const char *); ++static int update_card(int, int, const char *, int); + +int -+update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri) ++update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri, int qflag) +{ + struct pkcs11_uri *uri; + @@ -3078,14 +3060,14 @@ index adcc4599..e4fd5623 100644 + fatal("Failed to parse PKCS#11 URI"); + pkcs11_uri_cleanup(uri); + -+ return update_card(agent_fd, adding, pkcs11_uri); ++ return update_card(agent_fd, adding, pkcs11_uri, qflag); +} +#endif + static int add_file(int agent_fd, const char *filename, int key_only, int qflag) { -@@ -480,6 +499,13 @@ lock_agent(int agent_fd, int lock) +@@ -495,6 +514,13 @@ lock_agent(int agent_fd, int lock) static int do_file(int agent_fd, int deleting, int key_only, char *file, int qflag) { @@ -3093,16 +3075,15 @@ index adcc4599..e4fd5623 100644 + if (strlen(file) >= strlen(PKCS11_URI_SCHEME) && + strncmp(file, PKCS11_URI_SCHEME, + strlen(PKCS11_URI_SCHEME)) == 0) { -+ return update_pkcs11_uri(agent_fd, !deleting, file); ++ return update_pkcs11_uri(agent_fd, !deleting, file, qflag); + } +#endif if (deleting) { if (delete_file(agent_fd, file, key_only, qflag) == -1) return -1; -diff --git a/ssh-agent.c b/ssh-agent.c -index 2a4578b0..f6c86240 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c +diff -up openssh/ssh-agent.c.pkcs11-uri openssh/ssh-agent.c +--- openssh/ssh-agent.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh-agent.c 2018-10-12 13:52:55.454191434 +0200 @@ -546,10 +546,72 @@ no_identities(SocketEntry *e) } @@ -3177,7 +3158,7 @@ index 2a4578b0..f6c86240 100644 int r, i, count = 0, success = 0, confirm = 0; u_int seconds; time_t death = 0; -@@ -585,28 +645,23 @@ process_add_smartcard_key(SocketEntry *e) +@@ -585,28 +647,23 @@ process_add_smartcard_key(SocketEntry *e goto send; } } @@ -3214,7 +3195,7 @@ index 2a4578b0..f6c86240 100644 id->death = death; id->confirm = confirm; TAILQ_INSERT_TAIL(&idtab->idlist, id, next); -@@ -620,6 +675,7 @@ process_add_smartcard_key(SocketEntry *e) +@@ -620,6 +677,7 @@ process_add_smartcard_key(SocketEntry *e send: free(pin); free(provider); @@ -3222,7 +3203,7 @@ index 2a4578b0..f6c86240 100644 free(keys); send_status(e, success); } -@@ -627,7 +683,7 @@ send: +@@ -627,7 +685,7 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { @@ -3231,7 +3212,7 @@ index 2a4578b0..f6c86240 100644 int r, success = 0; Identity *id, *nxt; -@@ -638,30 +694,29 @@ process_remove_smartcard_key(SocketEntry *e) +@@ -638,30 +696,29 @@ process_remove_smartcard_key(SocketEntry } free(pin); @@ -3268,11 +3249,173 @@ index 2a4578b0..f6c86240 100644 send_status(e, success); } #endif /* ENABLE_PKCS11 */ -diff --git a/ssh-keygen.c b/ssh-keygen.c -index d1ffc30c..00e38049 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -820,6 +820,7 @@ do_download(struct passwd *pw) +diff -up openssh/ssh_config.5.pkcs11-uri openssh/ssh_config.5 +--- openssh/ssh_config.5.pkcs11-uri 2018-10-12 13:52:55.437191293 +0200 ++++ openssh/ssh_config.5 2018-10-12 13:52:55.459191475 +0200 +@@ -991,6 +991,19 @@ may also be used in conjunction with + .Cm CertificateFile + in order to provide any certificate also needed for authentication with + the identity. ++.Pp ++The authentication identity can be also specified in a form of PKCS#11 URI ++starting with a string ++.Cm pkcs11: . ++There is supported a subset of the PKCS#11 URI as defined ++in RFC 7512 (implemented path arguments ++.Cm id , ++.Cm manufacturer , ++.Cm object , ++.Cm token ++and query argument ++.Cm module-path ++). The URI can not be in quotes. + .It Cm IgnoreUnknown + Specifies a pattern-list of unknown options to be ignored if they are + encountered in configuration parsing. +diff -up openssh/ssh.c.pkcs11-uri openssh/ssh.c +--- openssh/ssh.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh.c 2018-10-12 13:52:55.458191467 +0200 +@@ -769,6 +769,14 @@ main(int ac, char **av) + options.gss_deleg_creds = 1; + break; + case 'i': ++#ifdef ENABLE_PKCS11 ++ if (strlen(optarg) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(optarg, PKCS11_URI_SCHEME, ++ strlen(PKCS11_URI_SCHEME)) == 0) { ++ add_identity_file(&options, NULL, optarg, 1); ++ break; ++ } ++#endif + p = tilde_expand_filename(optarg, getuid()); + if (stat(p, &st) < 0) + fprintf(stderr, "Warning: Identity file %s " +@@ -1975,6 +1983,45 @@ ssh_session2(struct ssh *ssh, struct pas + options.escape_char : SSH_ESCAPECHAR_NONE, id); + } + ++#ifdef ENABLE_PKCS11 ++static void ++load_pkcs11_identity(char *pkcs11_uri, char *identity_files[], ++ struct sshkey *identity_keys[], int *n_ids) ++{ ++ int nkeys, i; ++ struct sshkey **keys; ++ struct pkcs11_uri *uri; ++ ++ debug("identity file '%s' from pkcs#11", pkcs11_uri); ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PCKS#11 URI"); ++ ++ if (pkcs11_uri_parse(pkcs11_uri, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI %s", pkcs11_uri); ++ ++ /* we need to merge URI and provider together */ ++ if (options.pkcs11_provider != NULL && uri->module_path == NULL) ++ uri->module_path = strdup(options.pkcs11_provider); ++ ++ if (options.num_identity_files < SSH_MAX_IDENTITY_FILES && ++ (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys)) > 0) { ++ for (i = 0; i < nkeys; i++) { ++ if (*n_ids >= SSH_MAX_IDENTITY_FILES) { ++ sshkey_free(keys[i]); ++ continue; ++ } ++ identity_keys[*n_ids] = keys[i]; ++ identity_files[*n_ids] = pkcs11_uri_get(uri); ++ (*n_ids)++; ++ } ++ free(keys); ++ } ++ ++ pkcs11_uri_cleanup(uri); ++} ++#endif /* ENABLE_PKCS11 */ ++ + /* Loads all IdentityFile and CertificateFile keys */ + static void + load_public_identity_files(struct passwd *pw) +@@ -1989,10 +2036,6 @@ load_public_identity_files(struct passwd + char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; + struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; + int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; +-#ifdef ENABLE_PKCS11 +- struct sshkey **keys; +- int nkeys; +-#endif /* PKCS11 */ + + n_ids = n_certs = 0; + memset(identity_files, 0, sizeof(identity_files)); +@@ -2005,32 +2048,46 @@ load_public_identity_files(struct passwd + sizeof(certificate_file_userprovided)); + + #ifdef ENABLE_PKCS11 +- if (options.pkcs11_provider != NULL && +- options.num_identity_files < SSH_MAX_IDENTITY_FILES && +- (pkcs11_init(!options.batch_mode) == 0) && +- (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, +- &keys)) > 0) { +- for (i = 0; i < nkeys; i++) { +- if (n_ids >= SSH_MAX_IDENTITY_FILES) { +- sshkey_free(keys[i]); +- continue; +- } +- identity_keys[n_ids] = keys[i]; +- identity_files[n_ids] = +- xstrdup(options.pkcs11_provider); /* XXX */ +- n_ids++; +- } +- free(keys); ++ /* handle fallback from PKCS11Provider option */ ++ pkcs11_init(!options.batch_mode); ++ ++ if (options.pkcs11_provider != NULL) { ++ struct pkcs11_uri *uri; ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PCKS#11 URI"); ++ ++ /* Construct simple PKCS#11 URI to simplify access */ ++ uri->module_path = strdup(options.pkcs11_provider); ++ ++ /* Add it as any other IdentityFile */ ++ cp = pkcs11_uri_get(uri); ++ add_identity_file(&options, NULL, cp, 1); ++ free(cp); ++ ++ pkcs11_uri_cleanup(uri); + } + #endif /* ENABLE_PKCS11 */ + for (i = 0; i < options.num_identity_files; i++) { ++ char *name = options.identity_files[i]; + if (n_ids >= SSH_MAX_IDENTITY_FILES || +- strcasecmp(options.identity_files[i], "none") == 0) { ++ strcasecmp(name, "none") == 0) { + free(options.identity_files[i]); + options.identity_files[i] = NULL; + continue; + } +- cp = tilde_expand_filename(options.identity_files[i], getuid()); ++#ifdef ENABLE_PKCS11 ++ if (strlen(name) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(name, PKCS11_URI_SCHEME, ++ strlen(PKCS11_URI_SCHEME)) == 0) { ++ load_pkcs11_identity(name, identity_files, ++ identity_keys, &n_ids); ++ free(options.identity_files[i]); ++ continue; ++ } ++#endif /* ENABLE_PKCS11 */ ++ cp = tilde_expand_filename(name, getuid()); + filename = percent_expand(cp, "d", pw->pw_dir, + "u", pw->pw_name, "l", thishost, "h", host, + "r", options.user, (char *)NULL); +diff -up openssh/ssh-keygen.c.pkcs11-uri openssh/ssh-keygen.c +--- openssh/ssh-keygen.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh-keygen.c 2018-10-12 13:52:55.455191442 +0200 +@@ -825,6 +825,7 @@ do_download(struct passwd *pw) free(fp); } else { (void) sshkey_write(keys[i], stdout); /* XXX check */ @@ -3280,11 +3423,10 @@ index d1ffc30c..00e38049 100644 fprintf(stdout, "\n"); } sshkey_free(keys[i]); -diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c -index a023f5f4..882e8381 100644 ---- a/ssh-pkcs11-client.c -+++ b/ssh-pkcs11-client.c -@@ -117,6 +117,7 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, +diff -up openssh/ssh-pkcs11-client.c.pkcs11-uri openssh/ssh-pkcs11-client.c +--- openssh/ssh-pkcs11-client.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh-pkcs11-client.c 2018-10-12 13:52:55.455191442 +0200 +@@ -126,6 +126,7 @@ pkcs11_rsa_private_encrypt(int flen, con return (-1); key.type = KEY_RSA; key.rsa = rsa; @@ -3292,7 +3434,7 @@ index a023f5f4..882e8381 100644 if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) { error("%s: sshkey_to_blob: %s", __func__, ssh_err(r)); return -1; -@@ -195,6 +196,8 @@ pkcs11_add_provider(char *name, char *pin, Key ***keysp) +@@ -210,6 +211,8 @@ pkcs11_add_provider(char *name, char *pi u_int nkeys, i; struct sshbuf *msg; @@ -3301,7 +3443,7 @@ index a023f5f4..882e8381 100644 if (fd < 0 && pkcs11_start_helper() < 0) return (-1); -@@ -208,6 +211,7 @@ pkcs11_add_provider(char *name, char *pin, Key ***keysp) +@@ -226,6 +229,7 @@ pkcs11_add_provider(char *name, char *pi if ((r = sshbuf_get_u32(msg, &nkeys)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); @@ -3309,11 +3451,861 @@ index a023f5f4..882e8381 100644 for (i = 0; i < nkeys; i++) { /* XXX clean up properly instead of fatal() */ if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || -diff --git a/ssh-pkcs11-uri.c b/ssh-pkcs11-uri.c -new file mode 100644 -index 00000000..da15c164 ---- /dev/null -+++ b/ssh-pkcs11-uri.c +diff -up openssh/ssh-pkcs11.c.pkcs11-uri openssh/ssh-pkcs11.c +--- openssh/ssh-pkcs11.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh-pkcs11.c 2018-10-12 13:54:35.755023297 +0200 +@@ -49,8 +49,8 @@ struct pkcs11_slotinfo { + int logged_in; + }; + +-struct pkcs11_provider { +- char *name; ++struct pkcs11_module { ++ char *module_path; + void *handle; + CK_FUNCTION_LIST *function_list; + CK_INFO info; +@@ -59,6 +59,13 @@ struct pkcs11_provider { + struct pkcs11_slotinfo *slotinfo; + int valid; + int refcount; ++}; ++ ++struct pkcs11_provider { ++ char *name; ++ struct pkcs11_module *module; /* can be shared between various providers */ ++ int refcount; ++ int valid; + TAILQ_ENTRY(pkcs11_provider) next; + }; + +@@ -71,10 +78,46 @@ struct pkcs11_key { + RSA_METHOD *rsa_method; + char *keyid; + int keyid_len; ++ char *label; + }; + + int pkcs11_interactive = 0; + ++/* ++ * This can't be in the ssh-pkcs11-uri, becase we can not depend on ++ * PKCS#11 structures in ssh-agent (using client-helper communication) ++ */ ++int ++pkcs11_uri_write(const struct sshkey *key, FILE *f) ++{ ++ char *p = NULL; ++ struct pkcs11_uri uri; ++ struct pkcs11_key *k11; ++ ++ /* sanity - is it a RSA key with associated app_data? */ ++ if (key->type != KEY_RSA || ++ (k11 = RSA_get_app_data(key->rsa)) == NULL) ++ return -1; ++ ++ /* omit type -- we are looking for private-public or private-certificate pairs */ ++ uri.id = k11->keyid; ++ uri.id_len = k11->keyid_len; ++ uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label; ++ uri.object = k11->label; ++ uri.module_path = k11->provider->module->module_path; ++ uri.lib_manuf = k11->provider->module->info.manufacturerID; ++ uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID; ++ ++ p = pkcs11_uri_get(&uri); ++ /* do not cleanup -- we do not allocate here, only reference */ ++ if (p == NULL) ++ return -1; ++ ++ fprintf(f, " %s", p); ++ free(p); ++ return 0; ++} ++ + int + pkcs11_init(int interactive) + { +@@ -90,26 +133,63 @@ pkcs11_init(int interactive) + * this is called when a provider gets unregistered. + */ + static void +-pkcs11_provider_finalize(struct pkcs11_provider *p) ++pkcs11_module_finalize(struct pkcs11_module *m) + { + CK_RV rv; + CK_ULONG i; + +- debug("pkcs11_provider_finalize: %p refcount %d valid %d", +- p, p->refcount, p->valid); +- if (!p->valid) ++ debug("%s: %p refcount %d valid %d", __func__, ++ m, m->refcount, m->valid); ++ if (!m->valid) + return; +- for (i = 0; i < p->nslots; i++) { +- if (p->slotinfo[i].session && +- (rv = p->function_list->C_CloseSession( +- p->slotinfo[i].session)) != CKR_OK) ++ for (i = 0; i < m->nslots; i++) { ++ if (m->slotinfo[i].session && ++ (rv = m->function_list->C_CloseSession( ++ m->slotinfo[i].session)) != CKR_OK) + error("C_CloseSession failed: %lu", rv); + } +- if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) ++ if ((rv = m->function_list->C_Finalize(NULL)) != CKR_OK) + error("C_Finalize failed: %lu", rv); ++ m->valid = 0; ++ m->function_list = NULL; ++ dlclose(m->handle); ++} ++ ++/* ++ * remove a reference to the pkcs11 module. ++ * called when a provider is unregistered. ++ */ ++static void ++pkcs11_module_unref(struct pkcs11_module *m) ++{ ++ debug("%s: %p refcount %d", __func__, m, m->refcount); ++ if (--m->refcount <= 0) { ++ pkcs11_module_finalize(m); ++ if (m->valid) ++ error("%s: %p still valid", __func__, m); ++ free(m->slotlist); ++ free(m->slotinfo); ++ free(m->module_path); ++ free(m); ++ } ++} ++ ++/* ++ * finalize a provider shared libarary, it's no longer usable. ++ * however, there might still be keys referencing this provider, ++ * so the actuall freeing of memory is handled by pkcs11_provider_unref(). ++ * this is called when a provider gets unregistered. ++ */ ++static void ++pkcs11_provider_finalize(struct pkcs11_provider *p) ++{ ++ debug("%s: %p refcount %d valid %d", __func__, ++ p, p->refcount, p->valid); ++ if (!p->valid) ++ return; ++ pkcs11_module_unref(p->module); ++ p->module = NULL; + p->valid = 0; +- p->function_list = NULL; +- dlclose(p->handle); + } + + /* +@@ -119,12 +199,11 @@ pkcs11_provider_finalize(struct pkcs11_p + static void + pkcs11_provider_unref(struct pkcs11_provider *p) + { +- debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount); ++ debug("%s: %p refcount %d", __func__, p, p->refcount); + if (--p->refcount <= 0) { +- if (p->valid) +- error("pkcs11_provider_unref: %p still valid", p); +- free(p->slotlist); +- free(p->slotinfo); ++ if (p->module) ++ pkcs11_module_unref(p->module); ++ free(p->name); + free(p); + } + } +@@ -142,6 +221,20 @@ pkcs11_terminate(void) + } + } + ++/* lookup provider by module path */ ++static struct pkcs11_module * ++pkcs11_provider_lookup_module(char *module_path) ++{ ++ struct pkcs11_provider *p; ++ ++ TAILQ_FOREACH(p, &pkcs11_providers, next) { ++ debug("check %p %s (%s)", p, p->name, p->module->module_path); ++ if (!strcmp(module_path, p->module->module_path)) ++ return (p->module); ++ } ++ return (NULL); ++} ++ + /* lookup provider by name */ + static struct pkcs11_provider * + pkcs11_provider_lookup(char *provider_id) +@@ -156,19 +249,52 @@ pkcs11_provider_lookup(char *provider_id + return (NULL); + } + ++int pkcs11_del_provider_by_uri(struct pkcs11_uri *); ++ + /* unregister provider by name */ + int + pkcs11_del_provider(char *provider_id) + { ++ int rv; ++ struct pkcs11_uri *uri; ++ ++ debug("%s: called, provider_id = %s", __func__, provider_id); ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PCKS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ rv = pkcs11_del_provider_by_uri(uri); ++ pkcs11_uri_cleanup(uri); ++ return rv; ++} ++ ++/* unregister provider by PKCS#11 URI */ ++int ++pkcs11_del_provider_by_uri(struct pkcs11_uri *uri) ++{ + struct pkcs11_provider *p; ++ int rv = -1; ++ char *provider_uri = pkcs11_uri_get(uri); + +- if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { ++ debug3("%s(%s): called", __func__, provider_uri); ++ ++ if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) { + TAILQ_REMOVE(&pkcs11_providers, p, next); + pkcs11_provider_finalize(p); + pkcs11_provider_unref(p); +- return (0); ++ rv = 0; + } +- return (-1); ++ free(provider_uri); ++ return rv; + } + + /* openssl callback for freeing an RSA key */ +@@ -185,6 +311,7 @@ pkcs11_rsa_finish(RSA *rsa) + pkcs11_provider_unref(k11->provider); + RSA_meth_free(k11->rsa_method); + free(k11->keyid); ++ free(k11->label); + free(k11); + } + return (rv); +@@ -201,8 +328,8 @@ pkcs11_find(struct pkcs11_provider *p, C + CK_RV rv; + int ret = -1; + +- f = p->function_list; +- session = p->slotinfo[slotidx].session; ++ f = p->module->function_list; ++ session = p->module->slotinfo[slotidx].session; + if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { + error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); + return (-1); +@@ -249,12 +376,13 @@ pkcs11_rsa_private_encrypt(int flen, con + error("RSA_get_app_data failed for rsa %p", rsa); + return (-1); + } +- if (!k11->provider || !k11->provider->valid) { ++ if (!k11->provider || !k11->provider->valid || !k11->provider->module ++ || !k11->provider->module->valid) { + error("no pkcs11 (valid) provider for rsa %p", rsa); + return (-1); + } +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { + if (!pkcs11_interactive) { + error("need pin entry%s", (si->token.flags & +@@ -313,7 +441,7 @@ pkcs11_rsa_private_decrypt(int flen, con + /* redirect private key operations for rsa key to pkcs11 token */ + static int + pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, +- CK_ATTRIBUTE *keyid_attrib, RSA *rsa) ++ CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, RSA *rsa) + { + struct pkcs11_key *k11; + const RSA_METHOD *def = RSA_get_default_method(); +@@ -328,6 +456,11 @@ pkcs11_rsa_wrap(struct pkcs11_provider * + k11->keyid = xmalloc(k11->keyid_len); + memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); + } ++ if (label_attrib->ulValueLen > 0 ) { ++ k11->label = xmalloc(label_attrib->ulValueLen+1); ++ memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen); ++ k11->label[label_attrib->ulValueLen] = 0; ++ } + k11->rsa_method = RSA_meth_dup(def); + if (k11->rsa_method == NULL) + fatal("%s: RSA_meth_dup failed", __func__); +@@ -371,16 +504,16 @@ pkcs11_open_session(struct pkcs11_provid + CK_SESSION_HANDLE session; + int login_required; + +- f = p->function_list; +- login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED; ++ f = p->module->function_list; ++ login_required = p->module->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED; + if (pin && login_required && !strlen(pin)) { + error("pin required"); + return (-1); + } +- if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| ++ if ((rv = f->C_OpenSession(p->module->slotlist[slotidx], CKF_RW_SESSION| + CKF_SERIAL_SESSION, NULL, NULL, &session)) + != CKR_OK) { +- error("C_OpenSession failed: %lu", rv); ++ error("C_OpenSession failed for slot %lu: %lu", slotidx, rv); + return (-1); + } + if (login_required && pin) { +@@ -392,9 +525,9 @@ pkcs11_open_session(struct pkcs11_provid + error("C_CloseSession failed: %lu", rv); + return (-1); + } +- p->slotinfo[slotidx].logged_in = 1; ++ p->module->slotinfo[slotidx].logged_in = 1; + } +- p->slotinfo[slotidx].session = session; ++ p->module->slotinfo[slotidx].session = session; + return (0); + } + +@@ -404,38 +537,62 @@ pkcs11_open_session(struct pkcs11_provid + * keysp points to an (possibly empty) array with *nkeys keys. + */ + static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG, +- CK_ATTRIBUTE [], CK_ATTRIBUTE [3], struct sshkey ***, int *) ++ CK_ATTRIBUTE [], size_t, CK_ATTRIBUTE [3], struct sshkey ***, int *) + __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE)))); + + static int + pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, +- struct sshkey ***keysp, int *nkeys) ++ struct sshkey ***keysp, int *nkeys, struct pkcs11_uri *uri) + { ++ size_t filter_size = 1; + CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; + CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; + CK_ATTRIBUTE pubkey_filter[] = { +- { CKA_CLASS, NULL, sizeof(pubkey_class) } ++ { CKA_CLASS, NULL, sizeof(pubkey_class) }, ++ { CKA_ID, NULL, 0 }, ++ { CKA_LABEL, NULL, 0 } + }; + CK_ATTRIBUTE cert_filter[] = { +- { CKA_CLASS, NULL, sizeof(cert_class) } ++ { CKA_CLASS, NULL, sizeof(cert_class) }, ++ { CKA_ID, NULL, 0 }, ++ { CKA_LABEL, NULL, 0 } + }; + CK_ATTRIBUTE pubkey_attribs[] = { + { CKA_ID, NULL, 0 }, ++ { CKA_LABEL, NULL, 0 }, + { CKA_MODULUS, NULL, 0 }, + { CKA_PUBLIC_EXPONENT, NULL, 0 } + }; + CK_ATTRIBUTE cert_attribs[] = { + { CKA_ID, NULL, 0 }, ++ { CKA_LABEL, NULL, 0 }, + { CKA_SUBJECT, NULL, 0 }, + { CKA_VALUE, NULL, 0 } + }; + pubkey_filter[0].pValue = &pubkey_class; + cert_filter[0].pValue = &cert_class; + +- if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs, +- keysp, nkeys) < 0 || +- pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs, +- keysp, nkeys) < 0) ++ if (uri->id != NULL) { ++ pubkey_filter[filter_size].pValue = uri->id; ++ pubkey_filter[filter_size].ulValueLen = uri->id_len; ++ cert_filter[filter_size].pValue = uri->id; ++ cert_filter[filter_size].ulValueLen = uri->id_len; ++ filter_size++; ++ } ++ if (uri->object != NULL) { ++ pubkey_filter[filter_size].pValue = uri->object; ++ pubkey_filter[filter_size].ulValueLen = strlen(uri->object); ++ pubkey_filter[filter_size].type = CKA_LABEL; ++ cert_filter[filter_size].pValue = uri->object; ++ cert_filter[filter_size].ulValueLen = strlen(uri->object); ++ cert_filter[filter_size].type = CKA_LABEL; ++ filter_size++; ++ } ++ ++ if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, filter_size, ++ pubkey_attribs, keysp, nkeys) < 0 || ++ pkcs11_fetch_keys_filter(p, slotidx, cert_filter, filter_size, ++ cert_attribs, keysp, nkeys) < 0) + return (-1); + return (0); + } +@@ -462,14 +619,15 @@ have_rsa_key(const RSA *rsa) + + static int + pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, +- CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3], ++ CK_ATTRIBUTE filter[], size_t filter_size, CK_ATTRIBUTE attribs[4], + struct sshkey ***keysp, int *nkeys) + { + struct sshkey *key; + RSA *rsa; + X509 *x509; +- EVP_PKEY *evp; ++ EVP_PKEY *evp = NULL; + int i; ++ int nattribs = 4; + const u_char *cp; + CK_RV rv; + CK_OBJECT_HANDLE obj; +@@ -477,16 +635,15 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f; + +- f = p->function_list; +- session = p->slotinfo[slotidx].session; ++ f = p->module->function_list; ++ session = p->module->slotinfo[slotidx].session; + /* setup a filter the looks for public keys */ +- if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) { ++ if ((rv = f->C_FindObjectsInit(session, filter, filter_size)) != CKR_OK) { + error("C_FindObjectsInit failed: %lu", rv); + return (-1); + } + while (1) { +- /* XXX 3 attributes in attribs[] */ +- for (i = 0; i < 3; i++) { ++ for (i = 0; i < nattribs; i++) { + attribs[i].pValue = NULL; + attribs[i].ulValueLen = 0; + } +@@ -494,22 +651,22 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + || nfound == 0) + break; + /* found a key, so figure out size of the attributes */ +- if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) ++ if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs)) + != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + continue; + } + /* +- * Allow CKA_ID (always first attribute) to be empty, but +- * ensure that none of the others are zero length. ++ * Allow CKA_ID (always first attribute) and CKA_LABEL (second) ++ * to be empty, but ensure that none of the others are zero length. + * XXX assumes CKA_ID is always first. + */ +- if (attribs[1].ulValueLen == 0 || +- attribs[2].ulValueLen == 0) { ++ if (attribs[2].ulValueLen == 0 || ++ attribs[3].ulValueLen == 0) { + continue; + } + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) { ++ for (i = 0; i < nattribs; i++) { + if (attribs[i].ulValueLen > 0) { + attribs[i].pValue = xmalloc( + attribs[i].ulValueLen); +@@ -517,23 +674,23 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + } + + /* +- * retrieve ID, modulus and public exponent of RSA key, +- * or ID, subject and value for certificates. ++ * retrieve ID, label, modulus and public exponent of RSA key, ++ * or ID, label, subject and value for certificates. + */ + rsa = NULL; +- if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) ++ if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs)) + != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); +- } else if (attribs[1].type == CKA_MODULUS ) { ++ } else if (attribs[2].type == CKA_MODULUS ) { + if ((rsa = RSA_new()) == NULL) { + error("RSA_new failed"); + } else { + BIGNUM *rsa_n, *rsa_e; + +- rsa_n = BN_bin2bn(attribs[1].pValue, +- attribs[1].ulValueLen, NULL); +- rsa_e = BN_bin2bn(attribs[2].pValue, ++ rsa_n = BN_bin2bn(attribs[2].pValue, + attribs[2].ulValueLen, NULL); ++ rsa_e = BN_bin2bn(attribs[3].pValue, ++ attribs[3].ulValueLen, NULL); + if (rsa_n != NULL && rsa_e != NULL) { + if (!RSA_set0_key(rsa, + rsa_n, rsa_e, NULL)) +@@ -544,10 +701,10 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + BN_free(rsa_e); + } + } else { +- cp = attribs[2].pValue; ++ cp = attribs[3].pValue; + if ((x509 = X509_new()) == NULL) { + error("X509_new failed"); +- } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen) ++ } else if (d2i_X509(&x509, &cp, attribs[3].ulValueLen) + == NULL) { + error("d2i_X509 failed"); + } else if ((evp = X509_get_pubkey(x509)) == NULL || +@@ -559,9 +716,10 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + error("RSAPublicKey_dup"); + } + X509_free(x509); ++ EVP_PKEY_free(evp); + } + if (rsa && have_rsa_key(rsa) && +- pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { ++ pkcs11_rsa_wrap(p, slotidx, &attribs[0], &attribs[1], rsa) == 0) { + if ((key = sshkey_new(KEY_UNSPEC)) == NULL) + fatal("sshkey_new failed"); + key->rsa = rsa; +@@ -580,7 +738,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + } else if (rsa) { + RSA_free(rsa); + } +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattribs; i++) + free(attribs[i].pValue); + } + if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) +@@ -592,126 +750,239 @@ pkcs11_fetch_keys_filter(struct pkcs11_p + int + pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) + { +- int nkeys, need_finalize = 0; +- struct pkcs11_provider *p = NULL; ++ int rv; ++ struct pkcs11_uri *uri; ++ ++ debug("%s: called, provider_id = %s", __func__, provider_id); ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PCKS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ rv = pkcs11_add_provider_by_uri(uri, pin, keyp); ++ pkcs11_uri_cleanup(uri); ++ return rv; ++} ++ ++struct pkcs11_provider * ++pkcs11_provider_initialize(struct pkcs11_uri *uri) ++{ ++ int need_finalize = 0; + void *handle = NULL; + CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **); + CK_RV rv; + CK_FUNCTION_LIST *f = NULL; + CK_TOKEN_INFO *token; + CK_ULONG i; ++ char *provider_module = NULL; ++ struct pkcs11_provider *p; ++ struct pkcs11_module *m; + +- *keyp = NULL; +- if (pkcs11_provider_lookup(provider_id) != NULL) { +- debug("%s: provider already registered: %s", +- __func__, provider_id); ++ /* if no provider specified, fallback to p11-kit */ ++ if (uri->module_path == NULL) { ++#ifdef PKCS11_DEFAULT_PROVIDER ++ provider_module = strdup(PKCS11_DEFAULT_PROVIDER); ++#else ++ error("%s: No module path provided", __func__); + goto fail; ++#endif ++ } else ++ provider_module = strdup(uri->module_path); ++ ++ p = xcalloc(1, sizeof(*p)); ++ p->name = pkcs11_uri_get(uri); ++ ++ if ((m = pkcs11_provider_lookup_module(provider_module)) != NULL ++ && m->valid) { ++ debug("%s: provider module already initialized: %s", ++ __func__, provider_module); ++ free(provider_module); ++ /* Skip the initialization of PKCS#11 module */ ++ m->refcount++; ++ p->module = m; ++ p->valid = 1; ++ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); ++ p->refcount++; /* add to provider list */ ++ return p; ++ } else { ++ m = xcalloc(1, sizeof(*m)); ++ p->module = m; ++ m->refcount++; + } ++ + /* open shared pkcs11-libarary */ +- if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { +- error("dlopen %s failed: %s", provider_id, dlerror()); ++ if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) { ++ error("dlopen %s failed: %s", provider_module, dlerror()); + goto fail; + } + if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) { + error("dlsym(C_GetFunctionList) failed: %s", dlerror()); + goto fail; + } +- p = xcalloc(1, sizeof(*p)); +- p->name = xstrdup(provider_id); +- p->handle = handle; ++ m->handle = handle; + /* setup the pkcs11 callbacks */ + if ((rv = (*getfunctionlist)(&f)) != CKR_OK) { + error("C_GetFunctionList for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } +- p->function_list = f; ++ m->function_list = f; + if ((rv = f->C_Initialize(NULL)) != CKR_OK) { + error("C_Initialize for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } + need_finalize = 1; +- if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { ++ if ((rv = f->C_GetInfo(&m->info)) != CKR_OK) { + error("C_GetInfo for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); ++ goto fail; ++ } ++ rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); ++ if (uri->lib_manuf != NULL && ++ strcmp(uri->lib_manuf, m->info.manufacturerID)) { ++ debug("%s: Skipping provider %s not matching library_manufacturer", ++ __func__, m->info.manufacturerID); + goto fail; + } +- rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); +- rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); ++ rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); + debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d" + " libraryDescription <%s> libraryVersion %d.%d", +- provider_id, +- p->info.manufacturerID, +- p->info.cryptokiVersion.major, +- p->info.cryptokiVersion.minor, +- p->info.libraryDescription, +- p->info.libraryVersion.major, +- p->info.libraryVersion.minor); +- if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { ++ provider_module, ++ m->info.manufacturerID, ++ m->info.cryptokiVersion.major, ++ m->info.cryptokiVersion.minor, ++ m->info.libraryDescription, ++ m->info.libraryVersion.major, ++ m->info.libraryVersion.minor); ++ ++ if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) { + error("C_GetSlotList failed: %lu", rv); + goto fail; + } +- if (p->nslots == 0) { ++ if (m->nslots == 0) { + debug("%s: provider %s returned no slots", __func__, +- provider_id); ++ provider_module); + goto fail; + } +- p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); +- if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) ++ m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID)); ++ if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots)) + != CKR_OK) { + error("C_GetSlotList for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } +- p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); ++ m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo)); ++ m->valid = 1; + p->valid = 1; +- nkeys = 0; +- for (i = 0; i < p->nslots; i++) { +- token = &p->slotinfo[i].token; +- if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) ++ ++ for (i = 0; i < m->nslots; i++) { ++ token = &m->slotinfo[i].token; ++ if ((rv = f->C_GetTokenInfo(m->slotlist[i], token)) + != CKR_OK) { + error("C_GetTokenInfo for provider %s slot %lu " +- "failed: %lu", provider_id, (unsigned long)i, rv); ++ "failed: %lu", provider_module, (unsigned long)i, rv); + continue; + } + if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { +- debug2("%s: ignoring uninitialised token in " +- "provider %s slot %lu", __func__, +- provider_id, (unsigned long)i); + continue; + } + rmspace(token->label, sizeof(token->label)); + rmspace(token->manufacturerID, sizeof(token->manufacturerID)); + rmspace(token->model, sizeof(token->model)); + rmspace(token->serialNumber, sizeof(token->serialNumber)); ++ } ++ m->module_path = provider_module; ++ provider_module = NULL; ++ ++ /* insert unconditionally -- remove if there will be no keys later */ ++ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); ++ p->refcount++; /* add to provider list */ ++ return p; ++ ++fail: ++ if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) ++ error("C_Finalize for provider %s failed: %lu", ++ provider_module, rv); ++ free(provider_module); ++ free(p); ++ if (handle) ++ dlclose(handle); ++ return NULL; ++} ++ ++int ++pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp) ++{ ++ int nkeys; ++ struct pkcs11_provider *p = NULL; ++ CK_TOKEN_INFO *token; ++ CK_ULONG i; ++ char *provider_uri = pkcs11_uri_get(uri); ++ ++ debug("%s: called, provider_uri = %s", __func__, provider_uri); ++ ++ *keyp = NULL; ++ if ((p = pkcs11_provider_initialize(uri)) == NULL) { ++ debug("%s: failed to initialize provider: %s", ++ __func__, provider_uri); ++ goto fail; ++ } ++ ++ nkeys = 0; ++ for (i = 0; i < p->module->nslots; i++) { ++ token = &p->module->slotinfo[i].token; ++ if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { ++ debug2("%s: ignoring uninitialised token in " ++ "provider %s slot %lu", __func__, ++ provider_uri, (unsigned long)i); ++ continue; ++ } ++ if (uri->token != NULL && ++ strcmp(token->label, uri->token) != 0) { ++ debug2("%s: ignoring token not matching label (%s) " ++ "specified by PKCS#11 URI in slot %lu", __func__, ++ token->label, (unsigned long)i); ++ continue; ++ } ++ if (uri->manuf != NULL && ++ strcmp(token->manufacturerID, uri->manuf) != 0) { ++ debug2("%s: ignoring token not matching requrested " ++ "manufacturerID (%s) specified by PKCS#11 URI in " ++ "slot %lu", __func__, ++ token->manufacturerID, (unsigned long)i); ++ continue; ++ } + debug("provider %s slot %lu: label <%s> manufacturerID <%s> " + "model <%s> serial <%s> flags 0x%lx", +- provider_id, (unsigned long)i, ++ provider_uri, (unsigned long)i, + token->label, token->manufacturerID, token->model, + token->serialNumber, token->flags); +- /* open session, login with pin and retrieve public keys */ +- if (pkcs11_open_session(p, i, pin) == 0) +- pkcs11_fetch_keys(p, i, keyp, &nkeys); ++ /* open session if not yet opened, login with pin ++ * and retrieve public keys */ ++ if ((p->module->slotinfo[i].session != 0) || ++ pkcs11_open_session(p, i, pin) == 0) ++ pkcs11_fetch_keys(p, i, keyp, &nkeys, uri); + } + if (nkeys > 0) { +- TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); +- p->refcount++; /* add to provider list */ ++ free(provider_uri); + return (nkeys); + } +- debug("%s: provider %s returned no keys", __func__, provider_id); ++ debug("%s: provider %s returned no keys", __func__, provider_uri); + /* don't add the provider, since it does not have any keys */ + fail: +- if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) +- error("C_Finalize for provider %s failed: %lu", +- provider_id, rv); + if (p) { +- free(p->slotlist); +- free(p->slotinfo); +- free(p); ++ pkcs11_provider_unref(p); + } +- if (handle) +- dlclose(handle); ++ free(provider_uri); + return (-1); + } + +diff -up openssh/ssh-pkcs11.h.pkcs11-uri openssh/ssh-pkcs11.h +--- openssh/ssh-pkcs11.h.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200 ++++ openssh/ssh-pkcs11.h 2018-10-12 13:52:55.457191459 +0200 +@@ -14,10 +14,15 @@ + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ ++ ++#include "ssh-pkcs11-uri.h" ++ + int pkcs11_init(int); + void pkcs11_terminate(void); + int pkcs11_add_provider(char *, char *, struct sshkey ***); ++int pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***); + int pkcs11_del_provider(char *); ++int pkcs11_uri_write(const struct sshkey *, FILE *); + + #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) + #undef ENABLE_PKCS11 +diff -up openssh/ssh-pkcs11-uri.c.pkcs11-uri openssh/ssh-pkcs11-uri.c +--- openssh/ssh-pkcs11-uri.c.pkcs11-uri 2018-10-12 13:52:55.456191450 +0200 ++++ openssh/ssh-pkcs11-uri.c 2018-10-12 13:52:55.455191442 +0200 @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2017 Red Hat @@ -3710,11 +4702,9 @@ index 00000000..da15c164 +} + +#endif /* ENABLE_PKCS11 */ -diff --git a/ssh-pkcs11-uri.h b/ssh-pkcs11-uri.h -new file mode 100644 -index 00000000..609c4df1 ---- /dev/null -+++ b/ssh-pkcs11-uri.h +diff -up openssh/ssh-pkcs11-uri.h.pkcs11-uri openssh/ssh-pkcs11-uri.h +--- openssh/ssh-pkcs11-uri.h.pkcs11-uri 2018-10-12 13:52:55.456191450 +0200 ++++ openssh/ssh-pkcs11-uri.h 2018-10-12 13:52:55.456191450 +0200 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 Red Hat @@ -3757,1015 +4747,3 @@ index 00000000..609c4df1 +struct pkcs11_uri *pkcs11_uri_init(); +char * pkcs11_uri_get(struct pkcs11_uri *uri); + -diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c -index 88c9d6e2..a29b4451 100644 ---- a/ssh-pkcs11.c -+++ b/ssh-pkcs11.c -@@ -48,8 +48,8 @@ struct pkcs11_slotinfo { - int logged_in; - }; - --struct pkcs11_provider { -- char *name; -+struct pkcs11_module { -+ char *module_path; - void *handle; - CK_FUNCTION_LIST *function_list; - CK_INFO info; -@@ -58,6 +58,13 @@ struct pkcs11_provider { - struct pkcs11_slotinfo *slotinfo; - int valid; - int refcount; -+}; -+ -+struct pkcs11_provider { -+ char *name; -+ struct pkcs11_module *module; /* can be shared between various providers */ -+ int refcount; -+ int valid; - TAILQ_ENTRY(pkcs11_provider) next; - }; - -@@ -70,10 +77,46 @@ struct pkcs11_key { - RSA_METHOD rsa_method; - char *keyid; - int keyid_len; -+ char *label; - }; - - int pkcs11_interactive = 0; - -+/* -+ * This can't be in the ssh-pkcs11-uri, becase we can not depend on -+ * PKCS#11 structures in ssh-agent (using client-helper communication) -+ */ -+int -+pkcs11_uri_write(const struct sshkey *key, FILE *f) -+{ -+ char *p = NULL; -+ struct pkcs11_uri uri; -+ struct pkcs11_key *k11; -+ -+ /* sanity - is it a RSA key with associated app_data? */ -+ if (key->type != KEY_RSA || -+ (k11 = RSA_get_app_data(key->rsa)) == NULL) -+ return -1; -+ -+ /* omit type -- we are looking for private-public or private-certificate pairs */ -+ uri.id = k11->keyid; -+ uri.id_len = k11->keyid_len; -+ uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label; -+ uri.object = k11->label; -+ uri.module_path = k11->provider->module->module_path; -+ uri.lib_manuf = k11->provider->module->info.manufacturerID; -+ uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID; -+ -+ p = pkcs11_uri_get(&uri); -+ /* do not cleanup -- we do not allocate here, only reference */ -+ if (p == NULL) -+ return -1; -+ -+ fprintf(f, " %s", p); -+ free(p); -+ return 0; -+} -+ - int - pkcs11_init(int interactive) - { -@@ -89,26 +132,63 @@ pkcs11_init(int interactive) - * this is called when a provider gets unregistered. - */ - static void --pkcs11_provider_finalize(struct pkcs11_provider *p) -+pkcs11_module_finalize(struct pkcs11_module *m) - { - CK_RV rv; - CK_ULONG i; - -- debug("pkcs11_provider_finalize: %p refcount %d valid %d", -- p, p->refcount, p->valid); -- if (!p->valid) -+ debug("%s: %p refcount %d valid %d", __func__, -+ m, m->refcount, m->valid); -+ if (!m->valid) - return; -- for (i = 0; i < p->nslots; i++) { -- if (p->slotinfo[i].session && -- (rv = p->function_list->C_CloseSession( -- p->slotinfo[i].session)) != CKR_OK) -+ for (i = 0; i < m->nslots; i++) { -+ if (m->slotinfo[i].session && -+ (rv = m->function_list->C_CloseSession( -+ m->slotinfo[i].session)) != CKR_OK) - error("C_CloseSession failed: %lu", rv); - } -- if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) -+ if ((rv = m->function_list->C_Finalize(NULL)) != CKR_OK) - error("C_Finalize failed: %lu", rv); -+ m->valid = 0; -+ m->function_list = NULL; -+ dlclose(m->handle); -+} -+ -+/* -+ * remove a reference to the pkcs11 module. -+ * called when a provider is unregistered. -+ */ -+static void -+pkcs11_module_unref(struct pkcs11_module *m) -+{ -+ debug("%s: %p refcount %d", __func__, m, m->refcount); -+ if (--m->refcount <= 0) { -+ pkcs11_module_finalize(m); -+ if (m->valid) -+ error("%s: %p still valid", __func__, m); -+ free(m->slotlist); -+ free(m->slotinfo); -+ free(m->module_path); -+ free(m); -+ } -+} -+ -+/* -+ * finalize a provider shared libarary, it's no longer usable. -+ * however, there might still be keys referencing this provider, -+ * so the actuall freeing of memory is handled by pkcs11_provider_unref(). -+ * this is called when a provider gets unregistered. -+ */ -+static void -+pkcs11_provider_finalize(struct pkcs11_provider *p) -+{ -+ debug("%s: %p refcount %d valid %d", __func__, -+ p, p->refcount, p->valid); -+ if (!p->valid) -+ return; -+ pkcs11_module_unref(p->module); -+ p->module = NULL; - p->valid = 0; -- p->function_list = NULL; -- dlclose(p->handle); - } - - /* -@@ -118,12 +198,11 @@ pkcs11_provider_finalize(struct pkcs11_provider *p) - static void - pkcs11_provider_unref(struct pkcs11_provider *p) - { -- debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount); -+ debug("%s: %p refcount %d", __func__, p, p->refcount); - if (--p->refcount <= 0) { -- if (p->valid) -- error("pkcs11_provider_unref: %p still valid", p); -- free(p->slotlist); -- free(p->slotinfo); -+ if (p->module) -+ pkcs11_module_unref(p->module); -+ free(p->name); - free(p); - } - } -@@ -141,6 +220,20 @@ pkcs11_terminate(void) - } - } - -+/* lookup provider by module path */ -+static struct pkcs11_module * -+pkcs11_provider_lookup_module(char *module_path) -+{ -+ struct pkcs11_provider *p; -+ -+ TAILQ_FOREACH(p, &pkcs11_providers, next) { -+ debug("check %p %s (%s)", p, p->name, p->module->module_path); -+ if (!strcmp(module_path, p->module->module_path)) -+ return (p->module); -+ } -+ return (NULL); -+} -+ - /* lookup provider by name */ - static struct pkcs11_provider * - pkcs11_provider_lookup(char *provider_id) -@@ -155,19 +248,52 @@ pkcs11_provider_lookup(char *provider_id) - return (NULL); - } - -+int pkcs11_del_provider_by_uri(struct pkcs11_uri *); -+ - /* unregister provider by name */ - int - pkcs11_del_provider(char *provider_id) -+{ -+ int rv; -+ struct pkcs11_uri *uri; -+ -+ debug("%s: called, provider_id = %s", __func__, provider_id); -+ -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PCKS#11 URI"); -+ -+ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { -+ if (pkcs11_uri_parse(provider_id, uri) != 0) -+ fatal("Failed to parse PKCS#11 URI"); -+ } else { -+ uri->module_path = strdup(provider_id); -+ } -+ -+ rv = pkcs11_del_provider_by_uri(uri); -+ pkcs11_uri_cleanup(uri); -+ return rv; -+} -+ -+/* unregister provider by PKCS#11 URI */ -+int -+pkcs11_del_provider_by_uri(struct pkcs11_uri *uri) - { - struct pkcs11_provider *p; -+ int rv = -1; -+ char *provider_uri = pkcs11_uri_get(uri); - -- if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { -+ debug3("%s(%s): called", __func__, provider_uri); -+ -+ if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) { - TAILQ_REMOVE(&pkcs11_providers, p, next); - pkcs11_provider_finalize(p); - pkcs11_provider_unref(p); -- return (0); -+ rv = 0; - } -- return (-1); -+ free(provider_uri); -+ return rv; - } - - /* openssl callback for freeing an RSA key */ -@@ -183,6 +309,7 @@ pkcs11_rsa_finish(RSA *rsa) - if (k11->provider) - pkcs11_provider_unref(k11->provider); - free(k11->keyid); -+ free(k11->label); - free(k11); - } - return (rv); -@@ -199,8 +327,8 @@ pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr, - CK_RV rv; - int ret = -1; - -- f = p->function_list; -- session = p->slotinfo[slotidx].session; -+ f = p->module->function_list; -+ session = p->module->slotinfo[slotidx].session; - if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { - error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); - return (-1); -@@ -247,12 +375,13 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, - error("RSA_get_app_data failed for rsa %p", rsa); - return (-1); - } -- if (!k11->provider || !k11->provider->valid) { -+ if (!k11->provider || !k11->provider->valid || !k11->provider->module -+ || !k11->provider->module->valid) { - error("no pkcs11 (valid) provider for rsa %p", rsa); - return (-1); - } -- f = k11->provider->function_list; -- si = &k11->provider->slotinfo[k11->slotidx]; -+ f = k11->provider->module->function_list; -+ si = &k11->provider->module->slotinfo[k11->slotidx]; - if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { - if (!pkcs11_interactive) { - error("need pin entry%s", (si->token.flags & -@@ -311,7 +440,7 @@ pkcs11_rsa_private_decrypt(int flen, const u_char *from, u_char *to, RSA *rsa, - /* redirect private key operations for rsa key to pkcs11 token */ - static int - pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, -- CK_ATTRIBUTE *keyid_attrib, RSA *rsa) -+ CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, RSA *rsa) - { - struct pkcs11_key *k11; - const RSA_METHOD *def = RSA_get_default_method(); -@@ -326,6 +455,11 @@ 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); - } -+ if (label_attrib->ulValueLen > 0 ) { -+ k11->label = xmalloc(label_attrib->ulValueLen+1); -+ memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen); -+ k11->label[label_attrib->ulValueLen] = 0; -+ } - k11->orig_finish = def->finish; - memcpy(&k11->rsa_method, def, sizeof(k11->rsa_method)); - k11->rsa_method.name = "pkcs11"; -@@ -372,16 +506,16 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) - CK_SESSION_HANDLE session; - int login_required; - -- f = p->function_list; -- login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED; -+ f = p->module->function_list; -+ login_required = p->module->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED; - if (pin && login_required && !strlen(pin)) { - error("pin required"); - return (-1); - } -- if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| -+ if ((rv = f->C_OpenSession(p->module->slotlist[slotidx], CKF_RW_SESSION| - CKF_SERIAL_SESSION, NULL, NULL, &session)) - != CKR_OK) { -- error("C_OpenSession failed: %lu", rv); -+ error("C_OpenSession failed for slot %lu: %lu", slotidx, rv); - return (-1); - } - if (login_required && pin) { -@@ -393,9 +527,9 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) - error("C_CloseSession failed: %lu", rv); - return (-1); - } -- p->slotinfo[slotidx].logged_in = 1; -+ p->module->slotinfo[slotidx].logged_in = 1; - } -- p->slotinfo[slotidx].session = session; -+ p->module->slotinfo[slotidx].session = session; - return (0); - } - -@@ -405,38 +539,62 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin) - * keysp points to an (possibly empty) array with *nkeys keys. - */ - static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG, -- CK_ATTRIBUTE [], CK_ATTRIBUTE [3], struct sshkey ***, int *) -+ CK_ATTRIBUTE [], size_t, CK_ATTRIBUTE [3], struct sshkey ***, int *) - __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE)))); - - static int - pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, -- struct sshkey ***keysp, int *nkeys) -+ struct sshkey ***keysp, int *nkeys, struct pkcs11_uri *uri) - { -+ size_t filter_size = 1; - CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY; - CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE; - CK_ATTRIBUTE pubkey_filter[] = { -- { CKA_CLASS, NULL, sizeof(pubkey_class) } -+ { CKA_CLASS, NULL, sizeof(pubkey_class) }, -+ { CKA_ID, NULL, 0 }, -+ { CKA_LABEL, NULL, 0 } - }; - CK_ATTRIBUTE cert_filter[] = { -- { CKA_CLASS, NULL, sizeof(cert_class) } -+ { CKA_CLASS, NULL, sizeof(cert_class) }, -+ { CKA_ID, NULL, 0 }, -+ { CKA_LABEL, NULL, 0 } - }; - CK_ATTRIBUTE pubkey_attribs[] = { - { CKA_ID, NULL, 0 }, -+ { CKA_LABEL, NULL, 0 }, - { CKA_MODULUS, NULL, 0 }, - { CKA_PUBLIC_EXPONENT, NULL, 0 } - }; - CK_ATTRIBUTE cert_attribs[] = { - { CKA_ID, NULL, 0 }, -+ { CKA_LABEL, NULL, 0 }, - { CKA_SUBJECT, NULL, 0 }, - { CKA_VALUE, NULL, 0 } - }; - pubkey_filter[0].pValue = &pubkey_class; - cert_filter[0].pValue = &cert_class; - -- if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs, -- keysp, nkeys) < 0 || -- pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs, -- keysp, nkeys) < 0) -+ if (uri->id != NULL) { -+ pubkey_filter[filter_size].pValue = uri->id; -+ pubkey_filter[filter_size].ulValueLen = uri->id_len; -+ cert_filter[filter_size].pValue = uri->id; -+ cert_filter[filter_size].ulValueLen = uri->id_len; -+ filter_size++; -+ } -+ if (uri->object != NULL) { -+ pubkey_filter[filter_size].pValue = uri->object; -+ pubkey_filter[filter_size].ulValueLen = strlen(uri->object); -+ pubkey_filter[filter_size].type = CKA_LABEL; -+ cert_filter[filter_size].pValue = uri->object; -+ cert_filter[filter_size].ulValueLen = strlen(uri->object); -+ cert_filter[filter_size].type = CKA_LABEL; -+ filter_size++; -+ } -+ -+ if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, filter_size, -+ pubkey_attribs, keysp, nkeys) < 0 || -+ pkcs11_fetch_keys_filter(p, slotidx, cert_filter, filter_size, -+ cert_attribs, keysp, nkeys) < 0) - return (-1); - return (0); - } -@@ -454,14 +612,15 @@ pkcs11_key_included(struct sshkey ***keysp, int *nkeys, struct sshkey *key) - - static int - pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, -- CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3], -+ CK_ATTRIBUTE filter[], size_t filter_size, CK_ATTRIBUTE attribs[4], - struct sshkey ***keysp, int *nkeys) - { - struct sshkey *key; - RSA *rsa; - X509 *x509; -- EVP_PKEY *evp; -+ EVP_PKEY *evp = NULL; - int i; -+ int nattribs = 4; - const u_char *cp; - CK_RV rv; - CK_OBJECT_HANDLE obj; -@@ -470,16 +629,15 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f; - -- f = p->function_list; -- session = p->slotinfo[slotidx].session; -+ f = p->module->function_list; -+ session = p->module->slotinfo[slotidx].session; - /* setup a filter the looks for public keys */ -- if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) { -+ if ((rv = f->C_FindObjectsInit(session, filter, filter_size)) != CKR_OK) { - error("C_FindObjectsInit failed: %lu", rv); - return (-1); - } - while (1) { -- /* XXX 3 attributes in attribs[] */ -- for (i = 0; i < 3; i++) { -+ for (i = 0; i < nattribs; i++) { - attribs[i].pValue = NULL; - attribs[i].ulValueLen = 0; - } -@@ -487,22 +645,22 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, - || nfound == 0) - break; - /* found a key, so figure out size of the attributes */ -- if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) -+ if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs)) - != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - continue; - } - /* -- * Allow CKA_ID (always first attribute) to be empty, but -- * ensure that none of the others are zero length. -+ * Allow CKA_ID (always first attribute) and CKA_LABEL (second) -+ * to be empty, but ensure that none of the others are zero length. - * XXX assumes CKA_ID is always first. - */ -- if (attribs[1].ulValueLen == 0 || -- attribs[2].ulValueLen == 0) { -+ if (attribs[2].ulValueLen == 0 || -+ attribs[3].ulValueLen == 0) { - continue; - } - /* allocate buffers for attributes */ -- for (i = 0; i < 3; i++) { -+ for (i = 0; i < nattribs; i++) { - if (attribs[i].ulValueLen > 0) { - attribs[i].pValue = xmalloc( - attribs[i].ulValueLen); -@@ -510,27 +668,27 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, - } - - /* -- * retrieve ID, modulus and public exponent of RSA key, -- * or ID, subject and value for certificates. -+ * retrieve ID, label, modulus and public exponent of RSA key, -+ * or ID, label, subject and value for certificates. - */ - rsa = NULL; -- if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3)) -+ if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs)) - != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); -- } else if (attribs[1].type == CKA_MODULUS ) { -+ } else if (attribs[2].type == CKA_MODULUS ) { - 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, -+ rsa->n = BN_bin2bn(attribs[2].pValue, - attribs[2].ulValueLen, NULL); -+ rsa->e = BN_bin2bn(attribs[3].pValue, -+ attribs[3].ulValueLen, NULL); - } - } else { -- cp = attribs[2].pValue; -+ cp = attribs[3].pValue; - if ((x509 = X509_new()) == NULL) { - error("X509_new failed"); -- } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen) -+ } else if (d2i_X509(&x509, &cp, attribs[3].ulValueLen) - == NULL) { - error("d2i_X509 failed"); - } else if ((evp = X509_get_pubkey(x509)) == NULL || -@@ -546,9 +704,10 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, - error("RSAPublicKey_dup"); - } - X509_free(x509); -+ EVP_PKEY_free(evp); - } - if (rsa && rsa->n && rsa->e && -- pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) { -+ pkcs11_rsa_wrap(p, slotidx, &attribs[0], &attribs[1], rsa) == 0) { - if ((key = sshkey_new(KEY_UNSPEC)) == NULL) - fatal("sshkey_new failed"); - key->rsa = rsa; -@@ -569,7 +728,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, - } else if (rsa) { - RSA_free(rsa); - } -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattribs; i++) - free(attribs[i].pValue); - } - if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK) -@@ -581,126 +740,239 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx, - int - pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp) - { -- int nkeys, need_finalize = 0; -- struct pkcs11_provider *p = NULL; -+ int rv; -+ struct pkcs11_uri *uri; -+ -+ debug("%s: called, provider_id = %s", __func__, provider_id); -+ -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PCKS#11 URI"); -+ -+ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { -+ if (pkcs11_uri_parse(provider_id, uri) != 0) -+ fatal("Failed to parse PKCS#11 URI"); -+ } else { -+ uri->module_path = strdup(provider_id); -+ } -+ -+ rv = pkcs11_add_provider_by_uri(uri, pin, keyp); -+ pkcs11_uri_cleanup(uri); -+ return rv; -+} -+ -+struct pkcs11_provider * -+pkcs11_provider_initialize(struct pkcs11_uri *uri) -+{ -+ int need_finalize = 0; - void *handle = NULL; - CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **); - CK_RV rv; - CK_FUNCTION_LIST *f = NULL; - CK_TOKEN_INFO *token; - CK_ULONG i; -+ char *provider_module = NULL; -+ struct pkcs11_provider *p; -+ struct pkcs11_module *m; - -- *keyp = NULL; -- if (pkcs11_provider_lookup(provider_id) != NULL) { -- debug("%s: provider already registered: %s", -- __func__, provider_id); -+ /* if no provider specified, fallback to p11-kit */ -+ if (uri->module_path == NULL) { -+#ifdef PKCS11_DEFAULT_PROVIDER -+ provider_module = strdup(PKCS11_DEFAULT_PROVIDER); -+#else -+ error("%s: No module path provided", __func__); - goto fail; -+#endif -+ } else -+ provider_module = strdup(uri->module_path); -+ -+ p = xcalloc(1, sizeof(*p)); -+ p->name = pkcs11_uri_get(uri); -+ -+ if ((m = pkcs11_provider_lookup_module(provider_module)) != NULL -+ && m->valid) { -+ debug("%s: provider module already initialized: %s", -+ __func__, provider_module); -+ free(provider_module); -+ /* Skip the initialization of PKCS#11 module */ -+ m->refcount++; -+ p->module = m; -+ p->valid = 1; -+ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); -+ p->refcount++; /* add to provider list */ -+ return p; -+ } else { -+ m = xcalloc(1, sizeof(*m)); -+ p->module = m; -+ m->refcount++; - } -+ - /* open shared pkcs11-libarary */ -- if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { -- error("dlopen %s failed: %s", provider_id, dlerror()); -+ if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) { -+ error("dlopen %s failed: %s", provider_module, dlerror()); - goto fail; - } - if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) { - error("dlsym(C_GetFunctionList) failed: %s", dlerror()); - goto fail; - } -- p = xcalloc(1, sizeof(*p)); -- p->name = xstrdup(provider_id); -- p->handle = handle; -+ m->handle = handle; - /* setup the pkcs11 callbacks */ - if ((rv = (*getfunctionlist)(&f)) != CKR_OK) { - error("C_GetFunctionList for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } -- p->function_list = f; -+ m->function_list = f; - if ((rv = f->C_Initialize(NULL)) != CKR_OK) { - error("C_Initialize for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } - need_finalize = 1; -- if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { -+ if ((rv = f->C_GetInfo(&m->info)) != CKR_OK) { - error("C_GetInfo for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } -- rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); -- rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); -+ rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); -+ if (uri->lib_manuf != NULL && -+ strcmp(uri->lib_manuf, m->info.manufacturerID)) { -+ debug("%s: Skipping provider %s not matching library_manufacturer", -+ __func__, m->info.manufacturerID); -+ goto fail; -+ } -+ rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); - debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d" - " libraryDescription <%s> libraryVersion %d.%d", -- provider_id, -- p->info.manufacturerID, -- p->info.cryptokiVersion.major, -- p->info.cryptokiVersion.minor, -- p->info.libraryDescription, -- p->info.libraryVersion.major, -- p->info.libraryVersion.minor); -- if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { -+ provider_module, -+ m->info.manufacturerID, -+ m->info.cryptokiVersion.major, -+ m->info.cryptokiVersion.minor, -+ m->info.libraryDescription, -+ m->info.libraryVersion.major, -+ m->info.libraryVersion.minor); -+ -+ if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) { - error("C_GetSlotList failed: %lu", rv); - goto fail; - } -- if (p->nslots == 0) { -+ if (m->nslots == 0) { - debug("%s: provider %s returned no slots", __func__, -- provider_id); -+ provider_module); - goto fail; - } -- p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); -- if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) -+ m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID)); -+ if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots)) - != CKR_OK) { - error("C_GetSlotList for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } -- p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); -+ m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo)); -+ m->valid = 1; - p->valid = 1; -- nkeys = 0; -- for (i = 0; i < p->nslots; i++) { -- token = &p->slotinfo[i].token; -- if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) -+ -+ for (i = 0; i < m->nslots; i++) { -+ token = &m->slotinfo[i].token; -+ if ((rv = f->C_GetTokenInfo(m->slotlist[i], token)) - != CKR_OK) { - error("C_GetTokenInfo for provider %s slot %lu " -- "failed: %lu", provider_id, (unsigned long)i, rv); -+ "failed: %lu", provider_module, (unsigned long)i, rv); - continue; - } - if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { -- debug2("%s: ignoring uninitialised token in " -- "provider %s slot %lu", __func__, -- provider_id, (unsigned long)i); - continue; - } - rmspace(token->label, sizeof(token->label)); - rmspace(token->manufacturerID, sizeof(token->manufacturerID)); - rmspace(token->model, sizeof(token->model)); - rmspace(token->serialNumber, sizeof(token->serialNumber)); -+ } -+ m->module_path = provider_module; -+ provider_module = NULL; -+ -+ /* insert unconditionally -- remove if there will be no keys later */ -+ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); -+ p->refcount++; /* add to provider list */ -+ return p; -+ -+fail: -+ if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) -+ error("C_Finalize for provider %s failed: %lu", -+ provider_module, rv); -+ free(provider_module); -+ free(p); -+ if (handle) -+ dlclose(handle); -+ return NULL; -+} -+ -+int -+pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp) -+{ -+ int nkeys; -+ struct pkcs11_provider *p = NULL; -+ CK_TOKEN_INFO *token; -+ CK_ULONG i; -+ char *provider_uri = pkcs11_uri_get(uri); -+ -+ debug("%s: called, provider_uri = %s", __func__, provider_uri); -+ -+ *keyp = NULL; -+ if ((p = pkcs11_provider_initialize(uri)) == NULL) { -+ debug("%s: failed to initialize provider: %s", -+ __func__, provider_uri); -+ goto fail; -+ } -+ -+ nkeys = 0; -+ for (i = 0; i < p->module->nslots; i++) { -+ token = &p->module->slotinfo[i].token; -+ if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { -+ debug2("%s: ignoring uninitialised token in " -+ "provider %s slot %lu", __func__, -+ provider_uri, (unsigned long)i); -+ continue; -+ } -+ if (uri->token != NULL && -+ strcmp(token->label, uri->token) != 0) { -+ debug2("%s: ignoring token not matching label (%s) " -+ "specified by PKCS#11 URI in slot %lu", __func__, -+ token->label, (unsigned long)i); -+ continue; -+ } -+ if (uri->manuf != NULL && -+ strcmp(token->manufacturerID, uri->manuf) != 0) { -+ debug2("%s: ignoring token not matching requrested " -+ "manufacturerID (%s) specified by PKCS#11 URI in " -+ "slot %lu", __func__, -+ token->manufacturerID, (unsigned long)i); -+ continue; -+ } - debug("provider %s slot %lu: label <%s> manufacturerID <%s> " - "model <%s> serial <%s> flags 0x%lx", -- provider_id, (unsigned long)i, -+ provider_uri, (unsigned long)i, - token->label, token->manufacturerID, token->model, - token->serialNumber, token->flags); -- /* open session, login with pin and retrieve public keys */ -- if (pkcs11_open_session(p, i, pin) == 0) -- pkcs11_fetch_keys(p, i, keyp, &nkeys); -+ /* open session if not yet opened, login with pin -+ * and retrieve public keys */ -+ if ((p->module->slotinfo[i].session != 0) || -+ pkcs11_open_session(p, i, pin) == 0) -+ pkcs11_fetch_keys(p, i, keyp, &nkeys, uri); - } - if (nkeys > 0) { -- TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); -- p->refcount++; /* add to provider list */ -+ free(provider_uri); - return (nkeys); - } -- debug("%s: provider %s returned no keys", __func__, provider_id); -+ debug("%s: provider %s returned no keys", __func__, provider_uri); - /* don't add the provider, since it does not have any keys */ - fail: -- if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) -- error("C_Finalize for provider %s failed: %lu", -- provider_id, rv); - if (p) { -- free(p->slotlist); -- free(p->slotinfo); -- free(p); -+ pkcs11_provider_unref(p); - } -- if (handle) -- dlclose(handle); -+ free(provider_uri); - return (-1); - } - -diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h -index 0ced74f2..c63a88f6 100644 ---- a/ssh-pkcs11.h -+++ b/ssh-pkcs11.h -@@ -14,10 +14,15 @@ - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -+ -+#include "ssh-pkcs11-uri.h" -+ - int pkcs11_init(int); - void pkcs11_terminate(void); - int pkcs11_add_provider(char *, char *, struct sshkey ***); -+int pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***); - int pkcs11_del_provider(char *); -+int pkcs11_uri_write(const struct sshkey *, FILE *); - - #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) - #undef ENABLE_PKCS11 -diff --git a/ssh.c b/ssh.c -index d3619fe2..180eb2e0 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -769,6 +769,14 @@ main(int ac, char **av) - options.gss_deleg_creds = 1; - break; - case 'i': -+#ifdef ENABLE_PKCS11 -+ if (strlen(optarg) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(optarg, PKCS11_URI_SCHEME, -+ strlen(PKCS11_URI_SCHEME)) == 0) { -+ add_identity_file(&options, NULL, optarg, 1); -+ break; -+ } -+#endif - p = tilde_expand_filename(optarg, getuid()); - if (stat(p, &st) < 0) - fprintf(stderr, "Warning: Identity file %s " -@@ -1999,6 +2007,45 @@ ssh_session2(struct ssh *ssh, struct passwd *pw) - options.escape_char : SSH_ESCAPECHAR_NONE, id); - } - -+#ifdef ENABLE_PKCS11 -+static void -+load_pkcs11_identity(char *pkcs11_uri, char *identity_files[], -+ struct sshkey *identity_keys[], int *n_ids) -+{ -+ int nkeys, i; -+ struct sshkey **keys; -+ struct pkcs11_uri *uri; -+ -+ debug("identity file '%s' from pkcs#11", pkcs11_uri); -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PCKS#11 URI"); -+ -+ if (pkcs11_uri_parse(pkcs11_uri, uri) != 0) -+ fatal("Failed to parse PKCS#11 URI %s", pkcs11_uri); -+ -+ /* we need to merge URI and provider together */ -+ if (options.pkcs11_provider != NULL && uri->module_path == NULL) -+ uri->module_path = strdup(options.pkcs11_provider); -+ -+ if (options.num_identity_files < SSH_MAX_IDENTITY_FILES && -+ (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys)) > 0) { -+ for (i = 0; i < nkeys; i++) { -+ if (*n_ids >= SSH_MAX_IDENTITY_FILES) { -+ sshkey_free(keys[i]); -+ continue; -+ } -+ identity_keys[*n_ids] = keys[i]; -+ identity_files[*n_ids] = pkcs11_uri_get(uri); -+ (*n_ids)++; -+ } -+ free(keys); -+ } -+ -+ pkcs11_uri_cleanup(uri); -+} -+#endif /* ENABLE_PKCS11 */ -+ - /* Loads all IdentityFile and CertificateFile keys */ - static void - load_public_identity_files(struct passwd *pw) -@@ -2011,10 +2058,6 @@ load_public_identity_files(struct passwd *pw) - char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; - struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; - int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; --#ifdef ENABLE_PKCS11 -- struct sshkey **keys; -- int nkeys; --#endif /* PKCS11 */ - - n_ids = n_certs = 0; - memset(identity_files, 0, sizeof(identity_files)); -@@ -2023,32 +2066,46 @@ load_public_identity_files(struct passwd *pw) - sizeof(certificate_file_userprovided)); - - #ifdef ENABLE_PKCS11 -- if (options.pkcs11_provider != NULL && -- options.num_identity_files < SSH_MAX_IDENTITY_FILES && -- (pkcs11_init(!options.batch_mode) == 0) && -- (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, -- &keys)) > 0) { -- for (i = 0; i < nkeys; i++) { -- if (n_ids >= SSH_MAX_IDENTITY_FILES) { -- sshkey_free(keys[i]); -- continue; -- } -- identity_keys[n_ids] = keys[i]; -- identity_files[n_ids] = -- xstrdup(options.pkcs11_provider); /* XXX */ -- n_ids++; -- } -- free(keys); -+ /* handle fallback from PKCS11Provider option */ -+ pkcs11_init(!options.batch_mode); -+ -+ if (options.pkcs11_provider != NULL) { -+ struct pkcs11_uri *uri; -+ -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PCKS#11 URI"); -+ -+ /* Construct simple PKCS#11 URI to simplify access */ -+ uri->module_path = strdup(options.pkcs11_provider); -+ -+ /* Add it as any other IdentityFile */ -+ cp = pkcs11_uri_get(uri); -+ add_identity_file(&options, NULL, cp, 1); -+ free(cp); -+ -+ pkcs11_uri_cleanup(uri); - } - #endif /* ENABLE_PKCS11 */ - for (i = 0; i < options.num_identity_files; i++) { -+ char *name = options.identity_files[i]; - if (n_ids >= SSH_MAX_IDENTITY_FILES || -- strcasecmp(options.identity_files[i], "none") == 0) { -+ strcasecmp(name, "none") == 0) { - free(options.identity_files[i]); - options.identity_files[i] = NULL; - continue; - } -- cp = tilde_expand_filename(options.identity_files[i], getuid()); -+#ifdef ENABLE_PKCS11 -+ if (strlen(name) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(name, PKCS11_URI_SCHEME, -+ strlen(PKCS11_URI_SCHEME)) == 0) { -+ load_pkcs11_identity(name, identity_files, -+ identity_keys, &n_ids); -+ free(options.identity_files[i]); -+ continue; -+ } -+#endif /* ENABLE_PKCS11 */ -+ cp = tilde_expand_filename(name, getuid()); - filename = percent_expand(cp, "d", pw->pw_dir, - "u", pw->pw_name, "l", thishost, "h", host, - "r", options.user, (char *)NULL); -diff --git a/ssh_config.5 b/ssh_config.5 -index 71705cab..e0266609 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -919,6 +919,19 @@ may also be used in conjunction with - .Cm CertificateFile - in order to provide any certificate also needed for authentication with - the identity. -+.Pp -+The authentication identity can be also specified in a form of PKCS#11 URI -+starting with a string -+.Cm pkcs11: . -+There is supported a subset of the PKCS#11 URI as defined -+in RFC 7512 (implemented path arguments -+.Cm id , -+.Cm manufacturer , -+.Cm object , -+.Cm token -+and query argument -+.Cm module-path -+). The URI can not be in quotes. - .It Cm IgnoreUnknown - Specifies a pattern-list of unknown options to be ignored if they are - encountered in configuration parsing. diff --git a/openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch index 084c903..ae019fc 100644 --- a/openssh-7.7p1-fips.patch +++ b/openssh-7.7p1-fips.patch @@ -102,12 +102,14 @@ diff -up openssh-7.7p1/dh.h.fips openssh-7.7p1/dh.h diff -up openssh-7.7p1/entropy.c.fips openssh-7.7p1/entropy.c --- openssh-7.7p1/entropy.c.fips 2018-08-08 10:08:40.698718928 +0200 +++ openssh-7.7p1/entropy.c 2018-08-08 10:08:40.822719973 +0200 -@@ -217,6 +217,9 @@ seed_rng(void) +@@ -217,6 +217,11 @@ seed_rng(void) fatal("OpenSSL version mismatch. Built against %lx, you " "have %lx", (u_long)OPENSSL_VERSION_NUMBER, SSLeay()); + /* clean the PRNG status when exiting the program */ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + atexit(RAND_cleanup); ++#endif + #ifndef OPENSSL_PRNG_ONLY if (RAND_status() == 1) { @@ -377,16 +379,16 @@ diff -up openssh-7.7p1/myproposal.h.fips openssh-7.7p1/myproposal.h + "hmac-sha1" +#endif + - #else /* WITH_OPENSSL */ - - #define KEX_SERVER_KEX \ + /* Not a KEX value, but here so all the algorithm defaults are together */ + #define SSH_ALLOWED_CA_SIGALGS \ + "ecdsa-sha2-nistp256," \ diff -up openssh-7.7p1/readconf.c.fips openssh-7.7p1/readconf.c --- openssh-7.7p1/readconf.c.fips 2018-08-08 10:08:40.769719527 +0200 +++ openssh-7.7p1/readconf.c 2018-08-08 10:08:40.824719990 +0200 -@@ -2081,17 +2081,18 @@ fill_default_options(Options * options) - all_mac = mac_alg_list(','); +@@ -2081,18 +2081,19 @@ fill_default_options(Options * options) all_kex = kex_alg_list(','); all_key = sshkey_alg_list(0, 0, 1, ','); + all_sig = sshkey_alg_list(0, 1, 1, ','); -#define ASSEMBLE(what, defaults, all) \ +#define ASSEMBLE(what, defaults, fips_defaults, all) \ do { \ @@ -401,11 +403,13 @@ diff -up openssh-7.7p1/readconf.c.fips openssh-7.7p1/readconf.c - ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, all_kex); - ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key); - ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key); +- ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig); + ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, KEX_FIPS_ENCRYPT, all_cipher); + ASSEMBLE(macs, KEX_SERVER_MAC, KEX_FIPS_MAC, all_mac); + ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, KEX_DEFAULT_KEX_FIPS, all_kex); + ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); + ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); ++ ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, KEX_FIPS_PK_ALG, all_sig); #undef ASSEMBLE free(all_cipher); free(all_mac); @@ -425,10 +429,10 @@ diff -up openssh-7.7p1/sandbox-seccomp-filter.c.fips openssh-7.7p1/sandbox-secco diff -up openssh-7.7p1/servconf.c.fips openssh-7.7p1/servconf.c --- openssh-7.7p1/servconf.c.fips 2018-08-08 10:08:40.778719603 +0200 +++ openssh-7.7p1/servconf.c 2018-08-08 10:08:40.824719990 +0200 -@@ -196,17 +196,18 @@ option_clear_or_none(const char *o) - all_mac = mac_alg_list(','); +@@ -196,18 +196,19 @@ option_clear_or_none(const char *o) all_kex = kex_alg_list(','); all_key = sshkey_alg_list(0, 0, 1, ','); + all_sig = sshkey_alg_list(0, 1, 1, ','); -#define ASSEMBLE(what, defaults, all) \ +#define ASSEMBLE(what, defaults, fips_defaults, all) \ do { \ @@ -443,12 +447,14 @@ diff -up openssh-7.7p1/servconf.c.fips openssh-7.7p1/servconf.c - ASSEMBLE(hostkeyalgorithms, KEX_DEFAULT_PK_ALG, all_key); - ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key); - ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key); +- ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig); + ASSEMBLE(ciphers, KEX_SERVER_ENCRYPT, KEX_FIPS_ENCRYPT, all_cipher); + ASSEMBLE(macs, KEX_SERVER_MAC, KEX_FIPS_MAC, all_mac); + ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, KEX_DEFAULT_KEX_FIPS, all_kex); + ASSEMBLE(hostkeyalgorithms, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); + ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); + ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, KEX_FIPS_PK_ALG, all_key); ++ ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, KEX_FIPS_PK_ALG, all_sig); #undef ASSEMBLE free(all_cipher); free(all_mac); @@ -464,11 +470,13 @@ diff -up openssh-7.7p1/ssh.c.fips openssh-7.7p1/ssh.c #include "openbsd-compat/openssl-compat.h" #include "openbsd-compat/sys-queue.h" -@@ -579,6 +581,14 @@ main(int ac, char **av) +@@ -579,6 +581,16 @@ main(int ac, char **av) sanitise_stdfd(); __progname = ssh_get_progname(av[0]); -+ SSLeay_add_all_algorithms(); ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++ SSLeay_add_all_algorithms(); ++#endif + if (access("/etc/system-fips", F_OK) == 0) + if (! FIPSCHECK_verify(NULL, NULL)){ + if (FIPS_mode()) @@ -605,7 +613,7 @@ diff -up openssh-7.7p1/sshd.c.fips openssh-7.7p1/sshd.c #endif __progname = ssh_get_progname(av[0]); -+ SSLeay_add_all_algorithms(); ++ OpenSSL_add_all_algorithms(); + if (access("/etc/system-fips", F_OK) == 0) + if (! FIPSCHECK_verify(NULL, NULL)) { + openlog(__progname, LOG_PID, LOG_AUTHPRIV); diff --git a/openssh-7.8p1-gsskex.patch b/openssh-7.8p1-gsskex.patch index 6a350c7..a2c99e3 100644 --- a/openssh-7.8p1-gsskex.patch +++ b/openssh-7.8p1-gsskex.patch @@ -188,7 +188,7 @@ diff -up openssh/configure.ac.gsskex openssh/configure.ac diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c --- openssh/gss-genr.c.gsskex 2018-08-20 07:57:29.000000000 +0200 +++ openssh/gss-genr.c 2018-08-22 13:18:47.444383602 +0200 -@@ -35,18 +35,177 @@ +@@ -35,18 +35,179 @@ #include #include #include @@ -256,7 +256,7 @@ diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c + u_char digest[EVP_MAX_MD_SIZE]; + char deroid[2]; + const EVP_MD *evp_md = EVP_md5(); -+ EVP_MD_CTX md; ++ EVP_MD_CTX *md; + + if (gss_enc2oid != NULL) { + for (i = 0; gss_enc2oid[i].encoded != NULL; i++) @@ -270,6 +270,7 @@ diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c + if ((buf = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __func__); + ++ md = EVP_MD_CTX_new(); + oidpos = 0; + for (i = 0; i < gss_supported->count; i++) { + if (gss_supported->elements[i].length < 128 && @@ -278,12 +279,12 @@ diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c + deroid[0] = SSH_GSS_OIDTYPE; + deroid[1] = gss_supported->elements[i].length; + -+ EVP_DigestInit(&md, evp_md); -+ EVP_DigestUpdate(&md, deroid, 2); -+ EVP_DigestUpdate(&md, ++ EVP_DigestInit(md, evp_md); ++ EVP_DigestUpdate(md, deroid, 2); ++ EVP_DigestUpdate(md, + gss_supported->elements[i].elements, + gss_supported->elements[i].length); -+ EVP_DigestFinal(&md, digest, NULL); ++ EVP_DigestFinal(md, digest, NULL); + + encoded = xmalloc(EVP_MD_size(evp_md) * 2); + enclen = __b64_ntop(digest, EVP_MD_size(evp_md), @@ -311,6 +312,7 @@ diff -up openssh/gss-genr.c.gsskex openssh/gss-genr.c + oidpos++; + } + } ++ EVP_MD_CTX_free(md); + gss_enc2oid[oidpos].oid = NULL; + gss_enc2oid[oidpos].encoded = NULL; + @@ -988,7 +990,7 @@ diff -up openssh/kex.c.gsskex openssh/kex.c diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c --- openssh/kexgssc.c.gsskex 2018-08-22 11:47:33.311216457 +0200 +++ openssh/kexgssc.c 2018-08-22 11:47:33.311216457 +0200 -@@ -0,0 +1,338 @@ +@@ -0,0 +1,341 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1049,6 +1051,7 @@ diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c + BIGNUM *shared_secret = NULL; + BIGNUM *p = NULL; + BIGNUM *g = NULL; ++ const BIGNUM *pub_key, *p1, *g1; + u_char *kbuf; + u_char *serverhostkey = NULL; + u_char *empty = ""; @@ -1110,8 +1113,9 @@ diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c + fatal("%s: Unexpected KEX type %d", __func__, ssh->kex->kex_type); + } + -+ /* Step 1 - e is dh->pub_key */ ++ /* Step 1 - e is pub_key */ + dh_gen_key(dh, ssh->kex->we_need * 8); ++ DH_get0_key(dh, &pub_key, NULL); + + /* This is f, we initialise it now to make life easier */ + dh_server_pub = BN_new(); @@ -1159,7 +1163,7 @@ diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c + packet_start(SSH2_MSG_KEXGSS_INIT); + packet_put_string(send_tok.value, + send_tok.length); -+ packet_put_bignum2(dh->pub_key); ++ packet_put_bignum2((BIGNUM *)pub_key); + first = 0; + } else { + packet_start(SSH2_MSG_KEXGSS_CONTINUE); @@ -1266,13 +1270,14 @@ diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c + sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), + sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), + (serverhostkey ? serverhostkey : empty), slen, -+ dh->pub_key, /* e */ ++ pub_key, /* e */ + dh_server_pub, /* f */ + shared_secret, /* K */ + hash, &hashlen + ); + break; + case KEX_GSS_GEX_SHA1: ++ DH_get0_pqg(dh, &p1, NULL, &g1); + kexgex_hash( + ssh->kex->hash_alg, + ssh->kex->client_version_string, @@ -1281,8 +1286,8 @@ diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c + sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), + (serverhostkey ? serverhostkey : empty), slen, + min, nbits, max, -+ dh->p, dh->g, -+ dh->pub_key, ++ p, g, ++ pub_key, + dh_server_pub, + shared_secret, + hash, &hashlen @@ -1330,7 +1335,7 @@ diff -up openssh/kexgssc.c.gsskex openssh/kexgssc.c diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c --- openssh/kexgsss.c.gsskex 2018-08-22 11:47:33.311216457 +0200 +++ openssh/kexgsss.c 2018-08-22 11:47:33.311216457 +0200 -@@ -0,0 +1,297 @@ +@@ -0,0 +1,300 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1410,6 +1415,7 @@ diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c + char *mechs; + u_char hash[SSH_DIGEST_MAX_LENGTH]; + size_t hashlen; ++ const BIGNUM *p, *g, *pub_key; + + /* Initialise GSSAPI */ + @@ -1455,9 +1461,10 @@ diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c + if (dh == NULL) + packet_disconnect("Protocol error: no matching group found"); + ++ DH_get0_pqg(dh, &p, NULL, &g); + packet_start(SSH2_MSG_KEXGSS_GROUP); -+ packet_put_bignum2(dh->p); -+ packet_put_bignum2(dh->g); ++ packet_put_bignum2((BIGNUM *)p); ++ packet_put_bignum2((BIGNUM *)g); + packet_send(); + + packet_write_wait(); @@ -1549,6 +1556,7 @@ diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c + memset(kbuf, 0, klen); + free(kbuf); + ++ DH_get0_key(dh, &pub_key, NULL); + hashlen = sizeof(hash); + switch (ssh->kex->kex_type) { + case KEX_GSS_GRP1_SHA1: @@ -1558,7 +1566,7 @@ diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c + sshbuf_ptr(ssh->kex->peer), sshbuf_len(ssh->kex->peer), + sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), + NULL, 0, /* Change this if we start sending host keys */ -+ dh_client_pub, dh->pub_key, shared_secret, ++ dh_client_pub, pub_key, shared_secret, + hash, &hashlen + ); + break; @@ -1570,9 +1578,9 @@ diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c + sshbuf_ptr(ssh->kex->my), sshbuf_len(ssh->kex->my), + NULL, 0, + cmin, nbits, cmax, -+ dh->p, dh->g, ++ p, g, + dh_client_pub, -+ dh->pub_key, ++ pub_key, + shared_secret, + hash, &hashlen + ); @@ -1596,7 +1604,7 @@ diff -up openssh/kexgsss.c.gsskex openssh/kexgsss.c + fatal("Couldn't get MIC"); + + packet_start(SSH2_MSG_KEXGSS_COMPLETE); -+ packet_put_bignum2(dh->pub_key); ++ packet_put_bignum2(pub_key); + packet_put_string(msg_tok.value,msg_tok.length); + + if (send_tok.length != 0) { @@ -1928,7 +1936,7 @@ diff -up openssh/monitor_wrap.c.gsskex openssh/monitor_wrap.c + + sshbuf_free(m); + -+ return(major); ++ return (major); +} + +int @@ -2617,16 +2625,6 @@ diff -up openssh/sshconnect2.c.gsskex openssh/sshconnect2.c diff -up openssh/sshd.c.gsskex openssh/sshd.c --- openssh/sshd.c.gsskex 2018-08-22 11:47:33.299216360 +0200 +++ openssh/sshd.c 2018-08-22 13:34:28.455975954 +0200 -@@ -537,8 +537,7 @@ privsep_preauth_child(void) - - #ifdef GSSAPI - /* Cache supported mechanism OIDs for later use */ -- if (options.gss_authentication) -- ssh_gssapi_prepare_supported_oids(); -+ ssh_gssapi_prepare_supported_oids(); - #endif - - reseed_prngs(); @@ -887,8 +887,9 @@ notify_hostkeys(struct ssh *ssh) } debug3("%s: sent %u hostkeys", __func__, nkeys); diff --git a/openssh.spec b/openssh.spec index 55e0a13..2ec7712 100644 --- a/openssh.spec +++ b/openssh.spec @@ -65,10 +65,10 @@ %endif # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 -%global openssh_ver 7.8p1 -%global openssh_rel 3 +%global openssh_ver 7.9p1 +%global openssh_rel 1 %global pam_ssh_agent_ver 0.10.3 -%global pam_ssh_agent_rel 5 +%global pam_ssh_agent_rel 6 Summary: An open source implementation of SSH protocol version 2 Name: openssh @@ -100,8 +100,6 @@ Patch100: openssh-6.7p1-coverity.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1894 #https://bugzilla.redhat.com/show_bug.cgi?id=735889 #Patch102: openssh-5.8p1-getaddrinfo.patch -# OpenSSL 1.1.0 compatibility -Patch104: openssh-7.3p1-openssl-1.1.0.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1402 # https://bugzilla.redhat.com/show_bug.cgi?id=1171248 @@ -451,7 +449,6 @@ popd %patch700 -p1 -b .fips %patch100 -p1 -b .coverity -%patch104 -p1 -b .openssl %if 0 # Nothing here yet @@ -568,7 +565,10 @@ popd %if %{pam_ssh_agent} pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver} LDFLAGS="$SAVE_LDFLAGS" -%configure --with-selinux --libexecdir=/%{_libdir}/security --with-mantype=man +%configure --with-selinux \ + --libexecdir=/%{_libdir}/security \ + --with-mantype=man \ + --without-openssl-header-check `# The check is broken` make popd %endif diff --git a/sources b/sources index c3723f0..61a7b55 100644 --- a/sources +++ b/sources @@ -1,4 +1,4 @@ -SHA512 (openssh-7.8p1.tar.gz) = 8e5b0c8682a9243e4e8b7c374ec989dccd1a752eb6f84e593b67141e8b23dcc8b9a7322b1f7525d18e2ce8830a767d0d9793f997486339db201a57986b910705 -SHA512 (openssh-7.8p1.tar.gz.asc) = 3a7bef84df3c07aa78965a11a6bbd6ca6e5d1e9265ac08871b3e5d304646be651b74f5302a195e86a56e6a83b19d79292e5599c9a9cf6f003a513d4354e8ad2f +SHA512 (openssh-7.9p1.tar.gz) = 0412c9c429c9287f0794023951469c8e6ec833cdb55821bfa0300dd90d0879ff60484f620cffd93372641ab69bf0b032c2d700ccc680950892725fb631b7708e +SHA512 (openssh-7.9p1.tar.gz.asc) = 881db1b541813136fabd9adb9f5430c4f0fae372c06c99cb049feb8526a573275fe80c129c89511dd4e65f73f41e29364fefaaf8b7c78835224691c488d5da32 SHA512 (DJM-GPG-KEY.gpg) = db1191ed9b6495999e05eed2ef863fb5179bdb63e94850f192dad68eed8579836f88fbcfffd9f28524fe1457aff8cd248ee3e0afc112c8f609b99a34b80ecc0d SHA512 (pam_ssh_agent_auth-0.10.3.tar.bz2) = d75062c4e46b0b011f46aed9704a99049995fea8b5115ff7ee26dad7e93cbcf54a8af7efc6b521109d77dc03c6f5284574d2e1b84c6829cec25610f24fb4bd66