507 lines · 17.8 KB · Java
RawDownload
/* * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * *  (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 sun.security.krb5.internal.rcache.*;import java.net.InetAddress;import sun.security.util.*;import java.io.IOException;import java.util.Arrays; /** * This class encapsulates a KRB-AP-REQ that a client sends to a * server for authentication. */public class KrbApReq {     private byte[] obuf;    private KerberosTime ctime;    private int cusec;    private Authenticator authenticator;    private Credentials creds;    private APReq apReqMessg;     private static CacheTable table = new CacheTable();    private static boolean DEBUG = Krb5.DEBUG;     /**     * Contructs a AP-REQ message to send to the peer.     * @param tgsCred the <code>Credentials</code> to be used to construct the     *          AP Request  protocol message.     * @param mutualRequired Whether mutual authentication is required     * @param useSubkey Whether the subkey is to be used to protect this     *        specific application session. If this is not set then the     *        session key from the ticket will be used.     * @throws KrbException for any Kerberos protocol specific error     * @throws IOException for any IO related errors     *          (e.g. socket operations)     */     /*     // Not Used    public KrbApReq(Credentials tgsCred,                    boolean mutualRequired,                    boolean useSubKey,                    boolean useSeqNumber) throws Asn1Exception,                    KrbCryptoException, KrbException, IOException {         this(tgsCred, mutualRequired, useSubKey, useSeqNumber, null);    }*/     /**     * Contructs a AP-REQ message to send to the peer.     * @param tgsCred the <code>Credentials</code> to be used to construct the     *          AP Request  protocol message.     * @param mutualRequired Whether mutual authentication is required     * @param useSubkey Whether the subkey is to be used to protect this     *        specific application session. If this is not set then the     *        session key from the ticket will be used.     * @param checksum checksum of the the application data that accompanies     *        the KRB_AP_REQ.     * @throws KrbException for any Kerberos protocol specific error     * @throws IOException for any IO related errors     *          (e.g. socket operations)     */     // Used in InitSecContextToken    public KrbApReq(Credentials tgsCred,                    boolean mutualRequired,                    boolean useSubKey,                    boolean useSeqNumber,                    Checksum cksum) throws Asn1Exception,                    KrbCryptoException, KrbException, IOException  {         APOptions apOptions = (mutualRequired?                               new APOptions(Krb5.AP_OPTS_MUTUAL_REQUIRED):                               new APOptions());        if (DEBUG)            System.out.println(">>> KrbApReq: APOptions are " + apOptions);         EncryptionKey subKey = (useSubKey?                                new EncryptionKey(tgsCred.getSessionKey()):                                null);         SeqNumber seqNum = new LocalSeqNumber();         init(apOptions,             tgsCred,             cksum,             subKey,             seqNum,             null,   // AuthorizationData authzData            KeyUsage.KU_AP_REQ_AUTHENTICATOR);     }     /**     * Contructs a AP-REQ message from the bytes received from the     * peer.     * @param message The message received from the peer     * @param keys <code>EncrtyptionKey</code>s to decrypt the message;     *       key selected will depend on etype used to encrypte data     * @throws KrbException for any Kerberos protocol specific error     * @throws IOException for any IO related errors     *          (e.g. socket operations)     */     // Used in InitSecContextToken (for AP_REQ and not TGS REQ)    public KrbApReq(byte[] message,                    EncryptionKey[] keys,                    InetAddress initiator)        throws KrbException, IOException {        obuf = message;        if (apReqMessg == null)            decode();        authenticate(keys, initiator);    }     /**     * Contructs a AP-REQ message from the bytes received from the     * peer.     * @param value The <code>DerValue</code> that contains the     *              DER enoded AP-REQ protocol message     * @param keys <code>EncrtyptionKey</code>s to decrypt the message;     *     * @throws KrbException for any Kerberos protocol specific error     * @throws IOException for any IO related errors     *          (e.g. socket operations)     */     /*    public KrbApReq(DerValue value, EncryptionKey[] key, InetAddress initiator)        throws KrbException, IOException {        obuf = value.toByteArray();        if (apReqMessg == null)            decode(value);        authenticate(keys, initiator);    }     KrbApReq(APOptions options,             Credentials tgs_creds,             Checksum cksum,             EncryptionKey subKey,             SeqNumber seqNumber,             AuthorizationData authorizationData)        throws KrbException, IOException {        init(options, tgs_creds, cksum, subKey, seqNumber, authorizationData);    }*/      /** used by KrbTgsReq **/    KrbApReq(APOptions apOptions,             Ticket ticket,             EncryptionKey key,             Realm crealm,             PrincipalName cname,             Checksum cksum,             KerberosTime ctime,             EncryptionKey subKey,             SeqNumber seqNumber,        AuthorizationData authorizationData)        throws Asn1Exception, IOException,               KdcErrException, KrbCryptoException {         init(apOptions, ticket, key, crealm, cname,             cksum, ctime, subKey, seqNumber, authorizationData,            KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR);     }     private void init(APOptions options,                      Credentials tgs_creds,                      Checksum cksum,                      EncryptionKey subKey,                      SeqNumber seqNumber,                      AuthorizationData authorizationData,        int usage)        throws KrbException, IOException {         ctime = new KerberosTime(KerberosTime.NOW);        init(options,             tgs_creds.ticket,             tgs_creds.key,             tgs_creds.client.getRealm(),             tgs_creds.client,             cksum,             ctime,             subKey,             seqNumber,             authorizationData,            usage);    }     private void init(APOptions apOptions,                      Ticket ticket,                      EncryptionKey key,                      Realm crealm,                      PrincipalName cname,                      Checksum cksum,                      KerberosTime ctime,                      EncryptionKey subKey,                      SeqNumber seqNumber,                      AuthorizationData authorizationData,        int usage)        throws Asn1Exception, IOException,               KdcErrException, KrbCryptoException {         createMessage(apOptions, ticket, key, crealm, cname,                      cksum, ctime, subKey, seqNumber, authorizationData,            usage);        obuf = apReqMessg.asn1Encode();    }      void decode() throws KrbException, IOException {        DerValue encoding = new DerValue(obuf);        decode(encoding);    }     void decode(DerValue encoding) throws KrbException, IOException {        apReqMessg = null;        try {            apReqMessg = new APReq(encoding);        } catch (Asn1Exception e) {            apReqMessg = null;            KRBError err = new KRBError(encoding);            String errStr = err.getErrorString();            String eText;            if (errStr.charAt(errStr.length() - 1) == 0)                eText = errStr.substring(0, errStr.length() - 1);            else                eText = errStr;            KrbException ke = new KrbException(err.getErrorCode(), eText);            ke.initCause(e);            throw ke;        }    }     private void authenticate(EncryptionKey[] keys, InetAddress initiator)        throws KrbException, IOException {        int encPartKeyType = apReqMessg.ticket.encPart.getEType();        Integer kvno = apReqMessg.ticket.encPart.getKeyVersionNumber();        EncryptionKey dkey = EncryptionKey.findKey(encPartKeyType, kvno, keys);         if (dkey == null) {            throw new KrbException(Krb5.API_INVALID_ARG,                "Cannot find key of appropriate type to decrypt AP REP - " +                                   EType.toString(encPartKeyType));        }         byte[] bytes = apReqMessg.ticket.encPart.decrypt(dkey,            KeyUsage.KU_TICKET);        byte[] temp = apReqMessg.ticket.encPart.reset(bytes);        EncTicketPart enc_ticketPart = new EncTicketPart(temp);         checkPermittedEType(enc_ticketPart.key.getEType());         byte[] bytes2 = apReqMessg.authenticator.decrypt(enc_ticketPart.key,            KeyUsage.KU_AP_REQ_AUTHENTICATOR);        byte[] temp2 = apReqMessg.authenticator.reset(bytes2);        authenticator = new Authenticator(temp2);        ctime = authenticator.ctime;        cusec = authenticator.cusec;        authenticator.ctime.setMicroSeconds(authenticator.cusec);        authenticator.cname.setRealm(authenticator.crealm);        apReqMessg.ticket.sname.setRealm(apReqMessg.ticket.realm);        enc_ticketPart.cname.setRealm(enc_ticketPart.crealm);         if (!authenticator.cname.equals(enc_ticketPart.cname))            throw new KrbApErrException(Krb5.KRB_AP_ERR_BADMATCH);         KerberosTime currTime = new KerberosTime(KerberosTime.NOW);        if (!authenticator.ctime.inClockSkew(currTime))            throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);         // start to check if it is a replay attack.        AuthTime time =            new AuthTime(authenticator.ctime.getTime(), authenticator.cusec);        String client = authenticator.cname.toString();        if (table.get(time, authenticator.cname.toString()) != null) {            throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);        } else {            table.put(client, time, currTime.getTime());        }         if (initiator != null) {            // sender host address            HostAddress sender = new HostAddress(initiator);            if (enc_ticketPart.caddr != null                    && !enc_ticketPart.caddr.inList(sender)) {                if (DEBUG) {                    System.out.println(">>> KrbApReq: initiator is "                            + sender.getInetAddress()                            + ", but caddr is "                            + Arrays.toString(                                enc_ticketPart.caddr.getInetAddresses()));                }                throw new KrbApErrException(Krb5.KRB_AP_ERR_BADADDR);            }        }         // XXX check for repeated authenticator        // if found        //    throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);        // else        //    save authenticator to check for later         KerberosTime now = new KerberosTime(KerberosTime.NOW);         if ((enc_ticketPart.starttime != null &&             enc_ticketPart.starttime.greaterThanWRTClockSkew(now)) ||            enc_ticketPart.flags.get(Krb5.TKT_OPTS_INVALID))            throw new KrbApErrException(Krb5.KRB_AP_ERR_TKT_NYV);         // if the current time is later than end time by more        // than the allowable clock skew, throws ticket expired exception.        if (enc_ticketPart.endtime != null &&            now.greaterThanWRTClockSkew(enc_ticketPart.endtime)) {            throw new KrbApErrException(Krb5.KRB_AP_ERR_TKT_EXPIRED);        }         creds = new Credentials(                                apReqMessg.ticket,                                authenticator.cname,                                apReqMessg.ticket.sname,                                enc_ticketPart.key,                                enc_ticketPart.flags,                                enc_ticketPart.authtime,                                enc_ticketPart.starttime,                                enc_ticketPart.endtime,                                enc_ticketPart.renewTill,                                enc_ticketPart.caddr,                                enc_ticketPart.authorizationData);        if (DEBUG) {            System.out.println(">>> KrbApReq: authenticate succeed.");        }    }     /**     * Returns the credentials that are contained in the ticket that     * is part of this this AP-REP.     */    public Credentials getCreds() {        return creds;    }     KerberosTime getCtime() {        if (ctime != null)            return ctime;        return authenticator.ctime;    }     int cusec() {        return cusec;    }     APOptions getAPOptions() throws KrbException, IOException {        if (apReqMessg == null)            decode();        if (apReqMessg != null)            return apReqMessg.apOptions;        return null;    }     /**     * Returns true if mutual authentication is required and hence an     * AP-REP will need to be generated.     * @throws KrbException     * @throws IOException     */    public boolean getMutualAuthRequired() throws KrbException, IOException {        if (apReqMessg == null)            decode();        if (apReqMessg != null)            return apReqMessg.apOptions.get(Krb5.AP_OPTS_MUTUAL_REQUIRED);        return false;    }     boolean useSessionKey() throws KrbException, IOException {        if (apReqMessg == null)            decode();        if (apReqMessg != null)            return apReqMessg.apOptions.get(Krb5.AP_OPTS_USE_SESSION_KEY);        return false;    }     /**     * Returns the optional subkey stored in the Authenticator for     * this message. Returns null if none is stored.     */    public EncryptionKey getSubKey() {        // XXX Can authenticator be null        return authenticator.getSubKey();    }     /**     * Returns the optional sequence number stored in the     * Authenticator for this message. Returns null if none is     * stored.     */    public Integer getSeqNumber() {        // XXX Can authenticator be null        return authenticator.getSeqNumber();    }     /**     * Returns the optional Checksum stored in the     * Authenticator for this message. Returns null if none is     * stored.     */    public Checksum getChecksum() {        return authenticator.getChecksum();    }     /**     * Returns the ASN.1 encoding that should be sent to the peer.     */    public byte[] getMessage() {        return obuf;    }     /**     * Returns the principal name of the client that generated this     * message.     */    public PrincipalName getClient() {        return creds.getClient();    }     private void createMessage(APOptions apOptions,                               Ticket ticket,                               EncryptionKey key,                               Realm crealm,                               PrincipalName cname,                               Checksum cksum,                               KerberosTime ctime,                               EncryptionKey subKey,                               SeqNumber seqNumber,                               AuthorizationData authorizationData,        int usage)        throws Asn1Exception, IOException,               KdcErrException, KrbCryptoException {         Integer seqno = null;         if (seqNumber != null)            seqno = new Integer(seqNumber.current());         authenticator =            new Authenticator(crealm,                              cname,                              cksum,                              ctime.getMicroSeconds(),                              ctime,                              subKey,                              seqno,                              authorizationData);         byte[] temp = authenticator.asn1Encode();         EncryptedData encAuthenticator =            new EncryptedData(key, temp, usage);         apReqMessg =            new APReq(apOptions, ticket, encAuthenticator);    }      // Check that key is one of the permitted types     private static void checkPermittedEType(int target) throws KrbException {        int[] etypes = EType.getDefaults("permitted_enctypes");        if (etypes == null) {            throw new KrbException(                "No supported encryption types listed in permitted_enctypes");

Lines 1–500 of 507.