Skip to content

Commit 43b592a

Browse files
committed
tls: introduce a wrap function
Introduce `git_tls_stream_wrap` which will take an existing `stream` with an already connected socket and begin speaking TLS on top of it. This is useful if you've built a connection to a proxy server and you wish to begin CONNECT over it to tunnel a TLS connection. Also update the pluggable TLS stream layer so that it can accept a registration structure that provides an `init` and `wrap` function, instead of a single initialization function.
1 parent 6ba3e6a commit 43b592a

File tree

12 files changed

+351
-96
lines changed

12 files changed

+351
-96
lines changed

include/git2/sys/stream.h

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,48 @@ typedef struct git_stream {
4040
void (*free)(struct git_stream *);
4141
} git_stream;
4242

43-
typedef int (*git_stream_cb)(git_stream **out, const char *host, const char *port);
43+
typedef struct {
44+
/** The `version` field should be set to `GIT_STREAM_VERSION`. */
45+
int version;
46+
47+
/**
48+
* Called to create a new TLS connection to a given host.
49+
*
50+
* @param out The created TLS stream
51+
* @param host The hostname to connect to; may be a hostname or
52+
* IP address
53+
* @param port The port to connect to; may be a port number or
54+
* service name
55+
* @return 0 or an error code
56+
*/
57+
int (*init)(git_stream **out, const char *host, const char *port);
58+
59+
/**
60+
* Called to create a new TLS connection on top of the given
61+
* stream. May be used to proxy a TLS stream over a CONNECT
62+
* session.
63+
*
64+
* @param out The created TLS stream
65+
* @param in An existing stream to add TLS to
66+
* @param host The hostname that the stream is connected to,
67+
* for certificate validation
68+
* @return 0 or an error code
69+
*/
70+
int (*wrap)(git_stream **out, git_stream *in, const char *host);
71+
} git_stream_registration;
4472

4573
/**
46-
* Register a TLS stream constructor for the library to use
74+
* Register TLS stream constructors for the library to use
4775
*
48-
* If a constructor is already set, it will be overwritten. Pass
49-
* `NULL` in order to deregister the current constructor.
76+
* If a registration structure is already set, it will be overwritten.
77+
* Pass `NULL` in order to deregister the current constructor and return
78+
* to the system defaults.
5079
*
51-
* @param ctor the constructor to use
80+
* @param registration the registration data
5281
* @return 0 or an error code
5382
*/
54-
GIT_EXTERN(int) git_stream_register_tls(git_stream_cb ctor);
83+
GIT_EXTERN(int) git_stream_register_tls(
84+
git_stream_registration *registration);
5585

5686
GIT_END_DECL
5787

src/global.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "sysdir.h"
1313
#include "filter.h"
1414
#include "merge_driver.h"
15+
#include "streams/tls.h"
1516
#include "streams/curl.h"
1617
#include "streams/mbedtls.h"
1718
#include "streams/openssl.h"
@@ -67,6 +68,7 @@ static int init_common(void)
6768
(ret = git_filter_global_init()) == 0 &&
6869
(ret = git_merge_driver_global_init()) == 0 &&
6970
(ret = git_transport_ssh_global_init()) == 0 &&
71+
(ret = git_tls_stream_global_init()) == 0 &&
7072
(ret = git_openssl_stream_global_init()) == 0 &&
7173
(ret = git_curl_stream_global_init()) == 0 &&
7274
(ret = git_mbedtls_stream_global_init()) == 0)

src/streams/mbedtls.c

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ static int verify_server_cert(mbedtls_ssl_context *ssl)
242242
typedef struct {
243243
git_stream parent;
244244
git_stream *io;
245+
int owned;
245246
bool connected;
246247
char *host;
247248
mbedtls_ssl_context *ssl;
@@ -254,7 +255,7 @@ int mbedtls_connect(git_stream *stream)
254255
int ret;
255256
mbedtls_stream *st = (mbedtls_stream *) stream;
256257

257-
if ((ret = git_stream_connect(st->io)) < 0)
258+
if (st->owned && (ret = git_stream_connect(st->io)) < 0)
258259
return ret;
259260

260261
st->connected = true;
@@ -345,37 +346,37 @@ int mbedtls_stream_close(git_stream *stream)
345346

346347
st->connected = false;
347348

348-
return git_stream_close(st->io);
349+
return st->owned ? git_stream_close(st->io) : 0;
349350
}
350351

351352
void mbedtls_stream_free(git_stream *stream)
352353
{
353354
mbedtls_stream *st = (mbedtls_stream *) stream;
354355

356+
if (st->owned)
357+
git_stream_free(st->io);
358+
355359
git__free(st->host);
356360
git__free(st->cert_info.data);
357-
git_stream_free(st->io);
358361
mbedtls_ssl_free(st->ssl);
359362
git__free(st->ssl);
360363
git__free(st);
361364
}
362365

363-
int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
366+
static int mbedtls_stream_wrap(
367+
git_stream **out,
368+
git_stream *in,
369+
const char *host,
370+
int owned)
364371
{
365-
int error;
366372
mbedtls_stream *st;
373+
int error;
367374

368375
st = git__calloc(1, sizeof(mbedtls_stream));
369376
GITERR_CHECK_ALLOC(st);
370377

371-
#ifdef GIT_CURL
372-
error = git_curl_stream_new(&st->io, host, port);
373-
#else
374-
error = git_socket_stream_new(&st->io, host, port);
375-
#endif
376-
377-
if (error < 0)
378-
goto out_err;
378+
st->io = in;
379+
st->owned = owned;
379380

380381
st->ssl = git__malloc(sizeof(mbedtls_ssl_context));
381382
GITERR_CHECK_ALLOC(st->ssl);
@@ -405,12 +406,48 @@ int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
405406

406407
out_err:
407408
mbedtls_ssl_free(st->ssl);
409+
git_stream_close(st->io);
408410
git_stream_free(st->io);
409411
git__free(st);
410412

411413
return error;
412414
}
413415

