upstream: stricter UpdateHostkey signature verification logic on

the client- side. Require RSA/SHA2 signatures for RSA hostkeys except when
RSA/SHA1 was explicitly negotiated during initial KEX; bz3375

ok markus@

OpenBSD-Commit-ID: 46e75e8dfa2c813781805b842580dcfbd888cf29
This commit is contained in:
djm@openbsd.org 2022-01-06 21:57:28 +00:00 committed by Damien Miller
parent 0fa3368322
commit 291721bc7c

View File

@ -1,4 +1,4 @@
/* $OpenBSD: clientloop.c,v 1.374 2022/01/06 21:48:38 djm Exp $ */ /* $OpenBSD: clientloop.c,v 1.375 2022/01/06 21:57: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
@ -113,6 +113,9 @@
#include "ssherr.h" #include "ssherr.h"
#include "hostfile.h" #include "hostfile.h"
/* Permitted RSA signature algorithms for UpdateHostkeys proofs */
#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256"
/* import options */ /* import options */
extern Options options; extern Options options;
@ -2111,8 +2114,10 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx; struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i, ndone; size_t i, ndone;
struct sshbuf *signdata; struct sshbuf *signdata;
int r, kexsigtype, use_kexsigtype; int r, plaintype;
const u_char *sig; const u_char *sig;
const char *rsa_kexalg = NULL;
char *alg = NULL;
size_t siglen; size_t siglen;
if (ctx->nnew == 0) if (ctx->nnew == 0)
@ -2123,9 +2128,9 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
hostkeys_update_ctx_free(ctx); hostkeys_update_ctx_free(ctx);
return; return;
} }
kexsigtype = sshkey_type_plain( if (sshkey_type_plain(sshkey_type_from_name(
sshkey_type_from_name(ssh->kex->hostkey_alg)); ssh->kex->hostkey_alg)) == KEY_RSA)
rsa_kexalg = ssh->kex->hostkey_alg;
if ((signdata = sshbuf_new()) == NULL) if ((signdata = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed"); fatal_f("sshbuf_new failed");
/* /*
@ -2136,6 +2141,7 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
for (ndone = i = 0; i < ctx->nkeys; i++) { for (ndone = i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_match[i]) if (ctx->keys_match[i])
continue; continue;
plaintype = sshkey_type_plain(ctx->keys[i]->type);
/* Prepare data to be signed: session ID, unique string, key */ /* Prepare data to be signed: session ID, unique string, key */
sshbuf_reset(signdata); sshbuf_reset(signdata);
if ( (r = sshbuf_put_cstring(signdata, if ( (r = sshbuf_put_cstring(signdata,
@ -2149,19 +2155,33 @@ client_global_hostkeys_private_confirm(struct ssh *ssh, int type,
error_fr(r, "parse sig"); error_fr(r, "parse sig");
goto out; goto out;
} }
if ((r = sshkey_get_sigtype(sig, siglen, &alg)) != 0) {
error_fr(r, "server gave unintelligible signature "
"for %s key %zu", sshkey_type(ctx->keys[i]), i);
goto out;
}
/* /*
* For RSA keys, prefer to use the signature type negotiated * Special case for RSA keys: if a RSA hostkey was negotiated,
* during KEX to the default (SHA1). * then use its signature type for verification of RSA hostkey
* proofs. Otherwise, accept only RSA-SHA256/512 signatures.
*/ */
use_kexsigtype = kexsigtype == KEY_RSA && if (plaintype == KEY_RSA && rsa_kexalg == NULL &&
sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA; match_pattern_list(alg, HOSTKEY_PROOF_RSA_ALGS, 0) != 1) {
debug3_f("verify %s key %zu using %s sigalg", debug_f("server used untrusted RSA signature algorithm "
sshkey_type(ctx->keys[i]), i, "%s for key %zu, disregarding", alg, i);
use_kexsigtype ? ssh->kex->hostkey_alg : "default"); free(alg);
/* zap the key from the list */
sshkey_free(ctx->keys[i]);
ctx->keys[i] = NULL;
ndone++;
continue;
}
debug3_f("verify %s key %zu using sigalg %s",
sshkey_type(ctx->keys[i]), i, alg);
free(alg);
if ((r = sshkey_verify(ctx->keys[i], sig, siglen, if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
sshbuf_ptr(signdata), sshbuf_len(signdata), sshbuf_ptr(signdata), sshbuf_len(signdata),
use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, plaintype == KEY_RSA ? rsa_kexalg : NULL, 0, NULL)) != 0) {
NULL)) != 0) {
error_fr(r, "server gave bad signature for %s key %zu", error_fr(r, "server gave bad signature for %s key %zu",
sshkey_type(ctx->keys[i]), i); sshkey_type(ctx->keys[i]), i);
goto out; goto out;