diff options
Diffstat (limited to 'luni')
12 files changed, 457 insertions, 465 deletions
diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java index 5c73558..0309838 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/AbstractSessionContext.java @@ -24,6 +24,8 @@ import java.io.IOException; import java.util.Arrays; import java.util.Enumeration; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; import java.util.NoSuchElementException; import java.util.logging.Level; import javax.net.ssl.SSLSession; @@ -45,6 +47,15 @@ abstract class AbstractSessionContext implements SSLSessionContext { /** Identifies OpenSSL sessions. */ static final int OPEN_SSL = 1; + private final Map<ByteArray, SSLSession> sessions + = new LinkedHashMap<ByteArray, SSLSession>() { + @Override + protected boolean removeEldestEntry( + Map.Entry<ByteArray, SSLSession> eldest) { + return maximumSize > 0 && size() > maximumSize; + } + }; + /** * Constructs a new session context. * @@ -57,9 +68,15 @@ abstract class AbstractSessionContext implements SSLSessionContext { } /** - * Returns the collection of sessions ordered by least-recently-used first. + * Returns the collection of sessions ordered from oldest to newest */ - abstract Iterator<SSLSession> sessionIterator(); + private Iterator<SSLSession> sessionIterator() { + synchronized (sessions) { + SSLSession[] array = sessions.values().toArray( + new SSLSession[sessions.size()]); + return Arrays.asList(array).iterator(); + } + } public final Enumeration getIds() { final Iterator<SSLSession> i = sessionIterator(); @@ -101,7 +118,47 @@ abstract class AbstractSessionContext implements SSLSessionContext { /** * Makes sure cache size is < maximumSize. */ - abstract void trimToSize(); + protected void trimToSize() { + synchronized (sessions) { + int size = sessions.size(); + if (size > maximumSize) { + int removals = size - maximumSize; + Iterator<SSLSession> i = sessions.values().iterator(); + do { + SSLSession session = i.next(); + i.remove(); + sessionRemoved(session); + } while (--removals > 0); + } + } + } + + public void setSessionTimeout(int seconds) + throws IllegalArgumentException { + if (seconds < 0) { + throw new IllegalArgumentException("seconds < 0"); + } + timeout = seconds; + + synchronized (sessions) { + Iterator<SSLSession> i = sessions.values().iterator(); + while (i.hasNext()) { + SSLSession session = i.next(); + // SSLSession's know their context and consult the + // timeout as part of their validity condition. + if (!session.isValid()) { + i.remove(); + sessionRemoved(session); + } + } + } + } + + /** + * Called when a session is removed. Used by ClientSessionContext + * to update its host-and-port based cache. + */ + abstract protected void sessionRemoved(SSLSession session); public final void setSessionCacheSize(int size) throws IllegalArgumentException { @@ -201,10 +258,31 @@ abstract class AbstractSessionContext implements SSLSessionContext { } } - /** - * Puts an SSLSession in the AbstractSessionContext cache - */ - abstract void putSession(SSLSession session); + public SSLSession getSession(byte[] sessionId) { + if (sessionId == null) { + throw new NullPointerException("sessionId == null"); + } + ByteArray key = new ByteArray(sessionId); + SSLSession session; + synchronized (sessions) { + session = sessions.get(key); + } + if (session != null && session.isValid()) { + return session; + } + return null; + } + + void putSession(SSLSession session) { + byte[] id = session.getId(); + if (id.length == 0) { + return; + } + ByteArray key = new ByteArray(id); + synchronized (sessions) { + sessions.put(key, session); + } + } static void log(Throwable t) { java.util.logging.Logger.global.log(Level.WARNING, diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java index dac22f0..0b297a3 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ClientSessionContext.java @@ -16,42 +16,22 @@ package org.apache.harmony.xnet.provider.jsse; -import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.Map; import javax.net.ssl.SSLSession; /** * Caches client sessions. Indexes by host and port. Users are typically - * looking to reuse any session for a given host and port. Users of the - * standard API are forced to iterate over the sessions semi-linearly as - * opposed to in constant time. + * looking to reuse any session for a given host and port. */ public class ClientSessionContext extends AbstractSessionContext { - /** Sessions indexed by host and port in access order. */ - final Map<HostAndPort, SSLSession> sessions - = new LinkedHashMap<HostAndPort, SSLSession>() { - @Override - protected boolean removeEldestEntry( - Map.Entry<HostAndPort, SSLSession> eldest) { - // Called while lock is held on sessions. - boolean remove = maximumSize > 0 && size() > maximumSize; - if (remove) { - // don't just update sessions, but also sessionsById - removeById(eldest.getValue()); - } - return remove; - } - }; - /** - * Sessions indexed by ID. Initialized on demand. Protected from concurrent - * access by holding a lock on sessions. + * Sessions indexed by host and port. Protect from concurrent + * access by holding a lock on sessionsByHostAndPort. */ - Map<ByteArray, SSLSession> sessionsById; + final Map<HostAndPort, SSLSession> sessionsByHostAndPort + = new HashMap<HostAndPort, SSLSession>(); private SSLClientSessionCache persistentCache; @@ -63,106 +43,10 @@ public class ClientSessionContext extends AbstractSessionContext { this.persistentCache = persistentCache; } - public final void setSessionTimeout(int seconds) - throws IllegalArgumentException { - if (seconds < 0) { - throw new IllegalArgumentException("seconds < 0"); - } - timeout = seconds; - - synchronized (sessions) { - Iterator<SSLSession> i = sessions.values().iterator(); - while (i.hasNext()) { - SSLSession session = i.next(); - // SSLSession's know their context and consult the - // timeout as part of their validity condition. - if (!session.isValid()) { - i.remove(); - // don't just update sessions, but also sessionsById - removeById(session); - } - } - } - } - - Iterator<SSLSession> sessionIterator() { - synchronized (sessions) { - SSLSession[] array = sessions.values().toArray( - new SSLSession[sessions.size()]); - return Arrays.asList(array).iterator(); - } - } - - void trimToSize() { - synchronized (sessions) { - int size = sessions.size(); - if (size > maximumSize) { - int removals = size - maximumSize; - Iterator<SSLSession> i = sessions.values().iterator(); - do { - removeById(i.next()); - i.remove(); - } while (--removals > 0); - } - } - } - - void removeById(SSLSession session) { - if (sessionsById != null) { - sessionsById.remove(new ByteArray(session.getId())); - } - } - - /** - * {@inheritDoc} - * - * @see #getSession(String, int) for an implementation-specific but more - * efficient approach - */ - public SSLSession getSession(byte[] sessionId) { - if (sessionId == null) { - throw new NullPointerException("sessionId == null"); - } - /* - * This method is typically used in conjunction with getIds() to - * iterate over the sessions linearly, so it doesn't make sense for - * it to impact access order. - * - * It also doesn't load sessions from the persistent cache as doing - * so would likely force every session to load. - */ - - ByteArray id = new ByteArray(sessionId); - SSLSession session; - synchronized (sessions) { - indexById(); - session = sessionsById.get(id); - } - if (session != null && session.isValid()) { - return session; - } - return null; - } - - /** - * Ensures that the ID-based index is initialized. - */ - private void indexById() { - if (sessionsById == null) { - sessionsById = new HashMap<ByteArray, SSLSession>(); - for (SSLSession session : sessions.values()) { - sessionsById.put(new ByteArray(session.getId()), session); - } - } - } - - /** - * Adds the given session to the ID-based index if the index has already - * been initialized. - */ - private void indexById(byte[] id, SSLSession session) { - if (sessionsById != null) { - sessionsById.put(new ByteArray(id), session); + protected void sessionRemoved(SSLSession session) { + HostAndPort hostAndPortKey = new HostAndPort(session); + synchronized (sessionsByHostAndPort) { + sessionsByHostAndPort.remove(hostAndPortKey); } } @@ -175,8 +59,9 @@ public class ClientSessionContext extends AbstractSessionContext { */ public SSLSession getSession(String host, int port) { SSLSession session; - synchronized (sessions) { - session = sessions.get(new HostAndPort(host, port)); + HostAndPort hostAndPortKey = new HostAndPort(host, port); + synchronized (sessionsByHostAndPort) { + session = sessionsByHostAndPort.get(hostAndPortKey); } if (session != null && session.isValid()) { return session; @@ -188,9 +73,9 @@ public class ClientSessionContext extends AbstractSessionContext { if (data != null) { session = toSession(data, host, port); if (session != null && session.isValid()) { - synchronized (sessions) { - sessions.put(new HostAndPort(host, port), session); - indexById(session.getId(), session); + super.putSession(session); + synchronized (sessionsByHostAndPort) { + sessionsByHostAndPort.put(hostAndPortKey, session); } return session; } @@ -202,15 +87,11 @@ public class ClientSessionContext extends AbstractSessionContext { @Override void putSession(SSLSession session) { - byte[] id = session.getId(); - if (id.length == 0) { - return; - } - HostAndPort key = new HostAndPort(session.getPeerHost(), - session.getPeerPort()); - synchronized (sessions) { - sessions.put(key, session); - indexById(id, session); + super.putSession(session); + + HostAndPort hostAndPortKey = new HostAndPort(session); + synchronized (sessionsByHostAndPort) { + sessionsByHostAndPort.put(hostAndPortKey, session); } // TODO: This in a background thread. @@ -226,6 +107,10 @@ public class ClientSessionContext extends AbstractSessionContext { final String host; final int port; + HostAndPort(SSLSession session) { + this(session.getPeerHost(), session.getPeerPort()); + } + HostAndPort(String host, int port) { this.host = host; this.port = port; 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 6e38cf6..02b015b 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 @@ -25,6 +25,10 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import org.bouncycastle.openssl.PEMWriter; /** @@ -104,6 +108,106 @@ public class NativeCrypto { private static final String SUPPORTED_PROTOCOL_SSLV3 = "SSLv3"; private static final String SUPPORTED_PROTOCOL_TLSV1 = "TLSv1"; + public static final Map<String, String> OPENSSL_TO_STANDARD = new HashMap<String, String>(); + public static final Map<String, String> STANDARD_TO_OPENSSL = new LinkedHashMap<String, String>(); + + private static void add(String standard, String openssl) { + OPENSSL_TO_STANDARD.put(openssl, standard); + STANDARD_TO_OPENSSL.put(standard, openssl); + } + + static { + // Note these are added in priority order + add("SSL_RSA_WITH_RC4_128_MD5", "RC4-MD5"); + add("SSL_RSA_WITH_RC4_128_SHA", "RC4-SHA"); + add("TLS_RSA_WITH_AES_128_CBC_SHA", "AES128-SHA"); + add("TLS_RSA_WITH_AES_256_CBC_SHA", "AES256-SHA"); + add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", "ECDH-ECDSA-RC4-SHA"); + add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "ECDH-ECDSA-AES128-SHA"); + add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "ECDH-ECDSA-AES256-SHA"); + add("TLS_ECDH_RSA_WITH_RC4_128_SHA", "ECDH-RSA-RC4-SHA"); + add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "ECDH-RSA-AES128-SHA"); + add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "ECDH-RSA-AES256-SHA"); + add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", "ECDHE-ECDSA-RC4-SHA"); + add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "ECDHE-ECDSA-AES128-SHA"); + add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "ECDHE-ECDSA-AES256-SHA"); + add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", "ECDHE-RSA-RC4-SHA"); + add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "ECDHE-RSA-AES128-SHA"); + add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "ECDHE-RSA-AES256-SHA"); + add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "DHE-RSA-AES128-SHA"); + add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "DHE-RSA-AES256-SHA"); + add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "DHE-DSS-AES128-SHA"); + add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "DHE-DSS-AES256-SHA"); + add("SSL_RSA_WITH_3DES_EDE_CBC_SHA", "DES-CBC3-SHA"); + add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDH-ECDSA-DES-CBC3-SHA"); + add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "ECDH-RSA-DES-CBC3-SHA"); + add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-ECDSA-DES-CBC3-SHA"); + add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "ECDHE-RSA-DES-CBC3-SHA"); + add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", "EDH-RSA-DES-CBC3-SHA"); + add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "EDH-DSS-DES-CBC3-SHA"); + add("SSL_RSA_WITH_DES_CBC_SHA", "DES-CBC-SHA"); + add("SSL_DHE_RSA_WITH_DES_CBC_SHA", "EDH-RSA-DES-CBC-SHA"); + add("SSL_DHE_DSS_WITH_DES_CBC_SHA", "EDH-DSS-DES-CBC-SHA"); + add("SSL_RSA_EXPORT_WITH_RC4_40_MD5", "EXP-RC4-MD5"); + add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", "EXP-DES-CBC-SHA"); + add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", "EXP-EDH-RSA-DES-CBC-SHA"); + add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", "EXP-EDH-DSS-DES-CBC-SHA"); + add("SSL_RSA_WITH_NULL_MD5", "NULL-MD5"); + add("SSL_RSA_WITH_NULL_SHA", "NULL-SHA"); + add("TLS_ECDH_ECDSA_WITH_NULL_SHA", "ECDH-ECDSA-NULL-SHA"); + add("TLS_ECDH_RSA_WITH_NULL_SHA", "ECDH-RSA-NULL-SHA"); + add("TLS_ECDHE_ECDSA_WITH_NULL_SHA", "ECDHE-ECDSA-NULL-SHA"); + add("TLS_ECDHE_RSA_WITH_NULL_SHA", "ECDHE-RSA-NULL-SHA"); + add("SSL_DH_anon_WITH_RC4_128_MD5", "ADH-RC4-MD5"); + add("TLS_DH_anon_WITH_AES_128_CBC_SHA", "ADH-AES128-SHA"); + add("TLS_DH_anon_WITH_AES_256_CBC_SHA", "ADH-AES256-SHA"); + add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", "ADH-DES-CBC3-SHA"); + add("SSL_DH_anon_WITH_DES_CBC_SHA", "ADH-DES-CBC-SHA"); + add("TLS_ECDH_anon_WITH_RC4_128_SHA", "AECDH-RC4-SHA"); + add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", "AECDH-AES128-SHA"); + add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", "AECDH-AES256-SHA"); + add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", "AECDH-DES-CBC3-SHA"); + add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", "EXP-ADH-RC4-MD5"); + add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", "EXP-ADH-DES-CBC-SHA"); + add("TLS_ECDH_anon_WITH_NULL_SHA", "AECDH-NULL-SHA"); + + // No Kerberos in Android + //add("TLS_KRB5_WITH_RC4_128_SHA", "KRB5-RC4-SHA"); + //add("TLS_KRB5_WITH_RC4_128_MD5", "KRB5-RC4-MD5"); + //add("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", "KRB5-DES-CBC3-SHA"); + //add("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", "KRB5-DES-CBC3-MD5"); + //add("TLS_KRB5_WITH_DES_CBC_SHA", "KRB5-DES-CBC-SHA"); + //add("TLS_KRB5_WITH_DES_CBC_MD5", "KRB5-DES-CBC-MD5"); + //add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", "EXP-KRB5-RC4-SHA"); + //add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", "EXP-KRB5-RC4-MD5"); + //add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", "EXP-KRB5-DES-CBC-SHA"); + //add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", "EXP-KRB5-DES-CBC-MD5"); + + // not implemented by either RI or OpenSSL + //add("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", null); + //add("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", null); + + // EXPORT1024 suites were never standardized but were widely implemented. + // OpenSSL 0.9.8c and later have disabled TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES + //add("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA", "EXP1024-DES-CBC-SHA"); + //add("SSL_RSA_EXPORT1024_WITH_RC4_56_SHA", "EXP1024-RC4-SHA"); + + // No RC2 + //add("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-RC2-CBC-MD5"); + //add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", "EXP-KRB5-RC2-CBC-SHA"); + //add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", "EXP-KRB5-RC2-CBC-MD5"); + + // PSK is Private Shared Key - didn't exist in Froyo's openssl - no JSSE equivalent + //add(null, "PSK-3DES-EDE-CBC-SHA"); + //add(null, "PSK-AES128-CBC-SHA"); + //add(null, "PSK-AES256-CBC-SHA"); + //add(null, "PSK-RC4-SHA"); + + } + + private static final String[] SUPPORTED_CIPHER_SUITES + = STANDARD_TO_OPENSSL.keySet().toArray(new String[0]); + // SSL mode public static long SSL_MODE_HANDSHAKE_CUTTHROUGH = 0x00000040L; @@ -113,18 +217,28 @@ public class NativeCrypto { public static native int SSL_CTX_new(); - public static native String[] SSL_CTX_get_ciphers(int ssl_ctx); - public static String[] getDefaultCipherSuites() { - int ssl_ctx = SSL_CTX_new(); - String[] supportedCiphers = SSL_CTX_get_ciphers(ssl_ctx); - SSL_CTX_free(ssl_ctx); - return supportedCiphers; + return new String[] { + "SSL_RSA_WITH_RC4_128_MD5", + "SSL_RSA_WITH_RC4_128_SHA", + "TLS_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", + "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "SSL_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_RSA_WITH_DES_CBC_SHA", + "SSL_DHE_DSS_WITH_DES_CBC_SHA", + "SSL_RSA_EXPORT_WITH_RC4_40_MD5", + "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", + "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA" + }; } public static String[] getSupportedCipherSuites() { - // TODO really return full cipher list - return getDefaultCipherSuites(); + return SUPPORTED_CIPHER_SUITES.clone(); } public static native void SSL_CTX_free(int ssl_ctx); @@ -236,7 +350,7 @@ public class NativeCrypto { optionsToSet &= ~SSL_OP_NO_TLSv1; optionsToClear |= SSL_OP_NO_TLSv1; } else { - throw new IllegalArgumentException("Protocol " + protocol + + throw new IllegalArgumentException("protocol " + protocol + " is not supported"); } } @@ -256,29 +370,25 @@ public class NativeCrypto { } if ((!protocol.equals(SUPPORTED_PROTOCOL_SSLV3)) && (!protocol.equals(SUPPORTED_PROTOCOL_TLSV1))) { - throw new IllegalArgumentException("Protocol " + protocol + + throw new IllegalArgumentException("protocol " + protocol + " is not supported"); } } return protocols; } - public static native String[] SSL_get_ciphers(int ssl); - - public static native void SSL_set_cipher_list(int ssl, String ciphers); + public static native void SSL_set_cipher_lists(int ssl, String[] ciphers); public static void setEnabledCipherSuites(int ssl, String[] cipherSuites) { checkEnabledCipherSuites(cipherSuites); - String controlString = ""; + List<String> opensslSuites = new ArrayList<String>(); for (int i = 0; i < cipherSuites.length; i++) { String cipherSuite = cipherSuites[i]; - if (i == 0) { - controlString = cipherSuite; - } else { - controlString += ":" + cipherSuite; - } + String openssl = STANDARD_TO_OPENSSL.get(cipherSuite); + String cs = (openssl == null) ? cipherSuite : openssl; + opensslSuites.add(cs); } - SSL_set_cipher_list(ssl, controlString); + SSL_set_cipher_lists(ssl, opensslSuites.toArray(new String[opensslSuites.size()])); } public static String[] checkEnabledCipherSuites(String[] cipherSuites) { @@ -286,24 +396,21 @@ public class NativeCrypto { throw new IllegalArgumentException("cipherSuites == null"); } // makes sure all suites are valid, throwing on error - String[] supportedCipherSuites = getSupportedCipherSuites(); for (int i = 0; i < cipherSuites.length; i++) { String cipherSuite = cipherSuites[i]; if (cipherSuite == null) { throw new IllegalArgumentException("cipherSuites[" + i + "] == null"); } - findSuite(supportedCipherSuites, cipherSuite); - } - return cipherSuites; - } - - private static void findSuite(String[] supportedCipherSuites, String suite) { - for (String supportedCipherSuite : supportedCipherSuites) { - if (supportedCipherSuite.equals(suite)) { - return; + if (STANDARD_TO_OPENSSL.containsKey(cipherSuite)) { + continue; } + if (OPENSSL_TO_STANDARD.containsKey(cipherSuite)) { + // TODO log warning about using backward compatability + continue; + } + throw new IllegalArgumentException("cipherSuite " + cipherSuite + " is not supported."); } - throw new IllegalArgumentException("Protocol " + suite + " is not supported."); + return cipherSuites; } /* diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java index b722a97..b889e7d 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl.java @@ -23,9 +23,8 @@ import java.security.Principal; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.Iterator; -import java.util.UnknownFormatConversionException; +import java.util.Map; import java.util.Vector; - import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLPermission; import javax.net.ssl.SSLSession; @@ -33,7 +32,6 @@ import javax.net.ssl.SSLSessionBindingEvent; import javax.net.ssl.SSLSessionBindingListener; import javax.net.ssl.SSLSessionContext; import javax.security.cert.CertificateEncodingException; - import org.apache.harmony.luni.util.TwoKeyHashMap; import org.apache.harmony.security.provider.cert.X509CertImpl; @@ -54,6 +52,8 @@ public class OpenSSLSessionImpl implements SSLSession { protected int sslSessionNativePointer; private String peerHost; private int peerPort; + private String cipherSuite; + private String protocol; private AbstractSessionContext sessionContext; private byte[] id; @@ -310,7 +310,14 @@ public class OpenSSLSessionImpl implements SSLSession { * actual SSL session. */ public String getCipherSuite() { - return NativeCrypto.SSL_SESSION_cipher(sslSessionNativePointer); + if (cipherSuite == null) { + String name = NativeCrypto.SSL_SESSION_cipher(sslSessionNativePointer); + cipherSuite = NativeCrypto.OPENSSL_TO_STANDARD.get(name); + if (cipherSuite == null) { + cipherSuite = name; + } + } + return cipherSuite; } /** @@ -322,7 +329,10 @@ public class OpenSSLSessionImpl implements SSLSession { * */ public String getProtocol() { - return NativeCrypto.SSL_SESSION_get_version(sslSessionNativePointer); + if (protocol == null) { + protocol = NativeCrypto.SSL_SESSION_get_version(sslSessionNativePointer); + } + return protocol; } /** 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 f643249..acb6098 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 @@ -213,9 +213,38 @@ public class OpenSSLSocketImpl super.getInetAddress().getHostName() == null) { return null; } - return (OpenSSLSessionImpl) sessionContext.getSession( + OpenSSLSessionImpl session = (OpenSSLSessionImpl) sessionContext.getSession( super.getInetAddress().getHostName(), super.getPort()); + if (session == null) { + return null; + } + + String protocol = session.getProtocol(); + boolean protocolFound = false; + for (String enabledProtocol : enabledProtocols) { + if (protocol.equals(enabledProtocol)) { + protocolFound = true; + break; + } + } + if (!protocolFound) { + return null; + } + + String cipherSuite = session.getCipherSuite(); + boolean cipherSuiteFound = false; + for (String enabledCipherSuite : enabledCipherSuites) { + if (cipherSuite.equals(enabledCipherSuite)) { + cipherSuiteFound = true; + break; + } + } + if (!cipherSuiteFound) { + return null; + } + + return session; } /** @@ -323,7 +352,7 @@ public class OpenSSLSocketImpl byte[] sessionId = NativeCrypto.SSL_SESSION_session_id(sslSessionNativePointer); sslSession = (OpenSSLSessionImpl) sessionContext.getSession(sessionId); if (sslSession != null) { - session.lastAccessedTime = System.currentTimeMillis(); + sslSession.lastAccessedTime = System.currentTimeMillis(); LoggerHolder.logger.fine("Reused cached session for " + getInetAddress() + "."); NativeCrypto.SSL_SESSION_free(sslSessionNativePointer); diff --git a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java index 6ba82ff..0352ef6 100644 --- a/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java +++ b/luni/src/main/java/org/apache/harmony/xnet/provider/jsse/ServerSessionContext.java @@ -16,10 +16,6 @@ package org.apache.harmony.xnet.provider.jsse; -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; import javax.net.ssl.SSLSession; /** @@ -28,15 +24,6 @@ import javax.net.ssl.SSLSession; */ public class ServerSessionContext extends AbstractSessionContext { - private final Map<ByteArray, SSLSession> sessions - = new LinkedHashMap<ByteArray, SSLSession>() { - @Override - protected boolean removeEldestEntry( - Map.Entry<ByteArray, SSLSession> eldest) { - return maximumSize > 0 && size() > maximumSize; - } - }; - private SSLServerSessionCache persistentCache; public ServerSessionContext() { @@ -56,58 +43,13 @@ public class ServerSessionContext extends AbstractSessionContext { this.persistentCache = persistentCache; } - Iterator<SSLSession> sessionIterator() { - synchronized (sessions) { - SSLSession[] array = sessions.values().toArray( - new SSLSession[sessions.size()]); - return Arrays.asList(array).iterator(); - } - } - - void trimToSize() { - synchronized (sessions) { - int size = sessions.size(); - if (size > maximumSize) { - int removals = size - maximumSize; - Iterator<SSLSession> i = sessions.values().iterator(); - do { - i.next(); - i.remove(); - } while (--removals > 0); - } - } - } - - public void setSessionTimeout(int seconds) - throws IllegalArgumentException { - if (seconds < 0) { - throw new IllegalArgumentException("seconds < 0"); - } - timeout = seconds; - - synchronized (sessions) { - Iterator<SSLSession> i = sessions.values().iterator(); - while (i.hasNext()) { - SSLSession session = i.next(); - // SSLSession's know their context and consult the - // timeout as part of their validity condition. - if (!session.isValid()) { - i.remove(); - } - } - } - } + protected void sessionRemoved(SSLSession session) {} - public SSLSession getSession(byte[] sessionId) { - if (sessionId == null) { - throw new NullPointerException("sessionId == null"); - } - ByteArray key = new ByteArray(sessionId); - SSLSession session; - synchronized (sessions) { - session = sessions.get(key); - } - if (session != null && session.isValid()) { + @Override + public SSLSession getSession(byte[] sessionId) + { + SSLSession session = super.getSession(sessionId); + if (session != null) { return session; } @@ -117,9 +59,7 @@ public class ServerSessionContext extends AbstractSessionContext { if (data != null) { session = toSession(data, null, -1); if (session != null && session.isValid()) { - synchronized (sessions) { - sessions.put(key, session); - } + super.putSession(session); return session; } } @@ -130,14 +70,7 @@ public class ServerSessionContext extends AbstractSessionContext { @Override void putSession(SSLSession session) { - byte[] id = session.getId(); - if (id.length == 0) { - return; - } - ByteArray key = new ByteArray(id); - synchronized (sessions) { - sessions.put(key, session); - } + super.putSession(session); // TODO: In background thread. if (persistentCache != null) { diff --git a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp index 2c8a02a..0e9d641 100644 --- a/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp +++ b/luni/src/main/native/org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp @@ -1340,43 +1340,6 @@ static int NativeCrypto_SSL_CTX_new(JNIEnv* env, jclass) { return (jint) sslCtx; } -static jobjectArray makeCipherList(JNIEnv* env, STACK_OF(SSL_CIPHER)* cipher_list) { - // Create a String[]. - jclass stringClass = env->FindClass("java/lang/String"); - if (stringClass == NULL) { - return NULL; - } - int cipherCount = sk_SSL_CIPHER_num(cipher_list); - jobjectArray array = env->NewObjectArray(cipherCount, stringClass, NULL); - if (array == NULL) { - return NULL; - } - - // Fill in the cipher names. - for (int i = 0; i < cipherCount; ++i) { - const char* c = sk_SSL_CIPHER_value(cipher_list, i)->name; - JNI_TRACE("makeCipherList[i=%d]=%s", i, c); - env->SetObjectArrayElement(array, i, env->NewStringUTF(c)); - } - return array; -} - -/** - * Loads the ciphers suites that are supported by an SSL_CTX - * and returns them in a string array. - */ -static jobjectArray NativeCrypto_SSL_CTX_get_ciphers(JNIEnv* env, - jclass, jint ssl_ctx_address) -{ - SSL_CTX* ssl_ctx = to_SSL_CTX(ssl_ctx_address); - JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_get_ciphers", ssl_ctx); - if (ssl_ctx == NULL) { - jniThrowNullPointerException(env, "SSL_CTX is null"); - return NULL; - } - return makeCipherList(env, ssl_ctx->cipher_list); -} - /** * public static native void SSL_CTX_free(int ssl_ctx) */ @@ -1617,34 +1580,50 @@ static jlong NativeCrypto_SSL_clear_options(JNIEnv* env, jclass, } /** - * Loads the ciphers suites that are enabled in the SSL - * and returns them in a string array. + * Sets the ciphers suites that are enabled in the SSL */ -static jobjectArray NativeCrypto_SSL_get_ciphers(JNIEnv* env, - jclass, jint ssl_address) +static void NativeCrypto_SSL_set_cipher_lists(JNIEnv* env, jclass, + jint ssl_address, jobjectArray cipherSuites) { SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_get_ciphers", ssl); + JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuites=%p", ssl, cipherSuites); if (ssl == NULL) { - return NULL; + return; } - return makeCipherList(env, SSL_get_ciphers(ssl)); -} -/** - * Sets the ciphers suites that are enabled in the SSL - */ -static void NativeCrypto_SSL_set_cipher_list(JNIEnv* env, jclass, - jint ssl_address, jstring controlString) -{ - SSL* ssl = to_SSL(env, ssl_address, true); - JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_list controlString=%p", ssl, controlString); - if (ssl == NULL) { - return; + STACK_OF(SSL_CIPHER)* cipherstack = sk_SSL_CIPHER_new_null(); + if (cipherstack == NULL) { + jniThrowRuntimeException(env, "sk_SSL_CIPHER_new_null failed"); + return; } - ScopedUtfChars str(env, controlString); - JNI_TRACE("ssl=%p NativeCrypto_SSL_controlString str=%s", ssl, str.c_str()); - int rc = SSL_set_cipher_list(ssl, str.c_str()); + + const SSL_METHOD* ssl_method = ssl->method; + int num_ciphers = ssl_method->num_ciphers(); + + int length = env->GetArrayLength(cipherSuites); + JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists length=%d", ssl, length); + for (int i = 0; i < length; i++) { + jstring cipherSuite = (jstring) env->GetObjectArrayElement(cipherSuites, i); + ScopedUtfChars c(env, cipherSuite); + JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuite=%s", ssl, c.c_str()); + bool found = false; + for (int j = 0; j < num_ciphers; j++) { + 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, cipher); + found = true; + } + } + if (!found) { + sk_SSL_CIPHER_free(cipherstack); + jniThrowException(env, "java/lang/IllegalArgumentException", + "Could not find cipher suite."); + return; + } + } + + int rc = SSL_set_cipher_lists(ssl, cipherstack); if (rc == 0) { freeSslErrorState(); jniThrowException(env, "java/lang/IllegalArgumentException", @@ -2561,53 +2540,51 @@ static jint NativeCrypto_d2i_SSL_SESSION(JNIEnv* env, jclass, jbyteArray bytes, * (3) pointer to C function. */ static JNINativeMethod sNativeCryptoMethods[] = { - { "clinit", "()V", (void*)NativeCrypto_clinit}, - { "EVP_PKEY_new_DSA", "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_DSA }, - { "EVP_PKEY_new_RSA", "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_RSA }, - { "EVP_PKEY_free", "(I)V", (void*)NativeCrypto_EVP_PKEY_free }, - { "EVP_new", "()I", (void*)NativeCrypto_EVP_new }, - { "EVP_free", "(I)V", (void*)NativeCrypto_EVP_free }, - { "EVP_DigestFinal", "(I[BI)I", (void*)NativeCrypto_EVP_DigestFinal }, - { "EVP_DigestInit", "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_DigestInit }, - { "EVP_DigestBlockSize", "(I)I", (void*)NativeCrypto_EVP_DigestBlockSize }, - { "EVP_DigestSize", "(I)I", (void*)NativeCrypto_EVP_DigestSize }, - { "EVP_DigestUpdate", "(I[BII)V", (void*)NativeCrypto_EVP_DigestUpdate }, - { "EVP_VerifyInit", "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_VerifyInit }, - { "EVP_VerifyUpdate", "(I[BII)V", (void*)NativeCrypto_EVP_VerifyUpdate }, - { "EVP_VerifyFinal", "(I[BIII)I", (void*)NativeCrypto_EVP_VerifyFinal }, - { "verifySignature", "([B[BLjava/lang/String;[B[B)I", (void*)NativeCrypto_verifysignature}, - { "SSL_CTX_new", "()I", (void*)NativeCrypto_SSL_CTX_new }, - { "SSL_CTX_get_ciphers", "(I)[Ljava/lang/String;", (void*)NativeCrypto_SSL_CTX_get_ciphers}, - { "SSL_CTX_free", "(I)V", (void*)NativeCrypto_SSL_CTX_free }, - { "SSL_new", "(ILjava/lang/String;Ljava/lang/String;[B)I", (void*)NativeCrypto_SSL_new}, - { "SSL_get_mode", "(I)J", (void*)NativeCrypto_SSL_get_mode }, - { "SSL_set_mode", "(IJ)J", (void*)NativeCrypto_SSL_set_mode }, - { "SSL_clear_mode", "(IJ)J", (void*)NativeCrypto_SSL_clear_mode }, - { "SSL_get_options", "(I)J", (void*)NativeCrypto_SSL_get_options }, - { "SSL_set_options", "(IJ)J", (void*)NativeCrypto_SSL_set_options }, - { "SSL_clear_options", "(IJ)J", (void*)NativeCrypto_SSL_clear_options }, - { "SSL_get_ciphers", "(I)[Ljava/lang/String;", (void*)NativeCrypto_SSL_get_ciphers }, - { "SSL_set_cipher_list", "(ILjava/lang/String;)V", (void*)NativeCrypto_SSL_set_cipher_list }, - { "SSL_set_verify", "(II)V", (void*)NativeCrypto_SSL_set_verify}, - { "SSL_set_session", "(II)V", (void*)NativeCrypto_SSL_set_session }, + { "clinit", "()V", (void*)NativeCrypto_clinit}, + { "EVP_PKEY_new_DSA", "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_DSA }, + { "EVP_PKEY_new_RSA", "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_RSA }, + { "EVP_PKEY_free", "(I)V", (void*)NativeCrypto_EVP_PKEY_free }, + { "EVP_new", "()I", (void*)NativeCrypto_EVP_new }, + { "EVP_free", "(I)V", (void*)NativeCrypto_EVP_free }, + { "EVP_DigestFinal", "(I[BI)I", (void*)NativeCrypto_EVP_DigestFinal }, + { "EVP_DigestInit", "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_DigestInit }, + { "EVP_DigestBlockSize", "(I)I", (void*)NativeCrypto_EVP_DigestBlockSize }, + { "EVP_DigestSize", "(I)I", (void*)NativeCrypto_EVP_DigestSize }, + { "EVP_DigestUpdate", "(I[BII)V", (void*)NativeCrypto_EVP_DigestUpdate }, + { "EVP_VerifyInit", "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_VerifyInit }, + { "EVP_VerifyUpdate", "(I[BII)V", (void*)NativeCrypto_EVP_VerifyUpdate }, + { "EVP_VerifyFinal", "(I[BIII)I", (void*)NativeCrypto_EVP_VerifyFinal }, + { "verifySignature", "([B[BLjava/lang/String;[B[B)I", (void*)NativeCrypto_verifysignature}, + { "SSL_CTX_new", "()I", (void*)NativeCrypto_SSL_CTX_new }, + { "SSL_CTX_free", "(I)V", (void*)NativeCrypto_SSL_CTX_free }, + { "SSL_new", "(ILjava/lang/String;Ljava/lang/String;[B)I", (void*)NativeCrypto_SSL_new}, + { "SSL_get_mode", "(I)J", (void*)NativeCrypto_SSL_get_mode }, + { "SSL_set_mode", "(IJ)J", (void*)NativeCrypto_SSL_set_mode }, + { "SSL_clear_mode", "(IJ)J", (void*)NativeCrypto_SSL_clear_mode }, + { "SSL_get_options", "(I)J", (void*)NativeCrypto_SSL_get_options }, + { "SSL_set_options", "(IJ)J", (void*)NativeCrypto_SSL_set_options }, + { "SSL_clear_options", "(IJ)J", (void*)NativeCrypto_SSL_clear_options }, + { "SSL_set_cipher_lists", "(I[Ljava/lang/String;)V", (void*)NativeCrypto_SSL_set_cipher_lists }, + { "SSL_set_verify", "(II)V", (void*)NativeCrypto_SSL_set_verify}, + { "SSL_set_session", "(II)V", (void*)NativeCrypto_SSL_set_session }, { "SSL_set_session_creation_enabled", "(IZ)V", (void*)NativeCrypto_SSL_set_session_creation_enabled }, - { "SSL_do_handshake", "(ILjava/net/Socket;Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto$CertificateChainVerifier;Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto$HandshakeCompletedCallback;IZ)I",(void*)NativeCrypto_SSL_do_handshake}, - { "SSL_get_certificate", "(I)[[B", (void*)NativeCrypto_SSL_get_certificate}, - { "SSL_read_byte", "(II)I", (void*)NativeCrypto_SSL_read_byte}, - { "SSL_read", "(I[BIII)I", (void*)NativeCrypto_SSL_read}, - { "SSL_write_byte", "(II)V", (void*)NativeCrypto_SSL_write_byte}, - { "SSL_write", "(I[BII)V", (void*)NativeCrypto_SSL_write}, - { "SSL_interrupt", "(I)V", (void*)NativeCrypto_SSL_interrupt}, - { "SSL_shutdown", "(I)V", (void*)NativeCrypto_SSL_shutdown}, - { "SSL_free", "(I)V", (void*)NativeCrypto_SSL_free}, - { "SSL_SESSION_session_id", "(I)[B", (void*)NativeCrypto_SSL_SESSION_session_id }, + { "SSL_do_handshake", "(ILjava/net/Socket;Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto$CertificateChainVerifier;Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto$HandshakeCompletedCallback;IZ)I",(void*)NativeCrypto_SSL_do_handshake}, + { "SSL_get_certificate", "(I)[[B", (void*)NativeCrypto_SSL_get_certificate}, + { "SSL_read_byte", "(II)I", (void*)NativeCrypto_SSL_read_byte}, + { "SSL_read", "(I[BIII)I", (void*)NativeCrypto_SSL_read}, + { "SSL_write_byte", "(II)V", (void*)NativeCrypto_SSL_write_byte}, + { "SSL_write", "(I[BII)V", (void*)NativeCrypto_SSL_write}, + { "SSL_interrupt", "(I)V", (void*)NativeCrypto_SSL_interrupt}, + { "SSL_shutdown", "(I)V", (void*)NativeCrypto_SSL_shutdown}, + { "SSL_free", "(I)V", (void*)NativeCrypto_SSL_free}, + { "SSL_SESSION_session_id", "(I)[B", (void*)NativeCrypto_SSL_SESSION_session_id }, { "SSL_SESSION_get_peer_cert_chain", "(II)[[B", (void*)NativeCrypto_SSL_SESSION_get_peer_cert_chain }, - { "SSL_SESSION_get_time", "(I)J", (void*)NativeCrypto_SSL_SESSION_get_time }, + { "SSL_SESSION_get_time", "(I)J", (void*)NativeCrypto_SSL_SESSION_get_time }, { "SSL_SESSION_get_version", "(I)Ljava/lang/String;", (void*)NativeCrypto_SSL_SESSION_get_version }, - { "SSL_SESSION_cipher", "(I)Ljava/lang/String;", (void*)NativeCrypto_SSL_SESSION_cipher }, - { "SSL_SESSION_free", "(I)V", (void*)NativeCrypto_SSL_SESSION_free }, - { "i2d_SSL_SESSION", "(I)[B", (void*)NativeCrypto_i2d_SSL_SESSION }, - { "d2i_SSL_SESSION", "([BI)I", (void*)NativeCrypto_d2i_SSL_SESSION }, + { "SSL_SESSION_cipher", "(I)Ljava/lang/String;", (void*)NativeCrypto_SSL_SESSION_cipher }, + { "SSL_SESSION_free", "(I)V", (void*)NativeCrypto_SSL_SESSION_free }, + { "i2d_SSL_SESSION", "(I)[B", (void*)NativeCrypto_i2d_SSL_SESSION }, + { "d2i_SSL_SESSION", "([BI)I", (void*)NativeCrypto_d2i_SSL_SESSION }, }; int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env) { diff --git a/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java b/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java index 855949d..f8aed75 100644 --- a/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java +++ b/luni/src/test/java/javax/net/ssl/SSLSessionContextTest.java @@ -16,32 +16,44 @@ package javax.net.ssl; -import dalvik.annotation.KnownFailure; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedList; +import java.util.List; import junit.framework.TestCase; public class SSLSessionContextTest extends TestCase { - public static final void assertSSLSessionContextSize(int expected, SSLSessionContext s) { - assertEquals(expected, Collections.list(s.getIds()).size()); + public static final void assertSSLSessionContextSize(int expected, SSLContext sslContext) { + assertSSLSessionContextSize(expected, + sslContext.getClientSessionContext(), + sslContext.getServerSessionContext()); + } + + public static final void assertSSLSessionContextSize(int expected, + SSLSessionContext client, + SSLSessionContext server) { + assertSSLSessionContextSize(expected, client, false); + assertSSLSessionContextSize(expected, server, true); + } + + public static final void assertSSLSessionContextSize(int expected, SSLSessionContext s, boolean server) { + int size = Collections.list(s.getIds()).size(); + if (server && TestSSLContext.sslServerSocketSupportsSessionTickets()) { + assertEquals(0, size); + } else { + assertEquals(expected, size); + } } public void test_SSLSessionContext_getIds() { TestSSLContext c = TestSSLContext.create(); - assertSSLSessionContextSize(0, c.sslContext.getClientSessionContext()); - assertSSLSessionContextSize(0, c.sslContext.getServerSessionContext()); + assertSSLSessionContextSize(0, c.sslContext); TestSSLSocketPair s = TestSSLSocketPair.create(); - assertSSLSessionContextSize(1, s.c.sslContext.getClientSessionContext()); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, s.c.sslContext.getServerSessionContext()); - } else { - assertSSLSessionContextSize(1, s.c.sslContext.getServerSessionContext()); - } + assertSSLSessionContextSize(1, s.c.sslContext); Enumeration clientIds = s.c.sslContext.getClientSessionContext().getIds(); Enumeration serverIds = s.c.sslContext.getServerSessionContext().getIds(); byte[] clientId = (byte[]) clientIds.nextElement(); @@ -101,15 +113,15 @@ public class SSLSessionContextTest extends TestCase { s.c.sslContext.getServerSessionContext().getSessionCacheSize()); } - public void test_SSLSessionContext_setSessionCacheSize_basic() { + public void test_SSLSessionContext_setSessionCacheSize_noConnect() { TestSSLContext c = TestSSLContext.create(); - assertBasicSetSessionCacheSizeBehavior(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE, - c.sslContext.getClientSessionContext()); - assertBasicSetSessionCacheSizeBehavior(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE, - c.sslContext.getServerSessionContext()); + assertNoConnectSetSessionCacheSizeBehavior(TestSSLContext.EXPECTED_DEFAULT_CLIENT_SSL_SESSION_CACHE_SIZE, + c.sslContext.getClientSessionContext()); + assertNoConnectSetSessionCacheSizeBehavior(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE, + c.sslContext.getServerSessionContext()); } - private static void assertBasicSetSessionCacheSizeBehavior(int expectedDefault, SSLSessionContext s) { + private static void assertNoConnectSetSessionCacheSizeBehavior(int expectedDefault, SSLSessionContext s) { try { s.setSessionCacheSize(-1); fail(); @@ -120,9 +132,7 @@ public class SSLSessionContextTest extends TestCase { assertEquals(1, s.getSessionCacheSize()); } - @KnownFailure("Using OpenSSL cipher suite names") - public void test_SSLSessionContext_setSessionCacheSize_dynamic() { - + public void test_SSLSessionContext_setSessionCacheSize_oneConnect() { TestSSLSocketPair s = TestSSLSocketPair.create(); SSLSessionContext client = s.c.sslContext.getClientSessionContext(); SSLSessionContext server = s.c.sslContext.getServerSessionContext(); @@ -130,21 +140,29 @@ public class SSLSessionContextTest extends TestCase { client.getSessionCacheSize()); assertEquals(TestSSLContext.EXPECTED_DEFAULT_SERVER_SSL_SESSION_CACHE_SIZE, server.getSessionCacheSize()); - assertSSLSessionContextSize(1, client); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, server); - } else { - assertSSLSessionContextSize(1, server); - } + assertSSLSessionContextSize(1, s.c.sslContext); + } - LinkedList<String> uniqueCipherSuites - = new LinkedList(Arrays.asList(s.server.getEnabledCipherSuites())); - uniqueCipherSuites.remove(s.client.getSession().getCipherSuite()); + public void test_SSLSessionContext_setSessionCacheSize_dynamic() { + TestSSLContext c = TestSSLContext.create(); + SSLSessionContext client = c.sslContext.getClientSessionContext(); + SSLSessionContext server = c.sslContext.getServerSessionContext(); + String[] supportedCipherSuites = c.serverSocket.getSupportedCipherSuites(); + c.serverSocket.setEnabledCipherSuites(supportedCipherSuites); + LinkedList<String> uniqueCipherSuites + = new LinkedList(Arrays.asList(supportedCipherSuites)); // only use RSA cipher suites which will work with our TrustProvider Iterator<String> i = uniqueCipherSuites.iterator(); while (i.hasNext()) { String cipherSuite = i.next(); + + // Certificate key length too long for export ciphers + if (cipherSuite.startsWith("SSL_RSA_EXPORT_")) { + i.remove(); + continue; + } + if (cipherSuite.startsWith("SSL_RSA_")) { continue; } @@ -161,7 +179,7 @@ public class SSLSessionContextTest extends TestCase { } /* - * having more than 5 uniqueCipherSuites is a test + * having more than 3 uniqueCipherSuites is a test * requirement, not a requirement of the interface or * implementation. It simply allows us to make sure that we * will not get a cached session ID since we'll have to @@ -170,59 +188,32 @@ public class SSLSessionContextTest extends TestCase { * reused the unique cipher suites every time it resets the * session cache. */ - // TODO Fix Known Failure - // Need to fix CipherSuites methods to use JSSE names - assertTrue(uniqueCipherSuites.size() > 5); - - TestSSLSocketPair.connect(s.c, new String[] { uniqueCipherSuites.remove() }); // 1 - assertSSLSessionContextSize(2, client); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, server); - } else { - assertSSLSessionContextSize(2, server); - } - TestSSLSocketPair.connect(s.c, new String[] { uniqueCipherSuites.remove() }); // 2 - assertSSLSessionContextSize(3, client); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, server); - } else { - assertSSLSessionContextSize(3, server); - } + assertTrue(uniqueCipherSuites.size() >= 3); + String cipherSuite1 = uniqueCipherSuites.get(0); + String cipherSuite2 = uniqueCipherSuites.get(1); + String cipherSuite3 = uniqueCipherSuites.get(2); + + TestSSLSocketPair.connect(c, new String[] { cipherSuite1 }); + assertSSLSessionContextSize(1, c.sslContext); + TestSSLSocketPair.connect(c, new String[] { cipherSuite2 }); + assertSSLSessionContextSize(2, c.sslContext); + TestSSLSocketPair.connect(c, new String[] { cipherSuite3 }); + assertSSLSessionContextSize(3, c.sslContext); client.setSessionCacheSize(1); server.setSessionCacheSize(1); assertEquals(1, client.getSessionCacheSize()); assertEquals(1, server.getSessionCacheSize()); - assertSSLSessionContextSize(1, client); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, server); - } else { - assertSSLSessionContextSize(1, server); - } - TestSSLSocketPair.connect(s.c, new String[] { uniqueCipherSuites.remove() }); // 3 - assertSSLSessionContextSize(1, client); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, server); - } else { - assertSSLSessionContextSize(1, server); - } + assertSSLSessionContextSize(1, c.sslContext); + TestSSLSocketPair.connect(c, new String[] { cipherSuite1 }); + assertSSLSessionContextSize(1, c.sslContext); client.setSessionCacheSize(2); server.setSessionCacheSize(2); - TestSSLSocketPair.connect(s.c, new String[] { uniqueCipherSuites.remove() }); // 4 - assertSSLSessionContextSize(2, client); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, server); - } else { - assertSSLSessionContextSize(2, server); - } - TestSSLSocketPair.connect(s.c, new String[] { uniqueCipherSuites.remove() }); // 5 - assertSSLSessionContextSize(2, client); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, server); - } else { - assertSSLSessionContextSize(2, server); - } + TestSSLSocketPair.connect(c, new String[] { cipherSuite2 }); + assertSSLSessionContextSize(2, c.sslContext); + TestSSLSocketPair.connect(c, new String[] { cipherSuite3 }); + assertSSLSessionContextSize(2, c.sslContext); } public void test_SSLSessionContext_getSessionTimeout() { @@ -262,16 +253,10 @@ public class SSLSessionContextTest extends TestCase { } TestSSLSocketPair s = TestSSLSocketPair.create(); - assertSSLSessionContextSize(1, s.c.sslContext.getClientSessionContext()); - if (TestSSLContext.sslServerSocketSupportsSessionTickets()) { - assertSSLSessionContextSize(0, s.c.sslContext.getServerSessionContext()); - } else { - assertSSLSessionContextSize(1, s.c.sslContext.getServerSessionContext()); - } + assertSSLSessionContextSize(1, s.c.sslContext); Thread.sleep(1 * 1000); s.c.sslContext.getClientSessionContext().setSessionTimeout(1); s.c.sslContext.getServerSessionContext().setSessionTimeout(1); - assertSSLSessionContextSize(0, s.c.sslContext.getClientSessionContext()); - assertSSLSessionContextSize(0, s.c.sslContext.getServerSessionContext()); + assertSSLSessionContextSize(0, s.c.sslContext); } } diff --git a/luni/src/test/java/javax/net/ssl/SSLSessionTest.java b/luni/src/test/java/javax/net/ssl/SSLSessionTest.java index 36b565b..eb15e57 100644 --- a/luni/src/test/java/javax/net/ssl/SSLSessionTest.java +++ b/luni/src/test/java/javax/net/ssl/SSLSessionTest.java @@ -47,6 +47,7 @@ public class SSLSessionTest extends TestCase { assertNotNull(s.client.getCipherSuite()); assertEquals(s.server.getCipherSuite(), s.client.getCipherSuite()); + assertTrue(StandardNames.CIPHER_SUITES.contains(s.server.getCipherSuite())); } public void test_SSLSession_getCreationTime() { @@ -199,6 +200,7 @@ public class SSLSessionTest extends TestCase { assertNotNull(s.client.getProtocol()); assertEquals(s.server.getProtocol(), s.client.getProtocol()); + assertTrue(StandardNames.SSL_SOCKET_PROTOCOLS.contains(s.server.getProtocol())); } public void test_SSLSession_getSessionContext() { diff --git a/luni/src/test/java/javax/net/ssl/SSLSocketFactoryTest.java b/luni/src/test/java/javax/net/ssl/SSLSocketFactoryTest.java index bb76390..15e2e71 100644 --- a/luni/src/test/java/javax/net/ssl/SSLSocketFactoryTest.java +++ b/luni/src/test/java/javax/net/ssl/SSLSocketFactoryTest.java @@ -36,7 +36,6 @@ public class SSLSocketFactoryTest extends TestCase { assertTrue(SSLSocketFactory.class.isAssignableFrom(sf.getClass())); } - @KnownFailure("Using OpenSSL cipher suite names") public void test_SSLSocketFactory_getDefaultCipherSuites() { SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault(); String[] cipherSuites = sf.getDefaultCipherSuites(); @@ -52,13 +51,10 @@ public class SSLSocketFactoryTest extends TestCase { // Make sure all cipherSuites names are expected for (String cipherSuite : cipherSuites) { - // TODO Fix Known Failure - // Need to fix CipherSuites methods to use JSSE names assertTrue(StandardNames.CIPHER_SUITES.contains(cipherSuite)); } } - @KnownFailure("Using OpenSSL cipher suite names") public void test_SSLSocketFactory_getSupportedCipherSuites() { SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault(); String[] cipherSuites = sf.getSupportedCipherSuites(); @@ -75,11 +71,11 @@ public class SSLSocketFactoryTest extends TestCase { // Make sure all cipherSuites names are expected Set remainingCipherSuites = new HashSet<String>(StandardNames.CIPHER_SUITES); for (String cipherSuite : cipherSuites) { - assertNotNull(remainingCipherSuites.remove(cipherSuite)); + assertTrue(remainingCipherSuites.remove(cipherSuite)); } - // TODO Fix Known Failure - // Need to fix CipherSuites methods to use JSSE names assertEquals(Collections.EMPTY_SET, remainingCipherSuites); + + assertEquals(StandardNames.CIPHER_SUITES.size(), cipherSuites.length); } @KnownFailure("Should not parse bogus port number -1 during createSocket") diff --git a/luni/src/test/java/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/javax/net/ssl/SSLSocketTest.java index f9766a1..3a44510 100644 --- a/luni/src/test/java/javax/net/ssl/SSLSocketTest.java +++ b/luni/src/test/java/javax/net/ssl/SSLSocketTest.java @@ -33,7 +33,6 @@ import junit.framework.TestCase; public class SSLSocketTest extends TestCase { - @KnownFailure("Using OpenSSL cipher suite names") public void test_SSLSocket_getSupportedCipherSuites() throws Exception { SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket ssl = (SSLSocket) sf.createSocket(); @@ -42,14 +41,12 @@ public class SSLSocketTest extends TestCase { assertTrue(cipherSuites.length != 0); Set remainingCipherSuites = new HashSet<String>(StandardNames.CIPHER_SUITES); for (String cipherSuite : cipherSuites) { - assertNotNull(remainingCipherSuites.remove(cipherSuite)); + assertTrue(remainingCipherSuites.remove(cipherSuite)); } - // TODO Fix Known Failure - // Need to fix CipherSuites methods to use JSSE names assertEquals(Collections.EMPTY_SET, remainingCipherSuites); + assertEquals(StandardNames.CIPHER_SUITES.size(), cipherSuites.length); } - @KnownFailure("Using OpenSSL cipher suite names") public void test_SSLSocket_getEnabledCipherSuites() throws Exception { SSLSocketFactory sf = (SSLSocketFactory) SSLSocketFactory.getDefault(); SSLSocket ssl = (SSLSocket) sf.createSocket(); @@ -66,8 +63,6 @@ public class SSLSocketTest extends TestCase { // Make sure all cipherSuites names are expected for (String cipherSuite : cipherSuites) { - // TODO Fix Known Failure - // Need to fix CipherSuites methods to use JSSE names assertTrue(StandardNames.CIPHER_SUITES.contains(cipherSuite)); } } diff --git a/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java b/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java index cdad187..bce302a 100644 --- a/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java +++ b/luni/src/test/java/tests/api/javax/net/ssl/SSLSessionTest.java @@ -178,7 +178,7 @@ public class SSLSessionTest extends TestCase { @AndroidOnly("Uses bks key store. Change useBKS to false to run on the RI") public void test_getCipherSuite() { try { - assertEquals(cipherSuite, clientSession.getCipherSuite()); + assertEquals(CIPHER_SUITE, clientSession.getCipherSuite()); } catch (Exception ex) { fail("Unexpected exception " + ex); } @@ -571,9 +571,6 @@ public class SSLSessionTest extends TestCase { public void valueUnbound(SSLSessionBindingEvent event) {} } - - - String cipherSuiteBKS = "AES256-SHA"; /** * Defines the keystore contents for the server, BKS version. Holds just a * single self-generated key. The subject name is "Test Server". @@ -634,7 +631,7 @@ public class SSLSessionTest extends TestCase { "uJk07h3IZnNxE+/IKgeMTP/H4+jmyT4mhsexJ2BFHeiKF1KT/FMcJdSi+ZK5yoNVcYuY8aZbx0Ef" + "lHorCXAmLFB0W6Cz4KPP01nD9YBB4olxiK1t7m0AU9zscdivNiuUaB5OIEr+JuZ6dNw="; - String cipherSuiteJKS = "SSL_RSA_WITH_RC4_128_MD5"; + private static final String CIPHER_SUITE = "SSL_RSA_WITH_RC4_128_MD5"; /** * Defines the keystore contents for the server, JKS version. Holds just a * single self-generated key. The subject name is "Test Server". @@ -707,8 +704,6 @@ public class SSLSessionTest extends TestCase { private String PASSWORD = "android"; - String cipherSuite = (useBKS ? cipherSuiteBKS : cipherSuiteJKS); - /** * Implements a test SSL socket server. It waits for a connection on a given * port, requests client authentication (if specified), reads from the socket, |