CipherSuiteList.java revision 15049:61bcc186e9dc
1/* 2 * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 27package sun.security.ssl; 28 29import java.io.*; 30import java.util.*; 31 32import javax.net.ssl.SSLException; 33 34/** 35 * A list of CipherSuites. Also maintains the lists of supported and 36 * default ciphersuites and supports I/O from handshake streams. 37 * 38 * Instances of this class are immutable. 39 * 40 */ 41final class CipherSuiteList { 42 43 private final Collection<CipherSuite> cipherSuites; 44 private String[] suiteNames; 45 46 // flag indicating whether this list contains any ECC ciphersuites. 47 // null if not yet checked. 48 private volatile Boolean containsEC; 49 50 // for use by buildAvailableCache() and 51 // Handshaker.getKickstartMessage() only 52 CipherSuiteList(Collection<CipherSuite> cipherSuites) { 53 this.cipherSuites = cipherSuites; 54 } 55 56 /** 57 * Create a CipherSuiteList with a single element. 58 */ 59 CipherSuiteList(CipherSuite suite) { 60 cipherSuites = new ArrayList<CipherSuite>(1); 61 cipherSuites.add(suite); 62 } 63 64 /** 65 * Construct a CipherSuiteList from a array of names. We don't bother 66 * to eliminate duplicates. 67 * 68 * @exception IllegalArgumentException if the array or any of its elements 69 * is null or if the ciphersuite name is unrecognized or unsupported 70 * using currently installed providers. 71 */ 72 CipherSuiteList(String[] names) { 73 if (names == null) { 74 throw new IllegalArgumentException("CipherSuites may not be null"); 75 } 76 cipherSuites = new ArrayList<CipherSuite>(names.length); 77 for (int i = 0; i < names.length; i++) { 78 String suiteName = names[i]; 79 CipherSuite suite = CipherSuite.valueOf(suiteName); 80 if (suite.isAvailable() == false) { 81 throw new IllegalArgumentException("Cannot support " 82 + suiteName + " with currently installed providers"); 83 } 84 cipherSuites.add(suite); 85 } 86 } 87 88 /** 89 * Read a CipherSuiteList from a HandshakeInStream in V3 ClientHello 90 * format. Does not check if the listed ciphersuites are known or 91 * supported. 92 */ 93 CipherSuiteList(HandshakeInStream in) throws IOException { 94 byte[] bytes = in.getBytes16(); 95 if ((bytes.length & 1) != 0) { 96 throw new SSLException("Invalid ClientHello message"); 97 } 98 cipherSuites = new ArrayList<CipherSuite>(bytes.length >> 1); 99 for (int i = 0; i < bytes.length; i += 2) { 100 cipherSuites.add(CipherSuite.valueOf(bytes[i], bytes[i+1])); 101 } 102 } 103 104 /** 105 * Return whether this list contains the given CipherSuite. 106 */ 107 boolean contains(CipherSuite suite) { 108 return cipherSuites.contains(suite); 109 } 110 111 // Return whether this list contains any ECC ciphersuites 112 boolean containsEC() { 113 if (containsEC == null) { 114 for (CipherSuite c : cipherSuites) { 115 if (c.keyExchange.isEC) { 116 containsEC = true; 117 return true; 118 } 119 } 120 121 containsEC = false; 122 } 123 124 return containsEC; 125 } 126 127 /** 128 * Return an Iterator for the CipherSuites in this list. 129 */ 130 Iterator<CipherSuite> iterator() { 131 return cipherSuites.iterator(); 132 } 133 134 /** 135 * Return a reference to the internal Collection of CipherSuites. 136 * The Collection MUST NOT be modified. 137 */ 138 Collection<CipherSuite> collection() { 139 return cipherSuites; 140 } 141 142 /** 143 * Return the number of CipherSuites in this list. 144 */ 145 int size() { 146 return cipherSuites.size(); 147 } 148 149 /** 150 * Return an array with the names of the CipherSuites in this list. 151 */ 152 synchronized String[] toStringArray() { 153 if (suiteNames == null) { 154 suiteNames = new String[cipherSuites.size()]; 155 int i = 0; 156 for (CipherSuite c : cipherSuites) { 157 suiteNames[i++] = c.name; 158 } 159 } 160 return suiteNames.clone(); 161 } 162 163 @Override 164 public String toString() { 165 return cipherSuites.toString(); 166 } 167 168 /** 169 * Write this list to an HandshakeOutStream in V3 ClientHello format. 170 */ 171 void send(HandshakeOutStream s) throws IOException { 172 byte[] suiteBytes = new byte[cipherSuites.size() * 2]; 173 int i = 0; 174 for (CipherSuite c : cipherSuites) { 175 suiteBytes[i] = (byte)(c.id >> 8); 176 suiteBytes[i+1] = (byte)c.id; 177 i += 2; 178 } 179 s.putBytes16(suiteBytes); 180 } 181} 182