]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: allow security keys to act as host keys as well as user
authordjm@openbsd.org <djm@openbsd.org>
Sun, 15 Dec 2019 18:57:30 +0000 (18:57 +0000)
committerDamien Miller <djm@mindrot.org>
Mon, 16 Dec 2019 03:19:41 +0000 (14:19 +1100)
keys.

Previously we didn't do this because we didn't want to expose
the attack surface presented by USB and FIDO protocol handling,
but now that this is insulated behind ssh-sk-helper there is
less risk.

ok markus@

OpenBSD-Commit-ID: 77b068dd133b8d87e0f010987bd5131e640ee64c

monitor.c
monitor_wrap.c
myproposal.h
readconf.c
servconf.c
servconf.h
sshd.c

index 64eca98d61f1dc237e561fe775675e777a7290ea..6ee44204c6fb16b076fdf2c56af06fede0d5e7dc 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.205 2019/11/25 10:23:36 djm Exp $ */
+/* $OpenBSD: monitor.c,v 1.206 2019/12/15 18:57:30 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -679,7 +679,7 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m)
 
        if ((key = get_hostkey_by_index(keyid)) != NULL) {
                if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg,
-                   NULL, compat)) != 0)
+                   options.sk_provider, compat)) != 0)
                        fatal("%s: sshkey_sign failed: %s",
                            __func__, ssh_err(r));
        } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL &&
index 06599e3b1f364ccfee3aeabb6ea6638738d84bfe..001a8fa1c99a26d547464586877e84cc637f8703 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.116 2019/11/25 00:51:37 djm Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.117 2019/12/15 18:57:30 djm Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -224,8 +224,6 @@ mm_sshkey_sign(struct ssh *ssh, struct sshkey *key, u_char **sigp, size_t *lenp,
        int r;
 
        debug3("%s entering", __func__);
-       if (sk_provider != NULL)
-               fatal("%s: sk_provider != NULL", __func__);
        if ((m = sshbuf_new()) == NULL)
                fatal("%s: sshbuf_new failed", __func__);
        if ((r = sshbuf_put_u32(m, ndx)) != 0 ||
index b393db8b04dfedc09313016a8ef77af295645995..6688c30660d23d3b5019075081d64945476f90f3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: myproposal.h,v 1.62 2019/12/10 22:43:19 djm Exp $ */
+/* $OpenBSD: myproposal.h,v 1.63 2019/12/15 18:57:30 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
 #  define HOSTKEY_ECDSA_CERT_METHODS \
        "ecdsa-sha2-nistp256-cert-v01@openssh.com," \
        "ecdsa-sha2-nistp384-cert-v01@openssh.com," \
-       "ecdsa-sha2-nistp521-cert-v01@openssh.com,"
+       "ecdsa-sha2-nistp521-cert-v01@openssh.com," \
+       "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,"
 #  define HOSTKEY_ECDSA_METHODS \
        "ecdsa-sha2-nistp256," \
        "ecdsa-sha2-nistp384," \
-       "ecdsa-sha2-nistp521,"
+       "ecdsa-sha2-nistp521," \
+       "sk-ecdsa-sha2-nistp256@openssh.com,"
 # else /* OPENSSL_HAS_NISTP521 */
 #  define KEX_ECDH_METHODS \
        "ecdh-sha2-nistp256," \
        "ecdh-sha2-nistp384,"
 #  define HOSTKEY_ECDSA_CERT_METHODS \
        "ecdsa-sha2-nistp256-cert-v01@openssh.com," \
-       "ecdsa-sha2-nistp384-cert-v01@openssh.com,"
+       "ecdsa-sha2-nistp384-cert-v01@openssh.com," \
+       "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,"
 #  define HOSTKEY_ECDSA_METHODS \
        "ecdsa-sha2-nistp256," \
-       "ecdsa-sha2-nistp384,"
-# endif /* OPENSSL_HAS_NISTP521 */
-# define USERKEY_ECDSA_SK_CERT_METHODS \
-       "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,"
-# define USERKEY_ECDSA_SK_METHODS \
+       "ecdsa-sha2-nistp384," \
        "sk-ecdsa-sha2-nistp256@openssh.com,"
+# endif /* OPENSSL_HAS_NISTP521 */
 #else /* OPENSSL_HAS_ECC */
 # define KEX_ECDH_METHODS
 # define HOSTKEY_ECDSA_CERT_METHODS
 # define HOSTKEY_ECDSA_METHODS
