InitialToken.java revision 2894
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 * 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 * 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 * 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 * 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 Wapshottimport javax.security.auth.kerberos.DelegationPermission;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottimport java.security.NoSuchAlgorithmException;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshottabstract class InitialToken extends Krb5Token {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private static final int CHECKSUM_TYPE = 0x8003;
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 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 private final byte[] CHECKSUM_FIRST_BYTES =
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott {(byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00};
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 protected class OverloadedChecksum {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Called on the initiator side when creating the
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * InitSecContextToken.
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott public OverloadedChecksum(Krb5Context context,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throws KrbException, IOException, GSSException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int size = CHECKSUM_LENGTH_SIZE + CHECKSUM_BINDINGS_SIZE +
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // delegation not permitted by server policy, mark it
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott context.getCipherHelper(serviceTicket.getSessionKey());
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 ChannelBinding localBindings = context.getChannelBinding();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott computeChannelBinding(context.getChannelBinding());
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott checksumBytes, pos, localBindingsBytes.length);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // System.out.println("ChannelBinding hash: "
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // + getHexBytes(localBindingsBytes));
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // Cannot use '\"' instead of "\"" in constructor because
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // it is interpreted as suggested length!
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott buf.append(delegateTo.getName()).append('\"');
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott String realm = delegateTo.getRealmAsString();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott buf.append(" \"krbtgt/").append(realm).append('@');
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott SecurityManager sm = System.getSecurityManager();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Write 1 in little endian but in two bytes
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Write the length of the delegated credential in little
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * endian but in two bytes for Dlgth
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Incorrect messsage length");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott writeLittleEndian(krbCredMessage.length, temp);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * Called on the acceptor side when reading an InitSecContextToken.
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 public OverloadedChecksum(Krb5Context context,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throws GSSException, KrbException, IOException {
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 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 ChannelBinding localBindings = context.getChannelBinding();
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 // 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 byte[] remoteBindingBytes = new byte[CHECKSUM_BINDINGS_SIZE];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott System.arraycopy(checksumBytes, 4, remoteBindingBytes, 0,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott byte[] noBindings = new byte[CHECKSUM_BINDINGS_SIZE];
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if (!Arrays.equals(noBindings, remoteBindingBytes)) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.BAD_BINDINGS, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Bytes mismatch!");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.BAD_BINDINGS, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Token missing ChannelBinding!");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott flags = readLittleEndian(checksumBytes, 20, 4);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * if ((checksumBytes[24] != (byte)0x01) &&
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott * (checksumBytes[25] != (byte)0x00))
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int credLen = readLittleEndian(checksumBytes, 26, 2);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott System.arraycopy(checksumBytes, 28, credBytes, 0, credLen);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott CipherHelper cipherHelper = context.getCipherHelper(key);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott new KrbCred(credBytes, EncryptionKey.NULL_KEY).
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 public Checksum getChecksum() throws KrbException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott return new Checksum(checksumBytes, CHECKSUM_TYPE);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // Only called by acceptor
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott public void setContextFlags(Krb5Context context) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // default for cred delegation is false
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott // default for the following are true
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott if ((flags & CHECKSUM_SEQUENCE_FLAG) == 0) {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int addressType = CHANNEL_BINDING_AF_NULL_ADDR;
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private byte[] getAddrBytes(InetAddress addr) throws GSSException {
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Incorrect AF-INET address length in ChannelBinding.");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Incorrect AF-INET6 address length in ChannelBinding.");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott throw new GSSException(GSSException.FAILURE, -1,
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott "Cannot handle non AF-INET addresses in ChannelBinding.");
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott private byte[] computeChannelBinding(ChannelBinding channelBinding)
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott InetAddress initiatorAddress = channelBinding.getInitiatorAddress();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott InetAddress acceptorAddress = channelBinding.getAcceptorAddress();
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int initiatorAddressType = getAddrType(initiatorAddress);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott int acceptorAddressType = getAddrType(acceptorAddress);
1d407e39b7d8f68d9a2b1e178f35fab037d9835aRobert Wapshott initiatorAddressBytes = getAddrBytes(initiatorAddress);
} catch (NoSuchAlgorithmException e) {
+ e.getMessage());