8028780: JDK KRB5 module throws OutOfMemoryError when CCache is corrupt
authorweijun
Mon, 30 Dec 2013 11:51:19 +0800
changeset 22093 741504ef3df7
parent 22092 0fdcb913f6be
child 22094 1c154d8a9a96
8028780: JDK KRB5 module throws OutOfMemoryError when CCache is corrupt Reviewed-by: xuelei
jdk/src/share/classes/sun/security/jgss/GSSNameImpl.java
jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java
jdk/src/share/classes/sun/security/krb5/internal/ccache/FileCCacheConstants.java
jdk/test/sun/security/jgss/GssMemoryIssues.java
jdk/test/sun/security/krb5/TimeInCCache.java
jdk/test/sun/security/krb5/ccache/CorruptedCC.java
jdk/test/sun/security/krb5/ccache/TimeInCCache.java
--- a/jdk/src/share/classes/sun/security/jgss/GSSNameImpl.java	Tue Dec 24 20:07:12 2013 -0800
+++ b/jdk/src/share/classes/sun/security/jgss/GSSNameImpl.java	Mon Dec 30 11:51:19 2013 +0800
@@ -257,6 +257,10 @@
                               ((0xFF & bytes[pos++]) << 16) |
                               ((0xFF & bytes[pos++]) << 8) |
                               (0xFF & bytes[pos++]));
+        if (pos > bytes.length - mechPortionLen) {
+            throw new GSSExceptionImpl(GSSException.BAD_NAME,
+                    "Exported name mech name is corrupted!");
+        }
         byte[] mechPortion = new byte[mechPortionLen];
         System.arraycopy(bytes, pos, mechPortion, 0, mechPortionLen);
 
--- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java	Tue Dec 24 20:07:12 2013 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java	Mon Dec 30 11:51:19 2013 +0800
@@ -32,9 +32,11 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Hashtable;
-import java.util.Vector;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.StringTokenizer;
+
+import sun.misc.IOUtils;
 import sun.security.krb5.*;
 import sun.security.krb5.internal.*;
 import sun.security.krb5.internal.util.KrbDataInputStream;
@@ -74,7 +76,6 @@
     // this needs to be public for Kinit.
     public Tag readTag() throws IOException {
         char[] buf = new char[1024];
-        byte[] bytes;
         int len;
         int tag = -1;
         int taglen;
@@ -85,7 +86,6 @@
         if (len < 0) {
             throw new IOException("stop.");
         }
-        bytes = new byte[len + 2];
         if (len > buf.length) {
             throw new IOException("Invalid tag length.");
         }
@@ -101,11 +101,7 @@
             }
             len = len - (4 + taglen);
         }
-        Tag result;
-        if (tag == -1) {
-        }
-        result = new Tag(len, tag, time_offset, usec_offset);
-        return result;
+        return new Tag(len, tag, time_offset, usec_offset);
     }
     /*
      * In file-based credential cache, the realm name is stored as part of
@@ -123,7 +119,7 @@
             type = read(4);
         }
         length = read(4);
-        String[] result = new String[length + 1];
+        List<String> result = new ArrayList<String>();
         /*
          * DCE includes the principal's realm in the count; the new format
          * does not.
@@ -132,21 +128,26 @@
             length--;
         for (int i = 0; i <= length; i++) {
             namelength = read(4);
-            if (namelength > MAXNAMELENGTH) {
-                throw new IOException("Invalid name length in principal name.");
+            byte[] bytes = IOUtils.readFully(this, namelength, true);
+            result.add(new String(bytes));
+        }
+        if (result.isEmpty()) {
+            throw new IOException("No realm or principal");
+        }
+        if (isRealm(result.get(0))) {
+            realm = result.remove(0);
+            if (result.isEmpty()) {
+                throw new IOException("No principal name components");
             }
-            byte[] bytes = new byte[namelength];
-            read(bytes, 0, namelength);
-            result[i] = new String(bytes);
-        }
-        if (isRealm(result[0])) {
-            realm = result[0];
-            pname = new String[length];
-            System.arraycopy(result, 1, pname, 0, length);
-            return new PrincipalName(type, pname, new Realm(realm));
+            return new PrincipalName(
+                    type,
+                    result.toArray(new String[result.size()]),
+                    new Realm(realm));
         }
         try {
-            return new PrincipalName(result, type);
+            return new PrincipalName(
+                    result.toArray(new String[result.size()]),
+                    type);
         } catch (RealmException re) {
             return null;
         }
@@ -184,10 +185,7 @@
         if (version == KRB5_FCC_FVNO_3)
             read(2); /* keytype recorded twice in fvno 3 */
         keyLen = read(4);
