aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--NEWS1
-rw-r--r--netx/net/sourceforge/jnlp/resources/Messages.properties3
-rw-r--r--netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java6
-rw-r--r--netx/net/sourceforge/jnlp/security/CertificateUtils.java49
-rw-r--r--netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java38
6 files changed, 108 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 5b76186..5e41c58 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
diff --git a/NEWS b/NEWS
index 6a75b3d..8003f55 100644
--- a/NEWS
+++ b/NEWS
@@ -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();
}
}