]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/bind9/lib/dns/dst_parse.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / bind9 / lib / dns / dst_parse.c
1 /*
2  * Portions Copyright (C) 2004-2006, 2008  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/or 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.6.9 2008/01/22 23:27:05 tbox 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         {TAG_HMACMD5_BITS, "Bits:"},
71
72         {TAG_HMACSHA1_KEY, "Key:"},
73         {TAG_HMACSHA1_BITS, "Bits:"},
74
75         {TAG_HMACSHA224_KEY, "Key:"},
76         {TAG_HMACSHA224_BITS, "Bits:"},
77
78         {TAG_HMACSHA256_KEY, "Key:"},
79         {TAG_HMACSHA256_BITS, "Bits:"},
80
81         {TAG_HMACSHA384_KEY, "Key:"},
82         {TAG_HMACSHA384_BITS, "Bits:"},
83
84         {TAG_HMACSHA512_KEY, "Key:"},
85         {TAG_HMACSHA512_BITS, "Bits:"},
86
87         {0, NULL}
88 };
89
90 static int
91 find_value(const char *s, const unsigned int alg) {
92         int i;
93
94         for (i = 0; ; i++) {
95                 if (map[i].tag == NULL)
96                         return (-1);
97                 else if (strcasecmp(s, map[i].tag) == 0 &&
98                          TAG_ALG(map[i].value) == alg)
99                         return (map[i].value);
100         }
101 }
102
103 static const char *
104 find_tag(const int value) {
105         int i;
106
107         for (i = 0; ; i++) {
108                 if (map[i].tag == NULL)
109                         return (NULL);
110                 else if (value == map[i].value)
111                         return (map[i].tag);
112         }
113 }
114
115 static int
116 check_rsa(const dst_private_t *priv) {
117         int i, j;
118         if (priv->nelements != RSA_NTAGS)
119                 return (-1);
120         for (i = 0; i < RSA_NTAGS; i++) {
121                 for (j = 0; j < priv->nelements; j++)
122                         if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i))
123                                 break;
124                 if (j == priv->nelements)
125                         return (-1);
126         }
127         return (0);
128 }
129
130 static int
131 check_dh(const dst_private_t *priv) {
132         int i, j;
133         if (priv->nelements != DH_NTAGS)
134                 return (-1);
135         for (i = 0; i < DH_NTAGS; i++) {
136                 for (j = 0; j < priv->nelements; j++)
137                         if (priv->elements[j].tag == TAG(DST_ALG_DH, i))
138                                 break;
139                 if (j == priv->nelements)
140                         return (-1);
141         }
142         return (0);
143 }
144
145 static int
146 check_dsa(const dst_private_t *priv) {
147         int i, j;
148         if (priv->nelements != DSA_NTAGS)
149                 return (-1);
150         for (i = 0; i < DSA_NTAGS; i++) {
151                 for (j = 0; j < priv->nelements; j++)
152                         if (priv->elements[j].tag == TAG(DST_ALG_DSA, i))
153                                 break;
154                 if (j == priv->nelements)
155                         return (-1);
156         }
157         return (0);
158 }
159
160 static int
161 check_hmac_md5(const dst_private_t *priv, isc_boolean_t old) {
162         int i, j;
163
164         if (priv->nelements != HMACMD5_NTAGS) {
165                 /*
166                  * If this is a good old format and we are accepting
167                  * the old format return success.
168                  */
169                 if (old && priv->nelements == OLD_HMACMD5_NTAGS &&
170                     priv->elements[0].tag == TAG_HMACMD5_KEY)
171                         return (0);
172                 return (-1);
173         }
174         /*
175          * We must be new format at this point.
176          */
177         for (i = 0; i < HMACMD5_NTAGS; i++) {
178                 for (j = 0; j < priv->nelements; j++)
179                         if (priv->elements[j].tag == TAG(DST_ALG_HMACMD5, i))
180                                 break;
181                 if (j == priv->nelements)
182                         return (-1);
183         }
184         return (0);
185 }
186
187 static int
188 check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
189                unsigned int alg)
190 {
191         unsigned int i, j;
192         if (priv->nelements != ntags)
193                 return (-1);
194         for (i = 0; i < ntags; i++) {
195                 for (j = 0; j < priv->nelements; j++)
196                         if (priv->elements[j].tag == TAG(alg, i))
197                                 break;
198                 if (j == priv->nelements)
199                         return (-1);
200         }
201         return (0);
202 }
203
204 static int
205 check_data(const dst_private_t *priv, const unsigned int alg,
206            isc_boolean_t old)
207 {
208         /* XXXVIX this switch statement is too sparse to gen a jump table. */
209         switch (alg) {
210         case DST_ALG_RSAMD5:
211         case DST_ALG_RSASHA1:
212                 return (check_rsa(priv));
213         case DST_ALG_DH:
214                 return (check_dh(priv));
215         case DST_ALG_DSA:
216                 return (check_dsa(priv));
217         case DST_ALG_HMACMD5:
218                 return (check_hmac_md5(priv, old));
219         case DST_ALG_HMACSHA1:
220                 return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg));
221         case DST_ALG_HMACSHA224:
222                 return (check_hmac_sha(priv, HMACSHA224_NTAGS, alg));
223         case DST_ALG_HMACSHA256:
224                 return (check_hmac_sha(priv, HMACSHA256_NTAGS, alg));
225         case DST_ALG_HMACSHA384:
226                 return (check_hmac_sha(priv, HMACSHA384_NTAGS, alg));
227         case DST_ALG_HMACSHA512:
228                 return (check_hmac_sha(priv, HMACSHA512_NTAGS, alg));
229         default:
230                 return (DST_R_UNSUPPORTEDALG);
231         }
232 }
233
234 void
235 dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
236         int i;
237
238         if (priv == NULL)
239                 return;
240         for (i = 0; i < priv->nelements; i++) {
241                 if (priv->elements[i].data == NULL)
242                         continue;
243                 memset(priv->elements[i].data, 0, MAXFIELDSIZE);
244                 isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE);
245         }
246         priv->nelements = 0;
247 }
248
249 int
250 dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
251                       isc_mem_t *mctx, dst_private_t *priv)
252 {
253         int n = 0, major, minor;
254         isc_buffer_t b;
255         isc_token_t token;
256         unsigned char *data = NULL;
257         unsigned int opt = ISC_LEXOPT_EOL;
258         isc_result_t ret;
259
260         REQUIRE(priv != NULL);
261
262         priv->nelements = 0;
263         memset(priv->elements, 0, sizeof(priv->elements));
264
265 #define NEXTTOKEN(lex, opt, token)                              \
266         do {                                                    \
267                 ret = isc_lex_gettoken(lex, opt, token);        \
268                 if (ret != ISC_R_SUCCESS)                       \
269                         goto fail;                              \
270         } while (0)
271
272 #define READLINE(lex, opt, token)                               \
273         do {                                                    \
274                 ret = isc_lex_gettoken(lex, opt, token);        \
275                 if (ret == ISC_R_EOF)                           \
276                         break;                                  \
277                 else if (ret != ISC_R_SUCCESS)                  \
278                         goto fail;                              \
279         } while ((*token).type != isc_tokentype_eol)
280
281         /*
282          * Read the description line.
283          */
284         NEXTTOKEN(lex, opt, &token);
285         if (token.type != isc_tokentype_string ||
286             strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0)
287         {
288                 ret = DST_R_INVALIDPRIVATEKEY;
289                 goto fail;
290         }
291
292         NEXTTOKEN(lex, opt, &token);
293         if (token.type != isc_tokentype_string ||
294             (DST_AS_STR(token))[0] != 'v')
295         {
296                 ret = DST_R_INVALIDPRIVATEKEY;
297                 goto fail;
298         }
299         if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2)
300         {
301                 ret = DST_R_INVALIDPRIVATEKEY;
302                 goto fail;
303         }
304
305         if (major > MAJOR_VERSION ||
306             (major == MAJOR_VERSION && minor > MINOR_VERSION))
307         {
308                 ret = DST_R_INVALIDPRIVATEKEY;
309                 goto fail;
310         }
311
312         READLINE(lex, opt, &token);
313
314         /*
315          * Read the algorithm line.
316          */
317         NEXTTOKEN(lex, opt, &token);
318         if (token.type != isc_tokentype_string ||
319             strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0)
320         {
321                 ret = DST_R_INVALIDPRIVATEKEY;
322                 goto fail;
323         }
324
325         NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
326         if (token.type != isc_tokentype_number ||
327             token.value.as_ulong != (unsigned long) dst_key_alg(key))
328         {
329                 ret = DST_R_INVALIDPRIVATEKEY;
330                 goto fail;
331         }
332
333         READLINE(lex, opt, &token);
334
335         /*
336          * Read the key data.
337          */
338         for (n = 0; n < MAXFIELDS; n++) {
339                 int tag;
340                 isc_region_t r;
341
342                 do {
343                         ret = isc_lex_gettoken(lex, opt, &token);
344                         if (ret == ISC_R_EOF)
345                                 goto done;
346                         if (ret != ISC_R_SUCCESS)
347                                 goto fail;
348                 } while (token.type == isc_tokentype_eol);
349
350                 if (token.type != isc_tokentype_string) {
351                         ret = DST_R_INVALIDPRIVATEKEY;
352                         goto fail;
353                 }
354
355                 tag = find_value(DST_AS_STR(token), alg);
356                 if (tag < 0 || TAG_ALG(tag) != alg) {
357                         ret = DST_R_INVALIDPRIVATEKEY;
358                         goto fail;
359                 }
360                 priv->elements[n].tag = tag;
361
362                 data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE);
363                 if (data == NULL)
364                         goto fail;
365
366                 isc_buffer_init(&b, data, MAXFIELDSIZE);
367                 ret = isc_base64_tobuffer(lex, &b, -1);
368                 if (ret != ISC_R_SUCCESS)
369                         goto fail;
370                 isc_buffer_usedregion(&b, &r);
371                 priv->elements[n].length = r.length;
372                 priv->elements[n].data = r.base;
373
374                 READLINE(lex, opt, &token);
375                 data = NULL;
376         }
377  done:
378         priv->nelements = n;
379
380         if (check_data(priv, alg, ISC_TRUE) < 0)
381                 goto fail;
382
383         return (ISC_R_SUCCESS);
384
385 fail:
386         priv->nelements = n;
387         dst__privstruct_free(priv, mctx);
388         if (data != NULL)
389                 isc_mem_put(mctx, data, MAXFIELDSIZE);
390
391         return (ret);
392 }
393
394 int
395 dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
396                           const char *directory)
397 {
398         FILE *fp;
399         int ret, i;
400         isc_result_t iret;
401         char filename[ISC_DIR_NAMEMAX];
402         char buffer[MAXFIELDSIZE * 2];
403         isc_buffer_t b;
404         isc_fsaccess_t access;
405
406         REQUIRE(priv != NULL);
407
408         if (check_data(priv, dst_key_alg(key), ISC_FALSE) < 0)
409                 return (DST_R_INVALIDPRIVATEKEY);
410
411         isc_buffer_init(&b, filename, sizeof(filename));
412         ret = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b);
413         if (ret != ISC_R_SUCCESS)
414                 return (ret);
415
416         if ((fp = fopen(filename, "w")) == NULL)
417                 return (DST_R_WRITEERROR);
418
419         access = 0;
420         isc_fsaccess_add(ISC_FSACCESS_OWNER,
421                          ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
422                          &access);
423         (void)isc_fsaccess_set(filename, access);
424
425         /* XXXDCL return value should be checked for full filesystem */
426         fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, MAJOR_VERSION,
427                 MINOR_VERSION);
428
429         fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key));
430         /* XXXVIX this switch statement is too sparse to gen a jump table. */
431         switch (dst_key_alg(key)) {
432         case DST_ALG_RSAMD5:
433                 fprintf(fp, "(RSA)\n");
434                 break;
435         case DST_ALG_DH:
436                 fprintf(fp, "(DH)\n");
437                 break;
438         case DST_ALG_DSA:
439                 fprintf(fp, "(DSA)\n");
440                 break;
441         case DST_ALG_RSASHA1:
442                 fprintf(fp, "(RSASHA1)\n");
443                 break;
444         case DST_ALG_HMACMD5:
445                 fprintf(fp, "(HMAC_MD5)\n");
446                 break;
447         case DST_ALG_HMACSHA1:
448                 fprintf(fp, "(HMAC_SHA1)\n");
449                 break;
450         case DST_ALG_HMACSHA224:
451                 fprintf(fp, "(HMAC_SHA224)\n");
452                 break;
453         case DST_ALG_HMACSHA256:
454                 fprintf(fp, "(HMAC_SHA256)\n");
455                 break;
456         case DST_ALG_HMACSHA384:
457                 fprintf(fp, "(HMAC_SHA384)\n");
458                 break;
459         case DST_ALG_HMACSHA512:
460                 fprintf(fp, "(HMAC_SHA512)\n");
461                 break;
462         default:
463                 fprintf(fp, "(?)\n");
464                 break;
465         }
466
467         for (i = 0; i < priv->nelements; i++) {
468                 isc_buffer_t b;
469                 isc_region_t r;
470                 const char *s;
471
472                 s = find_tag(priv->elements[i].tag);
473
474                 r.base = priv->elements[i].data;
475                 r.length = priv->elements[i].length;
476                 isc_buffer_init(&b, buffer, sizeof(buffer));
477                 iret = isc_base64_totext(&r, sizeof(buffer), "", &b);
478                 if (iret != ISC_R_SUCCESS) {
479                         fclose(fp);
480                         return (DST_R_INVALIDPRIVATEKEY);
481                 }
482                 isc_buffer_usedregion(&b, &r);
483
484                 fprintf(fp, "%s ", s);
485                 fwrite(r.base, 1, r.length, fp);
486                 fprintf(fp, "\n");
487         }
488
489         fclose(fp);
490         return (ISC_R_SUCCESS);
491 }
492
493 /*! \file */