Issue #384: compatibility with OpenSSL 1.1.0

* Direct usage of BIO struct members is removed for new versions of
  OpenSSL.
* Workaround for double BIO free in SSL_free() was updated to work
  with new and old OpenSSL versions.
* Note that this patch only fixes compatibilty when building with
  configure option "--disable-runtime-loading" (like it is done
  for Debia package.).
This commit is contained in:
Luka Krajger 2016-10-08 16:10:33 +02:00
parent d4bd77ca45
commit d0d8c58882
2 changed files with 25 additions and 16 deletions

View file

@ -100,6 +100,7 @@ BIO_METHOD * (*BIO_f_buffer)(void);
void (*BIO_free_all)(BIO *); void (*BIO_free_all)(BIO *);
BIO * (*BIO_new)(BIO_METHOD *); BIO * (*BIO_new)(BIO_METHOD *);
BIO * (*BIO_new_socket)(int, int); BIO * (*BIO_new_socket)(int, int);
BIO * (*BIO_next)(BIO *);
BIO * (*BIO_pop)(BIO *); BIO * (*BIO_pop)(BIO *);
BIO * (*BIO_push)(BIO *, BIO *); BIO * (*BIO_push)(BIO *, BIO *);
#if defined(HAVE_OPENSSL_EC) #if defined(HAVE_OPENSSL_EC)
@ -280,6 +281,7 @@ static void loadSSL(void) {
{ { &BIO_free_all }, "BIO_free_all" }, { { &BIO_free_all }, "BIO_free_all" },
{ { &BIO_new }, "BIO_new" }, { { &BIO_new }, "BIO_new" },
{ { &BIO_new_socket }, "BIO_new_socket" }, { { &BIO_new_socket }, "BIO_new_socket" },
{ { &BIO_next }, "BIO_next" },
{ { &BIO_pop }, "BIO_pop" }, { { &BIO_pop }, "BIO_pop" },
{ { &BIO_push }, "BIO_push" }, { { &BIO_push }, "BIO_push" },
{ { &ERR_clear_error }, "ERR_clear_error" }, { { &ERR_clear_error }, "ERR_clear_error" },
@ -1013,6 +1015,14 @@ int sslPromoteToSSL(struct SSLSupport *ssl, SSL **sslHndl, int fd,
#endif #endif
} }
BIO *sslGetNextBIO(BIO *b) {
#if OPENSSL_VERSION_NUMBER <= 0x10100000L
return b->next_bio;
#else
return BIO_next(b);
#endif
}
void sslFreeHndl(SSL **sslHndl) { void sslFreeHndl(SSL **sslHndl) {
#if defined(HAVE_OPENSSL) #if defined(HAVE_OPENSSL)
if (*sslHndl) { if (*sslHndl) {
@ -1020,24 +1030,23 @@ void sslFreeHndl(SSL **sslHndl) {
// BIOs. This is particularly a problem if an SSL connection has two // BIOs. This is particularly a problem if an SSL connection has two
// different BIOs for the read and the write end, with one being a stacked // different BIOs for the read and the write end, with one being a stacked
// derivative of the other. Unfortunately, this is exactly the scenario // derivative of the other. Unfortunately, this is exactly the scenario
// that we set up. // that we set up with call to "BIO_push(readBIO, writeBIO)" in function
// "sslPromoteToSSL()".
// As a work-around, we un-stack the BIOs prior to freeing the SSL // As a work-around, we un-stack the BIOs prior to freeing the SSL
// connection. // connection.
debug("[ssl] Freeing SSL handle.");
ERR_clear_error(); ERR_clear_error();
BIO *writeBIO, *readBIO; BIO *writeBIO, *readBIO;
check(writeBIO = SSL_get_wbio(*sslHndl)); check(writeBIO = SSL_get_wbio(*sslHndl));
check(readBIO = SSL_get_rbio(*sslHndl)); check(readBIO = SSL_get_rbio(*sslHndl));
if (writeBIO != readBIO) { if (writeBIO != readBIO) {
if (readBIO->next_bio == writeBIO) { if (sslGetNextBIO(readBIO) == writeBIO) {
// OK, that's exactly the bug we are looking for. We know how to // OK, that's exactly the bug we are looking for. We know that
// fix it. // writeBIO needs to be removed from readBIO chain.
debug("[ssl] Removing stacked write BIO!");
check(BIO_pop(readBIO) == writeBIO); check(BIO_pop(readBIO) == writeBIO);
check(readBIO->references == 1); check(!sslGetNextBIO(readBIO));
check(writeBIO->references == 1); } else if (sslGetNextBIO(readBIO) == sslGetNextBIO(writeBIO)) {
check(!readBIO->next_bio);
check(!writeBIO->prev_bio);
} else if (readBIO->next_bio == writeBIO->next_bio &&
writeBIO->next_bio->prev_bio == writeBIO) {
// Things get even more confused, if the SSL handshake is aborted // Things get even more confused, if the SSL handshake is aborted
// prematurely. // prematurely.
// OpenSSL appears to internally stack a BIO onto the read end that // OpenSSL appears to internally stack a BIO onto the read end that
@ -1046,15 +1055,13 @@ void sslFreeHndl(SSL **sslHndl) {
// reading and one for writing). In this case, not only is the // reading and one for writing). In this case, not only is the
// reference count wrong, but the chain of next_bio/prev_bio pairs // reference count wrong, but the chain of next_bio/prev_bio pairs
// is corrupted, too. // is corrupted, too.
warn("[ssl] Removing stacked socket BIO!");
BIO *sockBIO; BIO *sockBIO;
check(sockBIO = BIO_pop(readBIO)); check(sockBIO = BIO_pop(readBIO));
check(sockBIO == BIO_pop(writeBIO)); check(sockBIO == BIO_pop(writeBIO));
check(readBIO->references == 1); check(!sslGetNextBIO(readBIO));
check(writeBIO->references == 1); check(!sslGetNextBIO(writeBIO));
check(sockBIO->references == 1); check(!sslGetNextBIO(sockBIO));
check(!readBIO->next_bio);
check(!writeBIO->next_bio);
check(!sockBIO->prev_bio);
BIO_free_all(sockBIO); BIO_free_all(sockBIO);
} else { } else {
// We do not know, how to fix this situation. Something must have // We do not know, how to fix this situation. Something must have

View file

@ -82,6 +82,7 @@ extern BIO_METHOD *(*x_BIO_f_buffer)(void);
extern void (*x_BIO_free_all)(BIO *); extern void (*x_BIO_free_all)(BIO *);
extern BIO *(*x_BIO_new)(BIO_METHOD *); extern BIO *(*x_BIO_new)(BIO_METHOD *);
extern BIO *(*x_BIO_new_socket)(int, int); extern BIO *(*x_BIO_new_socket)(int, int);
extern BIO *(*x_BIO_next)(BIO *);
extern BIO *(*x_BIO_pop)(BIO *); extern BIO *(*x_BIO_pop)(BIO *);
extern BIO *(*x_BIO_push)(BIO *, BIO *); extern BIO *(*x_BIO_push)(BIO *, BIO *);
#if defined(HAVE_OPENSSL_EC) #if defined(HAVE_OPENSSL_EC)
@ -131,6 +132,7 @@ extern void *(*x_SSL_COMP_get_compression_methods)(void);
#define BIO_free_all x_BIO_free_all #define BIO_free_all x_BIO_free_all
#define BIO_new x_BIO_new #define BIO_new x_BIO_new
#define BIO_new_socket x_BIO_new_socket #define BIO_new_socket x_BIO_new_socket
#define BIO_next x_BIO_next
#define BIO_pop x_BIO_pop #define BIO_pop x_BIO_pop
#define BIO_push x_BIO_push #define BIO_push x_BIO_push
#define EC_KEY_free x_EC_KEY_free #define EC_KEY_free x_EC_KEY_free