All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.iiop.security.GSSUtils Maven / Gradle / Ivy

There is a newer version: 8.0.0-JDK17-M9
Show newest version
/*
 * Copyright (c) 2022, 2023 Contributors to the Eclipse Foundation
 * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.enterprise.iiop.security;

import com.sun.corba.ee.org.omg.CSI.GSS_NT_Export_Name_OID;
import com.sun.corba.ee.org.omg.CSI.GSS_NT_Scoped_Username_OID;
import com.sun.corba.ee.org.omg.GSSUP.GSSUPMechOID;
import com.sun.logging.LogDomains;

import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.ietf.jgss.GSSException;
import org.ietf.jgss.Oid;

/**
 * @author Sekhar Vajjhala
 * (Almost complete rewrite of an old version)
 */
public class GSSUtils {
    private static final Logger LOG = LogDomains.getLogger(GSSUtils.class, LogDomains.CORBA_LOGGER, false);

    public static final Oid GSSUP_MECH_OID;

    public static final Oid GSS_NT_EXPORT_NAME_OID;

    /*
     * GSS_NT_SCOPED_USERNAME_OID is currently not used by this class. It is defined here for the sake of completeness.
     */
    public static final Oid GSS_NT_SCOPED_USERNAME_OID;

    private static byte[] mech;

