Re-add support for OpenSSL prior to 1.1, but now require at least 1.0.2 and drop LibreSSL support.

This commit is contained in:
Jim Hague 2019-01-11 11:16:48 +00:00
parent 65f4fbbc81
commit 51cb570809
7 changed files with 213 additions and 41 deletions

4
.gitmodules vendored
View File

@ -10,3 +10,7 @@
path = stubby
url = https://github.com/getdnsapi/stubby.git
branch = develop
[submodule "src/ssl_dane"]
path = src/ssl_dane
url = https://github.com/getdnsapi/ssl_dane
branch = getdns

View File

@ -464,6 +464,24 @@ AC_ARG_WITH([gnutls],
fi
ACX_LIB_SSL
AC_SUBST([TLSDIR], 'openssl')
# Verify OpenSSL is at least version 1.0.2.
# We also check it's not LibreSSL, but that's a little later, not here.
AC_CHECK_FUNCS([X509_check_host SSL_dane_enable])
if test "x$ac_cv_func_X509_check_host" != xyes; then
AC_MSG_ERROR([getdns requires OpenSSL version 1.0.2 or later])
fi
AC_MSG_CHECKING([whether we need to compile/link DANE support])
DANESSL_XTRA_OBJS=""
if test "x$ac_cv_func_SSL_dane_enable" = xyes; then
AC_MSG_RESULT([no])
else
AC_MSG_RESULT([yes])
AC_DEFINE([USE_DANESSL], [1], [Define this to use DANE functions from the ssl_dane/danessl library.])
DANESSL_XTRA_OBJS="danessl.lo"
fi
AC_SUBST(DANESSL_XTRA_OBJS)
])
@ -472,17 +490,14 @@ if test $USE_NSS = "no" -a $USE_NETTLE = "no" ; then
AC_MSG_CHECKING([for LibreSSL])
if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_LIBRESSL], [1], [Define if we have LibreSSL])
# libressl provides these compat functions, but they may also be
# declared by the OS in libc. See if they have been declared.
AC_CHECK_DECLS([strlcpy,arc4random,arc4random_uniform])
AC_MSG_ERROR([getdns does not support LibreSSL])
else
AC_MSG_RESULT([no])
fi
AC_CHECK_HEADERS([openssl/conf.h openssl/ssl.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([openssl/bn.h openssl/rsa.h openssl/dsa.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version SSL_CTX_dane_enable SSL_dane_enable SSL_dane_tlsa_add X509_check_host X509_get_notAfter X509_get0_notAfter SSL_CTX_set_ciphersuites SSL_set_ciphersuites])
AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version SSL_CTX_dane_enable SSL_dane_enable SSL_dane_tlsa_add X509_check_host X509_get_notAfter X509_get0_notAfter SSL_CTX_set_ciphersuites SSL_set_ciphersuites OPENSSL_init_crypto DSA_set0_pqg DSA_set0_key RSA_set0_key])
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set1_curves_list,SSL_set1_curves_list,SSL_set_min_proto_version,SSL_get_min_proto_version], [], [], [
AC_INCLUDES_DEFAULT
#ifdef HAVE_OPENSSL_ERR_H
@ -505,25 +520,6 @@ AC_INCLUDES_DEFAULT
])
fi
AC_MSG_CHECKING([for OpenSSL >= 1.1.1])
AC_LANG_PUSH(C)
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([
[#include <openssl/opensslv.h>]
[#if OPENSSL_VERSION_NUMBER < 0x10101000L]
[#error "OpenSSL 1.1.1 or higher required"]
[#elif defined(LIBRESSL_VERSION_NUMBER)]
[#error "LibreSSL not supported"]
[#endif]
],[[]])],
[
AC_MSG_RESULT([yes])
],
[
AC_MSG_ERROR([OpenSSL 1.1.1 or later required])
])
AC_LANG_POP(C)
AC_ARG_ENABLE(sha1, AC_HELP_STRING([--disable-sha1], [Disable SHA1 RRSIG support, does not disable nsec3 support]))
case "$enable_sha1" in
no)

View File

@ -99,8 +99,9 @@ TLS_OBJ=tls.lo pubkey-pinning-internal.lo keyraw-internal.lo val_secalgo.lo anch
YXML_OBJ=yxml.lo
YAML_OBJ=convert_yaml_to_json.lo
DANESSL_OBJ=danessl.lo
GETDNS_XTRA_OBJS=@GETDNS_XTRA_OBJS@
GETDNS_XTRA_OBJS=@GETDNS_XTRA_OBJS@ @DANESSL_XTRA_OBJS@
STUBBY_XTRA_OBJS=@STUBBY_XTRA_OBJS@
EXTENSION_OBJ=$(DEFAULT_EVENTLOOP_OBJ) libevent.lo libev.lo
@ -140,6 +141,9 @@ $(TLS_OBJ):
$(YAML_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -c $(stubbysrcdir)/src/yaml/$(@:.lo=.c) -o $@
$(DANESSL_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) $(WNOERRORFLAG) -c $(srcdir)/ssl_dane/$(@:.lo=.c) -o $@
$(YXML_OBJ):
$(LIBTOOL) --quiet --tag=CC --mode=compile $(CC) $(CFLAGS) -I$(srcdir)/yxml -DYXML_GETDNS -Wno-unused-parameter -c $(srcdir)/yxml/$(@:.lo=.c) -o $@

View File

@ -140,6 +140,8 @@ gldns_key_buf2dsa_raw(unsigned char* key, size_t len)
BN_free(Y);
return NULL;
}
#if defined(HAVE_DSA_SET0_PQG) && defined(HAVE_DSA_SET0_KEY)
if (!DSA_set0_pqg(dsa, P, Q, G)) {
/* QPG not yet attached, need to free */
BN_free(Q);
@ -156,6 +158,14 @@ gldns_key_buf2dsa_raw(unsigned char* key, size_t len)
BN_free(Y);
return NULL;
}
#else
# ifndef S_SPLINT_S
dsa->p = P;
dsa->q = Q;
dsa->g = G;
dsa->pub_key = Y;
# endif /* splint */
#endif
return dsa;
}
@ -208,12 +218,20 @@ gldns_key_buf2rsa_raw(unsigned char* key, size_t len)
BN_free(modulus);
return NULL;
}
#if defined(HAVE_RSA_SET0_KEY)
if (!RSA_set0_key(rsa, modulus, exponent, NULL)) {
BN_free(exponent);
BN_free(modulus);
RSA_free(rsa);
return NULL;
}
#else
# ifndef S_SPLINT_S
rsa->n = modulus;
rsa->e = exponent;
# endif /* splint */
#endif
return rsa;
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018, NLnet Labs
* Copyright (c) 2018-2019, NLnet Labs
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -54,12 +54,18 @@
#define GETDNS_TLS_MAX_DIGEST_LENGTH (EVP_MAX_MD_SIZE)
typedef struct sha256_pin sha256_pin_t;
typedef struct _getdns_tls_context {
SSL_CTX* ssl;
} _getdns_tls_context;
typedef struct _getdns_tls_connection {
SSL* ssl;
#if defined(USE_DANESSL)
const char* auth_name;
sha256_pin_t* pinset;
#endif
} _getdns_tls_connection;
typedef struct _getdns_tls_session {

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018, NLnet Labs
* Copyright (c) 2018-2019, NLnet Labs
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -47,8 +47,20 @@
#include "debug.h"
#include "context.h"
#ifdef USE_DANESSL
# include "ssl_dane/danessl.h"
#endif
#include "tls.h"
/* Double check configure has worked as expected. */
#if defined(USE_DANESSL) && \
(defined(HAVE_SSL_DANE_ENABLE) || \
defined(HAVE_OPENSSL_INIT_CRYPTO) || \
defined(HAVE_SSL_CTX_DANE_ENABLE))
#error Configure error USE_DANESSL defined with OpenSSL 1.1 functions!
#endif
/* Cipher suites recommended in RFC7525. */
char const * const _getdns_tls_context_default_cipher_list =
"TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:"
@ -57,6 +69,26 @@ char const * const _getdns_tls_context_default_cipher_list =
static char const * const _getdns_tls_connection_opportunistic_cipher_list =
"DEFAULT";
#if defined(USE_DANESSL) && defined(STUB_DEBUG) && STUB_DEBUG
static void _stub_debug_print_openssl_errors(void)
{
unsigned long err;
char buffer[1024];
const char *file;
const char *data;
int line;
int flags;
while ((err = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
ERR_error_string_n(err, buffer, sizeof(buffer));
if (flags & ERR_TXT_STRING)
DEBUG_STUB("DEBUG OpenSSL Error: %s:%s:%d:%s\n", buffer, file, line, data);
else
DEBUG_STUB("DEBUG OpenSSL Error: %s:%s:%d\n", buffer, file, line);
}
}
#endif
static int _getdns_tls_verify_always_ok(int ok, X509_STORE_CTX *ctx)
{
# if defined(STUB_DEBUG) && STUB_DEBUG
@ -218,10 +250,19 @@ add_WIN_cacerts_to_openssl_store(SSL_CTX* tls_ctx)
void _getdns_tls_init()
{
#ifdef HAVE_OPENSSL_INIT_CRYPTO
OPENSSL_init_crypto( OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
(void)OPENSSL_init_ssl(0, NULL);
#else
OpenSSL_add_all_algorithms();
SSL_library_init();
# ifdef USE_DANESSL
(void) DANESSL_library_init();
# endif
#endif
}
_getdns_tls_context* _getdns_tls_context_new(struct mem_funcs* mfs)
@ -255,14 +296,20 @@ getdns_return_t _getdns_tls_context_free(struct mem_funcs* mfs, _getdns_tls_cont
void _getdns_tls_context_pinset_init(_getdns_tls_context* ctx)
{
# if defined(STUB_DEBUG) && STUB_DEBUG
int osr =
# else
(void)
# endif
SSL_CTX_dane_enable(ctx->ssl);
DEBUG_STUB("%s %-35s: DEBUG: SSL_CTX_dane_enable() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
int osr;
(void) osr;
#if defined(HAVE_SSL_CTX_DANE_ENABLE)
osr = SSL_CTX_dane_enable(ctx->ssl);
DEBUG_STUB("%s %-35s: DEBUG: SSL_CTX_dane_enable() -> %d\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
#elif defined(USE_DANESSL)
osr = DANESSL_CTX_init(ctx->ssl);
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_CTX_init() -> %d\n",
STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
#else
#error Must have either DANE SSL or OpenSSL v1.1.
#endif
}
getdns_return_t _getdns_tls_context_set_min_proto_1_2(_getdns_tls_context* ctx)
@ -367,6 +414,13 @@ getdns_return_t _getdns_tls_connection_shutdown(_getdns_tls_connection* conn)
if (!conn || !conn->ssl)
return GETDNS_RETURN_INVALID_PARAMETER;
#ifdef USE_DANESSL
# if defined(STUB_DEBUG) && STUB_DEBUG
_stub_debug_print_openssl_errors();
# endif
DANESSL_cleanup(conn->ssl);
#endif
switch (SSL_shutdown(conn->ssl)) {
case 0: return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
case 1: return GETDNS_RETURN_GOOD;
@ -485,12 +539,19 @@ getdns_return_t _getdns_tls_connection_setup_hostname_auth(_getdns_tls_connectio
if (!conn || !conn->ssl || !auth_name)
return GETDNS_RETURN_INVALID_PARAMETER;
#if defined(HAVE_SSL_DANE_ENABLE)
SSL_set_tlsext_host_name(conn->ssl, auth_name);
/* Set up native OpenSSL hostname verification */
X509_VERIFY_PARAM *param;
param = SSL_get0_param(conn->ssl);
X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, auth_name, 0);
#elif defined(USE_DANESSL)
/* Stash auth name away for use in cert verification. */
conn->auth_name = auth_name;
#else
#error Must have either DANE SSL or OpenSSL v1.1.
#endif
return GETDNS_RETURN_GOOD;
}
@ -499,6 +560,13 @@ getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* c
if (!conn || !conn->ssl || !auth_name)
return GETDNS_RETURN_INVALID_PARAMETER;
#if defined(USE_DANE_SSL)
/* Stash auth name and pinset away for use in cert verification. */
conn->auth_name = auth_name;
conn->pinset = pinset;
#endif
#if defined(HAVE_SSL_DANE_ENABLE)
int osr = SSL_dane_enable(conn->ssl, *auth_name ? auth_name : NULL);
(void) osr;
DEBUG_STUB("%s %-35s: DEBUG: SSL_dane_enable(\"%s\") -> %d\n"
@ -520,6 +588,38 @@ getdns_return_t _getdns_tls_connection_set_host_pinset(_getdns_tls_connection* c
if (osr > 0)
++n_pins;
}
#elif defined(USE_DANESSL)
if (pinset) {
const char *auth_names[2] = { auth_name, NULL };
int osr = DANESSL_init(conn->ssl,
*auth_name ? auth_name : NULL,
*auth_name ? auth_names : NULL);
(void) osr;
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_init(\"%s\") -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, auth_name, osr);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
const sha256_pin_t *pin_p;
size_t n_pins = 0;
for (pin_p = pinset; pin_p; pin_p = pin_p->next) {
osr = DANESSL_add_tlsa(conn->ssl, 3, 1, "sha256",
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
if (osr > 0)
++n_pins;
osr = DANESSL_add_tlsa(conn->ssl, 2, 1, "sha256",
(unsigned char *)pin_p->pin, SHA256_DIGEST_LENGTH);
DEBUG_STUB("%s %-35s: DEBUG: DANESSL_add_tlsa() -> %d\n"
, STUB_DEBUG_SETUP_TLS, __FUNC__, osr);
if (osr > 0)
++n_pins;
}
} else {
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, _getdns_tls_verify_always_ok);
}
#else
#error Must have either DANE SSL or OpenSSL v1.1.
#endif
return GETDNS_RETURN_GOOD;
}
@ -529,10 +629,38 @@ getdns_return_t _getdns_tls_connection_certificate_verify(_getdns_tls_connection
return GETDNS_RETURN_INVALID_PARAMETER;
long verify_result = SSL_get_verify_result(conn->ssl);
/* Since we don't have DANE validation yet, DANE validation
* failures are always pinset validation failures */
switch (verify_result) {
case X509_V_OK:
#if defined(USE_DANESSL)
{
getdns_return_t res = GETDNS_RETURN_GOOD;
X509* peer_cert = SSL_get_peer_certificate(conn->ssl);
if (peer_cert) {
if (conn->auth_name[0] &&
X509_check_host(peer_cert,
conn->auth_name,
strlen(conn->auth_name),
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS,
NULL) <= 0) {
if (errnum)
*errnum = 1;
if (errmsg)
*errmsg = "Hostname mismatch";
res = GETDNS_RETURN_GENERIC_ERROR;
}
X509_free(peer_cert);
}
return res;
}
#else
return GETDNS_RETURN_GOOD;
#endif
#if defined(HAVE_SSL_DANE_ENABLE)
case X509_V_ERR_DANE_NO_MATCH:
if (errnum)
*errnum = 0;
@ -540,13 +668,28 @@ getdns_return_t _getdns_tls_connection_certificate_verify(_getdns_tls_connection
*errmsg = "Pinset validation failure";
return GETDNS_RETURN_GENERIC_ERROR;
default:
if (errnum)
*errnum = verify_result;
if (errmsg)
*errmsg = X509_verify_cert_error_string(verify_result);
return GETDNS_RETURN_GENERIC_ERROR;
#elif defined(USE_DANESSL)
case X509_V_ERR_CERT_UNTRUSTED:
if (conn->pinset &&
!DANESSL_get_match_cert(conn->ssl, NULL, NULL, NULL)) {
if (errnum)
*errnum = 0;
if (errmsg)
*errmsg = "Pinset validation failure";
return GETDNS_RETURN_GENERIC_ERROR;
}
break;
#else
#error Must have either DANE SSL or OpenSSL v1.1.
#endif
}
/* General error if we get here. */
if (errnum)
*errnum = verify_result;
if (errmsg)
*errmsg = X509_verify_cert_error_string(verify_result);
return GETDNS_RETURN_GENERIC_ERROR;
}

1
src/ssl_dane Submodule

@ -0,0 +1 @@
Subproject commit dd093e585a237e0321d303ec35e84c393ef739f4