1 /* 2 * Copyright (c) 2000, 2013, 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 package javax.security.auth.kerberos; 27 28 import java.util.Arrays; 29 import javax.crypto.SecretKey; 30 import javax.security.auth.Destroyable; 31 import javax.security.auth.DestroyFailedException; 32 33 /** 34 * This class encapsulates a long term secret key for a Kerberos 35 * principal.<p> 36 * 37 * All Kerberos JAAS login modules that obtain a principal's password and 38 * generate the secret key from it should use this class. 39 * Sometimes, such as when authenticating a server in 40 * the absence of user-to-user authentication, the login module will store 41 * an instance of this class in the private credential set of a 42 * {@link javax.security.auth.Subject Subject} during the commit phase of the 43 * authentication process.<p> 44 * 45 * A Kerberos service using a keytab to read secret keys should use 46 * the {@link KeyTab} class, where latest keys can be read when needed.<p> 47 * 48 * It might be necessary for the application to be granted a 49 * {@link javax.security.auth.PrivateCredentialPermission 50 * PrivateCredentialPermission} if it needs to access the KerberosKey 51 * instance from a Subject. This permission is not needed when the 52 * application depends on the default JGSS Kerberos mechanism to access the 53 * KerberosKey. In that case, however, the application will need an 54 * appropriate 55 * {@link javax.security.auth.kerberos.ServicePermission ServicePermission}. 56 * 57 * @author Mayank Upadhyay 58 * @since 1.4 59 */ 60 public class KerberosKey implements SecretKey, Destroyable { 61 62 private static final long serialVersionUID = -4625402278148246993L; 63 64 /** 65 * The principal that this secret key belongs to. 66 * 67 * @serial 68 */ 69 private KerberosPrincipal principal; 70 71 /** 72 * the version number of this secret key 73 * 74 * @serial 75 */ 76 private int versionNum; 77 78 /** 79 * {@code KeyImpl} is serialized by writing out the ASN1 Encoded bytes 80 * of the encryption key. 81 * The ASN1 encoding is defined in RFC4120 and as follows: 82 * <pre> 83 * EncryptionKey ::= SEQUENCE { 84 * keytype [0] Int32 -- actually encryption type --, 85 * keyvalue [1] OCTET STRING 86 * } 87 * </pre> 88 * 89 * @serial 90 */ 91 92 private KeyImpl key; 93 private transient boolean destroyed = false; 94 95 /** 96 * Constructs a KerberosKey from the given bytes when the key type and 97 * key version number are known. This can be used when reading the secret 98 * key information from a Kerberos "keytab". 99 * 100 * @param principal the principal that this secret key belongs to 101 * @param keyBytes the raw bytes for the secret key 102 * @param keyType the key type for the secret key as defined by the 103 * Kerberos protocol specification. 104 * @param versionNum the version number of this secret key 105 */ KerberosKey(KerberosPrincipal principal, byte[] keyBytes, int keyType, int versionNum)106 public KerberosKey(KerberosPrincipal principal, 107 byte[] keyBytes, 108 int keyType, 109 int versionNum) { 110 this.principal = principal; 111 this.versionNum = versionNum; 112 key = new KeyImpl(keyBytes, keyType); 113 } 114 115 /** 116 * Constructs a KerberosKey from a principal's password. 117 * 118 * @param principal the principal that this password belongs to 119 * @param password the password that should be used to compute the key 120 * @param algorithm the name for the algorithm that this key will be 121 * used for. This parameter may be null in which case the default 122 * algorithm "DES" will be assumed. 123 * @throws IllegalArgumentException if the name of the 124 * algorithm passed is unsupported. 125 */ KerberosKey(KerberosPrincipal principal, char[] password, String algorithm)126 public KerberosKey(KerberosPrincipal principal, 127 char[] password, 128 String algorithm) { 129 130 this.principal = principal; 131 // Pass principal in for salt 132 key = new KeyImpl(principal, password, algorithm); 133 } 134 135 /** 136 * Returns the principal that this key belongs to. 137 * 138 * @return the principal this key belongs to. 139 */ getPrincipal()140 public final KerberosPrincipal getPrincipal() { 141 if (destroyed) 142 throw new IllegalStateException("This key is no longer valid"); 143 return principal; 144 } 145 146 /** 147 * Returns the key version number. 148 * 149 * @return the key version number. 150 */ getVersionNumber()151 public final int getVersionNumber() { 152 if (destroyed) 153 throw new IllegalStateException("This key is no longer valid"); 154 return versionNum; 155 } 156 157 /** 158 * Returns the key type for this long-term key. 159 * 160 * @return the key type. 161 */ getKeyType()162 public final int getKeyType() { 163 if (destroyed) 164 throw new IllegalStateException("This key is no longer valid"); 165 return key.getKeyType(); 166 } 167 168 /* 169 * Methods from java.security.Key 170 */ 171 172 /** 173 * Returns the standard algorithm name for this key. For 174 * example, "DES" would indicate that this key is a DES key. 175 * See Appendix A in the <a href= 176 * "../../../../../technotes/guides/security/crypto/CryptoSpec.html#AppA"> 177 * Java Cryptography Architecture API Specification & Reference 178 * </a> 179 * for information about standard algorithm names. 180 * 181 * @return the name of the algorithm associated with this key. 182 */ getAlgorithm()183 public final String getAlgorithm() { 184 if (destroyed) 185 throw new IllegalStateException("This key is no longer valid"); 186 return key.getAlgorithm(); 187 } 188 189 /** 190 * Returns the name of the encoding format for this secret key. 191 * 192 * @return the String "RAW" 193 */ getFormat()194 public final String getFormat() { 195 if (destroyed) 196 throw new IllegalStateException("This key is no longer valid"); 197 return key.getFormat(); 198 } 199 200 /** 201 * Returns the key material of this secret key. 202 * 203 * @return the key material 204 */ getEncoded()205 public final byte[] getEncoded() { 206 if (destroyed) 207 throw new IllegalStateException("This key is no longer valid"); 208 return key.getEncoded(); 209 } 210 211 /** 212 * Destroys this key. A call to any of its other methods after this 213 * will cause an IllegalStateException to be thrown. 214 * 215 * @throws DestroyFailedException if some error occurs while destorying 216 * this key. 217 */ destroy()218 public void destroy() throws DestroyFailedException { 219 if (!destroyed) { 220 key.destroy(); 221 principal = null; 222 destroyed = true; 223 } 224 } 225 226 227 /** Determines if this key has been destroyed.*/ isDestroyed()228 public boolean isDestroyed() { 229 return destroyed; 230 } 231 toString()232 public String toString() { 233 if (destroyed) { 234 return "Destroyed Principal"; 235 } 236 return "Kerberos Principal " + principal.toString() + 237 "Key Version " + versionNum + 238 "key " + key.toString(); 239 } 240 241 /** 242 * Returns a hashcode for this KerberosKey. 243 * 244 * @return a hashCode() for the {@code KerberosKey} 245 * @since 1.6 246 */ hashCode()247 public int hashCode() { 248 int result = 17; 249 if (isDestroyed()) { 250 return result; 251 } 252 result = 37 * result + Arrays.hashCode(getEncoded()); 253 result = 37 * result + getKeyType(); 254 if (principal != null) { 255 result = 37 * result + principal.hashCode(); 256 } 257 return result * 37 + versionNum; 258 } 259 260 /** 261 * Compares the specified Object with this KerberosKey for equality. 262 * Returns true if the given object is also a 263 * {@code KerberosKey} and the two 264 * {@code KerberosKey} instances are equivalent. 265 * 266 * @param other the Object to compare to 267 * @return true if the specified object is equal to this KerberosKey, 268 * false otherwise. NOTE: Returns false if either of the KerberosKey 269 * objects has been destroyed. 270 * @since 1.6 271 */ equals(Object other)272 public boolean equals(Object other) { 273 274 if (other == this) 275 return true; 276 277 if (! (other instanceof KerberosKey)) { 278 return false; 279 } 280 281 KerberosKey otherKey = ((KerberosKey) other); 282 if (isDestroyed() || otherKey.isDestroyed()) { 283 return false; 284 } 285 286 if (versionNum != otherKey.getVersionNumber() || 287 getKeyType() != otherKey.getKeyType() || 288 !Arrays.equals(getEncoded(), otherKey.getEncoded())) { 289 return false; 290 } 291 292 if (principal == null) { 293 if (otherKey.getPrincipal() != null) { 294 return false; 295 } 296 } else { 297 if (!principal.equals(otherKey.getPrincipal())) { 298 return false; 299 } 300 } 301 302 return true; 303 } 304 } 305