Merge branch 'vendor/GMP' into gcc441
[dragonfly.git] / contrib / bind-9.3 / lib / dns / dst_parse.c
1 /*
2  * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2002  Internet Software Consortium.
4  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
13  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 /*
20  * Principal Author: Brian Wellington
21  * $Id: dst_parse.c,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $
22  */
23
24 #include <config.h>
25
26 #include <isc/base64.h>
27 #include <isc/dir.h>
28 #include <isc/fsaccess.h>
29 #include <isc/lex.h>
30 #include <isc/mem.h>
31 #include <isc/string.h>
32 #include <isc/util.h>
33
34 #include "dst_internal.h"
35 #include "dst_parse.h"
36 #include "dst/result.h"
37
38 #define DST_AS_STR(t) ((t).value.as_textregion.base)
39
40 #define PRIVATE_KEY_STR "Private-key-format:"
41 #define ALGORITHM_STR "Algorithm:"
42
43 struct parse_map {
44         const int value;
45         const char *tag;
46 };
47
48 static struct parse_map map[] = {
49         {TAG_RSA_MODULUS, "Modulus:"},
50         {TAG_RSA_PUBLICEXPONENT, "PublicExponent:"},
51         {TAG_RSA_PRIVATEEXPONENT, "PrivateExponent:"},
52         {TAG_RSA_PRIME1, "Prime1:"},
53         {TAG_RSA_PRIME2, "Prime2:"},
54         {TAG_RSA_EXPONENT1, "Exponent1:"},
55         {TAG_RSA_EXPONENT2, "Exponent2:"},
56         {TAG_RSA_COEFFICIENT, "Coefficient:"},
57
58         {TAG_DH_PRIME, "Prime(p):"},
59         {TAG_DH_GENERATOR, "Generator(g):"},
60         {TAG_DH_PRIVATE, "Private_value(x):"},
61         {TAG_DH_PUBLIC, "Public_value(y):"},
62
63         {TAG_DSA_PRIME, "Prime(p):"},
64         {TAG_DSA_SUBPRIME, "Subprime(q):"},
65         {TAG_DSA_BASE, "Base(g):"},
66         {TAG_DSA_PRIVATE, "Private_value(x):"},
67         {TAG_DSA_PUBLIC, "Public_value(y):"},
68
69         {TAG_HMACMD5_KEY, "Key:"},
70         {0, NULL}
71 };
72
73 static int
74 find_value(const char *s, const unsigned int alg) {
75         int i;
76
77         for (i = 0; ; i++) {
78                 if (map[i].tag == NULL)
79                         return (-1);
80                 else if (strcasecmp(s, map[i].tag) == 0 &&
81                          TAG_ALG(map[i].value) == alg)
82                         return (map[i].value);
83         }
84 }
85
86 static const char *
87 find_tag(const int value) {
88         int i;
89
90         for (i = 0; ; i++) {
91                 if (map[i].tag == NULL)
92                         return (NULL);
93                 else if (value == map[i].value)
94                         return (map[i].tag);
95         }
96 }
97
98 static int
99 check_rsa(const dst_private_t *priv) {
100         int i, j;
101         if (priv->nelements != RSA_NTAGS)
102                 return (-1);
103         for (i = 0; i < RSA_NTAGS; i++) {
104                 for (j = 0; j < priv->nelements; j++)
105                         if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i))
106                                 break;
107                 if (j == priv->nelements)
108                         return (-1);
109         }
110         return (0);
111 }
112
113 static int
114 check_dh(const dst_private_t *priv) {
115         int i, j;
116         if (priv->nelements != DH_NTAGS)
117                 return (-1);
118         for (i = 0; i < DH_NTAGS; i++) {
119                 for (j = 0; j < priv->nelements; j++)
120                         if (priv->elements[j].tag == TAG(DST_ALG_DH, i))
121                                 break;
122                 if (j == priv->nelements)
123                         return (-1);
124         }
125         return (0);
126 }
127
128 static int
129 check_dsa(const dst_private_t *priv) {
130         int i, j;
131         if (priv->nelements != DSA_NTAGS)
132                 return (-1);
133         for (i = 0; i < DSA_NTAGS; i++) {
134                 for (j = 0; j < priv->nelements; j++)
135                         if (priv->elements[j].tag == TAG(DST_ALG_DSA, i))
136                                 break;
137                 if (j == priv->nelements)
138                         return (-1);
139         }
140         return (0);
141 }
142
143 static int
144 check_hmac_md5(const dst_private_t *priv) {
145         if (priv->nelements != HMACMD5_NTAGS)
146                 return (-1);
147         if (priv->elements[0].tag != TAG_HMACMD5_KEY)
148                 return (-1);
149         return (0);
150 }
151
152 static int
153 check_data(const dst_private_t *priv, const unsigned int alg) {
154         /* XXXVIX this switch statement is too sparse to gen a jump table. */
155         switch (alg) {
156         case DST_ALG_RSAMD5:
157         case DST_ALG_RSASHA1:
158                 return (check_rsa(priv));
159         case DST_ALG_DH:
160                 return (check_dh(priv));
161         case DST_ALG_DSA:
162                 return (check_dsa(priv));
163         case DST_ALG_HMACMD5:
164                 return (check_hmac_md5(priv));
165         default:
166                 return (DST_R_UNSUPPORTEDALG);
167         }
168 }
169
170 void
171 dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
172         int i;
173
174         if (priv == NULL)
175                 return;
176         for (i = 0; i < priv->nelements; i++) {
177                 if (priv->elements[i].data == NULL)
178                         continue;
179                 memset(priv->elements[i].data, 0, MAXFIELDSIZE);
180                 isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE);
181         }
182         priv->nelements = 0;
183 }
184
185 int
186 dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
187                       isc_mem_t *mctx, dst_private_t *priv)
188 {
189         int n = 0, major, minor;
190         isc_buffer_t b;
191         isc_token_t token;
192         unsigned char *data = NULL;
193         unsigned int opt = ISC_LEXOPT_EOL;
194         isc_result_t ret;
195
196         REQUIRE(priv != NULL);
197
198         priv->nelements = 0;
199
200 #define NEXTTOKEN(lex, opt, token)                              \
201         do {                                                    \
202                 ret = isc_lex_gettoken(lex, opt, token);        \
203                 if (ret != ISC_R_SUCCESS)                       \
204                         goto fail;                              \
205         } while (0)
206
207 #define READLINE(lex, opt, token)                               \
208         do {                                                    \
209                 ret = isc_lex_gettoken(lex, opt, token);        \
210                 if (ret == ISC_R_EOF)                           \
211                         break;                                  \
212                 else if (ret != ISC_R_SUCCESS)                  \
213                         goto fail;                              \
214         } while ((*token).type != isc_tokentype_eol)
215
216         /*
217          * Read the description line.
218          */
219         NEXTTOKEN(lex, opt, &token);
220         if (token.type != isc_tokentype_string ||
221             strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0)
222         {
223                 ret = DST_R_INVALIDPRIVATEKEY;
224                 goto fail;
225         }
226
227         NEXTTOKEN(lex, opt, &token);
228         if (token.type != isc_tokentype_string ||
229             (DST_AS_STR(token))[0] != 'v')
230         {
231                 ret = DST_R_INVALIDPRIVATEKEY;
232                 goto fail;
233         }
234         if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2)
235         {
236                 ret = DST_R_INVALIDPRIVATEKEY;
237                 goto fail;
238         }
239
240         if (major > MAJOR_VERSION ||
241             (major == MAJOR_VERSION && minor > MINOR_VERSION))
242         {
243                 ret = DST_R_INVALIDPRIVATEKEY;
244                 goto fail;
245         }
246
247         READLINE(lex, opt, &token);
248
249         /*
250          * Read the algorithm line.
251          */
252         NEXTTOKEN(lex, opt, &token);
253         if (token.type != isc_tokentype_string ||
254             strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0)
255         {
256                 ret = DST_R_INVALIDPRIVATEKEY;
257                 goto fail;
258         }
259
260         NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
261         if (token.type != isc_tokentype_number ||
262             token.value.as_ulong != (unsigned long) dst_key_alg(key))
263         {
264                 ret = DST_R_INVALIDPRIVATEKEY;
265                 goto fail;
266         }
267
268         READLINE(lex, opt, &token);
269
270         /*
271          * Read the key data.
272          */
273         for (n = 0; n < MAXFIELDS; n++) {
274                 int tag;
275                 isc_region_t r;
276
277                 do {
278                         ret = isc_lex_gettoken(lex, opt, &token);
279                         if (ret == ISC_R_EOF)
280                                 goto done;
281                         if (ret != ISC_R_SUCCESS)
282                                 goto fail;
283                 } while (token.type == isc_tokentype_eol);
284
285                 if (token.type != isc_tokentype_string) {
286                         ret = DST_R_INVALIDPRIVATEKEY;
287                         goto fail;
288                 }
289
290                 memset(&priv->elements[n], 0, sizeof(dst_private_element_t));
291                 tag = find_value(DST_AS_STR(token), alg);
292                 if (tag < 0 || TAG_ALG(tag) != alg) {
293                         ret = DST_R_INVALIDPRIVATEKEY;
294                         goto fail;
295                 }
296                 priv->elements[n].tag = tag;
297
298                 data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE);
299                 if (data == NULL)
300                         goto fail;
301
302                 isc_buffer_init(&b, data, MAXFIELDSIZE);
303                 ret = isc_base64_tobuffer(lex, &b, -1);
304                 if (ret != ISC_R_SUCCESS)
305                         goto fail;
306                 isc_buffer_usedregion(&b, &r);
307                 priv->elements[n].length = r.length;
308                 priv->elements[n].data = r.base;
309
310                 READLINE(lex, opt, &token);
311                 data = NULL;
312         }
313  done:
314         priv->nelements = n;
315
316         if (check_data(priv, alg) < 0)
317                 goto fail;
318
319         return (ISC_R_SUCCESS);
320
321 fail:
322         priv->nelements = n;
323         dst__privstruct_free(priv, mctx);
324         if (data != NULL)
325                 isc_mem_put(mctx, data, MAXFIELDSIZE);
326
327         return (ret);
328 }
329
330 int
331 dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
332                           const char *directory)
333 {
334         FILE *fp;
335         int ret, i;
336         isc_result_t iret;
337         char filename[ISC_DIR_NAMEMAX];
338         char buffer[MAXFIELDSIZE * 2];
339         isc_buffer_t b;
340         isc_fsaccess_t access;
341
342         REQUIRE(priv != NULL);
343
344         if (check_data(priv, dst_key_alg(key)) < 0)
345                 return (DST_R_INVALIDPRIVATEKEY);
346
347         isc_buffer_init(&b, filename, sizeof(filename));
348         ret = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b);
349         if (ret != ISC_R_SUCCESS)
350                 return (ret);
351
352         if ((fp = fopen(filename, "w")) == NULL)
353                 return (DST_R_WRITEERROR);
354
355         access = 0;
356         isc_fsaccess_add(ISC_FSACCESS_OWNER,
357                          ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
358                          &access);
359         (void)isc_fsaccess_set(filename, access);
360
361         /* XXXDCL return value should be checked for full filesystem */
362         fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, MAJOR_VERSION,
363                 MINOR_VERSION);
364
365         fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key));
366         /* XXXVIX this switch statement is too sparse to gen a jump table. */
367         switch (dst_key_alg(key)) {
368         case DST_ALG_RSAMD5:
369                 fprintf(fp, "(RSA)\n");
370                 break;
371         case DST_ALG_DH:
372                 fprintf(fp, "(DH)\n");
373                 break;
374         case DST_ALG_DSA:
375                 fprintf(fp, "(DSA)\n");
376                 break;
377         case DST_ALG_RSASHA1:
378                 fprintf(fp, "(RSASHA1)\n");
379                 break;
380         case DST_ALG_HMACMD5:
381                 fprintf(fp, "(HMAC_MD5)\n");
382                 break;
383         default:
384                 fprintf(fp, "(?)\n");
385                 break;
386         }
387
388         for (i = 0; i < priv->nelements; i++) {
389                 isc_buffer_t b;
390                 isc_region_t r;
391                 const char *s;
392
393                 s = find_tag(priv->elements[i].tag);
394
395                 r.base = priv->elements[i].data;
396                 r.length = priv->elements[i].length;
397                 isc_buffer_init(&b, buffer, sizeof(buffer));
398                 iret = isc_base64_totext(&r, sizeof(buffer), "", &b);
399                 if (iret != ISC_R_SUCCESS) {
400                         fclose(fp);
401                         return (DST_R_INVALIDPRIVATEKEY);
402                 }
403                 isc_buffer_usedregion(&b, &r);
404
405                 fprintf(fp, "%s ", s);
406                 fwrite(r.base, 1, r.length, fp);
407                 fprintf(fp, "\n");
408         }
409
410         fclose(fp);
411         return (ISC_R_SUCCESS);
412 }