mirror of
https://github.com/igniterealtime/Spark.git
synced 2026-03-09 17:15:59 +00:00
Merge pull request #356 from Alameyo/SSLContext
SPARK-1966, SPARK-1952, SPARK-1969, SPARK-1970, SPARK-1971 and partially SPARK-1968
This commit is contained in:
@ -254,6 +254,13 @@
|
||||
<artifactId>bcpkix-jdk15on</artifactId>
|
||||
<version>1.57</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>
|
||||
org.bouncycastle.bctls-jdk15on.1.57.org.bouncycastle
|
||||
</groupId>
|
||||
<artifactId>bctls-jdk15on</artifactId>
|
||||
<version>1.57</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
|
||||
@ -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,10 +33,12 @@ 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.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;
|
||||
@ -353,7 +356,19 @@ public class AccountCreationWizard extends JPanel {
|
||||
{
|
||||
builder.setHost( localPreferences.getXmppHost() );
|
||||
}
|
||||
|
||||
|
||||
if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useOldSSL) {
|
||||
// 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 {
|
||||
SSLContext context = SparkSSLContext.setUpContext();
|
||||
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) {
|
||||
|
||||
@ -44,9 +44,10 @@ 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.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 +58,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;
|
||||
@ -277,6 +279,18 @@ public class LoginDialog {
|
||||
builder.setProxyInfo( proxyInfo );
|
||||
}
|
||||
|
||||
if (securityMode != ConnectionConfiguration.SecurityMode.disabled && !useOldSSL) {
|
||||
// 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 {
|
||||
SSLContext context = SparkSSLContext.setUpContext();
|
||||
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.
|
||||
|
||||
@ -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
|
||||
@ -64,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();
|
||||
@ -76,6 +79,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,64 +116,141 @@ 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(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);
|
||||
certTable.getModel().addTableModelListener(this);
|
||||
showCert.setEnabled(false);
|
||||
showCert.addActionListener(this);
|
||||
fileButton.addActionListener(this);
|
||||
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());
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
acceptSelfSigned.setSelected(true);
|
||||
acceptExpired.setSelected(true);
|
||||
acceptNotValidYet.setSelected(true);
|
||||
acceptRevoked.setSelected(true);
|
||||
checkCRL.setSelected(false);
|
||||
checkOCSP.setSelected(false);
|
||||
allowSoftFail.setSelected(false);
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
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);
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
} else if (e.getSource() == showCert) {
|
||||
certControll.showCertificate();
|
||||
|
||||
} else if (e.getSource() == fileButton) {
|
||||
addCertificate();
|
||||
|
||||
} else if (e.getSource() == checkCRL) {
|
||||
|
||||
if (checkCRL.isSelected()) {
|
||||
|
||||
checkOCSP.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 mouseEntered(MouseEvent e) {
|
||||
|
||||
}
|
||||
|
||||
@ -248,4 +329,16 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,6 +148,7 @@ public class LoginSettingDialog implements PropertyChangeListener
|
||||
proxyPanel.saveSettings();
|
||||
ssoPanel.saveSettings();
|
||||
pkiPanel.saveSettings();
|
||||
certManager.saveSettings();
|
||||
SettingsManager.saveSettings();
|
||||
optionsDialog.setVisible( false );
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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,18 +42,17 @@ 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 static String trustStorePath;
|
||||
private final static char[] passwd = "changeit".toCharArray();
|
||||
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();
|
||||
|
||||
|
||||
private List<CertificateModel> certificates = new ArrayList<>(); // contain all certificates from all keystores
|
||||
private List<CertificateModel> exemptedCertificates = new ArrayList<>(); // contain only certificates from exempted list
|
||||
private List<CertificateModel> 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 +65,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 +109,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 +136,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 +173,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 +198,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 +236,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 +289,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 +333,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 +369,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 +386,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 +415,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);
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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<String> 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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
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;
|
||||
|
||||
public class SparkSSLContext extends SSLContext {
|
||||
|
||||
protected SparkSSLContext(SSLContextSpi contextSpi, Provider provider, String protocol) {
|
||||
super(contextSpi, provider, protocol);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,408 @@
|
||||
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.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.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;
|
||||
|
||||
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.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 boolean allowSoftFail;
|
||||
|
||||
private CertStore crlStore;
|
||||
private Collection<X509CRL> crlCollection = new ArrayList<>();
|
||||
private X509TrustManager exceptionsTrustManager;
|
||||
private KeyStore trustStore;
|
||||
private CertificateController certControll = new CertificateController(localPref);
|
||||
|
||||
public SparkTrustManager() {
|
||||
exceptionsTrustManager = new SparkExceptionsTrustManager();
|
||||
|
||||
checkCRL = localPref.isCheckCRL();
|
||||
checkOCSP = localPref.isCheckOCSP();
|
||||
acceptExpired = localPref.isAcceptExpired();
|
||||
acceptNotValidYet = localPref.isAcceptNotValidYet();
|
||||
acceptRevoked = localPref.isAcceptRevoked();
|
||||
acceptSelfSigned = localPref.isAcceptSelfSigned();
|
||||
allowSoftFail = localPref.isAllowSoftFail();
|
||||
|
||||
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
|
||||
|
||||
// validate chain by date (expired/not valid yet)
|
||||
checkDateValidity(chain);
|
||||
|
||||
// check if certificate isn't self signed, self signed certificate still have to be in TrustStore to be
|
||||
// accepted
|
||||
if (isSelfSigned(chain) == false) {
|
||||
// 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 (isSelfSigned(chain) && !acceptSelfSigned) {
|
||||
// Self Signed certificate while it isn't accepted
|
||||
throw new CertificateException("Self Signed certificate");
|
||||
|
||||
} else if (isSelfSigned(chain) && acceptSelfSigned) {
|
||||
// check if certificate is in Keystore and check CRL, but do not validate path as certificate is Self
|
||||
// Signed important reminder: hostname validation must be also turned off to accept self signed
|
||||
// certificate
|
||||
List<X509Certificate> certList = new ArrayList<>(Arrays.asList(getAcceptedIssuers()));
|
||||
if (!certList.contains(chain[0])) {
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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<String> 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the certificate chain contain only one Self Signed certificate
|
||||
*/
|
||||
private boolean isSelfSigned(X509Certificate[] chain) {
|
||||
return chain[0].getIssuerX500Principal().getName().equals(chain[0].getSubjectX500Principal().getName())
|
||||
&& chain.length == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
// PKIX algorithm is defined in rfc3280
|
||||
CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
|
||||
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) {
|
||||
// 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
|
||||
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);
|
||||
} 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);
|
||||
parameters.setRevocationEnabled(true);
|
||||
|
||||
} catch (CertStoreException | IOException | CRLException e) {
|
||||
Log.error("Couldn't load crl", e);
|
||||
throw new CertificateException();
|
||||
}
|
||||
|
||||
} else {
|
||||
//revocation checks disabled
|
||||
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 {
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -1420,5 +1420,61 @@ 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 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"));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
public boolean isAllowSoftFail() {
|
||||
return Boolean.parseBoolean(props.getProperty("allowSoftFail", "true"));
|
||||
}
|
||||
|
||||
public void setAllowSoftFail(boolean allowSoftFail) {
|
||||
props.setProperty("allowSoftFail", Boolean.toString(allowSoftFail));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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.invalid = Accept invalid
|
||||
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
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user