1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.asn1;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.io.IOException;
4b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.text.ParseException;
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.text.SimpleDateFormat;
6b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.util.Date;
7b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport java.util.SimpleTimeZone;
8c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport java.util.TimeZone;
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
104c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstromimport org.bouncycastle.util.Arrays;
114c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstromimport org.bouncycastle.util.Strings;
124c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/**
14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * Generalized time object.
15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */
16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic class DERGeneralizedTime
174c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    extends ASN1Primitive
18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
194c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    private byte[]      time;
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
22b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return a generalized time from the passed in object
23b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalArgumentException if the object cannot be converted.
25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
264c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    public static ASN1GeneralizedTime getInstance(
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Object  obj)
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
294c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        if (obj == null || obj instanceof ASN1GeneralizedTime)
304c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        {
314c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            return (ASN1GeneralizedTime)obj;
324c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        }
334c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
344c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        if (obj instanceof DERGeneralizedTime)
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
364c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            return new ASN1GeneralizedTime(((DERGeneralizedTime)obj).time);
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        if (obj instanceof byte[])
4070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        {
4170c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            try
4270c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
4370c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                return (ASN1GeneralizedTime)fromByteArray((byte[])obj);
4470c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
4570c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            catch (Exception e)
4670c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            {
4770c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom                throw new IllegalArgumentException("encoding error in getInstance: " + e.toString());
4870c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom            }
4970c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom        }
5070c8287138e69a98c2f950036f9f703ee37228c8Brian Carlstrom
51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return a Generalized Time object from a tagged object.
56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param obj the tagged object holding the object we want
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param explicit true if the object is meant to be explicitly
59b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *              tagged false otherwise.
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @exception IllegalArgumentException if the tagged object cannot
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *               be converted.
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
634c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    public static ASN1GeneralizedTime getInstance(
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        ASN1TaggedObject obj,
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        boolean          explicit)
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
674c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        ASN1Primitive o = obj.getObject();
686e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom
696e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom        if (explicit || o instanceof DERGeneralizedTime)
706e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom        {
716e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            return getInstance(o);
726e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom        }
736e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom        else
746e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom        {
754c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            return new ASN1GeneralizedTime(((ASN1OctetString)o).getOctets());
766e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom        }
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
80c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * for local time, or Z+-HHMM on the end, for difference between local
82c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * time and UTC time. The fractional second amount f must consist of at
83c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * least one number with trailing zeroes removed.
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param time the time string.
86c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * @exception IllegalArgumentException if String is an illegal format.
87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public DERGeneralizedTime(
89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String  time)
90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
914c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        this.time = Strings.toByteArray(time);
92c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        try
93c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
94c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            this.getDate();
95c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
96c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        catch (ParseException e)
97c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
98c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            throw new IllegalArgumentException("invalid date string: " + e.getMessage());
99c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
101b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
1034c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom     * base constructor from a java.util.date object
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public DERGeneralizedTime(
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        Date time)
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        dateF.setTimeZone(new SimpleTimeZone(0,"Z"));
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
1124c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        this.time = Strings.toByteArray(dateF.format(time));
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
114b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
115b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    DERGeneralizedTime(
116b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[]  bytes)
117b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
1184c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        this.time = bytes;
119b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
120b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
121b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
122c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * Return the time.
123c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     * @return The time string as it appeared in the encoded object.
124c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom     */
125c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public String getTimeString()
126c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
1274c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return Strings.fromByteArray(time);
128c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
129c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
130c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    /**
131b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return the time - always in the form of
132b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *  YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
133b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * <p>
134b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Normally in a certificate we would expect "Z" rather than "GMT",
135b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * however adding the "GMT" means we can just use:
136b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * <pre>
137b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
138b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * </pre>
139b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * To read in the time and get a date which is compatible with our local
140b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * time zone.
141b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
142b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public String getTime()
143b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
1444c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        String stime = Strings.fromByteArray(time);
1454c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
146b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        //
147b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        // standardise the format.
148b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        //
1494c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        if (stime.charAt(stime.length() - 1) == 'Z')
150b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
1514c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            return stime.substring(0, stime.length() - 1) + "GMT+00:00";
152b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
153b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
154b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
1554c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            int signPos = stime.length() - 5;
1564c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            char sign = stime.charAt(signPos);
157b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (sign == '-' || sign == '+')
158b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
1594c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                return stime.substring(0, signPos)
160b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    + "GMT"
1614c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    + stime.substring(signPos, signPos + 3)
162b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                    + ":"
1634c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    + stime.substring(signPos + 3);
164b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
165b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
166b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
1674c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                signPos = stime.length() - 3;
1684c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                sign = stime.charAt(signPos);
169b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                if (sign == '-' || sign == '+')
170b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                {
1714c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    return stime.substring(0, signPos)
172b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        + "GMT"
1734c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                        + stime.substring(signPos)
174b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                        + ":00";
175b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                }
176b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
177b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
1784c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return stime + calculateGMTOffset();
179c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
180b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
181c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private String calculateGMTOffset()
182c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
183c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        String sign = "+";
184c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        TimeZone timeZone = TimeZone.getDefault();
185c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int offset = timeZone.getRawOffset();
186c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (offset < 0)
187c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
188c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            sign = "-";
189c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            offset = -offset;
190c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
191c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int hours = offset / (60 * 60 * 1000);
192c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);
193c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
194c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        try
195c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
196c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate()))
197c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
198c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                hours += sign.equals("+") ? 1 : -1;
199c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
200c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
201c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        catch (ParseException e)
202c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
203c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // we'll do our best and ignore daylight savings
204c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
205c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
206c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return "GMT" + sign + convert(hours) + ":" + convert(minutes);
207c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
208c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
209c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private String convert(int time)
210c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
211c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (time < 10)
212c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
213c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            return "0" + time;
214c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
215c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
216c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return Integer.toString(time);
217b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
218b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
219c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    public Date getDate()
220b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws ParseException
221b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
222b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        SimpleDateFormat dateF;
2234c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        String stime = Strings.fromByteArray(time);
2244c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        String d = stime;
225b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
2264c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        if (stime.endsWith("Z"))
227b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
228c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (hasFractionalSeconds())
229c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
230c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'");
231c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
232c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            else
233c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
234c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
235c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
236c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
237c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
238c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
2394c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        else if (stime.indexOf('-') > 0 || stime.indexOf('+') > 0)
240c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
241c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            d = this.getTime();
242c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (hasFractionalSeconds())
2436e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            {
244c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSz");
245c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
246c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            else
247c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
248c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
249c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
250c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
251c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
252b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
253b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        else
254b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
255c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (hasFractionalSeconds())
256c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
257c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
258c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
259c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            else
260c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
261c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                dateF = new SimpleDateFormat("yyyyMMddHHmmss");
262c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
263c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
264c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
265c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        }
266c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
267c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (hasFractionalSeconds())
268c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        {
269c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            // java misinterprets extra digits as being milliseconds...
270c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            String frac = d.substring(14);
271c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            int    index;
272c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            for (index = 1; index < frac.length(); index++)
273c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
274c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                char ch = frac.charAt(index);
275c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                if (!('0' <= ch && ch <= '9'))
276c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                {
277c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                    break;
278c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                }
279c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
2806e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom
281c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            if (index - 1 > 3)
282c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            {
283c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                frac = frac.substring(0, 4) + frac.substring(index);
284c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom                d = d.substring(0, 14) + frac;
285c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom            }
2866e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            else if (index - 1 == 1)
2876e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            {
2886e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                frac = frac.substring(0, index) + "00" + frac.substring(index);
2896e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                d = d.substring(0, 14) + frac;
2906e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            }
2916e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            else if (index - 1 == 2)
2926e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            {
2936e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                frac = frac.substring(0, index) + "0" + frac.substring(index);
2946e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom                d = d.substring(0, 14) + frac;
2956e736056d64d0e33b26cf9f7c4e351b496241fdeBrian Carlstrom            }
296b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
297c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
298c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return dateF.parse(d);
299b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
300c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
301c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    private boolean hasFractionalSeconds()
302c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    {
3034c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        for (int i = 0; i != time.length; i++)
3044c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        {
3054c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            if (time[i] == '.')
3064c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            {
3074c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                if (i == 14)
3084c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                {
3094c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                    return true;
3104c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom                }
3114c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom            }
3124c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        }
3134c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return false;
314c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    }
315c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom
3164c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    boolean isConstructed()
317b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
3184c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return false;
3194c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    }
320b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3214c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    int encodedLength()
3224c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    {
3234c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        int length = time.length;
324b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3254c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return 1 + StreamUtil.calculateBodyLength(length) + length;
326b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
327b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
328b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    void encode(
3294c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        ASN1OutputStream  out)
330b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
331b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
3324c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        out.writeEncoded(BERTags.GENERALIZED_TIME, time);
333b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
334b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
335c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom    boolean asn1Equals(
3364c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        ASN1Primitive  o)
337b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
338c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        if (!(o instanceof DERGeneralizedTime))
339b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
340b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            return false;
341b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
342b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
3434c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return Arrays.areEqual(time, ((DERGeneralizedTime)o).time);
344b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
345b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
346b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    public int hashCode()
347b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
3484c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom        return Arrays.hashCode(time);
349b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
350b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
351