Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
38830 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 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 REP - " +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);302303byte[] hash;304try {305hash = MessageDigest.getInstance("MD5")306.digest(apReqMessg.authenticator.cipher);307} catch (NoSuchAlgorithmException ex) {308throw new AssertionError("Impossible");309}310311char[] h = new char[hash.length * 2];312for (int i=0; i<hash.length; i++) {313h[2*i] = hexConst[(hash[i]&0xff)>>4];314h[2*i+1] = hexConst[hash[i]&0xf];315}316AuthTimeWithHash time = new AuthTimeWithHash(317authenticator.cname.toString(),318apReqMessg.ticket.sname.toString(),319authenticator.ctime.getSeconds(),320authenticator.cusec,321new String(h));322rcache.checkAndStore(KerberosTime.now(), time);323324if (initiator != null) {325// sender host address326HostAddress sender = new HostAddress(initiator);327if (enc_ticketPart.caddr != null328&& !enc_ticketPart.caddr.inList(sender)) {329if (DEBUG) {330System.out.println(">>> KrbApReq: initiator is "331+ sender.getInetAddress()332+ ", but caddr is "333+ Arrays.toString(334enc_ticketPart.caddr.getInetAddresses()));335}336throw new KrbApErrException(Krb5.KRB_AP_ERR_BADADDR);337}338}339340// XXX check for repeated authenticator341// if found342// throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);343// else344// save authenticator to check for later345346KerberosTime now = KerberosTime.now();347348if ((enc_ticketPart.starttime != null &&349enc_ticketPart.starttime.greaterThanWRTClockSkew(now)) ||350enc_ticketPart.flags.get(Krb5.TKT_OPTS_INVALID))351throw new KrbApErrException(Krb5.KRB_AP_ERR_TKT_NYV);352353// if the current time is later than end time by more354// than the allowable clock skew, throws ticket expired exception.355if (enc_ticketPart.endtime != null &&356now.greaterThanWRTClockSkew(enc_ticketPart.endtime)) {357throw new KrbApErrException(Krb5.KRB_AP_ERR_TKT_EXPIRED);358}359360creds = new Credentials(361apReqMessg.ticket,362authenticator.cname,363null,364apReqMessg.ticket.sname,365null,366enc_ticketPart.key,367enc_ticketPart.flags,368enc_ticketPart.authtime,369enc_ticketPart.starttime,370enc_ticketPart.endtime,371enc_ticketPart.renewTill,372enc_ticketPart.caddr,373enc_ticketPart.authorizationData);374if (DEBUG) {375System.out.println(">>> KrbApReq: authenticate succeed.");376}377}378379/**380* Returns the credentials that are contained in the ticket that381* is part of this this AP-REP.382*/383public Credentials getCreds() {384return creds;385}386387KerberosTime getCtime() {388if (ctime != null)389return ctime;390return authenticator.ctime;391}392393int cusec() {394return cusec;395}396397APOptions getAPOptions() throws KrbException, IOException {398if (apReqMessg == null)399decode();400if (apReqMessg != null)401return apReqMessg.apOptions;402return null;403}404405/**406* Returns true if mutual authentication is required and hence an407* AP-REP will need to be generated.408* @throws KrbException409* @throws IOException410*/411public boolean getMutualAuthRequired() throws KrbException, IOException {412if (apReqMessg == null)413decode();414if (apReqMessg != null)415return apReqMessg.apOptions.get(Krb5.AP_OPTS_MUTUAL_REQUIRED);416return false;417}418419boolean useSessionKey() throws KrbException, IOException {420if (apReqMessg == null)421decode();422if (apReqMessg != null)423return apReqMessg.apOptions.get(Krb5.AP_OPTS_USE_SESSION_KEY);424return false;425}426427/**428* Returns the optional subkey stored in the Authenticator for429* this message. Returns null if none is stored.430*/431public EncryptionKey getSubKey() {432// XXX Can authenticator be null433return authenticator.getSubKey();434}435436/**437* Returns the optional sequence number stored in the438* Authenticator for this message. Returns null if none is439* stored.440*/441public Integer getSeqNumber() {442// XXX Can authenticator be null443return authenticator.getSeqNumber();444}445446/**447* Returns the optional Checksum stored in the448* Authenticator for this message. Returns null if none is449* stored.450*/451public Checksum getChecksum() {452return authenticator.getChecksum();453}454455/**456* Returns the ASN.1 encoding that should be sent to the peer.457*/458public byte[] getMessage() {459return obuf;460}461462/**463* Returns the principal name of the client that generated this464* message.465*/466public PrincipalName getClient() {467return creds.getClient();468}469470private void createMessage(APOptions apOptions,471Ticket ticket,472EncryptionKey key,473PrincipalName cname,474Checksum cksum,475KerberosTime ctime,476EncryptionKey subKey,477SeqNumber seqNumber,478AuthorizationData authorizationData,479int usage)480throws Asn1Exception, IOException,481KdcErrException, KrbCryptoException {482483Integer seqno = null;484485if (seqNumber != null)486seqno = new Integer(seqNumber.current());487488authenticator =489new Authenticator(cname,490cksum,491ctime.getMicroSeconds(),492ctime,493subKey,494seqno,495authorizationData);496497byte[] temp = authenticator.asn1Encode();498499EncryptedData encAuthenticator =500new EncryptedData(key, temp, usage);501502apReqMessg =503new APReq(apOptions, ticket, encAuthenticator);504}505506// Check that key is one of the permitted types507private static void checkPermittedEType(int target) throws KrbException {508int[] etypes = EType.getDefaults("permitted_enctypes");509if (!EType.isSupported(target, etypes)) {510throw new KrbException(EType.toString(target) +511" encryption type not in permitted_enctypes list");512}513}514}515516517