Coverage Report

Created: 2026-01-10 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/private.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
#include <stdbool.h>
15
16
#include <isc/base64.h>
17
#include <isc/result.h>
18
#include <isc/string.h>
19
#include <isc/types.h>
20
#include <isc/util.h>
21
22
#include <dns/nsec3.h>
23
#include <dns/private.h>
24
25
/*
26
 * We need to build the relevant chain if there exists a NSEC/NSEC3PARAM
27
 * at the apex; normally only one or the other of NSEC/NSEC3PARAM will exist.
28
 *
29
 * If a NSEC3PARAM RRset exists then we will need to build a NSEC chain
30
 * if all the NSEC3PARAM records (and associated chains) are slated for
31
 * destruction and we have not been told to NOT build the NSEC chain.
32
 *
33
 * If the NSEC set exist then check to see if there is a request to create
34
 * a NSEC3 chain.
35
 *
36
 * If neither NSEC/NSEC3PARAM RRsets exist at the origin and the private
37
 * type exists then we need to examine it to determine if NSEC3 chain has
38
 * been requested to be built otherwise a NSEC chain needs to be built.
39
 */
40
41
0
#define REMOVE(x)  (((x) & DNS_NSEC3FLAG_REMOVE) != 0)
42
0
#define CREATE(x)  (((x) & DNS_NSEC3FLAG_CREATE) != 0)
43
#define INITIAL(x) (((x) & DNS_NSEC3FLAG_INITIAL) != 0)
44
0
#define NONSEC(x)  (((x) & DNS_NSEC3FLAG_NONSEC) != 0)
45
46
/*
47
 * Work out if 'param' should be ignored or not (i.e. it is in the process
48
 * of being removed).
49
 *
50
 * Note: we 'belt-and-braces' here by also checking for a CREATE private
51
 * record and keep the param record in this case.
52
 */
53
54
static bool
55
0
ignore(dns_rdata_t *param, dns_rdataset_t *privateset) {
56
0
  DNS_RDATASET_FOREACH(privateset) {
57
0
    unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
58
0
    dns_rdata_t private = DNS_RDATA_INIT;
59
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
60
61
0
    dns_rdataset_current(privateset, &private);
62
0
    if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
63
0
            sizeof(buf)))
64
0
    {
65
0
      continue;
66
0
    }
67
    /*
68
     * We are going to create a new NSEC3 chain so it
69
     * doesn't matter if we are removing this one.
70
     */
71
0
    if (CREATE(rdata.data[1])) {
72
0
      return false;
73
0
    }
74
0
    if (rdata.data[0] != param->data[0] ||
75
0
        rdata.data[2] != param->data[2] ||
76
0
        rdata.data[3] != param->data[3] ||
77
0
        rdata.data[4] != param->data[4] ||
78
0
        memcmp(&rdata.data[5], &param->data[5], param->data[4]))
79
0
    {
80
0
      continue;
81
0
    }
82
    /*
83
     * The removal of this NSEC3 chain does NOT cause a
84
     * NSEC chain to be created so we don't need to tell
85
     * the caller that it will be removed.
86
     */
87
0
    if (NONSEC(rdata.data[1])) {
88
0
      return false;
89
0
    }
90
0
    return true;
91
0
  }
92
0
  return false;
93
0
}
94
95
isc_result_t
96
dns_private_chains(dns_db_t *db, dns_dbversion_t *ver,
97
       dns_rdatatype_t privatetype, bool *build_nsec,
98
0
       bool *build_nsec3) {
99
0
  dns_dbnode_t *node;
100
0
  dns_rdataset_t nsecset, nsec3paramset, privateset;
101
0
  bool nsec3chain;
102
0
  bool signing;
103
0
  isc_result_t result;
104
0
  unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE];
105
0
  unsigned int count;
106
107
0
  node = NULL;
108
0
  dns_rdataset_init(&nsecset);
