Coverage Report

Created: 2025-08-03 06:33

/src/bind9/lib/dns/dst_parse.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0 AND ISC
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*
15
 * Copyright (C) Network Associates, Inc.
16
 *
17
 * Permission to use, copy, modify, and/or distribute this software for any
18
 * purpose with or without fee is hereby granted, provided that the above
19
 * copyright notice and this permission notice appear in all copies.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
22
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
23
 * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
24
 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
26
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
27
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28
 */
29
30
#include "dst_parse.h"
31
#include <inttypes.h>
32
#include <stdbool.h>
33
#include <unistd.h>
34
35
#include <isc/base64.h>
36
#include <isc/dir.h>
37
#include <isc/file.h>
38
#include <isc/lex.h>
39
#include <isc/log.h>
40
#include <isc/mem.h>
41
#include <isc/stdtime.h>
42
#include <isc/string.h>
43
#include <isc/util.h>
44
45
#include <dns/time.h>
46
47
#include "dst_internal.h"
48
#include "isc/result.h"
49
50
0
#define DST_AS_STR(t) ((t).value.as_textregion.base)
51
52
0
#define PRIVATE_KEY_STR "Private-key-format:"
53
0
#define ALGORITHM_STR "Algorithm:"
54
55
0
#define TIMING_NTAGS (DST_MAX_TIMES + 1)
56
static const char *timetags[TIMING_NTAGS] = {
57
  "Created:",    "Publish:", "Activate:",  "Revoke:",
58
  "Inactive:",   "Delete:",  "DSPublish:", "SyncPublish:",
59
  "SyncDelete:", NULL,     NULL,   NULL,
60
  NULL
61
};
62
63
0
#define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
64
static const char *numerictags[NUMERIC_NTAGS] = {
65
  "Predecessor:", "Successor:", "MaxTTL:", "RollPeriod:", NULL, NULL, NULL
66
};
67
68
struct parse_map {
69
  const int value;
70
  const char *tag;
71
};
72
73
static struct parse_map map[] = { { TAG_RSA_MODULUS, "Modulus:" },
74
          { TAG_RSA_PUBLICEXPONENT, "PublicExponent:" },
75
          { TAG_RSA_PRIVATEEXPONENT, "PrivateExponent"
76
                   ":" },
77
          { TAG_RSA_PRIME1, "Prime1:" },
78
          { TAG_RSA_PRIME2, "Prime2:" },
79
          { TAG_RSA_EXPONENT1, "Exponent1:" },
80
          { TAG_RSA_EXPONENT2, "Exponent2:" },
81
          { TAG_RSA_COEFFICIENT, "Coefficient:" },
82
          { TAG_RSA_ENGINE, "Engine:" },
83
          { TAG_RSA_LABEL, "Label:" },
84
85
          { TAG_ECDSA_PRIVATEKEY, "PrivateKey:" },
86
          { TAG_ECDSA_ENGINE, "Engine:" },
87
          { TAG_ECDSA_LABEL, "Label:" },
88
89
          { TAG_EDDSA_PRIVATEKEY, "PrivateKey:" },
90
          { TAG_EDDSA_ENGINE, "Engine:" },
91
          { TAG_EDDSA_LABEL, "Label:" },
92
93
          { TAG_HMACMD5_KEY, "Key:" },
94
          { TAG_HMACMD5_BITS, "Bits:" },
95
96
          { TAG_HMACSHA1_KEY, "Key:" },
97
          { TAG_HMACSHA1_BITS, "Bits:" },
98
99
          { TAG_HMACSHA224_KEY, "Key:" },
100
          { TAG_HMACSHA224_BITS, "Bits:" },
101
102
          { TAG_HMACSHA256_KEY, "Key:" },
103
          { TAG_HMACSHA256_BITS, "Bits:" },
104
105
          { TAG_HMACSHA384_KEY, "Key:" },
106
          { TAG_HMACSHA384_BITS, "Bits:" },
107
108
          { TAG_HMACSHA512_KEY, "Key:" },
109
          { TAG_HMACSHA512_BITS, "Bits:" },
110
111
          { 0, NULL } };
