checkpoint

This commit is contained in:
Edward Thomson
2023-08-22 06:40:28 -04:00
parent ae3d81e2b8
commit c2eafb2f6e
8 changed files with 128 additions and 99 deletions

View File

@@ -36,6 +36,14 @@ typedef struct {
#define GIT_STREAM_CONNECT_OPTIONS_INIT \
{ GIT_STREAM_CONNECT_OPTIONS_VERSION }
#ifdef GIT_WIN32
typedef SOCKET git_socket_t;
# define GIT_SOCKET_INVALID INVALID_SOCKET
#else
typedef int git_socket_t;
# define GIT_SOCKET_INVALID -1
#endif
/**
* Every stream must have this struct as its first element, so the
* API can talk to it. You'd define your stream as
@@ -64,6 +72,7 @@ typedef struct git_stream {
struct git_stream *,
struct git_stream *in,
const char *host);
git_socket_t GIT_CALLBACK(get_socket)(struct git_stream *);
int GIT_CALLBACK(certificate)(git_cert **, struct git_stream *);
ssize_t GIT_CALLBACK(read)(struct git_stream *, void *, size_t);
ssize_t GIT_CALLBACK(write)(struct git_stream *, const char *, size_t, int);
@@ -82,20 +91,6 @@ typedef struct {
* @return 0 or an error code
*/
int GIT_CALLBACK(init)(git_stream **out);
/**
* Called to create a new connection on top of the given stream. If
* this is a TLS stream, then this function may be used to proxy a
* TLS stream over an HTTP CONNECT session. If this is unset, then
* HTTP CONNECT proxies will not be supported.
*
* @param out The created stream
* @param in An existing stream to add TLS to
* @param host The hostname that the stream is connected to,
* for certificate validation
* @return 0 or an error code
*/
int GIT_CALLBACK(wrap)(git_stream **out, git_stream *in, const char *host);
} git_stream_registration;
/**

View File

@@ -14,6 +14,7 @@
#include "smart.h"
#include "http.h"
#include "trace.h"
#include "transport.h"
#include "streams/tls.h"
#include "streams/socket.h"
#include "net/auth.h"
@@ -25,6 +26,9 @@
bool git_http__expect_continue = false;
extern int git_transport__timeout;
extern int git_transport__connect_timeout;
typedef enum {
HTTP_STATE_NONE = 0,
HTTP_STATE_SENDING_REQUEST,
@@ -97,9 +101,6 @@ static const http_service receive_pack_service = {
1
};
extern int git_transport__connect_timeout;
extern int git_transport__timeout;
#define SERVER_TYPE_REMOTE "remote"
#define SERVER_TYPE_PROXY "proxy"
@@ -695,8 +696,9 @@ static int http_action(
GIT_ERROR_CHECK_ALLOC(stream);
opts.user_agent = transport->user_agent.ptr;
opts.connect_timeout = git_transport__connect_timeout;
opts.timeout = git_transport__timeout;
opts.connect_timeout = git_transport__connect_timeout;
opts.server_certificate_check_cb = connect_opts->callbacks.certificate_check;
opts.server_certificate_check_payload = connect_opts->callbacks.payload;

View File

@@ -13,6 +13,7 @@
#include "runtime.h"
#include "smart.h"
#include "transport.h"
#include "streams/socket.h"
#include "sysdir.h"
#include "net/url.h"
@@ -523,16 +524,22 @@ static int _git_ssh_session_create(
LIBSSH2_KNOWNHOSTS **hosts,
const char *hostname,
int port,
git_stream *io)
git_stream *stream)
{
git_stream_socket *socket = GIT_CONTAINER_OF(io, git_stream_socket, parent);
LIBSSH2_SESSION *s;
LIBSSH2_KNOWNHOSTS *known_hosts;
git_socket_t socket;
git_str prefs = GIT_STR_INIT;
int rc = 0;
GIT_ASSERT_ARG(session);
GIT_ASSERT_ARG(hosts);
GIT_ASSERT_ARG(stream);
if ((socket = git_stream_get_socket(stream)) == GIT_SOCKET_INVALID) {
git_error_set(GIT_ERROR_NET, "could not get socket");
return -1;
}
s = libssh2_session_init();
if (!s) {
@@ -559,7 +566,7 @@ static int _git_ssh_session_create(
git_str_dispose(&prefs);
do {
rc = libssh2_session_handshake(s, socket->s);
rc = libssh2_session_handshake(s, socket);
} while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
if (rc != LIBSSH2_ERROR_NONE) {
@@ -768,9 +775,10 @@ static int _git_ssh_setup_conn(
int auth_methods, error = 0, port;
ssh_stream *s;
git_credential *cred = NULL;
LIBSSH2_SESSION *session=NULL;
LIBSSH2_CHANNEL *channel=NULL;
LIBSSH2_SESSION *session = NULL;
LIBSSH2_CHANNEL *channel = NULL;
LIBSSH2_KNOWNHOSTS *known_hosts = NULL;
git_stream_connect_options opts = GIT_STREAM_CONNECT_OPTIONS_INIT;
t->current_stream = NULL;
@@ -782,9 +790,11 @@ static int _git_ssh_setup_conn(
s->session = NULL;
s->channel = NULL;
git_transport__set_connect_opts(&opts);
if ((error = git_net_url_parse_standard_or_scp(&s->url, url)) < 0 ||
(error = git_stream_socket_new(&s->io, s->url.host, s->url.port)) < 0 ||
(error = git_stream_connect(s->io)) < 0)
(error = git_stream_socket_new(&s->io)) < 0 ||
(error = git_stream_connect(s->io, s->url.host, s->url.port, &opts)) < 0)
goto done;
/*

View File

@@ -32,6 +32,11 @@ GIT_INLINE(int) git_stream_is_encrypted(git_stream *st)
return st->encrypted;
}
GIT_INLINE(GIT_SOCKET) git_stream_get_socket(git_stream *st)
{
return st->get_socket(st);
}
GIT_INLINE(int) git_stream_certificate(git_cert **out, git_stream *st)
{
if (!st->encrypted) {

View File

@@ -15,10 +15,9 @@
#include "git2_util.h"
#include "runtime.h"
#include "settings.h"
#include "posix.h"
#include "stream.h"
#include "net.h"
#include "net/url.h"
#include "streams/socket.h"
#include "git2/transport.h"
#include "git2/sys/openssl.h"
@@ -36,7 +35,7 @@
# include <openssl/bio.h>
#endif
SSL_CTX *git__ssl_ctx;
SSL_CTX *openssl_ctx;
#define GIT_SSL_DEFAULT_CIPHERS "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-DSS-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA"
@@ -55,9 +54,9 @@ static void shutdown_ssl(void)
git_stream_bio_method = NULL;
}
if (git__ssl_ctx) {
SSL_CTX_free(git__ssl_ctx);
git__ssl_ctx = NULL;
if (openssl_ctx) {
SSL_CTX_free(openssl_ctx);
openssl_ctx = NULL;
}
}
@@ -105,7 +104,6 @@ static void git_openssl_free(void *mem)
static int openssl_init(void)
{
long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
const char *ciphers = git_libgit2__ssl_ciphers();
#ifdef VALGRIND
static bool allocators_initialized = false;
#endif
@@ -138,19 +136,14 @@ static int openssl_init(void)
* compatibility. We then disable SSL so we only allow OpenSSL
* to speak TLSv1 to perform the encryption itself.
*/
if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method())))
if (!(openssl_ctx = SSL_CTX_new(SSLv23_method())))
goto error;
SSL_CTX_set_options(git__ssl_ctx, ssl_opts);
SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL);
if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx))
goto error;
SSL_CTX_set_options(openssl_ctx, ssl_opts);
SSL_CTX_set_mode(openssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_verify(openssl_ctx, SSL_VERIFY_NONE, NULL);
if (!ciphers)
ciphers = GIT_SSL_DEFAULT_CIPHERS;
if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers))
if (!SSL_CTX_set_default_verify_paths(openssl_ctx))
goto error;
if (init_bio_method() < 0)
@@ -161,8 +154,8 @@ static int openssl_init(void)
error:
git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s",
ERR_error_string(ERR_get_error(), NULL));
SSL_CTX_free(git__ssl_ctx);
git__ssl_ctx = NULL;
SSL_CTX_free(openssl_ctx);
openssl_ctx = NULL;
return -1;
}
@@ -503,14 +496,20 @@ typedef struct {
git_cert_x509 cert_info;
} openssl_stream;
static int openssl_connect(git_stream *stream)
static int openssl_create_session(openssl_stream *st, const char *host)
{
int ret;
BIO *bio;
openssl_stream *st = (openssl_stream *) stream;
int ret;
if (st->owned && (ret = git_stream_connect(st->io)) < 0)
return ret;
st->ssl = SSL_new(openssl_ctx);
if (st->ssl == NULL) {
git_error_set(GIT_ERROR_SSL, "failed to create ssl object");
return -1;
}
st->host = git__strdup(host);
GIT_ERROR_CHECK_ALLOC(st->host);
bio = BIO_new(git_stream_bio_method);
GIT_ERROR_CHECK_ALLOC(bio);
@@ -531,6 +530,33 @@ static int openssl_connect(git_stream *stream)
return verify_server_cert(st->ssl, st->host);
}
static int openssl_connect(
git_stream *stream,
const char *host,
const char *port,
const git_stream_connect_options *opts)
{
openssl_stream *st = (openssl_stream *)stream;
if (git_stream_socket_new(&st->io) < 0 ||
git_stream_connect(st->io, host, port, opts) < 0)
return -1;
st->owned = 1;
return openssl_create_session(st, host);
}
static int openssl_wrap(git_stream *stream, git_stream *in, const char *host)
{
openssl_stream *st = (openssl_stream *)stream;
st->io = in;
st->owned = 0;
return openssl_create_session(st, host);
}
static int openssl_certificate(git_cert **out, git_stream *stream)
{
openssl_stream *st = (openssl_stream *) stream;
@@ -622,37 +648,28 @@ static void openssl_free(git_stream *stream)
git__free(st);
}
static int openssl_stream_wrap(
git_stream **out,
git_stream *in,
const char *host,
int owned)
int git_stream_openssl_new(git_stream **out)
{
openssl_stream *st;
GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(in);
GIT_ASSERT_ARG(host);
if (openssl_ensure_initialized() < 0)
return -1;
st = git__calloc(1, sizeof(openssl_stream));
GIT_ERROR_CHECK_ALLOC(st);
st->io = in;
st->owned = owned;
st->ssl = SSL_new(git__ssl_ctx);
if (st->ssl == NULL) {
if ((st->ssl = SSL_new(openssl_ctx)) == NULL) {
git_error_set(GIT_ERROR_SSL, "failed to create ssl object");
git__free(st);
return -1;
}
st->host = git__strdup(host);
GIT_ERROR_CHECK_ALLOC(st->host);
st->parent.version = GIT_STREAM_VERSION;
st->parent.encrypted = 1;
st->parent.connect = openssl_connect;
st->parent.wrap = openssl_wrap;
st->parent.certificate = openssl_certificate;
st->parent.read = openssl_read;
st->parent.write = openssl_write;
@@ -663,43 +680,12 @@ static int openssl_stream_wrap(
return 0;
}
int git_stream_openssl_wrap(git_stream **out, git_stream *in, const char *host)
{
if (openssl_ensure_initialized() < 0)
return -1;
return openssl_stream_wrap(out, in, host, 0);
}
int git_stream_openssl_new(git_stream **out, const char *host, const char *port)
{
git_stream *stream = NULL;
int error;
GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(host);
GIT_ASSERT_ARG(port);
if (openssl_ensure_initialized() < 0)
return -1;
if ((error = git_stream_socket_new(&stream, host, port)) < 0)
return error;
if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) {
git_stream_close(stream);
git_stream_free(stream);
}
return error;
}
int git_openssl__set_cert_location(const char *file, const char *path)
{
if (openssl_ensure_initialized() < 0)
return -1;
if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) {
if (SSL_CTX_load_verify_locations(openssl_ctx, file, path) == 0) {
char errmsg[256];
ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
@@ -711,6 +697,20 @@ int git_openssl__set_cert_location(const char *file, const char *path)
return 0;
}
int git_openssl__set_ciphers(const char *ciphers)
{
if (!ciphers)
ciphers = GIT_SSL_DEFAULT_CIPHERS;
if (openssl_ensure_initialized() < 0)
return -1;
if(!SSL_CTX_set_cipher_list(openssl_ctx, GIT_SSL_DEFAULT_CIPHERS))
return -1;
return 0;
}
#else
#include "stream.h"

View File

@@ -23,9 +23,9 @@ extern int git_stream_openssl_global_init(void);
# endif
#ifdef GIT_HTTPS_OPENSSL
extern int git_openssl__set_ciphers(const char *ciphers);
extern int git_openssl__set_cert_location(const char *file, const char *path);
extern int git_stream_openssl_new(git_stream **out, const char *host, const char *port);
extern int git_stream_openssl_wrap(git_stream **out, git_stream *in, const char *host);
extern int git_stream_openssl_new(git_stream **out);
#endif
#endif

View File

@@ -108,7 +108,6 @@ int git_stream_register_tls(
if (ctor) {
registration.version = GIT_STREAM_VERSION;
registration.init = ctor;
registration.wrap = NULL;
return git_stream_register(GIT_STREAM_TLS, &registration);
} else {

View File

@@ -243,6 +243,22 @@ done:
return error;
}
static int socket_wrap(git_stream *stream, git_stream *in, const char *host)
{
GIT_UNUSED(stream);
GIT_UNUSED(in);
GIT_UNUSED(host);
git_error_set(GIT_ERROR_NET, "cannot wrap a plaintext socket");
return -1;
}
static git_socket_t socket_get(git_stream *stream)
{
git_stream_socket *st = (git_stream_socket *) stream;
return st->s;
}
static ssize_t socket_write(
git_stream *stream,
const char *data,
@@ -350,6 +366,8 @@ static int default_socket_stream_new(git_stream **out)
st->parent.version = GIT_STREAM_VERSION;
st->parent.connect = socket_connect;
st->parent.wrap = socket_wrap;
st->parent.get_socket = socket_get;
st->parent.write = socket_write;
st->parent.read = socket_read;
st->parent.close = socket_close;