109
0
  dns_rdataset_init(&nsec3paramset);
110
0
  dns_rdataset_init(&privateset);
111
112
0
  CHECK(dns_db_getoriginnode(db, &node));
113
114
0
  result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec, 0,
115
0
             (isc_stdtime_t)0, &nsecset, NULL);
116
117
0
  if (result != ISC_R_NOTFOUND) {
118
0
    CHECK(result);
119
0
  }
120
121
0
  result = dns_db_findrdataset(db, node, ver, dns_rdatatype_nsec3param, 0,
122
0
             (isc_stdtime_t)0, &nsec3paramset, NULL);
123
0
  if (result != ISC_R_NOTFOUND) {
124
0
    CHECK(result);
125
0
  }
126
127
0
  if (dns_rdataset_isassociated(&nsecset) &&
128
0
      dns_rdataset_isassociated(&nsec3paramset))
129
0
  {
130
0
    SET_IF_NOT_NULL(build_nsec, true);
131
0
    SET_IF_NOT_NULL(build_nsec3, true);
132
0
    goto success;
133
0
  }
134
135
0
  if (privatetype != (dns_rdatatype_t)0) {
136
0
    result = dns_db_findrdataset(db, node, ver, privatetype, 0,
137
0
               (isc_stdtime_t)0, &privateset,
138
0
               NULL);
139
0
    if (result != ISC_R_NOTFOUND) {
140
0
      CHECK(result);
141
0
    }
142
0
  }
143
144
  /*
145
   * Look to see if we also need to be creating a NSEC3 chain.
146
   */
147
0
  if (dns_rdataset_isassociated(&nsecset)) {
148
0
    SET_IF_NOT_NULL(build_nsec, true);
149
0
    SET_IF_NOT_NULL(build_nsec3, false);
150
0
    if (!dns_rdataset_isassociated(&privateset)) {
151
0
      goto success;
152
0
    }
153
0
    DNS_RDATASET_FOREACH(&privateset) {
154
0
      dns_rdata_t private = DNS_RDATA_INIT;
155
0
      dns_rdata_t rdata = DNS_RDATA_INIT;
156
157
0
      dns_rdataset_current(&privateset, &private);
158
0
      if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
159
0
              sizeof(buf)))
160
0
      {
161
0
        continue;
162
0
      }
163
0
      if (REMOVE(rdata.data[1])) {
164
0
        continue;
165
0
      }
166
0
      SET_IF_NOT_NULL(build_nsec3, true);
167
0
      break;
168
0
    }
169
0
    goto success;
170
0
  }
171
172
0
  if (dns_rdataset_isassociated(&nsec3paramset)) {
173
0
    SET_IF_NOT_NULL(build_nsec3, true);
174
0
    SET_IF_NOT_NULL(build_nsec, false);
175
0
    if (!dns_rdataset_isassociated(&privateset)) {
176
0
      goto success;
177
0
    }
178
    /*
179
     * If we are in the process of building a new NSEC3 chain
180
     * then we don't need to build a NSEC chain.
181
     */
182
0
    DNS_RDATASET_FOREACH(&privateset) {
183
0
      dns_rdata_t private = DNS_RDATA_INIT;
184
0
      dns_rdata_t rdata = DNS_RDATA_INIT;
185
186
0
      dns_rdataset_current(&privateset, &private);
187
0
      if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
188
0
              sizeof(buf)))
189
0
      {
190
0
        continue;
191
0
      }
192
0
      if (CREATE(rdata.data[1])) {
193
0
        goto success;
194
0
      }
195
0
    }
196
197
    /*
198
     * Check to see if there will be a active NSEC3CHAIN once
199
     * the changes queued complete.
200
     */
201
0
    count = 0;
