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