correctly match ECDSA subtype (== curve) for offered/recevied
authordjm <djm@openbsd.org>
Mon, 26 Jan 2015 06:10:03 +0000 (06:10 +0000)
committerdjm <djm@openbsd.org>
Mon, 26 Jan 2015 06:10:03 +0000 (06:10 +0000)
host keys. Fixes connection-killing host key mismatches when
a server offers multiple ECDSA keys with different curve type
(an extremely unlikely configuration).

ok markus, "looks mechanical" deraadt@

14 files changed:
usr.bin/ssh/auth.h
usr.bin/ssh/kex.c
usr.bin/ssh/kex.h
usr.bin/ssh/kexc25519c.c
usr.bin/ssh/kexc25519s.c
usr.bin/ssh/kexdhc.c
usr.bin/ssh/kexdhs.c
usr.bin/ssh/kexecdhc.c
usr.bin/ssh/kexecdhs.c
usr.bin/ssh/kexgexc.c
usr.bin/ssh/kexgexs.c
usr.bin/ssh/ssh_api.c
usr.bin/ssh/sshconnect.c
usr.bin/ssh/sshd.c

index 3cbc7ff..26250dc 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.h,v 1.80 2015/01/19 20:16:15 markus Exp $ */
+/* $OpenBSD: auth.h,v 1.81 2015/01/26 06:10:03 djm Exp $ */
 
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
@@ -180,8 +180,8 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *,
 /* hostkey handling */
 Key    *get_hostkey_by_index(int);
 Key    *get_hostkey_public_by_index(int, struct ssh *);
-Key    *get_hostkey_public_by_type(int, struct ssh *);
-Key    *get_hostkey_private_by_type(int, struct ssh *);
+Key    *get_hostkey_public_by_type(int, int, struct ssh *);
+Key    *get_hostkey_private_by_type(int, int, struct ssh *);
 int     get_hostkey_index(Key *, struct ssh *);
 int     ssh1_session_key(BIGNUM *);
 int     sshd_hostkey_sign(Key *, Key *, u_char **, size_t *, u_char *, size_t, u_int);
