Hello!

OpenSSL 1.1.1i changed behaviour when verifying certificates with an unknown CA
[1]. Now verification continues if user callback does not consider unknown CA as
an error.

The change affects test_ssl_handshake() and test_ssl_alpn_negotiate() tests that
use ssl_server_cert_cb_expect_failures() callback with SERF_SSL_CERT_UNKNOWNCA.
The callback will now be called one more time with failures = 0, which results
in REPORT_TEST_SUITE_ERROR().

—---------------------------
There were 2 failures:
1) test_ssl_handshake: test/test_util.c:551: expected <0> but was <120199>
2) test_ssl_alpn_negotiate: test/test_util.c:551: expected <0> but was <120199>

!!!FAILURES!!!
Runs: 127 Passes: 125 Fails: 2
—---------------------------

I would like to suggest a fix that uses ssl_server_cert_cb_log_failures()
callback for these tests and checks certificate failures on the call side.

P.S. It's likely that the same problem was discussed in "Bug#978353: serf:
FTBFS: test_ssl_handshake fails with OpenSSL 1.1.1i".

[1] 
https://github.com/openssl/openssl/commit/2e06150e3928daa06d5ff70c32bffad8088ebe58

Best Regards,
Denis Kovalchuk
Fix test_ssl_handshake() and test_ssl_alpn_negotiate() failures with OpenSSL
1.1.1i+.

OpenSSL 1.1.1i changed behaviour when verifying certificates with an unknown CA
[1]. Now verification continues if user callback does not consider unknown CA as
an error. The change causes ssl_server_cert_cb_expect_failures() to be called
one more time with failures = 0, which results in REPORT_TEST_SUITE_ERROR().

To fix these tests, use ssl_server_cert_cb_log_failures() callback and check
certificate failures on the call side.

[1] 
https://github.com/openssl/openssl/commit/2e06150e3928daa06d5ff70c32bffad8088ebe58

* test/test_ssl.c:
  (ssl_server_cert_cb_log_failures): Move above to be available for
   test_ssl_handshake() and test_ssl_alpn_negotiate().
  (test_ssl_handshake): Use ssl_server_cert_cb_log_failures.
  (test_ssl_alpn_negotiate): Use ssl_server_cert_cb_log_failures.

Index: test/test_ssl.c
===================================================================
--- test/test_ssl.c     (revision 1900545)
+++ test/test_ssl.c     (working copy)
@@ -496,6 +496,35 @@ ssl_server_cert_cb_reject(void *baton, int failure
     return REPORT_TEST_SUITE_ERROR();
 }
 
+/* Logs failures for each depth in tb->user_baton, for later validation. */
+/* TODO: use this in place of ssl_server_cert_cb_expect_failures */
+static apr_status_t
+ssl_server_cert_cb_log_failures(void *baton, int failures,
+                                const serf_ssl_certificate_t *cert)
+{
+    test_baton_t *tb = baton;
+    apr_array_header_t *failure_list = (apr_array_header_t *)tb->user_baton;
+    int depth = serf_ssl_cert_depth(cert);
+    int *failures_for_depth;
+
+    if (!tb->user_baton) {
+        /* make the array big enough to not have to worry about resizing */
+        tb->user_baton = apr_array_make(tb->pool, 10, sizeof(int));
+    }
+    failure_list = tb->user_baton;
+
+    if (depth + 1 > failure_list->nalloc) {
+        return REPORT_TEST_SUITE_ERROR();
+    }
+
+    failures_for_depth = &APR_ARRAY_IDX(failure_list, depth, int);
+    *failures_for_depth |= failures;
+
+    tb->result_flags |= TEST_RESULT_SERVERCERTCB_CALLED;
+
+    return APR_SUCCESS;
+}
+
 /* Validate that we can connect successfully to an https server. This
    certificate is not trusted, so a cert validation failure is expected. */
 static void test_ssl_handshake(CuTest *tc)
@@ -503,7 +532,6 @@ static void test_ssl_handshake(CuTest *tc)
     test_baton_t *tb = tc->testBaton;
     handler_baton_t handler_ctx[1];
     const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int expected_failures;
     apr_status_t status;
     static const char *server_cert[] = { "serfservercert.pem",
         NULL };
@@ -514,16 +542,10 @@ static void test_ssl_handshake(CuTest *tc)
                                  server_cert,
                                  test_clientcert_none);
     status = setup_test_client_https_context(tb, NULL,
-                                             
ssl_server_cert_cb_expect_failures,
+                                             ssl_server_cert_cb_log_failures,
                                              tb->pool);
     CuAssertIntEquals(tc, APR_SUCCESS, status);
 
