summaryrefslogtreecommitdiffstats
path: root/support
diff options
context:
space:
mode:
authorBrian Carlstrom <bdc@google.com>2010-05-02 11:27:52 -0700
committerBrian Carlstrom <bdc@google.com>2010-05-04 10:42:51 -0700
commitbcfb325d5b1f9529b439cc0805a1c140521510f7 (patch)
tree8f87598618a00c5b56fb78834bed49916fc37ce9 /support
parent6e1c2a95596e3ea72b48c7b54395131acbeab1da (diff)
downloadlibcore-bcfb325d5b1f9529b439cc0805a1c140521510f7.zip
libcore-bcfb325d5b1f9529b439cc0805a1c140521510f7.tar.gz
libcore-bcfb325d5b1f9529b439cc0805a1c140521510f7.tar.bz2
OpenSSLSocket handshake overhaul
Summary: - SSLSocket.startHandshake now generalized to handle both client and server handshaking as well as client/server role reversal - handshake_cutthrough.patch is properly integrated with support delayed handshake completion now integrated with delayed updates to session cache and callbacks to HandshakeCompletedListeners - Many fixes to SSLSession, which is the end product of the handshake - Generally more RI and SSLEngine compliant behavior. - More native code deletion through unification of client/server handshake, unification of client/server certificate chain verification, etc. More native code moved from various OpenSSL classes to cleaner NativeCrypto interfaces that more directly mirror the OpenSSL interfaces. Details: Delay SSL_new call until handshake time when we know for sure whether the OpenSSLSocket will be used in client or server mode and we can allocate the SSL_new from the apppriate client or server SSL_CTX used for session caching. Now that no SSL is allocated for an OpenSSLServerSocketImpl, store enabledProtocols and enabledCipherSuites in instance String arrays. Use new NativeCrypto.checkEnabled* methdods for argument validation. OpenSSLServerSocketImpl passes these enabled arrays to a new OpenSSLSocket constructor during accept(). Removed finalizer from OpenSSLServerSocketImpl since it no longer has any native storage and socket is already closed by PlainSocketImpl finalizer. X-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl.java x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java OpenSSLSocket major overhaul to properly implement handshaking including switching client and server roles and session ID caching with handshake_cutthrough.patch. - now implements NativeCrypto.HandshakeCompletedListeners for properly timed callback when handshake_cutthrough.patch delays handshake completion until first SSLSocket.getInputStream() read. - similar enabledProtocols/enabledCipherSuites changes as OpenSSLServerSocketImpl since we need to store the state somewhere other than an openssl SSL struct until we are sure if we are doing a client or server handshake. - added handshake completed field so that startHandshake can tell if handshake was completed during SSL_do_handshake or will be completed later by a call to HandshakeCompletedCallback.handshakeCompleted. - removed nativegetsession as the equivalent value is now returned by SSL_do_handshake - removed nativecipherauthenticationmethod as the value is now passed to verifyCertificateChain - startHandshake is now a wrapper that forces a fully synchronous handshake - startHandshake(boolean) is the the most changed method in this changelist, combinding both the old startHandshake logic, but also the OpenSSLSocketImpl.accept code as well. Notable differences from the old code: * now responsible for SSL_new * single code path for client/server handshaking dealing with SSLSession caching * now handles server certificate requests previously in OpenSSLServerSocketImpl, since a client can request to act like a server and therefore need to be able to make suck demands on its peer. * supports turning off handshake_cutthrough at a callers request via explicit call to startHandshake() * certificate verification happens during an upcall from openssl during SSL_do_handshake to verifyCertificateChain for both client and server cases. previously there was not quite right upcall support on the server side and post-handshake checking on the client, which did not allow for a proper alert to be sent to the peer informing them of the issue, which the RI and SSLEngine code do. * Similarly, setEnableSessionCreation(false) did not send an alert to the peer as the RI and SSLEngine code in the client case. In the server case, nothing was previously done. * The use of local certificates was not determined from introspecting the SSL struct post-handshake. This is now partially implemented and will be completed in a later change. - SSLSocket.{shutdownInput,shutdownOutput} are now restored to the proper behavior of throwing UnsupportedOperationException. - Gutted OpenSSLSocketImpl finalizer. The comment explains in detail the trouble of having the finalizer do anything more than touch its the instances own state due to unpredictable order of finalization and the future possability of parallel finalization. x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java SSLSession fixes - Made OpenSSLSessionImpl.sessionContext non-final so it could be nulled by SSLSession.invalidate to match RI behavior. - As noted in AbstractSessionContext discussion, removed OpenSSLSessionImpl constructor that took SSLParameters, instead we take the possibly null localCertificates directly. OpenSSLSessionImpl.getLocalCertificates now simply returns the localCertificates member variable instead of incorrectly trying to query the KeyManager for certificates that may not have been used. - OpenSSLSessionImpl now caches its native ID to avoid numerious native calls but also now provides as resetId which will update the cache when a delayed handshake happens due to the handshake_cutthrough.patch - Fixed bug in getPeerPrincipal that it wasn't calling getPeerCertificates to initialize peerCertificates field. - freeImpl is now 'public static' in preparation for move to NativeCrypto. x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java The old SSLSessionImpl class that is still used for representing the invalid session now returns isValid => false and getProtocol => "NONE" to match the RI. x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLSessionImpl.java NativeCrypto improvements - Adding NativeCrypto.SSL_{get,set,clear}_mode similar to NativeCrypto.SSL_{get,set,clear}_options along with SSL_MODE_HANDSHAKE_CUTTHROUGH constant which is used to explicitly disable/enable the Android handshake_cutthrough.patch behavior. - Added missing NativeCrypto.SSL_clear_options and used to properly implement NativeCrypto.setEnabledProtocols. - Added NativeCrypto.checkEnabledProtocols and NativeCrypto.checkEnabledCipherSuites helpers to implement exception compatability with the RI. While some of this code is refactored from existing NativeCrypto code, it is now also used by OpenSSLServerSocketImpl and OpenSSLSocketImpl which maintain their own String[]s of what is enabled until startHandshake time. (see below) - Changed NativeCrypto.findSuite to use foreach style loop for clarity. - Moved OpenSSLServerSocketImpl nativesetclientauth and SSL_VERIFY_* constants to NativeCrypto.SSL_set_verify - Added NativeCrypto.SSL_set_session based on part of old OpenSSLSocketImpl.nativeconnect - Added NativeCrypto.SSL_set_session_creation_enabled to properly implement SSLSocket.setEnableSessionCreation(false) which uses new external/openssl/patches/jsse.patch functionality. - New NativeCrypto.SSL_do_handshake consolidates OpenSSLSocketImpl.{nativeconnect, nativeaccept} while properly implementing SSLSocket.setUseClientMode(false) for clients and SSLSocket.setUseClientMode(true) for servers. - New NativeCrypto.SSL_get_certificate is determine if local certificate requested by peer. While functional, currently NativeCrypto.SSL_new always sets a value via SSL_use_certificate instead of relying on a callback set via SSL_CTX_set_client_cert_cb. - Changed NativeCrypto.CertificateChainVerifier.verifyCertificateChain to throw a checked CertificateException to match TrustManager.{checkServerTrusted, checkClientTrusted}. It also takes an authMethod so avoid the need to call the old OpenSSLSocketImpl.nativecipherauthenticationmethod. - Added NativeCrypto.HandshakeCompletedCallback which has its handshakeCompleted method called from OpenSSL when the now delayed handshake_cutthrough.patch handshake is completed so SSLSession caching can be delayed until a session ID is available and to provide a better time for HandshakeCompletedListeners to be notified. x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp Some other changes specific to the naitve side of the code - Added JNITRACE calls (enabled at compile time with JNI_TRACE) for future debugging. - throw SSLException subclass of IOException instead IOException itself for better RI compatability x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp - changed from old struct app_data to new class AppData at enh's request Remove dubious usage of SSLParameters within AbstractSessionContext to pass through to OpenSSLSessionImpl constructor for use in calling getLocalCertificates for sessions created from a byte array with AbstractSessionContext.toSession. Our AbstractSessionContext.toBytes doesn't currently include the local certificates in its output, so it cannot be expected to have in toSession. x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLParameters.java Test maintenance openssl 1.0.0 adds support for RFC 4507 session tickets which remove the need for server side session state. These tests needed to be updated for this new behavior. If IS_RI is true, they still follow the old behavior. 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 Update KnownFailures and add specific comments at point of failure about what remains to be fixed. luni/src/test/java/javax/net/ssl/SSLSessionTest.java Added tests to cover the use of standard cipher suite names. Historically Android has used OpenSSL string constants for cipher suite names, but JSSE actually specifies supported and expected names. luni/src/test/java/javax/net/ssl/SSLSocketFactoryTest.java luni/src/test/java/javax/net/ssl/SSLSocketTest.java Create new support/src/test/java/javax/net/ssl with old Helper support code pulled from javax.net.ssl tests: SSLContextTest.Helper -> TestSSLContext SSLSocketTest.Helper -> TestSSLSocketPair SSLSessionTest.Helper -> TestSSLSessions Also added new StandardNames here, which contains a collection of expected constants for test validation. luni/src/test/java/javax/net/ssl/SSLContextTest.java luni/src/test/java/javax/net/ssl/SSLSocketTest.java luni/src/test/java/javax/net/ssl/SSLSessionTest.java support/src/test/java/javax/net/ssl/TestSSLContext.java support/src/test/java/javax/net/ssl/TestSSLSocketPair.java support/src/test/java/javax/net/ssl/TestSSLSessions.java support/src/test/java/javax/net/ssl/StandardNames.java Removed some now fixed KnownFailures and unneeded !IS_RI code. Marked some [Un]KnownFailures where exceptions are thrown and visible in the output but aren't correctly causing the test to fail. Fixed assertNonNull to assertTrue in test_SSLSocketTest_Test_create. Added stress_test_SSLSocketTest_Test_create to track down test flakiness, leading to rewrite of SSLSocket finalization. luni/src/test/java/javax/net/ssl/SSLSocketTest.java Reenable javax.net.ssl.AllTests now that it is does not hang luni/src/test/java/tests/AllTests.java Improve error messages while debugging overflow problem. Added new assert when debugging new RFC 4507 behavior. Removed KnownFailure annotation for now working test case. x-net/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java Client code changes Now that startHandshake implies synchronous vs Android's default async handshake, remove unneeded explict calls to SSLSocket.startHandshake luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnection.java Removed IBM 1.4.x codepath that involved startHandshake x-net/src/main/java/javax/net/ssl/DefaultHostnameVerifier.java Unrelated Remove unneed SSLSocket.setUseClientMode while removing unneeded SSLSocket.startHandshake luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpConnection.java Removed warnings due to now missing modules in classpath run-core-tests Change-Id: I6e149ae259b3feccdfb0673209c85cfeb60befc8
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);
+ }
+ }
+}
+