Coverage Report

Created: 2026-02-26 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/rdata/generic/nsec3_50.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
/*
15
 * Copyright (C) 2004  Nominet, Ltd.
16
 *
17
 * Permission to use, copy, modify, and 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 NOMINET DISCLAIMS ALL WARRANTIES WITH
22
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
23
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
24
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
25
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
26
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
27
 * PERFORMANCE OF THIS SOFTWARE.
28
 */
29
30
/* RFC 5155 */
31
32
#ifndef RDATA_GENERIC_NSEC3_50_C
33
#define RDATA_GENERIC_NSEC3_50_C
34
35
#include <isc/base32.h>
36
#include <isc/iterated_hash.h>
37
38
#include <dns/nsec3.h>
39
40
18.2k
#define RRTYPE_NSEC3_ATTRIBUTES DNS_RDATATYPEATTR_DNSSEC
41
42
static isc_result_t
43
2.93k
fromtext_nsec3(ARGS_FROMTEXT) {
44
2.93k
  isc_token_t token;
45
2.93k
  unsigned int flags;
46
2.93k
  unsigned char hashalg;
47
2.93k
  isc_buffer_t b;
48
2.93k
  unsigned char buf[256];
49
50
2.93k
  REQUIRE(type == dns_rdatatype_nsec3);
51
52
2.93k
  UNUSED(type);
53
2.93k
  UNUSED(rdclass);
54
2.93k
  UNUSED(callbacks);
55
2.93k
  UNUSED(origin);
56
2.93k
  UNUSED(options);
57
58
  /* Hash. */
59
2.93k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
60
2.93k
              false));
61
2.93k
  RETTOK(dns_hashalg_fromtext(&hashalg, &token.value.as_textregion));
62
2.88k
  RETERR(uint8_tobuffer(hashalg, target));
63
64
  /* Flags. */
65
2.88k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
66
2.88k
              false));
67
2.87k
  flags = token.value.as_ulong;
68
2.87k
  if (flags > 255U) {
69
68
    RETTOK(ISC_R_RANGE);
70
68
  }
71
2.80k
  RETERR(uint8_tobuffer(flags, target));
72
73
  /* Iterations. */
74
2.80k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
75
2.80k
              false));
76
2.78k
  if (token.value.as_ulong > 0xffffU) {
77
12
    RETTOK(ISC_R_RANGE);
78
12
  }
79
2.77k
  RETERR(uint16_tobuffer(token.value.as_ulong, target));
80
81
  /* salt */
82
2.77k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
83
2.77k
              false));
84
2.76k
  if (token.value.as_textregion.length > (255 * 2)) {
85
2
    RETTOK(DNS_R_TEXTTOOLONG);
86
2
  }
87
2.76k
  if (strcmp(DNS_AS_STR(token), "-") == 0) {
88
618
    RETERR(uint8_tobuffer(0, target));
89
2.14k
  } else {
90
2.14k
    RETERR(uint8_tobuffer(strlen(DNS_AS_STR(token)) / 2, target));
91
2.14k
    RETERR(isc_hex_decodestring(DNS_AS_STR(token), target));
92
2.12k
  }
93
94
  /*
95
   * Next hash a single base32hex word.
96
   */
97
2.74k
  RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
98
2.74k
              false));
99
2.73k
  isc_buffer_init(&b, buf, sizeof(buf));
100
2.73k
  RETTOK(isc_base32hexnp_decodestring(DNS_AS_STR(token), &b));
101
2.68k
  switch (hashalg) {
102
49
  case dns_hash_sha1:
103
49
    if (isc_buffer_usedlength(&b) != ISC_SHA1_DIGESTLENGTH) {
104
45
      RETTOK(ISC_R_RANGE);
105
45
    }
106
4
    break;
107
2.63k
  default:
108
2.63k
    if (isc_buffer_usedlength(&b) > NSEC3_MAX_HASH_LENGTH) {
109
15
      RETTOK(ISC_R_RANGE);
110
15
    }
111
2.61k
    break;
112
2.68k
  }
113
2.62k
  RETERR(uint8_tobuffer(isc_buffer_usedlength(&b), target));
114
2.62k
  RETERR(mem_tobuffer(target, &buf, isc_buffer_usedlength(&b)));
115
116
2.62k
  return typemap_fromtext(lexer, target, true);
