/* * Verify or create TLS authentication with DANE (RFC6698) * * (c) NLnetLabs 2012-2020 * * See the file LICENSE for the license. * */ #include #ifdef USE_DANE #include #include #include #include #include #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETDB_H #include #endif #ifdef HAVE_SSL #include #include #include #endif /* OpenSSL context options. At the moment, disable SSLv2, SSLv3 * and Compression, if available. TLSv1.0 is allowed at the moment. * TLSv1.1 is the first to provide elliptic curves, so it is usually * allowed in a TLS stack. TLSv1.2 is the first to provide authentication * modes of operation, like GCM. The defines below are a moving * target based on OpenSSL library version. Grep is useful to find * the defines: grep -IR SSL_OP_NO_ /usr/include/openssl. */ #ifdef HAVE_SSL # ifdef SSL_OP_NO_SSLv2 const long NoOpenSSLv2 = SSL_OP_NO_SSLv2; # else const long NoOpenSSLv2 = 0L; # endif # ifdef SSL_OP_NO_SSLv3 const long NoOpenSSLv3 = SSL_OP_NO_SSLv3; # else const long NoOpenSSLv3 = 0L; # endif # ifdef SSL_OP_NO_TLSv1 const long NoOpenTLSv1 = SSL_OP_NO_TLSv1; # else const long NoOpenTLSv1 = 0L; # endif # ifdef SSL_OP_NO_DTLSv1 const long NoOpenDTLSv1 = SSL_OP_NO_DTLSv1; # else const long NoOpenDTLSv1 = 0L; # endif # ifdef SSL_OP_NO_COMPRESSION const long NoOpenSSLCompression = SSL_OP_NO_COMPRESSION; # else const long NoOpenSSLCompression = 0L; # endif #endif #if defined(USE_DANE_VERIFY) && defined(USE_DANE_TA_USAGE) static SSL_CTX* ldns_dane_new_ssl_context(void) { SSL_CTX* ssl_ctx; ssl_ctx = SSL_CTX_new(TLS_client_method()); if (ssl_ctx != NULL) { /* ldns allows TLS and DTLS v1.0 at the moment. Some may disagree. * Sometime in the future they may be disabled, too. Maybe * --disable-tlsv1 and --disable-dtlsv1 should be configure options. */ long flags = NoOpenSSLv2 | NoOpenSSLv3 | NoOpenSSLCompression; SSL_CTX_set_options(ssl_ctx, flags); } return ssl_ctx; } #endif ldns_status ldns_dane_create_tlsa_owner(ldns_rdf** tlsa_owner, const ldns_rdf* name, uint16_t port, ldns_dane_transport transport) { char buf[LDNS_MAX_DOMAINLEN]; size_t s; assert(tlsa_owner != NULL); assert(name != NULL); assert(ldns_rdf_get_type(name) == LDNS_RDF_TYPE_DNAME); s = (size_t)snprintf(buf, LDNS_MAX_DOMAINLEN, "X_%d", (int)port); buf[0] = (char)(s - 1); switch(transport) { case LDNS_DANE_TRANSPORT_TCP: s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_tcp"); break; case LDNS_DANE_TRANSPORT_UDP: s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\004_udp"); break; case LDNS_DANE_TRANSPORT_SCTP: s += snprintf(buf + s, LDNS_MAX_DOMAINLEN - s, "\005_sctp"); break; default: return LDNS_STATUS_DANE_UNKNOWN_TRANSPORT; } if (s + ldns_rdf_size(name) > LDNS_MAX_DOMAINLEN) { return LDNS_STATUS_DOMAINNAME_OVERFLOW; } memcpy(buf + s, ldns_rdf_data(name), ldns_rdf_size(name)); *tlsa_owner = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, s + ldns_rdf_size(name), buf); if (*tlsa_owner == NULL) { return LDNS_STATUS_MEM_ERR; } return LDNS_STATUS_OK; } #ifdef HAVE_SSL ldns_status ldns_dane_cert2rdf(ldns_rdf** rdf, X509* cert, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type) { unsigned char* buf = NULL; size_t len; X509_PUBKEY* xpubkey; EVP_PKEY* epubkey; unsigned char* digest; assert(rdf != NULL); assert(cert != NULL); switch(selector) { case LDNS_TLSA_SELECTOR_FULL_CERTIFICATE: len = (size_t)i2d_X509(cert, &buf); break; case LDNS_TLSA_SELECTOR_SUBJECTPUBLICKEYINFO: #ifndef S_SPLINT_S xpubkey = X509_get_X509_PUBKEY(cert); #endif if (! xpubkey) { return LDNS_STATUS_SSL_ERR; } epubkey = X509_PUBKEY_get(xpubkey); if (! epubkey) { return LDNS_STATUS_SSL_ERR; } len = (size_t)i2d_PUBKEY(epubkey, &buf); break; default: return LDNS_STATUS_DANE_UNKNOWN_SELECTOR; } switch(matching_type) { case LDNS_TLSA_MATCHING_TYPE_NO_HASH_USED: *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, len, buf); return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; break; case LDNS_TLSA_MATCHING_TYPE_SHA256: digest = LDNS_XMALLOC(unsigned char, LDNS_SHA256_DIGEST_LENGTH); if (digest == NULL) { LDNS_FREE(buf); return LDNS_STATUS_MEM_ERR; } (void) ldns_sha256(buf, (unsigned int)len, digest); *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA256_DIGEST_LENGTH, digest); LDNS_FREE(buf); return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; break; case LDNS_TLSA_MATCHING_TYPE_SHA512: digest = LDNS_XMALLOC(unsigned char, LDNS_SHA512_DIGEST_LENGTH); if (digest == NULL) { LDNS_FREE(buf); return LDNS_STATUS_MEM_ERR; } (void) ldns_sha512(buf, (unsigned int)len, digest); *rdf = ldns_rdf_new(LDNS_RDF_TYPE_HEX, LDNS_SHA512_DIGEST_LENGTH, digest); LDNS_FREE(buf); return *rdf ? LDNS_STATUS_OK : LDNS_STATUS_MEM_ERR; break; default: LDNS_FREE(buf); return LDNS_STATUS_DANE_UNKNOWN_MATCHING_TYPE; } } /* Ordinary PKIX validation of cert (with extra_certs to help) * against the CA's in store */ static ldns_status ldns_dane_pkix_validate(X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* store) { X509_STORE_CTX* vrfy_ctx; ldns_status s; if (! store) { return LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { return LDNS_STATUS_SSL_ERR; } else if (X509_STORE_CTX_init(vrfy_ctx, store, cert, extra_certs) != 1) { s = LDNS_STATUS_SSL_ERR; } else if (X509_verify_cert(vrfy_ctx) == 1) { s = LDNS_STATUS_OK; } else { s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } X509_STORE_CTX_free(vrfy_ctx); return s; } /* Ordinary PKIX validation of cert (with extra_certs to help) * against the CA's in store, but also return the validation chain. */ static ldns_status ldns_dane_pkix_validate_and_get_chain(STACK_OF(X509)** chain, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* store) { ldns_status s; X509_STORE* empty_store = NULL; X509_STORE_CTX* vrfy_ctx; assert(chain != NULL); if (! store) { store = empty_store = X509_STORE_new(); } s = LDNS_STATUS_SSL_ERR; vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { goto exit_free_empty_store; } else if (X509_STORE_CTX_init(vrfy_ctx, store, cert, extra_certs) != 1) { goto exit_free_vrfy_ctx; } else if (X509_verify_cert(vrfy_ctx) == 1) { s = LDNS_STATUS_OK; } else { s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } *chain = X509_STORE_CTX_get1_chain(vrfy_ctx); if (! *chain) { s = LDNS_STATUS_SSL_ERR; } exit_free_vrfy_ctx: X509_STORE_CTX_free(vrfy_ctx); exit_free_empty_store: if (empty_store) { X509_STORE_free(empty_store); } return s; } /* Return the validation chain that can be build out of cert, with extra_certs. */ static ldns_status ldns_dane_pkix_get_chain(STACK_OF(X509)** chain, X509* cert, STACK_OF(X509)* extra_certs) { ldns_status s; X509_STORE* empty_store = NULL; X509_STORE_CTX* vrfy_ctx; assert(chain != NULL); empty_store = X509_STORE_new(); s = LDNS_STATUS_SSL_ERR; vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { goto exit_free_empty_store; } else if (X509_STORE_CTX_init(vrfy_ctx, empty_store, cert, extra_certs) != 1) { goto exit_free_vrfy_ctx; } (void) X509_verify_cert(vrfy_ctx); *chain = X509_STORE_CTX_get1_chain(vrfy_ctx); if (! *chain) { s = LDNS_STATUS_SSL_ERR; } else { s = LDNS_STATUS_OK; } exit_free_vrfy_ctx: X509_STORE_CTX_free(vrfy_ctx); exit_free_empty_store: X509_STORE_free(empty_store); return s; } /* Pop n+1 certs and return the last popped. */ static ldns_status ldns_dane_get_nth_cert_from_validation_chain( X509** cert, STACK_OF(X509)* chain, int n, bool ca) { if (n >= sk_X509_num(chain) || n < 0) { return LDNS_STATUS_DANE_OFFSET_OUT_OF_RANGE; } *cert = sk_X509_pop(chain); while (n-- > 0) { X509_free(*cert); *cert = sk_X509_pop(chain); } if (ca && ! X509_check_ca(*cert)) { return LDNS_STATUS_DANE_NON_CA_CERTIFICATE; } return LDNS_STATUS_OK; } /* Create validation chain with cert and extra_certs and returns the last * self-signed (if present). */ static ldns_status ldns_dane_pkix_get_last_self_signed(X509** out_cert, X509* cert, STACK_OF(X509)* extra_certs) { ldns_status s; X509_STORE* empty_store = NULL; X509_STORE_CTX* vrfy_ctx; assert(out_cert != NULL); empty_store = X509_STORE_new(); s = LDNS_STATUS_SSL_ERR; vrfy_ctx = X509_STORE_CTX_new(); if (! vrfy_ctx) { goto exit_free_empty_store; } else if (X509_STORE_CTX_init(vrfy_ctx, empty_store, cert, extra_certs) != 1) { goto exit_free_vrfy_ctx; } (void) X509_verify_cert(vrfy_ctx); if (X509_STORE_CTX_get_error(vrfy_ctx) == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || X509_STORE_CTX_get_error(vrfy_ctx) == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT){ *out_cert = X509_STORE_CTX_get_current_cert( vrfy_ctx); s = LDNS_STATUS_OK; } else { s = LDNS_STATUS_DANE_PKIX_NO_SELF_SIGNED_TRUST_ANCHOR; } exit_free_vrfy_ctx: X509_STORE_CTX_free(vrfy_ctx); exit_free_empty_store: X509_STORE_free(empty_store); return s; } 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) { ldns_status s; STACK_OF(X509)* pkix_validation_chain = NULL; assert(selected_cert != NULL); assert(cert != NULL); /* With PKIX validation explicitly turned off (pkix_validation_store * == NULL), treat the "CA constraint" and "Service certificate * constraint" the same as "Trust anchor assertion" and "Domain issued * certificate" respectively. */ if (pkix_validation_store == NULL) { switch (cert_usage) { case LDNS_TLSA_USAGE_CA_CONSTRAINT: cert_usage = LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION; break; case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT: cert_usage = LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE; break; default: break; } } /* Now what to do with each Certificate usage... */ switch (cert_usage) { case LDNS_TLSA_USAGE_CA_CONSTRAINT: s = ldns_dane_pkix_validate_and_get_chain( &pkix_validation_chain, cert, extra_certs, pkix_validation_store); if (! pkix_validation_chain) { return s; } if (s == LDNS_STATUS_OK) { if (offset == -1) { offset = 0; } s = ldns_dane_get_nth_cert_from_validation_chain( selected_cert, pkix_validation_chain, offset, true); } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; break; case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT: *selected_cert = cert; return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); break; case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION: if (offset == -1) { s = ldns_dane_pkix_get_last_self_signed( selected_cert, cert, extra_certs); return s; } else { s = ldns_dane_pkix_get_chain( &pkix_validation_chain, cert, extra_certs); if (s == LDNS_STATUS_OK) { s = ldns_dane_get_nth_cert_from_validation_chain( selected_cert, pkix_validation_chain, offset, false); } else if (! pkix_validation_chain) { return s; } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; } break; case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE: *selected_cert = cert; return LDNS_STATUS_OK; break; default: return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE; break; } } 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) { ldns_rdf* rdf; ldns_status s; assert(tlsa != NULL); assert(cert != NULL); /* create rr */ *tlsa = ldns_rr_new_frm_type(LDNS_RR_TYPE_TLSA); if (*tlsa == NULL) { return LDNS_STATUS_MEM_ERR; } rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)certificate_usage); if (rdf == NULL) { goto memerror; } (void) ldns_rr_set_rdf(*tlsa, rdf, 0); rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)selector); if (rdf == NULL) { goto memerror; } (void) ldns_rr_set_rdf(*tlsa, rdf, 1); rdf = ldns_native2rdf_int8(LDNS_RDF_TYPE_INT8, (uint8_t)matching_type); if (rdf == NULL) { goto memerror; } (void) ldns_rr_set_rdf(*tlsa, rdf, 2); s = ldns_dane_cert2rdf(&rdf, cert, selector, matching_type); if (s == LDNS_STATUS_OK) { (void) ldns_rr_set_rdf(*tlsa, rdf, 3); return LDNS_STATUS_OK; } ldns_rr_free(*tlsa); *tlsa = NULL; return s; memerror: ldns_rr_free(*tlsa); *tlsa = NULL; return LDNS_STATUS_MEM_ERR; } #ifdef USE_DANE_VERIFY /* Return tlsas that actually are TLSA resource records with known values * for the Certificate usage, Selector and Matching type rdata fields. */ static ldns_rr_list* ldns_dane_filter_unusable_records(const ldns_rr_list* tlsas) { size_t i; ldns_rr_list* r = ldns_rr_list_new(); ldns_rr* tlsa_rr; if (! r) { return NULL; } for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) { tlsa_rr = ldns_rr_list_rr(tlsas, i); if (ldns_rr_get_type(tlsa_rr) == LDNS_RR_TYPE_TLSA && ldns_rr_rd_count(tlsa_rr) == 4 && ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)) <= 3 && ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)) <= 1 && ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)) <= 2) { if (! ldns_rr_list_push_rr(r, tlsa_rr)) { ldns_rr_list_free(r); return NULL; } } } return r; } #if !defined(USE_DANE_TA_USAGE) /* Return whether cert/selector/matching_type matches data. */ static ldns_status ldns_dane_match_cert_with_data(X509* cert, ldns_tlsa_selector selector, ldns_tlsa_matching_type matching_type, ldns_rdf* data) { ldns_status s; ldns_rdf* match_data; s = ldns_dane_cert2rdf(&match_data, cert, selector, matching_type); if (s == LDNS_STATUS_OK) { if (ldns_rdf_compare(data, match_data) != 0) { s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH; } ldns_rdf_free(match_data); } return s; } /* Return whether any certificate from the chain with selector/matching_type * matches data. * ca should be true if the certificate has to be a CA certificate too. */ 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) { ldns_status s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH; size_t n, i; X509* cert; n = (size_t)sk_X509_num(chain); for (i = 0; i < n; i++) { cert = sk_X509_pop(chain); if (! cert) { s = LDNS_STATUS_SSL_ERR; break; } s = ldns_dane_match_cert_with_data(cert, selector, matching_type, data); if (ca && s == LDNS_STATUS_OK && ! X509_check_ca(cert)) { s = LDNS_STATUS_DANE_NON_CA_CERTIFICATE; } X509_free(cert); if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH) { break; } /* when s == LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH, * try to match the next certificate */ } return s; } #endif /* !defined(USE_DANE_TA_USAGE) */ #endif /* USE_DANE_VERIFY */ #ifdef USE_DANE_VERIFY ldns_status ldns_dane_verify_rr(const ldns_rr* tlsa_rr, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store) { #if defined(USE_DANE_TA_USAGE) SSL_CTX *ssl_ctx = NULL; SSL *ssl = NULL; X509_STORE_CTX *store_ctx = NULL; #else STACK_OF(X509)* pkix_validation_chain = NULL; #endif ldns_status s = LDNS_STATUS_OK; ldns_tlsa_certificate_usage usage; ldns_tlsa_selector selector; ldns_tlsa_matching_type mtype; ldns_rdf* data; if (! tlsa_rr || ldns_rr_get_type(tlsa_rr) != LDNS_RR_TYPE_TLSA || ldns_rr_rd_count(tlsa_rr) != 4 || ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)) > 3 || ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)) > 1 || ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)) > 2 ) { /* No (usable) TLSA, so regular PKIX validation */ return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); } usage = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0)); selector = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1)); mtype = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2)); data = ldns_rr_rdf(tlsa_rr, 3) ; #if defined(USE_DANE_TA_USAGE) /* Rely on OpenSSL dane functions. * * OpenSSL does not provide offline dane verification. The dane unit * tests within openssl use the undocumented SSL_get0_dane() and * X509_STORE_CTX_set0_dane() to convey dane parameters set on SSL and * SSL_CTX to a X509_STORE_CTX that can be used to do offline * verification. We use these undocumented means with the ldns * dane function prototypes which did only offline dane verification. */ if (!(ssl_ctx = ldns_dane_new_ssl_context())) s = LDNS_STATUS_MEM_ERR; else if (SSL_CTX_dane_enable(ssl_ctx) <= 0) s = LDNS_STATUS_SSL_ERR; else if (SSL_CTX_dane_set_flags( ssl_ctx, DANE_FLAG_NO_DANE_EE_NAMECHECKS), !(ssl = SSL_new(ssl_ctx))) s = LDNS_STATUS_MEM_ERR; else if (SSL_set_connect_state(ssl), (SSL_dane_enable(ssl, NULL) <= 0)) s = LDNS_STATUS_SSL_ERR; else if (SSL_dane_tlsa_add(ssl, usage, selector, mtype, ldns_rdf_data(data), ldns_rdf_size(data)) <= 0) s = LDNS_STATUS_SSL_ERR; else if (!(store_ctx = X509_STORE_CTX_new())) s = LDNS_STATUS_MEM_ERR; else if (!X509_STORE_CTX_init(store_ctx, pkix_validation_store, cert, extra_certs)) s = LDNS_STATUS_SSL_ERR; else { int ret; X509_STORE_CTX_set_default(store_ctx, SSL_is_server(ssl) ? "ssl_client" : "ssl_server"); X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx), SSL_get0_param(ssl)); X509_STORE_CTX_set0_dane(store_ctx, SSL_get0_dane(ssl)); if (SSL_get_verify_callback(ssl)) X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl)); ret = X509_verify_cert(store_ctx); if (!ret) { if (X509_STORE_CTX_get_error(store_ctx) == X509_V_ERR_DANE_NO_MATCH) s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH; else s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } X509_STORE_CTX_cleanup(store_ctx); } if (store_ctx) X509_STORE_CTX_free(store_ctx); if (ssl) SSL_free(ssl); if (ssl_ctx) SSL_CTX_free(ssl_ctx); return s; #else switch (usage) { case LDNS_TLSA_USAGE_CA_CONSTRAINT: s = ldns_dane_pkix_validate_and_get_chain( &pkix_validation_chain, cert, extra_certs, pkix_validation_store); if (! pkix_validation_chain) { return s; } if (s == LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE) { /* * NO PKIX validation. We still try to match *any* * certificate from the chain, so we return * TLSA errors over PKIX errors. * * i.e. When the TLSA matches no certificate, we return * TLSA_DID_NOT_MATCH and not PKIX_DID_NOT_VALIDATE */ s = ldns_dane_match_any_cert_with_data( pkix_validation_chain, selector, mtype, data, true); if (s == LDNS_STATUS_OK) { /* A TLSA record did match a cert from the * chain, thus the error is failed PKIX * validation. */ s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } } else if (s == LDNS_STATUS_OK) { /* PKIX validated, does the TLSA match too? */ s = ldns_dane_match_any_cert_with_data( pkix_validation_chain, selector, mtype, data, true); } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; break; case LDNS_TLSA_USAGE_SERVICE_CERTIFICATE_CONSTRAINT: s = ldns_dane_match_cert_with_data(cert, selector, mtype, data); if (s == LDNS_STATUS_OK) { return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); } return s; break; case LDNS_TLSA_USAGE_TRUST_ANCHOR_ASSERTION: #if 0 s = ldns_dane_pkix_get_chain(&pkix_validation_chain, cert, extra_certs); if (s == LDNS_STATUS_OK) { s = ldns_dane_match_any_cert_with_data( pkix_validation_chain, selector, mtype, data, false); } else if (! pkix_validation_chain) { return s; } sk_X509_pop_free(pkix_validation_chain, X509_free); return s; #else return LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA; #endif break; case LDNS_TLSA_USAGE_DOMAIN_ISSUED_CERTIFICATE: return ldns_dane_match_cert_with_data(cert, selector, mtype, data); break; default: break; } #endif return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE; } ldns_status ldns_dane_verify(const ldns_rr_list* tlsas, X509* cert, STACK_OF(X509)* extra_certs, X509_STORE* pkix_validation_store) { #if defined(USE_DANE_TA_USAGE) SSL_CTX *ssl_ctx = NULL; ldns_rdf *basename_rdf = NULL; char *basename = NULL; SSL *ssl = NULL; X509_STORE_CTX *store_ctx = NULL; #else ldns_status ps; #endif size_t i; ldns_rr* tlsa_rr; ldns_rr_list *usable_tlsas; ldns_status s = LDNS_STATUS_OK; assert(cert != NULL); if (! tlsas || ldns_rr_list_rr_count(tlsas) == 0) /* No TLSA's, so regular PKIX validation */ return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); /* To enable name checks (which we don't) */ #if defined(USE_DANE_TA_USAGE) && 0 else if (!(basename_rdf = ldns_dname_clone_from( ldns_rr_list_owner(tlsas), 2))) /* Could nog get DANE base name */ s = LDNS_STATUS_ERR; else if (!(basename = ldns_rdf2str(basename_rdf))) s = LDNS_STATUS_MEM_ERR; else if (strlen(basename) && (basename[strlen(basename)-1] = 0)) s = LDNS_STATUS_ERR; /* Intended to be unreachable */ #endif else if (!(usable_tlsas = ldns_dane_filter_unusable_records(tlsas))) return LDNS_STATUS_MEM_ERR; else if (ldns_rr_list_rr_count(usable_tlsas) == 0) { /* No TLSA's, so regular PKIX validation */ ldns_rr_list_free(usable_tlsas); return ldns_dane_pkix_validate(cert, extra_certs, pkix_validation_store); } #if defined(USE_DANE_TA_USAGE) /* Rely on OpenSSL dane functions. * * OpenSSL does not provide offline dane verification. The dane unit * tests within openssl use the undocumented SSL_get0_dane() and * X509_STORE_CTX_set0_dane() to convey dane parameters set on SSL and * SSL_CTX to a X509_STORE_CTX that can be used to do offline * verification. We use these undocumented means with the ldns * dane function prototypes which did only offline dane verification. */ if (!(ssl_ctx = ldns_dane_new_ssl_context())) s = LDNS_STATUS_MEM_ERR; else if (SSL_CTX_dane_enable(ssl_ctx) <= 0) s = LDNS_STATUS_SSL_ERR; else if (SSL_CTX_dane_set_flags( ssl_ctx, DANE_FLAG_NO_DANE_EE_NAMECHECKS), !(ssl = SSL_new(ssl_ctx))) s = LDNS_STATUS_MEM_ERR; else if (SSL_set_connect_state(ssl), (SSL_dane_enable(ssl, basename) <= 0)) s = LDNS_STATUS_SSL_ERR; else for (i = 0; i < ldns_rr_list_rr_count(usable_tlsas); i++) { ldns_tlsa_certificate_usage usage; ldns_tlsa_selector selector; ldns_tlsa_matching_type mtype; ldns_rdf* data; tlsa_rr = ldns_rr_list_rr(usable_tlsas, i); usage = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr,0)); selector= ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr,1)); mtype = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr,2)); data = ldns_rr_rdf(tlsa_rr,3) ; if (SSL_dane_tlsa_add(ssl, usage, selector, mtype, ldns_rdf_data(data), ldns_rdf_size(data)) <= 0) { s = LDNS_STATUS_SSL_ERR; break; } } if (!s && !(store_ctx = X509_STORE_CTX_new())) s = LDNS_STATUS_MEM_ERR; else if (!X509_STORE_CTX_init(store_ctx, pkix_validation_store, cert, extra_certs)) s = LDNS_STATUS_SSL_ERR; else { int ret; X509_STORE_CTX_set_default(store_ctx, SSL_is_server(ssl) ? "ssl_client" : "ssl_server"); X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx), SSL_get0_param(ssl)); X509_STORE_CTX_set0_dane(store_ctx, SSL_get0_dane(ssl)); if (SSL_get_verify_callback(ssl)) X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl)); ret = X509_verify_cert(store_ctx); if (!ret) { if (X509_STORE_CTX_get_error(store_ctx) == X509_V_ERR_DANE_NO_MATCH) s = LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH; else s = LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE; } X509_STORE_CTX_cleanup(store_ctx); } if (store_ctx) X509_STORE_CTX_free(store_ctx); if (ssl) SSL_free(ssl); if (ssl_ctx) SSL_CTX_free(ssl_ctx); if (basename) free(basename); ldns_rdf_deep_free(basename_rdf); #else for (i = 0; i < ldns_rr_list_rr_count(usable_tlsas); i++) { tlsa_rr = ldns_rr_list_rr(usable_tlsas, i); ps = s; s = ldns_dane_verify_rr(tlsa_rr, cert, extra_certs, pkix_validation_store); if (s != LDNS_STATUS_DANE_TLSA_DID_NOT_MATCH && s != LDNS_STATUS_DANE_PKIX_DID_NOT_VALIDATE && s != LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA) { /* which would be LDNS_STATUS_OK (match) * or some fatal error preventing use from * trying the next TLSA record. */ break; } s = (s > ps ? s : ps); /* pref NEED_OPENSSL_GE_1_1_FOR_DANE_TA * over PKIX_DID_NOT_VALIDATE * over TLSA_DID_NOT_MATCH */ } #endif ldns_rr_list_free(usable_tlsas); return s; } #endif /* USE_DANE_VERIFY */ #endif /* HAVE_SSL */ #endif /* USE_DANE */