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