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