feat(core): Support older GnuTLS versions
Add version checking to GnuTLS and use manual host name verification in case GnuTLS does not support this natively. Because older GnuTLS versions do not support using the system trust, add a new configuration option to pass the system CA bundle. This option can also search for the default locations. If none is given, but the the GnuTLS version does not support loading the default system trust, compilation will fail.pull/56/head
parent
d79191fe91
commit
059a4075d9
|
@ -18,6 +18,7 @@ ARG_FRAMEWORK_DIR=""
|
|||
ARG_GSMAKE=`gnustep-config --variable=GNUSTEP_MAKEFILES`
|
||||
ARG_CFGMAKE="$PWD/config.make"
|
||||
ARG_CFGSSL="auto"
|
||||
ARG_CABUNDLE="none"
|
||||
ARG_FHSMAKE="$PWD/fhs-postinstall.make"
|
||||
ARG_WITH_GNUSTEP=0
|
||||
ARG_WITH_DEBUG=1
|
||||
|
@ -75,6 +76,7 @@ Build flags:
|
|||
--enable-debug turn on debugging and compile time warnings
|
||||
--enable-strip turn on stripping of debug symbols
|
||||
--with-ssl=SSL specify ssl library (none, ssl, gnutls, auto) [auto]
|
||||
--ca-bundle=CA_BUNDLE specify path to ca bundle (none, path, auto) [none]
|
||||
--enable-xml Enable xml support (auto if unspecified)
|
||||
--enable-mysql Enable mysql support (auto if unspecified)
|
||||
--enable-postgresql Enable postgresql support (auto if unspecified)
|
||||
|
@ -92,24 +94,24 @@ printParas() {
|
|||
if test $ARG_BEQUIET = 1; then echo " will be quite."; fi
|
||||
if test $ARG_NOCREATE = 1; then echo " won't create files"; fi
|
||||
if test "x$ARG_FRAMEWORK_DIR" != "x"; then
|
||||
echo " FHS: install in frameworks directory";
|
||||
echo " FHS: install in frameworks directory";
|
||||
elif test $DARG_IS_FHS = 1; then
|
||||
echo " FHS: install in FHS root";
|
||||
echo " FHS: install in FHS root";
|
||||
else
|
||||
echo " FHS: install in GNUstep tree";
|
||||
echo " FHS: install in GNUstep tree";
|
||||
fi
|
||||
|
||||
if test $ARG_WITH_DEBUG = 1; then
|
||||
if test $ARG_WITH_DEBUG = 1; then
|
||||
echo " debug: yes";
|
||||
else
|
||||
echo " debug: no";
|
||||
fi
|
||||
if test $ARG_WITH_STRIP = 1; then
|
||||
if test $ARG_WITH_STRIP = 1; then
|
||||
echo " strip: yes";
|
||||
else
|
||||
echo " strip: no";
|
||||
fi
|
||||
|
||||
|
||||
echo " prefix: $ARG_PREFIX"
|
||||
echo " frameworks: $ARG_FRAMEWORK_DIR"
|
||||
echo " gstep: $ARG_GSMAKE"
|
||||
|
@ -155,9 +157,9 @@ setupInternalGSMake() {
|
|||
ENABLE_PCH_OPT="--enable-pch"
|
||||
fi
|
||||
pregsmdir="$PWD"
|
||||
|
||||
|
||||
echo -n "configuring builtin gnustep-make environment (${SETUP_LOGNAME}) .."
|
||||
|
||||
|
||||
cd "$GSTEPMAKE_SRCDIR"
|
||||
./configure >${pregsmdir}/${SETUP_LOGNAME} \
|
||||
${ENABLE_PCH_OPT} \
|
||||
|
@ -171,7 +173,7 @@ setupInternalGSMake() {
|
|||
|
||||
echo -n ".. install .."
|
||||
$MAKE install >>${pregsmdir}/${SETUP_LOGNAME}
|
||||
|
||||
|
||||
ARG_GSMAKE="${INTERNAL_MAKEDIR}/Library/Makefiles/"
|
||||
ARG_IS_FHS=1
|
||||
DARG_IS_FHS=1
|
||||
|
@ -180,7 +182,7 @@ setupInternalGSMake() {
|
|||
if test "x$ARG_PREFIX" = "x"; then
|
||||
ARG_PREFIX="/usr/local/"
|
||||
fi
|
||||
|
||||
|
||||
cd "$pregsmdir"
|
||||
if test -f $ARG_GSMAKE/GNUstep.sh; then
|
||||
echo ".. done (log in ${SETUP_LOGNAME})."
|
||||
|
@ -229,7 +231,7 @@ setupAppleArgs() {
|
|||
if test "x${USES_INTERNAL_MAKE}" = "no"; then
|
||||
ARG_WITH_GNUSTEP=1
|
||||
fi
|
||||
|
||||
|
||||
# no reason to print a warning?
|
||||
#if test "x${xLIBRARY_COMBO}" != "xapple-apple-nil"; then
|
||||
# if test "x${LIBRARY_COMBO}" != "xapple-apple-apple"; then
|
||||
|
@ -285,7 +287,7 @@ validateArgs() {
|
|||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
if test $ARG_WITH_GNUSTEP = 1; then
|
||||
if test $DARG_IS_FHS = 1; then
|
||||
echo "error: configured for FHS root _and_ GNUstep tree. Choose one!"
|
||||
|
@ -316,17 +318,17 @@ genConfigMake() {
|
|||
# DYLD_LIBRARY_PATH
|
||||
# GUILE_LOAD_PATH
|
||||
# CLASSPATH
|
||||
|
||||
|
||||
if test $ARG_BEQUIET != 1; then
|
||||
echo "creating: $ARG_CFGMAKE"
|
||||
fi
|
||||
|
||||
|
||||
echo "# GNUstep environment configuration" > "${ARG_CFGMAKE}"
|
||||
cfgwrite "# created by: '$CFG_ARGS'"
|
||||
cfgwrite ""
|
||||
cfgwrite "SOPE_ROOT=`pwd | sed 's/ /\\\ /g'`"
|
||||
cfgwrite "include \${SOPE_ROOT}/Version"
|
||||
|
||||
|
||||
cfgwrite "# Note: you can override any option as a 'make' parameter, eg:"
|
||||
cfgwrite "# make debug=yes"
|
||||
cfgwrite ""
|
||||
|
@ -336,7 +338,7 @@ genConfigMake() {
|
|||
#cfgwrite "all :: "
|
||||
#cfgwrite " @echo Local GNUstep config.make is active"
|
||||
#cfgwrite ""
|
||||
|
||||
|
||||
# Note: GNUSTEP_TARGET_CPU is not yet available (set by common.make), so we
|
||||
# only have environment variables
|
||||
# Note: we can't set SYSTEM_LIB_DIR in this location, it gets overridden by
|
||||
|
@ -358,8 +360,8 @@ genConfigMake() {
|
|||
cfgwrite "endif"
|
||||
cfgwrite "GNUSTEP_INSTALLATION_DOMAIN:=LOCAL"
|
||||
cfgwrite "CONFIGURE_SYSTEM_LIB_DIR += -L/usr/\$(CGS_LIBDIR_NAME)/"
|
||||
|
||||
|
||||
|
||||
|
||||
if test "x$ARG_FRAMEWORK_DIR" != "x"; then
|
||||
cfgwrite "# configured to install in Frameworks directory"
|
||||
cfgwrite "FRAMEWORK_INSTALL_DIR:=${ARG_FRAMEWORK_DIR}"
|
||||
|
@ -396,7 +398,7 @@ genConfigMake() {
|
|||
cfgwrite "SOPE_TOOLS=\${GNUSTEP_TOOLS}"
|
||||
cfgwrite "SOPE_ADMIN_TOOLS=\${GNUSTEP_ADMIN_TOOLS}"
|
||||
fi
|
||||
|
||||
|
||||
if test $ARG_WITH_DEBUG = 1; then
|
||||
cfgwrite "# configured to produce debugging code";
|
||||
cfgwrite "debug:=yes"
|
||||
|
@ -406,7 +408,7 @@ genConfigMake() {
|
|||
cfgwrite "debug:=no"
|
||||
fi
|
||||
cfgwrite ""
|
||||
|
||||
|
||||
if test $ARG_WITH_STRIP = 1; then
|
||||
cfgwrite "# configured to produce stripped code";
|
||||
cfgwrite "strip:=yes"
|
||||
|
@ -419,7 +421,7 @@ genConfigMake() {
|
|||
cfgwrite "# enforce shared libraries";
|
||||
cfgwrite "shared:=yes"
|
||||
cfgwrite ""
|
||||
|
||||
|
||||
cfgwrite "# GNUstep environment variables:";
|
||||
for i in `env | grep GNUSTEP_ | sort`; do
|
||||
MAKE_ASSI="`echo $i | sed s/=/:=/`"
|
||||
|
@ -434,7 +436,7 @@ checkLinking() {
|
|||
# library-name => $1, type => $2
|
||||
local oldpwd="${PWD}"
|
||||
local tmpdir=".configure-test-$$"
|
||||
|
||||
|
||||
mkdir $tmpdir
|
||||
cd $tmpdir
|
||||
cp ../maintenance/dummytool.c .
|
||||
|
@ -443,7 +445,7 @@ checkLinking() {
|
|||
for LIB in $1;do
|
||||
LIBS="$LIBS -l${LIB}"
|
||||
done
|
||||
|
||||
|
||||
tmpmake="GNUmakefile"
|
||||
echo >$tmpmake "-include ../config.make"
|
||||
echo >>$tmpmake "include \$(GNUSTEP_MAKEFILES)/common.make"
|
||||
|
@ -457,10 +459,10 @@ checkLinking() {
|
|||
echo >>$tmpmake "SYSTEM_LIB_DIR += \$(CONFIGURE_SYSTEM_LIB_DIR)"
|
||||
echo >>$tmpmake "SYSTEM_LIB_DIR += ${LINK_SYSLIBDIRS}"
|
||||
echo >>$tmpmake "include \$(GNUSTEP_MAKEFILES)/ctool.make"
|
||||
|
||||
|
||||
$MAKE -s messages=yes -f $tmpmake linktest >out.log 2>err.log
|
||||
LINK_RESULT=$?
|
||||
|
||||
|
||||
if test $LINK_RESULT = 0; then
|
||||
echo "$2 library found: $1"
|
||||
cfgwrite "HAS_LIBRARY_$1=yes"
|
||||
|
@ -475,7 +477,7 @@ checkLinking() {
|
|||
LIBS=$OLDLIBS
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
cd "${oldpwd}"
|
||||
rm -rf $tmpdir
|
||||
|
||||
|
@ -514,6 +516,32 @@ checkDependencies() {
|
|||
checkLinking "gnutls" required;
|
||||
fi
|
||||
|
||||
if test "x$ARG_CABUNDLE" = "xauto"; then
|
||||
while read f; do
|
||||
if test -f $f; then
|
||||
echo "found $f"
|
||||
ARG_CABUNDLE="$f"
|
||||
break
|
||||
fi
|
||||
# we need this odd syntax in order not to spawn a sub
|
||||
# shell
|
||||
done << EOF
|
||||
/etc/ssl/certs/ca-certificates.crt
|
||||
/etc/pki/tls/certs/ca-bundle.crt
|
||||
/usr/share/ssl/certs/ca-bundle.crt
|
||||
/usr/local/share/certs/ca-root-nss.crt
|
||||
/etc/ssl/cert.pem
|
||||
EOF
|
||||
|
||||
if test "x$ARG_CABUNDLE" = "xauto"; then
|
||||
echo "failed to find CA root store"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if test "x$ARG_CABUNDLE" != "xnone"; then
|
||||
cfgwrite "CA_BUNDLE=$ARG_CABUNDLE"
|
||||
echo "Using CA Bundle: $ARG_CABUNDLE"
|
||||
fi
|
||||
if test "x$ARG_WITH_POSTGRESQL" = "xauto" ; then
|
||||
checkLinking "pq" optional;
|
||||
elif test $ARG_WITH_POSTGRESQL = 1 ; then
|
||||
|
@ -538,15 +566,15 @@ runIt() {
|
|||
if test $ARG_BEQUIET != 1; then
|
||||
printParas;
|
||||
fi
|
||||
|
||||
if test $ARG_NOCREATE = 1; then
|
||||
|
||||
if test $ARG_NOCREATE = 1; then
|
||||
if test $ARG_BEQUIET != 1; then
|
||||
echo "not creating the config file ...";
|
||||
fi
|
||||
else
|
||||
genConfigMake;
|
||||
checkDependencies;
|
||||
|
||||
|
||||
if test -x "${NGSTREAMS_DIR}/configure"; then
|
||||
if test $ARG_BEQUIET != 1; then
|
||||
echo -n "configuring NGStreams library .."
|
||||
|
@ -613,6 +641,10 @@ processOption() {
|
|||
extractFuncValue $1;
|
||||
ARG_CFGSSL="$VALUE"
|
||||
;;
|
||||
x--ca-bundle=*)
|
||||
extractFuncValue $1;
|
||||
ARG_CABUNDLE="$VALUE"
|
||||
;;
|
||||
"x--enable-mysql")
|
||||
ARG_WITH_MYSQL=1
|
||||
;;
|
||||
|
|
|
@ -60,6 +60,11 @@ NGStreams_LIBRARIES_DEPEND_UPON += -lssl -lcrypto
|
|||
endif
|
||||
endif
|
||||
|
||||
# pass CA bundle
|
||||
ifdef CA_BUNDLE
|
||||
ADDITIONAL_CPPFLAGS += -DCA_BUNDLE="\"$(CA_BUNDLE)\""
|
||||
endif
|
||||
|
||||
ADDITIONAL_CPPFLAGS += -Wall -Wno-protocol
|
||||
|
||||
# reentrant
|
||||
|
|
|
@ -57,6 +57,7 @@ DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#if HAVE_GNUTLS
|
||||
# include <gnutls/gnutls.h>
|
||||
# include <gnutls/x509.h>
|
||||
#define LOOP_CHECK(rval, cmd) \
|
||||
do { \
|
||||
rval = cmd; \
|
||||
|
@ -106,6 +107,90 @@ DEALINGS IN THE SOFTWARE.
|
|||
}
|
||||
|
||||
#if HAVE_GNUTLS
|
||||
|
||||
/* This function will verify the peer's certificate, and check
|
||||
* if the hostname matches, as well as the activation, expiration dates.
|
||||
*/
|
||||
static int
|
||||
_verify_certificate_callback (gnutls_session_t session)
|
||||
{
|
||||
unsigned int status;
|
||||
const gnutls_datum_t *cert_list;
|
||||
unsigned int cert_list_size;
|
||||
int ret;
|
||||
gnutls_x509_crt_t cert;
|
||||
const char *hostname;
|
||||
|
||||
/* read hostname */
|
||||
hostname = gnutls_session_get_ptr (session);
|
||||
|
||||
/* This verification function uses the trusted CAs in the credentials
|
||||
* structure. So you must have installed one or more CA certificates.
|
||||
*/
|
||||
ret = gnutls_certificate_verify_peers2 (session, &status);
|
||||
if (ret < 0)
|
||||
{
|
||||
NSLog(@"ERROR: verify_peer2 failed");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
|
||||
NSLog(@"ERROR: The certificate hasn't got a known issuer.");
|
||||
|
||||
if (status & GNUTLS_CERT_REVOKED)
|
||||
NSLog(@"ERROR: The certificate has been revoked.");
|
||||
|
||||
if (status & GNUTLS_CERT_EXPIRED)
|
||||
NSLog(@"ERROR: The certificate has expired");
|
||||
|
||||
if (status & GNUTLS_CERT_NOT_ACTIVATED)
|
||||
NSLog(@"ERROR: The certificate is not yet activated");
|
||||
|
||||
if (status & GNUTLS_CERT_INVALID)
|
||||
{
|
||||
NSLog(@"ERROR: The certificate is not trusted.");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
/* Up to here the process is the same for X.509 certificates and
|
||||
* OpenPGP keys. From now on X.509 certificates are assumed. This can
|
||||
* be easily extended to work with openpgp keys as well.
|
||||
*/
|
||||
if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509)
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
|
||||
if (gnutls_x509_crt_init (&cert) < 0)
|
||||
{
|
||||
NSLog(@"WARNING: could not initialize gnutls certificate");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
cert_list = gnutls_certificate_get_peers (session, &cert_list_size);
|
||||
if (cert_list == NULL)
|
||||
{
|
||||
NSLog(@"WARNING: GnuTLS certificate not found");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
if (gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
|
||||
{
|
||||
NSLog(@"WARNING: Unable to parse certificate");
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (!gnutls_x509_crt_check_hostname (cert, hostname))
|
||||
{
|
||||
NSLog(@"ERROR: Certificate does not match hostname '%s'", hostname);
|
||||
return GNUTLS_E_CERTIFICATE_ERROR;
|
||||
}
|
||||
|
||||
gnutls_x509_crt_deinit (cert);
|
||||
|
||||
/* notify gnutls to continue handshake normally */
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (id)initWithDomain:(id<NGSocketDomain>)_domain
|
||||
onHostName: (NSString *)_hostName
|
||||
{
|
||||
|
@ -132,8 +217,13 @@ DEALINGS IN THE SOFTWARE.
|
|||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
#ifdef CA_BUNDLE
|
||||
ret = gnutls_certificate_set_x509_trust_file(self->cred, CA_BUNDLE, GNUTLS_X509_FMT_PEM);
|
||||
#elif GNUTLS_VERSION_NUMBER >= 0x030020
|
||||
ret = gnutls_certificate_set_x509_system_trust(self->cred);
|
||||
#else
|
||||
#error "Cant use default system trust, CA_BUNDLE needs to be passed"
|
||||
#endif
|
||||
if (ret < 0)
|
||||
{
|
||||
NSLog(@"ERROR(%s): could not set GnuTLS system trust (%s)",
|
||||
|
@ -142,6 +232,10 @@ DEALINGS IN THE SOFTWARE.
|
|||
return nil;
|
||||
}
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030406
|
||||
gnutls_certificate_set_verify_function(self->cred, _verify_certificate_callback);
|
||||
#endif /* GNUTLS_VERSION_NUMBER >= 0x030406*/
|
||||
|
||||
self->session = NULL;
|
||||
}
|
||||
return self;
|
||||
|
@ -232,7 +326,11 @@ DEALINGS IN THE SOFTWARE.
|
|||
return NO;
|
||||
}
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030406
|
||||
gnutls_session_set_verify_cert(sess, [hostName UTF8String], 0);
|
||||
#else
|
||||
gnutls_session_set_ptr(session, (void *) [hostName UTF8String]);
|
||||
#endif /* GNUTLS_VERSION_NUMBER >= 0x030406*/
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER < 0x030109
|
||||
gnutls_transport_set_ptr(sess, (gnutls_transport_ptr_t)(long)self->fd);
|
||||
|
@ -240,7 +338,9 @@ DEALINGS IN THE SOFTWARE.
|
|||
gnutls_transport_set_int(sess, self->fd);
|
||||
#endif /* GNUTLS_VERSION_NUMBER < 0x030109 */
|
||||
|
||||
#if GNUTLS_VERSION_NUMBER >= 0x030100
|
||||
gnutls_handshake_set_timeout(sess, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
|
||||
#endif
|
||||
do {
|
||||
ret = gnutls_handshake(sess);
|
||||
} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
|
||||
|
@ -404,7 +504,12 @@ static int cert_verify_callback(X509_STORE_CTX *x509_ctx, void *arg)
|
|||
return nil;
|
||||
}
|
||||
// use system default trust store
|
||||
|
||||
#ifdef CA_BUNDLE
|
||||
SSL_CTX_load_verify_locations(self->ctx, CA_BUNDLE, NULL);
|
||||
#else
|
||||
SSL_CTX_set_default_verify_paths(self->ctx);
|
||||
#endif // CA_BUNDLE
|
||||
|
||||
if ((self->ssl = SSL_new(self->ctx)) == NULL) {
|
||||
// should set exception !
|
||||
|
|
Loading…
Reference in New Issue