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