Commit 65d24fd7 by Carlos Martín Nieto Committed by Carlos Martín Nieto

Add support for OpenSSL 1.1.0 for BIO filter

parent 4cf1ec7c
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "posix.h" #include "posix.h"
#include "stream.h" #include "stream.h"
#include "socket_stream.h" #include "socket_stream.h"
#include "openssl_stream.h"
#include "netops.h" #include "netops.h"
#include "git2/transport.h" #include "git2/transport.h"
#include "git2/sys/openssl.h" #include "git2/sys/openssl.h"
...@@ -71,12 +72,20 @@ static void shutdown_ssl_locking(void) ...@@ -71,12 +72,20 @@ static void shutdown_ssl_locking(void)
#endif /* GIT_THREADS */ #endif /* GIT_THREADS */
static BIO_METHOD *git_stream_bio_method;
static int init_bio_method(void);
/** /**
* This function aims to clean-up the SSL context which * This function aims to clean-up the SSL context which
* we allocated. * we allocated.
*/ */
static void shutdown_ssl(void) static void shutdown_ssl(void)
{ {
if (git_stream_bio_method) {
BIO_meth_free(git_stream_bio_method);
git_stream_bio_method = NULL;
}
if (git__ssl_ctx) { if (git__ssl_ctx) {
SSL_CTX_free(git__ssl_ctx); SSL_CTX_free(git__ssl_ctx);
git__ssl_ctx = NULL; git__ssl_ctx = NULL;
...@@ -121,6 +130,13 @@ int git_openssl_stream_global_init(void) ...@@ -121,6 +130,13 @@ int git_openssl_stream_global_init(void)
git__ssl_ctx = NULL; git__ssl_ctx = NULL;
return -1; return -1;
} }
if (init_bio_method() < 0) {
SSL_CTX_free(git__ssl_ctx);
git__ssl_ctx = NULL;
return -1;
}
#endif #endif
git__on_shutdown(shutdown_ssl); git__on_shutdown(shutdown_ssl);
...@@ -156,10 +172,8 @@ int git_openssl_set_locking(void) ...@@ -156,10 +172,8 @@ int git_openssl_set_locking(void)
static int bio_create(BIO *b) static int bio_create(BIO *b)
{ {
b->init = 1; BIO_set_init(b, 1);
b->num = 0; BIO_set_data(b, NULL);
b->ptr = NULL;
b->flags = 0;
return 1; return 1;
} }
...@@ -169,23 +183,22 @@ static int bio_destroy(BIO *b) ...@@ -169,23 +183,22 @@ static int bio_destroy(BIO *b)
if (!b) if (!b)
return 0; return 0;
b->init = 0; BIO_set_data(b, NULL);
b->num = 0;
b->ptr = NULL;
b->flags = 0;
return 1; return 1;
} }
static int bio_read(BIO *b, char *buf, int len) static int bio_read(BIO *b, char *buf, int len)
{ {
git_stream *io = (git_stream *) b->ptr; git_stream *io = (git_stream *) BIO_get_data(b);
return (int) git_stream_read(io, buf, len); return (int) git_stream_read(io, buf, len);
} }
static int bio_write(BIO *b, const char *buf, int len) static int bio_write(BIO *b, const char *buf, int len)
{ {
git_stream *io = (git_stream *) b->ptr; git_stream *io = (git_stream *) BIO_get_data(b);
return (int) git_stream_write(io, buf, len, 0); return (int) git_stream_write(io, buf, len, 0);
} }
...@@ -214,17 +227,22 @@ static int bio_puts(BIO *b, const char *str) ...@@ -214,17 +227,22 @@ static int bio_puts(BIO *b, const char *str)
return bio_write(b, str, strlen(str)); return bio_write(b, str, strlen(str));
} }
static BIO_METHOD git_stream_bio_method = { static int init_bio_method(void)
BIO_TYPE_SOURCE_SINK, {
"git_stream", /* Set up the BIO_METHOD we use for wrapping our own stream implementations */
bio_write, git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream");
bio_read, GITERR_CHECK_ALLOC(git_stream_bio_method);
bio_puts,
bio_gets, BIO_meth_set_write(git_stream_bio_method, bio_write);
bio_ctrl, BIO_meth_set_read(git_stream_bio_method, bio_read);
bio_create, BIO_meth_set_puts(git_stream_bio_method, bio_puts);
bio_destroy BIO_meth_set_gets(git_stream_bio_method, bio_gets);
}; BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl);
BIO_meth_set_create(git_stream_bio_method, bio_create);
BIO_meth_set_destroy(git_stream_bio_method, bio_destroy);
return 0;
}
static int ssl_set_error(SSL *ssl, int error) static int ssl_set_error(SSL *ssl, int error)
{ {
...@@ -339,7 +357,7 @@ static int verify_server_cert(SSL *ssl, const char *host) ...@@ -339,7 +357,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
num = sk_GENERAL_NAME_num(alts); num = sk_GENERAL_NAME_num(alts);
for (i = 0; i < num && matched != 1; i++) { for (i = 0; i < num && matched != 1; i++) {
const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i); const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i);
const char *name = (char *) ASN1_STRING_data(gn->d.ia5); const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5);
size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5); size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5);
/* Skip any names of a type we're not looking for */ /* Skip any names of a type we're not looking for */
...@@ -394,7 +412,7 @@ static int verify_server_cert(SSL *ssl, const char *host) ...@@ -394,7 +412,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
if (size > 0) { if (size > 0) {
peer_cn = OPENSSL_malloc(size + 1); peer_cn = OPENSSL_malloc(size + 1);
GITERR_CHECK_ALLOC(peer_cn); GITERR_CHECK_ALLOC(peer_cn);
memcpy(peer_cn, ASN1_STRING_data(str), size); memcpy(peer_cn, ASN1_STRING_get0_data(str), size);
peer_cn[size] = '\0'; peer_cn[size] = '\0';
} else { } else {
goto cert_fail_name; goto cert_fail_name;
...@@ -445,11 +463,12 @@ int openssl_connect(git_stream *stream) ...@@ -445,11 +463,12 @@ int openssl_connect(git_stream *stream)
st->connected = true; st->connected = true;
bio = BIO_new(&git_stream_bio_method); bio = BIO_new(git_stream_bio_method);
GITERR_CHECK_ALLOC(bio); GITERR_CHECK_ALLOC(bio);
bio->ptr = st->io;
BIO_set_data(bio, st->io);
SSL_set_bio(st->ssl, bio, bio); SSL_set_bio(st->ssl, bio, bio);
/* specify the host in case SNI is needed */ /* specify the host in case SNI is needed */
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
SSL_set_tlsext_host_name(st->ssl, st->host); SSL_set_tlsext_host_name(st->ssl, st->host);
......
...@@ -13,4 +13,110 @@ extern int git_openssl_stream_global_init(void); ...@@ -13,4 +13,110 @@ extern int git_openssl_stream_global_init(void);
extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port); extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
/*
* OpenSSL 1.1 made BIO opaque so we have to use functions to interact with it
* which do not exist in previous versions. We define these inline functions so
* we can program against the interface instead of littering the implementation
* with ifdefs.
*/
#ifdef GIT_OPENSSL
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/x509v3.h>
# include <openssl/bio.h>
# if OPENSSL_VERSION_NUMBER < 0x10100000L
GIT_INLINE(BIO_METHOD*) BIO_meth_new(int type, const char *name)
{
BIO_METHOD *meth = git__calloc(1, sizeof(BIO_METHOD));
if (!meth) {
return NULL;
}
meth->type = type;
meth->name = name;
return meth;
}
GIT_INLINE(void) BIO_meth_free(BIO_METHOD *biom)
{
git__free(biom);
}
GIT_INLINE(int) BIO_meth_set_write(BIO_METHOD *biom, int (*write) (BIO *, const char *, int))
{
biom->bwrite = write;
return 1;
}
GIT_INLINE(int) BIO_meth_set_read(BIO_METHOD *biom, int (*read) (BIO *, char *, int))
{
biom->bread = read;
return 1;
}
GIT_INLINE(int) BIO_meth_set_puts(BIO_METHOD *biom, int (*puts) (BIO *, const char *))
{
biom->bputs = puts;
return 1;
}
GIT_INLINE(int) BIO_meth_set_gets(BIO_METHOD *biom, int (*gets) (BIO *, char *, int))
{
biom->bgets = gets;
return 1;
}
GIT_INLINE(int) BIO_meth_set_ctrl(BIO_METHOD *biom, long (*ctrl) (BIO *, int, long, void *))
{
biom->ctrl = ctrl;
return 1;
}
GIT_INLINE(int) BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *))
{
biom->create = create;
return 1;
}
GIT_INLINE(int) BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *))
{
biom->destroy = destroy;
return 1;
}
GIT_INLINE(int) BIO_get_new_index(void)
{
/* This exists as of 1.1 so before we'd just have 0 */
return 0;
}
GIT_INLINE(void) BIO_set_init(BIO *b, int init)
{
b->init = init;
}
GIT_INLINE(void) BIO_set_data(BIO *a, void *ptr)
{
a->ptr = ptr;
}
GIT_INLINE(void*) BIO_get_data(BIO *a)
{
return a->ptr;
}
GIT_INLINE(const unsigned char *) ASN1_STRING_get0_data(const ASN1_STRING *x)
{
return ASN1_STRING_data((ASN1_STRING *)x);
}
# endif // OpenSSL < 1.1
#endif // GIT_OPENSSL
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment