perlsslopenssl

OpenSSL DH Key Too Small Error


I am trying to connect to a closed-off server - an air-conditioner - using a simple PERL script

#!/usr/bin/perl

use 5.10.1;
use warnings;
use strict;
use IO::Socket::SSL;
use IO::Socket::SSL qw/debug3/;
my $sock = IO::Socket::SSL->new(
        PeerHost => '192.168.1.4',
        PeerPort => 2878,
        verify_hostname => 0,   
        SSL_verify_mode => SSL_VERIFY_NONE,
        SSL_verifycn_scheme => undef
) or die "failed connect or ssl handshake: $!,$SSL_ERROR";
print "$sock\n";

Now, this was all working well and good, then I updated OpenSSL (libssl1.0.0) to be exact, and all hell broke loose:

DEBUG: .../IO/Socket/SSL.pm:220: set domain to 2
DEBUG: .../IO/Socket/SSL.pm:1653: new ctx 1984680
DEBUG: .../IO/Socket/SSL.pm:363: socket not yet connected
DEBUG: .../IO/Socket/SSL.pm:365: socket connected
DEBUG: .../IO/Socket/SSL.pm:383: ssl handshake not started
DEBUG: .../IO/Socket/SSL.pm:446: Net::SSLeay::connect -> -1
DEBUG: .../IO/Socket/SSL.pm:1328: SSL connect attempt failed with unknown error error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small

DEBUG: .../IO/Socket/SSL.pm:452: fatal SSL error: SSL connect attempt failed with unknown error error:14082174:SSL routines:SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small
DEBUG: .../IO/Socket/SSL.pm:1328: IO::Socket::INET6 configuration failed error:00000000:lib(0):func(0):reason(0)

DEBUG: .../IO/Socket/SSL.pm:1690: free ctx 1984680 open=1984680
DEBUG: .../IO/Socket/SSL.pm:1698: OK free ctx 1984680
failed connect or ssl handshake: ,IO::Socket::INET6 configuration failed error:00000000:lib(0):func(0):reason(0) at ./spare line 9.

I am happy to use any alternative packages to get around this, but I do need to get around it, as I can't update the certificate on the air-conditioner...

I have looked in to using LWP and raw Net:SSLeay, but the problem seems to be in the underlying OpenSSL libs.


Solution

  • ... SSL3_CHECK_CERT_AND_ALGORITHM:dh key too small
    

    I have looked in to using LWP and raw Net:SSLeay, but the problem seems to be in the underlying OpenSSL libs.

    While it is caused by changes to OpenSSL the problem is actually at the server side. The server is using a weak DH key within the key exchange and recent versions of OpenSSL enforce a non-weak DH key because of the Logjam attack.

    If the server supports ciphers which don't use DH key exchange you can work around the problem by restricting the ciphers offered by the client so that they don't include any DH ciphers.

    my $sock = IO::Socket::SSL->new(..., SSL_cipher_list => 'DEFAULT:!DH' ...);
    

    Apart from that simply disabling any validation like you do is bad:

        ...
        verify_hostname => 0,   
        SSL_verify_mode => SSL_VERIFY_NONE,
        SSL_verifycn_scheme => undef
    

    For one, verify_hostname is not a valid parameter at all (this is for LWP only). Also, you don't need to set a SSL_verifycn_scheme if you disable validation with SSL_verify_mode since no validation also means no validation of the certificates subject.

    But much better than disabling validation would be to use SSL_fingerprint to specify which certificate you expect and thus have a proper check even for self-signed or expired certificates. See common usage errors in the IO::Socket::SSL documentation for more information.