OpenSSLServerSocketImpl.java revision 3e6dd45baa0d7f9b4fa06f4ade76e088b59cc7bf
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.ECPrivateKey; 24import java.security.interfaces.DSAPrivateKey; 25import java.security.interfaces.RSAPrivateKey; 26import javax.net.ssl.SSLException; 27 28/** 29 * OpenSSL-based implementation of server sockets. 30 */ 31public 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 String[] enabledCompressionMethods = NativeCrypto.getDefaultCompressionMethods(); 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 * This method enables the cipher suites listed by 118 * getSupportedCipherSuites(). 119 * 120 * @param suites the names of all the cipher suites to enable 121 * @throws IllegalArgumentException when one or more of the ciphers in array 122 * suites are not supported, or when the array is null. 123 */ 124 @Override 125 public void setEnabledCipherSuites(String[] suites) { 126 enabledCipherSuites = NativeCrypto.checkEnabledCipherSuites(suites); 127 } 128 129 public String[] getSupportedCompressionMethods() { 130 return NativeCrypto.getSupportedCompressionMethods(); 131 } 132 133 public String[] getEnabledCompressionMethods() { 134 return enabledCompressionMethods.clone(); 135 } 136 137 /** 138 * This method enables the compression methods listed by 139 * getSupportedCompressionMethods(). 140 * 141 * @param suites the names of all the compression methods to enable 142 * @throws IllegalArgumentException when one or more of the ciphers in array 143 * suites are not supported, or when the array is null. 144 */ 145 public void setEnabledCompressionMethods(String[] methods) { 146 enabledCompressionMethods = NativeCrypto.checkEnabledCompressionMethods(methods); 147 } 148 149 @Override 150 public boolean getWantClientAuth() { 151 return sslParameters.getWantClientAuth(); 152 } 153 154 @Override 155 public void setWantClientAuth(boolean want) { 156 sslParameters.setWantClientAuth(want); 157 } 158 159 @Override 160 public boolean getNeedClientAuth() { 161 return sslParameters.getNeedClientAuth(); 162 } 163 164 @Override 165 public void setNeedClientAuth(boolean need) { 166 sslParameters.setNeedClientAuth(need); 167 } 168 169 @Override 170 public void setUseClientMode(boolean mode) { 171 sslParameters.setUseClientMode(mode); 172 } 173 174 @Override 175 public boolean getUseClientMode() { 176 return sslParameters.getUseClientMode(); 177 } 178 179 @Override 180 public Socket accept() throws IOException { 181 182 if (!sslParameters.getUseClientMode()) { 183 checkEnabledCipherSuites(); 184 } 185 186 OpenSSLSocketImpl socket = new OpenSSLSocketImpl(sslParameters, 187 enabledProtocols.clone(), 188 enabledCipherSuites.clone(), 189 enabledCompressionMethods.clone()); 190 implAccept(socket); 191 return socket; 192 } 193 194 /** 195 * Check if any of the enabled cipher suites has a chance to work. 196 * Not 100% accurate, just a useful diagnostic that the RI does. 197 */ 198 private void checkEnabledCipherSuites() throws SSLException { 199 /* Loop over all enabled cipher suites. If we find a problem, 200 * we just continue to the next one. If we find one that could 201 * work, we return. This basically makes sure the caller has 202 * configured some appropriate certificate/key unless 203 * an anonymous cipher is picked. 204 */ 205 for (String enabledCipherSuite : enabledCipherSuites) { 206 if (enabledCipherSuite.equals(NativeCrypto.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) { 207 continue; 208 } 209 String keyType = CipherSuite.getByName(enabledCipherSuite).getServerKeyType(); 210 if (keyType == null) { 211 // anonymous always work 212 return; 213 } 214 if (keyType.equals(CipherSuite.KEY_TYPE_RSA) 215 || keyType.equals(CipherSuite.KEY_TYPE_DH_RSA)) { 216 if (checkForPrivateKey(keyType, RSAPrivateKey.class)) { 217 return; 218 } 219 continue; 220 } 221 if (keyType.equals(CipherSuite.KEY_TYPE_DSA) 222 || keyType.equals(CipherSuite.KEY_TYPE_DH_DSA)) { 223 if (checkForPrivateKey(keyType, DSAPrivateKey.class)) { 224 return; 225 } 226 continue; 227 } 228 if (keyType.equals(CipherSuite.KEY_TYPE_EC) 229 || keyType.equals(CipherSuite.KEY_TYPE_EC_RSA) 230 || keyType.equals(CipherSuite.KEY_TYPE_EC_EC)) { 231 if (checkForPrivateKey(keyType, ECPrivateKey.class)) { 232 return; 233 } 234 continue; 235 } 236 throw new IllegalStateException("Unknown key type " + keyType); 237 } 238 throw new SSLException("Could not find any key store entries " 239 + "to support the enabled cipher suites."); 240 } 241 242 private boolean checkForPrivateKey(String keyType, Class keyClass) { 243 String alias = sslParameters.getKeyManager().chooseServerAlias(keyType, null, null); 244 if (alias == null) { 245 return false; 246 } 247 PrivateKey key = sslParameters.getKeyManager().getPrivateKey(alias); 248 return (key != null && keyClass.isAssignableFrom(key.getClass())); 249 } 250} 251