112
113
static int
114
0
find_value(const char *s, const unsigned int alg) {
115
0
  int i;
116
117
0
  for (i = 0; map[i].tag != NULL; i++) {
118
0
    if (strcasecmp(s, map[i].tag) == 0 &&
119
0
        (TAG_ALG(map[i].value) == alg))
120
0
    {
121
0
      return map[i].value;
122
0
    }
123
0
  }
124
0
  return -1;
125
0
}
126
127
static const char *
128
0
find_tag(const int value) {
129
0
  int i;
130
131
0
  for (i = 0;; i++) {
132
0
    if (map[i].tag == NULL) {
133
0
      return NULL;
134
0
    } else if (value == map[i].value) {
135
0
      return map[i].tag;
136
0
    }
137
0
  }
138
0
}
139
140
static int
141
0
find_metadata(const char *s, const char *tags[], int ntags) {
142
0
  int i;
143
144
0
  for (i = 0; i < ntags; i++) {
145
0
    if (tags[i] != NULL && strcasecmp(s, tags[i]) == 0) {
146
0
      return i;
147
0
    }
148
0
  }
149
150
0
  return -1;
151
0
}
152
153
static int
154
0
find_timedata(const char *s) {
155
0
  return find_metadata(s, timetags, TIMING_NTAGS);
156
0
}
157
158
static int
159
0
find_numericdata(const char *s) {
160
0
  return find_metadata(s, numerictags, NUMERIC_NTAGS);
161
0
}
162
163
static int
164
0
check_rsa(const dst_private_t *priv, bool external) {
165
0
  int i, j;
166
0
  bool have[RSA_NTAGS];
167
0
  bool ok;
168
0
  unsigned int mask;
169
170
0
  if (external) {
171
0
    return (priv->nelements == 0) ? 0 : -1;
172
0
  }
173
174
0
  for (i = 0; i < RSA_NTAGS; i++) {
175
0
    have[i] = false;
176
0
  }
177
178
0
  for (j = 0; j < priv->nelements; j++) {
179
0
    for (i = 0; i < RSA_NTAGS; i++) {
180
0
      if (priv->elements[j].tag == TAG(DST_ALG_RSA, i)) {
181
0
        break;
182
0
      }
183
0
    }
184
0
    if (i == RSA_NTAGS) {
185
0
      return -1;
186
0
    }
187
0
    have[i] = true;
188
0
  }
189
190
0
  mask = (1ULL << TAG_SHIFT) - 1;
191
192
0
  if (have[TAG_RSA_LABEL & mask]) {
193
0
    ok = have[TAG_RSA_MODULUS & mask] &&
194
0
         have[TAG_RSA_PUBLICEXPONENT & mask];
195
0
  } else {
196
0
    ok = have[TAG_RSA_MODULUS & mask] &&
197
0
         have[TAG_RSA_PUBLICEXPONENT & mask] &&
198
0
         have[TAG_RSA_PRIVATEEXPONENT & mask] &&
199
0
         have[TAG_RSA_PRIME1 & mask] &&
200
0
         have[TAG_RSA_PRIME2 & mask] &&
201
0
         have[TAG_RSA_EXPONENT1 & mask] &&
202
0
         have[TAG_RSA_EXPONENT2 & mask] &&
203
0
         have[TAG_RSA_COEFFICIENT & mask];
204
0
  }
205
0
  return ok ? 0 : -1;
206
0
}
207
208
static int
209
0
check_ecdsa(const dst_private_t *priv, bool external) {
210
0
  int i, j;
211
0
  bool have[ECDSA_NTAGS];
212
0
  bool ok;
213
0
  unsigned int mask;
214
215
0
  if (external) {
216
0
    return (priv->nelements == 0) ? 0 : -1;
217
0
  }
218
219
0
  for (i = 0; i < ECDSA_NTAGS; i++) {
220
0
    have[i] = false;
221
0
  }
222
0
  for (j = 0; j < priv->nelements; j++) {
223
0
    for (i = 0; i < ECDSA_NTAGS; i++) {
224
0
      if (priv->elements[j].tag == TAG(DST_ALG_ECDSA256, i)) {
225
0
        break;
226
0
      }
227
0
    }
228
0
    if (i == ECDSA_NTAGS) {
229
0
      return -1;
230
0
    }
231
0
    have[i] = true;
232
0
  }
233
234
0
  mask = (1ULL << TAG_SHIFT) - 1;
235
236
0
  ok = have[TAG_ECDSA_LABEL & mask] || have[TAG_ECDSA_PRIVATEKEY & mask];
237
238
0
  return ok ? 0 : -1;
239
0
}
240
241
static int
242
0
check_eddsa(const dst_private_t *priv, bool external) {
243
0
  int i, j;
244
0
  bool have[EDDSA_NTAGS];
245
0
  bool ok;
246
0
  unsigned int mask;
247
248
0
  if (external) {
249
0
    return (priv->nelements == 0) ? 0 : -1;
250
0
  }
251
252
0
  for (i = 0; i < EDDSA_NTAGS; i++) {
253
0
    have[i] = false;
254
0
  }
255
0
  for (j = 0; j < priv->nelements; j++) {
256
0
    for (i = 0; i < EDDSA_NTAGS; i++) {
257
0
      if (priv->elements[j].tag == TAG(DST_ALG_ED25519, i)) {
258
0
        break;
259
0
      }
260
0
    }
261
0
    if (i == EDDSA_NTAGS) {
262
0
      return -1;
263
0
    }
264
0
    have[i] = true;
265
0
  }
266
267
0
  mask = (1ULL << TAG_SHIFT) - 1;
268
269
0
  ok = have[TAG_EDDSA_LABEL & mask] || have[TAG_EDDSA_PRIVATEKEY & mask];
270
271
0
  return ok ? 0 : -1;
272
0
}
273
274
static int
275
0
check_hmac_md5(const dst_private_t *priv, bool old) {
276
0
  int i, j;
277
278
0
  if (priv->nelements != HMACMD5_NTAGS) {
279
    /*
280
     * If this is a good old format and we are accepting
281
     * the old format return success.
282
     */
283
0
    if (old && priv->nelements == OLD_HMACMD5_NTAGS &&
284
0
        priv->elements[0].tag == TAG_HMACMD5_KEY)
285
0
    {
286
0
      return 0;
287
0
    }
288
0
    return -1;
289
0
  }
290
  /*
291
   * We must be new format at this point.
292
   */
293
0
  for (i = 0; i < HMACMD5_NTAGS; i++) {
294
0
    for (j = 0; j < priv->nelements; j++) {
295
0
      if (priv->elements[j].tag == TAG(DST_ALG_HMACMD5, i)) {
296
0
        break;
297
0
      }
298
0
    }
299
0
    if (j == priv->nelements) {
300
0
      return -1;
301
0
    }
302
0
  }
303
0
  return 0;
304
0
}
305
306
static int
307
check_hmac_sha(const dst_private_t *priv, unsigned int ntags,
308
0
         unsigned int alg) {
309
0
  unsigned int i, j;
310
0
  if (priv->nelements != ntags) {
311
0
    return -1;
312
0
  }
313
0
  for (i = 0; i < ntags; i++) {
314
0
    for (j = 0; j < priv->nelements; j++) {
315
0
      if (priv->elements[j].tag == TAG(alg, i)) {
316
0
        break;
317
0
      }
318
0
    }
319
0
    if (j == priv->nelements) {
320
0
      return -1;
321
0
    }
322
0
  }
323
0
  return 0;
324
0
}
325
326
static int
327
check_data(const dst_private_t *priv, const unsigned int alg, bool old,
328
0
     bool external) {
329
0
  switch (alg) {
330
0
  case DST_ALG_RSA:
331
0
  case DST_ALG_RSASHA1:
332
0
  case DST_ALG_NSEC3RSASHA1:
333
0
  case DST_ALG_RSASHA256:
334
0
  case DST_ALG_RSASHA512:
335
0
  case DST_ALG_RSASHA256PRIVATEOID:
336
0
  case DST_ALG_RSASHA512PRIVATEOID:
337
0
    return check_rsa(priv, external);
338
0
  case DST_ALG_ECDSA256:
339
0
  case DST_ALG_ECDSA384:
340
0
    return check_ecdsa(priv, external);
341
0
  case DST_ALG_ED25519:
342
0
  case DST_ALG_ED448:
343
0
    return check_eddsa(priv, external);
344
0
  case DST_ALG_HMACMD5:
345
0
    return check_hmac_md5(priv, old);
346
0
  case DST_ALG_HMACSHA1:
347
0
    return check_hmac_sha(priv, HMACSHA1_NTAGS, alg);
348
0
  case DST_ALG_HMACSHA224:
349
0
    return check_hmac_sha(priv, HMACSHA224_NTAGS, alg);
350
0
  case DST_ALG_HMACSHA256:
351
0
    return check_hmac_sha(priv, HMACSHA256_NTAGS, alg);
352
0
  case DST_ALG_HMACSHA384:
353
0
    return check_hmac_sha(priv, HMACSHA384_NTAGS, alg);
354
0
  case DST_ALG_HMACSHA512:
355
0
    return check_hmac_sha(priv, HMACSHA512_NTAGS, alg);
356
0
  default:
357
0
    return DST_R_UNSUPPORTEDALG;
358
0
  }
359
0
}
360
361
void
362
0
dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
363
0
  int i;
