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.
Perché non lasciare che il gestore di fiducia tramite JSSE faccia tutto questo per te? – Bruno
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
No, è sufficiente rendere facoltativo il certificato client utilizzando l'opzione wantClientAuth (invece di necessità). – Bruno