18f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen/* ************************************************************************** 28f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * $OpenLDAP: /com/novell/sasl/client/DigestMD5SaslClient.java,v 1.4 2005/01/17 15:00:54 sunilk Exp $ 38f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 48f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Copyright (C) 2003 Novell, Inc. All Rights Reserved. 58f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 68f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * THIS WORK IS SUBJECT TO U.S. AND INTERNATIONAL COPYRIGHT LAWS AND 78f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * TREATIES. USE, MODIFICATION, AND REDISTRIBUTION OF THIS WORK IS SUBJECT 88f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * TO VERSION 2.0.1 OF THE OPENLDAP PUBLIC LICENSE, A COPY OF WHICH IS 98f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * AVAILABLE AT HTTP://WWW.OPENLDAP.ORG/LICENSE.HTML OR IN THE FILE "LICENSE" 108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * IN THE TOP-LEVEL DIRECTORY OF THE DISTRIBUTION. ANY USE OR EXPLOITATION 118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * OF THIS WORK OTHER THAN AS AUTHORIZED IN VERSION 2.0.1 OF THE OPENLDAP 128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * PUBLIC LICENSE, OR OTHER PRIOR WRITTEN CONSENT FROM NOVELL, COULD SUBJECT 138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. 148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen ******************************************************************************/ 158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenpackage com.novell.sasl.client; 168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.apache.harmony.javax.security.sasl.*; 188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.apache.harmony.javax.security.auth.callback.*; 198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.security.SecureRandom; 208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.security.MessageDigest; 218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.security.NoSuchAlgorithmException; 228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.io.UnsupportedEncodingException; 238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.io.IOException; 248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.util.*; 258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen/** 278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Implements the Client portion of DigestMD5 Sasl mechanism. 288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenpublic class DigestMD5SaslClient implements SaslClient 308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen{ 318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_authorizationId = ""; 328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_protocol = ""; 338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_serverName = ""; 348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private Map m_props; 358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private CallbackHandler m_cbh; 368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private int m_state; 378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_qopValue = ""; 388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private char[] m_HA1 = null; 398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_digestURI; 408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private DigestChallenge m_dc; 418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_clientNonce = ""; 428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_realm = ""; 438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String m_name = ""; 448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final int STATE_INITIAL = 0; 468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final int STATE_DIGEST_RESPONSE_SENT = 1; 478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final int STATE_VALID_SERVER_RESPONSE = 2; 488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final int STATE_INVALID_SERVER_RESPONSE = 3; 498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final int STATE_DISPOSED = 4; 508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final int NONCE_BYTE_COUNT = 32; 528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final int NONCE_HEX_COUNT = 2*NONCE_BYTE_COUNT; 538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static final String DIGEST_METHOD = "AUTHENTICATE"; 558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Creates an DigestMD5SaslClient object using the parameters supplied. 588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Assumes that the QOP, STRENGTH, and SERVER_AUTH properties are 598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * contained in props 608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param authorizationId The possibly null protocol-dependent 628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * identification to be used for authorization. If 638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * null or empty, the server derives an authorization 648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * ID from the client's authentication credentials. 658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * When the SASL authentication completes 668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * successfully, the specified entity is granted 678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * access. 688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param protocol The non-null string name of the protocol for which 708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the authentication is being performed (e.g. "ldap") 718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param serverName The non-null fully qualified host name of the server 738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * to authenticate to 748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param props The possibly null set of properties used to select 768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the SASL mechanism and to configure the 778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * authentication exchange of the selected mechanism. 788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * See the Sasl class for a list of standard properties. 798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Other, possibly mechanism-specific, properties can 808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * be included. Properties not relevant to the selected 818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * mechanism are ignored. 828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param cbh The possibly null callback handler to used by the 848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * SASL mechanisms to get further information from the 858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * application/library to complete the authentication. 868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * For example, a SASL mechanism might require the 878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * authentication ID, password and realm from the 888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * caller. The authentication ID is requested by using 898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * a NameCallback. The password is requested by using 908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * a PasswordCallback. The realm is requested by using 918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * a RealmChoiceCallback if there is a list of realms 928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * to choose from, and by using a RealmCallback if the 938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * realm must be entered. 948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return A possibly null SaslClient created using the 968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * parameters supplied. If null, this factory cannot 978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * produce a SaslClient using the parameters supplied. 988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException If a SaslClient instance cannot be created 1008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * because of an error 1018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 1028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public static SaslClient getClient( 1038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String authorizationId, 1048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String protocol, 1058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String serverName, 1068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen Map props, 1078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen CallbackHandler cbh) 1088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 1098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String desiredQOP = (String)props.get(Sasl.QOP); 1108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String desiredStrength = (String)props.get(Sasl.STRENGTH); 1118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String serverAuth = (String)props.get(Sasl.SERVER_AUTH); 1128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //only support qop equal to auth 1148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if ((desiredQOP != null) && !"auth".equals(desiredQOP)) 1158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return null; 1168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //doesn't support server authentication 1188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if ((serverAuth != null) && !"false".equals(serverAuth)) 1198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return null; 1208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //need a callback handler to get the password 1228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (cbh == null) 1238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return null; 1248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return new DigestMD5SaslClient(authorizationId, protocol, 1268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen serverName, props, cbh); 1278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 1288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 1308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Creates an DigestMD5SaslClient object using the parameters supplied. 1318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Assumes that the QOP, STRENGTH, and SERVER_AUTH properties are 1328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * contained in props 1338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 1348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param authorizationId The possibly null protocol-dependent 1358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * identification to be used for authorization. If 1368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * null or empty, the server derives an authorization 1378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * ID from the client's authentication credentials. 1388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * When the SASL authentication completes 1398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * successfully, the specified entity is granted 1408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * access. 1418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 1428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param protocol The non-null string name of the protocol for which 1438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the authentication is being performed (e.g. "ldap") 1448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 1458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param serverName The non-null fully qualified host name of the server 1468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * to authenticate to 1478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 1488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param props The possibly null set of properties used to select 1498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the SASL mechanism and to configure the 1508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * authentication exchange of the selected mechanism. 1518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * See the Sasl class for a list of standard properties. 1528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Other, possibly mechanism-specific, properties can 1538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * be included. Properties not relevant to the selected 1548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * mechanism are ignored. 1558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 1568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param cbh The possibly null callback handler to used by the 1578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * SASL mechanisms to get further information from the 1588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * application/library to complete the authentication. 1598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * For example, a SASL mechanism might require the 1608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * authentication ID, password and realm from the 1618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * caller. The authentication ID is requested by using 1628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * a NameCallback. The password is requested by using 1638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * a PasswordCallback. The realm is requested by using 1648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * a RealmChoiceCallback if there is a list of realms 1658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * to choose from, and by using a RealmCallback if the 1668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * realm must be entered. 1678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 1688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 1698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private DigestMD5SaslClient( 1708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String authorizationId, 1718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String protocol, 1728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String serverName, 1738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen Map props, 1748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen CallbackHandler cbh) 1758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 1768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_authorizationId = authorizationId; 1778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_protocol = protocol; 1788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_serverName = serverName; 1798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_props = props; 1808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_cbh = cbh; 1818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_state = STATE_INITIAL; 1838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 1848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 1868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Determines if this mechanism has an optional initial response. If true, 1878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * caller should call evaluateChallenge() with an empty array to get the 1888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * initial response. 1898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 1908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return true if this mechanism has an initial response 1918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 1928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public boolean hasInitialResponse() 1938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 1948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return false; 1958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 1968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 1978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 1988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Determines if the authentication exchange has completed. This method 1998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * may be called at any time, but typically, it will not be called until 2008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the caller has received indication from the server (in a protocol- 2018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * specific manner) that the exchange has completed. 2028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return true if the authentication exchange has completed; 2048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * false otherwise. 2058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 2068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public boolean isComplete() 2078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 2088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if ((m_state == STATE_VALID_SERVER_RESPONSE) || 2098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen (m_state == STATE_INVALID_SERVER_RESPONSE) || 2108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen (m_state == STATE_DISPOSED)) 2118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return true; 2128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 2138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return false; 2148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 2158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 2168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 2178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Unwraps a byte array received from the server. This method can be called 2188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * only after the authentication exchange has completed (i.e., when 2198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * isComplete() returns true) and only if the authentication exchange has 2208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * negotiated integrity and/or privacy as the quality of protection; 2218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * otherwise, an IllegalStateException is thrown. 2228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * incoming is the contents of the SASL buffer as defined in RFC 2222 2248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * without the leading four octet field that represents the length. 2258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * offset and len specify the portion of incoming to use. 2268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param incoming A non-null byte array containing the encoded bytes 2288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * from the server 2298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param offset The starting position at incoming of the bytes to use 2308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param len The number of bytes from incoming to use 2328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return A non-null byte array containing the decoded bytes 2348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 2368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public byte[] unwrap( 2378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] incoming, 2388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen int offset, 2398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen int len) 2408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throws SaslException 2418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 2428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new IllegalStateException( 2438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "unwrap: QOP has neither integrity nor privacy>"); 2448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 2458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 2468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 2478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Wraps a byte array to be sent to the server. This method can be called 2488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * only after the authentication exchange has completed (i.e., when 2498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * isComplete() returns true) and only if the authentication exchange has 2508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * negotiated integrity and/or privacy as the quality of protection; 2518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * otherwise, an IllegalStateException is thrown. 2528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * The result of this method will make up the contents of the SASL buffer as 2548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * defined in RFC 2222 without the leading four octet field that represents 2558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the length. offset and len specify the portion of outgoing to use. 2568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param outgoing A non-null byte array containing the bytes to encode 2588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param offset The starting position at outgoing of the bytes to use 2598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param len The number of bytes from outgoing to use 2608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return A non-null byte array containing the encoded bytes 2628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException if incoming cannot be successfully unwrapped. 2648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception IllegalStateException if the authentication exchange has 2668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * not completed, or if the negotiated quality of 2678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * protection has neither integrity nor privacy. 2688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 2698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public byte[] wrap( 2708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] outgoing, 2718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen int offset, 2728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen int len) 2738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throws SaslException 2748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 2758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new IllegalStateException( 2768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "wrap: QOP has neither integrity nor privacy>"); 2778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 2788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 2798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 2808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Retrieves the negotiated property. This method can be called only after 2818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the authentication exchange has completed (i.e., when isComplete() 2828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * returns true); otherwise, an IllegalStateException is thrown. 2838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param propName The non-null property name 2858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return The value of the negotiated property. If null, the property was 2878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * not negotiated or is not applicable to this mechanism. 2888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 2898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception IllegalStateException if this authentication exchange has 2908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * not completed 2918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 2928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public Object getNegotiatedProperty( 2938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String propName) 2948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 2958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (m_state != STATE_VALID_SERVER_RESPONSE) 2968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new IllegalStateException( 2978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "getNegotiatedProperty: authentication exchange not complete."); 2988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 2998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (Sasl.QOP.equals(propName)) 3008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return "auth"; 3018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 3028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return null; 3038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 3058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 3068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Disposes of any system resources or security-sensitive information the 3078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * SaslClient might be using. Invoking this method invalidates the 3088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * SaslClient instance. This method is idempotent. 3098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 3108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException if a problem was encountered while disposing 3118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * of the resources 3128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 3138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public void dispose() 3148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throws SaslException 3158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 3168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (m_state != STATE_DISPOSED) 3178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 3188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_state = STATE_DISPOSED; 3198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 3228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 3238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Evaluates the challenge data and generates a response. If a challenge 3248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * is received from the server during the authentication process, this 3258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * method is called to prepare an appropriate next response to submit to 3268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the server. 3278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 3288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param challenge The non-null challenge sent from the server. The 3298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * challenge array may have zero length. 3308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 3318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return The possibly null reponse to send to the server. It is null 3328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * if the challenge accompanied a "SUCCESS" status and the 3338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * challenge only contains data for the client to update its 3348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * state and no response needs to be sent to the server. 3358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * The response is a zero-length byte array if the client is to 3368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * send a response with no data. 3378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 3388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException If an error occurred while processing the 3398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * challenge or generating a response. 3408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 3418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public byte[] evaluateChallenge( 3428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] challenge) 3438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throws SaslException 3448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 3458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] response = null; 3468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 3478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //printState(); 3488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen switch (m_state) 3498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 3508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case STATE_INITIAL: 3518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (challenge.length == 0) 3528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("response = byte[0]"); 3538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 3548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen try 3558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 3568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen response = createDigestResponse(challenge). 3578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen getBytes("UTF-8"); 3588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_state = STATE_DIGEST_RESPONSE_SENT; 3598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch (java.io.UnsupportedEncodingException e) 3618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 3628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException( 3638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "UTF-8 encoding not suppported by platform", e); 3648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen break; 3668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case STATE_DIGEST_RESPONSE_SENT: 3678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (checkServerResponseAuth(challenge)) 3688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_state = STATE_VALID_SERVER_RESPONSE; 3698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 3708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 3718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_state = STATE_INVALID_SERVER_RESPONSE; 3728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("Could not validate response-auth " + 3738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "value from server"); 3748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen break; 3768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case STATE_VALID_SERVER_RESPONSE: 3778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case STATE_INVALID_SERVER_RESPONSE: 3788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("Authentication sequence is complete"); 3798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case STATE_DISPOSED: 3808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("Client has been disposed"); 3818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen default: 3828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("Unknown client state."); 3838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 3858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return response; 3868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 3878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 3888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 3898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * This function takes a 16 byte binary md5-hash value and creates a 32 3908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * character (plus a terminating null character) hex-digit 3918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * representation of binary data. 3928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 3938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param hash 16 byte binary md5-hash value in bytes 3948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 3958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return 32 character (plus a terminating null character) hex-digit 3968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * representation of binary data. 3978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 3988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] convertToHex( 3998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] hash) 4008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 4018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen int i; 4028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte j; 4038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte fifteen = 15; 4048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] hex = new char[32]; 4058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen for (i = 0; i < 16; i++) 4078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 4088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //convert value of top 4 bits to hex char 4098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen hex[i*2] = getHexChar((byte)((hash[i] & 0xf0) >> 4)); 4108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //convert value of bottom 4 bits to hex char 4118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen hex[(i*2)+1] = getHexChar((byte)(hash[i] & 0x0f)); 4128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 4138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return hex; 4158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 4168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 4188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Calculates the HA1 portion of the response 4198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 4208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param algorithm Algorith to use. 4218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param userName User being authenticated 4228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param realm realm information 4238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param password password of teh user 4248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param nonce nonce value 4258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param clientNonce Clients Nonce value 4268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 4278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return HA1 portion of the response in a character array 4288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 4298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException If an error occurs 4308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 4318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] DigestCalcHA1( 4328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String algorithm, 4338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String userName, 4348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String realm, 4358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String password, 4368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String nonce, 4378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String clientNonce) throws SaslException 4388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 4398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] hash; 4408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen try 4428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 4438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen MessageDigest md = MessageDigest.getInstance("MD5"); 4448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(userName.getBytes("UTF-8")); 4468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 4478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(realm.getBytes("UTF-8")); 4488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 4498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(password.getBytes("UTF-8")); 4508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen hash = md.digest(); 4518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if ("md5-sess".equals(algorithm)) 4538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 4548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(hash); 4558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 4568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(nonce.getBytes("UTF-8")); 4578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 4588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(clientNonce.getBytes("UTF-8")); 4598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen hash = md.digest(); 4608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 4618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 4628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch(NoSuchAlgorithmException e) 4638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 4648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("No provider found for MD5 hash", e); 4658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 4668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch(UnsupportedEncodingException e) 4678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 4688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException( 4698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "UTF-8 encoding not supported by platform.", e); 4708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 4718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return convertToHex(hash); 4738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 4748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 4768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 4778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * This function calculates the response-value of the response directive of 4788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the digest-response as documented in RFC 2831 4798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 4808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param HA1 H(A1) 4818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param serverNonce nonce from server 4828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param nonceCount 8 hex digits 4838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param clientNonce client nonce 4848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param qop qop-value: "", "auth", "auth-int" 4858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param method method from the request 4868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param digestUri requested URL 4878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param clientResponseFlag request-digest or response-digest 4888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 4898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return Response-value of the response directive of the digest-response 4908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 4918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException If an error occurs 4928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 4938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] DigestCalcResponse( 4948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] HA1, /* H(A1) */ 4958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String serverNonce, /* nonce from server */ 4968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String nonceCount, /* 8 hex digits */ 4978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String clientNonce, /* client nonce */ 4988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String qop, /* qop-value: "", "auth", "auth-int" */ 4998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String method, /* method from the request */ 5008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String digestUri, /* requested URL */ 5018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen boolean clientResponseFlag) /* request-digest or response-digest */ 5028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throws SaslException 5038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] HA2; 5058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] respHash; 5068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] HA2Hex; 5078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen // calculate H(A2) 5098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen try 5108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen MessageDigest md = MessageDigest.getInstance("MD5"); 5128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (clientResponseFlag) 5138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(method.getBytes("UTF-8")); 5148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 5158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(digestUri.getBytes("UTF-8")); 5168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if ("auth-int".equals(qop)) 5178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 5198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update("00000000000000000000000000000000".getBytes("UTF-8")); 5208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen HA2 = md.digest(); 5228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen HA2Hex = convertToHex(HA2); 5238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen // calculate response 5258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(new String(HA1).getBytes("UTF-8")); 5268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 5278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(serverNonce.getBytes("UTF-8")); 5288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 5298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (qop.length() > 0) 5308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(nonceCount.getBytes("UTF-8")); 5328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 5338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(clientNonce.getBytes("UTF-8")); 5348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 5358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(qop.getBytes("UTF-8")); 5368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(":".getBytes("UTF-8")); 5378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen md.update(new String(HA2Hex).getBytes("UTF-8")); 5398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen respHash = md.digest(); 5408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch(NoSuchAlgorithmException e) 5428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("No provider found for MD5 hash", e); 5448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch(UnsupportedEncodingException e) 5468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException( 5488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "UTF-8 encoding not supported by platform.", e); 5498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return convertToHex(respHash); 5528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 5568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Creates the intial response to be sent to the server. 5578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 5588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param challenge Challenge in bytes recived form the Server 5598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 5608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return Initial response to be sent to the server 5618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 5628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private String createDigestResponse( 5638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] challenge) 5648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throws SaslException 5658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] response; 5678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen StringBuffer digestResponse = new StringBuffer(512); 5688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen int realmSize; 5698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_dc = new DigestChallenge(challenge); 5718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_digestURI = m_protocol + "/" + m_serverName; 5738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if ((m_dc.getQop() & DigestChallenge.QOP_AUTH) 5758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen == DigestChallenge.QOP_AUTH ) 5768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_qopValue = "auth"; 5778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 5788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("Client only supports qop of 'auth'"); 5798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 5808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //get call back information 5818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen Callback[] callbacks = new Callback[3]; 5828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen ArrayList realms = m_dc.getRealms(); 5838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen realmSize = realms.size(); 5848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (realmSize == 0) 5858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen callbacks[0] = new RealmCallback("Realm"); 5878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else if (realmSize == 1) 5898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen callbacks[0] = new RealmCallback("Realm", (String)realms.get(0)); 5918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 5928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 5938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 5948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen callbacks[0] = 5958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen new RealmChoiceCallback( 5968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "Realm", 5978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen (String[])realms.toArray(new String[realmSize]), 5988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 0, //the default choice index 5998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen false); //no multiple selections 6008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 6018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen callbacks[1] = new PasswordCallback("Password", false); 6038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //false = no echo 6048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (m_authorizationId == null || m_authorizationId.length() == 0) 6068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen callbacks[2] = new NameCallback("Name"); 6078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 6088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen callbacks[2] = new NameCallback("Name", m_authorizationId); 6098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen try 6118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 6128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_cbh.handle(callbacks); 6138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 6148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch(UnsupportedCallbackException e) 6158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 6168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("Handler does not support" + 6178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen " necessary callbacks",e); 6188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 6198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch(IOException e) 6208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 6218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("IO exception in CallbackHandler.", e); 6228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 6238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (realmSize > 1) 6258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 6268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen int[] selections = 6278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen ((RealmChoiceCallback)callbacks[0]).getSelectedIndexes(); 6288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (selections.length > 0) 6308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_realm = 6318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen ((RealmChoiceCallback)callbacks[0]).getChoices()[selections[0]]; 6328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 6338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_realm = ((RealmChoiceCallback)callbacks[0]).getChoices()[0]; 6348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 6358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen else 6368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_realm = ((RealmCallback)callbacks[0]).getText(); 6378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_clientNonce = getClientNonce(); 6398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_name = ((NameCallback)callbacks[2]).getName(); 6418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (m_name == null) 6428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_name = ((NameCallback)callbacks[2]).getDefaultName(); 6438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (m_name == null) 6448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("No user name was specified."); 6458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_HA1 = DigestCalcHA1( 6478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_dc.getAlgorithm(), 6488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_name, 6498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_realm, 6508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen new String(((PasswordCallback)callbacks[1]).getPassword()), 6518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_dc.getNonce(), 6528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_clientNonce); 6538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen response = DigestCalcResponse(m_HA1, 6558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_dc.getNonce(), 6568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "00000001", 6578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_clientNonce, 6588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_qopValue, 6598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "AUTHENTICATE", 6608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_digestURI, 6618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen true); 6628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append("username=\""); 6648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(m_authorizationId); 6658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen if (0 != m_realm.length()) 6668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 6678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append("\",realm=\""); 6688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(m_realm); 6698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 6708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append("\",cnonce=\""); 6718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(m_clientNonce); 6728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append("\",nc="); 6738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append("00000001"); //nounce count 6748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(",qop="); 6758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(m_qopValue); 6768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(",digest-uri=\"ldap/"); 6778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(m_serverName); 6788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append("\",response="); 6798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(response); 6808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(",charset=utf-8,nonce=\""); 6818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append(m_dc.getNonce()); 6828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen digestResponse.append("\""); 6838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return digestResponse.toString(); 6858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 6868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 6888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 6898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * This function validates the server response. This step performs a 6908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * modicum of mutual authentication by verifying that the server knows 6918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * the user's password 6928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 6938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param serverResponse Response recived form Server 6948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 6958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return true if the mutual authentication succeeds; 6968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * else return false 6978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 6988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException If an error occurs 6998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 7008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen boolean checkServerResponseAuth( 7018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] serverResponse) throws SaslException 7028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 7038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] response; 7048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen ResponseAuth responseAuth = null; 7058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String responseStr; 7068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen responseAuth = new ResponseAuth(serverResponse); 7088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen response = DigestCalcResponse(m_HA1, 7108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_dc.getNonce(), 7118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen "00000001", 7128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_clientNonce, 7138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_qopValue, 7148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen DIGEST_METHOD, 7158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen m_digestURI, 7168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen false); 7178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen responseStr = new String(response); 7198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return responseStr.equals(responseAuth.getResponseValue()); 7218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 7228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 7258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * This function returns hex character representing the value of the input 7268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 7278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @param value Input value in byte 7288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 7298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return Hex value of the Input byte value 7308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 7318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen private static char getHexChar( 7328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte value) 7338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 7348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen switch (value) 7358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 7368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 0: 7378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '0'; 7388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 1: 7398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '1'; 7408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 2: 7418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '2'; 7428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 3: 7438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '3'; 7448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 4: 7458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '4'; 7468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 5: 7478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '5'; 7488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 6: 7498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '6'; 7508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 7: 7518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '7'; 7528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 8: 7538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '8'; 7548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 9: 7558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return '9'; 7568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 10: 7578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return 'a'; 7588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 11: 7598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return 'b'; 7608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 12: 7618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return 'c'; 7628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 13: 7638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return 'd'; 7648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 14: 7658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return 'e'; 7668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen case 15: 7678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return 'f'; 7688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen default: 7698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return 'Z'; 7708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 7718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 7728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 7748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Calculates the Nonce value of the Client 7758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 7768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return Nonce value of the client 7778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 7788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @exception SaslException If an error Occurs 7798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 7808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen String getClientNonce() throws SaslException 7818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 7828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte[] nonceBytes = new byte[NONCE_BYTE_COUNT]; 7838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen SecureRandom prng; 7848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen byte nonceByte; 7858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen char[] hexNonce = new char[NONCE_HEX_COUNT]; 7868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 7878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen try 7888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 7898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen prng = SecureRandom.getInstance("SHA1PRNG"); 7908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen prng.nextBytes(nonceBytes); 7918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen for(int i=0; i<NONCE_BYTE_COUNT; i++) 7928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 7938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //low nibble 7948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen hexNonce[i*2] = getHexChar((byte)(nonceBytes[i] & 0x0f)); 7958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen //high nibble 7968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen hexNonce[(i*2)+1] = getHexChar((byte)((nonceBytes[i] & 0xf0) 7978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen >> 4)); 7988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 7998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return new String(hexNonce); 8008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 8018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen catch(NoSuchAlgorithmException e) 8028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 8038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen throw new SaslException("No random number generator available", e); 8048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 8058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 8068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 8078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen /** 8088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Returns the IANA-registered mechanism name of this SASL client. 8098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * (e.g. "CRAM-MD5", "GSSAPI") 8108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * 8118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @return "DIGEST-MD5"the IANA-registered mechanism name of this SASL 8128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * client. 8138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */ 8148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen public String getMechanismName() 8158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen { 8168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen return "DIGEST-MD5"; 8178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen } 8188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 8198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen} //end class DigestMD5SaslClient 8208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen 821