202
0
    DNS_RDATASET_FOREACH(&nsec3paramset) {
203
0
      dns_rdata_t rdata = DNS_RDATA_INIT;
204
205
      /*
206
       * If there is more that one NSEC3 chain present then
207
       * we don't need to construct a NSEC chain.
208
       */
209
0
      if (++count > 1) {
210
0
        goto success;
211
0
      }
212
0
      dns_rdataset_current(&nsec3paramset, &rdata);
213
0
      if (ignore(&rdata, &privateset)) {
214
0
        continue;
215
0
      }
216
      /*
217
       * We still have a good NSEC3 chain or we are
218
       * not creating a NSEC chain as NONSEC is set.
219
       */
220
0
      goto success;
221
0
    }
222
223
    /*
224
     * The last NSEC3 chain is being removed and does not have
225
     * have NONSEC set.
226
     */
227
0
    SET_IF_NOT_NULL(build_nsec, true);
228
0
    goto success;
229
0
  }
230
231
0
  SET_IF_NOT_NULL(build_nsec, false);
232
0
  SET_IF_NOT_NULL(build_nsec3, false);
233
0
  if (!dns_rdataset_isassociated(&privateset)) {
234
0
    goto success;
235
0
  }
236
237
0
  signing = false;
238
0
  nsec3chain = false;
239
240
0
  DNS_RDATASET_FOREACH(&privateset) {
241
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
242
0
    dns_rdata_t private = DNS_RDATA_INIT;
243
244
0
    dns_rdataset_current(&privateset, &private);
245
0
    if (!dns_nsec3param_fromprivate(&private, &rdata, buf,
246
0
            sizeof(buf)))
247
0
    {
248
      /*
249
       * Look for record that says we are signing the
250
       * zone with a key.
251
       */
252
0
      if (private.length == 5 && private.data[0] != 0 &&
253
0
          private.data[3] == 0 && private.data[4] == 0)
254
0
      {
255
0
        signing = true;
256
0
      }
257
0
    } else {
258
0
      if (CREATE(rdata.data[1])) {
259
0
        nsec3chain = true;
260
0
      }
261
0
    }
262
0
  }
263
264
0
  if (signing) {
265
0
    if (nsec3chain) {
266
0
      SET_IF_NOT_NULL(build_nsec3, true);
267
0
    } else {
268
0
      SET_IF_NOT_NULL(build_nsec, true);
269
0
    }
270
0
  }
271
272
0
success:
273
0
  result = ISC_R_SUCCESS;
274
0
cleanup:
275
0
  dns_rdataset_cleanup(&nsecset);
276
0
  dns_rdataset_cleanup(&nsec3paramset);
277
0
  dns_rdataset_cleanup(&privateset);
278
0
  if (node != NULL) {
279
0
    dns_db_detachnode(&node);
280
0
  }
281
0
  return result;
