Source for gnu.javax.net.ssl.provider.ClientHandshake

   1: /* ClientHandshake.java --
   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.ClientHandshake.State.*;
  42: import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
  43: 
  44: import gnu.classpath.debug.Component;
  45: import gnu.java.security.action.GetSecurityPropertyAction;
  46: import gnu.javax.crypto.key.dh.GnuDHPublicKey;
  47: import gnu.javax.net.ssl.AbstractSessionContext;
  48: import gnu.javax.net.ssl.Session;
  49: import gnu.javax.net.ssl.provider.Alert.Description;
  50: import gnu.javax.net.ssl.provider.Alert.Level;
  51: import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
  52: import gnu.javax.net.ssl.provider.ServerNameList.NameType;
  53: import gnu.javax.net.ssl.provider.ServerNameList.ServerName;
  54: 
  55: import java.nio.ByteBuffer;
  56: import java.security.AccessController;
  57: import java.security.InvalidAlgorithmParameterException;
  58: import java.security.InvalidKeyException;
  59: import java.security.KeyPair;
  60: import java.security.KeyPairGenerator;
  61: import java.security.MessageDigest;
  62: import java.security.NoSuchAlgorithmException;
  63: import java.security.PrivateKey;
  64: import java.security.SignatureException;
  65: import java.security.cert.CertificateException;
  66: import java.security.cert.X509Certificate;
  67: import java.util.Arrays;
  68: import java.util.Collections;
  69: import java.util.LinkedList;
  70: import java.util.List;
  71: import java.util.zip.Deflater;
  72: import java.util.zip.Inflater;
  73: 
  74: import javax.crypto.BadPaddingException;
  75: import javax.crypto.Cipher;
  76: import javax.crypto.IllegalBlockSizeException;
  77: import javax.crypto.NoSuchPaddingException;
  78: import javax.crypto.interfaces.DHPrivateKey;
  79: import javax.crypto.interfaces.DHPublicKey;
  80: import javax.crypto.spec.DHParameterSpec;
  81: import javax.net.ssl.SSLException;
  82: import javax.net.ssl.SSLPeerUnverifiedException;
  83: import javax.net.ssl.X509ExtendedKeyManager;
  84: import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  85: import javax.security.auth.x500.X500Principal;
  86: 
  87: /**
  88:  * @author Casey Marshall (csm@gnu.org)
  89:  */
  90: public class ClientHandshake extends AbstractHandshake
  91: {
  92:   static enum State
  93:   {
  94:     WRITE_CLIENT_HELLO (false, true),
  95:     READ_SERVER_HELLO (true, false),
  96:     READ_CERTIFICATE (true, false),
  97:     READ_SERVER_KEY_EXCHANGE (true, false),
  98:     READ_CERTIFICATE_REQUEST (true, false),
  99:     READ_SERVER_HELLO_DONE (true, false),
 100:     WRITE_CERTIFICATE (false, true),
 101:     WRITE_CLIENT_KEY_EXCHANGE (false, true),
 102:     WRITE_CERTIFICATE_VERIFY (false, true),
 103:     WRITE_FINISHED (false, true),
 104:     READ_FINISHED (true, false),
 105:     DONE (false, false);
 106: 
 107:     private final boolean isWriteState;
 108:     private final boolean isReadState;
 109: 
 110:     private State(boolean isReadState, boolean isWriteState)
 111:     {
 112:       this.isReadState = isReadState;
 113:       this.isWriteState = isWriteState;
 114:     }
 115: 
 116:     boolean isReadState()
 117:     {
 118:       return isReadState;
 119:     }
 120: 
 121:     boolean isWriteState()
 122:     {
 123:       return isWriteState;
 124:     }
 125:   }
 126: 
 127:   private State state;
 128:   private ByteBuffer outBuffer;
 129:   private boolean continuedSession;
 130:   private SessionImpl continued;
 131:   private KeyPair dhPair;
 132:   private String keyAlias;
 133:   private PrivateKey privateKey;
 134:   private MaxFragmentLength maxFragmentLengthSent;
 135:   private boolean truncatedHMacSent;
 136:   private ProtocolVersion sentVersion;
 137: 
 138:   // Delegated tasks.
 139:   private CertVerifier certVerifier;
 140:   private ParamsVerifier paramsVerifier;
 141:   private DelegatedTask keyExchange;
 142:   private CertLoader certLoader;
 143:   private GenCertVerify genCertVerify;
 144: 
 145:   public ClientHandshake(SSLEngineImpl engine) throws NoSuchAlgorithmException
 146:   {
 147:     super(engine);
 148:     state = WRITE_CLIENT_HELLO;
 149:     continuedSession = false;
 150:   }
 151: 
 152:   /* (non-Javadoc)
 153:    * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleInput()
 154:    */
 155:   @Override protected HandshakeStatus implHandleInput() throws SSLException
 156:   {
 157:     if (state == DONE)
 158:       return HandshakeStatus.FINISHED;
 159: 
 160:     if (state.isWriteState()
 161:         || (outBuffer != null && outBuffer.hasRemaining()))
 162:       return HandshakeStatus.NEED_WRAP;
 163: 
 164:     // Copy the current buffer, and prepare it for reading.
 165:     ByteBuffer buffer = handshakeBuffer.duplicate ();
 166:     buffer.flip();
 167:     buffer.position(handshakeOffset);
 168: 
 169:     Handshake handshake = new Handshake(buffer.slice(),
 170:                                         engine.session().suite,
 171:                                         engine.session().version);
 172: 
 173:     if (Debug.DEBUG)
 174:       logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
 175:                   state, handshake);
 176: 
 177:     switch (state)
 178:       {
 179:         // Server Hello.
 180:         case READ_SERVER_HELLO:
 181:         {
 182:           if (handshake.type() != Handshake.Type.SERVER_HELLO)
 183:             throw new AlertException(new Alert(Alert.Level.FATAL,
 184:                                                Alert.Description.UNEXPECTED_MESSAGE));
 185:           ServerHello hello = (ServerHello) handshake.body();
 186:           serverRandom = hello.random().copy();
 187:           engine.session().suite = hello.cipherSuite();
 188:           engine.session().version = hello.version();
 189:           compression = hello.compressionMethod();
 190:           Session.ID serverId = new Session.ID(hello.sessionId());
 191:           if (continued != null
 192:               && continued.id().equals(serverId))
 193:             {
 194:               continuedSession = true;
 195:               engine.setSession(continued);
 196:             }
 197:           else if (engine.getEnableSessionCreation())
 198:             {
 199:               ((AbstractSessionContext) engine.contextImpl
 200:                   .engineGetClientSessionContext()).put(engine.session());
 201:             }
 202:           ExtensionList extensions = hello.extensions();
 203:           if (extensions != null)
 204:             {
 205:               for (Extension extension : extensions)
 206:                 {
 207:                   Extension.Type type = extension.type();
 208:                   if (type == null)
 209:                     continue;
 210:                   switch (type)
 211:                     {
 212:                       case MAX_FRAGMENT_LENGTH:
 213:                         MaxFragmentLength mfl
 214:                           = (MaxFragmentLength) extension.value();
 215:                         if (maxFragmentLengthSent == mfl)
 216:                           engine.session().setApplicationBufferSize(mfl.maxLength());
 217:                         break;
 218: 
 219:                       case TRUNCATED_HMAC:
 220:                         if (truncatedHMacSent)
 221:                           engine.session().setTruncatedMac(true);
 222:                         break;
 223:                     }
 224:                 }
 225:             }
 226: 
 227:           KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
 228:           if (continuedSession)
 229:             {
 230:               byte[][] keys = generateKeys(clientRandom, serverRandom,
 231:                                            engine.session());
 232:               setupSecurityParameters(keys, true, engine, compression);
 233:               state = READ_FINISHED;
 234:             }
 235:           else if (kex == RSA || kex == DH_DSS || kex == DH_RSA
 236:                    || kex == DHE_DSS || kex == DHE_RSA || kex == RSA_PSK)
 237:             state = READ_CERTIFICATE;
 238:           else if (kex == DH_anon || kex == PSK || kex == DHE_PSK)
 239:             state = READ_SERVER_KEY_EXCHANGE;
 240:           else
 241:             state = READ_CERTIFICATE_REQUEST;
 242:         }
 243:         break;
 244: 
 245:         // Server Certificate.
 246:         case READ_CERTIFICATE:
 247:         {
 248:           if (handshake.type() != Handshake.Type.CERTIFICATE)
 249:             {
 250:               // We need a certificate for non-anonymous suites.
 251:               if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
 252:                 throw new AlertException(new Alert(Level.FATAL,
 253:                                                    Description.UNEXPECTED_MESSAGE));
 254:               state = READ_SERVER_KEY_EXCHANGE;
 255:             }
 256:           Certificate cert = (Certificate) handshake.body();
 257:           X509Certificate[] chain = null;
 258:           try
 259:             {
 260:               chain = cert.certificates().toArray(new X509Certificate[0]);
 261:             }
 262:           catch (CertificateException ce)
 263:             {
 264:               throw new AlertException(new Alert(Level.FATAL,
 265:                                                  Description.BAD_CERTIFICATE),
 266:                                        ce);
 267:             }
 268:           catch (NoSuchAlgorithmException nsae)
 269:             {
 270:               throw new AlertException(new Alert(Level.FATAL,
 271:                                                  Description.UNSUPPORTED_CERTIFICATE),
 272:                                        nsae);
 273:             }
 274:           engine.session().setPeerCertificates(chain);
 275:           certVerifier = new CertVerifier(true, chain);
 276:           tasks.add(certVerifier);
 277: 
 278:           // If we are doing an RSA key exchange, generate our parameters.
 279:           KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
 280:           if (kea == RSA || kea == RSA_PSK)
 281:             {
 282:               keyExchange = new RSAGen(kea == RSA);
 283:               tasks.add(keyExchange);
 284:               if (kea == RSA)
 285:                 state = READ_CERTIFICATE_REQUEST;
 286:               else
 287:                 state = READ_SERVER_KEY_EXCHANGE;
 288:             }
 289:           else
 290:             state = READ_SERVER_KEY_EXCHANGE;
 291:         }
 292:         break;
 293: 
 294:         // Server Key Exchange.
 295:         case READ_SERVER_KEY_EXCHANGE:
 296:         {
 297:           CipherSuite s = engine.session().suite;
 298:           KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
 299:           // XXX also SRP.
 300:           if (kexalg != DHE_DSS && kexalg != DHE_RSA && kexalg != DH_anon
 301:               && kexalg != DHE_PSK && kexalg != PSK && kexalg != RSA_PSK)
 302:             throw new AlertException(new Alert(Level.FATAL,
 303:                                                Description.UNEXPECTED_MESSAGE));
 304: 
 305:           if (handshake.type() != Handshake.Type.SERVER_KEY_EXCHANGE)
 306:             {
 307:               if (kexalg != RSA_PSK && kexalg != PSK)
 308:                 throw new AlertException(new Alert(Level.FATAL,
 309:                                                    Description.UNEXPECTED_MESSAGE));
 310:               state = READ_CERTIFICATE_REQUEST;
 311:               return HandshakeStatus.NEED_UNWRAP;
 312:             }
 313: 
 314:           ServerKeyExchange skex = (ServerKeyExchange) handshake.body();
 315:           ByteBuffer paramsBuffer = null;
 316:           if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
 317:             {
 318:               ServerDHParams dhParams = (ServerDHParams) skex.params();
 319:               ByteBuffer b = dhParams.buffer();
 320:               paramsBuffer = ByteBuffer.allocate(b.remaining());
 321:               paramsBuffer.put(b);
 322:             }
 323: 
 324:           if (s.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
 325:             {
 326:               byte[] signature = skex.signature().signature();
 327:               paramsVerifier = new ParamsVerifier(paramsBuffer, signature);
 328:               tasks.add(paramsVerifier);
 329:             }
 330: 
 331:           if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
 332:             {
 333:               ServerDHParams dhParams = (ServerDHParams) skex.params();
 334:               DHPublicKey serverKey = new GnuDHPublicKey(null,
 335:                                                          dhParams.p(),
 336:                                                          dhParams.g(),
 337:                                                          dhParams.y());
 338:               DHParameterSpec params = new DHParameterSpec(dhParams.p(),
 339:                                                            dhParams.g());
 340:               keyExchange = new ClientDHGen(serverKey, params, true);
 341:               tasks.add(keyExchange);
 342:             }
 343:           if (kexalg == DHE_PSK)
 344:             {
 345:               ServerDHE_PSKParameters pskParams = (ServerDHE_PSKParameters)
 346:                 skex.params();
 347:               ServerDHParams dhParams = pskParams.params();
 348:               DHPublicKey serverKey = new GnuDHPublicKey(null,
 349:                                                          dhParams.p(),
 350:                                                          dhParams.g(),
 351:                                                          dhParams.y());
 352:               DHParameterSpec params = new DHParameterSpec(dhParams.p(),
 353:                                                            dhParams.g());
 354:               keyExchange = new ClientDHGen(serverKey, params, false);
 355:               tasks.add(keyExchange);
 356:             }
 357:           state = READ_CERTIFICATE_REQUEST;
 358:         }
 359:         break;
 360: 
 361:         // Certificate Request.
 362:         case READ_CERTIFICATE_REQUEST:
 363:         {
 364:           if (handshake.type() != Handshake.Type.CERTIFICATE_REQUEST)
 365:             {
 366:               state = READ_SERVER_HELLO_DONE;
 367:               return HandshakeStatus.NEED_UNWRAP;
 368:             }
 369: 
 370:           CertificateRequest req = (CertificateRequest) handshake.body();
 371:           ClientCertificateTypeList types = req.types();
 372:           LinkedList<String> typeList = new LinkedList<String>();
 373:           for (ClientCertificateType t : types)
 374:             typeList.add(t.name());
 375: 
 376:           X500PrincipalList issuers = req.authorities();
 377:           LinkedList<X500Principal> issuerList = new LinkedList<X500Principal>();
 378:           for (X500Principal p : issuers)
 379:             issuerList.add(p);
 380: 
 381:           certLoader = new CertLoader(typeList, issuerList);
 382:           tasks.add(certLoader);
 383:         }
 384:         break;
 385: 
 386:         // Server Hello Done.
 387:         case READ_SERVER_HELLO_DONE:
 388:         {
 389:           if (handshake.type() != Handshake.Type.SERVER_HELLO_DONE)
 390:             throw new AlertException(new Alert(Level.FATAL,
 391:                                                Description.UNEXPECTED_MESSAGE));
 392:           state = WRITE_CERTIFICATE;
 393:         }
 394:         break;
 395: 
 396:         // Finished.
 397:         case READ_FINISHED:
 398:         {
 399:           if (handshake.type() != Handshake.Type.FINISHED)
 400:             throw new AlertException(new Alert(Level.FATAL,
 401:                                                Description.UNEXPECTED_MESSAGE));
 402: 
 403:           Finished serverFinished = (Finished) handshake.body();
 404:           MessageDigest md5copy = null;
 405:           MessageDigest shacopy = null;
 406:           try
 407:             {
 408:               md5copy = (MessageDigest) md5.clone();
 409:               shacopy = (MessageDigest) sha.clone();
 410:             }
 411:           catch (CloneNotSupportedException cnse)
 412:             {
 413:               // We're improperly configured to use a non-cloneable
 414:               // md5/sha-1, OR there's a runtime bug.
 415:               throw new SSLException(cnse);
 416:             }
 417:           Finished clientFinished =
 418:             new Finished(generateFinished(md5copy, shacopy,
 419:                                           false, engine.session()),
 420:                                           engine.session().version);
 421: 
 422:           if (Debug.DEBUG)
 423:             logger.logv(Component.SSL_HANDSHAKE, "clientFinished: {0}",
 424:                         clientFinished);
 425: 
 426:           if (engine.session().version == ProtocolVersion.SSL_3)
 427:             {
 428:               if (!Arrays.equals(clientFinished.md5Hash(),
 429:                                  serverFinished.md5Hash())
 430:                   || !Arrays.equals(clientFinished.shaHash(),
 431:                                     serverFinished.shaHash()))
 432:                 {
 433:                   engine.session().invalidate();
 434:                   throw new SSLException("session verify failed");
 435:                 }
 436:             }
 437:           else
 438:             {
 439:               if (!Arrays.equals(clientFinished.verifyData(),
 440:                                  serverFinished.verifyData()))
 441:                 {
 442:                   engine.session().invalidate();
 443:                   throw new SSLException("session verify failed");
 444:                 }
 445:             }
 446: 
 447:           if (continuedSession)
 448:             {
 449:               engine.changeCipherSpec();
 450:               state = WRITE_FINISHED;
 451:             }
 452:           else
 453:             state = DONE;
 454:         }
 455:         break;
 456: 
 457:         default:
 458:           throw new IllegalStateException("invalid state: " + state);
 459:       }
 460: 
 461:     handshakeOffset += handshake.length() + 4;
 462: 
 463:     if (!tasks.isEmpty())
 464:       return HandshakeStatus.NEED_TASK;
 465:     if (state.isWriteState()
 466:         || (outBuffer != null && outBuffer.hasRemaining()))
 467:       return HandshakeStatus.NEED_WRAP;
 468:     if (state.isReadState())
 469:       return HandshakeStatus.NEED_UNWRAP;
 470: 
 471:     return HandshakeStatus.FINISHED;
 472:   }
 473: 
 474:   /* (non-Javadoc)
 475:    * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleOutput(java.nio.ByteBuffer)
 476:    */
 477:   @Override protected HandshakeStatus implHandleOutput(ByteBuffer fragment)
 478:     throws SSLException
 479:   {
 480:     if (Debug.DEBUG)
 481:       logger.logv(Component.SSL_HANDSHAKE, "output to {0}; state:{1}; outBuffer:{2}",
 482:                   fragment, state, outBuffer);
 483: 
 484:     // Drain the output buffer, if it needs it.
 485:     if (outBuffer != null && outBuffer.hasRemaining())
 486:       {
 487:         int l = Math.min(fragment.remaining(), outBuffer.remaining());
 488:         fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
 489:         outBuffer.position(outBuffer.position() + l);
 490:       }
 491: 
 492:     if (!fragment.hasRemaining())
 493:       {
 494:         if (state.isWriteState() || outBuffer.hasRemaining())
 495:           return HandshakeStatus.NEED_WRAP;
 496:         else
 497:           return HandshakeStatus.NEED_UNWRAP;
 498:       }
 499: 
 500: outer_loop:
 501:     while (fragment.remaining() >= 4 && state.isWriteState())
 502:       {
 503:         if (Debug.DEBUG)
 504:           logger.logv(Component.SSL_HANDSHAKE, "loop state={0}", state);
 505: 
 506:         switch (state)
 507:           {
 508:             case WRITE_CLIENT_HELLO:
 509:             {
 510:               ClientHelloBuilder hello = new ClientHelloBuilder();
 511:               AbstractSessionContext ctx = (AbstractSessionContext)
 512:                 engine.contextImpl.engineGetClientSessionContext();
 513:               continued = (SessionImpl) ctx.getSession(engine.getPeerHost(),
 514:                                                        engine.getPeerPort());
 515:               engine.session().setId(new Session.ID(new byte[0]));
 516:               Session.ID sid = engine.session().id();
 517:               // If we have a session that we may want to continue, send
 518:               // that ID.
 519:               if (continued != null)
 520:                 sid = continued.id();
 521: 
 522:               hello.setSessionId(sid.id());
 523:               sentVersion = chooseVersion();
 524:               hello.setVersion(sentVersion);
 525:               hello.setCipherSuites(getSuites());
 526:               hello.setCompressionMethods(getCompressionMethods());
 527:               Random r = hello.random();
 528:               r.setGmtUnixTime(Util.unixTime());
 529:               byte[] nonce = new byte[28];
 530:               engine.session().random().nextBytes(nonce);
 531:               r.setRandomBytes(nonce);
 532:               clientRandom = r.copy();
 533:               if (enableExtensions())
 534:                 {
 535:                   List<Extension> extensions = new LinkedList<Extension>();
 536:                   MaxFragmentLength fraglen = maxFragmentLength();
 537:                   if (fraglen != null)
 538:                     {
 539:                       extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH,
 540:                                                    fraglen));
 541:                       maxFragmentLengthSent = fraglen;
 542:                     }
 543: 
 544:                   String host = engine.getPeerHost();
 545:                   if (host != null)
 546:                     {
 547:                       ServerName name
 548:                         = new ServerName(NameType.HOST_NAME, host);
 549:                       ServerNameList names
 550:                         = new ServerNameList(Collections.singletonList(name));
 551:                       extensions.add(new Extension(Extension.Type.SERVER_NAME,
 552:                                                    names));
 553:                     }
 554: 
 555:                   if (truncatedHMac())
 556:                     {
 557:                       extensions.add(new Extension(Extension.Type.TRUNCATED_HMAC,
 558:                                                    new TruncatedHMAC()));
 559:                       truncatedHMacSent = true;
 560:                     }
 561: 
 562:                   ExtensionList elist = new ExtensionList(extensions);
 563:                   hello.setExtensions(elist.buffer());
 564:                 }
 565:               else
 566:                 hello.setDisableExtensions(true);
 567: 
 568:               if (Debug.DEBUG)
 569:                 logger.logv(Component.SSL_HANDSHAKE, "{0}", hello);
 570: 
 571:               fragment.putInt((Handshake.Type.CLIENT_HELLO.getValue() << 24)
 572:                               | (hello.length() & 0xFFFFFF));
 573:               outBuffer = hello.buffer();
 574:               int l = Math.min(fragment.remaining(), outBuffer.remaining());
 575:               fragment.put((ByteBuffer) outBuffer.duplicate()
 576:                            .limit(outBuffer.position() + l));
 577:               outBuffer.position(outBuffer.position() + l);
 578: 
 579:               state = READ_SERVER_HELLO;
 580:             }
 581:             break;
 582: 
 583:             case WRITE_CERTIFICATE:
 584:             {
 585:               java.security.cert.Certificate[] chain
 586:                 = engine.session().getLocalCertificates();
 587:               if (chain != null)
 588:                 {
 589:                   CertificateBuilder cert
 590:                     = new CertificateBuilder(CertificateType.X509);
 591:                   try
 592:                     {
 593:                       cert.setCertificates(Arrays.asList(chain));
 594:                     }
 595:                   catch (CertificateException ce)
 596:                     {
 597:                       throw new AlertException(new Alert(Level.FATAL,
 598:                                                          Description.INTERNAL_ERROR),
 599:                                                ce);
 600:                     }
 601: 
 602:                   outBuffer = cert.buffer();
 603: 
 604:                   fragment.putInt((Handshake.Type.CERTIFICATE.getValue() << 24)
 605:                                   | (cert.length() & 0xFFFFFF));
 606: 
 607:                   int l = Math.min(fragment.remaining(), outBuffer.remaining());
 608:                   fragment.put((ByteBuffer) outBuffer.duplicate()
 609:                                .limit(outBuffer.position() + l));
 610:                   outBuffer.position(outBuffer.position() + l);
 611:                 }
 612:               state = WRITE_CLIENT_KEY_EXCHANGE;
 613:             }
 614:             break;
 615: 
 616:             case WRITE_CLIENT_KEY_EXCHANGE:
 617:             {
 618:               KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
 619:               ClientKeyExchangeBuilder ckex
 620:                 = new ClientKeyExchangeBuilder(engine.session().suite,
 621:                                                engine.session().version);
 622:               if (kea == DHE_DSS || kea == DHE_RSA || kea == DH_anon
 623:                   || kea == DH_DSS || kea == DH_RSA)
 624:                 {
 625:                   assert(dhPair != null);
 626:                   DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
 627:                   ClientDiffieHellmanPublic pub
 628:                     = new ClientDiffieHellmanPublic(pubkey.getY());
 629:                   ckex.setExchangeKeys(pub.buffer());
 630:                 }
 631:               if (kea == RSA || kea == RSA_PSK)
 632:                 {
 633:                   assert(keyExchange instanceof RSAGen);
 634:                   assert(keyExchange.hasRun());
 635:                   if (keyExchange.thrown() != null)
 636:                     throw new AlertException(new Alert(Level.FATAL,
 637:                                                        Description.HANDSHAKE_FAILURE),
 638:                                              keyExchange.thrown());
 639:                   EncryptedPreMasterSecret epms
 640:                     = new EncryptedPreMasterSecret(((RSAGen) keyExchange).encryptedSecret(),
 641:                                                    engine.session().version);
 642:                   if (kea == RSA)
 643:                     ckex.setExchangeKeys(epms.buffer());
 644:                   else
 645:                     {
 646:                       String identity = getPSKIdentity();
 647:                       if (identity == null)
 648:                         throw new SSLException("no pre-shared-key identity;"
 649:                                                + " set the security property"
 650:                                                + " \"jessie.client.psk.identity\"");
 651:                       ClientRSA_PSKParameters params =
 652:                         new ClientRSA_PSKParameters(identity, epms.buffer());
 653:                       ckex.setExchangeKeys(params.buffer());
 654:                       generatePSKSecret(identity, preMasterSecret, true);
 655:                     }
 656:                 }
 657:               if (kea == DHE_PSK)
 658:                 {
 659:                   assert(keyExchange instanceof ClientDHGen);
 660:                   assert(dhPair != null);
 661:                   String identity = getPSKIdentity();
 662:                   if (identity == null)
 663:                     throw new SSLException("no pre-shared key identity; set"
 664:                                            + " the security property"
 665:                                            + " \"jessie.client.psk.identity\"");
 666:                   DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
 667:                   ClientDHE_PSKParameters params =
 668:                     new ClientDHE_PSKParameters(identity,
 669:                                                 new ClientDiffieHellmanPublic(pubkey.getY()));
 670:                   ckex.setExchangeKeys(params.buffer());
 671:                   generatePSKSecret(identity, preMasterSecret, true);
 672:                 }
 673:               if (kea == PSK)
 674:                 {
 675:                   String identity = getPSKIdentity();
 676:                   if (identity == null)
 677:                     throw new SSLException("no pre-shared key identity; set"
 678:                                            + " the security property"
 679:                                            + " \"jessie.client.psk.identity\"");
 680:                   generatePSKSecret(identity, null, true);
 681:                   ClientPSKParameters params = new ClientPSKParameters(identity);
 682:                   ckex.setExchangeKeys(params.buffer());
 683:                 }
 684:               if (kea == NONE)
 685:                 {
 686:                   Inflater inflater = null;
 687:                   Deflater deflater = null;
 688:                   if (compression == CompressionMethod.ZLIB)
 689:                     {
 690:                       inflater = new Inflater();
 691:                       deflater = new Deflater();
 692:                     }
 693:                   inParams = new InputSecurityParameters(null, null, inflater,
 694:                                                          engine.session(),
 695:                                                          engine.session().suite);
 696:                   outParams = new OutputSecurityParameters(null, null, deflater,
 697:                                                            engine.session(),
 698:                                                            engine.session().suite);
 699:                   engine.session().privateData.masterSecret = new byte[0];
 700:                 }
 701: 
 702:               if (Debug.DEBUG)
 703:                 logger.logv(Component.SSL_HANDSHAKE, "{0}", ckex);
 704: 
 705:               outBuffer = ckex.buffer();
 706:               if (Debug.DEBUG)
 707:                 logger.logv(Component.SSL_HANDSHAKE, "client kex buffer {0}", outBuffer);
 708:               fragment.putInt((Handshake.Type.CLIENT_KEY_EXCHANGE.getValue() << 24)
 709:                               | (ckex.length() & 0xFFFFFF));
 710:               int l = Math.min(fragment.remaining(), outBuffer.remaining());
 711:               fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
 712:               outBuffer.position(outBuffer.position() + l);
 713: 
 714:               if (privateKey != null)
 715:                 {
 716:                   genCertVerify = new GenCertVerify(md5, sha);
 717:                   tasks.add(genCertVerify);
 718:                   state = WRITE_CERTIFICATE_VERIFY;
 719:                 }
 720:               else
 721:                 {
 722:                   engine.changeCipherSpec();
 723:                   state = WRITE_FINISHED;
 724:                 }
 725:             }
 726:             // Both states terminate in a NEED_TASK, or a need to change cipher
 727:             // specs; so we can't write any more messages here.
 728:             break outer_loop;
 729: 
 730:             case WRITE_CERTIFICATE_VERIFY:
 731:             {
 732:               assert(genCertVerify != null);
 733:               assert(genCertVerify.hasRun());
 734:               CertificateVerify verify = new CertificateVerify(genCertVerify.signed(),
 735:                                                                engine.session().suite.signatureAlgorithm());
 736: 
 737:               outBuffer = verify.buffer();
 738:               fragment.putInt((Handshake.Type.CERTIFICATE_VERIFY.getValue() << 24)
 739:                               | (verify.length() & 0xFFFFFF));
 740:               int l = Math.min(fragment.remaining(), outBuffer.remaining());
 741:               fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
 742:               outBuffer.position(outBuffer.position() + l);
 743: 
 744:               // XXX This is a potential problem: we may not have drained
 745:               // outBuffer, but set the changeCipherSpec toggle.
 746:               engine.changeCipherSpec();
 747:               state = WRITE_FINISHED;
 748:             }
 749:             break outer_loop;
 750: 
 751:             case WRITE_FINISHED:
 752:             {
 753:               MessageDigest md5copy = null;
 754:               MessageDigest shacopy = null;
 755:               try
 756:                 {
 757:                   md5copy = (MessageDigest) md5.clone();
 758:                   shacopy = (MessageDigest) sha.clone();
 759:                 }
 760:               catch (CloneNotSupportedException cnse)
 761:                 {
 762:                   // We're improperly configured to use a non-cloneable
 763:                   // md5/sha-1, OR there's a runtime bug.
 764:                   throw new SSLException(cnse);
 765:                 }
 766:               outBuffer
 767:                 = generateFinished(md5copy, shacopy, true,
 768:                                    engine.session());
 769: 
 770:               fragment.putInt((Handshake.Type.FINISHED.getValue() << 24)
 771:                               | outBuffer.remaining() & 0xFFFFFF);
 772: 
 773:               int l = Math.min(outBuffer.remaining(), fragment.remaining());
 774:               fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
 775:               outBuffer.position(outBuffer.position() + l);
 776: 
 777:               if (continuedSession)
 778:                 state = DONE;
 779:               else
 780:                 state = READ_FINISHED;
 781:             }
 782:             break;
 783: 
 784:             default:
 785:               throw new IllegalStateException("invalid state: " + state);
 786:           }
 787:       }
 788: 
 789:     if (!tasks.isEmpty())
 790:       return HandshakeStatus.NEED_TASK;
 791:     if (state.isWriteState() ||
 792:         (outBuffer != null && outBuffer.hasRemaining()))
 793:       return HandshakeStatus.NEED_WRAP;
 794:     if (state.isReadState())
 795:       return HandshakeStatus.NEED_UNWRAP;
 796: 
 797:     return HandshakeStatus.FINISHED;
 798:   }
 799: 
 800:   /* (non-Javadoc)
 801:    * @see gnu.javax.net.ssl.provider.AbstractHandshake#status()
 802:    */
 803:   @Override HandshakeStatus status()
 804:   {
 805:     if (state.isReadState())
 806:       return HandshakeStatus.NEED_UNWRAP;
 807:     if (state.isWriteState())
 808:       return HandshakeStatus.NEED_WRAP;
 809:     return HandshakeStatus.FINISHED;
 810:   }
 811: 
 812:   @Override void checkKeyExchange() throws SSLException
 813:   {
 814:     // XXX implement.
 815:   }
 816: 
 817:   /* (non-Javadoc)
 818:    * @see gnu.javax.net.ssl.provider.AbstractHandshake#handleV2Hello(java.nio.ByteBuffer)
 819:    */
 820:   @Override void handleV2Hello(ByteBuffer hello) throws SSLException
 821:   {
 822:     throw new SSLException("this should be impossible");
 823:   }
 824: 
 825:   private ProtocolVersion chooseVersion() throws SSLException
 826:   {
 827:     // Select the highest enabled version, for our initial key exchange.
 828:     ProtocolVersion version = null;
 829:     for (String ver : engine.getEnabledProtocols())
 830:       {
 831:         try
 832:           {
 833:             ProtocolVersion v = ProtocolVersion.forName(ver);
 834:             if (version == null || version.compareTo(v) < 0)
 835:               version = v;
 836:           }
 837:         catch (Exception x)
 838:           {
 839:             continue;
 840:           }
 841:       }
 842: 
 843:     if (version == null)
 844:       throw new SSLException("no suitable enabled versions");
 845: 
 846:     return version;
 847:   }
 848: 
 849:   private List<CipherSuite> getSuites() throws SSLException
 850:   {
 851:     List<CipherSuite> suites = new LinkedList<CipherSuite>();
 852:     for (String s : engine.getEnabledCipherSuites())
 853:       {
 854:         CipherSuite suite = CipherSuite.forName(s);
 855:         if (suite != null)
 856:           suites.add(suite);
 857:       }
 858:     if (suites.isEmpty())
 859:       throw new SSLException("no cipher suites enabled");
 860:     return suites;
 861:   }
 862: 
 863:   private List<CompressionMethod> getCompressionMethods()
 864:   {
 865:     List<CompressionMethod> methods = new LinkedList<CompressionMethod>();
 866:     GetSecurityPropertyAction gspa = new GetSecurityPropertyAction("jessie.enable.compression");
 867:     if (Boolean.valueOf(AccessController.doPrivileged(gspa)))
 868:       methods.add(CompressionMethod.ZLIB);
 869:     methods.add(CompressionMethod.NULL);
 870:     return methods;
 871:   }
 872: 
 873:   private boolean enableExtensions()
 874:   {
 875:     GetSecurityPropertyAction action
 876:       = new GetSecurityPropertyAction("jessie.client.enable.extensions");
 877:     return Boolean.valueOf(AccessController.doPrivileged(action));
 878:   }
 879: 
 880:   private MaxFragmentLength maxFragmentLength()
 881:   {
 882:     GetSecurityPropertyAction action
 883:       = new GetSecurityPropertyAction("jessie.client.maxFragmentLength");
 884:     String s = AccessController.doPrivileged(action);
 885:     if (s != null)
 886:       {
 887:         try
 888:           {
 889:             int len = Integer.parseInt(s);
 890:             switch (len)
 891:               {
 892:                 case 9:
 893:                 case (1 <<  9): return MaxFragmentLength.LEN_2_9;
 894:                 case 10:
 895:                 case (1 << 10): return MaxFragmentLength.LEN_2_10;
 896:                 case 11:
 897:                 case (1 << 11): return MaxFragmentLength.LEN_2_11;
 898:                 case 12:
 899:                 case (1 << 12): return MaxFragmentLength.LEN_2_12;
 900:               }
 901:           }
 902:         catch (NumberFormatException nfe)
 903:           {
 904:           }
 905:       }
 906:     return null;
 907:   }
 908: 
 909:   private boolean truncatedHMac()
 910:   {
 911:     GetSecurityPropertyAction action
 912:       = new GetSecurityPropertyAction("jessie.client.truncatedHMac");
 913:     return Boolean.valueOf(AccessController.doPrivileged(action));
 914:   }
 915: 
 916:   private String getPSKIdentity()
 917:   {
 918:     GetSecurityPropertyAction action
 919:       = new GetSecurityPropertyAction("jessie.client.psk.identity");
 920:     return AccessController.doPrivileged(action);
 921:   }
 922: 
 923:   // Delegated tasks.
 924: 
 925:   class ParamsVerifier extends DelegatedTask
 926:   {
 927:     private final ByteBuffer paramsBuffer;
 928:     private final byte[] signature;
 929:     private boolean verified;
 930: 
 931:     ParamsVerifier(ByteBuffer paramsBuffer, byte[] signature)
 932:     {
 933:       this.paramsBuffer = paramsBuffer;
 934:       this.signature = signature;
 935:     }
 936: 
 937:     public void implRun()
 938:       throws InvalidKeyException, NoSuchAlgorithmException,
 939:              SSLPeerUnverifiedException, SignatureException
 940:     {
 941:       java.security.Signature s
 942:         = java.security.Signature.getInstance(engine.session().suite
 943:                                               .signatureAlgorithm().algorithm());
 944:       s.initVerify(engine.session().getPeerCertificates()[0]);
 945:       s.update(paramsBuffer);
 946:       verified = s.verify(signature);
 947:       synchronized (this)
 948:         {
 949:           notifyAll();
 950:         }
 951:     }
 952: 
 953:     boolean verified()
 954:     {
 955:       return verified;
 956:     }
 957:   }
 958: 
 959:   class ClientDHGen extends DelegatedTask
 960:   {
 961:     private final DHPublicKey serverKey;
 962:     private final DHParameterSpec params;
 963:     private final boolean full;
 964: 
 965:     ClientDHGen(DHPublicKey serverKey, DHParameterSpec params, boolean full)
 966:     {
 967:       this.serverKey = serverKey;
 968:       this.params = params;
 969:       this.full = full;
 970:     }
 971: 
 972:     public void implRun()
 973:       throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
 974:              SSLException
 975:     {
 976:       if (Debug.DEBUG)
 977:         logger.log(Component.SSL_DELEGATED_TASK, "running client DH phase");
 978:       if (paramsVerifier != null)
 979:         {
 980:           synchronized (paramsVerifier)
 981:             {
 982:               try
 983:                 {
 984:                   while (!paramsVerifier.hasRun())
 985:                     paramsVerifier.wait(500);
 986:                 }
 987:               catch (InterruptedException ie)
 988:                 {
 989:                   // Ignore.
 990:                 }
 991:             }
 992:         }
 993:       KeyPairGenerator gen = KeyPairGenerator.getInstance("DH");
 994:       gen.initialize(params, engine.session().random());
 995:       dhPair = gen.generateKeyPair();
 996:       if (Debug.DEBUG_KEY_EXCHANGE)
 997:         logger.logv(Component.SSL_KEY_EXCHANGE,
 998:                     "client keys public:{0} private:{1}", dhPair.getPublic(),
 999:                     dhPair.getPrivate());
1000: 
1001:       initDiffieHellman((DHPrivateKey) dhPair.getPrivate(), engine.session().random());
1002: 
1003:       // We have enough info to do the full key exchange; so let's do it.
1004:       DHPhase phase = new DHPhase(serverKey, full);
1005:       phase.run();
1006:       if (phase.thrown() != null)
1007:         throw new SSLException(phase.thrown());
1008:     }
1009: 
1010:     DHPublicKey serverKey()
1011:     {
1012:       return serverKey;
1013:     }
1014:   }
1015: 
1016:   class CertLoader extends DelegatedTask
1017:   {
1018:     private final List<String> keyTypes;
1019:     private final List<X500Principal> issuers;
1020: 
1021:     CertLoader(List<String> keyTypes, List<X500Principal> issuers)
1022:     {
1023:       this.keyTypes = keyTypes;
1024:       this.issuers = issuers;
1025:     }
1026: 
1027:     public void implRun()
1028:     {
1029:       X509ExtendedKeyManager km = engine.contextImpl.keyManager;
1030:       if (km == null)
1031:         return;
1032:       keyAlias = km.chooseEngineClientAlias(keyTypes.toArray(new String[keyTypes.size()]),
1033:                                             issuers.toArray(new X500Principal[issuers.size()]),
1034:                                             engine);
1035:       engine.session().setLocalCertificates(km.getCertificateChain(keyAlias));
1036:       privateKey = km.getPrivateKey(keyAlias);
1037:     }
1038:   }
1039: 
1040:   class RSAGen extends DelegatedTask
1041:   {
1042:     private byte[] encryptedPreMasterSecret;
1043:     private final boolean full;
1044: 
1045:     RSAGen()
1046:     {
1047:       this(true);
1048:     }
1049: 
1050:     RSAGen(boolean full)
1051:     {
1052:       this.full = full;
1053:     }
1054: 
1055:     public void implRun()
1056:       throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
1057:              NoSuchAlgorithmException, NoSuchPaddingException,
1058:              SSLException
1059:     {
1060:       if (certVerifier != null)
1061:         {
1062:           synchronized (certVerifier)
1063:             {
1064:               try
1065:                 {
1066:                   while (!certVerifier.hasRun())
1067:                     certVerifier.wait(500);
1068:                 }
1069:               catch (InterruptedException ie)
1070:                 {
1071:                   // Ignore.
1072:                 }
1073:             }
1074:         }
1075:       preMasterSecret = new byte[48];
1076:       engine.session().random().nextBytes(preMasterSecret);
1077:       preMasterSecret[0] = (byte) sentVersion.major();
1078:       preMasterSecret[1] = (byte) sentVersion.minor();
1079:       Cipher rsa = Cipher.getInstance("RSA");
1080:       java.security.cert.Certificate cert
1081:         = engine.session().getPeerCertificates()[0];
1082:       if (cert instanceof X509Certificate)
1083:         {
1084:           boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage();
1085:           if (keyUsage != null && !keyUsage[2])
1086:             throw new InvalidKeyException("certificate's keyUsage does not permit keyEncipherment");
1087:         }
1088:       rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
1089:       encryptedPreMasterSecret = rsa.doFinal(preMasterSecret);
1090: 
1091:       // Generate our session keys, because we can.
1092:       if (full)
1093:         {
1094:           generateMasterSecret(clientRandom, serverRandom, engine.session());
1095:           byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
1096:           setupSecurityParameters(keys, true, engine, compression);
1097:         }
1098:     }
1099: 
1100:     byte[] encryptedSecret()
1101:     {
1102:       return encryptedPreMasterSecret;
1103:     }
1104:   }
1105: 
1106:   class GenCertVerify extends DelegatedTask
1107:   {
1108:     private final MessageDigest md5, sha;
1109:     private byte[] signed;
1110: 
1111:     GenCertVerify(MessageDigest md5, MessageDigest sha)
1112:     {
1113:       try
1114:         {
1115:           this.md5 = (MessageDigest) md5.clone();
1116:           this.sha = (MessageDigest) sha.clone();
1117:         }
1118:       catch (CloneNotSupportedException cnse)
1119:         {
1120:           // Our message digests *should* be cloneable.
1121:           throw new Error(cnse);
1122:         }
1123:     }
1124: 
1125:     public void implRun()
1126:       throws InvalidKeyException, NoSuchAlgorithmException, SignatureException
1127:     {
1128:       byte[] toSign;
1129:       if (engine.session().version == ProtocolVersion.SSL_3)
1130:         {
1131:           toSign = genV3CertificateVerify(md5, sha, engine.session());
1132:         }
1133:       else
1134:         {
1135:           if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
1136:             toSign = Util.concat(md5.digest(), sha.digest());
1137:           else
1138:             toSign = sha.digest();
1139:         }
1140: 
1141:       java.security.Signature sig =
1142:         java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().name());
1143:       sig.initSign(privateKey);
1144:       sig.update(toSign);
1145:       signed = sig.sign();
1146:     }
1147: 
1148:     byte[] signed()
1149:     {
1150:       return signed;
1151:     }
1152:   }
1153: }