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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [gnu/] [javax/] [crypto/] [sasl/] [srp/] [SRPClient.java] - Blame information for rev 769

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 769 jeremybenn
/* SRPClient.java --
2
   Copyright (C) 2003, 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.crypto.sasl.srp;
40
 
41
import gnu.java.lang.CPStringBuilder;
42
 
43
import gnu.java.security.Configuration;
44
import gnu.java.security.Registry;
45
import gnu.java.security.hash.MD5;
46
import gnu.java.security.util.PRNG;
47
import gnu.java.security.util.Util;
48
import gnu.javax.crypto.assembly.Direction;
49
import gnu.javax.crypto.cipher.CipherFactory;
50
import gnu.javax.crypto.cipher.IBlockCipher;
51
import gnu.javax.crypto.key.IKeyAgreementParty;
52
import gnu.javax.crypto.key.IncomingMessage;
53
import gnu.javax.crypto.key.KeyAgreementException;
54
import gnu.javax.crypto.key.KeyAgreementFactory;
55
import gnu.javax.crypto.key.OutgoingMessage;
56
import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
57
import gnu.javax.crypto.sasl.ClientMechanism;
58
import gnu.javax.crypto.sasl.IllegalMechanismStateException;
59
import gnu.javax.crypto.sasl.InputBuffer;
60
import gnu.javax.crypto.sasl.IntegrityException;
61
import gnu.javax.crypto.sasl.OutputBuffer;
62
import gnu.javax.security.auth.Password;
63
 
64
import java.io.ByteArrayOutputStream;
65
import java.io.IOException;
66
import java.io.UnsupportedEncodingException;
67
import java.math.BigInteger;
68
import java.security.NoSuchAlgorithmException;
69
import java.util.Arrays;
70
import java.util.HashMap;
71
import java.util.StringTokenizer;
72
import java.util.logging.Logger;
73
 
74
import javax.security.auth.DestroyFailedException;
75
import javax.security.auth.callback.Callback;
76
import javax.security.auth.callback.NameCallback;
77
import javax.security.auth.callback.PasswordCallback;
78
import javax.security.auth.callback.UnsupportedCallbackException;
79
import javax.security.sasl.AuthenticationException;
80
import javax.security.sasl.SaslClient;
81
import javax.security.sasl.SaslException;
82
 
83
/**
84
 * The SASL-SRP client-side mechanism.
85
 */
86
public class SRPClient
87
    extends ClientMechanism
88
    implements SaslClient
