3 * $Id: key-data.c,v 1.1 1999/12/22 15:47:48 mdw Exp $
5 * Encoding and decoding of key data
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
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.
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.
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,
30 /*----- Revision history --------------------------------------------------*
32 * $Log: key-data.c,v $
33 * Revision 1.1 1999/12/22 15:47:48 mdw
34 * Major key-management revision.
38 /*----- Header files ------------------------------------------------------*/
44 #include <mLib/alloc.h>
45 #include <mLib/base64.h>
46 #include <mLib/bits.h>
47 #include <mLib/dstr.h>
55 /*----- Disposal ----------------------------------------------------------*/
57 /* --- @key_destroy@ --- *
59 * Arguments: @key_data *k@ = pointer to key data to destroy
63 * Use: Destroys a lump of key data.
66 void key_destroy(key_data
*k
)
68 switch (k
->e
& KF_ENCMASK
) {
72 memset(k
->u
.k
.k
, 0, k
->u
.k
.sz
);
73 sub_free(k
->u
.k
.k
, k
->u
.k
.sz
);
82 for (sym_mkiter(&i
, &k
->u
.s
); (ks
= sym_next(&i
)) != 0; )
89 /*----- Setting new values ------------------------------------------------*/
91 /* --- @key_binary@ --- *
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
99 * Use: Sets a binary key in a key data block.
102 void key_binary(key_data
*k
, const void *p
, size_t sz
)
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
);
110 /* --- @key_encrypted@ --- *
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
118 * Use: Sets an encrypted key in a key data block.
121 void key_encrypted(key_data
*k
, const void *p
, size_t sz
)
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
);
129 /* --- @key_mp@ --- *
131 * Arguments: @key_data *k@ = pointer to key data block
132 * @mp *m@ = pointer to the value to set
136 * Use: Sets a multiprecision integer key in a key block.
139 void key_mp(key_data
*k
, mp
*m
)
141 k
->e
= (k
->e
& ~KF_ENCMASK
) | KENC_MP
;
145 /* --- @key_structure@ --- *
147 * Arguments: @key_data *k@ = pointer to key data block
151 * Use: Initializes a structured key type.
154 void key_structure(key_data
*k
)
160 /* --- @key_structfind@ --- *
162 * Arguments: @key_data *k@ = pointer to key data block
163 * @const char *tag@ = pointer to tag string
165 * Returns: Pointer to key data block, or null.
167 * Use: Looks up the tag in a structured key.
170 key_data
*key_structfind(key_data
*k
, const char *tag
)
173 assert(((void)"Key is not structured", k
->e
== KENC_STRUCT
));
174 ks
= sym_find(&k
->u
.s
, tag
, -1, 0, 0);
178 /* --- @key_structcreate@ --- *
180 * Arguments: @key_data *k@ = pointer to key data block
181 * @const char *tag@ = pointer to tag string
183 * Returns: Pointer to newly created key data.
185 * Use: Creates a new uninitialized subkey.
188 key_data
*key_structcreate(key_data
*k
, const char *tag
)
193 assert(((void)"Key is not structured", k
->e
== KENC_STRUCT
));
194 ks
= sym_find(&k
->u
.s
, tag
, -1, sizeof(*ks
), &f
);
201 /* --- @key_match@ --- *
203 * Arguments: @key_data *k@ = pointer to key data block
204 * @const key_filter *kf@ = pointer to filter block
206 * Returns: Nonzero if the key matches the filter.
208 * Use: Checks whether a key matches a filter.
211 int key_match(key_data
*k
, const key_filter
*kf
)
218 if ((k
->e
& KF_ENCMASK
) != KENC_STRUCT
)
219 return ((k
->e
& kf
->m
) == kf
->f
);
221 for (sym_mkiter(&i
, &k
->u
.s
); (ks
= sym_next(&i
)) != 0; ) {
222 if (key_match(&ks
->k
, kf
))
228 /* --- @key_do@ --- *
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
236 * Returns: Nonzero return code from function, or zero.
238 * Use: Runs a function over all the leaves of a key.
241 int key_do(key_data
*k
, const key_filter
*kf
, dstr
*d
,
242 int (*func
)(key_data */
*kd*/
, dstr */
*d*/
, void */
*p*/
),
245 if (!KEY_MATCH(k
, kf
))
247 if ((k
->e
& KF_ENCMASK
) != KENC_STRUCT
)
248 return (func(k
, d
, p
));
257 for (sym_mkiter(&i
, &k
->u
.s
); (ks
= sym_next(&i
)) != 0; ) {
260 dstr_putf(d
, ".%s", SYM_NAME(ks
));
262 if ((rc
= key_do(&ks
->k
, kf
, d
, func
, p
)) != 0)
269 /*----- Copying -----------------------------------------------------------*/
271 /* --- @key_copy@ --- *
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
277 * Returns: Nonzero if an item was actually copied.
279 * Use: Copies a chunk of key data from one place to another.
282 int key_copy(key_data
*kd
, key_data
*k
, const key_filter
*kf
)
286 if (!KEY_MATCH(kd
, kf
))
288 switch (k
->e
& KF_ENCMASK
) {
290 /* --- Plain binary data --- */
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
;
299 /* --- Multiprecision integers --- */
302 kd
->u
.m
= MP_COPY(k
->u
.m
);
305 /* --- Structured key data --- */
312 sym_create(&kd
->u
.s
);
313 for (sym_mkiter(&i
, &k
->u
.s
); (ks
= sym_next(&i
)) != 0; ) {
315 key_struct
*kks
= sym_find(&kd
->u
.s
, SYM_NAME(ks
), -1,
317 assert(((void)"Duplicate subkey tags", !f
));
318 if (key_copy(&kks
->k
, &ks
->k
, kf
))
321 sym_remove(&kd
->u
.s
, kks
);
324 sym_destroy(&kd
->u
.s
);
332 /*----- Textual encoding --------------------------------------------------*/
334 /* --- @key_read@ --- *
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
340 * Returns: Zero if all went well, nonzero if there was a problem.
342 * Use: Parses a textual key description.
345 int key_read(const char *p
, key_data
*k
, char **pp
)
349 /* --- Read the encoding type --- *
351 * The key format is `[FLAGS:]DATA'. If there is no encoding type
352 * named, assume that it's `binary' for backwards compatibility.
355 if (strchr(p
, ':') == 0)
359 if (key_readflags(p
, &q
, &e
, 0))
364 /* --- Now scan the data based on the encoding type --- */
367 switch (e
& KF_ENCMASK
) {
369 /* --- Binary encoding --- *
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.
380 size_t sz
= strcspn(p
, ",]");
383 base64_decode(&b
, p
, sz
, &d
);
384 base64_decode(&b
, 0, 0, &d
);
385 k
->u
.k
.k
= sub_alloc(d
.len
);
387 memcpy(k
->u
.k
.k
, d
.buf
, d
.len
);
392 /* --- Multiprecision integer encoding --- *
394 * Multiprecision integers have a convenient reading function.
399 mp
*m
= mp_readstring(MP_NEW
, p
, &q
, 0);
408 /* --- Structured information encoding --- *
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
414 * The binary encoding only allows names up to 255 bytes long. Check for
422 /* --- Read the opening bracket --- */
430 /* --- Read named key subparts --- */
436 /* --- Stop if there's a close-bracket --- *
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
446 /* --- Read the name out and check the length --- */
448 if ((q
= strchr(p
, '=')) == 0)
457 /* --- Add an appropriate block to the key table --- *
459 * Simply destroy old data if there's already a match.
464 ks
= sym_find(&k
->u
.s
, d
.buf
, d
.len
+ 1, sizeof(*ks
), &f
);
469 /* --- Read the key data for the subkey --- */
471 if (key_read(q
+ 1, &ks
->k
, &q
)) {
472 sym_remove(&k
->u
.s
, ks
);
477 /* --- Read the comma or close-bracket --- */
487 /* --- Step past the close bracket --- */
493 /* --- Tidy up after a failure --- */
501 /* --- Anything else is unknown --- */
507 /* --- Return the end pointer --- */
514 /* --- @key_write@ --- *
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
520 * Returns: Nonzero if an item was actually written.
522 * Use: Writes a key in a textual encoding.
525 int key_write(key_data
*k
, dstr
*d
, const key_filter
*kf
)
528 if (!KEY_MATCH(k
, kf
))
530 switch (k
->e
& KF_ENCMASK
) {
535 if ((k
->e
& KF_ENCMASK
) == KENC_BINARY
)
536 key_writeflags(k
->e
, d
);
538 DPUTS(d
, "encrypt,secret");
543 base64_encode(&b
, k
->u
.k
.k
, k
->u
.k
.sz
, d
);
544 base64_encode(&b
, 0, 0, d
);
548 key_writeflags(k
->e
, d
);
550 mp_writedstr(k
->u
.m
, d
, 10);
559 DPUTS(d
, "struct:[");
560 for (sym_mkiter(&i
, &k
->u
.s
); (ks
= sym_next(&i
)) != 0; ) {
564 DPUTS(d
, SYM_NAME(ks
));
566 if (!key_write(&ks
->k
, d
, kf
))
584 /*----- Binary encoding ---------------------------------------------------*/
586 /* --- @key_decode@ --- *
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
592 * Returns: Zero if everything worked, nonzero otherwise.
594 * Use: Decodes a binary representation of a key.
597 int key_decode(const void *p
, size_t sz
, key_data
*k
)
603 /* --- Parse the header information --- *
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.)
616 /* --- Now decide what to do --- */
618 switch (e
& KF_ENCMASK
) {
620 /* --- Plain binary data --- */
624 k
->u
.k
.k
= sub_alloc(psz
);
625 memcpy(k
->u
.k
.k
, q
+ 4, psz
);
629 /* --- Multiprecision integer data --- */
632 k
->u
.m
= mp_loadb(MP_NEW
, q
+ 4, psz
);
637 /* --- Structured key data --- */
644 if ((k
->e
& ~KF_ENCMASK
) || (psz
& 3))
651 /* --- Read the tag string --- */
657 DPUTM(&d
, q
+ 1, sz
);
662 /* --- Read the encoding and size --- */
665 sz
= (LOAD16(q
+ 2) + 7) & ~3;
669 /* --- Create a table node and fill it in --- */
671 ks
= sym_find(&k
->u
.s
, d
.buf
, d
.len
+ 1, sizeof(*ks
), &f
);
674 if (key_decode(q
, sz
, &ks
->k
)) {
675 sym_remove(&k
->u
.s
, ks
);
684 /* --- Tidy up after a failure --- */
692 /* --- Everything else --- */
698 /* --- OK, that was good --- */
703 /* --- @key_encode@ --- *
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
709 * Returns: Nonzero if an item was actually written.
711 * Use: Encodes a key block as binary data.
714 int key_encode(key_data
*k
, dstr
*d
, const key_filter
*kf
)
717 if (!KEY_MATCH(k
, kf
))
719 switch (k
->e
& KF_ENCMASK
) {
724 DENSURE(d
, (k
->u
.k
.sz
+ 7) & ~3);
727 STORE16(p
+ 2, k
->u
.k
.sz
);
729 DPUTM(d
, k
->u
.k
.k
, k
->u
.k
.sz
);
735 size_t sz
= mp_octets(k
->u
.m
);
737 DENSURE(d
, (sz
+ 7) & ~3);
741 mp_storeb(k
->u
.m
, p
+ 4, sz
);
755 STORE16(p
, k
->e
& KF_ENCMASK
);
757 for (sym_mkiter(&i
, &k
->u
.s
); (ks
= sym_next(&i
)) != 0; ) {
760 *(octet
*)(d
->buf
+ d
->len
++) = strlen(SYM_NAME(ks
));
761 DPUTS(d
, SYM_NAME(ks
));
764 if (key_encode(&ks
->k
, d
, kf
))
783 /*----- That's all, folks -------------------------------------------------*/