feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
49
jdkSrc/jdk8/sun/security/jgss/GSSCaller.java
Normal file
49
jdkSrc/jdk8/sun/security/jgss/GSSCaller.java
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, 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;
|
||||
|
||||
/**
|
||||
* Denotes what client is calling the JGSS-API. The object can be sent deep
|
||||
* into the mechanism level so that special actions can be performed for
|
||||
* different callers.
|
||||
*/
|
||||
public class GSSCaller {
|
||||
public static final GSSCaller CALLER_UNKNOWN = new GSSCaller("UNKNOWN");
|
||||
public static final GSSCaller CALLER_INITIATE = new GSSCaller("INITIATE");
|
||||
public static final GSSCaller CALLER_ACCEPT = new GSSCaller("ACCEPT");
|
||||
public static final GSSCaller CALLER_SSL_CLIENT = new GSSCaller("SSL_CLIENT");
|
||||
public static final GSSCaller CALLER_SSL_SERVER = new GSSCaller("SSL_SERVER");
|
||||
|
||||
private String name;
|
||||
GSSCaller(String s) {
|
||||
name = s;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GSSCaller{" + name + '}';
|
||||
}
|
||||
}
|
||||
|
||||
661
jdkSrc/jdk8/sun/security/jgss/GSSContextImpl.java
Normal file
661
jdkSrc/jdk8/sun/security/jgss/GSSContextImpl.java
Normal file
@@ -0,0 +1,661 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2009, 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;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import com.sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* This class represents the JGSS security context and its associated
|
||||
* operations. JGSS security contexts are established between
|
||||
* peers using locally established credentials. Multiple contexts
|
||||
* may exist simultaneously between a pair of peers, using the same
|
||||
* or different set of credentials. The JGSS is independent of
|
||||
* the underlying transport protocols and depends on its callers to
|
||||
* transport the tokens between peers.
|
||||
* <p>
|
||||
* The context object can be thought of as having 3 implicit states:
|
||||
* before it is established, during its context establishment, and
|
||||
* after a fully established context exists.
|
||||
* <p>
|
||||
* Before the context establishment phase is initiated, the context
|
||||
* initiator may request specific characteristics desired of the
|
||||
* established context. These can be set using the set methods. After the
|
||||
* context is established, the caller can check the actual characteristic
|
||||
* and services offered by the context using the query methods.
|
||||
* <p>
|
||||
* The context establishment phase begins with the first call to the
|
||||
* initSecContext method by the context initiator. During this phase the
|
||||
* initSecContext and acceptSecContext methods will produce GSS-API
|
||||
* authentication tokens which the calling application needs to send to its
|
||||
* peer. The initSecContext and acceptSecContext methods may
|
||||
* return a CONTINUE_NEEDED code which indicates that a token is needed
|
||||
* from its peer in order to continue the context establishment phase. A
|
||||
* return code of COMPLETE signals that the local end of the context is
|
||||
* established. This may still require that a token be sent to the peer,
|
||||
* depending if one is produced by GSS-API. The isEstablished method can
|
||||
* also be used to determine if the local end of the context has been
|
||||
* fully established. During the context establishment phase, the
|
||||
* isProtReady method may be called to determine if the context can be
|
||||
* used for the per-message operations. This allows implementation to
|
||||
* use per-message operations on contexts which aren't fully established.
|
||||
* <p>
|
||||
* After the context has been established or the isProtReady method
|
||||
* returns "true", the query routines can be invoked to determine the actual
|
||||
* characteristics and services of the established context. The
|
||||
* application can also start using the per-message methods of wrap and
|
||||
* getMIC to obtain cryptographic operations on application supplied data.
|
||||
* <p>
|
||||
* When the context is no longer needed, the application should call
|
||||
* dispose to release any system resources the context may be using.
|
||||
* <DL><DT><B>RFC 2078</b>
|
||||
* <DD>This class corresponds to the context level calls together with
|
||||
* the per message calls of RFC 2078. The gss_init_sec_context and
|
||||
* gss_accept_sec_context calls have been made simpler by only taking
|
||||
* required parameters. The context can have its properties set before
|
||||
* the first call to initSecContext. The supplementary status codes for the
|
||||
* per-message operations are returned in an instance of the MessageProp
|
||||
* class, which is used as an argument in these calls.</dl>
|
||||
*/
|
||||
class GSSContextImpl implements ExtendedGSSContext {
|
||||
|
||||
private final GSSManagerImpl gssManager;
|
||||
private final boolean initiator;
|
||||
|
||||
// private flags for the context state
|
||||
private static final int PRE_INIT = 1;
|
||||
private static final int IN_PROGRESS = 2;
|
||||
private static final int READY = 3;
|
||||
private static final int DELETED = 4;
|
||||
|
||||
// instance variables
|
||||
private int currentState = PRE_INIT;
|
||||
|
||||
private GSSContextSpi mechCtxt = null;
|
||||
private Oid mechOid = null;
|
||||
private ObjectIdentifier objId = null;
|
||||
|
||||
private GSSCredentialImpl myCred = null;
|
||||
|
||||
private GSSNameImpl srcName = null;
|
||||
private GSSNameImpl targName = null;
|
||||
|
||||
private int reqLifetime = INDEFINITE_LIFETIME;
|
||||
private ChannelBinding channelBindings = null;
|
||||
|
||||
private boolean reqConfState = true;
|
||||
private boolean reqIntegState = true;
|
||||
private boolean reqMutualAuthState = true;
|
||||
private boolean reqReplayDetState = true;
|
||||
private boolean reqSequenceDetState = true;
|
||||
private boolean reqCredDelegState = false;
|
||||
private boolean reqAnonState = false;
|
||||
private boolean reqDelegPolicyState = false;
|
||||
|
||||
/**
|
||||
* Creates a GSSContextImp on the context initiator's side.
|
||||
*/
|
||||
public GSSContextImpl(GSSManagerImpl gssManager, GSSName peer, Oid mech,
|
||||
GSSCredential myCred, int lifetime)
|
||||
throws GSSException {
|
||||
if ((peer == null) || !(peer instanceof GSSNameImpl)) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
this.gssManager = gssManager;
|
||||
this.myCred = (GSSCredentialImpl) myCred; // XXX Check first
|
||||
reqLifetime = lifetime;
|
||||
targName = (GSSNameImpl)peer;
|
||||
this.mechOid = mech;
|
||||
initiator = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a GSSContextImpl on the context acceptor's side.
|
||||
*/
|
||||
public GSSContextImpl(GSSManagerImpl gssManager, GSSCredential myCred)
|
||||
throws GSSException {
|
||||
this.gssManager = gssManager;
|
||||
this.myCred = (GSSCredentialImpl) myCred; // XXX Check first
|
||||
initiator = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a GSSContextImpl out of a previously exported
|
||||
* GSSContext.
|
||||
*
|
||||
* @see #isTransferable
|
||||
*/
|
||||
public GSSContextImpl(GSSManagerImpl gssManager, byte[] interProcessToken)
|
||||
throws GSSException {
|
||||
this.gssManager = gssManager;
|
||||
mechCtxt = gssManager.getMechanismContext(interProcessToken);
|
||||
initiator = mechCtxt.isInitiator();
|
||||
this.mechOid = mechCtxt.getMech();
|
||||
}
|
||||
|
||||
public byte[] initSecContext(byte inputBuf[], int offset, int len)
|
||||
throws GSSException {
|
||||
/*
|
||||
* Size of ByteArrayOutputStream will double each time that extra
|
||||
* bytes are to be written. Usually, without delegation, a GSS
|
||||
* initial token containing the Kerberos AP-REQ is between 400 and
|
||||
* 600 bytes.
|
||||
*/
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(600);
|
||||
ByteArrayInputStream bin =
|
||||
new ByteArrayInputStream(inputBuf, offset, len);
|
||||
int size = initSecContext(bin, bos);
|
||||
return (size == 0? null : bos.toByteArray());
|
||||
}
|
||||
|
||||
public int initSecContext(InputStream inStream,
|
||||
OutputStream outStream) throws GSSException {
|
||||
|
||||
if (mechCtxt != null && currentState != IN_PROGRESS) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Illegal call to initSecContext");
|
||||
}
|
||||
|
||||
GSSHeader gssHeader = null;
|
||||
int inTokenLen = -1;
|
||||
GSSCredentialSpi credElement = null;
|
||||
boolean firstToken = false;
|
||||
|
||||
try {
|
||||
if (mechCtxt == null) {
|
||||
if (myCred != null) {
|
||||
try {
|
||||
credElement = myCred.getElement(mechOid, true);
|
||||
} catch (GSSException ge) {
|
||||
if (GSSUtil.isSpNegoMech(mechOid) &&
|
||||
ge.getMajor() == GSSException.NO_CRED) {
|
||||
credElement = myCred.getElement
|
||||
(myCred.getMechs()[0], true);
|
||||
} else {
|
||||
throw ge;
|
||||
}
|
||||
}
|
||||
}
|
||||
GSSNameSpi nameElement = targName.getElement(mechOid);
|
||||
mechCtxt = gssManager.getMechanismContext(nameElement,
|
||||
credElement,
|
||||
reqLifetime,
|
||||
mechOid);
|
||||
mechCtxt.requestConf(reqConfState);
|
||||
mechCtxt.requestInteg(reqIntegState);
|
||||
mechCtxt.requestCredDeleg(reqCredDelegState);
|
||||
mechCtxt.requestMutualAuth(reqMutualAuthState);
|
||||
mechCtxt.requestReplayDet(reqReplayDetState);
|
||||
mechCtxt.requestSequenceDet(reqSequenceDetState);
|
||||
mechCtxt.requestAnonymity(reqAnonState);
|
||||
mechCtxt.setChannelBinding(channelBindings);
|
||||
mechCtxt.requestDelegPolicy(reqDelegPolicyState);
|
||||
|
||||
objId = new ObjectIdentifier(mechOid.toString());
|
||||
|
||||
currentState = IN_PROGRESS;
|
||||
firstToken = true;
|
||||
} else {
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
GSSUtil.isSpNegoMech(mechOid)) {
|
||||
// do not parse GSS header for native provider or SPNEGO
|
||||
// mech
|
||||
} else {
|
||||
// parse GSS header
|
||||
gssHeader = new GSSHeader(inStream);
|
||||
if (!gssHeader.getOid().equals((Object) objId))
|
||||
throw new GSSExceptionImpl
|
||||
(GSSException.DEFECTIVE_TOKEN,
|
||||
"Mechanism not equal to " +
|
||||
mechOid.toString() +
|
||||
" in initSecContext token");
|
||||
inTokenLen = gssHeader.getMechTokenLength();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] obuf = mechCtxt.initSecContext(inStream, inTokenLen);
|
||||
|
||||
int retVal = 0;
|
||||
|
||||
if (obuf != null) {
|
||||
retVal = obuf.length;
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
(!firstToken && GSSUtil.isSpNegoMech(mechOid))) {
|
||||
// do not add GSS header for native provider or SPNEGO
|
||||
// except for the first SPNEGO token
|
||||
} else {
|
||||
// add GSS header
|
||||
gssHeader = new GSSHeader(objId, obuf.length);
|
||||
retVal += gssHeader.encode(outStream);
|
||||
}
|
||||
outStream.write(obuf);
|
||||
}
|
||||
|
||||
if (mechCtxt.isEstablished())
|
||||
currentState = READY;
|
||||
|
||||
return retVal;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.DEFECTIVE_TOKEN,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] acceptSecContext(byte inTok[], int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
/*
|
||||
* Usually initial GSS token containing a Kerberos AP-REP is less
|
||||
* than 100 bytes.
|
||||
*/
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(100);
|
||||
acceptSecContext(new ByteArrayInputStream(inTok, offset, len),
|
||||
bos);
|
||||
byte[] out = bos.toByteArray();
|
||||
return (out.length == 0) ? null : out;
|
||||
}
|
||||
|
||||
public void acceptSecContext(InputStream inStream,
|
||||
OutputStream outStream) throws GSSException {
|
||||
|
||||
if (mechCtxt != null && currentState != IN_PROGRESS) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Illegal call to acceptSecContext");
|
||||
}
|
||||
|
||||
GSSHeader gssHeader = null;
|
||||
int inTokenLen = -1;
|
||||
GSSCredentialSpi credElement = null;
|
||||
|
||||
try {
|
||||
if (mechCtxt == null) {
|
||||
// mechOid will be null for an acceptor's context
|
||||
gssHeader = new GSSHeader(inStream);
|
||||
inTokenLen = gssHeader.getMechTokenLength();
|
||||
|
||||
/*
|
||||
* Convert ObjectIdentifier to Oid
|
||||
*/
|
||||
objId = gssHeader.getOid();
|
||||
mechOid = new Oid(objId.toString());
|
||||
// System.out.println("Entered GSSContextImpl.acceptSecContext"
|
||||
// + " with mechanism = " + mechOid);
|
||||
if (myCred != null) {
|
||||
credElement = myCred.getElement(mechOid, false);
|
||||
}
|
||||
|
||||
mechCtxt = gssManager.getMechanismContext(credElement,
|
||||
mechOid);
|
||||
mechCtxt.setChannelBinding(channelBindings);
|
||||
|
||||
currentState = IN_PROGRESS;
|
||||
} else {
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
(GSSUtil.isSpNegoMech(mechOid))) {
|
||||
// do not parse GSS header for native provider and SPNEGO
|
||||
} else {
|
||||
// parse GSS Header
|
||||
gssHeader = new GSSHeader(inStream);
|
||||
if (!gssHeader.getOid().equals((Object) objId))
|
||||
throw new GSSExceptionImpl
|
||||
(GSSException.DEFECTIVE_TOKEN,
|
||||
"Mechanism not equal to " +
|
||||
mechOid.toString() +
|
||||
" in acceptSecContext token");
|
||||
inTokenLen = gssHeader.getMechTokenLength();
|
||||
}
|
||||
}
|
||||
|
||||
byte[] obuf = mechCtxt.acceptSecContext(inStream, inTokenLen);
|
||||
|
||||
if (obuf != null) {
|
||||
int retVal = obuf.length;
|
||||
if (mechCtxt.getProvider().getName().equals("SunNativeGSS") ||
|
||||
(GSSUtil.isSpNegoMech(mechOid))) {
|
||||
// do not add GSS header for native provider and SPNEGO
|
||||
} else {
|
||||
// add GSS header
|
||||
gssHeader = new GSSHeader(objId, obuf.length);
|
||||
retVal += gssHeader.encode(outStream);
|
||||
}
|
||||
outStream.write(obuf);
|
||||
}
|
||||
|
||||
if (mechCtxt.isEstablished()) {
|
||||
currentState = READY;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.DEFECTIVE_TOKEN,
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEstablished() {
|
||||
if (mechCtxt == null)
|
||||
return false;
|
||||
else
|
||||
return (currentState == READY);
|
||||
}
|
||||
|
||||
public int getWrapSizeLimit(int qop, boolean confReq,
|
||||
int maxTokenSize) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getWrapSizeLimit(qop, confReq, maxTokenSize);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte[] wrap(byte inBuf[], int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.wrap(inBuf, offset, len, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void wrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.wrap(inStream, outStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte [] unwrap(byte[] inBuf, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.unwrap(inBuf, offset, len, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void unwrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.unwrap(inStream, outStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte[] getMIC(byte []inMsg, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getMIC(inMsg, offset, len, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void getMIC(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.getMIC(inStream, outStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void verifyMIC(byte[] inTok, int tokOffset, int tokLen,
|
||||
byte[] inMsg, int msgOffset, int msgLen,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.verifyMIC(inTok, tokOffset, tokLen,
|
||||
inMsg, msgOffset, msgLen, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public void verifyMIC(InputStream tokStream, InputStream msgStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
mechCtxt.verifyMIC(tokStream, msgStream, msgProp);
|
||||
else
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
}
|
||||
|
||||
public byte[] export() throws GSSException {
|
||||
// Defaults to null to match old behavior
|
||||
byte[] result = null;
|
||||
// Only allow context export from native provider since JGSS
|
||||
// still has not defined its own interprocess token format
|
||||
if (mechCtxt.isTransferable() &&
|
||||
mechCtxt.getProvider().getName().equals("SunNativeGSS")) {
|
||||
result = mechCtxt.export();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void requestMutualAuth(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqMutualAuthState = state;
|
||||
}
|
||||
|
||||
public void requestReplayDet(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqReplayDetState = state;
|
||||
}
|
||||
|
||||
public void requestSequenceDet(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqSequenceDetState = state;
|
||||
}
|
||||
|
||||
public void requestCredDeleg(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqCredDelegState = state;
|
||||
}
|
||||
|
||||
public void requestAnonymity(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqAnonState = state;
|
||||
}
|
||||
|
||||
public void requestConf(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqConfState = state;
|
||||
}
|
||||
|
||||
public void requestInteg(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqIntegState = state;
|
||||
}
|
||||
|
||||
public void requestLifetime(int lifetime) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqLifetime = lifetime;
|
||||
}
|
||||
|
||||
public void setChannelBinding(ChannelBinding channelBindings)
|
||||
throws GSSException {
|
||||
|
||||
if (mechCtxt == null)
|
||||
this.channelBindings = channelBindings;
|
||||
|
||||
}
|
||||
|
||||
public boolean getCredDelegState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getCredDelegState();
|
||||
else
|
||||
return reqCredDelegState;
|
||||
}
|
||||
|
||||
public boolean getMutualAuthState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getMutualAuthState();
|
||||
else
|
||||
return reqMutualAuthState;
|
||||
}
|
||||
|
||||
public boolean getReplayDetState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getReplayDetState();
|
||||
else
|
||||
return reqReplayDetState;
|
||||
}
|
||||
|
||||
public boolean getSequenceDetState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getSequenceDetState();
|
||||
else
|
||||
return reqSequenceDetState;
|
||||
}
|
||||
|
||||
public boolean getAnonymityState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getAnonymityState();
|
||||
else
|
||||
return reqAnonState;
|
||||
}
|
||||
|
||||
public boolean isTransferable() throws GSSException {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.isTransferable();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isProtReady() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.isProtReady();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean getConfState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getConfState();
|
||||
else
|
||||
return reqConfState;
|
||||
}
|
||||
|
||||
public boolean getIntegState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getIntegState();
|
||||
else
|
||||
return reqIntegState;
|
||||
}
|
||||
|
||||
public int getLifetime() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getLifetime();
|
||||
else
|
||||
return reqLifetime;
|
||||
}
|
||||
|
||||
public GSSName getSrcName() throws GSSException {
|
||||
if (srcName == null) {
|
||||
srcName = GSSNameImpl.wrapElement
|
||||
(gssManager, mechCtxt.getSrcName());
|
||||
}
|
||||
return srcName;
|
||||
}
|
||||
|
||||
public GSSName getTargName() throws GSSException {
|
||||
if (targName == null) {
|
||||
targName = GSSNameImpl.wrapElement
|
||||
(gssManager, mechCtxt.getTargName());
|
||||
}
|
||||
return targName;
|
||||
}
|
||||
|
||||
public Oid getMech() throws GSSException {
|
||||
if (mechCtxt != null) {
|
||||
return mechCtxt.getMech();
|
||||
}
|
||||
return mechOid;
|
||||
}
|
||||
|
||||
public GSSCredential getDelegCred() throws GSSException {
|
||||
|
||||
if (mechCtxt == null)
|
||||
throw new GSSExceptionImpl(GSSException.NO_CONTEXT,
|
||||
"No mechanism context yet!");
|
||||
GSSCredentialSpi delCredElement = mechCtxt.getDelegCred();
|
||||
return (delCredElement == null ?
|
||||
null : new GSSCredentialImpl(gssManager, delCredElement));
|
||||
}
|
||||
|
||||
public boolean isInitiator() throws GSSException {
|
||||
return initiator;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
currentState = DELETED;
|
||||
if (mechCtxt != null) {
|
||||
mechCtxt.dispose();
|
||||
mechCtxt = null;
|
||||
}
|
||||
myCred = null;
|
||||
srcName = null;
|
||||
targName = null;
|
||||
}
|
||||
|
||||
// ExtendedGSSContext methods:
|
||||
|
||||
@Override
|
||||
public Object inquireSecContext(InquireType type) throws GSSException {
|
||||
SecurityManager security = System.getSecurityManager();
|
||||
if (security != null) {
|
||||
security.checkPermission(new InquireSecContextPermission(type.toString()));
|
||||
}
|
||||
if (mechCtxt == null) {
|
||||
throw new GSSException(GSSException.NO_CONTEXT);
|
||||
}
|
||||
return mechCtxt.inquireSecContext(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDelegPolicy(boolean state) throws GSSException {
|
||||
if (mechCtxt == null && initiator)
|
||||
reqDelegPolicyState = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDelegPolicyState() {
|
||||
if (mechCtxt != null)
|
||||
return mechCtxt.getDelegPolicyState();
|
||||
else
|
||||
return reqDelegPolicyState;
|
||||
}
|
||||
}
|
||||
690
jdkSrc/jdk8/sun/security/jgss/GSSCredentialImpl.java
Normal file
690
jdkSrc/jdk8/sun/security/jgss/GSSCredentialImpl.java
Normal file
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import java.util.*;
|
||||
import com.sun.security.jgss.*;
|
||||
import sun.security.jgss.spnego.SpNegoCredElement;
|
||||
|
||||
public class GSSCredentialImpl implements ExtendedGSSCredential {
|
||||
|
||||
private GSSManagerImpl gssManager = null;
|
||||
private boolean destroyed = false;
|
||||
|
||||
/*
|
||||
* We store all elements in a hashtable, using <oid, usage> as the
|
||||
* key. This makes it easy to locate the specific kind of credential we
|
||||
* need. The implementation needs to be optimized for the case where
|
||||
* there is just one element (tempCred).
|
||||
*/
|
||||
private Hashtable<SearchKey, GSSCredentialSpi> hashtable = null;
|
||||
|
||||
// XXX Optimization for single mech usage
|
||||
private GSSCredentialSpi tempCred = null;
|
||||
|
||||
GSSCredentialImpl(GSSManagerImpl gssManager, int usage)
|
||||
throws GSSException {
|
||||
this(gssManager, null, GSSCredential.DEFAULT_LIFETIME,
|
||||
(Oid[]) null, usage);
|
||||
}
|
||||
|
||||
GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
|
||||
int lifetime, Oid mech, int usage)
|
||||
throws GSSException {
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
init(gssManager);
|
||||
add(name, lifetime, lifetime, mech, usage);
|
||||
}
|
||||
|
||||
GSSCredentialImpl(GSSManagerImpl gssManager, GSSName name,
|
||||
int lifetime, Oid mechs[], int usage)
|
||||
throws GSSException {
|
||||
init(gssManager);
|
||||
boolean defaultList = false;
|
||||
if (mechs == null) {
|
||||
mechs = gssManager.getMechs();
|
||||
defaultList = true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
try {
|
||||
add(name, lifetime, lifetime, mechs[i], usage);
|
||||
} catch (GSSException e) {
|
||||
if (defaultList) {
|
||||
// Try the next mechanism
|
||||
GSSUtil.debug("Ignore " + e + " while acquring cred for "
|
||||
+ mechs[i]);
|
||||
//e.printStackTrace();
|
||||
} else throw e; // else try the next mechanism
|
||||
}
|
||||
}
|
||||
if ((hashtable.size() == 0) || (usage != getUsage()))
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
|
||||
// Wrap a mech cred into a GSS cred
|
||||
public GSSCredentialImpl(GSSManagerImpl gssManager,
|
||||
GSSCredentialSpi mechElement) throws GSSException {
|
||||
|
||||
init(gssManager);
|
||||
int usage = GSSCredential.ACCEPT_ONLY;
|
||||
if (mechElement.isInitiatorCredential()) {
|
||||
if (mechElement.isAcceptorCredential()) {
|
||||
usage = GSSCredential.INITIATE_AND_ACCEPT;
|
||||
} else {
|
||||
usage = GSSCredential.INITIATE_ONLY;
|
||||
}
|
||||
}
|
||||
SearchKey key = new SearchKey(mechElement.getMechanism(),
|
||||
usage);
|
||||
tempCred = mechElement;
|
||||
hashtable.put(key, tempCred);
|
||||
// More mechs that can use this cred, say, SPNEGO
|
||||
if (!GSSUtil.isSpNegoMech(mechElement.getMechanism())) {
|
||||
key = new SearchKey(GSSUtil.GSS_SPNEGO_MECH_OID, usage);
|
||||
hashtable.put(key, new SpNegoCredElement(mechElement));
|
||||
}
|
||||
}
|
||||
|
||||
void init(GSSManagerImpl gssManager) {
|
||||
this.gssManager = gssManager;
|
||||
hashtable = new Hashtable<SearchKey, GSSCredentialSpi>(
|
||||
gssManager.getMechs().length);
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
if (!destroyed) {
|
||||
GSSCredentialSpi element;
|
||||
Enumeration<GSSCredentialSpi> values = hashtable.elements();
|
||||
while (values.hasMoreElements()) {
|
||||
element = values.nextElement();
|
||||
element.dispose();
|
||||
}
|
||||
destroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public GSSCredential impersonate(GSSName name) throws GSSException {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
Oid mech = tempCred.getMechanism();
|
||||
GSSNameSpi nameElement = (name == null ? null :
|
||||
((GSSNameImpl)name).getElement(mech));
|
||||
GSSCredentialSpi cred = tempCred.impersonate(nameElement);
|
||||
return (cred == null ?
|
||||
null : new GSSCredentialImpl(gssManager, cred));
|
||||
}
|
||||
|
||||
public GSSName getName() throws GSSException {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
return GSSNameImpl.wrapElement(gssManager, tempCred.getName());
|
||||
}
|
||||
|
||||
public GSSName getName(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey key = null;
|
||||
GSSCredentialSpi element = null;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element == null) {
|
||||
key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
|
||||
return GSSNameImpl.wrapElement(gssManager, element.getName());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the remaining lifetime of this credential. The remaining
|
||||
* lifetime is defined as the minimum lifetime, either for initiate or
|
||||
* for accept, across all elements contained in it. Not terribly
|
||||
* useful, but required by GSS-API.
|
||||
*/
|
||||
public int getRemainingLifetime() throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey tempKey;
|
||||
GSSCredentialSpi tempCred;
|
||||
int tempLife = 0, tempInitLife = 0, tempAcceptLife = 0;
|
||||
int min = INDEFINITE_LIFETIME;
|
||||
|
||||
for (Enumeration<SearchKey> e = hashtable.keys();
|
||||
e.hasMoreElements(); ) {
|
||||
tempKey = e.nextElement();
|
||||
tempCred = hashtable.get(tempKey);
|
||||
if (tempKey.getUsage() == INITIATE_ONLY)
|
||||
tempLife = tempCred.getInitLifetime();
|
||||
else if (tempKey.getUsage() == ACCEPT_ONLY)
|
||||
tempLife = tempCred.getAcceptLifetime();
|
||||
else {
|
||||
tempInitLife = tempCred.getInitLifetime();
|
||||
tempAcceptLife = tempCred.getAcceptLifetime();
|
||||
tempLife = (tempInitLife < tempAcceptLife ?
|
||||
tempInitLife:
|
||||
tempAcceptLife);
|
||||
}
|
||||
if (min > tempLife)
|
||||
min = tempLife;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
public int getRemainingInitLifetime(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
SearchKey key = null;
|
||||
boolean found = false;
|
||||
int max = 0;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getInitLifetime())
|
||||
max = element.getInitLifetime();
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getInitLifetime())
|
||||
max = element.getInitLifetime();
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
|
||||
return max;
|
||||
|
||||
}
|
||||
|
||||
public int getRemainingAcceptLifetime(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
SearchKey key = null;
|
||||
boolean found = false;
|
||||
int max = 0;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getAcceptLifetime())
|
||||
max = element.getAcceptLifetime();
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
found = true;
|
||||
if (max < element.getAcceptLifetime())
|
||||
max = element.getAcceptLifetime();
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
|
||||
return max;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the usage mode for this credential. Returns
|
||||
* INITIATE_AND_ACCEPT if any one element contained in it supports
|
||||
* INITIATE_AND_ACCEPT or if two different elements exist where one
|
||||
* support INITIATE_ONLY and the other supports ACCEPT_ONLY.
|
||||
*/
|
||||
public int getUsage() throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey tempKey;
|
||||
boolean initiate = false;
|
||||
boolean accept = false;
|
||||
|
||||
for (Enumeration<SearchKey> e = hashtable.keys();
|
||||
e.hasMoreElements(); ) {
|
||||
tempKey = e.nextElement();
|
||||
if (tempKey.getUsage() == INITIATE_ONLY)
|
||||
initiate = true;
|
||||
else if (tempKey.getUsage() == ACCEPT_ONLY)
|
||||
accept = true;
|
||||
else
|
||||
return INITIATE_AND_ACCEPT;
|
||||
}
|
||||
if (initiate) {
|
||||
if (accept)
|
||||
return INITIATE_AND_ACCEPT;
|
||||
else
|
||||
return INITIATE_ONLY;
|
||||
} else
|
||||
return ACCEPT_ONLY;
|
||||
}
|
||||
|
||||
public int getUsage(Oid mech) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
SearchKey key = null;
|
||||
boolean initiate = false;
|
||||
boolean accept = false;
|
||||
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
initiate = true;
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
accept = true;
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, GSSCredential.INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element != null) {
|
||||
initiate = true;
|
||||
accept = true;
|
||||
}
|
||||
|
||||
if (initiate && accept)
|
||||
return GSSCredential.INITIATE_AND_ACCEPT;
|
||||
else if (initiate)
|
||||
return GSSCredential.INITIATE_ONLY;
|
||||
else if (accept)
|
||||
return GSSCredential.ACCEPT_ONLY;
|
||||
else {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mech);
|
||||
}
|
||||
}
|
||||
|
||||
public Oid[] getMechs() throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
Vector<Oid> result = new Vector<Oid>(hashtable.size());
|
||||
|
||||
for (Enumeration<SearchKey> e = hashtable.keys();
|
||||
e.hasMoreElements(); ) {
|
||||
SearchKey tempKey = e.nextElement();
|
||||
result.addElement(tempKey.getMech());
|
||||
}
|
||||
return result.toArray(new Oid[0]);
|
||||
}
|
||||
|
||||
public void add(GSSName name, int initLifetime, int acceptLifetime,
|
||||
Oid mech, int usage) throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
SearchKey key = new SearchKey(mech, usage);
|
||||
if (hashtable.containsKey(key)) {
|
||||
throw new GSSExceptionImpl(GSSException.DUPLICATE_ELEMENT,
|
||||
"Duplicate element found: " +
|
||||
getElementStr(mech, usage));
|
||||
}
|
||||
|
||||
// XXX If not instance of GSSNameImpl then throw exception
|
||||
// Application mixing GSS implementations
|
||||
GSSNameSpi nameElement = (name == null ? null :
|
||||
((GSSNameImpl)name).getElement(mech));
|
||||
|
||||
tempCred = gssManager.getCredentialElement(nameElement,
|
||||
initLifetime,
|
||||
acceptLifetime,
|
||||
mech,
|
||||
usage);
|
||||
/*
|
||||
* Not all mechanisms support the concept of one credential element
|
||||
* that can be used for both initiating and accepting a context. In
|
||||
* the event that an application requests usage INITIATE_AND_ACCEPT
|
||||
* for a credential from such a mechanism, the GSS framework will
|
||||
* need to obtain two different credential elements from the
|
||||
* mechanism, one that will have usage INITIATE_ONLY and another
|
||||
* that will have usage ACCEPT_ONLY. The mechanism will help the
|
||||
* GSS-API realize this by returning a credential element with
|
||||
* usage INITIATE_ONLY or ACCEPT_ONLY prompting it to make another
|
||||
* call to getCredentialElement, this time with the other usage
|
||||
* mode.
|
||||
*/
|
||||
|
||||
if (tempCred != null) {
|
||||
if (usage == GSSCredential.INITIATE_AND_ACCEPT &&
|
||||
(!tempCred.isAcceptorCredential() ||
|
||||
!tempCred.isInitiatorCredential())) {
|
||||
|
||||
int currentUsage;
|
||||
int desiredUsage;
|
||||
|
||||
if (!tempCred.isInitiatorCredential()) {
|
||||
currentUsage = GSSCredential.ACCEPT_ONLY;
|
||||
desiredUsage = GSSCredential.INITIATE_ONLY;
|
||||
} else {
|
||||
currentUsage = GSSCredential.INITIATE_ONLY;
|
||||
desiredUsage = GSSCredential.ACCEPT_ONLY;
|
||||
}
|
||||
|
||||
key = new SearchKey(mech, currentUsage);
|
||||
hashtable.put(key, tempCred);
|
||||
|
||||
tempCred = gssManager.getCredentialElement(nameElement,
|
||||
initLifetime,
|
||||
acceptLifetime,
|
||||
mech,
|
||||
desiredUsage);
|
||||
|
||||
key = new SearchKey(mech, desiredUsage);
|
||||
hashtable.put(key, tempCred);
|
||||
} else {
|
||||
hashtable.put(key, tempCred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(Object another) {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
if (this == another) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(another instanceof GSSCredentialImpl)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE: The specification does not define the criteria to compare
|
||||
// credentials.
|
||||
/*
|
||||
* XXX
|
||||
* The RFC says: "Tests if this GSSCredential refers to the same
|
||||
* entity as the supplied object. The two credentials must be
|
||||
* acquired over the same mechanisms and must refer to the same
|
||||
* principal. Returns "true" if the two GSSCredentials refer to
|
||||
* the same entity; "false" otherwise."
|
||||
*
|
||||
* Well, when do two credentials refer to the same principal? Do
|
||||
* they need to have one GSSName in common for the different
|
||||
* GSSName's that the credential elements return? Or do all
|
||||
* GSSName's have to be in common when the names are exported with
|
||||
* their respective mechanisms for the credential elements?
|
||||
*/
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSCredential.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode() {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
// NOTE: The specification does not define the criteria to compare
|
||||
// credentials.
|
||||
/*
|
||||
* XXX
|
||||
* Decide on a criteria for equals first then do this.
|
||||
*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified mechanism's credential-element.
|
||||
*
|
||||
* @param mechOid the oid for mechanism to retrieve
|
||||
* @param initiate boolean indicating if the function is
|
||||
* to throw exception or return null when element is not
|
||||
* found.
|
||||
* @return mechanism credential object
|
||||
* @exception GSSException of invalid mechanism
|
||||
*/
|
||||
public GSSCredentialSpi getElement(Oid mechOid, boolean initiate)
|
||||
throws GSSException {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
SearchKey key;
|
||||
GSSCredentialSpi element;
|
||||
|
||||
if (mechOid == null) {
|
||||
/*
|
||||
* First see if the default mechanism satisfies the
|
||||
* desired usage.
|
||||
*/
|
||||
mechOid = ProviderList.DEFAULT_MECH_OID;
|
||||
key = new SearchKey(mechOid,
|
||||
initiate? INITIATE_ONLY : ACCEPT_ONLY);
|
||||
element = hashtable.get(key);
|
||||
if (element == null) {
|
||||
key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
if (element == null) {
|
||||
/*
|
||||
* Now just return any element that satisfies the
|
||||
* desired usage.
|
||||
*/
|
||||
Object[] elements = hashtable.entrySet().toArray();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
element = (GSSCredentialSpi)
|
||||
((Map.Entry)elements[i]).getValue();
|
||||
if (element.isInitiatorCredential() == initiate)
|
||||
break;
|
||||
} // for loop
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
if (initiate)
|
||||
key = new SearchKey(mechOid, INITIATE_ONLY);
|
||||
else
|
||||
key = new SearchKey(mechOid, ACCEPT_ONLY);
|
||||
|
||||
element = hashtable.get(key);
|
||||
|
||||
if (element == null) {
|
||||
key = new SearchKey(mechOid, INITIATE_AND_ACCEPT);
|
||||
element = hashtable.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (element == null)
|
||||
throw new GSSExceptionImpl(GSSException.NO_CRED,
|
||||
"No credential found for: " +
|
||||
getElementStr(mechOid,
|
||||
initiate? INITIATE_ONLY : ACCEPT_ONLY));
|
||||
return element;
|
||||
}
|
||||
|
||||
Set<GSSCredentialSpi> getElements() {
|
||||
HashSet<GSSCredentialSpi> retVal =
|
||||
new HashSet<GSSCredentialSpi>(hashtable.size());
|
||||
Enumeration<GSSCredentialSpi> values = hashtable.elements();
|
||||
while (values.hasMoreElements()) {
|
||||
GSSCredentialSpi o = values.nextElement();
|
||||
retVal.add(o);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static String getElementStr(Oid mechOid, int usage) {
|
||||
String displayString = mechOid.toString();
|
||||
if (usage == GSSCredential.INITIATE_ONLY) {
|
||||
displayString =
|
||||
displayString.concat(" usage: Initiate");
|
||||
} else if (usage == GSSCredential.ACCEPT_ONLY) {
|
||||
displayString =
|
||||
displayString.concat(" usage: Accept");
|
||||
} else {
|
||||
displayString =
|
||||
displayString.concat(" usage: Initiate and Accept");
|
||||
}
|
||||
return displayString;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This credential is " +
|
||||
"no longer valid");
|
||||
}
|
||||
|
||||
GSSCredentialSpi element = null;
|
||||
StringBuffer buffer = new StringBuffer("[GSSCredential: ");
|
||||
Object[] elements = hashtable.entrySet().toArray();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
try {
|
||||
buffer.append('\n');
|
||||
element = (GSSCredentialSpi)
|
||||
((Map.Entry)elements[i]).getValue();
|
||||
buffer.append(element.getName());
|
||||
buffer.append(' ');
|
||||
buffer.append(element.getMechanism());
|
||||
buffer.append(element.isInitiatorCredential() ?
|
||||
" Initiate" : "");
|
||||
buffer.append(element.isAcceptorCredential() ?
|
||||
" Accept" : "");
|
||||
buffer.append(" [");
|
||||
buffer.append(element.getClass());
|
||||
buffer.append(']');
|
||||
} catch (GSSException e) {
|
||||
// skip to next element
|
||||
}
|
||||
}
|
||||
buffer.append(']');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
static class SearchKey {
|
||||
private Oid mechOid = null;
|
||||
private int usage = GSSCredential.INITIATE_AND_ACCEPT;
|
||||
public SearchKey(Oid mechOid, int usage) {
|
||||
|
||||
this.mechOid = mechOid;
|
||||
this.usage = usage;
|
||||
}
|
||||
public Oid getMech() {
|
||||
return mechOid;
|
||||
}
|
||||
public int getUsage() {
|
||||
return usage;
|
||||
}
|
||||
public boolean equals(Object other) {
|
||||
if (! (other instanceof SearchKey))
|
||||
return false;
|
||||
SearchKey that = (SearchKey) other;
|
||||
return ((this.mechOid.equals(that.mechOid)) &&
|
||||
(this.usage == that.usage));
|
||||
}
|
||||
public int hashCode() {
|
||||
return mechOid.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
89
jdkSrc/jdk8/sun/security/jgss/GSSExceptionImpl.java
Normal file
89
jdkSrc/jdk8/sun/security/jgss/GSSExceptionImpl.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, 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;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
|
||||
/**
|
||||
* This class helps overcome a limitation of the org.ietf.jgss.GSSException
|
||||
* class that does not allow the thrower to set a string corresponding to
|
||||
* the major code.
|
||||
*/
|
||||
public class GSSExceptionImpl extends GSSException {
|
||||
|
||||
private static final long serialVersionUID = 4251197939069005575L;
|
||||
|
||||
private String majorMessage;
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode as well as the mech oid that
|
||||
* will be appended to the standard message defined in its super class.
|
||||
*/
|
||||
GSSExceptionImpl(int majorCode, Oid mech) {
|
||||
super(majorCode);
|
||||
this.majorMessage = super.getMajorString() + ": " + mech;
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode as well as the message that
|
||||
* corresponds to it.
|
||||
*/
|
||||
public GSSExceptionImpl(int majorCode, String majorMessage) {
|
||||
super(majorCode);
|
||||
this.majorMessage = majorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode and the exception cause.
|
||||
*/
|
||||
public GSSExceptionImpl(int majorCode, Exception cause) {
|
||||
super(majorCode);
|
||||
initCause(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor that takes the majorCode, the message that
|
||||
* corresponds to it, and the exception cause.
|
||||
*/
|
||||
public GSSExceptionImpl(int majorCode, String majorMessage,
|
||||
Exception cause) {
|
||||
this(majorCode, majorMessage);
|
||||
initCause(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message that was embedded in this object, otherwise it
|
||||
* returns the default message that an org.ietf.jgss.GSSException
|
||||
* generates.
|
||||
*/
|
||||
public String getMessage() {
|
||||
if (majorMessage != null)
|
||||
return majorMessage;
|
||||
else
|
||||
return super.getMessage();
|
||||
}
|
||||
|
||||
}
|
||||
345
jdkSrc/jdk8/sun/security/jgss/GSSHeader.java
Normal file
345
jdkSrc/jdk8/sun/security/jgss/GSSHeader.java
Normal file
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, 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;
|
||||
|
||||
import org.ietf.jgss.GSSException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* This class represents the mechanism independent part of a GSS-API
|
||||
* context establishment token. Some mechanisms may choose to encode
|
||||
* all subsequent tokens as well such that they start with an encoding
|
||||
* of an instance of this class. e.g., The Kerberos v5 GSS-API Mechanism
|
||||
* uses this header for all GSS-API tokens.
|
||||
* <p>
|
||||
* The format is specified in RFC 2743 section 3.1.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
/*
|
||||
* The RFC states that implementations should explicitly follow the
|
||||
* encoding scheme descibed in this section rather than use ASN.1
|
||||
* compilers. However, we should consider removing duplicate ASN.1
|
||||
* like code from here and depend on sun.security.util if possible.
|
||||
*/
|
||||
|
||||
public class GSSHeader {
|
||||
|
||||
private ObjectIdentifier mechOid = null;
|
||||
private byte[] mechOidBytes = null;
|
||||
private int mechTokenLength = 0;
|
||||
|
||||
/**
|
||||
* The tag defined in the GSS-API mechanism independent token
|
||||
* format.
|
||||
*/
|
||||
public static final int TOKEN_ID=0x60;
|
||||
|
||||
/**
|
||||
* Creates a GSSHeader instance whose encoding can be used as the
|
||||
* prefix for a particular mechanism token.
|
||||
* @param mechOid the Oid of the mechanism which generated the token
|
||||
* @param mechTokenLength the length of the subsequent portion that
|
||||
* the mechanism will be adding.
|
||||
*/
|
||||
public GSSHeader(ObjectIdentifier mechOid, int mechTokenLength)
|
||||
throws IOException {
|
||||
|
||||
this.mechOid = mechOid;
|
||||
DerOutputStream temp = new DerOutputStream();
|
||||
temp.putOID(mechOid);
|
||||
mechOidBytes = temp.toByteArray();
|
||||
this.mechTokenLength = mechTokenLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads in a GSSHeader from an InputStream. Typically this would be
|
||||
* used as part of reading the complete token from an InputStream
|
||||
* that is obtained from a socket.
|
||||
*/
|
||||
public GSSHeader(InputStream is)
|
||||
throws IOException, GSSException {
|
||||
|
||||
// debug("Parsing GSS token: ");
|
||||
|
||||
int tag = is.read();
|
||||
|
||||
// debug("tag=" + tag);
|
||||
|
||||
if (tag != TOKEN_ID)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"GSSHeader did not find the right tag");
|
||||
|
||||
int length = getLength(is);
|
||||
|
||||
DerValue temp = new DerValue(is);
|
||||
mechOidBytes = temp.toByteArray();
|
||||
mechOid = temp.getOID();
|
||||
// debug (" oid=" + mechOid);
|
||||
|
||||
// debug (" len starting with oid=" + length);
|
||||
mechTokenLength = length - mechOidBytes.length;
|
||||
|
||||
// debug(" mechToken length=" + mechTokenLength);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the Oid stored in this GSSHeader instance.
|
||||
* @return the Oid of the mechanism.
|
||||
*/
|
||||
public ObjectIdentifier getOid() {
|
||||
return mechOid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the length of the mechanism specific token that
|
||||
* will follow the encoding of this GSSHeader instance.
|
||||
* @return the length of the mechanism specific token portion that
|
||||
* will follow this GSSHeader.
|
||||
*/
|
||||
public int getMechTokenLength() {
|
||||
return mechTokenLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the length of the encoding of this GSSHeader.
|
||||
* @return the lenght of the encoding of this GSSHeader instance.
|
||||
*/
|
||||
public int getLength() {
|
||||
int lenField = mechOidBytes.length + mechTokenLength;
|
||||
return (1 + getLenFieldSize(lenField) + mechOidBytes.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine what the maximum possible mechanism token
|
||||
* size is if the complete GSSToken returned to the application
|
||||
* (including a GSSHeader) is not to exceed some pre-determined
|
||||
* value in size.
|
||||
* @param mechOid the Oid of the mechanism that will generate
|
||||
* this GSS-API token
|
||||
* @param maxTotalSize the pre-determined value that serves as a
|
||||
* maximum size for the complete GSS-API token (including a
|
||||
* GSSHeader)
|
||||
* @return the maximum size of mechanism token that can be used
|
||||
* so as to not exceed maxTotalSize with the GSS-API token
|
||||
*/
|
||||
public static int getMaxMechTokenSize(ObjectIdentifier mechOid,
|
||||
int maxTotalSize) {
|
||||
|
||||
int mechOidBytesSize = 0;
|
||||
try {
|
||||
DerOutputStream temp = new DerOutputStream();
|
||||
temp.putOID(mechOid);
|
||||
mechOidBytesSize = temp.toByteArray().length;
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
// Subtract bytes needed for 0x60 tag and mechOidBytes
|
||||
maxTotalSize -= (1 + mechOidBytesSize);
|
||||
|
||||
// Subtract maximum len bytes
|
||||
maxTotalSize -= 5;
|
||||
|
||||
return maxTotalSize;
|
||||
|
||||
/*
|
||||
* Len field and mechanism token must fit in remaining
|
||||
* space. The range of the len field that we allow is
|
||||
* 1 through 5.
|
||||
*
|
||||
|
||||
int mechTokenSize = 0;
|
||||
for (int lenFieldSize = 1; lenFieldSize <= 5;
|
||||
lenFieldSize++) {
|
||||
mechTokenSize = maxTotalSize - lenFieldSize;
|
||||
if (getLenFieldSize(mechTokenSize + mechOidBytesSize +
|
||||
lenFieldSize) <= lenFieldSize)
|
||||
break;
|
||||
}
|
||||
|
||||
return mechTokenSize;
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the number of bytes that will be need to encode
|
||||
* the length field of the GSSHeader.
|
||||
*/
|
||||
private int getLenFieldSize(int len) {
|
||||
int retVal = 1;
|
||||
if (len < 128) {
|
||||
retVal=1;
|
||||
} else if (len < (1 << 8)) {
|
||||
retVal=2;
|
||||
} else if (len < (1 << 16)) {
|
||||
retVal=3;
|
||||
} else if (len < (1 << 24)) {
|
||||
retVal=4;
|
||||
} else {
|
||||
retVal=5; // See getMaxMechTokenSize
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes this GSSHeader instance onto the provided OutputStream.
|
||||
* @param os the OutputStream to which the token should be written.
|
||||
* @return the number of bytes that are output as a result of this
|
||||
* encoding
|
||||
*/
|
||||
public int encode(OutputStream os) throws IOException {
|
||||
int retVal = 1 + mechOidBytes.length;
|
||||
os.write(TOKEN_ID);
|
||||
int length = mechOidBytes.length + mechTokenLength;
|
||||
retVal += putLength(length, os);
|
||||
os.write(mechOidBytes);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a length from the input stream, allowing for at most 32 bits of
|
||||
* encoding to be used. (Not the same as getting a tagged integer!)
|
||||
*
|
||||
* @return the length or -1 if indefinite length found.
|
||||
* @exception IOException on parsing error or unsupported lengths.
|
||||
*/
|
||||
// shameless lifted from sun.security.util.DerInputStream.
|
||||
private int getLength(InputStream in) throws IOException {
|
||||
return getLength(in.read(), in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a length from the input stream, allowing for at most 32 bits of
|
||||
* encoding to be used. (Not the same as getting a tagged integer!)
|
||||
*
|
||||
* @return the length or -1 if indefinite length found.
|
||||
* @exception IOException on parsing error or unsupported lengths.
|
||||
*/
|
||||
// shameless lifted from sun.security.util.DerInputStream.
|
||||
private int getLength(int lenByte, InputStream in) throws IOException {
|
||||
int value, tmp;
|
||||
|
||||
tmp = lenByte;
|
||||
if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
|
||||
value = tmp;
|
||||
} else { // long form or indefinite
|
||||
tmp &= 0x07f;
|
||||
|
||||
/*
|
||||
* NOTE: tmp == 0 indicates indefinite length encoded data.
|
||||
* tmp > 4 indicates more than 4Gb of data.
|
||||
*/
|
||||
if (tmp == 0)
|
||||
return -1;
|
||||
if (tmp < 0 || tmp > 4)
|
||||
throw new IOException("DerInputStream.getLength(): lengthTag="
|
||||
+ tmp + ", "
|
||||
+ ((tmp < 0) ? "incorrect DER encoding." : "too big."));
|
||||
|
||||
for (value = 0; tmp > 0; tmp --) {
|
||||
value <<= 8;
|
||||
value += 0x0ff & in.read();
|
||||
}
|
||||
if (value < 0) {
|
||||
throw new IOException("Invalid length bytes");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the encoding of the length in the specified stream.
|
||||
*
|
||||
* @params len the length of the attribute.
|
||||
* @param out the outputstream to write the length to
|
||||
* @return the number of bytes written
|
||||
* @exception IOException on writing errors.
|
||||
*/
|
||||
// Shameless lifted from sun.security.util.DerOutputStream.
|
||||
private int putLength(int len, OutputStream out) throws IOException {
|
||||
int retVal = 0;
|
||||
if (len < 128) {
|
||||
out.write((byte)len);
|
||||
retVal=1;
|
||||
|
||||
} else if (len < (1 << 8)) {
|
||||
out.write((byte)0x081);
|
||||
out.write((byte)len);
|
||||
retVal=2;
|
||||
|
||||
} else if (len < (1 << 16)) {
|
||||
out.write((byte)0x082);
|
||||
out.write((byte)(len >> 8));
|
||||
out.write((byte)len);
|
||||
retVal=3;
|
||||
|
||||
} else if (len < (1 << 24)) {
|
||||
out.write((byte)0x083);
|
||||
out.write((byte)(len >> 16));
|
||||
out.write((byte)(len >> 8));
|
||||
out.write((byte)len);
|
||||
retVal=4;
|
||||
|
||||
} else {
|
||||
out.write((byte)0x084);
|
||||
out.write((byte)(len >> 24));
|
||||
out.write((byte)(len >> 16));
|
||||
out.write((byte)(len >> 8));
|
||||
out.write((byte)len);
|
||||
retVal=5;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
// XXX Call these two in some central class
|
||||
private void debug(String str) {
|
||||
System.err.print(str);
|
||||
}
|
||||
|
||||
private String getHexBytes(byte[] bytes, int len)
|
||||
throws IOException {
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
int b1 = (bytes[i]>>4) & 0x0f;
|
||||
int b2 = bytes[i] & 0x0f;
|
||||
|
||||
sb.append(Integer.toHexString(b1));
|
||||
sb.append(Integer.toHexString(b2));
|
||||
sb.append(' ');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
254
jdkSrc/jdk8/sun/security/jgss/GSSManagerImpl.java
Normal file
254
jdkSrc/jdk8/sun/security/jgss/GSSManagerImpl.java
Normal file
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, 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;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import java.security.Provider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
/**
|
||||
* This class provides the default implementation of the GSSManager
|
||||
* interface.
|
||||
*/
|
||||
public class GSSManagerImpl extends GSSManager {
|
||||
|
||||
// Undocumented property
|
||||
private static final String USE_NATIVE_PROP =
|
||||
"sun.security.jgss.native";
|
||||
private static final Boolean USE_NATIVE;
|
||||
|
||||
static {
|
||||
USE_NATIVE =
|
||||
AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
return Boolean.valueOf(System.getProperty
|
||||
(USE_NATIVE_PROP));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private ProviderList list;
|
||||
|
||||
// Used by java SPNEGO impl to make sure native is disabled
|
||||
public GSSManagerImpl(GSSCaller caller, boolean useNative) {
|
||||
list = new ProviderList(caller, useNative);
|
||||
}
|
||||
|
||||
// Used by HTTP/SPNEGO NegotiatorImpl
|
||||
public GSSManagerImpl(GSSCaller caller) {
|
||||
list = new ProviderList(caller, USE_NATIVE);
|
||||
}
|
||||
|
||||
public GSSManagerImpl() {
|
||||
list = new ProviderList(GSSCaller.CALLER_UNKNOWN, USE_NATIVE);
|
||||
}
|
||||
|
||||
public Oid[] getMechs(){
|
||||
return list.getMechs();
|
||||
}
|
||||
|
||||
public Oid[] getNamesForMech(Oid mech)
|
||||
throws GSSException {
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getNameTypes().clone();
|
||||
}
|
||||
|
||||
public Oid[] getMechsForName(Oid nameType){
|
||||
Oid[] mechs = list.getMechs();
|
||||
Oid[] retVal = new Oid[mechs.length];
|
||||
int pos = 0;
|
||||
|
||||
// Compatibility with RFC 2853 old NT_HOSTBASED_SERVICE value.
|
||||
if (nameType.equals(GSSNameImpl.oldHostbasedServiceName)) {
|
||||
nameType = GSSName.NT_HOSTBASED_SERVICE;
|
||||
}
|
||||
|
||||
// Iterate thru all mechs in GSS
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
// what nametypes does this mech support?
|
||||
Oid mech = mechs[i];
|
||||
try {
|
||||
Oid[] namesForMech = getNamesForMech(mech);
|
||||
// Is the desired Oid present in that list?
|
||||
if (nameType.containedIn(namesForMech)) {
|
||||
retVal[pos++] = mech;
|
||||
}
|
||||
} catch (GSSException e) {
|
||||
// Squelch it and just skip over this mechanism
|
||||
GSSUtil.debug("Skip " + mech +
|
||||
": error retrieving supported name types");
|
||||
}
|
||||
}
|
||||
|
||||
// Trim the list if needed
|
||||
if (pos < retVal.length) {
|
||||
Oid[] temp = new Oid[pos];
|
||||
for (int i = 0; i < pos; i++)
|
||||
temp[i] = retVal[i];
|
||||
retVal = temp;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public GSSName createName(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
return new GSSNameImpl(this, nameStr, nameType);
|
||||
}
|
||||
|
||||
public GSSName createName(byte name[], Oid nameType)
|
||||
throws GSSException {
|
||||
return new GSSNameImpl(this, name, nameType);
|
||||
}
|
||||
|
||||
public GSSName createName(String nameStr, Oid nameType,
|
||||
Oid mech) throws GSSException {
|
||||
return new GSSNameImpl(this, nameStr, nameType, mech);
|
||||
}
|
||||
|
||||
public GSSName createName(byte name[], Oid nameType, Oid mech)
|
||||
throws GSSException {
|
||||
return new GSSNameImpl(this, name, nameType, mech);
|
||||
}
|
||||
|
||||
public GSSCredential createCredential(int usage)
|
||||
throws GSSException {
|
||||
return new GSSCredentialImpl(this, usage);
|
||||
}
|
||||
|
||||
public GSSCredential createCredential(GSSName aName,
|
||||
int lifetime, Oid mech, int usage)
|
||||
throws GSSException {
|
||||
return new GSSCredentialImpl(this, aName, lifetime, mech, usage);
|
||||
}
|
||||
|
||||
public GSSCredential createCredential(GSSName aName,
|
||||
int lifetime, Oid mechs[], int usage)
|
||||
throws GSSException {
|
||||
return new GSSCredentialImpl(this, aName, lifetime, mechs, usage);
|
||||
}
|
||||
|
||||
public GSSContext createContext(GSSName peer, Oid mech,
|
||||
GSSCredential myCred, int lifetime)
|
||||
throws GSSException {
|
||||
return new GSSContextImpl(this, peer, mech, myCred, lifetime);
|
||||
}
|
||||
|
||||
public GSSContext createContext(GSSCredential myCred)
|
||||
throws GSSException {
|
||||
return new GSSContextImpl(this, myCred);
|
||||
}
|
||||
|
||||
public GSSContext createContext(byte[] interProcessToken)
|
||||
throws GSSException {
|
||||
return new GSSContextImpl(this, interProcessToken);
|
||||
}
|
||||
|
||||
public void addProviderAtFront(Provider p, Oid mech)
|
||||
throws GSSException {
|
||||
list.addProviderAtFront(p, mech);
|
||||
}
|
||||
|
||||
public void addProviderAtEnd(Provider p, Oid mech)
|
||||
throws GSSException {
|
||||
list.addProviderAtEnd(p, mech);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name, int initLifetime,
|
||||
int acceptLifetime, Oid mech, int usage)
|
||||
throws GSSException {
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getCredentialElement(name, initLifetime,
|
||||
acceptLifetime, usage);
|
||||
}
|
||||
|
||||
// Used by java SPNEGO impl
|
||||
public GSSNameSpi getNameElement(String name, Oid nameType, Oid mech)
|
||||
throws GSSException {
|
||||
// Just use the most preferred MF impl assuming GSSNameSpi
|
||||
// objects are interoperable among providers
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getNameElement(name, nameType);
|
||||
}
|
||||
|
||||
// Used by java SPNEGO impl
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType, Oid mech)
|
||||
throws GSSException {
|
||||
// Just use the most preferred MF impl assuming GSSNameSpi
|
||||
// objects are interoperable among providers
|
||||
MechanismFactory factory = list.getMechFactory(mech);
|
||||
return factory.getNameElement(name, nameType);
|
||||
}
|
||||
|
||||
GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred,
|
||||
int lifetime, Oid mech)
|
||||
throws GSSException {
|
||||
Provider p = null;
|
||||
if (myInitiatorCred != null) {
|
||||
p = myInitiatorCred.getProvider();
|
||||
}
|
||||
MechanismFactory factory = list.getMechFactory(mech, p);
|
||||
return factory.getMechanismContext(peer, myInitiatorCred, lifetime);
|
||||
}
|
||||
|
||||
GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred,
|
||||
Oid mech)
|
||||
throws GSSException {
|
||||
Provider p = null;
|
||||
if (myAcceptorCred != null) {
|
||||
p = myAcceptorCred.getProvider();
|
||||
}
|
||||
MechanismFactory factory = list.getMechFactory(mech, p);
|
||||
return factory.getMechanismContext(myAcceptorCred);
|
||||
}
|
||||
|
||||
GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
if ((exportedContext == null) || (exportedContext.length == 0)) {
|
||||
throw new GSSException(GSSException.NO_CONTEXT);
|
||||
}
|
||||
GSSContextSpi result = null;
|
||||
|
||||
// Only allow context import with native provider since JGSS
|
||||
// still has not defined its own interprocess token format
|
||||
Oid[] mechs = list.getMechs();
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
MechanismFactory factory = list.getMechFactory(mechs[i]);
|
||||
if (factory.getProvider().getName().equals("SunNativeGSS")) {
|
||||
result = factory.getMechanismContext(exportedContext);
|
||||
if (result != null) break;
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
throw new GSSException(GSSException.UNAVAILABLE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
507
jdkSrc/jdk8/sun/security/jgss/GSSNameImpl.java
Normal file
507
jdkSrc/jdk8/sun/security/jgss/GSSNameImpl.java
Normal file
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, 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;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import java.util.Set;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Arrays;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
|
||||
/**
|
||||
* This is the implementation class for GSSName. Conceptually the
|
||||
* GSSName is a container with mechanism specific name elements. Each
|
||||
* name element is a representation of how that particular mechanism
|
||||
* would canonicalize this principal.
|
||||
*
|
||||
* Generally a GSSName is created by an application when it supplies
|
||||
* a sequence of bytes and a nametype that helps each mechanism
|
||||
* decide how to interpret those bytes.
|
||||
*
|
||||
* It is not necessary to create name elements for each available
|
||||
* mechanism at the time the application creates the GSSName. This
|
||||
* implementation does this lazily, as and when name elements for
|
||||
* mechanisms are required to be handed out. (Generally, other GSS
|
||||
* classes like GSSContext and GSSCredential request specific
|
||||
* elements depending on the mechanisms that they are dealing with.)
|
||||
* Assume that getting a mechanism to parse the applciation specified
|
||||
* bytes is an expensive call.
|
||||
*
|
||||
* When a GSSName is canonicalized wrt some mechanism, it is supposed
|
||||
* to discard all elements of other mechanisms and retain only the
|
||||
* element for this mechanism. In GSS terminology this is called a
|
||||
* Mechanism Name or MN. This implementation tries to retain the
|
||||
* application provided bytes and name type just in case the MN is
|
||||
* asked to produce an element for a mechanism that is different.
|
||||
*
|
||||
* When a GSSName is to be exported, the name element for the desired
|
||||
* mechanism is converted to a byte representation and written
|
||||
* out. It might happen that a name element for that mechanism cannot
|
||||
* be obtained. This happens when the mechanism is just not supported
|
||||
* in this GSS-API or when the mechanism is supported but bytes
|
||||
* corresponding to the nametypes that it understands are not
|
||||
* available in this GSSName.
|
||||
*
|
||||
* This class is safe for sharing. Each retrieval of a name element
|
||||
* from getElement() might potentially add a new element to the
|
||||
* hashmap of elements, but getElement() is synchronized.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class GSSNameImpl implements GSSName {
|
||||
|
||||
/**
|
||||
* The old Oid used in RFC 2853. Now supported as
|
||||
* input parameters in:
|
||||
*
|
||||
* 1. The four overloaded GSSManager.createName(*) methods
|
||||
* 2. GSSManager.getMechsForName(Oid)
|
||||
*
|
||||
* Note that even if a GSSName is created with this old Oid,
|
||||
* its internal name type and getStringNameType() output are
|
||||
* always the new value.
|
||||
*/
|
||||
final static Oid oldHostbasedServiceName;
|
||||
|
||||
static {
|
||||
Oid tmp = null;
|
||||
try {
|
||||
tmp = new Oid("1.3.6.1.5.6.2");
|
||||
} catch (Exception e) {
|
||||
// should never happen
|
||||
}
|
||||
oldHostbasedServiceName = tmp;
|
||||
}
|
||||
|
||||
private GSSManagerImpl gssManager = null;
|
||||
|
||||
/*
|
||||
* Store whatever the application passed in. We will use this to
|
||||
* get individual mechanisms to create name elements as and when
|
||||
* needed.
|
||||
* Store both the String and the byte[]. Leave I18N to the
|
||||
* mechanism by allowing it to extract bytes from the String!
|
||||
*/
|
||||
|
||||
private String appNameStr = null;
|
||||
private byte[] appNameBytes = null;
|
||||
private Oid appNameType = null;
|
||||
|
||||
/*
|
||||
* When we figure out what the printable name would be, we store
|
||||
* both the name and its type.
|
||||
*/
|
||||
|
||||
private String printableName = null;
|
||||
private Oid printableNameType = null;
|
||||
|
||||
private HashMap<Oid, GSSNameSpi> elements = null;
|
||||
private GSSNameSpi mechElement = null;
|
||||
|
||||
static GSSNameImpl wrapElement(GSSManagerImpl gssManager,
|
||||
GSSNameSpi mechElement) throws GSSException {
|
||||
return (mechElement == null ?
|
||||
null : new GSSNameImpl(gssManager, mechElement));
|
||||
}
|
||||
|
||||
GSSNameImpl(GSSManagerImpl gssManager, GSSNameSpi mechElement) {
|
||||
this.gssManager = gssManager;
|
||||
appNameStr = printableName = mechElement.toString();
|
||||
appNameType = printableNameType = mechElement.getStringNameType();
|
||||
this.mechElement = mechElement;
|
||||
elements = new HashMap<Oid, GSSNameSpi>(1);
|
||||
elements.put(mechElement.getMechanism(), this.mechElement);
|
||||
}
|
||||
|
||||
GSSNameImpl(GSSManagerImpl gssManager,
|
||||
Object appName,
|
||||
Oid appNameType)
|
||||
throws GSSException {
|
||||
this(gssManager, appName, appNameType, null);
|
||||
}
|
||||
|
||||
GSSNameImpl(GSSManagerImpl gssManager,
|
||||
Object appName,
|
||||
Oid appNameType,
|
||||
Oid mech)
|
||||
throws GSSException {
|
||||
|
||||
if (oldHostbasedServiceName.equals(appNameType)) {
|
||||
appNameType = GSSName.NT_HOSTBASED_SERVICE;
|
||||
}
|
||||
if (appName == null)
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Cannot import null name");
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
if (NT_EXPORT_NAME.equals(appNameType)) {
|
||||
importName(gssManager, appName);
|
||||
} else {
|
||||
init(gssManager, appName, appNameType, mech);
|
||||
}
|
||||
}
|
||||
|
||||
private void init(GSSManagerImpl gssManager,
|
||||
Object appName, Oid appNameType,
|
||||
Oid mech)
|
||||
throws GSSException {
|
||||
|
||||
this.gssManager = gssManager;
|
||||
this.elements =
|
||||
new HashMap<Oid, GSSNameSpi>(gssManager.getMechs().length);
|
||||
|
||||
if (appName instanceof String) {
|
||||
this.appNameStr = (String) appName;
|
||||
/*
|
||||
* If appNameType is null, then the nametype for this printable
|
||||
* string is determined only by interrogating the
|
||||
* mechanism. Thus, defer the setting of printableName and
|
||||
* printableNameType till later.
|
||||
*/
|
||||
if (appNameType != null) {
|
||||
printableName = appNameStr;
|
||||
printableNameType = appNameType;
|
||||
}
|
||||
} else {
|
||||
this.appNameBytes = (byte[]) appName;
|
||||
}
|
||||
|
||||
this.appNameType = appNameType;
|
||||
|
||||
mechElement = getElement(mech);
|
||||
|
||||
/*
|
||||
* printableName will be null if appName was in a byte[] or if
|
||||
* appName was in a String but appNameType was null.
|
||||
*/
|
||||
if (printableName == null) {
|
||||
printableName = mechElement.toString();
|
||||
printableNameType = mechElement.getStringNameType();
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point the GSSNameImpl has the following set:
|
||||
* appNameStr or appNameBytes
|
||||
* appNameType (could be null)
|
||||
* printableName
|
||||
* printableNameType
|
||||
* mechElement (which also exists in the hashmap of elements)
|
||||
*/
|
||||
}
|
||||
|
||||
private void importName(GSSManagerImpl gssManager,
|
||||
Object appName)
|
||||
throws GSSException {
|
||||
|
||||
int pos = 0;
|
||||
byte[] bytes = null;
|
||||
|
||||
if (appName instanceof String) {
|
||||
try {
|
||||
bytes = ((String) appName).getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Won't happen
|
||||
}
|
||||
} else
|
||||
bytes = (byte[]) appName;
|
||||
|
||||
if ((bytes[pos++] != 0x04) ||
|
||||
(bytes[pos++] != 0x01))
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Exported name token id is corrupted!");
|
||||
|
||||
int oidLen = (((0xFF & bytes[pos++]) << 8) |
|
||||
(0xFF & bytes[pos++]));
|
||||
ObjectIdentifier temp = null;
|
||||
try {
|
||||
DerInputStream din = new DerInputStream(bytes, pos,
|
||||
oidLen);
|
||||
temp = new ObjectIdentifier(din);
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Exported name Object identifier is corrupted!");
|
||||
}
|
||||
Oid oid = new Oid(temp.toString());
|
||||
pos += oidLen;
|
||||
int mechPortionLen = (((0xFF & bytes[pos++]) << 24) |
|
||||
((0xFF & bytes[pos++]) << 16) |
|
||||
((0xFF & bytes[pos++]) << 8) |
|
||||
(0xFF & bytes[pos++]));
|
||||
if (mechPortionLen < 0 || pos > bytes.length - mechPortionLen) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME,
|
||||
"Exported name mech name is corrupted!");
|
||||
}
|
||||
byte[] mechPortion = new byte[mechPortionLen];
|
||||
System.arraycopy(bytes, pos, mechPortion, 0, mechPortionLen);
|
||||
|
||||
init(gssManager, mechPortion, NT_EXPORT_NAME, oid);
|
||||
}
|
||||
|
||||
public GSSName canonicalize(Oid mech) throws GSSException {
|
||||
if (mech == null) mech = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
return wrapElement(gssManager, getElement(mech));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method may return false negatives. But if it says two
|
||||
* names are equals, then there is some mechanism that
|
||||
* authenticates them as the same principal.
|
||||
*/
|
||||
public boolean equals(GSSName other) throws GSSException {
|
||||
|
||||
if (this.isAnonymous() || other.isAnonymous())
|
||||
return false;
|
||||
|
||||
if (other == this)
|
||||
return true;
|
||||
|
||||
if (! (other instanceof GSSNameImpl))
|
||||
return equals(gssManager.createName(other.toString(),
|
||||
other.getStringNameType()));
|
||||
|
||||
/*
|
||||
* XXX Do a comparison of the appNameStr/appNameBytes if
|
||||
* available. If that fails, then proceed with this test.
|
||||
*/
|
||||
|
||||
GSSNameImpl that = (GSSNameImpl) other;
|
||||
|
||||
GSSNameSpi myElement = this.mechElement;
|
||||
GSSNameSpi element = that.mechElement;
|
||||
|
||||
/*
|
||||
* XXX If they are not of the same mechanism type, convert both to
|
||||
* Kerberos since it is guaranteed to be present.
|
||||
*/
|
||||
if ((myElement == null) && (element != null)) {
|
||||
myElement = this.getElement(element.getMechanism());
|
||||
} else if ((myElement != null) && (element == null)) {
|
||||
element = that.getElement(myElement.getMechanism());
|
||||
}
|
||||
|
||||
if (myElement != null && element != null) {
|
||||
return myElement.equals(element);
|
||||
}
|
||||
|
||||
if ((this.appNameType != null) &&
|
||||
(that.appNameType != null)) {
|
||||
if (!this.appNameType.equals(that.appNameType)) {
|
||||
return false;
|
||||
}
|
||||
byte[] myBytes = null;
|
||||
byte[] bytes = null;
|
||||
try {
|
||||
myBytes =
|
||||
(this.appNameStr != null ?
|
||||
this.appNameStr.getBytes("UTF-8") :
|
||||
this.appNameBytes);
|
||||
bytes =
|
||||
(that.appNameStr != null ?
|
||||
that.appNameStr.getBytes("UTF-8") :
|
||||
that.appNameBytes);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Won't happen
|
||||
}
|
||||
|
||||
return Arrays.equals(myBytes, bytes);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSName.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode() {
|
||||
/*
|
||||
* XXX
|
||||
* In order to get this to work reliably and properly(!), obtain a
|
||||
* Kerberos name element for the name and then call hashCode on its
|
||||
* string representation. But this cannot be done if the nametype
|
||||
* is not one of those supported by the Kerberos provider and hence
|
||||
* this name cannot be imported by Kerberos. In that case return a
|
||||
* constant value!
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean equals(Object another) {
|
||||
|
||||
try {
|
||||
// XXX This can lead to an infinite loop. Extract info
|
||||
// and create a GSSNameImpl with it.
|
||||
|
||||
if (another instanceof GSSName)
|
||||
return equals((GSSName) another);
|
||||
} catch (GSSException e) {
|
||||
// Squelch it and return false
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a flat name representation for this object. The name
|
||||
* format is defined in RFC 2743:
|
||||
*<pre>
|
||||
* Length Name Description
|
||||
* 2 TOK_ID Token Identifier
|
||||
* For exported name objects, this
|
||||
* must be hex 04 01.
|
||||
* 2 MECH_OID_LEN Length of the Mechanism OID
|
||||
* MECH_OID_LEN MECH_OID Mechanism OID, in DER
|
||||
* 4 NAME_LEN Length of name
|
||||
* NAME_LEN NAME Exported name; format defined in
|
||||
* applicable mechanism draft.
|
||||
*</pre>
|
||||
*
|
||||
* Note that it is not required to canonicalize a name before
|
||||
* calling export(). i.e., the name need not be an MN. If it is
|
||||
* not an MN, an implementation defined algorithm can be used for
|
||||
* choosing the mechanism which should export this name.
|
||||
*
|
||||
* @return the flat name representation for this object
|
||||
* @exception GSSException with major codes NAME_NOT_MN, BAD_NAME,
|
||||
* BAD_NAME, FAILURE.
|
||||
*/
|
||||
public byte[] export() throws GSSException {
|
||||
|
||||
if (mechElement == null) {
|
||||
/* Use default mech */
|
||||
mechElement = getElement(ProviderList.DEFAULT_MECH_OID);
|
||||
}
|
||||
|
||||
byte[] mechPortion = mechElement.export();
|
||||
byte[] oidBytes = null;
|
||||
ObjectIdentifier oid = null;
|
||||
|
||||
try {
|
||||
oid = new ObjectIdentifier
|
||||
(mechElement.getMechanism().toString());
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Invalid OID String ");
|
||||
}
|
||||
DerOutputStream dout = new DerOutputStream();
|
||||
try {
|
||||
dout.putOID(oid);
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE,
|
||||
"Could not ASN.1 Encode "
|
||||
+ oid.toString());
|
||||
}
|
||||
oidBytes = dout.toByteArray();
|
||||
|
||||
byte[] retVal = new byte[2
|
||||
+ 2 + oidBytes.length
|
||||
+ 4 + mechPortion.length];
|
||||
int pos = 0;
|
||||
retVal[pos++] = 0x04;
|
||||
retVal[pos++] = 0x01;
|
||||
retVal[pos++] = (byte) (oidBytes.length>>>8);
|
||||
retVal[pos++] = (byte) oidBytes.length;
|
||||
System.arraycopy(oidBytes, 0, retVal, pos, oidBytes.length);
|
||||
pos += oidBytes.length;
|
||||
retVal[pos++] = (byte) (mechPortion.length>>>24);
|
||||
retVal[pos++] = (byte) (mechPortion.length>>>16);
|
||||
retVal[pos++] = (byte) (mechPortion.length>>>8);
|
||||
retVal[pos++] = (byte) mechPortion.length;
|
||||
System.arraycopy(mechPortion, 0, retVal, pos, mechPortion.length);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return printableName;
|
||||
|
||||
}
|
||||
|
||||
public Oid getStringNameType() throws GSSException {
|
||||
return printableNameType;
|
||||
}
|
||||
|
||||
public boolean isAnonymous() {
|
||||
if (printableNameType == null) {
|
||||
return false;
|
||||
} else {
|
||||
return GSSName.NT_ANONYMOUS.equals(printableNameType);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isMN() {
|
||||
return true; // Since always canonicalized for some mech
|
||||
}
|
||||
|
||||
public synchronized GSSNameSpi getElement(Oid mechOid)
|
||||
throws GSSException {
|
||||
|
||||
GSSNameSpi retVal = elements.get(mechOid);
|
||||
|
||||
if (retVal == null) {
|
||||
if (appNameStr != null) {
|
||||
retVal = gssManager.getNameElement
|
||||
(appNameStr, appNameType, mechOid);
|
||||
} else {
|
||||
retVal = gssManager.getNameElement
|
||||
(appNameBytes, appNameType, mechOid);
|
||||
}
|
||||
elements.put(mechOid, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
Set<GSSNameSpi> getElements() {
|
||||
return new HashSet<GSSNameSpi>(elements.values());
|
||||
}
|
||||
|
||||
private static String getNameTypeStr(Oid nameTypeOid) {
|
||||
|
||||
if (nameTypeOid == null)
|
||||
return "(NT is null)";
|
||||
|
||||
if (nameTypeOid.equals(NT_USER_NAME))
|
||||
return "NT_USER_NAME";
|
||||
if (nameTypeOid.equals(NT_HOSTBASED_SERVICE))
|
||||
return "NT_HOSTBASED_SERVICE";
|
||||
if (nameTypeOid.equals(NT_EXPORT_NAME))
|
||||
return "NT_EXPORT_NAME";
|
||||
if (nameTypeOid.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL))
|
||||
return "NT_GSS_KRB5_PRINCIPAL";
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
231
jdkSrc/jdk8/sun/security/jgss/GSSToken.java
Normal file
231
jdkSrc/jdk8/sun/security/jgss/GSSToken.java
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.EOFException;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* Utilities for processing GSS Tokens.
|
||||
*
|
||||
*/
|
||||
|
||||
public abstract class GSSToken {
|
||||
|
||||
/**
|
||||
* Copies an integer value to a byte array in little endian form.
|
||||
* @param value the integer value to write
|
||||
* @param array the byte array into which the integer must be copied. It
|
||||
* is assumed that the array will be large enough to hold the 4 bytes of
|
||||
* the integer.
|
||||
*/
|
||||
public static final void writeLittleEndian(int value, byte[] array) {
|
||||
writeLittleEndian(value, array, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies an integer value to a byte array in little endian form.
|
||||
* @param value the integer value to write
|
||||
* @param array the byte array into which the integer must be copied. It
|
||||
* is assumed that the array will be large enough to hold the 4 bytes of
|
||||
* the integer.
|
||||
* @param pos the position at which to start writing
|
||||
*/
|
||||
public static final void writeLittleEndian(int value, byte[] array,
|
||||
int pos) {
|
||||
array[pos++] = (byte)(value);
|
||||
array[pos++] = (byte)((value>>>8));
|
||||
array[pos++] = (byte)((value>>>16));
|
||||
array[pos++] = (byte)((value>>>24));
|
||||
}
|
||||
|
||||
public static final void writeBigEndian(int value, byte[] array) {
|
||||
writeBigEndian(value, array, 0);
|
||||
}
|
||||
|
||||
public static final void writeBigEndian(int value, byte[] array,
|
||||
int pos) {
|
||||
array[pos++] = (byte)((value>>>24));
|
||||
array[pos++] = (byte)((value>>>16));
|
||||
array[pos++] = (byte)((value>>>8));
|
||||
array[pos++] = (byte)(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an integer value from a byte array in little endian form. This
|
||||
* method allows the reading of two byte values as well as four bytes
|
||||
* values both of which are needed in the Kerberos v5 GSS-API mechanism.
|
||||
*
|
||||
* @param data the array containing the bytes of the integer value
|
||||
* @param pos the offset in the array
|
||||
* @param size the number of bytes to read from the array.
|
||||
* @return the integer value
|
||||
*/
|
||||
public static final int readLittleEndian(byte[] data, int pos, int size) {
|
||||
int retVal = 0;
|
||||
int shifter = 0;
|
||||
while (size > 0) {
|
||||
retVal += (data[pos] & 0xff) << shifter;
|
||||
shifter += 8;
|
||||
pos++;
|
||||
size--;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static final int readBigEndian(byte[] data, int pos, int size) {
|
||||
int retVal = 0;
|
||||
int shifter = (size-1)*8;
|
||||
while (size > 0) {
|
||||
retVal += (data[pos] & 0xff) << shifter;
|
||||
shifter -= 8;
|
||||
pos++;
|
||||
size--;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a two byte integer value to a OutputStream.
|
||||
*
|
||||
* @param val the integer value. It will lose the high-order two bytes.
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException if an error occurs while writing to the OutputStream
|
||||
*/
|
||||
public static final void writeInt(int val, OutputStream os)
|
||||
throws IOException {
|
||||
os.write(val>>>8);
|
||||
os.write(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a two byte integer value to a byte array.
|
||||
*
|
||||
* @param val the integer value. It will lose the high-order two bytes.
|
||||
* @param dest the byte array to write to
|
||||
* @param pos the offset to start writing to
|
||||
*/
|
||||
public static final int writeInt(int val, byte[] dest, int pos) {
|
||||
dest[pos++] = (byte)(val>>>8);
|
||||
dest[pos++] = (byte)val;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a two byte integer value from an InputStream.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @return the integer value
|
||||
* @throws IOException if some errors occurs while reading the integer
|
||||
* bytes.
|
||||
*/
|
||||
public static final int readInt(InputStream is) throws IOException {
|
||||
return (((0xFF & is.read()) << 8)
|
||||
| (0xFF & is.read()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a two byte integer value from a byte array.
|
||||
*
|
||||
* @param src the byte arra to read from
|
||||
* @param pos the offset to start reading from
|
||||
* @return the integer value
|
||||
*/
|
||||
public static final int readInt(byte[] src, int pos) {
|
||||
return ((0xFF & src[pos])<<8 | (0xFF & src[pos+1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks till the required number of bytes have been read from the
|
||||
* input stream.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param buffer the buffer to store the bytes into
|
||||
* @throws EOFException if EOF is reached before all bytes are
|
||||
* read.
|
||||
* @throws IOException is an error occurs while reading
|
||||
*/
|
||||
public static final void readFully(InputStream is, byte[] buffer)
|
||||
throws IOException {
|
||||
readFully(is, buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks till the required number of bytes have been read from the
|
||||
* input stream.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param buffer the buffer to store the bytes into
|
||||
* @param offset the offset to start storing at
|
||||
* @param len the number of bytes to read
|
||||
* @throws EOFException if EOF is reached before all bytes are
|
||||
* read.
|
||||
* @throws IOException is an error occurs while reading
|
||||
*/
|
||||
public static final void readFully(InputStream is,
|
||||
byte[] buffer, int offset, int len)
|
||||
throws IOException {
|
||||
int temp;
|
||||
while (len > 0) {
|
||||
temp = is.read(buffer, offset, len);
|
||||
if (temp == -1)
|
||||
throw new EOFException("Cannot read all "
|
||||
+ len
|
||||
+ " bytes needed to form this token!");
|
||||
offset += temp;
|
||||
len -= temp;
|
||||
}
|
||||
}
|
||||
|
||||
public static final void debug(String str) {
|
||||
System.err.print(str);
|
||||
}
|
||||
|
||||
public static final String getHexBytes(byte[] bytes) {
|
||||
return getHexBytes(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static final String getHexBytes(byte[] bytes, int len) {
|
||||
return getHexBytes(bytes, 0, len);
|
||||
}
|
||||
|
||||
public static final String getHexBytes(byte[] bytes, int pos, int len) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = pos; i < (pos+len); i++) {
|
||||
int b1 = (bytes[i]>>4) & 0x0f;
|
||||
int b2 = bytes[i] & 0x0f;
|
||||
|
||||
sb.append(Integer.toHexString(b1));
|
||||
sb.append(Integer.toHexString(b2));
|
||||
sb.append(' ');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
366
jdkSrc/jdk8/sun/security/jgss/GSSUtil.java
Normal file
366
jdkSrc/jdk8/sun/security/jgss/GSSUtil.java
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2017, 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;
|
||||
|
||||
import com.sun.security.auth.callback.TextCallbackHandler;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
import sun.security.jgss.spi.GSSCredentialSpi;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.jgss.krb5.Krb5NameElement;
|
||||
import sun.security.jgss.spnego.SpNegoCredElement;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Vector;
|
||||
import java.util.Iterator;
|
||||
import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
import javax.security.auth.callback.CallbackHandler;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
|
||||
/**
|
||||
* The GSSUtilImplementation that knows how to work with the internals of
|
||||
* the GSS-API.
|
||||
*/
|
||||
public class GSSUtil {
|
||||
|
||||
public static final Oid GSS_KRB5_MECH_OID =
|
||||
GSSUtil.createOid("1.2.840.113554.1.2.2");
|
||||
public static final Oid GSS_KRB5_MECH_OID2 =
|
||||
GSSUtil.createOid("1.3.5.1.5.2");
|
||||
public static final Oid GSS_KRB5_MECH_OID_MS =
|
||||
GSSUtil.createOid("1.2.840.48018.1.2.2");
|
||||
|
||||
public static final Oid GSS_SPNEGO_MECH_OID =
|
||||
GSSUtil.createOid("1.3.6.1.5.5.2");
|
||||
|
||||
public static final Oid NT_GSS_KRB5_PRINCIPAL =
|
||||
GSSUtil.createOid("1.2.840.113554.1.2.2.1");
|
||||
|
||||
private static final String DEFAULT_HANDLER =
|
||||
"auth.login.defaultCallbackHandler";
|
||||
|
||||
static final boolean DEBUG;
|
||||
static {
|
||||
DEBUG = (AccessController.doPrivileged
|
||||
(new GetBooleanAction("sun.security.jgss.debug"))).
|
||||
booleanValue();
|
||||
}
|
||||
|
||||
static void debug(String message) {
|
||||
if (DEBUG) {
|
||||
assert(message != null);
|
||||
System.out.println(message);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this method is only for creating Oid objects with
|
||||
// known to be valid <code>oidStr</code> given it ignores
|
||||
// the GSSException
|
||||
public static Oid createOid(String oidStr) {
|
||||
try {
|
||||
return new Oid(oidStr);
|
||||
} catch (GSSException e) {
|
||||
debug("Ignored invalid OID: " + oidStr);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSpNegoMech(Oid oid) {
|
||||
return (GSS_SPNEGO_MECH_OID.equals(oid));
|
||||
}
|
||||
|
||||
public static boolean isKerberosMech(Oid oid) {
|
||||
return (GSS_KRB5_MECH_OID.equals(oid) ||
|
||||
GSS_KRB5_MECH_OID2.equals(oid) ||
|
||||
GSS_KRB5_MECH_OID_MS.equals(oid));
|
||||
|
||||
}
|
||||
|
||||
public static String getMechStr(Oid oid) {
|
||||
if (isSpNegoMech(oid)) {
|
||||
return "SPNEGO";
|
||||
} else if (isKerberosMech(oid)) {
|
||||
return "Kerberos V5";
|
||||
} else {
|
||||
return oid.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: The current impl only works with Sun's impl of
|
||||
* GSSName and GSSCredential since it depends on package
|
||||
* private APIs.
|
||||
*/
|
||||
public static Subject getSubject(GSSName name,
|
||||
GSSCredential creds) {
|
||||
|
||||
HashSet<Object> privCredentials = null;
|
||||
HashSet<Object> pubCredentials = new HashSet<Object>(); // empty Set
|
||||
|
||||
Set<GSSCredentialSpi> gssCredentials = null;
|
||||
|
||||
Set<KerberosPrincipal> krb5Principals =
|
||||
new HashSet<KerberosPrincipal>();
|
||||
|
||||
if (name instanceof GSSNameImpl) {
|
||||
try {
|
||||
GSSNameSpi ne = ((GSSNameImpl) name).getElement
|
||||
(GSS_KRB5_MECH_OID);
|
||||
String krbName = ne.toString();
|
||||
if (ne instanceof Krb5NameElement) {
|
||||
krbName =
|
||||
((Krb5NameElement) ne).getKrb5PrincipalName().getName();
|
||||
}
|
||||
KerberosPrincipal krbPrinc = new KerberosPrincipal(krbName);
|
||||
krb5Principals.add(krbPrinc);
|
||||
} catch (GSSException ge) {
|
||||
debug("Skipped name " + name + " due to " + ge);
|
||||
}
|
||||
}
|
||||
|
||||
if (creds instanceof GSSCredentialImpl) {
|
||||
gssCredentials = ((GSSCredentialImpl) creds).getElements();
|
||||
privCredentials = new HashSet<Object>(gssCredentials.size());
|
||||
populateCredentials(privCredentials, gssCredentials);
|
||||
} else {
|
||||
privCredentials = new HashSet<Object>(); // empty Set
|
||||
}
|
||||
debug("Created Subject with the following");
|
||||
debug("principals=" + krb5Principals);
|
||||
debug("public creds=" + pubCredentials);
|
||||
debug("private creds=" + privCredentials);
|
||||
|
||||
return new Subject(false, krb5Principals, pubCredentials,
|
||||
privCredentials);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the set credentials with elements from gssCredentials. At
|
||||
* the same time, it converts any subclasses of KerberosTicket
|
||||
* into KerberosTicket instances and any subclasses of KerberosKey into
|
||||
* KerberosKey instances. (It is not desirable to expose the customer
|
||||
* to sun.security.jgss.krb5.Krb5InitCredential which extends
|
||||
* KerberosTicket and sun.security.jgss.krb5.Kbr5AcceptCredential which
|
||||
* extends KerberosKey.)
|
||||
*/
|
||||
private static void populateCredentials(Set<Object> credentials,
|
||||
Set<?> gssCredentials) {
|
||||
|
||||
Object cred;
|
||||
|
||||
Iterator<?> elements = gssCredentials.iterator();
|
||||
while (elements.hasNext()) {
|
||||
|
||||
cred = elements.next();
|
||||
|
||||
// Retrieve the internal cred out of SpNegoCredElement
|
||||
if (cred instanceof SpNegoCredElement) {
|
||||
cred = ((SpNegoCredElement) cred).getInternalCred();
|
||||
}
|
||||
|
||||
if (cred instanceof KerberosTicket) {
|
||||
if (!cred.getClass().getName().equals
|
||||
("javax.security.auth.kerberos.KerberosTicket")) {
|
||||
KerberosTicket tempTkt = (KerberosTicket) cred;
|
||||
cred = new KerberosTicket(tempTkt.getEncoded(),
|
||||
tempTkt.getClient(),
|
||||
tempTkt.getServer(),
|
||||
tempTkt.getSessionKey().getEncoded(),
|
||||
tempTkt.getSessionKeyType(),
|
||||
tempTkt.getFlags(),
|
||||
tempTkt.getAuthTime(),
|
||||
tempTkt.getStartTime(),
|
||||
tempTkt.getEndTime(),
|
||||
tempTkt.getRenewTill(),
|
||||
tempTkt.getClientAddresses());
|
||||
}
|
||||
credentials.add(cred);
|
||||
} else if (cred instanceof KerberosKey) {
|
||||
if (!cred.getClass().getName().equals
|
||||
("javax.security.auth.kerberos.KerberosKey")) {
|
||||
KerberosKey tempKey = (KerberosKey) cred;
|
||||
cred = new KerberosKey(tempKey.getPrincipal(),
|
||||
tempKey.getEncoded(),
|
||||
tempKey.getKeyType(),
|
||||
tempKey.getVersionNumber());
|
||||
}
|
||||
credentials.add(cred);
|
||||
} else {
|
||||
// Ignore non-KerberosTicket and non-KerberosKey elements
|
||||
debug("Skipped cred element: " + cred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate using the login module from the specified
|
||||
* configuration entry.
|
||||
*
|
||||
* @param caller the caller of JAAS Login
|
||||
* @param mech the mech to be used
|
||||
* @return the authenticated subject
|
||||
*/
|
||||
public static Subject login(GSSCaller caller, Oid mech) throws LoginException {
|
||||
|
||||
CallbackHandler cb = null;
|
||||
if (caller instanceof HttpCaller) {
|
||||
cb = new sun.net.www.protocol.http.spnego.NegotiateCallbackHandler(
|
||||
((HttpCaller)caller).info());
|
||||
} else {
|
||||
String defaultHandler =
|
||||
java.security.Security.getProperty(DEFAULT_HANDLER);
|
||||
// get the default callback handler
|
||||
if ((defaultHandler != null) && (defaultHandler.length() != 0)) {
|
||||
cb = null;
|
||||
} else {
|
||||
cb = new TextCallbackHandler();
|
||||
}
|
||||
}
|
||||
|
||||
// New instance of LoginConfigImpl must be created for each login,
|
||||
// since the entry name is not passed as the first argument, but
|
||||
// generated with caller and mech inside LoginConfigImpl
|
||||
LoginContext lc = new LoginContext("", null, cb,
|
||||
new LoginConfigImpl(caller, mech));
|
||||
lc.login();
|
||||
return lc.getSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the application doesn't mind if the mechanism obtains
|
||||
* the required credentials from outside of the current Subject. Our
|
||||
* Kerberos v5 mechanism would do a JAAS login on behalf of the
|
||||
* application if this were the case.
|
||||
*
|
||||
* The application indicates this by explicitly setting the system
|
||||
* property javax.security.auth.useSubjectCredsOnly to false.
|
||||
*/
|
||||
public static boolean useSubjectCredsOnly(GSSCaller caller) {
|
||||
|
||||
String propValue = GetPropertyAction.privilegedGetProperty(
|
||||
"javax.security.auth.useSubjectCredsOnly");
|
||||
|
||||
// Invalid values should be ignored and the default assumed.
|
||||
if (caller instanceof HttpCaller) {
|
||||
// Default for HTTP/SPNEGO is false.
|
||||
return "true".equalsIgnoreCase(propValue);
|
||||
} else {
|
||||
// Default for JGSS is true.
|
||||
return !("false".equalsIgnoreCase(propValue));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the SPNEGO interoperability mode with Microsoft;
|
||||
* by default it is set to true.
|
||||
*
|
||||
* To disable it, the application indicates this by explicitly setting
|
||||
* the system property sun.security.spnego.interop to false.
|
||||
*/
|
||||
public static boolean useMSInterop() {
|
||||
/*
|
||||
* Don't use GetBooleanAction because the default value in the JRE
|
||||
* (when this is unset) has to treated as true.
|
||||
*/
|
||||
String propValue = AccessController.doPrivileged(
|
||||
new GetPropertyAction("sun.security.spnego.msinterop",
|
||||
"true"));
|
||||
/*
|
||||
* This property has to be explicitly set to "false". Invalid
|
||||
* values should be ignored and the default "true" assumed.
|
||||
*/
|
||||
return (!propValue.equalsIgnoreCase("false"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the private credentials of current Subject with the
|
||||
* specified criteria and returns the matching GSSCredentialSpi
|
||||
* object out of Sun's impl of GSSCredential. Returns null if
|
||||
* no Subject present or a Vector which contains 0 or more
|
||||
* matching GSSCredentialSpi objects.
|
||||
*/
|
||||
public static <T extends GSSCredentialSpi> Vector<T>
|
||||
searchSubject(final GSSNameSpi name,
|
||||
final Oid mech,
|
||||
final boolean initiate,
|
||||
final Class<? extends T> credCls) {
|
||||
debug("Search Subject for " + getMechStr(mech) +
|
||||
(initiate? " INIT" : " ACCEPT") + " cred (" +
|
||||
(name == null? "<<DEF>>" : name.toString()) + ", " +
|
||||
credCls.getName() + ")");
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
try {
|
||||
Vector<T> creds =
|
||||
AccessController.doPrivileged
|
||||
(new PrivilegedExceptionAction<Vector<T>>() {
|
||||
public Vector<T> run() throws Exception {
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
Vector<T> result = null;
|
||||
if (accSubj != null) {
|
||||
result = new Vector<T>();
|
||||
Iterator<GSSCredentialImpl> iterator =
|
||||
accSubj.getPrivateCredentials
|
||||
(GSSCredentialImpl.class).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
GSSCredentialImpl cred = iterator.next();
|
||||
debug("...Found cred" + cred);
|
||||
try {
|
||||
GSSCredentialSpi ce =
|
||||
cred.getElement(mech, initiate);
|
||||
debug("......Found element: " + ce);
|
||||
if (ce.getClass().equals(credCls) &&
|
||||
(name == null ||
|
||||
name.equals((Object) ce.getName()))) {
|
||||
result.add(credCls.cast(ce));
|
||||
} else {
|
||||
debug("......Discard element");
|
||||
}
|
||||
} catch (GSSException ge) {
|
||||
debug("...Discard cred (" + ge + ")");
|
||||
}
|
||||
}
|
||||
} else debug("No Subject");
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return creds;
|
||||
} catch (PrivilegedActionException pae) {
|
||||
debug("Unexpected exception when searching Subject:");
|
||||
if (DEBUG) pae.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
46
jdkSrc/jdk8/sun/security/jgss/HttpCaller.java
Normal file
46
jdkSrc/jdk8/sun/security/jgss/HttpCaller.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2009, 2012, 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;
|
||||
|
||||
import sun.net.www.protocol.http.HttpCallerInfo;
|
||||
|
||||
/**
|
||||
* A special kind of GSSCaller, which origins from HTTP/Negotiate and contains
|
||||
* info about what triggers the JGSS calls.
|
||||
*/
|
||||
public class HttpCaller extends GSSCaller {
|
||||
final private HttpCallerInfo hci;
|
||||
|
||||
public HttpCaller(HttpCallerInfo hci) {
|
||||
super("HTTP_CLIENT");
|
||||
this.hci = hci;
|
||||
}
|
||||
|
||||
public HttpCallerInfo info() {
|
||||
return hci;
|
||||
}
|
||||
}
|
||||
|
||||
213
jdkSrc/jdk8/sun/security/jgss/LoginConfigImpl.java
Normal file
213
jdkSrc/jdk8/sun/security/jgss/LoginConfigImpl.java
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2017, 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import javax.security.auth.login.AppConfigurationEntry;
|
||||
import javax.security.auth.login.Configuration;
|
||||
import org.ietf.jgss.Oid;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* A Configuration implementation especially designed for JGSS.
|
||||
*
|
||||
* @author weijun.wang
|
||||
* @since 1.6
|
||||
*/
|
||||
public class LoginConfigImpl extends Configuration {
|
||||
|
||||
private final Configuration config;
|
||||
private final GSSCaller caller;
|
||||
private final String mechName;
|
||||
private static final sun.security.util.Debug debug =
|
||||
sun.security.util.Debug.getInstance("gssloginconfig", "\t[GSS LoginConfigImpl]");
|
||||
|
||||
public static final boolean HTTP_USE_GLOBAL_CREDS;
|
||||
|
||||
static {
|
||||
String prop = GetPropertyAction
|
||||
.privilegedGetProperty("http.use.global.creds");
|
||||
//HTTP_USE_GLOBAL_CREDS = "true".equalsIgnoreCase(prop); // default false
|
||||
HTTP_USE_GLOBAL_CREDS = !"false".equalsIgnoreCase(prop); // default true
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A new instance of LoginConfigImpl must be created for each login request
|
||||
* since it's only used by a single (caller, mech) pair
|
||||
* @param caller defined in GSSUtil as CALLER_XXX final fields
|
||||
* @param mech defined in GSSUtil as XXX_MECH_OID final fields
|
||||
*/
|
||||
public LoginConfigImpl(GSSCaller caller, Oid mech) {
|
||||
|
||||
this.caller = caller;
|
||||
|
||||
if (mech.equals(GSSUtil.GSS_KRB5_MECH_OID)) {
|
||||
mechName = "krb5";
|
||||
} else {
|
||||
throw new IllegalArgumentException(mech.toString() + " not supported");
|
||||
}
|
||||
config = java.security.AccessController.doPrivileged
|
||||
(new java.security.PrivilegedAction <Configuration> () {
|
||||
public Configuration run() {
|
||||
return Configuration.getConfiguration();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Almost useless, since the (caller, mech) is already passed
|
||||
* into constructor. The only use will be detecting OTHER which
|
||||
* is called in LoginContext
|
||||
*/
|
||||
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
|
||||
|
||||
AppConfigurationEntry[] entries = null;
|
||||
|
||||
// This is the second call from LoginContext, which we will just ignore
|
||||
if ("OTHER".equalsIgnoreCase(name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] alts = null;
|
||||
|
||||
// Compatibility:
|
||||
// For the 4 old callers, old entry names will be used if the new
|
||||
// entry name is not provided.
|
||||
|
||||
if ("krb5".equals(mechName)) {
|
||||
if (caller == GSSCaller.CALLER_INITIATE) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.initiate",
|
||||
"com.sun.security.jgss.initiate",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_ACCEPT) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.accept",
|
||||
"com.sun.security.jgss.accept",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_SSL_CLIENT) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.initiate",
|
||||
"com.sun.net.ssl.client",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_SSL_SERVER) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.accept",
|
||||
"com.sun.net.ssl.server",
|
||||
};
|
||||
} else if (caller instanceof HttpCaller) {
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss.krb5.initiate",
|
||||
};
|
||||
} else if (caller == GSSCaller.CALLER_UNKNOWN) {
|
||||
throw new AssertionError("caller not defined");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(mechName + " not supported");
|
||||
// No other mech at the moment, maybe --
|
||||
/*
|
||||
switch (caller) {
|
||||
case GSSUtil.CALLER_INITIATE:
|
||||
case GSSUtil.CALLER_SSL_CLIENT:
|
||||
case GSSUtil.CALLER_HTTP_NEGOTIATE:
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss." + mechName + ".initiate",
|
||||
};
|
||||
break;
|
||||
case GSSUtil.CALLER_ACCEPT:
|
||||
case GSSUtil.CALLER_SSL_SERVER:
|
||||
alts = new String[] {
|
||||
"com.sun.security.jgss." + mechName + ".accept",
|
||||
};
|
||||
break;
|
||||
case GSSUtil.CALLER_UNKNOWN:
|
||||
// should never use
|
||||
throw new AssertionError("caller cannot be unknown");
|
||||
default:
|
||||
throw new AssertionError("caller not defined");
|
||||
}
|
||||
*/
|
||||
}
|
||||
for (String alt: alts) {
|
||||
entries = config.getAppConfigurationEntry(alt);
|
||||
if (debug != null) {
|
||||
debug.println("Trying " + alt +
|
||||
((entries == null)?": does not exist.":": Found!"));
|
||||
}
|
||||
if (entries != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (entries == null) {
|
||||
if (debug != null) {
|
||||
debug.println("Cannot read JGSS entry, use default values instead.");
|
||||
}
|
||||
entries = getDefaultConfigurationEntry();
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value for a caller-mech pair when no entry is defined in
|
||||
* the system-wide Configuration object.
|
||||
*/
|
||||
private AppConfigurationEntry[] getDefaultConfigurationEntry() {
|
||||
HashMap <String, String> options = new HashMap <String, String> (2);
|
||||
|
||||
if (mechName == null || mechName.equals("krb5")) {
|
||||
if (isServerSide(caller)) {
|
||||
// Assuming the keytab file can be found through
|
||||
// krb5 config file or under user home directory
|
||||
options.put("useKeyTab", "true");
|
||||
options.put("storeKey", "true");
|
||||
options.put("doNotPrompt", "true");
|
||||
options.put("principal", "*");
|
||||
options.put("isInitiator", "false");
|
||||
} else {
|
||||
if (caller instanceof HttpCaller && !HTTP_USE_GLOBAL_CREDS) {
|
||||
options.put("useTicketCache", "false");
|
||||
} else {
|
||||
options.put("useTicketCache", "true");
|
||||
}
|
||||
options.put("doNotPrompt", "false");
|
||||
}
|
||||
return new AppConfigurationEntry[] {
|
||||
new AppConfigurationEntry(
|
||||
"com.sun.security.auth.module.Krb5LoginModule",
|
||||
AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
|
||||
options)
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isServerSide (GSSCaller caller) {
|
||||
return GSSCaller.CALLER_ACCEPT == caller ||
|
||||
GSSCaller.CALLER_SSL_SERVER == caller;
|
||||
}
|
||||
}
|
||||
547
jdkSrc/jdk8/sun/security/jgss/ProviderList.java
Normal file
547
jdkSrc/jdk8/sun/security/jgss/ProviderList.java
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2009, 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;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.AccessController;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.jgss.wrapper.NativeGSSFactory;
|
||||
import sun.security.jgss.wrapper.SunNativeProvider;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/**
|
||||
* This class stores the list of providers that this
|
||||
* GSS-Implementation is configured to use. The GSSManagerImpl class
|
||||
* queries this class whenever it needs a mechanism's factory.<p>
|
||||
*
|
||||
* This class stores an ordered list of pairs of the form
|
||||
* {@code <provider, oid>}. When it attempts to instantiate a mechanism
|
||||
* defined by oid o, it steps through the list looking for an entry
|
||||
* with oid=o, or with oid=null. (An entry with oid=null matches all
|
||||
* mechanisms.) When it finds such an entry, the corresponding
|
||||
* provider is approached for the mechanism's factory class.
|
||||
* At instantiation time this list in initialized to contain those
|
||||
* system wide providers that contain a property of the form
|
||||
* "GssApiMechanism.x.y.z..." where "x.y.z..." is a numeric object
|
||||
* identifier with numbers x, y, z, etc. Such a property is defined
|
||||
* to map to that provider's implementation of the MechanismFactory
|
||||
* interface for the mechanism x.y.z...
|
||||
* As and when a MechanismFactory is instantiated, it is
|
||||
* cached for future use. <p>
|
||||
*
|
||||
* An application can cause more providers to be added by means of
|
||||
* the addProviderAtFront and addProviderAtEnd methods on
|
||||
* GSSManager which get delegated to this class. The
|
||||
* addProviderAtFront method can also cause a change in the ordering
|
||||
* of the providers without adding any new providers, by causing a
|
||||
* provider to move up in a list. The method addProviderAtEnd can
|
||||
* only add providers at the end of the list if they are not already
|
||||
* in the list. The rationale is that an application will call
|
||||
* addProviderAtFront when it wants a provider to be used in
|
||||
* preference over the default ones. And it will call
|
||||
* addProviderAtEnd when it wants a provider to be used in case
|
||||
* the system ones don't suffice.<p>
|
||||
*
|
||||
* If a mechanism's factory is being obtained from a provider as a
|
||||
* result of encountering a entryof the form {@code <provider, oid>} where
|
||||
* oid is non-null, then the assumption is that the application added
|
||||
* this entry and it wants this mechanism to be obtained from this
|
||||
* provider. Thus is the provider does not actually contain the
|
||||
* requested mechanism, an exception will be thrown. However, if the
|
||||
* entry were of the form {@code <provider, null>}, then it is viewed more
|
||||
* liberally and is simply skipped over if the provider does not claim to
|
||||
* support the requested mechanism.
|
||||
*/
|
||||
|
||||
public final class ProviderList {
|
||||
|
||||
private static final String PROV_PROP_PREFIX = "GssApiMechanism.";
|
||||
private static final int PROV_PROP_PREFIX_LEN =
|
||||
PROV_PROP_PREFIX.length();
|
||||
|
||||
private static final String SPI_MECH_FACTORY_TYPE
|
||||
= "sun.security.jgss.spi.MechanismFactory";
|
||||
|
||||
// Undocumented property?
|
||||
private static final String DEFAULT_MECH_PROP =
|
||||
"sun.security.jgss.mechanism";
|
||||
|
||||
public static final Oid DEFAULT_MECH_OID;
|
||||
|
||||
static {
|
||||
/*
|
||||
* Set the default mechanism. Kerberos v5 is the default
|
||||
* mechanism unless it is overridden by a system property.
|
||||
* with a valid OID value
|
||||
*/
|
||||
Oid defOid = null;
|
||||
String defaultOidStr = AccessController.doPrivileged
|
||||
(new GetPropertyAction(DEFAULT_MECH_PROP));
|
||||
if (defaultOidStr != null) {
|
||||
defOid = GSSUtil.createOid(defaultOidStr);
|
||||
}
|
||||
DEFAULT_MECH_OID =
|
||||
(defOid == null ? GSSUtil.GSS_KRB5_MECH_OID : defOid);
|
||||
}
|
||||
|
||||
private ArrayList<PreferencesEntry> preferences =
|
||||
new ArrayList<PreferencesEntry>(5);
|
||||
private HashMap<PreferencesEntry, MechanismFactory> factories =
|
||||
new HashMap<PreferencesEntry, MechanismFactory>(5);
|
||||
private HashSet<Oid> mechs = new HashSet<Oid>(5);
|
||||
|
||||
final private GSSCaller caller;
|
||||
|
||||
public ProviderList(GSSCaller caller, boolean useNative) {
|
||||
this.caller = caller;
|
||||
Provider[] provList;
|
||||
if (useNative) {
|
||||
provList = new Provider[1];
|
||||
provList[0] = new SunNativeProvider();
|
||||
} else {
|
||||
provList = Security.getProviders();
|
||||
}
|
||||
|
||||
for (int i = 0; i < provList.length; i++) {
|
||||
Provider prov = provList[i];
|
||||
try {
|
||||
addProviderAtEnd(prov, null);
|
||||
} catch (GSSException ge) {
|
||||
// Move on to the next provider
|
||||
GSSUtil.debug("Error in adding provider " +
|
||||
prov.getName() + ": " + ge);
|
||||
}
|
||||
} // End of for loop
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given provider property represents a GSS-API
|
||||
* Oid to MechanismFactory mapping.
|
||||
* @return true if this is a GSS-API property, false otherwise.
|
||||
*/
|
||||
private boolean isMechFactoryProperty(String prop) {
|
||||
return (prop.startsWith(PROV_PROP_PREFIX) ||
|
||||
prop.regionMatches(true, 0, // Try ignoring case
|
||||
PROV_PROP_PREFIX, 0,
|
||||
PROV_PROP_PREFIX_LEN));
|
||||
}
|
||||
|
||||
private Oid getOidFromMechFactoryProperty(String prop)
|
||||
throws GSSException {
|
||||
|
||||
String oidPart = prop.substring(PROV_PROP_PREFIX_LEN);
|
||||
return new Oid(oidPart);
|
||||
}
|
||||
|
||||
// So the existing code do not have to be changed
|
||||
synchronized public MechanismFactory getMechFactory(Oid mechOid)
|
||||
throws GSSException {
|
||||
if (mechOid == null) mechOid = ProviderList.DEFAULT_MECH_OID;
|
||||
return getMechFactory(mechOid, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a MechanismFactory for a given mechanism. If the
|
||||
* specified provider is not null, then the impl from the
|
||||
* provider is used. Otherwise, the most preferred impl based
|
||||
* on the configured preferences is used.
|
||||
* @param mechOid the oid of the desired mechanism
|
||||
* @return a MechanismFactory for the desired mechanism.
|
||||
* @throws GSSException when the specified provider does not
|
||||
* support the desired mechanism, or when no provider supports
|
||||
* the desired mechanism.
|
||||
*/
|
||||
synchronized public MechanismFactory getMechFactory(Oid mechOid,
|
||||
Provider p)
|
||||
throws GSSException {
|
||||
|
||||
if (mechOid == null) mechOid = ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
if (p == null) {
|
||||
// Iterate thru all preferences to find right provider
|
||||
String className;
|
||||
PreferencesEntry entry;
|
||||
|
||||
Iterator<PreferencesEntry> list = preferences.iterator();
|
||||
while (list.hasNext()) {
|
||||
entry = list.next();
|
||||
if (entry.impliesMechanism(mechOid)) {
|
||||
MechanismFactory retVal = getMechFactory(entry, mechOid);
|
||||
if (retVal != null) return retVal;
|
||||
}
|
||||
} // end of while loop
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH, mechOid);
|
||||
} else {
|
||||
// Use the impl from the specified provider; return null if the
|
||||
// the mech is unsupported by the specified provider.
|
||||
PreferencesEntry entry = new PreferencesEntry(p, mechOid);
|
||||
return getMechFactory(entry, mechOid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine that uses a preferences entry to obtain an
|
||||
* implementation of a MechanismFactory from it.
|
||||
* @param e the preferences entry that contains the provider and
|
||||
* either a null of an explicit oid that matched the oid of the
|
||||
* desired mechanism.
|
||||
* @param mechOid the oid of the desired mechanism
|
||||
* @throws GSSException If the application explicitly requested
|
||||
* this entry's provider to be used for the desired mechanism but
|
||||
* some problem is encountered
|
||||
*/
|
||||
private MechanismFactory getMechFactory(PreferencesEntry e, Oid mechOid)
|
||||
throws GSSException {
|
||||
Provider p = e.getProvider();
|
||||
|
||||
/*
|
||||
* See if a MechanismFactory was previously instantiated for
|
||||
* this provider and mechanism combination.
|
||||
*/
|
||||
PreferencesEntry searchEntry = new PreferencesEntry(p, mechOid);
|
||||
MechanismFactory retVal = factories.get(searchEntry);
|
||||
if (retVal == null) {
|
||||
/*
|
||||
* Apparently not. Now try to instantiate this class from
|
||||
* the provider.
|
||||
*/
|
||||
String prop = PROV_PROP_PREFIX + mechOid.toString();
|
||||
String className = p.getProperty(prop);
|
||||
if (className != null) {
|
||||
retVal = getMechFactoryImpl(p, className, mechOid, caller);
|
||||
factories.put(searchEntry, retVal);
|
||||
} else {
|
||||
/*
|
||||
* This provider does not support this mechanism.
|
||||
* If the application explicitly requested that
|
||||
* this provider be used for this mechanism, then
|
||||
* throw an exception
|
||||
*/
|
||||
if (e.getOid() != null) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
"Provider " + p.getName() +
|
||||
" does not support mechanism " + mechOid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain a MechanismFactory implementation
|
||||
* from the same class loader as the provider of this
|
||||
* implementation.
|
||||
* @param p the provider whose classloader must be used for
|
||||
* instantiating the desired MechanismFactory
|
||||
* @ param className the name of the MechanismFactory class
|
||||
* @throws GSSException If some error occurs when trying to
|
||||
* instantiate this MechanismFactory.
|
||||
*/
|
||||
private static MechanismFactory getMechFactoryImpl(Provider p,
|
||||
String className,
|
||||
Oid mechOid,
|
||||
GSSCaller caller)
|
||||
throws GSSException {
|
||||
|
||||
try {
|
||||
Class<?> baseClass = Class.forName(SPI_MECH_FACTORY_TYPE);
|
||||
|
||||
/*
|
||||
* Load the implementation class with the same class loader
|
||||
* that was used to load the provider.
|
||||
* In order to get the class loader of a class, the
|
||||
* caller's class loader must be the same as or an ancestor of
|
||||
* the class loader being returned. Otherwise, the caller must
|
||||
* have "getClassLoader" permission, or a SecurityException
|
||||
* will be thrown.
|
||||
*/
|
||||
|
||||
ClassLoader cl = p.getClass().getClassLoader();
|
||||
Class<?> implClass;
|
||||
if (cl != null) {
|
||||
implClass = cl.loadClass(className);
|
||||
} else {
|
||||
implClass = Class.forName(className);
|
||||
}
|
||||
|
||||
if (baseClass.isAssignableFrom(implClass)) {
|
||||
|
||||
java.lang.reflect.Constructor<?> c =
|
||||
implClass.getConstructor(GSSCaller.class);
|
||||
MechanismFactory mf = (MechanismFactory) (c.newInstance(caller));
|
||||
|
||||
if (mf instanceof NativeGSSFactory) {
|
||||
((NativeGSSFactory) mf).setMech(mechOid);
|
||||
}
|
||||
return mf;
|
||||
} else {
|
||||
throw createGSSException(p, className, "is not a " +
|
||||
SPI_MECH_FACTORY_TYPE, null);
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (InstantiationException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
} catch (SecurityException e) {
|
||||
throw createGSSException(p, className, "cannot be created", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Only used by getMechFactoryImpl
|
||||
private static GSSException createGSSException(Provider p,
|
||||
String className,
|
||||
String trailingMsg,
|
||||
Exception cause) {
|
||||
String errClassInfo = className + " configured by " +
|
||||
p.getName() + " for GSS-API Mechanism Factory ";
|
||||
return new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
errClassInfo + trailingMsg,
|
||||
cause);
|
||||
}
|
||||
|
||||
public Oid[] getMechs() {
|
||||
return mechs.toArray(new Oid[] {});
|
||||
}
|
||||
|
||||
synchronized public void addProviderAtFront(Provider p, Oid mechOid)
|
||||
throws GSSException {
|
||||
|
||||
PreferencesEntry newEntry = new PreferencesEntry(p, mechOid);
|
||||
PreferencesEntry oldEntry;
|
||||
boolean foundSomeMech;
|
||||
|
||||
Iterator<PreferencesEntry> list = preferences.iterator();
|
||||
while (list.hasNext()) {
|
||||
oldEntry = list.next();
|
||||
if (newEntry.implies(oldEntry))
|
||||
list.remove();
|
||||
}
|
||||
|
||||
if (mechOid == null) {
|
||||
foundSomeMech = addAllMechsFromProvider(p);
|
||||
} else {
|
||||
String oidStr = mechOid.toString();
|
||||
if (p.getProperty(PROV_PROP_PREFIX + oidStr) == null)
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
"Provider " + p.getName()
|
||||
+ " does not support "
|
||||
+ oidStr);
|
||||
mechs.add(mechOid);
|
||||
foundSomeMech = true;
|
||||
}
|
||||
|
||||
if (foundSomeMech) {
|
||||
preferences.add(0, newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
synchronized public void addProviderAtEnd(Provider p, Oid mechOid)
|
||||
throws GSSException {
|
||||
|
||||
PreferencesEntry newEntry = new PreferencesEntry(p, mechOid);
|
||||
PreferencesEntry oldEntry;
|
||||
boolean foundSomeMech;
|
||||
|
||||
Iterator<PreferencesEntry> list = preferences.iterator();
|
||||
while (list.hasNext()) {
|
||||
oldEntry = list.next();
|
||||
if (oldEntry.implies(newEntry))
|
||||
return;
|
||||
}
|
||||
|
||||
// System.out.println("addProviderAtEnd: No it is not redundant");
|
||||
|
||||
if (mechOid == null)
|
||||
foundSomeMech = addAllMechsFromProvider(p);
|
||||
else {
|
||||
String oidStr = mechOid.toString();
|
||||
if (p.getProperty(PROV_PROP_PREFIX + oidStr) == null)
|
||||
throw new GSSExceptionImpl(GSSException.BAD_MECH,
|
||||
"Provider " + p.getName()
|
||||
+ " does not support "
|
||||
+ oidStr);
|
||||
mechs.add(mechOid);
|
||||
foundSomeMech = true;
|
||||
}
|
||||
|
||||
if (foundSomeMech) {
|
||||
preferences.add(newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to go through all properties contined in a
|
||||
* provider and add its mechanisms to the list of supported
|
||||
* mechanisms. If no default mechanism has been assinged so far,
|
||||
* it sets the default MechanismFactory and Oid as well.
|
||||
* @param p the provider to query
|
||||
* @return true if there is at least one mechanism that this
|
||||
* provider contributed, false otherwise
|
||||
*/
|
||||
private boolean addAllMechsFromProvider(Provider p) {
|
||||
|
||||
String prop;
|
||||
boolean retVal = false;
|
||||
|
||||
// Get all props for this provider
|
||||
Enumeration<Object> props = p.keys();
|
||||
|
||||
// See if there are any GSS prop's
|
||||
while (props.hasMoreElements()) {
|
||||
prop = (String) props.nextElement();
|
||||
if (isMechFactoryProperty(prop)) {
|
||||
// Ok! This is a GSS provider!
|
||||
try {
|
||||
Oid mechOid = getOidFromMechFactoryProperty(prop);
|
||||
mechs.add(mechOid);
|
||||
retVal = true;
|
||||
} catch (GSSException e) {
|
||||
// Skip to next property
|
||||
GSSUtil.debug("Ignore the invalid property " +
|
||||
prop + " from provider " + p.getName());
|
||||
}
|
||||
} // Processed GSS property
|
||||
} // while loop
|
||||
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a provider and a mechanism oid indicating that the
|
||||
* provider should be used for the mechanism. If the mechanism
|
||||
* Oid is null, then it indicates that this preference holds for
|
||||
* any mechanism.<p>
|
||||
*
|
||||
* The ProviderList maintains an ordered list of
|
||||
* PreferencesEntry's and iterates thru them as it tries to
|
||||
* instantiate MechanismFactory's.
|
||||
*/
|
||||
private static final class PreferencesEntry {
|
||||
private Provider p;
|
||||
private Oid oid;
|
||||
PreferencesEntry(Provider p, Oid oid) {
|
||||
this.p = p;
|
||||
this.oid = oid;
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(other instanceof PreferencesEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PreferencesEntry that = (PreferencesEntry)other;
|
||||
if (this.p.getName().equals(that.p.getName())) {
|
||||
if (this.oid != null && that.oid != null) {
|
||||
return this.oid.equals(that.oid);
|
||||
} else {
|
||||
return (this.oid == null && that.oid == null);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
|
||||
result = 37 * result + p.getName().hashCode();
|
||||
if (oid != null) {
|
||||
result = 37 * result + oid.hashCode();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a preference implies another. A preference
|
||||
* implies another if the latter is subsumed by the
|
||||
* former. e.g., <Provider1, null> implies <Provider1, OidX>
|
||||
* because the null in the former indicates that it should
|
||||
* be used for all mechanisms.
|
||||
*/
|
||||
boolean implies(Object other) {
|
||||
|
||||
if (other instanceof PreferencesEntry) {
|
||||
PreferencesEntry temp = (PreferencesEntry) other;
|
||||
return (equals(temp) ||
|
||||
p.getName().equals(temp.p.getName()) &&
|
||||
oid == null);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Provider getProvider() {
|
||||
return p;
|
||||
}
|
||||
|
||||
Oid getOid() {
|
||||
return oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this entry is applicable to the desired
|
||||
* mechanism. The entry is applicable to the desired mech if
|
||||
* it contains the same oid or if it contains a null oid
|
||||
* indicating that it is applicable to all mechs.
|
||||
* @param mechOid the desired mechanism
|
||||
* @return true if the provider in this entry should be
|
||||
* queried for this mechanism.
|
||||
*/
|
||||
boolean impliesMechanism(Oid oid) {
|
||||
return (this.oid == null || this.oid.equals(oid));
|
||||
}
|
||||
|
||||
// For debugging
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer("<");
|
||||
buf.append(p.getName());
|
||||
buf.append(", ");
|
||||
buf.append(oid);
|
||||
buf.append(">");
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
82
jdkSrc/jdk8/sun/security/jgss/SunProvider.java
Normal file
82
jdkSrc/jdk8/sun/security/jgss/SunProvider.java
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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;
|
||||
|
||||
import java.security.Provider;
|
||||
import java.security.AccessController;
|
||||
|
||||
/**
|
||||
* Defines the Sun JGSS provider.
|
||||
* Will merger this with the Sun security provider
|
||||
* sun.security.provider.Sun when the JGSS src is merged with the JDK
|
||||
* src.
|
||||
*
|
||||
* Mechanisms supported are:
|
||||
*
|
||||
* - Kerberos v5 as defined in RFC 1964.
|
||||
* Oid is 1.2.840.113554.1.2.2
|
||||
*
|
||||
* - SPNEGO as defined in RFC 2478
|
||||
* Oid is 1.3.6.1.5.5.2
|
||||
*
|
||||
* [Dummy mechanism is no longer compiled:
|
||||
* - Dummy mechanism. This is primarily useful to test a multi-mech
|
||||
* environment.
|
||||
* Oid is 1.3.6.1.4.1.42.2.26.1.2]
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public final class SunProvider extends Provider {
|
||||
|
||||
private static final long serialVersionUID = -238911724858694198L;
|
||||
|
||||
private static final String INFO = "Sun " +
|
||||
"(Kerberos v5, SPNEGO)";
|
||||
// "(Kerberos v5, Dummy GSS-API Mechanism)";
|
||||
|
||||
public static final SunProvider INSTANCE = new SunProvider();
|
||||
|
||||
public SunProvider() {
|
||||
/* We are the Sun JGSS provider */
|
||||
super("SunJGSS", 1.8d, INFO);
|
||||
|
||||
AccessController.doPrivileged(
|
||||
new java.security.PrivilegedAction<Void>() {
|
||||
public Void run() {
|
||||
put("GssApiMechanism.1.2.840.113554.1.2.2",
|
||||
"sun.security.jgss.krb5.Krb5MechFactory");
|
||||
put("GssApiMechanism.1.3.6.1.5.5.2",
|
||||
"sun.security.jgss.spnego.SpNegoMechFactory");
|
||||
/*
|
||||
put("GssApiMechanism.1.3.6.1.4.1.42.2.26.1.2",
|
||||
"sun.security.jgss.dummy.DummyMechFactory");
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
419
jdkSrc/jdk8/sun/security/jgss/TokenTracker.java
Normal file
419
jdkSrc/jdk8/sun/security/jgss/TokenTracker.java
Normal file
@@ -0,0 +1,419 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, 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;
|
||||
|
||||
import org.ietf.jgss.MessageProp;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* A utility class that implements a number list that keeps track of which
|
||||
* tokens have arrived by storing their token numbers in the list. It helps
|
||||
* detect old tokens, out of sequence tokens, and duplicate tokens.
|
||||
*
|
||||
* Each element of the list is an interval [a, b]. Its existence in the
|
||||
* list implies that all token numbers in the range a, a+1, ..., b-1, b
|
||||
* have arrived. Gaps in arrived token numbers are represented by the
|
||||
* numbers that fall in between two elements of the list. eg. {[a,b],
|
||||
* [c,d]} indicates that the token numbers b+1, ..., c-1 have not arrived
|
||||
* yet.
|
||||
*
|
||||
* The maximum number of intervals that we keep track of is
|
||||
* MAX_INTERVALS. Thus if there are too many gaps, then some of the older
|
||||
* sequence numbers are deleted from the list. The earliest sequence number
|
||||
* that exists in the list is the windowStart. The next expected sequence
|
||||
* number, or expectedNumber, is one greater than the latest sequence
|
||||
* number in the list.
|
||||
*
|
||||
* The list keeps track the first token number that should have arrived
|
||||
* (initNumber) so that it is able to detect if certain numbers occur after
|
||||
* the first valid token number but before windowStart. That would happen
|
||||
* if the number of elements (intervals) exceeds MAX_INTERVALS and some
|
||||
* initial elements had to be deleted.
|
||||
*
|
||||
* The working of the list is optimized for the normal case where the
|
||||
* tokens arrive in sequence.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
public class TokenTracker {
|
||||
|
||||
static final int MAX_INTERVALS = 5;
|
||||
|
||||
private int initNumber;
|
||||
private int windowStart;
|
||||
private int expectedNumber;
|
||||
|
||||
private int windowStartIndex = 0;
|
||||
|
||||
private LinkedList<Entry> list = new LinkedList<Entry>();
|
||||
|
||||
public TokenTracker(int initNumber) {
|
||||
|
||||
this.initNumber = initNumber;
|
||||
this.windowStart = initNumber;
|
||||
this.expectedNumber = initNumber;
|
||||
|
||||
// Make an entry with one less than the expected first token
|
||||
Entry entry = new Entry(initNumber-1);
|
||||
|
||||
list.add(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index for the entry into which this number will fit. If
|
||||
* there is none, it returns the index of the last interval
|
||||
* which precedes this number. It returns -1 if the number needs to be
|
||||
* a in a new interval ahead of the whole list.
|
||||
*/
|
||||
private int getIntervalIndex(int number) {
|
||||
Entry entry = null;
|
||||
int i;
|
||||
// Start from the rear to optimize for the normal case
|
||||
for (i = list.size() - 1; i >= 0; i--) {
|
||||
entry = list.get(i);
|
||||
if (entry.compareTo(number) <= 0)
|
||||
break;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sequencing and replay information for the given token
|
||||
* number.
|
||||
*
|
||||
* The following represents the number line with positions of
|
||||
* initNumber, windowStart, expectedNumber marked on it. Regions in
|
||||
* between them show the different sequencing and replay state
|
||||
* possibilites for tokens that fall in there.
|
||||
*
|
||||
* (1) windowStart
|
||||
* initNumber expectedNumber
|
||||
* | |
|
||||
* ---|---------------------------|---
|
||||
* GAP | DUP/UNSEQ | GAP
|
||||
*
|
||||
*
|
||||
* (2) initNumber windowStart expectedNumber
|
||||
* | | |
|
||||
* ---|---------------|--------------|---
|
||||
* GAP | OLD | DUP/UNSEQ | GAP
|
||||
*
|
||||
*
|
||||
* (3) windowStart
|
||||
* expectedNumber initNumber
|
||||
* | |
|
||||
* ---|---------------------------|---
|
||||
* DUP/UNSEQ | GAP | DUP/UNSEQ
|
||||
*
|
||||
*
|
||||
* (4) expectedNumber initNumber windowStart
|
||||
* | | |
|
||||
* ---|---------------|--------------|---
|
||||
* DUP/UNSEQ | GAP | OLD | DUP/UNSEQ
|
||||
*
|
||||
*
|
||||
*
|
||||
* (5) windowStart expectedNumber initNumber
|
||||
* | | |
|
||||
* ---|---------------|--------------|---
|
||||
* OLD | DUP/UNSEQ | GAP | OLD
|
||||
*
|
||||
*
|
||||
*
|
||||
* (This analysis leaves out the possibility that expectedNumber passes
|
||||
* initNumber after wrapping around. That may be added later.)
|
||||
*/
|
||||
synchronized public final void getProps(int number, MessageProp prop) {
|
||||
|
||||
boolean gap = false;
|
||||
boolean old = false;
|
||||
boolean unsequenced = false;
|
||||
boolean duplicate = false;
|
||||
|
||||
// System.out.println("\n\n==========");
|
||||
// System.out.println("TokenTracker.getProps(): number=" + number);
|
||||
// System.out.println(toString());
|
||||
|
||||
int pos = getIntervalIndex(number);
|
||||
Entry entry = null;
|
||||
if (pos != -1)
|
||||
entry = list.get(pos);
|
||||
|
||||
// Optimize for the expected case:
|
||||
|
||||
if (number == expectedNumber) {
|
||||
expectedNumber++;
|
||||
} else {
|
||||
|
||||
// Next trivial case is to check for duplicate
|
||||
if (entry != null && entry.contains(number))
|
||||
duplicate = true;
|
||||
else {
|
||||
|
||||
if (expectedNumber >= initNumber) {
|
||||
|
||||
// Cases (1) and (2)
|
||||
|
||||
if (number > expectedNumber) {
|
||||
gap = true;
|
||||
} else if (number >= windowStart) {
|
||||
unsequenced = true;
|
||||
} else if (number >= initNumber) {
|
||||
old = true;
|
||||
} else {
|
||||
gap = true;
|
||||
}
|
||||
} else {
|
||||
|
||||
// Cases (3), (4) and (5)
|
||||
|
||||
if (number > expectedNumber) {
|
||||
if (number < initNumber) {
|
||||
gap = true;
|
||||
} else if (windowStart >= initNumber) {
|
||||
if (number >= windowStart) {
|
||||
unsequenced = true;
|
||||
} else
|
||||
old = true;
|
||||
} else {
|
||||
old = true;
|
||||
}
|
||||
} else if (windowStart > expectedNumber) {
|
||||
unsequenced = true;
|
||||
} else if (number < windowStart) {
|
||||
old = true;
|
||||
} else
|
||||
unsequenced = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!duplicate && !old)
|
||||
add(number, pos);
|
||||
|
||||
if (gap)
|
||||
expectedNumber = number+1;
|
||||
|
||||
prop.setSupplementaryStates(duplicate, old, unsequenced, gap,
|
||||
0, null);
|
||||
|
||||
// System.out.println("Leaving with state:");
|
||||
// System.out.println(toString());
|
||||
// System.out.println("==========\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the number to the list just after the entry that is currently
|
||||
* at position prevEntryPos. If prevEntryPos is -1, then the number
|
||||
* will begin a new interval at the front of the list.
|
||||
*/
|
||||
private void add(int number, int prevEntryPos) {
|
||||
|
||||
Entry entry;
|
||||
Entry entryBefore = null;
|
||||
Entry entryAfter = null;
|
||||
|
||||
boolean appended = false;
|
||||
boolean prepended = false;
|
||||
|
||||
if (prevEntryPos != -1) {
|
||||
entryBefore = list.get(prevEntryPos);
|
||||
|
||||
// Can this number simply be added to the previous interval?
|
||||
if (number == (entryBefore.getEnd() + 1)) {
|
||||
entryBefore.setEnd(number);
|
||||
appended = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Now check the interval that follows this number
|
||||
|
||||
int nextEntryPos = prevEntryPos + 1;
|
||||
if ((nextEntryPos) < list.size()) {
|
||||
entryAfter = list.get(nextEntryPos);
|
||||
|
||||
// Can this number simply be added to the next interval?
|
||||
if (number == (entryAfter.getStart() - 1)) {
|
||||
if (!appended) {
|
||||
entryAfter.setStart(number);
|
||||
} else {
|
||||
// Merge the two entries
|
||||
entryAfter.setStart(entryBefore.getStart());
|
||||
list.remove(prevEntryPos);
|
||||
// Index of any entry following this gets decremented
|
||||
if (windowStartIndex > prevEntryPos)
|
||||
windowStartIndex--;
|
||||
}
|
||||
prepended = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (prepended || appended)
|
||||
return;
|
||||
|
||||
/*
|
||||
* At this point we know that the number will start a new interval
|
||||
* which needs to be added to the list. We might have to recyle an
|
||||
* older entry in the list.
|
||||
*/
|
||||
|
||||
if (list.size() < MAX_INTERVALS) {
|
||||
entry = new Entry(number);
|
||||
if (prevEntryPos < windowStartIndex)
|
||||
windowStartIndex++; // due to the insertion which will happen
|
||||
} else {
|
||||
/*
|
||||
* Delete the entry that marks the start of the current window.
|
||||
* The marker will automatically point to the next entry in the
|
||||
* list when this happens. If the current entry is at the end
|
||||
* of the list then set the marker to the start of the list.
|
||||
*/
|
||||
int oldWindowStartIndex = windowStartIndex;
|
||||
if (windowStartIndex == (list.size() - 1))
|
||||
windowStartIndex = 0;
|
||||
|
||||
entry = list.remove(oldWindowStartIndex);
|
||||
windowStart = list.get(windowStartIndex).getStart();
|
||||
entry.setStart(number);
|
||||
entry.setEnd(number);
|
||||
|
||||
if (prevEntryPos >= oldWindowStartIndex) {
|
||||
prevEntryPos--; // due to the deletion that just happened
|
||||
} else {
|
||||
/*
|
||||
* If the start of the current window just moved from the
|
||||
* end of the list to the front of the list, and if the new
|
||||
* entry will be added to the front of the list, then
|
||||
* the new entry is the actual window start.
|
||||
* eg, Consider { [-10, -8], ..., [-6, -3], [3, 9]}. In
|
||||
* this list, suppose the element [3, 9] is the start of
|
||||
* the window and has to be deleted to make place to add
|
||||
* [-12, -12]. The resultant list will be
|
||||
* {[-12, -12], [-10, -8], ..., [-6, -3]} and the new start
|
||||
* of the window should be the element [-12, -12], not
|
||||
* [-10, -8] which succeeded [3, 9] in the old list.
|
||||
*/
|
||||
if (oldWindowStartIndex != windowStartIndex) {
|
||||
// windowStartIndex is 0 at this point
|
||||
if (prevEntryPos == -1)
|
||||
// The new entry is going to the front
|
||||
windowStart = number;
|
||||
} else {
|
||||
// due to the insertion which will happen:
|
||||
windowStartIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we are ready to actually add to the list at index
|
||||
// 'prevEntryPos+1'
|
||||
|
||||
list.add(prevEntryPos+1, entry);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buf = new StringBuffer("TokenTracker: ");
|
||||
buf.append(" initNumber=").append(initNumber);
|
||||
buf.append(" windowStart=").append(windowStart);
|
||||
buf.append(" expectedNumber=").append(expectedNumber);
|
||||
buf.append(" windowStartIndex=").append(windowStartIndex);
|
||||
buf.append("\n\tIntervals are: {");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (i != 0)
|
||||
buf.append(", ");
|
||||
buf.append(list.get(i).toString());
|
||||
}
|
||||
buf.append('}');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry in the list that represents the sequence of received
|
||||
* tokens. Each entry is actaully an interval of numbers, all of which
|
||||
* have been received.
|
||||
*/
|
||||
class Entry {
|
||||
|
||||
private int start;
|
||||
private int end;
|
||||
|
||||
Entry(int number) {
|
||||
start = number;
|
||||
end = number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns -1 if this interval represented by this entry precedes
|
||||
* the number, 0 if the the number is contained in the interval,
|
||||
* and -1 if the interval occurs after the number.
|
||||
*/
|
||||
final int compareTo(int number) {
|
||||
if (start > number)
|
||||
return 1;
|
||||
else if (end < number)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
final boolean contains(int number) {
|
||||
return (number >= start &&
|
||||
number <= end);
|
||||
}
|
||||
|
||||
final void append(int number) {
|
||||
if (number == (end + 1))
|
||||
end = number;
|
||||
}
|
||||
|
||||
final void setInterval(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
final void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
final void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
final int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
final int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ("[" + start + ", " + end + "]");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
115
jdkSrc/jdk8/sun/security/jgss/krb5/AcceptSecContextToken.java
Normal file
115
jdkSrc/jdk8/sun/security/jgss/krb5/AcceptSecContextToken.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.AccessController;
|
||||
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.krb5.*;
|
||||
|
||||
class AcceptSecContextToken extends InitialToken {
|
||||
|
||||
private KrbApRep apRep = null;
|
||||
|
||||
/**
|
||||
* Creates an AcceptSecContextToken for the context acceptor to send to
|
||||
* the context initiator.
|
||||
*/
|
||||
public AcceptSecContextToken(Krb5Context context,
|
||||
KrbApReq apReq)
|
||||
throws KrbException, IOException, GSSException {
|
||||
|
||||
boolean useSubkey = AccessController.doPrivileged(
|
||||
new GetBooleanAction("sun.security.krb5.acceptor.subkey"));
|
||||
|
||||
boolean useSequenceNumber = true;
|
||||
|
||||
EncryptionKey subKey = null;
|
||||
if (useSubkey) {
|
||||
subKey = new EncryptionKey(apReq.getCreds().getSessionKey());
|
||||
context.setKey(Krb5Context.ACCEPTOR_SUBKEY, subKey);
|
||||
}
|
||||
apRep = new KrbApRep(apReq, useSequenceNumber, subKey);
|
||||
|
||||
context.resetMySequenceNumber(apRep.getSeqNumber().intValue());
|
||||
|
||||
/*
|
||||
* Note: The acceptor side context key was set when the
|
||||
* InitSecContextToken was received.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AcceptSecContextToken at the context initiator's side
|
||||
* using the bytes received from the acceptor.
|
||||
*/
|
||||
public AcceptSecContextToken(Krb5Context context,
|
||||
Credentials serviceCreds, KrbApReq apReq,
|
||||
InputStream is)
|
||||
throws IOException, GSSException, KrbException {
|
||||
|
||||
int tokenId = ((is.read()<<8) | is.read());
|
||||
|
||||
if (tokenId != Krb5Token.AP_REP_ID)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"AP_REP token id does not match!");
|
||||
|
||||
byte[] apRepBytes =
|
||||
new sun.security.util.DerValue(is).toByteArray();
|
||||
|
||||
KrbApRep apRep = new KrbApRep(apRepBytes, serviceCreds, apReq);
|
||||
|
||||
/*
|
||||
* Allow the context acceptor to set a subkey if desired, even
|
||||
* though our context acceptor will not do so.
|
||||
*/
|
||||
EncryptionKey subKey = apRep.getSubKey();
|
||||
if (subKey != null) {
|
||||
context.setKey(Krb5Context.ACCEPTOR_SUBKEY, subKey);
|
||||
/*
|
||||
System.out.println("\n\nSub-Session key from AP-REP is: " +
|
||||
getHexBytes(subKey.getBytes()) + "\n");
|
||||
*/
|
||||
}
|
||||
|
||||
Integer apRepSeqNumber = apRep.getSeqNumber();
|
||||
int peerSeqNumber = (apRepSeqNumber != null ?
|
||||
apRepSeqNumber.intValue() :
|
||||
0);
|
||||
context.resetPeerSequenceNumber(peerSeqNumber);
|
||||
}
|
||||
|
||||
public final byte[] encode() throws IOException {
|
||||
byte[] apRepBytes = apRep.getMessage();
|
||||
byte[] retVal = new byte[2 + apRepBytes.length];
|
||||
writeInt(Krb5Token.AP_REP_ID, retVal, 0);
|
||||
System.arraycopy(apRepBytes, 0, retVal, 2, apRepBytes.length);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
1502
jdkSrc/jdk8/sun/security/jgss/krb5/CipherHelper.java
Normal file
1502
jdkSrc/jdk8/sun/security/jgss/krb5/CipherHelper.java
Normal file
File diff suppressed because it is too large
Load Diff
215
jdkSrc/jdk8/sun/security/jgss/krb5/InitSecContextToken.java
Normal file
215
jdkSrc/jdk8/sun/security/jgss/krb5/InitSecContextToken.java
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, 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.krb5;
|
||||
|
||||
import com.sun.security.jgss.AuthorizationDataEntry;
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.security.krb5.*;
|
||||
import java.net.InetAddress;
|
||||
import sun.security.krb5.internal.AuthorizationData;
|
||||
import sun.security.krb5.internal.KerberosTime;
|
||||
|
||||
class InitSecContextToken extends InitialToken {
|
||||
|
||||
// If non-mutual authentication is requested, there is no AP-REP message.
|
||||
// The acceptor thus has no chance to send the seq-number field to the
|
||||
// initiator. In this case, the initiator and acceptor should has an
|
||||
// agreement to derive acceptor's initial seq-number if the acceptor wishes
|
||||
// to send messages to the initiator.
|
||||
|
||||
// If this flag is true, it will the same as the initiator's initial
|
||||
// seq-number (as MIT krb5 and Windows SSPI do). Otherwise, it will be zero
|
||||
// (as Heimdal does). The default value is true.
|
||||
private static final boolean ACCEPTOR_USE_INITIATOR_SEQNUM;
|
||||
|
||||
static {
|
||||
// The ACCEPTOR_USE_INITIATOR_SEQNUM value is determined by the system
|
||||
// property "sun.security.krb5.acceptor.sequence.number.nonmutual",
|
||||
// which can be set to "initiator", "zero" or "0".
|
||||
String propName = "sun.security.krb5.acceptor.sequence.number.nonmutual";
|
||||
String s = GetPropertyAction.privilegedGetProperty(propName, "initiator");
|
||||
if (s.equals("initiator")) {
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM = true;
|
||||
} else if (s.equals("zero") || s.equals("0")) {
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM = false;
|
||||
} else {
|
||||
throw new AssertionError("Unrecognized value for " + propName
|
||||
+ ": " + s);
|
||||
}
|
||||
}
|
||||
|
||||
private KrbApReq apReq = null;
|
||||
|
||||
/**
|
||||
* For the context initiator to call. It constructs a new
|
||||
* InitSecContextToken to send over to the peer containing the desired
|
||||
* flags and the AP-REQ. It also updates the context with the local
|
||||
* sequence number and shared context key.
|
||||
* (When mutual auth is enabled the peer has an opportunity to
|
||||
* renegotiate the session key in the followup AcceptSecContextToken
|
||||
* that it sends.)
|
||||
*/
|
||||
InitSecContextToken(Krb5Context context,
|
||||
Credentials tgt,
|
||||
Credentials serviceTicket)
|
||||
throws KrbException, IOException, GSSException {
|
||||
|
||||
boolean mutualRequired = context.getMutualAuthState();
|
||||
boolean useSubkey = true; // MIT Impl will crash if this is not set!
|
||||
boolean useSequenceNumber = true;
|
||||
|
||||
OverloadedChecksum gssChecksum =
|
||||
new OverloadedChecksum(context, tgt, serviceTicket);
|
||||
|
||||
Checksum checksum = gssChecksum.getChecksum();
|
||||
|
||||
context.setTktFlags(serviceTicket.getFlags());
|
||||
context.setAuthTime(
|
||||
new KerberosTime(serviceTicket.getAuthTime()).toString());
|
||||
apReq = new KrbApReq(serviceTicket,
|
||||
mutualRequired,
|
||||
useSubkey,
|
||||
useSequenceNumber,
|
||||
checksum);
|
||||
|
||||
context.resetMySequenceNumber(apReq.getSeqNumber().intValue());
|
||||
|
||||
EncryptionKey subKey = apReq.getSubKey();
|
||||
if (subKey != null)
|
||||
context.setKey(Krb5Context.INITIATOR_SUBKEY, subKey);
|
||||
else
|
||||
context.setKey(Krb5Context.SESSION_KEY, serviceTicket.getSessionKey());
|
||||
|
||||
if (!mutualRequired)
|
||||
context.resetPeerSequenceNumber(
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM
|
||||
? apReq.getSeqNumber().intValue()
|
||||
: 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* For the context acceptor to call. It reads the bytes out of an
|
||||
* InputStream and constructs an InitSecContextToken with them.
|
||||
*/
|
||||
InitSecContextToken(Krb5Context context, Krb5AcceptCredential cred,
|
||||
InputStream is)
|
||||
throws IOException, GSSException, KrbException {
|
||||
|
||||
int tokenId = ((is.read()<<8) | is.read());
|
||||
|
||||
if (tokenId != Krb5Token.AP_REQ_ID)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"AP_REQ token id does not match!");
|
||||
|
||||
// XXX Modify KrbApReq cons to take an InputStream
|
||||
byte[] apReqBytes =
|
||||
new sun.security.util.DerValue(is).toByteArray();
|
||||
//debug("=====ApReqBytes: [" + getHexBytes(apReqBytes) + "]\n");
|
||||
|
||||
InetAddress addr = null;
|
||||
if (context.getChannelBinding() != null) {
|
||||
addr = context.getChannelBinding().getInitiatorAddress();
|
||||
}
|
||||
apReq = new KrbApReq(apReqBytes, cred, addr);
|
||||
//debug("\nReceived AP-REQ and authenticated it.\n");
|
||||
|
||||
EncryptionKey sessionKey = apReq.getCreds().getSessionKey();
|
||||
|
||||
/*
|
||||
System.out.println("\n\nSession key from service ticket is: " +
|
||||
getHexBytes(sessionKey.getBytes()));
|
||||
*/
|
||||
|
||||
EncryptionKey subKey = apReq.getSubKey();
|
||||
if (subKey != null) {
|
||||
context.setKey(Krb5Context.INITIATOR_SUBKEY, subKey);
|
||||
/*
|
||||
System.out.println("Sub-Session key from authenticator is: " +
|
||||
getHexBytes(subKey.getBytes()) + "\n");
|
||||
*/
|
||||
} else {
|
||||
context.setKey(Krb5Context.SESSION_KEY, sessionKey);
|
||||
//System.out.println("Sub-Session Key Missing in Authenticator.\n");
|
||||
}
|
||||
|
||||
OverloadedChecksum gssChecksum = new OverloadedChecksum(
|
||||
context, apReq.getChecksum(), sessionKey, subKey);
|
||||
gssChecksum.setContextFlags(context);
|
||||
Credentials delegCred = gssChecksum.getDelegatedCreds();
|
||||
if (delegCred != null) {
|
||||
Krb5CredElement credElement =
|
||||
Krb5InitCredential.getInstance(
|
||||
(Krb5NameElement)context.getSrcName(),
|
||||
delegCred);
|
||||
context.setDelegCred(credElement);
|
||||
}
|
||||
|
||||
Integer apReqSeqNumber = apReq.getSeqNumber();
|
||||
int peerSeqNumber = (apReqSeqNumber != null ?
|
||||
apReqSeqNumber.intValue() :
|
||||
0);
|
||||
context.resetPeerSequenceNumber(peerSeqNumber);
|
||||
if (!context.getMutualAuthState()) {
|
||||
context.resetMySequenceNumber(
|
||||
ACCEPTOR_USE_INITIATOR_SEQNUM
|
||||
? peerSeqNumber
|
||||
: 0);
|
||||
}
|
||||
context.setAuthTime(
|
||||
new KerberosTime(apReq.getCreds().getAuthTime()).toString());
|
||||
context.setTktFlags(apReq.getCreds().getFlags());
|
||||
AuthorizationData ad = apReq.getCreds().getAuthzData();
|
||||
if (ad == null) {
|
||||
context.setAuthzData(null);
|
||||
} else {
|
||||
AuthorizationDataEntry[] authzData =
|
||||
new AuthorizationDataEntry[ad.count()];
|
||||
for (int i=0; i<ad.count(); i++) {
|
||||
authzData[i] = new AuthorizationDataEntry(
|
||||
ad.item(i).adType, ad.item(i).adData);
|
||||
}
|
||||
context.setAuthzData(authzData);
|
||||
}
|
||||
}
|
||||
|
||||
public final KrbApReq getKrbApReq() {
|
||||
return apReq;
|
||||
}
|
||||
|
||||
public final byte[] encode() throws IOException {
|
||||
byte[] apReqBytes = apReq.getMessage();
|
||||
byte[] retVal = new byte[2 + apReqBytes.length];
|
||||
writeInt(Krb5Token.AP_REQ_ID, retVal, 0);
|
||||
System.arraycopy(apReqBytes, 0, retVal, 2, apReqBytes.length);
|
||||
// System.out.println("GSS-Token with AP_REQ is:");
|
||||
// System.out.println(getHexBytes(retVal));
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
453
jdkSrc/jdk8/sun/security/jgss/krb5/InitialToken.java
Normal file
453
jdkSrc/jdk8/sun/security/jgss/krb5/InitialToken.java
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import javax.security.auth.kerberos.DelegationPermission;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.internal.Krb5;
|
||||
|
||||
abstract class InitialToken extends Krb5Token {
|
||||
|
||||
private static final int CHECKSUM_TYPE = 0x8003;
|
||||
|
||||
private static final int CHECKSUM_LENGTH_SIZE = 4;
|
||||
private static final int CHECKSUM_BINDINGS_SIZE = 16;
|
||||
private static final int CHECKSUM_FLAGS_SIZE = 4;
|
||||
private static final int CHECKSUM_DELEG_OPT_SIZE = 2;
|
||||
private static final int CHECKSUM_DELEG_LGTH_SIZE = 2;
|
||||
|
||||
private static final int CHECKSUM_DELEG_FLAG = 1;
|
||||
private static final int CHECKSUM_MUTUAL_FLAG = 2;
|
||||
private static final int CHECKSUM_REPLAY_FLAG = 4;
|
||||
private static final int CHECKSUM_SEQUENCE_FLAG = 8;
|
||||
private static final int CHECKSUM_CONF_FLAG = 16;
|
||||
private static final int CHECKSUM_INTEG_FLAG = 32;
|
||||
|
||||
private final byte[] CHECKSUM_FIRST_BYTES =
|
||||
{(byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00};
|
||||
|
||||
private static final int CHANNEL_BINDING_AF_INET = 2;
|
||||
private static final int CHANNEL_BINDING_AF_INET6 = 24;
|
||||
private static final int CHANNEL_BINDING_AF_NULL_ADDR = 255;
|
||||
|
||||
private static final int Inet4_ADDRSZ = 4;
|
||||
private static final int Inet6_ADDRSZ = 16;
|
||||
|
||||
protected class OverloadedChecksum {
|
||||
|
||||
private byte[] checksumBytes = null;
|
||||
private Credentials delegCreds = null;
|
||||
private int flags = 0;
|
||||
|
||||
/**
|
||||
* Called on the initiator side when creating the
|
||||
* InitSecContextToken.
|
||||
*/
|
||||
public OverloadedChecksum(Krb5Context context,
|
||||
Credentials tgt,
|
||||
Credentials serviceTicket)
|
||||
throws KrbException, IOException, GSSException {
|
||||
|
||||
byte[] krbCredMessage = null;
|
||||
int pos = 0;
|
||||
int size = CHECKSUM_LENGTH_SIZE + CHECKSUM_BINDINGS_SIZE +
|
||||
CHECKSUM_FLAGS_SIZE;
|
||||
|
||||
if (!tgt.isForwardable()) {
|
||||
context.setCredDelegState(false);
|
||||
context.setDelegPolicyState(false);
|
||||
} else if (context.getCredDelegState()) {
|
||||
if (context.getDelegPolicyState()) {
|
||||
if (!serviceTicket.checkDelegate()) {
|
||||
// delegation not permitted by server policy, mark it
|
||||
context.setDelegPolicyState(false);
|
||||
}
|
||||
}
|
||||
} else if (context.getDelegPolicyState()) {
|
||||
if (serviceTicket.checkDelegate()) {
|
||||
context.setCredDelegState(true);
|
||||
} else {
|
||||
context.setDelegPolicyState(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.getCredDelegState()) {
|
||||
KrbCred krbCred = null;
|
||||
CipherHelper cipherHelper =
|
||||
context.getCipherHelper(serviceTicket.getSessionKey());
|
||||
if (useNullKey(cipherHelper)) {
|
||||
krbCred = new KrbCred(tgt, serviceTicket,
|
||||
EncryptionKey.NULL_KEY);
|
||||
} else {
|
||||
krbCred = new KrbCred(tgt, serviceTicket,
|
||||
serviceTicket.getSessionKey());
|
||||
}
|
||||
krbCredMessage = krbCred.getMessage();
|
||||
size += CHECKSUM_DELEG_OPT_SIZE +
|
||||
CHECKSUM_DELEG_LGTH_SIZE +
|
||||
krbCredMessage.length;
|
||||
}
|
||||
|
||||
checksumBytes = new byte[size];
|
||||
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[0];
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[1];
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[2];
|
||||
checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[3];
|
||||
|
||||
ChannelBinding localBindings = context.getChannelBinding();
|
||||
if (localBindings != null) {
|
||||
byte[] localBindingsBytes =
|
||||
computeChannelBinding(context.getChannelBinding());
|
||||
System.arraycopy(localBindingsBytes, 0,
|
||||
checksumBytes, pos, localBindingsBytes.length);
|
||||
// System.out.println("ChannelBinding hash: "
|
||||
// + getHexBytes(localBindingsBytes));
|
||||
}
|
||||
|
||||
pos += CHECKSUM_BINDINGS_SIZE;
|
||||
|
||||
if (context.getCredDelegState())
|
||||
flags |= CHECKSUM_DELEG_FLAG;
|
||||
if (context.getMutualAuthState())
|
||||
flags |= CHECKSUM_MUTUAL_FLAG;
|
||||
if (context.getReplayDetState())
|
||||
flags |= CHECKSUM_REPLAY_FLAG;
|
||||
if (context.getSequenceDetState())
|
||||
flags |= CHECKSUM_SEQUENCE_FLAG;
|
||||
if (context.getIntegState())
|
||||
flags |= CHECKSUM_INTEG_FLAG;
|
||||
if (context.getConfState())
|
||||
flags |= CHECKSUM_CONF_FLAG;
|
||||
|
||||
byte[] temp = new byte[4];
|
||||
writeLittleEndian(flags, temp);
|
||||
checksumBytes[pos++] = temp[0];
|
||||
checksumBytes[pos++] = temp[1];
|
||||
checksumBytes[pos++] = temp[2];
|
||||
checksumBytes[pos++] = temp[3];
|
||||
|
||||
if (context.getCredDelegState()) {
|
||||
|
||||
PrincipalName delegateTo =
|
||||
serviceTicket.getServer();
|
||||
// Cannot use '\"' instead of "\"" in constructor because
|
||||
// it is interpreted as suggested length!
|
||||
StringBuffer buf = new StringBuffer("\"");
|
||||
buf.append(delegateTo.getName()).append('\"');
|
||||
String realm = delegateTo.getRealmAsString();
|
||||
buf.append(" \"krbtgt/").append(realm).append('@');
|
||||
buf.append(realm).append('\"');
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
DelegationPermission perm =
|
||||
new DelegationPermission(buf.toString());
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write 1 in little endian but in two bytes
|
||||
* for DlgOpt
|
||||
*/
|
||||
|
||||
checksumBytes[pos++] = (byte)0x01;
|
||||
checksumBytes[pos++] = (byte)0x00;
|
||||
|
||||
/*
|
||||
* Write the length of the delegated credential in little
|
||||
* endian but in two bytes for Dlgth
|
||||
*/
|
||||
|
||||
if (krbCredMessage.length > 0x0000ffff)
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect message length");
|
||||
|
||||
writeLittleEndian(krbCredMessage.length, temp);
|
||||
checksumBytes[pos++] = temp[0];
|
||||
checksumBytes[pos++] = temp[1];
|
||||
System.arraycopy(krbCredMessage, 0,
|
||||
checksumBytes, pos, krbCredMessage.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on the acceptor side when reading an InitSecContextToken.
|
||||
*/
|
||||
// XXX Passing in Checksum is not required. byte[] can
|
||||
// be passed in if this checksum type denotes a
|
||||
// raw_checksum. In that case, make Checksum class krb5
|
||||
// internal.
|
||||
public OverloadedChecksum(Krb5Context context, Checksum checksum,
|
||||
EncryptionKey key, EncryptionKey subKey)
|
||||
throws GSSException, KrbException, IOException {
|
||||
|
||||
int pos = 0;
|
||||
|
||||
if (checksum == null) {
|
||||
GSSException ge = new GSSException(GSSException.FAILURE, -1,
|
||||
"No cksum in AP_REQ's authenticator");
|
||||
ge.initCause(new KrbException(Krb5.KRB_AP_ERR_INAPP_CKSUM));
|
||||
throw ge;
|
||||
}
|
||||
checksumBytes = checksum.getBytes();
|
||||
|
||||
if ((checksumBytes[0] != CHECKSUM_FIRST_BYTES[0]) ||
|
||||
(checksumBytes[1] != CHECKSUM_FIRST_BYTES[1]) ||
|
||||
(checksumBytes[2] != CHECKSUM_FIRST_BYTES[2]) ||
|
||||
(checksumBytes[3] != CHECKSUM_FIRST_BYTES[3])) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect checksum");
|
||||
}
|
||||
|
||||
ChannelBinding localBindings = context.getChannelBinding();
|
||||
|
||||
// Ignore remote channel binding info when not requested at
|
||||
// local side (RFC 4121 4.1.1.2: the acceptor MAY ignore...).
|
||||
//
|
||||
// All major krb5 implementors implement this "MAY",
|
||||
// and some applications depend on it as a workaround
|
||||
// for not having a way to negotiate the use of channel
|
||||
// binding -- the initiator application always uses CB
|
||||
// and hopes the acceptor will ignore the CB if the
|
||||
// acceptor doesn't support CB.
|
||||
if (localBindings != null) {
|
||||
byte[] remoteBindingBytes = new byte[CHECKSUM_BINDINGS_SIZE];
|
||||
System.arraycopy(checksumBytes, 4, remoteBindingBytes, 0,
|
||||
CHECKSUM_BINDINGS_SIZE);
|
||||
|
||||
byte[] noBindings = new byte[CHECKSUM_BINDINGS_SIZE];
|
||||
if (!Arrays.equals(noBindings, remoteBindingBytes)) {
|
||||
byte[] localBindingsBytes =
|
||||
computeChannelBinding(localBindings);
|
||||
if (!Arrays.equals(localBindingsBytes,
|
||||
remoteBindingBytes)) {
|
||||
throw new GSSException(GSSException.BAD_BINDINGS, -1,
|
||||
"Bytes mismatch!");
|
||||
}
|
||||
} else {
|
||||
throw new GSSException(GSSException.BAD_BINDINGS, -1,
|
||||
"Token missing ChannelBinding!");
|
||||
}
|
||||
}
|
||||
|
||||
flags = readLittleEndian(checksumBytes, 20, 4);
|
||||
|
||||
if ((flags & CHECKSUM_DELEG_FLAG) > 0) {
|
||||
|
||||
/*
|
||||
* XXX
|
||||
* if ((checksumBytes[24] != (byte)0x01) &&
|
||||
* (checksumBytes[25] != (byte)0x00))
|
||||
*/
|
||||
|
||||
int credLen = readLittleEndian(checksumBytes, 26, 2);
|
||||
byte[] credBytes = new byte[credLen];
|
||||
System.arraycopy(checksumBytes, 28, credBytes, 0, credLen);
|
||||
|
||||
KrbCred cred;
|
||||
try {
|
||||
cred = new KrbCred(credBytes, key);
|
||||
} catch (KrbException ke) {
|
||||
if (subKey != null) {
|
||||
cred = new KrbCred(credBytes, subKey);
|
||||
} else {
|
||||
throw ke;
|
||||
}
|
||||
}
|
||||
delegCreds = cred.getDelegatedCreds()[0];
|
||||
}
|
||||
}
|
||||
|
||||
// check if KRB-CRED message should use NULL_KEY for encryption
|
||||
private boolean useNullKey(CipherHelper ch) {
|
||||
boolean flag = true;
|
||||
// for "newer" etypes and RC4-HMAC do not use NULL KEY
|
||||
if ((ch.getProto() == 1) || ch.isArcFour()) {
|
||||
flag = false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
public Checksum getChecksum() throws KrbException {
|
||||
return new Checksum(checksumBytes, CHECKSUM_TYPE);
|
||||
}
|
||||
|
||||
public Credentials getDelegatedCreds() {
|
||||
return delegCreds;
|
||||
}
|
||||
|
||||
// Only called by acceptor
|
||||
public void setContextFlags(Krb5Context context) {
|
||||
// default for cred delegation is false
|
||||
if ((flags & CHECKSUM_DELEG_FLAG) > 0)
|
||||
context.setCredDelegState(true);
|
||||
// default for the following are true
|
||||
if ((flags & CHECKSUM_MUTUAL_FLAG) == 0) {
|
||||
context.setMutualAuthState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_REPLAY_FLAG) == 0) {
|
||||
context.setReplayDetState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_SEQUENCE_FLAG) == 0) {
|
||||
context.setSequenceDetState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_CONF_FLAG) == 0) {
|
||||
context.setConfState(false);
|
||||
}
|
||||
if ((flags & CHECKSUM_INTEG_FLAG) == 0) {
|
||||
context.setIntegState(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getAddrType(InetAddress addr) {
|
||||
int addressType = CHANNEL_BINDING_AF_NULL_ADDR;
|
||||
|
||||
if (addr instanceof Inet4Address)
|
||||
addressType = CHANNEL_BINDING_AF_INET;
|
||||
else if (addr instanceof Inet6Address)
|
||||
addressType = CHANNEL_BINDING_AF_INET6;
|
||||
return (addressType);
|
||||
}
|
||||
|
||||
private byte[] getAddrBytes(InetAddress addr) throws GSSException {
|
||||
int addressType = getAddrType(addr);
|
||||
byte[] addressBytes = addr.getAddress();
|
||||
if (addressBytes != null) {
|
||||
switch (addressType) {
|
||||
case CHANNEL_BINDING_AF_INET:
|
||||
if (addressBytes.length != Inet4_ADDRSZ) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect AF-INET address length in ChannelBinding.");
|
||||
}
|
||||
return (addressBytes);
|
||||
case CHANNEL_BINDING_AF_INET6:
|
||||
if (addressBytes.length != Inet6_ADDRSZ) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Incorrect AF-INET6 address length in ChannelBinding.");
|
||||
}
|
||||
return (addressBytes);
|
||||
default:
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Cannot handle non AF-INET addresses in ChannelBinding.");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private byte[] computeChannelBinding(ChannelBinding channelBinding)
|
||||
throws GSSException {
|
||||
|
||||
InetAddress initiatorAddress = channelBinding.getInitiatorAddress();
|
||||
InetAddress acceptorAddress = channelBinding.getAcceptorAddress();
|
||||
int size = 5*4;
|
||||
|
||||
int initiatorAddressType = getAddrType(initiatorAddress);
|
||||
int acceptorAddressType = getAddrType(acceptorAddress);
|
||||
|
||||
byte[] initiatorAddressBytes = null;
|
||||
if (initiatorAddress != null) {
|
||||
initiatorAddressBytes = getAddrBytes(initiatorAddress);
|
||||
size += initiatorAddressBytes.length;
|
||||
}
|
||||
|
||||
byte[] acceptorAddressBytes = null;
|
||||
if (acceptorAddress != null) {
|
||||
acceptorAddressBytes = getAddrBytes(acceptorAddress);
|
||||
size += acceptorAddressBytes.length;
|
||||
}
|
||||
|
||||
byte[] appDataBytes = channelBinding.getApplicationData();
|
||||
if (appDataBytes != null) {
|
||||
size += appDataBytes.length;
|
||||
}
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
int pos = 0;
|
||||
|
||||
writeLittleEndian(initiatorAddressType, data, pos);
|
||||
pos += 4;
|
||||
|
||||
if (initiatorAddressBytes != null) {
|
||||
writeLittleEndian(initiatorAddressBytes.length, data, pos);
|
||||
pos += 4;
|
||||
System.arraycopy(initiatorAddressBytes, 0,
|
||||
data, pos, initiatorAddressBytes.length);
|
||||
pos += initiatorAddressBytes.length;
|
||||
} else {
|
||||
// Write length 0
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
writeLittleEndian(acceptorAddressType, data, pos);
|
||||
pos += 4;
|
||||
|
||||
if (acceptorAddressBytes != null) {
|
||||
writeLittleEndian(acceptorAddressBytes.length, data, pos);
|
||||
pos += 4;
|
||||
System.arraycopy(acceptorAddressBytes, 0,
|
||||
data, pos, acceptorAddressBytes.length);
|
||||
pos += acceptorAddressBytes.length;
|
||||
} else {
|
||||
// Write length 0
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
if (appDataBytes != null) {
|
||||
writeLittleEndian(appDataBytes.length, data, pos);
|
||||
pos += 4;
|
||||
System.arraycopy(appDataBytes, 0, data, pos,
|
||||
appDataBytes.length);
|
||||
pos += appDataBytes.length;
|
||||
} else {
|
||||
// Write 0
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
try {
|
||||
MessageDigest md5 = MessageDigest.getInstance("MD5");
|
||||
return md5.digest(data);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not get MD5 Message Digest - "
|
||||
+ e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public abstract byte[] encode() throws IOException;
|
||||
|
||||
}
|
||||
197
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5AcceptCredential.java
Normal file
197
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5AcceptCredential.java
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.krb5;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.*;
|
||||
import java.security.PrivilegedActionException;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
|
||||
/**
|
||||
* Implements the krb5 acceptor credential element.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
public class Krb5AcceptCredential
|
||||
implements Krb5CredElement {
|
||||
|
||||
private final Krb5NameElement name;
|
||||
private final ServiceCreds screds;
|
||||
|
||||
private Krb5AcceptCredential(Krb5NameElement name, ServiceCreds creds) {
|
||||
/*
|
||||
* Initialize this instance with the data from the acquired
|
||||
* KerberosKey. This class needs to be a KerberosKey too
|
||||
* hence we can't just store a reference.
|
||||
*/
|
||||
|
||||
this.name = name;
|
||||
this.screds = creds;
|
||||
}
|
||||
|
||||
static Krb5AcceptCredential getInstance(final GSSCaller caller, Krb5NameElement name)
|
||||
throws GSSException {
|
||||
|
||||
final String serverPrinc = (name == null? null:
|
||||
name.getKrb5PrincipalName().getName());
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
ServiceCreds creds = null;
|
||||
try {
|
||||
creds = AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<ServiceCreds>() {
|
||||
public ServiceCreds run() throws Exception {
|
||||
return Krb5Util.getServiceCreds(
|
||||
caller == GSSCaller.CALLER_UNKNOWN ? GSSCaller.CALLER_ACCEPT: caller,
|
||||
serverPrinc, acc);
|
||||
}});
|
||||
} catch (PrivilegedActionException e) {
|
||||
GSSException ge =
|
||||
new GSSException(GSSException.NO_CRED, -1,
|
||||
"Attempt to obtain new ACCEPT credentials failed!");
|
||||
ge.initCause(e.getException());
|
||||
throw ge;
|
||||
}
|
||||
|
||||
if (creds == null)
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
"Failed to find any Kerberos credentails");
|
||||
|
||||
if (name == null) {
|
||||
String fullName = creds.getName();
|
||||
if (fullName != null) {
|
||||
name = Krb5NameElement.getInstance(fullName,
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
}
|
||||
}
|
||||
|
||||
return new Krb5AcceptCredential(name, creds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the principal name for this credential. The name
|
||||
* is in mechanism specific format.
|
||||
*
|
||||
* @return GSSNameSpi representing principal name of this credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final GSSNameSpi getName() throws GSSException {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the init lifetime remaining.
|
||||
*
|
||||
* @return the init lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getInitLifetime() throws GSSException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accept lifetime remaining.
|
||||
*
|
||||
* @return the accept lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return GSSCredential.INDEFINITE_LIFETIME;
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid representing the underlying credential
|
||||
* mechanism oid.
|
||||
*
|
||||
* @return the Oid for this credential mechanism
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final Oid getMechanism() {
|
||||
return Krb5MechFactory.GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
public final java.security.Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
public EncryptionKey[] getKrb5EncryptionKeys(PrincipalName princ) {
|
||||
return screds.getEKeys(princ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to invalidate this credential element.
|
||||
*/
|
||||
public void dispose() throws GSSException {
|
||||
try {
|
||||
destroy();
|
||||
} catch (DestroyFailedException e) {
|
||||
GSSException gssException =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not destroy credentials - " + e.getMessage());
|
||||
gssException.initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the locally cached EncryptionKey value and then calls
|
||||
* destroy in the base class.
|
||||
*/
|
||||
public void destroy() throws DestroyFailedException {
|
||||
screds.destroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Impersonation is only available on the initiator side. The
|
||||
* service must starts as an initiator to get an initial TGT to complete
|
||||
* the S4U2self protocol.
|
||||
*/
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
Credentials cred = screds.getInitCred();
|
||||
if (cred != null) {
|
||||
return Krb5InitCredential.getInstance(this.name, cred)
|
||||
.impersonate(name);
|
||||
} else {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Only an initiate credentials can impersonate");
|
||||
}
|
||||
}
|
||||
}
|
||||
1454
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Context.java
Normal file
1454
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Context.java
Normal file
File diff suppressed because it is too large
Load Diff
41
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5CredElement.java
Normal file
41
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5CredElement.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* Provides type safety for Krb5 credential elements.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @since 1.4
|
||||
*/
|
||||
interface Krb5CredElement
|
||||
extends GSSCredentialSpi {
|
||||
}
|
||||
406
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5InitCredential.java
Normal file
406
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5InitCredential.java
Normal file
@@ -0,0 +1,406 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.Config;
|
||||
import javax.security.auth.kerberos.*;
|
||||
import java.net.InetAddress;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.security.PrivilegedActionException;
|
||||
|
||||
/**
|
||||
* Implements the krb5 initiator credential element.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @author Ram Marti
|
||||
* @since 1.4
|
||||
*/
|
||||
|
||||
public class Krb5InitCredential
|
||||
extends KerberosTicket
|
||||
implements Krb5CredElement {
|
||||
|
||||
private static final long serialVersionUID = 7723415700837898232L;
|
||||
|
||||
private Krb5NameElement name;
|
||||
private Credentials krb5Credentials;
|
||||
public KerberosTicket proxyTicket;
|
||||
|
||||
private Krb5InitCredential(Krb5NameElement name,
|
||||
byte[] asn1Encoding,
|
||||
KerberosPrincipal client,
|
||||
KerberosPrincipal clientAlias,
|
||||
KerberosPrincipal server,
|
||||
KerberosPrincipal serverAlias,
|
||||
byte[] sessionKey,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
Date authTime,
|
||||
Date startTime,
|
||||
Date endTime,
|
||||
Date renewTill,
|
||||
InetAddress[] clientAddresses)
|
||||
throws GSSException {
|
||||
super(asn1Encoding,
|
||||
client,
|
||||
server,
|
||||
sessionKey,
|
||||
keyType,
|
||||
flags,
|
||||
authTime,
|
||||
startTime,
|
||||
endTime,
|
||||
renewTill,
|
||||
clientAddresses);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetClientAlias(this, clientAlias);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetServerAlias(this, serverAlias);
|
||||
this.name = name;
|
||||
|
||||
try {
|
||||
// Cache this for later use by the sun.security.krb5 package.
|
||||
krb5Credentials = new Credentials(asn1Encoding,
|
||||
client.getName(),
|
||||
(clientAlias != null ?
|
||||
clientAlias.getName() : null),
|
||||
server.getName(),
|
||||
(serverAlias != null ?
|
||||
serverAlias.getName() : null),
|
||||
sessionKey,
|
||||
keyType,
|
||||
flags,
|
||||
authTime,
|
||||
startTime,
|
||||
endTime,
|
||||
renewTill,
|
||||
clientAddresses);
|
||||
} catch (KrbException e) {
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Krb5InitCredential(Krb5NameElement name,
|
||||
Credentials delegatedCred,
|
||||
byte[] asn1Encoding,
|
||||
KerberosPrincipal client,
|
||||
KerberosPrincipal clientAlias,
|
||||
KerberosPrincipal server,
|
||||
KerberosPrincipal serverAlias,
|
||||
byte[] sessionKey,
|
||||
int keyType,
|
||||
boolean[] flags,
|
||||
Date authTime,
|
||||
Date startTime,
|
||||
Date endTime,
|
||||
Date renewTill,
|
||||
InetAddress[] clientAddresses)
|
||||
throws GSSException {
|
||||
super(asn1Encoding,
|
||||
client,
|
||||
server,
|
||||
sessionKey,
|
||||
keyType,
|
||||
flags,
|
||||
authTime,
|
||||
startTime,
|
||||
endTime,
|
||||
renewTill,
|
||||
clientAddresses);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetClientAlias(this, clientAlias);
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetServerAlias(this, serverAlias);
|
||||
this.name = name;
|
||||
// A delegated cred does not have all fields set. So do not try to
|
||||
// creat new Credentials out of the delegatedCred.
|
||||
this.krb5Credentials = delegatedCred;
|
||||
}
|
||||
|
||||
static Krb5InitCredential getInstance(GSSCaller caller, Krb5NameElement name,
|
||||
int initLifetime)
|
||||
throws GSSException {
|
||||
|
||||
KerberosTicket tgt = getTgt(caller, name, initLifetime);
|
||||
if (tgt == null)
|
||||
throw new GSSException(GSSException.NO_CRED, -1,
|
||||
"Failed to find any Kerberos tgt");
|
||||
|
||||
if (name == null) {
|
||||
String fullName = tgt.getClient().getName();
|
||||
name = Krb5NameElement.getInstance(fullName,
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
}
|
||||
|
||||
KerberosPrincipal clientAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetClientAlias(tgt);
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(tgt);
|
||||
Krb5InitCredential result = new Krb5InitCredential(name,
|
||||
tgt.getEncoded(),
|
||||
tgt.getClient(),
|
||||
clientAlias,
|
||||
tgt.getServer(),
|
||||
serverAlias,
|
||||
tgt.getSessionKey().getEncoded(),
|
||||
tgt.getSessionKeyType(),
|
||||
tgt.getFlags(),
|
||||
tgt.getAuthTime(),
|
||||
tgt.getStartTime(),
|
||||
tgt.getEndTime(),
|
||||
tgt.getRenewTill(),
|
||||
tgt.getClientAddresses());
|
||||
result.proxyTicket = KerberosSecrets.getJavaxSecurityAuthKerberosAccess().
|
||||
kerberosTicketGetProxy(tgt);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Krb5InitCredential getInstance(Krb5NameElement name,
|
||||
Credentials delegatedCred)
|
||||
throws GSSException {
|
||||
|
||||
EncryptionKey sessionKey = delegatedCred.getSessionKey();
|
||||
|
||||
/*
|
||||
* all of the following data is optional in a KRB-CRED
|
||||
* messages. This check for each field.
|
||||
*/
|
||||
|
||||
PrincipalName cPrinc = delegatedCred.getClient();
|
||||
PrincipalName cAPrinc = delegatedCred.getClientAlias();
|
||||
PrincipalName sPrinc = delegatedCred.getServer();
|
||||
PrincipalName sAPrinc = delegatedCred.getServerAlias();
|
||||
|
||||
KerberosPrincipal client = null;
|
||||
KerberosPrincipal clientAlias = null;
|
||||
KerberosPrincipal server = null;
|
||||
KerberosPrincipal serverAlias = null;
|
||||
|
||||
Krb5NameElement credName = null;
|
||||
|
||||
if (cPrinc != null) {
|
||||
String fullName = cPrinc.getName();
|
||||
credName = Krb5NameElement.getInstance(fullName,
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
client = new KerberosPrincipal(fullName);
|
||||
}
|
||||
|
||||
if (cAPrinc != null) {
|
||||
clientAlias = new KerberosPrincipal(cAPrinc.getName());
|
||||
}
|
||||
|
||||
// XXX Compare name to credName
|
||||
|
||||
if (sPrinc != null) {
|
||||
server =
|
||||
new KerberosPrincipal(sPrinc.getName(),
|
||||
KerberosPrincipal.KRB_NT_SRV_INST);
|
||||
}
|
||||
|
||||
if (sAPrinc != null) {
|
||||
serverAlias = new KerberosPrincipal(sAPrinc.getName());
|
||||
}
|
||||
|
||||
return new Krb5InitCredential(credName,
|
||||
delegatedCred,
|
||||
delegatedCred.getEncoded(),
|
||||
client,
|
||||
clientAlias,
|
||||
server,
|
||||
serverAlias,
|
||||
sessionKey.getBytes(),
|
||||
sessionKey.getEType(),
|
||||
delegatedCred.getFlags(),
|
||||
delegatedCred.getAuthTime(),
|
||||
delegatedCred.getStartTime(),
|
||||
delegatedCred.getEndTime(),
|
||||
delegatedCred.getRenewTill(),
|
||||
delegatedCred.getClientAddresses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the principal name for this credential. The name
|
||||
* is in mechanism specific format.
|
||||
*
|
||||
* @return GSSNameSpi representing principal name of this credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final GSSNameSpi getName() throws GSSException {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the init lifetime remaining.
|
||||
*
|
||||
* @return the init lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getInitLifetime() throws GSSException {
|
||||
Date d = getEndTime();
|
||||
if (d == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long retVal = d.getTime() - System.currentTimeMillis();
|
||||
return (int)(retVal/1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the accept lifetime remaining.
|
||||
*
|
||||
* @return the accept lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid representing the underlying credential
|
||||
* mechanism oid.
|
||||
*
|
||||
* @return the Oid for this credential mechanism
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public final Oid getMechanism() {
|
||||
return Krb5MechFactory.GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
public final java.security.Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a sun.security.krb5.Credentials instance so that it maybe
|
||||
* used in that package for th Kerberos protocol.
|
||||
*/
|
||||
Credentials getKrb5Credentials() {
|
||||
return krb5Credentials;
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX Call to this.refresh() should refresh the locally cached copy
|
||||
* of krb5Credentials also.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Called to invalidate this credential element.
|
||||
*/
|
||||
public void dispose() throws GSSException {
|
||||
try {
|
||||
destroy();
|
||||
} catch (javax.security.auth.DestroyFailedException e) {
|
||||
GSSException gssException =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not destroy credentials - " + e.getMessage());
|
||||
gssException.initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX call to this.destroy() should destroy the locally cached copy
|
||||
// of krb5Credentials and then call super.destroy().
|
||||
|
||||
private static KerberosTicket getTgt(GSSCaller caller, Krb5NameElement name,
|
||||
int initLifetime)
|
||||
throws GSSException {
|
||||
|
||||
final String clientPrincipal;
|
||||
|
||||
/*
|
||||
* Find the TGT for the realm that the client is in. If the client
|
||||
* name is not available, then use the default realm.
|
||||
*/
|
||||
if (name != null) {
|
||||
clientPrincipal = (name.getKrb5PrincipalName()).getName();
|
||||
} else {
|
||||
clientPrincipal = null;
|
||||
}
|
||||
|
||||
final AccessControlContext acc = AccessController.getContext();
|
||||
|
||||
try {
|
||||
final GSSCaller realCaller = (caller == GSSCaller.CALLER_UNKNOWN)
|
||||
? GSSCaller.CALLER_INITIATE
|
||||
: caller;
|
||||
return AccessController.doPrivileged(
|
||||
new PrivilegedExceptionAction<KerberosTicket>() {
|
||||
public KerberosTicket run() throws Exception {
|
||||
// It's OK to use null as serverPrincipal. TGT is almost
|
||||
// the first ticket for a principal and we use list.
|
||||
return Krb5Util.getInitialTicket(
|
||||
realCaller,
|
||||
clientPrincipal, acc);
|
||||
}});
|
||||
} catch (PrivilegedActionException e) {
|
||||
GSSException ge =
|
||||
new GSSException(GSSException.NO_CRED, -1,
|
||||
"Attempt to obtain new INITIATE credentials failed!" +
|
||||
" (" + e.getMessage() + ")");
|
||||
ge.initCause(e.getException());
|
||||
throw ge;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
try {
|
||||
Krb5NameElement kname = (Krb5NameElement)name;
|
||||
Credentials newCred = Credentials.acquireS4U2selfCreds(
|
||||
kname.getKrb5PrincipalName(), krb5Credentials);
|
||||
return new Krb5ProxyCredential(this, kname, newCred.getTicket());
|
||||
} catch (IOException | KrbException ke) {
|
||||
GSSException ge =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Attempt to obtain S4U2self credentials failed!");
|
||||
ge.initCause(ke);
|
||||
throw ge;
|
||||
}
|
||||
}
|
||||
}
|
||||
234
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5MechFactory.java
Normal file
234
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5MechFactory.java
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
import java.security.Provider;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Krb5 Mechanism plug in for JGSS
|
||||
* This is the properties object required by the JGSS framework.
|
||||
* All mechanism specific information is defined here.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public final class Krb5MechFactory implements MechanismFactory {
|
||||
|
||||
private static final boolean DEBUG = Krb5Util.DEBUG;
|
||||
|
||||
static final Provider PROVIDER =
|
||||
new sun.security.jgss.SunProvider();
|
||||
|
||||
static final Oid GSS_KRB5_MECH_OID =
|
||||
createOid("1.2.840.113554.1.2.2");
|
||||
|
||||
static final Oid NT_GSS_KRB5_PRINCIPAL =
|
||||
createOid("1.2.840.113554.1.2.2.1");
|
||||
|
||||
private static Oid[] nameTypes =
|
||||
new Oid[] { GSSName.NT_USER_NAME,
|
||||
GSSName.NT_HOSTBASED_SERVICE,
|
||||
GSSName.NT_EXPORT_NAME,
|
||||
NT_GSS_KRB5_PRINCIPAL};
|
||||
|
||||
final private GSSCaller caller;
|
||||
|
||||
private static Krb5CredElement getCredFromSubject(GSSNameSpi name,
|
||||
boolean initiate)
|
||||
throws GSSException {
|
||||
Vector<Krb5CredElement> creds =
|
||||
GSSUtil.searchSubject(name, GSS_KRB5_MECH_OID, initiate,
|
||||
(initiate ?
|
||||
Krb5InitCredential.class :
|
||||
Krb5AcceptCredential.class));
|
||||
|
||||
Krb5CredElement result = ((creds == null || creds.isEmpty()) ?
|
||||
null : creds.firstElement());
|
||||
|
||||
// Force permission check before returning the cred to caller
|
||||
if (result != null) {
|
||||
if (initiate) {
|
||||
checkInitCredPermission((Krb5NameElement) result.getName());
|
||||
} else {
|
||||
checkAcceptCredPermission
|
||||
((Krb5NameElement) result.getName(), name);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Krb5MechFactory(GSSCaller caller) {
|
||||
this.caller = caller;
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
return Krb5NameElement.getInstance(nameStr, nameType);
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException {
|
||||
// At this point, even an exported name is stripped down to safe
|
||||
// bytes only
|
||||
// XXX Use encoding here
|
||||
return Krb5NameElement.getInstance(new String(name), nameType);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime, int acceptLifetime,
|
||||
int usage) throws GSSException {
|
||||
|
||||
if (name != null && !(name instanceof Krb5NameElement)) {
|
||||
name = Krb5NameElement.getInstance(name.toString(),
|
||||
name.getStringNameType());
|
||||
}
|
||||
|
||||
Krb5CredElement credElement = getCredFromSubject
|
||||
(name, (usage != GSSCredential.ACCEPT_ONLY));
|
||||
|
||||
if (credElement == null) {
|
||||
if (usage == GSSCredential.INITIATE_ONLY ||
|
||||
usage == GSSCredential.INITIATE_AND_ACCEPT) {
|
||||
credElement = Krb5InitCredential.getInstance
|
||||
(caller, (Krb5NameElement) name, initLifetime);
|
||||
credElement = Krb5ProxyCredential.tryImpersonation(
|
||||
caller, (Krb5InitCredential)credElement);
|
||||
checkInitCredPermission
|
||||
((Krb5NameElement) credElement.getName());
|
||||
} else if (usage == GSSCredential.ACCEPT_ONLY) {
|
||||
credElement =
|
||||
Krb5AcceptCredential.getInstance(caller,
|
||||
(Krb5NameElement) name);
|
||||
checkAcceptCredPermission
|
||||
((Krb5NameElement) credElement.getName(), name);
|
||||
} else
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Unknown usage mode requested");
|
||||
}
|
||||
return credElement;
|
||||
}
|
||||
|
||||
public static void checkInitCredPermission(Krb5NameElement name) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
String realm = (name.getKrb5PrincipalName()).getRealmAsString();
|
||||
String tgsPrincipal =
|
||||
new String("krbtgt/" + realm + '@' + realm);
|
||||
ServicePermission perm =
|
||||
new ServicePermission(tgsPrincipal, "initiate");
|
||||
try {
|
||||
sm.checkPermission(perm);
|
||||
} catch (SecurityException e) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Permission to initiate" +
|
||||
"kerberos init credential" + e.getMessage());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkAcceptCredPermission(Krb5NameElement name,
|
||||
GSSNameSpi originalName) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null && name != null) {
|
||||
ServicePermission perm = new ServicePermission
|
||||
(name.getKrb5PrincipalName().getName(), "accept");
|
||||
try {
|
||||
sm.checkPermission(perm);
|
||||
} catch (SecurityException e) {
|
||||
if (originalName == null) {
|
||||
// Don't disclose the name of the principal
|
||||
e = new SecurityException("No permission to acquire "
|
||||
+ "Kerberos accept credential");
|
||||
// Don't call e.initCause() with caught exception
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred, int lifetime)
|
||||
throws GSSException {
|
||||
if (peer != null && !(peer instanceof Krb5NameElement)) {
|
||||
peer = Krb5NameElement.getInstance(peer.toString(),
|
||||
peer.getStringNameType());
|
||||
}
|
||||
// XXX Convert myInitiatorCred to Krb5CredElement
|
||||
if (myInitiatorCred == null) {
|
||||
myInitiatorCred = getCredentialElement(null, lifetime, 0,
|
||||
GSSCredential.INITIATE_ONLY);
|
||||
}
|
||||
return new Krb5Context(caller, (Krb5NameElement)peer,
|
||||
(Krb5CredElement)myInitiatorCred, lifetime);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
|
||||
throws GSSException {
|
||||
// XXX Convert myAcceptorCred to Krb5CredElement
|
||||
if (myAcceptorCred == null) {
|
||||
myAcceptorCred = getCredentialElement(null, 0,
|
||||
GSSCredential.INDEFINITE_LIFETIME, GSSCredential.ACCEPT_ONLY);
|
||||
}
|
||||
return new Krb5Context(caller, (Krb5CredElement)myAcceptorCred);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
return new Krb5Context(caller, exportedContext);
|
||||
}
|
||||
|
||||
|
||||
public final Oid getMechanismOid() {
|
||||
return GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return PROVIDER;
|
||||
}
|
||||
|
||||
public Oid[] getNameTypes() {
|
||||
// nameTypes is cloned in GSSManager.getNamesForMech
|
||||
return nameTypes;
|
||||
}
|
||||
|
||||
private static Oid createOid(String oidStr) {
|
||||
Oid retVal = null;
|
||||
try {
|
||||
retVal = new Oid(oidStr);
|
||||
} catch (GSSException e) {
|
||||
// Should not happen!
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
348
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5NameElement.java
Normal file
348
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5NameElement.java
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.krb5.PrincipalName;
|
||||
import sun.security.krb5.Realm;
|
||||
import sun.security.krb5.KrbException;
|
||||
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.Provider;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Implements the GSSNameSpi for the krb5 mechanism.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
public class Krb5NameElement
|
||||
implements GSSNameSpi {
|
||||
|
||||
private PrincipalName krb5PrincipalName;
|
||||
|
||||
private String gssNameStr = null;
|
||||
private Oid gssNameType = null;
|
||||
|
||||
// XXX Move this concept into PrincipalName's asn1Encode() sometime
|
||||
private static String CHAR_ENCODING = "UTF-8";
|
||||
|
||||
private Krb5NameElement(PrincipalName principalName,
|
||||
String gssNameStr,
|
||||
Oid gssNameType) {
|
||||
this.krb5PrincipalName = principalName;
|
||||
this.gssNameStr = gssNameStr;
|
||||
this.gssNameType = gssNameType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Krb5NameElement object. Internally it stores the
|
||||
* information provided by the input parameters so that they may later
|
||||
* be used for output when a printable representaion of this name is
|
||||
* needed in GSS-API format rather than in Kerberos format.
|
||||
*
|
||||
*/
|
||||
static Krb5NameElement getInstance(String gssNameStr, Oid gssNameType)
|
||||
throws GSSException {
|
||||
|
||||
/*
|
||||
* A null gssNameType implies that the mechanism default
|
||||
* Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL be used.
|
||||
*/
|
||||
if (gssNameType == null)
|
||||
gssNameType = Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL;
|
||||
else
|
||||
if (!gssNameType.equals(GSSName.NT_USER_NAME) &&
|
||||
!gssNameType.equals(GSSName.NT_HOSTBASED_SERVICE) &&
|
||||
!gssNameType.equals(Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL) &&
|
||||
!gssNameType.equals(GSSName.NT_EXPORT_NAME))
|
||||
throw new GSSException(GSSException.BAD_NAMETYPE, -1,
|
||||
gssNameType.toString()
|
||||
+" is an unsupported nametype");
|
||||
|
||||
PrincipalName principalName;
|
||||
try {
|
||||
|
||||
if (gssNameType.equals(GSSName.NT_EXPORT_NAME) ||
|
||||
gssNameType.equals(Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL)) {
|
||||
principalName = new PrincipalName(gssNameStr,
|
||||
PrincipalName.KRB_NT_PRINCIPAL);
|
||||
} else {
|
||||
|
||||
String[] components = getComponents(gssNameStr);
|
||||
|
||||
/*
|
||||
* We have forms of GSS name strings that can come in:
|
||||
*
|
||||
* 1. names of the form "foo" with just one
|
||||
* component. (This might include a "@" but only in escaped
|
||||
* form like "\@")
|
||||
* 2. names of the form "foo@bar" with two components
|
||||
*
|
||||
* The nametypes that are accepted are NT_USER_NAME, and
|
||||
* NT_HOSTBASED_SERVICE.
|
||||
*/
|
||||
|
||||
if (gssNameType.equals(GSSName.NT_USER_NAME))
|
||||
principalName = new PrincipalName(gssNameStr,
|
||||
PrincipalName.KRB_NT_PRINCIPAL);
|
||||
else {
|
||||
String hostName = null;
|
||||
String service = components[0];
|
||||
if (components.length >= 2)
|
||||
hostName = components[1];
|
||||
|
||||
String principal = getHostBasedInstance(service, hostName);
|
||||
principalName = new PrincipalName(principal,
|
||||
PrincipalName.KRB_NT_SRV_HST);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (KrbException e) {
|
||||
throw new GSSException(GSSException.BAD_NAME, -1, e.getMessage());
|
||||
}
|
||||
|
||||
if (principalName.isRealmDeduced() && !Realm.AUTODEDUCEREALM) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
try {
|
||||
sm.checkPermission(new ServicePermission(
|
||||
"@" + principalName.getRealmAsString(), "-"));
|
||||
} catch (SecurityException se) {
|
||||
// Do not chain the actual exception to hide info
|
||||
throw new GSSException(GSSException.FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Krb5NameElement(principalName, gssNameStr, gssNameType);
|
||||
}
|
||||
|
||||
public static Krb5NameElement getInstance(PrincipalName principalName) {
|
||||
return new Krb5NameElement(principalName,
|
||||
principalName.getName(),
|
||||
Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL);
|
||||
}
|
||||
|
||||
private static String[] getComponents(String gssNameStr)
|
||||
throws GSSException {
|
||||
|
||||
String[] retVal;
|
||||
|
||||
// XXX Perhaps provide this parsing code in PrincipalName
|
||||
|
||||
// Look for @ as in service@host
|
||||
// Assumes host name will not have an escaped '@'
|
||||
int separatorPos = gssNameStr.lastIndexOf('@', gssNameStr.length());
|
||||
|
||||
// Not really a separator if it is escaped. Then this is just part
|
||||
// of the principal name or service name
|
||||
if ((separatorPos > 0) &&
|
||||
(gssNameStr.charAt(separatorPos-1) == '\\')) {
|
||||
// Is the `\` character escaped itself?
|
||||
if ((separatorPos - 2 < 0) ||
|
||||
(gssNameStr.charAt(separatorPos-2) != '\\'))
|
||||
separatorPos = -1;
|
||||
}
|
||||
|
||||
if (separatorPos > 0) {
|
||||
String serviceName = gssNameStr.substring(0, separatorPos);
|
||||
String hostName = gssNameStr.substring(separatorPos+1);
|
||||
retVal = new String[] { serviceName, hostName};
|
||||
} else {
|
||||
retVal = new String[] {gssNameStr};
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
private static String getHostBasedInstance(String serviceName,
|
||||
String hostName)
|
||||
throws GSSException {
|
||||
StringBuffer temp = new StringBuffer(serviceName);
|
||||
|
||||
try {
|
||||
// A lack of "@" defaults to the service being on the local
|
||||
// host as per RFC 2743
|
||||
// XXX Move this part into JGSS framework
|
||||
if (hostName == null)
|
||||
hostName = InetAddress.getLocalHost().getHostName();
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
// use hostname as it is
|
||||
}
|
||||
hostName = hostName.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
temp = temp.append('/').append(hostName);
|
||||
return temp.toString();
|
||||
}
|
||||
|
||||
public final PrincipalName getKrb5PrincipalName() {
|
||||
return krb5PrincipalName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equal method for the GSSNameSpi objects.
|
||||
* If either name denotes an anonymous principal, the call should
|
||||
* return false.
|
||||
*
|
||||
* @param other to be compared with
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @exception GSSException with major codes of BAD_NAMETYPE,
|
||||
* BAD_NAME, FAILURE
|
||||
*/
|
||||
public boolean equals(GSSNameSpi other) throws GSSException {
|
||||
|
||||
if (other == this)
|
||||
return true;
|
||||
|
||||
if (other instanceof Krb5NameElement) {
|
||||
Krb5NameElement that = (Krb5NameElement) other;
|
||||
return (this.krb5PrincipalName.getName().equals(
|
||||
that.krb5PrincipalName.getName()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this <code>GSSNameSpi</code> object to another Object
|
||||
* that might be a <code>GSSNameSpi</code>. The behaviour is exactly
|
||||
* the same as in {@link #equals(GSSNameSpi) equals} except that
|
||||
* no GSSException is thrown; instead, false will be returned in the
|
||||
* situation where an error occurs.
|
||||
*
|
||||
* @param another the object to be compared to
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @see #equals(GSSNameSpi)
|
||||
*/
|
||||
public boolean equals(Object another) {
|
||||
if (this == another) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (another instanceof Krb5NameElement)
|
||||
return equals((Krb5NameElement) another);
|
||||
} catch (GSSException e) {
|
||||
// ignore exception
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSNameSpi.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode() {
|
||||
return 37 * 17 + krb5PrincipalName.getName().hashCode();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the principal name in the form user@REALM or
|
||||
* host/service@REALM but with the following constraints that are
|
||||
* imposed by RFC 1964:
|
||||
* <pre>
|
||||
* (1) all occurrences of the characters `@`, `/`, and `\` within
|
||||
* principal components or realm names shall be quoted with an
|
||||
* immediately-preceding `\`.
|
||||
*
|
||||
* (2) all occurrences of the null, backspace, tab, or newline
|
||||
* characters within principal components or realm names will be
|
||||
* represented, respectively, with `\0`, `\b`, `\t`, or `\n`.
|
||||
*
|
||||
* (3) the `\` quoting character shall not be emitted within an
|
||||
* exported name except to accommodate cases (1) and (2).
|
||||
* </pre>
|
||||
*/
|
||||
public byte[] export() throws GSSException {
|
||||
// XXX Apply the above constraints.
|
||||
byte[] retVal = null;
|
||||
try {
|
||||
retVal = krb5PrincipalName.getName().getBytes(CHAR_ENCODING);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// Can't happen
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mechanism type that this NameElement corresponds to.
|
||||
*
|
||||
* @return the Oid of the mechanism type
|
||||
*/
|
||||
public Oid getMechanism() {
|
||||
return (Krb5MechFactory.GSS_KRB5_MECH_OID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation for this name. The printed
|
||||
* name type can be obtained by calling getStringNameType().
|
||||
*
|
||||
* @return string form of this name
|
||||
* @see #getStringNameType()
|
||||
* @overrides Object#toString
|
||||
*/
|
||||
public String toString() {
|
||||
return (gssNameStr);
|
||||
// For testing: return (super.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name type oid.
|
||||
*/
|
||||
public Oid getGSSNameType() {
|
||||
return (gssNameType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid describing the format of the printable name.
|
||||
*
|
||||
* @return the Oid for the format of the printed name
|
||||
*/
|
||||
public Oid getStringNameType() {
|
||||
// XXX For NT_EXPORT_NAME return a different name type. Infact,
|
||||
// don't even store NT_EXPORT_NAME in the cons.
|
||||
return (gssNameType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if this name object represents an Anonymous name.
|
||||
*/
|
||||
public boolean isAnonymousName() {
|
||||
return (gssNameType.equals(GSSName.NT_ANONYMOUS));
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
}
|
||||
142
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5ProxyCredential.java
Normal file
142
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5ProxyCredential.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2019, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.spi.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import sun.security.krb5.Credentials;
|
||||
import sun.security.krb5.KrbException;
|
||||
import sun.security.krb5.internal.Ticket;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
|
||||
/**
|
||||
* Implements the krb5 proxy credential element used in constrained
|
||||
* delegation. It is used in both impersonation (where there is no Kerberos 5
|
||||
* communication between the middle server and the client) and normal
|
||||
* constrained delegation (where there is, but client has not called
|
||||
* requestCredDeleg(true)).
|
||||
* @since 1.8
|
||||
*/
|
||||
|
||||
public class Krb5ProxyCredential
|
||||
implements Krb5CredElement {
|
||||
|
||||
public final Krb5InitCredential self; // the middle server
|
||||
private final Krb5NameElement client; // the client
|
||||
|
||||
// The ticket with cname=client and sname=self. This can be a normal
|
||||
// service ticket or an S4U2self ticket.
|
||||
public final Ticket tkt;
|
||||
|
||||
Krb5ProxyCredential(Krb5InitCredential self, Krb5NameElement client,
|
||||
Ticket tkt) {
|
||||
this.self = self;
|
||||
this.tkt = tkt;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
// The client name behind the proxy
|
||||
@Override
|
||||
public final Krb5NameElement getName() throws GSSException {
|
||||
return client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInitLifetime() throws GSSException {
|
||||
// endTime of tkt is not used by KDC, and it's also not
|
||||
// available in the case of kerberos constr deleg
|
||||
return self.getInitLifetime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Oid getMechanism() {
|
||||
return Krb5MechFactory.GSS_KRB5_MECH_OID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final java.security.Provider getProvider() {
|
||||
return Krb5MechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() throws GSSException {
|
||||
try {
|
||||
self.destroy();
|
||||
} catch (javax.security.auth.DestroyFailedException e) {
|
||||
GSSException gssException =
|
||||
new GSSException(GSSException.FAILURE, -1,
|
||||
"Could not destroy credentials - " + e.getMessage());
|
||||
gssException.initCause(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
// Cannot impersonate multiple levels without the impersonatee's TGT.
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Only an initiate credentials can impersonate");
|
||||
}
|
||||
|
||||
// Try to see if a default credential should act as an impersonator.
|
||||
static Krb5CredElement tryImpersonation(GSSCaller caller,
|
||||
Krb5InitCredential initiator) throws GSSException {
|
||||
|
||||
try {
|
||||
KerberosTicket proxy = initiator.proxyTicket;
|
||||
if (proxy != null) {
|
||||
Credentials proxyCreds = Krb5Util.ticketToCreds(proxy);
|
||||
return new Krb5ProxyCredential(initiator,
|
||||
Krb5NameElement.getInstance(proxyCreds.getClient()),
|
||||
proxyCreds.getTicket());
|
||||
} else {
|
||||
return initiator;
|
||||
}
|
||||
} catch (KrbException | IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_CREDENTIAL, -1,
|
||||
"Cannot create proxy credential");
|
||||
}
|
||||
}
|
||||
}
|
||||
118
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Token.java
Normal file
118
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Token.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, 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.krb5;
|
||||
|
||||
import java.io.IOException;
|
||||
import sun.security.util.*;
|
||||
import sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* This class represents a base class for all Kerberos v5 GSS-API
|
||||
* tokens. It contains commonly used definitions and utilities.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
abstract class Krb5Token extends GSSToken {
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the initSecContext call
|
||||
* carrying the AP_REQ .
|
||||
*/
|
||||
public static final int AP_REQ_ID = 0x0100;
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the acceptSecContext call
|
||||
* carrying the AP_REP .
|
||||
*/
|
||||
public static final int AP_REP_ID = 0x0200;
|
||||
|
||||
/**
|
||||
* The token id defined for any token carrying a KRB-ERR message.
|
||||
*/
|
||||
public static final int ERR_ID = 0x0300;
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the getMIC call.
|
||||
*/
|
||||
public static final int MIC_ID = 0x0101;
|
||||
|
||||
/**
|
||||
* The token id defined for the token emitted by the wrap call.
|
||||
*/
|
||||
public static final int WRAP_ID = 0x0201;
|
||||
|
||||
// new token ID draft-ietf-krb-wg-gssapi-cfx-07.txt
|
||||
public static final int MIC_ID_v2 = 0x0404;
|
||||
public static final int WRAP_ID_v2 = 0x0504;
|
||||
|
||||
/**
|
||||
* The object identifier corresponding to the Kerberos v5 GSS-API
|
||||
* mechanism.
|
||||
*/
|
||||
public static ObjectIdentifier OID;
|
||||
|
||||
static {
|
||||
try {
|
||||
OID = new ObjectIdentifier(Krb5MechFactory.
|
||||
GSS_KRB5_MECH_OID.toString());
|
||||
} catch (IOException ioe) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a strign representing the token type.
|
||||
*
|
||||
* @param tokenId the token id for which a string name is desired
|
||||
* @return the String name of this token type
|
||||
*/
|
||||
public static String getTokenName(int tokenId) {
|
||||
String retVal = null;
|
||||
switch (tokenId) {
|
||||
case AP_REQ_ID:
|
||||
case AP_REP_ID:
|
||||
retVal = "Context Establishment Token";
|
||||
break;
|
||||
case MIC_ID:
|
||||
retVal = "MIC Token";
|
||||
break;
|
||||
case MIC_ID_v2:
|
||||
retVal = "MIC Token (new format)";
|
||||
break;
|
||||
case WRAP_ID:
|
||||
retVal = "Wrap Token";
|
||||
break;
|
||||
case WRAP_ID_v2:
|
||||
retVal = "Wrap Token (new format)";
|
||||
break;
|
||||
default:
|
||||
retVal = "Kerberos GSS-API Mechanism Token";
|
||||
break;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
319
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Util.java
Normal file
319
jdkSrc/jdk8/sun/security/jgss/krb5/Krb5Util.java
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2019, 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.krb5;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import java.security.AccessControlContext;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
|
||||
import sun.security.krb5.Credentials;
|
||||
import sun.security.krb5.EncryptionKey;
|
||||
import sun.security.krb5.KrbException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import sun.security.krb5.KerberosSecrets;
|
||||
import sun.security.krb5.PrincipalName;
|
||||
/**
|
||||
* Utilities for obtaining and converting Kerberos tickets.
|
||||
*
|
||||
*/
|
||||
public class Krb5Util {
|
||||
|
||||
static final boolean DEBUG =
|
||||
java.security.AccessController.doPrivileged(
|
||||
new sun.security.action.GetBooleanAction
|
||||
("sun.security.krb5.debug")).booleanValue();
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
private Krb5Util() { // Cannot create one of these
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the service ticket for serverPrincipal from caller's Subject
|
||||
* or from Subject obtained by logging in, or if not found, via the
|
||||
* Ticket Granting Service using the TGT obtained from the Subject.
|
||||
*
|
||||
* Caller must have permission to:
|
||||
* - access and update Subject's private credentials
|
||||
* - create LoginContext
|
||||
* - read the auth.login.defaultCallbackHandler security property
|
||||
*
|
||||
* NOTE: This method is used by JSSE Kerberos Cipher Suites
|
||||
*/
|
||||
public static KerberosTicket getTicketFromSubjectAndTgs(GSSCaller caller,
|
||||
String clientPrincipal, String serverPrincipal, String tgsPrincipal,
|
||||
AccessControlContext acc)
|
||||
throws LoginException, KrbException, IOException {
|
||||
|
||||
// 1. Try to find service ticket in acc subject
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
KerberosTicket ticket = SubjectComber.find(accSubj,
|
||||
serverPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
|
||||
if (ticket != null) {
|
||||
return ticket; // found it
|
||||
}
|
||||
|
||||
Subject loginSubj = null;
|
||||
if (!GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
// 2. Try to get ticket from login
|
||||
try {
|
||||
loginSubj = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
ticket = SubjectComber.find(loginSubj,
|
||||
serverPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
if (ticket != null) {
|
||||
return ticket; // found it
|
||||
}
|
||||
} catch (LoginException e) {
|
||||
// No login entry to use
|
||||
// ignore and continue
|
||||
}
|
||||
}
|
||||
|
||||
// Service ticket not found in subject or login
|
||||
// Try to get TGT to acquire service ticket
|
||||
|
||||
// 3. Try to get TGT from acc subject
|
||||
KerberosTicket tgt = SubjectComber.find(accSubj,
|
||||
tgsPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
|
||||
boolean fromAcc;
|
||||
if (tgt == null && loginSubj != null) {
|
||||
// 4. Try to get TGT from login subject
|
||||
tgt = SubjectComber.find(loginSubj,
|
||||
tgsPrincipal, clientPrincipal, KerberosTicket.class);
|
||||
fromAcc = false;
|
||||
} else {
|
||||
fromAcc = true;
|
||||
}
|
||||
|
||||
// 5. Try to get service ticket using TGT
|
||||
if (tgt != null) {
|
||||
Credentials tgtCreds = ticketToCreds(tgt);
|
||||
Credentials serviceCreds = Credentials.acquireServiceCreds(
|
||||
serverPrincipal, tgtCreds);
|
||||
if (serviceCreds != null) {
|
||||
ticket = credsToTicket(serviceCreds);
|
||||
|
||||
// Store service ticket in acc's Subject
|
||||
if (fromAcc && accSubj != null && !accSubj.isReadOnly()) {
|
||||
accSubj.getPrivateCredentials().add(ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ticket corresponding to the client/server principal
|
||||
* pair from the Subject in the specified AccessControlContext.
|
||||
*/
|
||||
static KerberosTicket getServiceTicket(GSSCaller caller,
|
||||
String clientPrincipal, String serverPrincipal,
|
||||
AccessControlContext acc) throws LoginException {
|
||||
|
||||
// Try to get ticket from acc's Subject
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
KerberosTicket ticket =
|
||||
SubjectComber.find(accSubj, serverPrincipal, clientPrincipal,
|
||||
KerberosTicket.class);
|
||||
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the initial TGT corresponding to the client principal
|
||||
* from the Subject in the specified AccessControlContext.
|
||||
* If the ticket can not be found in the Subject, and if
|
||||
* useSubjectCredsOnly is false, then obtain ticket from
|
||||
* a LoginContext.
|
||||
*/
|
||||
static KerberosTicket getInitialTicket(GSSCaller caller,
|
||||
String clientPrincipal,
|
||||
AccessControlContext acc) throws LoginException {
|
||||
|
||||
// Try to get ticket from acc's Subject
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
KerberosTicket ticket =
|
||||
SubjectComber.find(accSubj, null, clientPrincipal,
|
||||
KerberosTicket.class);
|
||||
|
||||
// Try to get ticket from Subject obtained from GSSUtil
|
||||
if (ticket == null && !GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
ticket = SubjectComber.find(subject,
|
||||
null, clientPrincipal, KerberosTicket.class);
|
||||
}
|
||||
return ticket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the caller's Subject, or Subject obtained by logging in
|
||||
* via the specified caller.
|
||||
*
|
||||
* Caller must have permission to:
|
||||
* - access the Subject
|
||||
* - create LoginContext
|
||||
* - read the auth.login.defaultCallbackHandler security property
|
||||
*
|
||||
* NOTE: This method is used by JSSE Kerberos Cipher Suites
|
||||
*/
|
||||
public static Subject getSubject(GSSCaller caller,
|
||||
AccessControlContext acc) throws LoginException {
|
||||
|
||||
// Try to get the Subject from acc
|
||||
Subject subject = Subject.getSubject(acc);
|
||||
|
||||
// Try to get Subject obtained from GSSUtil
|
||||
if (subject == null && !GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
}
|
||||
return subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ServiceCreds for the specified server principal from
|
||||
* the Subject in the specified AccessControlContext. If not found, and if
|
||||
* useSubjectCredsOnly is false, then obtain from a LoginContext.
|
||||
*
|
||||
* NOTE: This method is also used by JSSE Kerberos Cipher Suites
|
||||
*/
|
||||
public static ServiceCreds getServiceCreds(GSSCaller caller,
|
||||
String serverPrincipal, AccessControlContext acc)
|
||||
throws LoginException {
|
||||
|
||||
Subject accSubj = Subject.getSubject(acc);
|
||||
ServiceCreds sc = null;
|
||||
if (accSubj != null) {
|
||||
sc = ServiceCreds.getInstance(accSubj, serverPrincipal);
|
||||
}
|
||||
if (sc == null && !GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
Subject subject = GSSUtil.login(caller, GSSUtil.GSS_KRB5_MECH_OID);
|
||||
sc = ServiceCreds.getInstance(subject, serverPrincipal);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
public static KerberosTicket credsToTicket(Credentials serviceCreds) {
|
||||
EncryptionKey sessionKey = serviceCreds.getSessionKey();
|
||||
KerberosTicket kt = new KerberosTicket(
|
||||
serviceCreds.getEncoded(),
|
||||
new KerberosPrincipal(serviceCreds.getClient().getName()),
|
||||
new KerberosPrincipal(serviceCreds.getServer().getName(),
|
||||
KerberosPrincipal.KRB_NT_SRV_INST),
|
||||
sessionKey.getBytes(),
|
||||
sessionKey.getEType(),
|
||||
serviceCreds.getFlags(),
|
||||
serviceCreds.getAuthTime(),
|
||||
serviceCreds.getStartTime(),
|
||||
serviceCreds.getEndTime(),
|
||||
serviceCreds.getRenewTill(),
|
||||
serviceCreds.getClientAddresses());
|
||||
PrincipalName clientAlias = serviceCreds.getClientAlias();
|
||||
PrincipalName serverAlias = serviceCreds.getServerAlias();
|
||||
if (clientAlias != null) {
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetClientAlias(kt, new KerberosPrincipal(
|
||||
clientAlias.getName(), clientAlias.getNameType()));
|
||||
}
|
||||
if (serverAlias != null) {
|
||||
KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketSetServerAlias(kt, new KerberosPrincipal(
|
||||
serverAlias.getName(), serverAlias.getNameType()));
|
||||
}
|
||||
return kt;
|
||||
};
|
||||
|
||||
public static Credentials ticketToCreds(KerberosTicket kerbTicket)
|
||||
throws KrbException, IOException {
|
||||
KerberosPrincipal clientAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetClientAlias(kerbTicket);
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(kerbTicket);
|
||||
return new Credentials(
|
||||
kerbTicket.getEncoded(),
|
||||
kerbTicket.getClient().getName(),
|
||||
(clientAlias != null ? clientAlias.getName() : null),
|
||||
kerbTicket.getServer().getName(),
|
||||
(serverAlias != null ? serverAlias.getName() : null),
|
||||
kerbTicket.getSessionKey().getEncoded(),
|
||||
kerbTicket.getSessionKeyType(),
|
||||
kerbTicket.getFlags(),
|
||||
kerbTicket.getAuthTime(),
|
||||
kerbTicket.getStartTime(),
|
||||
kerbTicket.getEndTime(),
|
||||
kerbTicket.getRenewTill(),
|
||||
kerbTicket.getClientAddresses());
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to get a sun..KeyTab from a javax..KeyTab
|
||||
* @param ktab the javax..KeyTab object
|
||||
* @return the sun..KeyTab object
|
||||
*/
|
||||
public static sun.security.krb5.internal.ktab.KeyTab
|
||||
snapshotFromJavaxKeyTab(KeyTab ktab) {
|
||||
return KerberosSecrets.getJavaxSecurityAuthKerberosAccess()
|
||||
.keyTabTakeSnapshot(ktab);
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper method to get EncryptionKeys from a javax..KeyTab
|
||||
* @param ktab the javax..KeyTab object
|
||||
* @param cname the PrincipalName
|
||||
* @return the EKeys, never null, might be empty
|
||||
*/
|
||||
public static EncryptionKey[] keysFromJavaxKeyTab(
|
||||
KeyTab ktab, PrincipalName cname) {
|
||||
return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname);
|
||||
}
|
||||
|
||||
public static String keyInfo(byte[] data) {
|
||||
if (data == null) {
|
||||
return "null key";
|
||||
} else if (data.length == 0) {
|
||||
return "empty key";
|
||||
} else {
|
||||
for (byte b : data) {
|
||||
if (b != 0) {
|
||||
return data.length + "-byte key";
|
||||
}
|
||||
}
|
||||
return data.length + "-byte zero key";
|
||||
}
|
||||
}
|
||||
}
|
||||
721
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken.java
Normal file
721
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken.java
Normal file
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/**
|
||||
* This class is a base class for other token definitions that pertain to
|
||||
* per-message GSS-API calls. Conceptually GSS-API has two types of
|
||||
* per-message tokens: WrapToken and MicToken. They differ in the respect
|
||||
* that a WrapToken carries additional plaintext or ciphertext application
|
||||
* data besides just the sequence number and checksum. This class
|
||||
* encapsulates the commonality in the structure of the WrapToken and the
|
||||
* MicToken. This structure can be represented as:
|
||||
* <p>
|
||||
* <pre>
|
||||
* 0..1 TOK_ID Identification field.
|
||||
* 01 01 - Mic token
|
||||
* 02 01 - Wrap token
|
||||
* 2..3 SGN_ALG Checksum algorithm indicator.
|
||||
* 00 00 - DES MAC MD5
|
||||
* 01 00 - MD2.5
|
||||
* 02 00 - DES MAC
|
||||
* 04 00 - HMAC SHA1 DES3-KD
|
||||
* 11 00 - RC4-HMAC
|
||||
* 4..5 SEAL_ALG ff ff - none
|
||||
* 00 00 - DES
|
||||
* 02 00 - DES3-KD
|
||||
* 10 00 - RC4-HMAC
|
||||
* 6..7 Filler Contains ff ff
|
||||
* 8..15 SND_SEQ Encrypted sequence number field.
|
||||
* 16..s+15 SGN_CKSUM Checksum of plaintext padded data,
|
||||
* calculated according to algorithm
|
||||
* specified in SGN_ALG field.
|
||||
* s+16..last Data encrypted or plaintext padded data
|
||||
* </pre>
|
||||
* Where "s" indicates the size of the checksum.
|
||||
* <p>
|
||||
* As always, this is preceeded by a GSSHeader.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
* @author Ram Marti
|
||||
* @see sun.security.jgss.GSSHeader
|
||||
*/
|
||||
|
||||
abstract class MessageToken extends Krb5Token {
|
||||
/* Fields in header minus checksum size */
|
||||
private static final int TOKEN_NO_CKSUM_SIZE = 16;
|
||||
|
||||
/**
|
||||
* Filler data as defined in the specification of the Kerberos v5 GSS-API
|
||||
* Mechanism.
|
||||
*/
|
||||
private static final int FILLER = 0xffff;
|
||||
|
||||
// Signing algorithm values (for the SNG_ALG field)
|
||||
|
||||
// From RFC 1964
|
||||
/* Use a DES MAC MD5 checksum */
|
||||
static final int SGN_ALG_DES_MAC_MD5 = 0x0000;
|
||||
|
||||
/* Use DES MAC checksum. */
|
||||
static final int SGN_ALG_DES_MAC = 0x0200;
|
||||
|
||||
// From draft-raeburn-cat-gssapi-krb5-3des-00
|
||||
/* Use a HMAC SHA1 DES3 -KD checksum */
|
||||
static final int SGN_ALG_HMAC_SHA1_DES3_KD = 0x0400;
|
||||
|
||||
// Sealing algorithm values (for the SEAL_ALG field)
|
||||
|
||||
// RFC 1964
|
||||
/**
|
||||
* A value for the SEAL_ALG field that indicates that no encryption was
|
||||
* used.
|
||||
*/
|
||||
static final int SEAL_ALG_NONE = 0xffff;
|
||||
/* Use DES CBC encryption algorithm. */
|
||||
static final int SEAL_ALG_DES = 0x0000;
|
||||
|
||||
// From draft-raeburn-cat-gssapi-krb5-3des-00
|
||||
/**
|
||||
* Use DES3-KD sealing algorithm. (draft-raeburn-cat-gssapi-krb5-3des-00)
|
||||
* This algorithm uses triple-DES with key derivation, with a usage
|
||||
* value KG_USAGE_SEAL. Padding is still to 8-byte multiples, and the
|
||||
* IV for encrypting application data is zero.
|
||||
*/
|
||||
static final int SEAL_ALG_DES3_KD = 0x0200;
|
||||
|
||||
// draft draft-brezak-win2k-krb-rc4-hmac-04.txt
|
||||
static final int SEAL_ALG_ARCFOUR_HMAC = 0x1000;
|
||||
static final int SGN_ALG_HMAC_MD5_ARCFOUR = 0x1100;
|
||||
|
||||
private static final int TOKEN_ID_POS = 0;
|
||||
private static final int SIGN_ALG_POS = 2;
|
||||
private static final int SEAL_ALG_POS = 4;
|
||||
|
||||
private int seqNumber;
|
||||
|
||||
private boolean confState = true;
|
||||
private boolean initiator = true;
|
||||
|
||||
private int tokenId = 0;
|
||||
private GSSHeader gssHeader = null;
|
||||
private MessageTokenHeader tokenHeader = null;
|
||||
private byte[] checksum = null;
|
||||
private byte[] encSeqNumber = null;
|
||||
private byte[] seqNumberData = null;
|
||||
|
||||
/* cipher instance used by the corresponding GSSContext */
|
||||
CipherHelper cipherHelper = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from a byte array. If there are more bytes
|
||||
* in the array than needed, the extra bytes are simply ignroed.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param tokenBytes the byte array containing the token
|
||||
* @param tokenOffset the offset where the token begins
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem parsing the token
|
||||
*/
|
||||
MessageToken(int tokenId, Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
this(tokenId, context,
|
||||
new ByteArrayInputStream(tokenBytes, tokenOffset, tokenLen),
|
||||
prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from an InputStream. Bytes will be read on
|
||||
* demand and the thread might block if there are not enough bytes to
|
||||
* complete the token.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param is the InputStream from which to read
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem reading from the
|
||||
* InputStream or parsing the token
|
||||
*/
|
||||
MessageToken(int tokenId, Krb5Context context, InputStream is,
|
||||
MessageProp prop) throws GSSException {
|
||||
init(tokenId, context);
|
||||
|
||||
try {
|
||||
gssHeader = new GSSHeader(is);
|
||||
|
||||
if (!gssHeader.getOid().equals((Object)OID)) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId));
|
||||
}
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
tokenHeader = new MessageTokenHeader(is, prop);
|
||||
|
||||
encSeqNumber = new byte[8];
|
||||
readFully(is, encSeqNumber);
|
||||
|
||||
// debug("\n\tRead EncSeq#=" +
|
||||
// getHexBytes(encSeqNumber, encSeqNumber.length));
|
||||
|
||||
checksum = new byte[cipherHelper.getChecksumLength()];
|
||||
readFully(is, checksum);
|
||||
|
||||
// debug("\n\tRead checksum=" +
|
||||
// getHexBytes(checksum, checksum.length));
|
||||
// debug("\nLeaving MessageToken.Cons\n");
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the GSSHeader that was at the start of this
|
||||
* token.
|
||||
*/
|
||||
public final GSSHeader getGSSHeader() {
|
||||
return gssHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the token id that was contained in this token.
|
||||
* @return the token id in the token
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the encrypted sequence number in this token.
|
||||
* @return the encrypted sequence number in the token
|
||||
*/
|
||||
public final byte[] getEncSeqNumber() {
|
||||
return encSeqNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the checksum that was contained in this token.
|
||||
* @return the checksum in the token
|
||||
*/
|
||||
public final byte[] getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine if this token contains any encrypted data.
|
||||
* @return true if it contains any encrypted data, false if there is only
|
||||
* plaintext data or if there is no data.
|
||||
*/
|
||||
public final boolean getConfState() {
|
||||
return confState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the checksum field and the encrypted sequence number
|
||||
* field. The encrypted sequence number uses the 8 bytes of the checksum
|
||||
* as an initial vector in a fixed DesCbc algorithm.
|
||||
*
|
||||
* @param prop the MessageProp structure that determines what sort of
|
||||
* checksum and sealing algorithm should be used. The lower byte
|
||||
* of qop determines the checksum algorithm while the upper byte
|
||||
* determines the signing algorithm.
|
||||
* Checksum values are:
|
||||
* 0 - default (DES_MAC)
|
||||
* 1 - MD5
|
||||
* 2 - DES_MD5
|
||||
* 3 - DES_MAC
|
||||
* 4 - HMAC_SHA1
|
||||
* Sealing values are:
|
||||
* 0 - default (DES)
|
||||
* 1 - DES
|
||||
* 2 - DES3-KD
|
||||
*
|
||||
* @param optionalHeader an optional header that will be processed first
|
||||
* during checksum calculation
|
||||
*
|
||||
* @param data the application data to checksum
|
||||
* @param offset the offset where the data starts
|
||||
* @param len the length of the data
|
||||
*
|
||||
* @param optionalTrailer an optional trailer that will be processed
|
||||
* last during checksum calculation. e.g., padding that should be
|
||||
* appended to the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation or
|
||||
* encryption sequence number calculation.
|
||||
*/
|
||||
public void genSignAndSeqNumber(MessageProp prop,
|
||||
byte[] optionalHeader,
|
||||
byte[] data, int offset, int len,
|
||||
byte[] optionalTrailer)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Inside MessageToken.genSignAndSeqNumber:\n");
|
||||
|
||||
int qop = prop.getQOP();
|
||||
if (qop != 0) {
|
||||
qop = 0;
|
||||
prop.setQOP(qop);
|
||||
}
|
||||
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
// Create a token header with the correct sign and seal algorithm
|
||||
// values.
|
||||
tokenHeader =
|
||||
new MessageTokenHeader(tokenId, prop.getPrivacy(), qop);
|
||||
|
||||
// Calculate SGN_CKSUM
|
||||
|
||||
checksum =
|
||||
getChecksum(optionalHeader, data, offset, len, optionalTrailer);
|
||||
|
||||
// debug("\n\tCalc checksum=" +
|
||||
// getHexBytes(checksum, checksum.length));
|
||||
|
||||
// Calculate SND_SEQ
|
||||
|
||||
seqNumberData = new byte[8];
|
||||
|
||||
// When using this RC4 based encryption type, the sequence number is
|
||||
// always sent in big-endian rather than little-endian order.
|
||||
if (cipherHelper.isArcFour()) {
|
||||
writeBigEndian(seqNumber, seqNumberData);
|
||||
} else {
|
||||
// for all other etypes
|
||||
writeLittleEndian(seqNumber, seqNumberData);
|
||||
}
|
||||
if (!initiator) {
|
||||
seqNumberData[4] = (byte)0xff;
|
||||
seqNumberData[5] = (byte)0xff;
|
||||
seqNumberData[6] = (byte)0xff;
|
||||
seqNumberData[7] = (byte)0xff;
|
||||
}
|
||||
|
||||
encSeqNumber = cipherHelper.encryptSeq(checksum, seqNumberData, 0, 8);
|
||||
|
||||
// debug("\n\tCalc seqNum=" +
|
||||
// getHexBytes(seqNumberData, seqNumberData.length));
|
||||
// debug("\n\tCalc encSeqNum=" +
|
||||
// getHexBytes(encSeqNumber, encSeqNumber.length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the checksum field and sequence number direction bytes
|
||||
* are valid and consistent with the application data.
|
||||
*
|
||||
* @param optionalHeader an optional header that will be processed first
|
||||
* during checksum calculation.
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @param optionalTrailer an optional trailer that will be processed last
|
||||
* during checksum calculation. e.g., padding that should be appended to
|
||||
* the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation or
|
||||
* encryption sequence number calculation.
|
||||
*/
|
||||
public final boolean verifySignAndSeqNumber(byte[] optionalHeader,
|
||||
byte[] data, int offset, int len,
|
||||
byte[] optionalTrailer)
|
||||
throws GSSException {
|
||||
// debug("\tIn verifySign:\n");
|
||||
|
||||
// debug("\t\tchecksum: [" + getHexBytes(checksum) + "]\n");
|
||||
|
||||
byte[] myChecksum =
|
||||
getChecksum(optionalHeader, data, offset, len, optionalTrailer);
|
||||
|
||||
// debug("\t\tmychecksum: [" + getHexBytes(myChecksum) +"]\n");
|
||||
// debug("\t\tchecksum: [" + getHexBytes(checksum) + "]\n");
|
||||
|
||||
if (MessageDigest.isEqual(checksum, myChecksum)) {
|
||||
|
||||
seqNumberData = cipherHelper.decryptSeq(
|
||||
checksum, encSeqNumber, 0, 8);
|
||||
|
||||
// debug("\t\tencSeqNumber: [" + getHexBytes(encSeqNumber)
|
||||
// + "]\n");
|
||||
// debug("\t\tseqNumberData: [" + getHexBytes(seqNumberData)
|
||||
// + "]\n");
|
||||
|
||||
/*
|
||||
* The token from the initiator has direction bytes 0x00 and
|
||||
* the token from the acceptor has direction bytes 0xff.
|
||||
*/
|
||||
byte directionByte = 0;
|
||||
if (initiator)
|
||||
directionByte = (byte) 0xff; // Received token from acceptor
|
||||
|
||||
if ((seqNumberData[4] == directionByte) &&
|
||||
(seqNumberData[5] == directionByte) &&
|
||||
(seqNumberData[6] == directionByte) &&
|
||||
(seqNumberData[7] == directionByte))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public final int getSequenceNumber() {
|
||||
int sequenceNum = 0;
|
||||
if (cipherHelper.isArcFour()) {
|
||||
sequenceNum = readBigEndian(seqNumberData, 0, 4);
|
||||
} else {
|
||||
sequenceNum = readLittleEndian(seqNumberData, 0, 4);
|
||||
}
|
||||
return sequenceNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the checksum based on the algorithm stored in the
|
||||
* tokenHeader.
|
||||
*
|
||||
* @param optionalHeader an optional header that will be processed first
|
||||
* during checksum calculation.
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @param optionalTrailer an optional trailer that will be processed last
|
||||
* during checksum calculation. e.g., padding that should be appended to
|
||||
* the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation.
|
||||
*/
|
||||
private byte[] getChecksum(byte[] optionalHeader,
|
||||
byte[] data, int offset, int len,
|
||||
byte[] optionalTrailer)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Will do getChecksum:\n");
|
||||
|
||||
/*
|
||||
* For checksum calculation the token header bytes i.e., the first 8
|
||||
* bytes following the GSSHeader, are logically prepended to the
|
||||
* application data to bind the data to this particular token.
|
||||
*
|
||||
* Note: There is no such requirement wrt adding padding to the
|
||||
* application data for checksumming, although the cryptographic
|
||||
* algorithm used might itself apply some padding.
|
||||
*/
|
||||
|
||||
byte[] tokenHeaderBytes = tokenHeader.getBytes();
|
||||
byte[] existingHeader = optionalHeader;
|
||||
byte[] checksumDataHeader = tokenHeaderBytes;
|
||||
|
||||
if (existingHeader != null) {
|
||||
checksumDataHeader = new byte[tokenHeaderBytes.length +
|
||||
existingHeader.length];
|
||||
System.arraycopy(tokenHeaderBytes, 0,
|
||||
checksumDataHeader, 0, tokenHeaderBytes.length);
|
||||
System.arraycopy(existingHeader, 0,
|
||||
checksumDataHeader, tokenHeaderBytes.length,
|
||||
existingHeader.length);
|
||||
}
|
||||
|
||||
return cipherHelper.calculateChecksum(tokenHeader.getSignAlg(),
|
||||
checksumDataHeader, optionalTrailer, data, offset, len, tokenId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an empty MessageToken for the local context to send to
|
||||
* the peer. It also increments the local sequence number in the
|
||||
* Krb5Context instance it uses after obtaining the object lock for
|
||||
* it.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token
|
||||
* @param context the Kerberos context associated with this token
|
||||
*/
|
||||
MessageToken(int tokenId, Krb5Context context) throws GSSException {
|
||||
/*
|
||||
debug("\n============================");
|
||||
debug("\nMySessionKey=" +
|
||||
getHexBytes(context.getMySessionKey().getBytes()));
|
||||
debug("\nPeerSessionKey=" +
|
||||
getHexBytes(context.getPeerSessionKey().getBytes()));
|
||||
debug("\n============================\n");
|
||||
*/
|
||||
init(tokenId, context);
|
||||
this.seqNumber = context.incrementMySequenceNumber();
|
||||
}
|
||||
|
||||
private void init(int tokenId, Krb5Context context) throws GSSException {
|
||||
this.tokenId = tokenId;
|
||||
// Just for consistency check in Wrap
|
||||
this.confState = context.getConfState();
|
||||
|
||||
this.initiator = context.isInitiator();
|
||||
|
||||
this.cipherHelper = context.getCipherHelper(null);
|
||||
// debug("In MessageToken.Cons");
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a GSSHeader and this token onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws GSSException if an error occurs while writing to the OutputStream
|
||||
*/
|
||||
public void encode(OutputStream os) throws IOException, GSSException {
|
||||
gssHeader = new GSSHeader(OID, getKrb5TokenSize());
|
||||
gssHeader.encode(os);
|
||||
tokenHeader.encode(os);
|
||||
// debug("Writing seqNumber: " + getHexBytes(encSeqNumber));
|
||||
os.write(encSeqNumber);
|
||||
// debug("Writing checksum: " + getHexBytes(checksum));
|
||||
os.write(checksum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the size of this token. Note that this excludes the size of
|
||||
* the GSSHeader.
|
||||
* @return token size
|
||||
*/
|
||||
protected int getKrb5TokenSize() throws GSSException {
|
||||
return getTokenSize();
|
||||
}
|
||||
|
||||
protected final int getTokenSize() throws GSSException {
|
||||
return TOKEN_NO_CKSUM_SIZE + cipherHelper.getChecksumLength();
|
||||
}
|
||||
|
||||
protected static final int getTokenSize(CipherHelper ch)
|
||||
throws GSSException {
|
||||
return TOKEN_NO_CKSUM_SIZE + ch.getChecksumLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the conext key that is associated with this token.
|
||||
* @return the context key
|
||||
*/
|
||||
/*
|
||||
public final byte[] getContextKey() {
|
||||
return contextKey;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtains the encryption algorithm that should be used in this token
|
||||
* given the state of confidentiality the application requested.
|
||||
* Requested qop must be consistent with negotiated session key.
|
||||
* @param confRequested true if the application desired confidentiality
|
||||
* on this token, false otherwise
|
||||
* @param qop the qop requested by the application
|
||||
* @throws GSSException if qop is incompatible with the negotiated
|
||||
* session key
|
||||
*/
|
||||
protected abstract int getSealAlg(boolean confRequested, int qop)
|
||||
throws GSSException;
|
||||
|
||||
// ******************************************* //
|
||||
// I N N E R C L A S S E S F O L L O W
|
||||
// ******************************************* //
|
||||
|
||||
/**
|
||||
* This inner class represents the initial portion of the message token
|
||||
* and contains information about the checksum and encryption algorithms
|
||||
* that are in use. It constitutes the first 8 bytes of the
|
||||
* message token:
|
||||
* <pre>
|
||||
* 0..1 TOK_ID Identification field.
|
||||
* 01 01 - Mic token
|
||||
* 02 01 - Wrap token
|
||||
* 2..3 SGN_ALG Checksum algorithm indicator.
|
||||
* 00 00 - DES MAC MD5
|
||||
* 01 00 - MD2.5
|
||||
* 02 00 - DES MAC
|
||||
* 04 00 - HMAC SHA1 DES3-KD
|
||||
* 11 00 - RC4-HMAC
|
||||
* 4..5 SEAL_ALG ff ff - none
|
||||
* 00 00 - DES
|
||||
* 02 00 - DES3-KD
|
||||
* 10 00 - RC4-HMAC
|
||||
* 6..7 Filler Contains ff ff
|
||||
* </pre>
|
||||
*/
|
||||
class MessageTokenHeader {
|
||||
|
||||
private int tokenId;
|
||||
private int signAlg;
|
||||
private int sealAlg;
|
||||
|
||||
private byte[] bytes = new byte[8];
|
||||
|
||||
/**
|
||||
* Constructs a MessageTokenHeader for the specified token type with
|
||||
* appropriate checksum and encryption algorithms fields.
|
||||
*
|
||||
* @param tokenId the token id for this message token
|
||||
* @param conf true if confidentiality will be resuested with this
|
||||
* message token, false otherwise.
|
||||
* @param qop the value of the quality of protection that will be
|
||||
* desired.
|
||||
*/
|
||||
public MessageTokenHeader(int tokenId, boolean conf, int qop)
|
||||
throws GSSException {
|
||||
|
||||
this.tokenId = tokenId;
|
||||
|
||||
signAlg = MessageToken.this.getSgnAlg(qop);
|
||||
|
||||
sealAlg = MessageToken.this.getSealAlg(conf, qop);
|
||||
|
||||
bytes[0] = (byte) (tokenId >>> 8);
|
||||
bytes[1] = (byte) (tokenId);
|
||||
|
||||
bytes[2] = (byte) (signAlg >>> 8);
|
||||
bytes[3] = (byte) (signAlg);
|
||||
|
||||
bytes[4] = (byte) (sealAlg >>> 8);
|
||||
bytes[5] = (byte) (sealAlg);
|
||||
|
||||
bytes[6] = (byte) (MessageToken.FILLER >>> 8);
|
||||
bytes[7] = (byte) (MessageToken.FILLER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageTokenHeader by reading it from an InputStream
|
||||
* and sets the appropriate confidentiality and quality of protection
|
||||
* values in a MessageProp structure.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param prop the MessageProp to populate
|
||||
* @throws IOException is an error occurs while reading from the
|
||||
* InputStream
|
||||
*/
|
||||
public MessageTokenHeader(InputStream is, MessageProp prop)
|
||||
throws IOException {
|
||||
readFully(is, bytes);
|
||||
tokenId = readInt(bytes, TOKEN_ID_POS);
|
||||
signAlg = readInt(bytes, SIGN_ALG_POS);
|
||||
sealAlg = readInt(bytes, SEAL_ALG_POS);
|
||||
// debug("\nMessageTokenHeader read tokenId=" +
|
||||
// getHexBytes(bytes) + "\n");
|
||||
// XXX compare to FILLER
|
||||
int temp = readInt(bytes, SEAL_ALG_POS + 2);
|
||||
|
||||
// debug("SIGN_ALG=" + signAlg);
|
||||
|
||||
switch (sealAlg) {
|
||||
case SEAL_ALG_DES:
|
||||
case SEAL_ALG_DES3_KD:
|
||||
case SEAL_ALG_ARCFOUR_HMAC:
|
||||
prop.setPrivacy(true);
|
||||
break;
|
||||
|
||||
default:
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
prop.setQOP(0); // default
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes this MessageTokenHeader onto an OutputStream
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException is an error occurs while writing
|
||||
*/
|
||||
public final void encode(OutputStream os) throws IOException {
|
||||
os.write(bytes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the token id for the message token.
|
||||
* @return the token id
|
||||
* @see sun.security.jgss.krb5.Krb5Token#MIC_ID
|
||||
* @see sun.security.jgss.krb5.Krb5Token#WRAP_ID
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sign algorithm for the message token.
|
||||
* @return the sign algorithm
|
||||
* @see sun.security.jgss.krb5.MessageToken#SIGN_DES_MAC
|
||||
* @see sun.security.jgss.krb5.MessageToken#SIGN_DES_MAC_MD5
|
||||
*/
|
||||
public final int getSignAlg() {
|
||||
return signAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the seal algorithm for the message token.
|
||||
* @return the seal algorithm
|
||||
* @see sun.security.jgss.krb5.MessageToken#SEAL_ALG_DES
|
||||
* @see sun.security.jgss.krb5.MessageToken#SEAL_ALG_NONE
|
||||
*/
|
||||
public final int getSealAlg() {
|
||||
return sealAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytes of this header.
|
||||
* @return 8 bytes that form this header
|
||||
*/
|
||||
public final byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
} // end of class MessageTokenHeader
|
||||
|
||||
|
||||
/**
|
||||
* Determine signing algorithm based on QOP.
|
||||
*/
|
||||
protected int getSgnAlg(int qop) throws GSSException {
|
||||
// QOP ignored
|
||||
return cipherHelper.getSgnAlg();
|
||||
}
|
||||
}
|
||||
643
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken_v2.java
Normal file
643
jdkSrc/jdk8/sun/security/jgss/krb5/MessageToken_v2.java
Normal file
@@ -0,0 +1,643 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2018, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* This class is a base class for new GSS token definitions, as defined
|
||||
* in RFC 4121, that pertain to per-message GSS-API calls. Conceptually
|
||||
* GSS-API has two types of per-message tokens: WrapToken and MicToken.
|
||||
* They differ in the respect that a WrapToken carries additional plaintext
|
||||
* or ciphertext application data besides just the sequence number and
|
||||
* checksum. This class encapsulates the commonality in the structure of
|
||||
* the WrapToken and the MicToken. This structure can be represented as:
|
||||
* <p>
|
||||
* <pre>
|
||||
* Wrap Tokens
|
||||
*
|
||||
* Octet no Name Description
|
||||
* ---------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_Wrap() contain the hex value 05 04
|
||||
* expressed in big-endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3 Filler Contains the hex value FF.
|
||||
* 4..5 EC Contains the "extra count" field, in big-
|
||||
* endian order as described in section 4.2.3.
|
||||
* 6..7 RRC Contains the "right rotation count" in big
|
||||
* endian order, as described in section 4.2.5.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big-endian order.
|
||||
* 16..last Data Encrypted data for Wrap tokens with
|
||||
* confidentiality, or plaintext data followed
|
||||
* by the checksum for Wrap tokens without
|
||||
* confidentiality, as described in section
|
||||
* 4.2.4.
|
||||
* MIC Tokens
|
||||
*
|
||||
* Octet no Name Description
|
||||
* -----------------------------------------------------------------
|
||||
* 0..1 TOK_ID Identification field. Tokens emitted by
|
||||
* GSS_GetMIC() contain the hex value 04 04
|
||||
* expressed in big-endian order in this field.
|
||||
* 2 Flags Attributes field, as described in section
|
||||
* 4.2.2.
|
||||
* 3..7 Filler Contains five octets of hex value FF.
|
||||
* 8..15 SND_SEQ Sequence number field in clear text,
|
||||
* expressed in big-endian order.
|
||||
* 16..last SGN_CKSUM Checksum of the "to-be-signed" data and
|
||||
* octet 0..15, as described in section 4.2.4.
|
||||
*
|
||||
* </pre>
|
||||
* <p>
|
||||
* This class is the super class of WrapToken_v2 and MicToken_v2. The token's
|
||||
* header (bytes[0..15]) and data (byte[16..]) are saved in tokenHeader and
|
||||
* tokenData fields. Since there is no easy way to find out the exact length
|
||||
* of a WrapToken_v2 token from any header info, in the case of reading from
|
||||
* stream, we read all available() bytes into the token.
|
||||
* <p>
|
||||
* All read actions are performed in this super class. On the write part, the
|
||||
* super class only write the tokenHeader, and the content writing is inside
|
||||
* child classes.
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
|
||||
abstract class MessageToken_v2 extends Krb5Token {
|
||||
|
||||
protected static final int TOKEN_HEADER_SIZE = 16;
|
||||
private static final int TOKEN_ID_POS = 0;
|
||||
private static final int TOKEN_FLAG_POS = 2;
|
||||
private static final int TOKEN_EC_POS = 4;
|
||||
private static final int TOKEN_RRC_POS = 6;
|
||||
|
||||
/**
|
||||
* The size of the random confounder used in a WrapToken.
|
||||
*/
|
||||
protected static final int CONFOUNDER_SIZE = 16;
|
||||
|
||||
// RFC 4121, key usage values
|
||||
static final int KG_USAGE_ACCEPTOR_SEAL = 22;
|
||||
static final int KG_USAGE_ACCEPTOR_SIGN = 23;
|
||||
static final int KG_USAGE_INITIATOR_SEAL = 24;
|
||||
static final int KG_USAGE_INITIATOR_SIGN = 25;
|
||||
|
||||
// RFC 4121, Flags Field
|
||||
private static final int FLAG_SENDER_IS_ACCEPTOR = 1;
|
||||
private static final int FLAG_WRAP_CONFIDENTIAL = 2;
|
||||
private static final int FLAG_ACCEPTOR_SUBKEY = 4;
|
||||
private static final int FILLER = 0xff;
|
||||
|
||||
private MessageTokenHeader tokenHeader = null;
|
||||
|
||||
// Common field
|
||||
private int tokenId = 0;
|
||||
private int seqNumber;
|
||||
protected byte[] tokenData; // content of token, without the header
|
||||
protected int tokenDataLen;
|
||||
|
||||
// Key usage number for crypto action
|
||||
private int key_usage = 0;
|
||||
|
||||
// EC and RRC fields, WrapToken only
|
||||
private int ec = 0;
|
||||
private int rrc = 0;
|
||||
|
||||
// Checksum. Always in MicToken, might be in WrapToken
|
||||
byte[] checksum = null;
|
||||
|
||||
// Context properties
|
||||
private boolean confState = true;
|
||||
private boolean initiator = true;
|
||||
private boolean have_acceptor_subkey = false;
|
||||
|
||||
/* cipher instance used by the corresponding GSSContext */
|
||||
CipherHelper cipherHelper = null;
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from a byte array.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param tokenBytes the byte array containing the token
|
||||
* @param tokenOffset the offset where the token begins
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem parsing the token
|
||||
*/
|
||||
MessageToken_v2(int tokenId, Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
this(tokenId, context,
|
||||
new ByteArrayInputStream(tokenBytes, tokenOffset, tokenLen),
|
||||
prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageToken from an InputStream. Bytes will be read on
|
||||
* demand and the thread might block if there are not enough bytes to
|
||||
* complete the token. Please note there is no accurate way to find out
|
||||
* the size of a token, but we try our best to make sure there is
|
||||
* enough bytes to construct one.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token as
|
||||
* it is read.
|
||||
* @param context the Kerberos context associated with this token
|
||||
* @param is the InputStream from which to read
|
||||
* @param prop the MessageProp structure in which the properties of the
|
||||
* token should be stored.
|
||||
* @throws GSSException if there is a problem reading from the
|
||||
* InputStream or parsing the token
|
||||
*/
|
||||
MessageToken_v2(int tokenId, Krb5Context context, InputStream is,
|
||||
MessageProp prop) throws GSSException {
|
||||
init(tokenId, context);
|
||||
|
||||
try {
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
tokenHeader = new MessageTokenHeader(is, prop, tokenId);
|
||||
|
||||
// set key_usage
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2) {
|
||||
key_usage = (!initiator ? KG_USAGE_INITIATOR_SEAL
|
||||
: KG_USAGE_ACCEPTOR_SEAL);
|
||||
} else if (tokenId == Krb5Token.MIC_ID_v2) {
|
||||
key_usage = (!initiator ? KG_USAGE_INITIATOR_SIGN
|
||||
: KG_USAGE_ACCEPTOR_SIGN);
|
||||
}
|
||||
|
||||
int minSize = 0; // minimal size for token data
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2 && prop.getPrivacy()) {
|
||||
minSize = CONFOUNDER_SIZE +
|
||||
TOKEN_HEADER_SIZE + cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
minSize = cipherHelper.getChecksumLength();
|
||||
}
|
||||
|
||||
// Read token data
|
||||
if (tokenId == Krb5Token.MIC_ID_v2) {
|
||||
// The only case we can precisely predict the token data length
|
||||
tokenDataLen = minSize;
|
||||
tokenData = new byte[minSize];
|
||||
readFully(is, tokenData);
|
||||
} else {
|
||||
tokenDataLen = is.available();
|
||||
if (tokenDataLen >= minSize) { // read in one shot
|
||||
tokenData = new byte[tokenDataLen];
|
||||
readFully(is, tokenData);
|
||||
} else {
|
||||
byte[] tmp = new byte[minSize];
|
||||
readFully(is, tmp);
|
||||
// Hope while blocked in the read above, more data would
|
||||
// come and is.available() below contains the whole token.
|
||||
int more = is.available();
|
||||
tokenDataLen = minSize + more;
|
||||
tokenData = Arrays.copyOf(tmp, tokenDataLen);
|
||||
readFully(is, tokenData, minSize, more);
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2) {
|
||||
rotate();
|
||||
}
|
||||
|
||||
if (tokenId == Krb5Token.MIC_ID_v2 ||
|
||||
(tokenId == Krb5Token.WRAP_ID_v2 && !prop.getPrivacy())) {
|
||||
// Read checksum
|
||||
int chkLen = cipherHelper.getChecksumLength();
|
||||
checksum = new byte[chkLen];
|
||||
System.arraycopy(tokenData, tokenDataLen-chkLen,
|
||||
checksum, 0, chkLen);
|
||||
|
||||
// validate EC for Wrap tokens without confidentiality
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2 && !prop.getPrivacy()) {
|
||||
if (chkLen != ec) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "EC incorrect!");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the token id that was contained in this token.
|
||||
* @return the token id in the token
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to obtain the key_usage type for this token.
|
||||
* @return the key_usage for the token
|
||||
*/
|
||||
public final int getKeyUsage() {
|
||||
return key_usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine if this token contains any encrypted data.
|
||||
* @return true if it contains any encrypted data, false if there is only
|
||||
* plaintext data or if there is no data.
|
||||
*/
|
||||
public final boolean getConfState() {
|
||||
return confState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the checksum field and the sequence number field.
|
||||
*
|
||||
* @param prop the MessageProp structure
|
||||
* @param data the application data to checksum
|
||||
* @param offset the offset where the data starts
|
||||
* @param len the length of the data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation or
|
||||
* sequence number calculation.
|
||||
*/
|
||||
public void genSignAndSeqNumber(MessageProp prop,
|
||||
byte[] data, int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Inside MessageToken.genSignAndSeqNumber:\n");
|
||||
|
||||
int qop = prop.getQOP();
|
||||
if (qop != 0) {
|
||||
qop = 0;
|
||||
prop.setQOP(qop);
|
||||
}
|
||||
|
||||
if (!confState) {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
// Create a new gss token header as defined in RFC 4121
|
||||
tokenHeader = new MessageTokenHeader(tokenId, prop.getPrivacy());
|
||||
// debug("\n\t Message Header = " +
|
||||
// getHexBytes(tokenHeader.getBytes(), tokenHeader.getBytes().length));
|
||||
|
||||
// set key_usage
|
||||
if (tokenId == Krb5Token.WRAP_ID_v2) {
|
||||
key_usage = (initiator ? KG_USAGE_INITIATOR_SEAL
|
||||
: KG_USAGE_ACCEPTOR_SEAL);
|
||||
} else if (tokenId == Krb5Token.MIC_ID_v2) {
|
||||
key_usage = (initiator ? KG_USAGE_INITIATOR_SIGN
|
||||
: KG_USAGE_ACCEPTOR_SIGN);
|
||||
}
|
||||
|
||||
// Calculate SGN_CKSUM
|
||||
if ((tokenId == MIC_ID_v2) ||
|
||||
(!prop.getPrivacy() && (tokenId == WRAP_ID_v2))) {
|
||||
checksum = getChecksum(data, offset, len);
|
||||
// debug("\n\tCalc checksum=" +
|
||||
// getHexBytes(checksum, checksum.length));
|
||||
}
|
||||
|
||||
// In Wrap tokens without confidentiality, the EC field SHALL be used
|
||||
// to encode the number of octets in the trailing checksum
|
||||
if (!prop.getPrivacy() && (tokenId == WRAP_ID_v2)) {
|
||||
byte[] tok_header = tokenHeader.getBytes();
|
||||
tok_header[4] = (byte) (checksum.length >>> 8);
|
||||
tok_header[5] = (byte) (checksum.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the validity of checksum field
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation
|
||||
*/
|
||||
public final boolean verifySign(byte[] data, int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
// debug("\t====In verifySign:====\n");
|
||||
// debug("\t\t checksum: [" + getHexBytes(checksum) + "]\n");
|
||||
// debug("\t\t data = [" + getHexBytes(data) + "]\n");
|
||||
|
||||
byte[] myChecksum = getChecksum(data, offset, len);
|
||||
// debug("\t\t mychecksum: [" + getHexBytes(myChecksum) +"]\n");
|
||||
|
||||
if (MessageDigest.isEqual(checksum, myChecksum)) {
|
||||
// debug("\t\t====Checksum PASS:====\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate bytes as per the "RRC" (Right Rotation Count) received.
|
||||
* Our implementation does not do any rotates when sending, only
|
||||
* when receiving, we rotate left as per the RRC count, to revert it.
|
||||
*/
|
||||
private void rotate() {
|
||||
if (rrc % tokenDataLen != 0) {
|
||||
rrc = rrc % tokenDataLen;
|
||||
byte[] newBytes = new byte[tokenDataLen];
|
||||
|
||||
System.arraycopy(tokenData, rrc, newBytes, 0, tokenDataLen-rrc);
|
||||
System.arraycopy(tokenData, 0, newBytes, tokenDataLen-rrc, rrc);
|
||||
|
||||
tokenData = newBytes;
|
||||
}
|
||||
}
|
||||
|
||||
public final int getSequenceNumber() {
|
||||
return seqNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the checksum based on the algorithm stored in the
|
||||
* tokenHeader.
|
||||
*
|
||||
* @param data the application data
|
||||
* @param offset the offset where the data begins
|
||||
* @param len the length of the application data
|
||||
*
|
||||
* @throws GSSException if an error occurs in the checksum calculation.
|
||||
*/
|
||||
byte[] getChecksum(byte[] data, int offset, int len)
|
||||
throws GSSException {
|
||||
|
||||
// debug("Will do getChecksum:\n");
|
||||
|
||||
/*
|
||||
* For checksum calculation the token header bytes i.e., the first 16
|
||||
* bytes following the GSSHeader, are logically prepended to the
|
||||
* application data to bind the data to this particular token.
|
||||
*
|
||||
* Note: There is no such requirement wrt adding padding to the
|
||||
* application data for checksumming, although the cryptographic
|
||||
* algorithm used might itself apply some padding.
|
||||
*/
|
||||
|
||||
byte[] tokenHeaderBytes = tokenHeader.getBytes();
|
||||
|
||||
// check confidentiality
|
||||
int conf_flag = tokenHeaderBytes[TOKEN_FLAG_POS] &
|
||||
FLAG_WRAP_CONFIDENTIAL;
|
||||
|
||||
// clear EC and RRC in token header for checksum calculation
|
||||
if ((conf_flag == 0) && (tokenId == WRAP_ID_v2)) {
|
||||
tokenHeaderBytes[4] = 0;
|
||||
tokenHeaderBytes[5] = 0;
|
||||
tokenHeaderBytes[6] = 0;
|
||||
tokenHeaderBytes[7] = 0;
|
||||
}
|
||||
return cipherHelper.calculateChecksum(tokenHeaderBytes, data,
|
||||
offset, len, key_usage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs an empty MessageToken for the local context to send to
|
||||
* the peer. It also increments the local sequence number in the
|
||||
* Krb5Context instance it uses after obtaining the object lock for
|
||||
* it.
|
||||
*
|
||||
* @param tokenId the token id that should be contained in this token
|
||||
* @param context the Kerberos context associated with this token
|
||||
*/
|
||||
MessageToken_v2(int tokenId, Krb5Context context) throws GSSException {
|
||||
/*
|
||||
debug("\n============================");
|
||||
debug("\nMySessionKey=" +
|
||||
getHexBytes(context.getMySessionKey().getBytes()));
|
||||
debug("\nPeerSessionKey=" +
|
||||
getHexBytes(context.getPeerSessionKey().getBytes()));
|
||||
debug("\n============================\n");
|
||||
*/
|
||||
init(tokenId, context);
|
||||
this.seqNumber = context.incrementMySequenceNumber();
|
||||
}
|
||||
|
||||
private void init(int tokenId, Krb5Context context) throws GSSException {
|
||||
this.tokenId = tokenId;
|
||||
// Just for consistency check in Wrap
|
||||
this.confState = context.getConfState();
|
||||
|
||||
this.initiator = context.isInitiator();
|
||||
|
||||
this.have_acceptor_subkey = context.getKeySrc() == Krb5Context.ACCEPTOR_SUBKEY;
|
||||
|
||||
this.cipherHelper = context.getCipherHelper(null);
|
||||
// debug("In MessageToken.Cons");
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a MessageTokenHeader onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws IOException is an error occurs while writing to the OutputStream
|
||||
*/
|
||||
protected void encodeHeader(OutputStream os) throws IOException {
|
||||
tokenHeader.encode(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a MessageToken_v2 onto an OutputStream.
|
||||
*
|
||||
* @param os the OutputStream to which this should be written
|
||||
* @throws IOException is an error occurs while encoding the token
|
||||
*/
|
||||
public abstract void encode(OutputStream os) throws IOException;
|
||||
|
||||
protected final byte[] getTokenHeader() {
|
||||
return (tokenHeader.getBytes());
|
||||
}
|
||||
|
||||
// ******************************************* //
|
||||
// I N N E R C L A S S E S F O L L O W
|
||||
// ******************************************* //
|
||||
|
||||
/**
|
||||
* This inner class represents the initial portion of the message token.
|
||||
* It constitutes the first 16 bytes of the message token.
|
||||
*/
|
||||
class MessageTokenHeader {
|
||||
|
||||
private int tokenId;
|
||||
private byte[] bytes = new byte[TOKEN_HEADER_SIZE];
|
||||
|
||||
// Writes a new token header
|
||||
public MessageTokenHeader(int tokenId, boolean conf) throws GSSException {
|
||||
|
||||
this.tokenId = tokenId;
|
||||
|
||||
bytes[0] = (byte) (tokenId >>> 8);
|
||||
bytes[1] = (byte) (tokenId);
|
||||
|
||||
// Flags (Note: MIT impl requires subkey)
|
||||
int flags = 0;
|
||||
flags = (initiator ? 0 : FLAG_SENDER_IS_ACCEPTOR) |
|
||||
((conf && tokenId != MIC_ID_v2) ?
|
||||
FLAG_WRAP_CONFIDENTIAL : 0) |
|
||||
(have_acceptor_subkey ? FLAG_ACCEPTOR_SUBKEY : 0);
|
||||
bytes[2] = (byte) flags;
|
||||
|
||||
// filler
|
||||
bytes[3] = (byte) FILLER;
|
||||
|
||||
if (tokenId == WRAP_ID_v2) {
|
||||
// EC field
|
||||
bytes[4] = (byte) 0;
|
||||
bytes[5] = (byte) 0;
|
||||
// RRC field
|
||||
bytes[6] = (byte) 0;
|
||||
bytes[7] = (byte) 0;
|
||||
} else if (tokenId == MIC_ID_v2) {
|
||||
// more filler for MicToken
|
||||
for (int i = 4; i < 8; i++) {
|
||||
bytes[i] = (byte) FILLER;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate SND_SEQ, only write 4 bytes from the 12th position
|
||||
writeBigEndian(seqNumber, bytes, 12);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a MessageTokenHeader from an InputStream and sets the
|
||||
* appropriate confidentiality and quality of protection
|
||||
* values in a MessageProp structure.
|
||||
*
|
||||
* @param is the InputStream to read from
|
||||
* @param prop the MessageProp to populate
|
||||
* @throws IOException is an error occurs while reading from the
|
||||
* InputStream
|
||||
*/
|
||||
public MessageTokenHeader(InputStream is, MessageProp prop, int tokId)
|
||||
throws IOException, GSSException {
|
||||
|
||||
readFully(is, bytes, 0, TOKEN_HEADER_SIZE);
|
||||
tokenId = readInt(bytes, TOKEN_ID_POS);
|
||||
|
||||
// validate Token ID
|
||||
if (tokenId != tokId) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token ID!");
|
||||
}
|
||||
|
||||
/*
|
||||
* Validate new GSS TokenHeader
|
||||
*/
|
||||
|
||||
// valid acceptor_flag
|
||||
// If I am initiator, the received token should have ACCEPTOR on
|
||||
int acceptor_flag = (initiator ? FLAG_SENDER_IS_ACCEPTOR : 0);
|
||||
int flag = bytes[TOKEN_FLAG_POS] & FLAG_SENDER_IS_ACCEPTOR;
|
||||
if (flag != acceptor_flag) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Acceptor Flag Error!");
|
||||
}
|
||||
|
||||
// check for confidentiality
|
||||
int conf_flag = bytes[TOKEN_FLAG_POS] & FLAG_WRAP_CONFIDENTIAL;
|
||||
if ((conf_flag == FLAG_WRAP_CONFIDENTIAL) &&
|
||||
(tokenId == WRAP_ID_v2)) {
|
||||
prop.setPrivacy(true);
|
||||
} else {
|
||||
prop.setPrivacy(false);
|
||||
}
|
||||
|
||||
if (tokenId == WRAP_ID_v2) {
|
||||
// validate filler
|
||||
if ((bytes[3] & 0xff) != FILLER) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(tokenId) + ":" + "Defective Token Filler!");
|
||||
}
|
||||
|
||||
// read EC field
|
||||
ec = readBigEndian(bytes, TOKEN_EC_POS, 2);
|
||||
|
||||
// read RRC field
|
||||
rrc = readBigEndian(bytes, TOKEN_RRC_POS, 2);
|
||||
} else if (tokenId == MIC_ID_v2) {
|
||||
for (int i = 3; i < 8; i++) {
|
||||
if ((bytes[i] & 0xff) != FILLER) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN,
|
||||
-1, getTokenName(tokenId) + ":" +
|
||||
"Defective Token Filler!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set default QOP
|
||||
prop.setQOP(0);
|
||||
|
||||
// sequence number
|
||||
seqNumber = readBigEndian(bytes, 12, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes this MessageTokenHeader onto an OutputStream
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException is an error occurs while writing
|
||||
*/
|
||||
public final void encode(OutputStream os) throws IOException {
|
||||
os.write(bytes);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the token id for the message token.
|
||||
* @return the token id
|
||||
* @see sun.security.jgss.krb5.Krb5Token#MIC_ID_v2
|
||||
* @see sun.security.jgss.krb5.Krb5Token#WRAP_ID_v2
|
||||
*/
|
||||
public final int getTokenId() {
|
||||
return tokenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bytes of this header.
|
||||
* @return 8 bytes that form this header
|
||||
*/
|
||||
public final byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
} // end of class MessageTokenHeader
|
||||
}
|
||||
114
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken.java
Normal file
114
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
class MicToken extends MessageToken {
|
||||
|
||||
public MicToken(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
super(Krb5Token.MIC_ID, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
}
|
||||
|
||||
public MicToken(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID, context, is, prop);
|
||||
}
|
||||
|
||||
public void verify(byte[] data, int offset, int len) throws GSSException {
|
||||
if (!verifySignAndSeqNumber(null, data, offset, len, null))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
|
||||
public void verify(InputStream data) throws GSSException {
|
||||
byte[] dataBytes = null;
|
||||
try {
|
||||
dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
} catch (IOException e) {
|
||||
// Error reading application data
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
verify(dataBytes, 0, dataBytes.length);
|
||||
}
|
||||
|
||||
public MicToken(Krb5Context context, MessageProp prop,
|
||||
byte[] data, int pos, int len)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID, context);
|
||||
|
||||
// debug("Application data to MicToken verify is [" +
|
||||
// getHexBytes(data, pos, len) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, null, data, pos, len, null);
|
||||
}
|
||||
|
||||
public MicToken(Krb5Context context, MessageProp prop,
|
||||
InputStream data)
|
||||
throws GSSException, IOException {
|
||||
super(Krb5Token.MIC_ID, context);
|
||||
byte[] dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
|
||||
//debug("Application data to MicToken cons is [" +
|
||||
// getHexBytes(dataBytes) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, null, dataBytes, 0, dataBytes.length, null);
|
||||
}
|
||||
|
||||
protected int getSealAlg(boolean confRequested, int qop) {
|
||||
return (SEAL_ALG_NONE);
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset)
|
||||
throws IOException, GSSException {
|
||||
// Token is small
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
super.encode(bos);
|
||||
byte[] token = bos.toByteArray();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException, GSSException{
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
118
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken_v2.java
Normal file
118
jdkSrc/jdk8/sun/security/jgss/krb5/MicToken_v2.java
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2010, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* This class represents the new format of GSS MIC tokens, as specified
|
||||
* in RFC 4121
|
||||
*
|
||||
* MIC tokens = { 16-byte token-header | HMAC }
|
||||
* where HMAC is on { plaintext | 16-byte token-header }
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
|
||||
class MicToken_v2 extends MessageToken_v2 {
|
||||
|
||||
public MicToken_v2(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context, InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context, is, prop);
|
||||
}
|
||||
|
||||
public void verify(byte[] data, int offset, int len) throws GSSException {
|
||||
if (!verifySign(data, offset, len))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
|
||||
public void verify(InputStream data) throws GSSException {
|
||||
byte[] dataBytes = null;
|
||||
try {
|
||||
dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
} catch (IOException e) {
|
||||
// Error reading application data
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in MIC token");
|
||||
}
|
||||
verify(dataBytes, 0, dataBytes.length);
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context, MessageProp prop,
|
||||
byte[] data, int pos, int len)
|
||||
throws GSSException {
|
||||
super(Krb5Token.MIC_ID_v2, context);
|
||||
|
||||
// debug("Application data to MicToken verify is [" +
|
||||
// getHexBytes(data, pos, len) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, data, pos, len);
|
||||
}
|
||||
|
||||
public MicToken_v2(Krb5Context context, MessageProp prop, InputStream data)
|
||||
throws GSSException, IOException {
|
||||
|
||||
super(Krb5Token.MIC_ID_v2, context);
|
||||
byte[] dataBytes = new byte[data.available()];
|
||||
data.read(dataBytes);
|
||||
|
||||
// debug("Application data to MicToken cons is [" +
|
||||
// getHexBytes(dataBytes) + "]\n");
|
||||
if (prop == null) prop = new MessageProp(0, false);
|
||||
genSignAndSeqNumber(prop, dataBytes, 0, dataBytes.length);
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException {
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset) throws IOException {
|
||||
byte[] token = encode();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException {
|
||||
encodeHeader(os);
|
||||
os.write(checksum);
|
||||
}
|
||||
}
|
||||
262
jdkSrc/jdk8/sun/security/jgss/krb5/ServiceCreds.java
Normal file
262
jdkSrc/jdk8/sun/security/jgss/krb5/ServiceCreds.java
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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.krb5;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import sun.security.krb5.Credentials;
|
||||
import sun.security.krb5.EncryptionKey;
|
||||
import sun.security.krb5.KrbException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import sun.security.krb5.*;
|
||||
import sun.security.krb5.internal.Krb5;
|
||||
|
||||
/**
|
||||
* Credentials of a kerberos acceptor. A KerberosPrincipal object (kp) is
|
||||
* the principal. It can be specified as the serverPrincipal argument
|
||||
* in the getInstance() method, or uses only KerberosPrincipal in the subject.
|
||||
* Otherwise, the creds object is unbound and kp is null.
|
||||
*
|
||||
* The class also encapsulates various secrets, which can be:
|
||||
*
|
||||
* 1. Some KerberosKeys (generated from password)
|
||||
* 2. Some KeyTabs (for a typical service based on keytabs)
|
||||
* 3. A TGT (for S4U2proxy extension or user2user)
|
||||
*
|
||||
* Note that some secrets can coexist. For example, a user2user service
|
||||
* can use its keytab (or keys) if the client can successfully obtain a
|
||||
* normal service ticket, or it can use the TGT (actually, the session key
|
||||
* of the TGT) if the client can only acquire a service ticket
|
||||
* of ENC-TKT-IN-SKEY style.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public final class ServiceCreds {
|
||||
// The principal, or null if unbound
|
||||
private KerberosPrincipal kp;
|
||||
|
||||
// All principals in the subject's princ set
|
||||
private Set<KerberosPrincipal> allPrincs;
|
||||
|
||||
// All private credentials that can be used
|
||||
private List<KeyTab> ktabs;
|
||||
private List<KerberosKey> kk;
|
||||
private KerberosTicket tgt;
|
||||
|
||||
private boolean destroyed;
|
||||
|
||||
private ServiceCreds() {
|
||||
// Make sure this class cannot be instantiated externally.
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ServiceCreds object based on info in a Subject for
|
||||
* a given principal name (if specified).
|
||||
* @return the object, or null if there is no private creds for it
|
||||
*/
|
||||
public static ServiceCreds getInstance(
|
||||
Subject subj, String serverPrincipal) {
|
||||
|
||||
ServiceCreds sc = new ServiceCreds();
|
||||
|
||||
sc.allPrincs =
|
||||
subj.getPrincipals(KerberosPrincipal.class);
|
||||
|
||||
// Compatibility. A key implies its own principal
|
||||
for (KerberosKey key: SubjectComber.findMany(
|
||||
subj, serverPrincipal, null, KerberosKey.class)) {
|
||||
sc.allPrincs.add(key.getPrincipal());
|
||||
}
|
||||
|
||||
if (serverPrincipal != null) { // A named principal
|
||||
sc.kp = new KerberosPrincipal(serverPrincipal);
|
||||
} else {
|
||||
// For compatibility reason, we set the name of default principal
|
||||
// to the "only possible" name it can take, which means there is
|
||||
// only one KerberosPrincipal and there is no unbound keytabs
|
||||
if (sc.allPrincs.size() == 1) {
|
||||
boolean hasUnbound = false;
|
||||
for (KeyTab ktab: SubjectComber.findMany(
|
||||
subj, null, null, KeyTab.class)) {
|
||||
if (!ktab.isBound()) {
|
||||
hasUnbound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasUnbound) {
|
||||
sc.kp = sc.allPrincs.iterator().next();
|
||||
serverPrincipal = sc.kp.getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sc.ktabs = SubjectComber.findMany(
|
||||
subj, serverPrincipal, null, KeyTab.class);
|
||||
sc.kk = SubjectComber.findMany(
|
||||
subj, serverPrincipal, null, KerberosKey.class);
|
||||
sc.tgt = SubjectComber.find(
|
||||
subj, null, serverPrincipal, KerberosTicket.class);
|
||||
if (sc.ktabs.isEmpty() && sc.kk.isEmpty() && sc.tgt == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
sc.destroyed = false;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
// can be null
|
||||
public String getName() {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
return kp == null ? null : kp.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets keys for "someone". Used in 2 cases:
|
||||
* 1. By TLS because it needs to get keys before client comes in.
|
||||
* 2. As a fallback in getEKeys() below.
|
||||
* This method can still return an empty array.
|
||||
*/
|
||||
public KerberosKey[] getKKeys() {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
KerberosPrincipal one = kp; // named principal
|
||||
if (one == null && !allPrincs.isEmpty()) { // or, a known principal
|
||||
one = allPrincs.iterator().next();
|
||||
}
|
||||
if (one == null) { // Or, some random one
|
||||
for (KeyTab ktab: ktabs) {
|
||||
// Must be unbound keytab, otherwise, allPrincs is not empty
|
||||
PrincipalName pn =
|
||||
Krb5Util.snapshotFromJavaxKeyTab(ktab).getOneName();
|
||||
if (pn != null) {
|
||||
one = new KerberosPrincipal(pn.getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (one != null) {
|
||||
return getKKeys(one);
|
||||
} else {
|
||||
return new KerberosKey[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get kkeys for a principal,
|
||||
* @param princ the target name initiator requests. Not null.
|
||||
* @return keys for the princ, never null, might be empty
|
||||
*/
|
||||
public KerberosKey[] getKKeys(KerberosPrincipal princ) {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
ArrayList<KerberosKey> keys = new ArrayList<>();
|
||||
if (kp != null && !princ.equals(kp)) { // named principal
|
||||
return new KerberosKey[0];
|
||||
}
|
||||
for (KerberosKey k: kk) {
|
||||
if (k.getPrincipal().equals(princ)) {
|
||||
keys.add(k);
|
||||
}
|
||||
}
|
||||
for (KeyTab ktab: ktabs) {
|
||||
if (ktab.getPrincipal() == null && ktab.isBound()) {
|
||||
// legacy bound keytab. although we don't know who
|
||||
// the bound principal is, it must be in allPrincs
|
||||
if (!allPrincs.contains(princ)) {
|
||||
continue; // skip this legacy bound keytab
|
||||
}
|
||||
}
|
||||
for (KerberosKey k: ktab.getKeys(princ)) {
|
||||
keys.add(k);
|
||||
}
|
||||
}
|
||||
return keys.toArray(new KerberosKey[keys.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets EKeys for a principal.
|
||||
* @param princ the target name initiator requests. Not null.
|
||||
* @return keys for the princ, never null, might be empty
|
||||
*/
|
||||
public EncryptionKey[] getEKeys(PrincipalName princ) {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
KerberosKey[] kkeys = getKKeys(new KerberosPrincipal(princ.getName()));
|
||||
if (kkeys.length == 0) {
|
||||
// Fallback: old JDK does not perform real name checking. If the
|
||||
// acceptor has host.sun.com but initiator requests for host,
|
||||
// as long as their keys match (i.e. keys for one can decrypt
|
||||
// the other's service ticket), the authentication is OK.
|
||||
// There are real customers depending on this to use different
|
||||
// names for a single service.
|
||||
kkeys = getKKeys();
|
||||
}
|
||||
EncryptionKey[] ekeys = new EncryptionKey[kkeys.length];
|
||||
for (int i=0; i<ekeys.length; i++) {
|
||||
ekeys[i] = new EncryptionKey(
|
||||
kkeys[i].getEncoded(), kkeys[i].getKeyType(),
|
||||
new Integer(kkeys[i].getVersionNumber()));
|
||||
}
|
||||
return ekeys;
|
||||
}
|
||||
|
||||
public Credentials getInitCred() {
|
||||
if (destroyed) {
|
||||
throw new IllegalStateException("This object is destroyed");
|
||||
}
|
||||
if (tgt == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Krb5Util.ticketToCreds(tgt);
|
||||
} catch (KrbException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
// Do not wipe out real keys because they are references to the
|
||||
// priv creds in subject. Just make it useless.
|
||||
destroyed = true;
|
||||
kp = null;
|
||||
ktabs.clear();
|
||||
kk.clear();
|
||||
tgt = null;
|
||||
}
|
||||
}
|
||||
251
jdkSrc/jdk8/sun/security/jgss/krb5/SubjectComber.java
Normal file
251
jdkSrc/jdk8/sun/security/jgss/krb5/SubjectComber.java
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2019, 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.krb5;
|
||||
|
||||
import sun.security.krb5.JavaxSecurityAuthKerberosAccess;
|
||||
import sun.security.krb5.KerberosSecrets;
|
||||
|
||||
import javax.security.auth.kerberos.KerberosTicket;
|
||||
import javax.security.auth.kerberos.KerberosKey;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.DestroyFailedException;
|
||||
import java.util.Iterator;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.security.auth.kerberos.KerberosPrincipal;
|
||||
import javax.security.auth.kerberos.KeyTab;
|
||||
|
||||
/**
|
||||
* This utility looks through the current Subject and retrieves private
|
||||
* credentials for the desired client/server principals.
|
||||
*
|
||||
* @author Ram Marti
|
||||
* @since 1.4.2
|
||||
*/
|
||||
|
||||
class SubjectComber {
|
||||
|
||||
private static final boolean DEBUG = Krb5Util.DEBUG;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
private SubjectComber() { // Cannot create one of these
|
||||
}
|
||||
|
||||
static <T> T find(Subject subject, String serverPrincipal,
|
||||
String clientPrincipal, Class<T> credClass) {
|
||||
|
||||
// findAux returns T if oneOnly.
|
||||
return credClass.cast(findAux(subject, serverPrincipal,
|
||||
clientPrincipal, credClass, true));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // findAux returns List<T> if !oneOnly.
|
||||
static <T> List<T> findMany(Subject subject, String serverPrincipal,
|
||||
String clientPrincipal, Class<T> credClass) {
|
||||
|
||||
return (List<T>)findAux(subject, serverPrincipal, clientPrincipal,
|
||||
credClass, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find private credentials for the specified client/server principals
|
||||
* in the subject. Returns null if the subject is null.
|
||||
*
|
||||
* @return the private credentials
|
||||
*/
|
||||
// Returns T if oneOnly and List<T> if !oneOnly.
|
||||
private static <T> Object findAux(Subject subject, String serverPrincipal,
|
||||
String clientPrincipal, Class<T> credClass, boolean oneOnly) {
|
||||
|
||||
if (subject == null) {
|
||||
return null;
|
||||
} else {
|
||||
List<T> answer = (oneOnly ? null : new ArrayList<T>());
|
||||
|
||||
if (credClass == KeyTab.class) {
|
||||
Iterator<KeyTab> iterator =
|
||||
subject.getPrivateCredentials(KeyTab.class).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
KeyTab t = iterator.next();
|
||||
if (serverPrincipal != null && t.isBound()) {
|
||||
KerberosPrincipal name = t.getPrincipal();
|
||||
if (name != null) {
|
||||
if (!serverPrincipal.equals(name.getName())) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// legacy bound keytab. although we don't know who
|
||||
// the bound principal is, it must be in allPrincs
|
||||
boolean found = false;
|
||||
for (KerberosPrincipal princ:
|
||||
subject.getPrincipals(KerberosPrincipal.class)) {
|
||||
if (princ.getName().equals(serverPrincipal)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) continue;
|
||||
}
|
||||
}
|
||||
// Check passed, we can add now
|
||||
if (DEBUG) {
|
||||
System.out.println("Found " + credClass.getSimpleName()
|
||||
+ " " + t);
|
||||
}
|
||||
if (oneOnly) {
|
||||
return t;
|
||||
} else {
|
||||
answer.add(credClass.cast(t));
|
||||
}
|
||||
}
|
||||
} else if (credClass == KerberosKey.class) {
|
||||
// We are looking for credentials for the serverPrincipal
|
||||
Iterator<KerberosKey> iterator =
|
||||
subject.getPrivateCredentials(KerberosKey.class).iterator();
|
||||
while (iterator.hasNext()) {
|
||||
KerberosKey t = iterator.next();
|
||||
String name = t.getPrincipal().getName();
|
||||
if (serverPrincipal == null || serverPrincipal.equals(name)) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Found " +
|
||||
credClass.getSimpleName() + " for " + name);
|
||||
}
|
||||
if (oneOnly) {
|
||||
return t;
|
||||
} else {
|
||||
answer.add(credClass.cast(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (credClass == KerberosTicket.class) {
|
||||
// we are looking for a KerberosTicket credentials
|
||||
// for client-service principal pair
|
||||
Set<Object> pcs = subject.getPrivateCredentials();
|
||||
synchronized (pcs) {
|
||||
Iterator<Object> iterator = pcs.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Object obj = iterator.next();
|
||||
if (!(obj instanceof KerberosTicket)) {
|
||||
continue;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
KerberosTicket ticket = (KerberosTicket)obj;
|
||||
if (DEBUG) {
|
||||
System.out.println("Found ticket for "
|
||||
+ ticket.getClient()
|
||||
+ " to go to "
|
||||
+ ticket.getServer()
|
||||
+ " expiring on "
|
||||
+ ticket.getEndTime());
|
||||
}
|
||||
if (!ticket.isCurrent()) {
|
||||
// let us remove the ticket from the Subject
|
||||
// Note that both TGT and service ticket will be
|
||||
// removed upon expiration
|
||||
if (!subject.isReadOnly()) {
|
||||
iterator.remove();
|
||||
try {
|
||||
ticket.destroy();
|
||||
if (DEBUG) {
|
||||
System.out.println("Removed and destroyed "
|
||||
+ "the expired Ticket \n"
|
||||
+ ticket);
|
||||
|
||||
}
|
||||
} catch (DestroyFailedException dfe) {
|
||||
if (DEBUG) {
|
||||
System.out.println("Expired ticket not" +
|
||||
" detroyed successfully. " + dfe);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
String serverMatch = findServerMatch(serverPrincipal, ticket);
|
||||
if (serverMatch != null) {
|
||||
String clientMatch = findClientMatch(clientPrincipal, ticket);
|
||||
if (clientMatch != null) {
|
||||
if (oneOnly) {
|
||||
return ticket;
|
||||
} else {
|
||||
// Record names so that tickets will
|
||||
// all belong to same principals
|
||||
if (clientPrincipal == null) {
|
||||
clientPrincipal = clientMatch;
|
||||
}
|
||||
if (serverPrincipal == null) {
|
||||
serverPrincipal = serverMatch;
|
||||
}
|
||||
answer.add(credClass.cast(ticket));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
||||
private static String findServerMatch(String input, KerberosTicket ticket) {
|
||||
KerberosPrincipal serverAlias = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess()
|
||||
.kerberosTicketGetServerAlias(ticket);
|
||||
if (input != null) {
|
||||
return ((serverAlias != null && input.equals(serverAlias.getName())) ||
|
||||
input.equals(ticket.getServer().getName()))
|
||||
? input : null;
|
||||
} else {
|
||||
return serverAlias != null
|
||||
? serverAlias.getName()
|
||||
: ticket.getServer().getName();
|
||||
}
|
||||
}
|
||||
|
||||
private static String findClientMatch(String input, KerberosTicket ticket) {
|
||||
JavaxSecurityAuthKerberosAccess access = KerberosSecrets
|
||||
.getJavaxSecurityAuthKerberosAccess();
|
||||
KerberosPrincipal clientAlias = access.kerberosTicketGetClientAlias(ticket);
|
||||
KerberosTicket proxy = access.kerberosTicketGetProxy(ticket);
|
||||
if (input != null) {
|
||||
return ((clientAlias != null && input.equals(clientAlias.getName())) ||
|
||||
(proxy != null && input.equals(proxy.getClient().getName())) ||
|
||||
(proxy == null && input.equals(ticket.getClient().getName())))
|
||||
? input : null;
|
||||
} else {
|
||||
if (clientAlias != null) {
|
||||
return clientAlias.getName();
|
||||
} else if (proxy != null) {
|
||||
return proxy.getClient().getName();
|
||||
} else {
|
||||
return ticket.getClient().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
532
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken.java
Normal file
532
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken.java
Normal file
@@ -0,0 +1,532 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import sun.security.krb5.Confounder;
|
||||
|
||||
/**
|
||||
* This class represents a token emitted by the GSSContext.wrap()
|
||||
* call. It is a MessageToken except that it also contains plaintext
|
||||
* or encrypted data at the end. A wrapToken has certain other rules
|
||||
* that are peculiar to it and different from a MICToken, which is
|
||||
* another type of MessageToken. All data in a WrapToken is prepended
|
||||
* by a random counfounder of 8 bytes. All data in a WrapToken is
|
||||
* also padded with one to eight bytes where all bytes are equal in
|
||||
* value to the number of bytes being padded. Thus, all application
|
||||
* data is replaced by (confounder || data || padding).
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
class WrapToken extends MessageToken {
|
||||
/**
|
||||
* The size of the random confounder used in a WrapToken.
|
||||
*/
|
||||
static final int CONFOUNDER_SIZE = 8;
|
||||
|
||||
/*
|
||||
* The padding used with a WrapToken. All data is padded to the
|
||||
* next multiple of 8 bytes, even if its length is already
|
||||
* multiple of 8.
|
||||
* Use this table as a quick way to obtain padding bytes by
|
||||
* indexing it with the number of padding bytes required.
|
||||
*/
|
||||
static final byte[][] pads = {
|
||||
null, // No, no one escapes padding
|
||||
{0x01},
|
||||
{0x02, 0x02},
|
||||
{0x03, 0x03, 0x03},
|
||||
{0x04, 0x04, 0x04, 0x04},
|
||||
{0x05, 0x05, 0x05, 0x05, 0x05},
|
||||
{0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
|
||||
{0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07},
|
||||
{0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}
|
||||
};
|
||||
|
||||
/*
|
||||
* A token may come in either in an InputStream or as a
|
||||
* byte[]. Store a reference to it in either case and process
|
||||
* it's data only later when getData() is called and
|
||||
* decryption/copying is needed to be done. Note that JCE can
|
||||
* decrypt both from a byte[] and from an InputStream.
|
||||
*/
|
||||
private boolean readTokenFromInputStream = true;
|
||||
private InputStream is = null;
|
||||
private byte[] tokenBytes = null;
|
||||
private int tokenOffset = 0;
|
||||
private int tokenLen = 0;
|
||||
|
||||
/*
|
||||
* Application data may come from an InputStream or from a
|
||||
* byte[]. However, it will always be stored and processed as a
|
||||
* byte[] since
|
||||
* (a) the MessageDigest class only accepts a byte[] as input and
|
||||
* (b) It allows writing to an OuputStream via a CipherOutputStream.
|
||||
*/
|
||||
private byte[] dataBytes = null;
|
||||
private int dataOffset = 0;
|
||||
private int dataLen = 0;
|
||||
|
||||
// the len of the token data: (confounder || data || padding)
|
||||
private int dataSize = 0;
|
||||
|
||||
// Accessed by CipherHelper
|
||||
byte[] confounder = null;
|
||||
byte[] padding = null;
|
||||
|
||||
private boolean privacy = false;
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes obtained from the
|
||||
* peer.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param tokenBytes the bytes of the token
|
||||
* @param tokenOffset the offset of the token
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective
|
||||
*/
|
||||
public WrapToken(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
|
||||
this.readTokenFromInputStream = false;
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.tokenBytes = tokenBytes;
|
||||
this.tokenOffset = tokenOffset;
|
||||
this.tokenLen = tokenLen;
|
||||
this.privacy = prop.getPrivacy();
|
||||
dataSize =
|
||||
getGSSHeader().getMechTokenLength() - getKrb5TokenSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes read on the fly from
|
||||
* an InputStream.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param is the InputStream containing the token bytes
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective or if there is
|
||||
* a problem reading from the InputStream
|
||||
*/
|
||||
public WrapToken(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
|
||||
// Just parse the MessageToken part first
|
||||
super(Krb5Token.WRAP_ID, context, is, prop);
|
||||
|
||||
// Will need the token bytes again when extracting data
|
||||
this.is = is;
|
||||
this.privacy = prop.getPrivacy();
|
||||
/*
|
||||
debug("WrapToken Cons: gssHeader.getMechTokenLength=" +
|
||||
getGSSHeader().getMechTokenLength());
|
||||
debug("\n token size="
|
||||
+ getTokenSize());
|
||||
*/
|
||||
|
||||
dataSize =
|
||||
getGSSHeader().getMechTokenLength() - getTokenSize();
|
||||
// debug("\n dataSize=" + dataSize);
|
||||
// debug("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken.
|
||||
* @return a byte array containing the application data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public byte[] getData() throws GSSException {
|
||||
|
||||
byte[] temp = new byte[dataSize];
|
||||
getData(temp, 0);
|
||||
|
||||
// Remove the confounder and the padding
|
||||
byte[] retVal = new byte[dataSize - confounder.length -
|
||||
padding.length];
|
||||
System.arraycopy(temp, 0, retVal, 0, retVal.length);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken, writing it into an application provided output
|
||||
* array.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @return the size of the data written
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public int getData(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
if (readTokenFromInputStream)
|
||||
getDataFromStream(dataBuf, dataBufOffset);
|
||||
else
|
||||
getDataFromBuffer(dataBuf, dataBufOffset);
|
||||
|
||||
return (dataSize - confounder.length - padding.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with a byte array as input.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
private void getDataFromBuffer(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
GSSHeader gssHeader = getGSSHeader();
|
||||
int dataPos = tokenOffset +
|
||||
gssHeader.getLength() + getTokenSize();
|
||||
|
||||
if (dataPos + dataSize > tokenOffset + tokenLen)
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Insufficient data in "
|
||||
+ getTokenName(getTokenId()));
|
||||
|
||||
// debug("WrapToken cons: data is token is [" +
|
||||
// getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n");
|
||||
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
|
||||
if (privacy) {
|
||||
cipherHelper.decryptData(this,
|
||||
tokenBytes, dataPos, dataSize, dataBuf, dataBufOffset);
|
||||
/*
|
||||
debug("\t\tDecrypted data is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE - padding.length) +
|
||||
getHexBytes(padding) +
|
||||
"]\n");
|
||||
*/
|
||||
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
System.arraycopy(tokenBytes, dataPos,
|
||||
confounder, 0, CONFOUNDER_SIZE);
|
||||
int padSize = tokenBytes[dataPos + dataSize - 1];
|
||||
if (padSize < 0)
|
||||
padSize = 0;
|
||||
if (padSize > 8)
|
||||
padSize %= 8;
|
||||
|
||||
padding = pads[padSize];
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
|
||||
System.arraycopy(tokenBytes, dataPos + CONFOUNDER_SIZE,
|
||||
dataBuf, dataBufOffset, dataSize -
|
||||
CONFOUNDER_SIZE - padSize);
|
||||
|
||||
// byte[] debugbuf = new byte[dataSize - CONFOUNDER_SIZE - padSize];
|
||||
// System.arraycopy(tokenBytes, dataPos + CONFOUNDER_SIZE,
|
||||
// debugbuf, 0, debugbuf.length);
|
||||
// debug("\t\tData is: " + getHexBytes(debugbuf, debugbuf.length));
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure sign and sequence number are not corrupt
|
||||
*/
|
||||
|
||||
if (!verifySignAndSeqNumber(confounder,
|
||||
dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE
|
||||
- padding.length,
|
||||
padding))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in Wrap token");
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to obtain the application data transmitted in
|
||||
* this WrapToken. It is called if the WrapToken was constructed
|
||||
* with an Inputstream.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
private void getDataFromStream(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
GSSHeader gssHeader = getGSSHeader();
|
||||
|
||||
// Don't check the token length. Data will be read on demand from
|
||||
// the InputStream.
|
||||
|
||||
// debug("WrapToken cons: data will be read from InputStream.\n");
|
||||
|
||||
confounder = new byte[CONFOUNDER_SIZE];
|
||||
|
||||
try {
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
|
||||
if (privacy) {
|
||||
cipherHelper.decryptData(this, is, dataSize,
|
||||
dataBuf, dataBufOffset);
|
||||
|
||||
// debug("\t\tDecrypted data is [" +
|
||||
// getHexBytes(confounder) + " " +
|
||||
// getHexBytes(dataBuf, dataBufOffset,
|
||||
// dataSize - CONFOUNDER_SIZE - padding.length) +
|
||||
// getHexBytes(padding) +
|
||||
// "]\n");
|
||||
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
readFully(is, confounder);
|
||||
|
||||
if (cipherHelper.isArcFour()) {
|
||||
padding = pads[1];
|
||||
readFully(is, dataBuf, dataBufOffset, dataSize-CONFOUNDER_SIZE-1);
|
||||
} else {
|
||||
// Data is always a multiple of 8 with this GSS Mech
|
||||
// Copy all but last block as they are
|
||||
int numBlocks = (dataSize - CONFOUNDER_SIZE)/8 - 1;
|
||||
int offset = dataBufOffset;
|
||||
for (int i = 0; i < numBlocks; i++) {
|
||||
readFully(is, dataBuf, offset, 8);
|
||||
offset += 8;
|
||||
}
|
||||
|
||||
byte[] finalBlock = new byte[8];
|
||||
readFully(is, finalBlock);
|
||||
|
||||
int padSize = finalBlock[7];
|
||||
padding = pads[padSize];
|
||||
|
||||
// debug("\t\tPadding applied was: " + padSize + "\n");
|
||||
System.arraycopy(finalBlock, 0, dataBuf, offset,
|
||||
finalBlock.length - padSize);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
getTokenName(getTokenId())
|
||||
+ ": " + e.getMessage());
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure sign and sequence number are not corrupt
|
||||
*/
|
||||
|
||||
if (!verifySignAndSeqNumber(confounder,
|
||||
dataBuf, dataBufOffset,
|
||||
dataSize - CONFOUNDER_SIZE
|
||||
- padding.length,
|
||||
padding))
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum or sequence number in Wrap token");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper routine to pick the right padding for a certain length
|
||||
* of application data. Every application message has some
|
||||
* padding between 1 and 8 bytes.
|
||||
* @param len the length of the application data
|
||||
* @return the padding to be applied
|
||||
*/
|
||||
private byte[] getPadding(int len) {
|
||||
int padSize = 0;
|
||||
// For RC4-HMAC, all padding is rounded up to 1 byte.
|
||||
// One byte is needed to say that there is 1 byte of padding.
|
||||
if (cipherHelper.isArcFour()) {
|
||||
padSize = 1;
|
||||
} else {
|
||||
padSize = len % 8;
|
||||
padSize = 8 - padSize;
|
||||
}
|
||||
return pads[padSize];
|
||||
}
|
||||
|
||||
public WrapToken(Krb5Context context, MessageProp prop,
|
||||
byte[] dataBytes, int dataOffset, int dataLen)
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID, context);
|
||||
|
||||
confounder = Confounder.bytes(CONFOUNDER_SIZE);
|
||||
|
||||
padding = getPadding(dataLen);
|
||||
dataSize = confounder.length + dataLen + padding.length;
|
||||
this.dataBytes = dataBytes;
|
||||
this.dataOffset = dataOffset;
|
||||
this.dataLen = dataLen;
|
||||
|
||||
/*
|
||||
debug("\nWrapToken cons: data to wrap is [" +
|
||||
getHexBytes(confounder) + " " +
|
||||
getHexBytes(dataBytes, dataOffset, dataLen) + " " +
|
||||
// padding is never null for Wrap
|
||||
getHexBytes(padding) + "]\n");
|
||||
*/
|
||||
|
||||
genSignAndSeqNumber(prop,
|
||||
confounder,
|
||||
dataBytes, dataOffset, dataLen,
|
||||
padding);
|
||||
|
||||
/*
|
||||
* If the application decides to ask for privacy when the context
|
||||
* did not negotiate for it, do not provide it. The peer might not
|
||||
* have support for it. The app will realize this with a call to
|
||||
* pop.getPrivacy() after wrap().
|
||||
*/
|
||||
if (!context.getConfState())
|
||||
prop.setPrivacy(false);
|
||||
|
||||
privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException, GSSException {
|
||||
|
||||
super.encode(os);
|
||||
|
||||
// debug("Writing data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// debug(getHexBytes(confounder, confounder.length));
|
||||
os.write(confounder);
|
||||
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
os.write(dataBytes, dataOffset, dataLen);
|
||||
|
||||
// debug(" " + getHexBytes(padding, padding.length));
|
||||
os.write(padding);
|
||||
|
||||
} else {
|
||||
|
||||
cipherHelper.encryptData(this, confounder,
|
||||
dataBytes, dataOffset, dataLen, padding, os);
|
||||
}
|
||||
// debug("]\n");
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException, GSSException {
|
||||
// XXX Fine tune this initial size
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(dataSize + 50);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset)
|
||||
throws IOException, GSSException {
|
||||
|
||||
// Token header is small
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
super.encode(bos);
|
||||
byte[] header = bos.toByteArray();
|
||||
System.arraycopy(header, 0, outToken, offset, header.length);
|
||||
offset += header.length;
|
||||
|
||||
// debug("WrapToken.encode: Writing data: [");
|
||||
if (!privacy) {
|
||||
|
||||
// debug(getHexBytes(confounder, confounder.length));
|
||||
System.arraycopy(confounder, 0, outToken, offset,
|
||||
confounder.length);
|
||||
offset += confounder.length;
|
||||
|
||||
// debug(" " + getHexBytes(dataBytes, dataOffset, dataLen));
|
||||
System.arraycopy(dataBytes, dataOffset, outToken, offset,
|
||||
dataLen);
|
||||
offset += dataLen;
|
||||
|
||||
// debug(" " + getHexBytes(padding, padding.length));
|
||||
System.arraycopy(padding, 0, outToken, offset, padding.length);
|
||||
|
||||
} else {
|
||||
|
||||
cipherHelper.encryptData(this, confounder, dataBytes,
|
||||
dataOffset, dataLen, padding, outToken, offset);
|
||||
|
||||
// debug(getHexBytes(outToken, offset, dataSize));
|
||||
}
|
||||
|
||||
// debug("]\n");
|
||||
|
||||
// %%% assume that plaintext length == ciphertext len
|
||||
return (header.length + confounder.length + dataLen + padding.length);
|
||||
|
||||
}
|
||||
|
||||
protected int getKrb5TokenSize() throws GSSException {
|
||||
return (getTokenSize() + dataSize);
|
||||
}
|
||||
|
||||
protected int getSealAlg(boolean conf, int qop) throws GSSException {
|
||||
if (!conf) {
|
||||
return SEAL_ALG_NONE;
|
||||
}
|
||||
|
||||
// ignore QOP
|
||||
return cipherHelper.getSealAlg();
|
||||
}
|
||||
|
||||
// This implementation is way too conservative. And it certainly
|
||||
// doesn't return the maximum limit.
|
||||
static int getSizeLimit(int qop, boolean confReq, int maxTokenSize,
|
||||
CipherHelper ch) throws GSSException {
|
||||
return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) -
|
||||
(getTokenSize(ch) + CONFOUNDER_SIZE) - 8); /* safety */
|
||||
}
|
||||
|
||||
}
|
||||
231
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken_v2.java
Normal file
231
jdkSrc/jdk8/sun/security/jgss/krb5/WrapToken_v2.java
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2010, 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.krb5;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
import sun.security.krb5.Confounder;
|
||||
|
||||
/**
|
||||
* This class represents the new format of GSS tokens, as specified in RFC
|
||||
* 4121, emitted by the GSSContext.wrap() call. It is a MessageToken except
|
||||
* that it also contains plaintext or encrypted data at the end. A WrapToken
|
||||
* has certain other rules that are peculiar to it and different from a
|
||||
* MICToken, which is another type of MessageToken. All data in a WrapToken is
|
||||
* prepended by a random confounder of 16 bytes. Thus, all application data
|
||||
* is replaced by (confounder || data || tokenHeader || checksum).
|
||||
*
|
||||
* @author Seema Malkani
|
||||
*/
|
||||
class WrapToken_v2 extends MessageToken_v2 {
|
||||
|
||||
// Accessed by CipherHelper
|
||||
byte[] confounder = null;
|
||||
|
||||
private final boolean privacy;
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes obtained from the
|
||||
* peer.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param tokenBytes the bytes of the token
|
||||
* @param tokenOffset the offset of the token
|
||||
* @param tokenLen the length of the token
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective
|
||||
*/
|
||||
public WrapToken_v2(Krb5Context context,
|
||||
byte[] tokenBytes, int tokenOffset, int tokenLen,
|
||||
MessageProp prop) throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID_v2, context,
|
||||
tokenBytes, tokenOffset, tokenLen, prop);
|
||||
this.privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a WrapToken from token bytes read on the fly from
|
||||
* an InputStream.
|
||||
* @param context the mechanism context associated with this
|
||||
* token
|
||||
* @param is the InputStream containing the token bytes
|
||||
* @param prop the MessageProp into which characteristics of the
|
||||
* parsed token will be stored.
|
||||
* @throws GSSException if the token is defective or if there is
|
||||
* a problem reading from the InputStream
|
||||
*/
|
||||
public WrapToken_v2(Krb5Context context,
|
||||
InputStream is, MessageProp prop)
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID_v2, context, is, prop);
|
||||
this.privacy = prop.getPrivacy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken.
|
||||
* @return a byte array containing the application data
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public byte[] getData() throws GSSException {
|
||||
|
||||
byte[] temp = new byte[tokenDataLen];
|
||||
int len = getData(temp, 0);
|
||||
return Arrays.copyOf(temp, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the application data that was transmitted in this
|
||||
* WrapToken, writing it into an application provided output
|
||||
* array.
|
||||
* @param dataBuf the output buffer into which the data must be
|
||||
* written
|
||||
* @param dataBufOffset the offset at which to write the data
|
||||
* @return the size of the data written
|
||||
* @throws GSSException if an error occurs while decrypting any
|
||||
* cipher text and checking for validity
|
||||
*/
|
||||
public int getData(byte[] dataBuf, int dataBufOffset)
|
||||
throws GSSException {
|
||||
|
||||
// debug("WrapToken cons: data is token is [" +
|
||||
// getHexBytes(tokenBytes, tokenOffset, tokenLen) + "]\n");
|
||||
|
||||
// Do decryption if this token was privacy protected.
|
||||
if (privacy) {
|
||||
|
||||
// decrypt data
|
||||
cipherHelper.decryptData(this, tokenData, 0, tokenDataLen,
|
||||
dataBuf, dataBufOffset, getKeyUsage());
|
||||
|
||||
return tokenDataLen - CONFOUNDER_SIZE -
|
||||
TOKEN_HEADER_SIZE - cipherHelper.getChecksumLength();
|
||||
} else {
|
||||
|
||||
// Token data is in cleartext
|
||||
// debug("\t\tNo encryption was performed by peer.\n");
|
||||
|
||||
// data
|
||||
int data_length = tokenDataLen - cipherHelper.getChecksumLength();
|
||||
System.arraycopy(tokenData, 0,
|
||||
dataBuf, dataBufOffset,
|
||||
data_length);
|
||||
// debug("\t\tData is: " + getHexBytes(dataBuf, data_length));
|
||||
|
||||
/*
|
||||
* Make sure checksum is not corrupt
|
||||
*/
|
||||
if (!verifySign(dataBuf, dataBufOffset, data_length)) {
|
||||
throw new GSSException(GSSException.BAD_MIC, -1,
|
||||
"Corrupt checksum in Wrap token");
|
||||
}
|
||||
return data_length;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a WrapToken_v2 object
|
||||
*/
|
||||
public WrapToken_v2(Krb5Context context, MessageProp prop,
|
||||
byte[] dataBytes, int dataOffset, int dataLen)
|
||||
throws GSSException {
|
||||
|
||||
super(Krb5Token.WRAP_ID_v2, context);
|
||||
|
||||
confounder = Confounder.bytes(CONFOUNDER_SIZE);
|
||||
|
||||
// debug("\nWrapToken cons: data to wrap is [" +
|
||||
// getHexBytes(confounder) + " " +
|
||||
// getHexBytes(dataBytes, dataOffset, dataLen) + "]\n");
|
||||
|
||||
genSignAndSeqNumber(prop, dataBytes, dataOffset, dataLen);
|
||||
|
||||
/*
|
||||
* If the application decides to ask for privacy when the context
|
||||
* did not negotiate for it, do not provide it. The peer might not
|
||||
* have support for it. The app will realize this with a call to
|
||||
* pop.getPrivacy() after wrap().
|
||||
*/
|
||||
if (!context.getConfState())
|
||||
prop.setPrivacy(false);
|
||||
|
||||
privacy = prop.getPrivacy();
|
||||
|
||||
if (!privacy) {
|
||||
// Wrap Tokens (without confidentiality) =
|
||||
// { 16 byte token_header | plaintext | 12-byte HMAC }
|
||||
// where HMAC is on { plaintext | token_header }
|
||||
|
||||
tokenData = new byte[dataLen + checksum.length];
|
||||
System.arraycopy(dataBytes, dataOffset, tokenData, 0, dataLen);
|
||||
System.arraycopy(checksum, 0, tokenData, dataLen, checksum.length);
|
||||
} else {
|
||||
// Wrap Tokens (with confidentiality) =
|
||||
// { 16 byte token_header |
|
||||
// Encrypt(16-byte confounder | plaintext | token_header) |
|
||||
// 12-byte HMAC }
|
||||
|
||||
tokenData = cipherHelper.encryptData(this, confounder, getTokenHeader(),
|
||||
dataBytes, dataOffset, dataLen, getKeyUsage());
|
||||
}
|
||||
}
|
||||
|
||||
public void encode(OutputStream os) throws IOException {
|
||||
encodeHeader(os);
|
||||
os.write(tokenData);
|
||||
}
|
||||
|
||||
public byte[] encode() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream(
|
||||
MessageToken_v2.TOKEN_HEADER_SIZE + tokenData.length);
|
||||
encode(bos);
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
public int encode(byte[] outToken, int offset) throws IOException {
|
||||
byte[] token = encode();
|
||||
System.arraycopy(token, 0, outToken, offset, token.length);
|
||||
return token.length;
|
||||
}
|
||||
|
||||
// This implementation is way to conservative. And it certainly
|
||||
// doesn't return the maximum limit.
|
||||
static int getSizeLimit(int qop, boolean confReq, int maxTokenSize,
|
||||
CipherHelper ch) throws GSSException {
|
||||
return (GSSHeader.getMaxMechTokenSize(OID, maxTokenSize) -
|
||||
(TOKEN_HEADER_SIZE + ch.getChecksumLength() + CONFOUNDER_SIZE)
|
||||
- 8 /* safety */);
|
||||
}
|
||||
}
|
||||
408
jdkSrc/jdk8/sun/security/jgss/spi/GSSContextSpi.java
Normal file
408
jdkSrc/jdk8/sun/security/jgss/spi/GSSContextSpi.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* (C) Copyright IBM Corp. 1999 All Rights Reserved.
|
||||
* Copyright 1997 The Open Group Research Institute. All rights reserved.
|
||||
*/
|
||||
package sun.security.jgss.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.Provider;
|
||||
import com.sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* This interface is implemented by a mechanism specific instance of a GSS
|
||||
* security context.
|
||||
* A GSSContextSpi object can be thought of having 3 states:
|
||||
* -before initialization
|
||||
* -during initialization with its peer
|
||||
* -after it is established
|
||||
* <p>
|
||||
* The context options can only be requested in state 1. In state 3,
|
||||
* the per message operations are available to the callers. The get
|
||||
* methods for the context options will return the requested options
|
||||
* while in state 1 and 2, and the established values in state 3.
|
||||
* Some mechanisms may allow the access to the per-message operations
|
||||
* and the context flags before the context is fully established. The
|
||||
* isProtReady method is used to indicate that these services are
|
||||
* available.
|
||||
* <p>
|
||||
* <strong>
|
||||
* Context establishment tokens are defined in a mechanism independent
|
||||
* format in section 3.1 of RFC 2743. The GSS-Framework will add
|
||||
* and remove the mechanism independent header portion of this token format
|
||||
* depending on whether a token is received or is being sent. The mechanism
|
||||
* should only generate or expect to read the inner-context token portion.
|
||||
* <br>
|
||||
* On the other hands, tokens used for per-message calls are generated
|
||||
* entirely by the mechanism. It is possible that the mechanism chooses to
|
||||
* encase inner-level per-message tokens in a header similar to that used
|
||||
* for initial tokens, however, this is upto the mechanism to do. The token
|
||||
* to/from the per-message calls are opaque to the GSS-Framework.
|
||||
* </strong>
|
||||
* <p>
|
||||
* An attempt has been made to allow for reading the peer's tokens from an
|
||||
* InputStream and writing tokens for the peer to an OutputStream. This
|
||||
* allows applications to pass in streams that are obtained from their network
|
||||
* connections and thus minimize the buffer copies that will happen. This
|
||||
* is especially important for tokens generated by wrap() which are
|
||||
* proportional in size to the length of the application data being
|
||||
* wrapped, and are probably also the most frequently used type of tokens.
|
||||
* <p>
|
||||
* It is anticipated that most applications will want to use wrap() in a
|
||||
* fashion where they obtain the application bytes to wrap from a byte[]
|
||||
* but want to output the wrap token straight to an
|
||||
* OutputStream. Similarly, they will want to use unwrap() where they read
|
||||
* the token directly form an InputStream but output it to some byte[] for
|
||||
* the application to process. Unfortunately the high level GSS bindings
|
||||
* do not contain overloaded forms of wrap() and unwrap() that do just
|
||||
* this, however we have accomodated those cases here with the expectation
|
||||
* that this will be rolled into the high level bindings sooner or later.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public interface GSSContextSpi {
|
||||
|
||||
public Provider getProvider();
|
||||
|
||||
// The specification for the following methods mirrors the
|
||||
// specification of the same methods in the GSSContext interface, as
|
||||
// defined in RFC 2853.
|
||||
|
||||
public void requestLifetime(int lifetime) throws GSSException;
|
||||
|
||||
public void requestMutualAuth(boolean state) throws GSSException;
|
||||
|
||||
public void requestReplayDet(boolean state) throws GSSException;
|
||||
|
||||
public void requestSequenceDet(boolean state) throws GSSException;
|
||||
|
||||
public void requestCredDeleg(boolean state) throws GSSException;
|
||||
|
||||
public void requestAnonymity(boolean state) throws GSSException;
|
||||
|
||||
public void requestConf(boolean state) throws GSSException;
|
||||
|
||||
public void requestInteg(boolean state) throws GSSException;
|
||||
|
||||
public void requestDelegPolicy(boolean state) throws GSSException;
|
||||
|
||||
public void setChannelBinding(ChannelBinding cb) throws GSSException;
|
||||
|
||||
public boolean getCredDelegState();
|
||||
|
||||
public boolean getMutualAuthState();
|
||||
|
||||
public boolean getReplayDetState();
|
||||
|
||||
public boolean getSequenceDetState();
|
||||
|
||||
public boolean getAnonymityState();
|
||||
|
||||
public boolean getDelegPolicyState();
|
||||
|
||||
public boolean isTransferable() throws GSSException;
|
||||
|
||||
public boolean isProtReady();
|
||||
|
||||
public boolean isInitiator();
|
||||
|
||||
public boolean getConfState();
|
||||
|
||||
public boolean getIntegState();
|
||||
|
||||
public int getLifetime();
|
||||
|
||||
public boolean isEstablished();
|
||||
|
||||
public GSSNameSpi getSrcName() throws GSSException;
|
||||
|
||||
public GSSNameSpi getTargName() throws GSSException;
|
||||
|
||||
public Oid getMech() throws GSSException;
|
||||
|
||||
public GSSCredentialSpi getDelegCred() throws GSSException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* This method is called by the GSS-Framework when the application
|
||||
* calls the initSecContext method on the GSSContext implementation
|
||||
* that it has a reference to.
|
||||
* <p>
|
||||
* All overloaded forms of GSSContext.initSecContext() can be handled
|
||||
* with this mechanism level initSecContext. Since the output token
|
||||
* from this method is a fixed size, not exeedingly large, and a one
|
||||
* time deal, an overloaded form that takes an OutputStream has not
|
||||
* been defined. The GSS-Framwork can write the returned byte[] to any
|
||||
* application provided OutputStream. Similarly, any application input
|
||||
* int he form of byte arrays will be wrapped in an input stream by the
|
||||
* GSS-Framework and then passed here.
|
||||
* <p>
|
||||
* <strong>
|
||||
* The GSS-Framework will strip off the leading mechanism independent
|
||||
* GSS-API header. In other words, only the mechanism specific
|
||||
* inner-context token of RFC 2743 section 3.1 will be available on the
|
||||
* InputStream.
|
||||
* </strong>
|
||||
*
|
||||
* @param is contains the inner context token portion of the GSS token
|
||||
* received from the peer. On the first call to initSecContext, there
|
||||
* will be no token hence it will be ignored.
|
||||
* @param mechTokenSize the size of the inner context token as read by
|
||||
* the GSS-Framework from the mechanism independent GSS-API level
|
||||
* header.
|
||||
* @return any inner-context token required to be sent to the peer as
|
||||
* part of a GSS token. The mechanism should not add the mechanism
|
||||
* independent part of the token. The GSS-Framework will add that on
|
||||
* the way out.
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public byte[] initSecContext(InputStream is, int mechTokenSize)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* This method is called by the GSS-Framework when the application
|
||||
* calls the acceptSecContext method on the GSSContext implementation
|
||||
* that it has a reference to.
|
||||
* <p>
|
||||
* All overloaded forms of GSSContext.acceptSecContext() can be handled
|
||||
* with this mechanism level acceptSecContext. Since the output token
|
||||
* from this method is a fixed size, not exeedingly large, and a one
|
||||
* time deal, an overloaded form that takes an OutputStream has not
|
||||
* been defined. The GSS-Framwork can write the returned byte[] to any
|
||||
* application provided OutputStream. Similarly, any application input
|
||||
* int he form of byte arrays will be wrapped in an input stream by the
|
||||
* GSS-Framework and then passed here.
|
||||
* <p>
|
||||
* <strong>
|
||||
* The GSS-Framework will strip off the leading mechanism independent
|
||||
* GSS-API header. In other words, only the mechanism specific
|
||||
* inner-context token of RFC 2743 section 3.1 will be available on the
|
||||
* InputStream.
|
||||
* </strong>
|
||||
*
|
||||
* @param is contains the inner context token portion of the GSS token
|
||||
* received from the peer.
|
||||
* @param mechTokenSize the size of the inner context token as read by
|
||||
* the GSS-Framework from the mechanism independent GSS-API level
|
||||
* header.
|
||||
* @return any inner-context token required to be sent to the peer as
|
||||
* part of a GSS token. The mechanism should not add the mechanism
|
||||
* independent part of the token. The GSS-Framework will add that on
|
||||
* the way out.
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public byte[] acceptSecContext(InputStream is, int mechTokenSize)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Queries the context for largest data size to accommodate
|
||||
* the specified protection and for the token to remain less then
|
||||
* maxTokSize.
|
||||
*
|
||||
* @param qop the quality of protection that the context will be
|
||||
* asked to provide.
|
||||
* @param confReq a flag indicating whether confidentiality will be
|
||||
* requested or not
|
||||
* @param maxTokSize the maximum size of the output token
|
||||
* @return the maximum size for the input message that can be
|
||||
* provided to the wrap() method in order to guarantee that these
|
||||
* requirements are met.
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getWrapSizeLimit(int qop, boolean confReq, int maxTokSize)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Provides per-message token encapsulation.
|
||||
*
|
||||
* @param is the user-provided message to be protected
|
||||
* @param os the token to be sent to the peer. It includes
|
||||
* the message from <i>is</i> with the requested protection.
|
||||
* @param msgProp on input it contains the requested qop and
|
||||
* confidentiality state, on output, the applied values
|
||||
* @exception GSSException may be thrown
|
||||
* @see unwrap
|
||||
*/
|
||||
public void wrap(InputStream is, OutputStream os, MessageProp msgProp)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that want simplicity and don't care about buffer copies.
|
||||
*/
|
||||
public byte[] wrap(byte inBuf[], int offset, int len,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that care about buffer copies but either cannot use streams
|
||||
* or want to avoid them for whatever reason. (Say, they are using
|
||||
* block ciphers.)
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public int wrap(byte inBuf[], int inOffset, int len,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* For apps that want to read from a specific application provided
|
||||
* buffer but want to write directly to the network stream.
|
||||
*/
|
||||
/*
|
||||
* Can be achieved by converting the input buffer to a
|
||||
* ByteInputStream. Provided to keep the API consistent
|
||||
* with unwrap.
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public void wrap(byte inBuf[], int offset, int len,
|
||||
OutputStream os, MessageProp msgProp)
|
||||
throws GSSException;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Retrieves the message token previously encapsulated in the wrap
|
||||
* call.
|
||||
*
|
||||
* @param is the token from the peer
|
||||
* @param os unprotected message data
|
||||
* @param msgProp will contain the applied qop and confidentiality
|
||||
* of the input token and any informatory status values
|
||||
* @exception GSSException may be thrown
|
||||
* @see wrap
|
||||
*/
|
||||
public void unwrap(InputStream is, OutputStream os,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that want simplicity and don't care about buffer copies.
|
||||
*/
|
||||
public byte[] unwrap(byte inBuf[], int offset, int len,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* For apps that care about buffer copies but either cannot use streams
|
||||
* or want to avoid them for whatever reason. (Say, they are using
|
||||
* block ciphers.)
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public int unwrap(byte inBuf[], int inOffset, int len,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* For apps that care about buffer copies and want to read
|
||||
* straight from the network, but also want the output in a specific
|
||||
* application provided buffer, say to reduce buffer allocation or
|
||||
* subsequent copy.
|
||||
*
|
||||
* NOTE: This method is not defined in public class org.ietf.jgss.GSSContext
|
||||
*
|
||||
public int unwrap(InputStream is,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
*/
|
||||
|
||||
/**
|
||||
* Applies per-message integrity services.
|
||||
*
|
||||
* @param is the user-provided message
|
||||
* @param os the token to be sent to the peer along with the
|
||||
* message token. The message token <b>is not</b> encapsulated.
|
||||
* @param msgProp on input the desired QOP and output the applied QOP
|
||||
* @exception GSSException
|
||||
*/
|
||||
public void getMIC(InputStream is, OutputStream os,
|
||||
MessageProp msgProp)
|
||||
throws GSSException;
|
||||
|
||||
public byte[] getMIC(byte []inMsg, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* Checks the integrity of the supplied tokens.
|
||||
* This token was previously generated by getMIC.
|
||||
*
|
||||
* @param is token generated by getMIC
|
||||
* @param msgStr the message to check integrity for
|
||||
* @param mProp will contain the applied QOP and confidentiality
|
||||
* states of the token as well as any informatory status codes
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public void verifyMIC(InputStream is, InputStream msgStr,
|
||||
MessageProp mProp) throws GSSException;
|
||||
|
||||
public void verifyMIC(byte []inTok, int tokOffset, int tokLen,
|
||||
byte[] inMsg, int msgOffset, int msgLen,
|
||||
MessageProp msgProp) throws GSSException;
|
||||
|
||||
/**
|
||||
* Produces a token representing this context. After this call
|
||||
* the context will no longer be usable until an import is
|
||||
* performed on the returned token.
|
||||
*
|
||||
* @return exported context token
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public byte[] export() throws GSSException;
|
||||
|
||||
/**
|
||||
* Releases context resources and terminates the
|
||||
* context between 2 peer.
|
||||
*
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public void dispose() throws GSSException;
|
||||
|
||||
/**
|
||||
* Return the mechanism-specific attribute associated with (@code type}.
|
||||
*
|
||||
* @param type the type of the attribute requested
|
||||
* @return the attribute
|
||||
* @throws GSSException see {@link ExtendedGSSContext#inquireSecContext}
|
||||
* for details
|
||||
*/
|
||||
public Object inquireSecContext(InquireType type)
|
||||
throws GSSException;
|
||||
}
|
||||
108
jdkSrc/jdk8/sun/security/jgss/spi/GSSCredentialSpi.java
Normal file
108
jdkSrc/jdk8/sun/security/jgss/spi/GSSCredentialSpi.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, 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.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* This interface is implemented by a mechanism specific credential
|
||||
* element. A GSSCredential is conceptually a container class of several
|
||||
* credential elements from different mechanisms.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
public interface GSSCredentialSpi {
|
||||
|
||||
public Provider getProvider();
|
||||
|
||||
/**
|
||||
* Called to invalidate this credential element and release
|
||||
* any system recourses and cryptographic information owned
|
||||
* by the credential.
|
||||
*
|
||||
* @exception GSSException with major codes NO_CRED and FAILURE
|
||||
*/
|
||||
public void dispose() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the principal name for this credential. The name
|
||||
* is in mechanism specific format.
|
||||
*
|
||||
* @return GSSNameSpi representing principal name of this credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public GSSNameSpi getName() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the init lifetime remaining.
|
||||
*
|
||||
* @return the init lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getInitLifetime() throws GSSException;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the accept lifetime remaining.
|
||||
*
|
||||
* @return the accept lifetime remaining in seconds
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public int getAcceptLifetime() throws GSSException;
|
||||
|
||||
/**
|
||||
* Determines if this credential element can be used by a context
|
||||
* initiator.
|
||||
* @return true if it can be used for initiating contexts
|
||||
*/
|
||||
public boolean isInitiatorCredential() throws GSSException;
|
||||
|
||||
/**
|
||||
* Determines if this credential element can be used by a context
|
||||
* acceptor.
|
||||
* @return true if it can be used for accepting contexts
|
||||
*/
|
||||
public boolean isAcceptorCredential() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the oid representing the underlying credential
|
||||
* mechanism oid.
|
||||
*
|
||||
* @return the Oid for this credential mechanism
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public Oid getMechanism();
|
||||
|
||||
/**
|
||||
* Impersonates another client.
|
||||
*
|
||||
* @param name the client to impersonate
|
||||
* @return the new credential
|
||||
* @exception GSSException may be thrown
|
||||
*/
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException;
|
||||
}
|
||||
115
jdkSrc/jdk8/sun/security/jgss/spi/GSSNameSpi.java
Normal file
115
jdkSrc/jdk8/sun/security/jgss/spi/GSSNameSpi.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2005, 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.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* This interface is implemented by a mechanism specific name element. A
|
||||
* GSSName is conceptually a container class of several name elements from
|
||||
* different mechanisms.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public interface GSSNameSpi {
|
||||
|
||||
public Provider getProvider();
|
||||
|
||||
/**
|
||||
* Equals method for the GSSNameSpi objects.
|
||||
* If either name denotes an anonymous principal, the call should
|
||||
* return false.
|
||||
*
|
||||
* @param name to be compared with
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @exception GSSException with major codes of BAD_NAMETYPE,
|
||||
* BAD_NAME, FAILURE
|
||||
*/
|
||||
public boolean equals(GSSNameSpi name) throws GSSException;
|
||||
|
||||
/**
|
||||
* Compares this <code>GSSNameSpi</code> object to another Object
|
||||
* that might be a <code>GSSNameSpi</code>. The behaviour is exactly
|
||||
* the same as in {@link #equals(GSSNameSpi) equals} except that
|
||||
* no GSSException is thrown; instead, false will be returned in the
|
||||
* situation where an error occurs.
|
||||
*
|
||||
* @param another the object to be compared to
|
||||
* @return true if they both refer to the same entity, else false
|
||||
* @see #equals(GSSNameSpi)
|
||||
*/
|
||||
public boolean equals(Object another);
|
||||
|
||||
/**
|
||||
* Returns a hashcode value for this GSSNameSpi.
|
||||
*
|
||||
* @return a hashCode value
|
||||
*/
|
||||
public int hashCode();
|
||||
|
||||
/**
|
||||
* Returns a flat name representation for this object. The name
|
||||
* format is defined in RFC 2078.
|
||||
*
|
||||
* @return the flat name representation for this object
|
||||
* @exception GSSException with major codes NAME_NOT_MN, BAD_NAME,
|
||||
* BAD_NAME, FAILURE.
|
||||
*/
|
||||
public byte[] export() throws GSSException;
|
||||
|
||||
|
||||
/**
|
||||
* Get the mechanism type that this NameElement corresponds to.
|
||||
*
|
||||
* @return the Oid of the mechanism type
|
||||
*/
|
||||
public Oid getMechanism();
|
||||
|
||||
/**
|
||||
* Returns a string representation for this name. The printed
|
||||
* name type can be obtained by calling getStringNameType().
|
||||
*
|
||||
* @return string form of this name
|
||||
* @see #getStringNameType()
|
||||
* @overrides Object#toString
|
||||
*/
|
||||
public String toString();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the oid describing the format of the printable name.
|
||||
*
|
||||
* @return the Oid for the format of the printed name
|
||||
*/
|
||||
public Oid getStringNameType();
|
||||
|
||||
/**
|
||||
* Indicates if this name object represents an Anonymous name.
|
||||
*/
|
||||
public boolean isAnonymousName();
|
||||
}
|
||||
214
jdkSrc/jdk8/sun/security/jgss/spi/MechanismFactory.java
Normal file
214
jdkSrc/jdk8/sun/security/jgss/spi/MechanismFactory.java
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, 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.spi;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
|
||||
/**
|
||||
* This interface is implemented by the factory class for every
|
||||
* plugin mechanism. The GSSManager locates an implementation of this
|
||||
* interface by querying the security providers installed on the
|
||||
* system. For a provider to support a mechanism defined by Oid x.y.z,
|
||||
* the provider master file would have to contain a mapping from the
|
||||
* property "GssApiMechanism.x.y.z" to an implementation class that serves
|
||||
* as the factory for that mechanism.
|
||||
* <p>
|
||||
* e.g., If a provider master file contained the a mapping from the
|
||||
* property "GssApiMechanism.1.2.840.113554.1.2.2" to the class name
|
||||
* "com.foo.krb5.Krb5GssFactory", then the GSS-API framework would assume
|
||||
* that com.foo.krb5.Krb5GssFactory implements the MechanismFactory
|
||||
* interface and that it can be used to obtain elements required by for
|
||||
* supporting this mechanism.
|
||||
*
|
||||
* @author Mayank Upadhyay
|
||||
*/
|
||||
|
||||
public interface MechanismFactory {
|
||||
|
||||
/**
|
||||
* Returns the Oid of the mechanism that this factory supports.
|
||||
* @return the Oid
|
||||
*/
|
||||
public Oid getMechanismOid();
|
||||
|
||||
/**
|
||||
* Returns the provider that this factory came from.
|
||||
* @return the provider
|
||||
*/
|
||||
public Provider getProvider();
|
||||
|
||||
/**
|
||||
* Returns the GSS-API nametypes that this mechanism can
|
||||
* support. Having this method helps the GSS-Framework decide quickly
|
||||
* if a certain mechanism can be skipped when importing a name.
|
||||
* @return an array of the Oid's corresponding to the different GSS-API
|
||||
* nametypes supported
|
||||
* @see org.ietf.jgss.GSSName
|
||||
*/
|
||||
public Oid[] getNameTypes() throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a credential element for this mechanism to be included as
|
||||
* part of a GSSCredential implementation. A GSSCredential is
|
||||
* conceptually a container class of several credential elements from
|
||||
* different mechanisms. A GSS-API credential can be used either for
|
||||
* initiating GSS security contexts or for accepting them. This method
|
||||
* also accepts parameters that indicate what usage is expected and how
|
||||
* long the life of the credential should be. It is not necessary that
|
||||
* the mechanism honor the request for lifetime. An application will
|
||||
* always query an acquired GSSCredential to determine what lifetime it
|
||||
* got back.<p>
|
||||
*
|
||||
* <b>Not all mechanisms support the concept of one credential element
|
||||
* that can be used for both initiating and accepting a context. In the
|
||||
* event that an application requests usage INITIATE_AND_ACCEPT for a
|
||||
* credential from such a mechanism, the GSS framework will need to
|
||||
* obtain two different credential elements from the mechanism, one
|
||||
* that will have usage INITIATE_ONLY and another that will have usage
|
||||
* ACCEPT_ONLY. The mechanism will help the GSS-API realize this by
|
||||
* returning a credential element with usage INITIATE_ONLY or
|
||||
* ACCEPT_ONLY prompting it to make another call to
|
||||
* getCredentialElement, this time with the other usage mode. The
|
||||
* mechanism indicates the missing mode by returning a 0 lifetime for
|
||||
* it.</b>
|
||||
*
|
||||
* @param name the mechanism level name element for the entity whose
|
||||
* credential is desired. A null value indicates that a mechanism
|
||||
* dependent default choice is to be made.
|
||||
* @param initLifetime indicates the lifetime (in seconds) that is
|
||||
* requested for this credential to be used at the context initiator's
|
||||
* end. This value should be ignored if the usage is
|
||||
* ACCEPT_ONLY. Predefined contants are available in the
|
||||
* org.ietf.jgss.GSSCredential interface.
|
||||
* @param acceptLifetime indicates the lifetime (in seconds) that is
|
||||
* requested for this credential to be used at the context acceptor's
|
||||
* end. This value should be ignored if the usage is
|
||||
* INITIATE_ONLY. Predefined contants are available in the
|
||||
* org.ietf.jgss.GSSCredential interface.
|
||||
* @param usage One of the values GSSCredential.INIATE_ONLY,
|
||||
* GSSCredential.ACCEPT_ONLY, and GSSCredential.INITIATE_AND_ACCEPT.
|
||||
* @see org.ietf.jgss.GSSCredential
|
||||
* @throws GSSException if one of the error situations described in RFC
|
||||
* 2743 with the GSS_Acquire_Cred or GSS_Add_Cred calls occurs.
|
||||
*/
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime, int acceptLifetime, int usage) throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a name element for this mechanism to be included as part of
|
||||
* a GSSName implementation. A GSSName is conceptually a container
|
||||
* class of several name elements from different mechanisms. A GSSName
|
||||
* can be created either with a String or with a sequence of
|
||||
* bytes. This factory method accepts the name in a String. Such a name
|
||||
* can generally be assumed to be printable and may be returned from
|
||||
* the name element's toString() method.
|
||||
*
|
||||
* @param nameStr a string containing the characters describing this
|
||||
* entity to the mechanism
|
||||
* @param nameType an Oid serving as a clue as to how the mechanism should
|
||||
* interpret the nameStr
|
||||
* @throws GSSException if any of the errors described in RFC 2743 for
|
||||
* the GSS_Import_Name or GSS_Canonicalize_Name calls occur.
|
||||
*/
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* This is a variation of the factory method that accepts a String for
|
||||
* the characters that make up the name. Usually the String characters
|
||||
* are assumed to be printable. The bytes passed in to this method have
|
||||
* to be converted to characters using some encoding of the mechanism's
|
||||
* choice. It is recommended that UTF-8 be used. (Note that UTF-8
|
||||
* preserves the encoding for 7-bit ASCII characters.)
|
||||
* <p>
|
||||
* An exported name will generally be passed in using this method.
|
||||
*
|
||||
* @param name the bytes describing this entity to the mechanism
|
||||
* @param nameType an Oid serving as a clue as to how the mechanism should
|
||||
* interpret the nameStr
|
||||
* @throws GSSException if any of the errors described in RFC 2743 for
|
||||
* the GSS_Import_Name or GSS_Canonicalize_Name calls occur.
|
||||
*/
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a security context for this mechanism so that it can be used
|
||||
* on the context initiator's side.
|
||||
*
|
||||
* @param peer the name element from this mechanism that represents the
|
||||
* peer
|
||||
* @param myInitiatorCred a credential element for the context
|
||||
* initiator obtained previously from this mechanism. The identity of
|
||||
* the context initiator can be obtained from this credential. Passing
|
||||
* a value of null here indicates that a default entity of the
|
||||
* mechanism's choice should be assumed to be the context initiator and
|
||||
* that default credentials should be applied.
|
||||
* @param lifetime the requested lifetime (in seconds) for the security
|
||||
* context. Predefined contants are available in the
|
||||
* org.ietf.jgss.GSSContext interface.
|
||||
* @throws GSSException if any of the errors described in RFC 2743 in
|
||||
* the GSS_Init_Sec_Context call occur.
|
||||
*/
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred,
|
||||
int lifetime) throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a security context for this mechanism so thatit can be used
|
||||
* on the context acceptor's side.
|
||||
*
|
||||
* @param myAcceptorCred a credential element for the context acceptor
|
||||
* obtained previously from this mechanism. The identity of the context
|
||||
* acceptor cna be obtained from this credential. Passing a value of
|
||||
* null here indicates that tha default entity of the mechanism's
|
||||
* choice should be assumed to be the context acceptor and default
|
||||
* credentials should be applied.
|
||||
*
|
||||
* @throws GSSException if any of the errors described in RFC 2743 in
|
||||
* the GSS_Accept_Sec_Context call occur.
|
||||
*/
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
|
||||
throws GSSException;
|
||||
|
||||
/**
|
||||
* Creates a security context from a previously exported (serialized)
|
||||
* security context. Note that this is different from Java
|
||||
* serialization and is defined at a mechanism level to interoperate
|
||||
* over the wire with non-Java implementations. Either the initiator or
|
||||
* the acceptor can export and then import a security context.
|
||||
* Implementations of mechanism contexts are not required to implement
|
||||
* exporting and importing.
|
||||
*
|
||||
* @param exportedContext the bytes representing this security context
|
||||
* @throws GSSException is any of the errors described in RFC 2743 in
|
||||
* the GSS_Import_Sec_Context call occur.
|
||||
*/
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException;
|
||||
|
||||
}
|
||||
229
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenInit.java
Normal file
229
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenInit.java
Normal file
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, 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.util.*;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* Implements the SPNEGO NegTokenInit token
|
||||
* as specified in RFC 2478
|
||||
*
|
||||
* NegTokenInit ::= SEQUENCE {
|
||||
* mechTypes [0] MechTypeList OPTIONAL,
|
||||
* reqFlags [1] ContextFlags OPTIONAL,
|
||||
* mechToken [2] OCTET STRING OPTIONAL,
|
||||
* mechListMIC [3] OCTET STRING OPTIONAL
|
||||
* }
|
||||
*
|
||||
* MechTypeList ::= SEQUENCE OF MechType
|
||||
*
|
||||
* MechType::= OBJECT IDENTIFIER
|
||||
*
|
||||
* ContextFlags ::= BIT STRING {
|
||||
* delegFlag (0),
|
||||
* mutualFlag (1),
|
||||
* replayFlag (2),
|
||||
* sequenceFlag (3),
|
||||
* anonFlag (4),
|
||||
* confFlag (5),
|
||||
* integFlag (6)
|
||||
* }
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public class NegTokenInit extends SpNegoToken {
|
||||
|
||||
// DER-encoded mechTypes
|
||||
private byte[] mechTypes = null;
|
||||
private Oid[] mechTypeList = null;
|
||||
|
||||
private BitArray reqFlags = null;
|
||||
private byte[] mechToken = null;
|
||||
private byte[] mechListMIC = null;
|
||||
|
||||
NegTokenInit(byte[] mechTypes, BitArray flags,
|
||||
byte[] token, byte[] mechListMIC)
|
||||
{
|
||||
super(NEG_TOKEN_INIT_ID);
|
||||
this.mechTypes = mechTypes;
|
||||
this.reqFlags = flags;
|
||||
this.mechToken = token;
|
||||
this.mechListMIC = mechListMIC;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to parse SPNEGO tokens
|
||||
public NegTokenInit(byte[] in) throws GSSException {
|
||||
super(NEG_TOKEN_INIT_ID);
|
||||
parseToken(in);
|
||||
}
|
||||
|
||||
final byte[] encode() throws GSSException {
|
||||
try {
|
||||
// create negInitToken
|
||||
DerOutputStream initToken = new DerOutputStream();
|
||||
|
||||
// DER-encoded mechTypes with CONTEXT 00
|
||||
if (mechTypes != null) {
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x00), mechTypes);
|
||||
}
|
||||
|
||||
// write context flags with CONTEXT 01
|
||||
if (reqFlags != null) {
|
||||
DerOutputStream flags = new DerOutputStream();
|
||||
flags.putUnalignedBitString(reqFlags);
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x01), flags);
|
||||
}
|
||||
|
||||
// mechToken with CONTEXT 02
|
||||
if (mechToken != null) {
|
||||
DerOutputStream dataValue = new DerOutputStream();
|
||||
dataValue.putOctetString(mechToken);
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x02), dataValue);
|
||||
}
|
||||
|
||||
// mechListMIC with CONTEXT 03
|
||||
if (mechListMIC != null) {
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"sending MechListMIC");
|
||||
}
|
||||
DerOutputStream mic = new DerOutputStream();
|
||||
mic.putOctetString(mechListMIC);
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x03), mic);
|
||||
}
|
||||
|
||||
// insert in a SEQUENCE
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.write(DerValue.tag_Sequence, initToken);
|
||||
|
||||
return out.toByteArray();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenInit token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseToken(byte[] in) throws GSSException {
|
||||
try {
|
||||
DerValue der = new DerValue(in);
|
||||
// verify NegotiationToken type token
|
||||
if (!der.isContextSpecific((byte) NEG_TOKEN_INIT_ID)) {
|
||||
throw new IOException("SPNEGO NegoTokenInit : " +
|
||||
"did not have right token type");
|
||||
}
|
||||
DerValue tmp1 = der.data.getDerValue();
|
||||
if (tmp1.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("SPNEGO NegoTokenInit : " +
|
||||
"did not have the Sequence tag");
|
||||
}
|
||||
|
||||
// parse various fields if present
|
||||
int lastField = -1;
|
||||
while (tmp1.data.available() > 0) {
|
||||
DerValue tmp2 = tmp1.data.getDerValue();
|
||||
if (tmp2.isContextSpecific((byte)0x00)) {
|
||||
// get the DER-encoded sequence of mechTypes
|
||||
lastField = checkNextField(lastField, 0);
|
||||
DerInputStream mValue = tmp2.data;
|
||||
mechTypes = mValue.toByteArray();
|
||||
|
||||
// read all the mechTypes
|
||||
DerValue[] mList = mValue.getSequence(0);
|
||||
mechTypeList = new Oid[mList.length];
|
||||
ObjectIdentifier mech = null;
|
||||
for (int i = 0; i < mList.length; i++) {
|
||||
mech = mList[i].getOID();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"reading Mechanism Oid = " + mech);
|
||||
}
|
||||
mechTypeList[i] = new Oid(mech.toString());
|
||||
}
|
||||
} else if (tmp2.isContextSpecific((byte)0x01)) {
|
||||
lastField = checkNextField(lastField, 1);
|
||||
// received reqFlags, skip it
|
||||
} else if (tmp2.isContextSpecific((byte)0x02)) {
|
||||
lastField = checkNextField(lastField, 2);
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"reading Mech Token");
|
||||
}
|
||||
mechToken = tmp2.data.getOctetString();
|
||||
} else if (tmp2.isContextSpecific((byte)0x03)) {
|
||||
lastField = checkNextField(lastField, 3);
|
||||
if (!GSSUtil.useMSInterop()) {
|
||||
mechListMIC = tmp2.data.getOctetString();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenInit: " +
|
||||
"MechListMIC Token = " +
|
||||
getHexBytes(mechListMIC));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenInit token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
byte[] getMechTypes() {
|
||||
return mechTypes;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to find the mechs in SPNEGO tokens
|
||||
public Oid[] getMechTypeList() {
|
||||
return mechTypeList;
|
||||
}
|
||||
|
||||
BitArray getReqFlags() {
|
||||
return reqFlags;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to access the mech token portion of SPNEGO tokens
|
||||
public byte[] getMechToken() {
|
||||
return mechToken;
|
||||
}
|
||||
|
||||
byte[] getMechListMIC() {
|
||||
return mechListMIC;
|
||||
}
|
||||
|
||||
}
|
||||
200
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenTarg.java
Normal file
200
jdkSrc/jdk8/sun/security/jgss/spnego/NegTokenTarg.java
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, 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 org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import sun.security.util.*;
|
||||
|
||||
/**
|
||||
* Implements the SPNEGO NegTokenTarg token
|
||||
* as specified in RFC 2478
|
||||
*
|
||||
* NegTokenTarg ::= SEQUENCE {
|
||||
* negResult [0] ENUMERATED {
|
||||
* accept_completed (0),
|
||||
* accept_incomplete (1),
|
||||
* reject (2) } OPTIONAL,
|
||||
* supportedMech [1] MechType OPTIONAL,
|
||||
* responseToken [2] OCTET STRING OPTIONAL,
|
||||
* mechListMIC [3] OCTET STRING OPTIONAL
|
||||
* }
|
||||
*
|
||||
* MechType::= OBJECT IDENTIFIER
|
||||
*
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public class NegTokenTarg extends SpNegoToken {
|
||||
|
||||
private int negResult = 0;
|
||||
private Oid supportedMech = null;
|
||||
private byte[] responseToken = null;
|
||||
private byte[] mechListMIC = null;
|
||||
|
||||
NegTokenTarg(int result, Oid mech, byte[] token, byte[] mechListMIC)
|
||||
{
|
||||
super(NEG_TOKEN_TARG_ID);
|
||||
this.negResult = result;
|
||||
this.supportedMech = mech;
|
||||
this.responseToken = token;
|
||||
this.mechListMIC = mechListMIC;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to parse SPNEGO tokens
|
||||
public NegTokenTarg(byte[] in) throws GSSException {
|
||||
super(NEG_TOKEN_TARG_ID);
|
||||
parseToken(in);
|
||||
}
|
||||
|
||||
final byte[] encode() throws GSSException {
|
||||
try {
|
||||
// create negTargToken
|
||||
DerOutputStream targToken = new DerOutputStream();
|
||||
|
||||
// write the negotiated result with CONTEXT 00
|
||||
DerOutputStream result = new DerOutputStream();
|
||||
result.putEnumerated(negResult);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x00), result);
|
||||
|
||||
// supportedMech with CONTEXT 01
|
||||
if (supportedMech != null) {
|
||||
DerOutputStream mech = new DerOutputStream();
|
||||
byte[] mechType = supportedMech.getDER();
|
||||
mech.write(mechType);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x01), mech);
|
||||
}
|
||||
|
||||
// response Token with CONTEXT 02
|
||||
if (responseToken != null) {
|
||||
DerOutputStream rspToken = new DerOutputStream();
|
||||
rspToken.putOctetString(responseToken);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x02), rspToken);
|
||||
}
|
||||
|
||||
// mechListMIC with CONTEXT 03
|
||||
if (mechListMIC != null) {
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: " +
|
||||
"sending MechListMIC");
|
||||
}
|
||||
DerOutputStream mic = new DerOutputStream();
|
||||
mic.putOctetString(mechListMIC);
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) 0x03), mic);
|
||||
}
|
||||
|
||||
// insert in a SEQUENCE
|
||||
DerOutputStream out = new DerOutputStream();
|
||||
out.write(DerValue.tag_Sequence, targToken);
|
||||
|
||||
return out.toByteArray();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenTarg token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void parseToken(byte[] in) throws GSSException {
|
||||
try {
|
||||
DerValue der = new DerValue(in);
|
||||
// verify NegotiationToken type token
|
||||
if (!der.isContextSpecific((byte) NEG_TOKEN_TARG_ID)) {
|
||||
throw new IOException("SPNEGO NegoTokenTarg : " +
|
||||
"did not have the right token type");
|
||||
}
|
||||
DerValue tmp1 = der.data.getDerValue();
|
||||
if (tmp1.tag != DerValue.tag_Sequence) {
|
||||
throw new IOException("SPNEGO NegoTokenTarg : " +
|
||||
"did not have the Sequence tag");
|
||||
}
|
||||
|
||||
// parse various fields if present
|
||||
int lastField = -1;
|
||||
while (tmp1.data.available() > 0) {
|
||||
DerValue tmp2 = tmp1.data.getDerValue();
|
||||
if (tmp2.isContextSpecific((byte)0x00)) {
|
||||
lastField = checkNextField(lastField, 0);
|
||||
negResult = tmp2.data.getEnumerated();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: negotiated" +
|
||||
" result = " + getNegoResultString(negResult));
|
||||
}
|
||||
} else if (tmp2.isContextSpecific((byte)0x01)) {
|
||||
lastField = checkNextField(lastField, 1);
|
||||
ObjectIdentifier mech = tmp2.data.getOID();
|
||||
supportedMech = new Oid(mech.toString());
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: " +
|
||||
"supported mechanism = " + supportedMech);
|
||||
}
|
||||
} else if (tmp2.isContextSpecific((byte)0x02)) {
|
||||
lastField = checkNextField(lastField, 2);
|
||||
responseToken = tmp2.data.getOctetString();
|
||||
} else if (tmp2.isContextSpecific((byte)0x03)) {
|
||||
lastField = checkNextField(lastField, 3);
|
||||
if (!GSSUtil.useMSInterop()) {
|
||||
mechListMIC = tmp2.data.getOctetString();
|
||||
if (DEBUG) {
|
||||
System.out.println("SpNegoToken NegTokenTarg: " +
|
||||
"MechListMIC Token = " +
|
||||
getHexBytes(mechListMIC));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SPNEGO NegTokenTarg token : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
int getNegotiatedResult() {
|
||||
return negResult;
|
||||
}
|
||||
|
||||
// Used by sun.security.jgss.wrapper.NativeGSSContext
|
||||
// to find the supported mech in SPNEGO tokens
|
||||
public Oid getSupportedMech() {
|
||||
return supportedMech;
|
||||
}
|
||||
|
||||
byte[] getResponseToken() {
|
||||
return responseToken;
|
||||
}
|
||||
|
||||
byte[] getMechListMIC() {
|
||||
return mechListMIC;
|
||||
}
|
||||
}
|
||||
1244
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoContext.java
Normal file
1244
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoContext.java
Normal file
File diff suppressed because it is too large
Load Diff
96
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoCredElement.java
Normal file
96
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoCredElement.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.ProviderList;
|
||||
import sun.security.jgss.GSSCredentialImpl;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
import sun.security.jgss.spi.GSSCredentialSpi;
|
||||
|
||||
/**
|
||||
* This class is the cred element implementation for SPNEGO mech.
|
||||
* NOTE: The current implementation can only support one mechanism.
|
||||
* This should be changed once multi-mechanism support is needed.
|
||||
*
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
public class SpNegoCredElement implements GSSCredentialSpi {
|
||||
|
||||
private GSSCredentialSpi cred = null;
|
||||
|
||||
public SpNegoCredElement(GSSCredentialSpi cred) throws GSSException {
|
||||
this.cred = cred;
|
||||
}
|
||||
|
||||
Oid getInternalMech() {
|
||||
return cred.getMechanism();
|
||||
}
|
||||
|
||||
// Used by GSSUtil.populateCredentials()
|
||||
public GSSCredentialSpi getInternalCred() {
|
||||
return cred;
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SpNegoMechFactory.PROVIDER;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
cred.dispose();
|
||||
}
|
||||
|
||||
public GSSNameSpi getName() throws GSSException {
|
||||
return cred.getName();
|
||||
}
|
||||
|
||||
public int getInitLifetime() throws GSSException {
|
||||
return cred.getInitLifetime();
|
||||
}
|
||||
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
return cred.getAcceptLifetime();
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() throws GSSException {
|
||||
return cred.isInitiatorCredential();
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() throws GSSException {
|
||||
return cred.isAcceptorCredential();
|
||||
}
|
||||
|
||||
public Oid getMechanism() {
|
||||
return GSSUtil.GSS_SPNEGO_MECH_OID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
return cred.impersonate(name);
|
||||
}
|
||||
}
|
||||
193
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoMechFactory.java
Normal file
193
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoMechFactory.java
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2009, 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 org.ietf.jgss.*;
|
||||
import sun.security.jgss.*;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.jgss.krb5.Krb5MechFactory;
|
||||
import sun.security.jgss.krb5.Krb5InitCredential;
|
||||
import sun.security.jgss.krb5.Krb5AcceptCredential;
|
||||
import sun.security.jgss.krb5.Krb5NameElement;
|
||||
import java.security.Provider;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* SpNego Mechanism plug in for JGSS
|
||||
* This is the properties object required by the JGSS framework.
|
||||
* All mechanism specific information is defined here.
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public final class SpNegoMechFactory implements MechanismFactory {
|
||||
|
||||
static final Provider PROVIDER =
|
||||
new sun.security.jgss.SunProvider();
|
||||
|
||||
static final Oid GSS_SPNEGO_MECH_OID =
|
||||
GSSUtil.createOid("1.3.6.1.5.5.2");
|
||||
|
||||
private static Oid[] nameTypes =
|
||||
new Oid[] { GSSName.NT_USER_NAME,
|
||||
GSSName.NT_HOSTBASED_SERVICE,
|
||||
GSSName.NT_EXPORT_NAME};
|
||||
|
||||
// The default underlying mech of SPNEGO, must not be SPNEGO itself.
|
||||
private static final Oid DEFAULT_SPNEGO_MECH_OID =
|
||||
ProviderList.DEFAULT_MECH_OID.equals(GSS_SPNEGO_MECH_OID)?
|
||||
GSSUtil.GSS_KRB5_MECH_OID:
|
||||
ProviderList.DEFAULT_MECH_OID;
|
||||
|
||||
// Use an instance of a GSSManager whose provider list
|
||||
// does not include native provider
|
||||
final GSSManagerImpl manager;
|
||||
final Oid[] availableMechs;
|
||||
|
||||
private static SpNegoCredElement getCredFromSubject(GSSNameSpi name,
|
||||
boolean initiate)
|
||||
throws GSSException {
|
||||
Vector<SpNegoCredElement> creds =
|
||||
GSSUtil.searchSubject(name, GSS_SPNEGO_MECH_OID,
|
||||
initiate, SpNegoCredElement.class);
|
||||
|
||||
SpNegoCredElement result = ((creds == null || creds.isEmpty()) ?
|
||||
null : creds.firstElement());
|
||||
|
||||
// Force permission check before returning the cred to caller
|
||||
if (result != null) {
|
||||
GSSCredentialSpi cred = result.getInternalCred();
|
||||
if (GSSUtil.isKerberosMech(cred.getMechanism())) {
|
||||
if (initiate) {
|
||||
Krb5InitCredential krbCred = (Krb5InitCredential) cred;
|
||||
Krb5MechFactory.checkInitCredPermission
|
||||
((Krb5NameElement) krbCred.getName());
|
||||
} else {
|
||||
Krb5AcceptCredential krbCred = (Krb5AcceptCredential) cred;
|
||||
Krb5MechFactory.checkAcceptCredPermission
|
||||
((Krb5NameElement) krbCred.getName(), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public SpNegoMechFactory(GSSCaller caller) {
|
||||
manager = new GSSManagerImpl(caller, false);
|
||||
Oid[] mechs = manager.getMechs();
|
||||
availableMechs = new Oid[mechs.length-1];
|
||||
for (int i = 0, j = 0; i < mechs.length; i++) {
|
||||
// Skip SpNego mechanism
|
||||
if (!mechs[i].equals(GSS_SPNEGO_MECH_OID)) {
|
||||
availableMechs[j++] = mechs[i];
|
||||
}
|
||||
}
|
||||
// Move the preferred mech to first place
|
||||
for (int i=0; i<availableMechs.length; i++) {
|
||||
if (availableMechs[i].equals(DEFAULT_SPNEGO_MECH_OID)) {
|
||||
if (i != 0) {
|
||||
availableMechs[i] = availableMechs[0];
|
||||
availableMechs[0] = DEFAULT_SPNEGO_MECH_OID;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
return manager.getNameElement(
|
||||
nameStr, nameType, DEFAULT_SPNEGO_MECH_OID);
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException {
|
||||
return manager.getNameElement(name, nameType, DEFAULT_SPNEGO_MECH_OID);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime, int acceptLifetime,
|
||||
int usage) throws GSSException {
|
||||
|
||||
SpNegoCredElement credElement = getCredFromSubject
|
||||
(name, (usage != GSSCredential.ACCEPT_ONLY));
|
||||
|
||||
if (credElement == null) {
|
||||
// get CredElement for the default Mechanism
|
||||
credElement = new SpNegoCredElement
|
||||
(manager.getCredentialElement(name, initLifetime,
|
||||
acceptLifetime, null, usage));
|
||||
}
|
||||
return credElement;
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myInitiatorCred, int lifetime)
|
||||
throws GSSException {
|
||||
// get SpNego mechanism context
|
||||
if (myInitiatorCred == null) {
|
||||
myInitiatorCred = getCredFromSubject(null, true);
|
||||
} else if (!(myInitiatorCred instanceof SpNegoCredElement)) {
|
||||
// convert to SpNegoCredElement
|
||||
SpNegoCredElement cred = new SpNegoCredElement(myInitiatorCred);
|
||||
return new SpNegoContext(this, peer, cred, lifetime);
|
||||
}
|
||||
return new SpNegoContext(this, peer, myInitiatorCred, lifetime);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myAcceptorCred)
|
||||
throws GSSException {
|
||||
// get SpNego mechanism context
|
||||
if (myAcceptorCred == null) {
|
||||
myAcceptorCred = getCredFromSubject(null, false);
|
||||
} else if (!(myAcceptorCred instanceof SpNegoCredElement)) {
|
||||
// convert to SpNegoCredElement
|
||||
SpNegoCredElement cred = new SpNegoCredElement(myAcceptorCred);
|
||||
return new SpNegoContext(this, cred);
|
||||
}
|
||||
return new SpNegoContext(this, myAcceptorCred);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
// get SpNego mechanism context
|
||||
return new SpNegoContext(this, exportedContext);
|
||||
}
|
||||
|
||||
public final Oid getMechanismOid() {
|
||||
return GSS_SPNEGO_MECH_OID;
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return PROVIDER;
|
||||
}
|
||||
|
||||
public Oid[] getNameTypes() {
|
||||
// nameTypes is cloned in GSSManager.getNamesForMech
|
||||
return nameTypes;
|
||||
}
|
||||
}
|
||||
207
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoToken.java
Normal file
207
jdkSrc/jdk8/sun/security/jgss/spnego/SpNegoToken.java
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, 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.util.*;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.util.*;
|
||||
import sun.security.jgss.*;
|
||||
|
||||
/**
|
||||
* Astract class for SPNEGO tokens.
|
||||
* Implementation is based on RFC 2478
|
||||
*
|
||||
* NegotiationToken ::= CHOICE {
|
||||
* negTokenInit [0] NegTokenInit,
|
||||
* negTokenTarg [1] NegTokenTarg }
|
||||
*
|
||||
*
|
||||
* @author Seema Malkani
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
abstract class SpNegoToken extends GSSToken {
|
||||
|
||||
static final int NEG_TOKEN_INIT_ID = 0x00;
|
||||
static final int NEG_TOKEN_TARG_ID = 0x01;
|
||||
|
||||
static enum NegoResult {
|
||||
ACCEPT_COMPLETE,
|
||||
ACCEPT_INCOMPLETE,
|
||||
REJECT,
|
||||
};
|
||||
|
||||
private int tokenType;
|
||||
|
||||
// property
|
||||
static final boolean DEBUG = SpNegoContext.DEBUG;
|
||||
|
||||
/**
|
||||
* The object identifier corresponding to the SPNEGO GSS-API
|
||||
* mechanism.
|
||||
*/
|
||||
public static ObjectIdentifier OID;
|
||||
|
||||
static {
|
||||
try {
|
||||
OID = new ObjectIdentifier(SpNegoMechFactory.
|
||||
GSS_SPNEGO_MECH_OID.toString());
|
||||
} catch (IOException ioe) {
|
||||
// should not happen
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates SPNEGO token of the specified type.
|
||||
*/
|
||||
protected SpNegoToken(int tokenType) {
|
||||
this.tokenType = tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the individual encoded SPNEGO token
|
||||
*
|
||||
* @return the encoded token
|
||||
* @exception GSSException
|
||||
*/
|
||||
abstract byte[] encode() throws GSSException;
|
||||
|
||||
/**
|
||||
* Returns the encoded SPNEGO token
|
||||
* Note: inserts the required CHOICE tags
|
||||
*
|
||||
* @return the encoded token
|
||||
* @exception GSSException
|
||||
*/
|
||||
byte[] getEncoded() throws IOException, GSSException {
|
||||
|
||||
// get the token encoded value
|
||||
DerOutputStream token = new DerOutputStream();
|
||||
token.write(encode());
|
||||
|
||||
// now insert the CHOICE
|
||||
switch (tokenType) {
|
||||
case NEG_TOKEN_INIT_ID:
|
||||
// Insert CHOICE of Negotiation Token
|
||||
DerOutputStream initToken = new DerOutputStream();
|
||||
initToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) NEG_TOKEN_INIT_ID), token);
|
||||
return initToken.toByteArray();
|
||||
|
||||
case NEG_TOKEN_TARG_ID:
|
||||
// Insert CHOICE of Negotiation Token
|
||||
DerOutputStream targToken = new DerOutputStream();
|
||||
targToken.write(DerValue.createTag(DerValue.TAG_CONTEXT,
|
||||
true, (byte) NEG_TOKEN_TARG_ID), token);
|
||||
return targToken.toByteArray();
|
||||
default:
|
||||
return token.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SPNEGO token type
|
||||
*
|
||||
* @return the token type
|
||||
*/
|
||||
final int getType() {
|
||||
return tokenType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the token type.
|
||||
*
|
||||
* @param tokenType the token type for which a string name is desired
|
||||
* @return the String name of this token type
|
||||
*/
|
||||
static String getTokenName(int type) {
|
||||
switch (type) {
|
||||
case NEG_TOKEN_INIT_ID:
|
||||
return "SPNEGO NegTokenInit";
|
||||
case NEG_TOKEN_TARG_ID:
|
||||
return "SPNEGO NegTokenTarg";
|
||||
default:
|
||||
return "SPNEGO Mechanism Token";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enumerated type of the Negotiation result.
|
||||
*
|
||||
* @param result the negotiated result represented by integer
|
||||
* @return the enumerated type of Negotiated result
|
||||
*/
|
||||
static NegoResult getNegoResultType(int result) {
|
||||
switch (result) {
|
||||
case 0:
|
||||
return NegoResult.ACCEPT_COMPLETE;
|
||||
case 1:
|
||||
return NegoResult.ACCEPT_INCOMPLETE;
|
||||
case 2:
|
||||
return NegoResult.REJECT;
|
||||
default:
|
||||
// unknown - return optimistic result
|
||||
return NegoResult.ACCEPT_COMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing the negotiation result.
|
||||
*
|
||||
* @param result the negotiated result
|
||||
* @return the String message of this negotiated result
|
||||
*/
|
||||
static String getNegoResultString(int result) {
|
||||
switch (result) {
|
||||
case 0:
|
||||
return "Accept Complete";
|
||||
case 1:
|
||||
return "Accept InComplete";
|
||||
case 2:
|
||||
return "Reject";
|
||||
default:
|
||||
return ("Unknown Negotiated Result: " + result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the context tag in a sequence is in correct order. The "last"
|
||||
* value must be smaller than "current".
|
||||
* @param last the last tag seen
|
||||
* @param current the current tag
|
||||
* @return the current tag, used as the next value for last
|
||||
* @throws GSSException if there's a wrong order
|
||||
*/
|
||||
static int checkNextField(int last, int current) throws GSSException {
|
||||
if (last < current) {
|
||||
return current;
|
||||
} else {
|
||||
throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
|
||||
"Invalid SpNegoToken token : wrong order");
|
||||
}
|
||||
}
|
||||
}
|
||||
142
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSCredElement.java
Normal file
142
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSCredElement.java
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, 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.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.spi.GSSCredentialSpi;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
|
||||
/**
|
||||
* This class is essentially a wrapper class for the gss_cred_id_t
|
||||
* structure of the native GSS library.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
public class GSSCredElement implements GSSCredentialSpi {
|
||||
|
||||
private int usage;
|
||||
long pCred; // Pointer to the gss_cred_id_t structure
|
||||
private GSSNameElement name = null;
|
||||
private GSSLibStub cStub;
|
||||
|
||||
// Perform the necessary ServicePermission check on this cred
|
||||
void doServicePermCheck() throws GSSException {
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech())) {
|
||||
if (System.getSecurityManager() != null) {
|
||||
if (isInitiatorCredential()) {
|
||||
String tgsName = Krb5Util.getTGSName(name);
|
||||
Krb5Util.checkServicePermission(tgsName, "initiate");
|
||||
}
|
||||
if (isAcceptorCredential() &&
|
||||
name != GSSNameElement.DEF_ACCEPTOR) {
|
||||
String krbName = name.getKrbName();
|
||||
Krb5Util.checkServicePermission(krbName, "accept");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct delegation cred using the actual context mech and srcName
|
||||
GSSCredElement(long pCredentials, GSSNameElement srcName, Oid mech)
|
||||
throws GSSException {
|
||||
pCred = pCredentials;
|
||||
cStub = GSSLibStub.getInstance(mech);
|
||||
usage = GSSCredential.INITIATE_ONLY;
|
||||
name = srcName;
|
||||
}
|
||||
|
||||
GSSCredElement(GSSNameElement name, int lifetime, int usage,
|
||||
GSSLibStub stub) throws GSSException {
|
||||
cStub = stub;
|
||||
this.usage = usage;
|
||||
|
||||
if (name != null) { // Could be GSSNameElement.DEF_ACCEPTOR
|
||||
this.name = name;
|
||||
doServicePermCheck();
|
||||
pCred = cStub.acquireCred(this.name.pName, lifetime, usage);
|
||||
} else {
|
||||
pCred = cStub.acquireCred(0, lifetime, usage);
|
||||
this.name = new GSSNameElement(cStub.getCredName(pCred), cStub);
|
||||
doServicePermCheck();
|
||||
}
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
name = null;
|
||||
if (pCred != 0) {
|
||||
pCred = cStub.releaseCred(pCred);
|
||||
}
|
||||
}
|
||||
|
||||
public GSSNameElement getName() throws GSSException {
|
||||
return (name == GSSNameElement.DEF_ACCEPTOR ?
|
||||
null : name);
|
||||
}
|
||||
|
||||
public int getInitLifetime() throws GSSException {
|
||||
if (isInitiatorCredential()) {
|
||||
return cStub.getCredTime(pCred);
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
public int getAcceptLifetime() throws GSSException {
|
||||
if (isAcceptorCredential()) {
|
||||
return cStub.getCredTime(pCred);
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
public boolean isInitiatorCredential() {
|
||||
return (usage != GSSCredential.ACCEPT_ONLY);
|
||||
}
|
||||
|
||||
public boolean isAcceptorCredential() {
|
||||
return (usage != GSSCredential.INITIATE_ONLY);
|
||||
}
|
||||
|
||||
public Oid getMechanism() {
|
||||
return cStub.getMech();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
// No hex bytes available for native impl
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Not supported yet");
|
||||
}
|
||||
}
|
||||
126
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSLibStub.java
Normal file
126
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSLibStub.java
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2014, 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.wrapper;
|
||||
|
||||
import java.util.Hashtable;
|
||||
import org.ietf.jgss.Oid;
|
||||
import org.ietf.jgss.GSSName;
|
||||
import org.ietf.jgss.ChannelBinding;
|
||||
import org.ietf.jgss.MessageProp;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
|
||||
/**
|
||||
* This class is essentially a JNI calling stub for all wrapper classes.
|
||||
*
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
class GSSLibStub {
|
||||
|
||||
private Oid mech;
|
||||
private long pMech;
|
||||
|
||||
/**
|
||||
* Initialization routine to dynamically load function pointers.
|
||||
*
|
||||
* @param lib library name to dlopen
|
||||
* @param debug set to true for reporting native debugging info
|
||||
* @return true if succeeded, false otherwise.
|
||||
*/
|
||||
static native boolean init(String lib, boolean debug);
|
||||
private static native long getMechPtr(byte[] oidDerEncoding);
|
||||
|
||||
// Miscellaneous routines
|
||||
static native Oid[] indicateMechs();
|
||||
native Oid[] inquireNamesForMech() throws GSSException;
|
||||
|
||||
// Name related routines
|
||||
native void releaseName(long pName);
|
||||
native long importName(byte[] name, Oid type);
|
||||
native boolean compareName(long pName1, long pName2);
|
||||
native long canonicalizeName(long pName);
|
||||
native byte[] exportName(long pName) throws GSSException;
|
||||
native Object[] displayName(long pName) throws GSSException;
|
||||
|
||||
// Credential related routines
|
||||
native long acquireCred(long pName, int lifetime, int usage)
|
||||
throws GSSException;
|
||||
native long releaseCred(long pCred);
|
||||
native long getCredName(long pCred);
|
||||
native int getCredTime(long pCred);
|
||||
native int getCredUsage(long pCred);
|
||||
|
||||
// Context related routines
|
||||
native NativeGSSContext importContext(byte[] interProcToken);
|
||||
native byte[] initContext(long pCred, long targetName, ChannelBinding cb,
|
||||
byte[] inToken, NativeGSSContext context);
|
||||
native byte[] acceptContext(long pCred, ChannelBinding cb,
|
||||
byte[] inToken, NativeGSSContext context);
|
||||
native long[] inquireContext(long pContext);
|
||||
native Oid getContextMech(long pContext);
|
||||
native long getContextName(long pContext, boolean isSrc);
|
||||
native int getContextTime(long pContext);
|
||||
native long deleteContext(long pContext);
|
||||
native int wrapSizeLimit(long pContext, int flags, int qop, int outSize);
|
||||
native byte[] exportContext(long pContext);
|
||||
native byte[] getMic(long pContext, int qop, byte[] msg);
|
||||
native void verifyMic(long pContext, byte[] token, byte[] msg,
|
||||
MessageProp prop) ;
|
||||
native byte[] wrap(long pContext, byte[] msg, MessageProp prop);
|
||||
native byte[] unwrap(long pContext, byte[] msgToken, MessageProp prop);
|
||||
|
||||
private static Hashtable<Oid, GSSLibStub>
|
||||
table = new Hashtable<Oid, GSSLibStub>(5);
|
||||
|
||||
static GSSLibStub getInstance(Oid mech) throws GSSException {
|
||||
GSSLibStub s = table.get(mech);
|
||||
if (s == null) {
|
||||
s = new GSSLibStub(mech);
|
||||
table.put(mech, s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
private GSSLibStub(Oid mech) throws GSSException {
|
||||
SunNativeProvider.debug("Created GSSLibStub for mech " + mech);
|
||||
this.mech = mech;
|
||||
this.pMech = getMechPtr(mech.getDER());
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (!(obj instanceof GSSLibStub)) {
|
||||
return false;
|
||||
}
|
||||
return (mech.equals(((GSSLibStub) obj).getMech()));
|
||||
}
|
||||
public int hashCode() {
|
||||
return mech.hashCode();
|
||||
}
|
||||
Oid getMech() {
|
||||
return mech;
|
||||
}
|
||||
}
|
||||
295
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSNameElement.java
Normal file
295
jdkSrc/jdk8/sun/security/jgss/wrapper/GSSNameElement.java
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2010, 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.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import java.security.Security;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import sun.security.krb5.Realm;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.util.DerInputStream;
|
||||
import sun.security.util.DerOutputStream;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSExceptionImpl;
|
||||
import sun.security.jgss.spi.GSSNameSpi;
|
||||
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
|
||||
/**
|
||||
* This class is essentially a wrapper class for the gss_name_t
|
||||
* structure of the native GSS library.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
|
||||
public class GSSNameElement implements GSSNameSpi {
|
||||
|
||||
long pName = 0; // Pointer to the gss_name_t structure
|
||||
private String printableName;
|
||||
private Oid printableType;
|
||||
private GSSLibStub cStub;
|
||||
|
||||
static final GSSNameElement DEF_ACCEPTOR = new GSSNameElement();
|
||||
|
||||
private static Oid getNativeNameType(Oid nameType, GSSLibStub stub) {
|
||||
if (GSSUtil.NT_GSS_KRB5_PRINCIPAL.equals(nameType)) {
|
||||
Oid[] supportedNTs = null;
|
||||
try {
|
||||
supportedNTs = stub.inquireNamesForMech();
|
||||
} catch (GSSException ge) {
|
||||
if (ge.getMajor() == GSSException.BAD_MECH &&
|
||||
GSSUtil.isSpNegoMech(stub.getMech())) {
|
||||
// Workaround known Heimdal issue and retry with KRB5
|
||||
try {
|
||||
stub = GSSLibStub.getInstance
|
||||
(GSSUtil.GSS_KRB5_MECH_OID);
|
||||
supportedNTs = stub.inquireNamesForMech();
|
||||
} catch (GSSException ge2) {
|
||||
// Should never happen
|
||||
SunNativeProvider.debug("Name type list unavailable: " +
|
||||
ge2.getMajorString());
|
||||
}
|
||||
} else {
|
||||
SunNativeProvider.debug("Name type list unavailable: " +
|
||||
ge.getMajorString());
|
||||
}
|
||||
}
|
||||
if (supportedNTs != null) {
|
||||
for (int i = 0; i < supportedNTs.length; i++) {
|
||||
if (supportedNTs[i].equals(nameType)) return nameType;
|
||||
}
|
||||
// Special handling the specified name type
|
||||
SunNativeProvider.debug("Override " + nameType +
|
||||
" with mechanism default(null)");
|
||||
return null; // Use mechanism specific default
|
||||
}
|
||||
}
|
||||
return nameType;
|
||||
}
|
||||
|
||||
private GSSNameElement() {
|
||||
printableName = "<DEFAULT ACCEPTOR>";
|
||||
}
|
||||
|
||||
GSSNameElement(long pNativeName, GSSLibStub stub) throws GSSException {
|
||||
assert(stub != null);
|
||||
if (pNativeName == 0) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
// Note: pNativeName is assumed to be a MN.
|
||||
pName = pNativeName;
|
||||
cStub = stub;
|
||||
setPrintables();
|
||||
}
|
||||
|
||||
GSSNameElement(byte[] nameBytes, Oid nameType, GSSLibStub stub)
|
||||
throws GSSException {
|
||||
assert(stub != null);
|
||||
if (nameBytes == null) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
cStub = stub;
|
||||
byte[] name = nameBytes;
|
||||
|
||||
if (nameType != null) {
|
||||
// Special handling the specified name type if
|
||||
// necessary
|
||||
nameType = getNativeNameType(nameType, stub);
|
||||
|
||||
if (GSSName.NT_EXPORT_NAME.equals(nameType)) {
|
||||
// Need to add back the mech Oid portion (stripped
|
||||
// off by GSSNameImpl class prior to calling this
|
||||
// method) for "NT_EXPORT_NAME"
|
||||
byte[] mechBytes = null;
|
||||
DerOutputStream dout = new DerOutputStream();
|
||||
Oid mech = cStub.getMech();
|
||||
try {
|
||||
dout.putOID(new ObjectIdentifier(mech.toString()));
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, e);
|
||||
}
|
||||
mechBytes = dout.toByteArray();
|
||||
name = new byte[2 + 2 + mechBytes.length + 4 + nameBytes.length];
|
||||
int pos = 0;
|
||||
name[pos++] = 0x04;
|
||||
name[pos++] = 0x01;
|
||||
name[pos++] = (byte) (mechBytes.length>>>8);
|
||||
name[pos++] = (byte) mechBytes.length;
|
||||
System.arraycopy(mechBytes, 0, name, pos, mechBytes.length);
|
||||
pos += mechBytes.length;
|
||||
name[pos++] = (byte) (nameBytes.length>>>24);
|
||||
name[pos++] = (byte) (nameBytes.length>>>16);
|
||||
name[pos++] = (byte) (nameBytes.length>>>8);
|
||||
name[pos++] = (byte) nameBytes.length;
|
||||
System.arraycopy(nameBytes, 0, name, pos, nameBytes.length);
|
||||
}
|
||||
}
|
||||
pName = cStub.importName(name, nameType);
|
||||
setPrintables();
|
||||
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null && !Realm.AUTODEDUCEREALM) {
|
||||
String krbName = getKrbName();
|
||||
int atPos = krbName.lastIndexOf('@');
|
||||
if (atPos != -1) {
|
||||
String atRealm = krbName.substring(atPos);
|
||||
// getNativeNameType() can modify NT_GSS_KRB5_PRINCIPAL to null
|
||||
if ((nameType == null
|
||||
|| nameType.equals(GSSUtil.NT_GSS_KRB5_PRINCIPAL))
|
||||
&& new String(nameBytes).endsWith(atRealm)) {
|
||||
// Created from Kerberos name with realm, no need to check
|
||||
} else {
|
||||
try {
|
||||
sm.checkPermission(new ServicePermission(atRealm, "-"));
|
||||
} catch (SecurityException se) {
|
||||
// Do not chain the actual exception to hide info
|
||||
throw new GSSException(GSSException.FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SunNativeProvider.debug("Imported " + printableName + " w/ type " +
|
||||
printableType);
|
||||
}
|
||||
|
||||
private void setPrintables() throws GSSException {
|
||||
Object[] printables = null;
|
||||
printables = cStub.displayName(pName);
|
||||
assert((printables != null) && (printables.length == 2));
|
||||
printableName = (String) printables[0];
|
||||
assert(printableName != null);
|
||||
printableType = (Oid) printables[1];
|
||||
if (printableType == null) {
|
||||
printableType = GSSName.NT_USER_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
// Need to be public for GSSUtil.getSubject()
|
||||
public String getKrbName() throws GSSException {
|
||||
long mName = 0;
|
||||
GSSLibStub stub = cStub;
|
||||
if (!GSSUtil.isKerberosMech(cStub.getMech())) {
|
||||
stub = GSSLibStub.getInstance(GSSUtil.GSS_KRB5_MECH_OID);
|
||||
}
|
||||
mName = stub.canonicalizeName(pName);
|
||||
Object[] printables2 = stub.displayName(mName);
|
||||
stub.releaseName(mName);
|
||||
SunNativeProvider.debug("Got kerberized name: " + printables2[0]);
|
||||
return (String) printables2[0];
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public boolean equals(GSSNameSpi other) throws GSSException {
|
||||
if (!(other instanceof GSSNameElement)) {
|
||||
return false;
|
||||
}
|
||||
return cStub.compareName(pName, ((GSSNameElement)other).pName);
|
||||
}
|
||||
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof GSSNameElement)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return equals((GSSNameElement) other);
|
||||
} catch (GSSException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return new Long(pName).hashCode();
|
||||
}
|
||||
|
||||
public byte[] export() throws GSSException {
|
||||
byte[] nameVal = cStub.exportName(pName);
|
||||
|
||||
// Need to strip off the mech Oid portion of the exported
|
||||
// bytes since GSSNameImpl class will subsequently add it.
|
||||
int pos = 0;
|
||||
if ((nameVal[pos++] != 0x04) ||
|
||||
(nameVal[pos++] != 0x01))
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
|
||||
int mechOidLen = (((0xFF & nameVal[pos++]) << 8) |
|
||||
(0xFF & nameVal[pos++]));
|
||||
ObjectIdentifier temp = null;
|
||||
try {
|
||||
DerInputStream din = new DerInputStream(nameVal, pos,
|
||||
mechOidLen);
|
||||
temp = new ObjectIdentifier(din);
|
||||
} catch (IOException e) {
|
||||
throw new GSSExceptionImpl(GSSException.BAD_NAME, e);
|
||||
}
|
||||
Oid mech2 = new Oid(temp.toString());
|
||||
assert(mech2.equals(getMechanism()));
|
||||
pos += mechOidLen;
|
||||
int mechPortionLen = (((0xFF & nameVal[pos++]) << 24) |
|
||||
((0xFF & nameVal[pos++]) << 16) |
|
||||
((0xFF & nameVal[pos++]) << 8) |
|
||||
(0xFF & nameVal[pos++]));
|
||||
if (mechPortionLen < 0) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
}
|
||||
byte[] mechPortion = new byte[mechPortionLen];
|
||||
System.arraycopy(nameVal, pos, mechPortion, 0, mechPortionLen);
|
||||
return mechPortion;
|
||||
}
|
||||
|
||||
public Oid getMechanism() {
|
||||
return cStub.getMech();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return printableName;
|
||||
}
|
||||
|
||||
public Oid getStringNameType() {
|
||||
return printableType;
|
||||
}
|
||||
|
||||
public boolean isAnonymousName() {
|
||||
return (GSSName.NT_ANONYMOUS.equals(printableType));
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
if (pName != 0) {
|
||||
cStub.releaseName(pName);
|
||||
pName = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
61
jdkSrc/jdk8/sun/security/jgss/wrapper/Krb5Util.java
Normal file
61
jdkSrc/jdk8/sun/security/jgss/wrapper/Krb5Util.java
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 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.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import javax.security.auth.kerberos.ServicePermission;
|
||||
|
||||
/**
|
||||
* This class is an utility class for Kerberos related stuff.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
class Krb5Util {
|
||||
|
||||
// Return the Kerberos TGS principal name using the domain
|
||||
// of the specified <code>name</code>
|
||||
static String getTGSName(GSSNameElement name)
|
||||
throws GSSException {
|
||||
String krbPrinc = name.getKrbName();
|
||||
int atIndex = krbPrinc.indexOf("@");
|
||||
String realm = krbPrinc.substring(atIndex + 1);
|
||||
StringBuffer buf = new StringBuffer("krbtgt/");
|
||||
buf.append(realm).append('@').append(realm);
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
// Perform the Service Permission check using the specified
|
||||
// <code>target</code> and <code>action</code>
|
||||
static void checkServicePermission(String target, String action) {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
SunNativeProvider.debug("Checking ServicePermission(" +
|
||||
target + ", " + action + ")");
|
||||
ServicePermission perm =
|
||||
new ServicePermission(target, action);
|
||||
sm.checkPermission(perm);
|
||||
}
|
||||
}
|
||||
}
|
||||
631
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSContext.java
Normal file
631
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSContext.java
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2009, 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.wrapper;
|
||||
|
||||
import org.ietf.jgss.*;
|
||||
import java.security.Provider;
|
||||
import sun.security.jgss.GSSHeader;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSExceptionImpl;
|
||||
import sun.security.jgss.spi.*;
|
||||
import sun.security.util.DerValue;
|
||||
import sun.security.util.ObjectIdentifier;
|
||||
import sun.security.jgss.spnego.NegTokenInit;
|
||||
import sun.security.jgss.spnego.NegTokenTarg;
|
||||
import javax.security.auth.kerberos.DelegationPermission;
|
||||
import com.sun.security.jgss.InquireType;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* This class is essentially a wrapper class for the gss_ctx_id_t
|
||||
* structure of the native GSS library.
|
||||
* @author Valerie Peng
|
||||
* @since 1.6
|
||||
*/
|
||||
class NativeGSSContext implements GSSContextSpi {
|
||||
|
||||
private static final int GSS_C_DELEG_FLAG = 1;
|
||||
private static final int GSS_C_MUTUAL_FLAG = 2;
|
||||
private static final int GSS_C_REPLAY_FLAG = 4;
|
||||
private static final int GSS_C_SEQUENCE_FLAG = 8;
|
||||
private static final int GSS_C_CONF_FLAG = 16;
|
||||
private static final int GSS_C_INTEG_FLAG = 32;
|
||||
private static final int GSS_C_ANON_FLAG = 64;
|
||||
private static final int GSS_C_PROT_READY_FLAG = 128;
|
||||
private static final int GSS_C_TRANS_FLAG = 256;
|
||||
|
||||
private static final int NUM_OF_INQUIRE_VALUES = 6;
|
||||
|
||||
private long pContext = 0; // Pointer to the gss_ctx_id_t structure
|
||||
private GSSNameElement srcName;
|
||||
private GSSNameElement targetName;
|
||||
private GSSCredElement cred;
|
||||
private boolean isInitiator;
|
||||
private boolean isEstablished;
|
||||
private Oid actualMech; // Assigned during context establishment
|
||||
|
||||
private ChannelBinding cb;
|
||||
private GSSCredElement delegatedCred;
|
||||
private int flags;
|
||||
private int lifetime = GSSCredential.DEFAULT_LIFETIME;
|
||||
private final GSSLibStub cStub;
|
||||
|
||||
private boolean skipDelegPermCheck;
|
||||
private boolean skipServicePermCheck;
|
||||
|
||||
// Retrieve the (preferred) mech out of SPNEGO tokens, i.e.
|
||||
// NegTokenInit & NegTokenTarg
|
||||
private static Oid getMechFromSpNegoToken(byte[] token,
|
||||
boolean isInitiator)
|
||||
throws GSSException {
|
||||
Oid mech = null;
|
||||
if (isInitiator) {
|
||||
GSSHeader header = null;
|
||||
try {
|
||||
header = new GSSHeader(new ByteArrayInputStream(token));
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
int negTokenLen = header.getMechTokenLength();
|
||||
byte[] negToken = new byte[negTokenLen];
|
||||
System.arraycopy(token, token.length-negTokenLen,
|
||||
negToken, 0, negToken.length);
|
||||
|
||||
NegTokenInit ntok = new NegTokenInit(negToken);
|
||||
if (ntok.getMechToken() != null) {
|
||||
Oid[] mechList = ntok.getMechTypeList();
|
||||
mech = mechList[0];
|
||||
}
|
||||
} else {
|
||||
NegTokenTarg ntok = new NegTokenTarg(token);
|
||||
mech = ntok.getSupportedMech();
|
||||
}
|
||||
return mech;
|
||||
}
|
||||
|
||||
// Perform the Service permission check
|
||||
private void doServicePermCheck() throws GSSException {
|
||||
if (System.getSecurityManager() != null) {
|
||||
String action = (isInitiator? "initiate" : "accept");
|
||||
// Need to check Service permission for accessing
|
||||
// initiator cred for SPNEGO during context establishment
|
||||
if (GSSUtil.isSpNegoMech(cStub.getMech()) && isInitiator
|
||||
&& !isEstablished) {
|
||||
if (srcName == null) {
|
||||
// Check by creating default initiator KRB5 cred
|
||||
GSSCredElement tempCred =
|
||||
new GSSCredElement(null, lifetime,
|
||||
GSSCredential.INITIATE_ONLY,
|
||||
GSSLibStub.getInstance(GSSUtil.GSS_KRB5_MECH_OID));
|
||||
tempCred.dispose();
|
||||
} else {
|
||||
String tgsName = Krb5Util.getTGSName(srcName);
|
||||
Krb5Util.checkServicePermission(tgsName, action);
|
||||
}
|
||||
}
|
||||
String targetStr = targetName.getKrbName();
|
||||
Krb5Util.checkServicePermission(targetStr, action);
|
||||
skipServicePermCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the Delegation permission check
|
||||
private void doDelegPermCheck() throws GSSException {
|
||||
SecurityManager sm = System.getSecurityManager();
|
||||
if (sm != null) {
|
||||
String targetStr = targetName.getKrbName();
|
||||
String tgsStr = Krb5Util.getTGSName(targetName);
|
||||
StringBuffer buf = new StringBuffer("\"");
|
||||
buf.append(targetStr).append("\" \"");
|
||||
buf.append(tgsStr).append('\"');
|
||||
String krbPrincPair = buf.toString();
|
||||
SunNativeProvider.debug("Checking DelegationPermission (" +
|
||||
krbPrincPair + ")");
|
||||
DelegationPermission perm =
|
||||
new DelegationPermission(krbPrincPair);
|
||||
sm.checkPermission(perm);
|
||||
skipDelegPermCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] retrieveToken(InputStream is, int mechTokenLen)
|
||||
throws GSSException {
|
||||
try {
|
||||
byte[] result = null;
|
||||
if (mechTokenLen != -1) {
|
||||
// Need to add back the GSS header for a complete GSS token
|
||||
SunNativeProvider.debug("Precomputed mechToken length: " +
|
||||
mechTokenLen);
|
||||
GSSHeader gssHeader = new GSSHeader
|
||||
(new ObjectIdentifier(cStub.getMech().toString()),
|
||||
mechTokenLen);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(600);
|
||||
|
||||
byte[] mechToken = new byte[mechTokenLen];
|
||||
int len = is.read(mechToken);
|
||||
assert(mechTokenLen == len);
|
||||
gssHeader.encode(baos);
|
||||
baos.write(mechToken);
|
||||
result = baos.toByteArray();
|
||||
} else {
|
||||
// Must be unparsed GSS token or SPNEGO's NegTokenTarg token
|
||||
assert(mechTokenLen == -1);
|
||||
DerValue dv = new DerValue(is);
|
||||
result = dv.toByteArray();
|
||||
}
|
||||
SunNativeProvider.debug("Complete Token length: " +
|
||||
result.length);
|
||||
return result;
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for context initiator
|
||||
NativeGSSContext(GSSNameElement peer, GSSCredElement myCred,
|
||||
int time, GSSLibStub stub) throws GSSException {
|
||||
if (peer == null) {
|
||||
throw new GSSException(GSSException.FAILURE, 1, "null peer");
|
||||
}
|
||||
cStub = stub;
|
||||
cred = myCred;
|
||||
targetName = peer;
|
||||
isInitiator = true;
|
||||
lifetime = time;
|
||||
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech())) {
|
||||
doServicePermCheck();
|
||||
if (cred == null) {
|
||||
cred = new GSSCredElement(null, lifetime,
|
||||
GSSCredential.INITIATE_ONLY, cStub);
|
||||
}
|
||||
srcName = cred.getName();
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor for context acceptor
|
||||
NativeGSSContext(GSSCredElement myCred, GSSLibStub stub)
|
||||
throws GSSException {
|
||||
cStub = stub;
|
||||
cred = myCred;
|
||||
|
||||
if (cred != null) targetName = cred.getName();
|
||||
|
||||
isInitiator = false;
|
||||
// Defer Service permission check for default acceptor cred
|
||||
// to acceptSecContext()
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech()) && targetName != null) {
|
||||
doServicePermCheck();
|
||||
}
|
||||
|
||||
// srcName and potentially targetName (when myCred is null)
|
||||
// will be set in GSSLibStub.acceptContext(...)
|
||||
}
|
||||
|
||||
// Constructor for imported context
|
||||
NativeGSSContext(long pCtxt, GSSLibStub stub) throws GSSException {
|
||||
assert(pContext != 0);
|
||||
pContext = pCtxt;
|
||||
cStub = stub;
|
||||
|
||||
// Set everything except cred, cb, delegatedCred
|
||||
long[] info = cStub.inquireContext(pContext);
|
||||
if (info.length != NUM_OF_INQUIRE_VALUES) {
|
||||
throw new RuntimeException("Bug w/ GSSLibStub.inquireContext()");
|
||||
}
|
||||
srcName = new GSSNameElement(info[0], cStub);
|
||||
targetName = new GSSNameElement(info[1], cStub);
|
||||
isInitiator = (info[2] != 0);
|
||||
isEstablished = (info[3] != 0);
|
||||
flags = (int) info[4];
|
||||
lifetime = (int) info[5];
|
||||
|
||||
// Do Service Permission check when importing SPNEGO context
|
||||
// just to be safe
|
||||
Oid mech = cStub.getMech();
|
||||
if (GSSUtil.isSpNegoMech(mech) || GSSUtil.isKerberosMech(mech)) {
|
||||
doServicePermCheck();
|
||||
}
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public byte[] initSecContext(InputStream is, int mechTokenLen)
|
||||
throws GSSException {
|
||||
byte[] outToken = null;
|
||||
if ((!isEstablished) && (isInitiator)) {
|
||||
byte[] inToken = null;
|
||||
// Ignore the specified input stream on the first call
|
||||
if (pContext != 0) {
|
||||
inToken = retrieveToken(is, mechTokenLen);
|
||||
SunNativeProvider.debug("initSecContext=> inToken len=" +
|
||||
inToken.length);
|
||||
}
|
||||
|
||||
if (!getCredDelegState()) skipDelegPermCheck = true;
|
||||
|
||||
if (GSSUtil.isKerberosMech(cStub.getMech()) && !skipDelegPermCheck) {
|
||||
doDelegPermCheck();
|
||||
}
|
||||
|
||||
long pCred = (cred == null? 0 : cred.pCred);
|
||||
outToken = cStub.initContext(pCred, targetName.pName,
|
||||
cb, inToken, this);
|
||||
SunNativeProvider.debug("initSecContext=> outToken len=" +
|
||||
(outToken == null ? 0 : outToken.length));
|
||||
|
||||
// Only inspect the token when the permission check
|
||||
// has not been performed
|
||||
if (GSSUtil.isSpNegoMech(cStub.getMech()) && outToken != null) {
|
||||
// WORKAROUND for SEAM bug#6287358
|
||||
actualMech = getMechFromSpNegoToken(outToken, true);
|
||||
|
||||
if (GSSUtil.isKerberosMech(actualMech)) {
|
||||
if (!skipServicePermCheck) doServicePermCheck();
|
||||
if (!skipDelegPermCheck) doDelegPermCheck();
|
||||
}
|
||||
}
|
||||
|
||||
if (isEstablished) {
|
||||
if (srcName == null) {
|
||||
srcName = new GSSNameElement
|
||||
(cStub.getContextName(pContext, true), cStub);
|
||||
}
|
||||
if (cred == null) {
|
||||
cred = new GSSCredElement(srcName, lifetime,
|
||||
GSSCredential.INITIATE_ONLY,
|
||||
cStub);
|
||||
}
|
||||
}
|
||||
}
|
||||
return outToken;
|
||||
}
|
||||
|
||||
public byte[] acceptSecContext(InputStream is, int mechTokenLen)
|
||||
throws GSSException {
|
||||
byte[] outToken = null;
|
||||
if ((!isEstablished) && (!isInitiator)) {
|
||||
byte[] inToken = retrieveToken(is, mechTokenLen);
|
||||
SunNativeProvider.debug("acceptSecContext=> inToken len=" +
|
||||
inToken.length);
|
||||
long pCred = (cred == null? 0 : cred.pCred);
|
||||
outToken = cStub.acceptContext(pCred, cb, inToken, this);
|
||||
SunNativeProvider.debug("acceptSecContext=> outToken len=" +
|
||||
(outToken == null? 0 : outToken.length));
|
||||
|
||||
if (targetName == null) {
|
||||
targetName = new GSSNameElement
|
||||
(cStub.getContextName(pContext, false), cStub);
|
||||
// Replace the current default acceptor cred now that
|
||||
// the context acceptor name is available
|
||||
if (cred != null) cred.dispose();
|
||||
cred = new GSSCredElement(targetName, lifetime,
|
||||
GSSCredential.ACCEPT_ONLY, cStub);
|
||||
}
|
||||
|
||||
// Only inspect token when the permission check has not
|
||||
// been performed
|
||||
if (GSSUtil.isSpNegoMech(cStub.getMech()) &&
|
||||
(outToken != null) && !skipServicePermCheck) {
|
||||
if (GSSUtil.isKerberosMech(getMechFromSpNegoToken
|
||||
(outToken, false))) {
|
||||
doServicePermCheck();
|
||||
}
|
||||
}
|
||||
}
|
||||
return outToken;
|
||||
}
|
||||
|
||||
public boolean isEstablished() {
|
||||
return isEstablished;
|
||||
}
|
||||
|
||||
public void dispose() throws GSSException {
|
||||
srcName = null;
|
||||
targetName = null;
|
||||
cred = null;
|
||||
delegatedCred = null;
|
||||
if (pContext != 0) {
|
||||
pContext = cStub.deleteContext(pContext);
|
||||
pContext = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int getWrapSizeLimit(int qop, boolean confReq,
|
||||
int maxTokenSize)
|
||||
throws GSSException {
|
||||
return cStub.wrapSizeLimit(pContext, (confReq? 1:0), qop,
|
||||
maxTokenSize);
|
||||
}
|
||||
|
||||
public byte[] wrap(byte[] inBuf, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] data = inBuf;
|
||||
if ((offset != 0) || (len != inBuf.length)) {
|
||||
data = new byte[len];
|
||||
System.arraycopy(inBuf, offset, data, 0, len);
|
||||
}
|
||||
return cStub.wrap(pContext, data, msgProp);
|
||||
}
|
||||
public void wrap(byte inBuf[], int offset, int len,
|
||||
OutputStream os, MessageProp msgProp)
|
||||
throws GSSException {
|
||||
try {
|
||||
byte[] result = wrap(inBuf, offset, len, msgProp);
|
||||
os.write(result);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
public int wrap(byte[] inBuf, int inOffset, int len, byte[] outBuf,
|
||||
int outOffset, MessageProp msgProp)
|
||||
throws GSSException {
|
||||
byte[] result = wrap(inBuf, inOffset, len, msgProp);
|
||||
System.arraycopy(result, 0, outBuf, outOffset, result.length);
|
||||
return result.length;
|
||||
}
|
||||
public void wrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
byte[] data = new byte[inStream.available()];
|
||||
int length = inStream.read(data);
|
||||
byte[] token = wrap(data, 0, length, msgProp);
|
||||
outStream.write(token);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] unwrap(byte[] inBuf, int offset, int len,
|
||||
MessageProp msgProp)
|
||||
throws GSSException {
|
||||
if ((offset != 0) || (len != inBuf.length)) {
|
||||
byte[] temp = new byte[len];
|
||||
System.arraycopy(inBuf, offset, temp, 0, len);
|
||||
return cStub.unwrap(pContext, temp, msgProp);
|
||||
} else {
|
||||
return cStub.unwrap(pContext, inBuf, msgProp);
|
||||
}
|
||||
}
|
||||
public int unwrap(byte[] inBuf, int inOffset, int len,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] result = null;
|
||||
if ((inOffset != 0) || (len != inBuf.length)) {
|
||||
byte[] temp = new byte[len];
|
||||
System.arraycopy(inBuf, inOffset, temp, 0, len);
|
||||
result = cStub.unwrap(pContext, temp, msgProp);
|
||||
} else {
|
||||
result = cStub.unwrap(pContext, inBuf, msgProp);
|
||||
}
|
||||
System.arraycopy(result, 0, outBuf, outOffset, result.length);
|
||||
return result.length;
|
||||
}
|
||||
public void unwrap(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
byte[] wrapped = new byte[inStream.available()];
|
||||
int wLength = inStream.read(wrapped);
|
||||
byte[] data = unwrap(wrapped, 0, wLength, msgProp);
|
||||
outStream.write(data);
|
||||
outStream.flush();
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public int unwrap(InputStream inStream,
|
||||
byte[] outBuf, int outOffset,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] wrapped = null;
|
||||
int wLength = 0;
|
||||
try {
|
||||
wrapped = new byte[inStream.available()];
|
||||
wLength = inStream.read(wrapped);
|
||||
byte[] result = unwrap(wrapped, 0, wLength, msgProp);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
byte[] result = unwrap(wrapped, 0, wLength, msgProp);
|
||||
System.arraycopy(result, 0, outBuf, outOffset, result.length);
|
||||
return result.length;
|
||||
}
|
||||
|
||||
public byte[] getMIC(byte[] in, int offset, int len,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
int qop = (msgProp == null? 0:msgProp.getQOP());
|
||||
byte[] inMsg = in;
|
||||
if ((offset != 0) || (len != in.length)) {
|
||||
inMsg = new byte[len];
|
||||
System.arraycopy(in, offset, inMsg, 0, len);
|
||||
}
|
||||
return cStub.getMic(pContext, qop, inMsg);
|
||||
}
|
||||
|
||||
public void getMIC(InputStream inStream, OutputStream outStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
int length = 0;
|
||||
byte[] msg = new byte[inStream.available()];
|
||||
length = inStream.read(msg);
|
||||
|
||||
byte[] msgToken = getMIC(msg, 0, length, msgProp);
|
||||
if ((msgToken != null) && msgToken.length != 0) {
|
||||
outStream.write(msgToken);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public void verifyMIC(byte[] inToken, int tOffset, int tLen,
|
||||
byte[] inMsg, int mOffset, int mLen,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
byte[] token = inToken;
|
||||
byte[] msg = inMsg;
|
||||
if ((tOffset != 0) || (tLen != inToken.length)) {
|
||||
token = new byte[tLen];
|
||||
System.arraycopy(inToken, tOffset, token, 0, tLen);
|
||||
}
|
||||
if ((mOffset != 0) || (mLen != inMsg.length)) {
|
||||
msg = new byte[mLen];
|
||||
System.arraycopy(inMsg, mOffset, msg, 0, mLen);
|
||||
}
|
||||
cStub.verifyMic(pContext, token, msg, msgProp);
|
||||
}
|
||||
|
||||
public void verifyMIC(InputStream tokStream, InputStream msgStream,
|
||||
MessageProp msgProp) throws GSSException {
|
||||
try {
|
||||
byte[] msg = new byte[msgStream.available()];
|
||||
int mLength = msgStream.read(msg);
|
||||
byte[] tok = new byte[tokStream.available()];
|
||||
int tLength = tokStream.read(tok);
|
||||
verifyMIC(tok, 0, tLength, msg, 0, mLength, msgProp);
|
||||
} catch (IOException ioe) {
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] export() throws GSSException {
|
||||
byte[] result = cStub.exportContext(pContext);
|
||||
pContext = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void changeFlags(int flagMask, boolean isEnable) {
|
||||
if (isInitiator && pContext == 0) {
|
||||
if (isEnable) {
|
||||
flags |= flagMask;
|
||||
} else {
|
||||
flags &= ~flagMask;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void requestMutualAuth(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_MUTUAL_FLAG, state);
|
||||
}
|
||||
public void requestReplayDet(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_REPLAY_FLAG, state);
|
||||
}
|
||||
public void requestSequenceDet(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_SEQUENCE_FLAG, state);
|
||||
}
|
||||
public void requestCredDeleg(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_DELEG_FLAG, state);
|
||||
}
|
||||
public void requestAnonymity(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_ANON_FLAG, state);
|
||||
}
|
||||
public void requestConf(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_CONF_FLAG, state);
|
||||
}
|
||||
public void requestInteg(boolean state) throws GSSException {
|
||||
changeFlags(GSS_C_INTEG_FLAG, state);
|
||||
}
|
||||
public void requestDelegPolicy(boolean state) throws GSSException {
|
||||
// Not supported, ignore
|
||||
}
|
||||
public void requestLifetime(int lifetime) throws GSSException {
|
||||
if (isInitiator && pContext == 0) {
|
||||
this.lifetime = lifetime;
|
||||
}
|
||||
}
|
||||
public void setChannelBinding(ChannelBinding cb) throws GSSException {
|
||||
if (pContext == 0) {
|
||||
this.cb = cb;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkFlags(int flagMask) {
|
||||
return ((flags & flagMask) != 0);
|
||||
}
|
||||
public boolean getCredDelegState() {
|
||||
return checkFlags(GSS_C_DELEG_FLAG);
|
||||
}
|
||||
public boolean getMutualAuthState() {
|
||||
return checkFlags(GSS_C_MUTUAL_FLAG);
|
||||
}
|
||||
public boolean getReplayDetState() {
|
||||
return checkFlags(GSS_C_REPLAY_FLAG);
|
||||
}
|
||||
public boolean getSequenceDetState() {
|
||||
return checkFlags(GSS_C_SEQUENCE_FLAG);
|
||||
}
|
||||
public boolean getAnonymityState() {
|
||||
return checkFlags(GSS_C_ANON_FLAG);
|
||||
}
|
||||
public boolean isTransferable() throws GSSException {
|
||||
return checkFlags(GSS_C_TRANS_FLAG);
|
||||
}
|
||||
public boolean isProtReady() {
|
||||
return checkFlags(GSS_C_PROT_READY_FLAG);
|
||||
}
|
||||
public boolean getConfState() {
|
||||
return checkFlags(GSS_C_CONF_FLAG);
|
||||
}
|
||||
public boolean getIntegState() {
|
||||
return checkFlags(GSS_C_INTEG_FLAG);
|
||||
}
|
||||
public boolean getDelegPolicyState() {
|
||||
return false;
|
||||
}
|
||||
public int getLifetime() {
|
||||
return cStub.getContextTime(pContext);
|
||||
}
|
||||
public GSSNameSpi getSrcName() throws GSSException {
|
||||
return srcName;
|
||||
}
|
||||
public GSSNameSpi getTargName() throws GSSException {
|
||||
return targetName;
|
||||
}
|
||||
public Oid getMech() throws GSSException {
|
||||
if (isEstablished && actualMech != null) {
|
||||
return actualMech;
|
||||
} else {
|
||||
return cStub.getMech();
|
||||
}
|
||||
}
|
||||
public GSSCredentialSpi getDelegCred() throws GSSException {
|
||||
return delegatedCred;
|
||||
}
|
||||
public boolean isInitiator() {
|
||||
return isInitiator;
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
dispose();
|
||||
}
|
||||
|
||||
public Object inquireSecContext(InquireType type)
|
||||
throws GSSException {
|
||||
throw new GSSException(GSSException.UNAVAILABLE, -1,
|
||||
"Inquire type not supported.");
|
||||
}
|
||||
}
|
||||
183
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSFactory.java
Normal file
183
jdkSrc/jdk8/sun/security/jgss/wrapper/NativeGSSFactory.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2011, 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.wrapper;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.Provider;
|
||||
import java.util.Vector;
|
||||
import org.ietf.jgss.*;
|
||||
import sun.security.jgss.GSSUtil;
|
||||
import sun.security.jgss.GSSCaller;
|
||||
import sun.security.jgss.GSSExceptionImpl;
|
||||
import sun.security.jgss.spi.*;
|
||||
|
||||
/**
|
||||
* JGSS plugin for generic mechanisms provided through native GSS framework.
|
||||
*
|
||||
* @author Valerie Peng
|
||||
*/
|
||||
|
||||
public final class NativeGSSFactory implements MechanismFactory {
|
||||
|
||||
GSSLibStub cStub = null;
|
||||
private final GSSCaller caller;
|
||||
|
||||
private GSSCredElement getCredFromSubject(GSSNameElement name,
|
||||
boolean initiate)
|
||||
throws GSSException {
|
||||
Oid mech = cStub.getMech();
|
||||
Vector<GSSCredElement> creds = GSSUtil.searchSubject
|
||||
(name, mech, initiate, GSSCredElement.class);
|
||||
|
||||
// If Subject is present but no native creds available
|
||||
if (creds != null && creds.isEmpty()) {
|
||||
if (GSSUtil.useSubjectCredsOnly(caller)) {
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
}
|
||||
|
||||
GSSCredElement result = ((creds == null || creds.isEmpty()) ?
|
||||
null : creds.firstElement());
|
||||
// Force permission check before returning the cred to caller
|
||||
if (result != null) {
|
||||
result.doServicePermCheck();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public NativeGSSFactory(GSSCaller caller) {
|
||||
this.caller = caller;
|
||||
// Have to call setMech(Oid) explicitly before calling other
|
||||
// methods. Otherwise, NPE may be thrown unexpectantly
|
||||
}
|
||||
|
||||
public void setMech(Oid mech) throws GSSException {
|
||||
cStub = GSSLibStub.getInstance(mech);
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(String nameStr, Oid nameType)
|
||||
throws GSSException {
|
||||
try {
|
||||
byte[] nameBytes =
|
||||
(nameStr == null ? null : nameStr.getBytes("UTF-8"));
|
||||
return new GSSNameElement(nameBytes, nameType, cStub);
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
// Shouldn't happen
|
||||
throw new GSSExceptionImpl(GSSException.FAILURE, uee);
|
||||
}
|
||||
}
|
||||
|
||||
public GSSNameSpi getNameElement(byte[] name, Oid nameType)
|
||||
throws GSSException {
|
||||
return new GSSNameElement(name, nameType, cStub);
|
||||
}
|
||||
|
||||
public GSSCredentialSpi getCredentialElement(GSSNameSpi name,
|
||||
int initLifetime,
|
||||
int acceptLifetime,
|
||||
int usage)
|
||||
throws GSSException {
|
||||
GSSNameElement nname = null;
|
||||
if (name != null && !(name instanceof GSSNameElement)) {
|
||||
nname = (GSSNameElement)
|
||||
getNameElement(name.toString(), name.getStringNameType());
|
||||
} else nname = (GSSNameElement) name;
|
||||
|
||||
if (usage == GSSCredential.INITIATE_AND_ACCEPT) {
|
||||
// Force separate acqusition of cred element since
|
||||
// MIT's impl does not correctly report NO_CRED error.
|
||||
usage = GSSCredential.INITIATE_ONLY;
|
||||
}
|
||||
|
||||
GSSCredElement credElement =
|
||||
getCredFromSubject(nname, (usage == GSSCredential.INITIATE_ONLY));
|
||||
|
||||
if (credElement == null) {
|
||||
// No cred in the Subject
|
||||
if (usage == GSSCredential.INITIATE_ONLY) {
|
||||
credElement = new GSSCredElement(nname, initLifetime,
|
||||
usage, cStub);
|
||||
} else if (usage == GSSCredential.ACCEPT_ONLY) {
|
||||
if (nname == null) {
|
||||
nname = GSSNameElement.DEF_ACCEPTOR;
|
||||
}
|
||||
credElement = new GSSCredElement(nname, acceptLifetime,
|
||||
usage, cStub);
|
||||
} else {
|
||||
throw new GSSException(GSSException.FAILURE, -1,
|
||||
"Unknown usage mode requested");
|
||||
}
|
||||
}
|
||||
return credElement;
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSNameSpi peer,
|
||||
GSSCredentialSpi myCred,
|
||||
int lifetime)
|
||||
throws GSSException {
|
||||
if (peer == null) {
|
||||
throw new GSSException(GSSException.BAD_NAME);
|
||||
} else if (!(peer instanceof GSSNameElement)) {
|
||||
peer = (GSSNameElement)
|
||||
getNameElement(peer.toString(), peer.getStringNameType());
|
||||
}
|
||||
if (myCred == null) {
|
||||
myCred = getCredFromSubject(null, true);
|
||||
} else if (!(myCred instanceof GSSCredElement)) {
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
return new NativeGSSContext((GSSNameElement) peer,
|
||||
(GSSCredElement) myCred,
|
||||
lifetime, cStub);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(GSSCredentialSpi myCred)
|
||||
throws GSSException {
|
||||
if (myCred == null) {
|
||||
myCred = getCredFromSubject(null, false);
|
||||
} else if (!(myCred instanceof GSSCredElement)) {
|
||||
throw new GSSException(GSSException.NO_CRED);
|
||||
}
|
||||
return new NativeGSSContext((GSSCredElement) myCred, cStub);
|
||||
}
|
||||
|
||||
public GSSContextSpi getMechanismContext(byte[] exportedContext)
|
||||
throws GSSException {
|
||||
return cStub.importContext(exportedContext);
|
||||
}
|
||||
|
||||
public final Oid getMechanismOid() {
|
||||
return cStub.getMech();
|
||||
}
|
||||
|
||||
public Provider getProvider() {
|
||||
return SunNativeProvider.INSTANCE;
|
||||
}
|
||||
|
||||
public Oid[] getNameTypes() throws GSSException {
|
||||
return cStub.inquireNamesForMech();
|
||||
}
|
||||
}
|
||||
134
jdkSrc/jdk8/sun/security/jgss/wrapper/SunNativeProvider.java
Normal file
134
jdkSrc/jdk8/sun/security/jgss/wrapper/SunNativeProvider.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2019, 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.wrapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.security.Provider;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import org.ietf.jgss.Oid;
|
||||
import sun.security.action.PutAllAction;
|
||||
|
||||
/**
|
||||
* Defines the Sun NativeGSS provider for plugging in the
|
||||
* native GSS mechanisms to Java GSS.
|
||||
*
|
||||
* List of supported mechanisms depends on the local
|
||||
* machine configuration.
|
||||
*
|
||||
* @author Yu-Ching Valerie Peng
|
||||
*/
|
||||
|
||||
public final class SunNativeProvider extends Provider {
|
||||
|
||||
private static final long serialVersionUID = -238911724858694204L;
|
||||
|
||||
private static final String NAME = "SunNativeGSS";
|
||||
private static final String INFO = "Sun Native GSS provider";
|
||||
private static final String MF_CLASS =
|
||||
"sun.security.jgss.wrapper.NativeGSSFactory";
|
||||
private static final String LIB_PROP = "sun.security.jgss.lib";
|
||||
private static final String DEBUG_PROP = "sun.security.nativegss.debug";
|
||||
private static HashMap<String, String> MECH_MAP;
|
||||
static final Provider INSTANCE = new SunNativeProvider();
|
||||
static boolean DEBUG;
|
||||
static void debug(String message) {
|
||||
if (DEBUG) {
|
||||
if (message == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
System.out.println(NAME + ": " + message);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
MECH_MAP =
|
||||
AccessController.doPrivileged(
|
||||
new PrivilegedAction<HashMap<String, String>>() {
|
||||
public HashMap<String, String> run() {
|
||||
DEBUG = Boolean.parseBoolean
|
||||
(System.getProperty(DEBUG_PROP));
|
||||
try {
|
||||
System.loadLibrary("j2gss");
|
||||
} catch (Error err) {
|
||||
debug("No j2gss library found!");
|
||||
if (DEBUG) err.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
String gssLibs[];
|
||||
String defaultLib = System.getProperty(LIB_PROP);
|
||||
if (defaultLib == null || defaultLib.trim().equals("")) {
|
||||
String osname = System.getProperty("os.name");
|
||||
if (osname.startsWith("SunOS")) {
|
||||
gssLibs = new String[]{ "libgss.so" };
|
||||
} else if (osname.startsWith("Linux")) {
|
||||
gssLibs = new String[]{
|
||||
"libgssapi.so",
|
||||
"libgssapi_krb5.so",
|
||||
"libgssapi_krb5.so.2",
|
||||
};
|
||||
} else if (osname.contains("OS X")) {
|
||||
gssLibs = new String[]{
|
||||
"libgssapi_krb5.dylib",
|
||||
"/usr/lib/sasl2/libgssapiv2.2.so",
|
||||
};
|
||||
} else if (osname.contains("Windows")) {
|
||||
// Full path needed, DLL is in jre/bin
|
||||
gssLibs = new String[]{ System.getProperty("java.home")
|
||||
+ "\\bin\\sspi_bridge.dll" };
|
||||
} else {
|
||||
gssLibs = new String[0];
|
||||
}
|
||||
} else {
|
||||
gssLibs = new String[]{ defaultLib };
|
||||
}
|
||||
for (String libName: gssLibs) {
|
||||
if (GSSLibStub.init(libName, DEBUG)) {
|
||||
debug("Loaded GSS library: " + libName);
|
||||
Oid[] mechs = GSSLibStub.indicateMechs();
|
||||
HashMap<String,String> map = new HashMap<>();
|
||||
for (int i = 0; i < mechs.length; i++) {
|
||||
debug("Native MF for " + mechs[i]);
|
||||
map.put("GssApiMechanism." + mechs[i],
|
||||
MF_CLASS);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public SunNativeProvider() {
|
||||
/* We are the Sun NativeGSS provider */
|
||||
super(NAME, 1.8d, INFO);
|
||||
|
||||
if (MECH_MAP != null) {
|
||||
AccessController.doPrivileged(new PutAllAction(this, MECH_MAP));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user