Added: 
tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java?rev=1608840&view=auto
==============================================================================
--- 
tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java
 (added)
+++ 
tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/OpenSSLCipherConfigurationParser.java
 Tue Jul  8 16:20:54 2014
@@ -0,0 +1,684 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.tomcat.util.net.jsse.openssl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * Class in charge with parsing openSSL expressions to define a list of 
ciphers.
+ */
+public class OpenSSLCipherConfigurationParser {
+
+    private static final org.apache.juli.logging.Log log =
+            
org.apache.juli.logging.LogFactory.getLog(OpenSSLCipherConfigurationParser.class);
+    private static final StringManager sm =
+            StringManager.getManager("org.apache.tomcat.util.net.jsse.res");
+
+    /**
+     * System property key to define the DEFAULT ciphers.
+     */
+    public static final String DEFAULT_EXPRESSION_KEY = 
"openssl.default.ciphers";
+
+    private static boolean initialized = false;
+
+    private static final String SEPARATOR = ":|,| ";
+    /**
+     * If ! is used then the ciphers are permanently deleted from the list. 
The ciphers deleted can never reappear in the list
+     * even if they are explicitly stated.
+     */
+    private final static String EXCLUDE = "!";
+    /**
+     * If - is used then the ciphers are deleted from the list, but some or 
all of the ciphers can be added again by later
+     * options.
+     */
+    private static final String DELETE = "-";
+    /**
+     * If + is used then the ciphers are moved to the end of the list. This 
option doesn't add any new ciphers it just moves
+     * matching existing ones.
+     */
+    private static final String TO_END = "+";
+     /**
+     * Lists of cipher suites can be combined in a single cipher string using 
the + character. 
+     * This is used as a logical and operation. 
+     * For example SHA1+DES represents all cipher suites containing the SHA1 
and the DES algorithms. 
+     */
+    private static final String AND = "+";
+    /**
+     * All ciphers by their openssl alias name.
+     */
+    private static final Map<String, List<Ciphers>> aliases = new 
LinkedHashMap<String, List<Ciphers>>();
+
+    /**
+     * the 'NULL' ciphers that is those offering no encryption. Because these 
offer no encryption at all and are a security risk
+     * they are disabled unless explicitly included.
+     */
+    private static final String eNULL = "eNULL";
+    /**
+     * The cipher suites offering no authentication. This is currently the 
anonymous DH algorithms. T These cipher suites are
+     * vulnerable to a 'man in the middle' attack and so their use is normally 
discouraged.
+     */
+    private static final String aNULL = "aNULL";
+
+    /**
+     * 'high' encryption cipher suites. This currently means those with key 
lengths larger than 128 bits, and some cipher suites
+     * with 128-bit keys.
+     */
+    private static final String HIGH = "HIGH";
+    /**
+     * 'medium' encryption cipher suites, currently some of those using 128 
bit encryption.
+     */
+    private static final String MEDIUM = "MEDIUM";
+    /**
+     * 'low' encryption cipher suites, currently those using 64 or 56 bit 
encryption algorithms but excluding export cipher
+     * suites.
+     */
+    private static final String LOW = "LOW";
+    /**
+     * Export encryption algorithms. Including 40 and 56 bits algorithms.
+     */
+    private static final String EXPORT = "EXPORT";
+    /**
+     * 40 bit export encryption algorithms.
+     */
+    private static final String EXPORT40 = "EXPORT40";
+    /**
+     * 56 bit export encryption algorithms.
+     */
+    private static final String EXPORT56 = "EXPORT56";
+    /**
+     * Cipher suites using RSA key exchange.
+     */
+    private static final String kRSA = "kRSA";
+    /**
+     * Cipher suites using RSA authentication.
+     */
+    private static final String aRSA = "aRSA";
+    /**
+     * Cipher suites using RSA for key exchange or for authentication.
+     */
+    private static final String RSA = "RSA";
+    /**
+     * Cipher suites using ephemeral DH key agreement.
+     */
+    private static final String kEDH = "kEDH";
+    /**
+     * Cipher suites using ephemeral DH key agreement.
+     */
+    private static final String kDHE = "kDHE";
+    /**
+     * Cipher suites using ephemeral DH key agreement. equivalent to kEDH:-ADH
+     */
+    private static final String EDH = "EDH";
+    /**
+     * Cipher suites using ephemeral DH key agreement. equivalent to kEDH:-ADH
+     */
+    private static final String DHE = "DHE";
+    /**
+     * Cipher suites using DH key agreement and DH certificates signed by CAs 
with RSA keys.
+     */
+    private static final String kDHr = "kDHr";
+    /**
+     * Cipher suites using DH key agreement and DH certificates signed by CAs 
with DSS keys.
+     */
+    private static final String kDHd = "kDHd";
+    /**
+     * Cipher suites using DH key agreement and DH certificates signed by CAs 
with RSA or DSS keys.
+     */
+    private static final String kDH = "kDH";
+    /**
+     * Cipher suites using fixed ECDH key agreement signed by CAs with RSA 
keys.
+     */
+    private static final String kECDHr = "kECDHr";
+    /**
+     * Cipher suites using fixed ECDH key agreement signed by CAs with ECDSA 
keys.
+     */
+    private static final String kECDHe = "kECDHe";
+    /**
+     * Cipher suites using fixed ECDH key agreement signed by CAs with RSA and 
ECDSA keys or either respectively.
+     */
+    private static final String kECDH = "kECDH";
+    /**
+     * Cipher suites using ephemeral ECDH key agreement, including anonymous 
cipher suites.
+     */
+    private static final String kEECDH = "kEECDH";
+    /**
+     * Cipher suitesusing ECDH key exchange, including anonymous, ephemeral 
and fixed ECDH.
+     */
+    private static final String ECDH = "ECDH";
+    /**
+     * Cipher suites using ephemeral ECDH key agreement, including anonymous 
cipher suites.
+     */
+    private static final String kECDHE = "kECDHE";
+    /**
+     * Cipher suites using authenticated ephemeral ECDH key agreement
+     */
+    private static final String ECDHE = "ECDHE";
+    /**
+     * Cipher suites using authenticated ephemeral ECDH key agreement
+     */
+    private static final String EECDHE = "EECDHE";
+    /**
+     * Anonymous Elliptic Curve Diffie Hellman cipher suites.
+     */
+    private static final String AECDH = "AECDH";
+    /**
+     * Cipher suites using DSS authentication, i.e. the certificates carry DSS 
keys.
+     */
+    private static final String aDSS = "aDSS";
+    /**
+     * Cipher suites effectively using DH authentication, i.e. the 
certificates carry DH keys.
+     */
+    private static final String aDH = "aDH";
+    /**
+     * Cipher suites effectively using ECDH authentication, i.e. the 
certificates carry ECDH keys.
+     */
+    private static final String aECDH = "aECDH";
+    /**
+     * Cipher suites effectively using ECDSA authentication, i.e. the 
certificates carry ECDSA keys.
+     */
+    private static final String aECDSA = "aECDSA";
+    /**
+     * Cipher suites effectively using ECDSA authentication, i.e. the 
certificates carry ECDSA keys.
+     */
+    private static final String ECDSA = "ECDSA";
+    /**
+     * Ciphers suites using FORTEZZA key exchange algorithms.
+     */
+    private static final String kFZA = "kFZA";
+    /**
+     * Ciphers suites using FORTEZZA authentication algorithms.
+     */
+    private static final String aFZA = "aFZA";
+    /**
+     * Ciphers suites using FORTEZZA encryption algorithms.
+     */
+    private static final String eFZA = "eFZA";
+    /**
+     * Ciphers suites using all FORTEZZA algorithms.
+     */
+    private static final String FZA = "FZA";
+    /**
+     * TLS v1.2 cipher suites. Note: there are no cipher suites specific to 
TLS v1.1.
+     */
+    private static final String TLSv1_2 = "TLSv1_2";
+    /**
+     * TLS v1.0 cipher suites.
+     */
+    private static final String TLSv1 = "TLSv1";
+    /**
+     * SSL v2.0 cipher suites.
+     */
+    private static final String SSLv2 = "SSLv2";
+    /**
+     * SSL v3.0 cipher suites.
+     */
+    private static final String SSLv3 = "SSLv3";
+    /**
+     * Cipher suites using DH, including anonymous DH, ephemeral DH and fixed 
DH.
+     */
+    private static final String DH = "DH";
+    /**
+     * Anonymous DH cipher suites.
+     */
+    private static final String ADH = "ADH";
+    /**
+     * Cipher suites using 128 bit AES.
+     */
+    private static final String AES128 = "AES128";
+    /**
+     * Cipher suites using 256 bit AE.
+     */
+    private static final String AES256 = "AES256";
+    /**
+     * Cipher suites using either 128 or 256 bit AES.
+     */
+    private static final String AES = "AES";
+    /**
+     * AES in Galois Counter Mode (GCM): these cipher suites are only 
supported in TLS v1.2.
+     */
+    private static final String AESGCM = "AESGCM";
+    /**
+     * Cipher suites using 128 bit CAMELLIA.
+     */
+    private static final String CAMELLIA128 = "CAMELLIA128";
+    /**
+     * Cipher suites using 256 bit CAMELLIA.
+     */
+    private static final String CAMELLIA256 = "CAMELLIA256";
+    /**
+     * Cipher suites using either 128 or 256 bit CAMELLIA.
+     */
+    private static final String CAMELLIA = "CAMELLIA";
+    /**
+     * Cipher suites using triple DES.
+     */
+    private static final String TRIPLE_DES = "3DES";
+    /**
+     * Cipher suites using DES (not triple DES).
+     */
+    private static final String DES = "DES";
+    /**
+     * Cipher suites using RC4.
+     */
+    private static final String RC4 = "RC4";
+    /**
+     * Cipher suites using RC2.
+     */
+    private static final String RC2 = "RC2";
+    /**
+     * Cipher suites using IDEA.
+     */
+    private static final String IDEA = "IDEA";
+    /**
+     * Cipher suites using SEED.
+     */
+    private static final String SEED = "SEED";
+    /**
+     * Cipher suites using MD5.
+     */
+    private static final String MD5 = "MD5";
+    /**
+     * Cipher suites using SHA1.
+     */
+    private static final String SHA1 = "SHA1";
+    /**
+     * Cipher suites using SHA1.
+     */
+    private static final String SHA = "SHA";
+    /**
+     * Cipher suites using SHA256.
+     */
+    private static final String SHA256 = "SHA256";
+    /**
+     * Cipher suites using SHA384.
+     */
+    private static final String SHA384 = "SHA384";
+    /**
+     * Cipher suites using KRB5.
+     */
+    private static final String KRB5 = "KRB5";
+    /**
+     * Cipher suites using GOST R 34.10 (either 2001 or 94) for authentication.
+     */
+    private static final String aGOST = "aGOST";
+    /**
+     * Cipher suites using GOST R 34.10-2001 for authentication.
+     */
+    private static final String aGOST01 = "aGOST01";
+    /**
+     * Cipher suites using GOST R 34.10-94 authentication (note that R 
34.10-94 standard has been expired so use GOST R
+     * 34.10-2001)
+     */
+    private static final String aGOST94 = "aGOST94";
+    /**
+     * Cipher suites using using VKO 34.10 key exchange, specified in the RFC 
4357.
+     */
+    private static final String kGOST = "kGOST";
+    /**
+     * Cipher suites, using HMAC based on GOST R 34.11-94.
+     */
+    private static final String GOST94 = "GOST94";
+    /**
+     * Cipher suites using GOST 28147-89 MAC instead of HMAC.
+     */
+    private static final String GOST89MAC = "GOST89MAC";
+    /**
+     * Cipher suites using pre-shared keys (PSK).
+     */
+    private static final String PSK = "PSK";
+
+    private static final String DEFAULT = "DEFAULT";
+    private static final String COMPLEMENTOFDEFAULT = "COMPLEMENTOFDEFAULT";
+
+    private static final String ALL = "ALL";
+    private static final String COMPLEMENTOFALL = "COMPLEMENTOFALL";
+
+    private static final void init() {
+
+        for (Ciphers cipher : Ciphers.values()) {
+            String alias = cipher.getOpenSSLAlias();
+            if (aliases.containsKey(alias)) {
+                aliases.get(alias).add(cipher);
+            } else {
+                List<Ciphers> list = new ArrayList<Ciphers>();
+                list.add(cipher);
+                aliases.put(alias, list);
+            }
+            aliases.put(cipher.name(), Collections.singletonList(cipher));
+        }
+        List<Ciphers> allCiphers = Arrays.asList(Ciphers.values());
+        Collections.reverse(allCiphers);
+        LinkedHashSet<Ciphers> all = defaultSort(new 
LinkedHashSet<Ciphers>(allCiphers));
+        addListAlias(ALL, all);
+        addListAlias(HIGH, filterByEncryptionLevel(all, 
Collections.singleton(EncryptionLevel.HIGH)));
+        addListAlias(MEDIUM, filterByEncryptionLevel(all, 
Collections.singleton(EncryptionLevel.MEDIUM)));
+        addListAlias(LOW, filterByEncryptionLevel(all, 
Collections.singleton(EncryptionLevel.LOW)));
+        addListAlias(EXPORT, filterByEncryptionLevel(all, new 
HashSet<EncryptionLevel>(Arrays.asList(EncryptionLevel.EXP40, 
EncryptionLevel.EXP56))));
+        aliases.put("EXP", aliases.get(EXPORT));
+        addListAlias(EXPORT40, filterByEncryptionLevel(all, 
Collections.singleton(EncryptionLevel.EXP40)));
+        addListAlias(EXPORT56, filterByEncryptionLevel(all, 
Collections.singleton(EncryptionLevel.EXP56)));
+        addListAlias(eNULL, filterByEncryption(all, 
Collections.singleton(Encryption.eNULL)));
+        aliases.put("NULL", aliases.get(eNULL));
+        aliases.put(COMPLEMENTOFALL, aliases.get(eNULL));
+        addListAlias(aNULL, filterByAuthentication(all, 
Collections.singleton(Authentication.aNULL)));
+        addListAlias(kRSA, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.RSA)));
+        addListAlias(aRSA, filterByAuthentication(all, 
Collections.singleton(Authentication.RSA)));
+        addListAlias(RSA, filter(all, null, 
Collections.singleton(KeyExchange.RSA), 
Collections.singleton(Authentication.RSA), null, null, null));
+        addListAlias(kEDH, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.EDH)));
+        addListAlias(kDHE, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.EDH)));
+        Set<Ciphers> edh = filterByKeyExchange(all, 
Collections.singleton(KeyExchange.EDH));
+        edh.removeAll(filterByAuthentication(all, 
Collections.singleton(Authentication.DH)));
+        addListAlias(EDH, edh);
+        addListAlias(DHE, edh);
+        addListAlias(kDHr, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.DHr)));
+        addListAlias(kDHd, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.DHd)));
+        addListAlias(kDH, filterByKeyExchange(all, new 
HashSet<KeyExchange>(Arrays.asList(KeyExchange.DHr, KeyExchange.DHd))));
+
+        addListAlias(kECDHr, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.ECDHr)));
+        addListAlias(kECDHe, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.ECDHe)));
+        addListAlias(kECDH, filterByKeyExchange(all, new 
HashSet<KeyExchange>(Arrays.asList(KeyExchange.ECDHe, KeyExchange.ECDHr))));
+        aliases.put(ECDH, aliases.get(kECDH));
+        addListAlias(kECDHE, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.ECDHe)));
+        aliases.put(ECDHE, aliases.get(kECDHE));
+        addListAlias(kEECDH, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.EECDH)));
+        aliases.put(EECDHE, aliases.get(kEECDH));
+        addListAlias(aDSS, filterByAuthentication(all, 
Collections.singleton(Authentication.DSS)));
+        aliases.put("DSS", aliases.get(aDSS));
+        addListAlias(aDH, filterByAuthentication(all, 
Collections.singleton(Authentication.DH)));
+        Set<Ciphers> aecdh = filterByKeyExchange(all, new 
HashSet<KeyExchange>(Arrays.asList(KeyExchange.ECDHe, KeyExchange.ECDHr)));
+        aecdh.removeAll(filterByAuthentication(all, 
Collections.singleton(Authentication.aNULL)));
+        addListAlias(AECDH, aecdh);
+        addListAlias(aECDH, filterByAuthentication(all, 
Collections.singleton(Authentication.ECDH)));
+        addListAlias(ECDSA, filterByAuthentication(all, 
Collections.singleton(Authentication.ECDSA)));
+        aliases.put(aECDSA, aliases.get(ECDSA));
+        addListAlias(kFZA, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.FZA)));
+        addListAlias(aFZA, filterByAuthentication(all, 
Collections.singleton(Authentication.FZA)));
+        addListAlias(eFZA, filterByEncryption(all, 
Collections.singleton(Encryption.FZA)));
+        addListAlias(FZA, filter(all, null, 
Collections.singleton(KeyExchange.FZA), 
Collections.singleton(Authentication.FZA), 
Collections.singleton(Encryption.FZA), null, null));
+        addListAlias(TLSv1_2, filterByProtocol(all, 
Collections.singleton(Protocol.TLSv1_2)));
+        addListAlias("TLSv1.1", filterByProtocol(all, 
Collections.singleton(Protocol.SSLv3)));
+        addListAlias(TLSv1, filterByProtocol(all, 
Collections.singleton(Protocol.TLSv1)));
+        addListAlias(SSLv3, filterByProtocol(all, 
Collections.singleton(Protocol.SSLv3)));
+        addListAlias(SSLv2, filterByProtocol(all, 
Collections.singleton(Protocol.SSLv2)));
+        addListAlias(DH, filterByKeyExchange(all, new 
HashSet<KeyExchange>(Arrays.asList(KeyExchange.DHr, KeyExchange.DHd, 
KeyExchange.EDH))));
+        Set<Ciphers> adh = filterByKeyExchange(all, 
Collections.singleton(KeyExchange.EDH));
+        adh.retainAll(filterByAuthentication(all, 
Collections.singleton(Authentication.aNULL)));
+        addListAlias(ADH, adh);
+        addListAlias(AES128, filterByEncryption(all, new 
HashSet<Encryption>(Arrays.asList(Encryption.AES128, Encryption.AES128GCM))));
+        addListAlias(AES256, filterByEncryption(all, new 
HashSet<Encryption>(Arrays.asList(Encryption.AES256, Encryption.AES256GCM))));
+        addListAlias(AES, filterByEncryption(all, new 
HashSet<Encryption>(Arrays.asList(Encryption.AES128, Encryption.AES128GCM, 
Encryption.AES256, Encryption.AES256GCM))));
+        addListAlias(AESGCM, filterByEncryption(all, new 
HashSet<Encryption>(Arrays.asList(Encryption.AES128GCM, 
Encryption.AES256GCM))));
+        addListAlias(CAMELLIA, filterByEncryption(all, new 
HashSet<Encryption>(Arrays.asList(Encryption.CAMELLIA128, 
Encryption.CAMELLIA256))));
+        addListAlias(CAMELLIA128, filterByEncryption(all, 
Collections.singleton(Encryption.CAMELLIA128)));
+        addListAlias(CAMELLIA256, filterByEncryption(all, 
Collections.singleton(Encryption.CAMELLIA256)));
+        addListAlias(TRIPLE_DES, filterByEncryption(all, 
Collections.singleton(Encryption.TRIPLE_DES)));
+        addListAlias(DES, filterByEncryption(all, 
Collections.singleton(Encryption.DES)));
+        addListAlias(RC4, filterByEncryption(all, 
Collections.singleton(Encryption.RC4)));
+        addListAlias(RC2, filterByEncryption(all, 
Collections.singleton(Encryption.RC2)));
+        addListAlias(IDEA, filterByEncryption(all, 
Collections.singleton(Encryption.IDEA)));
+        addListAlias(SEED, filterByEncryption(all, 
Collections.singleton(Encryption.SEED)));
+        addListAlias(MD5, filterByMessageDigest(all, 
Collections.singleton(MessageDigest.MD5)));
+        addListAlias(SHA1, filterByMessageDigest(all, 
Collections.singleton(MessageDigest.SHA1)));
+        aliases.put(SHA, aliases.get(SHA1));
+        addListAlias(SHA256, filterByMessageDigest(all, 
Collections.singleton(MessageDigest.SHA256)));
+        addListAlias(SHA384, filterByMessageDigest(all, 
Collections.singleton(MessageDigest.SHA384)));
+        addListAlias(aGOST, filterByAuthentication(all, new 
HashSet<Authentication>(Arrays.asList(Authentication.GOST01, 
Authentication.GOST94))));
+        addListAlias(aGOST01, filterByAuthentication(all, 
Collections.singleton(Authentication.GOST01)));
+        addListAlias(aGOST94, filterByAuthentication(all, 
Collections.singleton(Authentication.GOST94)));
+        addListAlias(kGOST, filterByKeyExchange(all, 
Collections.singleton(KeyExchange.GOST)));
+        addListAlias(GOST94, filterByMessageDigest(all, 
Collections.singleton(MessageDigest.GOST94)));
+        addListAlias(GOST89MAC, filterByMessageDigest(all, 
Collections.singleton(MessageDigest.GOST89MAC)));
+        addListAlias(PSK, filter(all, null, 
Collections.singleton(KeyExchange.PSK), 
Collections.singleton(Authentication.PSK), null, null, null));
+        addListAlias(KRB5, filter(all, null, 
Collections.singleton(KeyExchange.KRB5), 
Collections.singleton(Authentication.KRB5), null, null, null));
+        initialized = true;
+        String defaultExpression = System.getProperty(DEFAULT_EXPRESSION_KEY, 
"ALL:!eNULL:!aNULL");
+        addListAlias(DEFAULT, parse(defaultExpression));
+        LinkedHashSet<Ciphers> complementOfDefault = new 
LinkedHashSet<Ciphers>(all);
+        complementOfDefault.removeAll(aliases.get(DEFAULT));
+        addListAlias(COMPLEMENTOFDEFAULT, complementOfDefault);
+    }
+
+    static void addListAlias(String alias, Set<Ciphers> ciphers) {
+        aliases.put(alias, new ArrayList<Ciphers>(ciphers));
+    }
+
+    static void moveToEnd(final LinkedHashSet<Ciphers> ciphers, final String 
alias) {
+        moveToEnd(ciphers, aliases.get(alias));
+    }
+
+    static void moveToEnd(final LinkedHashSet<Ciphers> ciphers, final 
Collection<Ciphers> toBeMovedCiphers) {
+        List<Ciphers> movedCiphers = new ArrayList<Ciphers>(toBeMovedCiphers);
+        movedCiphers.retainAll(ciphers);
+        ciphers.removeAll(movedCiphers);
+        ciphers.addAll(movedCiphers);
+    }
+
+    static void add(final LinkedHashSet<Ciphers> ciphers, final String alias) {
+        ciphers.addAll(aliases.get(alias));
+    }
+
+    static void remove(final LinkedHashSet<Ciphers> ciphers, final String 
alias) {
+        ciphers.removeAll(aliases.get(alias));
+    }
+
+    static LinkedHashSet<Ciphers> strengthSort(final LinkedHashSet<Ciphers> 
ciphers) {
+        /*
+         * This routine sorts the ciphers with descending strength. The sorting
+         * must keep the pre-sorted sequence, so we apply the normal sorting
+         * routine as '+' movement to the end of the list.
+         */
+        Set<Integer> keySizes = new HashSet<Integer>();
+        for (Ciphers cipher : ciphers) {
+            keySizes.add(cipher.getStrength_bits());
+        }
+        List<Integer> strength_bits = new ArrayList<Integer>(keySizes);
+        Collections.sort(strength_bits);
+        Collections.reverse(strength_bits);
+        final LinkedHashSet<Ciphers> result = new 
LinkedHashSet<Ciphers>(ciphers);
+        for (int strength : strength_bits) {
+            moveToEnd(result, filterByStrengthBits(ciphers, strength));
+        }
+        return result;
+    }
+
+    static LinkedHashSet<Ciphers> defaultSort(final LinkedHashSet<Ciphers> 
ciphers) {
+        final LinkedHashSet<Ciphers> result = new 
LinkedHashSet<Ciphers>(ciphers.size());
+        /* Now arrange all ciphers by preference: */
+
+        /* Everything else being equal, prefer ephemeral ECDH over other key 
exchange mechanisms */
+        result.addAll(filterByKeyExchange(ciphers, 
Collections.singleton(KeyExchange.EECDH)));
+        /* AES is our preferred symmetric cipher */
+        result.addAll(filterByEncryption(ciphers, new 
HashSet<Encryption>(Arrays.asList(Encryption.AES128, Encryption.AES128GCM,
+                Encryption.AES256, Encryption.AES256GCM))));
+        /* Temporarily enable everything else for sorting */
+        result.addAll(ciphers);
+
+
+        /* Low priority for MD5 */
+        moveToEnd(result, filterByMessageDigest(result, 
Collections.singleton(MessageDigest.MD5)));
+
+        /* Move anonymous ciphers to the end.  Usually, these will remain 
disabled.
+         * (For applications that allow them, they aren't too bad, but we 
prefer
+         * authenticated ciphers.) */
+        moveToEnd(result, filterByAuthentication(result, 
Collections.singleton(Authentication.aNULL)));
+
+        /* Move ciphers without forward secrecy to the end */
+        moveToEnd(result, filterByAuthentication(result, 
Collections.singleton(Authentication.ECDH)));
+        moveToEnd(result, filterByKeyExchange(result, 
Collections.singleton(KeyExchange.RSA)));
+        moveToEnd(result, filterByKeyExchange(result, 
Collections.singleton(KeyExchange.PSK)));
+        moveToEnd(result, filterByKeyExchange(result, 
Collections.singleton(KeyExchange.KRB5)));
+        /* RC4 is sort-of broken -- move the the end */
+        moveToEnd(result, filterByEncryption(result, 
Collections.singleton(Encryption.RC4)));
+        return strengthSort(result);
+    }
+
+    static Set<Ciphers> filterByStrengthBits(Set<Ciphers> ciphers, int 
strength_bits) {
+        Set<Ciphers> result = new LinkedHashSet<Ciphers>(ciphers.size());
+        for (Ciphers cipher : ciphers) {
+            if (cipher.getStrength_bits() == strength_bits) {
+                result.add(cipher);
+            }
+        }
+        return result;
+    }
+
+    static Set<Ciphers> filterByProtocol(Set<Ciphers> ciphers, Set<Protocol> 
protocol) {
+        return filter(ciphers, protocol, null, null, null, null, null);
+    }
+
+    static Set<Ciphers> filterByKeyExchange(Set<Ciphers> ciphers, 
Set<KeyExchange> kx) {
+        return filter(ciphers, null, kx, null, null, null, null);
+    }
+
+    static Set<Ciphers> filterByAuthentication(Set<Ciphers> ciphers, 
Set<Authentication> au) {
+        return filter(ciphers, null, null, au, null, null, null);
+    }
+
+    static Set<Ciphers> filterByEncryption(Set<Ciphers> ciphers, 
Set<Encryption> enc) {
+        return filter(ciphers, null, null, null, enc, null, null);
+    }
+
+    static Set<Ciphers> filterByEncryptionLevel(Set<Ciphers> ciphers, 
Set<EncryptionLevel> level) {
+        return filter(ciphers, null, null, null, null, level, null);
+    }
+
+    static Set<Ciphers> filterByMessageDigest(Set<Ciphers> ciphers, 
Set<MessageDigest> mac) {
+        return filter(ciphers, null, null, null, null, null, mac);
+    }
+
+    static Set<Ciphers> filter(Set<Ciphers> ciphers, Set<Protocol> protocol, 
Set<KeyExchange> kx,
+            Set<Authentication> au, Set<Encryption> enc, Set<EncryptionLevel> 
level, Set<MessageDigest> mac) {
+        Set<Ciphers> result = new LinkedHashSet<Ciphers>(ciphers.size());
+        for (Ciphers cipher : ciphers) {
+            if (protocol != null && protocol.contains(cipher.getProtocol())) {
+                result.add(cipher);
+            }
+            if (kx != null && kx.contains(cipher.getKx())) {
+                result.add(cipher);
+            }
+            if (au != null && au.contains(cipher.getAu())) {
+                result.add(cipher);
+            }
+            if (enc != null && enc.contains(cipher.getEnc())) {
+                result.add(cipher);
+            }
+            if (level != null && level.contains(cipher.getLevel())) {
+                result.add(cipher);
+            }
+            if (mac != null && mac.contains(cipher.getMac())) {
+                result.add(cipher);
+            }
+        }
+        return result;
+    }
+
+    static LinkedHashSet<Ciphers> parse(String expression) {
+        if (!initialized) {
+            init();
+        }
+        String[] elements = expression.split(SEPARATOR);
+        LinkedHashSet<Ciphers> ciphers = new LinkedHashSet<Ciphers>();
+        Set<Ciphers> removedCiphers = new HashSet<Ciphers>();
+        for (String element : elements) {
+            if (element.startsWith(DELETE)) {
+                String alias = element.substring(1);
+                if (aliases.containsKey(alias)) {
+                    remove(ciphers, alias);
+                }
+            } else if (element.startsWith(EXCLUDE)) {
+                String alias = element.substring(1);
+                if (aliases.containsKey(alias)) {
+                    removedCiphers.addAll(aliases.get(alias));
+                } else {
+                    log.warn(sm.getString("jsse.openssl.unknownElement", 
alias));
+                }
+            } else if (element.startsWith(TO_END)) {
+                String alias = element.substring(1);
+                if (aliases.containsKey(alias)) {
+                    moveToEnd(ciphers, alias);
+                }
+            } else if ("@STRENGTH".equals(element)) {
+                strengthSort(ciphers);
+                break;
+            } else if (aliases.containsKey(element)) {
+                add(ciphers, element);
+            } else if (element.contains(AND)) {
+                String[] intersections = element.split("\\" + AND);
+                if(intersections.length > 0) {
+                    List<Ciphers> result = new 
ArrayList<Ciphers>(aliases.get(intersections[0]));
+                    for(int i = 1; i < intersections.length; i++) {
+                        if(aliases.containsKey(intersections[i])) {
+                            result.retainAll(aliases.get(intersections[i]));
+                        }
+                    }
+                     ciphers.addAll(result);
+                }
+            }
+        }
+        ciphers.removeAll(removedCiphers);
+        return defaultSort(ciphers);
+    }
+
+    static List<String> convertForJSSE(Collection<Ciphers> ciphers) {
+        List<String> result = new ArrayList<String>(ciphers.size());
+        for (Ciphers cipher : ciphers) {
+            result.add(cipher.name());
+        }
+        if (log.isDebugEnabled()) {
+            log.debug(sm.getString("jsse.openssl.effectiveCiphers", 
displayResult(ciphers, true, ",")));
+        }
+        return result;
+    }
+
+    /**
+     * Parse the specified expression according to the OpenSSL syntax and 
returns a list of standard cipher names.
+     *
+     * @param expression: the openssl expression to define a list of cipher.
+     * @return the corresponding list of ciphers.
+     */
+    public static List<String> parseExpression(String expression) {
+        return convertForJSSE(parse(expression));
+    }
+
+    static String displayResult(Collection<Ciphers> ciphers, boolean 
useJSSEFormat, String separator) {
+        if (ciphers.isEmpty()) {
+            return "";
+        }
+        StringBuilder builder = new StringBuilder(ciphers.size() * 16);
+        for (Ciphers cipher : ciphers) {
+            if (useJSSEFormat) {
+                builder.append(cipher.name());
+            } else {
+                builder.append(cipher.getOpenSSLAlias());
+            }
+            builder.append(separator);
+        }
+        return builder.toString().substring(0, builder.length() - 1);
+    }
+}

