[openssh-commits] [openssh] 02/02: upstream: add a new signature operations "find-principal" to look

git+noreply at mindrot.org git+noreply at mindrot.org
Thu Jan 23 13:45:29 AEDT 2020


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 56cffcc09f8a2e661d2ba02e61364ae6f998b2b1
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Thu Jan 23 02:43:48 2020 +0000

    upstream: add a new signature operations "find-principal" to look
    
    up the principal associated with a signature from an allowed-signers file.
    Work by Sebastian Kinne; ok dtucker@
    
    OpenBSD-Commit-ID: 6f782cc7e18e38fcfafa62af53246a1dcfe74e5d
---
 ssh-keygen.1 |  19 +++++++++-
 ssh-keygen.c |  84 +++++++++++++++++++++++++++++++++++++-----
 sshsig.c     | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 209 insertions(+), 11 deletions(-)

diff --git a/ssh-keygen.1 b/ssh-keygen.1
index c0a22606..33e3f537 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
-.\"	$OpenBSD: ssh-keygen.1,v 1.193 2020/01/18 21:16:43 naddy Exp $
+.\"	$OpenBSD: ssh-keygen.1,v 1.194 2020/01/23 02:43:48 djm Exp $
 .\"
 .\" Author: Tatu Ylonen <ylo at cs.hut.fi>
 .\" Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -35,7 +35,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: January 18 2020 $
+.Dd $Mdocdate: January 23 2020 $
 .Dt SSH-KEYGEN 1
 .Os
 .Sh NAME
@@ -138,6 +138,10 @@
 .Fl f Ar krl_file
 .Ar
 .Nm ssh-keygen
+.Fl Y Cm find-principal
+.Fl s Ar signature_file
+.Fl f Ar allowed_signers_file
+.Nm ssh-keygen
 .Fl Y Cm check-novalidate
 .Fl n Ar namespace
 .Fl s Ar signature_file
@@ -614,6 +618,17 @@ The maximum is 3.
 Specifies a path to a library that will be used when creating
 FIDO authenticator-hosted keys, overriding the default of using
 the internal USB HID support.
+.It Fl Y Cm find-principal
+Find the principal associated with the public key of a signature,
+provided using the
+.Fl s
+flag in an authorized signers file provided using the
+.Fl f
+flag.
+The format of the allowed signers file is documented in the
+.Sx ALLOWED SIGNERS
+section below. If a matching principal is found, it is 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 04492979..eebd89a2 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.385 2020/01/22 04:51:51 claudio Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.386 2020/01/23 02:43:48 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
@@ -2599,7 +2599,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
 }
 
 static int
-sign(const char *keypath, const char *sig_namespace, int argc, char **argv)
+sig_sign(const char *keypath, const char *sig_namespace, int argc, char **argv)
 {
 	int i, fd = -1, r, ret = -1;
 	int agent_fd = -1;
@@ -2670,8 +2670,8 @@ done:
 }
 
 static int
-verify(const char *signature, const char *sig_namespace, const char *principal,
-    const char *allowed_keys, const char *revoked_keys)
+sig_verify(const char *signature, const char *sig_namespace,
+    const char *principal, const char *allowed_keys, const char *revoked_keys)
 {
 	int r, ret = -1, sigfd = -1;
 	struct sshbuf *sigbuf = NULL, *abuf = NULL;
@@ -2694,7 +2694,7 @@ verify(const char *signature, const char *sig_namespace, const char *principal,
 	}
 	if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
 		error("%s: sshsig_armor: %s", __func__, ssh_err(r));
-		return r;
+		goto done;
 	}
 	if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace,
 	    &sign_key, &sig_details)) != 0)
@@ -2757,6 +2757,57 @@ done:
 	return ret;
 }
 
