/ / Sprawdź poprawność certyfikatu X.509 wobec CA w Javie - java, ssl, x509certificate, x509, x509trustmanager

Sprawdź certyfikat X.509 przed urzędem certyfikacji w języku Java - java, ssl, x509certificate, x509, x509trustmanager

Powiedzmy, że mam coś takiego (kod po stronie klienta):

TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {

@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};

SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(null, trustAllCerts, null);

SocketFactory sf = sslc.getSocketFactory();
SSLSocket s = (SSLSocket) sf.createSocket("127.0.0.1", 9124);

Ten kod jest w pełni funkcjonalny, ale naprawdę nie mogę dowiedzieć się, jak sprawdzić certyfikat serwera na podstawie konkretnego certyfikatu CA, który jest dostępny w pliku pem.

Wszystkie certyfikaty są podpisane przez mój samopodpisany CA i jest to CA, z którym muszę walidować (tylko przeciwko temu).

Każda odpowiedź jest doceniana.

EDYTOWAĆ:

W odpowiedzi na jglouie (dziękuję bardzo w ten sposób - nie mogę głosować na swoją odpowiedź).

Założyłem rozwiązanie:

new X509TrustManager() {

@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}

@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}

@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
throws CertificateException {
InputStream inStream = null;
try {
// Loading the CA cert
URL u = getClass().getResource("tcp/cacert.pem");
inStream = new FileInputStream(u.getFile());
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate ca = (X509Certificate) cf.generateCertificate(inStream);
inStream.close();

for (X509Certificate cert : certs) {
// Verifing by public key
cert.verify(ca.getPublicKey());
}
} catch (Exception ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
inStream.close();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}

}
}
};

Odpowiedzi:

19 dla odpowiedzi nr 1

Zakładam, że samopodpisany certyfikat twojego CA jest już załadowany w następujący sposób:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream finStream = new FileInputStream("CACertificate.pem");
X509Certificate caCertificate = (X509Certificate)cf.generateCertificate(finStream);

Następnie w metodzie sprawdzania certyfikatu:

@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)  throws CertificateException {

if (certs == null || certs.length == 0) {
throw new IllegalArgumentException("null or zero-length certificate chain");
}

if (authType == null || authType.length() == 0) {
throw new IllegalArgumentException("null or zero-length authentication type");
}

//Check if certificate send is your CA"s
if(!certs[0].equals(caCertificate)){
try
{   //Not your CA"s. Check if it has been signed by your CA
certs[0].verify(caCertificate.getPublicKey())
}
catch(Exception e){
throw new CertificateException("Certificate not trusted",e);
}
}
//If we end here certificate is trusted. Check if it has expired.
try{
certs[0].checkValidity();
}
catch(Exception e){
throw new CertificateException("Certificate not trusted. It has expired",e);
}
}

Zrzeczenie się: Nawet nie próbowałem skompilować kodu


3 dla odpowiedzi № 2

Przyjęta odpowiedź jest bardzo niepoprawna. Nie kryptograficznie weryfikuje żadnego połączenia między certyfikatem serwera a zaufanym urzędem certyfikacji. Ogólnie rzecz biorąc, prawie nigdy nie trzeba implementować własnego TrustManagera, co jest niezwykle niebezpieczne.

Jak stwierdził EJP, nie ma potrzeby implementowania własnego TrustManagera, można po prostu użyć domyślnego i upewnić się, że zaufany certyfikat CA został dodany do domyślnego TrustStore. to pytanie po więcej informacji.

Spójrz na CertPathValidator klasa z JDK, która weryfikuje ciągły łańcuch zaufania z własnego certyfikatu serwera przez zaufany CA. Patrz Dokumenty Oracle wprowadzenie do walidacji łańcucha certyfikatów.


-5 dla odpowiedzi nr 3

Ten kod jest całkowicie funkcjonalny

Ten kod jest całkowicie dysfunkcyjny. Jest całkowicie niepewny, a nawet nie jest zgodny z własną specyfikacją. Rzadko istnieje potrzeba dostarczenia własnego TrustManagera, domyślnie działa bardzo dobrze.

Wszystko, co musisz zrobić, to upewnić się, że certyfikat CA, który masz, jest obecny w magazynie zaufanych certyfikatów, a następnie ustaw właściwość systemu javax.net.ssl.trustStore wskazać na to, jeśli nie jest to domyślny plik zaufanych certyfikatów Java. Nie musisz w ogóle pisać kodu poza tym System.setProperty(), jeśli nie ustawisz go za pomocą linii poleceń -D.

EDYTOWAĆ Twoje „rozwiązanie” z pewnością nie zadziała w ogóle. Zakłada, że ​​każdy certyfikat w łańcuchu jest podpisany przez certyfikat. Może to być prawdziwe tylko dla łańcuchów o długości 1 lub długości 2, jeśli certyfikat podpisujący = twój certyfikat.