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 */ 24 25 /* 26 * 27 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 28 * Copyright 1997 The Open Group Research Institute. All rights reserved. 29 */ 30 31 package sun.security.krb5; 32 33 import sun.security.krb5.internal.*; 34 import sun.security.krb5.internal.crypto.KeyUsage; 35 import sun.security.util.DerInputStream; 36 37 abstract class KrbKdcRep { 38 39 static void check( 40 boolean isAsReq, 41 KDCReq req, 42 KDCRep rep, 43 EncryptionKey replyKey 44 ) throws KrbApErrException { 45 46 // cname change in AS-REP is allowed only if the client 47 // sent CANONICALIZE and the server supports RFC 6806 - Section 11 48 // FAST scheme (ENC-PA-REP flag). 49 if (isAsReq && !req.reqBody.cname.equals(rep.cname) && 50 (!req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) || 51 !rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP))) { 52 rep.encKDCRepPart.key.destroy(); 53 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 54 } 55 56 // sname change in TGS-REP is allowed only if client 57 // sent CANONICALIZE and new sname is a referral of 58 // the form krbtgt/TO-REALM.COM@FROM-REALM.COM. 59 if (!req.reqBody.sname.equals(rep.encKDCRepPart.sname)) { 60 String[] snameStrings = rep.encKDCRepPart.sname.getNameStrings(); 61 if (isAsReq || !req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE) || 62 snameStrings == null || snameStrings.length != 2 || 63 !snameStrings[0].equals(PrincipalName.TGS_DEFAULT_SRV_NAME) || 64 !rep.encKDCRepPart.sname.getRealmString().equals( 65 req.reqBody.sname.getRealmString())) { 66 rep.encKDCRepPart.key.destroy(); 67 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 68 } 69 } 70 71 if (req.reqBody.getNonce() != rep.encKDCRepPart.nonce) { 72 rep.encKDCRepPart.key.destroy(); 73 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 74 } 75 76 if ( 77 ((req.reqBody.addresses != null && rep.encKDCRepPart.caddr != null) && 78 !req.reqBody.addresses.equals(rep.encKDCRepPart.caddr))) { 79 rep.encKDCRepPart.key.destroy(); 80 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 81 } 82 83 // We allow KDC to return a non-forwardable ticket if request has -f 84 for (int i = 2; i < 6; i++) { 85 if (req.reqBody.kdcOptions.get(i) != 86 rep.encKDCRepPart.flags.get(i)) { 87 if (Krb5.DEBUG) { 88 System.out.println("> KrbKdcRep.check: at #" + i 89 + ". request for " + req.reqBody.kdcOptions.get(i) 90 + ", received " + rep.encKDCRepPart.flags.get(i)); 91 } 92 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 93 } 94 } 95 96 // Reply to a renewable request should be renewable, but if request does 97 // not contain renewable, KDC is free to issue a renewable ticket (for 98 // example, if ticket_lifetime is too big). 99 if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE) && 100 !rep.encKDCRepPart.flags.get(KDCOptions.RENEWABLE)) { 101 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 102 } 103 104 if ((req.reqBody.from == null) || req.reqBody.from.isZero()) { 105 // verify this is allowed 106 if ((rep.encKDCRepPart.starttime != null) && 107 !rep.encKDCRepPart.starttime.inClockSkew()) { 108 rep.encKDCRepPart.key.destroy(); 109 throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW); 110 } 111 } 112 113 if ((req.reqBody.from != null) && !req.reqBody.from.isZero()) { 114 // verify this is allowed 115 if ((rep.encKDCRepPart.starttime != null) && 116 !req.reqBody.from.equals(rep.encKDCRepPart.starttime)) { 117 rep.encKDCRepPart.key.destroy(); 118 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 119 } 120 } 121 122 if (!req.reqBody.till.isZero() && 123 rep.encKDCRepPart.endtime.greaterThan(req.reqBody.till)) { 124 rep.encKDCRepPart.key.destroy(); 125 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 126 } 127 128 if (req.reqBody.kdcOptions.get(KDCOptions.RENEWABLE)) { 129 if (req.reqBody.rtime != null && !req.reqBody.rtime.isZero()) { 130 // verify this is required 131 if ((rep.encKDCRepPart.renewTill == null) || 132 rep.encKDCRepPart.renewTill.greaterThan(req.reqBody.rtime) 133 ) { 134 rep.encKDCRepPart.key.destroy(); 135 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 136 } 137 } 138 } 139 140 // RFC 6806 - Section 11 mechanism check 141 if (rep.encKDCRepPart.flags.get(Krb5.TKT_OPTS_ENC_PA_REP) && 142 req.reqBody.kdcOptions.get(KDCOptions.CANONICALIZE)) { 143 boolean reqPaReqEncPaRep = false; 144 boolean repPaReqEncPaRepValid = false; 145 146 // PA_REQ_ENC_PA_REP only required for AS requests 147 for (PAData pa : req.pAData) { 148 if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { 149 reqPaReqEncPaRep = true; 150 break; 151 } 152 } 153 154 for (PAData pa : rep.encKDCRepPart.pAData) { 155 if (pa.getType() == Krb5.PA_REQ_ENC_PA_REP) { 156 try { 157 Checksum repCksum = new Checksum( 158 new DerInputStream(pa.getValue()).getDerValue()); 159 repPaReqEncPaRepValid = repCksum.verifyKeyedChecksum( 160 req.asn1Encode(), replyKey, KeyUsage.KU_AS_REQ); 161 } catch (Exception e) { 162 if (Krb5.DEBUG) { 163 e.printStackTrace(); 164 } 165 } 166 break; 167 } 168 } 169 170 if (reqPaReqEncPaRep && !repPaReqEncPaRepValid) { 171 throw new KrbApErrException(Krb5.KRB_AP_ERR_MODIFIED); 172 } 173 } 174 } 175 }