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