/* * 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. Load more
/* * 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;