[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