Coverage Report

Created: 2026-04-05 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdata/generic/key_25.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
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
/* RFC2535 */
15
16
#ifndef RDATA_GENERIC_KEY_25_C
17
#define RDATA_GENERIC_KEY_25_C
18
19
#include <dst/dst.h>
20
21
#define RRTYPE_KEY_ATTRIBUTES \
22
145k
  (DNS_RDATATYPEATTR_ATCNAME | DNS_RDATATYPEATTR_ZONECUTAUTH)
23
24
/*
25
 * RFC 2535 section 3.1.2 says that if bits 0-1 of the Flags field are
26
 * both set, it means there is no key information and the RR stops after
27
 * the algorithm octet.  However, this only applies to KEY records, as
28
 * indicated by the specifications of the RR types based on KEY:
29
 *
30
 *     CDNSKEY - RFC 7344
31
 *     DNSKEY - RFC 4034
32
 *     RKEY - draft-reid-dnsext-rkey-00
33
 */
34
static bool
35
84.1k
generic_key_nokey(dns_rdatatype_t type, unsigned int flags) {
36
84.1k
  switch (type) {
37
3.44k
  case dns_rdatatype_cdnskey:
38
10.2k
  case dns_rdatatype_dnskey:
39
12.7k
  case dns_rdatatype_rkey:
40
12.7k
    return false;
41
71.4k
  case dns_rdatatype_key:
42
71.4k
  default:
43
71.4k
    return (flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY;
44
84.1k
  }
45
84.1k
}
46
47
static isc_result_t
48
3.20k
generic_fromtext_key(ARGS_FROMTEXT) {
49
3.20k
  isc_token_t token;
50
3.20k
  dns_secalg_t alg;
51
3.20k
  dns_secproto_t proto;
52
3.20k
  dns_keyflags_t flags;
53
3.20k
  unsigned int used;
54
55
3.20k
  UNUSED(rdclass);
56
3.20k
  UNUSED(origin);
57
3.20k
  UNUSED(options);
58
3.20k
  UNUSED(callbacks);
59
60
  /* flags */
61
3.20k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
62
3.20k
              false));
63
3.18k
  RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion));
64
3.05k
  if (type == dns_rdatatype_rkey && flags != 0U) {
65
33
    RETTOK(DNS_R_FORMERR);
66
33
  }
67
3.02k
  RETERR(uint16_tobuffer(flags, target));
68
69
  /* protocol */
70
3.02k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
71
3.02k
              false));
72
2.98k
  RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion));
73
2.81k
  RETERR(mem_tobuffer(target, &proto, 1));
74
75
  /* algorithm */
76
2.81k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
77
2.81k
              false));
78
2.79k
  RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion));
79
2.77k
  RETERR(mem_tobuffer(target, &alg, 1));
80
81
  /* No Key? */
82
2.77k
  if (generic_key_nokey(type, flags)) {
83
286
    return ISC_R_SUCCESS;
84
286
  }
85
86
  /*
87
   * Save the current used value. It will become the current
88
   * value when we parse the keydata field.
89
   */
90
2.49k
  used = isc_buffer_usedlength(target);
91
92
2.49k
  RETERR(isc_base64_tobuffer(lexer, target, isc_one_or_more));
93
94
2.42k
  if (alg == DNS_KEYALG_PRIVATEDNS || alg == DNS_KEYALG_PRIVATEOID) {
95
209
    isc_buffer_t b;
96
97
    /*
98
     * Set up 'b' so that the key data can be parsed.
99
     */
100
209
    b = *target;
101
209
    b.active = b.used;
102
209
    b.current = used;
103
104
209
    RETERR(check_private(&b, alg));
105
158
  }
106
107
2.37k
  return ISC_R_SUCCESS;
