unbreak hostkey rotation; attempting to sign with a desired signature
authordjm <djm@openbsd.org>
Mon, 18 Dec 2017 23:16:23 +0000 (23:16 +0000)
committerdjm <djm@openbsd.org>
Mon, 18 Dec 2017 23:16:23 +0000 (23:16 +0000)
algorithm of kex->hostkey_alg is incorrect when the key type isn't
capable of making those signatures. ok markus@

usr.bin/ssh/clientloop.c
usr.bin/ssh/serverloop.c

index c7b9ff2..a4c0560 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.308 2017/12/18 02:25:15 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.309 2017/12/18 23:16:23 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1878,7 +1878,7 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
        struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
        size_t i, ndone;
        struct sshbuf *signdata;
-       int r;
+       int r, kexsigtype, use_kexsigtype;
        const u_char *sig;
        size_t siglen;
 
@@ -1890,6 +1890,9 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
                hostkeys_update_ctx_free(ctx);
                return;
        }
+       kexsigtype = sshkey_type_plain(
+           sshkey_type_from_name(ssh->kex->hostkey_alg));
+
        if ((signdata = sshbuf_new()) == NULL)
                fatal("%s: sshbuf_new failed", __func__);
        /* Don't want to accidentally accept an unbound signature */
@@ -1918,9 +1921,15 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
                            __func__, ssh_err(r));
                        goto out;
                }
+               /*
+                * For RSA keys, prefer to use the signature type negotiated
+                * during KEX to the default (SHA1).
+                */
+               use_kexsigtype = kexsigtype == KEY_RSA &&
+                   sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA;
                if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
                    sshbuf_ptr(signdata), sshbuf_len(signdata),
-                   ssh->kex->hostkey_alg, 0)) != 0) {
+                   use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0)) != 0) {
                        error("%s: server gave bad signature for %s key %zu",
                            __func__, sshkey_type(ctx->keys[i]), i);
                        goto out;
index 853c0fc..887ffae 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.201 2017/12/18 02:25:15 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.202 2017/12/18 23:16:24 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -660,7 +660,7 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
        struct sshbuf *resp = NULL;
        struct sshbuf *sigbuf = NULL;
        struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL;
-       int r, ndx, success = 0;
+       int r, ndx, kexsigtype, use_kexsigtype, success = 0;
        const u_char *blob;
        u_char *sig = 0;
        size_t blen, slen;
@@ -668,6 +668,8 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
        if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL)
                fatal("%s: sshbuf_new", __func__);
 
+       kexsigtype = sshkey_type_plain(
+           sshkey_type_from_name(ssh->kex->hostkey_alg));
        while (ssh_packet_remaining(ssh) > 0) {
                sshkey_free(key);
                key = NULL;
@@ -698,6 +700,12 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
                sshbuf_reset(sigbuf);
                free(sig);
                sig = NULL;
+               /*
+                * For RSA keys, prefer to use the signature type negotiated
+                * during KEX to the default (SHA1).
+                */
+               use_kexsigtype = kexsigtype == KEY_RSA &&
+                   sshkey_type_plain(key->type) == KEY_RSA;
                if ((r = sshbuf_put_cstring(sigbuf,
                    "hostkeys-prove-00@openssh.com")) != 0 ||
                    (r = sshbuf_put_string(sigbuf,
@@ -705,7 +713,7 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp)
                    (r = sshkey_puts(key, sigbuf)) != 0 ||
                    (r = ssh->kex->sign(key_prv, key_pub, &sig, &slen,
                    sshbuf_ptr(sigbuf), sshbuf_len(sigbuf),
-                   ssh->kex->hostkey_alg, 0)) != 0 ||
+                   use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0)) != 0 ||
                    (r = sshbuf_put_string(resp, sig, slen)) != 0) {
                        error("%s: couldn't prepare signature: %s",
                            __func__, ssh_err(r));