123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844 |
- /* SRPServer.java --
- Copyright (C) 2003, 2006, 2010 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 = Configuration.DEBUG ?
- Logger.getLogger(SRPServer.class.getName()) : null;
- 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;
- }
- }
|