364
365
0
  if (priv == NULL) {
366
0
    return;
367
0
  }
368
0
  for (i = 0; i < priv->nelements; i++) {
369
0
    if (priv->elements[i].data == NULL) {
370
0
      continue;
371
0
    }
372
0
    memset(priv->elements[i].data, 0, MAXFIELDSIZE);
373
0
    isc_mem_put(mctx, priv->elements[i].data, MAXFIELDSIZE);
374
0
  }
375
0
  priv->nelements = 0;
376
0
}
377
378
isc_result_t
379
dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
380
0
          isc_mem_t *mctx, dst_private_t *priv) {
381
0
  int n = 0, major, minor, check;
382
0
  isc_buffer_t b;
383
0
  isc_token_t token;
384
0
  unsigned char *data = NULL;
385
0
  unsigned int opt = ISC_LEXOPT_EOL;
386
0
  isc_stdtime_t when;
387
0
  isc_result_t ret;
388
0
  bool external = false;
389
390
0
  REQUIRE(priv != NULL);
391
392
0
  priv->nelements = 0;
393
0
  memset(priv->elements, 0, sizeof(priv->elements));
394
395
0
#define NEXTTOKEN(lex, opt, token)                       \
396
0
  do {                                             \
397
0
    ret = isc_lex_gettoken(lex, opt, token); \
398
0
    if (ret != ISC_R_SUCCESS)                \
399
0
      goto fail;                       \
400
0
  } while (0)
401
402
0
#define READLINE(lex, opt, token)                        \
403
0
  do {                                             \
404
0
    ret = isc_lex_gettoken(lex, opt, token); \
405
0
    if (ret == ISC_R_EOF)                    \
406
0
      break;                           \
407
0
    else if (ret != ISC_R_SUCCESS)           \
408
0
      goto fail;                       \
409
0
  } while ((*token).type != isc_tokentype_eol)
410
411
  /*
412
   * Read the description line.
413
   */
414
0
  NEXTTOKEN(lex, opt, &token);
415
0
  if (token.type != isc_tokentype_string ||
416
0
      strcmp(DST_AS_STR(token), PRIVATE_KEY_STR) != 0)
417
0
  {
418
0
    ret = DST_R_INVALIDPRIVATEKEY;
419
0
    goto fail;
420
0
  }
421
422
0
  NEXTTOKEN(lex, opt, &token);
423
0
  if (token.type != isc_tokentype_string || (DST_AS_STR(token))[0] != 'v')
424
0
  {
425
0
    ret = DST_R_INVALIDPRIVATEKEY;
426
0
    goto fail;
427
0
  }
428
0
  if (sscanf(DST_AS_STR(token), "v%d.%d", &major, &minor) != 2) {
429
0
    ret = DST_R_INVALIDPRIVATEKEY;
430
0
    goto fail;
431
0
  }
432
433
0
  if (major > DST_MAJOR_VERSION) {
434
0
    ret = DST_R_INVALIDPRIVATEKEY;
435
0
    goto fail;
436
0
  }
437
438
  /*
439
   * Store the private key format version number
440
   */
441
0
  dst_key_setprivateformat(key, major, minor);
442
443
0
  READLINE(lex, opt, &token);
444
445
  /*
446
   * Read the algorithm line.
447
   */
448
0
  NEXTTOKEN(lex, opt, &token);
449
0
  if (token.type != isc_tokentype_string ||
450
0
      strcmp(DST_AS_STR(token), ALGORITHM_STR) != 0)
451
0
  {
452
0
    ret = DST_R_INVALIDPRIVATEKEY;
453
0
    goto fail;
454
0
  }
455
456
0
  NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
457
0
  if (token.type != isc_tokentype_number ||
458
0
      token.value.as_ulong != (unsigned long)dst_key_alg(key))
459
0
  {
460
0
    ret = DST_R_INVALIDPRIVATEKEY;
461
0
    goto fail;
462
0
  }
463
464
0
  READLINE(lex, opt, &token);
465
466
  /*
467
   * Read the key data.
468
   */
469
0
  for (n = 0; n < MAXFIELDS; n++) {
470
0
    int tag;
471
0
    isc_region_t r;
472
0
    do {
473
0
      ret = isc_lex_gettoken(lex, opt, &token);
474
0
      if (ret == ISC_R_EOF) {
475
0
        goto done;
476
0
      }
477
0
      if (ret != ISC_R_SUCCESS) {
478
0
        goto fail;
479
0
      }
480
0
    } while (token.type == isc_tokentype_eol);
481
482
0
    if (token.type != isc_tokentype_string) {
483
0
      ret = DST_R_INVALIDPRIVATEKEY;
484
0
      goto fail;
485
0
    }
486
487
0
    if (strcmp(DST_AS_STR(token), "External:") == 0) {
488
0
      external = true;
489
0
      goto next;
490
0
    }
491
492
    /* Numeric metadata */
493
0
    tag = find_numericdata(DST_AS_STR(token));
494
0
    if (tag >= 0) {
495
0
      INSIST(tag < NUMERIC_NTAGS);
496
497
0
      NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
498
0
      if (token.type != isc_tokentype_number) {
499
0
        ret = DST_R_INVALIDPRIVATEKEY;
500
0
        goto fail;
501
0
      }
502
503
0
      dst_key_setnum(key, tag, token.value.as_ulong);
504
0
      goto next;
505
0
    }
506
507
    /* Timing metadata */
508
0
    tag = find_timedata(DST_AS_STR(token));
509
0
    if (tag >= 0) {
510
0
      INSIST(tag < TIMING_NTAGS);
511
512
0
      NEXTTOKEN(lex, opt, &token);
513
0
      if (token.type != isc_tokentype_string) {
514
0
        ret = DST_R_INVALIDPRIVATEKEY;
515
0
        goto fail;
516
0
      }
517
518
0
      ret = dns_time32_fromtext(DST_AS_STR(token), &when);
519
0
      if (ret != ISC_R_SUCCESS) {
520
0
        goto fail;
521
0
      }
522
523
0
      dst_key_settime(key, tag, when);
524
525
0
      goto next;
526
0
    }
527
528
    /* Key data */
529
0
    tag = find_value(DST_AS_STR(token), alg);
530
0
    if (tag < 0 && minor > DST_MINOR_VERSION) {
531
0
      goto next;
532
0
    } else if (tag < 0) {
533
0
      ret = DST_R_INVALIDPRIVATEKEY;
534
0
      goto fail;
535
0
    }
536
537
0
    priv->elements[n].tag = tag;
538
539
0
    data = isc_mem_get(mctx, MAXFIELDSIZE);
540
541
0
    isc_buffer_init(&b, data, MAXFIELDSIZE);
542
0
    ret = isc_base64_tobuffer(lex, &b, -1);
543
0
    if (ret != ISC_R_SUCCESS) {
544
0
      goto fail;
545
0
    }
546
547
0
    isc_buffer_usedregion(&b, &r);
548
0
    priv->elements[n].length = r.length;
549
0
    priv->elements[n].data = r.base;
550
0
    priv->nelements++;
551
552
0
  next:
553
0
    READLINE(lex, opt, &token);
554
0
    data = NULL;
555
0
  }
556
557
0
done:
558
0
  if (external && priv->nelements != 0) {
559
0
    ret = DST_R_INVALIDPRIVATEKEY;
560
0
    goto fail;
561
0
  }
562
563
0
  check = check_data(priv, alg, true, external);
564
0
  if (check < 0) {
565
0
    ret = DST_R_INVALIDPRIVATEKEY;
566
0
    goto fail;
567
0
  } else if (check != ISC_R_SUCCESS) {
568
0
    ret = check;
569
0
    goto fail;
570
0
  }
571
572
0
  key->external = external;
573
574
0
  return ISC_R_SUCCESS;
575
576
0
fail:
577
0
  dst__privstruct_free(priv, mctx);
578
0
  if (data != NULL) {
579
0
    isc_mem_put(mctx, data, MAXFIELDSIZE);
580
0
  }
581
582
0
  return ret;
583
0
}
584
585
isc_result_t
586
dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
587
0
        const char *directory) {
588
0
  FILE *fp;
589
0
  isc_result_t result;
590
0
  char filename[NAME_MAX];
591
0
  char tmpname[NAME_MAX];
592
0
  char buffer[MAXFIELDSIZE * 2];
593
0
  isc_stdtime_t when;
594
0
  uint32_t value;
595
0
  isc_buffer_t b;
596
0
  isc_buffer_t fileb;
597
0
  isc_buffer_t tmpb;
598
0
  isc_region_t r;
599
0
  int major, minor;
600
0
  mode_t mode;
601
0
  int i, ret;
602
603
0
  REQUIRE(priv != NULL);
604
605
0
  ret = check_data(priv, dst_key_alg(key), false, key->external);
606
0
  if (ret < 0) {
607
0
    return DST_R_INVALIDPRIVATEKEY;
608
0
  } else if (ret != ISC_R_SUCCESS) {
609
0
    return ret;
610
0
  }
611
612
0
  isc_buffer_init(&fileb, filename, sizeof(filename));
613
0
  result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory,
614
0
               &fileb);
