]> git.ipfire.org Git - thirdparty/ldns.git/commitdiff
DANE-TA usage verification needs OpenSSL 1.1.0
authorWillem Toorop <willem@nlnetlabs.nl>
Tue, 1 Nov 2016 15:11:36 +0000 (16:11 +0100)
committerWillem Toorop <willem@nlnetlabs.nl>
Tue, 1 Nov 2016 15:11:36 +0000 (16:11 +0100)
configure.ac
dane.c
error.c
ldns/error.h

index ed6aa572493b006671c0546c46f3502f91f73568..05f576f5a06cdb34c8afa68ed5dfaf1e152a3cc7 100644 (file)
@@ -410,9 +410,11 @@ case "$enable_ed448" in
 esac
 
 AC_ARG_ENABLE(dane, AC_HELP_STRING([--disable-dane], [Disable DANE support]))
+AC_ARG_ENABLE(dane-ta-usage, AC_HELP_STRING([--disable-dane-ta-usage], [Disable DANE-TA usage type support]))
 case "$enable_dane" in
     no)
       AC_SUBST(ldns_build_config_use_dane, 0)
+      AC_SUBST(ldns_build_config_use_dane_ta_usage, 0)
       ;;
     *) dnl default
       if test "x$HAVE_SSL" != "xyes"; then
@@ -421,6 +423,18 @@ case "$enable_dane" in
       AC_CHECK_FUNC(X509_check_ca, [], [AC_MSG_ERROR([OpenSSL does not support DANE: please upgrade OpenSSL or rerun with --disable-dane])])
       AC_DEFINE_UNQUOTED([USE_DANE], [1], [Define this to enable DANE support.])
       AC_SUBST(ldns_build_config_use_dane, 1)
+      case "$enable_dane_ta_usage" in
+          no)
+            AC_SUBST(ldns_build_config_use_dane_ta_usage, 0)
+            ;;
+          *) dnl default
+           LIBS="$LIBS -lssl"
+            AC_CHECK_FUNC(SSL_get0_dane, [], [AC_MSG_ERROR([OpenSSL does not support offline DANE verification (Needed for the DANE-TA usage type).  Please upgrade OpenSSL to version >= 1.1.0 or rerun with --disable-dane-ta-usage])])
+            LIBSSL_LIBS="$LIBSSL_LIBS -lssl"
+            AC_DEFINE_UNQUOTED([USE_DANE_TA_USAGE], [1], [Define this to enable DANE-TA usage type support.])
+            AC_SUBST(ldns_build_config_use_dane_ta_usage, 1)
+            ;;
+      esac
       ;;
 esac
 
diff --git a/dane.c b/dane.c
index 07c06df3f7ff07059e5e8e7a303ac3c93f0466c8..f9b5c661caec66ad5b43cc90e35cd0f89c6561bd 100644 (file)
--- a/dane.c
+++ b/dane.c
@@ -535,6 +535,7 @@ ldns_dane_filter_unusable_records(const ldns_rr_list* tlsas)
 }
 
 
+#if !defined(USE_DANE_TA_USAGE)
 /* Return whether cert/selector/matching_type matches data.
  */
 static ldns_status
@@ -591,34 +592,106 @@ ldns_dane_match_any_cert_with_data(STACK_OF(X509)* chain,
        }
        return s;
 }
