OpenSSLServerSocketImpl.java revision 4559b1d37edcb5d7f1da086cf2e3290388d74f46
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 17package org.apache.harmony.xnet.provider.jsse; 18 19import java.io.IOException; 20import java.net.InetAddress; 21import java.net.Socket; 22import java.security.PrivateKey; 23import java.security.interfaces.DSAPrivateKey; 24import java.security.interfaces.RSAPrivateKey; 25import javax.net.ssl.SSLException; 26 27/** 28 * OpenSSL-based implementation of server sockets. 29 * 30 * This class only supports SSLv3 and TLSv1. This should be documented elsewhere 31 * later, for example in the package.html or a separate reference document. 32 */ 33public class OpenSSLServerSocketImpl extends javax.net.ssl.SSLServerSocket { 34 private final SSLParameters sslParameters; 35 private String[] enabledProtocols = NativeCrypto.getSupportedProtocols(); 36 private String[] enabledCipherSuites = NativeCrypto.getDefaultCipherSuites(); 37 private String[] enabledCompressionMethods = NativeCrypto.getDefaultCompressionMethods(); 38 39 protected OpenSSLServerSocketImpl(SSLParameters sslParameters) 40 throws IOException { 41 super(); 42 this.sslParameters = sslParameters; 43 } 44 45 protected OpenSSLServerSocketImpl(int port, SSLParameters sslParameters) 46 throws IOException { 47 super(port); 48 this.sslParameters = sslParameters; 49 } 50 51 protected OpenSSLServerSocketImpl(int port, int backlog, SSLParameters sslParameters) 52 throws IOException { 53 super(port, backlog); 54 this.sslParameters = sslParameters; 55 } 56 57 protected OpenSSLServerSocketImpl(int port, 58 int backlog, 59 InetAddress iAddress, 60 SSLParameters sslParameters) 61 throws IOException { 62 super(port, backlog, iAddress); 63 this.sslParameters = sslParameters; 64 } 65 66 @Override 67 public boolean getEnableSessionCreation() { 68 return sslParameters.getEnableSessionCreation(); 69 } 70 71 @Override 72 public void setEnableSessionCreation(boolean flag) { 73 sslParameters.setEnableSessionCreation(flag); 74 } 75 76 /** 77 * The names of the protocols' versions that may be used on this SSL 78 * connection. 79 * @return an array of protocols names 80 */ 81 @Override 82 public String[] getSupportedProtocols() { 83 return NativeCrypto.getSupportedProtocols(); 84 } 85 86 /** 87 * The names of the protocols' versions that in use on this SSL connection. 88 * 89 * @return an array of protocols names 90 */ 91 @Override 92 public String[] getEnabledProtocols() { 93 return enabledProtocols.clone(); 94 } 95 96 /** 97 * This method enables the protocols' versions listed by 98 * getSupportedProtocols(). 99 * 100 * @param protocols names of all the protocols to enable. 101 * 102 * @throws IllegalArgumentException when one or more of the names in the 103 * array are not supported, or when the array is null. 104 */ 105 @Override 106 public void setEnabledProtocols(String[] protocols) { 107 enabledProtocols = NativeCrypto.checkEnabledProtocols(protocols); 108 } 109 110 @Override 111 public String[] getSupportedCipherSuites() { 112 return NativeCrypto.getSupportedCipherSuites(); 113 } 114 115 @Override 116 public String[] getEnabledCipherSuites() { 117 return enabledCipherSuites.clone(); 118 } 119 120 /** 121 * This method enables the cipher suites listed by 122 * getSupportedCipherSuites(). 123 * 124 * @param suites the names of all the cipher suites to enable 125 * @throws IllegalArgumentException when one or more of the ciphers in array 126 * suites are not supported, or when the array is null. 127 */ 128 @Override 129 public void setEnabledCipherSuites(String[] suites) { 130 enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites); 131 } 132 133 public String[] getSupportedCompressionMethods() { 134 return NativeCrypto.getSupportedCompressionMethods(); 135 } 136 137 public String[] getEnabledCompressionMethods() { 138 return enabledCompressionMethods.clone(); 139 } 140 141 /** 142 * This method enables the compression methods listed by 143 * getSupportedCompressionMethods(). 144 * 145 * @param suites the names of all the compression methods to enable 146 * @throws IllegalArgumentException when one or more of the ciphers in array 147 * suites are not supported, or when the array is null. 148 */ 149 public void setEnabledCompressionMethods(String[] methods) { 150 enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods); 151 } 152 153 @Override 154 public boolean getWantClientAuth() { 155 return sslParameters.getWantClientAuth(); 156 } 157 158 @Override 159 public void setWantClientAuth(boolean want) { 160 sslParameters.setWantClientAuth(want); 161 } 162 163 @Override 164 public boolean getNeedClientAuth() { 165 return sslParameters.getNeedClientAuth(); 166 } 167 168 @Override 169 public void setNeedClientAuth(boolean need) { 170 sslParameters.setNeedClientAuth(need); 171 } 172 173 @Override 174 public void setUseClientMode(boolean mode) { 175 sslParameters.setUseClientMode(mode); 176 } 177 178 @Override 179 public boolean getUseClientMode() { 180 return sslParameters.getUseClientMode(); 181 } 182 183 @Override 184 public Socket accept() throws IOException { 185 186 if (!sslParameters.getUseClientMode()) { 187 checkEnabledCipherSuites(); 188 } 189 190 OpenSSLSocketImpl socket = new OpenSSLSocketImpl(sslParameters, 191 enabledProtocols.clone(), 192 enabledCipherSuites.clone(), 193 enabledCompressionMethods.clone()); 194 implAccept(socket); 195 return socket; 196 } 197 198 /** 199 * Check if any of the enabled cipher suites has a chance to work. 200 * Not 100% accurate, just a useful diagnostic that the RI does. 201 */ 202 private void checkEnabledCipherSuites() throws SSLException { 203 /* Loop over all enabled cipher suites. If we find a problem, 204 * we just continue to the next one. If we find one that could 205 * work, we return. This basically makes sure the caller has 206 * configured some appropriate certificate/key unless 207 * an anonymous cipher is picked. 208 */ 209 for (String enabledCipherSuite : enabledCipherSuites) { 210 CipherSuite cipherSuite = CipherSuite.getByName(enabledCipherSuite); 211 212 int keyExchange; 213 if (cipherSuite == null) { 214 // An NativeCrypto cipher suite unknown to the Java 215 // implementation, use some safe heuristics 216 if (enabledCipherSuite.contains("_RSA_")) { 217 keyExchange = CipherSuite.KEY_EXCHANGE_RSA; 218 } else if (enabledCipherSuite.contains("_DSS_")) { 219 keyExchange = CipherSuite.KEY_EXCHANGE_DH_DSS; 220 } else if (enabledCipherSuite.contains("_anon_")) { 221 keyExchange = CipherSuite.KEY_EXCHANGE_DH_anon; 222 } else { 223 keyExchange = -1; 224 } 225 } else { 226 keyExchange = cipherSuite.keyExchange; 227 } 228 229 switch (keyExchange) { 230 case CipherSuite.KEY_EXCHANGE_DHE_RSA: 231 case CipherSuite.KEY_EXCHANGE_DHE_RSA_EXPORT: 232 case CipherSuite.KEY_EXCHANGE_DH_RSA: 233 case CipherSuite.KEY_EXCHANGE_DH_RSA_EXPORT: 234 case CipherSuite.KEY_EXCHANGE_RSA: 235 case CipherSuite.KEY_EXCHANGE_RSA_EXPORT: 236 if (checkForPrivateKey("RSA", RSAPrivateKey.class)) { 237 return; 238 } 239 continue; 240 241 case CipherSuite.KEY_EXCHANGE_DHE_DSS: 242 case CipherSuite.KEY_EXCHANGE_DHE_DSS_EXPORT: 243 case CipherSuite.KEY_EXCHANGE_DH_DSS: 244 case CipherSuite.KEY_EXCHANGE_DH_DSS_EXPORT: 245 if (checkForPrivateKey("DSA", DSAPrivateKey.class)) { 246 return; 247 } 248 continue; 249 250 case CipherSuite.KEY_EXCHANGE_DH_anon: 251 case CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT: 252 // anonymous always works 253 return; 254 default: 255 // unknown, just assume it will work 256 return; 257 } 258 } 259 throw new SSLException("Could not find any key store entries " 260 + "to support the enabled cipher suites."); 261 } 262 263 private boolean checkForPrivateKey(String keyType, Class keyClass) { 264 String alias = sslParameters.getKeyManager().chooseServerAlias(keyType, null, null); 265 if (alias == null) { 266 return false; 267 } 268 PrivateKey key = sslParameters.getKeyManager().getPrivateKey(alias); 269 return (key != null && keyClass.isAssignableFrom(key.getClass())); 270 } 271} 272