89
{
90
  private static final Logger log = Logger.getLogger(SRPClient.class.getName());
91
  private String uid; // the unique key for this type of client
92
  private String U; // the authentication identity
93
  BigInteger N, g, A, B;
94
  private Password password; // the authentication credentials
95
  private byte[] s; // the user's salt
96
  private byte[] cIV, sIV; // client+server IVs, when confidentiality is on
97
  private byte[] M1, M2; // client+server evidences
98
  private byte[] cn, sn; // client's and server's nonce
99
  private SRP srp; // SRP algorithm instance used by this client
100
  private byte[] sid; // session ID when re-used
101
  private int ttl; // session time-to-live in seconds
102
  private byte[] sCB; // the peer's channel binding data
103
  private String L; // available options
104
  private String o;
105
  private String chosenIntegrityAlgorithm;
106
  private String chosenConfidentialityAlgorithm;
107
  private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT;
108
  private byte[] K; // shared session key
109
  private boolean replayDetection = true; // whether Replay Detection is on
110
  private int inCounter = 0; // messages sequence numbers
111
  private int outCounter = 0;
112
  private IALG inMac, outMac; // if !null, use for integrity
113
  private CALG inCipher, outCipher; // if !null, use for confidentiality
114
  private IKeyAgreementParty clientHandler =
115
      KeyAgreementFactory.getPartyAInstance(Registry.SRP_SASL_KA);
116
  /** Our default source of randomness. */
117
  private PRNG prng = null;
118
 
119
  public SRPClient()
120
  {
121
    super(Registry.SASL_SRP_MECHANISM);
122
  }
123
 
124
  protected void initMechanism() throws SaslException
125
  {
126
    // we shall keep track of the sid (and the security context of this SRP
127
    // client) based on the initialisation parameters of an SRP session.
128
    // we shall compute a unique key for those parameters and key the sid
129
    // (and the security context) accordingly.
130
    // 1. compute the mapping key. use MD5 (the fastest) for this purpose
131
    final MD5 md = new MD5();
132
    byte[] b;
133
    b = authorizationID.getBytes();
134
    md.update(b, 0, b.length);
135
    b = serverName.getBytes();
136
    md.update(b, 0, b.length);
137
    b = protocol.getBytes();
138
    md.update(b, 0, b.length);
139
    if (channelBinding.length > 0)
140
      md.update(channelBinding, 0, channelBinding.length);
141
 
142
    uid = Util.toBase64(md.digest());
143
    if (ClientStore.instance().isAlive(uid))
144
      {
145
        final SecurityContext ctx = ClientStore.instance().restoreSession(uid);
146
        srp = SRP.instance(ctx.getMdName());
147
        sid = ctx.getSID();
148
        K = ctx.getK();
149
        cIV = ctx.getClientIV();
150
        sIV = ctx.getServerIV();
151
        replayDetection = ctx.hasReplayDetection();
152
        inCounter = ctx.getInCounter();
153
        outCounter = ctx.getOutCounter();
154
        inMac = ctx.getInMac();
155
        outMac = ctx.getOutMac();
156
        inCipher = ctx.getInCipher();
157
        outCipher = ctx.getOutCipher();
158
      }
159
    else
160
      {
161
        sid = new byte[0];
162
        ttl = 0;
163
        K = null;
164
        cIV = null;
165
        sIV = null;
166
        cn = null;
167
        sn = null;
168
      }
169
  }
170
 
171
  protected void resetMechanism() throws SaslException
172
  {
173
    try
174
      {
175
        password.destroy();
176
      }
177
    catch (DestroyFailedException dfe)
178
      {
179
        SaslException se = new SaslException("resetMechanism()");
180
        se.initCause(dfe);
181
        throw se;
182
      }
183
    password = null;
184
    M1 = null;
185
    K = null;
186
    cIV = null;
187
    sIV = null;
188
    inMac = outMac = null;
189
    inCipher = outCipher = null;
190
    sid = null;
191
    ttl = 0;
192
    cn = null;
193
    sn = null;
194
  }
195
 
196
  public boolean hasInitialResponse()
197
  {
198
    return true;
199
  }
200
 
201
  public byte[] evaluateChallenge(final byte[] challenge) throws SaslException
202
  {
203
    switch (state)
204
      {
205
      case 0:
206
        state++;
207
        return sendIdentities();
208
      case 1:
209
        state++;
210
        final byte[] result = sendPublicKey(challenge);
211
        try
212
          {
213
            password.destroy(); //don't need further this session
214
          }
215
        catch (DestroyFailedException x)
216
          {
217
            SaslException se = new SaslException("sendPublicKey()");
218
            se.initCause(se);
219
            throw se;
220
          }
221
        return result;
222
      case 2: // should only occur if session re-use was rejected
223
        if (! complete)
224
          {
225
            state++;
226
            return receiveEvidence(challenge);
227
          }
228
      // else fall through
229
      default:
230
        throw new IllegalMechanismStateException("evaluateChallenge()");
231
      }
232
  }
233
 
234
  protected byte[] engineUnwrap(final byte[] incoming, final int offset,
235
                                final int len) throws SaslException
236
  {
237
    if (Configuration.DEBUG)
238
      log.entering(this.getClass().getName(), "engineUnwrap");
239
    if (inMac == null && inCipher == null)
240
      throw new IllegalStateException("connection is not protected");
241
    // at this point one, or both, of confidentiality and integrity protection
242
    // services are active.
243
    final byte[] result;
244
    try
245
      {
246
        if (inMac != null)
247
          { // integrity bytes are at the end of the stream
248
            final int macBytesCount = inMac.length();
249
            final int payloadLength = len - macBytesCount;
250
            final byte[] received_mac = new byte[macBytesCount];
251
            System.arraycopy(incoming, offset + payloadLength, received_mac, 0,
252
                             macBytesCount);
253
            if (Configuration.DEBUG)
254
              log.fine("Got C (received MAC): " + Util.dumpString(received_mac));
255
            inMac.update(incoming, offset, payloadLength);
256
            if (replayDetection)
257
              {
258
                inCounter++;
259
                if (Configuration.DEBUG)
260
                  log.fine("inCounter=" + inCounter);
261
                inMac.update(new byte[] {
262
                    (byte)(inCounter >>> 24),
263
                    (byte)(inCounter >>> 16),
264
                    (byte)(inCounter >>> 8),
265
                    (byte) inCounter });
266
              }
267
            final byte[] computed_mac = inMac.doFinal();
268
            if (Configuration.DEBUG)
269
              log.fine("Computed MAC: " + Util.dumpString(computed_mac));
270
            if (! Arrays.equals(received_mac, computed_mac))
271
              throw new IntegrityException("engineUnwrap()");
272
            // deal with the payload, which can be either plain or encrypted
273
            if (inCipher != null)
274
              result = inCipher.doFinal(incoming, offset, payloadLength);
275
            else
276
              {
277
                result = new byte[len - macBytesCount];
278
                System.arraycopy(incoming, offset, result, 0, result.length);
279
              }
280
          }
281
        else // no integrity protection; just confidentiality
282
          result = inCipher.doFinal(incoming, offset, len);
283
      }
284
    catch (IOException x)
285
      {
286
        if (x instanceof SaslException)
287
          throw (SaslException) x;
288
        throw new SaslException("engineUnwrap()", x);
289
      }
290
    if (Configuration.DEBUG)
291
      log.exiting(this.getClass().getName(), "engineUnwrap");
292
    return result;
293
  }
294
 
295
  protected byte[] engineWrap(final byte[] outgoing, final int offset,
296
                              final int len) throws SaslException
297
  {
298
    if (Configuration.DEBUG)
299
      log.entering(this.getClass().getName(), "engineWrap");
300
    if (outMac == null && outCipher == null)
301
      throw new IllegalStateException("connection is not protected");
302
    // at this point one, or both, of confidentiality and integrity protection
303
    // services are active.
304
    byte[] result;
305
    try
306
      {
307
        final ByteArrayOutputStream out = new ByteArrayOutputStream();
308
        // Process the data
309
        if (outCipher != null)
310
          {
311
            result = outCipher.doFinal(outgoing, offset, len);
312
            if (Configuration.DEBUG)
313
              log.fine("Encoding c (encrypted plaintext): "
314
                       + Util.dumpString(result));
315
            out.write(result);
316
            if (outMac != null)
317
              {
318
                outMac.update(result);
319
                if (replayDetection)
320
                  {
321
                    outCounter++;
322
                    if (Configuration.DEBUG)
323
                      log.fine("outCounter=" + outCounter);
324
                    outMac.update(new byte[] {
325
                        (byte)(outCounter >>> 24),
326
                        (byte)(outCounter >>> 16),
327
                        (byte)(outCounter >>> 8),
328
                        (byte) outCounter });
329
                  }
330
                final byte[] C = outMac.doFinal();
331
                out.write(C);
332
                if (Configuration.DEBUG)
333
                  log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
334
              }
335
            // else confidentiality only; do nothing
336
          }
337
        else // no confidentiality; just integrity [+ replay detection]
338
          {
339
            if (Configuration.DEBUG)
340
              log.fine("Encoding p (plaintext): "
341
                       + Util.dumpString(outgoing, offset, len));
342
            out.write(outgoing, offset, len);
343
            outMac.update(outgoing, offset, len);
344
            if (replayDetection)
345
              {
346
                outCounter++;
347
                if (Configuration.DEBUG)
348
                  log.fine("outCounter=" + outCounter);
349
                outMac.update(new byte[] {
350
                    (byte)(outCounter >>> 24),
351
                    (byte)(outCounter >>> 16),
352
                    (byte)(outCounter >>> 8),
353
                    (byte) outCounter });
354
              }
355
            final byte[] C = outMac.doFinal();
356
            out.write(C);
357
            if (Configuration.DEBUG)
358
              log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
359
          }
360
        result = out.toByteArray();
361
      }
362
    catch (IOException x)
363
      {
364
        if (x instanceof SaslException)
365
          throw (SaslException) x;
366
        throw new SaslException("engineWrap()", x);
367
      }
368
    if (Configuration.DEBUG)
369
      log.exiting(this.getClass().getName(), "engineWrap");
370
    return result;
371
  }
372
 
373
  protected String getNegotiatedQOP()
374
  {
375
    if (inMac != null)
376
      {
377
        if (inCipher != null)
378
          return Registry.QOP_AUTH_CONF;
379
        return Registry.QOP_AUTH_INT;
380
      }
381
    return Registry.QOP_AUTH;
382
  }
383
 
384
  protected String getNegotiatedStrength()
385
  {
386
    if (inMac != null)
387
      {
388
        if (inCipher != null)
389
          return Registry.STRENGTH_HIGH;
390
        return Registry.STRENGTH_MEDIUM;
391
      }
392
    return Registry.STRENGTH_LOW;
393
  }
394
 
395
  protected String getNegotiatedRawSendSize()
396
  {
397
    return String.valueOf(rawSendSize);
398
  }
399
 
400
  protected String getReuse()
401
  {
402
    return Registry.REUSE_TRUE;
403
  }
404
 
405
  private byte[] sendIdentities() throws SaslException
406
  {
407
    if (Configuration.DEBUG)
408
      log.entering(this.getClass().getName(), "sendIdentities");
409
    // If necessary, prompt the client for the username and password
410
    getUsernameAndPassword();
411
    if (Configuration.DEBUG)
412
      {
413
        log.fine("Password: \"" + new String(password.getPassword()) + "\"");
414
        log.fine("Encoding U (username): \"" + U + "\"");
415
        log.fine("Encoding I (userid): \"" + authorizationID + "\"");
416
      }
417
    // if session re-use generate new 16-byte nonce
418
    if (sid.length != 0)
419
      {
420
        cn = new byte[16];
421
        getDefaultPRNG().nextBytes(cn);
422
      }
423
    else
424
      cn = new byte[0];
425
    final OutputBuffer frameOut = new OutputBuffer();
426
    try
427
      {
428
        frameOut.setText(U);
429
        frameOut.setText(authorizationID);
430
        frameOut.setEOS(sid); // session ID to re-use
431
        frameOut.setOS(cn); // client nonce
432
        frameOut.setEOS(channelBinding);
433
      }
434
    catch (IOException x)
435
      {
436
        if (x instanceof SaslException)
437
          throw (SaslException) x;
438
        throw new AuthenticationException("sendIdentities()", x);
439
      }
440
    final byte[] result = frameOut.encode();
441
    if (Configuration.DEBUG)
442
      {
443
        log.fine("C: " + Util.dumpString(result));
444
        log.fine("  U = " + U);
445
        log.fine("  I = " + authorizationID);
446
        log.fine("sid = " + new String(sid));
447
        log.fine(" cn = " + Util.dumpString(cn));
448
        log.fine("cCB = " + Util.dumpString(channelBinding));
449
        log.exiting(this.getClass().getName(), "sendIdentities");
450
      }
451
    return result;
452
  }
453
 
454
  private byte[] sendPublicKey(final byte[] input) throws SaslException
455
  {
456
    if (Configuration.DEBUG)
457
      {
458
        log.entering(this.getClass().getName(), "sendPublicKey");
459
        log.fine("S: " + Util.dumpString(input));
460
      }
461
    // Server sends [00], N, g, s, B, L
462
    // or [FF], sn, sCB
463
    final InputBuffer frameIn = new InputBuffer(input);
464
    final int ack;
465
    try
466
      {
467
        ack = (int) frameIn.getScalar(1);
468
        if (ack == 0x00) // new session
469
          {
470
            N = frameIn.getMPI();
471
            if (Configuration.DEBUG)
472
              log.fine("Got N (modulus): " + Util.dump(N));
473
            g = frameIn.getMPI();
474
            if (Configuration.DEBUG)
475
              log.fine("Got g (generator): " + Util.dump(g));
476
            s = frameIn.getOS();
477
            if (Configuration.DEBUG)
478
              log.fine("Got s (salt): " + Util.dumpString(s));
479
            B = frameIn.getMPI();
480
            if (Configuration.DEBUG)
481
              log.fine("Got B (server ephermeral public key): " + Util.dump(B));
482
            L = frameIn.getText();
483
            if (Configuration.DEBUG)
484
              log.fine("Got L (available options): \"" + L + "\"");
485
          }
486
        else if (ack == 0xFF) // session re-use
487
          {
488
            sn = frameIn.getOS();
489
            if (Configuration.DEBUG)
490
              log.fine("Got sn (server nonce): " + Util.dumpString(sn));
491
            sCB = frameIn.getEOS();
492
            if (Configuration.DEBUG)
493
              log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB));
494
          }
495
        else // unexpected scalar
496
          throw new SaslException("sendPublicKey(): Invalid scalar (" + ack
497
                                  + ") in server's request");
498
      }
