[PATCH 4/4] ssh-keygen: add match-principals call

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



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



[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux