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