01def8cfbc6043f04f2b4e54feae983a7aa7435d
[u/mdw/catacomb] / key-data.c
1 /* -*-c-*-
2 *
3 * $Id: key-data.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
4 *
5 * Encoding and decoding of key data
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30 /*----- Revision history --------------------------------------------------*
31 *
32 * $Log: key-data.c,v $
33 * Revision 1.1 1999/12/22 15:47:48 mdw
34 * Major key-management revision.
35 *
36 */
37
38 /*----- Header files ------------------------------------------------------*/
39
40 #include <assert.h>
41 #include <stdlib.h>
42 #include <string.h>
43
44 #include <mLib/alloc.h>
45 #include <mLib/base64.h>
46 #include <mLib/bits.h>
47 #include <mLib/dstr.h>
48 #include <mLib/sub.h>
49 #include <mLib/sym.h>
50
51 #include "key.h"
52 #include "mp.h"
53 #include "mptext.h"
54
55 /*----- Disposal ----------------------------------------------------------*/
56
57 /* --- @key_destroy@ --- *
58 *
59 * Arguments: @key_data *k@ = pointer to key data to destroy
60 *
61 * Returns: ---
62 *
63 * Use: Destroys a lump of key data.
64 */
65
66 void key_destroy(key_data *k)
67 {
68 switch (k->e & KF_ENCMASK) {
69 case KENC_BINARY:
70 case KENC_ENCRYPT:
71 if (k->e & KF_BURN)
72 memset(k->u.k.k, 0, k->u.k.sz);
73 sub_free(k->u.k.k, k->u.k.sz);
74 break;
75 case KENC_MP:
76 mp_drop(k->u.m);
77 break;
78 case KENC_STRUCT: {
79 sym_iter i;
80 key_struct *ks;
81
82 for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; )
83 key_destroy(&ks->k);
84 sym_destroy(&k->u.s);
85 } break;
86 }
87 }
88
89 /*----- Setting new values ------------------------------------------------*/
90
91 /* --- @key_binary@ --- *
92 *
93 * Arguments: @key_data *k@ = pointer to key data block
94 * @const void *p@ = pointer to key data
95 * @size_t sz@ = size of the key data
96 *
97 * Returns: ---
98 *
99 * Use: Sets a binary key in a key data block.
100 */
101
102 void key_binary(key_data *k, const void *p, size_t sz)
103 {
104 k->e = (k->e & ~KF_ENCMASK) | KENC_BINARY;
105 k->u.k.k = sub_alloc(sz);
106 memcpy(k->u.k.k, p, sz);
107 k->u.k.sz = sz;
108 }
109
110 /* --- @key_encrypted@ --- *
111 *
112 * Arguments: @key_data *k@ = pointer to key data block
113 * @const void *p@ = pointer to key data
114 * @size_t sz@ = size of the key data
115 *
116 * Returns: ---
117 *
118 * Use: Sets an encrypted key in a key data block.
119 */
120
121 void key_encrypted(key_data *k, const void *p, size_t sz)
122 {
123 k->e = (k->e & ~KF_ENCMASK) | KENC_ENCRYPT;
124 k->u.k.k = sub_alloc(sz);
125 memcpy(k->u.k.k, p, sz);
126 k->u.k.sz = sz;
127 }
128
129 /* --- @key_mp@ --- *
130 *
131 * Arguments: @key_data *k@ = pointer to key data block
132 * @mp *m@ = pointer to the value to set
133 *
134 * Returns: ---
135 *
136 * Use: Sets a multiprecision integer key in a key block.
137 */
138
139 void key_mp(key_data *k, mp *m)
140 {
141 k->e = (k->e & ~KF_ENCMASK) | KENC_MP;
142 k->u.m = MP_COPY(m);
143 }
144
145 /* --- @key_structure@ --- *
146 *
147 * Arguments: @key_data *k@ = pointer to key data block
148 *
149 * Returns: ---
150 *
151 * Use: Initializes a structured key type.
152 */
153
154 void key_structure(key_data *k)
155 {
156 k->e = KENC_STRUCT;
157 sym_create(&k->u.s);
158 }
159
160 /* --- @key_structfind@ --- *
161 *
162 * Arguments: @key_data *k@ = pointer to key data block
163 * @const char *tag@ = pointer to tag string
164 *
165 * Returns: Pointer to key data block, or null.
166 *
167 * Use: Looks up the tag in a structured key.
168 */
169
170 key_data *key_structfind(key_data *k, const char *tag)
171 {
172 key_struct *ks;
173 assert(((void)"Key is not structured", k->e == KENC_STRUCT));
174 ks = sym_find(&k->u.s, tag, -1, 0, 0);
175 return (&ks->k);
176 }
177
178 /* --- @key_structcreate@ --- *
179 *
180 * Arguments: @key_data *k@ = pointer to key data block
181 * @const char *tag@ = pointer to tag string
182 *
183 * Returns: Pointer to newly created key data.
184 *
185 * Use: Creates a new uninitialized subkey.
186 */
187
188 key_data *key_structcreate(key_data *k, const char *tag)
189 {
190 key_struct *ks;
191 unsigned f;
192
193 assert(((void)"Key is not structured", k->e == KENC_STRUCT));
194 ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f);
195 if (f)
196 key_destroy(&ks->k);
197 ks->k.e = 0;
198 return (&ks->k);
199 }
200
201 /* --- @key_match@ --- *
202 *
203 * Arguments: @key_data *k@ = pointer to key data block
204 * @const key_filter *kf@ = pointer to filter block
205 *
206 * Returns: Nonzero if the key matches the filter.
207 *
208 * Use: Checks whether a key matches a filter.
209 */
210
211 int key_match(key_data *k, const key_filter *kf)
212 {
213 sym_iter i;
214 key_struct *ks;
215
216 if (!kf)
217 return (1);
218 if ((k->e & KF_ENCMASK) != KENC_STRUCT)
219 return ((k->e & kf->m) == kf->f);
220
221 for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
222 if (key_match(&ks->k, kf))
223 return (1);
224 }
225 return (0);
226 }
227
228 /* --- @key_do@ --- *
229 *
230 * Arguments: @key_data *k@ = pointer to key data block
231 * @const key_filter *kf@ = pointer to filter block
232 * @dstr *d@ = pointer to base string
233 * @int (*func)(key_data *kd, dstr *d, void *p@ = function
234 * @void *p@ = argument to function
235 *
236 * Returns: Nonzero return code from function, or zero.
237 *
238 * Use: Runs a function over all the leaves of a key.
239 */
240
241 int key_do(key_data *k, const key_filter *kf, dstr *d,
242 int (*func)(key_data */*kd*/, dstr */*d*/, void */*p*/),
243 void *p)
244 {
245 if (!KEY_MATCH(k, kf))
246 return (0);
247 if ((k->e & KF_ENCMASK) != KENC_STRUCT)
248 return (func(k, d, p));
249 else {
250 sym_iter i;
251 key_struct *ks;
252 size_t n;
253 int rc;
254
255 if (d)
256 n = d->len;
257 for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
258 if (d) {
259 d->len = n;
260 dstr_putf(d, ".%s", SYM_NAME(ks));
261 }
262 if ((rc = key_do(&ks->k, kf, d, func, p)) != 0)
263 return (rc);
264 }
265 return (0);
266 }
267 }
268
269 /*----- Copying -----------------------------------------------------------*/
270
271 /* --- @key_copy@ --- *
272 *
273 * Arguments: @key_data *kd@ = pointer to destination data block
274 * @key_data *k@ = pointer to source data block
275 * @const key_filter *kf@ = pointer to filter block
276 *
277 * Returns: Nonzero if an item was actually copied.
278 *
279 * Use: Copies a chunk of key data from one place to another.
280 */
281
282 int key_copy(key_data *kd, key_data *k, const key_filter *kf)
283 {
284 kd->e = k->e;
285
286 if (!KEY_MATCH(kd, kf))
287 return (0);
288 switch (k->e & KF_ENCMASK) {
289
290 /* --- Plain binary data --- */
291
292 case KENC_BINARY:
293 case KENC_ENCRYPT:
294 kd->u.k.k = sub_alloc(k->u.k.sz);
295 memcpy(kd->u.k.k, k->u.k.k, k->u.k.sz);
296 kd->u.k.sz = k->u.k.sz;
297 break;
298
299 /* --- Multiprecision integers --- */
300
301 case KENC_MP:
302 kd->u.m = MP_COPY(k->u.m);
303 break;
304
305 /* --- Structured key data --- */
306
307 case KENC_STRUCT: {
308 sym_iter i;
309 key_struct *ks;
310 int rc = 0;
311
312 sym_create(&kd->u.s);
313 for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
314 unsigned f;
315 key_struct *kks = sym_find(&kd->u.s, SYM_NAME(ks), -1,
316 sizeof(*kks), &f);
317 assert(((void)"Duplicate subkey tags", !f));
318 if (key_copy(&kks->k, &ks->k, kf))
319 rc = 1;
320 else
321 sym_remove(&kd->u.s, kks);
322 }
323 if (!rc) {
324 sym_destroy(&kd->u.s);
325 return (0);
326 }
327 } break;
328 }
329 return (1);
330 }
331
332 /*----- Textual encoding --------------------------------------------------*/
333
334 /* --- @key_read@ --- *
335 *
336 * Arguments: @const char *p@ = pointer to textual key representation
337 * @key_data *k@ = pointer to output block for key data
338 * @char **pp@ = where to store the end pointer
339 *
340 * Returns: Zero if all went well, nonzero if there was a problem.
341 *
342 * Use: Parses a textual key description.
343 */
344
345 int key_read(const char *p, key_data *k, char **pp)
346 {
347 unsigned e;
348
349 /* --- Read the encoding type --- *
350 *
351 * The key format is `[FLAGS:]DATA'. If there is no encoding type
352 * named, assume that it's `binary' for backwards compatibility.
353 */
354
355 if (strchr(p, ':') == 0)
356 e = 0;
357 else {
358 char *q;
359 if (key_readflags(p, &q, &e, 0))
360 return (-1);
361 p = q + 1;
362 }
363
364 /* --- Now scan the data based on the encoding type --- */
365
366 k->e = e;
367 switch (e & KF_ENCMASK) {
368
369 /* --- Binary encoding --- *
370 *
371 * Simply read out the Base64-encoded data. Since `,' and `]' are our
372 * delimeter characters, and they can't appear in Base64-encoded data, I
373 * can just do a simple search to find the end of the encoded data.
374 */
375
376 case KENC_BINARY:
377 case KENC_ENCRYPT: {
378 dstr d = DSTR_INIT;
379 base64_ctx b;
380 size_t sz = strcspn(p, ",]");
381
382 base64_init(&b);
383 base64_decode(&b, p, sz, &d);
384 base64_decode(&b, 0, 0, &d);
385 k->u.k.k = sub_alloc(d.len);
386 k->u.k.sz = d.len;
387 memcpy(k->u.k.k, d.buf, d.len);
388 dstr_destroy(&d);
389 p += sz;
390 } break;
391
392 /* --- Multiprecision integer encoding --- *
393 *
394 * Multiprecision integers have a convenient reading function.
395 */
396
397 case KENC_MP: {
398 char *q;
399 mp *m = mp_readstring(MP_NEW, p, &q, 0);
400 if (!m)
401 return (-1);
402 if (k->e & KF_BURN)
403 mp_burn(m);
404 k->u.m = m;
405 p = q;
406 } break;
407
408 /* --- Structured information encoding --- *
409 *
410 * The format for structured key data is `[NAME=KEY,...]', where the
411 * brackets are part of the syntax. Structured keys have no flags apart
412 * from the encoding.
413 *
414 * The binary encoding only allows names up to 255 bytes long. Check for
415 * this here.
416 */
417
418 case KENC_STRUCT: {
419 dstr d = DSTR_INIT;
420 char *q;
421
422 /* --- Read the opening bracket --- */
423
424 k->e &= KF_ENCMASK;
425 if (*p != '[')
426 return (-1);
427 p++;
428 sym_create(&k->u.s);
429
430 /* --- Read named key subparts --- */
431
432 for (;;) {
433 size_t sz;
434 key_struct *ks;
435
436 /* --- Stop if there's a close-bracket --- *
437 *
438 * This allows `[]' to be an empty structured key, which is good. It
439 * also makes `[foo=enc:bar,]' legal, and that's less good but I can
440 * live with it.
441 */
442
443 if (*p == ']')
444 break;
445
446 /* --- Read the name out and check the length --- */
447
448 if ((q = strchr(p, '=')) == 0)
449 goto fail;
450 sz = q - p;
451 if (sz >= 256)
452 goto fail;
453 DRESET(&d);
454 DPUTM(&d, p, sz);
455 DPUTZ(&d);
456
457 /* --- Add an appropriate block to the key table --- *
458 *
459 * Simply destroy old data if there's already a match.
460 */
461
462 {
463 unsigned f;
464 ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f);
465 if (f)
466 key_destroy(&ks->k);
467 }
468
469 /* --- Read the key data for the subkey --- */
470
471 if (key_read(q + 1, &ks->k, &q)) {
472 sym_remove(&k->u.s, ks);
473 goto fail;
474 }
475 p = q;
476
477 /* --- Read the comma or close-bracket --- */
478
479 if (*p == ']')
480 break;
481 else if (*p == ',')
482 p++;
483 else
484 goto fail;
485 }
486
487 /* --- Step past the close bracket --- */
488
489 p++;
490 dstr_destroy(&d);
491 break;
492
493 /* --- Tidy up after a failure --- */
494
495 fail:
496 dstr_destroy(&d);
497 key_destroy(k);
498 return (-1);
499 } break;
500
501 /* --- Anything else is unknown --- */
502
503 default:
504 return (-1);
505 }
506
507 /* --- Return the end pointer --- */
508
509 if (pp)
510 *pp = (char *)p;
511 return (0);
512 }
513
514 /* --- @key_write@ --- *
515 *
516 * Arguments: @key_data *k@ = pointer to key data
517 * @dstr *d@ = destination string to write on
518 * @const key_filter *kf@ = pointer to key selection block
519 *
520 * Returns: Nonzero if an item was actually written.
521 *
522 * Use: Writes a key in a textual encoding.
523 */
524
525 int key_write(key_data *k, dstr *d, const key_filter *kf)
526 {
527 int rc = 0;
528 if (!KEY_MATCH(k, kf))
529 return (0);
530 switch (k->e & KF_ENCMASK) {
531 case KENC_BINARY:
532 case KENC_ENCRYPT: {
533 base64_ctx b;
534
535 if ((k->e & KF_ENCMASK) == KENC_BINARY)
536 key_writeflags(k->e, d);
537 else
538 DPUTS(d, "encrypt,secret");
539 DPUTC(d, ':');
540 base64_init(&b);
541 b.indent = "";
542 b.maxline = 0;
543 base64_encode(&b, k->u.k.k, k->u.k.sz, d);
544 base64_encode(&b, 0, 0, d);
545 rc = 1;
546 } break;
547 case KENC_MP:
548 key_writeflags(k->e, d);
549 DPUTC(d, ':');
550 mp_writedstr(k->u.m, d, 10);
551 rc = 1;
552 break;
553 case KENC_STRUCT: {
554 sym_iter i;
555 key_struct *ks;
556 char del = 0;
557 size_t n = d->len;
558
559 DPUTS(d, "struct:[");
560 for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
561 size_t o = d->len;
562 if (del)
563 DPUTC(d, del);
564 DPUTS(d, SYM_NAME(ks));
565 DPUTC(d, '=');
566 if (!key_write(&ks->k, d, kf))
567 d->len = o;
568 else {
569 del = ',';
570 rc = 1;
571 }
572 }
573 if (!rc)
574 d->len = n;
575 else
576 DPUTC(d, ']');
577 } break;
578 }
579 DPUTZ(d);
580
581 return (rc);
582 }
583
584 /*----- Binary encoding ---------------------------------------------------*/
585
586 /* --- @key_decode@ --- *
587 *
588 * Arguments: @const void *p@ = pointer to buffer to read
589 * @size_t sz@ = size of the buffer
590 * @key_data *k@ = pointer to key data block to write to
591 *
592 * Returns: Zero if everything worked, nonzero otherwise.
593 *
594 * Use: Decodes a binary representation of a key.
595 */
596
597 int key_decode(const void *p, size_t sz, key_data *k)
598 {
599 const octet *q = p;
600 size_t psz;
601 unsigned e;
602
603 /* --- Parse the header information --- *
604 *
605 * Make sure the size matches external reality. Security holes have been
606 * known to creep in without this sort of check. (No, this isn't an after-
607 * the-fact patch-up.)
608 */
609
610 e = LOAD16(q);
611 psz = LOAD16(q + 2);
612 if (psz + 4 > sz)
613 return (-1);
614 k->e = e;
615
616 /* --- Now decide what to do --- */
617
618 switch (e & KF_ENCMASK) {
619
620 /* --- Plain binary data --- */
621
622 case KENC_BINARY:
623 case KENC_ENCRYPT:
624 k->u.k.k = sub_alloc(psz);
625 memcpy(k->u.k.k, q + 4, psz);
626 k->u.k.sz = psz;
627 break;
628
629 /* --- Multiprecision integer data --- */
630
631 case KENC_MP:
632 k->u.m = mp_loadb(MP_NEW, q + 4, psz);
633 if (k->e & KF_BURN)
634 mp_burn(k->u.m);
635 break;
636
637 /* --- Structured key data --- */
638
639 case KENC_STRUCT: {
640 dstr d = DSTR_INIT;
641 key_struct *ks;
642 unsigned f;
643
644 if ((k->e & ~KF_ENCMASK) || (psz & 3))
645 return (-1);
646 q += 4;
647 sym_create(&k->u.s);
648
649 while (psz) {
650
651 /* --- Read the tag string --- */
652
653 DRESET(&d);
654 sz = LOAD8(q);
655 if (sz >= psz)
656 goto fail;
657 DPUTM(&d, q + 1, sz);
658 DPUTZ(&d);
659 sz = (sz + 4) & ~3;
660 q += sz; psz -= sz;
661
662 /* --- Read the encoding and size --- */
663
664 e = LOAD16(q);
665 sz = (LOAD16(q + 2) + 7) & ~3;
666 if (sz > psz)
667 goto fail;
668
669 /* --- Create a table node and fill it in --- */
670
671 ks = sym_find(&k->u.s, d.buf, d.len + 1, sizeof(*ks), &f);
672 if (f)
673 goto fail;
674 if (key_decode(q, sz, &ks->k)) {
675 sym_remove(&k->u.s, ks);
676 goto fail;
677 }
678 psz -= sz;
679 q += sz;
680 }
681 dstr_destroy(&d);
682 break;
683
684 /* --- Tidy up after a failure --- */
685
686 fail:
687 dstr_destroy(&d);
688 key_destroy(k);
689 return (-1);
690 } break;
691
692 /* --- Everything else --- */
693
694 default:
695 return (-1);
696 }
697
698 /* --- OK, that was good --- */
699
700 return (0);
701 }
702
703 /* --- @key_encode@ --- *
704 *
705 * Arguments: @key_data *k@ = pointer to key data block
706 * @dstr *d@ = pointer to destination string
707 * @const key_filter *kf@ = pointer to key selection block
708 *
709 * Returns: Nonzero if an item was actually written.
710 *
711 * Use: Encodes a key block as binary data.
712 */
713
714 int key_encode(key_data *k, dstr *d, const key_filter *kf)
715 {
716 int rc = 0;
717 if (!KEY_MATCH(k, kf))
718 return (0);
719 switch (k->e & KF_ENCMASK) {
720 case KENC_BINARY:
721 case KENC_ENCRYPT: {
722 char *p;
723
724 DENSURE(d, (k->u.k.sz + 7) & ~3);
725 p = d->buf + d->len;
726 STORE16(p, k->e);
727 STORE16(p + 2, k->u.k.sz);
728 d->len += 4;
729 DPUTM(d, k->u.k.k, k->u.k.sz);
730 rc = 1;
731 } break;
732
733 case KENC_MP: {
734 char *p;
735 size_t sz = mp_octets(k->u.m);
736
737 DENSURE(d, (sz + 7) & ~3);
738 p = d->buf + d->len;
739 STORE16(p, k->e);
740 STORE16(p + 2, sz);
741 mp_storeb(k->u.m, p + 4, sz);
742 d->len += sz + 4;
743 rc = 1;
744 } break;
745
746 case KENC_STRUCT: {
747 size_t n;
748 char *p;
749 key_struct *ks;
750 sym_iter i;
751
752 n = d->len;
753 DENSURE(d, 4);
754 p = d->buf + n;
755 STORE16(p, k->e & KF_ENCMASK);
756 d->len += 4;
757 for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
758 size_t o = d->len;
759 DENSURE(d, 1);
760 *(octet *)(d->buf + d->len++) = strlen(SYM_NAME(ks));
761 DPUTS(d, SYM_NAME(ks));
762 while (d->len & 3)
763 DPUTC(d, 0);
764 if (key_encode(&ks->k, d, kf))
765 rc = 1;
766 else
767 d->len = o;
768 }
769 if (!rc)
770 d->len = n;
771 else {
772 p = d->buf + n + 2;
773 n = d->len - n - 4;
774 STORE16(p, n);
775 }
776 } break;
777 }
778 while (d->len & 3)
779 DPUTC(d, 0);
780 return (rc);
781 }
782
783 /*----- That's all, folks -------------------------------------------------*/