chiark / gitweb /
fe491280cbcfd4f3792ce0dd9450cfa392d9f3c5
[tripe] / server / keyset.c
1 /* -*-c-*-
2  *
3  * Handling of symmetric keysets
4  *
5  * (c) 2001 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Trivial IP Encryption (TrIPE).
11  *
12  * TrIPE is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * TrIPE is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with TrIPE; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "tripe.h"
30
31 /*----- Tunable parameters ------------------------------------------------*/
32
33 /* --- Note on size limits --- *
34  *
35  * For a 64-bit block cipher (e.g., Blowfish), the probability of a collision
36  * occurring after 32 MB is less than %$2^{-21}$%, and the probability of a
37  * collision occurring after 64 MB is less than %$2^{-19}$%.  These could be
38  * adjusted dependent on the encryption scheme, but it's too much pain.
39  */
40
41 #define T_EXP MIN(60)                   /* Expiry time for a key */
42 #define T_REGEN MIN(45)                 /* Regeneration time for a key */
43 #define SZ_EXP MEG(64)                  /* Expiry data size for a key */
44 #define SZ_REGEN MEG(32)                /* Data size threshold for regen */
45
46 /*----- Handy macros ------------------------------------------------------*/
47
48 #define KEYOK(ks, now) ((ks)->sz_exp > 0 && (ks)->t_exp > now)
49
50 #define SEQSZ 4                         /* Size of sequence number packet */
51
52 /*----- Low-level packet encryption and decryption ------------------------*/
53
54 /* --- Encrypted data format --- *
55  *
56  * Let %$p_i$% be the %$i$%-th plaintext message, with type %$t$%.  We first
57  * compute
58  *
59  *   %$c_i = \mathcal{E}\textrm{-CBC}_{K_{\text{E}}}(p_i)$%
60  *
61  * as the CBC-ciphertext of %$p_i$%, and then
62  *
63  *   %$\sigma_i = \mathcal{T}_{K_{\text{M}}}(t, i, c_i)$%
64  *
65  * as a MAC on the %%\emph{ciphertext}%%.  The message sent is then the pair
66  * %$(\sigma_i, c_i)$%.  This construction is provably secure in the NM-CCA
67  * sense (assuming that the cipher is IND-CPA, and the MAC is SUF-CMA)
68  * [Bellare and Namprempre].
69  *
70  * This also ensures that, assuming the key is good, we have a secure channel
71  * [Krawczyk].  Actually, [Krawczyk] shows that, if the cipher is either a
72  * simple stream cipher or a block cipher in CBC mode, we can use the MAC-
73  * then-encrypt scheme and still have a secure channel.  However, I like the
74  * NM-CCA guarantee from [Bellare and Namprempre].  I'm less worried about
75  * the Horton Principle [Wagner and Schneier].
76  */
77
78 /* --- @doencrypt@ --- *
79  *
80  * Arguments:   @keyset *ks@ = pointer to keyset to use
81  *              @unsigned ty@ = type of message this is
82  *              @buf *b@ = pointer to an input buffer
83  *              @buf *bb@ = pointer to an output buffer
84  *
85  * Returns:     Zero if OK, nonzero if a new key is required.
86  *
87  * Use:         Encrypts a message with the given key.  We assume that the
88  *              keyset is OK to use.
89  */
90
91 static int doencrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
92 {
93   ghash *h;
94   gcipher *c = ks->cout;
95   const octet *p = BCUR(b);
96   size_t sz = BLEFT(b);
97   octet *qmac, *qseq, *qiv, *qpk;
98   uint32 oseq;
99   size_t ivsz = GC_CLASS(c)->blksz;
100   size_t tagsz = ks->tagsz;
101   size_t osz, nsz;
102   octet t[4];
103   int rc = 0;
104
105   /* --- Allocate the required buffer space --- */
106
107   if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz))
108     return (0); /* Caution! */
109   qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz;
110   BSTEP(bb, tagsz + SEQSZ + ivsz + sz);
111   STORE32(t, ty);
112
113   oseq = ks->oseq++; STORE32(qseq, oseq);
114   IF_TRACING(T_KEYSET, {
115     trace(T_KEYSET, "keyset: encrypting packet %lu using keyset %u",
116           (unsigned long)oseq, ks->seq);
117     trace_block(T_CRYPTO, "crypto: plaintext packet", p, sz);
118   })
119
120   /* --- Encrypt the packet --- */
121
122   if (ivsz) {
123     rand_get(RAND_GLOBAL, qiv, ivsz);
124     GC_SETIV(c, qiv);
125     IF_TRACING(T_KEYSET, {
126       trace_block(T_CRYPTO, "crypto: initialization vector", qiv, ivsz);
127     })
128   }
129   GC_ENCRYPT(c, p, qpk, sz);
130   IF_TRACING(T_KEYSET, {
131     trace_block(T_CRYPTO, "crypto: encrypted packet", qpk, sz);
132   })
133
134   /* --- Now compute the MAC --- */
135
136   if (tagsz) {
137     h = GM_INIT(ks->mout);
138     GH_HASH(h, t, sizeof(t));
139     GH_HASH(h, qseq, SEQSZ + ivsz + sz);
140     memcpy(qmac, GH_DONE(h, 0), tagsz);
141     GH_DESTROY(h);
142     IF_TRACING(T_KEYSET, {
143       trace_block(T_CRYPTO, "crypto: computed MAC", qmac, tagsz);
144     })
145   }
146
147   /* --- Deduct the packet size from the key's data life --- */
148
149   osz = ks->sz_exp;
150   if (osz > sz)
151     nsz = osz - sz;
152   else
153     nsz = 0;
154   if (osz >= SZ_REGEN && nsz < SZ_REGEN) {
155     T( trace(T_KEYSET, "keyset: keyset %u data regen limit exceeded -- "
156              "forcing exchange", ks->seq); )
157     rc = -1;
158   }
159   ks->sz_exp = nsz;
160   return (rc);
161 }
162
163 /* --- @dodecrypt@ --- *
164  *
165  * Arguments:   @keyset *ks@ = pointer to keyset to use
166  *              @unsigned ty@ = expected type code
167  *              @buf *b@ = pointer to an input buffer
168  *              @buf *bb@ = pointer to an output buffer
169  *              @uint32 *seq@ = where to store the sequence number
170  *
171  * Returns:     Zero if OK, nonzero if it failed.
172  *
173  * Use:         Attempts to decrypt a message with the given key.  No other
174  *              checking (e.g., sequence number checks) is performed.  We
175  *              assume that the keyset is OK to use, and that there is
176  *              sufficient output buffer space reserved.  If the decryption
177  *              is successful, the buffer pointer is moved past the decrypted
178  *              packet, and the packet's sequence number is stored in @*seq@.
179  */
180
181 static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
182 {
183   const octet *pmac, *piv, *pseq, *ppk;
184   size_t psz = BLEFT(b);
185   size_t sz;
186   octet *q = BCUR(bb);
187   ghash *h;
188   gcipher *c = ks->cin;
189   size_t ivsz = GC_CLASS(c)->blksz;
190   size_t tagsz = ks->tagsz;
191   octet *mac;
192   int eq;
193   octet t[4];
194
195   /* --- Break up the packet into its components --- */
196
197   if (psz < ivsz + SEQSZ + tagsz) {
198     T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
199     return (-1);
200   }
201   sz = psz - ivsz - SEQSZ - tagsz;
202   pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
203   STORE32(t, ty);
204
205   IF_TRACING(T_KEYSET, {
206     trace(T_KEYSET, "keyset: decrypting using keyset %u", ks->seq);
207     trace_block(T_CRYPTO, "crypto: ciphertext packet", ppk, sz);
208   })
209
210   /* --- Verify the MAC on the packet --- */
211
212   if (tagsz) {
213     h = GM_INIT(ks->min);
214     GH_HASH(h, t, sizeof(t));
215     GH_HASH(h, pseq, SEQSZ + ivsz + sz);
216     mac = GH_DONE(h, 0);
217     eq = !memcmp(mac, pmac, tagsz);
218     IF_TRACING(T_KEYSET, {
219       trace_block(T_CRYPTO, "crypto: computed MAC", mac, tagsz);
220     })
221     GH_DESTROY(h);
222     if (!eq) {
223       IF_TRACING(T_KEYSET, {
224         trace(T_KEYSET, "keyset: incorrect MAC: decryption failed");
225         trace_block(T_CRYPTO, "crypto: expected MAC", pmac, tagsz);
226       })
227       return (-1);
228     }
229   }
230
231   /* --- Decrypt the packet --- */
232
233   if (ivsz) {
234     GC_SETIV(c, piv);
235     IF_TRACING(T_KEYSET, {
236       trace_block(T_CRYPTO, "crypto: initialization vector", piv, ivsz);
237     })
238   }
239   GC_DECRYPT(c, ppk, q, sz);
240   if (seq)
241     *seq = LOAD32(pseq);
242   IF_TRACING(T_KEYSET, {
243     trace(T_KEYSET, "keyset: decrypted OK (sequence = %lu)",
244           (unsigned long)LOAD32(pseq));
245     trace_block(T_CRYPTO, "crypto: decrypted packet", q, sz);
246   })
247   BSTEP(bb, sz);
248   return (0);
249 }
250
251 /*----- Operations on a single keyset -------------------------------------*/
252
253 /* --- @ks_drop@ --- *
254  *
255  * Arguments:   @keyset *ks@ = pointer to a keyset
256  *
257  * Returns:     ---
258  *
259  * Use:         Decrements a keyset's reference counter.  If the counter hits
260  *              zero, the keyset is freed.
261  */
262
263 void ks_drop(keyset *ks)
264 {
265   if (--ks->ref)
266     return;
267   GC_DESTROY(ks->cin);
268   GC_DESTROY(ks->cout);
269   GM_DESTROY(ks->min);
270   GM_DESTROY(ks->mout);
271   DESTROY(ks);
272 }
273
274 /* --- @ks_gen@ --- *
275  *
276  * Arguments:   @const void *k@ = pointer to key material
277  *              @size_t x, y, z@ = offsets into key material (see below)
278  *              @peer *p@ = pointer to peer information
279  *
280  * Returns:     A pointer to the new keyset.
281  *
282  * Use:         Derives a new keyset from the given key material.  The
283  *              offsets @x@, @y@ and @z@ separate the key material into three
284  *              parts.  Between the @k@ and @k + x@ is `my' contribution to
285  *              the key material; between @k + x@ and @k + y@ is `your'
286  *              contribution; and between @k + y@ and @k + z@ is a shared
287  *              value we made together.  These are used to construct two
288  *              pairs of symmetric keys.  Each pair consists of an encryption
289  *              key and a message authentication key.  One pair is used for
290  *              outgoing messages, the other for incoming messages.
291  *
292  *              The new key is marked so that it won't be selected for output
293  *              by @ksl_encrypt@.  You can still encrypt data with it by
294  *              calling @ks_encrypt@ directly.
295  */
296
297 keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
298 {
299   ghash *h;
300   const octet *hh;
301   keyset *ks = CREATE(keyset);
302   time_t now = time(0);
303   const octet *pp = k;
304   T( static unsigned seq = 0; )
305
306   T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); )
307
308   /* --- Construct the various keys --- *
309    *
310    * This is done with macros, because it's quite tedious.
311    */
312
313 #define MINE GH_HASH(h, pp, x)
314 #define YOURS GH_HASH(h, pp + x, y - x)
315 #define OURS GH_HASH(h, pp + y, z - y)
316
317 #define HASH_in MINE; YOURS; OURS
318 #define HASH_out YOURS; MINE; OURS
319 #define INIT_c(k) GC_INIT(algs.c, (k), algs.cksz)
320 #define INIT_m(k) GM_KEY(algs.m, (k), algs.mksz)
321 #define STR_c "encryption"
322 #define STR_m "integrity"
323 #define STR_in "incoming"
324 #define STR_out "outgoing"
325
326 #define SETKEY(a, dir) do {                                             \
327   h = GH_INIT(algs.h);                                                  \
328   HASH_STRING(h, "tripe-" STR_##a);                                     \
329   HASH_##dir;                                                           \
330   hh = GH_DONE(h, 0);                                                   \
331   IF_TRACING(T_KEYSET, {                                                \
332     trace_block(T_CRYPTO, "crypto: " STR_##dir " key " STR_##a,         \
333                 hh, algs.a##ksz);                                       \
334   })                                                                    \
335   ks->a##dir = INIT_##a(hh);                                            \
336   GH_DESTROY(h);                                                        \
337 } while (0)
338
339   SETKEY(c, in); SETKEY(c, out);
340   SETKEY(m, in); SETKEY(m, out);
341
342 #undef MINE
343 #undef YOURS
344 #undef OURS
345 #undef STR_c
346 #undef STR_m
347 #undef STR_in
348 #undef STR_out
349 #undef INIT_c
350 #undef INIT_m
351 #undef HASH_in
352 #undef HASH_out
353 #undef SETKEY
354
355   T( ks->seq = seq++; )
356   ks->ref = 1;
357   ks->t_exp = now + T_EXP;
358   ks->sz_exp = SZ_EXP;
359   ks->oseq = 0;
360   seq_reset(&ks->iseq);
361   ks->next = 0;
362   ks->p = p;
363   ks->f = KSF_LISTEN;
364   ks->tagsz = algs.tagsz;
365   return (ks);
366 }
367
368 /* --- @ks_tregen@ --- *
369  *
370  * Arguments:   @keyset *ks@ = pointer to a keyset
371  *
372  * Returns:     The time at which moves ought to be made to replace this key.
373  */
374
375 time_t ks_tregen(keyset *ks) { return (ks->t_exp - T_EXP + T_REGEN); }
376
377 /* --- @ks_activate@ --- *
378  *
379  * Arguments:   @keyset *ks@ = pointer to a keyset
380  *
381  * Returns:     ---
382  *
383  * Use:         Activates a keyset, so that it can be used for encrypting
384  *              outgoing messages.
385  */
386
387 void ks_activate(keyset *ks)
388 {
389   if (ks->f & KSF_LISTEN) {
390     T( trace(T_KEYSET, "keyset: activating keyset %u", ks->seq); )
391     ks->f &= ~KSF_LISTEN;
392   }
393 }
394
395 /* --- @ks_encrypt@ --- *
396  *
397  * Arguments:   @keyset *ks@ = pointer to a keyset
398  *              @unsigned ty@ = message type
399  *              @buf *b@ = pointer to input buffer
400  *              @buf *bb@ = pointer to output buffer
401  *
402  * Returns:     Zero if OK, nonzero if the key needs replacing.  If the
403  *              encryption failed, the output buffer is broken and zero is
404  *              returned.
405  *
406  * Use:         Encrypts a block of data using the key.  Note that the `key
407  *              ought to be replaced' notification is only ever given once
408  *              for each key.  Also note that this call forces a keyset to be
409  *              used even if it's marked as not for data output.
410  */
411
412 int ks_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
413 {
414   time_t now = time(0);
415
416   if (!KEYOK(ks, now)) {
417     buf_break(bb);
418     return (0);
419   }
420   return (doencrypt(ks, ty, b, bb));
421 }
422
423 /* --- @ks_decrypt@ --- *
424  *
425  * Arguments:   @keyset *ks@ = pointer to a keyset
426  *              @unsigned ty@ = expected type code
427  *              @buf *b@ = pointer to an input buffer
428  *              @buf *bb@ = pointer to an output buffer
429  *
430  * Returns:     Zero on success, or nonzero if there was some problem.
431  *
432  * Use:         Attempts to decrypt a message using a given key.  Note that
433  *              requesting decryption with a key directly won't clear a
434  *              marking that it's not for encryption.
435  */
436
437 int ks_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
438 {
439   time_t now = time(0);
440   uint32 seq;
441
442   if (!KEYOK(ks, now) ||
443       buf_ensure(bb, BLEN(b)) ||
444       dodecrypt(ks, ty, b, bb, &seq) ||
445       seq_check(&ks->iseq, seq, "SYMM"))
446     return (-1);
447   return (0);
448 }
449
450 /*----- Keyset list handling ----------------------------------------------*/
451
452 /* --- @ksl_free@ --- *
453  *
454  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
455  *
456  * Returns:     ---
457  *
458  * Use:         Frees (releases references to) all of the keys in a keyset.
459  */
460
461 void ksl_free(keyset **ksroot)
462 {
463   keyset *ks, *ksn;
464   for (ks = *ksroot; ks; ks = ksn) {
465     ksn = ks->next;
466     ks->f &= ~KSF_LINK;
467     ks_drop(ks);
468   }
469 }
470
471 /* --- @ksl_link@ --- *
472  *
473  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
474  *              @keyset *ks@ = pointer to a keyset
475  *
476  * Returns:     ---
477  *
478  * Use:         Links a keyset into a list.  A keyset can only be on one list
479  *              at a time.  Bad things happen otherwise.
480  */
481
482 void ksl_link(keyset **ksroot, keyset *ks)
483 {
484   assert(!(ks->f & KSF_LINK));
485   ks->next = *ksroot;
486   *ksroot = ks;
487   ks->f |= KSF_LINK;
488   ks->ref++;
489 }
490
491 /* --- @ksl_prune@ --- *
492  *
493  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
494  *
495  * Returns:     ---
496  *
497  * Use:         Prunes the keyset list by removing keys which mustn't be used
498  *              any more.
499  */
500
501 void ksl_prune(keyset **ksroot)
502 {
503   time_t now = time(0);
504
505   while (*ksroot) {
506     keyset *ks = *ksroot;
507
508     if (ks->t_exp <= now) {
509       T( trace(T_KEYSET, "keyset: expiring keyset %u (time limit reached)",
510                ks->seq); )
511       goto kill;
512     } else if (ks->sz_exp == 0) {
513       T( trace(T_KEYSET, "keyset: expiring keyset %u (data limit reached)",
514                ks->seq); )
515       goto kill;
516     } else {
517       ksroot = &ks->next;
518       continue;
519     }
520
521   kill:
522     *ksroot = ks->next;
523     ks->f &= ~KSF_LINK;
524     ks_drop(ks);
525   }
526 }
527
528 /* --- @ksl_encrypt@ --- *
529  *
530  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
531  *              @unsigned ty@ = message type
532  *              @buf *b@ = pointer to input buffer
533  *              @buf *bb@ = pointer to output buffer
534  *
535  * Returns:     Nonzero if a new key is needed.
536  *
537  * Use:         Encrypts a packet.
538  */
539
540 int ksl_encrypt(keyset **ksroot, unsigned ty, buf *b, buf *bb)
541 {
542   time_t now = time(0);
543   keyset *ks = *ksroot;
544
545   for (;;) {
546     if (!ks) {
547       T( trace(T_KEYSET, "keyset: no suitable keysets found"); )
548       buf_break(bb);
549       return (-1);
550     }
551     if (KEYOK(ks, now) && !(ks->f & KSF_LISTEN))
552       break;
553     ks = ks->next;
554   }
555
556   return (doencrypt(ks, ty, b, bb));
557 }
558
559 /* --- @ksl_decrypt@ --- *
560  *
561  * Arguments:   @keyset **ksroot@ = pointer to keyset list head
562  *              @unsigned ty@ = expected type code
563  *              @buf *b@ = pointer to input buffer
564  *              @buf *bb@ = pointer to output buffer
565  *
566  * Returns:     Nonzero if the packet couldn't be decrypted.
567  *
568  * Use:         Decrypts a packet.
569  */
570
571 int ksl_decrypt(keyset **ksroot, unsigned ty, buf *b, buf *bb)
572 {
573   time_t now = time(0);
574   keyset *ks;
575   uint32 seq;
576
577   if (buf_ensure(bb, BLEN(b)))
578     return (-1);
579
580   for (ks = *ksroot; ks; ks = ks->next) {
581     if (!KEYOK(ks, now))
582       continue;
583     if (!dodecrypt(ks, ty, b, bb, &seq)) {
584       if (ks->f & KSF_LISTEN) {
585         T( trace(T_KEYSET, "keyset: implicitly activating keyset %u",
586                  ks->seq); )
587         ks->f &= ~KSF_LISTEN;
588       }
589       return (seq_check(&ks->iseq, seq, "SYMM"));
590     }
591   }
592   T( trace(T_KEYSET, "keyset: no matching keys, or incorrect MAC"); )
593   return (-1);
594 }
595
596 /*----- That's all, folks -------------------------------------------------*/