diff options
-rw-r--r-- | PROTOCOL.u2f | 8 | ||||
-rw-r--r-- | ssh-ed25519-sk.c | 11 | ||||
-rw-r--r-- | ssh-sk.c | 65 |
3 files changed, 39 insertions, 45 deletions
diff --git a/PROTOCOL.u2f b/PROTOCOL.u2f index bd60f9fac..ca55c4297 100644 --- a/PROTOCOL.u2f +++ b/PROTOCOL.u2f | |||
@@ -148,6 +148,14 @@ be reformatted slightly and the ecdsa_signature_blob value has the encoding: | |||
148 | Where 'r' and 's' are extracted by the client or token middleware from the | 148 | Where 'r' and 's' are extracted by the client or token middleware from the |
149 | ecdsa_signature field returned from the hardware. | 149 | ecdsa_signature field returned from the hardware. |
150 | 150 | ||
151 | For Ed25519 keys the signature is encoded as: | ||
152 | |||
153 | string "sk-ssh-ed25519@openssh.com" | ||
154 | string signature | ||
155 | byte flags | ||
156 | uint32 counter | ||
157 | |||
158 | |||
151 | ssh-agent protocol extensions | 159 | ssh-agent protocol extensions |
152 | ----------------------------- | 160 | ----------------------------- |
153 | 161 | ||
diff --git a/ssh-ed25519-sk.c b/ssh-ed25519-sk.c index f42c88303..622cb45c2 100644 --- a/ssh-ed25519-sk.c +++ b/ssh-ed25519-sk.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-ed25519-sk.c,v 1.1 2019/11/12 19:29:24 markus Exp $ */ | 1 | /* $OpenBSD: ssh-ed25519-sk.c,v 1.2 2019/11/12 19:34:40 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2019 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2019 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -36,7 +36,6 @@ ssh_ed25519_sk_verify(const struct sshkey *key, | |||
36 | const u_char *data, size_t datalen, u_int compat) | 36 | const u_char *data, size_t datalen, u_int compat) |
37 | { | 37 | { |
38 | struct sshbuf *b = NULL; | 38 | struct sshbuf *b = NULL; |
39 | struct sshbuf *sigbuf = NULL; | ||
40 | struct sshbuf *encoded = NULL; | 39 | struct sshbuf *encoded = NULL; |
41 | char *ktype = NULL; | 40 | char *ktype = NULL; |
42 | const u_char *sigblob; | 41 | const u_char *sigblob; |
@@ -60,10 +59,9 @@ ssh_ed25519_sk_verify(const struct sshkey *key, | |||
60 | if ((b = sshbuf_from(signature, signaturelen)) == NULL) | 59 | if ((b = sshbuf_from(signature, signaturelen)) == NULL) |
61 | return SSH_ERR_ALLOC_FAIL; | 60 | return SSH_ERR_ALLOC_FAIL; |
62 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || | 61 | if (sshbuf_get_cstring(b, &ktype, NULL) != 0 || |
63 | sshbuf_froms(b, &sigbuf) != 0 || | 62 | sshbuf_get_string_direct(b, &sigblob, &len) != 0 || |
64 | sshbuf_get_string_direct(sigbuf, &sigblob, &len) != 0 || | 63 | sshbuf_get_u8(b, &sig_flags) != 0 || |
65 | sshbuf_get_u8(sigbuf, &sig_flags) != 0 || | 64 | sshbuf_get_u32(b, &sig_counter) != 0) { |
66 | sshbuf_get_u32(sigbuf, &sig_counter) != 0) { | ||
67 | r = SSH_ERR_INVALID_FORMAT; | 65 | r = SSH_ERR_INVALID_FORMAT; |
68 | goto out; | 66 | goto out; |
69 | } | 67 | } |
@@ -123,7 +121,6 @@ ssh_ed25519_sk_verify(const struct sshkey *key, | |||
123 | free(m); | 121 | free(m); |
124 | } | 122 | } |
125 | sshbuf_free(b); | 123 | sshbuf_free(b); |
126 | sshbuf_free(sigbuf); | ||
127 | sshbuf_free(encoded); | 124 | sshbuf_free(encoded); |
128 | free(ktype); | 125 | free(ktype); |
129 | return r; | 126 | return r; |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-sk.c,v 1.8 2019/11/12 19:34:00 markus Exp $ */ | 1 | /* $OpenBSD: ssh-sk.c,v 1.9 2019/11/12 19:34:40 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2019 Google LLC | 3 | * Copyright (c) 2019 Google LLC |
4 | * | 4 | * |
@@ -359,12 +359,11 @@ sshsk_enroll(int type, const char *provider_path, const char *application, | |||
359 | } | 359 | } |
360 | 360 | ||
361 | static int | 361 | static int |
362 | sshsk_ecdsa_inner_sig(struct sk_sign_response *resp, struct sshbuf **retp) | 362 | sshsk_ecdsa_sig(struct sk_sign_response *resp, struct sshbuf *sig) |
363 | { | 363 | { |
364 | struct sshbuf *inner_sig = NULL; | 364 | struct sshbuf *inner_sig = NULL; |
365 | int r = SSH_ERR_INTERNAL_ERROR; | 365 | int r = SSH_ERR_INTERNAL_ERROR; |
366 | 366 | ||
367 | *retp = NULL; | ||
368 | /* Check response validity */ | 367 | /* Check response validity */ |
369 | if (resp->sig_r == NULL || resp->sig_r == NULL) { | 368 | if (resp->sig_r == NULL || resp->sig_r == NULL) { |
370 | error("%s: sk_sign response invalid", __func__); | 369 | error("%s: sk_sign response invalid", __func__); |
@@ -375,7 +374,7 @@ sshsk_ecdsa_inner_sig(struct sk_sign_response *resp, struct sshbuf **retp) | |||
375 | r = SSH_ERR_ALLOC_FAIL; | 374 | r = SSH_ERR_ALLOC_FAIL; |
376 | goto out; | 375 | goto out; |
377 | } | 376 | } |
378 | /* Prepare inner signature object */ | 377 | /* Prepare and append inner signature object */ |
379 | if ((r = sshbuf_put_bignum2_bytes(inner_sig, | 378 | if ((r = sshbuf_put_bignum2_bytes(inner_sig, |
380 | resp->sig_r, resp->sig_r_len)) != 0 || | 379 | resp->sig_r, resp->sig_r_len)) != 0 || |
381 | (r = sshbuf_put_bignum2_bytes(inner_sig, | 380 | (r = sshbuf_put_bignum2_bytes(inner_sig, |
@@ -385,42 +384,39 @@ sshsk_ecdsa_inner_sig(struct sk_sign_response *resp, struct sshbuf **retp) | |||
385 | debug("%s: buffer error: %s", __func__, ssh_err(r)); | 384 | debug("%s: buffer error: %s", __func__, ssh_err(r)); |
386 | goto out; | 385 | goto out; |
387 | } | 386 | } |
387 | if ((r = sshbuf_put_stringb(sig, inner_sig)) != 0) { | ||
388 | debug("%s: buffer error: %s", __func__, ssh_err(r)); | ||
389 | goto out; | ||
390 | } | ||
388 | #ifdef DEBUG_SK | 391 | #ifdef DEBUG_SK |
389 | fprintf(stderr, "%s: sig_r:\n", __func__); | 392 | fprintf(stderr, "%s: sig_r:\n", __func__); |
390 | sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr); | 393 | sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr); |
391 | fprintf(stderr, "%s: sig_s:\n", __func__); | 394 | fprintf(stderr, "%s: sig_s:\n", __func__); |
392 | sshbuf_dump_data(resp->sig_s, resp->sig_s_len, stderr); | 395 | sshbuf_dump_data(resp->sig_s, resp->sig_s_len, stderr); |
396 | fprintf(stderr, "%s: inner:\n", __func__); | ||
397 | sshbuf_dump(inner_sig, stderr); | ||
393 | #endif | 398 | #endif |
394 | *retp = inner_sig; | ||
395 | inner_sig = NULL; | ||
396 | r = 0; | 399 | r = 0; |
397 | out: | 400 | out: |
398 | sshbuf_free(inner_sig); | 401 | sshbuf_free(inner_sig); |
399 | return r; | 402 | return r; |
400 | } | 403 | } |
401 | 404 | ||
402 | static int | 405 | static int |
403 | sshsk_ed25519_inner_sig(struct sk_sign_response *resp, struct sshbuf **retp) | 406 | sshsk_ed25519_sig(struct sk_sign_response *resp, struct sshbuf *sig) |
404 | { | 407 | { |
405 | struct sshbuf *inner_sig = NULL; | ||
406 | int r = SSH_ERR_INTERNAL_ERROR; | 408 | int r = SSH_ERR_INTERNAL_ERROR; |
407 | 409 | ||
408 | *retp = NULL; | ||
409 | /* Check response validity */ | 410 | /* Check response validity */ |
410 | if (resp->sig_r == NULL) { | 411 | if (resp->sig_r == NULL) { |
411 | error("%s: sk_sign response invalid", __func__); | 412 | error("%s: sk_sign response invalid", __func__); |
412 | r = SSH_ERR_INVALID_FORMAT; | 413 | r = SSH_ERR_INVALID_FORMAT; |
413 | goto out; | 414 | goto out; |
414 | } | 415 | } |
415 | if ((inner_sig = sshbuf_new()) == NULL) { | 416 | if ((r = sshbuf_put_string(sig, |
416 | r = SSH_ERR_ALLOC_FAIL; | ||
417 | goto out; | ||
418 | } | ||
419 | /* Prepare inner signature object */ | ||
420 | if ((r = sshbuf_put_string(inner_sig, | ||
421 | resp->sig_r, resp->sig_r_len)) != 0 || | 417 | resp->sig_r, resp->sig_r_len)) != 0 || |
422 | (r = sshbuf_put_u8(inner_sig, resp->flags)) != 0 || | 418 | (r = sshbuf_put_u8(sig, resp->flags)) != 0 || |
423 | (r = sshbuf_put_u32(inner_sig, resp->counter)) != 0) { | 419 | (r = sshbuf_put_u32(sig, resp->counter)) != 0) { |
424 | debug("%s: buffer error: %s", __func__, ssh_err(r)); | 420 | debug("%s: buffer error: %s", __func__, ssh_err(r)); |
425 | goto out; | 421 | goto out; |
426 | } | 422 | } |
@@ -428,12 +424,9 @@ sshsk_ed25519_inner_sig(struct sk_sign_response *resp, struct sshbuf **retp) | |||
428 | fprintf(stderr, "%s: sig_r:\n", __func__); | 424 | fprintf(stderr, "%s: sig_r:\n", __func__); |
429 | sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr); | 425 | sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr); |
430 | #endif | 426 | #endif |
431 | *retp = inner_sig; | ||
432 | inner_sig = NULL; | ||
433 | r = 0; | 427 | r = 0; |
434 | out: | 428 | out: |
435 | sshbuf_free(inner_sig); | 429 | return 0; |
436 | return r; | ||
437 | } | 430 | } |
438 | 431 | ||
439 | int | 432 | int |
@@ -488,34 +481,30 @@ sshsk_sign(const char *provider_path, const struct sshkey *key, | |||
488 | debug("%s: sk_sign failed with code %d", __func__, r); | 481 | debug("%s: sk_sign failed with code %d", __func__, r); |
489 | goto out; | 482 | goto out; |
490 | } | 483 | } |
491 | /* Prepare inner signature object */ | 484 | /* Assemble signature */ |
485 | if ((sig = sshbuf_new()) == NULL) { | ||
486 | r = SSH_ERR_ALLOC_FAIL; | ||
487 | goto out; | ||
488 | } | ||
489 | if ((r = sshbuf_put_cstring(sig, sshkey_ssh_name_plain(key))) != 0) { | ||
490 | debug("%s: buffer error (outer): %s", __func__, ssh_err(r)); | ||
491 | goto out; | ||
492 | } | ||
492 | switch (type) { | 493 | switch (type) { |
493 | case KEY_ECDSA_SK: | 494 | case KEY_ECDSA_SK: |
494 | if ((r = sshsk_ecdsa_inner_sig(resp, &inner_sig)) != 0) | 495 | if ((r = sshsk_ecdsa_sig(resp, sig)) != 0) |
495 | goto out; | 496 | goto out; |
496 | break; | 497 | break; |
497 | case KEY_ED25519_SK: | 498 | case KEY_ED25519_SK: |
498 | if ((r = sshsk_ed25519_inner_sig(resp, &inner_sig)) != 0) | 499 | if ((r = sshsk_ed25519_sig(resp, sig)) != 0) |
499 | goto out; | 500 | goto out; |
500 | break; | 501 | break; |
501 | } | 502 | } |
502 | /* Assemble outer signature */ | ||
503 | if ((sig = sshbuf_new()) == NULL) { | ||
504 | r = SSH_ERR_ALLOC_FAIL; | ||
505 | goto out; | ||
506 | } | ||
507 | if ((r = sshbuf_put_cstring(sig, sshkey_ssh_name_plain(key))) != 0 || | ||
508 | (r = sshbuf_put_stringb(sig, inner_sig)) != 0) { | ||
509 | debug("%s: buffer error (outer): %s", __func__, ssh_err(r)); | ||
510 | goto out; | ||
511 | } | ||
512 | #ifdef DEBUG_SK | 503 | #ifdef DEBUG_SK |
513 | fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n", | 504 | fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n", |
514 | __func__, resp->flags, resp->counter); | 505 | __func__, resp->flags, resp->counter); |
515 | fprintf(stderr, "%s: hashed message:\n", __func__); | 506 | fprintf(stderr, "%s: hashed message:\n", __func__); |
516 | sshbuf_dump_data(message, sizeof(message), stderr); | 507 | sshbuf_dump_data(message, sizeof(message), stderr); |
517 | fprintf(stderr, "%s: inner:\n", __func__); | ||
518 | sshbuf_dump(inner_sig, stderr); | ||
519 | fprintf(stderr, "%s: sigbuf:\n", __func__); | 508 | fprintf(stderr, "%s: sigbuf:\n", __func__); |
520 | sshbuf_dump(sig, stderr); | 509 | sshbuf_dump(sig, stderr); |
521 | #endif | 510 | #endif |