xref: /freebsd/crypto/openssh/kexgen.c (revision 3d9fd9fcb432750f3716b28f6ccb0104cd9d351a)
1*3d9fd9fcSEd Maste /* $OpenBSD: kexgen.c,v 1.10 2024/09/09 02:39:57 djm Exp $ */
219261079SEd Maste /*
319261079SEd Maste  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
419261079SEd Maste  *
519261079SEd Maste  * Redistribution and use in source and binary forms, with or without
619261079SEd Maste  * modification, are permitted provided that the following conditions
719261079SEd Maste  * are met:
819261079SEd Maste  * 1. Redistributions of source code must retain the above copyright
919261079SEd Maste  *    notice, this list of conditions and the following disclaimer.
1019261079SEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
1119261079SEd Maste  *    notice, this list of conditions and the following disclaimer in the
1219261079SEd Maste  *    documentation and/or other materials provided with the distribution.
1319261079SEd Maste  *
1419261079SEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1519261079SEd Maste  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1619261079SEd Maste  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1719261079SEd Maste  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1819261079SEd Maste  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1919261079SEd Maste  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2019261079SEd Maste  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2119261079SEd Maste  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2219261079SEd Maste  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2319261079SEd Maste  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2419261079SEd Maste  */
2519261079SEd Maste 
2619261079SEd Maste #include "includes.h"
2719261079SEd Maste 
2819261079SEd Maste #include <sys/types.h>
2919261079SEd Maste 
3019261079SEd Maste #include <stdarg.h>
3119261079SEd Maste #include <stdio.h>
3219261079SEd Maste #include <string.h>
3319261079SEd Maste #include <signal.h>
3419261079SEd Maste 
3519261079SEd Maste #include "sshkey.h"
3619261079SEd Maste #include "kex.h"
3719261079SEd Maste #include "log.h"
3819261079SEd Maste #include "packet.h"
3919261079SEd Maste #include "ssh2.h"
4019261079SEd Maste #include "sshbuf.h"
4119261079SEd Maste #include "digest.h"
4219261079SEd Maste #include "ssherr.h"
4319261079SEd Maste 
4419261079SEd Maste static int input_kex_gen_init(int, u_int32_t, struct ssh *);
4519261079SEd Maste static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
4619261079SEd Maste 
4719261079SEd Maste static int
kex_gen_hash(int hash_alg,const struct sshbuf * client_version,const struct sshbuf * server_version,const struct sshbuf * client_kexinit,const struct sshbuf * server_kexinit,const struct sshbuf * server_host_key_blob,const struct sshbuf * client_pub,const struct sshbuf * server_pub,const struct sshbuf * shared_secret,u_char * hash,size_t * hashlen)4819261079SEd Maste kex_gen_hash(
4919261079SEd Maste     int hash_alg,
5019261079SEd Maste     const struct sshbuf *client_version,
5119261079SEd Maste     const struct sshbuf *server_version,
5219261079SEd Maste     const struct sshbuf *client_kexinit,
5319261079SEd Maste     const struct sshbuf *server_kexinit,
5419261079SEd Maste     const struct sshbuf *server_host_key_blob,
5519261079SEd Maste     const struct sshbuf *client_pub,
5619261079SEd Maste     const struct sshbuf *server_pub,
5719261079SEd Maste     const struct sshbuf *shared_secret,
5819261079SEd Maste     u_char *hash, size_t *hashlen)
5919261079SEd Maste {
6019261079SEd Maste 	struct sshbuf *b;
6119261079SEd Maste 	int r;
6219261079SEd Maste 
6319261079SEd Maste 	if (*hashlen < ssh_digest_bytes(hash_alg))
6419261079SEd Maste 		return SSH_ERR_INVALID_ARGUMENT;
6519261079SEd Maste 	if ((b = sshbuf_new()) == NULL)
6619261079SEd Maste 		return SSH_ERR_ALLOC_FAIL;
6719261079SEd Maste 	if ((r = sshbuf_put_stringb(b, client_version)) != 0 ||
6819261079SEd Maste 	    (r = sshbuf_put_stringb(b, server_version)) != 0 ||
6919261079SEd Maste 	    /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
7019261079SEd Maste 	    (r = sshbuf_put_u32(b, sshbuf_len(client_kexinit) + 1)) != 0 ||
7119261079SEd Maste 	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
7219261079SEd Maste 	    (r = sshbuf_putb(b, client_kexinit)) != 0 ||
7319261079SEd Maste 	    (r = sshbuf_put_u32(b, sshbuf_len(server_kexinit) + 1)) != 0 ||
7419261079SEd Maste 	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
7519261079SEd Maste 	    (r = sshbuf_putb(b, server_kexinit)) != 0 ||
7619261079SEd Maste 	    (r = sshbuf_put_stringb(b, server_host_key_blob)) != 0 ||
7719261079SEd Maste 	    (r = sshbuf_put_stringb(b, client_pub)) != 0 ||
7819261079SEd Maste 	    (r = sshbuf_put_stringb(b, server_pub)) != 0 ||
7919261079SEd Maste 	    (r = sshbuf_putb(b, shared_secret)) != 0) {
8019261079SEd Maste 		sshbuf_free(b);
8119261079SEd Maste 		return r;
8219261079SEd Maste 	}
8319261079SEd Maste #ifdef DEBUG_KEX
8419261079SEd Maste 	sshbuf_dump(b, stderr);
8519261079SEd Maste #endif
8619261079SEd Maste 	if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
8719261079SEd Maste 		sshbuf_free(b);
8819261079SEd Maste 		return SSH_ERR_LIBCRYPTO_ERROR;
8919261079SEd Maste 	}
9019261079SEd Maste 	sshbuf_free(b);
9119261079SEd Maste 	*hashlen = ssh_digest_bytes(hash_alg);
9219261079SEd Maste #ifdef DEBUG_KEX
9319261079SEd Maste 	dump_digest("hash", hash, *hashlen);
9419261079SEd Maste #endif
9519261079SEd Maste 	return 0;
9619261079SEd Maste }
9719261079SEd Maste 
9819261079SEd Maste int
kex_gen_client(struct ssh * ssh)9919261079SEd Maste kex_gen_client(struct ssh *ssh)
10019261079SEd Maste {
10119261079SEd Maste 	struct kex *kex = ssh->kex;
10219261079SEd Maste 	int r;
10319261079SEd Maste 
10419261079SEd Maste 	switch (kex->kex_type) {
10519261079SEd Maste #ifdef WITH_OPENSSL
10619261079SEd Maste 	case KEX_DH_GRP1_SHA1:
10719261079SEd Maste 	case KEX_DH_GRP14_SHA1:
10819261079SEd Maste 	case KEX_DH_GRP14_SHA256:
10919261079SEd Maste 	case KEX_DH_GRP16_SHA512:
11019261079SEd Maste 	case KEX_DH_GRP18_SHA512:
11119261079SEd Maste 		r = kex_dh_keypair(kex);
11219261079SEd Maste 		break;
11319261079SEd Maste 	case KEX_ECDH_SHA2:
11419261079SEd Maste 		r = kex_ecdh_keypair(kex);
11519261079SEd Maste 		break;
11619261079SEd Maste #endif
11719261079SEd Maste 	case KEX_C25519_SHA256:
11819261079SEd Maste 		r = kex_c25519_keypair(kex);
11919261079SEd Maste 		break;
12019261079SEd Maste 	case KEX_KEM_SNTRUP761X25519_SHA512:
12119261079SEd Maste 		r = kex_kem_sntrup761x25519_keypair(kex);
12219261079SEd Maste 		break;
123*3d9fd9fcSEd Maste 	case KEX_KEM_MLKEM768X25519_SHA256:
124*3d9fd9fcSEd Maste 		r = kex_kem_mlkem768x25519_keypair(kex);
125*3d9fd9fcSEd Maste 		break;
12619261079SEd Maste 	default:
12719261079SEd Maste 		r = SSH_ERR_INVALID_ARGUMENT;
12819261079SEd Maste 		break;
12919261079SEd Maste 	}
13019261079SEd Maste 	if (r != 0)
13119261079SEd Maste 		return r;
13219261079SEd Maste 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
13319261079SEd Maste 	    (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 ||
13419261079SEd Maste 	    (r = sshpkt_send(ssh)) != 0)
13519261079SEd Maste 		return r;
13619261079SEd Maste 	debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
13719261079SEd Maste 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply);
13819261079SEd Maste 	return 0;
13919261079SEd Maste }
14019261079SEd Maste 
14119261079SEd Maste static int
input_kex_gen_reply(int type,u_int32_t seq,struct ssh * ssh)14219261079SEd Maste input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
14319261079SEd Maste {
14419261079SEd Maste 	struct kex *kex = ssh->kex;
14519261079SEd Maste 	struct sshkey *server_host_key = NULL;
14619261079SEd Maste 	struct sshbuf *shared_secret = NULL;
14719261079SEd Maste 	struct sshbuf *server_blob = NULL;
14819261079SEd Maste 	struct sshbuf *tmp = NULL, *server_host_key_blob = NULL;
14919261079SEd Maste 	u_char *signature = NULL;
15019261079SEd Maste 	u_char hash[SSH_DIGEST_MAX_LENGTH];
15119261079SEd Maste 	size_t slen, hashlen;
15219261079SEd Maste 	int r;
15319261079SEd Maste 
15419261079SEd Maste 	debug("SSH2_MSG_KEX_ECDH_REPLY received");
15519261079SEd Maste 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error);
15619261079SEd Maste 
15719261079SEd Maste 	/* hostkey */
15819261079SEd Maste 	if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
15919261079SEd Maste 		goto out;
16019261079SEd Maste 	/* sshkey_fromb() consumes its buffer, so make a copy */
16119261079SEd Maste 	if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
16219261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
16319261079SEd Maste 		goto out;
16419261079SEd Maste 	}
16519261079SEd Maste 	if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
16619261079SEd Maste 		goto out;
16719261079SEd Maste 	if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
16819261079SEd Maste 		goto out;
16919261079SEd Maste 
17019261079SEd Maste 	/* Q_S, server public key */
17119261079SEd Maste 	/* signed H */
17219261079SEd Maste 	if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
17319261079SEd Maste 	    (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
17419261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
17519261079SEd Maste 		goto out;
17619261079SEd Maste 
17719261079SEd Maste 	/* compute shared secret */
17819261079SEd Maste 	switch (kex->kex_type) {
17919261079SEd Maste #ifdef WITH_OPENSSL
18019261079SEd Maste 	case KEX_DH_GRP1_SHA1:
18119261079SEd Maste 	case KEX_DH_GRP14_SHA1:
18219261079SEd Maste 	case KEX_DH_GRP14_SHA256:
18319261079SEd Maste 	case KEX_DH_GRP16_SHA512:
18419261079SEd Maste 	case KEX_DH_GRP18_SHA512:
18519261079SEd Maste 		r = kex_dh_dec(kex, server_blob, &shared_secret);
18619261079SEd Maste 		break;
18719261079SEd Maste 	case KEX_ECDH_SHA2:
18819261079SEd Maste 		r = kex_ecdh_dec(kex, server_blob, &shared_secret);
18919261079SEd Maste 		break;
19019261079SEd Maste #endif
19119261079SEd Maste 	case KEX_C25519_SHA256:
19219261079SEd Maste 		r = kex_c25519_dec(kex, server_blob, &shared_secret);
19319261079SEd Maste 		break;
19419261079SEd Maste 	case KEX_KEM_SNTRUP761X25519_SHA512:
19519261079SEd Maste 		r = kex_kem_sntrup761x25519_dec(kex, server_blob,
19619261079SEd Maste 		    &shared_secret);
19719261079SEd Maste 		break;
198*3d9fd9fcSEd Maste 	case KEX_KEM_MLKEM768X25519_SHA256:
199*3d9fd9fcSEd Maste 		r = kex_kem_mlkem768x25519_dec(kex, server_blob,
200*3d9fd9fcSEd Maste 		    &shared_secret);
201*3d9fd9fcSEd Maste 		break;
20219261079SEd Maste 	default:
20319261079SEd Maste 		r = SSH_ERR_INVALID_ARGUMENT;
20419261079SEd Maste 		break;
20519261079SEd Maste 	}
20619261079SEd Maste 	if (r !=0 )
20719261079SEd Maste 		goto out;
20819261079SEd Maste 
20919261079SEd Maste 	/* calc and verify H */
21019261079SEd Maste 	hashlen = sizeof(hash);
21119261079SEd Maste 	if ((r = kex_gen_hash(
21219261079SEd Maste 	    kex->hash_alg,
21319261079SEd Maste 	    kex->client_version,
21419261079SEd Maste 	    kex->server_version,
21519261079SEd Maste 	    kex->my,
21619261079SEd Maste 	    kex->peer,
21719261079SEd Maste 	    server_host_key_blob,
21819261079SEd Maste 	    kex->client_pub,
21919261079SEd Maste 	    server_blob,
22019261079SEd Maste 	    shared_secret,
22119261079SEd Maste 	    hash, &hashlen)) != 0)
22219261079SEd Maste 		goto out;
22319261079SEd Maste 
22419261079SEd Maste 	if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
22519261079SEd Maste 	    kex->hostkey_alg, ssh->compat, NULL)) != 0)
22619261079SEd Maste 		goto out;
22719261079SEd Maste 
2281323ec57SEd Maste 	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
2291323ec57SEd Maste 	    (r = kex_send_newkeys(ssh)) != 0)
2301323ec57SEd Maste 		goto out;
2311323ec57SEd Maste 
2321323ec57SEd Maste 	/* save initial signature and hostkey */
2331323ec57SEd Maste 	if ((kex->flags & KEX_INITIAL) != 0) {
2341323ec57SEd Maste 		if (kex->initial_hostkey != NULL || kex->initial_sig != NULL) {
2351323ec57SEd Maste 			r = SSH_ERR_INTERNAL_ERROR;
2361323ec57SEd Maste 			goto out;
2371323ec57SEd Maste 		}
2381323ec57SEd Maste 		if ((kex->initial_sig = sshbuf_new()) == NULL) {
2391323ec57SEd Maste 			r = SSH_ERR_ALLOC_FAIL;
2401323ec57SEd Maste 			goto out;
2411323ec57SEd Maste 		}
2421323ec57SEd Maste 		if ((r = sshbuf_put(kex->initial_sig, signature, slen)) != 0)
2431323ec57SEd Maste 			goto out;
2441323ec57SEd Maste 		kex->initial_hostkey = server_host_key;
2451323ec57SEd Maste 		server_host_key = NULL;
2461323ec57SEd Maste 	}
2471323ec57SEd Maste 	/* success */
24819261079SEd Maste out:
24919261079SEd Maste 	explicit_bzero(hash, sizeof(hash));
25019261079SEd Maste 	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
25119261079SEd Maste 	explicit_bzero(kex->sntrup761_client_key,
25219261079SEd Maste 	    sizeof(kex->sntrup761_client_key));
253*3d9fd9fcSEd Maste 	explicit_bzero(kex->mlkem768_client_key,
254*3d9fd9fcSEd Maste 	    sizeof(kex->mlkem768_client_key));
25519261079SEd Maste 	sshbuf_free(server_host_key_blob);
25619261079SEd Maste 	free(signature);
25719261079SEd Maste 	sshbuf_free(tmp);
25819261079SEd Maste 	sshkey_free(server_host_key);
25919261079SEd Maste 	sshbuf_free(server_blob);
26019261079SEd Maste 	sshbuf_free(shared_secret);
26119261079SEd Maste 	sshbuf_free(kex->client_pub);
26219261079SEd Maste 	kex->client_pub = NULL;
26319261079SEd Maste 	return r;
26419261079SEd Maste }
26519261079SEd Maste 
26619261079SEd Maste int
kex_gen_server(struct ssh * ssh)26719261079SEd Maste kex_gen_server(struct ssh *ssh)
26819261079SEd Maste {
26919261079SEd Maste 	debug("expecting SSH2_MSG_KEX_ECDH_INIT");
27019261079SEd Maste 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
27119261079SEd Maste 	return 0;
27219261079SEd Maste }
27319261079SEd Maste 
27419261079SEd Maste static int
input_kex_gen_init(int type,u_int32_t seq,struct ssh * ssh)27519261079SEd Maste input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
27619261079SEd Maste {
27719261079SEd Maste 	struct kex *kex = ssh->kex;
27819261079SEd Maste 	struct sshkey *server_host_private, *server_host_public;
27919261079SEd Maste 	struct sshbuf *shared_secret = NULL;
28019261079SEd Maste 	struct sshbuf *server_pubkey = NULL;
28119261079SEd Maste 	struct sshbuf *client_pubkey = NULL;
28219261079SEd Maste 	struct sshbuf *server_host_key_blob = NULL;
28319261079SEd Maste 	u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
28419261079SEd Maste 	size_t slen, hashlen;
28519261079SEd Maste 	int r;
28619261079SEd Maste 
28719261079SEd Maste 	debug("SSH2_MSG_KEX_ECDH_INIT received");
28819261079SEd Maste 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
28919261079SEd Maste 
29019261079SEd Maste 	if ((r = kex_load_hostkey(ssh, &server_host_private,
29119261079SEd Maste 	    &server_host_public)) != 0)
29219261079SEd Maste 		goto out;
29319261079SEd Maste 
29419261079SEd Maste 	if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
29519261079SEd Maste 	    (r = sshpkt_get_end(ssh)) != 0)
29619261079SEd Maste 		goto out;
29719261079SEd Maste 
29819261079SEd Maste 	/* compute shared secret */
29919261079SEd Maste 	switch (kex->kex_type) {
30019261079SEd Maste #ifdef WITH_OPENSSL
30119261079SEd Maste 	case KEX_DH_GRP1_SHA1:
30219261079SEd Maste 	case KEX_DH_GRP14_SHA1:
30319261079SEd Maste 	case KEX_DH_GRP14_SHA256:
30419261079SEd Maste 	case KEX_DH_GRP16_SHA512:
30519261079SEd Maste 	case KEX_DH_GRP18_SHA512:
30619261079SEd Maste 		r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
30719261079SEd Maste 		    &shared_secret);
30819261079SEd Maste 		break;
30919261079SEd Maste 	case KEX_ECDH_SHA2:
31019261079SEd Maste 		r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
31119261079SEd Maste 		    &shared_secret);
31219261079SEd Maste 		break;
31319261079SEd Maste #endif
31419261079SEd Maste 	case KEX_C25519_SHA256:
31519261079SEd Maste 		r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
31619261079SEd Maste 		    &shared_secret);
31719261079SEd Maste 		break;
31819261079SEd Maste 	case KEX_KEM_SNTRUP761X25519_SHA512:
31919261079SEd Maste 		r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
32019261079SEd Maste 		    &server_pubkey, &shared_secret);
32119261079SEd Maste 		break;
322*3d9fd9fcSEd Maste 	case KEX_KEM_MLKEM768X25519_SHA256:
323*3d9fd9fcSEd Maste 		r = kex_kem_mlkem768x25519_enc(kex, client_pubkey,
324*3d9fd9fcSEd Maste 		    &server_pubkey, &shared_secret);
325*3d9fd9fcSEd Maste 		break;
32619261079SEd Maste 	default:
32719261079SEd Maste 		r = SSH_ERR_INVALID_ARGUMENT;
32819261079SEd Maste 		break;
32919261079SEd Maste 	}
33019261079SEd Maste 	if (r !=0 )
33119261079SEd Maste 		goto out;
33219261079SEd Maste 
33319261079SEd Maste 	/* calc H */
33419261079SEd Maste 	if ((server_host_key_blob = sshbuf_new()) == NULL) {
33519261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
33619261079SEd Maste 		goto out;
33719261079SEd Maste 	}
33819261079SEd Maste 	if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
33919261079SEd Maste 		goto out;
34019261079SEd Maste 	hashlen = sizeof(hash);
34119261079SEd Maste 	if ((r = kex_gen_hash(
34219261079SEd Maste 	    kex->hash_alg,
34319261079SEd Maste 	    kex->client_version,
34419261079SEd Maste 	    kex->server_version,
34519261079SEd Maste 	    kex->peer,
34619261079SEd Maste 	    kex->my,
34719261079SEd Maste 	    server_host_key_blob,
34819261079SEd Maste 	    client_pubkey,
34919261079SEd Maste 	    server_pubkey,
35019261079SEd Maste 	    shared_secret,
35119261079SEd Maste 	    hash, &hashlen)) != 0)
35219261079SEd Maste 		goto out;
35319261079SEd Maste 
35419261079SEd Maste 	/* sign H */
35519261079SEd Maste 	if ((r = kex->sign(ssh, server_host_private, server_host_public,
35619261079SEd Maste 	    &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
35719261079SEd Maste 		goto out;
35819261079SEd Maste 
35919261079SEd Maste 	/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
36019261079SEd Maste 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
36119261079SEd Maste 	    (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
36219261079SEd Maste 	    (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
36319261079SEd Maste 	    (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
36419261079SEd Maste 	    (r = sshpkt_send(ssh)) != 0)
36519261079SEd Maste 		goto out;
36619261079SEd Maste 
3671323ec57SEd Maste 	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
3681323ec57SEd Maste 	    (r = kex_send_newkeys(ssh)) != 0)
3691323ec57SEd Maste 		goto out;
3701323ec57SEd Maste 	/* retain copy of hostkey used at initial KEX */
3711323ec57SEd Maste 	if (kex->initial_hostkey == NULL &&
3721323ec57SEd Maste 	    (r = sshkey_from_private(server_host_public,
3731323ec57SEd Maste 	    &kex->initial_hostkey)) != 0)
3741323ec57SEd Maste 		goto out;
3751323ec57SEd Maste 	/* success */
37619261079SEd Maste out:
37719261079SEd Maste 	explicit_bzero(hash, sizeof(hash));
37819261079SEd Maste 	sshbuf_free(server_host_key_blob);
37919261079SEd Maste 	free(signature);
38019261079SEd Maste 	sshbuf_free(shared_secret);
38119261079SEd Maste 	sshbuf_free(client_pubkey);
38219261079SEd Maste 	sshbuf_free(server_pubkey);
38319261079SEd Maste 	return r;
38419261079SEd Maste }
385