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 if (!*cert) return false; 43 auto cert_ = findCert(cert.subjectDn(), cert.subjectKeyId()); 44 if (!*cert_) return false; 45 return cert_ != X509Certificate.init; 46 } 47 48 // remove this (used by TLSServer) 49 Vector!X509DN allSubjects() const; 50 } 51 52 /** 53 * In Memory Certificate Store 54 */ 55 final class CertificateStoreInMemory : CertificateStore 56 { 57 public: 58 /** 59 * Attempt to parse all files in dir (including subdirectories) 60 * as certificates. Ignores errors. 61 */ 62 this(in string dir) 63 { 64 if (dir == "") 65 return; 66 foreach(string name; dirEntries(dir, SpanMode.breadth)) { 67 if (isFile(name)) 68 m_certs.pushBack(X509Certificate(name)); 69 } 70 } 71 72 this() {} 73 74 void addCertificate(X509Certificate cert) 75 { 76 foreach (const cert_stored; m_certs[]) 77 { 78 if (cert_stored == cert) 79 return; 80 } 81 82 m_certs.pushBack(cert); 83 } 84 85 override Vector!X509DN allSubjects() const 86 { 87 Vector!X509DN subjects; 88 foreach (ref cert; m_certs[]) { 89 auto subj_dn = cert.subjectDn(); 90 subjects.pushBack(subj_dn.dup); 91 } 92 return subjects; 93 } 94 95 override X509Certificate findCertRef(in X509DN subject_dn, const ref Vector!ubyte key_id) const 96 { 97 return certSearch(subject_dn, key_id, m_certs); 98 } 99 100 void addCrl(X509CRL crl) 101 { 102 X509DN crl_issuer = crl.issuerDn(); 103 104 foreach (ref crl_stored; m_crls[]) 105 { 106 // Found an update of a previously existing one; replace it 107 if (crl_stored.issuerDn() == crl_issuer) 108 { 109 if (crl_stored.thisUpdate() <= crl.thisUpdate()) 110 crl_stored = crl; 111 return; 112 } 113 } 114 115 // Totally new CRL, add to the list 116 m_crls.pushBack(crl); 117 } 118 119 override X509CRL findCrlFor(in X509Certificate subject) const 120 { 121 const Vector!ubyte key_id = subject.authorityKeyId(); 122 123 foreach (crl; m_crls[]) 124 { 125 // Only compare key ids if set in both call and in the CRL 126 if (key_id.length) 127 { 128 Vector!ubyte akid = crl.authorityKeyId(); 129 130 if (akid.length && akid != key_id) // no match 131 continue; 132 } 133 134 if (crl.issuerDn() == subject.issuerDn()) 135 return crl; 136 } 137 138 return X509CRL.init; 139 } 140 141 private: 142 // TODO: Add indexing on the DN and key id to avoid linear search 143 Vector!X509Certificate m_certs; 144 Vector!X509CRL m_crls; 145 } 146 147 final class CertificateStoreOverlay : CertificateStore 148 { 149 public: 150 this(const ref Vector!X509Certificate certs) 151 { 152 foreach (ref cert; certs[]) { 153 m_certs ~= cert; 154 } 155 } 156 157 override X509CRL findCrlFor(in X509Certificate subject) const { return X509CRL.init; } 158 159 override Vector!X509DN allSubjects() const 160 { 161 Vector!X509DN subjects; 162 foreach (cert; m_certs[]) 163 subjects.pushBack(cert.subjectDn().dup); 164 return subjects.move; 165 } 166 167 override X509Certificate findCertRef(in X509DN subject_dn, const ref Vector!ubyte key_id) const 168 { 169 return certSearch(subject_dn, key_id, m_certs); 170 } 171 private: 172 Vector!X509Certificate m_certs; 173 } 174 175 X509Certificate certSearch(in X509DN subject_dn, 176 const ref Vector!ubyte key_id, 177 const ref Vector!X509Certificate certs) 178 { 179 foreach (cert; certs[]) 180 { 181 // Only compare key ids if set in both call and in the cert 182 if (key_id.length) 183 { 184 const Vector!ubyte skid = cert.subjectKeyId(); 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 }