499
    catch (IOException x)
500
      {
501
        if (x instanceof SaslException)
502
          throw (SaslException) x;
503
        throw new SaslException("sendPublicKey()", x);
504
      }
505
    if (ack == 0x00)
506
      { // new session ---------------------------------------
507
        o = createO(L.toLowerCase()); // do this first to initialise the SRP hash
508
        final byte[] pBytes; // use ASCII encoding to inter-operate w/ non-java
509
        pBytes = password.getBytes();
510
        // ----------------------------------------------------------------------
511
        final HashMap mapA = new HashMap();
512
        mapA.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm());
513
        mapA.put(SRP6KeyAgreement.USER_IDENTITY, U);
514
        mapA.put(SRP6KeyAgreement.USER_PASSWORD, pBytes);
515
        try
516
          {
517
            clientHandler.init(mapA);
518
            clientHandler.processMessage(null);
519
          }
520
        catch (KeyAgreementException x)
521
          {
522
            throw new SaslException("sendPublicKey()", x);
523
          }
524
        // -------------------------------------------------------------------
525
        try
526
          {
527
            OutgoingMessage out = new OutgoingMessage();
528
            out.writeMPI(N);
529
            out.writeMPI(g);
530
            out.writeMPI(new BigInteger(1, s));
531
            out.writeMPI(B);
532
            IncomingMessage in = new IncomingMessage(out.toByteArray());
533
            out = clientHandler.processMessage(in);
534
            in = new IncomingMessage(out.toByteArray());
535
            A = in.readMPI();
536
            K = clientHandler.getSharedSecret();
537
          }
