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