xref: /dragonfly/lib/libdmsg/crypto.c (revision df49ec1e)
1 /*
2  * Copyright (c) 2011-2012 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
6  * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
7  * by Alex Hornung <alexh@dragonflybsd.org>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  * 3. Neither the name of The DragonFly Project nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific, prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #include "dmsg_local.h"
38 
39 /*
40  * Setup crypto for pthreads
41  */
42 static pthread_mutex_t *crypto_locks;
43 int crypto_count;
44 
45 static int dmsg_crypto_gcm_init(dmsg_ioq_t *, char *, int, char *, int, int);
46 static int dmsg_crypto_gcm_encrypt_chunk(dmsg_ioq_t *, char *, char *, int, int *);
47 static int dmsg_crypto_gcm_decrypt_chunk(dmsg_ioq_t *, char *, char *, int, int *);
48 
49 /*
50  * NOTE: the order of this table needs to match the DMSG_CRYPTO_ALGO_*_IDX
51  *       defines in network.h.
52  */
53 static struct crypto_algo crypto_algos[] = {
54 	{
55 		.name      = "aes-256-gcm",
56 		.keylen    = DMSG_CRYPTO_GCM_KEY_SIZE,
57 		.taglen    = DMSG_CRYPTO_GCM_TAG_SIZE,
58 		.init      = dmsg_crypto_gcm_init,
59 		.enc_chunk = dmsg_crypto_gcm_encrypt_chunk,
60 		.dec_chunk = dmsg_crypto_gcm_decrypt_chunk
61 	},
62 	{ NULL, 0, 0, NULL, NULL, NULL }
63 };
64 
65 static
66 unsigned long
67 dmsg_crypto_id_callback(void)
68 {
69 	return ((unsigned long)(uintptr_t)pthread_self());
70 }
71 
72 static
73 void
74 dmsg_crypto_locking_callback(int mode, int type,
75 				const char *file __unused, int line __unused)
76 {
77 	assert(type >= 0 && type < crypto_count);
78 	if (mode & CRYPTO_LOCK) {
79 		pthread_mutex_lock(&crypto_locks[type]);
80 	} else {
81 		pthread_mutex_unlock(&crypto_locks[type]);
82 	}
83 }
84 
85 void
86 dmsg_crypto_setup(void)
87 {
88 	crypto_count = CRYPTO_num_locks();
89 	crypto_locks = calloc(crypto_count, sizeof(crypto_locks[0]));
90 	CRYPTO_set_id_callback(dmsg_crypto_id_callback);
91 	CRYPTO_set_locking_callback(dmsg_crypto_locking_callback);
92 }
93 
94 static
95 int
96 dmsg_crypto_gcm_init(dmsg_ioq_t *ioq, char *key, int klen,
97 			char *iv_fixed, int ivlen, int enc)
98 {
99 	int i, ok;
100 
101 	if (klen < DMSG_CRYPTO_GCM_KEY_SIZE ||
102 	    ivlen < DMSG_CRYPTO_GCM_IV_FIXED_SIZE) {
103 		dm_printf(1, "%s\n", "Not enough key or iv material");
104 		return -1;
105 	}
106 
107 	dm_printf(6, "%s key: ", enc ? "Encryption" : "Decryption");
108 	for (i = 0; i < DMSG_CRYPTO_GCM_KEY_SIZE; ++i)
109 		dmx_printf(6, "%02x", (unsigned char)key[i]);
110 	dmx_printf(6, "%s\n", "");
111 
112 	dm_printf(6, "%s iv:  ", enc ? "Encryption" : "Decryption");
113 	for (i = 0; i < DMSG_CRYPTO_GCM_IV_FIXED_SIZE; ++i)
114 		dmx_printf(6, "%02x", (unsigned char)iv_fixed[i]);
115 	dmx_printf(6, "%s\n", " (fixed part only)");
116 
117 	EVP_CIPHER_CTX_init(&ioq->ctx);
118 
119 	if (enc)
120 		ok = EVP_EncryptInit_ex(&ioq->ctx, EVP_aes_256_gcm(), NULL,
121 					key, NULL);
122 	else
123 		ok = EVP_DecryptInit_ex(&ioq->ctx, EVP_aes_256_gcm(), NULL,
124 					key, NULL);
125 	if (!ok)
126 		goto fail;
127 
128 	/*
129 	 * According to the original Galois/Counter Mode of Operation (GCM)
130 	 * proposal, only IVs that are exactly 96 bits get used without any
131 	 * further processing. Other IV sizes cause the GHASH() operation
132 	 * to be applied to the IV, which is more costly.
133 	 *
134 	 * The NIST SP 800-38D also recommends using a 96 bit IV for the same
135 	 * reasons. We actually follow the deterministic construction
136 	 * recommended in NIST SP 800-38D with a 64 bit invocation field as an
137 	 * integer counter and a random, session-specific fixed field.
138 	 *
139 	 * This means that we can essentially use the same session key and
140 	 * IV fixed field for up to 2^64 invocations of the authenticated
141 	 * encryption or decryption.
142 	 *
143 	 * With a chunk size of 64 bytes, this adds up to 1 zettabyte of
144 	 * traffic.
145 	 */
146 	ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_IVLEN,
147 				 DMSG_CRYPTO_GCM_IV_SIZE, NULL);
148 	if (!ok)
149 		goto fail;
150 
151 	memset(ioq->iv, 0, DMSG_CRYPTO_GCM_IV_SIZE);
152 	memcpy(ioq->iv, iv_fixed, DMSG_CRYPTO_GCM_IV_FIXED_SIZE);
153 
154 	/*
155 	 * Strictly speaking, padding is irrelevant with a counter mode
156 	 * encryption.
157 	 *
158 	 * However, setting padding to 0, even if using a counter mode such
159 	 * as GCM, will cause an error in _finish if the pt/ct size is not
160 	 * a multiple of the cipher block size.
161 	 */
162 	EVP_CIPHER_CTX_set_padding(&ioq->ctx, 0);
163 
164 	return 0;
165 
166 fail:
167 	dm_printf(1, "%s\n", "Error during _gcm_init");
168 	return -1;
169 }
170 
171 static
172 int
173 _gcm_iv_increment(char *iv)
174 {
175 	/*
176 	 * Deterministic construction according to NIST SP 800-38D, with
177 	 * 64 bit invocation field as integer counter.
178 	 *
179 	 * In other words, our 96 bit IV consists of a 32 bit fixed field
180 	 * unique to the session and a 64 bit integer counter.
181 	 */
182 
183 	uint64_t *c = (uint64_t *)(&iv[DMSG_CRYPTO_GCM_IV_FIXED_SIZE]);
184 
185 	/* Increment invocation field integer counter */
186 	*c = htobe64(be64toh(*c)+1);
187 
188 	/*
189 	 * Detect wrap-around, which means it is time to renegotiate
190 	 * the session to get a new key and/or fixed field.
191 	 */
192 	return (*c == 0) ? 0 : 1;
193 }
194 
195 static
196 int
197 dmsg_crypto_gcm_encrypt_chunk(dmsg_ioq_t *ioq, char *ct, char *pt,
198 				 int in_size, int *out_size)
199 {
200 	int ok;
201 	int u_len, f_len;
202 
203 	*out_size = 0;
204 
205 	/* Re-initialize with new IV (but without redoing the key schedule) */
206 	ok = EVP_EncryptInit_ex(&ioq->ctx, NULL, NULL, NULL, ioq->iv);
207 	if (!ok)
208 		goto fail;
209 
210 	u_len = 0;	/* safety */
211 	ok = EVP_EncryptUpdate(&ioq->ctx, ct, &u_len, pt, in_size);
212 	if (!ok)
213 		goto fail;
214 
215 	f_len = 0;	/* safety */
216 	ok = EVP_EncryptFinal_ex(&ioq->ctx, ct + u_len, &f_len);
217 	if (!ok)
218 		goto fail;
219 
220 	/* Retrieve auth tag */
221 	ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_GET_TAG,
222 				 DMSG_CRYPTO_GCM_TAG_SIZE,
223 				 ct + u_len + f_len);
224 	if (!ok)
225 		goto fail;
226 
227 	ok = _gcm_iv_increment(ioq->iv);
228 	if (!ok) {
229 		ioq->error = DMSG_IOQ_ERROR_IVWRAP;
230 		goto fail_out;
231 	}
232 
233 	*out_size = u_len + f_len + DMSG_CRYPTO_GCM_TAG_SIZE;
234 	EVP_CIPHER_CTX_reset(&ioq->ctx);
235 
236 	return 0;
237 
238 fail:
239 	ioq->error = DMSG_IOQ_ERROR_ALGO;
240 fail_out:
241 	EVP_CIPHER_CTX_reset(&ioq->ctx);
242 	dm_printf(1, "%s\n", "error during encrypt_chunk");
243 	return -1;
244 }
245 
246 static
247 int
248 dmsg_crypto_gcm_decrypt_chunk(dmsg_ioq_t *ioq, char *ct, char *pt,
249 				 int out_size, int *consume_size)
250 {
251 	int ok;
252 	int u_len, f_len;
253 
254 	*consume_size = 0;
255 
256 	/* Re-initialize with new IV (but without redoing the key schedule) */
257 	ok = EVP_DecryptInit_ex(&ioq->ctx, NULL, NULL, NULL, ioq->iv);
258 	if (!ok) {
259 		ioq->error = DMSG_IOQ_ERROR_ALGO;
260 		goto fail_out;
261 	}
262 
263 	ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_TAG,
264 				 DMSG_CRYPTO_GCM_TAG_SIZE,
265 				 ct + out_size);
266 	if (!ok) {
267 		ioq->error = DMSG_IOQ_ERROR_ALGO;
268 		goto fail_out;
269 	}
270 
271 	ok = EVP_DecryptUpdate(&ioq->ctx, pt, &u_len, ct, out_size);
272 	if (!ok)
273 		goto fail;
274 
275 	ok = EVP_DecryptFinal_ex(&ioq->ctx, pt + u_len, &f_len);
276 	if (!ok)
277 		goto fail;
278 
279 	ok = _gcm_iv_increment(ioq->iv);
280 	if (!ok) {
281 		ioq->error = DMSG_IOQ_ERROR_IVWRAP;
282 		goto fail_out;
283 	}
284 
285 	*consume_size = u_len + f_len + DMSG_CRYPTO_GCM_TAG_SIZE;
286 	EVP_CIPHER_CTX_reset(&ioq->ctx);
287 
288 	return 0;
289 
290 fail:
291 	ioq->error = DMSG_IOQ_ERROR_MACFAIL;
292 fail_out:
293 	EVP_CIPHER_CTX_reset(&ioq->ctx);
294 	dm_printf(1, "%s\n",
295 		  "error during decrypt_chunk "
296 		  "(likely authentication error)");
297 	return -1;
298 }
299 
300 /*
301  * Synchronously negotiate crypto for a new session.  This must occur
302  * within 10 seconds or the connection is error'd out.
303  *
304  * We work off the IP address and/or reverse DNS.  The IP address is
305  * checked first, followed by the IP address at various levels of granularity,
306  * followed by the full domain name and domain names at various levels of
307  * granularity.
308  *
309  *	/etc/hammer2/remote/<name>.pub	- Contains a public key
310  *	/etc/hammer2/remote/<name>.none	- Indicates no encryption (empty file)
311  *					  (e.g. localhost.none).
312  *
313  * We first attempt to locate a public key file based on the peer address or
314  * peer FQDN.
315  *
316  *	<name>.none	- No further negotiation is needed.  We simply return.
317  *			  All communication proceeds without encryption.
318  *			  No public key handshake occurs in this situation.
319  *			  (both ends must match).
320  *
321  *	<name>.pub	- We have located the public key for the peer.  Both
322  *			  sides transmit a block encrypted with their private
323  *			  keys and the peer's public key.
324  *
325  *			  Both sides receive a block and decrypt it.
326  *
327  *			  Both sides formulate a reply using the decrypted
328  *			  block and transmit it.
329  *
330  *			  communication proceeds with the negotiated session
331  *			  key (typically AES-256-CBC).
332  *
333  * If we fail to locate the appropriate file and no floating.db exists the
334  * connection is terminated without further action.
335  *
336  * If floating.db exists the connection proceeds with a floating negotiation.
337  */
338 typedef union {
339 	struct sockaddr sa;
340 	struct sockaddr_in sa_in;
341 	struct sockaddr_in6 sa_in6;
342 } sockaddr_any_t;
343 
344 void
345 dmsg_crypto_negotiate(dmsg_iocom_t *iocom)
346 {
347 	sockaddr_any_t sa;
348 	socklen_t salen = sizeof(sa);
349 	char peername[128];
350 	char realname[128];
351 	dmsg_handshake_t handtx;
352 	dmsg_handshake_t handrx;
353 	char buf1[sizeof(handtx)];
354 	char buf2[sizeof(handtx)];
355 	char *ptr;
356 	char *path;
357 	struct stat st;
358 	FILE *fp;
359 	RSA *keys[3] = { NULL, NULL, NULL };
360 	size_t i;
361 	size_t blksize;
362 	size_t blkmask;
363 	ssize_t n;
364 	int fd;
365 	int error;
366 
367 	/*
368 	 * Get the peer IP address for the connection as a string.
369 	 */
370 	if (getpeername(iocom->sock_fd, &sa.sa, &salen) < 0) {
371 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOPEER;
372 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
373 		dm_printf(1, "%s\n", "accept: getpeername() failed");
374 		goto done;
375 	}
376 	if (getnameinfo(&sa.sa, salen, peername, sizeof(peername),
377 			NULL, 0, NI_NUMERICHOST) < 0) {
378 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOPEER;
379 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
380 		dm_printf(1, "%s\n", "accept: cannot decode sockaddr");
381 		goto done;
382 	}
383 	if (DMsgDebugOpt) {
384 		if (realhostname_sa(realname, sizeof(realname),
385 				    &sa.sa, salen) == HOSTNAME_FOUND) {
386 			dm_printf(1, "accept from %s (%s)\n",
387 				  peername, realname);
388 		} else {
389 			dm_printf(1, "accept from %s\n", peername);
390 		}
391 	}
392 
393 	/*
394 	 * Find the remote host's public key
395 	 *
396 	 * If the link is not to be encrypted (<ip>.none located) we shortcut
397 	 * the handshake entirely.  No buffers are exchanged.
398 	 */
399 	asprintf(&path, "%s/%s.pub", DMSG_PATH_REMOTE, peername);
400 	if ((fp = fopen(path, "r")) == NULL) {
401 		free(path);
402 		asprintf(&path, "%s/%s.none",
403 			 DMSG_PATH_REMOTE, peername);
404 		if (stat(path, &st) < 0) {
405 			iocom->ioq_rx.error = DMSG_IOQ_ERROR_NORKEY;
406 			atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
407 			dm_printf(1, "%s\n", "auth failure: unknown host");
408 			goto done;
409 		}
410 		dm_printf(1, "%s\n", "auth succeeded, unencrypted link");
411 		goto done;
412 	}
413 	if (fp) {
414 		keys[0] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
415 		fclose(fp);
416 		if (keys[0] == NULL) {
417 			iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
418 			atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
419 			dm_printf(1, "%s\n", "auth failure: bad key format");
420 			goto done;
421 		}
422 	}
423 
424 	/*
425 	 * Get our public and private keys
426 	 */
427 	free(path);
428 	asprintf(&path, DMSG_DEFAULT_DIR "/rsa.pub");
429 	if ((fp = fopen(path, "r")) == NULL) {
430 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOLKEY;
431 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
432 		goto done;
433 	}
434 	keys[1] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
435 	fclose(fp);
436 	if (keys[1] == NULL) {
437 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
438 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
439 		dm_printf(1, "%s\n", "auth failure: bad host key format");
440 		goto done;
441 	}
442 
443 	free(path);
444 	asprintf(&path, DMSG_DEFAULT_DIR "/rsa.prv");
445 	if ((fp = fopen(path, "r")) == NULL) {
446 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOLKEY;
447 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
448 		dm_printf(1, "%s\n", "auth failure: bad host key format");
449 		goto done;
450 	}
451 	keys[2] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
452 	fclose(fp);
453 	if (keys[2] == NULL) {
454 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
455 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
456 		dm_printf(1, "%s\n", "auth failure: bad host key format");
457 		goto done;
458 	}
459 	free(path);
460 	path = NULL;
461 
462 	/*
463 	 * public key encrypt/decrypt block size.
464 	 */
465 	if (keys[0]) {
466 		blksize = (size_t)RSA_size(keys[0]);
467 		if (blksize != (size_t)RSA_size(keys[1]) ||
468 		    blksize != (size_t)RSA_size(keys[2]) ||
469 		    sizeof(handtx) % blksize != 0) {
470 			iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
471 			atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
472 			dm_printf(1, "%s\n",
473 				  "auth failure: key size mismatch");
474 			goto done;
475 		}
476 	} else {
477 		blksize = sizeof(handtx);
478 	}
479 	blkmask = blksize - 1;
480 
481 	bzero(&handrx, sizeof(handrx));
482 	bzero(&handtx, sizeof(handtx));
483 
484 	/*
485 	 * Fill all unused fields (particular all junk fields) with random
486 	 * data, and also set the session key.
487 	 */
488 	fd = open("/dev/urandom", O_RDONLY);
489 	if (fd < 0 ||
490 	    fstat(fd, &st) < 0 ||	/* something wrong */
491 	    S_ISREG(st.st_mode) ||	/* supposed to be a RNG dev! */
492 	    read(fd, &handtx, sizeof(handtx)) != sizeof(handtx)) {
493 urandfail:
494 		if (fd >= 0)
495 			close(fd);
496 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_BADURANDOM;
497 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
498 		dm_printf(1, "%s\n", "auth failure: bad rng");
499 		goto done;
500 	}
501 	if (bcmp(&handrx, &handtx, sizeof(handtx)) == 0)
502 		goto urandfail;			/* read all zeros */
503 	close(fd);
504 	/* ERR_load_crypto_strings(); openssl debugging */
505 
506 	/*
507 	 * Handshake with the remote.
508 	 *
509 	 *	Encrypt with my private and remote's public
510 	 *	Decrypt with my private and remote's public
511 	 *
512 	 * When encrypting we have to make sure our buffer fits within the
513 	 * modulus, which typically requires bit 7 o the first byte to be
514 	 * zero.  To be safe make sure that bit 7 and bit 6 is zero.
515 	 */
516 	snprintf(handtx.quickmsg, sizeof(handtx.quickmsg), "Testing 1 2 3");
517 	handtx.magic = DMSG_HDR_MAGIC;
518 	handtx.version = 1;
519 	handtx.flags = 0;
520 	assert(sizeof(handtx.verf) * 4 == sizeof(handtx.sess));
521 	bzero(handtx.verf, sizeof(handtx.verf));
522 
523 	handtx.pad1[0] &= 0x3f;	/* message must fit within modulus */
524 	handtx.pad2[0] &= 0x3f;	/* message must fit within modulus */
525 
526 	for (i = 0; i < sizeof(handtx.sess); ++i)
527 		handtx.verf[i / 4] ^= handtx.sess[i];
528 
529 	/*
530 	 * Write handshake buffer to remote
531 	 */
532 	for (i = 0; i < sizeof(handtx); i += blksize) {
533 		ptr = (char *)&handtx + i;
534 		if (keys[0]) {
535 			/*
536 			 * Since we are double-encrypting we have to make
537 			 * sure that the result of the first stage does
538 			 * not blow out the modulus for the second stage.
539 			 *
540 			 * The pointer is pointing to the pad*[] area so
541 			 * we can mess with that until the first stage
542 			 * is legal.
543 			 */
544 			do {
545 				++*(int *)(ptr + 4);
546 				if (RSA_private_encrypt(blksize, ptr, buf1,
547 					    keys[2], RSA_NO_PADDING) < 0) {
548 					iocom->ioq_rx.error =
549 						DMSG_IOQ_ERROR_KEYXCHGFAIL;
550 				}
551 			} while (buf1[0] & 0xC0);
552 
553 			if (RSA_public_encrypt(blksize, buf1, buf2,
554 					    keys[0], RSA_NO_PADDING) < 0) {
555 				iocom->ioq_rx.error =
556 					DMSG_IOQ_ERROR_KEYXCHGFAIL;
557 			}
558 		}
559 		if (write(iocom->sock_fd, buf2, blksize) != (ssize_t)blksize) {
560 			dmio_printf(iocom, 1, "%s\n", "WRITE ERROR");
561 		}
562 	}
563 	if (iocom->ioq_rx.error) {
564 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
565 		dmio_printf(iocom, 1, "%s\n",
566 			    "auth failure: key exchange failure "
567 			    "during encryption");
568 		goto done;
569 	}
570 
571 	/*
572 	 * Read handshake buffer from remote
573 	 */
574 	i = 0;
575 	while (i < sizeof(handrx)) {
576 		ptr = (char *)&handrx + i;
577 		n = read(iocom->sock_fd, ptr, blksize - (i & blkmask));
578 		if (n <= 0)
579 			break;
580 		ptr -= (i & blkmask);
581 		i += n;
582 		if (keys[0] && (i & blkmask) == 0) {
583 			if (RSA_private_decrypt(blksize, ptr, buf1,
584 					   keys[2], RSA_NO_PADDING) < 0)
585 				iocom->ioq_rx.error =
586 						DMSG_IOQ_ERROR_KEYXCHGFAIL;
587 			if (RSA_public_decrypt(blksize, buf1, ptr,
588 					   keys[0], RSA_NO_PADDING) < 0)
589 				iocom->ioq_rx.error =
590 						DMSG_IOQ_ERROR_KEYXCHGFAIL;
591 		}
592 	}
593 	if (iocom->ioq_rx.error) {
594 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
595 		dmio_printf(iocom, 1, "%s\n",
596 			    "auth failure: key exchange failure "
597 			    "during decryption");
598 		goto done;
599 	}
600 
601 	/*
602 	 * Validate the received data.  Try to make this a constant-time
603 	 * algorithm.
604 	 */
605 	if (i != sizeof(handrx)) {
606 keyxchgfail:
607 		iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYXCHGFAIL;
608 		atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
609 		dmio_printf(iocom, 1, "%s\n",
610 			    "auth failure: key exchange failure");
611 		goto done;
612 	}
613 
614 	if (handrx.magic == DMSG_HDR_MAGIC_REV) {
615 		handrx.version = bswap16(handrx.version);
616 		handrx.flags = bswap32(handrx.flags);
617 	}
618 	for (i = 0; i < sizeof(handrx.sess); ++i)
619 		handrx.verf[i / 4] ^= handrx.sess[i];
620 	n = 0;
621 	for (i = 0; i < sizeof(handrx.verf); ++i)
622 		n += handrx.verf[i];
623 	if (handrx.version != 1)
624 		++n;
625 	if (n != 0)
626 		goto keyxchgfail;
627 
628 	/*
629 	 * Use separate session keys and session fixed IVs for receive and
630 	 * transmit.
631 	 */
632 	error = crypto_algos[DMSG_CRYPTO_ALGO].init(&iocom->ioq_rx,
633 	    (char*)handrx.sess,
634 	    crypto_algos[DMSG_CRYPTO_ALGO].keylen,
635 	    (char*)handrx.sess + crypto_algos[DMSG_CRYPTO_ALGO].keylen,
636 	    sizeof(handrx.sess) - crypto_algos[DMSG_CRYPTO_ALGO].keylen,
637 	    0 /* decryption */);
638 	if (error)
639 		goto keyxchgfail;
640 
641 	error = crypto_algos[DMSG_CRYPTO_ALGO].init(&iocom->ioq_tx,
642 	    (char*)handtx.sess,
643 	    crypto_algos[DMSG_CRYPTO_ALGO].keylen,
644 	    (char*)handtx.sess + crypto_algos[DMSG_CRYPTO_ALGO].keylen,
645 	    sizeof(handtx.sess) - crypto_algos[DMSG_CRYPTO_ALGO].keylen,
646 	    1 /* encryption */);
647 	if (error)
648 		goto keyxchgfail;
649 
650 	atomic_set_int(&iocom->flags, DMSG_IOCOMF_CRYPTED);
651 
652 	dmio_printf(iocom, 1, "auth success: %s\n", handrx.quickmsg);
653 done:
654 	if (path)
655 		free(path);
656 	if (keys[0])
657 		RSA_free(keys[0]);
658 	if (keys[1])
659 		RSA_free(keys[1]);
660 	if (keys[1])
661 		RSA_free(keys[2]);
662 }
663 
664 /*
665  * Decrypt pending data in the ioq's fifo.  The data is decrypted in-place.
666  */
667 void
668 dmsg_crypto_decrypt(dmsg_iocom_t *iocom __unused, dmsg_ioq_t *ioq)
669 {
670 	int p_len;
671 	int used;
672 	__unused int error;	/* XXX */
673 	char buf[512];
674 
675 	/*
676 	 * fifo_beg to fifo_cdx is data already decrypted.
677 	 * fifo_cdn to fifo_end is data not yet decrypted.
678 	 */
679 	p_len = ioq->fifo_end - ioq->fifo_cdn; /* data not yet decrypted */
680 
681 	if (p_len == 0)
682 		return;
683 
684 	while (p_len >= crypto_algos[DMSG_CRYPTO_ALGO].taglen +
685 	    DMSG_CRYPTO_CHUNK_SIZE) {
686 		bcopy(ioq->buf + ioq->fifo_cdn, buf,
687 		      crypto_algos[DMSG_CRYPTO_ALGO].taglen +
688 		      DMSG_CRYPTO_CHUNK_SIZE);
689 		error = crypto_algos[DMSG_CRYPTO_ALGO].dec_chunk(
690 		    ioq, buf,
691 		    ioq->buf + ioq->fifo_cdx,
692 		    DMSG_CRYPTO_CHUNK_SIZE,
693 		    &used);
694 #ifdef CRYPTO_DEBUG
695 		dmio_printf(iocom, 5,
696 			    "dec: p_len: %d, used: %d, "
697 			    "fifo_cdn: %ju, fifo_cdx: %ju\n",
698 			     p_len, used,
699 			     ioq->fifo_cdn, ioq->fifo_cdx);
700 #endif
701 		p_len -= used;
702 		ioq->fifo_cdn += used;
703 		ioq->fifo_cdx += DMSG_CRYPTO_CHUNK_SIZE;
704 #ifdef CRYPTO_DEBUG
705 		dmio_printf(iocom, 5,
706 			    "dec: p_len: %d, used: %d, "
707 			    "fifo_cdn: %ju, fifo_cdx: %ju\n",
708 			    p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
709 #endif
710 	}
711 }
712 
713 /*
714  * *nactp is set to the number of ORIGINAL bytes consumed by the encrypter.
715  * The FIFO may contain more data.
716  */
717 int
718 dmsg_crypto_encrypt(dmsg_iocom_t *iocom __unused, dmsg_ioq_t *ioq,
719 		    struct iovec *iov, int n, size_t *nactp)
720 {
721 	int p_len, used, ct_used;
722 	int i;
723 	__unused int error;	/* XXX */
724 	size_t nmax;
725 
726 	nmax = sizeof(ioq->buf) - ioq->fifo_end;	/* max new bytes */
727 
728 	*nactp = 0;
729 	for (i = 0; i < n && nmax; ++i) {
730 		used = 0;
731 		p_len = iov[i].iov_len;
732 		assert((p_len & DMSG_ALIGNMASK) == 0);
733 
734 		while (p_len >= DMSG_CRYPTO_CHUNK_SIZE &&
735 		    nmax >= DMSG_CRYPTO_CHUNK_SIZE +
736 		    (size_t)crypto_algos[DMSG_CRYPTO_ALGO].taglen) {
737 			error = crypto_algos[DMSG_CRYPTO_ALGO].enc_chunk(
738 			    ioq,
739 			    ioq->buf + ioq->fifo_cdx,
740 			    (char *)iov[i].iov_base + used,
741 			    DMSG_CRYPTO_CHUNK_SIZE, &ct_used);
742 #ifdef CRYPTO_DEBUG
743 			dmio_printf(iocom, 5,
744 				    "nactp: %ju, p_len: %d, "
745 				    "ct_used: %d, used: %d, nmax: %ju\n",
746 				    *nactp, p_len, ct_used, used, nmax);
747 #endif
748 
749 			*nactp += (size_t)DMSG_CRYPTO_CHUNK_SIZE;	/* plaintext count */
750 			used += DMSG_CRYPTO_CHUNK_SIZE;
751 			p_len -= DMSG_CRYPTO_CHUNK_SIZE;
752 
753 			/*
754 			 * NOTE: crypted count will eventually differ from
755 			 *	 nmax, but for now we have not yet introduced
756 			 *	 random armor.
757 			 */
758 			ioq->fifo_cdx += (size_t)ct_used;
759 			ioq->fifo_cdn += (size_t)ct_used;
760 			ioq->fifo_end += (size_t)ct_used;
761 			nmax -= (size_t)ct_used;
762 #ifdef CRYPTO_DEBUG
763 			dmio_printf(iocom, 5,
764 				    "nactp: %ju, p_len: %d, "
765 				    "ct_used: %d, used: %d, nmax: %ju\n",
766 				    *nactp, p_len, ct_used, used, nmax);
767 #endif
768 		}
769 	}
770 	iov[0].iov_base = ioq->buf + ioq->fifo_beg;
771 	iov[0].iov_len = ioq->fifo_cdx - ioq->fifo_beg;
772 
773 	return (1);
774 }
775