InitialToken.java revision 2894
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott/*
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott *
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * This code is free software; you can redistribute it and/or modify it
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * under the terms of the GNU General Public License version 2 only, as
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * published by the Free Software Foundation. Oracle designates this
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * particular file as subject to the "Classpath" exception as provided
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * by Oracle in the LICENSE file that accompanied this code.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott *
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * This code is distributed in the hope that it will be useful, but WITHOUT
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * version 2 for more details (a copy is included in the LICENSE file that
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * accompanied this code).
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott *
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * You should have received a copy of the GNU General Public License version
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * 2 along with this work; if not, write to the Free Software Foundation,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott *
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * or visit www.oracle.com if you need additional information or have any
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * questions.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott */
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottpackage sun.security.jgss.krb5;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport org.ietf.jgss.*;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport javax.security.auth.kerberos.DelegationPermission;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.io.IOException;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.net.InetAddress;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.net.Inet4Address;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.net.Inet6Address;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.security.MessageDigest;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.security.NoSuchAlgorithmException;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.util.Arrays;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport sun.security.krb5.*;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport sun.security.krb5.internal.Krb5;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottabstract class InitialToken extends Krb5Token {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_TYPE = 0x8003;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_LENGTH_SIZE = 4;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_BINDINGS_SIZE = 16;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_FLAGS_SIZE = 4;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_DELEG_OPT_SIZE = 2;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_DELEG_LGTH_SIZE = 2;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_DELEG_FLAG = 1;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_MUTUAL_FLAG = 2;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_REPLAY_FLAG = 4;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_SEQUENCE_FLAG = 8;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_CONF_FLAG = 16;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_INTEG_FLAG = 32;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private final byte[] CHECKSUM_FIRST_BYTES =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott {(byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00};
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHANNEL_BINDING_AF_INET = 2;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHANNEL_BINDING_AF_INET6 = 24;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHANNEL_BINDING_AF_NULL_ADDR = 255;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int Inet4_ADDRSZ = 4;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int Inet6_ADDRSZ = 16;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott protected class OverloadedChecksum {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private byte[] checksumBytes = null;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private Credentials delegCreds = null;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private int flags = 0;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott /**
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Called on the initiator side when creating the
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * InitSecContextToken.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott */
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott public OverloadedChecksum(Krb5Context context,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott Credentials tgt,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott Credentials serviceTicket)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throws KrbException, IOException, GSSException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] krbCredMessage = null;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int pos = 0;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int size = CHECKSUM_LENGTH_SIZE + CHECKSUM_BINDINGS_SIZE +
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott CHECKSUM_FLAGS_SIZE;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (!tgt.isForwardable()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setCredDelegState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setDelegPolicyState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott } else if (context.getCredDelegState()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getDelegPolicyState()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (!serviceTicket.checkDelegate()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // delegation not permitted by server policy, mark it
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setDelegPolicyState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott } else if (context.getDelegPolicyState()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (serviceTicket.checkDelegate()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setCredDelegState(true);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott } else {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setDelegPolicyState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getCredDelegState()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott KrbCred krbCred = null;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott CipherHelper cipherHelper =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.getCipherHelper(serviceTicket.getSessionKey());
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (useNullKey(cipherHelper)) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott krbCred = new KrbCred(tgt, serviceTicket,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott EncryptionKey.NULL_KEY);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott } else {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott krbCred = new KrbCred(tgt, serviceTicket,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott serviceTicket.getSessionKey());
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott krbCredMessage = krbCred.getMessage();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott size += CHECKSUM_DELEG_OPT_SIZE +
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott CHECKSUM_DELEG_LGTH_SIZE +
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott krbCredMessage.length;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes = new byte[size];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[0];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[1];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[2];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[3];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott ChannelBinding localBindings = context.getChannelBinding();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (localBindings != null) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] localBindingsBytes =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott computeChannelBinding(context.getChannelBinding());
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott System.arraycopy(localBindingsBytes, 0,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes, pos, localBindingsBytes.length);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // System.out.println("ChannelBinding hash: "
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // + getHexBytes(localBindingsBytes));
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott pos += CHECKSUM_BINDINGS_SIZE;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getCredDelegState())
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags |= CHECKSUM_DELEG_FLAG;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getMutualAuthState())
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags |= CHECKSUM_MUTUAL_FLAG;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getReplayDetState())
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags |= CHECKSUM_REPLAY_FLAG;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getSequenceDetState())
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags |= CHECKSUM_SEQUENCE_FLAG;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getIntegState())
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags |= CHECKSUM_INTEG_FLAG;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getConfState())
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags |= CHECKSUM_CONF_FLAG;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] temp = new byte[4];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott writeLittleEndian(flags, temp);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = temp[0];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = temp[1];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = temp[2];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = temp[3];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (context.getCredDelegState()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott PrincipalName delegateTo =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott serviceTicket.getServer();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // Cannot use '\"' instead of "\"" in constructor because
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // it is interpreted as suggested length!
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott StringBuffer buf = new StringBuffer("\"");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott buf.append(delegateTo.getName()).append('\"');
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott String realm = delegateTo.getRealmAsString();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott buf.append(" \"krbtgt/").append(realm).append('@');
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott buf.append(realm).append('\"');
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott SecurityManager sm = System.getSecurityManager();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (sm != null) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott DelegationPermission perm =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott new DelegationPermission(buf.toString());
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott sm.checkPermission(perm);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott /*
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Write 1 in little endian but in two bytes
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * for DlgOpt
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott */
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = (byte)0x01;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = (byte)0x00;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott /*
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Write the length of the delegated credential in little
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * endian but in two bytes for Dlgth
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott */
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (krbCredMessage.length > 0x0000ffff)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Incorrect messsage length");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott writeLittleEndian(krbCredMessage.length, temp);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = temp[0];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes[pos++] = temp[1];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott System.arraycopy(krbCredMessage, 0,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes, pos, krbCredMessage.length);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott /**
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Called on the acceptor side when reading an InitSecContextToken.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott */
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // XXX Passing in Checksum is not required. byte[] can
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // be passed in if this checksum type denotes a
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // raw_checksum. In that case, make Checksum class krb5
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // internal.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott public OverloadedChecksum(Krb5Context context,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott Checksum checksum, EncryptionKey key)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throws GSSException, KrbException, IOException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int pos = 0;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (checksum == null) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott GSSException ge = new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "No cksum in AP_REQ's authenticator");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott ge.initCause(new KrbException(Krb5.KRB_AP_ERR_INAPP_CKSUM));
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw ge;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes = checksum.getBytes();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((checksumBytes[0] != CHECKSUM_FIRST_BYTES[0]) ||
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott (checksumBytes[1] != CHECKSUM_FIRST_BYTES[1]) ||
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott (checksumBytes[2] != CHECKSUM_FIRST_BYTES[2]) ||
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott (checksumBytes[3] != CHECKSUM_FIRST_BYTES[3])) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Incorrect checksum");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott ChannelBinding localBindings = context.getChannelBinding();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // Ignore remote channel binding info when not requested at
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // local side (RFC 4121 4.1.1.2: the acceptor MAY ignore...).
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott //
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // All major krb5 implementors implement this "MAY",
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // and some applications depend on it as a workaround
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // for not having a way to negotiate the use of channel
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // binding -- the initiator application always uses CB
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // and hopes the acceptor will ignore the CB if the
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // acceptor doesn't support CB.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (localBindings != null) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] remoteBindingBytes = new byte[CHECKSUM_BINDINGS_SIZE];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott System.arraycopy(checksumBytes, 4, remoteBindingBytes, 0,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott CHECKSUM_BINDINGS_SIZE);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] noBindings = new byte[CHECKSUM_BINDINGS_SIZE];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (!Arrays.equals(noBindings, remoteBindingBytes)) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] localBindingsBytes =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott computeChannelBinding(localBindings);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (!Arrays.equals(localBindingsBytes,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott remoteBindingBytes)) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.BAD_BINDINGS, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Bytes mismatch!");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott } else {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.BAD_BINDINGS, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Token missing ChannelBinding!");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags = readLittleEndian(checksumBytes, 20, 4);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_DELEG_FLAG) > 0) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott /*
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * XXX
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * if ((checksumBytes[24] != (byte)0x01) &&
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * (checksumBytes[25] != (byte)0x00))
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott */
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int credLen = readLittleEndian(checksumBytes, 26, 2);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] credBytes = new byte[credLen];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott System.arraycopy(checksumBytes, 28, credBytes, 0, credLen);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott CipherHelper cipherHelper = context.getCipherHelper(key);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (useNullKey(cipherHelper)) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott delegCreds =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott new KrbCred(credBytes, EncryptionKey.NULL_KEY).
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott getDelegatedCreds()[0];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott } else {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott delegCreds =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott new KrbCred(credBytes, key).
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott getDelegatedCreds()[0];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // check if KRB-CRED message should use NULL_KEY for encryption
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private boolean useNullKey(CipherHelper ch) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott boolean flag = true;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // for "newer" etypes and RC4-HMAC do not use NULL KEY
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((ch.getProto() == 1) || ch.isArcFour()) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flag = false;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return flag;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott public Checksum getChecksum() throws KrbException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return new Checksum(checksumBytes, CHECKSUM_TYPE);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott public Credentials getDelegatedCreds() {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return delegCreds;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // Only called by acceptor
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott public void setContextFlags(Krb5Context context) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // default for cred delegation is false
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_DELEG_FLAG) > 0)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setCredDelegState(true);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // default for the following are true
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_MUTUAL_FLAG) == 0) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setMutualAuthState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_REPLAY_FLAG) == 0) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setReplayDetState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_SEQUENCE_FLAG) == 0) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setSequenceDetState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_CONF_FLAG) == 0) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setConfState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_INTEG_FLAG) == 0) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.setIntegState(false);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private int getAddrType(InetAddress addr) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int addressType = CHANNEL_BINDING_AF_NULL_ADDR;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (addr instanceof Inet4Address)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott addressType = CHANNEL_BINDING_AF_INET;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott else if (addr instanceof Inet6Address)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott addressType = CHANNEL_BINDING_AF_INET6;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return (addressType);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private byte[] getAddrBytes(InetAddress addr) throws GSSException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int addressType = getAddrType(addr);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] addressBytes = addr.getAddress();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (addressBytes != null) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott switch (addressType) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott case CHANNEL_BINDING_AF_INET:
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (addressBytes.length != Inet4_ADDRSZ) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Incorrect AF-INET address length in ChannelBinding.");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return (addressBytes);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott case CHANNEL_BINDING_AF_INET6:
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (addressBytes.length != Inet6_ADDRSZ) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Incorrect AF-INET6 address length in ChannelBinding.");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return (addressBytes);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott default:
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Cannot handle non AF-INET addresses in ChannelBinding.");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return null;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott }
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private byte[] computeChannelBinding(ChannelBinding channelBinding)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throws GSSException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott InetAddress initiatorAddress = channelBinding.getInitiatorAddress();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott InetAddress acceptorAddress = channelBinding.getAcceptorAddress();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int size = 5*4;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int initiatorAddressType = getAddrType(initiatorAddress);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int acceptorAddressType = getAddrType(acceptorAddress);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] initiatorAddressBytes = null;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (initiatorAddress != null) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott initiatorAddressBytes = getAddrBytes(initiatorAddress);
size += initiatorAddressBytes.length;
}
byte[] acceptorAddressBytes = null;
if (acceptorAddress != null) {
acceptorAddressBytes = getAddrBytes(acceptorAddress);
size += acceptorAddressBytes.length;
}
byte[] appDataBytes = channelBinding.getApplicationData();
if (appDataBytes != null) {
size += appDataBytes.length;
}
byte[] data = new byte[size];
int pos = 0;
writeLittleEndian(initiatorAddressType, data, pos);
pos += 4;
if (initiatorAddressBytes != null) {
writeLittleEndian(initiatorAddressBytes.length, data, pos);
pos += 4;
System.arraycopy(initiatorAddressBytes, 0,
data, pos, initiatorAddressBytes.length);
pos += initiatorAddressBytes.length;
} else {
// Write length 0
pos += 4;
}
writeLittleEndian(acceptorAddressType, data, pos);
pos += 4;
if (acceptorAddressBytes != null) {
writeLittleEndian(acceptorAddressBytes.length, data, pos);
pos += 4;
System.arraycopy(acceptorAddressBytes, 0,
data, pos, acceptorAddressBytes.length);
pos += acceptorAddressBytes.length;
} else {
// Write length 0
pos += 4;
}
if (appDataBytes != null) {
writeLittleEndian(appDataBytes.length, data, pos);
pos += 4;
System.arraycopy(appDataBytes, 0, data, pos,
appDataBytes.length);
pos += appDataBytes.length;
} else {
// Write 0
pos += 4;
}
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
return md5.digest(data);
} catch (NoSuchAlgorithmException e) {
throw new GSSException(GSSException.FAILURE, -1,
"Could not get MD5 Message Digest - "
+ e.getMessage());
}
}
public abstract byte[] encode() throws IOException;
}