-        byte[] bytes = new byte[keyLen];
-        for (int i = 0; i < keyLen; i++) {
-            bytes[i] = (byte)read();
-        }
+        byte[] bytes = IOUtils.readFully(this, keyLen, true);
         return new EncryptionKey(bytes, keyType, new Integer(version));
     }
 
@@ -211,7 +209,7 @@
         int numAddrs, addrType, addrLength;
         numAddrs = read(4);
         if (numAddrs > 0) {
-            HostAddress[] addrs = new HostAddress[numAddrs];
+            List<HostAddress> addrs = new ArrayList<>();
             for (int i = 0; i < numAddrs; i++) {
                 addrType = read(2);
                 addrLength = read(4);
@@ -224,9 +222,9 @@
                 byte[] result = new byte[addrLength];
                 for (int j = 0; j < addrLength; j++)
                     result[j] = (byte)read(1);
-                addrs[i] = new HostAddress(addrType, result);
+                addrs.add(new HostAddress(addrType, result));
             }
-            return addrs;
+            return addrs.toArray(new HostAddress[addrs.size()]);
         }
         return null;
     }
@@ -235,18 +233,15 @@
         int num, adtype, adlength;
         num = read(4);
         if (num > 0) {
-            AuthorizationDataEntry[] auData = new AuthorizationDataEntry[num];
+            List<AuthorizationDataEntry> auData = new ArrayList<>();
             byte[] data = null;
             for (int i = 0; i < num; i++) {
                 adtype = read(2);
                 adlength = read(4);
-                data = new byte[adlength];
-                for (int j = 0; j < adlength; j++) {
-                    data[j] = (byte)read();
-                }
-                auData[i] = new AuthorizationDataEntry(adtype, data);
+                data = IOUtils.readFully(this, adlength, true);
+                auData.add(new AuthorizationDataEntry(adtype, data));
             }
-            return auData;
+            return auData.toArray(new AuthorizationDataEntry[auData.size()]);
         }
         else return null;
     }
@@ -257,9 +252,7 @@
         if (length == 0) {
             return null;
         } else {
-            byte[] bytes = new byte[length];
-            read(bytes, 0, length);
-            return bytes;
+            return IOUtils.readFully(this, length, true);
         }
     }
 
--- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/FileCCacheConstants.java	Tue Dec 24 20:07:12 2013 -0800
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/FileCCacheConstants.java	Mon Dec 30 11:51:19 2013 +0800
@@ -49,7 +49,6 @@
     public final int KRB5_FCC_FVNO_4 = 0x504;
     public final int FCC_TAG_DELTATIME = 1;
     public final int KRB5_NT_UNKNOWN = 0;
-    public final int MAXNAMELENGTH = 1024;
     public final int TKT_FLG_FORWARDABLE = 0x40000000;
     public final int TKT_FLG_FORWARDED  =  0x20000000;
     public final int TKT_FLG_PROXIABLE   = 0x10000000;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/jgss/GssMemoryIssues.java	Mon Dec 30 11:51:19 2013 +0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8028780
