Path: blob/master/src/java.security.jgss/share/classes/sun/security/jgss/spnego/SpNegoContext.java
41161 views
/*1* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.jgss.spnego;2627import java.io.*;28import java.security.Provider;29import org.ietf.jgss.*;30import sun.security.action.GetBooleanAction;31import sun.security.jgss.*;32import sun.security.jgss.spi.*;33import sun.security.util.*;3435/**36* Implements the mechanism specific context class for SPNEGO37* GSS-API mechanism38*39* @author Seema Malkani40* @since 1.641*/42public class SpNegoContext implements GSSContextSpi {4344/*45* The different states that this context can be in.46*/47private static final int STATE_NEW = 1;48private static final int STATE_IN_PROCESS = 2;49private static final int STATE_DONE = 3;50private static final int STATE_DELETED = 4;5152private int state = STATE_NEW;5354/*55* Optional features that the application can set and their default56* values.57*/58private boolean credDelegState = false;59private boolean mutualAuthState = true;60private boolean replayDetState = true;61private boolean sequenceDetState = true;62private boolean confState = true;63private boolean integState = true;64private boolean delegPolicyState = false;6566private GSSNameSpi peerName = null;67private GSSNameSpi myName = null;68private SpNegoCredElement myCred = null;6970private GSSContext mechContext = null;71private byte[] DER_mechTypes = null;7273private int lifetime;74private ChannelBinding channelBinding;75private boolean initiator;7677// the underlying negotiated mechanism78private Oid internal_mech = null;7980// the SpNegoMechFactory that creates this context81private final SpNegoMechFactory factory;8283// debug property84static final boolean DEBUG = GetBooleanAction85.privilegedGetProperty("sun.security.spnego.debug");8687/**88* Constructor for SpNegoContext to be called on the context initiator's89* side.90*/91public SpNegoContext(SpNegoMechFactory factory, GSSNameSpi peerName,92GSSCredentialSpi myCred,93int lifetime) throws GSSException {9495if (peerName == null)96throw new IllegalArgumentException("Cannot have null peer name");97if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {98throw new IllegalArgumentException("Wrong cred element type");99}100this.peerName = peerName;101this.myCred = (SpNegoCredElement) myCred;102this.lifetime = lifetime;103this.initiator = true;104this.factory = factory;105}106107/**108* Constructor for SpNegoContext to be called on the context acceptor's109* side.110*/111public SpNegoContext(SpNegoMechFactory factory, GSSCredentialSpi myCred)112throws GSSException {113if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {114throw new IllegalArgumentException("Wrong cred element type");115}116this.myCred = (SpNegoCredElement) myCred;117this.initiator = false;118this.factory = factory;119}120121/**122* Constructor for SpNegoContext to import a previously exported context.123*/124public SpNegoContext(SpNegoMechFactory factory, byte [] interProcessToken)125throws GSSException {126throw new GSSException(GSSException.UNAVAILABLE,127-1, "GSS Import Context not available");128}129130/**131* Requests that confidentiality be available.132*/133public final void requestConf(boolean value) throws GSSException {134if (state == STATE_NEW && isInitiator())135confState = value;136}137138/**139* Is confidentiality available?140*/141public final boolean getConfState() {142return confState;143}144145/**146* Requests that integrity be available.147*/148public final void requestInteg(boolean value) throws GSSException {149if (state == STATE_NEW && isInitiator())150integState = value;151}152153/**154* Requests that deleg policy be respected.155*/156public final void requestDelegPolicy(boolean value) throws GSSException {157if (state == STATE_NEW && isInitiator())158delegPolicyState = value;159}160161/**162* Is integrity available?163*/164public final boolean getIntegState() {165return integState;166}167168/**169* Is deleg policy respected?170*/171public final boolean getDelegPolicyState() {172if (isInitiator() && mechContext != null &&173mechContext instanceof GSSContextImpl &&174(state == STATE_IN_PROCESS || state == STATE_DONE)) {175return ((GSSContextImpl)mechContext).getDelegPolicyState();176} else {177return delegPolicyState;178}179}180181/**182* Requests that credential delegation be done during context183* establishment.184*/185public final void requestCredDeleg(boolean value) throws GSSException {186if (state == STATE_NEW && isInitiator())187credDelegState = value;188}189190/**191* Is credential delegation enabled?192*/193public final boolean getCredDelegState() {194if (isInitiator() && mechContext != null &&195(state == STATE_IN_PROCESS || state == STATE_DONE)) {196return mechContext.getCredDelegState();197} else {198return credDelegState;199}200}201202/**203* Requests that mutual authentication be done during context204* establishment. Since this is fromm the client's perspective, it205* essentially requests that the server be authenticated.206*/207public final void requestMutualAuth(boolean value) throws GSSException {208if (state == STATE_NEW && isInitiator()) {209mutualAuthState = value;210}211}212213/**214* Is mutual authentication enabled? Since this is from the client's215* perspective, it essentially meas that the server is being216* authenticated.217*/218public final boolean getMutualAuthState() {219return mutualAuthState;220}221222/**223* Returns the mechanism oid.224*225* @return the Oid of this context226*/227public final Oid getMech() {228if (isEstablished()) {229return getNegotiatedMech();230}231return (SpNegoMechFactory.GSS_SPNEGO_MECH_OID);232}233234public final Oid getNegotiatedMech() {235return (internal_mech);236}237238public final Provider getProvider() {239return SpNegoMechFactory.PROVIDER;240}241242public final void dispose() throws GSSException {243mechContext = null;244state = STATE_DELETED;245}246247/**248* Tests if this is the initiator side of the context.249*250* @return boolean indicating if this is initiator (true)251* or target (false)252*/253public final boolean isInitiator() {254return initiator;255}256257/**258* Tests if the context can be used for per-message service.259* Context may allow the calls to the per-message service260* functions before being fully established.261*262* @return boolean indicating if per-message methods can263* be called.264*/265public final boolean isProtReady() {266return (state == STATE_DONE);267}268269/**270* Initiator context establishment call. This method may be271* required to be called several times. A CONTINUE_NEEDED return272* call indicates that more calls are needed after the next token273* is received from the peer.274*275* @param is contains the token received from the peer. On the276* first call it will be ignored.277* @return any token required to be sent to the peer278* It is responsibility of the caller to send the token279* to its peer for processing.280* @exception GSSException281*/282@Deprecated(since="11")283public final byte[] initSecContext(InputStream is, int mechTokenSize)284throws GSSException {285286byte[] retVal = null;287NegTokenInit initToken = null;288byte[] mechToken = null;289int errorCode = GSSException.FAILURE;290291if (DEBUG) {292System.out.println("Entered SpNego.initSecContext with " +293"state=" + printState(state));294}295if (!isInitiator()) {296throw new GSSException(GSSException.FAILURE, -1,297"initSecContext on an acceptor GSSContext");298}299300try {301if (state == STATE_NEW) {302state = STATE_IN_PROCESS;303304errorCode = GSSException.NO_CRED;305306// determine available mech set307Oid[] mechList = getAvailableMechs();308DER_mechTypes = getEncodedMechs(mechList);309310// pull out first mechanism311internal_mech = mechList[0];312313// get the token for first mechanism314mechToken = GSS_initSecContext(null);315316errorCode = GSSException.DEFECTIVE_TOKEN;317// generate SPNEGO token318initToken = new NegTokenInit(DER_mechTypes, getContextFlags(),319mechToken, null);320if (DEBUG) {321System.out.println("SpNegoContext.initSecContext: " +322"sending token of type = " +323SpNegoToken.getTokenName(initToken.getType()));324}325// get the encoded token326retVal = initToken.getEncoded();327328} else if (state == STATE_IN_PROCESS) {329330errorCode = GSSException.FAILURE;331if (is == null) {332throw new GSSException(errorCode, -1,333"No token received from peer!");334}335336errorCode = GSSException.DEFECTIVE_TOKEN;337byte[] server_token = new byte[is.available()];338SpNegoToken.readFully(is, server_token);339if (DEBUG) {340System.out.println("SpNegoContext.initSecContext: " +341"process received token = " +342SpNegoToken.getHexBytes(server_token));343}344345// read the SPNEGO token346// token will be validated when parsing347NegTokenTarg targToken = new NegTokenTarg(server_token);348349if (DEBUG) {350System.out.println("SpNegoContext.initSecContext: " +351"received token of type = " +352SpNegoToken.getTokenName(targToken.getType()));353}354355// pull out mechanism356internal_mech = targToken.getSupportedMech();357if (internal_mech == null) {358// return wth failure359throw new GSSException(errorCode, -1,360"supported mechanism from server is null");361}362363// get the negotiated result364SpNegoToken.NegoResult negoResult = null;365int result = targToken.getNegotiatedResult();366switch (result) {367case 0:368negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;369state = STATE_DONE;370break;371case 1:372negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;373state = STATE_IN_PROCESS;374break;375case 2:376negoResult = SpNegoToken.NegoResult.REJECT;377state = STATE_DELETED;378break;379default:380state = STATE_DONE;381break;382}383384errorCode = GSSException.BAD_MECH;385386if (negoResult == SpNegoToken.NegoResult.REJECT) {387throw new GSSException(errorCode, -1,388internal_mech.toString());389}390391errorCode = GSSException.DEFECTIVE_TOKEN;392393if ((negoResult == SpNegoToken.NegoResult.ACCEPT_COMPLETE) ||394(negoResult == SpNegoToken.NegoResult.ACCEPT_INCOMPLETE)) {395396// pull out the mechanism token397byte[] accept_token = targToken.getResponseToken();398if (accept_token == null) {399if (!isMechContextEstablished()) {400// return with failure401throw new GSSException(errorCode, -1,402"mechanism token from server is null");403}404} else {405mechToken = GSS_initSecContext(accept_token);406}407// verify MIC408if (!GSSUtil.useMSInterop()) {409byte[] micToken = targToken.getMechListMIC();410if (!verifyMechListMIC(DER_mechTypes, micToken)) {411throw new GSSException(errorCode, -1,412"verification of MIC on MechList Failed!");413}414}415if (isMechContextEstablished()) {416state = STATE_DONE;417retVal = mechToken;418if (DEBUG) {419System.out.println("SPNEGO Negotiated Mechanism = "420+ internal_mech + " " +421GSSUtil.getMechStr(internal_mech));422}423} else {424// generate SPNEGO token425initToken = new NegTokenInit(null, null,426mechToken, null);427if (DEBUG) {428System.out.println("SpNegoContext.initSecContext:" +429" continue sending token of type = " +430SpNegoToken.getTokenName(initToken.getType()));431}432// get the encoded token433retVal = initToken.getEncoded();434}435}436437} else {438// XXX Use logging API439if (DEBUG) {440System.out.println(state);441}442}443if (DEBUG) {444if (retVal != null) {445System.out.println("SNegoContext.initSecContext: " +446"sending token = " + SpNegoToken.getHexBytes(retVal));447}448}449} catch (GSSException e) {450GSSException gssException =451new GSSException(errorCode, -1, e.getMessage());452gssException.initCause(e);453throw gssException;454} catch (IOException e) {455GSSException gssException =456new GSSException(GSSException.FAILURE, -1, e.getMessage());457gssException.initCause(e);458throw gssException;459}460461return retVal;462}463464465/**466* Acceptor's context establishment call. This method may be467* required to be called several times. A CONTINUE_NEEDED return468* call indicates that more calls are needed after the next token469* is received from the peer.470*471* @param is contains the token received from the peer.472* @return any token required to be sent to the peer473* It is responsibility of the caller to send the token474* to its peer for processing.475* @exception GSSException476*/477@Deprecated(since="11")478public final byte[] acceptSecContext(InputStream is, int mechTokenSize)479throws GSSException {480481byte[] retVal = null;482SpNegoToken.NegoResult negoResult;483boolean valid = true;484485if (DEBUG) {486System.out.println("Entered SpNegoContext.acceptSecContext with " +487"state=" + printState(state));488}489490if (isInitiator()) {491throw new GSSException(GSSException.FAILURE, -1,492"acceptSecContext on an initiator " +493"GSSContext");494}495try {496if (state == STATE_NEW) {497state = STATE_IN_PROCESS;498499// read data500byte[] token = new byte[is.available()];501SpNegoToken.readFully(is, token);502if (DEBUG) {503System.out.println("SpNegoContext.acceptSecContext: " +504"receiving token = " +505SpNegoToken.getHexBytes(token));506}507508// read the SPNEGO token509// token will be validated when parsing510NegTokenInit initToken = new NegTokenInit(token);511512if (DEBUG) {513System.out.println("SpNegoContext.acceptSecContext: " +514"received token of type = " +515SpNegoToken.getTokenName(initToken.getType()));516}517518Oid[] mechList = initToken.getMechTypeList();519DER_mechTypes = initToken.getMechTypes();520if (DER_mechTypes == null) {521valid = false;522}523524/*525* Select the best match between the list of mechs526* that the initiator requested and the list that527* the acceptor will support.528*/529Oid[] supported_mechSet = getAvailableMechs();530Oid mech_wanted =531negotiate_mech_type(supported_mechSet, mechList);532if (mech_wanted == null) {533valid = false;534}535// save the desired mechanism536internal_mech = mech_wanted;537538// get the token for mechanism539byte[] accept_token;540541if (mechList[0].equals(mech_wanted) ||542(GSSUtil.isKerberosMech(mechList[0]) &&543GSSUtil.isKerberosMech(mech_wanted))) {544// get the mechanism token545if (DEBUG && !mech_wanted.equals(mechList[0])) {546System.out.println("SpNegoContext.acceptSecContext: " +547"negotiated mech adjusted to " + mechList[0]);548}549byte[] mechToken = initToken.getMechToken();550if (mechToken == null) {551throw new GSSException(GSSException.FAILURE, -1,552"mechToken is missing");553}554accept_token = GSS_acceptSecContext(mechToken);555mech_wanted = mechList[0];556} else {557accept_token = null;558}559560// verify MIC561if (!GSSUtil.useMSInterop() && valid) {562valid = verifyMechListMIC(DER_mechTypes,563initToken.getMechListMIC());564}565566// determine negotiated result status567if (valid) {568if (isMechContextEstablished()) {569negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;570state = STATE_DONE;571// now set the context flags for acceptor572setContextFlags();573// print the negotiated mech info574if (DEBUG) {575System.out.println("SPNEGO Negotiated Mechanism = "576+ internal_mech + " " +577GSSUtil.getMechStr(internal_mech));578}579} else {580negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;581state = STATE_IN_PROCESS;582}583} else {584negoResult = SpNegoToken.NegoResult.REJECT;585state = STATE_DELETED;586throw new GSSException(GSSException.FAILURE);587}588589if (DEBUG) {590System.out.println("SpNegoContext.acceptSecContext: " +591"mechanism wanted = " + mech_wanted);592System.out.println("SpNegoContext.acceptSecContext: " +593"negotiated result = " + negoResult);594}595596// generate SPNEGO token597NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(),598mech_wanted, accept_token, null);599if (DEBUG) {600System.out.println("SpNegoContext.acceptSecContext: " +601"sending token of type = " +602SpNegoToken.getTokenName(targToken.getType()));603}604// get the encoded token605retVal = targToken.getEncoded();606607} else if (state == STATE_IN_PROCESS) {608// read data609byte[] token = new byte[is.available()];610SpNegoToken.readFully(is, token);611if (DEBUG) {612System.out.println("SpNegoContext.acceptSecContext: " +613"receiving token = " +614SpNegoToken.getHexBytes(token));615}616617// read the SPNEGO token618// token will be validated when parsing619NegTokenTarg inputToken = new NegTokenTarg(token);620621if (DEBUG) {622System.out.println("SpNegoContext.acceptSecContext: " +623"received token of type = " +624SpNegoToken.getTokenName(inputToken.getType()));625}626627// read the token628byte[] client_token = inputToken.getResponseToken();629byte[] accept_token = GSS_acceptSecContext(client_token);630if (accept_token == null) {631valid = false;632}633634// determine negotiated result status635if (valid) {636if (isMechContextEstablished()) {637negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;638state = STATE_DONE;639} else {640negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;641state = STATE_IN_PROCESS;642}643} else {644negoResult = SpNegoToken.NegoResult.REJECT;645state = STATE_DELETED;646throw new GSSException(GSSException.FAILURE);647}648649// generate SPNEGO token650NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(),651null, accept_token, null);652if (DEBUG) {653System.out.println("SpNegoContext.acceptSecContext: " +654"sending token of type = " +655SpNegoToken.getTokenName(targToken.getType()));656}657// get the encoded token658retVal = targToken.getEncoded();659660} else {661// XXX Use logging API662if (DEBUG) {663System.out.println("AcceptSecContext: state = " + state);664}665}666if (DEBUG) {667System.out.println("SpNegoContext.acceptSecContext: " +668"sending token = " + SpNegoToken.getHexBytes(retVal));669}670} catch (IOException e) {671GSSException gssException =672new GSSException(GSSException.FAILURE, -1, e.getMessage());673gssException.initCause(e);674throw gssException;675}676677if (state == STATE_DONE) {678// now set the context flags for acceptor679setContextFlags();680}681return retVal;682}683684/**685* obtain the available mechanisms686*/687private Oid[] getAvailableMechs() {688if (myCred != null) {689Oid[] mechs = new Oid[1];690mechs[0] = myCred.getInternalMech();691return mechs;692} else {693return factory.availableMechs;694}695}696697/**698* get ther DER encoded MechList699*/700private byte[] getEncodedMechs(Oid[] mechSet)701throws IOException, GSSException {702703DerOutputStream mech = new DerOutputStream();704for (int i = 0; i < mechSet.length; i++) {705byte[] mechType = mechSet[i].getDER();706mech.write(mechType);707}708// insert in SEQUENCE709DerOutputStream mechTypeList = new DerOutputStream();710mechTypeList.write(DerValue.tag_Sequence, mech);711byte[] encoded = mechTypeList.toByteArray();712return encoded;713}714715/**716* get the context flags717*/718private BitArray getContextFlags() {719BitArray out = new BitArray(7);720721if (getCredDelegState()) out.set(0, true);722if (getMutualAuthState()) out.set(1, true);723if (getReplayDetState()) out.set(2, true);724if (getSequenceDetState()) out.set(3, true);725if (getConfState()) out.set(5, true);726if (getIntegState()) out.set(6, true);727728return out;729}730731// Only called on acceptor side. On the initiator side, most flags732// are already set at request. For those that might get chanegd,733// state from mech below is used.734private void setContextFlags() {735736if (mechContext != null) {737// default for cred delegation is false738if (mechContext.getCredDelegState()) {739credDelegState = true;740}741// default for the following are true742if (!mechContext.getMutualAuthState()) {743mutualAuthState = false;744}745if (!mechContext.getReplayDetState()) {746replayDetState = false;747}748if (!mechContext.getSequenceDetState()) {749sequenceDetState = false;750}751if (!mechContext.getIntegState()) {752integState = false;753}754if (!mechContext.getConfState()) {755confState = false;756}757}758}759760/**761* generate MIC on mechList. Not used at the moment.762*/763/*private byte[] generateMechListMIC(byte[] mechTypes)764throws GSSException {765766// sanity check the required input767if (mechTypes == null) {768if (DEBUG) {769System.out.println("SpNegoContext: no MIC token included");770}771return null;772}773774// check if mechanism supports integrity775if (!mechContext.getIntegState()) {776if (DEBUG) {777System.out.println("SpNegoContext: no MIC token included" +778" - mechanism does not support integrity");779}780return null;781}782783// compute MIC on DER encoded mechanism list784byte[] mic = null;785try {786MessageProp prop = new MessageProp(0, true);787mic = getMIC(mechTypes, 0, mechTypes.length, prop);788if (DEBUG) {789System.out.println("SpNegoContext: getMIC = " +790SpNegoToken.getHexBytes(mic));791}792} catch (GSSException e) {793mic = null;794if (DEBUG) {795System.out.println("SpNegoContext: no MIC token included" +796" - getMIC failed : " + e.getMessage());797}798}799return mic;800}*/801802/**803* verify MIC on MechList804*/805private boolean verifyMechListMIC(byte[] mechTypes, byte[] token)806throws GSSException {807808// sanity check the input809if (token == null) {810if (DEBUG) {811System.out.println("SpNegoContext: no MIC token validation");812}813return true;814}815816// check if mechanism supports integrity817if (!mechContext.getIntegState()) {818if (DEBUG) {819System.out.println("SpNegoContext: no MIC token validation" +820" - mechanism does not support integrity");821}822return true;823}824825// now verify the token826boolean valid = false;827try {828MessageProp prop = new MessageProp(0, true);829verifyMIC(token, 0, token.length, mechTypes,8300, mechTypes.length, prop);831valid = true;832} catch (GSSException e) {833valid = false;834if (DEBUG) {835System.out.println("SpNegoContext: MIC validation failed! " +836e.getMessage());837}838}839return valid;840}841842/**843* call gss_init_sec_context for the corresponding underlying mechanism844*/845private byte[] GSS_initSecContext(byte[] token) throws GSSException {846byte[] tok = null;847848if (mechContext == null) {849// initialize mech context850GSSName serverName =851factory.manager.createName(peerName.toString(),852peerName.getStringNameType(), internal_mech);853GSSCredential cred = null;854if (myCred != null) {855// create context with provided credential856cred = new GSSCredentialImpl(factory.manager,857myCred.getInternalCred());858}859mechContext =860factory.manager.createContext(serverName,861internal_mech, cred, GSSContext.DEFAULT_LIFETIME);862mechContext.requestConf(confState);863mechContext.requestInteg(integState);864mechContext.requestCredDeleg(credDelegState);865mechContext.requestMutualAuth(mutualAuthState);866mechContext.requestReplayDet(replayDetState);867mechContext.requestSequenceDet(sequenceDetState);868if (mechContext instanceof GSSContextImpl) {869((GSSContextImpl)mechContext).requestDelegPolicy(870delegPolicyState);871}872}873874// pass token875if (token != null) {876tok = token;877} else {878tok = new byte[0];879}880881// pass token to mechanism initSecContext882byte[] init_token = mechContext.initSecContext(tok, 0, tok.length);883884return init_token;885}886887/**888* call gss_accept_sec_context for the corresponding underlying mechanism889*/890private byte[] GSS_acceptSecContext(byte[] token) throws GSSException {891892if (mechContext == null) {893// initialize mech context894GSSCredential cred = null;895if (myCred != null) {896// create context with provided credential897cred = new GSSCredentialImpl(factory.manager,898myCred.getInternalCred());899}900mechContext = factory.manager.createContext(cred);901}902903// pass token to mechanism acceptSecContext904byte[] accept_token =905mechContext.acceptSecContext(token, 0, token.length);906907return accept_token;908}909910/**911* This routine compares the recieved mechset to the mechset that912* this server can support. It looks sequentially through the mechset913* and the first one that matches what the server can support is914* chosen as the negotiated mechanism. If one is found, negResult915* is set to ACCEPT_COMPLETE, otherwise we return NULL and negResult916* is set to REJECT.917*/918private static Oid negotiate_mech_type(Oid[] supported_mechSet,919Oid[] mechSet) {920for (int i = 0; i < supported_mechSet.length; i++) {921for (int j = 0; j < mechSet.length; j++) {922if (mechSet[j].equals(supported_mechSet[i])) {923if (DEBUG) {924System.out.println("SpNegoContext: " +925"negotiated mechanism = " + mechSet[j]);926}927return (mechSet[j]);928}929}930}931return null;932}933934public final boolean isEstablished() {935return (state == STATE_DONE);936}937938public final boolean isMechContextEstablished() {939if (mechContext != null) {940return mechContext.isEstablished();941} else {942if (DEBUG) {943System.out.println("The underlying mechanism context has " +944"not been initialized");945}946return false;947}948}949950public final byte [] export() throws GSSException {951throw new GSSException(GSSException.UNAVAILABLE, -1,952"GSS Export Context not available");953}954955/**956* Sets the channel bindings to be used during context957* establishment.958*/959public final void setChannelBinding(ChannelBinding channelBinding)960throws GSSException {961this.channelBinding = channelBinding;962}963964final ChannelBinding getChannelBinding() {965return channelBinding;966}967968/*969* Anonymity is a little different in that after an application970* requests anonymity it will want to know whether the mechanism971* can support it or not, prior to sending any tokens across for972* context establishment. Since this is from the initiator's973* perspective, it essentially requests that the initiator be974* anonymous.975*/976public final void requestAnonymity(boolean value) throws GSSException {977// Ignore silently. Application will check back with978// getAnonymityState.979}980981// RFC 2853 actually calls for this to be called after context982// establishment to get the right answer, but that is983// incorrect. The application may not want to send over any984// tokens if anonymity is not available.985public final boolean getAnonymityState() {986return false;987}988989/**990* Requests the desired lifetime. Can only be used on the context991* initiator's side.992*/993public void requestLifetime(int lifetime) throws GSSException {994if (state == STATE_NEW && isInitiator())995this.lifetime = lifetime;996}997998/**999* The lifetime remaining for this context.1000*/1001public final int getLifetime() {1002if (mechContext != null) {1003return mechContext.getLifetime();1004} else {1005return GSSContext.INDEFINITE_LIFETIME;1006}1007}10081009public final boolean isTransferable() throws GSSException {1010return false;1011}10121013/**1014* Requests that sequence checking be done on the GSS wrap and MIC1015* tokens.1016*/1017public final void requestSequenceDet(boolean value) throws GSSException {1018if (state == STATE_NEW && isInitiator())1019sequenceDetState = value;1020}10211022/**1023* Is sequence checking enabled on the GSS Wrap and MIC tokens?1024* We enable sequence checking if replay detection is enabled.1025*/1026public final boolean getSequenceDetState() {1027return sequenceDetState || replayDetState;1028}10291030/**1031* Requests that replay detection be done on the GSS wrap and MIC1032* tokens.1033*/1034public final void requestReplayDet(boolean value) throws GSSException {1035if (state == STATE_NEW && isInitiator())1036replayDetState = value;1037}10381039/**1040* Is replay detection enabled on the GSS wrap and MIC tokens?1041* We enable replay detection if sequence checking is enabled.1042*/1043public final boolean getReplayDetState() {1044return replayDetState || sequenceDetState;1045}10461047public final GSSNameSpi getTargName() throws GSSException {1048// fill-in the GSSName1049// get the peer name for the mechanism1050if (mechContext != null) {1051GSSNameImpl targName = (GSSNameImpl)mechContext.getTargName();1052peerName = targName.getElement(internal_mech);1053return peerName;1054} else {1055if (DEBUG) {1056System.out.println("The underlying mechanism context has " +1057"not been initialized");1058}1059return null;1060}1061}10621063public final GSSNameSpi getSrcName() throws GSSException {1064// fill-in the GSSName1065// get the src name for the mechanism1066if (mechContext != null) {1067GSSNameImpl srcName = (GSSNameImpl)mechContext.getSrcName();1068myName = srcName.getElement(internal_mech);1069return myName;1070} else {1071if (DEBUG) {1072System.out.println("The underlying mechanism context has " +1073"not been initialized");1074}1075return null;1076}1077}10781079/**1080* Returns the delegated credential for the context. This1081* is an optional feature of contexts which not all1082* mechanisms will support. A context can be requested to1083* support credential delegation by using the <b>CRED_DELEG</b>.1084* This is only valid on the acceptor side of the context.1085* @return GSSCredentialSpi object for the delegated credential1086* @exception GSSException1087* @see GSSContext#getCredDelegState1088*/1089public final GSSCredentialSpi getDelegCred() throws GSSException {1090if (state != STATE_IN_PROCESS && state != STATE_DONE)1091throw new GSSException(GSSException.NO_CONTEXT);1092if (mechContext != null) {1093GSSCredentialImpl delegCred =1094(GSSCredentialImpl)mechContext.getDelegCred();1095if (delegCred == null) {1096return null;1097}1098// determine delegated cred element usage1099boolean initiate = false;1100if (delegCred.getUsage() == GSSCredential.INITIATE_ONLY) {1101initiate = true;1102}1103GSSCredentialSpi mechCred =1104delegCred.getElement(internal_mech, initiate);1105SpNegoCredElement cred = new SpNegoCredElement(mechCred);1106return cred.getInternalCred();1107} else {1108throw new GSSException(GSSException.NO_CONTEXT, -1,1109"getDelegCred called in invalid state!");1110}1111}11121113public final int getWrapSizeLimit(int qop, boolean confReq,1114int maxTokSize) throws GSSException {1115if (mechContext != null) {1116return mechContext.getWrapSizeLimit(qop, confReq, maxTokSize);1117} else {1118throw new GSSException(GSSException.NO_CONTEXT, -1,1119"getWrapSizeLimit called in invalid state!");1120}1121}11221123public final byte[] wrap(byte inBuf[], int offset, int len,1124MessageProp msgProp) throws GSSException {1125if (mechContext != null) {1126return mechContext.wrap(inBuf, offset, len, msgProp);1127} else {1128throw new GSSException(GSSException.NO_CONTEXT, -1,1129"Wrap called in invalid state!");1130}1131}11321133@Deprecated(since="11")1134public final void wrap(InputStream is, OutputStream os,1135MessageProp msgProp) throws GSSException {1136if (mechContext != null) {1137mechContext.wrap(is, os, msgProp);1138} else {1139throw new GSSException(GSSException.NO_CONTEXT, -1,1140"Wrap called in invalid state!");1141}1142}11431144public final byte[] unwrap(byte inBuf[], int offset, int len,1145MessageProp msgProp)1146throws GSSException {1147if (mechContext != null) {1148return mechContext.unwrap(inBuf, offset, len, msgProp);1149} else {1150throw new GSSException(GSSException.NO_CONTEXT, -1,1151"UnWrap called in invalid state!");1152}1153}11541155@Deprecated(since="11")1156public final void unwrap(InputStream is, OutputStream os,1157MessageProp msgProp) throws GSSException {1158if (mechContext != null) {1159mechContext.unwrap(is, os, msgProp);1160} else {1161throw new GSSException(GSSException.NO_CONTEXT, -1,1162"UnWrap called in invalid state!");1163}1164}11651166public final byte[] getMIC(byte []inMsg, int offset, int len,1167MessageProp msgProp)1168throws GSSException {1169if (mechContext != null) {1170return mechContext.getMIC(inMsg, offset, len, msgProp);1171} else {1172throw new GSSException(GSSException.NO_CONTEXT, -1,1173"getMIC called in invalid state!");1174}1175}11761177@Deprecated(since="11")1178public final void getMIC(InputStream is, OutputStream os,1179MessageProp msgProp) throws GSSException {1180if (mechContext != null) {1181mechContext.getMIC(is, os, msgProp);1182} else {1183throw new GSSException(GSSException.NO_CONTEXT, -1,1184"getMIC called in invalid state!");1185}1186}11871188public final void verifyMIC(byte []inTok, int tokOffset, int tokLen,1189byte[] inMsg, int msgOffset, int msgLen,1190MessageProp msgProp)1191throws GSSException {1192if (mechContext != null) {1193mechContext.verifyMIC(inTok, tokOffset, tokLen, inMsg, msgOffset,1194msgLen, msgProp);1195} else {1196throw new GSSException(GSSException.NO_CONTEXT, -1,1197"verifyMIC called in invalid state!");1198}1199}12001201@Deprecated(since="11")1202public final void verifyMIC(InputStream is, InputStream msgStr,1203MessageProp msgProp) throws GSSException {1204if (mechContext != null) {1205mechContext.verifyMIC(is, msgStr, msgProp);1206} else {1207throw new GSSException(GSSException.NO_CONTEXT, -1,1208"verifyMIC called in invalid state!");1209}1210}12111212private static String printState(int state) {1213switch (state) {1214case STATE_NEW:1215return ("STATE_NEW");1216case STATE_IN_PROCESS:1217return ("STATE_IN_PROCESS");1218case STATE_DONE:1219return ("STATE_DONE");1220case STATE_DELETED:1221return ("STATE_DELETED");1222default:1223return ("Unknown state " + state);1224}1225}12261227/**1228* Retrieve attribute of the context for {@code type}.1229*/1230public Object inquireSecContext(String type)1231throws GSSException {1232if (mechContext == null) {1233throw new GSSException(GSSException.NO_CONTEXT, -1,1234"Underlying mech not established.");1235}1236if (mechContext instanceof GSSContextImpl) {1237return ((GSSContextImpl)mechContext).inquireSecContext(type);1238} else {1239throw new GSSException(GSSException.BAD_MECH, -1,1240"inquireSecContext not supported by underlying mech.");1241}1242}1243}1244124512461247