-# define USERKEY_ECDSA_SK_CERT_METHODS
-# define USERKEY_ECDSA_SK_METHODS
 #endif /* OPENSSL_HAS_ECC */
 
 #ifdef OPENSSL_HAVE_EVPGCM
 #define        KEX_DEFAULT_PK_ALG      \
        HOSTKEY_ECDSA_CERT_METHODS \
        "ssh-ed25519-cert-v01@openssh.com," \
+       "sk-ssh-ed25519-cert-v01@openssh.com," \
        "rsa-sha2-512-cert-v01@openssh.com," \
        "rsa-sha2-256-cert-v01@openssh.com," \
        "ssh-rsa-cert-v01@openssh.com," \
        HOSTKEY_ECDSA_METHODS \
        "ssh-ed25519," \
+       "sk-ssh-ed25519@openssh.com," \
        "rsa-sha2-512," \
        "rsa-sha2-256," \
        "ssh-rsa"
 /* Not a KEX value, but here so all the algorithm defaults are together */
 #define        SSH_ALLOWED_CA_SIGALGS  \
        HOSTKEY_ECDSA_METHODS \
-       USERKEY_ECDSA_SK_METHODS \
        "ssh-ed25519," \
        "sk-ssh-ed25519@openssh.com," \
        "rsa-sha2-512," \
        "rsa-sha2-256," \
        "ssh-rsa"
 
-#define        PUBKEY_DEFAULT_PK_ALG   \
-       USERKEY_ECDSA_SK_CERT_METHODS \
-       HOSTKEY_ECDSA_CERT_METHODS \
-       "sk-ssh-ed25519-cert-v01@openssh.com," \
-       "ssh-ed25519-cert-v01@openssh.com," \
-       "rsa-sha2-512-cert-v01@openssh.com," \
-       "rsa-sha2-256-cert-v01@openssh.com," \
-       "ssh-rsa-cert-v01@openssh.com," \
-       USERKEY_ECDSA_SK_METHODS \
-       HOSTKEY_ECDSA_METHODS \
-       "sk-ssh-ed25519@openssh.com," \
-       "ssh-ed25519," \
-       "rsa-sha2-512," \
-       "rsa-sha2-256," \
-       "ssh-rsa"
-
 #else /* WITH_OPENSSL */
 
 #define KEX_SERVER_KEX         \
 #define        KEX_DEFAULT_PK_ALG      \
        "ssh-ed25519-cert-v01@openssh.com," \
        "ssh-ed25519"
-#define PUBKEY_DEFAULT_PK_ALG KEX_DEFAULT_PK_ALG
 #define        KEX_SERVER_ENCRYPT \
        "chacha20-poly1305@openssh.com," \
        "aes128-ctr,aes192-ctr,aes256-ctr"
index c046e4dbf4d9d0df01466b39065a883f124255b7..4ea8ec56662d46174eebba824a8bbc313ccb85f4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.314 2019/11/14 21:27:29 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.315 2019/12/15 18:57:30 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -2153,7 +2153,7 @@ fill_default_options(Options * options)
        ASSEMBLE(macs, KEX_CLIENT_MAC, all_mac);
        ASSEMBLE(kex_algorithms, KEX_CLIENT_KEX, all_kex);
        ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
-       ASSEMBLE(pubkey_key_types, PUBKEY_DEFAULT_PK_ALG, all_key);
+       ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key);
        ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig);
 #undef ASSEMBLE
        free(all_cipher);
index 1f3beab4aab6b70fbc2e0892b5dc6f225a6f8ea6..30cd598403f814cf1597ece19f106b9d0f3adbb6 100644 (file)
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.354 2019/11/25 00:52:46 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.355 2019/12/15 18:57:30 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -171,6 +171,7 @@ initialize_server_options(ServerOptions *options)
        options->authorized_keys_command = NULL;
        options->authorized_keys_command_user = NULL;
        options->revoked_keys_file = NULL;
+       options->sk_provider = NULL;
        options->trusted_user_ca_keys = NULL;
        options->authorized_principals_file = NULL;
        options->authorized_principals_command = NULL;
@@ -211,7 +212,7 @@ assemble_algorithms(ServerOptions *o)
        ASSEMBLE(kex_algorithms, KEX_SERVER_KEX, all_kex);
        ASSEMBLE(hostkeyalgorithms, KEX_DEFAULT_PK_ALG, all_key);
        ASSEMBLE(hostbased_key_types, KEX_DEFAULT_PK_ALG, all_key);