+ * @summary JDK KRB5 module throws OutOfMemoryError when CCache is corrupt
+ * @run main/othervm -Xmx8m GssMemoryIssues
+ */
+
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+
+public class GssMemoryIssues {
+
+    public static void main(String[] argv) throws Exception {
+        GSSManager man = GSSManager.getInstance();
+        String s = "me@REALM";
+        GSSName name = man.createName(s, GSSName.NT_USER_NAME);
+        byte[] exported = name.export();
+        // Offset of the length of the mech name. Length in big endian
+        int lenOffset = exported.length - s.length() - 4;
+        // Make it huge
+        exported[lenOffset] = 0x7f;
+        try {
+            man.createName(exported, GSSName.NT_EXPORT_NAME);
+        } catch (GSSException gsse) {
+            System.out.println(gsse);
+        }
+    }
+}
--- a/jdk/test/sun/security/krb5/TimeInCCache.java	Tue Dec 24 20:07:12 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2007, 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-/*
- * @test
- * @bug 6590930
- * @run main/othervm TimeInCCache
- * @summary read/write does not match for ccache
- */
-
-import java.io.ByteArrayInputStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import sun.security.krb5.internal.ccache.CCacheInputStream;
-import sun.security.krb5.internal.ccache.Credentials;
-
-public class TimeInCCache {
-    public static void main(String[] args) throws Exception {
-        // A trivial cache file, with startdate and renewTill being zero.
-        // The endtime is set to sometime in year 2022, so that isValid()
-        // will always check starttime.
-        byte[] ccache = new byte[]{
-            5, 4, 0, 12, 0, 1, 0, 8, -1, -1, -1, 19, -1, -2, 89, 51,
-            0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 10, 77, 65, 88, 73,
-            46, 76, 79, 67, 65, 76, 0, 0, 0, 5, 100, 117, 109, 109, 121, 0,
-            0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 10, 77, 65, 88, 73, 46,
-            76, 79, 67, 65, 76, 0, 0, 0, 5, 100, 117, 109, 109, 121, 0, 0,
-            0, 0, 0, 0, 0, 2, 0, 0, 0, 10, 77, 65, 88, 73, 46, 76,
-            79, 67, 65, 76, 0, 0, 0, 6, 107, 114, 98, 116, 103, 116, 0, 0,
-            0, 10, 77, 65, 88, 73, 46, 76, 79, 67, 65, 76, 0, 17, 0, 0,
-            0, 16, -78, -85, -90, -50, -68, 115, 68, 8, -39, -109, 91, 61, -17, -27,
-            -122, -120, 71, 69, 16, -121, 0, 0, 0, 0, 98, 69, 16, -121, 0, 0,
-            0, 0, 0, 64, -32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-            0, 1, 0, 97, -127, -3, 48, -127, -6, -96, 3, 2, 1, 5, -95, 12,
-            27, 10, 77, 65, 88, 73, 46, 76, 79, 67, 65, 76, -94, 31, 48, 29,
-            -96, 3, 2, 1, 0, -95, 22, 48, 20, 27, 6, 107, 114, 98, 116, 103,
-            116, 27, 10, 77, 65, 88, 73, 46, 76, 79, 67, 65, 76, -93, -127, -61,
-            48, -127, -64, -96, 3, 2, 1, 17, -95, 3, 2, 1, 1, -94, -127, -77,
-            4, -127, -80, 43, 65, -66, 34, 21, -34, 37, 35, 32, 50, -14, 122, 77,
-            -3, -29, 37, 99, 50, 125, -43, -96, -78, 85, 23, 41, -80, 68, 2, -109,
-            -27, 38, -41, -72, -32, 127, 63, -76, -22, 81, 33, -114, -30, 104, 125, -81,
-            -29, 70, -25, 23, 100, -75, -25, 62, -120, -78, -61, -100, -74, 50, -117, -127,
-            -16, 79, -106, 62, -39, 91, 100, -10, 23, -88, -18, -47, 51, -19, 113, 18,
-            98, -101, 31, 98, 22, -81, 11, -41, -42, 67, 87, 92, -2, 42, -54, 79,
-            49, -90, 43, -37, 90, -102, 125, 62, -88, -77, 100, 102, 23, -57, -51, 38,
-            68, -44, -57, -102, 103, -6, 85, -58, 74, -117, -87, 67, -103, -36, 110, -122,
-            115, 12, 118, -106, -114, -51, 79, 68, 32, -91, -53, -5, -51, 89, 72, 70,
-            123, -12, -95, 9, 40, -30, -117, 74, 77, 38, 91, 126, -82, 17, 98, 98,
-            -49, 78, 36, 36, 103, -76, -100, -23, 118, -92, -8, 80, 103, -23, -98, 56,
-            21, 65, -77, 0, 0, 0, 0
-        };
-        System.setProperty("sun.security.krb5.debug", "true");  // test code changes in DEBUG
-        CCacheInputStream cis = new CCacheInputStream(new ByteArrayInputStream(ccache));
-        cis.readVersion();
-        cis.readTag();
-        cis.readPrincipal(0x504);
-        Method m = CCacheInputStream.class.getDeclaredMethod("readCred", Integer.TYPE);
-        m.setAccessible(true);
-        Credentials c = (Credentials) m.invoke(cis, new Integer(0x504));
-        sun.security.krb5.Credentials cc = c.setKrbCreds();
-
-        // 1. Make sure starttime is still null
-        if (cc.getStartTime() != null) {
-            throw new Exception("Fail, starttime should be zero here");
-        }
-
-        // 2. Make sure renewTill is still null
-        if (cc.getRenewTill() != null) {
-            throw new Exception("Fail, renewTill should be zero here");
-        }
-
-        // 3. Make sure isValid works
-        c.isValid();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/ccache/CorruptedCC.java	Mon Dec 30 11:51:19 2013 +0800
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8028780
+ * @summary JDK KRB5 module throws OutOfMemoryError when CCache is corrupt
+ * @run main/othervm -Xmx8m CorruptedCC
+ */
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import sun.security.krb5.internal.ccache.CredentialsCache;
+
+public class CorruptedCC {
+    public static void main(String[] args) throws Exception {
+        for (int i=0; i<TimeInCCache.ccache.length; i++) {
+            byte old = TimeInCCache.ccache[i];
+            TimeInCCache.ccache[i] = 0x7f;
+            Files.write(Paths.get("tmpcc"), TimeInCCache.ccache);
+            // The next line will return null for I/O issues. That's OK.
+            CredentialsCache.getInstance("tmpcc");
+            TimeInCCache.ccache[i] = old;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/ccache/TimeInCCache.java	Mon Dec 30 11:51:19 2013 +0800
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2007, 2011, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * @test
+ * @bug 6590930
+ * @run main/othervm TimeInCCache
+ * @summary read/write does not match for ccache
+ */
+
+import java.io.ByteArrayInputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import sun.security.krb5.internal.ccache.CCacheInputStream;
+import sun.security.krb5.internal.ccache.Credentials;
+
+public class TimeInCCache {
+    // Attention: this field is also used by CorruptedCC.java test
+    public static byte[] ccache;
+
+    static {
+        // A trivial cache file, with startdate and renewTill being zero.
+        // The endtime is set to sometime in year 2022, so that isValid()
+        // will always check starttime.
+        String var =
+            /*0000*/ "05 04 00 0C 00 01 00 08 FF FF FF 13 FF FE 59 33 " +
+            /*0010*/ "00 00 00 01 00 00 00 01 00 00 00 0A 4D 41 58 49 " +
+            /*0020*/ "2E 4C 4F 43 41 4C 00 00 00 05 64 75 6D 6D 79 00 " +
+            /*0030*/ "00 00 01 00 00 00 01 00 00 00 0A 4D 41 58 49 2E " +
+            /*0040*/ "4C 4F 43 41 4C 00 00 00 05 64 75 6D 6D 79 00 00 " +
+            /*0050*/ "00 00 00 00 00 02 00 00 00 0A 4D 41 58 49 2E 4C " +
+            /*0060*/ "4F 43 41 4C 00 00 00 06 6B 72 62 74 67 74 00 00 " +
+            /*0070*/ "00 0A 4D 41 58 49 2E 4C 4F 43 41 4C 00 11 00 00 " +
+            /*0080*/ "00 10 B2 AB A6 CE BC 73 44 08 D9 93 5B 3D EF E5 " +
+            /*0090*/ "86 88 47 45 10 87 00 00 00 00 62 45 10 87 00 00 " +
+            /*00A0*/ "00 00 00 40 E0 00 00 00 00 00 00 00 00 00 00 00 " +
+            /*00B0*/ "00 01 00 61 81 FD 30 81 FA A0 03 02 01 05 A1 0C " +
+            /*00C0*/ "1B 0A 4D 41 58 49 2E 4C 4F 43 41 4C A2 1F 30 1D " +
+            /*00D0*/ "A0 03 02 01 00 A1 16 30 14 1B 06 6B 72 62 74 67 " +
+            /*00E0*/ "74 1B 0A 4D 41 58 49 2E 4C 4F 43 41 4C A3 81 C3 " +
+            /*00F0*/ "30 81 C0 A0 03 02 01 11 A1 03 02 01 01 A2 81 B3 " +
+            /*0100*/ "04 81 B0 2B 41 BE 22 15 DE 25 23 20 32 F2 7A 4D " +
+            /*0110*/ "FD E3 25 63 32 7D D5 A0 B2 55 17 29 B0 44 02 93 " +
+            /*0120*/ "E5 26 D7 B8 E0 7F 3F B4 EA 51 21 8E E2 68 7D AF " +
+            /*0130*/ "E3 46 E7 17 64 B5 E7 3E 88 B2 C3 9C B6 32 8B 81 " +
+            /*0140*/ "F0 4F 96 3E D9 5B 64 F6 17 A8 EE D1 33 ED 71 12 " +
+            /*0150*/ "62 9B 1F 62 16 AF 0B D7 D6 43 57 5C FE 2A CA 4F " +
+            /*0160*/ "31 A6 2B DB 5A 9A 7D 3E A8 B3 64 66 17 C7 CD 26 " +
+            /*0170*/ "44 D4 C7 9A 67 FA 55 C6 4A 8B A9 43 99 DC 6E 86 " +
+            /*0180*/ "73 0C 76 96 8E CD 4F 44 20 A5 CB FB CD 59 48 46 " +
+            /*0190*/ "7B F4 A1 09 28 E2 8B 4A 4D 26 5B 7E AE 11 62 62 " +
+            /*01A0*/ "CF 4E 24 24 67 B4 9C E9 76 A4 F8 50 67 E9 9E 38 " +
+            /*01B0*/ "15 41 B3 00 00 00 00 ";
+        ccache = new byte[var.length()/3];
+        for (int i=0; i<ccache.length; i++) {
+            ccache[i] = Integer.valueOf(var.substring(3*i,3*i+2), 16).byteValue();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.setProperty("sun.security.krb5.debug", "true");  // test code changes in DEBUG
+        CCacheInputStream cis = new CCacheInputStream(new ByteArrayInputStream(ccache));
+        cis.readVersion();
+        cis.readTag();
+        cis.readPrincipal(0x504);
+        Method m = CCacheInputStream.class.getDeclaredMethod("readCred", Integer.TYPE);
+        m.setAccessible(true);
+        Credentials c = (Credentials) m.invoke(cis, new Integer(0x504));
+        sun.security.krb5.Credentials cc = c.setKrbCreds();
+
+        // 1. Make sure starttime is still null
+        if (cc.getStartTime() != null) {
+            throw new Exception("Fail, starttime should be zero here");
+        }
+
+        // 2. Make sure renewTill is still null
+        if (cc.getRenewTill() != null) {
+            throw new Exception("Fail, renewTill should be zero here");
+        }
+
+        // 3. Make sure isValid works
+        c.isValid();
+    }
+}