538
        catch (KeyAgreementException x)
539
          {
540
            throw new SaslException("sendPublicKey()", x);
541
          }
542
        // -------------------------------------------------------------------
543
        if (Configuration.DEBUG)
544
          {
545
            log.fine("K: " + Util.dumpString(K));
546
            log.fine("Encoding A (client ephemeral public key): " + Util.dump(A));
547
          }
548
        try
549
          {
550
            M1 = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn,
551
                                channelBinding);
552
          }
553
        catch (UnsupportedEncodingException x)
554
          {
555
            throw new AuthenticationException("sendPublicKey()", x);
556
          }
557
        if (Configuration.DEBUG)
558
          {
559
            log.fine("Encoding o (client chosen options): \"" + o + "\"");
560
            log.fine("Encoding cIV (client IV): \"" + Util.dumpString(cIV) + "\"");
561
          }
562
        final OutputBuffer frameOut = new OutputBuffer();
563
        try
564
          {
565
            frameOut.setMPI(A);
566
            frameOut.setOS(M1);
567
            frameOut.setText(o);
568
            frameOut.setOS(cIV);
569
          }
570
        catch (IOException x)
571
          {
572
            if (x instanceof SaslException)
573
              throw (SaslException) x;
574
            throw new AuthenticationException("sendPublicKey()", x);
575
          }