615
0
  if (result != ISC_R_SUCCESS) {
616
0
    return result;
617
0
  }
618
619
0
  result = isc_file_mode(filename, &mode);
620
0
  if (result == ISC_R_SUCCESS && mode != (S_IRUSR | S_IWUSR)) {
621
    /* File exists; warn that we are changing its permissions */
622
0
    int level;
623
624
0
    level = ISC_LOG_WARNING;
625
0
    isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DNSSEC,
626
0
            level,
627
0
            "Permissions on the file %s "
628
0
            "have changed from 0%o to 0600 as "
629
0
            "a result of this operation.",
630
0
            filename, (unsigned int)mode);
631
0
  }
632
633
0
  isc_buffer_init(&tmpb, tmpname, sizeof(tmpname));
634
0
  result = dst_key_buildfilename(key, DST_TYPE_TEMPLATE, directory,
635
0
               &tmpb);
636
0
  if (result != ISC_R_SUCCESS) {
637
0
    return result;
638
0
  }
639
640
0
  fp = dst_key_open(tmpname, S_IRUSR | S_IWUSR);
641
0
  if (fp == NULL) {
642
0
    return DST_R_WRITEERROR;
643
0
  }
644
645
0
  dst_key_getprivateformat(key, &major, &minor);
646
0
  if (major == 0 && minor == 0) {
647
0
    major = DST_MAJOR_VERSION;
648
0
    minor = DST_MINOR_VERSION;
649
0
  }
