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