/* * Copyright (c) 2004,2016 Red Hat, Inc.,. 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. Red Hat designates this * particular file as subject to the "Classpath" exception as provided * by Red Hat 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. */ package org.wildfly.iiop.openjdk.csiv2; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; 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.Integrity; 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.IOP.TAG_ALTERNATE_IIOP_ADDRESS; import org.omg.IOP.TAG_CSI_SEC_MECH_LIST; import org.omg.IOP.TaggedComponent; 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 com.sun.corba.se.impl.encoding.CDRInputStream; import com.sun.corba.se.impl.encoding.EncapsInputStream; import com.sun.corba.se.spi.ior.IOR; import com.sun.corba.se.spi.ior.iiop.AlternateIIOPAddressComponent; import com.sun.corba.se.spi.ior.iiop.IIOPAddress; import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate; import com.sun.corba.se.spi.orb.ORB; import com.sun.corba.se.spi.transport.IORToSocketInfo; import com.sun.corba.se.spi.transport.SocketInfo; import org.wildfly.iiop.openjdk.logging.IIOPLogger; import static java.security.AccessController.doPrivileged; /** * <p> * Implements an {@code com.sun.corba.se.spi.transport.IORToSocketInfo} which creates SocketInfo based on IOR contents. If CSIv2 * tagged component is present and it contains {@code org.omg.CSIIOP.TLS_SEC_TRANS} security mechanism then SSL socket is * created. * </p> * * @author <a href="mailto:tadamski@redhat.com">Tomasz Adamski</a> */ public class CSIV2IORToSocketInfo implements IORToSocketInfo { private static boolean clientRequiresSsl; public static void setClientRequiresSSL(final boolean clientRequiresSSL) { CSIV2IORToSocketInfo.clientRequiresSsl = clientRequiresSSL; } public List getSocketInfo(IOR ior) { List result = new ArrayList(); IIOPProfileTemplate iiopProfileTemplate = (IIOPProfileTemplate) ior.getProfile().getTaggedProfileTemplate(); IIOPAddress primary = iiopProfileTemplate.getPrimaryAddress(); String hostname = primary.getHost().toLowerCase(Locale.ENGLISH); int primaryPort = primary.getPort(); // NOTE: we could check for 0 (i.e., CSIv2) but, for a // non-CSIv2-configured client ORB talking to a CSIv2 configured // server ORB you might end up with an empty contact info list // which would then report a failure which would not be as // instructive as leaving a ContactInfo with a 0 port in the list. SocketInfo socketInfo; TransportAddress sslAddress = selectSSLTransportAddress(ior); SSL ssl = getSSL(ior); if (sslAddress != null) { socketInfo = createSSLSocketInfo(hostname, sslAddress.port); } else if (ssl != null) { socketInfo = createSSLSocketInfo(hostname, ssl.port); } else { // FIXME not all corba object export ssl port // if (clientRequiresSsl) { // throw new RuntimeException("Client requires SSL but target does not support it"); // } socketInfo = createSocketInfo(hostname, primaryPort); } result.add(socketInfo); addAlternateSocketInfos(iiopProfileTemplate, result); return result; } private SSL getSSL(IOR ior){ Iterator iter = ior.getProfile().getTaggedProfileTemplate().iteratorById(TAG_SSL_SEC_TRANS.value); if(!iter.hasNext()){ return null; } ORB orb = ior.getORB(); TaggedComponent compList = ((com.sun.corba.se.spi.ior.TaggedComponent) iter.next()).getIOPComponent(orb); CDRInputStream in = doPrivileged(new PrivilegedAction<CDRInputStream>() { @Override public CDRInputStream run() { return new EncapsInputStream(orb, compList.component_data, compList.component_data.length); } }); in.consumeEndian(); SSL ssl = SSLHelper.read(in); boolean targetRequiresSsl = ssl.target_requires > 0; boolean targetSupportsSsl = ssl.target_supports >0; if(!targetSupportsSsl && clientRequiresSsl){ throw IIOPLogger.ROOT_LOGGER.serverDoesNotSupportSsl(); } return targetSupportsSsl && (targetRequiresSsl || clientRequiresSsl) ? ssl : null; } private TransportAddress selectSSLTransportAddress(IOR ior) { CompoundSecMechList compoundSecMechList = readCompoundSecMechList(ior); if (compoundSecMechList != null) { for (CompoundSecMech mech : compoundSecMechList.mechanism_list) { TLS_SEC_TRANS sslMech = extractTlsSecTrans(ior, mech); if (sslMech == null) { continue; } boolean targetSupportsSsl = checkSSL(sslMech.target_supports); boolean targetRequiresSsl = checkSSL(sslMech.target_requires); if(!targetSupportsSsl && clientRequiresSsl){ throw IIOPLogger.ROOT_LOGGER.serverDoesNotSupportSsl(); } if (targetSupportsSsl && (targetRequiresSsl || clientRequiresSsl)) { return extractAddress(sslMech); } } } return null; } private boolean checkSSL(int options) { return (options & (Integrity.value | Confidentiality.value | DetectReplay.value | DetectMisordering.value | EstablishTrustInTarget.value | EstablishTrustInClient.value)) != 0; } private CompoundSecMechList readCompoundSecMechList(IOR ior) { Iterator iter = ior.getProfile().getTaggedProfileTemplate().iteratorById(TAG_CSI_SEC_MECH_LIST.value); if (!iter.hasNext()) { return null; } ORB orb = ior.getORB(); TaggedComponent compList = ((com.sun.corba.se.spi.ior.TaggedComponent) iter.next()).getIOPComponent(orb); CDRInputStream in = doPrivileged(new PrivilegedAction<CDRInputStream>() { @Override public CDRInputStream run() { return new EncapsInputStream(orb, compList.component_data, compList.component_data.length); } }); in.consumeEndian(); return CompoundSecMechListHelper.read(in); } private TLS_SEC_TRANS extractTlsSecTrans(IOR ior, CompoundSecMech mech) { TaggedComponent comp = mech.transport_mech; if (comp.tag != TAG_TLS_SEC_TRANS.value) { return null; } ORB orb = ior.getORB(); CDRInputStream in = doPrivileged(new PrivilegedAction<CDRInputStream>() { @Override public CDRInputStream run() { return new EncapsInputStream(orb, comp.component_data, comp.component_data.length); } }); in.consumeEndian(); return TLS_SEC_TRANSHelper.read(in); } private TransportAddress extractAddress(TLS_SEC_TRANS sslMech) { if (sslMech.addresses.length == 0) { return null; } return sslMech.addresses[0]; } private void addAlternateSocketInfos(IIOPProfileTemplate iiopProfileTemplate, final List result) { Iterator iterator = iiopProfileTemplate.iteratorById(TAG_ALTERNATE_IIOP_ADDRESS.value); while (iterator.hasNext()) { AlternateIIOPAddressComponent alternate = (AlternateIIOPAddressComponent) iterator.next(); String hostname = alternate.getAddress().getHost().toLowerCase(); int port = alternate.getAddress().getPort(); SocketInfo socketInfo = createSocketInfo(hostname, port); result.add(socketInfo); } } private SocketInfo createSocketInfo(final String hostname, final int port) { return new SocketInfo() { public String getType() { return SocketInfo.IIOP_CLEAR_TEXT; } public String getHost() { return hostname; } public int getPort() { return port; } }; } private SocketInfo createSSLSocketInfo(final String hostname, final int port) { return new SocketInfo() { public String getType() { return Constants.SSL_SOCKET_TYPE; } public String getHost() { return hostname; } public int getPort() { return port; } }; } }