Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/KrbTgsReq.java
41159 views
/*1* Copyright (c) 2000, 2019, 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*/2425/*26*27* (C) Copyright IBM Corp. 1999 All Rights Reserved.28* Copyright 1997 The Open Group Research Institute. All rights reserved.29*/3031package sun.security.krb5;3233import sun.security.krb5.internal.*;34import sun.security.krb5.internal.crypto.*;35import java.io.IOException;36import java.net.UnknownHostException;37import java.time.Instant;38import java.util.Arrays;3940/**41* This class encapsulates a Kerberos TGS-REQ that is sent from the42* client to the KDC.43*/44public class KrbTgsReq {4546private PrincipalName princName;47private PrincipalName clientAlias;48private PrincipalName servName;49private PrincipalName serverAlias;50private TGSReq tgsReqMessg;51private KerberosTime ctime;52private Ticket secondTicket = null;53private boolean useSubkey = false;54EncryptionKey tgsReqKey;5556private byte[] obuf;57private byte[] ibuf;5859// Used in CredentialsUtil60public KrbTgsReq(KDCOptions options, Credentials asCreds,61PrincipalName cname, PrincipalName clientAlias,62PrincipalName sname, PrincipalName serverAlias,63Ticket[] additionalTickets, PAData[] extraPAs)64throws KrbException, IOException {65this(options,66asCreds,67cname,68clientAlias,69sname,70serverAlias,71null, // KerberosTime from72null, // KerberosTime till73null, // KerberosTime rtime74null, // int[] eTypes75null, // HostAddresses addresses76null, // AuthorizationData authorizationData77additionalTickets,78null, // EncryptionKey subKey79extraPAs);80}8182// Called by Credentials, KrbCred83KrbTgsReq(84KDCOptions options,85Credentials asCreds,86PrincipalName sname,87PrincipalName serverAlias,88KerberosTime from,89KerberosTime till,90KerberosTime rtime,91int[] eTypes,92HostAddresses addresses,93AuthorizationData authorizationData,94Ticket[] additionalTickets,95EncryptionKey subKey) throws KrbException, IOException {96this(options, asCreds, asCreds.getClient(), asCreds.getClientAlias(),97sname, serverAlias, from, till, rtime, eTypes,98addresses, authorizationData, additionalTickets, subKey, null);99}100101private KrbTgsReq(102KDCOptions options,103Credentials asCreds,104PrincipalName cname,105PrincipalName clientAlias,106PrincipalName sname,107PrincipalName serverAlias,108KerberosTime from,109KerberosTime till,110KerberosTime rtime,111int[] eTypes,112HostAddresses addresses,113AuthorizationData authorizationData,114Ticket[] additionalTickets,115EncryptionKey subKey,116PAData[] extraPAs) throws KrbException, IOException {117118princName = cname;119this.clientAlias = clientAlias;120servName = sname;121this.serverAlias = serverAlias;122ctime = KerberosTime.now();123124// check if they are valid arguments. The optional fields125// should be consistent with settings in KDCOptions.126127if (options.get(KDCOptions.FORWARDABLE) &&128(!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) {129options.set(KDCOptions.FORWARDABLE, false);130}131if (options.get(KDCOptions.FORWARDED)) {132if (!(asCreds.flags.get(KDCOptions.FORWARDABLE)))133throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);134}135if (options.get(KDCOptions.PROXIABLE) &&136(!(asCreds.flags.get(Krb5.TKT_OPTS_PROXIABLE)))) {137throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);138}139if (options.get(KDCOptions.PROXY)) {140if (!(asCreds.flags.get(KDCOptions.PROXIABLE)))141throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);142}143if (options.get(KDCOptions.ALLOW_POSTDATE) &&144(!(asCreds.flags.get(Krb5.TKT_OPTS_MAY_POSTDATE)))) {145throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);146}147if (options.get(KDCOptions.RENEWABLE) &&148(!(asCreds.flags.get(Krb5.TKT_OPTS_RENEWABLE)))) {149throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);150}151152if (options.get(KDCOptions.POSTDATED)) {153if (!(asCreds.flags.get(KDCOptions.POSTDATED)))154throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);155} else {156if (from != null) from = null;157}158if (options.get(KDCOptions.RENEWABLE)) {159if (!(asCreds.flags.get(KDCOptions.RENEWABLE)))160throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);161} else {162if (rtime != null) rtime = null;163}164if (options.get(KDCOptions.ENC_TKT_IN_SKEY) || options.get(KDCOptions.CNAME_IN_ADDL_TKT)) {165if (additionalTickets == null)166throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);167// in TGS_REQ there could be more than one additional168// tickets, but in file-based credential cache,169// there is only one additional ticket field.170secondTicket = additionalTickets[0];171} else {172if (additionalTickets != null)173additionalTickets = null;174}175176tgsReqMessg = createRequest(177options,178asCreds.ticket,179asCreds.key,180ctime,181princName,182servName,183from,184till,185rtime,186eTypes,187addresses,188authorizationData,189additionalTickets,190subKey,191extraPAs);192obuf = tgsReqMessg.asn1Encode();193194// XXX We need to revisit this to see if can't move it195// up such that FORWARDED flag set in the options196// is included in the marshaled request.197/*198* If this is based on a forwarded ticket, record that in the199* options, because the returned TgsRep will contain the200* FORWARDED flag set.201*/202if (asCreds.flags.get(KDCOptions.FORWARDED))203options.set(KDCOptions.FORWARDED, true);204205206}207208/**209* Sends a TGS request to the realm of the target.210* @throws KrbException211* @throws IOException212*/213public void send() throws IOException, KrbException {214String realmStr = null;215if (servName != null)216realmStr = servName.getRealmString();217KdcComm comm = new KdcComm(realmStr);218ibuf = comm.send(obuf);219}220221public KrbTgsRep getReply()222throws KrbException, IOException {223return new KrbTgsRep(ibuf, this);224}225226/**227* Sends the request, waits for a reply, and returns the Credentials.228* Used in Credentials, KrbCred, and internal/CredentialsUtil.229*/230public Credentials sendAndGetCreds() throws IOException, KrbException {231KrbTgsRep tgs_rep = null;232String kdc = null;233send();234tgs_rep = getReply();235return tgs_rep.getCreds();236}237238KerberosTime getCtime() {239return ctime;240}241242private TGSReq createRequest(243KDCOptions kdc_options,244Ticket ticket,245EncryptionKey key,246KerberosTime ctime,247PrincipalName cname,248PrincipalName sname,249KerberosTime from,250KerberosTime till,251KerberosTime rtime,252int[] eTypes,253HostAddresses addresses,254AuthorizationData authorizationData,255Ticket[] additionalTickets,256EncryptionKey subKey,257PAData[] extraPAs)258throws IOException, KrbException, UnknownHostException {259KerberosTime req_till = null;260if (till == null) {261String d = Config.getInstance().get("libdefaults", "ticket_lifetime");262if (d != null) {263req_till = new KerberosTime(Instant.now().plusSeconds(Config.duration(d)));264} else {265req_till = new KerberosTime(0); // Choose KDC maximum allowed266}267} else {268req_till = till;269}270271/*272* RFC 4120, Section 5.4.2.273* For KRB_TGS_REP, the ciphertext is encrypted in the274* sub-session key from the Authenticator, or if absent,275* the session key from the ticket-granting ticket used276* in the request.277*278* To support this, use tgsReqKey to remember which key to use.279*/280tgsReqKey = key;281282int[] req_eTypes = null;283if (eTypes == null) {284req_eTypes = EType.getDefaults("default_tgs_enctypes");285} else {286req_eTypes = eTypes;287}288289EncryptionKey reqKey = null;290EncryptedData encAuthorizationData = null;291if (authorizationData != null) {292byte[] ad = authorizationData.asn1Encode();293if (subKey != null) {294reqKey = subKey;295tgsReqKey = subKey; // Key to use to decrypt reply296useSubkey = true;297encAuthorizationData = new EncryptedData(reqKey, ad,298KeyUsage.KU_TGS_REQ_AUTH_DATA_SUBKEY);299} else300encAuthorizationData = new EncryptedData(key, ad,301KeyUsage.KU_TGS_REQ_AUTH_DATA_SESSKEY);302}303304KDCReqBody reqBody = new KDCReqBody(305kdc_options,306cname,307sname,308from,309req_till,310rtime,311Nonce.value(),312req_eTypes,313addresses,314encAuthorizationData,315additionalTickets);316317byte[] temp = reqBody.asn1Encode(Krb5.KRB_TGS_REQ);318// if the checksum type is one of the keyed checksum types,319// use session key.320Checksum cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp, key,321KeyUsage.KU_PA_TGS_REQ_CKSUM);322323// Usage will be KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR324325byte[] tgs_ap_req = new KrbApReq(326new APOptions(),327ticket,328key,329cname,330cksum,331ctime,332reqKey,333null,334null).getMessage();335336PAData tgsPAData = new PAData(Krb5.PA_TGS_REQ, tgs_ap_req);337PAData[] pa;338if (extraPAs != null) {339pa = Arrays.copyOf(extraPAs, extraPAs.length + 1);340pa[extraPAs.length] = tgsPAData;341} else {342pa = new PAData[] {tgsPAData};343}344return new TGSReq(pa, reqBody);345}346347TGSReq getMessage() {348return tgsReqMessg;349}350351Ticket getSecondTicket() {352return secondTicket;353}354355PrincipalName getClientAlias() {356return clientAlias;357}358359PrincipalName getServerAlias() {360return serverAlias;361}362363private static void debug(String message) {364// System.err.println(">>> KrbTgsReq: " + message);365}366367boolean usedSubkey() {368return useSubkey;369}370371}372373374