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