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