Pregunta

Los archivos de claves que he utilizado en mi aplicación web expiró la semana pasada. Generé hace mucho tiempo. Así que empecé a generar nuevo certificado utilizando herramienta de claves. He utilizado este certificado para conectar un servidor de transacciones y el servidor web. Quería utilizar certificado autofirmado para esta aplicación. Genero que usando los siguientes comandos para generar clave firmada por uno mismo servidor de transacciones.

keytool -genkey -keystore keys/SvrKeyStore -keyalg rsa -validity 365 -alias Svr -storepass 123456 -keypass abcdefg -dname "CN=One1, OU=Development1, O=One, L=Bamba, S=Western Prov1, C=S1"

siguiente commnad para generar almacén de claves para aplicaciones web

keytool -genkey -keystore keys/ClientKeyStore -keyalg rsa -validity 365 -alias Web -storepass 123456 -keypass abcdefg -dname "CN=One, OU=Development, O=One, L=Bamba, S=Western Prov, C=SL"

utilicé siguiente código en el servidor de transacciones para crear la conexión de socket

          String KEYSTORE = Config.KEYSTORE_FILE;//SvrKeyStore  keystore file
          char[] KEYSTOREPW = "123456".toCharArray();
          char[] KEYPW = "abcdefg".toCharArray();
          com.sun.net.ssl.TrustManagerFactory tmf;

          boolean requireClientAuthentication;

          java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl.
                                             Provider());
          java.security.KeyStore keystore = java.security.KeyStore.getInstance(
              "JKS");
          keystore.load(new FileInputStream(KEYSTORE), KEYSTOREPW);

          com.sun.net.ssl.KeyManagerFactory kmf = com.sun.net.ssl.
              KeyManagerFactory.getInstance("SunX509");
          kmf.init(keystore, KEYPW);

          com.sun.net.ssl.SSLContext sslc = com.sun.net.ssl.SSLContext.
              getInstance("SSLv3");
          tmf = com.sun.net.ssl.TrustManagerFactory.getInstance("sunx509");
          tmf.init(keystore);

          sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
          SSLServerSocketFactory ssf = sslc.getServerSocketFactory();
          SSLServerSocket ssocket = (SSLServerSocket) ssf.createServerSocket(port);
          ssocket.setNeedClientAuth(true);

Pero da siguiente excepción cuando lo usé en mi aplicación e intente conectarse al servidor de transacciones a través del servidor web

javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHands
hakeException: java.security.cert.CertificateException: Untrusted Server Certifi
cate Chain
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.jav
a:1172)
        at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:
65)
        at net.schubart.fixme.internal.MessageInput.readExactly(MessageInput.jav
a:166)
        at net.schubart.fixme.internal.MessageInput.readMessage(MessageInput.jav
a:78)
        at cc.aot.itsWeb.ClientWriterThread.run(ClientWriterThread.java:241)
        at java.lang.Thread.run(Thread.java:619)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateEx
ception: Untrusted Server Certificate Chain
        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1
520)
        at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:182)
        at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:176)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien
tHandshaker.java:975)
        at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHa
ndshaker.java:123)
        at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:5
11)
        at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.jav
a:449)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.j
ava:817)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SS
LSocketImpl.java:1029)
        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.
java:621)
        at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.ja
va:59)
        at java.io.OutputStream.write(OutputStream.java:58)

Por favor, puede alguien decirme dónde está el problema

¿Fue útil?

Solución

En primer lugar, evitar el uso de los paquetes com.sun.net.ssl y clases directamente. La arquitectura de la JSSE está construido de manera que se pueden utilizar las fábricas y especificar los proveedores más tarde. Utilice javax.net.ssl.TrustManagerFactory (lo mismo para KeyManagerFactory y SSLContext) en su lugar. (Me gustaría sugerir el uso de "PKIX" en lugar de "SunX509" para el algoritmo de gestor de confianza, ya que es normalmente el valor por defecto con el proveedor de Sol, o mejor, el uso TrustManagerFactory.getDefaultAlgorithm()).

En segundo lugar, no es necesario establecer un keymanager en el lado del cliente, a menos que esté utilizando la autenticación de certificado de cliente.

Por último (y tal vez el más importante), es necesario exportar el certificado autofirmado que haya generado en el lado del servidor (sólo el certificado, no la clave privada) y la importación en el almacén de claves se utiliza como un fideicomiso tienda en el lado del cliente.

Cuando se genera el certificado, debe asegurarse de que utiliza CN=the.server.host.name.

keytool -genkey -keystore server-keystore.jks -alias server_alias \
        -dname "CN=the.server.host.name,OU=whateveryoulike" \
        -keyalg "RSA" -sigalg "SHA1withRSA" -keysize 2048 -validity 365

keytool -export -keystore server-keystore.jks -alias server_alias -file server.crt

keytool -import -keystore client-truststore.jks -file server.crt

Si desea utilizar la autenticación de certificado de cliente, es necesario repetir la operación mediante la sustitución de servidor-cliente-almacén de claves y almacén de confianza con el cliente-servidor de almacén de claves y almacén de confianza-respectivamente.

En este caso, server-keystore.jks y server-truststore.jks podría ser el mismo archivo, pero no es necesario que (lo mismo en el lado del cliente).

Otros consejos

Todo lo que tenía que hacer era herramienta de claves -selfcert - alias XXX -validity DDD donde XXX es el mismo alias que antes y DDD es el número de días antes del vencimiento, para el certificado del servidor, a continuación, exportar que cert y la importación en la década de los clientes almacén de confianza. Repetir a la inversa para el cliente. Has dejado de lado la parte de exportación / importación.

Sin embargo gran parte de ese código es ahora obsoleto. No es necesario llamar addProvider (), y se puede cambiar a com.sun.net.ssl ??javax.net.ssl ??lo largo del resto.

Para entender esto hay que entender cómo los certificados de trabajo.

Dado que cualquiera puede crear un certificado (como lo hizo), no es suficiente sólo para crearlo - certificados tienen que ser de confianza. Un certificado es de confianza sólo si está firmado por otro certificado, que es de confianza. En la parte superior de la "cadena alimentaria" confianza hay varias entidades emisoras principales, a las que puede pagar dinero para tener su certificado de "confianza pública" (el sistema viene con sus certificados instalados en él).

Por supuesto que no tiene que pagar a una CA con el fin de su aplicación, pero hay que imitar este comportamiento. Lo que probablemente tendrá que hacer es exportar la clave pública del servidor / cliente, e instalarlo en una especie de tienda de confianza.

Comprobar cómo su API que permite definir dónde están sus certificados de confianza son.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top