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