dnssec_sign.c revision 246827
1238104Sdes#include <ldns/config.h>
2238104Sdes
3238104Sdes#include <ldns/ldns.h>
4238104Sdes
5238104Sdes#include <ldns/dnssec.h>
6238104Sdes#include <ldns/dnssec_sign.h>
7238104Sdes
8238104Sdes#include <strings.h>
9238104Sdes#include <time.h>
10238104Sdes
11238104Sdes#ifdef HAVE_SSL
12238104Sdes/* this entire file is rather useless when you don't have
13238104Sdes * crypto...
14238104Sdes */
15238104Sdes#include <openssl/ssl.h>
16238104Sdes#include <openssl/evp.h>
17238104Sdes#include <openssl/rand.h>
18238104Sdes#include <openssl/err.h>
19238104Sdes#include <openssl/md5.h>
20238104Sdes#endif /* HAVE_SSL */
21238104Sdes
22238104Sdesldns_rr *
23238104Sdesldns_create_empty_rrsig(ldns_rr_list *rrset,
24238104Sdes                        ldns_key *current_key)
25238104Sdes{
26238104Sdes	uint32_t orig_ttl;
27238104Sdes	ldns_rr_class orig_class;
28238104Sdes	time_t now;
29238104Sdes	ldns_rr *current_sig;
30238104Sdes	uint8_t label_count;
31238104Sdes	ldns_rdf *signame;
32238104Sdes
33238104Sdes	label_count = ldns_dname_label_count(ldns_rr_owner(ldns_rr_list_rr(rrset,
34238104Sdes	                                                   0)));
35238104Sdes        /* RFC4035 2.2: not counting the leftmost label if it is a wildcard */
36238104Sdes        if(ldns_dname_is_wildcard(ldns_rr_owner(ldns_rr_list_rr(rrset, 0))))
37238104Sdes                label_count --;
38238104Sdes
39238104Sdes	current_sig = ldns_rr_new_frm_type(LDNS_RR_TYPE_RRSIG);
40238104Sdes
41238104Sdes	/* set the type on the new signature */
42238104Sdes	orig_ttl = ldns_rr_ttl(ldns_rr_list_rr(rrset, 0));
43238104Sdes	orig_class = ldns_rr_get_class(ldns_rr_list_rr(rrset, 0));
44238104Sdes
45238104Sdes	ldns_rr_set_ttl(current_sig, orig_ttl);
46238104Sdes	ldns_rr_set_class(current_sig, orig_class);
47238104Sdes	ldns_rr_set_owner(current_sig,
48238104Sdes			  ldns_rdf_clone(
49238104Sdes			       ldns_rr_owner(
50238104Sdes				    ldns_rr_list_rr(rrset,
51238104Sdes						    0))));
52238104Sdes
53238104Sdes	/* fill in what we know of the signature */
54238104Sdes
55238104Sdes	/* set the orig_ttl */
56238104Sdes	(void)ldns_rr_rrsig_set_origttl(
57238104Sdes		   current_sig,
58238104Sdes		   ldns_native2rdf_int32(LDNS_RDF_TYPE_INT32,
59238104Sdes					 orig_ttl));
60238104Sdes	/* the signers name */
61238104Sdes	signame = ldns_rdf_clone(ldns_key_pubkey_owner(current_key));
62238104Sdes	ldns_dname2canonical(signame);
63238104Sdes	(void)ldns_rr_rrsig_set_signame(
64238104Sdes			current_sig,
65238104Sdes			signame);
66238104Sdes	/* label count - get it from the first rr in the rr_list */
67238104Sdes	(void)ldns_rr_rrsig_set_labels(
68238104Sdes			current_sig,
69238104Sdes			ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
70238104Sdes			                     label_count));
71238104Sdes	/* inception, expiration */
72238104Sdes	now = time(NULL);
73238104Sdes	if (ldns_key_inception(current_key) != 0) {
74238104Sdes		(void)ldns_rr_rrsig_set_inception(
75238104Sdes				current_sig,
76238104Sdes				ldns_native2rdf_int32(
77238104Sdes				    LDNS_RDF_TYPE_TIME,
78238104Sdes				    ldns_key_inception(current_key)));
79238104Sdes	} else {
80238104Sdes		(void)ldns_rr_rrsig_set_inception(
81238104Sdes				current_sig,
82238104Sdes				ldns_native2rdf_int32(LDNS_RDF_TYPE_TIME, now));
83238104Sdes	}
84238104Sdes	if (ldns_key_expiration(current_key) != 0) {
85238104Sdes		(void)ldns_rr_rrsig_set_expiration(
86238104Sdes				current_sig,
87238104Sdes				ldns_native2rdf_int32(
88238104Sdes				    LDNS_RDF_TYPE_TIME,
89238104Sdes				    ldns_key_expiration(current_key)));
90238104Sdes	} else {
91238104Sdes		(void)ldns_rr_rrsig_set_expiration(
92238104Sdes			     current_sig,
93238104Sdes				ldns_native2rdf_int32(
94238104Sdes				    LDNS_RDF_TYPE_TIME,
95238104Sdes				    now + LDNS_DEFAULT_EXP_TIME));
96238104Sdes	}
97238104Sdes
98238104Sdes	(void)ldns_rr_rrsig_set_keytag(
99238104Sdes		   current_sig,
100238104Sdes		   ldns_native2rdf_int16(LDNS_RDF_TYPE_INT16,
101238104Sdes		                         ldns_key_keytag(current_key)));
102238104Sdes
103238104Sdes	(void)ldns_rr_rrsig_set_algorithm(
104238104Sdes			current_sig,
105238104Sdes			ldns_native2rdf_int8(
106238104Sdes			    LDNS_RDF_TYPE_ALG,
107238104Sdes			    ldns_key_algorithm(current_key)));
108238104Sdes
109238104Sdes	(void)ldns_rr_rrsig_set_typecovered(
110238104Sdes			current_sig,
111238104Sdes			ldns_native2rdf_int16(
112238104Sdes			    LDNS_RDF_TYPE_TYPE,
113238104Sdes			    ldns_rr_get_type(ldns_rr_list_rr(rrset,
114238104Sdes			                                     0))));
115238104Sdes	return current_sig;
116238104Sdes}
117238104Sdes
118238104Sdes#ifdef HAVE_SSL
119238104Sdesldns_rdf *
120238104Sdesldns_sign_public_buffer(ldns_buffer *sign_buf, ldns_key *current_key)
121238104Sdes{
122238104Sdes	ldns_rdf *b64rdf = NULL;
123238104Sdes
124238104Sdes	switch(ldns_key_algorithm(current_key)) {
125238104Sdes	case LDNS_SIGN_DSA:
126238104Sdes	case LDNS_SIGN_DSA_NSEC3:
127238104Sdes		b64rdf = ldns_sign_public_evp(
128238104Sdes				   sign_buf,
129238104Sdes				   ldns_key_evp_key(current_key),
130238104Sdes				   EVP_dss1());
131238104Sdes		break;
132238104Sdes	case LDNS_SIGN_RSASHA1:
133238104Sdes	case LDNS_SIGN_RSASHA1_NSEC3:
134238104Sdes		b64rdf = ldns_sign_public_evp(
135238104Sdes				   sign_buf,
136238104Sdes				   ldns_key_evp_key(current_key),
137238104Sdes				   EVP_sha1());
138238104Sdes		break;
139238104Sdes#ifdef USE_SHA2
140238104Sdes	case LDNS_SIGN_RSASHA256:
141238104Sdes		b64rdf = ldns_sign_public_evp(
142238104Sdes				   sign_buf,
143238104Sdes				   ldns_key_evp_key(current_key),
144238104Sdes				   EVP_sha256());
145238104Sdes		break;
146238104Sdes	case LDNS_SIGN_RSASHA512:
147238104Sdes		b64rdf = ldns_sign_public_evp(
148238104Sdes				   sign_buf,
149238104Sdes				   ldns_key_evp_key(current_key),
150238104Sdes				   EVP_sha512());
151238104Sdes		break;
152238104Sdes#endif /* USE_SHA2 */
153238104Sdes#ifdef USE_GOST
154238104Sdes	case LDNS_SIGN_ECC_GOST:
155238104Sdes		b64rdf = ldns_sign_public_evp(
156238104Sdes				   sign_buf,
157238104Sdes				   ldns_key_evp_key(current_key),
158238104Sdes				   EVP_get_digestbyname("md_gost94"));
159238104Sdes		break;
160238104Sdes#endif /* USE_GOST */
161238104Sdes#ifdef USE_ECDSA
162238104Sdes        case LDNS_SIGN_ECDSAP256SHA256:
163238104Sdes       		b64rdf = ldns_sign_public_evp(
164238104Sdes				   sign_buf,
165238104Sdes				   ldns_key_evp_key(current_key),
166238104Sdes				   EVP_sha256());
167238104Sdes                break;
168238104Sdes        case LDNS_SIGN_ECDSAP384SHA384:
169238104Sdes       		b64rdf = ldns_sign_public_evp(
170238104Sdes				   sign_buf,
171238104Sdes				   ldns_key_evp_key(current_key),
172238104Sdes				   EVP_sha384());
173238104Sdes                break;
174238104Sdes#endif
175238104Sdes	case LDNS_SIGN_RSAMD5:
176238104Sdes		b64rdf = ldns_sign_public_evp(
177238104Sdes				   sign_buf,
178238104Sdes				   ldns_key_evp_key(current_key),
179238104Sdes				   EVP_md5());
180238104Sdes		break;
181238104Sdes	default:
182238104Sdes		/* do _you_ know this alg? */
183238104Sdes		printf("unknown algorithm, ");
184238104Sdes		printf("is the one used available on this system?\n");
185238104Sdes		break;
186238104Sdes	}
187238104Sdes
188238104Sdes	return b64rdf;
189238104Sdes}
190238104Sdes
191238104Sdes/**
192238104Sdes * use this function to sign with a public/private key alg
193238104Sdes * return the created signatures
194238104Sdes */
195238104Sdesldns_rr_list *
196238104Sdesldns_sign_public(ldns_rr_list *rrset, ldns_key_list *keys)
197238104Sdes{
198238104Sdes	ldns_rr_list *signatures;
199238104Sdes	ldns_rr_list *rrset_clone;
200238104Sdes	ldns_rr *current_sig;
201238104Sdes	ldns_rdf *b64rdf;
202238104Sdes	ldns_key *current_key;
203238104Sdes	size_t key_count;
204238104Sdes	uint16_t i;
205238104Sdes	ldns_buffer *sign_buf;
206238104Sdes	ldns_rdf *new_owner;
207238104Sdes
208238104Sdes	if (!rrset || ldns_rr_list_rr_count(rrset) < 1 || !keys) {
209238104Sdes		return NULL;
210238104Sdes	}
211238104Sdes
212238104Sdes	new_owner = NULL;
213238104Sdes
214238104Sdes	signatures = ldns_rr_list_new();
215238104Sdes
216238104Sdes	/* prepare a signature and add all the know data
217238104Sdes	 * prepare the rrset. Sign this together.  */
218238104Sdes	rrset_clone = ldns_rr_list_clone(rrset);
219238104Sdes	if (!rrset_clone) {
220238104Sdes		return NULL;
221238104Sdes	}
222238104Sdes
223238104Sdes	/* make it canonical */
224238104Sdes	for(i = 0; i < ldns_rr_list_rr_count(rrset_clone); i++) {
225238104Sdes		ldns_rr_set_ttl(ldns_rr_list_rr(rrset_clone, i),
226238104Sdes			ldns_rr_ttl(ldns_rr_list_rr(rrset, 0)));
227238104Sdes		ldns_rr2canonical(ldns_rr_list_rr(rrset_clone, i));
228238104Sdes	}
229238104Sdes	/* sort */
230238104Sdes	ldns_rr_list_sort(rrset_clone);
231238104Sdes
232238104Sdes	for (key_count = 0;
233238104Sdes		key_count < ldns_key_list_key_count(keys);
234238104Sdes		key_count++) {
235238104Sdes		if (!ldns_key_use(ldns_key_list_key(keys, key_count))) {
236238104Sdes			continue;
237238104Sdes		}
238238104Sdes		sign_buf = ldns_buffer_new(LDNS_MAX_PACKETLEN);
239238104Sdes		if (!sign_buf) {
240238104Sdes			ldns_rr_list_free(rrset_clone);
241238104Sdes			ldns_rr_list_free(signatures);
242238104Sdes			ldns_rdf_free(new_owner);
243238104Sdes			return NULL;
244238104Sdes		}
245238104Sdes		b64rdf = NULL;
246238104Sdes
247238104Sdes		current_key = ldns_key_list_key(keys, key_count);
248238104Sdes		/* sign all RRs with keys that have ZSKbit, !SEPbit.
249238104Sdes		   sign DNSKEY RRs with keys that have ZSKbit&SEPbit */
250238104Sdes		if (ldns_key_flags(current_key) & LDNS_KEY_ZONE_KEY) {
251238104Sdes			current_sig = ldns_create_empty_rrsig(rrset_clone,
252238104Sdes			                                      current_key);
253238104Sdes
254238104Sdes			/* right now, we have: a key, a semi-sig and an rrset. For
255238104Sdes			 * which we can create the sig and base64 encode that and
256238104Sdes			 * add that to the signature */
257238104Sdes
258238104Sdes			if (ldns_rrsig2buffer_wire(sign_buf, current_sig)
259238104Sdes			    != LDNS_STATUS_OK) {
260238104Sdes				ldns_buffer_free(sign_buf);
261238104Sdes				/* ERROR */
262238104Sdes				ldns_rr_list_deep_free(rrset_clone);
263238104Sdes				return NULL;
264238104Sdes			}
265238104Sdes
266238104Sdes			/* add the rrset in sign_buf */
267238104Sdes			if (ldns_rr_list2buffer_wire(sign_buf, rrset_clone)
268238104Sdes			    != LDNS_STATUS_OK) {
269238104Sdes				ldns_buffer_free(sign_buf);
270238104Sdes				ldns_rr_list_deep_free(rrset_clone);
271238104Sdes				return NULL;
272238104Sdes			}
273238104Sdes
274238104Sdes			b64rdf = ldns_sign_public_buffer(sign_buf, current_key);
275238104Sdes
276238104Sdes			if (!b64rdf) {
277238104Sdes				/* signing went wrong */
278238104Sdes				ldns_rr_list_deep_free(rrset_clone);
279238104Sdes				return NULL;
280238104Sdes			}
281238104Sdes
282238104Sdes			ldns_rr_rrsig_set_sig(current_sig, b64rdf);
283238104Sdes
284238104Sdes			/* push the signature to the signatures list */
285238104Sdes			ldns_rr_list_push_rr(signatures, current_sig);
286238104Sdes		}
287238104Sdes		ldns_buffer_free(sign_buf); /* restart for the next key */
288238104Sdes	}
289238104Sdes	ldns_rr_list_deep_free(rrset_clone);
290238104Sdes
291238104Sdes	return signatures;
292238104Sdes}
293238104Sdes
294238104Sdes/**
295238104Sdes * Sign data with DSA
296238104Sdes *
297238104Sdes * \param[in] to_sign The ldns_buffer containing raw data that is
298238104Sdes *                    to be signed
299238104Sdes * \param[in] key The DSA key structure to sign with
300238104Sdes * \return ldns_rdf for the RRSIG ldns_rr
301238104Sdes */
302238104Sdesldns_rdf *
303238104Sdesldns_sign_public_dsa(ldns_buffer *to_sign, DSA *key)
304238104Sdes{
305238104Sdes	unsigned char *sha1_hash;
306238104Sdes	ldns_rdf *sigdata_rdf;
307238104Sdes	ldns_buffer *b64sig;
308238104Sdes
309238104Sdes	DSA_SIG *sig;
310238104Sdes	uint8_t *data;
311238104Sdes	size_t pad;
312238104Sdes
313238104Sdes	b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
314238104Sdes	if (!b64sig) {
315238104Sdes		return NULL;
316238104Sdes	}
317238104Sdes
318238104Sdes	sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign),
319238104Sdes				  ldns_buffer_position(to_sign), NULL);
320238104Sdes	if (!sha1_hash) {
321238104Sdes		ldns_buffer_free(b64sig);
322238104Sdes		return NULL;
323238104Sdes	}
324238104Sdes
325238104Sdes	sig = DSA_do_sign(sha1_hash, SHA_DIGEST_LENGTH, key);
326238104Sdes        if(!sig) {
327238104Sdes		ldns_buffer_free(b64sig);
328238104Sdes		return NULL;
329238104Sdes        }
330238104Sdes
331238104Sdes	data = LDNS_XMALLOC(uint8_t, 1 + 2 * SHA_DIGEST_LENGTH);
332238104Sdes        if(!data) {
333238104Sdes		ldns_buffer_free(b64sig);
334238104Sdes                DSA_SIG_free(sig);
335238104Sdes		return NULL;
336238104Sdes        }
337238104Sdes
338238104Sdes	data[0] = 1;
339238104Sdes	pad = 20 - (size_t) BN_num_bytes(sig->r);
340238104Sdes	if (pad > 0) {
341238104Sdes		memset(data + 1, 0, pad);
342238104Sdes	}
343238104Sdes	BN_bn2bin(sig->r, (unsigned char *) (data + 1) + pad);
344238104Sdes
345238104Sdes	pad = 20 - (size_t) BN_num_bytes(sig->s);
346238104Sdes	if (pad > 0) {
347238104Sdes		memset(data + 1 + SHA_DIGEST_LENGTH, 0, pad);
348238104Sdes	}
349238104Sdes	BN_bn2bin(sig->s, (unsigned char *) (data + 1 + SHA_DIGEST_LENGTH + pad));
350238104Sdes
351238104Sdes	sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64,
352238104Sdes								 1 + 2 * SHA_DIGEST_LENGTH,
353238104Sdes								 data);
354238104Sdes
355238104Sdes	ldns_buffer_free(b64sig);
356238104Sdes	LDNS_FREE(data);
357238104Sdes        DSA_SIG_free(sig);
358238104Sdes
359238104Sdes	return sigdata_rdf;
360238104Sdes}
361238104Sdes
362238104Sdes#ifdef USE_ECDSA
363238104Sdes#ifndef S_SPLINT_S
364238104Sdesstatic int
365238104Sdesldns_pkey_is_ecdsa(EVP_PKEY* pkey)
366238104Sdes{
367238104Sdes        EC_KEY* ec;
368238104Sdes        const EC_GROUP* g;
369238104Sdes        if(EVP_PKEY_type(pkey->type) != EVP_PKEY_EC)
370238104Sdes                return 0;
371238104Sdes        ec = EVP_PKEY_get1_EC_KEY(pkey);
372238104Sdes        g = EC_KEY_get0_group(ec);
373238104Sdes        if(!g) {
374238104Sdes                EC_KEY_free(ec);
375238104Sdes                return 0;
376238104Sdes        }
377238104Sdes        if(EC_GROUP_get_curve_name(g) == NID_secp224r1 ||
378238104Sdes                EC_GROUP_get_curve_name(g) == NID_X9_62_prime256v1 ||
379238104Sdes                EC_GROUP_get_curve_name(g) == NID_secp384r1) {
380238104Sdes                EC_KEY_free(ec);
381238104Sdes                return 1;
382238104Sdes        }
383238104Sdes        /* downref the eckey, the original is still inside the pkey */
384238104Sdes        EC_KEY_free(ec);
385238104Sdes        return 0;
386238104Sdes}
387238104Sdes#endif /* splint */
388238104Sdes#endif /* USE_ECDSA */
389238104Sdes
390238104Sdesldns_rdf *
391238104Sdesldns_sign_public_evp(ldns_buffer *to_sign,
392238104Sdes				 EVP_PKEY *key,
393238104Sdes				 const EVP_MD *digest_type)
394238104Sdes{
395238104Sdes	unsigned int siglen;
396238104Sdes	ldns_rdf *sigdata_rdf;
397238104Sdes	ldns_buffer *b64sig;
398238104Sdes	EVP_MD_CTX ctx;
399238104Sdes	const EVP_MD *md_type;
400238104Sdes	int r;
401238104Sdes
402238104Sdes	siglen = 0;
403238104Sdes	b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
404238104Sdes	if (!b64sig) {
405238104Sdes		return NULL;
406238104Sdes	}
407238104Sdes
408238104Sdes	/* initializes a signing context */
409238104Sdes	md_type = digest_type;
410238104Sdes	if(!md_type) {
411238104Sdes		/* unknown message difest */
412238104Sdes		ldns_buffer_free(b64sig);
413238104Sdes		return NULL;
414238104Sdes	}
415238104Sdes
416238104Sdes	EVP_MD_CTX_init(&ctx);
417238104Sdes	r = EVP_SignInit(&ctx, md_type);
418238104Sdes	if(r == 1) {
419238104Sdes		r = EVP_SignUpdate(&ctx, (unsigned char*)
420238104Sdes					    ldns_buffer_begin(to_sign),
421238104Sdes					    ldns_buffer_position(to_sign));
422238104Sdes	} else {
423238104Sdes		ldns_buffer_free(b64sig);
424238104Sdes		return NULL;
425238104Sdes	}
426238104Sdes	if(r == 1) {
427238104Sdes		r = EVP_SignFinal(&ctx, (unsigned char*)
428238104Sdes					   ldns_buffer_begin(b64sig), &siglen, key);
429238104Sdes	} else {
430238104Sdes		ldns_buffer_free(b64sig);
431238104Sdes		return NULL;
432238104Sdes	}
433238104Sdes	if(r != 1) {
434238104Sdes		ldns_buffer_free(b64sig);
435238104Sdes		return NULL;
436238104Sdes	}
437238104Sdes
438238104Sdes	/* unfortunately, OpenSSL output is differenct from DNS DSA format */
439238104Sdes#ifndef S_SPLINT_S
440238104Sdes	if (EVP_PKEY_type(key->type) == EVP_PKEY_DSA) {
441238104Sdes		sigdata_rdf = ldns_convert_dsa_rrsig_asn12rdf(b64sig, siglen);
442238104Sdes#ifdef USE_ECDSA
443238104Sdes        } else if(EVP_PKEY_type(key->type) == EVP_PKEY_EC &&
444238104Sdes                ldns_pkey_is_ecdsa(key)) {
445238104Sdes                sigdata_rdf = ldns_convert_ecdsa_rrsig_asn12rdf(b64sig, siglen);
446238104Sdes#endif
447238104Sdes	} else {
448238104Sdes		/* ok output for other types is the same */
449238104Sdes		sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
450238104Sdes									 ldns_buffer_begin(b64sig));
451238104Sdes	}
452238104Sdes#endif /* splint */
453238104Sdes	ldns_buffer_free(b64sig);
454238104Sdes	EVP_MD_CTX_cleanup(&ctx);
455238104Sdes	return sigdata_rdf;
456238104Sdes}
457238104Sdes
458238104Sdesldns_rdf *
459238104Sdesldns_sign_public_rsasha1(ldns_buffer *to_sign, RSA *key)
460238104Sdes{
461238104Sdes	unsigned char *sha1_hash;
462238104Sdes	unsigned int siglen;
463238104Sdes	ldns_rdf *sigdata_rdf;
464238104Sdes	ldns_buffer *b64sig;
465238104Sdes	int result;
466238104Sdes
467238104Sdes	siglen = 0;
468238104Sdes	b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
469238104Sdes	if (!b64sig) {
470238104Sdes		return NULL;
471238104Sdes	}
472238104Sdes
473238104Sdes	sha1_hash = SHA1((unsigned char*)ldns_buffer_begin(to_sign),
474238104Sdes				  ldns_buffer_position(to_sign), NULL);
475238104Sdes	if (!sha1_hash) {
476238104Sdes		ldns_buffer_free(b64sig);
477238104Sdes		return NULL;
478238104Sdes	}
479238104Sdes
480238104Sdes	result = RSA_sign(NID_sha1, sha1_hash, SHA_DIGEST_LENGTH,
481238104Sdes				   (unsigned char*)ldns_buffer_begin(b64sig),
482238104Sdes				   &siglen, key);
483238104Sdes	if (result != 1) {
484238104Sdes		return NULL;
485238104Sdes	}
486238104Sdes
487238104Sdes	if (result != 1) {
488238104Sdes		return NULL;
489238104Sdes	}
490238104Sdes
491238104Sdes	sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
492238104Sdes								 ldns_buffer_begin(b64sig));
493238104Sdes	ldns_buffer_free(b64sig); /* can't free this buffer ?? */
494238104Sdes	return sigdata_rdf;
495238104Sdes}
496238104Sdes
497238104Sdesldns_rdf *
498238104Sdesldns_sign_public_rsamd5(ldns_buffer *to_sign, RSA *key)
499238104Sdes{
500238104Sdes	unsigned char *md5_hash;
501238104Sdes	unsigned int siglen;
502238104Sdes	ldns_rdf *sigdata_rdf;
503238104Sdes	ldns_buffer *b64sig;
504238104Sdes
505238104Sdes	b64sig = ldns_buffer_new(LDNS_MAX_PACKETLEN);
506238104Sdes	if (!b64sig) {
507238104Sdes		return NULL;
508238104Sdes	}
509238104Sdes
510238104Sdes	md5_hash = MD5((unsigned char*)ldns_buffer_begin(to_sign),
511238104Sdes				ldns_buffer_position(to_sign), NULL);
512238104Sdes	if (!md5_hash) {
513238104Sdes		ldns_buffer_free(b64sig);
514238104Sdes		return NULL;
515238104Sdes	}
516238104Sdes
517238104Sdes	RSA_sign(NID_md5, md5_hash, MD5_DIGEST_LENGTH,
518238104Sdes		    (unsigned char*)ldns_buffer_begin(b64sig),
519238104Sdes		    &siglen, key);
520238104Sdes
521238104Sdes	sigdata_rdf = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_B64, siglen,
522238104Sdes								 ldns_buffer_begin(b64sig));
523238104Sdes	ldns_buffer_free(b64sig);
524238104Sdes	return sigdata_rdf;
525238104Sdes}
526238104Sdes#endif /* HAVE_SSL */
527238104Sdes
528238104Sdes/**
529238104Sdes * Pushes all rrs from the rrsets of type A and AAAA on gluelist.
530238104Sdes */
531238104Sdesstatic ldns_status
532238104Sdesldns_dnssec_addresses_on_glue_list(
533238104Sdes		ldns_dnssec_rrsets *cur_rrset,
534238104Sdes		ldns_rr_list *glue_list)
535238104Sdes{
536238104Sdes	ldns_dnssec_rrs *cur_rrs;
537238104Sdes	while (cur_rrset) {
538238104Sdes		if (cur_rrset->type == LDNS_RR_TYPE_A
539238104Sdes				|| cur_rrset->type == LDNS_RR_TYPE_AAAA) {
540238104Sdes			for (cur_rrs = cur_rrset->rrs;
541238104Sdes					cur_rrs;
542238104Sdes					cur_rrs = cur_rrs->next) {
543238104Sdes				if (cur_rrs->rr) {
544238104Sdes					if (!ldns_rr_list_push_rr(glue_list,
545238104Sdes							cur_rrs->rr)) {
546238104Sdes						return LDNS_STATUS_MEM_ERR;
547238104Sdes						/* ldns_rr_list_push_rr()
548238104Sdes						 * returns false when unable
549238104Sdes						 * to increase the capacity
550238104Sdes						 * of the ldsn_rr_list
551238104Sdes						 */
552238104Sdes					}
553238104Sdes				}
554238104Sdes			}
555238104Sdes		}
556238104Sdes		cur_rrset = cur_rrset->next;
557238104Sdes	}
558238104Sdes	return LDNS_STATUS_OK;
559238104Sdes}
560238104Sdes
561238104Sdes/**
562238104Sdes * Marks the names in the zone that are occluded. Those names will be skipped
563238104Sdes * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
564238104Sdes * function. But watch out! Names that are partially occluded (like glue with
565238104Sdes * the same name as the delegation) will not be marked and should specifically
566238104Sdes * be taken into account seperately.
567238104Sdes *
568238104Sdes * When glue_list is given (not NULL), in the process of marking the names, all
569238104Sdes * glue resource records will be pushed to that list, even glue at delegation names.
570238104Sdes *
571238104Sdes * \param[in] zone the zone in which to mark the names
572238104Sdes * \param[in] glue_list the list to which to push the glue rrs
573238104Sdes * \return LDNS_STATUS_OK on success, an error code otherwise
574238104Sdes */
575238104Sdesldns_status
576238104Sdesldns_dnssec_zone_mark_and_get_glue(ldns_dnssec_zone *zone,
577238104Sdes	ldns_rr_list *glue_list)
578238104Sdes{
579238104Sdes	ldns_rbnode_t    *node;
580238104Sdes	ldns_dnssec_name *name;
581238104Sdes	ldns_rdf         *owner;
582238104Sdes	ldns_rdf         *cut = NULL; /* keeps track of zone cuts */
583238104Sdes	/* When the cut is caused by a delegation, below_delegation will be 1.
584238104Sdes	 * When caused by a DNAME, below_delegation will be 0.
585238104Sdes	 */
586238104Sdes	int below_delegation = -1; /* init suppresses comiler warning */
587238104Sdes	ldns_status s;
588238104Sdes
589238104Sdes	if (!zone || !zone->names) {
590238104Sdes		return LDNS_STATUS_NULL;
591238104Sdes	}
592238104Sdes	for (node = ldns_rbtree_first(zone->names);
593238104Sdes			node != LDNS_RBTREE_NULL;
594238104Sdes			node = ldns_rbtree_next(node)) {
595238104Sdes		name = (ldns_dnssec_name *) node->data;
596238104Sdes		owner = ldns_dnssec_name_name(name);
597238104Sdes
598238104Sdes		if (cut) {
599238104Sdes			/* The previous node was a zone cut, or a subdomain
600238104Sdes			 * below a zone cut. Is this node (still) a subdomain
601238104Sdes			 * below the cut? Then the name is occluded. Unless
602238104Sdes			 * the name contains a SOA, after which we are
603238104Sdes			 * authoritative again.
604238104Sdes			 *
605238104Sdes			 * FIXME! If there are labels in between the SOA and
606238104Sdes			 * the cut, going from the authoritative space (below
607238104Sdes			 * the SOA) up into occluded space again, will not be
608238104Sdes			 * detected with the contruct below!
609238104Sdes			 */
610238104Sdes			if (ldns_dname_is_subdomain(owner, cut) &&
611238104Sdes					!ldns_dnssec_rrsets_contains_type(
612238104Sdes					name->rrsets, LDNS_RR_TYPE_SOA)) {
613238104Sdes
614238104Sdes				if (below_delegation && glue_list) {
615238104Sdes					s = ldns_dnssec_addresses_on_glue_list(
616238104Sdes						name->rrsets, glue_list);
617238104Sdes					if (s != LDNS_STATUS_OK) {
618238104Sdes						return s;
619238104Sdes					}
620238104Sdes				}
621238104Sdes				name->is_glue = true; /* Mark occluded name! */
622238104Sdes				continue;
623238104Sdes			} else {
624238104Sdes				cut = NULL;
625238104Sdes			}
626238104Sdes		}
627238104Sdes
628238104Sdes		/* The node is not below a zone cut. Is it a zone cut itself?
629238104Sdes		 * Everything below a SOA is authoritative of course; Except
630238104Sdes		 * when the name also contains a DNAME :).
631238104Sdes		 */
632238104Sdes		if (ldns_dnssec_rrsets_contains_type(
633238104Sdes				name->rrsets, LDNS_RR_TYPE_NS)
634238104Sdes			    && !ldns_dnssec_rrsets_contains_type(
635238104Sdes				name->rrsets, LDNS_RR_TYPE_SOA)) {
636238104Sdes			cut = owner;
637238104Sdes			below_delegation = 1;
638238104Sdes			if (glue_list) { /* record glue on the zone cut */
639238104Sdes				s = ldns_dnssec_addresses_on_glue_list(
640238104Sdes					name->rrsets, glue_list);
641238104Sdes				if (s != LDNS_STATUS_OK) {
642238104Sdes					return s;
643238104Sdes				}
644238104Sdes			}
645238104Sdes		} else if (ldns_dnssec_rrsets_contains_type(
646238104Sdes				name->rrsets, LDNS_RR_TYPE_DNAME)) {
647238104Sdes			cut = owner;
648238104Sdes			below_delegation = 0;
649238104Sdes		}
650238104Sdes	}
651238104Sdes	return LDNS_STATUS_OK;
652238104Sdes}
653238104Sdes
654238104Sdes/**
655238104Sdes * Marks the names in the zone that are occluded. Those names will be skipped
656238104Sdes * when walking the tree with the ldns_dnssec_name_node_next_nonglue()
657238104Sdes * function. But watch out! Names that are partially occluded (like glue with
658238104Sdes * the same name as the delegation) will not be marked and should specifically
659238104Sdes * be taken into account seperately.
660238104Sdes *
661238104Sdes * \param[in] zone the zone in which to mark the names
662238104Sdes * \return LDNS_STATUS_OK on success, an error code otherwise
663238104Sdes */
664238104Sdesldns_status
665238104Sdesldns_dnssec_zone_mark_glue(ldns_dnssec_zone *zone)
666238104Sdes{
667238104Sdes	return ldns_dnssec_zone_mark_and_get_glue(zone, NULL);
668238104Sdes}
669238104Sdes
670238104Sdesldns_rbnode_t *
671238104Sdesldns_dnssec_name_node_next_nonglue(ldns_rbnode_t *node)
672238104Sdes{
673238104Sdes	ldns_rbnode_t *next_node = NULL;
674238104Sdes	ldns_dnssec_name *next_name = NULL;
675238104Sdes	bool done = false;
676238104Sdes
677238104Sdes	if (node == LDNS_RBTREE_NULL) {
678238104Sdes		return NULL;
679238104Sdes	}
680238104Sdes	next_node = node;
681238104Sdes	while (!done) {
682238104Sdes		if (next_node == LDNS_RBTREE_NULL) {
683238104Sdes			return NULL;
684238104Sdes		} else {
685238104Sdes			next_name = (ldns_dnssec_name *)next_node->data;
686238104Sdes			if (!next_name->is_glue) {
687238104Sdes				done = true;
688238104Sdes			} else {
689238104Sdes				next_node = ldns_rbtree_next(next_node);
690238104Sdes			}
691238104Sdes		}
692238104Sdes	}
693238104Sdes	return next_node;
694238104Sdes}
695238104Sdes
696238104Sdesldns_status
697238104Sdesldns_dnssec_zone_create_nsecs(ldns_dnssec_zone *zone,
698238104Sdes                              ldns_rr_list *new_rrs)
699238104Sdes{
700238104Sdes
701238104Sdes	ldns_rbnode_t *first_node, *cur_node, *next_node;
702238104Sdes	ldns_dnssec_name *cur_name, *next_name;
703238104Sdes	ldns_rr *nsec_rr;
704238104Sdes	uint32_t nsec_ttl;
705238104Sdes	ldns_dnssec_rrsets *soa;
706238104Sdes
707238104Sdes	/* the TTL of NSEC rrs should be set to the minimum TTL of
708238104Sdes	 * the zone SOA (RFC4035 Section 2.3)
709238104Sdes	 */
710238104Sdes	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
711238104Sdes
712238104Sdes	/* did the caller actually set it? if not,
713238104Sdes	 * fall back to default ttl
714238104Sdes	 */
715238104Sdes	if (soa && soa->rrs && soa->rrs->rr
716238104Sdes			&& (ldns_rr_rdf(soa->rrs->rr, 6) != NULL)) {
717238104Sdes		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6));
718238104Sdes	} else {
719238104Sdes		nsec_ttl = LDNS_DEFAULT_TTL;
720238104Sdes	}
721238104Sdes
722238104Sdes	first_node = ldns_dnssec_name_node_next_nonglue(
723238104Sdes			       ldns_rbtree_first(zone->names));
724238104Sdes	cur_node = first_node;
725238104Sdes	if (cur_node) {
726238104Sdes		next_node = ldns_dnssec_name_node_next_nonglue(
727238104Sdes			           ldns_rbtree_next(cur_node));
728238104Sdes	} else {
729238104Sdes		next_node = NULL;
730238104Sdes	}
731238104Sdes
732238104Sdes	while (cur_node && next_node) {
733238104Sdes		cur_name = (ldns_dnssec_name *)cur_node->data;
734238104Sdes		next_name = (ldns_dnssec_name *)next_node->data;
735238104Sdes		nsec_rr = ldns_dnssec_create_nsec(cur_name,
736238104Sdes		                                  next_name,
737238104Sdes		                                  LDNS_RR_TYPE_NSEC);
738238104Sdes		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
739238104Sdes		if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){
740238104Sdes			ldns_rr_free(nsec_rr);
741238104Sdes			return LDNS_STATUS_ERR;
742238104Sdes		}
743238104Sdes		ldns_rr_list_push_rr(new_rrs, nsec_rr);
744238104Sdes		cur_node = next_node;
745238104Sdes		if (cur_node) {
746238104Sdes			next_node = ldns_dnssec_name_node_next_nonglue(
747238104Sdes                               ldns_rbtree_next(cur_node));
748238104Sdes		}
749238104Sdes	}
750238104Sdes
751238104Sdes	if (cur_node && !next_node) {
752238104Sdes		cur_name = (ldns_dnssec_name *)cur_node->data;
753238104Sdes		next_name = (ldns_dnssec_name *)first_node->data;
754238104Sdes		nsec_rr = ldns_dnssec_create_nsec(cur_name,
755238104Sdes		                                  next_name,
756238104Sdes		                                  LDNS_RR_TYPE_NSEC);
757238104Sdes		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
758238104Sdes		if(ldns_dnssec_name_add_rr(cur_name, nsec_rr)!=LDNS_STATUS_OK){
759238104Sdes			ldns_rr_free(nsec_rr);
760238104Sdes			return LDNS_STATUS_ERR;
761238104Sdes		}
762238104Sdes		ldns_rr_list_push_rr(new_rrs, nsec_rr);
763238104Sdes	} else {
764238104Sdes		printf("error\n");
765238104Sdes	}
766238104Sdes
767238104Sdes	return LDNS_STATUS_OK;
768238104Sdes}
769238104Sdes
770238104Sdes#ifdef HAVE_SSL
771238104Sdes/* in dnssec_zone.c */
772238104Sdesextern int ldns_dname_compare_v(const void *a, const void *b);
773238104Sdes
774246827Sdesstatic ldns_status
775238104Sdesldns_dnssec_zone_create_nsec3s_mkmap(ldns_dnssec_zone *zone,
776238104Sdes		ldns_rr_list *new_rrs,
777238104Sdes		uint8_t algorithm,
778238104Sdes		uint8_t flags,
779238104Sdes		uint16_t iterations,
780238104Sdes		uint8_t salt_length,
781238104Sdes		uint8_t *salt,
782238104Sdes		ldns_rbtree_t **map)
783238104Sdes{
784238104Sdes	ldns_rbnode_t *first_name_node;
785238104Sdes	ldns_rbnode_t *current_name_node;
786238104Sdes	ldns_dnssec_name *current_name;
787238104Sdes	ldns_status result = LDNS_STATUS_OK;
788238104Sdes	ldns_rr *nsec_rr;
789238104Sdes	ldns_rr_list *nsec3_list;
790238104Sdes	uint32_t nsec_ttl;
791238104Sdes	ldns_dnssec_rrsets *soa;
792238104Sdes	ldns_rbnode_t *hashmap_node;
793238104Sdes
794238104Sdes	if (!zone || !new_rrs || !zone->names) {
795238104Sdes		return LDNS_STATUS_ERR;
796238104Sdes	}
797238104Sdes
798238104Sdes	/* the TTL of NSEC rrs should be set to the minimum TTL of
799238104Sdes	 * the zone SOA (RFC4035 Section 2.3)
800238104Sdes	 */
801238104Sdes	soa = ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_SOA);
802238104Sdes
803238104Sdes	/* did the caller actually set it? if not,
804238104Sdes	 * fall back to default ttl
805238104Sdes	 */
806238104Sdes	if (soa && soa->rrs && soa->rrs->rr
807238104Sdes			&& ldns_rr_rdf(soa->rrs->rr, 6) != NULL) {
808238104Sdes		nsec_ttl = ldns_rdf2native_int32(ldns_rr_rdf(soa->rrs->rr, 6));
809238104Sdes	} else {
810238104Sdes		nsec_ttl = LDNS_DEFAULT_TTL;
811238104Sdes	}
812238104Sdes
813238104Sdes	if (map) {
814238104Sdes		if ((*map = ldns_rbtree_create(ldns_dname_compare_v))
815238104Sdes				== NULL) {
816238104Sdes			map = NULL;
817238104Sdes		};
818238104Sdes	}
819238104Sdes	nsec3_list = ldns_rr_list_new();
820238104Sdes
821238104Sdes	first_name_node = ldns_dnssec_name_node_next_nonglue(
822238104Sdes					  ldns_rbtree_first(zone->names));
823238104Sdes
824238104Sdes	current_name_node = first_name_node;
825238104Sdes
826238104Sdes	while (current_name_node &&
827238104Sdes	       current_name_node != LDNS_RBTREE_NULL) {
828238104Sdes		current_name = (ldns_dnssec_name *) current_name_node->data;
829238104Sdes		nsec_rr = ldns_dnssec_create_nsec3(current_name,
830238104Sdes		                                   NULL,
831238104Sdes		                                   zone->soa->name,
832238104Sdes		                                   algorithm,
833238104Sdes		                                   flags,
834238104Sdes		                                   iterations,
835238104Sdes		                                   salt_length,
836238104Sdes		                                   salt);
837238104Sdes		/* by default, our nsec based generator adds rrsigs
838238104Sdes		 * remove the bitmap for empty nonterminals */
839238104Sdes		if (!current_name->rrsets) {
840238104Sdes			ldns_rdf_deep_free(ldns_rr_pop_rdf(nsec_rr));
841238104Sdes		}
842238104Sdes		ldns_rr_set_ttl(nsec_rr, nsec_ttl);
843238104Sdes		result = ldns_dnssec_name_add_rr(current_name, nsec_rr);
844238104Sdes		ldns_rr_list_push_rr(new_rrs, nsec_rr);
845238104Sdes		ldns_rr_list_push_rr(nsec3_list, nsec_rr);
846238104Sdes		if (map) {
847238104Sdes			hashmap_node = LDNS_MALLOC(ldns_rbnode_t);
848238104Sdes			if (hashmap_node && ldns_rr_owner(nsec_rr)) {
849238104Sdes				hashmap_node->key = ldns_dname_label(
850238104Sdes					ldns_rr_owner(nsec_rr), 0);
851238104Sdes				if (hashmap_node->key) {
852238104Sdes					hashmap_node->data = current_name->name;
853238104Sdes					(void) ldns_rbtree_insert(
854238104Sdes							*map, hashmap_node);
855238104Sdes				}
856238104Sdes			}
857238104Sdes		}
858238104Sdes		current_name_node = ldns_dnssec_name_node_next_nonglue(
859238104Sdes		                   ldns_rbtree_next(current_name_node));
860238104Sdes	}
861238104Sdes	if (result != LDNS_STATUS_OK) {
862238104Sdes		return result;
863238104Sdes	}
864238104Sdes
865238104Sdes	ldns_rr_list_sort_nsec3(nsec3_list);
866238104Sdes	result = ldns_dnssec_chain_nsec3_list(nsec3_list);
867238104Sdes	if (result != LDNS_STATUS_OK) {
868238104Sdes		return result;
869238104Sdes	}
870238104Sdes
871238104Sdes	ldns_rr_list_free(nsec3_list);
872238104Sdes	return result;
873238104Sdes}
874238104Sdes
875238104Sdesldns_status
876238104Sdesldns_dnssec_zone_create_nsec3s(ldns_dnssec_zone *zone,
877238104Sdes		ldns_rr_list *new_rrs,
878238104Sdes		uint8_t algorithm,
879238104Sdes		uint8_t flags,
880238104Sdes		uint16_t iterations,
881238104Sdes		uint8_t salt_length,
882238104Sdes		uint8_t *salt)
883238104Sdes{
884238104Sdes	return ldns_dnssec_zone_create_nsec3s_mkmap(zone, new_rrs, algorithm,
885238104Sdes		       	flags, iterations, salt_length, salt, NULL);
886238104Sdes
887238104Sdes}
888238104Sdes#endif /* HAVE_SSL */
889238104Sdes
890238104Sdesldns_dnssec_rrs *
891238104Sdesldns_dnssec_remove_signatures( ldns_dnssec_rrs *signatures
892238104Sdes			     , ATTR_UNUSED(ldns_key_list *key_list)
893238104Sdes			     , int (*func)(ldns_rr *, void *)
894238104Sdes			     , void *arg
895238104Sdes			     )
896238104Sdes{
897238104Sdes	ldns_dnssec_rrs *base_rrs = signatures;
898238104Sdes	ldns_dnssec_rrs *cur_rr = base_rrs;
899238104Sdes	ldns_dnssec_rrs *prev_rr = NULL;
900238104Sdes	ldns_dnssec_rrs *next_rr;
901238104Sdes
902238104Sdes	uint16_t keytag;
903238104Sdes	size_t i;
904238104Sdes
905238104Sdes	if (!cur_rr) {
906238104Sdes		switch(func(NULL, arg)) {
907238104Sdes		case LDNS_SIGNATURE_LEAVE_ADD_NEW:
908238104Sdes		case LDNS_SIGNATURE_REMOVE_ADD_NEW:
909238104Sdes		break;
910238104Sdes		case LDNS_SIGNATURE_LEAVE_NO_ADD:
911238104Sdes		case LDNS_SIGNATURE_REMOVE_NO_ADD:
912238104Sdes		ldns_key_list_set_use(key_list, false);
913238104Sdes		break;
914238104Sdes		default:
915238104Sdes			fprintf(stderr, "[XX] unknown return value from callback\n");
916238104Sdes			break;
917238104Sdes		}
918238104Sdes		return NULL;
919238104Sdes	}
920238104Sdes	(void)func(cur_rr->rr, arg);
921238104Sdes
922238104Sdes	while (cur_rr) {
923238104Sdes		next_rr = cur_rr->next;
924238104Sdes
925238104Sdes		switch (func(cur_rr->rr, arg)) {
926238104Sdes		case  LDNS_SIGNATURE_LEAVE_ADD_NEW:
927238104Sdes			prev_rr = cur_rr;
928238104Sdes			break;
929238104Sdes		case LDNS_SIGNATURE_LEAVE_NO_ADD:
930238104Sdes			keytag = ldns_rdf2native_int16(
931238104Sdes					   ldns_rr_rrsig_keytag(cur_rr->rr));
932238104Sdes			for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
933238104Sdes				if (ldns_key_keytag(ldns_key_list_key(key_list, i)) ==
934238104Sdes				    keytag) {
935238104Sdes					ldns_key_set_use(ldns_key_list_key(key_list, i),
936238104Sdes								  false);
937238104Sdes				}
938238104Sdes			}
939238104Sdes			prev_rr = cur_rr;
940238104Sdes			break;
941238104Sdes		case LDNS_SIGNATURE_REMOVE_NO_ADD:
942238104Sdes			keytag = ldns_rdf2native_int16(
943238104Sdes					   ldns_rr_rrsig_keytag(cur_rr->rr));
944238104Sdes			for (i = 0; i < ldns_key_list_key_count(key_list); i++) {
945238104Sdes				if (ldns_key_keytag(ldns_key_list_key(key_list, i))
946238104Sdes				    == keytag) {
947238104Sdes					ldns_key_set_use(ldns_key_list_key(key_list, i),
948238104Sdes								  false);
949238104Sdes				}
950238104Sdes			}
951238104Sdes			if (prev_rr) {
952238104Sdes				prev_rr->next = next_rr;
953238104Sdes			} else {
954238104Sdes				base_rrs = next_rr;
955238104Sdes			}
956238104Sdes			LDNS_FREE(cur_rr);
957238104Sdes			break;
958238104Sdes		case LDNS_SIGNATURE_REMOVE_ADD_NEW:
959238104Sdes			if (prev_rr) {
960238104Sdes				prev_rr->next = next_rr;
961238104Sdes			} else {
962238104Sdes				base_rrs = next_rr;
963238104Sdes			}
964238104Sdes			LDNS_FREE(cur_rr);
965238104Sdes			break;
966238104Sdes		default:
967238104Sdes			fprintf(stderr, "[XX] unknown return value from callback\n");
968238104Sdes			break;
969238104Sdes		}
970238104Sdes		cur_rr = next_rr;
971238104Sdes	}
972238104Sdes
973238104Sdes	return base_rrs;
974238104Sdes}
975238104Sdes
976238104Sdes#ifdef HAVE_SSL
977238104Sdesldns_status
978238104Sdesldns_dnssec_zone_create_rrsigs(ldns_dnssec_zone *zone,
979238104Sdes                               ldns_rr_list *new_rrs,
980238104Sdes                               ldns_key_list *key_list,
981238104Sdes                               int (*func)(ldns_rr *, void*),
982238104Sdes                               void *arg)
983238104Sdes{
984238104Sdes	return ldns_dnssec_zone_create_rrsigs_flg(zone, new_rrs, key_list,
985238104Sdes		func, arg, 0);
986238104Sdes}
987238104Sdes
988238104Sdes/** If there are KSKs use only them and mark ZSKs unused */
989238104Sdesstatic void
990238104Sdesldns_key_list_filter_for_dnskey(ldns_key_list *key_list)
991238104Sdes{
992238104Sdes	int saw_ksk = 0;
993238104Sdes	size_t i;
994238104Sdes	for(i=0; i<ldns_key_list_key_count(key_list); i++)
995238104Sdes		if((ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY)) {
996238104Sdes			saw_ksk = 1;
997238104Sdes			break;
998238104Sdes		}
999238104Sdes	if(!saw_ksk)
1000238104Sdes		return;
1001238104Sdes	for(i=0; i<ldns_key_list_key_count(key_list); i++)
1002238104Sdes		if(!(ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY))
1003238104Sdes			ldns_key_set_use(ldns_key_list_key(key_list, i), 0);
1004238104Sdes}
1005238104Sdes
1006238104Sdes/** If there are no ZSKs use KSK as ZSK */
1007238104Sdesstatic void
1008238104Sdesldns_key_list_filter_for_non_dnskey(ldns_key_list *key_list)
1009238104Sdes{
1010238104Sdes	int saw_zsk = 0;
1011238104Sdes	size_t i;
1012238104Sdes	for(i=0; i<ldns_key_list_key_count(key_list); i++)
1013238104Sdes		if(!(ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY)) {
1014238104Sdes			saw_zsk = 1;
1015238104Sdes			break;
1016238104Sdes		}
1017238104Sdes	if(!saw_zsk)
1018238104Sdes		return;
1019238104Sdes	/* else filter all KSKs */
1020238104Sdes	for(i=0; i<ldns_key_list_key_count(key_list); i++)
1021238104Sdes		if((ldns_key_flags(ldns_key_list_key(key_list, i))&LDNS_KEY_SEP_KEY))
1022238104Sdes			ldns_key_set_use(ldns_key_list_key(key_list, i), 0);
1023238104Sdes}
1024238104Sdes
1025238104Sdesldns_status
1026238104Sdesldns_dnssec_zone_create_rrsigs_flg( ATTR_UNUSED(ldns_dnssec_zone *zone)
1027238104Sdes				  , ATTR_UNUSED(ldns_rr_list *new_rrs)
1028238104Sdes				  , ATTR_UNUSED(ldns_key_list *key_list)
1029238104Sdes				  , int (*func)(ldns_rr *, void*)
1030238104Sdes				  , void *arg
1031238104Sdes				  , int flags
1032238104Sdes				  )
1033238104Sdes{
1034238104Sdes	ldns_status result = LDNS_STATUS_OK;
1035238104Sdes
1036238104Sdes	ldns_rbnode_t *cur_node;
1037238104Sdes	ldns_rr_list *rr_list;
1038238104Sdes
1039238104Sdes	ldns_dnssec_name *cur_name;
1040238104Sdes	ldns_dnssec_rrsets *cur_rrset;
1041238104Sdes	ldns_dnssec_rrs *cur_rr;
1042238104Sdes
1043238104Sdes	ldns_rr_list *siglist;
1044238104Sdes
1045238104Sdes	size_t i;
1046238104Sdes
1047238104Sdes	int on_delegation_point = 0; /* handle partially occluded names */
1048238104Sdes
1049238104Sdes	ldns_rr_list *pubkey_list = ldns_rr_list_new();
1050238104Sdes	for (i = 0; i<ldns_key_list_key_count(key_list); i++) {
1051238104Sdes		ldns_rr_list_push_rr( pubkey_list
1052238104Sdes				    , ldns_key2rr(ldns_key_list_key(
1053238104Sdes							key_list, i))
1054238104Sdes				    );
1055238104Sdes	}
1056238104Sdes	/* TODO: callback to see is list should be signed */
1057238104Sdes	/* TODO: remove 'old' signatures from signature list */
1058238104Sdes	cur_node = ldns_rbtree_first(zone->names);
1059238104Sdes	while (cur_node != LDNS_RBTREE_NULL) {
1060238104Sdes		cur_name = (ldns_dnssec_name *) cur_node->data;
1061238104Sdes
1062238104Sdes		if (!cur_name->is_glue) {
1063238104Sdes			on_delegation_point = ldns_dnssec_rrsets_contains_type(
1064238104Sdes					cur_name->rrsets, LDNS_RR_TYPE_NS)
1065238104Sdes				&& !ldns_dnssec_rrsets_contains_type(
1066238104Sdes					cur_name->rrsets, LDNS_RR_TYPE_SOA);
1067238104Sdes			cur_rrset = cur_name->rrsets;
1068238104Sdes			while (cur_rrset) {
1069238104Sdes				/* reset keys to use */
1070238104Sdes				ldns_key_list_set_use(key_list, true);
1071238104Sdes
1072238104Sdes				/* walk through old sigs, remove the old,
1073238104Sdes				   and mark which keys (not) to use) */
1074238104Sdes				cur_rrset->signatures =
1075238104Sdes					ldns_dnssec_remove_signatures(cur_rrset->signatures,
1076238104Sdes											key_list,
1077238104Sdes											func,
1078238104Sdes											arg);
1079238104Sdes				if(!(flags&LDNS_SIGN_DNSKEY_WITH_ZSK) &&
1080238104Sdes					cur_rrset->type == LDNS_RR_TYPE_DNSKEY)
1081238104Sdes					ldns_key_list_filter_for_dnskey(key_list);
1082238104Sdes
1083238104Sdes				if(cur_rrset->type != LDNS_RR_TYPE_DNSKEY)
1084238104Sdes					ldns_key_list_filter_for_non_dnskey(key_list);
1085238104Sdes
1086238104Sdes				/* TODO: just set count to zero? */
1087238104Sdes				rr_list = ldns_rr_list_new();
1088238104Sdes
1089238104Sdes				cur_rr = cur_rrset->rrs;
1090238104Sdes				while (cur_rr) {
1091238104Sdes					ldns_rr_list_push_rr(rr_list, cur_rr->rr);
1092238104Sdes					cur_rr = cur_rr->next;
1093238104Sdes				}
1094238104Sdes
1095238104Sdes				/* only sign non-delegation RRsets */
1096238104Sdes				/* (glue should have been marked earlier,
1097238104Sdes				 *  except on the delegation points itself) */
1098238104Sdes				if (!on_delegation_point ||
1099238104Sdes						ldns_rr_list_type(rr_list)
1100238104Sdes							== LDNS_RR_TYPE_DS ||
1101238104Sdes						ldns_rr_list_type(rr_list)
1102238104Sdes							== LDNS_RR_TYPE_NSEC ||
1103238104Sdes						ldns_rr_list_type(rr_list)
1104238104Sdes							== LDNS_RR_TYPE_NSEC3) {
1105238104Sdes					siglist = ldns_sign_public(rr_list, key_list);
1106238104Sdes					for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) {
1107238104Sdes						if (cur_rrset->signatures) {
1108238104Sdes							result = ldns_dnssec_rrs_add_rr(cur_rrset->signatures,
1109238104Sdes											   ldns_rr_list_rr(siglist,
1110238104Sdes														    i));
1111238104Sdes						} else {
1112238104Sdes							cur_rrset->signatures = ldns_dnssec_rrs_new();
1113238104Sdes							cur_rrset->signatures->rr =
1114238104Sdes								ldns_rr_list_rr(siglist, i);
1115238104Sdes							ldns_rr_list_push_rr(new_rrs,
1116238104Sdes											 ldns_rr_list_rr(siglist,
1117238104Sdes														  i));
1118238104Sdes						}
1119238104Sdes					}
1120238104Sdes					ldns_rr_list_free(siglist);
1121238104Sdes				}
1122238104Sdes
1123238104Sdes				ldns_rr_list_free(rr_list);
1124238104Sdes
1125238104Sdes				cur_rrset = cur_rrset->next;
1126238104Sdes			}
1127238104Sdes
1128238104Sdes			/* sign the nsec */
1129238104Sdes			ldns_key_list_set_use(key_list, true);
1130238104Sdes			cur_name->nsec_signatures =
1131238104Sdes				ldns_dnssec_remove_signatures(cur_name->nsec_signatures,
1132238104Sdes										key_list,
1133238104Sdes										func,
1134238104Sdes										arg);
1135238104Sdes			ldns_key_list_filter_for_non_dnskey(key_list);
1136238104Sdes
1137238104Sdes			rr_list = ldns_rr_list_new();
1138238104Sdes			ldns_rr_list_push_rr(rr_list, cur_name->nsec);
1139238104Sdes			siglist = ldns_sign_public(rr_list, key_list);
1140238104Sdes
1141238104Sdes			for (i = 0; i < ldns_rr_list_rr_count(siglist); i++) {
1142238104Sdes				if (cur_name->nsec_signatures) {
1143238104Sdes					result = ldns_dnssec_rrs_add_rr(cur_name->nsec_signatures,
1144238104Sdes									   ldns_rr_list_rr(siglist, i));
1145238104Sdes				} else {
1146238104Sdes					cur_name->nsec_signatures = ldns_dnssec_rrs_new();
1147238104Sdes					cur_name->nsec_signatures->rr =
1148238104Sdes						ldns_rr_list_rr(siglist, i);
1149238104Sdes					ldns_rr_list_push_rr(new_rrs,
1150238104Sdes									 ldns_rr_list_rr(siglist, i));
1151238104Sdes				}
1152238104Sdes			}
1153238104Sdes
1154238104Sdes			ldns_rr_list_free(siglist);
1155238104Sdes			ldns_rr_list_free(rr_list);
1156238104Sdes		}
1157238104Sdes		cur_node = ldns_rbtree_next(cur_node);
1158238104Sdes	}
1159238104Sdes
1160238104Sdes	ldns_rr_list_deep_free(pubkey_list);
1161238104Sdes	return result;
1162238104Sdes}
1163238104Sdes
1164238104Sdesldns_status
1165238104Sdesldns_dnssec_zone_sign(ldns_dnssec_zone *zone,
1166238104Sdes				  ldns_rr_list *new_rrs,
1167238104Sdes				  ldns_key_list *key_list,
1168238104Sdes				  int (*func)(ldns_rr *, void *),
1169238104Sdes				  void *arg)
1170238104Sdes{
1171238104Sdes	return ldns_dnssec_zone_sign_flg(zone, new_rrs, key_list, func, arg, 0);
1172238104Sdes}
1173238104Sdes
1174238104Sdesldns_status
1175238104Sdesldns_dnssec_zone_sign_flg(ldns_dnssec_zone *zone,
1176238104Sdes				  ldns_rr_list *new_rrs,
1177238104Sdes				  ldns_key_list *key_list,
1178238104Sdes				  int (*func)(ldns_rr *, void *),
1179238104Sdes				  void *arg,
1180238104Sdes				  int flags)
1181238104Sdes{
1182238104Sdes	ldns_status result = LDNS_STATUS_OK;
1183238104Sdes
1184238104Sdes	if (!zone || !new_rrs || !key_list) {
1185238104Sdes		return LDNS_STATUS_ERR;
1186238104Sdes	}
1187238104Sdes
1188238104Sdes	/* zone is already sorted */
1189238104Sdes	result = ldns_dnssec_zone_mark_glue(zone);
1190238104Sdes	if (result != LDNS_STATUS_OK) {
1191238104Sdes		return result;
1192238104Sdes	}
1193238104Sdes
1194238104Sdes	/* check whether we need to add nsecs */
1195238104Sdes	if (zone->names && !((ldns_dnssec_name *)zone->names->root->data)->nsec) {
1196238104Sdes		result = ldns_dnssec_zone_create_nsecs(zone, new_rrs);
1197238104Sdes		if (result != LDNS_STATUS_OK) {
1198238104Sdes			return result;
1199238104Sdes		}
1200238104Sdes	}
1201238104Sdes
1202238104Sdes	result = ldns_dnssec_zone_create_rrsigs_flg(zone,
1203238104Sdes					new_rrs,
1204238104Sdes					key_list,
1205238104Sdes					func,
1206238104Sdes					arg,
1207238104Sdes					flags);
1208238104Sdes
1209238104Sdes	return result;
1210238104Sdes}
1211238104Sdes
1212238104Sdesldns_status
1213238104Sdesldns_dnssec_zone_sign_nsec3(ldns_dnssec_zone *zone,
1214238104Sdes					   ldns_rr_list *new_rrs,
1215238104Sdes					   ldns_key_list *key_list,
1216238104Sdes					   int (*func)(ldns_rr *, void *),
1217238104Sdes					   void *arg,
1218238104Sdes					   uint8_t algorithm,
1219238104Sdes					   uint8_t flags,
1220238104Sdes					   uint16_t iterations,
1221238104Sdes					   uint8_t salt_length,
1222238104Sdes					   uint8_t *salt)
1223238104Sdes{
1224238104Sdes	return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list,
1225238104Sdes		func, arg, algorithm, flags, iterations, salt_length, salt, 0,
1226238104Sdes	       	NULL);
1227238104Sdes}
1228238104Sdes
1229238104Sdesldns_status
1230238104Sdesldns_dnssec_zone_sign_nsec3_flg_mkmap(ldns_dnssec_zone *zone,
1231238104Sdes		ldns_rr_list *new_rrs,
1232238104Sdes		ldns_key_list *key_list,
1233238104Sdes		int (*func)(ldns_rr *, void *),
1234238104Sdes		void *arg,
1235238104Sdes		uint8_t algorithm,
1236238104Sdes		uint8_t flags,
1237238104Sdes		uint16_t iterations,
1238238104Sdes		uint8_t salt_length,
1239238104Sdes		uint8_t *salt,
1240238104Sdes		int signflags,
1241238104Sdes		ldns_rbtree_t **map)
1242238104Sdes{
1243238104Sdes	ldns_rr *nsec3, *nsec3param;
1244238104Sdes	ldns_status result = LDNS_STATUS_OK;
1245238104Sdes
1246238104Sdes	/* zone is already sorted */
1247238104Sdes	result = ldns_dnssec_zone_mark_glue(zone);
1248238104Sdes	if (result != LDNS_STATUS_OK) {
1249238104Sdes		return result;
1250238104Sdes	}
1251238104Sdes
1252238104Sdes	/* TODO if there are already nsec3s presents and their
1253238104Sdes	 * parameters are the same as these, we don't have to recreate
1254238104Sdes	 */
1255238104Sdes	if (zone->names) {
1256238104Sdes		/* add empty nonterminals */
1257238104Sdes		result = ldns_dnssec_zone_add_empty_nonterminals(zone);
1258238104Sdes		if (result != LDNS_STATUS_OK) {
1259238104Sdes			return result;
1260238104Sdes		}
1261238104Sdes
1262238104Sdes		nsec3 = ((ldns_dnssec_name *)zone->names->root->data)->nsec;
1263238104Sdes		if (nsec3 && ldns_rr_get_type(nsec3) == LDNS_RR_TYPE_NSEC3) {
1264238104Sdes			/* no need to recreate */
1265238104Sdes		} else {
1266238104Sdes			if (!ldns_dnssec_zone_find_rrset(zone,
1267238104Sdes									   zone->soa->name,
1268238104Sdes									   LDNS_RR_TYPE_NSEC3PARAM)) {
1269238104Sdes				/* create and add the nsec3param rr */
1270238104Sdes				nsec3param =
1271238104Sdes					ldns_rr_new_frm_type(LDNS_RR_TYPE_NSEC3PARAM);
1272238104Sdes				ldns_rr_set_owner(nsec3param,
1273238104Sdes							   ldns_rdf_clone(zone->soa->name));
1274238104Sdes				ldns_nsec3_add_param_rdfs(nsec3param,
1275238104Sdes									 algorithm,
1276238104Sdes									 flags,
1277238104Sdes									 iterations,
1278238104Sdes									 salt_length,
1279238104Sdes									 salt);
1280238104Sdes				/* always set bit 7 of the flags to zero, according to
1281238104Sdes				 * rfc5155 section 11. The bits are counted from right to left,
1282238104Sdes				 * so bit 7 in rfc5155 is bit 0 in ldns */
1283238104Sdes				ldns_set_bit(ldns_rdf_data(ldns_rr_rdf(nsec3param, 1)), 0, 0);
1284238104Sdes				result = ldns_dnssec_zone_add_rr(zone, nsec3param);
1285238104Sdes				if (result != LDNS_STATUS_OK) {
1286238104Sdes					return result;
1287238104Sdes				}
1288238104Sdes				ldns_rr_list_push_rr(new_rrs, nsec3param);
1289238104Sdes			}
1290238104Sdes			result = ldns_dnssec_zone_create_nsec3s_mkmap(zone,
1291238104Sdes											new_rrs,
1292238104Sdes											algorithm,
1293238104Sdes											flags,
1294238104Sdes											iterations,
1295238104Sdes											salt_length,
1296238104Sdes											salt,
1297238104Sdes											map);
1298238104Sdes			if (result != LDNS_STATUS_OK) {
1299238104Sdes				return result;
1300238104Sdes			}
1301238104Sdes		}
1302238104Sdes
1303238104Sdes		result = ldns_dnssec_zone_create_rrsigs_flg(zone,
1304238104Sdes						new_rrs,
1305238104Sdes						key_list,
1306238104Sdes						func,
1307238104Sdes						arg,
1308238104Sdes						signflags);
1309238104Sdes	}
1310238104Sdes
1311238104Sdes	return result;
1312238104Sdes}
1313238104Sdes
1314238104Sdesldns_status
1315238104Sdesldns_dnssec_zone_sign_nsec3_flg(ldns_dnssec_zone *zone,
1316238104Sdes		ldns_rr_list *new_rrs,
1317238104Sdes		ldns_key_list *key_list,
1318238104Sdes		int (*func)(ldns_rr *, void *),
1319238104Sdes		void *arg,
1320238104Sdes		uint8_t algorithm,
1321238104Sdes		uint8_t flags,
1322238104Sdes		uint16_t iterations,
1323238104Sdes		uint8_t salt_length,
1324238104Sdes		uint8_t *salt,
1325238104Sdes		int signflags)
1326238104Sdes{
1327238104Sdes	return ldns_dnssec_zone_sign_nsec3_flg_mkmap(zone, new_rrs, key_list,
1328238104Sdes		func, arg, algorithm, flags, iterations, salt_length, salt,
1329238104Sdes		signflags, NULL);
1330238104Sdes}
1331238104Sdes
1332238104Sdesldns_zone *
1333238104Sdesldns_zone_sign(const ldns_zone *zone, ldns_key_list *key_list)
1334238104Sdes{
1335238104Sdes	ldns_dnssec_zone *dnssec_zone;
1336238104Sdes	ldns_zone *signed_zone;
1337238104Sdes	ldns_rr_list *new_rrs;
1338238104Sdes	size_t i;
1339238104Sdes
1340238104Sdes	signed_zone = ldns_zone_new();
1341238104Sdes	dnssec_zone = ldns_dnssec_zone_new();
1342238104Sdes
1343238104Sdes	(void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
1344238104Sdes	ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
1345238104Sdes
1346238104Sdes	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
1347238104Sdes		(void) ldns_dnssec_zone_add_rr(dnssec_zone,
1348238104Sdes								 ldns_rr_list_rr(ldns_zone_rrs(zone),
1349238104Sdes											  i));
1350238104Sdes		ldns_zone_push_rr(signed_zone,
1351238104Sdes					   ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone),
1352238104Sdes											   i)));
1353238104Sdes	}
1354238104Sdes
1355238104Sdes	new_rrs = ldns_rr_list_new();
1356238104Sdes	(void) ldns_dnssec_zone_sign(dnssec_zone,
1357238104Sdes						    new_rrs,
1358238104Sdes						    key_list,
1359238104Sdes						    ldns_dnssec_default_replace_signatures,
1360238104Sdes						    NULL);
1361238104Sdes
1362238104Sdes    	for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) {
1363238104Sdes		ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone),
1364238104Sdes						 ldns_rr_clone(ldns_rr_list_rr(new_rrs, i)));
1365238104Sdes	}
1366238104Sdes
1367238104Sdes	ldns_rr_list_deep_free(new_rrs);
1368238104Sdes	ldns_dnssec_zone_free(dnssec_zone);
1369238104Sdes
1370238104Sdes	return signed_zone;
1371238104Sdes}
1372238104Sdes
1373238104Sdesldns_zone *
1374238104Sdesldns_zone_sign_nsec3(ldns_zone *zone, ldns_key_list *key_list, uint8_t algorithm, uint8_t flags, uint16_t iterations, uint8_t salt_length, uint8_t *salt)
1375238104Sdes{
1376238104Sdes	ldns_dnssec_zone *dnssec_zone;
1377238104Sdes	ldns_zone *signed_zone;
1378238104Sdes	ldns_rr_list *new_rrs;
1379238104Sdes	size_t i;
1380238104Sdes
1381238104Sdes	signed_zone = ldns_zone_new();
1382238104Sdes	dnssec_zone = ldns_dnssec_zone_new();
1383238104Sdes
1384238104Sdes	(void) ldns_dnssec_zone_add_rr(dnssec_zone, ldns_zone_soa(zone));
1385238104Sdes	ldns_zone_set_soa(signed_zone, ldns_rr_clone(ldns_zone_soa(zone)));
1386238104Sdes
1387238104Sdes	for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) {
1388238104Sdes		(void) ldns_dnssec_zone_add_rr(dnssec_zone,
1389238104Sdes								 ldns_rr_list_rr(ldns_zone_rrs(zone),
1390238104Sdes											  i));
1391238104Sdes		ldns_zone_push_rr(signed_zone,
1392238104Sdes					   ldns_rr_clone(ldns_rr_list_rr(ldns_zone_rrs(zone),
1393238104Sdes											   i)));
1394238104Sdes	}
1395238104Sdes
1396238104Sdes	new_rrs = ldns_rr_list_new();
1397238104Sdes	(void) ldns_dnssec_zone_sign_nsec3(dnssec_zone,
1398238104Sdes								new_rrs,
1399238104Sdes								key_list,
1400238104Sdes								ldns_dnssec_default_replace_signatures,
1401238104Sdes								NULL,
1402238104Sdes								algorithm,
1403238104Sdes								flags,
1404238104Sdes								iterations,
1405238104Sdes								salt_length,
1406238104Sdes								salt);
1407238104Sdes
1408238104Sdes    	for (i = 0; i < ldns_rr_list_rr_count(new_rrs); i++) {
1409238104Sdes		ldns_rr_list_push_rr(ldns_zone_rrs(signed_zone),
1410238104Sdes						 ldns_rr_clone(ldns_rr_list_rr(new_rrs, i)));
1411238104Sdes	}
1412238104Sdes
1413238104Sdes	ldns_rr_list_deep_free(new_rrs);
1414238104Sdes	ldns_dnssec_zone_free(dnssec_zone);
1415238104Sdes
1416238104Sdes	return signed_zone;
1417238104Sdes}
1418238104Sdes#endif /* HAVE_SSL */
1419238104Sdes
1420238104Sdes
1421