From f7c09f70880934f02e78fc220544f78d0f97f51d Mon Sep 17 00:00:00 2001 From: Alameyo Date: Thu, 27 Jul 2017 15:12:22 +0200 Subject: [PATCH 1/7] SPARK-1966, SPARK-1952, SPARK-1969, SPARK-1970, SPARK-1971 and partially SPARK-1968 --- core/pom.xml | 7 + .../jivesoftware/AccountCreationWizard.java | 25 +- .../java/org/jivesoftware/LoginDialog.java | 25 +- .../CertificatesManagerSettingsPanel.java | 45 ++- .../spark/ui/login/LoginSettingDialog.java | 1 + .../certificates/CertificateController.java | 57 +-- .../certificates/CertificateModel.java | 9 +- .../SparkExceptionsTrustManager.java | 130 +++++++ .../certificates/SparkSSLContext.java | 15 + .../certificates/SparkTrustManager.java | 365 ++++++++++++++++++ .../settings/local/LocalPreferences.java | 40 ++ .../main/resources/i18n/spark_i18n.properties | 2 +- core/src/main/security/exceptions | Bin 32 -> 3138 bytes core/src/main/security/truststore | Bin 113484 -> 112432 bytes 14 files changed, 678 insertions(+), 43 deletions(-) create mode 100644 core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkExceptionsTrustManager.java create mode 100644 core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java create mode 100644 core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java diff --git a/core/pom.xml b/core/pom.xml index 12b6c5f42..7faa934e7 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -254,6 +254,13 @@ bcpkix-jdk15on 1.57 + + + org.bouncycastle.bctls-jdk15on.1.57.org.bouncycastle + + bctls-jdk15on + 1.57 + diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index 50a391a10..e3731ac22 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -17,6 +17,7 @@ package org.jivesoftware; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.jivesoftware.resource.Res; import org.jivesoftware.smack.*; import org.jivesoftware.smack.packet.XMPPError; @@ -32,15 +33,21 @@ import org.jivesoftware.spark.util.ModelUtil; import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.spark.util.SwingWorker; import org.jivesoftware.spark.util.log.Log; +import org.jivesoftware.sparkimpl.certificates.SparkSSLContext; +import org.jivesoftware.sparkimpl.certificates.SparkTrustManager; import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; import org.jivesoftware.sparkimpl.settings.local.SettingsManager; import org.jxmpp.util.XmppStringUtils; +import javax.net.ssl.SSLContext; import javax.swing.*; import java.awt.*; import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; /** * Allows the creation of accounts on an XMPP server. @@ -353,7 +360,23 @@ public class AccountCreationWizard extends JPanel { { builder.setHost( localPreferences.getXmppHost() ); } - + + if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useOldSSL) { + builder.setPort(5222); + // This use STARTTLS which starts initially plain connection to upgrade it to TLS, it use the same port as + // plain connections which is 5222. + try { + Provider bcProvider = new BouncyCastleJsseProvider(); + Security.addProvider(bcProvider); + SSLContext context = SparkSSLContext.getInstance("TLS"); + context.init(null, SparkTrustManager.getTrustManagerList(), new SecureRandom()); + builder.setCustomSSLContext(context); + builder.setSecurityMode( securityMode ); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + Log.warning("Couldnt establish secured connection", e); + } + } + if ( securityMode != ConnectionConfiguration.SecurityMode.disabled && useOldSSL ) { if (!hostPortConfigured) { diff --git a/core/src/main/java/org/jivesoftware/LoginDialog.java b/core/src/main/java/org/jivesoftware/LoginDialog.java index a9862935c..5bdc6218d 100644 --- a/core/src/main/java/org/jivesoftware/LoginDialog.java +++ b/core/src/main/java/org/jivesoftware/LoginDialog.java @@ -16,6 +16,7 @@ package org.jivesoftware; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; @@ -44,9 +45,11 @@ import org.jivesoftware.spark.ui.login.LoginSettingDialog; import org.jivesoftware.spark.util.*; import org.jivesoftware.spark.util.SwingWorker; import org.jivesoftware.spark.util.log.Log; +import org.jivesoftware.sparkimpl.plugin.manager.Enterprise; +import org.jivesoftware.sparkimpl.certificates.SparkSSLContext; +import org.jivesoftware.sparkimpl.certificates.SparkTrustManager; import org.jivesoftware.sparkimpl.plugin.layout.LayoutSettings; import org.jivesoftware.sparkimpl.plugin.layout.LayoutSettingsManager; -import org.jivesoftware.sparkimpl.plugin.manager.Enterprise; import org.jivesoftware.sparkimpl.settings.JiveInfo; import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; import org.jivesoftware.sparkimpl.settings.local.SettingsManager; @@ -57,6 +60,7 @@ import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; +import javax.net.ssl.SSLContext; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; @@ -77,6 +81,9 @@ import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.Principal; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.Security; import java.util.*; import java.util.List; @@ -277,6 +284,22 @@ public class LoginDialog { builder.setProxyInfo( proxyInfo ); } + if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useOldSSL) { + builder.setPort(5222); + // This use STARTTLS which starts initially plain connection to upgrade it to TLS, it use the same port as + // plain connections which is 5222. + try { + Provider bcProvider = new BouncyCastleJsseProvider(); + Security.addProvider(bcProvider); + SSLContext context = SparkSSLContext.getInstance("TLS"); + context.init(null, SparkTrustManager.getTrustManagerList(), new SecureRandom()); + builder.setCustomSSLContext(context); + builder.setSecurityMode( securityMode ); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + Log.warning("Couldnt establish secured connection", e); + } + } + if ( securityMode != ConnectionConfiguration.SecurityMode.disabled && useOldSSL ) { if (!hostPortConfigured) { // SMACK 4.1.9 does not support XEP-0368, and does not apply a port change, if the host is not changed too. diff --git a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java index 7ed383099..5226adfe7 100644 --- a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java +++ b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java @@ -44,6 +44,7 @@ import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.certificates.CertificateController; import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; +import org.jivesoftware.sparkimpl.settings.local.SettingsManager; /** * This class serve as visual in implementation of manageable list of certificates. Together with CertificateController @@ -76,6 +77,7 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi this.localPreferences = localPreferences; certControll = new CertificateController(localPreferences); setLayout(new GridBagLayout()); + certControll.createCertTableModel(); certTable = new JTable(certControll.getTableModel()){ @Override @@ -112,19 +114,30 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi ResourceUtils.resButton(acceptAll, Res.getString("checkbox.accept.all")); ResourceUtils.resButton(acceptExpired, Res.getString("checkbox.accept.expired")); - ResourceUtils.resButton(acceptRevoked, Res.getString("checkbox.accept.invalid")); + ResourceUtils.resButton(acceptRevoked, Res.getString("checkbox.accept.revoked")); ResourceUtils.resButton(acceptSelfSigned, Res.getString("checkbox.accept.self.signed")); ResourceUtils.resButton(checkCRL, Res.getString("checkbox.check.crl")); ResourceUtils.resButton(checkOCSP, Res.getString("checkbox.check.ocsp")); ResourceUtils.resButton(showCert, Res.getString("button.show.certificate")); ResourceUtils.resButton(fileButton, Res.getString("label.choose.file")); - + + acceptAll.setSelected(localPreferences.isAcceptAllCertificates()); + acceptSelfSigned.setSelected(localPreferences.isAcceptSelfSigned()); + acceptExpired.setSelected(localPreferences.isAcceptExpired()); + acceptRevoked.setSelected(localPreferences.isAcceptRevoked()); + checkCRL.setSelected(localPreferences.isCheckCRL()); + checkOCSP.setSelected(localPreferences.isCheckOCSP()); + acceptAll.addActionListener(this); certTable.addMouseListener(this); certTable.getModel().addTableModelListener(this); showCert.setEnabled(false); showCert.addActionListener(this); fileButton.addActionListener(this); + checkCRL.addActionListener(this); + acceptRevoked.addActionListener(this); + checkCRL.setEnabled(!acceptRevoked.isSelected()); + checkOCSP.setEnabled(checkCRL.isSelected()); filePanel.setLayout(new GridBagLayout()); filePanel.add(fileButton, new GridBagConstraints(0, 0, 2, 1, 1.0, 1.0, WEST, HORIZONTAL, DEFAULT_INSETS, 40, 0)); @@ -160,8 +173,21 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi certControll.showCertificate(); } else if (e.getSource() == fileButton) { addCertificate(); - } - } + } else if (e.getSource() == checkCRL && checkCRL.isSelected()) { + checkOCSP.setEnabled(true); + } else if (e.getSource() == checkCRL && !checkCRL.isSelected()) { + checkOCSP.setSelected(false); + checkOCSP.setEnabled(false); + } else if (e.getSource() == acceptRevoked && acceptRevoked.isSelected()) { + checkCRL.setSelected(false); + checkOCSP.setSelected(false); + + checkCRL.setEnabled(false); + checkOCSP.setEnabled(false); + } else if (e.getSource() == acceptRevoked && !acceptRevoked.isSelected()) { + checkCRL.setEnabled(true); + } + } @Override public void mouseClicked(MouseEvent e) { @@ -248,4 +274,15 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi } }); } + + public void saveSettings() { + localPreferences.setAcceptExpired(acceptExpired.isSelected()); + localPreferences.setAcceptSelfSigned(acceptSelfSigned.isSelected()); + localPreferences.setAcceptRevoked(acceptRevoked.isSelected()); + localPreferences.setAcceptAllCertificates(acceptAll.isSelected()); + localPreferences.setCheckCRL(checkCRL.isSelected()); + localPreferences.setCheckOCSP(checkOCSP.isSelected()); + + SettingsManager.saveSettings(); + } } diff --git a/core/src/main/java/org/jivesoftware/spark/ui/login/LoginSettingDialog.java b/core/src/main/java/org/jivesoftware/spark/ui/login/LoginSettingDialog.java index 7c735dd51..33ddb75af 100644 --- a/core/src/main/java/org/jivesoftware/spark/ui/login/LoginSettingDialog.java +++ b/core/src/main/java/org/jivesoftware/spark/ui/login/LoginSettingDialog.java @@ -148,6 +148,7 @@ public class LoginSettingDialog implements PropertyChangeListener proxyPanel.saveSettings(); ssoPanel.saveSettings(); pkiPanel.saveSettings(); + certManager.saveSettings(); SettingsManager.saveSettings(); optionsDialog.setVisible( false ); } diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java index 77f568877..91f449398 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java @@ -43,15 +43,14 @@ public class CertificateController { public final static File TRUSTED = new File(System.getProperty("user.dir") +"\\src\\main\\security\\truststore"); public final static File BLACKLIST = new File(System.getProperty("user.dir") +"\\src\\main\\security\\blacklist"); public final static File EXCEPTIONS = new File(System.getProperty("user.dir") +"\\src\\main\\security\\exceptions"); - public static String trustStorePath; - private final static char[] passwd = "changeit".toCharArray(); + public final static char[] passwd = "changeit".toCharArray(); private List certificates = new ArrayList<>(); // contain all certificates from all keystores private List exemptedCertificates = new ArrayList<>(); // contain only certificates from exempted list private List blackListedCertificates = new ArrayList<>(); //contain only revoked certificates - private DefaultTableModel tableModel; + private static DefaultTableModel tableModel; private Object[] certEntry; private LocalPreferences localPreferences; private static final String[] COLUMN_NAMES = { Res.getString("table.column.certificate.subject"), @@ -64,7 +63,9 @@ public class CertificateController { throw new IllegalArgumentException("localPreferences cannot be null"); } this.localPreferences = localPreferences; - + } + + public void createCertTableModel(){ tableModel = new DefaultTableModel() { // return adequate classes for columns so last column is Boolean // displayed as checkbox @@ -106,12 +107,10 @@ public class CertificateController { } } } - - /** * If argument is true then move certificate to the exceptions Keystore, if false then move to the trusted Keystore. * Useful for checkboxes where it's selected value indicates where certificate should be moved. - * @param checked + * @param checked should it be moved? */ public void addOrRemoveFromExceptionList(boolean checked) { int row = CertificatesManagerSettingsPanel.getCertTable().getSelectedRow(); @@ -135,18 +134,16 @@ public class CertificateController { /** * Return information if certificate is on exception list. * - * @param alias + * @param alias of the certificate */ public boolean isOnExceptionList(CertificateModel cert) { - if(exemptedCertificates.contains(cert)){ - return true; - } - return false; - } - + return exemptedCertificates.contains(cert); + } + /** - * Add certificates from keyStore to - * @param storePath + * Add certificates from keyStore to + * + * @param storePath path of the store which will fill certificate table */ private void fillCertTableWithKeyStoreContent(File storePath) { @@ -174,8 +171,8 @@ public class CertificateController { /** * Return file which contains certificate with given alias; * - * @param alias - * @return File path + * @param alias of the certificate + * @return File path of KeyStore with certificate */ private File getAliasKeyStore(String alias) { for (CertificateModel model : exemptedCertificates) { @@ -199,7 +196,7 @@ public class CertificateController { /** * This method delete certificate with provided alias from the Truststore * - * @param alias + * @param alias Alias of the certificate to delete * @throws KeyStoreException * @throws IOException * @throws NoSuchAlgorithmException @@ -237,12 +234,16 @@ public class CertificateController { } + public void moveCertificateToBlackList(String alias) throws FileNotFoundException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException{ + moveCertificate(getAliasKeyStore(alias), BLACKLIST, alias); + } + /** * This method transfer certificate from source KeyStore to target KeyStore. * - * @param source - * @param target - * @param alias + * @param source File with source KeyStore + * @param target File with target KeyStore + * @param alias Alias of the certificate meant to move * @throws FileNotFoundException * @throws IOException * @throws KeyStoreException @@ -286,7 +287,7 @@ public class CertificateController { /** * This method add certifiate from file ((*.cer), (*.crt), (*.der)) to Truststore. * - * @param file + * @param file File with certificate that is added * @throws KeyStoreException * @throws CertificateException * @throws NoSuchAlgorithmException @@ -330,8 +331,8 @@ public class CertificateController { * This method also assure that it will not add second same alias to Truststore by adding number to alias. * In case when common name cannot be extracted method will return "cert{number}". * - * @param cert - * @return String Common Name + * @param cert Certificate which Common Name is meant to use + * @return String Common Name of the certificate * @throws InvalidNameException * @throws HeadlessException * @throws KeyStoreException @@ -366,7 +367,7 @@ public class CertificateController { /** * Check if there is certificate entry in Truststore with the same alias. * - * @param alias + * @param alias Alias of the certificate which is looked for in the model list * @return True if KeyStore contain the same alias. * @throws HeadlessException * @throws KeyStoreException @@ -383,7 +384,7 @@ public class CertificateController { /** * Check if this certificate already exist in Truststore. * - * @param alias + * @param alias Alias of the certificate for which it method look in the model list * @return true if KeyStore already have this certificate. * @throws KeyStoreException */ @@ -412,7 +413,7 @@ public class CertificateController { /** * Open dialog with certificate. * - * @param CertificateModel + * @param CertificateModel Model of the certificate which details are meant to be shown. */ public void showCertificate(CertificateModel certModel, CertificateDialogReason reason) { CertificateDialog certDialog = new CertificateDialog(localPreferences, certModel, this, reason); diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateModel.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateModel.java index 159861c39..4f0316c89 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateModel.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateModel.java @@ -1,12 +1,10 @@ package org.jivesoftware.sparkimpl.certificates; import java.io.IOException; -import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Base64; -import java.util.Calendar; import java.util.Date; import javax.naming.InvalidNameException; @@ -27,10 +25,8 @@ import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralSubtree; import org.bouncycastle.asn1.x509.NameConstraints; import org.bouncycastle.asn1.x509.PolicyConstraints; -import org.bouncycastle.asn1.x509.PolicyQualifierInfo; import org.bouncycastle.asn1.x509.SubjectDirectoryAttributes; import org.bouncycastle.asn1.x509.SubjectKeyIdentifier; -import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.bouncycastle.util.encoders.Hex; import org.jivesoftware.resource.Res; @@ -140,7 +136,7 @@ public class CertificateModel { String value = Res.getString("cert.is.critical") + critical + "\n"; boolean isSupported = true; - if (oid.equals(Extension.subjectDirectoryAttributes)) { + if (oid.equals(Extension.subjectDirectoryAttributes.toString())) { value += subjectDirectoryAttributesExtractor(primitive); } else if (oid.equals(Extension.subjectKeyIdentifier.toString())) { @@ -332,9 +328,6 @@ public class CertificateModel { } else if (isBeforeNotBefore()) { return "cert.not.valid.yet"; - } else if (isSelfSigned()) { - return Res.getString("cert.self.signed"); - } else { return Res.getString("cert.valid"); } diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkExceptionsTrustManager.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkExceptionsTrustManager.java new file mode 100644 index 000000000..061ec0b26 --- /dev/null +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkExceptionsTrustManager.java @@ -0,0 +1,130 @@ +package org.jivesoftware.sparkimpl.certificates; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.cert.CertPath; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathBuilderException; +import java.security.cert.CertPathBuilderResult; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertificateException; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.Enumeration; + +import javax.net.ssl.X509TrustManager; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.jivesoftware.spark.util.log.Log; + +public class SparkExceptionsTrustManager implements X509TrustManager { + + KeyStore exceptionsStore; + private Provider bcProvider = new BouncyCastleProvider(); // bc provider for path validation + + public SparkExceptionsTrustManager() { + try (InputStream inputStream = new FileInputStream(CertificateController.EXCEPTIONS)) { + this.exceptionsStore = KeyStore.getInstance("JKS"); + exceptionsStore.load(inputStream, CertificateController.passwd); + } catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException e) { + Log.error("Couldn't load keystore for certificate exceptions authentication", e); + ; + } + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + // doesen't do any checks as there is it use only accepted issuers from exception list + try { + validatePath(chain); + } catch (NoSuchAlgorithmException | KeyStoreException | InvalidAlgorithmParameterException + | CertPathValidatorException | CertPathBuilderException e) { + Log.warning("Cannot build certificate chain", e); + throw new CertificateException("Cannot build certificate chain"); + } + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + X509Certificate[] X509Certs = null; + try { + // See how many certificates are in the keystore. + int numberOfEntry = exceptionsStore.size(); + // If there are any certificates in the keystore. + if (numberOfEntry > 0) { + // Create an array of X509Certificates + X509Certs = new X509Certificate[numberOfEntry]; + + // Get all of the certificate alias out of the keystore. + Enumeration aliases = exceptionsStore.aliases(); + + // Retrieve all of the certificates out of the keystore + // via the alias name. + int i = 0; + while (aliases.hasMoreElements()) { + X509Certs[i] = (X509Certificate) exceptionsStore.getCertificate((String) aliases.nextElement()); + i++; + } + + } + } catch (Exception e) { + Log.error(e.getMessage(), e); + X509Certs = null; + } + return X509Certs; + } + + /** + * Validate certificate path. As it is exception, no checks against revocation or time validity are done but path + * still have to be validated in order to find connection between certificate presented by server and root CA in + * KeyStore + * + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws InvalidAlgorithmParameterException + * @throws CertPathValidatorException + * @throws CertPathBuilderException + * @throws CertificateException + */ + private void validatePath(X509Certificate[] chain) + throws NoSuchAlgorithmException, KeyStoreException, InvalidAlgorithmParameterException, + CertPathValidatorException, CertPathBuilderException, CertificateException { + + CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX", bcProvider); + CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX"); + X509CertSelector certSelector = new X509CertSelector(); + certSelector.setCertificate(chain[chain.length - 1]); + // checks against time validity aren't done here as it exceptions list + certSelector.setCertificateValid(null); + PKIXBuilderParameters parameters = new PKIXBuilderParameters(exceptionsStore, certSelector); + // no checks against revocation as it is exception + parameters.setRevocationEnabled(false); + + CertPathBuilderResult pathResult = certPathBuilder.build(parameters); + CertPath certPath = pathResult.getCertPath(); + PKIXCertPathValidatorResult validationResult = (PKIXCertPathValidatorResult) certPathValidator + .validate(certPath, parameters); + X509Certificate trustedCert = validationResult.getTrustAnchor().getTrustedCert(); + + if (trustedCert == null) { + throw new CertificateException("Certificate path failed"); + } else { + Log.debug("ClientTrustManager: Trusted CA: " + trustedCert.getSubjectDN()); + } + + } + +} \ No newline at end of file diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java new file mode 100644 index 000000000..eb09a1355 --- /dev/null +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java @@ -0,0 +1,15 @@ +package org.jivesoftware.sparkimpl.certificates; + +import java.security.Provider; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLContextSpi; + +public class SparkSSLContext extends SSLContext { + + protected SparkSSLContext(SSLContextSpi contextSpi, Provider provider, String protocol) { + super(contextSpi, provider, protocol); + // TODO Auto-generated constructor stub + } + +} diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java new file mode 100644 index 000000000..d296d3176 --- /dev/null +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java @@ -0,0 +1,365 @@ +package org.jivesoftware.sparkimpl.certificates; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.cert.CRLException; +import java.security.cert.CertPath; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathBuilderException; +import java.security.cert.CertPathBuilderResult; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateRevokedException; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.X509CRL; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; + +import javax.net.ssl.X509TrustManager; + +import org.bouncycastle.asn1.ASN1Primitive; +import org.bouncycastle.asn1.x509.CRLDistPoint; +import org.bouncycastle.asn1.x509.DistributionPoint; +import org.bouncycastle.asn1.x509.DistributionPointName; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.jivesoftware.spark.util.log.Log; +import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; +import org.jivesoftware.sparkimpl.settings.local.SettingsManager; + +/** + * This trust manager wrap around SparkExceptionsTrustManager. In case when SparkExceptionsTrustManager fail then this + * TrustManager will provide certificates from TRUSTED KeyStore which are checked against data validity, revocation, + * acceptance of self-signed certificates and basic constraints. + * + * + * @author A + * + */ +public class SparkTrustManager implements X509TrustManager { + + private LocalPreferences localPref = SettingsManager.getLocalPreferences(); + private boolean checkCRL; + private boolean checkOCSP; + private boolean acceptExpired; + private boolean acceptNotValidYet; + private boolean acceptRevoked; + private boolean acceptSelfSigned; + + private CertStore crlStore; + private X509TrustManager exceptionsTrustManager; + private Provider bcProvider = new BouncyCastleProvider(); // bc provider for path validation + private KeyStore trustStore; + private CertificateController certControll = new CertificateController(localPref); + + public SparkTrustManager() { + exceptionsTrustManager = new SparkExceptionsTrustManager(); + Security.addProvider(bcProvider); + + checkCRL = localPref.isCheckCRL(); + checkOCSP = localPref.isCheckOCSP(); + acceptExpired = localPref.isAcceptExpired(); + // acceptNotValidYet = localPref.isAcceptNotValidYet(); + acceptRevoked = localPref.isAcceptRevoked(); + acceptSelfSigned = localPref.isAcceptSelfSigned(); + + loadTrustStore(); + } + + public static X509TrustManager[] getTrustManagerList() { + return new X509TrustManager[] { new SparkTrustManager() }; + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + // TODO Auto-generated method stub + + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + try { + // first check if certificate is accepted as as certificate from exceptions list, exceptionsTrustManager + // will make use of chain provided by exceptions KeyStore + exceptionsTrustManager.checkServerTrusted(chain, authType); + } catch (CertificateException ex) { + // in case when certificate isn't on exceptions list then make use of this Trust Manager + + // check if certificate isn't self signed, self signed certificate still have to be in TrustStore to be + // accepted + if (chain.length == 1 && acceptSelfSigned == false) { + throw new CertificateException("SelfSigned certificate"); + } + + // validate chain by date (expired/not valid yet) + checkDateValidity(chain); + + // validate certificate path + try { + validatePath(chain); + } catch (NoSuchAlgorithmException | KeyStoreException | InvalidAlgorithmParameterException + | CertPathValidatorException | CertPathBuilderException e) { + Log.error("Validating path failed", e); + throw new CertificateException("Certificate path validation failed", e); + } + } + // check if have basic constraints + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + X509Certificate[] X509Certs = null; + try { + // See how many certificates are in the keystore. + int numberOfEntry = trustStore.size(); + // If there are any certificates in the keystore. + if (numberOfEntry > 0) { + // Create an array of X509Certificates + X509Certs = new X509Certificate[numberOfEntry]; + + // Get all of the certificate alias out of the keystore. + Enumeration aliases = trustStore.aliases(); + + // Retrieve all of the certificates out of the keystore + // via the alias name. + int i = 0; + while (aliases.hasMoreElements()) { + X509Certs[i] = (X509Certificate) trustStore.getCertificate((String) aliases.nextElement()); + i++; + } + + } + } catch (Exception e) { + Log.error(e.getMessage(), e); + X509Certs = null; + } + return X509Certs; + } + + /** + * Validate certificate path + * + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws InvalidAlgorithmParameterException + * @throws CertPathValidatorException + * @throws CertPathBuilderException + * @throws CertificateException + */ + private void validatePath(X509Certificate[] chain) + throws NoSuchAlgorithmException, KeyStoreException, InvalidAlgorithmParameterException, + CertPathValidatorException, CertPathBuilderException, CertificateException { + + CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX", bcProvider); + CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX"); + + X509CertSelector certSelector = new X509CertSelector(); + + // set root CA certificate from chain for CertSelector so trust store must contain it + certSelector.setCertificate(chain[chain.length - 1]); + + // checks against time validity aren't done here as are already done in checkDateValidity (X509Certificate[] + // chain) + certSelector.setCertificateValid(null); + // create parameters using trustStore as source of Trust Anchors and using X509CertSelector + PKIXBuilderParameters parameters = new PKIXBuilderParameters(trustStore, certSelector); + + if (acceptRevoked == false) { + if (checkCRL) { + // check add CRL store and download CRL list to this store. + try { + loadCRL(chain); + parameters.addCertStore(crlStore); + if (checkOCSP) { + // check OCSP, important reminder if CRL is disabled then then OCSP will not work either, for + // reference: + // http://docs.oracle.com/javase/7/docs/technotes/guides/security/certpath/CertPathProgGuide.html#AppC + // parameters.setCertPathCheckers(checkers); + } + + } catch (CertStoreException | IOException | CRLException e) { + Log.error("Couldn't load crl", e); + throw new CertificateException(); + } + + } else { + parameters.setRevocationEnabled(false); + } + + } else { + parameters.setRevocationEnabled(false); + } + try { + CertPathBuilderResult pathResult = certPathBuilder.build(parameters); + CertPath certPath = pathResult.getCertPath(); + + PKIXCertPathValidatorResult validationResult = (PKIXCertPathValidatorResult) certPathValidator + .validate(certPath, parameters); + X509Certificate trustedCert = validationResult.getTrustAnchor().getTrustedCert(); + + if (trustedCert == null) { + throw new CertificateException("certificate path failed: Trusted CA is NULL"); + } + // check if all certificates in path have Basic Constraints, only certificate that isn't required to have + // this extension is last certificate: root CA + for (int i = 0; i < chain.length - 1; i++) { + checkBasicConstraints(chain[i]); + } + } catch (CertificateRevokedException e) { + Log.warning("Certificate was revoked", e); + // moveToBlackList(cert); + throw new CertificateException("Certificate was revoked"); + } + } + + /** + * check time date validity of certificates + * + * @throws CertificateException + */ + private void checkDateValidity(X509Certificate[] chain) throws CertificateException { + + for (X509Certificate cert : chain) { + // expiration check + try { + cert.checkValidity(); + } catch (CertificateExpiredException e) { + Log.warning("Certificate is expired " + cert.getSubjectX500Principal().getName().toString(), e); + if (acceptExpired == false) { + throw new CertificateException("Certificate is expired"); + } + } catch (CertificateNotYetValidException e) { + Log.warning("Certificate is not valid yet " + cert.getSubjectX500Principal().getName().toString(), e); + if (acceptNotValidYet == false) { + throw new CertificateException("Certificate is not valid yet"); + } + } + + } + } + + /** + * Check if certificate have basic constraints exception. + * + * @param chain + * - with certificates given by server + * @throws CertificateException + */ + private void checkBasicConstraints(X509Certificate cert) throws CertificateException { + if (cert.getBasicConstraints() != -1) { + throw new CertificateException("Certificate have no basic constraints"); + } + } + + /** + * loads truststore + */ + private void loadTrustStore() { + try (FileInputStream inputStream = new FileInputStream(CertificateController.TRUSTED)) { + trustStore = KeyStore.getInstance("JKS"); + trustStore.load(inputStream, CertificateController.passwd); + } catch (NoSuchAlgorithmException | CertificateException | IOException | KeyStoreException e) { + Log.error("Error at accesing truststore", e); + } + } + + private void loadCRL(X509Certificate[] chain) throws IOException, InvalidAlgorithmParameterException, + NoSuchAlgorithmException, CertStoreException, CRLException, CertificateException { + + Collection crlCollection = new ArrayList<>(); + + // for each certificate in chain + for (X509Certificate cert : chain) { + if (cert.getExtensionValue(Extension.cRLDistributionPoints.getId()) != null) { + ASN1Primitive primitive = JcaX509ExtensionUtils + .parseExtensionValue(cert.getExtensionValue(Extension.cRLDistributionPoints.getId())); + // extract distribution point extension + CRLDistPoint distPoint = CRLDistPoint.getInstance(primitive); + DistributionPoint[] dp = distPoint.getDistributionPoints(); + // each distribution point extension can hold number of distribution points + for (DistributionPoint d : dp) { + DistributionPointName dpName = d.getDistributionPoint(); + // Look for URIs in fullName + if (dpName != null && dpName.getType() == DistributionPointName.FULL_NAME) { + GeneralName[] genNames = GeneralNames.getInstance(dpName.getName()).getNames(); + // Look for an URI + for (GeneralName genName : genNames) { + // extract url + URL url = new URL(genName.getName().toString()); + try { + // download from Internet to the collection + crlCollection.add(downloadCRL(url)); + } catch (CertificateException | CRLException e) { + throw new CRLException("Couldn't download CRL"); + } + } + } + } + } else { + Log.warning("Certificate " + cert.getSubjectX500Principal().getName().toString() + " have no CRLs"); + } + // parameters for cert store is collection type, using collection with crl create parameters + CollectionCertStoreParameters params = new CollectionCertStoreParameters(crlCollection); + // this parameters are next used for creation of certificate store with crls + crlStore = CertStore.getInstance("Collection", params); + } + } + + /** + * Move certificate to the blacklist of the revoked certificates. + * + * @param cert + * - certificate which is meant to move into blacklist + * @throws FileNotFoundException + * @throws KeyStoreException + * @throws NoSuchAlgorithmException + * @throws CertificateException + * @throws IOException + */ + private void moveToBlackList(X509Certificate cert) throws FileNotFoundException, KeyStoreException, + NoSuchAlgorithmException, CertificateException, IOException { + certControll.moveCertificateToBlackList(trustStore.getCertificateAlias(cert)); + } + + /** + * Downloads a CRL from given URL + * + * @param url + * - the web address with given CRL + * @throws IOException + * @throws CertificateException + * @throws CRLException + */ + private X509CRL downloadCRL(URL url) throws IOException, CertificateException, CRLException { + + try (InputStream crlStream = url.openStream()) { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (X509CRL) cf.generateCRL(crlStream); + } + } + +} diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java b/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java index e437e9d44..530a1dd91 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java @@ -1420,5 +1420,45 @@ public class LocalPreferences { public void setPswdAutologin(boolean ccPswdAutologin) { props.setProperty("ccPswdAutologin", Boolean.toString(ccPswdAutologin)); } + + public boolean isAcceptSelfSigned() { + return Boolean.parseBoolean(props.getProperty("acceptSelfSigned", "false")); + } + + public void setAcceptSelfSigned(boolean acceptSelfSigned) { + props.setProperty("acceptSelfSigned", Boolean.toString(acceptSelfSigned)); + } + + public boolean isAcceptRevoked() { + return Boolean.parseBoolean(props.getProperty("acceptRevoked", "false")); + } + + public void setAcceptRevoked(boolean acceptRevoked) { + props.setProperty("acceptRevoked", Boolean.toString(acceptRevoked)); + } + + public boolean isAcceptExpired() { + return Boolean.parseBoolean(props.getProperty("acceptExpired", "false")); + } + + public void setAcceptExpired(boolean acceptExpired) { + props.setProperty("acceptExpired", Boolean.toString(acceptExpired)); + } + + public boolean isCheckCRL() { + return Boolean.parseBoolean(props.getProperty("checkCRL", "true")); + } + + public void setCheckCRL(boolean checkCRL) { + props.setProperty("checkCRL", Boolean.toString(checkCRL)); + } + + public boolean isCheckOCSP() { + return Boolean.parseBoolean(props.getProperty("checkOCSP", "true")); + } + + public void setCheckOCSP(boolean checkOCSP) { + props.setProperty("checkOCSP", Boolean.toString(checkOCSP)); + } } diff --git a/core/src/main/resources/i18n/spark_i18n.properties b/core/src/main/resources/i18n/spark_i18n.properties index 2d8a023e9..114a3818f 100644 --- a/core/src/main/resources/i18n/spark_i18n.properties +++ b/core/src/main/resources/i18n/spark_i18n.properties @@ -394,7 +394,7 @@ checkbox.disable.hostname.verification = Disable certificate hostname verificati checkbox.accept.all = Accept all checkbox.accept.expired = Accept expired checkbox.accept.self.signed = Accept self-signed -checkbox.accept.invalid = Accept invalid +checkbox.accept.revoked = Accept revoked checkbox.check.crl = Check CRL checkbox.check.ocsp = Check OCSP checkbox.on.exception.list = On the exception list diff --git a/core/src/main/security/exceptions b/core/src/main/security/exceptions index c408465500cb0af9cfd1f7371422ef8899ae6725..f314364fc76137971f0f47001bf08ba3c2cc2f24 100644 GIT binary patch literal 3138 zcmc(hc{r47AIE3RjAbm7#+G%gCDHQ?V~iwYNjegl#K@^>W?qbakfqHMTFJg;iy})A zAz4mjsSYArw2+;mFnOt*Geh+{o%g!V`&aKD&vjqF-+kZD{kwk8{rNuMm3J%eAP@)_ z`+=>F(lolSk2lqc?n8H_yLh-UJv@A<6fDM`L343{K%fr$44RrD2wM#tKw$6520~yN zKnPbvCX5Tp#RXLX1iAUPhVKbq6of(%2ngT>@&kO_u!C@JG?%dnC=Ez*0wfx3{Pi3R zY3(2k(G-*eWH__@XfcvHCv8oqVn|G1Zy$^i-Q9=I1Qh{!&H@-(@^9M@unWZ)5iwXm zR$P!k0Pp|-#DX9Iki`YT)ex(RBe28&M@b=2h4qbrA|S93C<+3EK#^P_P$;B;KN~lA zQB|ZwB@n#Div~0(pm6qi*Y#2VSRp59(Y<|#b=#g* z<{28iZqKd?v17zY6-uY{^QtLtUUF76{V+JaEijdZ=6ZTs>tubp9>lJI)i1!p>Zui4 z_V+Zr3XOZ5CyIbw2bY~Cy zTJ;aigG)1BN!W)ZQDcFn)PwJeUQ6(1W`|!eo3TbjZ8GnEWgC#%$&fZIXzb2ycS0qM z3{jGfQ(B@=_UJ?2L|aA-r6I?P5<6v@bWc60?uTi0N7_SK44w+Ha`(MwxL{BSG}{m` zSiJx;LU1v-2-pxHRmHOI6(2kws4nh`ELBU>1W@eHFN22j0^CsOA6!rbAjC@GtgaWuOk0&QG%8ofepxQIT~0#|zPV#D!~7Su$V}L<{@~57&J&%bd2g6{Md^P8*^Q){lzrS$+)CJ#gdLrd zr(78UeC(x zeLGICsH2kSci#?xc^(gkpwzHh1jH%biRk=93tWi%ys*vKL&??sw6dKKkgA(1J4U#*>l}cI9bXVwirs29k2wa=Zwd_}>p+7Vg@L0#R zwFxK!Y~(adB%t`C2HLI1>a#iFF<*c=3|P8hVXeRBT4g-s;$QFv;Pl_E9%Wa!;aa966}iEO0<0{!8WKI=qg$tbR1H$kV3z z{r+7O*mR%AEmugBO-E4vX(c*R}yDz!X{Y(}T) z@Pu>aP3AePNL(o}FW#?Mpu7KU-|M!FA!m>Ky@tIm#v{!|Gj7BqOtKd*zBGWIW0x6+ zUxaKItdC*#KhuxRb<~5#!UjV_+*AZP*lN6{`rn0#FP=z!Ls~J>! zLXrgdR{{P??;745nh^kuJpjSUoM}aPa5NAc86@)G-jL;;T09#jnpkh^Oic<%} zlW73F8SD&8^2!1YWFT$g!O^+(>^SfV2bTvI1YE`_1-8ugGqYAn?NbGtY z`Ex|Of53V9lsD!)$Z%Zs+$*bxoe32$PFu`)evu|j3vgM9s7Ka_4L*3i+jm^4=DYdraO*6l0{9Jbto9sqbdAxc9kTHd3IDM41;VrL{#UJyJtz=u%SX6FKmM zv3V2R+wAyJRP(=U#DiQkCVw{f`L@!K70?XmoF9M|Wp;$G^%=+sE&61IuSi%?-ANU~4DGLcrNxr0$2_0*>nx$IJxW z2yEbJ1`^F@`0XeV4G42`{Ai?6z%e>=RfoXsfI24$L#upWi22Vn#)w@X#(J&5zbFle z2esH@!|@JS9DoDy-@L<5E99RPro}5oVq;|Bz*5R*;_be<1-{6lT`P`wz5YikmL(Y_)8h(VGwlxJ zc^1-X3DGaF*7)${F)8`Q^12^(ZiCtIbv}5}aJQL+FBns~c4xPj_haF6Gu7j?#izoO z-Uj3rvu&t~*(+z9g5Wy*Qm7qWtjyB-$RVw=pk%l7<6SYT1|{*G_#DTLX9kbmzlCc| z)($bQ9P^jZqJt6$FWj}Mu4TT>V^U<;r*3ZV=a0Fd0gYTRto$peF}6P*^K)?ram z_^82LM?s2*QcPfkA$j$OC4=VZ%r_?i`(K>I0iXQ%UlcAi?@Y*9aai7dw|e?L|D=tM zOoy9bR<+Z`_l-fFrFfjbbJ5S&%8J33jV+xUS;2{H;+{lj$dO^9hXd>-i5<%Tq_pryc(U6XA=E literal 32 ncmezO_TO6u1_mY|W_Xm5=la|E{*s%M?mC{^wn--0;QAy0^AQhj diff --git a/core/src/main/security/truststore b/core/src/main/security/truststore index 1480d6cb8379180285fdaabb78fdc2b41eb9821d..f4de542f84b352f9434d1b08abe7ba79d95e2916 100644 GIT binary patch delta 1991 zcmchXdsGv57RNIo2_}Fb;RKC5W>Fp?m<$p_cxl@p3nowj6)KNoNG32C0-a2dMLq4u>}!Y5AvTs4b53F0Fd^Z>(Btx9ldgCI|nd^9L1}2*t#y zDWDieF+_@pMHrGQ2SrLODHTPqOdJk~Q+6c!;fT?!O^^=`XL=t}oAy9zVoQ1Wb(>@& z5eMaXnn7fe$xZ@^iVqQb(jXgSK%rVh8qN6zb0H>Sc`_k}F>gk7iiE{V6b1v4Lly7VK5R&lq2#)PX^>_6q``NWs{1$Q-FgC^6~Wc^x<&5xVvpFytwa$|CejvQ&TDc zXJAdal@L^Q9(qE)Aq)B}qxyKZ)~i&HCJc6RL8tZc4}RLG=Tpv+B z`t*%5fpg8{u*%`+s|im3s_ql_BLc2@4eCOln)z*0394_qu;;WiJ9N{&UjMk!-eH$w zIyXHQc!JqDFHC4Phb(m&y&D`&Dotv7-UCy#_@=Rk>Z%6unQck`3;z>t< z^oF@=S7YCDu8s=Uh)Qt?s%+M&2j?=Kf;+BdBeQAUb6MVx9$5^e ze;l<~+CEY?pnH9LPkW-TZlUq?Wa46=EEAR`p5ID@3m=TBm9fn*0?JG zils@b^&Wi|JMT%2e9;A}m@d{8MYVky(Avzr+n$b}tQ}-l71+3=Z%4e2#E}Kmq3cIf z7&StGHvw=!jT#>TsqtZux#6F+rxJ*e2>>iYX2!^pKrq1r7a@CNu#!L{*o2wArl0>H zrq&iIgnBti{QeIw>LH2ou_GZ4ih(>d?i#lOmm~~J^JTM*d&yefQdTOO$W}-dV$lXM zs*;J6|59M`1 zuC!m*9W+2A1xCe)fevoV0AMU(1Twr$fSy+&M7E|N7%TyWh$sP(8BpZ`qOeE;Vo5Nl zfW=D~a~Hyi1`8o#kS>8u;SQ!smn6%sWi4xD+m{9bMd>0$CQ6XOpa=v1bcpw+UPU7B zDF_A%WLSX~lB85x%sQ9N1KvmIXl~Yo4&UAl%d=BO1 zzpTP|cJV`X&O|}k#?CRnp96G(Wb8CpzE3yf*wqs2#Z&v|O6)Z!+<)%D(CiynR~JudHS_PmZhkCufnyRk7nDo-X0uJZ} z?7!RP?rr~~bjr!^;_N&3-Z^!I=5@1RXZedx?W9xj1x}cY6X9&3hjLr{^Bn4TUztm8 zaR++X1=gw~>&TsJ)qaYQn&ha$W6uXO?pE@}Bcb2#+b|4Qq6mThSMsPOuxtIiW5>$O zhG^E+J7ggD__Y)qY4hdrZB{;y`kB)mFO?k?_`Bq_EB?LH`-i-F?}PjVu=mGZ0(g8u z*15iX{aMZn;$oH4#Zx(3eul#-bx?Ba)FHe57Vl8P;jshp?O`s!_%WL^aG!+NU4L%D Q;*!nBsY#f5?#zY%0-uw77TX>bXz%xzFqQt3Q5!oZt6+Kj(bE=e)nCVpj6E50bJg zZ&u!bKp=?d3#gQpH{fY7nBm+odH|El+{X-J2XokLE}e!)`>+^6z910Tqs7S}7bM|j zOaMqA5cE6{2Q2{NAc=)g2p9qZV*oix=?w|n5|-q^Uulq$Q!dV3J6P{Z^a? zpe8opNTmJOIB3dhAT-$#rv>oViI-)NDikB}e|IJwP2q%xanW|n5H6F0(*?A}4p5}p zKlbkwWs0^Vqw#>IsvL;~5CIYnkHY}~RaFl6r-?TqkVNMH%gJ-~@PAM0JLJT7!)o)& zWzG{uPZ}y!D#c&5QWz((3BKE}Jej7Q&Tx9qW}H{^`=$7jjn1**z6%qPeE9&d@WxNO zExI1omD<`o>pou}=gmq}zpRlnB8AmASPs;6d^b9?F*j14I_0WJd=y|GZ;#eO1rBKkj?vBOb`wb&d)Ba>1@FHtXt;+Qf$aWq- zRj8zoYmHK`UvwW-9X%dxq`D7Yh0QYo5TdfKL&Bs0Nig_#2v|bEP6BK2{mP_x=?rfn zi7{z7gIuAuoa1;LjE@5vW<&OoRI09pr(iJ}*m0$R<@_Ty zxe)rodh}9X@4?=x(&rp2VgBziJn!+`t<@haD>_MQv+xts+O#v{IPGN9%B4+&?ePjD zlP8GUP2Tj;`S>K9dmlw9et*<^W621E@J(8ECze;*>W9q6kG`H{);80r3l3Lf(}{iL zQv5>h|<=)cO*FchSUtiClSI&+K$~a6O5>J|S%Zb!_NUPq%~zgyC7GY%r`~ zr?Ho|j~f`w<}m4O1~V+sKO`{3pHBOhOp9y(A+tiqBDufgozMu7Qm}Sml~A0 z5xxm9TIC4CFUnLlu@fnx-B%^iVvxiP0RTY25pkx#DnodJ*!(v`{(Qeo;(y7=ek;Sr z2{62l&>Ykc$u94fP` zWc2JYU$lI5VVT*U8X(FM8+|WQ(FjUa`^A0ZkYsI}&d*h&}XE z{l&8tQ6X!ZPQ9KTG!OK-CF>DTurkv#){(S4-^pu=ueSFGxmv%+KpE2!hhP0{twD6` z7?>_zFtZZ0kT??QYxP?PiDbkrt;7>w%9^Gs8J^>h(u%sroL*UKr6Q@VDZ~0+PBD&% zJJ2haUo_YL3Mt!AHAUP5GeyxD46b+@4bH$^H=Y~EPyzenW+CY1w~9S z3d|Oee*xf-Z8t6?9av*x4j^{%J6iY9_$ zL+8W%g2wF){5Mdw7b)En!LHN+fnho|rot)uk#WYCx_iw;b0babRI+ftNBi3yTVCPw zx%WEGP^RweK}6=|*jUM5rj`Ayl#-uV#BzN+nB#I)qUvI3`q|JbS3h_=GLL7zCIM19 zRT_vvohf&&*r8i)vE$g#v#x@%K=#c++rc3F@pj>CFnJG$8Y)GsieeUf7p4=JK%3-R z(l{dz%sG#gO1Iwj-Eg?Jdf@i#JCOcI+KoV#m#$)MiAjn_xc6eG;h;k; z9Lv1^(3Y)yt?uBbxhY@we$$OqgH@Db9|N(&-*6*r%!)Rx#w>ljjiJmz8%Oo-Q`7|S z{K4q;*(|Y;ug!|MDveD-QiyD!cDcD#4c;uokZ(cQjtVWkB~iB2zLgkDPUO z_*hizu%?gF8eKDHO2tsb&CBF{j($hoDwgq^CqI9{AlqY9E;Lg=Cw50h9oNoz?z{$` zKxmkM>UO&~v-a^3m)ZSaG)ObD5H}^G7k!(9oXZ0!e@grVGGoRlZhzPil!e;E8ml ZbJ Date: Thu, 27 Jul 2017 21:11:09 +0200 Subject: [PATCH 2/7] SPARK-1975 Self Signed certificates now will be accepted. --- .../certificates/SparkTrustManager.java | 60 +++++++++++++------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java index d296d3176..0e3809461 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java @@ -32,6 +32,7 @@ import java.security.cert.X509CRL; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.List; @@ -71,6 +72,7 @@ public class SparkTrustManager implements X509TrustManager { private boolean acceptSelfSigned; private CertStore crlStore; + private Collection crlCollection = new ArrayList<>(); private X509TrustManager exceptionsTrustManager; private Provider bcProvider = new BouncyCastleProvider(); // bc provider for path validation private KeyStore trustStore; @@ -109,25 +111,49 @@ public class SparkTrustManager implements X509TrustManager { } catch (CertificateException ex) { // in case when certificate isn't on exceptions list then make use of this Trust Manager - // check if certificate isn't self signed, self signed certificate still have to be in TrustStore to be - // accepted - if (chain.length == 1 && acceptSelfSigned == false) { - throw new CertificateException("SelfSigned certificate"); - } - // validate chain by date (expired/not valid yet) checkDateValidity(chain); - // validate certificate path - try { - validatePath(chain); - } catch (NoSuchAlgorithmException | KeyStoreException | InvalidAlgorithmParameterException - | CertPathValidatorException | CertPathBuilderException e) { - Log.error("Validating path failed", e); - throw new CertificateException("Certificate path validation failed", e); + // check if certificate isn't self signed, self signed certificate still have to be in TrustStore to be + // accepted + if (chain.length > 1) { + // validate certificate path + try { + validatePath(chain); + + } catch (NoSuchAlgorithmException | KeyStoreException | InvalidAlgorithmParameterException + | CertPathValidatorException | CertPathBuilderException e) { + Log.error("Validating path failed", e); + throw new CertificateException("Certificate path validation failed", e); + + } + } else if (chain.length == 1 && !acceptSelfSigned) { + // Self Signed certificate while it isn't accepted + throw new CertificateException("Self Signed certificate"); + + } else if (chain.length == 1 && acceptSelfSigned) { + // check if certificate is in Keystore and check CRL, but do not validate path as certificate is Self + // Signed important reminder: hostname validation must be also turned off to accept self signed + // certificate + List certList = new ArrayList<>(Arrays.asList(getAcceptedIssuers())); + if (!certList.contains(chain[0])) { + throw new CertificateException("Certificate not in the TrustStore"); + } + try { + loadCRL(chain); + for (X509CRL crl : crlCollection) { + if (crl.isRevoked(chain[0])) { + throw new CertificateException("Certificate is revoked"); + } + } + } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | CertStoreException + | CRLException | IOException e) { + Log.warning("Couldn't load CRL"); + } + }else { + throw new CertificateException("Certificate chain cannot be trusted"); } } - // check if have basic constraints } @Override @@ -195,9 +221,7 @@ public class SparkTrustManager implements X509TrustManager { loadCRL(chain); parameters.addCertStore(crlStore); if (checkOCSP) { - // check OCSP, important reminder if CRL is disabled then then OCSP will not work either, for - // reference: - // http://docs.oracle.com/javase/7/docs/technotes/guides/security/certpath/CertPathProgGuide.html#AppC + // check OCSP, important reminder if CRL is disabled then then OCSP will not work either // parameters.setCertPathCheckers(checkers); } @@ -290,8 +314,6 @@ public class SparkTrustManager implements X509TrustManager { private void loadCRL(X509Certificate[] chain) throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, CertStoreException, CRLException, CertificateException { - Collection crlCollection = new ArrayList<>(); - // for each certificate in chain for (X509Certificate cert : chain) { if (cert.getExtensionValue(Extension.cRLDistributionPoints.getId()) != null) { From c0631d21de3438bf106c7d28da39b7f96cb178fc Mon Sep 17 00:00:00 2001 From: Alameyo Date: Fri, 28 Jul 2017 01:50:29 +0200 Subject: [PATCH 3/7] Additional file path changes. --- .../sparkimpl/certificates/CertificateController.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java index 91f449398..d63432342 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java @@ -25,6 +25,8 @@ import javax.naming.ldap.LdapName; import javax.naming.ldap.Rdn; import javax.swing.JOptionPane; import javax.swing.table.DefaultTableModel; + +import org.jivesoftware.Spark; import org.jivesoftware.resource.Res; import org.jivesoftware.spark.ui.login.CertificateDialog; import org.jivesoftware.spark.ui.login.CertificatesManagerSettingsPanel; @@ -40,9 +42,9 @@ import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; */ public class CertificateController { - public final static File TRUSTED = new File(System.getProperty("user.dir") +"\\src\\main\\security\\truststore"); - public final static File BLACKLIST = new File(System.getProperty("user.dir") +"\\src\\main\\security\\blacklist"); - public final static File EXCEPTIONS = new File(System.getProperty("user.dir") +"\\src\\main\\security\\exceptions"); + public final static File TRUSTED = new File(Spark.getSparkUserHome() + File.separator + "security" + File.separator + "truststore"); + public final static File BLACKLIST = new File(Spark.getSparkUserHome() + File.separator + "security" + File.separator + "blacklist"); + public final static File EXCEPTIONS = new File(Spark.getSparkUserHome() + File.separator + "security" + File.separator + "exceptions"); public final static char[] passwd = "changeit".toCharArray(); From a17fb9e3547500552b3bf732d03655877bebbce9 Mon Sep 17 00:00:00 2001 From: Alameyo Date: Fri, 28 Jul 2017 02:16:59 +0200 Subject: [PATCH 4/7] Now information if certificate is Self Signed is determined comparing subject name and issuer name (have to be equal). --- .../certificates/SparkTrustManager.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java index 0e3809461..92ec65239 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java @@ -47,6 +47,7 @@ import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; +import org.bouncycastle.jcajce.provider.asymmetric.X509; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; @@ -116,7 +117,7 @@ public class SparkTrustManager implements X509TrustManager { // check if certificate isn't self signed, self signed certificate still have to be in TrustStore to be // accepted - if (chain.length > 1) { + if (isSelfSigned(chain) == false) { // validate certificate path try { validatePath(chain); @@ -127,11 +128,11 @@ public class SparkTrustManager implements X509TrustManager { throw new CertificateException("Certificate path validation failed", e); } - } else if (chain.length == 1 && !acceptSelfSigned) { + } else if (isSelfSigned(chain) && !acceptSelfSigned) { // Self Signed certificate while it isn't accepted throw new CertificateException("Self Signed certificate"); - } else if (chain.length == 1 && acceptSelfSigned) { + } else if (isSelfSigned(chain) && acceptSelfSigned) { // check if certificate is in Keystore and check CRL, but do not validate path as certificate is Self // Signed important reminder: hostname validation must be also turned off to accept self signed // certificate @@ -186,6 +187,17 @@ public class SparkTrustManager implements X509TrustManager { return X509Certs; } + /** + * Return true if the certificate chain contain only one Self Signed certificate + */ + private boolean isSelfSigned(X509Certificate[] chain) { + if(chain[0].getIssuerX500Principal().getName().equals(chain[0].getSubjectX500Principal().getName())){ + return true; + } else { + return false; + } + } + /** * Validate certificate path * From bf2570bd123ae0f768b8bddd8cc5111bbf2a9fba Mon Sep 17 00:00:00 2001 From: Alameyo Date: Sat, 29 Jul 2017 14:40:28 +0200 Subject: [PATCH 5/7] SPARK-1977 Support for OCSP. Also removed Bouncy Castle provider for PKIX validator to use default one. --- .../certificates/SparkTrustManager.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java index 92ec65239..d25a84cff 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java @@ -9,8 +9,6 @@ import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.Security; import java.security.cert.CRLException; import java.security.cert.CertPath; import java.security.cert.CertPathBuilder; @@ -28,12 +26,14 @@ import java.security.cert.CertificateRevokedException; import java.security.cert.CollectionCertStoreParameters; import java.security.cert.PKIXBuilderParameters; import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.PKIXRevocationChecker; import java.security.cert.X509CRL; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.EnumSet; import java.util.Enumeration; import java.util.List; @@ -47,8 +47,7 @@ import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralNames; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; -import org.bouncycastle.jcajce.provider.asymmetric.X509; -import org.bouncycastle.jce.provider.BouncyCastleProvider; + import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; import org.jivesoftware.sparkimpl.settings.local.SettingsManager; @@ -75,13 +74,11 @@ public class SparkTrustManager implements X509TrustManager { private CertStore crlStore; private Collection crlCollection = new ArrayList<>(); private X509TrustManager exceptionsTrustManager; - private Provider bcProvider = new BouncyCastleProvider(); // bc provider for path validation private KeyStore trustStore; private CertificateController certControll = new CertificateController(localPref); public SparkTrustManager() { exceptionsTrustManager = new SparkExceptionsTrustManager(); - Security.addProvider(bcProvider); checkCRL = localPref.isCheckCRL(); checkOCSP = localPref.isCheckOCSP(); @@ -211,8 +208,9 @@ public class SparkTrustManager implements X509TrustManager { private void validatePath(X509Certificate[] chain) throws NoSuchAlgorithmException, KeyStoreException, InvalidAlgorithmParameterException, CertPathValidatorException, CertPathBuilderException, CertificateException { - - CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX", bcProvider); + + // PKIX algorithm is defined in rfc3280 + CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX"); CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX"); X509CertSelector certSelector = new X509CertSelector(); @@ -227,15 +225,24 @@ public class SparkTrustManager implements X509TrustManager { PKIXBuilderParameters parameters = new PKIXBuilderParameters(trustStore, certSelector); if (acceptRevoked == false) { - if (checkCRL) { - // check add CRL store and download CRL list to this store. + // check OCSP, CRL serve as backup + if (checkOCSP && checkCRL) { + // OCSP checking is done according to Java PKI Programmer's Guide, PKIXRevocationChecker was added in Java 8: + // https://docs.oracle.com/javase/8/docs/technotes/guides/security/certpath/CertPathProgGuide.html#PKIXRevocationChecker + PKIXRevocationChecker checker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker(); + // soft fail option mean that OCSP or CRL must pass validation, in case when OCSP cannot be + // validated it will validate CRL and then if both cannot be checked it will fail + checker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.SOFT_FAIL)); + parameters.addCertPathChecker(checker); + // will use PKIXRevocationChecker instead of the default revocation checker + parameters.setRevocationEnabled(false); + } else if (!checkOCSP && checkCRL) { + // check only CRL, need custom implementation + // add CRL store and download CRL list to this store. try { loadCRL(chain); parameters.addCertStore(crlStore); - if (checkOCSP) { - // check OCSP, important reminder if CRL is disabled then then OCSP will not work either - // parameters.setCertPathCheckers(checkers); - } + parameters.setRevocationEnabled(true); } catch (CertStoreException | IOException | CRLException e) { Log.error("Couldn't load crl", e); @@ -243,6 +250,7 @@ public class SparkTrustManager implements X509TrustManager { } } else { + //revocation checks disabled parameters.setRevocationEnabled(false); } From 6c4c7315f087bff7e6de9a4c965621cd9e6737d0 Mon Sep 17 00:00:00 2001 From: Alameyo Date: Thu, 3 Aug 2017 18:30:22 +0200 Subject: [PATCH 6/7] Changes for self signed certificate, soft fail policy, not Valid Yet and some other minor changes. --- .../CertificatesManagerSettingsPanel.java | 144 ++++++++++++------ .../certificates/SparkTrustManager.java | 17 ++- .../settings/local/LocalPreferences.java | 16 ++ .../main/resources/i18n/spark_i18n.properties | 2 + 4 files changed, 127 insertions(+), 52 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java index 5226adfe7..2f879411f 100644 --- a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java +++ b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java @@ -65,6 +65,8 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi private JCheckBox acceptSelfSigned = new JCheckBox(); private JCheckBox checkCRL = new JCheckBox(); private JCheckBox checkOCSP = new JCheckBox(); + private JCheckBox allowSoftFail = new JCheckBox(); + private JCheckBox acceptNotValidYet = new JCheckBox(); private JButton showCert = new JButton(); private JFileChooser fileChooser = new JFileChooser(); private JButton fileButton = new JButton(); @@ -114,19 +116,24 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi ResourceUtils.resButton(acceptAll, Res.getString("checkbox.accept.all")); ResourceUtils.resButton(acceptExpired, Res.getString("checkbox.accept.expired")); + ResourceUtils.resButton(acceptNotValidYet, Res.getString("checkbox.accept.not.valid.yet")); ResourceUtils.resButton(acceptRevoked, Res.getString("checkbox.accept.revoked")); ResourceUtils.resButton(acceptSelfSigned, Res.getString("checkbox.accept.self.signed")); ResourceUtils.resButton(checkCRL, Res.getString("checkbox.check.crl")); ResourceUtils.resButton(checkOCSP, Res.getString("checkbox.check.ocsp")); + ResourceUtils.resButton(allowSoftFail, Res.getString("checkbox.allow.soft.fail")); ResourceUtils.resButton(showCert, Res.getString("button.show.certificate")); ResourceUtils.resButton(fileButton, Res.getString("label.choose.file")); acceptAll.setSelected(localPreferences.isAcceptAllCertificates()); acceptSelfSigned.setSelected(localPreferences.isAcceptSelfSigned()); acceptExpired.setSelected(localPreferences.isAcceptExpired()); + acceptNotValidYet.setSelected(localPreferences.isAcceptNotValidYet()); acceptRevoked.setSelected(localPreferences.isAcceptRevoked()); checkCRL.setSelected(localPreferences.isCheckCRL()); checkOCSP.setSelected(localPreferences.isCheckOCSP()); + allowSoftFail.setSelected(localPreferences.isAllowSoftFail()); + acceptAll.addActionListener(this); certTable.addMouseListener(this); @@ -135,67 +142,115 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi showCert.addActionListener(this); fileButton.addActionListener(this); checkCRL.addActionListener(this); + checkOCSP.addActionListener(this); acceptRevoked.addActionListener(this); checkCRL.setEnabled(!acceptRevoked.isSelected()); checkOCSP.setEnabled(checkCRL.isSelected()); + allowSoftFail.setEnabled(checkOCSP.isSelected()); filePanel.setLayout(new GridBagLayout()); filePanel.add(fileButton, new GridBagConstraints(0, 0, 2, 1, 1.0, 1.0, WEST, HORIZONTAL, DEFAULT_INSETS, 40, 0)); filePanel.setBorder( BorderFactory.createTitledBorder(Res.getString("label.certificate.add.certificate.to.truststore"))); - add(scrollPane, new GridBagConstraints(0, 0, 6, 1, 1.0, 1.0, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - add(acceptAll, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - add(acceptSelfSigned, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - add(acceptExpired, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - add(acceptRevoked, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - add(checkCRL, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - add(checkOCSP, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - add(showCert, new GridBagConstraints(2, 1, 2, 1, 0.0, 0.0, WEST, HORIZONTAL, DEFAULT_INSETS, 40, 0)); - add(filePanel, new GridBagConstraints(2, 2, 2, 4, 0.0, 0.0, WEST, HORIZONTAL, DEFAULT_INSETS, 40, 0)); + add(scrollPane, new GridBagConstraints(0, 0, 6, 1, 1.0, 1.0, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + + add(acceptAll, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + add(acceptSelfSigned, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + + add(acceptExpired, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + add(acceptNotValidYet, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + + add(acceptRevoked, new GridBagConstraints(2, 1, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + add(checkCRL, new GridBagConstraints(3, 1, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + + add(checkOCSP, new GridBagConstraints(2, 2, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + add(allowSoftFail, new GridBagConstraints(3, 2, 1, 1, 0.0, 0.5, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + + add(showCert, new GridBagConstraints(4, 1, 2, 1, 0.0, 0.0, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); + add(filePanel, new GridBagConstraints(4, 2, 2, 4, 0.0, 0.0, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); } - @Override - public void actionPerformed(ActionEvent e) { - if (e.getSource() == acceptAll && acceptAll.isSelected()) { - acceptSelfSigned.setSelected(true); - acceptExpired.setSelected(true); - acceptRevoked.setSelected(true); + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == acceptAll) { + if (acceptAll.isSelected()) { - acceptSelfSigned.setEnabled(false); - acceptExpired.setEnabled(false); - acceptRevoked.setEnabled(false); - } else if (e.getSource() == acceptAll && !acceptAll.isSelected()) { - acceptSelfSigned.setEnabled(true); - acceptExpired.setEnabled(true); - acceptRevoked.setEnabled(true); - } else if (e.getSource() == showCert) { - certControll.showCertificate(); - } else if (e.getSource() == fileButton) { - addCertificate(); - } else if (e.getSource() == checkCRL && checkCRL.isSelected()) { - checkOCSP.setEnabled(true); - } else if (e.getSource() == checkCRL && !checkCRL.isSelected()) { - checkOCSP.setSelected(false); - checkOCSP.setEnabled(false); - } else if (e.getSource() == acceptRevoked && acceptRevoked.isSelected()) { - checkCRL.setSelected(false); - checkOCSP.setSelected(false); + acceptSelfSigned.setSelected(true); + acceptExpired.setSelected(true); + acceptNotValidYet.setSelected(true); + acceptRevoked.setSelected(true); + checkCRL.setSelected(false); + checkOCSP.setSelected(false); + allowSoftFail.setSelected(false); - checkCRL.setEnabled(false); - checkOCSP.setEnabled(false); - } else if (e.getSource() == acceptRevoked && !acceptRevoked.isSelected()) { - checkCRL.setEnabled(true); + acceptSelfSigned.setEnabled(false); + acceptExpired.setEnabled(false); + acceptNotValidYet.setEnabled(false); + acceptRevoked.setEnabled(false); + checkCRL.setEnabled(false); + checkOCSP.setEnabled(false); + allowSoftFail.setEnabled(false); + } else if (!acceptAll.isSelected()) { + + acceptSelfSigned.setEnabled(true); + acceptExpired.setEnabled(true); + acceptNotValidYet.setEnabled(true); + acceptRevoked.setEnabled(true); + checkCRL.setEnabled(true); + checkOCSP.setEnabled(true); + allowSoftFail.setEnabled(true); + + } + } else if (e.getSource() == showCert) { + certControll.showCertificate(); + + } else if (e.getSource() == fileButton) { + addCertificate(); + + } else if (e.getSource() == checkCRL) { + + if (checkCRL.isSelected()) { + + checkOCSP.setEnabled(true); + allowSoftFail.setEnabled(true); + } else if (!checkCRL.isSelected()) { + + checkOCSP.setSelected(false); + checkOCSP.setEnabled(false); + allowSoftFail.setEnabled(false); + } + + } else if (e.getSource() == acceptRevoked) { + if (acceptRevoked.isSelected()) { + + checkCRL.setSelected(false); + checkOCSP.setSelected(false); + + checkCRL.setEnabled(false); + checkOCSP.setEnabled(false); + } else if (!acceptRevoked.isSelected()) { + checkCRL.setEnabled(true); + } + } else if (e.getSource() == checkOCSP) { + if (checkOCSP.isSelected()) { + + allowSoftFail.setEnabled(true); + } else if (!checkOCSP.isSelected()) { + + allowSoftFail.setEnabled(false); + allowSoftFail.setSelected(false); + } } } - @Override - public void mouseClicked(MouseEvent e) { + @Override + public void mouseClicked(MouseEvent e) { - } + } - @Override - public void mouseEntered(MouseEvent e) { + @Override + public void mouseEntered(MouseEvent e) { } @@ -277,12 +332,13 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi public void saveSettings() { localPreferences.setAcceptExpired(acceptExpired.isSelected()); + localPreferences.setAcceptNotValidYet(acceptNotValidYet.isSelected()); localPreferences.setAcceptSelfSigned(acceptSelfSigned.isSelected()); localPreferences.setAcceptRevoked(acceptRevoked.isSelected()); localPreferences.setAcceptAllCertificates(acceptAll.isSelected()); localPreferences.setCheckCRL(checkCRL.isSelected()); localPreferences.setCheckOCSP(checkOCSP.isSelected()); - + localPreferences.setAllowSoftFail(allowSoftFail.isSelected()); SettingsManager.saveSettings(); } } diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java index d25a84cff..e17efbafd 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkTrustManager.java @@ -70,6 +70,7 @@ public class SparkTrustManager implements X509TrustManager { private boolean acceptNotValidYet; private boolean acceptRevoked; private boolean acceptSelfSigned; + private boolean allowSoftFail; private CertStore crlStore; private Collection crlCollection = new ArrayList<>(); @@ -83,10 +84,11 @@ public class SparkTrustManager implements X509TrustManager { checkCRL = localPref.isCheckCRL(); checkOCSP = localPref.isCheckOCSP(); acceptExpired = localPref.isAcceptExpired(); - // acceptNotValidYet = localPref.isAcceptNotValidYet(); + acceptNotValidYet = localPref.isAcceptNotValidYet(); acceptRevoked = localPref.isAcceptRevoked(); acceptSelfSigned = localPref.isAcceptSelfSigned(); - + allowSoftFail = localPref.isAllowSoftFail(); + loadTrustStore(); } @@ -188,11 +190,8 @@ public class SparkTrustManager implements X509TrustManager { * Return true if the certificate chain contain only one Self Signed certificate */ private boolean isSelfSigned(X509Certificate[] chain) { - if(chain[0].getIssuerX500Principal().getName().equals(chain[0].getSubjectX500Principal().getName())){ - return true; - } else { - return false; - } + return chain[0].getIssuerX500Principal().getName().equals(chain[0].getSubjectX500Principal().getName()) + && chain.length == 1; } /** @@ -232,7 +231,9 @@ public class SparkTrustManager implements X509TrustManager { PKIXRevocationChecker checker = (PKIXRevocationChecker) certPathBuilder.getRevocationChecker(); // soft fail option mean that OCSP or CRL must pass validation, in case when OCSP cannot be // validated it will validate CRL and then if both cannot be checked it will fail - checker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.SOFT_FAIL)); + if (allowSoftFail) { + checker.setOptions(EnumSet.of(PKIXRevocationChecker.Option.SOFT_FAIL)); + } parameters.addCertPathChecker(checker); // will use PKIXRevocationChecker instead of the default revocation checker parameters.setRevocationEnabled(false); diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java b/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java index 530a1dd91..c53b936af 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java @@ -1445,6 +1445,14 @@ public class LocalPreferences { props.setProperty("acceptExpired", Boolean.toString(acceptExpired)); } + public boolean isAcceptNotValidYet() { + return Boolean.parseBoolean(props.getProperty("acceptNotValidYet", "false")); + } + + public void setAcceptNotValidYet(boolean acceptNotValidYet) { + props.setProperty("acceptNotValidYet", Boolean.toString(acceptNotValidYet)); + } + public boolean isCheckCRL() { return Boolean.parseBoolean(props.getProperty("checkCRL", "true")); } @@ -1460,5 +1468,13 @@ public class LocalPreferences { public void setCheckOCSP(boolean checkOCSP) { props.setProperty("checkOCSP", Boolean.toString(checkOCSP)); } + public boolean isAllowSoftFail() { + return Boolean.parseBoolean(props.getProperty("allowSoftFail", "true")); + } + public void setAllowSoftFail(boolean allowSoftFail) { + props.setProperty("allowSoftFail", Boolean.toString(allowSoftFail)); + } + + } diff --git a/core/src/main/resources/i18n/spark_i18n.properties b/core/src/main/resources/i18n/spark_i18n.properties index 114a3818f..a204ac145 100644 --- a/core/src/main/resources/i18n/spark_i18n.properties +++ b/core/src/main/resources/i18n/spark_i18n.properties @@ -393,10 +393,12 @@ checkbox.accept.all.certificates = Accept all certificates (self-signed/expired/ checkbox.disable.hostname.verification = Disable certificate hostname verification (not recommended) checkbox.accept.all = Accept all checkbox.accept.expired = Accept expired +checkbox.accept.not.valid.yet = Accept not valid yet checkbox.accept.self.signed = Accept self-signed checkbox.accept.revoked = Accept revoked checkbox.check.crl = Check CRL checkbox.check.ocsp = Check OCSP +checkbox.allow.soft.fail = Allow soft fail policy checkbox.on.exception.list = On the exception list radio.encryptionmode.required = Required radio.encryptionmode.ifpossible = If possible From 8fc3d2c5cda067811ec6219ebd1f798afd76a1c2 Mon Sep 17 00:00:00 2001 From: Alameyo Date: Sat, 5 Aug 2017 00:06:02 +0200 Subject: [PATCH 7/7] Removed setting port for STARTTLS, fixed enabled on start checkboxes. Added setUp method to SPARKSSLContext, removed acceptAll from Security tab as there is already Accept All checkbox in certificates tab. --- .../org/jivesoftware/AccountCreationWizard.java | 10 +--------- .../main/java/org/jivesoftware/LoginDialog.java | 11 +---------- .../login/CertificatesManagerSettingsPanel.java | 8 ++++---- .../ui/login/SecurityLoginSettingsPanel.java | 12 +----------- .../sparkimpl/certificates/SparkSSLContext.java | 17 +++++++++++++++++ 5 files changed, 24 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java index e3731ac22..73f68ebfe 100644 --- a/core/src/main/java/org/jivesoftware/AccountCreationWizard.java +++ b/core/src/main/java/org/jivesoftware/AccountCreationWizard.java @@ -34,7 +34,6 @@ import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.spark.util.SwingWorker; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.certificates.SparkSSLContext; -import org.jivesoftware.sparkimpl.certificates.SparkTrustManager; import org.jivesoftware.sparkimpl.settings.local.LocalPreferences; import org.jivesoftware.sparkimpl.settings.local.SettingsManager; import org.jxmpp.util.XmppStringUtils; @@ -45,9 +44,6 @@ import java.awt.*; import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.Security; /** * Allows the creation of accounts on an XMPP server. @@ -362,14 +358,10 @@ public class AccountCreationWizard extends JPanel { } if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useOldSSL) { - builder.setPort(5222); // This use STARTTLS which starts initially plain connection to upgrade it to TLS, it use the same port as // plain connections which is 5222. try { - Provider bcProvider = new BouncyCastleJsseProvider(); - Security.addProvider(bcProvider); - SSLContext context = SparkSSLContext.getInstance("TLS"); - context.init(null, SparkTrustManager.getTrustManagerList(), new SecureRandom()); + SSLContext context = SparkSSLContext.setUpContext(); builder.setCustomSSLContext(context); builder.setSecurityMode( securityMode ); } catch (NoSuchAlgorithmException | KeyManagementException e) { diff --git a/core/src/main/java/org/jivesoftware/LoginDialog.java b/core/src/main/java/org/jivesoftware/LoginDialog.java index 5bdc6218d..55332aadc 100644 --- a/core/src/main/java/org/jivesoftware/LoginDialog.java +++ b/core/src/main/java/org/jivesoftware/LoginDialog.java @@ -16,7 +16,6 @@ package org.jivesoftware; -import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; @@ -47,7 +46,6 @@ import org.jivesoftware.spark.util.SwingWorker; import org.jivesoftware.spark.util.log.Log; import org.jivesoftware.sparkimpl.plugin.manager.Enterprise; import org.jivesoftware.sparkimpl.certificates.SparkSSLContext; -import org.jivesoftware.sparkimpl.certificates.SparkTrustManager; import org.jivesoftware.sparkimpl.plugin.layout.LayoutSettings; import org.jivesoftware.sparkimpl.plugin.layout.LayoutSettingsManager; import org.jivesoftware.sparkimpl.settings.JiveInfo; @@ -81,9 +79,6 @@ import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.Principal; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.Security; import java.util.*; import java.util.List; @@ -285,14 +280,10 @@ public class LoginDialog { } if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useOldSSL) { - builder.setPort(5222); // This use STARTTLS which starts initially plain connection to upgrade it to TLS, it use the same port as // plain connections which is 5222. try { - Provider bcProvider = new BouncyCastleJsseProvider(); - Security.addProvider(bcProvider); - SSLContext context = SparkSSLContext.getInstance("TLS"); - context.init(null, SparkTrustManager.getTrustManagerList(), new SecureRandom()); + SSLContext context = SparkSSLContext.setUpContext(); builder.setCustomSSLContext(context); builder.setSecurityMode( securityMode ); } catch (NoSuchAlgorithmException | KeyManagementException e) { diff --git a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java index 2f879411f..344e23b62 100644 --- a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java +++ b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java @@ -144,6 +144,10 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi checkCRL.addActionListener(this); checkOCSP.addActionListener(this); acceptRevoked.addActionListener(this); + acceptExpired.setEnabled(!acceptAll.isSelected()); + acceptNotValidYet.setEnabled(!acceptAll.isSelected()); + acceptRevoked.setEnabled(!acceptAll.isSelected()); + acceptSelfSigned.setEnabled(!acceptAll.isSelected()); checkCRL.setEnabled(!acceptRevoked.isSelected()); checkOCSP.setEnabled(checkCRL.isSelected()); allowSoftFail.setEnabled(checkOCSP.isSelected()); @@ -197,9 +201,6 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi acceptExpired.setEnabled(true); acceptNotValidYet.setEnabled(true); acceptRevoked.setEnabled(true); - checkCRL.setEnabled(true); - checkOCSP.setEnabled(true); - allowSoftFail.setEnabled(true); } } else if (e.getSource() == showCert) { @@ -213,7 +214,6 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi if (checkCRL.isSelected()) { checkOCSP.setEnabled(true); - allowSoftFail.setEnabled(true); } else if (!checkCRL.isSelected()) { checkOCSP.setSelected(false); diff --git a/core/src/main/java/org/jivesoftware/spark/ui/login/SecurityLoginSettingsPanel.java b/core/src/main/java/org/jivesoftware/spark/ui/login/SecurityLoginSettingsPanel.java index 53dfad841..c21fb787a 100644 --- a/core/src/main/java/org/jivesoftware/spark/ui/login/SecurityLoginSettingsPanel.java +++ b/core/src/main/java/org/jivesoftware/spark/ui/login/SecurityLoginSettingsPanel.java @@ -24,9 +24,6 @@ import org.jivesoftware.sparkimpl.settings.local.SettingsManager; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - import static java.awt.GridBagConstraints.*; /** @@ -49,7 +46,6 @@ public class SecurityLoginSettingsPanel extends JPanel // Checkbox that toggles between 'old' style SSL (socket encryption, typically on port 5223), or STARTTLS. A check indicates 'old' behavior. private JCheckBox useSSLBox; - private JCheckBox acceptAllCertificatesBox; private JCheckBox disableHostnameVerificationBox; public SecurityLoginSettingsPanel( LocalPreferences localPreferences, JDialog optionsDialog ) @@ -73,7 +69,6 @@ public class SecurityLoginSettingsPanel extends JPanel modeDisabledRadio.setToolTipText( Res.getString( "tooltip.encryptionmode.disabled" ) ); useSSLBox = new JCheckBox(); - acceptAllCertificatesBox = new JCheckBox(); disableHostnameVerificationBox = new JCheckBox(); // .. Set labels/text for all the components. @@ -81,7 +76,6 @@ public class SecurityLoginSettingsPanel extends JPanel ResourceUtils.resButton( modeIfPossibleRadio, Res.getString( "radio.encryptionmode.ifpossible" ) ); ResourceUtils.resButton( modeDisabledRadio, Res.getString( "radio.encryptionmode.disabled" ) ); ResourceUtils.resButton( useSSLBox, Res.getString( "label.old.ssl" ) ); - ResourceUtils.resButton( acceptAllCertificatesBox, Res.getString( "checkbox.accept.all.certificates" ) ); ResourceUtils.resButton( disableHostnameVerificationBox, Res.getString( "checkbox.disable.hostname.verification" ) ); // ... add the radio buttons to a group to make them interdependent. @@ -94,7 +88,6 @@ public class SecurityLoginSettingsPanel extends JPanel modeDisabledRadio.addChangeListener( e -> { final boolean encryptionPossible = !modeDisabledRadio.isSelected(); useSSLBox.setEnabled( encryptionPossible ); - acceptAllCertificatesBox.setEnabled( encryptionPossible ); disableHostnameVerificationBox.setEnabled( encryptionPossible ); } ); @@ -103,7 +96,6 @@ public class SecurityLoginSettingsPanel extends JPanel modeIfPossibleRadio.setSelected( localPreferences.getSecurityMode() == ConnectionConfiguration.SecurityMode.ifpossible ); modeDisabledRadio.setSelected( localPreferences.getSecurityMode() == ConnectionConfiguration.SecurityMode.disabled ); useSSLBox.setSelected( localPreferences.isSSL() ); - acceptAllCertificatesBox.setSelected( localPreferences.isAcceptAllCertificates() ); disableHostnameVerificationBox.setSelected( localPreferences.isDisableHostnameVerification() ); // ... place the components on the titled-border panel. @@ -116,8 +108,7 @@ public class SecurityLoginSettingsPanel extends JPanel add( encryptionModePanel, new GridBagConstraints( 0, 0, 1, 1, 1.0, 0.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) ); // ... place the other components under the titled-border panel. - add( acceptAllCertificatesBox, new GridBagConstraints( 0, 1, 1, 1, 0.0, 0.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) ); - add( disableHostnameVerificationBox, new GridBagConstraints( 0, 2, 1, 1, 0.0, 1.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) ); + add( disableHostnameVerificationBox, new GridBagConstraints( 0, 1, 1, 1, 0.0, 1.0, NORTHWEST, HORIZONTAL, DEFAULT_INSETS, 0, 0 ) ); } public boolean validate_settings() @@ -140,7 +131,6 @@ public class SecurityLoginSettingsPanel extends JPanel localPreferences.setSecurityMode( ConnectionConfiguration.SecurityMode.disabled ); } localPreferences.setSSL( useSSLBox.isSelected() ); - localPreferences.setAcceptAllCertificates( acceptAllCertificatesBox.isSelected() ); localPreferences.setDisableHostnameVerification( disableHostnameVerificationBox.isSelected() ); SettingsManager.saveSettings(); } diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java index eb09a1355..844000207 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/SparkSSLContext.java @@ -1,6 +1,10 @@ package org.jivesoftware.sparkimpl.certificates; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.Provider; +import java.security.SecureRandom; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContextSpi; @@ -12,4 +16,17 @@ public class SparkSSLContext extends SSLContext { // TODO Auto-generated constructor stub } + /** + * Create SSLContext and initialize it + * + * @return initialized SSL context with BouncyCastleProvider + * @throws KeyManagementException + * @throws NoSuchAlgorithmException + * @throws NoSuchProviderException + */ + public static SSLContext setUpContext() throws KeyManagementException, NoSuchAlgorithmException { + SSLContext context = SparkSSLContext.getInstance("TLS"); + context.init(null, SparkTrustManager.getTrustManagerList(), new SecureRandom()); + return context; + } }