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.security.AccessController; 22 import java.security.Key; 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.util.Arrays; 33 import javax.crypto.Cipher; 34 import javax.crypto.KeyAgreement; 35 import javax.crypto.interfaces.DHKey; 36 import javax.crypto.interfaces.DHPublicKey; 37 import javax.crypto.spec.DHParameterSpec; 38 import javax.crypto.spec.DHPublicKeySpec; 39 import javax.crypto.spec.SecretKeySpec; 40 import javax.net.ssl.X509ExtendedKeyManager; 41 import javax.net.ssl.X509KeyManager; 42 import javax.security.auth.x500.X500Principal; 43 44 /** 45 * Client side handshake protocol implementation. 46 * Handshake protocol operates on top of the Record Protocol. 47 * It is responsible for session negotiating. 48 * 49 * The implementation processes inbound server handshake messages, 50 * creates and sends respond messages. Outbound messages are supplied 51 * to Record Protocol. Detected errors are reported to the Alert protocol. 52 * 53 * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7. The 54 * TLS Handshake Protocol</a> 55 * 56 */ 57 public class ClientHandshakeImpl extends HandshakeProtocol { 58 59 /** 60 * Creates Client Handshake Implementation 61 * 62 * @param owner 63 */ 64 ClientHandshakeImpl(Object owner) { 65 super(owner); 66 } 67 68 /** 69 * Starts handshake 70 * 71 */ 72 @Override 73 public void start() { 74 if (session == null) { // initial handshake 75 session = findSessionToResume(); 76 } else { // start session renegotiation 77 if (clientHello != null && this.status != FINISHED) { 78 // current negotiation has not completed 79 return; // ignore 80 } 81 if (!session.isValid()) { 82 session = null; 83 } 84 } 85 if (session != null) { 86 isResuming = true; 87 } else if (parameters.getEnableSessionCreation()){ 88 isResuming = false; 89 session = new SSLSessionImpl(parameters.getSecureRandom()); 90 if (engineOwner != null) { 91 session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort()); 92 } else { 93 session.setPeer(socketOwner.getInetAddress().getHostName(), socketOwner.getPort()); 94 } 95 session.protocol = ProtocolVersion.getLatestVersion(parameters.getEnabledProtocols()); 96 recordProtocol.setVersion(session.protocol.version); 97 } else { 98 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "SSL Session may not be created "); 99 } 100 startSession(); 101 } 102 103 /** 104 * Starts renegotiation on a new session 105 * 106 */ 107 private void renegotiateNewSession() { 108 if (parameters.getEnableSessionCreation()){ 109 isResuming = false; 110 session = new SSLSessionImpl(parameters.getSecureRandom()); 111 if (engineOwner != null) { 112 session.setPeer(engineOwner.getPeerHost(), engineOwner.getPeerPort()); 113 } else { 114 session.setPeer(socketOwner.getInetAddress().getHostName(), socketOwner.getPort()); 115 } 116 session.protocol = ProtocolVersion.getLatestVersion(parameters.getEnabledProtocols()); 117 recordProtocol.setVersion(session.protocol.version); 118 startSession(); 119 } else { 120 status = NOT_HANDSHAKING; 121 sendWarningAlert(AlertProtocol.NO_RENEGOTIATION); 122 } 123 } 124 125 /* 126 * Starts/resumes session 127 */ 128 private void startSession() { 129 CipherSuite[] cipher_suites; 130 if (isResuming) { 131 cipher_suites = new CipherSuite[] { session.cipherSuite }; 132 } else { 133 cipher_suites = parameters.getEnabledCipherSuitesMember(); 134 } 135 clientHello = new ClientHello(parameters.getSecureRandom(), 136 session.protocol.version, session.id, cipher_suites); 137 session.clientRandom = clientHello.random; 138 send(clientHello); 139 status = NEED_UNWRAP; 140 } 141 142 /** 143 * Processes inbound handshake messages 144 * @param bytes 145 */ 146 @Override 147 public void unwrap(byte[] bytes) { 148 if (this.delegatedTaskErr != null) { 149 Exception e = this.delegatedTaskErr; 150 this.delegatedTaskErr = null; 151 this.fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, "Error in delegated task", e); 152 } 153 int handshakeType; 154 io_stream.append(bytes); 155 while (io_stream.available() > 0) { 156 io_stream.mark(); 157 int length; 158 try { 159 handshakeType = io_stream.read(); 160 length = io_stream.readUint24(); 161 if (io_stream.available() < length) { 162 io_stream.reset(); 163 return; 164 } 165 switch (handshakeType) { 166 case 0: // HELLO_REQUEST 167 // we don't need to take this message into account 168 // during FINISH message verification, so remove it 169 io_stream.removeFromMarkedPosition(); 170 if (clientHello != null 171 && (clientFinished == null || serverFinished == null)) { 172 //currently negotiating - ignore 173 break; 174 } 175 // renegotiate 176 if (session.isValid()) { 177 session = (SSLSessionImpl) session.clone(); 178 isResuming = true; 179 startSession(); 180 } else { 181 // if SSLSession is invalidated (e.g. timeout limit is 182 // exceeded) connection can't resume the session. 183 renegotiateNewSession(); 184 } 185 break; 186 case 2: // SERVER_HELLO 187 if (clientHello == null || serverHello != null) { 188 unexpectedMessage(); 189 return; 190 } 191 serverHello = new ServerHello(io_stream, length); 192 193 //check protocol version 194 ProtocolVersion servProt = ProtocolVersion.getByVersion(serverHello.server_version); 195 String[] enabled = parameters.getEnabledProtocols(); 196 find: { 197 for (int i = 0; i < enabled.length; i++) { 198 if (servProt.equals(ProtocolVersion.getByName(enabled[i]))) { 199 break find; 200 } 201 } 202 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, 203 "Bad server hello protocol version"); 204 } 205 206 // check compression method 207 if (serverHello.compression_method != 0) { 208 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, 209 "Bad server hello compression method"); 210 } 211 212 //check cipher_suite 213 CipherSuite[] enabledSuites = parameters.getEnabledCipherSuitesMember(); 214 find: { 215 for (int i = 0; i < enabledSuites.length; i++) { 216 if (serverHello.cipher_suite.equals(enabledSuites[i])) { 217 break find; 218 } 219 } 220 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, 221 "Bad server hello cipher suite"); 222 } 223 224 if (isResuming) { 225 if (serverHello.session_id.length == 0) { 226 // server is not willing to establish the new connection 227 // using specified session 228 isResuming = false; 229 } else if (!Arrays.equals(serverHello.session_id, clientHello.session_id)) { 230 isResuming = false; 231 } else if (!session.protocol.equals(servProt)) { 232 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, 233 "Bad server hello protocol version"); 234 } else if (!session.cipherSuite.equals(serverHello.cipher_suite)) { 235 fatalAlert(AlertProtocol.HANDSHAKE_FAILURE, 236 "Bad server hello cipher suite"); 237 } 238 if (serverHello.server_version[1] == 1) { 239 computerReferenceVerifyDataTLS("server finished"); 240 } else { 241 computerReferenceVerifyDataSSLv3(SSLv3Constants.server); 242 } 243 } 244 session.protocol = servProt; 245 recordProtocol.setVersion(session.protocol.version); 246 session.cipherSuite = serverHello.cipher_suite; 247 session.id = serverHello.session_id.clone(); 248 session.serverRandom = serverHello.random; 249 break; 250 case 11: // CERTIFICATE 251 if (serverHello == null || serverKeyExchange != null 252 || serverCert != null || isResuming) { 253 unexpectedMessage(); 254 return; 255 } 256 serverCert = new CertificateMessage(io_stream, length); 257 break; 258 case 12: // SERVER_KEY_EXCHANGE 259 if (serverHello == null || serverKeyExchange != null 260 || isResuming) { 261 unexpectedMessage(); 262 return; 263 } 264 serverKeyExchange = new ServerKeyExchange(io_stream, 265 length, session.cipherSuite.keyExchange); 266 break; 267 case 13: // CERTIFICATE_REQUEST 268 if (serverCert == null || certificateRequest != null 269 || session.cipherSuite.isAnonymous() || isResuming) { 270 unexpectedMessage(); 271 return; 272 } 273 certificateRequest = new CertificateRequest(io_stream, length); 274 break; 275 case 14: // SERVER_HELLO_DONE 276 if (serverHello == null || serverHelloDone != null || isResuming) { 277 unexpectedMessage(); 278 return; 279 } 280 serverHelloDone = new ServerHelloDone(io_stream, length); 281 if (this.nonBlocking) { 282 delegatedTasks.add(new DelegatedTask(new Runnable() { 283 public void run() { 284 processServerHelloDone(); 285 } 286 }, this)); 287 return; 288 } 289 processServerHelloDone(); 290 break; 291 case 20: // FINISHED 292 if (!changeCipherSpecReceived) { 293 unexpectedMessage(); 294 return; 295 } 296 serverFinished = new Finished(io_stream, length); 297 verifyFinished(serverFinished.getData()); 298 session.lastAccessedTime = System.currentTimeMillis(); 299 session.context = parameters.getClientSessionContext(); 300 parameters.getClientSessionContext().putSession(session); 301 if (isResuming) { 302 sendChangeCipherSpec(); 303 } else { 304 session.lastAccessedTime = System.currentTimeMillis(); 305 status = FINISHED; 306 } 307 // XXX there is no cleanup work 308 break; 309 default: 310 unexpectedMessage(); 311 return; 312 } 313 } catch (IOException e) { 314 // io stream dosn't contain complete handshake message 315 io_stream.reset(); 316 return; 317 } 318 } 319 320 } 321 322 /** 323 * Processes SSLv2 Hello message. 324 * SSLv2 client hello message message is an unexpected message 325 * for client side of handshake protocol. 326 * @ see TLS 1.0 spec., E.1. Version 2 client hello 327 * @param bytes 328 */ 329 @Override 330 public void unwrapSSLv2(byte[] bytes) { 331 unexpectedMessage(); 332 } 333 334 /** 335 * Creates and sends Finished message 336 */ 337 @Override 338 protected void makeFinished() { 339 byte[] verify_data; 340 if (serverHello.server_version[1] == 1) { 341 verify_data = new byte[12]; 342 computerVerifyDataTLS("client finished", verify_data); 343 } else { 344 verify_data = new byte[36]; 345 computerVerifyDataSSLv3(SSLv3Constants.client, verify_data); 346 } 347 clientFinished = new Finished(verify_data); 348 send(clientFinished); 349 if (isResuming) { 350 session.lastAccessedTime = System.currentTimeMillis(); 351 status = FINISHED; 352 } else { 353 if (serverHello.server_version[1] == 1) { 354 computerReferenceVerifyDataTLS("server finished"); 355 } else { 356 computerReferenceVerifyDataSSLv3(SSLv3Constants.server); 357 } 358 status = NEED_UNWRAP; 359 } 360 } 361 362 /** 363 * Processes ServerHelloDone: makes verification of the server messages; sends 364 * client messages, computers masterSecret, sends ChangeCipherSpec 365 */ 366 void processServerHelloDone() { 367 PrivateKey clientKey = null; 368 369 if (serverCert != null) { 370 if (session.cipherSuite.isAnonymous()) { 371 unexpectedMessage(); 372 return; 373 } 374 verifyServerCert(); 375 } else { 376 if (!session.cipherSuite.isAnonymous()) { 377 unexpectedMessage(); 378 return; 379 } 380 } 381 382 // Client certificate 383 if (certificateRequest != null) { 384 X509Certificate[] certs = null; 385 // obtain certificates from key manager 386 String alias = null; 387 String[] certTypes = certificateRequest.getTypesAsString(); 388 X500Principal[] issuers = certificateRequest.certificate_authorities; 389 X509KeyManager km = parameters.getKeyManager(); 390 if (km instanceof X509ExtendedKeyManager) { 391 X509ExtendedKeyManager ekm = (X509ExtendedKeyManager)km; 392 if (this.socketOwner != null) { 393 alias = ekm.chooseClientAlias(certTypes, issuers, this.socketOwner); 394 } else { 395 alias = ekm.chooseEngineClientAlias(certTypes, issuers, this.engineOwner); 396 } 397 if (alias != null) { 398 certs = ekm.getCertificateChain(alias); 399 } 400 } else { 401 alias = km.chooseClientAlias(certTypes, issuers, this.socketOwner); 402 if (alias != null) { 403 certs = km.getCertificateChain(alias); 404 } 405 } 406 407 session.localCertificates = certs; 408 clientCert = new CertificateMessage(certs); 409 clientKey = km.getPrivateKey(alias); 410 send(clientCert); 411 } 412 // Client key exchange 413 if (session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA 414 || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { 415 // RSA encrypted premaster secret message 416 Cipher c; 417 try { 418 c = Cipher.getInstance("RSA/ECB/PKCS1Padding"); 419 if (serverKeyExchange != null) { 420 c.init(Cipher.WRAP_MODE, serverKeyExchange 421 .getRSAPublicKey()); 422 } else { 423 c.init(Cipher.WRAP_MODE, serverCert.certs[0]); 424 } 425 } catch (Exception e) { 426 fatalAlert(AlertProtocol.INTERNAL_ERROR, 427 "Unexpected exception", e); 428 return; 429 } 430 preMasterSecret = new byte[48]; 431 parameters.getSecureRandom().nextBytes(preMasterSecret); 432 System.arraycopy(clientHello.client_version, 0, preMasterSecret, 0, 2); 433 try { 434 clientKeyExchange = new ClientKeyExchange(c 435 .wrap(new SecretKeySpec(preMasterSecret, "preMasterSecret")), 436 serverHello.server_version[1] == 1); 437 } catch (Exception e) { 438 fatalAlert(AlertProtocol.INTERNAL_ERROR, 439 "Unexpected exception", e); 440 return; 441 } 442 } else { 443 try { 444 KeyFactory kf = KeyFactory.getInstance("DH"); 445 KeyAgreement agreement = KeyAgreement.getInstance("DH"); 446 KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH"); 447 PublicKey serverPublic; 448 DHParameterSpec spec; 449 if (serverKeyExchange != null) { 450 serverPublic = kf.generatePublic(new DHPublicKeySpec( 451 serverKeyExchange.par3, serverKeyExchange.par1, 452 serverKeyExchange.par2)); 453 spec = new DHParameterSpec(serverKeyExchange.par1, 454 serverKeyExchange.par2); 455 } else { 456 serverPublic = serverCert.certs[0].getPublicKey(); 457 spec = ((DHPublicKey) serverPublic).getParams(); 458 } 459 kpg.initialize(spec); 460 461 KeyPair kp = kpg.generateKeyPair(); 462 Key key = kp.getPublic(); 463 if (clientCert != null 464 && serverCert != null 465 && (session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_RSA 466 || session.cipherSuite.keyExchange == CipherSuite.KEY_EXCHANGE_DHE_DSS)) { 467 PublicKey client_pk = clientCert.certs[0].getPublicKey(); 468 PublicKey server_pk = serverCert.certs[0].getPublicKey(); 469 if (client_pk instanceof DHKey 470 && server_pk instanceof DHKey) { 471 if (((DHKey) client_pk).getParams().getG().equals( 472 ((DHKey) server_pk).getParams().getG()) 473 && ((DHKey) client_pk).getParams().getP() 474 .equals(((DHKey) server_pk).getParams().getG())) { 475 // client cert message DH public key parameters 476 // matched those specified by the 477 // server in its certificate, 478 clientKeyExchange = new ClientKeyExchange(); // empty 479 } 480 } 481 } else { 482 clientKeyExchange = new ClientKeyExchange( 483 ((DHPublicKey) key).getY()); 484 } 485 key = kp.getPrivate(); 486 agreement.init(key); 487 agreement.doPhase(serverPublic, true); 488 preMasterSecret = agreement.generateSecret(); 489 } catch (Exception e) { 490 fatalAlert(AlertProtocol.INTERNAL_ERROR, 491 "Unexpected exception", e); 492 return; 493 } 494 } 495 if (clientKeyExchange != null) { 496 send(clientKeyExchange); 497 } 498 499 computerMasterSecret(); 500 501 // send certificate verify for all certificates except those containing 502 // fixed DH parameters 503 if (clientCert != null && !clientKeyExchange.isEmpty()) { 504 // Certificate verify 505 String authType = clientKey.getAlgorithm(); 506 DigitalSignature ds = new DigitalSignature(authType); 507 ds.init(clientKey); 508 509 if ("RSA".equals(authType)) { 510 ds.setMD5(io_stream.getDigestMD5()); 511 ds.setSHA(io_stream.getDigestSHA()); 512 } else if ("DSA".equals(authType)) { 513 ds.setSHA(io_stream.getDigestSHA()); 514 // The Signature should be empty in case of anonymous signature algorithm: 515 // } else if ("DH".equals(authType)) { 516 } 517 certificateVerify = new CertificateVerify(ds.sign()); 518 send(certificateVerify); 519 } 520 521 sendChangeCipherSpec(); 522 } 523 524 /* 525 * Verifies certificate path 526 */ 527 private void verifyServerCert() { 528 String authType = session.cipherSuite.getAuthType(serverKeyExchange != null); 529 if (authType == null) { 530 return; 531 } 532 try { 533 parameters.getTrustManager().checkServerTrusted(serverCert.certs, authType); 534 } catch (CertificateException e) { 535 fatalAlert(AlertProtocol.BAD_CERTIFICATE, "Not trusted server certificate", e); 536 return; 537 } 538 session.peerCertificates = serverCert.certs; 539 } 540 541 /** 542 * Processes ChangeCipherSpec message 543 */ 544 @Override 545 public void receiveChangeCipherSpec() { 546 if (isResuming) { 547 if (serverHello == null) { 548 unexpectedMessage(); 549 } 550 } else if (clientFinished == null) { 551 unexpectedMessage(); 552 } 553 changeCipherSpecReceived = true; 554 } 555 556 // Find session to resume in client session context 557 private SSLSessionImpl findSessionToResume() { 558 String host = null; 559 int port = -1; 560 if (engineOwner != null) { 561 host = engineOwner.getPeerHost(); 562 port = engineOwner.getPeerPort(); 563 } else { 564 host = socketOwner.getInetAddress().getHostName(); 565 port = socketOwner.getPort(); 566 } 567 if (host == null || port == -1) { 568 return null; // starts new session 569 } 570 571 ClientSessionContext context = parameters.getClientSessionContext(); 572 SSLSessionImpl session 573 = (SSLSessionImpl) context.getSession(host, port); 574 if (session != null) { 575 session = (SSLSessionImpl) session.clone(); 576 } 577 return session; 578 } 579 580 } 581