1 module hunt.security.x509.KeyIdentifier;
2 
3 import hunt.security.x509.AlgorithmId;
4 import hunt.security.util.DerValue;
5 import hunt.security.util.DerOutputStream;
6 
7 import hunt.security.Key;
8 import hunt.Exceptions;
9 
10 import std.format;
11 
12 /**
13  * Represent the Key Identifier ASN.1 object.
14  *
15  * @author Amit Kapoor
16  * @author Hemma Prafullchandra
17  */
18 class KeyIdentifier {
19     private byte[] octetString;
20 
21     /**
22      * Create a KeyIdentifier with the passed bit settings.
23      *
24      * @param octetString the octet string identifying the key identifier.
25      */
26     this(byte[] octetString) {
27         this.octetString = octetString.dup;
28     }
29 
30     /**
31      * Create a KeyIdentifier from the DER encoded value.
32      *
33      * @param val the DerValue
34      */
35     this(DerValue val) {
36         octetString = val.getOctetString();
37     }
38 
39     /**
40      * Creates a KeyIdentifier from a public-key value.
41      *
42      * <p>From RFC2459: Two common methods for generating key identifiers from
43      * the key are:
44      * <ol>
45      * <li>The keyIdentifier is composed of the 160-bit SHA-1 hash of the
46      * value of the BIT STRING subjectPublicKey (excluding the tag,
47      * length, and number of unused bits).
48      * <p>
49      * <li>The keyIdentifier is composed of a four bit type field with
50      * the value 0100 followed by the least significant 60 bits of the
51      * SHA-1 hash of the value of the BIT STRING subjectPublicKey.
52      * </ol>
53      * <p>This method supports method 1.
54      *
55      * @param pubKey the key from which to construct this KeyIdentifier
56      * @throws IOException on parsing errors
57      */
58     this(PublicKey pubKey)
59     {
60         DerValue algAndKey = new DerValue(pubKey.getEncoded());
61         if (algAndKey.tag != DerValue.tag_Sequence)
62             throw new IOException("PublicKey value is not a valid "
63                                   ~ "X.509 key");
64 
65         // AlgorithmId algid = AlgorithmId.parse(algAndKey.data.getDerValue());
66         // byte[] key = algAndKey.data.getUnalignedBitString().toByteArray();
67 
68         // MessageDigest md = null;
69         // try {
70         //     md = MessageDigest.getInstance("SHA1");
71         // } catch (NoSuchAlgorithmException e3) {
72         //     throw new IOException("SHA1 not supported");
73         // }
74         // md.update(key);
75         // this.octetString = md.digest();
76         implementationMissing();
77     }
78 
79     /**
80      * Return the value of the KeyIdentifier as byte array.
81      */
82     byte[] getIdentifier() {
83         return octetString.dup;
84     }
85 
86     /**
87      * Returns a printable representation of the KeyUsage.
88      */
89     override string toString() {
90         // string s = "KeyIdentifier [\n";
91 
92         // HexDumpEncoder encoder = new HexDumpEncoder();
93         // s += encoder.encodeBuffer(octetString);
94         // s += "]\n";
95         string s = format("KeyIdentifier [\n%(%02X%)]\n", octetString);
96         return (s);
97     }
98 
99     /**
100      * Write the KeyIdentifier to the DerOutputStream.
101      *
102      * @param stream the DerOutputStream to write the object to.
103      * @exception IOException
104      */
105     void encode(DerOutputStream stream) {
106         stream.putOctetString(octetString);
107     }
108 
109     /**
110      * Returns a hash code value for this object.
111      * Objects that are equal will also have the same hashcode.
112      */
113     override size_t toHash() @trusted const nothrow {
114         size_t retval = 0;
115         for (size_t i = 0; i < octetString.length; i++)
116             retval += octetString[i] * i;
117         return retval;
118     }
119 
120     /**
121      * Indicates whether some other object is "equal to" this one.
122      */
123     override bool opEquals(Object other) {
124         if (this is other)
125             return true;
126         KeyIdentifier id = cast(KeyIdentifier)other;
127         if(id is null)
128             return false;
129         byte[] otherString = id.octetString;
130         return octetString == otherString;
131     }
132 }