@@ -94,6 +94,7 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
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");

@@ -118,26 +119,30 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
p = g = NULL; /* belong to kex->dh now */

/* generate and send 'e', client DH public key */
if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 ||
(r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 ||
(r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 ||
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:
if (p)
BN_clear_free(p);
if (g)
BN_clear_free(g);
BN_clear_free(p);
BN_clear_free(g);
if (r != 0) {
DH_free(kex->dh);
kex->dh = NULL;
}
return r;
}

@@ -151,6 +156,7 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
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) {
@@ -213,6 +219,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
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,
@@ -222,8 +230,8 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
server_host_key_blob, sbloblen,
kex->min, kex->nbits, kex->max,
kex->dh->p, kex->dh->g,
kex->dh->pub_key,
p, g,
pub_key,
dh_server_pub,
shared_secret,
hash, &hashlen)) != 0)
@@ -72,6 +72,7 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
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_int32_t seq, struct ssh *ssh)
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_int32_t seq, struct ssh *ssh)
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_t seq, struct ssh *ssh)
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_t seq, struct ssh *ssh)
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_t seq, struct ssh *ssh)
sshbuf_ptr(kex->my), sshbuf_len(kex->my),
server_host_key_blob, sbloblen,
kex->min, kex->nbits, kex->max,
kex->dh->p, kex->dh->g,
p, g,
dh_client_pub,
kex->dh->pub_key,
pub_key,
shared_secret,
hash, &hashlen)) != 0)
goto out;
@@ -227,7 +236,7 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
/* send server hostkey, DH pubkey 'f' and singed 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;

Large diffs are not rendered by default.

@@ -0,0 +1,98 @@
#ifndef LIBCRYPTO_COMPAT_H
#define LIBCRYPTO_COMPAT_H

#if OPENSSL_VERSION_NUMBER < 0x10100000L

#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/ecdsa.h>
#include <openssl/dh.h>
#include <openssl/evp.h>

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);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(unused)


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_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(unused)

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);

EVP_CIPHER *EVP_CIPHER_meth_new(int cipher_type, int block_size, int key_len);
void EVP_CIPHER_meth_free(EVP_CIPHER *cipher);

int EVP_CIPHER_meth_set_iv_length(EVP_CIPHER *cipher, int iv_len);
int EVP_CIPHER_meth_set_flags(EVP_CIPHER *cipher, unsigned long flags);
int EVP_CIPHER_meth_set_init(EVP_CIPHER *cipher,
int (*init) (EVP_CIPHER_CTX *ctx,
const unsigned char *key,
const unsigned char *iv,
int enc));
int EVP_CIPHER_meth_set_do_cipher(EVP_CIPHER *cipher,
int (*do_cipher) (EVP_CIPHER_CTX *ctx,
unsigned char *out,
const unsigned char *in,
size_t inl));
int EVP_CIPHER_meth_set_cleanup(EVP_CIPHER *cipher,
int (*cleanup) (EVP_CIPHER_CTX *));
int EVP_CIPHER_meth_set_ctrl(EVP_CIPHER *cipher,
int (*ctrl) (EVP_CIPHER_CTX *, int type,
int arg, void *ptr));

int (*EVP_CIPHER_meth_get_init(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
const unsigned char *key,
const unsigned char *iv,
int enc);
int (*EVP_CIPHER_meth_get_do_cipher(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *ctx,
unsigned char *out,
const unsigned char *in,
size_t inl);
int (*EVP_CIPHER_meth_get_cleanup(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *);
int (*EVP_CIPHER_meth_get_ctrl(const EVP_CIPHER *cipher))(EVP_CIPHER_CTX *,
int type, int arg,
void *ptr);

#define EVP_CIPHER_CTX_reset(c) EVP_CIPHER_CTX_init(c)

int EVP_CIPHER_CTX_encrypting(const EVP_CIPHER_CTX *ctx);

#endif /* OPENSSL_VERSION_NUMBER */

#endif /* LIBCRYPTO_COMPAT_H */

@@ -587,9 +587,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);
buffer_put_char(m, 1);
buffer_put_bignum2(m, dh->p);
buffer_put_bignum2(m, dh->g);
buffer_put_bignum2(m, p);
buffer_put_bignum2(m, g);

DH_free(dh);
}
@@ -70,12 +70,19 @@ ssh_compatible_openssl(long headerver, long libver)
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

@@ -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);
@@ -197,18 +197,13 @@ 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();

TEST_START("new/free KEY_DSA");
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");
@@ -55,6 +55,7 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
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_char **sigp, size_t *lenp,
goto out;
}

