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 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 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 */ 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); 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 */ 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); 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 */ 147 private void decrypt(EncryptionKey dkey, KrbAsReq asReq) 148 throws KrbException, Asn1Exception, IOException { 149 byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey, 150 KeyUsage.KU_ENC_AS_REP_PART); 151 byte[] enc_as_rep_part = rep.encPart.reset(enc_as_rep_bytes); 152 153 DerValue encoding = new DerValue(enc_as_rep_part); 154 EncASRepPart enc_part = new EncASRepPart(encoding); 155 rep.encKDCRepPart = enc_part; 156 157 ASReq req = asReq.getMessage(); 158 check(true, req, rep, dkey); 159 160 creds = new Credentials( 161 rep.ticket, 162 rep.cname, 163 enc_part.sname, 164 enc_part.key, 165 enc_part.flags, 166 enc_part.authtime, 167 enc_part.starttime, 168 enc_part.endtime, 169 enc_part.renewTill, 170 enc_part.caddr); 171 if (DEBUG) { 172 System.out.println(">>> KrbAsRep cons in KrbAsReq.getReply " + 173 req.reqBody.cname.getNameString()); 174 } 175 } 176 177 Credentials getCreds() { 178 return Objects.requireNonNull(creds, "Creds not available yet."); 179 } 180 181 sun.security.krb5.internal.ccache.Credentials getCCreds() { 182 return new sun.security.krb5.internal.ccache.Credentials(rep); 183 } 184 }