/* **************************************************************************
* $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;
}
}