diff options
Diffstat (limited to 'src/com/novell/sasl/client/DigestChallenge.java')
-rw-r--r-- | src/com/novell/sasl/client/DigestChallenge.java | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/src/com/novell/sasl/client/DigestChallenge.java b/src/com/novell/sasl/client/DigestChallenge.java new file mode 100644 index 0000000..90e6247 --- /dev/null +++ b/src/com/novell/sasl/client/DigestChallenge.java @@ -0,0 +1,393 @@ +/* ************************************************************************** + * $OpenLDAP: /com/novell/sasl/client/DigestChallenge.java,v 1.3 2005/01/17 15:00:54 sunilk Exp $ + * + * Copyright (C) 2003 Novell, Inc. All Rights Reserved. + * + * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND + * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT + * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS + * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" + * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION + * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP + * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT + * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. + ******************************************************************************/ +package com.novell.sasl.client; + +import java.util.*; +import org.apache.harmony.javax.security.sasl.*; + +/** + * Implements the DigestChallenge class which will be used by the + * DigestMD5SaslClient class + */ +class DigestChallenge extends Object +{ + public static final int QOP_AUTH = 0x01; + public static final int QOP_AUTH_INT = 0x02; + public static final int QOP_AUTH_CONF = 0x04; + public static final int QOP_UNRECOGNIZED = 0x08; + + private static final int CIPHER_3DES = 0x01; + private static final int CIPHER_DES = 0x02; + private static final int CIPHER_RC4_40 = 0x04; + private static final int CIPHER_RC4 = 0x08; + private static final int CIPHER_RC4_56 = 0x10; + private static final int CIPHER_UNRECOGNIZED = 0x20; + private static final int CIPHER_RECOGNIZED_MASK = + CIPHER_3DES | CIPHER_DES | CIPHER_RC4_40 | CIPHER_RC4 | CIPHER_RC4_56; + + private ArrayList m_realms; + private String m_nonce; + private int m_qop; + private boolean m_staleFlag; + private int m_maxBuf; + private String m_characterSet; + private String m_algorithm; + private int m_cipherOptions; + + DigestChallenge( + byte[] challenge) + throws SaslException + { + m_realms = new ArrayList(5); + m_nonce = null; + m_qop = 0; + m_staleFlag = false; + m_maxBuf = -1; + m_characterSet = null; + m_algorithm = null; + m_cipherOptions = 0; + + DirectiveList dirList = new DirectiveList(challenge); + try + { + dirList.parseDirectives(); + checkSemantics(dirList); + } + catch (SaslException e) + { + } + } + + /** + * Checks the semantics of the directives in the directive list as parsed + * from the digest challenge byte array. + * + * @param dirList the list of directives parsed from the digest challenge + * + * @exception SaslException If a semantic error occurs + */ + void checkSemantics( + DirectiveList dirList) throws SaslException + { + Iterator directives = dirList.getIterator(); + ParsedDirective directive; + String name; + + while (directives.hasNext()) + { + directive = (ParsedDirective)directives.next(); + name = directive.getName(); + if (name.equals("realm")) + handleRealm(directive); + else if (name.equals("nonce")) + handleNonce(directive); + else if (name.equals("qop")) + handleQop(directive); + else if (name.equals("maxbuf")) + handleMaxbuf(directive); + else if (name.equals("charset")) + handleCharset(directive); + else if (name.equals("algorithm")) + handleAlgorithm(directive); + else if (name.equals("cipher")) + handleCipher(directive); + else if (name.equals("stale")) + handleStale(directive); + } + + /* post semantic check */ + if (-1 == m_maxBuf) + m_maxBuf = 65536; + + if (m_qop == 0) + m_qop = QOP_AUTH; + else if ( (m_qop & QOP_AUTH) != QOP_AUTH ) + throw new SaslException("Only qop-auth is supported by client"); + else if ( ((m_qop & QOP_AUTH_CONF) == QOP_AUTH_CONF) && + (0 == (m_cipherOptions & CIPHER_RECOGNIZED_MASK)) ) + throw new SaslException("Invalid cipher options"); + else if (null == m_nonce) + throw new SaslException("Missing nonce directive"); + else if (m_staleFlag) + throw new SaslException("Unexpected stale flag"); + else if ( null == m_algorithm ) + throw new SaslException("Missing algorithm directive"); + } + + /** + * This function implements the semenatics of the nonce directive. + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to too many nonce + * values + */ + void handleNonce( + ParsedDirective pd) throws SaslException + { + if (null != m_nonce) + throw new SaslException("Too many nonce values."); + + m_nonce = pd.getValue(); + } + + /** + * This function implements the semenatics of the realm directive. + * + * @param pd ParsedDirective + */ + void handleRealm( + ParsedDirective pd) + { + m_realms.add(pd.getValue()); + } + + /** + * This function implements the semenatics of the qop (quality of protection) + * directive. The value of the qop directive is as defined below: + * qop-options = "qop" "=" <"> qop-list <"> + * qop-list = 1#qop-value + * qop-value = "auth" | "auth-int" | "auth-conf" | token + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to too many qop + * directives + */ + void handleQop( + ParsedDirective pd) throws SaslException + { + String token; + TokenParser parser; + + if (m_qop != 0) + throw new SaslException("Too many qop directives."); + + parser = new TokenParser(pd.getValue()); + for (token = parser.parseToken(); + token != null; + token = parser.parseToken()) + { + if (token.equals("auth")) + m_qop |= QOP_AUTH; + else if (token.equals("auth-int")) + m_qop |= QOP_AUTH_INT; + else if (token.equals("auth-conf")) + m_qop |= QOP_AUTH_CONF; + else + m_qop |= QOP_UNRECOGNIZED; + } + } + + /** + * This function implements the semenatics of the Maxbuf directive. + * the value is defined as: 1*DIGIT + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occur + */ + void handleMaxbuf( + ParsedDirective pd) throws SaslException + { + if (-1 != m_maxBuf) /*it's initialized to -1 */ + throw new SaslException("Too many maxBuf directives."); + + m_maxBuf = Integer.parseInt(pd.getValue()); + + if (0 == m_maxBuf) + throw new SaslException("Max buf value must be greater than zero."); + } + + /** + * This function implements the semenatics of the charset directive. + * the value is defined as: 1*DIGIT + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs dur to too many charset + * directives or Invalid character encoding + * directive + */ + void handleCharset( + ParsedDirective pd) throws SaslException + { + if (null != m_characterSet) + throw new SaslException("Too many charset directives."); + + m_characterSet = pd.getValue(); + + if (!m_characterSet.equals("utf-8")) + throw new SaslException("Invalid character encoding directive"); + } + + /** + * This function implements the semenatics of the charset directive. + * the value is defined as: 1*DIGIT + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to too many algorith + * directive or Invalid algorithm directive + * value + */ + void handleAlgorithm( + ParsedDirective pd) throws SaslException + { + if (null != m_algorithm) + throw new SaslException("Too many algorithm directives."); + + m_algorithm = pd.getValue(); + + if (!"md5-sess".equals(m_algorithm)) + throw new SaslException("Invalid algorithm directive value: " + + m_algorithm); + } + + /** + * This function implements the semenatics of the cipher-opts directive + * directive. The value of the qop directive is as defined below: + * qop-options = "qop" "=" <"> qop-list <"> + * qop-list = 1#qop-value + * qop-value = "auth" | "auth-int" | "auth-conf" | token + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to Too many cipher + * directives + */ + void handleCipher( + ParsedDirective pd) throws SaslException + { + String token; + TokenParser parser; + + if (0 != m_cipherOptions) + throw new SaslException("Too many cipher directives."); + + parser = new TokenParser(pd.getValue()); + token = parser.parseToken(); + for (token = parser.parseToken(); + token != null; + token = parser.parseToken()) + { + if ("3des".equals(token)) + m_cipherOptions |= CIPHER_3DES; + else if ("des".equals(token)) + m_cipherOptions |= CIPHER_DES; + else if ("rc4-40".equals(token)) + m_cipherOptions |= CIPHER_RC4_40; + else if ("rc4".equals(token)) + m_cipherOptions |= CIPHER_RC4; + else if ("rc4-56".equals(token)) + m_cipherOptions |= CIPHER_RC4_56; + else + m_cipherOptions |= CIPHER_UNRECOGNIZED; + } + + if (m_cipherOptions == 0) + m_cipherOptions = CIPHER_UNRECOGNIZED; + } + + /** + * This function implements the semenatics of the stale directive. + * + * @param pd ParsedDirective + * + * @exception SaslException If an error occurs due to Too many stale + * directives or Invalid stale directive value + */ + void handleStale( + ParsedDirective pd) throws SaslException + { + if (false != m_staleFlag) + throw new SaslException("Too many stale directives."); + + if ("true".equals(pd.getValue())) + m_staleFlag = true; + else + throw new SaslException("Invalid stale directive value: " + + pd.getValue()); + } + + /** + * Return the list of the All the Realms + * + * @return List of all the realms + */ + public ArrayList getRealms() + { + return m_realms; + } + + /** + * @return Returns the Nonce + */ + public String getNonce() + { + return m_nonce; + } + + /** + * Return the quality-of-protection + * + * @return The quality-of-protection + */ + public int getQop() + { + return m_qop; + } + + /** + * @return The state of the Staleflag + */ + public boolean getStaleFlag() + { + return m_staleFlag; + } + + /** + * @return The Maximum Buffer value + */ + public int getMaxBuf() + { + return m_maxBuf; + } + + /** + * @return character set values as string + */ + public String getCharacterSet() + { + return m_characterSet; + } + + /** + * @return The String value of the algorithm + */ + public String getAlgorithm() + { + return m_algorithm; + } + + /** + * @return The cipher options + */ + public int getCipherOptions() + { + return m_cipherOptions; + } +} + |