-       ASSEMBLE(pubkey_key_types, PUBKEY_DEFAULT_PK_ALG, all_key);
+       ASSEMBLE(pubkey_key_types, KEX_DEFAULT_PK_ALG, all_key);
        ASSEMBLE(ca_sign_algorithms, SSH_ALLOWED_CA_SIGALGS, all_sig);
 #undef ASSEMBLE
        free(all_cipher);
@@ -428,6 +429,8 @@ fill_default_server_options(ServerOptions *options)
                options->disable_forwarding = 0;
        if (options->expose_userauth_info == -1)
                options->expose_userauth_info = 0;
+       if (options->sk_provider == NULL)
+               options->sk_provider = xstrdup("internal");
 
        assemble_algorithms(options);
 
@@ -447,6 +450,7 @@ fill_default_server_options(ServerOptions *options)
        CLEAR_ON_NONE(options->banner);
        CLEAR_ON_NONE(options->trusted_user_ca_keys);
        CLEAR_ON_NONE(options->revoked_keys_file);
+       CLEAR_ON_NONE(options->sk_provider);
        CLEAR_ON_NONE(options->authorized_principals_file);
        CLEAR_ON_NONE(options->adm_forced_command);
        CLEAR_ON_NONE(options->chroot_directory);
@@ -512,7 +516,7 @@ typedef enum {
        sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
        sStreamLocalBindMask, sStreamLocalBindUnlink,
        sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
-       sExposeAuthInfo, sRDomain, sPubkeyAuthOptions,
+       sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
        sDeprecated, sIgnore, sUnsupported
 } ServerOpCodes;
 
@@ -662,6 +666,7 @@ static struct {
        { "exposeauthinfo", sExposeAuthInfo, SSHCFG_ALL },
        { "rdomain", sRDomain, SSHCFG_ALL },
        { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
+       { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
        { NULL, sBadOption, 0 }
 };
 
@@ -2025,6 +2030,10 @@ process_server_config_line(ServerOptions *options, char *line,
                charptr = &options->revoked_keys_file;
                goto parse_filename;
 
+       case sSecurityKeyProvider:
+               charptr = &options->sk_provider;
+               goto parse_filename;
+
        case sIPQoS:
                arg = strdelim(&cp);
                if ((value = parse_ipqos(arg)) == -1)
@@ -2646,6 +2655,7 @@ dump_config(ServerOptions *o)
        dump_cfg_string(sChrootDirectory, o->chroot_directory);
        dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
        dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
+       dump_cfg_string(sSecurityKeyProvider, o->sk_provider);
        dump_cfg_string(sAuthorizedPrincipalsFile,
            o->authorized_principals_file);
        dump_cfg_string(sVersionAddendum, *o->version_addendum == '\0'
@@ -2664,7 +2674,7 @@ dump_config(ServerOptions *o)
        dump_cfg_string(sHostKeyAlgorithms, o->hostkeyalgorithms ?
            o->hostkeyalgorithms : KEX_DEFAULT_PK_ALG);
        dump_cfg_string(sPubkeyAcceptedKeyTypes, o->pubkey_key_types ?
-           o->pubkey_key_types : PUBKEY_DEFAULT_PK_ALG);
+           o->pubkey_key_types : KEX_DEFAULT_PK_ALG);
        dump_cfg_string(sRDomain, o->routing_domain);
 
        /* string arguments requiring a lookup */
index 9f202260a54735cb4c0fdc4d29392645eaf6e6d3..6fc1efb2c8a2bedd008c3e06f5c481e5c819e216 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.141 2019/11/25 00:52:46 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.142 2019/12/15 18:57:30 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -215,6 +215,7 @@ typedef struct {
        int     fingerprint_hash;
        int     expose_userauth_info;
        u_int64_t timing_secret;
+       char   *sk_provider;
 }       ServerOptions;
 
 /* Information about the incoming connection as used by Match */
diff --git a/sshd.c b/sshd.c
index 1e4d8a2955727759cbed747419cf5ea4990479cd..0cf13a741744daed887283d9bb952086c63f81df 100644 (file)
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.541 2019/11/18 16:10:05 naddy Exp $ */
+/* $OpenBSD: sshd.c,v 1.542 2019/12/15 18:57:30 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
 #include "auth-options.h"
 #include "version.h"
 #include "ssherr.h"
+#include "sk-api.h"
 
 /* Re-exec fds */
 #define REEXEC_DEVCRYPTO_RESERVED_FD   (STDERR_FILENO + 1)
@@ -632,6 +633,8 @@ list_hostkey_types(void)
                case KEY_DSA:
                case KEY_ECDSA:
                case KEY_ED25519:
+               case KEY_ECDSA_SK:
+               case KEY_ED25519_SK:
                case KEY_XMSS:
                        append_hostkey_type(b, sshkey_ssh_name(key));
                        break;
@@ -651,6 +654,8 @@ list_hostkey_types(void)
                case KEY_DSA_CERT:
                case KEY_ECDSA_CERT:
                case KEY_ED25519_CERT:
+               case KEY_ECDSA_SK_CERT:
+               case KEY_ED25519_SK_CERT:
                case KEY_XMSS_CERT:
                        append_hostkey_type(b, sshkey_ssh_name(key));
                        break;
@@ -675,6 +680,8 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
                case KEY_DSA_CERT:
                case KEY_ECDSA_CERT:
                case KEY_ED25519_CERT:
+               case KEY_ECDSA_SK_CERT:
+               case KEY_ED25519_SK_CERT:
                case KEY_XMSS_CERT:
                        key = sensitive_data.host_certificates[i];
                        break;
@@ -684,10 +691,20 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
                                key = sensitive_data.host_pubkeys[i];
                        break;
                }
-               if (key != NULL && key->type == type &&
-                   (key->type != KEY_ECDSA || key->ecdsa_nid == nid))
+               if (key == NULL || key->type != type)
+                       continue;
+               switch (type) {
+               case KEY_ECDSA:
+               case KEY_ECDSA_SK:
+               case KEY_ECDSA_CERT:
+               case KEY_ECDSA_SK_CERT:
+                       if (key->ecdsa_nid != nid)
+                               continue;
+                       /* FALLTHROUGH */
+               default:
                        return need_private ?
                            sensitive_data.host_keys[i] : key;
+               }
        }
        return NULL;
 }
