aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.4.3/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.4.3/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java')
-rw-r--r--gcc-4.4.3/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java842
1 files changed, 842 insertions, 0 deletions
diff --git a/gcc-4.4.3/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java b/gcc-4.4.3/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java
new file mode 100644
index 000000000..3f000deef
--- /dev/null
+++ b/gcc-4.4.3/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java
@@ -0,0 +1,842 @@
+/* SRPServer.java --
+ Copyright (C) 2003, 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.crypto.sasl.srp;
+
+import gnu.java.lang.CPStringBuilder;
+
+import gnu.java.security.Configuration;
+import gnu.java.security.Registry;
+import gnu.java.security.util.PRNG;
+import gnu.java.security.util.Util;
+import gnu.javax.crypto.assembly.Direction;
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.key.IKeyAgreementParty;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.KeyAgreementFactory;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
+import gnu.javax.crypto.sasl.IllegalMechanismStateException;
+import gnu.javax.crypto.sasl.InputBuffer;
+import gnu.javax.crypto.sasl.IntegrityException;
+import gnu.javax.crypto.sasl.OutputBuffer;
+import gnu.javax.crypto.sasl.ServerMechanism;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import java.util.logging.Logger;
+
+import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+/**
+ * The SASL-SRP server-side mechanism.
+ */
+public class SRPServer
+ extends ServerMechanism
+ implements SaslServer
+{
+ private static final Logger log = Logger.getLogger(SRPServer.class.getName());
+ private String U = null; // client's username
+ private BigInteger N, g, A, B;
+ private byte[] s; // salt
+ private byte[] cIV, sIV; // client+server IVs, when confidentiality is on
+ private byte[] cn, sn; // client's and server's nonce
+ private SRP srp; // SRP algorithm instance used by this server
+ private byte[] sid; // session ID when re-used
+ private int ttl = 360; // session time-to-live in seconds
+ private byte[] cCB; // peer's channel binding'
+ private String mandatory; // List of available options
+ private String L = null;
+ private String o;
+ private String chosenIntegrityAlgorithm;
+ private String chosenConfidentialityAlgorithm;
+ private int rawSendSize = Registry.SASL_BUFFER_MAX_LIMIT;
+ private byte[] K; // shared session key
+ private boolean replayDetection = true; // whether Replay Detection is on
+ private int inCounter = 0; // messages sequence numbers
+ private int outCounter = 0;
+ private IALG inMac, outMac; // if !null, use for integrity
+ private CALG inCipher, outCipher; // if !null, use for confidentiality
+ private IKeyAgreementParty serverHandler =
+ KeyAgreementFactory.getPartyBInstance(Registry.SRP_SASL_KA);
+ /** Our default source of randomness. */
+ private PRNG prng = null;
+
+ public SRPServer()
+ {
+ super(Registry.SASL_SRP_MECHANISM);
+ }
+
+ protected void initMechanism() throws SaslException
+ {
+ // TODO:
+ // we must have a means to map a given username to a preferred
+ // SRP hash algorithm; otherwise we end up using _always_ SHA.
+ // for the time being get it from the mechanism properties map
+ // and apply it for all users.
+ final String mda = (String) properties.get(SRPRegistry.SRP_HASH);
+ srp = SRP.instance(mda == null ? SRPRegistry.SRP_DEFAULT_DIGEST_NAME : mda);
+ }
+
+ protected void resetMechanism() throws SaslException
+ {
+ s = null;
+ A = B = null;
+ K = null;
+ inMac = outMac = null;
+ inCipher = outCipher = null;
+ sid = null;
+ }
+
+ public byte[] evaluateResponse(final byte[] response) throws SaslException
+ {
+ switch (state)
+ {
+ case 0:
+ if (response == null)
+ return null;
+ state++;
+ return sendProtocolElements(response);
+ case 1:
+ if (! complete)
+ {
+ state++;
+ return sendEvidence(response);
+ }
+ // else fall through
+ default:
+ throw new IllegalMechanismStateException("evaluateResponse()");
+ }
+ }
+
+ protected byte[] engineUnwrap(final byte[] incoming, final int offset,
+ final int len) throws SaslException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "engineUnwrap");
+ if (inMac == null && inCipher == null)
+ throw new IllegalStateException("connection is not protected");
+ if (Configuration.DEBUG)
+ log.fine("Incoming buffer (before security): "
+ + Util.dumpString(incoming, offset, len));
+ // at this point one, or both, of confidentiality and integrity protection
+ // services are active.
+ final byte[] result;
+ try
+ {
+ if (inMac != null)
+ { // integrity bytes are at the end of the stream
+ final int macBytesCount = inMac.length();
+ final int payloadLength = len - macBytesCount;
+ final byte[] received_mac = new byte[macBytesCount];
+ System.arraycopy(incoming, offset + payloadLength, received_mac, 0,
+ macBytesCount);
+ if (Configuration.DEBUG)
+ log.fine("Got C (received MAC): " + Util.dumpString(received_mac));
+ inMac.update(incoming, offset, payloadLength);
+ if (replayDetection)
+ {
+ inCounter++;
+ if (Configuration.DEBUG)
+ log.fine("inCounter=" + String.valueOf(inCounter));
+ inMac.update(new byte[] {
+ (byte)(inCounter >>> 24),
+ (byte)(inCounter >>> 16),
+ (byte)(inCounter >>> 8),
+ (byte) inCounter });
+ }
+ final byte[] computed_mac = inMac.doFinal();
+ if (Configuration.DEBUG)
+ log.fine("Computed MAC: " + Util.dumpString(computed_mac));
+ if (! Arrays.equals(received_mac, computed_mac))
+ throw new IntegrityException("engineUnwrap()");
+ // deal with the payload, which can be either plain or encrypted
+ if (inCipher != null)
+ result = inCipher.doFinal(incoming, offset, payloadLength);
+ else
+ {
+ result = new byte[payloadLength];
+ System.arraycopy(incoming, offset, result, 0, result.length);
+ }
+ }
+ else // no integrity protection; just confidentiality
+ result = inCipher.doFinal(incoming, offset, len);
+ }
+ catch (IOException x)
+ {
+ if (x instanceof SaslException)
+ throw (SaslException) x;
+ throw new SaslException("engineUnwrap()", x);
+ }
+ if (Configuration.DEBUG)
+ {
+ log.fine("Incoming buffer (after security): " + Util.dumpString(result));
+ log.exiting(this.getClass().getName(), "engineUnwrap");
+ }
+ return result;
+ }
+
+ protected byte[] engineWrap(final byte[] outgoing, final int offset,
+ final int len) throws SaslException
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "engineWrap");
+ if (outMac == null && outCipher == null)
+ throw new IllegalStateException("connection is not protected");
+ if (Configuration.DEBUG)
+ {
+ log.fine("Outgoing buffer (before security) (hex): "
+ + Util.dumpString(outgoing, offset, len));
+ log.fine("Outgoing buffer (before security) (str): \""
+ + new String(outgoing, offset, len) + "\"");
+ }
+ // at this point one, or both, of confidentiality and integrity protection
+ // services are active.
+ byte[] result;
+ try
+ {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ if (outCipher != null)
+ {
+ result = outCipher.doFinal(outgoing, offset, len);
+ if (Configuration.DEBUG)
+ log.fine("Encoding c (encrypted plaintext): "
+ + Util.dumpString(result));
+ out.write(result);
+ if (outMac != null)
+ {
+ outMac.update(result);
+ if (replayDetection)
+ {
+ outCounter++;
+ if (Configuration.DEBUG)
+ log.fine("outCounter=" + outCounter);
+ outMac.update(new byte[] {
+ (byte)(outCounter >>> 24),
+ (byte)(outCounter >>> 16),
+ (byte)(outCounter >>> 8),
+ (byte) outCounter });
+ }
+ final byte[] C = outMac.doFinal();
+ out.write(C);
+ if (Configuration.DEBUG)
+ log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
+ }
+ // else ciphertext only; do nothing
+ }
+ else // no confidentiality; just integrity [+ replay detection]
+ {
+ if (Configuration.DEBUG)
+ log.fine("Encoding p (plaintext): "
+ + Util.dumpString(outgoing, offset, len));
+ out.write(outgoing, offset, len);
+ outMac.update(outgoing, offset, len);
+ if (replayDetection)
+ {
+ outCounter++;
+ if (Configuration.DEBUG)
+ log.fine("outCounter=" + outCounter);
+ outMac.update(new byte[] {
+ (byte)(outCounter >>> 24),
+ (byte)(outCounter >>> 16),
+ (byte)(outCounter >>> 8),
+ (byte) outCounter });
+ }
+ final byte[] C = outMac.doFinal();
+ out.write(C);
+ if (Configuration.DEBUG)
+ log.fine("Encoding C (integrity checksum): " + Util.dumpString(C));
+ }
+ result = out.toByteArray();
+ }
+ catch (IOException x)
+ {
+ if (x instanceof SaslException)
+ throw (SaslException) x;
+ throw new SaslException("engineWrap()", x);
+ }
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "engineWrap");
+ return result;
+ }
+
+ protected String getNegotiatedQOP()
+ {
+ if (inMac != null)
+ {
+ if (inCipher != null)
+ return Registry.QOP_AUTH_CONF;
+ return Registry.QOP_AUTH_INT;
+ }
+ return Registry.QOP_AUTH;
+ }
+
+ protected String getNegotiatedStrength()
+ {
+ if (inMac != null)
+ {
+ if (inCipher != null)
+ return Registry.STRENGTH_HIGH;
+ return Registry.STRENGTH_MEDIUM;
+ }
+ return Registry.STRENGTH_LOW;
+ }
+
+ protected String getNegotiatedRawSendSize()
+ {
+ return String.valueOf(rawSendSize);
+ }
+
+ protected String getReuse()
+ {
+ return Registry.REUSE_TRUE;
+ }
+
+ private byte[] sendProtocolElements(final byte[] input) throws SaslException
+ {
+ if (Configuration.DEBUG)
+ {
+ log.entering(this.getClass().getName(), "sendProtocolElements");
+ log.fine("C: " + Util.dumpString(input));
+ }
+ // Client send U, I, sid, cn
+ final InputBuffer frameIn = new InputBuffer(input);
+ try
+ {
+ U = frameIn.getText(); // Extract username
+ if (Configuration.DEBUG)
+ log.fine("Got U (username): \"" + U + "\"");
+ authorizationID = frameIn.getText(); // Extract authorisation ID
+ if (Configuration.DEBUG)
+ log.fine("Got I (userid): \"" + authorizationID + "\"");
+ sid = frameIn.getEOS();
+ if (Configuration.DEBUG)
+ log.fine("Got sid (session ID): " + new String(sid));
+ cn = frameIn.getOS();
+ if (Configuration.DEBUG)
+ log.fine("Got cn (client nonce): " + Util.dumpString(cn));
+ cCB = frameIn.getEOS();
+ if (Configuration.DEBUG)
+ log.fine("Got cCB (client channel binding): " + Util.dumpString(cCB));
+ }
+ catch (IOException x)
+ {
+ if (x instanceof SaslException)
+ throw (SaslException) x;
+ throw new AuthenticationException("sendProtocolElements()", x);
+ }
+ // do/can we re-use?
+ if (ServerStore.instance().isAlive(sid))
+ {
+ final SecurityContext ctx = ServerStore.instance().restoreSession(sid);
+ srp = SRP.instance(ctx.getMdName());
+ K = ctx.getK();
+ cIV = ctx.getClientIV();
+ sIV = ctx.getServerIV();
+ replayDetection = ctx.hasReplayDetection();
+ inCounter = ctx.getInCounter();
+ outCounter = ctx.getOutCounter();
+ inMac = ctx.getInMac();
+ outMac = ctx.getOutMac();
+ inCipher = ctx.getInCipher();
+ outCipher = ctx.getOutCipher();
+ if (sn == null || sn.length != 16)
+ sn = new byte[16];
+ getDefaultPRNG().nextBytes(sn);
+ setupSecurityServices(false);
+ final OutputBuffer frameOut = new OutputBuffer();
+ try
+ {
+ frameOut.setScalar(1, 0xFF);
+ frameOut.setOS(sn);
+ frameOut.setEOS(channelBinding);
+ }
+ catch (IOException x)
+ {
+ if (x instanceof SaslException)
+ throw (SaslException) x;
+ throw new AuthenticationException("sendProtocolElements()", x);
+ }
+ final byte[] result = frameOut.encode();
+ if (Configuration.DEBUG)
+ {
+ log.fine("Old session...");
+ log.fine("S: " + Util.dumpString(result));
+ log.fine(" sn = " + Util.dumpString(sn));
+ log.fine(" sCB = " + Util.dumpString(channelBinding));
+ log.exiting(this.getClass().getName(), "sendProtocolElements");
+ }
+ return result;
+ }
+ else
+ { // new session
+ authenticator.activate(properties);
+ // -------------------------------------------------------------------
+ final HashMap mapB = new HashMap();
+ mapB.put(SRP6KeyAgreement.HASH_FUNCTION, srp.getAlgorithm());
+ mapB.put(SRP6KeyAgreement.HOST_PASSWORD_DB, authenticator);
+ try
+ {
+ serverHandler.init(mapB);
+ OutgoingMessage out = new OutgoingMessage();
+ out.writeString(U);
+ IncomingMessage in = new IncomingMessage(out.toByteArray());
+ out = serverHandler.processMessage(in);
+ in = new IncomingMessage(out.toByteArray());
+ N = in.readMPI();
+ g = in.readMPI();
+ s = in.readMPI().toByteArray();
+ B = in.readMPI();
+ }
+ catch (KeyAgreementException x)
+ {
+ throw new SaslException("sendProtocolElements()", x);
+ }
+ // -------------------------------------------------------------------
+ if (Configuration.DEBUG)
+ {
+ log.fine("Encoding N (modulus): " + Util.dump(N));
+ log.fine("Encoding g (generator): " + Util.dump(g));
+ log.fine("Encoding s (client's salt): " + Util.dumpString(s));
+ log.fine("Encoding B (server ephemeral public key): " + Util.dump(B));
+ }
+ // The server creates an options list (L), which consists of a
+ // comma-separated list of option strings that specify the security
+ // service options the server supports.
+ L = createL();
+ if (Configuration.DEBUG)
+ {
+ log.fine("Encoding L (available options): \"" + L + "\"");
+ log.fine("Encoding sIV (server IV): " + Util.dumpString(sIV));
+ }
+ final OutputBuffer frameOut = new OutputBuffer();
+ try
+ {
+ frameOut.setScalar(1, 0x00);
+ frameOut.setMPI(N);
+ frameOut.setMPI(g);
+ frameOut.setOS(s);
+ frameOut.setMPI(B);
+ frameOut.setText(L);
+ }
+ catch (IOException x)
+ {
+ if (x instanceof SaslException)
+ throw (SaslException) x;
+ throw new AuthenticationException("sendProtocolElements()", x);
+ }
+ final byte[] result = frameOut.encode();
+ if (Configuration.DEBUG)
+ {
+ log.fine("New session...");
+ log.fine("S: " + Util.dumpString(result));
+ log.fine(" N = 0x" + N.toString(16));
+ log.fine(" g = 0x" + g.toString(16));
+ log.fine(" s = " + Util.dumpString(s));
+ log.fine(" B = 0x" + B.toString(16));
+ log.fine(" L = " + L);
+ log.exiting(this.getClass().getName(), "sendProtocolElements");
+ }
+ return result;
+ }
+ }
+
+ private byte[] sendEvidence(final byte[] input) throws SaslException
+ {
+ if (Configuration.DEBUG)
+ {
+ log.entering(this.getClass().getName(), "sendEvidence");
+ log.fine("C: " + Util.dumpString(input));
+ }
+ // Client send A, M1, o, cIV
+ final InputBuffer frameIn = new InputBuffer(input);
+ final byte[] M1;
+ try
+ {
+ A = frameIn.getMPI(); // Extract client's ephemeral public key
+ if (Configuration.DEBUG)
+ log.fine("Got A (client ephemeral public key): " + Util.dump(A));
+ M1 = frameIn.getOS(); // Extract evidence
+ if (Configuration.DEBUG)
+ log.fine("Got M1 (client evidence): " + Util.dumpString(M1));
+ o = frameIn.getText(); // Extract client's options list
+ if (Configuration.DEBUG)
+ log.fine("Got o (client chosen options): \"" + o + "\"");
+ cIV = frameIn.getOS(); // Extract client's IV
+ if (Configuration.DEBUG)
+ log.fine("Got cIV (client IV): " + Util.dumpString(cIV));
+ }
+ catch (IOException x)
+ {
+ if (x instanceof SaslException)
+ throw (SaslException) x;
+ throw new AuthenticationException("sendEvidence()", x);
+ }
+ // Parse client's options and set security layer variables
+ parseO(o);
+ // ----------------------------------------------------------------------
+ try
+ {
+ final OutgoingMessage out = new OutgoingMessage();
+ out.writeMPI(A);
+ final IncomingMessage in = new IncomingMessage(out.toByteArray());
+ serverHandler.processMessage(in);
+ K = serverHandler.getSharedSecret();
+ }
+ catch (KeyAgreementException x)
+ {
+ throw new SaslException("sendEvidence()", x);
+ }
+ // ----------------------------------------------------------------------
+ if (Configuration.DEBUG)
+ log.fine("K: " + Util.dumpString(K));
+ final byte[] expected;
+ try
+ {
+ expected = srp.generateM1(N, g, U, s, A, B, K, authorizationID, L, cn,
+ cCB);
+ }
+ catch (UnsupportedEncodingException x)
+ {
+ throw new AuthenticationException("sendEvidence()", x);
+ }
+ // Verify client evidence
+ if (! Arrays.equals(M1, expected))
+ throw new AuthenticationException("M1 mismatch");
+ setupSecurityServices(true);
+ final byte[] M2;
+ try
+ {
+ M2 = srp.generateM2(A, M1, K, U, authorizationID, o, sid, ttl, cIV,
+ sIV, channelBinding);
+ }
+ catch (UnsupportedEncodingException x)
+ {
+ throw new AuthenticationException("sendEvidence()", x);
+ }
+ final OutputBuffer frameOut = new OutputBuffer();
+ try
+ {
+ frameOut.setOS(M2);
+ frameOut.setOS(sIV);
+ frameOut.setEOS(sid);
+ frameOut.setScalar(4, ttl);
+ frameOut.setEOS(channelBinding);
+ }
+ catch (IOException x)
+ {
+ if (x instanceof SaslException)
+ throw (SaslException) x;
+ throw new AuthenticationException("sendEvidence()", x);
+ }
+ final byte[] result = frameOut.encode();
+ if (Configuration.DEBUG)
+ {
+ log.fine("S: " + Util.dumpString(result));
+ log.fine(" M2 = " + Util.dumpString(M2));
+ log.fine(" sIV = " + Util.dumpString(sIV));
+ log.fine(" sid = " + new String(sid));
+ log.fine(" ttl = " + ttl);
+ log.fine(" sCB = " + Util.dumpString(channelBinding));
+ log.exiting(this.getClass().getName(), "sendEvidence");
+ }
+ return result;
+ }
+
+ private String createL()
+ {
+ if (Configuration.DEBUG)
+ log.entering(this.getClass().getName(), "createL()");
+ String s = (String) properties.get(SRPRegistry.SRP_MANDATORY);
+ if (s == null)
+ s = SRPRegistry.DEFAULT_MANDATORY;
+
+ if (! SRPRegistry.MANDATORY_NONE.equals(s)
+ && ! SRPRegistry.OPTION_REPLAY_DETECTION.equals(s)
+ && ! SRPRegistry.OPTION_INTEGRITY.equals(s)
+ && ! SRPRegistry.OPTION_CONFIDENTIALITY.equals(s))
+ {
+ if (Configuration.DEBUG)
+ log.fine("Unrecognised mandatory option (" + s + "). Using default...");
+ s = SRPRegistry.DEFAULT_MANDATORY;
+ }
+ mandatory = s;
+ s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY);
+ final boolean confidentiality = (s == null ? SRPRegistry.DEFAULT_CONFIDENTIALITY
+ : Boolean.valueOf(s).booleanValue());
+ s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION);
+ boolean integrity = (s == null ? SRPRegistry.DEFAULT_INTEGRITY
+ : Boolean.valueOf(s).booleanValue());
+ s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION);
+ final boolean replayDetection = (s == null ? SRPRegistry.DEFAULT_REPLAY_DETECTION
+ : Boolean.valueOf(s).booleanValue());
+ final CPStringBuilder sb = new CPStringBuilder();
+ sb.append(SRPRegistry.OPTION_SRP_DIGEST).append("=")
+ .append(srp.getAlgorithm()).append(",");
+
+ if (! SRPRegistry.MANDATORY_NONE.equals(mandatory))
+ sb.append(SRPRegistry.OPTION_MANDATORY)
+ .append("=").append(mandatory).append(",");
+
+ if (replayDetection)
+ {
+ sb.append(SRPRegistry.OPTION_REPLAY_DETECTION).append(",");
+ // if replay detection is on then force integrity protection
+ integrity = true;
+ }
+ int i;
+ if (integrity)
+ {
+ for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
+ sb.append(SRPRegistry.OPTION_INTEGRITY).append("=")
+ .append(SRPRegistry.INTEGRITY_ALGORITHMS[i]).append(",");
+ }
+ if (confidentiality)
+ {
+ IBlockCipher cipher;
+ for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
+ {
+ cipher = CipherFactory.getInstance(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]);
+ if (cipher != null)
+ sb.append(SRPRegistry.OPTION_CONFIDENTIALITY).append("=")
+ .append(SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i]).append(",");
+ }
+ }
+ final String result = sb.append(SRPRegistry.OPTION_MAX_BUFFER_SIZE)
+ .append("=").append(Registry.SASL_BUFFER_MAX_LIMIT)
+ .toString();
+ if (Configuration.DEBUG)
+ log.exiting(this.getClass().getName(), "createL");
+ return result;
+ }
+
+ // Parse client's options and set security layer variables
+ private void parseO(final String o) throws AuthenticationException
+ {
+ this.replayDetection = false;
+ boolean integrity = false;
+ boolean confidentiality = false;
+ String option;
+ int i;
+
+ final StringTokenizer st = new StringTokenizer(o.toLowerCase(), ",");
+ while (st.hasMoreTokens())
+ {
+ option = st.nextToken();
+ if (Configuration.DEBUG)
+ log.fine("option: <" + option + ">");
+ if (option.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
+ replayDetection = true;
+ else if (option.startsWith(SRPRegistry.OPTION_INTEGRITY + "="))
+ {
+ if (integrity)
+ throw new AuthenticationException(
+ "Only one integrity algorithm may be chosen");
+ option = option.substring(option.indexOf('=') + 1);
+ if (Configuration.DEBUG)
+ log.fine("algorithm: <" + option + ">");
+ for (i = 0; i < SRPRegistry.INTEGRITY_ALGORITHMS.length; i++)
+ {
+ if (SRPRegistry.INTEGRITY_ALGORITHMS[i].equals(option))
+ {
+ chosenIntegrityAlgorithm = option;
+ integrity = true;
+ break;
+ }
+ }
+ if (! integrity)
+ throw new AuthenticationException("Unknown integrity algorithm: "
+ + option);
+ }
+ else if (option.startsWith(SRPRegistry.OPTION_CONFIDENTIALITY + "="))
+ {
+ if (confidentiality)
+ throw new AuthenticationException(
+ "Only one confidentiality algorithm may be chosen");
+ option = option.substring(option.indexOf('=') + 1);
+ if (Configuration.DEBUG)
+ log.fine("algorithm: <" + option + ">");
+ for (i = 0; i < SRPRegistry.CONFIDENTIALITY_ALGORITHMS.length; i++)
+ {
+ if (SRPRegistry.CONFIDENTIALITY_ALGORITHMS[i].equals(option))
+ {
+ chosenConfidentialityAlgorithm = option;
+ confidentiality = true;
+ break;
+ }
+ }
+ if (! confidentiality)
+ throw new AuthenticationException("Unknown confidentiality algorithm: "
+ + option);
+ }
+ else if (option.startsWith(SRPRegistry.OPTION_MAX_BUFFER_SIZE + "="))
+ {
+ final String maxBufferSize = option.substring(option.indexOf('=') + 1);
+ try
+ {
+ rawSendSize = Integer.parseInt(maxBufferSize);
+ if (rawSendSize > Registry.SASL_BUFFER_MAX_LIMIT
+ || rawSendSize < 1)
+ throw new AuthenticationException(
+ "Illegal value for 'maxbuffersize' option");
+ }
+ catch (NumberFormatException x)
+ {
+ throw new AuthenticationException(
+ SRPRegistry.OPTION_MAX_BUFFER_SIZE + "=" + maxBufferSize, x);
+ }
+ }
+ }
+ // check if client did the right thing
+ if (replayDetection)
+ {
+ if (! integrity)
+ throw new AuthenticationException(
+ "Missing integrity protection algorithm but replay detection is chosen");
+ }
+ if (mandatory.equals(SRPRegistry.OPTION_REPLAY_DETECTION))
+ {
+ if (! replayDetection)
+ throw new AuthenticationException(
+ "Replay detection is mandatory but was not chosen");
+ }
+ if (mandatory.equals(SRPRegistry.OPTION_INTEGRITY))
+ {
+ if (! integrity)
+ throw new AuthenticationException(
+ "Integrity protection is mandatory but was not chosen");
+ }
+ if (mandatory.equals(SRPRegistry.OPTION_CONFIDENTIALITY))
+ {
+ if (! confidentiality)
+ throw new AuthenticationException(
+ "Confidentiality is mandatory but was not chosen");
+ }
+ int blockSize = 0;
+ if (chosenConfidentialityAlgorithm != null)
+ {
+ final IBlockCipher cipher = CipherFactory.getInstance(chosenConfidentialityAlgorithm);
+ if (cipher != null)
+ blockSize = cipher.defaultBlockSize();
+ else // should not happen
+ throw new AuthenticationException("Confidentiality algorithm ("
+ + chosenConfidentialityAlgorithm
+ + ") not available");
+ }
+ sIV = new byte[blockSize];
+ if (blockSize > 0)
+ getDefaultPRNG().nextBytes(sIV);
+ }
+
+ private void setupSecurityServices(final boolean newSession)
+ throws SaslException
+ {
+ complete = true; // signal end of authentication phase
+ if (newSession)
+ {
+ outCounter = inCounter = 0;
+ // instantiate cipher if confidentiality protection filter is active
+ if (chosenConfidentialityAlgorithm != null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Activating confidentiality protection filter");
+ inCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
+ outCipher = CALG.getInstance(chosenConfidentialityAlgorithm);
+ }
+ // instantiate hmacs if integrity protection filter is active
+ if (chosenIntegrityAlgorithm != null)
+ {
+ if (Configuration.DEBUG)
+ log.fine("Activating integrity protection filter");
+ inMac = IALG.getInstance(chosenIntegrityAlgorithm);
+ outMac = IALG.getInstance(chosenIntegrityAlgorithm);
+ }
+ // generate a new sid if at least integrity is used
+ sid = (inMac != null ? ServerStore.getNewSessionID() : new byte[0]);
+ }
+ else // same session new keys
+ K = srp.generateKn(K, cn, sn);
+
+ final KDF kdf = KDF.getInstance(K);
+ // initialise in/out ciphers if confidentaility protection is used
+ if (inCipher != null)
+ {
+ outCipher.init(kdf, sIV, Direction.FORWARD);
+ inCipher.init(kdf, cIV, Direction.REVERSED);
+ }
+ // initialise in/out macs if integrity protection is used
+ if (inMac != null)
+ {
+ outMac.init(kdf);
+ inMac.init(kdf);
+ }
+ if (sid != null && sid.length != 0)
+ { // update the security context and save in map
+ if (Configuration.DEBUG)
+ log.fine("Updating security context for sid = " + new String(sid));
+ ServerStore.instance().cacheSession(ttl,
+ new SecurityContext(srp.getAlgorithm(),
+ sid,
+ K,
+ cIV,
+ sIV,
+ replayDetection,
+ inCounter,
+ outCounter,
+ inMac, outMac,
+ inCipher,
+ outCipher));
+ }
+ }
+
+ private PRNG getDefaultPRNG()
+ {
+ if (prng == null)
+ prng = PRNG.getInstance();
+ return prng;
+ }
+}