math/mpreduce.h: Missing include files.
[u/mdw/catacomb] / key / key-text.c
1 /* -*-c-*-
2 *
3 * Key textual encoding
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <ctype.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <mLib/base64.h>
35 #include <mLib/bits.h>
36 #include <mLib/dstr.h>
37 #include <mLib/sub.h>
38 #include <mLib/sym.h>
39 #include <mLib/url.h>
40
41 #include "key-data.h"
42 #include "mp.h"
43 #include "mptext.h"
44
45 /*----- Main code ---------------------------------------------------------*/
46
47 /* --- @key_read@ --- *
48 *
49 * Arguments: @const char *p@ = pointer to textual key representation
50 * @char **pp@ = where to store the end pointer
51 *
52 * Returns: The newly-read key data, or null if it failed.
53 *
54 * Use: Parses a textual key description.
55 */
56
57 key_data *key_read(const char *p, char **pp)
58 {
59 unsigned e;
60 key_data *kd;
61
62 /* --- Read the encoding type --- *
63 *
64 * The key format is `[FLAGS:]DATA'. If there is no encoding type
65 * named, assume that it's `binary' for backwards compatibility.
66 */
67
68 if (strchr(p, ':') == 0)
69 e = 0;
70 else {
71 char *q;
72 if (key_readflags(p, &q, &e, 0))
73 return (0);
74 p = q + 1;
75 }
76
77 /* --- Now scan the data based on the encoding type --- */
78
79 switch (e & KF_ENCMASK) {
80
81 /* --- Binary encoding --- *
82 *
83 * Simply read out the Base64-encoded data. Since `,' and `]' are our
84 * delimeter characters, and they can't appear in Base64-encoded data, I
85 * can just do a simple search to find the end of the encoded data.
86 */
87
88 case KENC_BINARY:
89 case KENC_ENCRYPT: {
90 dstr d = DSTR_INIT;
91 base64_ctx b;
92 size_t sz = strcspn(p, ",]");
93
94 base64_init(&b);
95 base64_decode(&b, p, sz, &d);
96 base64_decode(&b, 0, 0, &d);
97 kd = key_newbinary(e, d.buf, d.len);
98 dstr_destroy(&d);
99 p += sz;
100 } break;
101
102 /* --- Multiprecision integer encoding --- *
103 *
104 * Multiprecision integers have a convenient reading function.
105 */
106
107 case KENC_MP: {
108 char *q;
109 mp *m = mp_readstring(e & KF_BURN ? MP_NEWSEC : MP_NEW, p, &q, 0);
110 if (!m)
111 return (0);
112 kd = key_newmp(e, m);
113 MP_DROP(m);
114 p = q;
115 } break;
116
117 /* --- String encoding --- *
118 *
119 * We use form-urlencoding to ensure that evil characters don't get out.
120 */
121
122 case KENC_STRING: {
123 dstr d = DSTR_INIT;
124 size_t sz = strcspn(p, ",]");
125 const char *l = p + sz;
126 unsigned int ch;
127 int x, n;
128
129 while (p < l) {
130 switch (*p) {
131 case '+':
132 DPUTC(&d, ' '); break;
133 case '%':
134 x = sscanf(p + 1, "%2x%n", &ch, &n);
135 if (x == 1) { DPUTC(&d, ch); p += n; break; }
136 default:
137 DPUTC(&d, *p); break;
138 }
139 p++;
140 }
141 DPUTZ(&d);
142 kd = key_newstring(e, d.buf);
143 dstr_destroy(&d);
144 } break;
145
146 /* --- Elliptic curve encoding --- *
147 *
148 * Again, we have a convenient function. Assume for now that points
149 * aren't secret. (Reasonably safe.)
150 */
151
152 case KENC_EC: {
153 ec pt = EC_INIT;
154 qd_parse qd;
155 qd.p = p;
156 qd.e = 0;
157 if (!ec_ptparse(&qd, &pt))
158 return (0);
159 kd = key_newec(e, &pt);
160 EC_DESTROY(&pt);
161 p = qd.p;
162 } break;
163
164 /* --- Structured information encoding --- *
165 *
166 * The format for structured key data is `[NAME=KEY,...]', where the
167 * brackets are part of the syntax. Structured keys have no flags apart
168 * from the encoding.
169 *
170 * The binary encoding only allows names up to 255 bytes long. Check for
171 * this here.
172 */
173
174 case KENC_STRUCT: {
175 dstr d = DSTR_INIT;
176 key_data *nkd;
177 char *q;
178
179 /* --- Read the opening bracket --- */
180
181 kd = key_newstruct();
182 if (*p != '[')
183 return (0);
184 p++;
185
186 /* --- Read named key subparts --- */
187
188 for (;;) {
189 size_t sz;
190
191 /* --- Stop if there's a close-bracket --- *
192 *
193 * This allows `[]' to be an empty structured key, which is good. It
194 * also makes `[foo=enc:bar,]' legal, and that's less good but I can
195 * live with it.
196 */
197
198 if (*p == ']')
199 break;
200
201 /* --- Read the name out and check the length --- */
202
203 if ((q = strchr(p, '=')) == 0)
204 goto fail;
205 sz = q - p;
206 if (sz >= 256)
207 goto fail;
208 DRESET(&d);
209 DPUTM(&d, p, sz);
210 DPUTZ(&d);
211
212 /* --- Read the key data for the subkey --- */
213
214 if ((nkd = key_read(q + 1, &q)) == 0)
215 goto fail;
216 key_structsteal(kd, d.buf, nkd);
217 p = q;
218
219 /* --- Read the comma or close-bracket --- */
220
221 if (*p == ']')
222 break;
223 else if (*p == ',')
224 p++;
225 else
226 goto fail;
227 }
228
229 /* --- Step past the close bracket --- */
230
231 p++;
232 dstr_destroy(&d);
233 break;
234
235 /* --- Tidy up after a failure --- */
236
237 fail:
238 dstr_destroy(&d);
239 return (0);
240 } break;
241
242 /* --- Anything else is unknown --- */
243
244 default:
245 return (0);
246 }
247
248 /* --- Return the end pointer --- */
249
250 kd->e = e;
251 if (pp)
252 *pp = (char *)p;
253 return (kd);
254 }
255
256 /* --- @key_write@ --- *
257 *
258 * Arguments: @key_data *k@ = pointer to key data
259 * @dstr *d@ = destination string to write on
260 * @const key_filter *kf@ = pointer to key selection block
261 *
262 * Returns: Nonzero if an item was actually written.
263 *
264 * Use: Writes a key in a textual encoding.
265 */
266
267 int key_write(key_data *k, dstr *d, const key_filter *kf)
268 {
269 int rc = 0;
270 if (!KEY_MATCH(k, kf))
271 return (0);
272 switch (k->e & KF_ENCMASK) {
273 case KENC_BINARY:
274 case KENC_ENCRYPT: {
275 base64_ctx b;
276
277 if ((k->e & KF_ENCMASK) == KENC_BINARY)
278 key_writeflags(k->e, d);
279 else
280 DPUTS(d, "encrypt,secret");
281 DPUTC(d, ':');
282 base64_init(&b);
283 b.indent = "";
284 b.maxline = 0;
285 base64_encode(&b, k->u.k.k, k->u.k.sz, d);
286 base64_encode(&b, 0, 0, d);
287 rc = 1;
288 } break;
289 case KENC_MP:
290 key_writeflags(k->e, d);
291 DPUTC(d, ':');
292 mp_writedstr(k->u.m, d, 10);
293 rc = 1;
294 break;
295 case KENC_STRING: {
296 const char *p = k->u.p;
297 key_writeflags(k->e, d);
298 DPUTC(d, ':');
299 while (*p) {
300 if (*p == ' ') DPUTC(d, '+');
301 else if (!isalnum((unsigned char)*p)) dstr_putf(d, "%%%02x", *p);
302 else DPUTC(d, *p);
303 p++;
304 }
305 rc = 1;
306 } break;
307 case KENC_EC:
308 key_writeflags(k->e, d);
309 DPUTS(d, ":0x"); mp_writedstr(k->u.e.x, d, 16);
310 DPUTS(d, ",0x"); mp_writedstr(k->u.e.y, d, 16);
311 rc = 1;
312 break;
313 case KENC_STRUCT: {
314 key_subkeyiter i;
315 const char *tag;
316 char del = 0;
317 size_t n = d->len;
318
319 DPUTS(d, "struct:[");
320 for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) {
321 size_t o = d->len;
322 if (del)
323 DPUTC(d, del);
324 DPUTS(d, tag);
325 DPUTC(d, '=');
326 if (!key_write(k, d, kf))
327 d->len = o;
328 else {
329 del = ',';
330 rc = 1;
331 }
332 }
333 if (!rc)
334 d->len = n;
335 else
336 DPUTC(d, ']');
337 } break;
338 }
339 DPUTZ(d);
340
341 return (rc);
342 }
343
344 /*----- That's all, folks -------------------------------------------------*/