/* * Copyright (c) 2005, 2013, 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 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 GSSContextImpl && (state == STATE_IN_PROCESS || state == STATE_DONE)) { return ((GSSContextImpl)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 mechanism 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; // read data byte[] token = new byte[is.available()]; SpNegoToken.readFully(is, token); if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "receiving token = " + SpNegoToken.getHexBytes(token)); } // read the SPNEGO token // token will be validated when parsing NegTokenInit initToken = new NegTokenInit(token); if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "received token of type = " + SpNegoToken.getTokenName(initToken.getType())); } Oid[] mechList = initToken.getMechTypeList(); DER_mechTypes = initToken.getMechTypes(); if (DER_mechTypes == null) { valid = false; } /* * Select the best match between the list of mechs * that the initiator requested and the list that * the acceptor will support. */ Oid[] supported_mechSet = getAvailableMechs(); Oid mech_wanted = negotiate_mech_type(supported_mechSet, mechList); if (mech_wanted == null) { valid = false; } // save the desired mechanism internal_mech = mech_wanted; // get the token for mechanism byte[] accept_token; if (mechList[0].equals(mech_wanted) || (GSSUtil.isKerberosMech(mechList[0]) && GSSUtil.isKerberosMech(mech_wanted))) { // get the mechanism token if (DEBUG && !mech_wanted.equals(mechList[0])) { System.out.println("SpNegoContext.acceptSecContext: " + "negotiated mech adjusted to " + mechList[0]); } byte[] mechToken = initToken.getMechToken(); if (mechToken == null) { throw new GSSException(GSSException.FAILURE, -1, "mechToken is missing"); } accept_token = GSS_acceptSecContext(mechToken); mech_wanted = mechList[0]; } else { accept_token = null; } // verify MIC if (!GSSUtil.useMSInterop() && valid) { valid = verifyMechListMIC(DER_mechTypes, initToken.getMechListMIC()); } // determine negotiated result status if (valid) { if (isMechContextEstablished()) { negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE; state = STATE_DONE; // now set the context flags for acceptor setContextFlags(); // print the negotiated mech info if (DEBUG) { System.out.println("SPNEGO Negotiated Mechanism = " + internal_mech + " " + GSSUtil.getMechStr(internal_mech)); } } else { negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE; state = STATE_IN_PROCESS; } } else { negoResult = SpNegoToken.NegoResult.REJECT; state = STATE_DONE; } if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "mechanism wanted = " + mech_wanted); System.out.println("SpNegoContext.acceptSecContext: " + "negotiated result = " + negoResult); } // generate SPNEGO token NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(), mech_wanted, accept_token, null); if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "sending token of type = " + SpNegoToken.getTokenName(targToken.getType())); } // get the encoded token retVal = targToken.getEncoded(); } else if (state == STATE_IN_PROCESS) { // read data byte[] token = new byte[is.available()]; SpNegoToken.readFully(is, token); if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "receiving token = " + SpNegoToken.getHexBytes(token)); } // read the SPNEGO token // token will be validated when parsing NegTokenTarg inputToken = new NegTokenTarg(token); if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "received token of type = " + SpNegoToken.getTokenName(inputToken.getType())); } // read the token byte[] client_token = inputToken.getResponseToken(); byte[] accept_token = GSS_acceptSecContext(client_token); if (accept_token == null) { valid = false; } // determine negotiated result status if (valid) { if (isMechContextEstablished()) { negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE; state = STATE_DONE; } else { negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE; state = STATE_IN_PROCESS; } } else { negoResult = SpNegoToken.NegoResult.REJECT; state = STATE_DONE; } // generate SPNEGO token NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(), null, accept_token, null); if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "sending token of type = " + SpNegoToken.getTokenName(targToken.getType())); } // get the encoded token retVal = targToken.getEncoded(); } else { // XXX Use logging API if (DEBUG) { System.out.println("AcceptSecContext: state = " + state); } } if (DEBUG) { System.out.println("SpNegoContext.acceptSecContext: " + "sending token = " + SpNegoToken.getHexBytes(retVal)); } } catch (IOException e) { GSSException gssException = new GSSException(GSSException.FAILURE, -1, e.getMessage()); gssException.initCause(e); throw gssException; } if (state == STATE_DONE) { // now set the context flags for acceptor setContextFlags(); } return retVal; } /** * obtain the available mechanisms */ private Oid[] getAvailableMechs() { if (myCred != null) { Oid[] mechs = new Oid[1]; mechs[0] = myCred.getInternalMech(); return mechs; } else { return factory.availableMechs; } } /** * get ther DER encoded MechList */ private byte[] getEncodedMechs(Oid[] mechSet) throws IOException, GSSException { DerOutputStream mech = new DerOutputStream(); for (int i = 0; i < mechSet.length; i++) { byte[] mechType = mechSet[i].getDER(); mech.write(mechType); } // insert in SEQUENCE DerOutputStream mechTypeList = new DerOutputStream(); mechTypeList.write(DerValue.tag_Sequence, mech); byte[] encoded = mechTypeList.toByteArray(); return encoded; } /** * get the context flags */ private BitArray getContextFlags() { BitArray out = new BitArray(7); if (getCredDelegState()) out.set(0, true); if (getMutualAuthState()) out.set(1, true); if (getReplayDetState()) out.set(2, true); if (getSequenceDetState()) out.set(3, true); if (getConfState()) out.set(5, true); if (getIntegState()) out.set(6, true); return out; } // Only called on acceptor side. On the initiator side, most flags // are already set at request. For those that might get chanegd, // state from mech below is used. private void setContextFlags() { if (mechContext != null) { // default for cred delegation is false if (mechContext.getCredDelegState()) { credDelegState = true; } // default for the following are true if (!mechContext.getMutualAuthState()) { mutualAuthState = false; } if (!mechContext.getReplayDetState()) { replayDetState = false; } if (!mechContext.getSequenceDetState()) { sequenceDetState = false; } if (!mechContext.getIntegState()) { integState = false; } if (!mechContext.getConfState()) { confState = false; } } } /** * generate MIC on mechList. Not used at the moment. */ /*private byte[] generateMechListMIC(byte[] mechTypes) throws GSSException { // sanity check the required input if (mechTypes == null) { if (DEBUG) { System.out.println("SpNegoContext: no MIC token included"); } return null; } // check if mechanism supports integrity if (!mechContext.getIntegState()) { if (DEBUG) { System.out.println("SpNegoContext: no MIC token included" + " - mechanism does not support integrity"); } return null; } // compute MIC on DER encoded mechanism list byte[] mic = null; try { MessageProp prop = new MessageProp(0, true); mic = getMIC(mechTypes, 0, mechTypes.length, prop); if (DEBUG) { System.out.println("SpNegoContext: getMIC = " + SpNegoToken.getHexBytes(mic)); } } catch (GSSException e) { mic = null; if (DEBUG) { System.out.println("SpNegoContext: no MIC token included" + " - getMIC failed : " + e.getMessage()); } } return mic; }*/ /** * verify MIC on MechList */ private boolean verifyMechListMIC(byte[] mechTypes, byte[] token) throws GSSException { // sanity check the input if (token == null) { if (DEBUG) { System.out.println("SpNegoContext: no MIC token validation"); } return true; } // check if mechanism supports integrity if (!mechContext.getIntegState()) { if (DEBUG) { System.out.println("SpNegoContext: no MIC token validation" + " - mechanism does not support integrity"); } return true; } // now verify the token boolean valid = false; try { MessageProp prop = new MessageProp(0, true); verifyMIC(token, 0, token.length, mechTypes, 0, mechTypes.length, prop); valid = true; } catch (GSSException e) { valid = false; if (DEBUG) { System.out.println("SpNegoContext: MIC validation failed! " + e.getMessage()); } } return valid; } /** * call gss_init_sec_context for the corresponding underlying mechanism */ private byte[] GSS_initSecContext(byte[] token) throws GSSException { byte[] tok = null; if (mechContext == null) { // initialize mech context GSSName serverName = factory.manager.createName(peerName.toString(), peerName.getStringNameType(), internal_mech); GSSCredential cred = null; if (myCred != null) { // create context with provided credential cred = new GSSCredentialImpl(factory.manager, myCred.getInternalCred()); } mechContext = factory.manager.createContext(serverName, internal_mech, cred, GSSContext.DEFAULT_LIFETIME); mechContext.requestConf(confState); mechContext.requestInteg(integState); mechContext.requestCredDeleg(credDelegState); mechContext.requestMutualAuth(mutualAuthState); mechContext.requestReplayDet(replayDetState); mechContext.requestSequenceDet(sequenceDetState); if (mechContext instanceof GSSContextImpl) { ((GSSContextImpl)mechContext).requestDelegPolicy( delegPolicyState); } } // pass token if (token != null) { tok = token; } else { tok = new byte[0]; } // pass token to mechanism initSecContext byte[] init_token = mechContext.initSecContext(tok, 0, tok.length); return init_token; } /** * call gss_accept_sec_context for the corresponding underlying mechanism */ private byte[] GSS_acceptSecContext(byte[] token) throws GSSException { if (mechContext == null) { // initialize mech context GSSCredential cred = null; if (myCred != null) { // create context with provided credential cred = new GSSCredentialImpl(factory.manager, myCred.getInternalCred()); } mechContext = factory.manager.createContext(cred); } // pass token to mechanism acceptSecContext byte[] accept_token = mechContext.acceptSecContext(token, 0, token.length); return accept_token; } /** * This routine compares the recieved mechset to the mechset that * this server can support. It looks sequentially through the mechset * and the first one that matches what the server can support is * chosen as the negotiated mechanism. If one is found, negResult * is set to ACCEPT_COMPLETE, otherwise we return NULL and negResult * is set to REJECT. */ private static Oid negotiate_mech_type(Oid[] supported_mechSet, Oid[] mechSet) { for (int i = 0; i < supported_mechSet.length; i++) { for (int j = 0; j < mechSet.length; j++) { if (mechSet[j].equals(supported_mechSet[i])) { if (DEBUG) { System.out.println("SpNegoContext: " + "negotiated mechanism = " + mechSet[j]); } return (mechSet[j]); } } } return null; } public final boolean isEstablished() { return (state == STATE_DONE); } public final boolean isMechContextEstablished() { if (mechContext != null) { return mechContext.isEstablished(); } else { if (DEBUG) { System.out.println("The underlying mechanism context has " + "not been initialized"); } return false; } } public final byte [] export() throws GSSException { throw new GSSException(GSSException.UNAVAILABLE, -1, "GSS Export Context not available"); } /** * Sets the channel bindings to be used during context * establishment. */ public final void setChannelBinding(ChannelBinding channelBinding) throws GSSException { this.channelBinding = channelBinding; } final ChannelBinding getChannelBinding() { return channelBinding; } /* * Anonymity is a little different in that after an application * requests anonymity it will want to know whether the mechanism * can support it or not, prior to sending any tokens across for * context establishment. Since this is from the initiator's * perspective, it essentially requests that the initiator be * anonymous. */ public final void requestAnonymity(boolean value) throws GSSException { // Ignore silently. Application will check back with // getAnonymityState. } // RFC 2853 actually calls for this to be called after context // establishment to get the right answer, but that is // incorrect. The application may not want to send over any // tokens if anonymity is not available. public final boolean getAnonymityState() { return false; } /** * Requests the desired lifetime. Can only be used on the context * initiator's side. */ public void requestLifetime(int lifetime) throws GSSException { if (state == STATE_NEW && isInitiator()) this.lifetime = lifetime; } /** * The lifetime remaining for this context. */ public final int getLifetime() { if (mechContext != null) { return mechContext.getLifetime(); } else { return GSSContext.INDEFINITE_LIFETIME; } } public final boolean isTransferable() throws GSSException { return false; } /** * Requests that sequence checking be done on the GSS wrap and MIC * tokens. */ public final void requestSequenceDet(boolean value) throws GSSException { if (state == STATE_NEW && isInitiator()) sequenceDetState = value; } /** * Is sequence checking enabled on the GSS Wrap and MIC tokens? * We enable sequence checking if replay detection is enabled. */ public final boolean getSequenceDetState() { return sequenceDetState || replayDetState; } /** * Requests that replay detection be done on the GSS wrap and MIC * tokens. */ public final void requestReplayDet(boolean value) throws GSSException { if (state == STATE_NEW && isInitiator()) replayDetState = value; } /** * Is replay detection enabled on the GSS wrap and MIC tokens? * We enable replay detection if sequence checking is enabled. */ public final boolean getReplayDetState() { return replayDetState || sequenceDetState; } public final GSSNameSpi getTargName() throws GSSException { // fill-in the GSSName // get the peer name for the mechanism if (mechContext != null) { GSSNameImpl targName = (GSSNameImpl)mechContext.getTargName(); peerName = targName.getElement(internal_mech); return peerName; } else { if (DEBUG) { System.out.println("The underlying mechanism context has " + "not been initialized"); } return null; } } public final GSSNameSpi getSrcName() throws GSSException { // fill-in the GSSName // get the src name for the mechanism if (mechContext != null) { GSSNameImpl srcName = (GSSNameImpl)mechContext.getSrcName(); myName = srcName.getElement(internal_mech); return myName; } else { if (DEBUG) { System.out.println("The underlying mechanism context has " + "not been initialized"); } return null; } } /** * Returns the delegated credential for the context. This * is an optional feature of contexts which not all * mechanisms will support. A context can be requested to * support credential delegation by using the CRED_DELEG. * This is only valid on the acceptor side of the context. * @return GSSCredentialSpi object for the delegated credential * @exception GSSException * @see GSSContext#getCredDelegState */ public final GSSCredentialSpi getDelegCred() throws GSSException { if (state != STATE_IN_PROCESS && state != STATE_DONE) throw new GSSException(GSSException.NO_CONTEXT); if (mechContext != null) { GSSCredentialImpl delegCred = (GSSCredentialImpl)mechContext.getDelegCred(); if (delegCred == null) { return null; } // determine delegated cred element usage boolean initiate = false; if (delegCred.getUsage() == GSSCredential.INITIATE_ONLY) { initiate = true; } GSSCredentialSpi mechCred = delegCred.getElement(internal_mech, initiate); SpNegoCredElement cred = new SpNegoCredElement(mechCred); return cred.getInternalCred(); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "getDelegCred called in invalid state!"); } } public final int getWrapSizeLimit(int qop, boolean confReq, int maxTokSize) throws GSSException { if (mechContext != null) { return mechContext.getWrapSizeLimit(qop, confReq, maxTokSize); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "getWrapSizeLimit called in invalid state!"); } } public final byte[] wrap(byte inBuf[], int offset, int len, MessageProp msgProp) throws GSSException { if (mechContext != null) { return mechContext.wrap(inBuf, offset, len, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "Wrap called in invalid state!"); } } public final void wrap(InputStream is, OutputStream os, MessageProp msgProp) throws GSSException { if (mechContext != null) { mechContext.wrap(is, os, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "Wrap called in invalid state!"); } } public final byte[] unwrap(byte inBuf[], int offset, int len, MessageProp msgProp) throws GSSException { if (mechContext != null) { return mechContext.unwrap(inBuf, offset, len, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "UnWrap called in invalid state!"); } } public final void unwrap(InputStream is, OutputStream os, MessageProp msgProp) throws GSSException { if (mechContext != null) { mechContext.unwrap(is, os, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "UnWrap called in invalid state!"); } } public final byte[] getMIC(byte []inMsg, int offset, int len, MessageProp msgProp) throws GSSException { if (mechContext != null) { return mechContext.getMIC(inMsg, offset, len, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "getMIC called in invalid state!"); } } public final void getMIC(InputStream is, OutputStream os, MessageProp msgProp) throws GSSException { if (mechContext != null) { mechContext.getMIC(is, os, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "getMIC called in invalid state!"); } } public final void verifyMIC(byte []inTok, int tokOffset, int tokLen, byte[] inMsg, int msgOffset, int msgLen, MessageProp msgProp) throws GSSException { if (mechContext != null) { mechContext.verifyMIC(inTok, tokOffset, tokLen, inMsg, msgOffset, msgLen, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "verifyMIC called in invalid state!"); } } public final void verifyMIC(InputStream is, InputStream msgStr, MessageProp msgProp) throws GSSException { if (mechContext != null) { mechContext.verifyMIC(is, msgStr, msgProp); } else { throw new GSSException(GSSException.NO_CONTEXT, -1, "verifyMIC called in invalid state!"); } } private static String printState(int state) { switch (state) { case STATE_NEW: return ("STATE_NEW"); case STATE_IN_PROCESS: return ("STATE_IN_PROCESS"); case STATE_DONE: return ("STATE_DONE"); case STATE_DELETED: return ("STATE_DELETED"); default: return ("Unknown state " + state); } } /** * Retrieve attribute of the context for {@code type}. */ public Object inquireSecContext(String type) throws GSSException { if (mechContext == null) { throw new GSSException(GSSException.NO_CONTEXT, -1, "Underlying mech not established."); } if (mechContext instanceof GSSContextImpl) { return ((GSSContextImpl)mechContext).inquireSecContext(type); } else { throw new GSSException(GSSException.BAD_MECH, -1, "inquireSecContext not supported by underlying mech."); } } }