diff options
author | Colin Watson <cjwatson@debian.org> | 2020-02-21 11:57:14 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2020-02-21 14:27:02 +0000 |
commit | 886e47e745586c34e81cfd5c5fb9b5dbc8e84d04 (patch) | |
tree | dd6c3b4dc64a17c520af7aaf213163f8a0a63e56 /sshsig.c | |
parent | ac2b4c0697fcac554041ab95f81736887eadf6ec (diff) | |
parent | a2dabf35ce0228c86a288d11cc847a9d9801604f (diff) |
New upstream release (8.2p1)
Diffstat (limited to 'sshsig.c')
-rw-r--r-- | sshsig.c | 326 |
1 files changed, 281 insertions, 45 deletions
@@ -151,8 +151,9 @@ done: | |||
151 | 151 | ||
152 | static int | 152 | static int |
153 | sshsig_wrap_sign(struct sshkey *key, const char *hashalg, | 153 | sshsig_wrap_sign(struct sshkey *key, const char *hashalg, |
154 | const struct sshbuf *h_message, const char *sig_namespace, | 154 | const char *sk_provider, const struct sshbuf *h_message, |
155 | struct sshbuf **out, sshsig_signer *signer, void *signer_ctx) | 155 | const char *sig_namespace, struct sshbuf **out, |
156 | sshsig_signer *signer, void *signer_ctx) | ||
156 | { | 157 | { |
157 | int r; | 158 | int r; |
158 | size_t slen = 0; | 159 | size_t slen = 0; |
@@ -184,14 +185,14 @@ sshsig_wrap_sign(struct sshkey *key, const char *hashalg, | |||
184 | if (signer != NULL) { | 185 | if (signer != NULL) { |
185 | if ((r = signer(key, &sig, &slen, | 186 | if ((r = signer(key, &sig, &slen, |
186 | sshbuf_ptr(tosign), sshbuf_len(tosign), | 187 | sshbuf_ptr(tosign), sshbuf_len(tosign), |
187 | sign_alg, 0, signer_ctx)) != 0) { | 188 | sign_alg, sk_provider, 0, signer_ctx)) != 0) { |
188 | error("Couldn't sign message: %s", ssh_err(r)); | 189 | error("Couldn't sign message: %s", ssh_err(r)); |
189 | goto done; | 190 | goto done; |
190 | } | 191 | } |
191 | } else { | 192 | } else { |
192 | if ((r = sshkey_sign(key, &sig, &slen, | 193 | if ((r = sshkey_sign(key, &sig, &slen, |
193 | sshbuf_ptr(tosign), sshbuf_len(tosign), | 194 | sshbuf_ptr(tosign), sshbuf_len(tosign), |
194 | sign_alg, 0)) != 0) { | 195 | sign_alg, sk_provider, 0)) != 0) { |
195 | error("Couldn't sign message: %s", ssh_err(r)); | 196 | error("Couldn't sign message: %s", ssh_err(r)); |
196 | goto done; | 197 | goto done; |
197 | } | 198 | } |
@@ -285,7 +286,7 @@ sshsig_peek_hashalg(struct sshbuf *signature, char **hashalgp) | |||
285 | static int | 286 | static int |
286 | sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg, | 287 | sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg, |
287 | const struct sshbuf *h_message, const char *expect_namespace, | 288 | const struct sshbuf *h_message, const char *expect_namespace, |
288 | struct sshkey **sign_keyp) | 289 | struct sshkey **sign_keyp, struct sshkey_sig_details **sig_details) |
289 | { | 290 | { |
290 | int r = SSH_ERR_INTERNAL_ERROR; | 291 | int r = SSH_ERR_INTERNAL_ERROR; |
291 | struct sshbuf *buf = NULL, *toverify = NULL; | 292 | struct sshbuf *buf = NULL, *toverify = NULL; |
@@ -295,6 +296,8 @@ sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg, | |||
295 | size_t siglen; | 296 | size_t siglen; |
296 | 297 | ||
297 | debug("%s: verify message length %zu", __func__, sshbuf_len(h_message)); | 298 | debug("%s: verify message length %zu", __func__, sshbuf_len(h_message)); |
299 | if (sig_details != NULL) | ||
300 | *sig_details = NULL; | ||
298 | if (sign_keyp != NULL) | 301 | if (sign_keyp != NULL) |
299 | *sign_keyp = NULL; | 302 | *sign_keyp = NULL; |
300 | 303 | ||
@@ -360,7 +363,7 @@ sshsig_wrap_verify(struct sshbuf *signature, const char *hashalg, | |||
360 | } | 363 | } |
361 | } | 364 | } |
362 | if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify), | 365 | if ((r = sshkey_verify(key, sig, siglen, sshbuf_ptr(toverify), |
363 | sshbuf_len(toverify), NULL, 0)) != 0) { | 366 | sshbuf_len(toverify), NULL, 0, sig_details)) != 0) { |
364 | error("Signature verification failed: %s", ssh_err(r)); | 367 | error("Signature verification failed: %s", ssh_err(r)); |
365 | goto done; | 368 | goto done; |
366 | } | 369 | } |
@@ -425,7 +428,7 @@ hash_buffer(const struct sshbuf *m, const char *hashalg, struct sshbuf **bp) | |||
425 | } | 428 | } |
426 | 429 | ||
427 | int | 430 | int |
428 | sshsig_signb(struct sshkey *key, const char *hashalg, | 431 | sshsig_signb(struct sshkey *key, const char *hashalg, const char *sk_provider, |
429 | const struct sshbuf *message, const char *sig_namespace, | 432 | const struct sshbuf *message, const char *sig_namespace, |
430 | struct sshbuf **out, sshsig_signer *signer, void *signer_ctx) | 433 | struct sshbuf **out, sshsig_signer *signer, void *signer_ctx) |
431 | { | 434 | { |
@@ -440,8 +443,8 @@ sshsig_signb(struct sshkey *key, const char *hashalg, | |||
440 | error("%s: hash_buffer failed: %s", __func__, ssh_err(r)); | 443 | error("%s: hash_buffer failed: %s", __func__, ssh_err(r)); |
441 | goto out; | 444 | goto out; |
442 | } | 445 | } |
443 | if ((r = sshsig_wrap_sign(key, hashalg, b, sig_namespace, out, | 446 | if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b, |
444 | signer, signer_ctx)) != 0) | 447 | sig_namespace, out, signer, signer_ctx)) != 0) |
445 | goto out; | 448 | goto out; |
446 | /* success */ | 449 | /* success */ |
447 | r = 0; | 450 | r = 0; |
@@ -452,15 +455,17 @@ sshsig_signb(struct sshkey *key, const char *hashalg, | |||
452 | 455 | ||
453 | int | 456 | int |
454 | sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message, | 457 | sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message, |
455 | const char *expect_namespace, struct sshkey **sign_keyp) | 458 | const char *expect_namespace, struct sshkey **sign_keyp, |
459 | struct sshkey_sig_details **sig_details) | ||
456 | { | 460 | { |
457 | struct sshbuf *b = NULL; | 461 | struct sshbuf *b = NULL; |
458 | int r = SSH_ERR_INTERNAL_ERROR; | 462 | int r = SSH_ERR_INTERNAL_ERROR; |
459 | char *hashalg = NULL; | 463 | char *hashalg = NULL; |
460 | 464 | ||
465 | if (sig_details != NULL) | ||
466 | *sig_details = NULL; | ||
461 | if (sign_keyp != NULL) | 467 | if (sign_keyp != NULL) |
462 | *sign_keyp = NULL; | 468 | *sign_keyp = NULL; |
463 | |||
464 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) | 469 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) |
465 | return r; | 470 | return r; |
466 | debug("%s: signature made with hash \"%s\"", __func__, hashalg); | 471 | debug("%s: signature made with hash \"%s\"", __func__, hashalg); |
@@ -469,7 +474,7 @@ sshsig_verifyb(struct sshbuf *signature, const struct sshbuf *message, | |||
469 | goto out; | 474 | goto out; |
470 | } | 475 | } |
471 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, | 476 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, |
472 | sign_keyp)) != 0) | 477 | sign_keyp, sig_details)) != 0) |
473 | goto out; | 478 | goto out; |
474 | /* success */ | 479 | /* success */ |
475 | r = 0; | 480 | r = 0; |
@@ -551,7 +556,7 @@ hash_file(int fd, const char *hashalg, struct sshbuf **bp) | |||
551 | } | 556 | } |
552 | 557 | ||
553 | int | 558 | int |
554 | sshsig_sign_fd(struct sshkey *key, const char *hashalg, | 559 | sshsig_sign_fd(struct sshkey *key, const char *hashalg, const char *sk_provider, |
555 | int fd, const char *sig_namespace, struct sshbuf **out, | 560 | int fd, const char *sig_namespace, struct sshbuf **out, |
556 | sshsig_signer *signer, void *signer_ctx) | 561 | sshsig_signer *signer, void *signer_ctx) |
557 | { | 562 | { |
@@ -566,8 +571,8 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, | |||
566 | error("%s: hash_file failed: %s", __func__, ssh_err(r)); | 571 | error("%s: hash_file failed: %s", __func__, ssh_err(r)); |
567 | return r; | 572 | return r; |
568 | } | 573 | } |
569 | if ((r = sshsig_wrap_sign(key, hashalg, b, sig_namespace, out, | 574 | if ((r = sshsig_wrap_sign(key, hashalg, sk_provider, b, |
570 | signer, signer_ctx)) != 0) | 575 | sig_namespace, out, signer, signer_ctx)) != 0) |
571 | goto out; | 576 | goto out; |
572 | /* success */ | 577 | /* success */ |
573 | r = 0; | 578 | r = 0; |
@@ -578,15 +583,17 @@ sshsig_sign_fd(struct sshkey *key, const char *hashalg, | |||
578 | 583 | ||
579 | int | 584 | int |
580 | sshsig_verify_fd(struct sshbuf *signature, int fd, | 585 | sshsig_verify_fd(struct sshbuf *signature, int fd, |
581 | const char *expect_namespace, struct sshkey **sign_keyp) | 586 | const char *expect_namespace, struct sshkey **sign_keyp, |
587 | struct sshkey_sig_details **sig_details) | ||
582 | { | 588 | { |
583 | struct sshbuf *b = NULL; | 589 | struct sshbuf *b = NULL; |
584 | int r = SSH_ERR_INTERNAL_ERROR; | 590 | int r = SSH_ERR_INTERNAL_ERROR; |
585 | char *hashalg = NULL; | 591 | char *hashalg = NULL; |
586 | 592 | ||
593 | if (sig_details != NULL) | ||
594 | *sig_details = NULL; | ||
587 | if (sign_keyp != NULL) | 595 | if (sign_keyp != NULL) |
588 | *sign_keyp = NULL; | 596 | *sign_keyp = NULL; |
589 | |||
590 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) | 597 | if ((r = sshsig_peek_hashalg(signature, &hashalg)) != 0) |
591 | return r; | 598 | return r; |
592 | debug("%s: signature made with hash \"%s\"", __func__, hashalg); | 599 | debug("%s: signature made with hash \"%s\"", __func__, hashalg); |
@@ -595,7 +602,7 @@ sshsig_verify_fd(struct sshbuf *signature, int fd, | |||
595 | goto out; | 602 | goto out; |
596 | } | 603 | } |
597 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, | 604 | if ((r = sshsig_wrap_verify(signature, hashalg, b, expect_namespace, |
598 | sign_keyp)) != 0) | 605 | sign_keyp, sig_details)) != 0) |
599 | goto out; | 606 | goto out; |
600 | /* success */ | 607 | /* success */ |
601 | r = 0; | 608 | r = 0; |
@@ -672,56 +679,116 @@ sshsigopt_free(struct sshsigopt *opts) | |||
672 | } | 679 | } |
673 | 680 | ||
674 | static int | 681 | static int |
675 | check_allowed_keys_line(const char *path, u_long linenum, char *line, | 682 | parse_principals_key_and_options(const char *path, u_long linenum, char *line, |
676 | const struct sshkey *sign_key, const char *principal, | 683 | const char *required_principal, char **principalsp, struct sshkey **keyp, |
677 | const char *sig_namespace) | 684 | struct sshsigopt **sigoptsp) |
678 | { | 685 | { |
679 | struct sshkey *found_key = NULL; | 686 | char *opts = NULL, *tmp, *cp, *principals = NULL; |
680 | char *cp, *opts = NULL, *identities = NULL; | ||
681 | int r, found = 0; | ||
682 | const char *reason = NULL; | 687 | const char *reason = NULL; |
683 | struct sshsigopt *sigopts = NULL; | 688 | struct sshsigopt *sigopts = NULL; |
689 | struct sshkey *key = NULL; | ||
690 | int r = SSH_ERR_INTERNAL_ERROR; | ||
684 | 691 | ||
685 | if ((found_key = sshkey_new(KEY_UNSPEC)) == NULL) { | 692 | if (principalsp != NULL) |
686 | error("%s: sshkey_new failed", __func__); | 693 | *principalsp = NULL; |
687 | return SSH_ERR_ALLOC_FAIL; | 694 | if (sigoptsp != NULL) |
688 | } | 695 | *sigoptsp = NULL; |
696 | if (keyp != NULL) | ||
697 | *keyp = NULL; | ||
689 | 698 | ||
690 | /* format: identity[,identity...] [option[,option...]] key */ | ||
691 | cp = line; | 699 | cp = line; |
692 | cp = cp + strspn(cp, " \t"); /* skip leading whitespace */ | 700 | cp = cp + strspn(cp, " \t"); /* skip leading whitespace */ |
693 | if (*cp == '#' || *cp == '\0') | 701 | if (*cp == '#' || *cp == '\0') |
694 | goto done; | 702 | return SSH_ERR_KEY_NOT_FOUND; /* blank or all-comment line */ |
695 | if ((identities = strdelimw(&cp)) == NULL) { | 703 | |
704 | /* format: identity[,identity...] [option[,option...]] key */ | ||
705 | if ((tmp = strdelimw(&cp)) == NULL) { | ||
696 | error("%s:%lu: invalid line", path, linenum); | 706 | error("%s:%lu: invalid line", path, linenum); |
697 | goto done; | 707 | r = SSH_ERR_INVALID_FORMAT; |
708 | goto out; | ||
698 | } | 709 | } |
699 | if (match_pattern_list(principal, identities, 0) != 1) { | 710 | if ((principals = strdup(tmp)) == NULL) { |
700 | /* principal didn't match */ | 711 | error("%s: strdup failed", __func__); |
701 | goto done; | 712 | r = SSH_ERR_ALLOC_FAIL; |
713 | goto out; | ||
714 | } | ||
715 | /* | ||
716 | * Bail out early if we're looking for a particular principal and this | ||
717 | * line does not list it. | ||
718 | */ | ||
719 | if (required_principal != NULL) { | ||
720 | if (match_pattern_list(required_principal, | ||
721 | principals, 0) != 1) { | ||
722 | /* principal didn't match */ | ||
723 | r = SSH_ERR_KEY_NOT_FOUND; | ||
724 | goto out; | ||
725 | } | ||
726 | debug("%s: %s:%lu: matched principal \"%s\"", | ||
727 | __func__, path, linenum, required_principal); | ||
702 | } | 728 | } |
703 | debug("%s: %s:%lu: matched principal \"%s\"", | ||
704 | __func__, path, linenum, principal); | ||
705 | 729 | ||
706 | if (sshkey_read(found_key, &cp) != 0) { | 730 | if ((key = sshkey_new(KEY_UNSPEC)) == NULL) { |
731 | error("%s: sshkey_new failed", __func__); | ||
732 | r = SSH_ERR_ALLOC_FAIL; | ||
733 | goto out; | ||
734 | } | ||
735 | if (sshkey_read(key, &cp) != 0) { | ||
707 | /* no key? Check for options */ | 736 | /* no key? Check for options */ |
708 | opts = cp; | 737 | opts = cp; |
709 | if (sshkey_advance_past_options(&cp) != 0) { | 738 | if (sshkey_advance_past_options(&cp) != 0) { |
710 | error("%s:%lu: invalid options", | 739 | error("%s:%lu: invalid options", path, linenum); |
711 | path, linenum); | 740 | r = SSH_ERR_INVALID_FORMAT; |
712 | goto done; | 741 | goto out; |
713 | } | 742 | } |
714 | *cp++ = '\0'; | 743 | *cp++ = '\0'; |
715 | skip_space(&cp); | 744 | skip_space(&cp); |
716 | if (sshkey_read(found_key, &cp) != 0) { | 745 | if (sshkey_read(key, &cp) != 0) { |
717 | error("%s:%lu: invalid key", path, | 746 | error("%s:%lu: invalid key", path, linenum); |
718 | linenum); | 747 | r = SSH_ERR_INVALID_FORMAT; |
719 | goto done; | 748 | goto out; |
720 | } | 749 | } |
721 | } | 750 | } |
722 | debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts); | 751 | debug3("%s:%lu: options %s", path, linenum, opts == NULL ? "" : opts); |
723 | if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) { | 752 | if ((sigopts = sshsigopt_parse(opts, path, linenum, &reason)) == NULL) { |
724 | error("%s:%lu: bad options: %s", path, linenum, reason); | 753 | error("%s:%lu: bad options: %s", path, linenum, reason); |
754 | r = SSH_ERR_INVALID_FORMAT; | ||
755 | goto out; | ||
756 | } | ||
757 | /* success */ | ||
758 | if (principalsp != NULL) { | ||
759 | *principalsp = principals; | ||
760 | principals = NULL; /* transferred */ | ||
761 | } | ||
762 | if (sigoptsp != NULL) { | ||
763 | *sigoptsp = sigopts; | ||
764 | sigopts = NULL; /* transferred */ | ||
765 | } | ||
766 | if (keyp != NULL) { | ||
767 | *keyp = key; | ||
768 | key = NULL; /* transferred */ | ||
769 | } | ||
770 | r = 0; | ||
771 | out: | ||
772 | free(principals); | ||
773 | sshsigopt_free(sigopts); | ||
774 | sshkey_free(key); | ||
775 | return r; | ||
776 | } | ||
777 | |||
778 | static int | ||
779 | check_allowed_keys_line(const char *path, u_long linenum, char *line, | ||
780 | const struct sshkey *sign_key, const char *principal, | ||
781 | const char *sig_namespace) | ||
782 | { | ||
783 | struct sshkey *found_key = NULL; | ||
784 | int r, found = 0; | ||
785 | const char *reason = NULL; | ||
786 | struct sshsigopt *sigopts = NULL; | ||
787 | |||
788 | /* Parse the line */ | ||
789 | if ((r = parse_principals_key_and_options(path, linenum, line, | ||
790 | principal, NULL, &found_key, &sigopts)) != 0) { | ||
791 | /* error already logged */ | ||
725 | goto done; | 792 | goto done; |
726 | } | 793 | } |
727 | 794 | ||
@@ -799,3 +866,172 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, | |||
799 | free(line); | 866 | free(line); |
800 | return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; | 867 | return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; |
801 | } | 868 | } |
869 | |||
870 | static int | ||
871 | cert_filter_principals(const char *path, u_long linenum, | ||
872 | char **principalsp, const struct sshkey *cert) | ||
873 | { | ||
874 | char *cp, *oprincipals, *principals; | ||
875 | const char *reason; | ||
876 | struct sshbuf *nprincipals; | ||
877 | int r = SSH_ERR_INTERNAL_ERROR, success = 0; | ||
878 | |||
879 | oprincipals = principals = *principalsp; | ||
880 | *principalsp = NULL; | ||
881 | |||
882 | if ((nprincipals = sshbuf_new()) == NULL) | ||
883 | return SSH_ERR_ALLOC_FAIL; | ||
884 | |||
885 | while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') { | ||
886 | if (strcspn(cp, "!?*") != strlen(cp)) { | ||
887 | debug("%s:%lu: principal \"%s\" not authorized: " | ||
888 | "contains wildcards", path, linenum, cp); | ||
889 | continue; | ||
890 | } | ||
891 | /* Check against principals list in certificate */ | ||
892 | if ((r = sshkey_cert_check_authority(cert, 0, 1, | ||
893 | cp, &reason)) != 0) { | ||
894 | debug("%s:%lu: principal \"%s\" not authorized: %s", | ||
895 | path, linenum, cp, reason); | ||
896 | continue; | ||
897 | } | ||
898 | if ((r = sshbuf_putf(nprincipals, "%s%s", | ||
899 | sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) { | ||
900 | error("%s: buffer error", __func__); | ||
901 | goto out; | ||
902 | } | ||
903 | } | ||
904 | if (sshbuf_len(nprincipals) == 0) { | ||
905 | error("%s:%lu: no valid principals found", path, linenum); | ||
906 | r = SSH_ERR_KEY_CERT_INVALID; | ||
907 | goto out; | ||
908 | } | ||
909 | if ((principals = sshbuf_dup_string(nprincipals)) == NULL) { | ||
910 | error("%s: buffer error", __func__); | ||
911 | goto out; | ||
912 | } | ||
913 | /* success */ | ||
914 | success = 1; | ||
915 | *principalsp = principals; | ||
916 | out: | ||
917 | sshbuf_free(nprincipals); | ||
918 | free(oprincipals); | ||
919 | return success ? 0 : r; | ||
920 | } | ||
921 | |||
922 | static int | ||
923 | get_matching_principals_from_line(const char *path, u_long linenum, char *line, | ||
924 | const struct sshkey *sign_key, char **principalsp) | ||
925 | { | ||
926 | struct sshkey *found_key = NULL; | ||
927 | char *principals = NULL; | ||
928 | int r, found = 0; | ||
929 | struct sshsigopt *sigopts = NULL; | ||
930 | |||
931 | if (principalsp != NULL) | ||
932 | *principalsp = NULL; | ||
933 | |||
934 | /* Parse the line */ | ||
935 | if ((r = parse_principals_key_and_options(path, linenum, line, | ||
936 | NULL, &principals, &found_key, &sigopts)) != 0) { | ||
937 | /* error already logged */ | ||
938 | goto done; | ||
939 | } | ||
940 | |||
941 | if (!sigopts->ca && sshkey_equal(found_key, sign_key)) { | ||
942 | /* Exact match of key */ | ||
943 | debug("%s:%lu: matched key", path, linenum); | ||
944 | /* success */ | ||
945 | found = 1; | ||
946 | } else if (sigopts->ca && sshkey_is_cert(sign_key) && | ||
947 | sshkey_equal_public(sign_key->cert->signature_key, found_key)) { | ||
948 | /* Remove principals listed in file but not allowed by cert */ | ||
949 | if ((r = cert_filter_principals(path, linenum, | ||
950 | &principals, sign_key)) != 0) { | ||
951 | /* error already displayed */ | ||
952 | debug("%s:%lu: cert_filter_principals: %s", | ||
953 | path, linenum, ssh_err(r)); | ||
954 | goto done; | ||
955 | } | ||
956 | debug("%s:%lu: matched certificate CA key", path, linenum); | ||
957 | /* success */ | ||
958 | found = 1; | ||
959 | } else { | ||
960 | /* Key didn't match */ | ||
961 | goto done; | ||
962 | } | ||
963 | done: | ||
964 | if (found) { | ||
965 | *principalsp = principals; | ||
966 | principals = NULL; /* transferred */ | ||
967 | } | ||
968 | free(principals); | ||
969 | sshkey_free(found_key); | ||
970 | sshsigopt_free(sigopts); | ||
971 | return found ? 0 : SSH_ERR_KEY_NOT_FOUND; | ||
972 | } | ||
973 | |||
974 | int | ||
975 | sshsig_find_principals(const char *path, const struct sshkey *sign_key, | ||
976 | char **principals) | ||
977 | { | ||
978 | FILE *f = NULL; | ||
979 | char *line = NULL; | ||
980 | size_t linesize = 0; | ||
981 | u_long linenum = 0; | ||
982 | int r, oerrno; | ||
983 | |||
984 | if ((f = fopen(path, "r")) == NULL) { | ||
985 | oerrno = errno; | ||
986 | error("Unable to open allowed keys file \"%s\": %s", | ||
987 | path, strerror(errno)); | ||
988 | errno = oerrno; | ||
989 | return SSH_ERR_SYSTEM_ERROR; | ||
990 | } | ||
991 | |||
992 | while (getline(&line, &linesize, f) != -1) { | ||
993 | linenum++; | ||
994 | r = get_matching_principals_from_line(path, linenum, line, | ||
995 | sign_key, principals); | ||
996 | free(line); | ||
997 | line = NULL; | ||
998 | if (r == SSH_ERR_KEY_NOT_FOUND) | ||
999 | continue; | ||
1000 | else if (r == 0) { | ||
1001 | /* success */ | ||
1002 | fclose(f); | ||
1003 | return 0; | ||
1004 | } else | ||
1005 | break; | ||
1006 | } | ||
1007 | free(line); | ||
1008 | /* Either we hit an error parsing or we simply didn't find the key */ | ||
1009 | if (ferror(f) != 0) { | ||
1010 | oerrno = errno; | ||
1011 | fclose(f); | ||
1012 | error("Unable to read allowed keys file \"%s\": %s", | ||
1013 | path, strerror(errno)); | ||
1014 | errno = oerrno; | ||
1015 | return SSH_ERR_SYSTEM_ERROR; | ||
1016 | } | ||
1017 | fclose(f); | ||
1018 | return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; | ||
1019 | } | ||
1020 | |||
1021 | int | ||
1022 | sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey) | ||
1023 | { | ||
1024 | struct sshkey *pk = NULL; | ||
1025 | int r = SSH_ERR_SIGNATURE_INVALID; | ||
1026 | |||
1027 | if (pubkey != NULL) | ||
1028 | *pubkey = NULL; | ||
1029 | if ((r = sshsig_parse_preamble(signature)) != 0) | ||
1030 | return r; | ||
1031 | if ((r = sshkey_froms(signature, &pk)) != 0) | ||
1032 | return r; | ||
1033 | |||
1034 | *pubkey = pk; | ||
1035 | pk = NULL; | ||
1036 | return 0; | ||
1037 | } | ||