631 lines · 23.4 KB · Java
RawDownload
/* * 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);

Lines 1–500 of 631.