immutable principalname
diff -r a7786f546f3f src/share/classes/sun/security/krb5/Credentials.java
--- a/src/share/classes/sun/security/krb5/Credentials.java
+++ b/src/share/classes/sun/security/krb5/Credentials.java
@@ -357,17 +357,32 @@
}
KRBError error = ke.getError();
- // update salt in PrincipalName
- byte[] newSalt = error.getSalt();
- if (newSalt != null && newSalt.length > 0) {
- princ.setSalt(new String(newSalt));
- }
// refresh keys
if (password != null) {
+ String salt;
+ // use salt from KDC response
+ byte[] newSalt = error.getSalt();
+ if (newSalt != null && newSalt.length > 0) {
+ if (DEBUG) {
+ System.out.println(">>> acquireTGT: New " +
+ "KrbAsReq salt is " + new String(newSalt));
+ }
+ salt = new String(newSalt);
+ } else {
+ salt = princ.getSalt();
+ }
secretKeys = EncryptionKey.acquireSecretKeys(password,
- princ.getSalt(), true,
+ salt, true,
error.getEType(), error.getParams());
+ } else if (DEBUG) {
+ byte[] newSalt = error.getSalt();
+ if (newSalt != null && newSalt.length > 0) {
+ System.out.println(">>> acquireTGT: New KrbAsReq " +
+ "salt is " + new String(newSalt));
+ System.out.println(">>> acquireTGT: WARNING: " +
+ "cannot regenerate key, no password");
+ }
}
asRep = sendASRequest(princ, secretKeys, ke.getError());
} else {
diff -r a7786f546f3f src/share/classes/sun/security/krb5/KrbAsReq.java
--- a/src/share/classes/sun/security/krb5/KrbAsReq.java
+++ b/src/share/classes/sun/security/krb5/KrbAsReq.java
@@ -119,14 +119,6 @@
pa_salt = salt;
pa_s2kparams = params;
- // update salt in PrincipalName
- if (salt != null && salt.length > 0) {
- String newSalt = new String(salt);
- name.setSalt(newSalt);
- if (DEBUG) {
- System.out.println("Updated salt from pre-auth = " + name.getSalt());
- }
- }
PA_ENC_TIMESTAMP_REQUIRED = true;
}
@@ -156,7 +148,16 @@
additionalTickets); // Ticket[] additionalTickets
}
- // Used by Kinit
+ private String getCurrentSalt(PrincipalName pn) {
+ if (pa_exists) {
+ if (pa_salt != null && pa_salt.length > 0) {
+ return new String(pa_salt);
+ }
+ }
+ return pn.getSalt();
+ }
+
+ // Used by Kinit
public KrbAsReq(
char[] password,
boolean pa_exists,
@@ -182,11 +183,14 @@
}
if (password != null) {
- keys = EncryptionKey.acquireSecretKeys(password, cname.getSalt(), pa_exists,
+ keys = EncryptionKey.acquireSecretKeys(password, getCurrentSalt(cname), pa_exists,
pa_etype, pa_s2kparams);
}
if (DEBUG) {
- System.out.println(">>>KrbAsReq salt is " + cname.getSalt());
+ System.out.println(">>> KrbAsReq: KrbAsReq salt is "
+ + cname.getSalt());
+ System.out.println(">>> KrbAsReq: " +
+ "keys will be regenerated from password");
}
try {
@@ -265,7 +269,10 @@
updatePA(etype, salt, s2kparams, cname);
if (DEBUG) {
- System.out.println(">>>KrbAsReq salt is " + cname.getSalt());
+ System.out.println(">>> KrbAsReq: New KrbAsReq salt is "
+ + new String(salt));
+ System.out.println(">>> KrbAsReq: WARNING: " +
+ "cannot regenerate key, no password");
}
}
@@ -424,7 +431,7 @@
EncryptionKey[] keys = null;
try {
keys = EncryptionKey.acquireSecretKeys(password,
- princName.getSalt(), pa_exists, pa_etype, pa_s2kparams);
+ getCurrentSalt(princName), pa_exists, pa_etype, pa_s2kparams);
temp = getReply(keys);
} finally {
/*
diff -r a7786f546f3f src/share/classes/sun/security/krb5/PrincipalName.java
--- a/src/share/classes/sun/security/krb5/PrincipalName.java
+++ b/src/share/classes/sun/security/krb5/PrincipalName.java
@@ -101,7 +101,7 @@
// Note: the nameRealm is not included in the default ASN.1 encoding
// salt for principal
- private String salt = null;
+ private transient String salt = null;
protected PrincipalName() {
}
@@ -122,18 +122,20 @@
}
public Object clone() {
- PrincipalName pName = new PrincipalName();
- pName.nameType = nameType;
- if (nameStrings != null) {
- pName.nameStrings =
- new String[nameStrings.length];
- System.arraycopy(nameStrings,0,pName.nameStrings,0,
- nameStrings.length);
- }
- if (nameRealm != null) {
- pName.nameRealm = (Realm)nameRealm.clone();
- }
- return pName;
+ try {
+ PrincipalName pName = (PrincipalName) super.clone();
+ pName.nameType = nameType;
+ if (nameStrings != null) {
+ pName.nameStrings = new String[nameStrings.length];
+ System.arraycopy(nameStrings, 0, pName.nameStrings, 0, nameStrings.length);
+ }
+ if (nameRealm != null) {
+ pName.nameRealm = (Realm) nameRealm.clone();
+ }
+ return pName;
+ } catch (CloneNotSupportedException ex) {
+ throw new Error("Assertion failure"); // won't happen
+ }
}
/*
@@ -509,10 +511,6 @@
return salt;
}
- public void setSalt(String salt) {
- this.salt = salt;
- }
-
public String toString() {
StringBuffer str = new StringBuffer();
for (int i = 0; i < nameStrings.length; i++) {
diff -r a7786f546f3f test/sun/security/krb5/ServiceNameClone.java
--- /dev/null
+++ b/test/sun/security/krb5/ServiceNameClone.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+/*
+ * @test
+ * @bug 6856069
+ * @summary PrincipalName.clone() does not invoke super.clone()
+ */
+
+import sun.security.krb5.ServiceName;
+
+public class ServiceNameClone {
+ public static void main(String[] args) throws Exception {
+ ServiceName sn = new ServiceName("me@HERE");
+ if (sn.clone().getClass() != ServiceName.class) {
+ throw new Exception("ServiceName's clone is not a ServiceName");
+ }
+ }
+}
diff -r a7786f546f3f test/sun/security/krb5/auto/Context.java
--- a/test/sun/security/krb5/auto/Context.java
+++ b/test/sun/security/krb5/auto/Context.java
@@ -198,7 +198,7 @@
* @throws org.ietf.jgss.GSSException
*/
public void dispose() throws GSSException {
- x.dispose();
+ if (x != null) x.dispose();
}
/**
diff -r a7786f546f3f test/sun/security/krb5/auto/KDC.java
--- a/test/sun/security/krb5/auto/KDC.java
+++ b/test/sun/security/krb5/auto/KDC.java
@@ -120,8 +120,13 @@
// The random generator to generate random keys (including session keys)
private static SecureRandom secureRandom = new SecureRandom();
- // Principal db. principal -> pass
- private Map<String,char[]> passwords = new HashMap<String,char[]>();
+
+ // Principal db. principal -> pass. A case-insensitive TreeMap is used
+ // so that even if the client provides a name with different case, the KDC
+ // can still locate the principal and give back correct salt.
+ private TreeMap<String,char[]> passwords = new TreeMap<String,char[]>
+ (String.CASE_INSENSITIVE_ORDER);
+
// Realm name
private String realm;
// KDC
@@ -151,7 +156,7 @@
* A standalone KDC server.
*/
public static void main(String[] args) throws Exception {
- KDC kdc = create("RABBIT.HOLE", "kdc.rabbit,hole", 0, false);
+ KDC kdc = create("RABBIT.HOLE", "kdc.rabbit.hole", 0, false);
kdc.addPrincipal("dummy", "bogus".toCharArray());
kdc.addPrincipal("foo", "bar".toCharArray());
kdc.addPrincipalRandKey("krbtgt/RABBIT.HOLE");
@@ -422,18 +427,21 @@
/**
* Returns the password for a given principal
* @param p principal
+ * @param server looking for a server principal?
* @return the password
* @throws sun.security.krb5.KrbException when the principal is not inside
* the database.
*/
- private char[] getPassword(PrincipalName p) throws KrbException {
+ private char[] getPassword(PrincipalName p, boolean server) throws KrbException {
String pn = p.toString();
if (p.getRealmString() == null) {
pn = pn + "@" + getRealm();
}
char[] pass = passwords.get(pn);
if (pass == null) {
- throw new KrbException(Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN);
+ throw new KrbException(server?
+ Krb5.KDC_ERR_S_PRINCIPAL_UNKNOWN:
+ Krb5.KDC_ERR_C_PRINCIPAL_UNKNOWN);
}
return pass;
}
@@ -444,7 +452,21 @@
* @return the salt
*/
private String getSalt(PrincipalName p) {
- String[] ns = p.getNameStrings();
+ if (System.getProperty("test.kdc.use.salt") != null) {
+ return System.getProperty("test.kdc.use.salt");
+ }
+ String pn = p.toString();
+ if (p.getRealmString() == null) {
+ pn = pn + "@" + getRealm();
+ }
+ if (passwords.containsKey(pn)) {
+ try {
+ // Find the principal name with correct case.
+ p = new PrincipalName(passwords.ceilingEntry(pn).getKey());
+ } catch (RealmException re) {
+ // Won't happen
+ }
+ }
String s = p.getRealmString();
if (s == null) s = getRealm();
for (String n: p.getNameStrings()) {
@@ -456,20 +478,23 @@
/**
* Returns the key for a given principal of the given encryption type
* @param p the principal
+ * @param server looking for a server principal?
* @param etype the encryption type
* @return the key
* @throws sun.security.krb5.KrbException for unknown/unsupported etype
*/
- private EncryptionKey keyForUser(PrincipalName p, int etype) throws KrbException {
+ private EncryptionKey keyForUser(PrincipalName p, int etype, boolean server) throws KrbException {
try {
// Do not call EncryptionKey.acquireSecretKeys(), otherwise
// the krb5.conf config file would be loaded.
Method stringToKey = EncryptionKey.class.getDeclaredMethod("stringToKey", char[].class, String.class, byte[].class, Integer.TYPE);
stringToKey.setAccessible(true);
- return new EncryptionKey((byte[]) stringToKey.invoke(null, getPassword(p), getSalt(p), null, etype), etype, null);
+ return new EncryptionKey((byte[]) stringToKey.invoke(null, getPassword(p, server), getSalt(p), null, etype), etype, null);
} catch (InvocationTargetException ex) {
KrbException ke = (KrbException)ex.getCause();
throw ke;
+ } catch (KrbException ke) {
+ throw ke;
} catch (Exception e) {
throw new RuntimeException(e); // should not happen
}
@@ -520,7 +545,7 @@
tkt = apReq.ticket;
etype = tkt.encPart.getEType();
tkt.sname.setRealm(tkt.realm);
- EncryptionKey kkey = keyForUser(tkt.sname, etype);
+ EncryptionKey kkey = keyForUser(tkt.sname, etype, true);
byte[] bb = tkt.encPart.decrypt(kkey, KeyUsage.KU_TICKET);
DerInputStream derIn = new DerInputStream(bb);
DerValue der = derIn.getDerValue();
@@ -531,7 +556,7 @@
throw new KrbException(Krb5.KDC_ERR_PADATA_TYPE_NOSUPP);
}
}
- EncryptionKey skey = keyForUser(body.sname, etype);
+ EncryptionKey skey = keyForUser(body.sname, etype, true);
if (skey == null) {
throw new KrbException(Krb5.KDC_ERR_SUMTYPE_NOSUPP); // TODO
}
@@ -661,8 +686,8 @@
eTypes = (int[])f.get(body);
int eType = eTypes[0];
- EncryptionKey ckey = keyForUser(body.cname, eType);
- EncryptionKey skey = keyForUser(body.sname, eType);
+ EncryptionKey ckey = keyForUser(body.cname, eType, false);
+ EncryptionKey skey = keyForUser(body.sname, eType, true);
if (ckey == null) {
throw new KrbException(Krb5.KDC_ERR_ETYPE_NOSUPP);
}
@@ -800,7 +825,8 @@
ke.returnCode() == Krb5.KDC_ERR_PREAUTH_FAILED) {
PAData pa;
- ETypeInfo2 ei2 = new ETypeInfo2(eTypes[0], null, null);
+ byte[] salt = getSalt(body.cname).getBytes();
+ ETypeInfo2 ei2 = new ETypeInfo2(eTypes[0], salt, null);
DerOutputStream eid = new DerOutputStream();
eid.write(DerValue.tag_Sequence, ei2.asn1Encode());
diff -r a7786f546f3f test/sun/security/krb5/auto/NewSalt.java
--- /dev/null
+++ b/test/sun/security/krb5/auto/NewSalt.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6856039
+ * @summary duplicate setSalt() called in AS-REQ
+ */
+
+import sun.security.jgss.GSSUtil;
+
+public class NewSalt {
+
+ public static void main(String[] args)
+ throws Exception {
+
+ // Create and start the KDC
+ new OneKDC(null);
+
+ // Use a different case of name. KDC will return correct salt
+ Context.fromUserPass(OneKDC.USER.toUpperCase(),
+ OneKDC.PASS, true);
+
+ // KDC always uses a different salt from the default one
+ System.setProperty("test.kdc.usesalt", "anyway");
+ Context.fromUserPass(OneKDC.USER,
+ OneKDC.PASS, true);
+ }
+}