version 1.250, 2019/11/19 16:02:32 |
version 1.251, 2019/12/13 19:09:10 |
|
|
#include "ssherr.h" |
#include "ssherr.h" |
#include "pathnames.h" |
#include "pathnames.h" |
#include "ssh-pkcs11.h" |
#include "ssh-pkcs11.h" |
#include "ssh-sk.h" |
#include "sk-api.h" |
|
|
#ifndef DEFAULT_PROVIDER_WHITELIST |
#ifndef DEFAULT_PROVIDER_WHITELIST |
# define DEFAULT_PROVIDER_WHITELIST "/usr/lib*/*,/usr/local/lib*/*" |
# define DEFAULT_PROVIDER_WHITELIST "/usr/lib*/*,/usr/local/lib*/*" |
|
|
return NULL; |
return NULL; |
} |
} |
|
|
static int |
|
provider_sign(const char *provider, struct sshkey *key, |
|
u_char **sigp, size_t *lenp, |
|
const u_char *data, size_t datalen, |
|
const char *alg, u_int compat) |
|
{ |
|
int status, pair[2], r = SSH_ERR_INTERNAL_ERROR; |
|
pid_t pid; |
|
char *helper, *verbosity = NULL, *fp = NULL; |
|
struct sshbuf *kbuf, *req, *resp; |
|
u_char version; |
|
struct notifier_ctx *notifier = NULL; |
|
|
|
debug3("%s: start for provider %s", __func__, provider); |
|
|
|
*sigp = NULL; |
|
*lenp = 0; |
|
|
|
helper = getenv("SSH_SK_HELPER"); |
|
if (helper == NULL || strlen(helper) == 0) |
|
helper = _PATH_SSH_SK_HELPER; |
|
if (log_level_get() >= SYSLOG_LEVEL_DEBUG1) |
|
verbosity = "-vvv"; |
|
|
|
/* Start helper */ |
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { |
|
error("socketpair: %s", strerror(errno)); |
|
return SSH_ERR_SYSTEM_ERROR; |
|
} |
|
if ((pid = fork()) == -1) { |
|
error("fork: %s", strerror(errno)); |
|
close(pair[0]); |
|
close(pair[1]); |
|
return SSH_ERR_SYSTEM_ERROR; |
|
} |
|
if (pid == 0) { |
|
if ((dup2(pair[1], STDIN_FILENO) == -1) || |
|
(dup2(pair[1], STDOUT_FILENO) == -1)) |
|
fatal("%s: dup2: %s", __func__, ssh_err(r)); |
|
close(pair[0]); |
|
close(pair[1]); |
|
closefrom(STDERR_FILENO + 1); |
|
debug("%s: starting %s %s", __func__, helper, |
|
verbosity == NULL ? "" : verbosity); |
|
execlp(helper, helper, verbosity, (char *)NULL); |
|
fatal("%s: execlp: %s", __func__, strerror(errno)); |
|
} |
|
close(pair[1]); |
|
|
|
if ((kbuf = sshbuf_new()) == NULL || |
|
(req = sshbuf_new()) == NULL || |
|
(resp = sshbuf_new()) == NULL) |
|
fatal("%s: sshbuf_new failed", __func__); |
|
|
|
if ((r = sshkey_private_serialize(key, kbuf)) != 0 || |
|
(r = sshbuf_put_stringb(req, kbuf)) != 0 || |
|
(r = sshbuf_put_cstring(req, provider)) != 0 || |
|
(r = sshbuf_put_string(req, data, datalen)) != 0 || |
|
(r = sshbuf_put_u32(req, compat)) != 0) |
|
fatal("%s: compose: %s", __func__, ssh_err(r)); |
|
|
|
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, |
|
SSH_FP_DEFAULT)) == NULL) |
|
fatal("%s: sshkey_fingerprint failed", __func__); |
|
notifier = notify_start(0, |
|
"Confirm user presence for key %s %s", sshkey_type(key), fp); |
|
|
|
if ((r = ssh_msg_send(pair[0], SSH_SK_HELPER_VERSION, req)) != 0) { |
|
error("%s: send: %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
if ((r = ssh_msg_recv(pair[0], resp)) != 0) { |
|
error("%s: receive: %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_u8(resp, &version)) != 0) { |
|
error("%s: parse version: %s", __func__, ssh_err(r)); |
|
goto out; |
|
} |
|
if (version != SSH_SK_HELPER_VERSION) { |
|
error("%s: unsupported version: got %u, expected %u", |
|
__func__, version, SSH_SK_HELPER_VERSION); |
|
r = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) { |
|
error("%s: parse signature: %s", __func__, ssh_err(r)); |
|
r = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
if (sshbuf_len(resp) != 0) { |
|
error("%s: trailing data in response", __func__); |
|
r = SSH_ERR_INVALID_FORMAT; |
|
goto out; |
|
} |
|
/* success */ |
|
r = 0; |
|
out: |
|
while (waitpid(pid, &status, 0) == -1) { |
|
if (errno != EINTR) |
|
fatal("%s: waitpid: %s", __func__, ssh_err(r)); |
|
} |
|
notify_complete(notifier); |
|
if (!WIFEXITED(status)) { |
|
error("%s: helper %s exited abnormally", __func__, helper); |
|
if (r == 0) |
|
r = SSH_ERR_SYSTEM_ERROR; |
|
} else if (WEXITSTATUS(status) != 0) { |
|
error("%s: helper %s exited with non-zero exit status", |
|
__func__, helper); |
|
if (r == 0) |
|
r = SSH_ERR_SYSTEM_ERROR; |
|
} |
|
if (r != 0) { |
|
freezero(*sigp, *lenp); |
|
*sigp = NULL; |
|
*lenp = 0; |
|
} |
|
sshbuf_free(kbuf); |
|
sshbuf_free(req); |
|
sshbuf_free(resp); |
|
return r; |
|
} |
|
|
|
/* ssh2 only */ |
/* ssh2 only */ |
static void |
static void |
process_sign_request2(SocketEntry *e) |
process_sign_request2(SocketEntry *e) |
|
|
size_t dlen, slen = 0; |
size_t dlen, slen = 0; |
u_int compat = 0, flags; |
u_int compat = 0, flags; |
int r, ok = -1; |
int r, ok = -1; |
|
char *fp = NULL; |
struct sshbuf *msg; |
struct sshbuf *msg; |
struct sshkey *key = NULL; |
struct sshkey *key = NULL; |
struct identity *id; |
struct identity *id; |
|
struct notifier_ctx *notifier = NULL; |
|
|
if ((msg = sshbuf_new()) == NULL) |
if ((msg = sshbuf_new()) == NULL) |
fatal("%s: sshbuf_new failed", __func__); |
fatal("%s: sshbuf_new failed", __func__); |
|
|
verbose("%s: user refused key", __func__); |
verbose("%s: user refused key", __func__); |
goto send; |
goto send; |
} |
} |
if (id->sk_provider != NULL) { |
if (sshkey_is_sk(id->key) && |
if ((r = provider_sign(id->sk_provider, id->key, &signature, |
(id->key->sk_flags & SSH_SK_USER_PRESENCE_REQD)) { |
&slen, data, dlen, agent_decode_alg(key, flags), |
if ((fp = sshkey_fingerprint(key, SSH_FP_HASH_DEFAULT, |
compat)) != 0) { |
SSH_FP_DEFAULT)) == NULL) |
error("%s: sign: %s", __func__, ssh_err(r)); |
fatal("%s: fingerprint failed", __func__); |
goto send; |
notifier = notify_start(0, |
} |
"Confirm user presence for key %s %s", |
} else { |
sshkey_type(id->key), fp); |
if ((r = sshkey_sign(id->key, &signature, &slen, |
|
data, dlen, agent_decode_alg(key, flags), |
|
NULL, compat)) != 0) { |
|
error("%s: sshkey_sign: %s", __func__, ssh_err(r)); |
|
goto send; |
|
} |
|
} |
} |
|
if ((r = sshkey_sign(id->key, &signature, &slen, |
|
data, dlen, agent_decode_alg(key, flags), |
|
id->sk_provider, compat)) != 0) { |
|
error("%s: sshkey_sign: %s", __func__, ssh_err(r)); |
|
goto send; |
|
} |
/* Success */ |
/* Success */ |
ok = 0; |
ok = 0; |
send: |
send: |
|
notify_complete(notifier); |
sshkey_free(key); |
sshkey_free(key); |
|
free(fp); |
if (ok == 0) { |
if (ok == 0) { |
if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 || |
if ((r = sshbuf_put_u8(msg, SSH2_AGENT_SIGN_RESPONSE)) != 0 || |
(r = sshbuf_put_string(msg, signature, slen)) != 0) |
(r = sshbuf_put_string(msg, signature, slen)) != 0) |