Skip to content

Commit 6bc2e52

Browse files
Add misc. x509 un/lock and set1 functions (aws#1449)
1 parent ef6d5a4 commit 6bc2e52

File tree

7 files changed

+144
-8
lines changed

7 files changed

+144
-8
lines changed

.github/workflows/integrations.yml

+13-2
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ jobs:
9191
- name: Run integration build
9292
run: |
9393
./tests/ci/integration/run_socat_integration.sh
94-
python:
94+
python-main:
9595
runs-on: ubuntu-latest
9696
steps:
9797
- name: Install OS Dependencies
@@ -101,7 +101,18 @@ jobs:
101101
- uses: actions/checkout@v3
102102
- name: Build AWS-LC, build python, run tests
103103
run: |
104-
./tests/ci/integration/run_python_integration.sh
104+
./tests/ci/integration/run_python_integration.sh main
105+
python-releases:
106+
runs-on: ubuntu-latest
107+
steps:
108+
- name: Install OS Dependencies
109+
run: |
110+
sudo apt-get update
111+
sudo apt-get -y --no-install-recommends install cmake gcc ninja-build golang make
112+
- uses: actions/checkout@v3
113+
- name: Build AWS-LC, build python, run tests
114+
run: |
115+
./tests/ci/integration/run_python_integration.sh 3.10 3.11 3.12
105116
bind9:
106117
runs-on: ubuntu-latest
107118
steps:

crypto/x509/x509_lu.c

+38
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,22 @@ X509_STORE *X509_STORE_new(void) {
196196
return NULL;
197197
}
198198

199+
int X509_STORE_lock(X509_STORE *v) {
200+
if (v == NULL) {
201+
return 0;
202+
}
203+
CRYPTO_MUTEX_lock_write(&v->objs_lock);
204+
return 1;
205+
}
206+
207+
int X509_STORE_unlock(X509_STORE *v) {
208+
if (v == NULL) {
209+
return 0;
210+
}
211+
CRYPTO_MUTEX_unlock_write(&v->objs_lock);
212+
return 1;
213+
}
214+
199215
int X509_STORE_up_ref(X509_STORE *store) {
200216
CRYPTO_refcount_inc(&store->references);
201217
return 1;
@@ -405,6 +421,28 @@ X509_CRL *X509_OBJECT_get0_X509_CRL(const X509_OBJECT *a) {
405421
return a->data.crl;
406422
}
407423

424+
int X509_OBJECT_set1_X509(X509_OBJECT *a, X509 *obj) {
425+
if (a == NULL || !X509_up_ref(obj)) {
426+
return 0;
427+
}
428+
429+
X509_OBJECT_free_contents(a);
430+
a->type = X509_LU_X509;
431+
a->data.x509 = obj;
432+
return 1;
433+
}
434+
435+
int X509_OBJECT_set1_X509_CRL(X509_OBJECT *a, X509_CRL *obj) {
436+
if (a == NULL || !X509_CRL_up_ref(obj)) {
437+
return 0;
438+
}
439+
440+
X509_OBJECT_free_contents(a);
441+
a->type = X509_LU_CRL;
442+
a->data.crl = obj;
443+
return 1;
444+
}
445+
408446
static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, int type,
409447
X509_NAME *name, int *pnmatch) {
410448
X509_OBJECT stmp;

crypto/x509/x509_test.cc

+57-4
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <openssl/nid.h>
3131
#include <openssl/pem.h>
3232
#include <openssl/pool.h>
33+
#include <openssl/rand.h>
3334
#include <openssl/x509.h>
3435
#include <openssl/x509v3.h>
3536

@@ -1945,6 +1946,26 @@ TEST(X509Test, TestCRL) {
19451946
ASSERT_EQ(nullptr, X509_OBJECT_get0_X509_CRL(&invalidCRL));
19461947
}
19471948

1949+
TEST(X509Test, TestX509GettersSetters) {
1950+
bssl::UniquePtr<X509_OBJECT> obj(X509_OBJECT_new());
1951+
bssl::UniquePtr<X509> x509(CertFromPEM(kCRLTestRoot));
1952+
bssl::UniquePtr<X509_CRL> crl(CRLFromPEM(kBasicCRL));
1953+
1954+
ASSERT_TRUE(obj);
1955+
ASSERT_TRUE(x509);
1956+
ASSERT_TRUE(crl);
1957+
1958+
EXPECT_EQ(0, X509_OBJECT_get0_X509(obj.get()));
1959+
EXPECT_EQ(0, X509_OBJECT_get0_X509_CRL(obj.get()));
1960+
EXPECT_EQ(0, X509_OBJECT_set1_X509(nullptr, x509.get()));
1961+
EXPECT_EQ(0, X509_OBJECT_set1_X509_CRL(nullptr, crl.get()));
1962+
1963+
EXPECT_EQ(1, X509_OBJECT_set1_X509(obj.get(), x509.get()));
1964+
EXPECT_EQ(x509.get(), X509_OBJECT_get0_X509(obj.get()));
1965+
EXPECT_EQ(1, X509_OBJECT_set1_X509_CRL(obj.get(), crl.get()));
1966+
EXPECT_EQ(crl.get(), X509_OBJECT_get0_X509_CRL(obj.get()));
1967+
}
1968+
19481969
TEST(X509Test, ManyNamesAndConstraints) {
19491970
bssl::UniquePtr<X509> many_constraints(CertFromPEM(
19501971
GetTestData("crypto/x509/test/many_constraints.pem").c_str()));
@@ -5022,12 +5043,44 @@ TEST(X509Test, AddDuplicates) {
50225043
ASSERT_TRUE(a);
50235044
ASSERT_TRUE(b);
50245045

5046+
// To begin, add the certs to the store. Subsequent adds will be duplicative.
50255047
EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get()));
50265048
EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get()));
5027-
EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get()));
5028-
EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get()));
5029-
EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get()));
5030-
EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get()));
5049+
5050+
// Half the threads add duplicate certs, the other half take a lock and
5051+
// look them up to exercise un/locking functions.
5052+
const size_t kNumThreads = 10;
5053+
std::vector<std::thread> threads;
5054+
for (size_t i = 0; i < kNumThreads/2; i++) {
5055+
threads.emplace_back([&] {
5056+
// Sleep with some jitter to offset thread execution
5057+
uint8_t sleep_buf[1];
5058+
ASSERT_TRUE(RAND_bytes(sleep_buf, sizeof(sleep_buf)));
5059+
std::this_thread::sleep_for(std::chrono::microseconds(1 + (sleep_buf[0] % 5)));
5060+
EXPECT_TRUE(X509_STORE_add_cert(store.get(), a.get()));
5061+
EXPECT_TRUE(X509_STORE_add_cert(store.get(), b.get()));
5062+
});
5063+
threads.emplace_back([&] {
5064+
uint8_t sleep_buf[1];
5065+
ASSERT_TRUE(RAND_bytes(sleep_buf, sizeof(sleep_buf)));
5066+
ASSERT_TRUE(X509_STORE_lock(store.get()));
5067+
// Sleep after taking the lock to cause contention. Sleep longer than the
5068+
// adder half of threads to ensure we hold the lock while they contend
5069+
// for it. |X509_OBJECT_retrieve_by_subject| is called because it doesn't
5070+
// take a lock on the store, thus avoiding deadlock.
5071+
std::this_thread::sleep_for(std::chrono::microseconds(11 + (sleep_buf[0] % 5)));
5072+
EXPECT_TRUE(X509_OBJECT_retrieve_by_subject(
5073+
store->objs, X509_LU_X509, X509_get_subject_name(a.get())
5074+
));
5075+
EXPECT_TRUE(X509_OBJECT_retrieve_by_subject(
5076+
store->objs, X509_LU_X509, X509_get_subject_name(b.get())
5077+
));
5078+
ASSERT_TRUE(X509_STORE_unlock(store.get()));
5079+
});
5080+
}
5081+
for (auto &thread : threads) {
5082+
thread.join();
5083+
}
50315084

