Annotation of src/usr.bin/ssh/kexgen.c, Revision 1.8
1.8 ! djm 1: /* $OpenBSD: kexgen.c,v 1.7 2021/04/03 06:18:40 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:
1.8 ! djm 218: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
! 219: (r = kex_send_newkeys(ssh)) != 0)
! 220: goto out;
! 221:
! 222: /* save initial signature and hostkey */
! 223: if ((kex->flags & KEX_INITIAL) != 0) {
! 224: if (kex->initial_hostkey != NULL || kex->initial_sig != NULL) {
! 225: r = SSH_ERR_INTERNAL_ERROR;
! 226: goto out;
! 227: }
! 228: if ((kex->initial_sig = sshbuf_new()) == NULL) {
! 229: r = SSH_ERR_ALLOC_FAIL;
! 230: goto out;
! 231: }
! 232: if ((r = sshbuf_put(kex->initial_sig, signature, slen)) != 0)
! 233: goto out;
! 234: kex->initial_hostkey = server_host_key;
! 235: server_host_key = NULL;
! 236: }
! 237: /* success */
1.1 djm 238: out:
239: explicit_bzero(hash, sizeof(hash));
240: explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
1.5 djm 241: explicit_bzero(kex->sntrup761_client_key,
242: sizeof(kex->sntrup761_client_key));
1.2 djm 243: sshbuf_free(server_host_key_blob);
1.1 djm 244: free(signature);
1.2 djm 245: sshbuf_free(tmp);
1.1 djm 246: sshkey_free(server_host_key);
247: sshbuf_free(server_blob);
248: sshbuf_free(shared_secret);
249: sshbuf_free(kex->client_pub);
250: kex->client_pub = NULL;
251: return r;
252: }
253:
254: int
255: kex_gen_server(struct ssh *ssh)
256: {
257: debug("expecting SSH2_MSG_KEX_ECDH_INIT");
258: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
259: return 0;
260: }
261:
262: static int
263: input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
264: {
265: struct kex *kex = ssh->kex;
266: struct sshkey *server_host_private, *server_host_public;
267: struct sshbuf *shared_secret = NULL;
268: struct sshbuf *server_pubkey = NULL;
269: struct sshbuf *client_pubkey = NULL;
1.2 djm 270: struct sshbuf *server_host_key_blob = NULL;
271: u_char *signature = NULL, hash[SSH_DIGEST_MAX_LENGTH];
272: size_t slen, hashlen;
1.1 djm 273: int r;
1.6 djm 274:
275: debug("SSH2_MSG_KEX_ECDH_INIT received");
276: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
1.1 djm 277:
278: if ((r = kex_load_hostkey(ssh, &server_host_private,
279: &server_host_public)) != 0)
280: goto out;
281:
282: if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
283: (r = sshpkt_get_end(ssh)) != 0)
284: goto out;
285:
286: /* compute shared secret */
287: switch (kex->kex_type) {
1.3 djm 288: #ifdef WITH_OPENSSL
1.1 djm 289: case KEX_DH_GRP1_SHA1:
290: case KEX_DH_GRP14_SHA1:
291: case KEX_DH_GRP14_SHA256:
292: case KEX_DH_GRP16_SHA512:
293: case KEX_DH_GRP18_SHA512:
294: r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
295: &shared_secret);
296: break;
297: case KEX_ECDH_SHA2:
298: r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
299: &shared_secret);
300: break;
1.3 djm 301: #endif /* WITH_OPENSSL */
1.1 djm 302: case KEX_C25519_SHA256:
303: r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
304: &shared_secret);
305: break;
1.5 djm 306: case KEX_KEM_SNTRUP761X25519_SHA512:
307: r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
1.1 djm 308: &server_pubkey, &shared_secret);
309: break;
310: default:
311: r = SSH_ERR_INVALID_ARGUMENT;
312: break;
313: }
314: if (r !=0 )
315: goto out;
316:
317: /* calc H */
1.2 djm 318: if ((server_host_key_blob = sshbuf_new()) == NULL) {
319: r = SSH_ERR_ALLOC_FAIL;
320: goto out;
321: }
322: if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0)
1.1 djm 323: goto out;
324: hashlen = sizeof(hash);
325: if ((r = kex_gen_hash(
326: kex->hash_alg,
327: kex->client_version,
328: kex->server_version,
1.2 djm 329: kex->peer,
330: kex->my,
331: server_host_key_blob,
1.1 djm 332: client_pubkey,
333: server_pubkey,
334: shared_secret,
335: hash, &hashlen)) != 0)
336: goto out;
337:
338: /* sign H */
339: if ((r = kex->sign(ssh, server_host_private, server_host_public,
1.7 djm 340: &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
1.1 djm 341: goto out;
342:
343: /* send server hostkey, ECDH pubkey 'Q_S' and signed H */
344: if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
1.2 djm 345: (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 ||
1.1 djm 346: (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
347: (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
348: (r = sshpkt_send(ssh)) != 0)
349: goto out;
350:
1.8 ! djm 351: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) != 0 ||
! 352: (r = kex_send_newkeys(ssh)) != 0)
! 353: goto out;
! 354: /* retain copy of hostkey used at initial KEX */
! 355: if (kex->initial_hostkey == NULL &&
! 356: (r = sshkey_from_private(server_host_public,
! 357: &kex->initial_hostkey)) != 0)
! 358: goto out;
! 359: /* success */
1.1 djm 360: out:
361: explicit_bzero(hash, sizeof(hash));
1.2 djm 362: sshbuf_free(server_host_key_blob);
1.1 djm 363: free(signature);
364: sshbuf_free(shared_secret);
365: sshbuf_free(client_pubkey);
366: sshbuf_free(server_pubkey);
367: return r;
368: }