From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- .../gnu/javax/crypto/sasl/srp/SRPServer.java | 842 +++++++++++++++++++++ 1 file changed, 842 insertions(+) create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java (limited to 'libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java') diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java new file mode 100644 index 000000000..fca5c3bf3 --- /dev/null +++ b/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; + } +} -- cgit v1.2.3