|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
/* |
|
* |
|
* (C) Copyright IBM Corp. 1999 All Rights Reserved. |
|
* Copyright 1997 The Open Group Research Institute. All rights reserved. |
|
*/ |
|
|
|
package sun.security.krb5; |
|
|
|
import sun.security.krb5.internal.*; |
|
import sun.security.krb5.internal.crypto.*; |
|
import java.io.IOException; |
|
import java.net.UnknownHostException; |
|
import java.time.Instant; |
|
import java.util.Arrays; |
|
|
|
|
|
|
|
|
|
*/ |
|
public class KrbTgsReq { |
|
|
|
private PrincipalName princName; |
|
private PrincipalName clientAlias; |
|
private PrincipalName servName; |
|
private PrincipalName serverAlias; |
|
private TGSReq tgsReqMessg; |
|
private KerberosTime ctime; |
|
private Ticket secondTicket = null; |
|
private boolean useSubkey = false; |
|
EncryptionKey tgsReqKey; |
|
|
|
private static final boolean DEBUG = Krb5.DEBUG; |
|
|
|
private byte[] obuf; |
|
private byte[] ibuf; |
|
|
|
|
|
public KrbTgsReq(KDCOptions options, Credentials asCreds, |
|
PrincipalName cname, PrincipalName clientAlias, |
|
PrincipalName sname, PrincipalName serverAlias, |
|
Ticket[] additionalTickets, PAData[] extraPAs) |
|
throws KrbException, IOException { |
|
this(options, |
|
asCreds, |
|
cname, |
|
clientAlias, |
|
sname, |
|
serverAlias, |
|
null, |
|
null, |
|
null, |
|
null, |
|
null, |
|
null, |
|
additionalTickets, |
|
null, |
|
extraPAs); |
|
} |
|
|
|
|
|
KrbTgsReq( |
|
KDCOptions options, |
|
Credentials asCreds, |
|
PrincipalName sname, |
|
PrincipalName serverAlias, |
|
KerberosTime from, |
|
KerberosTime till, |
|
KerberosTime rtime, |
|
int[] eTypes, |
|
HostAddresses addresses, |
|
AuthorizationData authorizationData, |
|
Ticket[] additionalTickets, |
|
EncryptionKey subKey) throws KrbException, IOException { |
|
this(options, asCreds, asCreds.getClient(), asCreds.getClientAlias(), |
|
sname, serverAlias, from, till, rtime, eTypes, |
|
addresses, authorizationData, additionalTickets, subKey, null); |
|
} |
|
|
|
private KrbTgsReq( |
|
KDCOptions options, |
|
Credentials asCreds, |
|
PrincipalName cname, |
|
PrincipalName clientAlias, |
|
PrincipalName sname, |
|
PrincipalName serverAlias, |
|
KerberosTime from, |
|
KerberosTime till, |
|
KerberosTime rtime, |
|
int[] eTypes, |
|
HostAddresses addresses, |
|
AuthorizationData authorizationData, |
|
Ticket[] additionalTickets, |
|
EncryptionKey subKey, |
|
PAData[] extraPAs) throws KrbException, IOException { |
|
|
|
princName = cname; |
|
this.clientAlias = clientAlias; |
|
servName = sname; |
|
this.serverAlias = serverAlias; |
|
ctime = KerberosTime.now(); |
|
|
|
// check if they are valid arguments. The optional fields |
|
// should be consistent with settings in KDCOptions. |
|
|
|
if (options.get(KDCOptions.FORWARDABLE) && |
|
(!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) { |
|
options.set(KDCOptions.FORWARDABLE, false); |
|
} |
|
if (options.get(KDCOptions.FORWARDED)) { |
|
if (!(asCreds.flags.get(KDCOptions.FORWARDABLE))) |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
} |
|
if (options.get(KDCOptions.PROXIABLE) && |
|
(!(asCreds.flags.get(Krb5.TKT_OPTS_PROXIABLE)))) { |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
} |
|
if (options.get(KDCOptions.PROXY)) { |
|
if (!(asCreds.flags.get(KDCOptions.PROXIABLE))) |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
} |
|
if (options.get(KDCOptions.ALLOW_POSTDATE) && |
|
(!(asCreds.flags.get(Krb5.TKT_OPTS_MAY_POSTDATE)))) { |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
} |
|
if (options.get(KDCOptions.RENEWABLE) && |
|
(!(asCreds.flags.get(Krb5.TKT_OPTS_RENEWABLE)))) { |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
} |
|
|
|
if (options.get(KDCOptions.POSTDATED)) { |
|
if (!(asCreds.flags.get(KDCOptions.POSTDATED))) |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
} else { |
|
if (from != null) from = null; |
|
} |
|
if (options.get(KDCOptions.RENEWABLE)) { |
|
if (!(asCreds.flags.get(KDCOptions.RENEWABLE))) |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
} else { |
|
if (rtime != null) rtime = null; |
|
} |
|
if (options.get(KDCOptions.ENC_TKT_IN_SKEY) || options.get(KDCOptions.CNAME_IN_ADDL_TKT)) { |
|
if (additionalTickets == null) |
|
throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS); |
|
// in TGS_REQ there could be more than one additional |
|
// tickets, but in file-based credential cache, |
|
|
|
secondTicket = additionalTickets[0]; |
|
} else { |
|
if (additionalTickets != null) |
|
additionalTickets = null; |
|
} |
|
|
|
tgsReqMessg = createRequest( |
|
options, |
|
asCreds.ticket, |
|
asCreds.key, |
|
ctime, |
|
princName, |
|
servName, |
|
from, |
|
till, |
|
rtime, |
|
eTypes, |
|
addresses, |
|
authorizationData, |
|
additionalTickets, |
|
subKey, |
|
extraPAs); |
|
obuf = tgsReqMessg.asn1Encode(); |
|
|
|
// XXX We need to revisit this to see if can't move it |
|
// up such that FORWARDED flag set in the options |
|
// is included in the marshaled request. |
|
|
|
|
|
|
|
|
|
*/ |
|
if (asCreds.flags.get(KDCOptions.FORWARDED)) |
|
options.set(KDCOptions.FORWARDED, true); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public void send() throws IOException, KrbException { |
|
String realmStr = null; |
|
if (servName != null) |
|
realmStr = servName.getRealmString(); |
|
KdcComm comm = new KdcComm(realmStr); |
|
ibuf = comm.send(obuf); |
|
} |
|
|
|
public KrbTgsRep getReply() |
|
throws KrbException, IOException { |
|
return new KrbTgsRep(ibuf, this); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public Credentials sendAndGetCreds() throws IOException, KrbException { |
|
KrbTgsRep tgs_rep = null; |
|
String kdc = null; |
|
send(); |
|
tgs_rep = getReply(); |
|
return tgs_rep.getCreds(); |
|
} |
|
|
|
KerberosTime getCtime() { |
|
return ctime; |
|
} |
|
|
|
private TGSReq createRequest( |
|
KDCOptions kdc_options, |
|
Ticket ticket, |
|
EncryptionKey key, |
|
KerberosTime ctime, |
|
PrincipalName cname, |
|
PrincipalName sname, |
|
KerberosTime from, |
|
KerberosTime till, |
|
KerberosTime rtime, |
|
int[] eTypes, |
|
HostAddresses addresses, |
|
AuthorizationData authorizationData, |
|
Ticket[] additionalTickets, |
|
EncryptionKey subKey, |
|
PAData[] extraPAs) |
|
throws IOException, KrbException, UnknownHostException { |
|
KerberosTime req_till = null; |
|
if (till == null) { |
|
String d = Config.getInstance().get("libdefaults", "ticket_lifetime"); |
|
if (d != null) { |
|
req_till = new KerberosTime(Instant.now().plusSeconds(Config.duration(d))); |
|
} else { |
|
req_till = new KerberosTime(0); |
|
} |
|
} else { |
|
req_till = till; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
tgsReqKey = key; |
|
|
|
int[] req_eTypes = null; |
|
if (eTypes == null) { |
|
req_eTypes = EType.getDefaults("default_tgs_enctypes"); |
|
} else { |
|
req_eTypes = eTypes; |
|
} |
|
|
|
EncryptionKey reqKey = null; |
|
EncryptedData encAuthorizationData = null; |
|
if (authorizationData != null) { |
|
byte[] ad = authorizationData.asn1Encode(); |
|
if (subKey != null) { |
|
reqKey = subKey; |
|
tgsReqKey = subKey; |
|
useSubkey = true; |
|
encAuthorizationData = new EncryptedData(reqKey, ad, |
|
KeyUsage.KU_TGS_REQ_AUTH_DATA_SUBKEY); |
|
} else |
|
encAuthorizationData = new EncryptedData(key, ad, |
|
KeyUsage.KU_TGS_REQ_AUTH_DATA_SESSKEY); |
|
} |
|
|
|
KDCReqBody reqBody = new KDCReqBody( |
|
kdc_options, |
|
cname, |
|
sname, |
|
from, |
|
req_till, |
|
rtime, |
|
Nonce.value(), |
|
req_eTypes, |
|
addresses, |
|
encAuthorizationData, |
|
additionalTickets); |
|
|
|
byte[] temp = reqBody.asn1Encode(Krb5.KRB_TGS_REQ); |
|
// if the checksum type is one of the keyed checksum types, |
|
|
|
Checksum cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp, key, |
|
KeyUsage.KU_PA_TGS_REQ_CKSUM); |
|
|
|
// Usage will be KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR |
|
|
|
byte[] tgs_ap_req = new KrbApReq( |
|
new APOptions(), |
|
ticket, |
|
key, |
|
cname, |
|
cksum, |
|
ctime, |
|
reqKey, |
|
null, |
|
null).getMessage(); |
|
|
|
PAData tgsPAData = new PAData(Krb5.PA_TGS_REQ, tgs_ap_req); |
|
PAData[] pa; |
|
if (extraPAs != null) { |
|
pa = Arrays.copyOf(extraPAs, extraPAs.length + 1); |
|
pa[extraPAs.length] = tgsPAData; |
|
} else { |
|
pa = new PAData[] {tgsPAData}; |
|
} |
|
return new TGSReq(pa, reqBody); |
|
} |
|
|
|
TGSReq getMessage() { |
|
return tgsReqMessg; |
|
} |
|
|
|
Ticket getSecondTicket() { |
|
return secondTicket; |
|
} |
|
|
|
PrincipalName getClientAlias() { |
|
return clientAlias; |
|
} |
|
|
|
PrincipalName getServerAlias() { |
|
return serverAlias; |
|
} |
|
|
|
private static void debug(String message) { |
|
// System.err.println(">>> KrbTgsReq: " + message); |
|
} |
|
|
|
boolean usedSubkey() { |
|
return useSubkey; |
|
} |
|
|
|
} |