mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-31 01:35:11 +02:00
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
This commit is contained in:
parent
65cf8730de
commit
56cffcc09f
19
ssh-keygen.1
19
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@cs.hut.fi>
|
.\" Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
.\" Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -35,7 +35,7 @@
|
|||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" 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
|
.Dt SSH-KEYGEN 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -138,6 +138,10 @@
|
|||||||
.Fl f Ar krl_file
|
.Fl f Ar krl_file
|
||||||
.Ar
|
.Ar
|
||||||
.Nm ssh-keygen
|
.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 Y Cm check-novalidate
|
||||||
.Fl n Ar namespace
|
.Fl n Ar namespace
|
||||||
.Fl s Ar signature_file
|
.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
|
Specifies a path to a library that will be used when creating
|
||||||
FIDO authenticator-hosted keys, overriding the default of using
|
FIDO authenticator-hosted keys, overriding the default of using
|
||||||
the internal USB HID support.
|
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
|
.It Fl Y Cm check-novalidate
|
||||||
Checks that a signature generated using
|
Checks that a signature generated using
|
||||||
.Nm
|
.Nm
|
||||||
|
84
ssh-keygen.c
84
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@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
@ -2599,7 +2599,7 @@ sign_one(struct sshkey *signkey, const char *filename, int fd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 i, fd = -1, r, ret = -1;
|
||||||
int agent_fd = -1;
|
int agent_fd = -1;
|
||||||
@ -2670,8 +2670,8 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
verify(const char *signature, const char *sig_namespace, const char *principal,
|
sig_verify(const char *signature, const char *sig_namespace,
|
||||||
const char *allowed_keys, const char *revoked_keys)
|
const char *principal, const char *allowed_keys, const char *revoked_keys)
|
||||||
{
|
{
|
||||||
int r, ret = -1, sigfd = -1;
|
int r, ret = -1, sigfd = -1;
|
||||||
struct sshbuf *sigbuf = NULL, *abuf = NULL;
|
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) {
|
if ((r = sshsig_dearmor(abuf, &sigbuf)) != 0) {
|
||||||
error("%s: sshsig_armor: %s", __func__, ssh_err(r));
|
error("%s: sshsig_armor: %s", __func__, ssh_err(r));
|
||||||
return r;
|
goto done;
|
||||||
}
|
}
|
||||||
if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace,
|
if ((r = sshsig_verify_fd(sigbuf, STDIN_FILENO, sig_namespace,
|
||||||
&sign_key, &sig_details)) != 0)
|
&sign_key, &sig_details)) != 0)
|
||||||
@ -2757,6 +2757,57 @@ done:
|
|||||||
return ret;
|
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
|
static void
|
||||||
do_moduli_gen(const char *out_file, char **opts, size_t nopts)
|
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"
|
" ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number]\n"
|
||||||
" file ...\n"
|
" file ...\n"
|
||||||
" ssh-keygen -Q -f krl_file 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 check-novalidate -n namespace -s signature_file\n"
|
||||||
" ssh-keygen -Y sign -f key_file -n namespace 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"
|
" ssh-keygen -Y verify -f allowed_signers_file -I signer_identity\n"
|
||||||
@ -3305,6 +3357,19 @@ main(int argc, char **argv)
|
|||||||
argc -= optind;
|
argc -= optind;
|
||||||
|
|
||||||
if (sign_op != NULL) {
|
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') {
|
if (cert_principals == NULL || *cert_principals == '\0') {
|
||||||
error("Too few arguments for sign/verify: "
|
error("Too few arguments for sign/verify: "
|
||||||
"missing namespace");
|
"missing namespace");
|
||||||
@ -3316,15 +3381,16 @@ main(int argc, char **argv)
|
|||||||
"missing key");
|
"missing key");
|
||||||
exit(1);
|
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) {
|
} else if (strncmp(sign_op, "check-novalidate", 16) == 0) {
|
||||||
if (ca_key_path == NULL) {
|
if (ca_key_path == NULL) {
|
||||||
error("Too few arguments for check-novalidate: "
|
error("Too few arguments for check-novalidate: "
|
||||||
"missing signature file");
|
"missing signature file");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return verify(ca_key_path, cert_principals,
|
return sig_verify(ca_key_path, cert_principals,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
} else if (strncmp(sign_op, "verify", 6) == 0) {
|
} else if (strncmp(sign_op, "verify", 6) == 0) {
|
||||||
if (ca_key_path == NULL) {
|
if (ca_key_path == NULL) {
|
||||||
error("Too few arguments for verify: "
|
error("Too few arguments for verify: "
|
||||||
@ -3341,7 +3407,7 @@ main(int argc, char **argv)
|
|||||||
"missing principal ID");
|
"missing principal ID");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
return verify(ca_key_path, cert_principals,
|
return sig_verify(ca_key_path, cert_principals,
|
||||||
cert_key_id, identity_file, rr_hostname);
|
cert_key_id, identity_file, rr_hostname);
|
||||||
}
|
}
|
||||||
usage();
|
usage();
|
||||||
|
117
sshsig.c
117
sshsig.c
@ -866,3 +866,120 @@ sshsig_check_allowed_keys(const char *path, const struct sshkey *sign_key,
|
|||||||
free(line);
|
free(line);
|
||||||
return r == 0 ? SSH_ERR_KEY_NOT_FOUND : r;
|
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;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user