diff options
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | NEWS | 1 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/resources/Messages.properties | 3 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java | 6 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/security/CertificateUtils.java | 49 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java | 38 |
6 files changed, 108 insertions, 5 deletions
@@ -1,3 +1,19 @@ +2011-09-26 Lars Herschke <[email protected]> + + * netx/net/sourceforge/jnlp/resources/Messages.properties: Add + CVExportPasswordMessage, CVImportPasswordMessage and + CVPasswordTitle. + * netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java (initialize): + Initialize SSLContext with the user's client certificates. + * netx/net/sourceforge/jnlp/security/CertificateUtils.java + (addPKCS12ToKeyStore, addPKCS12ToKeyStore, dumpPKCS12): New methods. + * netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java + (getPasswords): New method. + (ImportButtonListener.actionPerformed): Import client certificates + in PKCS12 format. + (ExportButtonListener.actionPerformed): Export client certificates + in PKCS12 format. + 2011-09-23 Omair Majid <[email protected]> RH738814: Access denied at ssl handshake @@ -27,6 +27,7 @@ Common - PR789: typo in jrunscript.sh - RH734081: Javaws cannot use proxy settings from Firefox - RH738814: Access denied at ssl handshake + - Support for authenticating using client certificates New in release 1.1 (2011-XX-XX): * Security updates diff --git a/netx/net/sourceforge/jnlp/resources/Messages.properties b/netx/net/sourceforge/jnlp/resources/Messages.properties index 7365532..2825bb7 100644 --- a/netx/net/sourceforge/jnlp/resources/Messages.properties +++ b/netx/net/sourceforge/jnlp/resources/Messages.properties @@ -242,9 +242,12 @@ CVCertificateViewer=Certificates CVCertificateType=Certificate Type
CVDetails=Details
CVExport=Export
+CVExportPasswordMessage=Enter password to protect key file:
CVImport=Import
+CVImportPasswordMessage=Enter password to access file:
CVIssuedBy=Issued By
CVIssuedTo=Issued To
+CVPasswordTitle=Authentication Required
CVRemove=Remove
CVRemoveConfirmMessage=Are you sure you want to remove the selected certificate?
CVRemoveConfirmTitle=Confirmation - Remove Certificate?
diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java index 32fb348..ab97eb2 100644 --- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java +++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java @@ -29,6 +29,7 @@ import java.security.*; import javax.jnlp.*; import javax.naming.ConfigurationException; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; @@ -225,8 +226,11 @@ public class JNLPRuntime { try { SSLSocketFactory sslSocketFactory; SSLContext context = SSLContext.getInstance("SSL"); + KeyStore ks = KeyStores.getKeyStore(KeyStores.Level.USER, KeyStores.Type.CLIENT_CERTS); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, KeyStores.getPassword()); TrustManager[] trust = new TrustManager[] { VariableX509TrustManager.getInstance() }; - context.init(null, trust, null); + context.init(kmf.getKeyManagers(), trust, null); sslSocketFactory = context.getSocketFactory(); HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory); diff --git a/netx/net/sourceforge/jnlp/security/CertificateUtils.java b/netx/net/sourceforge/jnlp/security/CertificateUtils.java index fb7ecef..a4dfeae 100644 --- a/netx/net/sourceforge/jnlp/security/CertificateUtils.java +++ b/netx/net/sourceforge/jnlp/security/CertificateUtils.java @@ -38,12 +38,15 @@ exception statement from your version. package net.sourceforge.jnlp.security; import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.math.BigInteger; import java.security.InvalidKeyException; +import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; @@ -117,6 +120,41 @@ public class CertificateUtils { ks.setCertificateEntry(alias, cert); } + public static void addPKCS12ToKeyStore(File file, KeyStore ks, char[] password) + throws Exception { + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + keyStore.load(bis, password); + + Enumeration<String> aliasList = keyStore.aliases(); + + while (aliasList.hasMoreElements()) { + String alias = aliasList.nextElement(); + Certificate[] certChain = keyStore.getCertificateChain(alias); + Key key = keyStore.getKey(alias, password); + addPKCS12ToKeyStore(certChain, key, ks); + } + } + + public static void addPKCS12ToKeyStore(Certificate[] certChain, Key key, KeyStore ks) + throws KeyStoreException { + String alias = null; + + // does this certificate already exist? + alias = ks.getCertificateAlias(certChain[0]); + if (alias != null) { + return; + } + + // create a unique alias for this new certificate + Random random = new Random(); + do { + alias = new BigInteger(20, random).toString(); + } while (ks.getCertificate(alias) != null); + + ks.setKeyEntry(alias, key, KeyStores.getPassword(), certChain); + } + /** * Checks whether an X509Certificate is already in one of the keystores * @param c the certificate @@ -177,4 +215,15 @@ public class CertificateUtils { encoder.encodeBuffer(cert.getEncoded(), out); out.println(X509Factory.END_CERT); } + + public static void dumpPKCS12(String alias, File file, KeyStore ks, char[] password) + throws Exception { + Certificate[] certChain = ks.getCertificateChain(alias); + Key key = ks.getKey(alias, KeyStores.getPassword()); + BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); + KeyStore keyStore = KeyStore.getInstance("PKCS12"); + keyStore.load(null, null); + keyStore.setKeyEntry(alias, key, password, certChain); + keyStore.store(bos, password); + } } diff --git a/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java b/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java index 04f0982..36a809b 100644 --- a/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java +++ b/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java @@ -66,6 +66,7 @@ import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JPasswordField; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTable; @@ -100,6 +101,7 @@ public class CertificatePane extends JPanel { new CertificateType(KeyStores.Type.JSSE_CA_CERTS), new CertificateType(KeyStores.Type.CERTS), new CertificateType(KeyStores.Type.JSSE_CERTS), + new CertificateType(KeyStores.Type.CLIENT_CERTS) }; JTabbedPane tabbedPane; @@ -301,6 +303,18 @@ public class CertificatePane extends JPanel { } } + private char[] getPassword(final String label) { + JPasswordField jpf = new JPasswordField(); + int result = JOptionPane.showConfirmDialog(parent, + new Object[]{label, jpf}, R("CVPasswordTitle"), + JOptionPane.OK_CANCEL_OPTION, + JOptionPane.INFORMATION_MESSAGE); + if (result == JOptionPane.OK_OPTION) + return jpf.getPassword(); + else + return null; + } + /** Allows storing KeyStores.Types in a JComponent */ private static class CertificateType { private final KeyStores.Type type; @@ -364,7 +378,17 @@ public class CertificatePane extends JPanel { if (returnVal == JFileChooser.APPROVE_OPTION) { try { KeyStore ks = keyStore; - CertificateUtils.addToKeyStore(chooser.getSelectedFile(), ks); + if (currentKeyStoreType == KeyStores.Type.CLIENT_CERTS) { + char[] password = getPassword(R("CVImportPasswordMessage")); + if (password != null) { + CertificateUtils.addPKCS12ToKeyStore( + chooser.getSelectedFile(), ks, password); + } else { + return; + } + } else { + CertificateUtils.addToKeyStore(chooser.getSelectedFile(), ks); + } File keyStoreFile = new File(KeyStores .getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType)); if (!keyStoreFile.isFile()) { @@ -408,9 +432,15 @@ public class CertificatePane extends JPanel { String alias = keyStore.getCertificateAlias(certs .get(selectedRow)); if (alias != null) { - Certificate c = keyStore.getCertificate(alias); - PrintStream ps = new PrintStream(chooser.getSelectedFile().getAbsolutePath()); - CertificateUtils.dump(c, ps); + if (currentKeyStoreType == KeyStores.Type.CLIENT_CERTS) { + char[] password = getPassword(R("CVExportPasswordMessage")); + if (password != null) + CertificateUtils.dumpPKCS12(alias, chooser.getSelectedFile(), keyStore, password); + } else { + Certificate c = keyStore.getCertificate(alias); + PrintStream ps = new PrintStream(chooser.getSelectedFile().getAbsolutePath()); + CertificateUtils.dump(c, ps); + } repopulateTables(); } } |