50325085
EXPECT_EQ(sk_X509_OBJECT_num(X509_STORE_get0_objects(store.get())), 2u);
50335086
}

crypto/x509/x509cset.c

+3
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ int X509_CRL_sort(X509_CRL *c) {
138138
}
139139

140140
int X509_CRL_up_ref(X509_CRL *crl) {
141+
if (crl == NULL) {
142+
return 0;
143+
}
141144
CRYPTO_refcount_inc(&crl->references);
142145
return 1;
143146
}

crypto/x509/x_x509.c

+3
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,9 @@ X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf) {
198198
}
199199

200200
int X509_up_ref(X509 *x) {
201+
if (x == NULL) {
202+
return 0;
203+
}
201204
CRYPTO_refcount_inc(&x->references);
202205
return 1;
203206
}

include/openssl/x509.h

+20
Original file line numberDiff line numberDiff line change
@@ -2802,7 +2802,26 @@ OPENSSL_EXPORT int X509_OBJECT_get_type(const X509_OBJECT *a);
28022802
OPENSSL_EXPORT X509 *X509_OBJECT_get0_X509(const X509_OBJECT *a);
28032803
// X509_OBJECT_get0_X509_CRL returns the |X509_CRL| associated with |a|
28042804
OPENSSL_EXPORT X509_CRL *X509_OBJECT_get0_X509_CRL(const X509_OBJECT *a);
2805+
2806+
// X509_OBJECT_set1_X509 sets |obj| on |a| and uprefs |obj|. As with other set1
2807+
// methods, |a| does not take ownership of |obj|; the caller is responsible for
2808+
// managing freeing |obj| when appropriate.
2809+
OPENSSL_EXPORT int X509_OBJECT_set1_X509(X509_OBJECT *a, X509 *obj);
2810+
2811+
// X509_OBJECT_set1_X509_CRL sets CRL |obj| on |a| and uprefs |obj|. As with
2812+
// other set1 methods, |a| does not take ownership of |obj|; the caller is
2813+
// responsible for managing freeing |obj| when appropriate.
2814+
OPENSSL_EXPORT int X509_OBJECT_set1_X509_CRL(X509_OBJECT *a, X509_CRL *obj);
2815+
28052816
OPENSSL_EXPORT X509_STORE *X509_STORE_new(void);
2817+
// X509_STORE_lock takes a write lock on |v|. return 1 on success, 0 on failure.
2818+
//
2819+
// Avoid operations on the X509_STORE or a X509_STORE_CTX containing it while
2820+
// it is locked; many |X509_STORE_*| functions take this lock internally which
2821+
// will cause a deadlock when called on a locked store.
2822+
OPENSSL_EXPORT int X509_STORE_lock(X509_STORE *v);
2823+
// X509_STORE_unlock releases a lock on |v|. return 1 on success, 0 on failure
2824+
OPENSSL_EXPORT int X509_STORE_unlock(X509_STORE *v);
28062825
OPENSSL_EXPORT int X509_STORE_up_ref(X509_STORE *store);
28072826
OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v);
28082827

