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