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 }