1204 lines · 42.4 KB · Java
RawDownload
/* * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.jgss.spnego; import com.sun.security.jgss.ExtendedGSSContext;import com.sun.security.jgss.InquireType;import java.io.*;import java.security.Provider;import org.ietf.jgss.*;import sun.security.jgss.*;import sun.security.jgss.spi.*;import sun.security.util.*; /** * Implements the mechanism specific context class for SPNEGO * GSS-API mechanism * * @author Seema Malkani * @since 1.6 */public class SpNegoContext implements GSSContextSpi {     /*     * The different states that this context can be in.     */    private static final int STATE_NEW = 1;    private static final int STATE_IN_PROCESS = 2;    private static final int STATE_DONE = 3;    private static final int STATE_DELETED = 4;     private int state = STATE_NEW;     /*     * Optional features that the application can set and their default     * values.     */    private boolean credDelegState = false;    private boolean mutualAuthState = true;    private boolean replayDetState = true;    private boolean sequenceDetState = true;    private boolean confState = true;    private boolean integState = true;    private boolean delegPolicyState = false;     private GSSNameSpi peerName = null;    private GSSNameSpi myName = null;    private SpNegoCredElement myCred = null;     private GSSContext mechContext = null;    private byte[] DER_mechTypes = null;     private int lifetime;    private ChannelBinding channelBinding;    private boolean initiator;     // the underlying negotiated mechanism    private Oid internal_mech = null;     // the SpNegoMechFactory that creates this context    final private SpNegoMechFactory factory;     // debug property    static final boolean DEBUG =        java.security.AccessController.doPrivileged(            new sun.security.action.GetBooleanAction            ("sun.security.spnego.debug")).booleanValue();     /**     * Constructor for SpNegoContext to be called on the context initiator's     * side.     */    public SpNegoContext(SpNegoMechFactory factory, GSSNameSpi peerName,                        GSSCredentialSpi myCred,                        int lifetime) throws GSSException {         if (peerName == null)            throw new IllegalArgumentException("Cannot have null peer name");        if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {            throw new IllegalArgumentException("Wrong cred element type");        }        this.peerName = peerName;        this.myCred = (SpNegoCredElement) myCred;        this.lifetime = lifetime;        this.initiator = true;        this.factory = factory;    }     /**     * Constructor for SpNegoContext to be called on the context acceptor's     * side.     */    public SpNegoContext(SpNegoMechFactory factory, GSSCredentialSpi myCred)            throws GSSException {        if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {            throw new IllegalArgumentException("Wrong cred element type");        }        this.myCred = (SpNegoCredElement) myCred;        this.initiator = false;        this.factory = factory;    }     /**     * Constructor for SpNegoContext to import a previously exported context.     */    public SpNegoContext(SpNegoMechFactory factory, byte [] interProcessToken)        throws GSSException {        throw new GSSException(GSSException.UNAVAILABLE,                               -1, "GSS Import Context not available");    }     /**     * Requests that confidentiality be available.     */    public final void requestConf(boolean value) throws GSSException {        if (state == STATE_NEW && isInitiator())            confState  = value;    }     /**     * Is confidentiality available?     */    public final boolean getConfState() {        return confState;    }     /**     * Requests that integrity be available.     */    public final void requestInteg(boolean value) throws GSSException {        if (state == STATE_NEW && isInitiator())            integState  = value;    }     /**     * Requests that deleg policy be respected.     */    public final void requestDelegPolicy(boolean value) throws GSSException {        if (state == STATE_NEW && isInitiator())            delegPolicyState = value;    }     /**     * Is integrity available?     */    public final boolean getIntegState() {        return integState;    }     /**     * Is deleg policy respected?     */    public final boolean getDelegPolicyState() {        if (isInitiator() && mechContext != null &&                mechContext instanceof ExtendedGSSContext &&                (state == STATE_IN_PROCESS || state == STATE_DONE)) {            return ((ExtendedGSSContext)mechContext).getDelegPolicyState();        } else {            return delegPolicyState;        }    }     /**     * Requests that credential delegation be done during context     * establishment.     */    public final void requestCredDeleg(boolean value) throws GSSException {        if (state == STATE_NEW && isInitiator())            credDelegState  = value;    }     /**     * Is credential delegation enabled?     */    public final boolean getCredDelegState() {        if (isInitiator() && mechContext != null &&                (state == STATE_IN_PROCESS || state == STATE_DONE)) {            return mechContext.getCredDelegState();        } else {            return credDelegState;        }    }     /**     * Requests that mutual authentication be done during context     * establishment. Since this is fromm the client's perspective, it     * essentially requests that the server be authenticated.     */    public final void requestMutualAuth(boolean value) throws GSSException {        if (state == STATE_NEW && isInitiator()) {            mutualAuthState  = value;        }    }     /**     * Is mutual authentication enabled? Since this is from the client's     * perspective, it essentially meas that the server is being     * authenticated.     */    public final boolean getMutualAuthState() {        return mutualAuthState;    }     /**     * Returns the mechanism oid.     *     * @return the Oid of this context     */    public final Oid getMech() {        if (isEstablished()) {            return getNegotiatedMech();        }        return (SpNegoMechFactory.GSS_SPNEGO_MECH_OID);    }     public final Oid getNegotiatedMech() {        return (internal_mech);    }     public final Provider getProvider() {        return SpNegoMechFactory.PROVIDER;    }     public final void dispose() throws GSSException {        mechContext = null;        state = STATE_DELETED;    }     /**     * Tests if this is the initiator side of the context.     *     * @return boolean indicating if this is initiator (true)     *  or target (false)     */    public final boolean isInitiator() {        return initiator;    }     /**     * Tests if the context can be used for per-message service.     * Context may allow the calls to the per-message service     * functions before being fully established.     *     * @return boolean indicating if per-message methods can     *  be called.     */    public final boolean isProtReady() {        return (state == STATE_DONE);    }     /**     * Initiator context establishment call. This method may be     * required to be called several times. A CONTINUE_NEEDED return     * call indicates that more calls are needed after the next token     * is received from the peer.     *     * @param is contains the token received from the peer. On the     *        first call it will be ignored.     * @return any token required to be sent to the peer     * It is responsibility of the caller to send the token     * to its peer for processing.     * @exception GSSException     */    public final byte[] initSecContext(InputStream is, int mechTokenSize)        throws GSSException {         byte[] retVal = null;        NegTokenInit initToken = null;        byte[] mechToken = null;        int errorCode = GSSException.FAILURE;         if (DEBUG) {            System.out.println("Entered SpNego.initSecContext with " +                                "state=" + printState(state));        }        if (!isInitiator()) {            throw new GSSException(GSSException.FAILURE, -1,                "initSecContext on an acceptor GSSContext");        }         try {            if (state == STATE_NEW) {                state = STATE_IN_PROCESS;                 errorCode = GSSException.NO_CRED;                 // determine available mech set                Oid[] mechList = getAvailableMechs();                DER_mechTypes = getEncodedMechs(mechList);                 // pull out first mechanism                internal_mech = mechList[0];                 // get the token for first mechanism                mechToken = GSS_initSecContext(null);                 errorCode = GSSException.DEFECTIVE_TOKEN;                // generate SPNEGO token                initToken = new NegTokenInit(DER_mechTypes, getContextFlags(),                                        mechToken, null);                if (DEBUG) {                    System.out.println("SpNegoContext.initSecContext: " +                                "sending token of type = " +                                SpNegoToken.getTokenName(initToken.getType()));                }                // get the encoded token                retVal = initToken.getEncoded();             } else if (state == STATE_IN_PROCESS) {                 errorCode = GSSException.FAILURE;                if (is == null) {                    throw new GSSException(errorCode, -1,                                "No token received from peer!");                }                 errorCode = GSSException.DEFECTIVE_TOKEN;                byte[] server_token = new byte[is.available()];                SpNegoToken.readFully(is, server_token);                if (DEBUG) {                    System.out.println("SpNegoContext.initSecContext: " +                                        "process received token = " +                                        SpNegoToken.getHexBytes(server_token));                }                 // read the SPNEGO token                // token will be validated when parsing                NegTokenTarg targToken = new NegTokenTarg(server_token);                 if (DEBUG) {                    System.out.println("SpNegoContext.initSecContext: " +                                "received token of type = " +                                SpNegoToken.getTokenName(targToken.getType()));                }                 // pull out mechanism                internal_mech = targToken.getSupportedMech();                if (internal_mech == null) {                    // return wth failure                    throw new GSSException(errorCode, -1,                                "supported mechansim from server is null");                }                 // get the negotiated result                SpNegoToken.NegoResult negoResult = null;                int result = targToken.getNegotiatedResult();                switch (result) {                    case 0:                        negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;                        state = STATE_DONE;                        break;                    case 1:                        negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;                        state = STATE_IN_PROCESS;                        break;                    case 2:                        negoResult = SpNegoToken.NegoResult.REJECT;                        state = STATE_DELETED;                        break;                    default:                        state = STATE_DONE;                        break;                }                 errorCode = GSSException.BAD_MECH;                 if (negoResult == SpNegoToken.NegoResult.REJECT) {                    throw new GSSException(errorCode, -1,                                        internal_mech.toString());                }                 errorCode = GSSException.DEFECTIVE_TOKEN;                 if ((negoResult == SpNegoToken.NegoResult.ACCEPT_COMPLETE) ||                    (negoResult == SpNegoToken.NegoResult.ACCEPT_INCOMPLETE)) {                     // pull out the mechanism token                    byte[] accept_token = targToken.getResponseToken();                    if (accept_token == null) {                        if (!isMechContextEstablished()) {                            // return with failure                            throw new GSSException(errorCode, -1,                                    "mechanism token from server is null");                        }                    } else {                        mechToken = GSS_initSecContext(accept_token);                    }                    // verify MIC                    if (!GSSUtil.useMSInterop()) {                        byte[] micToken = targToken.getMechListMIC();                        if (!verifyMechListMIC(DER_mechTypes, micToken)) {                            throw new GSSException(errorCode, -1,                                "verification of MIC on MechList Failed!");                        }                    }                    if (isMechContextEstablished()) {                        state = STATE_DONE;                        retVal = mechToken;                        if (DEBUG) {                            System.out.println("SPNEGO Negotiated Mechanism = "                                + internal_mech + " " +                                GSSUtil.getMechStr(internal_mech));                        }                    } else {                        // generate SPNEGO token                        initToken = new NegTokenInit(null, null,                                                mechToken, null);                        if (DEBUG) {                            System.out.println("SpNegoContext.initSecContext:" +                                " continue sending token of type = " +                                SpNegoToken.getTokenName(initToken.getType()));                        }                        // get the encoded token                        retVal = initToken.getEncoded();                    }                }             } else {                // XXX Use logging API                if (DEBUG) {                    System.out.println(state);                }            }            if (DEBUG) {                if (retVal != null) {                    System.out.println("SNegoContext.initSecContext: " +                        "sending token = " + SpNegoToken.getHexBytes(retVal));                }            }        } catch (GSSException e) {            GSSException gssException =                        new GSSException(errorCode, -1, e.getMessage());            gssException.initCause(e);            throw gssException;        } catch (IOException e) {            GSSException gssException =                new GSSException(GSSException.FAILURE, -1, e.getMessage());            gssException.initCause(e);            throw gssException;        }         return retVal;    }      /**     * Acceptor's context establishment call. This method may be     * required to be called several times. A CONTINUE_NEEDED return     * call indicates that more calls are needed after the next token     * is received from the peer.     *     * @param is contains the token received from the peer.     * @return any token required to be sent to the peer     * It is responsibility of the caller to send the token     * to its peer for processing.     * @exception GSSException     */    public final byte[] acceptSecContext(InputStream is, int mechTokenSize)        throws GSSException {         byte[] retVal = null;        SpNegoToken.NegoResult negoResult;        boolean valid = true;         if (DEBUG) {            System.out.println("Entered SpNegoContext.acceptSecContext with " +                               "state=" +  printState(state));        }         if (isInitiator()) {            throw new GSSException(GSSException.FAILURE, -1,                                   "acceptSecContext on an initiator " +                                   "GSSContext");        }        try {            if (state == STATE_NEW) {                state = STATE_IN_PROCESS; 

Lines 1–500 of 1204.