mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-26 23:34:55 +02:00
upstream: SK API and sk-helper error/PIN passing
Allow passing a PIN via the SK API (API major crank) and let the ssh-sk-helper API follow. Also enhance the ssh-sk-helper API to support passing back an error code instead of a complete reply. Will be used to signal "wrong PIN", etc. feedback and ok markus@ OpenBSD-Commit-ID: a1bd6b0a2421646919a0c139b8183ad76d28fb71
This commit is contained in:
parent
79fe22d9bc
commit
c54cd1892c
8
sk-api.h
8
sk-api.h
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: sk-api.h,v 1.4 2019/12/30 09:21:16 djm Exp $ */
|
/* $OpenBSD: sk-api.h,v 1.5 2019/12/30 09:23:28 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Google LLC
|
* Copyright (c) 2019 Google LLC
|
||||||
*
|
*
|
||||||
@ -59,7 +59,7 @@ struct sk_resident_key {
|
|||||||
struct sk_enroll_response key;
|
struct sk_enroll_response key;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SSH_SK_VERSION_MAJOR 0x00020000 /* current API version */
|
#define SSH_SK_VERSION_MAJOR 0x00030000 /* current API version */
|
||||||
#define SSH_SK_VERSION_MAJOR_MASK 0xffff0000
|
#define SSH_SK_VERSION_MAJOR_MASK 0xffff0000
|
||||||
|
|
||||||
/* Return the version of the middleware API */
|
/* Return the version of the middleware API */
|
||||||
@ -67,13 +67,13 @@ uint32_t sk_api_version(void);
|
|||||||
|
|
||||||
/* Enroll a U2F key (private key generation) */
|
/* Enroll a U2F key (private key generation) */
|
||||||
int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
|
int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
|
||||||
const char *application, uint8_t flags,
|
const char *application, uint8_t flags, const char *pin,
|
||||||
struct sk_enroll_response **enroll_response);
|
struct sk_enroll_response **enroll_response);
|
||||||
|
|
||||||
/* Sign a challenge */
|
/* Sign a challenge */
|
||||||
int sk_sign(int alg, const uint8_t *message, size_t message_len,
|
int sk_sign(int alg, const uint8_t *message, size_t message_len,
|
||||||
const char *application, const uint8_t *key_handle, size_t key_handle_len,
|
const char *application, const uint8_t *key_handle, size_t key_handle_len,
|
||||||
uint8_t flags, struct sk_sign_response **sign_response);
|
uint8_t flags, const char *pin, struct sk_sign_response **sign_response);
|
||||||
|
|
||||||
/* Enumerate all resident keys */
|
/* Enumerate all resident keys */
|
||||||
int sk_load_resident_keys(const char *pin,
|
int sk_load_resident_keys(const char *pin,
|
||||||
|
10
sk-usbhid.c
10
sk-usbhid.c
@ -54,7 +54,7 @@
|
|||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SK_VERSION_MAJOR 0x00020000 /* current API version */
|
#define SK_VERSION_MAJOR 0x00030000 /* current API version */
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
#define SK_USER_PRESENCE_REQD 0x01
|
#define SK_USER_PRESENCE_REQD 0x01
|
||||||
@ -105,13 +105,13 @@ uint32_t sk_api_version(void);
|
|||||||
|
|
||||||
/* Enroll a U2F key (private key generation) */
|
/* Enroll a U2F key (private key generation) */
|
||||||
int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
|
int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
|
||||||
const char *application, uint8_t flags,
|
const char *application, uint8_t flags, const char *pin,
|
||||||
struct sk_enroll_response **enroll_response);
|
struct sk_enroll_response **enroll_response);
|
||||||
|
|
||||||
/* Sign a challenge */
|
/* Sign a challenge */
|
||||||
int sk_sign(int alg, const uint8_t *message, size_t message_len,
|
int sk_sign(int alg, const uint8_t *message, size_t message_len,
|
||||||
const char *application, const uint8_t *key_handle, size_t key_handle_len,
|
const char *application, const uint8_t *key_handle, size_t key_handle_len,
|
||||||
uint8_t flags, struct sk_sign_response **sign_response);
|
uint8_t flags, const char *pin, struct sk_sign_response **sign_response);
|
||||||
|
|
||||||
/* Load resident keys */
|
/* Load resident keys */
|
||||||
int sk_load_resident_keys(const char *pin,
|
int sk_load_resident_keys(const char *pin,
|
||||||
@ -414,7 +414,7 @@ pack_public_key(int alg, const fido_cred_t *cred,
|
|||||||
|
|
||||||
int
|
int
|
||||||
sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
|
sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len,
|
||||||
const char *application, uint8_t flags,
|
const char *application, uint8_t flags, const char *pin,
|
||||||
struct sk_enroll_response **enroll_response)
|
struct sk_enroll_response **enroll_response)
|
||||||
{
|
{
|
||||||
fido_cred_t *cred = NULL;
|
fido_cred_t *cred = NULL;
|
||||||
@ -652,7 +652,7 @@ int
|
|||||||
sk_sign(int alg, const uint8_t *message, size_t message_len,
|
sk_sign(int alg, const uint8_t *message, size_t message_len,
|
||||||
const char *application,
|
const char *application,
|
||||||
const uint8_t *key_handle, size_t key_handle_len,
|
const uint8_t *key_handle, size_t key_handle_len,
|
||||||
uint8_t flags, struct sk_sign_response **sign_response)
|
uint8_t flags, const char *pin, struct sk_sign_response **sign_response)
|
||||||
{
|
{
|
||||||
fido_assert_t *assert = NULL;
|
fido_assert_t *assert = NULL;
|
||||||
fido_dev_t *dev = NULL;
|
fido_dev_t *dev = NULL;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh-keygen.c,v 1.377 2019/12/30 09:19:52 djm Exp $ */
|
/* $OpenBSD: ssh-keygen.c,v 1.378 2019/12/30 09:23:28 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -3368,7 +3368,7 @@ main(int argc, char **argv)
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
if (sshsk_enroll(type, sk_provider,
|
if (sshsk_enroll(type, sk_provider,
|
||||||
cert_key_id == NULL ? "ssh:" : cert_key_id,
|
cert_key_id == NULL ? "ssh:" : cert_key_id,
|
||||||
sk_flags, NULL, &private, NULL) != 0)
|
sk_flags, NULL, NULL, &private, NULL) != 0)
|
||||||
exit(1); /* error message already printed */
|
exit(1); /* error message already printed */
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh-sk-client.c,v 1.2 2019/12/30 09:21:59 djm Exp $ */
|
/* $OpenBSD: ssh-sk-client.c,v 1.3 2019/12/30 09:23:28 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Google LLC
|
* Copyright (c) 2019 Google LLC
|
||||||
*
|
*
|
||||||
@ -21,6 +21,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -128,14 +129,14 @@ reap_helper(pid_t pid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
client_converse(struct sshbuf *req, struct sshbuf **respp)
|
client_converse(struct sshbuf *req, struct sshbuf **respp, u_int msg)
|
||||||
{
|
{
|
||||||
int oerrno, fd, r2, r = SSH_ERR_INTERNAL_ERROR;
|
int oerrno, fd, r2, r = SSH_ERR_INTERNAL_ERROR;
|
||||||
|
u_int rmsg, rerr;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
u_char version;
|
u_char version;
|
||||||
void (*osigchld)(int);
|
void (*osigchld)(int);
|
||||||
struct sshbuf *resp = NULL;
|
struct sshbuf *resp = NULL;
|
||||||
|
|
||||||
*respp = NULL;
|
*respp = NULL;
|
||||||
|
|
||||||
if ((r = start_helper(&fd, &pid, &osigchld)) != 0)
|
if ((r = start_helper(&fd, &pid, &osigchld)) != 0)
|
||||||
@ -164,6 +165,28 @@ client_converse(struct sshbuf *req, struct sshbuf **respp)
|
|||||||
r = SSH_ERR_INVALID_FORMAT;
|
r = SSH_ERR_INVALID_FORMAT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if ((r = sshbuf_get_u32(resp, &rmsg)) != 0) {
|
||||||
|
error("%s: parse message type: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (rmsg == SSH_SK_HELPER_ERROR) {
|
||||||
|
if ((r = sshbuf_get_u32(resp, &rerr)) != 0) {
|
||||||
|
error("%s: parse error: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
debug("%s: helper returned error -%u", __func__, rerr);
|
||||||
|
/* OpenSSH error values are negative; encoded as -err on wire */
|
||||||
|
if (rerr == 0 || rerr >= INT_MAX)
|
||||||
|
r = SSH_ERR_INTERNAL_ERROR;
|
||||||
|
else
|
||||||
|
r = -(int)rerr;
|
||||||
|
goto out;
|
||||||
|
} else if (rmsg != msg) {
|
||||||
|
error("%s: helper returned incorrect message type %u, "
|
||||||
|
"expecting %u", __func__, rmsg, msg);
|
||||||
|
r = SSH_ERR_INTERNAL_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
/* success */
|
/* success */
|
||||||
r = 0;
|
r = 0;
|
||||||
out:
|
out:
|
||||||
@ -189,7 +212,7 @@ client_converse(struct sshbuf *req, struct sshbuf **respp)
|
|||||||
int
|
int
|
||||||
sshsk_sign(const char *provider, struct sshkey *key,
|
sshsk_sign(const char *provider, struct sshkey *key,
|
||||||
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
||||||
u_int compat)
|
u_int compat, const char *pin)
|
||||||
{
|
{
|
||||||
int oerrno, r = SSH_ERR_INTERNAL_ERROR;
|
int oerrno, r = SSH_ERR_INTERNAL_ERROR;
|
||||||
char *fp = NULL;
|
char *fp = NULL;
|
||||||
@ -217,7 +240,8 @@ sshsk_sign(const char *provider, struct sshkey *key,
|
|||||||
(r = sshbuf_put_cstring(req, provider)) != 0 ||
|
(r = sshbuf_put_cstring(req, provider)) != 0 ||
|
||||||
(r = sshbuf_put_string(req, data, datalen)) != 0 ||
|
(r = sshbuf_put_string(req, data, datalen)) != 0 ||
|
||||||
(r = sshbuf_put_cstring(req, NULL)) != 0 || /* alg */
|
(r = sshbuf_put_cstring(req, NULL)) != 0 || /* alg */
|
||||||
(r = sshbuf_put_u32(req, compat)) != 0) {
|
(r = sshbuf_put_u32(req, compat)) != 0 ||
|
||||||
|
(r = sshbuf_put_cstring(req, pin)) != 0) {
|
||||||
error("%s: compose: %s", __func__, ssh_err(r));
|
error("%s: compose: %s", __func__, ssh_err(r));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -228,7 +252,7 @@ sshsk_sign(const char *provider, struct sshkey *key,
|
|||||||
r = SSH_ERR_ALLOC_FAIL;
|
r = SSH_ERR_ALLOC_FAIL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if ((r = client_converse(req, &resp)) != 0)
|
if ((r = client_converse(req, &resp, SSH_SK_HELPER_SIGN)) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) {
|
if ((r = sshbuf_get_string(resp, sigp, lenp)) != 0) {
|
||||||
@ -259,8 +283,8 @@ sshsk_sign(const char *provider, struct sshkey *key,
|
|||||||
|
|
||||||
int
|
int
|
||||||
sshsk_enroll(int type, const char *provider_path, const char *application,
|
sshsk_enroll(int type, const char *provider_path, const char *application,
|
||||||
uint8_t flags, struct sshbuf *challenge_buf, struct sshkey **keyp,
|
uint8_t flags, const char *pin, struct sshbuf *challenge_buf,
|
||||||
struct sshbuf *attest)
|
struct sshkey **keyp, struct sshbuf *attest)
|
||||||
{
|
{
|
||||||
int oerrno, r = SSH_ERR_INTERNAL_ERROR;
|
int oerrno, r = SSH_ERR_INTERNAL_ERROR;
|
||||||
struct sshbuf *kbuf = NULL, *abuf = NULL, *req = NULL, *resp = NULL;
|
struct sshbuf *kbuf = NULL, *abuf = NULL, *req = NULL, *resp = NULL;
|
||||||
@ -289,12 +313,13 @@ sshsk_enroll(int type, const char *provider_path, const char *application,
|
|||||||
(r = sshbuf_put_cstring(req, provider_path)) != 0 ||
|
(r = sshbuf_put_cstring(req, provider_path)) != 0 ||
|
||||||
(r = sshbuf_put_cstring(req, application)) != 0 ||
|
(r = sshbuf_put_cstring(req, application)) != 0 ||
|
||||||
(r = sshbuf_put_u8(req, flags)) != 0 ||
|
(r = sshbuf_put_u8(req, flags)) != 0 ||
|
||||||
|
(r = sshbuf_put_cstring(req, pin)) != 0 ||
|
||||||
(r = sshbuf_put_stringb(req, challenge_buf)) != 0) {
|
(r = sshbuf_put_stringb(req, challenge_buf)) != 0) {
|
||||||
error("%s: compose: %s", __func__, ssh_err(r));
|
error("%s: compose: %s", __func__, ssh_err(r));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((r = client_converse(req, &resp)) != 0)
|
if ((r = client_converse(req, &resp, SSH_SK_HELPER_ENROLL)) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if ((r = sshbuf_get_stringb(resp, kbuf)) != 0 ||
|
if ((r = sshbuf_get_stringb(resp, kbuf)) != 0 ||
|
||||||
@ -358,7 +383,7 @@ sshsk_load_resident(const char *provider_path, const char *pin,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((r = client_converse(req, &resp)) != 0)
|
if ((r = client_converse(req, &resp, SSH_SK_HELPER_LOAD_RESIDENT)) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
while (sshbuf_len(resp) != 0) {
|
while (sshbuf_len(resp) != 0) {
|
||||||
@ -378,6 +403,8 @@ sshsk_load_resident(const char *provider_path, const char *pin,
|
|||||||
error("%s: recallocarray keys failed", __func__);
|
error("%s: recallocarray keys failed", __func__);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
debug("%s: keys[%zu]: %s %s", __func__,
|
||||||
|
nkeys, sshkey_type(key), key->sk_application);
|
||||||
keys = tmp;
|
keys = tmp;
|
||||||
keys[nkeys++] = key;
|
keys[nkeys++] = key;
|
||||||
key = NULL;
|
key = NULL;
|
||||||
|
106
ssh-sk-helper.c
106
ssh-sk-helper.c
@ -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
|
* Copyright (c) 2019 Google LLC
|
||||||
*
|
*
|
||||||
@ -50,6 +50,33 @@
|
|||||||
#ifdef ENABLE_SK
|
#ifdef ENABLE_SK
|
||||||
extern char *__progname;
|
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 *
|
static struct sshbuf *
|
||||||
process_sign(struct sshbuf *req)
|
process_sign(struct sshbuf *req)
|
||||||
{
|
{
|
||||||
@ -60,13 +87,14 @@ process_sign(struct sshbuf *req)
|
|||||||
const u_char *message;
|
const u_char *message;
|
||||||
u_char *sig;
|
u_char *sig;
|
||||||
size_t msglen, siglen;
|
size_t msglen, siglen;
|
||||||
char *provider;
|
char *provider, *pin;
|
||||||
|
|
||||||
if ((r = sshbuf_froms(req, &kbuf)) != 0 ||
|
if ((r = sshbuf_froms(req, &kbuf)) != 0 ||
|
||||||
(r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
|
(r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
|
||||||
(r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 ||
|
(r = sshbuf_get_string_direct(req, &message, &msglen)) != 0 ||
|
||||||
(r = sshbuf_get_cstring(req, NULL, NULL)) != 0 || /* alg */
|
(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));
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
if (sshbuf_len(req) != 0)
|
if (sshbuf_len(req) != 0)
|
||||||
fatal("%s: trailing data in request", __progname);
|
fatal("%s: trailing data in request", __progname);
|
||||||
@ -80,19 +108,28 @@ process_sign(struct sshbuf *req)
|
|||||||
"msg len %zu, compat 0x%lx", __progname, sshkey_type(key),
|
"msg len %zu, compat 0x%lx", __progname, sshkey_type(key),
|
||||||
provider, msglen, (u_long)compat);
|
provider, msglen, (u_long)compat);
|
||||||
|
|
||||||
|
if (*pin == 0) {
|
||||||
|
free(pin);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((r = sshsk_sign(provider, key, &sig, &siglen,
|
if ((r = sshsk_sign(provider, key, &sig, &siglen,
|
||||||
message, msglen, compat)) != 0)
|
message, msglen, compat, pin)) != 0) {
|
||||||
fatal("Signing failed: %s", ssh_err(r));
|
resp = reply_error(r, "Signing failed: %s", ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if ((resp = sshbuf_new()) == NULL)
|
if ((resp = sshbuf_new()) == NULL)
|
||||||
fatal("%s: sshbuf_new failed", __progname);
|
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));
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
|
out:
|
||||||
sshbuf_free(kbuf);
|
sshbuf_free(kbuf);
|
||||||
free(provider);
|
free(provider);
|
||||||
|
if (pin != NULL)
|
||||||
|
freezero(pin, strlen(pin));
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,14 +138,12 @@ process_enroll(struct sshbuf *req)
|
|||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
u_int type;
|
u_int type;
|
||||||
char *provider;
|
char *provider, *application, *pin;
|
||||||
char *application;
|
|
||||||
uint8_t flags;
|
uint8_t flags;
|
||||||
struct sshbuf *challenge, *attest, *kbuf, *resp;
|
struct sshbuf *challenge, *attest, *kbuf, *resp;
|
||||||
struct sshkey *key;
|
struct sshkey *key;
|
||||||
|
|
||||||
if ((resp = sshbuf_new()) == NULL ||
|
if ((attest = sshbuf_new()) == NULL ||
|
||||||
(attest = sshbuf_new()) == NULL ||
|
|
||||||
(kbuf = sshbuf_new()) == NULL)
|
(kbuf = sshbuf_new()) == NULL)
|
||||||
fatal("%s: sshbuf_new failed", __progname);
|
fatal("%s: sshbuf_new failed", __progname);
|
||||||
|
|
||||||
@ -116,6 +151,7 @@ process_enroll(struct sshbuf *req)
|
|||||||
(r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
|
(r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
|
||||||
(r = sshbuf_get_cstring(req, &application, NULL)) != 0 ||
|
(r = sshbuf_get_cstring(req, &application, NULL)) != 0 ||
|
||||||
(r = sshbuf_get_u8(req, &flags)) != 0 ||
|
(r = sshbuf_get_u8(req, &flags)) != 0 ||
|
||||||
|
(r = sshbuf_get_cstring(req, &pin, NULL)) != 0 ||
|
||||||
(r = sshbuf_froms(req, &challenge)) != 0)
|
(r = sshbuf_froms(req, &challenge)) != 0)
|
||||||
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
if (sshbuf_len(req) != 0)
|
if (sshbuf_len(req) != 0)
|
||||||
@ -127,23 +163,35 @@ process_enroll(struct sshbuf *req)
|
|||||||
sshbuf_free(challenge);
|
sshbuf_free(challenge);
|
||||||
challenge = NULL;
|
challenge = NULL;
|
||||||
}
|
}
|
||||||
|
if (*pin == 0) {
|
||||||
|
free(pin);
|
||||||
|
pin = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if ((r = sshsk_enroll((int)type, provider, application, flags,
|
if ((r = sshsk_enroll((int)type, provider, application, flags, pin,
|
||||||
challenge, &key, attest)) != 0)
|
challenge, &key, attest)) != 0) {
|
||||||
fatal("%s: sshsk_enroll failed: %s", __progname, ssh_err(r));
|
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)
|
if ((r = sshkey_private_serialize(key, kbuf)) != 0)
|
||||||
fatal("%s: serialize private key: %s", __progname, ssh_err(r));
|
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)
|
(r = sshbuf_put_stringb(resp, attest)) != 0)
|
||||||
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
|
|
||||||
|
out:
|
||||||
sshkey_free(key);
|
sshkey_free(key);
|
||||||
sshbuf_free(kbuf);
|
sshbuf_free(kbuf);
|
||||||
sshbuf_free(attest);
|
sshbuf_free(attest);
|
||||||
sshbuf_free(challenge);
|
sshbuf_free(challenge);
|
||||||
free(provider);
|
free(provider);
|
||||||
free(application);
|
free(application);
|
||||||
|
if (pin != NULL)
|
||||||
|
freezero(pin, strlen(pin));
|
||||||
|
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
@ -157,8 +205,7 @@ process_load_resident(struct sshbuf *req)
|
|||||||
struct sshkey **keys = NULL;
|
struct sshkey **keys = NULL;
|
||||||
size_t nkeys = 0, i;
|
size_t nkeys = 0, i;
|
||||||
|
|
||||||
if ((resp = sshbuf_new()) == NULL ||
|
if ((kbuf = sshbuf_new()) == NULL)
|
||||||
(kbuf = sshbuf_new()) == NULL)
|
|
||||||
fatal("%s: sshbuf_new failed", __progname);
|
fatal("%s: sshbuf_new failed", __progname);
|
||||||
|
|
||||||
if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
|
if ((r = sshbuf_get_cstring(req, &provider, NULL)) != 0 ||
|
||||||
@ -167,9 +214,22 @@ process_load_resident(struct sshbuf *req)
|
|||||||
if (sshbuf_len(req) != 0)
|
if (sshbuf_len(req) != 0)
|
||||||
fatal("%s: trailing data in request", __progname);
|
fatal("%s: trailing data in request", __progname);
|
||||||
|
|
||||||
if ((r = sshsk_load_resident(provider, pin, &keys, &nkeys)) != 0)
|
if (*pin == 0) {
|
||||||
fatal("%s: sshsk_load_resident failed: %s",
|
free(pin);
|
||||||
__progname, ssh_err(r));
|
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++) {
|
for (i = 0; i < nkeys; i++) {
|
||||||
debug("%s: key %zu %s %s", __func__, i,
|
debug("%s: key %zu %s %s", __func__, i,
|
||||||
@ -183,12 +243,14 @@ process_load_resident(struct sshbuf *req)
|
|||||||
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
fatal("%s: buffer error: %s", __progname, ssh_err(r));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
for (i = 0; i < nkeys; i++)
|
for (i = 0; i < nkeys; i++)
|
||||||
sshkey_free(keys[i]);
|
sshkey_free(keys[i]);
|
||||||
free(keys);
|
free(keys);
|
||||||
sshbuf_free(kbuf);
|
sshbuf_free(kbuf);
|
||||||
free(provider);
|
free(provider);
|
||||||
freezero(pin, strlen(pin));
|
if (pin != NULL)
|
||||||
|
freezero(pin, strlen(pin));
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
ssh-sk.c
31
ssh-sk.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh-sk.c,v 1.20 2019/12/30 09:21:16 djm Exp $ */
|
/* $OpenBSD: ssh-sk.c,v 1.21 2019/12/30 09:23:28 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Google LLC
|
* Copyright (c) 2019 Google LLC
|
||||||
*
|
*
|
||||||
@ -53,13 +53,14 @@ struct sshsk_provider {
|
|||||||
/* Enroll a U2F key (private key generation) */
|
/* Enroll a U2F key (private key generation) */
|
||||||
int (*sk_enroll)(int alg, const uint8_t *challenge,
|
int (*sk_enroll)(int alg, const uint8_t *challenge,
|
||||||
size_t challenge_len, const char *application, uint8_t flags,
|
size_t challenge_len, const char *application, uint8_t flags,
|
||||||
struct sk_enroll_response **enroll_response);
|
const char *pin, struct sk_enroll_response **enroll_response);
|
||||||
|
|
||||||
/* Sign a challenge */
|
/* Sign a challenge */
|
||||||
int (*sk_sign)(int alg, const uint8_t *message, size_t message_len,
|
int (*sk_sign)(int alg, const uint8_t *message, size_t message_len,
|
||||||
const char *application,
|
const char *application,
|
||||||
const uint8_t *key_handle, size_t key_handle_len,
|
const uint8_t *key_handle, size_t key_handle_len,
|
||||||
uint8_t flags, struct sk_sign_response **sign_response);
|
uint8_t flags, const char *pin,
|
||||||
|
struct sk_sign_response **sign_response);
|
||||||
|
|
||||||
/* Enumerate resident keys */
|
/* Enumerate resident keys */
|
||||||
int (*sk_load_resident_keys)(const char *pin,
|
int (*sk_load_resident_keys)(const char *pin,
|
||||||
@ -69,11 +70,11 @@ struct sshsk_provider {
|
|||||||
/* Built-in version */
|
/* Built-in version */
|
||||||
int ssh_sk_enroll(int alg, const uint8_t *challenge,
|
int ssh_sk_enroll(int alg, const uint8_t *challenge,
|
||||||
size_t challenge_len, const char *application, uint8_t flags,
|
size_t challenge_len, const char *application, uint8_t flags,
|
||||||
struct sk_enroll_response **enroll_response);
|
const char *pin, struct sk_enroll_response **enroll_response);
|
||||||
int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len,
|
int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len,
|
||||||
const char *application,
|
const char *application,
|
||||||
const uint8_t *key_handle, size_t key_handle_len,
|
const uint8_t *key_handle, size_t key_handle_len,
|
||||||
uint8_t flags, struct sk_sign_response **sign_response);
|
uint8_t flags, const char *pin, struct sk_sign_response **sign_response);
|
||||||
int ssh_sk_load_resident_keys(const char *pin,
|
int ssh_sk_load_resident_keys(const char *pin,
|
||||||
struct sk_resident_key ***rks, size_t *nrks);
|
struct sk_resident_key ***rks, size_t *nrks);
|
||||||
|
|
||||||
@ -326,8 +327,8 @@ sshsk_key_from_response(int alg, const char *application, uint8_t flags,
|
|||||||
|
|
||||||
int
|
int
|
||||||
sshsk_enroll(int type, const char *provider_path, const char *application,
|
sshsk_enroll(int type, const char *provider_path, const char *application,
|
||||||
uint8_t flags, struct sshbuf *challenge_buf, struct sshkey **keyp,
|
uint8_t flags, const char *pin, struct sshbuf *challenge_buf,
|
||||||
struct sshbuf *attest)
|
struct sshkey **keyp, struct sshbuf *attest)
|
||||||
{
|
{
|
||||||
struct sshsk_provider *skp = NULL;
|
struct sshsk_provider *skp = NULL;
|
||||||
struct sshkey *key = NULL;
|
struct sshkey *key = NULL;
|
||||||
@ -339,8 +340,9 @@ sshsk_enroll(int type, const char *provider_path, const char *application,
|
|||||||
int alg;
|
int alg;
|
||||||
|
|
||||||
debug("%s: provider \"%s\", application \"%s\", flags 0x%02x, "
|
debug("%s: provider \"%s\", application \"%s\", flags 0x%02x, "
|
||||||
"challenge len %zu", __func__, provider_path, application,
|
"challenge len %zu%s", __func__, provider_path, application,
|
||||||
flags, challenge_buf == NULL ? 0 : sshbuf_len(challenge_buf));
|
flags, challenge_buf == NULL ? 0 : sshbuf_len(challenge_buf),
|
||||||
|
(pin != NULL && *pin != '\0') ? " with-pin" : "");
|
||||||
|
|
||||||
*keyp = NULL;
|
*keyp = NULL;
|
||||||
if (attest)
|
if (attest)
|
||||||
@ -391,7 +393,7 @@ sshsk_enroll(int type, const char *provider_path, const char *application,
|
|||||||
/* XXX validate flags? */
|
/* XXX validate flags? */
|
||||||
/* enroll key */
|
/* enroll key */
|
||||||
if ((r = skp->sk_enroll(alg, challenge, challenge_len, application,
|
if ((r = skp->sk_enroll(alg, challenge, challenge_len, application,
|
||||||
flags, &resp)) != 0) {
|
flags, pin, &resp)) != 0) {
|
||||||
error("Security key provider %s returned failure %d",
|
error("Security key provider %s returned failure %d",
|
||||||
provider_path, r);
|
provider_path, r);
|
||||||
r = SSH_ERR_INVALID_FORMAT; /* XXX error codes in API? */
|
r = SSH_ERR_INVALID_FORMAT; /* XXX error codes in API? */
|
||||||
@ -504,7 +506,7 @@ sshsk_ed25519_sig(struct sk_sign_response *resp, struct sshbuf *sig)
|
|||||||
int
|
int
|
||||||
sshsk_sign(const char *provider_path, struct sshkey *key,
|
sshsk_sign(const char *provider_path, struct sshkey *key,
|
||||||
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
||||||
u_int compat)
|
u_int compat, const char *pin)
|
||||||
{
|
{
|
||||||
struct sshsk_provider *skp = NULL;
|
struct sshsk_provider *skp = NULL;
|
||||||
int r = SSH_ERR_INTERNAL_ERROR;
|
int r = SSH_ERR_INTERNAL_ERROR;
|
||||||
@ -513,8 +515,9 @@ sshsk_sign(const char *provider_path, struct sshkey *key,
|
|||||||
struct sshbuf *inner_sig = NULL, *sig = NULL;
|
struct sshbuf *inner_sig = NULL, *sig = NULL;
|
||||||
uint8_t message[32];
|
uint8_t message[32];
|
||||||
|
|
||||||
debug("%s: provider \"%s\", key %s, flags 0x%02x", __func__,
|
debug("%s: provider \"%s\", key %s, flags 0x%02x%s", __func__,
|
||||||
provider_path, sshkey_type(key), key->sk_flags);
|
provider_path, sshkey_type(key), key->sk_flags,
|
||||||
|
(pin != NULL && *pin != '\0') ? " with-pin" : "");
|
||||||
|
|
||||||
if (sigp != NULL)
|
if (sigp != NULL)
|
||||||
*sigp = NULL;
|
*sigp = NULL;
|
||||||
@ -554,7 +557,7 @@ sshsk_sign(const char *provider_path, struct sshkey *key,
|
|||||||
if ((r = skp->sk_sign(alg, message, sizeof(message),
|
if ((r = skp->sk_sign(alg, message, sizeof(message),
|
||||||
key->sk_application,
|
key->sk_application,
|
||||||
sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle),
|
sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle),
|
||||||
key->sk_flags, &resp)) != 0) {
|
key->sk_flags, pin, &resp)) != 0) {
|
||||||
debug("%s: sk_sign failed with code %d", __func__, r);
|
debug("%s: sk_sign failed with code %d", __func__, r);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
17
ssh-sk.h
17
ssh-sk.h
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh-sk.h,v 1.7 2019/12/30 09:21:16 djm Exp $ */
|
/* $OpenBSD: ssh-sk.h,v 1.8 2019/12/30 09:23:28 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019 Google LLC
|
* Copyright (c) 2019 Google LLC
|
||||||
*
|
*
|
||||||
@ -21,6 +21,15 @@
|
|||||||
struct sshbuf;
|
struct sshbuf;
|
||||||
struct sshkey;
|
struct sshkey;
|
||||||
|
|
||||||
|
/* Version of protocol expected from ssh-sk-helper */
|
||||||
|
#define SSH_SK_HELPER_VERSION 3
|
||||||
|
|
||||||
|
/* ssh-sk-helper messages */
|
||||||
|
#define SSH_SK_HELPER_ERROR 0 /* Only valid H->C */
|
||||||
|
#define SSH_SK_HELPER_SIGN 1
|
||||||
|
#define SSH_SK_HELPER_ENROLL 2
|
||||||
|
#define SSH_SK_HELPER_LOAD_RESIDENT 3
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enroll (generate) a new security-key hosted private key of given type
|
* Enroll (generate) a new security-key hosted private key of given type
|
||||||
* via the specified provider middleware.
|
* via the specified provider middleware.
|
||||||
@ -32,8 +41,8 @@ struct sshkey;
|
|||||||
* information is placed there.
|
* information is placed there.
|
||||||
*/
|
*/
|
||||||
int sshsk_enroll(int type, const char *provider_path, const char *application,
|
int sshsk_enroll(int type, const char *provider_path, const char *application,
|
||||||
uint8_t flags, struct sshbuf *challenge_buf, struct sshkey **keyp,
|
uint8_t flags, const char *pin, struct sshbuf *challenge_buf,
|
||||||
struct sshbuf *attest);
|
struct sshkey **keyp, struct sshbuf *attest);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate an ECDSA_SK or ED25519_SK signature using the specified key
|
* Calculate an ECDSA_SK or ED25519_SK signature using the specified key
|
||||||
@ -43,7 +52,7 @@ int sshsk_enroll(int type, const char *provider_path, const char *application,
|
|||||||
*/
|
*/
|
||||||
int sshsk_sign(const char *provider_path, struct sshkey *key,
|
int sshsk_sign(const char *provider_path, struct sshkey *key,
|
||||||
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
||||||
u_int compat);
|
u_int compat, const char *pin);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enumerates and loads all SSH-compatible resident keys from a security
|
* Enumerates and loads all SSH-compatible resident keys from a security
|
||||||
|
4
sshkey.c
4
sshkey.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: sshkey.c,v 1.97 2019/12/13 19:09:10 djm Exp $ */
|
/* $OpenBSD: sshkey.c,v 1.98 2019/12/30 09:23:28 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||||
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
|
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
|
||||||
@ -2765,7 +2765,7 @@ sshkey_sign(struct sshkey *key,
|
|||||||
case KEY_ECDSA_SK_CERT:
|
case KEY_ECDSA_SK_CERT:
|
||||||
case KEY_ECDSA_SK:
|
case KEY_ECDSA_SK:
|
||||||
r = sshsk_sign(sk_provider, key, sigp, lenp, data,
|
r = sshsk_sign(sk_provider, key, sigp, lenp, data,
|
||||||
datalen, compat);
|
datalen, compat, /* XXX PIN */ NULL);
|
||||||
break;
|
break;
|
||||||
#ifdef WITH_XMSS
|
#ifdef WITH_XMSS
|
||||||
case KEY_XMSS:
|
case KEY_XMSS:
|
||||||
|
10
sshkey.h
10
sshkey.h
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: sshkey.h,v 1.43 2019/12/30 09:21:59 djm Exp $ */
|
/* $OpenBSD: sshkey.h,v 1.44 2019/12/30 09:23:28 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||||
@ -51,14 +51,6 @@
|
|||||||
#define SSH_RSA_MINIMUM_MODULUS_SIZE 1024
|
#define SSH_RSA_MINIMUM_MODULUS_SIZE 1024
|
||||||
#define SSH_KEY_MAX_SIGN_DATA_SIZE (1 << 20)
|
#define SSH_KEY_MAX_SIGN_DATA_SIZE (1 << 20)
|
||||||
|
|
||||||
/* Version of protocol expected from ssh-sk-helper */
|
|
||||||
#define SSH_SK_HELPER_VERSION 2
|
|
||||||
|
|
||||||
/* ssh-sk-helper messages */
|
|
||||||
#define SSH_SK_HELPER_SIGN 1
|
|
||||||
#define SSH_SK_HELPER_ENROLL 2
|
|
||||||
#define SSH_SK_HELPER_LOAD_RESIDENT 3
|
|
||||||
|
|
||||||
struct sshbuf;
|
struct sshbuf;
|
||||||
|
|
||||||
/* Key types */
|
/* Key types */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user