version 1.143, 2015/02/13 18:57:00 |
version 1.144, 2015/02/16 22:13:32 |
|
|
int |
int |
mm_answer_sign(int sock, Buffer *m) |
mm_answer_sign(int sock, Buffer *m) |
{ |
{ |
|
struct ssh *ssh = active_state; /* XXX */ |
extern int auth_sock; /* XXX move to state struct? */ |
extern int auth_sock; /* XXX move to state struct? */ |
struct sshkey *key; |
struct sshkey *key; |
|
struct sshbuf *sigbuf; |
u_char *p; |
u_char *p; |
u_char *signature; |
u_char *signature; |
size_t datlen, siglen; |
size_t datlen, siglen; |
int r, keyid; |
int r, keyid, is_proof = 0; |
|
const char proof_req[] = "hostkeys-prove@openssh.com"; |
|
|
debug3("%s", __func__); |
debug3("%s", __func__); |
|
|
|
|
/* |
/* |
* Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), |
* Supported KEX types use SHA1 (20 bytes), SHA256 (32 bytes), |
* SHA384 (48 bytes) and SHA512 (64 bytes). |
* SHA384 (48 bytes) and SHA512 (64 bytes). |
|
* |
|
* Otherwise, verify the signature request is for a hostkey |
|
* proof. |
|
* |
|
* XXX perform similar check for KEX signature requests too? |
|
* it's not trivial, since what is signed is the hash, rather |
|
* than the full kex structure... |
*/ |
*/ |
if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) |
if (datlen != 20 && datlen != 32 && datlen != 48 && datlen != 64) { |
fatal("%s: data length incorrect: %zu", __func__, datlen); |
/* |
|
* Construct expected hostkey proof and compare it to what |
|
* the client sent us. |
|
*/ |
|
if (session_id2_len == 0) /* hostkeys is never first */ |
|
fatal("%s: bad data length: %zu", __func__, datlen); |
|
if ((key = get_hostkey_public_by_index(keyid, ssh)) == NULL) |
|
fatal("%s: no hostkey for index %d", __func__, keyid); |
|
if ((sigbuf = sshbuf_new()) == NULL) |
|
fatal("%s: sshbuf_new", __func__); |
|
if ((r = sshbuf_put_string(sigbuf, session_id2, |
|
session_id2_len) != 0) || |
|
(r = sshbuf_put_cstring(sigbuf, proof_req)) != 0 || |
|
(r = sshkey_puts(key, sigbuf)) != 0) |
|
fatal("%s: couldn't prepare private key " |
|
"proof buffer: %s", __func__, ssh_err(r)); |
|
if (datlen != sshbuf_len(sigbuf) || |
|
memcmp(p, sshbuf_ptr(sigbuf), sshbuf_len(sigbuf)) != 0) |
|
fatal("%s: bad data length: %zu, hostkey proof len %zu", |
|
__func__, datlen, sshbuf_len(sigbuf)); |
|
sshbuf_free(sigbuf); |
|
is_proof = 1; |
|
} |
|
|
/* save session id, it will be passed on the first call */ |
/* save session id, it will be passed on the first call */ |
if (session_id2_len == 0) { |
if (session_id2_len == 0) { |
|
|
datafellows)) != 0) |
datafellows)) != 0) |
fatal("%s: sshkey_sign failed: %s", |
fatal("%s: sshkey_sign failed: %s", |
__func__, ssh_err(r)); |
__func__, ssh_err(r)); |
} else if ((key = get_hostkey_public_by_index(keyid, active_state)) != NULL && |
} else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && |
auth_sock > 0) { |
auth_sock > 0) { |
if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, |
if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, |
p, datlen, datafellows)) != 0) { |
p, datlen, datafellows)) != 0) { |
|
|
} else |
} else |
fatal("%s: no hostkey from index %d", __func__, keyid); |
fatal("%s: no hostkey from index %d", __func__, keyid); |
|
|
debug3("%s: signature %p(%zu)", __func__, signature, siglen); |
debug3("%s: %s signature %p(%zu)", __func__, |
|
is_proof ? "KEX" : "hostkey proof", signature, siglen); |
|
|
sshbuf_reset(m); |
sshbuf_reset(m); |
if ((r = sshbuf_put_string(m, signature, siglen)) != 0) |
if ((r = sshbuf_put_string(m, signature, siglen)) != 0) |