416+
int git_mbedtls_stream_wrap(
417+
git_stream **out,
418+
git_stream *in,
419+
const char *host)
420+
{
421+
return mbedtls_stream_wrap(out, in, host, 0);
422+
}
423+
424+
int git_mbedtls_stream_new(
425+
git_stream **out,
426+
const char *host,
427+
const char *port)
428+
{
429+
git_stream *stream;
430+
int error;
431+
432+
assert(out && host && port);
433+
434+
#ifdef GIT_CURL
435+
error = git_curl_stream_new(&stream, host, port);
436+
#else
437+
error = git_socket_stream_new(&stream, host, port);
438+
#endif
439+
440+
if (error < 0)
441+
return error;
442+
443+
if ((error = mbedtls_stream_wrap(out, stream, host, 1)) < 0) {
444+
git_stream_close(stream);
445+
git_stream_free(stream);
446+
}
447+
448+
return error;
449+
}
450+
414451
int git_mbedtls__set_cert_location(const char *path, int is_dir)
415452
{
416453
int ret = 0;

src/streams/mbedtls.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
extern int git_mbedtls_stream_global_init(void);
1515

1616
extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port);
17+
extern int git_mbedtls_stream_wrap(git_stream **out, git_stream *in, const char *host);
1718

1819
extern int git_mbedtls__set_cert_location(const char *path, int is_dir);
1920

src/streams/openssl.c

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ static int verify_server_cert(SSL *ssl, const char *host)
569569
typedef struct {
570570
git_stream parent;
571571
git_stream *io;
572+
int owned;
572573
bool connected;
573574
char *host;
574575
SSL *ssl;
@@ -583,7 +584,7 @@ int openssl_connect(git_stream *stream)
583584
BIO *bio;
584585
openssl_stream *st = (openssl_stream *) stream;
585586

586-
if ((ret = git_stream_connect(st->io)) < 0)
587+
if (st->owned && (ret = git_stream_connect(st->io)) < 0)
587588
return ret;
588589

589590
bio = BIO_new(git_stream_bio_method);
@@ -682,43 +683,43 @@ int openssl_close(git_stream *stream)
682683

683684
st->connected = false;
684685

685-
return git_stream_close(st->io);
686+
return st->owned ? git_stream_close(st->io) : 0;
686687
}
687688

688689
void openssl_free(git_stream *stream)
689690
{
690691
openssl_stream *st = (openssl_stream *) stream;
691692

693+
if (st->owned)
694+
git_stream_free(st->io);
695+
692696
SSL_free(st->ssl);
693697
git__free(st->host);
694698
git__free(st->cert_info.data);
695-
git_stream_free(st->io);
696699
git__free(st);
697700
}
698701

699-
int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
702+
static int openssl_stream_wrap(
703+
git_stream **out,
704+
git_stream *in,
705+
const char *host,
706+
int owned)
700707
{
701-
int error;
702708
openssl_stream *st;
703709

710+
assert(out && in && host);
711+
704712
st = git__calloc(1, sizeof(openssl_stream));
705713
GITERR_CHECK_ALLOC(st);
706714

707-
st->io = NULL;
708-
#ifdef GIT_CURL
709-
error = git_curl_stream_new(&st->io, host, port);
710-
#else
711-
error = git_socket_stream_new(&st->io, host, port);
712-
#endif
713-
714-
if (error < 0)
715-
goto out_err;
715+
st->io = in;
716+
st->owned = owned;
716717

717718
st->ssl = SSL_new(git__ssl_ctx);
718719
if (st->ssl == NULL) {
719720
giterr_set(GITERR_SSL, "failed to create ssl object");
720-
error = -1;
721-
goto out_err;
721+
git__free(st);
722+
return -1;
722723
}
723724

724725
st->host = git__strdup(host);
@@ -737,10 +738,33 @@ int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
737738

738739
*out = (git_stream *) st;
739740
return 0;
741+
}
740742

741-
out_err:
742-
git_stream_free(st->io);
743-
git__free(st);
743+
int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host)
744+
{
745+
return openssl_stream_wrap(out, in, host, 0);
746+
}
747+
748+
int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
749+
{
750+
git_stream *stream = NULL;
751+
int error;
752+
753+
assert(out && host && port);
754+
755+
#ifdef GIT_CURL
756+
error = git_curl_stream_new(&stream, host, port);
757+
#else
758+
error = git_socket_stream_new(&stream, host, port);
759+
#endif
760+
761+
if (error < 0)
762+
return error;
763+
764+
if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) {
765+
git_stream_close(stream);
766+
git_stream_free(stream);
767+
}
744768

745769
return error;
746770
}

src/streams/openssl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
extern int git_openssl_stream_global_init(void);
1515

1616
extern int git_openssl_stream_new(git_stream **out, const char *host, const char *port);
17+
extern int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host);
1718

1819
extern int git_openssl__set_cert_location(const char *file, const char *path);
1920

0 commit comments

Comments
 (0)