1 /* 2 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.jgss.krb5; 27 28 import org.ietf.jgss.*; 29 import java.io.InputStream; 30 import java.io.IOException; 31 32 import sun.security.action.GetPropertyAction; 33 import sun.security.krb5.*; 34 import java.net.InetAddress; 35 import sun.security.krb5.internal.AuthorizationData; 36 import sun.security.krb5.internal.KerberosTime; 37 38 class InitSecContextToken extends InitialToken { 39 40 // If non-mutual authentication is requested, there is no AP-REP message. 41 // The acceptor thus has no chance to send the seq-number field to the 42 // initiator. In this case, the initiator and acceptor should has an 43 // agreement to derive acceptor's initial seq-number if the acceptor wishes 44 // to send messages to the initiator. 45 46 // If this flag is true, it will the same as the initiator's initial 47 // seq-number (as MIT krb5 and Windows SSPI do). Otherwise, it will be zero 48 // (as Heimdal does). The default value is true. 49 private static final boolean ACCEPTOR_USE_INITIATOR_SEQNUM; 50 51 static { 52 // The ACCEPTOR_USE_INITIATOR_SEQNUM value is determined by the system 53 // property "sun.security.krb5.acceptor.sequence.number.nonmutual", 54 // which can be set to "initiator", "zero" or "0". 55 String propName = "sun.security.krb5.acceptor.sequence.number.nonmutual"; 56 String s = GetPropertyAction.privilegedGetProperty(propName, "initiator"); 57 if (s.equals("initiator")) { 58 ACCEPTOR_USE_INITIATOR_SEQNUM = true; 59 } else if (s.equals("zero") || s.equals("0")) { 60 ACCEPTOR_USE_INITIATOR_SEQNUM = false; 61 } else { 62 throw new AssertionError("Unrecognized value for " + propName 63 + ": " + s); 64 } 65 } 66 67 private KrbApReq apReq = null; 68 69 /** 70 * For the context initiator to call. It constructs a new 71 * InitSecContextToken to send over to the peer containing the desired 72 * flags and the AP-REQ. It also updates the context with the local 73 * sequence number and shared context key. 74 * (When mutual auth is enabled the peer has an opportunity to 75 * renegotiate the session key in the followup AcceptSecContextToken 76 * that it sends.) 77 */ InitSecContextToken(Krb5Context context, Credentials tgt, Credentials serviceTicket)78 InitSecContextToken(Krb5Context context, 79 Credentials tgt, 80 Credentials serviceTicket) 81 throws KrbException, IOException, GSSException { 82 83 boolean mutualRequired = context.getMutualAuthState(); 84 boolean useSubkey = true; // MIT Impl will crash if this is not set! 85 boolean useSequenceNumber = true; 86 87 OverloadedChecksum gssChecksum = 88 new OverloadedChecksum(context, tgt, serviceTicket); 89 90 Checksum checksum = gssChecksum.getChecksum(); 91 92 context.setTktFlags(serviceTicket.getFlags()); 93 context.setAuthTime( 94 new KerberosTime(serviceTicket.getAuthTime()).toString()); 95 apReq = new KrbApReq(serviceTicket, 96 mutualRequired, 97 useSubkey, 98 useSequenceNumber, 99 checksum); 100 101 context.resetMySequenceNumber(apReq.getSeqNumber().intValue()); 102 103 EncryptionKey subKey = apReq.getSubKey(); 104 if (subKey != null) 105 context.setKey(Krb5Context.INITIATOR_SUBKEY, subKey); 106 else 107 context.setKey(Krb5Context.SESSION_KEY, serviceTicket.getSessionKey()); 108 109 if (!mutualRequired) 110 context.resetPeerSequenceNumber( 111 ACCEPTOR_USE_INITIATOR_SEQNUM 112 ? apReq.getSeqNumber().intValue() 113 : 0); 114 } 115 116 /** 117 * For the context acceptor to call. It reads the bytes out of an 118 * InputStream and constructs an InitSecContextToken with them. 119 */ InitSecContextToken(Krb5Context context, Krb5AcceptCredential cred, InputStream is)120 InitSecContextToken(Krb5Context context, Krb5AcceptCredential cred, 121 InputStream is) 122 throws IOException, GSSException, KrbException { 123 124 int tokenId = ((is.read()<<8) | is.read()); 125 126 if (tokenId != Krb5Token.AP_REQ_ID) 127 throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1, 128 "AP_REQ token id does not match!"); 129 130 // XXX Modify KrbApReq cons to take an InputStream 131 byte[] apReqBytes = 132 new sun.security.util.DerValue(is).toByteArray(); 133 //debug("=====ApReqBytes: [" + getHexBytes(apReqBytes) + "]\n"); 134 135 InetAddress addr = null; 136 if (context.getChannelBinding() != null) { 137 addr = context.getChannelBinding().getInitiatorAddress(); 138 } 139 apReq = new KrbApReq(apReqBytes, cred, addr); 140 //debug("\nReceived AP-REQ and authenticated it.\n"); 141 142 EncryptionKey sessionKey = apReq.getCreds().getSessionKey(); 143 144 /* 145 System.out.println("\n\nSession key from service ticket is: " + 146 getHexBytes(sessionKey.getBytes())); 147 */ 148 149 EncryptionKey subKey = apReq.getSubKey(); 150 if (subKey != null) { 151 context.setKey(Krb5Context.INITIATOR_SUBKEY, subKey); 152 /* 153 System.out.println("Sub-Session key from authenticator is: " + 154 getHexBytes(subKey.getBytes()) + "\n"); 155 */ 156 } else { 157 context.setKey(Krb5Context.SESSION_KEY, sessionKey); 158 //System.out.println("Sub-Session Key Missing in Authenticator.\n"); 159 } 160 161 OverloadedChecksum gssChecksum = new OverloadedChecksum( 162 context, apReq.getChecksum(), sessionKey, subKey); 163 gssChecksum.setContextFlags(context); 164 Credentials delegCred = gssChecksum.getDelegatedCreds(); 165 if (delegCred != null) { 166 Krb5CredElement credElement = 167 Krb5InitCredential.getInstance( 168 (Krb5NameElement)context.getSrcName(), 169 delegCred); 170 context.setDelegCred(credElement); 171 } 172 173 Integer apReqSeqNumber = apReq.getSeqNumber(); 174 int peerSeqNumber = (apReqSeqNumber != null ? 175 apReqSeqNumber.intValue() : 176 0); 177 context.resetPeerSequenceNumber(peerSeqNumber); 178 if (!context.getMutualAuthState()) { 179 context.resetMySequenceNumber( 180 ACCEPTOR_USE_INITIATOR_SEQNUM 181 ? peerSeqNumber 182 : 0); 183 } 184 context.setAuthTime( 185 new KerberosTime(apReq.getCreds().getAuthTime()).toString()); 186 context.setTktFlags(apReq.getCreds().getFlags()); 187 AuthorizationData ad = apReq.getCreds().getAuthzData(); 188 context.setAuthzData(ad); 189 } 190 getKrbApReq()191 public final KrbApReq getKrbApReq() { 192 return apReq; 193 } 194 encode()195 public final byte[] encode() throws IOException { 196 byte[] apReqBytes = apReq.getMessage(); 197 byte[] retVal = new byte[2 + apReqBytes.length]; 198 writeInt(Krb5Token.AP_REQ_ID, retVal, 0); 199 System.arraycopy(apReqBytes, 0, retVal, 2, apReqBytes.length); 200 // System.out.println("GSS-Token with AP_REQ is:"); 201 // System.out.println(getHexBytes(retVal)); 202 return retVal; 203 } 204 } 205