diff options
author | djm@openbsd.org <djm@openbsd.org> | 2020-01-23 23:31:52 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2020-01-25 11:27:29 +1100 |
commit | 72a8bea2d748c8bd7f076a8b39a52082c79ae95f (patch) | |
tree | 14bea4a63d81af371d75708384811f5829a38267 /sshsig.c | |
parent | 0585b5697201f5d8b32e6f1b0fee7e188268d30d (diff) |
upstream: ssh-keygen -Y find-principals fixes based on feedback
from Markus:
use "principals" instead of principal, as allowed_signers lines may list
multiple.
When the signing key is a certificate, emit only principals that match
the certificate principal list.
NB. the command -Y name changes: "find-principal" => "find-principals"
ok markus@
OpenBSD-Commit-ID: ab575946ff9a55624cd4e811bfd338bf3b1d0faf
Diffstat (limited to 'sshsig.c')
-rw-r--r-- | sshsig.c | 74 |
1 files changed, 63 insertions, 11 deletions
@@ -868,13 +868,64 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, | |||
868 | } | 868 | } |
869 | 869 | ||
870 | static int | 870 | static int |
871 | get_matching_principal_from_line(const char *path, u_long linenum, char *line, | 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, | ||
872 | const struct sshkey *sign_key, char **principalsp) | 924 | const struct sshkey *sign_key, char **principalsp) |
873 | { | 925 | { |
874 | struct sshkey *found_key = NULL; | 926 | struct sshkey *found_key = NULL; |
875 | char *principals = NULL; | 927 | char *principals = NULL; |
876 | int r, found = 0; | 928 | int r, found = 0; |
877 | const char *reason = NULL; | ||
878 | struct sshsigopt *sigopts = NULL; | 929 | struct sshsigopt *sigopts = NULL; |
879 | 930 | ||
880 | if (principalsp != NULL) | 931 | if (principalsp != NULL) |
@@ -894,11 +945,12 @@ get_matching_principal_from_line(const char *path, u_long linenum, char *line, | |||
894 | found = 1; | 945 | found = 1; |
895 | } else if (sigopts->ca && sshkey_is_cert(sign_key) && | 946 | } else if (sigopts->ca && sshkey_is_cert(sign_key) && |
896 | sshkey_equal_public(sign_key->cert->signature_key, found_key)) { | 947 | sshkey_equal_public(sign_key->cert->signature_key, found_key)) { |
897 | /* Match of certificate's CA key */ | 948 | /* Remove principals listed in file but not allowed by cert */ |
898 | if ((r = sshkey_cert_check_authority(sign_key, 0, 1, | 949 | if ((r = cert_filter_principals(path, linenum, |
899 | principals, &reason)) != 0) { | 950 | &principals, sign_key)) != 0) { |
900 | error("%s:%lu: certificate not authorized: %s", | 951 | /* error already displayed */ |
901 | path, linenum, reason); | 952 | debug("%s:%lu: cert_filter_principals: %s", |
953 | path, linenum, ssh_err(r)); | ||
902 | goto done; | 954 | goto done; |
903 | } | 955 | } |
904 | debug("%s:%lu: matched certificate CA key", path, linenum); | 956 | debug("%s:%lu: matched certificate CA key", path, linenum); |
@@ -920,8 +972,8 @@ get_matching_principal_from_line(const char *path, u_long linenum, char *line, | |||
920 | } | 972 | } |
921 | 973 | ||
922 | int | 974 | int |
923 | sshsig_find_principal(const char *path, const struct sshkey *sign_key, | 975 | sshsig_find_principals(const char *path, const struct sshkey *sign_key, |
924 | char **principal) | 976 | char **principals) |
925 | { | 977 | { |
926 | FILE *f = NULL; | 978 | FILE *f = NULL; |
927 | char *line = NULL; | 979 | char *line = NULL; |
@@ -939,8 +991,8 @@ sshsig_find_principal(const char *path, const struct sshkey *sign_key, | |||
939 | 991 | ||
940 | while (getline(&line, &linesize, f) != -1) { | 992 | while (getline(&line, &linesize, f) != -1) { |
941 | linenum++; | 993 | linenum++; |
942 | r = get_matching_principal_from_line(path, linenum, line, | 994 | r = get_matching_principals_from_line(path, linenum, line, |
943 | sign_key, principal); | 995 | sign_key, principals); |
944 | free(line); | 996 | free(line); |
945 | line = NULL; | 997 | line = NULL; |
946 | if (r == SSH_ERR_KEY_NOT_FOUND) | 998 | if (r == SSH_ERR_KEY_NOT_FOUND) |