Проверьте сертификат X.509 против CA в Java
Допустим, у меня есть что-то вроде этого (код на стороне клиента):
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);
Этот код полностью функционален, но я действительно не могу понять, как проверить сертификат сервера по одному конкретному сертификату CA, который у меня есть в файле pem.
Все сертификаты подписаны моим самозаверяющим ЦС, и это ЦС, который мне нужно проверить (только против этого).
Каждый ответ приветствуется.
РЕДАКТИРОВАТЬ:
В ответ на jglouie (большое спасибо таким образом - не могу проголосовать за ваш ответ).
Я основал решение:
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);
}
}
}
}
};
3 ответа
Я предполагаю, что самоподписанный сертификат вашего CA уже загружен следующим образом:
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream finStream = new FileInputStream("CACertificate.pem");
X509Certificate caCertificate = (X509Certificate)cf.generateCertificate(finStream);
Затем в методе проверки сертификата:
@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);
}
}
Отказ от ответственности: даже не пытался скомпилировать код
Принятый ответ крайне неверен. Он не криптографически проверяет соединение между сертификатом сервера и доверенным центром сертификации. В общем, вам почти никогда не нужно реализовывать свой собственный TrustManager, это крайне опасно.
Как заявил EJP, нет необходимости реализовывать собственный TrustManager, вы можете просто использовать его по умолчанию и убедиться, что доверенный сертификат CA был добавлен в ваш TrustStore по умолчанию. Смотрите этот вопрос для получения дополнительной информации.
Взгляните на класс CertPathValidator из JDK, который проверяет непрерывную цепочку доверия от собственного сертификата сервера до доверенного ЦС. См . Документацию Oracle для ознакомления с проверкой цепочки сертификатов.
Этот код полностью функционален
Этот код полностью не работает . Это абсолютно небезопасно, а также не соответствует его собственной спецификации. Редко возникает необходимость предоставить собственный TrustManager, по умолчанию он работает очень хорошо.
Все, что вам нужно сделать, это убедиться, что ваш сертификат CA присутствует в вашем хранилище доверенных сертификатов, а затем установить системное свойство javax.net.ssl.trustStore
указать на него, если это не файл хранилища доверенных сертификатов Java по умолчанию. Вам не нужно писать какой-либо код, кроме возможного System.setProperty()
, если вы не установите его через опцию командной строки -D.
РЕДАКТИРОВАТЬ Ваше "решение", конечно, не будет работать в целом. Предполагается, что каждый сертификат в цепочке подписан вашим сертификатом. Это может быть верно только для цепочек длиной 1 или длиной 2, если сертификат подписи = ваш сертификат.