[PATCH 4/4] ssh-keygen: add match-principals call
Fabian Stelzer
fs at gigacodes.de
Fri Oct 22 00:54:27 AEDT 2021
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 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
More information about the openssh-unix-dev
mailing list