0N/A/*
3054N/A * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A *
0N/A * (C) Copyright IBM Corp. 1999 All Rights Reserved.
0N/A * Copyright 1997 The Open Group Research Institute. All rights reserved.
0N/A */
0N/A
0N/Apackage sun.security.krb5;
0N/A
0N/Aimport sun.security.krb5.internal.*;
0N/Aimport sun.security.krb5.internal.crypto.*;
0N/Aimport java.io.IOException;
0N/Aimport java.net.UnknownHostException;
0N/A
0N/A/**
0N/A * This class encapsulates a Kerberos TGS-REQ that is sent from the
0N/A * client to the KDC.
0N/A */
3054N/Apublic class KrbTgsReq {
0N/A
0N/A private PrincipalName princName;
0N/A private PrincipalName servName;
0N/A private TGSReq tgsReqMessg;
0N/A private KerberosTime ctime;
0N/A private Ticket secondTicket = null;
0N/A private boolean useSubkey = false;
0N/A EncryptionKey tgsReqKey;
0N/A
0N/A private static final boolean DEBUG = Krb5.DEBUG;
0N/A
3054N/A private byte[] obuf;
3054N/A private byte[] ibuf;
0N/A
0N/A // Used in CredentialsUtil
0N/A public KrbTgsReq(Credentials asCreds,
0N/A PrincipalName sname)
0N/A throws KrbException, IOException {
0N/A this(new KDCOptions(),
0N/A asCreds,
0N/A sname,
0N/A null, // KerberosTime from
0N/A null, // KerberosTime till
0N/A null, // KerberosTime rtime
0N/A null, // eTypes, // null, // int[] eTypes
0N/A null, // HostAddresses addresses
0N/A null, // AuthorizationData authorizationData
0N/A null, // Ticket[] additionalTickets
0N/A null); // EncryptionKey subSessionKey
0N/A }
0N/A
50N/A // Called by Credentials, KrbCred
50N/A KrbTgsReq(
50N/A KDCOptions options,
50N/A Credentials asCreds,
50N/A PrincipalName sname,
50N/A KerberosTime from,
50N/A KerberosTime till,
50N/A KerberosTime rtime,
50N/A int[] eTypes,
50N/A HostAddresses addresses,
50N/A AuthorizationData authorizationData,
50N/A Ticket[] additionalTickets,
50N/A EncryptionKey subKey) throws KrbException, IOException {
0N/A
50N/A princName = asCreds.client;
50N/A servName = sname;
50N/A ctime = new KerberosTime(KerberosTime.NOW);
0N/A
0N/A
50N/A // check if they are valid arguments. The optional fields
50N/A // should be consistent with settings in KDCOptions.
50N/A if (options.get(KDCOptions.FORWARDABLE) &&
50N/A (!(asCreds.flags.get(Krb5.TKT_OPTS_FORWARDABLE)))) {
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A }
50N/A if (options.get(KDCOptions.FORWARDED)) {
50N/A if (!(asCreds.flags.get(KDCOptions.FORWARDABLE)))
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A }
50N/A if (options.get(KDCOptions.PROXIABLE) &&
50N/A (!(asCreds.flags.get(Krb5.TKT_OPTS_PROXIABLE)))) {
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A }
50N/A if (options.get(KDCOptions.PROXY)) {
50N/A if (!(asCreds.flags.get(KDCOptions.PROXIABLE)))
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A }
50N/A if (options.get(KDCOptions.ALLOW_POSTDATE) &&
50N/A (!(asCreds.flags.get(Krb5.TKT_OPTS_MAY_POSTDATE)))) {
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A }
50N/A if (options.get(KDCOptions.RENEWABLE) &&
50N/A (!(asCreds.flags.get(Krb5.TKT_OPTS_RENEWABLE)))) {
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A }
0N/A
50N/A if (options.get(KDCOptions.POSTDATED)) {
50N/A if (!(asCreds.flags.get(KDCOptions.POSTDATED)))
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A } else {
50N/A if (from != null) from = null;
50N/A }
50N/A if (options.get(KDCOptions.RENEWABLE)) {
50N/A if (!(asCreds.flags.get(KDCOptions.RENEWABLE)))
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A } else {
50N/A if (rtime != null) rtime = null;
50N/A }
50N/A if (options.get(KDCOptions.ENC_TKT_IN_SKEY)) {
50N/A if (additionalTickets == null)
50N/A throw new KrbException(Krb5.KRB_AP_ERR_REQ_OPTIONS);
50N/A // in TGS_REQ there could be more than one additional
50N/A // tickets, but in file-based credential cache,
50N/A // there is only one additional ticket field.
50N/A secondTicket = additionalTickets[0];
50N/A } else {
50N/A if (additionalTickets != null)
50N/A additionalTickets = null;
50N/A }
0N/A
50N/A tgsReqMessg = createRequest(
50N/A options,
50N/A asCreds.ticket,
50N/A asCreds.key,
50N/A ctime,
50N/A princName,
50N/A princName.getRealm(),
50N/A servName,
50N/A from,
50N/A till,
50N/A rtime,
50N/A eTypes,
50N/A addresses,
50N/A authorizationData,
50N/A additionalTickets,
50N/A subKey);
50N/A obuf = tgsReqMessg.asn1Encode();
0N/A
50N/A // XXX We need to revisit this to see if can't move it
50N/A // up such that FORWARDED flag set in the options
50N/A // is included in the marshaled request.
50N/A /*
50N/A * If this is based on a forwarded ticket, record that in the
50N/A * options, because the returned TgsRep will contain the
50N/A * FORWARDED flag set.
50N/A */
50N/A if (asCreds.flags.get(KDCOptions.FORWARDED))
50N/A options.set(KDCOptions.FORWARDED, true);
0N/A
0N/A
50N/A }
0N/A
0N/A /**
0N/A * Sends a TGS request to the realm of the target.
0N/A * @throws KrbException
0N/A * @throws IOException
0N/A */
3054N/A public void send() throws IOException, KrbException {
0N/A String realmStr = null;
0N/A if (servName != null)
0N/A realmStr = servName.getRealmString();
3054N/A KdcComm comm = new KdcComm(realmStr);
3054N/A ibuf = comm.send(obuf);
0N/A }
0N/A
0N/A public KrbTgsRep getReply()
0N/A throws KrbException, IOException {
0N/A return new KrbTgsRep(ibuf, this);
0N/A }
0N/A
0N/A /**
0N/A * Sends the request, waits for a reply, and returns the Credentials.
0N/A * Used in Credentials, KrbCred, and internal/CredentialsUtil.
0N/A */
0N/A public Credentials sendAndGetCreds() throws IOException, KrbException {
0N/A KrbTgsRep tgs_rep = null;
0N/A String kdc = null;
3054N/A send();
3054N/A tgs_rep = getReply();
0N/A return tgs_rep.getCreds();
0N/A }
0N/A
0N/A KerberosTime getCtime() {
0N/A return ctime;
0N/A }
0N/A
0N/A private TGSReq createRequest(
0N/A KDCOptions kdc_options,
0N/A Ticket ticket,
0N/A EncryptionKey key,
0N/A KerberosTime ctime,
0N/A PrincipalName cname,
0N/A Realm crealm,
0N/A PrincipalName sname,
0N/A KerberosTime from,
0N/A KerberosTime till,
0N/A KerberosTime rtime,
0N/A int[] eTypes,
0N/A HostAddresses addresses,
0N/A AuthorizationData authorizationData,
0N/A Ticket[] additionalTickets,
0N/A EncryptionKey subKey)
0N/A throws Asn1Exception, IOException, KdcErrException, KrbApErrException,
0N/A UnknownHostException, KrbCryptoException {
0N/A KerberosTime req_till = null;
0N/A if (till == null) {
3054N/A req_till = new KerberosTime(0);
0N/A } else {
0N/A req_till = till;
0N/A }
0N/A
0N/A /*
0N/A * RFC 4120, Section 5.4.2.
0N/A * For KRB_TGS_REP, the ciphertext is encrypted in the
0N/A * sub-session key from the Authenticator, or if absent,
0N/A * the session key from the ticket-granting ticket used
0N/A * in the request.
0N/A *
0N/A * To support this, use tgsReqKey to remember which key to use.
0N/A */
0N/A tgsReqKey = key;
0N/A
0N/A int[] req_eTypes = null;
0N/A if (eTypes == null) {
0N/A req_eTypes = EType.getDefaults("default_tgs_enctypes");
0N/A if (req_eTypes == null) {
0N/A throw new KrbCryptoException(
0N/A "No supported encryption types listed in default_tgs_enctypes");
0N/A }
0N/A } else {
0N/A req_eTypes = eTypes;
0N/A }
0N/A
0N/A EncryptionKey reqKey = null;
0N/A EncryptedData encAuthorizationData = null;
0N/A if (authorizationData != null) {
0N/A byte[] ad = authorizationData.asn1Encode();
0N/A if (subKey != null) {
0N/A reqKey = subKey;
0N/A tgsReqKey = subKey; // Key to use to decrypt reply
0N/A useSubkey = true;
0N/A encAuthorizationData = new EncryptedData(reqKey, ad,
0N/A KeyUsage.KU_TGS_REQ_AUTH_DATA_SUBKEY);
0N/A } else
0N/A encAuthorizationData = new EncryptedData(key, ad,
0N/A KeyUsage.KU_TGS_REQ_AUTH_DATA_SESSKEY);
0N/A }
0N/A
0N/A KDCReqBody reqBody = new KDCReqBody(
0N/A kdc_options,
0N/A cname,
0N/A // crealm,
0N/A sname.getRealm(), // TO
0N/A sname,
0N/A from,
0N/A req_till,
0N/A rtime,
0N/A Nonce.value(),
0N/A req_eTypes,
0N/A addresses,
0N/A encAuthorizationData,
0N/A additionalTickets);
0N/A
0N/A byte[] temp = reqBody.asn1Encode(Krb5.KRB_TGS_REQ);
0N/A // if the checksum type is one of the keyed checksum types,
0N/A // use session key.
0N/A Checksum cksum;
0N/A switch (Checksum.CKSUMTYPE_DEFAULT) {
0N/A case Checksum.CKSUMTYPE_RSA_MD4_DES:
0N/A case Checksum.CKSUMTYPE_DES_MAC:
0N/A case Checksum.CKSUMTYPE_DES_MAC_K:
0N/A case Checksum.CKSUMTYPE_RSA_MD4_DES_K:
0N/A case Checksum.CKSUMTYPE_RSA_MD5_DES:
0N/A case Checksum.CKSUMTYPE_HMAC_SHA1_DES3_KD:
0N/A case Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR:
0N/A case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES128:
0N/A case Checksum.CKSUMTYPE_HMAC_SHA1_96_AES256:
0N/A cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp, key,
0N/A KeyUsage.KU_PA_TGS_REQ_CKSUM);
0N/A break;
0N/A case Checksum.CKSUMTYPE_CRC32:
0N/A case Checksum.CKSUMTYPE_RSA_MD4:
0N/A case Checksum.CKSUMTYPE_RSA_MD5:
0N/A default:
0N/A cksum = new Checksum(Checksum.CKSUMTYPE_DEFAULT, temp);
0N/A }
0N/A
0N/A // Usage will be KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR
0N/A
0N/A byte[] tgs_ap_req = new KrbApReq(
0N/A new APOptions(),
0N/A ticket,
0N/A key,
0N/A crealm,
0N/A cname,
0N/A cksum,
0N/A ctime,
0N/A reqKey,
0N/A null,
0N/A null).getMessage();
0N/A
0N/A PAData[] tgsPAData = new PAData[1];
0N/A tgsPAData[0] = new PAData(Krb5.PA_TGS_REQ, tgs_ap_req);
0N/A
0N/A return new TGSReq(tgsPAData, reqBody);
0N/A }
0N/A
0N/A TGSReq getMessage() {
0N/A return tgsReqMessg;
0N/A }
0N/A
0N/A Ticket getSecondTicket() {
0N/A return secondTicket;
0N/A }
0N/A
0N/A private static void debug(String message) {
0N/A // System.err.println(">>> KrbTgsReq: " + message);
0N/A }
0N/A
0N/A boolean usedSubkey() {
0N/A return useSubkey;
0N/A }
0N/A
0N/A}