Home | History | Annotate | Download | only in client
      1 /* **************************************************************************
      2  * $OpenLDAP: /com/novell/sasl/client/DigestChallenge.java,v 1.3 2005/01/17 15:00:54 sunilk Exp $
      3  *
      4  * Copyright (C) 2003 Novell, Inc. All Rights Reserved.
      5  *
      6  * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND
      7  * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT
      8  * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS
      9  * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE"
     10  * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION
     11  * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP
     12  * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT
     13  * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
     14  ******************************************************************************/
     15 package com.novell.sasl.client;
     16 
     17 import java.util.*;
     18 import org.apache.harmony.javax.security.sasl.*;
     19 
     20 /**
     21  * Implements the DigestChallenge class which will be used by the
     22  * DigestMD5SaslClient class
     23  */
     24 class DigestChallenge extends Object
     25 {
     26     public static final int QOP_AUTH           =    0x01;
     27     public static final int QOP_AUTH_INT       =    0x02;
     28     public static final int QOP_AUTH_CONF       =    0x04;
     29     public static final int QOP_UNRECOGNIZED   =    0x08;
     30 
     31     private static final int CIPHER_3DES          = 0x01;
     32     private static final int CIPHER_DES           = 0x02;
     33     private static final int CIPHER_RC4_40        = 0x04;
     34     private static final int CIPHER_RC4           = 0x08;
     35     private static final int CIPHER_RC4_56        = 0x10;
     36     private static final int CIPHER_UNRECOGNIZED  = 0x20;
     37     private static final int CIPHER_RECOGNIZED_MASK =
     38      CIPHER_3DES | CIPHER_DES | CIPHER_RC4_40 | CIPHER_RC4 | CIPHER_RC4_56;
     39 
     40     private ArrayList m_realms;
     41     private String    m_nonce;
     42     private int       m_qop;
     43     private boolean   m_staleFlag;
     44     private int       m_maxBuf;
     45     private String    m_characterSet;
     46     private String    m_algorithm;
     47     private int       m_cipherOptions;
     48 
     49     DigestChallenge(
     50         byte[] challenge)
     51             throws SaslException
     52     {
     53         m_realms = new ArrayList(5);
     54         m_nonce = null;
     55         m_qop = 0;
     56         m_staleFlag = false;
     57         m_maxBuf = -1;
     58         m_characterSet = null;
     59         m_algorithm = null;
     60         m_cipherOptions = 0;
     61 
     62         DirectiveList dirList = new DirectiveList(challenge);
     63         try
     64         {
     65             dirList.parseDirectives();
     66             checkSemantics(dirList);
     67         }
     68         catch (SaslException e)
     69         {
     70         }
     71     }
     72 
     73     /**
     74      * Checks the semantics of the directives in the directive list as parsed
     75      * from the digest challenge byte array.
     76      *
     77      * @param dirList  the list of directives parsed from the digest challenge
     78      *
     79      * @exception SaslException   If a semantic error occurs
     80      */
     81     void checkSemantics(
     82         DirectiveList dirList) throws SaslException
     83     {
     84     Iterator        directives = dirList.getIterator();
     85     ParsedDirective directive;
     86     String          name;
     87 
     88     while (directives.hasNext())
     89     {
     90         directive = (ParsedDirective)directives.next();
     91         name = directive.getName();
     92         if (name.equals("realm"))
     93             handleRealm(directive);
     94         else if (name.equals("nonce"))
     95             handleNonce(directive);
     96         else if (name.equals("qop"))
     97             handleQop(directive);
     98         else if (name.equals("maxbuf"))
     99             handleMaxbuf(directive);
    100         else if (name.equals("charset"))
    101             handleCharset(directive);
    102         else if (name.equals("algorithm"))
    103             handleAlgorithm(directive);
    104         else if (name.equals("cipher"))
    105             handleCipher(directive);
    106         else if (name.equals("stale"))
    107             handleStale(directive);
    108     }
    109 
    110     /* post semantic check */
    111     if (-1 == m_maxBuf)
    112         m_maxBuf = 65536;
    113 
    114     if (m_qop == 0)
    115         m_qop = QOP_AUTH;
    116     else if ( (m_qop & QOP_AUTH) != QOP_AUTH )
    117         throw new SaslException("Only qop-auth is supported by client");
    118     else if ( ((m_qop & QOP_AUTH_CONF) == QOP_AUTH_CONF) &&
    119               (0 == (m_cipherOptions & CIPHER_RECOGNIZED_MASK)) )
    120         throw new SaslException("Invalid cipher options");
    121     else if (null == m_nonce)
    122         throw new SaslException("Missing nonce directive");
    123     else if (m_staleFlag)
    124         throw new SaslException("Unexpected stale flag");
    125     else if ( null == m_algorithm )
    126         throw new SaslException("Missing algorithm directive");
    127     }
    128 
    129     /**
    130      * This function implements the semenatics of the nonce directive.
    131      *
    132      * @param      pd   ParsedDirective
    133      *
    134      * @exception  SaslException   If an error occurs due to too many nonce
    135      *                             values
    136      */
    137     void handleNonce(
    138         ParsedDirective  pd) throws SaslException
    139     {
    140         if (null != m_nonce)
    141             throw new SaslException("Too many nonce values.");
    142 
    143         m_nonce = pd.getValue();
    144     }
    145 
    146     /**
    147      * This function implements the semenatics of the realm directive.
    148      *
    149      * @param      pd   ParsedDirective
    150      */
    151     void handleRealm(
    152         ParsedDirective  pd)
    153     {
    154         m_realms.add(pd.getValue());
    155     }
    156 
    157     /**
    158      * This function implements the semenatics of the qop (quality of protection)
    159      * directive. The value of the qop directive is as defined below:
    160      *      qop-options =     "qop" "=" <"> qop-list <">
    161      *      qop-list    =     1#qop-value
    162      *      qop-value    =     "auth" | "auth-int"  | "auth-conf" | token
    163      *
    164      * @param      pd   ParsedDirective
    165      *
    166      * @exception  SaslException   If an error occurs due to too many qop
    167      *                             directives
    168      */
    169     void handleQop(
    170         ParsedDirective  pd) throws SaslException
    171     {
    172         String       token;
    173         TokenParser  parser;
    174 
    175         if (m_qop != 0)
    176             throw new SaslException("Too many qop directives.");
    177 
    178         parser = new TokenParser(pd.getValue());
    179         for (token = parser.parseToken();
    180              token != null;
    181              token = parser.parseToken())
    182         {
    183             if (token.equals("auth"))
    184                   m_qop |= QOP_AUTH;
    185               else if (token.equals("auth-int"))
    186                   m_qop |= QOP_AUTH_INT;
    187             else if (token.equals("auth-conf"))
    188                 m_qop |= QOP_AUTH_CONF;
    189             else
    190                 m_qop |= QOP_UNRECOGNIZED;
    191         }
    192     }
    193 
    194     /**
    195      * This function implements the semenatics of the Maxbuf directive.
    196      * the value is defined as: 1*DIGIT
    197      *
    198      * @param      pd   ParsedDirective
    199      *
    200      * @exception  SaslException If an error occur
    201      */
    202     void handleMaxbuf(
    203         ParsedDirective  pd) throws SaslException
    204     {
    205         if (-1 != m_maxBuf) /*it's initialized to -1 */
    206             throw new SaslException("Too many maxBuf directives.");
    207 
    208         m_maxBuf = Integer.parseInt(pd.getValue());
    209 
    210         if (0 == m_maxBuf)
    211             throw new SaslException("Max buf value must be greater than zero.");
    212     }
    213 
    214     /**
    215      * This function implements the semenatics of the charset directive.
    216      * the value is defined as: 1*DIGIT
    217      *
    218      * @param      pd   ParsedDirective
    219      *
    220      * @exception  SaslException If an error occurs dur to too many charset
    221      *                           directives or Invalid character encoding
    222      *                           directive
    223      */
    224     void handleCharset(
    225         ParsedDirective  pd) throws SaslException
    226     {
    227         if (null != m_characterSet)
    228             throw new SaslException("Too many charset directives.");
    229 
    230         m_characterSet = pd.getValue();
    231 
    232         if (!m_characterSet.equals("utf-8"))
    233             throw new SaslException("Invalid character encoding directive");
    234     }
    235 
    236     /**
    237      * This function implements the semenatics of the charset directive.
    238      * the value is defined as: 1*DIGIT
    239      *
    240      * @param      pd   ParsedDirective
    241      *
    242      * @exception  SaslException If an error occurs due to too many algorith
    243      *                           directive or Invalid algorithm directive
    244      *                           value
    245      */
    246     void handleAlgorithm(
    247         ParsedDirective  pd) throws SaslException
    248     {
    249         if (null != m_algorithm)
    250             throw new SaslException("Too many algorithm directives.");
    251 
    252           m_algorithm = pd.getValue();
    253 
    254         if (!"md5-sess".equals(m_algorithm))
    255             throw new SaslException("Invalid algorithm directive value: " +
    256                                     m_algorithm);
    257     }
    258 
    259     /**
    260      * This function implements the semenatics of the cipher-opts directive
    261      * directive. The value of the qop directive is as defined below:
    262      *      qop-options =     "qop" "=" <"> qop-list <">
    263      *      qop-list    =     1#qop-value
    264      *      qop-value    =     "auth" | "auth-int"  | "auth-conf" | token
    265      *
    266      * @param      pd   ParsedDirective
    267      *
    268      * @exception  SaslException If an error occurs due to Too many cipher
    269      *                           directives
    270      */
    271     void handleCipher(
    272         ParsedDirective  pd) throws SaslException
    273     {
    274         String  token;
    275         TokenParser parser;
    276 
    277         if (0 != m_cipherOptions)
    278             throw new SaslException("Too many cipher directives.");
    279 
    280         parser = new TokenParser(pd.getValue());
    281         token = parser.parseToken();
    282         for (token = parser.parseToken();
    283              token != null;
    284              token = parser.parseToken())
    285         {
    286               if ("3des".equals(token))
    287                   m_cipherOptions |= CIPHER_3DES;
    288               else if ("des".equals(token))
    289                   m_cipherOptions |= CIPHER_DES;
    290             else if ("rc4-40".equals(token))
    291                 m_cipherOptions |= CIPHER_RC4_40;
    292             else if ("rc4".equals(token))
    293                 m_cipherOptions |= CIPHER_RC4;
    294             else if ("rc4-56".equals(token))
    295                 m_cipherOptions |= CIPHER_RC4_56;
    296             else
    297                 m_cipherOptions |= CIPHER_UNRECOGNIZED;
    298         }
    299 
    300         if (m_cipherOptions == 0)
    301             m_cipherOptions = CIPHER_UNRECOGNIZED;
    302     }
    303 
    304     /**
    305      * This function implements the semenatics of the stale directive.
    306      *
    307      * @param      pd   ParsedDirective
    308      *
    309      * @exception  SaslException If an error occurs due to Too many stale
    310      *                           directives or Invalid stale directive value
    311      */
    312     void handleStale(
    313         ParsedDirective  pd) throws SaslException
    314     {
    315         if (false != m_staleFlag)
    316             throw new SaslException("Too many stale directives.");
    317 
    318         if ("true".equals(pd.getValue()))
    319             m_staleFlag = true;
    320         else
    321             throw new SaslException("Invalid stale directive value: " +
    322                                     pd.getValue());
    323     }
    324 
    325     /**
    326      * Return the list of the All the Realms
    327      *
    328      * @return  List of all the realms
    329      */
    330     public ArrayList getRealms()
    331     {
    332         return m_realms;
    333     }
    334 
    335     /**
    336      * @return Returns the Nonce
    337      */
    338     public String getNonce()
    339     {
    340         return m_nonce;
    341     }
    342 
    343     /**
    344      * Return the quality-of-protection
    345      *
    346      * @return The quality-of-protection
    347      */
    348     public int getQop()
    349     {
    350         return m_qop;
    351     }
    352 
    353     /**
    354      * @return The state of the Staleflag
    355      */
    356     public boolean getStaleFlag()
    357     {
    358         return m_staleFlag;
    359     }
    360 
    361     /**
    362      * @return The Maximum Buffer value
    363      */
    364     public int getMaxBuf()
    365     {
    366         return m_maxBuf;
    367     }
    368 
    369     /**
    370      * @return character set values as string
    371      */
    372     public String getCharacterSet()
    373     {
    374         return m_characterSet;
    375     }
    376 
    377     /**
    378      * @return The String value of the algorithm
    379      */
    380     public String getAlgorithm()
    381     {
    382         return m_algorithm;
    383     }
    384 
    385     /**
    386      * @return The cipher options
    387      */
    388     public int getCipherOptions()
    389     {
    390         return m_cipherOptions;
    391     }
    392 }
    393 
    394