Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/openssl/bio.h
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ struct bio_st {
#define BIO_C_GET_FILE_PTR 107
#define BIO_C_SET_FILENAME 108
#define BIO_C_SET_SSL 109
#define BIO_C_GET_SSL 110
#define BIO_C_SET_MD 111
#define BIO_C_GET_MD 112
#define BIO_C_GET_CIPHER_STATUS 113
Expand Down
49 changes: 36 additions & 13 deletions include/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5112,6 +5112,42 @@ OPENSSL_EXPORT int SSL_CTX_sess_timeouts(const SSL_CTX *ctx);
OPENSSL_EXPORT int SSL_CTX_sess_cache_full(const SSL_CTX *ctx);


// SSL BIO methods

// BIO_f_ssl returns a |BIO_METHOD| that can wrap an |SSL*| in a |BIO*|. Note
// that this has quite different behaviour from the version in OpenSSL (notably
// that it doesn't try to auto renegotiate). There is also no current support
// for the |BIO_set_ssl*| related functions in OpenSSL or |BIO_puts| with this
// BIO type within AWS-LC.
OPENSSL_EXPORT const BIO_METHOD *BIO_f_ssl(void);

// BIO_set_ssl sets |ssl| as the underlying connection for |bio|, which must
// have been created using |BIO_f_ssl|. If |take_owership| is true, |bio| will
// call |SSL_free| on |ssl| when closed. It returns one on success or something
// other than one on error.
OPENSSL_EXPORT long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership);

// BIO_get_ssl assigns the internal |SSL| of |bio| to |*ssl|. |*ssl| should
// not be freed. It returns one on success or something other than one on error.
OPENSSL_EXPORT long BIO_get_ssl(BIO *bio, SSL **ssl);

// BIO_new_ssl_connect uses |ctx| to return a newly allocated BIO chain with
// |BIO_new_ssl|, followed by a connect BIO.
//
// Note: This allocates a |BIO| with |BIO_f_ssl| to the user, so the same
// caveats hold true for this function as well. See |BIO_f_ssl| for more
// details.
OPENSSL_EXPORT BIO *BIO_new_ssl_connect(SSL_CTX *ctx);

// BIO_new_ssl returns a newly allocated SSL BIO created with |ctx|. A client
// SSL is created if |client| is non-zero, and a server is created if otherwise.
//
// Note: This allocates a |BIO| with |BIO_f_ssl| to the user, so the same
// caveats hold true for this function as well. See |BIO_f_ssl| for more
// details.
OPENSSL_EXPORT BIO *BIO_new_ssl(SSL_CTX *ctx, int client);


// Deprecated functions.

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

// BIO_f_ssl returns a |BIO_METHOD| that can wrap an |SSL*| in a |BIO*|. Note
// that this has quite different behaviour from the version in OpenSSL (notably
// that it doesn't try to auto renegotiate).
//
// IMPORTANT: if you are not curl, don't use this.
OPENSSL_EXPORT const BIO_METHOD *BIO_f_ssl(void);

// BIO_set_ssl sets |ssl| as the underlying connection for |bio|, which must
// have been created using |BIO_f_ssl|. If |take_owership| is true, |bio| will
// call |SSL_free| on |ssl| when closed. It returns one on success or something
// other than one on error.
OPENSSL_EXPORT long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership);

// SSL_get_session returns a non-owning pointer to |ssl|'s session. For
// historical reasons, which session it returns depends on |ssl|'s state.
//
Expand Down
49 changes: 49 additions & 0 deletions ssl/bio_ssl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ static long ssl_ctrl(BIO *bio, int cmd, long num, void *ptr) {
bio->init = 1;
return 1;

case BIO_C_GET_SSL:
if (ptr != nullptr) {
auto sslp = static_cast<SSL **>(ptr);
*sslp = ssl;
return 1;
}
return 0;

case BIO_CTRL_GET_CLOSE:
return bio->shutdown;

Expand Down Expand Up @@ -190,3 +198,44 @@ const BIO_METHOD *BIO_f_ssl(void) { return &ssl_method; }
long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership) {
return BIO_ctrl(bio, BIO_C_SET_SSL, take_owership, ssl);
}

long BIO_get_ssl(BIO *bio, SSL **ssl) {
return BIO_ctrl(bio, BIO_C_GET_SSL, 0, ssl);
}

BIO *BIO_new_ssl_connect(SSL_CTX *ctx) {
bssl::UniquePtr<BIO> con(BIO_new(BIO_s_connect()));
bssl::UniquePtr<BIO> ssl(BIO_new_ssl(ctx, 1));
if (!con || !ssl) {
return nullptr;
}
bssl::UniquePtr<BIO> ret(BIO_push(ssl.get(), con.get()));
if (!ret) {
return nullptr;
}

con.release();
ssl.release();
return ret.release();
}

BIO *BIO_new_ssl(SSL_CTX *ctx, int client) {
bssl::UniquePtr<BIO> ret(BIO_new(BIO_f_ssl()));
SSL *ssl = SSL_new(ctx);

if (!ret || !ssl) {
return nullptr;
}
if (client) {
SSL_set_connect_state(ssl);
} else {
SSL_set_accept_state(ssl);
}

if (BIO_set_ssl(ret.get(), ssl, BIO_CLOSE) <= 0) {
return nullptr;
}
return ret.release();
}


34 changes: 34 additions & 0 deletions ssl/ssl_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11148,6 +11148,40 @@ TEST(SSLTest, BIO) {
}
}

TEST(SSLTest, BIO_2) {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
bssl::UniquePtr<SSL_CTX> server_ctx(
CreateContextWithTestCertificate(TLS_method()));
ASSERT_TRUE(client_ctx);
ASSERT_TRUE(server_ctx);

bssl::UniquePtr<BIO> server_bio(BIO_new_ssl(server_ctx.get(), 0));
bssl::UniquePtr<BIO> client_bio(BIO_new_ssl_connect(client_ctx.get()));
ASSERT_TRUE(server_bio);
ASSERT_TRUE(client_bio);

SSL *server_ssl_ptr, *client_ssl_ptr;
ASSERT_TRUE(BIO_get_ssl(server_bio.get(), &server_ssl_ptr));
ASSERT_TRUE(BIO_get_ssl(client_bio.get(), &client_ssl_ptr));
ASSERT_TRUE(server_ssl_ptr);
ASSERT_TRUE(client_ssl_ptr);

// Client SSL BIOs typically establish connections to a host using
// |BIO_do_connect|, which leverages the underlying connect |BIO| for socket
// management. While OpenSSL provides |BIO_new_accept| and |BIO_s_accept| for
// server-side socket setup, we haven't yet implemented this functionality.
// For these tests, we opt for traditional SSL connection methods instead
// until we have support for server-side socket management via |BIO|s.
// Adding full socket management on the server side would exceed the scope of
// testing |BIO_new_ssl(_connect)|, especially since we have dedicated tests
// elsewhere that verify |BIO_do_connect|'s correctness.
BIO *bio1, *bio2;
ASSERT_TRUE(BIO_new_bio_pair(&bio1, 0, &bio2, 0));
SSL_set_bio(client_ssl_ptr, bio1, bio1);
SSL_set_bio(server_ssl_ptr, bio2, bio2);
ASSERT_TRUE(CompleteHandshakes(client_ssl_ptr, server_ssl_ptr));
}

TEST(SSLTest, ALPNConfig) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
ASSERT_TRUE(ctx);
Expand Down
Loading