-    /* This unknown failures is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
-       meaning the chain has only the server cert. A good candidate for its
-       own failure code. */
-    expected_failures = SERF_SSL_CERT_UNKNOWNCA;
-    tb->user_baton = &expected_failures;
-
     Given(tb->mh)
       GETRequest(URLEqualTo("/"), ChunkedBodyEqualTo("1"),
                  HeaderEqualTo("Host", tb->serv_host))
@@ -534,6 +556,13 @@ static void test_ssl_handshake(CuTest *tc)
 
     run_client_and_mock_servers_loops_expect_ok(tc, tb, num_requests,
                                                 handler_ctx, tb->pool);
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCB_CALLED);
+    apr_array_header_t *failure_list = tb->user_baton;
+    /* This unknown failures is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
+       meaning the chain has only the server cert. A good candidate for its
+       own failure code. */
+    CuAssertIntEquals(tc, SERF_SSL_CERT_UNKNOWNCA,
+                      APR_ARRAY_IDX(failure_list, 0, int));
 }
 
 /* Validate that connecting to a SSLv2 only server fails. */
@@ -1197,35 +1226,6 @@ https_load_crl_conn_setup(apr_socket_t *skt,
     return status;
 }
 
-/* Logs failures for each depth in tb->user_baton, for later validation. */
-/* TODO: use this in place of ssl_server_cert_cb_expect_failures */
-static apr_status_t
-ssl_server_cert_cb_log_failures(void *baton, int failures,
-                                const serf_ssl_certificate_t *cert)
-{
-    test_baton_t *tb = baton;
-    apr_array_header_t *failure_list = (apr_array_header_t *)tb->user_baton;
-    int depth = serf_ssl_cert_depth(cert);
-    int *failures_for_depth;
-
-    if (!tb->user_baton) {
-        /* make the array big enough to not have to worry about resizing */
-        tb->user_baton = apr_array_make(tb->pool, 10, sizeof(int));
-    }
-    failure_list = tb->user_baton;
-
-    if (depth + 1 > failure_list->nalloc) {
-        return REPORT_TEST_SUITE_ERROR();
-    }
-
-    failures_for_depth = &APR_ARRAY_IDX(failure_list, depth, int);
-    *failures_for_depth |= failures;
-
-    tb->result_flags |= TEST_RESULT_SERVERCERTCB_CALLED;
-
-    return APR_SUCCESS;
-}
-
 /* Validate that a CRL file can be loaded and revocation actually works. */
 static void test_ssl_revoked_server_cert(CuTest *tc)
 {
@@ -2271,7 +2271,6 @@ static void test_ssl_alpn_negotiate(CuTest *tc)
     test_baton_t *tb = tc->testBaton;
     handler_baton_t handler_ctx[1];
     const int num_requests = sizeof(handler_ctx)/sizeof(handler_ctx[0]);
-    int expected_failures;
     apr_status_t status;
     static const char *server_cert[] = { "serfservercert.pem",
                                          NULL };
@@ -2295,13 +2294,10 @@ static void test_ssl_alpn_negotiate(CuTest *tc)
 
     status = setup_test_client_https_context(tb,
                                              http11_alpn_setup,
-                                             
ssl_server_cert_cb_expect_failures,
+                                             ssl_server_cert_cb_log_failures,
                                              tb->pool);
     CuAssertIntEquals(tc, APR_SUCCESS, status);
 
-    expected_failures = SERF_SSL_CERT_UNKNOWNCA;
-    tb->user_baton = &expected_failures;
-
     Given(tb->mh)
       GETRequest(URLEqualTo("/"), ChunkedBodyEqualTo("1"),
                  HeaderEqualTo("Host", tb->serv_host))
@@ -2312,6 +2308,13 @@ static void test_ssl_alpn_negotiate(CuTest *tc)
 
     run_client_and_mock_servers_loops_expect_ok(tc, tb, num_requests,
                                                 handler_ctx, tb->pool);
+    CuAssertTrue(tc, tb->result_flags & TEST_RESULT_SERVERCERTCB_CALLED);
+    apr_array_header_t *failure_list = tb->user_baton;
+    /* This unknown failures is X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
+       meaning the chain has only the server cert. A good candidate for its
+       own failure code. */
+    CuAssertIntEquals(tc, SERF_SSL_CERT_UNKNOWNCA,
+                      APR_ARRAY_IDX(failure_list, 0, int));
 #endif /* OPENSSL_NO_TLSEXT */
 }
 

Reply via email to