Extend tests of SSL_check_chain()
authorMatt Caswell <matt@openssl.org>
Tue, 23 Jul 2019 16:10:05 +0000 (17:10 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 9 Aug 2019 16:29:39 +0000 (17:29 +0100)
Actually supply a chain and then test:
1) A successful check of both the ee and chain certs
2) A failure to check the ee cert
3) A failure to check a chain cert

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/9442)

test/ct_test.c
test/recipes/90-test_sslapi.t
test/sslapitest.c
test/testutil.h
test/testutil/driver.c

index 8f1e1990b8cfd9d49d694363fee0f2ce0997cdd8..e2f50efcf397cdedfee17696df76c0d419b750cb 100644 (file)
@@ -87,29 +87,10 @@ static void tear_down(CT_TEST_FIXTURE *fixture)
     OPENSSL_free(fixture);
 }
 
-static char *mk_file_path(const char *dir, const char *file)
-{
-# ifndef OPENSSL_SYS_VMS
-    const char *sep = "/";
-# else
-    const char *sep = "";
-# endif
-    size_t len = strlen(dir) + strlen(sep) + strlen(file) + 1;
-    char *full_file = OPENSSL_zalloc(len);
-
-    if (full_file != NULL) {
-        OPENSSL_strlcpy(full_file, dir, len);
-        OPENSSL_strlcat(full_file, sep, len);
-        OPENSSL_strlcat(full_file, file, len);
-    }
-
-    return full_file;
-}
-
 static X509 *load_pem_cert(const char *dir, const char *file)
 {
     X509 *cert = NULL;
-    char *file_path = mk_file_path(dir, file);
+    char *file_path = test_mk_file_path(dir, file);
 
     if (file_path != NULL) {
         BIO *cert_io = BIO_new_file(file_path, "r");
@@ -127,7 +108,7 @@ static int read_text_file(const char *dir, const char *file,
                           char *buffer, int buffer_length)
 {
     int len = -1;
-    char *file_path = mk_file_path(dir, file);
+    char *file_path = test_mk_file_path(dir, file);
 
     if (file_path != NULL) {
         BIO *file_io = BIO_new_file(file_path, "r");
index ac0bf07fa11289e60d6a7984ba4c14945c258cca..f01056c6f64b9ba83b4a6666a8330f160cabff58 100644 (file)
@@ -8,7 +8,7 @@
 
 
 use OpenSSL::Test::Utils;
-use OpenSSL::Test qw/:DEFAULT srctop_file/;
+use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir/;
 use File::Temp qw(tempfile);
 
 setup("test_sslapi");
@@ -20,8 +20,7 @@ plan tests => 1;
 
 (undef, my $tmpfilename) = tempfile();
 
-ok(run(test(["sslapitest", srctop_file("apps", "server.pem"),
-             srctop_file("apps", "server.pem"),
+ok(run(test(["sslapitest", srctop_dir("test", "certs"),
              srctop_file("test", "recipes", "90-test_sslapi_data",
                          "passwd.txt"), $tmpfilename])),
              "running sslapitest");
index 074232db7764e4653488601ba2820fd449d4ad52..05f8731165faa882bcaa9761b6f0517a6dfb1e8d 100644 (file)
@@ -45,6 +45,7 @@ static int find_session_cb_cnt = 0;
 static SSL_SESSION *create_a_psk(SSL *ssl);
 #endif
 
+static char *certsdir = NULL;
 static char *cert = NULL;
 static char *privkey = NULL;
 static char *srpvfile = NULL;
@@ -6291,7 +6292,10 @@ static int cert_cb(SSL *s, void *arg)
     SSL_CTX *ctx = (SSL_CTX *)arg;
     BIO *in = NULL;
     EVP_PKEY *pkey = NULL;
-    X509 *x509 = NULL;
+    X509 *x509 = NULL, *rootx = NULL;
+    STACK_OF(X509) *chain = NULL;
+    char *rootfile = NULL, *ecdsacert = NULL, *ecdsakey = NULL;
+    int ret = 0;
 
     if (cert_cb_cnt == 0) {
         /* Suspend the handshake */
@@ -6314,38 +6318,58 @@ static int cert_cb(SSL *s, void *arg)
         return 1;
     } else if (cert_cb_cnt == 3) {
         int rv;
+
+        rootfile = test_mk_file_path(certsdir, "rootcert.pem");
+        ecdsacert = test_mk_file_path(certsdir, "server-ecdsa-cert.pem");
+        ecdsakey = test_mk_file_path(certsdir, "server-ecdsa-key.pem");
+        if (!TEST_ptr(rootfile) || !TEST_ptr(ecdsacert) || !TEST_ptr(ecdsakey))
+            goto out;
+        chain = sk_X509_new_null();
+        if (!TEST_ptr(chain))
+            goto out;
         if (!TEST_ptr(in = BIO_new(BIO_s_file()))
-                || !TEST_int_ge(BIO_read_filename(in, cert), 0)
+                || !TEST_int_ge(BIO_read_filename(in, rootfile), 0)
+                || !TEST_ptr(rootx = PEM_read_bio_X509(in, NULL, NULL, NULL))
+                || !TEST_true(sk_X509_push(chain, rootx)))
+            goto out;
+        rootx = NULL;
+        BIO_free(in);
+        if (!TEST_ptr(in = BIO_new(BIO_s_file()))
+                || !TEST_int_ge(BIO_read_filename(in, ecdsacert), 0)
                 || !TEST_ptr(x509 = PEM_read_bio_X509(in, NULL, NULL, NULL)))
             goto out;
         BIO_free(in);
         if (!TEST_ptr(in = BIO_new(BIO_s_file()))
-                || !TEST_int_ge(BIO_read_filename(in, privkey), 0)
+                || !TEST_int_ge(BIO_read_filename(in, ecdsakey), 0)
                 || !TEST_ptr(pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL)))
             goto out;
-        rv = SSL_check_chain(s, x509, pkey, NULL);
+        rv = SSL_check_chain(s, x509, pkey, chain);
         /*
          * If the cert doesn't show as valid here (e.g., because we don't
          * have any shared sigalgs), then we will not set it, and there will
          * be no certificate at all on the SSL or SSL_CTX.  This, in turn,
          * will cause tls_choose_sigalgs() to fail the connection.
          */
-        if ((rv & CERT_PKEY_VALID)) {
+        if ((rv & (CERT_PKEY_VALID | CERT_PKEY_CA_SIGNATURE))
+                == (CERT_PKEY_VALID | CERT_PKEY_CA_SIGNATURE)) {
             if (!SSL_use_cert_and_key(s, x509, pkey, NULL, 1))
                 goto out;
         }
-        BIO_free(in);
-        EVP_PKEY_free(pkey);
-        X509_free(x509);
-        return 1;
+
+        ret = 1;
     }
 
     /* Abort the handshake */
  out:
+    OPENSSL_free(ecdsacert);
+    OPENSSL_free(ecdsakey);
+    OPENSSL_free(rootfile);
     BIO_free(in);
     EVP_PKEY_free(pkey);
     X509_free(x509);
-    return 0;
+    X509_free(rootx);
+    sk_X509_pop_free(chain, X509_free);
+    return ret;
 }
 
 /*
@@ -6353,6 +6377,10 @@ static int cert_cb(SSL *s, void *arg)
  * Test 0: Callback fails
  * Test 1: Success - no SSL_set_SSL_CTX() in the callback
  * Test 2: Success - SSL_set_SSL_CTX() in the callback
+ * Test 3: Success - Call SSL_check_chain from the callback
+ * Test 4: Failure - SSL_check_chain fails from callback due to bad cert in the
+ *                   chain
+ * Test 5: Failure - SSL_check_chain fails from callback due to bad ee cert
  */
 static int test_cert_cb_int(int prot, int tst)
 {
@@ -6360,6 +6388,12 @@ static int test_cert_cb_int(int prot, int tst)
     SSL *clientssl = NULL, *serverssl = NULL;
     int testresult = 0, ret;
 
+#ifdef OPENSSL_NO_EC
+    /* We use an EC cert in these tests, so we skip in a no-ec build */
+    if (tst >= 3)
+        return 1;
+#endif
+
     if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(),
                                        TLS_client_method(),
                                        TLS1_VERSION,
@@ -6369,10 +6403,11 @@ static int test_cert_cb_int(int prot, int tst)
 
     if (tst == 0)
         cert_cb_cnt = -1;
-    else if (tst == 3)
+    else if (tst >= 3)
         cert_cb_cnt = 3;
     else
         cert_cb_cnt = 0;
+
     if (tst == 2)
         snictx = SSL_CTX_new(TLS_server_method());
     SSL_CTX_set_cert_cb(sctx, cert_cb, snictx);
@@ -6381,8 +6416,26 @@ static int test_cert_cb_int(int prot, int tst)
                                       NULL, NULL)))
         goto end;
 
+    if (tst == 4) {
+        /*
+         * We cause SSL_check_chain() to fail by specifying sig_algs that
+         * the chain doesn't meet (the root uses an RSA cert)
+         */
+        if (!TEST_true(SSL_set1_sigalgs_list(clientssl,
+                                             "ecdsa_secp256r1_sha256")))
+            goto end;
+    } else if (tst == 5) {
+        /*
+         * We cause SSL_check_chain() to fail by specifying sig_algs that
+         * the ee cert doesn't meet (the ee uses an ECDSA cert)
+         */
+        if (!TEST_true(SSL_set1_sigalgs_list(clientssl,
+                           "rsa_pss_rsae_sha256:rsa_pkcs1_sha256")))
+            goto end;
+    }
+
     ret = create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE);
-    if (!TEST_true(tst == 0 ? !ret : ret)
+    if (!TEST_true(tst == 0 || tst == 4 || tst == 5 ? !ret : ret)
             || (tst > 0
                 && !TEST_int_eq((cert_cb_cnt - 2) * (cert_cb_cnt - 3), 0))) {
         goto end;
@@ -6648,10 +6701,9 @@ OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile\n")
 
 int setup_tests(void)
 {
-    if (!TEST_ptr(cert = test_get_argument(0))
-            || !TEST_ptr(privkey = test_get_argument(1))
-            || !TEST_ptr(srpvfile = test_get_argument(2))
-            || !TEST_ptr(tmpfilename = test_get_argument(3)))
+    if (!TEST_ptr(certsdir = test_get_argument(0))
+            || !TEST_ptr(srpvfile = test_get_argument(1))
+            || !TEST_ptr(tmpfilename = test_get_argument(2)))
         return 0;
 
     if (getenv("OPENSSL_TEST_GETCOUNTS") != NULL) {
@@ -6670,6 +6722,16 @@ int setup_tests(void)
 #endif
     }
 
+    cert = test_mk_file_path(certsdir, "servercert.pem");
+    if (cert == NULL)
+        return 0;
+
+    privkey = test_mk_file_path(certsdir, "serverkey.pem");
+    if (privkey == NULL) {
+        OPENSSL_free(cert);
+        return 0;
+    }
+
 #if !defined(OPENSSL_NO_TLS1_2) && !defined(OPENSSL_NO_KTLS) \
     && !defined(OPENSSL_NO_SOCK)
     ADD_TEST(test_ktls_no_txrx_client_no_txrx_server);
@@ -6772,7 +6834,7 @@ int setup_tests(void)
     ADD_ALL_TESTS(test_ssl_get_shared_ciphers, OSSL_NELEM(shared_ciphers_data));
     ADD_ALL_TESTS(test_ticket_callbacks, 12);
     ADD_ALL_TESTS(test_shutdown, 7);
-    ADD_ALL_TESTS(test_cert_cb, 4);
+    ADD_ALL_TESTS(test_cert_cb, 6);
     ADD_ALL_TESTS(test_client_cert_cb, 2);
     ADD_ALL_TESTS(test_ca_names, 3);
     return 1;
@@ -6780,6 +6842,8 @@ int setup_tests(void)
 
 void cleanup_tests(void)
 {
+    OPENSSL_free(cert);
+    OPENSSL_free(privkey);
     bio_s_mempacket_test_free();
     bio_s_always_retry_free();
 }
index 00e2d0aa81510d5dbb97461f7401995072df8eb7..f7d00dc813998fd76affaae0931c8d118aaf1026 100644 (file)
@@ -545,4 +545,7 @@ char *glue_strings(const char *list[], size_t *out_len);
 uint32_t test_random(void);
 void test_random_seed(uint32_t sd);
 
+/* Create a file path from a directory and a filename */
+char *test_mk_file_path(const char *dir, const char *file);
+
 #endif                          /* HEADER_TESTUTIL_H */
index 7a67a0587cd7f938ae6edb857fc8532d2b6b6df9..2ced5634bc4e88880e9b245452b5066bed664a93 100644 (file)
@@ -439,3 +439,21 @@ char *glue_strings(const char *list[], size_t *out_len)
     return ret;
 }
 
+char *test_mk_file_path(const char *dir, const char *file)
+{
+# ifndef OPENSSL_SYS_VMS
+    const char *sep = "/";
+# else
+    const char *sep = "";
+# endif
+    size_t len = strlen(dir) + strlen(sep) + strlen(file) + 1;
+    char *full_file = OPENSSL_zalloc(len);
+
+    if (full_file != NULL) {
+        OPENSSL_strlcpy(full_file, dir, len);
+        OPENSSL_strlcat(full_file, sep, len);
+        OPENSSL_strlcat(full_file, file, len);
+    }
+
+    return full_file;
+}