Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / external / bsd / bind / dist / lib / dns / dst_parse.c
blob17f96b36f6f7e7cf12ee97732956ab19b465b76f
1 /* $NetBSD$ */
3 /*
4 * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1999-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
12 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
14 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
17 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
21 * Permission to use, copy, modify, and/or distribute this software for any
22 * purpose with or without fee is hereby granted, provided that the above
23 * copyright notice and this permission notice appear in all copies.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
27 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
28 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
31 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34 /*%
35 * Principal Author: Brian Wellington
36 * Id: dst_parse.c,v 1.23 2009/10/26 21:18:24 each Exp
39 #include <config.h>
41 #include <isc/base64.h>
42 #include <isc/dir.h>
43 #include <isc/fsaccess.h>
44 #include <isc/lex.h>
45 #include <isc/mem.h>
46 #include <isc/stdtime.h>
47 #include <isc/string.h>
48 #include <isc/util.h>
50 #include <dns/time.h>
52 #include "dst_internal.h"
53 #include "dst_parse.h"
54 #include "dst/result.h"
56 #define DST_AS_STR(t) ((t).value.as_textregion.base)
58 #define PRIVATE_KEY_STR "Private-key-format:"
59 #define ALGORITHM_STR "Algorithm:"
61 #define TIMING_NTAGS (DST_MAX_TIMES + 1)
62 static const char *timetags[TIMING_NTAGS] = {
63 "Created:",
64 "Publish:",
65 "Activate:",
66 "Revoke:",
67 "Unpublish:",
68 "Delete:",
69 "DSPublish:"
72 #define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
73 static const char *numerictags[NUMERIC_NTAGS] = {
74 "Predecessor:",
75 "Successor:",
76 "MaxTTL:",
77 "RollPeriod:"
80 struct parse_map {
81 const int value;
82 const char *tag;
85 static struct parse_map map[] = {
86 {TAG_RSA_MODULUS, "Modulus:"},
87 {TAG_RSA_PUBLICEXPONENT, "PublicExponent:"},
88 {TAG_RSA_PRIVATEEXPONENT, "PrivateExponent:"},
89 {TAG_RSA_PRIME1, "Prime1:"},
90 {TAG_RSA_PRIME2, "Prime2:"},
91 {TAG_RSA_EXPONENT1, "Exponent1:"},
92 {TAG_RSA_EXPONENT2, "Exponent2:"},
93 {TAG_RSA_COEFFICIENT, "Coefficient:"},
94 {TAG_RSA_ENGINE, "Engine:" },
95 {TAG_RSA_LABEL, "Label:" },
96 {TAG_RSA_PIN, "PIN:" },
98 {TAG_DH_PRIME, "Prime(p):"},
99 {TAG_DH_GENERATOR, "Generator(g):"},
100 {TAG_DH_PRIVATE, "Private_value(x):"},
101 {TAG_DH_PUBLIC, "Public_value(y):"},
103 {TAG_DSA_PRIME, "Prime(p):"},
104 {TAG_DSA_SUBPRIME, "Subprime(q):"},
105 {TAG_DSA_BASE, "Base(g):"},
106 {TAG_DSA_PRIVATE, "Private_value(x):"},
107 {TAG_DSA_PUBLIC, "Public_value(y):"},
109 {TAG_HMACMD5_KEY, "Key:"},
110 {TAG_HMACMD5_BITS, "Bits:"},
112 {TAG_HMACSHA1_KEY, "Key:"},
113 {TAG_HMACSHA1_BITS, "Bits:"},
115 {TAG_HMACSHA224_KEY, "Key:"},
116 {TAG_HMACSHA224_BITS, "Bits:"},
118 {TAG_HMACSHA256_KEY, "Key:"},
119 {TAG_HMACSHA256_BITS, "Bits:"},
121 {TAG_HMACSHA384_KEY, "Key:"},
122 {TAG_HMACSHA384_BITS, "Bits:"},
124 {TAG_HMACSHA512_KEY, "Key:"},
125 {TAG_HMACSHA512_BITS, "Bits:"},
127 {0, NULL}
130 static int
131 find_value(const char *s, const unsigned int alg) {
132 int i;
134 for (i = 0; map[i].tag != NULL; i++) {
135 if (strcasecmp(s, map[i].tag) == 0 &&
136 (TAG_ALG(map[i].value) == alg))
137 return (map[i].value);
139 return (-1);
142 static const char *
143 find_tag(const int value) {
144 int i;
146 for (i = 0; ; i++) {
147 if (map[i].tag == NULL)
148 return (NULL);
149 else if (value == map[i].value)
150 return (map[i].tag);
154 static int
155 find_metadata(const char *s, const char *tags[], int ntags) {
156 int i;
158 for (i = 0; i < ntags; i++) {
159 if (strcasecmp(s, tags[i]) == 0)
160 return (i);
163 return (-1);
166 static int
167 find_timedata(const char *s) {
168 return (find_metadata(s, timetags, TIMING_NTAGS));
171 static int
172 find_numericdata(const char *s) {
173 return (find_metadata(s, numerictags, NUMERIC_NTAGS));
176 static int
177 check_rsa(const dst_private_t *priv) {
178 int i, j;
179 isc_boolean_t have[RSA_NTAGS];
180 isc_boolean_t ok;
181 unsigned int mask;
183 for (i = 0; i < RSA_NTAGS; i++)
184 have[i] = ISC_FALSE;
185 for (j = 0; j < priv->nelements; j++) {
186 for (i = 0; i < RSA_NTAGS; i++)
187 if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i))
188 break;
189 if (i == RSA_NTAGS)
190 return (-1);
191 have[i] = ISC_TRUE;
194 mask = ~0;
195 mask <<= sizeof(mask) * 8 - TAG_SHIFT;
196 mask >>= sizeof(mask) * 8 - TAG_SHIFT;
198 if (have[TAG_RSA_ENGINE & mask])
199 ok = have[TAG_RSA_MODULUS & mask] &&
200 have[TAG_RSA_PUBLICEXPONENT & mask] &&
201 have[TAG_RSA_LABEL & mask];
202 else
203 ok = have[TAG_RSA_MODULUS & mask] &&
204 have[TAG_RSA_PUBLICEXPONENT & mask] &&
205 have[TAG_RSA_PRIVATEEXPONENT & mask] &&
206 have[TAG_RSA_PRIME1 & mask] &&
207 have[TAG_RSA_PRIME2 & mask] &&
208 have[TAG_RSA_EXPONENT1 & mask] &&
209 have[TAG_RSA_EXPONENT2 & mask] &&
210 have[TAG_RSA_COEFFICIENT & mask];
211 return (ok ? 0 : -1 );
214 static int
215 check_dh(const dst_private_t *priv) {
216 int i, j;
217 if (priv->nelements != DH_NTAGS)
218 return (-1);
219 for (i = 0; i < DH_NTAGS; i++) {
220 for (j = 0; j < priv->nelements; j++)
221 if (priv->elements[j].tag == TAG(DST_ALG_DH, i))
222 break;
223 if (j == priv->nelements)
224 return (-1);
226 return (0);
229 static int
230 check_dsa(const dst_private_t *priv) {
231 int i, j;
232 if (priv->nelements != DSA_NTAGS)
233 return (-1);
234 for (i = 0; i < DSA_NTAGS; i++) {
235 for (j = 0; j < priv->nelements; j++)
236 if (priv->elements[j].tag == TAG(DST_ALG_DSA, i))
237 break;
238 if (j == priv->nelements)
239 return (-1);
241 return (0);
244 static int
245 check_hmac_md5(const dst_private_t *priv, isc_boolean_t old) {
246 int i, j;
248 if (priv->nelements != HMACMD5_NTAGS) {
250 * If this is a good old format and we are accepting
251 * the old format return success.
253 if (old && priv->nelements == OLD_HMACMD5_NTAGS &&
254 priv->elements[0].tag == TAG_HMACMD5_KEY)
255 return (0);
256 return (-1);
259 * We must be new format at this point.
261 for (i = 0; i < HMACMD5_NTAGS; i++) {
262 for (j = 0; j < priv->nelements; j++)
263 if (priv->elements[j].tag == TAG(DST_ALG_HMACMD5, i))
264 break;
265 if (j == priv->nelements)
266 return (-1);
268 return (0);
271 static int
272 check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
273 unsigned int alg)
275 unsigned int i, j;
276 if (priv->nelements != ntags)
277 return (-1);
278 for (i = 0; i < ntags; i++) {
279 for (j = 0; j < priv->nelements; j++)
280 if (priv->elements[j].tag == TAG(alg, i))
281 break;
282 if (j == priv->nelements)
283 return (-1);
285 return (0);
288 static int
289 check_data(const dst_private_t *priv, const unsigned int alg,
290 isc_boolean_t old)
292 /* XXXVIX this switch statement is too sparse to gen a jump table. */
293 switch (alg) {
294 case DST_ALG_RSAMD5:
295 case DST_ALG_RSASHA1:
296 return (check_rsa(priv));
297 case DST_ALG_DH:
298 return (check_dh(priv));
299 case DST_ALG_DSA:
300 return (check_dsa(priv));
301 case DST_ALG_HMACMD5:
302 return (check_hmac_md5(priv, old));
303 case DST_ALG_HMACSHA1:
304 return (check_hmac_sha(priv, HMACSHA1_NTAGS, alg));
305 case DST_ALG_HMACSHA224:
306 return (check_hmac_sha(priv, HMACSHA224_NTAGS, alg));
307 case DST_ALG_HMACSHA256:
308 return (check_hmac_sha(priv, HMACSHA256_NTAGS, alg));
309 case DST_ALG_HMACSHA384:
310 return (check_hmac_sha(priv, HMACSHA384_NTAGS, alg));
311 case DST_ALG_HMACSHA512:
312 return (check_hmac_sha(priv, HMACSHA512_NTAGS, alg));
313 default:
314 return (DST_R_UNSUPPORTEDALG);
318 void
319 dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
320 int i;
322 if (priv == NULL)
323 return;
324 for (i = 0; i < priv->nelements; i++) {
325 if (priv->elements[i].data == NULL)
326 continue;
327 memset(priv->elements[i].data, 0, MAXFIELDSIZE);
328 isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE);
330 priv->nelements = 0;
333 isc_result_t
334 dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
335 isc_mem_t *mctx, dst_private_t *priv)
337 int n = 0, major, minor;
338 isc_buffer_t b;
339 isc_token_t token;
340 unsigned char *data = NULL;
341 unsigned int opt = ISC_LEXOPT_EOL;
342 isc_stdtime_t when;
343 isc_result_t ret;
345 REQUIRE(priv != NULL);
347 priv->nelements = 0;
348 memset(priv->elements, 0, sizeof(priv->elements));
350 #define NEXTTOKEN(lex, opt, token) \
351 do { \
352 ret = isc_lex_gettoken(lex, opt, token); \
353 if (ret != ISC_R_SUCCESS) \
354 goto fail; \
355 } while (0)
357 #define READLINE(lex, opt, token) \
358 do { \
359 ret = isc_lex_gettoken(lex, opt, token); \
360 if (ret == ISC_R_EOF) \
361 break; \
362 else if (ret != ISC_R_SUCCESS) \
363 goto fail; \
364 } while ((*token).type != isc_tokentype_eol)
367 * Read the description line.
369 NEXTTOKEN(lex, opt, &token);
370 if (token.type != isc_tokentype_string ||
371 strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0)
373 ret = DST_R_INVALIDPRIVATEKEY;
374 goto fail;
377 NEXTTOKEN(lex, opt, &token);
378 if (token.type != isc_tokentype_string ||
379 (DST_AS_STR(token))[0] != 'v')
381 ret = DST_R_INVALIDPRIVATEKEY;
382 goto fail;
384 if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2)
386 ret = DST_R_INVALIDPRIVATEKEY;
387 goto fail;
390 if (major > DST_MAJOR_VERSION) {
391 ret = DST_R_INVALIDPRIVATEKEY;
392 goto fail;
396 * Store the private key format version number
398 dst_key_setprivateformat(key, major, minor);
400 READLINE(lex, opt, &token);
403 * Read the algorithm line.
405 NEXTTOKEN(lex, opt, &token);
406 if (token.type != isc_tokentype_string ||
407 strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0)
409 ret = DST_R_INVALIDPRIVATEKEY;
410 goto fail;
413 NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
414 if (token.type != isc_tokentype_number ||
415 token.value.as_ulong != (unsigned long) dst_key_alg(key))
417 ret = DST_R_INVALIDPRIVATEKEY;
418 goto fail;
421 READLINE(lex, opt, &token);
424 * Read the key data.
426 for (n = 0; n < MAXFIELDS; n++) {
427 int tag;
428 isc_region_t r;
429 do {
430 ret = isc_lex_gettoken(lex, opt, &token);
431 if (ret == ISC_R_EOF)
432 goto done;
433 if (ret != ISC_R_SUCCESS)
434 goto fail;
435 } while (token.type == isc_tokentype_eol);
437 if (token.type != isc_tokentype_string) {
438 ret = DST_R_INVALIDPRIVATEKEY;
439 goto fail;
442 /* Numeric metadata */
443 tag = find_numericdata(DST_AS_STR(token));
444 if (tag >= 0) {
445 INSIST(tag < NUMERIC_NTAGS);
447 NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
448 if (token.type != isc_tokentype_number) {
449 ret = DST_R_INVALIDPRIVATEKEY;
450 goto fail;
453 dst_key_setnum(key, tag, token.value.as_ulong);
454 goto next;
457 /* Timing metadata */
458 tag = find_timedata(DST_AS_STR(token));
459 if (tag >= 0) {
460 INSIST(tag < TIMING_NTAGS);
462 NEXTTOKEN(lex, opt, &token);
463 if (token.type != isc_tokentype_string) {
464 ret = DST_R_INVALIDPRIVATEKEY;
465 goto fail;
468 ret = dns_time32_fromtext(DST_AS_STR(token), &when);
469 if (ret != ISC_R_SUCCESS)
470 goto fail;
472 dst_key_settime(key, tag, when);
474 goto next;
477 /* Key data */
478 tag = find_value(DST_AS_STR(token), alg);
479 if (tag < 0 && minor > DST_MINOR_VERSION)
480 goto next;
481 else if (tag < 0) {
482 ret = DST_R_INVALIDPRIVATEKEY;
483 goto fail;
486 priv->elements[n].tag = tag;
488 data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE);
489 if (data == NULL)
490 goto fail;
492 isc_buffer_init(&b, data, MAXFIELDSIZE);
493 ret = isc_base64_tobuffer(lex, &b, -1);
494 if (ret != ISC_R_SUCCESS)
495 goto fail;
497 isc_buffer_usedregion(&b, &r);
498 priv->elements[n].length = r.length;
499 priv->elements[n].data = r.base;
500 priv->nelements++;
502 next:
503 READLINE(lex, opt, &token);
504 data = NULL;
506 done:
507 if (check_data(priv, alg, ISC_TRUE) < 0)
508 goto fail;
510 return (ISC_R_SUCCESS);
512 fail:
513 dst__privstruct_free(priv, mctx);
514 if (data != NULL)
515 isc_mem_put(mctx, data, MAXFIELDSIZE);
517 return (ret);
520 isc_result_t
521 dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
522 const char *directory)
524 FILE *fp;
525 int ret, i;
526 isc_result_t result;
527 char filename[ISC_DIR_NAMEMAX];
528 char buffer[MAXFIELDSIZE * 2];
529 isc_fsaccess_t access;
530 isc_stdtime_t when;
531 isc_uint32_t value;
532 isc_buffer_t b;
533 isc_region_t r;
534 int major, minor;
536 REQUIRE(priv != NULL);
538 if (check_data(priv, dst_key_alg(key), ISC_FALSE) < 0)
539 return (DST_R_INVALIDPRIVATEKEY);
541 isc_buffer_init(&b, filename, sizeof(filename));
542 ret = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &b);
543 if (ret != ISC_R_SUCCESS)
544 return (ret);
546 if ((fp = fopen(filename, "w")) == NULL)
547 return (DST_R_WRITEERROR);
549 access = 0;
550 isc_fsaccess_add(ISC_FSACCESS_OWNER,
551 ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
552 &access);
553 (void)isc_fsaccess_set(filename, access);
555 dst_key_getprivateformat(key, &major, &minor);
556 if (major == 0 && minor == 0) {
557 major = DST_MAJOR_VERSION;
558 minor = DST_MINOR_VERSION;
561 /* XXXDCL return value should be checked for full filesystem */
562 fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, major, minor);
564 fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key));
566 /* XXXVIX this switch statement is too sparse to gen a jump table. */
567 switch (dst_key_alg(key)) {
568 case DST_ALG_RSAMD5:
569 fprintf(fp, "(RSA)\n");
570 break;
571 case DST_ALG_DH:
572 fprintf(fp, "(DH)\n");
573 break;
574 case DST_ALG_DSA:
575 fprintf(fp, "(DSA)\n");
576 break;
577 case DST_ALG_RSASHA1:
578 fprintf(fp, "(RSASHA1)\n");
579 break;
580 case DST_ALG_NSEC3RSASHA1:
581 fprintf(fp, "(NSEC3RSASHA1)\n");
582 break;
583 case DST_ALG_NSEC3DSA:
584 fprintf(fp, "(NSEC3DSA)\n");
585 break;
586 case DST_ALG_RSASHA256:
587 fprintf(fp, "(RSASHA256)\n");
588 break;
589 case DST_ALG_RSASHA512:
590 fprintf(fp, "(RSASHA512)\n");
591 break;
592 case DST_ALG_HMACMD5:
593 fprintf(fp, "(HMAC_MD5)\n");
594 break;
595 case DST_ALG_HMACSHA1:
596 fprintf(fp, "(HMAC_SHA1)\n");
597 break;
598 case DST_ALG_HMACSHA224:
599 fprintf(fp, "(HMAC_SHA224)\n");
600 break;
601 case DST_ALG_HMACSHA256:
602 fprintf(fp, "(HMAC_SHA256)\n");
603 break;
604 case DST_ALG_HMACSHA384:
605 fprintf(fp, "(HMAC_SHA384)\n");
606 break;
607 case DST_ALG_HMACSHA512:
608 fprintf(fp, "(HMAC_SHA512)\n");
609 break;
610 default:
611 fprintf(fp, "(?)\n");
612 break;
615 for (i = 0; i < priv->nelements; i++) {
616 const char *s;
618 s = find_tag(priv->elements[i].tag);
620 r.base = priv->elements[i].data;
621 r.length = priv->elements[i].length;
622 isc_buffer_init(&b, buffer, sizeof(buffer));
623 result = isc_base64_totext(&r, sizeof(buffer), "", &b);
624 if (result != ISC_R_SUCCESS) {
625 fclose(fp);
626 return (DST_R_INVALIDPRIVATEKEY);
628 isc_buffer_usedregion(&b, &r);
630 fprintf(fp, "%s ", s);
631 fwrite(r.base, 1, r.length, fp);
632 fprintf(fp, "\n");
635 /* Add the metadata tags */
636 if (major > 1 || (major == 1 && minor >= 3)) {
637 for (i = 0; i < NUMERIC_NTAGS; i++) {
638 result = dst_key_getnum(key, i, &value);
639 if (result != ISC_R_SUCCESS)
640 continue;
641 fprintf(fp, "%s %u\n", numerictags[i], value);
643 for (i = 0; i < TIMING_NTAGS; i++) {
644 result = dst_key_gettime(key, i, &when);
645 if (result != ISC_R_SUCCESS)
646 continue;
648 isc_buffer_init(&b, buffer, sizeof(buffer));
649 result = dns_time32_totext(when, &b);
650 if (result != ISC_R_SUCCESS)
651 continue;
653 isc_buffer_usedregion(&b, &r);
655 fprintf(fp, "%s ", timetags[i]);
656 fwrite(r.base, 1, r.length, fp);
657 fprintf(fp, "\n");
661 fflush(fp);
662 result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS;
663 fclose(fp);
664 return (result);
667 /*! \file */