Added: tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/Protocol.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/Protocol.java?rev=1608840&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/Protocol.java 
(added)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/jsse/openssl/Protocol.java Tue 
Jul  8 16:20:54 2014
@@ -0,0 +1,22 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.tomcat.util.net.jsse.openssl;
+
+enum Protocol {
+    SSLv3, SSLv2, TLSv1, TLSv1_2;
+}

Modified: 
tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties?rev=1608840&r1=1608839&r2=1608840&view=diff
==============================================================================
--- 
tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties 
(original)
+++ 
tomcat/trunk/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties 
Tue Jul  8 16:20:54 2014
@@ -28,4 +28,6 @@ jsseSupport.clientCertError=Error trying
 jseeSupport.certTranslationError=Error translating certificate [{0}]
 jsseSupport.noCertWant=No client certificate sent for want
 jsseSupport.serverRenegDisabled=SSL server initiated renegotiation is 
disabled, closing connection
-jsseSupport.unexpectedData=Unexpected data read from input stream
\ No newline at end of file
+jsseSupport.unexpectedData=Unexpected data read from input stream
+jsse.openssl.unknownElement=Unknown element in cipher string: {0}
+jsse.openssl.effectiveCiphers=Ciphers used: {0}

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1608840&r1=1608839&r2=1608840&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Tue Jul  8 16:20:54 2014
@@ -136,6 +136,10 @@
         Avoid possible NPE stopping endpoints that are not started (stop
         shouldn't do anything in that case). (remm)
       </fix>
+      <add>
+        <bug>56704</bug>: Add support for OpenSSL syntax for ciphers when
+        using JSSE SSL connectors. Submitted by Emmanuel Hugonnet. (remm)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Jasper">



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to