choose not to include this information in the public key or save it by
default.
-Attestation information is very useful however in an organisational
-context, where it may be used by a CA as part of certificate
-issuance. In this case, exposure to the CA of hardware identity is
-desirable. To support this case, OpenSSH optionally allows retaining the
-attestation information at the time of key generation. It will take the
-following format:
-
- string "sk-attest-v00"
- uint32 version (1 for U2F, 2 for FIDO2 in future)
+Attestation information is useful for out-of-band key and certificate
+registration worksflows, e.g. proving to a CA that a key is backed
+by trusted hardware before it will issue a certificate. To support this
+case, OpenSSH optionally allows retaining the attestation information
+at the time of key generation. It will take the following format:
+
+ string "ssh-sk-attest-v00"
string attestation certificate
string enrollment signature
+ uint32 reserved flags
+ string reserved string
+
+OpenSSH treats the attestation certificate and enrollment signatures as
+opaque objects and does no interpretation of them itself.
SSH U2F signatures
------------------
}
if ((ptr = fido_cred_x5c_ptr(cred)) != NULL) {
len = fido_cred_x5c_len(cred);
+ debug3("%s: attestation cert len=%zu", __func__, len);
if ((response->attestation_cert = calloc(1, len)) == NULL) {
skdebug(__func__, "calloc attestation cert failed");
goto out;
-.\" $OpenBSD: ssh-keygen.1,v 1.196 2020/01/23 23:31:52 djm Exp $
+.\" $OpenBSD: ssh-keygen.1,v 1.197 2020/01/28 08:01:34 djm Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: January 23 2020 $
+.Dd $Mdocdate: January 28 2020 $
.Dt SSH-KEYGEN 1
.Os
.Sh NAME
.Xr sshd 8
will refuse such signatures by default, unless overridden via
an authorized_keys option.
+.It Cm challenge=path
+Specifies a path to a challenge string that will be passed to the
+FIDO token during key generation.
+The challenge string is optional, but may be used as part of an out-of-band
+protocol for key enrollment.
+If no
+.Cm challenge
+is specified, a random challenge is used.
.It Cm resident
Indicate that the key should be stored on the FIDO authenticator itself.
Resident keys may be supported on FIDO2 tokens and typically require that
overriding the empty default username.
Specifying a username may be useful when generating multiple resident keys
for the same application name.
+.It Cm write-attestation=path
+May be used at key generation time to record the attestation certificate
+returned from FIDO tokens during key generation.
+By default this information is discarded.
.El
.Pp
The
-/* $OpenBSD: ssh-keygen.c,v 1.394 2020/01/25 23:13:09 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.395 2020/01/28 08:01:34 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
unsigned long long cert_serial = 0;
char *identity_comment = NULL, *ca_key_path = NULL, **opts = NULL;
char *sk_application = NULL, *sk_device = NULL, *sk_user = NULL;
+ char *sk_attestaion_path = NULL;
+ struct sshbuf *challenge = NULL, *attest = NULL;
size_t i, nopts = 0;
u_int32_t bits = 0;
uint8_t sk_flags = SSH_SK_USER_PRESENCE_REQD;
sk_device = xstrdup(opts[i] + 7);
} else if (strncasecmp(opts[i], "user=", 5) == 0) {
sk_user = xstrdup(opts[i] + 5);
+ } else if (strncasecmp(opts[i], "challenge=", 10) == 0) {
+ if ((r = sshbuf_load_file(opts[i] + 10,
+ &challenge)) != 0) {
+ fatal("Unable to load FIDO enrollment "
+ "challenge \"%s\": %s",
+ opts[i] + 10, ssh_err(r));
+ }
+ } else if (strncasecmp(opts[i],
+ "write-attestation=", 18) == 0) {
+ sk_attestaion_path = opts[i] + 18;
} else if (strncasecmp(opts[i],
"application=", 12) == 0) {
sk_application = xstrdup(opts[i] + 12);
"to authorize key generation.\n");
}
passphrase = NULL;
+ if ((attest = sshbuf_new()) == NULL)
+ fatal("sshbuf_new failed");
for (i = 0 ; i < 3; i++) {
fflush(stdout);
r = sshsk_enroll(type, sk_provider, sk_device,
sk_application == NULL ? "ssh:" : sk_application,
- sk_user, sk_flags, passphrase, NULL,
- &private, NULL);
+ sk_user, sk_flags, passphrase, challenge,
+ &private, attest);
if (r == 0)
break;
if (r != SSH_ERR_KEY_WRONG_PASSPHRASE)
free(fp);
}
+ if (sk_attestaion_path != NULL) {
+ if (attest == NULL || sshbuf_len(attest) == 0) {
+ fatal("Enrollment did not return attestation "
+ "certificate");
+ }
+ if ((r = sshbuf_write_file(sk_attestaion_path, attest)) != 0) {
+ fatal("Unable to write attestation certificate "
+ "\"%s\": %s", sk_attestaion_path, ssh_err(r));
+ }
+ if (!quiet) {
+ printf("Your FIDO attestation certificate has been "
+ "saved in %s\n", sk_attestaion_path);
+ }
+ }
+ sshbuf_free(attest);
sshkey_free(public);
+
exit(0);
}
-/* $OpenBSD: ssh-sk.c,v 1.25 2020/01/25 23:13:09 djm Exp $ */
+/* $OpenBSD: ssh-sk.c,v 1.26 2020/01/28 08:01:34 djm Exp $ */
/*
* Copyright (c) 2019 Google LLC
*
/* Optionally fill in the attestation information */
if (attest != NULL) {
- if ((r = sshbuf_put_cstring(attest, "sk-attest-v00")) != 0 ||
- (r = sshbuf_put_u32(attest, 1)) != 0 || /* XXX U2F ver */
+ if ((r = sshbuf_put_cstring(attest,
+ "ssh-sk-attest-v00")) != 0 ||
(r = sshbuf_put_string(attest,
resp->attestation_cert, resp->attestation_cert_len)) != 0 ||
(r = sshbuf_put_string(attest,
resp->signature, resp->signature_len)) != 0 ||
- (r = sshbuf_put_u32(attest, flags)) != 0 || /* XXX right? */
- (r = sshbuf_put_string(attest, NULL, 0)) != 0) {
+ (r = sshbuf_put_u32(attest, 0)) != 0 || /* resvd flags */
+ (r = sshbuf_put_string(attest, NULL, 0)) != 0 /* resvd */) {
error("%s: buffer error: %s", __func__, ssh_err(r));
goto out;
}