diff options
author | djm@openbsd.org <djm@openbsd.org> | 2019-09-03 08:35:27 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2019-09-03 18:40:24 +1000 |
commit | d637c4aee6f9b5280c13c020d7653444ac1fcaa5 (patch) | |
tree | f4844d9e77f1008b5928f72d5542ec075239dd4e /sshsig.c | |
parent | 2a9c9f7272c1e8665155118fe6536bebdafb6166 (diff) |
upstream: sshsig tweaks and improvements from and suggested by
Markus
ok markus/me
OpenBSD-Commit-ID: ea4f46ad5a16b27af96e08c4877423918c4253e9
Diffstat (limited to 'sshsig.c')
-rw-r--r-- | sshsig.c | 180 |
1 files changed, 96 insertions, 84 deletions
@@ -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 | } |