JDK-8078495 : End time checking for native TGT is wrong
  • Type: Bug
  • Component: security-libs
  • Sub-Component: org.ietf.jgss:krb5
  • Affected Version: 7u76
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2015-03-25
  • Updated: 2017-08-02
  • Resolved: 2015-05-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
7u95Fixed 8u66Fixed 9 b64Fixed
Sub Tasks
JDK-8143922 :  

The issue is that the native TGT credential read out from MS LSA is ignored even if the TGT is not expired. It turns out that the way the end time check of the TGT is wrong when determining whether the TGT is expired in NativeCreds.c.

The root cause is the time formats for the two times to be checked is inconsistent. The current system time is UTC time, while the local end time is a time depending the timezone setting of the system. How can these two times be compared? Why don't convert them to the same time format for comparison? e.g UTC time.

For example, if the native TGT start time is 03/25/2015 13:00:00(UTC) and the lifetime of the TGT is 1 hour. This means the end time of the TGT is 03/25/2015 14:00:00(UTC). Assuming the user starts to use JGSS to get the credential. See what will happen if the user is at different time zones.

For time zone  ((UTC-05:00) Eastern Time (US & Canada)) :
TGT start time           :  03/25/2015  13 :00:00(UTC)
TGT end time            :  03/25/2015  14:00:00(UTC)
System time (Now)  :  03/25/2015  13:00:00(UTC)
TGT local end time  :  03/25/2015   09:00:00(Eastern Time (US & Canada)) 

The TGT will be "EXPIRED"

For time zone ((UTC+08:00) Beijing) :

TGT start time           :  03/25/2015  13:00:00(UTC)
TGT end time            :  03/25/2015  14:00:00(UTC)
System time (Now)  :  03/25/2015  13:00:00(UTC)
TGT local end time  :  03/25/2015   22:00:00(Beijing)

The TGT will be "VALID"

The native code should be fixed regarding this issue.

1. Having a Windows 7 client and Windows 2008 R2(AD);
2. Update the Group Policy on AD to set the user ticket lifetime to 1 hour(or 2)
3. Change the timezone of the Windows 7 client to UTC-5
4. Run below code :
Credentials cred = Credentials.acquireDefaultCreds();
		System.out.println("==============CREDENTIAL START====================");
		System.out.println("Client : " + cred.getClient().getName());
		System.out.println("Server : " + cred.getServer().getName());
		//Session key type 
		// DES_CBC_MD5 3
		// RC4_HMAC    23
		System.out.println("Session key type : " + cred.getSessionKey().getEType());
		System.out.println("Start time : "+cred.getStartTime().getTime()+ " GMT time : "+cred.getStartTime().toGMTString()+ " Local time : "+cred.getStartTime().toLocaleString());
		System.out.println("End time : "+cred.getEndTime().getTime()+ " GMT time : "+cred.getEndTime().toGMTString()+ " Local time : "+cred.getEndTime().toLocaleString());
		System.out.println("AUth time : "+cred.getAuthTime().getTime() + " GMT time : "+cred.getAuthTime().toGMTString() + " Local time : " + cred.getAuthTime().toLocaleString());
		//Print ticket info
		Ticket tkt = cred.getTicket();
		System.out.println("Ticket realm : "+tkt.realm);
		System.out.println("Ticket server : "+tkt.sname.getName());
		System.out.println("Ticket flags  : "+cred.getTicketFlags());
//		System.out.println("Ticket info : "+tkt.toString());
		System.out.println("=============CREDENTIAL END=========================");

If the information printed out is different from the klist(Windows version of klist) output, then the issue is reproduced. It can always be reproduced.

This bug can be reproduced always.

There is no easy way to write a regression test. A manual test can be: 1. A Windows client joining a Windows domain, or, run the test on the domain controller itself. 2. Write a simple program calling Credentials.acquireDefaultCreds() and print its content as described in the bug report. 3. Make sure the machine is configured to be in a timezone west of UTC. The distance from UTC should be bigger than KDC's lifetime setting. For example, default lifetime of a KDC is 10 hours, and you should set the time zone to UTC-11. 4. Run the program and see if the output is the same as Windows' own klist.exe (look at the initial ticket) There can be other reason that a ticket is re-acquired. For example, Windows Server 2012's native ticket is aes256 (session key type 18). If the client side JDK has not enabled unlimited crypto strength, it must re-acquire an aes128 ticket (session key type 17).

Yes, I found the expiration check wrong. GetSystemTimeAsFileTime(&Now); EndTime.dwLowDateTime = msticket->EndTime.LowPart; EndTime.dwHighDateTime = msticket->EndTime.HighPart; FileTimeToLocalFileTime(&EndTime, &LocalEndTime); if (CompareFileTime(&Now, &LocalEndTime) < 0) { Here, the output of GetSystemTimeAsFileTime and msticket->EndTime are both UTC, and there is no need to convert EndTime to a local time. I guess the reason this was not reported earlier is because Java will reacquire a ticket if it sees an expired one, so once it succeeds no error will be reported. In fact, the bug report mentions the output of MS klist.exe is different from what Java reports, it's not because Java does a wrong time conversion, but because Java has acquired a new ticket.

Need test infrastructure in order to verify this issue. Not able to reproduce currently. Moving this up for further review,