clean up OCSP / verify routines
[freeradius.git] / src / main / tls.c
index ce73f2f..b126f5f 100644 (file)
@@ -77,7 +77,28 @@ static libssl_defect_t libssl_defects[] =
                .id             = "CVE-2014-0160",
                .name           = "Heartbleed",
                .comment        = "For more information see http://heartbleed.com"
-       }
+       },
+       {
+               .low            = 0x01000100f,          /* 1.0.1  */
+               .high           = 0x01000114f,          /* 1.0.1t */
+               .id             = "CVE-2016-6304",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+       },
+       {
+               .low            = 0x01000200f,          /* 1.0.2  */
+               .high           = 0x01000208f,          /* 1.0.2h */
+               .id             = "CVE-2016-6304",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+       },
+       {
+               .low            = 0x01010100f,          /* 1.1.0  */
+               .high           = 0x01010100f,          /* 1.1.0 */
+               .id             = "CVE-2016-6304",
+               .name           = "OCSP status request extension",
+               .comment        = "For more information see https://www.openssl.org/news/secadv/20160922.txt"
+       },
 };
 #endif /* ENABLE_OPENSSL_VERSION_CHECK */
 
@@ -118,25 +139,6 @@ static unsigned int        record_plus(record_t *buf, void const *ptr,
 static unsigned int    record_minus(record_t *buf, void *ptr,
                                     unsigned int size);
 
-#ifdef PSK_MAX_IDENTITY_LEN
-static bool identity_is_safe(const char *identity)
-{
-       char c;
-
-       if (!identity) return true;
-
-       while ((c = *(identity++)) != '\0') {
-               if (isalpha((int) c) || isdigit((int) c) || isspace((int) c) ||
-                   (c == '@') || (c == '-') || (c == '_') || (c == '.')) {
-                       continue;
-               }
-
-               return false;
-       }
-
-       return true;
-}
-
 DIAG_OFF(format-nonliteral)
 /** Print errors in the TLS thread local error stack
  *
@@ -314,6 +316,25 @@ int tls_error_io_log(REQUEST *request, tls_session_t *session, int ret, char con
        return 1;
 }
 
+#ifdef PSK_MAX_IDENTITY_LEN
+static bool identity_is_safe(const char *identity)
+{
+       char c;
+
+       if (!identity) return true;
+
+       while ((c = *(identity++)) != '\0') {
+               if (isalpha((int) c) || isdigit((int) c) || isspace((int) c) ||
+                   (c == '@') || (c == '-') || (c == '_') || (c == '.')) {
+                       continue;
+               }
+
+               return false;
+       }
+
+       return true;
+}
+
 /*
  *     When a client uses TLS-PSK to talk to a server, this callback
  *     is used by the server to determine the PSK to use.
@@ -1889,6 +1910,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
 #ifdef HAVE_OPENSSL_OCSP_H
        X509_STORE      *ocsp_store = NULL;
        X509            *issuer_cert;
+       bool            do_verify = false;
 #endif
        VALUE_PAIR      *vp;
        TALLOC_CTX      *talloc_ctx;
@@ -1921,7 +1943,7 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
 
        identity = (char **)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_IDENTITY);
 #ifdef HAVE_OPENSSL_OCSP_H
-       ocsp_store = (X509_STORE *)SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_STORE);
+       ocsp_store = conf->ocsp_store;
 #endif
 
        talloc_ctx = SSL_get_ex_data(ssl, FR_TLS_EX_INDEX_TALLOC);
@@ -2193,29 +2215,47 @@ int cbtls_verify(int ok, X509_STORE_CTX *ctx)
                } /* check_cert_cn */
 
 #ifdef HAVE_OPENSSL_OCSP_H
-               if (my_ok && conf->ocsp_enable){
-                       RDEBUG2("Starting OCSP Request");
-                       if (X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert) != 1) {
-                               RERROR("Couldn't get issuer_cert for %s", common_name);
+               if (my_ok) {
+                       /*
+                        *      No OCSP, allow external verification.
+                        */
+                       if (!conf->ocsp_enable) {
+                               do_verify = true;
+
                        } else {
-                               my_ok = ocsp_check(request, ocsp_store, issuer_cert, client_cert, conf);
+                               RDEBUG2("Starting OCSP Request");
+                               if ((X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert) != 1) ||
+                                   !issuer_cert) {
+                                       /*
+                                        *      Allow for external verify.
+                                        */
+                                       RERROR("Couldn't get issuer_cert for %s", common_name);
+                                       do_verify = true;
+
+                               } else {
+                                       /*
+                                        *      Do the full OCSP checks.
+                                        *
+                                        *      If they fail, don't run the external verify.  We don't want
+                                        *      to allow admins to force authentication success for bad
+                                        *      certificates.
+                                        *
+                                        *      If the OCSP checks succeed, check whether we still want to
+                                        *      run the external verification routine.  If it's marked as
+                                        *      "skip verify on OK", then we don't do verify.
+                                        */
+                                       my_ok = ocsp_check(request, ocsp_store, issuer_cert, client_cert, conf);
+                                       if (my_ok != OCSP_STATUS_FAILED) {
+                                               do_verify = !conf->verify_skip_if_ocsp_ok;
+                                       }
+                               }
                        }
                }
 #endif
 
-               /*
-                *      If OCSP returns fail (0), the certificate has expired.
-                *      Don't run the verify routines/
-                *
-                *      If OCSP returns success (1), we MAY want to run the verify section.
-                *      but only if verify_skip_if_ocsp_ok is false.
-                *
-                *      If OCSP returns skipped (2), we run the verify command, unless
-                *      conf->verify_skip_if_ocsp_ok is true.
-                */
-               if ((my_ok != 0)
+               if ((my_ok != OCSP_STATUS_FAILED)
 #ifdef HAVE_OPENSSL_OCSP_H
-                   && conf->ocsp_enable && (my_ok != OCSP_STATUS_OK) && conf->verify_skip_if_ocsp_ok
+                   && do_verify
 #endif
                        ) while (conf->verify_client_cert_cmd) {
                        char filename[256];
@@ -2414,34 +2454,32 @@ void tls_global_init(void)
 int tls_global_version_check(char const *acknowledged)
 {
        uint64_t v;
+       bool bad = false;
+       size_t i;
 
-       if ((strcmp(acknowledged, libssl_defects[0].id) != 0) && (strcmp(acknowledged, "yes") != 0)) {
-               bool bad = false;
-               size_t i;
-
-               /* Check for bad versions */
-               v = (uint64_t) SSLeay();
+       if (strcmp(acknowledged, "yes") == 0) return 0;
 
-               for (i = 0; i < (sizeof(libssl_defects) / sizeof(*libssl_defects)); i++) {
-                       libssl_defect_t *defect = &libssl_defects[i];
+       /* Check for bad versions */
+       v = (uint64_t) SSLeay();
 
-                       if ((v >= defect->low) && (v <= defect->high)) {
-                               ERROR("Refusing to start with libssl version %s (in range %s)",
-                                     ssl_version(), ssl_version_range(defect->low, defect->high));
-                               ERROR("Security advisory %s (%s)", defect->id, defect->name);
-                               ERROR("%s", defect->comment);
+       for (i = 0; i < (sizeof(libssl_defects) / sizeof(*libssl_defects)); i++) {
+               libssl_defect_t *defect = &libssl_defects[i];
 
-                               bad = true;
-                       }
-               }
+               if ((v >= defect->low) && (v <= defect->high)) {
+                       ERROR("Refusing to start with libssl version %s (in range %s)",
+                             ssl_version(), ssl_version_range(defect->low, defect->high));
+                       ERROR("Security advisory %s (%s)", defect->id, defect->name);
+                       ERROR("%s", defect->comment);
 
-               if (bad) {
                        INFO("Once you have verified libssl has been correctly patched, "
-                            "set security.allow_vulnerable_openssl = '%s'", libssl_defects[0].id);
-                       return -1;
+                            "set security.allow_vulnerable_openssl = '%s'", defect->id);
+
+                       bad = true;
                }
        }
 
+       if (bad) return -1;
+
        return 0;
 }
 #endif