diff options
author | djm@openbsd.org <djm@openbsd.org> | 2020-01-23 02:43:48 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2020-01-23 13:45:24 +1100 |
commit | 56cffcc09f8a2e661d2ba02e61364ae6f998b2b1 (patch) | |
tree | 7056f21f29a73cce790ed19c6118983f1ceb6c7d /sshsig.c | |
parent | 65cf8730de6876a56595eef296e07a86c52534a6 (diff) |
upstream: add a new signature operations "find-principal" to look
up the principal associated with a signature from an allowed-signers file.
Work by Sebastian Kinne; ok dtucker@
OpenBSD-Commit-ID: 6f782cc7e18e38fcfafa62af53246a1dcfe74e5d
Diffstat (limited to 'sshsig.c')
-rw-r--r-- | sshsig.c | 117 |
1 files changed, 117 insertions, 0 deletions
@@ -866,3 +866,120 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, | |||
866 | free(line); | 866 | free(line); |
867 | return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; | 867 | return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; |
868 | } | 868 | } |
869 | |||
870 | static int | ||
871 | get_matching_principal_from_line(const char *path, u_long linenum, char *line, | ||
872 | const struct sshkey *sign_key, char **principalsp) | ||
873 | { | ||
874 | struct sshkey *found_key = NULL; | ||
875 | char *principals = NULL; | ||
876 | int r, found = 0; | ||
877 | const char *reason = NULL; | ||
878 | struct sshsigopt *sigopts = NULL; | ||
879 | |||
880 | if (principalsp != NULL) | ||
881 | *principalsp = NULL; | ||
882 | |||
883 | /* Parse the line */ | ||
884 | if ((r = parse_principals_key_and_options(path, linenum, line, | ||
885 | NULL, &principals, &found_key, &sigopts)) != 0) { | ||
886 | /* error already logged */ | ||
887 | goto done; | ||
888 | } | ||
889 | |||
890 | if (!sigopts->ca && sshkey_equal(found_key, sign_key)) { | ||
891 | /* Exact match of key */ | ||
892 | debug("%s:%lu: matched key", path, linenum); | ||
893 | /* success */ | ||
894 | found = 1; | ||
895 | } else if (sigopts->ca && sshkey_is_cert(sign_key) && | ||
896 | sshkey_equal_public(sign_key->cert->signature_key, found_key)) { | ||
897 | /* Match of certificate's CA key */ | ||
898 | if ((r = sshkey_cert_check_authority(sign_key, 0, 1, | ||
899 | principals, &reason)) != 0) { | ||
900 | error("%s:%lu: certificate not authorized: %s", | ||
901 | path, linenum, reason); | ||
902 | goto done; | ||
903 | } | ||
904 | debug("%s:%lu: matched certificate CA key", path, linenum); | ||
905 | /* success */ | ||
906 | found = 1; | ||
907 | } else { | ||
908 | /* Key didn't match */ | ||
909 | goto done; | ||
910 | } | ||
911 | done: | ||
912 | if (found) { | ||
913 | *principalsp = principals; | ||
914 | principals = NULL; /* transferred */ | ||
915 | } | ||
916 | free(principals); | ||
917 | sshkey_free(found_key); | ||
918 | sshsigopt_free(sigopts); | ||
919 | return found ? 0 : SSH_ERR_KEY_NOT_FOUND; | ||
920 | } | ||
921 | |||
922 | int | ||
923 | sshsig_find_principal(const char *path, const struct sshkey *sign_key, | ||
924 | char **principal) | ||
925 | { | ||
926 | FILE *f = NULL; | ||
927 | char *line = NULL; | ||
928 | size_t linesize = 0; | ||
929 | u_long linenum = 0; | ||
930 | int r, oerrno; | ||
931 | |||
932 | if ((f = fopen(path, "r")) == NULL) { | ||
933 | oerrno = errno; | ||
934 | error("Unable to open allowed keys file \"%s\": %s", | ||
935 | path, strerror(errno)); | ||
936 | errno = oerrno; | ||
937 | return SSH_ERR_SYSTEM_ERROR; | ||
938 | } | ||
939 | |||
940 | while (getline(&line, &linesize, f) != -1) { | ||
941 | linenum++; | ||
942 | r = get_matching_principal_from_line(path, linenum, line, | ||
943 | sign_key, principal); | ||
944 | free(line); | ||
945 | line = NULL; | ||
946 | if (r == SSH_ERR_KEY_NOT_FOUND) | ||
947 | continue; | ||
948 | else if (r == 0) { | ||
949 | /* success */ | ||
950 | fclose(f); | ||
951 | return 0; | ||
952 | } else | ||
953 | break; | ||
954 | } | ||
955 | free(line); | ||
956 | /* Either we hit an error parsing or we simply didn't find the key */ | ||
957 | if (ferror(f) != 0) { | ||
958 | oerrno = errno; | ||
959 | fclose(f); | ||
960 | error("Unable to read allowed keys file \"%s\": %s", | ||
961 | path, strerror(errno)); | ||
962 | errno = oerrno; | ||
963 | return SSH_ERR_SYSTEM_ERROR; | ||
964 | } | ||
965 | fclose(f); | ||
966 | return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; | ||
967 | } | ||
968 | |||
969 | int | ||
970 | sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey) | ||
971 | { | ||
972 | struct sshkey *pk = NULL; | ||
973 | int r = SSH_ERR_SIGNATURE_INVALID; | ||
974 | |||
975 | if (pubkey != NULL) | ||
976 | *pubkey = NULL; | ||
977 | if ((r = sshsig_parse_preamble(signature)) != 0) | ||
978 | return r; | ||
979 | if ((r = sshkey_froms(signature, &pk)) != 0) | ||
980 | return r; | ||
981 | |||
982 | *pubkey = pk; | ||
983 | pk = NULL; | ||
984 | return 0; | ||
985 | } | ||