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