108
2.42k
}
109
110
static isc_result_t
111
6.36k
generic_totext_key(ARGS_TOTEXT) {
112
6.36k
  isc_region_t sr;
113
6.36k
  char buf[sizeof("[key id = 64000]")];
114
6.36k
  unsigned int flags;
115
6.36k
  unsigned char algorithm;
116
6.36k
  char algbuf[DNS_NAME_FORMATSIZE];
117
6.36k
  const char *keyinfo;
118
6.36k
  isc_region_t tmpr;
119
120
6.36k
  REQUIRE(rdata->length != 0);
121
122
6.36k
  dns_rdata_toregion(rdata, &sr);
123
124
  /* flags */
125
6.36k
  flags = uint16_fromregion(&sr);
126
6.36k
  isc_region_consume(&sr, 2);
127
6.36k
  snprintf(buf, sizeof(buf), "%u", flags);
128
6.36k
  RETERR(str_totext(buf, target));
129
6.36k
  RETERR(str_totext(" ", target));
130
6.36k
  if ((flags & DNS_KEYFLAG_KSK) != 0) {
131
2.51k
    if (flags & DNS_KEYFLAG_REVOKE) {
132
850
      keyinfo = "revoked KSK";
133
1.66k
    } else {
134
1.66k
      keyinfo = "KSK";
135
1.66k
    }
136
3.84k
  } else {
137
3.84k
    keyinfo = "ZSK";
138
3.84k
  }
139
140
  /* protocol */
141
6.36k
  snprintf(buf, sizeof(buf), "%u", sr.base[0]);
142
6.36k
  isc_region_consume(&sr, 1);
143
6.36k
  RETERR(str_totext(buf, target));
144
6.36k
  RETERR(str_totext(" ", target));
145
146
  /* algorithm */
147
6.36k
  algorithm = sr.base[0];
148
6.36k
  snprintf(buf, sizeof(buf), "%u", algorithm);
149
6.36k
  isc_region_consume(&sr, 1);
150
6.36k
  RETERR(str_totext(buf, target));
151
152
  /* No Key? */
153
6.36k
  if (generic_key_nokey(rdata->type, flags)) {
154
1.06k
    return ISC_R_SUCCESS;
155
1.06k
  }
156
157
5.30k
  if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 &&
158
124
      algorithm == DNS_KEYALG_PRIVATEDNS)
159
52
  {
160
52
    dns_name_t name;
161
52
    dns_name_init(&name);
162
52
    dns_name_fromregion(&name, &sr);
163
52
    dns_name_format(&name, algbuf, sizeof(algbuf));
164
5.24k
  } else if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 &&
165
72
       algorithm == DNS_KEYALG_PRIVATEOID)
166
26
  {
167
26
    const unsigned char *in = sr.base + 1;
168
26
    ASN1_OBJECT *obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base);
169
26
    INSIST(obj != NULL);
170
26
    int n = i2t_ASN1_OBJECT(algbuf, sizeof(buf), obj);
171
26
    ASN1_OBJECT_free(obj);
172
26
    if (n == -1 || (size_t)n >= sizeof(algbuf)) {
173
0
      dns_secalg_format((dns_secalg_t)algorithm, algbuf,
174
0
            sizeof(algbuf));
175
0
    }
176
5.22k
  } else {
177
5.22k
    dns_secalg_format((dns_secalg_t)algorithm, algbuf,
178
5.22k
          sizeof(algbuf));
179
5.22k
  }
180
181
  /* key */
182
5.30k
  if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
183
124
    RETERR(str_totext(" (", target));
184
124
  }
185
5.30k
  RETERR(str_totext(tctx->linebreak, target));
186
187
5.30k
  if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) {
188
5.30k
    if (tctx->width == 0) { /* No splitting */
189
0
      RETERR(isc_base64_totext(&sr, 60, "", target));
190
5.30k
    } else {
191
5.30k
      RETERR(isc_base64_totext(&sr, tctx->width - 2,
192
5.30k
             tctx->linebreak, target));
193
5.30k
    }
194
5.30k
  } else {
195
0
    dns_rdata_toregion(rdata, &tmpr);
196
0
    snprintf(buf, sizeof(buf), "[key id = %u]",
197
0
       dst_region_computeid(&tmpr));
198
0
    RETERR(str_totext(buf, target));
199
0
  }
200
201
5.30k
  if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) {
202
124
    RETERR(str_totext(tctx->linebreak, target));
203
5.17k
  } else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
204
0
    RETERR(str_totext(" ", target));
205
0
  }
206
207
5.30k
  if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
208
124
    RETERR(str_totext(")", target));
209
124
  }
210
211
5.30k
  if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) {
212
124
    if (rdata->type == dns_rdatatype_dnskey ||
213
110
        rdata->type == dns_rdatatype_cdnskey)
214
59
    {
215
59
      RETERR(str_totext(" ; ", target));
216
59
      RETERR(str_totext(keyinfo, target));
217
59
    }
218
124
    RETERR(str_totext("; alg = ", target));
219
124
    RETERR(str_totext(algbuf, target));
220
124
    RETERR(str_totext(" ; key id = ", target));
221
124
    dns_rdata_toregion(rdata, &tmpr);
222
124
    snprintf(buf, sizeof(buf), "%u", dst_region_computeid(&tmpr));
223
124
    RETERR(str_totext(buf, target));
224
124
  }
225
5.30k
  return ISC_R_SUCCESS;
