summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2010-07-08 14:44:44 -0700
committerBrian Carlstrom <bdc@google.com>2010-07-13 16:42:50 -0700
commit059dbc04218144f985b20a228bbe98139d400d0c (patch)
treeb92a47bd1f418a51444714e2f2b2cf8af180ad48 /support
parenta5df574bf93265d41986b7e5474fb2fbb527c9f0 (diff)
downloadlibcore-059dbc04218144f985b20a228bbe98139d400d0c.zip
libcore-059dbc04218144f985b20a228bbe98139d400d0c.tar.gz
libcore-059dbc04218144f985b20a228bbe98139d400d0c.tar.bz2
Improved client certificate and certificate chain support
Summary: - openssl: add openssl support for specifying per key certificate chains - libcore: properly implement client certificate request call back - libcore: properly implement sending certificate chain - libcore: properly implement retreiving local certificate chain - libcore: added an SSLContext for non-OpenSSL SSLSocket creation Details: external/openssl Improve patch generate support by applying all other patches to baseline to remove cross polluting other patch changes into target patch. Move cleanup of ./Configure output to import script from openssl.config. import_openssl.sh openssl.config Adding SSL_use_certificate_chain and SSL_get_certificate_chain to continue to finish most of remaining JSSE issues. include/openssl/ssl.h ssl/s3_both.c ssl/ssl.h ssl/ssl_locl.h ssl/ssl_rsa.c Updated patch (and list of input files to patch) patches/jsse.patch openssl.config libcore Restoring SSLContextImpl as provider of non-OpenSSL SSLSocketImpl instances for interoperability testing. OpenSSLContextImpl is the new subclass that provides OpenSSLSocketImpl. JSSEProvider provides the old style SSLContexts, OpenSSLProvider provides the OpenSSL SSLContext, which includes the "default" context. Changed to register SSLContexts without aliases to match the RI. luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DefaultSSLContextImpl.java luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLContextImpl.java luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java Native interface updates to support OpenSSLSocketImpl improvements - KEY_TYPES now expanded based on what we are being provided by OpenSSL. keyType function now maps key type values received from clientCertificateRequested callback. - Removed remaining uses of string PEM encoding, now using ASN1 DER consistently Includes SSL_SESSION_get_peer_cert_chain, verifyCertificateChain - Fixed clientCertificateRequested to properly include all key types supported by server, not just the one from the cipher suite. We also now properly include the list of supported CAs to help the client select a certificate to use. - Fixed NativeCrypto.SSL_use_certificate implementation to use new SSL_use_certificate_chain function from openssl to pass chain to OpenSSL. - Added error handling of all uses of sk_*_push which can fail due to out of memory - Fixed compile warning due to missing JNI_TRACE argument luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java luni/src/main/native/NativeCrypto.cpp luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java Pass this into chooseServerAlias call as well in significantly revamped choseClientAlias luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java Minor code cleanup while reviewing diff between checkClientTrusted and checkServerTrusted luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java Improvements to SSL test support to go along with client certificate and certificate chain changes. TestSSLContext now has separate contexts for the client and server (as well as seperate key stores information). TestKeyStore now is more realistic by default, creating a CA, intermediate CA, and separate client and server certificates, as well as a client keystore that simply contains the CA and no certificates. support/src/test/java/javax/net/ssl/TestKeyStore.java support/src/test/java/javax/net/ssl/TestSSLContext.java Tests tracking API changes. Tests involving cert chains now now updated to use TestKeyStore.assertChainLength to avoid hardwiring expected chain length in tests. These tests also now use TestSSLContext.assertClientCertificateChain to validate that the chain is properly constructed and trusted by a trust manager. luni/src/test/java/java/net/URLConnectionTest.java luni/src/test/java/javax/net/ssl/SSLContextTest.java luni/src/test/java/javax/net/ssl/SSLEngineTest.java luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java luni/src/test/java/javax/net/ssl/SSLSessionTest.java luni/src/test/java/javax/net/ssl/SSLSocketTest.java support/src/test/java/java/security/StandardNames.java support/src/test/java/javax/net/ssl/TestSSLEnginePair.java support/src/test/java/javax/net/ssl/TestSSLSocketPair.java frameworks/base Tracking change of SSLContextImpl to OpenSSLContextImpl core/java/android/net/SSLCertificateSocketFactory.java core/java/android/net/http/HttpsConnection.java tests/CoreTests/android/core/SSLPerformanceTest.java tests/CoreTests/android/core/SSLSocketTest.java Tracking changes to TestSSLContext core/tests/coretests/src/android/net/http/HttpsThroughHttpProxyTest.java Change-Id: Ie35ebce89966dfce62c316f7fe7252bf06935680
Diffstat (limited to 'support')
-rw-r--r--support/src/test/java/java/security/StandardNames.java7
-rw-r--r--support/src/test/java/javax/net/ssl/TestKeyStore.java295
-rw-r--r--support/src/test/java/javax/net/ssl/TestSSLContext.java156
-rw-r--r--support/src/test/java/javax/net/ssl/TestSSLEnginePair.java16
-rw-r--r--support/src/test/java/javax/net/ssl/TestSSLSocketPair.java2
5 files changed, 371 insertions, 105 deletions
diff --git a/support/src/test/java/java/security/StandardNames.java b/support/src/test/java/java/security/StandardNames.java
index 4b278b6..1e4355e 100644
--- a/support/src/test/java/java/security/StandardNames.java
+++ b/support/src/test/java/java/security/StandardNames.java
@@ -49,7 +49,7 @@ public final class StandardNames extends Assert {
public static final boolean IS_RI
= !"Dalvik Core Library".equals(System.getProperty("java.specification.name"));
- public static final String PROVIDER_NAME = (IS_RI) ? "SunJSSE" : "HarmonyJSSE";
+ public static final String JSSE_PROVIDER_NAME = (IS_RI) ? "SunJSSE" : "AndroidOpenSSL";
/**
* A map from algorithm type (e.g. Cipher) to a set of algorithms (e.g. AES, DES, ...)
@@ -277,11 +277,6 @@ public final class StandardNames extends Assert {
// TODO remove one, probably Harmony's
provide("CertificateFactory", "X509");
- // Harmony JSSEProvider is missing these
- // TODO add them
- unprovide("SSLContext", "SSLv3");
- unprovide("SSLContext", "TLSv1");
-
// not just different names, but different binary formats
unprovide("KeyStore", "JKS");
provide("KeyStore", "BKS");
diff --git a/support/src/test/java/javax/net/ssl/TestKeyStore.java b/support/src/test/java/javax/net/ssl/TestKeyStore.java
index 72a76de..fbbd4db 100644
--- a/support/src/test/java/javax/net/ssl/TestKeyStore.java
+++ b/support/src/test/java/javax/net/ssl/TestKeyStore.java
@@ -16,18 +16,29 @@
package javax.net.ssl;
+import java.io.PrintStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.KeyStore.PasswordProtection;
+import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.Security;
+import java.security.StandardNames;
+import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
+import java.util.Collections;
import java.util.Date;
import java.util.Hashtable;
+import junit.framework.Assert;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.X509V3CertificateGenerator;
/**
@@ -37,8 +48,14 @@ import org.bouncycastle.x509.X509V3CertificateGenerator;
* Creating a key store is relatively slow, so a singleton instance is
* accessible via TestKeyStore.get().
*/
-public final class TestKeyStore {
+public final class TestKeyStore extends Assert {
+ static {
+ if (StandardNames.IS_RI) {
+ // Needed to create BKS keystore
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
public final KeyStore keyStore;
public final char[] keyStorePassword;
@@ -48,28 +65,91 @@ public final class TestKeyStore {
this.keyStorePassword = keyStorePassword;
}
- private static final TestKeyStore SINGLETON = create(new String[] { "RSA" } );
+ private static final TestKeyStore ROOT_CA
+ = create(new String[] { "RSA" },
+ null,
+ "RootCA",
+ x509Principal("Test Root Certificate Authority"),
+ true,
+ null);
+ private static final TestKeyStore INTERMEDIATE_CA
+ = create(new String[] { "RSA" },
+ null,
+ "IntermediateCA",
+ x509Principal("Test Intermediate Certificate Authority"),
+ true,
+ ROOT_CA);
+ private static final TestKeyStore SERVER
+ = create(new String[] { "RSA" },
+ null,
+ "server",
+ localhost(),
+ false,
+ INTERMEDIATE_CA);
+ private static final TestKeyStore CLIENT
+ = new TestKeyStore(createClient(INTERMEDIATE_CA.keyStore), null);
+ private static final TestKeyStore CLIENT_CERTIFICATE
+ = create(new String[] { "RSA" },
+ null,
+ "client",
+ x509Principal("test@user"),
+ false,
+ INTERMEDIATE_CA);
+
+ /**
+ * Return a server keystore with a matched RSA certificate and
+ * private key as well as a CA certificate.
+ */
+ public static TestKeyStore getServer() {
+ return SERVER;
+ }
+
+ /**
+ * Return a keystore with a CA certificate
+ */
+ public static TestKeyStore getClient() {
+ return CLIENT;
+ }
/**
- * Return a keystore with an RSA keypair
+ * Return a client keystore with a matched RSA certificate and
+ * private key as well as a CA certificate.
*/
- public static TestKeyStore get() {
- return SINGLETON;
+ public static TestKeyStore getClientCertificate() {
+ return CLIENT_CERTIFICATE;
}
/**
* Create a new KeyStore containing the requested key types.
* Since key generation can be expensive, most tests should reuse
* the RSA-only singleton instance returned by TestKeyStore.get
+ *
+ * @param keyAlgorithms The requested key types to generate and include
+ * @param keyStorePassword Password used to protect the private key
+ * @param aliasPrefix A unique prefix to identify the key aliases
+ * @param ca true If the keys being created are for a CA
+ * @param signer If non-null, key store used for signing key, otherwise self-signed
*/
- public static TestKeyStore create(String[] keyAlgorithms) {
+ public static TestKeyStore create(String[] keyAlgorithms,
+ char[] keyStorePassword,
+ String aliasPrefix,
+ X509Principal subject,
+ boolean ca,
+ TestKeyStore signer) {
try {
- char[] keyStorePassword = null;
KeyStore keyStore = createKeyStore();
for (String keyAlgorithm : keyAlgorithms) {
- String publicAlias = "public-" + keyAlgorithm;
- String privateAlias = "private-" + keyAlgorithm;
- createKeys(keyStore, keyStorePassword, keyAlgorithm, publicAlias, privateAlias);
+ String publicAlias = aliasPrefix + "-public-" + keyAlgorithm;
+ String privateAlias = aliasPrefix + "-private-" + keyAlgorithm;
+ createKeys(keyStore, keyStorePassword,
+ keyAlgorithm,
+ publicAlias, privateAlias,
+ subject,
+ ca,
+ signer);
+ }
+ if (signer != null) {
+ copySelfSignedCertificates(keyStore, signer.keyStore);
}
return new TestKeyStore(keyStore, keyStorePassword);
} catch (RuntimeException e) {
@@ -95,15 +175,14 @@ public final class TestKeyStore {
/**
* Add newly generated keys of a given key type to an existing
* KeyStore. The PrivateKey will be stored under the specified
- * private alias name and a X509Certificate based on the matching
- * PublicKey stored under the given public alias name.
+ * private alias name. The X509Certificate will be stored on the
+ * public alias name and have the given subject distiguished
+ * name.
*
- * The private key will have a certificate chain including the
- * certificate stored under the alias name privateAlias. The
- * certificate will be signed by the private key. The certificate
- * Subject and Issuer Common-Name will be the local host's
- * canonical hostname. The certificate will be valid for one day
- * before and one day after the time of creation.
+ * If a CA is provided, it will be used to sign the generated
+ * certificate. Otherwise, the certificate will be self
+ * signed. The certificate will be valid for one day before and
+ * one day after the time of creation.
*
* Based on:
* org.bouncycastle.jce.provider.test.SigTest
@@ -113,7 +192,25 @@ public final class TestKeyStore {
char[] keyStorePassword,
String keyAlgorithm,
String publicAlias,
- String privateAlias) throws Exception {
+ String privateAlias,
+ X509Principal subject,
+ boolean ca,
+ TestKeyStore signer) throws Exception {
+ PrivateKey caKey;
+ X509Certificate caCert;
+ X509Certificate[] caCertChain;
+ if (signer == null) {
+ caKey = null;
+ caCert = null;
+ caCertChain = null;
+ } else {
+ PrivateKeyEntry privateKeyEntry
+ = privateKey(signer.keyStore, signer.keyStorePassword, keyAlgorithm);
+ caKey = privateKeyEntry.getPrivateKey();
+ caCert = (X509Certificate)privateKeyEntry.getCertificate();
+ caCertChain = (X509Certificate[])privateKeyEntry.getCertificateChain();
+ }
+
PrivateKey privateKey;
X509Certificate x509c;
if (publicAlias == null && privateAlias == null) {
@@ -135,10 +232,12 @@ public final class TestKeyStore {
// interface assumes you want to read in a stream of bytes a
// factory specific format. So here we use Bouncy Castle's
// X509V3CertificateGenerator and related classes.
-
- Hashtable attributes = new Hashtable();
- attributes.put(X509Principal.CN, InetAddress.getLocalHost().getCanonicalHostName());
- X509Principal dn = new X509Principal(attributes);
+ X509Principal issuer;
+ if (caCert == null) {
+ issuer = subject;
+ } else {
+ issuer = (X509Principal) caCert.getSubjectDN();
+ }
long millisPerDay = 24 * 60 * 60 * 1000;
long now = System.currentTimeMillis();
@@ -147,22 +246,32 @@ public final class TestKeyStore {
BigInteger serial = BigInteger.valueOf(1);
X509V3CertificateGenerator x509cg = new X509V3CertificateGenerator();
- x509cg.setSubjectDN(dn);
- x509cg.setIssuerDN(dn);
+ x509cg.setSubjectDN(subject);
+ x509cg.setIssuerDN(issuer);
x509cg.setNotBefore(start);
x509cg.setNotAfter(end);
x509cg.setPublicKey(publicKey);
x509cg.setSignatureAlgorithm("sha1With" + keyAlgorithm);
x509cg.setSerialNumber(serial);
- x509c = x509cg.generateX509Certificate(privateKey);
+ if (ca) {
+ x509cg.addExtension(X509Extensions.BasicConstraints,
+ true,
+ new BasicConstraints(true));
+ }
+ PrivateKey signingKey = (caKey == null) ? privateKey : caKey;
+ x509c = x509cg.generateX509Certificate(signingKey);
}
X509Certificate[] x509cc;
if (privateAlias == null) {
// don't need certificate chain
x509cc = null;
- } else {
+ } else if (caCertChain == null) {
x509cc = new X509Certificate[] { x509c };
+ } else {
+ x509cc = new X509Certificate[caCertChain.length+1];
+ x509cc[0] = x509c;
+ System.arraycopy(caCertChain, 0, x509cc, 1, caCertChain.length);
}
// 3.) put certificate and private key into the key store
@@ -174,4 +283,136 @@ public final class TestKeyStore {
}
return keyStore;
}
+
+ /**
+ * Create an X509Principal with the given attributes
+ */
+ public static X509Principal localhost() {
+ try {
+ return x509Principal(InetAddress.getLocalHost().getCanonicalHostName());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Create an X509Principal with the given attributes
+ */
+ public static X509Principal x509Principal(String commonName) {
+ Hashtable attributes = new Hashtable();
+ attributes.put(X509Principal.CN, commonName);
+ return new X509Principal(attributes);
+ }
+
+ /**
+ * Return the only private key in a keystore for the given
+ * algorithm. Throws IllegalStateException if there are are more
+ * or less than one.
+ */
+ public static PrivateKeyEntry privateKey(KeyStore keyStore,
+ char[] keyStorePassword,
+ String algorithm) {
+ try {
+ PrivateKeyEntry found = null;
+ PasswordProtection password = new PasswordProtection(keyStorePassword);
+ for (String alias: Collections.list(keyStore.aliases())) {
+ if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
+ continue;
+ }
+ PrivateKeyEntry privateKey = (PrivateKeyEntry) keyStore.getEntry(alias, password);
+ if (!privateKey.getPrivateKey().getAlgorithm().equals(algorithm)) {
+ continue;
+ }
+ if (found != null) {
+ throw new IllegalStateException("keyStore has more than one private key");
+ }
+ found = privateKey;
+ }
+ if (found == null) {
+ throw new IllegalStateException("keyStore contained no private key");
+ }
+ return found;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Create a client key store that only contains self-signed certificates but no private keys
+ */
+ public static KeyStore createClient(KeyStore caKeyStore) {
+ try {
+ KeyStore clientKeyStore = clientKeyStore = KeyStore.getInstance("BKS");
+ clientKeyStore.load(null, null);
+ copySelfSignedCertificates(clientKeyStore, caKeyStore);
+ return clientKeyStore;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copy self-signed certifcates from one key store to another
+ */
+ public static void copySelfSignedCertificates(KeyStore dst, KeyStore src) throws Exception {
+ for (String alias: Collections.list(src.aliases())) {
+ if (!src.isCertificateEntry(alias)) {
+ continue;
+ }
+ X509Certificate cert = (X509Certificate)src.getCertificate(alias);
+ if (!cert.getSubjectDN().equals(cert.getIssuerDN())) {
+ continue;
+ }
+ dst.setCertificateEntry(alias, cert);
+ }
+ }
+
+ /**
+ * Dump a key store for debugging.
+ */
+ public static void dump(String context,
+ KeyStore keyStore,
+ char[] keyStorePassword) {
+ try {
+ PrintStream out = System.out;
+ out.println("context=" + context);
+ out.println("\tkeyStore=" + keyStore);
+ out.println("\tpassword="
+ + ((keyStorePassword == null) ? null : new String(keyStorePassword)));
+ for (String alias: Collections.list(keyStore.aliases())) {
+ out.println("\talias=" + alias);
+ if (keyStore.isCertificateEntry(alias)) {
+ out.println("\tcertificate:");
+ out.println("==========================================");
+ out.println(keyStore.getCertificate(alias));
+ out.println("==========================================");
+ continue;
+ }
+ if (keyStore.isKeyEntry(alias)) {
+ out.println("\tkey:");
+ out.println("==========================================");
+ out.println(keyStore.getKey(alias, keyStorePassword));
+ out.println("==========================================");
+ continue;
+ }
+ out.println("\tunknown entry type");
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void assertChainLength(Object[] chain) {
+ /*
+ * Note chain is Object[] to support both
+ * java.security.cert.X509Certificate and
+ * javax.security.cert.X509Certificate
+ */
+ assertEquals(3, chain.length);
+ }
+
}
diff --git a/support/src/test/java/javax/net/ssl/TestSSLContext.java b/support/src/test/java/javax/net/ssl/TestSSLContext.java
index 8d759ee..5174b15 100644
--- a/support/src/test/java/javax/net/ssl/TestSSLContext.java
+++ b/support/src/test/java/javax/net/ssl/TestSSLContext.java
@@ -21,13 +21,12 @@ import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.security.Principal;
import java.security.SecureRandom;
-import java.security.Security;
import java.security.StandardNames;
import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import junit.framework.Assert;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* TestSSLContext is a convenience class for other tests that
@@ -45,11 +44,6 @@ public final class TestSSLContext extends Assert {
public static final int EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE = (IS_RI) ? 0 : 10;
public static final int EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE = (IS_RI) ? 0 : 100;
public static final int EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT = (IS_RI) ? 86400 : 0;
- static {
- if (IS_RI) {
- Security.addProvider(new BouncyCastleProvider());
- }
- }
/**
* The Android SSLSocket and SSLServerSocket implementations are
@@ -72,22 +66,43 @@ public final class TestSSLContext extends Assert {
return false;
}
- public final KeyStore keyStore;
- public final char[] keyStorePassword;
- public final SSLContext sslContext;
+ public final KeyStore clientKeyStore;
+ public final char[] clientKeyStorePassword;
+ public final KeyStore serverKeyStore;
+ public final char[] serverKeyStorePassword;
+ public final X509ExtendedKeyManager clientKeyManager;
+ public final X509ExtendedKeyManager serverKeyManager;
+ public final X509TrustManager clientTrustManager;
+ public final X509TrustManager serverTrustManager;
+ public final SSLContext clientContext;
+ public final SSLContext serverContext;
public final SSLServerSocket serverSocket;
public final InetAddress host;
public final int port;
- private TestSSLContext(KeyStore keyStore,
- char[] keyStorePassword,
- SSLContext sslContext,
+ private TestSSLContext(KeyStore clientKeyStore,
+ char[] clientKeyStorePassword,
+ KeyStore serverKeyStore,
+ char[] serverKeyStorePassword,
+ X509ExtendedKeyManager clientKeyManager,
+ X509ExtendedKeyManager serverKeyManager,
+ X509TrustManager clientTrustManager,
+ X509TrustManager serverTrustManager,
+ SSLContext clientContext,
+ SSLContext serverContext,
SSLServerSocket serverSocket,
InetAddress host,
int port) {
- this.keyStore = keyStore;
- this.keyStorePassword = keyStorePassword;
- this.sslContext = sslContext;
+ this.clientKeyStore = clientKeyStore;
+ this.clientKeyStorePassword = clientKeyStorePassword;
+ this.serverKeyStore = serverKeyStore;
+ this.serverKeyStorePassword = serverKeyStorePassword;
+ this.clientKeyManager = clientKeyManager;
+ this.serverKeyManager = serverKeyManager;
+ this.clientTrustManager = clientTrustManager;
+ this.serverTrustManager = serverTrustManager;
+ this.clientContext = clientContext;
+ this.serverContext = serverContext;
this.serverSocket = serverSocket;
this.host = host;
this.port = port;
@@ -99,60 +114,51 @@ public final class TestSSLContext extends Assert {
* listening provided host and port.
*/
public static TestSSLContext create() {
- TestKeyStore testKeyStore = TestKeyStore.get();
- return create(testKeyStore.keyStore, testKeyStore.keyStorePassword);
+ return create(TestKeyStore.getClient(),
+ TestKeyStore.getServer());
}
/**
- * TestSSLContext creation method that allows separate creation of key store
+ * TestSSLContext creation method that allows separate creation of server key store
*/
- public static TestSSLContext create(KeyStore keyStore, char[] keyStorePassword) {
- try {
- SSLContext sslContext = createSSLContext(keyStore, keyStorePassword);
-
- SSLServerSocket serverSocket = (SSLServerSocket)
- sslContext.getServerSocketFactory().createServerSocket(0);
- InetSocketAddress sa = (InetSocketAddress) serverSocket.getLocalSocketAddress();
- InetAddress host = sa.getAddress();
- int port = sa.getPort();
-
- return new TestSSLContext(keyStore, keyStorePassword,
- sslContext, serverSocket, host, port);
- } catch (RuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ public static TestSSLContext create(TestKeyStore client, TestKeyStore server) {
+ return create(client.keyStore, client.keyStorePassword,
+ server.keyStore, server.keyStorePassword);
}
/**
- * Create a client version of the server TestSSLContext. The
- * client will trust the server's certificate, but not contain any
- * keys of its own.
+ * TestSSLContext creation method that allows separate creation of client and server key store
*/
- public static TestSSLContext createClient(TestSSLContext server) {
+ public static TestSSLContext create(KeyStore clientKeyStore, char[] clientKeyStorePassword,
+ KeyStore serverKeyStore, char[] serverKeyStorePassword) {
try {
- KeyStore keyStore = KeyStore.getInstance("BKS");
- keyStore.load(null, null);
- for (String alias: Collections.list(server.keyStore.aliases())) {
- if (!server.keyStore.isCertificateEntry(alias)) {
- continue;
- }
- Certificate cert = server.keyStore.getCertificate(alias);
- keyStore.setCertificateEntry(alias, cert);
- }
+ KeyManager[] clientKeyManagers = createKeyManagers(clientKeyStore,
+ clientKeyStorePassword);
+ KeyManager[] serverKeyManagers = createKeyManagers(serverKeyStore,
+ serverKeyStorePassword);
- char[] keyStorePassword = server.keyStorePassword;
+ TrustManager[] clientTrustManagers = createTrustManagers(clientKeyStore,
+ clientKeyStorePassword);
+ TrustManager[] serverTrustManagers = createTrustManagers(serverKeyStore,
+ serverKeyStorePassword);
- String tmfa = TrustManagerFactory.getDefaultAlgorithm();
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa);
- tmf.init(keyStore);
+ SSLContext clientContext = createSSLContext(clientKeyManagers, clientTrustManagers);
+ SSLContext serverContext = createSSLContext(serverKeyManagers, serverTrustManagers);
- SSLContext sslContext = SSLContext.getInstance("TLS");
- sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
+ SSLServerSocket serverSocket = (SSLServerSocket)
+ serverContext.getServerSocketFactory().createServerSocket(0);
+ InetSocketAddress sa = (InetSocketAddress) serverSocket.getLocalSocketAddress();
+ InetAddress host = sa.getAddress();
+ int port = sa.getPort();
- return new TestSSLContext(keyStore, keyStorePassword,
- sslContext, null, null, -1);
+ return new TestSSLContext(clientKeyStore, clientKeyStorePassword,
+ serverKeyStore, serverKeyStorePassword,
+ (X509ExtendedKeyManager) clientKeyManagers[0],
+ (X509ExtendedKeyManager) serverKeyManagers[0],
+ (X509TrustManager) clientTrustManagers[0],
+ (X509TrustManager) serverTrustManagers[0],
+ clientContext, serverContext,
+ serverSocket, host, port);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
@@ -165,20 +171,28 @@ public final class TestSSLContext extends Assert {
* certificate chain from the given KeyStore and a TrustManager
* using the certificates authorities from the same KeyStore.
*/
- public static final SSLContext createSSLContext(final KeyStore keyStore,
- final char[] keyStorePassword)
- throws Exception {
+ public static final SSLContext createSSLContext(final KeyManager[] keyManagers,
+ final TrustManager[] trustManagers)
+ throws Exception {
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(keyManagers, trustManagers, new SecureRandom());
+ return context;
+ }
+
+ public static KeyManager[] createKeyManagers(final KeyStore keyStore,
+ final char[] keyStorePassword) throws Exception {
String kmfa = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfa);
kmf.init(keyStore, keyStorePassword);
+ return kmf.getKeyManagers();
+ }
+ public static TrustManager[] createTrustManagers(final KeyStore keyStore,
+ final char[] keyStorePassword) throws Exception {
String tmfa = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfa);
tmf.init(keyStore);
-
- SSLContext context = SSLContext.getInstance("TLS");
- context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
- return context;
+ return tmf.getTrustManagers();
}
public static void assertCertificateInKeyStore(Principal principal,
@@ -213,4 +227,18 @@ public final class TestSSLContext extends Assert {
}
assertTrue(found);
}
+
+ public static void assertServerCertificateChain(X509TrustManager trustManager,
+ Certificate[] serverChain)
+ throws CertificateException {
+ X509Certificate[] chain = (X509Certificate[]) serverChain;
+ trustManager.checkServerTrusted(chain, chain[0].getPublicKey().getAlgorithm());
+ }
+
+ public static void assertClientCertificateChain(X509TrustManager trustManager,
+ Certificate[] clientChain)
+ throws CertificateException {
+ X509Certificate[] chain = (X509Certificate[]) clientChain;
+ trustManager.checkClientTrusted(chain, chain[0].getPublicKey().getAlgorithm());
+ }
}
diff --git a/support/src/test/java/javax/net/ssl/TestSSLEnginePair.java b/support/src/test/java/javax/net/ssl/TestSSLEnginePair.java
index f3250e6..1ed2a92 100644
--- a/support/src/test/java/javax/net/ssl/TestSSLEnginePair.java
+++ b/support/src/test/java/javax/net/ssl/TestSSLEnginePair.java
@@ -40,8 +40,11 @@ public final class TestSSLEnginePair extends Assert {
}
public static TestSSLEnginePair create(Hooks hooks) throws IOException {
- TestSSLContext c = TestSSLContext.create();
- SSLEngine[] engines = connect(c, c, hooks);
+ return create(TestSSLContext.create(), hooks);
+ }
+
+ public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks) throws IOException {
+ SSLEngine[] engines = connect(c, hooks);
return new TestSSLEnginePair(c, engines[0], engines[1]);
}
@@ -52,14 +55,13 @@ public final class TestSSLEnginePair extends Assert {
* caching. Optionally specify serverCipherSuites for testing
* cipher suite negotiation.
*/
- public static SSLEngine[] connect(final TestSSLContext clientContext,
- final TestSSLContext serverContext,
+ public static SSLEngine[] connect(final TestSSLContext c,
Hooks hooks) throws IOException {
if (hooks == null) {
hooks = new Hooks();
}
- SSLSession session = clientContext.sslContext.createSSLEngine().getSession();
+ SSLSession session = c.clientContext.createSSLEngine().getSession();
int packetBufferSize = session.getPacketBufferSize();
ByteBuffer clientToServer = ByteBuffer.allocate(packetBufferSize);
@@ -68,8 +70,8 @@ public final class TestSSLEnginePair extends Assert {
int applicationBufferSize = session.getApplicationBufferSize();
ByteBuffer scratch = ByteBuffer.allocate(applicationBufferSize);
- SSLEngine client = clientContext.sslContext.createSSLEngine();
- SSLEngine server = serverContext.sslContext.createSSLEngine();
+ SSLEngine client = c.clientContext.createSSLEngine();
+ SSLEngine server = c.serverContext.createSSLEngine();
client.setUseClientMode(true);
server.setUseClientMode(false);
hooks.beforeBeginHandshake(client, server);
diff --git a/support/src/test/java/javax/net/ssl/TestSSLSocketPair.java b/support/src/test/java/javax/net/ssl/TestSSLSocketPair.java
index cda664c..1d0345f 100644
--- a/support/src/test/java/javax/net/ssl/TestSSLSocketPair.java
+++ b/support/src/test/java/javax/net/ssl/TestSSLSocketPair.java
@@ -55,7 +55,7 @@ public final class TestSSLSocketPair {
final String[] serverCipherSuites) {
try {
SSLSocket client = (SSLSocket)
- c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ c.clientContext.getSocketFactory().createSocket(c.host, c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {