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