2012-08-03 13 views
10

estoy tratando de configurar una conexión de socket SSL (y estoy haciendo lo siguiente en el cliente)recibido una alerta fatal: bad_certificate

  1. que generan una certificte solicitud de firma para obtener un certificado de cliente firmado

  2. Ahora tengo una clave privada (utilizada durante la CSR), un certificado de cliente firmado y un certificado raíz (obtenido fuera de banda).

  3. Agrego la clave privada y el certificado de cliente firmado a una cadena de certificados y lo agrego al administrador de claves. y el certificado raíz para el administrador de confianza. Pero recibo un error de certificado erróneo.

Estoy bastante seguro de que estoy usando los certes correctos. ¿Debo agregar también el certificado firmado del cliente al administrador de confianza? Intenté eso, sin suerte aún.

//I add the private key and the client cert to KeyStore ks 
FileInputStream certificateStream = new FileInputStream(clientCertFile); 
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); 
java.security.cert.Certificate[] chain = {}; 
chain = certificateFactory.generateCertificates(certificateStream).toArray(chain); 
certificateStream.close(); 
String privateKeyEntryPassword = "123"; 
ks.setEntry("abc", new KeyStore.PrivateKeyEntry(privateKey, chain), 
     new KeyStore.PasswordProtection(privateKeyEntryPassword.toCharArray())); 

//Add the root certificate to keystore jks 
FileInputStream is = new FileInputStream(new File(filename)); 
CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
java.security.cert.X509Certificate cert = (X509Certificate) cf.generateCertificate(is); 
System.out.println("Certificate Information: "); 
System.out.println(cert.getSubjectDN().toString()); 
jks.setCertificateEntry(cert.getSubjectDN().toString(), cert); 

//Initialize the keymanager and trustmanager and add them to the SSL context 
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 
kmf.init(ks, "123".toCharArray()); 
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 
tmf.init(jks); 

¿Hay algún tipo de cadena de certificados que deba crear aquí?
Tuve un p12 con estos componentes también y al usar un código bastante similar, agregando la clave privada al administrador de claves y el certificado raíz de p12 al administrador de confianza pude hacerlo funcionar. Pero ahora necesito hacerlo funcionar sin el p12.

EDITAR: Se solicitó seguimiento de pila. Espero que esto sea suficiente. (NOTA: Me enmascara los nombres de archivo)

Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate 
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174) 
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165) 
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149) 
at client.abc2.openSocketConnection(abc2.java:33) 
at client.abc1.runClient(abc1.java:63) 
at screens.app.abc.validateLogin(abc.java:197) 
... 32 more 

Respuesta

7

También debe agregar el certificado raíz al almacén de claves.

+2

Gracias de nuevo. Agregué el certificado del cliente y la clave privada al primer almacén de claves (k1) y luego k1 al administrador de claves. Luego, el certificado raíz para el almacén de claves (k2) y k2 para el trustmanagerfactory – highflyer

+0

¿Quiere decir "agregar certificado raíz al almacén de confianza", ¿verdad? – FaithReaper

1

siempre que el certificado del servidor está firmado y válido, sólo tiene que abrir la conexión como de costumbre:

import java.net.*; 
import java.io.*; 

public class URLConnectionReader { 
    public static void main(String[] args) throws Exception { 
     URL google = new URL("https://www.google.com/"); 
     URLConnection yc = google.openConnection(); 
     BufferedReader in = new BufferedReader(new InputStreamReader(
            yc.getInputStream())); 
     String inputLine; 
     while ((inputLine = in.readLine()) != null) 
      System.out.println(inputLine); 
     in.close(); 
    } 
} 

Tenga en cuenta que la URL tiene el esquema HTTPS para indicar el uso de SSL.

Si el certificado del servidor está firmado, pero está accediendo utilizando una dirección IP/nombre de dominio diferente a la que en el certificado, se puede omitir la verificación de nombre de host con esto:

HostnameVerifier hv = new HostnameVerifier() { 
    public boolean verify(String urlHostName,SSLSession session) { 
     return true; 
    } 
}; 

HttpsURLConnection.setDefaultHostnameVerifier(hv); 

Si el certificado no está firmado luego debe agregarlo al almacén de claves utilizado por la JVM (useful commands).

+2

Él * se * 'abrir la conexión como de costumbre' y * * no es de trabajo. Él no está usando HTTPS. No necesita un HostnameVerifier para SSL, solo para HTTPS. El que ha publicado es radicalmente inseguro y debe anotarse o no publicarse en absoluto. No es una respuesta. – EJP

1

Recibí este error cuando eliminé estas 2 líneas. Si sabe que su almacén de claves tiene los certificados correctos, asegúrese de que su código esté mirando el almacén de claves correcto.

System.setProperty("javax.net.ssl.keyStore", <keystorePath>)); 
System.setProperty("javax.net.ssl.keyStorePassword",<keystorePassword>)); 

También necesitaba este argumento VM: -Djavax.net.ssl.trustStore=/app/certs/keystore.jk ver aquí para más detalles: https://stackoverflow.com/a/34311797/1308453