1 module hunt.security.x509.CertificateValidity; 2 3 4 import hunt.security.x509.CertAttrSet; 5 6 import hunt.security.util.DerValue; 7 import hunt.security.util.DerInputStream; 8 import hunt.security.util.DerOutputStream; 9 10 import hunt.collection.Enumeration; 11 12 import hunt.stream.Common; 13 import hunt.Exceptions; 14 import hunt.text.Common; 15 16 import std.datetime; 17 18 /** 19 * This class defines the interval for which the certificate is valid. 20 * 21 * @author Amit Kapoor 22 * @author Hemma Prafullchandra 23 * @see CertAttrSet 24 */ 25 class CertificateValidity : CertAttrSet!(string, Date) { 26 /** 27 * Identifier for this attribute, to be used with the 28 * get, set, delete methods of Certificate, x509 type. 29 */ 30 enum string IDENT = "x509.info.validity"; 31 /** 32 * Sub attributes name for this CertAttrSet. 33 */ 34 enum string NAME = "validity"; 35 enum string NOT_BEFORE = "notBefore"; 36 enum string NOT_AFTER = "notAfter"; 37 private enum long YR_2050 = 2524636800000L; 38 39 // Private data members 40 private Date notBefore; 41 private Date notAfter; 42 43 // Returns the first time the certificate is valid. 44 private Date getNotBefore() { 45 // return (new Date(notBefore.getTime())); 46 return notBefore; 47 } 48 49 // Returns the last time the certificate is valid. 50 private Date getNotAfter() { 51 // return (new Date(notAfter.getTime())); 52 return notAfter; 53 } 54 55 // Construct the class from the DerValue 56 private void construct(DerValue derVal) { 57 if (derVal.tag != DerValue.tag_Sequence) { 58 throw new IOException("Invalid encoded CertificateValidity, " ~ 59 "starting sequence tag missing."); 60 } 61 // check if UTCTime encoded or GeneralizedTime 62 // if (derVal.data.available() == 0) 63 // throw new IOException("No data encoded for CertificateValidity"); 64 65 // DerInputStream derIn = new DerInputStream(derVal.toByteArray()); 66 // DerValue[] seq = derIn.getSequence(2); 67 // if (seq.length != 2) 68 // throw new IOException("Invalid encoding for CertificateValidity"); 69 70 // if (seq[0].tag == DerValue.tag_UtcTime) { 71 // notBefore = derVal.data.getUTCTime(); 72 // } else if (seq[0].tag == DerValue.tag_GeneralizedTime) { 73 // notBefore = derVal.data.getGeneralizedTime(); 74 // } else { 75 // throw new IOException("Invalid encoding for CertificateValidity"); 76 // } 77 78 // if (seq[1].tag == DerValue.tag_UtcTime) { 79 // notAfter = derVal.data.getUTCTime(); 80 // } else if (seq[1].tag == DerValue.tag_GeneralizedTime) { 81 // notAfter = derVal.data.getGeneralizedTime(); 82 // } else { 83 // throw new IOException("Invalid encoding for CertificateValidity"); 84 // } 85 implementationMissing(); 86 } 87 88 /** 89 * Default constructor for the class. 90 */ 91 this() { } 92 93 /** 94 * The default constructor for this class for the specified interval. 95 * 96 * @param notBefore the date and time before which the certificate 97 * is not valid. 98 * @param notAfter the date and time after which the certificate is 99 * not valid. 100 */ 101 this(Date notBefore, Date notAfter) { 102 this.notBefore = notBefore; 103 this.notAfter = notAfter; 104 } 105 106 /** 107 * Create the object, decoding the values from the passed DER stream. 108 * 109 * @param stream the DerInputStream to read the CertificateValidity from. 110 * @exception IOException on decoding errors. 111 */ 112 this(DerInputStream stream) { 113 DerValue derVal = stream.getDerValue(); 114 construct(derVal); 115 } 116 117 /** 118 * Return the validity period as user readable string. 119 */ 120 override string toString() { 121 if (notBefore == Date.init || notAfter == Date.init) 122 return ""; 123 return ("Validity: [From: " ~ notBefore.toString() ~ 124 ",\n To: " ~ notAfter.toString() ~ "]"); 125 } 126 127 /** 128 * Encode the CertificateValidity period in DER form to the stream. 129 * 130 * @param stream the OutputStream to marshal the contents to. 131 * @exception IOException on errors. 132 */ 133 void encode(OutputStream stream) { 134 135 // in cases where default constructor is used check for 136 // null values 137 if (notBefore == Date.init || notAfter == Date.init) { 138 throw new IOException("CertAttrSet:CertificateValidity:" ~ 139 " null values to encode.\n"); 140 } 141 DerOutputStream pair = new DerOutputStream(); 142 143 // if (notBefore.getTime() < YR_2050) { 144 // pair.putUTCTime(notBefore); 145 // } else 146 // pair.putGeneralizedTime(notBefore); 147 148 // if (notAfter.getTime() < YR_2050) { 149 // pair.putUTCTime(notAfter); 150 // } else { 151 // pair.putGeneralizedTime(notAfter); 152 // } 153 implementationMissing(); 154 DerOutputStream seq = new DerOutputStream(); 155 seq.write(DerValue.tag_Sequence, pair); 156 157 stream.write(seq.toByteArray()); 158 } 159 160 /** 161 * Set the attribute value. 162 */ 163 void set(string name, Date obj) { 164 implementationMissing(); 165 // if (!(obj instanceof Date)) { 166 // throw new IOException("Attribute must be of type Date."); 167 // } 168 // if (name.equalsIgnoreCase(NOT_BEFORE)) { 169 // notBefore = (Date)obj; 170 // } else if (name.equalsIgnoreCase(NOT_AFTER)) { 171 // notAfter = (Date)obj; 172 // } else { 173 // throw new IOException("Attribute name not recognized by " ~ 174 // "CertAttrSet: CertificateValidity."); 175 // } 176 } 177 178 /** 179 * Get the attribute value. 180 */ 181 Date get(string name) { 182 if (name.equalsIgnoreCase(NOT_BEFORE)) { 183 return (getNotBefore()); 184 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 185 return (getNotAfter()); 186 } else { 187 throw new IOException("Attribute name not recognized by " ~ 188 "CertAttrSet: CertificateValidity."); 189 } 190 } 191 192 /** 193 * Delete the attribute value. 194 */ 195 void remove(string name) { 196 if (name.equalsIgnoreCase(NOT_BEFORE)) { 197 notBefore = Date.init; 198 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 199 notAfter = Date.init; 200 } else { 201 throw new IOException("Attribute name not recognized by " ~ 202 "CertAttrSet: CertificateValidity."); 203 } 204 } 205 206 /** 207 * Return an enumeration of names of attributes existing within this 208 * attribute. 209 */ 210 Enumeration!string getElements() { 211 // AttributeNameEnumeration elements = new AttributeNameEnumeration(); 212 // elements.addElement(NOT_BEFORE); 213 // elements.addElement(NOT_AFTER); 214 215 // return (elements.elements()); 216 implementationMissing(); 217 return null; 218 } 219 220 /** 221 * Return the name of this attribute. 222 */ 223 string getName() { 224 return (NAME); 225 } 226 227 /** 228 * Verify that the current time is within the validity period. 229 * 230 * @exception CertificateExpiredException if the certificate has expired. 231 * @exception CertificateNotYetValidException if the certificate is not 232 * yet valid. 233 */ 234 void valid() { 235 Date now = cast(Date)(Clock.currTime); 236 valid(now); 237 } 238 239 /** 240 * Verify that the passed time is within the validity period. 241 * @param now the Date against which to compare the validity 242 * period. 243 * 244 * @exception CertificateExpiredException if the certificate has expired 245 * with respect to the <code>Date</code> supplied. 246 * @exception CertificateNotYetValidException if the certificate is not 247 * yet valid with respect to the <code>Date</code> supplied. 248 * 249 */ 250 void valid(Date now) { 251 /* 252 * we use the internal Dates rather than the passed in Date 253 * because someone could override the Date methods after() 254 * and before() to do something entirely different. 255 */ 256 if (notBefore > now) { 257 throw new CertificateNotYetValidException("NotBefore: " ~ 258 notBefore.toString()); 259 } 260 if (notAfter < now) { 261 throw new CertificateExpiredException("NotAfter: " ~ 262 notAfter.toString()); 263 } 264 } 265 }