Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
This commit is contained in:
Sergey Ponomarev 2024-08-15 22:16:20 +03:00
parent c2e504e6fa
commit 7f61c5024e
3 changed files with 32 additions and 55 deletions

View File

@ -19,13 +19,13 @@ import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
/**
* This class contain some of the methods and variables that are common for Spark's TrustManagers
* @author Pawel Scibiorski
*
*/
public abstract class GeneralTrustManager implements X509TrustManager {
protected final LocalPreferences localPref = SettingsManager.getLocalPreferences();
protected final CertificateController certControll = new CertificateController(localPref);
protected KeyStore allStore;
protected abstract void loadKeyStores();
/**
* Adds content of the keystore to allStore which should contain all certificates from accepted issuers.
* @param keyStore
@ -37,20 +37,21 @@ public abstract class GeneralTrustManager implements X509TrustManager {
throws KeyStoreException, HeadlessException, InvalidNameException {
Enumeration<String> aliases = keyStore.aliases();
// Retrieve all of the certificates out of the KeyStore using aliases
// Retrieve all the certificates out of the KeyStore using aliases
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
X509Certificate certificate = (X509Certificate) keyStore.getCertificate(alias);
allStore.setCertificateEntry(certControll.useCommonNameAsAlias(certificate), certificate);
}
}
protected void loadAllStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
allStore = KeyStore.getInstance("JKS");
allStore.load(null, CertificateController.passwd);
protected void loadAllStore() {
try {
allStore = KeyStore.getInstance("JKS");
allStore.load(null, CertificateController.passwd);
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | HeadlessException e) {
Log.error("Cannot create allStore KeyStore", e);
}
}
@Override
@ -59,16 +60,13 @@ public abstract class GeneralTrustManager implements X509TrustManager {
try {
// See how many certificates are in the keystore.
int numberOfEntry = allStore.size();
// Create an array of X509Certificates
X509Certs = new X509Certificate[numberOfEntry];
// If there are any certificates in the keystore.
if (numberOfEntry > 0) {
// Get all of the certificate alias out of the keystore.
// Get all the certificate alias out of the keystore.
Enumeration<String> aliases = allStore.aliases();
// Retrieve all of the certificates out of the keystore
// Retrieve all the certificates out of the keystore
// via the alias name.
int i = 0;
while (aliases.hasMoreElements()) {

View File

@ -17,15 +17,16 @@ import javax.net.ssl.X509TrustManager;
import org.jivesoftware.spark.util.log.Log;
/**
* This TrustManager serves for purpose of accepting certificates from exceptions lists. The only check it does is check
* if certification path can be builded. It doesn't do any checks against time of expiration or revocation.
* This TrustManager serves for purpose of accepting certificates from exceptions lists.
* The only check it does is check if certification path can be built.
* It doesn't do any checks against time of expiration or revocation.
*
* @author Pawel Scibiorski
*
*/
public class SparkExceptionsTrustManager extends GeneralTrustManager implements X509TrustManager {
KeyStore exceptionsStore, cacertsExceptionsStore;
public SparkExceptionsTrustManager() {
loadKeyStores();
}
@ -51,9 +52,10 @@ public class SparkExceptionsTrustManager extends GeneralTrustManager implements
}
/**
* Validate certificate path. As it is exception, no checks against revocation or time validity are done but path
* still have to be validated in order to find connection between certificate presented by server and root CA in
* KeyStore
* Validate certificate path.
* As it is exception, no checks against revocation or time validity are done.
* But the path still have to be validated in order to find connection between
* certificate presented by server and root CA in KeyStore
*
* @throws NoSuchAlgorithmException
* @throws KeyStoreException
@ -70,8 +72,8 @@ public class SparkExceptionsTrustManager extends GeneralTrustManager implements
throw new IllegalArgumentException("Method cannot be used with self-signed certificate.");
}
// The certificate representing the {@link TrustAnchor TrustAnchor} should not be included in the certification
// path. If it does, certain validation (like OCSP) might give unexpected results/fail. SPARK-2188
// The certificate representing the {@link TrustAnchor} should not be included in the certification path.
// If it does, certain validation (like OCSP) might give unexpected results/fail. SPARK-2188
final List<X509Certificate> certificates = Arrays.stream(chain)
.filter( cert -> !SparkTrustManager.isRootCACertificate(cert))
.collect(Collectors.toList());
@ -101,7 +103,6 @@ public class SparkExceptionsTrustManager extends GeneralTrustManager implements
PKIXCertPathValidatorResult validationResult = (PKIXCertPathValidatorResult) certPathValidator
.validate(certPath, parameters);
X509Certificate trustAnchor = validationResult.getTrustAnchor().getTrustedCert();
if (trustAnchor == null) {
throw new CertificateException("certificate path failed: Trusted CA is NULL");
}
@ -130,7 +131,6 @@ public class SparkExceptionsTrustManager extends GeneralTrustManager implements
} else {
return exceptionsStore.getCertificateAlias(chain[chain.length - 1]) != null;
}
}
/**
@ -140,12 +140,8 @@ public class SparkExceptionsTrustManager extends GeneralTrustManager implements
protected void loadKeyStores() {
exceptionsStore = certControll.openKeyStore(CertificateController.EXCEPTIONS);
cacertsExceptionsStore = certControll.openKeyStore(CertificateController.CACERTS_EXCEPTIONS);
try {
loadAllStore();
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | HeadlessException e) {
Log.error("Cannot create allStore KeyStore");
}
loadAllStore();
try {
addKeyStoreContentToAllStore(exceptionsStore);
} catch (HeadlessException | KeyStoreException | InvalidNameException e) {
@ -156,7 +152,6 @@ public class SparkExceptionsTrustManager extends GeneralTrustManager implements
} catch (HeadlessException | KeyStoreException | InvalidNameException e) {
Log.error("Cannot add cacertsExceptionsStore to allStore", e);
}
}
}

View File

@ -19,6 +19,7 @@ import java.util.stream.Collectors;
import javax.naming.InvalidNameException;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.lang3.ArrayUtils;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.DistributionPoint;
@ -30,13 +31,12 @@ import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.jivesoftware.spark.util.log.Log;
/**
* This trust manager wrap around SparkExceptionsTrustManager. In case when SparkExceptionsTrustManager fail then this
* This trust manager wrap around SparkExceptionsTrustManager.
* In case when SparkExceptionsTrustManager fail then this
* TrustManager will provide certificates from TRUSTED KeyStore which are checked against data validity, revocation,
* acceptance of self-signed certificates and basic constraints.
*
*
* @author Pawel Scibiorsk
*
* @author Pawel Scibiorsk
*/
public class SparkTrustManager extends GeneralTrustManager implements X509TrustManager {
@ -101,13 +101,13 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
/**
* Do chain validity checks
* @param chain with certificates from server
* @param authType
* @param authType "RSA" etc.
* @throws CertificateException
* @throws CertPathValidatorException
*/
private void doTheChecks(X509Certificate[] chain, String authType) throws CertificateException, CertPathValidatorException {
try {
// first check if certificate is accepted as as certificate from exceptions list, exceptionsTrustManager
// first check if certificate is accepted as a certificate from exceptions list, exceptionsTrustManager
// will make use of chain provided by exceptions KeyStore
exceptionsTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException ex) {
@ -121,22 +121,18 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
// validate certificate path
try {
validatePath(chain);
} catch (NoSuchAlgorithmException | KeyStoreException | InvalidAlgorithmParameterException | CertPathValidatorException e) {
Log.error("Validating path failed", e);
throw new CertPathValidatorException("Certificate path validation failed", e);
}
} else if (isSelfSigned(chain) && !acceptSelfSigned) {
// Self Signed certificate while it isn't accepted
throw new CertificateException("Self Signed certificate");
} else if (isSelfSigned(chain) && acceptSelfSigned) {
// check if certificate is in Keystore and check CRL, but do not validate path as certificate is Self
// Signed important reminder: hostname validation must be also turned off to accept self signed
// certificate
List<X509Certificate> certList = new ArrayList<>(Arrays.asList(getAcceptedIssuers()));
if (!certList.contains(chain[0])) {
if (!ArrayUtils.contains(getAcceptedIssuers(), chain[0])) {
throw new CertPathValidatorException("Certificate not in the TrustStore");
}
try {
@ -239,7 +235,6 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
// if revoked certificates aren't accepted, but no revocation checks then only
// certificates from blacklist will be rejected
if (!acceptRevoked) {
// OCSP checking is done according to Java PKI Programmer's Guide, PKIXRevocationChecker was added in Java 8:
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/certpath/CertPathProgGuide.html#PKIXRevocationChecker
PKIXRevocationChecker checker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker();
@ -262,14 +257,12 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
checker.setOptions(checkerOptions);
parameters.addCertPathChecker(checker);
}
}
try {
PKIXCertPathValidatorResult validationResult = (PKIXCertPathValidatorResult) certPathValidator
.validate(certPath, parameters);
X509Certificate trustAnchor = validationResult.getTrustAnchor().getTrustedCert();
if (trustAnchor == null) {
throw new CertificateException("certificate path failed: Trusted CA is NULL");
}
@ -312,7 +305,6 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
* @throws CertificateException
*/
private void checkDateValidity(X509Certificate[] chain) throws CertificateException {
for (X509Certificate cert : chain) {
// expiration check
try {
@ -328,7 +320,6 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
throw new CertificateException("Certificate is not valid yet");
}
}
}
}
@ -377,7 +368,7 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
}
/**
* loads truststores and potentially (depending on settings) blacklist
* loads trust stores and potentially (depending on settings) blacklist
*/
@Override
protected void loadKeyStores() {
@ -385,12 +376,7 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
trustStore = certControll.openKeyStore(CertificateController.TRUSTED);
displayedCaCerts = certControll.openCacertsKeyStore();
try {
loadAllStore();
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException
| HeadlessException e) {
Log.error("Cannot create allStore KeyStore");
}
loadAllStore();
try {
addKeyStoreContentToAllStore(trustStore);
@ -402,7 +388,6 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
} catch (HeadlessException | KeyStoreException | InvalidNameException e) {
Log.error("Cannot add displayedCaCerts to the allStore", e);
}
}
@ -469,7 +454,6 @@ public class SparkTrustManager extends GeneralTrustManager implements X509TrustM
* @throws CRLException
*/
private X509CRL downloadCRL(URL url) throws IOException, CertificateException, CRLException {
try (InputStream crlStream = url.openStream()) {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
return (X509CRL) cf.generateCRL(crlStream);