mbedtls: load default CA certificates
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 027e76a..fa86d9f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -193,6 +193,43 @@ IF (USE_HTTPS)
MESSAGE(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found")
ENDIF()
+ IF(NOT CERT_LOCATION)
+ MESSAGE("Auto-detecting default certificates location")
+ IF(CMAKE_SYSTEM_NAME MATCHES Darwin)
+ # Check for an Homebrew installation
+ SET(OPENSSL_CMD "/usr/local/opt/openssl/bin/openssl")
+ ELSE()
+ SET(OPENSSL_CMD "openssl")
+ ENDIF()
+ EXECUTE_PROCESS(COMMAND ${OPENSSL_CMD} version -d OUTPUT_VARIABLE OPENSSL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
+ IF(OPENSSL_DIR)
+ STRING(REGEX REPLACE "^OPENSSLDIR: \"(.*)\"$" "\\1/" OPENSSL_DIR ${OPENSSL_DIR})
+
+ SET(OPENSSL_CA_LOCATIONS
+ "ca-bundle.pem" # OpenSUSE Leap 42.1
+ "cert.pem" # Ubuntu 14.04, FreeBSD
+ "certs/ca-certificates.crt" # Ubuntu 16.04
+ "certs/ca.pem" # Debian 7
+ )
+ FOREACH(SUFFIX IN LISTS OPENSSL_CA_LOCATIONS)
+ SET(LOC "${OPENSSL_DIR}${SUFFIX}")
+ IF(NOT CERT_LOCATION AND EXISTS "${OPENSSL_DIR}${SUFFIX}")
+ SET(CERT_LOCATION ${LOC})
+ ENDIF()
+ ENDFOREACH()
+ ELSE()
+ MESSAGE("Unable to find OpenSSL executable. Please provide default certificate location via CERT_LOCATION")
+ ENDIF()
+ ENDIF()
+
+ IF(CERT_LOCATION)
+ IF(NOT EXISTS ${CERT_LOCATION})
+ MESSAGE(FATAL_ERROR "Cannot use CERT_LOCATION=${CERT_LOCATION} as it doesn't exist")
+ ENDIF()
+ ADD_FEATURE_INFO(CERT_LOCATION ON "using certificates from ${CERT_LOCATION}")
+ ADD_DEFINITIONS(-DGIT_DEFAULT_CERT_LOCATION="${CERT_LOCATION}")
+ ENDIF()
+
SET(GIT_MBEDTLS 1)
LIST(APPEND LIBGIT2_INCLUDES ${MBEDTLS_INCLUDE_DIR})
LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
diff --git a/src/settings.c b/src/settings.c
index 1195075..f6bc5b2 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -184,7 +184,10 @@ int git_libgit2_opts(int key, ...)
{
const char *file = va_arg(ap, const char *);
const char *path = va_arg(ap, const char *);
- error = git_mbedtls__set_cert_location(file, path);
+ if (file)
+ error = git_mbedtls__set_cert_location(file, 0);
+ if (error && path)
+ error = git_mbedtls__set_cert_location(path, 1);
}
#else
giterr_set(GITERR_SSL, "TLS backend doesn't support certificate locations");
diff --git a/src/streams/mbedtls.c b/src/streams/mbedtls.c
index ea96ae3..d134e86 100644
--- a/src/streams/mbedtls.c
+++ b/src/streams/mbedtls.c
@@ -22,13 +22,16 @@
# include "streams/curl.h"
#endif
+#ifndef GIT_DEFAULT_CERT_LOCATION
+#define GIT_DEFAULT_CERT_LOCATION NULL
+#endif
+
#include <mbedtls/config.h>
#include <mbedtls/ssl.h>
+#include <mbedtls/error.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
-#define CRT_LOC "/etc/ssl/certs"
-
mbedtls_ssl_config *git__ssl_conf;
mbedtls_entropy_context *mbedtls_entropy;
@@ -57,9 +60,13 @@ static void shutdown_ssl(void)
}
}
+int git_mbedtls__set_cert_location(const char *path, int is_dir);
+
int git_mbedtls_stream_global_init(void)
{
- int ret;
+ int loaded = 0;
+ char *crtpath = GIT_DEFAULT_CERT_LOCATION;
+ struct stat statbuf;
mbedtls_ctr_drbg_context *ctr_drbg = NULL;
int *ciphers_list = NULL;
@@ -121,16 +128,11 @@ int git_mbedtls_stream_global_init(void)
mbedtls_ssl_conf_rng(git__ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg);
- // set root certificates
- cacert = git__malloc(sizeof(mbedtls_x509_crt));
- mbedtls_x509_crt_init(cacert);
- ret = mbedtls_x509_crt_parse_path(cacert, CRT_LOC);
- if (ret) {
- giterr_set(GITERR_SSL, "failed to load CA certificates: %d", ret);
- goto cleanup;
- }
-
- mbedtls_ssl_conf_ca_chain(git__ssl_conf, cacert, NULL);
+ /* load default certificates */
+ if (crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISREG(statbuf.st_mode))
+ loaded = (git_mbedtls__set_cert_location(crtpath, 0) == 0);
+ if (!loaded && crtpath != NULL && stat(crtpath, &statbuf) == 0 && S_ISDIR(statbuf.st_mode))
+ loaded = (git_mbedtls__set_cert_location(crtpath, 1) == 0);
git__on_shutdown(shutdown_ssl);
@@ -388,20 +390,34 @@ out_err:
return error;
}
-int git_mbedtls__set_cert_location(const char *file, const char *path)
+int git_mbedtls__set_cert_location(const char *path, int is_dir)
{
int ret = 0;
char errbuf[512];
- if (!file) {
- ret = mbedtls_x509_crt_parse_file(git__ssl_conf->ca_chain, file);
- } else if (!path) {
- ret = mbedtls_x509_crt_parse_path(git__ssl_conf->ca_chain, path);
+ mbedtls_x509_crt *cacert;
+
+ assert(path != NULL);
+
+ cacert = git__malloc(sizeof(mbedtls_x509_crt));
+ mbedtls_x509_crt_init(cacert);
+ if (is_dir) {
+ ret = mbedtls_x509_crt_parse_path(cacert, path);
+ } else {
+ ret = mbedtls_x509_crt_parse_file(cacert, path);
}
- if (ret != 0) {
+ /* mbedtls_x509_crt_parse_path returns the number of invalid certs on success */
+ if (ret < 0) {
+ mbedtls_x509_crt_free(cacert);
+ git__free(cacert);
mbedtls_strerror( ret, errbuf, 512 );
- giterr_set(GITERR_NET, "SSL error: %d - %s", ret, errbuf);
+ giterr_set(GITERR_SSL, "failed to load CA certificates : %s (%d)", errbuf, ret);
return -1;
}
+
+ mbedtls_x509_crt_free(git__ssl_conf->ca_chain);
+ git__free(git__ssl_conf->ca_chain);
+ mbedtls_ssl_conf_ca_chain(git__ssl_conf, cacert, NULL);
+
return 0;
}
@@ -424,10 +440,10 @@ int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
return -1;
}
-int git_mbedtls__set_cert_location(const char *file, const char *path)
+int git_mbedtls__set_cert_location(const char *path, int is_dir)
{
- GIT_UNUSED(file);
GIT_UNUSED(path);
+ GIT_UNUSED(is_dir);
giterr_set(GITERR_SSL, "mbedTLS is not supported in this version");
return -1;
diff --git a/src/streams/mbedtls.h b/src/streams/mbedtls.h
index 8dab2b6..7283698 100644
--- a/src/streams/mbedtls.h
+++ b/src/streams/mbedtls.h
@@ -15,6 +15,6 @@ extern int git_mbedtls_stream_global_init(void);
extern int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port);
-extern int git_mbedtls__set_cert_location(const char *file, const char *path);
+extern int git_mbedtls__set_cert_location(const char *path, int is_dir);
#endif