1

Short Version of Question

Assuming the existence of the relevant files, why does the following sequence of commands not work?

socat tcp-listen:10001,fork exec:'/bin/cat' &
socat openssl-listen:10002,fork,reuseaddr,cert=server.pem,cafile=client.crt tcp:localhost:10001 &
socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt &
socat stdout tcp:localhost:10003

Long Version of Question

I'm trying to use socat with openssl as described by the following documents:

For context, I'm running socat version 1.7.2.4+sigfix and OpenSSL version 1.1.0f on Debian 9.

Before proceeding to try out openssl, I first use socat by itself as a sanity check. I start one socat instance as an "echo server", use two intermediate socat instances (i.e. a second and third instance) to create a tunnel, and then a fourth instance as a "client" to send data to the original process via the tunnel. Here is an example of the commands that I ran:

socat tcp-listen:10001,fork exec:'/bin/cat' &
socat tcp-listen:10002,fork tcp:localhost:10001 &
socat tcp-listen:10003,fork tcp:localhost:10002 &
socat stdout tcp:localhost:10003

This works as expected - text entered to the terminal is echoed back to the console. A sample session looked something like the following:

user@host:~$ socat tcp-listen:10001,fork exec:'/bin/cat' &
[1] 1001

user@host:~$ socat tcp-listen:10002,fork tcp:localhost:10001 &
[2] 1002

user@host:~$ socat tcp-listen:10003,fork tcp:localhost:10002 &
[3] 1003

user@host:~$ socat stdout tcp:localhost:10003
hey
hey

Having verified my sanity, I proceeded with the certificate and key generation process.

First I generated a server key and self-signed certificate:

openssl genrsa -out server.key 2048
openssl req -new -key server.key -x509 -days 3653 -out server.crt
cat server.key server.crt > server.pem
chmod 600 server.key server.pem

Then I generated a client key and self-signed certificate:

openssl genrsa -out client.key 2048
openssl req -new -key client.key -x509 -days 3653 -out client.crt
cat client.key client.crt > client.pem
chmod 600 client.key client.pem

Finally I tried setting up the same tunnel as before, but using OpenSSL encryption:

socat tcp-listen:10001,fork exec:'/bin/cat' &
socat openssl-listen:10002,fork,reuseaddr,cert=server.pem,cafile=client.crt tcp:localhost:10001 &
socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt &
socat stdout tcp:localhost:10003

This does NOT seem to work and after executing the last command I get the following error:

YYYY/mm/dd HH:MM:SS socat[pid1] E SSL_connect(): error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small
YYYY/mm/dd HH:MM:SS socat[pid2] E SSL_accept(): error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure

Here is what an example session looked like:

user@host:~$ socat tcp-listen:10001,fork exec:'/bin/cat' &
[1] 1001

user@host:~$ socat openssl-listen:10002,fork,reuseaddr,cert=server.pem,cafile=client.crt tcp:localhost:10001 &
[2] 1002

user@host:~$ socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt &
[3] 1003

user@host:~$ socat stdout tcp:localhost:10003
2018/08/22 23:43:30 socat[1005] E SSL_accept(): error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
2018/08/22 23:43:30 socat[1003] E SSL_connect(): error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small
[3]+  Exit 1                  socat tcp-listen:10003 openssl-connect:localhost:10002,cert=client.pem,cafile=server.crt

Follow the advice of user dave_thompson_085 I tried using the openssl s_client command as follows:

openssl s_client -cipher 'DHE:!EXPORT:!LOW' -connect localhost:10002

This produced error output which contained the following:

socat[pid] E SSL_accept(): error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
error:141A318A:SSL routines:tls_process_ske_dhe:dh key too small:../ssl/statem/statem_clnt.c:1460:
  • 1
    (fixed) What versions of socat and openssl(lib) and how built? According to dest-unreach.org/socat/contrib/socat-secadv7.html socat before 1.7.3.1 or 2.0.0-b9 defaulted to a 1024-bit tmpdh that wasn't actually prime -- but OpenSSL client doesn't catch nonprimality and I can't find a version that should reject 1024-bit unless someone has tweaked the build. If you have openssl (commandline) 1.0.2+ try openssl s_client to your server (add -cipher 'DHE:!EXPORT:!LOW' if needed to get it to negotiate DHE) and see what the output says for 'Server Temp Key:' – dave_thompson_085 Aug 23 '18 at 9:00
  • @dave_thompson_085 Thank you for the suggestions. I updated my question as you suggested. I'm running socat version 1.7.2.4+sigfix and OpenSSL version 1.1.0f on Debian 9. I got what appears to be the same error (dh key too small) when using the openssl s_client command. – igal Aug 23 '18 at 14:29
  • 1
    dh key too small: see weakdh.org – Patrick Mevzek Aug 24 '18 at 4:00
  • 1
    Generate a new DH params file, as explained in link above, that is openssl dhparam -out dhparams.pem 2048 and then launch socat with dhparams parameter pointing to the file you just created. – Patrick Mevzek Aug 24 '18 at 5:33
  • 1
    Sorry I hadn't noticed 1.1.0 s_client no longer outputs the info after this error, but I think the version was enough to sort it. – dave_thompson_085 Aug 24 '18 at 7:22
0

First, are you sure socat is using OpenSSL 1.1.0? Upstream (from socat.org) 1.7.2.4 source (released in 2014) is not compatible with OpenSSL 1.1.0 (released in 2016) which made significant API changes. Check ldd $(which socat). Are (both) your socat and OpenSSL from standard repositories, other builders/packagers, or built from source?

Anyway, although "what's new" doesn't say so and assuming whatever the "sig" patch is doesn't change it, 1.7.2.4 (upstream) source defaults to 512-bit DH parameters. That is indeed too small -- it was known breakable even before Logjam, and unacceptable to any libssl client from 1.0.1n or 1.0.2b up (both released 2015-06) (and any 1.1.0, first released 2016-08).

AFAICS your alternatives are:

  • upgrade socat to at least 1.7.3.0 (which in upstream does have 1024-bit); 3.1+ with 2048-bit is even better

  • generate, or obtain from somewhere, DH parameters of at least 1024 bits (2048 is better for most clients, including yours, although some clients may have trouble such as obsolete versions of Java) and add them to your server's cert file.

    You can generate DH parameters with openssl dhparam $n >file where $n is 1024 or 2048. If this is too slow you can add -dsaparam.

  • ditto, but put the parameters in a separate file configured on the server. The manpage says this option is dhparams=<file> but the code says it is dh= and testing confirms the latter.

  • configure the server or client, or both in some combination, so that they don't agree on a ciphersuite that uses DHE; since your server is the one at fault here, personally I would configure only the server. Again the manpage says cipher but reality is ciphers. Since 1.7.2.4 doesn't set 'tmp_ecdh' parameters, and (AFAICT) it can't use 1.1.0, it won't support ECDHE, which means without DHE your connections will not have Perfect Forward Secrecy. If you can accept that limitation, using ,ciphers='DEFAULT:!DHE' on the server is a simple fix.

    (1.7.3.0 up do set 'tmp_ecdh' and support ECDHE, which would avoid the problem here even if they didn't default DH-1024 or better, because ECDHE suites are preferred over DHE, so ECDHE would be selected and then the DHE parameters aren't used and don't matter.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.