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 @Override 200 public String[] getEnabledCipherSuites() { 201 return OpenSSLSocketImpl.nativeGetEnabledCipherSuites(ssl_ctx); 202 } 203 204 /** 205 * This method enables the cipher suites listed by 206 * getSupportedCipherSuites(). 207 * 208 * @param suites the names of all the cipher suites to enable 209 * @throws IllegalArgumentException when one or more of the ciphers in array 210 * suites are not supported, or when the array is null. 211 */ 212 @Override 213 public void setEnabledCipherSuites(String[] suites) { 214 OpenSSLSocketImpl.setEnabledCipherSuites(ssl_ctx, suites); 215 } 216 217 /** 218 * See the OpenSSL ssl.h header file for more information. 219 */ 220 static private int SSL_VERIFY_NONE = 0x00; 221 static private int SSL_VERIFY_PEER = 0x01; 222 static private int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 0x02; 223 static private int SSL_VERIFY_CLIENT_ONCE = 0x04; 224 225 /** 226 * Calls the SSL_CTX_set_verify(...) OpenSSL function with the passed int 227 * value. 228 */ 229 private native void nativesetclientauth(int value); 230 231 private void setClientAuth() { 232 int value = SSL_VERIFY_NONE; 233 234 if (sslParameters.getNeedClientAuth()) { 235 value |= SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_CLIENT_ONCE; 236 } else if (sslParameters.getWantClientAuth()) { 237 value |= SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE; 238 } 239 240 nativesetclientauth(value); 241 } 242 243 @Override 244 public boolean getWantClientAuth() { 245 return sslParameters.getWantClientAuth(); 246 } 247 248 @Override 249 public void setWantClientAuth(boolean want) { 250 sslParameters.setWantClientAuth(want); 251 setClientAuth(); 252 } 253 254 @Override 255 public boolean getNeedClientAuth() { 256 return sslParameters.getNeedClientAuth(); 257 } 258 259 @Override 260 public void setNeedClientAuth(boolean need) { 261 sslParameters.setNeedClientAuth(need); 262 setClientAuth(); 263 } 264 265 @Override 266 public void setUseClientMode(boolean mode) { 267 sslParameters.setUseClientMode(mode); 268 } 269 270 @Override 271 public boolean getUseClientMode() { 272 return sslParameters.getUseClientMode(); 273 } 274 275 @Override 276 public Socket accept() throws IOException { 277 OpenSSLSocketImpl socket 278 = new OpenSSLSocketImpl(sslParameters, ssl_op_no); 279 implAccept(socket); 280 socket.accept(ssl_ctx, client_mode); 281 282 return socket; 283 } 284 285 /** 286 * Removes OpenSSL objects from memory. 287 */ 288 private native void nativefree(); 289 290 /** 291 * Unbinds the port if the socket is open. 292 */ 293 @Override 294 protected void finalize() throws Throwable { 295 if (!isClosed()) close(); 296 } 297 298 @Override 299 public synchronized void close() throws IOException { 300 nativefree(); 301 super.close(); 302 } 303} 304