@@ -3124,6 +3143,7 @@ BORINGSSL_MAKE_UP_REF(X509_CRL, X509_CRL_up_ref)
31243143
BORINGSSL_MAKE_DELETER(X509_EXTENSION, X509_EXTENSION_free)
31253144
BORINGSSL_MAKE_DELETER(X509_INFO, X509_INFO_free)
31263145
BORINGSSL_MAKE_DELETER(X509_LOOKUP, X509_LOOKUP_free)
3146+
BORINGSSL_MAKE_DELETER(X509_OBJECT, X509_OBJECT_free)
31273147
BORINGSSL_MAKE_DELETER(X509_NAME, X509_NAME_free)
31283148
BORINGSSL_MAKE_DELETER(X509_NAME_ENTRY, X509_NAME_ENTRY_free)
31293149
BORINGSSL_MAKE_DELETER(X509_PKEY, X509_PKEY_free)

tests/ci/integration/run_python_integration.sh

+10-2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ function python_patch() {
9595
local branch=${1}
9696
local src_dir="${PYTHON_SRC_FOLDER}/${branch}"
9797
local patch_dir="${PYTHON_PATCH_FOLDER}/${branch}"
98+
if [[ ! $(find -L ${patch_dir} -type f -name '*.patch') ]]; then
99+
echo "No patch for ${branch}!"
100+
exit 1
101+
fi
98102
git clone https://github.com/python/cpython.git ${src_dir} \
99103
--depth 1 \
100104
--branch ${branch}
@@ -106,6 +110,11 @@ function python_patch() {
106110
done
107111
}
108112

113+
if [[ "$#" -eq "0" ]]; then
114+
echo "No python branches provided for testing"
115+
exit 1
116+
fi
117+
109118
mkdir -p ${SCRATCH_FOLDER}
110119
rm -rf ${SCRATCH_FOLDER}/*
111120
cd ${SCRATCH_FOLDER}
@@ -126,9 +135,8 @@ pushd ${PYTHON_SRC_FOLDER}
126135
which sysctl && ( sysctl -w net.ipv6.conf.all.disable_ipv6=0 || /bin/true )
127136
echo 0 >/proc/sys/net/ipv6/conf/all/disable_ipv6 || /bin/true
128137

129-
# NOTE: cpython keeps a unique branch per version, add version branches here
130138
# NOTE: As we add more versions to support, we may want to parallelize here
131-
for branch in 3.10 3.11 3.12 main; do
139+
for branch in "$@"; do
132140
python_patch ${branch}
133141
python_build ${branch}
134142
python_run_tests ${branch}

0 commit comments

Comments
 (0)