576
        final byte[] result = frameOut.encode();
577
        if (Configuration.DEBUG)
578
          {
579
            log.fine("New session, or session re-use rejected...");
580
            log.fine("C: " + Util.dumpString(result));
581
            log.fine("  A = 0x" + A.toString(16));
582
            log.fine(" M1 = " + Util.dumpString(M1));
583
            log.fine("  o = " + o);
584
            log.fine("cIV = " + Util.dumpString(cIV));
585
            log.exiting(this.getClass().getName(), "sendPublicKey");
586
          }
587
        return result;
588
      }
589
    else // session re-use accepted -------------------------------------------
590
      {
591
        setupSecurityServices(true);
592
        if (Configuration.DEBUG)
593
          {
594
            log.fine("Session re-use accepted...");
595
            log.exiting(this.getClass().getName(), "sendPublicKey");
596
          }
597
        return null;
598
      }
599
  }
600
 
601
  private byte[] receiveEvidence(byte[] input) throws SaslException
602
  {
603
    if (Configuration.DEBUG)
604
      {
605
        log.entering(this.getClass().getName(), "receiveEvidence");
606
        log.fine("S: " + Util.dumpString(input));
607
      }
608
    // Server send M2, sIV, sCB, sid, ttl
609
    final InputBuffer frameIn = new InputBuffer(input);
610
    try
611
      {
612
        M2 = frameIn.getOS();
613
        if (Configuration.DEBUG)
614
          log.fine("Got M2 (server evidence): " + Util.dumpString(M2));
615
        sIV = frameIn.getOS();
616
        if (Configuration.DEBUG)
617
          log.fine("Got sIV (server IV): " + Util.dumpString(sIV));
618
        sid = frameIn.getEOS();
619
        if (Configuration.DEBUG)
620
          log.fine("Got sid (session ID): " + new String(sid));
621
        ttl = (int) frameIn.getScalar(4);
622
        if (Configuration.DEBUG)
623
          log.fine("Got ttl (session time-to-live): " + ttl + "sec.");
624
        sCB = frameIn.getEOS();
625
        if (Configuration.DEBUG)
626
          log.fine("Got sCB (server channel binding): " + Util.dumpString(sCB));
627
      }
628
    catch (IOException x)
629
      {
630
        if (x instanceof SaslException)
631
          throw (SaslException) x;
632
        throw new AuthenticationException("receiveEvidence()", x);
633
      }
634
 
635
    final byte[] expected;
636
    try
637
      {
638
        expected = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl,
639
                                  cIV, sIV, sCB);
640
      }
