summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2020-01-23 23:31:52 +0000
committerDamien Miller <djm@mindrot.org>2020-01-25 11:27:29 +1100
commit72a8bea2d748c8bd7f076a8b39a52082c79ae95f (patch)
tree14bea4a63d81af371d75708384811f5829a38267
parent0585b5697201f5d8b32e6f1b0fee7e188268d30d (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
-rw-r--r--ssh-keygen.111
-rw-r--r--ssh-keygen.c27
-rw-r--r--sshsig.c74
-rw-r--r--sshsig.h5
4 files changed, 84 insertions, 33 deletions
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 5d33902f7..b4a873920 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keygen.1,v 1.195 2020/01/23 07:16:38 jmc Exp $ 1.\" $OpenBSD: ssh-keygen.1,v 1.196 2020/01/23 23:31:52 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
@@ -138,7 +138,7 @@
138.Fl f Ar krl_file 138.Fl f Ar krl_file
139.Ar 139.Ar
140.Nm ssh-keygen 140.Nm ssh-keygen
141.Fl Y Cm find-principal 141.Fl Y Cm find-principals
142.Fl s Ar signature_file 142.Fl s Ar signature_file
143.Fl f Ar allowed_signers_file 143.Fl f Ar allowed_signers_file
144.Nm ssh-keygen 144.Nm ssh-keygen
@@ -618,8 +618,8 @@ The maximum is 3.
618Specifies a path to a library that will be used when creating 618Specifies a path to a library that will be used when creating
619FIDO authenticator-hosted keys, overriding the default of using 619FIDO authenticator-hosted keys, overriding the default of using
620the internal USB HID support. 620the internal USB HID support.
621.It Fl Y Cm find-principal 621.It Fl Y Cm find-principals
622Find the principal associated with the public key of a signature, 622Find the principal(s) associated with the public key of a signature,
623provided using the 623provided using the
624.Fl s 624.Fl s
625flag in an authorized signers file provided using the 625flag in an authorized signers file provided using the
@@ -628,7 +628,8 @@ flag.
628The format of the allowed signers file is documented in the 628The format of the allowed signers file is documented in the
629.Sx ALLOWED SIGNERS 629.Sx ALLOWED SIGNERS
630section below. 630section below.
631If a matching principal is found, it is returned on standard output. 631If one or more matching principals are found, they are returned on
632standard output.
632.It Fl Y Cm check-novalidate 633.It Fl Y Cm check-novalidate
633Checks that a signature generated using 634Checks that a signature generated using
634.Nm 635.Nm
diff --git a/ssh-keygen.c b/ssh-keygen.c
index ce94a5ab0..363da70db 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.387 2020/01/23 07:54:04 djm Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.388 2020/01/23 23:31:52 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
@@ -2758,11 +2758,11 @@ done:
2758} 2758}
2759 2759
2760static int 2760static int
2761sig_find_principal(const char *signature, const char *allowed_keys) { 2761sig_find_principals(const char *signature, const char *allowed_keys) {
2762 int r, ret = -1, sigfd = -1; 2762 int r, ret = -1, sigfd = -1;
2763 struct sshbuf *sigbuf = NULL, *abuf = NULL; 2763 struct sshbuf *sigbuf = NULL, *abuf = NULL;
2764 struct sshkey *sign_key = NULL; 2764 struct sshkey *sign_key = NULL;
2765 char *principal = NULL; 2765 char *principals = NULL;
2766 2766
2767 if ((abuf = sshbuf_new()) == NULL) 2767 if ((abuf = sshbuf_new()) == NULL)
2768 fatal("%s: sshbuf_new() failed", __func__); 2768 fatal("%s: sshbuf_new() failed", __func__);
@@ -2782,12 +2782,11 @@ sig_find_principal(const char *signature, const char *allowed_keys) {
2782 } 2782 }
2783 if ((r = sshsig_get_pubkey(sigbuf, &sign_key)) != 0) { 2783 if ((r = sshsig_get_pubkey(sigbuf, &sign_key)) != 0) {
2784 error("%s: sshsig_get_pubkey: %s", 2784 error("%s: sshsig_get_pubkey: %s",
2785 __func__, ssh_err(r)); 2785 __func__, ssh_err(r));
2786 goto done; 2786 goto done;
2787 } 2787 }
2788 2788 if ((r = sshsig_find_principals(allowed_keys, sign_key,
2789 if ((r = sshsig_find_principal(allowed_keys, sign_key, 2789 &principals)) != 0) {
2790 &principal)) != 0) {
2791 error("%s: sshsig_get_principal: %s", 2790 error("%s: sshsig_get_principal: %s",
2792 __func__, ssh_err(r)); 2791 __func__, ssh_err(r));
2793 goto done; 2792 goto done;
@@ -2795,7 +2794,7 @@ sig_find_principal(const char *signature, const char *allowed_keys) {
2795 ret = 0; 2794 ret = 0;
2796done: 2795done:
2797 if (ret == 0 ) { 2796 if (ret == 0 ) {
2798 printf("Found matching principal: %s\n", principal); 2797 printf("Found matching principal: %s\n", principals);
2799 } else { 2798 } else {
2800 printf("Could not find matching principal.\n"); 2799 printf("Could not find matching principal.\n");
2801 } 2800 }
@@ -2804,7 +2803,7 @@ done:
2804 sshbuf_free(sigbuf); 2803 sshbuf_free(sigbuf);
2805 sshbuf_free(abuf); 2804 sshbuf_free(abuf);
2806 sshkey_free(sign_key); 2805 sshkey_free(sign_key);
2807 free(principal); 2806 free(principals);
2808 return ret; 2807 return ret;
2809} 2808}
2810 2809
@@ -3093,7 +3092,7 @@ usage(void)
3093 " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n" 3092 " ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
3094 " file ...\n" 3093 " file ...\n"
3095 " ssh-keygen -Q -f krl_file file ...\n" 3094 " ssh-keygen -Q -f krl_file file ...\n"
3096 " ssh-keygen -Y find-principal -s signature_file -f allowed_signers_file\n" 3095 " ssh-keygen -Y find-principals -s signature_file -f allowed_signers_file\n"
3097 " ssh-keygen -Y check-novalidate -n namespace -s signature_file\n" 3096 " ssh-keygen -Y check-novalidate -n namespace -s signature_file\n"
3098 " ssh-keygen -Y sign -f key_file -n namespace file ...\n" 3097 " ssh-keygen -Y sign -f key_file -n namespace file ...\n"
3099 " ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n" 3098 " ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n"
@@ -3357,18 +3356,18 @@ main(int argc, char **argv)
3357 argc -= optind; 3356 argc -= optind;
3358 3357
3359 if (sign_op != NULL) { 3358 if (sign_op != NULL) {
3360 if (strncmp(sign_op, "find-principal", 14) == 0) { 3359 if (strncmp(sign_op, "find-principals", 15) == 0) {
3361 if (ca_key_path == NULL) { 3360 if (ca_key_path == NULL) {
3362 error("Too few arguments for find-principal:" 3361 error("Too few arguments for find-principals:"
3363 "missing signature file"); 3362 "missing signature file");
3364 exit(1); 3363 exit(1);
3365 } 3364 }
3366 if (!have_identity) { 3365 if (!have_identity) {
3367 error("Too few arguments for find-principal:" 3366 error("Too few arguments for find-principals:"
3368 "missing allowed keys file"); 3367 "missing allowed keys file");
3369 exit(1); 3368 exit(1);
3370 } 3369 }
3371 return sig_find_principal(ca_key_path, identity_file); 3370 return sig_find_principals(ca_key_path, identity_file);
3372 } 3371 }
3373 if (cert_principals == NULL || *cert_principals == '\0') { 3372 if (cert_principals == NULL || *cert_principals == '\0') {
3374 error("Too few arguments for sign/verify: " 3373 error("Too few arguments for sign/verify: "
diff --git a/sshsig.c b/sshsig.c
index e9f4baa76..e63a36e1e 100644
--- a/sshsig.c
+++ b/sshsig.c
@@ -868,13 +868,64 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
868} 868}
869 869
870static int 870static int
871get_matching_principal_from_line(const char *path, u_long linenum, char *line, 871cert_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
922static int
923get_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
922int 974int
923sshsig_find_principal(const char *path, const struct sshkey *sign_key, 975sshsig_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)
diff --git a/sshsig.h b/sshsig.h
index 939e3dfe0..63cc1ad1a 100644
--- a/sshsig.h
+++ b/sshsig.h
@@ -93,13 +93,12 @@ struct sshsigopt *sshsigopt_parse(const char *opts,
93void sshsigopt_free(struct sshsigopt *opts); 93void sshsigopt_free(struct sshsigopt *opts);
94 94
95/* Get public key from signature */ 95/* Get public key from signature */
96int 96int sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey);
97sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey);
98 97
99/* Find principal in allowed_keys file, given a sshkey. Returns 98/* Find principal in allowed_keys file, given a sshkey. Returns
100 * 0 on success. 99 * 0 on success.
101 */ 100 */
102int sshsig_find_principal(const char *path, const struct sshkey *sign_key, 101int sshsig_find_principals(const char *path, const struct sshkey *sign_key,
103 char **principal); 102 char **principal);
104 103
105#endif /* SSHSIG_H */ 104#endif /* SSHSIG_H */