in fizz/protocol/DefaultCertificateVerifier.cpp [49:119]
void DefaultCertificateVerifier::verify(
const std::vector<std::shared_ptr<const fizz::PeerCert>>& certs) const {
if (certs.empty()) {
throw std::runtime_error("no certificates to verify");
}
auto leafCert = certs.front()->getX509();
auto certChainStack = std::unique_ptr<STACK_OF(X509), STACK_OF_X509_deleter>(
sk_X509_new_null());
if (!certChainStack) {
throw std::bad_alloc();
}
for (size_t i = 1; i < certs.size(); i++) {
sk_X509_push(certChainStack.get(), certs[i]->getX509().get());
}
auto ctx = folly::ssl::X509StoreCtxUniquePtr(X509_STORE_CTX_new());
if (!ctx) {
throw std::bad_alloc();
}
if (X509_STORE_CTX_init(
ctx.get(),
x509Store_ ? x509Store_.get() : getDefaultX509Store(),
leafCert.get(),
certChainStack.get()) != 1) {
throw std::runtime_error("failed to initialize store context");
}
if (X509_STORE_CTX_set_default(
ctx.get(),
context_ == VerificationContext::Server ? "ssl_client"
: "ssl_server") != 1) {
throw std::runtime_error("failed to set default verification method");
}
if (customVerifyCallback_) {
X509_STORE_CTX_set_verify_cb(ctx.get(), customVerifyCallback_);
}
folly::ssl::X509VerifyParam param(X509_VERIFY_PARAM_new());
if (!param) {
throw std::bad_alloc();
}
if (X509_VERIFY_PARAM_set_flags(param.get(), X509_V_FLAG_X509_STRICT) != 1) {
throw std::runtime_error("failed to set strict certificate checking");
}
if (X509_VERIFY_PARAM_set1(
X509_STORE_CTX_get0_param(ctx.get()), param.get()) != 1) {
throw std::runtime_error("failed to apply verification parameters");
}
int ret = 0;
// if openssl is not built with TSAN then we can get a TSAN false positive
// when calling X509_verify_cert from multiple threads
{
folly::annotate_ignore_thread_sanitizer_guard g(__FILE__, __LINE__);
ret = X509_verify_cert(ctx.get());
}
if (ret != 1) {
const auto errorInt = X509_STORE_CTX_get_error(ctx.get());
std::string errorText =
std::string(X509_verify_cert_error_string(errorInt));
throw std::runtime_error("certificate verification failed: " + errorText);
}
}