641
    catch (UnsupportedEncodingException x)
642
      {
643
        throw new AuthenticationException("receiveEvidence()", x);
644
      }
645
    if (Configuration.DEBUG)
646
      log.fine("Expected: " + Util.dumpString(expected));
647
    if (! Arrays.equals(M2, expected))
648
      throw new AuthenticationException("M2 mismatch");
649
    setupSecurityServices(false);
650
    if (Configuration.DEBUG)
651
      log.exiting(this.getClass().getName(), "receiveEvidence");
652
    return null;
653
  }
654
 
655
  private void getUsernameAndPassword() throws AuthenticationException
656
  {
657
    try
658
      {
659
        if ((! properties.containsKey(Registry.SASL_USERNAME))
660
            && (! properties.containsKey(Registry.SASL_PASSWORD)))
661
          {
662
            final NameCallback nameCB;
663
            final String defaultName = System.getProperty("user.name");
664
            if (defaultName == null)
665
              nameCB = new NameCallback("username: ");
666
            else
667
              nameCB = new NameCallback("username: ", defaultName);
668
            final PasswordCallback pwdCB = new PasswordCallback("password: ",
669
                                                                false);
670
            handler.handle(new Callback[] { nameCB, pwdCB });
671
            U = nameCB.getName();
672
            password = new Password(pwdCB.getPassword());
673
          }
674
        else
675
          {
676
            if (properties.containsKey(Registry.SASL_USERNAME))
677
              this.U = (String) properties.get(Registry.SASL_USERNAME);
678
            else
679
              {
680
                final NameCallback nameCB;
681
                final String defaultName = System.getProperty("user.name");
682
                if (defaultName == null)
683
                  nameCB = new NameCallback("username: ");
684
                else
685
                  nameCB = new NameCallback("username: ", defaultName);
686
                this.handler.handle(new Callback[] { nameCB });
687
                this.U = nameCB.getName();
688
              }
689
 
690
            if (properties.containsKey(Registry.SASL_PASSWORD))
691
              {
692
                Object pw = properties.get(Registry.SASL_PASSWORD);
693
                if (pw instanceof char[])
694
                  password = new Password((char[]) pw);
695
                else if (pw instanceof Password)
696
                  password = (Password) pw;
697
                else if (pw instanceof String)
698
                  password = new Password(((String) pw).toCharArray());
699
                else
700
                  throw new IllegalArgumentException(pw.getClass().getName()
701
                                                     + "is not a valid password class");
702
              }
703
            else
704
              {
705
                final PasswordCallback pwdCB = new PasswordCallback("password: ",
706
                                                                    false);
707
                this.handler.handle(new Callback[] { pwdCB });
708
                password = new Password(pwdCB.getPassword());
709
              }
710
          }
711
 
712
        if (U == null)
713
          throw new AuthenticationException("null username supplied");
714
        if (password == null)
715
          throw new AuthenticationException("null password supplied");
716
      }
717
    catch (UnsupportedCallbackException x)
718
      {
719
        throw new AuthenticationException("getUsernameAndPassword()", x);
720
      }
721
    catch (IOException x)
722
      {
723
        throw new AuthenticationException("getUsernameAndPassword()", x);
724
      }
725
  }
