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