2012-09-17 20 views
5

Estoy trabajando en una autenticación de cliente-cert entre un servidor de embarcadero incrustado y un cliente. Ambos usan keystore. El certificado del cliente está firmado por el certificado del servidor que está firmado por una CA. Jetty usa el método 2 para autenticar un certificado de cliente, javax.net.ssl.SSLEngine que parece funcionar y también usan el código anterior.Java/Keystore Verificar Certificado firmado

List<X509Certificate> certList = Certificate chain sent by the client 
KeyStore truststore = server's truststore 

//No use of CRL/OSCP/CRLDP 
_crls = null; 
_enableOCSP = false; 
_enableCRLDP = false; 

try{ 
X509CertSelector certSelect = new X509CertSelector(); 
certSelect.setCertificate((X509Certificate) certList.get(0)); 

// Configure certification path builder parameters 
PKIXBuilderParameters pbParams = new PKIXBuilderParameters(truststore, certSelect); 
pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList))); 

// Set maximum certification path length 
pbParams.setMaxPathLength(-1); 

// Enable revocation checking 
pbParams.setRevocationEnabled(true); 

// Set static Certificate Revocation List 
if (_crls != null && !_crls.isEmpty()) 
    pbParams.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(_crls))); 

    // Enable On-Line Certificate Status Protocol (OCSP) support 
    if (_enableOCSP) 
     Security.setProperty("ocsp.enable","true"); 

    // Enable Certificate Revocation List Distribution Points (CRLDP) support 
    if (_enableCRLDP) 
     System.setProperty("com.sun.security.enableCRLDP","true"); 

// Build certification path 
CertPathBuilderResult buildResult = CertPathBuilder.getInstance("PKIX").build(pbParams);    

// Validate certification path 
CertPathValidator.getInstance("PKIX").validate(buildResult.getCertPath(),pbParams); 
}catch(GeneralSecurityException gse){ 
... 
} 

Por supuesto debo utilizar este segundo camino ... Así que vamos a concentrarnos en este código, se trata de una buena manera de verificar un certificado firmado? Aquí es un vertedero de mis almacenes de claves:

almacén de claves de cliente:

Entry type: PrivateKeyEntry 
Certificate chain length: 2 
Certificate[1]: 
Owner: [email protected], CN=Servlet, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
... 

Certificate[2]: 
Owner: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 
... 

almacén de confianza del servidor:

Entry type: trustedCertEntry 

Owner: [email protected], CN=Greenpacs, OU=dev, O=Imbasoft, L=Bondy, ST=Ile-de-France, C=FR 
Issuer: [email protected], CN=Greenpacs Certificate Authority, OU=dev, O=Imbasoft, ST=Ile-de-France, C=FR 

No estoy seguro acerca de estos almacenes de claves, pero he intentado con uno diferente (añadiendo el Certificado de CA a la cadena de certificados del cliente, agregando certificado al almacén de confianza) y la validación sigue fallando. Y con estos almacenes de claves, la primera forma de validación (SSLEngine) parece funcionar.

El resultado de la depuración es demasiado grande como para poner aquí, pero aquí es la StackTrace:

java.security.cert.CertPathValidatorException: Could not determine revocation status 
    at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:153) 
    at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:325) 
    at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:187) 
    at java.security.cert.CertPathValidator.validate(CertPathValidator.java:267) 
    at MainClass.main(MainClass.java:75) 
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:197) 
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:255) 
    at sun.security.provider.certpath.CrlRevocationChecker.buildToNewKey(CrlRevocationChecker.java:583) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyWithSeparateSigningKey(CrlRevocationChecker.java:459) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyRevocationStatus(CrlRevocationChecker.java:339) 
    at sun.security.provider.certpath.CrlRevocationChecker.verifyRevocationStatus(CrlRevocationChecker.java:248) 
    at sun.security.provider.certpath.CrlRevocationChecker.check(CrlRevocationChecker.java:189) 
    at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:131) 
    ... 4 more 

Si desactivo la revocación o si fijo el último certificado (en lugar de la primera) como X509CertSelector que el código funcione pero no estoy seguro de lo que estoy haciendo.

Estoy empezando a dudar del código del muelle, pero no soy un experto en el protocolo y el protocolo de enlace SSL, por lo que también podría provenir del almacén de claves incorrecto/almacén de confianza. Es por eso que no creé un problema en el tablero de embarcadero y pregunté aquí antes, para asegurarme de que el código necesita ser cambiado.

También podría ser útil saber cómo validar un certificado firmado en Java.

+0

¿Por qué no dejas que el administrador de confianza a través de JSSE haga todo esto por ti? – Bruno

+0

Porque mi servidor también acepta conexiones no cert-auth. Debo dejar que acepte todas las conexiones primero y luego, en algún caso, validar el certificado del cliente, si corresponde. – Ghetolay

+4

No, solo necesita hacer que el certificado del cliente sea opcional utilizando la opción wantClientAuth (en lugar de necesitarla). – Bruno

Respuesta

0

por confirmar su certificado o CRL OCSP es accesible, se puede encontrar esta información en el certificado, como

[1]CRL Distribution Point 
    Distribution Point Name: 
      Full Name: 
       URL=http://crl.verisign.com/pca2-g2.crl 
+0

No uso CRL, OSCP o CRLDP. No hay tal línea en mi certificado. Además, el código que se muestra no está completo. Hay algunos "si" para CRL/OSCP/CRLDP, pero estos "si" nunca se alcanzan porque no establecí estas opciones. Debería ? es absolutamente necesario? – Ghetolay

0

En realidad no tiene que hacer la validación mí mismo.

El SSLEngine ya lo está haciendo y si un certificado válido es enviado por el cliente lo puede conseguir usando getPeerCertificateChain(), si no hay ningún certificado o un certificado no válido se envía por el cliente getPeerCertificateChain() devuelto nulo lanza una excepción.

Utilizando jetty (o cualquier Java ServletContainer, supongo) solo necesita comprobar el atributo HttpServletRequest ["javax.servlet.request.X509Certificate"] para saber si el cliente envió un certificado válido.

Todavía no sé cómo validar un certificado en Java, pero esta solución es suficiente para mí :) Ya no tengo que hacerlo. ¡Gracias a Bruno!

+0

getPeerCertificateChain() no devuelve nulo, arroja una excepción. – EJP

Cuestiones relacionadas