xref: /openbsd-src/usr.bin/ssh/kexgen.c (revision 4e5f03cb47c24aef03761f29b01d695b98a8148e)
1*4e5f03cbSdjm /* $OpenBSD: kexgen.c,v 1.10 2024/09/09 02:39:57 djm Exp $ */
2d84d4014Sdjm /*
3d84d4014Sdjm  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
4d84d4014Sdjm  *
5d84d4014Sdjm  * Redistribution and use in source and binary forms, with or without
6d84d4014Sdjm  * modification, are permitted provided that the following conditions
7d84d4014Sdjm  * are met:
8d84d4014Sdjm  * 1. Redistributions of source code must retain the above copyright
9d84d4014Sdjm  *    notice, this list of conditions and the following disclaimer.
10d84d4014Sdjm  * 2. Redistributions in binary form must reproduce the above copyright
11d84d4014Sdjm  *    notice, this list of conditions and the following disclaimer in the
12d84d4014Sdjm  *    documentation and/or other materials provided with the distribution.
13d84d4014Sdjm  *
14d84d4014Sdjm  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15d84d4014Sdjm  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16d84d4014Sdjm  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17d84d4014Sdjm  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18d84d4014Sdjm  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19d84d4014Sdjm  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20d84d4014Sdjm  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21d84d4014Sdjm  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22d84d4014Sdjm  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23d84d4014Sdjm  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24d84d4014Sdjm  */
25d84d4014Sdjm 
26d84d4014Sdjm #include <sys/types.h>
27d84d4014Sdjm 
28d84d4014Sdjm #include <stdio.h>
29d84d4014Sdjm #include <string.h>
30d84d4014Sdjm #include <signal.h>
31d84d4014Sdjm 
32d84d4014Sdjm #include "sshkey.h"
33d84d4014Sdjm #include "kex.h"
34d84d4014Sdjm #include "log.h"
35d84d4014Sdjm #include "packet.h"
36d84d4014Sdjm #include "ssh2.h"
37d84d4014Sdjm #include "sshbuf.h"
38d84d4014Sdjm #include "digest.h"
39d84d4014Sdjm #include "ssherr.h"
40d84d4014Sdjm 
41d84d4014Sdjm static int input_kex_gen_init(int, u_int32_t, struct ssh *);
42d84d4014Sdjm static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
43d84d4014Sdjm 
44d84d4014Sdjm static int
45d84d4014Sdjm kex_gen_hash(
46d84d4014Sdjm     int hash_alg,
47d84d4014Sdjm     const struct sshbuf *client_version,
48d84d4014Sdjm     const struct sshbuf *server_version,
4921d29470Sdjm     const struct sshbuf *client_kexinit,
5021d29470Sdjm     const struct sshbuf *server_kexinit,
5121d29470Sdjm     const struct sshbuf *server_host_key_blob,
52d84d4014Sdjm     const struct sshbuf *client_pub,
53d84d4014Sdjm     const struct sshbuf *server_pub,
54d84d4014Sdjm     const struct sshbuf *shared_secret,
55d84d4014Sdjm     u_char *hash, size_t *hashlen)
56d84d4014Sdjm {
57d84d4014Sdjm 	struct sshbuf *b;
58d84d4014Sdjm 	int r;
59d84d4014Sdjm 
60d84d4014Sdjm 	if (*hashlen < ssh_digest_bytes(hash_alg))
61d84d4014Sdjm 		return SSH_ERR_INVALID_ARGUMENT;
62d84d4014Sdjm 	if ((b = sshbuf_new()) == NULL)
63d84d4014Sdjm 		return SSH_ERR_ALLOC_FAIL;
64d84d4014Sdjm 	if ((r = sshbuf_put_stringb(b, client_version)) != 0 ||
65d84d4014Sdjm 	    (r = sshbuf_put_stringb(b, server_version)) != 0 ||
66d84d4014Sdjm 	    /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
6721d29470Sdjm 	    (r = sshbuf_put_u32(b, sshbuf_len(client_kexinit) + 1)) != 0 ||
68d84d4014Sdjm 	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
6921d29470Sdjm 	    (r = sshbuf_putb(b, client_kexinit)) != 0 ||
7021d29470Sdjm 	    (r = sshbuf_put_u32(b, sshbuf_len(server_kexinit) + 1)) != 0 ||
71d84d4014Sdjm 	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
7221d29470Sdjm 	    (r = sshbuf_putb(b, server_kexinit)) != 0 ||
7321d29470Sdjm 	    (r = sshbuf_put_stringb(b, server_host_key_blob)) != 0 ||
74d84d4014Sdjm 	    (r = sshbuf_put_stringb(b, client_pub)) != 0 ||
75d84d4014Sdjm 	    (r = sshbuf_put_stringb(b, server_pub)) != 0 ||
76d84d4014Sdjm 	    (r = sshbuf_putb(b, shared_secret)) != 0) {
77d84d4014Sdjm 		sshbuf_free(b);
78d84d4014Sdjm 		return r;
79d84d4014Sdjm 	}
80d84d4014Sdjm #ifdef DEBUG_KEX
81d84d4014Sdjm 	sshbuf_dump(b, stderr);
82d84d4014Sdjm #endif
83d84d4014Sdjm 	if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
84d84d4014Sdjm 		sshbuf_free(b);
85d84d4014Sdjm 		return SSH_ERR_LIBCRYPTO_ERROR;
86d84d4014Sdjm 	}
87d84d4014Sdjm 	sshbuf_free(b);
88d84d4014Sdjm 	*hashlen = ssh_digest_bytes(hash_alg);
89d84d4014Sdjm #ifdef DEBUG_KEX
90d84d4014Sdjm 	dump_digest("hash", hash, *hashlen);
91d84d4014Sdjm #endif
92d84d4014Sdjm 	return 0;
93d84d4014Sdjm }
94d84d4014Sdjm 
95d84d4014Sdjm int
96d84d4014Sdjm kex_gen_client(struct ssh *ssh)
97d84d4014Sdjm {
98d84d4014Sdjm 	struct kex *kex = ssh->kex;
99d84d4014Sdjm 	int r;
100d84d4014Sdjm 
101d84d4014Sdjm 	switch (kex->kex_type) {
1021f96526fSdjm #ifdef WITH_OPENSSL
103d84d4014Sdjm 	case KEX_DH_GRP1_SHA1:
104d84d4014Sdjm 	case KEX_DH_GRP14_SHA1:
105d84d4014Sdjm 	case KEX_DH_GRP14_SHA256:
106d84d4014Sdjm 	case KEX_DH_GRP16_SHA512:
107d84d4014Sdjm 	case KEX_DH_GRP18_SHA512:
108d84d4014Sdjm 		r = kex_dh_keypair(kex);
109d84d4014Sdjm 		break;
110d84d4014Sdjm 	case KEX_ECDH_SHA2:
111d84d4014Sdjm 		r = kex_ecdh_keypair(kex);
112d84d4014Sdjm 		break;
1131f96526fSdjm #endif /* WITH_OPENSSL */
114d84d4014Sdjm 	case KEX_C25519_SHA256:
115d84d4014Sdjm 		r = kex_c25519_keypair(kex);
116d84d4014Sdjm 		break;
1173e284e19Sdjm 	case KEX_KEM_SNTRUP761X25519_SHA512:
1183e284e19Sdjm 		r = kex_kem_sntrup761x25519_keypair(kex);
119d84d4014Sdjm 		break;
1209dc26a4eSdjm 	case KEX_KEM_MLKEM768X25519_SHA256:
1219dc26a4eSdjm 		r = kex_kem_mlkem768x25519_keypair(kex);
1229dc26a4eSdjm 		break;
123d84d4014Sdjm 	default:
124d84d4014Sdjm 		r = SSH_ERR_INVALID_ARGUMENT;
125d84d4014Sdjm 		break;
126d84d4014Sdjm 	}
127d84d4014Sdjm 	if (r != 0)
128d84d4014Sdjm 		return r;
129d84d4014Sdjm 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
130d84d4014Sdjm 	    (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 ||
131d84d4014Sdjm 	    (r = sshpkt_send(ssh)) != 0)
132d84d4014Sdjm 		return r;
133d84d4014Sdjm 	debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
134d84d4014Sdjm 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply);
135d84d4014Sdjm 	return 0;
136d84d4014Sdjm }
137d84d4014Sdjm 
138d84d4014Sdjm static int
139d84d4014Sdjm input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
140d84d4014Sdjm {
141d84d4014Sdjm 	struct kex *kex = ssh->kex;
142d84d4014Sdjm 	struct sshkey *server_host_key = NULL;
143d84d4014Sdjm 	struct sshbuf *shared_secret = NULL;
144d84d4014Sdjm 	struct sshbuf *server_blob = NULL;
14521d29470Sdjm 	struct sshbuf *tmp = NULL, *server_host_key_blob = NULL;
14621d29470Sdjm 	u_char *signature = NULL;
147d84d4014Sdjm 	u_char hash[SSH_DIGEST_MAX_LENGTH];
14821d29470Sdjm 	size_t slen, hashlen;
149d84d4014Sdjm 	int r;
150d84d4014Sdjm 
1511c4876f5Sdjm 	debug("SSH2_MSG_KEX_ECDH_REPLY received");
1521c4876f5Sdjm 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error);
1531c4876f5Sdjm 
154d84d4014Sdjm 	/* hostkey */
15521d29470Sdjm 	if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
15621d29470Sdjm 		goto out;
15721d29470Sdjm 	/* sshkey_fromb() consumes its buffer, so make a copy */
15821d29470Sdjm 	if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
15921d29470Sdjm 		r = SSH_ERR_ALLOC_FAIL;
16021d29470Sdjm 		goto out;
16121d29470Sdjm 	}
16221d29470Sdjm 	if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
163d84d4014Sdjm 		goto out;
164d84d4014Sdjm 	if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
165d84d4014Sdjm 		goto out;
166d84d4014Sdjm 
167d84d4014Sdjm 	/* Q_S, server public key */
168d84d4014Sdjm 	/* signed H */
169d84d4014Sdjm 	if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
170d84d4014Sdjm 	    (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
171d84d4014Sdjm 	    (r = sshpkt_get_end(ssh)) != 0)
172d84d4014Sdjm 		goto out;
173d84d4014Sdjm 
174d84d4014Sdjm 	/* compute shared secret */
175d84d4014Sdjm 	switch (kex->kex_type) {
1761f96526fSdjm #ifdef WITH_OPENSSL
177d84d4014Sdjm 	case KEX_DH_GRP1_SHA1:
178d84d4014Sdjm 	case KEX_DH_GRP14_SHA1:
179d84d4014Sdjm 	case KEX_DH_GRP14_SHA256:
180d84d4014Sdjm 	case KEX_DH_GRP16_SHA512:
181d84d4014Sdjm 	case KEX_DH_GRP18_SHA512:
182d84d4014Sdjm 		r = kex_dh_dec(kex, server_blob, &shared_secret);
183d84d4014Sdjm 		break;
184d84d4014Sdjm 	case KEX_ECDH_SHA2:
185d84d4014Sdjm 		r = kex_ecdh_dec(kex, server_blob, &shared_secret);
186d84d4014Sdjm 		break;
1871f96526fSdjm #endif /* WITH_OPENSSL */
188d84d4014Sdjm 	case KEX_C25519_SHA256:
189d84d4014Sdjm 		r = kex_c25519_dec(kex, server_blob, &shared_secret);
190d84d4014Sdjm 		break;
1913e284e19Sdjm 	case KEX_KEM_SNTRUP761X25519_SHA512:
1923e284e19Sdjm 		r = kex_kem_sntrup761x25519_dec(kex, server_blob,
193d84d4014Sdjm 		    &shared_secret);
194d84d4014Sdjm 		break;
1959dc26a4eSdjm 	case KEX_KEM_MLKEM768X25519_SHA256:
1969dc26a4eSdjm 		r = kex_kem_mlkem768x25519_dec(kex, server_blob,
1979dc26a4eSdjm 		    &shared_secret);
1989dc26a4eSdjm 		break;
199d84d4014Sdjm 	default:
200d84d4014Sdjm 		r = SSH_ERR_INVALID_ARGUMENT;
201d84d4014Sdjm 		break;
202d84d4014Sdjm 	}
203d84d4014Sdjm 	if (r !=0 )
204d84d4014Sdjm 		goto out;
205d84d4014Sdjm 
206d84d4014Sdjm 	/* calc and verify H */
207d84d4014Sdjm 	hashlen = sizeof(hash);
208d84d4014Sdjm 	if ((r = kex_gen_hash(
209d84d4014Sdjm 	    kex->hash_alg,
210d84d4014Sdjm 	    kex->client_version,
211d84d4014Sdjm 	    kex->server_version,
21221d29470Sdjm 	    kex->my,
21321d29470Sdjm 	    kex->peer,
21421d29470Sdjm 	    server_host_key_blob,
215d84d4014Sdjm 	    kex->client_pub,
216d84d4014Sdjm 	    server_blob,
217d84d4014Sdjm 	    shared_secret,
218d84d4014Sdjm 	    hash, &hashlen)) != 0)
219d84d4014Sdjm 		goto out;
220d84d4014Sdjm 
221d84d4014Sdjm 	if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
222493ad5b0Sdjm 	    kex->hostkey_alg, ssh->compat, NULL)) != 0)
223d84d4014Sdjm 		goto out;
224d84d4014Sdjm 
225b2c330ecSdjm 	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
226b2c330ecSdjm 	    (r = kex_send_newkeys(ssh)) != 0)
227b2c330ecSdjm 		goto out;
228b2c330ecSdjm 
229b2c330ecSdjm 	/* save initial signature and hostkey */
230b2c330ecSdjm 	if ((kex->flags & KEX_INITIAL) != 0) {
231b2c330ecSdjm 		if (kex->initial_hostkey != NULL || kex->initial_sig != NULL) {
232b2c330ecSdjm 			r = SSH_ERR_INTERNAL_ERROR;
233b2c330ecSdjm 			goto out;
234b2c330ecSdjm 		}
235b2c330ecSdjm 		if ((kex->initial_sig = sshbuf_new()) == NULL) {
236b2c330ecSdjm 			r = SSH_ERR_ALLOC_FAIL;
237b2c330ecSdjm 			goto out;
238b2c330ecSdjm 		}
239b2c330ecSdjm 		if ((r = sshbuf_put(kex->initial_sig, signature, slen)) != 0)
240b2c330ecSdjm 			goto out;
241b2c330ecSdjm 		kex->initial_hostkey = server_host_key;
242b2c330ecSdjm 		server_host_key = NULL;
243b2c330ecSdjm 	}
244b2c330ecSdjm 	/* success */
245d84d4014Sdjm out:
246d84d4014Sdjm 	explicit_bzero(hash, sizeof(hash));
247d84d4014Sdjm 	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
2483e284e19Sdjm 	explicit_bzero(kex->sntrup761_client_key,
2493e284e19Sdjm 	    sizeof(kex->sntrup761_client_key));
2509dc26a4eSdjm 	explicit_bzero(kex->mlkem768_client_key,
2519dc26a4eSdjm 	    sizeof(kex->mlkem768_client_key));
25221d29470Sdjm 	sshbuf_free(server_host_key_blob);
253d84d4014Sdjm 	free(signature);
25421d29470Sdjm 	sshbuf_free(tmp);
255d84d4014Sdjm 	sshkey_free(server_host_key);
256d84d4014Sdjm 	sshbuf_free(server_blob);
257d84d4014Sdjm 	sshbuf_free(shared_secret);
258d84d4014Sdjm 	sshbuf_free(kex->client_pub);
259d84d4014Sdjm 	kex->client_pub = NULL;
260d84d4014Sdjm 	return r;
261d84d4014Sdjm }
262d84d4014Sdjm 
263d84d4014Sdjm int
264d84d4014Sdjm kex_gen_server(struct ssh *ssh)
265d84d4014Sdjm {
266d84d4014Sdjm 	debug("expecting SSH2_MSG_KEX_ECDH_INIT");
267d84d4014Sdjm 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
268d84d4014Sdjm 	return 0;
269d84d4014Sdjm }
270d84d4014Sdjm 
271d84d4014Sdjm static int
272d84d4014Sdjm input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
273d84d4014Sdjm {
274d84d4014Sdjm 	struct kex *kex = ssh->kex;
275d84d4014Sdjm 	struct sshkey *server_host_private, *server_host_public;
276d84d4014Sdjm 	struct sshbuf *shared_secret = NULL;
277d84d4014Sdjm 	struct sshbuf *server_pubkey = NULL;
278d84d4014Sdjm 	struct sshbuf *client_pubkey = NULL;
27921d29470Sdjm 	struct sshbuf *server_host_key_blob = NULL;
28021d29470Sdjm 	u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
28121d29470Sdjm 	size_t slen, hashlen;
282d84d4014Sdjm 	int r;
283d84d4014Sdjm 
2841c4876f5Sdjm 	debug("SSH2_MSG_KEX_ECDH_INIT received");
2851c4876f5Sdjm 	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
2861c4876f5Sdjm 
287d84d4014Sdjm 	if ((r = kex_load_hostkey(ssh, &server_host_private,
288d84d4014Sdjm 	    &server_host_public)) != 0)
289d84d4014Sdjm 		goto out;
290d84d4014Sdjm 
291d84d4014Sdjm 	if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
292d84d4014Sdjm 	    (r = sshpkt_get_end(ssh)) != 0)
293d84d4014Sdjm 		goto out;
294d84d4014Sdjm 
295d84d4014Sdjm 	/* compute shared secret */
296d84d4014Sdjm 	switch (kex->kex_type) {
2971f96526fSdjm #ifdef WITH_OPENSSL
298d84d4014Sdjm 	case KEX_DH_GRP1_SHA1:
299d84d4014Sdjm 	case KEX_DH_GRP14_SHA1:
300d84d4014Sdjm 	case KEX_DH_GRP14_SHA256:
301d84d4014Sdjm 	case KEX_DH_GRP16_SHA512:
302d84d4014Sdjm 	case KEX_DH_GRP18_SHA512:
303d84d4014Sdjm 		r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
304d84d4014Sdjm 		    &shared_secret);
305d84d4014Sdjm 		break;
306d84d4014Sdjm 	case KEX_ECDH_SHA2:
307d84d4014Sdjm 		r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
308d84d4014Sdjm 		    &shared_secret);
309d84d4014Sdjm 		break;
3101f96526fSdjm #endif /* WITH_OPENSSL */
311d84d4014Sdjm 	case KEX_C25519_SHA256:
312d84d4014Sdjm 		r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
313d84d4014Sdjm 		    &shared_secret);
314d84d4014Sdjm 		break;
3153e284e19Sdjm 	case KEX_KEM_SNTRUP761X25519_SHA512:
3163e284e19Sdjm 		r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
317d84d4014Sdjm 		    &server_pubkey, &shared_secret);
318d84d4014Sdjm 		break;
3199dc26a4eSdjm 	case KEX_KEM_MLKEM768X25519_SHA256:
3209dc26a4eSdjm 		r = kex_kem_mlkem768x25519_enc(kex, client_pubkey,
3219dc26a4eSdjm 		    &server_pubkey, &shared_secret);
3229dc26a4eSdjm 		break;
323d84d4014Sdjm 	default:
324d84d4014Sdjm 		r = SSH_ERR_INVALID_ARGUMENT;
325d84d4014Sdjm 		break;
326d84d4014Sdjm 	}
327d84d4014Sdjm 	if (r !=0 )
328d84d4014Sdjm 		goto out;
329d84d4014Sdjm 
330d84d4014Sdjm 	/* calc H */
33121d29470Sdjm 	if ((server_host_key_blob = sshbuf_new()) == NULL) {
33221d29470Sdjm 		r = SSH_ERR_ALLOC_FAIL;
33321d29470Sdjm 		goto out;
33421d29470Sdjm 	}
33521d29470Sdjm 	if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
336d84d4014Sdjm 		goto out;
337d84d4014Sdjm 	hashlen = sizeof(hash);
338d84d4014Sdjm 	if ((r = kex_gen_hash(
339d84d4014Sdjm 	    kex->hash_alg,
340d84d4014Sdjm 	    kex->client_version,
341d84d4014Sdjm 	    kex->server_version,
34221d29470Sdjm 	    kex->peer,
34321d29470Sdjm 	    kex->my,
34421d29470Sdjm 	    server_host_key_blob,
345d84d4014Sdjm 	    client_pubkey,
346d84d4014Sdjm 	    server_pubkey,
347d84d4014Sdjm 	    shared_secret,
348d84d4014Sdjm 	    hash, &hashlen)) != 0)
349d84d4014Sdjm 		goto out;
350d84d4014Sdjm 
351d84d4014Sdjm 	/* sign H */
352d84d4014Sdjm 	if ((r = kex->sign(ssh, server_host_private, server_host_public,
353d84d4014Sdjm 	    &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
354d84d4014Sdjm 		goto out;
355d84d4014Sdjm 
356d84d4014Sdjm 	/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
357d84d4014Sdjm 	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
35821d29470Sdjm 	    (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
359d84d4014Sdjm 	    (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
360d84d4014Sdjm 	    (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
361d84d4014Sdjm 	    (r = sshpkt_send(ssh)) != 0)
362d84d4014Sdjm 		goto out;
363d84d4014Sdjm 
364b2c330ecSdjm 	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
365b2c330ecSdjm 	    (r = kex_send_newkeys(ssh)) != 0)
366b2c330ecSdjm 		goto out;
367b2c330ecSdjm 	/* retain copy of hostkey used at initial KEX */
368b2c330ecSdjm 	if (kex->initial_hostkey == NULL &&
369b2c330ecSdjm 	    (r = sshkey_from_private(server_host_public,
370b2c330ecSdjm 	    &kex->initial_hostkey)) != 0)
371b2c330ecSdjm 		goto out;
372b2c330ecSdjm 	/* success */
373d84d4014Sdjm out:
374d84d4014Sdjm 	explicit_bzero(hash, sizeof(hash));
37521d29470Sdjm 	sshbuf_free(server_host_key_blob);
376d84d4014Sdjm 	free(signature);
377d84d4014Sdjm 	sshbuf_free(shared_secret);
378d84d4014Sdjm 	sshbuf_free(client_pubkey);
379d84d4014Sdjm 	sshbuf_free(server_pubkey);
380d84d4014Sdjm 	return r;
381d84d4014Sdjm }
382