1:
37:
38:
39: package ;
40:
41: import ;
42:
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: import ;
62: import ;
63:
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73:
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82:
83:
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;
92: private String U;
93: BigInteger N, g, A, B;
94: private Password password;
95: private byte[] s;
96: private byte[] cIV, sIV;
97: private byte[] M1, M2;
98: private byte[] cn, sn;
99: private SRP srp;
100: private byte[] sid;
101: private int ttl;
102: private byte[] sCB;
103: private String L;
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;
109: private boolean replayDetection = true;
110: private int inCounter = 0;
111: private int outCounter = 0;
112: private IALG inMac, outMac;
113: private CALG inCipher, outCipher;
114: private IKeyAgreementParty clientHandler =
115: KeyAgreementFactory.getPartyAInstance(Registry.SRP_SASL_KA);
116:
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:
127:
128:
129:
130:
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();
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:
223: if (! complete)
224: {
225: state++;
226: return receiveEvidence(challenge);
227: }
228:
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:
242:
243: final byte[] result;
244: try
245: {
246: if (inMac != null)
247: {
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:
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
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:
303:
304: byte[] result;
305: try
306: {
307: final ByteArrayOutputStream out = new ByteArrayOutputStream();
308:
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:
336: }
337: else
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:
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:
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);
431: frameOut.setOS(cn);
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:
462:
463: final InputBuffer frameIn = new InputBuffer(input);
464: final int ack;
465: try
466: {
467: ack = (int) frameIn.getScalar(1);
468: if (ack == 0x00)
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)
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
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: {
507: o = createO(L.toLowerCase());
508: final byte[] pBytes;
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
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:
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:
728:
729:
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:
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:
847: if (chosenConfidentialityAlgorithm == null)
848: cIV = new byte[0];
849: else
850: {
851:
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:
858: cIV = new byte[blockSize];
859: getDefaultPRNG().nextBytes(cIV);
860: }
861: srp = SRP.instance(mdName);
862:
863:
864:
865:
866:
867:
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;
892: if (! sessionReUse)
893: {
894: outCounter = inCounter = 0;
895:
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:
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
913: K = srp.generateKn(K, cn, sn);
914:
915: final KDF kdf = KDF.getInstance(K);
916:
917: if (inCipher != null)
918: {
919: inCipher.init(kdf, sIV, Direction.REVERSED);
920: outCipher.init(kdf, cIV, Direction.FORWARD);
921: }
922:
923: if (inMac != null)
924: {
925: inMac.init(kdf);
926: outMac.init(kdf);
927: }
928: if (sid != null && sid.length != 0)
929: {
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: }