blob: 5288d58632d6f7be89fedcddc7a448308565a272 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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 it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 */
24
25/*
26 *
27 * (C) Copyright IBM Corp. 1999 All Rights Reserved.
28 * Copyright 1997 The Open Group Research Institute. All rights reserved.
29 */
30
31package sun.security.krb5.internal;
32
33import java.util.TimeZone;
34import sun.security.util.*;
35import sun.security.krb5.Config;
36import sun.security.krb5.KrbException;
37import sun.security.krb5.Asn1Exception;
38import java.util.Date;
39import java.util.GregorianCalendar;
40import java.util.Calendar;
41import java.io.IOException;
42
43/**
44 * Implements the ASN.1 KerberosTime type.
45 *
46 * <xmp>
47 * KerberosTime ::= GeneralizedTime -- with no fractional seconds
48 * </xmp>
49 *
50 * The timestamps used in Kerberos are encoded as GeneralizedTimes. A
51 * KerberosTime value shall not include any fractional portions of the
52 * seconds. As required by the DER, it further shall not include any
53 * separators, and it shall specify the UTC time zone (Z).
54 *
55 * <p>
56 * This definition reflects the Network Working Group RFC 4120
57 * specification available at
58 * <a href="http://www.ietf.org/rfc/rfc4120.txt">
59 * http://www.ietf.org/rfc/rfc4120.txt</a>.
60 */
61
62public class KerberosTime implements Cloneable {
63
64 private long kerberosTime; // milliseconds since epoch, a Date.getTime() value
65 private static long syncTime;
66 private static boolean DEBUG = Krb5.DEBUG;
67
68 public static final boolean NOW = true;
69 public static final boolean UNADJUSTED_NOW = false;
70
71 //defaults to zero instead of now; use setNow() for current time
72 public KerberosTime() {
73 kerberosTime = 0;
74 }
75
76 public KerberosTime(long time) {
77 kerberosTime = time;
78 }
79
80
81 public Object clone() {
82 return new KerberosTime(kerberosTime);
83 }
84
85 // This constructor is used in the native code
86 // src/windows/native/sun/security/krb5/NativeCreds.c
87 public KerberosTime(String time) throws Asn1Exception {
88 kerberosTime = toKerberosTime(time);
89 }
90
91 /**
92 * Constructs a KerberosTime object.
93 * @param encoding a DER-encoded data.
94 * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
95 * @exception IOException if an I/O error occurs while reading encoded data.
96 */
97 public KerberosTime(DerValue encoding) throws Asn1Exception, IOException {
98 GregorianCalendar calendar = new GregorianCalendar();
99 Date temp = encoding.getGeneralizedTime();
100 kerberosTime = temp.getTime();
101 }
102
103 private static long toKerberosTime(String time) throws Asn1Exception {
104 // this method only used by KerberosTime class.
105
106 // ASN.1 GeneralizedTime format:
107
108 // "19700101000000Z"
109 // | | | | | | |
110 // 0 4 6 8 | | |
111 // 10 | |
112 // 12 |
113 // 14
114
115 if (time.length() != 15)
116 throw new Asn1Exception(Krb5.ASN1_BAD_TIMEFORMAT);
117 if (time.charAt(14) != 'Z')
118 throw new Asn1Exception(Krb5.ASN1_BAD_TIMEFORMAT);
119 int year = Integer.parseInt(time.substring(0, 4));
120 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
121 calendar.clear(); // so that millisecond is zero
122 calendar.set(year,
123 Integer.parseInt(time.substring(4, 6)) - 1,
124 Integer.parseInt(time.substring(6, 8)),
125 Integer.parseInt(time.substring(8, 10)),
126 Integer.parseInt(time.substring(10, 12)),
127 Integer.parseInt(time.substring(12, 14)));
128
129 //The Date constructor assumes the setting are local relative
130 //and converts the time to UTC before storing it. Since we
131 //want the internal representation to correspond to local
132 //and not UTC time we subtract the UTC time offset.
133 return (calendar.getTime().getTime());
134
135 }
136
137 // should be moved to sun.security.krb5.util class
138 public static String zeroPad(String s, int length) {
139 StringBuffer temp = new StringBuffer(s);
140 while (temp.length() < length)
141 temp.insert(0, '0');
142 return temp.toString();
143 }
144
145 public KerberosTime(Date time) {
146 kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
147 }
148
149 public KerberosTime(boolean initToNow) {
150 if (initToNow) {
151 Date temp = new Date();
152 setTime(temp);
153 }
154 else
155 kerberosTime = 0;
156 }
157
158 /**
159 * Returns a string representation of KerberosTime object.
160 * @return a string representation of this object.
161 */
162 public String toGeneralizedTimeString() {
163 Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
164 calendar.clear();
165
166 calendar.setTimeInMillis(kerberosTime);
167 return zeroPad(Integer.toString(calendar.get(Calendar.YEAR)), 4) +
168 zeroPad(Integer.toString(calendar.get(Calendar.MONTH) + 1), 2) +
169 zeroPad(Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)), 2) +
170 zeroPad(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)), 2) +
171 zeroPad(Integer.toString(calendar.get(Calendar.MINUTE)), 2) +
172 zeroPad(Integer.toString(calendar.get(Calendar.SECOND)), 2) + 'Z';
173
174 }
175
176 /**
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 */
182 public byte[] asn1Encode() throws Asn1Exception, IOException {
183 DerOutputStream out = new DerOutputStream();
184 out.putGeneralizedTime(this.toDate());
185 return out.toByteArray();
186 }
187
188 public long getTime() {
189 return kerberosTime;
190 }
191
192
193 public void setTime(Date time) {
194 kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
195 }
196
197 public void setTime(long time) {
198 kerberosTime = time;
199 }
200
201 public Date toDate() {
202 Date temp = new Date(kerberosTime);
203 temp.setTime(temp.getTime());
204 return temp;
205 }
206
207 public void setNow() {
208 Date temp = new Date();
209 setTime(temp);
210 }
211
212 public int getMicroSeconds() {
213 Long temp_long = new Long((kerberosTime % 1000L) * 1000L);
214 return temp_long.intValue();
215 }
216
217 public void setMicroSeconds(int usec) {
218 Integer temp_int = new Integer(usec);
219 long temp_long = temp_int.longValue() / 1000L;
220 kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
221 }
222
223 public void setMicroSeconds(Integer usec) {
224 if (usec != null) {
225 long temp_long = usec.longValue() / 1000L;
226 kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
227 }
228 }
229
230 public boolean inClockSkew(int clockSkew) {
231 KerberosTime now = new KerberosTime(KerberosTime.NOW);
232
233 if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
234 clockSkew * 1000L)
235 return false;
236 return true;
237 }
238
239 public boolean inClockSkew() {
240 return inClockSkew(getDefaultSkew());
241 }
242
243 public boolean inClockSkew(int clockSkew, KerberosTime now) {
244 if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
245 clockSkew * 1000L)
246 return false;
247 return true;
248 }
249
250 public boolean inClockSkew(KerberosTime time) {
251 return inClockSkew(getDefaultSkew(), time);
252 }
253
254 public boolean greaterThanWRTClockSkew(KerberosTime time, int clockSkew) {
255 if ((kerberosTime - time.kerberosTime) > clockSkew * 1000L)
256 return true;
257 return false;
258 }
259
260 public boolean greaterThanWRTClockSkew(KerberosTime time) {
261 return greaterThanWRTClockSkew(time, getDefaultSkew());
262 }
263
264 public boolean greaterThan(KerberosTime time) {
265 return kerberosTime > time.kerberosTime;
266 }
267
268 public boolean equals(Object obj) {
269 if (this == obj) {
270 return true;
271 }
272
273 if (!(obj instanceof KerberosTime)) {
274 return false;
275 }
276
277 return kerberosTime == ((KerberosTime)obj).kerberosTime;
278 }
279
280 public int hashCode() {
281 return 37 * 17 + (int)(kerberosTime ^ (kerberosTime >>> 32));
282 }
283
284 public boolean isZero() {
285 return kerberosTime == 0;
286 }
287
288 public int getSeconds() {
289 Long temp_long = new Long(kerberosTime / 1000L);
290 return temp_long.intValue();
291 }
292
293 public void setSeconds(int sec) {
294 Integer temp_int = new Integer(sec);
295 kerberosTime = temp_int.longValue() * 1000L;
296 }
297
298 /**
299 * Parse (unmarshal) a kerberostime from a DER input stream. This form
300 * parsing might be used when expanding a value which is part of
301 * a constructed sequence and uses explicitly tagged type.
302 *
303 * @exception Asn1Exception on error.
304 * @param data the Der input stream value, which contains one or more marshaled value.
305 * @param explicitTag tag number.
306 * @param optional indicates if this data field is optional
307 * @return an instance of KerberosTime.
308 *
309 */
310 public static KerberosTime parse(DerInputStream data, byte explicitTag, boolean optional) throws Asn1Exception, IOException {
311 if ((optional) && (((byte)data.peekByte() & (byte)0x1F)!= explicitTag))
312 return null;
313 DerValue der = data.getDerValue();
314 if (explicitTag != (der.getTag() & (byte)0x1F)) {
315 throw new Asn1Exception(Krb5.ASN1_BAD_ID);
316 }
317 else {
318 DerValue subDer = der.getData().getDerValue();
319 return new KerberosTime(subDer);
320 }
321 }
322
323 public static int getDefaultSkew() {
324 int tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW;
325 try {
326 Config c = Config.getInstance();
327 if ((tdiff = c.getDefaultIntValue("clockskew",
328 "libdefaults")) == Integer.MIN_VALUE) { //value is not defined
329 tdiff = Krb5.DEFAULT_ALLOWABLE_CLOCKSKEW;
330 }
331 } catch (KrbException e) {
332 if (DEBUG) {
333 System.out.println("Exception in getting clockskew from " +
334 "Configuration " +
335 "using default value " +
336 e.getMessage());
337 }
338 }
339 return tdiff;
340 }
341
342 public String toString() {
343 return toGeneralizedTimeString();
344 }
345}