726
 
727
  // We go through the list of available services and for each available one
728
  // we decide whether or not we want it enabled, based on properties passed
729
  // to us by the client.
730
  private String createO(final String aol) throws AuthenticationException
731
  {
732
    if (Configuration.DEBUG)
733
      log.entering(this.getClass().getName(), "createO", aol);
734
    boolean replaydetectionAvailable = false;
735
    boolean integrityAvailable = false;
736
    boolean confidentialityAvailable = false;
737
    String option, mandatory = SRPRegistry.DEFAULT_MANDATORY;
738
    int i;
739
 
740
    String mdName = SRPRegistry.SRP_DEFAULT_DIGEST_NAME;
741
    final StringTokenizer st = new StringTokenizer(aol, ",");
742
    while (st.hasMoreTokens())
743
      {
744
        option = st.nextToken();
745
        if (option.startsWith(SRPRegistry.OPTION_SRP_DIGEST + "="))
746
          {
747
            option = option.substring(option.indexOf('=') + 1);
748
            if (Configuration.DEBUG)
749
              log.fine("mda: <" + option + ">");
750
            for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
751
              if (SRPRegistry.SRP_ALGORITHMS[i].equals(option))
752
                {
753
                  mdName = option;
754
                  break;
755
                }
756
          }
757
        else if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
758
          replaydetectionAvailable = true;
759
        else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "="))
760
          {
761
            option = option.substring(option.indexOf('=') + 1);
762
            if (Configuration.DEBUG)
763
              log.fine("ialg: <" + option + ">");
764
            for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
765
              if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option))
766
                {
767
                  chosenIntegrityAlgorithm = option;
768
                  integrityAvailable = true;
769
                  break;
770
                }
771
          }
772
        else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "="))
773
          {
774
            option = option.substring(option.indexOf('=') + 1);
775
            if (Configuration.DEBUG)
776
              log.fine("calg: <" + option + ">");
777
            for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
778
              if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option))
779
                {
780
                  chosenConfidentialityAlgorithm = option;
781
                  confidentialityAvailable = true;
782
                  break;
783
                }
784
          }
785
        else if (option.startsWith(SRPRegistry.OPTION_MANDATORY + "="))
786
          mandatory = option.substring(option.indexOf('=') + 1);
787
        else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "="))
788
          {
789
            final String maxBufferSize = option.substring(option.indexOf('=') + 1);
790
            try
791
              {
792
                rawSendSize = Integer.parseInt(maxBufferSize);
793
                if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT
794
                    || rawSendSize < 1)
795
                  throw new AuthenticationException(
796
                      "Illegal value for 'maxbuffersize' option");
797
              }
798
            catch (NumberFormatException x)
799
              {
800
                throw new AuthenticationException(
801
                    SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x);
802
              }
803
          }
804
      }
805
    String s;
806
    Boolean flag;
807
    s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION);
808
    flag = Boolean.valueOf(s);
809
    replayDetection = replaydetectionAvailable && flag.booleanValue();
810
    s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION);
811
    flag = Boolean.valueOf(s);
812
    boolean integrity = integrityAvailable && flag.booleanValue();
813
    s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY);
814
    flag = Boolean.valueOf(s);
815
    boolean confidentiality = confidentialityAvailable && flag.booleanValue();
816
    // make sure we do the right thing
817
    if (SRPRegistry.OPTION_REPLAY_DETECTION.equals(mandatory))
818
      {
819
        replayDetection = true;
820
        integrity = true;
821
      }
822
    else if (SRPRegistry.OPTION_INTEGRITY.equals(mandatory))
823
      integrity = true;
824
    else if (SRPRegistry.OPTION_CONFIDENTIALITY.equals(mandatory))
825
      confidentiality = true;
826
 
827
    if (replayDetection)
828
      {
829
        if (chosenIntegrityAlgorithm == null)
830
          throw new AuthenticationException(
831
              "Replay detection is required but no integrity protection "
832
              + "algorithm was chosen");
833
      }
834
    if (integrity)
835
      {
836
        if (chosenIntegrityAlgorithm == null)
837
          throw new AuthenticationException(
838
              "Integrity protection is required but no algorithm was chosen");
839
      }
