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