diff options
-rw-r--r-- | PROTOCOL.sshsig | 4 | ||||
-rw-r--r-- | ssh-keygen.1 | 4 | ||||
-rw-r--r-- | ssh-keygen.c | 10 | ||||
-rw-r--r-- | sshsig.c | 180 | ||||
-rw-r--r-- | sshsig.h | 28 |
5 files changed, 122 insertions, 104 deletions
diff --git a/PROTOCOL.sshsig b/PROTOCOL.sshsig index 806c35da6..720e1f18a 100644 --- a/PROTOCOL.sshsig +++ b/PROTOCOL.sshsig | |||
@@ -8,9 +8,9 @@ At present, only detached and armored signatures are supported. | |||
8 | The Armored SSH signatures consist of a header, a base64 | 8 | The Armored SSH signatures consist of a header, a base64 |
9 | encoded blob, and a footer. | 9 | encoded blob, and a footer. |
10 | 10 | ||
11 | The header is the string “-----BEGIN SSH SIGNATURE-----” | 11 | The header is the string "-----BEGIN SSH SIGNATURE-----" |
12 | followed by a newline. The footer is the string | 12 | followed by a newline. The footer is the string |
13 | “-----END SSH SIGNATURE-----” immediately after a newline. | 13 | "-----END SSH SIGNATURE-----" immediately after a newline. |
14 | 14 | ||
15 | The header MUST be present at the start of every signature. | 15 | The header MUST be present at the start of every signature. |
16 | Files containing the signature MUST start with the header. | 16 | Files containing the signature MUST start with the header. |
diff --git a/ssh-keygen.1 b/ssh-keygen.1 index 93c76ef8a..cbaf29809 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .\" $OpenBSD: ssh-keygen.1,v 1.163 2019/09/03 08:34:19 djm Exp $ | 1 | .\" $OpenBSD: ssh-keygen.1,v 1.164 2019/09/03 08:35:27 djm Exp $ |
2 | .\" | 2 | .\" |
3 | .\" Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | .\" Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | .\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -986,7 +986,7 @@ Indicates that this key is accepted as a certificate authority (CA) and | |||
986 | that certificates signed by this CA may be accepted for verification. | 986 | that certificates signed by this CA may be accepted for verification. |
987 | .It Cm namespaces="namespace-list" | 987 | .It Cm namespaces="namespace-list" |
988 | Specifies a pattern-list of namespaces that are accepted for this key. | 988 | Specifies a pattern-list of namespaces that are accepted for this key. |
989 | If this option is present, the the signature namespace embedded in the | 989 | If this option is present, the signature namespace embedded in the |
990 | signature object and presented on the verification command-line must | 990 | signature object and presented on the verification command-line must |
991 | match the specified list before the key will be considered acceptable. | 991 | match the specified list before the key will be considered acceptable. |
992 | .El | 992 | .El |
diff --git a/ssh-keygen.c b/ssh-keygen.c index 76bc41b2f..527cfcf63 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.344 2019/09/03 08:34:19 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.345 2019/09/03 08:35:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -2659,10 +2659,10 @@ verify(const char *signature, const char *sig_namespace, const char *principal, | |||
2659 | fp = NULL; | 2659 | fp = NULL; |
2660 | 2660 | ||
2661 | if (revoked_keys != NULL) { | 2661 | if (revoked_keys != NULL) { |
2662 | if ((r = sshkey_check_revoked(sign_key, revoked_keys)) != 0) { | 2662 | if ((r = sshkey_check_revoked(sign_key, revoked_keys)) != 0) { |
2663 | debug3("sshkey_check_revoked failed: %s", ssh_err(r)); | 2663 | debug3("sshkey_check_revoked failed: %s", ssh_err(r)); |
2664 | goto done; | 2664 | goto done; |
2665 | } | 2665 | } |
2666 | } | 2666 | } |
2667 | 2667 | ||
2668 | if ((r = sshsig_check_allowed_keys(allowed_keys, sign_key, | 2668 | if ((r = sshsig_check_allowed_keys(allowed_keys, sign_key, |
@@ -230,7 +230,7 @@ sshsig_parse_preamble(struct sshbuf *buf) | |||
230 | return r; | 230 | return r; |
231 | } | 231 | } |
232 | 232 | ||
233 | if (sversion < SIG_VERSION) { | 233 | if (sversion > SIG_VERSION) { |
234 | error("Signature version %lu is larger than supported " | 234 | error("Signature version %lu is larger than supported " |
235 | "version %u", (unsigned long)sversion, SIG_VERSION); | 235 | "version %u", (unsigned long)sversion, SIG_VERSION); |
236 | return SSH_ERR_INVALID_FORMAT; | 236 | return SSH_ERR_INVALID_FORMAT; |
@@ -241,7 +241,8 @@ sshsig_parse_preamble(struct sshbuf *buf) | |||
241 | static int | 241 | static int |
242 | sshsig_check_hashalg(const char *hashalg) | 242 | sshsig_check_hashalg(const char *hashalg) |
243 | { | 243 | { |
244 | if (match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1) | 244 | if (hashalg == NULL || |
245 | match_pattern_list(hashalg, HASHALG_ALLOWED, 0) == 1) | ||
245 | return 0; | 246 | return 0; |
246 | error("%s: unsupported hash algorithm \"%.100s\"", __func__, hashalg); | 247 | error("%s: unsupported hash algorithm \"%.100s\"", __func__, hashalg); |
247 | return SSH_ERR_SIGN_ALG_UNSUPPORTED; | 248 | return SSH_ERR_SIGN_ALG_UNSUPPORTED; |
@@ -268,8 +269,6 @@ sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp) | |||
268 | error("Couldn't parse signature blob: %s", ssh_err(r)); | 269 | error("Couldn't parse signature blob: %s", ssh_err(r)); |
269 | goto done; | 270 | goto done; |
270 | } | 271 | } |
271 | if ((r = sshsig_check_hashalg(hashalg)) != 0) | ||
272 | goto done; | ||
273 | 272 | ||
274 | /* success */ | 273 | /* success */ |
275 | r = 0; | 274 | r = 0; |
@@ -293,6 +292,7 @@ sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg, | |||
293 | char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL; | 292 | char *got_namespace = NULL, *sigtype = NULL, *sig_hashalg = NULL; |
294 | size_t siglen; | 293 | size_t siglen; |
295 | 294 | ||
295 | debug("%s: verify message length %zu", __func__, sshbuf_len(h_message)); | ||
296 | if (sign_keyp != NULL) | 296 | if (sign_keyp != NULL) |
297 | *sign_keyp = NULL; | 297 | *sign_keyp = NULL; |
298 | 298 | ||
@@ -301,9 +301,6 @@ sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg, | |||
301 | r = SSH_ERR_ALLOC_FAIL; | 301 | r = SSH_ERR_ALLOC_FAIL; |
302 | goto done; | 302 | goto done; |
303 | } | 303 | } |
304 | if ((r = sshsig_check_hashalg(hashalg)) != 0) | ||
305 | goto done; | ||
306 | |||
307 | if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE, | 304 | if ((r = sshbuf_put(toverify, MAGIC_PREAMBLE, |
308 | MAGIC_PREAMBLE_LEN)) != 0 || | 305 | MAGIC_PREAMBLE_LEN)) != 0 || |
309 | (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 || | 306 | (r = sshbuf_put_cstring(toverify, expect_namespace)) != 0 || |
@@ -382,36 +379,65 @@ done: | |||
382 | return r; | 379 | return r; |
383 | } | 380 | } |
384 | 381 | ||
385 | int | 382 | static int |
386 | sshsig_sign_message(struct sshkey *key, const char *hashalg, | 383 | hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp) |
387 | const struct sshbuf *message, const char *sig_namespace, | ||
388 | struct sshbuf **out, sshsig_signer *signer, void *signer_ctx) | ||
389 | { | 384 | { |
390 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | 385 | char *hex, hash[SSH_DIGEST_MAX_LENGTH]; |
391 | struct sshbuf *b = NULL; | ||
392 | int alg, r = SSH_ERR_INTERNAL_ERROR; | 386 | int alg, r = SSH_ERR_INTERNAL_ERROR; |
387 | struct sshbuf *b = NULL; | ||
393 | 388 | ||
394 | if (out != NULL) | 389 | *bp = NULL; |
395 | *out = NULL; | 390 | memset(hash, 0, sizeof(hash)); |
396 | if (hashalg == NULL) | ||
397 | hashalg = HASHALG_DEFAULT; | ||
398 | 391 | ||
399 | if ((r = sshsig_check_hashalg(hashalg)) != 0) | 392 | if ((r = sshsig_check_hashalg(hashalg)) != 0) |
400 | return r; | 393 | return r; |
401 | if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { | 394 | if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { |
402 | error("%s: can't look up hash algorithm %s", | 395 | error("%s: can't look up hash algorithm %s", |
403 | __func__, HASHALG_DEFAULT); | 396 | __func__, hashalg); |
404 | return SSH_ERR_INTERNAL_ERROR; | 397 | return SSH_ERR_INTERNAL_ERROR; |
405 | } | 398 | } |
406 | if ((r = ssh_digest_buffer(alg, message, hash, sizeof(hash))) != 0) { | 399 | if ((r = ssh_digest_buffer(alg, m, hash, sizeof(hash))) != 0) { |
407 | error("%s: ssh_digest_buffer failed: %s", __func__, ssh_err(r)); | 400 | error("%s: ssh_digest_buffer failed: %s", __func__, ssh_err(r)); |
408 | return r; | 401 | return r; |
409 | } | 402 | } |
410 | if ((b = sshbuf_from(hash, ssh_digest_bytes(alg))) == NULL) { | 403 | if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) { |
411 | error("%s: sshbuf_from failed", __func__); | 404 | debug3("%s: final hash: %s", __func__, hex); |
405 | freezero(hex, strlen(hex)); | ||
406 | } | ||
407 | if ((b = sshbuf_new()) == NULL) { | ||
412 | r = SSH_ERR_ALLOC_FAIL; | 408 | r = SSH_ERR_ALLOC_FAIL; |
413 | goto out; | 409 | goto out; |
414 | } | 410 | } |
411 | if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) { | ||
412 | error("%s: sshbuf_put: %s", __func__, ssh_err(r)); | ||
413 | goto out; | ||
414 | } | ||
415 | *bp = b; | ||
416 | b = NULL; /* transferred */ | ||
417 | /* success */ | ||
418 | r = 0; | ||
419 | out: | ||
420 | sshbuf_free(b); | ||
421 | explicit_bzero(hash, sizeof(hash)); | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | int | ||
426 | sshsig_signb(struct sshkey *key, const char *hashalg, | ||
427 | const struct sshbuf *message, const char *sig_namespace, | ||
428 | struct sshbuf **out, sshsig_signer *signer, void *signer_ctx) | ||
429 | { | ||
430 | struct sshbuf *b = NULL; | ||
431 | int r = SSH_ERR_INTERNAL_ERROR; | ||
432 | |||
433 | if (hashalg == NULL) | ||
434 | hashalg = HASHALG_DEFAULT; | ||
435 | if (out != NULL) | ||
436 | *out = NULL; | ||
437 | if ((r = hash_buffer(message, hashalg, &b)) != 0) { | ||
438 | error("%s: hash_buffer failed: %s", __func__, ssh_err(r)); | ||
439 | goto out; | ||
440 | } | ||
415 | if ((r = sshsig_wrap_sign(key, hashalg, b, sig_namespace, out, | 441 | if ((r = sshsig_wrap_sign(key, hashalg, b, sig_namespace, out, |
416 | signer, signer_ctx)) != 0) | 442 | signer, signer_ctx)) != 0) |
417 | goto out; | 443 | goto out; |
@@ -419,17 +445,15 @@ sshsig_sign_message(struct sshkey *key, const char *hashalg, | |||
419 | r = 0; | 445 | r = 0; |
420 | out: | 446 | out: |
421 | sshbuf_free(b); | 447 | sshbuf_free(b); |
422 | explicit_bzero(hash, sizeof(hash)); | ||
423 | return r; | 448 | return r; |
424 | } | 449 | } |
425 | 450 | ||
426 | int | 451 | int |
427 | sshsig_verify_message(struct sshbuf *signature, const struct sshbuf *message, | 452 | sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message, |
428 | const char *expect_namespace, struct sshkey **sign_keyp) | 453 | const char *expect_namespace, struct sshkey **sign_keyp) |
429 | { | 454 | { |
430 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
431 | struct sshbuf *b = NULL; | 455 | struct sshbuf *b = NULL; |
432 | int alg, r = SSH_ERR_INTERNAL_ERROR; | 456 | int r = SSH_ERR_INTERNAL_ERROR; |
433 | char *hashalg = NULL; | 457 | char *hashalg = NULL; |
434 | 458 | ||
435 | if (sign_keyp != NULL) | 459 | if (sign_keyp != NULL) |
@@ -437,18 +461,9 @@ sshsig_verify_message(struct sshbuf *signature, const struct sshbuf *message, | |||
437 | 461 | ||
438 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) | 462 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) |
439 | return r; | 463 | return r; |
440 | if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { | 464 | debug("%s: signature made with hash \"%s\"", __func__, hashalg); |
441 | error("%s: can't look up hash algorithm %s", | 465 | if ((r = hash_buffer(message, hashalg, &b)) != 0) { |
442 | __func__, HASHALG_DEFAULT); | 466 | error("%s: hash_buffer failed: %s", __func__, ssh_err(r)); |
443 | return SSH_ERR_INTERNAL_ERROR; | ||
444 | } | ||
445 | if ((r = ssh_digest_buffer(alg, message, hash, sizeof(hash))) != 0) { | ||
446 | error("%s: ssh_digest_buffer failed: %s", __func__, ssh_err(r)); | ||
447 | goto out; | ||
448 | } | ||
449 | if ((b = sshbuf_from(hash, ssh_digest_bytes(alg))) == NULL) { | ||
450 | error("%s: sshbuf_from failed", __func__); | ||
451 | r = SSH_ERR_ALLOC_FAIL; | ||
452 | goto out; | 467 | goto out; |
453 | } | 468 | } |
454 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, | 469 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, |
@@ -459,20 +474,29 @@ sshsig_verify_message(struct sshbuf *signature, const struct sshbuf *message, | |||
459 | out: | 474 | out: |
460 | sshbuf_free(b); | 475 | sshbuf_free(b); |
461 | free(hashalg); | 476 | free(hashalg); |
462 | explicit_bzero(hash, sizeof(hash)); | ||
463 | return r; | 477 | return r; |
464 | } | 478 | } |
465 | 479 | ||
466 | static int | 480 | static int |
467 | hash_file(int fd, int hashalg, u_char *hash, size_t hashlen) | 481 | hash_file(int fd, const char *hashalg, struct sshbuf **bp) |
468 | { | 482 | { |
469 | char *hex, rbuf[8192]; | 483 | char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH]; |
470 | ssize_t n, total = 0; | 484 | ssize_t n, total = 0; |
471 | struct ssh_digest_ctx *ctx; | 485 | struct ssh_digest_ctx *ctx; |
472 | int r, oerrno; | 486 | int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR; |
487 | struct sshbuf *b = NULL; | ||
488 | |||
489 | *bp = NULL; | ||
490 | memset(hash, 0, sizeof(hash)); | ||
473 | 491 | ||
474 | memset(hash, 0, hashlen); | 492 | if ((r = sshsig_check_hashalg(hashalg)) != 0) |
475 | if ((ctx = ssh_digest_start(hashalg)) == NULL) { | 493 | return r; |
494 | if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { | ||
495 | error("%s: can't look up hash algorithm %s", | ||
496 | __func__, hashalg); | ||
497 | return SSH_ERR_INTERNAL_ERROR; | ||
498 | } | ||
499 | if ((ctx = ssh_digest_start(alg)) == NULL) { | ||
476 | error("%s: ssh_digest_start failed", __func__); | 500 | error("%s: ssh_digest_start failed", __func__); |
477 | return SSH_ERR_INTERNAL_ERROR; | 501 | return SSH_ERR_INTERNAL_ERROR; |
478 | } | 502 | } |
@@ -484,7 +508,8 @@ hash_file(int fd, int hashalg, u_char *hash, size_t hashlen) | |||
484 | error("%s: read: %s", __func__, strerror(errno)); | 508 | error("%s: read: %s", __func__, strerror(errno)); |
485 | ssh_digest_free(ctx); | 509 | ssh_digest_free(ctx); |
486 | errno = oerrno; | 510 | errno = oerrno; |
487 | return SSH_ERR_SYSTEM_ERROR; | 511 | r = SSH_ERR_SYSTEM_ERROR; |
512 | goto out; | ||
488 | } else if (n == 0) { | 513 | } else if (n == 0) { |
489 | debug2("%s: hashed %zu bytes", __func__, total); | 514 | debug2("%s: hashed %zu bytes", __func__, total); |
490 | break; /* EOF */ | 515 | break; /* EOF */ |
@@ -493,20 +518,33 @@ hash_file(int fd, int hashalg, u_char *hash, size_t hashlen) | |||
493 | if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) { | 518 | if ((r = ssh_digest_update(ctx, rbuf, (size_t)n)) != 0) { |
494 | error("%s: ssh_digest_update: %s", | 519 | error("%s: ssh_digest_update: %s", |
495 | __func__, ssh_err(r)); | 520 | __func__, ssh_err(r)); |
496 | ssh_digest_free(ctx); | 521 | goto out; |
497 | return r; | ||
498 | } | 522 | } |
499 | } | 523 | } |
500 | if ((r = ssh_digest_final(ctx, hash, hashlen)) != 0) { | 524 | if ((r = ssh_digest_final(ctx, hash, sizeof(hash))) != 0) { |
501 | error("%s: ssh_digest_final: %s", __func__, ssh_err(r)); | 525 | error("%s: ssh_digest_final: %s", __func__, ssh_err(r)); |
502 | ssh_digest_free(ctx); | 526 | goto out; |
503 | } | 527 | } |
504 | if ((hex = tohex(hash, hashlen)) != NULL) { | 528 | if ((hex = tohex(hash, ssh_digest_bytes(alg))) != NULL) { |
505 | debug3("%s: final hash: %s", __func__, hex); | 529 | debug3("%s: final hash: %s", __func__, hex); |
506 | freezero(hex, strlen(hex)); | 530 | freezero(hex, strlen(hex)); |
507 | } | 531 | } |
532 | if ((b = sshbuf_new()) == NULL) { | ||
533 | r = SSH_ERR_ALLOC_FAIL; | ||
534 | goto out; | ||
535 | } | ||
536 | if ((r = sshbuf_put(b, hash, ssh_digest_bytes(alg))) != 0) { | ||
537 | error("%s: sshbuf_put: %s", __func__, ssh_err(r)); | ||
538 | goto out; | ||
539 | } | ||
540 | *bp = b; | ||
541 | b = NULL; /* transferred */ | ||
508 | /* success */ | 542 | /* success */ |
543 | r = 0; | ||
544 | out: | ||
545 | sshbuf_free(b); | ||
509 | ssh_digest_free(ctx); | 546 | ssh_digest_free(ctx); |
547 | explicit_bzero(hash, sizeof(hash)); | ||
510 | return 0; | 548 | return 0; |
511 | } | 549 | } |
512 | 550 | ||
@@ -515,31 +553,17 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, | |||
515 | int fd, const char *sig_namespace, struct sshbuf **out, | 553 | int fd, const char *sig_namespace, struct sshbuf **out, |
516 | sshsig_signer *signer, void *signer_ctx) | 554 | sshsig_signer *signer, void *signer_ctx) |
517 | { | 555 | { |
518 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
519 | struct sshbuf *b = NULL; | 556 | struct sshbuf *b = NULL; |
520 | int alg, r = SSH_ERR_INTERNAL_ERROR; | 557 | int r = SSH_ERR_INTERNAL_ERROR; |
521 | 558 | ||
559 | if (hashalg == NULL) | ||
560 | hashalg = HASHALG_DEFAULT; | ||
522 | if (out != NULL) | 561 | if (out != NULL) |
523 | *out = NULL; | 562 | *out = NULL; |
524 | if (hashalg == NULL) | 563 | if ((r = hash_file(fd, hashalg, &b)) != 0) { |
525 | hashalg = HASHALG_DEFAULT; | ||
526 | |||
527 | if ((r = sshsig_check_hashalg(hashalg)) != 0) | ||
528 | return r; | ||
529 | if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { | ||
530 | error("%s: can't look up hash algorithm %s", | ||
531 | __func__, HASHALG_DEFAULT); | ||
532 | return SSH_ERR_INTERNAL_ERROR; | ||
533 | } | ||
534 | if ((r = hash_file(fd, alg, hash, sizeof(hash))) != 0) { | ||
535 | error("%s: hash_file failed: %s", __func__, ssh_err(r)); | 564 | error("%s: hash_file failed: %s", __func__, ssh_err(r)); |
536 | return r; | 565 | return r; |
537 | } | 566 | } |
538 | if ((b = sshbuf_from(hash, ssh_digest_bytes(alg))) == NULL) { | ||
539 | error("%s: sshbuf_from failed", __func__); | ||
540 | r = SSH_ERR_ALLOC_FAIL; | ||
541 | goto out; | ||
542 | } | ||
543 | if ((r = sshsig_wrap_sign(key, hashalg, b, sig_namespace, out, | 567 | if ((r = sshsig_wrap_sign(key, hashalg, b, sig_namespace, out, |
544 | signer, signer_ctx)) != 0) | 568 | signer, signer_ctx)) != 0) |
545 | goto out; | 569 | goto out; |
@@ -547,7 +571,6 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, | |||
547 | r = 0; | 571 | r = 0; |
548 | out: | 572 | out: |
549 | sshbuf_free(b); | 573 | sshbuf_free(b); |
550 | explicit_bzero(hash, sizeof(hash)); | ||
551 | return r; | 574 | return r; |
552 | } | 575 | } |
553 | 576 | ||
@@ -555,9 +578,8 @@ int | |||
555 | sshsig_verify_fd(struct sshbuf *signature, int fd, | 578 | sshsig_verify_fd(struct sshbuf *signature, int fd, |
556 | const char *expect_namespace, struct sshkey **sign_keyp) | 579 | const char *expect_namespace, struct sshkey **sign_keyp) |
557 | { | 580 | { |
558 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
559 | struct sshbuf *b = NULL; | 581 | struct sshbuf *b = NULL; |
560 | int alg, r = SSH_ERR_INTERNAL_ERROR; | 582 | int r = SSH_ERR_INTERNAL_ERROR; |
561 | char *hashalg = NULL; | 583 | char *hashalg = NULL; |
562 | 584 | ||
563 | if (sign_keyp != NULL) | 585 | if (sign_keyp != NULL) |
@@ -565,18 +587,9 @@ sshsig_verify_fd(struct sshbuf *signature, int fd, | |||
565 | 587 | ||
566 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) | 588 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) |
567 | return r; | 589 | return r; |
568 | if ((alg = ssh_digest_alg_by_name(hashalg)) == -1) { | 590 | debug("%s: signature made with hash \"%s\"", __func__, hashalg); |
569 | error("%s: can't look up hash algorithm %s", | 591 | if ((r = hash_file(fd, hashalg, &b)) != 0) { |
570 | __func__, HASHALG_DEFAULT); | ||
571 | return SSH_ERR_INTERNAL_ERROR; | ||
572 | } | ||
573 | if ((r = hash_file(fd, alg, hash, sizeof(hash))) != 0) { | ||
574 | error("%s: hash_file failed: %s", __func__, ssh_err(r)); | 592 | error("%s: hash_file failed: %s", __func__, ssh_err(r)); |
575 | return r; | ||
576 | } | ||
577 | if ((b = sshbuf_from(hash, ssh_digest_bytes(alg))) == NULL) { | ||
578 | error("%s: sshbuf_from failed", __func__); | ||
579 | r = SSH_ERR_ALLOC_FAIL; | ||
580 | goto out; | 593 | goto out; |
581 | } | 594 | } |
582 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, | 595 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, |
@@ -587,7 +600,6 @@ sshsig_verify_fd(struct sshbuf *signature, int fd, | |||
587 | out: | 600 | out: |
588 | sshbuf_free(b); | 601 | sshbuf_free(b); |
589 | free(hashalg); | 602 | free(hashalg); |
590 | explicit_bzero(hash, sizeof(hash)); | ||
591 | return r; | 603 | return r; |
592 | } | 604 | } |
593 | 605 | ||
@@ -769,14 +781,14 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, | |||
769 | linenum++; | 781 | linenum++; |
770 | r = check_allowed_keys_line(path, linenum, line, sign_key, | 782 | r = check_allowed_keys_line(path, linenum, line, sign_key, |
771 | principal, sig_namespace); | 783 | principal, sig_namespace); |
784 | free(line); | ||
785 | line = NULL; | ||
772 | if (r == SSH_ERR_KEY_NOT_FOUND) | 786 | if (r == SSH_ERR_KEY_NOT_FOUND) |
773 | continue; | 787 | continue; |
774 | else if (r == 0) { | 788 | else if (r == 0) { |
775 | /* success */ | 789 | /* success */ |
776 | fclose(f); | 790 | fclose(f); |
777 | free(line); | ||
778 | return 0; | 791 | return 0; |
779 | /* XXX continue and check revocation? */ | ||
780 | } else | 792 | } else |
781 | break; | 793 | break; |
782 | } | 794 | } |
@@ -23,16 +23,29 @@ struct sshkey; | |||
23 | typedef int sshsig_signer(struct sshkey *, u_char **, size_t *, | 23 | typedef int sshsig_signer(struct sshkey *, u_char **, size_t *, |
24 | const u_char *, size_t, const char *, u_int, void *); | 24 | const u_char *, size_t, const char *, u_int, void *); |
25 | 25 | ||
26 | /* Buffer-oriented API */ | ||
27 | |||
26 | /* | 28 | /* |
27 | * Creates a detached SSH signature for a given message. | 29 | * Creates a detached SSH signature for a given buffer. |
28 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. | 30 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. |
29 | * out is populated with the detached signature, or NULL on failure. | 31 | * out is populated with the detached signature, or NULL on failure. |
30 | */ | 32 | */ |
31 | int sshsig_sign_message(struct sshkey *key, const char *hashalg, | 33 | int sshsig_signb(struct sshkey *key, const char *hashalg, |
32 | const struct sshbuf *message, const char *sig_namespace, | 34 | const struct sshbuf *message, const char *sig_namespace, |
33 | struct sshbuf **out, sshsig_signer *signer, void *signer_ctx); | 35 | struct sshbuf **out, sshsig_signer *signer, void *signer_ctx); |
34 | 36 | ||
35 | /* | 37 | /* |
38 | * Verifies that a detached signature is valid and optionally returns key | ||
39 | * used to sign via argument. | ||
40 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. | ||
41 | */ | ||
42 | int sshsig_verifyb(struct sshbuf *signature, | ||
43 | const struct sshbuf *message, const char *sig_namespace, | ||
44 | struct sshkey **sign_keyp); | ||
45 | |||
46 | /* File/FD-oriented API */ | ||
47 | |||
48 | /* | ||
36 | * Creates a detached SSH signature for a given file. | 49 | * Creates a detached SSH signature for a given file. |
37 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. | 50 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. |
38 | * out is populated with the detached signature, or NULL on failure. | 51 | * out is populated with the detached signature, or NULL on failure. |
@@ -42,15 +55,6 @@ int sshsig_sign_fd(struct sshkey *key, const char *hashalg, | |||
42 | sshsig_signer *signer, void *signer_ctx); | 55 | sshsig_signer *signer, void *signer_ctx); |
43 | 56 | ||
44 | /* | 57 | /* |
45 | * Verifies that a detached signature is valid and optionally returns key | ||
46 | * used to sign via argument. | ||
47 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. | ||
48 | */ | ||
49 | int sshsig_verify_message(struct sshbuf *signature, | ||
50 | const struct sshbuf *message, const char *sig_namespace, | ||
51 | struct sshkey **sign_keyp); | ||
52 | |||
53 | /* | ||
54 | * Verifies that a detached signature over a file is valid and optionally | 58 | * Verifies that a detached signature over a file is valid and optionally |
55 | * returns key used to sign via argument. | 59 | * returns key used to sign via argument. |
56 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. | 60 | * Returns 0 on success or a negative SSH_ERR_* error code on failure. |
@@ -58,6 +62,8 @@ int sshsig_verify_message(struct sshbuf *signature, | |||
58 | int sshsig_verify_fd(struct sshbuf *signature, int fd, | 62 | int sshsig_verify_fd(struct sshbuf *signature, int fd, |
59 | const char *sig_namespace, struct sshkey **sign_keyp); | 63 | const char *sig_namespace, struct sshkey **sign_keyp); |
60 | 64 | ||
65 | /* Utility functions */ | ||
66 | |||
61 | /* | 67 | /* |
62 | * Return a base64 encoded "ASCII armoured" version of a raw signature. | 68 | * Return a base64 encoded "ASCII armoured" version of a raw signature. |
63 | */ | 69 | */ |