-
+#endif
 
 ldns_status
 ldns_dane_verify_rr(const ldns_rr* tlsa_rr,
                X509* cert, STACK_OF(X509)* extra_certs,
                X509_STORE* pkix_validation_store)
 {
-       ldns_status s;
-
+#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 cert_usage;
+       ldns_tlsa_certificate_usage usage;
        ldns_tlsa_selector          selector;
-       ldns_tlsa_matching_type     matching_type;
+       ldns_tlsa_matching_type     mtype;
        ldns_rdf*                   data;
 
-       if (! tlsa_rr) {
-               /* No TLSA, so regular PKIX validation
+       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);
        }
-       cert_usage    = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 0));
-       selector      = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 1));
-       matching_type = ldns_rdf2native_int8(ldns_rr_rdf(tlsa_rr, 2));
-       data          =                      ldns_rr_rdf(tlsa_rr, 3) ;
+       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 = SSL_CTX_new(TLS_client_method())))
+               s = LDNS_STATUS_MEM_ERR;
 
-       switch (cert_usage) {
+       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, 
@@ -638,7 +711,7 @@ ldns_dane_verify_rr(const ldns_rr* tlsa_rr,
                         */
                        s = ldns_dane_match_any_cert_with_data(
                                        pkix_validation_chain,
-                                       selector, matching_type, data, true);
+                                       selector, mtype, data, true);
 
                        if (s == LDNS_STATUS_OK) {
                                /* A TLSA record did match a cert from the
@@ -653,15 +726,16 @@ ldns_dane_verify_rr(const ldns_rr* tlsa_rr,
 
                        s = ldns_dane_match_any_cert_with_data(
                                        pkix_validation_chain,
-                                       selector, matching_type, data, true);
+                                       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, matching_type, data);
+                               selector, mtype, data);
 
                if (s == LDNS_STATUS_OK) {
                        return ldns_dane_pkix_validate(cert, extra_certs,
@@ -671,29 +745,34 @@ ldns_dane_verify_rr(const ldns_rr* tlsa_rr,
                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, matching_type, data, false);
+                                       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, matching_type, data);
+                               selector, mtype, data);
                break;
 
        default:
                break;
        }
+#endif
        return LDNS_STATUS_DANE_UNKNOWN_CERTIFICATE_USAGE;
 }
 
@@ -703,9 +782,19 @@ 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_status s = LDNS_STATUS_OK, ps;
+       ldns_rr_list *usable_tlsas;
+       ldns_status s = LDNS_STATUS_OK;
 
        assert(cert != NULL);
 
@@ -715,24 +804,119 @@ ldns_dane_verify(const ldns_rr_list* tlsas,
                return ldns_dane_pkix_validate(cert, extra_certs,
                                pkix_validation_store);
 
-       else if (!(tlsas = ldns_dane_filter_unusable_records(tlsas)))
+/* 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(tlsas) == 0) {
+       else if (ldns_rr_list_rr_count(usable_tlsas) == 0) {
                /* No TLSA's, so regular PKIX validation
                 */
-               ldns_rr_list_free((ldns_rr_list *)tlsas);
+               ldns_rr_list_free(usable_tlsas);
                return ldns_dane_pkix_validate(cert, extra_certs,
                                pkix_validation_store);
        }
-       for (i = 0; i < ldns_rr_list_rr_count(tlsas); i++) {
-               tlsa_rr = ldns_rr_list_rr(tlsas, i);
+#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 = SSL_CTX_new(TLS_client_method())))
+               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_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
@@ -740,11 +924,13 @@ ldns_dane_verify(const ldns_rr_list* tlsas,
                         */
                        break;
                }
-               s = (s > ps ? s : ps); /* prefer PKIX_DID_NOT_VALIDATE
-                                       * over   TLSA_DID_NOT_MATCH
+               s = (s > ps ? s : ps); /* pref NEED_OPENSSL_GE_1_1_FOR_DANE_TA
+                                       * over PKIX_DID_NOT_VALIDATE
+                                       * over TLSA_DID_NOT_MATCH
                                        */
        }
-       ldns_rr_list_free((ldns_rr_list *)tlsas);
+#endif
+       ldns_rr_list_free(usable_tlsas);
        return s;
 }
 #endif /* HAVE_SSL */
diff --git a/error.c b/error.c
index 30ffdc88a1a80632310dd2d3de6b7a4244ebb9dc..e8e682d7a649d158ce60ee510db3b3f3ac3fc479 100644 (file)
--- a/error.c
+++ b/error.c
@@ -147,6 +147,16 @@ ldns_lookup_table ldns_error_str[] = {
                "Syntax error, superfluous text present" },
         { LDNS_STATUS_NSEC3_DOMAINNAME_OVERFLOW,
                "The NSEC3 domainname length overflow" },
+#if OPENSSL_VERSION_NUMBER < 0x10100000
+        { LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA,
+               "ldns needs to be linked with OpenSSL >= 1.1.0 to be able "
+                       "to verify the DANE-TA usage type." },
+#else
+        { LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA,
+               "ldns depends on the availability of the SSL_get0_dane() and "
+               "X509_STORE_CTX_set0_dane() functions within OpenSSL >= 1.1.0 "
+               "to be able to verify the DANE-TA usage type." },
+#endif
        { 0, NULL }
 };
 
index fc31737d9a838b26003d2d4e7bf16caf8cf15330..15f49a28e153e80652cf9255ab763f6da69234cf 100644 (file)
@@ -128,7 +128,8 @@ enum ldns_enum_status {
        LDNS_STATUS_INVALID_RDF_TYPE,
        LDNS_STATUS_RDATA_OVERFLOW,
        LDNS_STATUS_SYNTAX_SUPERFLUOUS_TEXT_ERR,
-       LDNS_STATUS_NSEC3_DOMAINNAME_OVERFLOW
+       LDNS_STATUS_NSEC3_DOMAINNAME_OVERFLOW,
+       LDNS_STATUS_DANE_NEED_OPENSSL_GE_1_1_FOR_DANE_TA
 };
 typedef enum ldns_enum_status ldns_status;