summaryrefslogtreecommitdiffstats
path: root/lib/dnssec.h
blob: 0fbd47c025bc8ccf74a6012e1b1a30b18a646b7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*  Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
 *  SPDX-License-Identifier: GPL-3.0-or-later
 */

#pragma once

#include "lib/defines.h"
#include "lib/utils.h"
#include <libknot/packet/pkt.h>

/**
 * Initialise cryptographic back-end.
 */
KR_EXPORT
void kr_crypto_init(void);

/**
 * De-initialise cryptographic back-end.
 */
KR_EXPORT
void kr_crypto_cleanup(void);

/**
 * Re-initialise cryptographic back-end.
 * @note Must be called after fork() in the child.
 */
KR_EXPORT
void kr_crypto_reinit(void);

#define KR_DNSSEC_VFLG_WEXPAND 0x01
#define KR_DNSSEC_VFLG_OPTOUT  0x02

/** DNSSEC validation context. */
struct kr_rrset_validation_ctx {
	const knot_pkt_t *pkt;		/*!< Packet to be validated. */
	ranked_rr_array_t *rrs;		/*!< List of preselected RRs to be validated. */
	knot_section_t section_id;	/*!< Section to work with. */
	knot_rrset_t *keys;		/*!< DNSKEY RRSet; TTLs may get lowered when validating this set. */
        const knot_dname_t *zone_name;	/*!< Name of the zone containing the RRSIG RRSet. */
	uint32_t timestamp;		/*!< Validation time. */
	uint32_t ttl_min;		/*!< See trim_ttl() for details. */
        bool has_nsec3;			/*!< Whether to use NSEC3 validation. */
	uint32_t qry_uid;		/*!< Current query uid. */
	uint32_t flags;			/*!< Output - Flags. */
	uint32_t err_cnt;		/*!< Output - Number of validation failures. */
	uint32_t cname_norrsig_cnt;	/*!< Output - Number of CNAMEs missing RRSIGs. */

	/** Validation result: kr_error() code.
	 *
	 * ENOENT: the usual, no suitable signature found
	 * EAGAIN: encountered a different signer name
	 * +others
	 */
	int result;
	const struct kr_query *log_qry; /*!< The query; just for logging purposes. */
	struct {
		unsigned int matching_name_type;	/*!< Name + type matches */
		unsigned int expired;
		unsigned int notyet;
		unsigned int signer_invalid;		/*!< Signer is not zone apex */
		unsigned int labels_invalid;		/*!< Number of labels in RRSIG */
		unsigned int key_invalid;		/*!< Algorithm/keytag/key owner */
		unsigned int crypto_invalid;
		unsigned int nsec_invalid;
	} rrs_counters;	/*!< Error counters for single RRset validation. */
};

typedef struct kr_rrset_validation_ctx kr_rrset_validation_ctx_t;

/**
 * Validate RRSet.
 * @param vctx    Pointer to validation context.
 * @param covered RRSet covered by a signature. It must be in canonical format.
 * 		  Its TTL may get lowered.
 * @return        0 or kr_error() code, same as vctx->result (see its docs).
 */
int kr_rrset_validate(kr_rrset_validation_ctx_t *vctx, knot_rrset_t *covered);

/**
 * Return true iff the RRset contains at least one usable DS.  See RFC6840 5.2.
 */
KR_EXPORT KR_PURE
bool kr_ds_algo_support(const knot_rrset_t *ta);

/**
 * Check whether the DNSKEY rrset matches the supplied trust anchor RRSet.
 *
 * @param vctx  Pointer to validation context.  Note that TTL of vctx->keys may get lowered.
 * @param sigs  RRSIGs for this DNSKEY set
 * @param ta    Trusted DS RRSet against which to validate the DNSKEY RRSet.
 * @return      0 or error code, same as vctx->result.
 */
int kr_dnskeys_trusted(kr_rrset_validation_ctx_t *vctx, const knot_rdataset_t *sigs,
			const knot_rrset_t *ta);

/** Return true if the DNSKEY can be used as a ZSK.  */
KR_EXPORT KR_PURE
bool kr_dnssec_key_zsk(const uint8_t *dnskey_rdata);

