Commit ca3b2234 by Etienne Samson

mbedtls: initial support

parent 0eca4230
# - Try to find mbedTLS
# Once done this will define
#
# Read-Only variables
# MBEDTLS_FOUND - system has mbedTLS
# MBEDTLS_INCLUDE_DIR - the mbedTLS include directory
# MBEDTLS_LIBRARY_DIR - the mbedTLS library directory
# MBEDTLS_LIBRARIES - Link these to use mbedTLS
# MBEDTLS_LIBRARY - path to mbedTLS library
# MBEDX509_LIBRARY - path to mbedTLS X.509 library
# MBEDCRYPTO_LIBRARY - path to mbedTLS Crypto library
#
# Hint
# MBEDTLS_ROOT_DIR can be pointed to a local mbedTLS installation.
SET(_MBEDTLS_ROOT_HINTS
${MBEDTLS_ROOT_DIR}
ENV MBEDTLS_ROOT_DIR
)
SET(_MBEDTLS_ROOT_HINTS_AND_PATHS
HINTS ${_MBEDTLS_ROOT_HINTS}
PATHS ${_MBEDTLS_ROOT_PATHS}
)
FIND_PATH(MBEDTLS_INCLUDE_DIR
NAMES mbedtls/version.h
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES include
)
IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARIES)
# Already in cache, be silent
SET(MBEDTLS_FIND_QUIETLY TRUE)
ENDIF()
FIND_LIBRARY(MBEDTLS_LIBRARY
NAMES mbedtls libmbedtls
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES library
)
FIND_LIBRARY(MBEDX509_LIBRARY
NAMES mbedx509 libmbedx509
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES library
)
FIND_LIBRARY(MBEDCRYPTO_LIBRARY
NAMES mbedcrypto libmbedcrypto
${_MBEDTLS_ROOT_HINTS_AND_PATHS}
PATH_SUFFIXES library
)
IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY)
SET(MBEDTLS_FOUND TRUE)
ENDIF()
IF(MBEDTLS_FOUND)
# split mbedTLS into -L and -l linker options, so we can set them for pkg-config
GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_DIR ${MBEDTLS_LIBRARY} PATH)
GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY} NAME_WE)
GET_FILENAME_COMPONENT(MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY} NAME_WE)
GET_FILENAME_COMPONENT(MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY} NAME_WE)
STRING(REGEX REPLACE "^lib" "" MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY_FILE})
STRING(REGEX REPLACE "^lib" "" MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY_FILE})
STRING(REGEX REPLACE "^lib" "" MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY_FILE})
SET(MBEDTLS_LIBRARIES "-L${MBEDTLS_LIBRARY_DIR} -l${MBEDTLS_LIBRARY_FILE} -l${MBEDX509_LIBRARY_FILE} -l${MBEDCRYPTO_LIBRARY_FILE}")
IF(NOT MBEDTLS_FIND_QUIETLY)
MESSAGE(STATUS "Found mbedTLS:")
FILE(READ ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h MBEDTLSCONTENT)
STRING(REGEX MATCH "MBEDTLS_VERSION_STRING +\"[0-9|.]+\"" MBEDTLSMATCH ${MBEDTLSCONTENT})
IF (MBEDTLSMATCH)
STRING(REGEX REPLACE "MBEDTLS_VERSION_STRING +\"([0-9|.]+)\"" "\\1" MBEDTLS_VERSION ${MBEDTLSMATCH})
MESSAGE(STATUS " version ${MBEDTLS_VERSION}")
ENDIF(MBEDTLSMATCH)
MESSAGE(STATUS " TLS: ${MBEDTLS_LIBRARY}")
MESSAGE(STATUS " X509: ${MBEDX509_LIBRARY}")
MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}")
ENDIF(NOT MBEDTLS_FIND_QUIETLY)
ELSE(MBEDTLS_FOUND)
IF(MBEDTLS_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find mbedTLS")
ENDIF(MBEDTLS_FIND_REQUIRED)
ENDIF(MBEDTLS_FOUND)
MARK_AS_ADVANCED(
MBEDTLS_INCLUDE_DIR
MBEDTLS_LIBRARY_DIR
MBEDTLS_LIBRARIES
MBEDTLS_LIBRARY
MBEDX509_LIBRARY
MBEDCRYPTO_LIBRARY
)
......@@ -133,6 +133,7 @@ ELSE ()
ENDIF()
IF (USE_HTTPS)
FIND_PACKAGE(mbedTLS)
IF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
FIND_PACKAGE(Security)
FIND_PACKAGE(CoreFoundation)
......@@ -149,6 +150,8 @@ IF (USE_HTTPS)
ENDIF()
ELSEIF (WINHTTP)
SET(HTTPS_BACKEND "WinHTTP")
ELSEIF(MBEDTLS_FOUND)
SET(HTTPS_BACKEND "mbedTLS")
ELSE()
SET(HTTPS_BACKEND "OpenSSL")
ENDIF()
......@@ -185,6 +188,16 @@ IF (USE_HTTPS)
LIST(APPEND LIBGIT2_LIBS ${OPENSSL_LIBRARIES})
LIST(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS})
LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
ELSEIF(HTTPS_BACKEND STREQUAL "mbedTLS")
IF (NOT MBEDTLS_FOUND)
MESSAGE(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found")
ENDIF()
SET(GIT_MBEDTLS 1)
LIST(APPEND LIBGIT2_INCLUDES ${MBEDTLS_INCLUDE_DIR})
LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LDFLAGS})
LIST(APPEND LIBGIT2_PC_REQUIRES "mbedtls")
ELSEIF (HTTPS_BACKEND STREQUAL "WinHTTP")
# WinHTTP setup was handled in the WinHTTP-specific block above
ELSE()
......
......@@ -27,6 +27,7 @@
#cmakedefine GIT_HTTPS 1
#cmakedefine GIT_OPENSSL 1
#cmakedefine GIT_SECURE_TRANSPORT 1
#cmakedefine GIT_MBEDTLS 1
#cmakedefine GIT_SHA1_COLLISIONDETECT 1
#cmakedefine GIT_SHA1_WIN32 1
......
......@@ -11,6 +11,10 @@
# include <openssl/err.h>
#endif
#ifdef GIT_MBEDTLS
# include <mbedtls/error.h>
#endif
#include <git2.h>
#include "sysdir.h"
#include "cache.h"
......@@ -20,6 +24,7 @@
#include "refs.h"
#include "transports/smart.h"
#include "streams/openssl.h"
#include "streams/mbedtls.h"
void git_libgit2_version(int *major, int *minor, int *rev)
{
......@@ -175,6 +180,12 @@ int git_libgit2_opts(int key, ...)
const char *path = va_arg(ap, const char *);
error = git_openssl__set_cert_location(file, path);
}
#elif defined(GIT_MBEDTLS)
{
const char *file = va_arg(ap, const char *);
const char *path = va_arg(ap, const char *);
error = git_mbedtls__set_cert_location(file, path);
}
#else
giterr_set(GITERR_SSL, "TLS backend doesn't support certificate locations");
error = -1;
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "streams/mbedtls.h"
#ifdef GIT_MBEDTLS
#include <ctype.h>
#include "global.h"
#include "stream.h"
#include "streams/socket.h"
#include "netops.h"
#include "git2/transport.h"
#ifdef GIT_CURL
# include "streams/curl.h"
#endif
#include <mbedtls/ssl.h>
#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/error.h>
mbedtls_ssl_config *git__ssl_conf;
static int bio_read(void *b, unsigned char *buf, size_t len)
{
git_stream *io = (git_stream *) b;
return (int) git_stream_read(io, buf, len);
}
static int bio_write(void *b, const unsigned char *buf, size_t len)
{
git_stream *io = (git_stream *) b;
return (int) git_stream_write(io, (const char *)buf, len, 0);
}
static int ssl_set_error(mbedtls_ssl_context *ssl, int error)
{
char errbuf[512];
int ret = -1;
assert(error != MBEDTLS_ERR_SSL_WANT_READ);
assert(error != MBEDTLS_ERR_SSL_WANT_WRITE);
if (error != 0)
mbedtls_strerror( error, errbuf, 512 );
switch(error) {
case 0:
giterr_set(GITERR_SSL, "SSL error: unknown error");
break;
case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:
giterr_set(GITERR_SSL, "SSL error: %x[%x] - %s", error, ssl->session_negotiate->verify_result, errbuf);
ret = GIT_ECERTIFICATE;
break;
default:
giterr_set(GITERR_SSL, "SSL error: %x - %s", error, errbuf);
}
return ret;
}
static int ssl_teardown(mbedtls_ssl_context *ssl)
{
int ret = 0;
ret = mbedtls_ssl_close_notify(ssl);
if (ret < 0)
ret = ssl_set_error(ssl, ret);
mbedtls_ssl_free(ssl);
return ret;
}
static int verify_server_cert(mbedtls_ssl_context *ssl, const char *host)
{
const mbedtls_x509_crt *cert;
int flags;
struct in6_addr addr6;
struct in_addr addr4;
void *addr;
if( ( flags = mbedtls_ssl_get_verify_result(ssl) ) != 0 )
{
char vrfy_buf[512];
mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags );
giterr_set(GITERR_SSL, "The SSL certificate is invalid: %s", vrfy_buf);
return GIT_ECERTIFICATE;
}
/* Try to parse the host as an IP address to see if it is */
if (p_inet_pton(AF_INET, host, &addr4)) {
addr = &addr4;
} else {
if(p_inet_pton(AF_INET6, host, &addr6)) {
addr = &addr6;
}
}
cert = mbedtls_ssl_get_peer_cert(ssl);
if (!cert) {
giterr_set(GITERR_SSL, "the server did not provide a certificate");
return -1;
}
/* Check the alternative names */
//TODO: cert->subject_alt_names
/* If no alternative names are available, check the common name */
/*TODO
mbedtls_x509_name peer_name = cert->subject;
if (peer_name == NULL)
goto on_error;
*/
return 0;
on_error:
return ssl_set_error(ssl, 0);
cert_fail_name:
giterr_set(GITERR_SSL, "hostname does not match certificate");
return GIT_ECERTIFICATE;
}
typedef struct {
git_stream parent;
git_stream *io;
bool connected;
char *host;
mbedtls_ssl_context *ssl;
git_cert_x509 cert_info;
} mbedtls_stream;
int mbedtls_connect(git_stream *stream)
{
int ret;
mbedtls_stream *st = (mbedtls_stream *) stream;
if ((ret = git_stream_connect(st->io)) < 0)
return ret;
st->connected = true;
mbedtls_ssl_set_bio(st->ssl, st->io, bio_write, bio_read, NULL);
/* specify the host in case SNI is needed */
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
mbedtls_ssl_set_hostname(st->ssl, st->host);
#endif
if ((ret = mbedtls_ssl_handshake(st->ssl)) != 0)
return ssl_set_error(st->ssl, ret);
return verify_server_cert(st->ssl, st->host);
}
int mbedtls_certificate(git_cert **out, git_stream *stream)
{
unsigned char *encoded_cert;
mbedtls_stream *st = (mbedtls_stream *) stream;
const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(st->ssl);
if (!cert) {
giterr_set(GITERR_SSL, "the server did not provide a certificate");
return -1;
}
/* Retrieve the length of the certificate first */
if (cert->raw.len == 0) {
giterr_set(GITERR_NET, "failed to retrieve certificate information");
return -1;
}
encoded_cert = git__malloc(cert->raw.len);
GITERR_CHECK_ALLOC(encoded_cert);
memcpy(encoded_cert, cert->raw.p, cert->raw.len);
st->cert_info.parent.cert_type = GIT_CERT_X509;
st->cert_info.data = encoded_cert;
st->cert_info.len = cert->raw.len;
*out = &st->cert_info.parent;
return 0;
}
static int mbedtls_set_proxy(git_stream *stream, const git_proxy_options *proxy_options)
{
mbedtls_stream *st = (mbedtls_stream *) stream;
return git_stream_set_proxy(st->io, proxy_options);
}
ssize_t mbedtls_stream_write(git_stream *stream, const char *data, size_t len, int flags)
{
mbedtls_stream *st = (mbedtls_stream *) stream;
int ret;
GIT_UNUSED(flags);
if ((ret = mbedtls_ssl_write(st->ssl, (const unsigned char *)data, len)) <= 0) {
return ssl_set_error(st->ssl, ret);
}
return ret;
}
ssize_t mbedtls_stream_read(git_stream *stream, void *data, size_t len)
{
mbedtls_stream *st = (mbedtls_stream *) stream;
int ret;
if ((ret = mbedtls_ssl_read(st->ssl, (unsigned char *)data, len)) <= 0)
ssl_set_error(st->ssl, ret);
return ret;
}
int mbedtls_stream_close(git_stream *stream)
{
mbedtls_stream *st = (mbedtls_stream *) stream;
int ret = 0;
if (st->connected && (ret = ssl_teardown(st->ssl)) != 0)
return -1;
st->connected = false;
return git_stream_close(st->io);
}
void mbedtls_stream_free(git_stream *stream)
{
mbedtls_stream *st = (mbedtls_stream *) stream;
git__free(st->host);
git__free(st->cert_info.data);
git_stream_free(st->io);
git__free(st->ssl);
git__free(st);
}
int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
{
int error;
mbedtls_stream *st;
st = git__calloc(1, sizeof(mbedtls_stream));
GITERR_CHECK_ALLOC(st);
#ifdef GIT_CURL
error = git_curl_stream_new(&st->io, host, port);
#else
error = git_socket_stream_new(&st->io, host, port);
#endif
if (error < 0)
goto out_err;
st->ssl = git__malloc(sizeof(mbedtls_ssl_context));
GITERR_CHECK_ALLOC(st->ssl);
mbedtls_ssl_init(st->ssl);
if (mbedtls_ssl_setup(st->ssl, git__ssl_conf)) {
giterr_set(GITERR_SSL, "failed to create ssl object");
error = -1;
goto out_err;
}
st->host = git__strdup(host);
GITERR_CHECK_ALLOC(st->host);
st->parent.version = GIT_STREAM_VERSION;
st->parent.encrypted = 1;
st->parent.proxy_support = git_stream_supports_proxy(st->io);
st->parent.connect = mbedtls_connect;
st->parent.certificate = mbedtls_certificate;
st->parent.set_proxy = mbedtls_set_proxy;
st->parent.read = mbedtls_stream_read;
st->parent.write = mbedtls_stream_write;
st->parent.close = mbedtls_stream_close;
st->parent.free = mbedtls_stream_free;
*out = (git_stream *) st;
return 0;
out_err:
mbedtls_ssl_free(st->ssl);
git_stream_free(st->io);
git__free(st);
return error;
}
int git_mbedtls__set_cert_location(const char *file, const char *path)
{
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);
}
if (ret != 0) {
mbedtls_strerror( ret, errbuf, 512 );
giterr_set(GITERR_NET, "SSL error: %d - %s", ret, errbuf);
return -1;
}
return 0;
}
#else
#include "stream.h"
int git_mbedtls_stream_new(git_stream **out, const char *host, const char *port)
{
GIT_UNUSED(out);
GIT_UNUSED(host);
GIT_UNUSED(port);
giterr_set(GITERR_SSL, "mbedTLS is not supported in this version");
return -1;
}
int git_mbedtls__set_cert_location(const char *file, const char *path)
{
GIT_UNUSED(file);
GIT_UNUSED(path);
giterr_set(GITERR_SSL, "mbedTLS is not supported in this version");
return -1;
}
#endif
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_steams_mbedtls_h__
#define INCLUDE_steams_mbedtls_h__
#include "common.h"
#include "git2/sys/stream.h"
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);
#endif
......@@ -9,6 +9,7 @@
#include "git2/errors.h"
#include "streams/mbedtls.h"
#include "streams/openssl.h"
#include "streams/stransport.h"
......@@ -31,6 +32,8 @@ int git_tls_stream_new(git_stream **out, const char *host, const char *port)
return git_stransport_stream_new(out, host, port);
#elif defined(GIT_OPENSSL)
return git_openssl_stream_new(out, host, port);
#elif defined(GIT_MBEDTLS)
return git_mbedtls_stream_new(out, host, port);
#else
GIT_UNUSED(out);
GIT_UNUSED(host);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment