Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/jgss/krb5/Krb5Context.java
38922 views
/*1* Copyright (c) 2000, 2019, 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.krb5;2627import com.sun.security.jgss.InquireType;28import org.ietf.jgss.*;29import sun.misc.HexDumpEncoder;30import sun.security.jgss.GSSUtil;31import sun.security.jgss.GSSCaller;32import sun.security.jgss.spi.*;33import sun.security.jgss.TokenTracker;34import sun.security.krb5.*;35import java.io.InputStream;36import java.io.OutputStream;37import java.io.IOException;38import java.security.Provider;39import java.security.AccessController;40import java.security.AccessControlContext;41import java.security.Key;42import java.security.PrivilegedExceptionAction;43import java.security.PrivilegedActionException;44import javax.crypto.Cipher;45import javax.security.auth.Subject;46import javax.security.auth.kerberos.*;47import sun.security.krb5.internal.Ticket;4849/**50* Implements the mechanism specific context class for the Kerberos v551* GSS-API mechanism.52*53* @author Mayank Upadhyay54* @author Ram Marti55* @since 1.456*/57class Krb5Context implements GSSContextSpi {5859/*60* The different states that this context can be in.61*/6263private static final int STATE_NEW = 1;64private static final int STATE_IN_PROCESS = 2;65private static final int STATE_DONE = 3;66private static final int STATE_DELETED = 4;6768private int state = STATE_NEW;6970public static final int SESSION_KEY = 0;71public static final int INITIATOR_SUBKEY = 1;72public static final int ACCEPTOR_SUBKEY = 2;7374/*75* Optional features that the application can set and their default76* values.77*/7879private boolean credDelegState = false; // now only useful at client80private boolean mutualAuthState = true;81private boolean replayDetState = true;82private boolean sequenceDetState = true;83private boolean confState = true;84private boolean integState = true;85private boolean delegPolicyState = false;8687private boolean isConstrainedDelegationTried = false;8889private int mySeqNumber;90private int peerSeqNumber;91private int keySrc;92private TokenTracker peerTokenTracker;9394private CipherHelper cipherHelper = null;9596/*97* Separate locks for the sequence numbers allow the application to98* receive tokens at the same time that it is sending tokens. Note99* that the application must synchronize the generation and100* transmission of tokens such that tokens are processed in the same101* order that they are generated. This is important when sequence102* checking of per-message tokens is enabled.103*/104105private Object mySeqNumberLock = new Object();106private Object peerSeqNumberLock = new Object();107108private EncryptionKey key;109private Krb5NameElement myName;110private Krb5NameElement peerName;111private int lifetime;112private boolean initiator;113private ChannelBinding channelBinding;114115private Krb5CredElement myCred;116private Krb5CredElement delegatedCred; // Set only on acceptor side117118// XXX See if the required info from these can be extracted and119// stored elsewhere120private Credentials serviceCreds;121private KrbApReq apReq;122Ticket serviceTicket;123final private GSSCaller caller;124private static final boolean DEBUG = Krb5Util.DEBUG;125126/**127* Constructor for Krb5Context to be called on the context initiator's128* side.129*/130Krb5Context(GSSCaller caller, Krb5NameElement peerName, Krb5CredElement myCred,131int lifetime)132throws GSSException {133134if (peerName == null)135throw new IllegalArgumentException("Cannot have null peer name");136137this.caller = caller;138this.peerName = peerName;139this.myCred = myCred;140this.lifetime = lifetime;141this.initiator = true;142}143144/**145* Constructor for Krb5Context to be called on the context acceptor's146* side.147*/148Krb5Context(GSSCaller caller, Krb5CredElement myCred)149throws GSSException {150this.caller = caller;151this.myCred = myCred;152this.initiator = false;153}154155/**156* Constructor for Krb5Context to import a previously exported context.157*/158public Krb5Context(GSSCaller caller, byte [] interProcessToken)159throws GSSException {160throw new GSSException(GSSException.UNAVAILABLE,161-1, "GSS Import Context not available");162}163164/**165* Method to determine if the context can be exported and then166* re-imported.167*/168public final boolean isTransferable() throws GSSException {169return false;170}171172/**173* The lifetime remaining for this context.174*/175public final int getLifetime() {176// XXX Return service ticket lifetime177return GSSContext.INDEFINITE_LIFETIME;178}179180/*181* Methods that may be invoked by the GSS framework in response182* to an application request for setting/getting these183* properties.184*185* These can only be called on the initiator side.186*187* Notice that an application can only request these188* properties. The mechanism may or may not support them. The189* application must make getXXX calls after context establishment190* to see if the mechanism implementations on both sides support191* these features. requestAnonymity is an exception where the192* application will want to call getAnonymityState prior to sending any193* GSS token during context establishment.194*195* Also note that the requests can only be placed before context196* establishment starts. i.e. when state is STATE_NEW197*/198199/**200* Requests the desired lifetime. Can only be used on the context201* initiator's side.202*/203public void requestLifetime(int lifetime) throws GSSException {204if (state == STATE_NEW && isInitiator())205this.lifetime = lifetime;206}207208/**209* Requests that confidentiality be available.210*/211public final void requestConf(boolean value) throws GSSException {212if (state == STATE_NEW && isInitiator())213confState = value;214}215216/**217* Is confidentiality available?218*/219public final boolean getConfState() {220return confState;221}222223/**224* Requests that integrity be available.225*/226public final void requestInteg(boolean value) throws GSSException {227if (state == STATE_NEW && isInitiator())228integState = value;229}230231/**232* Is integrity available?233*/234public final boolean getIntegState() {235return integState;236}237238/**239* Requests that credential delegation be done during context240* establishment.241*/242public final void requestCredDeleg(boolean value) throws GSSException {243if (state == STATE_NEW && isInitiator()) {244if (myCred == null || !(myCred instanceof Krb5ProxyCredential)) {245credDelegState = value;246}247}248}249250/**251* Is credential delegation enabled?252*/253public final boolean getCredDelegState() {254if (isInitiator()) {255return credDelegState;256} else {257// Server side deleg state is not flagged by credDelegState.258// It can use constrained delegation.259tryConstrainedDelegation();260return delegatedCred != null;261}262}263264/**265* Requests that mutual authentication be done during context266* establishment. Since this is fromm the client's perspective, it267* essentially requests that the server be authenticated.268*/269public final void requestMutualAuth(boolean value) throws GSSException {270if (state == STATE_NEW && isInitiator()) {271mutualAuthState = value;272}273}274275/**276* Is mutual authentication enabled? Since this is from the client's277* perspective, it essentially meas that the server is being278* authenticated.279*/280public final boolean getMutualAuthState() {281return mutualAuthState;282}283284/**285* Requests that replay detection be done on the GSS wrap and MIC286* tokens.287*/288public final void requestReplayDet(boolean value) throws GSSException {289if (state == STATE_NEW && isInitiator())290replayDetState = value;291}292293/**294* Is replay detection enabled on the GSS wrap and MIC tokens?295* We enable replay detection if sequence checking is enabled.296*/297public final boolean getReplayDetState() {298return replayDetState || sequenceDetState;299}300301/**302* Requests that sequence checking be done on the GSS wrap and MIC303* tokens.304*/305public final void requestSequenceDet(boolean value) throws GSSException {306if (state == STATE_NEW && isInitiator())307sequenceDetState = value;308}309310/**311* Is sequence checking enabled on the GSS Wrap and MIC tokens?312* We enable sequence checking if replay detection is enabled.313*/314public final boolean getSequenceDetState() {315return sequenceDetState || replayDetState;316}317318/**319* Requests that the deleg policy be respected.320*/321public final void requestDelegPolicy(boolean value) {322if (state == STATE_NEW && isInitiator())323delegPolicyState = value;324}325326/**327* Is deleg policy respected?328*/329public final boolean getDelegPolicyState() {330return delegPolicyState;331}332333/*334* Anonymity is a little different in that after an application335* requests anonymity it will want to know whether the mechanism336* can support it or not, prior to sending any tokens across for337* context establishment. Since this is from the initiator's338* perspective, it essentially requests that the initiator be339* anonymous.340*/341342public final void requestAnonymity(boolean value) throws GSSException {343// Ignore silently. Application will check back with344// getAnonymityState.345}346347// RFC 2853 actually calls for this to be called after context348// establishment to get the right answer, but that is349// incorrect. The application may not want to send over any350// tokens if anonymity is not available.351public final boolean getAnonymityState() {352return false;353}354355/*356* Package private methods invoked by other Krb5 plugin classes.357*/358359/**360* Get the context specific DESCipher instance, invoked in361* MessageToken.init()362*/363final CipherHelper getCipherHelper(EncryptionKey ckey) throws GSSException {364EncryptionKey cipherKey = null;365if (cipherHelper == null) {366cipherKey = (getKey() == null) ? ckey: getKey();367cipherHelper = new CipherHelper(cipherKey);368}369return cipherHelper;370}371372final int incrementMySequenceNumber() {373int retVal;374synchronized (mySeqNumberLock) {375retVal = mySeqNumber;376mySeqNumber = retVal + 1;377}378return retVal;379}380381final void resetMySequenceNumber(int seqNumber) {382if (DEBUG) {383System.out.println("Krb5Context setting mySeqNumber to: "384+ seqNumber);385}386synchronized (mySeqNumberLock) {387mySeqNumber = seqNumber;388}389}390391final void resetPeerSequenceNumber(int seqNumber) {392if (DEBUG) {393System.out.println("Krb5Context setting peerSeqNumber to: "394+ seqNumber);395}396synchronized (peerSeqNumberLock) {397peerSeqNumber = seqNumber;398peerTokenTracker = new TokenTracker(peerSeqNumber);399}400}401402final void setKey(int keySrc, EncryptionKey key) throws GSSException {403this.key = key;404this.keySrc = keySrc;405// %%% to do: should clear old cipherHelper first406cipherHelper = new CipherHelper(key); // Need to use new key407}408409public final int getKeySrc() {410return keySrc;411}412413private final EncryptionKey getKey() {414return key;415}416417/**418* Called on the acceptor side to store the delegated credentials419* received in the AcceptSecContextToken.420*/421final void setDelegCred(Krb5CredElement delegatedCred) {422this.delegatedCred = delegatedCred;423}424425/*426* While the application can only request the following features,427* other classes in the package can call the actual set methods428* for them. They are called as context establishment tokens are429* received on an acceptor side and the context feature list that430* the initiator wants becomes known.431*/432433/*434* This method is also called by InitialToken.OverloadedChecksum if the435* TGT is not forwardable and the user requested delegation.436*/437final void setCredDelegState(boolean state) {438credDelegState = state;439}440441final void setMutualAuthState(boolean state) {442mutualAuthState = state;443}444445final void setReplayDetState(boolean state) {446replayDetState = state;447}448449final void setSequenceDetState(boolean state) {450sequenceDetState = state;451}452453final void setConfState(boolean state) {454confState = state;455}456457final void setIntegState(boolean state) {458integState = state;459}460461final void setDelegPolicyState(boolean state) {462delegPolicyState = state;463}464465/**466* Sets the channel bindings to be used during context467* establishment.468*/469public final void setChannelBinding(ChannelBinding channelBinding)470throws GSSException {471this.channelBinding = channelBinding;472}473474final ChannelBinding getChannelBinding() {475return channelBinding;476}477478/**479* Returns the mechanism oid.480*481* @return the Oid of this context482*/483public final Oid getMech() {484return (Krb5MechFactory.GSS_KRB5_MECH_OID);485}486487/**488* Returns the context initiator name.489*490* @return initiator name491* @exception GSSException492*/493public final GSSNameSpi getSrcName() throws GSSException {494return (isInitiator()? myName : peerName);495}496497/**498* Returns the context acceptor.499*500* @return context acceptor(target) name501* @exception GSSException502*/503public final GSSNameSpi getTargName() throws GSSException {504return (!isInitiator()? myName : peerName);505}506507/**508* Returns the delegated credential for the context. This509* is an optional feature of contexts which not all510* mechanisms will support. A context can be requested to511* support credential delegation by using the <b>CRED_DELEG</b>,512* or it can request for a constrained delegation.513* This is only valid on the acceptor side of the context.514* @return GSSCredentialSpi object for the delegated credential515* @exception GSSException516* @see GSSContext#getDelegCredState517*/518public final GSSCredentialSpi getDelegCred() throws GSSException {519if (state != STATE_IN_PROCESS && state != STATE_DONE)520throw new GSSException(GSSException.NO_CONTEXT);521if (isInitiator()) {522throw new GSSException(GSSException.NO_CRED);523}524tryConstrainedDelegation();525if (delegatedCred == null) {526throw new GSSException(GSSException.NO_CRED);527}528return delegatedCred;529}530531private void tryConstrainedDelegation() {532if (state != STATE_IN_PROCESS && state != STATE_DONE) {533return;534}535// We will only try constrained delegation once (if necessary).536if (!isConstrainedDelegationTried) {537if (delegatedCred == null) {538if (DEBUG) {539System.out.println(">>> Constrained deleg from " + caller);540}541// The constrained delegation part. The acceptor needs to have542// isInitiator=true in order to get a TGT, either earlier at543// logon stage, if useSubjectCredsOnly, or now.544try {545delegatedCred = new Krb5ProxyCredential(546Krb5InitCredential.getInstance(547GSSCaller.CALLER_ACCEPT, myName, lifetime),548peerName, serviceTicket);549} catch (GSSException gsse) {550// OK, delegatedCred is null then551}552}553isConstrainedDelegationTried = true;554}555}556/**557* Tests if this is the initiator side of the context.558*559* @return boolean indicating if this is initiator (true)560* or target (false)561*/562public final boolean isInitiator() {563return initiator;564}565566/**567* Tests if the context can be used for per-message service.568* Context may allow the calls to the per-message service569* functions before being fully established.570*571* @return boolean indicating if per-message methods can572* be called.573*/574public final boolean isProtReady() {575return (state == STATE_DONE);576}577578/**579* Initiator context establishment call. This method may be580* required to be called several times. A CONTINUE_NEEDED return581* call indicates that more calls are needed after the next token582* is received from the peer.583*584* @param is contains the token received from the peer. On the585* first call it will be ignored.586* @return any token required to be sent to the peer587* It is responsibility of the caller588* to send the token to its peer for processing.589* @exception GSSException590*/591public final byte[] initSecContext(InputStream is, int mechTokenSize)592throws GSSException {593594byte[] retVal = null;595InitialToken token = null;596int errorCode = GSSException.FAILURE;597if (DEBUG) {598System.out.println("Entered Krb5Context.initSecContext with " +599"state=" + printState(state));600}601if (!isInitiator()) {602throw new GSSException(GSSException.FAILURE, -1,603"initSecContext on an acceptor " +604"GSSContext");605}606607try {608if (state == STATE_NEW) {609state = STATE_IN_PROCESS;610611errorCode = GSSException.NO_CRED;612613if (myCred == null) {614myCred = Krb5InitCredential.getInstance(caller, myName,615GSSCredential.DEFAULT_LIFETIME);616myCred = Krb5ProxyCredential.tryImpersonation(617caller, (Krb5InitCredential)myCred);618} else if (!myCred.isInitiatorCredential()) {619throw new GSSException(errorCode, -1,620"No TGT available");621}622myName = (Krb5NameElement) myCred.getName();623Credentials tgt;624final Krb5ProxyCredential second;625if (myCred instanceof Krb5InitCredential) {626second = null;627tgt = ((Krb5InitCredential) myCred).getKrb5Credentials();628} else {629second = (Krb5ProxyCredential) myCred;630tgt = second.self.getKrb5Credentials();631}632633checkPermission(peerName.getKrb5PrincipalName().getName(),634"initiate");635/*636* If useSubjectCredsonly is true then637* we check whether we already have the ticket638* for this service in the Subject and reuse it639*/640641final AccessControlContext acc =642AccessController.getContext();643644if (GSSUtil.useSubjectCredsOnly(caller)) {645KerberosTicket kerbTicket = null;646try {647// get service ticket from caller's subject648kerbTicket = AccessController.doPrivileged(649new PrivilegedExceptionAction<KerberosTicket>() {650public KerberosTicket run() throws Exception {651// XXX to be cleaned652// highly consider just calling:653// Subject.getSubject654// SubjectComber.find655// instead of Krb5Util.getServiceTicket656return Krb5Util.getServiceTicket(657GSSCaller.CALLER_UNKNOWN,658// since it's useSubjectCredsOnly here,659// don't worry about the null660second == null ?661myName.getKrb5PrincipalName().getName():662second.getName().getKrb5PrincipalName().getName(),663peerName.getKrb5PrincipalName().getName(),664acc);665}});666} catch (PrivilegedActionException e) {667if (DEBUG) {668System.out.println("Attempt to obtain service"669+ " ticket from the subject failed!");670}671}672if (kerbTicket != null) {673if (DEBUG) {674System.out.println("Found service ticket in " +675"the subject" +676kerbTicket);677}678679// convert Ticket to serviceCreds680// XXX Should merge these two object types681// avoid converting back and forth682serviceCreds = Krb5Util.ticketToCreds(kerbTicket);683}684}685if (serviceCreds == null) {686// either we did not find the serviceCreds in the687// Subject or useSubjectCreds is false688if (DEBUG) {689System.out.println("Service ticket not found in " +690"the subject");691}692// Get Service ticket using the Kerberos protocols693if (second == null) {694serviceCreds = Credentials.acquireServiceCreds(695peerName.getKrb5PrincipalName().getName(),696tgt);697} else {698serviceCreds = Credentials.acquireS4U2proxyCreds(699peerName.getKrb5PrincipalName().getName(),700second.tkt,701second.getName().getKrb5PrincipalName(),702tgt);703}704if (GSSUtil.useSubjectCredsOnly(caller)) {705final Subject subject =706AccessController.doPrivileged(707new java.security.PrivilegedAction<Subject>() {708public Subject run() {709return (Subject.getSubject(acc));710}711});712if (subject != null &&713!subject.isReadOnly()) {714/*715* Store the service credentials as716* javax.security.auth.kerberos.KerberosTicket in717* the Subject. We could wait until the context is718* successfully established; however it is easier719* to do it here and there is no harm.720*/721final KerberosTicket kt =722Krb5Util.credsToTicket(serviceCreds);723AccessController.doPrivileged (724new java.security.PrivilegedAction<Void>() {725public Void run() {726subject.getPrivateCredentials().add(kt);727return null;728}729});730} else {731// log it for debugging purpose732if (DEBUG) {733System.out.println("Subject is " +734"readOnly;Kerberos Service "+735"ticket not stored");736}737}738}739}740741errorCode = GSSException.FAILURE;742token = new InitSecContextToken(this, tgt, serviceCreds);743apReq = ((InitSecContextToken)token).getKrbApReq();744retVal = token.encode();745myCred = null;746if (!getMutualAuthState()) {747state = STATE_DONE;748}749if (DEBUG) {750System.out.println("Created InitSecContextToken:\n"+751new HexDumpEncoder().encodeBuffer(retVal));752}753} else if (state == STATE_IN_PROCESS) {754// No need to write anything;755// just validate the incoming token756new AcceptSecContextToken(this, serviceCreds, apReq, is);757serviceCreds = null;758apReq = null;759state = STATE_DONE;760} else {761// XXX Use logging API?762if (DEBUG) {763System.out.println(state);764}765}766} catch (KrbException e) {767if (DEBUG) {768e.printStackTrace();769}770GSSException gssException =771new GSSException(errorCode, -1, e.getMessage());772gssException.initCause(e);773throw gssException;774} catch (IOException e) {775GSSException gssException =776new GSSException(errorCode, -1, e.getMessage());777gssException.initCause(e);778throw gssException;779}780return retVal;781}782783public final boolean isEstablished() {784return (state == STATE_DONE);785}786787/**788* Acceptor's context establishment call. This method may be789* required to be called several times. A CONTINUE_NEEDED return790* call indicates that more calls are needed after the next token791* is received from the peer.792*793* @param is contains the token received from the peer.794* @return any token required to be sent to the peer795* It is responsibility of the caller796* to send the token to its peer for processing.797* @exception GSSException798*/799public final byte[] acceptSecContext(InputStream is, int mechTokenSize)800throws GSSException {801802byte[] retVal = null;803804if (DEBUG) {805System.out.println("Entered Krb5Context.acceptSecContext with " +806"state=" + printState(state));807}808809if (isInitiator()) {810throw new GSSException(GSSException.FAILURE, -1,811"acceptSecContext on an initiator " +812"GSSContext");813}814try {815if (state == STATE_NEW) {816state = STATE_IN_PROCESS;817if (myCred == null) {818myCred = Krb5AcceptCredential.getInstance(caller, myName);819} else if (!myCred.isAcceptorCredential()) {820throw new GSSException(GSSException.NO_CRED, -1,821"No Secret Key available");822}823myName = (Krb5NameElement) myCred.getName();824825// If there is already a bound name, check now826if (myName != null) {827Krb5MechFactory.checkAcceptCredPermission(myName, myName);828}829830InitSecContextToken token = new InitSecContextToken(this,831(Krb5AcceptCredential) myCred, is);832PrincipalName clientName = token.getKrbApReq().getClient();833peerName = Krb5NameElement.getInstance(clientName);834835// If unbound, check after the bound name is found836if (myName == null) {837myName = Krb5NameElement.getInstance(838token.getKrbApReq().getCreds().getServer());839Krb5MechFactory.checkAcceptCredPermission(myName, myName);840}841842if (getMutualAuthState()) {843retVal = new AcceptSecContextToken(this,844token.getKrbApReq()).encode();845}846serviceTicket = token.getKrbApReq().getCreds().getTicket();847myCred = null;848state = STATE_DONE;849} else {850// XXX Use logging API?851if (DEBUG) {852System.out.println(state);853}854}855} catch (KrbException e) {856GSSException gssException =857new GSSException(GSSException.FAILURE, -1, e.getMessage());858gssException.initCause(e);859throw gssException;860} catch (IOException e) {861if (DEBUG) {862e.printStackTrace();863}864GSSException gssException =865new GSSException(GSSException.FAILURE, -1, e.getMessage());866gssException.initCause(e);867throw gssException;868}869870return retVal;871}872873/**874* Queries the context for largest data size to accommodate875* the specified protection and be <= maxTokSize.876*877* @param qop the quality of protection that the context will be878* asked to provide.879* @param confReq a flag indicating whether confidentiality will be880* requested or not881* @param outputSize the maximum size of the output token882* @return the maximum size for the input message that can be883* provided to the wrap() method in order to guarantee that these884* requirements are met.885* @throws GSSException886*/887public final int getWrapSizeLimit(int qop, boolean confReq,888int maxTokSize) throws GSSException {889890int retVal = 0;891if (cipherHelper.getProto() == 0) {892retVal = WrapToken.getSizeLimit(qop, confReq, maxTokSize,893getCipherHelper(null));894} else if (cipherHelper.getProto() == 1) {895retVal = WrapToken_v2.getSizeLimit(qop, confReq, maxTokSize,896getCipherHelper(null));897}898return retVal;899}900901/*902* Per-message calls depend on the sequence number. The sequence number903* synchronization is at a finer granularity because wrap and getMIC904* care about the local sequence number (mySeqNumber) where are unwrap905* and verifyMIC care about the remote sequence number (peerSeqNumber).906*/907908public final byte[] wrap(byte inBuf[], int offset, int len,909MessageProp msgProp) throws GSSException {910if (DEBUG) {911System.out.println("Krb5Context.wrap: data=["912+ getHexBytes(inBuf, offset, len)913+ "]");914}915916if (state != STATE_DONE)917throw new GSSException(GSSException.NO_CONTEXT, -1,918"Wrap called in invalid state!");919920byte[] encToken = null;921try {922if (cipherHelper.getProto() == 0) {923WrapToken token =924new WrapToken(this, msgProp, inBuf, offset, len);925encToken = token.encode();926} else if (cipherHelper.getProto() == 1) {927WrapToken_v2 token =928new WrapToken_v2(this, msgProp, inBuf, offset, len);929encToken = token.encode();930}931if (DEBUG) {932System.out.println("Krb5Context.wrap: token=["933+ getHexBytes(encToken, 0, encToken.length)934+ "]");935}936return encToken;937} catch (IOException e) {938encToken = null;939GSSException gssException =940new GSSException(GSSException.FAILURE, -1, e.getMessage());941gssException.initCause(e);942throw gssException;943}944}945946public final int wrap(byte inBuf[], int inOffset, int len,947byte[] outBuf, int outOffset,948MessageProp msgProp) throws GSSException {949950if (state != STATE_DONE)951throw new GSSException(GSSException.NO_CONTEXT, -1,952"Wrap called in invalid state!");953954int retVal = 0;955try {956if (cipherHelper.getProto() == 0) {957WrapToken token =958new WrapToken(this, msgProp, inBuf, inOffset, len);959retVal = token.encode(outBuf, outOffset);960} else if (cipherHelper.getProto() == 1) {961WrapToken_v2 token =962new WrapToken_v2(this, msgProp, inBuf, inOffset, len);963retVal = token.encode(outBuf, outOffset);964}965if (DEBUG) {966System.out.println("Krb5Context.wrap: token=["967+ getHexBytes(outBuf, outOffset, retVal)968+ "]");969}970return retVal;971} catch (IOException e) {972retVal = 0;973GSSException gssException =974new GSSException(GSSException.FAILURE, -1, e.getMessage());975gssException.initCause(e);976throw gssException;977}978}979980public final void wrap(byte inBuf[], int offset, int len,981OutputStream os, MessageProp msgProp)982throws GSSException {983984if (state != STATE_DONE)985throw new GSSException(GSSException.NO_CONTEXT, -1,986"Wrap called in invalid state!");987988byte[] encToken = null;989try {990if (cipherHelper.getProto() == 0) {991WrapToken token =992new WrapToken(this, msgProp, inBuf, offset, len);993token.encode(os);994if (DEBUG) {995encToken = token.encode();996}997} else if (cipherHelper.getProto() == 1) {998WrapToken_v2 token =999new WrapToken_v2(this, msgProp, inBuf, offset, len);1000token.encode(os);1001if (DEBUG) {1002encToken = token.encode();1003}1004}1005} catch (IOException e) {1006GSSException gssException =1007new GSSException(GSSException.FAILURE, -1, e.getMessage());1008gssException.initCause(e);1009throw gssException;1010}10111012if (DEBUG) {1013System.out.println("Krb5Context.wrap: token=["1014+ getHexBytes(encToken, 0, encToken.length)1015+ "]");1016}1017}10181019public final void wrap(InputStream is, OutputStream os,1020MessageProp msgProp) throws GSSException {10211022byte[] data;1023try {1024data = new byte[is.available()];1025is.read(data);1026} catch (IOException e) {1027GSSException gssException =1028new GSSException(GSSException.FAILURE, -1, e.getMessage());1029gssException.initCause(e);1030throw gssException;1031}1032wrap(data, 0, data.length, os, msgProp);1033}10341035public final byte[] unwrap(byte inBuf[], int offset, int len,1036MessageProp msgProp)1037throws GSSException {10381039if (DEBUG) {1040System.out.println("Krb5Context.unwrap: token=["1041+ getHexBytes(inBuf, offset, len)1042+ "]");1043}10441045if (state != STATE_DONE) {1046throw new GSSException(GSSException.NO_CONTEXT, -1,1047" Unwrap called in invalid state!");1048}10491050byte[] data = null;1051if (cipherHelper.getProto() == 0) {1052WrapToken token =1053new WrapToken(this, inBuf, offset, len, msgProp);1054data = token.getData();1055setSequencingAndReplayProps(token, msgProp);1056} else if (cipherHelper.getProto() == 1) {1057WrapToken_v2 token =1058new WrapToken_v2(this, inBuf, offset, len, msgProp);1059data = token.getData();1060setSequencingAndReplayProps(token, msgProp);1061}10621063if (DEBUG) {1064System.out.println("Krb5Context.unwrap: data=["1065+ getHexBytes(data, 0, data.length)1066+ "]");1067}10681069return data;1070}10711072public final int unwrap(byte inBuf[], int inOffset, int len,1073byte[] outBuf, int outOffset,1074MessageProp msgProp) throws GSSException {10751076if (state != STATE_DONE)1077throw new GSSException(GSSException.NO_CONTEXT, -1,1078"Unwrap called in invalid state!");10791080if (cipherHelper.getProto() == 0) {1081WrapToken token =1082new WrapToken(this, inBuf, inOffset, len, msgProp);1083len = token.getData(outBuf, outOffset);1084setSequencingAndReplayProps(token, msgProp);1085} else if (cipherHelper.getProto() == 1) {1086WrapToken_v2 token =1087new WrapToken_v2(this, inBuf, inOffset, len, msgProp);1088len = token.getData(outBuf, outOffset);1089setSequencingAndReplayProps(token, msgProp);1090}1091return len;1092}10931094public final int unwrap(InputStream is,1095byte[] outBuf, int outOffset,1096MessageProp msgProp) throws GSSException {10971098if (state != STATE_DONE)1099throw new GSSException(GSSException.NO_CONTEXT, -1,1100"Unwrap called in invalid state!");11011102int len = 0;1103if (cipherHelper.getProto() == 0) {1104WrapToken token = new WrapToken(this, is, msgProp);1105len = token.getData(outBuf, outOffset);1106setSequencingAndReplayProps(token, msgProp);1107} else if (cipherHelper.getProto() == 1) {1108WrapToken_v2 token = new WrapToken_v2(this, is, msgProp);1109len = token.getData(outBuf, outOffset);1110setSequencingAndReplayProps(token, msgProp);1111}1112return len;1113}111411151116public final void unwrap(InputStream is, OutputStream os,1117MessageProp msgProp) throws GSSException {11181119if (state != STATE_DONE)1120throw new GSSException(GSSException.NO_CONTEXT, -1,1121"Unwrap called in invalid state!");11221123byte[] data = null;1124if (cipherHelper.getProto() == 0) {1125WrapToken token = new WrapToken(this, is, msgProp);1126data = token.getData();1127setSequencingAndReplayProps(token, msgProp);1128} else if (cipherHelper.getProto() == 1) {1129WrapToken_v2 token = new WrapToken_v2(this, is, msgProp);1130data = token.getData();1131setSequencingAndReplayProps(token, msgProp);1132}11331134try {1135os.write(data);1136} catch (IOException e) {1137GSSException gssException =1138new GSSException(GSSException.FAILURE, -1, e.getMessage());1139gssException.initCause(e);1140throw gssException;1141}1142}11431144public final byte[] getMIC(byte []inMsg, int offset, int len,1145MessageProp msgProp)1146throws GSSException {11471148byte[] micToken = null;1149try {1150if (cipherHelper.getProto() == 0) {1151MicToken token =1152new MicToken(this, msgProp, inMsg, offset, len);1153micToken = token.encode();1154} else if (cipherHelper.getProto() == 1) {1155MicToken_v2 token =1156new MicToken_v2(this, msgProp, inMsg, offset, len);1157micToken = token.encode();1158}1159return micToken;1160} catch (IOException e) {1161micToken = null;1162GSSException gssException =1163new GSSException(GSSException.FAILURE, -1, e.getMessage());1164gssException.initCause(e);1165throw gssException;1166}1167}11681169private int getMIC(byte []inMsg, int offset, int len,1170byte[] outBuf, int outOffset,1171MessageProp msgProp)1172throws GSSException {11731174int retVal = 0;1175try {1176if (cipherHelper.getProto() == 0) {1177MicToken token =1178new MicToken(this, msgProp, inMsg, offset, len);1179retVal = token.encode(outBuf, outOffset);1180} else if (cipherHelper.getProto() == 1) {1181MicToken_v2 token =1182new MicToken_v2(this, msgProp, inMsg, offset, len);1183retVal = token.encode(outBuf, outOffset);1184}1185return retVal;1186} catch (IOException e) {1187retVal = 0;1188GSSException gssException =1189new GSSException(GSSException.FAILURE, -1, e.getMessage());1190gssException.initCause(e);1191throw gssException;1192}1193}11941195/*1196* Checksum calculation requires a byte[]. Hence might as well pass1197* a byte[] into the MicToken constructor. However, writing the1198* token can be optimized for cases where the application passed in1199* an OutputStream.1200*/12011202private void getMIC(byte[] inMsg, int offset, int len,1203OutputStream os, MessageProp msgProp)1204throws GSSException {12051206try {1207if (cipherHelper.getProto() == 0) {1208MicToken token =1209new MicToken(this, msgProp, inMsg, offset, len);1210token.encode(os);1211} else if (cipherHelper.getProto() == 1) {1212MicToken_v2 token =1213new MicToken_v2(this, msgProp, inMsg, offset, len);1214token.encode(os);1215}1216} catch (IOException e) {1217GSSException gssException =1218new GSSException(GSSException.FAILURE, -1, e.getMessage());1219gssException.initCause(e);1220throw gssException;1221}1222}12231224public final void getMIC(InputStream is, OutputStream os,1225MessageProp msgProp) throws GSSException {1226byte[] data;1227try {1228data = new byte[is.available()];1229is.read(data);1230} catch (IOException e) {1231GSSException gssException =1232new GSSException(GSSException.FAILURE, -1, e.getMessage());1233gssException.initCause(e);1234throw gssException;1235}1236getMIC(data, 0, data.length, os, msgProp);1237}12381239public final void verifyMIC(byte []inTok, int tokOffset, int tokLen,1240byte[] inMsg, int msgOffset, int msgLen,1241MessageProp msgProp)1242throws GSSException {12431244if (cipherHelper.getProto() == 0) {1245MicToken token =1246new MicToken(this, inTok, tokOffset, tokLen, msgProp);1247token.verify(inMsg, msgOffset, msgLen);1248setSequencingAndReplayProps(token, msgProp);1249} else if (cipherHelper.getProto() == 1) {1250MicToken_v2 token =1251new MicToken_v2(this, inTok, tokOffset, tokLen, msgProp);1252token.verify(inMsg, msgOffset, msgLen);1253setSequencingAndReplayProps(token, msgProp);1254}1255}12561257private void verifyMIC(InputStream is,1258byte[] inMsg, int msgOffset, int msgLen,1259MessageProp msgProp)1260throws GSSException {12611262if (cipherHelper.getProto() == 0) {1263MicToken token = new MicToken(this, is, msgProp);1264token.verify(inMsg, msgOffset, msgLen);1265setSequencingAndReplayProps(token, msgProp);1266} else if (cipherHelper.getProto() == 1) {1267MicToken_v2 token = new MicToken_v2(this, is, msgProp);1268token.verify(inMsg, msgOffset, msgLen);1269setSequencingAndReplayProps(token, msgProp);1270}1271}12721273public final void verifyMIC(InputStream is, InputStream msgStr,1274MessageProp mProp) throws GSSException {1275byte[] msg;1276try {1277msg = new byte[msgStr.available()];1278msgStr.read(msg);1279} catch (IOException e) {1280GSSException gssException =1281new GSSException(GSSException.FAILURE, -1, e.getMessage());1282gssException.initCause(e);1283throw gssException;1284}1285verifyMIC(is, msg, 0, msg.length, mProp);1286}12871288/**1289* Produces a token representing this context. After this call1290* the context will no longer be usable until an import is1291* performed on the returned token.1292*1293* @param os the output token will be written to this stream1294* @exception GSSException1295*/1296public final byte [] export() throws GSSException {1297throw new GSSException(GSSException.UNAVAILABLE, -1,1298"GSS Export Context not available");1299}13001301/**1302* Releases context resources and terminates the1303* context between 2 peer.1304*1305* @exception GSSException with major codes NO_CONTEXT, FAILURE.1306*/13071308public final void dispose() throws GSSException {1309state = STATE_DELETED;1310delegatedCred = null;1311}13121313public final Provider getProvider() {1314return Krb5MechFactory.PROVIDER;1315}13161317/**1318* Sets replay and sequencing information for a message token received1319* form the peer.1320*/1321private void setSequencingAndReplayProps(MessageToken token,1322MessageProp prop) {1323if (replayDetState || sequenceDetState) {1324int seqNum = token.getSequenceNumber();1325peerTokenTracker.getProps(seqNum, prop);1326}1327}13281329/**1330* Sets replay and sequencing information for a message token received1331* form the peer.1332*/1333private void setSequencingAndReplayProps(MessageToken_v2 token,1334MessageProp prop) {1335if (replayDetState || sequenceDetState) {1336int seqNum = token.getSequenceNumber();1337peerTokenTracker.getProps(seqNum, prop);1338}1339}13401341private void checkPermission(String principal, String action) {1342SecurityManager sm = System.getSecurityManager();1343if (sm != null) {1344ServicePermission perm =1345new ServicePermission(principal, action);1346sm.checkPermission(perm);1347}1348}13491350private static String getHexBytes(byte[] bytes, int pos, int len) {13511352StringBuffer sb = new StringBuffer();1353for (int i = 0; i < len; i++) {13541355int b1 = (bytes[i]>>4) & 0x0f;1356int b2 = bytes[i] & 0x0f;13571358sb.append(Integer.toHexString(b1));1359sb.append(Integer.toHexString(b2));1360sb.append(' ');1361}1362return sb.toString();1363}13641365private static String printState(int state) {1366switch (state) {1367case STATE_NEW:1368return ("STATE_NEW");1369case STATE_IN_PROCESS:1370return ("STATE_IN_PROCESS");1371case STATE_DONE:1372return ("STATE_DONE");1373case STATE_DELETED:1374return ("STATE_DELETED");1375default:1376return ("Unknown state " + state);1377}1378}13791380GSSCaller getCaller() {1381// Currently used by InitialToken only1382return caller;1383}13841385/**1386* The session key returned by inquireSecContext(KRB5_INQ_SSPI_SESSION_KEY)1387*/1388static class KerberosSessionKey implements Key {1389private static final long serialVersionUID = 699307378954123869L;13901391private final EncryptionKey key;13921393KerberosSessionKey(EncryptionKey key) {1394this.key = key;1395}13961397@Override1398public String getAlgorithm() {1399return Integer.toString(key.getEType());1400}14011402@Override1403public String getFormat() {1404return "RAW";1405}14061407@Override1408public byte[] getEncoded() {1409return key.getBytes().clone();1410}14111412@Override1413public String toString() {1414return "Kerberos session key: etype: " + key.getEType() + "\n" +1415new sun.misc.HexDumpEncoder().encodeBuffer(key.getBytes());1416}1417}14181419/**1420* Return the mechanism-specific attribute associated with {@code type}.1421*/1422public Object inquireSecContext(InquireType type)1423throws GSSException {1424if (!isEstablished()) {1425throw new GSSException(GSSException.NO_CONTEXT, -1,1426"Security context not established.");1427}1428switch (type) {1429case KRB5_GET_SESSION_KEY:1430return new KerberosSessionKey(key);1431case KRB5_GET_TKT_FLAGS:1432return tktFlags.clone();1433case KRB5_GET_AUTHZ_DATA:1434if (isInitiator()) {1435throw new GSSException(GSSException.UNAVAILABLE, -1,1436"AuthzData not available on initiator side.");1437} else {1438return (authzData==null)?null:authzData.clone();1439}1440case KRB5_GET_AUTHTIME:1441return authTime;1442}1443throw new GSSException(GSSException.UNAVAILABLE, -1,1444"Inquire type not supported.");1445}14461447// Helpers for inquireSecContext1448private boolean[] tktFlags;1449private String authTime;1450private com.sun.security.jgss.AuthorizationDataEntry[] authzData;14511452public void setTktFlags(boolean[] tktFlags) {1453this.tktFlags = tktFlags;1454}14551456public void setAuthTime(String authTime) {1457this.authTime = authTime;1458}14591460public void setAuthzData(com.sun.security.jgss.AuthorizationDataEntry[] authzData) {1461this.authzData = authzData;1462}1463}146414651466