2 * Copyright (C) the libgit2 contributors. All rights reserved.
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.
8 #include "streams/openssl.h"
17 #include "streams/socket.h"
19 #include "git2/transport.h"
20 #include "git2/sys/openssl.h"
23 # include "streams/curl.h"
27 # include <sys/types.h>
28 # include <sys/socket.h>
29 # include <netinet/in.h>
32 #include <openssl/ssl.h>
33 #include <openssl/err.h>
34 #include <openssl/x509v3.h>
35 #include <openssl/bio.h>
37 SSL_CTX
*git__ssl_ctx
;
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"
41 #if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
43 static git_mutex
*openssl_locks
;
45 static void openssl_locking_function(
46 int mode
, int n
, const char *file
, int line
)
53 lock
= mode
& CRYPTO_LOCK
;
56 git_mutex_lock(&openssl_locks
[n
]);
58 git_mutex_unlock(&openssl_locks
[n
]);
62 static void shutdown_ssl_locking(void)
66 num_locks
= CRYPTO_num_locks();
67 CRYPTO_set_locking_callback(NULL
);
69 for (i
= 0; i
< num_locks
; ++i
)
70 git_mutex_free(&openssl_locks
[i
]);
71 git__free(openssl_locks
);
74 #endif /* GIT_THREADS && OPENSSL_VERSION_NUMBER < 0x10100000L */
76 static BIO_METHOD
*git_stream_bio_method
;
77 static int init_bio_method(void);
80 * This function aims to clean-up the SSL context which
83 static void shutdown_ssl(void)
85 if (git_stream_bio_method
) {
86 BIO_meth_free(git_stream_bio_method
);
87 git_stream_bio_method
= NULL
;
91 SSL_CTX_free(git__ssl_ctx
);
96 int git_openssl_stream_global_init(void)
99 long ssl_opts
= SSL_OP_NO_SSLv2
| SSL_OP_NO_SSLv3
;
100 const char *ciphers
= git_libgit2__ssl_ciphers();
102 /* Older OpenSSL and MacOS OpenSSL doesn't have this */
103 #ifdef SSL_OP_NO_COMPRESSION
104 ssl_opts
|= SSL_OP_NO_COMPRESSION
;
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();
112 OPENSSL_init_ssl(0, NULL
);
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.
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
);
132 ciphers
= GIT_SSL_DEFAULT_CIPHERS
;
135 if(!SSL_CTX_set_cipher_list(git__ssl_ctx
, ciphers
)) {
136 SSL_CTX_free(git__ssl_ctx
);
141 if (init_bio_method() < 0) {
142 SSL_CTX_free(git__ssl_ctx
);
149 git__on_shutdown(shutdown_ssl
);
154 #if defined(GIT_THREADS)
155 static void threadid_cb(CRYPTO_THREADID
*threadid
)
157 CRYPTO_THREADID_set_numeric(threadid
, git_thread_currentid());
161 int git_openssl_set_locking(void)
163 #if defined(GIT_THREADS) && OPENSSL_VERSION_NUMBER < 0x10100000L
166 CRYPTO_THREADID_set_callback(threadid_cb
);
168 num_locks
= CRYPTO_num_locks();
169 openssl_locks
= git__calloc(num_locks
, sizeof(git_mutex
));
170 GITERR_CHECK_ALLOC(openssl_locks
);
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");
179 CRYPTO_set_locking_callback(openssl_locking_function
);
180 git__on_shutdown(shutdown_ssl_locking
);
182 #elif OPENSSL_VERSION_NUMBER >= 0x10100000L
185 giterr_set(GITERR_THREAD
, "libgit2 was not built with threads");
191 static int bio_create(BIO
*b
)
194 BIO_set_data(b
, NULL
);
199 static int bio_destroy(BIO
*b
)
204 BIO_set_data(b
, NULL
);
209 static int bio_read(BIO
*b
, char *buf
, int len
)
211 git_stream
*io
= (git_stream
*) BIO_get_data(b
);
213 return (int) git_stream_read(io
, buf
, len
);
216 static int bio_write(BIO
*b
, const char *buf
, int len
)
218 git_stream
*io
= (git_stream
*) BIO_get_data(b
);
220 return (int) git_stream_write(io
, buf
, len
, 0);
223 static long bio_ctrl(BIO
*b
, int cmd
, long num
, void *ptr
)
229 if (cmd
== BIO_CTRL_FLUSH
)
235 static int bio_gets(BIO
*b
, char *buf
, int len
)
243 static int bio_puts(BIO
*b
, const char *str
)
245 return bio_write(b
, str
, strlen(str
));
248 static int init_bio_method(void)
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
);
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
);
265 static int ssl_set_error(SSL
*ssl
, int error
)
270 err
= SSL_get_error(ssl
, error
);
272 assert(err
!= SSL_ERROR_WANT_READ
);
273 assert(err
!= SSL_ERROR_WANT_WRITE
);
276 case SSL_ERROR_WANT_CONNECT
:
277 case SSL_ERROR_WANT_ACCEPT
:
278 giterr_set(GITERR_NET
, "SSL error: connection failure");
280 case SSL_ERROR_WANT_X509_LOOKUP
:
281 giterr_set(GITERR_NET
, "SSL error: x509 error");
283 case SSL_ERROR_SYSCALL
:
287 ERR_error_string_n(e
, errmsg
, sizeof(errmsg
));
288 giterr_set(GITERR_NET
, "SSL error: %s", errmsg
);
290 } else if (error
< 0) {
291 giterr_set(GITERR_OS
, "SSL error: syscall failure");
294 giterr_set(GITERR_NET
, "SSL error: received early EOF");
301 ERR_error_string_n(e
, errmsg
, sizeof(errmsg
));
302 giterr_set(GITERR_NET
, "SSL error: %s", errmsg
);
306 case SSL_ERROR_ZERO_RETURN
:
308 giterr_set(GITERR_NET
, "SSL error: unknown error");
314 static int ssl_teardown(SSL
*ssl
)
318 ret
= SSL_shutdown(ssl
);
320 ret
= ssl_set_error(ssl
, ret
);
327 static int check_host_name(const char *name
, const char *host
)
329 if (!strcasecmp(name
, host
))
332 if (gitno__match_host(name
, host
) < 0)
338 static int verify_server_cert(SSL
*ssl
, const char *host
)
341 X509_NAME
*peer_name
;
343 unsigned char *peer_cn
= NULL
;
344 int matched
= -1, type
= GEN_DNS
;
346 struct in6_addr addr6
;
347 struct in_addr addr4
;
349 int i
= -1, j
, error
= 0;
351 if (SSL_get_verify_result(ssl
) != X509_V_OK
) {
352 giterr_set(GITERR_SSL
, "the SSL certificate is invalid");
353 return GIT_ECERTIFICATE
;
356 /* Try to parse the host as an IP address to see if it is */
357 if (p_inet_pton(AF_INET
, host
, &addr4
)) {
361 if (p_inet_pton(AF_INET6
, host
, &addr6
)) {
368 cert
= SSL_get_peer_certificate(ssl
);
371 giterr_set(GITERR_SSL
, "the server did not provide a certificate");
375 /* Check the alternative names */
376 alts
= X509_get_ext_d2i(cert
, NID_subject_alt_name
, NULL
, NULL
);
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
);
386 /* Skip any names of a type we're not looking for */
387 if (gn
->type
!= type
)
390 if (type
== GEN_DNS
) {
391 /* If it contains embedded NULs, don't even try */
392 if (memchr(name
, '\0', namelen
))
395 if (check_host_name(name
, host
) < 0)
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
);
405 GENERAL_NAMES_free(alts
);
414 /* If no alternative names are available, check the common name */
415 peer_name
= X509_get_subject_name(cert
);
416 if (peer_name
== NULL
)
420 /* Get the index of the last CN entry */
421 while ((j
= X509_NAME_get_index_by_NID(peer_name
, NID_commonName
, i
)) >= 0)
428 str
= X509_NAME_ENTRY_get_data(X509_NAME_get_entry(peer_name
, i
));
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
);
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';
445 int size
= ASN1_STRING_to_UTF8(&peer_cn
, str
);
446 GITERR_CHECK_ALLOC(peer_cn
);
447 if (memchr(peer_cn
, '\0', size
))
451 if (check_host_name((char *)peer_cn
, host
) < 0)
457 error
= GIT_ECERTIFICATE
;
458 giterr_set(GITERR_SSL
, "hostname does not match certificate");
462 error
= ssl_set_error(ssl
, 0);
467 OPENSSL_free(peer_cn
);
477 git_cert_x509 cert_info
;
480 int openssl_close(git_stream
*stream
);
482 int openssl_connect(git_stream
*stream
)
486 openssl_stream
*st
= (openssl_stream
*) stream
;
488 if ((ret
= git_stream_connect(st
->io
)) < 0)
491 st
->connected
= true;
493 bio
= BIO_new(git_stream_bio_method
);
494 GITERR_CHECK_ALLOC(bio
);
496 BIO_set_data(bio
, st
->io
);
497 SSL_set_bio(st
->ssl
, bio
, bio
);
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
);
504 if ((ret
= SSL_connect(st
->ssl
)) <= 0)
505 return ssl_set_error(st
->ssl
, ret
);
507 return verify_server_cert(st
->ssl
, st
->host
);
510 int openssl_certificate(git_cert
**out
, git_stream
*stream
)
512 openssl_stream
*st
= (openssl_stream
*) stream
;
514 X509
*cert
= SSL_get_peer_certificate(st
->ssl
);
515 unsigned char *guard
, *encoded_cert
;
517 /* Retrieve the length of the certificate first */
518 len
= i2d_X509(cert
, NULL
);
520 giterr_set(GITERR_NET
, "failed to retrieve certificate information");
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
;
529 len
= i2d_X509(cert
, &guard
);
531 git__free(encoded_cert
);
532 giterr_set(GITERR_NET
, "failed to retrieve certificate information");
536 st
->cert_info
.parent
.cert_type
= GIT_CERT_X509
;
537 st
->cert_info
.data
= encoded_cert
;
538 st
->cert_info
.len
= len
;
540 *out
= &st
->cert_info
.parent
;
545 static int openssl_set_proxy(git_stream
*stream
, const git_proxy_options
*proxy_opts
)
547 openssl_stream
*st
= (openssl_stream
*) stream
;
549 return git_stream_set_proxy(st
->io
, proxy_opts
);
552 ssize_t
openssl_write(git_stream
*stream
, const char *data
, size_t len
, int flags
)
554 openssl_stream
*st
= (openssl_stream
*) stream
;
559 if ((ret
= SSL_write(st
->ssl
, data
, len
)) <= 0) {
560 return ssl_set_error(st
->ssl
, ret
);
566 ssize_t
openssl_read(git_stream
*stream
, void *data
, size_t len
)
568 openssl_stream
*st
= (openssl_stream
*) stream
;
571 if ((ret
= SSL_read(st
->ssl
, data
, len
)) <= 0)
572 return ssl_set_error(st
->ssl
, ret
);
577 int openssl_close(git_stream
*stream
)
579 openssl_stream
*st
= (openssl_stream
*) stream
;
582 if (st
->connected
&& (ret
= ssl_teardown(st
->ssl
)) < 0)
585 st
->connected
= false;
587 return git_stream_close(st
->io
);
590 void openssl_free(git_stream
*stream
)
592 openssl_stream
*st
= (openssl_stream
*) stream
;
596 git__free(st
->cert_info
.data
);
597 git_stream_free(st
->io
);
601 int git_openssl_stream_new(git_stream
**out
, const char *host
, const char *port
)
606 st
= git__calloc(1, sizeof(openssl_stream
));
607 GITERR_CHECK_ALLOC(st
);
611 error
= git_curl_stream_new(&st
->io
, host
, port
);
613 error
= git_socket_stream_new(&st
->io
, host
, port
);
619 st
->ssl
= SSL_new(git__ssl_ctx
);
620 if (st
->ssl
== NULL
) {
621 giterr_set(GITERR_SSL
, "failed to create ssl object");
626 st
->host
= git__strdup(host
);
627 GITERR_CHECK_ALLOC(st
->host
);
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
;
640 *out
= (git_stream
*) st
;
644 git_stream_free(st
->io
);
650 int git_openssl__set_cert_location(const char *file
, const char *path
)
652 if (SSL_CTX_load_verify_locations(git__ssl_ctx
, file
, path
) == 0) {
655 ERR_error_string_n(ERR_get_error(), errmsg
, sizeof(errmsg
));
656 giterr_set(GITERR_SSL
, "OpenSSL error: failed to load certificates: %s",
667 #include "git2/sys/openssl.h"
669 int git_openssl_stream_global_init(void)
674 int git_openssl_set_locking(void)
676 giterr_set(GITERR_SSL
, "libgit2 was not built with OpenSSL support");
680 int git_openssl_stream_new(git_stream
**out
, const char *host
, const char *port
)
686 giterr_set(GITERR_SSL
, "openssl is not supported in this version");
690 int git_openssl__set_cert_location(const char *file
, const char *path
)
695 giterr_set(GITERR_SSL
, "openssl is not supported in this version");