1 /* ServerHandshake.java -- the server-side handshake.
2    Copyright (C) 2006  Free Software Foundation, Inc.
3 
4 This file is a part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at
9 your option) any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 USA
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version.  */
37 
38 
39 package gnu.javax.net.ssl.provider;
40 
41 import static gnu.javax.net.ssl.provider.Handshake.Type.*;
42 import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
43 import static gnu.javax.net.ssl.provider.ServerHandshake.State.*;
44 
45 import gnu.classpath.debug.Component;
46 import gnu.java.security.action.GetSecurityPropertyAction;
47 import gnu.javax.crypto.key.dh.GnuDHPublicKey;
48 import gnu.javax.net.ssl.AbstractSessionContext;
49 import gnu.javax.net.ssl.Session;
50 import gnu.javax.net.ssl.provider.Alert.Description;
51 import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
52 
53 import java.nio.ByteBuffer;
54 
55 import java.security.AccessController;
56 import java.security.InvalidAlgorithmParameterException;
57 import java.security.InvalidKeyException;
58 import java.security.KeyManagementException;
59 import java.security.KeyPair;
60 import java.security.KeyPairGenerator;
61 import java.security.MessageDigest;
62 import java.security.NoSuchAlgorithmException;
63 import java.security.Principal;
64 import java.security.PrivateKey;
65 import java.security.SignatureException;
66 import java.security.cert.CertificateException;
67 import java.security.cert.X509Certificate;
68 import java.util.ArrayList;
69 import java.util.Arrays;
70 import java.util.HashSet;
71 import java.util.List;
72 import java.util.logging.Level;
73 import java.util.zip.Deflater;
74 import java.util.zip.Inflater;
75 
76 import javax.crypto.BadPaddingException;
77 import javax.crypto.Cipher;
78 import javax.crypto.IllegalBlockSizeException;
79 import javax.crypto.NoSuchPaddingException;
80 import javax.crypto.SecretKey;
81 import javax.crypto.interfaces.DHPrivateKey;
82 import javax.crypto.interfaces.DHPublicKey;
83 import javax.crypto.spec.DHParameterSpec;
84 import javax.crypto.spec.SecretKeySpec;
85 import javax.net.ssl.SSLException;
86 import javax.net.ssl.SSLPeerUnverifiedException;
87 import javax.net.ssl.SSLSession;
88 import javax.net.ssl.X509ExtendedKeyManager;
89 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
90 import javax.security.auth.x500.X500Principal;
91 
92 class ServerHandshake extends AbstractHandshake
93 {
94   /**
95    * Handshake state enumeration.
96    */
97   static enum State
98   {
99     WRITE_HELLO_REQUEST (true, false),
100     WRITE_SERVER_HELLO (true, false),
101     WRITE_CERTIFICATE (true, false),
102     WRITE_SERVER_KEY_EXCHANGE (true, false),
103     WRITE_CERTIFICATE_REQUEST (true, false),
104     WRITE_SERVER_HELLO_DONE (true, false),
105     WRITE_FINISHED (true, false),
106     READ_CLIENT_HELLO (false, true),
107     READ_CERTIFICATE (false, true),
108     READ_CLIENT_KEY_EXCHANGE (false, true),
109     READ_CERTIFICATE_VERIFY (false, true),
110     READ_FINISHED (false, true),
111     DONE (false, false);
112 
113     private final boolean isWriteState;
114     private final boolean isReadState;
115 
State(final boolean isWriteState, final boolean isReadState)116     private State(final boolean isWriteState, final boolean isReadState)
117     {
118       this.isWriteState = isWriteState;
119       this.isReadState = isReadState;
120     }
121 
isReadState()122     boolean isReadState()
123     {
124       return isReadState;
125     }
126 
isWriteState()127     boolean isWriteState()
128     {
129       return isWriteState;
130     }
131   }
132 
133   private State state;
134 
135   /* Handshake result fields. */
136   private ByteBuffer outBuffer;
137   private boolean clientHadExtensions = false;
138   private boolean continuedSession = false;
139   private ServerNameList requestedNames = null;
140   private String keyAlias = null;
141   private X509Certificate clientCert = null;
142   private X509Certificate localCert = null;
143   private boolean helloV2 = false;
144   private KeyPair dhPair;
145   private PrivateKey serverKey;
146 
147   // Delegated tasks we use.
148   private GenDH genDH;
149   private CertVerifier certVerifier;
150   private CertLoader certLoader;
151   private DelegatedTask keyExchangeTask;
152 
ServerHandshake(boolean writeHelloRequest, final SSLEngineImpl engine)153   ServerHandshake (boolean writeHelloRequest, final SSLEngineImpl engine)
154     throws NoSuchAlgorithmException
155   {
156     super(engine);
157     if (writeHelloRequest)
158       state = WRITE_HELLO_REQUEST;
159     else
160       state = READ_CLIENT_HELLO;
161     handshakeOffset = 0;
162   }
163 
164   /**
165    * Choose the protocol version. Here we choose the largest protocol
166    * version we support that is not greater than the client's
167    * requested version.
168    */
chooseProtocol(final ProtocolVersion clientVersion, final String[] enabledVersions)169   private static ProtocolVersion chooseProtocol (final ProtocolVersion clientVersion,
170                                                  final String[] enabledVersions)
171     throws SSLException
172   {
173     ProtocolVersion version = null;
174     for (int i = 0; i < enabledVersions.length; i++)
175       {
176         ProtocolVersion v = ProtocolVersion.forName (enabledVersions[i]);
177         if (v.compareTo (clientVersion) <= 0)
178           {
179             if (version == null
180                 || v.compareTo (version) > 0)
181               version = v;
182           }
183       }
184 
185     // The client requested a protocol version too old, or no protocol
186     // versions are enabled.
187     if (version == null)
188       throw new SSLException ("no acceptable protocol version available");
189     return version;
190   }
191 
192   /**
193    * Choose the first cipher suite in the client's requested list that
194    * we have enabled.
195    */
chooseSuite(final CipherSuiteList clientSuites, final String[] enabledSuites, final ProtocolVersion version)196   private CipherSuite chooseSuite (final CipherSuiteList clientSuites,
197                                    final String[] enabledSuites,
198                                    final ProtocolVersion version)
199     throws SSLException
200   {
201     // Figure out which SignatureAlgorithms we can support.
202     HashSet<KeyExchangeAlgorithm> kexes = new HashSet<KeyExchangeAlgorithm>(8);
203 
204     kexes.add(NONE);
205     X509ExtendedKeyManager km = engine.contextImpl.keyManager;
206     if (km != null)
207       {
208         if (km.getServerAliases(DH_DSS.name(), null).length > 0)
209           kexes.add(DH_DSS);
210         if (km.getServerAliases(DH_RSA.name(), null).length > 0)
211           kexes.add(DH_RSA);
212         if (km.getServerAliases(DHE_DSS.name(), null).length > 0)
213           kexes.add(DHE_DSS);
214         if (km.getServerAliases(DHE_RSA.name(), null).length > 0)
215           kexes.add(DHE_RSA);
216         if (km.getServerAliases(RSA.name(), null).length > 0)
217           kexes.add(RSA);
218         if (km.getServerAliases(RSA_PSK.name(), null).length > 0
219             && engine.contextImpl.pskManager != null)
220           kexes.add(RSA_PSK);
221       }
222     if (engine.contextImpl.pskManager != null)
223       {
224         kexes.add(DHE_PSK);
225         kexes.add(PSK);
226       }
227 
228     if (Debug.DEBUG)
229       logger.logv(Component.SSL_HANDSHAKE,
230                   "we have certs for key exchange algorithms {0}", kexes);
231 
232     HashSet<CipherSuite> suites = new HashSet<CipherSuite>();
233     for (String s : enabledSuites)
234       {
235         CipherSuite suite = CipherSuite.forName(s);
236         if (suite == null)
237           continue;
238         if (!kexes.contains(suite.keyExchangeAlgorithm()))
239           continue;
240         suites.add(suite);
241       }
242     for (CipherSuite suite : clientSuites)
243       {
244         CipherSuite resolved = suite.resolve();
245         if (!resolved.isResolved())
246           continue;
247         if (suites.contains(resolved))
248           return resolved;
249       }
250 
251     // We didn't find a match?
252     throw new AlertException(new Alert(Alert.Level.FATAL,
253                                        Alert.Description.INSUFFICIENT_SECURITY));
254   }
255 
256   /**
257    * Choose a compression method that we support, among the client's
258    * requested compression methods. We prefer ZLIB over NONE in this
259    * implementation.
260    *
261    * XXX Maybe consider implementing lzo (GNUTLS supports that).
262    */
chooseCompression(final CompressionMethodList comps)263   private static CompressionMethod chooseCompression (final CompressionMethodList comps)
264     throws SSLException
265   {
266     GetSecurityPropertyAction gspa
267       = new GetSecurityPropertyAction("jessie.enable.compression");
268     String enable = AccessController.doPrivileged(gspa);
269     // Scan for ZLIB first.
270     if (Boolean.valueOf(enable))
271       {
272         for (CompressionMethod cm : comps)
273           {
274             if (cm.equals (CompressionMethod.ZLIB))
275               return CompressionMethod.ZLIB;
276           }
277       }
278     for (CompressionMethod cm : comps)
279       {
280         if (cm.equals (CompressionMethod.NULL))
281           return CompressionMethod.NULL;
282       }
283 
284     throw new SSLException ("no supported compression method");
285   }
286 
doHash()287   protected @Override boolean doHash()
288   {
289     boolean b = helloV2;
290     helloV2 = false;
291     return (state != WRITE_HELLO_REQUEST) && !b;
292   }
293 
implHandleInput()294   public @Override HandshakeStatus implHandleInput()
295     throws SSLException
296   {
297     if (state == DONE)
298       return HandshakeStatus.FINISHED;
299 
300     if (state.isWriteState()
301         || (outBuffer != null && outBuffer.hasRemaining()))
302       return HandshakeStatus.NEED_WRAP;
303 
304     // Copy the current buffer, and prepare it for reading.
305     ByteBuffer buffer = handshakeBuffer.duplicate ();
306     buffer.flip();
307     buffer.position(handshakeOffset);
308     Handshake handshake = new Handshake(buffer.slice(),
309                                         engine.session().suite,
310                                         engine.session().version);
311 
312     if (Debug.DEBUG)
313       logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
314                   state, handshake);
315 
316     switch (state)
317       {
318         // Client Hello.
319         //
320         // This message is sent by the client to initiate a new handshake.
321         // On a new connection, it is the first handshake message sent.
322         //
323         // The state of the handshake, after this message is processed,
324         // will have a protocol version, cipher suite, compression method,
325         // session ID, and various extensions (that the server also
326         // supports).
327         case READ_CLIENT_HELLO:
328           if (handshake.type () != CLIENT_HELLO)
329             throw new AlertException(new Alert(Alert.Level.FATAL,
330                                                Alert.Description.UNEXPECTED_MESSAGE));
331 
332           {
333             ClientHello hello = (ClientHello) handshake.body ();
334             engine.session().version
335               = chooseProtocol (hello.version (),
336                                 engine.getEnabledProtocols ());
337             engine.session().suite =
338               chooseSuite (hello.cipherSuites (),
339                            engine.getEnabledCipherSuites (),
340                            engine.session().version);
341             compression = chooseCompression (hello.compressionMethods ());
342             if (Debug.DEBUG)
343               logger.logv(Component.SSL_HANDSHAKE,
344                           "chose version:{0} suite:{1} compression:{2}",
345                           engine.session().version, engine.session().suite,
346                           compression);
347             clientRandom = hello.random().copy();
348             byte[] sessionId = hello.sessionId();
349             if (hello.hasExtensions())
350               {
351                 ExtensionList exts = hello.extensions();
352                 clientHadExtensions = exts.size() > 0;
353                 for (Extension e : hello.extensions())
354                   {
355                     Extension.Type type = e.type();
356                     if (type == null)
357                       continue;
358                     switch (type)
359                     {
360                     case TRUNCATED_HMAC:
361                       engine.session().setTruncatedMac(true);
362                       break;
363 
364                     case MAX_FRAGMENT_LENGTH:
365                       MaxFragmentLength len = (MaxFragmentLength) e.value();
366                       engine.session().maxLength = len;
367                       engine.session().setApplicationBufferSize(len.maxLength());
368                       break;
369 
370                     case SERVER_NAME:
371                       requestedNames = (ServerNameList) e.value();
372                       List<String> names
373                         = new ArrayList<String>(requestedNames.size());
374                       for (ServerNameList.ServerName name : requestedNames)
375                         names.add(name.name());
376                       engine.session().putValue("gnu.javax.net.ssl.RequestedServerNames", names);
377                       break;
378 
379                     default:
380                       logger.log(Level.INFO, "skipping unsupported extension {0}", e);
381                     }
382                   }
383               }
384             AbstractSessionContext sessions = (AbstractSessionContext)
385               engine.contextImpl.engineGetServerSessionContext();
386             SSLSession s = sessions.getSession(sessionId);
387             if (Debug.DEBUG)
388               logger.logv(Component.SSL_HANDSHAKE, "looked up saved session {0}", s);
389             if (s != null && s.isValid() && (s instanceof SessionImpl))
390               {
391                 engine.setSession((SessionImpl) s);
392                 continuedSession = true;
393               }
394             else
395               {
396                 // We *may* wind up with a badly seeded PRNG, and emit the
397                 // same session ID over and over (this did happen to me,
398                 // so we add this sanity check just in case).
399                 if (engine.session().id().equals(new Session.ID(sessionId)))
400                   {
401                     byte[] newId = new byte[32];
402                     engine.session().random().nextBytes(newId);
403                     engine.session().setId(new Session.ID(newId));
404                   }
405                 sessions.put(engine.session());
406               }
407             state = WRITE_SERVER_HELLO;
408           }
409           break;
410 
411         // Certificate.
412         //
413         // This message is sent by the client if the server had previously
414         // requested that the client authenticate itself with a certificate,
415         // and if the client has an appropriate certificate available.
416         //
417         // Processing this message will save the client's certificate,
418         // rejecting it if the certificate is not trusted, in preparation
419         // for the certificate verify message that will follow.
420         case READ_CERTIFICATE:
421           {
422             if (handshake.type() != CERTIFICATE)
423               {
424                 if (engine.getNeedClientAuth()) // XXX throw better exception.
425                   throw new SSLException("client auth required");
426                 state = READ_CLIENT_KEY_EXCHANGE;
427                 return HandshakeStatus.NEED_UNWRAP;
428               }
429 
430             Certificate cert = (Certificate) handshake.body();
431             try
432               {
433                 engine.session().setPeerVerified(false);
434                 X509Certificate[] chain
435                   = cert.certificates().toArray(new X509Certificate[0]);
436                 if (chain.length == 0)
437                   throw new CertificateException("no certificates in chain");
438                 certVerifier = new CertVerifier(false, chain);
439                 tasks.add(certVerifier);
440                 engine.session().setPeerCertificates(chain);
441                 clientCert = chain[0];
442                 // Delay setting 'peerVerified' until CertificateVerify.
443               }
444             catch (CertificateException ce)
445               {
446                 if (engine.getNeedClientAuth())
447                   {
448                     SSLPeerUnverifiedException x
449                       = new SSLPeerUnverifiedException("client certificates could not be verified");
450                     x.initCause(ce);
451                     throw x;
452                   }
453               }
454             catch (NoSuchAlgorithmException nsae)
455               {
456                 throw new SSLException(nsae);
457               }
458             state = READ_CLIENT_KEY_EXCHANGE;
459           }
460           break;
461 
462         // Client Key Exchange.
463         //
464         // The client's key exchange. This message is sent either following
465         // the certificate message, or if no certificate is available or
466         // requested, following the server's hello done message.
467         //
468         // After receipt of this message, the session keys for this
469         // session will have been created.
470         case READ_CLIENT_KEY_EXCHANGE:
471           {
472             if (handshake.type() != CLIENT_KEY_EXCHANGE)
473               throw new SSLException("expecting client key exchange");
474             ClientKeyExchange kex = (ClientKeyExchange) handshake.body();
475 
476             KeyExchangeAlgorithm alg = engine.session().suite.keyExchangeAlgorithm();
477             switch (alg)
478               {
479                 case DHE_DSS:
480                 case DHE_RSA:
481                 case DH_anon:
482                   {
483                     ClientDiffieHellmanPublic pub = (ClientDiffieHellmanPublic)
484                       kex.exchangeKeys();
485                     DHPublicKey myKey = (DHPublicKey) dhPair.getPublic();
486                     DHPublicKey clientKey =
487                       new GnuDHPublicKey(null, myKey.getParams().getP(),
488                                          myKey.getParams().getG(),
489                                          pub.publicValue());
490                     keyExchangeTask = new DHPhase(clientKey);
491                     tasks.add(keyExchangeTask);
492                   }
493                   break;
494 
495                 case RSA:
496                   {
497                     EncryptedPreMasterSecret secret = (EncryptedPreMasterSecret)
498                       kex.exchangeKeys();
499                     keyExchangeTask = new RSAKeyExchange(secret.encryptedSecret());
500                     tasks.add(keyExchangeTask);
501                   }
502                   break;
503 
504                 case PSK:
505                   {
506                     ClientPSKParameters params = (ClientPSKParameters)
507                       kex.exchangeKeys();
508                     generatePSKSecret(params.identity(), null, false);
509                   }
510                   break;
511 
512                 case DHE_PSK:
513                   {
514                     ClientDHE_PSKParameters params = (ClientDHE_PSKParameters)
515                       kex.exchangeKeys();
516                     DHPublicKey serverKey = (DHPublicKey) dhPair.getPublic();
517                     DHPublicKey clientKey =
518                       new GnuDHPublicKey(null, serverKey.getParams().getP(),
519                                          serverKey.getParams().getG(),
520                                          params.params().publicValue());
521                     SecretKey psk = null;
522                     try
523                       {
524                         psk = engine.contextImpl.pskManager.getKey(params.identity());
525                       }
526                     catch (KeyManagementException kme)
527                       {
528                       }
529                     keyExchangeTask = new DHE_PSKGen(clientKey, psk, false);
530                     tasks.add(keyExchangeTask);
531                   }
532                   break;
533 
534                 case RSA_PSK:
535                   {
536                     ClientRSA_PSKParameters params = (ClientRSA_PSKParameters)
537                       kex.exchangeKeys();
538                     SecretKey psk = null;
539                     try
540                       {
541                         psk = engine.contextImpl.pskManager.getKey(params.identity());
542                       }
543                     catch (KeyManagementException kme)
544                       {
545                       }
546                     if (psk == null)
547                       {
548                         byte[] fakeKey = new byte[16];
549                         engine.session().random().nextBytes(fakeKey);
550                         psk = new SecretKeySpec(fakeKey, "DHE_PSK");
551                       }
552                     keyExchangeTask =
553                       new RSA_PSKExchange(params.secret().encryptedSecret(), psk);
554                     tasks.add(keyExchangeTask);
555                   }
556                   break;
557 
558                 case NONE:
559                   {
560                     Inflater inflater = null;
561                     Deflater deflater = null;
562                     if (compression == CompressionMethod.ZLIB)
563                       {
564                         inflater = new Inflater();
565                         deflater = new Deflater();
566                       }
567                     inParams = new InputSecurityParameters(null, null, inflater,
568                                                            engine.session(),
569                                                            engine.session().suite);
570                     outParams = new OutputSecurityParameters(null, null, deflater,
571                                                              engine.session(),
572                                                              engine.session().suite);
573                     engine.session().privateData.masterSecret = new byte[0];
574                   }
575                   break;
576               }
577             // XXX SRP
578 
579             if (clientCert != null)
580               state = READ_CERTIFICATE_VERIFY;
581             else
582               state = READ_FINISHED;
583           }
584           break;
585 
586         // Certificate Verify.
587         //
588         // This message is sent following the client key exchange message,
589         // but only when the client included its certificate in a previous
590         // message.
591         //
592         // After receipt of this message, the client's certificate (and,
593         // to a degree, the client's identity) will have been verified.
594         case READ_CERTIFICATE_VERIFY:
595           {
596             if (handshake.type() != CERTIFICATE_VERIFY)
597               throw new SSLException("expecting certificate verify message");
598 
599             CertificateVerify verify = (CertificateVerify) handshake.body();
600             try
601               {
602                 verifyClient(verify.signature());
603                 if (certVerifier != null && certVerifier.verified())
604                   engine.session().setPeerVerified(true);
605               }
606             catch (SignatureException se)
607               {
608                 if (engine.getNeedClientAuth())
609                   throw new SSLException("client auth failed", se);
610               }
611             if (continuedSession)
612               {
613                 engine.changeCipherSpec();
614                 state = WRITE_FINISHED;
615               }
616             else
617               state = READ_FINISHED;
618           }
619           break;
620 
621         // Finished.
622         //
623         // This message is sent immediately following the change cipher
624         // spec message (which is sent outside of the handshake layer).
625         // After receipt of this message, the session keys for the client
626         // side will have been verified (this is the first message the
627         // client sends encrypted and authenticated with the newly
628         // negotiated keys).
629         //
630         // In the case of a continued session, the client sends its
631         // finished message first. Otherwise, the server will send its
632         // finished message first.
633         case READ_FINISHED:
634           {
635             if (handshake.type() != FINISHED)
636               throw new AlertException(new Alert(Alert.Level.FATAL,
637                                                  Description.UNEXPECTED_MESSAGE));
638 
639             Finished clientFinished = (Finished) handshake.body();
640 
641             MessageDigest md5copy = null;
642             MessageDigest shacopy = null;
643             try
644               {
645                 md5copy = (MessageDigest) md5.clone();
646                 shacopy = (MessageDigest) sha.clone();
647               }
648             catch (CloneNotSupportedException cnse)
649               {
650                 // We're improperly configured to use a non-cloneable
651                 // md5/sha-1, OR there's a runtime bug.
652                 throw new SSLException(cnse);
653               }
654             Finished serverFinished =
655               new Finished(generateFinished(md5copy, shacopy,
656                                             true, engine.session()),
657                                             engine.session().version);
658 
659             if (Debug.DEBUG)
660               logger.log(Component.SSL_HANDSHAKE, "server finished: {0}",
661                          serverFinished);
662 
663             if (engine.session().version == ProtocolVersion.SSL_3)
664               {
665                 if (!Arrays.equals(clientFinished.md5Hash(),
666                                    serverFinished.md5Hash())
667                     || !Arrays.equals(clientFinished.shaHash(),
668                                       serverFinished.shaHash()))
669                   {
670                     engine.session().invalidate();
671                     throw new SSLException("session verify failed");
672                   }
673               }
674             else
675               {
676                 if (!Arrays.equals(clientFinished.verifyData(),
677                                    serverFinished.verifyData()))
678                   {
679                     engine.session().invalidate();
680                     throw new SSLException("session verify failed");
681                   }
682               }
683 
684             if (continuedSession)
685               state = DONE;
686             else
687               {
688                 engine.changeCipherSpec();
689                 state = WRITE_FINISHED;
690               }
691           }
692           break;
693       }
694 
695     handshakeOffset += handshake.length() + 4;
696 
697     if (!tasks.isEmpty())
698       return HandshakeStatus.NEED_TASK;
699     if (state.isReadState())
700       return HandshakeStatus.NEED_UNWRAP;
701     if (state.isWriteState())
702       return HandshakeStatus.NEED_WRAP;
703 
704     return HandshakeStatus.FINISHED;
705   }
706 
implHandleOutput(ByteBuffer fragment)707   public @Override HandshakeStatus implHandleOutput (ByteBuffer fragment)
708     throws SSLException
709   {
710     if (Debug.DEBUG)
711       logger.logv(Component.SSL_HANDSHAKE,
712                   "handle output state: {0}; output fragment: {1}",
713                   state, fragment);
714 
715     // Drain the output buffer, if it needs it.
716     if (outBuffer != null && outBuffer.hasRemaining())
717       {
718         int l = Math.min(fragment.remaining(), outBuffer.remaining());
719         fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
720         outBuffer.position(outBuffer.position() + l);
721       }
722 
723     if (!fragment.hasRemaining())
724       {
725         if (state.isWriteState() || outBuffer.hasRemaining())
726           return HandshakeStatus.NEED_WRAP;
727         else
728           return HandshakeStatus.NEED_UNWRAP;
729       }
730 
731     // XXX what we need to do here is generate a "stream" of handshake
732     // messages, and insert them into fragment amounts that we have available.
733     // A handshake message can span multiple records, and we can put
734     // multiple records into a single record.
735     //
736     // So, we can have one of two states:
737     //
738     // 1) We have enough space in the record we are creating to push out
739     //    everything we need to on this round. This is easy; we just
740     //    repeatedly fill in these messages in the buffer, so we get something
741     //    that looks like this:
742     //                 ________________________________
743     //       records: |________________________________|
744     //    handshakes: |______|__|__________|
745     //
746     // 2) We can put part of one handshake message in the current record,
747     //    but we must put the rest of it in the following record, or possibly
748     //    more than one following record. So here, we'd see this:
749     //
750     //                 ________________________
751     //       records: |_______|_______|________|
752     //    handshakes: |____|_______|_________|
753     //
754     // We *could* make this a lot easier by just only ever emitting one
755     // record per call, but then we would waste potentially a lot of space
756     // and waste a lot of TCP packets by doing it the simple way. What
757     // we desire here is that we *maximize* our usage of the resources
758     // given to us, and to use as much space in the present fragment as
759     // we can.
760     //
761     // Note that we pretty much have to support this, anyway, because SSL
762     // provides no guarantees that the record size is large enough to
763     // admit *even one* handshake message. Also, callers could call on us
764     // with a short buffer, even though they aren't supposed to.
765     //
766     // This is somewhat complicated by the fact that we don't know, a priori,
767     // how large a handshake message will be until we've built it, and our
768     // design builds the message around the byte buffer.
769     //
770     // Some ways to handle this:
771     //
772     //  1. Write our outgoing handshake messages to a private buffer,
773     //     big enough per message (and, if we run out of space, resize that
774     //     buffer) and push (possibly part of) this buffer out to the
775     //     outgoing buffer. This isn't that great because we'd need to
776     //     store and copy things unnecessarily.
777     //
778     //  2. Build outgoing handshake objects 'virtually', that is, store them
779     //     as collections of objects, then compute the length, and then write
780     //     them to a buffer, instead of making the objects views on
781     //     ByteBuffers for both input and output. This would complicate the
782     //     protocol objects a bit (although, it would amount to doing
783     //     separation between client objects and server objects, which is
784     //     pretty OK), and we still need to figure out how exactly to chunk
785     //     those objects across record boundaries.
786     //
787     //  3. Try to build these objects on the buffer we're given, but detect
788     //     when we run out of space in the output buffer, and split the
789     //     overflow message. This sounds like the best, but also probably
790     //     the hardest to code.
791 output_loop:
792     while (fragment.remaining() >= 4 && state.isWriteState())
793       {
794         switch (state)
795           {
796             // Hello Request.
797             //
798             // This message is sent by the server to initiate a new
799             // handshake, to establish new session keys.
800             case WRITE_HELLO_REQUEST:
801             {
802               Handshake handshake = new Handshake(fragment);
803               handshake.setType(Handshake.Type.HELLO_REQUEST);
804               handshake.setLength(0);
805               fragment.position(fragment.position() + 4);
806               if (Debug.DEBUG)
807                 logger.log(Component.SSL_HANDSHAKE, "{0}", handshake);
808               state = READ_CLIENT_HELLO;
809             }
810             break output_loop; // XXX temporary
811 
812             // Server Hello.
813             //
814             // This message is sent immediately following the client hello.
815             // It informs the client of the cipher suite, compression method,
816             // session ID (which may have been a continued session), and any
817             // supported extensions.
818             case WRITE_SERVER_HELLO:
819             {
820               ServerHelloBuilder hello = new ServerHelloBuilder();
821               hello.setVersion(engine.session().version);
822               Random r = hello.random();
823               r.setGmtUnixTime(Util.unixTime());
824               byte[] nonce = new byte[28];
825               engine.session().random().nextBytes(nonce);
826               r.setRandomBytes(nonce);
827               serverRandom = r.copy();
828               hello.setSessionId(engine.session().getId());
829               hello.setCipherSuite(engine.session().suite);
830               hello.setCompressionMethod(compression);
831               if (clientHadExtensions)
832                 {
833                   // XXX figure this out.
834                 }
835               else // Don't send any extensions.
836                 hello.setDisableExtensions(true);
837 
838               if (Debug.DEBUG)
839                 logger.log(Component.SSL_HANDSHAKE, "{0}", hello);
840 
841               int typeLen = ((Handshake.Type.SERVER_HELLO.getValue() << 24)
842                   | (hello.length() & 0xFFFFFF));
843               fragment.putInt(typeLen);
844 
845               outBuffer = hello.buffer();
846               int l = Math.min(fragment.remaining(), outBuffer.remaining());
847               fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
848               outBuffer.position(outBuffer.position() + l);
849 
850               CipherSuite cs = engine.session().suite;
851               KeyExchangeAlgorithm kex = cs.keyExchangeAlgorithm();
852               if (continuedSession)
853                 {
854                   byte[][] keys = generateKeys(clientRandom, serverRandom,
855                                                engine.session());
856                   setupSecurityParameters(keys, false, engine, compression);
857                   engine.changeCipherSpec();
858                   state = WRITE_FINISHED;
859                 }
860               else if (kex == DHE_DSS || kex == DHE_RSA || kex == RSA
861                        || kex == RSA_PSK)
862                 {
863                   certLoader = new CertLoader();
864                   tasks.add(certLoader);
865                   state = WRITE_CERTIFICATE;
866                   if (kex == DHE_DSS || kex == DHE_RSA)
867                     {
868                       genDH = new GenDH();
869                       tasks.add(genDH);
870                     }
871                   break output_loop;
872                 }
873               else if (kex == PSK)
874                 {
875                   state = WRITE_SERVER_KEY_EXCHANGE;
876                 }
877               else if (kex == DHE_PSK || kex == DH_anon)
878                 {
879                   genDH = new GenDH();
880                   tasks.add(genDH);
881                   state = WRITE_SERVER_KEY_EXCHANGE;
882                   break output_loop;
883                 }
884               else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
885                 {
886                   state = WRITE_CERTIFICATE_REQUEST;
887                 }
888               else
889                 state = WRITE_SERVER_HELLO_DONE;
890             }
891             break;
892 
893             // Certificate.
894             //
895             // This message is sent immediately following the server hello,
896             // IF the cipher suite chosen requires that the server identify
897             // itself (usually, servers must authenticate).
898             case WRITE_CERTIFICATE:
899             {
900               // We must have scheduled a certificate loader to run.
901               assert(certLoader != null);
902               assert(certLoader.hasRun());
903               if (certLoader.thrown() != null)
904                 throw new AlertException(new Alert(Alert.Level.FATAL,
905                                                    Alert.Description.HANDSHAKE_FAILURE),
906                                          certLoader.thrown());
907               java.security.cert.Certificate[] chain
908                 = engine.session().getLocalCertificates();
909               CertificateBuilder cert = new CertificateBuilder(CertificateType.X509);
910               try
911                 {
912                   cert.setCertificates(Arrays.asList(chain));
913                 }
914               catch (CertificateException ce)
915                 {
916                   throw new SSLException(ce);
917                 }
918 
919               if (Debug.DEBUG)
920                 {
921                   logger.logv(Component.SSL_HANDSHAKE, "my cert:\n{0}", localCert);
922                   logger.logv(Component.SSL_HANDSHAKE, "{0}", cert);
923                 }
924 
925               int typeLen = ((CERTIFICATE.getValue() << 24)
926                              | (cert.length() & 0xFFFFFF));
927               fragment.putInt(typeLen);
928 
929               outBuffer = cert.buffer();
930               final int l = Math.min(fragment.remaining(), outBuffer.remaining());
931               fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
932               outBuffer.position(outBuffer.position() + l);
933 
934               CipherSuite s = engine.session().suite;
935               KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
936               if (kexalg == DHE_DSS || kexalg == DHE_RSA)
937                 {
938                   genDH = new GenDH();
939                   tasks.add(genDH);
940                   state = WRITE_SERVER_KEY_EXCHANGE;
941                   break output_loop;
942                 }
943               else if (kexalg == RSA_PSK)
944                 state = WRITE_SERVER_KEY_EXCHANGE;
945               else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
946                 {
947                   state = WRITE_CERTIFICATE_REQUEST;
948                 }
949               else
950                 state = WRITE_SERVER_HELLO_DONE;
951             }
952             break output_loop; // XXX temporary
953 
954             // Server key exchange.
955             //
956             // This message is sent, following the certificate if sent,
957             // otherwise following the server hello, IF the chosen cipher
958             // suite requires that the server send explicit key exchange
959             // parameters (that is, if the key exchange parameters are not
960             // implicit in the server's certificate).
961             case WRITE_SERVER_KEY_EXCHANGE:
962             {
963               KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
964 
965               ByteBuffer paramBuffer = null;
966               ByteBuffer sigBuffer = null;
967               if (kex == DHE_DSS || kex == DHE_RSA || kex == DH_anon
968                   || kex == DHE_PSK)
969                 {
970                   assert(genDH != null);
971                   assert(genDH.hasRun());
972                   if (genDH.thrown() != null)
973                     throw new AlertException(new Alert(Alert.Level.FATAL,
974                                                        Alert.Description.HANDSHAKE_FAILURE),
975                                              genDH.thrown());
976                   assert(dhPair != null);
977                   initDiffieHellman((DHPrivateKey) dhPair.getPrivate(),
978                                     engine.session().random());
979                   paramBuffer = genDH.paramsBuffer;
980                   sigBuffer = genDH.sigBuffer;
981 
982                   if (kex == DHE_PSK)
983                     {
984                       String identityHint
985                         = engine.contextImpl.pskManager.chooseIdentityHint();
986                       ServerDHE_PSKParameters psk =
987                         new ServerDHE_PSKParameters(identityHint, paramBuffer);
988                       paramBuffer = psk.buffer();
989                     }
990                 }
991               if (kex == RSA_PSK)
992                 {
993                   String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
994                   if (idHint != null)
995                     {
996                       ServerRSA_PSKParameters params
997                         = new ServerRSA_PSKParameters(idHint);
998                       paramBuffer = params.buffer();
999                     }
1000                 }
1001               if (kex == PSK)
1002                 {
1003                   String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
1004                   if (idHint != null)
1005                     {
1006                       ServerPSKParameters params
1007                         = new ServerPSKParameters(idHint);
1008                       paramBuffer = params.buffer();
1009                     }
1010                 }
1011               // XXX handle SRP
1012 
1013               if (paramBuffer != null)
1014                 {
1015                   ServerKeyExchangeBuilder ske
1016                     = new ServerKeyExchangeBuilder(engine.session().suite);
1017                   ske.setParams(paramBuffer);
1018                   if (sigBuffer != null)
1019                     ske.setSignature(sigBuffer);
1020 
1021                   if (Debug.DEBUG)
1022                     logger.log(Component.SSL_HANDSHAKE, "{0}", ske);
1023 
1024                   outBuffer = ske.buffer();
1025                   int l = Math.min(fragment.remaining(), outBuffer.remaining());
1026                   fragment.putInt((SERVER_KEY_EXCHANGE.getValue() << 24)
1027                                   | (ske.length() & 0xFFFFFF));
1028                   fragment.put((ByteBuffer) outBuffer.duplicate().limit
1029                                (outBuffer.position() + l));
1030                   outBuffer.position(outBuffer.position() + l);
1031                 }
1032 
1033               if (engine.getWantClientAuth() || engine.getNeedClientAuth())
1034                 state = WRITE_CERTIFICATE_REQUEST;
1035               else
1036                 state = WRITE_SERVER_HELLO_DONE;
1037             }
1038             break;
1039 
1040             // Certificate Request.
1041             //
1042             // This message is sent when the server desires or requires
1043             // client authentication with a certificate; if it is sent, it
1044             // will be sent just after the Certificate or Server Key
1045             // Exchange messages, whichever is sent. If neither of the
1046             // above are sent, it will be the message that follows the
1047             // server hello.
1048             case WRITE_CERTIFICATE_REQUEST:
1049             {
1050               CertificateRequestBuilder req = new CertificateRequestBuilder();
1051 
1052               List<ClientCertificateType> types
1053                 = new ArrayList<ClientCertificateType>(4);
1054               types.add(ClientCertificateType.RSA_SIGN);
1055               types.add(ClientCertificateType.RSA_FIXED_DH);
1056               types.add(ClientCertificateType.DSS_SIGN);
1057               types.add(ClientCertificateType.DSS_FIXED_DH);
1058               req.setTypes(types);
1059 
1060               X509Certificate[] anchors
1061                 = engine.contextImpl.trustManager.getAcceptedIssuers();
1062               List<X500Principal> issuers
1063                 = new ArrayList<X500Principal>(anchors.length);
1064               for (X509Certificate cert : anchors)
1065                 issuers.add(cert.getIssuerX500Principal());
1066               req.setAuthorities(issuers);
1067 
1068               if (Debug.DEBUG)
1069                 logger.log(Component.SSL_HANDSHAKE, "{0}", req);
1070 
1071               fragment.putInt((CERTIFICATE_REQUEST.getValue() << 24)
1072                               | (req.length() & 0xFFFFFF));
1073 
1074               outBuffer = req.buffer();
1075               int l = Math.min(outBuffer.remaining(), fragment.remaining());
1076               fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
1077               outBuffer.position(outBuffer.position() + l);
1078 
1079               state = WRITE_SERVER_HELLO_DONE;
1080             }
1081             break;
1082 
1083             // Server Hello Done.
1084             //
1085             // This message is always sent by the server, to terminate its
1086             // side of the handshake. Since the server's handshake message
1087             // may comprise multiple, optional messages, this sentinel
1088             // message lets the client know when the server's message stream
1089             // is complete.
1090             case WRITE_SERVER_HELLO_DONE:
1091             {
1092               // ServerHelloDone is zero-length; just put in the type
1093               // field.
1094               fragment.putInt(SERVER_HELLO_DONE.getValue() << 24);
1095               if (Debug.DEBUG)
1096                 logger.logv(Component.SSL_HANDSHAKE, "writing ServerHelloDone");
1097               state = READ_CERTIFICATE;
1098             }
1099             break output_loop; // XXX temporary
1100 
1101             // Finished.
1102             //
1103             // This is always sent by the server to verify the keys that the
1104             // server will use to encrypt and authenticate. In a full
1105             // handshake, this message will be sent after the client's
1106             // finished message; in an abbreviated handshake (with a continued
1107             // session) the server sends its finished message first.
1108             //
1109             // This message follows the change cipher spec message, which is
1110             // sent out-of-band in a different SSL content-type.
1111             //
1112             // This is the first message that the server will send encrypted
1113             // and authenticated with the newly negotiated session keys.
1114             case WRITE_FINISHED:
1115             {
1116               MessageDigest md5copy = null;
1117               MessageDigest shacopy = null;
1118               try
1119                 {
1120                   md5copy = (MessageDigest) md5.clone();
1121                   shacopy = (MessageDigest) sha.clone();
1122                 }
1123               catch (CloneNotSupportedException cnse)
1124                 {
1125                   // We're improperly configured to use a non-cloneable
1126                   // md5/sha-1, OR there's a runtime bug.
1127                   throw new SSLException(cnse);
1128                 }
1129               outBuffer
1130                 = generateFinished(md5copy, shacopy, false,
1131                                    engine.session());
1132 
1133               fragment.putInt((FINISHED.getValue() << 24)
1134                               | outBuffer.remaining() & 0xFFFFFF);
1135 
1136               int l = Math.min(outBuffer.remaining(), fragment.remaining());
1137               fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
1138               outBuffer.position(outBuffer.position() + l);
1139 
1140               if (continuedSession)
1141                 state = READ_FINISHED;
1142               else
1143                 state = DONE;
1144             }
1145             break;
1146           }
1147       }
1148     if (!tasks.isEmpty())
1149       return HandshakeStatus.NEED_TASK;
1150     if (state.isWriteState() || outBuffer.hasRemaining())
1151       return HandshakeStatus.NEED_WRAP;
1152     if (state.isReadState())
1153       return HandshakeStatus.NEED_UNWRAP;
1154 
1155     return HandshakeStatus.FINISHED;
1156   }
1157 
status()1158   @Override HandshakeStatus status()
1159   {
1160     if (!tasks.isEmpty())
1161       return HandshakeStatus.NEED_TASK;
1162     if (state.isReadState())
1163       return HandshakeStatus.NEED_UNWRAP;
1164     if (state.isWriteState())
1165       return HandshakeStatus.NEED_WRAP;
1166 
1167     return HandshakeStatus.FINISHED;
1168   }
1169 
checkKeyExchange()1170   @Override void checkKeyExchange() throws SSLException
1171   {
1172     if (continuedSession) // No key exchange needed.
1173       return;
1174     KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
1175     if (kex == NONE || kex == PSK || kex == RSA_PSK) // Don't need one.
1176       return;
1177     if (keyExchangeTask == null) // An error if we never created one.
1178       throw new AlertException(new Alert(Alert.Level.FATAL,
1179                                          Alert.Description.INTERNAL_ERROR));
1180     if (!keyExchangeTask.hasRun()) // An error if the caller never ran it.
1181       throw new AlertException(new Alert(Alert.Level.FATAL,
1182                                          Alert.Description.INTERNAL_ERROR));
1183     if (keyExchangeTask.thrown() != null) // An error was thrown.
1184       throw new AlertException(new Alert(Alert.Level.FATAL,
1185                                          Alert.Description.HANDSHAKE_FAILURE),
1186                                keyExchangeTask.thrown());
1187   }
1188 
handleV2Hello(ByteBuffer hello)1189   @Override void handleV2Hello(ByteBuffer hello)
1190   {
1191     int len = hello.getShort(0) & 0x7FFF;
1192     md5.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
1193     sha.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
1194     helloV2 = true;
1195   }
1196 
signParams(ByteBuffer serverParams)1197   private ByteBuffer signParams(ByteBuffer serverParams)
1198     throws NoSuchAlgorithmException, InvalidKeyException, SignatureException
1199   {
1200     SignatureAlgorithm alg = engine.session().suite.signatureAlgorithm();
1201     java.security.Signature sig
1202       = java.security.Signature.getInstance(alg.algorithm());
1203     PrivateKey key = engine.contextImpl.keyManager.getPrivateKey(keyAlias);
1204     if (Debug.DEBUG_KEY_EXCHANGE)
1205       logger.logv(Component.SSL_HANDSHAKE, "server key: {0}", key);
1206     sig.initSign(key);
1207     sig.update(clientRandom.buffer());
1208     sig.update(serverRandom.buffer());
1209     sig.update(serverParams);
1210     byte[] sigVal = sig.sign();
1211     Signature signature = new Signature(sigVal, engine.session().suite.signatureAlgorithm());
1212     return signature.buffer();
1213   }
1214 
verifyClient(byte[] sigValue)1215   private void verifyClient(byte[] sigValue) throws SSLException, SignatureException
1216   {
1217     MessageDigest md5copy = null;
1218     MessageDigest shacopy = null;
1219     try
1220       {
1221         md5copy = (MessageDigest) md5.clone();
1222         shacopy = (MessageDigest) sha.clone();
1223       }
1224     catch (CloneNotSupportedException cnse)
1225       {
1226         // Mis-configured with non-cloneable digests.
1227         throw new SSLException(cnse);
1228       }
1229     byte[] toSign = null;
1230     if (engine.session().version == ProtocolVersion.SSL_3)
1231       toSign = genV3CertificateVerify(md5copy, shacopy, engine.session());
1232     else
1233       {
1234         if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
1235           toSign = Util.concat(md5copy.digest(), shacopy.digest());
1236         else
1237           toSign = shacopy.digest();
1238       }
1239 
1240     try
1241       {
1242         java.security.Signature sig = java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().toString());
1243         sig.initVerify(clientCert);
1244         sig.update(toSign);
1245         sig.verify(sigValue);
1246       }
1247     catch (InvalidKeyException ike)
1248       {
1249         throw new SSLException(ike);
1250       }
1251     catch (NoSuchAlgorithmException nsae)
1252       {
1253         throw new SSLException(nsae);
1254       }
1255   }
1256 
1257   // Delegated tasks.
1258 
1259   class CertLoader extends DelegatedTask
1260   {
CertLoader()1261     CertLoader()
1262     {
1263     }
1264 
implRun()1265     public void implRun() throws SSLException
1266     {
1267       KeyExchangeAlgorithm kexalg = engine.session().suite.keyExchangeAlgorithm();
1268       X509ExtendedKeyManager km = engine.contextImpl.keyManager;
1269       Principal[] issuers = null; // XXX use TrustedAuthorities extension.
1270       keyAlias = km.chooseEngineServerAlias(kexalg.name(), issuers, engine);
1271       if (keyAlias == null)
1272         throw new SSLException("no certificates available");
1273       X509Certificate[] chain = km.getCertificateChain(keyAlias);
1274       engine.session().setLocalCertificates(chain);
1275       localCert = chain[0];
1276       serverKey = km.getPrivateKey(keyAlias);
1277       if (kexalg == DH_DSS || kexalg == DH_RSA)
1278         dhPair = new KeyPair(localCert.getPublicKey(),
1279                              km.getPrivateKey(keyAlias));
1280     }
1281   }
1282 
1283   /**
1284    * Delegated task for generating Diffie-Hellman parameters.
1285    */
1286   private class GenDH extends DelegatedTask
1287   {
1288     ByteBuffer paramsBuffer;
1289     ByteBuffer sigBuffer;
1290 
implRun()1291     protected void implRun()
1292       throws NoSuchAlgorithmException, InvalidAlgorithmParameterException,
1293              InvalidKeyException, SignatureException
1294     {
1295       KeyPairGenerator dhGen = KeyPairGenerator.getInstance("DH");
1296       DHParameterSpec dhparams = DiffieHellman.getParams().getParams();
1297       dhGen.initialize(dhparams, engine.session().random());
1298       dhPair = dhGen.generateKeyPair();
1299       DHPublicKey pub = (DHPublicKey) dhPair.getPublic();
1300 
1301       // Generate the parameters message.
1302       ServerDHParams params = new ServerDHParams(pub.getParams().getP(),
1303                                                  pub.getParams().getG(),
1304                                                  pub.getY());
1305       paramsBuffer = params.buffer();
1306 
1307       // Sign the parameters, if needed.
1308       if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
1309         {
1310           sigBuffer = signParams(paramsBuffer);
1311           paramsBuffer.rewind();
1312         }
1313       if (Debug.DEBUG_KEY_EXCHANGE)
1314         logger.logv(Component.SSL_KEY_EXCHANGE,
1315                     "Diffie-Hellman public:{0} private:{1}",
1316                     dhPair.getPublic(), dhPair.getPrivate());
1317     }
1318   }
1319 
1320   class RSAKeyExchange extends DelegatedTask
1321   {
1322     private final byte[] encryptedPreMasterSecret;
1323 
RSAKeyExchange(byte[] encryptedPreMasterSecret)1324     RSAKeyExchange(byte[] encryptedPreMasterSecret)
1325     {
1326       this.encryptedPreMasterSecret = encryptedPreMasterSecret;
1327     }
1328 
implRun()1329     public void implRun()
1330       throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
1331              NoSuchAlgorithmException, NoSuchPaddingException, SSLException
1332     {
1333       Cipher rsa = Cipher.getInstance("RSA");
1334       rsa.init(Cipher.DECRYPT_MODE, serverKey);
1335       rsa.init(Cipher.DECRYPT_MODE, localCert);
1336       preMasterSecret = rsa.doFinal(encryptedPreMasterSecret);
1337       generateMasterSecret(clientRandom, serverRandom, engine.session());
1338       byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
1339       setupSecurityParameters(keys, false, engine, compression);
1340     }
1341   }
1342 
1343   class RSA_PSKExchange extends DelegatedTask
1344   {
1345     private final byte[] encryptedPreMasterSecret;
1346     private final SecretKey psKey;
1347 
RSA_PSKExchange(byte[] encryptedPreMasterSecret, SecretKey psKey)1348     RSA_PSKExchange(byte[] encryptedPreMasterSecret, SecretKey psKey)
1349     {
1350       this.encryptedPreMasterSecret = encryptedPreMasterSecret;
1351       this.psKey = psKey;
1352     }
1353 
implRun()1354     public @Override void implRun()
1355       throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
1356              NoSuchAlgorithmException, NoSuchPaddingException, SSLException
1357     {
1358       Cipher rsa = Cipher.getInstance("RSA");
1359       rsa.init(Cipher.DECRYPT_MODE, serverKey);
1360       rsa.init(Cipher.DECRYPT_MODE, localCert);
1361       byte[] rsaSecret = rsa.doFinal(encryptedPreMasterSecret);
1362       byte[] psSecret = psKey.getEncoded();
1363       preMasterSecret = new byte[rsaSecret.length + psSecret.length + 4];
1364       preMasterSecret[0] = (byte) (rsaSecret.length >>> 8);
1365       preMasterSecret[1] = (byte)  rsaSecret.length;
1366       System.arraycopy(rsaSecret, 0, preMasterSecret, 2, rsaSecret.length);
1367       preMasterSecret[rsaSecret.length + 2] = (byte) (psSecret.length >>> 8);
1368       preMasterSecret[rsaSecret.length + 3] = (byte)  psSecret.length;
1369       System.arraycopy(psSecret, 0, preMasterSecret, rsaSecret.length+4,
1370                        psSecret.length);
1371 
1372       generateMasterSecret(clientRandom, serverRandom, engine.session());
1373       byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
1374       setupSecurityParameters(keys, false, engine, compression);
1375     }
1376   }
1377 }
1378