Skip to content

Commit bd41f9a

Browse files
Add support for more SSL BIO functions (#2273)
Xtrabackup happens to take a dependency on some of OpenSSL's BIO_ssl methods. These are essentially helper BIOs that maintain an `SSL` within them. We have the necessary functionality available, this is just wrapping these BIOs around them. ### Testing: Ideally we would test against the "connect" BIO created within `BIO_new_ssl_connect` with `BIO_do_connect`, but this isn't quite easy since we do not have any BIO methods that set up sockets on the server end (`BIO_s_accept`). We have other mechanisms of doing so in our `bssl` tool and `ocsp_integration_tests`, but pulling the functionality over just to test these `BIO`s seemed a bit overkill for my liking. I've given my reasoning in the test comments, if we ever do support `BIO_s_accept` we can look to update the test. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and the ISC license.
1 parent ea052e5 commit bd41f9a

4 files changed

Lines changed: 120 additions & 13 deletions

File tree

include/openssl/bio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,7 @@ struct bio_st {
10351035
#define BIO_C_GET_FILE_PTR 107
10361036
#define BIO_C_SET_FILENAME 108
10371037
#define BIO_C_SET_SSL 109
1038+
#define BIO_C_GET_SSL 110
10381039
#define BIO_C_SET_MD 111
10391040
#define BIO_C_GET_MD 112
10401041
#define BIO_C_GET_CIPHER_STATUS 113

include/openssl/ssl.h

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5112,6 +5112,42 @@ OPENSSL_EXPORT int SSL_CTX_sess_timeouts(const SSL_CTX *ctx);
51125112
OPENSSL_EXPORT int SSL_CTX_sess_cache_full(const SSL_CTX *ctx);
51135113

51145114

5115+
// SSL BIO methods
5116+
5117+
// BIO_f_ssl returns a |BIO_METHOD| that can wrap an |SSL*| in a |BIO*|. Note
5118+
// that this has quite different behaviour from the version in OpenSSL (notably
5119+
// that it doesn't try to auto renegotiate). There is also no current support
5120+
// for the |BIO_set_ssl*| related functions in OpenSSL or |BIO_puts| with this
5121+
// BIO type within AWS-LC.
5122+
OPENSSL_EXPORT const BIO_METHOD *BIO_f_ssl(void);
5123+
5124+
// BIO_set_ssl sets |ssl| as the underlying connection for |bio|, which must
5125+
// have been created using |BIO_f_ssl|. If |take_owership| is true, |bio| will
5126+
// call |SSL_free| on |ssl| when closed. It returns one on success or something
5127+
// other than one on error.
5128+
OPENSSL_EXPORT long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership);
5129+
5130+
// BIO_get_ssl assigns the internal |SSL| of |bio| to |*ssl|. |*ssl| should
5131+
// not be freed. It returns one on success or something other than one on error.
5132+
OPENSSL_EXPORT long BIO_get_ssl(BIO *bio, SSL **ssl);
5133+
5134+
// BIO_new_ssl_connect uses |ctx| to return a newly allocated BIO chain with
5135+
// |BIO_new_ssl|, followed by a connect BIO.
5136+
//
5137+
// Note: This allocates a |BIO| with |BIO_f_ssl| to the user, so the same
5138+
// caveats hold true for this function as well. See |BIO_f_ssl| for more
5139+
// details.
5140+
OPENSSL_EXPORT BIO *BIO_new_ssl_connect(SSL_CTX *ctx);
5141+
5142+
// BIO_new_ssl returns a newly allocated SSL BIO created with |ctx|. A client
5143+
// SSL is created if |client| is non-zero, and a server is created if otherwise.
5144+
//
5145+
// Note: This allocates a |BIO| with |BIO_f_ssl| to the user, so the same
5146+
// caveats hold true for this function as well. See |BIO_f_ssl| for more
5147+
// details.
5148+
OPENSSL_EXPORT BIO *BIO_new_ssl(SSL_CTX *ctx, int client);
5149+
5150+
51155151
// Deprecated functions.
51165152

51175153
// SSL_library_init calls |CRYPTO_library_init| and returns one.
@@ -5509,19 +5545,6 @@ OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx);
55095545
// SSL_enable_tls_channel_id calls |SSL_set_tls_channel_id_enabled|.
55105546
OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl);
55115547

5512-
// BIO_f_ssl returns a |BIO_METHOD| that can wrap an |SSL*| in a |BIO*|. Note
5513-
// that this has quite different behaviour from the version in OpenSSL (notably
5514-
// that it doesn't try to auto renegotiate).
5515-
//
5516-
// IMPORTANT: if you are not curl, don't use this.
5517-
OPENSSL_EXPORT const BIO_METHOD *BIO_f_ssl(void);
5518-
5519-
// BIO_set_ssl sets |ssl| as the underlying connection for |bio|, which must
5520-
// have been created using |BIO_f_ssl|. If |take_owership| is true, |bio| will
5521-
// call |SSL_free| on |ssl| when closed. It returns one on success or something
5522-
// other than one on error.
5523-
OPENSSL_EXPORT long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership);
5524-
55255548
// SSL_get_session returns a non-owning pointer to |ssl|'s session. For
55265549
// historical reasons, which session it returns depends on |ssl|'s state.
55275550
//

