cluster - more libdmsg work
[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                 if (DMsgDebugOpt)
104                         fprintf(stderr, "Not enough key or iv material\n");
105                 return -1;
106         }
107
108         printf("%s key: ", enc ? "Encryption" : "Decryption");
109         for (i = 0; i < DMSG_CRYPTO_GCM_KEY_SIZE; ++i)
110                 printf("%02x", (unsigned char)key[i]);
111         printf("\n");
112
113         printf("%s iv:  ", enc ? "Encryption" : "Decryption");
114         for (i = 0; i < DMSG_CRYPTO_GCM_IV_FIXED_SIZE; ++i)
115                 printf("%02x", (unsigned char)iv_fixed[i]);
116         printf(" (fixed part only)\n");
117
118         EVP_CIPHER_CTX_init(&ioq->ctx);
119
120         if (enc)
121                 ok = EVP_EncryptInit_ex(&ioq->ctx, EVP_aes_256_gcm(), NULL,
122                                         key, NULL);
123         else
124                 ok = EVP_DecryptInit_ex(&ioq->ctx, EVP_aes_256_gcm(), NULL,
125                                         key, NULL);
126         if (!ok)
127                 goto fail;
128
129         /*
130          * According to the original Galois/Counter Mode of Operation (GCM)
131          * proposal, only IVs that are exactly 96 bits get used without any
132          * further processing. Other IV sizes cause the GHASH() operation
133          * to be applied to the IV, which is more costly.
134          *
135          * The NIST SP 800-38D also recommends using a 96 bit IV for the same
136          * reasons. We actually follow the deterministic construction
137          * recommended in NIST SP 800-38D with a 64 bit invocation field as an
138          * integer counter and a random, session-specific fixed field.
139          *
140          * This means that we can essentially use the same session key and
141          * IV fixed field for up to 2^64 invocations of the authenticated
142          * encryption or decryption.
143          *
144          * With a chunk size of 64 bytes, this adds up to 1 zettabyte of
145          * traffic.
146          */
147         ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_IVLEN,
148                                  DMSG_CRYPTO_GCM_IV_SIZE, NULL);
149         if (!ok)
150                 goto fail;
151
152         memset(ioq->iv, 0, DMSG_CRYPTO_GCM_IV_SIZE);
153         memcpy(ioq->iv, iv_fixed, DMSG_CRYPTO_GCM_IV_FIXED_SIZE);
154
155         /*
156          * Strictly speaking, padding is irrelevant with a counter mode
157          * encryption.
158          *
159          * However, setting padding to 0, even if using a counter mode such
160          * as GCM, will cause an error in _finish if the pt/ct size is not
161          * a multiple of the cipher block size.
162          */
163         EVP_CIPHER_CTX_set_padding(&ioq->ctx, 0);
164
165         return 0;
166
167 fail:
168         if (DMsgDebugOpt)
169                 fprintf(stderr, "Error during _gcm_init\n");
170         return -1;
171 }
172
173 static
174 int
175 _gcm_iv_increment(char *iv)
176 {
177         /*
178          * Deterministic construction according to NIST SP 800-38D, with
179          * 64 bit invocation field as integer counter.
180          *
181          * In other words, our 96 bit IV consists of a 32 bit fixed field
182          * unique to the session and a 64 bit integer counter.
183          */
184
185         uint64_t *c = (uint64_t *)(&iv[DMSG_CRYPTO_GCM_IV_FIXED_SIZE]);
186
187         /* Increment invocation field integer counter */
188         *c = htobe64(be64toh(*c)+1);
189
190         /*
191          * Detect wrap-around, which means it is time to renegotiate
192          * the session to get a new key and/or fixed field.
193          */
194         return (c == 0) ? 0 : 1;
195 }
196
197 static
198 int
199 dmsg_crypto_gcm_encrypt_chunk(dmsg_ioq_t *ioq, char *ct, char *pt,
200                                  int in_size, int *out_size)
201 {
202         int ok;
203         int u_len, f_len;
204
205         *out_size = 0;
206
207         /* Re-initialize with new IV (but without redoing the key schedule) */
208         ok = EVP_EncryptInit_ex(&ioq->ctx, NULL, NULL, NULL, ioq->iv);
209         if (!ok)
210                 goto fail;
211
212         ok = EVP_EncryptUpdate(&ioq->ctx, ct, &u_len, pt, in_size);
213         if (!ok)
214                 goto fail;
215
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         if (DMsgDebugOpt)
241                 fprintf(stderr, "error during encrypt_chunk\n");
242         return -1;
243 }
244
245 static
246 int
247 dmsg_crypto_gcm_decrypt_chunk(dmsg_ioq_t *ioq, char *ct, char *pt,
248                                  int out_size, int *consume_size)
249 {
250         int ok;
251         int u_len, f_len;
252
253         *consume_size = 0;
254
255         /* Re-initialize with new IV (but without redoing the key schedule) */
256         ok = EVP_DecryptInit_ex(&ioq->ctx, NULL, NULL, NULL, ioq->iv);
257         if (!ok) {
258                 ioq->error = DMSG_IOQ_ERROR_ALGO;
259                 goto fail_out;
260         }
261
262         ok = EVP_CIPHER_CTX_ctrl(&ioq->ctx, EVP_CTRL_GCM_SET_TAG,
263                                  DMSG_CRYPTO_GCM_TAG_SIZE,
264                                  ct + out_size);
265         if (!ok) {
266                 ioq->error = DMSG_IOQ_ERROR_ALGO;
267                 goto fail_out;
268         }
269
270         ok = EVP_DecryptUpdate(&ioq->ctx, pt, &u_len, ct, out_size);
271         if (!ok)
272                 goto fail;
273
274         ok = EVP_DecryptFinal(&ioq->ctx, pt + u_len, &f_len);
275         if (!ok)
276                 goto fail;
277
278         ok = _gcm_iv_increment(ioq->iv);
279         if (!ok) {
280                 ioq->error = DMSG_IOQ_ERROR_IVWRAP;
281                 goto fail_out;
282         }
283
284         *consume_size = u_len + f_len + DMSG_CRYPTO_GCM_TAG_SIZE;
285
286         return 0;
287
288 fail:
289         ioq->error = DMSG_IOQ_ERROR_MACFAIL;
290 fail_out:
291         if (DMsgDebugOpt)
292                 fprintf(stderr, "error during decrypt_chunk (likely authentication error)\n");
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                 if (DMsgDebugOpt)
370                         fprintf(stderr, "accept: getpeername() failed\n");
371                 goto done;
372         }
373         if (getnameinfo(&sa.sa, salen, peername, sizeof(peername),
374                         NULL, 0, NI_NUMERICHOST) < 0) {
375                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOPEER;
376                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
377                 if (DMsgDebugOpt)
378                         fprintf(stderr, "accept: cannot decode sockaddr\n");
379                 goto done;
380         }
381         if (DMsgDebugOpt) {
382                 if (realhostname_sa(realname, sizeof(realname),
383                                     &sa.sa, salen) == HOSTNAME_FOUND) {
384                         fprintf(stderr, "accept from %s (%s)\n",
385                                 peername, realname);
386                 } else {
387                         fprintf(stderr, "accept from %s\n", peername);
388                 }
389         }
390
391         /*
392          * Find the remote host's public key
393          *
394          * If the link is not to be encrypted (<ip>.none located) we shortcut
395          * the handshake entirely.  No buffers are exchanged.
396          */
397         asprintf(&path, "%s/%s.pub", DMSG_PATH_REMOTE, peername);
398         if ((fp = fopen(path, "r")) == NULL) {
399                 free(path);
400                 asprintf(&path, "%s/%s.none",
401                          DMSG_PATH_REMOTE, peername);
402                 if (stat(path, &st) < 0) {
403                         iocom->ioq_rx.error = DMSG_IOQ_ERROR_NORKEY;
404                         atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
405                         if (DMsgDebugOpt)
406                                 fprintf(stderr, "auth failure: unknown host\n");
407                         goto done;
408                 }
409                 if (DMsgDebugOpt)
410                         fprintf(stderr, "auth succeeded, unencrypted link\n");
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                         if (DMsgDebugOpt)
420                                 fprintf(stderr,
421                                         "auth failure: bad key format\n");
422                         goto done;
423                 }
424         }
425
426         /*
427          * Get our public and private keys
428          */
429         free(path);
430         asprintf(&path, DMSG_DEFAULT_DIR "/rsa.pub");
431         if ((fp = fopen(path, "r")) == NULL) {
432                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOLKEY;
433                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
434                 goto done;
435         }
436         keys[1] = PEM_read_RSA_PUBKEY(fp, NULL, NULL, NULL);
437         fclose(fp);
438         if (keys[1] == NULL) {
439                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
440                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
441                 if (DMsgDebugOpt)
442                         fprintf(stderr, "auth failure: bad host key format\n");
443                 goto done;
444         }
445
446         free(path);
447         asprintf(&path, DMSG_DEFAULT_DIR "/rsa.prv");
448         if ((fp = fopen(path, "r")) == NULL) {
449                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_NOLKEY;
450                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
451                 if (DMsgDebugOpt)
452                         fprintf(stderr, "auth failure: bad host key format\n");
453                 goto done;
454         }
455         keys[2] = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
456         fclose(fp);
457         if (keys[2] == NULL) {
458                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
459                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
460                 if (DMsgDebugOpt)
461                         fprintf(stderr, "auth failure: bad host key format\n");
462                 goto done;
463         }
464         free(path);
465         path = NULL;
466
467         /*
468          * public key encrypt/decrypt block size.
469          */
470         if (keys[0]) {
471                 blksize = (size_t)RSA_size(keys[0]);
472                 if (blksize != (size_t)RSA_size(keys[1]) ||
473                     blksize != (size_t)RSA_size(keys[2]) ||
474                     sizeof(handtx) % blksize != 0) {
475                         iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYFMT;
476                         atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
477                         if (DMsgDebugOpt)
478                                 fprintf(stderr, "auth failure: "
479                                                 "key size mismatch\n");
480                         goto done;
481                 }
482         } else {
483                 blksize = sizeof(handtx);
484         }
485         blkmask = blksize - 1;
486
487         bzero(&handrx, sizeof(handrx));
488         bzero(&handtx, sizeof(handtx));
489
490         /*
491          * Fill all unused fields (particular all junk fields) with random
492          * data, and also set the session key.
493          */
494         fd = open("/dev/urandom", O_RDONLY);
495         if (fd < 0 ||
496             fstat(fd, &st) < 0 ||       /* something wrong */
497             S_ISREG(st.st_mode) ||      /* supposed to be a RNG dev! */
498             read(fd, &handtx, sizeof(handtx)) != sizeof(handtx)) {
499 urandfail:
500                 if (fd >= 0)
501                         close(fd);
502                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_BADURANDOM;
503                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
504                 if (DMsgDebugOpt)
505                         fprintf(stderr, "auth failure: bad rng\n");
506                 goto done;
507         }
508         if (bcmp(&handrx, &handtx, sizeof(handtx)) == 0)
509                 goto urandfail;                 /* read all zeros */
510         close(fd);
511         /* ERR_load_crypto_strings(); openssl debugging */
512
513         /*
514          * Handshake with the remote.
515          *
516          *      Encrypt with my private and remote's public
517          *      Decrypt with my private and remote's public
518          *
519          * When encrypting we have to make sure our buffer fits within the
520          * modulus, which typically requires bit 7 o the first byte to be
521          * zero.  To be safe make sure that bit 7 and bit 6 is zero.
522          */
523         snprintf(handtx.quickmsg, sizeof(handtx.quickmsg), "Testing 1 2 3");
524         handtx.magic = DMSG_HDR_MAGIC;
525         handtx.version = 1;
526         handtx.flags = 0;
527         assert(sizeof(handtx.verf) * 4 == sizeof(handtx.sess));
528         bzero(handtx.verf, sizeof(handtx.verf));
529
530         handtx.pad1[0] &= 0x3f; /* message must fit within modulus */
531         handtx.pad2[0] &= 0x3f; /* message must fit within modulus */
532
533         for (i = 0; i < sizeof(handtx.sess); ++i)
534                 handtx.verf[i / 4] ^= handtx.sess[i];
535
536         /*
537          * Write handshake buffer to remote
538          */
539         for (i = 0; i < sizeof(handtx); i += blksize) {
540                 ptr = (char *)&handtx + i;
541                 if (keys[0]) {
542                         /*
543                          * Since we are double-encrypting we have to make
544                          * sure that the result of the first stage does
545                          * not blow out the modulus for the second stage.
546                          *
547                          * The pointer is pointing to the pad*[] area so
548                          * we can mess with that until the first stage
549                          * is legal.
550                          */
551                         do {
552                                 ++*(int *)(ptr + 4);
553                                 if (RSA_private_encrypt(blksize, ptr, buf1,
554                                             keys[2], RSA_NO_PADDING) < 0) {
555                                         iocom->ioq_rx.error =
556                                                 DMSG_IOQ_ERROR_KEYXCHGFAIL;
557                                 }
558                         } while (buf1[0] & 0xC0);
559
560                         if (RSA_public_encrypt(blksize, buf1, buf2,
561                                             keys[0], RSA_NO_PADDING) < 0) {
562                                 iocom->ioq_rx.error =
563                                         DMSG_IOQ_ERROR_KEYXCHGFAIL;
564                         }
565                 }
566                 if (write(iocom->sock_fd, buf2, blksize) != (ssize_t)blksize) {
567                         fprintf(stderr, "WRITE ERROR\n");
568                 }
569         }
570         if (iocom->ioq_rx.error) {
571                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
572                 if (DMsgDebugOpt)
573                         fprintf(stderr, "auth failure: key exchange failure "
574                                         "during encryption\n");
575                 goto done;
576         }
577
578         /*
579          * Read handshake buffer from remote
580          */
581         i = 0;
582         while (i < sizeof(handrx)) {
583                 ptr = (char *)&handrx + i;
584                 n = read(iocom->sock_fd, ptr, blksize - (i & blkmask));
585                 if (n <= 0)
586                         break;
587                 ptr -= (i & blkmask);
588                 i += n;
589                 if (keys[0] && (i & blkmask) == 0) {
590                         if (RSA_private_decrypt(blksize, ptr, buf1,
591                                            keys[2], RSA_NO_PADDING) < 0)
592                                 iocom->ioq_rx.error =
593                                                 DMSG_IOQ_ERROR_KEYXCHGFAIL;
594                         if (RSA_public_decrypt(blksize, buf1, ptr,
595                                            keys[0], RSA_NO_PADDING) < 0)
596                                 iocom->ioq_rx.error =
597                                                 DMSG_IOQ_ERROR_KEYXCHGFAIL;
598                 }
599         }
600         if (iocom->ioq_rx.error) {
601                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
602                 if (DMsgDebugOpt)
603                         fprintf(stderr, "auth failure: key exchange failure "
604                                         "during decryption\n");
605                 goto done;
606         }
607
608         /*
609          * Validate the received data.  Try to make this a constant-time
610          * algorithm.
611          */
612         if (i != sizeof(handrx)) {
613 keyxchgfail:
614                 iocom->ioq_rx.error = DMSG_IOQ_ERROR_KEYXCHGFAIL;
615                 atomic_set_int(&iocom->flags, DMSG_IOCOMF_EOF);
616                 if (DMsgDebugOpt)
617                         fprintf(stderr, "auth failure: key exchange failure\n");
618                 goto done;
619         }
620
621         if (handrx.magic == DMSG_HDR_MAGIC_REV) {
622                 handrx.version = bswap16(handrx.version);
623                 handrx.flags = bswap32(handrx.flags);
624         }
625         for (i = 0; i < sizeof(handrx.sess); ++i)
626                 handrx.verf[i / 4] ^= handrx.sess[i];
627         n = 0;
628         for (i = 0; i < sizeof(handrx.verf); ++i)
629                 n += handrx.verf[i];
630         if (handrx.version != 1)
631                 ++n;
632         if (n != 0)
633                 goto keyxchgfail;
634
635         /*
636          * Use separate session keys and session fixed IVs for receive and
637          * transmit.
638          */
639         error = crypto_algos[DMSG_CRYPTO_ALGO].init(&iocom->ioq_rx, handrx.sess,
640             crypto_algos[DMSG_CRYPTO_ALGO].keylen,
641             handrx.sess + crypto_algos[DMSG_CRYPTO_ALGO].keylen,
642             sizeof(handrx.sess) - crypto_algos[DMSG_CRYPTO_ALGO].keylen,
643             0 /* decryption */);
644         if (error)
645                 goto keyxchgfail;
646
647         error = crypto_algos[DMSG_CRYPTO_ALGO].init(&iocom->ioq_tx, handtx.sess,
648             crypto_algos[DMSG_CRYPTO_ALGO].keylen,
649             handtx.sess + crypto_algos[DMSG_CRYPTO_ALGO].keylen,
650             sizeof(handtx.sess) - crypto_algos[DMSG_CRYPTO_ALGO].keylen,
651             1 /* encryption */);
652         if (error)
653                 goto keyxchgfail;
654
655         atomic_set_int(&iocom->flags, DMSG_IOCOMF_CRYPTED);
656
657         if (DMsgDebugOpt)
658                 fprintf(stderr, "auth success: %s\n", handrx.quickmsg);
659 done:
660         if (path)
661                 free(path);
662         if (keys[0])
663                 RSA_free(keys[0]);
664         if (keys[1])
665                 RSA_free(keys[1]);
666         if (keys[1])
667                 RSA_free(keys[2]);
668 }
669
670 /*
671  * Decrypt pending data in the ioq's fifo.  The data is decrypted in-place.
672  */
673 void
674 dmsg_crypto_decrypt(dmsg_iocom_t *iocom __unused, dmsg_ioq_t *ioq)
675 {
676         int p_len;
677         int used;
678         int error;
679         char buf[512];
680
681         /*
682          * fifo_beg to fifo_cdx is data already decrypted.
683          * fifo_cdn to fifo_end is data not yet decrypted.
684          */
685         p_len = ioq->fifo_end - ioq->fifo_cdn; /* data not yet decrypted */
686
687         if (p_len == 0)
688                 return;
689
690         while (p_len >= crypto_algos[DMSG_CRYPTO_ALGO].taglen +
691             DMSG_CRYPTO_CHUNK_SIZE) {
692                 bcopy(ioq->buf + ioq->fifo_cdn, buf,
693                       crypto_algos[DMSG_CRYPTO_ALGO].taglen +
694                       DMSG_CRYPTO_CHUNK_SIZE);
695                 error = crypto_algos[DMSG_CRYPTO_ALGO].dec_chunk(
696                     ioq, buf,
697                     ioq->buf + ioq->fifo_cdx,
698                     DMSG_CRYPTO_CHUNK_SIZE,
699                     &used);
700 #ifdef CRYPTO_DEBUG
701                 printf("dec: p_len: %d, used: %d, fifo_cdn: %ju, fifo_cdx: %ju\n",
702                        p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
703 #endif
704                 p_len -= used;
705                 ioq->fifo_cdn += used;
706                 ioq->fifo_cdx += DMSG_CRYPTO_CHUNK_SIZE;
707 #ifdef CRYPTO_DEBUG
708                 printf("dec: p_len: %d, used: %d, fifo_cdn: %ju, fifo_cdx: %ju\n",
709                        p_len, used, ioq->fifo_cdn, ioq->fifo_cdx);
710 #endif
711         }
712 }
713
714 /*
715  * *nactp is set to the number of ORIGINAL bytes consumed by the encrypter.
716  * The FIFO may contain more data.
717  */
718 int
719 dmsg_crypto_encrypt(dmsg_iocom_t *iocom __unused, dmsg_ioq_t *ioq,
720                     struct iovec *iov, int n, size_t *nactp)
721 {
722         int p_len, used, ct_used;
723         int i;
724         int error;
725         size_t nmax;
726
727         nmax = sizeof(ioq->buf) - ioq->fifo_end;        /* max new bytes */
728
729         *nactp = 0;
730         for (i = 0; i < n && nmax; ++i) {
731                 used = 0;
732                 p_len = iov[i].iov_len;
733                 assert((p_len & DMSG_ALIGNMASK) == 0);
734
735                 while (p_len >= DMSG_CRYPTO_CHUNK_SIZE &&
736                     nmax >= DMSG_CRYPTO_CHUNK_SIZE +
737                     (size_t)crypto_algos[DMSG_CRYPTO_ALGO].taglen) {
738                         error = crypto_algos[DMSG_CRYPTO_ALGO].enc_chunk(
739                             ioq,
740                             ioq->buf + ioq->fifo_cdx,
741                             (char *)iov[i].iov_base + used,
742                             DMSG_CRYPTO_CHUNK_SIZE, &ct_used);
743 #ifdef CRYPTO_DEBUG
744                         printf("nactp: %ju, p_len: %d, ct_used: %d, used: %d, nmax: %ju\n",
745                                *nactp, p_len, ct_used, used, nmax);
746 #endif
747
748                         *nactp += (size_t)DMSG_CRYPTO_CHUNK_SIZE;       /* plaintext count */
749                         used += DMSG_CRYPTO_CHUNK_SIZE;
750                         p_len -= DMSG_CRYPTO_CHUNK_SIZE;
751
752                         ioq->fifo_cdx += (size_t)ct_used;       /* crypted count */
753                         ioq->fifo_cdn += (size_t)ct_used;       /* crypted count */
754                         ioq->fifo_end += (size_t)ct_used;
755                         nmax -= (size_t)ct_used;
756 #ifdef CRYPTO_DEBUG
757                         printf("nactp: %ju, p_len: %d, ct_used: %d, used: %d, nmax: %ju\n",
758                                *nactp, p_len, ct_used, used, nmax);
759 #endif
760                 }
761         }
762         iov[0].iov_base = ioq->buf + ioq->fifo_beg;
763         iov[0].iov_len = ioq->fifo_cdx - ioq->fifo_beg;
764
765         return (1);
766 }