• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DigestChallenge( byte[] challenge)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      */
checkSemantics( DirectiveList dirList)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      */
handleNonce( ParsedDirective pd)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      */
handleRealm( ParsedDirective pd)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      */
handleQop( ParsedDirective pd)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      */
handleMaxbuf( ParsedDirective pd)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      */
handleCharset( ParsedDirective pd)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      */
handleAlgorithm( ParsedDirective pd)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      */
handleCipher( ParsedDirective pd)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      */
handleStale( ParsedDirective pd)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      */
getRealms()330     public ArrayList getRealms()
331     {
332         return m_realms;
333     }
334 
335     /**
336      * @return Returns the Nonce
337      */
getNonce()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      */
getQop()348     public int getQop()
349     {
350         return m_qop;
351     }
352 
353     /**
354      * @return The state of the Staleflag
355      */
getStaleFlag()356     public boolean getStaleFlag()
357     {
358         return m_staleFlag;
359     }
360 
361     /**
362      * @return The Maximum Buffer value
363      */
getMaxBuf()364     public int getMaxBuf()
365     {
366         return m_maxBuf;
367     }
368 
369     /**
370      * @return character set values as string
371      */
getCharacterSet()372     public String getCharacterSet()
373     {
374         return m_characterSet;
375     }
376 
377     /**
378      * @return The String value of the algorithm
379      */
getAlgorithm()380     public String getAlgorithm()
381     {
382         return m_algorithm;
383     }
384 
385     /**
386      * @return The cipher options
387      */
getCipherOptions()388     public int getCipherOptions()
389     {
390         return m_cipherOptions;
391     }
392 }
393 
394