226
5.30k
}
227
228
static isc_result_t
229
75.1k
generic_fromwire_key(ARGS_FROMWIRE) {
230
75.1k
  unsigned char algorithm;
231
75.1k
  uint16_t flags;
232
75.1k
  isc_region_t sr;
233
234
75.1k
  UNUSED(rdclass);
235
75.1k
  UNUSED(dctx);
236
237
75.1k
  isc_buffer_activeregion(source, &sr);
238
75.1k
  if (sr.length < 4) {
239
38
    return ISC_R_UNEXPECTEDEND;
240
38
  }
241
75.1k
  flags = (sr.base[0] << 8) | sr.base[1];
242
243
75.1k
  if (type == dns_rdatatype_rkey && flags != 0U) {
244
15
    return DNS_R_FORMERR;
245
15
  }
246
247
75.0k
  algorithm = sr.base[3];
248
75.0k
  RETERR(mem_tobuffer(target, sr.base, 4));
249
75.0k
  isc_region_consume(&sr, 4);
250
75.0k
  isc_buffer_forward(source, 4);
251
252
75.0k
  if (generic_key_nokey(type, flags)) {
253
1.05k
    return ISC_R_SUCCESS;
254
1.05k
  }
255
73.9k
  if (sr.length == 0) {
256
20
    return ISC_R_UNEXPECTEDEND;
257
20
  }
258
259
73.9k
  if (algorithm == DNS_KEYALG_PRIVATEDNS ||
260
73.4k
      algorithm == DNS_KEYALG_PRIVATEOID)
261
643
  {
262
643
    isc_buffer_t b = *source;
263
643
    RETERR(check_private(&b, algorithm));
264
532
  }
265
266
73.8k
  isc_buffer_activeregion(source, &sr);
267
73.8k
  isc_buffer_forward(source, sr.length);
268
73.8k
  return mem_tobuffer(target, sr.base, sr.length);
269
73.9k
}
270
271
static isc_result_t
272
1.23k
fromtext_key(ARGS_FROMTEXT) {
273
1.23k
  REQUIRE(type == dns_rdatatype_key);
274
275
1.23k
  return generic_fromtext_key(CALL_FROMTEXT);
276
1.23k
}
277
278
static isc_result_t
279
2.03k
totext_key(ARGS_TOTEXT) {
280
2.03k
  REQUIRE(rdata != NULL);
281
2.03k
  REQUIRE(rdata->type == dns_rdatatype_key);
282
283
2.03k
  return generic_totext_key(CALL_TOTEXT);
284
2.03k
}
285
286
static isc_result_t
287
68.3k
fromwire_key(ARGS_FROMWIRE) {
288
68.3k
  REQUIRE(type == dns_rdatatype_key);
289
290
68.3k
  return generic_fromwire_key(CALL_FROMWIRE);
291
68.3k
}
292
293
static isc_result_t
294
1.03k
towire_key(ARGS_TOWIRE) {
295
1.03k
  isc_region_t sr;
296
297
1.03k
  REQUIRE(rdata != NULL);
298
1.03k
  REQUIRE(rdata->type == dns_rdatatype_key);
299
1.03k
  REQUIRE(rdata->length != 0);
300
301
1.03k
  UNUSED(cctx);
302
303
1.03k
  dns_rdata_toregion(rdata, &sr);
304
1.03k
  return mem_tobuffer(target, sr.base, sr.length);
305
1.03k
}
306
307
static int
308
2.01k
compare_key(ARGS_COMPARE) {
309
2.01k
  isc_region_t r1;
310
2.01k
  isc_region_t r2;
311
312
2.01k
  REQUIRE(rdata1 != NULL);
313
2.01k
  REQUIRE(rdata2 != NULL);
314
2.01k
  REQUIRE(rdata1->type == rdata2->type);
315
2.01k
  REQUIRE(rdata1->rdclass == rdata2->rdclass);
316
2.01k
  REQUIRE(rdata1->type == dns_rdatatype_key);
317
2.01k
  REQUIRE(rdata1->length != 0);
318
2.01k
  REQUIRE(rdata2->length != 0);
319
320
2.01k
  dns_rdata_toregion(rdata1, &r1);
321
2.01k
  dns_rdata_toregion(rdata2, &r2);
322
2.01k
  return isc_region_compare(&r1, &r2);
323
2.01k
}
324
325
static isc_result_t
326
0
generic_fromstruct_key(ARGS_FROMSTRUCT) {
327
0
  dns_rdata_key_t *key = source;
328
329
0
  REQUIRE(key != NULL);
330
0
  REQUIRE(key->common.rdtype == type);
331
0
  REQUIRE(key->common.rdclass == rdclass);
332
333
0
  UNUSED(type);
334
0
  UNUSED(rdclass);
335
336
0
  if (type == dns_rdatatype_rkey) {
337
0
    INSIST(key->flags == 0U);
338
0
  }
339
340
  /* Flags */
341
0
  RETERR(uint16_tobuffer(key->flags, target));
342
343
  /* Protocol */
344
0
  RETERR(uint8_tobuffer(key->protocol, target));
345
346
  /* Algorithm */
347
0
  RETERR(uint8_tobuffer(key->algorithm, target));
348
349
  /* Data */
350
0
  return mem_tobuffer(target, key->data, key->datalen);
351
0
}
352
353
static isc_result_t
354
230
generic_tostruct_key(ARGS_TOSTRUCT) {
355
230
  dns_rdata_key_t *key = target;
356
230
  isc_region_t sr;
357
358
230
  REQUIRE(key != NULL);
359
230
  REQUIRE(rdata->length >= 4U);
360
361
230
  REQUIRE(key != NULL);
362
230
  REQUIRE(key->common.rdclass == rdata->rdclass);
363
230
  REQUIRE(key->common.rdtype == rdata->type);
364
365
230
  dns_rdata_toregion(rdata, &sr);
366
367
  /* Flags */
368
230
  key->flags = uint16_fromregion(&sr);
369
230
  isc_region_consume(&sr, 2);
370
371
  /* Protocol */
372
230
  key->protocol = uint8_fromregion(&sr);
373
230
  isc_region_consume(&sr, 1);
374
375
  /* Algorithm */
376
230
  key->algorithm = uint8_fromregion(&sr);
377
230
  isc_region_consume(&sr, 1);
378
379
  /* Data */
380
230
  key->datalen = sr.length;
381
230
  key->data = mem_maybedup(mctx, sr.base, key->datalen);
382
230
  key->mctx = mctx;
383
230
  return ISC_R_SUCCESS;
384
230
}
385
386
static void
387
0
generic_freestruct_key(ARGS_FREESTRUCT) {
388
0
  dns_rdata_key_t *key = (dns_rdata_key_t *)source;
389
390
0
  REQUIRE(key != NULL);
391
392
0
  if (key->mctx == NULL) {
393
0
    return;
394
0
  }
395
396
0
  if (key->data != NULL) {
397
0
    isc_mem_free(key->mctx, key->data);
398
0
  }
399
0
  key->mctx = NULL;
400
0
}
401
402
static isc_result_t
403
0
fromstruct_key(ARGS_FROMSTRUCT) {
404
0
  REQUIRE(type == dns_rdatatype_key);
405
406
0
  return generic_fromstruct_key(CALL_FROMSTRUCT);
407
0
}
408
409
static isc_result_t
410
132
tostruct_key(ARGS_TOSTRUCT) {
411
132
  dns_rdata_key_t *key = target;
412
413
132
  REQUIRE(key != NULL);
414
132
  REQUIRE(rdata != NULL);
415
132
  REQUIRE(rdata->type == dns_rdatatype_key);
416
417
132
  DNS_RDATACOMMON_INIT(key, rdata->type, rdata->rdclass);
418
419
132
  return generic_tostruct_key(CALL_TOSTRUCT);
420
132
}
421
422
static void
423
0
freestruct_key(ARGS_FREESTRUCT) {
424
0
  dns_rdata_key_t *key = (dns_rdata_key_t *)source;
425
426
0
  REQUIRE(key != NULL);
427
0
  REQUIRE(key->common.rdtype == dns_rdatatype_key);
428
429
0
  generic_freestruct_key(source);
430
0
}
431
432
static isc_result_t
433
0
additionaldata_key(ARGS_ADDLDATA) {
434
0
  REQUIRE(rdata != NULL);
435
0
  REQUIRE(rdata->type == dns_rdatatype_key);
436
437
0
  UNUSED(rdata);
438
0
  UNUSED(owner);
439
0
  UNUSED(add);
440
0
  UNUSED(arg);
441
442
0
  return ISC_R_SUCCESS;
443
0
}
444
445
static isc_result_t
446
0
digest_key(ARGS_DIGEST) {
447
0
  isc_region_t r;
448
449
0
  REQUIRE(rdata != NULL);
450
0
  REQUIRE(rdata->type == dns_rdatatype_key);
451
452
0
  dns_rdata_toregion(rdata, &r);
453
454
0
  return (digest)(arg, &r);
455
0
}
456
457
static bool
458
0
checkowner_key(ARGS_CHECKOWNER) {
459
0
  REQUIRE(type == dns_rdatatype_key);
460
461
0
  UNUSED(name);
462
0
  UNUSED(type);
463
0
  UNUSED(rdclass);
464
0
  UNUSED(wildcard);
465
466
0
  return true;
467
0
}
468
469
static bool
470
0
checknames_key(ARGS_CHECKNAMES) {
471
0
  REQUIRE(rdata != NULL);
472
0
  REQUIRE(rdata->type == dns_rdatatype_key);
473
474
0
  UNUSED(rdata);
475
0
  UNUSED(owner);
476
0
  UNUSED(bad);
477
478
0
  return true;
479
0
}
480
481
static int
482
0
casecompare_key(ARGS_COMPARE) {
483
0
  return compare_key(rdata1, rdata2);
484
0
}
485
486
#endif /* RDATA_GENERIC_KEY_25_C */