version 1.257, 2020/03/06 18:28:27 |
version 1.258, 2020/05/26 01:26:58 |
|
|
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "ssh.h" |
#include "ssh.h" |
|
#include "ssh2.h" |
#include "sshbuf.h" |
#include "sshbuf.h" |
#include "sshkey.h" |
#include "sshkey.h" |
#include "authfd.h" |
#include "authfd.h" |
|
|
|
|
static int fingerprint_hash = SSH_FP_HASH_DEFAULT; |
static int fingerprint_hash = SSH_FP_HASH_DEFAULT; |
|
|
|
/* Refuse signing of non-SSH messages for web-origin FIDO keys */ |
|
static int restrict_websafe = 1; |
|
|
static void |
static void |
close_socket(SocketEntry *e) |
close_socket(SocketEntry *e) |
{ |
{ |
|
|
return NULL; |
return NULL; |
} |
} |
|
|
|
/* |
|
* This function inspects a message to be signed by a FIDO key that has a |
|
* web-like application string (i.e. one that does not begin with "ssh:". |
|
* It checks that the message is one of those expected for SSH operations |
|
* (pubkey userauth, sshsig, CA key signing) to exclude signing challenges |
|
* for the web. |
|
*/ |
|
static int |
|
check_websafe_message_contents(struct sshkey *key, |
|
const u_char *msg, size_t len) |
|
{ |
|
int matched = 0; |
|
struct sshbuf *b; |
|
u_char m, n; |
|
char *cp1 = NULL, *cp2 = NULL; |
|
int r; |
|
struct sshkey *mkey = NULL; |
|
|
|
if ((b = sshbuf_from(msg, len)) == NULL) |
|
fatal("%s: sshbuf_new", __func__); |
|
|
|
/* SSH userauth request */ |
|
if ((r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* sess_id */ |
|
(r = sshbuf_get_u8(b, &m)) == 0 && /* SSH2_MSG_USERAUTH_REQUEST */ |
|
(r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* server user */ |
|
(r = sshbuf_get_cstring(b, &cp1, NULL)) == 0 && /* service */ |
|
(r = sshbuf_get_cstring(b, &cp2, NULL)) == 0 && /* method */ |
|
(r = sshbuf_get_u8(b, &n)) == 0 && /* sig-follows */ |
|
(r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* alg */ |
|
(r = sshkey_froms(b, &mkey)) == 0 && /* key */ |
|
sshbuf_len(b) == 0) { |
|
debug("%s: parsed userauth", __func__); |
|
if (m == SSH2_MSG_USERAUTH_REQUEST && n == 1 && |
|
strcmp(cp1, "ssh-connection") == 0 && |
|
strcmp(cp2, "publickey") == 0 && |
|
sshkey_equal(key, mkey)) { |
|
debug("%s: well formed userauth", __func__); |
|
matched = 1; |
|
} |
|
} |
|
free(cp1); |
|
free(cp2); |
|
sshkey_free(mkey); |
|
sshbuf_free(b); |
|
if (matched) |
|
return 1; |
|
|
|
if ((b = sshbuf_from(msg, len)) == NULL) |
|
fatal("%s: sshbuf_new", __func__); |
|
cp1 = cp2 = NULL; |
|
mkey = NULL; |
|
|
|
/* SSHSIG */ |
|
if ((r = sshbuf_cmp(b, 0, "SSHSIG", 6)) == 0 && |
|
(r = sshbuf_consume(b, 6)) == 0 && |
|
(r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* namespace */ |
|
(r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* reserved */ |
|
(r = sshbuf_get_cstring(b, NULL, NULL)) == 0 && /* hashalg */ |
|
(r = sshbuf_get_string_direct(b, NULL, NULL)) == 0 && /* H(msg) */ |
|
sshbuf_len(b) == 0) { |
|
debug("%s: parsed sshsig", __func__); |
|
matched = 1; |
|
} |
|
|
|
sshbuf_free(b); |
|
if (matched) |
|
return 1; |
|
|
|
/* XXX CA signature operation */ |
|
|
|
error("web-origin key attempting to sign non-SSH message"); |
|
return 0; |
|
} |
|
|
/* ssh2 only */ |
/* ssh2 only */ |
static void |
static void |
process_sign_request2(SocketEntry *e) |
process_sign_request2(SocketEntry *e) |
|
|
verbose("%s: user refused key", __func__); |
verbose("%s: user refused key", __func__); |
goto send; |
goto send; |
} |
} |
if (sshkey_is_sk(id->key) && |
if (sshkey_is_sk(id->key)) { |
(id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { |
if (strncmp(id->key->sk_application, "ssh:", 4) != 0 && |
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, |
!check_websafe_message_contents(key, data, dlen)) { |
SSH_FP_DEFAULT)) == NULL) |
/* error already logged */ |
fatal("%s: fingerprint failed", __func__); |
goto send; |
notifier = notify_start(0, |
} |
"Confirm user presence for key %s %s", |
if ((id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { |
sshkey_type(id->key), fp); |
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, |
|
SSH_FP_DEFAULT)) == NULL) |
|
fatal("%s: fingerprint failed", __func__); |
|
notifier = notify_start(0, |
|
"Confirm user presence for key %s %s", |
|
sshkey_type(id->key), fp); |
|
} |
} |
} |
if ((r = sshkey_sign(id->key, &signature, &slen, |
if ((r = sshkey_sign(id->key, &signature, &slen, |
data, dlen, agent_decode_alg(key, flags), |
data, dlen, agent_decode_alg(key, flags), |
|
|
OpenSSL_add_all_algorithms(); |
OpenSSL_add_all_algorithms(); |
#endif |
#endif |
|
|
while ((ch = getopt(ac, av, "cDdksE:a:P:t:")) != -1) { |
while ((ch = getopt(ac, av, "cDdksE:a:O:P:t:")) != -1) { |
switch (ch) { |
switch (ch) { |
case 'E': |
case 'E': |
fingerprint_hash = ssh_digest_alg_by_name(optarg); |
fingerprint_hash = ssh_digest_alg_by_name(optarg); |
|
|
break; |
break; |
case 'k': |
case 'k': |
k_flag++; |
k_flag++; |
|
break; |
|
case 'O': |
|
if (strcmp(optarg, "no-restrict-websafe") == 0) |
|
restrict_websafe = 0; |
|
else |
|
fatal("Unknown -O option"); |
break; |
break; |
case 'P': |
case 'P': |
if (provider_whitelist != NULL) |
if (provider_whitelist != NULL) |