/* * Return information about the subject */ std::vector<std::string> X509_Certificate::subject_info(const std::string& req) const { if(req == "Email") return this->subject_info("RFC822"); if(subject_dn().has_field(req)) return subject_dn().get_attribute(req); if(subject_alt_name().has_field(req)) return subject_alt_name().get_attribute(req); // These will be removed later: if(req == "X509.Certificate.v2.key_id") return {hex_encode(this->v2_subject_key_id())}; if(req == "X509v3.SubjectKeyIdentifier") return {hex_encode(this->subject_key_id())}; if(req == "X509.Certificate.dn_bits") return {hex_encode(this->raw_subject_dn())}; if(req == "X509.Certificate.start") return {not_before().to_string()}; if(req == "X509.Certificate.end") return {not_after().to_string()}; if(req == "X509.Certificate.version") return {std::to_string(x509_version())}; if(req == "X509.Certificate.serial") return {hex_encode(serial_number())}; return data().m_subject_ds.get(req); }
Test::Result test_response_certificate_access() { Test::Result result("OCSP response certificate access"); try { Botan::OCSP::Response resp1(Test::read_binary_data_file("x509/ocsp/resp1.der")); const auto &certs1 = resp1.certificates(); if(result.test_eq("Expected count of certificates", certs1.size(), 1)) { const auto cert = certs1.front(); const Botan::X509_DN expected_dn({std::make_pair( "X520.CommonName", "Symantec Class 3 EV SSL CA - G3 OCSP Responder")}); const bool matches = cert.subject_dn() == expected_dn; result.test_eq("CN matches expected", matches, true); } Botan::OCSP::Response resp2(Test::read_binary_data_file("x509/ocsp/resp2.der")); const auto &certs2 = resp2.certificates(); result.test_eq("Expect no certificates", certs2.size(), 0); } catch(Botan::Exception& e) { result.test_failure("Parsing failed", e.what()); } return result; }
std::vector<X509_DN> Certificate_Store_MacOS::all_subjects() const { scoped_CFType<CFArrayRef> result(m_impl->search()); if(!result) { return {}; // not a single certificate found in the keychain } const auto count = CFArrayGetCount(result.get()); BOTAN_ASSERT(count > 0, "subject result list contains data"); std::vector<X509_DN> output; output.reserve(count); for(unsigned int i = 0; i < count; ++i) { // Note: Apple's API provides SecCertificateCopyNormalizedSubjectSequence // which would have saved us from reading a Botan::X509_Certificate, // however, this function applies the same DN "normalization" as // stated above. auto cfCert = to_SecCertificateRef(CFArrayGetValueAtIndex(result.get(), i)); auto cert = readCertificate(cfCert); output.emplace_back(cert->subject_dn()); } return output; }
std::string X509_Certificate::to_string() const { std::ostringstream out; out << "Version: " << this->x509_version() << "\n"; out << "Subject: " << subject_dn() << "\n"; out << "Issuer: " << issuer_dn() << "\n"; out << "Issued: " << this->not_before().readable_string() << "\n"; out << "Expires: " << this->not_after().readable_string() << "\n"; out << "Constraints:\n"; Key_Constraints constraints = this->constraints(); if(constraints == NO_CONSTRAINTS) out << " None\n"; else { if(constraints & DIGITAL_SIGNATURE) out << " Digital Signature\n"; if(constraints & NON_REPUDIATION) out << " Non-Repudiation\n"; if(constraints & KEY_ENCIPHERMENT) out << " Key Encipherment\n"; if(constraints & DATA_ENCIPHERMENT) out << " Data Encipherment\n"; if(constraints & KEY_AGREEMENT) out << " Key Agreement\n"; if(constraints & KEY_CERT_SIGN) out << " Cert Sign\n"; if(constraints & CRL_SIGN) out << " CRL Sign\n"; if(constraints & ENCIPHER_ONLY) out << " Encipher Only\n"; if(constraints & DECIPHER_ONLY) out << " Decipher Only\n"; } const std::vector<OID> policies = this->certificate_policy_oids(); if(!policies.empty()) { out << "Policies: " << "\n"; for(auto oid : policies) out << " " << oid.as_string() << "\n"; } std::vector<OID> ex_constraints = this->extended_key_usage(); if(!ex_constraints.empty()) { out << "Extended Constraints:\n"; for(size_t i = 0; i != ex_constraints.size(); i++) out << " " << OIDS::oid2str(ex_constraints[i]) << "\n"; } const NameConstraints& name_constraints = this->name_constraints(); if(!name_constraints.permitted().empty() || !name_constraints.excluded().empty()) { out << "Name Constraints:\n"; if(!name_constraints.permitted().empty()) { out << " Permit"; for(auto st: name_constraints.permitted()) { out << " " << st.base(); } out << "\n"; } if(!name_constraints.excluded().empty()) { out << " Exclude"; for(auto st: name_constraints.excluded()) { out << " " << st.base(); } out << "\n"; } } if(!ocsp_responder().empty()) out << "OCSP responder " << ocsp_responder() << "\n"; std::vector<std::string> ca_issuers = this->ca_issuers(); if(!ca_issuers.empty()) { out << "CA Issuers:\n"; for(size_t i = 0; i != ca_issuers.size(); i++) out << " URI: " << ca_issuers[i] << "\n"; } if(!crl_distribution_point().empty()) out << "CRL " << crl_distribution_point() << "\n"; out << "Signature algorithm: " << OIDS::oid2str(this->signature_algorithm().get_oid()) << "\n"; out << "Serial number: " << hex_encode(this->serial_number()) << "\n"; if(this->authority_key_id().size()) out << "Authority keyid: " << hex_encode(this->authority_key_id()) << "\n"; if(this->subject_key_id().size()) out << "Subject keyid: " << hex_encode(this->subject_key_id()) << "\n"; try { std::unique_ptr<Public_Key> pubkey(this->subject_public_key()); out << "Public Key [" << pubkey->algo_name() << "-" << pubkey->key_length() << "]\n\n"; out << X509::PEM_encode(*pubkey); } catch(Decoding_Error&) { const AlgorithmIdentifier& alg_id = this->subject_public_key_algo(); out << "Failed to decode key with oid " << alg_id.get_oid().as_string() << "\n"; } return out.str(); }