version 1.93, 2013/11/07 11:58:27 |
version 1.94, 2014/01/09 23:20:00 |
|
|
#include "dispatch.h" |
#include "dispatch.h" |
#include "monitor.h" |
#include "monitor.h" |
#include "roaming.h" |
#include "roaming.h" |
|
#include "digest.h" |
|
|
/* prototype */ |
/* prototype */ |
static void kex_kexinit_finish(Kex *); |
static void kex_kexinit_finish(Kex *); |
|
|
char *name; |
char *name; |
int type; |
int type; |
int ec_nid; |
int ec_nid; |
const EVP_MD *(*mdfunc)(void); |
int hash_alg; |
}; |
}; |
static const struct kexalg kexalgs[] = { |
static const struct kexalg kexalgs[] = { |
{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 }, |
{ KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, |
{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 }, |
{ KEX_DH14, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, |
{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 }, |
{ KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, |
{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 }, |
{ KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, |
{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 }, |
{ KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, |
{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 }, |
NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, |
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 }, |
{ KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, |
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, EVP_sha256 }, |
SSH_DIGEST_SHA384 }, |
{ NULL, -1, -1, NULL}, |
{ KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, |
|
SSH_DIGEST_SHA512 }, |
|
{ KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, |
|
{ NULL, -1, -1, -1}, |
}; |
}; |
|
|
char * |
char * |
|
|
if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
fatal("unsupported kex alg %s", k->name); |
fatal("unsupported kex alg %s", k->name); |
k->kex_type = kexalg->type; |
k->kex_type = kexalg->type; |
k->evp_md = kexalg->mdfunc(); |
k->hash_alg = kexalg->hash_alg; |
k->ec_nid = kexalg->ec_nid; |
k->ec_nid = kexalg->ec_nid; |
} |
} |
|
|
|
|
BIGNUM *shared_secret) |
BIGNUM *shared_secret) |
{ |
{ |
Buffer b; |
Buffer b; |
EVP_MD_CTX md; |
struct ssh_digest_ctx *hashctx; |
char c = id; |
char c = id; |
u_int have; |
u_int have; |
int mdsz; |
size_t mdsz; |
u_char *digest; |
u_char *digest; |
|
|
if ((mdsz = EVP_MD_size(kex->evp_md)) <= 0) |
if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) |
fatal("bad kex md size %d", mdsz); |
fatal("bad kex md size %zu", mdsz); |
digest = xmalloc(roundup(need, mdsz)); |
digest = xmalloc(roundup(need, mdsz)); |
|
|
buffer_init(&b); |
buffer_init(&b); |
buffer_put_bignum2(&b, shared_secret); |
buffer_put_bignum2(&b, shared_secret); |
|
|
/* K1 = HASH(K || H || "A" || session_id) */ |
/* K1 = HASH(K || H || "A" || session_id) */ |
EVP_DigestInit(&md, kex->evp_md); |
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) |
if (!(datafellows & SSH_BUG_DERIVEKEY)) |
fatal("%s: ssh_digest_start failed", __func__); |
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); |
if (ssh_digest_update_buffer(hashctx, &b) != 0 || |
EVP_DigestUpdate(&md, hash, hashlen); |
ssh_digest_update(hashctx, hash, hashlen) != 0 || |
EVP_DigestUpdate(&md, &c, 1); |
ssh_digest_update(hashctx, &c, 1) != 0 || |
EVP_DigestUpdate(&md, kex->session_id, kex->session_id_len); |
ssh_digest_update(hashctx, kex->session_id, |
EVP_DigestFinal(&md, digest, NULL); |
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: |
* expand key: |
|
|
* Key = K1 || K2 || ... || Kn |
* Key = K1 || K2 || ... || Kn |
*/ |
*/ |
for (have = mdsz; need > have; have += mdsz) { |
for (have = mdsz; need > have; have += mdsz) { |
EVP_DigestInit(&md, kex->evp_md); |
if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) |
if (!(datafellows & SSH_BUG_DERIVEKEY)) |
fatal("%s: ssh_digest_start failed", __func__); |
EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); |
if (ssh_digest_update_buffer(hashctx, &b) != 0 || |
EVP_DigestUpdate(&md, hash, hashlen); |
ssh_digest_update(hashctx, hash, hashlen) != 0 || |
EVP_DigestUpdate(&md, digest, have); |
ssh_digest_update(hashctx, digest, have) != 0) |
EVP_DigestFinal(&md, digest + have, NULL); |
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); |
buffer_free(&b); |
#ifdef DEBUG_KEX |
#ifdef DEBUG_KEX |
|
|
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, |
derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, |
u_int8_t cookie[8], u_int8_t id[16]) |
u_int8_t cookie[8], u_int8_t id[16]) |
{ |
{ |
const EVP_MD *evp_md = EVP_md5(); |
u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; |
EVP_MD_CTX md; |
|
u_int8_t nbuf[2048], obuf[EVP_MAX_MD_SIZE]; |
|
int len; |
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); |
len = BN_num_bytes(host_modulus); |
if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) |
if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) |
fatal("%s: bad host modulus (len %d)", __func__, len); |
fatal("%s: bad host modulus (len %d)", __func__, len); |
BN_bn2bin(host_modulus, nbuf); |
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); |
len = BN_num_bytes(server_modulus); |
if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) |
if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) |
fatal("%s: bad server modulus (len %d)", __func__, len); |
fatal("%s: bad server modulus (len %d)", __func__, len); |
BN_bn2bin(server_modulus, nbuf); |
BN_bn2bin(server_modulus, nbuf); |
EVP_DigestUpdate(&md, nbuf, len); |
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)); |
|
|
EVP_DigestUpdate(&md, cookie, 8); |
|
|
|
EVP_DigestFinal(&md, obuf, NULL); |
|
memcpy(id, obuf, 16); |
|
|
|
memset(nbuf, 0, sizeof(nbuf)); |
memset(nbuf, 0, sizeof(nbuf)); |
memset(obuf, 0, sizeof(obuf)); |
memset(obuf, 0, sizeof(obuf)); |
memset(&md, 0, sizeof(md)); |
|
} |
} |
|
|
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) |
#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) |