840
    if (confidentiality)
841
      {
842
        if (chosenConfidentialityAlgorithm == null)
843
          throw new AuthenticationException(
844
              "Confidentiality protection is required but no algorithm was chosen");
845
      }
846
    // 1. check if we'll be using confidentiality; if not set IV to 0-byte
847
    if (chosenConfidentialityAlgorithm == null)
848
      cIV = new byte[0];
849
    else
850
      {
851
        // 2. get the block size of the cipher
852
        final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm);
853
        if (cipher == null)
854
          throw new AuthenticationException("createO()",
855
                                            new NoSuchAlgorithmException());
856
        final int blockSize = cipher.defaultBlockSize();
857
        // 3. generate random iv
858
        cIV = new byte[blockSize];
859
        getDefaultPRNG().nextBytes(cIV);
860
      }
861
    srp = SRP.instance(mdName);
862
    // Now create the options list specifying which of the available options
863
    // we have chosen.
864
 
865
    // For now we just select the defaults. Later we need to add support for
866
    // properties (perhaps in a file) where a user can specify the list of
867
    // algorithms they would prefer to use.
868
    final CPStringBuilder sb = new CPStringBuilder();
869
    sb.append(SRPRegistry.OPTION_SRP_DIGEST)
870
      .append("=").append(mdName).append(",");
871
    if (replayDetection)
872
      sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(",");
873
    if (integrity)
874
      sb.append(SRPRegistry.OPTION_INTEGRITY)
875
        .append("=").append(chosenIntegrityAlgorithm).append(",");
876
    if (confidentiality)
877
      sb.append(SRPRegistry.OPTION_CONFIDENTIALITY)
878
        .append("=").append(chosenConfidentialityAlgorithm).append(",");
879
 
880
    final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE)
881
                            .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT)
882
                            .toString();
883
    if (Configuration.DEBUG)
884
      log.exiting(this.getClass().getName(), "createO", result);
885
    return result;
886
  }
887
 
888
  private void setupSecurityServices(final boolean sessionReUse)
889
      throws SaslException
890
  {
891
    complete = true; // signal end of authentication phase
892
    if (! sessionReUse)
893
      {
894
        outCounter = inCounter = 0;
895
        // instantiate cipher if confidentiality protection filter is active
896
        if (chosenConfidentialityAlgorithm != null)
897
          {
898
            if (Configuration.DEBUG)
899
              log.fine("Activating confidentiality protection filter");
900
            inCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
901
            outCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
902
          }
903
        // instantiate hmacs if integrity protection filter is active
904
        if (chosenIntegrityAlgorithm != null)
905
          {
906
            if (Configuration.DEBUG)
907
              log.fine("Activating integrity protection filter");
908
            inMac = IALG.getInstance(chosenIntegrityAlgorithm);
909
            outMac = IALG.getInstance(chosenIntegrityAlgorithm);
910
          }
911
      }
912
    else // same session new Keys
913
      K = srp.generateKn(K, cn, sn);
914
 
915
    final KDF kdf = KDF.getInstance(K);
916
    // initialise in/out ciphers if confidentiality protection is used
917
    if (inCipher != null)
918
      {
919
        inCipher.init(kdf, sIV, Direction.REVERSED);
920
        outCipher.init(kdf, cIV, Direction.FORWARD);
921
      }
922
    // initialise in/out macs if integrity protection is used
923
    if (inMac != null)
924
      {
925
        inMac.init(kdf);
926
        outMac.init(kdf);
927
      }
928
    if (sid != null && sid.length != 0)
929
      { // update the security context and save in map
930
        if (Configuration.DEBUG)
931
          log.fine("Updating security context for UID = " + uid);
932
        ClientStore.instance().cacheSession(uid,
933
                                            ttl,
934
                                            new SecurityContext(srp.getAlgorithm(),
935
                                                                sid,
936
                                                                K,
937
                                                                cIV,
938
                                                                sIV,
939
                                                                replayDetection,
940
                                                                inCounter,
941
                                                                outCounter,
942
                                                                inMac, outMac,
943
                                                                inCipher,
944
                                                                outCipher));
945
      }
946
  }
947
 
948
  private PRNG getDefaultPRNG()
949
  {
950
    if (prng == null)
951
      prng = PRNG.getInstance();
952
    return prng;
953
  }
954
}

powered by: WebSVN 2.1.0

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