зеркало из https://github.com/github/putty.git
Remove arbitrary limit SSH2_MKKEY_ITERS.
Tim Kosse points out that we now support some combinations of crypto primitives which break the hardwired assumption that two blocks of hash output from the session-key derivation algorithm are sufficient to key every cipher and MAC in the system. So now ssh2_mkkey is given the desired key length, and performs as many iterations as necessary.
This commit is contained in:
Родитель
42cf086b6b
Коммит
e460f30831
125
ssh.c
125
ssh.c
|
@ -6127,16 +6127,24 @@ static void ssh2_pkt_addstring_commasep(struct Packet *pkt, const char *data)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SSH-2 key creation method.
|
* SSH-2 key derivation (RFC 4253 section 7.2).
|
||||||
* (Currently assumes 2 lots of any hash are sufficient to generate
|
|
||||||
* keys/IVs for any cipher/MAC. SSH2_MKKEY_ITERS documents this assumption.)
|
|
||||||
*/
|
*/
|
||||||
#define SSH2_MKKEY_ITERS (2)
|
static unsigned char *ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H,
|
||||||
static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, char chr,
|
char chr, int keylen)
|
||||||
unsigned char *keyspace)
|
|
||||||
{
|
{
|
||||||
const struct ssh_hash *h = ssh->kex->hash;
|
const struct ssh_hash *h = ssh->kex->hash;
|
||||||
void *s;
|
int keylen_padded;
|
||||||
|
unsigned char *key;
|
||||||
|
void *s, *s2;
|
||||||
|
|
||||||
|
if (keylen == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Round up to the next multiple of hash length. */
|
||||||
|
keylen_padded = ((keylen + h->hlen - 1) / h->hlen) * h->hlen;
|
||||||
|
|
||||||
|
key = snewn(keylen_padded, unsigned char);
|
||||||
|
|
||||||
/* First hlen bytes. */
|
/* First hlen bytes. */
|
||||||
s = h->init();
|
s = h->init();
|
||||||
if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))
|
if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))
|
||||||
|
@ -6144,14 +6152,33 @@ static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H, char chr,
|
||||||
h->bytes(s, H, h->hlen);
|
h->bytes(s, H, h->hlen);
|
||||||
h->bytes(s, &chr, 1);
|
h->bytes(s, &chr, 1);
|
||||||
h->bytes(s, ssh->v2_session_id, ssh->v2_session_id_len);
|
h->bytes(s, ssh->v2_session_id, ssh->v2_session_id_len);
|
||||||
h->final(s, keyspace);
|
h->final(s, key);
|
||||||
/* Next hlen bytes. */
|
|
||||||
s = h->init();
|
/* Subsequent blocks of hlen bytes. */
|
||||||
if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))
|
if (keylen_padded > h->hlen) {
|
||||||
hash_mpint(h, s, K);
|
int offset;
|
||||||
h->bytes(s, H, h->hlen);
|
|
||||||
h->bytes(s, keyspace, h->hlen);
|
s = h->init();
|
||||||
h->final(s, keyspace + h->hlen);
|
if (!(ssh->remote_bugs & BUG_SSH2_DERIVEKEY))
|
||||||
|
hash_mpint(h, s, K);
|
||||||
|
h->bytes(s, H, h->hlen);
|
||||||
|
|
||||||
|
for (offset = h->hlen; offset < keylen_padded; offset += h->hlen) {
|
||||||
|
h->bytes(s, key + offset - h->hlen, h->hlen);
|
||||||
|
s2 = h->copy(s);
|
||||||
|
h->final(s2, key + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
h->free(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now clear any extra bytes of key material beyond the length
|
||||||
|
* we're officially returning, because the caller won't know to
|
||||||
|
* smemclr those. */
|
||||||
|
if (keylen_padded > keylen)
|
||||||
|
smemclr(key + keylen, keylen_padded - keylen);
|
||||||
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7153,21 +7180,25 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
|
||||||
* hash from the _first_ key exchange.
|
* hash from the _first_ key exchange.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];
|
unsigned char *key;
|
||||||
assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
|
||||||
ssh2_mkkey(ssh,s->K,s->exchange_hash,'C',keyspace);
|
key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'C',
|
||||||
assert((ssh->cscipher->keylen+7) / 8 <=
|
(ssh->cscipher->keylen+7) / 8);
|
||||||
ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
ssh->cscipher->setkey(ssh->cs_cipher_ctx, key);
|
||||||
ssh->cscipher->setkey(ssh->cs_cipher_ctx, keyspace);
|
smemclr(key, (ssh->cscipher->keylen+7) / 8);
|
||||||
ssh2_mkkey(ssh,s->K,s->exchange_hash,'A',keyspace);
|
sfree(key);
|
||||||
assert(ssh->cscipher->blksize <=
|
|
||||||
ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'A',
|
||||||
ssh->cscipher->setiv(ssh->cs_cipher_ctx, keyspace);
|
ssh->cscipher->blksize);
|
||||||
ssh2_mkkey(ssh,s->K,s->exchange_hash,'E',keyspace);
|
ssh->cscipher->setiv(ssh->cs_cipher_ctx, key);
|
||||||
assert(ssh->csmac->keylen <=
|
smemclr(key, ssh->cscipher->blksize);
|
||||||
ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
sfree(key);
|
||||||
ssh->csmac->setkey(ssh->cs_mac_ctx, keyspace);
|
|
||||||
smemclr(keyspace, sizeof(keyspace));
|
key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'E',
|
||||||
|
ssh->csmac->keylen);
|
||||||
|
ssh->csmac->setkey(ssh->cs_mac_ctx, key);
|
||||||
|
smemclr(key, ssh->csmac->keylen);
|
||||||
|
sfree(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
logeventf(ssh, "Initialised %.200s client->server encryption",
|
logeventf(ssh, "Initialised %.200s client->server encryption",
|
||||||
|
@ -7222,21 +7253,25 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
|
||||||
* hash from the _first_ key exchange.
|
* hash from the _first_ key exchange.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
unsigned char keyspace[SSH2_KEX_MAX_HASH_LEN * SSH2_MKKEY_ITERS];
|
unsigned char *key;
|
||||||
assert(sizeof(keyspace) >= ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
|
||||||
ssh2_mkkey(ssh,s->K,s->exchange_hash,'D',keyspace);
|
key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'D',
|
||||||
assert((ssh->sccipher->keylen+7) / 8 <=
|
(ssh->sccipher->keylen + 7) / 8);
|
||||||
ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
ssh->sccipher->setkey(ssh->sc_cipher_ctx, key);
|
||||||
ssh->sccipher->setkey(ssh->sc_cipher_ctx, keyspace);
|
smemclr(key, (ssh->sccipher->keylen + 7) / 8);
|
||||||
ssh2_mkkey(ssh,s->K,s->exchange_hash,'B',keyspace);
|
sfree(key);
|
||||||
assert(ssh->sccipher->blksize <=
|
|
||||||
ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'B',
|
||||||
ssh->sccipher->setiv(ssh->sc_cipher_ctx, keyspace);
|
ssh->sccipher->blksize);
|
||||||
ssh2_mkkey(ssh,s->K,s->exchange_hash,'F',keyspace);
|
ssh->sccipher->setiv(ssh->sc_cipher_ctx, key);
|
||||||
assert(ssh->scmac->keylen <=
|
smemclr(key, ssh->sccipher->blksize);
|
||||||
ssh->kex->hash->hlen * SSH2_MKKEY_ITERS);
|
sfree(key);
|
||||||
ssh->scmac->setkey(ssh->sc_mac_ctx, keyspace);
|
|
||||||
smemclr(keyspace, sizeof(keyspace));
|
key = ssh2_mkkey(ssh, s->K, s->exchange_hash, 'F',
|
||||||
|
ssh->scmac->keylen);
|
||||||
|
ssh->scmac->setkey(ssh->sc_mac_ctx, key);
|
||||||
|
smemclr(key, ssh->scmac->keylen);
|
||||||
|
sfree(key);
|
||||||
}
|
}
|
||||||
logeventf(ssh, "Initialised %.200s server->client encryption",
|
logeventf(ssh, "Initialised %.200s server->client encryption",
|
||||||
ssh->sccipher->text_name);
|
ssh->sccipher->text_name);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче