Fabian Stelzer
2021-Nov-03 08:51 UTC
[PATCH v2 0/3] sshsig: find-principal fix & match-principals
This patch series adds a few tests to the find-principals & verify operations of ssh-keygen and fixes a bug in find-principals. find-principals was checking key validity times for CA signed certs but not for normal keys or a validity specified on the CA key. The verify operation correctly does both. As find-principals just returns the first match, this could return principals with an expired/notyetvalid key. This patch changes this behaviour and could therefore be considered a breaking change. At the moment the docs are not quite clear about this. find-principals is specified to return a list of principals. It wasn't clear to me that this meant only those found on a single line. I assumed i would get all that match the signatures public key. If my understanding is correct that find-principals should always just return one match (sometimes having multiple principals) then i can update the manpage as well. It also adds a new -Y match-principals that can be used to determine if a principal is present in the allowed signers file (considering wildcard matches). I am implementing "Trust on first use" for git commit signing via ssh keys and needed a safe way to check that i will not add a principal already present (and thereby possibly overriding their key if it expires for example). Generally i only would like to add principals not already matching any existing entry. Changes since v1: - instead of fixing just the find-principals check consolidate find & verify functions into one so we always use the same logic for both - drops the already merged tests & optional verify_time parsing patches Fabian Stelzer (3): sshsig: move cert_filter_principals() for reuse sshsig: fix find-principals key lifespan validation ssh-keygen: add match-principals call regress/sshsig.sh | 129 ++++++++++++++++++++++++ ssh-keygen.1 | 14 +++ ssh-keygen.c | 35 +++++++ sshsig.c | 246 ++++++++++++++++++++++++---------------------- sshsig.h | 4 + 5 files changed, 310 insertions(+), 118 deletions(-) base-commit: 0328a081f38c09d2d4d650e94461a47fb5eef536 -- 2.31.1
Fabian Stelzer
2021-Nov-03 08:51 UTC
[PATCH v2 1/3] sshsig: move cert_filter_principals() for reuse
--- sshsig.c | 108 +++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/sshsig.c b/sshsig.c index d0d401a3..40d132d3 100644 --- a/sshsig.c +++ b/sshsig.c @@ -812,6 +812,60 @@ parse_principals_key_and_options(const char *path, u_long linenum, char *line, return r; } +static int +cert_filter_principals(const char *path, u_long linenum, + char **principalsp, const struct sshkey *cert, uint64_t verify_time) +{ + char *cp, *oprincipals, *principals; + const char *reason; + struct sshbuf *nprincipals; + int r = SSH_ERR_INTERNAL_ERROR, success = 0; + + oprincipals = principals = *principalsp; + *principalsp = NULL; + + if ((nprincipals = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + + while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') { + if (strcspn(cp, "!?*") != strlen(cp)) { + debug("%s:%lu: principal \"%s\" not authorized: " + "contains wildcards", path, linenum, cp); + continue; + } + /* Check against principals list in certificate */ + if ((r = sshkey_cert_check_authority(cert, 0, 1, 0, + verify_time, cp, &reason)) != 0) { + debug("%s:%lu: principal \"%s\" not authorized: %s", + path, linenum, cp, reason); + continue; + } + if ((r = sshbuf_putf(nprincipals, "%s%s", + sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) { + error_f("buffer error"); + goto out; + } + } + if (sshbuf_len(nprincipals) == 0) { + error("%s:%lu: no valid principals found", path, linenum); + r = SSH_ERR_KEY_CERT_INVALID; + goto out; + } + if ((principals = sshbuf_dup_string(nprincipals)) == NULL) { + error_f("buffer error"); + goto out; + } + /* success */ + success = 1; + *principalsp = principals; + out: + sshbuf_free(nprincipals); + free(oprincipals); + return success ? 0 : r; +} + static int check_allowed_keys_line(const char *path, u_long linenum, char *line, const struct sshkey *sign_key, const char *principal, @@ -925,60 +979,6 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; } -static int -cert_filter_principals(const char *path, u_long linenum, - char **principalsp, const struct sshkey *cert, uint64_t verify_time) -{ - char *cp, *oprincipals, *principals; - const char *reason; - struct sshbuf *nprincipals; - int r = SSH_ERR_INTERNAL_ERROR, success = 0; - - oprincipals = principals = *principalsp; - *principalsp = NULL; - - if ((nprincipals = sshbuf_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - - while ((cp = strsep(&principals, ",")) != NULL && *cp != '\0') { - if (strcspn(cp, "!?*") != strlen(cp)) { - debug("%s:%lu: principal \"%s\" not authorized: " - "contains wildcards", path, linenum, cp); - continue; - } - /* Check against principals list in certificate */ - if ((r = sshkey_cert_check_authority(cert, 0, 1, 0, - verify_time, cp, &reason)) != 0) { - debug("%s:%lu: principal \"%s\" not authorized: %s", - path, linenum, cp, reason); - continue; - } - if ((r = sshbuf_putf(nprincipals, "%s%s", - sshbuf_len(nprincipals) != 0 ? "," : "", cp)) != 0) { - error_f("buffer error"); - goto out; - } - } - if (sshbuf_len(nprincipals) == 0) { - error("%s:%lu: no valid principals found", path, linenum); - r = SSH_ERR_KEY_CERT_INVALID; - goto out; - } - if ((principals = sshbuf_dup_string(nprincipals)) == NULL) { - error_f("buffer error"); - goto out; - } - /* success */ - success = 1; - *principalsp = principals; - out: - sshbuf_free(nprincipals); - free(oprincipals); - return success ? 0 : r; -} - static int get_matching_principals_from_line(const char *path, u_long linenum, char *line, const struct sshkey *sign_key, uint64_t verify_time, char **principalsp) -- 2.31.1
Fabian Stelzer
2021-Nov-03 08:51 UTC
[PATCH v2 2/3] sshsig: fix find-principals key lifespan validation
find-principals was verifying key validity when using ca certs but not with simple key lifetimes within the allowed signers file. Since it returns the first keys principal it finds this could result in a principal with an expired key even though a valid one is just below. - Add return of matching principals functionality to check_allowed_keys_line(). This way we can reuse this function and avoid behaviour differences between find-principals & verify calls. Use this function for find-principals then as well fixing the above mentioned bug. - Add test cases for it. - Add test for find-principals & verify when multiple identical keys are present just having different key lifetimes. This could for example happen when a committer looses access to a repo for a time and regains it later. This way we can only mark signatures in the respective timespans valid. - Remove the now unused second check function Signed-off-by: Fabian Stelzer <fs at gigacodes.de> --- regress/sshsig.sh | 103 ++++++++++++++++++++++++++++++++++++++++++++++ sshsig.c | 97 +++++++++++++++---------------------------- 2 files changed, 136 insertions(+), 64 deletions(-) diff --git a/regress/sshsig.sh b/regress/sshsig.sh index 6c96cd5a..788e63ff 100644 --- a/regress/sshsig.sh +++ b/regress/sshsig.sh @@ -149,6 +149,26 @@ for t in $SIGNKEYS; do < $DATA >/dev/null 2>&1 && \ fail "failed signature for $t with expired key" + # key lifespan valid + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19850101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 || \ + fail "failed find-principals for $t key with valid expiry interval" + # key not yet valid + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19790101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 && \ + fail "failed find-principals for $t not-yet-valid key" + # key expired + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19990101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 && \ + fail "failed find-principals for $t with expired key" + # NB. assumes we're not running this test in the 1980s + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -f $OBJ/allowed_signers >/dev/null 2>&1 && \ + fail "failed find-principals for $t with expired key" + # public key in revoked keys file cat $pubkey > $OBJ/revoked_keys (printf "$sig_principal namespaces=\"whatever\" " ; @@ -205,12 +225,89 @@ for t in $SIGNKEYS; do # Move private key back mv ${privkey}.tmp ${privkey} + # Duplicate principals & keys in allowed_signers but with different validities + ( printf "$sig_principal " ; + printf "valid-after=\"19800101\",valid-before=\"19900101\" " ; + cat $pubkey; + printf "${sig_principal} " ; + printf "valid-after=\"19850101\",valid-before=\"20000101\" " ; + cat $pubkey) > $OBJ/allowed_signers + + # find-principals outside of any validity lifespan + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="20100101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 && \ + fail "succeeded find-principals for $t verify-time outside of validity" + # find-principals matching only the first lifespan + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19830101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 || \ + fail "failed find-principals for $t verify-time within first span" + # find-principals matching both lifespans + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19880101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 || \ + fail "failed find-principals for $t verify-time within both spans" + # find-principals matching only the second lifespan + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19950101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 || \ + fail "failed find-principals for $t verify-time within second span" + + # verify outside of any validity lifespan + ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \ + -Overify-time="20100101" -I $sig_principal \ + -r $OBJ/revoked_keys -f $OBJ/allowed_signers \ + < $DATA >/dev/null 2>&1 && \ + fail "succeeded verify for $t verify-time outside of validity" + # verify matching only the first lifespan + ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \ + -Overify-time="19830101" -I $sig_principal \ + -r $OBJ/revoked_keys -f $OBJ/allowed_signers \ + < $DATA >/dev/null 2>&1 || \ + fail "failed verify for $t verify-time within first span" + # verify matching both lifespans + ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \ + -Overify-time="19880101" -I $sig_principal \ + -r $OBJ/revoked_keys -f $OBJ/allowed_signers \ + < $DATA >/dev/null 2>&1 || \ + fail "failed verify for $t verify-time within both spans" + # verify matching only the second lifespan + ${SSHKEYGEN} -vvv -Y verify -s $sigfile -n $sig_namespace \ + -Overify-time="19950101" -I $sig_principal \ + -r $OBJ/revoked_keys -f $OBJ/allowed_signers \ + < $DATA >/dev/null 2>&1 || \ + fail "failed verify for $t verify-time within second span" + # Remaining tests are for certificates only. case "$keybase" in *-cert) ;; *) continue ;; esac + # Check key lifespan on find-principals when using the CA + ( printf "$sig_principal " ; + printf "cert-authority,valid-after=\"19800101\",valid-before=\"19900101\" "; + cat $CA_PUB) > $OBJ/allowed_signers + # key lifespan valid + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19850101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 || \ + fail "failed find-principals for $t key with valid expiry interval" + # key not yet valid + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19790101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 && \ + fail "failed find-principals for $t not-yet-valid key" + # key expired + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time="19990101" \ + -f $OBJ/allowed_signers >/dev/null 2>&1 && \ + fail "failed find-principals for $t with expired key" + # NB. assumes we're not running this test in the 1980s + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -f $OBJ/allowed_signers >/dev/null 2>&1 && \ + fail "failed find-principals for $t with expired key" # correct CA key (printf "$sig_principal cert-authority " ; @@ -221,6 +318,12 @@ for t in $SIGNKEYS; do < $DATA >/dev/null 2>&1 || \ fail "failed signature for $t cert" + # find-principals + ${SSHKEYGEN} -vvv -Y find-principals -s $sigfile \ + -Overify-time=19850101 \ + -f $OBJ/allowed_signers >/dev/null 2>&1 || \ + fail "failed find-principals for $t with ca key" + # signing key listed as cert-authority (printf "$sig_principal cert-authority " ; cat $pubkey) > $OBJ/allowed_signers diff --git a/sshsig.c b/sshsig.c index 40d132d3..5f8a7b16 100644 --- a/sshsig.c +++ b/sshsig.c @@ -869,17 +869,21 @@ cert_filter_principals(const char *path, u_long linenum, static int check_allowed_keys_line(const char *path, u_long linenum, char *line, const struct sshkey *sign_key, const char *principal, - const char *sig_namespace, uint64_t verify_time) + const char *sig_namespace, uint64_t verify_time, char **principalsp) { struct sshkey *found_key = NULL; + char *principals = NULL; int r, success = 0; const char *reason = NULL; struct sshsigopt *sigopts = NULL; char tvalid[64], tverify[64]; + if (principalsp != NULL) + *principalsp = NULL; + /* Parse the line */ if ((r = parse_principals_key_and_options(path, linenum, line, - principal, NULL, &found_key, &sigopts)) != 0) { + principal, &principals, &found_key, &sigopts)) != 0) { /* error already logged */ goto done; } @@ -889,14 +893,26 @@ check_allowed_keys_line(const char *path, u_long linenum, char *line, debug("%s:%lu: matched key", path, linenum); } else if (sigopts->ca && sshkey_is_cert(sign_key) && sshkey_equal_public(sign_key->cert->signature_key, found_key)) { - /* Match of certificate's CA key */ - if ((r = sshkey_cert_check_authority(sign_key, 0, 1, 0, - verify_time, principal, &reason)) != 0) { - error("%s:%lu: certificate not authorized: %s", - path, linenum, reason); - goto done; + if (principal) { + /* Match of certificate's CA key with a specified principal */ + if ((r = sshkey_cert_check_authority(sign_key, 0, 1, 0, + verify_time, principal, &reason)) != 0) { + error("%s:%lu: certificate not authorized: %s", + path, linenum, reason); + goto done; + } + debug("%s:%lu: matched certificate CA key", path, linenum); + } else { + /* No principal specified - find all matching ones */ + if ((r = cert_filter_principals(path, linenum, + &principals, sign_key, verify_time)) != 0) { + /* error already displayed */ + debug_r(r, "%s:%lu: cert_filter_principals", + path, linenum); + goto done; + } + debug("%s:%lu: matched certificate CA key", path, linenum); } - debug("%s:%lu: matched certificate CA key", path, linenum); } else { /* Didn't match key */ goto done; @@ -933,6 +949,11 @@ check_allowed_keys_line(const char *path, u_long linenum, char *line, success = 1; done: + if (success && principalsp != NULL) { + *principalsp = principals; + principals = NULL; /* transferred */ + } + free(principals); sshkey_free(found_key); sshsigopt_free(sigopts); return success ? 0 : SSH_ERR_KEY_NOT_FOUND; @@ -960,7 +981,7 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, while (getline(&line, &linesize, f) != -1) { linenum++; r = check_allowed_keys_line(path, linenum, line, sign_key, - principal, sig_namespace, verify_time); + principal, sig_namespace, verify_time, NULL); free(line); line = NULL; linesize = 0; @@ -979,58 +1000,6 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key, return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; } -static int -get_matching_principals_from_line(const char *path, u_long linenum, char *line, - const struct sshkey *sign_key, uint64_t verify_time, char **principalsp) -{ - struct sshkey *found_key = NULL; - char *principals = NULL; - int r, found = 0; - struct sshsigopt *sigopts = NULL; - - if (principalsp != NULL) - *principalsp = NULL; - - /* Parse the line */ - if ((r = parse_principals_key_and_options(path, linenum, line, - NULL, &principals, &found_key, &sigopts)) != 0) { - /* error already logged */ - goto done; - } - - if (!sigopts->ca && sshkey_equal(found_key, sign_key)) { - /* Exact match of key */ - debug("%s:%lu: matched key", path, linenum); - /* success */ - found = 1; - } else if (sigopts->ca && sshkey_is_cert(sign_key) && - sshkey_equal_public(sign_key->cert->signature_key, found_key)) { - /* Remove principals listed in file but not allowed by cert */ - if ((r = cert_filter_principals(path, linenum, - &principals, sign_key, verify_time)) != 0) { - /* error already displayed */ - debug_r(r, "%s:%lu: cert_filter_principals", - path, linenum); - goto done; - } - debug("%s:%lu: matched certificate CA key", path, linenum); - /* success */ - found = 1; - } else { - /* Key didn't match */ - goto done; - } - done: - if (found && principalsp != NULL) { - *principalsp = principals; - principals = NULL; /* transferred */ - } - free(principals); - sshkey_free(found_key); - sshsigopt_free(sigopts); - return found ? 0 : SSH_ERR_KEY_NOT_FOUND; -} - int sshsig_find_principals(const char *path, const struct sshkey *sign_key, uint64_t verify_time, char **principals) @@ -1051,8 +1020,8 @@ sshsig_find_principals(const char *path, const struct sshkey *sign_key, while (getline(&line, &linesize, f) != -1) { linenum++; - r = get_matching_principals_from_line(path, linenum, line, - sign_key, verify_time, principals); + r = check_allowed_keys_line(path, linenum, line, + sign_key, NULL, NULL, verify_time, principals); free(line); line = NULL; linesize = 0; -- 2.31.1
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 at gigacodes.de> --- 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 788e63ff..8e8b31b8 100644 --- a/regress/sshsig.sh +++ b/regress/sshsig.sh @@ -410,6 +410,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 248a0ae7..b227a2e7 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) { @@ -3187,6 +3208,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" @@ -3468,6 +3490,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 match-principals: " + "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 5f8a7b16..97cb1fac 100644 --- a/sshsig.c +++ b/sshsig.c @@ -1048,6 +1048,47 @@ sshsig_find_principals(const char *path, const struct sshkey *sign_key, return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r; } +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; +} + int sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey) { 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