650
651
  /* XXXDCL return value should be checked for full filesystem */
652
0
  fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, major, minor);
653
654
0
  fprintf(fp, "%s %u ", ALGORITHM_STR, dst_key_alg(key));
655
656
0
  switch (dst_key_alg(key)) {
657
0
  case DST_ALG_RSASHA1:
658
0
    fprintf(fp, "(RSASHA1)\n");
659
0
    break;
660
0
  case DST_ALG_NSEC3RSASHA1:
661
0
    fprintf(fp, "(NSEC3RSASHA1)\n");
662
0
    break;
663
0
  case DST_ALG_RSASHA256:
664
0
    fprintf(fp, "(RSASHA256)\n");
665
0
    break;
666
0
  case DST_ALG_RSASHA512:
667
0
    fprintf(fp, "(RSASHA512)\n");
668
0
    break;
669
0
  case DST_ALG_ECDSA256:
670
0
    fprintf(fp, "(ECDSAP256SHA256)\n");
671
0
    break;
672
0
  case DST_ALG_ECDSA384:
673
0
    fprintf(fp, "(ECDSAP384SHA384)\n");
674
0
    break;
675
0
  case DST_ALG_ED25519:
676
0
    fprintf(fp, "(ED25519)\n");
677
0
    break;
678
0
  case DST_ALG_ED448:
679
0
    fprintf(fp, "(ED448)\n");
680
0
    break;
681
0
  case DST_ALG_HMACMD5:
682
0
    fprintf(fp, "(HMAC_MD5)\n");
683
0
    break;
684
0
  case DST_ALG_HMACSHA1:
685
0
    fprintf(fp, "(HMAC_SHA1)\n");
686
0
    break;
687
0
  case DST_ALG_HMACSHA224:
688
0
    fprintf(fp, "(HMAC_SHA224)\n");
689
0
    break;
690
0
  case DST_ALG_HMACSHA256:
691
0
    fprintf(fp, "(HMAC_SHA256)\n");
692
0
    break;
693
0
  case DST_ALG_HMACSHA384:
694
0
    fprintf(fp, "(HMAC_SHA384)\n");
695
0
    break;
696
0
  case DST_ALG_HMACSHA512:
697
0
    fprintf(fp, "(HMAC_SHA512)\n");
698
0
    break;
699
0
  case DST_ALG_RSASHA256PRIVATEOID:
700
0
    fprintf(fp, "(OID:RSASHA256)\n");
701
0
    break;
702
0
  case DST_ALG_RSASHA512PRIVATEOID:
703
0
    fprintf(fp, "(OID:RSASHA512)\n");
704
0
    break;
705
0
  default:
706
0
    fprintf(fp, "(?)\n");
707
0
    break;
708
0
  }