/** Return true if the DNSKEY indicates being KSK (=> has SEP).  */
KR_EXPORT KR_PURE
bool kr_dnssec_key_ksk(const uint8_t *dnskey_rdata);

/** Return true if the DNSKEY is revoked. */
KR_EXPORT KR_PURE
bool kr_dnssec_key_revoked(const uint8_t *dnskey_rdata);

/** Return DNSKEY tag.
  * @param rrtype RR type (either DS or DNSKEY are supported)
  * @param rdata  Key/digest RDATA.
  * @param rdlen  RDATA length.
  * @return Key tag (positive number), or an error code
  */
KR_EXPORT KR_PURE
int kr_dnssec_key_tag(uint16_t rrtype, const uint8_t *rdata, size_t rdlen);

/** Return 0 if the two keys are identical.
  * @note This compares RDATA only, algorithm and public key must match.
  * @param key_a_rdata First key RDATA
  * @param key_a_rdlen First key RDATA length
  * @param key_b_rdata Second key RDATA
  * @param key_b_rdlen Second key RDATA length
  * @return 0 if they match or an error code
  */
KR_EXPORT KR_PURE
int kr_dnssec_key_match(const uint8_t *key_a_rdata, size_t key_a_rdlen,
                        const uint8_t *key_b_rdata, size_t key_b_rdlen);

/* Opaque DNSSEC key struct; forward declaration from libdnssec. */
struct dnssec_key;

/**
 * Construct a DNSSEC key.
 * @param key   Pointer to be set to newly created DNSSEC key.
 * @param kown  DNSKEY owner name.
 * @param rdata DNSKEY RDATA
 * @param rdlen DNSKEY RDATA length
 * @return 0 or error code; in particular: DNSSEC_INVALID_KEY_ALGORITHM
 */
int kr_dnssec_key_from_rdata(struct dnssec_key **key, const knot_dname_t *kown, const uint8_t *rdata, size_t rdlen);

/**
 * Frees the DNSSEC key.
 * @param key Pointer to freed key.
 */
void kr_dnssec_key_free(struct dnssec_key **key);

/**
 * Checks whether NSEC/NSEC3 RR selected by iterator matches the supplied name and type.
 * @param rrs     Records selected by iterator.
 * @param qry_uid Query unique identifier where NSEC/NSEC3 belongs to.
 * @param name    Name to be checked.
 * @param type    Type to be checked.
 * @return        0 or error code.
 */
int kr_dnssec_matches_name_and_type(const ranked_rr_array_t *rrs, uint32_t qry_uid,
				    const knot_dname_t *name, uint16_t type);


/* Simple validator API.  Main use case: prefill module, i.e. RRs from a zone file. */

/** Opaque context for simple validator. */
struct kr_svldr_ctx;
/**
 * Create new context for validating within a given zone.
 *
 * - `ds` is assumed to be trusted, and it's used to validate `dnskey+dnskey_sigs`.
 * - The TTL of `dnskey` may get trimmed.
 * - The insides are placed on malloc heap (use _free_ctx).
 * - `err_ctx` is optional, for use when error happens (but avoid the inside pointers)
 */
KR_EXPORT
struct kr_svldr_ctx * kr_svldr_new_ctx(const knot_rrset_t *ds, knot_rrset_t *dnskey,
		const knot_rdataset_t *dnskey_sigs, uint32_t timestamp,
		kr_rrset_validation_ctx_t *err_ctx);
/** Free the context.  Passing NULL is OK. */
KR_EXPORT
void kr_svldr_free_ctx(struct kr_svldr_ctx *ctx);
/**
 * Validate an RRset with the associated signatures; assume no wildcard expansions.
 *
 * - It's caller's responsibility that rrsigs have matching owner, class and type.
 * - The TTL of `rrs` may get trimmed.
 * - If it's a wildcard other than in its simple `*.` form, it may fail to validate.
 * - More generally, non-existence proofs are not supported.
 * @return  0 or kr_error() code, same as kr_rrset_validation_ctx::result (see its docs).
 */
KR_EXPORT
int kr_svldr_rrset(knot_rrset_t *rrs, const knot_rdataset_t *rrsigs,
			struct kr_svldr_ctx *ctx);