1 module hunt.security.x509.CRLExtensions; 2 3 4 import hunt.security.util.DerInputStream; 5 import hunt.security.util.DerOutputStream; 6 import hunt.security.util.DerValue; 7 import hunt.security.x509.CertAttrSet; 8 import hunt.security.x509.Extension; 9 10 import hunt.stream.Common; 11 12 import hunt.collection; 13 import hunt.Exceptions; 14 15 /** 16 * This class defines the CRL Extensions. 17 * It is used for both CRL Extensions and CRL Entry Extensions, 18 * which are defined are follows: 19 * <pre> 20 * TBSCertList ::= SEQUENCE { 21 * version Version OPTIONAL, -- if present, must be v2 22 * signature AlgorithmIdentifier, 23 * issuer Name, 24 * thisUpdate Time, 25 * nextUpdate Time OPTIONAL, 26 * revokedCertificates SEQUENCE OF SEQUENCE { 27 * userCertificate CertificateSerialNumber, 28 * revocationDate Time, 29 * crlEntryExtensions Extensions OPTIONAL -- if present, must be v2 30 * } OPTIONAL, 31 * crlExtensions [0] EXPLICIT Extensions OPTIONAL -- if present, must be v2 32 * } 33 * </pre> 34 * 35 * @author Hemma Prafullchandra 36 */ 37 class CRLExtensions { 38 39 private Map!(string,Extension) map; 40 private bool unsupportedCritExt = false; 41 42 /** 43 * Default constructor. 44 */ 45 this() { 46 map = new TreeMap!(string,Extension)(); 47 // map = Collections.synchronizedMap( 48 // new TreeMap!(string,Extension)()); 49 } 50 51 /** 52 * Create the object, decoding the values from the passed DER stream. 53 * 54 * @param in the DerInputStream to read the Extension from, i.e. the 55 * sequence of extensions. 56 * @exception CRLException on decoding errors. 57 */ 58 this(DerInputStream inputStream) { 59 this(); 60 initilize(inputStream); 61 } 62 63 // helper routine 64 private void initilize(DerInputStream derStrm) { 65 try { 66 DerInputStream str = derStrm; 67 68 byte nextByte = cast(byte)derStrm.peekByte(); 69 // check for context specific byte 0; skip it 70 if (((nextByte & 0x0c0) == 0x080) && 71 ((nextByte & 0x01f) == 0x000)) { 72 implementationMissing(); 73 // DerValue val = str.getDerValue(); 74 // str = val.data; 75 } 76 77 DerValue[] exts = str.getSequence(5); 78 for (int i = 0; i < exts.length; i++) { 79 Extension ext = new Extension(exts[i]); 80 parseExtension(ext); 81 } 82 } catch (IOException e) { 83 throw new CRLException("Parsing error: " ~ e.toString()); 84 } 85 } 86 87 // private static final Class[] PARAMS = {Boolean.class, Object.class}; 88 89 // Parse the encoded extension 90 private void parseExtension(Extension ext) { 91 implementationMissing(); 92 // try { 93 // Class<?> extClass = OIDMap.getClass(ext.getExtensionId()); 94 // if (extClass is null) { // Unsupported extension 95 // if (ext.isCritical()) 96 // unsupportedCritExt = true; 97 // if (map.put(ext.getExtensionId().toString(), ext) !is null) 98 // throw new CRLException("Duplicate extensions not allowed"); 99 // return; 100 // } 101 // Constructor<?> cons = extClass.getConstructor(PARAMS); 102 // Object[] passed = new Object[] {Boolean.valueOf(ext.isCritical()), 103 // ext.getExtensionValue()}; 104 // CertAttrSet<?> crlExt = (CertAttrSet<?>)cons.newInstance(passed); 105 // if (map.put(crlExt.getName(), (Extension)crlExt) !is null) { 106 // throw new CRLException("Duplicate extensions not allowed"); 107 // } 108 // } catch (InvocationTargetException invk) { 109 // throw new CRLException(invk.getTargetException().getMessage()); 110 // } catch (Exception e) { 111 // throw new CRLException(e.toString()); 112 // } 113 } 114 115 /** 116 * Encode the extensions in DER form to the stream. 117 * 118 * @param stream the DerOutputStream to marshal the contents to. 119 * @param isExplicit the tag indicating whether this is an entry 120 * extension (false) or a CRL extension (true). 121 * @exception CRLException on encoding errors. 122 */ 123 void encode(OutputStream stream, bool isExplicit) 124 { 125 implementationMissing(); 126 // try { 127 // DerOutputStream extOut = new DerOutputStream(); 128 // Collection<Extension> allExts = map.values(); 129 // Object[] objs = allExts.toArray(); 130 131 // for (int i = 0; i < objs.length; i++) { 132 // if (objs[i] instanceof CertAttrSet) 133 // ((CertAttrSet)objs[i]).encode(extOut); 134 // else if (objs[i] instanceof Extension) 135 // ((Extension)objs[i]).encode(extOut); 136 // else 137 // throw new CRLException("Illegal extension object"); 138 // } 139 140 // DerOutputStream seq = new DerOutputStream(); 141 // seq.write(DerValue.tag_Sequence, extOut); 142 143 // DerOutputStream tmp = new DerOutputStream(); 144 // if (isExplicit) 145 // tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, 146 // true, cast(byte)0), seq); 147 // else 148 // tmp = seq; 149 150 // stream.write(tmp.toByteArray()); 151 // } catch (IOException e) { 152 // throw new CRLException("Encoding error: " ~ e.toString()); 153 // } catch (CertificateException e) { 154 // throw new CRLException("Encoding error: " ~ e.toString()); 155 // } 156 } 157 158 /** 159 * Get the extension with this as. 160 * 161 * @param as the identifier string for the extension to retrieve. 162 */ 163 Extension get(string as) { 164 // X509AttributeName attr = new X509AttributeName(as); 165 string name; 166 // string id = attr.getPrefix(); 167 // if (id.equalsIgnoreCase(X509CertImpl.NAME)) { // fully qualified 168 // int index = as.lastIndexOf("."); 169 // name = as.substring(index + 1); 170 // } else 171 // name = as; 172 implementationMissing(); 173 return map.get(name); 174 } 175 176 /** 177 * Set the extension value with this as. 178 * 179 * @param as the identifier string for the extension to set. 180 * @param obj the Object to set the extension identified by the 181 * as. 182 */ 183 void set(string as, Object obj) { 184 map.put(as, cast(Extension)obj); 185 } 186 187 /** 188 * Delete the extension value with this as. 189 * 190 * @param as the identifier string for the extension to delete. 191 */ 192 void remove(string as) { 193 map.remove(as); 194 } 195 196 /** 197 * Return an enumeration of the extensions. 198 * @return an enumeration of the extensions in this CRL. 199 */ 200 Enumeration!Extension getElements() { 201 return Collections.enumeration(map.values()); 202 } 203 204 /** 205 * Return a collection view of the extensions. 206 * @return a collection view of the extensions in this CRL. 207 */ 208 Extension[] getAllExtensions() { 209 return map.values(); 210 } 211 212 /** 213 * Return true if a critical extension is found that is 214 * not supported, otherwise return false. 215 */ 216 bool hasUnsupportedCriticalExtension() { 217 return unsupportedCritExt; 218 } 219 220 /** 221 * Compares this CRLExtensions for equality with the specified 222 * object. If the <code>other</code> object is an 223 * <code>instanceof</code> <code>CRLExtensions</code>, then 224 * all the entries are compared with the entries from this. 225 * 226 * @param other the object to test for equality with this CRLExtensions. 227 * @return true iff all the entries match that of the Other, 228 * false otherwise. 229 */ 230 override bool opEquals(Object other) { 231 if (this is other) 232 return true; 233 CRLExtensions crlExtensions = cast(CRLExtensions)other; 234 if (crlExtensions is null) 235 return false; 236 // Collection<Extension> otherC = 237 // ((CRLExtensions)other).getAllExtensions(); 238 Extension[] objs = crlExtensions.getAllExtensions(); 239 240 size_t len = objs.length; 241 if (len != map.size()) 242 return false; 243 244 Extension otherExt, thisExt; 245 string key = null; 246 for (int i = 0; i < len; i++) { 247 implementationMissing(); 248 // CertAttrSet!string certAttrSet = cast(CertAttrSet!string)objs[i]; 249 // if (certAttrSet !is null) 250 // key = certAttrSet.getName(); 251 // otherExt = objs[i]; 252 // if (key is null) 253 // key = otherExt.getExtensionId().toString(); 254 // thisExt = map.get(key); 255 // if (thisExt is null) 256 // return false; 257 // if (! thisExt.opEquals(otherExt)) 258 // return false; 259 } 260 return true; 261 } 262 263 /** 264 * Returns a hashcode value for this CRLExtensions. 265 * 266 * @return the hashcode value. 267 */ 268 override size_t toHash() @trusted nothrow { 269 return map.toHash(); 270 } 271 272 /** 273 * Returns a string representation of this <tt>CRLExtensions</tt> object 274 * in the form of a set of entries, enclosed in braces and separated 275 * by the ASCII characters "<tt>, </tt>" (comma and space). 276 * <p>Overrides to <tt>toString</tt> method of <tt>Object</tt>. 277 * 278 * @return a string representation of this CRLExtensions. 279 */ 280 override string toString() { 281 return map.toString(); 282 } 283 }