23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package com.sun.security.sasl.digest; |
26 package com.sun.security.sasl.digest; |
27 |
27 |
28 import java.security.NoSuchAlgorithmException; |
|
29 import java.io.ByteArrayOutputStream; |
28 import java.io.ByteArrayOutputStream; |
30 import java.io.IOException; |
29 import java.io.IOException; |
31 import java.io.UnsupportedEncodingException; |
30 import java.security.NoSuchAlgorithmException; |
32 import java.util.StringTokenizer; |
31 import java.util.StringTokenizer; |
33 import java.util.ArrayList; |
32 import java.util.ArrayList; |
34 import java.util.List; |
33 import java.util.List; |
35 import java.util.Map; |
34 import java.util.Map; |
36 import java.util.Arrays; |
35 import java.util.Arrays; |
37 |
36 |
38 import java.util.logging.Level; |
37 import java.util.logging.Level; |
39 |
38 |
40 import javax.security.sasl.*; |
39 import javax.security.sasl.*; |
41 import javax.security.auth.callback.*; |
40 import javax.security.auth.callback.*; |
|
41 |
|
42 import static java.nio.charset.StandardCharsets.*; |
42 |
43 |
43 /** |
44 /** |
44 * An implementation of the DIGEST-MD5 server SASL mechanism. |
45 * An implementation of the DIGEST-MD5 server SASL mechanism. |
45 * (<a href="http://www.ietf.org/rfc/rfc2831.txt">RFC 2831</a>) |
46 * (<a href="http://www.ietf.org/rfc/rfc2831.txt">RFC 2831</a>) |
46 * <p> |
47 * <p> |
169 serverRealms.add(token); |
170 serverRealms.add(token); |
170 } |
171 } |
171 } |
172 } |
172 } |
173 } |
173 |
174 |
174 encoding = (useUTF8 ? "UTF8" : "8859_1"); |
175 encoding = (useUTF8 ? UTF_8 : ISO_8859_1); |
175 |
176 |
176 // By default, use server name as realm |
177 // By default, use server name as realm |
177 if (serverRealms.isEmpty()) { |
178 if (serverRealms.isEmpty()) { |
178 if (serverName == null) { |
179 if (serverName == null) { |
179 throw new SaslException( |
180 throw new SaslException( |
227 challenge = generateChallenge(serverRealms, specifiedQops, |
228 challenge = generateChallenge(serverRealms, specifiedQops, |
228 supportedCiphers); |
229 supportedCiphers); |
229 |
230 |
230 step = 3; |
231 step = 3; |
231 return challenge; |
232 return challenge; |
232 } catch (UnsupportedEncodingException e) { |
|
233 throw new SaslException( |
|
234 "DIGEST-MD5: Error encoding challenge", e); |
|
235 } catch (IOException e) { |
233 } catch (IOException e) { |
236 throw new SaslException( |
234 throw new SaslException( |
237 "DIGEST-MD5: Error generating challenge", e); |
235 "DIGEST-MD5: Error generating challenge", e); |
238 } |
236 } |
239 |
237 |
245 */ |
243 */ |
246 try { |
244 try { |
247 byte[][] responseVal = parseDirectives(response, DIRECTIVE_KEY, |
245 byte[][] responseVal = parseDirectives(response, DIRECTIVE_KEY, |
248 null, REALM); |
246 null, REALM); |
249 challenge = validateClientResponse(responseVal); |
247 challenge = validateClientResponse(responseVal); |
250 } catch (SaslException e) { |
|
251 throw e; |
|
252 } catch (UnsupportedEncodingException e) { |
|
253 throw new SaslException( |
|
254 "DIGEST-MD5: Error validating client response", e); |
|
255 } finally { |
248 } finally { |
256 step = 0; // Set to invalid state |
249 step = 0; // Set to invalid state |
257 } |
250 } |
258 |
251 |
259 completed = true; |
252 completed = true; |
296 * cipher-value = "3des" | "des" | "rc4-40" | "rc4" | |
289 * cipher-value = "3des" | "des" | "rc4-40" | "rc4" | |
297 * "rc4-56" | token |
290 * "rc4-56" | token |
298 * auth-param = token "=" ( token | quoted-string ) |
291 * auth-param = token "=" ( token | quoted-string ) |
299 */ |
292 */ |
300 private byte[] generateChallenge(List<String> realms, String qopStr, |
293 private byte[] generateChallenge(List<String> realms, String qopStr, |
301 String cipherStr) throws UnsupportedEncodingException, IOException { |
294 String cipherStr) throws IOException { |
302 ByteArrayOutputStream out = new ByteArrayOutputStream(); |
295 ByteArrayOutputStream out = new ByteArrayOutputStream(); |
303 |
296 |
304 // Realms (>= 0) |
297 // Realms (>= 0) |
305 for (int i = 0; realms != null && i < realms.size(); i++) { |
298 for (int i = 0; realms != null && i < realms.size(); i++) { |
306 out.write("realm=\"".getBytes(encoding)); |
299 out.write("realm=\"".getBytes(encoding)); |
387 * sendMaxBufSize |
380 * sendMaxBufSize |
388 * authzid (gotten from callback) |
381 * authzid (gotten from callback) |
389 * @return response-value ('rspauth') for client to validate |
382 * @return response-value ('rspauth') for client to validate |
390 */ |
383 */ |
391 private byte[] validateClientResponse(byte[][] responseVal) |
384 private byte[] validateClientResponse(byte[][] responseVal) |
392 throws SaslException, UnsupportedEncodingException { |
385 throws SaslException { |
393 |
386 |
394 /* CHARSET: optional atmost once */ |
387 /* CHARSET: optional atmost once */ |
395 if (responseVal[CHARSET] != null) { |
388 if (responseVal[CHARSET] != null) { |
396 // The client should send this directive only if the server has |
389 // The client should send this directive only if the server has |
397 // indicated it supports UTF-8. |
390 // indicated it supports UTF-8. |