upstream commit
allow ssh to use certificates accompanied by a private key file but no corresponding plain *.pub public key. bz#2617 based on patch from Adam Eijdenberg; ok dtucker@ markus@ Upstream-ID: 295668dca2c39505281577217583ddd2bd4b00b9
This commit is contained in:
parent
0fb1a617a0
commit
1e24552716
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshconnect2.c,v 1.254 2017/02/03 02:56:00 dtucker Exp $ */
|
||||
/* $OpenBSD: sshconnect2.c,v 1.255 2017/03/11 23:40:26 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
||||
|
@ -996,11 +996,11 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
|
|||
}
|
||||
|
||||
static const char *
|
||||
identity_sign_encode(struct identity *id)
|
||||
key_sign_encode(const struct sshkey *key)
|
||||
{
|
||||
struct ssh *ssh = active_state;
|
||||
|
||||
if (id->key->type == KEY_RSA) {
|
||||
if (key->type == KEY_RSA) {
|
||||
switch (ssh->kex->rsa_sha2) {
|
||||
case 256:
|
||||
return "rsa-sha2-256";
|
||||
|
@ -1008,7 +1008,7 @@ identity_sign_encode(struct identity *id)
|
|||
return "rsa-sha2-512";
|
||||
}
|
||||
}
|
||||
return key_ssh_name(id->key);
|
||||
return key_ssh_name(key);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -1017,30 +1017,49 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
|
|||
{
|
||||
Key *prv;
|
||||
int ret;
|
||||
const char *alg;
|
||||
|
||||
alg = identity_sign_encode(id);
|
||||
|
||||
/* the agent supports this key */
|
||||
if (id->agent_fd != -1)
|
||||
if (id->key != NULL && id->agent_fd != -1)
|
||||
return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp,
|
||||
data, datalen, alg, compat);
|
||||
data, datalen, key_sign_encode(id->key), compat);
|
||||
|
||||
/*
|
||||
* we have already loaded the private key or
|
||||
* the private key is stored in external hardware
|
||||
*/
|
||||
if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))
|
||||
return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg,
|
||||
compat));
|
||||
if (id->key != NULL &&
|
||||
(id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)))
|
||||
return (sshkey_sign(id->key, sigp, lenp, data, datalen,
|
||||
key_sign_encode(id->key), compat));
|
||||
|
||||
/* load the private key from the file */
|
||||
if ((prv = load_identity_file(id)) == NULL)
|
||||
return SSH_ERR_KEY_NOT_FOUND;
|
||||
ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat);
|
||||
ret = sshkey_sign(prv, sigp, lenp, data, datalen,
|
||||
key_sign_encode(prv), compat);
|
||||
sshkey_free(prv);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
id_filename_matches(Identity *id, Identity *private_id)
|
||||
{
|
||||
const char *suffixes[] = { ".pub", "-cert.pub", NULL };
|
||||
size_t len = strlen(id->filename), plen = strlen(private_id->filename);
|
||||
size_t i, slen;
|
||||
|
||||
if (strcmp(id->filename, private_id->filename) == 0)
|
||||
return 1;
|
||||
for (i = 0; suffixes[i]; i++) {
|
||||
slen = strlen(suffixes[i]);
|
||||
if (len > slen && plen == len - slen &&
|
||||
strcmp(id->filename + (len - slen), suffixes[i]) == 0 &&
|
||||
memcmp(id->filename, private_id->filename, plen) == 0)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
|
||||
{
|
||||
|
@ -1083,7 +1102,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
|
|||
} else {
|
||||
buffer_put_cstring(&b, authctxt->method->name);
|
||||
buffer_put_char(&b, have_sig);
|
||||
buffer_put_cstring(&b, identity_sign_encode(id));
|
||||
buffer_put_cstring(&b, key_sign_encode(id->key));
|
||||
}
|
||||
buffer_put_string(&b, blob, bloblen);
|
||||
|
||||
|
@ -1103,6 +1122,24 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
|
|||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Exact key matches are preferred, but also allow
|
||||
* filename matches for non-PKCS#11/agent keys that
|
||||
* didn't load public keys. This supports the case
|
||||
* of keeping just a private key file and public
|
||||
* certificate on disk.
|
||||
*/
|
||||
if (!matched && !id->isprivate && id->agent_fd == -1 &&
|
||||
(id->key->flags & SSHKEY_FLAG_EXT) == 0) {
|
||||
TAILQ_FOREACH(private_id, &authctxt->keys, next) {
|
||||
if (private_id->key == NULL &&
|
||||
id_filename_matches(id, private_id)) {
|
||||
id = private_id;
|
||||
matched = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matched) {
|
||||
debug2("%s: using private key \"%s\"%s for "
|
||||
"certificate", __func__, id->filename,
|
||||
|
@ -1181,7 +1218,7 @@ send_pubkey_test(Authctxt *authctxt, Identity *id)
|
|||
packet_put_cstring(authctxt->method->name);
|
||||
packet_put_char(have_sig);
|
||||
if (!(datafellows & SSH_BUG_PKAUTH))
|
||||
packet_put_cstring(identity_sign_encode(id));
|
||||
packet_put_cstring(key_sign_encode(id->key));
|
||||
packet_put_string(blob, bloblen);
|
||||
free(blob);
|
||||
packet_send();
|
||||
|
|
Loading…
Reference in New Issue