+static int
+sig_find_principal(const char *signature, const char *allowed_keys) {
+	int r, ret = -1, sigfd = -1;
+	struct sshbuf *sigbuf = NULL, *abuf = NULL;
+	struct sshkey *sign_key = NULL;
+	char *principal = NULL;
+
+	if ((abuf = sshbuf_new()) == NULL)
+		fatal("%s: sshbuf_new() failed", __func__);
+
+	if ((sigfd = open(signature, O_RDONLY)) < 0) {
+		error("Couldn't open signature file %s", signature);
+		goto done;
+	}
+
+	if ((r = sshkey_load_file(sigfd, abuf)) != 0) {
+		error("Couldn't read signature file: %s", ssh_err(r));
+		goto done;
+	}
+	if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
+		error("%s: sshsig_armor: %s", __func__, ssh_err(r));
+		goto done;
+	}
+	if ((r = sshsig_get_pubkey(sigbuf, &sign_key)) != 0) {
+		error("%s: sshsig_get_pubkey: %s",
+		      __func__, ssh_err(r));
+		goto done;
+	}
+
+	if ((r = sshsig_find_principal(allowed_keys, sign_key,
+				      &principal)) != 0) {
+		error("%s: sshsig_get_principal: %s",
+		      __func__, ssh_err(r));
+		goto done;
+	}
+	ret = 0;
+done:
+	if (ret == 0 ) {
+		printf("Found matching principal: %s\n", principal);
+	} else {
+		printf("Could not find matching principal.\n");
+	}
+	if (sigfd != -1)
+		close(sigfd);
+	sshbuf_free(sigbuf);
+	sshbuf_free(abuf);
+	sshkey_free(sign_key);
+	free(principal);
+	return ret;
+}
+
 static void
 do_moduli_gen(const char *out_file, char **opts, size_t nopts)
 {
@@ -3042,6 +3093,7 @@ usage(void)
 	    "       ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
 	    "                  file ...\n"
 	    "       ssh-keygen -Q -f krl_file file ...\n"
+	    "       ssh-keygen -Y find-principal -s signature_file -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"
@@ -3305,6 +3357,19 @@ main(int argc, char **argv)
 	argc -= optind;
 
 	if (sign_op != NULL) {
+		if (strncmp(sign_op, "find-principal", 14) == 0) {
+			if (ca_key_path == NULL) {
+				error("Too few arguments for find-principal:"
+				      "missing signature file");
+				exit(1);
+			}
+			if (!have_identity) {
+				error("Too few arguments for find-principal:"
+				      "missing allowed keys file");
+				exit(1);
+			}
+			return sig_find_principal(ca_key_path, identity_file);
+		}
 		if (cert_principals == NULL || *cert_principals == '\0') {
 			error("Too few arguments for sign/verify: "
 			    "missing namespace");
@@ -3316,15 +3381,16 @@ main(int argc, char **argv)
 				    "missing key");
 				exit(1);
 			}
-			return sign(identity_file, cert_principals, argc, argv);
+			return sig_sign(identity_file, cert_principals,
+			    argc, argv);
 		} else if (strncmp(sign_op, "check-novalidate", 16) == 0) {
 			if (ca_key_path == NULL) {
 				error("Too few arguments for check-novalidate: "
 				      "missing signature file");
 				exit(1);
 			}
-			return verify(ca_key_path, cert_principals,
-				      NULL, NULL, NULL);
+			return sig_verify(ca_key_path, cert_principals,
+			    NULL, NULL, NULL);
 		} else if (strncmp(sign_op, "verify", 6) == 0) {
 			if (ca_key_path == NULL) {
 				error("Too few arguments for verify: "
@@ -3341,7 +3407,7 @@ main(int argc, char **argv)
 				    "missing principal ID");
 				exit(1);
 			}
-			return verify(ca_key_path, cert_principals,
+			return sig_verify(ca_key_path, cert_principals,
 			    cert_key_id, identity_file, rr_hostname);
 		}
 		usage();
diff --git a/sshsig.c b/sshsig.c
index 6d72f92f..e9f4baa7 100644
--- a/sshsig.c
+++ b/sshsig.c
@@ -866,3 +866,120 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
 	free(line);
 	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
 }
+
+static int
+get_matching_principal_from_line(const char *path, u_long linenum, char *line,
+    const struct sshkey *sign_key, char **principalsp)
+{
+	struct sshkey *found_key = NULL;
+	char *principals = NULL;
+	int r, found = 0;
+	const char *reason = NULL;
+	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)) {
+		/* Match of certificate's CA key */
+		if ((r = sshkey_cert_check_authority(sign_key, 0, 1,
+		    principals, &reason)) != 0) {
+			error("%s:%lu: certificate not authorized: %s",
+			    path, linenum, reason);
+			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 = principals;
+		principals = NULL; /* transferred */
+	}
+	free(principals);
+	sshkey_free(found_key);
+	sshsigopt_free(sigopts);
+	return found ? 0 : SSH_ERR_KEY_NOT_FOUND;
+}
+
+int
+sshsig_find_principal(const char *path, const struct sshkey *sign_key,
+    char **principal)
+{
+	FILE *f = NULL;
+	char *line = NULL;
+	size_t linesize = 0;
+	u_long linenum = 0;
+	int r, oerrno;
+
+	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++;
+		r = get_matching_principal_from_line(path, linenum, line,
+		    sign_key, principal);
+		free(line);
+		line = NULL;
+		if (r == SSH_ERR_KEY_NOT_FOUND)
+			continue;
+		else if (r == 0) {
+			/* success */
+			fclose(f);
+			return 0;
+		} else
+			break;
+	}
+	free(line);
+	/* Either we hit an error parsing or we simply didn't find the key */
+	if (ferror(f) != 0) {
+		oerrno = errno;
+		fclose(f);
+		error("Unable to read allowed keys file \"%s\": %s",
+		    path, strerror(errno));
+		errno = oerrno;
+		return SSH_ERR_SYSTEM_ERROR;
+	}
+	fclose(f);
+	return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
+}
+
+int
+sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey)
+{
+	struct sshkey *pk = NULL;
+	int r = SSH_ERR_SIGNATURE_INVALID;
+
+	if (pubkey != NULL)
+		*pubkey = NULL;
+	if ((r = sshsig_parse_preamble(signature)) != 0)
+		return r;
+	if ((r = sshkey_froms(signature, &pk)) != 0)
+		return r;
+
+	*pubkey = pk;
+	pk = NULL;
+	return 0;
+}

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list