summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2010-05-04 10:47:14 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2010-05-04 10:47:14 -0700
commitf4c62bce9efbba1ded656acacb0695694a16d309 (patch)
tree6de77ce3c3ef091e1b474ce6b1efa9e7308e1c94 /support
parent4cb7f05dc68abb23ae54a5891c369062185f2210 (diff)
parentbcfb325d5b1f9529b439cc0805a1c140521510f7 (diff)
downloadlibcore-f4c62bce9efbba1ded656acacb0695694a16d309.zip
libcore-f4c62bce9efbba1ded656acacb0695694a16d309.tar.gz
libcore-f4c62bce9efbba1ded656acacb0695694a16d309.tar.bz2
Merge "OpenSSLSocket handshake overhaul" into dalvik-dev
Diffstat (limited to 'support')
-rw-r--r--support/src/test/java/javax/net/ssl/StandardNames.java112
-rw-r--r--support/src/test/java/javax/net/ssl/TestSSLContext.java226
-rw-r--r--support/src/test/java/javax/net/ssl/TestSSLSessions.java68
-rw-r--r--support/src/test/java/javax/net/ssl/TestSSLSocketPair.java84
4 files changed, 490 insertions, 0 deletions
diff --git a/support/src/test/java/javax/net/ssl/StandardNames.java b/support/src/test/java/javax/net/ssl/StandardNames.java
new file mode 100644
index 0000000..ccd3ee1
--- /dev/null
+++ b/support/src/test/java/javax/net/ssl/StandardNames.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.net.ssl;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This class defines expected string names for protocols, key types, client and server auth types, cipher suites.
+ * Based on documentation from http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#AppA
+ */
+public final class StandardNames {
+
+ public static final Set<String> SSL_CONTEXT_PROTOCOLS = new HashSet<String>(Arrays.asList(
+ "SSL",
+ "SSLv2",
+ "SSLv3",
+ "TLS",
+ "TLSv1"));
+
+ public static final Set<String> KEY_TYPES = new HashSet<String>(Arrays.asList(
+ "RSA",
+ "DSA",
+ "DH_RSA",
+ "DH_DSA"));
+
+ public static final Set<String> SSL_SOCKET_PROTOCOLS = new HashSet<String>(Arrays.asList(
+ "SSLv2",
+ "SSLv3",
+ "TLSv1",
+ "SSLv2Hello"));
+
+ public static final Set<String> CLIENT_AUTH_TYPES = new HashSet<String>(KEY_TYPES);
+
+ public static final Set<String> SERVER_AUTH_TYPES = new HashSet<String>(Arrays.asList(
+ "DHE_DSS",
+ "DHE_DSS_EXPORT",
+ "DHE_RSA",
+ "DHE_RSA_EXPORT",
+ "DH_DSS_EXPORT",
+ "DH_RSA_EXPORT",
+ "DH_anon",
+ "DH_anon_EXPORT",
+ "KRB5",
+ "KRB5_EXPORT",
+ "RSA",
+ "RSA_EXPORT",
+ "RSA_EXPORT1024",
+ "UNKNOWN"));
+
+ // removed cipher suites not actually found in RI
+ public static final Set<String> CIPHER_SUITES = new HashSet<String>(Arrays.asList(
+ "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_DSS_WITH_DES_CBC_SHA",
+ "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DHE_RSA_WITH_DES_CBC_SHA",
+ //"SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
+ //"SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
+ "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5",
+ "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
+ "SSL_DH_anon_WITH_DES_CBC_SHA",
+ "SSL_DH_anon_WITH_RC4_128_MD5",
+ //"SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA",
+ //"SSL_RSA_EXPORT1024_WITH_RC4_56_SHA",
+ "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
+ //"SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
+ "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
+ "SSL_RSA_WITH_3DES_EDE_CBC_SHA",
+ "SSL_RSA_WITH_DES_CBC_SHA",
+ "SSL_RSA_WITH_NULL_MD5",
+ "SSL_RSA_WITH_NULL_SHA",
+ "SSL_RSA_WITH_RC4_128_MD5",
+ "SSL_RSA_WITH_RC4_128_SHA",
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+ //"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+ //"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
+ "TLS_DH_anon_WITH_AES_128_CBC_SHA",
+ //"TLS_DH_anon_WITH_AES_256_CBC_SHA",
+ "TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
+ "TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
+ //"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
+ //"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
+ "TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
+ "TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
+ "TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
+ "TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
+ "TLS_KRB5_WITH_DES_CBC_MD5",
+ "TLS_KRB5_WITH_DES_CBC_SHA",
+ "TLS_KRB5_WITH_RC4_128_MD5",
+ "TLS_KRB5_WITH_RC4_128_SHA",
+ "TLS_RSA_WITH_AES_128_CBC_SHA"));
+ //"TLS_RSA_WITH_AES_256_CBC_SHA"));
+}
diff --git a/support/src/test/java/javax/net/ssl/TestSSLContext.java b/support/src/test/java/javax/net/ssl/TestSSLContext.java
new file mode 100644
index 0000000..44b21c9
--- /dev/null
+++ b/support/src/test/java/javax/net/ssl/TestSSLContext.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.net.ssl;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+import java.util.Hashtable;
+import org.bouncycastle.jce.X509Principal;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.x509.X509V3CertificateGenerator;
+
+/**
+ * TestSSLContext is a convenience class for other tests that
+ * want a canned SSLContext and related state for testing so they
+ * don't have to duplicate the logic.
+ */
+public final class TestSSLContext {
+
+ 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";
+
+ static {
+ if (IS_RI) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ /**
+ * The Android SSLSocket and SSLServerSocket implementations are
+ * based on a version of OpenSSL which includes support for RFC
+ * 4507 session tickets. When using session tickets, the server
+ * does not need to keep a cache mapping session IDs to SSL
+ * sessions for reuse. Instead, the client presents the server
+ * with a session ticket it received from the server earlier,
+ * which is an SSL session encrypted by the server's secret
+ * key. Since in this case the server does not need to keep a
+ * cache, some tests may find different results depending on
+ * whether or not the session tickets are in use. These tests can
+ * use this function to determine if loopback SSL connections are
+ * expected to use session tickets and conditionalize their
+ * results appropriately.
+ */
+ public static boolean sslServerSocketSupportsSessionTickets () {
+ return !IS_RI;
+ }
+
+ public final KeyStore keyStore;
+ public final char[] keyStorePassword;
+ public final String publicAlias;
+ public final String privateAlias;
+ public final SSLContext sslContext;
+ public final SSLServerSocket serverSocket;
+ public final InetAddress host;
+ public final int port;
+
+ private TestSSLContext(KeyStore keyStore,
+ char[] keyStorePassword,
+ String publicAlias,
+ String privateAlias,
+ SSLContext sslContext,
+ SSLServerSocket serverSocket,
+ InetAddress host,
+ int port) {
+ this.keyStore = keyStore;
+ this.keyStorePassword = keyStorePassword;
+ this.publicAlias = publicAlias;
+ this.privateAlias = privateAlias;
+ this.sslContext = sslContext;
+ this.serverSocket = serverSocket;
+ this.host = host;
+ this.port = port;
+ }
+
+ public static TestSSLContext create() {
+ try {
+ char[] keyStorePassword = null;
+ String publicAlias = "public";
+ String privateAlias = "private";
+ return create(createKeyStore(keyStorePassword, publicAlias, privateAlias),
+ null,
+ publicAlias,
+ privateAlias);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static TestSSLContext create(KeyStore keyStore,
+ char[] keyStorePassword,
+ String publicAlias,
+ String privateAlias) {
+ 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, publicAlias, privateAlias,
+ sslContext, serverSocket, host, port);
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Create a BKS KeyStore containing an RSAPrivateKey with alias
+ * "private" and a X509Certificate based on the matching
+ * RSAPublicKey stored under the alias name publicAlias.
+ *
+ * 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.
+ *
+ * The KeyStore is optionally password protected by the
+ * keyStorePassword argument, which can be null if a password is
+ * not desired.
+ *
+ * Based on:
+ * org.bouncycastle.jce.provider.test.SigTest
+ * org.bouncycastle.jce.provider.test.CertTest
+ */
+ public static KeyStore createKeyStore(char[] keyStorePassword,
+ String publicAlias,
+ String privateAlias)
+ throws Exception {
+
+ // 1.) we make the keys
+ int keysize = 1024;
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(keysize, new SecureRandom());
+ KeyPair kp = kpg.generateKeyPair();
+ RSAPrivateKey privateKey = (RSAPrivateKey)kp.getPrivate();
+ RSAPublicKey publicKey = (RSAPublicKey)kp.getPublic();
+
+ // 2.) use keys to make certficate
+
+ // note that there doesn't seem to be a standard way to make a
+ // certificate using java.* or javax.*. The CertificateFactory
+ // 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);
+
+ long millisPerDay = 24 * 60 * 60 * 1000;
+ long now = System.currentTimeMillis();
+ Date start = new Date(now - millisPerDay);
+ Date end = new Date(now + millisPerDay);
+ BigInteger serial = BigInteger.valueOf(1);
+
+ X509V3CertificateGenerator x509cg = new X509V3CertificateGenerator();
+ x509cg.setSubjectDN(dn);
+ x509cg.setIssuerDN(dn);
+ x509cg.setNotBefore(start);
+ x509cg.setNotAfter(end);
+ x509cg.setPublicKey(publicKey);
+ x509cg.setSignatureAlgorithm("sha1WithRSAEncryption");
+ x509cg.setSerialNumber(serial);
+ X509Certificate x509c = x509cg.generateX509Certificate(privateKey);
+ X509Certificate[] x509cc = new X509Certificate[] { x509c };
+
+
+ // 3.) put certificate and private key to make a key store
+ KeyStore ks = KeyStore.getInstance("BKS");
+ ks.load(null, null);
+ ks.setKeyEntry(privateAlias, privateKey, keyStorePassword, x509cc);
+ ks.setCertificateEntry(publicAlias, x509c);
+ return ks;
+ }
+
+ /**
+ * Create a SSLContext with a KeyManager using the private key and
+ * 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 {
+ String kmfa = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(kmfa);
+ kmf.init(keyStore, keyStorePassword);
+
+ 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;
+ }
+}
diff --git a/support/src/test/java/javax/net/ssl/TestSSLSessions.java b/support/src/test/java/javax/net/ssl/TestSSLSessions.java
new file mode 100644
index 0000000..061a7f2
--- /dev/null
+++ b/support/src/test/java/javax/net/ssl/TestSSLSessions.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.net.ssl;
+
+/**
+ * TestSSLSessions is a convenience class for other tests that want
+ * precreated SSLSessions for testing. It contains a connected
+ * client/server pair of SSLSession as well as an invalid SSLSession.
+ */
+public final class TestSSLSessions {
+
+ /**
+ * An invalid session that is not connected
+ */
+ public final SSLSession invalid;
+
+ /**
+ * The server side of a connected session
+ */
+ public final SSLSession server;
+
+ /**
+ * The client side of a connected session
+ */
+ public final SSLSession client;
+
+ /**
+ * The associated SSLSocketTest.Helper that is the source of
+ * the client and server SSLSessions.
+ */
+ public final TestSSLSocketPair s;
+
+ private TestSSLSessions(SSLSession invalid,
+ SSLSession server,
+ SSLSession client,
+ TestSSLSocketPair s) {
+ this.invalid = invalid;
+ this.server = server;
+ this.client = client;
+ this.s = s;
+ }
+
+ public static final TestSSLSessions create() {
+ try {
+ SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ SSLSocket ssl = (SSLSocket) sf.createSocket();
+ SSLSession invalid = ssl.getSession();
+ TestSSLSocketPair s = TestSSLSocketPair.create_workaround();
+ return new TestSSLSessions(invalid, s.server.getSession(), s.client.getSession(), s);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/support/src/test/java/javax/net/ssl/TestSSLSocketPair.java b/support/src/test/java/javax/net/ssl/TestSSLSocketPair.java
new file mode 100644
index 0000000..6347877
--- /dev/null
+++ b/support/src/test/java/javax/net/ssl/TestSSLSocketPair.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package javax.net.ssl;
+
+/**
+ * TestSSLSocketPair is a convenience class for other tests that want
+ * a pair of connected and handshaked client and server SSLSockets for
+ * testing.
+ */
+public final class TestSSLSocketPair {
+ public final TestSSLContext c;
+ public final SSLSocket server;
+ public final SSLSocket client;
+
+ private TestSSLSocketPair (TestSSLContext c,
+ SSLSocket server,
+ SSLSocket client) {
+ this.c = c;
+ this.server = server;
+ this.client = client;
+ }
+
+ /**
+ * based on test_SSLSocket_startHandshake_workaround, should
+ * be written to non-workaround form when possible
+ */
+ public static TestSSLSocketPair create_workaround () {
+ TestSSLContext c = TestSSLContext.create();
+ SSLSocket[] sockets = connect_workaround(c, null);
+ return new TestSSLSocketPair(c, sockets[0], sockets[1]);
+ }
+
+ /**
+ * Create a new connected server/client socket pair within a
+ * existing SSLContext. Optional clientCipherSuites allows
+ * forcing new SSLSession to test SSLSessionContext caching
+ */
+ public static SSLSocket[] connect_workaround (final TestSSLContext c,
+ String[] clientCipherSuites) {
+ try {
+ final SSLSocket[] server = new SSLSocket[1];
+ Thread thread = new Thread(new Runnable () {
+ public void run() {
+ try {
+ server[0] = (SSLSocket) c.serverSocket.accept();
+ server[0].startHandshake();
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ thread.start();
+ SSLSocket client = (SSLSocket)
+ c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ if (clientCipherSuites != null) {
+ client.setEnabledCipherSuites(clientCipherSuites);
+ }
+ client.startHandshake();
+ thread.join();
+ return new SSLSocket[] { server[0], client };
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
+