upstream: ssh-keygen -Y find-principals fixes based on feedback

from Markus:

use "principals" instead of principal, as allowed_signers lines may list
multiple.

When the signing key is a certificate, emit only principals that match
the certificate principal list.

NB. the command -Y name changes: "find-principal" => "find-principals"

ok markus@

OpenBSD-Commit-ID: ab575946ff9a55624cd4e811bfd338bf3b1d0faf
This commit is contained in:
djm@openbsd.org 2020-01-23 23:31:52 +00:00 коммит произвёл Damien Miller
Родитель 0585b56972
Коммит 72a8bea2d7
4 изменённых файлов: 84 добавлений и 33 удалений

Просмотреть файл

@ -1,4 +1,4 @@
.\" $OpenBSD: ssh-keygen.1,v 1.195 2020/01/23 07:16:38 jmc Exp $
.\" $OpenBSD: ssh-keygen.1,v 1.196 2020/01/23 23:31:52 djm Exp $
.\"
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -138,7 +138,7 @@
.Fl f Ar krl_file
.Ar
.Nm ssh-keygen
.Fl Y Cm find-principal
.Fl Y Cm find-principals
.Fl s Ar signature_file
.Fl f Ar allowed_signers_file
.Nm ssh-keygen
@ -618,8 +618,8 @@ 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,
.It Fl Y Cm find-principals
Find the principal(s) associated with the public key of a signature,
provided using the
.Fl s
flag in an authorized signers file provided using the
@ -628,7 +628,8 @@ 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.
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

Просмотреть файл

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keygen.c,v 1.387 2020/01/23 07:54:04 djm Exp $ */
/* $OpenBSD: ssh-keygen.c,v 1.388 2020/01/23 23:31:52 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -2758,11 +2758,11 @@ done:
}
static int
sig_find_principal(const char *signature, const char *allowed_keys) {
sig_find_principals(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;
char *principals = NULL;
if ((abuf = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new() failed", __func__);
@ -2782,12 +2782,11 @@ sig_find_principal(const char *signature, const char *allowed_keys) {
}
if ((r = sshsig_get_pubkey(sigbuf, &sign_key)) != 0) {
error("%s: sshsig_get_pubkey: %s",
__func__, ssh_err(r));
__func__, ssh_err(r));
goto done;
}
if ((r = sshsig_find_principal(allowed_keys, sign_key,
&principal)) != 0) {
if ((r = sshsig_find_principals(allowed_keys, sign_key,
&principals)) != 0) {
error("%s: sshsig_get_principal: %s",
__func__, ssh_err(r));
goto done;
@ -2795,7 +2794,7 @@ sig_find_principal(const char *signature, const char *allowed_keys) {
ret = 0;
done:
if (ret == 0 ) {
printf("Found matching principal: %s\n", principal);
printf("Found matching principal: %s\n", principals);
} else {
printf("Could not find matching principal.\n");
}
@ -2804,7 +2803,7 @@ done:
sshbuf_free(sigbuf);
sshbuf_free(abuf);
sshkey_free(sign_key);
free(principal);
free(principals);
return ret;
}
@ -3093,7 +3092,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 find-principals -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"
@ -3357,18 +3356,18 @@ main(int argc, char **argv)
argc -= optind;
if (sign_op != NULL) {
if (strncmp(sign_op, "find-principal", 14) == 0) {
if (strncmp(sign_op, "find-principals", 15) == 0) {
if (ca_key_path == NULL) {
error("Too few arguments for find-principal:"
error("Too few arguments for find-principals:"
"missing signature file");
exit(1);
}
if (!have_identity) {
error("Too few arguments for find-principal:"
error("Too few arguments for find-principals:"
"missing allowed keys file");
exit(1);
}
return sig_find_principal(ca_key_path, identity_file);
return sig_find_principals(ca_key_path, identity_file);
}
if (cert_principals == NULL || *cert_principals == '\0') {
error("Too few arguments for sign/verify: "

Просмотреть файл

@ -868,13 +868,64 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
}
static int
get_matching_principal_from_line(const char *path, u_long linenum, char *line,
cert_filter_principals(const char *path, u_long linenum,
char **principalsp, const struct sshkey *cert)
{
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)
return SSH_ERR_ALLOC_FAIL;
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,
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("%s: buffer error", __func__);
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("%s: buffer error", __func__);
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, 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)
@ -894,11 +945,12 @@ get_matching_principal_from_line(const char *path, u_long linenum, char *line,
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);
/* Remove principals listed in file but not allowed by cert */
if ((r = cert_filter_principals(path, linenum,
&principals, sign_key)) != 0) {
/* error already displayed */
debug("%s:%lu: cert_filter_principals: %s",
path, linenum, ssh_err(r));
goto done;
}
debug("%s:%lu: matched certificate CA key", path, linenum);
@ -920,8 +972,8 @@ get_matching_principal_from_line(const char *path, u_long linenum, char *line,
}
int
sshsig_find_principal(const char *path, const struct sshkey *sign_key,
char **principal)
sshsig_find_principals(const char *path, const struct sshkey *sign_key,
char **principals)
{
FILE *f = NULL;
char *line = NULL;
@ -939,8 +991,8 @@ sshsig_find_principal(const char *path, const struct sshkey *sign_key,
while (getline(&line, &linesize, f) != -1) {
linenum++;
r = get_matching_principal_from_line(path, linenum, line,
sign_key, principal);
r = get_matching_principals_from_line(path, linenum, line,
sign_key, principals);
free(line);
line = NULL;
if (r == SSH_ERR_KEY_NOT_FOUND)

Просмотреть файл

@ -93,13 +93,12 @@ struct sshsigopt *sshsigopt_parse(const char *opts,
void sshsigopt_free(struct sshsigopt *opts);
/* Get public key from signature */
int
sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey);
int sshsig_get_pubkey(struct sshbuf *signature, struct sshkey **pubkey);
/* Find principal in allowed_keys file, given a sshkey. Returns
* 0 on success.
*/
int sshsig_find_principal(const char *path, const struct sshkey *sign_key,
int sshsig_find_principals(const char *path, const struct sshkey *sign_key,
char **principal);
#endif /* SSHSIG_H */