From d430147bc60c72aa7aa71ee7da3160f86216ee5a Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Fri, 23 Jan 2015 18:38:06 +0100 Subject: [PATCH] Added TLS methods support --- CHANGES | 5 +++ config.h.in | 28 ++++++++++-- configure.in | 15 ++++++- doc/socat.yo | 11 +++-- sslcls.c | 56 ++++++++++++++++++++++++ sslcls.h | 8 +++- test.sh | 50 ++++++++++++++++++++- xio-openssl.c | 119 +++++++++++++++++++++++++++++++++++++------------- 8 files changed, 251 insertions(+), 41 deletions(-) diff --git a/CHANGES b/CHANGES index 7f4a505..a00c796 100644 --- a/CHANGES +++ b/CHANGES @@ -44,6 +44,9 @@ new features: SOCAT_OPENSSL_X509V3_SUBJECTALTNAME_DNS Tests: ENV_OPENSSL_{CLIENT,SERVER}_X509_* + Added support for methods TLSv1, TLSv1.1, TLSv1.2, and DTLS1 + Tests: OPENSSL_METHOD_* + corrections: Bind with ABSTRACT commands used non-abstract namespace (Linux). Test: ABSTRACT_BIND @@ -67,6 +70,8 @@ corrections: files that failed to compile due to missing IPPROTO_TCP. Thanks to Thierry Fournier for report and patch. + fixed a few minor bugs with OpenSSL in configure and with messages + porting: Socat included instead of POSIX Thanks to John Spencer for reporting this issue. diff --git a/config.h.in b/config.h.in index a9dd941..b61e35e 100644 --- a/config.h.in +++ b/config.h.in @@ -394,15 +394,37 @@ /* Define if you have the unsetenv function. not on HP-UX */ #undef HAVE_UNSETENV -/* Define if you have the SSLv2_client_method function. not in new openssl */ +/* Define if you have the SSLv2 client and server method functions. not in new openssl */ #undef HAVE_SSLv2_client_method - -/* Define if you have the SSLv2_server_method function. not in new openssl */ #undef HAVE_SSLv2_server_method /* Define if you have the HAVE_SSL_CTX_set_default_verify_paths function */ #undef HAVE_SSL_CTX_set_default_verify_paths +/* Define if you have the SSLv3 client and server method functions. not in new openssl */ +#undef HAVE_SSLv3_client_method +#undef HAVE_SSLv3_server_method + +/* Define if you have the SSLv3 client and server method functions with rollback to v2 */ +#undef HAVE_SSLv23_client_method +#undef HAVE_SSLv23_server_method + +/* Define if you have the TLSv1.0 client and server method functions */ +#undef HAVE_TLSv1_client_method +#undef HAVE_TLSv1_server_method + +/* Define if you have the TLSv1.1 client and server method functions */ +#undef HAVE_TLSv1_1_client_method +#undef HAVE_TLSv1_1_server_method + +/* Define if you have the TLSv1.2 client and server method functions */ +#undef HAVE_TLSv1_2_client_method +#undef HAVE_TLSv1_2_server_method + +/* Define if you have the DTLSv1 client and server method functions */ +#undef HAVE_DTLSv1_client_method +#undef HAVE_DTLSv1_server_method + /* Define if you have the flock function */ #undef HAVE_FLOCK diff --git a/configure.in b/configure.in index 910ce35..32b878d 100644 --- a/configure.in +++ b/configure.in @@ -1334,11 +1334,24 @@ dnl Search for unsetenv() AC_CHECK_FUNC(unsetenv, AC_DEFINE(HAVE_UNSETENV)) dnl Search for SSLv2_client_method, SSLv2_server_method -AC_CHECK_FUNC(SSLv3_client_method, AC_DEFINE(HAVE_SSLv3_client_method), AC_CHECK_LIB(crypt, SSLv3_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(SSLv2_client_method, AC_DEFINE(HAVE_SSLv2_client_method), AC_CHECK_LIB(crypt, SSLv2_client_method, [LIBS=-lcrypt $LIBS])) AC_CHECK_FUNC(SSLv2_server_method, AC_DEFINE(HAVE_SSLv2_server_method), AC_CHECK_LIB(crypt, SSLv2_server_method, [LIBS=-lcrypt $LIBS])) dnl AC_CHECK_FUNC(SSL_CTX_set_default_verify_paths, AC_DEFINE(HAVE_SSL_CTX_set_default_verify_paths)) +AC_CHECK_FUNC(SSLv3_client_method, AC_DEFINE(HAVE_SSLv3_client_method), AC_CHECK_LIB(crypt, SSLv3_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(SSLv3_server_method, AC_DEFINE(HAVE_SSLv3_server_method), AC_CHECK_LIB(crypt, SSLv3_server_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(SSLv23_client_method, AC_DEFINE(HAVE_SSLv23_client_method), AC_CHECK_LIB(crypt, SSLv23_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(SSLv23_server_method, AC_DEFINE(HAVE_SSLv23_server_method), AC_CHECK_LIB(crypt, SSLv23_server_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(TLSv1_client_method, AC_DEFINE(HAVE_TLSv1_client_method), AC_CHECK_LIB(crypt, TLSv1_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(TLSv1_server_method, AC_DEFINE(HAVE_TLSv1_server_method), AC_CHECK_LIB(crypt, TLSv1_server_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(TLSv1_1_client_method, AC_DEFINE(HAVE_TLSv1_1_client_method), AC_CHECK_LIB(crypt, TLSv1_1_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(TLSv1_1_server_method, AC_DEFINE(HAVE_TLSv1_1_server_method), AC_CHECK_LIB(crypt, TLSv1_1_server_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(TLSv1_2_client_method, AC_DEFINE(HAVE_TLSv1_2_client_method), AC_CHECK_LIB(crypt, TLSv1_2_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(TLSv1_2_server_method, AC_DEFINE(HAVE_TLSv1_2_server_method), AC_CHECK_LIB(crypt, TLSv1_2_server_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(DTLSv1_client_method, AC_DEFINE(HAVE_DTLSv1_client_method), AC_CHECK_LIB(crypt, DTLSv1_client_method, [LIBS=-lcrypt $LIBS])) +AC_CHECK_FUNC(DTLSv1_server_method, AC_DEFINE(HAVE_DTLSv1_server_method), AC_CHECK_LIB(crypt, DTLSv1_server_method, [LIBS=-lcrypt $LIBS])) + dnl Run time checks diff --git a/doc/socat.yo b/doc/socat.yo index 312f0de..e030a02 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -2635,11 +2635,14 @@ label(OPTION_OPENSSL_METHOD)dit(bf(tt(method=))) Sets the protocol version to be used. Valid strings (not case sensitive) are: startdit() - dit(tt(SSLv2)) Select SSL protocol version 2. - dit(tt(SSLv3)) Select SSL protocol version 3. - dit(tt(SSLv23)) Select SSL protocol version 2 or 3. This is the default when + dit(tt(SSL2)) Select SSL protocol version 2. + dit(tt(SSL3)) Select SSL protocol version 3. + dit(tt(SSL23)) Select the best available SSL or TLS protocol. This is the default when this option is not provided. - dit(tt(TLSv1)) Select TLS protocol version 1. + dit(tt(TLS1)) Select TLS protocol version 1. + dit(tt(TLS1.1)) Select TLS protocol version 1.1. + dit(tt(TLS1.2)) Select TLS protocol version 1.2. + dit(tt(DTLS1)) Select DTLS protocol version 1. enddit() label(OPTION_OPENSSL_VERIFY)dit(bf(tt(verify=))) Controls check of the peer's certificate. Default is 1 (true). Disabling diff --git a/sslcls.c b/sslcls.c index 7391abc..6ddc077 100644 --- a/sslcls.c +++ b/sslcls.c @@ -103,6 +103,62 @@ const SSL_METHOD *sycTLSv1_server_method(void) { return result; } +#if HAVE_TLSv1_1_client_method +const SSL_METHOD *sycTLSv1_1_client_method(void) { + const SSL_METHOD *result; + Debug("TLSv1_1_client_method()"); + result = TLSv1_1_client_method(); + Debug1("TLSv1_1_client_method() -> %p", result); + return result; +} +#endif + +#if HAVE_TLSv1_1_server_method +const SSL_METHOD *sycTLSv1_1_server_method(void) { + const SSL_METHOD *result; + Debug("TLSv1_1_server_method()"); + result = TLSv1_1_server_method(); + Debug1("TLSv1_1_server_method() -> %p", result); + return result; +} +#endif + +#if HAVE_TLSv1_2_client_method +const SSL_METHOD *sycTLSv1_2_client_method(void) { + const SSL_METHOD *result; + Debug("TLSv1_2_client_method()"); + result = TLSv1_2_client_method(); + Debug1("TLSv1_2_client_method() -> %p", result); + return result; +} +#endif + +#if HAVE_TLSv1_2_server_method +const SSL_METHOD *sycTLSv1_2_server_method(void) { + const SSL_METHOD *result; + Debug("TLSv1_2_server_method()"); + result = TLSv1_2_server_method(); + Debug1("TLSv1_2_server_method() -> %p", result); + return result; +} +#endif + +const SSL_METHOD *sycDTLSv1_client_method(void) { + const SSL_METHOD *result; + Debug("DTLSv1_client_method()"); + result = DTLSv1_client_method(); + Debug1("DTLSv1_client_method() -> %p", result); + return result; +} + +const SSL_METHOD *sycDTLSv1_server_method(void) { + const SSL_METHOD *result; + Debug("DTLSv1_server_method()"); + result = DTLSv1_server_method(); + Debug1("DTLSv1_server_method() -> %p", result); + return result; +} + SSL_CTX *sycSSL_CTX_new(const SSL_METHOD *method) { SSL_CTX *result; Debug1("SSL_CTX_new(%p)", method); diff --git a/sslcls.h b/sslcls.h index b324fff..aece28a 100644 --- a/sslcls.h +++ b/sslcls.h @@ -1,5 +1,5 @@ /* source: sslcls.h */ -/* Copyright Gerhard Rieger 2001-2011 */ +/* Copyright Gerhard Rieger */ /* Published under the GNU General Public License V.2, see file COPYING */ #ifndef __sslcls_h_included @@ -18,6 +18,12 @@ const SSL_METHOD *sycSSLv23_client_method(void); const SSL_METHOD *sycSSLv23_server_method(void); const SSL_METHOD *sycTLSv1_client_method(void); const SSL_METHOD *sycTLSv1_server_method(void); +const SSL_METHOD *sycTLSv1_1_client_method(void); +const SSL_METHOD *sycTLSv1_1_server_method(void); +const SSL_METHOD *sycTLSv1_2_client_method(void); +const SSL_METHOD *sycTLSv1_2_server_method(void); +const SSL_METHOD *sycDTLSv1_client_method(void); +const SSL_METHOD *sycDTLSv1_server_method(void); SSL_CTX *sycSSL_CTX_new(const SSL_METHOD *method); SSL *sycSSL_new(SSL_CTX *ctx); int sycSSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, diff --git a/test.sh b/test.sh index 0ee2c96..9c6fc56 100755 --- a/test.sh +++ b/test.sh @@ -11455,7 +11455,7 @@ N=$((N+1)) # Linux) with "Invalid argument". NAME=OPENSSL_CONNECT_BIND case "$TESTS" in -*%$N%*|*%functions%*|*%openssl%*|*%bugs%*|*%socket%*|*%ssl%*|*%$NAME%*) +*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%openssl%*|*%$NAME%*) TEST="$NAME: test OPENSSL-CONNECT with bind option" # have a simple SSL server that just echoes data. # connect with socat using OPENSSL-CONNECT with bind, send data and check if the @@ -12004,7 +12004,7 @@ unix-recvfrom . . unixport . -e FILE:/dev/null " -# bug fix: SYSTEM address child process shutted down parents sockets including +# bug fix: SYSTEM address child process shut down parents sockets including # SSL connection under some circumstances. NAME=SYSTEM_SHUTDOWN case "$TESTS" in @@ -12102,6 +12102,52 @@ esac PORT=$((PORT+1)) N=$((N+1)) +# test if the various SSL methods can be used with OpenSSL +for method in SSL3 SSL23 TLS1 TLS1.1 TLS1.2 DTLS1; do + +NAME=OPENSSL_METHOD_$method +case "$TESTS" in +*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%openssl%*|*%$NAME%*) +TEST="$NAME: test OpenSSL method $method" +# Start a socat process listening with OpenSSL and echoing data, +# using the selected method +# Start a second socat process connecting to the listener using +# the same method, send some data and catch the reply. +# If the reply is identical to the sent data the test succeeded. +if ! eval $NUMCOND; then :; else +tf="$td/test$N.stdout" +te="$td/test$N.stderr" +tdiff="$td/test$N.diff" +da="test$N $(date) $RANDOM" +CMD0="$SOCAT $opts OPENSSL-LISTEN:$PORT,reuseaddr,method=$method,cipher=aNULL,verify=0 PIPE" +CMD1="$SOCAT $opts - OPENSSL-CONNECT:$LOCALHOST:$PORT,method=$method,cipher=aNULL,verify=0" +printf "test $F_n $TEST... " $N +$CMD0 >/dev/null 2>"${te}0" & +pid0=$! +waittcp4port $PORT 1 +echo "$da" |$CMD1 >"${tf}1" 2>"${te}1" +rc1=$? +kill $pid0 2>/dev/null; wait +if echo "$da" |diff - "${tf}1"; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +else + $PRINTF "$FAILED\n" + echo "$CMD0 &" + echo "$CMD1" + cat "${te}0" + cat "${te}1" + numFAIL=$((numFAIL+1)) + listFAIL="$listFAIL $N" +fi +fi # NUMCOND + ;; +esac +PORT=$((PORT+1)) +N=$((N+1)) + +done + ################################################################################## #================================================================================= diff --git a/xio-openssl.c b/xio-openssl.c index 0e442dc..3d8c3f1 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -715,7 +715,7 @@ int SSL_CTX **ctx) { bool opt_fips = false; - const SSL_METHOD *method; + const SSL_METHOD *method = NULL; char *me_str = NULL; /* method string */ char *ci_str = "HIGH:-NULL:-PSK:-aNULL"; /* cipher string */ char *opt_key = NULL; /* file name of client private key */ @@ -771,54 +771,109 @@ int /*! actions_to_seed_PRNG();*/ if (!server) { - if (me_str != 0) { - if (!strcasecmp(me_str, "SSLv2") || !strcasecmp(me_str, "SSL2")) { + if (me_str != NULL) { + if (false) { + ; /* for canonical reasons */ #if HAVE_SSLv2_client_method + } else if (!strcasecmp(me_str, "SSL2")) { method = sycSSLv2_client_method(); -#else - Error1("OpenSSL method \"%s\" not provided by library", me_str); - method = sycSSLv23_server_method(); #endif - } else - if (!strcasecmp(me_str, "SSLv3") || !strcasecmp(me_str, "SSL3")) { +#if HAVE_SSLv3_client_method + } else if (!strcasecmp(me_str, "SSL3")) { method = sycSSLv3_client_method(); - } else if (!strcasecmp(me_str, "SSLv23") || !strcasecmp(me_str, "SSL23") || - !strcasecmp(me_str, "SSL")) { +#endif +#if HAVE_SSLv23_client_method + } else if (!strcasecmp(me_str, "SSL23")) { method = sycSSLv23_client_method(); - } else if (!strcasecmp(me_str, "TLSv1") || !strcasecmp(me_str, "TLS1") || - !strcasecmp(me_str, "TLS")) { +#endif +#if HAVE_TLSv1_client_method + } else if (!strcasecmp(me_str, "TLS1") || !strcasecmp(me_str, "TLS1.0")) { method = sycTLSv1_client_method(); +#endif +#if HAVE_TLSv1_1_client_method + } else if (!strcasecmp(me_str, "TLS1.1")) { + method = sycTLSv1_1_client_method(); +#endif +#if HAVE_TLSv1_2_client_method + } else if (!strcasecmp(me_str, "TLS1.2")) { + method = sycTLSv1_2_client_method(); +#endif +#if HAVE_DTLSv1_client_method + } else if (!strcasecmp(me_str, "DTLS") || !strcasecmp(me_str, "DTLS1")) { + method = sycDTLSv1_client_method(); +#endif } else { - Error1("openssl-method=\"%s\": unknown method", me_str); - method = sycSSLv23_client_method(); + Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str); } } else { +#if HAVE_TLSv1_2_client_method + method = sycTLSv1_2_client_method(); +#elif HAVE_TLSv1_1_client_method + method = sycTLSv1_1_client_method(); +#elif HAVE_TLSv1_client_method + method = sycTLSv1_client_method(); +#elif HAVE_SSLv3_client_method + method = sycSSLv3_client_method(); +#elif HAVE_SSLv23_client_method method = sycSSLv23_client_method(); +#elif HAVE_SSLv2_client_method + method = sycSSLv2_client_method(); +#else +# error "OpenSSL does not seem to provide client methods" +#endif } } else /* server */ { if (me_str != 0) { - if (!strcasecmp(me_str, "SSLv2") || !strcasecmp(me_str, "SSL2")) { + if (false) { + ; /* for canonical reasons */ + #if HAVE_SSLv2_server_method + } else if (!strcasecmp(me_str, "SSL2")) { method = sycSSLv2_server_method(); -#else - Error1("OpenSSL method \"%s\" not provided by library", me_str); +#endif +#if HAVE_SSLv3_server_method + } else if (!strcasecmp(me_str, "SSL3")) { + method = sycSSLv3_server_method(); +#endif +#if HAVE_SSLv23_server_method + } else if (!strcasecmp(me_str, "SSL23")) { method = sycSSLv23_server_method(); #endif - } else - if (!strcasecmp(me_str, "SSLv3") || !strcasecmp(me_str, "SSL3")) { - method = sycSSLv3_server_method(); - } else if (!strcasecmp(me_str, "SSLv23") || !strcasecmp(me_str, "SSL23") || - !strcasecmp(me_str, "SSL")) { - method = sycSSLv23_server_method(); - } else if (!strcasecmp(me_str, "TLSv1") || !strcasecmp(me_str, "TLS1") || - !strcasecmp(me_str, "TLS")) { +#if HAVE_TLSv1_server_method + } else if (!strcasecmp(me_str, "TLS1") || !strcasecmp(me_str, "TLS1.0")) { method = sycTLSv1_server_method(); +#endif +#if HAVE_TLSv1_1_server_method + } else if (!strcasecmp(me_str, "TLS1.1")) { + method = sycTLSv1_1_server_method(); +#endif +#if HAVE_TLSv1_2_server_method + } else if (!strcasecmp(me_str, "TLS1.2")) { + method = sycTLSv1_2_server_method(); +#endif +#if HAVE_DTLSv1_server_method + } else if (!strcasecmp(me_str, "DTLS") || !strcasecmp(me_str, "DTLS1")) { + method = sycDTLSv1_server_method(); +#endif } else { - Error1("openssl-method=\"%s\": unknown method", me_str); - method = sycSSLv23_server_method(); + Error1("openssl-method=\"%s\": method unknown or not provided by library", me_str); } } else { +#if HAVE_TLSv1_2_server_method + method = sycTLSv1_2_server_method(); +#elif HAVE_TLSv1_1_server_method + method = sycTLSv1_1_server_method(); +#elif HAVE_TLSv1_server_method + method = sycTLSv1_1_method(); +#elif HAVE_SSLv3_server_method + method = sycSSLv3_server_method(); +#elif HAVE_SSLv23_server_method method = sycSSLv23_server_method(); +#elif HAVE_SSLv2_server_method + method = sycSSLv2_server_method(); +#else +# error "OpenSSL does not seem to provide client methods" +#endif } } @@ -887,7 +942,7 @@ int } Error("BN_bin2bn() failed"); } else { - if (SSL_CTX_set_tmp_dh(*ctx, dh) <= 0) { + if (sycSSL_CTX_set_tmp_dh(*ctx, dh) <= 0) { while (err = ERR_get_error()) { Warn3("SSL_CTX_set_tmp_dh(%p, %p): %s", *ctx, dh, ERR_error_string(err, NULL)); @@ -961,8 +1016,12 @@ int Info1("PEM_read_bio_DHparams(%p, NULL, NULL, NULL): error", bio); } else { BIO_free(bio); - if (sycSSL_CTX_set_tmp_dh(*ctx, dh) == 0) { - Error2("SSL_CTX_set_tmp_dh(%p, %p): error", ctx, dh); + if (sycSSL_CTX_set_tmp_dh(*ctx, dh) <= 0) { + while (err = ERR_get_error()) { + Warn3("SSL_CTX_set_tmp_dh(%p, %p): %s", *ctx, dh, + ERR_error_string(err, NULL)); + } + Error2("SSL_CTX_set_tmp_dh(%p, %p): error", *ctx, dh); } } }