Botan
1.11.15
|
00001 /* 00002 * X.509 Certificate Path Validation 00003 * (C) 2010,2011,2012,2014 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/x509path.h> 00009 #include <botan/ocsp.h> 00010 #include <botan/http_util.h> 00011 #include <botan/parsing.h> 00012 #include <botan/pubkey.h> 00013 #include <botan/oids.h> 00014 #include <algorithm> 00015 #include <chrono> 00016 #include <vector> 00017 #include <set> 00018 00019 #include <iostream> 00020 00021 namespace Botan { 00022 00023 namespace { 00024 00025 const X509_Certificate* 00026 find_issuing_cert(const X509_Certificate& cert, 00027 Certificate_Store& end_certs, 00028 const std::vector<Certificate_Store*>& certstores) 00029 { 00030 const X509_DN issuer_dn = cert.issuer_dn(); 00031 const std::vector<byte> auth_key_id = cert.authority_key_id(); 00032 00033 if(const X509_Certificate* c = end_certs.find_cert(issuer_dn, auth_key_id)) 00034 return c; 00035 00036 for(size_t i = 0; i != certstores.size(); ++i) 00037 { 00038 if(const X509_Certificate* c = certstores[i]->find_cert(issuer_dn, auth_key_id)) 00039 return c; 00040 } 00041 00042 return nullptr; 00043 } 00044 00045 const X509_CRL* find_crls_for(const X509_Certificate& cert, 00046 const std::vector<Certificate_Store*>& certstores) 00047 { 00048 for(size_t i = 0; i != certstores.size(); ++i) 00049 { 00050 if(const X509_CRL* crl = certstores[i]->find_crl_for(cert)) 00051 return crl; 00052 } 00053 00054 #if 0 00055 const std::string crl_url = cert.crl_distribution_point(); 00056 if(crl_url != "") 00057 { 00058 std::cout << "Downloading CRL " << crl_url << "\n"; 00059 auto http = HTTP::GET_sync(crl_url); 00060 00061 std::cout << http.status_message() << "\n"; 00062 00063 http.throw_unless_ok(); 00064 // check the mime type 00065 00066 std::unique_ptr<X509_CRL> crl(new X509_CRL(http.body())); 00067 00068 return crl.release(); 00069 } 00070 #endif 00071 00072 return nullptr; 00073 } 00074 00075 std::vector<std::set<Certificate_Status_Code>> 00076 check_chain(const std::vector<X509_Certificate>& cert_path, 00077 const Path_Validation_Restrictions& restrictions, 00078 const std::vector<Certificate_Store*>& certstores) 00079 { 00080 const std::set<std::string>& trusted_hashes = restrictions.trusted_hashes(); 00081 00082 const bool self_signed_ee_cert = (cert_path.size() == 1); 00083 00084 X509_Time current_time(std::chrono::system_clock::now()); 00085 00086 std::vector<std::future<OCSP::Response>> ocsp_responses; 00087 00088 std::vector<std::set<Certificate_Status_Code>> cert_status(cert_path.size()); 00089 00090 for(size_t i = 0; i != cert_path.size(); ++i) 00091 { 00092 std::set<Certificate_Status_Code>& status = cert_status.at(i); 00093 00094 const bool at_self_signed_root = (i == cert_path.size() - 1); 00095 00096 const X509_Certificate& subject = cert_path[i]; 00097 00098 const X509_Certificate& issuer = cert_path[at_self_signed_root ? (i) : (i + 1)]; 00099 00100 if(i == 0 || restrictions.ocsp_all_intermediates()) 00101 { 00102 // certstore[0] is treated as trusted for OCSP (FIXME) 00103 if(certstores.size() > 1) 00104 ocsp_responses.push_back( 00105 std::async(std::launch::async, 00106 OCSP::online_check, issuer, subject, certstores[0])); 00107 } 00108 00109 // Check all certs for valid time range 00110 if(current_time < X509_Time(subject.start_time())) 00111 status.insert(Certificate_Status_Code::CERT_NOT_YET_VALID); 00112 00113 if(current_time > X509_Time(subject.end_time())) 00114 status.insert(Certificate_Status_Code::CERT_HAS_EXPIRED); 00115 00116 // Check issuer constraints 00117 00118 // Don't require CA bit set on self-signed end entity cert 00119 if(!issuer.is_CA_cert() && !self_signed_ee_cert) 00120 status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER); 00121 00122 if(issuer.path_limit() < i) 00123 status.insert(Certificate_Status_Code::CERT_CHAIN_TOO_LONG); 00124 00125 std::unique_ptr<Public_Key> issuer_key(issuer.subject_public_key()); 00126 00127 if(!issuer_key) 00128 { 00129 status.insert(Certificate_Status_Code::SIGNATURE_ERROR); 00130 } 00131 else 00132 { 00133 if(subject.check_signature(*issuer_key) == false) 00134 status.insert(Certificate_Status_Code::SIGNATURE_ERROR); 00135 00136 if(issuer_key->estimated_strength() < restrictions.minimum_key_strength()) 00137 status.insert(Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK); 00138 } 00139 00140 // Allow untrusted hashes on self-signed roots 00141 if(!trusted_hashes.empty() && !at_self_signed_root) 00142 { 00143 if(!trusted_hashes.count(subject.hash_used_for_signature())) 00144 status.insert(Certificate_Status_Code::UNTRUSTED_HASH); 00145 } 00146 } 00147 00148 for(size_t i = 0; i != cert_path.size() - 1; ++i) 00149 { 00150 std::set<Certificate_Status_Code>& status = cert_status.at(i); 00151 00152 const X509_Certificate& subject = cert_path.at(i); 00153 const X509_Certificate& ca = cert_path.at(i+1); 00154 00155 if(i < ocsp_responses.size()) 00156 { 00157 try 00158 { 00159 OCSP::Response ocsp = ocsp_responses[i].get(); 00160 00161 auto ocsp_status = ocsp.status_for(ca, subject); 00162 00163 status.insert(ocsp_status); 00164 00165 //std::cout << "OCSP status: " << Path_Validation_Result::status_string(ocsp_status) << "\n"; 00166 00167 // Either way we have a definitive answer, no need to check CRLs 00168 if(ocsp_status == Certificate_Status_Code::CERT_IS_REVOKED) 00169 return cert_status; 00170 else if(ocsp_status == Certificate_Status_Code::OCSP_RESPONSE_GOOD) 00171 continue; 00172 } 00173 catch(std::exception& e) 00174 { 00175 //std::cout << "OCSP error: " << e.what() << "\n"; 00176 } 00177 } 00178 00179 const X509_CRL* crl_p = find_crls_for(subject, certstores); 00180 00181 if(!crl_p) 00182 { 00183 if(restrictions.require_revocation_information()) 00184 status.insert(Certificate_Status_Code::NO_REVOCATION_DATA); 00185 continue; 00186 } 00187 00188 const X509_CRL& crl = *crl_p; 00189 00190 if(!ca.allowed_usage(CRL_SIGN)) 00191 status.insert(Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER); 00192 00193 if(current_time < X509_Time(crl.this_update())) 00194 status.insert(Certificate_Status_Code::CRL_NOT_YET_VALID); 00195 00196 if(current_time > X509_Time(crl.next_update())) 00197 status.insert(Certificate_Status_Code::CRL_HAS_EXPIRED); 00198 00199 if(crl.check_signature(ca.subject_public_key()) == false) 00200 status.insert(Certificate_Status_Code::CRL_BAD_SIGNATURE); 00201 00202 if(crl.is_revoked(subject)) 00203 status.insert(Certificate_Status_Code::CERT_IS_REVOKED); 00204 } 00205 00206 if(self_signed_ee_cert) 00207 cert_status.back().insert(Certificate_Status_Code::CANNOT_ESTABLISH_TRUST); 00208 00209 return cert_status; 00210 } 00211 00212 } 00213 00214 Path_Validation_Result x509_path_validate( 00215 const std::vector<X509_Certificate>& end_certs, 00216 const Path_Validation_Restrictions& restrictions, 00217 const std::vector<Certificate_Store*>& certstores) 00218 { 00219 if(end_certs.empty()) 00220 throw std::invalid_argument("x509_path_validate called with no subjects"); 00221 00222 std::vector<X509_Certificate> cert_path; 00223 cert_path.push_back(end_certs[0]); 00224 00225 Certificate_Store_Overlay extra(end_certs); 00226 00227 // iterate until we reach a root or cannot find the issuer 00228 while(!cert_path.back().is_self_signed()) 00229 { 00230 const X509_Certificate* cert = find_issuing_cert(cert_path.back(), extra, certstores); 00231 if(!cert) 00232 return Path_Validation_Result(Certificate_Status_Code::CERT_ISSUER_NOT_FOUND); 00233 00234 cert_path.push_back(*cert); 00235 } 00236 00237 return Path_Validation_Result(check_chain(cert_path, restrictions, certstores), 00238 std::move(cert_path)); 00239 } 00240 00241 Path_Validation_Result x509_path_validate( 00242 const X509_Certificate& end_cert, 00243 const Path_Validation_Restrictions& restrictions, 00244 const std::vector<Certificate_Store*>& certstores) 00245 { 00246 std::vector<X509_Certificate> certs; 00247 certs.push_back(end_cert); 00248 return x509_path_validate(certs, restrictions, certstores); 00249 } 00250 00251 Path_Validation_Result x509_path_validate( 00252 const std::vector<X509_Certificate>& end_certs, 00253 const Path_Validation_Restrictions& restrictions, 00254 const Certificate_Store& store) 00255 { 00256 std::vector<Certificate_Store*> certstores; 00257 certstores.push_back(const_cast<Certificate_Store*>(&store)); 00258 00259 return x509_path_validate(end_certs, restrictions, certstores); 00260 } 00261 00262 Path_Validation_Result x509_path_validate( 00263 const X509_Certificate& end_cert, 00264 const Path_Validation_Restrictions& restrictions, 00265 const Certificate_Store& store) 00266 { 00267 std::vector<X509_Certificate> certs; 00268 certs.push_back(end_cert); 00269 00270 std::vector<Certificate_Store*> certstores; 00271 certstores.push_back(const_cast<Certificate_Store*>(&store)); 00272 00273 return x509_path_validate(certs, restrictions, certstores); 00274 } 00275 00276 Path_Validation_Restrictions::Path_Validation_Restrictions(bool require_rev, 00277 size_t key_strength, 00278 bool ocsp_all) : 00279 m_require_revocation_information(require_rev), 00280 m_ocsp_all_intermediates(ocsp_all), 00281 m_minimum_key_strength(key_strength) 00282 { 00283 if(key_strength <= 80) 00284 m_trusted_hashes.insert("SHA-160"); 00285 00286 m_trusted_hashes.insert("SHA-224"); 00287 m_trusted_hashes.insert("SHA-256"); 00288 m_trusted_hashes.insert("SHA-384"); 00289 m_trusted_hashes.insert("SHA-512"); 00290 } 00291 00292 Path_Validation_Result::Path_Validation_Result(std::vector<std::set<Certificate_Status_Code>> status, 00293 std::vector<X509_Certificate>&& cert_chain) : 00294 m_overall(Certificate_Status_Code::VERIFIED), 00295 m_all_status(status), 00296 m_cert_path(cert_chain) 00297 { 00298 // take the "worst" error as overall 00299 for(const auto& s : m_all_status) 00300 { 00301 if(!s.empty()) 00302 { 00303 auto worst = *s.rbegin(); 00304 // Leave OCSP confirmations on cert-level status only 00305 if(worst != Certificate_Status_Code::OCSP_RESPONSE_GOOD) 00306 m_overall = worst; 00307 } 00308 } 00309 } 00310 00311 const X509_Certificate& Path_Validation_Result::trust_root() const 00312 { 00313 return m_cert_path[m_cert_path.size()-1]; 00314 } 00315 00316 std::set<std::string> Path_Validation_Result::trusted_hashes() const 00317 { 00318 std::set<std::string> hashes; 00319 for(size_t i = 0; i != m_cert_path.size(); ++i) 00320 hashes.insert(m_cert_path[i].hash_used_for_signature()); 00321 return hashes; 00322 } 00323 00324 bool Path_Validation_Result::successful_validation() const 00325 { 00326 if(result() == Certificate_Status_Code::VERIFIED || 00327 result() == Certificate_Status_Code::OCSP_RESPONSE_GOOD) 00328 return true; 00329 return false; 00330 } 00331 00332 std::string Path_Validation_Result::result_string() const 00333 { 00334 return status_string(result()); 00335 } 00336 00337 const char* Path_Validation_Result::status_string(Certificate_Status_Code code) 00338 { 00339 switch(code) 00340 { 00341 case Certificate_Status_Code::VERIFIED: 00342 return "Verified"; 00343 case Certificate_Status_Code::OCSP_RESPONSE_GOOD: 00344 return "OCSP response good"; 00345 case Certificate_Status_Code::NO_REVOCATION_DATA: 00346 return "No revocation data"; 00347 case Certificate_Status_Code::SIGNATURE_METHOD_TOO_WEAK: 00348 return "Signature method too weak"; 00349 case Certificate_Status_Code::UNTRUSTED_HASH: 00350 return "Untrusted hash"; 00351 00352 case Certificate_Status_Code::CERT_NOT_YET_VALID: 00353 return "Certificate is not yet valid"; 00354 case Certificate_Status_Code::CERT_HAS_EXPIRED: 00355 return "Certificate has expired"; 00356 case Certificate_Status_Code::OCSP_NOT_YET_VALID: 00357 return "OCSP is not yet valid"; 00358 case Certificate_Status_Code::OCSP_HAS_EXPIRED: 00359 return "OCSP has expired"; 00360 case Certificate_Status_Code::CRL_NOT_YET_VALID: 00361 return "CRL is not yet valid"; 00362 case Certificate_Status_Code::CRL_HAS_EXPIRED: 00363 return "CRL has expired"; 00364 00365 case Certificate_Status_Code::CERT_ISSUER_NOT_FOUND: 00366 return "Certificate issuer not found"; 00367 case Certificate_Status_Code::CANNOT_ESTABLISH_TRUST: 00368 return "Cannot establish trust"; 00369 00370 case Certificate_Status_Code::POLICY_ERROR: 00371 return "Policy error"; 00372 case Certificate_Status_Code::INVALID_USAGE: 00373 return "Invalid usage"; 00374 case Certificate_Status_Code::CERT_CHAIN_TOO_LONG: 00375 return "Certificate chain too long"; 00376 case Certificate_Status_Code::CA_CERT_NOT_FOR_CERT_ISSUER: 00377 return "CA certificate not allowed to issue certs"; 00378 case Certificate_Status_Code::CA_CERT_NOT_FOR_CRL_ISSUER: 00379 return "CA certificate not allowed to issue CRLs"; 00380 case Certificate_Status_Code::OCSP_CERT_NOT_LISTED: 00381 return "OCSP cert not listed"; 00382 case Certificate_Status_Code::OCSP_BAD_STATUS: 00383 return "OCSP bad status"; 00384 00385 case Certificate_Status_Code::CERT_IS_REVOKED: 00386 return "Certificate is revoked"; 00387 case Certificate_Status_Code::CRL_BAD_SIGNATURE: 00388 return "CRL bad signature"; 00389 case Certificate_Status_Code::SIGNATURE_ERROR: 00390 return "Signature error"; 00391 default: 00392 return "Unknown error"; 00393 } 00394 } 00395 00396 }