Annotation of src/usr.bin/ssh/kexgen.c, Revision 1.4
1.4 ! djm 1: /* $OpenBSD: kexgen.c,v 1.3 2019/09/06 05:23:55 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;
117: case KEX_KEM_SNTRUP4591761X25519_SHA512:
118: r = kex_kem_sntrup4591761x25519_keypair(kex);
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:
148: /* hostkey */
1.2 djm 149: if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
150: goto out;
151: /* sshkey_fromb() consumes its buffer, so make a copy */
152: if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) {
153: r = SSH_ERR_ALLOC_FAIL;
154: goto out;
155: }
156: if ((r = sshkey_fromb(tmp, &server_host_key)) != 0)
1.1 djm 157: goto out;
158: if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
159: goto out;
160:
161: /* Q_S, server public key */
162: /* signed H */
163: if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
164: (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
165: (r = sshpkt_get_end(ssh)) != 0)
166: goto out;
167:
168: /* compute shared secret */
169: switch (kex->kex_type) {
1.3 djm 170: #ifdef WITH_OPENSSL
1.1 djm 171: case KEX_DH_GRP1_SHA1:
172: case KEX_DH_GRP14_SHA1:
173: case KEX_DH_GRP14_SHA256:
174: case KEX_DH_GRP16_SHA512:
175: case KEX_DH_GRP18_SHA512:
176: r = kex_dh_dec(kex, server_blob, &shared_secret);
177: break;
178: case KEX_ECDH_SHA2:
179: r = kex_ecdh_dec(kex, server_blob, &shared_secret);
180: break;
1.3 djm 181: #endif /* WITH_OPENSSL */
1.1 djm 182: case KEX_C25519_SHA256:
183: r = kex_c25519_dec(kex, server_blob, &shared_secret);
184: break;
185: case KEX_KEM_SNTRUP4591761X25519_SHA512:
186: r = kex_kem_sntrup4591761x25519_dec(kex, server_blob,
187: &shared_secret);
188: break;
189: default:
190: r = SSH_ERR_INVALID_ARGUMENT;
191: break;
192: }
193: if (r !=0 )
194: goto out;
195:
196: /* calc and verify H */
197: hashlen = sizeof(hash);
198: if ((r = kex_gen_hash(
199: kex->hash_alg,
200: kex->client_version,
201: kex->server_version,
1.2 djm 202: kex->my,
203: kex->peer,
204: server_host_key_blob,
1.1 djm 205: kex->client_pub,
206: server_blob,
207: shared_secret,
208: hash, &hashlen)) != 0)
209: goto out;
210:
211: if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
1.4 ! djm 212: kex->hostkey_alg, ssh->compat, NULL)) != 0)
1.1 djm 213: goto out;
214:
215: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
216: r = kex_send_newkeys(ssh);
217: out:
218: explicit_bzero(hash, sizeof(hash));
219: explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
220: explicit_bzero(kex->sntrup4591761_client_key,
221: sizeof(kex->sntrup4591761_client_key));
1.2 djm 222: sshbuf_free(server_host_key_blob);
1.1 djm 223: free(signature);
1.2 djm 224: sshbuf_free(tmp);
1.1 djm 225: sshkey_free(server_host_key);
226: sshbuf_free(server_blob);
227: sshbuf_free(shared_secret);
228: sshbuf_free(kex->client_pub);
229: kex->client_pub = NULL;
230: return r;
231: }
232:
233: int
234: kex_gen_server(struct ssh *ssh)
235: {
236: debug("expecting SSH2_MSG_KEX_ECDH_INIT");
237: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
238: return 0;
239: }
240:
241: static int
242: input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
243: {
244: struct kex *kex = ssh->kex;
245: struct sshkey *server_host_private, *server_host_public;
246: struct sshbuf *shared_secret = NULL;
247: struct sshbuf *server_pubkey = NULL;
248: struct sshbuf *client_pubkey = NULL;
1.2 djm 249: struct sshbuf *server_host_key_blob = NULL;
250: u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
251: size_t slen, hashlen;
1.1 djm 252: int r;
253:
254: if ((r = kex_load_hostkey(ssh, &server_host_private,
255: &server_host_public)) != 0)
256: goto out;
257:
258: if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
259: (r = sshpkt_get_end(ssh)) != 0)
260: goto out;
261:
262: /* compute shared secret */
263: switch (kex->kex_type) {
1.3 djm 264: #ifdef WITH_OPENSSL
1.1 djm 265: case KEX_DH_GRP1_SHA1:
266: case KEX_DH_GRP14_SHA1:
267: case KEX_DH_GRP14_SHA256:
268: case KEX_DH_GRP16_SHA512:
269: case KEX_DH_GRP18_SHA512:
270: r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
271: &shared_secret);
272: break;
273: case KEX_ECDH_SHA2:
274: r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
275: &shared_secret);
276: break;
1.3 djm 277: #endif /* WITH_OPENSSL */
1.1 djm 278: case KEX_C25519_SHA256:
279: r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
280: &shared_secret);
281: break;
282: case KEX_KEM_SNTRUP4591761X25519_SHA512:
283: r = kex_kem_sntrup4591761x25519_enc(kex, client_pubkey,
284: &server_pubkey, &shared_secret);
285: break;
286: default:
287: r = SSH_ERR_INVALID_ARGUMENT;
288: break;
289: }
290: if (r !=0 )
291: goto out;
292:
293: /* calc H */
1.2 djm 294: if ((server_host_key_blob = sshbuf_new()) == NULL) {
295: r = SSH_ERR_ALLOC_FAIL;
296: goto out;
297: }
298: if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
1.1 djm 299: goto out;
300: hashlen = sizeof(hash);
301: if ((r = kex_gen_hash(
302: kex->hash_alg,
303: kex->client_version,
304: kex->server_version,
1.2 djm 305: kex->peer,
306: kex->my,
307: server_host_key_blob,
1.1 djm 308: client_pubkey,
309: server_pubkey,
310: shared_secret,
311: hash, &hashlen)) != 0)
312: goto out;
313:
314: /* sign H */
315: if ((r = kex->sign(ssh, server_host_private, server_host_public,
316: &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
317: goto out;
318:
319: /* send server hostkey, ECDH pubkey 'Q_S' and signed H */
320: if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
1.2 djm 321: (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
1.1 djm 322: (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
323: (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
324: (r = sshpkt_send(ssh)) != 0)
325: goto out;
326:
327: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
328: r = kex_send_newkeys(ssh);
329: out:
330: explicit_bzero(hash, sizeof(hash));
1.2 djm 331: sshbuf_free(server_host_key_blob);
1.1 djm 332: free(signature);
333: sshbuf_free(shared_secret);
334: sshbuf_free(client_pubkey);
335: sshbuf_free(server_pubkey);
336: return r;
337: }