@@ -1723,7 +1740,14 @@ main(int ac, char **av)
                    &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
                        do_log2(ll, "Unable to load host key \"%s\": %s",
                            options.host_key_files[i], ssh_err(r));
-               if (r == 0 && (r = sshkey_shield_private(key)) != 0) {
+               if (sshkey_is_sk(key) &&
+                   key->sk_flags & SSH_SK_USER_PRESENCE_REQD) {
+                       debug("host key %s requires user presence, ignoring",
+                           options.host_key_files[i]);
+                       key->sk_flags &= ~SSH_SK_USER_PRESENCE_REQD;
+               }
+               if (r == 0 && key != NULL &&
+                   (r = sshkey_shield_private(key)) != 0) {
                        do_log2(ll, "Unable to shield host key \"%s\": %s",
                            options.host_key_files[i], ssh_err(r));
                        sshkey_free(key);
@@ -1760,6 +1784,8 @@ main(int ac, char **av)
                case KEY_DSA:
                case KEY_ECDSA:
                case KEY_ED25519:
+               case KEY_ECDSA_SK:
+               case KEY_ED25519_SK:
                case KEY_XMSS:
                        if (have_agent || key != NULL)
                                sensitive_data.have_ssh2_key = 1;
@@ -2212,17 +2238,19 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey,
        if (use_privsep) {
                if (privkey) {
                        if (mm_sshkey_sign(ssh, privkey, signature, slenp,
-                           data, dlen, alg, NULL, ssh->compat) < 0)
+                           data, dlen, alg, options.sk_provider,
+                           ssh->compat) < 0)
                                fatal("%s: privkey sign failed", __func__);
                } else {
                        if (mm_sshkey_sign(ssh, pubkey, signature, slenp,
-                           data, dlen, alg, NULL, ssh->compat) < 0)
+                           data, dlen, alg, options.sk_provider,
+                           ssh->compat) < 0)
                                fatal("%s: pubkey sign failed", __func__);
                }
        } else {
                if (privkey) {
                        if (sshkey_sign(privkey, signature, slenp, data, dlen,
-                           alg, NULL, ssh->compat) < 0)
+                           alg, options.sk_provider, ssh->compat) < 0)
                                fatal("%s: privkey sign failed", __func__);
                } else {
                        if ((r = ssh_agent_sign(auth_sock, pubkey,