/*
* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.security.jgss.spnego;
import java.io.*;
import java.security.Provider;
import org.ietf.jgss.*;
import sun.security.jgss.*;
import sun.security.jgss.spi.*;
import sun.security.util.*;
Implements the mechanism specific context class for SPNEGO
GSS-API mechanism
Author: Seema Malkani Since: 1.6
/**
* Implements the mechanism specific context class for SPNEGO
* GSS-API mechanism
*
* @author Seema Malkani
* @since 1.6
*/
public class SpNegoContext implements GSSContextSpi {
/*
* The different states that this context can be in.
*/
private static final int STATE_NEW = 1;
private static final int STATE_IN_PROCESS = 2;
private static final int STATE_DONE = 3;
private static final int STATE_DELETED = 4;
private int state = STATE_NEW;
/*
* Optional features that the application can set and their default
* values.
*/
private boolean credDelegState = false;
private boolean mutualAuthState = true;
private boolean replayDetState = true;
private boolean sequenceDetState = true;
private boolean confState = true;
private boolean integState = true;
private boolean delegPolicyState = false;
private GSSNameSpi peerName = null;
private GSSNameSpi myName = null;
private SpNegoCredElement myCred = null;
private GSSContext mechContext = null;
private byte[] DER_mechTypes = null;
private int lifetime;
private ChannelBinding channelBinding;
private boolean initiator;
// the underlying negotiated mechanism
private Oid internal_mech = null;
// the SpNegoMechFactory that creates this context
final private SpNegoMechFactory factory;
// debug property
static final boolean DEBUG =
java.security.AccessController.doPrivileged(
new sun.security.action.GetBooleanAction
("sun.security.spnego.debug")).booleanValue();
Constructor for SpNegoContext to be called on the context initiator's
side.
/**
* Constructor for SpNegoContext to be called on the context initiator's
* side.
*/
public SpNegoContext(SpNegoMechFactory factory, GSSNameSpi peerName,
GSSCredentialSpi myCred,
int lifetime) throws GSSException {
if (peerName == null)
throw new IllegalArgumentException("Cannot have null peer name");
if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {
throw new IllegalArgumentException("Wrong cred element type");
}
this.peerName = peerName;
this.myCred = (SpNegoCredElement) myCred;
this.lifetime = lifetime;
this.initiator = true;
this.factory = factory;
}
Constructor for SpNegoContext to be called on the context acceptor's
side.
/**
* Constructor for SpNegoContext to be called on the context acceptor's
* side.
*/
public SpNegoContext(SpNegoMechFactory factory, GSSCredentialSpi myCred)
throws GSSException {
if ((myCred != null) && !(myCred instanceof SpNegoCredElement)) {
throw new IllegalArgumentException("Wrong cred element type");
}
this.myCred = (SpNegoCredElement) myCred;
this.initiator = false;
this.factory = factory;
}
Constructor for SpNegoContext to import a previously exported context.
/**
* Constructor for SpNegoContext to import a previously exported context.
*/
public SpNegoContext(SpNegoMechFactory factory, byte [] interProcessToken)
throws GSSException {
throw new GSSException(GSSException.UNAVAILABLE,
-1, "GSS Import Context not available");
}
Requests that confidentiality be available.
/**
* Requests that confidentiality be available.
*/
public final void requestConf(boolean value) throws GSSException {
if (state == STATE_NEW && isInitiator())
confState = value;
}
Is confidentiality available?
/**
* Is confidentiality available?
*/
public final boolean getConfState() {
return confState;
}
Requests that integrity be available.
/**
* Requests that integrity be available.
*/
public final void requestInteg(boolean value) throws GSSException {
if (state == STATE_NEW && isInitiator())
integState = value;
}
Requests that deleg policy be respected.
/**
* Requests that deleg policy be respected.
*/
public final void requestDelegPolicy(boolean value) throws GSSException {
if (state == STATE_NEW && isInitiator())
delegPolicyState = value;
}
Is integrity available?
/**
* Is integrity available?
*/
public final boolean getIntegState() {
return integState;
}
Is deleg policy respected?
/**
* Is deleg policy respected?
*/
public final boolean getDelegPolicyState() {
if (isInitiator() && mechContext != null &&
mechContext instanceof GSSContextImpl &&
(state == STATE_IN_PROCESS || state == STATE_DONE)) {
return ((GSSContextImpl)mechContext).getDelegPolicyState();
} else {
return delegPolicyState;
}
}
Requests that credential delegation be done during context
establishment.
/**
* Requests that credential delegation be done during context
* establishment.
*/
public final void requestCredDeleg(boolean value) throws GSSException {
if (state == STATE_NEW && isInitiator())
credDelegState = value;
}
Is credential delegation enabled?
/**
* Is credential delegation enabled?
*/
public final boolean getCredDelegState() {
if (isInitiator() && mechContext != null &&
(state == STATE_IN_PROCESS || state == STATE_DONE)) {
return mechContext.getCredDelegState();
} else {
return credDelegState;
}
}
Requests that mutual authentication be done during context
establishment. Since this is fromm the client's perspective, it
essentially requests that the server be authenticated.
/**
* Requests that mutual authentication be done during context
* establishment. Since this is fromm the client's perspective, it
* essentially requests that the server be authenticated.
*/
public final void requestMutualAuth(boolean value) throws GSSException {
if (state == STATE_NEW && isInitiator()) {
mutualAuthState = value;
}
}
Is mutual authentication enabled? Since this is from the client's
perspective, it essentially meas that the server is being
authenticated.
/**
* Is mutual authentication enabled? Since this is from the client's
* perspective, it essentially meas that the server is being
* authenticated.
*/
public final boolean getMutualAuthState() {
return mutualAuthState;
}
Returns the mechanism oid.
Returns: the Oid of this context
/**
* Returns the mechanism oid.
*
* @return the Oid of this context
*/
public final Oid getMech() {
if (isEstablished()) {
return getNegotiatedMech();
}
return (SpNegoMechFactory.GSS_SPNEGO_MECH_OID);
}
public final Oid getNegotiatedMech() {
return (internal_mech);
}
public final Provider getProvider() {
return SpNegoMechFactory.PROVIDER;
}
public final void dispose() throws GSSException {
mechContext = null;
state = STATE_DELETED;
}
Tests if this is the initiator side of the context.
Returns: boolean indicating if this is initiator (true)
or target (false)
/**
* Tests if this is the initiator side of the context.
*
* @return boolean indicating if this is initiator (true)
* or target (false)
*/
public final boolean isInitiator() {
return initiator;
}
Tests if the context can be used for per-message service.
Context may allow the calls to the per-message service
functions before being fully established.
Returns: boolean indicating if per-message methods can
be called.
/**
* Tests if the context can be used for per-message service.
* Context may allow the calls to the per-message service
* functions before being fully established.
*
* @return boolean indicating if per-message methods can
* be called.
*/
public final boolean isProtReady() {
return (state == STATE_DONE);
}
Initiator context establishment call. This method may be
required to be called several times. A CONTINUE_NEEDED return
call indicates that more calls are needed after the next token
is received from the peer.
Params: - is – contains the token received from the peer. On the
first call it will be ignored.
Throws: Returns: any token required to be sent to the peer
It is responsibility of the caller to send the token
to its peer for processing.
/**
* Initiator context establishment call. This method may be
* required to be called several times. A CONTINUE_NEEDED return
* call indicates that more calls are needed after the next token
* is received from the peer.
*
* @param is contains the token received from the peer. On the
* first call it will be ignored.
* @return any token required to be sent to the peer
* It is responsibility of the caller to send the token
* to its peer for processing.
* @exception GSSException
*/
public final byte[] initSecContext(InputStream is, int mechTokenSize)
throws GSSException {
byte[] retVal = null;
NegTokenInit initToken = null;
byte[] mechToken = null;
int errorCode = GSSException.FAILURE;
if (DEBUG) {
System.out.println("Entered SpNego.initSecContext with " +
"state=" + printState(state));
}
if (!isInitiator()) {
throw new GSSException(GSSException.FAILURE, -1,
"initSecContext on an acceptor GSSContext");
}
try {
if (state == STATE_NEW) {
state = STATE_IN_PROCESS;
errorCode = GSSException.NO_CRED;
// determine available mech set
Oid[] mechList = getAvailableMechs();
DER_mechTypes = getEncodedMechs(mechList);
// pull out first mechanism
internal_mech = mechList[0];
// get the token for first mechanism
mechToken = GSS_initSecContext(null);
errorCode = GSSException.DEFECTIVE_TOKEN;
// generate SPNEGO token
initToken = new NegTokenInit(DER_mechTypes, getContextFlags(),
mechToken, null);
if (DEBUG) {
System.out.println("SpNegoContext.initSecContext: " +
"sending token of type = " +
SpNegoToken.getTokenName(initToken.getType()));
}
// get the encoded token
retVal = initToken.getEncoded();
} else if (state == STATE_IN_PROCESS) {
errorCode = GSSException.FAILURE;
if (is == null) {
throw new GSSException(errorCode, -1,
"No token received from peer!");
}
errorCode = GSSException.DEFECTIVE_TOKEN;
byte[] server_token = new byte[is.available()];
SpNegoToken.readFully(is, server_token);
if (DEBUG) {
System.out.println("SpNegoContext.initSecContext: " +
"process received token = " +
SpNegoToken.getHexBytes(server_token));
}
// read the SPNEGO token
// token will be validated when parsing
NegTokenTarg targToken = new NegTokenTarg(server_token);
if (DEBUG) {
System.out.println("SpNegoContext.initSecContext: " +
"received token of type = " +
SpNegoToken.getTokenName(targToken.getType()));
}
// pull out mechanism
internal_mech = targToken.getSupportedMech();
if (internal_mech == null) {
// return wth failure
throw new GSSException(errorCode, -1,
"supported mechanism from server is null");
}
// get the negotiated result
SpNegoToken.NegoResult negoResult = null;
int result = targToken.getNegotiatedResult();
switch (result) {
case 0:
negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;
state = STATE_DONE;
break;
case 1:
negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;
state = STATE_IN_PROCESS;
break;
case 2:
negoResult = SpNegoToken.NegoResult.REJECT;
state = STATE_DELETED;
break;
default:
state = STATE_DONE;
break;
}
errorCode = GSSException.BAD_MECH;
if (negoResult == SpNegoToken.NegoResult.REJECT) {
throw new GSSException(errorCode, -1,
internal_mech.toString());
}
errorCode = GSSException.DEFECTIVE_TOKEN;
if ((negoResult == SpNegoToken.NegoResult.ACCEPT_COMPLETE) ||
(negoResult == SpNegoToken.NegoResult.ACCEPT_INCOMPLETE)) {
// pull out the mechanism token
byte[] accept_token = targToken.getResponseToken();
if (accept_token == null) {
if (!isMechContextEstablished()) {
// return with failure
throw new GSSException(errorCode, -1,
"mechanism token from server is null");
}
} else {
mechToken = GSS_initSecContext(accept_token);
}
// verify MIC
if (!GSSUtil.useMSInterop()) {
byte[] micToken = targToken.getMechListMIC();
if (!verifyMechListMIC(DER_mechTypes, micToken)) {
throw new GSSException(errorCode, -1,
"verification of MIC on MechList Failed!");
}
}
if (isMechContextEstablished()) {
state = STATE_DONE;
retVal = mechToken;
if (DEBUG) {
System.out.println("SPNEGO Negotiated Mechanism = "
+ internal_mech + " " +
GSSUtil.getMechStr(internal_mech));
}
} else {
// generate SPNEGO token
initToken = new NegTokenInit(null, null,
mechToken, null);
if (DEBUG) {
System.out.println("SpNegoContext.initSecContext:" +
" continue sending token of type = " +
SpNegoToken.getTokenName(initToken.getType()));
}
// get the encoded token
retVal = initToken.getEncoded();
}
}
} else {
// XXX Use logging API
if (DEBUG) {
System.out.println(state);
}
}
if (DEBUG) {
if (retVal != null) {
System.out.println("SNegoContext.initSecContext: " +
"sending token = " + SpNegoToken.getHexBytes(retVal));
}
}
} catch (GSSException e) {
GSSException gssException =
new GSSException(errorCode, -1, e.getMessage());
gssException.initCause(e);
throw gssException;
} catch (IOException e) {
GSSException gssException =
new GSSException(GSSException.FAILURE, -1, e.getMessage());
gssException.initCause(e);
throw gssException;
}
return retVal;
}
Acceptor's context establishment call. This method may be
required to be called several times. A CONTINUE_NEEDED return
call indicates that more calls are needed after the next token
is received from the peer.
Params: - is – contains the token received from the peer.
Throws: Returns: any token required to be sent to the peer
It is responsibility of the caller to send the token
to its peer for processing.
/**
* Acceptor's context establishment call. This method may be
* required to be called several times. A CONTINUE_NEEDED return
* call indicates that more calls are needed after the next token
* is received from the peer.
*
* @param is contains the token received from the peer.
* @return any token required to be sent to the peer
* It is responsibility of the caller to send the token
* to its peer for processing.
* @exception GSSException
*/
public final byte[] acceptSecContext(InputStream is, int mechTokenSize)
throws GSSException {
byte[] retVal = null;
SpNegoToken.NegoResult negoResult;
boolean valid = true;
if (DEBUG) {
System.out.println("Entered SpNegoContext.acceptSecContext with " +
"state=" + printState(state));
}
if (isInitiator()) {
throw new GSSException(GSSException.FAILURE, -1,
"acceptSecContext on an initiator " +
"GSSContext");
}
try {
if (state == STATE_NEW) {
state = STATE_IN_PROCESS;
// read data
byte[] token = new byte[is.available()];
SpNegoToken.readFully(is, token);
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"receiving token = " +
SpNegoToken.getHexBytes(token));
}
// read the SPNEGO token
// token will be validated when parsing
NegTokenInit initToken = new NegTokenInit(token);
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"received token of type = " +
SpNegoToken.getTokenName(initToken.getType()));
}
Oid[] mechList = initToken.getMechTypeList();
DER_mechTypes = initToken.getMechTypes();
if (DER_mechTypes == null) {
valid = false;
}
/*
* Select the best match between the list of mechs
* that the initiator requested and the list that
* the acceptor will support.
*/
Oid[] supported_mechSet = getAvailableMechs();
Oid mech_wanted =
negotiate_mech_type(supported_mechSet, mechList);
if (mech_wanted == null) {
valid = false;
}
// save the desired mechanism
internal_mech = mech_wanted;
// get the token for mechanism
byte[] accept_token;
if (mechList[0].equals(mech_wanted) ||
(GSSUtil.isKerberosMech(mechList[0]) &&
GSSUtil.isKerberosMech(mech_wanted))) {
// get the mechanism token
if (DEBUG && !mech_wanted.equals(mechList[0])) {
System.out.println("SpNegoContext.acceptSecContext: " +
"negotiated mech adjusted to " + mechList[0]);
}
byte[] mechToken = initToken.getMechToken();
if (mechToken == null) {
throw new GSSException(GSSException.FAILURE, -1,
"mechToken is missing");
}
accept_token = GSS_acceptSecContext(mechToken);
mech_wanted = mechList[0];
} else {
accept_token = null;
}
// verify MIC
if (!GSSUtil.useMSInterop() && valid) {
valid = verifyMechListMIC(DER_mechTypes,
initToken.getMechListMIC());
}
// determine negotiated result status
if (valid) {
if (isMechContextEstablished()) {
negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;
state = STATE_DONE;
// now set the context flags for acceptor
setContextFlags();
// print the negotiated mech info
if (DEBUG) {
System.out.println("SPNEGO Negotiated Mechanism = "
+ internal_mech + " " +
GSSUtil.getMechStr(internal_mech));
}
} else {
negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;
state = STATE_IN_PROCESS;
}
} else {
negoResult = SpNegoToken.NegoResult.REJECT;
state = STATE_DONE;
}
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"mechanism wanted = " + mech_wanted);
System.out.println("SpNegoContext.acceptSecContext: " +
"negotiated result = " + negoResult);
}
// generate SPNEGO token
NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(),
mech_wanted, accept_token, null);
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"sending token of type = " +
SpNegoToken.getTokenName(targToken.getType()));
}
// get the encoded token
retVal = targToken.getEncoded();
} else if (state == STATE_IN_PROCESS) {
// read data
byte[] token = new byte[is.available()];
SpNegoToken.readFully(is, token);
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"receiving token = " +
SpNegoToken.getHexBytes(token));
}
// read the SPNEGO token
// token will be validated when parsing
NegTokenTarg inputToken = new NegTokenTarg(token);
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"received token of type = " +
SpNegoToken.getTokenName(inputToken.getType()));
}
// read the token
byte[] client_token = inputToken.getResponseToken();
byte[] accept_token = GSS_acceptSecContext(client_token);
if (accept_token == null) {
valid = false;
}
// determine negotiated result status
if (valid) {
if (isMechContextEstablished()) {
negoResult = SpNegoToken.NegoResult.ACCEPT_COMPLETE;
state = STATE_DONE;
} else {
negoResult = SpNegoToken.NegoResult.ACCEPT_INCOMPLETE;
state = STATE_IN_PROCESS;
}
} else {
negoResult = SpNegoToken.NegoResult.REJECT;
state = STATE_DONE;
}
// generate SPNEGO token
NegTokenTarg targToken = new NegTokenTarg(negoResult.ordinal(),
null, accept_token, null);
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"sending token of type = " +
SpNegoToken.getTokenName(targToken.getType()));
}
// get the encoded token
retVal = targToken.getEncoded();
} else {
// XXX Use logging API
if (DEBUG) {
System.out.println("AcceptSecContext: state = " + state);
}
}
if (DEBUG) {
System.out.println("SpNegoContext.acceptSecContext: " +
"sending token = " + SpNegoToken.getHexBytes(retVal));
}
} catch (IOException e) {
GSSException gssException =
new GSSException(GSSException.FAILURE, -1, e.getMessage());
gssException.initCause(e);
throw gssException;
}
if (state == STATE_DONE) {
// now set the context flags for acceptor
setContextFlags();
}
return retVal;
}
obtain the available mechanisms
/**
* obtain the available mechanisms
*/
private Oid[] getAvailableMechs() {
if (myCred != null) {
Oid[] mechs = new Oid[1];
mechs[0] = myCred.getInternalMech();
return mechs;
} else {
return factory.availableMechs;
}
}
get ther DER encoded MechList
/**
* get ther DER encoded MechList
*/
private byte[] getEncodedMechs(Oid[] mechSet)
throws IOException, GSSException {
DerOutputStream mech = new DerOutputStream();
for (int i = 0; i < mechSet.length; i++) {
byte[] mechType = mechSet[i].getDER();
mech.write(mechType);
}
// insert in SEQUENCE
DerOutputStream mechTypeList = new DerOutputStream();
mechTypeList.write(DerValue.tag_Sequence, mech);
byte[] encoded = mechTypeList.toByteArray();
return encoded;
}
get the context flags
/**
* get the context flags
*/
private BitArray getContextFlags() {
BitArray out = new BitArray(7);
if (getCredDelegState()) out.set(0, true);
if (getMutualAuthState()) out.set(1, true);
if (getReplayDetState()) out.set(2, true);
if (getSequenceDetState()) out.set(3, true);
if (getConfState()) out.set(5, true);
if (getIntegState()) out.set(6, true);
return out;
}
// Only called on acceptor side. On the initiator side, most flags
// are already set at request. For those that might get chanegd,
// state from mech below is used.
private void setContextFlags() {
if (mechContext != null) {
// default for cred delegation is false
if (mechContext.getCredDelegState()) {
credDelegState = true;
}
// default for the following are true
if (!mechContext.getMutualAuthState()) {
mutualAuthState = false;
}
if (!mechContext.getReplayDetState()) {
replayDetState = false;
}
if (!mechContext.getSequenceDetState()) {
sequenceDetState = false;
}
if (!mechContext.getIntegState()) {
integState = false;
}
if (!mechContext.getConfState()) {
confState = false;
}
}
}
/**
* generate MIC on mechList. Not used at the moment.
*/
/*private byte[] generateMechListMIC(byte[] mechTypes)
throws GSSException {
// sanity check the required input
if (mechTypes == null) {
if (DEBUG) {
System.out.println("SpNegoContext: no MIC token included");
}
return null;
}
// check if mechanism supports integrity
if (!mechContext.getIntegState()) {
if (DEBUG) {
System.out.println("SpNegoContext: no MIC token included" +
" - mechanism does not support integrity");
}
return null;
}
// compute MIC on DER encoded mechanism list
byte[] mic = null;
try {
MessageProp prop = new MessageProp(0, true);
mic = getMIC(mechTypes, 0, mechTypes.length, prop);
if (DEBUG) {
System.out.println("SpNegoContext: getMIC = " +
SpNegoToken.getHexBytes(mic));
}
} catch (GSSException e) {
mic = null;
if (DEBUG) {
System.out.println("SpNegoContext: no MIC token included" +
" - getMIC failed : " + e.getMessage());
}
}
return mic;
}*/
verify MIC on MechList
/**
* verify MIC on MechList
*/
private boolean verifyMechListMIC(byte[] mechTypes, byte[] token)
throws GSSException {
// sanity check the input
if (token == null) {
if (DEBUG) {
System.out.println("SpNegoContext: no MIC token validation");
}
return true;
}
// check if mechanism supports integrity
if (!mechContext.getIntegState()) {
if (DEBUG) {
System.out.println("SpNegoContext: no MIC token validation" +
" - mechanism does not support integrity");
}
return true;
}
// now verify the token
boolean valid = false;
try {
MessageProp prop = new MessageProp(0, true);
verifyMIC(token, 0, token.length, mechTypes,
0, mechTypes.length, prop);
valid = true;
} catch (GSSException e) {
valid = false;
if (DEBUG) {
System.out.println("SpNegoContext: MIC validation failed! " +
e.getMessage());
}
}
return valid;
}
call gss_init_sec_context for the corresponding underlying mechanism
/**
* call gss_init_sec_context for the corresponding underlying mechanism
*/
private byte[] GSS_initSecContext(byte[] token) throws GSSException {
byte[] tok = null;
if (mechContext == null) {
// initialize mech context
GSSName serverName =
factory.manager.createName(peerName.toString(),
peerName.getStringNameType(), internal_mech);
GSSCredential cred = null;
if (myCred != null) {
// create context with provided credential
cred = new GSSCredentialImpl(factory.manager,
myCred.getInternalCred());
}
mechContext =
factory.manager.createContext(serverName,
internal_mech, cred, GSSContext.DEFAULT_LIFETIME);
mechContext.requestConf(confState);
mechContext.requestInteg(integState);
mechContext.requestCredDeleg(credDelegState);
mechContext.requestMutualAuth(mutualAuthState);
mechContext.requestReplayDet(replayDetState);
mechContext.requestSequenceDet(sequenceDetState);
if (mechContext instanceof GSSContextImpl) {
((GSSContextImpl)mechContext).requestDelegPolicy(
delegPolicyState);
}
}
// pass token
if (token != null) {
tok = token;
} else {
tok = new byte[0];
}
// pass token to mechanism initSecContext
byte[] init_token = mechContext.initSecContext(tok, 0, tok.length);
return init_token;
}
call gss_accept_sec_context for the corresponding underlying mechanism
/**
* call gss_accept_sec_context for the corresponding underlying mechanism
*/
private byte[] GSS_acceptSecContext(byte[] token) throws GSSException {
if (mechContext == null) {
// initialize mech context
GSSCredential cred = null;
if (myCred != null) {
// create context with provided credential
cred = new GSSCredentialImpl(factory.manager,
myCred.getInternalCred());
}
mechContext = factory.manager.createContext(cred);
}
// pass token to mechanism acceptSecContext
byte[] accept_token =
mechContext.acceptSecContext(token, 0, token.length);
return accept_token;
}
This routine compares the recieved mechset to the mechset that
this server can support. It looks sequentially through the mechset
and the first one that matches what the server can support is
chosen as the negotiated mechanism. If one is found, negResult
is set to ACCEPT_COMPLETE, otherwise we return NULL and negResult
is set to REJECT.
/**
* This routine compares the recieved mechset to the mechset that
* this server can support. It looks sequentially through the mechset
* and the first one that matches what the server can support is
* chosen as the negotiated mechanism. If one is found, negResult
* is set to ACCEPT_COMPLETE, otherwise we return NULL and negResult
* is set to REJECT.
*/
private static Oid negotiate_mech_type(Oid[] supported_mechSet,
Oid[] mechSet) {
for (int i = 0; i < supported_mechSet.length; i++) {
for (int j = 0; j < mechSet.length; j++) {
if (mechSet[j].equals(supported_mechSet[i])) {
if (DEBUG) {
System.out.println("SpNegoContext: " +
"negotiated mechanism = " + mechSet[j]);
}
return (mechSet[j]);
}
}
}
return null;
}
public final boolean isEstablished() {
return (state == STATE_DONE);
}
public final boolean isMechContextEstablished() {
if (mechContext != null) {
return mechContext.isEstablished();
} else {
if (DEBUG) {
System.out.println("The underlying mechanism context has " +
"not been initialized");
}
return false;
}
}
public final byte [] export() throws GSSException {
throw new GSSException(GSSException.UNAVAILABLE, -1,
"GSS Export Context not available");
}
Sets the channel bindings to be used during context
establishment.
/**
* Sets the channel bindings to be used during context
* establishment.
*/
public final void setChannelBinding(ChannelBinding channelBinding)
throws GSSException {
this.channelBinding = channelBinding;
}
final ChannelBinding getChannelBinding() {
return channelBinding;
}
/*
* Anonymity is a little different in that after an application
* requests anonymity it will want to know whether the mechanism
* can support it or not, prior to sending any tokens across for
* context establishment. Since this is from the initiator's
* perspective, it essentially requests that the initiator be
* anonymous.
*/
public final void requestAnonymity(boolean value) throws GSSException {
// Ignore silently. Application will check back with
// getAnonymityState.
}
// RFC 2853 actually calls for this to be called after context
// establishment to get the right answer, but that is
// incorrect. The application may not want to send over any
// tokens if anonymity is not available.
public final boolean getAnonymityState() {
return false;
}
Requests the desired lifetime. Can only be used on the context
initiator's side.
/**
* Requests the desired lifetime. Can only be used on the context
* initiator's side.
*/
public void requestLifetime(int lifetime) throws GSSException {
if (state == STATE_NEW && isInitiator())
this.lifetime = lifetime;
}
The lifetime remaining for this context.
/**
* The lifetime remaining for this context.
*/
public final int getLifetime() {
if (mechContext != null) {
return mechContext.getLifetime();
} else {
return GSSContext.INDEFINITE_LIFETIME;
}
}
public final boolean isTransferable() throws GSSException {
return false;
}
Requests that sequence checking be done on the GSS wrap and MIC
tokens.
/**
* Requests that sequence checking be done on the GSS wrap and MIC
* tokens.
*/
public final void requestSequenceDet(boolean value) throws GSSException {
if (state == STATE_NEW && isInitiator())
sequenceDetState = value;
}
Is sequence checking enabled on the GSS Wrap and MIC tokens?
We enable sequence checking if replay detection is enabled.
/**
* Is sequence checking enabled on the GSS Wrap and MIC tokens?
* We enable sequence checking if replay detection is enabled.
*/
public final boolean getSequenceDetState() {
return sequenceDetState || replayDetState;
}
Requests that replay detection be done on the GSS wrap and MIC
tokens.
/**
* Requests that replay detection be done on the GSS wrap and MIC
* tokens.
*/
public final void requestReplayDet(boolean value) throws GSSException {
if (state == STATE_NEW && isInitiator())
replayDetState = value;
}
Is replay detection enabled on the GSS wrap and MIC tokens?
We enable replay detection if sequence checking is enabled.
/**
* Is replay detection enabled on the GSS wrap and MIC tokens?
* We enable replay detection if sequence checking is enabled.
*/
public final boolean getReplayDetState() {
return replayDetState || sequenceDetState;
}
public final GSSNameSpi getTargName() throws GSSException {
// fill-in the GSSName
// get the peer name for the mechanism
if (mechContext != null) {
GSSNameImpl targName = (GSSNameImpl)mechContext.getTargName();
peerName = targName.getElement(internal_mech);
return peerName;
} else {
if (DEBUG) {
System.out.println("The underlying mechanism context has " +
"not been initialized");
}
return null;
}
}
public final GSSNameSpi getSrcName() throws GSSException {
// fill-in the GSSName
// get the src name for the mechanism
if (mechContext != null) {
GSSNameImpl srcName = (GSSNameImpl)mechContext.getSrcName();
myName = srcName.getElement(internal_mech);
return myName;
} else {
if (DEBUG) {
System.out.println("The underlying mechanism context has " +
"not been initialized");
}
return null;
}
}
Returns the delegated credential for the context. This
is an optional feature of contexts which not all
mechanisms will support. A context can be requested to
support credential delegation by using the CRED_DELEG.
This is only valid on the acceptor side of the context.
Throws: See Also: Returns: GSSCredentialSpi object for the delegated credential
/**
* Returns the delegated credential for the context. This
* is an optional feature of contexts which not all
* mechanisms will support. A context can be requested to
* support credential delegation by using the <b>CRED_DELEG</b>.
* This is only valid on the acceptor side of the context.
* @return GSSCredentialSpi object for the delegated credential
* @exception GSSException
* @see GSSContext#getCredDelegState
*/
public final GSSCredentialSpi getDelegCred() throws GSSException {
if (state != STATE_IN_PROCESS && state != STATE_DONE)
throw new GSSException(GSSException.NO_CONTEXT);
if (mechContext != null) {
GSSCredentialImpl delegCred =
(GSSCredentialImpl)mechContext.getDelegCred();
if (delegCred == null) {
return null;
}
// determine delegated cred element usage
boolean initiate = false;
if (delegCred.getUsage() == GSSCredential.INITIATE_ONLY) {
initiate = true;
}
GSSCredentialSpi mechCred =
delegCred.getElement(internal_mech, initiate);
SpNegoCredElement cred = new SpNegoCredElement(mechCred);
return cred.getInternalCred();
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"getDelegCred called in invalid state!");
}
}
public final int getWrapSizeLimit(int qop, boolean confReq,
int maxTokSize) throws GSSException {
if (mechContext != null) {
return mechContext.getWrapSizeLimit(qop, confReq, maxTokSize);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"getWrapSizeLimit called in invalid state!");
}
}
public final byte[] wrap(byte inBuf[], int offset, int len,
MessageProp msgProp) throws GSSException {
if (mechContext != null) {
return mechContext.wrap(inBuf, offset, len, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"Wrap called in invalid state!");
}
}
public final void wrap(InputStream is, OutputStream os,
MessageProp msgProp) throws GSSException {
if (mechContext != null) {
mechContext.wrap(is, os, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"Wrap called in invalid state!");
}
}
public final byte[] unwrap(byte inBuf[], int offset, int len,
MessageProp msgProp)
throws GSSException {
if (mechContext != null) {
return mechContext.unwrap(inBuf, offset, len, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"UnWrap called in invalid state!");
}
}
public final void unwrap(InputStream is, OutputStream os,
MessageProp msgProp) throws GSSException {
if (mechContext != null) {
mechContext.unwrap(is, os, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"UnWrap called in invalid state!");
}
}
public final byte[] getMIC(byte []inMsg, int offset, int len,
MessageProp msgProp)
throws GSSException {
if (mechContext != null) {
return mechContext.getMIC(inMsg, offset, len, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"getMIC called in invalid state!");
}
}
public final void getMIC(InputStream is, OutputStream os,
MessageProp msgProp) throws GSSException {
if (mechContext != null) {
mechContext.getMIC(is, os, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"getMIC called in invalid state!");
}
}
public final void verifyMIC(byte []inTok, int tokOffset, int tokLen,
byte[] inMsg, int msgOffset, int msgLen,
MessageProp msgProp)
throws GSSException {
if (mechContext != null) {
mechContext.verifyMIC(inTok, tokOffset, tokLen, inMsg, msgOffset,
msgLen, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"verifyMIC called in invalid state!");
}
}
public final void verifyMIC(InputStream is, InputStream msgStr,
MessageProp msgProp) throws GSSException {
if (mechContext != null) {
mechContext.verifyMIC(is, msgStr, msgProp);
} else {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"verifyMIC called in invalid state!");
}
}
private static String printState(int state) {
switch (state) {
case STATE_NEW:
return ("STATE_NEW");
case STATE_IN_PROCESS:
return ("STATE_IN_PROCESS");
case STATE_DONE:
return ("STATE_DONE");
case STATE_DELETED:
return ("STATE_DELETED");
default:
return ("Unknown state " + state);
}
}
Retrieve attribute of the context for type
. /**
* Retrieve attribute of the context for {@code type}.
*/
public Object inquireSecContext(String type)
throws GSSException {
if (mechContext == null) {
throw new GSSException(GSSException.NO_CONTEXT, -1,
"Underlying mech not established.");
}
if (mechContext instanceof GSSContextImpl) {
return ((GSSContextImpl)mechContext).inquireSecContext(type);
} else {
throw new GSSException(GSSException.BAD_MECH, -1,
"inquireSecContext not supported by underlying mech.");
}
}
}