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.DECRYPT_MODE, privKey);
    209                             preMasterSecret = c.doFinal(clientKeyExchange.exchange_keys);
    210                             // check preMasterSecret:
    211                             if (preMasterSecret.length != 48
    212                                     || preMasterSecret[0] != clientHello.client_version[0]
    213                                     || preMasterSecret[1] != clientHello.client_version[1]) {
    214                                 // incorrect preMasterSecret
    215                                 // prevent an attack (see TLS 1.0 spec., 7.4.7.1.)
    216                                 preMasterSecret = new byte[48];
    217                                 parameters.getSecureRandom().nextBytes(
    218                                         preMasterSecret);
    219                             }
    220                         } catch (Exception e) {
    221                             fatalAlert(AlertProtocol.INTERNAL_ERROR,
    222                                        "INTERNAL ERROR", e);
    223                         }
    224                     } else { // diffie hellman key exchange
    225                         clientKeyExchange = new ClientKeyExchange(io_stream,
    226                                 length, serverHello.server_version[1] == 1,
    227                                 false);
    228                         if (clientKeyExchange.isEmpty()) {
    229                             // TODO check that client cert. DH params
    230                             // matched server cert. DH params
    231 
    232                             // client cert. contains fixed DH parameters
    233                             preMasterSecret = ((DHPublicKey) clientCert.certs[0].getPublicKey()).getY().toByteArray();
    234                         } else {
    235                             try {
    236                                 KeyFactory kf = KeyFactory.getInstance("DH");
    237                                 KeyAgreement agreement = KeyAgreement.getInstance("DH");
    238                                 PublicKey clientPublic = kf.generatePublic(new DHPublicKeySpec(
    239                                                 new BigInteger(
    240                                                         1,
    241                                                         clientKeyExchange.exchange_keys),
    242                                                 serverKeyExchange.par1,
    243                                                 serverKeyExchange.par2));
    244                                 agreement.init(privKey);
    245                                 agreement.doPhase(clientPublic, true);
    246                                 preMasterSecret = agreement.generateSecret();
    247                             } catch (Exception e) {
    248                                 fatalAlert(AlertProtocol.INTERNAL_ERROR,
    249                                            "INTERNAL ERROR", e);
    250                                 return;
    251                             }
    252                         }
    253                     }
    254 
    255                     computerMasterSecret();
    256                     break;
    257 
    258                 case 20: // FINISHED
    259                     if (!isResuming && !changeCipherSpecReceived) {
    260                         unexpectedMessage();
    261                         return;
    262                     }
    263 
    264                     clientFinished = new Finished(io_stream, length);
    265                     verifyFinished(clientFinished.getData());
    266                     session.context = parameters.getServerSessionContext();
    267                     parameters.getServerSessionContext().putSession(session);
    268                     if (!isResuming) {
    269                         sendChangeCipherSpec();
    270                     } else {
    271                         session.lastAccessedTime = System.currentTimeMillis();
    272                         status = FINISHED;
    273                     }
    274                     break;
    275                 default:
    276                     unexpectedMessage();
    277                     return;
    278                 }
    279             } catch (IOException e) {
    280                 // io stream dosn't contain complete handshake message
    281                 io_stream.reset();
    282                 return;
    283             }
    284         }
    285     }
    286     /**
    287      * Processes SSLv2 Hello message
    288      * @ see TLS 1.0 spec., E.1. Version 2 client hello
    289      * @param bytes
    290      */
    291     @Override
    292     public void unwrapSSLv2(byte[] bytes) {
    293         io_stream.append(bytes);
    294         io_stream.mark();
    295         try {
    296             clientHello = new ClientHello(io_stream);
    297         } catch (IOException e) {
    298             io_stream.reset();
    299             return;
    300         }
    301         if (nonBlocking) {
    302             delegatedTasks.add(new DelegatedTask(new Runnable() {
    303                 public void run() {
    304                     processClientHello();
    305                 }
    306             }, this));
    307             return;
    308         }
    309         processClientHello();
    310     }
    311 
    312     /**
    313      *
    314      * Processes Client Hello message.
    315      * Server responds to client hello message with server hello
    316      * and (if necessary) server certificate, server key exchange,
    317      * certificate request, and server hello done messages.
    318      */
    319     void processClientHello() {
    320         CipherSuite cipher_suite;
    321 
    322         // check that clientHello contains CompressionMethod.null
    323         checkCompression: {
    324             for (int i = 0; i < clientHello.compression_methods.length; i++) {
    325                 if (clientHello.compression_methods[i] == 0) {
    326                     break checkCompression;
    327                 }
    328             }
    329             fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
    330                        "HANDSHAKE FAILURE. Incorrect client hello message");
    331         }
    332 
    333         if (!ProtocolVersion.isSupported(clientHello.client_version)) {
    334             fatalAlert(AlertProtocol.PROTOCOL_VERSION,
    335                        "PROTOCOL VERSION. Unsupported client version "
    336                        + clientHello.client_version[0]
    337                        + clientHello.client_version[1]);
    338         }
    339 
    340         isResuming = false;
    341         FIND: if (clientHello.session_id.length != 0) {
    342             // client wishes to reuse session
    343 
    344             SSLSessionImpl sessionToResume;
    345             boolean reuseCurrent = false;
    346 
    347             // reuse current session
    348             if (session != null
    349                     && Arrays.equals(session.id, clientHello.session_id)) {
    350                 if (session.isValid()) {
    351                     isResuming = true;
    352                     break FIND;
    353                 }
    354                 reuseCurrent = true;
    355             }
    356 
    357             // find session in cash
    358             sessionToResume = findSessionToResume(clientHello.session_id);
    359             if (sessionToResume == null || !sessionToResume.isValid()) {
    360                 if (!parameters.getEnableSessionCreation()) {
    361                     if (reuseCurrent) {
    362                         // we can continue current session
    363                         sendWarningAlert(AlertProtocol.NO_RENEGOTIATION);
    364                         status = NOT_HANDSHAKING;
    365                         clearMessages();
    366                         return;
    367                     }
    368                     // throw AlertException
    369                     fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "SSL Session may not be created");
    370                 }
    371                 session = null;
    372             } else {
    373                 session = (SSLSessionImpl)sessionToResume.clone();
    374                 isResuming = true;
    375             }
    376         }
    377 
    378         if (isResuming) {
    379             cipher_suite = session.cipherSuite;
    380             // clientHello.cipher_suites must include at least cipher_suite from the session
    381             checkCipherSuite: {
    382                 for (int i = 0; i < clientHello.cipher_suites.length; i++) {
    383                     if (cipher_suite.equals(clientHello.cipher_suites[i])) {
    384                         break checkCipherSuite;
    385                     }
    386                 }
    387                 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
    388                            "HANDSHAKE FAILURE. Incorrect client hello message");
    389             }
    390         } else {
    391             cipher_suite = selectSuite(clientHello.cipher_suites);
    392             if (cipher_suite == null) {
    393                 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "HANDSHAKE FAILURE. NO COMMON SUITE");
    394             }
    395             if (!parameters.getEnableSessionCreation()) {
    396                 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE,
    397                            "SSL Session may not be created");
    398             }
    399             session = new SSLSessionImpl(cipher_suite, parameters.getSecureRandom());
    400             if (engineOwner != null) {
    401                 session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort());
    402             } else {
    403                 session.setPeer(socketOwner.getInetAddress().getHostName(), socketOwner.getPort());
    404             }
    405         }
    406 
    407         recordProtocol.setVersion(clientHello.client_version);
    408         session.protocol = ProtocolVersion.getByVersion(clientHello.client_version);
    409         session.clientRandom = clientHello.random;
    410 
    411         // create server hello message
    412         serverHello = new ServerHello(parameters.getSecureRandom(),
    413                 clientHello.client_version,
    414                 session.getId(), cipher_suite, (byte) 0); //CompressionMethod.null
    415         session.serverRandom = serverHello.random;
    416         send(serverHello);
    417         if (isResuming) {
    418             sendChangeCipherSpec();
    419             return;
    420         }
    421 
    422         //    create and send server certificate message if needed
    423         if (!cipher_suite.isAnonymous()) { // need to send server certificate
    424             X509Certificate[] certs = null;
    425             String certType = cipher_suite.getServerKeyType();
    426             if (certType == null) {
    427                 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "NO CERT TYPE FOR " + cipher_suite.getName());
    428             }
    429             // obtain certificates from key manager
    430             String alias = null;
    431             X509KeyManager km = parameters.getKeyManager();
    432             if (km instanceof X509ExtendedKeyManager) {
    433                 X509ExtendedKeyManager ekm = (X509ExtendedKeyManager)km;
    434                 if (this.socketOwner != null) {
    435                     alias = ekm.chooseServerAlias(certType, null,
    436                             this.socketOwner);
    437                 } else {
    438                     alias = ekm.chooseEngineServerAlias(certType, null,
    439                             this.engineOwner);
    440                 }
    441                 if (alias != null) {
    442                     certs = ekm.getCertificateChain(alias);
    443                 }
    444             } else {
    445                 alias = km.chooseServerAlias(certType, null, this.socketOwner);
    446                 if (alias != null) {
    447                     certs = km.getCertificateChain(alias);
    448                 }
    449             }
    450 
    451             if (certs == null) {
    452                 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "NO SERVER CERTIFICATE FOUND");
    453                 return;
    454             }
    455             session.localCertificates = certs;
    456             serverCert = new CertificateMessage(certs);
    457             privKey = km.getPrivateKey(alias);
    458             send(serverCert);
    459         }
    460 
    461         // create and send server key exchange message if needed
    462         RSAPublicKey rsakey = null;
    463         DHPublicKeySpec dhkeySpec = null;
    464         byte[] hash = null;
    465         BigInteger p = null;
    466         BigInteger g = null;
    467 
    468         KeyPairGenerator kpg = null;
    469 
    470         try {
    471             if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) {
    472                 PublicKey pk = serverCert.certs[0].getPublicKey();
    473                 if (getRSAKeyLength(pk) > 512) {
    474                     // key is longer than 512 bits
    475                     kpg = KeyPairGenerator.getInstance("RSA");
    476                     kpg.initialize(512);
    477                 }
    478             } else if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS
    479                     || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS_EXPORT
    480                     || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA
    481                     || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA_EXPORT
    482                     || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DH_anon
    483                     || cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT) {
    484                 kpg = KeyPairGenerator.getInstance("DH");
    485                 p = new BigInteger(1, DHParameters.getPrime());
    486                 g = new BigInteger("2");
    487                 DHParameterSpec spec = new DHParameterSpec(p, g);
    488                 kpg.initialize(spec);
    489             }
    490         } catch (Exception e) {
    491             fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e);
    492         }
    493 
    494         if (kpg != null) {
    495             // need to send server key exchange message
    496             DigitalSignature ds = new DigitalSignature(cipher_suite.authType);
    497             KeyPair kp = null;
    498             try {
    499                 kp = kpg.genKeyPair();
    500                 if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) {
    501                     rsakey = (RSAPublicKey) kp.getPublic();
    502                 } else {
    503                     DHPublicKey dhkey = (DHPublicKey) kp.getPublic();
    504                     KeyFactory kf = KeyFactory.getInstance("DH");
    505                     dhkeySpec = kf.getKeySpec(dhkey, DHPublicKeySpec.class);
    506                 }
    507                 if (!cipher_suite.isAnonymous()) { // calculate signed_params
    508 
    509                     // init by private key which correspond to
    510                     // server certificate
    511                     ds.init(privKey);
    512 
    513                     // use emphemeral key for key exchange
    514                     privKey = kp.getPrivate();
    515                     ds.update(clientHello.getRandom());
    516                     ds.update(serverHello.getRandom());
    517 
    518                     byte[] tmp;
    519                     byte[] tmpLength = new byte[2];
    520 //FIXME 1_byte==0x00
    521                     if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) {
    522                         tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getModulus());
    523                         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    524                         tmpLength[1] = (byte) (tmp.length & 0xFF);
    525                         ds.update(tmpLength);
    526                         ds.update(tmp);
    527                         tmp = ServerKeyExchange.toUnsignedByteArray(rsakey.getPublicExponent());
    528                         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    529                         tmpLength[1] = (byte) (tmp.length & 0xFF);
    530                         ds.update(tmpLength);
    531                         ds.update(tmp);
    532                     } else {
    533                         tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getP());
    534                         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    535                         tmpLength[1] = (byte) (tmp.length & 0xFF);
    536                         ds.update(tmpLength);
    537                         ds.update(tmp);
    538                         tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getG());
    539                         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    540                         tmpLength[1] = (byte) (tmp.length & 0xFF);
    541                         ds.update(tmpLength);
    542                         ds.update(tmp);
    543                         tmp = ServerKeyExchange.toUnsignedByteArray(dhkeySpec.getY());
    544                         tmpLength[0] = (byte) ((tmp.length & 0xFF00) >>> 8);
    545                         tmpLength[1] = (byte) (tmp.length & 0xFF);
    546                         ds.update(tmpLength);
    547                         ds.update(tmp);
    548                     }
    549                     hash = ds.sign();
    550                 } else {
    551                     privKey = kp.getPrivate(); // use emphemeral key for key exchange
    552                 }
    553             } catch (Exception e) {
    554                 fatalAlert(AlertProtocol.INTERNAL_ERROR, "INTERNAL ERROR", e);
    555             }
    556 
    557             if (cipher_suite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) {
    558                 serverKeyExchange = new ServerKeyExchange(rsakey.getModulus(),
    559                         rsakey.getPublicExponent(), null, hash);
    560             } else {
    561                 serverKeyExchange = new ServerKeyExchange(p,
    562                         g, dhkeySpec.getY(), hash);
    563             }
    564             send(serverKeyExchange);
    565         }
    566 
    567         // CERTIFICATE_REQUEST
    568         certRequest: if (parameters.getWantClientAuth()
    569                 || parameters.getNeedClientAuth()) {
    570             X509Certificate[] accepted;
    571             try {
    572                 X509TrustManager tm = parameters.getTrustManager();
    573                 accepted = tm.getAcceptedIssuers();
    574             } catch (ClassCastException e) {
    575                 // don't send certificateRequest
    576                 break certRequest;
    577             }
    578             byte[] requestedClientCertTypes = { CipherSuite.TLS_CT_RSA_SIGN,
    579                                                 CipherSuite.TLS_CT_DSS_SIGN };
    580             certificateRequest = new CertificateRequest(
    581                     requestedClientCertTypes, accepted);
    582             send(certificateRequest);
    583         }
    584 
    585         // SERVER_HELLO_DONE
    586         serverHelloDone = new ServerHelloDone();
    587         send(serverHelloDone);
    588         status = NEED_UNWRAP;
    589     }
    590 
    591     /**
    592      * Creates and sends finished message
    593      */
    594     @Override
    595     protected void makeFinished() {
    596         byte[] verify_data;
    597         boolean isTLS = (serverHello.server_version[1] == 1); // TLS 1.0 protocol
    598         if (isTLS) {
    599             verify_data = new byte[12];
    600             computerVerifyDataTLS("server finished", verify_data);
    601         } else { // SSL 3.0 protocol (http://wp.netscape.com/eng/ssl3)
    602             verify_data = new byte[36];
    603             computerVerifyDataSSLv3(SSLv3Constants.server, verify_data);
    604         }
    605         serverFinished = new Finished(verify_data);
    606         send(serverFinished);
    607         if (isResuming) {
    608             if (isTLS) {
    609                 computerReferenceVerifyDataTLS("client finished");
    610             } else {
    611                 computerReferenceVerifyDataSSLv3(SSLv3Constants.client);
    612             }
    613             status = NEED_UNWRAP;
    614         } else {
    615             session.lastAccessedTime = System.currentTimeMillis();
    616             status = FINISHED;
    617         }
    618     }
    619 
    620     // find sesssion in the session hash
    621     private SSLSessionImpl findSessionToResume(byte[] session_id) {
    622         return (SSLSessionImpl)parameters.getServerSessionContext().getSession(session_id);
    623     }
    624 
    625     // find appropriate cipher_suite in the client suites
    626     private CipherSuite selectSuite(CipherSuite[] clientSuites) {
    627         for (CipherSuite clientSuite : clientSuites) {
    628             if (!clientSuite.supported) {
    629                 continue;
    630             }
    631             for (CipherSuite enabledCipherSuite : parameters.getEnabledCipherSuitesMember()) {
    632                 if (clientSuite.equals(enabledCipherSuite)) {
    633                     return clientSuite;
    634                 }
    635             }
    636         }
    637         return null;
    638     }
    639 
    640     /**
    641      * Processes inbound ChangeCipherSpec message
    642      */
    643     @Override
    644     public void receiveChangeCipherSpec() {
    645         if (isResuming) {
    646             if (serverFinished == null) {
    647                 unexpectedMessage();
    648             } else {
    649                 changeCipherSpecReceived = true;
    650             }
    651         } else {
    652             if ((parameters.getNeedClientAuth() && clientCert == null)
    653                     || clientKeyExchange == null
    654                     || (clientCert != null
    655                             && !clientKeyExchange.isEmpty()
    656                             && certificateVerify == null)) {
    657                 unexpectedMessage();
    658             } else {
    659                 changeCipherSpecReceived = true;
    660             }
    661             if (serverHello.server_version[1] == 1) {
    662                 computerReferenceVerifyDataTLS("client finished");
    663             } else {
    664                 computerReferenceVerifyDataSSLv3(SSLv3Constants.client);
    665             }
    666         }
    667     }
    668 
    669 }
    670