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 pkcs12comando 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=sslmas é 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