1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import java.io.IOException; 20 import java.net.InetAddress; 21 import java.net.Socket; 22 import java.security.PrivateKey; 23 import java.security.interfaces.ECPrivateKey; 24 import java.security.interfaces.DSAPrivateKey; 25 import java.security.interfaces.RSAPrivateKey; 26 import javax.net.ssl.SSLException; 27 28 /** 29 * OpenSSL-based implementation of server sockets. 30 */ 31 public class OpenSSLServerSocketImpl extends javax.net.ssl.SSLServerSocket { 32 private final SSLParametersImpl sslParameters; 33 private String[] enabledProtocols = NativeCrypto.getSupportedProtocols(); 34 private String[] enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); 35 private boolean channelIdEnabled; 36 37 protected OpenSSLServerSocketImpl(SSLParametersImpl sslParameters) throws IOException { 38 this.sslParameters = sslParameters; 39 } 40 41 protected OpenSSLServerSocketImpl(int port, SSLParametersImpl sslParameters) 42 throws IOException { 43 super(port); 44 this.sslParameters = sslParameters; 45 } 46 47 protected OpenSSLServerSocketImpl(int port, int backlog, SSLParametersImpl sslParameters) 48 throws IOException { 49 super(port, backlog); 50 this.sslParameters = sslParameters; 51 } 52 53 protected OpenSSLServerSocketImpl(int port, 54 int backlog, 55 InetAddress iAddress, 56 SSLParametersImpl sslParameters) 57 throws IOException { 58 super(port, backlog, iAddress); 59 this.sslParameters = sslParameters; 60 } 61 62 @Override 63 public boolean getEnableSessionCreation() { 64 return sslParameters.getEnableSessionCreation(); 65 } 66 67 @Override 68 public void setEnableSessionCreation(boolean flag) { 69 sslParameters.setEnableSessionCreation(flag); 70 } 71 72 /** 73 * The names of the protocols' versions that may be used on this SSL 74 * connection. 75 * @return an array of protocols names 76 */ 77 @Override 78 public String[] getSupportedProtocols() { 79 return NativeCrypto.getSupportedProtocols(); 80 } 81 82 /** 83 * The names of the protocols' versions that in use on this SSL connection. 84 * 85 * @return an array of protocols names 86 */ 87 @Override 88 public String[] getEnabledProtocols() { 89 return enabledProtocols.clone(); 90 } 91 92 /** 93 * This method enables the protocols' versions listed by 94 * getSupportedProtocols(). 95 * 96 * @param protocols names of all the protocols to enable. 97 * 98 * @throws IllegalArgumentException when one or more of the names in the 99 * array are not supported, or when the array is null. 100 */ 101 @Override 102 public void setEnabledProtocols(String[] protocols) { 103 enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols); 104 } 105 106 @Override 107 public String[] getSupportedCipherSuites() { 108 return NativeCrypto.getSupportedCipherSuites(); 109 } 110 111 @Override 112 public String[] getEnabledCipherSuites() { 113 return enabledCipherSuites.clone(); 114 } 115 116 /** 117 * Enables/disables the TLS Channel ID extension for this server socket. 118 */ 119 public void setChannelIdEnabled(boolean enabled) { 120 channelIdEnabled = enabled; 121 } 122 123 /** 124 * Checks whether the TLS Channel ID extension is enabled for this server socket. 125 */ 126 public boolean isChannelIdEnabled() { 127 return channelIdEnabled; 128 } 129 130 /** 131 * This method enables the cipher suites listed by 132 * getSupportedCipherSuites(). 133 * 134 * @param suites the names of all the cipher suites to enable 135 * @throws IllegalArgumentException when one or more of the ciphers in array 136 * suites are not supported, or when the array is null. 137 */ 138 @Override 139 public void setEnabledCipherSuites(String[] suites) { 140 enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites); 141 } 142 143 @Override 144 public boolean getWantClientAuth() { 145 return sslParameters.getWantClientAuth(); 146 } 147 148 @Override 149 public void setWantClientAuth(boolean want) { 150 sslParameters.setWantClientAuth(want); 151 } 152 153 @Override 154 public boolean getNeedClientAuth() { 155 return sslParameters.getNeedClientAuth(); 156 } 157 158 @Override 159 public void setNeedClientAuth(boolean need) { 160 sslParameters.setNeedClientAuth(need); 161 } 162 163 @Override 164 public void setUseClientMode(boolean mode) { 165 sslParameters.setUseClientMode(mode); 166 } 167 168 @Override 169 public boolean getUseClientMode() { 170 return sslParameters.getUseClientMode(); 171 } 172 173 @Override 174 public Socket accept() throws IOException { 175 176 if (!sslParameters.getUseClientMode()) { 177 checkEnabledCipherSuites(); 178 } 179 180 OpenSSLSocketImpl socket = new OpenSSLSocketImpl(sslParameters, 181 enabledProtocols.clone(), 182 enabledCipherSuites.clone()); 183 socket.setChannelIdEnabled(channelIdEnabled); 184 implAccept(socket); 185 return socket; 186 } 187 188 /** 189 * Check if any of the enabled cipher suites has a chance to work. 190 * Not 100% accurate, just a useful diagnostic that the RI does. 191 */ 192 private void checkEnabledCipherSuites() throws SSLException { 193 /* Loop over all enabled cipher suites. If we find a problem, 194 * we just continue to the next one. If we find one that could 195 * work, we return. This basically makes sure the caller has 196 * configured some appropriate certificate/key unless 197 * an anonymous cipher is picked. 198 */ 199 for (String enabledCipherSuite : enabledCipherSuites) { 200 if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) { 201 continue; 202 } 203 String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType(); 204 if (keyType == null) { 205 // anonymous always work 206 return; 207 } 208 if (keyType.equals(CipherSuite.KEY_TYPE_RSA) 209 || keyType.equals(CipherSuite.KEY_TYPE_DH_RSA)) { 210 if (checkForPrivateKey(keyType, RSAPrivateKey.class)) { 211 return; 212 } 213 continue; 214 } 215 if (keyType.equals(CipherSuite.KEY_TYPE_DSA) 216 || keyType.equals(CipherSuite.KEY_TYPE_DH_DSA)) { 217 if (checkForPrivateKey(keyType, DSAPrivateKey.class)) { 218 return; 219 } 220 continue; 221 } 222 if (keyType.equals(CipherSuite.KEY_TYPE_EC) 223 || keyType.equals(CipherSuite.KEY_TYPE_EC_RSA) 224 || keyType.equals(CipherSuite.KEY_TYPE_EC_EC)) { 225 if (checkForPrivateKey(keyType, ECPrivateKey.class)) { 226 return; 227 } 228 continue; 229 } 230 throw new IllegalStateException("Unknown key type " + keyType); 231 } 232 throw new SSLException("Could not find any key store entries " 233 + "to support the enabled cipher suites."); 234 } 235 236 private boolean checkForPrivateKey(String keyType, Class<?> keyClass) { 237 String alias = sslParameters.getKeyManager().chooseServerAlias(keyType, null, null); 238 if (alias == null) { 239 return false; 240 } 241 PrivateKey key = sslParameters.getKeyManager().getPrivateKey(alias); 242 return (key != null && keyClass.isAssignableFrom(key.getClass())); 243 } 244 } 245