1 /**
2 * OCSP subtypes
3 * 
4 * Copyright:
5 * (C) 2012 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.cert.x509.ocsp_types;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_X509_CERTIFICATES):
15 
16 import botan.cert.x509.x509cert;
17 import botan.asn1.asn1_time;
18 import botan.math.bigint.bigint;
19 import botan.asn1.der_enc;
20 import botan.asn1.ber_dec;
21 import botan.cert.x509.x509_ext;
22 import botan.libstate.lookup;
23 import botan.hash.hash;
24 import botan.asn1.oids;
25 import botan.utils.types;
26 import botan.utils.mem_ops;
27 
28 alias CertID = RefCounted!CertIDImpl;
29 
30 final class CertIDImpl : ASN1Object
31 {
32 public:
33     this() {}
34 
35     this(in X509Certificate issuer,
36          in X509Certificate subject)
37     {
38         /*
39         In practice it seems some responders, including, notably,
40         ocsp.verisign.com, will reject anything but SHA-1 here
41         */
42         Unique!HashFunction hash = retrieveHash("SHA-160").clone();
43         
44         m_hash_id = AlgorithmIdentifier(hash.name, AlgorithmIdentifierImpl.USE_NULL_PARAM);
45         m_issuer_key_hash = unlock(hash.process(extractKeyBitstr(issuer)));
46         m_issuer_dn_hash = unlock(hash.process(subject.rawIssuerDn()));
47         m_subject_serial = BigInt.decode(subject.serialNumber());
48     }
49 
50     bool isIdFor(in X509Certificate issuer,
51                    const X509Certificate subject) const
52     {
53         try
54         {
55             if (BigInt.decode(subject.serialNumber()) != m_subject_serial)
56                 return false;
57             
58             Unique!HashFunction hash = retrieveHash(OIDS.lookup(m_hash_id.oid)).clone();
59             
60             if (m_issuer_dn_hash != unlock(hash.process(subject.rawIssuerDn())))
61                 return false;
62             
63             if (m_issuer_key_hash != unlock(hash.process(extractKeyBitstr(issuer))))
64                 return false;
65         }
66         catch (Exception)
67         {
68             return false;
69         }
70         
71         return true;
72     }
73 
74     override void encodeInto(ref DEREncoder to) const
75     {
76         to.startCons(ASN1Tag.SEQUENCE)
77                 .encode(m_hash_id)
78                 .encode(m_issuer_dn_hash, ASN1Tag.OCTET_STRING)
79                 .encode(m_issuer_key_hash, ASN1Tag.OCTET_STRING)
80                 .encode(m_subject_serial)
81                 .endCons();
82     }
83 
84 
85     override void decodeFrom(ref BERDecoder from)
86     {
87         from.startCons(ASN1Tag.SEQUENCE)
88                 .decode(m_hash_id)
89                 .decode(m_issuer_dn_hash, ASN1Tag.OCTET_STRING)
90                 .decode(m_issuer_key_hash, ASN1Tag.OCTET_STRING)
91                 .decode(m_subject_serial)
92                 .endCons();
93         
94     }
95 
96 package:
97     Vector!ubyte extractKeyBitstr(in X509Certificate cert) const
98     {
99         const auto key_bits = cert.subjectPublicKeyBits();
100         
101         auto public_key_algid = AlgorithmIdentifier();
102         Vector!ubyte public_key_bitstr;
103         
104         BERDecoder(key_bits)
105                 .decode(public_key_algid)
106                 .decode(public_key_bitstr, ASN1Tag.BIT_STRING);
107         
108         return public_key_bitstr;
109     }
110 
111     AlgorithmIdentifier m_hash_id;
112     Vector!ubyte m_issuer_dn_hash;
113     Vector!ubyte m_issuer_key_hash;
114     BigInt m_subject_serial;
115 }
116 
117 alias SingleResponse = RefCounted!SingleResponseImpl;
118 
119 final class SingleResponseImpl : ASN1Object
120 {
121 public:
122     const(CertID) certid() const { return m_certid; }
123 
124     size_t certStatus() const { return m_cert_status; }
125 
126     const(X509Time) thisUpdate() const { return m_thisupdate; }
127 
128     const(X509Time) nextUpdate() const { return m_nextupdate; }
129 
130     override void encodeInto(ref DEREncoder) const
131     {
132         throw new Exception("Not implemented (SingleResponse::encodeInto)");
133     }
134 
135     override void decodeFrom(ref BERDecoder from)
136     {
137         BERObject cert_status;
138         X509Extensions extensions = X509Extensions(true);
139         
140         from.startCons(ASN1Tag.SEQUENCE)
141                 .decode(m_certid)
142                 .getNext(cert_status)
143                 .decode(m_thisupdate)
144                 .decodeOptional(m_nextupdate, (cast(ASN1Tag) 0),
145                                  ASN1Tag.CONTEXT_SPECIFIC | ASN1Tag.CONSTRUCTED)
146                 .decodeOptional(extensions, (cast(ASN1Tag)1),
147                                  ASN1Tag.CONTEXT_SPECIFIC | ASN1Tag.CONSTRUCTED)
148                 .endCons();
149         
150         m_cert_status = cert_status.type_tag;
151     }
152 
153 private:
154     CertID m_certid;
155     size_t m_cert_status = 2; // unknown
156     X509Time m_thisupdate;
157     X509Time m_nextupdate;
158 }