2012-09-17 19 views
5

Sto lavorando su un'autenticazione client-cert tra un server di jetty e un client incorporati. Entrambi usano il keystore. Il certificato client è firmato dal certificato del server che è firmato da una CA. Il molo usa il metodo 2 per autenticare un certificato client, javax.net.ssl.SSLEngine, che sembra funzionare e usano anche il codice sopra.Java/Keystore Verifica Certificato firmato

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){ 
... 
} 

Naturalmente devo usare questo secondo modo ... Quindi concentriamoci su questo codice, questo è un buon modo per verificare un certificato firmato? Ecco una discarica dei miei archivi di chiavi:

Keystore 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 
... 

Server truststore:

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 

io non sono sicuro di questi archivi di chiavi, ma ho provato con uno diverso (aggiungendo il Certificato CA alla catena di certificati del client, aggiunta del certificato al truststore) e la convalida non riesce ancora. E con questi keystore il primo modo di convalidare (SSLEngine) sembra funzionare.

L'output di debug è troppo grande per metterlo qui, ma qui è 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 

Se rendo invalida la revoca o se ho impostato l'ultimo certificato (al posto del primo) come X509CertSelector il codice di lavoro ma non sono sicuro di quello che sto facendo.

Sto iniziando a dubitare del codice jetty ma non sono un esperto in certificati e handshaking SSL, quindi potrebbe anche provenire da bad keystore/truststore. Questo è il motivo per cui non ho creato un problema sul board di jetty e ho chiesto qui prima di essere sicuro che il codice debba essere modificato.

Inoltre, potrebbe essere utile sapere come convalidare un certificato firmato in Java.

+0

Perché non lasciare che il gestore di fiducia tramite JSSE faccia tutto questo per te? – Bruno

+0

Poiché il mio server accetta anche la connessione non cert-auth. Devo lasciare che accetti prima tutte le connessioni e poi in alcuni casi convalidare il certificato del cliente, se presente. – Ghetolay

+4

No, è sufficiente rendere facoltativo il certificato client utilizzando l'opzione wantClientAuth (invece di necessità). – Bruno

risposta

0

Abilita le CRL certificato o OCSP è accessibile, è possibile trovare tali informazioni in certificato, ad esempio

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

Non utilizzo alcun CRL, OSCP o CRLDP. Non esiste una riga del genere sul mio certificato. Anche il codice mostrato non è completo ci sono alcuni "se" per CRL/OSCP/CRLDP ma questi "se" non vengono mai raggiunti perché non ho impostato queste opzioni. Dovrei ? è assolutamente necessario? – Ghetolay

0

In realtà non c'è bisogno di fare la convalida me stesso.

Lo SSLEngine sta già facendo e se un certificato valido viene inviato dal client si può ottenere usando getPeerCertificateChain(), se non certificato o un certificato non valido viene inviato dal cliente getPeerCertificateChain() ritorno nullo getta una eccezione.

Utilizzando pontile (o qualsiasi ServletContainer Java immagino) è sufficiente per controllare l'attributo del HttpServletRequest [ "javax.servlet.request.X509Certificate"] per sapere se un certificato valido è stato inviato dal client.

Ancora non so come convalidare un certificato in Java, ma questa soluzione è sufficiente per me :) Non ho più bisogno di farlo da solo. Grazie a Bruno!

+0

getPeerCertificateChain() non restituisce null, genera un'eccezione. – EJP

Problemi correlati