dane.c revision 246828
1246828Sdes/*
2246828Sdes * Verify or create TLS authentication with DANE (RFC6698)
3246828Sdes *
4246828Sdes * (c) NLnetLabs 2012
5246828Sdes *
6246828Sdes * See the file LICENSE for the license.
7246828Sdes *
8246828Sdes */
9246828Sdes
10246828Sdes#include <ldns/config.h>
11246828Sdes
12246828Sdes#include <ldns/ldns.h>
13246828Sdes#include <ldns/dane.h>
14246828Sdes
15246828Sdes#include <unistd.h>
16246828Sdes#include <stdlib.h>
17246828Sdes#include <sys/types.h>
18246828Sdes#include <sys/socket.h>
19246828Sdes#include <netdb.h>
20246828Sdes
21246828Sdes#ifdef HAVE_SSL
22246828Sdes#include <openssl/ssl.h>
23246828Sdes#include <openssl/err.h>
24246828Sdes#include <openssl/x509v3.h>
25246828Sdes#endif
26246828Sdes
27246828Sdesldns_status
28246828Sdesldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name,
29246828Sdes		uint16_t port, ldns_dane_transport transport)
30246828Sdes{
31246828Sdes	char buf[LDNS_MAX_DOMAINLEN];
32246828Sdes	size_t s;
33246828Sdes
34246828Sdes	assert(tlsa_owner != NULL);
35246828Sdes	assert(name != NULL);
36246828Sdes	assert(ldns_rdf_get_type(name) == LDNS_RDF_TYPE_DNAME);
37246828Sdes
38246828Sdes	s = (size_t)snprintf(buf, LDNS_MAX_DOMAINLEN, "X_%d", (int)port);
39246828Sdes	buf[0] = (char)(s - 1);
40246828Sdes
41246828Sdes	switch(transport) {
42246828Sdes	case LDNS_DANE_TRANSPORT_TCP:
43246828Sdes		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_tcp");
44246828Sdes		break;
45246828Sdes
46246828Sdes	case LDNS_DANE_TRANSPORT_UDP:
47246828Sdes		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_udp");
48246828Sdes		break;
49246828Sdes
50246828Sdes	case LDNS_DANE_TRANSPORT_SCTP:
51246828Sdes		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\005_sctp");
52246828Sdes		break;
53246828Sdes
54246828Sdes	default:
55246828Sdes		return LDNS_STATUS_DANE_UNKNOWN_TRANSPORT;
56246828Sdes	}
57246828Sdes	if (s + ldns_rdf_size(name) > LDNS_MAX_DOMAINLEN) {
58246828Sdes		return LDNS_STATUS_DOMAINNAME_OVERFLOW;
59246828Sdes	}
60246828Sdes	memcpy(buf + s, ldns_rdf_data(name), ldns_rdf_size(name));
61246828Sdes	*tlsa_owner = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
62246828Sdes			s + ldns_rdf_size(name), buf);
63246828Sdes	if (*tlsa_owner == NULL) {
64246828Sdes		return LDNS_STATUS_MEM_ERR;
65246828Sdes	}
66246828Sdes	return LDNS_STATUS_OK;
67246828Sdes}
68246828Sdes
69246828Sdes
70246828Sdes#ifdef HAVE_SSL
71246828Sdesldns_status
72246828Sdesldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert,
73246828Sdes		ldns_tlsa_selector      selector,
74246828Sdes		ldns_tlsa_matching_type matching_type)
75246828Sdes{
76246828Sdes	unsigned char* buf = NULL;
77246828Sdes	size_t len;
78246828Sdes
79246828Sdes	X509_PUBKEY* xpubkey;
80246828Sdes	EVP_PKEY* epubkey;
81246828Sdes
82246828Sdes	unsigned char* digest;
83246828Sdes
84246828Sdes	assert(rdf != NULL);
85246828Sdes	assert(cert != NULL);
86246828Sdes
87246828Sdes	switch(selector) {
88246828Sdes	case LDNS_TLSA_SELECTOR_FULL_CERTIFICATE:
89246828Sdes
90246828Sdes		len = (size_t)i2d_X509(cert, &buf);
91246828Sdes		break;
92246828Sdes
93246828Sdes	case LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
94246828Sdes
95246828Sdes#ifndef S_SPLINT_S
96246828Sdes		xpubkey = X509_get_X509_PUBKEY(cert);
97246828Sdes#endif
98246828Sdes		if (! xpubkey) {
99246828Sdes			return LDNS_STATUS_SSL_ERR;
100246828Sdes		}
101246828Sdes		epubkey = X509_PUBKEY_get(xpubkey);
102246828Sdes		if (! epubkey) {
103246828Sdes			return LDNS_STATUS_SSL_ERR;
104246828Sdes		}
105246828Sdes		len = (size_t)i2d_PUBKEY(epubkey, &buf);
106246828Sdes		break;
107246828Sdes
108246828Sdes	default:
109246828Sdes		return LDNS_STATUS_DANE_UNKNOWN_SELECTOR;
110246828Sdes	}
111246828Sdes
112246828Sdes	switch(matching_type) {
113246828Sdes	case LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
114246828Sdes
115246828Sdes		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, len, buf);
116246828Sdes
117246828Sdes		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
118246828Sdes		break;
119246828Sdes
120246828Sdes	case LDNS_TLSA_MATCHING_TYPE_SHA256:
121246828Sdes
122246828Sdes		digest = LDNS_XMALLOC(unsigned char, SHA256_DIGEST_LENGTH);
123246828Sdes		if (digest == NULL) {
124246828Sdes			LDNS_FREE(buf);
125246828Sdes			return LDNS_STATUS_MEM_ERR;
126246828Sdes		}
127246828Sdes		(void) ldns_sha256(buf, (unsigned int)len, digest);
128246828Sdes		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, SHA256_DIGEST_LENGTH,
129246828Sdes				digest);
130246828Sdes		LDNS_FREE(buf);
131246828Sdes
132246828Sdes		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
133246828Sdes		break;
134246828Sdes
135246828Sdes	case LDNS_TLSA_MATCHING_TYPE_SHA512:
136246828Sdes
137246828Sdes		digest = LDNS_XMALLOC(unsigned char, SHA512_DIGEST_LENGTH);
138246828Sdes		if (digest == NULL) {
139246828Sdes			LDNS_FREE(buf);
140246828Sdes			return LDNS_STATUS_MEM_ERR;
141246828Sdes		}
142246828Sdes		(void) ldns_sha512(buf, (unsigned int)len, digest);
143246828Sdes		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, SHA512_DIGEST_LENGTH,
144246828Sdes				digest);
145246828Sdes		LDNS_FREE(buf);
146246828Sdes
147246828Sdes		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
148246828Sdes		break;
149246828Sdes
150246828Sdes	default:
151246828Sdes		LDNS_FREE(buf);
152246828Sdes		return LDNS_STATUS_DANE_UNKNOWN_MATCHING_TYPE;
153246828Sdes	}
154246828Sdes}
155246828Sdes
156246828Sdes
157246828Sdes/* Ordinary PKIX validation of cert (with extra_certs to help)
158246828Sdes * against the CA's in store
159246828Sdes */
160246828Sdesstatic ldns_status
161246828Sdesldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs,
162246828Sdes		X509_STORE* store)
163246828Sdes{
164246828Sdes	X509_STORE_CTX* vrfy_ctx;
165246828Sdes	ldns_status s;
166246828Sdes
167246828Sdes	if (! store) {
168246828Sdes		return LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
169246828Sdes	}
170246828Sdes	vrfy_ctx = X509_STORE_CTX_new();
171246828Sdes	if (! vrfy_ctx) {
172246828Sdes
173246828Sdes		return LDNS_STATUS_SSL_ERR;
174246828Sdes
175246828Sdes	} else if (X509_STORE_CTX_init(vrfy_ctx, store,
176246828Sdes				cert, extra_certs) != 1) {
177246828Sdes		s = LDNS_STATUS_SSL_ERR;
178246828Sdes
179246828Sdes	} else if (X509_verify_cert(vrfy_ctx) == 1) {
180246828Sdes
181246828Sdes		s = LDNS_STATUS_OK;
182246828Sdes
183246828Sdes	} else {
184246828Sdes		s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
185246828Sdes	}
186246828Sdes	X509_STORE_CTX_free(vrfy_ctx);
187246828Sdes	return s;
188246828Sdes}
189246828Sdes
190246828Sdes
191246828Sdes/* Orinary PKIX validation of cert (with extra_certs to help)
192246828Sdes * against the CA's in store, but also return the validation chain.
193246828Sdes */
194246828Sdesstatic ldns_status
195246828Sdesldns_dane_pkix_validate_and_get_chain(STACK_OF(X509)** chain, X509* cert,
196246828Sdes		STACK_OF(X509)* extra_certs, X509_STORE* store)
197246828Sdes{
198246828Sdes	ldns_status s;
199246828Sdes	X509_STORE* empty_store = NULL;
200246828Sdes	X509_STORE_CTX* vrfy_ctx;
201246828Sdes
202246828Sdes	assert(chain != NULL);
203246828Sdes
204246828Sdes	if (! store) {
205246828Sdes		store = empty_store = X509_STORE_new();
206246828Sdes	}
207246828Sdes	s = LDNS_STATUS_SSL_ERR;
208246828Sdes	vrfy_ctx = X509_STORE_CTX_new();
209246828Sdes	if (! vrfy_ctx) {
210246828Sdes
211246828Sdes		goto exit_free_empty_store;
212246828Sdes
213246828Sdes	} else if (X509_STORE_CTX_init(vrfy_ctx, store,
214246828Sdes					cert, extra_certs) != 1) {
215246828Sdes		goto exit_free_vrfy_ctx;
216246828Sdes
217246828Sdes	} else if (X509_verify_cert(vrfy_ctx) == 1) {
218246828Sdes
219246828Sdes		s = LDNS_STATUS_OK;
220246828Sdes
221246828Sdes	} else {
222246828Sdes		s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
223246828Sdes	}
224246828Sdes	*chain = X509_STORE_CTX_get1_chain(vrfy_ctx);
225246828Sdes	if (! *chain) {
226246828Sdes		s = LDNS_STATUS_SSL_ERR;
227246828Sdes	}
228246828Sdes
229246828Sdesexit_free_vrfy_ctx:
230246828Sdes	X509_STORE_CTX_free(vrfy_ctx);
231246828Sdes
232246828Sdesexit_free_empty_store:
233246828Sdes	if (empty_store) {
234246828Sdes		X509_STORE_free(empty_store);
235246828Sdes	}
236246828Sdes	return s;
237246828Sdes}
238246828Sdes
239246828Sdes
240246828Sdes/* Return the validation chain that can be build out of cert, with extra_certs.
241246828Sdes */
242246828Sdesstatic ldns_status
243246828Sdesldns_dane_pkix_get_chain(STACK_OF(X509)** chain,
244246828Sdes		X509* cert, STACK_OF(X509)* extra_certs)
245246828Sdes{
246246828Sdes	ldns_status s;
247246828Sdes	X509_STORE* empty_store = NULL;
248246828Sdes	X509_STORE_CTX* vrfy_ctx;
249246828Sdes
250246828Sdes	assert(chain != NULL);
251246828Sdes
252246828Sdes	empty_store = X509_STORE_new();
253246828Sdes	s = LDNS_STATUS_SSL_ERR;
254246828Sdes	vrfy_ctx = X509_STORE_CTX_new();
255246828Sdes	if (! vrfy_ctx) {
256246828Sdes
257246828Sdes		goto exit_free_empty_store;
258246828Sdes
259246828Sdes	} else if (X509_STORE_CTX_init(vrfy_ctx, empty_store,
260246828Sdes					cert, extra_certs) != 1) {
261246828Sdes		goto exit_free_vrfy_ctx;
262246828Sdes	}
263246828Sdes	(void) X509_verify_cert(vrfy_ctx);
264246828Sdes	*chain = X509_STORE_CTX_get1_chain(vrfy_ctx);
265246828Sdes	if (! *chain) {
266246828Sdes		s = LDNS_STATUS_SSL_ERR;
267246828Sdes	} else {
268246828Sdes		s = LDNS_STATUS_OK;
269246828Sdes	}
270246828Sdesexit_free_vrfy_ctx:
271246828Sdes	X509_STORE_CTX_free(vrfy_ctx);
272246828Sdes
273246828Sdesexit_free_empty_store:
274246828Sdes	X509_STORE_free(empty_store);
275246828Sdes	return s;
276246828Sdes}
277246828Sdes
278246828Sdes
279246828Sdes/* Pop n+1 certs and return the last popped.
280246828Sdes */
281246828Sdesstatic ldns_status
282246828Sdesldns_dane_get_nth_cert_from_validation_chain(
283246828Sdes		X509** cert, STACK_OF(X509)* chain, int n, bool ca)
284246828Sdes{
285246828Sdes	if (n >= sk_X509_num(chain) || n < 0) {
286246828Sdes		return LDNS_STATUS_DANE_OFFSET_OUT_OF_RANGE;
287246828Sdes	}
288246828Sdes	*cert = sk_X509_pop(chain);
289246828Sdes	while (n-- > 0) {
290246828Sdes		X509_free(*cert);
291246828Sdes		*cert = sk_X509_pop(chain);
292246828Sdes	}
293246828Sdes	if (ca && ! X509_check_ca(*cert)) {
294246828Sdes		return LDNS_STATUS_DANE_NON_CA_CERTIFICATE;
295246828Sdes	}
296246828Sdes	return LDNS_STATUS_OK;
297246828Sdes}
298246828Sdes
299246828Sdes
300246828Sdes/* Create validation chain with cert and extra_certs and returns the last
301246828Sdes * self-signed (if present).
302246828Sdes */
303246828Sdesstatic ldns_status
304246828Sdesldns_dane_pkix_get_last_self_signed(X509** out_cert,
305246828Sdes		X509* cert, STACK_OF(X509)* extra_certs)
306246828Sdes{
307246828Sdes	ldns_status s;
308246828Sdes	X509_STORE* empty_store = NULL;
309246828Sdes	X509_STORE_CTX* vrfy_ctx;
310246828Sdes
311246828Sdes	assert(out_cert != NULL);
312246828Sdes
313246828Sdes	empty_store = X509_STORE_new();
314246828Sdes	s = LDNS_STATUS_SSL_ERR;
315246828Sdes	vrfy_ctx = X509_STORE_CTX_new();
316246828Sdes	if (! vrfy_ctx) {
317246828Sdes		goto exit_free_empty_store;
318246828Sdes
319246828Sdes	} else if (X509_STORE_CTX_init(vrfy_ctx, empty_store,
320246828Sdes					cert, extra_certs) != 1) {
321246828Sdes		goto exit_free_vrfy_ctx;
322246828Sdes
323246828Sdes	}
324246828Sdes	(void) X509_verify_cert(vrfy_ctx);
325246828Sdes	if (vrfy_ctx->error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
326246828Sdes	    vrfy_ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT){
327246828Sdes
328246828Sdes		*out_cert = X509_STORE_CTX_get_current_cert( vrfy_ctx);
329246828Sdes		s = LDNS_STATUS_OK;
330246828Sdes	} else {
331246828Sdes		s = LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR;
332246828Sdes	}
333246828Sdesexit_free_vrfy_ctx:
334246828Sdes	X509_STORE_CTX_free(vrfy_ctx);
335246828Sdes
336246828Sdesexit_free_empty_store:
337246828Sdes	X509_STORE_free(empty_store);
338246828Sdes	return s;
339246828Sdes}
340246828Sdes
341246828Sdes
342246828Sdesldns_status
343246828Sdesldns_dane_select_certificate(X509** selected_cert,
344246828Sdes		X509* cert, STACK_OF(X509)* extra_certs,
345246828Sdes		X509_STORE* pkix_validation_store,
346246828Sdes		ldns_tlsa_certificate_usage cert_usage, int offset)
347246828Sdes{
348246828Sdes	ldns_status s;
349246828Sdes	STACK_OF(X509)* pkix_validation_chain = NULL;
350246828Sdes
351246828Sdes	assert(selected_cert != NULL);
352246828Sdes	assert(cert != NULL);
353246828Sdes
354246828Sdes	/* With PKIX validation explicitely turned off (pkix_validation_store
355246828Sdes	 *  == NULL), treat the "CA constraint" and "Service certificate
356246828Sdes	 * constraint" the same as "Trust anchor assertion" and "Domain issued
357246828Sdes	 * certificate" respectively.
358246828Sdes	 */
359246828Sdes	if (pkix_validation_store == NULL) {
360246828Sdes		switch (cert_usage) {
361246828Sdes
362246828Sdes		case LDNS_TLSA_USAGE_CA_CONSTRAINT:
363246828Sdes
364246828Sdes			cert_usage = LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION;
365246828Sdes			break;
366246828Sdes
367246828Sdes		case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
368246828Sdes
369246828Sdes			cert_usage = LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE;
370246828Sdes			break;
371246828Sdes
372246828Sdes		default:
373246828Sdes			break;
374246828Sdes		}
375246828Sdes	}
376246828Sdes
377246828Sdes	/* Now what to do with each Certificate usage...
378246828Sdes	 */
379246828Sdes	switch (cert_usage) {
380246828Sdes
381246828Sdes	case LDNS_TLSA_USAGE_CA_CONSTRAINT:
382246828Sdes
383246828Sdes		s = ldns_dane_pkix_validate_and_get_chain(
384246828Sdes				&pkix_validation_chain,
385246828Sdes				cert, extra_certs,
386246828Sdes				pkix_validation_store);
387246828Sdes		if (! pkix_validation_chain) {
388246828Sdes			return s;
389246828Sdes		}
390246828Sdes		if (s == LDNS_STATUS_OK) {
391246828Sdes			if (offset == -1) {
392246828Sdes				offset = 0;
393246828Sdes			}
394246828Sdes			s = ldns_dane_get_nth_cert_from_validation_chain(
395246828Sdes					selected_cert, pkix_validation_chain,
396246828Sdes					offset, true);
397246828Sdes		}
398246828Sdes		sk_X509_pop_free(pkix_validation_chain, X509_free);
399246828Sdes		return s;
400246828Sdes		break;
401246828Sdes
402246828Sdes
403246828Sdes	case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
404246828Sdes
405246828Sdes		*selected_cert = cert;
406246828Sdes		return ldns_dane_pkix_validate(cert, extra_certs,
407246828Sdes				pkix_validation_store);
408246828Sdes		break;
409246828Sdes
410246828Sdes
411246828Sdes	case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
412246828Sdes
413246828Sdes		if (offset == -1) {
414246828Sdes			s = ldns_dane_pkix_get_last_self_signed(
415246828Sdes					selected_cert, cert, extra_certs);
416246828Sdes			return s;
417246828Sdes		} else {
418246828Sdes			s = ldns_dane_pkix_get_chain(
419246828Sdes					&pkix_validation_chain,
420246828Sdes					cert, extra_certs);
421246828Sdes			if (s == LDNS_STATUS_OK) {
422246828Sdes				s =
423246828Sdes				ldns_dane_get_nth_cert_from_validation_chain(
424246828Sdes					selected_cert, pkix_validation_chain,
425246828Sdes					offset, false);
426246828Sdes			} else if (! pkix_validation_chain) {
427246828Sdes				return s;
428246828Sdes			}
429246828Sdes			sk_X509_pop_free(pkix_validation_chain, X509_free);
430246828Sdes			return s;
431246828Sdes		}
432246828Sdes		break;
433246828Sdes
434246828Sdes
435246828Sdes	case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
436246828Sdes
437246828Sdes		*selected_cert = cert;
438246828Sdes		return LDNS_STATUS_OK;
439246828Sdes		break;
440246828Sdes
441246828Sdes	default:
442246828Sdes		return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE;
443246828Sdes		break;
444246828Sdes	}
445246828Sdes}
446246828Sdes
447246828Sdes
448246828Sdesldns_status
449246828Sdesldns_dane_create_tlsa_rr(ldns_rr** tlsa,
450246828Sdes		ldns_tlsa_certificate_usage certificate_usage,
451246828Sdes		ldns_tlsa_selector          selector,
452246828Sdes		ldns_tlsa_matching_type     matching_type,
453246828Sdes		X509* cert)
454246828Sdes{
455246828Sdes	ldns_rdf* rdf;
456246828Sdes	ldns_status s;
457246828Sdes
458246828Sdes	assert(tlsa != NULL);
459246828Sdes	assert(cert != NULL);
460246828Sdes
461246828Sdes	/* create rr */
462246828Sdes	*tlsa = ldns_rr_new_frm_type(LDNS_RR_TYPE_TLSA);
463246828Sdes	if (*tlsa == NULL) {
464246828Sdes		return LDNS_STATUS_MEM_ERR;
465246828Sdes	}
466246828Sdes
467246828Sdes	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
468246828Sdes			(uint8_t)certificate_usage);
469246828Sdes	if (rdf == NULL) {
470246828Sdes		goto memerror;
471246828Sdes	}
472246828Sdes	(void) ldns_rr_set_rdf(*tlsa, rdf, 0);
473246828Sdes
474246828Sdes	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)selector);
475246828Sdes	if (rdf == NULL) {
476246828Sdes		goto memerror;
477246828Sdes	}
478246828Sdes	(void) ldns_rr_set_rdf(*tlsa, rdf, 1);
479246828Sdes
480246828Sdes	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)matching_type);
481246828Sdes	if (rdf == NULL) {
482246828Sdes		goto memerror;
483246828Sdes	}
484246828Sdes	(void) ldns_rr_set_rdf(*tlsa, rdf, 2);
485246828Sdes
486246828Sdes	s = ldns_dane_cert2rdf(&rdf, cert, selector, matching_type);
487246828Sdes	if (s == LDNS_STATUS_OK) {
488246828Sdes		(void) ldns_rr_set_rdf(*tlsa, rdf, 3);
489246828Sdes		return LDNS_STATUS_OK;
490246828Sdes	}
491246828Sdes	ldns_rr_free(*tlsa);
492246828Sdes	*tlsa = NULL;
493246828Sdes	return s;
494246828Sdes
495246828Sdesmemerror:
496246828Sdes	ldns_rr_free(*tlsa);
497246828Sdes	*tlsa = NULL;
498246828Sdes	return LDNS_STATUS_MEM_ERR;
499246828Sdes}
500246828Sdes
501246828Sdes
502246828Sdes/* Return tlsas that actually are TLSA resource records with known values
503246828Sdes * for the Certificate usage, Selector and Matching type rdata fields.
504246828Sdes */
505246828Sdesstatic ldns_rr_list*
506246828Sdesldns_dane_filter_unusable_records(const ldns_rr_list* tlsas)
507246828Sdes{
508246828Sdes	size_t i;
509246828Sdes	ldns_rr_list* r = ldns_rr_list_new();
510246828Sdes	ldns_rr* tlsa_rr;
511246828Sdes
512246828Sdes	if (! r) {
513246828Sdes		return NULL;
514246828Sdes	}
515246828Sdes	for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) {
516246828Sdes		tlsa_rr = ldns_rr_list_rr(tlsas, i);
517246828Sdes		if (ldns_rr_get_type(tlsa_rr) == LDNS_RR_TYPE_TLSA &&
518246828Sdes		    ldns_rr_rd_count(tlsa_rr) == 4 &&
519246828Sdes		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)) <= 3 &&
520246828Sdes		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)) <= 1 &&
521246828Sdes		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)) <= 2) {
522246828Sdes
523246828Sdes			if (! ldns_rr_list_push_rr(r, tlsa_rr)) {
524246828Sdes				ldns_rr_list_free(r);
525246828Sdes				return NULL;
526246828Sdes			}
527246828Sdes		}
528246828Sdes	}
529246828Sdes	return r;
530246828Sdes}
531246828Sdes
532246828Sdes
533246828Sdes/* Return whether cert/selector/matching_type matches data.
534246828Sdes */
535246828Sdesstatic ldns_status
536246828Sdesldns_dane_match_cert_with_data(X509* cert, ldns_tlsa_selector selector,
537246828Sdes		ldns_tlsa_matching_type matching_type, ldns_rdf* data)
538246828Sdes{
539246828Sdes	ldns_status s;
540246828Sdes	ldns_rdf* match_data;
541246828Sdes
542246828Sdes	s = ldns_dane_cert2rdf(&match_data, cert, selector, matching_type);
543246828Sdes	if (s == LDNS_STATUS_OK) {
544246828Sdes		if (ldns_rdf_compare(data, match_data) != 0) {
545246828Sdes			s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
546246828Sdes		}
547246828Sdes		ldns_rdf_free(match_data);
548246828Sdes	}
549246828Sdes	return s;
550246828Sdes}
551246828Sdes
552246828Sdes
553246828Sdes/* Return whether any certificate from the chain with selector/matching_type
554246828Sdes * matches data.
555246828Sdes * ca should be true if the certificate has to be a CA certificate too.
556246828Sdes */
557246828Sdesstatic ldns_status
558246828Sdesldns_dane_match_any_cert_with_data(STACK_OF(X509)* chain,
559246828Sdes		ldns_tlsa_selector      selector,
560246828Sdes		ldns_tlsa_matching_type matching_type,
561246828Sdes		ldns_rdf* data, bool ca)
562246828Sdes{
563246828Sdes	ldns_status s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
564246828Sdes	size_t n, i;
565246828Sdes	X509* cert;
566246828Sdes
567246828Sdes	n = (size_t)sk_X509_num(chain);
568246828Sdes	for (i = 0; i < n; i++) {
569246828Sdes		cert = sk_X509_pop(chain);
570246828Sdes		if (! cert) {
571246828Sdes			s = LDNS_STATUS_SSL_ERR;
572246828Sdes			break;
573246828Sdes		}
574246828Sdes		s = ldns_dane_match_cert_with_data(cert,
575246828Sdes				selector, matching_type, data);
576246828Sdes		if (ca && s == LDNS_STATUS_OK && ! X509_check_ca(cert)) {
577246828Sdes			s = LDNS_STATUS_DANE_NON_CA_CERTIFICATE;
578246828Sdes		}
579246828Sdes		X509_free(cert);
580246828Sdes		if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH) {
581246828Sdes			break;
582246828Sdes		}
583246828Sdes		/* when s == LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH,
584246828Sdes		 * try to match the next certificate
585246828Sdes		 */
586246828Sdes	}
587246828Sdes	return s;
588246828Sdes}
589246828Sdes
590246828Sdes
591246828Sdesldns_status
592246828Sdesldns_dane_verify_rr(const ldns_rr* tlsa_rr,
593246828Sdes		X509* cert, STACK_OF(X509)* extra_certs,
594246828Sdes		X509_STORE* pkix_validation_store)
595246828Sdes{
596246828Sdes	ldns_status s;
597246828Sdes
598246828Sdes	STACK_OF(X509)* pkix_validation_chain = NULL;
599246828Sdes
600246828Sdes	ldns_tlsa_certificate_usage cert_usage;
601246828Sdes	ldns_tlsa_selector          selector;
602246828Sdes	ldns_tlsa_matching_type     matching_type;
603246828Sdes	ldns_rdf*                   data;
604246828Sdes
605246828Sdes	if (! tlsa_rr) {
606246828Sdes		/* No TLSA, so regular PKIX validation
607246828Sdes		 */
608246828Sdes		return ldns_dane_pkix_validate(cert, extra_certs,
609246828Sdes				pkix_validation_store);
610246828Sdes	}
611246828Sdes	cert_usage    = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0));
612246828Sdes	selector      = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1));
613246828Sdes	matching_type = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2));
614246828Sdes	data          =                      ldns_rr_rdf(tlsa_rr, 3) ;
615246828Sdes
616246828Sdes	switch (cert_usage) {
617246828Sdes	case LDNS_TLSA_USAGE_CA_CONSTRAINT:
618246828Sdes		s = ldns_dane_pkix_validate_and_get_chain(
619246828Sdes				&pkix_validation_chain,
620246828Sdes				cert, extra_certs,
621246828Sdes				pkix_validation_store);
622246828Sdes		if (! pkix_validation_chain) {
623246828Sdes			return s;
624246828Sdes		}
625246828Sdes		if (s == LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) {
626246828Sdes			/*
627246828Sdes			 * NO PKIX validation. We still try to match *any*
628246828Sdes			 * certificate from the chain, so we return
629246828Sdes			 * TLSA errors over PKIX errors.
630246828Sdes			 *
631246828Sdes			 * i.e. When the TLSA matches no certificate, we return
632246828Sdes			 * TLSA_DID_NOT_MATCH and not PKIX_DID_NOT_VALIDATE
633246828Sdes			 */
634246828Sdes			s = ldns_dane_match_any_cert_with_data(
635246828Sdes					pkix_validation_chain,
636246828Sdes					selector, matching_type, data, true);
637246828Sdes
638246828Sdes			if (s == LDNS_STATUS_OK) {
639246828Sdes				/* A TLSA record did match a cert from the
640246828Sdes				 * chain, thus the error is failed PKIX
641246828Sdes				 * validation.
642246828Sdes				 */
643246828Sdes				s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
644246828Sdes			}
645246828Sdes
646246828Sdes		} else if (s == LDNS_STATUS_OK) {
647246828Sdes			/* PKIX validated, does the TLSA match too? */
648246828Sdes
649246828Sdes			s = ldns_dane_match_any_cert_with_data(
650246828Sdes					pkix_validation_chain,
651246828Sdes					selector, matching_type, data, true);
652246828Sdes		}
653246828Sdes		sk_X509_pop_free(pkix_validation_chain, X509_free);
654246828Sdes		return s;
655246828Sdes		break;
656246828Sdes
657246828Sdes	case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
658246828Sdes		s = ldns_dane_match_cert_with_data(cert,
659246828Sdes				selector, matching_type, data);
660246828Sdes
661246828Sdes		if (s == LDNS_STATUS_OK) {
662246828Sdes			return ldns_dane_pkix_validate(cert, extra_certs,
663246828Sdes					pkix_validation_store);
664246828Sdes		}
665246828Sdes		return s;
666246828Sdes		break;
667246828Sdes
668246828Sdes	case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
669246828Sdes		s = ldns_dane_pkix_get_chain(&pkix_validation_chain,
670246828Sdes				cert, extra_certs);
671246828Sdes
672246828Sdes		if (s == LDNS_STATUS_OK) {
673246828Sdes			s = ldns_dane_match_any_cert_with_data(
674246828Sdes					pkix_validation_chain,
675246828Sdes					selector, matching_type, data, false);
676246828Sdes
677246828Sdes		} else if (! pkix_validation_chain) {
678246828Sdes			return s;
679246828Sdes		}
680246828Sdes		sk_X509_pop_free(pkix_validation_chain, X509_free);
681246828Sdes		return s;
682246828Sdes		break;
683246828Sdes
684246828Sdes	case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
685246828Sdes		return ldns_dane_match_cert_with_data(cert,
686246828Sdes				selector, matching_type, data);
687246828Sdes		break;
688246828Sdes
689246828Sdes	default:
690246828Sdes		break;
691246828Sdes	}
692246828Sdes	return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE;
693246828Sdes}
694246828Sdes
695246828Sdes
696246828Sdesldns_status
697246828Sdesldns_dane_verify(ldns_rr_list* tlsas,
698246828Sdes		X509* cert, STACK_OF(X509)* extra_certs,
699246828Sdes		X509_STORE* pkix_validation_store)
700246828Sdes{
701246828Sdes	size_t i;
702246828Sdes	ldns_rr* tlsa_rr;
703246828Sdes	ldns_status s = LDNS_STATUS_OK, ps;
704246828Sdes
705246828Sdes	assert(cert != NULL);
706246828Sdes
707246828Sdes	if (tlsas && ldns_rr_list_rr_count(tlsas) > 0) {
708246828Sdes		tlsas = ldns_dane_filter_unusable_records(tlsas);
709246828Sdes		if (! tlsas) {
710246828Sdes			return LDNS_STATUS_MEM_ERR;
711246828Sdes		}
712246828Sdes	}
713246828Sdes	if (! tlsas || ldns_rr_list_rr_count(tlsas) == 0) {
714246828Sdes		/* No TLSA's, so regular PKIX validation
715246828Sdes		 */
716246828Sdes		return ldns_dane_pkix_validate(cert, extra_certs,
717246828Sdes				pkix_validation_store);
718246828Sdes	} else {
719246828Sdes		for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) {
720246828Sdes			tlsa_rr = ldns_rr_list_rr(tlsas, i);
721246828Sdes			ps = s;
722246828Sdes			s = ldns_dane_verify_rr(tlsa_rr, cert, extra_certs,
723246828Sdes					pkix_validation_store);
724246828Sdes
725246828Sdes			if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH &&
726246828Sdes			    s != LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) {
727246828Sdes
728246828Sdes				/* which would be LDNS_STATUS_OK (match)
729246828Sdes				 * or some fatal error preventing use from
730246828Sdes				 * trying the next TLSA record.
731246828Sdes				 */
732246828Sdes				break;
733246828Sdes			}
734246828Sdes			s = (s > ps ? s : ps); /* prefer PKIX_DID_NOT_VALIDATE
735246828Sdes						* over   TLSA_DID_NOT_MATCH
736246828Sdes						*/
737246828Sdes		}
738246828Sdes		ldns_rr_list_free(tlsas);
739246828Sdes	}
740246828Sdes	return s;
741246828Sdes}
742246828Sdes#endif /* HAVE_SSL */
743