mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-29 16:54:51 +02:00
upstream: ssh client support for U2F/FIDO keys
OpenBSD-Commit-ID: eb2cfa6cf7419a1895e06e398ea6d41516c5b0bc
This commit is contained in:
parent
01a0670f69
commit
884416bdb1
17
readconf.c
17
readconf.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: readconf.c,v 1.309 2019/09/06 14:45:34 naddy Exp $ */
|
/* $OpenBSD: readconf.c,v 1.310 2019/10/31 21:18:28 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
|
||||||
@ -174,6 +174,7 @@ typedef enum {
|
|||||||
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
|
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
|
||||||
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
|
oFingerprintHash, oUpdateHostkeys, oHostbasedKeyTypes,
|
||||||
oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump,
|
oPubkeyAcceptedKeyTypes, oCASignatureAlgorithms, oProxyJump,
|
||||||
|
oSecurityKeyProvider,
|
||||||
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
|
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
|
||||||
} OpCodes;
|
} OpCodes;
|
||||||
|
|
||||||
@ -214,6 +215,7 @@ static struct {
|
|||||||
{ "smartcarddevice", oUnsupported },
|
{ "smartcarddevice", oUnsupported },
|
||||||
{ "pkcs11provider", oUnsupported },
|
{ "pkcs11provider", oUnsupported },
|
||||||
#endif
|
#endif
|
||||||
|
{ "securitykeyprovider", oSecurityKeyProvider },
|
||||||
{ "rsaauthentication", oUnsupported },
|
{ "rsaauthentication", oUnsupported },
|
||||||
{ "rhostsrsaauthentication", oUnsupported },
|
{ "rhostsrsaauthentication", oUnsupported },
|
||||||
{ "compressionlevel", oUnsupported },
|
{ "compressionlevel", oUnsupported },
|
||||||
@ -1146,6 +1148,10 @@ parse_char_array:
|
|||||||
charptr = &options->pkcs11_provider;
|
charptr = &options->pkcs11_provider;
|
||||||
goto parse_string;
|
goto parse_string;
|
||||||
|
|
||||||
|
case oSecurityKeyProvider:
|
||||||
|
charptr = &options->sk_provider;
|
||||||
|
goto parse_string;
|
||||||
|
|
||||||
case oProxyCommand:
|
case oProxyCommand:
|
||||||
charptr = &options->proxy_command;
|
charptr = &options->proxy_command;
|
||||||
/* Ignore ProxyCommand if ProxyJump already specified */
|
/* Ignore ProxyCommand if ProxyJump already specified */
|
||||||
@ -1906,6 +1912,7 @@ initialize_options(Options * options)
|
|||||||
options->bind_address = NULL;
|
options->bind_address = NULL;
|
||||||
options->bind_interface = NULL;
|
options->bind_interface = NULL;
|
||||||
options->pkcs11_provider = NULL;
|
options->pkcs11_provider = NULL;
|
||||||
|
options->sk_provider = NULL;
|
||||||
options->enable_ssh_keysign = - 1;
|
options->enable_ssh_keysign = - 1;
|
||||||
options->no_host_authentication_for_localhost = - 1;
|
options->no_host_authentication_for_localhost = - 1;
|
||||||
options->identities_only = - 1;
|
options->identities_only = - 1;
|
||||||
@ -2043,6 +2050,8 @@ fill_default_options(Options * options)
|
|||||||
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
|
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_DSA, 0);
|
||||||
#ifdef OPENSSL_HAS_ECC
|
#ifdef OPENSSL_HAS_ECC
|
||||||
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
|
add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_ECDSA, 0);
|
||||||
|
add_identity_file(options, "~/",
|
||||||
|
_PATH_SSH_CLIENT_ID_ECDSA_SK, 0);
|
||||||
#endif
|
#endif
|
||||||
add_identity_file(options, "~/",
|
add_identity_file(options, "~/",
|
||||||
_PATH_SSH_CLIENT_ID_ED25519, 0);
|
_PATH_SSH_CLIENT_ID_ED25519, 0);
|
||||||
@ -2118,6 +2127,8 @@ fill_default_options(Options * options)
|
|||||||
options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
|
options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
|
||||||
if (options->update_hostkeys == -1)
|
if (options->update_hostkeys == -1)
|
||||||
options->update_hostkeys = 0;
|
options->update_hostkeys = 0;
|
||||||
|
if (options->sk_provider == NULL)
|
||||||
|
options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
|
||||||
|
|
||||||
/* Expand KEX name lists */
|
/* Expand KEX name lists */
|
||||||
all_cipher = cipher_alg_list(',', 0);
|
all_cipher = cipher_alg_list(',', 0);
|
||||||
@ -2135,7 +2146,7 @@ fill_default_options(Options * options)
|
|||||||
ASSEMBLE(macs, KEX_CLIENT_MAC, all_mac);
|
ASSEMBLE(macs, KEX_CLIENT_MAC, all_mac);
|
||||||
ASSEMBLE(kex_algorithms, KEX_CLIENT_KEX, all_kex);
|
ASSEMBLE(kex_algorithms, KEX_CLIENT_KEX, all_kex);
|
||||||
ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
|
ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
|
||||||
ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key);
|
ASSEMBLE(pubkey_key_types, PUBKEY_DEFAULT_PK_ALG, all_key);
|
||||||
ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig);
|
ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig);
|
||||||
#undef ASSEMBLE
|
#undef ASSEMBLE
|
||||||
free(all_cipher);
|
free(all_cipher);
|
||||||
@ -2157,6 +2168,7 @@ fill_default_options(Options * options)
|
|||||||
CLEAR_ON_NONE(options->control_path);
|
CLEAR_ON_NONE(options->control_path);
|
||||||
CLEAR_ON_NONE(options->revoked_host_keys);
|
CLEAR_ON_NONE(options->revoked_host_keys);
|
||||||
CLEAR_ON_NONE(options->pkcs11_provider);
|
CLEAR_ON_NONE(options->pkcs11_provider);
|
||||||
|
CLEAR_ON_NONE(options->sk_provider);
|
||||||
if (options->jump_host != NULL &&
|
if (options->jump_host != NULL &&
|
||||||
strcmp(options->jump_host, "none") == 0 &&
|
strcmp(options->jump_host, "none") == 0 &&
|
||||||
options->jump_port == 0 && options->jump_user == NULL) {
|
options->jump_port == 0 && options->jump_user == NULL) {
|
||||||
@ -2673,6 +2685,7 @@ dump_client_config(Options *o, const char *host)
|
|||||||
#ifdef ENABLE_PKCS11
|
#ifdef ENABLE_PKCS11
|
||||||
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
|
dump_cfg_string(oPKCS11Provider, o->pkcs11_provider);
|
||||||
#endif
|
#endif
|
||||||
|
dump_cfg_string(oSecurityKeyProvider, o->sk_provider);
|
||||||
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
|
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
|
||||||
dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
|
dump_cfg_string(oPubkeyAcceptedKeyTypes, o->pubkey_key_types);
|
||||||
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
|
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: readconf.h,v 1.129 2018/11/23 05:08:07 djm Exp $ */
|
/* $OpenBSD: readconf.h,v 1.130 2019/10/31 21:18:28 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
@ -82,6 +82,7 @@ typedef struct {
|
|||||||
char *bind_address; /* local socket address for connection to sshd */
|
char *bind_address; /* local socket address for connection to sshd */
|
||||||
char *bind_interface; /* local interface for bind address */
|
char *bind_interface; /* local interface for bind address */
|
||||||
char *pkcs11_provider; /* PKCS#11 provider */
|
char *pkcs11_provider; /* PKCS#11 provider */
|
||||||
|
char *sk_provider; /* Security key provider */
|
||||||
int verify_host_key_dns; /* Verify host key using DNS */
|
int verify_host_key_dns; /* Verify host key using DNS */
|
||||||
|
|
||||||
int num_identity_files; /* Number of files for RSA/DSA identities. */
|
int num_identity_files; /* Number of files for RSA/DSA identities. */
|
||||||
|
18
ssh.c
18
ssh.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: ssh.c,v 1.507 2019/09/13 04:27:35 djm Exp $ */
|
/* $OpenBSD: ssh.c,v 1.508 2019/10/31 21:18:28 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
|
||||||
@ -1344,6 +1344,22 @@ main(int ac, char **av)
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Expand SecurityKeyProvider if it refers to an environment variable */
|
||||||
|
if (options.sk_provider != NULL && *options.sk_provider == '$' &&
|
||||||
|
strlen(options.sk_provider) > 1) {
|
||||||
|
if ((cp = getenv(options.sk_provider + 1)) == NULL) {
|
||||||
|
debug("Security key provider %s did not resolve; "
|
||||||
|
"disabling", options.sk_provider);
|
||||||
|
free(options.sk_provider);
|
||||||
|
options.sk_provider = NULL;
|
||||||
|
} else {
|
||||||
|
debug2("resolved SecurityKeyProvider %s => %s",
|
||||||
|
options.sk_provider, cp);
|
||||||
|
free(options.sk_provider);
|
||||||
|
options.sk_provider = xstrdup(cp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (muxclient_command != 0 && options.control_path == NULL)
|
if (muxclient_command != 0 && options.control_path == NULL)
|
||||||
fatal("No ControlPath specified for \"-O\" command");
|
fatal("No ControlPath specified for \"-O\" command");
|
||||||
if (options.control_path != NULL) {
|
if (options.control_path != NULL) {
|
||||||
|
111
sshconnect2.c
111
sshconnect2.c
@ -1,4 +1,4 @@
|
|||||||
/* $OpenBSD: sshconnect2.c,v 1.308 2019/08/05 11:50:33 dtucker Exp $ */
|
/* $OpenBSD: sshconnect2.c,v 1.309 2019/10/31 21:18:28 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||||
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
* Copyright (c) 2008 Damien Miller. All rights reserved.
|
||||||
@ -72,6 +72,7 @@
|
|||||||
#include "hostfile.h"
|
#include "hostfile.h"
|
||||||
#include "ssherr.h"
|
#include "ssherr.h"
|
||||||
#include "utf8.h"
|
#include "utf8.h"
|
||||||
|
#include "ssh-sk.h"
|
||||||
|
|
||||||
#ifdef GSSAPI
|
#ifdef GSSAPI
|
||||||
#include "ssh-gss.h"
|
#include "ssh-gss.h"
|
||||||
@ -601,17 +602,23 @@ static char *
|
|||||||
format_identity(Identity *id)
|
format_identity(Identity *id)
|
||||||
{
|
{
|
||||||
char *fp = NULL, *ret = NULL;
|
char *fp = NULL, *ret = NULL;
|
||||||
|
const char *note = "";
|
||||||
|
|
||||||
if (id->key != NULL) {
|
if (id->key != NULL) {
|
||||||
fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
|
fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
|
||||||
SSH_FP_DEFAULT);
|
SSH_FP_DEFAULT);
|
||||||
}
|
}
|
||||||
|
if (id->key) {
|
||||||
|
if ((id->key->flags & SSHKEY_FLAG_EXT) != 0)
|
||||||
|
note = " token";
|
||||||
|
else if (sshkey_type_plain(id->key->type) == KEY_ECDSA_SK)
|
||||||
|
note = " security-key";
|
||||||
|
}
|
||||||
xasprintf(&ret, "%s %s%s%s%s%s%s",
|
xasprintf(&ret, "%s %s%s%s%s%s%s",
|
||||||
id->filename,
|
id->filename,
|
||||||
id->key ? sshkey_type(id->key) : "", id->key ? " " : "",
|
id->key ? sshkey_type(id->key) : "", id->key ? " " : "",
|
||||||
fp ? fp : "",
|
fp ? fp : "",
|
||||||
id->userprovided ? " explicit" : "",
|
id->userprovided ? " explicit" : "", note,
|
||||||
(id->key && (id->key->flags & SSHKEY_FLAG_EXT)) ? " token" : "",
|
|
||||||
id->agent_fd != -1 ? " agent" : "");
|
id->agent_fd != -1 ? " agent" : "");
|
||||||
free(fp);
|
free(fp);
|
||||||
return ret;
|
return ret;
|
||||||
@ -1140,8 +1147,11 @@ static int
|
|||||||
identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
|
identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
|
||||||
const u_char *data, size_t datalen, u_int compat, const char *alg)
|
const u_char *data, size_t datalen, u_int compat, const char *alg)
|
||||||
{
|
{
|
||||||
struct sshkey *prv;
|
struct sshkey *sign_key = NULL, *prv = NULL;
|
||||||
int r;
|
int r = SSH_ERR_INTERNAL_ERROR;
|
||||||
|
|
||||||
|
*sigp = NULL;
|
||||||
|
*lenp = 0;
|
||||||
|
|
||||||
/* The agent supports this key. */
|
/* The agent supports this key. */
|
||||||
if (id->key != NULL && id->agent_fd != -1) {
|
if (id->key != NULL && id->agent_fd != -1) {
|
||||||
@ -1155,27 +1165,46 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
|
|||||||
*/
|
*/
|
||||||
if (id->key != NULL &&
|
if (id->key != NULL &&
|
||||||
(id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) {
|
(id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) {
|
||||||
if ((r = sshkey_sign(id->key, sigp, lenp, data, datalen,
|
sign_key = id->key;
|
||||||
alg, compat)) != 0)
|
} else {
|
||||||
return r;
|
/* Load the private key from the file. */
|
||||||
/*
|
if ((prv = load_identity_file(id)) == NULL)
|
||||||
* PKCS#11 tokens may not support all signature algorithms,
|
return SSH_ERR_KEY_NOT_FOUND;
|
||||||
* so check what we get back.
|
if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
|
||||||
*/
|
error("%s: private key %s contents do not match public",
|
||||||
if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0)
|
__func__, id->filename);
|
||||||
return r;
|
r = SSH_ERR_KEY_NOT_FOUND;
|
||||||
return 0;
|
goto out;
|
||||||
|
}
|
||||||
|
sign_key = prv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load the private key from the file. */
|
if (sshkey_type_plain(sign_key->type) == KEY_ECDSA_SK) {
|
||||||
if ((prv = load_identity_file(id)) == NULL)
|
if (options.sk_provider == NULL) {
|
||||||
return SSH_ERR_KEY_NOT_FOUND;
|
/* Shouldn't happen here; checked in pubkey_prepare() */
|
||||||
if (id->key != NULL && !sshkey_equal_public(prv, id->key)) {
|
fatal("%s: missing SecurityKeyProvider", __func__);
|
||||||
error("%s: private key %s contents do not match public",
|
}
|
||||||
__func__, id->filename);
|
if ((r = sshsk_ecdsa_sign(options.sk_provider, sign_key,
|
||||||
return SSH_ERR_KEY_NOT_FOUND;
|
sigp, lenp, data, datalen, compat)) != 0) {
|
||||||
|
debug("%s: sshsk_ecdsa_sign: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
} else if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen,
|
||||||
|
alg, compat)) != 0) {
|
||||||
|
debug("%s: sshkey_sign: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
r = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat);
|
/*
|
||||||
|
* PKCS#11 tokens may not support all signature algorithms,
|
||||||
|
* so check what we get back.
|
||||||
|
*/
|
||||||
|
if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) {
|
||||||
|
debug("%s: sshkey_check_sigtype: %s", __func__, ssh_err(r));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* success */
|
||||||
|
r = 0;
|
||||||
|
out:
|
||||||
sshkey_free(prv);
|
sshkey_free(prv);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -1450,6 +1479,15 @@ load_identity_file(Identity *id)
|
|||||||
quit = 1;
|
quit = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (private != NULL &&
|
||||||
|
sshkey_type_plain(private->type) == KEY_ECDSA_SK &&
|
||||||
|
options.sk_provider == NULL) {
|
||||||
|
debug("key \"%s\" is a security key, but no "
|
||||||
|
"provider specified", id->filename);
|
||||||
|
sshkey_free(private);
|
||||||
|
private = NULL;
|
||||||
|
quit = 1;
|
||||||
|
}
|
||||||
if (!quit && private != NULL && id->agent_fd == -1 &&
|
if (!quit && private != NULL && id->agent_fd == -1 &&
|
||||||
!(id->key && id->isprivate))
|
!(id->key && id->isprivate))
|
||||||
maybe_add_key_to_agent(id->filename, private, comment,
|
maybe_add_key_to_agent(id->filename, private, comment,
|
||||||
@ -1520,8 +1558,20 @@ pubkey_prepare(Authctxt *authctxt)
|
|||||||
/* list of keys stored in the filesystem and PKCS#11 */
|
/* list of keys stored in the filesystem and PKCS#11 */
|
||||||
for (i = 0; i < options.num_identity_files; i++) {
|
for (i = 0; i < options.num_identity_files; i++) {
|
||||||
key = options.identity_keys[i];
|
key = options.identity_keys[i];
|
||||||
if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER)
|
if (key && key->cert &&
|
||||||
|
key->cert->type != SSH2_CERT_TYPE_USER) {
|
||||||
|
debug("%s: ignoring certificate %s: not a user "
|
||||||
|
"certificate", __func__,
|
||||||
|
options.identity_files[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (key && sshkey_type_plain(key->type) == KEY_ECDSA_SK &&
|
||||||
|
options.sk_provider == NULL) {
|
||||||
|
debug("%s: ignoring security key %s as no "
|
||||||
|
"SecurityKeyProvider has been specified",
|
||||||
|
__func__, options.identity_files[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
options.identity_keys[i] = NULL;
|
options.identity_keys[i] = NULL;
|
||||||
id = xcalloc(1, sizeof(*id));
|
id = xcalloc(1, sizeof(*id));
|
||||||
id->agent_fd = -1;
|
id->agent_fd = -1;
|
||||||
@ -1534,8 +1584,19 @@ pubkey_prepare(Authctxt *authctxt)
|
|||||||
for (i = 0; i < options.num_certificate_files; i++) {
|
for (i = 0; i < options.num_certificate_files; i++) {
|
||||||
key = options.certificates[i];
|
key = options.certificates[i];
|
||||||
if (!sshkey_is_cert(key) || key->cert == NULL ||
|
if (!sshkey_is_cert(key) || key->cert == NULL ||
|
||||||
key->cert->type != SSH2_CERT_TYPE_USER)
|
key->cert->type != SSH2_CERT_TYPE_USER) {
|
||||||
|
debug("%s: ignoring certificate %s: not a user "
|
||||||
|
"certificate", __func__,
|
||||||
|
options.identity_files[i]);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
if (key && sshkey_type_plain(key->type) == KEY_ECDSA_SK &&
|
||||||
|
options.sk_provider == NULL) {
|
||||||
|
debug("%s: ignoring security key certificate %s as no "
|
||||||
|
"SecurityKeyProvider has been specified",
|
||||||
|
__func__, options.identity_files[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
id = xcalloc(1, sizeof(*id));
|
id = xcalloc(1, sizeof(*id));
|
||||||
id->agent_fd = -1;
|
id->agent_fd = -1;
|
||||||
id->key = key;
|
id->key = key;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user