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