Soy bastante nuevo HTTPS/SSL/TLS
y estoy un poco confundido sobre lo que se supone que deben presentar exactamente los clientes al autenticarse con certificados.
Estoy escribiendo un cliente Java que necesita hacer un simple POST
de datos a un particular URL
. Esa parte funciona bien, el único problema es que se supone que debe hacer más HTTPS
. La HTTPS
parte es bastante fácil de manejar (ya sea con HTTPclient
o utilizando el HTTPS
soporte incorporado de Java ), pero estoy atascado en la autenticación con certificados de cliente. He notado que ya hay una pregunta muy similar aquí, que aún no he probado con mi código (lo haré lo suficientemente pronto). Mi problema actual es que, haga lo que haga, el cliente Java nunca envía el certificado (puedo verificarlo con los PCAP
volcados).
¿Me gustaría saber qué se supone que debe presentar exactamente el cliente al servidor cuando se autentica con certificados (específicamente para Java, si eso es importante)? ¿Es esto un JKS
archivo o PKCS#12
? Lo que se supone que debe estar en ellos; solo el certificado del cliente o una clave? Si es así, ¿qué clave? Hay bastante confusión sobre todos los diferentes tipos de archivos, tipos de certificados y demás.
Como he dicho antes, soy nuevo, HTTPS/SSL/TLS
por lo que agradecería también algunos antecedentes (no tiene que ser un ensayo; me conformaré con enlaces a buenos artículos).
fuente
Respuestas:
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
Para generarlo utilicé el
pkcs12
comando de OpenSSL , por ejemplo;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;
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
-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) :
fuente
SSLContext
como en la respuesta de @ Magnus.Otras respuestas muestran cómo configurar globalmente los certificados de cliente. Sin embargo, si desea definir mediante programación la clave del cliente para una conexión en particular, en lugar de definirla globalmente en todas las aplicaciones que se ejecutan en su JVM, puede configurar su propio SSLContext de la siguiente manera:
fuente
sslContext = SSLContexts.custom().loadTrustMaterial(keyFile, PASSWORD).build();
. No pude hacerlo funcionarloadKeyMaterial(...)
.loadKeyMaterial(keystore, keyPassphrase.toCharArray())
código 'también!SSLContext
.El archivo JKS es solo un contenedor para certificados y pares de claves. En un escenario de autenticación del lado del cliente, las diversas partes de las claves se ubicarán aquí:
La separación del almacén de confianza y el almacén de claves no es obligatoria pero se recomienda. Pueden ser el mismo archivo físico.
Para establecer las ubicaciones del sistema de archivos de las dos tiendas, use las siguientes propiedades del sistema:
y en el servidor:
Para exportar el certificado del cliente (clave pública) a un archivo, para poder copiarlo en el servidor, use
Para importar la clave pública del cliente en el almacén de claves del servidor, use (como se menciona en el póster, esto ya lo han hecho los administradores del servidor)
fuente
Maven pom.xml:
Código Java:
fuente
configureRequest()
correcto el método para configurar el proxy del proyecto del cliente?Para aquellos de ustedes que simplemente desean configurar una autenticación bidireccional (certificados de servidor y cliente), una combinación de estos dos enlaces lo llevará hasta allí:
Configuración de autenticación bidireccional:
https://linuxconfig.org/apache-web-server-ssl-authentication
No necesita usar el archivo de configuración openssl que mencionan; Solo usa
$ openssl genrsa -des3 -out ca.key 4096
$ openssl req -new -x509 -days 365 -key ca.key -out ca.crt
para generar su propio certificado de CA y luego generar y firmar las claves del servidor y del cliente a través de:
$ openssl genrsa -des3 -out server.key 4096
$ openssl req -new -key server.key -out server.csr
$ openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 100 -out server.crt
y
$ openssl genrsa -des3 -out client.key 4096
$ openssl req -new -key client.key -out client.csr
$ openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 101 -out client.crt
Para el resto, siga los pasos en el enlace. La administración de los certificados para Chrome funciona igual que en el ejemplo para Firefox que se menciona.
A continuación, configure el servidor a través de:
https://www.digitalocean.com/community/tutorials/how-to-create-a-ssl-certificate-on-apache-for-ubuntu-14-04
Tenga en cuenta que ya ha creado el servidor .crt y .key para que ya no tenga que seguir ese paso.
fuente
server.key
noclient.key
Me he conectado al banco con SSL de dos vías (certificado de cliente y servidor) con Spring Boot. Así que describa aquí todos mis pasos, espero que ayude a alguien (la solución de trabajo más simple que he encontrado):
Generar solicitud de certificado:
Generar clave privada:
Generar solicitud de certificado:
Conservar
user.key
(y contraseña) y enviar una solicitud de certificadouser.csr
al banco para mi certificadoRecibir 2 certificados: mi certificado raíz del cliente
clientId.crt
y el certificado raíz del banco:bank.crt
Cree el almacén de claves Java (ingrese la contraseña de clave y establezca la contraseña del almacén de claves):
No preste atención a la salida:
unable to write 'random state'
. Java PKCS12keystore.p12
creado.Agregar al almacén de claves
bank.crt
(por simplicidad, he usado un almacén de claves):Verifique los certificados del almacén de claves por:
Listo para el código Java :) He usado Spring Boot
RestTemplate
con agregarorg.apache.httpcomponents.httpcore
dependencia:fuente
Dado un archivo p12 con el certificado y la clave privada (generada por openssl, por ejemplo), el siguiente código lo usará para una conexión HttpsURLConnection específica:
La
SSLContext
inicialización demora un poco, por lo que es posible que desee almacenarlo en caché.fuente
Creo que la solución aquí fue el tipo de almacén de claves, pkcs12 (pfx) siempre tiene clave privada y el tipo JKS puede existir sin clave privada. A menos que especifique en su código o seleccione un certificado a través del navegador, el servidor no tiene forma de saber que representa a un cliente en el otro extremo.
fuente