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