version 1.81, 2015/01/13 19:31:40 |
version 1.82, 2015/01/19 19:52:16 |
|
|
#include "servconf.h" |
#include "servconf.h" |
#include "roaming.h" |
#include "roaming.h" |
|
|
|
#include "ssherr.h" |
|
|
/* Imports */ |
/* Imports */ |
extern int compat20; |
extern int compat20; |
extern z_stream incoming_stream; |
extern z_stream incoming_stream; |
|
|
return (verified); |
return (verified); |
} |
} |
|
|
/* Export key state after authentication */ |
|
Newkeys * |
|
mm_newkeys_from_blob(u_char *blob, int blen) |
|
{ |
|
Buffer b; |
|
u_int len; |
|
Newkeys *newkey = NULL; |
|
Enc *enc; |
|
Mac *mac; |
|
Comp *comp; |
|
|
|
debug3("%s: %p(%d)", __func__, blob, blen); |
|
#ifdef DEBUG_PK |
|
dump_base64(stderr, blob, blen); |
|
#endif |
|
buffer_init(&b); |
|
buffer_append(&b, blob, blen); |
|
|
|
newkey = xcalloc(1, sizeof(*newkey)); |
|
enc = &newkey->enc; |
|
mac = &newkey->mac; |
|
comp = &newkey->comp; |
|
|
|
/* Enc structure */ |
|
enc->name = buffer_get_string(&b, NULL); |
|
buffer_get(&b, &enc->cipher, sizeof(enc->cipher)); |
|
enc->enabled = buffer_get_int(&b); |
|
enc->block_size = buffer_get_int(&b); |
|
enc->key = buffer_get_string(&b, &enc->key_len); |
|
enc->iv = buffer_get_string(&b, &enc->iv_len); |
|
|
|
if (enc->name == NULL || cipher_by_name(enc->name) != enc->cipher) |
|
fatal("%s: bad cipher name %s or pointer %p", __func__, |
|
enc->name, enc->cipher); |
|
|
|
/* Mac structure */ |
|
if (cipher_authlen(enc->cipher) == 0) { |
|
mac->name = buffer_get_string(&b, NULL); |
|
if (mac->name == NULL || mac_setup(mac, mac->name) != 0) |
|
fatal("%s: can not setup mac %s", __func__, mac->name); |
|
mac->enabled = buffer_get_int(&b); |
|
mac->key = buffer_get_string(&b, &len); |
|
if (len > mac->key_len) |
|
fatal("%s: bad mac key length: %u > %d", __func__, len, |
|
mac->key_len); |
|
mac->key_len = len; |
|
} |
|
|
|
/* Comp structure */ |
|
comp->type = buffer_get_int(&b); |
|
comp->enabled = buffer_get_int(&b); |
|
comp->name = buffer_get_string(&b, NULL); |
|
|
|
len = buffer_len(&b); |
|
if (len != 0) |
|
error("newkeys_from_blob: remaining bytes in blob %u", len); |
|
buffer_free(&b); |
|
return (newkey); |
|
} |
|
|
|
int |
|
mm_newkeys_to_blob(int mode, u_char **blobp, u_int *lenp) |
|
{ |
|
Buffer b; |
|
int len; |
|
Enc *enc; |
|
Mac *mac; |
|
Comp *comp; |
|
Newkeys *newkey = (Newkeys *)packet_get_newkeys(mode); |
|
|
|
debug3("%s: converting %p", __func__, newkey); |
|
|
|
if (newkey == NULL) { |
|
error("%s: newkey == NULL", __func__); |
|
return 0; |
|
} |
|
enc = &newkey->enc; |
|
mac = &newkey->mac; |
|
comp = &newkey->comp; |
|
|
|
buffer_init(&b); |
|
/* Enc structure */ |
|
buffer_put_cstring(&b, enc->name); |
|
/* The cipher struct is constant and shared, you export pointer */ |
|
buffer_append(&b, &enc->cipher, sizeof(enc->cipher)); |
|
buffer_put_int(&b, enc->enabled); |
|
buffer_put_int(&b, enc->block_size); |
|
buffer_put_string(&b, enc->key, enc->key_len); |
|
packet_get_keyiv(mode, enc->iv, enc->iv_len); |
|
buffer_put_string(&b, enc->iv, enc->iv_len); |
|
|
|
/* Mac structure */ |
|
if (cipher_authlen(enc->cipher) == 0) { |
|
buffer_put_cstring(&b, mac->name); |
|
buffer_put_int(&b, mac->enabled); |
|
buffer_put_string(&b, mac->key, mac->key_len); |
|
} |
|
|
|
/* Comp structure */ |
|
buffer_put_int(&b, comp->type); |
|
buffer_put_int(&b, comp->enabled); |
|
buffer_put_cstring(&b, comp->name); |
|
|
|
len = buffer_len(&b); |
|
if (lenp != NULL) |
|
*lenp = len; |
|
if (blobp != NULL) { |
|
*blobp = xmalloc(len); |
|
memcpy(*blobp, buffer_ptr(&b), len); |
|
} |
|
explicit_bzero(buffer_ptr(&b), len); |
|
buffer_free(&b); |
|
return len; |
|
} |
|
|
|
static void |
|
mm_send_kex(Buffer *m, Kex *kex) |
|
{ |
|
buffer_put_string(m, kex->session_id, kex->session_id_len); |
|
buffer_put_int(m, kex->we_need); |
|
buffer_put_int(m, kex->hostkey_type); |
|
buffer_put_int(m, kex->kex_type); |
|
buffer_put_string(m, buffer_ptr(&kex->my), buffer_len(&kex->my)); |
|
buffer_put_string(m, buffer_ptr(&kex->peer), buffer_len(&kex->peer)); |
|
buffer_put_int(m, kex->flags); |
|
buffer_put_cstring(m, kex->client_version_string); |
|
buffer_put_cstring(m, kex->server_version_string); |
|
} |
|
|
|
void |
void |
mm_send_keystate(struct monitor *monitor) |
mm_send_keystate(struct monitor *monitor) |
{ |
{ |
Buffer m, *input, *output; |
struct ssh *ssh = active_state; /* XXX */ |
u_char *blob, *p; |
struct sshbuf *m; |
u_int bloblen, plen; |
int r; |
u_int32_t seqnr, packets; |
|
u_int64_t blocks, bytes; |
|
|
|
buffer_init(&m); |
if ((m = sshbuf_new()) == NULL) |
|
fatal("%s: sshbuf_new failed", __func__); |
if (!compat20) { |
if ((r = ssh_packet_get_state(ssh, m)) != 0) |
u_char iv[24]; |
fatal("%s: get_state failed: %s", |
u_char *key; |
__func__, ssh_err(r)); |
u_int ivlen, keylen; |
mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, m); |
|
|
buffer_put_int(&m, packet_get_protocol_flags()); |
|
|
|
buffer_put_int(&m, packet_get_ssh1_cipher()); |
|
|
|
debug3("%s: Sending ssh1 KEY+IV", __func__); |
|
keylen = packet_get_encryption_key(NULL); |
|
key = xmalloc(keylen+1); /* add 1 if keylen == 0 */ |
|
keylen = packet_get_encryption_key(key); |
|
buffer_put_string(&m, key, keylen); |
|
explicit_bzero(key, keylen); |
|
free(key); |
|
|
|
ivlen = packet_get_keyiv_len(MODE_OUT); |
|
packet_get_keyiv(MODE_OUT, iv, ivlen); |
|
buffer_put_string(&m, iv, ivlen); |
|
ivlen = packet_get_keyiv_len(MODE_IN); |
|
packet_get_keyiv(MODE_IN, iv, ivlen); |
|
buffer_put_string(&m, iv, ivlen); |
|
goto skip; |
|
} else { |
|
/* Kex for rekeying */ |
|
mm_send_kex(&m, *monitor->m_pkex); |
|
} |
|
|
|
debug3("%s: Sending new keys: %p %p", |
|
__func__, packet_get_newkeys(MODE_OUT), |
|
packet_get_newkeys(MODE_IN)); |
|
|
|
/* Keys from Kex */ |
|
if (!mm_newkeys_to_blob(MODE_OUT, &blob, &bloblen)) |
|
fatal("%s: conversion of newkeys failed", __func__); |
|
|
|
buffer_put_string(&m, blob, bloblen); |
|
free(blob); |
|
|
|
if (!mm_newkeys_to_blob(MODE_IN, &blob, &bloblen)) |
|
fatal("%s: conversion of newkeys failed", __func__); |
|
|
|
buffer_put_string(&m, blob, bloblen); |
|
free(blob); |
|
|
|
packet_get_state(MODE_OUT, &seqnr, &blocks, &packets, &bytes); |
|
buffer_put_int(&m, seqnr); |
|
buffer_put_int64(&m, blocks); |
|
buffer_put_int(&m, packets); |
|
buffer_put_int64(&m, bytes); |
|
packet_get_state(MODE_IN, &seqnr, &blocks, &packets, &bytes); |
|
buffer_put_int(&m, seqnr); |
|
buffer_put_int64(&m, blocks); |
|
buffer_put_int(&m, packets); |
|
buffer_put_int64(&m, bytes); |
|
|
|
debug3("%s: New keys have been sent", __func__); |
|
skip: |
|
/* More key context */ |
|
plen = packet_get_keycontext(MODE_OUT, NULL); |
|
p = xmalloc(plen+1); |
|
packet_get_keycontext(MODE_OUT, p); |
|
buffer_put_string(&m, p, plen); |
|
free(p); |
|
|
|
plen = packet_get_keycontext(MODE_IN, NULL); |
|
p = xmalloc(plen+1); |
|
packet_get_keycontext(MODE_IN, p); |
|
buffer_put_string(&m, p, plen); |
|
free(p); |
|
|
|
/* Compression state */ |
|
debug3("%s: Sending compression state", __func__); |
|
buffer_put_string(&m, &outgoing_stream, sizeof(outgoing_stream)); |
|
buffer_put_string(&m, &incoming_stream, sizeof(incoming_stream)); |
|
|
|
/* Network I/O buffers */ |
|
input = (Buffer *)packet_get_input(); |
|
output = (Buffer *)packet_get_output(); |
|
buffer_put_string(&m, buffer_ptr(input), buffer_len(input)); |
|
buffer_put_string(&m, buffer_ptr(output), buffer_len(output)); |
|
|
|
/* Roaming */ |
|
if (compat20) { |
|
buffer_put_int64(&m, get_sent_bytes()); |
|
buffer_put_int64(&m, get_recv_bytes()); |
|
} |
|
|
|
mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, &m); |
|
debug3("%s: Finished sending state", __func__); |
debug3("%s: Finished sending state", __func__); |
|
sshbuf_free(m); |
buffer_free(&m); |
|
} |
} |
|
|
int |
int |