summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/openssl_stream.c122
1 files changed, 110 insertions, 12 deletions
diff --git a/src/openssl_stream.c b/src/openssl_stream.c
index 9b2d5951c..396744032 100644
--- a/src/openssl_stream.c
+++ b/src/openssl_stream.c
@@ -16,6 +16,10 @@
#include "netops.h"
#include "git2/transport.h"
+#ifdef GIT_CURL
+# include "curl_stream.h"
+#endif
+
#ifndef GIT_WIN32
# include <sys/types.h>
# include <sys/socket.h>
@@ -25,6 +29,79 @@
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>
+#include <openssl/bio.h>
+
+static int bio_create(BIO *b)
+{
+ b->init = 1;
+ b->num = 0;
+ b->ptr = NULL;
+ b->flags = 0;
+
+ return 1;
+}
+
+static int bio_destroy(BIO *b)
+{
+ if (!b)
+ return 0;
+
+ b->init = 0;
+ b->num = 0;
+ b->ptr = NULL;
+ b->flags = 0;
+
+ return 1;
+}
+
+static int bio_read(BIO *b, char *buf, int len)
+{
+ git_stream *io = (git_stream *) b->ptr;
+ return (int) git_stream_read(io, buf, len);
+}
+
+static int bio_write(BIO *b, const char *buf, int len)
+{
+ git_stream *io = (git_stream *) b->ptr;
+ return (int) git_stream_write(io, buf, len, 0);
+}
+
+static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+ GIT_UNUSED(b);
+ GIT_UNUSED(num);
+ GIT_UNUSED(ptr);
+
+ if (cmd == BIO_CTRL_FLUSH)
+ return 1;
+
+ return 0;
+}
+
+static int bio_gets(BIO *b, char *buf, int len)
+{
+ GIT_UNUSED(b);
+ GIT_UNUSED(buf);
+ GIT_UNUSED(len);
+ return -1;
+}
+
+static int bio_puts(BIO *b, const char *str)
+{
+ return bio_write(b, str, strlen(str));
+}
+
+static BIO_METHOD git_stream_bio_method = {
+ BIO_TYPE_SOURCE_SINK,
+ "git_stream",
+ bio_write,
+ bio_read,
+ bio_puts,
+ bio_gets,
+ bio_ctrl,
+ bio_create,
+ bio_destroy
+};
static int ssl_set_error(SSL *ssl, int error)
{
@@ -224,7 +301,8 @@ cert_fail_name:
typedef struct {
git_stream parent;
- git_socket_stream *socket;
+ git_stream *io;
+ char *host;
SSL *ssl;
git_cert_x509 cert_info;
} openssl_stream;
@@ -234,23 +312,24 @@ int openssl_close(git_stream *stream);
int openssl_connect(git_stream *stream)
{
int ret;
+ BIO *bio;
openssl_stream *st = (openssl_stream *) stream;
- if ((ret = git_stream_connect((git_stream *)st->socket)) < 0)
+ if ((ret = git_stream_connect(st->io)) < 0)
return ret;
- if ((ret = SSL_set_fd(st->ssl, st->socket->s)) <= 0) {
- openssl_close((git_stream *) st);
- return ssl_set_error(st->ssl, ret);
- }
+ bio = BIO_new(&git_stream_bio_method);
+ GITERR_CHECK_ALLOC(bio);
+ bio->ptr = st->io;
+ SSL_set_bio(st->ssl, bio, bio);
/* specify the host in case SNI is needed */
- SSL_set_tlsext_host_name(st->ssl, st->socket->host);
+ SSL_set_tlsext_host_name(st->ssl, st->host);
if ((ret = SSL_connect(st->ssl)) <= 0)
return ssl_set_error(st->ssl, ret);
- return verify_server_cert(st->ssl, st->socket->host);
+ return verify_server_cert(st->ssl, st->host);
}
int openssl_certificate(git_cert **out, git_stream *stream)
@@ -287,6 +366,13 @@ int openssl_certificate(git_cert **out, git_stream *stream)
return 0;
}
+static int openssl_set_proxy(git_stream *stream, const char *proxy_url)
+{
+ openssl_stream *st = (openssl_stream *) stream;
+
+ return git_stream_set_proxy(st->io, proxy_url);
+}
+
ssize_t openssl_write(git_stream *stream, const char *data, size_t len, int flags)
{
openssl_stream *st = (openssl_stream *) stream;
@@ -320,7 +406,7 @@ int openssl_close(git_stream *stream)
if ((ret = ssl_teardown(st->ssl)) < 0)
return -1;
- return git_stream_close((git_stream *)st->socket);
+ return git_stream_close(st->io);
}
void openssl_free(git_stream *stream)
@@ -328,19 +414,26 @@ void openssl_free(git_stream *stream)
openssl_stream *st = (openssl_stream *) stream;
git__free(st->cert_info.data);
- git_stream_free((git_stream *) st->socket);
+ git_stream_free(st->io);
git__free(st);
}
int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
{
+ int error;
openssl_stream *st;
st = git__calloc(1, sizeof(openssl_stream));
GITERR_CHECK_ALLOC(st);
- if (git_socket_stream_new((git_stream **) &st->socket, host, port))
- return -1;
+#ifdef GIT_CURL
+ error = git_curl_stream_new(&st->io, host, port, false);
+#else
+ error = git_socket_stream_new(&st->io, host, port)
+#endif
+
+ if (error < 0)
+ return error;
st->ssl = SSL_new(git__ssl_ctx);
if (st->ssl == NULL) {
@@ -348,10 +441,15 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
return -1;
}
+ st->host = git__strdup(host);
+ GITERR_CHECK_ALLOC(st->host);
+
st->parent.version = GIT_STREAM_VERSION;
st->parent.encrypted = 1;
+ st->parent.proxy_support = git_stream_supports_proxy(st->io);
st->parent.connect = openssl_connect;
st->parent.certificate = openssl_certificate;
+ st->parent.set_proxy = openssl_set_proxy;
st->parent.read = openssl_read;
st->parent.write = openssl_write;
st->parent.close = openssl_close;