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/] [ClientHandshake.java] - Blame information for rev 769

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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