Erro ao usar openssl com socat - SSL3_CHECK_CERT_AND_ALGORITHM: chave dh muito pequena

1

Versão resumida da pergunta

Assumindo a existência dos arquivos relevantes, por que a seguinte sequência de comandos não funciona?

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

Versão longa da pergunta

Estou tentando usar socat com openssl conforme descrito nos seguintes documentos:

Para o contexto, estou executando a versão socat 1.7.2.4 + sigfix e OpenSSL versão 1.1.0f no Debian 9.

Antes de prosseguir para experimentar openssl , primeiro uso socat como uma verificação de sanidade. Eu inicio um socat instance como um "echo server", uso dois intermediários socat instances (ie uma segunda e terceira instância) para criar um túnel, e depois uma quarta instância como um "client" para enviar dados ao original processo através do túnel. Aqui está um exemplo dos comandos que eu executei:

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

Isso funciona como esperado - o texto digitado no terminal é retornado para o console. Uma sessão de amostra foi parecida com a seguinte:

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

Após verificar minha sanidade mental, continuei com o processo de geração de certificados e chaves.

Primeiro, gerei uma chave de servidor e um certificado autoassinado:

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

Em seguida, gerei uma chave de cliente e um certificado autoassinado:

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

Por fim, tentei configurar o mesmo túnel de antes, mas usando a criptografia OpenSSL:

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

Isto parece não funcionar e depois de executar o último comando, recebo o seguinte erro:

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

Aqui está uma sessão de exemplo:

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

Siga o conselho do usuário dave_thompson_085 Tentei usar o comando openssl s_client da seguinte forma:

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

Isso produziu uma saída de erro que continha o seguinte:

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:
    
por igal 23.08.2018 / 02:06

1 resposta

0

Primeiro, você tem certeza de que socat está usando o OpenSSL 1.1.0? Upstream (de socat.org) 1.7.2.4 source (lançado em 2014) não é compatível com o OpenSSL 1.1.0 (lançado em 2016) que fez mudanças significativas na API. Verifique ldd $(which socat) . São (ambos) seu socat e OpenSSL de repositórios padrão, outros construtores / empacotadores ou construídos a partir do código-fonte?

De qualquer forma, embora "o que há de novo" não diga e assumindo seja qual for o patch "sig" não o altera, a fonte 1.7.2.4 (upstream) é padronizada para os parâmetros DH de 512 bits. Isso é realmente muito pequeno - era conhecido como breakable mesmo antes de Logjam, e inaceitável para qualquer cliente libssl de 1.0.1n ou 1.0.2b (ambos lançados em 2015-06) (e qualquer 1.1.0 , lançado pela primeira vez em 2016-08).

AFAICS suas alternativas são:

  • atualize o socat para pelo menos 1.7.3.0 (que no upstream tem 1024 bits); 3.1+ com 2048 bits é ainda melhor

  • gera ou obtém de algum lugar parâmetros DH de pelo menos 1024 bits (2048 é melhor para a maioria dos clientes, incluindo o seu, embora alguns clientes possam ter problemas como versões obsoletas do Java) e adicionar -los para o arquivo cert do seu servidor.

    Você pode gerar parâmetros DH com openssl dhparam $n >file , em que $n é 1024 ou 2048. Se isso for muito lento você pode adicionar -dsaparam .

  • idem, mas coloque os parâmetros em um arquivo separado configurado no servidor. A página de manual diz que esta opção é dhparams=<file> , mas o código diz que é dh= e o teste confirma o último.

  • configure o servidor ou o cliente, ou ambos em alguma combinação, para que eles não concordem em um ciphersuite que use o DHE; desde que o seu servidor é o único culpado aqui, pessoalmente eu iria configurar apenas o servidor. Novamente, a manpage diz cipher , mas a realidade é ciphers . Como o 1.7.2.4 não define os parâmetros 'tmp_ecdh' e (AFAICT) ele não pode usar o 1.1.0, ele não suportará o ECDHE, o que significa que sem o DHE suas conexões não terão o Perfect Forward Secrecy. Se você puder aceitar essa limitação, usar ,ciphers='DEFAULT:!DHE' no servidor é uma correção simples.

    (1.7.3.0 configuram 'tmp_ecdh' e suportam ECDHE, o que evitaria o problema aqui mesmo se eles não tivessem o DH-1024 padrão ou melhor, porque os pacotes ECDHE são preferidos em relação ao DHE, então o ECDHE seria selecionado e então os parâmetros DHE não são usados e não importam.)

por 24.08.2018 / 09:21