    static {

        int i; // index
        Oid x = null;

        /* Construct an ObjectIdentifer by extracting each OID */

        try {
            i = GSSUPMechOID.value.indexOf(':');
            x = new Oid(GSSUPMechOID.value.substring(i + 1));
        } catch (GSSException e) {
            x = null;
            LOG.log(Level.SEVERE, "Invalid OID", e);
        }
        GSSUP_MECH_OID = x;

        try {
            i = GSS_NT_Export_Name_OID.value.indexOf(':');
            x = new Oid(GSS_NT_Export_Name_OID.value.substring(i + 1));
        } catch (GSSException e) {
            x = null;
            LOG.log(Level.SEVERE, "Invalid OID", e);
        }
        GSS_NT_EXPORT_NAME_OID = x;

        try {
            i = GSS_NT_Scoped_Username_OID.value.indexOf(':');
            x = new Oid(GSS_NT_Scoped_Username_OID.value.substring(i + 1));
        } catch (GSSException e) {
            x = null;
            LOG.log(Level.SEVERE, "Invalid OID", e);
        }
        GSS_NT_SCOPED_USERNAME_OID = x;

        try {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "GSSUP_MECH_OID: " + dumpHex(getDER(GSSUP_MECH_OID)));
                LOG.log(Level.FINE, "GSS_NT_EXPORT_NAME_OID: " + dumpHex(getDER(GSS_NT_EXPORT_NAME_OID)));
                LOG.log(Level.FINE, "GSS_NT_SCOPED_USERNAME_OID: " + dumpHex(getDER(GSS_NT_SCOPED_USERNAME_OID)));
            }
        } catch (GSSException e) {
            LOG.log(Level.SEVERE, "Invalid OID", e);
        }

        try {
            mech = GSSUtils.getDER(GSSUtils.GSSUP_MECH_OID);
        } catch (GSSException io) {
            mech = null;
        }
    }

    // Dumps the hex values in the given byte array
    public static String dumpHex(byte[] octets) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < octets.length; i++) {
            if ((i != 0) && ((i % 16) == 0)) {
                result.append("\n    ");
            }
            int b = octets[i];
            if (b < 0) {
                b = 256 + b;
            }
            String hex = Integer.toHexString(b);
            if (hex.length() == 1) {
                hex = "0" + hex;
            }
            result.append(hex).append(' ');
        }

        return result.toString();
    }

    /*
     * Import the exported name from the mechanism independent exported name.
     */

    public static byte[] importName(Oid oid, byte[] externalName) throws GSSException {
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Attempting to import mechanism independent name");
            LOG.log(Level.FINE, dumpHex(externalName));
        }

        GSSException e = new GSSException(GSSException.BAD_NAME);

        if (externalName[0] != 0x04) {
            throw e;
        }

        if (externalName[1] != 0x01) {
            throw e;
        }

        int mechoidlen = ((externalName[2]) << 8) + (externalName[3] & 0xff);

        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Mech OID length = " + mechoidlen);
        }
        if (externalName.length < (4 + mechoidlen + 4)) {
            throw e;
        }

        /*
         * get the mechanism OID and verify it is the same as oid passed as an argument.
         */

        byte[] deroid = new byte[mechoidlen];
        System.arraycopy(externalName, 4, deroid, 0, mechoidlen);
        Oid oid1 = getOID(deroid);
        if (!oid1.equals(oid)) {
            throw e;
        }

        int pos = 4 + mechoidlen;

        int namelen = ((externalName[pos]) << 24) + ((externalName[pos + 1]) << 16) + ((externalName[pos + 2]) << 8)
                + ((externalName[pos + 3]));

        pos += 4; // start of the mechanism specific exported name

        if (externalName.length != (4 + mechoidlen + 4 + namelen)) {
            throw e;
        }

        byte[] name = new byte[externalName.length - pos];
        System.arraycopy(externalName, pos, name, 0, externalName.length - pos);
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Mechanism specific name:");
            LOG.log(Level.FINE, dumpHex(name));
            LOG.log(Level.FINE, "Successfully imported mechanism independent name");
        }
        return name;
    }

    /* verify if exportedName is of object ObjectIdentifier. */

    public static boolean verifyMechOID(Oid oid, byte[] externalName) throws GSSException {
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Attempting to verify mechanism independent name");
            LOG.log(Level.FINE, dumpHex(externalName));
        }

        GSSException e = new GSSException(GSSException.BAD_NAME);

        if (externalName[0] != 0x04) {
            throw e;
        }

        if (externalName[1] != 0x01) {
            throw e;
        }

        int mechoidlen = ((externalName[2]) << 8) + (externalName[3] & 0xff);

        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Mech OID length = " + mechoidlen);
        }
        if (externalName.length < (4 + mechoidlen + 4)) {
            throw e;
        }

        /*
         * get the mechanism OID and verify it is the same as oid passed as an argument.
         */

        byte[] deroid = new byte[mechoidlen];
        System.arraycopy(externalName, 4, deroid, 0, mechoidlen);
        Oid oid1 = getOID(deroid);
        if (!oid1.equals(oid)) {
            return false;
        } else {
            return true;
        }
    }

    /*
     * Generate an exported name as specified in [RFC 2743] section 3.2,
     * "Mechanism-Independent Exported Name Object Format". For convenience, the format of the exported name is reproduced
     * here from [RFC2743] :
     *
     * Format: Bytes 2 0x04 0x01 2 mech OID length (len) len mech OID's DER value 4 exported name len name len exported name
     *
     */
    public static byte[] createExportedName(Oid oid, byte[] extName) throws GSSException {
        byte[] oidDER = getDER(oid);
        int tokensize = 2 + 2 + oidDER.length + 4 + extName.length;

        byte[] token = new byte[tokensize];

        // construct the Exported Name
        int pos = 0;

        token[0] = 0x04;
        token[1] = 0x01;
        token[2] = (byte) (oidDER.length & 0xFF00);
        token[3] = (byte) (oidDER.length & 0x00FF);

        pos = 4;
        System.arraycopy(oidDER, 0, token, pos, oidDER.length);
        pos += oidDER.length;

        int namelen = extName.length;

        token[pos++] = (byte) (namelen & 0xFF000000);
        token[pos++] = (byte) (namelen & 0x00FF0000);
        token[pos++] = (byte) (namelen & 0x0000FF00);
        token[pos++] = (byte) (namelen & 0x000000FF);

        System.arraycopy(extName, 0, token, pos, namelen);

        return token;
    }

    /*
     * Return the DER representation of an ObjectIdentifier. The DER representation is as follows:
     *
     * 0x06 -- Tag for OBJECT IDENTIFIER derOID.length -- length in octets of OID DER value of OID -- written as specified
     * byte the DER representation for an ObjectIdentifier.
     */

    public static byte[] getDER(Oid id) throws GSSException {
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Returning OID in DER format");
            LOG.log(Level.FINE, "    OID = " + id.toString());
        }

        byte[] oid = id.getDER();
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "    DER OID: " + dumpHex(oid));
        }

        return oid;
    }

    /*
     * Return the OID corresponding to an OID represented in DER format as follows:
     *
     * 0x06 -- Tag for OBJECT IDENTIFIER derOID.length -- length in octets of OID DER value of OID -- written as specified
     * byte the DER representation for an ObjectIdentifier.
     */

    public static Oid getOID(byte[] derOID) throws GSSException {
        return new Oid(derOID);
    }

    /*
     * Construct a mechanism level independent token as specified in section 3.1, [RFC 2743]. This consists of a token tag
     * followed byte a mechanism specific token. The format - here for convenience - is as follows:
     *
     * Token Tag Description
     *
     * 0x60 | Tag for [APPLICATION 0] SEQUENCE  | 0x06 | Along with the next two entries
     *  | is a DER encoding of an object  | identifier
     *
     * Mechanism specific token | format defined by the mechanism itself outside of RFC 2743.
     */

    public static byte[] createMechIndToken(Oid mechoid, byte mechtok[]) throws GSSException {
        byte[] deroid = getDER(mechoid);

        byte[] token = new byte[1 // for 0x60
                + getDERLengthSize(deroid.length + mechtok.length) + deroid.length + mechtok.length];
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Going to create a mechanism independent token");
        }
        int index = 0;

        token[index++] = 0x60;

        index = writeDERLength(token, index, deroid.length + mechtok.length);

        System.arraycopy(deroid, 0, token, index, deroid.length);

        index += deroid.length;
        System.arraycopy(mechtok, 0, token, index, mechtok.length);

        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Mechanism independent token created: ");
            LOG.log(Level.FINE, dumpHex(token));
        }

        return token;
    }

    /*
     * Retrieve a mechanism specific token from a mechanism independent token. The format of a mechanism independent token
     * is specified in section 3.1, [RFC 2743].
     */

    public static byte[] getMechToken(Oid oid, byte[] token) {
        byte[] mechtoken = null;
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Received mechanism independent token: ");
            LOG.log(Level.FINE, dumpHex(token));
        }

        try {
            int index = verifyTokenHeader(oid, token);
            int mechtoklen = token.length - index;
            mechtoken = new byte[mechtoklen];
            System.arraycopy(token, index, mechtoken, 0, mechtoklen);
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "Mechanism specific token : ");
                LOG.log(Level.FINE, dumpHex(mechtoken));
            }
        } catch (GSSException e) {
            LOG.log(Level.SEVERE, "Invalid token header", e);
        }
        return mechtoken;
    }

    /*
     * Verfies the header of a mechanism independent token. The header must be as specified in RFC 2743, section 3.1. The
     * header must contain an object identifier specified by the first parameter.
     *
     * If the header is well formed, then the starting position of the mechanism specific token within the token is
     * returned.
     *
     * If the header is mal formed, then an exception is thrown.
     */

    private static int verifyTokenHeader(Oid oid, byte[] token) throws GSSException {
        int index = 0;
        LOG.log(Level.FINE, "Attempting to verify tokenheader in the mechanism independent token.");

        // verify header
        if (token[index++] != 0x60) {
            throw new GSSException(GSSException.DEFECTIVE_TOKEN);
        }

        int toklen = readDERLength(token, index); // derOID length + token length

        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Mech OID length + Mech specific length = " + toklen);
        }
        index += getDERLengthSize(toklen);
        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Mechanism OID index : " + index);
        }

        if (token[index] != 0x06) {
            throw new GSSException(GSSException.DEFECTIVE_TOKEN);
        }

        // add first two bytes to the MECH_OID_LEN
        int oidlen = token[index+1] + 2;
        byte[] buf = new byte[oidlen];

        System.arraycopy(token, index, buf, 0, oidlen);

        Oid mechoid = getOID(buf);

        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Comparing mech OID in token with the expected mech OID");
            LOG.log(Level.FINE, "mech OID: " + dumpHex(getDER(mechoid)));
            LOG.log(Level.FINE, "expected mech OID: " + dumpHex(getDER(oid)));
        }

        if (!mechoid.equals(oid)) {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "mech OID in token does not match expected mech OID");
            }
            throw new GSSException(GSSException.DEFECTIVE_TOKEN);
        }
        int mechoidlen = getDER(oid).length;

        if (LOG.isLoggable(Level.FINE)) {
            LOG.log(Level.FINE, "Mechanism specific token index : " + index + mechoidlen);
            LOG.log(Level.FINE, "Successfully verified header in the mechanism independent token.");
        }
        return (index + mechoidlen); // starting position of mech specific token
    }

    static int getDERLengthSize(int length) {
        if (length < (1 << 7)) {
            return (1);
        } else if (length < (1 << 8)) {
            return (2);
        } else if (length < (1 << 16)) {
            return (3);
        } else if (length < (1 << 24)) {
            return (4);
        } else {
            return (5);
        }
    }

    static int writeDERLength(byte[] token, int index, int length) {
        if (length < (1 << 7)) {
            token[index++] = (byte) length;
        } else {
            token[index++] = (byte) (getDERLengthSize(length) + 127);
            if (length >= (1 << 24)) {
                token[index++] = (byte) (length >> 24);
            }
            if (length >= (1 << 16)) {
                token[index++] = (byte) ((length >> 16) & 0xff);
            }
            if (length >= (1 << 8)) {
                token[index++] = (byte) ((length >> 8) & 0xff);
            }
            token[index++] = (byte) (length & 0xff);
        }
        return (index);
    }

    static int readDERLength(byte[] token, int index) {
        byte sf;
        int ret = 0;
        int nooctets;

        sf = token[index++];

        if ((sf & 0x80) == 0x80) { // value > 128
            // bit 8 is 1 ; bits 0-7 of first bye is the number of octets
            nooctets = (sf & 0x7f); // remove the 8th bit
            for (; nooctets != 0; nooctets--) {
                ret = (ret << 8) + (token[index++] & 0x00FF);
            }
        } else { // value > 128
            ret = sf;
        }

        return (ret);
    }

    /**
     * Return the ASN.1 encoded representation of a GSS mechanism identifier. Currently only the GSSUP Mechanism is
     * supported.
     */
    public static byte[] getMechanism() {
        byte[] mechCopy = Arrays.copyOf(mech, mech.length);
        return mechCopy;
    }

    public static void main(String[] args) {
        try {
            byte[] len = new byte[3];
            len[0] = (byte) 0x82;
            len[1] = (byte) 0x01;
            len[2] = (byte) 0xd3;
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "Length byte array : " + dumpHex(len));
                LOG.log(Level.FINE, " Der length = " + readDERLength(len, 0));
            }
            String name = "default";
            byte[] externalName = createExportedName(GSSUtils.GSSUP_MECH_OID, name.getBytes());
            byte[] m = importName(GSSUtils.GSSUP_MECH_OID, externalName);
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "BAR:" + new String(m));
            }
            String msg = "dummy_gss_export_sec_context";
            byte[] foo = createMechIndToken(GSSUtils.GSSUP_MECH_OID, msg.getBytes());
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "FOO:" + dumpHex(foo));
            }
            byte[] msg1 = getMechToken(GSSUtils.GSSUP_MECH_OID, foo);
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "BAR:" + dumpHex(msg1));
                LOG.log(Level.FINE, "BAR string: " + new String(msg1));
            }
        } catch (Exception e) {
            LOG.log(Level.SEVERE, "main crashed", e);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy