Finalmente logré resolver todos los problemas, así que responderé mi propia pregunta. Estas son las configuraciones / archivos que he usado para administrar para resolver mis problemas particulares;
El almacén de claves del cliente es un archivo de formato PKCS # 12 que contiene
- El certificado público del cliente (en este caso firmado por una CA autofirmada)
- La clave privada del cliente.
Para generarlo utilicé el pkcs12
comando de OpenSSL , por ejemplo;
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "Whatever"
Consejo: asegúrese de obtener la última versión de OpenSSL, no la versión 0.9.8h, porque parece sufrir un error que no le permite generar correctamente los archivos PKCS # 12.
El cliente Java utilizará este archivo PKCS # 12 para presentar el certificado del cliente al servidor cuando el servidor haya solicitado explícitamente que el cliente se autentique. Consulte el artículo de Wikipedia sobre TLS para obtener una descripción general de cómo funciona realmente el protocolo para la autenticación del certificado del cliente (también explica por qué necesitamos la clave privada del cliente aquí).
El almacén de confianza del cliente es un archivo de formato JKS que contiene los certificados de CA raíz o intermedios . Estos certificados de CA determinarán con qué puntos finales podrá comunicarse, en este caso permitirá que su cliente se conecte a cualquier servidor que presente un certificado firmado por una de las CA del almacén de confianza.
Para generarlo, puede utilizar la herramienta de claves estándar de Java, por ejemplo;
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
Con este almacén de confianza, su cliente intentará hacer un protocolo de enlace SSL completo con todos los servidores que presenten un certificado firmado por la CA identificada por myca.crt
.
Los archivos anteriores son estrictamente para el cliente solamente. Cuando desee configurar también un servidor, el servidor necesita sus propios archivos de almacén de claves y de confianza. En este sitio web se puede encontrar un gran tutorial para configurar un ejemplo completamente funcional para un cliente y servidor Java (usando Tomcat) .
Problemas / Observaciones / Consejos
- La autenticación del certificado del cliente solo puede ser forzada por el servidor.
- ( ¡Importante! ) Cuando el servidor solicita un certificado de cliente (como parte del protocolo de enlace TLS), también proporcionará una lista de CA de confianza como parte de la solicitud de certificado. Cuando el certificado de cliente que desea presentar para la autenticación no está firmado por una de estas CA, no se presentará en absoluto (en mi opinión, este es un comportamiento extraño, pero estoy seguro de que hay una razón para ello). Esta fue la causa principal de mis problemas, ya que la otra parte no había configurado su servidor correctamente para aceptar mi certificado de cliente autofirmado y asumimos que el problema estaba en mi extremo por no proporcionar adecuadamente el certificado de cliente en la solicitud.
- Consigue Wireshark. Tiene un excelente análisis de paquetes SSL / HTTPS y será de gran ayuda para depurar y encontrar el problema. Es similar
-Djavax.net.debug=ssl
pero está más estructurado y (posiblemente) más fácil de interpretar si no se siente cómodo con la salida de depuración SSL de Java.
Es perfectamente posible usar la biblioteca httpclient de Apache. Si desea usar httpclient, simplemente reemplace la URL de destino con el equivalente HTTPS y agregue los siguientes argumentos JVM (que son los mismos para cualquier otro cliente, independientemente de la biblioteca que desee usar para enviar / recibir datos a través de 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