d11a0bf7 |
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 -------------------------------------------------*/ |