Path: blob/master/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java
41161 views
/*1* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.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 it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* 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 WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 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 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth.kerberos;2627import java.util.Arrays;28import javax.crypto.SecretKey;29import javax.security.auth.DestroyFailedException;3031/**32* This class encapsulates a long term secret key for a Kerberos33* principal.<p>34*35* A {@code KerberosKey} object includes an EncryptionKey, a36* {@link KerberosPrincipal} as its owner, and the version number37* of the key.<p>38*39* An EncryptionKey is defined in Section 4.2.9 of the Kerberos Protocol40* Specification (<a href=http://www.ietf.org/rfc/rfc4120.txt>RFC 4120</a>) as:41* <pre>42* EncryptionKey ::= SEQUENCE {43* keytype [0] Int32 -- actually encryption type --,44* keyvalue [1] OCTET STRING45* }46* </pre>47* The key material of a {@code KerberosKey} is defined as the value48* of the {@code keyValue} above.<p>49*50* All Kerberos JAAS login modules that obtain a principal's password and51* generate the secret key from it should use this class.52* Sometimes, such as when authenticating a server in53* the absence of user-to-user authentication, the login module will store54* an instance of this class in the private credential set of a55* {@link javax.security.auth.Subject Subject} during the commit phase of the56* authentication process.<p>57*58* A Kerberos service using a keytab to read secret keys should use59* the {@link KeyTab} class, where latest keys can be read when needed.<p>60*61* It might be necessary for the application to be granted a62* {@link javax.security.auth.PrivateCredentialPermission63* PrivateCredentialPermission} if it needs to access the {@code KerberosKey}64* instance from a Subject. This permission is not needed when the65* application depends on the default JGSS Kerberos mechanism to access the66* {@code KerberosKey}. In that case, however, the application will need an67* appropriate68* {@link javax.security.auth.kerberos.ServicePermission ServicePermission}.<p>69*70* When creating a {@code KerberosKey} using the71* {@link #KerberosKey(KerberosPrincipal, char[], String)} constructor,72* an implementation may accept non-IANA algorithm names (For example,73* "ArcFourMac" for "rc4-hmac"), but the {@link #getAlgorithm} method74* must always return the IANA algorithm name.75*76* @implNote Old algorithm names used before JDK 9 are supported in the77* {@link #KerberosKey(KerberosPrincipal, char[], String)} constructor in this78* implementation for compatibility reasons, which are "DES" (and null) for79* "des-cbc-md5", "DESede" for "des3-cbc-sha1-kd", "ArcFourHmac" for "rc4-hmac",80* "AES128" for "aes128-cts-hmac-sha1-96", and "AES256" for81* "aes256-cts-hmac-sha1-96".82*83* @author Mayank Upadhyay84* @since 1.485*/86public class KerberosKey implements SecretKey {8788private static final long serialVersionUID = -4625402278148246993L;8990/**91* The principal that this secret key belongs to.92*93* @serial94*/95private KerberosPrincipal principal;9697/**98* the version number of this secret key99*100* @serial101*/102private final int versionNum;103104/**105* {@code KeyImpl} is serialized by writing out the ASN.1 encoded bytes106* of the encryption key.107*108* @serial109*/110private KeyImpl key;111112private transient boolean destroyed = false;113114/**115* Constructs a {@code KerberosKey} from the given bytes when the key type116* and key version number are known. This can be used when reading the117* secret key information from a Kerberos "keytab".118*119* @param principal the principal that this secret key belongs to120* @param keyBytes the key material for the secret key121* @param keyType the key type for the secret key as defined by the122* Kerberos protocol specification.123* @param versionNum the version number of this secret key124*/125public KerberosKey(KerberosPrincipal principal,126byte[] keyBytes,127int keyType,128int versionNum) {129this.principal = principal;130this.versionNum = versionNum;131key = new KeyImpl(keyBytes, keyType);132}133134/**135* Constructs a {@code KerberosKey} from a principal's password using the136* specified algorithm name. The algorithm name (case insensitive) should137* be provided as the encryption type string defined on the IANA138* <a href="https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1">Kerberos Encryption Type Numbers</a>139* page. The version number of the key generated will be 0.140*141* @param principal the principal that this password belongs to142* @param password the password that should be used to compute the key143* @param algorithm the name for the algorithm that this key will be144* used for145* @throws IllegalArgumentException if the name of the146* algorithm passed is unsupported.147*/148public KerberosKey(KerberosPrincipal principal,149char[] password,150String algorithm) {151152this.principal = principal;153this.versionNum = 0;154// Pass principal in for salt155key = new KeyImpl(principal, password, algorithm);156}157158/**159* Returns the principal that this key belongs to.160*161* @return the principal this key belongs to.162* @throws IllegalStateException if the key is destroyed163*/164public final KerberosPrincipal getPrincipal() {165if (destroyed) {166throw new IllegalStateException("This key is no longer valid");167}168return principal;169}170171/**172* Returns the key version number.173*174* @return the key version number.175* @throws IllegalStateException if the key is destroyed176*/177public final int getVersionNumber() {178if (destroyed) {179throw new IllegalStateException("This key is no longer valid");180}181return versionNum;182}183184/**185* Returns the key type for this long-term key.186*187* @return the key type.188* @throws IllegalStateException if the key is destroyed189*/190public final int getKeyType() {191// KeyImpl already checked if destroyed192return key.getKeyType();193}194195/*196* Methods from java.security.Key197*/198199/**200* Returns the standard algorithm name for this key. The algorithm names201* are the encryption type string defined on the IANA202* <a href="https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1">Kerberos Encryption Type Numbers</a>203* page.204* <p>205* This method can return the following value not defined on the IANA page:206* <ol>207* <li>none: for etype equal to 0</li>208* <li>unknown: for etype greater than 0 but unsupported by209* the implementation</li>210* <li>private: for etype smaller than 0</li>211* </ol>212*213* @return the name of the algorithm associated with this key.214* @throws IllegalStateException if the key is destroyed215*/216public final String getAlgorithm() {217// KeyImpl already checked if destroyed218return key.getAlgorithm();219}220221/**222* Returns the name of the encoding format for this secret key.223*224* @return the String "RAW"225* @throws IllegalStateException if the key is destroyed226*/227public final String getFormat() {228// KeyImpl already checked if destroyed229return key.getFormat();230}231232/**233* Returns the key material of this secret key.234*235* @return the key material236* @throws IllegalStateException if the key is destroyed237*/238public final byte[] getEncoded() {239// KeyImpl already checked if destroyed240return key.getEncoded();241}242243/**244* Destroys this key by clearing out the key material of this secret key.245*246* @throws DestroyFailedException if some error occurs while destorying247* this key.248*/249public void destroy() throws DestroyFailedException {250if (!destroyed) {251key.destroy();252principal = null;253destroyed = true;254}255}256257258/** Determines if this key has been destroyed.*/259public boolean isDestroyed() {260return destroyed;261}262263/**264* Returns an informative textual representation of this {@code KerberosKey}.265*266* @return an informative textual representation of this {@code KerberosKey}.267*/268public String toString() {269if (destroyed) {270return "Destroyed KerberosKey";271}272return "Kerberos Principal " + principal +273"Key Version " + versionNum +274"key " + key.toString();275}276277/**278* Returns a hash code for this {@code KerberosKey}.279*280* @return a hash code for this {@code KerberosKey}.281* @since 1.6282*/283public int hashCode() {284int result = 17;285if (isDestroyed()) {286return result;287}288result = 37 * result + Arrays.hashCode(getEncoded());289result = 37 * result + getKeyType();290if (principal != null) {291result = 37 * result + principal.hashCode();292}293return result * 37 + versionNum;294}295296/**297* Compares the specified object with this {@code KerberosKey} for298* equality. Returns true if the given object is also a299* {@code KerberosKey} and the two300* {@code KerberosKey} instances are equivalent.301* A destroyed {@code KerberosKey} object is only equal to itself.302*303* @param other the object to compare to304* @return true if the specified object is equal to this {@code KerberosKey},305* false otherwise.306* @since 1.6307*/308public boolean equals(Object other) {309310if (other == this) {311return true;312}313314if (! (other instanceof KerberosKey)) {315return false;316}317318KerberosKey otherKey = ((KerberosKey) other);319if (isDestroyed() || otherKey.isDestroyed()) {320return false;321}322323if (versionNum != otherKey.getVersionNumber() ||324getKeyType() != otherKey.getKeyType() ||325!Arrays.equals(getEncoded(), otherKey.getEncoded())) {326return false;327}328329if (principal == null) {330if (otherKey.getPrincipal() != null) {331return false;332}333} else {334if (!principal.equals(otherKey.getPrincipal())) {335return false;336}337}338339return true;340}341}342343344