| /* | |
| * Copyright (c) 2000, 2023, 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 org.ietf.jgss; | |
| import java.net.InetAddress; | |
| import java.util.Arrays; | |
| /** | |
| * This class encapsulates the concept of caller-provided channel | |
| * binding information. Channel bindings are used to strengthen the | |
| * quality with which peer entity authentication is provided during | |
| * context establishment. They enable the GSS-API callers to bind the | |
| * establishment of the security context to relevant characteristics | |
| * like addresses or to application specific data.<p> | |
| * | |
| * The caller initiating the security context must determine the | |
| * appropriate channel binding values to set in the GSSContext object. | |
| * The acceptor must provide an identical binding in order to validate | |
| * that received tokens possess correct channel-related characteristics.<p> | |
| * | |
| * Use of channel bindings is optional in GSS-API. ChannelBinding can be | |
| * set for the {@link GSSContext GSSContext} using the {@link | |
| * GSSContext#setChannelBinding(ChannelBinding) setChannelBinding} method | |
| * before the first call to {@link GSSContext#initSecContext(byte[], int, int) | |
| * initSecContext} or {@link GSSContext#acceptSecContext(byte[], int, int) | |
| * acceptSecContext} has been performed. Unless the <code>setChannelBinding</code> | |
| * method has been used to set the ChannelBinding for a GSSContext object, | |
| * <code>null</code> ChannelBinding will be assumed. <p> | |
| * | |
| * Conceptually, the GSS-API concatenates the initiator and acceptor | |
| * address information, and the application supplied byte array to form an | |
| * octet string. The mechanism calculates a MIC over this octet string and | |
| * binds the MIC to the context establishment token emitted by | |
| * <code>initSecContext</code> method of the <code>GSSContext</code> | |
| * interface. The same bindings are set by the context acceptor for its | |
| * <code>GSSContext</code> object and during processing of the | |
| * <code>acceptSecContext</code> method a MIC is calculated in the same | |
| * way. The calculated MIC is compared with that found in the token, and if | |
| * the MICs differ, accept will throw a <code>GSSException</code> with the | |
| * major code set to {@link GSSException#BAD_BINDINGS BAD_BINDINGS}, and | |
| * the context will not be established. Some mechanisms may include the | |
| * actual channel binding data in the token (rather than just a MIC); | |
| * applications should therefore not use confidential data as | |
| * channel-binding components.<p> | |
| * | |
| * Individual mechanisms may impose additional constraints on addresses | |
| * that may appear in channel bindings. For example, a mechanism may | |
| * verify that the initiator address field of the channel binding | |
| * contains the correct network address of the host system. Portable | |
| * applications should therefore ensure that they either provide correct | |
| * information for the address fields, or omit setting of the addressing | |
| * information. | |
| * | |
| * @author Mayank Upadhyay | |
| * @since 1.4 | |
| */ | |
| public class ChannelBinding { | |
| private final InetAddress initiator; | |
| private final InetAddress acceptor; | |
| private byte[] appData; | |
| /** | |
| * Create a ChannelBinding object with user supplied address information | |
| * and data. <code>null</code> values can be used for any fields which the | |
| * application does not want to specify. | |
| * | |
| * @param initAddr the address of the context initiator. | |
| * <code>null</code> value can be supplied to indicate that the | |
| * application does not want to set this value. | |
| * @param acceptAddr the address of the context | |
| * acceptor. <code>null</code> value can be supplied to indicate that | |
| * the application does not want to set this value. | |
| * @param appData application supplied data to be used as part of the | |
| * channel bindings. <code>null</code> value can be supplied to | |
| * indicate that the application does not want to set this value. | |
| */ | |
| public ChannelBinding(InetAddress initAddr, InetAddress acceptAddr, | |
| byte[] appData) { | |
| initiator = initAddr; | |
| acceptor = acceptAddr; | |
| if (appData != null) { | |
| this.appData = new byte[appData.length]; | |
| java.lang.System.arraycopy(appData, 0, this.appData, 0, | |
| appData.length); | |
| } | |
| } | |
| /** | |
| * Creates a ChannelBinding object without any addressing information. | |
| * | |
| * @param appData application supplied data to be used as part of the | |
| * channel bindings. | |
| */ | |
| public ChannelBinding(byte[] appData) { | |
| this(null, null, appData); | |
| } | |
| /** | |
| * Get the initiator's address for this channel binding. | |
| * | |
| * @return the initiator's address. <code>null</code> is returned if | |
| * the address has not been set. | |
| */ | |
| public InetAddress getInitiatorAddress() { | |
| return initiator; | |
| } | |
| /** | |
| * Get the acceptor's address for this channel binding. | |
| * | |
| * @return the acceptor's address. null is returned if the address has | |
| * not been set. | |
| */ | |
| public InetAddress getAcceptorAddress() { | |
| return acceptor; | |
| } | |
| /** | |
| * Get the application specified data for this channel binding. | |
| * | |
| * @return the application data being used as part of the | |
| * ChannelBinding. <code>null</code> is returned if no application data | |
| * has been specified for the channel binding. | |
| */ | |
| public byte[] getApplicationData() { | |
| if (appData == null) { | |
| return null; | |
| } | |
| byte[] retVal = new byte[appData.length]; | |
| System.arraycopy(appData, 0, retVal, 0, appData.length); | |
| return retVal; | |
| } | |
| /** | |
| * Compares two instances of ChannelBinding. | |
| * | |
| * @param obj another ChannelBinding to compare this one with | |
| * @return true if the two ChannelBinding's contain | |
| * the same values for the initiator and acceptor addresses and the | |
| * application data. | |
| */ | |
| @Override | |
| public boolean equals(Object obj) { | |
| if (this == obj) | |
| return true; | |
| if (! (obj instanceof ChannelBinding cb)) | |
| return false; | |
| if ((initiator != null && cb.initiator == null) || | |
| (initiator == null && cb.initiator != null)) | |
| return false; | |
| if (initiator != null && !initiator.equals(cb.initiator)) | |
| return false; | |
| if ((acceptor != null && cb.acceptor == null) || | |
| (acceptor == null && cb.acceptor != null)) | |
| return false; | |
| if (acceptor != null && !acceptor.equals(cb.acceptor)) | |
| return false; | |
| return Arrays.equals(appData, cb.appData); | |
| } | |
| /** | |
| * {@return a hashcode value for this ChannelBinding object} | |
| */ | |
| @Override | |
| public int hashCode() { | |
| if (initiator != null) | |
| return initiator.hashCode(); | |
| else if (acceptor != null) | |
| return acceptor.hashCode(); | |
| else if (appData != null) | |
| return Arrays.hashCode(appData); | |
| else | |
| return 1; | |
| } | |
| } |