src/share/classes/sun/security/krb5/KrbKdcRep.java

Sun, 31 May 2020 10:13:04 +0800

author
mbalao
date
Sun, 31 May 2020 10:13:04 +0800
changeset 14203
d8bd882cfd2a
parent 14114
971263b8cd56
child 14222
5a272e10d7e7
permissions
-rw-r--r--

8246193: Possible NPE in ENC-PA-REP search in AS-REQ
Reviewed-by: zgu, andrew

     1 /*
     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 it
     5  * under the terms of the GNU General Public License version 2 only, as
     6  * published by the Free Software Foundation.  Oracle designates this
     7  * particular file as subject to the "Classpath" exception as provided
     8  * 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 WITHOUT
    11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    13  * version 2 for more details (a copy is included in the LICENSE file that
    14  * accompanied this code).
    15  *
    16  * You should have received a copy of the GNU General Public License version
    17  * 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 USA
    21  * or visit www.oracle.com if you need additional information or have any
    22  * questions.
    23  */
    25 /*
    26  *
    27  *  (C) Copyright IBM Corp. 1999 All Rights Reserved.
    28  *  Copyright 1997 The Open Group Research Institute.  All rights reserved.
    29  */
    31 package sun.security.krb5;
    33 import sun.security.krb5.internal.*;
    34 import sun.security.krb5.internal.crypto.KeyUsage;
    35 import sun.security.util.DerInputStream;
    37 abstract class KrbKdcRep {
    39     static void check(
    40                       boolean isAsReq,
    41                       KDCReq req,
    42                       KDCRep rep,
    43                       EncryptionKey replyKey
    44                       ) throws KrbApErrException {
    46         // cname change in AS-REP is allowed only if the client
    47         // sent CANONICALIZE or an NT-ENTERPRISE cname in the request, and the
    48         // server supports RFC 6806 - Section 11 FAST scheme (ENC-PA-REP flag).
    49         if (isAsReq && !req.reqBody.cname.equals(rep.cname) &&
    50                 ((!req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) &&
    51                 req.reqBody.cname.getNameType() !=
    52                 PrincipalName.KRB_NT_ENTERPRISE) ||
    53                 !rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP))) {
    54             rep.encKDCRepPart.key.destroy();
    55             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
    56         }
    58         // sname change in TGS-REP is allowed only if client
    59         // sent CANONICALIZE and new sname is a referral of
    60         // the form krbtgt/TO-REALM.COM@FROM-REALM.COM.
    61         if (!req.reqBody.sname.equals(rep.encKDCRepPart.sname)) {
    62             String[] snameStrings = rep.encKDCRepPart.sname.getNameStrings();
    63             if (isAsReq || !req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) ||
    64                     snameStrings == null || snameStrings.length != 2 ||
    65                     !snameStrings[0].equals(PrincipalName.TGS_DEFAULT_SRV_NAME) ||
    66                     !rep.encKDCRepPart.sname.getRealmString().equals(
    67                             req.reqBody.sname.getRealmString())) {
    68                 rep.encKDCRepPart.key.destroy();
    69                 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
    70             }
    71         }
    73         if (req.reqBody.getNonce() != rep.encKDCRepPart.nonce) {
    74             rep.encKDCRepPart.key.destroy();
    75             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
    76         }
    78         if (
    79             ((req.reqBody.addresses != null && rep.encKDCRepPart.caddr != null) &&
    80              !req.reqBody.addresses.equals(rep.encKDCRepPart.caddr))) {
    81             rep.encKDCRepPart.key.destroy();
    82             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
    83         }
    85         // We allow KDC to return a non-forwardable ticket if request has -f
    86         for (int i = 2; i < 6; i++) {
    87             if (req.reqBody.kdcOptions.get(i) !=
    88                    rep.encKDCRepPart.flags.get(i)) {
    89                 if (Krb5.DEBUG) {
    90                     System.out.println("> KrbKdcRep.check: at #" + i
    91                             + ". request for " + req.reqBody.kdcOptions.get(i)
    92                             + ", received " + rep.encKDCRepPart.flags.get(i));
    93                 }
    94                 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
    95             }
    96         }
    98         // Reply to a renewable request should be renewable, but if request does
    99         // not contain renewable, KDC is free to issue a renewable ticket (for
   100         // example, if ticket_lifetime is too big).
   101         if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE) &&
   102                 !rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE)) {
   103             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
   104         }
   106         if ((req.reqBody.from == null) || req.reqBody.from.isZero()) {
   107             // verify this is allowed
   108             if ((rep.encKDCRepPart.starttime != null) &&
   109                     !rep.encKDCRepPart.starttime.inClockSkew()) {
   110                 rep.encKDCRepPart.key.destroy();
   111                 throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
   112             }
   113         }
   115         if ((req.reqBody.from != null) && !req.reqBody.from.isZero()) {
   116             // verify this is allowed
   117             if ((rep.encKDCRepPart.starttime != null) &&
   118                     !req.reqBody.from.equals(rep.encKDCRepPart.starttime)) {
   119                 rep.encKDCRepPart.key.destroy();
   120                 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
   121             }
   122         }
   124         if (!req.reqBody.till.isZero() &&
   125                 rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) {
   126             rep.encKDCRepPart.key.destroy();
   127             throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
   128         }
   130         // RFC 6806 - Section 11 mechanism check
   131         // The availability of the ENC-PA-REP flag in the KDC response is
   132         // mandatory on some cases (see Krb5.TKT_OPTS_ENC_PA_REP check above).
   133         if (rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP)) {
   134             boolean reqPaReqEncPaRep = false;
   135             boolean repPaReqEncPaRepValid = false;
   137             if (req.pAData != null) {
   138                 for (PAData pa : req.pAData) {
   139                     if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) {
   140                         // The KDC supports RFC 6806 and ENC-PA-REP was sent in
   141                         // the request (AS-REQ). A valid checksum is now required.
   142                         reqPaReqEncPaRep = true;
   143                         break;
   144                     }
   145                 }
   146             }
   148             if (rep.encKDCRepPart.pAData != null) {
   149                 for (PAData pa : rep.encKDCRepPart.pAData) {
   150                     if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) {
   151                         try {
   152                             Checksum repCksum = new Checksum(
   153                                     new DerInputStream(
   154                                             pa.getValue()).getDerValue());
   155                             // The checksum is inside encKDCRepPart so we don't
   156                             // care if it's keyed or not.
   157                             repPaReqEncPaRepValid =
   158                                     repCksum.verifyAnyChecksum(
   159                                             req.asn1Encode(), replyKey,
   160                                             KeyUsage.KU_AS_REQ);
   161                         } catch (Exception e) {
   162                             if (Krb5.DEBUG) {
   163                                 e.printStackTrace();
   164                             }
   165                         }
   166                         break;
   167                     }
   168                 }
   169             }
   171             if (reqPaReqEncPaRep && !repPaReqEncPaRepValid) {
   172                 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
   173             }
   174         }
   176         if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE)) {
   177             if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero()) {
   178                 // verify this is required
   179                 if ((rep.encKDCRepPart.renewTill == null) ||
   180                         rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.rtime)
   181                         ) {
   182                     rep.encKDCRepPart.key.destroy();
   183                     throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED);
   184                 }
   186             }
   187         }
   188     }
   189 }

mercurial