1 /* 2 * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 /* 27 * 28 * (C) Copyright IBM Corp. 1999 All Rights Reserved. 29 * Copyright 1997 The Open Group Research Institute. All rights reserved. 30 */ 31 32 package sun.security.krb5; 33 34 import sun.security.krb5.internal.*; 35 import sun.security.krb5.internal.crypto.KeyUsage; 36 import sun.security.krb5.internal.crypto.EType; 37 import sun.security.util.*; 38 import java.io.IOException; 39 import java.util.Objects; 40 import javax.security.auth.kerberos.KeyTab; 41 import sun.security.jgss.krb5.Krb5Util; 42 43 /** 44 * This class encapsulates a AS-REP message that the KDC sends to the 45 * client. 46 */ 47 class KrbAsRep extends KrbKdcRep { 48 49 private ASRep rep; // The AS-REP message 50 private Credentials creds; // The Credentials provide by the AS-REP 51 // message, created by initiator after calling 52 // the decrypt() method 53 54 private boolean DEBUG = Krb5.DEBUG; 55 KrbAsRep(byte[] ibuf)56 KrbAsRep(byte[] ibuf) throws 57 KrbException, Asn1Exception, IOException { 58 DerValue encoding = new DerValue(ibuf); 59 try { 60 rep = new ASRep(encoding); 61 } catch (Asn1Exception e) { 62 rep = null; 63 KRBError err = new KRBError(encoding); 64 String errStr = err.getErrorString(); 65 String eText = null; // pick up text sent by the server (if any) 66 67 if (errStr != null && errStr.length() > 0) { 68 if (errStr.charAt(errStr.length() - 1) == 0) 69 eText = errStr.substring(0, errStr.length() - 1); 70 else 71 eText = errStr; 72 } 73 KrbException ke; 74 if (eText == null) { 75 // no text sent from server 76 ke = new KrbException(err); 77 } else { 78 if (DEBUG) { 79 System.out.println("KRBError received: " + eText); 80 } 81 // override default text with server text 82 ke = new KrbException(err, eText); 83 } 84 ke.initCause(e); 85 throw ke; 86 } 87 } 88 89 // KrbAsReqBuilder need to read back the PA for key generation getPA()90 PAData[] getPA() { 91 return rep.pAData; 92 } 93 94 /** 95 * Called by KrbAsReqBuilder to resolve a AS-REP message using a keytab. 96 * @param ktab the keytab, not null 97 * @param asReq the original AS-REQ sent, used to validate AS-REP 98 * @param cname the user principal name, used to locate keys in ktab 99 */ decryptUsingKeyTab(KeyTab ktab, KrbAsReq asReq, PrincipalName cname)100 void decryptUsingKeyTab(KeyTab ktab, KrbAsReq asReq, PrincipalName cname) 101 throws KrbException, Asn1Exception, IOException { 102 EncryptionKey dkey = null; 103 int encPartKeyType = rep.encPart.getEType(); 104 Integer encPartKvno = rep.encPart.kvno; 105 try { 106 dkey = EncryptionKey.findKey(encPartKeyType, encPartKvno, 107 Krb5Util.keysFromJavaxKeyTab(ktab, cname)); 108 } catch (KrbException ke) { 109 if (ke.returnCode() == Krb5.KRB_AP_ERR_BADKEYVER) { 110 // Fallback to no kvno. In some cases, keytab is generated 111 // not by sysadmin but Java's ktab command 112 dkey = EncryptionKey.findKey(encPartKeyType, 113 Krb5Util.keysFromJavaxKeyTab(ktab, cname)); 114 } 115 } 116 if (dkey == null) { 117 throw new KrbException(Krb5.API_INVALID_ARG, 118 "Cannot find key for type/kvno to decrypt AS REP - " + 119 EType.toString(encPartKeyType) + "/" + encPartKvno); 120 } 121 decrypt(dkey, asReq, cname); 122 } 123 124 /** 125 * Called by KrbAsReqBuilder to resolve a AS-REP message using a password. 126 * @param password user provided password. not null 127 * @param asReq the original AS-REQ sent, used to validate AS-REP 128 * @param cname the user principal name, used to provide salt 129 */ decryptUsingPassword(char[] password, KrbAsReq asReq, PrincipalName cname)130 void decryptUsingPassword(char[] password, 131 KrbAsReq asReq, PrincipalName cname) 132 throws KrbException, Asn1Exception, IOException { 133 int encPartKeyType = rep.encPart.getEType(); 134 EncryptionKey dkey = EncryptionKey.acquireSecretKey( 135 cname, 136 password, 137 encPartKeyType, 138 PAData.getSaltAndParams(encPartKeyType, rep.pAData)); 139 decrypt(dkey, asReq, cname); 140 } 141 142 /** 143 * Decrypts encrypted content inside AS-REP. Called by initiator. 144 * @param dkey the decryption key to use 145 * @param asReq the original AS-REQ sent, used to validate AS-REP 146 */ decrypt(EncryptionKey dkey, KrbAsReq asReq, PrincipalName cname)147 private void decrypt(EncryptionKey dkey, KrbAsReq asReq, 148 PrincipalName cname) 149 throws KrbException, Asn1Exception, IOException { 150 byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey, 151 KeyUsage.KU_ENC_AS_REP_PART); 152 byte[] enc_as_rep_part = rep.encPart.reset(enc_as_rep_bytes); 153 154 DerValue encoding = new DerValue(enc_as_rep_part); 155 EncASRepPart enc_part = new EncASRepPart(encoding); 156 rep.encKDCRepPart = enc_part; 157 158 ASReq req = asReq.getMessage(); 159 check(true, req, rep, dkey); 160 161 PrincipalName clientAlias = cname; 162 if (clientAlias.equals(rep.cname)) 163 clientAlias = null; 164 165 creds = new Credentials( 166 rep.ticket, 167 rep.cname, 168 clientAlias, 169 enc_part.sname, 170 null, // No server alias expected in a TGT 171 enc_part.key, 172 enc_part.flags, 173 enc_part.authtime, 174 enc_part.starttime, 175 enc_part.endtime, 176 enc_part.renewTill, 177 enc_part.caddr); 178 if (DEBUG) { 179 System.out.println(">>> KrbAsRep cons in KrbAsReq.getReply " + 180 req.reqBody.cname.getNameString()); 181 } 182 } 183 getCreds()184 Credentials getCreds() { 185 return Objects.requireNonNull(creds, "Creds not available yet."); 186 } 187 getCCreds()188 sun.security.krb5.internal.ccache.Credentials getCCreds() { 189 return new sun.security.krb5.internal.ccache.Credentials(rep); 190 } 191 } 192