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

   1: /* AbstractHandshake.java -- abstract handshake handler.
   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 gnu.classpath.debug.Component;
  42: import gnu.classpath.debug.SystemLogger;
  43: import gnu.java.security.action.GetSecurityPropertyAction;
  44: import gnu.java.security.prng.IRandom;
  45: import gnu.java.security.prng.LimitReachedException;
  46: import gnu.java.security.util.ByteArray;
  47: import gnu.javax.security.auth.callback.CertificateCallback;
  48: import gnu.javax.security.auth.callback.DefaultCallbackHandler;
  49: 
  50: import java.nio.ByteBuffer;
  51: import java.security.AccessController;
  52: import java.security.DigestException;
  53: import java.security.InvalidAlgorithmParameterException;
  54: import java.security.InvalidKeyException;
  55: import java.security.KeyManagementException;
  56: import java.security.MessageDigest;
  57: import java.security.NoSuchAlgorithmException;
  58: import java.security.PrivilegedExceptionAction;
  59: import java.security.SecureRandom;
  60: import java.security.cert.CertificateException;
  61: import java.security.cert.X509Certificate;
  62: import java.util.Arrays;
  63: import java.util.HashMap;
  64: import java.util.LinkedList;
  65: import java.util.zip.Deflater;
  66: import java.util.zip.Inflater;
  67: 
  68: import javax.crypto.Cipher;
  69: import javax.crypto.KeyAgreement;
  70: import javax.crypto.Mac;
  71: import javax.crypto.NoSuchPaddingException;
  72: import javax.crypto.SecretKey;
  73: import javax.crypto.interfaces.DHPrivateKey;
  74: import javax.crypto.interfaces.DHPublicKey;
  75: import javax.crypto.spec.IvParameterSpec;
  76: import javax.crypto.spec.SecretKeySpec;
  77: import javax.net.ssl.SSLEngineResult;
  78: import javax.net.ssl.SSLException;
  79: import javax.net.ssl.X509TrustManager;
  80: import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  81: import javax.security.auth.callback.Callback;
  82: import javax.security.auth.callback.CallbackHandler;
  83: import javax.security.auth.callback.ConfirmationCallback;
  84: 
  85: /**
  86:  * The base interface for handshake implementations. Concrete
  87:  * subclasses of this class (one for the server, one for the client)
  88:  * handle the HANDSHAKE content-type in communications.
  89:  */
  90: public abstract class AbstractHandshake
  91: {
  92:   protected static final SystemLogger logger = SystemLogger.SYSTEM;
  93: 
  94:   /**
  95:    * "server finished" -- TLS 1.0 and later
  96:    */
  97:   protected static final byte[] SERVER_FINISHED
  98:     = new byte[] {
  99:       115, 101, 114, 118, 101, 114,  32, 102, 105, 110, 105, 115,
 100:       104, 101, 100
 101:     };
 102: 
 103:   /**
 104:    * "client finished" -- TLS 1.0 and later
 105:    */
 106:   protected static final byte[] CLIENT_FINISHED
 107:     = new byte[] {
 108:        99, 108, 105, 101, 110, 116,  32, 102, 105, 110, 105, 115,
 109:       104, 101, 100
 110:     };
 111: 
 112:   /**
 113:    * "key expansion" -- TLS 1.0 and later
 114:    */
 115:   private static final byte[] KEY_EXPANSION =
 116:     new byte[] { 107, 101, 121,  32, 101, 120, 112,
 117:                   97, 110, 115, 105, 111, 110 };
 118: 
 119:   /**
 120:    * "master secret" -- TLS 1.0 and later
 121:    */
 122:   private static final byte[] MASTER_SECRET
 123:     = new byte[] {
 124:       109,  97, 115, 116, 101, 114,  32, 115, 101,  99, 114, 101, 116
 125:     };
 126: 
 127:   /**
 128:    * "client write key" -- TLS 1.0 exportable whitener.
 129:    */
 130:   private static final byte[] CLIENT_WRITE_KEY
 131:     = new byte[] {
 132:        99, 108, 105, 101, 110, 116,  32, 119, 114, 105, 116, 101,  32, 107,
 133:       101, 121
 134:     };
 135: 
 136:   /**
 137:    * "server write key" -- TLS 1.0 exportable whitener.
 138:    */
 139:   private static final byte[] SERVER_WRITE_KEY
 140:     = new byte[] {
 141:       115, 101, 114, 118, 101, 114,  32, 119, 114, 105, 116, 101,  32, 107,
 142:       101, 121
 143:     };
 144: 
 145:   private static final byte[] IV_BLOCK
 146:     = new byte[] {
 147:        73,  86,  32,  98, 108, 111,  99, 107
 148:     };
 149: 
 150:   /**
 151:    * SSL 3.0; the string "CLNT"
 152:    */
 153:   private static final byte[] SENDER_CLIENT
 154:     = new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
 155: 
 156:   /**
 157:    * SSL 3.0; the string "SRVR"
 158:    */
 159:   private static final byte[] SENDER_SERVER
 160:     = new byte[] { 0x53, 0x52, 0x56, 0x52 };
 161: 
 162:   /**
 163:    * SSL 3.0; the value 0x36 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
 164:    * times.
 165:    */
 166:   protected static final byte[] PAD1 = new byte[48];
 167: 
 168:   /**
 169:    * SSL 3.0; the value 0x5c 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
 170:    * times.
 171:    */
 172:   protected static final byte[] PAD2 = new byte[48];
 173: 
 174:   static
 175:   {
 176:     Arrays.fill(PAD1, SSLHMac.PAD1);
 177:     Arrays.fill(PAD2, SSLHMac.PAD2);
 178:   }
 179: 
 180:   /**
 181:    * The currently-read handshake messages. There may be zero, or
 182:    * multiple, handshake messages in this buffer.
 183:    */
 184:   protected ByteBuffer handshakeBuffer;
 185: 
 186:   /**
 187:    * The offset into `handshakeBuffer' where the first unread
 188:    * handshake message resides.
 189:    */
 190:   protected int handshakeOffset;
 191: 
 192:   protected MessageDigest sha;
 193:   protected MessageDigest md5;
 194: 
 195:   protected final SSLEngineImpl engine;
 196:   protected KeyAgreement keyAgreement;
 197:   protected byte[] preMasterSecret;
 198:   protected InputSecurityParameters inParams;
 199:   protected OutputSecurityParameters outParams;
 200:   protected LinkedList<DelegatedTask> tasks;
 201:   protected Random serverRandom;
 202:   protected Random clientRandom;
 203:   protected CompressionMethod compression;
 204: 
 205:   protected AbstractHandshake(SSLEngineImpl engine)
 206:     throws NoSuchAlgorithmException
 207:   {
 208:     this.engine = engine;
 209:     sha = MessageDigest.getInstance("SHA-1");
 210:     md5 = MessageDigest.getInstance("MD5");
 211:     tasks = new LinkedList<DelegatedTask>();
 212:   }
 213: 
 214:   /**
 215:    * Handles the next input message in the handshake. This is called
 216:    * in response to a call to {@link javax.net.ssl.SSLEngine#unwrap}
 217:    * for a message with content-type HANDSHAKE.
 218:    *
 219:    * @param record The input record. The callee should not assume that
 220:    * the record's buffer is writable, and should not try to use it for
 221:    * output or temporary storage.
 222:    * @return An {@link SSLEngineResult} describing the result.
 223:    */
 224:   public final HandshakeStatus handleInput (ByteBuffer fragment)
 225:     throws SSLException
 226:   {
 227:     if (!tasks.isEmpty())
 228:       return HandshakeStatus.NEED_TASK;
 229: 
 230:     HandshakeStatus status = status();
 231:     if (status != HandshakeStatus.NEED_UNWRAP)
 232:       return status;
 233: 
 234:     // Try to read another...
 235:     if (!pollHandshake(fragment))
 236:       return HandshakeStatus.NEED_UNWRAP;
 237: 
 238:     while (hasMessage() && status != HandshakeStatus.NEED_WRAP)
 239:       {
 240:         int pos = handshakeOffset;
 241:         status = implHandleInput();
 242:         int len = handshakeOffset - pos;
 243:         if (len == 0)
 244:           {
 245:             // Don't bother; the impl is just telling us to go around
 246:             // again.
 247:             continue;
 248:           }
 249:         if (doHash())
 250:           {
 251:             if (Debug.DEBUG)
 252:               logger.logv(Component.SSL_HANDSHAKE, "hashing output\n{0}",
 253:                           Util.hexDump((ByteBuffer) handshakeBuffer
 254:                                        .duplicate().position(pos)
 255:                                        .limit(pos+len), " >> "));
 256:             sha.update((ByteBuffer) handshakeBuffer.duplicate()
 257:                        .position(pos).limit(pos+len));
 258:             md5.update((ByteBuffer) handshakeBuffer.duplicate()
 259:                        .position(pos).limit(pos+len));
 260:           }
 261:       }
 262:     return status;
 263:   }
 264: 
 265:   /**
 266:    * Called to process more handshake data. This method will be called
 267:    * repeatedly while there is remaining handshake data, and while the
 268:    * status is
 269:    * @return
 270:    * @throws SSLException
 271:    */
 272:   protected abstract HandshakeStatus implHandleInput()
 273:     throws SSLException;
 274: 
 275:   /**
 276:    * Produce more handshake output. This is called in response to a
 277:    * call to {@link javax.net.ssl.SSLEngine#wrap}, when the handshake
 278:    * is still in progress.
 279:    *
 280:    * @param record The output record; the callee should put its output
 281:    * handshake message (or a part of it) in the argument's
 282:    * <code>fragment</code>, and should set the record length
 283:    * appropriately.
 284:    * @return An {@link SSLEngineResult} describing the result.
 285:    */
 286:   public final HandshakeStatus handleOutput (ByteBuffer fragment)
 287:     throws SSLException
 288:   {
 289:     if (!tasks.isEmpty())
 290:       return HandshakeStatus.NEED_TASK;
 291: 
 292:     int orig = fragment.position();
 293:     SSLEngineResult.HandshakeStatus status = implHandleOutput(fragment);
 294:     if (doHash())
 295:       {
 296:         if (Debug.DEBUG)
 297:           logger.logv(Component.SSL_HANDSHAKE, "hashing output:\n{0}",
 298:                       Util.hexDump((ByteBuffer) fragment.duplicate().flip().position(orig), " >> "));
 299:         sha.update((ByteBuffer) fragment.duplicate().flip().position(orig));
 300:         md5.update((ByteBuffer) fragment.duplicate().flip().position(orig));
 301:       }
 302:     return status;
 303:   }
 304: 
 305:   /**
 306:    * Called to implement the underlying output handling. The callee should
 307:    * attempt to fill the given buffer as much as it can; this can include
 308:    * multiple, and even partial, handshake messages.
 309:    *
 310:    * @param fragment The buffer the callee should write handshake messages to.
 311:    * @return The new status of the handshake.
 312:    * @throws SSLException If an error occurs processing the output message.
 313:    */
 314:   protected abstract SSLEngineResult.HandshakeStatus implHandleOutput (ByteBuffer fragment)
 315:     throws SSLException;
 316: 
 317:   /**
 318:    * Return a new instance of input security parameters, initialized with
 319:    * the session key. It is, of course, only valid to invoke this method
 320:    * once the handshake is complete, and the session keys established.
 321:    *
 322:    * <p>In the presence of a well-behaving peer, this should be called once
 323:    * the <code>ChangeCipherSpec</code> message is recieved.
 324:    *
 325:    * @return The input parameters for the newly established session.
 326:    * @throws SSLException If the handshake is not complete.
 327:    */
 328:   final InputSecurityParameters getInputParams() throws SSLException
 329:   {
 330:     checkKeyExchange();
 331:     return inParams;
 332:   }
 333: 
 334:   /**
 335:    * Return a new instance of output security parameters, initialized with
 336:    * the session key. This should be called after the
 337:    * <code>ChangeCipherSpec</code> message is sent to the peer.
 338:    *
 339:    * @return The output parameters for the newly established session.
 340:    * @throws SSLException If the handshake is not complete.
 341:    */
 342:   final OutputSecurityParameters getOutputParams() throws SSLException
 343:   {
 344:     checkKeyExchange();
 345:     return outParams;
 346:   }
 347: 
 348:   /**
 349:    * Fetch a delegated task waiting to run, if any.
 350:    *
 351:    * @return The task.
 352:    */
 353:   final Runnable getTask()
 354:   {
 355:     if (tasks.isEmpty())
 356:       return null;
 357:     return tasks.removeFirst();
 358:   }
 359: 
 360:   /**
 361:    * Used by the skeletal code to query the current status of the handshake.
 362:    * This <em>should</em> be the same value as returned by the previous call
 363:    * to {@link #implHandleOutput(ByteBuffer)} or {@link
 364:    *  #implHandleInput(ByteBuffer)}.
 365:    *
 366:    * @return The current handshake status.
 367:    */
 368:   abstract HandshakeStatus status();
 369: 
 370:   /**
 371:    * Check if the key exchange completed successfully, throwing an exception
 372:    * if not.
 373:    *
 374:    * <p>Note that we assume that the caller of our SSLEngine is correct, and
 375:    * that they did run the delegated tasks that encapsulate the key exchange.
 376:    * What we are primarily checking, therefore, is that no error occurred in the
 377:    * key exchange operation itself.
 378:    *
 379:    * @throws SSLException If the key exchange did not complete successfully.
 380:    */
 381:   abstract void checkKeyExchange() throws SSLException;
 382: 
 383:   /**
 384:    * Handle an SSLv2 client hello. This is only used by SSL servers.
 385:    *
 386:    * @param hello The hello message.
 387:    */
 388:   abstract void handleV2Hello(ByteBuffer hello) throws SSLException;
 389: 
 390:   /**
 391:    * Attempt to read the next handshake message from the given
 392:    * record. If only a partial handshake message is available, then
 393:    * this method saves the incoming bytes and returns false. If a
 394:    * complete handshake is read, or if there was one buffered in the
 395:    * handshake buffer, this method returns true, and `handshakeBuffer'
 396:    * can be used to read the handshake.
 397:    *
 398:    * @param record The input record.
 399:    * @return True if a complete handshake is present in the buffer;
 400:    * false if only a partial one.
 401:    */
 402:   protected boolean pollHandshake (final ByteBuffer fragment)
 403:   {
 404:     // Allocate space for the new fragment.
 405:     if (handshakeBuffer == null
 406:         || handshakeBuffer.remaining() < fragment.remaining())
 407:       {
 408:         // We need space for anything still unread in the handshake
 409:         // buffer...
 410:         int len = ((handshakeBuffer == null) ? 0
 411:                    : handshakeBuffer.position() - handshakeOffset);
 412: 
 413:         // Plus room for the incoming record.
 414:         len += fragment.remaining();
 415:         reallocateBuffer(len);
 416:       }
 417: 
 418:     if (Debug.DEBUG)
 419:       logger.logv(Component.SSL_HANDSHAKE, "inserting {0} into {1}",
 420:                   fragment, handshakeBuffer);
 421: 
 422:     // Put the fragment into the buffer.
 423:     handshakeBuffer.put(fragment);
 424: 
 425:     return hasMessage();
 426:   }
 427: 
 428:   protected boolean doHash()
 429:   {
 430:     return true;
 431:   }
 432: 
 433:   /**
 434:    * Tell if the handshake buffer currently has a full handshake
 435:    * message.
 436:    */
 437:   protected boolean hasMessage()
 438:   {
 439:     if (handshakeBuffer == null)
 440:       return false;
 441:     ByteBuffer tmp = handshakeBuffer.duplicate();
 442:     tmp.flip();
 443:     tmp.position(handshakeOffset);
 444:     if (Debug.DEBUG)
 445:       logger.logv(Component.SSL_HANDSHAKE, "current buffer: {0}; test buffer {1}",
 446:                   handshakeBuffer, tmp);
 447:     if (tmp.remaining() < 4)
 448:       return false;
 449:     Handshake handshake = new Handshake(tmp.slice());
 450:     if (Debug.DEBUG)
 451:       logger.logv(Component.SSL_HANDSHAKE, "handshake len:{0} remaining:{1}",
 452:                   handshake.length(), tmp.remaining());
 453:     return (handshake.length() <= tmp.remaining() - 4);
 454:   }
 455: 
 456:   /**
 457:    * Reallocate the handshake buffer so it can hold `totalLen'
 458:    * bytes. The smallest buffer allocated is 1024 bytes, and the size
 459:    * doubles from there until the buffer is sufficiently large.
 460:    */
 461:   private void reallocateBuffer (final int totalLen)
 462:   {
 463:     int len = handshakeBuffer == null ? -1
 464:                                       : handshakeBuffer.capacity() - (handshakeBuffer.limit() - handshakeOffset);
 465:     if (len >= totalLen)
 466:       {
 467:         // Big enough; no need to reallocate; but maybe shift the contents
 468:         // down.
 469:         if (handshakeOffset > 0)
 470:           {
 471:             handshakeBuffer.flip().position(handshakeOffset);
 472:             handshakeBuffer.compact();
 473:             handshakeOffset = 0;
 474:           }
 475:         return;
 476:       }
 477: 
 478:     // Start at 1K (probably the system's page size). Double the size
 479:     // from there.
 480:     len = 1024;
 481:     while (len < totalLen)
 482:       len = len << 1;
 483:     ByteBuffer newBuf = ByteBuffer.allocate (len);
 484: 
 485:     // Copy the unread bytes from the old buffer.
 486:     if (handshakeBuffer != null)
 487:       {
 488:         handshakeBuffer.flip ();
 489:         handshakeBuffer.position(handshakeOffset);
 490:         newBuf.put(handshakeBuffer);
 491:       }
 492:     handshakeBuffer = newBuf;
 493: 
 494:     // We just put only unread handshake messages in the new buffer;
 495:     // the offset of the next one is now zero.
 496:     handshakeOffset = 0;
 497:   }
 498: 
 499:   /**
 500:    * Generate a certificate verify message for SSLv3. In SSLv3, a different
 501:    * algorithm was used to generate this value was subtly different than
 502:    * that used in TLSv1.0 and later. In TLSv1.0 and later, this value is
 503:    * just the digest over the handshake messages.
 504:    *
 505:    * <p>SSLv3 uses the algorithm:
 506:    *
 507:    * <pre>
 508: CertificateVerify.signature.md5_hash
 509:   MD5(master_secret + pad_2 +
 510:       MD5(handshake_messages + master_secret + pad_1));
 511: Certificate.signature.sha_hash
 512:   SHA(master_secret + pad_2 +
 513:       SHA(handshake_messages + master_secret + pad_1));</pre>
 514:    *
 515:    * @param md5 The running MD5 hash of the handshake.
 516:    * @param sha The running SHA-1 hash of the handshake.
 517:    * @param session The current session being negotiated.
 518:    * @return The computed to-be-signed value.
 519:    */
 520:   protected byte[] genV3CertificateVerify(MessageDigest md5,
 521:                                           MessageDigest sha,
 522:                                           SessionImpl session)
 523:   {
 524:     byte[] md5value = null;
 525:     if (session.suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
 526:       {
 527:         md5.update(session.privateData.masterSecret);
 528:         md5.update(PAD1, 0, 48);
 529:         byte[] tmp = md5.digest();
 530:         md5.reset();
 531:         md5.update(session.privateData.masterSecret);
 532:         md5.update(PAD2, 0, 48);
 533:         md5.update(tmp);
 534:         md5value = md5.digest();
 535:       }
 536: 
 537:     sha.update(session.privateData.masterSecret);
 538:     sha.update(PAD1, 0, 40);
 539:     byte[] tmp = sha.digest();
 540:     sha.reset();
 541:     sha.update(session.privateData.masterSecret);
 542:     sha.update(PAD2, 0, 40);
 543:     sha.update(tmp);
 544:     byte[] shavalue = sha.digest();
 545: 
 546:     if (md5value != null)
 547:       return Util.concat(md5value, shavalue);
 548: 
 549:     return shavalue;
 550:   }
 551: 
 552:   /**
 553:    * Generate the session keys from the computed master secret.
 554:    *
 555:    * @param clientRandom The client's nonce.
 556:    * @param serverRandom The server's nonce.
 557:    * @param session The session being established.
 558:    * @return The derived keys.
 559:    */
 560:   protected byte[][] generateKeys(Random clientRandom, Random serverRandom,
 561:                                   SessionImpl session)
 562:   {
 563:     int maclen = 20; // SHA-1.
 564:     if (session.suite.macAlgorithm() == MacAlgorithm.MD5)
 565:       maclen = 16;
 566:     int ivlen = 0;
 567:     if (session.suite.cipherAlgorithm() == CipherAlgorithm.DES
 568:         || session.suite.cipherAlgorithm() == CipherAlgorithm.DESede)
 569:       ivlen = 8;
 570:     if (session.suite.cipherAlgorithm() == CipherAlgorithm.AES)
 571:       ivlen = 16;
 572:     int keylen = session.suite.keyLength();
 573: 
 574:     byte[][] keys = new byte[6][];
 575:     keys[0] = new byte[maclen]; // client_write_MAC_secret
 576:     keys[1] = new byte[maclen]; // server_write_MAC_secret
 577:     keys[2] = new byte[keylen]; // client_write_key
 578:     keys[3] = new byte[keylen]; // server_write_key
 579:     keys[4] = new byte[ivlen];  // client_write_iv
 580:     keys[5] = new byte[ivlen];  // server_write_iv
 581: 
 582:     IRandom prf = null;
 583:     if (session.version == ProtocolVersion.SSL_3)
 584:       {
 585:         byte[] seed = new byte[clientRandom.length()
 586:                                + serverRandom.length()];
 587:         serverRandom.buffer().get(seed, 0, serverRandom.length());
 588:         clientRandom.buffer().get(seed, serverRandom.length(),
 589:                                   clientRandom.length());
 590:         prf = new SSLRandom();
 591:         HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
 592:         attr.put(SSLRandom.SECRET, session.privateData.masterSecret);
 593:         attr.put(SSLRandom.SEED, seed);
 594:         prf.init(attr);
 595:       }
 596:     else
 597:       {
 598:         byte[] seed = new byte[KEY_EXPANSION.length
 599:                                + clientRandom.length()
 600:                                + serverRandom.length()];
 601:         System.arraycopy(KEY_EXPANSION, 0, seed, 0, KEY_EXPANSION.length);
 602:         serverRandom.buffer().get(seed, KEY_EXPANSION.length,
 603:                                   serverRandom.length());
 604:         clientRandom.buffer().get(seed, (KEY_EXPANSION.length
 605:                                          + serverRandom.length()),
 606:                                   clientRandom.length());
 607: 
 608:         prf = new TLSRandom();
 609:         HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
 610:         attr.put(TLSRandom.SECRET, session.privateData.masterSecret);
 611:         attr.put(TLSRandom.SEED, seed);
 612:         prf.init(attr);
 613:       }
 614: 
 615:     try
 616:       {
 617:         prf.nextBytes(keys[0], 0, keys[0].length);
 618:         prf.nextBytes(keys[1], 0, keys[1].length);
 619:         prf.nextBytes(keys[2], 0, keys[2].length);
 620:         prf.nextBytes(keys[3], 0, keys[3].length);
 621: 
 622:         if (session.suite.isExportable())
 623:           {
 624:             if (session.version == ProtocolVersion.SSL_3)
 625:               {
 626:                 MessageDigest md5 = MessageDigest.getInstance("MD5");
 627:                 md5.update(clientRandom.buffer());
 628:                 md5.update(serverRandom.buffer());
 629:                 byte[] d = md5.digest();
 630:                 System.arraycopy(d, 0, keys[4], 0, keys[4].length);
 631: 
 632:                 md5.reset();
 633:                 md5.update(serverRandom.buffer());
 634:                 md5.update(clientRandom.buffer());
 635:                 d = md5.digest();
 636:                 System.arraycopy(d, 0, keys[5], 0, keys[5].length);
 637: 
 638:                 md5.reset();
 639:                 md5.update(keys[2]);
 640:                 md5.update(clientRandom.buffer());
 641:                 md5.update(serverRandom.buffer());
 642:                 keys[2] = Util.trim(md5.digest(), 8);
 643: 
 644:                 md5.reset();
 645:                 md5.update(keys[3]);
 646:                 md5.update(serverRandom.buffer());
 647:                 md5.update(clientRandom.buffer());
 648:                 keys[3] = Util.trim(md5.digest(), 8);
 649:               }
 650:             else
 651:               {
 652:                 TLSRandom prf2 = new TLSRandom();
 653:                 HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
 654:                 attr.put(TLSRandom.SECRET, keys[2]);
 655:                 byte[] seed = new byte[CLIENT_WRITE_KEY.length +
 656:                                        clientRandom.length() +
 657:                                        serverRandom.length()];
 658:                 System.arraycopy(CLIENT_WRITE_KEY, 0, seed, 0,
 659:                                  CLIENT_WRITE_KEY.length);
 660:                 clientRandom.buffer().get(seed, CLIENT_WRITE_KEY.length,
 661:                                           clientRandom.length());
 662:                 serverRandom.buffer().get(seed, CLIENT_WRITE_KEY.length
 663:                                           + clientRandom.length(),
 664:                                           serverRandom.length());
 665:                 attr.put(TLSRandom.SEED, seed);
 666:                 prf2.init(attr);
 667:                 keys[2] = new byte[8];
 668:                 prf2.nextBytes(keys[2], 0, keys[2].length);
 669: 
 670:                 attr.put(TLSRandom.SECRET, keys[3]);
 671:                 seed = new byte[SERVER_WRITE_KEY.length +
 672:                                 serverRandom.length() +
 673:                                 clientRandom.length()];
 674:                 System.arraycopy(SERVER_WRITE_KEY, 0, seed, 0,
 675:                                  SERVER_WRITE_KEY.length);
 676:                 serverRandom.buffer().get(seed, SERVER_WRITE_KEY.length,
 677:                                           serverRandom.length());
 678:                 clientRandom.buffer().get(seed, SERVER_WRITE_KEY.length
 679:                                           + serverRandom.length(),
 680:                                           + clientRandom.length());
 681:                 attr.put(TLSRandom.SEED, seed);
 682:                 prf2.init(attr);
 683:                 keys[3] = new byte[8];
 684:                 prf2.nextBytes(keys[3], 0, keys[3].length);
 685: 
 686:                 attr.put(TLSRandom.SECRET, new byte[0]);
 687:                 seed = new byte[IV_BLOCK.length +
 688:                                 clientRandom.length() +
 689:                                 serverRandom.length()];
 690:                 System.arraycopy(IV_BLOCK, 0, seed, 0, IV_BLOCK.length);
 691:                 clientRandom.buffer().get(seed, IV_BLOCK.length,
 692:                                           clientRandom.length());
 693:                 serverRandom.buffer().get(seed, IV_BLOCK.length
 694:                                           + clientRandom.length(),
 695:                                           serverRandom.length());
 696:                 attr.put(TLSRandom.SEED, seed);
 697:                 prf2.init(attr);
 698:                 prf2.nextBytes(keys[4], 0, keys[4].length);
 699:                 prf2.nextBytes(keys[5], 0, keys[5].length);
 700:               }
 701:           }
 702:         else
 703:           {
 704:             prf.nextBytes(keys[4], 0, keys[4].length);
 705:             prf.nextBytes(keys[5], 0, keys[5].length);
 706:           }
 707:       }
 708:     catch (LimitReachedException lre)
 709:       {
 710:         // Won't happen with our implementation.
 711:         throw new Error(lre);
 712:       }
 713:     catch (NoSuchAlgorithmException nsae)
 714:       {
 715:         throw new Error(nsae);
 716:       }
 717: 
 718:     if (Debug.DEBUG_KEY_EXCHANGE)
 719:       logger.logv(Component.SSL_KEY_EXCHANGE,
 720:                   "keys generated;\n  [0]: {0}\n  [1]: {1}\n  [2]: {2}\n" +
 721:                   "  [3]: {3}\n  [4]: {4}\n  [5]: {5}",
 722:                   Util.toHexString(keys[0], ':'),
 723:                   Util.toHexString(keys[1], ':'),
 724:                   Util.toHexString(keys[2], ':'),
 725:                   Util.toHexString(keys[3], ':'),
 726:                   Util.toHexString(keys[4], ':'),
 727:                   Util.toHexString(keys[5], ':'));
 728:     return keys;
 729:   }
 730: 
 731:   /**
 732:    * Generate a "finished" message. The hashes passed in are modified
 733:    * by this function, so they should be clone copies of the digest if
 734:    * the hash function needs to be used more.
 735:    *
 736:    * @param md5 The MD5 computation.
 737:    * @param sha The SHA-1 computation.
 738:    * @param isClient Whether or not the client-side finished message is
 739:    *  being computed.
 740:    * @param session The current session.
 741:    * @return A byte buffer containing the computed finished message.
 742:    */
 743:   protected ByteBuffer generateFinished(MessageDigest md5,
 744:                                         MessageDigest sha,
 745:                                         boolean isClient,
 746:                                         SessionImpl session)
 747:   {
 748:     ByteBuffer finishedBuffer = null;
 749:     if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
 750:       {
 751:         finishedBuffer = ByteBuffer.allocate(12);
 752:         TLSRandom prf = new TLSRandom();
 753:         byte[] md5val = md5.digest();
 754:         byte[] shaval = sha.digest();
 755:         if (Debug.DEBUG)
 756:           logger.logv(Component.SSL_HANDSHAKE, "finished md5:{0} sha:{1}",
 757:                       Util.toHexString(md5val, ':'),
 758:                       Util.toHexString(shaval, ':'));
 759:         byte[] seed = new byte[CLIENT_FINISHED.length
 760:                                + md5val.length
 761:                                + shaval.length];
 762:         if (isClient)
 763:           System.arraycopy(CLIENT_FINISHED, 0, seed, 0, CLIENT_FINISHED.length);
 764:         else
 765:           System.arraycopy(SERVER_FINISHED, 0, seed, 0, SERVER_FINISHED.length);
 766:         System.arraycopy(md5val, 0,
 767:                          seed, CLIENT_FINISHED.length,
 768:                          md5val.length);
 769:         System.arraycopy(shaval, 0,
 770:                          seed, CLIENT_FINISHED.length + md5val.length,
 771:                          shaval.length);
 772:         HashMap<String, Object> params = new HashMap<String, Object>(2);
 773:         params.put(TLSRandom.SECRET, session.privateData.masterSecret);
 774:         params.put(TLSRandom.SEED, seed);
 775:         prf.init(params);
 776:         byte[] buf = new byte[12];
 777:         prf.nextBytes(buf, 0, buf.length);
 778:         finishedBuffer.put(buf).position(0);
 779:       }
 780:     else
 781:       {
 782:         // The SSLv3 algorithm is:
 783:         //
 784:         //   enum { client(0x434C4E54), server(0x53525652) } Sender;
 785:         //
 786:         //   struct {
 787:         //     opaque md5_hash[16];
 788:         //     opaque sha_hash[20];
 789:         //   } Finished;
 790:         //
 791:         //   md5_hash       MD5(master_secret + pad2 +
 792:         //                      MD5(handshake_messages + Sender +
 793:         //                          master_secret + pad1));
 794:         //   sha_hash        SHA(master_secret + pad2 +
 795:         //                       SHA(handshake_messages + Sender +
 796:         //                           master_secret + pad1));
 797:         //
 798: 
 799:         finishedBuffer = ByteBuffer.allocate(36);
 800: 
 801:         md5.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
 802:         md5.update(session.privateData.masterSecret);
 803:         md5.update(PAD1);
 804: 
 805:         byte[] tmp = md5.digest();
 806:         md5.reset();
 807:         md5.update(session.privateData.masterSecret);
 808:         md5.update(PAD2);
 809:         md5.update(tmp);
 810:         finishedBuffer.put(md5.digest());
 811: 
 812:         sha.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
 813:         sha.update(session.privateData.masterSecret);
 814:         sha.update(PAD1, 0, 40);
 815: 
 816:         tmp = sha.digest();
 817:         sha.reset();
 818:         sha.update(session.privateData.masterSecret);
 819:         sha.update(PAD2, 0, 40);
 820:         sha.update(tmp);
 821:         finishedBuffer.put(sha.digest()).position(0);
 822:       }
 823:     return finishedBuffer;
 824:   }
 825: 
 826:   protected void initDiffieHellman(DHPrivateKey dhKey, SecureRandom random)
 827:     throws SSLException
 828:   {
 829:     try
 830:       {
 831:         keyAgreement = KeyAgreement.getInstance("DH");
 832:         keyAgreement.init(dhKey, random);
 833:       }
 834:     catch (InvalidKeyException ike)
 835:       {
 836:         throw new SSLException(ike);
 837:       }
 838:     catch (NoSuchAlgorithmException nsae)
 839:       {
 840:         throw new SSLException(nsae);
 841:       }
 842:   }
 843: 
 844:   protected void generateMasterSecret(Random clientRandom,
 845:                                       Random serverRandom,
 846:                                       SessionImpl session)
 847:     throws SSLException
 848:   {
 849:     assert(clientRandom != null);
 850:     assert(serverRandom != null);
 851:     assert(session != null);
 852: 
 853:     if (Debug.DEBUG_KEY_EXCHANGE)
 854:       logger.logv(Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
 855:                   new ByteArray(preMasterSecret));
 856: 
 857:     if (session.version == ProtocolVersion.SSL_3)
 858:       {
 859:         try
 860:           {
 861:             MessageDigest _md5 = MessageDigest.getInstance("MD5");
 862:             MessageDigest _sha = MessageDigest.getInstance("SHA");
 863:             session.privateData.masterSecret = new byte[48];
 864: 
 865:             _sha.update((byte) 'A');
 866:             _sha.update(preMasterSecret);
 867:             _sha.update(clientRandom.buffer());
 868:             _sha.update(serverRandom.buffer());
 869:             _md5.update(preMasterSecret);
 870:             _md5.update(_sha.digest());
 871:             _md5.digest(session.privateData.masterSecret, 0, 16);
 872: 
 873:             _sha.update((byte) 'B');
 874:             _sha.update((byte) 'B');
 875:             _sha.update(preMasterSecret);
 876:             _sha.update(clientRandom.buffer());
 877:             _sha.update(serverRandom.buffer());
 878:             _md5.update(preMasterSecret);
 879:             _md5.update(_sha.digest());
 880:             _md5.digest(session.privateData.masterSecret, 16, 16);
 881: 
 882:             _sha.update((byte) 'C');
 883:             _sha.update((byte) 'C');
 884:             _sha.update((byte) 'C');
 885:             _sha.update(preMasterSecret);
 886:             _sha.update(clientRandom.buffer());
 887:             _sha.update(serverRandom.buffer());
 888:             _md5.update(preMasterSecret);
 889:             _md5.update(_sha.digest());
 890:             _md5.digest(session.privateData.masterSecret, 32, 16);
 891:           }
 892:         catch (DigestException de)
 893:           {
 894:             throw new SSLException(de);
 895:           }
 896:         catch (NoSuchAlgorithmException nsae)
 897:           {
 898:             throw new SSLException(nsae);
 899:           }
 900:       }
 901:     else // TLSv1.0 and later
 902:       {
 903:         byte[] seed = new byte[clientRandom.length()
 904:                                + serverRandom.length()
 905:                                + MASTER_SECRET.length];
 906:         System.arraycopy(MASTER_SECRET, 0, seed, 0, MASTER_SECRET.length);
 907:         clientRandom.buffer().get(seed, MASTER_SECRET.length,
 908:                                   clientRandom.length());
 909:         serverRandom.buffer().get(seed,
 910:                                   MASTER_SECRET.length + clientRandom.length(),
 911:                                   serverRandom.length());
 912:         TLSRandom prf = new TLSRandom();
 913:         HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
 914:         attr.put(TLSRandom.SECRET, preMasterSecret);
 915:         attr.put(TLSRandom.SEED, seed);
 916:         prf.init(attr);
 917: 
 918:         session.privateData.masterSecret = new byte[48];
 919:         prf.nextBytes(session.privateData.masterSecret, 0, 48);
 920:       }
 921: 
 922:     if (Debug.DEBUG_KEY_EXCHANGE)
 923:       logger.log(Component.SSL_KEY_EXCHANGE, "master_secret: {0}",
 924:                  new ByteArray(session.privateData.masterSecret));
 925: 
 926:     // Wipe out the preMasterSecret.
 927:     for (int i = 0; i < preMasterSecret.length; i++)
 928:       preMasterSecret[i] = 0;
 929:   }
 930: 
 931:   protected void setupSecurityParameters(byte[][] keys, boolean isClient,
 932:                                          SSLEngineImpl engine,
 933:                                          CompressionMethod compression)
 934:     throws SSLException
 935:   {
 936:     assert(keys.length == 6);
 937:     assert(engine != null);
 938:     assert(compression != null);
 939: 
 940:     try
 941:       {
 942:         CipherSuite s = engine.session().suite;
 943:         Cipher inCipher = s.cipher();
 944:         Mac inMac = s.mac(engine.session().version);
 945:         Inflater inflater = (compression == CompressionMethod.ZLIB
 946:                              ? new Inflater() : null);
 947:         inCipher.init(Cipher.DECRYPT_MODE,
 948:                       new SecretKeySpec(keys[isClient ? 3 : 2],
 949:                                         s.cipherAlgorithm().toString()),
 950:                       new IvParameterSpec(keys[isClient ? 5 : 4]));
 951:         inMac.init(new SecretKeySpec(keys[isClient ? 1 : 0],
 952:                                      inMac.getAlgorithm()));
 953:         inParams = new InputSecurityParameters(inCipher, inMac,
 954:                                                inflater,
 955:                                                engine.session(), s);
 956: 
 957:         Cipher outCipher = s.cipher();
 958:         Mac outMac = s.mac(engine.session().version);
 959:         Deflater deflater = (compression == CompressionMethod.ZLIB
 960:                              ? new Deflater() : null);
 961:         outCipher.init(Cipher.ENCRYPT_MODE,
 962:                        new SecretKeySpec(keys[isClient ? 2 : 3],
 963:                                          s.cipherAlgorithm().toString()),
 964:                        new IvParameterSpec(keys[isClient ? 4 : 5]));
 965:         outMac.init(new SecretKeySpec(keys[isClient ? 0 : 1],
 966:                                       outMac.getAlgorithm()));
 967:         outParams = new OutputSecurityParameters(outCipher, outMac,
 968:                                                  deflater,
 969:                                                  engine.session(), s);
 970:       }
 971:     catch (InvalidAlgorithmParameterException iape)
 972:       {
 973:         throw new SSLException(iape);
 974:       }
 975:     catch (InvalidKeyException ike)
 976:       {
 977:         throw new SSLException(ike);
 978:       }
 979:     catch (NoSuchAlgorithmException nsae)
 980:       {
 981:         throw new SSLException(nsae);
 982:       }
 983:     catch (NoSuchPaddingException nspe)
 984:       {
 985:         throw new SSLException(nspe);
 986:       }
 987:   }
 988: 
 989:   protected void generatePSKSecret(String identity, byte[] otherkey,
 990:                                    boolean isClient)
 991:     throws SSLException
 992:   {
 993:     SecretKey key = null;
 994:     try
 995:       {
 996:         key = engine.contextImpl.pskManager.getKey(identity);
 997:       }
 998:     catch (KeyManagementException kme)
 999:       {
1000:       }
1001:     if (key != null)
1002:       {
1003:         byte[] keyb = key.getEncoded();
1004:         if (otherkey == null)
1005:           {
1006:             otherkey = new byte[keyb.length];
1007:           }
1008:         preMasterSecret = new byte[otherkey.length + keyb.length + 4];
1009:         preMasterSecret[0] = (byte) (otherkey.length >>> 8);
1010:         preMasterSecret[1] = (byte)  otherkey.length;
1011:         System.arraycopy(otherkey, 0, preMasterSecret, 2, otherkey.length);
1012:         preMasterSecret[otherkey.length + 2]
1013:           = (byte) (keyb.length >>> 8);
1014:         preMasterSecret[otherkey.length + 3]
1015:           = (byte)  keyb.length;
1016:         System.arraycopy(keyb, 0, preMasterSecret,
1017:                          otherkey.length + 4, keyb.length);
1018:       }
1019:     else
1020:       {
1021:         // Generate a random, fake secret.
1022:         preMasterSecret = new byte[8];
1023:         preMasterSecret[1] = 2;
1024:         preMasterSecret[5] = 2;
1025:         preMasterSecret[6] = (byte) engine.session().random().nextInt();
1026:         preMasterSecret[7] = (byte) engine.session().random().nextInt();
1027:       }
1028: 
1029:     if (Debug.DEBUG_KEY_EXCHANGE)
1030:       logger.logv(Component.SSL_KEY_EXCHANGE, "PSK identity {0} key {1}",
1031:                   identity, key);
1032: 
1033:     generateMasterSecret(clientRandom, serverRandom,
1034:                          engine.session());
1035:     byte[][] keys = generateKeys(clientRandom, serverRandom,
1036:                                  engine.session());
1037:     setupSecurityParameters(keys, isClient, engine, compression);
1038:   }
1039: 
1040:   protected class DHPhase extends DelegatedTask
1041:   {
1042:     private final DHPublicKey key;
1043:     private final boolean full;
1044: 
1045:     protected DHPhase(DHPublicKey key)
1046:     {
1047:       this(key, true);
1048:     }
1049: 
1050:     protected DHPhase(DHPublicKey key, boolean full)
1051:     {
1052:       this.key = key;
1053:       this.full = full;
1054:     }
1055: 
1056:     protected void implRun() throws InvalidKeyException, SSLException
1057:     {
1058:       keyAgreement.doPhase(key, true);
1059:       preMasterSecret = keyAgreement.generateSecret();
1060:       if (full)
1061:         {
1062:           generateMasterSecret(clientRandom, serverRandom, engine.session());
1063:           byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
1064:           setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression);
1065:         }
1066:     }
1067:   }
1068: 
1069:   protected class CertVerifier extends DelegatedTask
1070:   {
1071:     private final boolean clientSide;
1072:     private final X509Certificate[] chain;
1073:     private boolean verified;
1074: 
1075:     protected CertVerifier(boolean clientSide, X509Certificate[] chain)
1076:     {
1077:       this.clientSide = clientSide;
1078:       this.chain = chain;
1079:     }
1080: 
1081:     boolean verified()
1082:     {
1083:       return verified;
1084:     }
1085: 
1086:     protected void implRun()
1087:     {
1088:       X509TrustManager tm = engine.contextImpl.trustManager;
1089:       if (clientSide)
1090:         {
1091:           try
1092:             {
1093:               tm.checkServerTrusted(chain, null);
1094:               verified = true;
1095:             }
1096:           catch (CertificateException ce)
1097:             {
1098:               if (Debug.DEBUG)
1099:                 logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce);
1100:               // For client connections, ask the user if the certificate is OK.
1101:               CallbackHandler verify = new DefaultCallbackHandler();
1102:               GetSecurityPropertyAction gspa
1103:                 = new GetSecurityPropertyAction("jessie.certificate.handler");
1104:               String clazz = AccessController.doPrivileged(gspa);
1105:               try
1106:                 {
1107:                   ClassLoader cl =
1108:                     AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>()
1109:                       {
1110:                         public ClassLoader run() throws Exception
1111:                         {
1112:                           return ClassLoader.getSystemClassLoader();
1113:                         }
1114:                       });
1115:                   verify = (CallbackHandler) cl.loadClass(clazz).newInstance();
1116:                 }
1117:               catch (Exception x)
1118:                 {
1119:                   // Ignore.
1120:                   if (Debug.DEBUG)
1121:                     logger.log(Component.SSL_DELEGATED_TASK,
1122:                                "callback handler loading", x);
1123:                 }
1124:               // XXX Internationalize
1125:               CertificateCallback confirm =
1126:                 new CertificateCallback(chain[0],
1127:                 "The server's certificate could not be verified. There is no proof " +
1128:                 "that this server is who it claims to be, or that their certificate " +
1129:                 "is valid. Do you wish to continue connecting? ");
1130: 
1131:               try
1132:                 {
1133:                   verify.handle(new Callback[] { confirm });
1134:                   verified = confirm.getSelectedIndex() == ConfirmationCallback.YES;
1135:                 }
1136:               catch (Exception x)
1137:                 {
1138:                   if (Debug.DEBUG)
1139:                     logger.log(Component.SSL_DELEGATED_TASK,
1140:                                "callback handler exception", x);
1141:                   verified = false;
1142:                 }
1143:             }
1144:         }
1145:       else
1146:         {
1147:           try
1148:             {
1149:               tm.checkClientTrusted(chain, null);
1150:             }
1151:           catch (CertificateException ce)
1152:             {
1153:               verified = false;
1154:             }
1155:         }
1156: 
1157:       if (verified)
1158:         engine.session().setPeerVerified(true);
1159:     }
1160:   }
1161: 
1162:   protected class DHE_PSKGen extends DelegatedTask
1163:   {
1164:     private final DHPublicKey dhKey;
1165:     private final SecretKey psKey;
1166:     private final boolean isClient;
1167: 
1168:     protected DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient)
1169:     {
1170:       this.dhKey = dhKey;
1171:       this.psKey = psKey;
1172:       this.isClient = isClient;
1173:     }
1174: 
1175:     /* (non-Javadoc)
1176:      * @see gnu.javax.net.ssl.provider.DelegatedTask#implRun()
1177:      */
1178:     @Override protected void implRun() throws Throwable
1179:     {
1180:       keyAgreement.doPhase(dhKey, true);
1181:       byte[] dhSecret = keyAgreement.generateSecret();
1182:       byte[] psSecret = null;
1183:       if (psKey != null)
1184:         psSecret = psKey.getEncoded();
1185:       else
1186:         {
1187:           psSecret = new byte[8];
1188:           engine.session().random().nextBytes(psSecret);
1189:         }
1190: 
1191:       preMasterSecret = new byte[dhSecret.length + psSecret.length + 4];
1192:       preMasterSecret[0] = (byte) (dhSecret.length >>> 8);
1193:       preMasterSecret[1] = (byte)  dhSecret.length;
1194:       System.arraycopy(dhSecret, 0, preMasterSecret, 2, dhSecret.length);
1195:       preMasterSecret[dhSecret.length + 2] = (byte) (psSecret.length >>> 8);
1196:       preMasterSecret[dhSecret.length + 3] = (byte)  psSecret.length;
1197:       System.arraycopy(psSecret, 0, preMasterSecret, dhSecret.length + 4,
1198:                        psSecret.length);
1199: 
1200:       generateMasterSecret(clientRandom, serverRandom, engine.session());
1201:       byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
1202:       setupSecurityParameters(keys, isClient, engine, compression);
1203:     }
1204:   }
1205: }