• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.asn1;
2 
3 import java.io.IOException;
4 import java.text.ParseException;
5 import java.text.SimpleDateFormat;
6 import java.util.Date;
7 import java.util.SimpleTimeZone;
8 
9 import org.bouncycastle.util.Arrays;
10 import org.bouncycastle.util.Strings;
11 
12 /**
13  * UTC time object.
14  */
15 public class DERUTCTime
16     extends ASN1Primitive
17 {
18     private byte[]      time;
19 
20     /**
21      * return an UTC Time from the passed in object.
22      *
23      * @exception IllegalArgumentException if the object cannot be converted.
24      */
getInstance( Object obj)25     public static ASN1UTCTime getInstance(
26         Object  obj)
27     {
28         if (obj == null || obj instanceof ASN1UTCTime)
29         {
30             return (ASN1UTCTime)obj;
31         }
32 
33         if (obj instanceof DERUTCTime)
34         {
35             return new ASN1UTCTime(((DERUTCTime)obj).time);
36         }
37 
38         if (obj instanceof byte[])
39         {
40             try
41             {
42                 return (ASN1UTCTime)fromByteArray((byte[])obj);
43             }
44             catch (Exception e)
45             {
46                 throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
47             }
48         }
49 
50         throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
51     }
52 
53     /**
54      * return an UTC Time from a tagged object.
55      *
56      * @param obj the tagged object holding the object we want
57      * @param explicit true if the object is meant to be explicitly
58      *              tagged false otherwise.
59      * @exception IllegalArgumentException if the tagged object cannot
60      *               be converted.
61      */
getInstance( ASN1TaggedObject obj, boolean explicit)62     public static ASN1UTCTime getInstance(
63         ASN1TaggedObject obj,
64         boolean          explicit)
65     {
66         ASN1Object o = obj.getObject();
67 
68         if (explicit || o instanceof ASN1UTCTime)
69         {
70             return getInstance(o);
71         }
72         else
73         {
74             return new ASN1UTCTime(((ASN1OctetString)o).getOctets());
75         }
76     }
77 
78     /**
79      * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
80      * never encoded. When you're creating one of these objects from scratch, that's
81      * what you want to use, otherwise we'll try to deal with whatever gets read from
82      * the input stream... (this is why the input format is different from the getTime()
83      * method output).
84      * <p>
85      *
86      * @param time the time string.
87      */
DERUTCTime( String time)88     public DERUTCTime(
89         String  time)
90     {
91         this.time = Strings.toByteArray(time);
92         try
93         {
94             this.getDate();
95         }
96         catch (ParseException e)
97         {
98             throw new IllegalArgumentException("invalid date string: " + e.getMessage());
99         }
100     }
101 
102     /**
103      * base constructer from a java.util.date object
104      */
DERUTCTime( Date time)105     public DERUTCTime(
106         Date time)
107     {
108         SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'");
109 
110         dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
111 
112         this.time = Strings.toByteArray(dateF.format(time));
113     }
114 
DERUTCTime( byte[] time)115     DERUTCTime(
116         byte[]  time)
117     {
118         this.time = time;
119     }
120 
121     /**
122      * return the time as a date based on whatever a 2 digit year will return. For
123      * standardised processing use getAdjustedDate().
124      *
125      * @return the resulting date
126      * @exception ParseException if the date string cannot be parsed.
127      */
getDate()128     public Date getDate()
129         throws ParseException
130     {
131         SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz");
132 
133         return dateF.parse(getTime());
134     }
135 
136     /**
137      * return the time as an adjusted date
138      * in the range of 1950 - 2049.
139      *
140      * @return a date in the range of 1950 to 2049.
141      * @exception ParseException if the date string cannot be parsed.
142      */
getAdjustedDate()143     public Date getAdjustedDate()
144         throws ParseException
145     {
146         SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
147 
148         dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
149 
150         return dateF.parse(getAdjustedTime());
151     }
152 
153     /**
154      * return the time - always in the form of
155      *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
156      * <p>
157      * Normally in a certificate we would expect "Z" rather than "GMT",
158      * however adding the "GMT" means we can just use:
159      * <pre>
160      *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
161      * </pre>
162      * To read in the time and get a date which is compatible with our local
163      * time zone.
164      * <p>
165      * <b>Note:</b> In some cases, due to the local date processing, this
166      * may lead to unexpected results. If you want to stick the normal
167      * convention of 1950 to 2049 use the getAdjustedTime() method.
168      */
getTime()169     public String getTime()
170     {
171         String stime = Strings.fromByteArray(time);
172 
173         //
174         // standardise the format.
175         //
176         if (stime.indexOf('-') < 0 && stime.indexOf('+') < 0)
177         {
178             if (stime.length() == 11)
179             {
180                 return stime.substring(0, 10) + "00GMT+00:00";
181             }
182             else
183             {
184                 return stime.substring(0, 12) + "GMT+00:00";
185             }
186         }
187         else
188         {
189             int index = stime.indexOf('-');
190             if (index < 0)
191             {
192                 index = stime.indexOf('+');
193             }
194             String d = stime;
195 
196             if (index == stime.length() - 3)
197             {
198                 d += "00";
199             }
200 
201             if (index == 10)
202             {
203                 return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15);
204             }
205             else
206             {
207                 return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" +  d.substring(15, 17);
208             }
209         }
210     }
211 
212     /**
213      * return a time string as an adjusted date with a 4 digit year. This goes
214      * in the range of 1950 - 2049.
215      */
getAdjustedTime()216     public String getAdjustedTime()
217     {
218         String   d = this.getTime();
219 
220         if (d.charAt(0) < '5')
221         {
222             return "20" + d;
223         }
224         else
225         {
226             return "19" + d;
227         }
228     }
229 
isConstructed()230     boolean isConstructed()
231     {
232         return false;
233     }
234 
encodedLength()235     int encodedLength()
236     {
237         int length = time.length;
238 
239         return 1 + StreamUtil.calculateBodyLength(length) + length;
240     }
241 
encode( ASN1OutputStream out)242     void encode(
243         ASN1OutputStream  out)
244         throws IOException
245     {
246         out.write(BERTags.UTC_TIME);
247 
248         int length = time.length;
249 
250         out.writeLength(length);
251 
252         for (int i = 0; i != length; i++)
253         {
254             out.write((byte)time[i]);
255         }
256     }
257 
asn1Equals( ASN1Primitive o)258     boolean asn1Equals(
259         ASN1Primitive o)
260     {
261         if (!(o instanceof DERUTCTime))
262         {
263             return false;
264         }
265 
266         return Arrays.areEqual(time, ((DERUTCTime)o).time);
267     }
268 
hashCode()269     public int hashCode()
270     {
271         return Arrays.hashCode(time);
272     }
273 
toString()274     public String toString()
275     {
276       return Strings.fromByteArray(time);
277     }
278 }
279