From 32b86bd750f52395f820ce62ac244e9358c7eebc Mon Sep 17 00:00:00 2001 From: akila94 Date: Fri, 1 Dec 2023 09:17:48 +0530 Subject: [PATCH 01/10] Do cert revocation improvement --- .../RevocationVerificationManager.java | 96 ++++++++++++++++++- .../certificatevalidation/ocsp/OCSPCache.java | 2 +- .../ocsp/OCSPVerifier.java | 68 +++++++------ .../config/ClientConnFactoryBuilder.java | 2 +- .../config/ServerConnFactoryBuilder.java | 63 +++++++++++- .../core/ssl/SSLServerConnFactoryBuilder.java | 2 +- .../util/ConfigurationBuilderUtil.java | 31 ++++++ 7 files changed, 225 insertions(+), 39 deletions(-) diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java index 338b8a8a36..e2aa54498a 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java @@ -25,9 +25,21 @@ import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPCache; import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPVerifier; import org.apache.synapse.transport.certificatevalidation.pathvalidation.CertificatePathValidator; +import org.apache.synapse.transport.util.ConfigurationBuilderUtil; +import org.wso2.securevault.KeyStoreType; import java.io.ByteArrayInputStream; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SignatureException; +import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Optional; /** * Manager class responsible for verifying certificates. This class will use the available verifiers according to @@ -37,9 +49,11 @@ public class RevocationVerificationManager { private int cacheSize = Constants.CACHE_DEFAULT_ALLOCATED_SIZE; private int cacheDelayMins = Constants.CACHE_DEFAULT_DELAY_MINS; + private boolean isFullCertChainValidationEnabled = false; private static final Log log = LogFactory.getLog(RevocationVerificationManager.class); - public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins) { + public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins, + boolean isFullCertChainValidationEnabled) { if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { @@ -49,6 +63,7 @@ public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDe && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) { this.cacheDelayMins = cacheDelayMins; } + this.isFullCertChainValidationEnabled = isFullCertChainValidationEnabled; } /** @@ -62,6 +77,69 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer X509Certificate[] convertedCertificates = convert(peerCertificates); + Optional peerCertOpt; + X509Certificate peerCert = null; + X509Certificate issuerCert = null; + String alias; + + if (!isFullCertChainValidationEnabled) { + + if (log.isDebugEnabled()) { + log.debug("Retrieving the issuer certificate from client truststore since full certificate chain " + + "validation is disabled"); + } + + KeyStore trustStore; + Enumeration aliases; + String truststorePath = System.getProperty("javax.net.ssl.trustStore"); + String truststorePassword = System.getProperty("javax.net.ssl.trustStorePassword");; + + try { + trustStore = ConfigurationBuilderUtil.getKeyStore(truststorePath, truststorePassword, + KeyStoreType.JKS.toString()); + } catch (KeyStoreException e) { + throw new CertificateVerificationException("Error loading the truststore", e); + } + + try { + aliases = trustStore.aliases(); + } catch (KeyStoreException e) { + throw new CertificateVerificationException("Error while retrieving aliases from truststore", e); + } + + while (aliases.hasMoreElements()) { + alias = aliases.nextElement(); + try { + issuerCert = (X509Certificate) trustStore.getCertificate(alias); + } catch (KeyStoreException e) { + throw new CertificateVerificationException("Unable to read the certificate from truststore with " + + "the alias: " + alias, e); + } + + if (issuerCert == null) { + throw new CertificateVerificationException("Issuer certificate not found in truststore"); + } + + // When full chain validation is disabled, only one cert is expected + peerCertOpt = Arrays.stream(convertedCertificates).findFirst(); + if (peerCertOpt.isPresent()) { + peerCert = peerCertOpt.get(); + } else { + throw new CertificateVerificationException("Peer certificate is not provided"); + } + + try { + peerCert.verify(issuerCert.getPublicKey()); + log.debug("Valid issuer certificate found in the client truststore"); + break; + } catch (SignatureException | CertificateException | NoSuchAlgorithmException | InvalidKeyException | + NoSuchProviderException e) { + // Unable to verify the signature. Check with the next certificate. + log.error("Signature not matching for alias : " + alias + ", validate with next cert"); + } + } + } + long start = System.currentTimeMillis(); OCSPCache ocspCache = OCSPCache.getCache(); @@ -73,9 +151,19 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer for (RevocationVerifier verifier : verifiers) { try { - CertificatePathValidator pathValidator = new CertificatePathValidator(convertedCertificates, verifier); - pathValidator.validatePath(); - log.info("Path verification Successful. Took " + (System.currentTimeMillis() - start) + " ms."); + if (isFullCertChainValidationEnabled) { + log.debug("Doing full certificate chain validation"); + CertificatePathValidator pathValidator = new CertificatePathValidator(convertedCertificates, + verifier); + pathValidator.validatePath(); + log.info("Path verification Successful. Took " + (System.currentTimeMillis() - start) + " ms."); + } else { + if (log.isDebugEnabled()) { + log.debug("Validating client certificate with the issuer certificate retrieved from" + + "the trust store"); + } + verifier.checkRevocationStatus(peerCert, issuerCert); + } return; } catch (Exception e) { log.info(verifier.getClass().getSimpleName() + " failed."); diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java index b01d509867..471323e6b3 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java @@ -116,7 +116,7 @@ private synchronized void replaceNewCacheValue(OCSPCacheValue cacheValue){ try { String serviceUrl = cacheValue.serviceUrl; OCSPReq request = cacheValue.request; - OCSPResp response= ocspVerifier.getOCSPResponce(serviceUrl, request); + OCSPResp response= ocspVerifier.getOCSPResponse(serviceUrl, request); if (OCSPResponseStatus.SUCCESSFUL != response.getStatus()) throw new CertificateVerificationException("OCSP response status not SUCCESSFUL"); diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java index d9a3a11039..393127d1b8 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java @@ -20,6 +20,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.http.HttpResponse; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; import org.bouncycastle.asn1.*; import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; @@ -52,6 +59,12 @@ public OCSPVerifier(OCSPCache cache) { this.cache = cache; } + public static final String CONTENT_TYPE = "Content-Type"; + public static final String JSON_TYPE ="application/json"; + public static final String ACCEPT_TYPE = "Accept"; + public static final String OCSP_REQUEST_TYPE = "application/ocsp-request"; + public static final String OCSP_RESPONSE_TYPE = "application/ocsp-response"; + /** * Gets the revocation status (Good, Revoked or Unknown) of the given peer certificate. * @@ -83,7 +96,7 @@ public RevocationStatus checkRevocationStatus(X509Certificate peerCert, X509Cert SingleResp[] responses; try { - OCSPResp ocspResponse = getOCSPResponce(serviceUrl, request); + OCSPResp ocspResponse = getOCSPResponse(serviceUrl, request); if (OCSPResponseStatus.SUCCESSFUL != ocspResponse.getStatus()) { continue; // Server didn't give the response right. } @@ -128,37 +141,34 @@ private RevocationStatus getRevocationStatus(SingleResp resp) throws Certificate * @throws CertificateVerificationException * */ - protected OCSPResp getOCSPResponce(String serviceUrl, OCSPReq request) throws CertificateVerificationException { + protected OCSPResp getOCSPResponse(String serviceUrl, OCSPReq request) throws CertificateVerificationException { - try { - //Todo: Use http client. - byte[] array = request.getEncoded(); - if (serviceUrl.startsWith("http")) { - HttpURLConnection con; - URL url = new URL(serviceUrl); - con = (HttpURLConnection) url.openConnection(); - con.setRequestProperty("Content-Type", "application/ocsp-request"); - con.setRequestProperty("Accept", "application/ocsp-response"); - con.setDoOutput(true); - OutputStream out = con.getOutputStream(); - DataOutputStream dataOut = new DataOutputStream(new BufferedOutputStream(out)); - dataOut.write(array); - - dataOut.flush(); - dataOut.close(); - - //Check errors in response: - if (con.getResponseCode() / 100 != 2) { - throw new CertificateVerificationException("Error getting ocsp response." + - "Response code is " + con.getResponseCode()); - } + if (log.isDebugEnabled()) { + log.debug("Initiating HTTP request to URL: " + serviceUrl + " to get the OCSP response"); + } + + try (CloseableHttpClient client = HttpClientBuilder.create().build()) { + HttpPost httpPost = new HttpPost(serviceUrl); + + // adding request timeout configurations + if (httpPost.getConfig() == null) { + httpPost.setConfig(RequestConfig.custom().build()); + } - //Get Response - InputStream in = (InputStream) con.getContent(); - return new OCSPResp(in); - } else { - throw new CertificateVerificationException("Only http is supported for ocsp calls"); + httpPost.addHeader(CONTENT_TYPE, OCSP_REQUEST_TYPE); + httpPost.addHeader(ACCEPT_TYPE, OCSP_RESPONSE_TYPE); + httpPost.setEntity(new ByteArrayEntity(request.getEncoded(), ContentType.create(JSON_TYPE))); + HttpResponse httpResponse = client.execute(httpPost); + + //Check errors in response, if response status code is not 200 (success) range, throws exception + // eg: if response code is 200 (success) or 201 (accepted) return true, + // if response code is 404 (not found) or 500 throw exception + if (httpResponse.getStatusLine().getStatusCode() / 100 != 2) { + throw new CertificateVerificationException("Error getting ocsp response." + + "Response code is " + httpResponse.getStatusLine().getStatusCode()); } + InputStream in = httpResponse.getEntity().getContent(); + return new OCSPResp(in); } catch (IOException e) { throw new CertificateVerificationException("Cannot get ocspResponse from url: " + serviceUrl, e); } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java index bf504b9999..5219a29fe5 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java @@ -146,7 +146,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault { cacheDelay = new Integer(cacheDelayString); } catch (NumberFormatException e) { } - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay); + revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, true); } // Process HttpProtocols diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java index 817c11e99b..fd4a9fe133 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java @@ -26,6 +26,7 @@ import org.apache.axis2.description.Parameter; import org.apache.axis2.description.TransportInDescription; import org.apache.axis2.transport.base.ParamUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpHost; @@ -305,8 +306,22 @@ public ServerConnFactoryBuilder parseSSL() throws AxisFault { cacheSize = new Integer(cacheSizeString); cacheDelay = new Integer(cacheDelayString); } - catch (NumberFormatException e) {} - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay); + catch (NumberFormatException e) { + throw new AxisFault("Cache size or Cache delay values are malformed", e); + } + + // Checking whether the full certificate chain validation is enabled or not. + boolean isFullCertChainValidationEnabled = true; + OMElement isFullCertChainValidationConfig = cvp.getParameterElement() + .getFirstChildWithName(new QName("FullChainValidation")); + + if (isFullCertChainValidationConfig != null + && StringUtils.equals("false", isFullCertChainValidationConfig.getText())) { + isFullCertChainValidationEnabled = false; + } + + revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, + isFullCertChainValidationEnabled); } ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, preferredCiphersEl, @@ -324,6 +339,8 @@ public ServerConnFactoryBuilder parseMultiProfileSSL() throws AxisFault { OMElement profilesEl = profileParam.getParameterElement(); SecretResolver secretResolver = SecretResolverFactory.create(profilesEl, true); Iterator profiles = profilesEl.getChildrenWithName(new QName("profile")); + RevocationVerificationManager revocationVerifier = null; + while (profiles.hasNext()) { OMElement profileEl = (OMElement) profiles.next(); OMElement bindAddressEl = profileEl.getFirstChildWithName(new QName("bindAddress")); @@ -341,8 +358,48 @@ public ServerConnFactoryBuilder parseMultiProfileSSL() throws AxisFault { OMElement preferredCiphersEl = profileEl.getFirstChildWithName(new QName(NhttpConstants.PREFERRED_CIPHERS)); final Parameter sslpParameter = transportIn.getParameter("SSLProtocol"); final String sslProtocol = sslpParameter != null ? sslpParameter.getValue().toString() : "TLS"; + + /* If multi SSL profiles are configured, checking whether the certificate revocation verifier is + configured and full certificate chain validation is enabled or not. */ + if (profileEl.getFirstChildWithName(new QName("CertificateRevocationVerifier")) != null) { + + Integer cacheSize = null; + Integer cacheDelay = null; + + OMElement revocationVerifierConfig = profileEl + .getFirstChildWithName(new QName("CertificateRevocationVerifier")); + OMElement revocationEnabled = revocationVerifierConfig + .getFirstChildWithName(new QName("Enable")); + + if (revocationEnabled != null && "true".equals(revocationEnabled.getText())) { + String cacheSizeString = revocationVerifierConfig + .getFirstChildWithName(new QName("CacheSize")).getText(); + String cacheDelayString = revocationVerifierConfig + .getFirstChildWithName(new QName("CacheDelay")).getText(); + + try { + cacheSize = new Integer(cacheSizeString); + cacheDelay = new Integer(cacheDelayString); + } catch (NumberFormatException e) { + throw new AxisFault("Cache size or Cache delay values are malformed", e); + } + } + + boolean isFullCertChainValidationEnabled = true; + OMElement isFullCertChainValidationConfig = revocationVerifierConfig + .getFirstChildWithName(new QName("FullChainValidation")); + + if (isFullCertChainValidationConfig != null + && StringUtils.equals("false", isFullCertChainValidationConfig.getText())) { + isFullCertChainValidationEnabled = false; + } + + revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, + isFullCertChainValidationEnabled); + } + SSLContextDetails ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, - preferredCiphersEl, null, sslProtocol, secretResolver); + preferredCiphersEl, revocationVerifier, sslProtocol, secretResolver); if (sslByIPMap == null) { sslByIPMap = new HashMap(); } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java index 282900b956..4b552bd799 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java @@ -70,7 +70,7 @@ public ServerConnFactoryBuilder parseSSL(OMElement keyStoreEl, OMElement trustSt } catch (NumberFormatException e) { log.error("Please specify correct Integer numbers for CacheDelay and CacheSize"); } - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay); + revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, true); } ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, preferredCiphers, revocationVerifier, diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java index f5a81c1572..cadb9e499b 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java @@ -21,6 +21,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.util.Properties; public class ConfigurationBuilderUtil { @@ -171,4 +178,28 @@ public static String getStringProperty(String name, String def, Properties props return val == null ? def : val; } + /** + * Returns the keystore of the given file path. + * + * @param keyStoreFilePath the keystore file path + * @param keyStorePassword the keystore password + * @param keyStoreType the keystore type + * @return KeyStore + * @throws KeyStoreException On error while creating keystore + */ + public static KeyStore getKeyStore(String keyStoreFilePath, String keyStorePassword, String keyStoreType) + throws KeyStoreException { + + String file = new File(keyStoreFilePath).getAbsolutePath(); + try (FileInputStream keyStoreFileInputStream = new FileInputStream(file)) { + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + keyStore.load(keyStoreFileInputStream, keyStorePassword.toCharArray()); + return keyStore; + } catch (IOException | NoSuchAlgorithmException | CertificateException e) { + String errorMessage = String.format("Keystore file does not exist in the path as configured " + + "in '%s' property.", keyStoreFilePath); + throw new KeyStoreException(errorMessage); + } + } + } From d56091b13082cdf04fe43bb600249f25c52ebf89 Mon Sep 17 00:00:00 2001 From: akila94 Date: Mon, 1 Jan 2024 19:47:55 +0530 Subject: [PATCH 02/10] Add trust store holder and cache --- .../RevocationVerificationManager.java | 113 +++++++---- .../cache/CertCache.java | 188 ++++++++++++++++++ .../ocsp/OCSPVerifier.java | 29 ++- .../config/ClientConnFactoryBuilder.java | 119 ++++++----- .../config/ServerConnFactoryBuilder.java | 68 ++++--- .../nhttp/config/TrustStoreHolder.java | 60 ++++++ .../passthru/PassThroughHttpListener.java | 7 +- .../passthru/PassThroughHttpSender.java | 8 +- .../util/ConfigurationBuilderUtil.java | 32 --- 9 files changed, 459 insertions(+), 165 deletions(-) create mode 100644 modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java create mode 100644 modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java index e2aa54498a..683df58258 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java @@ -20,13 +20,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.synapse.transport.certificatevalidation.cache.CertCache; import org.apache.synapse.transport.certificatevalidation.crl.CRLCache; import org.apache.synapse.transport.certificatevalidation.crl.CRLVerifier; import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPCache; import org.apache.synapse.transport.certificatevalidation.ocsp.OCSPVerifier; import org.apache.synapse.transport.certificatevalidation.pathvalidation.CertificatePathValidator; -import org.apache.synapse.transport.util.ConfigurationBuilderUtil; -import org.wso2.securevault.KeyStoreType; +import org.apache.synapse.transport.nhttp.config.TrustStoreHolder; import java.io.ByteArrayInputStream; import java.security.InvalidKeyException; @@ -52,6 +52,18 @@ public class RevocationVerificationManager { private boolean isFullCertChainValidationEnabled = false; private static final Log log = LogFactory.getLog(RevocationVerificationManager.class); + public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins) { + + if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE + && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { + this.cacheSize = cacheAllocatedSize; + } + if (cacheDelayMins != null && cacheDelayMins > Constants.CACHE_MIN_DELAY_MINS + && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) { + this.cacheDelayMins = cacheDelayMins; + } + } + public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins, boolean isFullCertChainValidationEnabled) { @@ -67,8 +79,15 @@ public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDe } /** - * This method first tries to verify the given certificate chain using OCSP since OCSP verification is - * faster. If that fails it tries to do the verification using CRL. + * This method verifies the given certificate chain or given peer certificate for revocation based on the + * requirement of full certificate chain validation. If full chain validation is enabled (default), + * the full certificate chain will be validated before checking the chain for revocation. If full chain validation + * is disabled, this method expects a single peer certificate, and it is validated with the immediate issuer + * certificate in the truststore (The truststore must contain the immediate issuer of the peer certificate). + * In both cases, OCSP and CRL verifiers are used for revocation verification. + * It first tries to verify using OCSP since OCSP verification is faster. If that fails it tries to do the + * verification using CRL. + * * @param peerCertificates javax.security.cert.X509Certificate[] array of peer certificate chain from peer/client. * @throws CertificateVerificationException */ @@ -89,53 +108,71 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer "validation is disabled"); } - KeyStore trustStore; + KeyStore trustStore = TrustStoreHolder.getInstance().getClientTrustStore(); Enumeration aliases; - String truststorePath = System.getProperty("javax.net.ssl.trustStore"); - String truststorePassword = System.getProperty("javax.net.ssl.trustStorePassword");; - try { - trustStore = ConfigurationBuilderUtil.getKeyStore(truststorePath, truststorePassword, - KeyStoreType.JKS.toString()); - } catch (KeyStoreException e) { - throw new CertificateVerificationException("Error loading the truststore", e); + // When full chain validation is disabled, only one cert is expected + peerCertOpt = Arrays.stream(convertedCertificates).findFirst(); + if (peerCertOpt.isPresent()) { + peerCert = peerCertOpt.get(); + } else { + throw new CertificateVerificationException("Peer certificate is not provided"); } - try { - aliases = trustStore.aliases(); - } catch (KeyStoreException e) { - throw new CertificateVerificationException("Error while retrieving aliases from truststore", e); - } + // Get cert cache and initialize it + CertCache certCache = CertCache.getCache(); + certCache.init(cacheSize,cacheDelayMins); + + if (certCache.getCacheValue(peerCert.getSerialNumber().toString()) == null) { - while (aliases.hasMoreElements()) { - alias = aliases.nextElement(); try { - issuerCert = (X509Certificate) trustStore.getCertificate(alias); + aliases = trustStore.aliases(); } catch (KeyStoreException e) { - throw new CertificateVerificationException("Unable to read the certificate from truststore with " + - "the alias: " + alias, e); + throw new CertificateVerificationException("Error while retrieving aliases from truststore", e); } - if (issuerCert == null) { - throw new CertificateVerificationException("Issuer certificate not found in truststore"); - } - - // When full chain validation is disabled, only one cert is expected - peerCertOpt = Arrays.stream(convertedCertificates).findFirst(); - if (peerCertOpt.isPresent()) { - peerCert = peerCertOpt.get(); - } else { - throw new CertificateVerificationException("Peer certificate is not provided"); + while (aliases.hasMoreElements()) { + try { + alias = aliases.nextElement(); + try { + issuerCert = (X509Certificate) trustStore.getCertificate(alias); + } catch (KeyStoreException e) { + throw new CertificateVerificationException("Unable to read the certificate from " + + "truststore with the alias: " + alias, e); + } + + if (issuerCert == null) { + throw new CertificateVerificationException("Issuer certificate not found in truststore"); + } + + peerCert.verify(issuerCert.getPublicKey()); + log.debug("Valid issuer certificate found in the client truststore. Caching.."); + + // Store the valid issuer cert in cache for future use + certCache.setCacheValue(peerCert.getSerialNumber().toString(), issuerCert); + if (log.isDebugEnabled()) { + log.debug("Issuer certificate with serial number: " + issuerCert.getSerialNumber() + .toString() + " has been cached against the serial number: " + peerCert + .getSerialNumber().toString() + " of the peer certificate."); + } + break; + } catch (SignatureException | CertificateException | NoSuchAlgorithmException | + InvalidKeyException | + NoSuchProviderException e) { + // Unable to verify the signature. Check with the next certificate. + //todo: change this to a debug log after testing. + log.error("Unable to verify the signature, checking with the next certificate..."); + } } - + } else { + X509Certificate cachedIssuerCert = certCache.getCacheValue(peerCert.getSerialNumber().toString()); try { - peerCert.verify(issuerCert.getPublicKey()); - log.debug("Valid issuer certificate found in the client truststore"); - break; - } catch (SignatureException | CertificateException | NoSuchAlgorithmException | InvalidKeyException | + peerCert.verify(cachedIssuerCert.getPublicKey()); + } catch (SignatureException | CertificateException | NoSuchAlgorithmException | + InvalidKeyException | NoSuchProviderException e) { // Unable to verify the signature. Check with the next certificate. - log.error("Signature not matching for alias : " + alias + ", validate with next cert"); + log.error("Signature not matching for alias validate with next cert"); } } } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java new file mode 100644 index 0000000000..71a483539d --- /dev/null +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java @@ -0,0 +1,188 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.transport.certificatevalidation.cache; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.synapse.commons.jmx.MBeanRegistrar; + +import java.security.cert.X509Certificate; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * This is a cache to store a certificate against a unique string (can be a serial number). This is a singleton since + * more than one cache of this kind should not be allowed. This cache can be used by any place where certificate + * caching is needed. + */ +public class CertCache implements ManageableCache { + + private static volatile CertCache cache; + private static volatile Map hashMap = new ConcurrentHashMap(); + private static volatile Iterator> iterator = hashMap.entrySet().iterator(); + private static volatile CacheManager cacheManager; + private static final Log log = LogFactory.getLog(CertCache.class); + + private CertCache() { + } + + public static CertCache getCache() { + //Double-checked locking + if (cache == null) { + synchronized (CertCache.class) { + if (cache == null) { + cache = new CertCache(); + } + } + } + return cache; + } + + /** + * This initialize the Cache with a CacheManager. If this method is called, a cache manager will not be used. + * + * @param size max size of the cache + * @param delay defines how frequently the CacheManager will be started + */ + public void init(int size, int delay) { + if (cacheManager == null) { + synchronized (CertCache.class) { + if (cacheManager == null) { + cacheManager = new CacheManager(cache, size, delay); + CacheController mbean = new CacheController(cache,cacheManager); + MBeanRegistrar.getInstance().registerMBean(mbean, "CacheController", "CertCacheController"); + } + } + } + } + + public synchronized X509Certificate getCacheValue(String serialNumber) { + CertCache.TempCacheValue cacheValue = hashMap.get(serialNumber); + if (cacheValue != null) { + return cacheValue.getValue(); + } else + return null; + } + + @Override + public ManageableCacheValue getNextCacheValue() { + + //changes to the map are reflected on the keySet. And its iterator is weakly consistent. so will never + //throw concurrent modification exception. + if (iterator.hasNext()) { + return hashMap.get(iterator.next().getKey()); + } else { + resetIterator(); + return null; + } + } + + @Override + public int getCacheSize() { + + return hashMap.size(); + } + + @Override + public void resetIterator() { + + iterator = hashMap.entrySet().iterator(); + } + + public static void resetCache() { + + hashMap.clear(); + } + + public synchronized void setCacheValue(String serialNumber, X509Certificate cert) { + CertCache.TempCacheValue cacheValue = new CertCache.TempCacheValue(serialNumber, cert); + + if (log.isDebugEnabled()) { + log.debug("Before set - HashMap size " + hashMap.size()); + } + hashMap.put(serialNumber, cacheValue); + if (log.isDebugEnabled()) { + log.debug("After set - HashMap size " + hashMap.size()); + } + } + + public synchronized void removeCacheValue(String serialNumber) { + + if (log.isDebugEnabled()) { + log.debug("Before remove - HashMap size " + hashMap.size()); + } + hashMap.remove(serialNumber); + if (log.isDebugEnabled()) { + log.debug("After remove - HashMap size " + hashMap.size()); + } + } + + /** + * This is the wrapper class of the actual cache value which is a X509CRL. + */ + private class TempCacheValue implements ManageableCacheValue { + + private final String serialNumber; + private final X509Certificate issuerCertificate; + private final long timeStamp = System.currentTimeMillis(); + + public TempCacheValue(String serialNumber, X509Certificate issuerCertificate) { + + this.serialNumber = serialNumber; + this.issuerCertificate = issuerCertificate; + } + + public X509Certificate getValue() { + + return issuerCertificate; + } + + public String getKey() { + + return serialNumber; + } + + /** + * CRL has a validity period. We can reuse a downloaded CRL within that period. + */ + public boolean isValid() { + + // Will be always return true since we only set defined data. + return true; + } + + public long getTimeStamp() { + + return timeStamp; + } + + /** + * Used by cacheManager to remove invalid entries. + */ + public void removeThisCacheValue() { + + removeCacheValue(serialNumber); + } + + public void updateCacheWithNewValue() { + // No implementation needed since there are no scenarios of the cache value being invalid. + } + } +} diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java index 393127d1b8..5744365730 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPVerifier.java @@ -27,20 +27,35 @@ import org.apache.http.entity.ContentType; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; -import org.bouncycastle.asn1.*; +import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException; +import org.apache.synapse.transport.certificatevalidation.Constants; +import org.apache.synapse.transport.certificatevalidation.RevocationStatus; +import org.apache.synapse.transport.certificatevalidation.RevocationVerifier; +import org.bouncycastle.asn1.ASN1InputStream; +import org.bouncycastle.asn1.DERIA5String; +import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers; import org.bouncycastle.asn1.ocsp.OCSPResponseStatus; -import org.bouncycastle.asn1.x509.*; +import org.bouncycastle.asn1.x509.AccessDescription; +import org.bouncycastle.asn1.x509.AuthorityInformationAccess; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.ocsp.*; -import org.apache.synapse.transport.certificatevalidation.*; +import org.bouncycastle.cert.ocsp.BasicOCSPResp; +import org.bouncycastle.cert.ocsp.CertificateID; +import org.bouncycastle.cert.ocsp.CertificateStatus; +import org.bouncycastle.cert.ocsp.OCSPReq; +import org.bouncycastle.cert.ocsp.OCSPReqBuilder; +import org.bouncycastle.cert.ocsp.OCSPResp; +import org.bouncycastle.cert.ocsp.SingleResp; import org.bouncycastle.operator.DigestCalculatorProvider; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; import java.math.BigInteger; -import java.net.HttpURLConnection; -import java.net.URL; import java.security.Provider; import java.security.Security; import java.security.cert.X509Certificate; diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java index 5219a29fe5..44710be55a 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java @@ -19,27 +19,6 @@ package org.apache.synapse.transport.nhttp.config; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.xml.namespace.QName; -import javax.xml.stream.XMLStreamException; - -import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axis2.AxisFault; @@ -52,7 +31,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.params.HttpParams; -import org.apache.synapse.commons.crypto.CryptoConstants; import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager; import org.apache.synapse.transport.exceptions.InvalidConfigurationException; import org.apache.synapse.transport.http.conn.ClientConnFactory; @@ -63,8 +41,25 @@ import org.apache.synapse.transport.nhttp.util.SecureVaultValueReader; import org.wso2.securevault.SecretResolver; import org.wso2.securevault.SecretResolverFactory; -import org.wso2.securevault.SecureVaultException; -import org.wso2.securevault.commons.MiscellaneousUtil; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLStreamException; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; public class ClientConnFactoryBuilder { @@ -76,6 +71,7 @@ public class ClientConnFactoryBuilder { private SSLContextDetails ssl = null; private Map sslByHostMap = null; private ConfigurationContext configurationContext; + TrustStoreHolder trustStoreHolder = TrustStoreHolder.getInstance(); public ClientConnFactoryBuilder(final TransportOutDescription transportOut, ConfigurationContext configurationContext) { this(transportOut); @@ -87,7 +83,7 @@ public ClientConnFactoryBuilder(final TransportOutDescription transportOut) { this.transportOut = transportOut; this.name = transportOut.getName().toUpperCase(Locale.US); } - + public ClientConnFactoryBuilder parseSSL() throws AxisFault { Parameter keyParam = transportOut.getParameter("keystore"); Parameter trustParam = transportOut.getParameter("truststore"); @@ -146,7 +142,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault { cacheDelay = new Integer(cacheDelayString); } catch (NumberFormatException e) { } - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, true); + revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay); } // Process HttpProtocols @@ -353,28 +349,37 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE log.warn(name + " Ignoring novalidatecert parameter since a truststore has been specified"); } - String location = trustStoreElt.getFirstChildWithName(new QName("Location")).getText(); - String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText(); - OMElement passwordElement = trustStoreElt.getFirstChildWithName(new QName("Password")); - if (passwordElement == null) { - throw new AxisFault("Cannot proceed because Password element is missing in TrustStore"); - } - String storePassword = SecureVaultValueReader.getSecureVaultValue(resolver, passwordElement); - FileInputStream fis = null; + String location = trustStoreElt.getFirstChildWithName(new QName("Location")).getText();; + KeyStore trustStore; + try { - KeyStore trustStore = KeyStore.getInstance(type); - fis = new FileInputStream(location); - if (log.isDebugEnabled()) { - log.debug(name + " Loading Trust Keystore from : " + location); + if (trustStoreHolder.getClientTrustStore() == null) { + String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText(); + OMElement passwordElement = trustStoreElt.getFirstChildWithName(new QName("Password")); + + if (passwordElement == null) { + throw new AxisFault("Cannot proceed because Password element is missing in TrustStore"); + } + + String storePassword = SecureVaultValueReader.getSecureVaultValue(resolver, passwordElement); + trustStore = KeyStore.getInstance(type); + fis = new FileInputStream(location); + + if (log.isDebugEnabled()) { + log.debug(name + " Loading Trust Keystore from : " + location); + } + + trustStore.load(fis, storePassword.toCharArray()); + trustStoreHolder.setClientTrustStore(trustStore); + } else { + trustStore = trustStoreHolder.getClientTrustStore(); } - trustStore.load(fis, storePassword.toCharArray()); TrustManagerFactory trustManagerfactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); trustManagerfactory.init(trustStore); trustManagers = trustManagerfactory.getTrustManagers(); - } catch (GeneralSecurityException gse) { log.error(name + " Error loading Key store : " + location, gse); throw new AxisFault("Error loading Key store : " + location, gse); @@ -424,9 +429,9 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE keyStoreElt.getFirstChildWithName(new QName("Password"))); String keyPassword = SecureVaultValueReader.getSecureVaultValue(secretResolver, keyStoreElt.getFirstChildWithName(new QName("KeyPassword"))); - - try (FileInputStream fis = new FileInputStream(location)) { - KeyStore keyStore = KeyStore.getInstance(type); + + try (FileInputStream fis = new FileInputStream(location)) { + KeyStore keyStore = KeyStore.getInstance(type); if (log.isDebugEnabled()) { log.debug(name + " Loading Identity Keystore from : " + location); } @@ -443,7 +448,7 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE } catch (IOException ioe) { log.error(name + " Error opening Keystore : " + location, ioe); throw new AxisFault("Error opening Keystore : " + location, ioe); - } + } } if (trustStoreElt != null) { @@ -451,31 +456,35 @@ private SSLContext createSSLContext(OMElement keyStoreElt, OMElement trustStoreE log.warn(name + " Ignoring novalidatecert parameter since a truststore has been specified"); } + KeyStore trustStore; String location = trustStoreElt.getFirstChildWithName(new QName("Location")).getText(); - String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText(); - String storePassword = SecureVaultValueReader - .getSecureVaultValue(secretResolver, trustStoreElt.getFirstChildWithName(new QName("Password"))); - + try (FileInputStream fis = new FileInputStream(location)) { - KeyStore trustStore = KeyStore.getInstance(type); - - if (log.isDebugEnabled()) { - log.debug(name + " Loading Trust Keystore from : " + location); + if (trustStoreHolder.getClientTrustStore() == null) { + String type = trustStoreElt.getFirstChildWithName(new QName("Type")).getText(); + String storePassword = SecureVaultValueReader.getSecureVaultValue(secretResolver, + trustStoreElt.getFirstChildWithName(new QName("Password"))); + trustStore = KeyStore.getInstance(type); + if (log.isDebugEnabled()) { + log.debug(name + " Loading Trust Keystore from : " + location); + } + trustStore.load(fis, storePassword.toCharArray()); + trustStoreHolder.setClientTrustStore(trustStore); + } else { + trustStore = trustStoreHolder.getClientTrustStore(); } - trustStore.load(fis, storePassword.toCharArray()); TrustManagerFactory trustManagerfactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); trustManagerfactory.init(trustStore); trustManagers = trustManagerfactory.getTrustManagers(); - } catch (GeneralSecurityException gse) { log.error(name + " Error loading Key store : " + location, gse); throw new AxisFault("Error loading Key store : " + location, gse); } catch (IOException ioe) { log.error(name + " Error opening Key store : " + location, ioe); throw new AxisFault("Error opening Key store : " + location, ioe); - } + } } else if (novalidatecert) { if (log.isWarnEnabled()) { log.warn(name + " Server certificate validation (trust) has been disabled. " + diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java index fd4a9fe133..483d5b56ee 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java @@ -41,6 +41,13 @@ import org.wso2.securevault.SecretResolver; import org.wso2.securevault.SecretResolverFactory; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; +import javax.xml.namespace.QName; import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; @@ -55,14 +62,6 @@ import java.util.Locale; import java.util.Map; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509KeyManager; -import javax.xml.namespace.QName; - public class ServerConnFactoryBuilder { private final Log log = LogFactory.getLog(ServerConnFactoryBuilder.class); @@ -90,13 +89,13 @@ public ServerConnFactoryBuilder(final TransportInDescription transportIn, final } protected SSLContextDetails createSSLContext( - final OMElement keyStoreEl, - final OMElement trustStoreEl, - final OMElement cientAuthEl, - final OMElement httpsProtocolsEl, - final OMElement preferredCiphersEl, - final RevocationVerificationManager verificationManager, - final String sslProtocol) throws AxisFault { + final OMElement keyStoreEl, + final OMElement trustStoreEl, + final OMElement cientAuthEl, + final OMElement httpsProtocolsEl, + final OMElement preferredCiphersEl, + final RevocationVerificationManager verificationManager, + final String sslProtocol) throws AxisFault { SecretResolver secretResolver; if (configurationContext != null && configurationContext.getAxisConfiguration() != null) { @@ -183,25 +182,38 @@ protected SSLContextDetails createSSLContext( } if (trustStoreEl != null) { - String location = getValueOfElementWithLocalName(trustStoreEl, "Location"); - String type = getValueOfElementWithLocalName(trustStoreEl, "Type"); - OMElement storePasswordEl = trustStoreEl.getFirstChildWithName(new QName("Password")); - if (storePasswordEl == null) { - throw new AxisFault("Cannot proceed because Password element is missing in TrustStore"); - } - String storePassword = SecureVaultValueReader.getSecureVaultValue(secretResolver, storePasswordEl); + TrustStoreHolder trustStoreHolder = TrustStoreHolder.getInstance(); FileInputStream fis = null; + String location = getValueOfElementWithLocalName(trustStoreEl, "Location"); + KeyStore trustStore; + try { - KeyStore trustStore = KeyStore.getInstance(type); - fis = new FileInputStream(location); - if (log.isDebugEnabled()) { - log.debug(name + " Loading Trust Keystore from : " + location); + if (trustStoreHolder.getClientTrustStore() == null) { + + String type = getValueOfElementWithLocalName(trustStoreEl, "Type"); + OMElement storePasswordEl = trustStoreEl.getFirstChildWithName(new QName("Password")); + + if (storePasswordEl == null) { + throw new AxisFault("Cannot proceed because Password element is missing in TrustStore"); + } + + String storePassword = SecureVaultValueReader.getSecureVaultValue(secretResolver, storePasswordEl); + trustStore = KeyStore.getInstance(type); + fis = new FileInputStream(location); + + if (log.isDebugEnabled()) { + log.debug(name + " Loading Trust Keystore from : " + location); + } + + trustStore.load(fis, storePassword.toCharArray()); + trustStoreHolder.setClientTrustStore(trustStore); + } else { + trustStore = trustStoreHolder.getClientTrustStore(); } - trustStore.load(fis, storePassword.toCharArray()); TrustManagerFactory trustManagerfactory = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); + TrustManagerFactory.getDefaultAlgorithm()); trustManagerfactory.init(trustStore); trustManagers = trustManagerfactory.getTrustManagers(); diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java new file mode 100644 index 0000000000..7f59f0b162 --- /dev/null +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.transport.nhttp.config; + +import java.security.KeyStore; + +/** + * A data holder class to store the client trust store. + */ +public class TrustStoreHolder { + + private static volatile TrustStoreHolder instance; + private KeyStore clientTrustStore; + + private TrustStoreHolder() {} + + public static TrustStoreHolder getInstance() { + + if (instance == null) { + synchronized (TrustStoreHolder.class) { + if (instance == null) { + instance = new TrustStoreHolder(); + } + } + } + return instance; + } + + public KeyStore getClientTrustStore() { + return clientTrustStore; + } + + public void setClientTrustStore(KeyStore clientTrustStore) { + this.clientTrustStore = clientTrustStore; + } + + /** + * Reset the instance. + */ + public static void resetInstance() { + + instance = null; + } +} diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java index 1d4ddf2a6a..b69cb80abd 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java @@ -47,8 +47,6 @@ import org.apache.axis2.transport.TransportListener; import org.apache.axis2.transport.base.BaseConstants; import org.apache.axis2.transport.base.BaseUtils; -import org.apache.axis2.transport.base.ManagementSupport; -import org.apache.axis2.transport.base.TransportMBeanSupport; import org.apache.axis2.transport.base.threads.NativeThreadFactory; import org.apache.axis2.transport.base.threads.WorkerPool; import org.apache.axis2.transport.base.tracker.AxisServiceFilter; @@ -62,8 +60,10 @@ import org.apache.http.nio.reactor.IOReactorException; import org.apache.http.nio.reactor.IOReactorExceptionHandler; import org.apache.http.params.HttpConnectionParams; +import org.apache.synapse.transport.certificatevalidation.cache.CertCache; import org.apache.synapse.transport.http.conn.Scheme; import org.apache.synapse.transport.http.conn.ServerConnFactory; +import org.apache.synapse.transport.nhttp.config.TrustStoreHolder; import org.apache.synapse.transport.nhttp.config.ServerConnFactoryBuilder; import org.apache.synapse.transport.passthru.config.PassThroughConfiguration; import org.apache.synapse.transport.passthru.config.SourceConfiguration; @@ -679,9 +679,10 @@ public void reloadDynamicSSLConfig(TransportInDescription transportInDescription Parameter profilePathParam = transportInDescription.getParameter("dynamicSSLProfilesConfig"); if (oldParameter != null && profilePathParam != null) { + CertCache.resetCache(); + TrustStoreHolder.resetInstance(); transportInDescription.removeParameter(oldParameter); this.reloadSpecificEndPoints(transportInDescription); } } - } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java index 3af961c03f..7379363af3 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java @@ -47,12 +47,14 @@ import org.apache.http.nio.reactor.IOReactorExceptionHandler; import org.apache.http.protocol.HTTP; import org.apache.synapse.commons.CorrelationConstants; +import org.apache.synapse.transport.certificatevalidation.cache.CertCache; import org.apache.synapse.transport.exceptions.InvalidConfigurationException; import org.apache.synapse.transport.http.conn.ClientConnFactory; import org.apache.synapse.transport.http.conn.ProxyConfig; import org.apache.synapse.transport.http.conn.Scheme; import org.apache.synapse.transport.nhttp.NhttpConstants; import org.apache.synapse.transport.nhttp.config.ClientConnFactoryBuilder; +import org.apache.synapse.transport.nhttp.config.TrustStoreHolder; import org.apache.synapse.transport.nhttp.config.ProxyConfigBuilder; import org.apache.synapse.transport.nhttp.util.MessageFormatterDecoratorFactory; import org.apache.synapse.transport.nhttp.util.NhttpUtil; @@ -557,7 +559,7 @@ public void submitResponse(MessageContext msgContext) ProtocolState state = SourceContext.getState(conn); if (state != null && state.compareTo(ProtocolState.REQUEST_DONE) <= 0) { // start sending the response if we - + boolean noEntityBodyResponse = false; if (noEntityBody != null && Boolean.TRUE == noEntityBody && pipe != null) { @@ -567,7 +569,7 @@ public void submitResponse(MessageContext msgContext) out.close(); noEntityBodyResponse = true; } - + if (!noEntityBodyResponse && msgContext.isPropertyTrue(PassThroughConstants.MESSAGE_BUILDER_INVOKED) && pipe != null) { OutputStream out = pipe.getOutputStream(); /*if (msgContext.isPropertyTrue(NhttpConstants.SC_ACCEPTED)) { @@ -705,6 +707,8 @@ private void handleException(String msg) throws AxisFault { public void reloadDynamicSSLConfig(TransportOutDescription transport) throws AxisFault { log.info("PassThroughHttpSender reloading SSL Config.."); try { + CertCache.resetCache(); + TrustStoreHolder.resetInstance(); ClientConnFactoryBuilder connFactoryBuilder = initConnFactoryBuilder(transport, this.configurationContext); connFactory = connFactoryBuilder.createConnFactory(targetConfiguration.getHttpParams()); diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java index cadb9e499b..406a7a2d30 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/util/ConfigurationBuilderUtil.java @@ -21,13 +21,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; import java.util.Properties; public class ConfigurationBuilderUtil { @@ -177,29 +170,4 @@ public static String getStringProperty(String name, String def, Properties props return val == null ? def : val; } - - /** - * Returns the keystore of the given file path. - * - * @param keyStoreFilePath the keystore file path - * @param keyStorePassword the keystore password - * @param keyStoreType the keystore type - * @return KeyStore - * @throws KeyStoreException On error while creating keystore - */ - public static KeyStore getKeyStore(String keyStoreFilePath, String keyStorePassword, String keyStoreType) - throws KeyStoreException { - - String file = new File(keyStoreFilePath).getAbsolutePath(); - try (FileInputStream keyStoreFileInputStream = new FileInputStream(file)) { - KeyStore keyStore = KeyStore.getInstance(keyStoreType); - keyStore.load(keyStoreFileInputStream, keyStorePassword.toCharArray()); - return keyStore; - } catch (IOException | NoSuchAlgorithmException | CertificateException e) { - String errorMessage = String.format("Keystore file does not exist in the path as configured " + - "in '%s' property.", keyStoreFilePath); - throw new KeyStoreException(errorMessage); - } - } - } From 9ceda59358a47305771e6fc734d3031c27f876b0 Mon Sep 17 00:00:00 2001 From: akila94 Date: Wed, 3 Jan 2024 10:20:47 +0530 Subject: [PATCH 03/10] Add expiry validation --- ...va => CertificateVerificationManager.java} | 46 ++++++++++++++----- .../http/conn/ClientSSLSetupHandler.java | 6 +-- .../http/conn/ServerSSLSetupHandler.java | 15 ++++-- .../config/ClientConnFactoryBuilder.java | 6 +-- .../config/ServerConnFactoryBuilder.java | 17 ++++--- .../core/ssl/SSLServerConnFactoryBuilder.java | 7 ++- 6 files changed, 63 insertions(+), 34 deletions(-) rename modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/{RevocationVerificationManager.java => CertificateVerificationManager.java} (86%) diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java similarity index 86% rename from modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java rename to modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java index 683df58258..3ff125fd6d 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java @@ -36,6 +36,8 @@ import java.security.NoSuchProviderException; import java.security.SignatureException; import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Enumeration; @@ -45,14 +47,14 @@ * Manager class responsible for verifying certificates. This class will use the available verifiers according to * a predefined policy. */ -public class RevocationVerificationManager { +public class CertificateVerificationManager { private int cacheSize = Constants.CACHE_DEFAULT_ALLOCATED_SIZE; private int cacheDelayMins = Constants.CACHE_DEFAULT_DELAY_MINS; private boolean isFullCertChainValidationEnabled = false; - private static final Log log = LogFactory.getLog(RevocationVerificationManager.class); + private static final Log log = LogFactory.getLog(CertificateVerificationManager.class); - public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins) { + public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins) { if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { @@ -64,8 +66,8 @@ public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDe } } - public RevocationVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins, - boolean isFullCertChainValidationEnabled) { + public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins, + boolean isFullCertChainValidationEnabled) { if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { @@ -157,11 +159,8 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer } break; } catch (SignatureException | CertificateException | NoSuchAlgorithmException | - InvalidKeyException | - NoSuchProviderException e) { + InvalidKeyException | NoSuchProviderException e) { // Unable to verify the signature. Check with the next certificate. - //todo: change this to a debug log after testing. - log.error("Unable to verify the signature, checking with the next certificate..."); } } } else { @@ -171,8 +170,8 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer } catch (SignatureException | CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException e) { - // Unable to verify the signature. Check with the next certificate. - log.error("Signature not matching for alias validate with next cert"); + // Unable to verify the signature. + throw new CertificateVerificationException("Unable to verify the signature of the certificate."); } } } @@ -238,4 +237,29 @@ private X509Certificate[] convert(javax.security.cert.X509Certificate[] certs) } return certChain; } + + /** + * Checks whether a provided certificate is expired or not at the time it is validated. + * + * @param certificates + * @throws CertificateNotYetValidException + * @throws CertificateExpiredException + * @throws CertificateVerificationException + */ + public void isExpired(javax.security.cert.X509Certificate[] certificates) throws CertificateVerificationException { + + X509Certificate[] convertedCertificates = convert(certificates); + + for (X509Certificate cert : convertedCertificates) { + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + String msg = "Peer certificate is expired"; + throw new CertificateVerificationException(msg); + } catch (CertificateNotYetValidException e) { + String msg = "Peer certificate is not valid yet"; + throw new CertificateVerificationException(msg); + } + } + } } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java index 24977a7115..803be5cedd 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java @@ -33,7 +33,7 @@ import org.apache.http.nio.reactor.IOSession; import org.apache.http.nio.reactor.ssl.SSLSetupHandler; import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException; -import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager; +import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager; public class ClientSSLSetupHandler implements SSLSetupHandler { @@ -139,10 +139,10 @@ public void verify( }; private final X509HostnameVerifier hostnameVerifier; - private final RevocationVerificationManager verificationManager; + private final CertificateVerificationManager verificationManager; public ClientSSLSetupHandler(final X509HostnameVerifier hostnameVerifier, - final RevocationVerificationManager verificationManager) { + final CertificateVerificationManager verificationManager) { this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier : DEFAULT; this.verificationManager = verificationManager; } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java index a4bc324ce1..3152d8f054 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java @@ -21,27 +21,32 @@ import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; +import javax.security.cert.X509Certificate; import org.apache.http.nio.reactor.IOSession; import org.apache.http.nio.reactor.ssl.SSLSetupHandler; import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException; -import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager; +import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.util.Arrays; +import java.util.List; public class ServerSSLSetupHandler implements SSLSetupHandler { private final SSLClientAuth clientAuth; /** Enabled SSL handshake protocols (e.g. SSLv3, TLSv1) */ private final String[] httpsProtocols; - private RevocationVerificationManager verificationManager; + private CertificateVerificationManager verificationManager; /** Ciphers enabled in axis2.xml, enabled all if null*/ private final String[] preferredCiphers; public ServerSSLSetupHandler(final SSLClientAuth clientAuth, final String[] httpsProtocols, - final RevocationVerificationManager verificationManager, final String[] preferredCiphers) { + final CertificateVerificationManager verificationManager, final String[] preferredCiphers) { this.clientAuth = clientAuth; this.httpsProtocols = httpsProtocols; this.verificationManager = verificationManager; @@ -78,7 +83,9 @@ public void verify( if (verificationManager != null) { try { - verificationManager.verifyRevocationStatus(sslsession.getPeerCertificateChain()); + X509Certificate[] peerCertChain = sslsession.getPeerCertificateChain(); + verificationManager.isExpired(peerCertChain); + verificationManager.verifyRevocationStatus(peerCertChain); } catch (CertificateVerificationException e) { SocketAddress remoteAddress = iosession.getRemoteAddress(); String address; diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java index 44710be55a..bec88bfa25 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java @@ -31,7 +31,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.http.conn.ssl.X509HostnameVerifier; import org.apache.http.params.HttpParams; -import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager; +import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager; import org.apache.synapse.transport.exceptions.InvalidConfigurationException; import org.apache.synapse.transport.http.conn.ClientConnFactory; import org.apache.synapse.transport.http.conn.ClientSSLSetupHandler; @@ -129,7 +129,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault { final Parameter cvp = transportOut.getParameter("CertificateRevocationVerifier"); final String cvEnable = cvp != null ? cvp.getParameterElement().getAttribute(new QName("enable")).getAttributeValue() : null; - RevocationVerificationManager revocationVerifier = null; + CertificateVerificationManager revocationVerifier = null; if ("true".equalsIgnoreCase(cvEnable)) { String cacheSizeString = cvp.getParameterElement().getFirstChildWithName(new QName("CacheSize")).getText(); @@ -142,7 +142,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault { cacheDelay = new Integer(cacheDelayString); } catch (NumberFormatException e) { } - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay); + revocationVerifier = new CertificateVerificationManager(cacheSize, cacheDelay); } // Process HttpProtocols diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java index 483d5b56ee..2598138105 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java @@ -31,7 +31,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.http.HttpHost; import org.apache.http.params.HttpParams; -import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager; +import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager; import org.apache.synapse.transport.http.conn.SSLClientAuth; import org.apache.synapse.transport.http.conn.SSLContextDetails; import org.apache.synapse.transport.http.conn.ServerConnFactory; @@ -73,6 +73,7 @@ public class ServerConnFactoryBuilder { protected SSLContextDetails ssl; private Map sslByIPMap = null; private ConfigurationContext configurationContext; + CertificateVerificationManager certificateVerifier = null; public ServerConnFactoryBuilder(final TransportInDescription transportIn, final HttpHost host, ConfigurationContext configurationContext) { @@ -94,7 +95,7 @@ protected SSLContextDetails createSSLContext( final OMElement cientAuthEl, final OMElement httpsProtocolsEl, final OMElement preferredCiphersEl, - final RevocationVerificationManager verificationManager, + final CertificateVerificationManager verificationManager, final String sslProtocol) throws AxisFault { SecretResolver secretResolver; @@ -114,7 +115,7 @@ protected SSLContextDetails createSSLContext( final OMElement cientAuthEl, final OMElement httpsProtocolsEl, final OMElement preferredCiphersEl, - final RevocationVerificationManager verificationManager, + final CertificateVerificationManager verificationManager, final String sslProtocol, final SecretResolver secretResolver) throws AxisFault { KeyManager[] keymanagers = null; @@ -307,7 +308,6 @@ public ServerConnFactoryBuilder parseSSL() throws AxisFault { final Parameter cvp = transportIn.getParameter("CertificateRevocationVerifier"); final String cvEnable = cvp != null ? cvp.getParameterElement().getAttribute(new QName("enable")).getAttributeValue() : null; - RevocationVerificationManager revocationVerifier = null; if ("true".equalsIgnoreCase(cvEnable)) { String cacheSizeString = cvp.getParameterElement().getFirstChildWithName(new QName("CacheSize")).getText(); @@ -332,12 +332,12 @@ public ServerConnFactoryBuilder parseSSL() throws AxisFault { isFullCertChainValidationEnabled = false; } - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, + certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay, isFullCertChainValidationEnabled); } ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, preferredCiphersEl, - revocationVerifier, sslProtocol); + certificateVerifier, sslProtocol); return this; } @@ -351,7 +351,6 @@ public ServerConnFactoryBuilder parseMultiProfileSSL() throws AxisFault { OMElement profilesEl = profileParam.getParameterElement(); SecretResolver secretResolver = SecretResolverFactory.create(profilesEl, true); Iterator profiles = profilesEl.getChildrenWithName(new QName("profile")); - RevocationVerificationManager revocationVerifier = null; while (profiles.hasNext()) { OMElement profileEl = (OMElement) profiles.next(); @@ -406,12 +405,12 @@ public ServerConnFactoryBuilder parseMultiProfileSSL() throws AxisFault { isFullCertChainValidationEnabled = false; } - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, + certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay, isFullCertChainValidationEnabled); } SSLContextDetails ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, - preferredCiphersEl, revocationVerifier, sslProtocol, secretResolver); + preferredCiphersEl, certificateVerifier, sslProtocol, secretResolver); if (sslByIPMap == null) { sslByIPMap = new HashMap(); } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java index 4b552bd799..8ea5433d4f 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/core/ssl/SSLServerConnFactoryBuilder.java @@ -19,12 +19,11 @@ import org.apache.axiom.om.OMElement; import org.apache.axis2.AxisFault; -import org.apache.axis2.description.Parameter; import org.apache.axis2.description.TransportInDescription; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpHost; -import org.apache.synapse.transport.certificatevalidation.RevocationVerificationManager; +import org.apache.synapse.transport.certificatevalidation.CertificateVerificationManager; import org.apache.synapse.transport.nhttp.config.ServerConnFactoryBuilder; import javax.xml.namespace.QName; @@ -46,7 +45,7 @@ public ServerConnFactoryBuilder parseSSL(OMElement keyStoreEl, OMElement trustSt AxisFault { final String cvEnable = cvp != null ? cvp.getAttribute(new QName("enable")).getAttributeValue() : null; - RevocationVerificationManager revocationVerifier = null; + CertificateVerificationManager revocationVerifier = null; if ("true".equalsIgnoreCase(cvEnable)) { Iterator iterator = cvp.getChildElements(); @@ -70,7 +69,7 @@ public ServerConnFactoryBuilder parseSSL(OMElement keyStoreEl, OMElement trustSt } catch (NumberFormatException e) { log.error("Please specify correct Integer numbers for CacheDelay and CacheSize"); } - revocationVerifier = new RevocationVerificationManager(cacheSize, cacheDelay, true); + revocationVerifier = new CertificateVerificationManager(cacheSize, cacheDelay); } ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, preferredCiphers, revocationVerifier, From 6bb0c86ac614ec6159b498861397b20dc7279224 Mon Sep 17 00:00:00 2001 From: akila94 Date: Thu, 4 Jan 2024 09:08:27 +0530 Subject: [PATCH 04/10] Format code --- .../certificatevalidation/cache/CertCache.java | 12 ++++++------ .../nhttp/config/ClientConnFactoryBuilder.java | 6 +++--- .../conf/vfs-move-failed-records.properties | 4 ++++ 3 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java index 71a483539d..eed0a4801c 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java @@ -35,8 +35,8 @@ public class CertCache implements ManageableCache { private static volatile CertCache cache; - private static volatile Map hashMap = new ConcurrentHashMap(); - private static volatile Iterator> iterator = hashMap.entrySet().iterator(); + private static volatile Map hashMap = new ConcurrentHashMap(); + private static volatile Iterator> iterator = hashMap.entrySet().iterator(); private static volatile CacheManager cacheManager; private static final Log log = LogFactory.getLog(CertCache.class); @@ -74,7 +74,7 @@ public void init(int size, int delay) { } public synchronized X509Certificate getCacheValue(String serialNumber) { - CertCache.TempCacheValue cacheValue = hashMap.get(serialNumber); + CertCacheValue cacheValue = hashMap.get(serialNumber); if (cacheValue != null) { return cacheValue.getValue(); } else @@ -112,7 +112,7 @@ public static void resetCache() { } public synchronized void setCacheValue(String serialNumber, X509Certificate cert) { - CertCache.TempCacheValue cacheValue = new CertCache.TempCacheValue(serialNumber, cert); + CertCacheValue cacheValue = new CertCacheValue(serialNumber, cert); if (log.isDebugEnabled()) { log.debug("Before set - HashMap size " + hashMap.size()); @@ -137,13 +137,13 @@ public synchronized void removeCacheValue(String serialNumber) { /** * This is the wrapper class of the actual cache value which is a X509CRL. */ - private class TempCacheValue implements ManageableCacheValue { + private class CertCacheValue implements ManageableCacheValue { private final String serialNumber; private final X509Certificate issuerCertificate; private final long timeStamp = System.currentTimeMillis(); - public TempCacheValue(String serialNumber, X509Certificate issuerCertificate) { + public CertCacheValue(String serialNumber, X509Certificate issuerCertificate) { this.serialNumber = serialNumber; this.issuerCertificate = issuerCertificate; diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java index bec88bfa25..5495ae9fc2 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ClientConnFactoryBuilder.java @@ -129,7 +129,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault { final Parameter cvp = transportOut.getParameter("CertificateRevocationVerifier"); final String cvEnable = cvp != null ? cvp.getParameterElement().getAttribute(new QName("enable")).getAttributeValue() : null; - CertificateVerificationManager revocationVerifier = null; + CertificateVerificationManager certificateVerifier = null; if ("true".equalsIgnoreCase(cvEnable)) { String cacheSizeString = cvp.getParameterElement().getFirstChildWithName(new QName("CacheSize")).getText(); @@ -142,7 +142,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault { cacheDelay = new Integer(cacheDelayString); } catch (NumberFormatException e) { } - revocationVerifier = new CertificateVerificationManager(cacheSize, cacheDelay); + certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay); } // Process HttpProtocols @@ -163,7 +163,7 @@ public ClientConnFactoryBuilder parseSSL() throws AxisFault { } // Initiated separately to cater setting https protocols - ClientSSLSetupHandler clientSSLSetupHandler = new ClientSSLSetupHandler(hostnameVerifier, revocationVerifier); + ClientSSLSetupHandler clientSSLSetupHandler = new ClientSSLSetupHandler(hostnameVerifier, certificateVerifier); if (null != httpsProtocols) { clientSSLSetupHandler.setHttpsProtocols(httpsProtocols); diff --git a/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties b/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties new file mode 100644 index 0000000000..ccabbbabad --- /dev/null +++ b/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties @@ -0,0 +1,4 @@ +t-0-1704257728276.txt 03/01/2024/ 10:25:28 +in 03/01/2024/ 13:29:16 +t-0-1704268757607.txt 03/01/2024/ 13:29:17 +t-0-1704336995522.txt 04/01/2024/ 08:26:35 From be0c832d3e96f046cb2c7007019e7be31fa379d9 Mon Sep 17 00:00:00 2001 From: akila94 Date: Thu, 4 Jan 2024 09:19:42 +0530 Subject: [PATCH 05/10] Format code --- .../transport/certificatevalidation/cache/CertCache.java | 7 +------ .../synapse/transport/nhttp/config/TrustStoreHolder.java | 2 ++ .../vfs/repository/conf/vfs-move-failed-records.properties | 4 ---- 3 files changed, 3 insertions(+), 10 deletions(-) delete mode 100644 modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java index eed0a4801c..4dbd3d847a 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java @@ -84,8 +84,6 @@ public synchronized X509Certificate getCacheValue(String serialNumber) { @Override public ManageableCacheValue getNextCacheValue() { - //changes to the map are reflected on the keySet. And its iterator is weakly consistent. so will never - //throw concurrent modification exception. if (iterator.hasNext()) { return hashMap.get(iterator.next().getKey()); } else { @@ -135,7 +133,7 @@ public synchronized void removeCacheValue(String serialNumber) { } /** - * This is the wrapper class of the actual cache value which is a X509CRL. + * This is the wrapper class of the actual cache value. */ private class CertCacheValue implements ManageableCacheValue { @@ -159,9 +157,6 @@ public String getKey() { return serialNumber; } - /** - * CRL has a validity period. We can reuse a downloaded CRL within that period. - */ public boolean isValid() { // Will be always return true since we only set defined data. diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java index 7f59f0b162..697dd6eba6 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/TrustStoreHolder.java @@ -43,10 +43,12 @@ public static TrustStoreHolder getInstance() { } public KeyStore getClientTrustStore() { + return clientTrustStore; } public void setClientTrustStore(KeyStore clientTrustStore) { + this.clientTrustStore = clientTrustStore; } diff --git a/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties b/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties deleted file mode 100644 index ccabbbabad..0000000000 --- a/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties +++ /dev/null @@ -1,4 +0,0 @@ -t-0-1704257728276.txt 03/01/2024/ 10:25:28 -in 03/01/2024/ 13:29:16 -t-0-1704268757607.txt 03/01/2024/ 13:29:17 -t-0-1704336995522.txt 04/01/2024/ 08:26:35 From 56c0e4fd0233b5832e1706a3644b65074a8827c1 Mon Sep 17 00:00:00 2001 From: akila94 Date: Thu, 4 Jan 2024 11:19:37 +0530 Subject: [PATCH 06/10] Refactor method comment --- .../CertificateVerificationManager.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java index 3ff125fd6d..ed70bc8f5a 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java @@ -241,10 +241,8 @@ private X509Certificate[] convert(javax.security.cert.X509Certificate[] certs) /** * Checks whether a provided certificate is expired or not at the time it is validated. * - * @param certificates - * @throws CertificateNotYetValidException - * @throws CertificateExpiredException - * @throws CertificateVerificationException + * @param certificates array of certificates needs to be validated + * @throws CertificateVerificationException if one of the certs are expired, this exception will be thrown */ public void isExpired(javax.security.cert.X509Certificate[] certificates) throws CertificateVerificationException { From c173c834510ff31cacaa75d56fcd1bd7deb2a711 Mon Sep 17 00:00:00 2001 From: akila94 Date: Fri, 5 Jan 2024 14:29:58 +0530 Subject: [PATCH 07/10] Fix code review comments --- .../CertificateVerificationManager.java | 73 ++++++++++++------- .../cache/CertCache.java | 21 +----- .../CertificatePathValidator.java | 1 + .../http/conn/ClientSSLSetupHandler.java | 2 +- .../http/conn/ServerSSLSetupHandler.java | 8 +- .../config/ServerConnFactoryBuilder.java | 38 ++++++++-- .../passthru/PassThroughHttpListener.java | 2 - .../PassThroughHttpMultiSSLListener.java | 4 + .../passthru/PassThroughHttpSender.java | 2 - 9 files changed, 85 insertions(+), 66 deletions(-) diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java index ed70bc8f5a..100767e1ef 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java @@ -51,7 +51,8 @@ public class CertificateVerificationManager { private int cacheSize = Constants.CACHE_DEFAULT_ALLOCATED_SIZE; private int cacheDelayMins = Constants.CACHE_DEFAULT_DELAY_MINS; - private boolean isFullCertChainValidationEnabled = false; + private boolean isFullCertChainValidationEnabled = true; + private boolean isCertExpiryValidationEnabled = false; private static final Log log = LogFactory.getLog(CertificateVerificationManager.class); public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins) { @@ -67,7 +68,8 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD } public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins, - boolean isFullCertChainValidationEnabled) { + boolean isFullCertChainValidationEnabled, + boolean isCertExpiryValidationEnabled) { if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { @@ -78,6 +80,7 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD this.cacheDelayMins = cacheDelayMins; } this.isFullCertChainValidationEnabled = isFullCertChainValidationEnabled; + this.isCertExpiryValidationEnabled = isCertExpiryValidationEnabled; } /** @@ -93,7 +96,7 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD * @param peerCertificates javax.security.cert.X509Certificate[] array of peer certificate chain from peer/client. * @throws CertificateVerificationException */ - public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCertificates) + public void verifyCertificateValidity(javax.security.cert.X509Certificate[] peerCertificates) throws CertificateVerificationException { X509Certificate[] convertedCertificates = convert(peerCertificates); @@ -123,7 +126,6 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer // Get cert cache and initialize it CertCache certCache = CertCache.getCache(); - certCache.init(cacheSize,cacheDelayMins); if (certCache.getCacheValue(peerCert.getSerialNumber().toString()) == null) { @@ -134,20 +136,22 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer } while (aliases.hasMoreElements()) { + + alias = aliases.nextElement(); try { - alias = aliases.nextElement(); - try { - issuerCert = (X509Certificate) trustStore.getCertificate(alias); - } catch (KeyStoreException e) { - throw new CertificateVerificationException("Unable to read the certificate from " + - "truststore with the alias: " + alias, e); - } + issuerCert = (X509Certificate) trustStore.getCertificate(alias); + } catch (KeyStoreException e) { + throw new CertificateVerificationException("Unable to read the certificate from " + + "truststore with the alias: " + alias, e); + } - if (issuerCert == null) { - throw new CertificateVerificationException("Issuer certificate not found in truststore"); - } + if (issuerCert == null) { + throw new CertificateVerificationException("Issuer certificate not found in truststore"); + } + try { peerCert.verify(issuerCert.getPublicKey()); + log.debug("Valid issuer certificate found in the client truststore. Caching.."); // Store the valid issuer cert in cache for future use @@ -160,7 +164,7 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer break; } catch (SignatureException | CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException e) { - // Unable to verify the signature. Check with the next certificate. + // Unable to verify the signature. Check with the next certificate in the next loop traversal. } } } else { @@ -188,16 +192,30 @@ public void verifyRevocationStatus(javax.security.cert.X509Certificate[] peerCer for (RevocationVerifier verifier : verifiers) { try { if (isFullCertChainValidationEnabled) { + + if (isCertExpiryValidationEnabled) { + log.debug("Validating certificate chain for expiry"); + if (isExpired(convertedCertificates)) { + throw new CertificateVerificationException("One of the provided certificates are expired"); + } + } + log.debug("Doing full certificate chain validation"); CertificatePathValidator pathValidator = new CertificatePathValidator(convertedCertificates, verifier); pathValidator.validatePath(); log.info("Path verification Successful. Took " + (System.currentTimeMillis() - start) + " ms."); } else { - if (log.isDebugEnabled()) { - log.debug("Validating client certificate with the issuer certificate retrieved from" + - "the trust store"); + + if (isCertExpiryValidationEnabled) { + log.debug("Validating the client certificate for expiry"); + if (isExpired(convertedCertificates)) { + throw new CertificateVerificationException("The provided certificate is expired"); + } } + + log.debug("Validating client certificate with the issuer certificate retrieved from" + + "the trust store"); verifier.checkRevocationStatus(peerCert, issuerCert); } return; @@ -241,23 +259,22 @@ private X509Certificate[] convert(javax.security.cert.X509Certificate[] certs) /** * Checks whether a provided certificate is expired or not at the time it is validated. * - * @param certificates array of certificates needs to be validated - * @throws CertificateVerificationException if one of the certs are expired, this exception will be thrown + * @param certificates certificates to be validated for expiry + * @return true if one of the certs are expired, false otherwise */ - public void isExpired(javax.security.cert.X509Certificate[] certificates) throws CertificateVerificationException { - - X509Certificate[] convertedCertificates = convert(certificates); + public boolean isExpired(X509Certificate[] certificates) { - for (X509Certificate cert : convertedCertificates) { + for (X509Certificate cert : certificates) { try { cert.checkValidity(); } catch (CertificateExpiredException e) { - String msg = "Peer certificate is expired"; - throw new CertificateVerificationException(msg); + log.error("Peer certificate is expired"); + return true; } catch (CertificateNotYetValidException e) { - String msg = "Peer certificate is not valid yet"; - throw new CertificateVerificationException(msg); + log.error("Peer certificate is not valid yet"); + return true; } } + return false; } } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java index 4dbd3d847a..9ada86e88d 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/cache/CertCache.java @@ -21,6 +21,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.commons.jmx.MBeanRegistrar; +import org.apache.synapse.transport.certificatevalidation.Constants; import java.security.cert.X509Certificate; import java.util.Iterator; @@ -49,30 +50,14 @@ public static CertCache getCache() { synchronized (CertCache.class) { if (cache == null) { cache = new CertCache(); + cacheManager = new CacheManager(cache, Constants.CACHE_DEFAULT_ALLOCATED_SIZE, + Constants.CACHE_DEFAULT_DELAY_MINS); } } } return cache; } - /** - * This initialize the Cache with a CacheManager. If this method is called, a cache manager will not be used. - * - * @param size max size of the cache - * @param delay defines how frequently the CacheManager will be started - */ - public void init(int size, int delay) { - if (cacheManager == null) { - synchronized (CertCache.class) { - if (cacheManager == null) { - cacheManager = new CacheManager(cache, size, delay); - CacheController mbean = new CacheController(cache,cacheManager); - MBeanRegistrar.getInstance().registerMBean(mbean, "CacheController", "CertCacheController"); - } - } - } - } - public synchronized X509Certificate getCacheValue(String serialNumber) { CertCacheValue cacheValue = hashMap.get(serialNumber); if (cacheValue != null) { diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java index b041a7314d..b6335f88a4 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/pathvalidation/CertificatePathValidator.java @@ -22,6 +22,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.synapse.transport.certificatevalidation.*; +import java.lang.reflect.InvocationTargetException; import java.security.*; import java.security.cert.X509Certificate; import java.util.List; diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java index 803be5cedd..e5c94d91f6 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ClientSSLSetupHandler.java @@ -184,7 +184,7 @@ public void verify(IOSession iosession, SSLSession sslsession) throws SSLExcepti if (verificationManager!=null) { try { - verificationManager.verifyRevocationStatus(sslsession.getPeerCertificateChain()); + verificationManager.verifyCertificateValidity(sslsession.getPeerCertificateChain()); } catch (CertificateVerificationException e) { throw new SSLException("Certificate Chain Validation failed for host : " + address, e); } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java index 3152d8f054..bb4e7c08d6 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/http/conn/ServerSSLSetupHandler.java @@ -31,10 +31,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.util.Arrays; -import java.util.List; public class ServerSSLSetupHandler implements SSLSetupHandler { @@ -83,9 +79,7 @@ public void verify( if (verificationManager != null) { try { - X509Certificate[] peerCertChain = sslsession.getPeerCertificateChain(); - verificationManager.isExpired(peerCertChain); - verificationManager.verifyRevocationStatus(peerCertChain); + verificationManager.verifyCertificateValidity(sslsession.getPeerCertificateChain()); } catch (CertificateVerificationException e) { SocketAddress remoteAddress = iosession.getRemoteAddress(); String address; diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java index 2598138105..b9b4b0018e 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/config/ServerConnFactoryBuilder.java @@ -324,16 +324,23 @@ public ServerConnFactoryBuilder parseSSL() throws AxisFault { // Checking whether the full certificate chain validation is enabled or not. boolean isFullCertChainValidationEnabled = true; - OMElement isFullCertChainValidationConfig = cvp.getParameterElement() + boolean isCertExpiryValidationEnabled = false; + OMElement fullCertChainValidationConfig = cvp.getParameterElement() .getFirstChildWithName(new QName("FullChainValidation")); + OMElement certExpiryValidationConfig = cvp.getParameterElement() + .getFirstChildWithName(new QName("ExpiryValidation")); - if (isFullCertChainValidationConfig != null - && StringUtils.equals("false", isFullCertChainValidationConfig.getText())) { + if (fullCertChainValidationConfig != null + && StringUtils.equals("false", fullCertChainValidationConfig.getText())) { isFullCertChainValidationEnabled = false; } + if (certExpiryValidationConfig != null && StringUtils.equals("true", certExpiryValidationConfig.getText())) { + isCertExpiryValidationEnabled = true; + } + certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay, - isFullCertChainValidationEnabled); + isFullCertChainValidationEnabled, isCertExpiryValidationEnabled); } ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, preferredCiphersEl, @@ -397,16 +404,31 @@ public ServerConnFactoryBuilder parseMultiProfileSSL() throws AxisFault { } boolean isFullCertChainValidationEnabled = true; - OMElement isFullCertChainValidationConfig = revocationVerifierConfig + boolean isCertExpiryValidationEnabled = false; + + OMElement fullCertChainValidationConfig = revocationVerifierConfig .getFirstChildWithName(new QName("FullChainValidation")); - if (isFullCertChainValidationConfig != null - && StringUtils.equals("false", isFullCertChainValidationConfig.getText())) { + OMElement certExpiryValidationConfig = revocationVerifierConfig + .getFirstChildWithName(new QName("ExpiryValidation")); + + if (fullCertChainValidationConfig != null + && StringUtils.equals("false", fullCertChainValidationConfig.getText())) { + isFullCertChainValidationEnabled = false; + } + + if (certExpiryValidationConfig != null + && StringUtils.equals("true", certExpiryValidationConfig.getText())) { + isCertExpiryValidationEnabled = true; + } + + if (fullCertChainValidationConfig != null + && StringUtils.equals("false", fullCertChainValidationConfig.getText())) { isFullCertChainValidationEnabled = false; } certificateVerifier = new CertificateVerificationManager(cacheSize, cacheDelay, - isFullCertChainValidationEnabled); + isFullCertChainValidationEnabled, isCertExpiryValidationEnabled); } SSLContextDetails ssl = createSSLContext(keyStoreEl, trustStoreEl, clientAuthEl, httpsProtocolsEl, diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java index b69cb80abd..3e7f92c6d6 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpListener.java @@ -679,8 +679,6 @@ public void reloadDynamicSSLConfig(TransportInDescription transportInDescription Parameter profilePathParam = transportInDescription.getParameter("dynamicSSLProfilesConfig"); if (oldParameter != null && profilePathParam != null) { - CertCache.resetCache(); - TrustStoreHolder.resetInstance(); transportInDescription.removeParameter(oldParameter); this.reloadSpecificEndPoints(transportInDescription); } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java index 208b364178..406ae5a53b 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpMultiSSLListener.java @@ -5,10 +5,12 @@ import org.apache.axis2.description.ParameterInclude; import org.apache.axis2.description.TransportInDescription; import org.apache.http.HttpHost; +import org.apache.synapse.transport.certificatevalidation.cache.CertCache; import org.apache.synapse.transport.http.conn.Scheme; import org.apache.synapse.transport.nhttp.config.ServerConnFactoryBuilder; import org.apache.synapse.transport.dynamicconfigurations.ListenerProfileReloader; import org.apache.synapse.transport.dynamicconfigurations.SSLProfileLoader; +import org.apache.synapse.transport.nhttp.config.TrustStoreHolder; public class PassThroughHttpMultiSSLListener extends PassThroughHttpListener implements SSLProfileLoader{ @@ -39,6 +41,8 @@ protected ServerConnFactoryBuilder initConnFactoryBuilder(final TransportInDescr * @throws AxisFault */ public void reloadConfig(ParameterInclude transport) throws AxisFault { + CertCache.resetCache(); + TrustStoreHolder.resetInstance(); reloadDynamicSSLConfig((TransportInDescription) transport); } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java index 7379363af3..b977eb30a7 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/passthru/PassThroughHttpSender.java @@ -707,8 +707,6 @@ private void handleException(String msg) throws AxisFault { public void reloadDynamicSSLConfig(TransportOutDescription transport) throws AxisFault { log.info("PassThroughHttpSender reloading SSL Config.."); try { - CertCache.resetCache(); - TrustStoreHolder.resetInstance(); ClientConnFactoryBuilder connFactoryBuilder = initConnFactoryBuilder(transport, this.configurationContext); connFactory = connFactoryBuilder.createConnFactory(targetConfiguration.getHttpParams()); From a543877ee3b835d9c6b8da909b49701c49accf34 Mon Sep 17 00:00:00 2001 From: akila94 Date: Mon, 22 Jan 2024 11:48:30 +0530 Subject: [PATCH 08/10] Add warn log --- .../certificatevalidation/CertificateVerificationManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java index 100767e1ef..ceca801109 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java @@ -61,6 +61,8 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { this.cacheSize = cacheAllocatedSize; } + log.warn("The cache size is out of range. Hence, using the default cache size value of " + + Constants.CACHE_DEFAULT_ALLOCATED_SIZE + "."); if (cacheDelayMins != null && cacheDelayMins > Constants.CACHE_MIN_DELAY_MINS && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) { this.cacheDelayMins = cacheDelayMins; From 6671e3971d4341cc691d4558088b42f1e30ec40a Mon Sep 17 00:00:00 2001 From: akila94 Date: Tue, 23 Jan 2024 10:39:53 +0530 Subject: [PATCH 09/10] Fix PR comments --- .../CertificateVerificationManager.java | 14 +++++++------- .../certificatevalidation/crl/CRLCache.java | 3 ++- .../certificatevalidation/ocsp/OCSPCache.java | 7 +++++-- .../certificatevalidation/CRLVerifierTest.java | 3 +-- .../certificatevalidation/OCSPVerifierTest.java | 3 +-- .../RevocationVerificationTest.java | 6 ++---- .../conf/vfs-move-failed-records.properties | 1 + 7 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java index ceca801109..93ca51e710 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java @@ -67,6 +67,8 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) { this.cacheDelayMins = cacheDelayMins; } + log.warn("The cache delay is out of range. Hence, using the default cache delay value of " + + Constants.CACHE_DEFAULT_DELAY_MINS + "."); } public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins, @@ -81,6 +83,9 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) { this.cacheDelayMins = cacheDelayMins; } + log.warn("The cache delay is out of range. Hence, using the default cache delay value of " + + Constants.CACHE_DEFAULT_DELAY_MINS + "."); + this.isFullCertChainValidationEnabled = isFullCertChainValidationEnabled; this.isCertExpiryValidationEnabled = isCertExpiryValidationEnabled; } @@ -182,12 +187,8 @@ public void verifyCertificateValidity(javax.security.cert.X509Certificate[] peer } } - long start = System.currentTimeMillis(); - - OCSPCache ocspCache = OCSPCache.getCache(); - ocspCache.init(cacheSize, cacheDelayMins); - CRLCache crlCache = CRLCache.getCache(); - crlCache.init(cacheSize, cacheDelayMins); + OCSPCache ocspCache = OCSPCache.getCache(cacheSize, cacheDelayMins); + CRLCache crlCache = CRLCache.getCache(cacheSize, cacheDelayMins); RevocationVerifier[] verifiers = {new OCSPVerifier(ocspCache), new CRLVerifier(crlCache)}; @@ -206,7 +207,6 @@ public void verifyCertificateValidity(javax.security.cert.X509Certificate[] peer CertificatePathValidator pathValidator = new CertificatePathValidator(convertedCertificates, verifier); pathValidator.validatePath(); - log.info("Path verification Successful. Took " + (System.currentTimeMillis() - start) + " ms."); } else { if (isCertExpiryValidationEnabled) { diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java index 11db425524..2597960102 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/crl/CRLCache.java @@ -50,12 +50,13 @@ public class CRLCache implements ManageableCache { private CRLCache() { } - public static CRLCache getCache() { + public static CRLCache getCache(int cacheSize, int cacheDelayMins) { //Double checked locking if (cache == null) { synchronized (CRLCache.class) { if (cache == null) { cache = new CRLCache(); + cacheManager = new CacheManager(cache, cacheSize, cacheDelayMins); } } } diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java index 471323e6b3..cf904cd3f4 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/ocsp/OCSPCache.java @@ -22,6 +22,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.synapse.commons.jmx.MBeanRegistrar; import org.apache.synapse.transport.certificatevalidation.CertificateVerificationException; +import org.apache.synapse.transport.certificatevalidation.Constants; import org.apache.synapse.transport.certificatevalidation.cache.CacheController; import org.apache.synapse.transport.certificatevalidation.cache.CacheManager; import org.apache.synapse.transport.certificatevalidation.cache.ManageableCache; @@ -51,12 +52,14 @@ public class OCSPCache implements ManageableCache { private OCSPCache() {} - public static OCSPCache getCache() { + public static OCSPCache getCache(int cacheSize, int cacheDelayMins) { //Double checked locking if (cache == null) { synchronized (OCSPCache.class) { - if (cache == null) + if (cache == null) { cache = new OCSPCache(); + cacheManager = new CacheManager(cache, cacheSize, cacheDelayMins); + } } } return cache; diff --git a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java index 38d7964b8a..ec582f9dd7 100644 --- a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java +++ b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/CRLVerifierTest.java @@ -88,8 +88,7 @@ public void testRevokedCertificate() throws Exception { //Create a crl with fakeRevokedCertificate marked as revoked. X509CRL x509CRL = createCRL(fakeCACert, caKeyPair.getPrivate(), revokedSerialNumber); - CRLCache cache = CRLCache.getCache(); - cache.init(5, 5); + CRLCache cache = CRLCache.getCache(5, 5); cache.setCacheValue(crlDistributionPointUrl, x509CRL); CRLVerifier crlVerifier = new CRLVerifier(cache); diff --git a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java index 9c2299bb2b..9d4f0a01bd 100644 --- a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java +++ b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/OCSPVerifierTest.java @@ -107,8 +107,7 @@ public void testOCSPVerifier() throws Exception{ OCSPResp response = generateOCSPResponse(request, certificateHolder, caKeyPair.getPrivate(), caKeyPair.getPublic(), revokedID); SingleResp singleResp = ((BasicOCSPResp)response.getResponseObject()).getResponses()[0]; - OCSPCache cache = OCSPCache.getCache(); - cache.init(5,5); + OCSPCache cache = OCSPCache.getCache(5, 5); cache.setCacheValue(revokedSerialNumber,singleResp, request, null); OCSPVerifier ocspVerifier= new OCSPVerifier(cache); diff --git a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java index 7f282dd86c..9adc063ea0 100644 --- a/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java +++ b/modules/transports/core/nhttp/src/test/java/org/apache/synapse/transport/certificatevalidation/RevocationVerificationTest.java @@ -116,8 +116,7 @@ public void testOCSPPathValidationWithFakeCerts() throws Exception { private void crlPathValidation(X509Certificate[] certChain) throws Exception { - CRLCache crlCache = CRLCache.getCache(); - crlCache.init(5, 5); + CRLCache crlCache = CRLCache.getCache(5, 5); RevocationVerifier verifier = new CRLVerifier(crlCache); CertificatePathValidator pathValidator = new CertificatePathValidator(certChain, verifier); pathValidator.validatePath(); @@ -125,8 +124,7 @@ private void crlPathValidation(X509Certificate[] certChain) throws Exception { private void ocspPathValidation(X509Certificate[] certChain) throws Exception { - OCSPCache ocspCache = OCSPCache.getCache(); - ocspCache.init(5, 5); + OCSPCache ocspCache = OCSPCache.getCache(5, 5); RevocationVerifier verifier = new OCSPVerifier(ocspCache); CertificatePathValidator pathValidator = new CertificatePathValidator(certChain, verifier); pathValidator.validatePath(); diff --git a/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties b/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties new file mode 100644 index 0000000000..8f1ee4a76d --- /dev/null +++ b/modules/transports/core/vfs/repository/conf/vfs-move-failed-records.properties @@ -0,0 +1 @@ +t-0-1705986523002.txt 23/01/2024/ 10:38:43 \ No newline at end of file From d02fc9094da18bb166796929d8009da570dfb0b2 Mon Sep 17 00:00:00 2001 From: akila94 Date: Fri, 26 Jan 2024 15:16:20 +0530 Subject: [PATCH 10/10] Reformat logs --- .../CertificateVerificationManager.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java index 93ca51e710..2765ac41a1 100644 --- a/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java +++ b/modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/certificatevalidation/CertificateVerificationManager.java @@ -60,15 +60,17 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { this.cacheSize = cacheAllocatedSize; + } else { + log.warn("The cache size is out of range. Hence, using the default cache size value of " + + Constants.CACHE_DEFAULT_ALLOCATED_SIZE + "."); } - log.warn("The cache size is out of range. Hence, using the default cache size value of " - + Constants.CACHE_DEFAULT_ALLOCATED_SIZE + "."); if (cacheDelayMins != null && cacheDelayMins > Constants.CACHE_MIN_DELAY_MINS && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) { this.cacheDelayMins = cacheDelayMins; + } else { + log.warn("The cache delay is out of range. Hence, using the default cache delay value of " + + Constants.CACHE_DEFAULT_DELAY_MINS + "."); } - log.warn("The cache delay is out of range. Hence, using the default cache delay value of " - + Constants.CACHE_DEFAULT_DELAY_MINS + "."); } public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheDelayMins, @@ -78,13 +80,17 @@ public CertificateVerificationManager(Integer cacheAllocatedSize, Integer cacheD if (cacheAllocatedSize != null && cacheAllocatedSize > Constants.CACHE_MIN_ALLOCATED_SIZE && cacheAllocatedSize < Constants.CACHE_MAX_ALLOCATED_SIZE) { this.cacheSize = cacheAllocatedSize; + } else { + log.warn("The cache size is out of range. Hence, using the default cache size value of " + + Constants.CACHE_DEFAULT_ALLOCATED_SIZE + "."); } if (cacheDelayMins != null && cacheDelayMins > Constants.CACHE_MIN_DELAY_MINS && cacheDelayMins < Constants.CACHE_MAX_DELAY_MINS) { this.cacheDelayMins = cacheDelayMins; + } else { + log.warn("The cache delay is out of range. Hence, using the default cache delay value of " + + Constants.CACHE_DEFAULT_DELAY_MINS + "."); } - log.warn("The cache delay is out of range. Hence, using the default cache delay value of " - + Constants.CACHE_DEFAULT_DELAY_MINS + "."); this.isFullCertChainValidationEnabled = isFullCertChainValidationEnabled; this.isCertExpiryValidationEnabled = isCertExpiryValidationEnabled; @@ -222,7 +228,6 @@ public void verifyCertificateValidity(javax.security.cert.X509Certificate[] peer } return; } catch (Exception e) { - log.info(verifier.getClass().getSimpleName() + " failed."); log.debug("Certificate verification with " + verifier.getClass().getSimpleName() + " failed. ", e); } }