117
2.62k
}
118
119
static isc_result_t
120
3.62k
totext_nsec3(ARGS_TOTEXT) {
121
3.62k
  isc_region_t sr;
122
3.62k
  unsigned int i, j;
123
3.62k
  unsigned char hash;
124
3.62k
  unsigned char flags;
125
3.62k
  char buf[sizeof("TYPE65535")];
126
3.62k
  uint32_t iterations;
127
128
3.62k
  REQUIRE(rdata->type == dns_rdatatype_nsec3);
129
3.62k
  REQUIRE(rdata->length != 0);
130
131
3.62k
  dns_rdata_toregion(rdata, &sr);
132
133
  /* Hash */
134
3.62k
  hash = uint8_fromregion(&sr);
135
3.62k
  isc_region_consume(&sr, 1);
136
3.62k
  snprintf(buf, sizeof(buf), "%u ", hash);
137
3.62k
  RETERR(str_totext(buf, target));
138
139
  /* Flags */
140
3.62k
  flags = uint8_fromregion(&sr);
141
3.62k
  isc_region_consume(&sr, 1);
142
3.62k
  snprintf(buf, sizeof(buf), "%u ", flags);
143
3.62k
  RETERR(str_totext(buf, target));
144
145
  /* Iterations */
146
3.62k
  iterations = uint16_fromregion(&sr);
147
3.62k
  isc_region_consume(&sr, 2);
148
3.62k
  snprintf(buf, sizeof(buf), "%u ", iterations);
149
3.62k
  RETERR(str_totext(buf, target));
150
151
  /* Salt */
152
3.62k
  j = uint8_fromregion(&sr);
153
3.62k
  isc_region_consume(&sr, 1);
154
3.62k
  INSIST(j <= sr.length);
155
156
3.62k
  if (j != 0) {
157
1.57k
    i = sr.length;
158
1.57k
    sr.length = j;
159
1.57k
    RETERR(isc_hex_totext(&sr, 1, "", target));
160
1.57k
    sr.length = i - j;
161
2.05k
  } else {
162
2.05k
    RETERR(str_totext("-", target));
163
2.05k
  }
164
165
3.62k
  if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
166
68
    RETERR(str_totext(" (", target));
167
68
  }
168
3.62k
  RETERR(str_totext(tctx->linebreak, target));
169
170
  /* Next hash */
171
3.62k
  j = uint8_fromregion(&sr);
172
3.62k
  isc_region_consume(&sr, 1);
173
3.62k
  INSIST(j <= sr.length);
174
175
3.62k
  i = sr.length;
176
3.62k
  sr.length = j;
177
3.62k
  RETERR(isc_base32hexnp_totext(&sr, 1, "", target));
178
3.62k
  sr.length = i - j;
179
180
  /*
181
   * Don't leave a trailing space when there's no typemap present.
182
   */
183
3.62k
  if (((tctx->flags & DNS_STYLEFLAG_MULTILINE) == 0) && (sr.length > 0)) {
184
1.25k
    RETERR(str_totext(" ", target));
185
1.25k
  }
186
3.62k
  RETERR(typemap_totext(&sr, tctx, target));
187
188
3.62k
  if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
189
68
    RETERR(str_totext(" )", target));
190
68
  }
191
192
3.62k
  return ISC_R_SUCCESS;
