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