282
0
}
283
284
isc_result_t
285
0
dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) {
286
0
  isc_result_t result;
287
288
0
  if (private->length < 5) {
289
0
    return ISC_R_NOTFOUND;
290
0
  }
291
292
0
  if (private->data[0] == 0) {
293
0
    unsigned char nsec3buf[DNS_NSEC3PARAM_BUFFERSIZE];
294
0
    unsigned char newbuf[DNS_NSEC3PARAM_BUFFERSIZE];
295
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
296
0
    dns_rdata_nsec3param_t nsec3param;
297
0
    bool del, init, nonsec;
298
0
    isc_buffer_t b;
299
300
0
    if (!dns_nsec3param_fromprivate(private, &rdata, nsec3buf,
301
0
            sizeof(nsec3buf)))
302
0
    {
303
0
      CLEANUP(ISC_R_FAILURE);
304
0
    }
305
306
0
    CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
307
308
0
    del = ((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0);
309
0
    init = ((nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0);
310
0
    nonsec = ((nsec3param.flags & DNS_NSEC3FLAG_NONSEC) != 0);
311
312
0
    nsec3param.flags &=
313
0
      ~(DNS_NSEC3FLAG_CREATE | DNS_NSEC3FLAG_REMOVE |
314
0
        DNS_NSEC3FLAG_INITIAL | DNS_NSEC3FLAG_NONSEC);
315
316
0
    if (init) {
317
0
      isc_buffer_putstr(buf, "Pending NSEC3 chain ");
318
0
    } else if (del) {
319
0
      isc_buffer_putstr(buf, "Removing NSEC3 chain ");
320
0
    } else {
321
0
      isc_buffer_putstr(buf, "Creating NSEC3 chain ");
322
0
    }
323
324
0
    dns_rdata_reset(&rdata);
325
0
    isc_buffer_init(&b, newbuf, sizeof(newbuf));
326
0
    CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
327
0
             dns_rdatatype_nsec3param,
328
0
             &nsec3param, &b));
329
330
0
    CHECK(dns_rdata_totext(&rdata, NULL, buf));
331
332
0
    if (del && !nonsec) {
333
0
      isc_buffer_putstr(buf, " / creating NSEC chain");
334
0
    }
335
0
  } else if (private->length == 5) {
336
    /* Old Form */
337
0
    unsigned char alg = private->data[0];
338
0
    dns_keytag_t keyid = (private->data[2] | private->data[1] << 8);
339
0
    char keybuf[DNS_SECALG_FORMATSIZE + BUFSIZ],
340
0
      algbuf[DNS_SECALG_FORMATSIZE];
341
0
    bool del = private->data[3];
342
0
    bool complete = private->data[4];
343
344
0
    if (del && complete) {
345
0
      isc_buffer_putstr(buf, "Done removing signatures for ");
346
0
    } else if (del) {
347
0
      isc_buffer_putstr(buf, "Removing signatures for ");
348
0
    } else if (complete) {
349
0
      isc_buffer_putstr(buf, "Done signing with ");
350
0
    } else {
351
0
      isc_buffer_putstr(buf, "Signing with ");
352
0
    }
353
354
0
    dns_secalg_format(alg, algbuf, sizeof(algbuf));
355
0
    snprintf(keybuf, sizeof(keybuf), "key %d/%s", keyid, algbuf);
356
0
    isc_buffer_putstr(buf, keybuf);
357
0
  } else if (private->length == 7) {
358
    /* New Form - supports private types */
359
0
    dns_keytag_t keyid = private->data[2] | (private->data[1] << 8);
360
0
    char keybuf[DNS_SECALG_FORMATSIZE + BUFSIZ],
361
0
      algbuf[DNS_SECALG_FORMATSIZE];
362
0
    bool del = private->data[3];
363
0
    bool complete = private->data[4];
364
0
    dst_algorithm_t alg = private->data[6] |
365
0
              (private->data[5] << 8);
366
367
0
    if (dst_algorithm_tosecalg(alg) != private->data[0]) {
368
0
      return ISC_R_NOTFOUND;
369
0
    }
370
371
0
    if (del && complete) {
372
0
      isc_buffer_putstr(buf, "Done removing signatures for ");
373
0
    } else if (del) {
374
0
      isc_buffer_putstr(buf, "Removing signatures for ");
375
0
    } else if (complete) {
376
0
      isc_buffer_putstr(buf, "Done signing with ");
377
0
    } else {
378
0
      isc_buffer_putstr(buf, "Signing with ");
379
0
    }
380
381
0
    dns_secalg_format(alg, algbuf, sizeof(algbuf));
382
0
    snprintf(keybuf, sizeof(keybuf), "key %d/%s", keyid, algbuf);
383
0
    isc_buffer_putstr(buf, keybuf);
384
0
  } else {
385
0
    return ISC_R_NOTFOUND;
386
0
  }
387
388
0
  isc_buffer_putuint8(buf, 0);
389
0
  result = ISC_R_SUCCESS;
390
0
cleanup:
391
0
  return result;
392
0
}