Finalmente consegui resolver todos os problemas, então vou responder minha própria pergunta. Essas são as configurações / arquivos que eu usei para gerenciar para resolver meus problemas específicos;
O keystore do cliente é um arquivo no formato PKCS # 12 que contém
- O certificado público do cliente (nesse caso, assinado por uma CA autoassinada)
- A chave privada do cliente
Para gerá-lo, usei o pkcs12
comando do OpenSSL , por exemplo;
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "Whatever"
Dica: certifique-se de obter o OpenSSL mais recente, não a versão 0.9.8h, porque isso parece sofrer de um bug que não permite gerar corretamente arquivos PKCS # 12.
Esse arquivo PKCS # 12 será usado pelo cliente Java para apresentar o certificado do cliente ao servidor quando o servidor solicitar explicitamente a autenticação do cliente. Consulte o artigo da Wikipedia sobre TLS para obter uma visão geral de como o protocolo para autenticação de certificado de cliente realmente funciona (também explica por que precisamos da chave privada do cliente aqui).
O armazenamento confiável do cliente é um arquivo de formato JKS direto que contém os certificados CA raiz ou intermediários . Esses certificados de autoridade de certificação determinarão com quais pontos de extremidade você poderá se comunicar; nesse caso, permitirá que seu cliente se conecte a qualquer servidor que apresente um certificado que foi assinado por uma das autoridades de certificação do armazenamento confiável.
Para gerá-lo, você pode usar a ferramenta chave do Java padrão, por exemplo;
keytool -genkey -dname "cn=CLIENT" -alias truststorekey -keyalg RSA -keystore ./client-truststore.jks -keypass whatever -storepass whatever
keytool -import -keystore ./client-truststore.jks -file myca.crt -alias myca
Usando esse armazenamento confiável, seu cliente tentará executar um handshake SSL completo com todos os servidores que apresentarem um certificado assinado pela CA identificado por myca.crt
.
Os arquivos acima são estritamente apenas para o cliente. Quando você também deseja configurar um servidor, ele precisa de seus próprios arquivos de armazenamento de chaves e de confiança. Um ótimo passo a passo para configurar um exemplo completo de trabalho para um cliente e servidor Java (usando o Tomcat) pode ser encontrado neste site .
Questões / Comentários / Dicas
- A autenticação de certificado de cliente pode ser aplicada apenas pelo servidor.
- ( Importante! ) Quando o servidor solicita um certificado de cliente (como parte do handshake TLS), ele também fornece uma lista de CAs confiáveis como parte da solicitação de certificado. Quando o certificado de cliente que você deseja apresentar para autenticação não for assinado por uma dessas autoridades de certificação, ele não será apresentado (na minha opinião, esse é um comportamento estranho, mas tenho certeza de que há uma razão para isso). Essa foi a principal causa dos meus problemas, pois a outra parte não havia configurado o servidor corretamente para aceitar meu certificado de cliente autoassinado e presumimos que o problema estava ao meu alcance por não fornecer corretamente o certificado de cliente na solicitação.
- Obtenha o Wireshark. Possui excelente análise de pacotes SSL / HTTPS e será uma tremenda ajuda para depurar e encontrar o problema. É semelhante,
-Djavax.net.debug=ssl
mas é mais estruturado e (sem dúvida) mais fácil de interpretar se você não se sentir confortável com a saída de depuração SSL do Java.
É perfeitamente possível usar a biblioteca httpclient Apache. Se você deseja usar o httpclient, substitua o URL de destino pelo equivalente HTTPS e adicione os seguintes argumentos da JVM (que são iguais para qualquer outro cliente, independentemente da biblioteca que você deseja usar para enviar / receber dados por HTTP / HTTPS) :
-Djavax.net.debug=ssl
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.keyStore=client.p12
-Djavax.net.ssl.keyStorePassword=whatever
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.trustStore=client-truststore.jks
-Djavax.net.ssl.trustStorePassword=whatever