193
3.62k
}
194
195
static isc_result_t
196
4.49k
fromwire_nsec3(ARGS_FROMWIRE) {
197
4.49k
  isc_region_t sr, rr;
198
4.49k
  unsigned int hash, saltlen, hashlen;
199
200
4.49k
  REQUIRE(type == dns_rdatatype_nsec3);
201
202
4.49k
  UNUSED(type);
203
4.49k
  UNUSED(rdclass);
204
4.49k
  UNUSED(dctx);
205
206
4.49k
  isc_buffer_activeregion(source, &sr);
207
4.49k
  rr = sr;
208
209
  /* hash(1), flags(1), iteration(2), saltlen(1) */
210
4.49k
  if (sr.length < 5U) {
211
12
    RETERR(DNS_R_FORMERR);
212
0
  }
213
4.48k
  hash = sr.base[0];
214
4.48k
  saltlen = sr.base[4];
215
4.48k
  isc_region_consume(&sr, 5);
216
217
4.48k
  if (sr.length < saltlen) {
218
9
    RETERR(DNS_R_FORMERR);
219
0
  }
220
4.47k
  isc_region_consume(&sr, saltlen);
221
222
4.47k
  if (sr.length < 1U) {
223
4
    RETERR(DNS_R_FORMERR);
224
0
  }
225
4.47k
  hashlen = sr.base[0];
226
4.47k
  isc_region_consume(&sr, 1);
227
228
4.47k
  switch (hash) {
229
1.40k
  case dns_hash_sha1:
230
1.40k
    if (hashlen != ISC_SHA1_DIGESTLENGTH || sr.length < hashlen) {
231
25
      RETERR(DNS_R_FORMERR);
232
0
    }
233
1.38k
    break;
234
3.06k
  default:
235
3.06k
    if (hashlen < 1 || hashlen > NSEC3_MAX_HASH_LENGTH ||
236
3.03k
        sr.length < hashlen)
237
37
    {
238
37
      RETERR(DNS_R_FORMERR);
239
0
    }
240
3.02k
    break;
241
4.47k
  }
242
4.41k
  isc_region_consume(&sr, hashlen);
243
244
4.41k
  RETERR(typemap_test(&sr, true));
245
246
4.28k
  RETERR(mem_tobuffer(target, rr.base, rr.length));
247
4.11k
  isc_buffer_forward(source, rr.length);
248
4.11k
  return ISC_R_SUCCESS;
249
4.28k
}
250
251
static isc_result_t
252
1.83k
towire_nsec3(ARGS_TOWIRE) {
253
1.83k
  isc_region_t sr;
254
255
1.83k
  REQUIRE(rdata->type == dns_rdatatype_nsec3);
256
1.83k
  REQUIRE(rdata->length != 0);
257
258
1.83k
  UNUSED(cctx);
259
260
1.83k
  dns_rdata_toregion(rdata, &sr);
261
1.83k
  return mem_tobuffer(target, sr.base, sr.length);
262
1.83k
}
263
264
static int
265
3.55k
compare_nsec3(ARGS_COMPARE) {
266
3.55k
  isc_region_t r1;
267
3.55k
  isc_region_t r2;
268
269
3.55k
  REQUIRE(rdata1->type == rdata2->type);
270
3.55k
  REQUIRE(rdata1->rdclass == rdata2->rdclass);
271
3.55k
  REQUIRE(rdata1->type == dns_rdatatype_nsec3);
272
3.55k
  REQUIRE(rdata1->length != 0);
273
3.55k
  REQUIRE(rdata2->length != 0);
274
275
3.55k
  dns_rdata_toregion(rdata1, &r1);
276
3.55k
  dns_rdata_toregion(rdata2, &r2);
277
3.55k
  return isc_region_compare(&r1, &r2);
278
3.55k
}
279
280
static isc_result_t
281
0
fromstruct_nsec3(ARGS_FROMSTRUCT) {
282
0
  dns_rdata_nsec3_t *nsec3 = source;
283
0
  isc_region_t region;
284
285
0
  REQUIRE(type == dns_rdatatype_nsec3);
286
0
  REQUIRE(nsec3 != NULL);
287
0
  REQUIRE(nsec3->common.rdtype == type);
288
0
  REQUIRE(nsec3->common.rdclass == rdclass);
289
0
  REQUIRE(nsec3->typebits != NULL || nsec3->len == 0);
290
291
0
  UNUSED(type);
292
0
  UNUSED(rdclass);
293
294
0
  RETERR(uint8_tobuffer(nsec3->hash, target));
295
0
  RETERR(uint8_tobuffer(nsec3->flags, target));
296
0
  RETERR(uint16_tobuffer(nsec3->iterations, target));
297
0
  RETERR(uint8_tobuffer(nsec3->salt_length, target));
298
0
  RETERR(mem_tobuffer(target, nsec3->salt, nsec3->salt_length));
299
0
  RETERR(uint8_tobuffer(nsec3->next_length, target));
300
0
  RETERR(mem_tobuffer(target, nsec3->next, nsec3->next_length));
301
302
0
  region.base = nsec3->typebits;
303
0
  region.length = nsec3->len;
304
0
  RETERR(typemap_test(&region, true));
305
0
  return mem_tobuffer(target, nsec3->typebits, nsec3->len);
306
0
}
307
308
static isc_result_t
309
0
tostruct_nsec3(ARGS_TOSTRUCT) {
310
0
  isc_region_t region;
311
0
  dns_rdata_nsec3_t *nsec3 = target;
312
313
0
  REQUIRE(rdata->type == dns_rdatatype_nsec3);
314
0
  REQUIRE(nsec3 != NULL);
315
0
  REQUIRE(rdata->length != 0);
316
317
0
  DNS_RDATACOMMON_INIT(nsec3, rdata->type, rdata->rdclass);
318
319
0
  region.base = rdata->data;
320
0
  region.length = rdata->length;
321
0
  nsec3->hash = uint8_consume_fromregion(&region);
322
0
  nsec3->flags = uint8_consume_fromregion(&region);
323
0
  nsec3->iterations = uint16_consume_fromregion(&region);
324
325
0
  nsec3->salt_length = uint8_consume_fromregion(&region);
326
0
  INSIST(nsec3->salt_length <= region.length);
327
0
  nsec3->salt = mem_maybedup(mctx, region.base, nsec3->salt_length);
328
0
  isc_region_consume(&region, nsec3->salt_length);
329
330
0
  nsec3->next_length = uint8_consume_fromregion(&region);
331
0
  INSIST(nsec3->next_length <= region.length);
332
0
  nsec3->next = mem_maybedup(mctx, region.base, nsec3->next_length);
333
0
  isc_region_consume(&region, nsec3->next_length);
334
335
0
  nsec3->len = region.length;
336
0
  nsec3->typebits = mem_maybedup(mctx, region.base, region.length);
337
0
  nsec3->mctx = mctx;
338
339
0
  return ISC_R_SUCCESS;
340
0
}
341
342
static void
343
0
freestruct_nsec3(ARGS_FREESTRUCT) {
344
0
  dns_rdata_nsec3_t *nsec3 = source;
345
346
0
  REQUIRE(nsec3 != NULL);
347
0
  REQUIRE(nsec3->common.rdtype == dns_rdatatype_nsec3);
348
349
0
  if (nsec3->mctx == NULL) {
350
0
    return;
351
0
  }
352
353
0
  if (nsec3->salt != NULL) {
354
0
    isc_mem_free(nsec3->mctx, nsec3->salt);
355
0
  }
356
0
  if (nsec3->next != NULL) {
357
0
    isc_mem_free(nsec3->mctx, nsec3->next);
358
0
  }
359
0
  if (nsec3->typebits != NULL) {
360
0
    isc_mem_free(nsec3->mctx, nsec3->typebits);
361
0
  }
362
0
  nsec3->mctx = NULL;
363
0
}
364
365
static isc_result_t
366
0
additionaldata_nsec3(ARGS_ADDLDATA) {
367
0
  REQUIRE(rdata->type == dns_rdatatype_nsec3);
368
369
0
  UNUSED(rdata);
370
0
  UNUSED(owner);
371
0
  UNUSED(add);
372
0
  UNUSED(arg);
373
374
0
  return ISC_R_SUCCESS;
375
0
}
376
377
static isc_result_t
378
0
digest_nsec3(ARGS_DIGEST) {
379
0
  isc_region_t r;
380
381
0
  REQUIRE(rdata->type == dns_rdatatype_nsec3);
382
383
0
  dns_rdata_toregion(rdata, &r);
384
0
  return (digest)(arg, &r);
385
0
}
386
387
static bool
388
5.12k
checkowner_nsec3(ARGS_CHECKOWNER) {
389
5.12k
  unsigned char owner[NSEC3_MAX_HASH_LENGTH];
390
5.12k
  isc_buffer_t buffer;
391
5.12k
  dns_label_t label;
392
393
5.12k
  REQUIRE(type == dns_rdatatype_nsec3);
394
395
5.12k
  UNUSED(type);
396
5.12k
  UNUSED(rdclass);
397
5.12k
  UNUSED(wildcard);
398
399
  /*
400
   * First label is a base32hex string without padding.
401
   */
402
5.12k
  dns_name_getlabel(name, 0, &label);
403
5.12k
  isc_region_consume(&label, 1);
404
5.12k
  isc_buffer_init(&buffer, owner, sizeof(owner));
405
5.12k
  if (isc_base32hexnp_decoderegion(&label, &buffer) == ISC_R_SUCCESS) {
406
5.09k
    return true;
407
5.09k
  }
408
409
24
  return false;
410
5.12k
}
411
412
static bool
413
0
checknames_nsec3(ARGS_CHECKNAMES) {
414
0
  REQUIRE(rdata->type == dns_rdatatype_nsec3);
415
416
0
  UNUSED(rdata);
417
0
  UNUSED(owner);
418
0
  UNUSED(bad);
419
420
0
  return true;
421
0
}
422
423
static int
424
0
casecompare_nsec3(ARGS_COMPARE) {
425
0
  return compare_nsec3(rdata1, rdata2);
426
0
}
427
428
#endif /* RDATA_GENERIC_NSEC3_50_C */