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