Add a multi-thread test for shared EVP_PKEYs
authorMatt Caswell <matt@openssl.org>
Tue, 26 Jan 2021 13:30:06 +0000 (13:30 +0000)
committerMatt Caswell <matt@openssl.org>
Tue, 2 Feb 2021 12:21:21 +0000 (12:21 +0000)
EVP_PKEYs may be shared across mutliple threads. For example this is
common for users of libssl who provide a single EVP_PKEY private key for
an SSL_CTX, which is then shared between multiple threads for each SSL
object.

Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/13987)

test/recipes/90-test_threads.t
test/recipes/90-test_threads_data/rsakey.pem [new file with mode: 0644]
test/threadstest.c

index f46121a7513e9c6cd9408f53b279fa675a873395..0410cd80079958a961afdf010f2fbe9aacac9a86 100644 (file)
@@ -8,7 +8,7 @@
 
 
 use OpenSSL::Test::Simple;
-use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file/;
+use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file data_dir/;
 use OpenSSL::Test::Utils;
 use Cwd qw(abs_path);
 
@@ -35,8 +35,8 @@ if (!$no_fips) {
 
 if ($no_fips) {
     $ENV{OPENSSL_CONF} = abs_path(srctop_file("test", "default.cnf"));
-    ok(run(test(["threadstest"])), "running test_threads");
+    ok(run(test(["threadstest", data_dir()])), "running test_threads");
 } else {
     $ENV{OPENSSL_CONF} = abs_path(srctop_file("test", "default-and-fips.cnf"));
-    ok(run(test(["threadstest", "-fips"])), "running test_threads");
+    ok(run(test(["threadstest", "-fips", data_dir()])), "running test_threads");
 }
diff --git a/test/recipes/90-test_threads_data/rsakey.pem b/test/recipes/90-test_threads_data/rsakey.pem
new file mode 100644 (file)
index 0000000..0d7e404
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDVXWBq3/xh7kiq
+jBFIQ6VttlJdqphJsWGSNbH8OgQlDG15/7TVyelcHDvgq7O4faPebb3g3ddavxRH
+EUJepoLQYcF/3RNG5gmFBw7y1PwaZNIKrSCrIGuW8K3MxBlTVdwBHaSz74q0SVNd
+igUc8dzhRL/F1+J3GVdclwt17ohDcQ/KbMG0slCnd0ZsWA8Rv/F2JFquOUK3UWcp
+4dBVMG8X5JHqrfgowkNvomSp+52YkmJIPusNT4JKiv8/cu6Wta6hwZi6732QdW3/
+WlKeq/XAftCHQ9uFBwcPfTh6/dHT7mUd0+o5aoc37krT4A1u9XCswr3xbvOSlV6p
+8KFllZONAgMBAAECggEADLTt7A+A2Vg2jamf0dztejY0e42QWjstI2b9PZc67fXq
+gyx+WYkX07t+uWegYWliG/oPJ9guXiIpE/5sJHToL37S5kmFP2CtynVcJ4wVo4DD
+nY0n9+kLX0bgIuS+2V6wpoRcbbbjXM9NHrH8kfe5ftT4UtEDlLI2qLX6IcDd7p4u
+OYjILChR8GSGTw96yIy2Ws/1Uq9PMw64JoT4RcK5QqnkcPMDFRH1SeLOL+zXP2c4
+nEl9yOy3HauZKxwl/Ry/XK1s3DdjopIAU29ut+hAuMiTb06kzZnumL9NoplKoZtU
+otw/gVcCKhT+Ep+p6i8InLF0XEME8A0qUR0niWebgQKBgQD6vkxR49B8ZZQrzjw4
+XKs1lI9cP7cgPiuWlDHMNjYou3WbOaGrMeScvbB1Ldh9A8pjAhxlw8AaV/xs4qcA
+trmVmSISVMVyc1wSGlJXWi2nUzTNs9OE3vj22SyStihf8UUZtWwX2b5Y4JrYhA/V
++ThGGqHR03oLNLShNLtJc2c7YQKBgQDZ1nkibEyrepexw/fnwkw61IJKq9wRIh1G
+PREakhbe9wU5ie0knuf9razt7awzQiwFmlixmWqsM7UEtLuXNnNPciwdrKhhbvrd
+vD/rkbIEHEPllIhFlDtOzn3hRBWTzWmXFjpou/2LvHTSbVis4IYVZymTp2jb1ZLs
+7VbiG9JTrQKBgQDc6n75g1szzpdehQT/r33U5j/syeJBUSU8NPMu9fB/sLHsgjlT
+SNEf2+y1QSBE/Or6kmiMrIv7advn30W+Vj9qc5HWTsPrk4HiHTjA553jl2alebN5
+lK4LZspjtIQcC8mS3goPdXPEgJdM/gWpwzr2YQ6DfOxBJT2j7n64NyoT4QKBgH7/
+yx+GhCx1DHtXBPDZFhg2TL+78lEK0oZgk9gp06up2CHzh44SFq6O0oLkTcCUk5Ww
+poTkLIy4mJBlzfgahp+KsK2cO46SZS9g0ONFzcMXt33hWpE2Gl2XhUwPpYTF/QlY
+rDTjZK5S8Mi9dzVSsNlJi7PJphiEK2R1+nFYRwcBAoGBANWoIG85jpXAOnq/Kcgx
+Rl3YivR0Ke6r1tFlP58rT7X3EkiboXyQl5vLIFCAwUte6RGrLl1dy3Qyh80B9ySL
+Jx6vj42CK7vgv6A96TuVYhnXTnEI6ZvwAQ2VGaw4BizhjALs/kdSE/og9aSCs3ws
+KQypwAFz0tbHxaNag/bSAN0J
+-----END PRIVATE KEY-----
index 2b9afa7d476c0ef65dd41f07653286abd7107ee4..9c8e2181d0ee980feb36db16c45b2bb2f953c248 100644 (file)
@@ -19,6 +19,7 @@
 #include "testutil.h"
 
 static int do_fips = 0;
+static char *privkey;
 
 #if !defined(OPENSSL_THREADS) || defined(CRYPTO_TDEBUG)
 
@@ -352,17 +353,66 @@ static void thread_multi_simple_fetch(void)
         multi_success = 0;
 }
 
