lib/libdmsg: Fix compile-time warning on Linux
[dragonfly.git] / lib / libdmsg / crypto.c
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(&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
235         return 0;
236
237 fail:
238         ioq->error = DMSG_IOQ_ERROR_ALGO;
239 fail_out:
240         dm_printf(1, "%s\n", "error during encrypt_chunk");
241         return -1;
242 }
243
244 static
245 int
246 dmsg_crypto_gcm_decrypt_chunk(dmsg_ioq_t *ioq, char *ct, char *pt,
247                                  int out_size, int *consume_size)
248 {
249         int ok;
250         int u_len, f_len;
251
252         *consume_size = 0;
253
254         /* Re-initialize with new IV (but without redoing the key schedule) */
255         ok = EVP_DecryptInit_ex(&ioq->ctx, NULL, NULL, NULL, ioq->iv);
256         if (!ok) {
257                 ioq->error = DMSG_IOQ_ERROR_ALGO;
258                 goto fail_out;
259         }
260
261         ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_TAG,
262                                  DMSG_CRYPTO_GCM_TAG_SIZE,
263                                  ct + out_size);
264         if (!ok) {
265                 ioq->error = DMSG_IOQ_ERROR_ALGO;
266                 goto fail_out;
267         }
268
269         ok = EVP_DecryptUpdate(&ioq->ctx, pt, &u_len, ct, out_size);
270         if (!ok)
271                 goto fail;
272
273         ok = EVP_DecryptFinal(&ioq->ctx, pt + u_len, &f_len);
274         if (!ok)
275                 goto fail;
276
277         ok = _gcm_iv_increment(ioq->iv);
278         if (!ok) {
279                 ioq->error = DMSG_IOQ_ERROR_IVWRAP;
280                 goto fail_out;
281         }
282
283         *consume_size = u_len + f_len + DMSG_CRYPTO_GCM_TAG_SIZE;
284
285         return 0;
286
287 fail:
288         ioq->error = DMSG_IOQ_ERROR_MACFAIL;
289 fail_out:
290         dm_printf(1, "%s\n",
291                   "error during decrypt_chunk "
292                   "(likely authentication error)");
293         return -1;
294 }
295
296 /*
297  * Synchronously negotiate crypto for a new session.  This must occur
298  * within 10 seconds or the connection is error'd out.
299  *
300  * We work off the IP address and/or reverse DNS.  The IP address is
301  * checked first, followed by the IP address at various levels of granularity,
302  * followed by the full domain name and domain names at various levels of
303  * granularity.
304  *
305  *      /etc/hammer2/remote/<name>.pub  - Contains a public key
306  *      /etc/hammer2/remote/<name>.none - Indicates no encryption (empty file)
307  *                                        (e.g. localhost.none).
308  *
309  * We first attempt to locate a public key file based on the peer address or
310  * peer FQDN.
311  *
312  *      <name>.none     - No further negotiation is needed.  We simply return.
313  *                        All communication proceeds without encryption.
314  *                        No public key handshake occurs in this situation.
315  *                        (both ends must match).
316  *
317  *      <name>.pub      - We have located the public key for the peer.  Both
318  *                        sides transmit a block encrypted with their private
319  *                        keys and the peer's public key.
320  *
321  *                        Both sides receive a block and decrypt it.
322  *
323  *                        Both sides formulate a reply using the decrypted
324  *                        block and transmit it.
325  *
326  *                        communication proceeds with the negotiated session
327  *                        key (typically AES-256-CBC).
328  *
329  * If we fail to locate the appropriate file and no floating.db exists the
330  * connection is terminated without further action.
331  *
332  * If floating.db exists the connection proceeds with a floating negotiation.
333  */
334 typedef union {
335         struct sockaddr sa;
336         struct sockaddr_in sa_in;
337         struct sockaddr_in6 sa_in6;
338 } sockaddr_any_t;
339
340 void
341 dmsg_crypto_negotiate(dmsg_iocom_t *iocom)
342 {
343         sockaddr_any_t sa;
344         socklen_t salen = sizeof(sa);
345         char peername[128];
346         char realname[128];
347         dmsg_handshake_t handtx;
348         dmsg_handshake_t handrx;
349         char buf1[sizeof(handtx)];
350         char buf2[sizeof(handtx)];
351         char *ptr;
352         char *path;
353         struct stat st;
354         FILE *fp;
355         RSA *keys[3] = { NULL, NULL, NULL };
356         size_t i;
357         size_t blksize;
358         size_t blkmask;
359         ssize_t n;
360         int fd;
361         int error;
362
363         /*
364          * Get the peer IP address for the connection as a string.
365          */
366         if (getpeername(iocom->sock_fd, &sa.sa, &salen) < 0) {
367                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOPEER;
368                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
369                 dm_printf(1, "%s\n", "accept: getpeername() failed");
370                 goto done;
371         }
372         if (getnameinfo(&sa.sa, salen, peername, sizeof(peername),
373                         NULL, 0, NI_NUMERICHOST) < 0) {
374                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOPEER;
375                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
376                 dm_printf(1, "%s\n", "accept: cannot decode sockaddr");
377                 goto done;
378         }
379         if (DMsgDebugOpt) {
380                 if (realhostname_sa(realname, sizeof(realname),
381                                     &sa.sa, salen) == HOSTNAME_FOUND) {
382                         dm_printf(1, "accept from %s (%s)\n",
383                                   peername, realname);
384                 } else {
385                         dm_printf(1, "accept from %s\n", peername);
386                 }
387         }
388
389         /*
390          * Find the remote host's public key
391          *
392          * If the link is not to be encrypted (<ip>.none located) we shortcut
393          * the handshake entirely.  No buffers are exchanged.
394          */
395         asprintf(&path, "%s/%s.pub", DMSG_PATH_REMOTE, peername);
396         if ((fp = fopen(path, "r")) == NULL) {
397                 free(path);
398                 asprintf(&path, "%s/%s.none",
399                          DMSG_PATH_REMOTE, peername);
400                 if (stat(path, &st) < 0) {
401                         iocom->ioq_rx.error = DMSG_IOQ_ERROR_NORKEY;
402                         atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
403                         dm_printf(1, "%s\n", "auth failure: unknown host");
404                         goto done;
405                 }
406                 dm_printf(1, "%s\n", "auth succeeded, unencrypted link");
407                 goto done;
408         }
409         if (fp) {
410                 keys[0] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
411                 fclose(fp);
412                 if (keys[0] == NULL) {
413                         iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
414                         atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
415                         dm_printf(1, "%s\n", "auth failure: bad key format");
416                         goto done;
417                 }
418         }
419
420         /*
421          * Get our public and private keys
422          */
423         free(path);
424         asprintf(&path, DMSG_DEFAULT_DIR "/rsa.pub");
425         if ((fp = fopen(path, "r")) == NULL) {
426                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOLKEY;
427                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
428                 goto done;
429         }
430         keys[1] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
431         fclose(fp);
432         if (keys[1] == NULL) {
433                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
434                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
435                 dm_printf(1, "%s\n", "auth failure: bad host key format");
436                 goto done;
437         }
438
439         free(path);
440         asprintf(&path, DMSG_DEFAULT_DIR "/rsa.prv");
441         if ((fp = fopen(path, "r")) == NULL) {
442                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOLKEY;
443                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
444                 dm_printf(1, "%s\n", "auth failure: bad host key format");
445                 goto done;
446         }
447         keys[2] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
448         fclose(fp);
449         if (keys[2] == NULL) {
450                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
451                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
452                 dm_printf(1, "%s\n", "auth failure: bad host key format");
453                 goto done;
454         }
455         free(path);
456         path = NULL;
457
458         /*
459          * public key encrypt/decrypt block size.
460          */
461         if (keys[0]) {
462                 blksize = (size_t)RSA_size(keys[0]);
463                 if (blksize != (size_t)RSA_size(keys[1]) ||
464                     blksize != (size_t)RSA_size(keys[2]) ||
465                     sizeof(handtx) % blksize != 0) {
466                         iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
467                         atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
468                         dm_printf(1, "%s\n",
469                                   "auth failure: key size mismatch");
470                         goto done;
471                 }
472         } else {
473                 blksize = sizeof(handtx);
474         }
475         blkmask = blksize - 1;
476
477         bzero(&handrx, sizeof(handrx));
478         bzero(&handtx, sizeof(handtx));
479
480         /*
481          * Fill all unused fields (particular all junk fields) with random
482          * data, and also set the session key.
483          */
484         fd = open("/dev/urandom", O_RDONLY);
485         if (fd < 0 ||
486             fstat(fd, &st) < 0 ||       /* something wrong */
487             S_ISREG(st.st_mode) ||      /* supposed to be a RNG dev! */
488             read(fd, &handtx, sizeof(handtx)) != sizeof(handtx)) {
489 urandfail:
490                 if (fd >= 0)
491                         close(fd);
492                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_BADURANDOM;
493                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
494                 dm_printf(1, "%s\n", "auth failure: bad rng");
495                 goto done;
496         }
497         if (bcmp(&handrx, &handtx, sizeof(handtx)) == 0)
498                 goto urandfail;                 /* read all zeros */
499         close(fd);
500         /* ERR_load_crypto_strings(); openssl debugging */
501
502         /*
503          * Handshake with the remote.
504          *
505          *      Encrypt with my private and remote's public
506          *      Decrypt with my private and remote's public
507          *
508          * When encrypting we have to make sure our buffer fits within the
509          * modulus, which typically requires bit 7 o the first byte to be
510          * zero.  To be safe make sure that bit 7 and bit 6 is zero.
511          */
512         snprintf(handtx.quickmsg, sizeof(handtx.quickmsg), "Testing 1 2 3");
513         handtx.magic = DMSG_HDR_MAGIC;
514         handtx.version = 1;
515         handtx.flags = 0;
516         assert(sizeof(handtx.verf) * 4 == sizeof(handtx.sess));
517         bzero(handtx.verf, sizeof(handtx.verf));
518
519         handtx.pad1[0] &= 0x3f; /* message must fit within modulus */
520         handtx.pad2[0] &= 0x3f; /* message must fit within modulus */
521
522         for (i = 0; i < sizeof(handtx.sess); ++i)
523                 handtx.verf[i / 4] ^= handtx.sess[i];
524
525         /*
526          * Write handshake buffer to remote
527          */
528         for (i = 0; i < sizeof(handtx); i += blksize) {
529                 ptr = (char *)&handtx + i;
530                 if (keys[0]) {
531                         /*
532                          * Since we are double-encrypting we have to make
533                          * sure that the result of the first stage does
534                          * not blow out the modulus for the second stage.
535                          *
536                          * The pointer is pointing to the pad*[] area so
537                          * we can mess with that until the first stage
538                          * is legal.
539                          */
540                         do {
541                                 ++*(int *)(ptr + 4);
542                                 if (RSA_private_encrypt(blksize, ptr, buf1,
543                                             keys[2], RSA_NO_PADDING) < 0) {
544                                         iocom->ioq_rx.error =
545                                                 DMSG_IOQ_ERROR_KEYXCHGFAIL;
546                                 }
547                         } while (buf1[0] & 0xC0);
548
549                         if (RSA_public_encrypt(blksize, buf1, buf2,
550                                             keys[0], RSA_NO_PADDING) < 0) {
551                                 iocom->ioq_rx.error =
552                                         DMSG_IOQ_ERROR_KEYXCHGFAIL;
553                         }
554                 }
555                 if (write(iocom->sock_fd, buf2, blksize) != (ssize_t)blksize) {
556                         dmio_printf(iocom, 1, "%s\n", "WRITE ERROR");
557                 }
558         }
559         if (iocom->ioq_rx.error) {
560                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
561                 dmio_printf(iocom, 1, "%s\n",
562                             "auth failure: key exchange failure "
563                             "during encryption");
564                 goto done;
565         }
566
567         /*
568          * Read handshake buffer from remote
569          */
570         i = 0;
571         while (i < sizeof(handrx)) {
572                 ptr = (char *)&handrx + i;
573                 n = read(iocom->sock_fd, ptr, blksize - (i & blkmask));
574                 if (n <= 0)
575                         break;
576                 ptr -= (i & blkmask);
577                 i += n;
578                 if (keys[0] && (i & blkmask) == 0) {
579                         if (RSA_private_decrypt(blksize, ptr, buf1,
580                                            keys[2], RSA_NO_PADDING) < 0)
581                                 iocom->ioq_rx.error =
582                                                 DMSG_IOQ_ERROR_KEYXCHGFAIL;
583                         if (RSA_public_decrypt(blksize, buf1, ptr,
584                                            keys[0], RSA_NO_PADDING) < 0)
585                                 iocom->ioq_rx.error =
586                                                 DMSG_IOQ_ERROR_KEYXCHGFAIL;
587                 }
588         }
589         if (iocom->ioq_rx.error) {
590                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
591                 dmio_printf(iocom, 1, "%s\n",
592                             "auth failure: key exchange failure "
593                             "during decryption");
594                 goto done;
595         }
596
597         /*
598          * Validate the received data.  Try to make this a constant-time
599          * algorithm.
600          */
601         if (i != sizeof(handrx)) {
602 keyxchgfail:
603                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYXCHGFAIL;
604                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
605                 dmio_printf(iocom, 1, "%s\n",
606                             "auth failure: key exchange failure");
607                 goto done;
608         }
609
610         if (handrx.magic == DMSG_HDR_MAGIC_REV) {
611                 handrx.version = bswap16(handrx.version);
612                 handrx.flags = bswap32(handrx.flags);
613         }
614         for (i = 0; i < sizeof(handrx.sess); ++i)
615                 handrx.verf[i / 4] ^= handrx.sess[i];
616         n = 0;
617         for (i = 0; i < sizeof(handrx.verf); ++i)
618                 n += handrx.verf[i];
619         if (handrx.version != 1)
620                 ++n;
621         if (n != 0)
622                 goto keyxchgfail;
623
624         /*
625          * Use separate session keys and session fixed IVs for receive and
626          * transmit.
627          */
628         error = crypto_algos[DMSG_CRYPTO_ALGO].init(&iocom->ioq_rx,
629             (char*)handrx.sess,
630             crypto_algos[DMSG_CRYPTO_ALGO].keylen,
631             (char*)handrx.sess + crypto_algos[DMSG_CRYPTO_ALGO].keylen,
632             sizeof(handrx.sess) - crypto_algos[DMSG_CRYPTO_ALGO].keylen,
633             0 /* decryption */);
634         if (error)
635                 goto keyxchgfail;
636
637         error = crypto_algos[DMSG_CRYPTO_ALGO].init(&iocom->ioq_tx,
638             (char*)handtx.sess,
639             crypto_algos[DMSG_CRYPTO_ALGO].keylen,
640             (char*)handtx.sess + crypto_algos[DMSG_CRYPTO_ALGO].keylen,
641             sizeof(handtx.sess) - crypto_algos[DMSG_CRYPTO_ALGO].keylen,
642             1 /* encryption */);
643         if (error)
644                 goto keyxchgfail;
645
646         atomic_set_int(&iocom->flags, DMSG_IOCOMF_CRYPTED);
647
648         dmio_printf(iocom, 1, "auth success: %s\n", handrx.quickmsg);
649 done:
650         if (path)
651                 free(path);
652         if (keys[0])
653                 RSA_free(keys[0]);
654         if (keys[1])
655                 RSA_free(keys[1]);
656         if (keys[1])
657                 RSA_free(keys[2]);
658 }
659
660 /*
661  * Decrypt pending data in the ioq's fifo.  The data is decrypted in-place.
662  */
663 void
664 dmsg_crypto_decrypt(dmsg_iocom_t *iocom __unused, dmsg_ioq_t *ioq)
665 {
666         int p_len;
667         int used;
668         __unused int error;     /* XXX */
669         char buf[512];
670
671         /*
672          * fifo_beg to fifo_cdx is data already decrypted.
673          * fifo_cdn to fifo_end is data not yet decrypted.
674          */
675         p_len = ioq->fifo_end - ioq->fifo_cdn; /* data not yet decrypted */
676
677         if (p_len == 0)
678                 return;
679
680         while (p_len >= crypto_algos[DMSG_CRYPTO_ALGO].taglen +
681             DMSG_CRYPTO_CHUNK_SIZE) {
682                 bcopy(ioq->buf + ioq->fifo_cdn, buf,
683                       crypto_algos[DMSG_CRYPTO_ALGO].taglen +
684                       DMSG_CRYPTO_CHUNK_SIZE);
685                 error = crypto_algos[DMSG_CRYPTO_ALGO].dec_chunk(
686                     ioq, buf,
687                     ioq->buf + ioq->fifo_cdx,
688                     DMSG_CRYPTO_CHUNK_SIZE,
689                     &used);
690 #ifdef CRYPTO_DEBUG
691                 dmio_printf(iocom, 5,
692                             "dec: p_len: %d, used: %d, "
693                             "fifo_cdn: %ju, fifo_cdx: %ju\n",
694                              p_len, used,
695                              ioq->fifo_cdn, ioq->fifo_cdx);
696 #endif
697                 p_len -= used;
698                 ioq->fifo_cdn += used;
699                 ioq->fifo_cdx += DMSG_CRYPTO_CHUNK_SIZE;
700 #ifdef CRYPTO_DEBUG
701                 dmio_printf(iocom, 5,
702                             "dec: p_len: %d, used: %d, "
703                             "fifo_cdn: %ju, fifo_cdx: %ju\n",
704                             p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
705 #endif
706         }
707 }
708
709 /*
710  * *nactp is set to the number of ORIGINAL bytes consumed by the encrypter.
711  * The FIFO may contain more data.
712  */
713 int
714 dmsg_crypto_encrypt(dmsg_iocom_t *iocom __unused, dmsg_ioq_t *ioq,
715                     struct iovec *iov, int n, size_t *nactp)
716 {
717         int p_len, used, ct_used;
718         int i;
719         __unused int error;     /* XXX */
720         size_t nmax;
721
722         nmax = sizeof(ioq->buf) - ioq->fifo_end;        /* max new bytes */
723
724         *nactp = 0;
725         for (i = 0; i < n && nmax; ++i) {
726                 used = 0;
727                 p_len = iov[i].iov_len;
728                 assert((p_len & DMSG_ALIGNMASK) == 0);
729
730                 while (p_len >= DMSG_CRYPTO_CHUNK_SIZE &&
731                     nmax >= DMSG_CRYPTO_CHUNK_SIZE +
732                     (size_t)crypto_algos[DMSG_CRYPTO_ALGO].taglen) {
733                         error = crypto_algos[DMSG_CRYPTO_ALGO].enc_chunk(
734                             ioq,
735                             ioq->buf + ioq->fifo_cdx,
736                             (char *)iov[i].iov_base + used,
737                             DMSG_CRYPTO_CHUNK_SIZE, &ct_used);
738 #ifdef CRYPTO_DEBUG
739                         dmio_printf(iocom, 5,
740                                     "nactp: %ju, p_len: %d, "
741                                     "ct_used: %d, used: %d, nmax: %ju\n",
742                                     *nactp, p_len, ct_used, used, nmax);
743 #endif
744
745                         *nactp += (size_t)DMSG_CRYPTO_CHUNK_SIZE;       /* plaintext count */
746                         used += DMSG_CRYPTO_CHUNK_SIZE;
747                         p_len -= DMSG_CRYPTO_CHUNK_SIZE;
748
749                         /*
750                          * NOTE: crypted count will eventually differ from
751                          *       nmax, but for now we have not yet introduced
752                          *       random armor.
753                          */
754                         ioq->fifo_cdx += (size_t)ct_used;
755                         ioq->fifo_cdn += (size_t)ct_used;
756                         ioq->fifo_end += (size_t)ct_used;
757                         nmax -= (size_t)ct_used;
758 #ifdef CRYPTO_DEBUG
759                         dmio_printf(iocom, 5,
760                                     "nactp: %ju, p_len: %d, "
761                                     "ct_used: %d, used: %d, nmax: %ju\n",
762                                     *nactp, p_len, ct_used, used, nmax);
763 #endif
764                 }
765         }
766         iov[0].iov_base = ioq->buf + ioq->fifo_beg;
767         iov[0].iov_len = ioq->fifo_cdx - ioq->fifo_beg;
768
769         return (1);
770 }