1 /* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17 #include <assert.h>
18 #include <pthread.h>
19 #include <sys/types.h>
20
21 #include "libdnssec/error.h"
22 #include "libdnssec/key.h"
23 #include "libdnssec/keytag.h"
24 #include "libdnssec/sign.h"
25 #include "knot/common/log.h"
26 #include "knot/dnssec/key-events.h"
27 #include "knot/dnssec/key_records.h"
28 #include "knot/dnssec/rrset-sign.h"
29 #include "knot/dnssec/zone-sign.h"
30 #include "libknot/libknot.h"
31 #include "libknot/dynarray.h"
32 #include "contrib/wire_ctx.h"
33
34 typedef struct {
35 node_t n;
36 uint16_t type;
37 } type_node_t;
38
39 typedef struct {
40 knot_dname_t *dname;
41 knot_dname_t *hashed_dname;
42 list_t *type_list;
43 } signed_info_t;
44
45 /*- private API - common functions -------------------------------------------*/
46
47 /*!
48 * \brief Initializes RR set and set owner and rclass from template RR set.
49 */
rrset_init_from(const knot_rrset_t * src,uint16_t type)50 static knot_rrset_t rrset_init_from(const knot_rrset_t *src, uint16_t type)
51 {
52 assert(src);
53 knot_rrset_t rrset;
54 knot_rrset_init(&rrset, src->owner, type, src->rclass, src->ttl);
55 return rrset;
56 }
57
58 /*!
59 * \brief Create empty RRSIG RR set for a given RR set to be covered.
60 */
create_empty_rrsigs_for(const knot_rrset_t * covered)61 static knot_rrset_t create_empty_rrsigs_for(const knot_rrset_t *covered)
62 {
63 assert(!knot_rrset_empty(covered));
64 return rrset_init_from(covered, KNOT_RRTYPE_RRSIG);
65 }
66
apex_rr_changed(const zone_node_t * old_apex,const zone_node_t * new_apex,uint16_t type)67 static bool apex_rr_changed(const zone_node_t *old_apex,
68 const zone_node_t *new_apex,
69 uint16_t type)
70 {
71 assert(old_apex);
72 assert(new_apex);
73 knot_rrset_t old_rr = node_rrset(old_apex, type);
74 knot_rrset_t new_rr = node_rrset(new_apex, type);
75
76 return !knot_rrset_equal(&old_rr, &new_rr, false);
77 }
78
apex_dnssec_changed(zone_update_t * update)79 static bool apex_dnssec_changed(zone_update_t *update)
80 {
81 if (update->zone->contents == NULL || update->new_cont == NULL) {
82 return false;
83 }
84 return apex_rr_changed(update->zone->contents->apex,
85 update->new_cont->apex, KNOT_RRTYPE_DNSKEY) ||
86 apex_rr_changed(update->zone->contents->apex,
87 update->new_cont->apex, KNOT_RRTYPE_NSEC3PARAM);
88 }
89
90 /*- private API - signing of in-zone nodes -----------------------------------*/
91
92 /*!
93 * \brief Check if there is a valid signature for a given RR set and key.
94 *
95 * \param covered RR set with covered records.
96 * \param rrsigs RR set with RRSIGs.
97 * \param key Signing key.
98 * \param ctx Signing context.
99 * \param policy DNSSEC policy.
100 * \param skip_crypto All RRSIGs in this node have been verified, just check validity.
101 * \param found_invalid Out: some matching but expired%invalid RRSIG found.
102 * \param at Out: RRSIG position.
103 *
104 * \return The signature exists and is valid.
105 */
valid_signature_exists(const knot_rrset_t * covered,const knot_rrset_t * rrsigs,const dnssec_key_t * key,dnssec_sign_ctx_t * ctx,const kdnssec_ctx_t * dnssec_ctx,bool skip_crypto,int * found_invalid,uint16_t * at)106 static bool valid_signature_exists(const knot_rrset_t *covered,
107 const knot_rrset_t *rrsigs,
108 const dnssec_key_t *key,
109 dnssec_sign_ctx_t *ctx,
110 const kdnssec_ctx_t *dnssec_ctx,
111 bool skip_crypto,
112 int *found_invalid,
113 uint16_t *at)
114 {
115 assert(key);
116
117 if (knot_rrset_empty(rrsigs)) {
118 return false;
119 }
120
121 uint16_t rrsigs_rdata_count = rrsigs->rrs.count;
122 knot_rdata_t *rdata = rrsigs->rrs.rdata;
123 bool found_valid = false;
124 for (uint16_t i = 0; i < rrsigs_rdata_count; i++) {
125 uint16_t rr_keytag = knot_rrsig_key_tag(rdata);
126 uint16_t rr_covered = knot_rrsig_type_covered(rdata);
127 uint8_t rr_algo = knot_rrsig_alg(rdata);
128 rdata = knot_rdataset_next(rdata);
129
130 uint16_t keytag = dnssec_key_get_keytag(key);
131 uint8_t algo = dnssec_key_get_algorithm(key);
132 if (rr_keytag != keytag || rr_algo != algo || rr_covered != covered->type) {
133 continue;
134 }
135
136 int ret = knot_check_signature(covered, rrsigs, i, key, ctx,
137 dnssec_ctx, skip_crypto);
138 if (ret == KNOT_EOK) {
139 if (at != NULL) {
140 *at = i;
141 }
142 if (found_invalid == NULL) {
143 return true;
144 } else {
145 found_valid = true; // continue searching for invalid RRSIG
146 }
147 } else if (found_invalid != NULL) {
148 *found_invalid = ret;
149 }
150 }
151
152 return found_valid;
153 }
154
155 /*!
156 * \brief Check if valid signature exists for all keys for a given RR set.
157 *
158 * \param covered RR set with covered records.
159 * \param rrsigs RR set with RRSIGs.
160 * \param sign_ctx Local zone signing context.
161 *
162 * \return Valid signature exists for every key.
163 */
all_signatures_exist(const knot_rrset_t * covered,const knot_rrset_t * rrsigs,zone_sign_ctx_t * sign_ctx)164 static bool all_signatures_exist(const knot_rrset_t *covered,
165 const knot_rrset_t *rrsigs,
166 zone_sign_ctx_t *sign_ctx)
167 {
168 assert(sign_ctx);
169
170 for (int i = 0; i < sign_ctx->count; i++) {
171 zone_key_t *key = &sign_ctx->keys[i];
172 if (!knot_zone_sign_use_key(key, covered)) {
173 continue;
174 }
175
176 if (!valid_signature_exists(covered, rrsigs, key->key,
177 sign_ctx->sign_ctxs[i],
178 sign_ctx->dnssec_ctx, false, NULL, NULL)) {
179 return false;
180 }
181 }
182
183 return true;
184 }
185
186 /*!
187 * \brief Note earliest expiration of a signature.
188 *
189 * \param rrsig RRSIG rdata.
190 * \param expires_at Current earliest expiration, will be updated.
191 */
note_earliest_expiration(const knot_rdata_t * rrsig,knot_time_t * expires_at)192 static void note_earliest_expiration(const knot_rdata_t *rrsig, knot_time_t *expires_at)
193 {
194 assert(rrsig);
195 if (expires_at == NULL) {
196 return;
197 }
198
199 uint32_t curr_rdata = knot_rrsig_sig_expiration(rrsig);
200 knot_time_t current = knot_time_from_u32(curr_rdata);
201 *expires_at = knot_time_min(current, *expires_at);
202 }
203
rrsig_covers_type(const knot_rrset_t * rrsig,uint16_t type)204 bool rrsig_covers_type(const knot_rrset_t *rrsig, uint16_t type)
205 {
206 if (knot_rrset_empty(rrsig)) {
207 return false;
208 }
209 assert(rrsig->type == KNOT_RRTYPE_RRSIG);
210 knot_rdata_t *one_rr = rrsig->rrs.rdata;
211 for (int i = 0; i < rrsig->rrs.count; i++) {
212 if (type == knot_rrsig_type_covered(one_rr)) {
213 return true;
214 }
215 one_rr = knot_rdataset_next(one_rr);
216 }
217 return false;
218 }
219
220 /*!
221 * \brief Add missing RRSIGs into the changeset for adding.
222 *
223 * \note Also removes invalid RRSIGs.
224 *
225 * \param covered RR set with covered records.
226 * \param rrsigs RR set with RRSIGs.
227 * \param sign_ctx Local zone signing context.
228 * \param skip_crypto All RRSIGs in this node have been verified, just check validity.
229 * \param changeset Changeset to be updated.
230 * \param update Zone update to be updated. Exactly one of "changeset" and "update" must be NULL!
231 * \param expires_at Earliest RRSIG expiration.
232 *
233 * \return Error code, KNOT_EOK if successful.
234 */
add_missing_rrsigs(const knot_rrset_t * covered,const knot_rrset_t * rrsigs,zone_sign_ctx_t * sign_ctx,bool skip_crypto,changeset_t * changeset,zone_update_t * update,knot_time_t * expires_at)235 static int add_missing_rrsigs(const knot_rrset_t *covered,
236 const knot_rrset_t *rrsigs,
237 zone_sign_ctx_t *sign_ctx,
238 bool skip_crypto,
239 changeset_t *changeset,
240 zone_update_t *update,
241 knot_time_t *expires_at)
242 {
243 assert(!knot_rrset_empty(covered));
244 assert(sign_ctx);
245 assert((bool)changeset != (bool)update);
246
247 knot_rrset_t to_add = create_empty_rrsigs_for(covered);
248 knot_rrset_t to_remove = create_empty_rrsigs_for(covered);
249 int result = (!rrsig_covers_type(rrsigs, covered->type) ? KNOT_EOK :
250 knot_synth_rrsig(covered->type, &rrsigs->rrs, &to_remove.rrs, NULL));
251
252 if (result == KNOT_EOK && sign_ctx->dnssec_ctx->offline_rrsig != NULL &&
253 knot_dname_cmp(sign_ctx->dnssec_ctx->offline_rrsig->owner, covered->owner) == 0 &&
254 rrsig_covers_type(sign_ctx->dnssec_ctx->offline_rrsig, covered->type)) {
255 result = knot_synth_rrsig(covered->type,
256 &sign_ctx->dnssec_ctx->offline_rrsig->rrs, &to_add.rrs, NULL);
257 if (result == KNOT_EOK) {
258 // don't remove what shall be added
259 result = knot_rdataset_subtract(&to_remove.rrs, &to_add.rrs, NULL);
260 }
261 if (result == KNOT_EOK && !knot_rrset_empty(rrsigs)) {
262 // don't add what's already present
263 result = knot_rdataset_subtract(&to_add.rrs, &rrsigs->rrs, NULL);
264 }
265 }
266
267 for (size_t i = 0; i < sign_ctx->count && result == KNOT_EOK; i++) {
268 const zone_key_t *key = &sign_ctx->keys[i];
269 if (!knot_zone_sign_use_key(key, covered)) {
270 continue;
271 }
272
273 uint16_t valid_at;
274 if (valid_signature_exists(covered, rrsigs, key->key, sign_ctx->sign_ctxs[i],
275 sign_ctx->dnssec_ctx, skip_crypto, NULL, &valid_at)) {
276 knot_rdata_t *valid_rr = knot_rdataset_at(&rrsigs->rrs, valid_at);
277 result = knot_rdataset_remove(&to_remove.rrs, valid_rr, NULL);
278 note_earliest_expiration(valid_rr, expires_at);
279 continue;
280 }
281
282 result = knot_sign_rrset(&to_add, covered, key->key, sign_ctx->sign_ctxs[i],
283 sign_ctx->dnssec_ctx, NULL, expires_at);
284 }
285
286 if (!knot_rrset_empty(&to_remove) && result == KNOT_EOK) {
287 if (changeset != NULL) {
288 result = changeset_add_removal(changeset, &to_remove, 0);
289 } else {
290 result = zone_update_remove(update, &to_remove);
291 }
292 }
293
294 if (!knot_rrset_empty(&to_add) && result == KNOT_EOK) {
295 if (changeset != NULL) {
296 result = changeset_add_addition(changeset, &to_add, 0);
297 } else {
298 result = zone_update_add(update, &to_add);
299 }
300 }
301
302 knot_rdataset_clear(&to_add.rrs, NULL);
303 knot_rdataset_clear(&to_remove.rrs, NULL);
304
305 return result;
306 }
307
key_used(bool ksk,bool zsk,uint16_t type,const knot_dname_t * owner,const knot_dname_t * zone_apex)308 static bool key_used(bool ksk, bool zsk, uint16_t type,
309 const knot_dname_t *owner, const knot_dname_t *zone_apex)
310 {
311 if (knot_dname_cmp(owner, zone_apex) != 0) {
312 return zsk;
313 }
314 switch (type) {
315 case KNOT_RRTYPE_DNSKEY:
316 case KNOT_RRTYPE_CDNSKEY:
317 case KNOT_RRTYPE_CDS:
318 return ksk;
319 default:
320 return zsk;
321 }
322 }
323
knot_validate_rrsigs(const knot_rrset_t * covered,const knot_rrset_t * rrsigs,zone_sign_ctx_t * sign_ctx,bool skip_crypto)324 int knot_validate_rrsigs(const knot_rrset_t *covered,
325 const knot_rrset_t *rrsigs,
326 zone_sign_ctx_t *sign_ctx,
327 bool skip_crypto)
328 {
329 if (covered == NULL || rrsigs == NULL || sign_ctx == NULL) {
330 return KNOT_EINVAL;
331 }
332
333 bool valid_exists = false;
334 int ret = KNOT_EOK;
335 for (size_t i = 0; i < sign_ctx->count; i++) {
336 const knot_kasp_key_t *key = &sign_ctx->dnssec_ctx->zone->keys[i];
337 if (!key_used(key->is_ksk, key->is_zsk, covered->type,
338 covered->owner, sign_ctx->dnssec_ctx->zone->dname)) {
339 continue;
340 }
341
342 uint16_t valid_at;
343 if (valid_signature_exists(covered, rrsigs, key->key, sign_ctx->sign_ctxs[i],
344 sign_ctx->dnssec_ctx, skip_crypto, &ret, &valid_at)) {
345 valid_exists = true;
346 }
347 }
348
349 return valid_exists ? ret : KNOT_DNSSEC_ENOSIG;
350 }
351
352 /*!
353 * \brief Add all RRSIGs into the changeset for removal.
354 *
355 * \param covered RR set with covered records.
356 * \param changeset Changeset to be updated.
357 *
358 * \return Error code, KNOT_EOK if successful.
359 */
remove_rrset_rrsigs(const knot_dname_t * owner,uint16_t type,const knot_rrset_t * rrsigs,changeset_t * changeset)360 static int remove_rrset_rrsigs(const knot_dname_t *owner, uint16_t type,
361 const knot_rrset_t *rrsigs,
362 changeset_t *changeset)
363 {
364 assert(owner);
365 assert(changeset);
366 knot_rrset_t synth_rrsig;
367 knot_rrset_init(&synth_rrsig, (knot_dname_t *)owner,
368 KNOT_RRTYPE_RRSIG, rrsigs->rclass, rrsigs->ttl);
369 int ret = knot_synth_rrsig(type, &rrsigs->rrs, &synth_rrsig.rrs, NULL);
370 if (ret != KNOT_EOK) {
371 if (ret != KNOT_ENOENT) {
372 return ret;
373 }
374 return KNOT_EOK;
375 }
376
377 ret = changeset_add_removal(changeset, &synth_rrsig, 0);
378 knot_rdataset_clear(&synth_rrsig.rrs, NULL);
379
380 return ret;
381 }
382
383 /*!
384 * \brief Drop all existing and create new RRSIGs for covered records.
385 *
386 * \param covered RR set with covered records.
387 * \param rrsigs Existing RRSIGs for covered RR set.
388 * \param sign_ctx Local zone signing context.
389 * \param changeset Changeset to be updated.
390 *
391 * \return Error code, KNOT_EOK if successful.
392 */
force_resign_rrset(const knot_rrset_t * covered,const knot_rrset_t * rrsigs,zone_sign_ctx_t * sign_ctx,changeset_t * changeset)393 static int force_resign_rrset(const knot_rrset_t *covered,
394 const knot_rrset_t *rrsigs,
395 zone_sign_ctx_t *sign_ctx,
396 changeset_t *changeset)
397 {
398 assert(!knot_rrset_empty(covered));
399
400 if (!knot_rrset_empty(rrsigs)) {
401 int result = remove_rrset_rrsigs(covered->owner, covered->type,
402 rrsigs, changeset);
403 if (result != KNOT_EOK) {
404 return result;
405 }
406 }
407
408 return add_missing_rrsigs(covered, NULL, sign_ctx, false, changeset, NULL, NULL);
409 }
410
411 /*!
412 * \brief Drop all expired and create new RRSIGs for covered records.
413 *
414 * \param covered RR set with covered records.
415 * \param rrsigs Existing RRSIGs for covered RR set.
416 * \param sign_ctx Local zone signing context.
417 * \param skip_crypto All RRSIGs in this node have been verified, just check validity.
418 * \param changeset Changeset to be updated.
419 * \param expires_at Current earliest expiration, will be updated.
420 *
421 * \return Error code, KNOT_EOK if successful.
422 */
resign_rrset(const knot_rrset_t * covered,const knot_rrset_t * rrsigs,zone_sign_ctx_t * sign_ctx,bool skip_crypto,changeset_t * changeset,knot_time_t * expires_at)423 static int resign_rrset(const knot_rrset_t *covered,
424 const knot_rrset_t *rrsigs,
425 zone_sign_ctx_t *sign_ctx,
426 bool skip_crypto,
427 changeset_t *changeset,
428 knot_time_t *expires_at)
429 {
430 assert(!knot_rrset_empty(covered));
431
432 return add_missing_rrsigs(covered, rrsigs, sign_ctx, skip_crypto, changeset, NULL, expires_at);
433 }
434
remove_standalone_rrsigs(const zone_node_t * node,const knot_rrset_t * rrsigs,changeset_t * changeset)435 static int remove_standalone_rrsigs(const zone_node_t *node,
436 const knot_rrset_t *rrsigs,
437 changeset_t *changeset)
438 {
439 if (rrsigs == NULL) {
440 return KNOT_EOK;
441 }
442
443 uint16_t rrsigs_rdata_count = rrsigs->rrs.count;
444 knot_rdata_t *rdata = rrsigs->rrs.rdata;
445 for (uint16_t i = 0; i < rrsigs_rdata_count; ++i) {
446 uint16_t type_covered = knot_rrsig_type_covered(rdata);
447 if (!node_rrtype_exists(node, type_covered)) {
448 knot_rrset_t to_remove;
449 knot_rrset_init(&to_remove, rrsigs->owner, rrsigs->type,
450 rrsigs->rclass, rrsigs->ttl);
451 int ret = knot_rdataset_add(&to_remove.rrs, rdata, NULL);
452 if (ret != KNOT_EOK) {
453 return ret;
454 }
455 ret = changeset_add_removal(changeset, &to_remove, 0);
456 knot_rdataset_clear(&to_remove.rrs, NULL);
457 if (ret != KNOT_EOK) {
458 return ret;
459 }
460 }
461 rdata = knot_rdataset_next(rdata);
462 }
463
464 return KNOT_EOK;
465 }
466
467 /*!
468 * \brief Update RRSIGs in a given node by updating changeset.
469 *
470 * \param node Node to be signed.
471 * \param sign_ctx Local zone signing context.
472 * \param changeset Changeset to be updated.
473 * \param expires_at Current earliest expiration, will be updated.
474 *
475 * \return Error code, KNOT_EOK if successful.
476 */
sign_node_rrsets(const zone_node_t * node,zone_sign_ctx_t * sign_ctx,changeset_t * changeset,knot_time_t * expires_at,dnssec_validation_hint_t * hint)477 static int sign_node_rrsets(const zone_node_t *node,
478 zone_sign_ctx_t *sign_ctx,
479 changeset_t *changeset,
480 knot_time_t *expires_at,
481 dnssec_validation_hint_t *hint)
482 {
483 assert(node);
484 assert(sign_ctx);
485
486 int result = KNOT_EOK;
487 knot_rrset_t rrsigs = node_rrset(node, KNOT_RRTYPE_RRSIG);
488 bool skip_crypto = (node->flags & NODE_FLAGS_RRSIGS_VALID) &&
489 !sign_ctx->dnssec_ctx->keytag_conflict;
490
491 for (int i = 0; result == KNOT_EOK && i < node->rrset_count; i++) {
492 knot_rrset_t rrset = node_rrset_at(node, i);
493 assert(rrset.type != KNOT_RRTYPE_ANY);
494
495 if (!knot_zone_sign_rr_should_be_signed(node, &rrset)) {
496 if (!sign_ctx->dnssec_ctx->validation_mode) {
497 result = remove_rrset_rrsigs(rrset.owner, rrset.type, &rrsigs, changeset);
498 }
499 continue;
500 }
501
502 if (sign_ctx->dnssec_ctx->validation_mode) {
503 result = knot_validate_rrsigs(&rrset, &rrsigs, sign_ctx, skip_crypto);
504 if (result != KNOT_EOK) {
505 hint->node = node->owner;
506 hint->rrtype = rrset.type;
507 }
508 } else if (sign_ctx->dnssec_ctx->rrsig_drop_existing) {
509 result = force_resign_rrset(&rrset, &rrsigs,
510 sign_ctx, changeset);
511 } else {
512 result = resign_rrset(&rrset, &rrsigs, sign_ctx, skip_crypto,
513 changeset, expires_at);
514 }
515 }
516
517 if (result == KNOT_EOK) {
518 result = remove_standalone_rrsigs(node, &rrsigs, changeset);
519 }
520 return result;
521 }
522
523 /*!
524 * \brief Struct to carry data for 'sign_data' callback function.
525 */
526 typedef struct {
527 zone_tree_t *tree;
528 zone_sign_ctx_t *sign_ctx;
529 changeset_t changeset;
530 knot_time_t expires_at;
531 dnssec_validation_hint_t *hint;
532 size_t num_threads;
533 size_t thread_index;
534 size_t rrset_index;
535 int errcode;
536 int thread_init_errcode;
537 pthread_t thread;
538 } node_sign_args_t;
539
540 /*!
541 * \brief Sign node (callback function).
542 *
543 * \param node Node to be signed.
544 * \param data Callback data, node_sign_args_t.
545 */
sign_node(zone_node_t * node,void * data)546 static int sign_node(zone_node_t *node, void *data)
547 {
548 assert(node);
549 assert(data);
550
551 node_sign_args_t *args = (node_sign_args_t *)data;
552
553 if (node->rrset_count == 0) {
554 return KNOT_EOK;
555 }
556
557 if (args->rrset_index++ % args->num_threads != args->thread_index) {
558 return KNOT_EOK;
559 }
560
561 int result = sign_node_rrsets(node, args->sign_ctx,
562 &args->changeset, &args->expires_at,
563 args->hint);
564
565 return result;
566 }
567
tree_sign_thread(void * _arg)568 static void *tree_sign_thread(void *_arg)
569 {
570 node_sign_args_t *arg = _arg;
571 arg->errcode = zone_tree_apply(arg->tree, sign_node, _arg);
572 return NULL;
573 }
574
set_signed(zone_node_t * node,_unused_ void * data)575 static int set_signed(zone_node_t *node, _unused_ void *data)
576 {
577 node->flags |= NODE_FLAGS_RRSIGS_VALID;
578 return KNOT_EOK;
579 }
580
581 /*!
582 * \brief Update RRSIGs in a given zone tree by updating changeset.
583 *
584 * \param tree Zone tree to be signed.
585 * \param num_threads Number of threads to use for parallel signing.
586 * \param zone_keys Zone keys.
587 * \param policy DNSSEC policy.
588 * \param update Zone update structure to be updated.
589 * \param expires_at Expiration time of the oldest signature in zone.
590 *
591 * \return Error code, KNOT_EOK if successful.
592 */
zone_tree_sign(zone_tree_t * tree,size_t num_threads,zone_keyset_t * zone_keys,const kdnssec_ctx_t * dnssec_ctx,zone_update_t * update,knot_time_t * expires_at)593 static int zone_tree_sign(zone_tree_t *tree,
594 size_t num_threads,
595 zone_keyset_t *zone_keys,
596 const kdnssec_ctx_t *dnssec_ctx,
597 zone_update_t *update,
598 knot_time_t *expires_at)
599 {
600 assert(zone_keys || dnssec_ctx->validation_mode);
601 assert(dnssec_ctx);
602 assert(update || dnssec_ctx->validation_mode);
603
604 int ret = KNOT_EOK;
605 node_sign_args_t args[num_threads];
606 memset(args, 0, sizeof(args));
607 *expires_at = knot_time_plus(dnssec_ctx->now, dnssec_ctx->policy->rrsig_lifetime);
608
609 // init context structures
610 for (size_t i = 0; i < num_threads; i++) {
611 args[i].tree = tree;
612 args[i].sign_ctx = dnssec_ctx->validation_mode
613 ? zone_validation_ctx(dnssec_ctx)
614 : zone_sign_ctx(zone_keys, dnssec_ctx);
615 if (args[i].sign_ctx == NULL) {
616 ret = KNOT_ENOMEM;
617 break;
618 }
619 ret = changeset_init(&args[i].changeset, dnssec_ctx->zone->dname);
620 if (ret != KNOT_EOK) {
621 break;
622 }
623 args[i].expires_at = 0;
624 args[i].hint = &update->validation_hint;
625 args[i].num_threads = num_threads;
626 args[i].thread_index = i;
627 args[i].rrset_index = 0;
628 args[i].errcode = KNOT_EOK;
629 args[i].thread_init_errcode = -1;
630 }
631 if (ret != KNOT_EOK) {
632 for (size_t i = 0; i < num_threads; i++) {
633 changeset_clear(&args[i].changeset);
634 zone_sign_ctx_free(args[i].sign_ctx);
635 }
636 return ret;
637 }
638
639 if (num_threads == 1) {
640 args[0].thread_init_errcode = 0;
641 tree_sign_thread(&args[0]);
642 } else {
643 // start working threads
644 for (size_t i = 0; i < num_threads; i++) {
645 args[i].thread_init_errcode =
646 pthread_create(&args[i].thread, NULL, tree_sign_thread, &args[i]);
647 }
648
649 // join those threads that have been really started
650 for (size_t i = 0; i < num_threads; i++) {
651 if (args[i].thread_init_errcode == 0) {
652 args[i].thread_init_errcode = pthread_join(args[i].thread, NULL);
653 }
654 }
655 }
656
657 // collect return code and results
658 for (size_t i = 0; i < num_threads; i++) {
659 if (ret == KNOT_EOK) {
660 if (args[i].thread_init_errcode != 0) {
661 ret = knot_map_errno_code(args[i].thread_init_errcode);
662 } else {
663 ret = args[i].errcode;
664 if (ret == KNOT_EOK && !dnssec_ctx->validation_mode) {
665 ret = zone_update_apply_changeset(update, &args[i].changeset); // _fix not needed
666 *expires_at = knot_time_min(*expires_at, args[i].expires_at);
667 }
668 }
669 }
670 assert(!dnssec_ctx->validation_mode || changeset_empty(&args[i].changeset));
671 changeset_clear(&args[i].changeset);
672 zone_sign_ctx_free(args[i].sign_ctx);
673 }
674
675 return ret;
676 }
677
678 /*- private API - signing of NSEC(3) in changeset ----------------------------*/
679
680 /*!
681 * \brief Struct to carry data for changeset signing callback functions.
682 */
683 typedef struct {
684 const zone_contents_t *zone;
685 changeset_iter_t itt;
686 zone_sign_ctx_t *sign_ctx;
687 changeset_t changeset;
688 knot_time_t expires_at;
689 size_t num_threads;
690 size_t thread_index;
691 size_t rrset_index;
692 int errcode;
693 int thread_init_errcode;
694 pthread_t thread;
695 } changeset_signing_data_t;
696
rrset_add_zone_key(knot_rrset_t * rrset,zone_key_t * zone_key)697 int rrset_add_zone_key(knot_rrset_t *rrset, zone_key_t *zone_key)
698 {
699 if (rrset == NULL || zone_key == NULL) {
700 return KNOT_EINVAL;
701 }
702
703 dnssec_binary_t dnskey_rdata = { 0 };
704 dnssec_key_get_rdata(zone_key->key, &dnskey_rdata);
705
706 return knot_rrset_add_rdata(rrset, dnskey_rdata.data, dnskey_rdata.size, NULL);
707 }
708
rrset_add_zone_ds(knot_rrset_t * rrset,zone_key_t * zone_key,dnssec_key_digest_t dt)709 static int rrset_add_zone_ds(knot_rrset_t *rrset, zone_key_t *zone_key, dnssec_key_digest_t dt)
710 {
711 assert(rrset);
712 assert(zone_key);
713
714 dnssec_binary_t cds_rdata = { 0 };
715 zone_key_calculate_ds(zone_key, dt, &cds_rdata);
716
717 return knot_rrset_add_rdata(rrset, cds_rdata.data, cds_rdata.size, NULL);
718 }
719
knot_zone_sign(zone_update_t * update,zone_keyset_t * zone_keys,const kdnssec_ctx_t * dnssec_ctx,knot_time_t * expire_at)720 int knot_zone_sign(zone_update_t *update,
721 zone_keyset_t *zone_keys,
722 const kdnssec_ctx_t *dnssec_ctx,
723 knot_time_t *expire_at)
724 {
725 if (!update || !dnssec_ctx || !expire_at ||
726 dnssec_ctx->policy->signing_threads < 1 ||
727 (zone_keys == NULL && !dnssec_ctx->validation_mode)) {
728 return KNOT_EINVAL;
729 }
730
731 int result;
732
733 knot_time_t normal_expire = 0;
734 result = zone_tree_sign(update->new_cont->nodes, dnssec_ctx->policy->signing_threads,
735 zone_keys, dnssec_ctx, update, &normal_expire);
736 if (result != KNOT_EOK) {
737 return result;
738 }
739
740 knot_time_t nsec3_expire = 0;
741 result = zone_tree_sign(update->new_cont->nsec3_nodes, dnssec_ctx->policy->signing_threads,
742 zone_keys, dnssec_ctx, update, &nsec3_expire);
743 if (result != KNOT_EOK) {
744 return result;
745 }
746
747 bool whole = !(update->flags & UPDATE_INCREMENTAL);
748 result = zone_tree_apply(whole ? update->new_cont->nodes : update->a_ctx->node_ptrs, set_signed, NULL);
749 if (result == KNOT_EOK) {
750 result = zone_tree_apply(whole ? update->new_cont->nsec3_nodes : update->a_ctx->nsec3_ptrs, set_signed, NULL);
751 }
752
753 *expire_at = knot_time_min(normal_expire, nsec3_expire);
754
755 return result;
756 }
757
knot_zone_sign_get_cdnskeys(const kdnssec_ctx_t * ctx,zone_keyset_t * zone_keys)758 keyptr_dynarray_t knot_zone_sign_get_cdnskeys(const kdnssec_ctx_t *ctx,
759 zone_keyset_t *zone_keys)
760 {
761 keyptr_dynarray_t r = { 0 };
762 unsigned crp = ctx->policy->cds_cdnskey_publish;
763 unsigned cds_published = 0;
764
765 if (crp == CDS_CDNSKEY_ROLLOVER || crp == CDS_CDNSKEY_ALWAYS ||
766 crp == CDS_CDNSKEY_DOUBLE_DS) {
767 // first, add strictly-ready keys
768 for (int i = 0; i < zone_keys->count; i++) {
769 zone_key_t *key = &zone_keys->keys[i];
770 if (key->is_ready) {
771 assert(key->is_ksk);
772 keyptr_dynarray_add(&r, &key);
773 if (!key->is_pub_only) {
774 cds_published++;
775 }
776 }
777 }
778
779 // second, add active keys
780 if ((crp == CDS_CDNSKEY_ALWAYS && cds_published == 0) ||
781 (crp == CDS_CDNSKEY_DOUBLE_DS)) {
782 for (int i = 0; i < zone_keys->count; i++) {
783 zone_key_t *key = &zone_keys->keys[i];
784 if (key->is_ksk && key->is_active && !key->is_ready) {
785 keyptr_dynarray_add(&r, &key);
786 }
787 }
788 }
789
790 if ((crp != CDS_CDNSKEY_DOUBLE_DS && cds_published > 1) ||
791 (cds_published > 2)) {
792 log_zone_warning(ctx->zone->dname, "DNSSEC, published CDS/CDNSKEY records for too many (%u) keys", cds_published);
793 }
794 }
795
796 return r;
797 }
798
knot_zone_sign_add_dnskeys(zone_keyset_t * zone_keys,const kdnssec_ctx_t * dnssec_ctx,key_records_t * add_r)799 int knot_zone_sign_add_dnskeys(zone_keyset_t *zone_keys, const kdnssec_ctx_t *dnssec_ctx,
800 key_records_t *add_r)
801 {
802 if (add_r == NULL) {
803 return KNOT_EINVAL;
804 }
805 int ret = KNOT_EOK;
806 for (int i = 0; i < zone_keys->count; i++) {
807 zone_key_t *key = &zone_keys->keys[i];
808 if (key->is_public) {
809 ret = rrset_add_zone_key(&add_r->dnskey, key);
810 if (ret != KNOT_EOK) {
811 return ret;
812 }
813 }
814 }
815 keyptr_dynarray_t kcdnskeys = knot_zone_sign_get_cdnskeys(dnssec_ctx, zone_keys);
816 knot_dynarray_foreach(keyptr, zone_key_t *, ksk_for_cds, kcdnskeys) {
817 ret = rrset_add_zone_key(&add_r->cdnskey, *ksk_for_cds);
818 if (ret == KNOT_EOK) {
819 ret = rrset_add_zone_ds(&add_r->cds, *ksk_for_cds, dnssec_ctx->policy->cds_dt);
820 }
821 }
822
823 if (dnssec_ctx->policy->cds_cdnskey_publish == CDS_CDNSKEY_EMPTY && ret == KNOT_EOK) {
824 const uint8_t cdnskey_empty[5] = { 0, 0, 3, 0, 0 };
825 const uint8_t cds_empty[5] = { 0, 0, 0, 0, 0 };
826 ret = knot_rrset_add_rdata(&add_r->cdnskey, cdnskey_empty, sizeof(cdnskey_empty), NULL);
827 if (ret == KNOT_EOK) {
828 ret = knot_rrset_add_rdata(&add_r->cds, cds_empty, sizeof(cds_empty), NULL);
829 }
830 }
831
832 keyptr_dynarray_free(&kcdnskeys);
833 return ret;
834 }
835
knot_zone_sign_update_dnskeys(zone_update_t * update,zone_keyset_t * zone_keys,kdnssec_ctx_t * dnssec_ctx,knot_time_t * next_resign)836 int knot_zone_sign_update_dnskeys(zone_update_t *update,
837 zone_keyset_t *zone_keys,
838 kdnssec_ctx_t *dnssec_ctx,
839 knot_time_t *next_resign)
840 {
841 if (update == NULL || zone_keys == NULL || dnssec_ctx == NULL) {
842 return KNOT_EINVAL;
843 }
844
845 if (dnssec_ctx->policy->unsafe & UNSAFE_DNSKEY) {
846 return KNOT_EOK;
847 }
848
849 const zone_node_t *apex = update->new_cont->apex;
850 knot_rrset_t dnskeys = node_rrset(apex, KNOT_RRTYPE_DNSKEY);
851 knot_rrset_t cdnskeys = node_rrset(apex, KNOT_RRTYPE_CDNSKEY);
852 knot_rrset_t cdss = node_rrset(apex, KNOT_RRTYPE_CDS);
853 key_records_t add_r;
854 memset(&add_r, 0, sizeof(add_r));
855 knot_rrset_t soa = node_rrset(apex, KNOT_RRTYPE_SOA);
856 if (knot_rrset_empty(&soa)) {
857 return KNOT_EINVAL;
858 }
859
860 changeset_t ch;
861 int ret = changeset_init(&ch, apex->owner);
862 if (ret != KNOT_EOK) {
863 return ret;
864 }
865
866 #define CHECK_RET if (ret != KNOT_EOK) goto cleanup
867
868 // remove all. This will cancel out with additions later
869 ret = changeset_add_removal(&ch, &dnskeys, 0);
870 CHECK_RET;
871 ret = changeset_add_removal(&ch, &cdnskeys, 0);
872 CHECK_RET;
873 ret = changeset_add_removal(&ch, &cdss, 0);
874 CHECK_RET;
875
876 // add DNSKEYs, CDNSKEYs and CDSs
877 key_records_init(dnssec_ctx, &add_r);
878
879 if (dnssec_ctx->policy->offline_ksk) {
880 ret = kasp_db_load_offline_records(dnssec_ctx->kasp_db, apex->owner, dnssec_ctx->now, next_resign, &add_r);
881 if (ret == KNOT_EOK) {
882 log_zone_info(dnssec_ctx->zone->dname,
883 "DNSSEC, using offline records, DNSKEYs %hu, CDNSKEYs %hu, CDs %hu, RRSIGs %hu",
884 add_r.dnskey.rrs.count, add_r.cdnskey.rrs.count, add_r.cds.rrs.count, add_r.rrsig.rrs.count);
885 } else {
886 log_zone_warning(dnssec_ctx->zone->dname, "DNSSEC, failed to load offline records (%s)",
887 knot_strerror(ret));
888 }
889 } else {
890 ret = knot_zone_sign_add_dnskeys(zone_keys, dnssec_ctx, &add_r);
891 }
892 CHECK_RET;
893
894 if (!knot_rrset_empty(&add_r.cdnskey)) {
895 ret = changeset_add_addition(&ch, &add_r.cdnskey, CHANGESET_CHECK);
896 CHECK_RET;
897 }
898
899 if (!knot_rrset_empty(&add_r.cds)) {
900 ret = changeset_add_addition(&ch, &add_r.cds, CHANGESET_CHECK);
901 if (node_rrtype_exists(ch.add->apex, KNOT_RRTYPE_CDS)) {
902 // there is indeed a change to CDS
903 update->zone->timers.next_ds_push = time(NULL);
904 zone_events_schedule_now(update->zone, ZONE_EVENT_DS_PUSH);
905 }
906 CHECK_RET;
907 }
908
909 if (!knot_rrset_empty(&add_r.dnskey)) {
910 ret = changeset_add_addition(&ch, &add_r.dnskey, CHANGESET_CHECK);
911 CHECK_RET;
912 }
913
914 if (!knot_rrset_empty(&add_r.rrsig)) {
915 dnssec_ctx->offline_rrsig = knot_rrset_copy(&add_r.rrsig, NULL);
916 }
917
918 ret = zone_update_apply_changeset(update, &ch);
919
920 #undef CHECK_RET
921
922 cleanup:
923 key_records_clear(&add_r);
924 changeset_clear(&ch);
925 return ret;
926 }
927
knot_zone_sign_use_key(const zone_key_t * key,const knot_rrset_t * covered)928 bool knot_zone_sign_use_key(const zone_key_t *key, const knot_rrset_t *covered)
929 {
930 if (key == NULL || covered == NULL) {
931 return false;
932 }
933
934 bool active_ksk = ((key->is_active || key->is_ksk_active_plus) && key->is_ksk);
935 bool active_zsk = ((key->is_active || key->is_zsk_active_plus) && key->is_zsk);;
936
937 // this may be a problem with offline KSK
938 bool cds_sign_by_ksk = true;
939
940 assert(key->is_zsk || key->is_ksk);
941 bool is_apex = knot_dname_is_equal(covered->owner,
942 dnssec_key_get_dname(key->key));
943 if (!is_apex) {
944 return active_zsk;
945 }
946
947 switch (covered->type) {
948 case KNOT_RRTYPE_DNSKEY:
949 return active_ksk;
950 case KNOT_RRTYPE_CDS:
951 case KNOT_RRTYPE_CDNSKEY:
952 return (cds_sign_by_ksk ? active_ksk : active_zsk);
953 default:
954 return active_zsk;
955 }
956 }
957
knot_zone_sign_soa_expired(const zone_contents_t * zone,const zone_keyset_t * zone_keys,const kdnssec_ctx_t * dnssec_ctx)958 bool knot_zone_sign_soa_expired(const zone_contents_t *zone,
959 const zone_keyset_t *zone_keys,
960 const kdnssec_ctx_t *dnssec_ctx)
961 {
962 if (zone == NULL || zone_keys == NULL || dnssec_ctx == NULL) {
963 return false;
964 }
965
966 knot_rrset_t soa = node_rrset(zone->apex, KNOT_RRTYPE_SOA);
967 assert(!knot_rrset_empty(&soa));
968 knot_rrset_t rrsigs = node_rrset(zone->apex, KNOT_RRTYPE_RRSIG);
969 zone_sign_ctx_t *sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx);
970 if (sign_ctx == NULL) {
971 return false;
972 }
973 bool exist = all_signatures_exist(&soa, &rrsigs, sign_ctx);
974 zone_sign_ctx_free(sign_ctx);
975 return !exist;
976 }
977
sign_in_changeset(zone_node_t * node,uint16_t rrtype,knot_rrset_t * rrsigs,zone_sign_ctx_t * sign_ctx,int ret_prev,bool skip_crypto,zone_update_t * up)978 static int sign_in_changeset(zone_node_t *node, uint16_t rrtype, knot_rrset_t *rrsigs,
979 zone_sign_ctx_t *sign_ctx, int ret_prev,
980 bool skip_crypto, zone_update_t *up)
981 {
982 if (ret_prev != KNOT_EOK) {
983 return ret_prev;
984 }
985 knot_rrset_t rr = node_rrset(node, rrtype);
986 if (knot_rrset_empty(&rr)) {
987 return KNOT_EOK;
988 }
989 return add_missing_rrsigs(&rr, rrsigs, sign_ctx, skip_crypto, NULL, up, NULL);
990 }
991
knot_zone_sign_nsecs_in_changeset(const zone_keyset_t * zone_keys,const kdnssec_ctx_t * dnssec_ctx,zone_update_t * update)992 int knot_zone_sign_nsecs_in_changeset(const zone_keyset_t *zone_keys,
993 const kdnssec_ctx_t *dnssec_ctx,
994 zone_update_t *update)
995 {
996 if (zone_keys == NULL || dnssec_ctx == NULL || update == NULL) {
997 return KNOT_EINVAL;
998 }
999
1000 zone_sign_ctx_t *sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx);
1001 if (sign_ctx == NULL) {
1002 return KNOT_ENOMEM;
1003 }
1004
1005 zone_tree_it_t it = { 0 };
1006 int ret = zone_tree_it_double_begin(update->a_ctx->node_ptrs, update->a_ctx->nsec3_ptrs, &it);
1007
1008 while (!zone_tree_it_finished(&it) && ret == KNOT_EOK) {
1009 zone_node_t *n = zone_tree_it_val(&it);
1010 bool skip_crypto = (n->flags & NODE_FLAGS_RRSIGS_VALID) && !dnssec_ctx->keytag_conflict;
1011
1012 knot_rrset_t rrsigs = node_rrset(n, KNOT_RRTYPE_RRSIG);
1013 ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC, &rrsigs, sign_ctx, ret, skip_crypto, update);
1014 ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC3, &rrsigs, sign_ctx, ret, skip_crypto, update);
1015 ret = sign_in_changeset(n, KNOT_RRTYPE_NSEC3PARAM, &rrsigs, sign_ctx, ret, skip_crypto, update);
1016
1017 if (ret == KNOT_EOK) {
1018 n->flags |= NODE_FLAGS_RRSIGS_VALID; // non-NSEC RRSIGs had been validated in knot_dnssec_sign_update()
1019 }
1020
1021 zone_tree_it_next(&it);
1022 }
1023 zone_tree_it_free(&it);
1024 zone_sign_ctx_free(sign_ctx);
1025
1026 return ret;
1027 }
1028
knot_zone_sign_rr_should_be_signed(const zone_node_t * node,const knot_rrset_t * rrset)1029 bool knot_zone_sign_rr_should_be_signed(const zone_node_t *node,
1030 const knot_rrset_t *rrset)
1031 {
1032 if (node == NULL || knot_rrset_empty(rrset)) {
1033 return false;
1034 }
1035
1036 if (rrset->type == KNOT_RRTYPE_RRSIG || (node->flags & NODE_FLAGS_NONAUTH)) {
1037 return false;
1038 }
1039
1040 // At delegation points we only want to sign NSECs and DSs
1041 if (node->flags & NODE_FLAGS_DELEG) {
1042 if (!(rrset->type == KNOT_RRTYPE_NSEC ||
1043 rrset->type == KNOT_RRTYPE_DS)) {
1044 return false;
1045 }
1046 }
1047
1048 return true;
1049 }
1050
knot_zone_sign_update(zone_update_t * update,zone_keyset_t * zone_keys,const kdnssec_ctx_t * dnssec_ctx,knot_time_t * expire_at)1051 int knot_zone_sign_update(zone_update_t *update,
1052 zone_keyset_t *zone_keys,
1053 const kdnssec_ctx_t *dnssec_ctx,
1054 knot_time_t *expire_at)
1055 {
1056 if (update == NULL || dnssec_ctx == NULL || expire_at == NULL ||
1057 dnssec_ctx->policy->signing_threads < 1 ||
1058 (zone_keys == NULL && !dnssec_ctx->validation_mode)) {
1059 return KNOT_EINVAL;
1060 }
1061
1062 int ret = KNOT_EOK;
1063
1064 /* Check if the UPDATE changed DNSKEYs or NSEC3PARAM.
1065 * If so, we have to sign the whole zone. */
1066 const bool full_sign = apex_dnssec_changed(update);
1067 if (full_sign) {
1068 ret = knot_zone_sign(update, zone_keys, dnssec_ctx, expire_at);
1069 } else {
1070 ret = zone_tree_sign(update->a_ctx->node_ptrs, dnssec_ctx->policy->signing_threads,
1071 zone_keys, dnssec_ctx, update, expire_at);
1072 if (ret == KNOT_EOK) {
1073 ret = zone_tree_apply(update->a_ctx->node_ptrs, set_signed, NULL);
1074 }
1075 if (ret == KNOT_EOK && dnssec_ctx->validation_mode) {
1076 ret = zone_tree_sign(update->a_ctx->nsec3_ptrs, dnssec_ctx->policy->signing_threads,
1077 zone_keys, dnssec_ctx, update, expire_at);
1078 }
1079 if (ret == KNOT_EOK && dnssec_ctx->validation_mode) {
1080 ret = zone_tree_apply(update->a_ctx->nsec3_ptrs, set_signed, NULL);
1081 }
1082 }
1083
1084 return ret;
1085 }
1086
knot_zone_sign_apex_rr(zone_update_t * update,uint16_t rrtype,const zone_keyset_t * zone_keys,const kdnssec_ctx_t * dnssec_ctx)1087 int knot_zone_sign_apex_rr(zone_update_t *update, uint16_t rrtype,
1088 const zone_keyset_t *zone_keys,
1089 const kdnssec_ctx_t *dnssec_ctx)
1090 {
1091 knot_rrset_t rr = node_rrset(update->new_cont->apex, rrtype);
1092 knot_rrset_t rrsig = node_rrset(update->new_cont->apex, KNOT_RRTYPE_RRSIG);
1093 changeset_t ch;
1094 int ret = changeset_init(&ch, update->zone->name);
1095 if (ret == KNOT_EOK) {
1096 zone_sign_ctx_t *sign_ctx = zone_sign_ctx(zone_keys, dnssec_ctx);
1097 if (sign_ctx == NULL) {
1098 changeset_clear(&ch);
1099 return KNOT_ENOMEM;
1100 }
1101 ret = force_resign_rrset(&rr, &rrsig, sign_ctx, &ch);
1102 if (ret == KNOT_EOK) {
1103 ret = zone_update_apply_changeset(update, &ch);
1104 }
1105 zone_sign_ctx_free(sign_ctx);
1106 }
1107 changeset_clear(&ch);
1108 return ret;
1109 }
1110