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