Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/jgss/krb5/InitialToken.java
38922 views
/*1* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.jgss.krb5;2627import org.ietf.jgss.*;28import javax.security.auth.kerberos.DelegationPermission;29import java.io.IOException;30import java.net.InetAddress;31import java.net.Inet4Address;32import java.net.Inet6Address;33import java.security.MessageDigest;34import java.security.NoSuchAlgorithmException;35import java.util.Arrays;36import sun.security.krb5.*;37import sun.security.krb5.internal.Krb5;3839abstract class InitialToken extends Krb5Token {4041private static final int CHECKSUM_TYPE = 0x8003;4243private static final int CHECKSUM_LENGTH_SIZE = 4;44private static final int CHECKSUM_BINDINGS_SIZE = 16;45private static final int CHECKSUM_FLAGS_SIZE = 4;46private static final int CHECKSUM_DELEG_OPT_SIZE = 2;47private static final int CHECKSUM_DELEG_LGTH_SIZE = 2;4849private static final int CHECKSUM_DELEG_FLAG = 1;50private static final int CHECKSUM_MUTUAL_FLAG = 2;51private static final int CHECKSUM_REPLAY_FLAG = 4;52private static final int CHECKSUM_SEQUENCE_FLAG = 8;53private static final int CHECKSUM_CONF_FLAG = 16;54private static final int CHECKSUM_INTEG_FLAG = 32;5556private final byte[] CHECKSUM_FIRST_BYTES =57{(byte)0x10, (byte)0x00, (byte)0x00, (byte)0x00};5859private static final int CHANNEL_BINDING_AF_INET = 2;60private static final int CHANNEL_BINDING_AF_INET6 = 24;61private static final int CHANNEL_BINDING_AF_NULL_ADDR = 255;6263private static final int Inet4_ADDRSZ = 4;64private static final int Inet6_ADDRSZ = 16;6566protected class OverloadedChecksum {6768private byte[] checksumBytes = null;69private Credentials delegCreds = null;70private int flags = 0;7172/**73* Called on the initiator side when creating the74* InitSecContextToken.75*/76public OverloadedChecksum(Krb5Context context,77Credentials tgt,78Credentials serviceTicket)79throws KrbException, IOException, GSSException {8081byte[] krbCredMessage = null;82int pos = 0;83int size = CHECKSUM_LENGTH_SIZE + CHECKSUM_BINDINGS_SIZE +84CHECKSUM_FLAGS_SIZE;8586if (!tgt.isForwardable()) {87context.setCredDelegState(false);88context.setDelegPolicyState(false);89} else if (context.getCredDelegState()) {90if (context.getDelegPolicyState()) {91if (!serviceTicket.checkDelegate()) {92// delegation not permitted by server policy, mark it93context.setDelegPolicyState(false);94}95}96} else if (context.getDelegPolicyState()) {97if (serviceTicket.checkDelegate()) {98context.setCredDelegState(true);99} else {100context.setDelegPolicyState(false);101}102}103104if (context.getCredDelegState()) {105KrbCred krbCred = null;106CipherHelper cipherHelper =107context.getCipherHelper(serviceTicket.getSessionKey());108if (useNullKey(cipherHelper)) {109krbCred = new KrbCred(tgt, serviceTicket,110EncryptionKey.NULL_KEY);111} else {112krbCred = new KrbCred(tgt, serviceTicket,113serviceTicket.getSessionKey());114}115krbCredMessage = krbCred.getMessage();116size += CHECKSUM_DELEG_OPT_SIZE +117CHECKSUM_DELEG_LGTH_SIZE +118krbCredMessage.length;119}120121checksumBytes = new byte[size];122123checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[0];124checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[1];125checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[2];126checksumBytes[pos++] = CHECKSUM_FIRST_BYTES[3];127128ChannelBinding localBindings = context.getChannelBinding();129if (localBindings != null) {130byte[] localBindingsBytes =131computeChannelBinding(context.getChannelBinding());132System.arraycopy(localBindingsBytes, 0,133checksumBytes, pos, localBindingsBytes.length);134// System.out.println("ChannelBinding hash: "135// + getHexBytes(localBindingsBytes));136}137138pos += CHECKSUM_BINDINGS_SIZE;139140if (context.getCredDelegState())141flags |= CHECKSUM_DELEG_FLAG;142if (context.getMutualAuthState())143flags |= CHECKSUM_MUTUAL_FLAG;144if (context.getReplayDetState())145flags |= CHECKSUM_REPLAY_FLAG;146if (context.getSequenceDetState())147flags |= CHECKSUM_SEQUENCE_FLAG;148if (context.getIntegState())149flags |= CHECKSUM_INTEG_FLAG;150if (context.getConfState())151flags |= CHECKSUM_CONF_FLAG;152153byte[] temp = new byte[4];154writeLittleEndian(flags, temp);155checksumBytes[pos++] = temp[0];156checksumBytes[pos++] = temp[1];157checksumBytes[pos++] = temp[2];158checksumBytes[pos++] = temp[3];159160if (context.getCredDelegState()) {161162PrincipalName delegateTo =163serviceTicket.getServer();164// Cannot use '\"' instead of "\"" in constructor because165// it is interpreted as suggested length!166StringBuffer buf = new StringBuffer("\"");167buf.append(delegateTo.getName()).append('\"');168String realm = delegateTo.getRealmAsString();169buf.append(" \"krbtgt/").append(realm).append('@');170buf.append(realm).append('\"');171SecurityManager sm = System.getSecurityManager();172if (sm != null) {173DelegationPermission perm =174new DelegationPermission(buf.toString());175sm.checkPermission(perm);176}177178179/*180* Write 1 in little endian but in two bytes181* for DlgOpt182*/183184checksumBytes[pos++] = (byte)0x01;185checksumBytes[pos++] = (byte)0x00;186187/*188* Write the length of the delegated credential in little189* endian but in two bytes for Dlgth190*/191192if (krbCredMessage.length > 0x0000ffff)193throw new GSSException(GSSException.FAILURE, -1,194"Incorrect message length");195196writeLittleEndian(krbCredMessage.length, temp);197checksumBytes[pos++] = temp[0];198checksumBytes[pos++] = temp[1];199System.arraycopy(krbCredMessage, 0,200checksumBytes, pos, krbCredMessage.length);201}202203}204205/**206* Called on the acceptor side when reading an InitSecContextToken.207*/208// XXX Passing in Checksum is not required. byte[] can209// be passed in if this checksum type denotes a210// raw_checksum. In that case, make Checksum class krb5211// internal.212public OverloadedChecksum(Krb5Context context, Checksum checksum,213EncryptionKey key, EncryptionKey subKey)214throws GSSException, KrbException, IOException {215216int pos = 0;217218if (checksum == null) {219GSSException ge = new GSSException(GSSException.FAILURE, -1,220"No cksum in AP_REQ's authenticator");221ge.initCause(new KrbException(Krb5.KRB_AP_ERR_INAPP_CKSUM));222throw ge;223}224checksumBytes = checksum.getBytes();225226if ((checksumBytes[0] != CHECKSUM_FIRST_BYTES[0]) ||227(checksumBytes[1] != CHECKSUM_FIRST_BYTES[1]) ||228(checksumBytes[2] != CHECKSUM_FIRST_BYTES[2]) ||229(checksumBytes[3] != CHECKSUM_FIRST_BYTES[3])) {230throw new GSSException(GSSException.FAILURE, -1,231"Incorrect checksum");232}233234ChannelBinding localBindings = context.getChannelBinding();235236// Ignore remote channel binding info when not requested at237// local side (RFC 4121 4.1.1.2: the acceptor MAY ignore...).238//239// All major krb5 implementors implement this "MAY",240// and some applications depend on it as a workaround241// for not having a way to negotiate the use of channel242// binding -- the initiator application always uses CB243// and hopes the acceptor will ignore the CB if the244// acceptor doesn't support CB.245if (localBindings != null) {246byte[] remoteBindingBytes = new byte[CHECKSUM_BINDINGS_SIZE];247System.arraycopy(checksumBytes, 4, remoteBindingBytes, 0,248CHECKSUM_BINDINGS_SIZE);249250byte[] noBindings = new byte[CHECKSUM_BINDINGS_SIZE];251if (!Arrays.equals(noBindings, remoteBindingBytes)) {252byte[] localBindingsBytes =253computeChannelBinding(localBindings);254if (!Arrays.equals(localBindingsBytes,255remoteBindingBytes)) {256throw new GSSException(GSSException.BAD_BINDINGS, -1,257"Bytes mismatch!");258}259} else {260throw new GSSException(GSSException.BAD_BINDINGS, -1,261"Token missing ChannelBinding!");262}263}264265flags = readLittleEndian(checksumBytes, 20, 4);266267if ((flags & CHECKSUM_DELEG_FLAG) > 0) {268269/*270* XXX271* if ((checksumBytes[24] != (byte)0x01) &&272* (checksumBytes[25] != (byte)0x00))273*/274275int credLen = readLittleEndian(checksumBytes, 26, 2);276byte[] credBytes = new byte[credLen];277System.arraycopy(checksumBytes, 28, credBytes, 0, credLen);278279KrbCred cred;280try {281cred = new KrbCred(credBytes, key);282} catch (KrbException ke) {283if (subKey != null) {284cred = new KrbCred(credBytes, subKey);285} else {286throw ke;287}288}289delegCreds = cred.getDelegatedCreds()[0];290}291}292293// check if KRB-CRED message should use NULL_KEY for encryption294private boolean useNullKey(CipherHelper ch) {295boolean flag = true;296// for "newer" etypes and RC4-HMAC do not use NULL KEY297if ((ch.getProto() == 1) || ch.isArcFour()) {298flag = false;299}300return flag;301}302303public Checksum getChecksum() throws KrbException {304return new Checksum(checksumBytes, CHECKSUM_TYPE);305}306307public Credentials getDelegatedCreds() {308return delegCreds;309}310311// Only called by acceptor312public void setContextFlags(Krb5Context context) {313// default for cred delegation is false314if ((flags & CHECKSUM_DELEG_FLAG) > 0)315context.setCredDelegState(true);316// default for the following are true317if ((flags & CHECKSUM_MUTUAL_FLAG) == 0) {318context.setMutualAuthState(false);319}320if ((flags & CHECKSUM_REPLAY_FLAG) == 0) {321context.setReplayDetState(false);322}323if ((flags & CHECKSUM_SEQUENCE_FLAG) == 0) {324context.setSequenceDetState(false);325}326if ((flags & CHECKSUM_CONF_FLAG) == 0) {327context.setConfState(false);328}329if ((flags & CHECKSUM_INTEG_FLAG) == 0) {330context.setIntegState(false);331}332}333}334335private int getAddrType(InetAddress addr) {336int addressType = CHANNEL_BINDING_AF_NULL_ADDR;337338if (addr instanceof Inet4Address)339addressType = CHANNEL_BINDING_AF_INET;340else if (addr instanceof Inet6Address)341addressType = CHANNEL_BINDING_AF_INET6;342return (addressType);343}344345private byte[] getAddrBytes(InetAddress addr) throws GSSException {346int addressType = getAddrType(addr);347byte[] addressBytes = addr.getAddress();348if (addressBytes != null) {349switch (addressType) {350case CHANNEL_BINDING_AF_INET:351if (addressBytes.length != Inet4_ADDRSZ) {352throw new GSSException(GSSException.FAILURE, -1,353"Incorrect AF-INET address length in ChannelBinding.");354}355return (addressBytes);356case CHANNEL_BINDING_AF_INET6:357if (addressBytes.length != Inet6_ADDRSZ) {358throw new GSSException(GSSException.FAILURE, -1,359"Incorrect AF-INET6 address length in ChannelBinding.");360}361return (addressBytes);362default:363throw new GSSException(GSSException.FAILURE, -1,364"Cannot handle non AF-INET addresses in ChannelBinding.");365}366}367return null;368}369370private byte[] computeChannelBinding(ChannelBinding channelBinding)371throws GSSException {372373InetAddress initiatorAddress = channelBinding.getInitiatorAddress();374InetAddress acceptorAddress = channelBinding.getAcceptorAddress();375int size = 5*4;376377int initiatorAddressType = getAddrType(initiatorAddress);378int acceptorAddressType = getAddrType(acceptorAddress);379380byte[] initiatorAddressBytes = null;381if (initiatorAddress != null) {382initiatorAddressBytes = getAddrBytes(initiatorAddress);383size += initiatorAddressBytes.length;384}385386byte[] acceptorAddressBytes = null;387if (acceptorAddress != null) {388acceptorAddressBytes = getAddrBytes(acceptorAddress);389size += acceptorAddressBytes.length;390}391392byte[] appDataBytes = channelBinding.getApplicationData();393if (appDataBytes != null) {394size += appDataBytes.length;395}396397byte[] data = new byte[size];398399int pos = 0;400401writeLittleEndian(initiatorAddressType, data, pos);402pos += 4;403404if (initiatorAddressBytes != null) {405writeLittleEndian(initiatorAddressBytes.length, data, pos);406pos += 4;407System.arraycopy(initiatorAddressBytes, 0,408data, pos, initiatorAddressBytes.length);409pos += initiatorAddressBytes.length;410} else {411// Write length 0412pos += 4;413}414415writeLittleEndian(acceptorAddressType, data, pos);416pos += 4;417418if (acceptorAddressBytes != null) {419writeLittleEndian(acceptorAddressBytes.length, data, pos);420pos += 4;421System.arraycopy(acceptorAddressBytes, 0,422data, pos, acceptorAddressBytes.length);423pos += acceptorAddressBytes.length;424} else {425// Write length 0426pos += 4;427}428429if (appDataBytes != null) {430writeLittleEndian(appDataBytes.length, data, pos);431pos += 4;432System.arraycopy(appDataBytes, 0, data, pos,433appDataBytes.length);434pos += appDataBytes.length;435} else {436// Write 0437pos += 4;438}439440try {441MessageDigest md5 = MessageDigest.getInstance("MD5");442return md5.digest(data);443} catch (NoSuchAlgorithmException e) {444throw new GSSException(GSSException.FAILURE, -1,445"Could not get MD5 Message Digest - "446+ e.getMessage());447}448}449450public abstract byte[] encode() throws IOException;451452}453454455