configure.ac: Replace with a new version.
[u/mdw/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 -------------------------------------------------*/