diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c index cb25ae71c69..ad9ef3f8321 100644 --- a/crypto/x509/x509_lu.c +++ b/crypto/x509/x509_lu.c @@ -200,6 +200,16 @@ X509_STORE *X509_STORE_new(void) { return NULL; } +int X509_STORE_lock(X509_STORE *v) { + CRYPTO_MUTEX_lock_write(&v->objs_lock); + return 1; +} + +int X509_STORE_unlock(X509_STORE *v) { + CRYPTO_MUTEX_unlock_write(&v->objs_lock); + return 1; +} + int X509_STORE_up_ref(X509_STORE *store) { CRYPTO_refcount_inc(&store->references); return 1; @@ -410,6 +420,26 @@ X509_CRL *X509_OBJECT_get0_X509_CRL(const X509_OBJECT *a) { return a->data.crl; } +int X509_OBJECT_set1_X509(X509_OBJECT *a, X509 *obj) { + if (a == NULL || !X509_up_ref(obj)) { + return 0; + } + + a->type = X509_LU_X509; + a->data.x509 = obj; + return 1; +} + +int X509_OBJECT_set1_X509_CRL(X509_OBJECT *a, X509_CRL *obj) { + if (a == NULL || !X509_CRL_up_ref(obj)) { + return 0; + } + + a->type = X509_LU_CRL; + a->data.crl = obj; + return 1; +} + static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, int type, X509_NAME *name, int *pnmatch) { X509_OBJECT stmp; diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 910fc630222..6d8b34c8538 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -1945,6 +1946,24 @@ TEST(X509Test, TestCRL) { ASSERT_EQ(nullptr, X509_OBJECT_get0_X509_CRL(&invalidCRL)); } +TEST(X509Test, TestX509GettersSetters) { + bssl::UniquePtr obj(X509_OBJECT_new()); + bssl::UniquePtr x509(CertFromPEM(kCRLTestRoot)); + bssl::UniquePtr crl(CRLFromPEM(kBasicCRL)); + + ASSERT_TRUE(obj); + ASSERT_TRUE(x509); + ASSERT_TRUE(crl); + + EXPECT_EQ(0, X509_OBJECT_get0_X509(obj.get())); + EXPECT_EQ(0, X509_OBJECT_get0_X509_CRL(obj.get())); + + EXPECT_EQ(1, X509_OBJECT_set1_X509(obj.get(), x509.get())); + EXPECT_EQ(x509.get(), X509_OBJECT_get0_X509(obj.get())); + EXPECT_EQ(1, X509_OBJECT_set1_X509_CRL(obj.get(), crl.get())); + EXPECT_EQ(crl.get(), X509_OBJECT_get0_X509_CRL(obj.get())); +} + TEST(X509Test, ManyNamesAndConstraints) { bssl::UniquePtr many_constraints(CertFromPEM( GetTestData("crypto/x509/test/many_constraints.pem").c_str())); @@ -5022,12 +5041,40 @@ TEST(X509Test, AddDuplicates) { ASSERT_TRUE(a); ASSERT_TRUE(b); + // To begin, add the certs to the store. Subsequent adds will be duplicative. EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get())); EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get())); - EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get())); - EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get())); - EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get())); - EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get())); + + const size_t kNumThreads = 50; + std::vector threads; + for (size_t i = 0; i < kNumThreads; i++) { + threads.emplace_back([&] { + // Firstly, save off |i| in the thread's context. + const size_t idx = i; + // Sleep with some jitter to offset thread execution + uint8_t sleep_buf[1]; + ASSERT_TRUE(RAND_bytes(sleep_buf, sizeof(sleep_buf))); + std::this_thread::sleep_for(std::chrono::milliseconds(sleep_buf[0] % 100)); + // Half the threads add duplicate certs, the other half take a lock and + // look them up to exercise un/locking functions. + if (idx % 2 == 0) { + EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get())); + EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get())); + } else { + ASSERT_TRUE(X509_STORE_lock(store.get())); + EXPECT_TRUE(X509_OBJECT_retrieve_by_subject( + store->objs, X509_LU_X509, X509_get_subject_name(a.get()) + )); + EXPECT_TRUE(X509_OBJECT_retrieve_by_subject( + store->objs, X509_LU_X509, X509_get_subject_name(b.get()) + )); + ASSERT_TRUE(X509_STORE_unlock(store.get())); + } + }); + } + for (auto &thread : threads) { + thread.join(); + } EXPECT_EQ(sk_X509_OBJECT_num(X509_STORE_get0_objects(store.get())), 2u); } diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 5068f0aef79..46dcdd0f442 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -2800,7 +2800,11 @@ OPENSSL_EXPORT int X509_OBJECT_get_type(const X509_OBJECT *a); OPENSSL_EXPORT X509 *X509_OBJECT_get0_X509(const X509_OBJECT *a); // X509_OBJECT_get0_X509_CRL returns the |X509_CRL| associated with |a| OPENSSL_EXPORT X509_CRL *X509_OBJECT_get0_X509_CRL(const X509_OBJECT *a); +int X509_OBJECT_set1_X509(X509_OBJECT *a, X509 *obj); +int X509_OBJECT_set1_X509_CRL(X509_OBJECT *a, X509_CRL *obj); OPENSSL_EXPORT X509_STORE *X509_STORE_new(void); +OPENSSL_EXPORT int X509_STORE_lock(X509_STORE *v); +OPENSSL_EXPORT int X509_STORE_unlock(X509_STORE *v); OPENSSL_EXPORT int X509_STORE_up_ref(X509_STORE *store); OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v); @@ -3122,6 +3126,7 @@ BORINGSSL_MAKE_UP_REF(X509_CRL, X509_CRL_up_ref) BORINGSSL_MAKE_DELETER(X509_EXTENSION, X509_EXTENSION_free) BORINGSSL_MAKE_DELETER(X509_INFO, X509_INFO_free) BORINGSSL_MAKE_DELETER(X509_LOOKUP, X509_LOOKUP_free) +BORINGSSL_MAKE_DELETER(X509_OBJECT, X509_OBJECT_free) BORINGSSL_MAKE_DELETER(X509_NAME, X509_NAME_free) BORINGSSL_MAKE_DELETER(X509_NAME_ENTRY, X509_NAME_ENTRY_free) BORINGSSL_MAKE_DELETER(X509_PKEY, X509_PKEY_free)