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