chiark / gitweb /
ec-bin (ec_binproj): Make curve setup faster.
[catacomb] / key-pack.c
1 /* -*-c-*-
2  *
3  * $Id$
4  *
5  * Packing and unpacking key data
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 <mLib/dstr.h>
33
34 #include "key.h"
35 #include "key-data.h"
36
37 /*----- Generic packing and unpacking -------------------------------------*/
38
39 /* --- @key_pack@ --- *
40  *
41  * Arguments:   @key_packdef *kp@ = pointer to packing structure
42  *              @key_data **kd@ = where to put the key data pointer
43  *              @dstr *d@ = pointer to tag string for the key data
44  *
45  * Returns:     Error code, or zero.
46  *
47  * Use:         Packs a key from a data structure.
48  */
49
50 int key_pack(key_packdef *kp, key_data **kd, dstr *d)
51 {
52   switch (kp->e & KF_ENCMASK) {
53
54     /* --- Binary and integer keys are easy --- */
55
56     case KENC_BINARY: {
57       key_bin *b = kp->p;
58       *kd = key_newbinary(kp->e, b->k, b->sz);
59       return (0);
60     }
61     case KENC_MP:
62       *kd = key_newmp(kp->e, *(mp **)kp->p);
63       return (0);
64     case KENC_STRING:
65       *kd = key_newstring(kp->e, *(char **)kp->p);
66       return (0);
67     case KENC_EC:
68       *kd = key_newec(kp->e, (ec *)kp->p);
69       return (0);
70
71     /* --- Encrypted keys are a little tricky --- *
72      *
73      * This works rather differently to unpacking.
74      */
75
76     case KENC_ENCRYPT: {
77       key_data *kkd;
78       int err = key_pack(kp->p, &kkd, d);
79       if (!err) {
80         err = key_plock(kd, kkd, d->buf);
81         key_drop(kkd);
82       }
83       return (err);
84     }
85
86     /* --- Structured keys, as ever, are a nuisance --- */
87
88     case KENC_STRUCT: {
89       int err;
90       key_packstruct *p;
91       size_t l = d->len;
92
93       *kd = key_newstruct();
94       DPUTC(d, '.');
95       for (p = kp->p; p->name; p++) {
96         key_data *kkd;
97         d->len = l + 1;
98         DPUTS(d, p->name);
99         if ((err = key_pack(&p->kp, &kkd, d)) != 0) {
100           key_drop(*kd);
101           return (err);
102         }
103         key_structsteal(*kd, p->name, kkd);
104       }
105       d->len = l;
106       d->buf[l] = 0;
107       return (0);
108     }
109     default:
110       abort();
111   }
112 }
113
114 /* --- @key_unpack@ --- *
115  *
116  * Arguments:   @key_packdef *kp@ = pointer to packing structure
117  *              @key_data *kd@ = pointer to source key data
118  *              @dstr *d@ = pointer to tag string for the key data
119  *
120  * Returns:     Error code, or zero.
121  *
122  * Use:         Unpacks a key into an appropriate data structure.
123  */
124
125 int key_unpack(key_packdef *kp, key_data *kd, dstr *d)
126 {
127   unsigned e = kp->e & KF_ENCMASK;
128   int err;
129
130   /* --- Decrypt the encrypted key --- */
131
132   if ((kd->e & KF_ENCMASK) == KENC_ENCRYPT) {
133     if ((err = key_punlock(&kp->kd, kd, d->buf)) != 0)
134       goto fail;
135     kd = kp->kd;
136   }
137
138   /* --- Ensure that the key has the right type --- */
139
140   if ((kd->e & KF_ENCMASK) != e) {
141     err = KERR_WRONGTYPE;
142     goto fail;
143   }
144
145   /* --- Unpack the key --- *
146    *
147    * Only three possibilities left now.
148    */
149
150   switch (e) {
151
152     /* --- Binary and integer keys are easy --- */
153
154     case KENC_BINARY:
155       *(key_bin *)kp->p = kd->u.k;
156       break;
157     case KENC_MP:
158       *(mp **)kp->p = kd->u.m;
159       break;
160     case KENC_STRING:
161       *(char **)kp->p = kd->u.p;
162       break;
163     case KENC_EC:
164       *(ec *)kp->p = kd->u.e;
165       break;
166
167     /* --- Structured keys take a little care --- */
168
169     case KENC_STRUCT: {
170       key_packstruct *p, *q;
171       size_t l = d->len;
172
173       /* --- Iterate over the requested subparts --- */
174
175       DPUTC(d, '.');
176       for (p = kp->p; p->name; p++) {
177         key_data *kkd;
178
179         /* --- Build the name --- */
180
181         d->len = l + 1;
182         DPUTS(d, p->name);
183
184         /* --- Find and unpack the subkey --- */
185
186         if ((kkd = key_structfind(kd, p->name)) == 0) {
187           if (!(p->kp.e & KF_OPT)) {
188             err = KERR_NOTFOUND;
189             goto tidy;
190           }
191         } else if ((err = key_unpack(&p->kp, kkd, d)) != 0) {
192           p++;
193           goto tidy;
194         }
195       }
196
197       /* --- Done --- */
198
199       d->len = l;
200       d->buf[l] = 0;
201       break;
202
203       /* --- Tidy up if something went wrong --- */
204
205     tidy:
206       for (q = kp->p; q < p; q++)
207         key_unpackdone(&q->kp);
208       goto fail;
209     }
210
211     default:
212       abort();
213   }
214
215   return (0);
216
217   /* --- Something went wrong --- */
218
219 fail:
220   if (kp->kd) {
221     key_drop(kp->kd);
222     kp->kd = 0;
223   }
224   return (err);
225 }
226
227 /* --- @key_unpackdone@ --- *
228  *
229  * Arguments:   @key_packdef *kp@ = pointer to packing definition
230  *
231  * Returns:     ---
232  *
233  * Use:         Frees the key components contained within a packing
234  *              definition, created during key unpacking.
235  */
236
237 void key_unpackdone(key_packdef *kp)
238 {
239   if (kp->kd) {
240     key_drop(kp->kd);
241     kp->kd = 0;
242   }
243   if ((kp->e & KF_ENCMASK) == KENC_STRUCT) {
244     key_packstruct *p;
245     for (p = kp->p; p->name; p++)
246       key_unpackdone(&p->kp);
247   }
248 }
249
250 /*----- That's all, folks -------------------------------------------------*/