Annotation of src/usr.bin/ssh/kexgen.c, Revision 1.7
1.7 ! djm 1: /* $OpenBSD: kexgen.c,v 1.6 2021/01/31 22:55:29 djm Exp $ */
1.1 djm 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 <sys/types.h>
27:
28: #include <stdio.h>
29: #include <string.h>
30: #include <signal.h>
31:
32: #include "sshkey.h"
33: #include "kex.h"
34: #include "log.h"
35: #include "packet.h"
36: #include "ssh2.h"
37: #include "sshbuf.h"
38: #include "digest.h"
39: #include "ssherr.h"
40:
41: static int input_kex_gen_init(int, u_int32_t, struct ssh *);
42: static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
43:
44: static int
45: kex_gen_hash(
46: int hash_alg,
47: const struct sshbuf *client_version,
48: const struct sshbuf *server_version,
1.2 djm 49: const struct sshbuf *client_kexinit,
50: const struct sshbuf *server_kexinit,
51: const struct sshbuf *server_host_key_blob,
1.1 djm 52: const struct sshbuf *client_pub,
53: const struct sshbuf *server_pub,
54: const struct sshbuf *shared_secret,
55: u_char *hash, size_t *hashlen)
56: {
57: struct sshbuf *b;
58: int r;
59:
60: if (*hashlen < ssh_digest_bytes(hash_alg))
61: return SSH_ERR_INVALID_ARGUMENT;
62: if ((b = sshbuf_new()) == NULL)
63: return SSH_ERR_ALLOC_FAIL;
64: if ((r = sshbuf_put_stringb(b, client_version)) != 0 ||
65: (r = sshbuf_put_stringb(b, server_version)) != 0 ||
66: /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
1.2 djm 67: (r = sshbuf_put_u32(b, sshbuf_len(client_kexinit) + 1)) != 0 ||
1.1 djm 68: (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
1.2 djm 69: (r = sshbuf_putb(b, client_kexinit)) != 0 ||
70: (r = sshbuf_put_u32(b, sshbuf_len(server_kexinit) + 1)) != 0 ||
1.1 djm 71: (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
1.2 djm 72: (r = sshbuf_putb(b, server_kexinit)) != 0 ||
73: (r = sshbuf_put_stringb(b, server_host_key_blob)) != 0 ||
1.1 djm 74: (r = sshbuf_put_stringb(b, client_pub)) != 0 ||
75: (r = sshbuf_put_stringb(b, server_pub)) != 0 ||
76: (r = sshbuf_putb(b, shared_secret)) != 0) {
77: sshbuf_free(b);
78: return r;
79: }
80: #ifdef DEBUG_KEX
81: sshbuf_dump(b, stderr);
82: #endif
83: if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
84: sshbuf_free(b);
85: return SSH_ERR_LIBCRYPTO_ERROR;
86: }
87: sshbuf_free(b);
88: *hashlen = ssh_digest_bytes(hash_alg);
89: #ifdef DEBUG_KEX
90: dump_digest("hash", hash, *hashlen);
91: #endif
92: return 0;
93: }
94:
95: int
96: kex_gen_client(struct ssh *ssh)
97: {
98: struct kex *kex = ssh->kex;
99: int r;
100:
101: switch (kex->kex_type) {
1.3 djm 102: #ifdef WITH_OPENSSL
1.1 djm 103: case KEX_DH_GRP1_SHA1:
104: case KEX_DH_GRP14_SHA1:
105: case KEX_DH_GRP14_SHA256:
106: case KEX_DH_GRP16_SHA512:
107: case KEX_DH_GRP18_SHA512:
108: r = kex_dh_keypair(kex);
109: break;
110: case KEX_ECDH_SHA2:
111: r = kex_ecdh_keypair(kex);
112: break;
1.3 djm 113: #endif /* WITH_OPENSSL */
1.1 djm 114: case KEX_C25519_SHA256:
115: r = kex_c25519_keypair(kex);
116: break;
1.5 djm 117: case KEX_KEM_SNTRUP761X25519_SHA512:
118: r = kex_kem_sntrup761x25519_keypair(kex);
1.1 djm 119: break;
120: default:
121: r = SSH_ERR_INVALID_ARGUMENT;
122: break;
123: }
124: if (r != 0)
125: return r;
126: if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
127: (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 ||
128: (r = sshpkt_send(ssh)) != 0)
129: return r;
130: debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
131: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply);
132: return 0;
133: }
134:
135: static int
136: input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
137: {
138: struct kex *kex = ssh->kex;
139: struct sshkey *server_host_key = NULL;
140: struct sshbuf *shared_secret = NULL;
141: struct sshbuf *server_blob = NULL;
1.2 djm 142: struct sshbuf *tmp = NULL, *server_host_key_blob = NULL;
143: u_char *signature = NULL;
1.1 djm 144: u_char hash[SSH_DIGEST_MAX_LENGTH];
1.2 djm 145: size_t slen, hashlen;
1.1 djm 146: int r;
147:
1.6 djm 148: debug("SSH2_MSG_KEX_ECDH_REPLY received");
149: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error);
150:
1.1 djm 151: /* hostkey */
1.2 djm 152: if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
153: goto out;
154: /* sshkey_fromb() consumes its buffer, so make a copy */
155: if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
156: r = SSH_ERR_ALLOC_FAIL;
157: goto out;
158: }
159: if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
1.1 djm 160: goto out;
161: if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
162: goto out;
163:
164: /* Q_S, server public key */
165: /* signed H */
166: if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
167: (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
168: (r = sshpkt_get_end(ssh)) != 0)
169: goto out;
170:
171: /* compute shared secret */
172: switch (kex->kex_type) {
1.3 djm 173: #ifdef WITH_OPENSSL
1.1 djm 174: case KEX_DH_GRP1_SHA1:
175: case KEX_DH_GRP14_SHA1:
176: case KEX_DH_GRP14_SHA256:
177: case KEX_DH_GRP16_SHA512:
178: case KEX_DH_GRP18_SHA512:
179: r = kex_dh_dec(kex, server_blob, &shared_secret);
180: break;
181: case KEX_ECDH_SHA2:
182: r = kex_ecdh_dec(kex, server_blob, &shared_secret);
183: break;
1.3 djm 184: #endif /* WITH_OPENSSL */
1.1 djm 185: case KEX_C25519_SHA256:
186: r = kex_c25519_dec(kex, server_blob, &shared_secret);
187: break;
1.5 djm 188: case KEX_KEM_SNTRUP761X25519_SHA512:
189: r = kex_kem_sntrup761x25519_dec(kex, server_blob,
1.1 djm 190: &shared_secret);
191: break;
192: default:
193: r = SSH_ERR_INVALID_ARGUMENT;
194: break;
195: }
196: if (r !=0 )
197: goto out;
198:
199: /* calc and verify H */
200: hashlen = sizeof(hash);
201: if ((r = kex_gen_hash(
202: kex->hash_alg,
203: kex->client_version,
204: kex->server_version,
1.2 djm 205: kex->my,
206: kex->peer,
207: server_host_key_blob,
1.1 djm 208: kex->client_pub,
209: server_blob,
210: shared_secret,
211: hash, &hashlen)) != 0)
212: goto out;
213:
214: if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
1.4 djm 215: kex->hostkey_alg, ssh->compat, NULL)) != 0)
1.1 djm 216: goto out;
217:
218: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
219: r = kex_send_newkeys(ssh);
220: out:
221: explicit_bzero(hash, sizeof(hash));
222: explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
1.5 djm 223: explicit_bzero(kex->sntrup761_client_key,
224: sizeof(kex->sntrup761_client_key));
1.2 djm 225: sshbuf_free(server_host_key_blob);
1.1 djm 226: free(signature);
1.2 djm 227: sshbuf_free(tmp);
1.1 djm 228: sshkey_free(server_host_key);
229: sshbuf_free(server_blob);
230: sshbuf_free(shared_secret);
231: sshbuf_free(kex->client_pub);
232: kex->client_pub = NULL;
233: return r;
234: }
235:
236: int
237: kex_gen_server(struct ssh *ssh)
238: {
239: debug("expecting SSH2_MSG_KEX_ECDH_INIT");
240: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
241: return 0;
242: }
243:
244: static int
245: input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
246: {
247: struct kex *kex = ssh->kex;
248: struct sshkey *server_host_private, *server_host_public;
249: struct sshbuf *shared_secret = NULL;
250: struct sshbuf *server_pubkey = NULL;
251: struct sshbuf *client_pubkey = NULL;
1.2 djm 252: struct sshbuf *server_host_key_blob = NULL;
253: u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
254: size_t slen, hashlen;
1.1 djm 255: int r;
1.6 djm 256:
257: debug("SSH2_MSG_KEX_ECDH_INIT received");
258: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
1.1 djm 259:
260: if ((r = kex_load_hostkey(ssh, &server_host_private,
261: &server_host_public)) != 0)
262: goto out;
263:
264: if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
265: (r = sshpkt_get_end(ssh)) != 0)
266: goto out;
267:
268: /* compute shared secret */
269: switch (kex->kex_type) {
1.3 djm 270: #ifdef WITH_OPENSSL
1.1 djm 271: case KEX_DH_GRP1_SHA1:
272: case KEX_DH_GRP14_SHA1:
273: case KEX_DH_GRP14_SHA256:
274: case KEX_DH_GRP16_SHA512:
275: case KEX_DH_GRP18_SHA512:
276: r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
277: &shared_secret);
278: break;
279: case KEX_ECDH_SHA2:
280: r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
281: &shared_secret);
282: break;
1.3 djm 283: #endif /* WITH_OPENSSL */
1.1 djm 284: case KEX_C25519_SHA256:
285: r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
286: &shared_secret);
287: break;
1.5 djm 288: case KEX_KEM_SNTRUP761X25519_SHA512:
289: r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
1.1 djm 290: &server_pubkey, &shared_secret);
291: break;
292: default:
293: r = SSH_ERR_INVALID_ARGUMENT;
294: break;
295: }
296: if (r !=0 )
297: goto out;
298:
299: /* calc H */
1.2 djm 300: if ((server_host_key_blob = sshbuf_new()) == NULL) {
301: r = SSH_ERR_ALLOC_FAIL;
302: goto out;
303: }
304: if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
1.1 djm 305: goto out;
306: hashlen = sizeof(hash);
307: if ((r = kex_gen_hash(
308: kex->hash_alg,
309: kex->client_version,
310: kex->server_version,
1.2 djm 311: kex->peer,
312: kex->my,
313: server_host_key_blob,
1.1 djm 314: client_pubkey,
315: server_pubkey,
316: shared_secret,
317: hash, &hashlen)) != 0)
318: goto out;
319:
320: /* sign H */
321: if ((r = kex->sign(ssh, server_host_private, server_host_public,
1.7 ! djm 322: &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
1.1 djm 323: goto out;
324:
325: /* send server hostkey, ECDH pubkey 'Q_S' and signed H */
326: if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
1.2 djm 327: (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
1.1 djm 328: (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
329: (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
330: (r = sshpkt_send(ssh)) != 0)
331: goto out;
332:
333: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
334: r = kex_send_newkeys(ssh);
335: out:
336: explicit_bzero(hash, sizeof(hash));
1.2 djm 337: sshbuf_free(server_host_key_blob);
1.1 djm 338: free(signature);
339: sshbuf_free(shared_secret);
340: sshbuf_free(client_pubkey);
341: sshbuf_free(server_pubkey);
342: return r;
343: }