OpenSSLServerSocketImpl.java revision 27e65e506369aa7eaca3e92a77631af63079ebd6
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.ByteArrayOutputStream; 20import java.io.IOException; 21import java.io.OutputStreamWriter; 22import java.net.InetAddress; 23import java.net.Socket; 24import java.security.PrivateKey; 25import java.security.cert.X509Certificate; 26import java.util.ArrayList; 27 28import org.bouncycastle.openssl.PEMWriter; 29 30/** 31 * OpenSSL-based implementation of server sockets. 32 * 33 * This class only supports SSLv3 and TLSv1. This should be documented elsewhere 34 * later, for example in the package.html or a separate reference document. 35 */ 36public class OpenSSLServerSocketImpl extends javax.net.ssl.SSLServerSocket { 37 private int ssl_ctx; 38 private boolean client_mode = true; 39 private long ssl_op_no = 0x00000000L; 40 private SSLParameters sslParameters; 41 private static final String[] supportedProtocols = new String[] { 42 "SSLv3", 43 "TLSv1" 44 }; 45 46 private native static void nativeinitstatic(); 47 48 static { 49 nativeinitstatic(); 50 } 51 52 private native void nativeinit(String privatekey, String certificate, byte[] seed); 53 54 /** 55 * Initialize the SSL server socket and set the certificates for the 56 * future handshaking. 57 */ 58 private void init() throws IOException { 59 String alias = sslParameters.getKeyManager().chooseServerAlias("RSA", null, null); 60 if (alias == null) { 61 throw new IOException("No suitable certificates found"); 62 } 63 64 PrivateKey privateKey = sslParameters.getKeyManager().getPrivateKey(alias); 65 X509Certificate[] certificates = sslParameters.getKeyManager().getCertificateChain(alias); 66 67 ByteArrayOutputStream privateKeyOS = new ByteArrayOutputStream(); 68 PEMWriter privateKeyPEMWriter = new PEMWriter(new OutputStreamWriter(privateKeyOS)); 69 privateKeyPEMWriter.writeObject(privateKey); 70 privateKeyPEMWriter.close(); 71 72 ByteArrayOutputStream certificateOS = new ByteArrayOutputStream(); 73 PEMWriter certificateWriter = new PEMWriter(new OutputStreamWriter(certificateOS)); 74 75 for (int i = 0; i < certificates.length; i++) { 76 certificateWriter.writeObject(certificates[i]); 77 } 78 certificateWriter.close(); 79 80 nativeinit(privateKeyOS.toString(), certificateOS.toString(), 81 sslParameters.getSecureRandomMember() != null ? 82 sslParameters.getSecureRandomMember().generateSeed(1024) : null); 83 } 84 85 protected OpenSSLServerSocketImpl(SSLParameters sslParameters) 86 throws IOException { 87 super(); 88 this.sslParameters = sslParameters; 89 init(); 90 } 91 92 protected OpenSSLServerSocketImpl(int port, SSLParameters sslParameters) 93 throws IOException { 94 super(port); 95 this.sslParameters = sslParameters; 96 init(); 97 } 98 99 protected OpenSSLServerSocketImpl(int port, int backlog, SSLParameters sslParameters) 100 throws IOException { 101 super(port, backlog); 102 this.sslParameters = sslParameters; 103 init(); 104 } 105 106 protected OpenSSLServerSocketImpl(int port, int backlog, InetAddress iAddress, SSLParameters sslParameters) 107 throws IOException { 108 super(port, backlog, iAddress); 109 this.sslParameters = sslParameters; 110 init(); 111 } 112 113 @Override 114 public boolean getEnableSessionCreation() { 115 return sslParameters.getEnableSessionCreation(); 116 } 117 118 @Override 119 public void setEnableSessionCreation(boolean flag) { 120 sslParameters.setEnableSessionCreation(flag); 121 } 122 123 /** 124 * The names of the protocols' versions that may be used on this SSL 125 * connection. 126 * @return an array of protocols names 127 */ 128 @Override 129 public String[] getSupportedProtocols() { 130 return supportedProtocols.clone(); 131 } 132 133 /** 134 * See the OpenSSL ssl.h header file for more information. 135 */ 136 static private long SSL_OP_NO_SSLv3 = 0x02000000L; 137 static private long SSL_OP_NO_TLSv1 = 0x04000000L; 138 139 /** 140 * The names of the protocols' versions that in use on this SSL connection. 141 * 142 * @return an array of protocols names 143 */ 144 @Override 145 public String[] getEnabledProtocols() { 146 ArrayList<String> array = new ArrayList<String>(); 147 148 if ((ssl_op_no & SSL_OP_NO_SSLv3) == 0x00000000L) { 149 array.add(supportedProtocols[0]); 150 } 151 if ((ssl_op_no & SSL_OP_NO_TLSv1) == 0x00000000L) { 152 array.add(supportedProtocols[1]); 153 } 154 return array.toArray(new String[array.size()]); 155 } 156 157 private native void nativesetenabledprotocols(long l); 158 159 /** 160 * This method enables the protocols' versions listed by 161 * getSupportedProtocols(). 162 * 163 * @param protocols names of all the protocols to enable. 164 * 165 * @throws IllegalArgumentException when one or more of the names in the 166 * array are not supported, or when the array is null. 167 */ 168 @Override 169 public void setEnabledProtocols(String[] protocols) { 170 if (protocols == null) { 171 throw new IllegalArgumentException("Provided parameter is null"); 172 } 173 174 ssl_op_no = SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1; 175 176 for (int i = 0; i < protocols.length; i++) { 177 if (protocols[i].equals("SSLv3")) 178 ssl_op_no ^= SSL_OP_NO_SSLv3; 179 else if (protocols[i].equals("TLSv1")) 180 ssl_op_no ^= SSL_OP_NO_TLSv1; 181 else throw new IllegalArgumentException("Protocol " + protocols[i] + 182 " is not supported."); 183 } 184 185 nativesetenabledprotocols(ssl_op_no); 186 } 187 188 /** 189 * Gets all available ciphers from the current OpenSSL library. 190 * Needed by OpenSSLServerSocketFactory too. 191 */ 192 static native String[] nativegetsupportedciphersuites(); 193 194 @Override 195 public String[] getSupportedCipherSuites() { 196 return nativegetsupportedciphersuites(); 197 } 198 199 /** 200 * Calls native OpenSSL functions to get the enabled ciphers. 201 */ 202 private native String[] nativegetenabledciphersuites(); 203 204 @Override 205 public String[] getEnabledCipherSuites() { 206 return nativegetenabledciphersuites(); 207 } 208 209 /** 210 * Calls the SSL_CTX_set_cipher_list(...) OpenSSL function with the passed 211 * char array. 212 */ 213 private native void nativesetenabledciphersuites(String controlString); 214 215 private boolean findSuite(String suite) { 216 String[] supportedCipherSuites = nativegetsupportedciphersuites(); 217 for(int i = 0; i < supportedCipherSuites.length; i++) 218 if (supportedCipherSuites[i].equals(suite)) return true; 219 throw new IllegalArgumentException("Protocol " + suite + 220 " is not supported."); 221 } 222 223 /** 224 * This method enables the cipher suites listed by 225 * getSupportedCipherSuites(). 226 * 227 * @param suites the names of all the cipher suites to enable 228 * @throws IllegalArgumentException when one or more of the ciphers in array 229 * suites are not supported, or when the array is null. 230 */ 231 @Override 232 public void setEnabledCipherSuites(String[] suites) { 233 if (suites == null) { 234 throw new IllegalArgumentException("Provided parameter is null"); 235 } 236 String controlString = ""; 237 for (int i = 0; i < suites.length; i++) { 238 findSuite(suites[i]); 239 if (i == 0) controlString = suites[i]; 240 else controlString += ":" + suites[i]; 241 } 242 nativesetenabledciphersuites(controlString); 243 } 244 245 /** 246 * See the OpenSSL ssl.h header file for more information. 247 */ 248 static private int SSL_VERIFY_NONE = 0x00; 249 static private int SSL_VERIFY_PEER = 0x01; 250 static private int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 0x02; 251 static private int SSL_VERIFY_CLIENT_ONCE = 0x04; 252 253 /** 254 * Calls the SSL_CTX_set_verify(...) OpenSSL function with the passed int 255 * value. 256 */ 257 private native void nativesetclientauth(int value); 258 259 private void setClientAuth() { 260 int value = SSL_VERIFY_NONE; 261 262 if (sslParameters.getNeedClientAuth()) { 263 value |= SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_CLIENT_ONCE; 264 } else if (sslParameters.getWantClientAuth()) { 265 value |= SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE; 266 } 267 268 nativesetclientauth(value); 269 } 270 271 @Override 272 public boolean getWantClientAuth() { 273 return sslParameters.getWantClientAuth(); 274 } 275 276 @Override 277 public void setWantClientAuth(boolean want) { 278 sslParameters.setWantClientAuth(want); 279 setClientAuth(); 280 } 281 282 @Override 283 public boolean getNeedClientAuth() { 284 return sslParameters.getNeedClientAuth(); 285 } 286 287 @Override 288 public void setNeedClientAuth(boolean need) { 289 sslParameters.setNeedClientAuth(need); 290 setClientAuth(); 291 } 292 293 @Override 294 public void setUseClientMode(boolean mode) { 295 sslParameters.setUseClientMode(mode); 296 } 297 298 @Override 299 public boolean getUseClientMode() { 300 return sslParameters.getUseClientMode(); 301 } 302 303 @Override 304 public Socket accept() throws IOException { 305 OpenSSLSocketImpl socket 306 = new OpenSSLSocketImpl(sslParameters, ssl_op_no); 307 implAccept(socket); 308 socket.accept(ssl_ctx, client_mode); 309 310 return socket; 311 } 312 313 /** 314 * Removes OpenSSL objects from memory. 315 */ 316 private native void nativefree(); 317 318 /** 319 * Unbinds the port if the socket is open. 320 */ 321 @Override 322 protected void finalize() throws Throwable { 323 if (!isClosed()) close(); 324 } 325 326 @Override 327 public synchronized void close() throws IOException { 328 nativefree(); 329 super.close(); 330 } 331} 332