Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoContext.java
38922 views
/*1* Copyright (c) 2005, 2013, 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 com.sun.security.jgss.ExtendedGSSContext;28import com.sun.security.jgss.InquireType;29import java.io.*;30import java.security.Provider;31import org.ietf.jgss.*;32import sun.security.jgss.*;33import sun.security.jgss.spi.*;34import sun.security.util.*;3536/**37* Implements the mechanism specific context class for SPNEGO38* GSS-API mechanism39*40* @author Seema Malkani41* @since 1.642*/43public class SpNegoContext implements GSSContextSpi {4445/*46* The different states that this context can be in.47*/48private static final int STATE_NEW = 1;49private static final int STATE_IN_PROCESS = 2;50private static final int STATE_DONE = 3;51private static final int STATE_DELETED = 4;5253private int state = STATE_NEW;5455/*56* Optional features that the application can set and their default57* values.58*/59private boolean credDelegState = false;60private boolean mutualAuthState = true;61private boolean replayDetState = true;62private boolean sequenceDetState = true;63private boolean confState = true;64private boolean integState = true;65private boolean delegPolicyState = false;6667private GSSNameSpi peerName = null;68private GSSNameSpi myName = null;69private SpNegoCredElement myCred = null;7071private GSSContext mechContext = null;72private byte[] DER_mechTypes = null;7374private int lifetime;75private ChannelBinding channelBinding;76private boolean initiator;7778// the underlying negotiated mechanism79private Oid internal_mech = null;8081// the SpNegoMechFactory that creates this context82final private SpNegoMechFactory factory;8384// debug property85static final boolean DEBUG =86java.security.AccessController.doPrivileged(87new sun.security.action.GetBooleanAction88("sun.security.spnego.debug")).booleanValue();8990/**91* Constructor for SpNegoContext to be called on the context initiator's92* side.93*/94public SpNegoContext(SpNegoMechFactory factory, GSSNameSpi peerName,95GSSCredentialSpi myCred,96int lifetime) throws GSSException {9798if (peerName == null)99throw new IllegalArgumentException("Cannot have null peer name");100if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {101throw new IllegalArgumentException("Wrong cred element type");102}103this.peerName = peerName;104this.myCred = (SpNegoCredElement) myCred;105this.lifetime = lifetime;106this.initiator = true;107this.factory = factory;108}109110/**111* Constructor for SpNegoContext to be called on the context acceptor's112* side.113*/114public SpNegoContext(SpNegoMechFactory factory, GSSCredentialSpi myCred)115throws GSSException {116if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {117throw new IllegalArgumentException("Wrong cred element type");118}119this.myCred = (SpNegoCredElement) myCred;120this.initiator = false;121this.factory = factory;122}123124/**125* Constructor for SpNegoContext to import a previously exported context.126*/127public SpNegoContext(SpNegoMechFactory factory, byte [] interProcessToken)128throws GSSException {129throw new GSSException(GSSException.UNAVAILABLE,130-1, "GSS Import Context not available");131}132133/**134* Requests that confidentiality be available.135*/136public final void requestConf(boolean value) throws GSSException {137if (state == STATE_NEW && isInitiator())138confState = value;139}140141/**142* Is confidentiality available?143*/144public final boolean getConfState() {145return confState;146}147148/**149* Requests that integrity be available.150*/151public final void requestInteg(boolean value) throws GSSException {152if (state == STATE_NEW && isInitiator())153integState = value;154}155156/**157* Requests that deleg policy be respected.158*/159public final void requestDelegPolicy(boolean value) throws GSSException {160if (state == STATE_NEW && isInitiator())161delegPolicyState = value;162}163164/**165* Is integrity available?166*/167public final boolean getIntegState() {168return integState;169}170171/**172* Is deleg policy respected?173*/174public final boolean getDelegPolicyState() {175if (isInitiator() && mechContext != null &&176mechContext instanceof ExtendedGSSContext &&177(state == STATE_IN_PROCESS || state == STATE_DONE)) {178return ((ExtendedGSSContext)mechContext).getDelegPolicyState();179} else {180return delegPolicyState;181}182}183184/**185* Requests that credential delegation be done during context186* establishment.187*/188public final void requestCredDeleg(boolean value) throws GSSException {189if (state == STATE_NEW && isInitiator())190credDelegState = value;191}192193/**194* Is credential delegation enabled?195*/196public final boolean getCredDelegState() {197if (isInitiator() && mechContext != null &&198(state == STATE_IN_PROCESS || state == STATE_DONE)) {199return mechContext.getCredDelegState();200} else {201return credDelegState;202}203}204205/**206* Requests that mutual authentication be done during context207* establishment. Since this is fromm the client's perspective, it208* essentially requests that the server be authenticated.209*/210public final void requestMutualAuth(boolean value) throws GSSException {211if (state == STATE_NEW && isInitiator()) {212mutualAuthState = value;213}214}215216/**217* Is mutual authentication enabled? Since this is from the client's218* perspective, it essentially meas that the server is being219* authenticated.220*/221public final boolean getMutualAuthState() {222return mutualAuthState;223}224225/**226* Returns the mechanism oid.227*228* @return the Oid of this context229*/230public final Oid getMech() {231if (isEstablished()) {232return getNegotiatedMech();233}234return (SpNegoMechFactory.GSS_SPNEGO_MECH_OID);235}236237public final Oid getNegotiatedMech() {238return (internal_mech);239}240241public final Provider getProvider() {242return SpNegoMechFactory.PROVIDER;243}244245public final void dispose() throws GSSException {246mechContext = null;247state = STATE_DELETED;248}249250/**251* Tests if this is the initiator side of the context.252*253* @return boolean indicating if this is initiator (true)254* or target (false)255*/256public final boolean isInitiator() {257return initiator;258}259260/**261* Tests if the context can be used for per-message service.262* Context may allow the calls to the per-message service263* functions before being fully established.264*265* @return boolean indicating if per-message methods can266* be called.267*/268public final boolean isProtReady() {269return (state == STATE_DONE);270}271272/**273* Initiator context establishment call. This method may be274* required to be called several times. A CONTINUE_NEEDED return275* call indicates that more calls are needed after the next token276* is received from the peer.277*278* @param is contains the token received from the peer. On the279* first call it will be ignored.280* @return any token required to be sent to the peer281* It is responsibility of the caller to send the token282* to its peer for processing.283* @exception GSSException284*/285public final byte[] initSecContext(InputStream is, int mechTokenSize)286throws GSSException {287288byte[] retVal = null;289NegTokenInit initToken = null;290byte[] mechToken = null;291int errorCode = GSSException.FAILURE;292293if (DEBUG) {294System.out.println("Entered SpNego.initSecContext with " +295"state=" + printState(state));296}297if (!isInitiator()) {298throw new GSSException(GSSException.FAILURE, -1,299"initSecContext on an acceptor GSSContext");300}301302try {303if (state == STATE_NEW) {304state = STATE_IN_PROCESS;305306errorCode = GSSException.NO_CRED;307308// determine available mech set309Oid[] mechList = getAvailableMechs();310DER_mechTypes = getEncodedMechs(mechList);311312// pull out first mechanism313internal_mech = mechList[0];314315// get the token for first mechanism316mechToken = GSS_initSecContext(null);317318errorCode = GSSException.DEFECTIVE_TOKEN;319// generate SPNEGO token320initToken = new NegTokenInit(DER_mechTypes, getContextFlags(),321mechToken, null);322if (DEBUG) {323System.out.println("SpNegoContext.initSecContext: " +324"sending token of type = " +325SpNegoToken.getTokenName(initToken.getType()));326}327// get the encoded token328retVal = initToken.getEncoded();329330} else if (state == STATE_IN_PROCESS) {331332errorCode = GSSException.FAILURE;333if (is == null) {334throw new GSSException(errorCode, -1,335"No token received from peer!");336}337338errorCode = GSSException.DEFECTIVE_TOKEN;339byte[] server_token = new byte[is.available()];340SpNegoToken.readFully(is, server_token);341if (DEBUG) {342System.out.println("SpNegoContext.initSecContext: " +343"process received token = " +344SpNegoToken.getHexBytes(server_token));345}346347// read the SPNEGO token348// token will be validated when parsing349NegTokenTarg targToken = new NegTokenTarg(server_token);350351if (DEBUG) {352System.out.println("SpNegoContext.initSecContext: " +353"received token of type = " +354SpNegoToken.getTokenName(targToken.getType()));355}356357// pull out mechanism358internal_mech = targToken.getSupportedMech();359if (internal_mech == null) {360// return wth failure361throw new GSSException(errorCode, -1,362"supported mechanism from server is null");363}364365// get the negotiated result366SpNegoToken.NegoResult negoResult = null;367int result = targToken.getNegotiatedResult();368switch (result) {369case 0:370negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;371state = STATE_DONE;372break;373case 1:374negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;375state = STATE_IN_PROCESS;376break;377case 2:378negoResult = SpNegoToken.NegoResult.REJECT;379state = STATE_DELETED;380break;381default:382state = STATE_DONE;383break;384}385386errorCode = GSSException.BAD_MECH;387388if (negoResult == SpNegoToken.NegoResult.REJECT) {389throw new GSSException(errorCode, -1,390internal_mech.toString());391}392393errorCode = GSSException.DEFECTIVE_TOKEN;394395if ((negoResult == SpNegoToken.NegoResult.ACCEPT_COMPLETE) ||396(negoResult == SpNegoToken.NegoResult.ACCEPT_INCOMPLETE)) {397398// pull out the mechanism token399byte[] accept_token = targToken.getResponseToken();400if (accept_token == null) {401if (!isMechContextEstablished()) {402// return with failure403throw new GSSException(errorCode, -1,404"mechanism token from server is null");405}406} else {407mechToken = GSS_initSecContext(accept_token);408}409// verify MIC410if (!GSSUtil.useMSInterop()) {411byte[] micToken = targToken.getMechListMIC();412if (!verifyMechListMIC(DER_mechTypes, micToken)) {413throw new GSSException(errorCode, -1,414"verification of MIC on MechList Failed!");415}416}417if (isMechContextEstablished()) {418state = STATE_DONE;419retVal = mechToken;420if (DEBUG) {421System.out.println("SPNEGO Negotiated Mechanism = "422+ internal_mech + " " +423GSSUtil.getMechStr(internal_mech));424}425} else {426// generate SPNEGO token427initToken = new NegTokenInit(null, null,428mechToken, null);429if (DEBUG) {430System.out.println("SpNegoContext.initSecContext:" +431" continue sending token of type = " +432SpNegoToken.getTokenName(initToken.getType()));433}434// get the encoded token435retVal = initToken.getEncoded();436}437}438439} else {440// XXX Use logging API441if (DEBUG) {442System.out.println(state);443}444}445if (DEBUG) {446if (retVal != null) {447System.out.println("SNegoContext.initSecContext: " +448"sending token = " + SpNegoToken.getHexBytes(retVal));449}450}451} catch (GSSException e) {452GSSException gssException =453new GSSException(errorCode, -1, e.getMessage());454gssException.initCause(e);455throw gssException;456} catch (IOException e) {457GSSException gssException =458new GSSException(GSSException.FAILURE, -1, e.getMessage());459gssException.initCause(e);460throw gssException;461}462463return retVal;464}465466467/**468* Acceptor's context establishment call. This method may be469* required to be called several times. A CONTINUE_NEEDED return470* call indicates that more calls are needed after the next token471* is received from the peer.472*473* @param is contains the token received from the peer.474* @return any token required to be sent to the peer475* It is responsibility of the caller to send the token476* to its peer for processing.477* @exception GSSException478*/479public final byte[] acceptSecContext(InputStream is, int mechTokenSize)480throws GSSException {481482byte[] retVal = null;483SpNegoToken.NegoResult negoResult;484boolean valid = true;485486if (DEBUG) {487System.out.println("Entered SpNegoContext.acceptSecContext with " +488"state=" + printState(state));489}490491if (isInitiator()) {492throw new GSSException(GSSException.FAILURE, -1,493"acceptSecContext on an initiator " +494"GSSContext");495}496try {497if (state == STATE_NEW) {498state = STATE_IN_PROCESS;499500// read data501byte[] token = new byte[is.available()];502SpNegoToken.readFully(is, token);503if (DEBUG) {504System.out.println("SpNegoContext.acceptSecContext: " +505"receiving token = " +506SpNegoToken.getHexBytes(token));507}508509// read the SPNEGO token510// token will be validated when parsing511NegTokenInit initToken = new NegTokenInit(token);512513if (DEBUG) {514System.out.println("SpNegoContext.acceptSecContext: " +515"received token of type = " +516SpNegoToken.getTokenName(initToken.getType()));517}518519Oid[] mechList = initToken.getMechTypeList();520DER_mechTypes = initToken.getMechTypes();521if (DER_mechTypes == null) {522valid = false;523}524525/*526* Select the best match between the list of mechs527* that the initiator requested and the list that528* the acceptor will support.529*/530Oid[] supported_mechSet = getAvailableMechs();531Oid mech_wanted =532negotiate_mech_type(supported_mechSet, mechList);533if (mech_wanted == null) {534valid = false;535}536// save the desired mechanism537internal_mech = mech_wanted;538539// get the token for mechanism540byte[] accept_token;541542if (mechList[0].equals(mech_wanted) ||543(GSSUtil.isKerberosMech(mechList[0]) &&544GSSUtil.isKerberosMech(mech_wanted))) {545// get the mechanism token546if (DEBUG && !mech_wanted.equals(mechList[0])) {547System.out.println("SpNegoContext.acceptSecContext: " +548"negotiated mech adjusted to " + mechList[0]);549}550byte[] mechToken = initToken.getMechToken();551if (mechToken == null) {552throw new GSSException(GSSException.FAILURE, -1,553"mechToken is missing");554}555accept_token = GSS_acceptSecContext(mechToken);556mech_wanted = mechList[0];557} else {558accept_token = null;559}560561// verify MIC562if (!GSSUtil.useMSInterop() && valid) {563valid = verifyMechListMIC(DER_mechTypes,564initToken.getMechListMIC());565}566567// determine negotiated result status568if (valid) {569if (isMechContextEstablished()) {570negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;571state = STATE_DONE;572// now set the context flags for acceptor573setContextFlags();574// print the negotiated mech info575if (DEBUG) {576System.out.println("SPNEGO Negotiated Mechanism = "577+ internal_mech + " " +578GSSUtil.getMechStr(internal_mech));579}580} else {581negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;582state = STATE_IN_PROCESS;583}584} else {585negoResult = SpNegoToken.NegoResult.REJECT;586state = STATE_DONE;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_DONE;646}647648// generate SPNEGO token649NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(),650null, accept_token, null);651if (DEBUG) {652System.out.println("SpNegoContext.acceptSecContext: " +653"sending token of type = " +654SpNegoToken.getTokenName(targToken.getType()));655}656// get the encoded token657retVal = targToken.getEncoded();658659} else {660// XXX Use logging API661if (DEBUG) {662System.out.println("AcceptSecContext: state = " + state);663}664}665if (DEBUG) {666System.out.println("SpNegoContext.acceptSecContext: " +667"sending token = " + SpNegoToken.getHexBytes(retVal));668}669} catch (IOException e) {670GSSException gssException =671new GSSException(GSSException.FAILURE, -1, e.getMessage());672gssException.initCause(e);673throw gssException;674}675676if (state == STATE_DONE) {677// now set the context flags for acceptor678setContextFlags();679}680return retVal;681}682683/**684* obtain the available mechanisms685*/686private Oid[] getAvailableMechs() {687if (myCred != null) {688Oid[] mechs = new Oid[1];689mechs[0] = myCred.getInternalMech();690return mechs;691} else {692return factory.availableMechs;693}694}695696/**697* get ther DER encoded MechList698*/699private byte[] getEncodedMechs(Oid[] mechSet)700throws IOException, GSSException {701702DerOutputStream mech = new DerOutputStream();703for (int i = 0; i < mechSet.length; i++) {704byte[] mechType = mechSet[i].getDER();705mech.write(mechType);706}707// insert in SEQUENCE708DerOutputStream mechTypeList = new DerOutputStream();709mechTypeList.write(DerValue.tag_Sequence, mech);710byte[] encoded = mechTypeList.toByteArray();711return encoded;712}713714/**715* get the context flags716*/717private BitArray getContextFlags() {718BitArray out = new BitArray(7);719720if (getCredDelegState()) out.set(0, true);721if (getMutualAuthState()) out.set(1, true);722if (getReplayDetState()) out.set(2, true);723if (getSequenceDetState()) out.set(3, true);724if (getConfState()) out.set(5, true);725if (getIntegState()) out.set(6, true);726727return out;728}729730// Only called on acceptor side. On the initiator side, most flags731// are already set at request. For those that might get chanegd,732// state from mech below is used.733private void setContextFlags() {734735if (mechContext != null) {736// default for cred delegation is false737if (mechContext.getCredDelegState()) {738credDelegState = true;739}740// default for the following are true741if (!mechContext.getMutualAuthState()) {742mutualAuthState = false;743}744if (!mechContext.getReplayDetState()) {745replayDetState = false;746}747if (!mechContext.getSequenceDetState()) {748sequenceDetState = false;749}750if (!mechContext.getIntegState()) {751integState = false;752}753if (!mechContext.getConfState()) {754confState = false;755}756}757}758759/**760* generate MIC on mechList. Not used at the moment.761*/762/*private byte[] generateMechListMIC(byte[] mechTypes)763throws GSSException {764765// sanity check the required input766if (mechTypes == null) {767if (DEBUG) {768System.out.println("SpNegoContext: no MIC token included");769}770return null;771}772773// check if mechanism supports integrity774if (!mechContext.getIntegState()) {775if (DEBUG) {776System.out.println("SpNegoContext: no MIC token included" +777" - mechanism does not support integrity");778}779return null;780}781782// compute MIC on DER encoded mechanism list783byte[] mic = null;784try {785MessageProp prop = new MessageProp(0, true);786mic = getMIC(mechTypes, 0, mechTypes.length, prop);787if (DEBUG) {788System.out.println("SpNegoContext: getMIC = " +789SpNegoToken.getHexBytes(mic));790}791} catch (GSSException e) {792mic = null;793if (DEBUG) {794System.out.println("SpNegoContext: no MIC token included" +795" - getMIC failed : " + e.getMessage());796}797}798return mic;799}*/800801/**802* verify MIC on MechList803*/804private boolean verifyMechListMIC(byte[] mechTypes, byte[] token)805throws GSSException {806807// sanity check the input808if (token == null) {809if (DEBUG) {810System.out.println("SpNegoContext: no MIC token validation");811}812return true;813}814815// check if mechanism supports integrity816if (!mechContext.getIntegState()) {817if (DEBUG) {818System.out.println("SpNegoContext: no MIC token validation" +819" - mechanism does not support integrity");820}821return true;822}823824// now verify the token825boolean valid = false;826try {827MessageProp prop = new MessageProp(0, true);828verifyMIC(token, 0, token.length, mechTypes,8290, mechTypes.length, prop);830valid = true;831} catch (GSSException e) {832valid = false;833if (DEBUG) {834System.out.println("SpNegoContext: MIC validation failed! " +835e.getMessage());836}837}838return valid;839}840841/**842* call gss_init_sec_context for the corresponding underlying mechanism843*/844private byte[] GSS_initSecContext(byte[] token) throws GSSException {845byte[] tok = null;846847if (mechContext == null) {848// initialize mech context849GSSName serverName =850factory.manager.createName(peerName.toString(),851peerName.getStringNameType(), internal_mech);852GSSCredential cred = null;853if (myCred != null) {854// create context with provided credential855cred = new GSSCredentialImpl(factory.manager,856myCred.getInternalCred());857}858mechContext =859factory.manager.createContext(serverName,860internal_mech, cred, GSSContext.DEFAULT_LIFETIME);861mechContext.requestConf(confState);862mechContext.requestInteg(integState);863mechContext.requestCredDeleg(credDelegState);864mechContext.requestMutualAuth(mutualAuthState);865mechContext.requestReplayDet(replayDetState);866mechContext.requestSequenceDet(sequenceDetState);867if (mechContext instanceof ExtendedGSSContext) {868((ExtendedGSSContext)mechContext).requestDelegPolicy(869delegPolicyState);870}871}872873// pass token874if (token != null) {875tok = token;876} else {877tok = new byte[0];878}879880// pass token to mechanism initSecContext881byte[] init_token = mechContext.initSecContext(tok, 0, tok.length);882883return init_token;884}885886/**887* call gss_accept_sec_context for the corresponding underlying mechanism888*/889private byte[] GSS_acceptSecContext(byte[] token) throws GSSException {890891if (mechContext == null) {892// initialize mech context893GSSCredential cred = null;894if (myCred != null) {895// create context with provided credential896cred = new GSSCredentialImpl(factory.manager,897myCred.getInternalCred());898}899mechContext =900factory.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}11321133public final void wrap(InputStream is, OutputStream os,1134MessageProp msgProp) throws GSSException {1135if (mechContext != null) {1136mechContext.wrap(is, os, msgProp);1137} else {1138throw new GSSException(GSSException.NO_CONTEXT, -1,1139"Wrap called in invalid state!");1140}1141}11421143public final byte[] unwrap(byte inBuf[], int offset, int len,1144MessageProp msgProp)1145throws GSSException {1146if (mechContext != null) {1147return mechContext.unwrap(inBuf, offset, len, msgProp);1148} else {1149throw new GSSException(GSSException.NO_CONTEXT, -1,1150"UnWrap called in invalid state!");1151}1152}11531154public final void unwrap(InputStream is, OutputStream os,1155MessageProp msgProp) throws GSSException {1156if (mechContext != null) {1157mechContext.unwrap(is, os, msgProp);1158} else {1159throw new GSSException(GSSException.NO_CONTEXT, -1,1160"UnWrap called in invalid state!");1161}1162}11631164public final byte[] getMIC(byte []inMsg, int offset, int len,1165MessageProp msgProp)1166throws GSSException {1167if (mechContext != null) {1168return mechContext.getMIC(inMsg, offset, len, msgProp);1169} else {1170throw new GSSException(GSSException.NO_CONTEXT, -1,1171"getMIC called in invalid state!");1172}1173}11741175public final void getMIC(InputStream is, OutputStream os,1176MessageProp msgProp) throws GSSException {1177if (mechContext != null) {1178mechContext.getMIC(is, os, msgProp);1179} else {1180throw new GSSException(GSSException.NO_CONTEXT, -1,1181"getMIC called in invalid state!");1182}1183}11841185public final void verifyMIC(byte []inTok, int tokOffset, int tokLen,1186byte[] inMsg, int msgOffset, int msgLen,1187MessageProp msgProp)1188throws GSSException {1189if (mechContext != null) {1190mechContext.verifyMIC(inTok, tokOffset, tokLen, inMsg, msgOffset,1191msgLen, msgProp);1192} else {1193throw new GSSException(GSSException.NO_CONTEXT, -1,1194"verifyMIC called in invalid state!");1195}1196}11971198public final void verifyMIC(InputStream is, InputStream msgStr,1199MessageProp msgProp) throws GSSException {1200if (mechContext != null) {1201mechContext.verifyMIC(is, msgStr, msgProp);1202} else {1203throw new GSSException(GSSException.NO_CONTEXT, -1,1204"verifyMIC called in invalid state!");1205}1206}12071208private static String printState(int state) {1209switch (state) {1210case STATE_NEW:1211return ("STATE_NEW");1212case STATE_IN_PROCESS:1213return ("STATE_IN_PROCESS");1214case STATE_DONE:1215return ("STATE_DONE");1216case STATE_DELETED:1217return ("STATE_DELETED");1218default:1219return ("Unknown state " + state);1220}1221}12221223/**1224* Retrieve attribute of the context for {@code type}.1225*/1226public Object inquireSecContext(InquireType type)1227throws GSSException {1228if (mechContext == null) {1229throw new GSSException(GSSException.NO_CONTEXT, -1,1230"Underlying mech not established.");1231}1232if (mechContext instanceof ExtendedGSSContext) {1233return ((ExtendedGSSContext)mechContext).inquireSecContext(type);1234} else {1235throw new GSSException(GSSException.BAD_MECH, -1,1236"inquireSecContext not supported by underlying mech.");1237}1238}1239}1240124112421243