ssl/bio_ssl.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,14 @@ static long ssl_ctrl(BIO *bio, int cmd, long num, void *ptr) {
114114
bio->init = 1;
115115
return 1;
116116

117+
case BIO_C_GET_SSL:
118+
if (ptr != nullptr) {
119+
auto sslp = static_cast<SSL **>(ptr);
120+
*sslp = ssl;
121+
return 1;
122+
}
123+
return 0;
124+
117125
case BIO_CTRL_GET_CLOSE:
118126
return bio->shutdown;
119127

@@ -190,3 +198,44 @@ const BIO_METHOD *BIO_f_ssl(void) { return &ssl_method; }
190198
long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership) {
191199
return BIO_ctrl(bio, BIO_C_SET_SSL, take_owership, ssl);
192200
}
201+
202+
long BIO_get_ssl(BIO *bio, SSL **ssl) {
203+
return BIO_ctrl(bio, BIO_C_GET_SSL, 0, ssl);
204+
}
205+
206+
BIO *BIO_new_ssl_connect(SSL_CTX *ctx) {
207+
bssl::UniquePtr<BIO> con(BIO_new(BIO_s_connect()));
208+
bssl::UniquePtr<BIO> ssl(BIO_new_ssl(ctx, 1));
209+
if (!con || !ssl) {
210+
return nullptr;
211+
}
212+
bssl::UniquePtr<BIO> ret(BIO_push(ssl.get(), con.get()));
213+
if (!ret) {
214+
return nullptr;
215+
}
216+
217+
con.release();
218+
ssl.release();
219+
return ret.release();
220+
}
221+
222+
BIO *BIO_new_ssl(SSL_CTX *ctx, int client) {
223+
bssl::UniquePtr<BIO> ret(BIO_new(BIO_f_ssl()));
224+
SSL *ssl = SSL_new(ctx);
225+
226+
if (!ret || !ssl) {
227+
return nullptr;
228+
}
229+
if (client) {
230+
SSL_set_connect_state(ssl);
231+
} else {
232+
SSL_set_accept_state(ssl);
233+
}
234+
235+
if (BIO_set_ssl(ret.get(), ssl, BIO_CLOSE) <= 0) {
236+
return nullptr;
237+
}
238+
return ret.release();
239+
}
240+
241+

ssl/ssl_test.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11148,6 +11148,40 @@ TEST(SSLTest, BIO) {
1114811148
}
1114911149
}
1115011150

11151+
TEST(SSLTest, BIO_2) {
11152+
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
11153+
bssl::UniquePtr<SSL_CTX> server_ctx(
11154+
CreateContextWithTestCertificate(TLS_method()));
11155+
ASSERT_TRUE(client_ctx);
11156+
ASSERT_TRUE(server_ctx);
11157+
11158+
bssl::UniquePtr<BIO> server_bio(BIO_new_ssl(server_ctx.get(), 0));
11159+
bssl::UniquePtr<BIO> client_bio(BIO_new_ssl_connect(client_ctx.get()));
11160+
ASSERT_TRUE(server_bio);
11161+
ASSERT_TRUE(client_bio);
11162+
11163+
SSL *server_ssl_ptr, *client_ssl_ptr;
11164+
ASSERT_TRUE(BIO_get_ssl(server_bio.get(), &server_ssl_ptr));
11165+
ASSERT_TRUE(BIO_get_ssl(client_bio.get(), &client_ssl_ptr));
11166+
ASSERT_TRUE(server_ssl_ptr);
11167+
ASSERT_TRUE(client_ssl_ptr);
11168+
11169+
// Client SSL BIOs typically establish connections to a host using
11170+
// |BIO_do_connect|, which leverages the underlying connect |BIO| for socket
11171+
// management. While OpenSSL provides |BIO_new_accept| and |BIO_s_accept| for
11172+
// server-side socket setup, we haven't yet implemented this functionality.
11173+
// For these tests, we opt for traditional SSL connection methods instead
11174+
// until we have support for server-side socket management via |BIO|s.
11175+
// Adding full socket management on the server side would exceed the scope of
11176+
// testing |BIO_new_ssl(_connect)|, especially since we have dedicated tests
11177+
// elsewhere that verify |BIO_do_connect|'s correctness.
11178+
BIO *bio1, *bio2;
11179+
ASSERT_TRUE(BIO_new_bio_pair(&bio1, 0, &bio2, 0));
11180+
SSL_set_bio(client_ssl_ptr, bio1, bio1);
11181+
SSL_set_bio(server_ssl_ptr, bio2, bio2);
11182+
ASSERT_TRUE(CompleteHandshakes(client_ssl_ptr, server_ssl_ptr));
11183+
}
11184+
1115111185
TEST(SSLTest, ALPNConfig) {
1115211186
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
1115311187
ASSERT_TRUE(ctx);

0 commit comments

Comments
 (0)