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