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