Generate, store and retreive elliptic curve keys.
[u/mdw/catacomb] / key-text.c
1 /* -*-c-*-
2 *
3 * $Id: key-text.c,v 1.4 2004/03/28 01:58:47 mdw Exp $
4 *
5 * Key textual 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 /*----- Revision history --------------------------------------------------*
31 *
32 * $Log: key-text.c,v $
33 * Revision 1.4 2004/03/28 01:58:47 mdw
34 * Generate, store and retreive elliptic curve keys.
35 *
36 * Revision 1.3 2001/02/03 11:57:00 mdw
37 * Track mLib change: symbols no longer need to include a terminating
38 * null.
39 *
40 * Revision 1.2 2000/06/17 11:27:20 mdw
41 * Use secure memory interface from MP library.
42 *
43 * Revision 1.1 2000/02/12 18:21:02 mdw
44 * Overhaul of key management (again).
45 *
46 */
47
48 /*----- Header files ------------------------------------------------------*/
49
50 #include <stdlib.h>
51 #include <string.h>
52
53 #include <mLib/base64.h>
54 #include <mLib/bits.h>
55 #include <mLib/dstr.h>
56 #include <mLib/sub.h>
57 #include <mLib/sym.h>
58 #include <mLib/url.h>
59
60 #include "key-data.h"
61 #include "mp.h"
62 #include "mptext.h"
63
64 /*----- Main code ---------------------------------------------------------*/
65
66 /* --- @key_read@ --- *
67 *
68 * Arguments: @const char *p@ = pointer to textual key representation
69 * @key_data *k@ = pointer to output block for key data
70 * @char **pp@ = where to store the end pointer
71 *
72 * Returns: Zero if all went well, nonzero if there was a problem.
73 *
74 * Use: Parses a textual key description.
75 */
76
77 int key_read(const char *p, key_data *k, char **pp)
78 {
79 unsigned e;
80
81 /* --- Read the encoding type --- *
82 *
83 * The key format is `[FLAGS:]DATA'. If there is no encoding type
84 * named, assume that it's `binary' for backwards compatibility.
85 */
86
87 if (strchr(p, ':') == 0)
88 e = 0;
89 else {
90 char *q;
91 if (key_readflags(p, &q, &e, 0))
92 return (-1);
93 p = q + 1;
94 }
95
96 /* --- Now scan the data based on the encoding type --- */
97
98 k->e = e;
99 switch (e & KF_ENCMASK) {
100
101 /* --- Binary encoding --- *
102 *
103 * Simply read out the Base64-encoded data. Since `,' and `]' are our
104 * delimeter characters, and they can't appear in Base64-encoded data, I
105 * can just do a simple search to find the end of the encoded data.
106 */
107
108 case KENC_BINARY:
109 case KENC_ENCRYPT: {
110 dstr d = DSTR_INIT;
111 base64_ctx b;
112 size_t sz = strcspn(p, ",]");
113
114 base64_init(&b);
115 base64_decode(&b, p, sz, &d);
116 base64_decode(&b, 0, 0, &d);
117 k->u.k.k = sub_alloc(d.len);
118 k->u.k.sz = d.len;
119 memcpy(k->u.k.k, d.buf, d.len);
120 dstr_destroy(&d);
121 p += sz;
122 } break;
123
124 /* --- Multiprecision integer encoding --- *
125 *
126 * Multiprecision integers have a convenient reading function.
127 */
128
129 case KENC_MP: {
130 char *q;
131 mp *m = mp_readstring(k->e & KF_BURN ? MP_NEWSEC : MP_NEW, p, &q, 0);
132 if (!m)
133 return (-1);
134 k->u.m = m;
135 p = q;
136 } break;
137
138 /* --- String encoding --- *
139 *
140 * We use form-urlencoding to ensure that evil characters don't get out.
141 */
142
143 case KENC_STRING: {
144 dstr d = DSTR_INIT;
145 size_t sz = strcspn(p, ",]");
146 const char *l = p + sz;
147 unsigned int ch;
148 int x, n;
149
150 while (p < l) {
151 switch (*p) {
152 case '+':
153 DPUTC(&d, ' '); break;
154 case '%':
155 x = sscanf(p + 1, "%2x%n", &ch, &n);
156 if (x == 1) { DPUTC(&d, ch); p += n; break; }
157 default:
158 DPUTC(&d, *p); break;
159 }
160 p++;
161 }
162 DPUTZ(&d);
163 k->u.p = xstrdup(d.buf);
164 dstr_destroy(&d);
165 } break;
166
167 /* --- Elliptic curve encoding --- *
168 *
169 * Again, we have a convenient function. Assume for now that points
170 * aren't secret. (Reasonably safe.)
171 */
172
173 case KENC_EC: {
174 qd_parse qd;
175 qd.p = p;
176 qd.e = 0;
177 EC_CREATE(&k->u.e);
178 if (!ec_ptparse(&qd, &k->u.e))
179 return (-1);
180 p = qd.p;
181 } break;
182
183 /* --- Structured information encoding --- *
184 *
185 * The format for structured key data is `[NAME=KEY,...]', where the
186 * brackets are part of the syntax. Structured keys have no flags apart
187 * from the encoding.
188 *
189 * The binary encoding only allows names up to 255 bytes long. Check for
190 * this here.
191 */
192
193 case KENC_STRUCT: {
194 dstr d = DSTR_INIT;
195 char *q;
196
197 /* --- Read the opening bracket --- */
198
199 k->e &= KF_ENCMASK;
200 if (*p != '[')
201 return (-1);
202 p++;
203 sym_create(&k->u.s);
204
205 /* --- Read named key subparts --- */
206
207 for (;;) {
208 size_t sz;
209 key_struct *ks;
210
211 /* --- Stop if there's a close-bracket --- *
212 *
213 * This allows `[]' to be an empty structured key, which is good. It
214 * also makes `[foo=enc:bar,]' legal, and that's less good but I can
215 * live with it.
216 */
217
218 if (*p == ']')
219 break;
220
221 /* --- Read the name out and check the length --- */
222
223 if ((q = strchr(p, '=')) == 0)
224 goto fail;
225 sz = q - p;
226 if (sz >= 256)
227 goto fail;
228 DRESET(&d);
229 DPUTM(&d, p, sz);
230 DPUTZ(&d);
231
232 /* --- Add an appropriate block to the key table --- *
233 *
234 * Simply destroy old data if there's already a match.
235 */
236
237 {
238 unsigned f;
239 ks = sym_find(&k->u.s, d.buf, d.len, sizeof(*ks), &f);
240 if (f)
241 key_destroy(&ks->k);
242 }
243
244 /* --- Read the key data for the subkey --- */
245
246 if (key_read(q + 1, &ks->k, &q)) {
247 sym_remove(&k->u.s, ks);
248 goto fail;
249 }
250 p = q;
251
252 /* --- Read the comma or close-bracket --- */
253
254 if (*p == ']')
255 break;
256 else if (*p == ',')
257 p++;
258 else
259 goto fail;
260 }
261
262 /* --- Step past the close bracket --- */
263
264 p++;
265 dstr_destroy(&d);
266 break;
267
268 /* --- Tidy up after a failure --- */
269
270 fail:
271 dstr_destroy(&d);
272 key_destroy(k);
273 return (-1);
274 } break;
275
276 /* --- Anything else is unknown --- */
277
278 default:
279 return (-1);
280 }
281
282 /* --- Return the end pointer --- */
283
284 if (pp)
285 *pp = (char *)p;
286 return (0);
287 }
288
289 /* --- @key_write@ --- *
290 *
291 * Arguments: @key_data *k@ = pointer to key data
292 * @dstr *d@ = destination string to write on
293 * @const key_filter *kf@ = pointer to key selection block
294 *
295 * Returns: Nonzero if an item was actually written.
296 *
297 * Use: Writes a key in a textual encoding.
298 */
299
300 int key_write(key_data *k, dstr *d, const key_filter *kf)
301 {
302 int rc = 0;
303 if (!KEY_MATCH(k, kf))
304 return (0);
305 switch (k->e & KF_ENCMASK) {
306 case KENC_BINARY:
307 case KENC_ENCRYPT: {
308 base64_ctx b;
309
310 if ((k->e & KF_ENCMASK) == KENC_BINARY)
311 key_writeflags(k->e, d);
312 else
313 DPUTS(d, "encrypt,secret");
314 DPUTC(d, ':');
315 base64_init(&b);
316 b.indent = "";
317 b.maxline = 0;
318 base64_encode(&b, k->u.k.k, k->u.k.sz, d);
319 base64_encode(&b, 0, 0, d);
320 rc = 1;
321 } break;
322 case KENC_MP:
323 key_writeflags(k->e, d);
324 DPUTC(d, ':');
325 mp_writedstr(k->u.m, d, 10);
326 rc = 1;
327 break;
328 case KENC_STRING: {
329 const char *p = k->u.p;
330 key_writeflags(k->e, d);
331 DPUTC(d, ':');
332 while (*p) {
333 if (*p == ' ') DPUTC(d, '+');
334 else if (!isalnum((unsigned char)*p)) dstr_putf(d, "%%%02x", *p);
335 else DPUTC(d, *p);
336 p++;
337 }
338 rc = 1;
339 } break;
340 case KENC_EC:
341 key_writeflags(k->e, d);
342 DPUTS(d, ":0x"); mp_writedstr(k->u.e.x, d, 16);
343 DPUTS(d, ",0x"); mp_writedstr(k->u.e.y, d, 16);
344 rc = 1;
345 break;
346 case KENC_STRUCT: {
347 sym_iter i;
348 key_struct *ks;
349 char del = 0;
350 size_t n = d->len;
351
352 DPUTS(d, "struct:[");
353 for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
354 size_t o = d->len;
355 if (del)
356 DPUTC(d, del);
357 DPUTS(d, SYM_NAME(ks));
358 DPUTC(d, '=');
359 if (!key_write(&ks->k, d, kf))
360 d->len = o;
361 else {
362 del = ',';
363 rc = 1;
364 }
365 }
366 if (!rc)
367 d->len = n;
368 else
369 DPUTC(d, ']');
370 } break;
371 }
372 DPUTZ(d);
373
374 return (rc);
375 }
376
377 /*----- That's all, folks -------------------------------------------------*/