Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java
38923 views
/*1* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation. Oracle designates this6* particular file as subject to the "Classpath" exception as provided7* by Oracle in the LICENSE file that accompanied this code.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*/2324/*25*26* (C) Copyright IBM Corp. 1999 All Rights Reserved.27* Copyright 1997 The Open Group Research Institute. All rights reserved.28*/2930package sun.security.krb5.internal;3132import sun.security.krb5.Asn1Exception;33import sun.security.krb5.Config;34import sun.security.krb5.KrbException;35import sun.security.util.DerInputStream;36import sun.security.util.DerOutputStream;37import sun.security.util.DerValue;3839import java.io.IOException;40import java.time.Instant;41import java.util.Calendar;42import java.util.Date;43import java.util.TimeZone;4445/**46* Implements the ASN.1 KerberosTime type. This is an immutable class.47*48* {@code KerberosTime ::= GeneralizedTime} -- with no fractional seconds49*50* The timestamps used in Kerberos are encoded as GeneralizedTimes. A51* KerberosTime value shall not include any fractional portions of the52* seconds. As required by the DER, it further shall not include any53* separators, and it shall specify the UTC time zone (Z).54*55* <p>56* This definition reflects the Network Working Group RFC 412057* specification available at58* <a href="http://www.ietf.org/rfc/rfc4120.txt">59* http://www.ietf.org/rfc/rfc4120.txt</a>.60*61* The implementation also includes the microseconds info so that the62* same class can be used as a precise timestamp in Authenticator etc.63*/6465public class KerberosTime {6667private final long kerberosTime; // milliseconds since epoch, Date.getTime()68private final int microSeconds; // last 3 digits of the real microsecond6970// The time when this class is loaded. Used in setNow()71private static long initMilli = System.currentTimeMillis();72private static long initMicro = System.nanoTime() / 1000;7374private static boolean DEBUG = Krb5.DEBUG;7576// Do not make this public. It's a little confusing that micro77// is only the last 3 digits of microsecond.78private KerberosTime(long time, int micro) {79kerberosTime = time;80microSeconds = micro;81}8283/**84* Creates a KerberosTime object from milliseconds since epoch.85*/86public KerberosTime(long time) {87this(time, 0);88}8990// This constructor is used in the native code91// src/windows/native/sun/security/krb5/NativeCreds.c92public KerberosTime(String time) throws Asn1Exception {93this(toKerberosTime(time), 0);94}9596private static long toKerberosTime(String time) throws Asn1Exception {97// ASN.1 GeneralizedTime format:9899// "19700101000000Z"100// | | | | | | |101// 0 4 6 8 | | |102// 10 | |103// 12 |104// 14105106if (time.length() != 15)107throw new Asn1Exception(Krb5.ASN1_BAD_TIMEFORMAT);108if (time.charAt(14) != 'Z')109throw new Asn1Exception(Krb5.ASN1_BAD_TIMEFORMAT);110int year = Integer.parseInt(time.substring(0, 4));111Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));112calendar.clear(); // so that millisecond is zero113calendar.set(year,114Integer.parseInt(time.substring(4, 6)) - 1,115Integer.parseInt(time.substring(6, 8)),116Integer.parseInt(time.substring(8, 10)),117Integer.parseInt(time.substring(10, 12)),118Integer.parseInt(time.substring(12, 14)));119return calendar.getTimeInMillis();120}121122/**123* Creates a KerberosTime object from a Date object.124*/125public KerberosTime(Date time) {126this(time.getTime(), 0);127}128129/**130* Creates a KerberosTime object from an Instant object131*/132public KerberosTime(Instant instant) {133this(instant.getEpochSecond()*1000 + instant.getNano()/1000000L,134instant.getNano()/1000%1000);135}136137/**138* Creates a KerberosTime object for now. It uses System.nanoTime()139* to get a more precise time than "new Date()".140*/141public static KerberosTime now() {142long newMilli = System.currentTimeMillis();143long newMicro = System.nanoTime() / 1000;144long microElapsed = newMicro - initMicro;145long calcMilli = initMilli + microElapsed/1000;146if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) {147if (DEBUG) {148System.out.println("System time adjusted");149}150initMilli = newMilli;151initMicro = newMicro;152return new KerberosTime(newMilli, 0);153} else {154return new KerberosTime(calcMilli, (int)(microElapsed % 1000));155}156}157158/**159* Returns a string representation of KerberosTime object.160* @return a string representation of this object.161*/162public String toGeneralizedTimeString() {163Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));164calendar.clear();165166calendar.setTimeInMillis(kerberosTime);167return String.format("%04d%02d%02d%02d%02d%02dZ",168calendar.get(Calendar.YEAR),169calendar.get(Calendar.MONTH) + 1,170calendar.get(Calendar.DAY_OF_MONTH),171calendar.get(Calendar.HOUR_OF_DAY),172calendar.get(Calendar.MINUTE),173calendar.get(Calendar.SECOND));174}175176/**177* Encodes this object to a byte array.178* @return a byte array of encoded data.179* @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.180* @exception IOException if an I/O error occurs while reading encoded data.181*/182public byte[] asn1Encode() throws Asn1Exception, IOException {183DerOutputStream out = new DerOutputStream();184out.putGeneralizedTime(this.toDate());185return out.toByteArray();186}187188public long getTime() {189return kerberosTime;190}191192public Date toDate() {193return new Date(kerberosTime);194}195196public int getMicroSeconds() {197Long temp_long = new Long((kerberosTime % 1000L) * 1000L);198return temp_long.intValue() + microSeconds;199}200201/**202* Returns a new KerberosTime object with the original seconds203* and the given microseconds.204*/205public KerberosTime withMicroSeconds(int usec) {206return new KerberosTime(207kerberosTime - kerberosTime%1000L + usec/1000L,208usec%1000);209}210211private boolean inClockSkew(int clockSkew) {212return java.lang.Math.abs(kerberosTime - System.currentTimeMillis())213<= clockSkew * 1000L;214}215216public boolean inClockSkew() {217return inClockSkew(getDefaultSkew());218}219220public boolean greaterThanWRTClockSkew(KerberosTime time, int clockSkew) {221if ((kerberosTime - time.kerberosTime) > clockSkew * 1000L)222return true;223return false;224}225226public boolean greaterThanWRTClockSkew(KerberosTime time) {227return greaterThanWRTClockSkew(time, getDefaultSkew());228}229230public boolean greaterThan(KerberosTime time) {231return kerberosTime > time.kerberosTime ||232kerberosTime == time.kerberosTime &&233microSeconds > time.microSeconds;234}235236public boolean equals(Object obj) {237if (this == obj) {238return true;239}240241if (!(obj instanceof KerberosTime)) {242return false;243}244245return kerberosTime == ((KerberosTime)obj).kerberosTime &&246microSeconds == ((KerberosTime)obj).microSeconds;247}248249public int hashCode() {250int result = 37 * 17 + (int)(kerberosTime ^ (kerberosTime >>> 32));251return result * 17 + microSeconds;252}253254public boolean isZero() {255return kerberosTime == 0 && microSeconds == 0;256}257258public int getSeconds() {259Long temp_long = new Long(kerberosTime / 1000L);260return temp_long.intValue();261}262263/**264* Parse (unmarshal) a kerberostime from a DER input stream. This form265* parsing might be used when expanding a value which is part of266* a constructed sequence and uses explicitly tagged type.267*268* @exception Asn1Exception on error.269* @param data the Der input stream value, which contains270* one or more marshaled value.271* @param explicitTag tag number.272* @param optional indicates if this data field is optional273* @return an instance of KerberosTime.274*275*/276public static KerberosTime parse(277DerInputStream data, byte explicitTag, boolean optional)278throws Asn1Exception, IOException {279if ((optional) && (((byte)data.peekByte() & (byte)0x1F)!= explicitTag))280return null;281DerValue der = data.getDerValue();282if (explicitTag != (der.getTag() & (byte)0x1F)) {283throw new Asn1Exception(Krb5.ASN1_BAD_ID);284}285else {286DerValue subDer = der.getData().getDerValue();287Date temp = subDer.getGeneralizedTime();288return new KerberosTime(temp.getTime(), 0);289}290}291292public static int getDefaultSkew() {293int tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW;294try {295if ((tdiff = Config.getInstance().getIntValue(296"libdefaults", "clockskew"))297== Integer.MIN_VALUE) { //value is not defined298tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW;299}300} catch (KrbException e) {301if (DEBUG) {302System.out.println("Exception in getting clockskew from " +303"Configuration " +304"using default value " +305e.getMessage());306}307}308return tdiff;309}310311public String toString() {312return toGeneralizedTimeString();313}314}315316317