diff --git a/crypto/stack/stack.c b/crypto/stack/stack.c index 80d2fce5ed5..9d95d3e0967 100644 --- a/crypto/stack/stack.c +++ b/crypto/stack/stack.c @@ -338,6 +338,10 @@ int OPENSSL_sk_find(const OPENSSL_STACK *sk, size_t *out_index, const void *p, return 0; // Not found. } +int OPENSSL_sk_unshift(OPENSSL_STACK *sk, void *data) { + return (int)OPENSSL_sk_insert(sk, data, 0); +} + void *OPENSSL_sk_shift(OPENSSL_STACK *sk) { if (sk == NULL) { return NULL; diff --git a/crypto/stack/stack_test.cc b/crypto/stack/stack_test.cc index 3d6357f2e91..6f15a74ca78 100644 --- a/crypto/stack/stack_test.cc +++ b/crypto/stack/stack_test.cc @@ -153,6 +153,16 @@ TEST(StackTest, Basic) { EXPECT_EQ(raw, removed.get()); ExpectStackEquals(sk.get(), {1, 2, 4, 5, 7}); + // Test using "unshift" to insert at the beginning. + value = TEST_INT_new(8); + ASSERT_TRUE(value); + ASSERT_TRUE(sk_TEST_INT_unshift(sk.get(), value.get())); + value.release(); // sk_TEST_INT_unshift takes ownership on success. + ExpectStackEquals(sk.get(), {8, 1, 2, 4, 5, 7}); + removed.reset(sk_TEST_INT_shift(sk.get())); + EXPECT_EQ(8, *removed); + ExpectStackEquals(sk.get(), {1, 2, 4, 5, 7}); + // Deleting is a no-op is the object is not found. value = TEST_INT_new(100); ASSERT_TRUE(value); diff --git a/crypto/x509/x509_req.c b/crypto/x509/x509_req.c index 9745cba9f2c..c50aaf3dc98 100644 --- a/crypto/x509/x509_req.c +++ b/crypto/x509/x509_req.c @@ -83,6 +83,13 @@ EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req) { return (X509_PUBKEY_get(req->req_info->pubkey)); } +EVP_PKEY *X509_REQ_get0_pubkey(X509_REQ *req) { + if ((req == NULL) || (req->req_info == NULL)) { + return NULL; + } + return (X509_PUBKEY_get0(req->req_info->pubkey)); +} + int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k) { EVP_PKEY *xk = NULL; int ok = 0; diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 7bcef522c18..3ebe75d9b55 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2947,6 +2947,10 @@ OPENSSL_EXPORT int SSL_set_trust(SSL *ssl, int trust); // See also |SSL_MODE_NO_AUTO_CHAIN|. OPENSSL_EXPORT void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store); +// SSL_CTX_set1_cert_store is like |SSL_CTX_set_cert_store|, but does not take +// additional ownership of |store|. +OPENSSL_EXPORT void SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store); + // SSL_CTX_get_cert_store returns |ctx|'s certificate store. OPENSSL_EXPORT X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); diff --git a/include/openssl/stack.h b/include/openssl/stack.h index 9c96eed4b30..bb82e7eb867 100644 --- a/include/openssl/stack.h +++ b/include/openssl/stack.h @@ -168,7 +168,7 @@ void sk_SAMPLE_pop_free(STACK_OF(SAMPLE) *sk, sk_SAMPLE_free_func free_func); // sk_SAMPLE_insert inserts |p| into the stack at index |where|, moving existing // elements if needed. It returns the length of the new stack, or zero on -// error. +// error. Ownership of |p| is taken by |sk|. size_t sk_SAMPLE_insert(STACK_OF(SAMPLE) *sk, SAMPLE *p, size_t where); // sk_SAMPLE_delete removes the pointer at index |where|, moving other elements @@ -210,6 +210,10 @@ int sk_SAMPLE_find(const STACK_OF(SAMPLE) *sk, const SAMPLE *p); int sk_SAMPLE_find_awslc(const STACK_OF(SAMPLE) *sk, size_t *out_index, const SAMPLE *p); +// sk_SAMPLE_unshift inserts |p| as the first element of |sk| and takes +// ownership of |p|. It is equivalent to "sk_SAMPLE_insert(sk, p, 0)". +SAMPLE *sk_SAMPLE_unshift(STACK_OF(SAMPLE) *sk, SAMPLE *p); + // sk_SAMPLE_shift removes and returns the first element in |sk|, or NULL if // |sk| is empty. SAMPLE *sk_SAMPLE_shift(STACK_OF(SAMPLE) *sk); @@ -318,6 +322,7 @@ OPENSSL_EXPORT void OPENSSL_sk_delete_if( OPENSSL_EXPORT int OPENSSL_sk_find(const OPENSSL_STACK *sk, size_t *out_index, const void *p, OPENSSL_sk_call_cmp_func call_cmp_func); +OPENSSL_EXPORT int OPENSSL_sk_unshift(OPENSSL_STACK *sk, void *data); OPENSSL_EXPORT void *OPENSSL_sk_shift(OPENSSL_STACK *sk); OPENSSL_EXPORT size_t OPENSSL_sk_push(OPENSSL_STACK *sk, void *p); OPENSSL_EXPORT void *OPENSSL_sk_pop(OPENSSL_STACK *sk); @@ -517,6 +522,10 @@ BSSL_NAMESPACE_END return (int) out_index; \ } \ \ + OPENSSL_INLINE int sk_##name##_unshift(STACK_OF(name) *sk, ptrtype p) { \ + return OPENSSL_sk_unshift((OPENSSL_STACK *)sk, (void *)p); \ + } \ + \ OPENSSL_INLINE ptrtype sk_##name##_shift(STACK_OF(name) *sk) { \ return (ptrtype)OPENSSL_sk_shift((OPENSSL_STACK *)sk); \ } \ diff --git a/include/openssl/x509.h b/include/openssl/x509.h index efa160214b3..de8ed006314 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -749,6 +749,10 @@ OPENSSL_EXPORT X509_NAME *X509_REQ_get_subject_name(const X509_REQ *req); // |EVP_PKEY_free| when done. OPENSSL_EXPORT EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req); +// X509_REQ_get0_pubkey is like |X509_REQ_get_pubkey|, but directly returns the +// reference to |req|. The caller must not free the result after use. +OPENSSL_EXPORT EVP_PKEY *X509_REQ_get0_pubkey(X509_REQ *req); + // X509_REQ_get_attr_count returns the number of attributes in |req|. OPENSSL_EXPORT int X509_REQ_get_attr_count(const X509_REQ *req); diff --git a/ssl/ssl_x509.cc b/ssl/ssl_x509.cc index 88e3eabc78a..98060f1bf36 100644 --- a/ssl/ssl_x509.cc +++ b/ssl/ssl_x509.cc @@ -765,6 +765,14 @@ void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) { ctx->cert_store = store; } +void SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store) { + check_ssl_ctx_x509_method(ctx); + if (store != nullptr) { + X509_STORE_up_ref(store); + } + SSL_CTX_set_cert_store(ctx, store); +} + static int ssl_use_certificate(CERT *cert, X509 *x) { if (x == nullptr) { OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);