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