rlen = BN_num_bytes(sig->r);
slen = BN_num_bytes(sig->s);
DSA_SIG_get0(sig, &r, &s);
rlen = BN_num_bytes(r);
slen = BN_num_bytes(s);
if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
ret = SSH_ERR_INTERNAL_ERROR;
goto out;
}
explicit_bzero(sigblob, SIGBLOB_LEN);
BN_bn2bin(sig->r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
BN_bn2bin(sig->s, sigblob + SIGBLOB_LEN - slen);
BN_bn2bin(r, sigblob + SIGBLOB_LEN - INTBLOB_LEN - rlen);
BN_bn2bin(s, sigblob + SIGBLOB_LEN - slen);

if (compat & SSH_BUG_SIGBLOB) {
if (sigp != NULL) {
@@ -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,8 +213,9 @@ ssh_dss_verify(const struct sshkey *key,

out:
explicit_bzero(digest, sizeof(digest));
if (sig != NULL)
DSA_SIG_free(sig);
BN_free(r);
BN_free(s);
DSA_SIG_free(sig);
sshbuf_free(b);
free(ktype);
if (sigblob != NULL) {
@@ -54,6 +54,7 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
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, u_char **sigp, size_t *lenp,
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((ret = sshbuf_put_bignum2(bb, sig->r)) != 0 ||
(ret = sshbuf_put_bignum2(bb, sig->s)) != 0)
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 *key,
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 *key,
}

/* 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,8 +191,9 @@ ssh_ecdsa_verify(const struct sshkey *key,
explicit_bzero(digest, sizeof(digest));
sshbuf_free(sigbuf);
sshbuf_free(b);
if (sig != NULL)
ECDSA_SIG_free(sig);
BN_free(r);
BN_free(s);
ECDSA_SIG_free(sig);
free(ktype);
return ret;
}
@@ -495,40 +495,68 @@ do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
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: {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: These blocks seem over-indented (which makes the diff a little more annoying), or is that the preferred style here? Ditto with the other case FOO: { ... } blocks.

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);
@@ -636,7 +664,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private)
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");
@@ -660,7 +688,7 @@ do_convert_from_pkcs8(struct sshkey **k, int *private)
#endif
default:
fatal("%s: unsupported pubkey type %d", __func__,
EVP_PKEY_type(pubkey->type));
EVP_PKEY_base_id(pubkey));
}
EVP_PKEY_free(pubkey);
return;
@@ -143,12 +143,20 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
static int
wrap_key(RSA *rsa)
{
static RSA_METHOD helper_rsa;

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);
static RSA_METHOD *helper_rsa;

if (helper_rsa == NULL) {
helper_rsa = RSA_meth_dup(RSA_get_default_method());
if (helper_rsa == NULL)
return -1;
if (RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper") == 0 ||
RSA_meth_set_priv_enc(helper_rsa, pkcs11_rsa_private_encrypt) == 0) {
RSA_meth_free(helper_rsa);
helper_rsa = NULL;
return -1;
}
}
RSA_set_method(rsa, helper_rsa);
return (0);
}

@@ -67,7 +67,7 @@ struct pkcs11_key {
struct pkcs11_provider *provider;
CK_ULONG slotidx;
int (*orig_finish)(RSA *rsa);
RSA_METHOD rsa_method;
RSA_METHOD *rsa_method;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pkcs11_rsa_finish doesn't free this.

char *keyid;
int keyid_len;
};
@@ -182,6 +182,7 @@ pkcs11_rsa_finish(RSA *rsa)
rv = k11->orig_finish(rsa);
if (k11->provider)
pkcs11_provider_unref(k11->provider);
RSA_meth_free(k11->rsa_method);
free(k11->keyid);
free(k11);
}
@@ -326,13 +327,21 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
k11->keyid = xmalloc(k11->keyid_len);
memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
}
k11->orig_finish = def->finish;
memcpy(&k11->rsa_method, def, sizeof(k11->rsa_method));
k11->rsa_method.name = "pkcs11";
k11->rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt;
k11->rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt;
k11->rsa_method.finish = pkcs11_rsa_finish;
RSA_set_method(rsa, &k11->rsa_method);
k11->orig_finish = RSA_meth_get_finish(def);
if ((k11->rsa_method = RSA_meth_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);
}
@@ -512,10 +521,15 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
if ((rsa = RSA_new()) == NULL) {
error("RSA_new failed");
} else {
rsa->n = BN_bin2bn(attribs[1].pValue,
BIGNUM *rsa_n, *rsa_e;

rsa_n = BN_bin2bn(attribs[1].pValue,
attribs[1].ulValueLen, NULL);
rsa->e = BN_bin2bn(attribs[2].pValue,
rsa_e = BN_bin2bn(attribs[2].pValue,
attribs[2].ulValueLen, NULL);
if (rsa_n == NULL || rsa_e == NULL ||
RSA_set0_key(rsa, rsa_n, rsa_e, NULL) == 0)
error("RSA_set0_key failed");
}
} else {
cp = attribs[2].pValue;
@@ -525,35 +539,40 @@ pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
== NULL) {
error("d2i_X509 failed");
} else if ((evp = X509_get_pubkey(x509)) == NULL ||
evp->type != EVP_PKEY_RSA ||
evp->pkey.rsa == NULL) {
EVP_PKEY_id(evp) != EVP_PKEY_RSA ||
EVP_PKEY_get0_RSA(evp) == NULL) {
debug("X509_get_pubkey failed or no rsa");
} else if ((rsa = RSAPublicKey_dup(evp->pkey.rsa))
} else if ((rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(evp)))
== NULL) {
error("RSAPublicKey_dup");
}
if (x509)
X509_free(x509);
}
if (rsa && rsa->n && rsa->e &&
pkcs11_rsa_wrap(p, slotidx, &attribs[0], 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;
if (pkcs11_key_included(keysp, nkeys, key)) {
sshkey_free(key);
if (rsa) {
const BIGNUM *n, *e;

RSA_get0_key(rsa, &n, &e, NULL);
if (n && e &&
pkcs11_rsa_wrap(p, slotidx, &attribs[0], 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;
if (pkcs11_key_included(keysp, nkeys, key)) {
sshkey_free(key);
} else {
/* expand key array and add key */
*keysp = xrecallocarray(*keysp, *nkeys,
*nkeys + 1, sizeof(struct sshkey *));
(*keysp)[*nkeys] = key;
*nkeys = *nkeys + 1;
debug("have %d keys", *nkeys);
}
} else {
/* expand key array and add key */
*keysp = xrecallocarray(*keysp, *nkeys,
*nkeys + 1, sizeof(struct sshkey *));
(*keysp)[*nkeys] = key;
*nkeys = *nkeys + 1;
debug("have %d keys", *nkeys);
RSA_free(rsa);
}
} else if (rsa) {
RSA_free(rsa);
}
for (i = 0; i < 3; i++)
free(attribs[i].pValue);
@@ -78,12 +78,15 @@ rsa_hash_alg_nid(int type)
}
}

