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