1 /** 2 * Certificate Store 3 * 4 * Copyright: 5 * (C) 1999-2010,2013 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.certstor; 12 13 import botan.constants; 14 15 import botan.cert.x509.x509cert; 16 import botan.cert.x509.x509_crl; 17 import botan.utils.types; 18 import std.file; 19 20 version(X509): 21 22 /** 23 * Certificate Store Interface 24 */ 25 interface CertificateStore 26 { 27 public: 28 /** 29 * Subject DN and (optionally) key identifier 30 */ 31 X509Certificate findCertRef(in X509DN subject_dn, const ref Vector!ubyte key_id) const; 32 33 final X509Certificate findCert()(in X509DN subject_dn, auto const ref Vector!ubyte key_id) const { 34 return findCertRef(subject_dn, key_id); 35 } 36 37 X509CRL findCrlFor(in X509Certificate subject) const; 38 39 40 final bool certificateKnown(in X509Certificate cert) const 41 { 42 auto cert_ = findCert(cert.subjectDn(), cert.subjectKeyId()); 43 if (!*cert_) return false; 44 return cert_ != X509Certificate.init; 45 } 46 47 // remove this (used by TLSServer) 48 Vector!X509DN allSubjects() const; 49 } 50 51 /** 52 * In Memory Certificate Store 53 */ 54 final class CertificateStoreInMemory : CertificateStore 55 { 56 public: 57 /** 58 * Attempt to parse all files in dir (including subdirectories) 59 * as certificates. Ignores errors. 60 */ 61 this(in string dir) 62 { 63 if (dir == "") 64 return; 65 foreach(string name; dirEntries(dir, SpanMode.breadth)) { 66 if (isFile(name)) 67 m_certs.pushBack(X509Certificate(name)); 68 } 69 } 70 71 this() {} 72 73 void addCertificate(X509Certificate cert) 74 { 75 foreach (const cert_stored; m_certs[]) 76 { 77 if (cert_stored == cert) 78 return; 79 } 80 81 m_certs.pushBack(cert); 82 } 83 84 override Vector!X509DN allSubjects() const 85 { 86 Vector!X509DN subjects; 87 foreach (ref cert; m_certs[]) { 88 auto subj_dn = cert.subjectDn(); 89 subjects.pushBack(subj_dn.dup); 90 } 91 return subjects; 92 } 93 94 override X509Certificate findCertRef(in X509DN subject_dn, const ref Vector!ubyte key_id) const 95 { 96 return certSearch(subject_dn, key_id, m_certs); 97 } 98 99 void addCrl(X509CRL crl) 100 { 101 X509DN crl_issuer = crl.issuerDn(); 102 103 foreach (ref crl_stored; m_crls[]) 104 { 105 // Found an update of a previously existing one; replace it 106 if (crl_stored.issuerDn() == crl_issuer) 107 { 108 if (crl_stored.thisUpdate() <= crl.thisUpdate()) 109 crl_stored = crl; 110 return; 111 } 112 } 113 114 // Totally new CRL, add to the list 115 m_crls.pushBack(crl); 116 } 117 118 override X509CRL findCrlFor(in X509Certificate subject) const 119 { 120 const Vector!ubyte key_id = subject.authorityKeyId(); 121 122 foreach (crl; m_crls[]) 123 { 124 // Only compare key ids if set in both call and in the CRL 125 if (key_id.length) 126 { 127 Vector!ubyte akid = crl.authorityKeyId(); 128 129 if (akid.length && akid != key_id) // no match 130 continue; 131 } 132 133 if (crl.issuerDn() == subject.issuerDn()) 134 return crl; 135 } 136 137 return X509CRL.init; 138 } 139 140 private: 141 // TODO: Add indexing on the DN and key id to avoid linear search 142 Vector!X509Certificate m_certs; 143 Vector!X509CRL m_crls; 144 } 145 146 final class CertificateStoreOverlay : CertificateStore 147 { 148 public: 149 this(const ref Vector!X509Certificate certs) 150 { 151 foreach (ref cert; certs[]) { 152 m_certs ~= cert; 153 } 154 } 155 156 override X509CRL findCrlFor(in X509Certificate subject) const { return X509CRL.init; } 157 158 override Vector!X509DN allSubjects() const 159 { 160 Vector!X509DN subjects; 161 foreach (cert; m_certs[]) 162 subjects.pushBack(cert.subjectDn().dup); 163 return subjects.move; 164 } 165 166 override X509Certificate findCertRef(in X509DN subject_dn, const ref Vector!ubyte key_id) const 167 { 168 return certSearch(subject_dn, key_id, m_certs); 169 } 170 private: 171 Vector!X509Certificate m_certs; 172 } 173 174 X509Certificate certSearch(in X509DN subject_dn, 175 const ref Vector!ubyte key_id, 176 const ref Vector!X509Certificate certs) 177 { 178 foreach (cert; certs[]) 179 { 180 // Only compare key ids if set in both call and in the cert 181 if (key_id.length) 182 { 183 const Vector!ubyte skid = cert.subjectKeyId(); 184 185 if (skid.length && skid != key_id) // no match 186 continue; 187 } 188 189 if (cert.subjectDn() == subject_dn) { 190 return cert; 191 } 192 } 193 194 return X509Certificate.init; 195 }