/* calculate p-1 and q-1 */
/* Fill in the CRT parameters, calculate d mod (p-1) and d mod (q-1) */
int
ssh_rsa_generate_additional_parameters(struct sshkey *key)
ssh_rsa_generate_additional_parameters(struct sshkey *key, BIGNUM *iqmp)
{
RSA *rsa;
BIGNUM *aux = NULL;
BIGNUM *dmp1 = NULL;
BIGNUM *dmq1 = NULL;
const BIGNUM *p, *q, *d;
BN_CTX *ctx = NULL;
int r;

@@ -93,19 +96,26 @@ ssh_rsa_generate_additional_parameters(struct sshkey *key)

if ((ctx = BN_CTX_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((aux = BN_new()) == NULL) {
if ((aux = BN_new()) == NULL ||
(dmp1 = BN_new()) == NULL ||
(dmq1 = BN_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
rsa = key->rsa;
RSA_get0_key(rsa, NULL, NULL, &d);
RSA_get0_factors(rsa, &p, &q);

if ((BN_sub(aux, rsa->q, BN_value_one()) == 0) ||
(BN_mod(rsa->dmq1, rsa->d, aux, ctx) == 0) ||
(BN_sub(aux, rsa->p, BN_value_one()) == 0) ||
(BN_mod(rsa->dmp1, rsa->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(rsa, dmp1, dmq1, iqmp) == 0)) {
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
dmp1 = NULL;
dmq1 = NULL;
r = 0;
out:
BN_clear_free(aux);
@@ -136,7 +146,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
if (key == NULL || key->rsa == NULL || hash_alg == -1 ||
sshkey_type_plain(key->type) != KEY_RSA)
return SSH_ERR_INVALID_ARGUMENT;
if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
return SSH_ERR_KEY_LENGTH;
slen = RSA_size(key->rsa);
if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM)
@@ -210,7 +220,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)
536 sshkey.c

Large diffs are not rendered by default.

@@ -197,7 +197,7 @@ int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
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);

#ifdef SSHKEY_INTERNAL
int ssh_rsa_sign(const struct sshkey *key,