2
Copyright (C) 2003, 2006 Free Software Foundation, Inc.
4
This file is a part of GNU Classpath.
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.
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.
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
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
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. */
39
package gnu.javax.crypto.sasl.srp;
41
import gnu.java.security.Registry;
42
import gnu.java.security.util.PRNG;
43
import gnu.java.security.util.Util;
45
import gnu.javax.crypto.assembly.Direction;
46
import gnu.javax.crypto.cipher.CipherFactory;
47
import gnu.javax.crypto.cipher.IBlockCipher;
48
import gnu.javax.crypto.key.IKeyAgreementParty;
49
import gnu.javax.crypto.key.KeyAgreementFactory;
50
import gnu.javax.crypto.key.KeyAgreementException;
51
import gnu.javax.crypto.key.OutgoingMessage;
52
import gnu.javax.crypto.key.IncomingMessage;
53
import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
54
import gnu.javax.crypto.sasl.IllegalMechanismStateException;
55
import gnu.javax.crypto.sasl.InputBuffer;
56
import gnu.javax.crypto.sasl.IntegrityException;
57
import gnu.javax.crypto.sasl.OutputBuffer;
58
import gnu.javax.crypto.sasl.ServerMechanism;
60
import java.io.IOException;
61
import java.io.PrintWriter;
62
import java.io.ByteArrayOutputStream;
63
import java.io.UnsupportedEncodingException;
64
import java.math.BigInteger;
65
import java.util.Arrays;
66
import java.util.HashMap;
67
import java.util.StringTokenizer;
69
import javax.security.sasl.AuthenticationException;
70
import javax.security.sasl.SaslException;
71
import javax.security.sasl.SaslServer;
74
* <p>The SASL-SRP server-side mechanism.</p>
76
public class SRPServer extends ServerMechanism implements SaslServer
79
// Debugging methods and variables
80
// -------------------------------------------------------------------------
82
private static final String NAME = "SRPServer";
84
// private static final String ERROR = "ERROR";
85
private static final String WARN = " WARN";
87
private static final String INFO = " INFO";
89
private static final String TRACE = "DEBUG";
91
private static final boolean DEBUG = true;
93
private static final int debuglevel = 3;
95
private static final PrintWriter err = new PrintWriter(System.out, true);
97
private static void debug(final String level, final Object obj)
99
err.println("[" + level + "] " + NAME + ": " + String.valueOf(obj));
102
// Constants and variables
103
// -------------------------------------------------------------------------
105
private String U = null; // client's username
107
private BigInteger N, g, A, B;
109
private byte[] s; // salt
111
private byte[] cIV, sIV; // client+server IVs, when confidentiality is on
113
private byte[] cn, sn; // client's and server's nonce
115
private SRP srp; // SRP algorithm instance used by this server
117
private byte[] sid; // session ID when re-used
119
private int ttl = 360; // session time-to-live in seconds
121
private byte[] cCB; // peer's channel binding'
123
private String mandatory; // List of available options
125
private String L = null;
129
private String chosenIntegrityAlgorithm;
131
private String chosenConfidentialityAlgorithm;
133
private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT;
135
private byte[] K; // shared session key
137
private boolean replayDetection = true; // whether Replay Detection is on
139
private int inCounter = 0; // messages sequence numbers
141
private int outCounter = 0;
143
private IALG inMac, outMac; // if !null, use for integrity
145
private CALG inCipher, outCipher; // if !null, use for confidentiality
147
private IKeyAgreementParty serverHandler = KeyAgreementFactory.getPartyBInstance(Registry.SRP_SASL_KA);
149
/** Our default source of randomness. */
150
private PRNG prng = null;
153
// -------------------------------------------------------------------------
157
super(Registry.SASL_SRP_MECHANISM);
161
// -------------------------------------------------------------------------
164
// -------------------------------------------------------------------------
166
// abstract methods implementation -----------------------------------------
168
protected void initMechanism() throws SaslException
171
// we must have a means to map a given username to a preferred
172
// SRP hash algorithm; otherwise we end up using _always_ SHA.
173
// for the time being get it from the mechanism properties map
174
// and apply it for all users.
175
final String mda = (String) properties.get(SRPRegistry.SRP_HASH);
176
srp = SRP.instance(mda == null ? SRPRegistry.SRP_DEFAULT_DIGEST_NAME : mda);
179
protected void resetMechanism() throws SaslException
184
inMac = outMac = null;
185
inCipher = outCipher = null;
190
// javax.security.sasl.SaslServer interface implementation -----------------
192
public byte[] evaluateResponse(final byte[] response) throws SaslException
197
if (response == null)
202
return sendProtocolElements(response);
207
return sendEvidence(response);
211
throw new IllegalMechanismStateException("evaluateResponse()");
215
protected byte[] engineUnwrap(final byte[] incoming, final int offset,
216
final int len) throws SaslException
218
// if (DEBUG && debuglevel > 8) debug(TRACE, "==> engineUnwrap()");
220
// if (inMac == null && inCipher == null) {
221
// throw new IllegalStateException("connection is not protected");
224
// if (DEBUG && debuglevel > 6) debug(TRACE, "Incoming buffer (before security): "+Util.dumpString(incoming, offset, len));
226
// byte[] data = null;
228
// InputBuffer frameIn = InputBuffer.getInstance(incoming, offset, len);
229
// data = frameIn.getEOS();
230
// if (inMac != null) {
231
// byte[] received_mac = frameIn.getOS();
232
// if (DEBUG && debuglevel > 6) debug(TRACE, "Got C (received MAC): "+Util.dumpString(received_mac));
233
// inMac.update(data);
234
// if (replayDetection) {
236
// if (DEBUG && debuglevel > 6) debug(TRACE, "inCounter="+String.valueOf(inCounter));
237
// inMac.update(new byte[] {
238
// (byte)(inCounter >>> 24),
239
// (byte)(inCounter >>> 16),
240
// (byte)(inCounter >>> 8),
241
// (byte) inCounter });
243
// final byte[] computed_mac = inMac.doFinal();
244
// if (DEBUG && debuglevel > 6) debug(TRACE, "Computed MAC: "+Util.dumpString(computed_mac));
245
// if (!Arrays.equals(received_mac, computed_mac))
246
// throw new IntegrityException("engineUnwrap()");
248
// if (inCipher != null) {
249
// data = inCipher.doFinal(data);
251
// } catch (IOException x) {
252
// if (x instanceof SaslException) {
253
// throw (SaslException) x;
255
// throw new SaslException("engineUnwrap()", x);
258
// if (DEBUG && debuglevel > 6) debug(TRACE, "Incoming buffer (after security): "+Util.dumpString(data));
259
// if (DEBUG && debuglevel > 8) debug(TRACE, "<== engineUnwrap()");
262
if (DEBUG && debuglevel > 8)
263
debug(TRACE, "==> engineUnwrap()");
265
if (inMac == null && inCipher == null)
267
throw new IllegalStateException("connection is not protected");
270
if (DEBUG && debuglevel > 6)
271
debug(TRACE, "Incoming buffer (before security): "
272
+ Util.dumpString(incoming, offset, len));
274
// at this point one, or both, of confidentiality and integrity protection
275
// services are active.
281
{ // integrity bytes are at the end of the stream
282
final int macBytesCount = inMac.length();
283
final int payloadLength = len - macBytesCount;
284
final byte[] received_mac = new byte[macBytesCount];
285
System.arraycopy(incoming, offset + payloadLength, received_mac, 0,
287
if (DEBUG && debuglevel > 6)
288
debug(TRACE, "Got C (received MAC): "
289
+ Util.dumpString(received_mac));
290
inMac.update(incoming, offset, payloadLength);
294
if (DEBUG && debuglevel > 6)
295
debug(TRACE, "inCounter=" + String.valueOf(inCounter));
296
inMac.update(new byte[] { (byte) (inCounter >>> 24),
297
(byte) (inCounter >>> 16),
298
(byte) (inCounter >>> 8),
302
final byte[] computed_mac = inMac.doFinal();
303
if (DEBUG && debuglevel > 6)
304
debug(TRACE, "Computed MAC: " + Util.dumpString(computed_mac));
305
if (!Arrays.equals(received_mac, computed_mac))
307
throw new IntegrityException("engineUnwrap()");
310
// deal with the payload, which can be either plain or encrypted
311
if (inCipher != null)
313
result = inCipher.doFinal(incoming, offset, payloadLength);
317
result = new byte[payloadLength];
318
System.arraycopy(incoming, offset, result, 0, result.length);
322
{ // no integrity protection; just confidentiality
323
// if (inCipher != null) {
324
result = inCipher.doFinal(incoming, offset, len);
326
// result = new byte[len];
327
// System.arraycopy(incoming, offset, result, 0, len);
331
catch (IOException x)
333
if (x instanceof SaslException)
335
throw (SaslException) x;
337
throw new SaslException("engineUnwrap()", x);
339
if (DEBUG && debuglevel > 6)
340
debug(TRACE, "Incoming buffer (after security): "
341
+ Util.dumpString(result));
342
if (DEBUG && debuglevel > 8)
343
debug(TRACE, "<== engineUnwrap()");
347
protected byte[] engineWrap(final byte[] outgoing, final int offset,
348
final int len) throws SaslException
350
// if (DEBUG && debuglevel > 8) debug(TRACE, "==> engineWrap()");
352
// if (outMac == null && outCipher == null) {
353
// throw new IllegalStateException("connection is not protected");
356
// byte[] data = new byte[len];
357
// System.arraycopy(outgoing, offset, data, 0, len);
359
// if (DEBUG && debuglevel > 6) debug(TRACE, "Outgoing buffer (before security) (hex): "+Util.dumpString(data));
360
// if (DEBUG && debuglevel > 6) debug(TRACE, "Outgoing buffer (before security) (str): \""+new String(data)+"\"");
362
// final byte[] result;
364
// OutputBuffer frameOut = new OutputBuffer();
365
// // Process the data
366
// if (outCipher != null) {
367
// data = outCipher.doFinal(data);
368
// if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding c (encrypted plaintext): "+Util.dumpString(data));
370
// if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding p (plaintext): "+Util.dumpString(data));
372
// frameOut.setEOS(data);
373
// if (outMac != null) {
374
// outMac.update(data);
375
// if (replayDetection) {
377
// if (DEBUG && debuglevel > 6) debug(TRACE, "outCounter="+String.valueOf(outCounter));
378
// outMac.update(new byte[] {
379
// (byte)(outCounter >>> 24),
380
// (byte)(outCounter >>> 16),
381
// (byte)(outCounter >>> 8),
382
// (byte) outCounter});
384
// byte[] C = outMac.doFinal();
385
// frameOut.setOS(C);
386
// if (DEBUG && debuglevel > 6) debug(TRACE, "Encoding C (integrity checksum): "+Util.dumpString(C));
388
// result = frameOut.wrap();
390
// } catch (IOException x) {
391
// if (x instanceof SaslException) {
392
// throw (SaslException) x;
394
// throw new SaslException("engineWrap()", x);
397
// if (DEBUG && debuglevel > 8) debug(TRACE, "<== engineWrap()");
400
if (DEBUG && debuglevel > 8)
401
debug(TRACE, "==> engineWrap()");
403
if (outMac == null && outCipher == null)
405
throw new IllegalStateException("connection is not protected");
408
if (DEBUG && debuglevel > 6)
409
debug(TRACE, "Outgoing buffer (before security) (hex): "
410
+ Util.dumpString(outgoing, offset, len));
411
if (DEBUG && debuglevel > 6)
412
debug(TRACE, "Outgoing buffer (before security) (str): \""
413
+ new String(outgoing, offset, len) + "\"");
415
// at this point one, or both, of confidentiality and integrity protection
416
// services are active.
421
final ByteArrayOutputStream out = new ByteArrayOutputStream();
422
if (outCipher != null)
424
result = outCipher.doFinal(outgoing, offset, len);
425
if (DEBUG && debuglevel > 6)
426
debug(TRACE, "Encoding c (encrypted plaintext): "
427
+ Util.dumpString(result));
433
outMac.update(result);
437
if (DEBUG && debuglevel > 6)
438
debug(TRACE, "outCounter=" + String.valueOf(outCounter));
439
outMac.update(new byte[] { (byte) (outCounter >>> 24),
440
(byte) (outCounter >>> 16),
441
(byte) (outCounter >>> 8),
442
(byte) outCounter });
444
final byte[] C = outMac.doFinal();
446
if (DEBUG && debuglevel > 6)
447
debug(TRACE, "Encoding C (integrity checksum): "
448
+ Util.dumpString(C));
449
} // else ciphertext only; do nothing
452
{ // no confidentiality; just integrity [+ replay detection]
453
if (DEBUG && debuglevel > 6)
454
debug(TRACE, "Encoding p (plaintext): "
455
+ Util.dumpString(outgoing, offset, len));
457
out.write(outgoing, offset, len);
459
// if (outMac != null) {
460
outMac.update(outgoing, offset, len);
464
if (DEBUG && debuglevel > 6)
465
debug(TRACE, "outCounter=" + String.valueOf(outCounter));
466
outMac.update(new byte[] { (byte) (outCounter >>> 24),
467
(byte) (outCounter >>> 16),
468
(byte) (outCounter >>> 8),
469
(byte) outCounter });
471
final byte[] C = outMac.doFinal();
473
if (DEBUG && debuglevel > 6)
474
debug(TRACE, "Encoding C (integrity checksum): "
475
+ Util.dumpString(C));
476
// } // else plaintext only; do nothing
479
result = out.toByteArray();
482
catch (IOException x)
484
if (x instanceof SaslException)
486
throw (SaslException) x;
488
throw new SaslException("engineWrap()", x);
491
if (DEBUG && debuglevel > 8)
492
debug(TRACE, "<== engineWrap()");
496
protected String getNegotiatedQOP()
500
if (inCipher != null)
502
return Registry.QOP_AUTH_CONF;
506
return Registry.QOP_AUTH_INT;
509
return Registry.QOP_AUTH;
512
protected String getNegotiatedStrength()
516
if (inCipher != null)
518
return Registry.STRENGTH_HIGH;
522
return Registry.STRENGTH_MEDIUM;
525
return Registry.STRENGTH_LOW;
528
protected String getNegotiatedRawSendSize()
530
return String.valueOf(rawSendSize);
533
protected String getReuse()
535
return Registry.REUSE_TRUE;
538
// other methods -----------------------------------------------------------
540
private byte[] sendProtocolElements(final byte[] input) throws SaslException
542
if (DEBUG && debuglevel > 8)
543
debug(TRACE, "==> sendProtocolElements()");
544
if (DEBUG && debuglevel > 6)
545
debug(TRACE, "C: " + Util.dumpString(input));
547
// Client send U, I, sid, cn
548
final InputBuffer frameIn = new InputBuffer(input);
551
U = frameIn.getText(); // Extract username
552
if (DEBUG && debuglevel > 6)
553
debug(TRACE, "Got U (username): \"" + U + "\"");
554
authorizationID = frameIn.getText(); // Extract authorisation ID
555
if (DEBUG && debuglevel > 6)
556
debug(TRACE, "Got I (userid): \"" + authorizationID + "\"");
557
sid = frameIn.getEOS();
558
if (DEBUG && debuglevel > 6)
559
debug(TRACE, "Got sid (session ID): " + new String(sid));
560
cn = frameIn.getOS();
561
if (DEBUG && debuglevel > 6)
562
debug(TRACE, "Got cn (client nonce): " + Util.dumpString(cn));
563
cCB = frameIn.getEOS();
564
if (DEBUG && debuglevel > 6)
565
debug(TRACE, "Got cCB (client channel binding): "
566
+ Util.dumpString(cCB));
568
catch (IOException x)
570
if (x instanceof SaslException)
572
throw (SaslException) x;
574
throw new AuthenticationException("sendProtocolElements()", x);
578
if (ServerStore.instance().isAlive(sid))
580
final SecurityContext ctx = ServerStore.instance().restoreSession(sid);
581
srp = SRP.instance(ctx.getMdName());
583
cIV = ctx.getClientIV();
584
sIV = ctx.getServerIV();
585
replayDetection = ctx.hasReplayDetection();
586
inCounter = ctx.getInCounter();
587
outCounter = ctx.getOutCounter();
588
inMac = ctx.getInMac();
589
outMac = ctx.getOutMac();
590
inCipher = ctx.getInCipher();
591
outCipher = ctx.getOutCipher();
593
if (sn == null || sn.length != 16)
597
getDefaultPRNG().nextBytes(sn);
599
setupSecurityServices(false);
601
final OutputBuffer frameOut = new OutputBuffer();
604
frameOut.setScalar(1, 0xFF);
606
frameOut.setEOS(channelBinding);
608
catch (IOException x)
610
if (x instanceof SaslException)
612
throw (SaslException) x;
614
throw new AuthenticationException("sendProtocolElements()", x);
616
final byte[] result = frameOut.encode();
617
if (DEBUG && debuglevel > 8)
618
debug(TRACE, "<== sendProtocolElements()");
619
if (DEBUG && debuglevel > 2)
620
debug(INFO, "Old session...");
621
if (DEBUG && debuglevel > 2)
622
debug(INFO, "S: " + Util.dumpString(result));
623
if (DEBUG && debuglevel > 2)
624
debug(INFO, " sn = " + Util.dumpString(sn));
625
if (DEBUG && debuglevel > 2)
626
debug(INFO, " sCB = " + Util.dumpString(channelBinding));
631
authenticator.activate(properties);
633
// -------------------------------------------------------------------
634
final HashMap mapB = new HashMap();
635
// mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.newDigest());
636
mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm());
637
mapB.put(SRP6KeyAgreement.HOST_PASSWORD_DB, authenticator);
641
serverHandler.init(mapB);
642
OutgoingMessage out = new OutgoingMessage();
644
IncomingMessage in = new IncomingMessage(out.toByteArray());
645
out = serverHandler.processMessage(in);
647
in = new IncomingMessage(out.toByteArray());
650
s = in.readMPI().toByteArray();
653
catch (KeyAgreementException x)
655
throw new SaslException("sendProtocolElements()", x);
657
// -------------------------------------------------------------------
659
if (DEBUG && debuglevel > 6)
660
debug(TRACE, "Encoding N (modulus): " + Util.dump(N));
661
if (DEBUG && debuglevel > 6)
662
debug(TRACE, "Encoding g (generator): " + Util.dump(g));
663
if (DEBUG && debuglevel > 6)
664
debug(TRACE, "Encoding s (client's salt): " + Util.dumpString(s));
665
if (DEBUG && debuglevel > 6)
666
debug(TRACE, "Encoding B (server ephemeral public key): "
669
// The server creates an options list (L), which consists of a
670
// comma-separated list of option strings that specify the security
671
// service options the server supports.
673
if (DEBUG && debuglevel > 6)
674
debug(TRACE, "Encoding L (available options): \"" + L + "\"");
675
if (DEBUG && debuglevel > 6)
676
debug(TRACE, "Encoding sIV (server IV): " + Util.dumpString(sIV));
678
final OutputBuffer frameOut = new OutputBuffer();
681
frameOut.setScalar(1, 0x00);
688
catch (IOException x)
690
if (x instanceof SaslException)
692
throw (SaslException) x;
694
throw new AuthenticationException("sendProtocolElements()", x);
696
final byte[] result = frameOut.encode();
697
if (DEBUG && debuglevel > 8)
698
debug(TRACE, "<== sendProtocolElements()");
699
if (DEBUG && debuglevel > 2)
700
debug(INFO, "New session...");
701
if (DEBUG && debuglevel > 2)
702
debug(INFO, "S: " + Util.dumpString(result));
703
if (DEBUG && debuglevel > 2)
704
debug(INFO, " N = 0x" + N.toString(16));
705
if (DEBUG && debuglevel > 2)
706
debug(INFO, " g = 0x" + g.toString(16));
707
if (DEBUG && debuglevel > 2)
708
debug(INFO, " s = " + Util.dumpString(s));
709
if (DEBUG && debuglevel > 2)
710
debug(INFO, " B = 0x" + B.toString(16));
711
if (DEBUG && debuglevel > 2)
712
debug(INFO, " L = " + L);
717
private byte[] sendEvidence(final byte[] input) throws SaslException
719
if (DEBUG && debuglevel > 8)
720
debug(TRACE, "==> sendEvidence()");
721
if (DEBUG && debuglevel > 6)
722
debug(TRACE, "C: " + Util.dumpString(input));
724
// Client send A, M1, o, cIV
725
final InputBuffer frameIn = new InputBuffer(input);
729
A = frameIn.getMPI(); // Extract client's ephemeral public key
730
if (DEBUG && debuglevel > 6)
731
debug(TRACE, "Got A (client ephemeral public key): " + Util.dump(A));
732
M1 = frameIn.getOS(); // Extract evidence
733
if (DEBUG && debuglevel > 6)
734
debug(TRACE, "Got M1 (client evidence): " + Util.dumpString(M1));
735
o = frameIn.getText(); // Extract client's options list
736
if (DEBUG && debuglevel > 6)
737
debug(TRACE, "Got o (client chosen options): \"" + o + "\"");
738
cIV = frameIn.getOS(); // Extract client's IV
739
if (DEBUG && debuglevel > 6)
740
debug(TRACE, "Got cIV (client IV): " + Util.dumpString(cIV));
742
catch (IOException x)
744
if (x instanceof SaslException)
746
throw (SaslException) x;
748
throw new AuthenticationException("sendEvidence()", x);
751
// Parse client's options and set security layer variables
754
// ----------------------------------------------------------------------
757
final OutgoingMessage out = new OutgoingMessage();
759
final IncomingMessage in = new IncomingMessage(out.toByteArray());
760
serverHandler.processMessage(in);
761
K = serverHandler.getSharedSecret();
763
catch (KeyAgreementException x)
765
throw new SaslException("sendEvidence()", x);
767
// ----------------------------------------------------------------------
769
if (DEBUG && debuglevel > 6)
770
debug(TRACE, "K: " + Util.dumpString(K));
772
final byte[] expected;
775
expected = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn,
778
catch (UnsupportedEncodingException x)
780
throw new AuthenticationException("sendEvidence()", x);
783
// Verify client evidence
784
if (!Arrays.equals(M1, expected))
786
throw new AuthenticationException("M1 mismatch");
789
setupSecurityServices(true);
794
M2 = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, cIV,
795
sIV, channelBinding);
797
catch (UnsupportedEncodingException x)
799
throw new AuthenticationException("sendEvidence()", x);
802
final OutputBuffer frameOut = new OutputBuffer();
807
frameOut.setEOS(sid);
808
frameOut.setScalar(4, ttl);
809
frameOut.setEOS(channelBinding);
811
catch (IOException x)
813
if (x instanceof SaslException)
815
throw (SaslException) x;
817
throw new AuthenticationException("sendEvidence()", x);
819
final byte[] result = frameOut.encode();
820
if (DEBUG && debuglevel > 2)
821
debug(INFO, "S: " + Util.dumpString(result));
822
if (DEBUG && debuglevel > 2)
823
debug(INFO, " M2 = " + Util.dumpString(M2));
824
if (DEBUG && debuglevel > 2)
825
debug(INFO, " sIV = " + Util.dumpString(sIV));
826
if (DEBUG && debuglevel > 2)
827
debug(INFO, " sid = " + new String(sid));
828
if (DEBUG && debuglevel > 2)
829
debug(INFO, " ttl = " + ttl);
830
if (DEBUG && debuglevel > 2)
831
debug(INFO, " sCB = " + Util.dumpString(channelBinding));
833
if (DEBUG && debuglevel > 8)
834
debug(TRACE, "<== sendEvidence()");
838
private String createL()
840
if (DEBUG && debuglevel > 8)
841
debug(TRACE, "==> createL()");
843
String s = (String) properties.get(SRPRegistry.SRP_MANDATORY);
846
s = SRPRegistry.DEFAULT_MANDATORY;
848
if (!SRPRegistry.MANDATORY_NONE.equals(s)
849
&& !SRPRegistry.OPTION_REPLAY_DETECTION.equals(s)
850
&& !SRPRegistry.OPTION_INTEGRITY.equals(s)
851
&& !SRPRegistry.OPTION_CONFIDENTIALITY.equals(s))
853
if (DEBUG && debuglevel > 4)
854
debug(WARN, "Unrecognised mandatory option (" + s
855
+ "). Using default...");
856
s = SRPRegistry.DEFAULT_MANDATORY;
861
s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY);
862
final boolean confidentiality = (s == null ? SRPRegistry.DEFAULT_CONFIDENTIALITY
863
: Boolean.valueOf(s).booleanValue());
865
s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION);
866
boolean integrity = (s == null ? SRPRegistry.DEFAULT_INTEGRITY
867
: Boolean.valueOf(s).booleanValue());
869
s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION);
870
final boolean replayDetection = (s == null ? SRPRegistry.DEFAULT_REPLAY_DETECTION
871
: Boolean.valueOf(s).booleanValue());
873
final StringBuffer sb = new StringBuffer();
874
sb.append(SRPRegistry.OPTION_SRP_DIGEST).append("=").append(
875
srp.getAlgorithm()).append(
878
if (!SRPRegistry.MANDATORY_NONE.equals(mandatory))
880
sb.append(SRPRegistry.OPTION_MANDATORY).append("=").append(mandatory).append(
885
sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(",");
886
// if replay detection is on then force integrity protection
893
for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
895
sb.append(SRPRegistry.OPTION_INTEGRITY).append("=").append(
896
SRPRegistry.INTEGRITY_ALGORITHMS[i]).append(
904
for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
906
cipher = CipherFactory.getInstance(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]);
909
sb.append(SRPRegistry.OPTION_CONFIDENTIALITY).append("=").append(
910
SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]).append(
916
final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE).append(
918
Registry.SASL_BUFFER_MAX_LIMIT).toString();
919
if (DEBUG && debuglevel > 8)
920
debug(TRACE, "<== createL()");
924
// Parse client's options and set security layer variables
925
private void parseO(final String o) throws AuthenticationException
927
this.replayDetection = false;
928
boolean integrity = false;
929
boolean confidentiality = false;
933
final StringTokenizer st = new StringTokenizer(o.toLowerCase(), ",");
934
while (st.hasMoreTokens())
936
option = st.nextToken();
937
if (DEBUG && debuglevel > 6)
938
debug(TRACE, "option: <" + option + ">");
939
if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
941
replayDetection = true;
943
else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "="))
947
throw new AuthenticationException(
948
"Only one integrity algorithm may be chosen");
952
option = option.substring(option.indexOf('=') + 1);
953
if (DEBUG && debuglevel > 6)
954
debug(TRACE, "algorithm: <" + option + ">");
955
for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
957
if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option))
959
chosenIntegrityAlgorithm = option;
966
throw new AuthenticationException(
967
"Unknown integrity algorithm: "
972
else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "="))
976
throw new AuthenticationException(
977
"Only one confidentiality algorithm may be chosen");
981
option = option.substring(option.indexOf('=') + 1);
982
if (DEBUG && debuglevel > 6)
983
debug(TRACE, "algorithm: <" + option + ">");
984
for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
986
if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option))
988
chosenConfidentialityAlgorithm = option;
989
confidentiality = true;
993
if (!confidentiality)
995
throw new AuthenticationException(
996
"Unknown confidentiality algorithm: "
1001
else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "="))
1003
final String maxBufferSize = option.substring(option.indexOf('=') + 1);
1006
rawSendSize = Integer.parseInt(maxBufferSize);
1007
if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT
1009
throw new AuthenticationException(
1010
"Illegal value for 'maxbuffersize' option");
1012
catch (NumberFormatException x)
1014
throw new AuthenticationException(
1015
SRPRegistry.OPTION_MAX_BUFFER_SIZE
1017
+ String.valueOf(maxBufferSize),
1023
// check if client did the right thing
1024
if (replayDetection)
1028
throw new AuthenticationException(
1029
"Missing integrity protection algorithm "
1030
+ "but replay detection is chosen");
1033
if (mandatory.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
1035
if (!replayDetection)
1037
throw new AuthenticationException(
1038
"Replay detection is mandatory but was not chosen");
1041
if (mandatory.equals(SRPRegistry.OPTION_INTEGRITY))
1045
throw new AuthenticationException(
1046
"Integrity protection is mandatory but was not chosen");
1049
if (mandatory.equals(SRPRegistry.OPTION_CONFIDENTIALITY))
1051
if (!confidentiality)
1053
throw new AuthenticationException(
1054
"Confidentiality is mandatory but was not chosen");
1059
if (chosenConfidentialityAlgorithm != null)
1061
final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm);
1064
blockSize = cipher.defaultBlockSize();
1067
{ // should not happen
1068
throw new AuthenticationException("Confidentiality algorithm ("
1069
+ chosenConfidentialityAlgorithm
1070
+ ") not available");
1074
sIV = new byte[blockSize];
1076
getDefaultPRNG().nextBytes(sIV);
1079
private void setupSecurityServices(final boolean newSession)
1080
throws SaslException
1082
complete = true; // signal end of authentication phase
1085
outCounter = inCounter = 0;
1086
// instantiate cipher if confidentiality protection filter is active
1087
if (chosenConfidentialityAlgorithm != null)
1089
if (DEBUG && debuglevel > 2)
1090
debug(INFO, "Activating confidentiality protection filter");
1091
inCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
1092
outCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
1094
// instantiate hmacs if integrity protection filter is active
1095
if (chosenIntegrityAlgorithm != null)
1097
if (DEBUG && debuglevel > 2)
1098
debug(INFO, "Activating integrity protection filter");
1099
inMac = IALG.getInstance(chosenIntegrityAlgorithm);
1100
outMac = IALG.getInstance(chosenIntegrityAlgorithm);
1103
// generate a new sid if at least integrity is used
1104
sid = (inMac != null ? ServerStore.getNewSessionID() : new byte[0]);
1107
{ // same session new keys
1108
K = srp.generateKn(K, cn, sn);
1111
final KDF kdf = KDF.getInstance(K);
1113
// initialise in/out ciphers if confidentaility protection is used
1114
if (inCipher != null)
1116
outCipher.init(kdf, sIV, Direction.FORWARD);
1117
inCipher.init(kdf, cIV, Direction.REVERSED);
1119
// initialise in/out macs if integrity protection is used
1126
if (sid != null && sid.length != 0)
1127
{ // update the security context and save in map
1128
if (DEBUG && debuglevel > 2)
1129
debug(INFO, "Updating security context for sid = " + new String(sid));
1130
ServerStore.instance().cacheSession(
1132
new SecurityContext(
1147
private PRNG getDefaultPRNG()
1150
prng = PRNG.getInstance();