blob: b8395665d5a3373bb7f16de9f8d08f7533b2b9ac [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26
27package sun.security.ssl;
28
29import java.io.*;
30import java.util.*;
31import java.security.*;
32import java.security.MessageDigest;
33import java.security.NoSuchAlgorithmException;
34import java.security.AccessController;
35import java.security.AccessControlContext;
36import java.security.PrivilegedExceptionAction;
37import java.security.PrivilegedActionException;
38import java.security.cert.X509Certificate;
39
40import javax.crypto.*;
41import javax.crypto.spec.*;
42
43import javax.net.ssl.*;
44import sun.misc.HexDumpEncoder;
45
46import sun.security.internal.spec.*;
47import sun.security.internal.interfaces.TlsMasterSecret;
48
49import sun.security.ssl.HandshakeMessage.*;
50import sun.security.ssl.CipherSuite.*;
51
52/**
53 * Handshaker ... processes handshake records from an SSL V3.0
54 * data stream, handling all the details of the handshake protocol.
55 *
56 * Note that the real protocol work is done in two subclasses, the base
57 * class just provides the control flow and key generation framework.
58 *
59 * @author David Brownell
60 */
61abstract class Handshaker {
62
63 // current protocol version
64 ProtocolVersion protocolVersion;
65
66 // list of enabled protocols
67 ProtocolList enabledProtocols;
68
69 private boolean isClient;
70
71 SSLSocketImpl conn = null;
72 SSLEngineImpl engine = null;
73
74 HandshakeHash handshakeHash;
75 HandshakeInStream input;
76 HandshakeOutStream output;
77 int state;
78 SSLContextImpl sslContext;
79 RandomCookie clnt_random, svr_random;
80 SSLSessionImpl session;
81
82 // Temporary MD5 and SHA message digests. Must always be left
83 // in reset state after use.
84 private MessageDigest md5Tmp, shaTmp;
85
86 // list of enabled CipherSuites
87 CipherSuiteList enabledCipherSuites;
88
89 // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
90 CipherSuite cipherSuite;
91
92 // current key exchange. Never null, initially K_NULL
93 KeyExchange keyExchange;
94
95 /* True if this session is being resumed (fast handshake) */
96 boolean resumingSession;
97
98 /* True if it's OK to start a new SSL session */
99 boolean enableNewSession;
100
101 // Temporary storage for the individual keys. Set by
102 // calculateConnectionKeys() and cleared once the ciphers are
103 // activated.
104 private SecretKey clntWriteKey, svrWriteKey;
105 private IvParameterSpec clntWriteIV, svrWriteIV;
106 private SecretKey clntMacSecret, svrMacSecret;
107
108 /*
109 * Delegated task subsystem data structures.
110 *
111 * If thrown is set, we need to propagate this back immediately
112 * on entry into processMessage().
113 *
114 * Data is protected by the SSLEngine.this lock.
115 */
116 private volatile boolean taskDelegated = false;
117 private volatile DelegatedTask delegatedTask = null;
118 private volatile Exception thrown = null;
119
120 // Could probably use a java.util.concurrent.atomic.AtomicReference
121 // here instead of using this lock. Consider changing.
122 private Object thrownLock = new Object();
123
124 /* Class and subclass dynamic debugging support */
125 static final Debug debug = Debug.getInstance("ssl");
126
127 Handshaker(SSLSocketImpl c, SSLContextImpl context,
128 ProtocolList enabledProtocols, boolean needCertVerify,
129 boolean isClient) {
130 this.conn = c;
131 init(context, enabledProtocols, needCertVerify, isClient);
132 }
133
134 Handshaker(SSLEngineImpl engine, SSLContextImpl context,
135 ProtocolList enabledProtocols, boolean needCertVerify,
136 boolean isClient) {
137 this.engine = engine;
138 init(context, enabledProtocols, needCertVerify, isClient);
139 }
140
141 private void init(SSLContextImpl context, ProtocolList enabledProtocols,
142 boolean needCertVerify, boolean isClient) {
143
144 this.sslContext = context;
145 this.isClient = isClient;
146 enableNewSession = true;
147
148 setCipherSuite(CipherSuite.C_NULL);
149
150 md5Tmp = JsseJce.getMD5();
151 shaTmp = JsseJce.getSHA();
152
153 //
154 // We accumulate digests of the handshake messages so that
155 // we can read/write CertificateVerify and Finished messages,
156 // getting assurance against some particular active attacks.
157 //
158 handshakeHash = new HandshakeHash(needCertVerify);
159
160 setEnabledProtocols(enabledProtocols);
161
162 if (conn != null) {
163 conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
164 } else { // engine != null
165 engine.inputRecord.setHandshakeHash(handshakeHash);
166 }
167
168
169 //
170 // In addition to the connection state machine, controlling
171 // how the connection deals with the different sorts of records
172 // that get sent (notably handshake transitions!), there's
173 // also a handshaking state machine that controls message
174 // sequencing.
175 //
176 // It's a convenient artifact of the protocol that this can,
177 // with only a couple of minor exceptions, be driven by the
178 // type constant for the last message seen: except for the
179 // client's cert verify, those constants are in a convenient
180 // order to drastically simplify state machine checking.
181 //
182 state = -1;
183 }
184
185 /*
186 * Reroutes calls to the SSLSocket or SSLEngine (*SE).
187 *
188 * We could have also done it by extra classes
189 * and letting them override, but this seemed much
190 * less involved.
191 */
192 void fatalSE(byte b, String diagnostic) throws IOException {
193 fatalSE(b, diagnostic, null);
194 }
195
196 void fatalSE(byte b, Throwable cause) throws IOException {
197 fatalSE(b, null, cause);
198 }
199
200 void fatalSE(byte b, String diagnostic, Throwable cause)
201 throws IOException {
202 if (conn != null) {
203 conn.fatal(b, diagnostic, cause);
204 } else {
205 engine.fatal(b, diagnostic, cause);
206 }
207 }
208
209 void warningSE(byte b) {
210 if (conn != null) {
211 conn.warning(b);
212 } else {
213 engine.warning(b);
214 }
215 }
216
217 String getHostSE() {
218 if (conn != null) {
219 return conn.getHost();
220 } else {
221 return engine.getPeerHost();
222 }
223 }
224
225 String getHostAddressSE() {
226 if (conn != null) {
227 return conn.getInetAddress().getHostAddress();
228 } else {
229 /*
230 * This is for caching only, doesn't matter that's is really
231 * a hostname. The main thing is that it doesn't do
232 * a reverse DNS lookup, potentially slowing things down.
233 */
234 return engine.getPeerHost();
235 }
236 }
237
238 boolean isLoopbackSE() {
239 if (conn != null) {
240 return conn.getInetAddress().isLoopbackAddress();
241 } else {
242 return false;
243 }
244 }
245
246 int getPortSE() {
247 if (conn != null) {
248 return conn.getPort();
249 } else {
250 return engine.getPeerPort();
251 }
252 }
253
254 int getLocalPortSE() {
255 if (conn != null) {
256 return conn.getLocalPort();
257 } else {
258 return -1;
259 }
260 }
261
262 String getHostnameVerificationSE() {
263 if (conn != null) {
264 return conn.getHostnameVerification();
265 } else {
266 return engine.getHostnameVerification();
267 }
268 }
269
270 AccessControlContext getAccSE() {
271 if (conn != null) {
272 return conn.getAcc();
273 } else {
274 return engine.getAcc();
275 }
276 }
277
278 private void setVersionSE(ProtocolVersion protocolVersion) {
279 if (conn != null) {
280 conn.setVersion(protocolVersion);
281 } else {
282 engine.setVersion(protocolVersion);
283 }
284 }
285
286 /**
287 * Set the active protocol version and propagate it to the SSLSocket
288 * and our handshake streams. Called from ClientHandshaker
289 * and ServerHandshaker with the negotiated protocol version.
290 */
291 void setVersion(ProtocolVersion protocolVersion) {
292 this.protocolVersion = protocolVersion;
293 setVersionSE(protocolVersion);
294 output.r.setVersion(protocolVersion);
295 }
296
297
298 /**
299 * Set the enabled protocols. Called from the constructor or
300 * SSLSocketImpl.setEnabledProtocols() (if the handshake is not yet
301 * in progress).
302 */
303 void setEnabledProtocols(ProtocolList enabledProtocols) {
304 this.enabledProtocols = enabledProtocols;
305
306 // temporary protocol version until the actual protocol version
307 // is negotiated in the Hello exchange. This affects the record
308 // version we sent with the ClientHello. Using max() as the record
309 // version is not really correct but some implementations fail to
310 // correctly negotiate TLS otherwise.
311 protocolVersion = enabledProtocols.max;
312
313 ProtocolVersion helloVersion = enabledProtocols.helloVersion;
314
315 input = new HandshakeInStream(handshakeHash);
316
317 if (conn != null) {
318 output = new HandshakeOutStream(protocolVersion, helloVersion,
319 handshakeHash, conn);
320 conn.getAppInputStream().r.setHelloVersion(helloVersion);
321 } else {
322 output = new HandshakeOutStream(protocolVersion, helloVersion,
323 handshakeHash, engine);
324 engine.outputRecord.setHelloVersion(helloVersion);
325 }
326
327 }
328
329 /**
330 * Set cipherSuite and keyExchange to the given CipherSuite.
331 * Does not perform any verification that this is a valid selection,
332 * this must be done before calling this method.
333 */
334 void setCipherSuite(CipherSuite s) {
335 this.cipherSuite = s;
336 this.keyExchange = s.keyExchange;
337 }
338
339 /**
340 * Check if the given ciphersuite is enabled and available.
341 * (Enabled ciphersuites are always available unless the status has
342 * changed due to change in JCE providers since it was enabled).
343 * Does not check if the required server certificates are available.
344 */
345 boolean isEnabled(CipherSuite s) {
346 return enabledCipherSuites.contains(s) && s.isAvailable();
347 }
348
349 /**
350 * As long as handshaking has not started, we can
351 * change whether session creations are allowed.
352 *
353 * Callers should do their own checking if handshaking
354 * has started.
355 */
356 void setEnableSessionCreation(boolean newSessions) {
357 enableNewSession = newSessions;
358 }
359
360 /**
361 * Create a new read cipher and return it to caller.
362 */
363 CipherBox newReadCipher() throws NoSuchAlgorithmException {
364 BulkCipher cipher = cipherSuite.cipher;
365 CipherBox box;
366 if (isClient) {
367 box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
368 false);
369 svrWriteKey = null;
370 svrWriteIV = null;
371 } else {
372 box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
373 false);
374 clntWriteKey = null;
375 clntWriteIV = null;
376 }
377 return box;
378 }
379
380 /**
381 * Create a new write cipher and return it to caller.
382 */
383 CipherBox newWriteCipher() throws NoSuchAlgorithmException {
384 BulkCipher cipher = cipherSuite.cipher;
385 CipherBox box;
386 if (isClient) {
387 box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV,
388 true);
389 clntWriteKey = null;
390 clntWriteIV = null;
391 } else {
392 box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV,
393 true);
394 svrWriteKey = null;
395 svrWriteIV = null;
396 }
397 return box;
398 }
399
400 /**
401 * Create a new read MAC and return it to caller.
402 */
403 MAC newReadMAC() throws NoSuchAlgorithmException, InvalidKeyException {
404 MacAlg macAlg = cipherSuite.macAlg;
405 MAC mac;
406 if (isClient) {
407 mac = macAlg.newMac(protocolVersion, svrMacSecret);
408 svrMacSecret = null;
409 } else {
410 mac = macAlg.newMac(protocolVersion, clntMacSecret);
411 clntMacSecret = null;
412 }
413 return mac;
414 }
415
416 /**
417 * Create a new write MAC and return it to caller.
418 */
419 MAC newWriteMAC() throws NoSuchAlgorithmException, InvalidKeyException {
420 MacAlg macAlg = cipherSuite.macAlg;
421 MAC mac;
422 if (isClient) {
423 mac = macAlg.newMac(protocolVersion, clntMacSecret);
424 clntMacSecret = null;
425 } else {
426 mac = macAlg.newMac(protocolVersion, svrMacSecret);
427 svrMacSecret = null;
428 }
429 return mac;
430 }
431
432 /*
433 * Returns true iff the handshake sequence is done, so that
434 * this freshly created session can become the current one.
435 */
436 boolean isDone() {
437 return state == HandshakeMessage.ht_finished;
438 }
439
440
441 /*
442 * Returns the session which was created through this
443 * handshake sequence ... should be called after isDone()
444 * returns true.
445 */
446 SSLSessionImpl getSession() {
447 return session;
448 }
449
450 /*
451 * This routine is fed SSL handshake records when they become available,
452 * and processes messages found therein.
453 */
454 void process_record(InputRecord r, boolean expectingFinished)
455 throws IOException {
456
457 checkThrown();
458
459 /*
460 * Store the incoming handshake data, then see if we can
461 * now process any completed handshake messages
462 */
463 input.incomingRecord(r);
464
465 /*
466 * We don't need to create a separate delegatable task
467 * for finished messages.
468 */
469 if ((conn != null) || expectingFinished) {
470 processLoop();
471 } else {
472 delegateTask(new PrivilegedExceptionAction<Void>() {
473 public Void run() throws Exception {
474 processLoop();
475 return null;
476 }
477 });
478 }
479 }
480
481 /*
482 * On input, we hash messages one at a time since servers may need
483 * to access an intermediate hash to validate a CertificateVerify
484 * message.
485 *
486 * Note that many handshake messages can come in one record (and often
487 * do, to reduce network resource utilization), and one message can also
488 * require multiple records (e.g. very large Certificate messages).
489 */
490 void processLoop() throws IOException {
491
492 while (input.available() > 0) {
493 byte messageType;
494 int messageLen;
495
496 /*
497 * See if we can read the handshake message header, and
498 * then the entire handshake message. If not, wait till
499 * we can read and process an entire message.
500 */
501 input.mark(4);
502
503 messageType = (byte)input.getInt8();
504 messageLen = input.getInt24();
505
506 if (input.available() < messageLen) {
507 input.reset();
508 return;
509 }
510
511 /*
512 * Process the messsage. We require
513 * that processMessage() consumes the entire message. In
514 * lieu of explicit error checks (how?!) we assume that the
515 * data will look like garbage on encoding/processing errors,
516 * and that other protocol code will detect such errors.
517 *
518 * Note that digesting is normally deferred till after the
519 * message has been processed, though to process at least the
520 * client's Finished message (i.e. send the server's) we need
521 * to acccelerate that digesting.
522 *
523 * Also, note that hello request messages are never hashed;
524 * that includes the hello request header, too.
525 */
526 if (messageType == HandshakeMessage.ht_hello_request) {
527 input.reset();
528 processMessage(messageType, messageLen);
529 input.ignore(4 + messageLen);
530 } else {
531 input.mark(messageLen);
532 processMessage(messageType, messageLen);
533 input.digestNow();
534 }
535 }
536 }
537
538
539 /**
540 * Returns true iff the handshaker has sent any messages.
541 * Server kickstarting is not as neat as it should be; we
542 * need to create a new handshaker, this method lets us
543 * know if we should.
544 */
545 boolean started() {
546 return state >= 0;
547 }
548
549
550 /*
551 * Used to kickstart the negotiation ... either writing a
552 * ClientHello or a HelloRequest as appropriate, whichever
553 * the subclass returns. NOP if handshaking's already started.
554 */
555 void kickstart() throws IOException {
556 if (state >= 0) {
557 return;
558 }
559 HandshakeMessage m = getKickstartMessage();
560
561 if (debug != null && Debug.isOn("handshake")) {
562 m.print(System.out);
563 }
564 m.write(output);
565 output.flush();
566
567 state = m.messageType();
568 }
569
570 /**
571 * Both client and server modes can start handshaking; but the
572 * message they send to do so is different.
573 */
574 abstract HandshakeMessage getKickstartMessage() throws SSLException;
575
576 /*
577 * Client and Server side protocols are each driven though this
578 * call, which processes a single message and drives the appropriate
579 * side of the protocol state machine (depending on the subclass).
580 */
581 abstract void processMessage(byte messageType, int messageLen)
582 throws IOException;
583
584 /*
585 * Most alerts in the protocol relate to handshaking problems.
586 * Alerts are detected as the connection reads data.
587 */
588 abstract void handshakeAlert(byte description) throws SSLProtocolException;
589
590 /*
591 * Sends a change cipher spec message and updates the write side
592 * cipher state so that future messages use the just-negotiated spec.
593 */
594 void sendChangeCipherSpec(Finished mesg, boolean lastMessage)
595 throws IOException {
596
597 output.flush(); // i.e. handshake data
598
599 /*
600 * The write cipher state is protected by the connection write lock
601 * so we must grab it while making the change. We also
602 * make sure no writes occur between sending the ChangeCipherSpec
603 * message, installing the new cipher state, and sending the
604 * Finished message.
605 *
606 * We already hold SSLEngine/SSLSocket "this" by virtue
607 * of this being called from the readRecord code.
608 */
609 OutputRecord r;
610 if (conn != null) {
611 r = new OutputRecord(Record.ct_change_cipher_spec);
612 } else {
613 r = new EngineOutputRecord(Record.ct_change_cipher_spec, engine);
614 }
615
616 r.setVersion(protocolVersion);
617 r.write(1); // single byte of data
618
619 if (conn != null) {
620 synchronized (conn.writeLock) {
621 conn.writeRecord(r);
622 conn.changeWriteCiphers();
623 if (debug != null && Debug.isOn("handshake")) {
624 mesg.print(System.out);
625 }
626 mesg.write(output);
627 output.flush();
628 }
629 } else {
630 synchronized (engine.writeLock) {
631 engine.writeRecord((EngineOutputRecord)r);
632 engine.changeWriteCiphers();
633 if (debug != null && Debug.isOn("handshake")) {
634 mesg.print(System.out);
635 }
636 mesg.write(output);
637
638 if (lastMessage) {
639 output.setFinishedMsg();
640 }
641 output.flush();
642 }
643 }
644 }
645
646 /*
647 * Single access point to key calculation logic. Given the
648 * pre-master secret and the nonces from client and server,
649 * produce all the keying material to be used.
650 */
651 void calculateKeys(SecretKey preMasterSecret, ProtocolVersion version) {
652 SecretKey master = calculateMasterSecret(preMasterSecret, version);
653 session.setMasterSecret(master);
654 calculateConnectionKeys(master);
655 }
656
657
658 /*
659 * Calculate the master secret from its various components. This is
660 * used for key exchange by all cipher suites.
661 *
662 * The master secret is the catenation of three MD5 hashes, each
663 * consisting of the pre-master secret and a SHA1 hash. Those three
664 * SHA1 hashes are of (different) constant strings, the pre-master
665 * secret, and the nonces provided by the client and the server.
666 */
667 private SecretKey calculateMasterSecret(SecretKey preMasterSecret,
668 ProtocolVersion requestedVersion) {
669 TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec
670 (preMasterSecret, protocolVersion.major, protocolVersion.minor,
671 clnt_random.random_bytes, svr_random.random_bytes);
672
673 if (debug != null && Debug.isOn("keygen")) {
674 HexDumpEncoder dump = new HexDumpEncoder();
675
676 System.out.println("SESSION KEYGEN:");
677
678 System.out.println("PreMaster Secret:");
679 printHex(dump, preMasterSecret.getEncoded());
680
681 // Nonces are dumped with connection keygen, no
682 // benefit to doing it twice
683 }
684
685 SecretKey masterSecret;
686 try {
687 KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsMasterSecret");
688 kg.init(spec);
689 masterSecret = kg.generateKey();
690 } catch (GeneralSecurityException e) {
691 // For RSA premaster secrets, do not signal a protocol error
692 // due to the Bleichenbacher attack. See comments further down.
693 if (!preMasterSecret.getAlgorithm().equals("TlsRsaPremasterSecret")) {
694 throw new ProviderException(e);
695 }
696 if (debug != null && Debug.isOn("handshake")) {
697 System.out.println("RSA master secret generation error:");
698 e.printStackTrace(System.out);
699 System.out.println("Generating new random premaster secret");
700 }
701 preMasterSecret = RSAClientKeyExchange.generateDummySecret(protocolVersion);
702 // recursive call with new premaster secret
703 return calculateMasterSecret(preMasterSecret, null);
704 }
705
706 // if no version check requested (client side handshake),
707 // or version information is not available (not an RSA premaster secret),
708 // return master secret immediately.
709 if ((requestedVersion == null) || !(masterSecret instanceof TlsMasterSecret)) {
710 return masterSecret;
711 }
712 TlsMasterSecret tlsKey = (TlsMasterSecret)masterSecret;
713 int major = tlsKey.getMajorVersion();
714 int minor = tlsKey.getMinorVersion();
715 if ((major < 0) || (minor < 0)) {
716 return masterSecret;
717 }
718
719 // check if the premaster secret version is ok
720 // the specification says that it must be the maximum version supported
721 // by the client from its ClientHello message. However, many
722 // implementations send the negotiated version, so accept both
723 // NOTE that we may be comparing two unsupported version numbers in
724 // the second case, which is why we cannot use object reference
725 // equality in this special case
726 ProtocolVersion premasterVersion = ProtocolVersion.valueOf(major, minor);
727 boolean versionMismatch = (premasterVersion != protocolVersion) &&
728 (premasterVersion.v != requestedVersion.v);
729
730
731 if (versionMismatch == false) {
732 // check passed, return key
733 return masterSecret;
734 }
735
736 // Due to the Bleichenbacher attack, do not signal a protocol error.
737 // Generate a random premaster secret and continue with the handshake,
738 // which will fail when verifying the finished messages.
739 // For more information, see comments in PreMasterSecret.
740 if (debug != null && Debug.isOn("handshake")) {
741 System.out.println("RSA PreMasterSecret version error: expected"
742 + protocolVersion + " or " + requestedVersion + ", decrypted: "
743 + premasterVersion);
744 System.out.println("Generating new random premaster secret");
745 }
746 preMasterSecret = RSAClientKeyExchange.generateDummySecret(protocolVersion);
747 // recursive call with new premaster secret
748 return calculateMasterSecret(preMasterSecret, null);
749 }
750
751 /*
752 * Calculate the keys needed for this connection, once the session's
753 * master secret has been calculated. Uses the master key and nonces;
754 * the amount of keying material generated is a function of the cipher
755 * suite that's been negotiated.
756 *
757 * This gets called both on the "full handshake" (where we exchanged
758 * a premaster secret and started a new session) as well as on the
759 * "fast handshake" (where we just resumed a pre-existing session).
760 */
761 void calculateConnectionKeys(SecretKey masterKey) {
762 /*
763 * For both the read and write sides of the protocol, we use the
764 * master to generate MAC secrets and cipher keying material. Block
765 * ciphers need initialization vectors, which we also generate.
766 *
767 * First we figure out how much keying material is needed.
768 */
769 int hashSize = cipherSuite.macAlg.size;
770 boolean is_exportable = cipherSuite.exportable;
771 BulkCipher cipher = cipherSuite.cipher;
772 int keySize = cipher.keySize;
773 int ivSize = cipher.ivSize;
774 int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0;
775
776 TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec
777 (masterKey, protocolVersion.major, protocolVersion.minor,
778 clnt_random.random_bytes, svr_random.random_bytes,
779 cipher.algorithm, cipher.keySize, expandedKeySize,
780 cipher.ivSize, hashSize);
781
782 try {
783 KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsKeyMaterial");
784 kg.init(spec);
785 TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey();
786
787 clntWriteKey = keySpec.getClientCipherKey();
788 svrWriteKey = keySpec.getServerCipherKey();
789
790 clntWriteIV = keySpec.getClientIv();
791 svrWriteIV = keySpec.getServerIv();
792
793 clntMacSecret = keySpec.getClientMacKey();
794 svrMacSecret = keySpec.getServerMacKey();
795 } catch (GeneralSecurityException e) {
796 throw new ProviderException(e);
797 }
798
799 //
800 // Dump the connection keys as they're generated.
801 //
802 if (debug != null && Debug.isOn("keygen")) {
803 synchronized (System.out) {
804 HexDumpEncoder dump = new HexDumpEncoder();
805
806 System.out.println("CONNECTION KEYGEN:");
807
808 // Inputs:
809 System.out.println("Client Nonce:");
810 printHex(dump, clnt_random.random_bytes);
811 System.out.println("Server Nonce:");
812 printHex(dump, svr_random.random_bytes);
813 System.out.println("Master Secret:");
814 printHex(dump, masterKey.getEncoded());
815
816 // Outputs:
817 System.out.println("Client MAC write Secret:");
818 printHex(dump, clntMacSecret.getEncoded());
819 System.out.println("Server MAC write Secret:");
820 printHex(dump, svrMacSecret.getEncoded());
821
822 if (clntWriteKey != null) {
823 System.out.println("Client write key:");
824 printHex(dump, clntWriteKey.getEncoded());
825 System.out.println("Server write key:");
826 printHex(dump, svrWriteKey.getEncoded());
827 } else {
828 System.out.println("... no encryption keys used");
829 }
830
831 if (clntWriteIV != null) {
832 System.out.println("Client write IV:");
833 printHex(dump, clntWriteIV.getIV());
834 System.out.println("Server write IV:");
835 printHex(dump, svrWriteIV.getIV());
836 } else {
837 System.out.println("... no IV used for this cipher");
838 }
839 System.out.flush();
840 }
841 }
842 }
843
844 private static void printHex(HexDumpEncoder dump, byte[] bytes) {
845 if (bytes == null) {
846 System.out.println("(key bytes not available)");
847 } else {
848 try {
849 dump.encodeBuffer(bytes, System.out);
850 } catch (IOException e) {
851 // just for debugging, ignore this
852 }
853 }
854 }
855
856 /**
857 * Throw an SSLException with the specified message and cause.
858 * Shorthand until a new SSLException constructor is added.
859 * This method never returns.
860 */
861 static void throwSSLException(String msg, Throwable cause)
862 throws SSLException {
863 SSLException e = new SSLException(msg);
864 e.initCause(cause);
865 throw e;
866 }
867
868
869 /*
870 * Implement a simple task delegator.
871 *
872 * We are currently implementing this as a single delegator, may
873 * try for parallel tasks later. Client Authentication could
874 * benefit from this, where ClientKeyExchange/CertificateVerify
875 * could be carried out in parallel.
876 */
877 class DelegatedTask<E> implements Runnable {
878
879 private PrivilegedExceptionAction<E> pea;
880
881 DelegatedTask(PrivilegedExceptionAction<E> pea) {
882 this.pea = pea;
883 }
884
885 public void run() {
886 synchronized (engine) {
887 try {
888 AccessController.doPrivileged(pea, engine.getAcc());
889 } catch (PrivilegedActionException pae) {
890 thrown = pae.getException();
891 } catch (RuntimeException rte) {
892 thrown = rte;
893 }
894 delegatedTask = null;
895 taskDelegated = false;
896 }
897 }
898 }
899
900 private <T> void delegateTask(PrivilegedExceptionAction<T> pea) {
901 delegatedTask = new DelegatedTask<T>(pea);
902 taskDelegated = false;
903 thrown = null;
904 }
905
906 DelegatedTask getTask() {
907 if (!taskDelegated) {
908 taskDelegated = true;
909 return delegatedTask;
910 } else {
911 return null;
912 }
913 }
914
915 /*
916 * See if there are any tasks which need to be delegated
917 *
918 * Locked by SSLEngine.this.
919 */
920 boolean taskOutstanding() {
921 return (delegatedTask != null);
922 }
923
924 /*
925 * The previous caller failed for some reason, report back the
926 * Exception. We won't worry about Error's.
927 *
928 * Locked by SSLEngine.this.
929 */
930 void checkThrown() throws SSLException {
931 synchronized (thrownLock) {
932 if (thrown != null) {
933
934 String msg = thrown.getMessage();
935
936 if (msg == null) {
937 msg = "Delegated task threw Exception/Error";
938 }
939
940 /*
941 * See what the underlying type of exception is. We should
942 * throw the same thing. Chain thrown to the new exception.
943 */
944 Exception e = thrown;
945 thrown = null;
946
947 if (e instanceof RuntimeException) {
948 throw (RuntimeException)
949 new RuntimeException(msg).initCause(e);
950 } else if (e instanceof SSLHandshakeException) {
951 throw (SSLHandshakeException)
952 new SSLHandshakeException(msg).initCause(e);
953 } else if (e instanceof SSLKeyException) {
954 throw (SSLKeyException)
955 new SSLKeyException(msg).initCause(e);
956 } else if (e instanceof SSLPeerUnverifiedException) {
957 throw (SSLPeerUnverifiedException)
958 new SSLPeerUnverifiedException(msg).initCause(e);
959 } else if (e instanceof SSLProtocolException) {
960 throw (SSLProtocolException)
961 new SSLProtocolException(msg).initCause(e);
962 } else {
963 /*
964 * If it's SSLException or any other Exception,
965 * we'll wrap it in an SSLException.
966 */
967 throw (SSLException)
968 new SSLException(msg).initCause(e);
969 }
970 }
971 }
972 }
973}