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