/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.wildfly.iiop.openjdk.csiv2; import java.nio.charset.StandardCharsets; import org.ietf.jgss.GSSException; import org.ietf.jgss.Oid; import org.jboss.metadata.ejb.jboss.IORASContextMetaData; import org.jboss.metadata.ejb.jboss.IORSASContextMetaData; import org.jboss.metadata.ejb.jboss.IORSecurityConfigMetaData; import org.jboss.metadata.ejb.jboss.IORTransportConfigMetaData; import org.omg.CORBA.Any; import org.omg.CORBA.BAD_PARAM; import org.omg.CORBA.ORB; import org.omg.CSI.ITTAnonymous; import org.omg.CSI.ITTDistinguishedName; import org.omg.CSI.ITTPrincipalName; import org.omg.CSI.ITTX509CertChain; import org.omg.CSIIOP.AS_ContextSec; import org.omg.CSIIOP.CompoundSecMech; import org.omg.CSIIOP.CompoundSecMechList; import org.omg.CSIIOP.CompoundSecMechListHelper; import org.omg.CSIIOP.Confidentiality; import org.omg.CSIIOP.DetectMisordering; import org.omg.CSIIOP.DetectReplay; import org.omg.CSIIOP.EstablishTrustInClient; import org.omg.CSIIOP.EstablishTrustInTarget; import org.omg.CSIIOP.IdentityAssertion; import org.omg.CSIIOP.Integrity; import org.omg.CSIIOP.SAS_ContextSec; import org.omg.CSIIOP.ServiceConfiguration; import org.omg.CSIIOP.TAG_TLS_SEC_TRANS; import org.omg.CSIIOP.TLS_SEC_TRANS; import org.omg.CSIIOP.TLS_SEC_TRANSHelper; import org.omg.CSIIOP.TransportAddress; import org.omg.GSSUP.GSSUPMechOID; import org.omg.GSSUP.InitialContextToken; import org.omg.GSSUP.InitialContextTokenHelper; import org.omg.IOP.Codec; import org.omg.IOP.TAG_CSI_SEC_MECH_LIST; import org.omg.IOP.TAG_NULL_TAG; import org.omg.IOP.TaggedComponent; import org.omg.IOP.CodecPackage.InvalidTypeForEncoding; import org.omg.PortableInterceptor.ClientRequestInfo; import org.omg.SSLIOP.SSL; import org.omg.SSLIOP.SSLHelper; import org.omg.SSLIOP.TAG_SSL_SEC_TRANS; import org.wildfly.iiop.openjdk.Constants; import org.wildfly.iiop.openjdk.logging.IIOPLogger; import org.wildfly.iiop.openjdk.service.CorbaORBService; /** * <p> * This class defines utility methods for creating, comparing, encoding and decoding CSIv2 components. * </p> * * @author <a href="mailto:reverbel@ime.usp.br">Francisco Reverbel</a> * @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a> */ public final class CSIv2Util { /** * DER-encoded ASN.1 representation of the GSSUP mechanism OID. */ private static final byte[] gssUpMechOidArray = createGSSUPMechOID(); /** * <p> * Private constructor to implement the singleton pattern. * </p> */ private CSIv2Util() { } /** * <p> * Make a deep copy of an {@code IOP:TaggedComponent}. * </p> * * @param tc the {@code TaggedComponent} to be copied. * @return a reference to the created copy. */ public static TaggedComponent createCopy(TaggedComponent tc) { TaggedComponent copy = null; if (tc != null) { byte[] buf = new byte[tc.component_data.length]; System.arraycopy(tc.component_data, 0, buf, 0, tc.component_data.length); copy = new TaggedComponent(tc.tag, buf); } return copy; } /** * <p> * Return a top-level {@code IOP::TaggedComponent} to be stuffed into an IOR, containing a structure * {@code SSLIOP::SSL}, tagged as {@code TAG_SSL_SEC_TRANS}. * </p> * <p> * Should be called with non-null metadata, in which case we probably don't want to include security info in the IOR. * </p> * * @param metadata the metadata object that contains the SSL configuration info. * @param codec the {@code Codec} used to encode the SSL component. * @param sslPort an {@code int} representing the SSL port. * @param orb a reference to the running {@code ORB}. * @return a {@code TaggedComponent} representing the encoded SSL component. */ public static TaggedComponent createSSLTaggedComponent(IORSecurityConfigMetaData metadata, Codec codec, int sslPort, ORB orb) { if (metadata == null) { IIOPLogger.ROOT_LOGGER.debug("Method createSSLTaggedComponent() called with null metadata"); return null; } if (sslPort == 0) { // no support for transport security. return null; } TaggedComponent tc; try { int supports = createTargetSupports(metadata.getTransportConfig()); int requires = createTargetRequires(metadata.getTransportConfig()); SSL ssl = new SSL((short) supports, (short) requires, (short) sslPort); Any any = orb.create_any(); SSLHelper.insert(any, ssl); byte[] componentData = codec.encode_value(any); tc = new TaggedComponent(TAG_SSL_SEC_TRANS.value, componentData); } catch (InvalidTypeForEncoding e) { throw IIOPLogger.ROOT_LOGGER.unexpectedException(e); } return tc; } /** * <p> * Return a top-level {@code IOP:TaggedComponent} to be stuffed into an IOR, containing a {@code org.omg.CSIIOP}. * {@code CompoundSecMechList}, tagged as {@code TAG_CSI_SEC_MECH_LIST}. Only one such component can exist inside * an IOR. * </p> * <p> * Should be called with non-null metadata, in which case we probably don't want to include security info in the IOR. * </p> * * @param metadata the metadata object that contains the CSIv2 security configuration info. * @param codec the {@code Codec} used to encode the CSIv2 security component. * @param sslPort an {@code int} representing the SSL port. * @param orb a reference to the running {@code ORB}. * @return a {@code TaggedComponent} representing the encoded CSIv2 security component. */ public static TaggedComponent createSecurityTaggedComponent(IORSecurityConfigMetaData metadata, Codec codec, int sslPort, ORB orb) { if (metadata == null) { IIOPLogger.ROOT_LOGGER.debug("Method createSecurityTaggedComponent() called with null metadata"); return null; } TaggedComponent tc; // get the the supported security mechanisms. CompoundSecMech[] mechList = createCompoundSecMechanisms(metadata, codec, sslPort, orb); // the above is wrapped into a org.omg.CSIIOP.CompoundSecMechList structure, which is NOT a CompoundSecMech[]. // we don't support stateful/reusable security contexts (false). CompoundSecMechList csmList = new CompoundSecMechList(false, mechList); // finally, the CompoundSecMechList must be encoded as a TaggedComponent try { Any any = orb.create_any(); CompoundSecMechListHelper.insert(any, csmList); byte[] b = codec.encode_value(any); tc = new TaggedComponent(TAG_CSI_SEC_MECH_LIST.value, b); } catch (InvalidTypeForEncoding e) { throw IIOPLogger.ROOT_LOGGER.unexpectedException(e); } return tc; } /** * <p> * Create a {@code org.omg.CSIIOP.CompoundSecMechanisms} which is a sequence of {@code CompoundSecMech}. Here we only * support one security mechanism. * </p> * * @param metadata the metadata object that contains the CSIv2 security configuration info. * @param codec the {@code Codec} used to encode the CSIv2 security component. * @param sslPort an {@code int} representing the SSL port. * @param orb a reference to the running {@code ORB}. * @return the constructed {@code CompoundSecMech} array. */ public static CompoundSecMech[] createCompoundSecMechanisms(IORSecurityConfigMetaData metadata, Codec codec, int sslPort, ORB orb) { // support just 1 security mechanism for now (and ever). CompoundSecMech[] csmList = new CompoundSecMech[1]; // a CompoundSecMech contains: target_requires, transport_mech, as_context_mech, sas_context_mech. TaggedComponent transport_mech = createTransportMech(metadata.getTransportConfig(), codec, sslPort, orb); // create AS Context. AS_ContextSec asContext = createAuthenticationServiceContext(metadata); // create SAS Context. SAS_ContextSec sasContext = createSecureAttributeServiceContext(metadata); // create target_requires bit field (AssociationOption) can't read directly the transport_mech TaggedComponent. int target_requires = createTargetRequires(metadata.getTransportConfig()) | asContext.target_requires | sasContext.target_requires; CompoundSecMech csm = new CompoundSecMech((short) target_requires, transport_mech, asContext, sasContext); csmList[0] = csm; return csmList; } /** * <p> * Create the Secure Attribute Service (SAS) context included in a {@code CompoundSecMech} definition. * </p> * * @param metadata the metadata object that contains the CSIv2 security configuration info. * @return the constructed {@code SAS_ContextSec} instance. */ public static SAS_ContextSec createSecureAttributeServiceContext(IORSecurityConfigMetaData metadata) { SAS_ContextSec context; // context contains target_supports, target_requires, privilige_authorities, supported_naming_mechanisms, supported_identity_types. int support = 0; int require = 0; ServiceConfiguration[] privilAuth = new ServiceConfiguration[0]; byte[][] supNamMechs = {}; int supIdenTypes = 0; // 0 means ITTAbsent // the the SasContext metadata. IORSASContextMetaData sasMeta = metadata.getSasContext(); // if no SAS context metadata, or caller propagation is not supported, we return with a more or less empty sas context. if (sasMeta == null || sasMeta.getCallerPropagation().equals(IORSASContextMetaData.CALLER_PROPAGATION_NONE)) { context = new SAS_ContextSec((short) support, (short) require, privilAuth, supNamMechs, supIdenTypes); } else { support = IdentityAssertion.value; // supporting GSSUP (username/password) naming mechanism. byte[] upMech = createGSSUPMechOID(); supNamMechs = new byte[1][upMech.length]; System.arraycopy(upMech, 0, supNamMechs[0], 0, upMech.length); // since we support IdentityAssertion we need to specify supported identity types. CTS says we need them all supIdenTypes = ITTAnonymous.value | ITTPrincipalName.value | ITTX509CertChain.value | ITTDistinguishedName.value; context = new SAS_ContextSec((short) support, (short) require, privilAuth, supNamMechs, supIdenTypes); } return context; } /** * <p> * Create the client Authentication Service (AS) context included in a {@code CompoundSecMech} definition. * </p> * * @param metadata the metadata object that contains the CSIv2 security configuration info. * @return the constructed {@code AS_ContextSec} instance. */ public static AS_ContextSec createAuthenticationServiceContext(IORSecurityConfigMetaData metadata) { AS_ContextSec context; // the content of the context. int support = 0; int require = 0; byte[] clientAuthMech = {}; byte[] targetName = {}; IORASContextMetaData asMeta = metadata.getAsContext(); // if no AS context metatada exists, or authentication method "none" is specified, we can produce an empty AS context. if (asMeta == null || asMeta.getAuthMethod().equals(IORASContextMetaData.AUTH_METHOD_NONE)) { context = new AS_ContextSec((short) support, (short) require, clientAuthMech, targetName); } else { // we do support. support = EstablishTrustInClient.value; // required depends on the metadata. if (asMeta.isRequired()) { require = EstablishTrustInClient.value; } // we only support GSSUP authentication method. clientAuthMech = createGSSUPMechOID(); // finally, encode the "realm" name as a CSI.GSS_NT_ExportedName. // clientAuthMech should contain the DER encoded GSSUPMechOID at this point. String realm = asMeta.getRealm(); targetName = createGSSExportedName(clientAuthMech, realm.getBytes()); context = new AS_ContextSec((short) support, (short) require, clientAuthMech, targetName); } return context; } /** * <p> * Create a transport mechanism {@code TaggedComponent} to be stuffed into a {@code CompoundSecMech}. * </p> * <p> * If no {@code TransportConfig} metadata is specified, or ssl port is negative, or the specified metadata indicates * that transport config is not supported, then a {@code TAG_NULL_TAG} (empty) {@code TaggedComponent} will be returned. * </p> * <p> * Otherwise a {@code org.omg.CSIIOP.TLS_SEC_TRANS}, tagged as {@code TAG_TLS_SEC_TRANS} will be returned, indicating support * for TLS/SSL as a CSIv2 transport mechanism. * </p> * <p> * Multiple {@code TransportAddress} may be included in the SSL info (host/port pairs), but we only include one. * </p> * * @param tconfig the transport configuration metadata. * @param codec the {@code Codec} used to encode the transport configuration. * @param sslPort an {@code int} representing the SSL port. * @param orb a reference to the running {@code ORB}. * @return the constructed {@code TaggedComponent}. */ public static TaggedComponent createTransportMech(IORTransportConfigMetaData tconfig, Codec codec, int sslPort, ORB orb) { TaggedComponent tc; // what we support and require as a target. int support = 0; int require = 0; if (tconfig != null) { require = createTargetRequires(tconfig); support = createTargetSupports(tconfig); } if (tconfig == null || support == 0 || sslPort == 0) { // no support for transport security. tc = new TaggedComponent(TAG_NULL_TAG.value, new byte[0]); } else { // my ip address. String host = CorbaORBService.getORBProperty(Constants.ORB_ADDRESS); // this will create only one transport address. TransportAddress[] taList = createTransportAddress(host, sslPort); TLS_SEC_TRANS tst = new TLS_SEC_TRANS((short) support, (short) require, taList); // The tricky part, we must encode TLS_SEC_TRANS into an octet sequence. try { Any any = orb.create_any(); TLS_SEC_TRANSHelper.insert(any, tst); byte[] b = codec.encode_value(any); tc = new TaggedComponent(TAG_TLS_SEC_TRANS.value, b); } catch (InvalidTypeForEncoding e) { throw IIOPLogger.ROOT_LOGGER.unexpectedException(e); } } return tc; } /** * <p> * Create a {@code TransportAddress[]} with a single {@code TransportAddress}. * </p> * * @param host a {@code String} representing the address host. * @param port an {@code int} representing the address port. * @return the constructed {@code TransportAddress} array. */ public static TransportAddress[] createTransportAddress(String host, int port) { // idl type is unsigned sort, so we need this trick short short_port = (port > 32767) ? (short) (port - 65536) : (short) port; TransportAddress ta = new TransportAddress(host, short_port); TransportAddress[] taList = new TransportAddress[1]; taList[0] = ta; return taList; } /** * <p> * Create the bitmask of what the target requires. * </p> * * @param tc the transport configuration metadata. * @return an {@code int} representing the transport mechanism required by the target. */ public static int createTargetRequires(IORTransportConfigMetaData tc) { int requires = 0; if (tc != null) { if (tc.getIntegrity().equals(IORTransportConfigMetaData.INTEGRITY_REQUIRED)) { requires = requires | Integrity.value; } if (tc.getConfidentiality().equals(IORTransportConfigMetaData.CONFIDENTIALITY_REQUIRED)) { requires = requires | Confidentiality.value; } if (tc.getDetectMisordering().equalsIgnoreCase(IORTransportConfigMetaData.DETECT_MISORDERING_REQUIRED)) { requires = requires | DetectMisordering.value; } if (tc.getDetectReplay().equalsIgnoreCase(IORTransportConfigMetaData.DETECT_REPLAY_REQUIRED)) { requires = requires | DetectReplay.value; } // no EstablishTrustInTarget required - client decides if (tc.getEstablishTrustInClient().equals(IORTransportConfigMetaData.ESTABLISH_TRUST_IN_CLIENT_REQUIRED)) { requires = requires | EstablishTrustInClient.value; } } return requires; } /** * <p> * Create the bitmask of what the target supports. * </p> * * @param tc the transport configuration metadata. * @return an {@code int} representing the transport mechanisms supported by the target. */ public static int createTargetSupports(IORTransportConfigMetaData tc) { int supports = 0; if (tc != null) { if (!tc.getIntegrity().equals(IORTransportConfigMetaData.INTEGRITY_NONE)) { supports = supports | Integrity.value; } if (!tc.getConfidentiality().equals(IORTransportConfigMetaData.CONFIDENTIALITY_NONE)) { supports = supports | Confidentiality.value; } if (!tc.getDetectMisordering().equalsIgnoreCase(IORTransportConfigMetaData.DETECT_MISORDERING_NONE)) { supports = supports | DetectMisordering.value; } if (!tc.getDetectReplay().equalsIgnoreCase(IORTransportConfigMetaData.DETECT_REPLAY_NONE)) { supports = supports | DetectReplay.value; } if (!tc.getEstablishTrustInTarget().equals(IORTransportConfigMetaData.ESTABLISH_TRUST_IN_TARGET_NONE)) { supports = supports | EstablishTrustInTarget.value; } if (!tc.getEstablishTrustInClient().equals(IORTransportConfigMetaData.ESTABLISH_TRUST_IN_CLIENT_NONE)) { supports = supports | EstablishTrustInClient.value; } } return supports; } /** * <p> * Create an ASN.1, DER encoded representation for the GSSUP OID mechanism. * </p> * * @return the DER encoded representation of the GSSUP OID. */ public static byte[] createGSSUPMechOID() { // kudos to org.ietf.jgss.Oid for the Oid utility need to strip the "oid:" part of the GSSUPMechOID first. byte[] retval = {}; try { Oid oid = new Oid(GSSUPMechOID.value.substring(4)); retval = oid.getDER(); } catch (GSSException e) { IIOPLogger.ROOT_LOGGER.caughtExceptionEncodingGSSUPMechOID(e); } return retval; } /** * <p/> * Generate an exported name as specified in [RFC 2743], section 3.2 copied below: * <p/> * 3.2: Mechanism-Independent Exported Name Object Format * <p/> * This section specifies a mechanism-independent level of encapsulating representation for names exported via the * GSS_Export_name() call, including an object identifier representing the exporting mechanism. The format of names * encapsulated via this representation shall be defined within individual mechanism drafts. The Object Identifier * value to indicate names of this type is defined in Section 4.7 of this document. * <p/> * No name type OID is included in this mechanism-independent level of format definition, since (depending on * individual mechanism specifications) the enclosed name may be implicitly typed or may be explicitly typed using * a means other than OID encoding. * <p/> * The bytes within MECH_OID_LEN and NAME_LEN elements are represented most significant byte first (equivalently, * in IP network byte order). * <p/> * Length Name Description * <p/> * 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. * <p/> * A concrete example of the contents of an exported name object, derived from the Kerberos Version 5 mechanism, is * as follows: * <p/> * 04 01 00 0B 06 09 2A 86 48 86 F7 12 01 02 02 hx xx xx xl pp qq ... zz * <p/> * ... * * @param oid the DER encoded OID. * @param name the name to be converted to {@code GSSExportedName}. * @return a {@code byte[]} representing the exported name. */ public static byte[] createGSSExportedName(byte[] oid, byte[] name) { int olen = oid.length; int nlen = name.length; // size according to spec. int size = 2 + 2 + olen + 4 + nlen; // allocate space for the exported name. byte[] buf = new byte[size]; // index. int i = 0; // standard header. buf[i++] = 0x04; buf[i++] = 0x01; // encode oid length. buf[i++] = (byte) (olen & 0xFF00); buf[i++] = (byte) (olen & 0x00FF); // copy the oid in the exported name buffer. System.arraycopy(oid, 0, buf, i, olen); i += olen; // encode the name length in the exported buffer. buf[i++] = (byte) (nlen & 0xFF000000); buf[i++] = (byte) (nlen & 0x00FF0000); buf[i++] = (byte) (nlen & 0x0000FF00); buf[i++] = (byte) (nlen & 0x000000FF); // finally, copy the name bytes. System.arraycopy(name, 0, buf, i, nlen); return buf; } /** * <p> * ASN.1-encode an {@code InitialContextToken} as defined in RFC 2743, Section 3.1, "Mechanism-Independent Token * Format", pp. 81-82. The encoded token contains the ASN.1 tag 0x60, followed by a token length (which is itself * stored in a variable-length format and takes 1 to 5 bytes), the GSSUP mechanism identifier, and a mechanism-specific * token, which in this case is a CDR encapsulation of the GSSUP {@code InitialContextToken} in the {@code authToken} * parameter. * </p> * * @param authToken the {@code InitialContextToken} to be encoded. * @param codec the {@code Codec} used to encode the token. * @return a {@code byte[]} representing the encoded token. */ public static byte[] encodeInitialContextToken(InitialContextToken authToken, Codec codec) { byte[] out; Any any = ORB.init().create_any(); InitialContextTokenHelper.insert(any, authToken); try { out = codec.encode_value(any); } catch (Exception e) { return new byte[0]; } int length = out.length + gssUpMechOidArray.length; int n; if (length < (1 << 7)) { n = 0; } else if (length < (1 << 8)) { n = 1; } else if (length < (1 << 16)) { n = 2; } else if (length < (1 << 24)) { n = 3; } else {// if (length < (1 << 32)) n = 4; } byte[] encodedToken = new byte[2 + n + length]; encodedToken[0] = 0x60; if (n == 0) { encodedToken[1] = (byte) length; } else { encodedToken[1] = (byte) (n | 0x80); switch (n) { case 1: encodedToken[2] = (byte) length; break; case 2: encodedToken[2] = (byte) (length >> 8); encodedToken[3] = (byte) length; break; case 3: encodedToken[2] = (byte) (length >> 16); encodedToken[3] = (byte) (length >> 8); encodedToken[4] = (byte) length; break; default: // case 4: encodedToken[2] = (byte) (length >> 24); encodedToken[3] = (byte) (length >> 16); encodedToken[4] = (byte) (length >> 8); encodedToken[5] = (byte) length; } } System.arraycopy(gssUpMechOidArray, 0, encodedToken, 2 + n, gssUpMechOidArray.length); System.arraycopy(out, 0, encodedToken, 2 + n + gssUpMechOidArray.length, out.length); return encodedToken; } /** * <p> * Decodes an ASN.1-encoded {@code InitialContextToken}. See {@code encodeInitialContextToken} for a description of * the encoded token format. * </p> * * @param encodedToken the encoded token. * @param codec the {@code Codec} used to decode the token. * @return the decoded {@code InitialContextToken} instance. * @see #encodeInitialContextToken(org.omg.GSSUP.InitialContextToken, org.omg.IOP.Codec) */ public static InitialContextToken decodeInitialContextToken(byte[] encodedToken, Codec codec) { if (encodedToken[0] != 0x60) return null; int encodedLength = 0; int n = 0; if (encodedToken[1] >= 0) encodedLength = encodedToken[1]; else { n = encodedToken[1] & 0x7F; for (int i = 1; i <= n; i++) { encodedLength += (encodedToken[1 + i] & 0xFF) << (n - i) * 8; } } int length = encodedLength - gssUpMechOidArray.length; byte[] encodedInitialContextToken = new byte[length]; System.arraycopy(encodedToken, 2 + n + gssUpMechOidArray.length, encodedInitialContextToken, 0, length); Any any; try { any = codec.decode_value(encodedInitialContextToken, InitialContextTokenHelper.type()); } catch (Exception e) { return null; } return InitialContextTokenHelper.extract(any); } /** * <p> * ASN.1-encodes a GSS exported name with the GSSUP mechanism OID. See {@code createGSSExportedName} for a * description of the encoding format. * </p> * * @param name the exported name to be encoded. * @return a {@code byte[]} representing the encoded exported name. * @see #createGSSExportedName(byte[], byte[]) */ public static byte[] encodeGssExportedName(byte[] name) { return createGSSExportedName(gssUpMechOidArray, name); } /** * <p> * Decodes a GSS exported name that has been encoded with the GSSUP mechanism OID. See {@code createGSSExportedName} * for a description of the encoding format. * </p> * * @param encodedName the encoded exported name. * @return a {@code byte[]} representing the decoded exported name. * @see #createGSSExportedName(byte[], byte[]) */ public static byte[] decodeGssExportedName(byte[] encodedName) { if (encodedName[0] != 0x04 || encodedName[1] != 0x01) return null; int mechOidLength = (encodedName[2] & 0xFF) << 8; //MECH_OID_LEN mechOidLength += (encodedName[3] & 0xFF); // MECH_OID_LEN byte[] oidArray = new byte[mechOidLength]; System.arraycopy(encodedName, 4, oidArray, 0, mechOidLength); for (int i = 0; i < mechOidLength; i++) { if (gssUpMechOidArray[i] != oidArray[i]) { return null; } } int offset = 4 + mechOidLength; int nameLength = (encodedName[offset] & 0xFF) << 24; nameLength += (encodedName[++offset] & 0xFF) << 16; nameLength += (encodedName[++offset] & 0xFF) << 8; nameLength += (encodedName[++offset] & 0xFF); byte[] name = new byte[nameLength]; System.arraycopy(encodedName, ++offset, name, 0, nameLength); return name; } /** * <p> * Helper method to be called from a client request interceptor. The {@code ri} parameter refers to the current * request. This method returns the first {@code CompoundSecMech} found in the target IOR such that * <ul> * <li>all {@code CompoundSecMech} requirements are satisfied by the options in the {@code clientSupports} * parameter, and</li> * <li>every requirement in the {@code clientRequires} parameter is satisfied by the {@code CompoundSecMech}. * </li> * </ul> * The method returns null if the target IOR contains no {@code CompoundSecMech}s or if no matching * {@code CompoundSecMech} is found. * </p> * <p> * Since this method is intended to be called from a client request interceptor, it converts unexpected exceptions * into {@code MARSHAL} exceptions. * </p> * * @param ri a reference to the current {@code ClientRequestInfo}. * @param codec the {@code Codec} used to decode the CSIv2 components. * @param clientSupports the client supported transport options that must be satisfied by the {@code CompoundSecMech}. * @param clientRequires the client required transport options that must be satisfied by the {@code CompoundSecMech}. * @return the {@code CompoundSecMech} instance that satisfies all client options, or {@code null} if no such object * can be found. */ public static CompoundSecMech getMatchingSecurityMech(ClientRequestInfo ri, Codec codec, short clientSupports, short clientRequires) { CompoundSecMechList csmList; try { TaggedComponent tc = ri.get_effective_component(org.omg.IOP.TAG_CSI_SEC_MECH_LIST.value); Any any = codec.decode_value(tc.component_data, CompoundSecMechListHelper.type()); csmList = CompoundSecMechListHelper.extract(any); // look for the first matching security mech. for (int i = 0; i < csmList.mechanism_list.length; i++) { CompoundSecMech securityMech = csmList.mechanism_list[i]; AS_ContextSec authConfig = securityMech.as_context_mech; if ((EstablishTrustInTarget.value & (clientRequires ^ authConfig.target_supports) & ~authConfig.target_supports) != 0) { // client requires EstablishTrustInTarget, but target does not support it: skip this securityMech. continue; } if ((EstablishTrustInClient.value & (authConfig.target_requires ^ clientSupports) & ~clientSupports) != 0) { // target requires EstablishTrustInClient, but client does not support it: skip this securityMech. continue; } SAS_ContextSec identityConfig = securityMech.sas_context_mech; if ((IdentityAssertion.value & (identityConfig.target_requires ^ clientSupports) & ~clientSupports) != 0) { // target requires IdentityAssertion, but client does not support it: skip this securityMech continue; } // found matching securityMech. return securityMech; } // no matching securityMech was found. return null; } catch (BAD_PARAM e) { // no component with TAG_CSI_SEC_MECH_LIST was found. return null; } catch (org.omg.IOP.CodecPackage.TypeMismatch e) { // unexpected exception in codec throw IIOPLogger.ROOT_LOGGER.unexpectedException(e); } catch (org.omg.IOP.CodecPackage.FormatMismatch e) { // unexpected exception in codec throw IIOPLogger.ROOT_LOGGER.unexpectedException(e); } } /** * <p> * Generate a string representation of the {@code CompoundSecMech}. * </p> * * @param securityMech the {@code CompoundSecMech} to create the string for. * @param builder the buffer to write to. */ public static void toString(CompoundSecMech securityMech, StringBuilder builder) { AS_ContextSec asMech = securityMech != null ? securityMech.as_context_mech : null; SAS_ContextSec sasMech = securityMech != null ? securityMech.sas_context_mech : null; if (securityMech != null) { builder.append("CompoundSecMech["); builder.append("target_requires: "); builder.append(securityMech.target_requires); if (asMech != null) { builder.append("AS_ContextSec["); builder.append("client_authentication_mech: "); builder.append(new String(asMech.client_authentication_mech, StandardCharsets.UTF_8)); builder.append(", target_name: "); builder.append(new String(asMech.target_name, StandardCharsets.UTF_8)); builder.append(", target_requires: "); builder.append(asMech.target_requires); builder.append(", target_supports: "); builder.append(asMech.target_supports); builder.append("]"); } if (sasMech != null) { builder.append("SAS_ContextSec["); builder.append("supported_identity_types: "); builder.append(sasMech.supported_identity_types); builder.append(", target_requires: "); builder.append(sasMech.target_requires); builder.append(", target_supports: "); builder.append(sasMech.target_supports); builder.append("]"); } builder.append("]"); } } }