Adds "-Y match-principals -s signers_file -I identity" so we are able to look up principals considering wildcard matches. Users (git in this case) implementing "Trust on first use" can use this to make sure they don't add overlapping principals with new keys. Signed-off-by: Fabian Stelzer <fs@xxxxxxxxxxxx> --- regress/sshsig.sh | 26 ++++++++++++++++++++++++++ ssh-keygen.1 | 14 ++++++++++++++ ssh-keygen.c | 35 +++++++++++++++++++++++++++++++++++ sshsig.c | 41 +++++++++++++++++++++++++++++++++++++++++ sshsig.h | 4 ++++ 5 files changed, 120 insertions(+) diff --git a/regress/sshsig.sh b/regress/sshsig.sh index 9947afc1..420d7e3d 100644 --- a/regress/sshsig.sh +++ b/regress/sshsig.sh @@ -356,6 +356,32 @@ for t in $SIGNKEYS; do done +# Test key independant match-principals +( + printf "principal1 " ; cat $pubkey; + printf "princi* " ; cat $pubkey; + printf "unique " ; cat $pubkey; +) > $OBJ/allowed_signers + +${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers \ + -I "unique" \ + | grep -F "unique" || \ + fail "faild to match static principal" + +${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers \ + -I "princip" \ + | grep -F "princi*" || \ + fail "faild to match wildcard principal" + +${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers \ + -I "principal1" \ + | grep -F -e "principal1" -e "princi*" || \ + fail "faild to match static and wildcard principal" + +${SSHKEYGEN} -Y match-principals -f $OBJ/allowed_signers \ + -I "unknown" >/dev/null 2>&1 && \ + fail "succeeded to match unknown principal" + trace "kill agent" ${SSHAGENT} -k > /dev/null diff --git a/ssh-keygen.1 b/ssh-keygen.1 index f83f515f..08a509cd 100644 --- a/ssh-keygen.1 +++ b/ssh-keygen.1 @@ -151,6 +151,11 @@ .Fl s Ar signature_file .Fl f Ar allowed_signers_file .Nm ssh-keygen +.Fl Y Cm match-principals +.Op Fl O Ar option +.Fl I Ar signer_identity +.Fl f Ar allowed_signers_file +.Nm ssh-keygen .Fl Y Cm check-novalidate .Op Fl O Ar option .Fl n Ar namespace @@ -683,6 +688,15 @@ The format of the allowed signers file is documented in the section below. If one or more matching principals are found, they are returned on standard output. +.It Fl Y Cm match-principals +Find all the principal(s) matching the principal name, +provided using the +.Fl I +flag in an authorized signers file provided using the +.Fl f +flag. +If one or more matching principals are found, they are returned on +standard output. .It Fl Y Cm check-novalidate Checks that a signature generated using .Nm diff --git a/ssh-keygen.c b/ssh-keygen.c index 927a1d62..8fae13f3 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c @@ -2849,6 +2849,27 @@ done: return ret; } +static int +sig_match_principals(const char *allowed_keys, char *principal, + char * const *opts, size_t nopts) +{ + int ret = -1; + struct sshbuf *matching_principals = sshbuf_new(); + + if (sig_process_opts(opts, nopts, NULL, NULL) != 0) + return ret; /* error already logged */ + + ret = sshsig_match_principals(allowed_keys, principal, &matching_principals); + if (ret == 0 && matching_principals) { + printf("%s", sshbuf_ptr(matching_principals)); + } else { + fprintf(stderr, "No principal matched.\n"); + } + sshbuf_free(matching_principals); + + return ret; +} + static void do_moduli_gen(const char *out_file, char **opts, size_t nopts) { @@ -3162,6 +3183,7 @@ usage(void) " file ...\n" " ssh-keygen -Q [-l] -f krl_file [file ...]\n" " ssh-keygen -Y find-principals -s signature_file -f allowed_signers_file\n" + " ssh-keygen -Y match-principals -I signer_identity -f allowed_signers_file\n" " ssh-keygen -Y check-novalidate -n namespace -s signature_file\n" " ssh-keygen -Y sign -f key_file -n namespace file ...\n" " ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n" @@ -3443,6 +3465,19 @@ main(int argc, char **argv) } return sig_find_principals(ca_key_path, identity_file, opts, nopts); + } else if (strncmp(sign_op, "match-principals", 16) == 0) { + if (!have_identity) { + error("Too few arguments for match-principals:" + "missing allowed keys file"); + exit(1); + } + if (cert_key_id == NULL) { + error("Too few arguments for verify: " + "missing principal ID"); + exit(1); + } + return sig_match_principals(identity_file, cert_key_id, + opts, nopts); } else if (strncmp(sign_op, "sign", 4) == 0) { if (cert_principals == NULL || *cert_principals == '\0') { diff --git a/sshsig.c b/sshsig.c index b50a9779..ddfb96c4 100644 --- a/sshsig.c +++ b/sshsig.c @@ -841,6 +841,47 @@ check_key_validity(uint64_t verify_time, struct sshsigopt *sigopts, const char * return 0; } +int +sshsig_match_principals(const char *path, + const char *principal, struct sshbuf **matching_principals) +{ + FILE *f = NULL; + char *line = NULL; + size_t linesize = 0; + u_long linenum = 0; + int oerrno; + int found = 0; + + /* Check key and principal against file */ + if ((f = fopen(path, "r")) == NULL) { + oerrno = errno; + error("Unable to open allowed keys file \"%s\": %s", + path, strerror(errno)); + errno = oerrno; + return SSH_ERR_SYSTEM_ERROR; + } + + while (getline(&line, &linesize, f) != -1) { + linenum++; + char *principals = NULL; + + /* Parse the line */ + if (parse_principals_key_and_options(path, linenum, line, + principal, &principals, NULL, NULL) == 0) { + sshbuf_putf(*matching_principals, "%s\n", principals); + found = 1; + } + + free(principals); + free(line); + line = NULL; + linesize = 0; + } + fclose(f); + + return !found; +} + static int check_allowed_keys_line(const char *path, u_long linenum, char *line, const struct sshkey *sign_key, const char *principal, diff --git a/sshsig.h b/sshsig.h index b725c7d7..fee3bc20 100644 --- a/sshsig.h +++ b/sshsig.h @@ -104,4 +104,8 @@ int sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey); int sshsig_find_principals(const char *path, const struct sshkey *sign_key, uint64_t verify_time, char **principal); +/* Find all principals in allowed_keys file matching *principal */ +int sshsig_match_principals(const char *path, + const char *principal, struct sshbuf **matching_principals); + #endif /* SSHSIG_H */ -- 2.31.1 _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev