From 6a79aa65295a1809a3ac6d91a0497b17e8af9d37 Mon Sep 17 00:00:00 2001 From: Gerhard Rieger Date: Thu, 2 Apr 2015 16:25:51 +0200 Subject: [PATCH] Added TLS methods support --- CHANGES | 4 ++ config.h.in | 29 ++++++++++-- configure.in | 16 ++++++- doc/socat.yo | 11 +++-- sslcls.c | 56 +++++++++++++++++++++++ sslcls.h | 6 +++ test.sh | 49 +++++++++++++++++++- xio-openssl.c | 124 ++++++++++++++++++++++++++++++++++++-------------- 8 files changed, 253 insertions(+), 42 deletions(-) diff --git a/CHANGES b/CHANGES index fc4e231..9aa3997 100644 --- a/CHANGES +++ b/CHANGES @@ -202,6 +202,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: Red Hat issue 1020203: configure checks fail with some compilers. Use case: clang @@ -306,6 +308,8 @@ 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_* docu minor corrections in docu (thanks to Paggas) diff --git a/config.h.in b/config.h.in index c08f709..be94bd7 100644 --- a/config.h.in +++ b/config.h.in @@ -394,15 +394,38 @@ /* 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 4e6ff4e..3716fe8 100644 --- a/configure.in +++ b/configure.in @@ -1350,11 +1350,25 @@ 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_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 3006289..2a2eecc 100644 --- a/doc/socat.yo +++ b/doc/socat.yo @@ -2704,11 +2704,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 58190c0..ea4c303 100644 --- a/sslcls.c +++ b/sslcls.c @@ -102,6 +102,62 @@ const SSL_METHOD *sycTLSv1_server_method(void) { Debug1("TLSv1_server_method() -> %p", result); 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; diff --git a/sslcls.h b/sslcls.h index fc837a3..152fe5b 100644 --- a/sslcls.h +++ b/sslcls.h @@ -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 d1e0623..94907ed 100755 --- a/test.sh +++ b/test.sh @@ -11843,7 +11843,7 @@ N=$((N+1)) # Linux) with "Invalid argument". NAME=OPENSSL_CONNECT_BIND case "$TESTS" in -*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%ssl%*|*%openssl%*|*%$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 @@ -12490,6 +12490,53 @@ 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 + + ############################################################################### # here come tests that might affect your systems integrity. Put normal tests # before this paragraph. diff --git a/xio-openssl.c b/xio-openssl.c index ff6dfa7..c17aa32 100644 --- a/xio-openssl.c +++ b/xio-openssl.c @@ -850,7 +850,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 */ @@ -905,54 +905,108 @@ 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(); - } else { - Error1("openssl-method=\"%s\": unknown method", me_str); - method = sycSSLv23_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\": 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 (me_str != NULL) { + if (false) { + ; /* for canonical reasons */ #if HAVE_SSLv2_server_method - method = sycSSLv2_server_method(); -#else - Error1("OpenSSL method \"%s\" not provided by library", me_str); + } else if (!strcasecmp(me_str, "SSL2")) { + method = sycSSLv2_server_method(); +#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 } } @@ -1021,7 +1075,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)); @@ -1095,8 +1149,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); } } }