OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [javax/] [net/] [ssl/] [provider/] [AbstractHandshake.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.