1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package org.apache.harmony.xnet.provider.jsse;
19
20import org.apache.harmony.xnet.provider.jsse.SSLv3Constants;
21import org.apache.harmony.xnet.provider.jsse.SSLSessionImpl;
22import org.apache.harmony.xnet.provider.jsse.ProtocolVersion;
23
24import java.io.IOException;
25import java.math.BigInteger;
26import java.security.AccessController;
27import java.security.KeyFactory;
28import java.security.KeyPair;
29import java.security.KeyPairGenerator;
30import java.security.NoSuchAlgorithmException;
31import java.security.PrivateKey;
32import java.security.PrivilegedExceptionAction;
33import java.security.PublicKey;
34import java.security.cert.CertificateException;
35import java.security.cert.X509Certificate;
36import java.security.interfaces.RSAPublicKey;
37
38import java.util.Arrays;
39
40import javax.crypto.Cipher;
41import javax.crypto.KeyAgreement;
42import javax.crypto.interfaces.DHPublicKey;
43import javax.crypto.spec.DHParameterSpec;
44import javax.crypto.spec.DHPublicKeySpec;
45import javax.net.ssl.X509ExtendedKeyManager;
46import javax.net.ssl.X509KeyManager;
47import javax.net.ssl.X509TrustManager;
48
49/**
50 * Server side handshake protocol implementation.
51 * Handshake protocol operates on top of the Record Protocol.
52 * It responsible for negotiating a session.
53 *
54 * The implementation processes inbound client handshake messages,
55 * creates and sends respond messages. Outbound messages are supplied
56 * to Record Protocol. Detected errors are reported to the Alert protocol.
57 *
58 * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.
59 * Handshake protocol.</a>
60 *
61 */
62public class ServerHandshakeImpl extends HandshakeProtocol {
63
64    // private key used in key exchange
65    private PrivateKey privKey;
66
67    /**
68     * Creates Server Handshake Implementation
69     *
70     * @param owner
71     */
72    public ServerHandshakeImpl(Object owner) {
73        super(owner);
74        status = NEED_UNWRAP;
75    }
76
77    /**
78     * Start session negotiation
79     */
80    @Override
81    public void start() {
82        if (session == null) { // initial handshake
83            status = NEED_UNWRAP;
84            return; // wait client hello
85        }
86        if (clientHello != null && this.status != FINISHED) {
87            // current negotiation has not completed
88            return; // ignore
89        }
90
91        // renegotiation
92        sendHelloRequest();
93        status = NEED_UNWRAP;
94    }
95
96    /**
97     * Proceses inbound handshake messages
98     * @param bytes
99     */
100    @Override
101    public void unwrap(byte[] bytes) {
102
103        io_stream.append(bytes);
104        while (io_stream.available() > 0) {
105            int handshakeType;
106            int length;
107            io_stream.mark();
108            try {
109                handshakeType = io_stream.read();
110                length = io_stream.readUint24();
111                if (io_stream.available() < length) {
112                    io_stream.reset();
113                    return;
114                }
115
116                switch (handshakeType) {
117                case 1: // CLIENT_HELLO
118                    if (clientHello != null && this.status != FINISHED) {
119                            // Client hello has been received during handshake
120                            unexpectedMessage();
121                            return;
122                    }
123                    // if protocol planed to send Hello Request message
124                    // - cancel this demand.
125                    needSendHelloRequest = false;
126                    clientHello = new ClientHello(io_stream, length);
127                    if (nonBlocking) {
128                        delegatedTasks.add(new DelegatedTask(new PrivilegedExceptionAction<Void>() {
129                            public Void run() throws Exception {
130                                processClientHello();
131                                return null;
132                            }
133                        }, this, AccessController.getContext()));
134                        return;
135                    }
136                    processClientHello();
137                    break;
138
139                case 11: //    CLIENT CERTIFICATE
140                    if (isResuming || certificateRequest == null
141                            || serverHelloDone == null || clientCert != null) {
142                        unexpectedMessage();
143                        return;
144                    }
145                    clientCert = new CertificateMessage(io_stream, length);
146                    if (clientCert.certs.length == 0) {
147                        if (parameters.getNeedClientAuth()) {
148                            fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
149                                    "HANDSHAKE FAILURE: no client certificate received");
150                        }
151                    } else {
152                        String authType = clientCert.certs[0].getPublicKey()
153                                .getAlgorithm();
154                        try {
155                            parameters.getTrustManager().checkClientTrusted(
156                                    clientCert.certs, authType);
157                        } catch (CertificateException e) {
158                            fatalAlert(AlertProtocol.BAD_CERTIFICATE,
159                                    "Untrusted Client Certificate ", e);
160                        }
161                        session.peerCertificates = clientCert.certs;
162                    }
163                    break;
164
165                case 15: // CERTIFICATE_VERIFY
166                    if (isResuming
167                            || clientKeyExchange == null
168                            || clientCert == null
169                            || clientKeyExchange.isEmpty() //client certificate
170                                                           // contains fixed DH
171                                                           // parameters
172                            || certificateVerify != null
173                            || changeCipherSpecReceived) {
174                        unexpectedMessage();
175                        return;
176                    }
177                    certificateVerify = new CertificateVerify(io_stream, length);
178
179                    DigitalSignature ds = new DigitalSignature(session.cipherSuite.keyExchange);
180                    ds.init(serverCert.certs[0]);
181                    byte[] md5_hash = null;
182                    byte[] sha_hash = null;
183
184                    if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT
185                            || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA
186                            || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_RSA
187                            || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
188                        md5_hash = io_stream.getDigestMD5withoutLast();
189                        sha_hash = io_stream.getDigestSHAwithoutLast();
190                    } else if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_DSS
191                            || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
192                        sha_hash = io_stream.getDigestSHAwithoutLast();
193                    } else if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon
194                            || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_DH_anon_EXPORT) {
195                    }
196                    ds.setMD5(md5_hash);
197                    ds.setSHA(sha_hash);
198                    if (!ds.verifySignature(certificateVerify.signedHash)) {
199                        fatalAlert(AlertProtocol.DECRYPT_ERROR,
200                                "DECRYPT ERROR: CERTIFICATE_VERIFY incorrect signature");
201                    }
202                    break;
203                case 16: // CLIENT_KEY_EXCHANGE
204                    if (isResuming
205                            || serverHelloDone == null
206                            || clientKeyExchange != null
207                            || (clientCert == null && parameters
208                                    .getNeedClientAuth())) {
209                        unexpectedMessage();
210                        return;
211                    }
212                    if (session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA
213                            || session.cipherSuite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT) {
214                        clientKeyExchange = new ClientKeyExchange(io_stream,
215                                length, serverHello.server_version[1] == 1,
216                                true);
217                        Cipher c = null;
218                        try {
219                            c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
220                            c.init(Cipher.DECRYPT_MODE, privKey);
221                            preMasterSecret = c
222                                    .doFinal(clientKeyExchange.exchange_keys);
223                            // check preMasterSecret:
224                            if (preMasterSecret.length != 48
225                                    || preMasterSecret[0] != clientHello.client_version[0]
226                                    || preMasterSecret[1] != clientHello.client_version[1]) {
227                                // incorrect preMasterSecret
228                                // prevent an attack (see TLS 1.0 spec., 7.4.7.1.)
229                                preMasterSecret = new byte[48];
230                                parameters.getSecureRandom().nextBytes(
231                                        preMasterSecret);
232                            }
233                        } catch (Exception e) {
234                            fatalAlert(AlertProtocol.INTERNAL_ERROR,
235                                    "INTERNAL ERROR", e);
236                        }
237                    } else { // diffie hellman key exchange
238                        clientKeyExchange = new ClientKeyExchange(io_stream,
239                                length, serverHello.server_version[1] == 1,
240                                false);
241                        if (clientKeyExchange.isEmpty()) {
242                            // TODO check that client cert. DH params
243                            // matched server cert. DH params
244
245                            // client cert. contains fixed DH parameters
246                            preMasterSecret = ((DHPublicKey) clientCert.certs[0]
247                                    .getPublicKey()).getY().toByteArray();
248                        } else {
249                            PublicKey clientPublic;
250                            KeyAgreement agreement;
251                            try {
252                                KeyFactory kf = null;
253                                try {
254                                    kf = KeyFactory.getInstance("DH");
255                                } catch (NoSuchAlgorithmException ee) {
256                                    kf = KeyFactory
257                                            .getInstance("DiffieHellman");
258                                }
259                                try {
260                                    agreement = KeyAgreement.getInstance("DH");
261                                } catch (NoSuchAlgorithmException ee) {
262                                    agreement = KeyAgreement
263                                            .getInstance("DiffieHellman");
264                                }
265                                clientPublic = kf
266                                        .generatePublic(new DHPublicKeySpec(
267                                                new BigInteger(
268                                                        1,
269                                                        clientKeyExchange.exchange_keys),
270                                                serverKeyExchange.par1,
271                                                serverKeyExchange.par2));
272                                agreement.init(privKey);
273                                agreement.doPhase(clientPublic, true);
274                                preMasterSecret = agreement.generateSecret();
275                            } catch (Exception e) {
276                                fatalAlert(AlertProtocol.INTERNAL_ERROR,
277                                        "INTERNAL ERROR", e);
278                                return;
279                            }
280                        }
281                    }
282
283                    computerMasterSecret();
284                    break;
285
286                case 20: // FINISHED
287                    if (!isResuming && !changeCipherSpecReceived) {
288                        unexpectedMessage();
289                        return;
290                    }
291
292                    clientFinished = new Finished(io_stream, length);
293                    verifyFinished(clientFinished.getData());
294                    // BEGIN android-added
295                    session.context = parameters.getServerSessionContext();
296                    // END android-added
297                    parameters.getServerSessionContext().putSession(session);
298                    if (!isResuming) {
299                        sendChangeCipherSpec();
300                    } else {
301                        session.lastAccessedTime = System.currentTimeMillis();
302                        status = FINISHED;
303                    }
304                    break;
305                default:
306                    unexpectedMessage();
307                    return;
308                }
309            } catch (IOException e) {
310                // io stream dosn't contain complete handshake message
311                io_stream.reset();
312                return;
313            }
314        }
315    }
316    /**
317     * Processes SSLv2 Hello message
318     * @ see TLS 1.0 spec., E.1. Version 2 client hello
319     * @param bytes
320     */
321    @Override
322    public void unwrapSSLv2(byte[] bytes) {
323        io_stream.append(bytes);
324        io_stream.mark();
325        try {
326            clientHello = new ClientHello(io_stream);
327        } catch (IOException e) {
328            io_stream.reset();
329            return;
330        }
331        if (nonBlocking) {
332            delegatedTasks.add(new DelegatedTask(
333                    new PrivilegedExceptionAction<Void>() {
334                        public Void run() throws Exception {
335                            processClientHello();
336                            return null;
337                        }
338                    }, this, AccessController.getContext()));
339            return;
340        }
341        processClientHello();
342    }
343
344    /**
345     *
346     * Processes Client Hello message.
347     * Server responds to client hello message with server hello
348     * and (if necessary) server certificate, server key exchange,
349     * certificate request, and server hello done messages.
350     */
351    void processClientHello() {
352        CipherSuite cipher_suite;
353
354        // check that clientHello contains CompressionMethod.null
355        checkCompression: {
356            for (int i = 0; i < clientHello.compression_methods.length; i++) {
357                if (clientHello.compression_methods[i] == 0) {
358                    break checkCompression;
359                }
360            }
361            fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
362                    "HANDSHAKE FAILURE. Incorrect client hello message");
363        }
364
365        if (!ProtocolVersion.isSupported(clientHello.client_version)) {
366            fatalAlert(AlertProtocol.PROTOCOL_VERSION,
367                    "PROTOCOL VERSION. Unsupported client version "
368                    + clientHello.client_version[0]
369                    + clientHello.client_version[1]);
370        }
371
372        isResuming = false;
373        FIND: if (clientHello.session_id.length != 0) {
374            // client wishes to reuse session
375
376            SSLSessionImpl sessionToResume;
377            boolean reuseCurrent = false;
378
379            // reuse current session
380            if (session != null
381                    && Arrays.equals(session.id, clientHello.session_id)) {
382                if (session.isValid()) {
383                    isResuming = true;
384                    break FIND;
385                }
386                reuseCurrent = true;
387            }
388
389            // find session in cash
390            sessionToResume = findSessionToResume(clientHello.session_id);
391            if (sessionToResume == null || !sessionToResume.isValid()) {
392                if (!parameters.getEnableSessionCreation()) {
393                    if (reuseCurrent) {
394                        // we can continue current session
395                        sendWarningAlert(AlertProtocol.NO_RENEGOTIATION);
396                        status = NOT_HANDSHAKING;
397                        clearMessages();
398                        return;
399                    }
400                    // throw AlertException
401                    fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "SSL Session may not be created");
402                }
403                session = null;
404            } else {
405                session = (SSLSessionImpl)sessionToResume.clone();
406                isResuming = true;
407            }
408        }
409
410        if (isResuming) {
411            cipher_suite = session.cipherSuite;
412            // clientHello.cipher_suites must include at least cipher_suite from the session
413            checkCipherSuite: {
414                for (int i = 0; i < clientHello.cipher_suites.length; i++) {
415                    if (cipher_suite.equals(clientHello.cipher_suites[i])) {
416                        break checkCipherSuite;
417                    }
418                }
419                fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
420                        "HANDSHAKE FAILURE. Incorrect client hello message");
421            }
422        } else {
423            cipher_suite = selectSuite(clientHello.cipher_suites);
424            if (cipher_suite == null) {
425                fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "HANDSHAKE FAILURE. NO COMMON SUITE");
426            }
427            if (!parameters.getEnableSessionCreation()) {
428                fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
429                        "SSL Session may not be created");
430            }
431            session = new SSLSessionImpl(cipher_suite, parameters.getSecureRandom());
432            session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort());
433        }
434
435        recordProtocol.setVersion(clientHello.client_version);
436        session.protocol = ProtocolVersion.getByVersion(clientHello.client_version);
437        session.clientRandom = clientHello.random;
438
439        // create server hello message
440        serverHello = new ServerHello(parameters.getSecureRandom(),
441                clientHello.client_version,
442                session.getId(), cipher_suite, (byte) 0); //CompressionMethod.null
443        session.serverRandom = serverHello.random;
444        send(serverHello);
445        if (isResuming) {
446            sendChangeCipherSpec();
447            return;
448        }
449
450        //    create and send server certificate message if needed
451        if (!cipher_suite.isAnonymous()) { // need to send server certificate
452            X509Certificate[] certs = null;
453            String certType = null;
454            if (cipher_suite.keyExchange == CipherSuite.KeyExchange_RSA
455                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT
456                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_RSA
457                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_RSA_EXPORT) {
458                certType = "RSA";
459            } else if (cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_DSS
460                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_DSS_EXPORT) {
461                certType = "DSA";
462            } else if (cipher_suite.keyExchange == CipherSuite.KeyExchange_DH_DSS) {
463                certType = "DH_DSA";
464            } else if (cipher_suite.keyExchange == CipherSuite.KeyExchange_DH_RSA) {
465                certType = "DH_RSA";
466            }
467            // obtain certificates from key manager
468            String alias = null;
469            X509KeyManager km = parameters.getKeyManager();
470            if (km instanceof X509ExtendedKeyManager) {
471                X509ExtendedKeyManager ekm = (X509ExtendedKeyManager)km;
472                // BEGIN android-removed
473                // if (this.socketOwner != null) {
474                //     alias = ekm.chooseServerAlias(certType, null,
475                //             this.socketOwner);
476                // } else {
477                // END android-removed
478                    alias = ekm.chooseEngineServerAlias(certType, null,
479                            this.engineOwner);
480                // BEGIN android-removed
481                // }
482                // END android-removed
483                if (alias != null) {
484                    certs = ekm.getCertificateChain(alias);
485                }
486            } else {
487                // BEGIN android-removed
488                // alias = km.chooseServerAlias(certType, null, this.socketOwner);
489                // if (alias != null) {
490                // END android-removed
491                    certs = km.getCertificateChain(alias);
492                // BEGIN android-removed
493                // }
494                // END android-removed
495            }
496
497            if (certs == null) {
498                fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "NO SERVER CERTIFICATE FOUND");
499                return;
500            }
501            session.localCertificates = certs;
502            serverCert = new CertificateMessage(certs);
503            privKey = parameters.getKeyManager().getPrivateKey(alias);
504            send(serverCert);
505        }
506
507        // create and send server key exchange message if needed
508        RSAPublicKey rsakey = null;
509        DHPublicKeySpec dhkeySpec = null;
510        byte[] hash = null;
511        BigInteger p = null;
512        BigInteger g = null;
513
514        KeyPairGenerator kpg = null;
515
516        try {
517            if (cipher_suite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT) {
518                PublicKey pk = serverCert.certs[0].getPublicKey();
519                if (getRSAKeyLength(pk) > 512) {
520                    // key is longer than 512 bits
521                    kpg = KeyPairGenerator.getInstance("RSA");
522                    kpg.initialize(512);
523                }
524            } else if (cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_DSS
525                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_DSS_EXPORT
526                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_RSA
527                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DHE_RSA_EXPORT
528                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DH_anon
529                    || cipher_suite.keyExchange == CipherSuite.KeyExchange_DH_anon_EXPORT) {
530                try {
531                    kpg = KeyPairGenerator.getInstance("DH");
532                } catch (NoSuchAlgorithmException ee) {
533                    kpg = KeyPairGenerator.getInstance("DiffieHellman");
534                }
535                p = new BigInteger(1, DHParameters.getPrime());
536                g = new BigInteger("2");
537                DHParameterSpec spec = new DHParameterSpec(p, g);
538                kpg.initialize(spec);
539            }
540        } catch (Exception e) {
541            fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e);
542        }
543
544        if (kpg != null) {
545            // need to send server key exchange message
546            DigitalSignature ds = new DigitalSignature(cipher_suite.keyExchange);
547            KeyPair kp = null;
548            try {
549                kp = kpg.genKeyPair();
550                if (cipher_suite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT) {
551                    rsakey = (RSAPublicKey) kp.getPublic();
552                } else {
553                    DHPublicKey dhkey = (DHPublicKey) kp.getPublic();
554                    KeyFactory kf = null;
555                    try {
556                        kf = KeyFactory.getInstance("DH");
557                    } catch (NoSuchAlgorithmException e) {
558                            kf = KeyFactory.getInstance("DiffieHellman");
559                    }
560                    dhkeySpec = kf.getKeySpec(dhkey,
561                            DHPublicKeySpec.class);
562                }
563                if (!cipher_suite.isAnonymous()) { // calculate signed_params
564
565                    // init by private key which correspond to
566                    // server certificate
567                    ds.init(privKey);
568
569                    // use emphemeral key for key exchange
570                    privKey = kp.getPrivate();
571                    ds.update(clientHello.getRandom());
572                    ds.update(serverHello.getRandom());
573
574                    byte[] tmp;
575                    byte[] tmpLength = new byte[2];
576//FIXME 1_byte==0x00
577                    if (cipher_suite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT) {
578                        tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getModulus());
579                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
580                        tmpLength[1] = (byte) (tmp.length & 0xFF);
581                        ds.update(tmpLength);
582                        ds.update(tmp);
583                        tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getPublicExponent());
584                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
585                        tmpLength[1] = (byte) (tmp.length & 0xFF);
586                        ds.update(tmpLength);
587                        ds.update(tmp);
588                    } else {
589                        tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getP());
590                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
591                        tmpLength[1] = (byte) (tmp.length & 0xFF);
592                        ds.update(tmpLength);
593                        ds.update(tmp);
594                        tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getG());
595                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
596                        tmpLength[1] = (byte) (tmp.length & 0xFF);
597                        ds.update(tmpLength);
598                        ds.update(tmp);
599                        tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getY());
600                        tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
601                        tmpLength[1] = (byte) (tmp.length & 0xFF);
602                        ds.update(tmpLength);
603                        ds.update(tmp);
604                    }
605                    hash = ds.sign();
606                } else {
607                    privKey = kp.getPrivate(); // use emphemeral key for key exchange
608                }
609            } catch (Exception e) {
610                fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e);
611            }
612
613            if (cipher_suite.keyExchange == CipherSuite.KeyExchange_RSA_EXPORT) {
614                serverKeyExchange = new ServerKeyExchange(rsakey.getModulus(),
615                        rsakey.getPublicExponent(), null, hash);
616            } else {
617                serverKeyExchange = new ServerKeyExchange(p,
618                        g, dhkeySpec.getY(), hash);
619            }
620            send(serverKeyExchange);
621        }
622
623        // CERTIFICATE_REQUEST
624        certRequest: if (parameters.getWantClientAuth()
625                || parameters.getNeedClientAuth()) {
626            X509Certificate[] accepted;
627            try {
628                X509TrustManager tm = parameters.getTrustManager();
629                accepted = tm.getAcceptedIssuers();
630            } catch (ClassCastException e) {
631                // don't send certificateRequest
632                break certRequest;
633            }
634            byte[] requestedClientCertTypes = {1, 2}; // rsa sign, dsa sign
635            certificateRequest = new CertificateRequest(
636                    requestedClientCertTypes, accepted);
637            send(certificateRequest);
638        }
639
640        // SERVER_HELLO_DONE
641        serverHelloDone = new ServerHelloDone();
642        send(serverHelloDone);
643        status = NEED_UNWRAP;
644    }
645
646    /**
647     * Creates and sends finished message
648     */
649    @Override
650    protected void makeFinished() {
651        byte[] verify_data;
652        boolean isTLS = (serverHello.server_version[1] == 1); // TLS 1.0 protocol
653        if (isTLS) {
654            verify_data = new byte[12];
655            computerVerifyDataTLS("server finished", verify_data);
656        } else { // SSL 3.0 protocol (http://wp.netscape.com/eng/ssl3)
657            verify_data = new byte[36];
658            computerVerifyDataSSLv3(SSLv3Constants.server, verify_data);
659        }
660        serverFinished = new Finished(verify_data);
661        send(serverFinished);
662        if (isResuming) {
663            if (isTLS) {
664                computerReferenceVerifyDataTLS("client finished");
665            } else {
666                computerReferenceVerifyDataSSLv3(SSLv3Constants.client);
667            }
668            status = NEED_UNWRAP;
669        } else {
670            session.lastAccessedTime = System.currentTimeMillis();
671            status = FINISHED;
672        }
673    }
674
675    // find sesssion in the session hash
676    private SSLSessionImpl findSessionToResume(byte[] session_id) {
677        return (SSLSessionImpl)parameters.getServerSessionContext().getSession(session_id);
678    }
679
680    // find appropriate cipher_suite in the client suites
681    private CipherSuite selectSuite(CipherSuite[] client_suites) {
682        for (int i = 0; i < client_suites.length; i++) {
683            if (!client_suites[i].supported) {
684                continue;
685            }
686            // BEGIN android-changed
687            for (int j = 0; j < parameters.getEnabledCipherSuitesMember().length; j++) {
688                if (client_suites[i].equals(parameters.getEnabledCipherSuitesMember()[j])) {
689                    return client_suites[i];
690                }
691            }
692            // END android-changed
693        }
694        return null;
695    }
696
697    /**
698     * Processes inbound ChangeCipherSpec message
699     */
700    @Override
701    public void receiveChangeCipherSpec() {
702        if (isResuming) {
703            if (serverFinished == null) {
704                unexpectedMessage();
705            } else {
706                changeCipherSpecReceived = true;
707            }
708        } else {
709            if ((parameters.getNeedClientAuth() && clientCert == null)
710                    || clientKeyExchange == null
711                    || (clientCert != null && !clientKeyExchange.isEmpty() && certificateVerify == null)) {
712                unexpectedMessage();
713            } else {
714                changeCipherSpecReceived = true;
715            }
716            if (serverHello.server_version[1] == 1) {
717                computerReferenceVerifyDataTLS("client finished");
718            } else {
719                computerReferenceVerifyDataSSLv3(SSLv3Constants.client);
720            }
721        }
722    }
723
724}
725