+static EVP_PKEY *shared_evp_pkey = NULL;
+
+static void thread_shared_evp_pkey(void)
+{
+    char *msg = "Hello World";
+    unsigned char ctbuf[256];
+    unsigned char ptbuf[256];
+    size_t ptlen = sizeof(ptbuf), ctlen = sizeof(ctbuf);
+    EVP_PKEY_CTX *ctx = NULL;
+    int success = 0;
+    int i;
+
+    for (i = 0; i < 1 + do_fips; i++) {
+        if (i > 0)
+            EVP_PKEY_CTX_free(ctx);
+        ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey,
+                                         i == 0 ? "provider=default"
+                                                : "provider=fips");
+        if (!TEST_ptr(ctx))
+            goto err;
+
+        if (!TEST_int_ge(EVP_PKEY_encrypt_init(ctx), 0)
+                || !TEST_int_ge(EVP_PKEY_encrypt(ctx, ctbuf, &ctlen,
+                                                (unsigned char *)msg, strlen(msg)),
+                                                0))
+            goto err;
+
+        EVP_PKEY_CTX_free(ctx);
+        ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey, NULL);
+
+        if (!TEST_ptr(ctx))
+            goto err;
+
+        if (!TEST_int_ge(EVP_PKEY_decrypt_init(ctx), 0)
+                || !TEST_int_ge(EVP_PKEY_decrypt(ctx, ptbuf, &ptlen, ctbuf, ctlen),
+                                                0)
+                || !TEST_mem_eq(msg, strlen(msg), ptbuf, ptlen))
+            goto err;
+    }
+
+    success = 1;
+
+ err:
+    EVP_PKEY_CTX_free(ctx);
+    if (!success)
+        multi_success = 0;
+}
+
 /*
  * Do work in multiple worker threads at the same time.
  * Test 0: General worker, using the default provider
  * Test 1: General worker, using the fips provider
  * Test 2: Simple fetch worker
+ * Test 3: Worker using a shared EVP_PKEY
  */
 static int test_multi(int idx)
 {
     thread_t thread1, thread2;
     int testresult = 0;
-    OSSL_PROVIDER *prov = NULL;
+    OSSL_PROVIDER *prov = NULL, *prov2 = NULL;
     void (*worker)(void);
 
     if (idx == 1 && !do_fips)
@@ -384,6 +434,18 @@ static int test_multi(int idx)
     case 2:
         worker = thread_multi_simple_fetch;
         break;
+    case 3:
+        /*
+         * If available we have both the default and fips providers for this
+         * test
+         */
+        if (do_fips
+                && !TEST_ptr(prov2 = OSSL_PROVIDER_load(multi_libctx, "fips")))
+            goto err;
+        if (!TEST_ptr(shared_evp_pkey = load_pkey_pem(privkey, multi_libctx)))
+            goto err;
+        worker = thread_shared_evp_pkey;
+        break;
     default:
         TEST_error("Invalid test index");
         goto err;
@@ -404,7 +466,10 @@ static int test_multi(int idx)
 
  err:
     OSSL_PROVIDER_unload(prov);
+    OSSL_PROVIDER_unload(prov2);
     OSSL_LIB_CTX_free(multi_libctx);
+    EVP_PKEY_free(shared_evp_pkey);
+    shared_evp_pkey = NULL;
     return testresult;
 }
 
@@ -428,6 +493,7 @@ const OPTIONS *test_get_options(void)
 int setup_tests(void)
 {
     OPTION_CHOICE o;
+    char *datadir;
 
     while ((o = opt_next()) != OPT_EOF) {
         switch (o) {
@@ -441,10 +507,22 @@ int setup_tests(void)
         }
     }
 
+    if (!TEST_ptr(datadir = test_get_argument(0)))
+        return 0;
+
+    privkey = test_mk_file_path(datadir, "rsakey.pem");
+    if (!TEST_ptr(privkey))
+        return 0;
+
     ADD_TEST(test_lock);
     ADD_TEST(test_once);
     ADD_TEST(test_thread_local);
     ADD_TEST(test_atomic);
-    ADD_ALL_TESTS(test_multi, 3);
+    ADD_ALL_TESTS(test_multi, 4);
     return 1;
 }
+
+void cleanup_tests(void)
+{
+    OPENSSL_free(privkey);
+}