=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-sk-helper.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- src/usr.bin/ssh/ssh-sk-helper.c 2019/12/30 09:21:59 1.5 +++ src/usr.bin/ssh/ssh-sk-helper.c 2019/12/30 09:23:28 1.6 @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-sk-helper.c,v 1.5 2019/12/30 09:21:59 djm Exp $ */ +/* $OpenBSD: ssh-sk-helper.c,v 1.6 2019/12/30 09:23:28 djm Exp $ */ /* * Copyright (c) 2019 Google LLC * @@ -47,7 +47,34 @@ extern char *__progname; +static struct sshbuf *reply_error(int r, char *fmt, ...) + __attribute__((__format__ (printf, 2, 3))); + static struct sshbuf * +reply_error(int r, char *fmt, ...) +{ + char *msg; + va_list ap; + struct sshbuf *resp; + + va_start(ap, fmt); + xvasprintf(&msg, fmt, ap); + va_end(ap); + error("%s: %s", __progname, msg); + free(msg); + + if (r >= 0) + fatal("%s: invalid error code %d", __func__, r); + + if ((resp = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __progname); + if (sshbuf_put_u32(resp, SSH_SK_HELPER_ERROR) != 0 || + sshbuf_put_u32(resp, (u_int)-r) != 0) + fatal("%s: buffer error", __progname); + return resp; +} + +static struct sshbuf * process_sign(struct sshbuf *req) { int r = SSH_ERR_INTERNAL_ERROR; @@ -57,13 +84,14 @@ const u_char *message; u_char *sig; size_t msglen, siglen; - char *provider; + char *provider, *pin; if ((r = sshbuf_froms(req, &kbuf)) != 0 || (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || (r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 || (r = sshbuf_get_cstring(req, NULL, NULL)) != 0 || /* alg */ - (r = sshbuf_get_u32(req, &compat)) != 0) + (r = sshbuf_get_u32(req, &compat)) != 0 || + (r = sshbuf_get_cstring(req, &pin, NULL)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); if (sshbuf_len(req) != 0) fatal("%s: trailing data in request", __progname); @@ -77,19 +105,28 @@ "msg len %zu, compat 0x%lx", __progname, sshkey_type(key), provider, msglen, (u_long)compat); + if (*pin == 0) { + free(pin); + pin = NULL; + } + if ((r = sshsk_sign(provider, key, &sig, &siglen, - message, msglen, compat)) != 0) - fatal("Signing failed: %s", ssh_err(r)); + message, msglen, compat, pin)) != 0) { + resp = reply_error(r, "Signing failed: %s", ssh_err(r)); + goto out; + } if ((resp = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __progname); - if ((r = sshbuf_put_string(resp, sig, siglen)) != 0) + if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_SIGN)) != 0 || + (r = sshbuf_put_string(resp, sig, siglen)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); - + out: sshbuf_free(kbuf); free(provider); - + if (pin != NULL) + freezero(pin, strlen(pin)); return resp; } @@ -98,14 +135,12 @@ { int r; u_int type; - char *provider; - char *application; + char *provider, *application, *pin; uint8_t flags; struct sshbuf *challenge, *attest, *kbuf, *resp; struct sshkey *key; - if ((resp = sshbuf_new()) == NULL || - (attest = sshbuf_new()) == NULL || + if ((attest = sshbuf_new()) == NULL || (kbuf = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __progname); @@ -113,6 +148,7 @@ (r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || (r = sshbuf_get_cstring(req, &application, NULL)) != 0 || (r = sshbuf_get_u8(req, &flags)) != 0 || + (r = sshbuf_get_cstring(req, &pin, NULL)) != 0 || (r = sshbuf_froms(req, &challenge)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); if (sshbuf_len(req) != 0) @@ -124,23 +160,35 @@ sshbuf_free(challenge); challenge = NULL; } + if (*pin == 0) { + free(pin); + pin = NULL; + } - if ((r = sshsk_enroll((int)type, provider, application, flags, - challenge, &key, attest)) != 0) - fatal("%s: sshsk_enroll failed: %s", __progname, ssh_err(r)); + if ((r = sshsk_enroll((int)type, provider, application, flags, pin, + challenge, &key, attest)) != 0) { + resp = reply_error(r, "Enrollment failed: %s", ssh_err(r)); + goto out; + } + if ((resp = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __progname); if ((r = sshkey_private_serialize(key, kbuf)) != 0) fatal("%s: serialize private key: %s", __progname, ssh_err(r)); - if ((r = sshbuf_put_stringb(resp, kbuf)) != 0 || + if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_ENROLL)) != 0 || + (r = sshbuf_put_stringb(resp, kbuf)) != 0 || (r = sshbuf_put_stringb(resp, attest)) != 0) fatal("%s: buffer error: %s", __progname, ssh_err(r)); + out: sshkey_free(key); sshbuf_free(kbuf); sshbuf_free(attest); sshbuf_free(challenge); free(provider); free(application); + if (pin != NULL) + freezero(pin, strlen(pin)); return resp; } @@ -154,8 +202,7 @@ struct sshkey **keys = NULL; size_t nkeys = 0, i; - if ((resp = sshbuf_new()) == NULL || - (kbuf = sshbuf_new()) == NULL) + if ((kbuf = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __progname); if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 || @@ -164,10 +211,23 @@ if (sshbuf_len(req) != 0) fatal("%s: trailing data in request", __progname); - if ((r = sshsk_load_resident(provider, pin, &keys, &nkeys)) != 0) - fatal("%s: sshsk_load_resident failed: %s", - __progname, ssh_err(r)); + if (*pin == 0) { + free(pin); + pin = NULL; + } + if ((r = sshsk_load_resident(provider, pin, &keys, &nkeys)) != 0) { + resp = reply_error(r, " sshsk_load_resident failed: %s", + ssh_err(r)); + goto out; + } + + if ((resp = sshbuf_new()) == NULL) + fatal("%s: sshbuf_new failed", __progname); + + if ((r = sshbuf_put_u32(resp, SSH_SK_HELPER_LOAD_RESIDENT)) != 0) + fatal("%s: buffer error: %s", __progname, ssh_err(r)); + for (i = 0; i < nkeys; i++) { debug("%s: key %zu %s %s", __func__, i, sshkey_type(keys[i]), keys[i]->sk_application); @@ -180,12 +240,14 @@ fatal("%s: buffer error: %s", __progname, ssh_err(r)); } + out: for (i = 0; i < nkeys; i++) sshkey_free(keys[i]); free(keys); sshbuf_free(kbuf); free(provider); - freezero(pin, strlen(pin)); + if (pin != NULL) + freezero(pin, strlen(pin)); return resp; }