xref: /dflybsd-src/contrib/ldns/dane.c (revision d1b2b5caec9ab35b37f82c6e75b7f14f9c9103b2)
1*d1b2b5caSJohn Marino /*
2*d1b2b5caSJohn Marino  * Verify or create TLS authentication with DANE (RFC6698)
3*d1b2b5caSJohn Marino  *
4*d1b2b5caSJohn Marino  * (c) NLnetLabs 2012
5*d1b2b5caSJohn Marino  *
6*d1b2b5caSJohn Marino  * See the file LICENSE for the license.
7*d1b2b5caSJohn Marino  *
8*d1b2b5caSJohn Marino  */
9*d1b2b5caSJohn Marino 
10*d1b2b5caSJohn Marino #include <ldns/config.h>
11*d1b2b5caSJohn Marino 
12*d1b2b5caSJohn Marino #include <ldns/ldns.h>
13*d1b2b5caSJohn Marino #include <ldns/dane.h>
14*d1b2b5caSJohn Marino 
15*d1b2b5caSJohn Marino #include <unistd.h>
16*d1b2b5caSJohn Marino #include <stdlib.h>
17*d1b2b5caSJohn Marino #include <sys/types.h>
18*d1b2b5caSJohn Marino #include <sys/socket.h>
19*d1b2b5caSJohn Marino #include <netdb.h>
20*d1b2b5caSJohn Marino 
21*d1b2b5caSJohn Marino #ifdef HAVE_SSL
22*d1b2b5caSJohn Marino #include <openssl/ssl.h>
23*d1b2b5caSJohn Marino #include <openssl/err.h>
24*d1b2b5caSJohn Marino #include <openssl/x509v3.h>
25*d1b2b5caSJohn Marino #endif
26*d1b2b5caSJohn Marino 
27*d1b2b5caSJohn Marino ldns_status
28*d1b2b5caSJohn Marino ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name,
29*d1b2b5caSJohn Marino 		uint16_t port, ldns_dane_transport transport)
30*d1b2b5caSJohn Marino {
31*d1b2b5caSJohn Marino 	char buf[LDNS_MAX_DOMAINLEN];
32*d1b2b5caSJohn Marino 	size_t s;
33*d1b2b5caSJohn Marino 
34*d1b2b5caSJohn Marino 	assert(tlsa_owner != NULL);
35*d1b2b5caSJohn Marino 	assert(name != NULL);
36*d1b2b5caSJohn Marino 	assert(ldns_rdf_get_type(name) == LDNS_RDF_TYPE_DNAME);
37*d1b2b5caSJohn Marino 
38*d1b2b5caSJohn Marino 	s = (size_t)snprintf(buf, LDNS_MAX_DOMAINLEN, "X_%d", (int)port);
39*d1b2b5caSJohn Marino 	buf[0] = (char)(s - 1);
40*d1b2b5caSJohn Marino 
41*d1b2b5caSJohn Marino 	switch(transport) {
42*d1b2b5caSJohn Marino 	case LDNS_DANE_TRANSPORT_TCP:
43*d1b2b5caSJohn Marino 		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_tcp");
44*d1b2b5caSJohn Marino 		break;
45*d1b2b5caSJohn Marino 
46*d1b2b5caSJohn Marino 	case LDNS_DANE_TRANSPORT_UDP:
47*d1b2b5caSJohn Marino 		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_udp");
48*d1b2b5caSJohn Marino 		break;
49*d1b2b5caSJohn Marino 
50*d1b2b5caSJohn Marino 	case LDNS_DANE_TRANSPORT_SCTP:
51*d1b2b5caSJohn Marino 		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\005_sctp");
52*d1b2b5caSJohn Marino 		break;
53*d1b2b5caSJohn Marino 
54*d1b2b5caSJohn Marino 	default:
55*d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_TRANSPORT;
56*d1b2b5caSJohn Marino 	}
57*d1b2b5caSJohn Marino 	if (s + ldns_rdf_size(name) > LDNS_MAX_DOMAINLEN) {
58*d1b2b5caSJohn Marino 		return LDNS_STATUS_DOMAINNAME_OVERFLOW;
59*d1b2b5caSJohn Marino 	}
60*d1b2b5caSJohn Marino 	memcpy(buf + s, ldns_rdf_data(name), ldns_rdf_size(name));
61*d1b2b5caSJohn Marino 	*tlsa_owner = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
62*d1b2b5caSJohn Marino 			s + ldns_rdf_size(name), buf);
63*d1b2b5caSJohn Marino 	if (*tlsa_owner == NULL) {
64*d1b2b5caSJohn Marino 		return LDNS_STATUS_MEM_ERR;
65*d1b2b5caSJohn Marino 	}
66*d1b2b5caSJohn Marino 	return LDNS_STATUS_OK;
67*d1b2b5caSJohn Marino }
68*d1b2b5caSJohn Marino 
69*d1b2b5caSJohn Marino 
70*d1b2b5caSJohn Marino #ifdef HAVE_SSL
71*d1b2b5caSJohn Marino ldns_status
72*d1b2b5caSJohn Marino ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert,
73*d1b2b5caSJohn Marino 		ldns_tlsa_selector      selector,
74*d1b2b5caSJohn Marino 		ldns_tlsa_matching_type matching_type)
75*d1b2b5caSJohn Marino {
76*d1b2b5caSJohn Marino 	unsigned char* buf = NULL;
77*d1b2b5caSJohn Marino 	size_t len;
78*d1b2b5caSJohn Marino 
79*d1b2b5caSJohn Marino 	X509_PUBKEY* xpubkey;
80*d1b2b5caSJohn Marino 	EVP_PKEY* epubkey;
81*d1b2b5caSJohn Marino 
82*d1b2b5caSJohn Marino 	unsigned char* digest;
83*d1b2b5caSJohn Marino 
84*d1b2b5caSJohn Marino 	assert(rdf != NULL);
85*d1b2b5caSJohn Marino 	assert(cert != NULL);
86*d1b2b5caSJohn Marino 
87*d1b2b5caSJohn Marino 	switch(selector) {
88*d1b2b5caSJohn Marino 	case LDNS_TLSA_SELECTOR_FULL_CERTIFICATE:
89*d1b2b5caSJohn Marino 
90*d1b2b5caSJohn Marino 		len = (size_t)i2d_X509(cert, &buf);
91*d1b2b5caSJohn Marino 		break;
92*d1b2b5caSJohn Marino 
93*d1b2b5caSJohn Marino 	case LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
94*d1b2b5caSJohn Marino 
95*d1b2b5caSJohn Marino #ifndef S_SPLINT_S
96*d1b2b5caSJohn Marino 		xpubkey = X509_get_X509_PUBKEY(cert);
97*d1b2b5caSJohn Marino #endif
98*d1b2b5caSJohn Marino 		if (! xpubkey) {
99*d1b2b5caSJohn Marino 			return LDNS_STATUS_SSL_ERR;
100*d1b2b5caSJohn Marino 		}
101*d1b2b5caSJohn Marino 		epubkey = X509_PUBKEY_get(xpubkey);
102*d1b2b5caSJohn Marino 		if (! epubkey) {
103*d1b2b5caSJohn Marino 			return LDNS_STATUS_SSL_ERR;
104*d1b2b5caSJohn Marino 		}
105*d1b2b5caSJohn Marino 		len = (size_t)i2d_PUBKEY(epubkey, &buf);
106*d1b2b5caSJohn Marino 		break;
107*d1b2b5caSJohn Marino 
108*d1b2b5caSJohn Marino 	default:
109*d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_SELECTOR;
110*d1b2b5caSJohn Marino 	}
111*d1b2b5caSJohn Marino 
112*d1b2b5caSJohn Marino 	switch(matching_type) {
113*d1b2b5caSJohn Marino 	case LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
114*d1b2b5caSJohn Marino 
115*d1b2b5caSJohn Marino 		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, len, buf);
116*d1b2b5caSJohn Marino 
117*d1b2b5caSJohn Marino 		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
118*d1b2b5caSJohn Marino 		break;
119*d1b2b5caSJohn Marino 
120*d1b2b5caSJohn Marino 	case LDNS_TLSA_MATCHING_TYPE_SHA256:
121*d1b2b5caSJohn Marino 
122*d1b2b5caSJohn Marino 		digest = LDNS_XMALLOC(unsigned char, SHA256_DIGEST_LENGTH);
123*d1b2b5caSJohn Marino 		if (digest == NULL) {
124*d1b2b5caSJohn Marino 			LDNS_FREE(buf);
125*d1b2b5caSJohn Marino 			return LDNS_STATUS_MEM_ERR;
126*d1b2b5caSJohn Marino 		}
127*d1b2b5caSJohn Marino 		(void) ldns_sha256(buf, (unsigned int)len, digest);
128*d1b2b5caSJohn Marino 		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, SHA256_DIGEST_LENGTH,
129*d1b2b5caSJohn Marino 				digest);
130*d1b2b5caSJohn Marino 		LDNS_FREE(buf);
131*d1b2b5caSJohn Marino 
132*d1b2b5caSJohn Marino 		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
133*d1b2b5caSJohn Marino 		break;
134*d1b2b5caSJohn Marino 
135*d1b2b5caSJohn Marino 	case LDNS_TLSA_MATCHING_TYPE_SHA512:
136*d1b2b5caSJohn Marino 
137*d1b2b5caSJohn Marino 		digest = LDNS_XMALLOC(unsigned char, SHA512_DIGEST_LENGTH);
138*d1b2b5caSJohn Marino 		if (digest == NULL) {
139*d1b2b5caSJohn Marino 			LDNS_FREE(buf);
140*d1b2b5caSJohn Marino 			return LDNS_STATUS_MEM_ERR;
141*d1b2b5caSJohn Marino 		}
142*d1b2b5caSJohn Marino 		(void) ldns_sha512(buf, (unsigned int)len, digest);
143*d1b2b5caSJohn Marino 		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, SHA512_DIGEST_LENGTH,
144*d1b2b5caSJohn Marino 				digest);
145*d1b2b5caSJohn Marino 		LDNS_FREE(buf);
146*d1b2b5caSJohn Marino 
147*d1b2b5caSJohn Marino 		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
148*d1b2b5caSJohn Marino 		break;
149*d1b2b5caSJohn Marino 
150*d1b2b5caSJohn Marino 	default:
151*d1b2b5caSJohn Marino 		LDNS_FREE(buf);
152*d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_MATCHING_TYPE;
153*d1b2b5caSJohn Marino 	}
154*d1b2b5caSJohn Marino }
155*d1b2b5caSJohn Marino 
156*d1b2b5caSJohn Marino 
157*d1b2b5caSJohn Marino /* Ordinary PKIX validation of cert (with extra_certs to help)
158*d1b2b5caSJohn Marino  * against the CA's in store
159*d1b2b5caSJohn Marino  */
160*d1b2b5caSJohn Marino static ldns_status
161*d1b2b5caSJohn Marino ldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs,
162*d1b2b5caSJohn Marino 		X509_STORE* store)
163*d1b2b5caSJohn Marino {
164*d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
165*d1b2b5caSJohn Marino 	ldns_status s;
166*d1b2b5caSJohn Marino 
167*d1b2b5caSJohn Marino 	if (! store) {
168*d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
169*d1b2b5caSJohn Marino 	}
170*d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
171*d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
172*d1b2b5caSJohn Marino 
173*d1b2b5caSJohn Marino 		return LDNS_STATUS_SSL_ERR;
174*d1b2b5caSJohn Marino 
175*d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, store,
176*d1b2b5caSJohn Marino 				cert, extra_certs) != 1) {
177*d1b2b5caSJohn Marino 		s = LDNS_STATUS_SSL_ERR;
178*d1b2b5caSJohn Marino 
179*d1b2b5caSJohn Marino 	} else if (X509_verify_cert(vrfy_ctx) == 1) {
180*d1b2b5caSJohn Marino 
181*d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
182*d1b2b5caSJohn Marino 
183*d1b2b5caSJohn Marino 	} else {
184*d1b2b5caSJohn Marino 		s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
185*d1b2b5caSJohn Marino 	}
186*d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
187*d1b2b5caSJohn Marino 	return s;
188*d1b2b5caSJohn Marino }
189*d1b2b5caSJohn Marino 
190*d1b2b5caSJohn Marino 
191*d1b2b5caSJohn Marino /* Orinary PKIX validation of cert (with extra_certs to help)
192*d1b2b5caSJohn Marino  * against the CA's in store, but also return the validation chain.
193*d1b2b5caSJohn Marino  */
194*d1b2b5caSJohn Marino static ldns_status
195*d1b2b5caSJohn Marino ldns_dane_pkix_validate_and_get_chain(STACK_OF(X509)** chain, X509* cert,
196*d1b2b5caSJohn Marino 		STACK_OF(X509)* extra_certs, X509_STORE* store)
197*d1b2b5caSJohn Marino {
198*d1b2b5caSJohn Marino 	ldns_status s;
199*d1b2b5caSJohn Marino 	X509_STORE* empty_store = NULL;
200*d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
201*d1b2b5caSJohn Marino 
202*d1b2b5caSJohn Marino 	assert(chain != NULL);
203*d1b2b5caSJohn Marino 
204*d1b2b5caSJohn Marino 	if (! store) {
205*d1b2b5caSJohn Marino 		store = empty_store = X509_STORE_new();
206*d1b2b5caSJohn Marino 	}
207*d1b2b5caSJohn Marino 	s = LDNS_STATUS_SSL_ERR;
208*d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
209*d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
210*d1b2b5caSJohn Marino 
211*d1b2b5caSJohn Marino 		goto exit_free_empty_store;
212*d1b2b5caSJohn Marino 
213*d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, store,
214*d1b2b5caSJohn Marino 					cert, extra_certs) != 1) {
215*d1b2b5caSJohn Marino 		goto exit_free_vrfy_ctx;
216*d1b2b5caSJohn Marino 
217*d1b2b5caSJohn Marino 	} else if (X509_verify_cert(vrfy_ctx) == 1) {
218*d1b2b5caSJohn Marino 
219*d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
220*d1b2b5caSJohn Marino 
221*d1b2b5caSJohn Marino 	} else {
222*d1b2b5caSJohn Marino 		s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
223*d1b2b5caSJohn Marino 	}
224*d1b2b5caSJohn Marino 	*chain = X509_STORE_CTX_get1_chain(vrfy_ctx);
225*d1b2b5caSJohn Marino 	if (! *chain) {
226*d1b2b5caSJohn Marino 		s = LDNS_STATUS_SSL_ERR;
227*d1b2b5caSJohn Marino 	}
228*d1b2b5caSJohn Marino 
229*d1b2b5caSJohn Marino exit_free_vrfy_ctx:
230*d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
231*d1b2b5caSJohn Marino 
232*d1b2b5caSJohn Marino exit_free_empty_store:
233*d1b2b5caSJohn Marino 	if (empty_store) {
234*d1b2b5caSJohn Marino 		X509_STORE_free(empty_store);
235*d1b2b5caSJohn Marino 	}
236*d1b2b5caSJohn Marino 	return s;
237*d1b2b5caSJohn Marino }
238*d1b2b5caSJohn Marino 
239*d1b2b5caSJohn Marino 
240*d1b2b5caSJohn Marino /* Return the validation chain that can be build out of cert, with extra_certs.
241*d1b2b5caSJohn Marino  */
242*d1b2b5caSJohn Marino static ldns_status
243*d1b2b5caSJohn Marino ldns_dane_pkix_get_chain(STACK_OF(X509)** chain,
244*d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs)
245*d1b2b5caSJohn Marino {
246*d1b2b5caSJohn Marino 	ldns_status s;
247*d1b2b5caSJohn Marino 	X509_STORE* empty_store = NULL;
248*d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
249*d1b2b5caSJohn Marino 
250*d1b2b5caSJohn Marino 	assert(chain != NULL);
251*d1b2b5caSJohn Marino 
252*d1b2b5caSJohn Marino 	empty_store = X509_STORE_new();
253*d1b2b5caSJohn Marino 	s = LDNS_STATUS_SSL_ERR;
254*d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
255*d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
256*d1b2b5caSJohn Marino 
257*d1b2b5caSJohn Marino 		goto exit_free_empty_store;
258*d1b2b5caSJohn Marino 
259*d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, empty_store,
260*d1b2b5caSJohn Marino 					cert, extra_certs) != 1) {
261*d1b2b5caSJohn Marino 		goto exit_free_vrfy_ctx;
262*d1b2b5caSJohn Marino 	}
263*d1b2b5caSJohn Marino 	(void) X509_verify_cert(vrfy_ctx);
264*d1b2b5caSJohn Marino 	*chain = X509_STORE_CTX_get1_chain(vrfy_ctx);
265*d1b2b5caSJohn Marino 	if (! *chain) {
266*d1b2b5caSJohn Marino 		s = LDNS_STATUS_SSL_ERR;
267*d1b2b5caSJohn Marino 	} else {
268*d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
269*d1b2b5caSJohn Marino 	}
270*d1b2b5caSJohn Marino exit_free_vrfy_ctx:
271*d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
272*d1b2b5caSJohn Marino 
273*d1b2b5caSJohn Marino exit_free_empty_store:
274*d1b2b5caSJohn Marino 	X509_STORE_free(empty_store);
275*d1b2b5caSJohn Marino 	return s;
276*d1b2b5caSJohn Marino }
277*d1b2b5caSJohn Marino 
278*d1b2b5caSJohn Marino 
279*d1b2b5caSJohn Marino /* Pop n+1 certs and return the last popped.
280*d1b2b5caSJohn Marino  */
281*d1b2b5caSJohn Marino static ldns_status
282*d1b2b5caSJohn Marino ldns_dane_get_nth_cert_from_validation_chain(
283*d1b2b5caSJohn Marino 		X509** cert, STACK_OF(X509)* chain, int n, bool ca)
284*d1b2b5caSJohn Marino {
285*d1b2b5caSJohn Marino 	if (n >= sk_X509_num(chain) || n < 0) {
286*d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_OFFSET_OUT_OF_RANGE;
287*d1b2b5caSJohn Marino 	}
288*d1b2b5caSJohn Marino 	*cert = sk_X509_pop(chain);
289*d1b2b5caSJohn Marino 	while (n-- > 0) {
290*d1b2b5caSJohn Marino 		X509_free(*cert);
291*d1b2b5caSJohn Marino 		*cert = sk_X509_pop(chain);
292*d1b2b5caSJohn Marino 	}
293*d1b2b5caSJohn Marino 	if (ca && ! X509_check_ca(*cert)) {
294*d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_NON_CA_CERTIFICATE;
295*d1b2b5caSJohn Marino 	}
296*d1b2b5caSJohn Marino 	return LDNS_STATUS_OK;
297*d1b2b5caSJohn Marino }
298*d1b2b5caSJohn Marino 
299*d1b2b5caSJohn Marino 
300*d1b2b5caSJohn Marino /* Create validation chain with cert and extra_certs and returns the last
301*d1b2b5caSJohn Marino  * self-signed (if present).
302*d1b2b5caSJohn Marino  */
303*d1b2b5caSJohn Marino static ldns_status
304*d1b2b5caSJohn Marino ldns_dane_pkix_get_last_self_signed(X509** out_cert,
305*d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs)
306*d1b2b5caSJohn Marino {
307*d1b2b5caSJohn Marino 	ldns_status s;
308*d1b2b5caSJohn Marino 	X509_STORE* empty_store = NULL;
309*d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
310*d1b2b5caSJohn Marino 
311*d1b2b5caSJohn Marino 	assert(out_cert != NULL);
312*d1b2b5caSJohn Marino 
313*d1b2b5caSJohn Marino 	empty_store = X509_STORE_new();
314*d1b2b5caSJohn Marino 	s = LDNS_STATUS_SSL_ERR;
315*d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
316*d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
317*d1b2b5caSJohn Marino 		goto exit_free_empty_store;
318*d1b2b5caSJohn Marino 
319*d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, empty_store,
320*d1b2b5caSJohn Marino 					cert, extra_certs) != 1) {
321*d1b2b5caSJohn Marino 		goto exit_free_vrfy_ctx;
322*d1b2b5caSJohn Marino 
323*d1b2b5caSJohn Marino 	}
324*d1b2b5caSJohn Marino 	(void) X509_verify_cert(vrfy_ctx);
325*d1b2b5caSJohn Marino 	if (vrfy_ctx->error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
326*d1b2b5caSJohn Marino 	    vrfy_ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT){
327*d1b2b5caSJohn Marino 
328*d1b2b5caSJohn Marino 		*out_cert = X509_STORE_CTX_get_current_cert( vrfy_ctx);
329*d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
330*d1b2b5caSJohn Marino 	} else {
331*d1b2b5caSJohn Marino 		s = LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR;
332*d1b2b5caSJohn Marino 	}
333*d1b2b5caSJohn Marino exit_free_vrfy_ctx:
334*d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
335*d1b2b5caSJohn Marino 
336*d1b2b5caSJohn Marino exit_free_empty_store:
337*d1b2b5caSJohn Marino 	X509_STORE_free(empty_store);
338*d1b2b5caSJohn Marino 	return s;
339*d1b2b5caSJohn Marino }
340*d1b2b5caSJohn Marino 
341*d1b2b5caSJohn Marino 
342*d1b2b5caSJohn Marino ldns_status
343*d1b2b5caSJohn Marino ldns_dane_select_certificate(X509** selected_cert,
344*d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs,
345*d1b2b5caSJohn Marino 		X509_STORE* pkix_validation_store,
346*d1b2b5caSJohn Marino 		ldns_tlsa_certificate_usage cert_usage, int offset)
347*d1b2b5caSJohn Marino {
348*d1b2b5caSJohn Marino 	ldns_status s;
349*d1b2b5caSJohn Marino 	STACK_OF(X509)* pkix_validation_chain = NULL;
350*d1b2b5caSJohn Marino 
351*d1b2b5caSJohn Marino 	assert(selected_cert != NULL);
352*d1b2b5caSJohn Marino 	assert(cert != NULL);
353*d1b2b5caSJohn Marino 
354*d1b2b5caSJohn Marino 	/* With PKIX validation explicitely turned off (pkix_validation_store
355*d1b2b5caSJohn Marino 	 *  == NULL), treat the "CA constraint" and "Service certificate
356*d1b2b5caSJohn Marino 	 * constraint" the same as "Trust anchor assertion" and "Domain issued
357*d1b2b5caSJohn Marino 	 * certificate" respectively.
358*d1b2b5caSJohn Marino 	 */
359*d1b2b5caSJohn Marino 	if (pkix_validation_store == NULL) {
360*d1b2b5caSJohn Marino 		switch (cert_usage) {
361*d1b2b5caSJohn Marino 
362*d1b2b5caSJohn Marino 		case LDNS_TLSA_USAGE_CA_CONSTRAINT:
363*d1b2b5caSJohn Marino 
364*d1b2b5caSJohn Marino 			cert_usage = LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION;
365*d1b2b5caSJohn Marino 			break;
366*d1b2b5caSJohn Marino 
367*d1b2b5caSJohn Marino 		case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
368*d1b2b5caSJohn Marino 
369*d1b2b5caSJohn Marino 			cert_usage = LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE;
370*d1b2b5caSJohn Marino 			break;
371*d1b2b5caSJohn Marino 
372*d1b2b5caSJohn Marino 		default:
373*d1b2b5caSJohn Marino 			break;
374*d1b2b5caSJohn Marino 		}
375*d1b2b5caSJohn Marino 	}
376*d1b2b5caSJohn Marino 
377*d1b2b5caSJohn Marino 	/* Now what to do with each Certificate usage...
378*d1b2b5caSJohn Marino 	 */
379*d1b2b5caSJohn Marino 	switch (cert_usage) {
380*d1b2b5caSJohn Marino 
381*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_CA_CONSTRAINT:
382*d1b2b5caSJohn Marino 
383*d1b2b5caSJohn Marino 		s = ldns_dane_pkix_validate_and_get_chain(
384*d1b2b5caSJohn Marino 				&pkix_validation_chain,
385*d1b2b5caSJohn Marino 				cert, extra_certs,
386*d1b2b5caSJohn Marino 				pkix_validation_store);
387*d1b2b5caSJohn Marino 		if (! pkix_validation_chain) {
388*d1b2b5caSJohn Marino 			return s;
389*d1b2b5caSJohn Marino 		}
390*d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_OK) {
391*d1b2b5caSJohn Marino 			if (offset == -1) {
392*d1b2b5caSJohn Marino 				offset = 0;
393*d1b2b5caSJohn Marino 			}
394*d1b2b5caSJohn Marino 			s = ldns_dane_get_nth_cert_from_validation_chain(
395*d1b2b5caSJohn Marino 					selected_cert, pkix_validation_chain,
396*d1b2b5caSJohn Marino 					offset, true);
397*d1b2b5caSJohn Marino 		}
398*d1b2b5caSJohn Marino 		sk_X509_pop_free(pkix_validation_chain, X509_free);
399*d1b2b5caSJohn Marino 		return s;
400*d1b2b5caSJohn Marino 		break;
401*d1b2b5caSJohn Marino 
402*d1b2b5caSJohn Marino 
403*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
404*d1b2b5caSJohn Marino 
405*d1b2b5caSJohn Marino 		*selected_cert = cert;
406*d1b2b5caSJohn Marino 		return ldns_dane_pkix_validate(cert, extra_certs,
407*d1b2b5caSJohn Marino 				pkix_validation_store);
408*d1b2b5caSJohn Marino 		break;
409*d1b2b5caSJohn Marino 
410*d1b2b5caSJohn Marino 
411*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
412*d1b2b5caSJohn Marino 
413*d1b2b5caSJohn Marino 		if (offset == -1) {
414*d1b2b5caSJohn Marino 			s = ldns_dane_pkix_get_last_self_signed(
415*d1b2b5caSJohn Marino 					selected_cert, cert, extra_certs);
416*d1b2b5caSJohn Marino 			return s;
417*d1b2b5caSJohn Marino 		} else {
418*d1b2b5caSJohn Marino 			s = ldns_dane_pkix_get_chain(
419*d1b2b5caSJohn Marino 					&pkix_validation_chain,
420*d1b2b5caSJohn Marino 					cert, extra_certs);
421*d1b2b5caSJohn Marino 			if (s == LDNS_STATUS_OK) {
422*d1b2b5caSJohn Marino 				s =
423*d1b2b5caSJohn Marino 				ldns_dane_get_nth_cert_from_validation_chain(
424*d1b2b5caSJohn Marino 					selected_cert, pkix_validation_chain,
425*d1b2b5caSJohn Marino 					offset, false);
426*d1b2b5caSJohn Marino 			} else if (! pkix_validation_chain) {
427*d1b2b5caSJohn Marino 				return s;
428*d1b2b5caSJohn Marino 			}
429*d1b2b5caSJohn Marino 			sk_X509_pop_free(pkix_validation_chain, X509_free);
430*d1b2b5caSJohn Marino 			return s;
431*d1b2b5caSJohn Marino 		}
432*d1b2b5caSJohn Marino 		break;
433*d1b2b5caSJohn Marino 
434*d1b2b5caSJohn Marino 
435*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
436*d1b2b5caSJohn Marino 
437*d1b2b5caSJohn Marino 		*selected_cert = cert;
438*d1b2b5caSJohn Marino 		return LDNS_STATUS_OK;
439*d1b2b5caSJohn Marino 		break;
440*d1b2b5caSJohn Marino 
441*d1b2b5caSJohn Marino 	default:
442*d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE;
443*d1b2b5caSJohn Marino 		break;
444*d1b2b5caSJohn Marino 	}
445*d1b2b5caSJohn Marino }
446*d1b2b5caSJohn Marino 
447*d1b2b5caSJohn Marino 
448*d1b2b5caSJohn Marino ldns_status
449*d1b2b5caSJohn Marino ldns_dane_create_tlsa_rr(ldns_rr** tlsa,
450*d1b2b5caSJohn Marino 		ldns_tlsa_certificate_usage certificate_usage,
451*d1b2b5caSJohn Marino 		ldns_tlsa_selector          selector,
452*d1b2b5caSJohn Marino 		ldns_tlsa_matching_type     matching_type,
453*d1b2b5caSJohn Marino 		X509* cert)
454*d1b2b5caSJohn Marino {
455*d1b2b5caSJohn Marino 	ldns_rdf* rdf;
456*d1b2b5caSJohn Marino 	ldns_status s;
457*d1b2b5caSJohn Marino 
458*d1b2b5caSJohn Marino 	assert(tlsa != NULL);
459*d1b2b5caSJohn Marino 	assert(cert != NULL);
460*d1b2b5caSJohn Marino 
461*d1b2b5caSJohn Marino 	/* create rr */
462*d1b2b5caSJohn Marino 	*tlsa = ldns_rr_new_frm_type(LDNS_RR_TYPE_TLSA);
463*d1b2b5caSJohn Marino 	if (*tlsa == NULL) {
464*d1b2b5caSJohn Marino 		return LDNS_STATUS_MEM_ERR;
465*d1b2b5caSJohn Marino 	}
466*d1b2b5caSJohn Marino 
467*d1b2b5caSJohn Marino 	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
468*d1b2b5caSJohn Marino 			(uint8_t)certificate_usage);
469*d1b2b5caSJohn Marino 	if (rdf == NULL) {
470*d1b2b5caSJohn Marino 		goto memerror;
471*d1b2b5caSJohn Marino 	}
472*d1b2b5caSJohn Marino 	(void) ldns_rr_set_rdf(*tlsa, rdf, 0);
473*d1b2b5caSJohn Marino 
474*d1b2b5caSJohn Marino 	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)selector);
475*d1b2b5caSJohn Marino 	if (rdf == NULL) {
476*d1b2b5caSJohn Marino 		goto memerror;
477*d1b2b5caSJohn Marino 	}
478*d1b2b5caSJohn Marino 	(void) ldns_rr_set_rdf(*tlsa, rdf, 1);
479*d1b2b5caSJohn Marino 
480*d1b2b5caSJohn Marino 	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)matching_type);
481*d1b2b5caSJohn Marino 	if (rdf == NULL) {
482*d1b2b5caSJohn Marino 		goto memerror;
483*d1b2b5caSJohn Marino 	}
484*d1b2b5caSJohn Marino 	(void) ldns_rr_set_rdf(*tlsa, rdf, 2);
485*d1b2b5caSJohn Marino 
486*d1b2b5caSJohn Marino 	s = ldns_dane_cert2rdf(&rdf, cert, selector, matching_type);
487*d1b2b5caSJohn Marino 	if (s == LDNS_STATUS_OK) {
488*d1b2b5caSJohn Marino 		(void) ldns_rr_set_rdf(*tlsa, rdf, 3);
489*d1b2b5caSJohn Marino 		return LDNS_STATUS_OK;
490*d1b2b5caSJohn Marino 	}
491*d1b2b5caSJohn Marino 	ldns_rr_free(*tlsa);
492*d1b2b5caSJohn Marino 	*tlsa = NULL;
493*d1b2b5caSJohn Marino 	return s;
494*d1b2b5caSJohn Marino 
495*d1b2b5caSJohn Marino memerror:
496*d1b2b5caSJohn Marino 	ldns_rr_free(*tlsa);
497*d1b2b5caSJohn Marino 	*tlsa = NULL;
498*d1b2b5caSJohn Marino 	return LDNS_STATUS_MEM_ERR;
499*d1b2b5caSJohn Marino }
500*d1b2b5caSJohn Marino 
501*d1b2b5caSJohn Marino 
502*d1b2b5caSJohn Marino /* Return tlsas that actually are TLSA resource records with known values
503*d1b2b5caSJohn Marino  * for the Certificate usage, Selector and Matching type rdata fields.
504*d1b2b5caSJohn Marino  */
505*d1b2b5caSJohn Marino static ldns_rr_list*
506*d1b2b5caSJohn Marino ldns_dane_filter_unusable_records(const ldns_rr_list* tlsas)
507*d1b2b5caSJohn Marino {
508*d1b2b5caSJohn Marino 	size_t i;
509*d1b2b5caSJohn Marino 	ldns_rr_list* r = ldns_rr_list_new();
510*d1b2b5caSJohn Marino 	ldns_rr* tlsa_rr;
511*d1b2b5caSJohn Marino 
512*d1b2b5caSJohn Marino 	if (! r) {
513*d1b2b5caSJohn Marino 		return NULL;
514*d1b2b5caSJohn Marino 	}
515*d1b2b5caSJohn Marino 	for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) {
516*d1b2b5caSJohn Marino 		tlsa_rr = ldns_rr_list_rr(tlsas, i);
517*d1b2b5caSJohn Marino 		if (ldns_rr_get_type(tlsa_rr) == LDNS_RR_TYPE_TLSA &&
518*d1b2b5caSJohn Marino 		    ldns_rr_rd_count(tlsa_rr) == 4 &&
519*d1b2b5caSJohn Marino 		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)) <= 3 &&
520*d1b2b5caSJohn Marino 		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)) <= 1 &&
521*d1b2b5caSJohn Marino 		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)) <= 2) {
522*d1b2b5caSJohn Marino 
523*d1b2b5caSJohn Marino 			if (! ldns_rr_list_push_rr(r, tlsa_rr)) {
524*d1b2b5caSJohn Marino 				ldns_rr_list_free(r);
525*d1b2b5caSJohn Marino 				return NULL;
526*d1b2b5caSJohn Marino 			}
527*d1b2b5caSJohn Marino 		}
528*d1b2b5caSJohn Marino 	}
529*d1b2b5caSJohn Marino 	return r;
530*d1b2b5caSJohn Marino }
531*d1b2b5caSJohn Marino 
532*d1b2b5caSJohn Marino 
533*d1b2b5caSJohn Marino /* Return whether cert/selector/matching_type matches data.
534*d1b2b5caSJohn Marino  */
535*d1b2b5caSJohn Marino static ldns_status
536*d1b2b5caSJohn Marino ldns_dane_match_cert_with_data(X509* cert, ldns_tlsa_selector selector,
537*d1b2b5caSJohn Marino 		ldns_tlsa_matching_type matching_type, ldns_rdf* data)
538*d1b2b5caSJohn Marino {
539*d1b2b5caSJohn Marino 	ldns_status s;
540*d1b2b5caSJohn Marino 	ldns_rdf* match_data;
541*d1b2b5caSJohn Marino 
542*d1b2b5caSJohn Marino 	s = ldns_dane_cert2rdf(&match_data, cert, selector, matching_type);
543*d1b2b5caSJohn Marino 	if (s == LDNS_STATUS_OK) {
544*d1b2b5caSJohn Marino 		if (ldns_rdf_compare(data, match_data) != 0) {
545*d1b2b5caSJohn Marino 			s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
546*d1b2b5caSJohn Marino 		}
547*d1b2b5caSJohn Marino 		ldns_rdf_free(match_data);
548*d1b2b5caSJohn Marino 	}
549*d1b2b5caSJohn Marino 	return s;
550*d1b2b5caSJohn Marino }
551*d1b2b5caSJohn Marino 
552*d1b2b5caSJohn Marino 
553*d1b2b5caSJohn Marino /* Return whether any certificate from the chain with selector/matching_type
554*d1b2b5caSJohn Marino  * matches data.
555*d1b2b5caSJohn Marino  * ca should be true if the certificate has to be a CA certificate too.
556*d1b2b5caSJohn Marino  */
557*d1b2b5caSJohn Marino static ldns_status
558*d1b2b5caSJohn Marino ldns_dane_match_any_cert_with_data(STACK_OF(X509)* chain,
559*d1b2b5caSJohn Marino 		ldns_tlsa_selector      selector,
560*d1b2b5caSJohn Marino 		ldns_tlsa_matching_type matching_type,
561*d1b2b5caSJohn Marino 		ldns_rdf* data, bool ca)
562*d1b2b5caSJohn Marino {
563*d1b2b5caSJohn Marino 	ldns_status s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
564*d1b2b5caSJohn Marino 	size_t n, i;
565*d1b2b5caSJohn Marino 	X509* cert;
566*d1b2b5caSJohn Marino 
567*d1b2b5caSJohn Marino 	n = (size_t)sk_X509_num(chain);
568*d1b2b5caSJohn Marino 	for (i = 0; i < n; i++) {
569*d1b2b5caSJohn Marino 		cert = sk_X509_pop(chain);
570*d1b2b5caSJohn Marino 		if (! cert) {
571*d1b2b5caSJohn Marino 			s = LDNS_STATUS_SSL_ERR;
572*d1b2b5caSJohn Marino 			break;
573*d1b2b5caSJohn Marino 		}
574*d1b2b5caSJohn Marino 		s = ldns_dane_match_cert_with_data(cert,
575*d1b2b5caSJohn Marino 				selector, matching_type, data);
576*d1b2b5caSJohn Marino 		if (ca && s == LDNS_STATUS_OK && ! X509_check_ca(cert)) {
577*d1b2b5caSJohn Marino 			s = LDNS_STATUS_DANE_NON_CA_CERTIFICATE;
578*d1b2b5caSJohn Marino 		}
579*d1b2b5caSJohn Marino 		X509_free(cert);
580*d1b2b5caSJohn Marino 		if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH) {
581*d1b2b5caSJohn Marino 			break;
582*d1b2b5caSJohn Marino 		}
583*d1b2b5caSJohn Marino 		/* when s == LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH,
584*d1b2b5caSJohn Marino 		 * try to match the next certificate
585*d1b2b5caSJohn Marino 		 */
586*d1b2b5caSJohn Marino 	}
587*d1b2b5caSJohn Marino 	return s;
588*d1b2b5caSJohn Marino }
589*d1b2b5caSJohn Marino 
590*d1b2b5caSJohn Marino 
591*d1b2b5caSJohn Marino ldns_status
592*d1b2b5caSJohn Marino ldns_dane_verify_rr(const ldns_rr* tlsa_rr,
593*d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs,
594*d1b2b5caSJohn Marino 		X509_STORE* pkix_validation_store)
595*d1b2b5caSJohn Marino {
596*d1b2b5caSJohn Marino 	ldns_status s;
597*d1b2b5caSJohn Marino 
598*d1b2b5caSJohn Marino 	STACK_OF(X509)* pkix_validation_chain = NULL;
599*d1b2b5caSJohn Marino 
600*d1b2b5caSJohn Marino 	ldns_tlsa_certificate_usage cert_usage;
601*d1b2b5caSJohn Marino 	ldns_tlsa_selector          selector;
602*d1b2b5caSJohn Marino 	ldns_tlsa_matching_type     matching_type;
603*d1b2b5caSJohn Marino 	ldns_rdf*                   data;
604*d1b2b5caSJohn Marino 
605*d1b2b5caSJohn Marino 	if (! tlsa_rr) {
606*d1b2b5caSJohn Marino 		/* No TLSA, so regular PKIX validation
607*d1b2b5caSJohn Marino 		 */
608*d1b2b5caSJohn Marino 		return ldns_dane_pkix_validate(cert, extra_certs,
609*d1b2b5caSJohn Marino 				pkix_validation_store);
610*d1b2b5caSJohn Marino 	}
611*d1b2b5caSJohn Marino 	cert_usage    = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0));
612*d1b2b5caSJohn Marino 	selector      = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1));
613*d1b2b5caSJohn Marino 	matching_type = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2));
614*d1b2b5caSJohn Marino 	data          =                      ldns_rr_rdf(tlsa_rr, 3) ;
615*d1b2b5caSJohn Marino 
616*d1b2b5caSJohn Marino 	switch (cert_usage) {
617*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_CA_CONSTRAINT:
618*d1b2b5caSJohn Marino 		s = ldns_dane_pkix_validate_and_get_chain(
619*d1b2b5caSJohn Marino 				&pkix_validation_chain,
620*d1b2b5caSJohn Marino 				cert, extra_certs,
621*d1b2b5caSJohn Marino 				pkix_validation_store);
622*d1b2b5caSJohn Marino 		if (! pkix_validation_chain) {
623*d1b2b5caSJohn Marino 			return s;
624*d1b2b5caSJohn Marino 		}
625*d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) {
626*d1b2b5caSJohn Marino 			/*
627*d1b2b5caSJohn Marino 			 * NO PKIX validation. We still try to match *any*
628*d1b2b5caSJohn Marino 			 * certificate from the chain, so we return
629*d1b2b5caSJohn Marino 			 * TLSA errors over PKIX errors.
630*d1b2b5caSJohn Marino 			 *
631*d1b2b5caSJohn Marino 			 * i.e. When the TLSA matches no certificate, we return
632*d1b2b5caSJohn Marino 			 * TLSA_DID_NOT_MATCH and not PKIX_DID_NOT_VALIDATE
633*d1b2b5caSJohn Marino 			 */
634*d1b2b5caSJohn Marino 			s = ldns_dane_match_any_cert_with_data(
635*d1b2b5caSJohn Marino 					pkix_validation_chain,
636*d1b2b5caSJohn Marino 					selector, matching_type, data, true);
637*d1b2b5caSJohn Marino 
638*d1b2b5caSJohn Marino 			if (s == LDNS_STATUS_OK) {
639*d1b2b5caSJohn Marino 				/* A TLSA record did match a cert from the
640*d1b2b5caSJohn Marino 				 * chain, thus the error is failed PKIX
641*d1b2b5caSJohn Marino 				 * validation.
642*d1b2b5caSJohn Marino 				 */
643*d1b2b5caSJohn Marino 				s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
644*d1b2b5caSJohn Marino 			}
645*d1b2b5caSJohn Marino 
646*d1b2b5caSJohn Marino 		} else if (s == LDNS_STATUS_OK) {
647*d1b2b5caSJohn Marino 			/* PKIX validated, does the TLSA match too? */
648*d1b2b5caSJohn Marino 
649*d1b2b5caSJohn Marino 			s = ldns_dane_match_any_cert_with_data(
650*d1b2b5caSJohn Marino 					pkix_validation_chain,
651*d1b2b5caSJohn Marino 					selector, matching_type, data, true);
652*d1b2b5caSJohn Marino 		}
653*d1b2b5caSJohn Marino 		sk_X509_pop_free(pkix_validation_chain, X509_free);
654*d1b2b5caSJohn Marino 		return s;
655*d1b2b5caSJohn Marino 		break;
656*d1b2b5caSJohn Marino 
657*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
658*d1b2b5caSJohn Marino 		s = ldns_dane_match_cert_with_data(cert,
659*d1b2b5caSJohn Marino 				selector, matching_type, data);
660*d1b2b5caSJohn Marino 
661*d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_OK) {
662*d1b2b5caSJohn Marino 			return ldns_dane_pkix_validate(cert, extra_certs,
663*d1b2b5caSJohn Marino 					pkix_validation_store);
664*d1b2b5caSJohn Marino 		}
665*d1b2b5caSJohn Marino 		return s;
666*d1b2b5caSJohn Marino 		break;
667*d1b2b5caSJohn Marino 
668*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
669*d1b2b5caSJohn Marino 		s = ldns_dane_pkix_get_chain(&pkix_validation_chain,
670*d1b2b5caSJohn Marino 				cert, extra_certs);
671*d1b2b5caSJohn Marino 
672*d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_OK) {
673*d1b2b5caSJohn Marino 			s = ldns_dane_match_any_cert_with_data(
674*d1b2b5caSJohn Marino 					pkix_validation_chain,
675*d1b2b5caSJohn Marino 					selector, matching_type, data, false);
676*d1b2b5caSJohn Marino 
677*d1b2b5caSJohn Marino 		} else if (! pkix_validation_chain) {
678*d1b2b5caSJohn Marino 			return s;
679*d1b2b5caSJohn Marino 		}
680*d1b2b5caSJohn Marino 		sk_X509_pop_free(pkix_validation_chain, X509_free);
681*d1b2b5caSJohn Marino 		return s;
682*d1b2b5caSJohn Marino 		break;
683*d1b2b5caSJohn Marino 
684*d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
685*d1b2b5caSJohn Marino 		return ldns_dane_match_cert_with_data(cert,
686*d1b2b5caSJohn Marino 				selector, matching_type, data);
687*d1b2b5caSJohn Marino 		break;
688*d1b2b5caSJohn Marino 
689*d1b2b5caSJohn Marino 	default:
690*d1b2b5caSJohn Marino 		break;
691*d1b2b5caSJohn Marino 	}
692*d1b2b5caSJohn Marino 	return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE;
693*d1b2b5caSJohn Marino }
694*d1b2b5caSJohn Marino 
695*d1b2b5caSJohn Marino 
696*d1b2b5caSJohn Marino ldns_status
697*d1b2b5caSJohn Marino ldns_dane_verify(ldns_rr_list* tlsas,
698*d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs,
699*d1b2b5caSJohn Marino 		X509_STORE* pkix_validation_store)
700*d1b2b5caSJohn Marino {
701*d1b2b5caSJohn Marino 	size_t i;
702*d1b2b5caSJohn Marino 	ldns_rr* tlsa_rr;
703*d1b2b5caSJohn Marino 	ldns_status s = LDNS_STATUS_OK, ps;
704*d1b2b5caSJohn Marino 
705*d1b2b5caSJohn Marino 	assert(cert != NULL);
706*d1b2b5caSJohn Marino 
707*d1b2b5caSJohn Marino 	if (tlsas && ldns_rr_list_rr_count(tlsas) > 0) {
708*d1b2b5caSJohn Marino 		tlsas = ldns_dane_filter_unusable_records(tlsas);
709*d1b2b5caSJohn Marino 		if (! tlsas) {
710*d1b2b5caSJohn Marino 			return LDNS_STATUS_MEM_ERR;
711*d1b2b5caSJohn Marino 		}
712*d1b2b5caSJohn Marino 	}
713*d1b2b5caSJohn Marino 	if (! tlsas || ldns_rr_list_rr_count(tlsas) == 0) {
714*d1b2b5caSJohn Marino 		/* No TLSA's, so regular PKIX validation
715*d1b2b5caSJohn Marino 		 */
716*d1b2b5caSJohn Marino 		return ldns_dane_pkix_validate(cert, extra_certs,
717*d1b2b5caSJohn Marino 				pkix_validation_store);
718*d1b2b5caSJohn Marino 	} else {
719*d1b2b5caSJohn Marino 		for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) {
720*d1b2b5caSJohn Marino 			tlsa_rr = ldns_rr_list_rr(tlsas, i);
721*d1b2b5caSJohn Marino 			ps = s;
722*d1b2b5caSJohn Marino 			s = ldns_dane_verify_rr(tlsa_rr, cert, extra_certs,
723*d1b2b5caSJohn Marino 					pkix_validation_store);
724*d1b2b5caSJohn Marino 
725*d1b2b5caSJohn Marino 			if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH &&
726*d1b2b5caSJohn Marino 			    s != LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) {
727*d1b2b5caSJohn Marino 
728*d1b2b5caSJohn Marino 				/* which would be LDNS_STATUS_OK (match)
729*d1b2b5caSJohn Marino 				 * or some fatal error preventing use from
730*d1b2b5caSJohn Marino 				 * trying the next TLSA record.
731*d1b2b5caSJohn Marino 				 */
732*d1b2b5caSJohn Marino 				break;
733*d1b2b5caSJohn Marino 			}
734*d1b2b5caSJohn Marino 			s = (s > ps ? s : ps); /* prefer PKIX_DID_NOT_VALIDATE
735*d1b2b5caSJohn Marino 						* over   TLSA_DID_NOT_MATCH
736*d1b2b5caSJohn Marino 						*/
737*d1b2b5caSJohn Marino 		}
738*d1b2b5caSJohn Marino 		ldns_rr_list_free(tlsas);
739*d1b2b5caSJohn Marino 	}
740*d1b2b5caSJohn Marino 	return s;
741*d1b2b5caSJohn Marino }
742*d1b2b5caSJohn Marino #endif /* HAVE_SSL */
743