Path: blob/master/src/java.security.jgss/share/classes/sun/security/jgss/GSSContextImpl.java
41159 views
/*1* Copyright (c) 2000, 2020, 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;2627import org.ietf.jgss.*;28import sun.security.jgss.spi.*;29import sun.security.util.ObjectIdentifier;30import java.io.InputStream;31import java.io.OutputStream;32import java.io.ByteArrayInputStream;33import java.io.ByteArrayOutputStream;34import java.io.IOException;35import java.lang.reflect.Field;36import java.lang.reflect.Modifier;3738/**39* This class represents the JGSS security context and its associated40* operations. JGSS security contexts are established between41* peers using locally established credentials. Multiple contexts42* may exist simultaneously between a pair of peers, using the same43* or different set of credentials. The JGSS is independent of44* the underlying transport protocols and depends on its callers to45* transport the tokens between peers.46* <p>47* The context object can be thought of as having 3 implicit states:48* before it is established, during its context establishment, and49* after a fully established context exists.50* <p>51* Before the context establishment phase is initiated, the context52* initiator may request specific characteristics desired of the53* established context. These can be set using the set methods. After the54* context is established, the caller can check the actual characteristic55* and services offered by the context using the query methods.56* <p>57* The context establishment phase begins with the first call to the58* initSecContext method by the context initiator. During this phase the59* initSecContext and acceptSecContext methods will produce GSS-API60* authentication tokens which the calling application needs to send to its61* peer. The initSecContext and acceptSecContext methods may62* return a CONTINUE_NEEDED code which indicates that a token is needed63* from its peer in order to continue the context establishment phase. A64* return code of COMPLETE signals that the local end of the context is65* established. This may still require that a token be sent to the peer,66* depending if one is produced by GSS-API. The isEstablished method can67* also be used to determine if the local end of the context has been68* fully established. During the context establishment phase, the69* isProtReady method may be called to determine if the context can be70* used for the per-message operations. This allows implementation to71* use per-message operations on contexts which aren't fully established.72* <p>73* After the context has been established or the isProtReady method74* returns "true", the query routines can be invoked to determine the actual75* characteristics and services of the established context. The76* application can also start using the per-message methods of wrap and77* getMIC to obtain cryptographic operations on application supplied data.78* <p>79* When the context is no longer needed, the application should call80* dispose to release any system resources the context may be using.81* <DL><DT><B>RFC 2078</b>82* <DD>This class corresponds to the context level calls together with83* the per message calls of RFC 2078. The gss_init_sec_context and84* gss_accept_sec_context calls have been made simpler by only taking85* required parameters. The context can have its properties set before86* the first call to initSecContext. The supplementary status codes for the87* per-message operations are returned in an instance of the MessageProp88* class, which is used as an argument in these calls.</dl>89*/90public class GSSContextImpl implements GSSContext {9192private GSSManagerImpl gssManager;93private boolean initiator;9495// private flags for the context state96private static final int PRE_INIT = 1;97private static final int IN_PROGRESS = 2;98private static final int READY = 3;99private static final int DELETED = 4;100101// instance variables102private int currentState = PRE_INIT;103104private GSSContextSpi mechCtxt = null;105private Oid mechOid = null;106private ObjectIdentifier objId = null;107108private GSSCredentialImpl myCred = null;109110private GSSNameImpl srcName = null;111private GSSNameImpl targName = null;112113private int reqLifetime = INDEFINITE_LIFETIME;114private ChannelBinding channelBindings = null;115116private boolean reqConfState = true;117private boolean reqIntegState = true;118private boolean reqMutualAuthState = true;119private boolean reqReplayDetState = true;120private boolean reqSequenceDetState = true;121private boolean reqCredDelegState = false;122private boolean reqAnonState = false;123private boolean reqDelegPolicyState = false;124125public GSSContextImpl() {126// Useless127}128129// Used by new ExtendedGSSContext.ExtendedGSSContextImpl(ctxt)130protected GSSContextImpl(GSSContextImpl src) {131for (Field f: GSSContextImpl.class.getDeclaredFields()) {132if (!Modifier.isStatic(f.getModifiers())) {133try {134f.set(this, f.get(src));135} catch (Exception e) {136throw new RuntimeException(e);137}138}139}140}141/**142* Creates a GSSContextImp on the context initiator's side.143*/144public GSSContextImpl(GSSManagerImpl gssManager, GSSName peer, Oid mech,145GSSCredential myCred, int lifetime)146throws GSSException {147if ((peer == null) || !(peer instanceof GSSNameImpl)) {148throw new GSSException(GSSException.BAD_NAME);149}150if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;151152this.gssManager = gssManager;153this.myCred = (GSSCredentialImpl) myCred; // XXX Check first154reqLifetime = lifetime;155targName = (GSSNameImpl)peer;156this.mechOid = mech;157initiator = true;158}159160/**161* Creates a GSSContextImpl on the context acceptor's side.162*/163public GSSContextImpl(GSSManagerImpl gssManager, GSSCredential myCred)164throws GSSException {165this.gssManager = gssManager;166this.myCred = (GSSCredentialImpl) myCred; // XXX Check first167initiator = false;168}169170/**171* Creates a GSSContextImpl out of a previously exported172* GSSContext.173*174* @see #isTransferable175*/176public GSSContextImpl(GSSManagerImpl gssManager, byte[] interProcessToken)177throws GSSException {178this.gssManager = gssManager;179mechCtxt = gssManager.getMechanismContext(interProcessToken);180initiator = mechCtxt.isInitiator();181this.mechOid = mechCtxt.getMech();182}183184public byte[] initSecContext(byte inputBuf[], int offset, int len)185throws GSSException {186/*187* Size of ByteArrayOutputStream will double each time that extra188* bytes are to be written. Usually, without delegation, a GSS189* initial token containing the Kerberos AP-REQ is between 400 and190* 600 bytes.191*/192ByteArrayOutputStream bos = new ByteArrayOutputStream(600);193ByteArrayInputStream bin =194new ByteArrayInputStream(inputBuf, offset, len);195int size = initSecContext(bin, bos);196return (size == 0? null : bos.toByteArray());197}198199@Deprecated(since="11")200public int initSecContext(InputStream inStream,201OutputStream outStream) throws GSSException {202203if (mechCtxt != null && currentState != IN_PROGRESS) {204throw new GSSExceptionImpl(GSSException.FAILURE,205"Illegal call to initSecContext");206}207208GSSHeader gssHeader = null;209int inTokenLen = -1;210GSSCredentialSpi credElement = null;211boolean firstToken = false;212213try {214if (mechCtxt == null) {215if (myCred != null) {216try {217credElement = myCred.getElement(mechOid, true);218} catch (GSSException ge) {219if (GSSUtil.isSpNegoMech(mechOid) &&220ge.getMajor() == GSSException.NO_CRED) {221credElement = myCred.getElement222(myCred.getMechs()[0], true);223} else {224throw ge;225}226}227}228GSSNameSpi nameElement = targName.getElement(mechOid);229mechCtxt = gssManager.getMechanismContext(nameElement,230credElement,231reqLifetime,232mechOid);233mechCtxt.requestConf(reqConfState);234mechCtxt.requestInteg(reqIntegState);235mechCtxt.requestCredDeleg(reqCredDelegState);236mechCtxt.requestMutualAuth(reqMutualAuthState);237mechCtxt.requestReplayDet(reqReplayDetState);238mechCtxt.requestSequenceDet(reqSequenceDetState);239mechCtxt.requestAnonymity(reqAnonState);240mechCtxt.setChannelBinding(channelBindings);241mechCtxt.requestDelegPolicy(reqDelegPolicyState);242243objId = ObjectIdentifier.of(mechOid.toString());244245currentState = IN_PROGRESS;246firstToken = true;247} else {248if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||249GSSUtil.isSpNegoMech(mechOid)) {250// do not parse GSS header for native provider or SPNEGO251// mech252} else {253// parse GSS header254gssHeader = new GSSHeader(inStream);255if (!gssHeader.getOid().equals(objId))256throw new GSSExceptionImpl257(GSSException.DEFECTIVE_TOKEN,258"Mechanism not equal to " +259mechOid.toString() +260" in initSecContext token");261inTokenLen = gssHeader.getMechTokenLength();262}263}264265byte[] obuf = mechCtxt.initSecContext(inStream, inTokenLen);266267int retVal = 0;268269if (obuf != null) {270retVal = obuf.length;271if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||272(!firstToken && GSSUtil.isSpNegoMech(mechOid))) {273// do not add GSS header for native provider or SPNEGO274// except for the first SPNEGO token275} else {276// add GSS header277gssHeader = new GSSHeader(objId, obuf.length);278retVal += gssHeader.encode(outStream);279}280outStream.write(obuf);281}282283if (mechCtxt.isEstablished())284currentState = READY;285286return retVal;287288} catch (IOException e) {289throw new GSSExceptionImpl(GSSException.DEFECTIVE_TOKEN,290e.getMessage());291}292}293294public byte[] acceptSecContext(byte inTok[], int offset, int len)295throws GSSException {296297/*298* Usually initial GSS token containing a Kerberos AP-REP is less299* than 100 bytes.300*/301ByteArrayOutputStream bos = new ByteArrayOutputStream(100);302acceptSecContext(new ByteArrayInputStream(inTok, offset, len),303bos);304byte[] out = bos.toByteArray();305return (out.length == 0) ? null : out;306}307308@Deprecated(since="11")309public void acceptSecContext(InputStream inStream,310OutputStream outStream) throws GSSException {311312if (mechCtxt != null && currentState != IN_PROGRESS) {313throw new GSSExceptionImpl(GSSException.FAILURE,314"Illegal call to acceptSecContext");315}316317GSSHeader gssHeader = null;318int inTokenLen = -1;319GSSCredentialSpi credElement = null;320321try {322if (mechCtxt == null) {323// mechOid will be null for an acceptor's context324gssHeader = new GSSHeader(inStream);325inTokenLen = gssHeader.getMechTokenLength();326327/*328* Convert ObjectIdentifier to Oid329*/330objId = gssHeader.getOid();331mechOid = new Oid(objId.toString());332// System.out.println("Entered GSSContextImpl.acceptSecContext"333// + " with mechanism = " + mechOid);334if (myCred != null) {335credElement = myCred.getElement(mechOid, false);336}337338mechCtxt = gssManager.getMechanismContext(credElement,339mechOid);340mechCtxt.setChannelBinding(channelBindings);341342currentState = IN_PROGRESS;343} else {344if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||345(GSSUtil.isSpNegoMech(mechOid))) {346// do not parse GSS header for native provider and SPNEGO347} else {348// parse GSS Header349gssHeader = new GSSHeader(inStream);350if (!gssHeader.getOid().equals(objId))351throw new GSSExceptionImpl352(GSSException.DEFECTIVE_TOKEN,353"Mechanism not equal to " +354mechOid.toString() +355" in acceptSecContext token");356inTokenLen = gssHeader.getMechTokenLength();357}358}359360byte[] obuf = mechCtxt.acceptSecContext(inStream, inTokenLen);361362if (obuf != null) {363int retVal = obuf.length;364if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||365(GSSUtil.isSpNegoMech(mechOid))) {366// do not add GSS header for native provider and SPNEGO367} else {368// add GSS header369gssHeader = new GSSHeader(objId, obuf.length);370retVal += gssHeader.encode(outStream);371}372outStream.write(obuf);373}374375if (mechCtxt.isEstablished()) {376currentState = READY;377}378} catch (IOException e) {379throw new GSSExceptionImpl(GSSException.DEFECTIVE_TOKEN,380e.getMessage());381}382}383384public boolean isEstablished() {385if (mechCtxt == null)386return false;387else388return (currentState == READY);389}390391public int getWrapSizeLimit(int qop, boolean confReq,392int maxTokenSize) throws GSSException {393if (mechCtxt != null)394return mechCtxt.getWrapSizeLimit(qop, confReq, maxTokenSize);395else396throw new GSSExceptionImpl(GSSException.NO_CONTEXT,397"No mechanism context yet!");398}399400public byte[] wrap(byte inBuf[], int offset, int len,401MessageProp msgProp) throws GSSException {402if (mechCtxt != null)403return mechCtxt.wrap(inBuf, offset, len, msgProp);404else405throw new GSSExceptionImpl(GSSException.NO_CONTEXT,406"No mechanism context yet!");407}408409@Deprecated(since="11")410public void wrap(InputStream inStream, OutputStream outStream,411MessageProp msgProp) throws GSSException {412if (mechCtxt != null)413mechCtxt.wrap(inStream, outStream, msgProp);414else415throw new GSSExceptionImpl(GSSException.NO_CONTEXT,416"No mechanism context yet!");417}418419public byte [] unwrap(byte[] inBuf, int offset, int len,420MessageProp msgProp) throws GSSException {421if (mechCtxt != null)422return mechCtxt.unwrap(inBuf, offset, len, msgProp);423else424throw new GSSExceptionImpl(GSSException.NO_CONTEXT,425"No mechanism context yet!");426}427428@Deprecated(since="11")429public void unwrap(InputStream inStream, OutputStream outStream,430MessageProp msgProp) throws GSSException {431if (mechCtxt != null)432mechCtxt.unwrap(inStream, outStream, msgProp);433else434throw new GSSExceptionImpl(GSSException.NO_CONTEXT,435"No mechanism context yet!");436}437438public byte[] getMIC(byte []inMsg, int offset, int len,439MessageProp msgProp) throws GSSException {440if (mechCtxt != null)441return mechCtxt.getMIC(inMsg, offset, len, msgProp);442else443throw new GSSExceptionImpl(GSSException.NO_CONTEXT,444"No mechanism context yet!");445}446447@Deprecated(since="11")448public void getMIC(InputStream inStream, OutputStream outStream,449MessageProp msgProp) throws GSSException {450if (mechCtxt != null)451mechCtxt.getMIC(inStream, outStream, msgProp);452else453throw new GSSExceptionImpl(GSSException.NO_CONTEXT,454"No mechanism context yet!");455}456457public void verifyMIC(byte[] inTok, int tokOffset, int tokLen,458byte[] inMsg, int msgOffset, int msgLen,459MessageProp msgProp) throws GSSException {460if (mechCtxt != null)461mechCtxt.verifyMIC(inTok, tokOffset, tokLen,462inMsg, msgOffset, msgLen, msgProp);463else464throw new GSSExceptionImpl(GSSException.NO_CONTEXT,465"No mechanism context yet!");466}467468@Deprecated(since="11")469public void verifyMIC(InputStream tokStream, InputStream msgStream,470MessageProp msgProp) throws GSSException {471if (mechCtxt != null)472mechCtxt.verifyMIC(tokStream, msgStream, msgProp);473else474throw new GSSExceptionImpl(GSSException.NO_CONTEXT,475"No mechanism context yet!");476}477478public byte[] export() throws GSSException {479// Defaults to null to match old behavior480byte[] result = null;481// Only allow context export from native provider since JGSS482// still has not defined its own interprocess token format483if (mechCtxt.isTransferable() &&484mechCtxt.getProvider().getName().equals("SunNativeGSS")) {485result = mechCtxt.export();486}487return result;488}489490public void requestMutualAuth(boolean state) throws GSSException {491if (mechCtxt == null && initiator)492reqMutualAuthState = state;493}494495public void requestReplayDet(boolean state) throws GSSException {496if (mechCtxt == null && initiator)497reqReplayDetState = state;498}499500public void requestSequenceDet(boolean state) throws GSSException {501if (mechCtxt == null && initiator)502reqSequenceDetState = state;503}504505public void requestCredDeleg(boolean state) throws GSSException {506if (mechCtxt == null && initiator)507reqCredDelegState = state;508}509510public void requestAnonymity(boolean state) throws GSSException {511if (mechCtxt == null && initiator)512reqAnonState = state;513}514515public void requestConf(boolean state) throws GSSException {516if (mechCtxt == null && initiator)517reqConfState = state;518}519520public void requestInteg(boolean state) throws GSSException {521if (mechCtxt == null && initiator)522reqIntegState = state;523}524525public void requestLifetime(int lifetime) throws GSSException {526if (mechCtxt == null && initiator)527reqLifetime = lifetime;528}529530public void setChannelBinding(ChannelBinding channelBindings)531throws GSSException {532533if (mechCtxt == null)534this.channelBindings = channelBindings;535536}537538public boolean getCredDelegState() {539if (mechCtxt != null)540return mechCtxt.getCredDelegState();541else542return reqCredDelegState;543}544545public boolean getMutualAuthState() {546if (mechCtxt != null)547return mechCtxt.getMutualAuthState();548else549return reqMutualAuthState;550}551552public boolean getReplayDetState() {553if (mechCtxt != null)554return mechCtxt.getReplayDetState();555else556return reqReplayDetState;557}558559public boolean getSequenceDetState() {560if (mechCtxt != null)561return mechCtxt.getSequenceDetState();562else563return reqSequenceDetState;564}565566public boolean getAnonymityState() {567if (mechCtxt != null)568return mechCtxt.getAnonymityState();569else570return reqAnonState;571}572573public boolean isTransferable() throws GSSException {574if (mechCtxt != null)575return mechCtxt.isTransferable();576else577return false;578}579580public boolean isProtReady() {581if (mechCtxt != null)582return mechCtxt.isProtReady();583else584return false;585}586587public boolean getConfState() {588if (mechCtxt != null)589return mechCtxt.getConfState();590else591return reqConfState;592}593594public boolean getIntegState() {595if (mechCtxt != null)596return mechCtxt.getIntegState();597else598return reqIntegState;599}600601public int getLifetime() {602if (mechCtxt != null)603return mechCtxt.getLifetime();604else605return reqLifetime;606}607608public GSSName getSrcName() throws GSSException {609if (srcName == null) {610srcName = GSSNameImpl.wrapElement611(gssManager, mechCtxt.getSrcName());612}613return srcName;614}615616public GSSName getTargName() throws GSSException {617if (targName == null) {618targName = GSSNameImpl.wrapElement619(gssManager, mechCtxt.getTargName());620}621return targName;622}623624public Oid getMech() throws GSSException {625if (mechCtxt != null) {626return mechCtxt.getMech();627}628return mechOid;629}630631public GSSCredential getDelegCred() throws GSSException {632633if (mechCtxt == null)634throw new GSSExceptionImpl(GSSException.NO_CONTEXT,635"No mechanism context yet!");636GSSCredentialSpi delCredElement = mechCtxt.getDelegCred();637return (delCredElement == null ?638null : GSSManagerImpl.wrap(new GSSCredentialImpl(gssManager, delCredElement)));639}640641public boolean isInitiator() throws GSSException {642return initiator;643}644645public void dispose() throws GSSException {646currentState = DELETED;647if (mechCtxt != null) {648mechCtxt.dispose();649mechCtxt = null;650}651myCred = null;652srcName = null;653targName = null;654}655656// ExtendedGSSContext methods:657658public Object inquireSecContext(String type) throws GSSException {659if (mechCtxt == null) {660throw new GSSException(GSSException.NO_CONTEXT);661}662return mechCtxt.inquireSecContext(type);663}664665public void requestDelegPolicy(boolean state) throws GSSException {666if (mechCtxt == null && initiator)667reqDelegPolicyState = state;668}669670public boolean getDelegPolicyState() {671if (mechCtxt != null)672return mechCtxt.getDelegPolicyState();673else674return reqDelegPolicyState;675}676}677678679