xref: /netbsd-src/crypto/external/bsd/openssh/dist/kexgen.c (revision 9469f4f13c84743995b7d51c506f9c9849ba30de)
1*9469f4f1Schristos /*	$NetBSD: kexgen.c,v 1.8 2024/09/24 21:32:18 christos Exp $	*/
2*9469f4f1Schristos /* $OpenBSD: kexgen.c,v 1.10 2024/09/09 02:39:57 djm Exp $ */
3*9469f4f1Schristos 
47afc6c7eSchristos /*
57afc6c7eSchristos  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
67afc6c7eSchristos  *
77afc6c7eSchristos  * Redistribution and use in source and binary forms, with or without
87afc6c7eSchristos  * modification, are permitted provided that the following conditions
97afc6c7eSchristos  * are met:
107afc6c7eSchristos  * 1. Redistributions of source code must retain the above copyright
117afc6c7eSchristos  *    notice, this list of conditions and the following disclaimer.
127afc6c7eSchristos  * 2. Redistributions in binary form must reproduce the above copyright
137afc6c7eSchristos  *    notice, this list of conditions and the following disclaimer in the
147afc6c7eSchristos  *    documentation and/or other materials provided with the distribution.
157afc6c7eSchristos  *
167afc6c7eSchristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
177afc6c7eSchristos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
187afc6c7eSchristos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
197afc6c7eSchristos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
207afc6c7eSchristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
217afc6c7eSchristos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
227afc6c7eSchristos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
237afc6c7eSchristos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
247afc6c7eSchristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
257afc6c7eSchristos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
267afc6c7eSchristos  */
27aa36fcacSchristos #include "includes.h"
28aa36fcacSchristos __RCSID("$NetBSD");
297afc6c7eSchristos 
307afc6c7eSchristos #include <sys/types.h>
317afc6c7eSchristos 
327afc6c7eSchristos #include <stdio.h>
337afc6c7eSchristos #include <string.h>
347afc6c7eSchristos #include <signal.h>
357afc6c7eSchristos 
367afc6c7eSchristos #include "sshkey.h"
377afc6c7eSchristos #include "kex.h"
387afc6c7eSchristos #include "log.h"
397afc6c7eSchristos #include "packet.h"
407afc6c7eSchristos #include "ssh2.h"
417afc6c7eSchristos #include "sshbuf.h"
427afc6c7eSchristos #include "digest.h"
437afc6c7eSchristos #include "ssherr.h"
447afc6c7eSchristos 
457afc6c7eSchristos static int input_kex_gen_init(int, u_int32_t, struct ssh *);
467afc6c7eSchristos static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
477afc6c7eSchristos 
487afc6c7eSchristos static int
497afc6c7eSchristos kex_gen_hash(
507afc6c7eSchristos     int hash_alg,
517afc6c7eSchristos     const struct sshbuf *client_version,
527afc6c7eSchristos     const struct sshbuf *server_version,
537afc6c7eSchristos     const struct sshbuf *client_kexinit,
547afc6c7eSchristos     const struct sshbuf *server_kexinit,
557afc6c7eSchristos     const struct sshbuf *server_host_key_blob,
567afc6c7eSchristos     const struct sshbuf *client_pub,
577afc6c7eSchristos     const struct sshbuf *server_pub,
587afc6c7eSchristos     const struct sshbuf *shared_secret,
597afc6c7eSchristos     u_char *hash, size_t *hashlen)
607afc6c7eSchristos {
617afc6c7eSchristos 	struct sshbuf *b;
627afc6c7eSchristos 	int r;
637afc6c7eSchristos 
647afc6c7eSchristos 	if (*hashlen < ssh_digest_bytes(hash_alg))
657afc6c7eSchristos 		return SSH_ERR_INVALID_ARGUMENT;
667afc6c7eSchristos 	if ((b = sshbuf_new()) == NULL)
677afc6c7eSchristos 		return SSH_ERR_ALLOC_FAIL;
687afc6c7eSchristos 	if ((r = sshbuf_put_stringb(b, client_version)) != 0 ||
697afc6c7eSchristos 	    (r = sshbuf_put_stringb(b, server_version)) != 0 ||
707afc6c7eSchristos 	    /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
717afc6c7eSchristos 	    (r = sshbuf_put_u32(b, sshbuf_len(client_kexinit) + 1)) != 0 ||
727afc6c7eSchristos 	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
737afc6c7eSchristos 	    (r = sshbuf_putb(b, client_kexinit)) != 0 ||
747afc6c7eSchristos 	    (r = sshbuf_put_u32(b, sshbuf_len(server_kexinit) + 1)) != 0 ||
757afc6c7eSchristos 	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
767afc6c7eSchristos 	    (r = sshbuf_putb(b, server_kexinit)) != 0 ||
777afc6c7eSchristos 	    (r = sshbuf_put_stringb(b, server_host_key_blob)) != 0 ||
787afc6c7eSchristos 	    (r = sshbuf_put_stringb(b, client_pub)) != 0 ||
797afc6c7eSchristos 	    (r = sshbuf_put_stringb(b, server_pub)) != 0 ||
807afc6c7eSchristos 	    (r = sshbuf_putb(b, shared_secret)) != 0) {
817afc6c7eSchristos 		sshbuf_free(b);
827afc6c7eSchristos 		return r;
837afc6c7eSchristos 	}
847afc6c7eSchristos #ifdef DEBUG_KEX
857afc6c7eSchristos 	sshbuf_dump(b, stderr);
867afc6c7eSchristos #endif
877afc6c7eSchristos 	if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
887afc6c7eSchristos 		sshbuf_free(b);
897afc6c7eSchristos 		return SSH_ERR_LIBCRYPTO_ERROR;
907afc6c7eSchristos 	}
917afc6c7eSchristos 	sshbuf_free(b);
927afc6c7eSchristos 	*hashlen = ssh_digest_bytes(hash_alg);
937afc6c7eSchristos #ifdef DEBUG_KEX
947afc6c7eSchristos 	dump_digest("hash", hash, *hashlen);
957afc6c7eSchristos #endif
967afc6c7eSchristos 	return 0;
977afc6c7eSchristos }
987afc6c7eSchristos 
997afc6c7eSchristos int
1007afc6c7eSchristos kex_gen_client(struct ssh *ssh)
1017afc6c7eSchristos {
1027afc6c7eSchristos 	struct kex *kex = ssh->kex;
1037afc6c7eSchristos 	int r;
1047afc6c7eSchristos 
1057afc6c7eSchristos 	switch (kex->kex_type) {
106cd4ada6aSchristos #ifdef WITH_OPENSSL
1077afc6c7eSchristos 	case KEX_DH_GRP1_SHA1:
1087afc6c7eSchristos 	case KEX_DH_GRP14_SHA1:
1097afc6c7eSchristos 	case KEX_DH_GRP14_SHA256:
1107afc6c7eSchristos 	case KEX_DH_GRP16_SHA512:
1117afc6c7eSchristos 	case KEX_DH_GRP18_SHA512:
1127afc6c7eSchristos 		r = kex_dh_keypair(kex);
1137afc6c7eSchristos 		break;
1147afc6c7eSchristos 	case KEX_ECDH_SHA2:
1157afc6c7eSchristos 		r = kex_ecdh_keypair(kex);
1167afc6c7eSchristos 		break;
117cd4ada6aSchristos #endif /* WITH_OPENSSL */
1187afc6c7eSchristos 	case KEX_C25519_SHA256:
1197afc6c7eSchristos 		r = kex_c25519_keypair(kex);
1207afc6c7eSchristos 		break;
12117418e98Schristos 	case KEX_KEM_SNTRUP761X25519_SHA512:
12217418e98Schristos 		r = kex_kem_sntrup761x25519_keypair(kex);
1237afc6c7eSchristos 		break;
124*9469f4f1Schristos 	case KEX_KEM_MLKEM768X25519_SHA256:
125*9469f4f1Schristos 		r = kex_kem_mlkem768x25519_keypair(kex);
126*9469f4f1Schristos 		break;
1277afc6c7eSchristos 	default:
1287afc6c7eSchristos 		r = SSH_ERR_INVALID_ARGUMENT;
1297afc6c7eSchristos 		break;
1307afc6c7eSchristos 	}
1317afc6c7eSchristos 	if (r != 0)
1327afc6c7eSchristos 		return r;
1337afc6c7eSchristos 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
1347afc6c7eSchristos 	    (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 ||
1357afc6c7eSchristos 	    (r = sshpkt_send(ssh)) != 0)
1367afc6c7eSchristos 		return r;
1377afc6c7eSchristos 	debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
1387afc6c7eSchristos 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply);
1397afc6c7eSchristos 	return 0;
1407afc6c7eSchristos }
1417afc6c7eSchristos 
1427afc6c7eSchristos static int
1437afc6c7eSchristos input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
1447afc6c7eSchristos {
1457afc6c7eSchristos 	struct kex *kex = ssh->kex;
1467afc6c7eSchristos 	struct sshkey *server_host_key = NULL;
1477afc6c7eSchristos 	struct sshbuf *shared_secret = NULL;
1487afc6c7eSchristos 	struct sshbuf *server_blob = NULL;
1497afc6c7eSchristos 	struct sshbuf *tmp = NULL, *server_host_key_blob = NULL;
1507afc6c7eSchristos 	u_char *signature = NULL;
1517afc6c7eSchristos 	u_char hash[SSH_DIGEST_MAX_LENGTH];
1527afc6c7eSchristos 	size_t slen, hashlen;
1537afc6c7eSchristos 	int r;
1547afc6c7eSchristos 
15517418e98Schristos 	debug("SSH2_MSG_KEX_ECDH_REPLY received");
15617418e98Schristos 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error);
15717418e98Schristos 
1587afc6c7eSchristos 	/* hostkey */
1597afc6c7eSchristos 	if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
1607afc6c7eSchristos 		goto out;
1617afc6c7eSchristos 	/* sshkey_fromb() consumes its buffer, so make a copy */
1627afc6c7eSchristos 	if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
1637afc6c7eSchristos 		r = SSH_ERR_ALLOC_FAIL;
1647afc6c7eSchristos 		goto out;
1657afc6c7eSchristos 	}
1667afc6c7eSchristos 	if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
1677afc6c7eSchristos 		goto out;
1687afc6c7eSchristos 	if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
1697afc6c7eSchristos 		goto out;
1707afc6c7eSchristos 
1717afc6c7eSchristos 	/* Q_S, server public key */
1727afc6c7eSchristos 	/* signed H */
1737afc6c7eSchristos 	if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
1747afc6c7eSchristos 	    (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
1757afc6c7eSchristos 	    (r = sshpkt_get_end(ssh)) != 0)
1767afc6c7eSchristos 		goto out;
1777afc6c7eSchristos 
1787afc6c7eSchristos 	/* compute shared secret */
1797afc6c7eSchristos 	switch (kex->kex_type) {
180cd4ada6aSchristos #ifdef WITH_OPENSSL
1817afc6c7eSchristos 	case KEX_DH_GRP1_SHA1:
1827afc6c7eSchristos 	case KEX_DH_GRP14_SHA1:
1837afc6c7eSchristos 	case KEX_DH_GRP14_SHA256:
1847afc6c7eSchristos 	case KEX_DH_GRP16_SHA512:
1857afc6c7eSchristos 	case KEX_DH_GRP18_SHA512:
1867afc6c7eSchristos 		r = kex_dh_dec(kex, server_blob, &shared_secret);
1877afc6c7eSchristos 		break;
1887afc6c7eSchristos 	case KEX_ECDH_SHA2:
1897afc6c7eSchristos 		r = kex_ecdh_dec(kex, server_blob, &shared_secret);
1907afc6c7eSchristos 		break;
191cd4ada6aSchristos #endif /* WITH_OPENSSL */
1927afc6c7eSchristos 	case KEX_C25519_SHA256:
1937afc6c7eSchristos 		r = kex_c25519_dec(kex, server_blob, &shared_secret);
1947afc6c7eSchristos 		break;
19517418e98Schristos 	case KEX_KEM_SNTRUP761X25519_SHA512:
19617418e98Schristos 		r = kex_kem_sntrup761x25519_dec(kex, server_blob,
1977afc6c7eSchristos 		    &shared_secret);
1987afc6c7eSchristos 		break;
199*9469f4f1Schristos 	case KEX_KEM_MLKEM768X25519_SHA256:
200*9469f4f1Schristos 		r = kex_kem_mlkem768x25519_dec(kex, server_blob,
201*9469f4f1Schristos 		    &shared_secret);
202*9469f4f1Schristos 		break;
2037afc6c7eSchristos 	default:
2047afc6c7eSchristos 		r = SSH_ERR_INVALID_ARGUMENT;
2057afc6c7eSchristos 		break;
2067afc6c7eSchristos 	}
2077afc6c7eSchristos 	if (r !=0 )
2087afc6c7eSchristos 		goto out;
2097afc6c7eSchristos 
2107afc6c7eSchristos 	/* calc and verify H */
2117afc6c7eSchristos 	hashlen = sizeof(hash);
2127afc6c7eSchristos 	if ((r = kex_gen_hash(
2137afc6c7eSchristos 	    kex->hash_alg,
2147afc6c7eSchristos 	    kex->client_version,
2157afc6c7eSchristos 	    kex->server_version,
2167afc6c7eSchristos 	    kex->my,
2177afc6c7eSchristos 	    kex->peer,
2187afc6c7eSchristos 	    server_host_key_blob,
2197afc6c7eSchristos 	    kex->client_pub,
2207afc6c7eSchristos 	    server_blob,
2217afc6c7eSchristos 	    shared_secret,
2227afc6c7eSchristos 	    hash, &hashlen)) != 0)
2237afc6c7eSchristos 		goto out;
2247afc6c7eSchristos 
2257afc6c7eSchristos 	if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
226ed75d7a8Schristos 	    kex->hostkey_alg, ssh->compat, NULL)) != 0)
2277afc6c7eSchristos 		goto out;
2287afc6c7eSchristos 
229a03ec00cSchristos 	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
230a03ec00cSchristos 	    (r = kex_send_newkeys(ssh)) != 0)
231a03ec00cSchristos 		goto out;
232a03ec00cSchristos 
233a03ec00cSchristos 	/* save initial signature and hostkey */
234a03ec00cSchristos 	if ((kex->flags & KEX_INITIAL) != 0) {
235a03ec00cSchristos 		if (kex->initial_hostkey != NULL || kex->initial_sig != NULL) {
236a03ec00cSchristos 			r = SSH_ERR_INTERNAL_ERROR;
237a03ec00cSchristos 			goto out;
238a03ec00cSchristos 		}
239a03ec00cSchristos 		if ((kex->initial_sig = sshbuf_new()) == NULL) {
240a03ec00cSchristos 			r = SSH_ERR_ALLOC_FAIL;
241a03ec00cSchristos 			goto out;
242a03ec00cSchristos 		}
243a03ec00cSchristos 		if ((r = sshbuf_put(kex->initial_sig, signature, slen)) != 0)
244a03ec00cSchristos 			goto out;
245a03ec00cSchristos 		kex->initial_hostkey = server_host_key;
246a03ec00cSchristos 		server_host_key = NULL;
247a03ec00cSchristos 	}
248a03ec00cSchristos 	/* success */
2497afc6c7eSchristos out:
2507afc6c7eSchristos 	explicit_bzero(hash, sizeof(hash));
2517afc6c7eSchristos 	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
25217418e98Schristos 	explicit_bzero(kex->sntrup761_client_key,
25317418e98Schristos 	    sizeof(kex->sntrup761_client_key));
254*9469f4f1Schristos 	explicit_bzero(kex->mlkem768_client_key,
255*9469f4f1Schristos 	    sizeof(kex->mlkem768_client_key));
2567afc6c7eSchristos 	sshbuf_free(server_host_key_blob);
2577afc6c7eSchristos 	free(signature);
2587afc6c7eSchristos 	sshbuf_free(tmp);
2597afc6c7eSchristos 	sshkey_free(server_host_key);
2607afc6c7eSchristos 	sshbuf_free(server_blob);
2617afc6c7eSchristos 	sshbuf_free(shared_secret);
2627afc6c7eSchristos 	sshbuf_free(kex->client_pub);
2637afc6c7eSchristos 	kex->client_pub = NULL;
2647afc6c7eSchristos 	return r;
2657afc6c7eSchristos }
2667afc6c7eSchristos 
2677afc6c7eSchristos int
2687afc6c7eSchristos kex_gen_server(struct ssh *ssh)
2697afc6c7eSchristos {
2707afc6c7eSchristos 	debug("expecting SSH2_MSG_KEX_ECDH_INIT");
2717afc6c7eSchristos 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
2727afc6c7eSchristos 	return 0;
2737afc6c7eSchristos }
2747afc6c7eSchristos 
2757afc6c7eSchristos static int
2767afc6c7eSchristos input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
2777afc6c7eSchristos {
2787afc6c7eSchristos 	struct kex *kex = ssh->kex;
2797afc6c7eSchristos 	struct sshkey *server_host_private, *server_host_public;
2807afc6c7eSchristos 	struct sshbuf *shared_secret = NULL;
2817afc6c7eSchristos 	struct sshbuf *server_pubkey = NULL;
2827afc6c7eSchristos 	struct sshbuf *client_pubkey = NULL;
2837afc6c7eSchristos 	struct sshbuf *server_host_key_blob = NULL;
2847afc6c7eSchristos 	u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
2857afc6c7eSchristos 	size_t slen, hashlen;
2867afc6c7eSchristos 	int r;
2877afc6c7eSchristos 
28817418e98Schristos 	debug("SSH2_MSG_KEX_ECDH_INIT received");
28917418e98Schristos 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
29017418e98Schristos 
2917afc6c7eSchristos 	if ((r = kex_load_hostkey(ssh, &server_host_private,
2927afc6c7eSchristos 	    &server_host_public)) != 0)
2937afc6c7eSchristos 		goto out;
2947afc6c7eSchristos 
2957afc6c7eSchristos 	if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
2967afc6c7eSchristos 	    (r = sshpkt_get_end(ssh)) != 0)
2977afc6c7eSchristos 		goto out;
2987afc6c7eSchristos 
2997afc6c7eSchristos 	/* compute shared secret */
3007afc6c7eSchristos 	switch (kex->kex_type) {
301cd4ada6aSchristos #ifdef WITH_OPENSSL
3027afc6c7eSchristos 	case KEX_DH_GRP1_SHA1:
3037afc6c7eSchristos 	case KEX_DH_GRP14_SHA1:
3047afc6c7eSchristos 	case KEX_DH_GRP14_SHA256:
3057afc6c7eSchristos 	case KEX_DH_GRP16_SHA512:
3067afc6c7eSchristos 	case KEX_DH_GRP18_SHA512:
3077afc6c7eSchristos 		r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
3087afc6c7eSchristos 		    &shared_secret);
3097afc6c7eSchristos 		break;
3107afc6c7eSchristos 	case KEX_ECDH_SHA2:
3117afc6c7eSchristos 		r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
3127afc6c7eSchristos 		    &shared_secret);
3137afc6c7eSchristos 		break;
314cd4ada6aSchristos #endif /* WITH_OPENSSL */
3157afc6c7eSchristos 	case KEX_C25519_SHA256:
3167afc6c7eSchristos 		r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
3177afc6c7eSchristos 		    &shared_secret);
3187afc6c7eSchristos 		break;
31917418e98Schristos 	case KEX_KEM_SNTRUP761X25519_SHA512:
32017418e98Schristos 		r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
3217afc6c7eSchristos 		    &server_pubkey, &shared_secret);
3227afc6c7eSchristos 		break;
323*9469f4f1Schristos 	case KEX_KEM_MLKEM768X25519_SHA256:
324*9469f4f1Schristos 		r = kex_kem_mlkem768x25519_enc(kex, client_pubkey,
325*9469f4f1Schristos 		    &server_pubkey, &shared_secret);
326*9469f4f1Schristos 		break;
3277afc6c7eSchristos 	default:
3287afc6c7eSchristos 		r = SSH_ERR_INVALID_ARGUMENT;
3297afc6c7eSchristos 		break;
3307afc6c7eSchristos 	}
3317afc6c7eSchristos 	if (r !=0 )
3327afc6c7eSchristos 		goto out;
3337afc6c7eSchristos 
3347afc6c7eSchristos 	/* calc H */
3357afc6c7eSchristos 	if ((server_host_key_blob = sshbuf_new()) == NULL) {
3367afc6c7eSchristos 		r = SSH_ERR_ALLOC_FAIL;
3377afc6c7eSchristos 		goto out;
3387afc6c7eSchristos 	}
3397afc6c7eSchristos 	if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
3407afc6c7eSchristos 		goto out;
3417afc6c7eSchristos 	hashlen = sizeof(hash);
3427afc6c7eSchristos 	if ((r = kex_gen_hash(
3437afc6c7eSchristos 	    kex->hash_alg,
3447afc6c7eSchristos 	    kex->client_version,
3457afc6c7eSchristos 	    kex->server_version,
3467afc6c7eSchristos 	    kex->peer,
3477afc6c7eSchristos 	    kex->my,
3487afc6c7eSchristos 	    server_host_key_blob,
3497afc6c7eSchristos 	    client_pubkey,
3507afc6c7eSchristos 	    server_pubkey,
3517afc6c7eSchristos 	    shared_secret,
3527afc6c7eSchristos 	    hash, &hashlen)) != 0)
3537afc6c7eSchristos 		goto out;
3547afc6c7eSchristos 
3557afc6c7eSchristos 	/* sign H */
3567afc6c7eSchristos 	if ((r = kex->sign(ssh, server_host_private, server_host_public,
3577afc6c7eSchristos 	    &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
3587afc6c7eSchristos 		goto out;
3597afc6c7eSchristos 
3607afc6c7eSchristos 	/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
3617afc6c7eSchristos 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
3627afc6c7eSchristos 	    (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
3637afc6c7eSchristos 	    (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
3647afc6c7eSchristos 	    (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
3657afc6c7eSchristos 	    (r = sshpkt_send(ssh)) != 0)
3667afc6c7eSchristos 		goto out;
3677afc6c7eSchristos 
368a03ec00cSchristos 	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
369a03ec00cSchristos 	    (r = kex_send_newkeys(ssh)) != 0)
370a03ec00cSchristos 		goto out;
371a03ec00cSchristos 	/* retain copy of hostkey used at initial KEX */
372a03ec00cSchristos 	if (kex->initial_hostkey == NULL &&
373a03ec00cSchristos 	    (r = sshkey_from_private(server_host_public,
374a03ec00cSchristos 	    &kex->initial_hostkey)) != 0)
375a03ec00cSchristos 		goto out;
376a03ec00cSchristos 	/* success */
3777afc6c7eSchristos out:
3787afc6c7eSchristos 	explicit_bzero(hash, sizeof(hash));
3797afc6c7eSchristos 	sshbuf_free(server_host_key_blob);
3807afc6c7eSchristos 	free(signature);
3817afc6c7eSchristos 	sshbuf_free(shared_secret);
3827afc6c7eSchristos 	sshbuf_free(client_pubkey);
3837afc6c7eSchristos 	sshbuf_free(server_pubkey);
3847afc6c7eSchristos 	return r;
3857afc6c7eSchristos }
386