1/* $OpenBSD: kexgen.c,v 1.8 2021/12/19 22:08:06 djm Exp $ */
2/*
3 * Copyright (c) 2019 Markus Friedl.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27
28#include <sys/types.h>
29
30#include <stdarg.h>
31#include <stdio.h>
32#include <string.h>
33#include <signal.h>
34
35#include "sshkey.h"
36#include "kex.h"
37#include "log.h"
38#include "packet.h"
39#include "ssh2.h"
40#include "sshbuf.h"
41#include "digest.h"
42#include "ssherr.h"
43
44static int input_kex_gen_init(int, u_int32_t, struct ssh *);
45static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
46
47static int
48kex_gen_hash(
49    int hash_alg,
50    const struct sshbuf *client_version,
51    const struct sshbuf *server_version,
52    const struct sshbuf *client_kexinit,
53    const struct sshbuf *server_kexinit,
54    const struct sshbuf *server_host_key_blob,
55    const struct sshbuf *client_pub,
56    const struct sshbuf *server_pub,
57    const struct sshbuf *shared_secret,
58    u_char *hash, size_t *hashlen)
59{
60	struct sshbuf *b;
61	int r;
62
63	if (*hashlen < ssh_digest_bytes(hash_alg))
64		return SSH_ERR_INVALID_ARGUMENT;
65	if ((b = sshbuf_new()) == NULL)
66		return SSH_ERR_ALLOC_FAIL;
67	if ((r = sshbuf_put_stringb(b, client_version)) != 0 ||
68	    (r = sshbuf_put_stringb(b, server_version)) != 0 ||
69	    /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
70	    (r = sshbuf_put_u32(b, sshbuf_len(client_kexinit) + 1)) != 0 ||
71	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
72	    (r = sshbuf_putb(b, client_kexinit)) != 0 ||
73	    (r = sshbuf_put_u32(b, sshbuf_len(server_kexinit) + 1)) != 0 ||
74	    (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
75	    (r = sshbuf_putb(b, server_kexinit)) != 0 ||
76	    (r = sshbuf_put_stringb(b, server_host_key_blob)) != 0 ||
77	    (r = sshbuf_put_stringb(b, client_pub)) != 0 ||
78	    (r = sshbuf_put_stringb(b, server_pub)) != 0 ||
79	    (r = sshbuf_putb(b, shared_secret)) != 0) {
80		sshbuf_free(b);
81		return r;
82	}
83#ifdef DEBUG_KEX
84	sshbuf_dump(b, stderr);
85#endif
86	if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
87		sshbuf_free(b);
88		return SSH_ERR_LIBCRYPTO_ERROR;
89	}
90	sshbuf_free(b);
91	*hashlen = ssh_digest_bytes(hash_alg);
92#ifdef DEBUG_KEX
93	dump_digest("hash", hash, *hashlen);
94#endif
95	return 0;
96}
97
98int
99kex_gen_client(struct ssh *ssh)
100{
101	struct kex *kex = ssh->kex;
102	int r;
103
104	switch (kex->kex_type) {
105#ifdef WITH_OPENSSL
106	case KEX_DH_GRP1_SHA1:
107	case KEX_DH_GRP14_SHA1:
108	case KEX_DH_GRP14_SHA256:
109	case KEX_DH_GRP16_SHA512:
110	case KEX_DH_GRP18_SHA512:
111		r = kex_dh_keypair(kex);
112		break;
113	case KEX_ECDH_SHA2:
114		r = kex_ecdh_keypair(kex);
115		break;
116#endif
117	case KEX_C25519_SHA256:
118		r = kex_c25519_keypair(kex);
119		break;
120	case KEX_KEM_SNTRUP761X25519_SHA512:
121		r = kex_kem_sntrup761x25519_keypair(kex);
122		break;
123	default:
124		r = SSH_ERR_INVALID_ARGUMENT;
125		break;
126	}
127	if (r != 0)
128		return r;
129	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
130	    (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 ||
131	    (r = sshpkt_send(ssh)) != 0)
132		return r;
133	debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
134	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply);
135	return 0;
136}
137
138static int
139input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
140{
141	struct kex *kex = ssh->kex;
142	struct sshkey *server_host_key = NULL;
143	struct sshbuf *shared_secret = NULL;
144	struct sshbuf *server_blob = NULL;
145	struct sshbuf *tmp = NULL, *server_host_key_blob = NULL;
146	u_char *signature = NULL;
147	u_char hash[SSH_DIGEST_MAX_LENGTH];
148	size_t slen, hashlen;
149	int r;
150
151	debug("SSH2_MSG_KEX_ECDH_REPLY received");
152	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error);
153
154	/* hostkey */
155	if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
156		goto out;
157	/* sshkey_fromb() consumes its buffer, so make a copy */
158	if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
159		r = SSH_ERR_ALLOC_FAIL;
160		goto out;
161	}
162	if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
163		goto out;
164	if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
165		goto out;
166
167	/* Q_S, server public key */
168	/* signed H */
169	if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
170	    (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
171	    (r = sshpkt_get_end(ssh)) != 0)
172		goto out;
173
174	/* compute shared secret */
175	switch (kex->kex_type) {
176#ifdef WITH_OPENSSL
177	case KEX_DH_GRP1_SHA1:
178	case KEX_DH_GRP14_SHA1:
179	case KEX_DH_GRP14_SHA256:
180	case KEX_DH_GRP16_SHA512:
181	case KEX_DH_GRP18_SHA512:
182		r = kex_dh_dec(kex, server_blob, &shared_secret);
183		break;
184	case KEX_ECDH_SHA2:
185		r = kex_ecdh_dec(kex, server_blob, &shared_secret);
186		break;
187#endif
188	case KEX_C25519_SHA256:
189		r = kex_c25519_dec(kex, server_blob, &shared_secret);
190		break;
191	case KEX_KEM_SNTRUP761X25519_SHA512:
192		r = kex_kem_sntrup761x25519_dec(kex, server_blob,
193		    &shared_secret);
194		break;
195	default:
196		r = SSH_ERR_INVALID_ARGUMENT;
197		break;
198	}
199	if (r !=0 )
200		goto out;
201
202	/* calc and verify H */
203	hashlen = sizeof(hash);
204	if ((r = kex_gen_hash(
205	    kex->hash_alg,
206	    kex->client_version,
207	    kex->server_version,
208	    kex->my,
209	    kex->peer,
210	    server_host_key_blob,
211	    kex->client_pub,
212	    server_blob,
213	    shared_secret,
214	    hash, &hashlen)) != 0)
215		goto out;
216
217	if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
218	    kex->hostkey_alg, ssh->compat, NULL)) != 0)
219		goto out;
220
221	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
222	    (r = kex_send_newkeys(ssh)) != 0)
223		goto out;
224
225	/* save initial signature and hostkey */
226	if ((kex->flags & KEX_INITIAL) != 0) {
227		if (kex->initial_hostkey != NULL || kex->initial_sig != NULL) {
228			r = SSH_ERR_INTERNAL_ERROR;
229			goto out;
230		}
231		if ((kex->initial_sig = sshbuf_new()) == NULL) {
232			r = SSH_ERR_ALLOC_FAIL;
233			goto out;
234		}
235		if ((r = sshbuf_put(kex->initial_sig, signature, slen)) != 0)
236			goto out;
237		kex->initial_hostkey = server_host_key;
238		server_host_key = NULL;
239	}
240	/* success */
241out:
242	explicit_bzero(hash, sizeof(hash));
243	explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
244	explicit_bzero(kex->sntrup761_client_key,
245	    sizeof(kex->sntrup761_client_key));
246	sshbuf_free(server_host_key_blob);
247	free(signature);
248	sshbuf_free(tmp);
249	sshkey_free(server_host_key);
250	sshbuf_free(server_blob);
251	sshbuf_free(shared_secret);
252	sshbuf_free(kex->client_pub);
253	kex->client_pub = NULL;
254	return r;
255}
256
257int
258kex_gen_server(struct ssh *ssh)
259{
260	debug("expecting SSH2_MSG_KEX_ECDH_INIT");
261	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
262	return 0;
263}
264
265static int
266input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
267{
268	struct kex *kex = ssh->kex;
269	struct sshkey *server_host_private, *server_host_public;
270	struct sshbuf *shared_secret = NULL;
271	struct sshbuf *server_pubkey = NULL;
272	struct sshbuf *client_pubkey = NULL;
273	struct sshbuf *server_host_key_blob = NULL;
274	u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
275	size_t slen, hashlen;
276	int r;
277
278	debug("SSH2_MSG_KEX_ECDH_INIT received");
279	ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
280
281	if ((r = kex_load_hostkey(ssh, &server_host_private,
282	    &server_host_public)) != 0)
283		goto out;
284
285	if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
286	    (r = sshpkt_get_end(ssh)) != 0)
287		goto out;
288
289	/* compute shared secret */
290	switch (kex->kex_type) {
291#ifdef WITH_OPENSSL
292	case KEX_DH_GRP1_SHA1:
293	case KEX_DH_GRP14_SHA1:
294	case KEX_DH_GRP14_SHA256:
295	case KEX_DH_GRP16_SHA512:
296	case KEX_DH_GRP18_SHA512:
297		r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
298		    &shared_secret);
299		break;
300	case KEX_ECDH_SHA2:
301		r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
302		    &shared_secret);
303		break;
304#endif
305	case KEX_C25519_SHA256:
306		r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
307		    &shared_secret);
308		break;
309	case KEX_KEM_SNTRUP761X25519_SHA512:
310		r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
311		    &server_pubkey, &shared_secret);
312		break;
313	default:
314		r = SSH_ERR_INVALID_ARGUMENT;
315		break;
316	}
317	if (r !=0 )
318		goto out;
319
320	/* calc H */
321	if ((server_host_key_blob = sshbuf_new()) == NULL) {
322		r = SSH_ERR_ALLOC_FAIL;
323		goto out;
324	}
325	if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
326		goto out;
327	hashlen = sizeof(hash);
328	if ((r = kex_gen_hash(
329	    kex->hash_alg,
330	    kex->client_version,
331	    kex->server_version,
332	    kex->peer,
333	    kex->my,
334	    server_host_key_blob,
335	    client_pubkey,
336	    server_pubkey,
337	    shared_secret,
338	    hash, &hashlen)) != 0)
339		goto out;
340
341	/* sign H */
342	if ((r = kex->sign(ssh, server_host_private, server_host_public,
343	    &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
344		goto out;
345
346	/* send server hostkey, ECDH pubkey 'Q_S' and signed H */
347	if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
348	    (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
349	    (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
350	    (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
351	    (r = sshpkt_send(ssh)) != 0)
352		goto out;
353
354	if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
355	    (r = kex_send_newkeys(ssh)) != 0)
356		goto out;
357	/* retain copy of hostkey used at initial KEX */
358	if (kex->initial_hostkey == NULL &&
359	    (r = sshkey_from_private(server_host_public,
360	    &kex->initial_hostkey)) != 0)
361		goto out;
362	/* success */
363out:
364	explicit_bzero(hash, sizeof(hash));
365	sshbuf_free(server_host_key_blob);
366	free(signature);
367	sshbuf_free(shared_secret);
368	sshbuf_free(client_pubkey);
369	sshbuf_free(server_pubkey);
370	return r;
371}
372