709
710
0
  for (i = 0; i < priv->nelements; i++) {
711
0
    const char *s;
712
713
0
    s = find_tag(priv->elements[i].tag);
714
715
0
    r.base = priv->elements[i].data;
716
0
    r.length = priv->elements[i].length;
717
0
    isc_buffer_init(&b, buffer, sizeof(buffer));
718
0
    result = isc_base64_totext(&r, sizeof(buffer), "", &b);
719
0
    if (result != ISC_R_SUCCESS) {
720
0
      return dst_key_cleanup(tmpname, fp);
721
0
    }
722
0
    isc_buffer_usedregion(&b, &r);
723
724
0
    fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base);
725
0
  }
726
727
0
  if (key->external) {
728
0
    fprintf(fp, "External:\n");
729
0
  }
730
731
  /* Add the metadata tags */
732
0
  if (major > 1 || (major == 1 && minor >= 3)) {
733
0
    for (i = 0; i < NUMERIC_NTAGS; i++) {
734
0
      result = dst_key_getnum(key, i, &value);
735
0
      if (result != ISC_R_SUCCESS) {
736
0
        continue;
737
0
      }
738
0
      if (numerictags[i] != NULL) {
739
0
        fprintf(fp, "%s %u\n", numerictags[i], value);
740
0
      }
741
0
    }
742
0
    for (i = 0; i < TIMING_NTAGS; i++) {
743
0
      result = dst_key_gettime(key, i, &when);
744
0
      if (result != ISC_R_SUCCESS) {
745
0
        continue;
746
0
      }
747
748
0
      isc_buffer_init(&b, buffer, sizeof(buffer));
749
0
      result = dns_time32_totext(when, &b);
750
0
      if (result != ISC_R_SUCCESS) {
751
0
        return dst_key_cleanup(tmpname, fp);
752
0
      }
753
754
0
      isc_buffer_usedregion(&b, &r);
755
756
0
      if (timetags[i] != NULL) {
757
0
        fprintf(fp, "%s %.*s\n", timetags[i],
758
0
          (int)r.length, r.base);
759
0
      }
760
0
    }
761
0
  }
762
763
0
  result = dst_key_close(tmpname, fp, filename);
764
0
  return result;
765
0
}
766
767
/*! \file */