xref: /dragonfly/contrib/ldns/dane.c (revision ee791feb)
1d1b2b5caSJohn Marino /*
2d1b2b5caSJohn Marino  * Verify or create TLS authentication with DANE (RFC6698)
3d1b2b5caSJohn Marino  *
4*ee791febSAntonio Huete Jimenez  * (c) NLnetLabs 2012-2020
5d1b2b5caSJohn Marino  *
6d1b2b5caSJohn Marino  * See the file LICENSE for the license.
7d1b2b5caSJohn Marino  *
8d1b2b5caSJohn Marino  */
9d1b2b5caSJohn Marino 
10d1b2b5caSJohn Marino #include <ldns/config.h>
115340022aSzrj #ifdef USE_DANE
12d1b2b5caSJohn Marino 
13d1b2b5caSJohn Marino #include <ldns/ldns.h>
14d1b2b5caSJohn Marino #include <ldns/dane.h>
15d1b2b5caSJohn Marino 
16d1b2b5caSJohn Marino #include <unistd.h>
17d1b2b5caSJohn Marino #include <stdlib.h>
18d1b2b5caSJohn Marino #include <sys/types.h>
195340022aSzrj #ifdef HAVE_SYS_SOCKET_H
20d1b2b5caSJohn Marino #include <sys/socket.h>
215340022aSzrj #endif
225340022aSzrj #ifdef HAVE_NETDB_H
23d1b2b5caSJohn Marino #include <netdb.h>
245340022aSzrj #endif
25d1b2b5caSJohn Marino 
26d1b2b5caSJohn Marino #ifdef HAVE_SSL
27d1b2b5caSJohn Marino #include <openssl/ssl.h>
28d1b2b5caSJohn Marino #include <openssl/err.h>
29d1b2b5caSJohn Marino #include <openssl/x509v3.h>
30d1b2b5caSJohn Marino #endif
31d1b2b5caSJohn Marino 
32*ee791febSAntonio Huete Jimenez /* OpenSSL context options. At the moment, disable SSLv2, SSLv3
33*ee791febSAntonio Huete Jimenez  * and Compression, if available. TLSv1.0 is allowed at the moment.
34*ee791febSAntonio Huete Jimenez  * TLSv1.1 is the first to provide elliptic curves, so it is usually
35*ee791febSAntonio Huete Jimenez  * allowed in a TLS stack. TLSv1.2 is the first to provide authentication
36*ee791febSAntonio Huete Jimenez  * modes of operation, like GCM. The defines below are a moving
37*ee791febSAntonio Huete Jimenez  * target based on OpenSSL library version. Grep is useful to find
38*ee791febSAntonio Huete Jimenez  * the defines: grep -IR SSL_OP_NO_ /usr/include/openssl.
39*ee791febSAntonio Huete Jimenez  */
40*ee791febSAntonio Huete Jimenez #ifdef HAVE_SSL
41*ee791febSAntonio Huete Jimenez # ifdef SSL_OP_NO_SSLv2
42*ee791febSAntonio Huete Jimenez 	const long NoOpenSSLv2 = SSL_OP_NO_SSLv2;
43*ee791febSAntonio Huete Jimenez # else
44*ee791febSAntonio Huete Jimenez 	const long NoOpenSSLv2 = 0L;
45*ee791febSAntonio Huete Jimenez # endif
46*ee791febSAntonio Huete Jimenez # ifdef SSL_OP_NO_SSLv3
47*ee791febSAntonio Huete Jimenez 	const long NoOpenSSLv3 = SSL_OP_NO_SSLv3;
48*ee791febSAntonio Huete Jimenez # else
49*ee791febSAntonio Huete Jimenez 	const long NoOpenSSLv3 = 0L;
50*ee791febSAntonio Huete Jimenez # endif
51*ee791febSAntonio Huete Jimenez # ifdef SSL_OP_NO_TLSv1
52*ee791febSAntonio Huete Jimenez 	const long NoOpenTLSv1 = SSL_OP_NO_TLSv1;
53*ee791febSAntonio Huete Jimenez # else
54*ee791febSAntonio Huete Jimenez 	const long NoOpenTLSv1 = 0L;
55*ee791febSAntonio Huete Jimenez # endif
56*ee791febSAntonio Huete Jimenez # ifdef SSL_OP_NO_DTLSv1
57*ee791febSAntonio Huete Jimenez 	const long NoOpenDTLSv1 = SSL_OP_NO_DTLSv1;
58*ee791febSAntonio Huete Jimenez # else
59*ee791febSAntonio Huete Jimenez 	const long NoOpenDTLSv1 = 0L;
60*ee791febSAntonio Huete Jimenez # endif
61*ee791febSAntonio Huete Jimenez # ifdef SSL_OP_NO_COMPRESSION
62*ee791febSAntonio Huete Jimenez 	const long NoOpenSSLCompression = SSL_OP_NO_COMPRESSION;
63*ee791febSAntonio Huete Jimenez # else
64*ee791febSAntonio Huete Jimenez 	const long NoOpenSSLCompression = 0L;
65*ee791febSAntonio Huete Jimenez # endif
66*ee791febSAntonio Huete Jimenez #endif
67*ee791febSAntonio Huete Jimenez 
68*ee791febSAntonio Huete Jimenez #if defined(USE_DANE_VERIFY) && defined(USE_DANE_TA_USAGE)
69*ee791febSAntonio Huete Jimenez static SSL_CTX*
ldns_dane_new_ssl_context(void)70*ee791febSAntonio Huete Jimenez ldns_dane_new_ssl_context(void)
71*ee791febSAntonio Huete Jimenez {
72*ee791febSAntonio Huete Jimenez 	SSL_CTX* ssl_ctx;
73*ee791febSAntonio Huete Jimenez 
74*ee791febSAntonio Huete Jimenez 	ssl_ctx = SSL_CTX_new(TLS_client_method());
75*ee791febSAntonio Huete Jimenez 	if (ssl_ctx != NULL)
76*ee791febSAntonio Huete Jimenez 	{
77*ee791febSAntonio Huete Jimenez 		/* ldns allows TLS and DTLS v1.0 at the moment. Some may disagree.
78*ee791febSAntonio Huete Jimenez 		 * Sometime in the future they may be disabled, too. Maybe
79*ee791febSAntonio Huete Jimenez 		 * --disable-tlsv1 and --disable-dtlsv1 should be configure options.
80*ee791febSAntonio Huete Jimenez 		 */
81*ee791febSAntonio Huete Jimenez 		long flags = NoOpenSSLv2 | NoOpenSSLv3 | NoOpenSSLCompression;
82*ee791febSAntonio Huete Jimenez 		SSL_CTX_set_options(ssl_ctx, flags);
83*ee791febSAntonio Huete Jimenez 	}
84*ee791febSAntonio Huete Jimenez 
85*ee791febSAntonio Huete Jimenez 	return ssl_ctx;
86*ee791febSAntonio Huete Jimenez }
87*ee791febSAntonio Huete Jimenez #endif
88*ee791febSAntonio Huete Jimenez 
89d1b2b5caSJohn Marino ldns_status
ldns_dane_create_tlsa_owner(ldns_rdf ** tlsa_owner,const ldns_rdf * name,uint16_t port,ldns_dane_transport transport)90d1b2b5caSJohn Marino ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name,
91d1b2b5caSJohn Marino 		uint16_t port, ldns_dane_transport transport)
92d1b2b5caSJohn Marino {
93d1b2b5caSJohn Marino 	char buf[LDNS_MAX_DOMAINLEN];
94d1b2b5caSJohn Marino 	size_t s;
95d1b2b5caSJohn Marino 
96d1b2b5caSJohn Marino 	assert(tlsa_owner != NULL);
97d1b2b5caSJohn Marino 	assert(name != NULL);
98d1b2b5caSJohn Marino 	assert(ldns_rdf_get_type(name) == LDNS_RDF_TYPE_DNAME);
99d1b2b5caSJohn Marino 
100d1b2b5caSJohn Marino 	s = (size_t)snprintf(buf, LDNS_MAX_DOMAINLEN, "X_%d", (int)port);
101d1b2b5caSJohn Marino 	buf[0] = (char)(s - 1);
102d1b2b5caSJohn Marino 
103d1b2b5caSJohn Marino 	switch(transport) {
104d1b2b5caSJohn Marino 	case LDNS_DANE_TRANSPORT_TCP:
105d1b2b5caSJohn Marino 		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_tcp");
106d1b2b5caSJohn Marino 		break;
107d1b2b5caSJohn Marino 
108d1b2b5caSJohn Marino 	case LDNS_DANE_TRANSPORT_UDP:
109d1b2b5caSJohn Marino 		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_udp");
110d1b2b5caSJohn Marino 		break;
111d1b2b5caSJohn Marino 
112d1b2b5caSJohn Marino 	case LDNS_DANE_TRANSPORT_SCTP:
113d1b2b5caSJohn Marino 		s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\005_sctp");
114d1b2b5caSJohn Marino 		break;
115d1b2b5caSJohn Marino 
116d1b2b5caSJohn Marino 	default:
117d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_TRANSPORT;
118d1b2b5caSJohn Marino 	}
119d1b2b5caSJohn Marino 	if (s + ldns_rdf_size(name) > LDNS_MAX_DOMAINLEN) {
120d1b2b5caSJohn Marino 		return LDNS_STATUS_DOMAINNAME_OVERFLOW;
121d1b2b5caSJohn Marino 	}
122d1b2b5caSJohn Marino 	memcpy(buf + s, ldns_rdf_data(name), ldns_rdf_size(name));
123d1b2b5caSJohn Marino 	*tlsa_owner = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME,
124d1b2b5caSJohn Marino 			s + ldns_rdf_size(name), buf);
125d1b2b5caSJohn Marino 	if (*tlsa_owner == NULL) {
126d1b2b5caSJohn Marino 		return LDNS_STATUS_MEM_ERR;
127d1b2b5caSJohn Marino 	}
128d1b2b5caSJohn Marino 	return LDNS_STATUS_OK;
129d1b2b5caSJohn Marino }
130d1b2b5caSJohn Marino 
131d1b2b5caSJohn Marino 
132d1b2b5caSJohn Marino #ifdef HAVE_SSL
133d1b2b5caSJohn Marino ldns_status
ldns_dane_cert2rdf(ldns_rdf ** rdf,X509 * cert,ldns_tlsa_selector selector,ldns_tlsa_matching_type matching_type)134d1b2b5caSJohn Marino ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert,
135d1b2b5caSJohn Marino 		ldns_tlsa_selector      selector,
136d1b2b5caSJohn Marino 		ldns_tlsa_matching_type matching_type)
137d1b2b5caSJohn Marino {
138d1b2b5caSJohn Marino 	unsigned char* buf = NULL;
139d1b2b5caSJohn Marino 	size_t len;
140d1b2b5caSJohn Marino 
141d1b2b5caSJohn Marino 	X509_PUBKEY* xpubkey;
142d1b2b5caSJohn Marino 	EVP_PKEY* epubkey;
143d1b2b5caSJohn Marino 
144d1b2b5caSJohn Marino 	unsigned char* digest;
145d1b2b5caSJohn Marino 
146d1b2b5caSJohn Marino 	assert(rdf != NULL);
147d1b2b5caSJohn Marino 	assert(cert != NULL);
148d1b2b5caSJohn Marino 
149d1b2b5caSJohn Marino 	switch(selector) {
150d1b2b5caSJohn Marino 	case LDNS_TLSA_SELECTOR_FULL_CERTIFICATE:
151d1b2b5caSJohn Marino 
152d1b2b5caSJohn Marino 		len = (size_t)i2d_X509(cert, &buf);
153d1b2b5caSJohn Marino 		break;
154d1b2b5caSJohn Marino 
155d1b2b5caSJohn Marino 	case LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO:
156d1b2b5caSJohn Marino 
157d1b2b5caSJohn Marino #ifndef S_SPLINT_S
158d1b2b5caSJohn Marino 		xpubkey = X509_get_X509_PUBKEY(cert);
159d1b2b5caSJohn Marino #endif
160d1b2b5caSJohn Marino 		if (! xpubkey) {
161d1b2b5caSJohn Marino 			return LDNS_STATUS_SSL_ERR;
162d1b2b5caSJohn Marino 		}
163d1b2b5caSJohn Marino 		epubkey = X509_PUBKEY_get(xpubkey);
164d1b2b5caSJohn Marino 		if (! epubkey) {
165d1b2b5caSJohn Marino 			return LDNS_STATUS_SSL_ERR;
166d1b2b5caSJohn Marino 		}
167d1b2b5caSJohn Marino 		len = (size_t)i2d_PUBKEY(epubkey, &buf);
168d1b2b5caSJohn Marino 		break;
169d1b2b5caSJohn Marino 
170d1b2b5caSJohn Marino 	default:
171d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_SELECTOR;
172d1b2b5caSJohn Marino 	}
173d1b2b5caSJohn Marino 
174d1b2b5caSJohn Marino 	switch(matching_type) {
175d1b2b5caSJohn Marino 	case LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED:
176d1b2b5caSJohn Marino 
177d1b2b5caSJohn Marino 		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, len, buf);
178d1b2b5caSJohn Marino 
179d1b2b5caSJohn Marino 		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
180d1b2b5caSJohn Marino 		break;
181d1b2b5caSJohn Marino 
182d1b2b5caSJohn Marino 	case LDNS_TLSA_MATCHING_TYPE_SHA256:
183d1b2b5caSJohn Marino 
1845340022aSzrj 		digest = LDNS_XMALLOC(unsigned char, LDNS_SHA256_DIGEST_LENGTH);
185d1b2b5caSJohn Marino 		if (digest == NULL) {
186d1b2b5caSJohn Marino 			LDNS_FREE(buf);
187d1b2b5caSJohn Marino 			return LDNS_STATUS_MEM_ERR;
188d1b2b5caSJohn Marino 		}
189d1b2b5caSJohn Marino 		(void) ldns_sha256(buf, (unsigned int)len, digest);
1905340022aSzrj 		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA256_DIGEST_LENGTH,
191d1b2b5caSJohn Marino 				digest);
192d1b2b5caSJohn Marino 		LDNS_FREE(buf);
193d1b2b5caSJohn Marino 
194d1b2b5caSJohn Marino 		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
195d1b2b5caSJohn Marino 		break;
196d1b2b5caSJohn Marino 
197d1b2b5caSJohn Marino 	case LDNS_TLSA_MATCHING_TYPE_SHA512:
198d1b2b5caSJohn Marino 
1995340022aSzrj 		digest = LDNS_XMALLOC(unsigned char, LDNS_SHA512_DIGEST_LENGTH);
200d1b2b5caSJohn Marino 		if (digest == NULL) {
201d1b2b5caSJohn Marino 			LDNS_FREE(buf);
202d1b2b5caSJohn Marino 			return LDNS_STATUS_MEM_ERR;
203d1b2b5caSJohn Marino 		}
204d1b2b5caSJohn Marino 		(void) ldns_sha512(buf, (unsigned int)len, digest);
2055340022aSzrj 		*rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA512_DIGEST_LENGTH,
206d1b2b5caSJohn Marino 				digest);
207d1b2b5caSJohn Marino 		LDNS_FREE(buf);
208d1b2b5caSJohn Marino 
209d1b2b5caSJohn Marino 		return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR;
210d1b2b5caSJohn Marino 		break;
211d1b2b5caSJohn Marino 
212d1b2b5caSJohn Marino 	default:
213d1b2b5caSJohn Marino 		LDNS_FREE(buf);
214d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_MATCHING_TYPE;
215d1b2b5caSJohn Marino 	}
216d1b2b5caSJohn Marino }
217d1b2b5caSJohn Marino 
218d1b2b5caSJohn Marino 
219d1b2b5caSJohn Marino /* Ordinary PKIX validation of cert (with extra_certs to help)
220d1b2b5caSJohn Marino  * against the CA's in store
221d1b2b5caSJohn Marino  */
222d1b2b5caSJohn Marino static ldns_status
ldns_dane_pkix_validate(X509 * cert,STACK_OF (X509)* extra_certs,X509_STORE * store)223d1b2b5caSJohn Marino ldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs,
224d1b2b5caSJohn Marino 		X509_STORE* store)
225d1b2b5caSJohn Marino {
226d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
227d1b2b5caSJohn Marino 	ldns_status s;
228d1b2b5caSJohn Marino 
229d1b2b5caSJohn Marino 	if (! store) {
230d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
231d1b2b5caSJohn Marino 	}
232d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
233d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
234d1b2b5caSJohn Marino 
235d1b2b5caSJohn Marino 		return LDNS_STATUS_SSL_ERR;
236d1b2b5caSJohn Marino 
237d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, store,
238d1b2b5caSJohn Marino 				cert, extra_certs) != 1) {
239d1b2b5caSJohn Marino 		s = LDNS_STATUS_SSL_ERR;
240d1b2b5caSJohn Marino 
241d1b2b5caSJohn Marino 	} else if (X509_verify_cert(vrfy_ctx) == 1) {
242d1b2b5caSJohn Marino 
243d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
244d1b2b5caSJohn Marino 
245d1b2b5caSJohn Marino 	} else {
246d1b2b5caSJohn Marino 		s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
247d1b2b5caSJohn Marino 	}
248d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
249d1b2b5caSJohn Marino 	return s;
250d1b2b5caSJohn Marino }
251d1b2b5caSJohn Marino 
252d1b2b5caSJohn Marino 
253*ee791febSAntonio Huete Jimenez /* Ordinary PKIX validation of cert (with extra_certs to help)
254d1b2b5caSJohn Marino  * against the CA's in store, but also return the validation chain.
255d1b2b5caSJohn Marino  */
256d1b2b5caSJohn Marino static ldns_status
ldns_dane_pkix_validate_and_get_chain(STACK_OF (X509)** chain,X509 * cert,STACK_OF (X509)* extra_certs,X509_STORE * store)257d1b2b5caSJohn Marino ldns_dane_pkix_validate_and_get_chain(STACK_OF(X509)** chain, X509* cert,
258d1b2b5caSJohn Marino 		STACK_OF(X509)* extra_certs, X509_STORE* store)
259d1b2b5caSJohn Marino {
260d1b2b5caSJohn Marino 	ldns_status s;
261d1b2b5caSJohn Marino 	X509_STORE* empty_store = NULL;
262d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
263d1b2b5caSJohn Marino 
264d1b2b5caSJohn Marino 	assert(chain != NULL);
265d1b2b5caSJohn Marino 
266d1b2b5caSJohn Marino 	if (! store) {
267d1b2b5caSJohn Marino 		store = empty_store = X509_STORE_new();
268d1b2b5caSJohn Marino 	}
269d1b2b5caSJohn Marino 	s = LDNS_STATUS_SSL_ERR;
270d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
271d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
272d1b2b5caSJohn Marino 
273d1b2b5caSJohn Marino 		goto exit_free_empty_store;
274d1b2b5caSJohn Marino 
275d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, store,
276d1b2b5caSJohn Marino 					cert, extra_certs) != 1) {
277d1b2b5caSJohn Marino 		goto exit_free_vrfy_ctx;
278d1b2b5caSJohn Marino 
279d1b2b5caSJohn Marino 	} else if (X509_verify_cert(vrfy_ctx) == 1) {
280d1b2b5caSJohn Marino 
281d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
282d1b2b5caSJohn Marino 
283d1b2b5caSJohn Marino 	} else {
284d1b2b5caSJohn Marino 		s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
285d1b2b5caSJohn Marino 	}
286d1b2b5caSJohn Marino 	*chain = X509_STORE_CTX_get1_chain(vrfy_ctx);
287d1b2b5caSJohn Marino 	if (! *chain) {
288d1b2b5caSJohn Marino 		s = LDNS_STATUS_SSL_ERR;
289d1b2b5caSJohn Marino 	}
290d1b2b5caSJohn Marino 
291d1b2b5caSJohn Marino exit_free_vrfy_ctx:
292d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
293d1b2b5caSJohn Marino 
294d1b2b5caSJohn Marino exit_free_empty_store:
295d1b2b5caSJohn Marino 	if (empty_store) {
296d1b2b5caSJohn Marino 		X509_STORE_free(empty_store);
297d1b2b5caSJohn Marino 	}
298d1b2b5caSJohn Marino 	return s;
299d1b2b5caSJohn Marino }
300d1b2b5caSJohn Marino 
301d1b2b5caSJohn Marino 
302d1b2b5caSJohn Marino /* Return the validation chain that can be build out of cert, with extra_certs.
303d1b2b5caSJohn Marino  */
304d1b2b5caSJohn Marino static ldns_status
ldns_dane_pkix_get_chain(STACK_OF (X509)** chain,X509 * cert,STACK_OF (X509)* extra_certs)305d1b2b5caSJohn Marino ldns_dane_pkix_get_chain(STACK_OF(X509)** chain,
306d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs)
307d1b2b5caSJohn Marino {
308d1b2b5caSJohn Marino 	ldns_status s;
309d1b2b5caSJohn Marino 	X509_STORE* empty_store = NULL;
310d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
311d1b2b5caSJohn Marino 
312d1b2b5caSJohn Marino 	assert(chain != NULL);
313d1b2b5caSJohn Marino 
314d1b2b5caSJohn Marino 	empty_store = X509_STORE_new();
315d1b2b5caSJohn Marino 	s = LDNS_STATUS_SSL_ERR;
316d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
317d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
318d1b2b5caSJohn Marino 
319d1b2b5caSJohn Marino 		goto exit_free_empty_store;
320d1b2b5caSJohn Marino 
321d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, empty_store,
322d1b2b5caSJohn Marino 					cert, extra_certs) != 1) {
323d1b2b5caSJohn Marino 		goto exit_free_vrfy_ctx;
324d1b2b5caSJohn Marino 	}
325d1b2b5caSJohn Marino 	(void) X509_verify_cert(vrfy_ctx);
326d1b2b5caSJohn Marino 	*chain = X509_STORE_CTX_get1_chain(vrfy_ctx);
327d1b2b5caSJohn Marino 	if (! *chain) {
328d1b2b5caSJohn Marino 		s = LDNS_STATUS_SSL_ERR;
329d1b2b5caSJohn Marino 	} else {
330d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
331d1b2b5caSJohn Marino 	}
332d1b2b5caSJohn Marino exit_free_vrfy_ctx:
333d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
334d1b2b5caSJohn Marino 
335d1b2b5caSJohn Marino exit_free_empty_store:
336d1b2b5caSJohn Marino 	X509_STORE_free(empty_store);
337d1b2b5caSJohn Marino 	return s;
338d1b2b5caSJohn Marino }
339d1b2b5caSJohn Marino 
340d1b2b5caSJohn Marino 
341d1b2b5caSJohn Marino /* Pop n+1 certs and return the last popped.
342d1b2b5caSJohn Marino  */
343d1b2b5caSJohn Marino static ldns_status
ldns_dane_get_nth_cert_from_validation_chain(X509 ** cert,STACK_OF (X509)* chain,int n,bool ca)344d1b2b5caSJohn Marino ldns_dane_get_nth_cert_from_validation_chain(
345d1b2b5caSJohn Marino 		X509** cert, STACK_OF(X509)* chain, int n, bool ca)
346d1b2b5caSJohn Marino {
347d1b2b5caSJohn Marino 	if (n >= sk_X509_num(chain) || n < 0) {
348d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_OFFSET_OUT_OF_RANGE;
349d1b2b5caSJohn Marino 	}
350d1b2b5caSJohn Marino 	*cert = sk_X509_pop(chain);
351d1b2b5caSJohn Marino 	while (n-- > 0) {
352d1b2b5caSJohn Marino 		X509_free(*cert);
353d1b2b5caSJohn Marino 		*cert = sk_X509_pop(chain);
354d1b2b5caSJohn Marino 	}
355d1b2b5caSJohn Marino 	if (ca && ! X509_check_ca(*cert)) {
356d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_NON_CA_CERTIFICATE;
357d1b2b5caSJohn Marino 	}
358d1b2b5caSJohn Marino 	return LDNS_STATUS_OK;
359d1b2b5caSJohn Marino }
360d1b2b5caSJohn Marino 
361d1b2b5caSJohn Marino 
362d1b2b5caSJohn Marino /* Create validation chain with cert and extra_certs and returns the last
363d1b2b5caSJohn Marino  * self-signed (if present).
364d1b2b5caSJohn Marino  */
365d1b2b5caSJohn Marino static ldns_status
ldns_dane_pkix_get_last_self_signed(X509 ** out_cert,X509 * cert,STACK_OF (X509)* extra_certs)366d1b2b5caSJohn Marino ldns_dane_pkix_get_last_self_signed(X509** out_cert,
367d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs)
368d1b2b5caSJohn Marino {
369d1b2b5caSJohn Marino 	ldns_status s;
370d1b2b5caSJohn Marino 	X509_STORE* empty_store = NULL;
371d1b2b5caSJohn Marino 	X509_STORE_CTX* vrfy_ctx;
372d1b2b5caSJohn Marino 
373d1b2b5caSJohn Marino 	assert(out_cert != NULL);
374d1b2b5caSJohn Marino 
375d1b2b5caSJohn Marino 	empty_store = X509_STORE_new();
376d1b2b5caSJohn Marino 	s = LDNS_STATUS_SSL_ERR;
377d1b2b5caSJohn Marino 	vrfy_ctx = X509_STORE_CTX_new();
378d1b2b5caSJohn Marino 	if (! vrfy_ctx) {
379d1b2b5caSJohn Marino 		goto exit_free_empty_store;
380d1b2b5caSJohn Marino 
381d1b2b5caSJohn Marino 	} else if (X509_STORE_CTX_init(vrfy_ctx, empty_store,
382d1b2b5caSJohn Marino 					cert, extra_certs) != 1) {
383d1b2b5caSJohn Marino 		goto exit_free_vrfy_ctx;
384d1b2b5caSJohn Marino 
385d1b2b5caSJohn Marino 	}
386d1b2b5caSJohn Marino 	(void) X509_verify_cert(vrfy_ctx);
3875340022aSzrj 	if (X509_STORE_CTX_get_error(vrfy_ctx) == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN ||
3885340022aSzrj 	    X509_STORE_CTX_get_error(vrfy_ctx) == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT){
389d1b2b5caSJohn Marino 
390d1b2b5caSJohn Marino 		*out_cert = X509_STORE_CTX_get_current_cert( vrfy_ctx);
391d1b2b5caSJohn Marino 		s = LDNS_STATUS_OK;
392d1b2b5caSJohn Marino 	} else {
393d1b2b5caSJohn Marino 		s = LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR;
394d1b2b5caSJohn Marino 	}
395d1b2b5caSJohn Marino exit_free_vrfy_ctx:
396d1b2b5caSJohn Marino 	X509_STORE_CTX_free(vrfy_ctx);
397d1b2b5caSJohn Marino 
398d1b2b5caSJohn Marino exit_free_empty_store:
399d1b2b5caSJohn Marino 	X509_STORE_free(empty_store);
400d1b2b5caSJohn Marino 	return s;
401d1b2b5caSJohn Marino }
402d1b2b5caSJohn Marino 
403d1b2b5caSJohn Marino 
404d1b2b5caSJohn Marino ldns_status
ldns_dane_select_certificate(X509 ** selected_cert,X509 * cert,STACK_OF (X509)* extra_certs,X509_STORE * pkix_validation_store,ldns_tlsa_certificate_usage cert_usage,int offset)405d1b2b5caSJohn Marino ldns_dane_select_certificate(X509** selected_cert,
406d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs,
407d1b2b5caSJohn Marino 		X509_STORE* pkix_validation_store,
408d1b2b5caSJohn Marino 		ldns_tlsa_certificate_usage cert_usage, int offset)
409d1b2b5caSJohn Marino {
410d1b2b5caSJohn Marino 	ldns_status s;
411d1b2b5caSJohn Marino 	STACK_OF(X509)* pkix_validation_chain = NULL;
412d1b2b5caSJohn Marino 
413d1b2b5caSJohn Marino 	assert(selected_cert != NULL);
414d1b2b5caSJohn Marino 	assert(cert != NULL);
415d1b2b5caSJohn Marino 
4165340022aSzrj 	/* With PKIX validation explicitly turned off (pkix_validation_store
417d1b2b5caSJohn Marino 	 *  == NULL), treat the "CA constraint" and "Service certificate
418d1b2b5caSJohn Marino 	 * constraint" the same as "Trust anchor assertion" and "Domain issued
419d1b2b5caSJohn Marino 	 * certificate" respectively.
420d1b2b5caSJohn Marino 	 */
421d1b2b5caSJohn Marino 	if (pkix_validation_store == NULL) {
422d1b2b5caSJohn Marino 		switch (cert_usage) {
423d1b2b5caSJohn Marino 
424d1b2b5caSJohn Marino 		case LDNS_TLSA_USAGE_CA_CONSTRAINT:
425d1b2b5caSJohn Marino 
426d1b2b5caSJohn Marino 			cert_usage = LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION;
427d1b2b5caSJohn Marino 			break;
428d1b2b5caSJohn Marino 
429d1b2b5caSJohn Marino 		case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
430d1b2b5caSJohn Marino 
431d1b2b5caSJohn Marino 			cert_usage = LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE;
432d1b2b5caSJohn Marino 			break;
433d1b2b5caSJohn Marino 
434d1b2b5caSJohn Marino 		default:
435d1b2b5caSJohn Marino 			break;
436d1b2b5caSJohn Marino 		}
437d1b2b5caSJohn Marino 	}
438d1b2b5caSJohn Marino 
439d1b2b5caSJohn Marino 	/* Now what to do with each Certificate usage...
440d1b2b5caSJohn Marino 	 */
441d1b2b5caSJohn Marino 	switch (cert_usage) {
442d1b2b5caSJohn Marino 
443d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_CA_CONSTRAINT:
444d1b2b5caSJohn Marino 
445d1b2b5caSJohn Marino 		s = ldns_dane_pkix_validate_and_get_chain(
446d1b2b5caSJohn Marino 				&pkix_validation_chain,
447d1b2b5caSJohn Marino 				cert, extra_certs,
448d1b2b5caSJohn Marino 				pkix_validation_store);
449d1b2b5caSJohn Marino 		if (! pkix_validation_chain) {
450d1b2b5caSJohn Marino 			return s;
451d1b2b5caSJohn Marino 		}
452d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_OK) {
453d1b2b5caSJohn Marino 			if (offset == -1) {
454d1b2b5caSJohn Marino 				offset = 0;
455d1b2b5caSJohn Marino 			}
456d1b2b5caSJohn Marino 			s = ldns_dane_get_nth_cert_from_validation_chain(
457d1b2b5caSJohn Marino 					selected_cert, pkix_validation_chain,
458d1b2b5caSJohn Marino 					offset, true);
459d1b2b5caSJohn Marino 		}
460d1b2b5caSJohn Marino 		sk_X509_pop_free(pkix_validation_chain, X509_free);
461d1b2b5caSJohn Marino 		return s;
462d1b2b5caSJohn Marino 		break;
463d1b2b5caSJohn Marino 
464d1b2b5caSJohn Marino 
465d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
466d1b2b5caSJohn Marino 
467d1b2b5caSJohn Marino 		*selected_cert = cert;
468d1b2b5caSJohn Marino 		return ldns_dane_pkix_validate(cert, extra_certs,
469d1b2b5caSJohn Marino 				pkix_validation_store);
470d1b2b5caSJohn Marino 		break;
471d1b2b5caSJohn Marino 
472d1b2b5caSJohn Marino 
473d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
474d1b2b5caSJohn Marino 
475d1b2b5caSJohn Marino 		if (offset == -1) {
476d1b2b5caSJohn Marino 			s = ldns_dane_pkix_get_last_self_signed(
477d1b2b5caSJohn Marino 					selected_cert, cert, extra_certs);
478d1b2b5caSJohn Marino 			return s;
479d1b2b5caSJohn Marino 		} else {
480d1b2b5caSJohn Marino 			s = ldns_dane_pkix_get_chain(
481d1b2b5caSJohn Marino 					&pkix_validation_chain,
482d1b2b5caSJohn Marino 					cert, extra_certs);
483d1b2b5caSJohn Marino 			if (s == LDNS_STATUS_OK) {
484d1b2b5caSJohn Marino 				s =
485d1b2b5caSJohn Marino 				ldns_dane_get_nth_cert_from_validation_chain(
486d1b2b5caSJohn Marino 					selected_cert, pkix_validation_chain,
487d1b2b5caSJohn Marino 					offset, false);
488d1b2b5caSJohn Marino 			} else if (! pkix_validation_chain) {
489d1b2b5caSJohn Marino 				return s;
490d1b2b5caSJohn Marino 			}
491d1b2b5caSJohn Marino 			sk_X509_pop_free(pkix_validation_chain, X509_free);
492d1b2b5caSJohn Marino 			return s;
493d1b2b5caSJohn Marino 		}
494d1b2b5caSJohn Marino 		break;
495d1b2b5caSJohn Marino 
496d1b2b5caSJohn Marino 
497d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
498d1b2b5caSJohn Marino 
499d1b2b5caSJohn Marino 		*selected_cert = cert;
500d1b2b5caSJohn Marino 		return LDNS_STATUS_OK;
501d1b2b5caSJohn Marino 		break;
502d1b2b5caSJohn Marino 
503d1b2b5caSJohn Marino 	default:
504d1b2b5caSJohn Marino 		return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE;
505d1b2b5caSJohn Marino 		break;
506d1b2b5caSJohn Marino 	}
507d1b2b5caSJohn Marino }
508d1b2b5caSJohn Marino 
509d1b2b5caSJohn Marino 
510d1b2b5caSJohn Marino ldns_status
ldns_dane_create_tlsa_rr(ldns_rr ** tlsa,ldns_tlsa_certificate_usage certificate_usage,ldns_tlsa_selector selector,ldns_tlsa_matching_type matching_type,X509 * cert)511d1b2b5caSJohn Marino ldns_dane_create_tlsa_rr(ldns_rr** tlsa,
512d1b2b5caSJohn Marino 		ldns_tlsa_certificate_usage certificate_usage,
513d1b2b5caSJohn Marino 		ldns_tlsa_selector          selector,
514d1b2b5caSJohn Marino 		ldns_tlsa_matching_type     matching_type,
515d1b2b5caSJohn Marino 		X509* cert)
516d1b2b5caSJohn Marino {
517d1b2b5caSJohn Marino 	ldns_rdf* rdf;
518d1b2b5caSJohn Marino 	ldns_status s;
519d1b2b5caSJohn Marino 
520d1b2b5caSJohn Marino 	assert(tlsa != NULL);
521d1b2b5caSJohn Marino 	assert(cert != NULL);
522d1b2b5caSJohn Marino 
523d1b2b5caSJohn Marino 	/* create rr */
524d1b2b5caSJohn Marino 	*tlsa = ldns_rr_new_frm_type(LDNS_RR_TYPE_TLSA);
525d1b2b5caSJohn Marino 	if (*tlsa == NULL) {
526d1b2b5caSJohn Marino 		return LDNS_STATUS_MEM_ERR;
527d1b2b5caSJohn Marino 	}
528d1b2b5caSJohn Marino 
529d1b2b5caSJohn Marino 	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8,
530d1b2b5caSJohn Marino 			(uint8_t)certificate_usage);
531d1b2b5caSJohn Marino 	if (rdf == NULL) {
532d1b2b5caSJohn Marino 		goto memerror;
533d1b2b5caSJohn Marino 	}
534d1b2b5caSJohn Marino 	(void) ldns_rr_set_rdf(*tlsa, rdf, 0);
535d1b2b5caSJohn Marino 
536d1b2b5caSJohn Marino 	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)selector);
537d1b2b5caSJohn Marino 	if (rdf == NULL) {
538d1b2b5caSJohn Marino 		goto memerror;
539d1b2b5caSJohn Marino 	}
540d1b2b5caSJohn Marino 	(void) ldns_rr_set_rdf(*tlsa, rdf, 1);
541d1b2b5caSJohn Marino 
542d1b2b5caSJohn Marino 	rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)matching_type);
543d1b2b5caSJohn Marino 	if (rdf == NULL) {
544d1b2b5caSJohn Marino 		goto memerror;
545d1b2b5caSJohn Marino 	}
546d1b2b5caSJohn Marino 	(void) ldns_rr_set_rdf(*tlsa, rdf, 2);
547d1b2b5caSJohn Marino 
548d1b2b5caSJohn Marino 	s = ldns_dane_cert2rdf(&rdf, cert, selector, matching_type);
549d1b2b5caSJohn Marino 	if (s == LDNS_STATUS_OK) {
550d1b2b5caSJohn Marino 		(void) ldns_rr_set_rdf(*tlsa, rdf, 3);
551d1b2b5caSJohn Marino 		return LDNS_STATUS_OK;
552d1b2b5caSJohn Marino 	}
553d1b2b5caSJohn Marino 	ldns_rr_free(*tlsa);
554d1b2b5caSJohn Marino 	*tlsa = NULL;
555d1b2b5caSJohn Marino 	return s;
556d1b2b5caSJohn Marino 
557d1b2b5caSJohn Marino memerror:
558d1b2b5caSJohn Marino 	ldns_rr_free(*tlsa);
559d1b2b5caSJohn Marino 	*tlsa = NULL;
560d1b2b5caSJohn Marino 	return LDNS_STATUS_MEM_ERR;
561d1b2b5caSJohn Marino }
562d1b2b5caSJohn Marino 
563d1b2b5caSJohn Marino 
5645340022aSzrj #ifdef USE_DANE_VERIFY
565d1b2b5caSJohn Marino /* Return tlsas that actually are TLSA resource records with known values
566d1b2b5caSJohn Marino  * for the Certificate usage, Selector and Matching type rdata fields.
567d1b2b5caSJohn Marino  */
568d1b2b5caSJohn Marino static ldns_rr_list*
ldns_dane_filter_unusable_records(const ldns_rr_list * tlsas)569d1b2b5caSJohn Marino ldns_dane_filter_unusable_records(const ldns_rr_list* tlsas)
570d1b2b5caSJohn Marino {
571d1b2b5caSJohn Marino 	size_t i;
572d1b2b5caSJohn Marino 	ldns_rr_list* r = ldns_rr_list_new();
573d1b2b5caSJohn Marino 	ldns_rr* tlsa_rr;
574d1b2b5caSJohn Marino 
575d1b2b5caSJohn Marino 	if (! r) {
576d1b2b5caSJohn Marino 		return NULL;
577d1b2b5caSJohn Marino 	}
578d1b2b5caSJohn Marino 	for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) {
579d1b2b5caSJohn Marino 		tlsa_rr = ldns_rr_list_rr(tlsas, i);
580d1b2b5caSJohn Marino 		if (ldns_rr_get_type(tlsa_rr) == LDNS_RR_TYPE_TLSA &&
581d1b2b5caSJohn Marino 		    ldns_rr_rd_count(tlsa_rr) == 4 &&
582d1b2b5caSJohn Marino 		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)) <= 3 &&
583d1b2b5caSJohn Marino 		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)) <= 1 &&
584d1b2b5caSJohn Marino 		    ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)) <= 2) {
585d1b2b5caSJohn Marino 
586d1b2b5caSJohn Marino 			if (! ldns_rr_list_push_rr(r, tlsa_rr)) {
587d1b2b5caSJohn Marino 				ldns_rr_list_free(r);
588d1b2b5caSJohn Marino 				return NULL;
589d1b2b5caSJohn Marino 			}
590d1b2b5caSJohn Marino 		}
591d1b2b5caSJohn Marino 	}
592d1b2b5caSJohn Marino 	return r;
593d1b2b5caSJohn Marino }
594d1b2b5caSJohn Marino 
595d1b2b5caSJohn Marino 
5965340022aSzrj #if !defined(USE_DANE_TA_USAGE)
597d1b2b5caSJohn Marino /* Return whether cert/selector/matching_type matches data.
598d1b2b5caSJohn Marino  */
599d1b2b5caSJohn Marino static ldns_status
ldns_dane_match_cert_with_data(X509 * cert,ldns_tlsa_selector selector,ldns_tlsa_matching_type matching_type,ldns_rdf * data)600d1b2b5caSJohn Marino ldns_dane_match_cert_with_data(X509* cert, ldns_tlsa_selector selector,
601d1b2b5caSJohn Marino 		ldns_tlsa_matching_type matching_type, ldns_rdf* data)
602d1b2b5caSJohn Marino {
603d1b2b5caSJohn Marino 	ldns_status s;
604d1b2b5caSJohn Marino 	ldns_rdf* match_data;
605d1b2b5caSJohn Marino 
606d1b2b5caSJohn Marino 	s = ldns_dane_cert2rdf(&match_data, cert, selector, matching_type);
607d1b2b5caSJohn Marino 	if (s == LDNS_STATUS_OK) {
608d1b2b5caSJohn Marino 		if (ldns_rdf_compare(data, match_data) != 0) {
609d1b2b5caSJohn Marino 			s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
610d1b2b5caSJohn Marino 		}
611d1b2b5caSJohn Marino 		ldns_rdf_free(match_data);
612d1b2b5caSJohn Marino 	}
613d1b2b5caSJohn Marino 	return s;
614d1b2b5caSJohn Marino }
615d1b2b5caSJohn Marino 
616d1b2b5caSJohn Marino 
617d1b2b5caSJohn Marino /* Return whether any certificate from the chain with selector/matching_type
618d1b2b5caSJohn Marino  * matches data.
619d1b2b5caSJohn Marino  * ca should be true if the certificate has to be a CA certificate too.
620d1b2b5caSJohn Marino  */
621d1b2b5caSJohn Marino static ldns_status
ldns_dane_match_any_cert_with_data(STACK_OF (X509)* chain,ldns_tlsa_selector selector,ldns_tlsa_matching_type matching_type,ldns_rdf * data,bool ca)622d1b2b5caSJohn Marino ldns_dane_match_any_cert_with_data(STACK_OF(X509)* chain,
623d1b2b5caSJohn Marino 		ldns_tlsa_selector      selector,
624d1b2b5caSJohn Marino 		ldns_tlsa_matching_type matching_type,
625d1b2b5caSJohn Marino 		ldns_rdf* data, bool ca)
626d1b2b5caSJohn Marino {
627d1b2b5caSJohn Marino 	ldns_status s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
628d1b2b5caSJohn Marino 	size_t n, i;
629d1b2b5caSJohn Marino 	X509* cert;
630d1b2b5caSJohn Marino 
631d1b2b5caSJohn Marino 	n = (size_t)sk_X509_num(chain);
632d1b2b5caSJohn Marino 	for (i = 0; i < n; i++) {
633d1b2b5caSJohn Marino 		cert = sk_X509_pop(chain);
634d1b2b5caSJohn Marino 		if (! cert) {
635d1b2b5caSJohn Marino 			s = LDNS_STATUS_SSL_ERR;
636d1b2b5caSJohn Marino 			break;
637d1b2b5caSJohn Marino 		}
638d1b2b5caSJohn Marino 		s = ldns_dane_match_cert_with_data(cert,
639d1b2b5caSJohn Marino 				selector, matching_type, data);
640d1b2b5caSJohn Marino 		if (ca && s == LDNS_STATUS_OK && ! X509_check_ca(cert)) {
641d1b2b5caSJohn Marino 			s = LDNS_STATUS_DANE_NON_CA_CERTIFICATE;
642d1b2b5caSJohn Marino 		}
643d1b2b5caSJohn Marino 		X509_free(cert);
644d1b2b5caSJohn Marino 		if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH) {
645d1b2b5caSJohn Marino 			break;
646d1b2b5caSJohn Marino 		}
647d1b2b5caSJohn Marino 		/* when s == LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH,
648d1b2b5caSJohn Marino 		 * try to match the next certificate
649d1b2b5caSJohn Marino 		 */
650d1b2b5caSJohn Marino 	}
651d1b2b5caSJohn Marino 	return s;
652d1b2b5caSJohn Marino }
6535340022aSzrj #endif /* !defined(USE_DANE_TA_USAGE) */
6545340022aSzrj #endif /* USE_DANE_VERIFY */
655d1b2b5caSJohn Marino 
6565340022aSzrj #ifdef USE_DANE_VERIFY
657d1b2b5caSJohn Marino ldns_status
ldns_dane_verify_rr(const ldns_rr * tlsa_rr,X509 * cert,STACK_OF (X509)* extra_certs,X509_STORE * pkix_validation_store)658d1b2b5caSJohn Marino ldns_dane_verify_rr(const ldns_rr* tlsa_rr,
659d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs,
660d1b2b5caSJohn Marino 		X509_STORE* pkix_validation_store)
661d1b2b5caSJohn Marino {
6625340022aSzrj #if defined(USE_DANE_TA_USAGE)
6635340022aSzrj 	SSL_CTX *ssl_ctx = NULL;
6645340022aSzrj 	SSL *ssl = NULL;
6655340022aSzrj 	X509_STORE_CTX *store_ctx = NULL;
6665340022aSzrj #else
667d1b2b5caSJohn Marino 	STACK_OF(X509)* pkix_validation_chain = NULL;
6685340022aSzrj #endif
6695340022aSzrj 	ldns_status s = LDNS_STATUS_OK;
670d1b2b5caSJohn Marino 
6715340022aSzrj 	ldns_tlsa_certificate_usage usage;
672d1b2b5caSJohn Marino 	ldns_tlsa_selector          selector;
6735340022aSzrj 	ldns_tlsa_matching_type     mtype;
674d1b2b5caSJohn Marino 	ldns_rdf*                   data;
675d1b2b5caSJohn Marino 
6765340022aSzrj 	if (! tlsa_rr || ldns_rr_get_type(tlsa_rr) != LDNS_RR_TYPE_TLSA ||
6775340022aSzrj 			ldns_rr_rd_count(tlsa_rr) != 4 ||
6785340022aSzrj 			ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)) > 3 ||
6795340022aSzrj 			ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)) > 1 ||
6805340022aSzrj 			ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)) > 2 ) {
6815340022aSzrj 		/* No (usable) TLSA, so regular PKIX validation
682d1b2b5caSJohn Marino 		 */
683d1b2b5caSJohn Marino 		return ldns_dane_pkix_validate(cert, extra_certs,
684d1b2b5caSJohn Marino 				pkix_validation_store);
685d1b2b5caSJohn Marino 	}
6865340022aSzrj 	usage    = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0));
687d1b2b5caSJohn Marino 	selector = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1));
6885340022aSzrj 	mtype    = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2));
689d1b2b5caSJohn Marino 	data     =                      ldns_rr_rdf(tlsa_rr, 3) ;
690d1b2b5caSJohn Marino 
6915340022aSzrj #if defined(USE_DANE_TA_USAGE)
6925340022aSzrj 	/* Rely on OpenSSL dane functions.
6935340022aSzrj 	 *
6945340022aSzrj 	 * OpenSSL does not provide offline dane verification.  The dane unit
6955340022aSzrj 	 * tests within openssl use the undocumented SSL_get0_dane() and
6965340022aSzrj 	 * X509_STORE_CTX_set0_dane() to convey dane parameters set on SSL and
6975340022aSzrj 	 * SSL_CTX to a X509_STORE_CTX that can be used to do offline
6985340022aSzrj 	 * verification.  We use these undocumented means with the ldns
6995340022aSzrj 	 * dane function prototypes which did only offline dane verification.
7005340022aSzrj 	 */
701*ee791febSAntonio Huete Jimenez 	if (!(ssl_ctx = ldns_dane_new_ssl_context()))
7025340022aSzrj 		s = LDNS_STATUS_MEM_ERR;
7035340022aSzrj 
7045340022aSzrj 	else if (SSL_CTX_dane_enable(ssl_ctx) <= 0)
7055340022aSzrj 		s = LDNS_STATUS_SSL_ERR;
7065340022aSzrj 
7075340022aSzrj 	else if (SSL_CTX_dane_set_flags(
7085340022aSzrj 				ssl_ctx, DANE_FLAG_NO_DANE_EE_NAMECHECKS),
7095340022aSzrj 			!(ssl = SSL_new(ssl_ctx)))
7105340022aSzrj 		s = LDNS_STATUS_MEM_ERR;
7115340022aSzrj 
7125340022aSzrj 	else if (SSL_set_connect_state(ssl),
7135340022aSzrj 			(SSL_dane_enable(ssl, NULL) <= 0))
7145340022aSzrj 		s = LDNS_STATUS_SSL_ERR;
7155340022aSzrj 
7165340022aSzrj 	else if (SSL_dane_tlsa_add(ssl, usage, selector, mtype,
7175340022aSzrj 				ldns_rdf_data(data), ldns_rdf_size(data)) <= 0)
7185340022aSzrj 		s = LDNS_STATUS_SSL_ERR;
7195340022aSzrj 
7205340022aSzrj 	else if (!(store_ctx =  X509_STORE_CTX_new()))
7215340022aSzrj 		s = LDNS_STATUS_MEM_ERR;
7225340022aSzrj 
7235340022aSzrj 	else if (!X509_STORE_CTX_init(store_ctx, pkix_validation_store, cert, extra_certs))
7245340022aSzrj 		s = LDNS_STATUS_SSL_ERR;
7255340022aSzrj 
7265340022aSzrj 	else {
7275340022aSzrj 		int ret;
7285340022aSzrj 
7295340022aSzrj 		X509_STORE_CTX_set_default(store_ctx,
7305340022aSzrj 				SSL_is_server(ssl) ? "ssl_client" : "ssl_server");
7315340022aSzrj 		X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx),
7325340022aSzrj 				SSL_get0_param(ssl));
7335340022aSzrj 		X509_STORE_CTX_set0_dane(store_ctx, SSL_get0_dane(ssl));
7345340022aSzrj 		if (SSL_get_verify_callback(ssl))
7355340022aSzrj 			X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl));
7365340022aSzrj 
7375340022aSzrj 		ret = X509_verify_cert(store_ctx);
7385340022aSzrj 		if (!ret) {
7395340022aSzrj 			if (X509_STORE_CTX_get_error(store_ctx) == X509_V_ERR_DANE_NO_MATCH)
7405340022aSzrj 				s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
7415340022aSzrj 			else
7425340022aSzrj 				s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
7435340022aSzrj 		}
7445340022aSzrj 		X509_STORE_CTX_cleanup(store_ctx);
7455340022aSzrj 	}
7465340022aSzrj 	if (store_ctx)
7475340022aSzrj 		X509_STORE_CTX_free(store_ctx);
7485340022aSzrj 	if (ssl)
7495340022aSzrj 		SSL_free(ssl);
7505340022aSzrj 	if (ssl_ctx)
7515340022aSzrj 		SSL_CTX_free(ssl_ctx);
7525340022aSzrj 	return s;
7535340022aSzrj #else
7545340022aSzrj 	switch (usage) {
755d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_CA_CONSTRAINT:
756d1b2b5caSJohn Marino 		s = ldns_dane_pkix_validate_and_get_chain(
757d1b2b5caSJohn Marino 				&pkix_validation_chain,
758d1b2b5caSJohn Marino 				cert, extra_certs,
759d1b2b5caSJohn Marino 				pkix_validation_store);
760d1b2b5caSJohn Marino 		if (! pkix_validation_chain) {
761d1b2b5caSJohn Marino 			return s;
762d1b2b5caSJohn Marino 		}
763d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) {
764d1b2b5caSJohn Marino 			/*
765d1b2b5caSJohn Marino 			 * NO PKIX validation. We still try to match *any*
766d1b2b5caSJohn Marino 			 * certificate from the chain, so we return
767d1b2b5caSJohn Marino 			 * TLSA errors over PKIX errors.
768d1b2b5caSJohn Marino 			 *
769d1b2b5caSJohn Marino 			 * i.e. When the TLSA matches no certificate, we return
770d1b2b5caSJohn Marino 			 * TLSA_DID_NOT_MATCH and not PKIX_DID_NOT_VALIDATE
771d1b2b5caSJohn Marino 			 */
772d1b2b5caSJohn Marino 			s = ldns_dane_match_any_cert_with_data(
773d1b2b5caSJohn Marino 					pkix_validation_chain,
7745340022aSzrj 					selector, mtype, data, true);
775d1b2b5caSJohn Marino 
776d1b2b5caSJohn Marino 			if (s == LDNS_STATUS_OK) {
777d1b2b5caSJohn Marino 				/* A TLSA record did match a cert from the
778d1b2b5caSJohn Marino 				 * chain, thus the error is failed PKIX
779d1b2b5caSJohn Marino 				 * validation.
780d1b2b5caSJohn Marino 				 */
781d1b2b5caSJohn Marino 				s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
782d1b2b5caSJohn Marino 			}
783d1b2b5caSJohn Marino 
784d1b2b5caSJohn Marino 		} else if (s == LDNS_STATUS_OK) {
785d1b2b5caSJohn Marino 			/* PKIX validated, does the TLSA match too? */
786d1b2b5caSJohn Marino 
787d1b2b5caSJohn Marino 			s = ldns_dane_match_any_cert_with_data(
788d1b2b5caSJohn Marino 					pkix_validation_chain,
7895340022aSzrj 					selector, mtype, data, true);
790d1b2b5caSJohn Marino 		}
791d1b2b5caSJohn Marino 		sk_X509_pop_free(pkix_validation_chain, X509_free);
792d1b2b5caSJohn Marino 		return s;
793d1b2b5caSJohn Marino 		break;
794d1b2b5caSJohn Marino 
795d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT:
7965340022aSzrj 
797d1b2b5caSJohn Marino 		s = ldns_dane_match_cert_with_data(cert,
7985340022aSzrj 				selector, mtype, data);
799d1b2b5caSJohn Marino 
800d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_OK) {
801d1b2b5caSJohn Marino 			return ldns_dane_pkix_validate(cert, extra_certs,
802d1b2b5caSJohn Marino 					pkix_validation_store);
803d1b2b5caSJohn Marino 		}
804d1b2b5caSJohn Marino 		return s;
805d1b2b5caSJohn Marino 		break;
806d1b2b5caSJohn Marino 
807d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION:
8085340022aSzrj #if 0
809d1b2b5caSJohn Marino 		s = ldns_dane_pkix_get_chain(&pkix_validation_chain,
810d1b2b5caSJohn Marino 				cert, extra_certs);
811d1b2b5caSJohn Marino 
812d1b2b5caSJohn Marino 		if (s == LDNS_STATUS_OK) {
813d1b2b5caSJohn Marino 			s = ldns_dane_match_any_cert_with_data(
814d1b2b5caSJohn Marino 					pkix_validation_chain,
8155340022aSzrj 					selector, mtype, data, false);
816d1b2b5caSJohn Marino 
817d1b2b5caSJohn Marino 		} else if (! pkix_validation_chain) {
818d1b2b5caSJohn Marino 			return s;
819d1b2b5caSJohn Marino 		}
820d1b2b5caSJohn Marino 		sk_X509_pop_free(pkix_validation_chain, X509_free);
821d1b2b5caSJohn Marino 		return s;
8225340022aSzrj #else
8235340022aSzrj 		return LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA;
8245340022aSzrj #endif
825d1b2b5caSJohn Marino 		break;
826d1b2b5caSJohn Marino 
827d1b2b5caSJohn Marino 	case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE:
828d1b2b5caSJohn Marino 		return ldns_dane_match_cert_with_data(cert,
8295340022aSzrj 				selector, mtype, data);
830d1b2b5caSJohn Marino 		break;
831d1b2b5caSJohn Marino 
832d1b2b5caSJohn Marino 	default:
833d1b2b5caSJohn Marino 		break;
834d1b2b5caSJohn Marino 	}
8355340022aSzrj #endif
836d1b2b5caSJohn Marino 	return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE;
837d1b2b5caSJohn Marino }
838d1b2b5caSJohn Marino 
839d1b2b5caSJohn Marino 
840d1b2b5caSJohn Marino ldns_status
ldns_dane_verify(const ldns_rr_list * tlsas,X509 * cert,STACK_OF (X509)* extra_certs,X509_STORE * pkix_validation_store)8415340022aSzrj ldns_dane_verify(const ldns_rr_list* tlsas,
842d1b2b5caSJohn Marino 		X509* cert, STACK_OF(X509)* extra_certs,
843d1b2b5caSJohn Marino 		X509_STORE* pkix_validation_store)
844d1b2b5caSJohn Marino {
8455340022aSzrj #if defined(USE_DANE_TA_USAGE)
8465340022aSzrj 	SSL_CTX *ssl_ctx = NULL;
8475340022aSzrj 	ldns_rdf *basename_rdf = NULL;
8485340022aSzrj 	char *basename = NULL;
8495340022aSzrj 	SSL *ssl = NULL;
8505340022aSzrj 	X509_STORE_CTX *store_ctx = NULL;
8515340022aSzrj #else
8525340022aSzrj 	ldns_status ps;
8535340022aSzrj #endif
854d1b2b5caSJohn Marino 	size_t i;
855d1b2b5caSJohn Marino 	ldns_rr* tlsa_rr;
8565340022aSzrj 	ldns_rr_list *usable_tlsas;
8575340022aSzrj 	ldns_status s = LDNS_STATUS_OK;
858d1b2b5caSJohn Marino 
859d1b2b5caSJohn Marino 	assert(cert != NULL);
860d1b2b5caSJohn Marino 
8615340022aSzrj 	if (! tlsas || ldns_rr_list_rr_count(tlsas) == 0)
862d1b2b5caSJohn Marino 		/* No TLSA's, so regular PKIX validation
863d1b2b5caSJohn Marino 		 */
864d1b2b5caSJohn Marino 		return ldns_dane_pkix_validate(cert, extra_certs,
865d1b2b5caSJohn Marino 				pkix_validation_store);
8665340022aSzrj 
8675340022aSzrj /* To enable name checks (which we don't) */
8685340022aSzrj #if defined(USE_DANE_TA_USAGE) && 0
8695340022aSzrj 	else if (!(basename_rdf = ldns_dname_clone_from(
8705340022aSzrj 					ldns_rr_list_owner(tlsas), 2)))
8715340022aSzrj 		/* Could nog get DANE base name */
8725340022aSzrj 		s = LDNS_STATUS_ERR;
8735340022aSzrj 
8745340022aSzrj 	else if (!(basename = ldns_rdf2str(basename_rdf)))
8755340022aSzrj 		s = LDNS_STATUS_MEM_ERR;
8765340022aSzrj 
8775340022aSzrj 	else if (strlen(basename) && (basename[strlen(basename)-1]  = 0))
8785340022aSzrj 		s = LDNS_STATUS_ERR; /* Intended to be unreachable */
8795340022aSzrj #endif
8805340022aSzrj 
8815340022aSzrj 	else if (!(usable_tlsas = ldns_dane_filter_unusable_records(tlsas)))
8825340022aSzrj 		return LDNS_STATUS_MEM_ERR;
8835340022aSzrj 
8845340022aSzrj 	else if (ldns_rr_list_rr_count(usable_tlsas) == 0) {
8855340022aSzrj 		/* No TLSA's, so regular PKIX validation
8865340022aSzrj 		 */
8875340022aSzrj 		ldns_rr_list_free(usable_tlsas);
8885340022aSzrj 		return ldns_dane_pkix_validate(cert, extra_certs,
8895340022aSzrj 				pkix_validation_store);
8905340022aSzrj 	}
8915340022aSzrj #if defined(USE_DANE_TA_USAGE)
8925340022aSzrj 	/* Rely on OpenSSL dane functions.
8935340022aSzrj 	 *
8945340022aSzrj 	 * OpenSSL does not provide offline dane verification.  The dane unit
8955340022aSzrj 	 * tests within openssl use the undocumented SSL_get0_dane() and
8965340022aSzrj 	 * X509_STORE_CTX_set0_dane() to convey dane parameters set on SSL and
8975340022aSzrj 	 * SSL_CTX to a X509_STORE_CTX that can be used to do offline
8985340022aSzrj 	 * verification.  We use these undocumented means with the ldns
8995340022aSzrj 	 * dane function prototypes which did only offline dane verification.
9005340022aSzrj 	 */
901*ee791febSAntonio Huete Jimenez 	if (!(ssl_ctx = ldns_dane_new_ssl_context()))
9025340022aSzrj 		s = LDNS_STATUS_MEM_ERR;
9035340022aSzrj 
9045340022aSzrj 	else if (SSL_CTX_dane_enable(ssl_ctx) <= 0)
9055340022aSzrj 		s = LDNS_STATUS_SSL_ERR;
9065340022aSzrj 
9075340022aSzrj 	else if (SSL_CTX_dane_set_flags(
9085340022aSzrj 				ssl_ctx, DANE_FLAG_NO_DANE_EE_NAMECHECKS),
9095340022aSzrj 			!(ssl = SSL_new(ssl_ctx)))
9105340022aSzrj 		s = LDNS_STATUS_MEM_ERR;
9115340022aSzrj 
9125340022aSzrj 	else if (SSL_set_connect_state(ssl),
9135340022aSzrj 			(SSL_dane_enable(ssl, basename) <= 0))
9145340022aSzrj 		s = LDNS_STATUS_SSL_ERR;
9155340022aSzrj 
9165340022aSzrj 	else for (i = 0; i < ldns_rr_list_rr_count(usable_tlsas); i++) {
9175340022aSzrj 		ldns_tlsa_certificate_usage usage;
9185340022aSzrj 		ldns_tlsa_selector          selector;
9195340022aSzrj 		ldns_tlsa_matching_type     mtype;
9205340022aSzrj 		ldns_rdf*                   data;
9215340022aSzrj 
9225340022aSzrj 		tlsa_rr = ldns_rr_list_rr(usable_tlsas, i);
9235340022aSzrj 		usage   = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr,0));
9245340022aSzrj 		selector= ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr,1));
9255340022aSzrj 		mtype   = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr,2));
9265340022aSzrj 		data    =                      ldns_rr_rdf(tlsa_rr,3) ;
9275340022aSzrj 
9285340022aSzrj 		if (SSL_dane_tlsa_add(ssl, usage, selector, mtype,
9295340022aSzrj 					ldns_rdf_data(data),
9305340022aSzrj 					ldns_rdf_size(data)) <= 0) {
9315340022aSzrj 			s = LDNS_STATUS_SSL_ERR;
9325340022aSzrj 			break;
9335340022aSzrj 		}
9345340022aSzrj 	}
9355340022aSzrj 	if (!s && !(store_ctx =  X509_STORE_CTX_new()))
9365340022aSzrj 		s = LDNS_STATUS_MEM_ERR;
9375340022aSzrj 
9385340022aSzrj 	else if (!X509_STORE_CTX_init(store_ctx, pkix_validation_store, cert, extra_certs))
9395340022aSzrj 		s = LDNS_STATUS_SSL_ERR;
9405340022aSzrj 
9415340022aSzrj 	else {
9425340022aSzrj 		int ret;
9435340022aSzrj 
9445340022aSzrj 		X509_STORE_CTX_set_default(store_ctx,
9455340022aSzrj 				SSL_is_server(ssl) ? "ssl_client" : "ssl_server");
9465340022aSzrj 		X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx),
9475340022aSzrj 				SSL_get0_param(ssl));
9485340022aSzrj 		X509_STORE_CTX_set0_dane(store_ctx, SSL_get0_dane(ssl));
9495340022aSzrj 		if (SSL_get_verify_callback(ssl))
9505340022aSzrj 			X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl));
9515340022aSzrj 
9525340022aSzrj 		ret = X509_verify_cert(store_ctx);
9535340022aSzrj 		if (!ret) {
9545340022aSzrj 			if (X509_STORE_CTX_get_error(store_ctx) == X509_V_ERR_DANE_NO_MATCH)
9555340022aSzrj 				s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH;
9565340022aSzrj 			else
9575340022aSzrj 				s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE;
9585340022aSzrj 		}
9595340022aSzrj 		X509_STORE_CTX_cleanup(store_ctx);
9605340022aSzrj 	}
9615340022aSzrj 	if (store_ctx)
9625340022aSzrj 		X509_STORE_CTX_free(store_ctx);
9635340022aSzrj 	if (ssl)
9645340022aSzrj 		SSL_free(ssl);
9655340022aSzrj 	if (ssl_ctx)
9665340022aSzrj 		SSL_CTX_free(ssl_ctx);
9675340022aSzrj 	if (basename)
9685340022aSzrj 		free(basename);
9695340022aSzrj 	ldns_rdf_deep_free(basename_rdf);
9705340022aSzrj #else
9715340022aSzrj 	for (i = 0; i < ldns_rr_list_rr_count(usable_tlsas); i++) {
9725340022aSzrj 		tlsa_rr = ldns_rr_list_rr(usable_tlsas, i);
973d1b2b5caSJohn Marino 		ps = s;
974d1b2b5caSJohn Marino 		s = ldns_dane_verify_rr(tlsa_rr, cert, extra_certs,
975d1b2b5caSJohn Marino 				pkix_validation_store);
976d1b2b5caSJohn Marino 
977d1b2b5caSJohn Marino 		if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH &&
9785340022aSzrj 		    s != LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE &&
9795340022aSzrj 		    s != LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA) {
980d1b2b5caSJohn Marino 
981d1b2b5caSJohn Marino 			/* which would be LDNS_STATUS_OK (match)
982d1b2b5caSJohn Marino 			 * or some fatal error preventing use from
983d1b2b5caSJohn Marino 			 * trying the next TLSA record.
984d1b2b5caSJohn Marino 			 */
985d1b2b5caSJohn Marino 			break;
986d1b2b5caSJohn Marino 		}
9875340022aSzrj 		s = (s > ps ? s : ps); /* pref NEED_OPENSSL_GE_1_1_FOR_DANE_TA
9885340022aSzrj 		                        * over PKIX_DID_NOT_VALIDATE
989d1b2b5caSJohn Marino 					* over TLSA_DID_NOT_MATCH
990d1b2b5caSJohn Marino 					*/
991d1b2b5caSJohn Marino 	}
9925340022aSzrj #endif
9935340022aSzrj 	ldns_rr_list_free(usable_tlsas);
994d1b2b5caSJohn Marino 	return s;
995d1b2b5caSJohn Marino }
9965340022aSzrj #endif /* USE_DANE_VERIFY */
997d1b2b5caSJohn Marino #endif /* HAVE_SSL */
9985340022aSzrj #endif /* USE_DANE */
999