Path: blob/master/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/NativeGSSContext.java
41161 views
/*1* Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.jgss.wrapper;2627import org.ietf.jgss.*;28import java.security.Provider;29import sun.security.jgss.GSSHeader;30import sun.security.jgss.GSSUtil;31import sun.security.jgss.GSSExceptionImpl;32import sun.security.jgss.spi.*;33import sun.security.util.DerValue;34import sun.security.util.ObjectIdentifier;35import sun.security.jgss.spnego.NegTokenInit;36import sun.security.jgss.spnego.NegTokenTarg;37import javax.security.auth.kerberos.DelegationPermission;38import java.io.*;394041/**42* This class is essentially a wrapper class for the gss_ctx_id_t43* structure of the native GSS library.44* @author Valerie Peng45* @since 1.646*/47class NativeGSSContext implements GSSContextSpi {4849private static final int GSS_C_DELEG_FLAG = 1;50private static final int GSS_C_MUTUAL_FLAG = 2;51private static final int GSS_C_REPLAY_FLAG = 4;52private static final int GSS_C_SEQUENCE_FLAG = 8;53private static final int GSS_C_CONF_FLAG = 16;54private static final int GSS_C_INTEG_FLAG = 32;55private static final int GSS_C_ANON_FLAG = 64;56private static final int GSS_C_PROT_READY_FLAG = 128;57private static final int GSS_C_TRANS_FLAG = 256;5859private static final int NUM_OF_INQUIRE_VALUES = 6;6061// Warning: The following 9 fields are used by NativeUtil.c62private long pContext = 0; // Pointer to the gss_ctx_id_t structure63private GSSNameElement srcName;64private GSSNameElement targetName;65private boolean isInitiator;66private boolean isEstablished;67private GSSCredElement delegatedCred;68private int flags;69private int lifetime = GSSCredential.DEFAULT_LIFETIME;70private Oid actualMech; // Assigned during context establishment7172private GSSCredElement cred;73private GSSCredElement disposeCred;7475private ChannelBinding cb;76private GSSCredElement disposeDelegatedCred;77private final GSSLibStub cStub;7879private boolean skipDelegPermCheck;80private boolean skipServicePermCheck;8182// Retrieve the (preferred) mech out of SPNEGO tokens, i.e.83// NegTokenInit & NegTokenTarg84private static Oid getMechFromSpNegoToken(byte[] token,85boolean isInitiator)86throws GSSException {87Oid mech = null;88if (isInitiator) {89GSSHeader header = null;90try {91header = new GSSHeader(new ByteArrayInputStream(token));92} catch (IOException ioe) {93throw new GSSExceptionImpl(GSSException.FAILURE, ioe);94}95int negTokenLen = header.getMechTokenLength();96byte[] negToken = new byte[negTokenLen];97System.arraycopy(token, token.length-negTokenLen,98negToken, 0, negToken.length);99100NegTokenInit ntok = new NegTokenInit(negToken);101if (ntok.getMechToken() != null) {102Oid[] mechList = ntok.getMechTypeList();103mech = mechList[0];104}105} else {106NegTokenTarg ntok = new NegTokenTarg(token);107mech = ntok.getSupportedMech();108}109return mech;110}111112// Perform the Service permission check113@SuppressWarnings("removal")114private void doServicePermCheck() throws GSSException {115if (System.getSecurityManager() != null) {116String action = (isInitiator? "initiate" : "accept");117// Need to check Service permission for accessing118// initiator cred for SPNEGO during context establishment119if (GSSUtil.isSpNegoMech(cStub.getMech()) && isInitiator120&& !isEstablished) {121if (srcName == null) {122// Check by creating default initiator KRB5 cred123GSSCredElement tempCred =124new GSSCredElement(null, lifetime,125GSSCredential.INITIATE_ONLY,126GSSLibStub.getInstance(GSSUtil.GSS_KRB5_MECH_OID));127tempCred.dispose();128} else {129String tgsName = Krb5Util.getTGSName(srcName);130Krb5Util.checkServicePermission(tgsName, action);131}132}133String targetStr = targetName.getKrbName();134Krb5Util.checkServicePermission(targetStr, action);135skipServicePermCheck = true;136}137}138139// Perform the Delegation permission check140private void doDelegPermCheck() throws GSSException {141@SuppressWarnings("removal")142SecurityManager sm = System.getSecurityManager();143if (sm != null) {144String targetStr = targetName.getKrbName();145String tgsStr = Krb5Util.getTGSName(targetName);146StringBuilder sb = new StringBuilder("\"");147sb.append(targetStr).append("\" \"");148sb.append(tgsStr).append('\"');149String krbPrincPair = sb.toString();150SunNativeProvider.debug("Checking DelegationPermission (" +151krbPrincPair + ")");152DelegationPermission perm =153new DelegationPermission(krbPrincPair);154sm.checkPermission(perm);155skipDelegPermCheck = true;156}157}158159private byte[] retrieveToken(InputStream is, int mechTokenLen)160throws GSSException {161try {162byte[] result = null;163if (mechTokenLen != -1) {164// Need to add back the GSS header for a complete GSS token165SunNativeProvider.debug("Precomputed mechToken length: " +166mechTokenLen);167GSSHeader gssHeader = new GSSHeader168(ObjectIdentifier.of(cStub.getMech().toString()),169mechTokenLen);170ByteArrayOutputStream baos = new ByteArrayOutputStream(600);171172byte[] mechToken = new byte[mechTokenLen];173int len = is.read(mechToken);174assert(mechTokenLen == len);175gssHeader.encode(baos);176baos.write(mechToken);177result = baos.toByteArray();178} else {179// Must be unparsed GSS token or SPNEGO's NegTokenTarg token180assert(mechTokenLen == -1);181DerValue dv = new DerValue(is);182result = dv.toByteArray();183}184SunNativeProvider.debug("Complete Token length: " +185result.length);186return result;187} catch (IOException ioe) {188throw new GSSExceptionImpl(GSSException.FAILURE, ioe);189}190}191192// Constructor for context initiator193NativeGSSContext(GSSNameElement peer, GSSCredElement myCred,194int time, GSSLibStub stub) throws GSSException {195if (peer == null) {196throw new GSSException(GSSException.FAILURE, 1, "null peer");197}198cStub = stub;199cred = myCred;200disposeCred = null;201targetName = peer;202isInitiator = true;203lifetime = time;204205if (GSSUtil.isKerberosMech(cStub.getMech())) {206doServicePermCheck();207if (cred == null) {208disposeCred = cred =209new GSSCredElement(null, lifetime,210GSSCredential.INITIATE_ONLY, cStub);211}212srcName = cred.getName();213}214}215216// Constructor for context acceptor217NativeGSSContext(GSSCredElement myCred, GSSLibStub stub)218throws GSSException {219cStub = stub;220cred = myCred;221disposeCred = null;222223if (cred != null) targetName = cred.getName();224225isInitiator = false;226// Defer Service permission check for default acceptor cred227// to acceptSecContext()228if (GSSUtil.isKerberosMech(cStub.getMech()) && targetName != null) {229doServicePermCheck();230}231232// srcName and potentially targetName (when myCred is null)233// will be set in GSSLibStub.acceptContext(...)234}235236// Constructor for imported context237// Warning: called by NativeUtil.c238NativeGSSContext(long pCtxt, GSSLibStub stub) throws GSSException {239assert(pContext != 0);240pContext = pCtxt;241cStub = stub;242243// Set everything except cred, cb, delegatedCred244long[] info = cStub.inquireContext(pContext);245if (info.length != NUM_OF_INQUIRE_VALUES) {246throw new RuntimeException("Bug w/ GSSLibStub.inquireContext()");247}248srcName = new GSSNameElement(info[0], cStub);249targetName = new GSSNameElement(info[1], cStub);250isInitiator = (info[2] != 0);251isEstablished = (info[3] != 0);252flags = (int) info[4];253lifetime = (int) info[5];254255// Do Service Permission check when importing SPNEGO context256// just to be safe257Oid mech = cStub.getMech();258if (GSSUtil.isSpNegoMech(mech) || GSSUtil.isKerberosMech(mech)) {259doServicePermCheck();260}261}262263public Provider getProvider() {264return SunNativeProvider.INSTANCE;265}266267public byte[] initSecContext(InputStream is, int mechTokenLen)268throws GSSException {269byte[] outToken = null;270if ((!isEstablished) && (isInitiator)) {271byte[] inToken = null;272// Ignore the specified input stream on the first call273if (pContext != 0) {274inToken = retrieveToken(is, mechTokenLen);275SunNativeProvider.debug("initSecContext=> inToken len=" +276inToken.length);277}278279if (!getCredDelegState()) skipDelegPermCheck = true;280281if (GSSUtil.isKerberosMech(cStub.getMech()) && !skipDelegPermCheck) {282doDelegPermCheck();283}284285long pCred = (cred == null? 0 : cred.pCred);286outToken = cStub.initContext(pCred, targetName.pName,287cb, inToken, this);288SunNativeProvider.debug("initSecContext=> outToken len=" +289(outToken == null ? 0 : outToken.length));290291// Only inspect the token when the permission check292// has not been performed293if (GSSUtil.isSpNegoMech(cStub.getMech()) && outToken != null) {294// WORKAROUND for SEAM bug#6287358295actualMech = getMechFromSpNegoToken(outToken, true);296297if (GSSUtil.isKerberosMech(actualMech)) {298if (!skipServicePermCheck) doServicePermCheck();299if (!skipDelegPermCheck) doDelegPermCheck();300}301}302303if (isEstablished) {304if (srcName == null) {305srcName = new GSSNameElement306(cStub.getContextName(pContext, true), cStub);307}308if (cred == null) {309disposeCred = cred =310new GSSCredElement(srcName, lifetime,311GSSCredential.INITIATE_ONLY, cStub);312}313}314}315return outToken;316}317318public byte[] acceptSecContext(InputStream is, int mechTokenLen)319throws GSSException {320byte[] outToken = null;321if ((!isEstablished) && (!isInitiator)) {322byte[] inToken = retrieveToken(is, mechTokenLen);323SunNativeProvider.debug("acceptSecContext=> inToken len=" +324inToken.length);325long pCred = (cred == null? 0 : cred.pCred);326outToken = cStub.acceptContext(pCred, cb, inToken, this);327disposeDelegatedCred = delegatedCred;328SunNativeProvider.debug("acceptSecContext=> outToken len=" +329(outToken == null? 0 : outToken.length));330331if (targetName == null) {332targetName = new GSSNameElement333(cStub.getContextName(pContext, false), cStub);334// Replace the current default acceptor cred now that335// the context acceptor name is available336if (disposeCred != null) {337disposeCred.dispose();338}339disposeCred = cred =340new GSSCredElement(targetName, lifetime,341GSSCredential.ACCEPT_ONLY, cStub);342}343344// Only inspect token when the permission check has not345// been performed346if (GSSUtil.isSpNegoMech(cStub.getMech()) &&347(outToken != null) && !skipServicePermCheck) {348if (GSSUtil.isKerberosMech(getMechFromSpNegoToken349(outToken, false))) {350doServicePermCheck();351}352}353}354return outToken;355}356357public boolean isEstablished() {358return isEstablished;359}360361public void dispose() throws GSSException {362if (disposeCred != null) {363disposeCred.dispose();364}365if (disposeDelegatedCred != null) {366disposeDelegatedCred.dispose();367}368disposeDelegatedCred = disposeCred = cred = null;369srcName = null;370targetName = null;371delegatedCred = null;372if (pContext != 0) {373pContext = cStub.deleteContext(pContext);374pContext = 0;375}376}377378public int getWrapSizeLimit(int qop, boolean confReq,379int maxTokenSize)380throws GSSException {381return cStub.wrapSizeLimit(pContext, (confReq? 1:0), qop,382maxTokenSize);383}384385public byte[] wrap(byte[] inBuf, int offset, int len,386MessageProp msgProp) throws GSSException {387byte[] data = inBuf;388if ((offset != 0) || (len != inBuf.length)) {389data = new byte[len];390System.arraycopy(inBuf, offset, data, 0, len);391}392return cStub.wrap(pContext, data, msgProp);393}394public void wrap(byte[] inBuf, int offset, int len,395OutputStream os, MessageProp msgProp)396throws GSSException {397try {398byte[] result = wrap(inBuf, offset, len, msgProp);399os.write(result);400} catch (IOException ioe) {401throw new GSSExceptionImpl(GSSException.FAILURE, ioe);402}403}404public int wrap(byte[] inBuf, int inOffset, int len, byte[] outBuf,405int outOffset, MessageProp msgProp)406throws GSSException {407byte[] result = wrap(inBuf, inOffset, len, msgProp);408System.arraycopy(result, 0, outBuf, outOffset, result.length);409return result.length;410}411public void wrap(InputStream inStream, OutputStream outStream,412MessageProp msgProp) throws GSSException {413try {414byte[] data = new byte[inStream.available()];415int length = inStream.read(data);416byte[] token = wrap(data, 0, length, msgProp);417outStream.write(token);418} catch (IOException ioe) {419throw new GSSExceptionImpl(GSSException.FAILURE, ioe);420}421}422423public byte[] unwrap(byte[] inBuf, int offset, int len,424MessageProp msgProp)425throws GSSException {426if ((offset != 0) || (len != inBuf.length)) {427byte[] temp = new byte[len];428System.arraycopy(inBuf, offset, temp, 0, len);429return cStub.unwrap(pContext, temp, msgProp);430} else {431return cStub.unwrap(pContext, inBuf, msgProp);432}433}434public int unwrap(byte[] inBuf, int inOffset, int len,435byte[] outBuf, int outOffset,436MessageProp msgProp) throws GSSException {437byte[] result = null;438if ((inOffset != 0) || (len != inBuf.length)) {439byte[] temp = new byte[len];440System.arraycopy(inBuf, inOffset, temp, 0, len);441result = cStub.unwrap(pContext, temp, msgProp);442} else {443result = cStub.unwrap(pContext, inBuf, msgProp);444}445System.arraycopy(result, 0, outBuf, outOffset, result.length);446return result.length;447}448public void unwrap(InputStream inStream, OutputStream outStream,449MessageProp msgProp) throws GSSException {450try {451byte[] wrapped = new byte[inStream.available()];452int wLength = inStream.read(wrapped);453byte[] data = unwrap(wrapped, 0, wLength, msgProp);454outStream.write(data);455outStream.flush();456} catch (IOException ioe) {457throw new GSSExceptionImpl(GSSException.FAILURE, ioe);458}459}460461public int unwrap(InputStream inStream,462byte[] outBuf, int outOffset,463MessageProp msgProp) throws GSSException {464byte[] wrapped = null;465int wLength = 0;466try {467wrapped = new byte[inStream.available()];468wLength = inStream.read(wrapped);469byte[] result = unwrap(wrapped, 0, wLength, msgProp);470} catch (IOException ioe) {471throw new GSSExceptionImpl(GSSException.FAILURE, ioe);472}473byte[] result = unwrap(wrapped, 0, wLength, msgProp);474System.arraycopy(result, 0, outBuf, outOffset, result.length);475return result.length;476}477478public byte[] getMIC(byte[] in, int offset, int len,479MessageProp msgProp) throws GSSException {480int qop = (msgProp == null? 0:msgProp.getQOP());481byte[] inMsg = in;482if ((offset != 0) || (len != in.length)) {483inMsg = new byte[len];484System.arraycopy(in, offset, inMsg, 0, len);485}486return cStub.getMic(pContext, qop, inMsg);487}488489public void getMIC(InputStream inStream, OutputStream outStream,490MessageProp msgProp) throws GSSException {491try {492int length = 0;493byte[] msg = new byte[inStream.available()];494length = inStream.read(msg);495496byte[] msgToken = getMIC(msg, 0, length, msgProp);497if ((msgToken != null) && msgToken.length != 0) {498outStream.write(msgToken);499}500} catch (IOException ioe) {501throw new GSSExceptionImpl(GSSException.FAILURE, ioe);502}503}504505public void verifyMIC(byte[] inToken, int tOffset, int tLen,506byte[] inMsg, int mOffset, int mLen,507MessageProp msgProp) throws GSSException {508byte[] token = inToken;509byte[] msg = inMsg;510if ((tOffset != 0) || (tLen != inToken.length)) {511token = new byte[tLen];512System.arraycopy(inToken, tOffset, token, 0, tLen);513}514if ((mOffset != 0) || (mLen != inMsg.length)) {515msg = new byte[mLen];516System.arraycopy(inMsg, mOffset, msg, 0, mLen);517}518cStub.verifyMic(pContext, token, msg, msgProp);519}520521public void verifyMIC(InputStream tokStream, InputStream msgStream,522MessageProp msgProp) throws GSSException {523try {524byte[] msg = new byte[msgStream.available()];525int mLength = msgStream.read(msg);526byte[] tok = new byte[tokStream.available()];527int tLength = tokStream.read(tok);528verifyMIC(tok, 0, tLength, msg, 0, mLength, msgProp);529} catch (IOException ioe) {530throw new GSSExceptionImpl(GSSException.FAILURE, ioe);531}532}533534public byte[] export() throws GSSException {535byte[] result = cStub.exportContext(pContext);536pContext = 0;537return result;538}539540private void changeFlags(int flagMask, boolean isEnable) {541if (isInitiator && pContext == 0) {542if (isEnable) {543flags |= flagMask;544} else {545flags &= ~flagMask;546}547}548}549public void requestMutualAuth(boolean state) throws GSSException {550changeFlags(GSS_C_MUTUAL_FLAG, state);551}552public void requestReplayDet(boolean state) throws GSSException {553changeFlags(GSS_C_REPLAY_FLAG, state);554}555public void requestSequenceDet(boolean state) throws GSSException {556changeFlags(GSS_C_SEQUENCE_FLAG, state);557}558public void requestCredDeleg(boolean state) throws GSSException {559changeFlags(GSS_C_DELEG_FLAG, state);560}561public void requestAnonymity(boolean state) throws GSSException {562changeFlags(GSS_C_ANON_FLAG, state);563}564public void requestConf(boolean state) throws GSSException {565changeFlags(GSS_C_CONF_FLAG, state);566}567public void requestInteg(boolean state) throws GSSException {568changeFlags(GSS_C_INTEG_FLAG, state);569}570public void requestDelegPolicy(boolean state) throws GSSException {571// Not supported, ignore572}573public void requestLifetime(int lifetime) throws GSSException {574if (isInitiator && pContext == 0) {575this.lifetime = lifetime;576}577}578public void setChannelBinding(ChannelBinding cb) throws GSSException {579if (pContext == 0) {580this.cb = cb;581}582}583584private boolean checkFlags(int flagMask) {585return ((flags & flagMask) != 0);586}587public boolean getCredDelegState() {588return checkFlags(GSS_C_DELEG_FLAG);589}590public boolean getMutualAuthState() {591return checkFlags(GSS_C_MUTUAL_FLAG);592}593public boolean getReplayDetState() {594return checkFlags(GSS_C_REPLAY_FLAG);595}596public boolean getSequenceDetState() {597return checkFlags(GSS_C_SEQUENCE_FLAG);598}599public boolean getAnonymityState() {600return checkFlags(GSS_C_ANON_FLAG);601}602public boolean isTransferable() throws GSSException {603return checkFlags(GSS_C_TRANS_FLAG);604}605public boolean isProtReady() {606return checkFlags(GSS_C_PROT_READY_FLAG);607}608public boolean getConfState() {609return checkFlags(GSS_C_CONF_FLAG);610}611public boolean getIntegState() {612return checkFlags(GSS_C_INTEG_FLAG);613}614public boolean getDelegPolicyState() {615return false;616}617public int getLifetime() {618return cStub.getContextTime(pContext);619}620public GSSNameSpi getSrcName() throws GSSException {621return srcName;622}623public GSSNameSpi getTargName() throws GSSException {624return targetName;625}626public Oid getMech() throws GSSException {627if (isEstablished && actualMech != null) {628return actualMech;629} else {630return cStub.getMech();631}632}633public GSSCredentialSpi getDelegCred() throws GSSException {634disposeDelegatedCred = null;635return delegatedCred;636}637public boolean isInitiator() {638return isInitiator;639}640641@SuppressWarnings("deprecation")642protected void finalize() throws Throwable {643dispose();644}645646public Object inquireSecContext(String type)647throws GSSException {648throw new GSSException(GSSException.UNAVAILABLE, -1,649"Inquire type not supported.");650}651}652653654