index 417896b..f0123d7 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.c,v 1.103 2015/01/20 23:14:00 deraadt Exp $ */
+/* $OpenBSD: kex.c,v 1.104 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  *
@@ -527,6 +527,7 @@ choose_hostkeyalg(struct kex *k, char *client, char *server)
        k->hostkey_type = sshkey_type_from_name(hostkeyalg);
        if (k->hostkey_type == KEY_UNSPEC)
                return SSH_ERR_INTERNAL_ERROR;
+       k->hostkey_nid = sshkey_ecdsa_nid_from_name(hostkeyalg);
        free(hostkeyalg);
        return 0;
 }
index 1798eea..45d3577 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kex.h,v 1.69 2015/01/19 20:16:15 markus Exp $ */
+/* $OpenBSD: kex.h,v 1.70 2015/01/26 06:10:03 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -116,6 +116,7 @@ struct kex {
        int     server;
        char    *name;
        int     hostkey_type;
+       int     hostkey_nid;
        u_int   kex_type;
        int     roaming;
        struct sshbuf *my;
@@ -127,8 +128,8 @@ struct kex {
        char    *client_version_string;
        char    *server_version_string;
        int     (*verify_host_key)(struct sshkey *, struct ssh *);
-       struct sshkey *(*load_host_public_key)(int, struct ssh *);
-       struct sshkey *(*load_host_private_key)(int, struct ssh *);
+       struct sshkey *(*load_host_public_key)(int, int, struct ssh *);
+       struct sshkey *(*load_host_private_key)(int, int, struct ssh *);
        int     (*host_key_index)(struct sshkey *, struct ssh *);
        int     (*sign)(struct sshkey *, struct sshkey *,
            u_char **, size_t *, u_char *, size_t, u_int);
index 240f309..3b3659e 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexc25519c.c,v 1.6 2015/01/19 20:16:15 markus Exp $ */
+/* $OpenBSD: kexc25519c.c,v 1.7 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -90,7 +90,9 @@ input_kex_c25519_reply(int type, u_int32_t seq, void *ctxt)
            (r = sshkey_from_blob(server_host_key_blob, sbloblen,
            &server_host_key)) != 0)
                goto out;
-       if (server_host_key->type != kex->hostkey_type) {
+       if (server_host_key->type != kex->hostkey_type ||
+           (kex->hostkey_type == KEY_ECDSA &&
+           server_host_key->ecdsa_nid != kex->hostkey_nid)) {
                r = SSH_ERR_KEY_TYPE_MISMATCH;
                goto out;
        }
index 867b6e7..bd8e314 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexc25519s.c,v 1.7 2015/01/20 07:55:33 djm Exp $ */
+/* $OpenBSD: kexc25519s.c,v 1.8 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -73,8 +73,10 @@ input_kex_c25519_init(int type, u_int32_t seq, void *ctxt)
                r = SSH_ERR_INVALID_ARGUMENT;
                goto out;
        }
-       server_host_public = kex->load_host_public_key(kex->hostkey_type, ssh);
-       server_host_private = kex->load_host_private_key(kex->hostkey_type, ssh);
+       server_host_public = kex->load_host_public_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
+       server_host_private = kex->load_host_private_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
        if (server_host_public == NULL) {
                r = SSH_ERR_NO_HOSTKEY_LOADED;
                goto out;
index 388c77a..d532686 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexdhc.c,v 1.17 2015/01/19 20:16:15 markus Exp $ */
+/* $OpenBSD: kexdhc.c,v 1.18 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  *
@@ -109,7 +109,9 @@ input_kex_dh(int type, u_int32_t seq, void *ctxt)
            (r = sshkey_from_blob(server_host_key_blob, sbloblen,
            &server_host_key)) != 0)
                goto out;
-       if (server_host_key->type != kex->hostkey_type) {
+       if (server_host_key->type != kex->hostkey_type ||
+           (kex->hostkey_type == KEY_ECDSA &&
+           server_host_key->ecdsa_nid != kex->hostkey_nid)) {
                r = SSH_ERR_KEY_TYPE_MISMATCH;
                goto out;
        }
index 0ceea56..a6c0cb8 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexdhs.c,v 1.21 2015/01/20 07:55:33 djm Exp $ */
+/* $OpenBSD: kexdhs.c,v 1.22 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  *
@@ -96,8 +96,10 @@ input_kex_dh_init(int type, u_int32_t seq, void *ctxt)
                r = SSH_ERR_INVALID_ARGUMENT;
                goto out;
        }
-       server_host_public = kex->load_host_public_key(kex->hostkey_type, ssh);
-       server_host_private = kex->load_host_private_key(kex->hostkey_type, ssh);
+       server_host_public = kex->load_host_public_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
+       server_host_private = kex->load_host_private_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
        if (server_host_public == NULL) {
                r = SSH_ERR_NO_HOSTKEY_LOADED;
                goto out;
index dd7a21d..63b6e10 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexecdhc.c,v 1.9 2015/01/19 20:16:15 markus Exp $ */
+/* $OpenBSD: kexecdhc.c,v 1.10 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -120,7 +120,9 @@ input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt)
            (r = sshkey_from_blob(server_host_key_blob, sbloblen,
            &server_host_key)) != 0)
                goto out;
-       if (server_host_key->type != kex->hostkey_type) {
+       if (server_host_key->type != kex->hostkey_type ||
+           (kex->hostkey_type == KEY_ECDSA &&
+           server_host_key->ecdsa_nid != kex->hostkey_nid)) {
                r = SSH_ERR_KEY_TYPE_MISMATCH;
                goto out;
        }
index 48e9226..13be60f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexecdhs.c,v 1.13 2015/01/20 07:55:33 djm Exp $ */
+/* $OpenBSD: kexecdhs.c,v 1.14 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2010 Damien Miller.  All rights reserved.
@@ -91,8 +91,10 @@ input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt)
                r = SSH_ERR_INVALID_ARGUMENT;
                goto out;
        }
-       server_host_public = kex->load_host_public_key(kex->hostkey_type, ssh);
-       server_host_private = kex->load_host_private_key(kex->hostkey_type, ssh);
+       server_host_public = kex->load_host_public_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
+       server_host_private = kex->load_host_private_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
        if (server_host_public == NULL) {
                r = SSH_ERR_NO_HOSTKEY_LOADED;
                goto out;
index 9eda14e..322c29a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgexc.c,v 1.19 2015/01/19 20:16:15 markus Exp $ */
+/* $OpenBSD: kexgexc.c,v 1.20 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2000 Niels Provos.  All rights reserved.
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
@@ -171,6 +171,12 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt)
                r = SSH_ERR_KEY_TYPE_MISMATCH;
                goto out;
        }
+       if (server_host_key->type != kex->hostkey_type ||
+           (kex->hostkey_type == KEY_ECDSA &&
+           server_host_key->ecdsa_nid != kex->hostkey_nid)) {
+               r = SSH_ERR_KEY_TYPE_MISMATCH;
+               goto out;
+       }
        if (kex->verify_host_key(server_host_key, ssh) == -1) {
                r = SSH_ERR_SIGNATURE_INVALID;
                goto out;
index db83597..6a17227 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: kexgexs.c,v 1.23 2015/01/20 23:14:00 deraadt Exp $ */
+/* $OpenBSD: kexgexs.c,v 1.24 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2000 Niels Provos.  All rights reserved.
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
@@ -155,8 +155,10 @@ input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt)
                r = SSH_ERR_INVALID_ARGUMENT;
                goto out;
        }
-       server_host_public = kex->load_host_public_key(kex->hostkey_type, ssh);
-       server_host_private = kex->load_host_private_key(kex->hostkey_type, ssh);
+       server_host_public = kex->load_host_public_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
+       server_host_private = kex->load_host_private_key(kex->hostkey_type,
+           kex->hostkey_nid, ssh);
        if (server_host_public == NULL) {
                r = SSH_ERR_NO_HOSTKEY_LOADED;
                goto out;
index 236e46c..68cc691 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh_api.c,v 1.1 2015/01/19 20:30:23 markus Exp $ */
+/* $OpenBSD: ssh_api.c,v 1.2 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Copyright (c) 2012 Markus Friedl.  All rights reserved.
  *
@@ -36,8 +36,8 @@ int   _ssh_send_banner(struct ssh *, char **);
 int    _ssh_read_banner(struct ssh *, char **);
 int    _ssh_order_hostkeyalgs(struct ssh *);
 int    _ssh_verify_host_key(struct sshkey *, struct ssh *);
-struct sshkey *_ssh_host_public_key(int, struct ssh *);
-struct sshkey *_ssh_host_private_key(int, struct ssh *);
+struct sshkey *_ssh_host_public_key(int, int, struct ssh *);
+struct sshkey *_ssh_host_private_key(int, int, struct ssh *);
 int    _ssh_host_key_sign(struct sshkey *, struct sshkey *, u_char **,
     size_t *, u_char *, size_t, u_int);
 
@@ -423,28 +423,30 @@ _ssh_exchange_banner(struct ssh *ssh)
 }
 
 struct sshkey *
-_ssh_host_public_key(int type, struct ssh *ssh)
+_ssh_host_public_key(int type, int nid, struct ssh *ssh)
 {
        struct key_entry *k;
 
        debug3("%s: need %d", __func__, type);
        TAILQ_FOREACH(k, &ssh->public_keys, next) {
                debug3("%s: check %s", __func__, sshkey_type(k->key));
-               if (k->key->type == type)
+               if (k->key->type == type &&
+                   (type != KEY_ECDSA || k->key->ecdsa_nid == nid))
                        return (k->key);
        }
        return (NULL);
 }
 
 struct sshkey *
-_ssh_host_private_key(int type, struct ssh *ssh)
+_ssh_host_private_key(int type, int nid, struct ssh *ssh)
 {
        struct key_entry *k;
 
        debug3("%s: need %d", __func__, type);
        TAILQ_FOREACH(k, &ssh->private_keys, next) {
                debug3("%s: check %s", __func__, sshkey_type(k->key));
-               if (k->key->type == type)
+               if (k->key->type == type &&
+                   (type != KEY_ECDSA || k->key->ecdsa_nid == nid))
                        return (k->key);
        }
        return (NULL);
index ab65e58..0b19421 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.257 2015/01/26 03:04:46 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.258 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1217,7 +1217,8 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
                goto out;
        }
 
-       debug("Server host key: %s %s", sshkey_type(host_key), fp);
+       debug("Server host key: %s %s",
+           compat20 ? sshkey_ssh_name(host_key) : sshkey_type(host_key), fp);
 
        if (sshkey_equal(previous_host_key, host_key)) {
                debug2("%s: server host key %s %s matches cached key",
index b7596e4..ae85797 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.439 2015/01/26 03:04:46 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.440 2015/01/26 06:10:03 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -799,7 +799,7 @@ list_hostkey_types(void)
 }
 
 static Key *
-get_hostkey_by_type(int type, int need_private, struct ssh *ssh)
+get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
 {
        int i;
        Key *key;
@@ -820,7 +820,8 @@ get_hostkey_by_type(int type, int need_private, struct ssh *ssh)
                                key = sensitive_data.host_pubkeys[i];
                        break;
                }
-               if (key != NULL && key->type == type)
+               if (key != NULL && key->type == type &&
+                   (key->type != KEY_ECDSA || key->ecdsa_nid == nid))
                        return need_private ?
                            sensitive_data.host_keys[i] : key;
        }
@@ -828,15 +829,15 @@ get_hostkey_by_type(int type, int need_private, struct ssh *ssh)
 }
 
 Key *
-get_hostkey_public_by_type(int type, struct ssh *ssh)
+get_hostkey_public_by_type(int type, int nid, struct ssh *ssh)
 {
-       return get_hostkey_by_type(type, 0, ssh);
+       return get_hostkey_by_type(type, nid, 0, ssh);
 }
 
 Key *
-get_hostkey_private_by_type(int type, struct ssh *ssh)
+get_hostkey_private_by_type(int type, int nid, struct ssh *ssh)
 {
-       return get_hostkey_by_type(type, 1, ssh);
+       return get_hostkey_by_type(type, nid, 1, ssh);
 }
 
 Key *