Path: blob/master/src/java.security.jgss/share/classes/sun/security/krb5/KrbApReq.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 sun.security.jgss.krb5.Krb5AcceptCredential;36import java.net.InetAddress;37import sun.security.util.*;38import java.io.IOException;39import java.util.Arrays;40import java.security.MessageDigest;41import java.security.NoSuchAlgorithmException;42import sun.security.krb5.internal.rcache.AuthTimeWithHash;4344/**45* This class encapsulates a KRB-AP-REQ that a client sends to a46* server for authentication.47*/48public class KrbApReq {4950private byte[] obuf;51private KerberosTime ctime;52private int cusec;53private Authenticator authenticator;54private Credentials creds;55private APReq apReqMessg;5657// Used by acceptor side58private static ReplayCache rcache = ReplayCache.getInstance();59private static boolean DEBUG = Krb5.DEBUG;60private static final char[] hexConst = "0123456789ABCDEF".toCharArray();6162/**63* Constructs an AP-REQ message to send to the peer.64* @param tgsCred the <code>Credentials</code> to be used to construct the65* AP Request protocol message.66* @param mutualRequired Whether mutual authentication is required67* @param useSubkey Whether the subkey is to be used to protect this68* specific application session. If this is not set then the69* session key from the ticket will be used.70* @throws KrbException for any Kerberos protocol specific error71* @throws IOException for any IO related errors72* (e.g. socket operations)73*/74/*75// Not Used76public KrbApReq(Credentials tgsCred,77boolean mutualRequired,78boolean useSubKey,79boolean useSeqNumber) throws Asn1Exception,80KrbCryptoException, KrbException, IOException {8182this(tgsCred, mutualRequired, useSubKey, useSeqNumber, null);83}84*/8586/**87* Constructs an AP-REQ message to send to the peer.88* @param tgsCred the <code>Credentials</code> to be used to construct the89* AP Request protocol message.90* @param mutualRequired Whether mutual authentication is required91* @param useSubKey Whether the subkey is to be used to protect this92* specific application session. If this is not set then the93* session key from the ticket will be used.94* @param cksum checksum of the application data that accompanies95* the KRB_AP_REQ.96* @throws KrbException for any Kerberos protocol specific error97* @throws IOException for any IO related errors98* (e.g. socket operations)99*/100// Used in InitSecContextToken101public KrbApReq(Credentials tgsCred,102boolean mutualRequired,103boolean useSubKey,104boolean useSeqNumber,105Checksum cksum) throws Asn1Exception,106KrbCryptoException, KrbException, IOException {107108APOptions apOptions = (mutualRequired?109new APOptions(Krb5.AP_OPTS_MUTUAL_REQUIRED):110new APOptions());111if (DEBUG)112System.out.println(">>> KrbApReq: APOptions are " + apOptions);113114EncryptionKey subKey = (useSubKey?115new EncryptionKey(tgsCred.getSessionKey()):116null);117118SeqNumber seqNum = new LocalSeqNumber();119120init(apOptions,121tgsCred,122cksum,123subKey,124seqNum,125null, // AuthorizationData authzData126KeyUsage.KU_AP_REQ_AUTHENTICATOR);127128}129130/**131* Constructs an AP-REQ message from the bytes received from the132* peer.133* @param message The message received from the peer134* @param cred <code>KrbAcceptCredential</code> containing keys to decrypt135* the message; key selected will depend on etype used to encrypt data136* @throws KrbException for any Kerberos protocol specific error137* @throws IOException for any IO related errors138* (e.g. socket operations)139*/140// Used in InitSecContextToken (for AP_REQ and not TGS REQ)141public KrbApReq(byte[] message,142Krb5AcceptCredential cred,143InetAddress initiator)144throws KrbException, IOException {145obuf = message;146if (apReqMessg == null)147decode();148authenticate(cred, initiator);149}150151/**152* Constructs an AP-REQ message from the bytes received from the153* peer.154* @param value The <code>DerValue</code> that contains the155* DER enoded AP-REQ protocol message156* @param keys <code>EncrtyptionKey</code>s to decrypt the message;157*158* @throws KrbException for any Kerberos protocol specific error159* @throws IOException for any IO related errors160* (e.g. socket operations)161*/162/*163public KrbApReq(DerValue value, EncryptionKey[] key, InetAddress initiator)164throws KrbException, IOException {165obuf = value.toByteArray();166if (apReqMessg == null)167decode(value);168authenticate(keys, initiator);169}170171KrbApReq(APOptions options,172Credentials tgs_creds,173Checksum cksum,174EncryptionKey subKey,175SeqNumber seqNumber,176AuthorizationData authorizationData)177throws KrbException, IOException {178init(options, tgs_creds, cksum, subKey, seqNumber, authorizationData);179}180*/181182/** used by KrbTgsReq **/183KrbApReq(APOptions apOptions,184Ticket ticket,185EncryptionKey key,186PrincipalName cname,187Checksum cksum,188KerberosTime ctime,189EncryptionKey subKey,190SeqNumber seqNumber,191AuthorizationData authorizationData)192throws Asn1Exception, IOException,193KdcErrException, KrbCryptoException {194195init(apOptions, ticket, key, cname,196cksum, ctime, subKey, seqNumber, authorizationData,197KeyUsage.KU_PA_TGS_REQ_AUTHENTICATOR);198199}200201private void init(APOptions options,202Credentials tgs_creds,203Checksum cksum,204EncryptionKey subKey,205SeqNumber seqNumber,206AuthorizationData authorizationData,207int usage)208throws KrbException, IOException {209210ctime = KerberosTime.now();211init(options,212tgs_creds.ticket,213tgs_creds.key,214tgs_creds.client,215cksum,216ctime,217subKey,218seqNumber,219authorizationData,220usage);221}222223private void init(APOptions apOptions,224Ticket ticket,225EncryptionKey key,226PrincipalName cname,227Checksum cksum,228KerberosTime ctime,229EncryptionKey subKey,230SeqNumber seqNumber,231AuthorizationData authorizationData,232int usage)233throws Asn1Exception, IOException,234KdcErrException, KrbCryptoException {235236createMessage(apOptions, ticket, key, cname,237cksum, ctime, subKey, seqNumber, authorizationData,238usage);239obuf = apReqMessg.asn1Encode();240}241242243void decode() throws KrbException, IOException {244DerValue encoding = new DerValue(obuf);245decode(encoding);246}247248void decode(DerValue encoding) throws KrbException, IOException {249apReqMessg = null;250try {251apReqMessg = new APReq(encoding);252} catch (Asn1Exception e) {253apReqMessg = null;254KRBError err = new KRBError(encoding);255String errStr = err.getErrorString();256String eText;257if (errStr.charAt(errStr.length() - 1) == 0)258eText = errStr.substring(0, errStr.length() - 1);259else260eText = errStr;261KrbException ke = new KrbException(err.getErrorCode(), eText);262ke.initCause(e);263throw ke;264}265}266267private void authenticate(Krb5AcceptCredential cred, InetAddress initiator)268throws KrbException, IOException {269int encPartKeyType = apReqMessg.ticket.encPart.getEType();270Integer kvno = apReqMessg.ticket.encPart.getKeyVersionNumber();271EncryptionKey[] keys = cred.getKrb5EncryptionKeys(apReqMessg.ticket.sname);272EncryptionKey dkey = EncryptionKey.findKey(encPartKeyType, kvno, keys);273274if (dkey == null) {275throw new KrbException(Krb5.API_INVALID_ARG,276"Cannot find key of appropriate type to decrypt AP-REQ - " +277EType.toString(encPartKeyType));278}279280byte[] bytes = apReqMessg.ticket.encPart.decrypt(dkey,281KeyUsage.KU_TICKET);282byte[] temp = apReqMessg.ticket.encPart.reset(bytes);283EncTicketPart enc_ticketPart = new EncTicketPart(temp);284285checkPermittedEType(enc_ticketPart.key.getEType());286287byte[] bytes2 = apReqMessg.authenticator.decrypt(enc_ticketPart.key,288KeyUsage.KU_AP_REQ_AUTHENTICATOR);289byte[] temp2 = apReqMessg.authenticator.reset(bytes2);290authenticator = new Authenticator(temp2);291ctime = authenticator.ctime;292cusec = authenticator.cusec;293authenticator.ctime =294authenticator.ctime.withMicroSeconds(authenticator.cusec);295296if (!authenticator.cname.equals(enc_ticketPart.cname)) {297throw new KrbApErrException(Krb5.KRB_AP_ERR_BADMATCH);298}299300if (!authenticator.ctime.inClockSkew())301throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);302303String alg = AuthTimeWithHash.DEFAULT_HASH_ALG;304byte[] hash;305try {306hash = MessageDigest.getInstance(AuthTimeWithHash.realAlg(alg))307.digest(apReqMessg.authenticator.cipher);308} catch (NoSuchAlgorithmException ex) {309throw new AssertionError("Impossible " + alg);310}311312char[] h = new char[hash.length * 2];313for (int i=0; i<hash.length; i++) {314h[2*i] = hexConst[(hash[i]&0xff)>>4];315h[2*i+1] = hexConst[hash[i]&0xf];316}317AuthTimeWithHash time = new AuthTimeWithHash(318authenticator.cname.toString(),319apReqMessg.ticket.sname.toString(),320authenticator.ctime.getSeconds(),321authenticator.cusec,322alg,323new String(h));324rcache.checkAndStore(KerberosTime.now(), time);325326if (initiator != null) {327// sender host address328HostAddress sender = new HostAddress(initiator);329if (enc_ticketPart.caddr != null330&& !enc_ticketPart.caddr.inList(sender)) {331if (DEBUG) {332System.out.println(">>> KrbApReq: initiator is "333+ sender.getInetAddress()334+ ", but caddr is "335+ Arrays.toString(336enc_ticketPart.caddr.getInetAddresses()));337}338throw new KrbApErrException(Krb5.KRB_AP_ERR_BADADDR);339}340}341342// XXX check for repeated authenticator343// if found344// throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);345// else346// save authenticator to check for later347348KerberosTime now = KerberosTime.now();349350if ((enc_ticketPart.starttime != null &&351enc_ticketPart.starttime.greaterThanWRTClockSkew(now)) ||352enc_ticketPart.flags.get(Krb5.TKT_OPTS_INVALID))353throw new KrbApErrException(Krb5.KRB_AP_ERR_TKT_NYV);354355// if the current time is later than end time by more356// than the allowable clock skew, throws ticket expired exception.357if (enc_ticketPart.endtime != null &&358now.greaterThanWRTClockSkew(enc_ticketPart.endtime)) {359throw new KrbApErrException(Krb5.KRB_AP_ERR_TKT_EXPIRED);360}361362creds = new Credentials(363apReqMessg.ticket,364authenticator.cname,365null,366apReqMessg.ticket.sname,367null,368enc_ticketPart.key,369enc_ticketPart.flags,370enc_ticketPart.authtime,371enc_ticketPart.starttime,372enc_ticketPart.endtime,373enc_ticketPart.renewTill,374enc_ticketPart.caddr,375enc_ticketPart.authorizationData);376if (DEBUG) {377System.out.println(">>> KrbApReq: authenticate succeed.");378}379}380381/**382* Returns the credentials that are contained in the ticket that383* is part of this AP-REQ.384*/385public Credentials getCreds() {386return creds;387}388389KerberosTime getCtime() {390if (ctime != null)391return ctime;392return authenticator.ctime;393}394395int cusec() {396return cusec;397}398399APOptions getAPOptions() throws KrbException, IOException {400if (apReqMessg == null)401decode();402if (apReqMessg != null)403return apReqMessg.apOptions;404return null;405}406407/**408* Returns true if mutual authentication is required and hence an409* AP-REP will need to be generated.410* @throws KrbException411* @throws IOException412*/413public boolean getMutualAuthRequired() throws KrbException, IOException {414if (apReqMessg == null)415decode();416if (apReqMessg != null)417return apReqMessg.apOptions.get(Krb5.AP_OPTS_MUTUAL_REQUIRED);418return false;419}420421boolean useSessionKey() throws KrbException, IOException {422if (apReqMessg == null)423decode();424if (apReqMessg != null)425return apReqMessg.apOptions.get(Krb5.AP_OPTS_USE_SESSION_KEY);426return false;427}428429/**430* Returns the optional subkey stored in the Authenticator for431* this message. Returns null if none is stored.432*/433public EncryptionKey getSubKey() {434// XXX Can authenticator be null435return authenticator.getSubKey();436}437438/**439* Returns the optional sequence number stored in the440* Authenticator for this message. Returns null if none is441* stored.442*/443public Integer getSeqNumber() {444// XXX Can authenticator be null445return authenticator.getSeqNumber();446}447448/**449* Returns the optional Checksum stored in the450* Authenticator for this message. Returns null if none is451* stored.452*/453public Checksum getChecksum() {454return authenticator.getChecksum();455}456457/**458* Returns the ASN.1 encoding that should be sent to the peer.459*/460public byte[] getMessage() {461return obuf;462}463464/**465* Returns the principal name of the client that generated this466* message.467*/468public PrincipalName getClient() {469return creds.getClient();470}471472private void createMessage(APOptions apOptions,473Ticket ticket,474EncryptionKey key,475PrincipalName cname,476Checksum cksum,477KerberosTime ctime,478EncryptionKey subKey,479SeqNumber seqNumber,480AuthorizationData authorizationData,481int usage)482throws Asn1Exception, IOException,483KdcErrException, KrbCryptoException {484485Integer seqno = null;486487if (seqNumber != null)488seqno = seqNumber.current();489490authenticator =491new Authenticator(cname,492cksum,493ctime.getMicroSeconds(),494ctime,495subKey,496seqno,497authorizationData);498499byte[] temp = authenticator.asn1Encode();500501EncryptedData encAuthenticator =502new EncryptedData(key, temp, usage);503504apReqMessg =505new APReq(apOptions, ticket, encAuthenticator);506}507508// Check that key is one of the permitted types509private static void checkPermittedEType(int target) throws KrbException {510int[] etypes = EType.getDefaults("permitted_enctypes");511if (!EType.isSupported(target, etypes)) {512throw new KrbException(EType.toString(target) +513" encryption type not in permitted_enctypes list");514}515}516}517518519