1 19 20 package com.maverick.ssl; 21 22 import java.io.ByteArrayInputStream ; 23 import java.io.ByteArrayOutputStream ; 24 import java.io.IOException ; 25 import java.math.BigInteger ; 26 import java.text.MessageFormat ; 27 28 import org.apache.commons.logging.Log; 30 import org.apache.commons.logging.LogFactory; 31 33 import com.maverick.crypto.asn1.ASN1Sequence; 34 import com.maverick.crypto.asn1.DERInputStream; 35 import com.maverick.crypto.asn1.x509.CertificateException; 36 import com.maverick.crypto.asn1.x509.X509Certificate; 37 import com.maverick.crypto.asn1.x509.X509CertificateStructure; 38 import com.maverick.crypto.digests.MD5Digest; 39 import com.maverick.crypto.digests.SHA1Digest; 40 import com.maverick.crypto.publickey.PublicKey; 41 import com.maverick.crypto.publickey.Rsa; 42 import com.maverick.crypto.publickey.RsaPublicKey; 43 44 48 class SSLHandshakeProtocol { 49 50 final static int HANDSHAKE_PROTOCOL_MSG = 22; 51 52 final static int HELLO_REQUEST_MSG = 0; 53 final static int CLIENT_HELLO_MSG = 1; 54 final static int SERVER_HELLO_MSG = 2; 55 56 final static int CERTIFICATE_MSG = 11; 57 final static int KEY_EXCHANGE_MSG = 12; 58 59 final static int CERTIFICATE_REQUEST_MSG = 13; 60 final static int SERVER_HELLO_DONE_MSG = 14; 61 62 final static int CERTIFICATE_VERIFY_MSG = 15; 63 final static int CLIENT_KEY_EXCHANGE_MSG = 16; 64 final static int FINISHED_MSG = 20; 65 66 final static int HANDSHAKE_PENDING_OR_COMPLETE = -1; 67 68 SSLContext context; 69 SSLTransportImpl socket; 70 71 MD5Digest handshakeMD5 = new MD5Digest(); 72 SHA1Digest handshakeSHA1 = new SHA1Digest(); 73 74 SSLCipherSuiteID cipherSuiteID; 76 int compressionID; 77 byte[] sessionID; 78 int majorVersion; 79 int minorVersion; 80 byte[] clientRandom; 81 byte[] serverRandom; 82 byte[] premasterSecret; 83 byte[] masterSecret; 84 85 X509Certificate x509; 86 87 SSLCipherSuite pendingCipherSuite; 88 boolean wantsClientAuth = false; 89 int currentHandshakeStep = HANDSHAKE_PENDING_OR_COMPLETE; 90 91 Log log = LogFactory.getLog(SSLHandshakeProtocol.class); 93 94 96 public SSLHandshakeProtocol(SSLTransportImpl socket, SSLContext context) throws IOException { 97 this.socket = socket; 98 this.context = context; 99 100 } 101 102 boolean isComplete() { 103 return currentHandshakeStep == HANDSHAKE_PENDING_OR_COMPLETE; 104 } 105 106 void processMessage(byte[] fragment, int off, int len) throws SSLException { 107 108 ByteArrayInputStream reader = new ByteArrayInputStream (fragment, off, len); 109 110 updateHandshakeHashes(fragment); 112 113 while (reader.available() > 0 && !isComplete()) { 114 115 int type = reader.read(); 116 117 int length = (reader.read() & 0xFF) << 16 | (reader.read() & 0xFF) << 8 | (reader.read() & 0xFF); 118 119 log.debug(MessageFormat.format(Messages.getString("SSLHandshakeProtocol.processingType"), new Object [] { new Integer (type), new Long (length) })); 123 byte[] msg = new byte[length]; 124 try { 125 reader.read(msg); 126 } catch (IOException ex) { 127 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() 128 : ex.getMessage()); 129 } 130 131 switch (type) { 132 case HELLO_REQUEST_MSG: 133 134 log.debug(Messages.getString("SSLHandshakeProtocol.receivedHELLO")); 142 if (currentHandshakeStep == HANDSHAKE_PENDING_OR_COMPLETE) { 143 startHandshake(); 144 } 145 break; 146 147 case SERVER_HELLO_MSG: 148 149 log.debug(Messages.getString("SSLHandshakeProtocol.receivedServerHELLO")); 153 if (currentHandshakeStep != CLIENT_HELLO_MSG) { 154 throw new SSLException(SSLException.PROTOCOL_VIOLATION, 155 MessageFormat.format(Messages.getString("SSLHandshakeProtocol.receivedUnexpectedServerHello"), new Object [] { new Integer (currentHandshakeStep) })); } 157 158 onServerHelloMsg(msg); 159 break; 160 161 case CERTIFICATE_MSG: 162 163 log.debug(Messages.getString("SSLHandshakeProtocol.receivedServerCertificate")); 167 if (currentHandshakeStep != SERVER_HELLO_MSG) { 168 throw new SSLException(SSLException.PROTOCOL_VIOLATION, 169 MessageFormat.format(Messages.getString("SSLHandshakeProtocol.unexpectedCertificateMessageReceived"), new Object [] { new Integer (currentHandshakeStep) })); } 171 onCertificateMsg(msg); 172 break; 173 174 case KEY_EXCHANGE_MSG: 175 176 log.debug(Messages.getString("SSLHandshakeProtocol.receivedUnsupportedServerKEX")); 180 throw new SSLException(SSLException.UNSUPPORTED_OPERATION, 181 Messages.getString("SSLHandshakeProtocol.kexNotSupported")); 183 case CERTIFICATE_REQUEST_MSG: 184 185 log.debug(Messages.getString("SSLHandshakeProtocol.receivedUnsupportedClientCert")); 189 wantsClientAuth = true; 190 break; 191 192 case SERVER_HELLO_DONE_MSG: 193 194 log.debug(Messages.getString("SSLHandshakeProtocol.helloDone")); 198 if (currentHandshakeStep != CERTIFICATE_MSG) { 199 throw new SSLException(SSLException.PROTOCOL_VIOLATION, 200 MessageFormat.format(Messages.getString("SSLHandshakeProtocol.unexpectedServerHelloDone"), new Object [] { new Integer (currentHandshakeStep) })); } 202 203 if (wantsClientAuth) { 204 205 log.debug(Messages.getString("SSLHandshakeProtocol.sendingNoCert")); socket.sendMessage(SSLTransportImpl.ALERT_PROTOCOL, new byte[] { (byte) SSLTransportImpl.WARNING_ALERT, 209 (byte) SSLException.NO_CERTIFICATE }); 210 } 211 onServerHelloDoneMsg(); 212 break; 213 214 case FINISHED_MSG: 215 216 log.debug(Messages.getString("SSLHandshakeProtocol.receivedServerFinished")); 220 if (currentHandshakeStep != FINISHED_MSG) { 221 throw new SSLException(SSLException.PROTOCOL_VIOLATION); 222 } 223 224 currentHandshakeStep = HANDSHAKE_PENDING_OR_COMPLETE; 225 226 break; 227 228 default: 229 230 } 231 } 232 } 233 234 public X509Certificate getCertificate() { 235 return x509; 236 } 237 238 private void sendMessage(int type, byte[] data) throws SSLException { 239 240 ByteArrayOutputStream msg = new ByteArrayOutputStream (); 241 242 try { 243 msg.write(type); 244 msg.write((data.length >> 16) & 0xFF); 245 msg.write((data.length >> 8) & 0xFF); 246 msg.write(data.length); 247 msg.write(data); 248 } catch (IOException ex) { 249 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 250 } 251 252 byte[] m = msg.toByteArray(); 253 254 if (type != FINISHED_MSG) { 256 updateHandshakeHashes(m); 257 258 } 259 socket.sendMessage(HANDSHAKE_PROTOCOL_MSG, m); 260 } 261 262 public void startHandshake() throws SSLException { 263 264 if (currentHandshakeStep != HANDSHAKE_PENDING_OR_COMPLETE) { 265 throw new SSLException(SSLException.PROTOCOL_VIOLATION, Messages.getString("SSLHandshakeProtocol.alreadyInProgress")); } 267 268 log.debug(Messages.getString("SSLHandshakeProtocol.starting")); 272 sendClientHello(); 273 } 274 275 private void calculateMasterSecret() throws SSLException { 276 277 log.debug(Messages.getString("SSLHandshakeProtocol.calculatingMasterSecret")); 281 try { 282 MD5Digest md5 = new MD5Digest(); 283 SHA1Digest sha1 = new SHA1Digest(); 284 285 ByteArrayOutputStream out = new ByteArrayOutputStream (); 286 287 String [] mixers = new String [] { "A", "BB", "CCC" }; 289 for (int i = 0; i < mixers.length; i++) { 290 md5.reset(); 291 sha1.reset(); 292 sha1.update(mixers[i].getBytes(), 0, mixers[i].getBytes().length); 293 sha1.update(premasterSecret, 0, premasterSecret.length); 294 sha1.update(clientRandom, 0, clientRandom.length); 295 sha1.update(serverRandom, 0, serverRandom.length); 296 297 md5.update(premasterSecret, 0, premasterSecret.length); 298 byte[] tmp = new byte[sha1.getDigestSize()]; 299 sha1.doFinal(tmp, 0); 300 301 md5.update(tmp, 0, tmp.length); 302 303 tmp = new byte[md5.getDigestSize()]; 304 md5.doFinal(tmp, 0); 305 306 out.write(tmp); 307 308 } 309 310 masterSecret = out.toByteArray(); 311 } catch (IOException ex) { 312 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 313 } 314 315 } 316 317 private void calculatePreMasterSecret() { 318 319 log.debug(Messages.getString("SSLHandshakeProtocol.generatingPreMasterSecret")); 323 premasterSecret = new byte[48]; 324 context.getRND().nextBytes(premasterSecret); 325 premasterSecret[0] = (byte) SSLTransportImpl.VERSION_MAJOR; 326 premasterSecret[1] = (byte) SSLTransportImpl.VERSION_MINOR; 327 328 } 329 330 private void debugBytes(byte[] b, String s) { 331 332 System.out.print(s + ": "); 334 for (int i = 0; i < b.length; i++) { 335 336 System.out.print(Integer.toHexString((int) (b[i] & 0xFF))); 337 338 } 339 340 System.out.println(); 341 342 } 343 344 private void onServerHelloDoneMsg() throws SSLException { 345 346 calculatePreMasterSecret(); 348 349 byte[] secret = null; 350 351 try { 352 353 BigInteger input = new BigInteger (1, premasterSecret); 355 356 PublicKey key = x509.getPublicKey(); 357 358 if (key instanceof RsaPublicKey) { 359 360 BigInteger padded = Rsa.padPKCS1(input, 0x02, 128); 361 BigInteger s = Rsa.doPublic(padded, ((RsaPublicKey) key).getModulus(), ((RsaPublicKey) key).getPublicExponent()); 362 363 secret = s.toByteArray(); 364 } else { 365 throw new SSLException(SSLException.UNSUPPORTED_CERTIFICATE); 366 } 367 } catch (CertificateException ex) { 368 throw new SSLException(SSLException.UNSUPPORTED_CERTIFICATE, ex.getMessage()); 369 } 370 371 if (secret[0] == 0) { 372 byte[] tmp = new byte[secret.length - 1]; 373 System.arraycopy(secret, 1, tmp, 0, secret.length - 1); 374 secret = tmp; 375 } 376 377 sendMessage(CLIENT_KEY_EXCHANGE_MSG, secret); 378 379 calculateMasterSecret(); 381 382 log.debug(Messages.getString("SSLHandshakeProtocol.generatingKeyData")); 386 byte[] keydata; 388 int length = 0; 389 390 length += pendingCipherSuite.getKeyLength() * 2; 391 length += pendingCipherSuite.getMACLength() * 2; 392 length += pendingCipherSuite.getIVLength() * 2; 393 394 ByteArrayOutputStream out = new ByteArrayOutputStream (); 395 396 MD5Digest md5 = new MD5Digest(); 397 SHA1Digest sha1 = new SHA1Digest(); 398 399 int turn = 0; 400 while (out.size() < length) { 401 md5.reset(); 402 sha1.reset(); 403 404 for (int i = 0; i <= turn; i++) { 405 sha1.update((byte) ('A' + turn)); 406 } 407 408 sha1.update(masterSecret, 0, masterSecret.length); 409 sha1.update(serverRandom, 0, serverRandom.length); 410 sha1.update(clientRandom, 0, clientRandom.length); 411 412 md5.update(masterSecret, 0, masterSecret.length); 413 byte[] tmp = new byte[sha1.getDigestSize()]; 414 sha1.doFinal(tmp, 0); 415 md5.update(tmp, 0, tmp.length); 416 tmp = new byte[md5.getDigestSize()]; 417 md5.doFinal(tmp, 0); 418 419 out.write(tmp, 0, tmp.length); 421 422 turn++; 423 } 424 425 keydata = out.toByteArray(); 426 427 ByteArrayInputStream in = new ByteArrayInputStream (keydata); 428 429 byte[] encryptKey = new byte[pendingCipherSuite.getKeyLength()]; 430 byte[] encryptIV = new byte[pendingCipherSuite.getIVLength()]; 431 byte[] encryptMAC = new byte[pendingCipherSuite.getMACLength()]; 432 byte[] decryptKey = new byte[pendingCipherSuite.getKeyLength()]; 433 byte[] decryptIV = new byte[pendingCipherSuite.getIVLength()]; 434 byte[] decryptMAC = new byte[pendingCipherSuite.getMACLength()]; 435 436 try { 437 in.read(encryptMAC); 438 in.read(decryptMAC); 439 in.read(encryptKey); 440 in.read(decryptKey); 441 in.read(encryptIV); 442 in.read(decryptIV); 443 } catch (IOException ex) { 444 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 445 446 } 447 448 pendingCipherSuite.init(encryptKey, encryptIV, encryptMAC, decryptKey, decryptIV, decryptMAC); 449 450 currentHandshakeStep = SERVER_HELLO_DONE_MSG; 451 452 socket.sendCipherChangeSpec(pendingCipherSuite); 454 455 sendHandshakeFinished(); 457 458 } 459 460 SSLCipherSuite getPendingCipherSuite() { 461 return pendingCipherSuite; 462 } 463 464 void updateHandshakeHashes(byte[] data) { 465 466 log.debug(Messages.getString("SSLHandshakeProtocol.updatingHandshakeHashes")); 470 handshakeMD5.update(data, 0, data.length); 471 handshakeSHA1.update(data, 0, data.length); 472 } 473 474 private void completeHandshakeHashes() { 475 476 log.debug(Messages.getString("SSLHandshakeProtocol.completingHandshakeHashes")); 480 handshakeMD5.update((byte) 0x43); 482 handshakeMD5.update((byte) 0x4c); 483 handshakeMD5.update((byte) 0x4e); 484 handshakeMD5.update((byte) 0x54); 485 486 handshakeMD5.update(masterSecret, 0, masterSecret.length); 487 488 for (int i = 0; i < 48; i++) { 489 handshakeMD5.update((byte) 0x36); 490 } 491 492 byte[] tmp = new byte[handshakeMD5.getDigestSize()]; 493 handshakeMD5.doFinal(tmp, 0); 494 495 handshakeMD5.reset(); 496 497 log.debug(MessageFormat.format(Messages.getString("SSLHandshakeProtocol.masterSecret"), new Object [] { new Long (masterSecret.length), String.valueOf(masterSecret[0]) })); 501 handshakeMD5.update(masterSecret, 0, masterSecret.length); 502 for (int i = 0; i < 48; i++) { 503 handshakeMD5.update((byte) 0x5c); 504 } 505 506 handshakeMD5.update(tmp, 0, tmp.length); 507 508 handshakeSHA1.update((byte) 0x43); 509 handshakeSHA1.update((byte) 0x4c); 510 handshakeSHA1.update((byte) 0x4e); 511 handshakeSHA1.update((byte) 0x54); 512 513 handshakeSHA1.update(masterSecret, 0, masterSecret.length); 514 for (int i = 0; i < 40; i++) { 515 handshakeSHA1.update((byte) 0x36); 516 } 517 518 tmp = new byte[handshakeSHA1.getDigestSize()]; 519 handshakeSHA1.doFinal(tmp, 0); 520 521 handshakeSHA1.reset(); 522 handshakeSHA1.update(masterSecret, 0, masterSecret.length); 523 for (int i = 0; i < 40; i++) { 524 handshakeSHA1.update((byte) 0x5c); 525 } 526 527 handshakeSHA1.update(tmp, 0, tmp.length); 528 529 } 530 531 private void sendHandshakeFinished() throws SSLException { 532 533 completeHandshakeHashes(); 534 535 log.debug("Sending client FINISHED"); 539 byte[] msg = new byte[handshakeMD5.getDigestSize() + handshakeSHA1.getDigestSize()]; 540 541 handshakeMD5.doFinal(msg, 0); 542 handshakeSHA1.doFinal(msg, handshakeMD5.getDigestSize()); 543 544 sendMessage(FINISHED_MSG, msg); 545 546 currentHandshakeStep = FINISHED_MSG; 547 548 } 549 550 private void onCertificateMsg(byte[] msg) throws SSLException { 551 552 ByteArrayInputStream in = new ByteArrayInputStream (msg); 553 554 int length2 = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8 | (in.read() & 0xFF); 556 557 try { 558 559 boolean trusted = false; 560 561 X509Certificate chainCert; 562 while (in.available() > 0 && !trusted) { 563 int certlen = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8 | (in.read() & 0xFF); 566 567 DERInputStream der = new DERInputStream(in); 569 570 ASN1Sequence certificate = (ASN1Sequence) der.readObject(); 571 572 chainCert = new X509Certificate(X509CertificateStructure.getInstance(certificate)); 574 575 if (x509 == null) 576 x509 = chainCert; 577 578 try { 580 trusted = context.getTrustedCACerts().isTrustedCertificate(chainCert, 581 context.isInvalidCertificateAllowed(), 582 context.isUntrustedCertificateAllowed()); 583 } catch (SSLException ex1) { 584 log.warn(Messages.getString("SSLHandshakeProtocol.failedToVerifyCertAgainstTruststore"), ex1); } 588 } 589 590 if (!trusted) 591 throw new SSLException(SSLException.BAD_CERTIFICATE, 592 Messages.getString("SSLHandshakeProtocol.certInvalidOrUntrusted")); 594 } catch (IOException ex) { 595 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage()); 596 } 597 598 log.debug(Messages.getString("SSLHandshakeProtocol.x509Cert")); 601 log.debug(Messages.getString("SSLHandshakeProtocol.x509Cert.subject") + x509.getSubjectDN()); 603 log.debug(Messages.getString("SSLHandshakeProtocol.x509Cert.issuer") + x509.getIssuerDN()); 606 currentHandshakeStep = CERTIFICATE_MSG; 607 608 } 609 610 private void onServerHelloMsg(byte[] msg) throws SSLException { 611 612 try { 613 ByteArrayInputStream in = new ByteArrayInputStream (msg); 614 615 majorVersion = in.read(); 616 minorVersion = in.read(); 617 618 serverRandom = new byte[32]; 619 in.read(serverRandom); 620 621 sessionID = new byte[(in.read() & 0xFF)]; 622 in.read(sessionID); 623 624 cipherSuiteID = new SSLCipherSuiteID(in.read(), in.read()); 625 626 pendingCipherSuite = (SSLCipherSuite) context.getCipherSuiteClass(cipherSuiteID).newInstance(); 627 628 compressionID = in.read(); 629 630 currentHandshakeStep = SERVER_HELLO_MSG; 631 } catch (IllegalAccessException ex) { 632 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 633 634 } catch (InstantiationException ex) { 635 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 636 } catch (IOException ex) { 637 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 638 } 639 640 } 641 642 private void sendClientHello() throws SSLException { 643 644 log.debug(Messages.getString("SSLHandshakeProtocol.sendingClientHello")); 648 ByteArrayOutputStream msg = new ByteArrayOutputStream (); 649 650 try { 651 clientRandom = new byte[32]; 652 context.getRND().nextBytes(clientRandom); 653 long time = System.currentTimeMillis(); 654 clientRandom[0] = (byte) ((time >> 24) & 0xFF); 655 clientRandom[1] = (byte) ((time >> 16) & 0xFF); 656 clientRandom[2] = (byte) ((time >> 8) & 0xFF); 657 clientRandom[3] = (byte) (time & 0xFF); 658 659 msg.write(SSLTransportImpl.VERSION_MAJOR); 661 msg.write(SSLTransportImpl.VERSION_MINOR); 662 663 msg.write(clientRandom); 665 666 msg.write(0); 669 670 SSLCipherSuiteID[] ids = context.getCipherSuiteIDs(); 673 msg.write(0); 674 msg.write(ids.length * 2); 675 676 for (int i = 0; i < ids.length; i++) { 677 msg.write(ids[i].id1); 678 msg.write(ids[i].id2); 679 } 680 681 msg.write(1); 683 msg.write(0); 684 } catch (IOException ex) { 685 throw new SSLException(SSLException.INTERNAL_ERROR, ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage()); 686 } 687 688 sendMessage(CLIENT_HELLO_MSG, msg.toByteArray()); 689 690 currentHandshakeStep = CLIENT_HELLO_MSG; 691 } 692 } 693 | Popular Tags |