PAForUserEnc.java revision 12489:339e2b4a5241
1/* 2 * Copyright (c) 2012, 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 26package sun.security.krb5.internal; 27 28import java.io.ByteArrayOutputStream; 29import java.io.IOException; 30import sun.security.krb5.*; 31import sun.security.krb5.internal.crypto.KeyUsage; 32import sun.security.krb5.internal.util.KerberosString; 33import sun.security.util.DerOutputStream; 34import sun.security.util.DerValue; 35 36/** 37 * Implements the ASN.1 PA-FOR-USER type. 38 * 39 * <pre>{@code 40 * padata-type ::= PA-FOR-USER 41 * -- value 129 42 * padata-value ::= EncryptedData 43 * -- PA-FOR-USER-ENC 44 * PA-FOR-USER-ENC ::= SEQUENCE { 45 * userName[0] PrincipalName, 46 * userRealm[1] Realm, 47 * cksum[2] Checksum, 48 * auth-package[3] KerberosString 49 * } 50 * }</pre> 51 * 52 * <p> 53 * This definition reflects MS-SFU. 54 */ 55 56public class PAForUserEnc { 57 final public PrincipalName name; 58 final private EncryptionKey key; 59 final public static String AUTH_PACKAGE = "Kerberos"; 60 61 public PAForUserEnc(PrincipalName name, EncryptionKey key) { 62 this.name = name; 63 this.key = key; 64 } 65 66 /** 67 * Constructs a PA-FOR-USER object from a DER encoding. 68 * @param encoding the input object 69 * @param key the key to verify the checksum inside encoding 70 * @throws KrbException if the verification fails. 71 * Note: this method is now only used by test KDC, therefore 72 * the verification is ignored (at the moment). 73 */ 74 public PAForUserEnc(DerValue encoding, EncryptionKey key) 75 throws Asn1Exception, KrbException, IOException { 76 DerValue der = null; 77 this.key = key; 78 79 if (encoding.getTag() != DerValue.tag_Sequence) { 80 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 81 } 82 83 // Realm after name? Quite abnormal. 84 PrincipalName tmpName = null; 85 der = encoding.getData().getDerValue(); 86 if ((der.getTag() & 0x1F) == 0x00) { 87 try { 88 tmpName = new PrincipalName(der.getData().getDerValue(), 89 new Realm("PLACEHOLDER")); 90 } catch (RealmException re) { 91 // Impossible 92 } 93 } else { 94 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 95 } 96 97 der = encoding.getData().getDerValue(); 98 if ((der.getTag() & 0x1F) == 0x01) { 99 try { 100 Realm realm = new Realm(der.getData().getDerValue()); 101 name = new PrincipalName( 102 tmpName.getNameType(), tmpName.getNameStrings(), realm); 103 } catch (RealmException re) { 104 throw new IOException(re); 105 } 106 } else { 107 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 108 } 109 110 der = encoding.getData().getDerValue(); 111 if ((der.getTag() & 0x1F) == 0x02) { 112 // Deal with the checksum 113 } else { 114 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 115 } 116 117 der = encoding.getData().getDerValue(); 118 if ((der.getTag() & 0x1F) == 0x03) { 119 String authPackage = new KerberosString(der.getData().getDerValue()).toString(); 120 if (!authPackage.equalsIgnoreCase(AUTH_PACKAGE)) { 121 throw new IOException("Incorrect auth-package"); 122 } 123 } else { 124 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 125 } 126 if (encoding.getData().available() > 0) 127 throw new Asn1Exception(Krb5.ASN1_BAD_ID); 128 } 129 130 public byte[] asn1Encode() throws Asn1Exception, IOException { 131 DerOutputStream bytes = new DerOutputStream(); 132 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x00), name.asn1Encode()); 133 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), name.getRealm().asn1Encode()); 134 135 try { 136 Checksum cks = new Checksum( 137 Checksum.CKSUMTYPE_HMAC_MD5_ARCFOUR, 138 getS4UByteArray(), 139 key, 140 KeyUsage.KU_PA_FOR_USER_ENC_CKSUM); 141 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x02), cks.asn1Encode()); 142 } catch (KrbException ke) { 143 throw new IOException(ke); 144 } 145 146 DerOutputStream temp = new DerOutputStream(); 147 temp.putDerValue(new KerberosString(AUTH_PACKAGE).toDerValue()); 148 bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x03), temp); 149 150 temp = new DerOutputStream(); 151 temp.write(DerValue.tag_Sequence, bytes); 152 return temp.toByteArray(); 153 } 154 155 /** 156 * Returns S4UByteArray, the block to calculate checksum inside a 157 * PA-FOR-USER-ENC data structure. It includes: 158 * 1. userName.name-type encoded as a 4-byte integer in little endian 159 * byte order 160 * 2. all string values in the sequence of strings contained in the 161 * userName.name-string field 162 * 3. the string value of the userRealm field 163 * 4. the string value of auth-package field 164 */ 165 public byte[] getS4UByteArray() { 166 try { 167 ByteArrayOutputStream ba = new ByteArrayOutputStream(); 168 ba.write(new byte[4]); 169 for (String s: name.getNameStrings()) { 170 ba.write(s.getBytes("UTF-8")); 171 } 172 ba.write(name.getRealm().toString().getBytes("UTF-8")); 173 ba.write(AUTH_PACKAGE.getBytes("UTF-8")); 174 byte[] output = ba.toByteArray(); 175 int pnType = name.getNameType(); 176 output[0] = (byte)(pnType & 0xff); 177 output[1] = (byte)((pnType>>8) & 0xff); 178 output[2] = (byte)((pnType>>16) & 0xff); 179 output[3] = (byte)((pnType>>24) & 0xff); 180 return output; 181 } catch (IOException ioe) { 182 // not possible 183 throw new AssertionError("Cannot write ByteArrayOutputStream", ioe); 184 } 185 } 186 187 public String toString() { 188 return "PA-FOR-USER: " + name; 189 } 190} 191