aboutsummaryrefslogtreecommitdiff
path: root/kex.c
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2014-01-30 10:56:49 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2014-01-30 10:56:49 +0000
commit02d4c2ac3daa0f36264392972709ccd7676ab3e8 (patch)
tree6c519c109631364b652faced88b665da4b6058ae /kex.c
parentff96c0c81d9ee141236b95d52ad0578684d59ab5 (diff)
downloadsrc-02d4c2ac3daa0f36264392972709ccd7676ab3e8.tar.gz
src-02d4c2ac3daa0f36264392972709ccd7676ab3e8.zip
Vendor import of OpenSSH 6.5p1.vendor/openssh/6.5p1
Notes
Notes: svn path=/vendor-crypto/openssh/dist/; revision=261287 svn path=/vendor-crypto/openssh/6.5p1/; revision=261288; tag=vendor/openssh/6.5p1
Diffstat (limited to 'kex.c')
-rw-r--r--kex.c143
1 files changed, 87 insertions, 56 deletions
diff --git a/kex.c b/kex.c
index 54bd1a438192..616484b85d22 100644
--- a/kex.c
+++ b/kex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.91 2013/05/17 00:13:13 djm Exp $ */
+/* $OpenBSD: kex.c,v 1.97 2014/01/25 20:35:37 markus Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
@@ -49,6 +49,7 @@
#include "dispatch.h"
#include "monitor.h"
#include "roaming.h"
+#include "digest.h"
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
# if defined(HAVE_EVP_SHA256)
@@ -66,25 +67,34 @@ struct kexalg {
char *name;
int type;
int ec_nid;
- const EVP_MD *(*mdfunc)(void);
+ int hash_alg;
};
static const struct kexalg kexalgs[] = {
- { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 },
- { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 },
- { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 },
+ { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },
+ { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },
#ifdef HAVE_EVP_SHA256
- { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 },
+ { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
#endif
#ifdef OPENSSL_HAS_ECC
- { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 },
- { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 },
- { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 },
+ { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,
+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },
+ { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,
+ SSH_DIGEST_SHA384 },
+# ifdef OPENSSL_HAS_NISTP521
+ { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
+ SSH_DIGEST_SHA512 },
+# endif
+#endif
+ { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },
+#ifdef HAVE_EVP_SHA256
+ { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
#endif
- { NULL, -1, -1, NULL},
+ { NULL, -1, -1, -1},
};
char *
-kex_alg_list(void)
+kex_alg_list(char sep)
{
char *ret = NULL;
size_t nlen, rlen = 0;
@@ -92,7 +102,7 @@ kex_alg_list(void)
for (k = kexalgs; k->name != NULL; k++) {
if (ret != NULL)
- ret[rlen++] = '\n';
+ ret[rlen++] = sep;
nlen = strlen(k->name);
ret = xrealloc(ret, 1, rlen + nlen + 2);
memcpy(ret + rlen, k->name, nlen + 1);
@@ -401,7 +411,7 @@ choose_kex(Kex *k, char *client, char *server)
if ((kexalg = kex_alg_by_name(k->name)) == NULL)
fatal("unsupported kex alg %s", k->name);
k->kex_type = kexalg->type;
- k->evp_md = kexalg->mdfunc();
+ k->hash_alg = kexalg->hash_alg;
k->ec_nid = kexalg->ec_nid;
}
@@ -448,7 +458,7 @@ kex_choose_conf(Kex *kex)
char **my, **peer;
char **cprop, **sprop;
int nenc, nmac, ncomp;
- u_int mode, ctos, need, authlen;
+ u_int mode, ctos, need, dh_need, authlen;
int first_kex_follows, type;
my = kex_buf2prop(&kex->my, NULL);
@@ -496,20 +506,21 @@ kex_choose_conf(Kex *kex)
choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
- need = 0;
+ need = dh_need = 0;
for (mode = 0; mode < MODE_MAX; mode++) {
newkeys = kex->newkeys[mode];
- if (need < newkeys->enc.key_len)
- need = newkeys->enc.key_len;
- if (need < newkeys->enc.block_size)
- need = newkeys->enc.block_size;
- if (need < newkeys->enc.iv_len)
- need = newkeys->enc.iv_len;
- if (need < newkeys->mac.key_len)
- need = newkeys->mac.key_len;
+ need = MAX(need, newkeys->enc.key_len);
+ need = MAX(need, newkeys->enc.block_size);
+ need = MAX(need, newkeys->enc.iv_len);
+ need = MAX(need, newkeys->mac.key_len);
+ dh_need = MAX(dh_need, cipher_seclen(newkeys->enc.cipher));
+ dh_need = MAX(dh_need, newkeys->enc.block_size);
+ dh_need = MAX(dh_need, newkeys->enc.iv_len);
+ dh_need = MAX(dh_need, newkeys->mac.key_len);
}
/* XXX need runden? */
kex->we_need = need;
+ kex->dh_need = dh_need;
/* ignore the next message if the proposals do not match */
if (first_kex_follows && !proposals_match(my, peer) &&
@@ -524,30 +535,34 @@ kex_choose_conf(Kex *kex)
static u_char *
derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen,
- BIGNUM *shared_secret)
+ const u_char *shared_secret, u_int slen)
{
Buffer b;
- EVP_MD_CTX md;
+ struct ssh_digest_ctx *hashctx;
char c = id;
u_int have;
- int mdsz;
+ size_t mdsz;
u_char *digest;
- if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0)
- fatal("bad kex md size %d", mdsz);
+ if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0)
+ fatal("bad kex md size %zu", mdsz);
digest = xmalloc(roundup(need, mdsz));
buffer_init(&b);
- buffer_put_bignum2(&b, shared_secret);
+ buffer_append(&b, shared_secret, slen);
/* K1 = HASH(K || H || "A" || session_id) */
- EVP_DigestInit(&md, kex->evp_md);
- if (!(datafellows & SSH_BUG_DERIVEKEY))
- EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
- EVP_DigestUpdate(&md, hash, hashlen);
- EVP_DigestUpdate(&md, &c, 1);
- EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len);
- EVP_DigestFinal(&md, digest, NULL);
+ if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL)
+ fatal("%s: ssh_digest_start failed", __func__);
+ if (ssh_digest_update_buffer(hashctx, &b) != 0 ||
+ ssh_digest_update(hashctx, hash, hashlen) != 0 ||
+ ssh_digest_update(hashctx, &c, 1) != 0 ||
+ ssh_digest_update(hashctx, kex->session_id,
+ kex->session_id_len) != 0)
+ fatal("%s: ssh_digest_update failed", __func__);
+ if (ssh_digest_final(hashctx, digest, mdsz) != 0)
+ fatal("%s: ssh_digest_final failed", __func__);
+ ssh_digest_free(hashctx);
/*
* expand key:
@@ -555,12 +570,15 @@ derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen,
* Key = K1 || K2 || ... || Kn
*/
for (have = mdsz; need > have; have += mdsz) {
- EVP_DigestInit(&md, kex->evp_md);
- if (!(datafellows & SSH_BUG_DERIVEKEY))
- EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
- EVP_DigestUpdate(&md, hash, hashlen);
- EVP_DigestUpdate(&md, digest, have);
- EVP_DigestFinal(&md, digest + have, NULL);
+ if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL)
+ fatal("%s: ssh_digest_start failed", __func__);
+ if (ssh_digest_update_buffer(hashctx, &b) != 0 ||
+ ssh_digest_update(hashctx, hash, hashlen) != 0 ||
+ ssh_digest_update(hashctx, digest, have) != 0)
+ fatal("%s: ssh_digest_update failed", __func__);
+ if (ssh_digest_final(hashctx, digest + have, mdsz) != 0)
+ fatal("%s: ssh_digest_final failed", __func__);
+ ssh_digest_free(hashctx);
}
buffer_free(&b);
#ifdef DEBUG_KEX
@@ -574,14 +592,15 @@ Newkeys *current_keys[MODE_MAX];
#define NKEYS 6
void
-kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret)
+kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen,
+ const u_char *shared_secret, u_int slen)
{
u_char *keys[NKEYS];
u_int i, mode, ctos;
for (i = 0; i < NKEYS; i++) {
keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen,
- shared_secret);
+ shared_secret, slen);
}
debug2("kex_derive_keys");
@@ -596,6 +615,18 @@ kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, BIGNUM *shared_secret)
}
}
+void
+kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret)
+{
+ Buffer shared_secret;
+
+ buffer_init(&shared_secret);
+ buffer_put_bignum2(&shared_secret, secret);
+ kex_derive_keys(kex, hash, hashlen,
+ buffer_ptr(&shared_secret), buffer_len(&shared_secret));
+ buffer_free(&shared_secret);
+}
+
Newkeys *
kex_get_newkeys(int mode)
{
@@ -610,33 +641,33 @@ void
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus,
u_int8_t cookie[8], u_int8_t id[16])
{
- const EVP_MD *evp_md = EVP_md5();
- EVP_MD_CTX md;
- u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE];
+ u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH];
int len;
+ struct ssh_digest_ctx *hashctx;
- EVP_DigestInit(&md, evp_md);
+ if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL)
+ fatal("%s: ssh_digest_start", __func__);
len = BN_num_bytes(host_modulus);
if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
fatal("%s: bad host modulus (len %d)", __func__, len);
BN_bn2bin(host_modulus, nbuf);
- EVP_DigestUpdate(&md, nbuf, len);
+ if (ssh_digest_update(hashctx, nbuf, len) != 0)
+ fatal("%s: ssh_digest_update failed", __func__);
len = BN_num_bytes(server_modulus);
if (len < (512 / 8) || (u_int)len > sizeof(nbuf))
fatal("%s: bad server modulus (len %d)", __func__, len);
BN_bn2bin(server_modulus, nbuf);
- EVP_DigestUpdate(&md, nbuf, len);
-
- EVP_DigestUpdate(&md, cookie, 8);
-
- EVP_DigestFinal(&md, obuf, NULL);
- memcpy(id, obuf, 16);
+ if (ssh_digest_update(hashctx, nbuf, len) != 0 ||
+ ssh_digest_update(hashctx, cookie, 8) != 0)
+ fatal("%s: ssh_digest_update failed", __func__);
+ if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0)
+ fatal("%s: ssh_digest_final failed", __func__);
+ memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5));
memset(nbuf, 0, sizeof(nbuf));
memset(obuf, 0, sizeof(obuf));
- memset(&md, 0, sizeof(md));
}
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH)