1 module hunt.security.x509.AlgorithmId;
2 
3 import hunt.security.AlgorithmParameters;
4 
5 import hunt.security.util.DerEncoder;
6 import hunt.security.util.DerInputStream;
7 import hunt.security.util.DerOutputStream;
8 import hunt.security.util.DerValue;
9 import hunt.security.util.ObjectIdentifier;
10 
11 import hunt.collection;
12 import hunt.stream.Common;
13 
14 import hunt.Exceptions;
15 import hunt.text.Common;
16 import hunt.util.StringBuilder;
17 
18 import std.string;
19 
20 
21 /**
22  * This class identifies algorithms, such as cryptographic transforms, each
23  * of which may be associated with parameters.  Instances of this base class
24  * are used when this runtime environment has no special knowledge of the
25  * algorithm type, and may also be used in other cases.  Equivalence is
26  * defined according to OID and (where relevant) parameters.
27  *
28  * <P>Subclasses may be used, for example when when the algorithm ID has
29  * associated parameters which some code (e.g. code using keys) needs
30  * to have parsed.  Two examples of such algorithms are Diffie-Hellman key
31  * exchange, and the Digital Signature Standard Algorithm (DSS/DSA).
32  *
33  * <P>The OID constants defined in this class correspond to some widely
34  * used algorithms, for which conventional string names have been defined.
35  * This class is not a general repository for OIDs, or for such string names.
36  * Note that the mappings between algorithm IDs and algorithm names is
37  * not one-to-one.
38  *
39  *
40  * @author David Brownell
41  * @author Amit Kapoor
42  * @author Hemma Prafullchandra
43  */
44 class AlgorithmId : DerEncoder {
45 
46     /** use serialVersionUID from JDK 1.1. for interoperability */
47     // private static final long serialVersionUID = 7205873507486557157L;
48 
49     /**
50      * The object identitifer being used for this algorithm.
51      */
52     private ObjectIdentifier algid;
53 
54     // The (parsed) parameters
55     private AlgorithmParameters algParams;
56     private bool constructedFromDer = true;
57 
58     /**
59      * Parameters for this algorithm.  These are stored in unparsed
60      * DER-encoded form; subclasses can be made to automaticaly parse
61      * them so there is fast access to these parameters.
62      */
63     protected DerValue          params;
64 
65 
66     /**
67      * Constructs an algorithm ID which will be initialized
68      * separately, for example by deserialization.
69      * @deprecated use one of the other constructors.
70      */
71     // @Deprecated
72     // this() { }
73 
74     /**
75      * Constructs a parameterless algorithm ID.
76      *
77      * @param oid the identifier for the algorithm
78      */
79     this(ObjectIdentifier oid) {
80         algid = oid;
81     }
82 
83     /**
84      * Constructs an algorithm ID with algorithm parameters.
85      *
86      * @param oid the identifier for the algorithm.
87      * @param algparams the associated algorithm parameters.
88      */
89     this(ObjectIdentifier oid, AlgorithmParameters algparams) {
90         algid = oid;
91         algParams = algparams;
92         constructedFromDer = false;
93     }
94 
95     private this(ObjectIdentifier oid, DerValue params){
96         this.algid = oid;
97         this.params = params;
98         if (this.params !is null) {
99             decodeParams();
100         }
101     }
102 
103     protected void decodeParams() {
104         string algidString = algid.toString();
105         try {
106             algParams = AlgorithmParameters.getInstance(algidString);
107         } catch (NoSuchAlgorithmException e) {
108             /*
109              * This algorithm parameter type is not supported, so we cannot
110              * parse the parameters.
111              */
112             algParams = null;
113             return;
114         }
115 
116         // Decode (parse) the parameters
117         try {
118             algParams.initilize(params.toByteArray());
119         } catch (IOException e) {
120             if (null != e.msg && e.msg.startsWith("Unknown named curve: ")) {
121                 // named curve not supported
122                 algParams = null;
123                 return;
124             }
125             throw e;
126         }
127     }
128 
129     /**
130      * Marshal a DER-encoded "AlgorithmID" sequence on the DER stream.
131      */
132     final void encode(DerOutputStream o) {
133         derEncode(o);
134     }
135 
136     /**
137      * DER encode this object onto an output stream.
138      * Implements the <code>DerEncoder</code> interface.
139      *
140      * @param outputStream
141      * the output stream on which to write the DER encoding.
142      *
143      * @exception IOException on encoding error.
144      */
145     void derEncode (OutputStream outputStream) {
146         DerOutputStream bytes = new DerOutputStream();
147         DerOutputStream tmp = new DerOutputStream();
148 
149         algid.encode(bytes);
150 
151         // Setup params from algParams since no DER encoding is given
152         if (constructedFromDer == false) {
153             if (algParams !is null) {
154                 params = new DerValue(algParams.getEncoded());
155             } else {
156                 params = null;
157             }
158         }
159         if (params is null) {
160             // Changes backed out for compatibility with Solaris
161 
162             // Several AlgorithmId should omit the whole parameter part when
163             // it's NULL. They are ---
164             // rfc3370 2.1: Implementations SHOULD generate SHA-1
165             // AlgorithmIdentifiers with absent parameters.
166             // rfc3447 C1: When id-sha1, id-sha224, id-sha256, id-sha384 and
167             // id-sha512 are used in an AlgorithmIdentifier the parameters
168             // (which are optional) SHOULD be omitted.
169             // rfc3279 2.3.2: The id-dsa algorithm syntax includes optional
170             // domain parameters... When omitted, the parameters component
171             // MUST be omitted entirely
172             // rfc3370 3.1: When the id-dsa-with-sha1 algorithm identifier
173             // is used, the AlgorithmIdentifier parameters field MUST be absent.
174             /*if (
175                 algid.equals((Object)SHA_oid) ||
176                 algid.equals((Object)SHA224_oid) ||
177                 algid.equals((Object)SHA256_oid) ||
178                 algid.equals((Object)SHA384_oid) ||
179                 algid.equals((Object)SHA512_oid) ||
180                 algid.equals((Object)DSA_oid) ||
181                 algid.equals((Object)sha1WithDSA_oid)) {
182                 ; // no parameter part encoded
183             } else {
184                 bytes.putNull();
185             }*/
186             bytes.putNull();
187         } else {
188             bytes.putDerValue(params);
189         }
190         tmp.write(DerValue.tag_Sequence, bytes);
191         outputStream.write(tmp.toByteArray());
192     }
193 
194 
195     /**
196      * Returns the DER-encoded X.509 AlgorithmId as a byte array.
197      */
198     final byte[] encode() {
199         DerOutputStream outputStream = new DerOutputStream();
200         derEncode(outputStream);
201         return outputStream.toByteArray();
202     }
203 
204     /**
205      * Returns the ISO OID for this algorithm.  This is usually converted
206      * to a string and used as part of an algorithm name, for example
207      * "OID.1.3.14.3.2.13" style notation.  Use the <code>getName</code>
208      * call when you do not need to ensure cross-system portability
209      * of algorithm names, or need a user friendly name.
210      */
211     final ObjectIdentifier getOID () {
212         return algid;
213     }
214 
215     /**
216      * Returns a name for the algorithm which may be more intelligible
217      * to humans than the algorithm's OID, but which won't necessarily
218      * be comprehensible on other systems.  For example, this might
219      * return a name such as "MD5withRSA" for a signature algorithm on
220      * some systems.  It also returns names like "OID.1.2.3.4", when
221      * no particular name for the algorithm is known.
222      */
223     string getName() {
224         string algName = nameTable.get(algid);
225         if (algName !is null) {
226             return algName;
227         }
228         if ((params !is null) && algid.opEquals(cast(Object)specifiedWithECDSA_oid)) {
229             try {
230                 AlgorithmId paramsId =
231                         AlgorithmId.parse(new DerValue(getEncodedParams()));
232                 string paramsName = paramsId.getName();
233                 algName = makeSigAlg(paramsName, "EC");
234             } catch (IOException e) {
235                 // ignore
236             }
237         }
238         return (algName is null) ? algid.toString() : algName;
239     }
240 
241     AlgorithmParameters getParameters() {
242         return algParams;
243     }
244 
245     /**
246      * Returns the DER encoded parameter, which can then be
247      * used to initialize java.security.AlgorithmParamters.
248      *
249      * @return DER encoded parameters, or null not present.
250      */
251     byte[] getEncodedParams() {
252         return (params is null) ? null : params.toByteArray();
253     }
254 
255     /**
256      * Returns true iff the argument indicates the same algorithm
257      * with the same parameters.
258      */
259     bool equals(AlgorithmId other) {
260         bool paramsEqual =
261           (params is null ? other.params is null : params.opEquals(other.params));
262         return algid == other.algid && paramsEqual;
263     }
264 
265     /**
266      * Compares this AlgorithmID to another.  If algorithm parameters are
267      * available, they are compared.  Otherwise, just the object IDs
268      * for the algorithm are compared.
269      *
270      * @param other preferably an AlgorithmId, else an ObjectIdentifier
271      */
272     override bool opEquals(Object other) {
273         if (this is other) {
274             return true;
275         }
276         AlgorithmId aid = cast(AlgorithmId) other;
277         if (aid !is null) {
278             return equals(aid);
279         } 
280         ObjectIdentifier oid = cast(ObjectIdentifier) other;
281         if (oid !is null) {
282             return equals(oid);
283         } else {
284             return false;
285         }
286     }
287 
288     /**
289      * Compares two algorithm IDs for equality.  Returns true iff
290      * they are the same algorithm, ignoring algorithm parameters.
291      */
292     final bool equals(ObjectIdentifier id) {
293         return algid == id;
294     }
295 
296     /**
297      * Returns a hashcode for this AlgorithmId.
298      *
299      * @return a hashcode for this AlgorithmId.
300      */
301     override size_t toHash() @trusted nothrow {
302         try
303         {
304             StringBuilder sbuf = new StringBuilder();
305             sbuf.append(algid.toString());
306             sbuf.append(paramsToString());
307             return sbuf.toString().hashOf();
308         }
309         catch(Exception)
310         {
311             return 0;
312         }
313     }
314 
315     /**
316      * Provides a human-readable description of the algorithm parameters.
317      * This may be redefined by subclasses which parse those parameters.
318      */
319     protected string paramsToString() {
320         if (params is null) {
321             return "";
322         } else if (algParams !is null) {
323             return algParams.toString();
324         } else {
325             return ", params unparsed";
326         }
327     }
328 
329     /**
330      * Returns a string describing the algorithm and its parameters.
331      */
332     override string toString() {
333         return getName() ~ paramsToString();
334     }
335 
336     /**
337      * Parse (unmarshal) an ID from a DER sequence input value.  This form
338      * parsing might be used when expanding a value which has already been
339      * partially unmarshaled as a set or sequence member.
340      *
341      * @exception IOException on error.
342      * @param val the input value, which contains the algid and, if
343      *          there are any parameters, those parameters.
344      * @return an ID for the algorithm.  If the system is configured
345      *          appropriately, this may be an instance of a class
346      *          with some kind of special support for this algorithm.
347      *          In that case, you may "narrow" the type of the ID.
348      */
349     static AlgorithmId parse(DerValue val) {
350         if (val.tag != DerValue.tag_Sequence) {
351             throw new IOException("algid parse error, not a sequence");
352         }
353 
354         /*
355          * Get the algorithm ID and any parameters.
356          */
357         ObjectIdentifier        algid;
358         DerValue                params;
359         DerInputStream          inputStream; //  = val.toDerInputStream();
360         // inputStream = new DerInputStream(val.toByteArray);
361 
362         implementationMissing(false);
363 
364         // algid = new ObjectIdentifier(inputStream); // inputStream.getOID();
365         // if (inputStream.available() == 0) {
366         //     params = null;
367         // } else {
368         //     params = inputStream.getDerValue();
369         //     if (params.tag == DerValue.tag_Null) {
370         //         if (params.length() != 0) {
371         //             throw new IOException("invalid NULL");
372         //         }
373         //         params = null;
374         //     }
375         //     if (inputStream.available() != 0) {
376         //         throw new IOException("Invalid AlgorithmIdentifier: extra data");
377         //     }
378         // }
379 
380         // return new AlgorithmId(algid, params);
381         return null;
382     }
383 
384     /**
385      * Returns one of the algorithm IDs most commonly associated
386      * with this algorithm name.
387      *
388      * @param algname the name being used
389      * @deprecated use the short get form of this method.
390      * @exception NoSuchAlgorithmException on error.
391      */
392     // @Deprecated
393     // static AlgorithmId getAlgorithmId(string algname) {
394     //     return get(algname);
395     // }
396 
397     /**
398      * Returns one of the algorithm IDs most commonly associated
399      * with this algorithm name.
400      *
401      * @param algname the name being used
402      * @exception NoSuchAlgorithmException on error.
403      */
404     static AlgorithmId get(string algname) {
405         ObjectIdentifier oid;
406         try {
407             oid = algOID(algname);
408         } catch (IOException ioe) {
409             throw new NoSuchAlgorithmException
410                 ("Invalid ObjectIdentifier " ~ algname);
411         }
412 
413         if (oid is null) {
414             throw new NoSuchAlgorithmException
415                 ("unrecognized algorithm name: " ~ algname);
416         }
417         return new AlgorithmId(oid);
418     }
419 
420     /**
421      * Returns one of the algorithm IDs most commonly associated
422      * with this algorithm parameters.
423      *
424      * @param algparams the associated algorithm parameters.
425      * @exception NoSuchAlgorithmException on error.
426      */
427     static AlgorithmId get(AlgorithmParameters algparams) {
428         ObjectIdentifier oid;
429         string algname = algparams.getAlgorithm();
430         try {
431             oid = algOID(algname);
432         } catch (IOException ioe) {
433             throw new NoSuchAlgorithmException
434                 ("Invalid ObjectIdentifier " ~ algname);
435         }
436         if (oid is null) {
437             throw new NoSuchAlgorithmException
438                 ("unrecognized algorithm name: " ~ algname);
439         }
440         return new AlgorithmId(oid, algparams);
441     }
442 
443     /*
444      * Translates from some common algorithm names to the
445      * OID with which they're usually associated ... this mapping
446      * is the reverse of the one below, except in those cases
447      * where synonyms are supported or where a given algorithm
448      * is commonly associated with multiple OIDs.
449      *
450      * XXX This method needs to be enhanced so that we can also pass the
451      * scope of the algorithm name to it, e.g., the algorithm name "DSA"
452      * may have a different OID when used as a "Signature" algorithm than when
453      * used as a "KeyPairGenerator" algorithm.
454      */
455     private static ObjectIdentifier algOID(string name) {
456         // See if algname is in printable OID ("dot-dot") notation
457         if (name.indexOf('.') != -1) {
458             if (name.startsWith("OID.")) {
459                 return new ObjectIdentifier(name.substring("OID.".length));
460             } else {
461                 return new ObjectIdentifier(name);
462             }
463         }
464 
465         // Digesting algorithms
466         if (name.equalsIgnoreCase("MD5")) {
467             return AlgorithmId.MD5_oid;
468         }
469         if (name.equalsIgnoreCase("MD2")) {
470             return AlgorithmId.MD2_oid;
471         }
472         if (name.equalsIgnoreCase("SHA") || name.equalsIgnoreCase("SHA1")
473             || name.equalsIgnoreCase("SHA-1")) {
474             return AlgorithmId.SHA_oid;
475         }
476         if (name.equalsIgnoreCase("SHA-256") ||
477             name.equalsIgnoreCase("SHA256")) {
478             return AlgorithmId.SHA256_oid;
479         }
480         if (name.equalsIgnoreCase("SHA-384") ||
481             name.equalsIgnoreCase("SHA384")) {
482             return AlgorithmId.SHA384_oid;
483         }
484         if (name.equalsIgnoreCase("SHA-512") ||
485             name.equalsIgnoreCase("SHA512")) {
486             return AlgorithmId.SHA512_oid;
487         }
488         if (name.equalsIgnoreCase("SHA-224") ||
489             name.equalsIgnoreCase("SHA224")) {
490             return AlgorithmId.SHA224_oid;
491         }
492 
493         // Various key algorithms
494         if (name.equalsIgnoreCase("RSA")) {
495             return AlgorithmId.RSAEncryption_oid;
496         }
497         if (name.equalsIgnoreCase("Diffie-Hellman")
498             || name.equalsIgnoreCase("DH")) {
499             return AlgorithmId.DH_oid;
500         }
501         if (name.equalsIgnoreCase("DSA")) {
502             return AlgorithmId.DSA_oid;
503         }
504         if (name.equalsIgnoreCase("EC")) {
505             return EC_oid;
506         }
507         if (name.equalsIgnoreCase("ECDH")) {
508             return AlgorithmId.ECDH_oid;
509         }
510 
511         // Secret key algorithms
512         if (name.equalsIgnoreCase("AES")) {
513             return AlgorithmId.AES_oid;
514         }
515 
516         // Common signature types
517         if (name.equalsIgnoreCase("MD5withRSA")
518             || name.equalsIgnoreCase("MD5/RSA")) {
519             return AlgorithmId.md5WithRSAEncryption_oid;
520         }
521         if (name.equalsIgnoreCase("MD2withRSA")
522             || name.equalsIgnoreCase("MD2/RSA")) {
523             return AlgorithmId.md2WithRSAEncryption_oid;
524         }
525         if (name.equalsIgnoreCase("SHAwithDSA")
526             || name.equalsIgnoreCase("SHA1withDSA")
527             || name.equalsIgnoreCase("SHA/DSA")
528             || name.equalsIgnoreCase("SHA1/DSA")
529             || name.equalsIgnoreCase("DSAWithSHA1")
530             || name.equalsIgnoreCase("DSS")
531             || name.equalsIgnoreCase("SHA-1/DSA")) {
532             return AlgorithmId.sha1WithDSA_oid;
533         }
534         if (name.equalsIgnoreCase("SHA224WithDSA")) {
535             return AlgorithmId.sha224WithDSA_oid;
536         }
537         if (name.equalsIgnoreCase("SHA256WithDSA")) {
538             return AlgorithmId.sha256WithDSA_oid;
539         }
540         if (name.equalsIgnoreCase("SHA1WithRSA")
541             || name.equalsIgnoreCase("SHA1/RSA")) {
542             return AlgorithmId.sha1WithRSAEncryption_oid;
543         }
544         if (name.equalsIgnoreCase("SHA1withECDSA")
545                 || name.equalsIgnoreCase("ECDSA")) {
546             return AlgorithmId.sha1WithECDSA_oid;
547         }
548         if (name.equalsIgnoreCase("SHA224withECDSA")) {
549             return AlgorithmId.sha224WithECDSA_oid;
550         }
551         if (name.equalsIgnoreCase("SHA256withECDSA")) {
552             return AlgorithmId.sha256WithECDSA_oid;
553         }
554         if (name.equalsIgnoreCase("SHA384withECDSA")) {
555             return AlgorithmId.sha384WithECDSA_oid;
556         }
557         if (name.equalsIgnoreCase("SHA512withECDSA")) {
558             return AlgorithmId.sha512WithECDSA_oid;
559         }
560 
561         implementationMissing();
562 
563         // See if any of the installed providers supply a mapping from
564         // the given algorithm name to an OID string
565         // string oidString;
566         // if (!initOidTable) {
567         //     Provider[] provs = Security.getProviders();
568         //     for (int i=0; i<provs.length; i++) {
569         //         for (Enumeration!Object enum_ = provs[i].keys();
570         //              enum_.hasMoreElements(); ) {
571         //             string alias = (string)enum_.nextElement();
572         //             string upperCaseAlias = alias.toUpperCase(Locale.ENGLISH);
573         //             int index;
574         //             if (upperCaseAlias.startsWith("ALG.ALIAS") &&
575         //                     (index=upperCaseAlias.indexOf("OID.", 0)) != -1) {
576         //                 index += "OID.".length();
577         //                 if (index == alias.length()) {
578         //                     // invalid alias entry
579         //                     break;
580         //                 }
581         //                 if (oidTable is null) {
582         //                     oidTable = new HashMap!(string,ObjectIdentifier)();
583         //                 }
584         //                 oidString = alias.substring(index);
585         //                 string stdAlgName = provs[i].getProperty(alias);
586         //                 if (stdAlgName !is null) {
587         //                     stdAlgName = stdAlgName.toUpperCase(Locale.ENGLISH);
588         //                 }
589         //                 if (stdAlgName !is null &&
590         //                         oidTable.get(stdAlgName) is null) {
591         //                     oidTable.put(stdAlgName,
592         //                                  new ObjectIdentifier(oidString));
593         //                 }
594         //             }
595         //         }
596         //     }
597 
598         //     if (oidTable is null) {
599         //         oidTable = Collections.!(string,ObjectIdentifier)emptyMap();
600         //     }
601             // initOidTable = true;
602         // }
603 
604         return oidTable.get(name.toUpper());
605     }
606 
607     private static ObjectIdentifier oid(int[] values...) {
608         return ObjectIdentifier.newInternal(values);
609     }
610 
611     private static bool initOidTable = false;
612     private static Map!(string,ObjectIdentifier) oidTable;
613     private __gshared static Map!(ObjectIdentifier,string) nameTable;
614 
615     /*****************************************************************/
616 
617     /*
618      * HASHING ALGORITHMS
619      */
620 
621     /**
622      * Algorithm ID for the MD2 Message Digest Algorthm, from RFC 1319.
623      * OID = 1.2.840.113549.2.2
624      */
625     __gshared static ObjectIdentifier MD2_oid;
626 
627     /**
628      * Algorithm ID for the MD5 Message Digest Algorthm, from RFC 1321.
629      * OID = 1.2.840.113549.2.5
630      */
631     __gshared static ObjectIdentifier MD5_oid;
632 
633     /**
634      * Algorithm ID for the SHA1 Message Digest Algorithm, from FIPS 180-1.
635      * This is sometimes called "SHA", though that is often confusing since
636      * many people refer to FIPS 180 (which has an error) as defining SHA.
637      * OID = 1.3.14.3.2.26. Old SHA-0 OID: 1.3.14.3.2.18.
638      */
639     __gshared static ObjectIdentifier SHA_oid;
640 
641     __gshared static ObjectIdentifier SHA224_oid;
642 
643     __gshared static ObjectIdentifier SHA256_oid;
644 
645     __gshared static ObjectIdentifier SHA384_oid;
646 
647     __gshared static ObjectIdentifier SHA512_oid;
648 
649     /*
650      * COMMON PUBLIC KEY TYPES
651      */
652     private enum int[] DH_data = [ 1, 2, 840, 113549, 1, 3, 1 ];
653     private enum int[] DH_PKIX_data = [ 1, 2, 840, 10046, 2, 1 ];
654     private enum int[] DSA_OIW_data = [ 1, 3, 14, 3, 2, 12 ];
655     private enum int[] DSA_PKIX_data = [ 1, 2, 840, 10040, 4, 1 ];
656     private enum int[] RSA_data = [ 2, 5, 8, 1, 1 ];
657     private enum int[] RSAEncryption_data =
658                                  [ 1, 2, 840, 113549, 1, 1, 1 ];
659 
660     __gshared static ObjectIdentifier DH_oid;
661     __gshared static ObjectIdentifier DH_PKIX_oid;
662     __gshared static ObjectIdentifier DSA_oid;
663     __gshared static ObjectIdentifier DSA_OIW_oid;
664     __gshared static ObjectIdentifier EC_oid;
665     __gshared static ObjectIdentifier ECDH_oid;
666     __gshared static ObjectIdentifier RSA_oid;
667     __gshared static ObjectIdentifier RSAEncryption_oid;
668 
669     /*
670      * COMMON SECRET KEY TYPES
671      */
672     __gshared static ObjectIdentifier AES_oid;
673 
674     /*
675      * COMMON SIGNATURE ALGORITHMS
676      */
677     private enum int[] md2WithRSAEncryption_data =
678                                        [ 1, 2, 840, 113549, 1, 1, 2 ];
679     private enum int[] md5WithRSAEncryption_data =
680                                        [ 1, 2, 840, 113549, 1, 1, 4 ];
681     private enum int[] sha1WithRSAEncryption_data =
682                                        [ 1, 2, 840, 113549, 1, 1, 5 ];
683     private enum int[] sha1WithRSAEncryption_OIW_data =
684                                        [ 1, 3, 14, 3, 2, 29 ];
685     private enum int[] sha224WithRSAEncryption_data =
686                                        [ 1, 2, 840, 113549, 1, 1, 14 ];
687     private enum int[] sha256WithRSAEncryption_data =
688                                        [ 1, 2, 840, 113549, 1, 1, 11 ];
689     private enum int[] sha384WithRSAEncryption_data =
690                                        [ 1, 2, 840, 113549, 1, 1, 12 ];
691     private enum int[] sha512WithRSAEncryption_data =
692                                        [ 1, 2, 840, 113549, 1, 1, 13 ];
693     private enum int[] shaWithDSA_OIW_data =
694                                        [ 1, 3, 14, 3, 2, 13 ];
695     private enum int[] sha1WithDSA_OIW_data =
696                                        [ 1, 3, 14, 3, 2, 27 ];
697     private enum int[] dsaWithSHA1_PKIX_data =
698                                        [ 1, 2, 840, 10040, 4, 3 ];
699 
700     __gshared static ObjectIdentifier md2WithRSAEncryption_oid;
701     __gshared static ObjectIdentifier md5WithRSAEncryption_oid;
702     __gshared static ObjectIdentifier sha1WithRSAEncryption_oid;
703     __gshared static ObjectIdentifier sha1WithRSAEncryption_OIW_oid;
704     __gshared static ObjectIdentifier sha224WithRSAEncryption_oid;
705     __gshared static ObjectIdentifier sha256WithRSAEncryption_oid;
706     __gshared static ObjectIdentifier sha384WithRSAEncryption_oid;
707     __gshared static ObjectIdentifier sha512WithRSAEncryption_oid;
708     __gshared static ObjectIdentifier shaWithDSA_OIW_oid;
709     __gshared static ObjectIdentifier sha1WithDSA_OIW_oid;
710     __gshared static ObjectIdentifier sha1WithDSA_oid;
711     __gshared static ObjectIdentifier sha224WithDSA_oid;
712     __gshared static ObjectIdentifier sha256WithDSA_oid;
713 
714     __gshared static ObjectIdentifier sha1WithECDSA_oid;
715     __gshared static ObjectIdentifier sha224WithECDSA_oid;
716     __gshared static ObjectIdentifier sha256WithECDSA_oid;
717     __gshared static ObjectIdentifier sha384WithECDSA_oid;
718     __gshared static ObjectIdentifier sha512WithECDSA_oid;
719     __gshared static ObjectIdentifier specifiedWithECDSA_oid;
720 
721     /**
722      * Algorithm ID for the PBE encryption algorithms from PKCS#5 and
723      * PKCS#12.
724      */
725     __gshared static ObjectIdentifier pbeWithMD5AndDES_oid;
726     __gshared static ObjectIdentifier pbeWithMD5AndRC2_oid;
727     __gshared static ObjectIdentifier pbeWithSHA1AndDES_oid;
728     __gshared static ObjectIdentifier pbeWithSHA1AndRC2_oid;
729     __gshared static ObjectIdentifier pbeWithSHA1AndDESede_oid;
730     __gshared static ObjectIdentifier pbeWithSHA1AndRC2_40_oid;
731 
732     shared static this() {
733         MD2_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 2, 2]);
734         MD5_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 2, 5]);
735         SHA_oid = ObjectIdentifier.newInternal([1, 3, 14, 3, 2, 26]);
736         SHA224_oid = ObjectIdentifier.newInternal([2, 16, 840, 1, 101, 3, 4, 2, 4]);
737         SHA256_oid = ObjectIdentifier.newInternal([2, 16, 840, 1, 101, 3, 4, 2, 1]);
738         SHA384_oid = ObjectIdentifier.newInternal([2, 16, 840, 1, 101, 3, 4, 2, 2]);
739         SHA512_oid = ObjectIdentifier.newInternal([2, 16, 840, 1, 101, 3, 4, 2, 3]);
740 
741         EC_oid = oid(1, 2, 840, 10045, 2, 1);
742         ECDH_oid = oid(1, 3, 132, 1, 12);
743         AES_oid = oid(2, 16, 840, 1, 101, 3, 4, 1);
744         sha224WithDSA_oid = oid(2, 16, 840, 1, 101, 3, 4, 3, 1);
745         sha256WithDSA_oid = oid(2, 16, 840, 1, 101, 3, 4, 3, 2);
746         
747         sha1WithECDSA_oid = oid(1, 2, 840, 10045, 4, 1);
748         sha224WithECDSA_oid = oid(1, 2, 840, 10045, 4, 3, 1);
749         sha256WithECDSA_oid = oid(1, 2, 840, 10045, 4, 3, 2);
750         sha384WithECDSA_oid = oid(1, 2, 840, 10045, 4, 3, 3);
751         sha512WithECDSA_oid = oid(1, 2, 840, 10045, 4, 3, 4);
752         specifiedWithECDSA_oid = oid(1, 2, 840, 10045, 4, 3);
753 
754         pbeWithMD5AndDES_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 1, 5, 3]);
755         pbeWithMD5AndRC2_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 1, 5, 6]);
756         pbeWithSHA1AndDES_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 1, 5, 10]);
757         pbeWithSHA1AndRC2_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 1, 5, 11]);
758         pbeWithSHA1AndDESede_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 1, 12, 1, 3]);
759         pbeWithSHA1AndRC2_40_oid = ObjectIdentifier.newInternal([1, 2, 840, 113549, 1, 12, 1, 6]);
760     /*
761      * Note the preferred OIDs are named simply with no "OIW" or
762      * "PKIX" in them, even though they may point to data from these
763      * specs; e.g. SHA_oid, DH_oid, DSA_oid, SHA1WithDSA_oid...
764      */
765     /**
766      * Algorithm ID for Diffie Hellman Key agreement, from PKCS #3.
767      * Parameters include values P and G, and may optionally specify
768      * the length of the private key X.  Alternatively, algorithm parameters
769      * may be derived from another source such as a Certificate Authority's
770      * certificate.
771      * OID = 1.2.840.113549.1.3.1
772      */
773         DH_oid = ObjectIdentifier.newInternal(DH_data);
774 
775     /**
776      * Algorithm ID for the Diffie Hellman Key Agreement (DH), from RFC 3279.
777      * Parameters may include values P and G.
778      * OID = 1.2.840.10046.2.1
779      */
780         DH_PKIX_oid = ObjectIdentifier.newInternal(DH_PKIX_data);
781 
782     /**
783      * Algorithm ID for the Digital Signing Algorithm (DSA), from the
784      * NIST OIW Stable Agreements part 12.
785      * Parameters may include values P, Q, and G; or these may be
786      * derived from
787      * another source such as a Certificate Authority's certificate.
788      * OID = 1.3.14.3.2.12
789      */
790         DSA_OIW_oid = ObjectIdentifier.newInternal(DSA_OIW_data);
791 
792     /**
793      * Algorithm ID for the Digital Signing Algorithm (DSA), from RFC 3279.
794      * Parameters may include values P, Q, and G; or these may be
795      * derived from another source such as a Certificate Authority's
796      * certificate.
797      * OID = 1.2.840.10040.4.1
798      */
799         DSA_oid = ObjectIdentifier.newInternal(DSA_PKIX_data);
800 
801     /**
802      * Algorithm ID for RSA keys used for any purpose, as defined in X.509.
803      * The algorithm parameter is a single value, the number of bits in the
804      * modulus.
805      * OID = 2.5.8.1.1
806      */
807         RSA_oid = ObjectIdentifier.newInternal(RSA_data);
808 
809     /**
810      * Algorithm ID for RSA keys used with RSA encryption, as defined
811      * in PKCS #1.  There are no parameters associated with this algorithm.
812      * OID = 1.2.840.113549.1.1.1
813      */
814         RSAEncryption_oid = ObjectIdentifier.newInternal(RSAEncryption_data);
815 
816     /**
817      * Identifies a signing algorithm where an MD2 digest is encrypted
818      * using an RSA private key; defined in PKCS #1.  Use of this
819      * signing algorithm is discouraged due to MD2 vulnerabilities.
820      * OID = 1.2.840.113549.1.1.2
821      */
822         md2WithRSAEncryption_oid =
823             ObjectIdentifier.newInternal(md2WithRSAEncryption_data);
824 
825     /**
826      * Identifies a signing algorithm where an MD5 digest is
827      * encrypted using an RSA private key; defined in PKCS #1.
828      * OID = 1.2.840.113549.1.1.4
829      */
830         md5WithRSAEncryption_oid =
831             ObjectIdentifier.newInternal(md5WithRSAEncryption_data);
832 
833     /**
834      * Identifies a signing algorithm where a SHA1 digest is
835      * encrypted using an RSA private key; defined by RSA DSI.
836      * OID = 1.2.840.113549.1.1.5
837      */
838         sha1WithRSAEncryption_oid =
839             ObjectIdentifier.newInternal(sha1WithRSAEncryption_data);
840 
841     /**
842      * Identifies a signing algorithm where a SHA1 digest is
843      * encrypted using an RSA private key; defined in NIST OIW.
844      * OID = 1.3.14.3.2.29
845      */
846         sha1WithRSAEncryption_OIW_oid =
847             ObjectIdentifier.newInternal(sha1WithRSAEncryption_OIW_data);
848 
849     /**
850      * Identifies a signing algorithm where a SHA224 digest is
851      * encrypted using an RSA private key; defined by PKCS #1.
852      * OID = 1.2.840.113549.1.1.14
853      */
854         sha224WithRSAEncryption_oid =
855             ObjectIdentifier.newInternal(sha224WithRSAEncryption_data);
856 
857     /**
858      * Identifies a signing algorithm where a SHA256 digest is
859      * encrypted using an RSA private key; defined by PKCS #1.
860      * OID = 1.2.840.113549.1.1.11
861      */
862         sha256WithRSAEncryption_oid =
863             ObjectIdentifier.newInternal(sha256WithRSAEncryption_data);
864 
865     /**
866      * Identifies a signing algorithm where a SHA384 digest is
867      * encrypted using an RSA private key; defined by PKCS #1.
868      * OID = 1.2.840.113549.1.1.12
869      */
870         sha384WithRSAEncryption_oid =
871             ObjectIdentifier.newInternal(sha384WithRSAEncryption_data);
872 
873     /**
874      * Identifies a signing algorithm where a SHA512 digest is
875      * encrypted using an RSA private key; defined by PKCS #1.
876      * OID = 1.2.840.113549.1.1.13
877      */
878         sha512WithRSAEncryption_oid =
879             ObjectIdentifier.newInternal(sha512WithRSAEncryption_data);
880 
881     /**
882      * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a
883      * SHA digest is signed using the Digital Signing Algorithm (DSA).
884      * This should not be used.
885      * OID = 1.3.14.3.2.13
886      */
887         shaWithDSA_OIW_oid = ObjectIdentifier.newInternal(shaWithDSA_OIW_data);
888 
889     /**
890      * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a
891      * SHA1 digest is signed using the Digital Signing Algorithm (DSA).
892      * OID = 1.3.14.3.2.27
893      */
894         sha1WithDSA_OIW_oid = ObjectIdentifier.newInternal(sha1WithDSA_OIW_data);
895 
896     /**
897      * Identifies the FIPS 186 "Digital Signature Standard" (DSS), where a
898      * SHA1 digest is signed using the Digital Signing Algorithm (DSA).
899      * OID = 1.2.840.10040.4.3
900      */
901         sha1WithDSA_oid = ObjectIdentifier.newInternal(dsaWithSHA1_PKIX_data);
902 
903         nameTable = new HashMap!(ObjectIdentifier,string)();
904         nameTable.put(MD5_oid, "MD5");
905         nameTable.put(MD2_oid, "MD2");
906         nameTable.put(SHA_oid, "SHA-1");
907         nameTable.put(SHA224_oid, "SHA-224");
908         nameTable.put(SHA256_oid, "SHA-256");
909         nameTable.put(SHA384_oid, "SHA-384");
910         nameTable.put(SHA512_oid, "SHA-512");
911         nameTable.put(RSAEncryption_oid, "RSA");
912         nameTable.put(RSA_oid, "RSA");
913         nameTable.put(DH_oid, "Diffie-Hellman");
914         nameTable.put(DH_PKIX_oid, "Diffie-Hellman");
915         nameTable.put(DSA_oid, "DSA");
916         nameTable.put(DSA_OIW_oid, "DSA");
917         nameTable.put(EC_oid, "EC");
918         nameTable.put(ECDH_oid, "ECDH");
919 
920         nameTable.put(AES_oid, "AES");
921 
922         nameTable.put(sha1WithECDSA_oid, "SHA1withECDSA");
923         nameTable.put(sha224WithECDSA_oid, "SHA224withECDSA");
924         nameTable.put(sha256WithECDSA_oid, "SHA256withECDSA");
925         nameTable.put(sha384WithECDSA_oid, "SHA384withECDSA");
926         nameTable.put(sha512WithECDSA_oid, "SHA512withECDSA");
927         nameTable.put(md5WithRSAEncryption_oid, "MD5withRSA");
928         nameTable.put(md2WithRSAEncryption_oid, "MD2withRSA");
929         nameTable.put(sha1WithDSA_oid, "SHA1withDSA");
930         nameTable.put(sha1WithDSA_OIW_oid, "SHA1withDSA");
931         nameTable.put(shaWithDSA_OIW_oid, "SHA1withDSA");
932         nameTable.put(sha224WithDSA_oid, "SHA224withDSA");
933         nameTable.put(sha256WithDSA_oid, "SHA256withDSA");
934         nameTable.put(sha1WithRSAEncryption_oid, "SHA1withRSA");
935         nameTable.put(sha1WithRSAEncryption_OIW_oid, "SHA1withRSA");
936         nameTable.put(sha224WithRSAEncryption_oid, "SHA224withRSA");
937         nameTable.put(sha256WithRSAEncryption_oid, "SHA256withRSA");
938         nameTable.put(sha384WithRSAEncryption_oid, "SHA384withRSA");
939         nameTable.put(sha512WithRSAEncryption_oid, "SHA512withRSA");
940         nameTable.put(pbeWithMD5AndDES_oid, "PBEWithMD5AndDES");
941         nameTable.put(pbeWithMD5AndRC2_oid, "PBEWithMD5AndRC2");
942         nameTable.put(pbeWithSHA1AndDES_oid, "PBEWithSHA1AndDES");
943         nameTable.put(pbeWithSHA1AndRC2_oid, "PBEWithSHA1AndRC2");
944         nameTable.put(pbeWithSHA1AndDESede_oid, "PBEWithSHA1AndDESede");
945         nameTable.put(pbeWithSHA1AndRC2_40_oid, "PBEWithSHA1AndRC2_40");
946     }
947 
948     /**
949      * Creates a signature algorithm name from a digest algorithm
950      * name and a encryption algorithm name.
951      */
952     static string makeSigAlg(string digAlg, string encAlg) {
953         digAlg = digAlg.replace("-", "");
954         if (encAlg.equalsIgnoreCase("EC")) encAlg = "ECDSA";
955 
956         return digAlg ~ "with" ~ encAlg;
957     }
958 
959     /**
960      * Extracts the encryption algorithm name from a signature
961      * algorithm name.
962       */
963     static string getEncAlgFromSigAlg(string signatureAlgorithm) {
964         signatureAlgorithm = signatureAlgorithm.toUpper();
965         ptrdiff_t w = signatureAlgorithm.indexOf("WITH");
966         string keyAlgorithm = null;
967         if (w > 0) {
968             ptrdiff_t and = signatureAlgorithm.indexOf("AND", w + 4);
969             if (and > 0) {
970                 keyAlgorithm = signatureAlgorithm[w + 4 .. and];
971             } else {
972                 keyAlgorithm = signatureAlgorithm[w + 4 .. $];
973             }
974             if (keyAlgorithm.equalsIgnoreCase("ECDSA")) {
975                 keyAlgorithm = "EC";
976             }
977         }
978         return keyAlgorithm;
979     }
980 
981     /**
982      * Extracts the digest algorithm name from a signature
983      * algorithm name.
984       */
985     static string getDigAlgFromSigAlg(string signatureAlgorithm) {
986         signatureAlgorithm = signatureAlgorithm.toUpper();
987         ptrdiff_t w = signatureAlgorithm.indexOf("WITH");
988         if (w > 0) {
989             return signatureAlgorithm[0 .. w];
990         }
991         return null;
992     }
993 }