summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DefaultSSLContextImpl.java2
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java10
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java38
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLContextImpl.java52
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java6
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java55
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java6
-rw-r--r--luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java29
-rw-r--r--luni/src/main/native/NativeCrypto.cpp181
-rw-r--r--luni/src/test/java/java/net/URLConnectionTest.java22
-rw-r--r--luni/src/test/java/javax/net/ssl/SSLContextTest.java17
-rw-r--r--luni/src/test/java/javax/net/ssl/SSLEngineTest.java73
-rw-r--r--luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java101
-rw-r--r--luni/src/test/java/javax/net/ssl/SSLSessionTest.java27
-rw-r--r--luni/src/test/java/javax/net/ssl/SSLSocketTest.java93
-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
20 files changed, 854 insertions, 334 deletions
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DefaultSSLContextImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DefaultSSLContextImpl.java
index 609a448..5057518 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DefaultSSLContextImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/DefaultSSLContextImpl.java
@@ -34,7 +34,7 @@ import javax.net.ssl.TrustManagerFactory;
/**
* Support class for this package.
*/
-public final class DefaultSSLContextImpl extends SSLContextImpl {
+public final class DefaultSSLContextImpl extends OpenSSLContextImpl {
/**
* Accessed by SSLContextImpl(DefaultSSLContextImpl) holding the
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
index 35cac53..62b6560 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
@@ -110,15 +110,13 @@ public final class JSSEProvider extends Provider {
super("HarmonyJSSE", 1.0, "Harmony JSSE Provider");
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
+ put("SSLContext.SSL", SSLContextImpl.class.getName());
+ put("SSLContext.SSLv3", SSLContextImpl.class.getName());
put("SSLContext.TLS", SSLContextImpl.class.getName());
- put("Alg.Alias.SSLContext.TLSv1", "TLS");
+ put("SSLContext.TLSv1", SSLContextImpl.class.getName());
+
put("KeyManagerFactory.X509", KeyManagerFactoryImpl.class.getName());
put("TrustManagerFactory.X509", TrustManagerFactoryImpl.class.getName());
- // BEGIN android-added
- put("SSLContext.Default", DefaultSSLContextImpl.class.getName());
- put("SSLContext.SSL", SSLContextImpl.class.getName());
- put("Alg.Alias.SSLContext.SSLv3", "SSL");
- // END android-added
return null;
}
});
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
index 63275f0..5de1e8e 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/NativeCrypto.java
@@ -254,7 +254,30 @@ public final class NativeCrypto {
public static native int SSL_new(int ssl_ctx) throws IOException;
- public static final String[] KEY_TYPES = new String[] { "RSA", "DSA", "DH_RSA" , "DH_DSA" };
+ public static final String[] KEY_TYPES = new String[] {
+ "RSA",
+ "DSA",
+ "DH_RSA",
+ "DH_DSA",
+ "EC"
+ };
+
+ public static String keyType(int keyType) {
+ switch (keyType) {
+ case 1: // TLS_CT_RSA_SIGN
+ return "RSA";
+ case 2: // TLS_CT_DSS_SIGN
+ return "DSA";
+ case 3: // TLS_CT_RSA_FIXED_DH
+ return "DH_RSA";
+ case 4: // TLS_CT_DSS_FIXED_DH
+ return "DH_DSA";
+ case 64: // TLS_CT_ECDSA_SIGN
+ return "EC";
+ default:
+ return null;
+ }
+ }
public static native void SSL_use_certificate(int ssl, byte[][] asn1DerEncodedCertificate);
@@ -414,7 +437,7 @@ public final class NativeCrypto {
public static native byte[] SSL_SESSION_session_id(int sslSessionNativePointer);
/**
- * Returns the X509 certificates of the peer in the PEM format.
+ * Returns the ASN.1 DER encoded X509 certificates of the peer.
*/
public static native byte[][] SSL_SESSION_get_peer_cert_chain(int sslCtxNativePointer,
int sslSessionNativePointer);
@@ -439,12 +462,12 @@ public final class NativeCrypto {
/**
* Verify that we trust the certificate chain is trusted.
*
- * @param bytes An array of certficates in PEM encode bytes
+ * @param asn1DerEncodedCertificate An array of ASN.1 DER encoded certficates
* @param authMethod auth algorithm name
*
* @throws CertificateException if the certificate is untrusted
*/
- public void verifyCertificateChain(byte[][] bytes, String authMethod)
+ public void verifyCertificateChain(byte[][] asn1DerEncodedCertificate, String authMethod)
throws CertificateException;
/**
@@ -454,9 +477,12 @@ public final class NativeCrypto {
* certificate if has an appropriate one available, similar to
* how the server provides its certificate.
*
- * @param keyType One of KEY_TYPES such as RSA or DSA
+ * @param keyTypes key types supported by the server,
+ * convertible to strings with #keyType
+ * @param asn1DerEncodedX500Principals CAs known to the server
*/
- public void clientCertificateRequested(String keyType)
+ public void clientCertificateRequested(byte[] keyTypes,
+ byte[][] asn1DerEncodedX500Principals)
throws IOException;
/**
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLContextImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLContextImpl.java
new file mode 100644
index 0000000..b4e4a46
--- /dev/null
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLContextImpl.java
@@ -0,0 +1,52 @@
+/*
+ * 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 org.apache.harmony.xnet.provider.jsse;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * Overrides the original SSLContextImpl to provide OpenSSL-based
+ * SSLSocketFactory and SSLServerSocketFactory instances.
+ */
+public class OpenSSLContextImpl extends SSLContextImpl {
+
+ public OpenSSLContextImpl() {}
+
+ protected OpenSSLContextImpl(DefaultSSLContextImpl dummy)
+ throws GeneralSecurityException, IOException {
+ super(dummy);
+ }
+
+ @Override
+ public SSLSocketFactory engineGetSocketFactory() {
+ if (sslParameters == null) {
+ throw new IllegalStateException("SSLContext is not initialized.");
+ }
+ return new OpenSSLSocketFactoryImpl(sslParameters);
+ }
+
+ @Override
+ public SSLServerSocketFactory engineGetServerSocketFactory() {
+ if (sslParameters == null) {
+ throw new IllegalStateException("SSLContext is not initialized.");
+ }
+ return new OpenSSLServerSocketFactoryImpl(sslParameters);
+ }
+}
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
index 01681f1..4c8ad3a 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLProvider.java
@@ -23,6 +23,12 @@ public final class OpenSSLProvider extends Provider {
public OpenSSLProvider() {
super("AndroidOpenSSL", 1.0, "Android's OpenSSL-backed security provider");
+ put("SSLContext.SSL", OpenSSLContextImpl.class.getName());
+ put("SSLContext.SSLv3", OpenSSLContextImpl.class.getName());
+ put("SSLContext.TLS", OpenSSLContextImpl.class.getName());
+ put("SSLContext.TLSv1", OpenSSLContextImpl.class.getName());
+ put("SSLContext.Default", DefaultSSLContextImpl.class.getName());
+
put("MessageDigest.SHA-1",
"org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK$SHA1");
put("Alg.Alias.MessageDigest.SHA1", "SHA-1");
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
index 0435717..3349926 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl.java
@@ -35,6 +35,7 @@ import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
+import javax.security.auth.x500.X500Principal;
import org.apache.harmony.security.provider.cert.X509CertImpl;
/**
@@ -308,7 +309,7 @@ public class OpenSSLSocketImpl
for (String keyType : NativeCrypto.KEY_TYPES) {
setCertificate(sslParameters.getKeyManager().chooseServerAlias(keyType,
null,
- null));
+ this));
}
}
@@ -354,6 +355,18 @@ public class OpenSSLSocketImpl
NativeCrypto.SSL_VERIFY_CLIENT_ONCE);
}
// ... and it defaults properly so we don't need call SSL_set_verify in the common case.
+
+ // TODO Need to call SSL_CTX_set_client_CA_list to notify trusted issuers to client
+ //
+ // From SSL_CTX_load_verify_locations(3SSL)
+ // In server mode, when requesting a client
+ // certificate, the server must send the list of CAs
+ // of which it will accept client certificates. This
+ // list is not influenced by the contents of CAfile or
+ // CApath and must explicitly be set using the
+ // SSL_CTX_set_client_CA_list(3) family of functions.
+ //
+ // We can get the list from sslParameters.getTrustManager().getAcceptedIssuers()
}
if (client && full) {
@@ -398,15 +411,7 @@ public class OpenSSLSocketImpl
} else {
localCertificates = new X509Certificate[localCertificatesBytes.length];
for (int i = 0; i < localCertificatesBytes.length; i++) {
- try {
- // TODO do not go through PEM decode, DER encode, DER decode
- localCertificates[i]
- = new X509CertImpl(
- javax.security.cert.X509Certificate.getInstance(
- localCertificatesBytes[i]).getEncoded());
- } catch (javax.security.cert.CertificateException e) {
- throw new IOException("Problem decoding local certificate", e);
- }
+ localCertificates[i] = new X509CertImpl(localCertificatesBytes[i]);
}
}
@@ -441,7 +446,7 @@ public class OpenSSLSocketImpl
}
- private void setCertificate (String alias) throws IOException {
+ private void setCertificate(String alias) throws IOException {
if (alias == null) {
return;
}
@@ -459,9 +464,6 @@ public class OpenSSLSocketImpl
throw new IOException("Problem encoding certificate " + certificates[i], e);
}
}
- // TODO SSL_use_certificate only looks at the first certificate in the chain.
- // It would be better to use a custom version of SSL_CTX_use_certificate_chain_file
- // to set the whole chain. Note there is no SSL_ equivalent of this SSL_CTX_ function.
NativeCrypto.SSL_use_certificate(sslNativePointer, certificateBytes);
// checks the last installed private key and certificate,
@@ -473,10 +475,25 @@ public class OpenSSLSocketImpl
* Implementation of NativeCrypto.SSLHandshakeCallbacks
* invoked via JNI from client_cert_cb
*/
- public void clientCertificateRequested(String keyType) throws IOException {
- setCertificate(sslParameters.getKeyManager().chooseClientAlias(new String[] { keyType },
- null,
- null));
+ public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
+ throws IOException {
+
+ String[] keyTypes = new String[keyTypeBytes.length];
+ for (int i = 0; i < keyTypeBytes.length; i++) {
+ keyTypes[i] = NativeCrypto.keyType(keyTypeBytes[i]);
+ }
+
+ X500Principal[] issuers;
+ if (asn1DerEncodedPrincipals == null) {
+ issuers = null;
+ } else {
+ issuers = new X500Principal[asn1DerEncodedPrincipals.length];
+ for (int i = 0; i < asn1DerEncodedPrincipals.length; i++) {
+ issuers[i] = new X500Principal(asn1DerEncodedPrincipals[i]);
+ }
+ }
+
+ setCertificate(sslParameters.getKeyManager().chooseClientAlias(keyTypes, issuers, this));
}
/**
@@ -533,7 +550,7 @@ public class OpenSSLSocketImpl
/**
* Implementation of NativeCrypto.SSLHandshakeCallbacks
*
- * @param bytes An array of certficates in PEM encode bytes
+ * @param bytes An array of ASN.1 DER encoded certficates
* @param authMethod auth algorithm name
*
* @throws CertificateException if the certificate is untrusted
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java
index 06f569b..44f6c7f 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLContextImpl.java
@@ -56,6 +56,7 @@ public class SSLContextImpl extends SSLContextSpi {
clientSessionContext = new ClientSessionContext();
serverSessionContext = new ServerSessionContext();
}
+
/**
* Constuctor for the DefaultSSLContextImpl.
* @param dummy is null, used to distinguish this case from the
@@ -110,11 +111,12 @@ public class SSLContextImpl extends SSLContextSpi {
engineGetServerSessionContext().setPersistentCache(serverCache);
}
+ @Override
public SSLSocketFactory engineGetSocketFactory() {
if (sslParameters == null) {
throw new IllegalStateException("SSLContext is not initialized.");
}
- return new OpenSSLSocketFactoryImpl(sslParameters);
+ return new SSLSocketFactoryImpl(sslParameters);
}
@Override
@@ -122,7 +124,7 @@ public class SSLContextImpl extends SSLContextSpi {
if (sslParameters == null) {
throw new IllegalStateException("SSLContext is not initialized.");
}
- return new OpenSSLServerSocketFactoryImpl(sslParameters);
+ return new SSLServerSocketFactoryImpl(sslParameters);
}
@Override
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
index 502396e..8ccf085 100644
--- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/TrustManagerImpl.java
@@ -20,8 +20,10 @@ package org.apache.harmony.xnet.provider.jsse;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.PKIXParameters;
@@ -32,15 +34,8 @@ import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
-
import javax.net.ssl.X509TrustManager;
-// BEGIN android-added
-import java.lang.reflect.Method;
-import java.security.cert.CertPath;
-import java.security.cert.CertificateEncodingException;
-// END android-added
-
/**
*
* TrustManager implementation. The implementation is based on CertPathValidator
@@ -109,7 +104,7 @@ public class TrustManagerImpl implements X509TrustManager {
throw new CertificateException(err);
}
// BEGIN android-added
- // Cater for degenerate special case where we can't
+ // Caters to degenerate special case where we can't
// establish an actual certificate chain the usual way,
// but have the peer certificate in our trust store.
if (isDirectlyTrustedCert(chain)) {
@@ -122,7 +117,8 @@ public class TrustManagerImpl implements X509TrustManager {
if (!Arrays.equals(chain[0].getEncoded(),
((X509Certificate)certPath.getCertificates().get(0))
.getEncoded())) {
- // sanity check failed (shouldn't ever happen, but we are using pretty remote code)
+ // Sanity check failed (shouldn't ever happen, but we
+ // are using pretty remote code)
throw new CertificateException("Certificate chain error");
}
validator.validate(certPath, params);
@@ -142,29 +138,29 @@ public class TrustManagerImpl implements X509TrustManager {
throws CertificateException {
if (chain == null || chain.length == 0 || authType == null
|| authType.length() == 0) {
- throw new IllegalArgumentException(
- "null or zero-length parameter");
+ throw new IllegalArgumentException("null or zero-length parameter");
}
if (err != null) {
throw new CertificateException(err);
}
-// BEGIN android-changed
+ // BEGIN android-changed
CertificateException ce = null;
try {
- CertPath certPath = factory.generateCertPath(
- Arrays.asList(chain));
+ CertPath certPath = factory.generateCertPath(Arrays.asList(chain));
if (!Arrays.equals(chain[0].getEncoded(),
certPath.getCertificates().get(0).getEncoded())) {
- // Sanity check failed (shouldn't ever happen, but we are
- // using pretty remote code)
+ // Sanity check failed (shouldn't ever happen, but we
+ // are using pretty remote code)
throw new CertificateException("Certificate chain error");
}
validator.validate(certPath, params);
+ // END android-changed
} catch (InvalidAlgorithmParameterException e) {
ce = new CertificateException(e);
} catch (CertPathValidatorException e) {
ce = new CertificateException(e);
}
+ // BEGIN android-added
if (ce != null) {
// Caters to degenerate special case where we can't
// establish an actual certificate chain the usual way
@@ -173,6 +169,7 @@ public class TrustManagerImpl implements X509TrustManager {
throw ce;
}
}
+ // END android-added
}
/**
diff --git a/luni/src/main/native/NativeCrypto.cpp b/luni/src/main/native/NativeCrypto.cpp
index c3c4a91..3f1825b 100644
--- a/luni/src/main/native/NativeCrypto.cpp
+++ b/luni/src/main/native/NativeCrypto.cpp
@@ -151,6 +151,11 @@ static void freeSslErrorState(void) {
ERR_remove_state(0);
}
+// FIXME: move to JNIHelp.h
+static void jniThrowOutOfMemoryError(JNIEnv* env, const char* message) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", message);
+}
+
/*
* Checks this thread's OpenSSL error queue and throws a RuntimeException if
* necessary.
@@ -1035,37 +1040,74 @@ static jobjectArray getCertificateBytes(JNIEnv* env, const STACK_OF(X509)* chain
return NULL;
}
- Unique_BIO bio(BIO_new(BIO_s_mem()));
- if (bio.get() == NULL) {
- jniThrowRuntimeException(env, "BIO_new failed");
+ for (int i = 0; i < count; i++) {
+ X509* cert = sk_X509_value(chain, i);
+
+ int len = i2d_X509(cert, NULL);
+ if (len < 0) {
+ return NULL;
+ }
+ ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(len));
+ if (byteArray.get() == NULL) {
+ return NULL;
+ }
+ ScopedByteArrayRW bytes(env, byteArray.get());
+ if (bytes.get() == NULL) {
+ return NULL;
+ }
+ unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get());
+ int n = i2d_X509(cert, &p);
+ if (n < 0) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(joa, i, byteArray.get());
+ }
+
+ return joa;
+}
+
+/**
+ * Returns an array containing all the X500 principal's bytes.
+ */
+static jobjectArray getPrincipalBytes(JNIEnv* env, const STACK_OF(X509_NAME)* names)
+{
+ if (names == NULL) {
return NULL;
}
- // LOGD("Start fetching the certificates");
- for (int i = 0; i < count; i++) {
- X509* cert = sk_X509_value(chain, i);
+ int count = sk_X509_NAME_num(names);
+ if (count <= 0) {
+ return NULL;
+ }
- BIO_reset(bio.get());
- PEM_write_bio_X509(bio.get(), cert);
+ jobjectArray joa = env->NewObjectArray(count, JniConstants::byteArrayClass, NULL);
+ if (joa == NULL) {
+ return NULL;
+ }
- BUF_MEM* bptr;
- BIO_get_mem_ptr(bio.get(), &bptr);
- jbyteArray bytes = env->NewByteArray(bptr->length);
+ for (int i = 0; i < count; i++) {
+ X509_NAME* principal = sk_X509_NAME_value(names, i);
- if (bytes == NULL) {
- /*
- * Indicate an error by resetting joa to NULL. It will
- * eventually get gc'ed.
- */
- joa = NULL;
- break;
+ int len = i2d_X509_NAME(principal, NULL);
+ if (len < 0) {
+ return NULL;
+ }
+ ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(len));
+ if (byteArray.get() == NULL) {
+ return NULL;
+ }
+ ScopedByteArrayRW bytes(env, byteArray.get());
+ if (bytes.get() == NULL) {
+ return NULL;
+ }
+ unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get());
+ int n = i2d_X509_NAME(principal, &p);
+ if (n < 0) {
+ return NULL;
}
- jbyte* src = reinterpret_cast<jbyte*>(bptr->data);
- env->SetByteArrayRegion(bytes, 0, bptr->length, src);
- env->SetObjectArrayElement(joa, i, bytes);
+ env->SetObjectArrayElement(joa, i, byteArray.get());
}
- // LOGD("Certificate fetching complete");
return joa;
}
@@ -1492,14 +1534,37 @@ static int client_cert_cb(SSL* ssl, X509** x509Out, EVP_PKEY** pkeyOut) {
jclass cls = env->GetObjectClass(sslHandshakeCallbacks);
jmethodID methodID
- = env->GetMethodID(cls, "clientCertificateRequested", "(Ljava/lang/String;)V");
+ = env->GetMethodID(cls, "clientCertificateRequested", "([B[[B)V");
// Call Java callback which can use SSL_use_certificate and SSL_use_PrivateKey to set values
- const char* authMethod = SSL_authentication_method(ssl);
- JNI_TRACE("ssl=%p clientCertificateRequested calling clientCertificateRequested authMethod=%s",
- ssl, authMethod);
- jstring authMethodString = env->NewStringUTF(authMethod);
- env->CallVoidMethod(sslHandshakeCallbacks, methodID, authMethodString);
+ char ssl2_ctype = SSL3_CT_RSA_SIGN;
+ const char* ctype = NULL;
+ int ctype_num = 0;
+ jobjectArray issuers = NULL;
+ switch (ssl->version) {
+ case SSL2_VERSION:
+ ctype = &ssl2_ctype;
+ ctype_num = 1;
+ break;
+ case SSL3_VERSION:
+ case TLS1_VERSION:
+ case DTLS1_VERSION:
+ ctype = ssl->s3->tmp.ctype;
+ ctype_num = ssl->s3->tmp.ctype_num;
+ issuers = getPrincipalBytes(env, ssl->s3->tmp.ca_names);
+ break;
+ }
+
+ jbyteArray keyTypes = env->NewByteArray(ctype_num);
+ if (keyTypes == NULL) {
+ JNI_TRACE("ssl=%p client_cert_cb bytes == null => 0", ssl);
+ return 0;
+ }
+ env->SetByteArrayRegion(keyTypes, 0, ctype_num, reinterpret_cast<const jbyte*>(ctype));
+
+ JNI_TRACE("ssl=%p clientCertificateRequested calling clientCertificateRequested "
+ "keyTypes=%p issuers=%p", ssl, keyTypes, issuers);
+ env->CallVoidMethod(sslHandshakeCallbacks, methodID, keyTypes, issuers);
if (env->ExceptionCheck()) {
JNI_TRACE("ssl=%p client_cert_cb exception => 0", ssl);
@@ -1812,6 +1877,29 @@ static void NativeCrypto_SSL_use_certificate(JNIEnv* env, jclass,
return;
}
+ Unique_sk_X509 chain(sk_X509_new_null());
+ if (chain.get() == NULL) {
+ jniThrowOutOfMemoryError(env, "Unable to allocate local certificate chain");
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => chain allocation error", ssl);
+ return;
+ }
+ for (int i = 1; i < length; i++) {
+ if (!sk_X509_push(chain.get(), certificatesX509[i].release())) {
+ jniThrowOutOfMemoryError(env, "Unable to push certificate");
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificate push error", ssl);
+ return;
+ }
+ }
+ int chainResult = SSL_use_certificate_chain(ssl, chain.get());
+ if (chainResult == 0) {
+ throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate chain");
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate_chain error",
+ ssl);
+ return;
+ } else {
+ chain.release();
+ }
+
JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => ok", ssl);
}
@@ -1957,7 +2045,11 @@ static void NativeCrypto_SSL_set_cipher_lists(JNIEnv* env, jclass,
const SSL_CIPHER* cipher = ssl_method->get_cipher(j);
if ((strcmp(c.c_str(), cipher->name) == 0)
&& (strcmp(SSL_CIPHER_get_version(cipher), "SSLv2"))) {
- sk_SSL_CIPHER_push(cipherstack.get(), cipher);
+ if (!sk_SSL_CIPHER_push(cipherstack.get(), cipher)) {
+ jniThrowOutOfMemoryError(env, "Unable to push cipher");
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists => cipher push error", ssl);
+ return;
+ }
found = true;
}
}
@@ -2228,17 +2320,27 @@ static jobjectArray NativeCrypto_SSL_get_certificate(JNIEnv* env, jclass, jint s
JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl);
return NULL;
}
- // TODO convert from single certificate to chain properly. One
- // option would be to have the chain remembered where
- // SSL_use_certificate is used. Another would be to save the
- // intermediate CAs with SSL_CTX SSL_CTX_add_extra_chain_cert.
+
Unique_sk_X509 chain(sk_X509_new_null());
if (chain.get() == NULL) {
- jniThrowRuntimeException(env, "Unable to allocate local certificate chain");
+ jniThrowOutOfMemoryError(env, "Unable to allocate local certificate chain");
JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => threw exception", ssl);
return NULL;
}
- sk_X509_push(chain.get(), certificate);
+ if (!sk_X509_push(chain.get(), certificate)) {
+ jniThrowOutOfMemoryError(env, "Unable to push local certificate");
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl);
+ return NULL;
+ }
+ STACK_OF(X509)* cert_chain = SSL_get_certificate_chain(ssl, certificate);
+ for (int i=0; i<sk_X509_num(cert_chain); i++) {
+ if (!sk_X509_push(chain.get(), sk_X509_value(cert_chain,i))) {
+ jniThrowOutOfMemoryError(env, "Unable to push local certificate chain");
+ JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl);
+ return NULL;
+ }
+ }
+
jobjectArray objectArray = getCertificateBytes(env, chain.get());
JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => %p", ssl, objectArray);
return objectArray;
@@ -2438,7 +2540,7 @@ static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jint
// See sslRead() regarding improper failure to handle normal cases.
throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Read error");
result = -1;
- } else if(ret == THROW_SOCKETTIMEOUTEXCEPTION) {
+ } else if (ret == THROW_SOCKETTIMEOUTEXCEPTION) {
throwSocketTimeoutException(env, "Read timed out");
result = -1;
} else {
@@ -2593,7 +2695,7 @@ static void NativeCrypto_SSL_write_byte(JNIEnv* env, jclass, jint ssl_address, j
if (ret == THROW_EXCEPTION) {
// See sslWrite() regarding improper failure to handle normal cases.
throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Write error");
- } else if(ret == THROW_SOCKETTIMEOUTEXCEPTION) {
+ } else if (ret == THROW_SOCKETTIMEOUTEXCEPTION) {
throwSocketTimeoutException(env, "Write timed out");
}
}
@@ -2627,7 +2729,7 @@ static void NativeCrypto_SSL_write(JNIEnv* env, jclass,
if (ret == THROW_EXCEPTION) {
// See sslWrite() regarding improper failure to handle normal cases.
throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Write error");
- } else if(ret == THROW_SOCKETTIMEOUTEXCEPTION) {
+ } else if (ret == THROW_SOCKETTIMEOUTEXCEPTION) {
throwSocketTimeoutException(env, "Write timed out");
}
}
@@ -2880,7 +2982,8 @@ static jbyteArray NativeCrypto_i2d_SSL_SESSION(JNIEnv* env, jclass, jint ssl_ses
if (bytes != NULL) {
ScopedByteArrayRW tmp(env, bytes);
if (tmp.get() == NULL) {
- JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION => threw exception");
+ JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION => threw exception",
+ ssl_session);
return NULL;
}
unsigned char* ucp = reinterpret_cast<unsigned char*>(tmp.get());
diff --git a/luni/src/test/java/java/net/URLConnectionTest.java b/luni/src/test/java/java/net/URLConnectionTest.java
index 87de3b5..4c6bd83 100644
--- a/luni/src/test/java/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/java/net/URLConnectionTest.java
@@ -261,12 +261,12 @@ public class URLConnectionTest extends junit.framework.TestCase {
public void testConnectViaHttps() throws IOException, InterruptedException {
TestSSLContext testSSLContext = TestSSLContext.create();
- server.useHttps(testSSLContext.sslContext.getSocketFactory(), false);
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
server.play();
HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/foo").openConnection();
- connection.setSSLSocketFactory(testSSLContext.sslContext.getSocketFactory());
+ connection.setSSLSocketFactory(testSSLContext.serverContext.getSocketFactory());
assertContent("this response comes via HTTPS", connection);
@@ -277,14 +277,14 @@ public class URLConnectionTest extends junit.framework.TestCase {
public void testConnectViaHttpsReusingConnections() throws IOException, InterruptedException {
TestSSLContext testSSLContext = TestSSLContext.create();
- server.useHttps(testSSLContext.sslContext.getSocketFactory(), false);
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("this response comes via HTTPS"));
server.enqueue(new MockResponse().setBody("another response via HTTPS"));
server.play();
// install a custom SSL socket factory so the server can be authorized
HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
- connection.setSSLSocketFactory(testSSLContext.sslContext.getSocketFactory());
+ connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
assertContent("this response comes via HTTPS", connection);
// without an SSL socket factory, the connection should fail
@@ -339,7 +339,7 @@ public class URLConnectionTest extends junit.framework.TestCase {
public void testConnectViaHttpProxyToHttps() throws IOException, InterruptedException {
TestSSLContext testSSLContext = TestSSLContext.create();
- server.useHttps(testSSLContext.sslContext.getSocketFactory(), true);
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), true);
server.enqueue(new MockResponse().clearHeaders()); // for CONNECT
server.enqueue(new MockResponse().setBody("this response comes via a secure proxy"));
server.play();
@@ -347,7 +347,7 @@ public class URLConnectionTest extends junit.framework.TestCase {
URL url = new URL("https://android.com/foo");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection(
server.toProxyAddress());
- connection.setSSLSocketFactory(testSSLContext.sslContext.getSocketFactory());
+ connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
connection.setHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
@@ -841,7 +841,7 @@ public class URLConnectionTest extends junit.framework.TestCase {
public void testRedirectedOnHttps() throws IOException, InterruptedException {
TestSSLContext testSSLContext = TestSSLContext.create();
- server.useHttps(testSSLContext.sslContext.getSocketFactory(), false);
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse()
.setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
.addHeader("Location: /foo")
@@ -850,7 +850,7 @@ public class URLConnectionTest extends junit.framework.TestCase {
server.play();
HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
- connection.setSSLSocketFactory(testSSLContext.sslContext.getSocketFactory());
+ connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
assertEquals("This is the new location!",
readAscii(connection.getInputStream(), Integer.MAX_VALUE));
@@ -863,7 +863,7 @@ public class URLConnectionTest extends junit.framework.TestCase {
public void testNotRedirectedFromHttpsToHttp() throws IOException, InterruptedException {
TestSSLContext testSSLContext = TestSSLContext.create();
- server.useHttps(testSSLContext.sslContext.getSocketFactory(), false);
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse()
.setResponseCode(HttpURLConnection.HTTP_MOVED_TEMP)
.addHeader("Location: http://anyhost/foo")
@@ -871,7 +871,7 @@ public class URLConnectionTest extends junit.framework.TestCase {
server.play();
HttpsURLConnection connection = (HttpsURLConnection) server.getUrl("/").openConnection();
- connection.setSSLSocketFactory(testSSLContext.sslContext.getSocketFactory());
+ connection.setSSLSocketFactory(testSSLContext.clientContext.getSocketFactory());
assertEquals("This page has moved!",
readAscii(connection.getInputStream(), Integer.MAX_VALUE));
}
@@ -931,7 +931,7 @@ public class URLConnectionTest extends junit.framework.TestCase {
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
try {
TestSSLContext testSSLContext = TestSSLContext.create();
- server.useHttps(testSSLContext.sslContext.getSocketFactory(), false);
+ server.useHttps(testSSLContext.serverContext.getSocketFactory(), false);
server.enqueue(new MockResponse().setBody("ABC"));
server.enqueue(new MockResponse().setBody("DEF"));
server.enqueue(new MockResponse().setBody("GHI"));
diff --git a/luni/src/test/java/javax/net/ssl/SSLContextTest.java b/luni/src/test/java/javax/net/ssl/SSLContextTest.java
index 9ed372b..104ceee 100644
--- a/luni/src/test/java/javax/net/ssl/SSLContextTest.java
+++ b/luni/src/test/java/javax/net/ssl/SSLContextTest.java
@@ -83,7 +83,7 @@ public class SSLContextTest extends TestCase {
}
}
try {
- SSLContext.getInstance(null, StandardNames.PROVIDER_NAME);
+ SSLContext.getInstance(null, StandardNames.JSSE_PROVIDER_NAME);
fail();
} catch (NullPointerException expected) {
}
@@ -100,7 +100,7 @@ public class SSLContextTest extends TestCase {
public void test_SSLContext_getProvider() throws Exception {
Provider provider = SSLContext.getDefault().getProvider();
assertNotNull(provider);
- assertEquals(StandardNames.PROVIDER_NAME, provider.getName());
+ assertEquals(StandardNames.JSSE_PROVIDER_NAME, provider.getName());
}
public void test_SSLContext_init() throws Exception {
@@ -286,9 +286,16 @@ public class SSLContextTest extends TestCase {
public void test_SSLContextTest_TestSSLContext_create() {
TestSSLContext testContext = TestSSLContext.create();
assertNotNull(testContext);
- assertNotNull(testContext.keyStore);
- assertNull(testContext.keyStorePassword);
- assertNotNull(testContext.sslContext);
+ assertNotNull(testContext.clientKeyStore);
+ assertNull(testContext.clientKeyStorePassword);
+ assertNotNull(testContext.serverKeyStore);
+ assertNull(testContext.serverKeyStorePassword);
+ assertNotNull(testContext.clientKeyManager);
+ assertNotNull(testContext.serverKeyManager);
+ assertNotNull(testContext.clientTrustManager);
+ assertNotNull(testContext.serverTrustManager);
+ assertNotNull(testContext.clientContext);
+ assertNotNull(testContext.serverContext);
assertNotNull(testContext.serverSocket);
assertNotNull(testContext.host);
assertTrue(testContext.port != 0);
diff --git a/luni/src/test/java/javax/net/ssl/SSLEngineTest.java b/luni/src/test/java/javax/net/ssl/SSLEngineTest.java
index 2aa43dd..e731345 100644
--- a/luni/src/test/java/javax/net/ssl/SSLEngineTest.java
+++ b/luni/src/test/java/javax/net/ssl/SSLEngineTest.java
@@ -53,7 +53,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_getSupportedCipherSuites_names() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
String[] cipherSuites = e.getSupportedCipherSuites();
StandardNames.assertSupportedCipherSuites(StandardNames.CIPHER_SUITES_SSLENGINE,
cipherSuites);
@@ -62,8 +62,15 @@ public class SSLEngineTest extends TestCase {
@KnownFailure("No *_WITH_NULL_* ciphers work because of 'Invalid transformation: null'")
public void test_SSLEngine_getSupportedCipherSuites_connect() throws Exception {
- String[] cipherSuites
- = SSLContext.getDefault().createSSLEngine().getSupportedCipherSuites();
+ // note the rare usage of DSA keys here in addition to RSA
+ TestKeyStore testKeyStore = TestKeyStore.create(new String[] { "RSA", "DSA" },
+ null,
+ "rsa-dsa",
+ TestKeyStore.localhost(),
+ true,
+ null);
+ TestSSLContext c = TestSSLContext.create(testKeyStore, testKeyStore);
+ String[] cipherSuites = c.clientContext.createSSLEngine().getSupportedCipherSuites();
for (String cipherSuite : cipherSuites) {
/*
* Kerberos cipher suites require external setup. See "Kerberos Requirements" in
@@ -72,9 +79,9 @@ public class SSLEngineTest extends TestCase {
if (cipherSuite.startsWith("TLS_KRB5_")) {
continue;
}
- System.out.println("Trying to connect cipher suite " + cipherSuite);
+ // System.out.println("Trying to connect cipher suite " + cipherSuite);
final String[] cipherSuiteArray = new String[] { cipherSuite };
- assertConnected(TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ assertConnected(TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setEnabledCipherSuites(cipherSuiteArray);
@@ -86,7 +93,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_getEnabledCipherSuites() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
String[] cipherSuites = e.getEnabledCipherSuites();
StandardNames.assertValidCipherSuites(StandardNames.CIPHER_SUITES_SSLENGINE,
cipherSuites);
@@ -95,7 +102,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_setEnabledCipherSuites() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
try {
e.setEnabledCipherSuites(null);
@@ -120,7 +127,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_getSupportedProtocols() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
String[] protocols = e.getSupportedProtocols();
StandardNames.assertSupportedProtocols(StandardNames.SSL_SOCKET_PROTOCOLS, protocols);
assertNotSame(protocols, e.getSupportedProtocols());
@@ -128,7 +135,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_getEnabledProtocols() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
String[] protocols = e.getEnabledProtocols();
StandardNames.assertValidProtocols(StandardNames.SSL_SOCKET_PROTOCOLS, protocols);
assertNotSame(protocols, e.getEnabledProtocols());
@@ -136,7 +143,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_setEnabledProtocols() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
try {
e.setEnabledProtocols(null);
@@ -160,7 +167,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_getSession() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
SSLSession session = e.getSession();
assertNotNull(session);
assertFalse(session.isValid());
@@ -170,7 +177,7 @@ public class SSLEngineTest extends TestCase {
TestSSLContext c = TestSSLContext.create();
try {
- c.sslContext.createSSLEngine().beginHandshake();
+ c.clientContext.createSSLEngine().beginHandshake();
fail();
} catch (IllegalStateException expected) {
}
@@ -180,27 +187,26 @@ public class SSLEngineTest extends TestCase {
@KnownFailure("NO SERVER CERTIFICATE FOUND")
public void test_SSLEngine_beginHandshake_noKeyStore() throws Exception {
- TestSSLContext c = TestSSLContext.create(null, null);
+ TestSSLContext c = TestSSLContext.create(null, null, null, null);
try {
// TODO Fix KnownFailure AlertException "NO SERVER CERTIFICATE FOUND"
// ServerHandshakeImpl.selectSuite should not select a suite without a required cert
- TestSSLEnginePair.connect(c, c, null);
+ TestSSLEnginePair.connect(c, null);
fail();
} catch (SSLHandshakeException expected) {
}
}
public void test_SSLEngine_beginHandshake_noClientCertificate() throws Exception {
- TestSSLContext serverContext = TestSSLContext.create();
- TestSSLContext clientContext = TestSSLContext.createClient(serverContext);
- SSLEngine[] engines = TestSSLEnginePair.connect(clientContext, serverContext, null);
+ TestSSLContext c = TestSSLContext.create();
+ SSLEngine[] engines = TestSSLEnginePair.connect(c, null);
assertConnected(engines[0], engines[1]);
}
public void test_SSLEngine_getUseClientMode() throws Exception {
TestSSLContext c = TestSSLContext.create();
- assertFalse(c.sslContext.createSSLEngine().getUseClientMode());
- assertFalse(c.sslContext.createSSLEngine(null, -1).getUseClientMode());
+ assertFalse(c.clientContext.createSSLEngine().getUseClientMode());
+ assertFalse(c.clientContext.createSSLEngine(null, -1).getUseClientMode());
}
@KnownFailure("SSLHandshakeException instead assertNotConnected")
@@ -221,7 +227,14 @@ public class SSLEngineTest extends TestCase {
private TestSSLEnginePair test_SSLEngine_setUseClientMode(final boolean clientClientMode,
final boolean serverClientMode)
throws Exception {
- return TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ TestSSLContext c;
+ if (!clientClientMode && serverClientMode) {
+ c = TestSSLContext.create(TestKeyStore.getServer(), TestKeyStore.getClient());
+ } else {
+ c = TestSSLContext.create();
+ }
+
+ return TestSSLEnginePair.create(c, new TestSSLEnginePair.Hooks() {
@Override
void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
client.setUseClientMode(clientClientMode);
@@ -233,7 +246,7 @@ public class SSLEngineTest extends TestCase {
@KnownFailure("init - invalid private key")
public void test_SSLEngine_clientAuth() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
assertFalse(e.getWantClientAuth());
assertFalse(e.getNeedClientAuth());
@@ -254,20 +267,26 @@ public class SSLEngineTest extends TestCase {
assertFalse(e.getNeedClientAuth());
// TODO Fix KnownFailure "init - invalid private key"
- TestSSLEnginePair p = TestSSLEnginePair.create(new TestSSLEnginePair.Hooks() {
+ TestSSLContext clientAuthContext
+ = TestSSLContext.create(TestKeyStore.getClientCertificate(),
+ TestKeyStore.getServer());
+ TestSSLEnginePair p = TestSSLEnginePair.create(clientAuthContext,
+ new TestSSLEnginePair.Hooks() {
@Override
- void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
+ void beforeBeginHandshake(SSLEngine client, SSLEngine server) {
server.setWantClientAuth(true);
}
});
assertConnected(p);
assertNotNull(p.client.getSession().getLocalCertificates());
- assertEquals(1, p.client.getSession().getLocalCertificates().length);
+ TestKeyStore.assertChainLength(p.client.getSession().getLocalCertificates());
+ TestSSLContext.assertClientCertificateChain(clientAuthContext.clientTrustManager,
+ p.client.getSession().getLocalCertificates());
}
public void test_SSLEngine_getEnableSessionCreation() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
assertTrue(e.getEnableSessionCreation());
}
@@ -298,7 +317,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_getSSLParameters() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
SSLParameters p = e.getSSLParameters();
assertNotNull(p);
@@ -320,7 +339,7 @@ public class SSLEngineTest extends TestCase {
public void test_SSLEngine_setSSLParameters() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLEngine e = c.sslContext.createSSLEngine();
+ SSLEngine e = c.clientContext.createSSLEngine();
String[] defaultCipherSuites = e.getEnabledCipherSuites();
String[] defaultProtocols = e.getEnabledProtocols();
String[] supportedCipherSuites = e.getSupportedCipherSuites();
diff --git a/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java b/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java
index 7e2cbd0..0b258b5 100644
--- a/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java
+++ b/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java
@@ -25,10 +25,13 @@ import junit.framework.TestCase;
public class SSLSessionContextTest extends TestCase {
- public static final void assertSSLSessionContextSize(int expected, SSLContext sslContext) {
+ public static final void assertSSLSessionContextSize(int expected, TestSSLContext c) {
assertSSLSessionContextSize(expected,
- sslContext.getClientSessionContext(),
- sslContext.getServerSessionContext());
+ c.clientContext.getClientSessionContext(),
+ c.serverContext.getServerSessionContext());
+ assertSSLSessionContextSize(0,
+ c.serverContext.getClientSessionContext(),
+ c.clientContext.getServerSessionContext());
}
public static final void assertSSLSessionContextSize(int expected,
@@ -51,12 +54,12 @@ public class SSLSessionContextTest extends TestCase {
public void test_SSLSessionContext_getIds() {
TestSSLContext c = TestSSLContext.create();
- assertSSLSessionContextSize(0, c.sslContext);
+ assertSSLSessionContextSize(0, c);
TestSSLSocketPair s = TestSSLSocketPair.create();
- assertSSLSessionContextSize(1, s.c.sslContext);
- Enumeration clientIds = s.c.sslContext.getClientSessionContext().getIds();
- Enumeration serverIds = s.c.sslContext.getServerSessionContext().getIds();
+ assertSSLSessionContextSize(1, s.c);
+ Enumeration clientIds = s.c.clientContext.getClientSessionContext().getIds();
+ Enumeration serverIds = s.c.serverContext.getServerSessionContext().getIds();
byte[] clientId = (byte[]) clientIds.nextElement();
assertEquals(32, clientId.length);
if (TestSSLContext.sslServerSocketSupportsSessionTickets()) {
@@ -71,23 +74,23 @@ public class SSLSessionContextTest extends TestCase {
public void test_SSLSessionContext_getSession() {
TestSSLContext c = TestSSLContext.create();
try {
- c.sslContext.getClientSessionContext().getSession(null);
+ c.clientContext.getClientSessionContext().getSession(null);
fail();
} catch (NullPointerException expected) {
}
- assertNull(c.sslContext.getClientSessionContext().getSession(new byte[0]));
- assertNull(c.sslContext.getClientSessionContext().getSession(new byte[1]));
+ assertNull(c.clientContext.getClientSessionContext().getSession(new byte[0]));
+ assertNull(c.clientContext.getClientSessionContext().getSession(new byte[1]));
try {
- c.sslContext.getServerSessionContext().getSession(null);
+ c.serverContext.getServerSessionContext().getSession(null);
fail();
} catch (NullPointerException expected) {
}
- assertNull(c.sslContext.getServerSessionContext().getSession(new byte[0]));
- assertNull(c.sslContext.getServerSessionContext().getSession(new byte[1]));
+ assertNull(c.serverContext.getServerSessionContext().getSession(new byte[0]));
+ assertNull(c.serverContext.getServerSessionContext().getSession(new byte[1]));
TestSSLSocketPair s = TestSSLSocketPair.create();
- SSLSessionContext client = s.c.sslContext.getClientSessionContext();
- SSLSessionContext server = s.c.sslContext.getServerSessionContext();
+ SSLSessionContext client = s.c.clientContext.getClientSessionContext();
+ SSLSessionContext server = s.c.serverContext.getServerSessionContext();
byte[] clientId = (byte[]) client.getIds().nextElement();
assertNotNull(client.getSession(clientId));
assertTrue(Arrays.equals(clientId, client.getSession(clientId).getId()));
@@ -103,25 +106,25 @@ public class SSLSessionContextTest extends TestCase {
public void test_SSLSessionContext_getSessionCacheSize() {
TestSSLContext c = TestSSLContext.create();
assertEquals(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
- c.sslContext.getClientSessionContext().getSessionCacheSize());
+ c.clientContext.getClientSessionContext().getSessionCacheSize());
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
- c.sslContext.getServerSessionContext().getSessionCacheSize());
+ c.serverContext.getServerSessionContext().getSessionCacheSize());
TestSSLSocketPair s = TestSSLSocketPair.create();
assertEquals(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
- s.c.sslContext.getClientSessionContext().getSessionCacheSize());
+ s.c.clientContext.getClientSessionContext().getSessionCacheSize());
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
- s.c.sslContext.getServerSessionContext().getSessionCacheSize());
+ s.c.serverContext.getServerSessionContext().getSessionCacheSize());
}
public void test_SSLSessionContext_setSessionCacheSize_noConnect() {
TestSSLContext c = TestSSLContext.create();
assertNoConnectSetSessionCacheSizeBehavior(
TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
- c.sslContext.getClientSessionContext());
+ c.clientContext.getClientSessionContext());
assertNoConnectSetSessionCacheSizeBehavior(
TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
- c.sslContext.getServerSessionContext());
+ c.serverContext.getServerSessionContext());
}
private static void assertNoConnectSetSessionCacheSizeBehavior(int expectedDefault,
@@ -138,19 +141,19 @@ public class SSLSessionContextTest extends TestCase {
public void test_SSLSessionContext_setSessionCacheSize_oneConnect() {
TestSSLSocketPair s = TestSSLSocketPair.create();
- SSLSessionContext client = s.c.sslContext.getClientSessionContext();
- SSLSessionContext server = s.c.sslContext.getServerSessionContext();
+ SSLSessionContext client = s.c.clientContext.getClientSessionContext();
+ SSLSessionContext server = s.c.serverContext.getServerSessionContext();
assertEquals(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE,
client.getSessionCacheSize());
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE,
server.getSessionCacheSize());
- assertSSLSessionContextSize(1, s.c.sslContext);
+ assertSSLSessionContextSize(1, s.c);
}
public void test_SSLSessionContext_setSessionCacheSize_dynamic() {
TestSSLContext c = TestSSLContext.create();
- SSLSessionContext client = c.sslContext.getClientSessionContext();
- SSLSessionContext server = c.sslContext.getServerSessionContext();
+ SSLSessionContext client = c.clientContext.getClientSessionContext();
+ SSLSessionContext server = c.serverContext.getServerSessionContext();
String[] supportedCipherSuites = c.serverSocket.getSupportedCipherSuites();
c.serverSocket.setEnabledCipherSuites(supportedCipherSuites);
@@ -198,69 +201,69 @@ public class SSLSessionContextTest extends TestCase {
String cipherSuite3 = uniqueCipherSuites.get(2);
TestSSLSocketPair.connect(c, new String[] { cipherSuite1 }, null);
- assertSSLSessionContextSize(1, c.sslContext);
+ assertSSLSessionContextSize(1, c);
TestSSLSocketPair.connect(c, new String[] { cipherSuite2 }, null);
- assertSSLSessionContextSize(2, c.sslContext);
+ assertSSLSessionContextSize(2, c);
TestSSLSocketPair.connect(c, new String[] { cipherSuite3 }, null);
- assertSSLSessionContextSize(3, c.sslContext);
+ assertSSLSessionContextSize(3, c);
client.setSessionCacheSize(1);
server.setSessionCacheSize(1);
assertEquals(1, client.getSessionCacheSize());
assertEquals(1, server.getSessionCacheSize());
- assertSSLSessionContextSize(1, c.sslContext);
+ assertSSLSessionContextSize(1, c);
TestSSLSocketPair.connect(c, new String[] { cipherSuite1 }, null);
- assertSSLSessionContextSize(1, c.sslContext);
+ assertSSLSessionContextSize(1, c);
client.setSessionCacheSize(2);
server.setSessionCacheSize(2);
TestSSLSocketPair.connect(c, new String[] { cipherSuite2 }, null);
- assertSSLSessionContextSize(2, c.sslContext);
+ assertSSLSessionContextSize(2, c);
TestSSLSocketPair.connect(c, new String[] { cipherSuite3 }, null);
- assertSSLSessionContextSize(2, c.sslContext);
+ assertSSLSessionContextSize(2, c);
}
public void test_SSLSessionContext_getSessionTimeout() {
TestSSLContext c = TestSSLContext.create();
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
- c.sslContext.getClientSessionContext().getSessionTimeout());
+ c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
- c.sslContext.getServerSessionContext().getSessionTimeout());
+ c.serverContext.getServerSessionContext().getSessionTimeout());
TestSSLSocketPair s = TestSSLSocketPair.create();
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
- s.c.sslContext.getClientSessionContext().getSessionTimeout());
+ s.c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
- s.c.sslContext.getServerSessionContext().getSessionTimeout());
+ s.c.serverContext.getServerSessionContext().getSessionTimeout());
}
public void test_SSLSessionContext_setSessionTimeout() throws Exception {
TestSSLContext c = TestSSLContext.create();
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
- c.sslContext.getClientSessionContext().getSessionTimeout());
+ c.clientContext.getClientSessionContext().getSessionTimeout());
assertEquals(TestSSLContext.EXPECTED_DEFAULT_SSL_SESSION_CACHE_TIMEOUT,
- c.sslContext.getServerSessionContext().getSessionTimeout());
- c.sslContext.getClientSessionContext().setSessionTimeout(0);
- c.sslContext.getServerSessionContext().setSessionTimeout(0);
- assertEquals(0, c.sslContext.getClientSessionContext().getSessionTimeout());
- assertEquals(0, c.sslContext.getServerSessionContext().getSessionTimeout());
+ c.serverContext.getServerSessionContext().getSessionTimeout());
+ c.clientContext.getClientSessionContext().setSessionTimeout(0);
+ c.serverContext.getServerSessionContext().setSessionTimeout(0);
+ assertEquals(0, c.clientContext.getClientSessionContext().getSessionTimeout());
+ assertEquals(0, c.serverContext.getServerSessionContext().getSessionTimeout());
try {
- c.sslContext.getClientSessionContext().setSessionTimeout(-1);
+ c.clientContext.getClientSessionContext().setSessionTimeout(-1);
fail();
} catch (IllegalArgumentException expected) {
}
try {
- c.sslContext.getServerSessionContext().setSessionTimeout(-1);
+ c.serverContext.getServerSessionContext().setSessionTimeout(-1);
fail();
} catch (IllegalArgumentException expected) {
}
TestSSLSocketPair s = TestSSLSocketPair.create();
- assertSSLSessionContextSize(1, s.c.sslContext);
+ assertSSLSessionContextSize(1, s.c);
Thread.sleep(1 * 1000);
- s.c.sslContext.getClientSessionContext().setSessionTimeout(1);
- s.c.sslContext.getServerSessionContext().setSessionTimeout(1);
- assertSSLSessionContextSize(0, s.c.sslContext);
+ s.c.clientContext.getClientSessionContext().setSessionTimeout(1);
+ s.c.serverContext.getServerSessionContext().setSessionTimeout(1);
+ assertSSLSessionContextSize(0, s.c);
}
}
diff --git a/luni/src/test/java/javax/net/ssl/SSLSessionTest.java b/luni/src/test/java/javax/net/ssl/SSLSessionTest.java
index 6435af6..f05b04c 100644
--- a/luni/src/test/java/javax/net/ssl/SSLSessionTest.java
+++ b/luni/src/test/java/javax/net/ssl/SSLSessionTest.java
@@ -89,9 +89,11 @@ public class SSLSessionTest extends TestCase {
assertNull(s.invalid.getLocalCertificates());
assertNull(s.client.getLocalCertificates());
assertNotNull(s.server.getLocalCertificates());
- assertEquals(1, s.server.getLocalCertificates().length);
+ TestKeyStore.assertChainLength(s.server.getLocalCertificates());
+ TestSSLContext.assertServerCertificateChain(s.s.c.serverTrustManager,
+ s.server.getLocalCertificates());
TestSSLContext.assertCertificateInKeyStore(s.server.getLocalCertificates()[0],
- s.s.c.keyStore);
+ s.s.c.serverKeyStore);
}
public void test_SSLSession_getLocalPrincipal() throws Exception {
@@ -101,7 +103,7 @@ public class SSLSessionTest extends TestCase {
assertNotNull(s.server.getLocalPrincipal());
assertNotNull(s.server.getLocalPrincipal().getName());
TestSSLContext.assertCertificateInKeyStore(s.server.getLocalPrincipal(),
- s.s.c.keyStore);
+ s.s.c.serverKeyStore);
}
public void test_SSLSession_getPacketBufferSize() {
@@ -119,12 +121,9 @@ public class SSLSessionTest extends TestCase {
} catch (SSLPeerUnverifiedException expected) {
}
assertNotNull(s.client.getPeerCertificates());
- assertEquals(1, s.client.getPeerCertificates().length);
- TestSSLContext.assertCertificateInKeyStore(s.client.getPeerCertificates()[0],
- s.s.c.keyStore);
-
+ TestKeyStore.assertChainLength(s.client.getPeerCertificateChain());
try {
- assertNull(s.server.getPeerCertificates());
+ assertNull(s.server.getPeerCertificateChain());
fail();
} catch (SSLPeerUnverifiedException expected) {
}
@@ -138,9 +137,11 @@ public class SSLSessionTest extends TestCase {
} catch (SSLPeerUnverifiedException expected) {
}
assertNotNull(s.client.getPeerCertificates());
- assertEquals(1, s.client.getPeerCertificates().length);
+ TestKeyStore.assertChainLength(s.client.getPeerCertificates());
+ TestSSLContext.assertServerCertificateChain(s.s.c.serverTrustManager,
+ s.client.getPeerCertificates());
TestSSLContext.assertCertificateInKeyStore(s.client.getPeerCertificates()[0],
- s.s.c.keyStore);
+ s.s.c.serverKeyStore);
try {
s.server.getPeerCertificates();
fail();
@@ -177,7 +178,7 @@ public class SSLSessionTest extends TestCase {
assertNotNull(s.client.getPeerPrincipal());
assertNotNull(s.client.getPeerPrincipal().getName());
TestSSLContext.assertCertificateInKeyStore(s.client.getPeerPrincipal(),
- s.s.c.keyStore);
+ s.s.c.serverKeyStore);
}
public void test_SSLSession_getProtocol() {
@@ -196,9 +197,9 @@ public class SSLSessionTest extends TestCase {
assertNull(s.invalid.getSessionContext());
assertNotNull(s.server.getSessionContext());
assertNotNull(s.client.getSessionContext());
- assertEquals(s.s.c.sslContext.getServerSessionContext(),
+ assertEquals(s.s.c.serverContext.getServerSessionContext(),
s.server.getSessionContext());
- assertEquals(s.s.c.sslContext.getClientSessionContext(),
+ assertEquals(s.s.c.clientContext.getClientSessionContext(),
s.client.getSessionContext());
assertNotSame(s.server.getSessionContext(),
s.client.getSessionContext());
diff --git a/luni/src/test/java/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/javax/net/ssl/SSLSocketTest.java
index ca318f3..225358d 100644
--- a/luni/src/test/java/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/javax/net/ssl/SSLSocketTest.java
@@ -37,10 +37,14 @@ public class SSLSocketTest extends TestCase {
public void test_SSLSocket_getSupportedCipherSuites_connect() throws Exception {
// note the rare usage of DSA keys here in addition to RSA
- TestKeyStore testKeyStore = TestKeyStore.create(new String[] { "RSA", "DSA" } );
- TestSSLContext c = TestSSLContext.create(testKeyStore.keyStore,
- testKeyStore.keyStorePassword);
- String[] cipherSuites = c.sslContext.getSocketFactory().getSupportedCipherSuites();
+ TestKeyStore testKeyStore = TestKeyStore.create(new String[] { "RSA", "DSA" },
+ null,
+ "rsa-dsa",
+ TestKeyStore.localhost(),
+ true,
+ null);
+ TestSSLContext c = TestSSLContext.create(testKeyStore, testKeyStore);
+ String[] cipherSuites = c.clientContext.getSocketFactory().getSupportedCipherSuites();
for (String cipherSuite : cipherSuites) {
/*
* Kerberos cipher suites require external setup. See "Kerberos Requirements" in
@@ -138,7 +142,8 @@ public class SSLSocketTest extends TestCase {
public void test_SSLSocket_startHandshake() throws Exception {
final TestSSLContext c = TestSSLContext.create();
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {
@@ -152,9 +157,12 @@ public class SSLSocketTest extends TestCase {
}
Certificate[] localCertificates = server.getSession().getLocalCertificates();
assertNotNull(localCertificates);
- assertEquals(1, localCertificates.length);
+ TestKeyStore.assertChainLength(localCertificates);
assertNotNull(localCertificates[0]);
- TestSSLContext.assertCertificateInKeyStore(localCertificates[0], c.keyStore);
+ TestSSLContext.assertServerCertificateChain(c.serverTrustManager,
+ localCertificates);
+ TestSSLContext.assertCertificateInKeyStore(localCertificates[0],
+ c.serverKeyStore);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
@@ -168,15 +176,18 @@ public class SSLSocketTest extends TestCase {
assertNull(client.getSession().getLocalCertificates());
Certificate[] peerCertificates = client.getSession().getPeerCertificates();
assertNotNull(peerCertificates);
- assertEquals(1, peerCertificates.length);
+ TestKeyStore.assertChainLength(peerCertificates);
assertNotNull(peerCertificates[0]);
- TestSSLContext.assertCertificateInKeyStore(peerCertificates[0], c.keyStore);
+ TestSSLContext.assertServerCertificateChain(c.clientTrustManager,
+ peerCertificates);
+ TestSSLContext.assertCertificateInKeyStore(peerCertificates[0], c.serverKeyStore);
thread.join();
}
public void test_SSLSocket_startHandshake_noKeyStore() throws Exception {
- TestSSLContext c = TestSSLContext.create(null, null);
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ TestSSLContext c = TestSSLContext.create(null, null, null, null);
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
try {
SSLSocket server = (SSLSocket) c.serverSocket.accept();
fail();
@@ -185,12 +196,12 @@ public class SSLSocketTest extends TestCase {
}
public void test_SSLSocket_startHandshake_noClientCertificate() throws Exception {
- TestSSLContext serverContext = TestSSLContext.create();
- TestSSLContext clientContext = TestSSLContext.createClient(serverContext);
+ TestSSLContext c = TestSSLContext.create();
+ SSLContext serverContext = c.serverContext;
+ SSLContext clientContext = c.clientContext;
SSLSocket client = (SSLSocket)
- clientContext.sslContext.getSocketFactory().createSocket(serverContext.host,
- serverContext.port);
- final SSLSocket server = (SSLSocket) serverContext.serverSocket.accept();
+ clientContext.getSocketFactory().createSocket(c.host, c.port);
+ final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {
try {
@@ -209,8 +220,8 @@ public class SSLSocketTest extends TestCase {
public void test_SSLSocket_HandshakeCompletedListener() throws Exception {
final TestSSLContext c = TestSSLContext.create();
- final SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host,
- c.port);
+ final SSLSocket client = (SSLSocket)
+ c.clientContext.getSocketFactory().createSocket(c.host, c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {
@@ -253,7 +264,7 @@ public class SSLSocketTest extends TestCase {
byte[] id = session.getId();
assertNotNull(id);
assertEquals(32, id.length);
- assertNotNull(c.sslContext.getClientSessionContext().getSession(id));
+ assertNotNull(c.clientContext.getClientSessionContext().getSession(id));
assertNotNull(cipherSuite);
assertTrue(Arrays.asList(
@@ -264,18 +275,21 @@ public class SSLSocketTest extends TestCase {
assertNull(localCertificates);
assertNotNull(peerCertificates);
- assertEquals(1, peerCertificates.length);
+ TestKeyStore.assertChainLength(peerCertificates);
assertNotNull(peerCertificates[0]);
- TestSSLContext.assertCertificateInKeyStore(peerCertificates[0], c.keyStore);
+ TestSSLContext.assertServerCertificateChain(c.clientTrustManager,
+ peerCertificates);
+ TestSSLContext.assertCertificateInKeyStore(peerCertificates[0],
+ c.serverKeyStore);
assertNotNull(peerCertificateChain);
- assertEquals(1, peerCertificateChain.length);
+ TestKeyStore.assertChainLength(peerCertificateChain);
assertNotNull(peerCertificateChain[0]);
TestSSLContext.assertCertificateInKeyStore(
- peerCertificateChain[0].getSubjectDN(), c.keyStore);
+ peerCertificateChain[0].getSubjectDN(), c.serverKeyStore);
assertNotNull(peerPrincipal);
- TestSSLContext.assertCertificateInKeyStore(peerPrincipal, c.keyStore);
+ TestSSLContext.assertCertificateInKeyStore(peerPrincipal, c.serverKeyStore);
assertNull(localPrincipal);
@@ -297,7 +311,7 @@ public class SSLSocketTest extends TestCase {
client.startHandshake();
thread.join();
if (!TestSSLContext.sslServerSocketSupportsSessionTickets()) {
- assertNotNull(c.sslContext.getServerSessionContext().getSession(
+ assertNotNull(c.serverContext.getServerSessionContext().getSession(
client.getSession().getId()));
}
synchronized (handshakeCompletedListenerCalled) {
@@ -309,8 +323,8 @@ public class SSLSocketTest extends TestCase {
public void test_SSLSocket_HandshakeCompletedListener_RuntimeException() throws Exception {
final TestSSLContext c = TestSSLContext.create();
- final SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host,
- c.port);
+ final SSLSocket client = (SSLSocket)
+ c.clientContext.getSocketFactory().createSocket(c.host, c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {
@@ -335,7 +349,8 @@ public class SSLSocketTest extends TestCase {
public void test_SSLSocket_getUseClientMode() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
SSLSocket server = (SSLSocket) c.serverSocket.accept();
assertTrue(client.getUseClientMode());
assertFalse(server.getUseClientMode());
@@ -365,7 +380,8 @@ public class SSLSocketTest extends TestCase {
final boolean serverClientMode)
throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
final SSLProtocolException[] sslProtocolException = new SSLProtocolException[1];
@@ -405,8 +421,10 @@ public class SSLSocketTest extends TestCase {
}
public void test_SSLSocket_clientAuth() throws Exception {
- TestSSLContext c = TestSSLContext.create();
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ TestSSLContext c = TestSSLContext.create(TestKeyStore.getClientCertificate(),
+ TestKeyStore.getServer());
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {
@@ -441,13 +459,16 @@ public class SSLSocketTest extends TestCase {
thread.start();
client.startHandshake();
assertNotNull(client.getSession().getLocalCertificates());
- assertEquals(1, client.getSession().getLocalCertificates().length);
+ TestKeyStore.assertChainLength(client.getSession().getLocalCertificates());
+ TestSSLContext.assertClientCertificateChain(c.clientTrustManager,
+ client.getSession().getLocalCertificates());
thread.join();
}
public void test_SSLSocket_getEnableSessionCreation() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
SSLSocket server = (SSLSocket) c.serverSocket.accept();
assertTrue(client.getEnableSessionCreation());
assertTrue(server.getEnableSessionCreation());
@@ -455,7 +476,8 @@ public class SSLSocketTest extends TestCase {
public void test_SSLSocket_setEnableSessionCreation_server() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {
@@ -484,7 +506,8 @@ public class SSLSocketTest extends TestCase {
public void test_SSLSocket_setEnableSessionCreation_client() throws Exception {
TestSSLContext c = TestSSLContext.create();
- SSLSocket client = (SSLSocket) c.sslContext.getSocketFactory().createSocket(c.host, c.port);
+ SSLSocket client = (SSLSocket) c.clientContext.getSocketFactory().createSocket(c.host,
+ c.port);
final SSLSocket server = (SSLSocket) c.serverSocket.accept();
Thread thread = new Thread(new Runnable () {
public void run() {
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() {