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