From b50d3949d81d8cece6c71c2b094297317e584308 Mon Sep 17 00:00:00 2001 From: Nick Hudson Date: Wed, 3 Apr 2013 11:54:02 +0100 Subject: Provide mechanism to allow clients to restrict available ciphersuites By default, when a TLS connection is established, the SSLContext will enable all available ciphersuites. This may not be appropriate in situations where export restrictions apply and higher grade ciphersuites are prohibitied. This change allows a caller to configure a restricted set of ciphersuites to be used when establishing TLS connections. Callers use the JSSEContextFactory.setRestrictedCipherSuites() method to configure a list of ciphersuites. Any ciphersuites which are not included in the list will be excluded in subsequent TLS connections. If the JSSEContextFactory.setRestrictedCipherSuites() is never called, or called with a null parameter, then no restriction will apply. Test-information: Validated that by calling the new method to restrict the available ciphers, TLS connections initiated by Stroke only propose ciphersuites in the restricted list, and connections fail when the server fails to find an acceptable cipher. Change-Id: Id0b4b19553a6f386cda27a71f0172410d899218e Signed-off-by: Nick Hudson diff --git a/src/com/isode/stroke/tls/PlatformTLSFactories.java b/src/com/isode/stroke/tls/PlatformTLSFactories.java index 6b98a95..cbfcfe2 100644 --- a/src/com/isode/stroke/tls/PlatformTLSFactories.java +++ b/src/com/isode/stroke/tls/PlatformTLSFactories.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Isode Limited, London, England. + * Copyright (c) 2012-2013 Isode Limited, London, England. * All rights reserved. */ /* @@ -11,8 +11,10 @@ package com.isode.stroke.tls; import com.isode.stroke.tls.java.JSSEContextFactory; public class PlatformTLSFactories { + private JSSEContextFactory contextFactory = new JSSEContextFactory(); + public TLSContextFactory getTLSContextFactory() { - return new JSSEContextFactory(); + return contextFactory; } public CertificateFactory getCertificateFactory() { diff --git a/src/com/isode/stroke/tls/java/JSSEContext.java b/src/com/isode/stroke/tls/java/JSSEContext.java index 9cb0109..257a70c 100644 --- a/src/com/isode/stroke/tls/java/JSSEContext.java +++ b/src/com/isode/stroke/tls/java/JSSEContext.java @@ -26,6 +26,8 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; +import java.util.HashSet; +import java.util.Set; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; @@ -117,13 +119,14 @@ public class JSSEContext extends TLSContext { @Override public void connect() { try { - doSetup(); + doSetup(); } catch (SSLException e) { emitError(e,"doSetup() failed"); } } + private void doSetup() throws SSLException { SSLContext sslContext = getSSLContext(); @@ -143,6 +146,23 @@ public class JSSEContext extends TLSContext { /* "the SSLContextImpl requires initialization and init() has not been called" */ throw new SSLException(e); } + + /* Restrict cipher suites if necessary */ + if (restrictedCipherSuites != null) { + String[] supportedSuites = sslEngine.getSupportedCipherSuites(); + Set matchedSuites = new HashSet(); + for (String suite:supportedSuites) { + if (restrictedCipherSuites.contains(suite)) { + matchedSuites.add(suite); + } + } + String[] suitesToEnable = new String[]{}; + if (!matchedSuites.isEmpty()) { + suitesToEnable = (String[])matchedSuites.toArray(); + } + + sslEngine.setEnabledCipherSuites(suitesToEnable); + } sslEngine.setUseClientMode(true); /* I am a client */ sslEngine.setEnableSessionCreation(true); /* can create new sessions */ @@ -1018,10 +1038,21 @@ public class JSSEContext extends TLSContext { /** * Construct a new JSSEContext object. + * @param restrictedCipherSuites a list of cipher suites that are to be + * enabled for this context. Null means no restriction */ - public JSSEContext() { - /* */ + public JSSEContext(Set restrictedCipherSuites) { + if (restrictedCipherSuites != null) { + this.restrictedCipherSuites = new HashSet(restrictedCipherSuites); + } } + + + /** + * Specific list of suites to allow - null (the default) means + * no restriction. + */ + private Set restrictedCipherSuites = null; /** * Reference to the SSLEngine being used diff --git a/src/com/isode/stroke/tls/java/JSSEContextFactory.java b/src/com/isode/stroke/tls/java/JSSEContextFactory.java index 0ddb4fd..63b184d 100644 --- a/src/com/isode/stroke/tls/java/JSSEContextFactory.java +++ b/src/com/isode/stroke/tls/java/JSSEContextFactory.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2012, Isode Limited, London, England. +/* Copyright (c) 2012-2013, Isode Limited, London, England. * All rights reserved. * * Acquisition and use of this software and related materials for any @@ -10,12 +10,19 @@ package com.isode.stroke.tls.java; +import java.util.HashSet; +import java.util.Set; + import com.isode.stroke.tls.TLSContext; import com.isode.stroke.tls.TLSContextFactory; /** * Concrete implementation of a TLSContextFactory which uses SSLEngine - * and maybe other stuff? ..tbs... + * + *

Ciphersuite names recognised by this class correspond to the standard + * names as described in + * + * Oracle's "Java Cryptography Architecture Standard Algorithm Name Documentation". * */ public class JSSEContextFactory implements TLSContextFactory { @@ -27,7 +34,29 @@ public class JSSEContextFactory implements TLSContextFactory { @Override public TLSContext createTLSContext() { - return new JSSEContext(); + return new JSSEContext(restrictedCipherSuites); } + + private static Set restrictedCipherSuites = null; + + /** + * Restrict which cipher suites are to be enabled for any TLSContexts + * returned by this factory from now on. Any name which is + * not recognised, or not available is ignored: this method cannot be + * used to enable otherwise unavailable ciphersuites. + * + * @param cipherSuites a set of cipher suite names. If this parameter is + * null, then no restriction on cipher suites applies (all suites available + * to the implementation will be enabled). + * + */ + public static void setRestrictedCipherSuites(Set cipherSuites) { + if (cipherSuites == null) { + restrictedCipherSuites = null; + return; + } + + restrictedCipherSuites = new HashSet(cipherSuites); + } } -- cgit v0.10.2-6-g49f6