1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "streams/openssl.h"
9 #include "streams/openssl_legacy.h"
10 #include "streams/openssl_dynamic.h"
11 
12 #ifdef GIT_OPENSSL
13 
14 #include <ctype.h>
15 
16 #include "common.h"
17 #include "runtime.h"
18 #include "settings.h"
19 #include "posix.h"
20 #include "stream.h"
21 #include "streams/socket.h"
22 #include "netops.h"
23 #include "git2/transport.h"
24 #include "git2/sys/openssl.h"
25 
26 #ifndef GIT_WIN32
27 # include <sys/types.h>
28 # include <sys/socket.h>
29 # include <netinet/in.h>
30 #endif
31 
32 #ifndef GIT_OPENSSL_DYNAMIC
33 # include <openssl/ssl.h>
34 # include <openssl/err.h>
35 # include <openssl/x509v3.h>
36 # include <openssl/bio.h>
37 #endif
38 
39 SSL_CTX *git__ssl_ctx;
40 
41 #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"
42 
43 
44 static BIO_METHOD *git_stream_bio_method;
45 static int init_bio_method(void);
46 
47 /**
48  * This function aims to clean-up the SSL context which
49  * we allocated.
50  */
shutdown_ssl(void)51 static void shutdown_ssl(void)
52 {
53 	if (git_stream_bio_method) {
54 		BIO_meth_free(git_stream_bio_method);
55 		git_stream_bio_method = NULL;
56 	}
57 
58 	if (git__ssl_ctx) {
59 		SSL_CTX_free(git__ssl_ctx);
60 		git__ssl_ctx = NULL;
61 	}
62 }
63 
64 #ifdef VALGRIND
65 # if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC)
66 
git_openssl_malloc(size_t bytes,const char * file,int line)67 static void *git_openssl_malloc(size_t bytes, const char *file, int line)
68 {
69 	GIT_UNUSED(file);
70 	GIT_UNUSED(line);
71 	return git__calloc(1, bytes);
72 }
73 
git_openssl_realloc(void * mem,size_t size,const char * file,int line)74 static void *git_openssl_realloc(void *mem, size_t size, const char *file, int line)
75 {
76 	GIT_UNUSED(file);
77 	GIT_UNUSED(line);
78 	return git__realloc(mem, size);
79 }
80 
git_openssl_free(void * mem,const char * file,int line)81 static void git_openssl_free(void *mem, const char *file, int line)
82 {
83 	GIT_UNUSED(file);
84 	GIT_UNUSED(line);
85 	git__free(mem);
86 }
87 # else /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */
git_openssl_malloc(size_t bytes)88 static void *git_openssl_malloc(size_t bytes)
89 {
90 	return git__calloc(1, bytes);
91 }
92 
git_openssl_realloc(void * mem,size_t size)93 static void *git_openssl_realloc(void *mem, size_t size)
94 {
95 	return git__realloc(mem, size);
96 }
97 
git_openssl_free(void * mem)98 static void git_openssl_free(void *mem)
99 {
100 	git__free(mem);
101 }
102 # endif /* !GIT_OPENSSL_LEGACY && !GIT_OPENSSL_DYNAMIC */
103 #endif /* VALGRIND */
104 
openssl_init(void)105 static int openssl_init(void)
106 {
107 	long ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
108 	const char *ciphers = git_libgit2__ssl_ciphers();
109 #ifdef VALGRIND
110 	static bool allocators_initialized = false;
111 #endif
112 
113 	/* Older OpenSSL and MacOS OpenSSL doesn't have this */
114 #ifdef SSL_OP_NO_COMPRESSION
115 	ssl_opts |= SSL_OP_NO_COMPRESSION;
116 #endif
117 
118 #ifdef VALGRIND
119 	/*
120 	 * Swap in our own allocator functions that initialize
121 	 * allocated memory to avoid spurious valgrind warnings.
122 	 * Don't error on failure; many builds of OpenSSL do not
123 	 * allow you to set these functions.
124 	 */
125 	if (!allocators_initialized) {
126 	    CRYPTO_set_mem_functions(git_openssl_malloc,
127 				     git_openssl_realloc,
128 				     git_openssl_free);
129 		allocators_initialized = true;
130 	}
131 #endif
132 
133 	OPENSSL_init_ssl(0, NULL);
134 
135 	/*
136 	 * Load SSLv{2,3} and TLSv1 so that we can talk with servers
137 	 * which use the SSL hellos, which are often used for
138 	 * compatibility. We then disable SSL so we only allow OpenSSL
139 	 * to speak TLSv1 to perform the encryption itself.
140 	 */
141 	if (!(git__ssl_ctx = SSL_CTX_new(SSLv23_method())))
142 		goto error;
143 
144 	SSL_CTX_set_options(git__ssl_ctx, ssl_opts);
145 	SSL_CTX_set_mode(git__ssl_ctx, SSL_MODE_AUTO_RETRY);
146 	SSL_CTX_set_verify(git__ssl_ctx, SSL_VERIFY_NONE, NULL);
147 	if (!SSL_CTX_set_default_verify_paths(git__ssl_ctx))
148 		goto error;
149 
150 	if (!ciphers)
151 		ciphers = GIT_SSL_DEFAULT_CIPHERS;
152 
153 	if(!SSL_CTX_set_cipher_list(git__ssl_ctx, ciphers))
154 		goto error;
155 
156 	if (init_bio_method() < 0)
157 		goto error;
158 
159 	return git_runtime_shutdown_register(shutdown_ssl);
160 
161 error:
162 	git_error_set(GIT_ERROR_NET, "could not initialize openssl: %s",
163 		ERR_error_string(ERR_get_error(), NULL));
164 	SSL_CTX_free(git__ssl_ctx);
165 	git__ssl_ctx = NULL;
166 	return -1;
167 }
168 
169 /*
170  * When we use dynamic loading, we defer OpenSSL initialization until
171  * it's first used.  `openssl_ensure_initialized` will do the work
172  * under a mutex.
173  */
174 git_mutex openssl_mutex;
175 bool openssl_initialized;
176 
git_openssl_stream_global_init(void)177 int git_openssl_stream_global_init(void)
178 {
179 #ifndef GIT_OPENSSL_DYNAMIC
180 	return openssl_init();
181 #else
182 	if (git_mutex_init(&openssl_mutex) != 0)
183 		return -1;
184 
185 	return 0;
186 #endif
187 }
188 
openssl_ensure_initialized(void)189 static int openssl_ensure_initialized(void)
190 {
191 #ifdef GIT_OPENSSL_DYNAMIC
192 	int error = 0;
193 
194 	if (git_mutex_lock(&openssl_mutex) != 0)
195 		return -1;
196 
197 	if (!openssl_initialized) {
198 		if ((error = git_openssl_stream_dynamic_init()) == 0)
199 			error = openssl_init();
200 
201 		openssl_initialized = true;
202 	}
203 
204 	error |= git_mutex_unlock(&openssl_mutex);
205 	return error;
206 
207 #else
208 	return 0;
209 #endif
210 }
211 
212 #if !defined(GIT_OPENSSL_LEGACY) && !defined(GIT_OPENSSL_DYNAMIC)
git_openssl_set_locking(void)213 int git_openssl_set_locking(void)
214 {
215 # ifdef GIT_THREADS
216 	return 0;
217 # else
218 	git_error_set(GIT_ERROR_THREAD, "libgit2 was not built with threads");
219 	return -1;
220 # endif
221 }
222 #endif
223 
224 
bio_create(BIO * b)225 static int bio_create(BIO *b)
226 {
227 	BIO_set_init(b, 1);
228 	BIO_set_data(b, NULL);
229 
230 	return 1;
231 }
232 
bio_destroy(BIO * b)233 static int bio_destroy(BIO *b)
234 {
235 	if (!b)
236 		return 0;
237 
238 	BIO_set_data(b, NULL);
239 
240 	return 1;
241 }
242 
bio_read(BIO * b,char * buf,int len)243 static int bio_read(BIO *b, char *buf, int len)
244 {
245 	git_stream *io = (git_stream *) BIO_get_data(b);
246 
247 	return (int) git_stream_read(io, buf, len);
248 }
249 
bio_write(BIO * b,const char * buf,int len)250 static int bio_write(BIO *b, const char *buf, int len)
251 {
252 	git_stream *io = (git_stream *) BIO_get_data(b);
253 	return (int) git_stream_write(io, buf, len, 0);
254 }
255 
bio_ctrl(BIO * b,int cmd,long num,void * ptr)256 static long bio_ctrl(BIO *b, int cmd, long num, void *ptr)
257 {
258 	GIT_UNUSED(b);
259 	GIT_UNUSED(num);
260 	GIT_UNUSED(ptr);
261 
262 	if (cmd == BIO_CTRL_FLUSH)
263 		return 1;
264 
265 	return 0;
266 }
267 
bio_gets(BIO * b,char * buf,int len)268 static int bio_gets(BIO *b, char *buf, int len)
269 {
270 	GIT_UNUSED(b);
271 	GIT_UNUSED(buf);
272 	GIT_UNUSED(len);
273 	return -1;
274 }
275 
bio_puts(BIO * b,const char * str)276 static int bio_puts(BIO *b, const char *str)
277 {
278 	return bio_write(b, str, strlen(str));
279 }
280 
init_bio_method(void)281 static int init_bio_method(void)
282 {
283 	/* Set up the BIO_METHOD we use for wrapping our own stream implementations */
284 	git_stream_bio_method = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "git_stream");
285 	GIT_ERROR_CHECK_ALLOC(git_stream_bio_method);
286 
287 	BIO_meth_set_write(git_stream_bio_method, bio_write);
288 	BIO_meth_set_read(git_stream_bio_method, bio_read);
289 	BIO_meth_set_puts(git_stream_bio_method, bio_puts);
290 	BIO_meth_set_gets(git_stream_bio_method, bio_gets);
291 	BIO_meth_set_ctrl(git_stream_bio_method, bio_ctrl);
292 	BIO_meth_set_create(git_stream_bio_method, bio_create);
293 	BIO_meth_set_destroy(git_stream_bio_method, bio_destroy);
294 
295 	return 0;
296 }
297 
ssl_set_error(SSL * ssl,int error)298 static int ssl_set_error(SSL *ssl, int error)
299 {
300 	int err;
301 	unsigned long e;
302 
303 	err = SSL_get_error(ssl, error);
304 
305 	GIT_ASSERT(err != SSL_ERROR_WANT_READ);
306 	GIT_ASSERT(err != SSL_ERROR_WANT_WRITE);
307 
308 	switch (err) {
309 	case SSL_ERROR_WANT_CONNECT:
310 	case SSL_ERROR_WANT_ACCEPT:
311 		git_error_set(GIT_ERROR_SSL, "SSL error: connection failure");
312 		break;
313 	case SSL_ERROR_WANT_X509_LOOKUP:
314 		git_error_set(GIT_ERROR_SSL, "SSL error: x509 error");
315 		break;
316 	case SSL_ERROR_SYSCALL:
317 		e = ERR_get_error();
318 		if (e > 0) {
319 			char errmsg[256];
320 			ERR_error_string_n(e, errmsg, sizeof(errmsg));
321 			git_error_set(GIT_ERROR_NET, "SSL error: %s", errmsg);
322 			break;
323 		} else if (error < 0) {
324 			git_error_set(GIT_ERROR_OS, "SSL error: syscall failure");
325 			break;
326 		}
327 		git_error_set(GIT_ERROR_SSL, "SSL error: received early EOF");
328 		return GIT_EEOF;
329 		break;
330 	case SSL_ERROR_SSL:
331 	{
332 		char errmsg[256];
333 		e = ERR_get_error();
334 		ERR_error_string_n(e, errmsg, sizeof(errmsg));
335 		git_error_set(GIT_ERROR_SSL, "SSL error: %s", errmsg);
336 		break;
337 	}
338 	case SSL_ERROR_NONE:
339 	case SSL_ERROR_ZERO_RETURN:
340 	default:
341 		git_error_set(GIT_ERROR_SSL, "SSL error: unknown error");
342 		break;
343 	}
344 	return -1;
345 }
346 
ssl_teardown(SSL * ssl)347 static int ssl_teardown(SSL *ssl)
348 {
349 	int ret;
350 
351 	ret = SSL_shutdown(ssl);
352 	if (ret < 0)
353 		ret = ssl_set_error(ssl, ret);
354 	else
355 		ret = 0;
356 
357 	return ret;
358 }
359 
check_host_name(const char * name,const char * host)360 static int check_host_name(const char *name, const char *host)
361 {
362 	if (!strcasecmp(name, host))
363 		return 0;
364 
365 	if (gitno__match_host(name, host) < 0)
366 		return -1;
367 
368 	return 0;
369 }
370 
verify_server_cert(SSL * ssl,const char * host)371 static int verify_server_cert(SSL *ssl, const char *host)
372 {
373 	X509 *cert = NULL;
374 	X509_NAME *peer_name;
375 	ASN1_STRING *str;
376 	unsigned char *peer_cn = NULL;
377 	int matched = -1, type = GEN_DNS;
378 	GENERAL_NAMES *alts;
379 	struct in6_addr addr6;
380 	struct in_addr addr4;
381 	void *addr = NULL;
382 	int i = -1, j, error = 0;
383 
384 	if (SSL_get_verify_result(ssl) != X509_V_OK) {
385 		git_error_set(GIT_ERROR_SSL, "the SSL certificate is invalid");
386 		return GIT_ECERTIFICATE;
387 	}
388 
389 	/* Try to parse the host as an IP address to see if it is */
390 	if (p_inet_pton(AF_INET, host, &addr4)) {
391 		type = GEN_IPADD;
392 		addr = &addr4;
393 	} else {
394 		if (p_inet_pton(AF_INET6, host, &addr6)) {
395 			type = GEN_IPADD;
396 			addr = &addr6;
397 		}
398 	}
399 
400 
401 	cert = SSL_get_peer_certificate(ssl);
402 	if (!cert) {
403 		error = -1;
404 		git_error_set(GIT_ERROR_SSL, "the server did not provide a certificate");
405 		goto cleanup;
406 	}
407 
408 	/* Check the alternative names */
409 	alts = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
410 	if (alts) {
411 		int num;
412 
413 		num = sk_GENERAL_NAME_num(alts);
414 		for (i = 0; i < num && matched != 1; i++) {
415 			const GENERAL_NAME *gn = sk_GENERAL_NAME_value(alts, i);
416 			const char *name = (char *) ASN1_STRING_get0_data(gn->d.ia5);
417 			size_t namelen = (size_t) ASN1_STRING_length(gn->d.ia5);
418 
419 			/* Skip any names of a type we're not looking for */
420 			if (gn->type != type)
421 				continue;
422 
423 			if (type == GEN_DNS) {
424 				/* If it contains embedded NULs, don't even try */
425 				if (memchr(name, '\0', namelen))
426 					continue;
427 
428 				if (check_host_name(name, host) < 0)
429 					matched = 0;
430 				else
431 					matched = 1;
432 			} else if (type == GEN_IPADD) {
433 				/* Here name isn't so much a name but a binary representation of the IP */
434 				matched = addr && !!memcmp(name, addr, namelen);
435 			}
436 		}
437 	}
438 	GENERAL_NAMES_free(alts);
439 
440 	if (matched == 0)
441 		goto cert_fail_name;
442 
443 	if (matched == 1) {
444 		goto cleanup;
445 	}
446 
447 	/* If no alternative names are available, check the common name */
448 	peer_name = X509_get_subject_name(cert);
449 	if (peer_name == NULL)
450 		goto on_error;
451 
452 	if (peer_name) {
453 		/* Get the index of the last CN entry */
454 		while ((j = X509_NAME_get_index_by_NID(peer_name, NID_commonName, i)) >= 0)
455 			i = j;
456 	}
457 
458 	if (i < 0)
459 		goto on_error;
460 
461 	str = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name, i));
462 	if (str == NULL)
463 		goto on_error;
464 
465 	/* Work around a bug in OpenSSL whereby ASN1_STRING_to_UTF8 fails if it's already in utf-8 */
466 	if (ASN1_STRING_type(str) == V_ASN1_UTF8STRING) {
467 		int size = ASN1_STRING_length(str);
468 
469 		if (size > 0) {
470 			peer_cn = OPENSSL_malloc(size + 1);
471 			GIT_ERROR_CHECK_ALLOC(peer_cn);
472 			memcpy(peer_cn, ASN1_STRING_get0_data(str), size);
473 			peer_cn[size] = '\0';
474 		} else {
475 			goto cert_fail_name;
476 		}
477 	} else {
478 		int size = ASN1_STRING_to_UTF8(&peer_cn, str);
479 		GIT_ERROR_CHECK_ALLOC(peer_cn);
480 		if (memchr(peer_cn, '\0', size))
481 			goto cert_fail_name;
482 	}
483 
484 	if (check_host_name((char *)peer_cn, host) < 0)
485 		goto cert_fail_name;
486 
487 	goto cleanup;
488 
489 cert_fail_name:
490 	error = GIT_ECERTIFICATE;
491 	git_error_set(GIT_ERROR_SSL, "hostname does not match certificate");
492 	goto cleanup;
493 
494 on_error:
495 	error = ssl_set_error(ssl, 0);
496 	goto cleanup;
497 
498 cleanup:
499 	X509_free(cert);
500 	OPENSSL_free(peer_cn);
501 	return error;
502 }
503 
504 typedef struct {
505 	git_stream parent;
506 	git_stream *io;
507 	int owned;
508 	bool connected;
509 	char *host;
510 	SSL *ssl;
511 	git_cert_x509 cert_info;
512 } openssl_stream;
513 
openssl_connect(git_stream * stream)514 static int openssl_connect(git_stream *stream)
515 {
516 	int ret;
517 	BIO *bio;
518 	openssl_stream *st = (openssl_stream *) stream;
519 
520 	if (st->owned && (ret = git_stream_connect(st->io)) < 0)
521 		return ret;
522 
523 	bio = BIO_new(git_stream_bio_method);
524 	GIT_ERROR_CHECK_ALLOC(bio);
525 
526 	BIO_set_data(bio, st->io);
527 	SSL_set_bio(st->ssl, bio, bio);
528 
529 	/* specify the host in case SNI is needed */
530 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
531 	SSL_set_tlsext_host_name(st->ssl, st->host);
532 #endif
533 
534 	if ((ret = SSL_connect(st->ssl)) <= 0)
535 		return ssl_set_error(st->ssl, ret);
536 
537 	st->connected = true;
538 
539 	return verify_server_cert(st->ssl, st->host);
540 }
541 
openssl_certificate(git_cert ** out,git_stream * stream)542 static int openssl_certificate(git_cert **out, git_stream *stream)
543 {
544 	openssl_stream *st = (openssl_stream *) stream;
545 	X509 *cert = SSL_get_peer_certificate(st->ssl);
546 	unsigned char *guard, *encoded_cert = NULL;
547 	int error, len;
548 
549 	/* Retrieve the length of the certificate first */
550 	len = i2d_X509(cert, NULL);
551 	if (len < 0) {
552 		git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information");
553 		error = -1;
554 		goto out;
555 	}
556 
557 	encoded_cert = git__malloc(len);
558 	GIT_ERROR_CHECK_ALLOC(encoded_cert);
559 	/* i2d_X509 makes 'guard' point to just after the data */
560 	guard = encoded_cert;
561 
562 	len = i2d_X509(cert, &guard);
563 	if (len < 0) {
564 		git_error_set(GIT_ERROR_NET, "failed to retrieve certificate information");
565 		error = -1;
566 		goto out;
567 	}
568 
569 	st->cert_info.parent.cert_type = GIT_CERT_X509;
570 	st->cert_info.data = encoded_cert;
571 	st->cert_info.len = len;
572 	encoded_cert = NULL;
573 
574 	*out = &st->cert_info.parent;
575 	error = 0;
576 
577 out:
578 	git__free(encoded_cert);
579 	X509_free(cert);
580 	return error;
581 }
582 
openssl_set_proxy(git_stream * stream,const git_proxy_options * proxy_opts)583 static int openssl_set_proxy(git_stream *stream, const git_proxy_options *proxy_opts)
584 {
585 	openssl_stream *st = (openssl_stream *) stream;
586 
587 	return git_stream_set_proxy(st->io, proxy_opts);
588 }
589 
openssl_write(git_stream * stream,const char * data,size_t data_len,int flags)590 static ssize_t openssl_write(git_stream *stream, const char *data, size_t data_len, int flags)
591 {
592 	openssl_stream *st = (openssl_stream *) stream;
593 	int ret, len = min(data_len, INT_MAX);
594 
595 	GIT_UNUSED(flags);
596 
597 	if ((ret = SSL_write(st->ssl, data, len)) <= 0)
598 		return ssl_set_error(st->ssl, ret);
599 
600 	return ret;
601 }
602 
openssl_read(git_stream * stream,void * data,size_t len)603 static ssize_t openssl_read(git_stream *stream, void *data, size_t len)
604 {
605 	openssl_stream *st = (openssl_stream *) stream;
606 	int ret;
607 
608 	if ((ret = SSL_read(st->ssl, data, len)) <= 0)
609 		return ssl_set_error(st->ssl, ret);
610 
611 	return ret;
612 }
613 
openssl_close(git_stream * stream)614 static int openssl_close(git_stream *stream)
615 {
616 	openssl_stream *st = (openssl_stream *) stream;
617 	int ret;
618 
619 	if (st->connected && (ret = ssl_teardown(st->ssl)) < 0)
620 		return -1;
621 
622 	st->connected = false;
623 
624 	return st->owned ? git_stream_close(st->io) : 0;
625 }
626 
openssl_free(git_stream * stream)627 static void openssl_free(git_stream *stream)
628 {
629 	openssl_stream *st = (openssl_stream *) stream;
630 
631 	if (st->owned)
632 		git_stream_free(st->io);
633 
634 	SSL_free(st->ssl);
635 	git__free(st->host);
636 	git__free(st->cert_info.data);
637 	git__free(st);
638 }
639 
openssl_stream_wrap(git_stream ** out,git_stream * in,const char * host,int owned)640 static int openssl_stream_wrap(
641 	git_stream **out,
642 	git_stream *in,
643 	const char *host,
644 	int owned)
645 {
646 	openssl_stream *st;
647 
648 	GIT_ASSERT_ARG(out);
649 	GIT_ASSERT_ARG(in);
650 	GIT_ASSERT_ARG(host);
651 
652 	st = git__calloc(1, sizeof(openssl_stream));
653 	GIT_ERROR_CHECK_ALLOC(st);
654 
655 	st->io = in;
656 	st->owned = owned;
657 
658 	st->ssl = SSL_new(git__ssl_ctx);
659 	if (st->ssl == NULL) {
660 		git_error_set(GIT_ERROR_SSL, "failed to create ssl object");
661 		git__free(st);
662 		return -1;
663 	}
664 
665 	st->host = git__strdup(host);
666 	GIT_ERROR_CHECK_ALLOC(st->host);
667 
668 	st->parent.version = GIT_STREAM_VERSION;
669 	st->parent.encrypted = 1;
670 	st->parent.proxy_support = git_stream_supports_proxy(st->io);
671 	st->parent.connect = openssl_connect;
672 	st->parent.certificate = openssl_certificate;
673 	st->parent.set_proxy = openssl_set_proxy;
674 	st->parent.read = openssl_read;
675 	st->parent.write = openssl_write;
676 	st->parent.close = openssl_close;
677 	st->parent.free = openssl_free;
678 
679 	*out = (git_stream *) st;
680 	return 0;
681 }
682 
git_openssl_stream_wrap(git_stream ** out,git_stream * in,const char * host)683 int git_openssl_stream_wrap(git_stream **out, git_stream *in, const char *host)
684 {
685 	if (openssl_ensure_initialized() < 0)
686 		return -1;
687 
688 	return openssl_stream_wrap(out, in, host, 0);
689 }
690 
git_openssl_stream_new(git_stream ** out,const char * host,const char * port)691 int git_openssl_stream_new(git_stream **out, const char *host, const char *port)
692 {
693 	git_stream *stream = NULL;
694 	int error;
695 
696 	GIT_ASSERT_ARG(out);
697 	GIT_ASSERT_ARG(host);
698 	GIT_ASSERT_ARG(port);
699 
700 	if (openssl_ensure_initialized() < 0)
701 		return -1;
702 
703 	if ((error = git_socket_stream_new(&stream, host, port)) < 0)
704 		return error;
705 
706 	if ((error = openssl_stream_wrap(out, stream, host, 1)) < 0) {
707 		git_stream_close(stream);
708 		git_stream_free(stream);
709 	}
710 
711 	return error;
712 }
713 
git_openssl__set_cert_location(const char * file,const char * path)714 int git_openssl__set_cert_location(const char *file, const char *path)
715 {
716 	if (openssl_ensure_initialized() < 0)
717 		return -1;
718 
719 	if (SSL_CTX_load_verify_locations(git__ssl_ctx, file, path) == 0) {
720 		char errmsg[256];
721 
722 		ERR_error_string_n(ERR_get_error(), errmsg, sizeof(errmsg));
723 		git_error_set(GIT_ERROR_SSL, "OpenSSL error: failed to load certificates: %s",
724 			errmsg);
725 
726 		return -1;
727 	}
728 	return 0;
729 }
730 
731 #else
732 
733 #include "stream.h"
734 #include "git2/sys/openssl.h"
735 
git_openssl_stream_global_init(void)736 int git_openssl_stream_global_init(void)
737 {
738 	return 0;
739 }
740 
git_openssl_set_locking(void)741 int git_openssl_set_locking(void)
742 {
743 	git_error_set(GIT_ERROR_SSL, "libgit2 was not built with OpenSSL support");
744 	return -1;
745 }
746 
747 #endif
748