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 sun.security.jgss.GSSCaller; 30 import sun.security.jgss.spi.*; 31 import sun.security.krb5.*; 32 import sun.security.krb5.Config; 33 import javax.security.auth.kerberos.*; 34 import java.net.InetAddress; 35 import java.io.IOException; 36 import java.util.Date; 37 import java.security.AccessController; 38 import java.security.AccessControlContext; 39 import java.security.PrivilegedExceptionAction; 40 import java.security.PrivilegedActionException; 41 42 /** 43 * Implements the krb5 initiator credential element. 44 * 45 * @author Mayank Upadhyay 46 * @author Ram Marti 47 * @since 1.4 48 */ 49 50 public class Krb5InitCredential 51 extends KerberosTicket 52 implements Krb5CredElement { 53 54 private static final long serialVersionUID = 7723415700837898232L; 55 56 private Krb5NameElement name; 57 private Credentials krb5Credentials; 58 59 private Krb5InitCredential(Krb5NameElement name, 60 byte[] asn1Encoding, 61 KerberosPrincipal client, 62 KerberosPrincipal server, 63 byte[] sessionKey, 64 int keyType, 65 boolean[] flags, 66 Date authTime, 67 Date startTime, 68 Date endTime, 69 Date renewTill, 70 InetAddress[] clientAddresses) 71 throws GSSException { 72 super(asn1Encoding, 73 client, 74 server, 75 sessionKey, 76 keyType, 77 flags, 78 authTime, 79 startTime, 80 endTime, 81 renewTill, 82 clientAddresses); 83 84 this.name = name; 85 86 try { 87 // Cache this for later use by the sun.security.krb5 package. 88 krb5Credentials = new Credentials(asn1Encoding, 89 client.getName(), 90 server.getName(), 91 sessionKey, 92 keyType, 93 flags, 94 authTime, 95 startTime, 96 endTime, 97 renewTill, 98 clientAddresses); 99 } catch (KrbException e) { 100 throw new GSSException(GSSException.NO_CRED, -1, 101 e.getMessage()); 102 } catch (IOException e) { 103 throw new GSSException(GSSException.NO_CRED, -1, 104 e.getMessage()); 105 } 106 107 } 108 109 private Krb5InitCredential(Krb5NameElement name, 110 Credentials delegatedCred, 111 byte[] asn1Encoding, 112 KerberosPrincipal client, 113 KerberosPrincipal server, 114 byte[] sessionKey, 115 int keyType, 116 boolean[] flags, 117 Date authTime, 118 Date startTime, 119 Date endTime, 120 Date renewTill, 121 InetAddress[] clientAddresses) 122 throws GSSException { 123 super(asn1Encoding, 124 client, 125 server, 126 sessionKey, 127 keyType, 128 flags, 129 authTime, 130 startTime, 131 endTime, 132 renewTill, 133 clientAddresses); 134 135 this.name = name; 136 // A delegated cred does not have all fields set. So do not try to 137 // creat new Credentials out of the delegatedCred. 138 this.krb5Credentials = delegatedCred; 139 } 140 141 static Krb5InitCredential getInstance(GSSCaller caller, Krb5NameElement name, 142 int initLifetime) 143 throws GSSException { 144 145 KerberosTicket tgt = getTgt(caller, name, initLifetime); 146 if (tgt == null) 147 throw new GSSException(GSSException.NO_CRED, -1, 148 "Failed to find any Kerberos tgt"); 149 150 if (name == null) { 151 String fullName = tgt.getClient().getName(); 152 name = Krb5NameElement.getInstance(fullName, 153 Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); 154 } 155 156 return new Krb5InitCredential(name, 157 tgt.getEncoded(), 158 tgt.getClient(), 159 tgt.getServer(), 160 tgt.getSessionKey().getEncoded(), 161 tgt.getSessionKeyType(), 162 tgt.getFlags(), 163 tgt.getAuthTime(), 164 tgt.getStartTime(), 165 tgt.getEndTime(), 166 tgt.getRenewTill(), 167 tgt.getClientAddresses()); 168 } 169 170 static Krb5InitCredential getInstance(Krb5NameElement name, 171 Credentials delegatedCred) 172 throws GSSException { 173 174 EncryptionKey sessionKey = delegatedCred.getSessionKey(); 175 176 /* 177 * all of the following data is optional in a KRB-CRED 178 * messages. This check for each field. 179 */ 180 181 PrincipalName cPrinc = delegatedCred.getClient(); 182 PrincipalName sPrinc = delegatedCred.getServer(); 183 184 KerberosPrincipal client = null; 185 KerberosPrincipal server = null; 186 187 Krb5NameElement credName = null; 188 189 if (cPrinc != null) { 190 String fullName = cPrinc.getName(); 191 credName = Krb5NameElement.getInstance(fullName, 192 Krb5MechFactory.NT_GSS_KRB5_PRINCIPAL); 193 client = new KerberosPrincipal(fullName); 194 } 195 196 // XXX Compare name to credName 197 198 if (sPrinc != null) { 199 server = 200 new KerberosPrincipal(sPrinc.getName(), 201 KerberosPrincipal.KRB_NT_SRV_INST); 202 } 203 204 return new Krb5InitCredential(credName, 205 delegatedCred, 206 delegatedCred.getEncoded(), 207 client, 208 server, 209 sessionKey.getBytes(), 210 sessionKey.getEType(), 211 delegatedCred.getFlags(), 212 delegatedCred.getAuthTime(), 213 delegatedCred.getStartTime(), 214 delegatedCred.getEndTime(), 215 delegatedCred.getRenewTill(), 216 delegatedCred.getClientAddresses()); 217 } 218 219 /** 220 * Returns the principal name for this credential. The name 221 * is in mechanism specific format. 222 * 223 * @return GSSNameSpi representing principal name of this credential 224 * @exception GSSException may be thrown 225 */ 226 public final GSSNameSpi getName() throws GSSException { 227 return name; 228 } 229 230 /** 231 * Returns the init lifetime remaining. 232 * 233 * @return the init lifetime remaining in seconds 234 * @exception GSSException may be thrown 235 */ 236 public int getInitLifetime() throws GSSException { 237 Date d = getEndTime(); 238 if (d == null) { 239 return 0; 240 } 241 242 long retVal = d.getTime() - System.currentTimeMillis(); 243 return (int)(retVal/1000); 244 } 245 246 /** 247 * Returns the accept lifetime remaining. 248 * 249 * @return the accept lifetime remaining in seconds 250 * @exception GSSException may be thrown 251 */ 252 public int getAcceptLifetime() throws GSSException { 253 return 0; 254 } 255 256 public boolean isInitiatorCredential() throws GSSException { 257 return true; 258 } 259 260 public boolean isAcceptorCredential() throws GSSException { 261 return false; 262 } 263 264 /** 265 * Returns the oid representing the underlying credential 266 * mechanism oid. 267 * 268 * @return the Oid for this credential mechanism 269 * @exception GSSException may be thrown 270 */ 271 public final Oid getMechanism() { 272 return Krb5MechFactory.GSS_KRB5_MECH_OID; 273 } 274 275 public final java.security.Provider getProvider() { 276 return Krb5MechFactory.PROVIDER; 277 } 278 279 280 /** 281 * Returns a sun.security.krb5.Credentials instance so that it maybe 282 * used in that package for th Kerberos protocol. 283 */ 284 Credentials getKrb5Credentials() { 285 return krb5Credentials; 286 } 287 288 /* 289 * XXX Call to this.refresh() should refresh the locally cached copy 290 * of krb5Credentials also. 291 */ 292 293 /** 294 * Called to invalidate this credential element. 295 */ 296 public void dispose() throws GSSException { 297 try { 298 destroy(); 299 } catch (javax.security.auth.DestroyFailedException e) { 300 GSSException gssException = 301 new GSSException(GSSException.FAILURE, -1, 302 "Could not destroy credentials - " + e.getMessage()); 303 gssException.initCause(e); 304 } 305 } 306 307 // XXX call to this.destroy() should destroy the locally cached copy 308 // of krb5Credentials and then call super.destroy(). 309 310 private static KerberosTicket getTgt(GSSCaller caller, Krb5NameElement name, 311 int initLifetime) 312 throws GSSException { 313 314 final String clientPrincipal; 315 316 /* 317 * Find the TGT for the realm that the client is in. If the client 318 * name is not available, then use the default realm. 319 */ 320 if (name != null) { 321 clientPrincipal = (name.getKrb5PrincipalName()).getName(); 322 } else { 323 clientPrincipal = null; 324 } 325 326 final AccessControlContext acc = AccessController.getContext(); 327 328 try { 329 final GSSCaller realCaller = (caller == GSSCaller.CALLER_UNKNOWN) 330 ? GSSCaller.CALLER_INITIATE 331 : caller; 332 return AccessController.doPrivileged( 333 new PrivilegedExceptionAction<KerberosTicket>() { 334 public KerberosTicket run() throws Exception { 335 // It's OK to use null as serverPrincipal. TGT is almost 336 // the first ticket for a principal and we use list. 337 return Krb5Util.getTicket( 338 realCaller, 339 clientPrincipal, null, acc); 340 }}); 341 } catch (PrivilegedActionException e) { 342 GSSException ge = 343 new GSSException(GSSException.NO_CRED, -1, 344 "Attempt to obtain new INITIATE credentials failed!" + 345 " (" + e.getMessage() + ")"); 346 ge.initCause(e.getException()); 347 throw ge; 348 } 349 } 350 351 @Override 352 public GSSCredentialSpi impersonate(GSSNameSpi name) throws GSSException { 353 try { 354 Krb5NameElement kname = (Krb5NameElement)name; 355 Credentials newCred = Credentials.acquireS4U2selfCreds( 356 kname.getKrb5PrincipalName(), krb5Credentials); 357 return new Krb5ProxyCredential(this, kname, newCred.getTicket()); 358 } catch (IOException | KrbException ke) { 359 GSSException ge = 360 new GSSException(GSSException.FAILURE, -1, 361 "Attempt to obtain S4U2self credentials failed!"); 362 ge.initCause(ke); 363 throw ge; 364 } 365 } 366 }