Внедрить диспетчер хранилища доверенных сертификатов на сервере для проверки одноранговых сертификатов X509
У меня есть двухсторонняя реализация SSL между несколькими клиентами и серверами, работающими на Spring-Boot. В хранилище доверенных сертификатов сервера я добавляю доменные сертификаты для клиента, поскольку у нас есть клиенты с аналогичными промежуточными и корневыми сертификатами, и мы хотим только аутентифицировать клиентов, чьи доменные сертификаты присутствуют в нашем хранилище доверенных сертификатов, или возвращать исключение (я знаю, что реализация SSL для проверки подлинности, и об этом следует позаботиться в части авторизации, но это является обязательным требованием:(). Я хочу настроить реализацию хранилища доверенных сертификатов, чтобы проверять наличие сертификата домена, а не всей цепочки, если клиент отправляет только сертификат домена, в то же время проверяя Все другие проверки выполняются как есть с помощью реализации хранилища доверенных сертификатов по умолчанию. Для этого я реализовал свой собственный TrustManager и перенес часть другой проверки в реализацию по умолчанию TrustStoreManager.
char [] password = new String("abcde").toCharArray();
String keyFilename = "some-path/server-truststore.jks";
static Map<String,String> map = new HashMap<>();
KeyStore trustStore= null;
try {
trustStore = KeyStore.getInstance("JKS");
} catch (KeyStoreException e) {
e.printStackTrace();
}
try {
trustStore.load(new FileInputStream(keyFilename), password);
} catch (IOException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
}
try {
Enumeration<String> trustStoreEnum= trustStore.aliases();
while(trustStoreEnum.hasMoreElements()){
String nextElement= trustStoreEnum.nextElement();
X509Certificate certificate = (X509Certificate)trustStore.getCertificate(nextElement);
String key=certificate.getSubjectDN().getName().trim();
map.put(key,certificate.getSerialNumber().toString());
}
} catch (KeyStoreException e) {
e.printStackTrace();
}
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
try {
tmf.init(trustStore);
} catch (KeyStoreException e) {
e.printStackTrace();
}
X509TrustManager x509Tm = null;
for(TrustManager tm :tmf.getTrustManagers()){
logger.info(tm.toString());
x509Tm = (X509TrustManager) tm;
break;
}
//Truststrore Manager implementation
final X509TrustManager finalTm = x509Tm;
TrustManager[] x509ExtendedTrustManager = new TrustManager[] {
new X509TrustManager() {
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return finalTm.getAcceptedIssuers();
}
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) throws CertificateException {
logger.info("client blah");
finalTm.checkClientTrusted(certs,authType);
for(X509Certificate x509Certificate: certs){
String certName=x509Certificate.getSubjectDN().getName().trim();
if(!(map.containsKey(certName) && map.get(certName).equals(x509Certificate.getSerialNumber().toString())))
throw new CertificateException("Certificate not present in truststore");
}
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) throws CertificateException {
logger.info("server blah");
finalTm.checkServerTrusted(certs, authType);
}
}
};
Проблема в том, что эта реализация никогда не вызывается, хотя я установил ее в своем SSLContext на сервере, и вместо этого используется реализация менеджера склада доверенных сертификатов по умолчанию.
try {
SSLContext sc = SSLContext.getInstance("TLS");
char [] password2 =
new String("changeit").toCharArray();
String keyFilename2 = "/<some-path>/server-keystore.jks";
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(keyFilename2), password2);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
kmf.init(ks, "changeit".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
sc.init(kms, x509ExtendedTrustManager, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
SSLContext.setDefault(sc);
} catch (GeneralSecurityException e) {
logger.error(e.getMessage());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
logger.info("SSL context set");
}
Я не уверен, что это потому, что мы не можем установить SSLContext на порт, который уже был инициализирован. Я хотел бы знать, есть ли лучший способ сделать это или мы можем инициализировать SSLContext на том же порту?
Заранее спасибо!