chiark / gitweb /
c1ef53b2397ec4d9b424a3668cb2a24c5edc974d
[catacomb] / key-binary.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Key binary encoding
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 /*----- Header files ------------------------------------------------------*/
31
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include <mLib/bits.h>
36 #include <mLib/dstr.h>
37 #include <mLib/sub.h>
38 #include <mLib/sym.h>
39
40 #include "key-data.h"
41 #include "mp.h"
42 #include "mptext.h"
43
44 /*----- Main code ---------------------------------------------------------*/
45
46 /* --- @key_decode@ --- *
47  *
48  * Arguments:   @const void *p@ = pointer to buffer to read
49  *              @size_t sz@ = size of the buffer
50  *
51  * Returns:     The newly-read key data, or null if it failed.
52  *
53  * Use:         Decodes a binary representation of a key.
54  */
55
56 key_data *key_decode(const void *p, size_t sz)
57 {
58   const octet *q = p;
59   size_t psz;
60   key_data *kd;
61   unsigned e;
62
63   /* --- Parse the header information --- *
64    *
65    * Make sure the size matches external reality.  Security holes have been
66    * known to creep in without this sort of check.  (No, this isn't an after-
67    * the-fact patch-up.)
68    */
69
70   e = LOAD16(q);
71   psz = LOAD16(q + 2);
72   if (psz + 4 > sz)
73     return (0);
74
75   /* --- Now decide what to do --- */
76
77   switch (e & KF_ENCMASK) {
78
79     /* --- Plain binary data --- */
80
81     case KENC_BINARY:
82     case KENC_ENCRYPT:
83       kd = key_newbinary(e, q + 4, psz);
84       break;
85
86     /* --- Multiprecision integer data --- */
87
88     case KENC_MP:
89       kd = key_newmp(e, mp_loadb(e & KF_BURN ? MP_NEWSEC : MP_NEW,
90                                  q + 4, psz));
91       break;
92
93     /* --- String data --- */
94
95     case KENC_STRING:
96       kd = key_newraw(e);
97       kd->u.p = xmalloc(sz + 1);
98       memcpy(kd->u.p, q + 4, sz);
99       kd->u.p[sz] = 0;
100       break;
101
102     /* --- Elliptic curve point data --- */
103
104     case KENC_EC: {
105       size_t xsz, ysz;
106       kd = key_newraw(e);
107       EC_CREATE(&kd->u.e);
108       if (!sz) break;
109       if (sz < 2) return (0);
110       xsz = LOAD16(q + 4);
111       if (sz < xsz + 4) return (0);
112       ysz = LOAD16(q + 6 + xsz);
113       if (sz < xsz + ysz + 4) return (0);
114       kd->u.e.x = mp_loadb(MP_NEW, q + 6, xsz);
115       kd->u.e.y = mp_loadb(MP_NEW, q + 8 + xsz, ysz);
116     } break;
117
118     /* --- Structured key data --- */
119
120     case KENC_STRUCT: {
121       dstr d = DSTR_INIT;
122       key_data *nkd;
123
124       if ((e & ~KF_ENCMASK) || (psz & 3))
125         return (0);
126       q += 4;
127       kd = key_newstruct();
128
129       while (psz) {
130
131         /* --- Read the tag string --- */
132
133         DRESET(&d);
134         sz = LOAD8(q);
135         if (sz >= psz)
136           goto fail;
137         DPUTM(&d, q + 1, sz);
138         DPUTZ(&d);
139         sz = (sz + 4) & ~3;
140         q += sz; psz -= sz;
141
142         /* --- Read the encoding and size --- */
143
144         sz = (LOAD16(q + 2) + 7) & ~3;
145         if (sz > psz)
146           goto fail;
147
148         /* --- Create a table node and fill it in --- */
149
150         if ((nkd = key_decode(q, sz)) == 0)
151           goto fail;
152         key_structsteal(kd, d.buf, nkd);
153         psz -= sz;
154         q += sz;
155       }
156       dstr_destroy(&d);
157       break;
158
159       /* --- Tidy up after a failure --- */
160
161     fail:
162       dstr_destroy(&d);
163       key_drop(kd);
164       return (0);
165     } break;
166
167     /* --- Everything else --- */
168
169     default:
170       return (0);
171   }
172
173   /* --- OK, that was good --- */
174
175   kd->e = e;
176   return (kd);
177 }
178
179 /* --- @key_encode@ --- *
180  *
181  * Arguments:   @key_data *k@ = pointer to key data block
182  *              @dstr *d@ = pointer to destination string
183  *              @const key_filter *kf@ = pointer to key selection block
184  *
185  * Returns:     Nonzero if an item was actually written.
186  *
187  * Use:         Encodes a key block as binary data.
188  */
189
190 static int ksbyname(const void *a, const void *b) {
191   key_struct *const *x = a, *const *y = b;
192   return (strcmp(SYM_NAME(*x), SYM_NAME(*y)));
193 }
194
195 int key_encode(key_data *k, dstr *d, const key_filter *kf)
196 {
197   int rc = 0;
198   if (!KEY_MATCH(k, kf))
199     return (0);
200   switch (k->e & KF_ENCMASK) {
201     case KENC_BINARY:
202     case KENC_ENCRYPT: {
203       char *p;
204
205       DENSURE(d, (k->u.k.sz + 7) & ~3);
206       p = d->buf + d->len;
207       STORE16(p, k->e);
208       STORE16(p + 2, k->u.k.sz);
209       d->len += 4;
210       DPUTM(d, k->u.k.k, k->u.k.sz);
211       rc = 1;
212     } break;
213
214     case KENC_MP: {
215       char *p;
216       size_t sz = mp_octets(k->u.m);
217
218       DENSURE(d, (sz + 7) & ~3);
219       p = d->buf + d->len;
220       STORE16(p, k->e);
221       STORE16(p + 2, sz);
222       mp_storeb(k->u.m, p + 4, sz);
223       d->len += sz + 4;
224       rc = 1;
225     } break;
226
227     case KENC_STRING: {
228       char *p;
229       size_t sz = strlen(k->u.p);
230
231       DENSURE(d, (sz + 7) & ~3);
232       p = d->buf + d->len;
233       STORE16(p, k->e);
234       STORE16(p + 2, sz);
235       memcpy(p + 4, k->u.p, sz);
236       d->len += sz + 4;
237       rc = 1;
238     } break;
239
240     case KENC_EC: {
241       char *p;
242       size_t xsz = 0, ysz = 0;
243       size_t sz;
244
245       if (EC_ATINF(&k->u.e))
246         sz = 0;
247       else {
248         xsz = mp_octets(k->u.e.x);
249         ysz = mp_octets(k->u.e.y);
250         sz = xsz + ysz + 4;
251       }
252       DENSURE(d, (sz + 7) & ~3);
253       p = d->buf + d->len;
254       STORE16(p, k->e);
255       STORE16(p + 2, sz);
256       if (!EC_ATINF(&k->u.e)) {
257         STORE16(p + 4, xsz);
258         mp_storeb(k->u.e.x, p + 6, xsz);
259         STORE16(p + 6 + xsz, ysz);
260         mp_storeb(k->u.e.y, p + 8 + xsz, ysz);
261       }
262       d->len += sz + 4;
263       rc = 1;
264     } break;
265
266     case KENC_STRUCT: {
267       size_t n;
268       char *p;
269       key_struct *ks, **ksv;
270       size_t nks, j;
271       sym_iter i;
272
273       n = d->len;
274       DENSURE(d, 4);
275       p = d->buf + n;
276       STORE16(p, k->e & KF_ENCMASK);
277       d->len += 4;
278
279       for (nks = 0, sym_mkiter(&i, &k->u.s);
280            (ks = sym_next(&i)) != 0;
281            nks++);
282       if (nks) {
283         ksv = xmalloc(nks * sizeof(*ksv));
284         for (j = 0, sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; j++)
285           ksv[j] = ks;
286         qsort(ksv, nks, sizeof(*ksv), ksbyname);
287         for (j = 0; j < nks; j++) {
288           size_t o = d->len;
289           ks = ksv[j];
290           DENSURE(d, 1);
291           *(octet *)(d->buf + d->len++) = strlen(SYM_NAME(ks));
292           DPUTS(d, SYM_NAME(ks));
293           while (d->len & 3)
294             DPUTC(d, 0);
295           if (key_encode(ks->k, d, kf))
296             rc = 1;
297           else
298             d->len = o;
299         }
300         xfree(ksv);
301       }
302       if (!rc)
303         d->len = n;
304       else {
305         p = d->buf + n + 2;
306         n = d->len - n - 4;
307         STORE16(p,  n);
308       }
309     } break;
310   }
311   while (d->len & 3)
312     DPUTC(d, 0);
313   return (rc);
314 }
315
316 /*----- That's all, folks -------------------------------------------------*/