1 package org.bouncycastle.asn1.cms; 2 3 import java.text.ParseException; 4 import java.text.SimpleDateFormat; 5 import java.util.Date; 6 import java.util.Locale; 7 import java.util.SimpleTimeZone; 8 9 import org.bouncycastle.asn1.ASN1Choice; 10 import org.bouncycastle.asn1.ASN1GeneralizedTime; 11 import org.bouncycastle.asn1.ASN1Object; 12 import org.bouncycastle.asn1.ASN1Primitive; 13 import org.bouncycastle.asn1.ASN1TaggedObject; 14 import org.bouncycastle.asn1.ASN1UTCTime; 15 import org.bouncycastle.asn1.DERGeneralizedTime; 16 import org.bouncycastle.asn1.DERUTCTime; 17 18 /** 19 * <a href="https://tools.ietf.org/html/rfc5652#section-11.3">RFC 5652</a>: 20 * Dual-mode timestamp format producing either UTCTIme or GeneralizedTime. 21 * <p> 22 * <pre> 23 * Time ::= CHOICE { 24 * utcTime UTCTime, 25 * generalTime GeneralizedTime } 26 * </pre> 27 * <p> 28 * This has a constructor using java.util.Date for input which generates 29 * a {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object if the 30 * supplied datetime is in range 1950-01-01-00:00:00 UTC until 2049-12-31-23:59:60 UTC. 31 * If the datetime value is outside that range, the generated object will be 32 * {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime}. 33 */ 34 public class Time 35 extends ASN1Object 36 implements ASN1Choice 37 { 38 ASN1Primitive time; 39 getInstance( ASN1TaggedObject obj, boolean explicit)40 public static Time getInstance( 41 ASN1TaggedObject obj, 42 boolean explicit) 43 { 44 return getInstance(obj.getObject()); 45 } 46 47 /** 48 * @deprecated use getInstance() 49 */ Time( ASN1Primitive time)50 public Time( 51 ASN1Primitive time) 52 { 53 if (!(time instanceof ASN1UTCTime) 54 && !(time instanceof ASN1GeneralizedTime)) 55 { 56 throw new IllegalArgumentException("unknown object passed to Time"); 57 } 58 59 this.time = time; 60 } 61 62 /** 63 * Creates a time object from a given date - if the date is between 1950 64 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime 65 * is used. 66 * 67 * @param time a date object representing the time of interest. 68 */ Time( Date time)69 public Time( 70 Date time) 71 { 72 SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); 73 SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss"); 74 75 dateF.setTimeZone(tz); 76 77 String d = dateF.format(time) + "Z"; 78 int year = Integer.parseInt(d.substring(0, 4)); 79 80 if (year < 1950 || year > 2049) 81 { 82 this.time = new DERGeneralizedTime(d); 83 } 84 else 85 { 86 this.time = new DERUTCTime(d.substring(2)); 87 } 88 } 89 90 /** 91 * Creates a time object from a given date and locale - if the date is between 1950 92 * and 2049 a UTCTime object is generated, otherwise a GeneralizedTime 93 * is used. You may need to use this constructor if the default locale 94 * doesn't use a Gregorian calender so that the GeneralizedTime produced is compatible with other ASN.1 implementations. 95 * 96 * @param time a date object representing the time of interest. 97 * @param locale an appropriate Locale for producing an ASN.1 GeneralizedTime value. 98 */ Time( Date time, Locale locale)99 public Time( 100 Date time, 101 Locale locale) 102 { 103 SimpleTimeZone tz = new SimpleTimeZone(0, "Z"); 104 SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss", locale); 105 106 dateF.setTimeZone(tz); 107 108 String d = dateF.format(time) + "Z"; 109 int year = Integer.parseInt(d.substring(0, 4)); 110 111 if (year < 1950 || year > 2049) 112 { 113 this.time = new DERGeneralizedTime(d); 114 } 115 else 116 { 117 this.time = new DERUTCTime(d.substring(2)); 118 } 119 } 120 121 /** 122 * Return a Time object from the given object. 123 * <p> 124 * Accepted inputs: 125 * <ul> 126 * <li> null → null 127 * <li> {@link Time} object 128 * <li> {@link org.bouncycastle.asn1.DERUTCTime DERUTCTime} object 129 * <li> {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime} object 130 * </ul> 131 * 132 * @param obj the object we want converted. 133 * @exception IllegalArgumentException if the object cannot be converted. 134 */ getInstance( Object obj)135 public static Time getInstance( 136 Object obj) 137 { 138 if (obj == null || obj instanceof Time) 139 { 140 return (Time)obj; 141 } 142 else if (obj instanceof ASN1UTCTime) 143 { 144 return new Time((ASN1UTCTime)obj); 145 } 146 else if (obj instanceof ASN1GeneralizedTime) 147 { 148 return new Time((ASN1GeneralizedTime)obj); 149 } 150 151 throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName()); 152 } 153 154 /** 155 * Get the date+tine as a String in full form century format. 156 */ getTime()157 public String getTime() 158 { 159 if (time instanceof ASN1UTCTime) 160 { 161 return ((ASN1UTCTime)time).getAdjustedTime(); 162 } 163 else 164 { 165 return ((ASN1GeneralizedTime)time).getTime(); 166 } 167 } 168 169 /** 170 * Get java.util.Date version of date+time. 171 */ getDate()172 public Date getDate() 173 { 174 try 175 { 176 if (time instanceof ASN1UTCTime) 177 { 178 return ((ASN1UTCTime)time).getAdjustedDate(); 179 } 180 else 181 { 182 return ((ASN1GeneralizedTime)time).getDate(); 183 } 184 } 185 catch (ParseException e) 186 { // this should never happen 187 throw new IllegalStateException("invalid date string: " + e.getMessage()); 188 } 189 } 190 191 /** 192 * Produce an object suitable for an ASN1OutputStream. 193 */ toASN1Primitive()194 public ASN1Primitive toASN1Primitive() 195 { 196 return time; 197 } 198 } 199