in source/common/http/conn_manager_utility.cc [256:331]
void ConnectionManagerUtility::mutateXfccRequestHeader(HeaderMap& request_headers,
Network::Connection& connection,
ConnectionManagerConfig& config) {
// When AlwaysForwardOnly is set, always forward the XFCC header without modification.
if (config.forwardClientCert() == ForwardClientCertType::AlwaysForwardOnly) {
return;
}
// When Sanitize is set, or the connection is not mutual TLS, remove the XFCC header.
if (config.forwardClientCert() == ForwardClientCertType::Sanitize ||
!(connection.ssl() && connection.ssl()->peerCertificatePresented())) {
request_headers.removeForwardedClientCert();
return;
}
// When ForwardOnly is set, always forward the XFCC header without modification.
if (config.forwardClientCert() == ForwardClientCertType::ForwardOnly) {
return;
}
// TODO(myidpt): Handle the special characters in By and URI fields.
// TODO: Optimize client_cert_details based on perf analysis (direct string appending may be more
// preferable).
std::vector<std::string> client_cert_details;
// When AppendForward or SanitizeSet is set, the client certificate information should be set into
// the XFCC header.
if (config.forwardClientCert() == ForwardClientCertType::AppendForward ||
config.forwardClientCert() == ForwardClientCertType::SanitizeSet) {
const std::string uri_san_local_cert = connection.ssl()->uriSanLocalCertificate();
if (!uri_san_local_cert.empty()) {
client_cert_details.push_back("By=" + uri_san_local_cert);
}
const std::string cert_digest = connection.ssl()->sha256PeerCertificateDigest();
if (!cert_digest.empty()) {
client_cert_details.push_back("Hash=" + cert_digest);
}
for (const auto& detail : config.setCurrentClientCertDetails()) {
switch (detail) {
case ClientCertDetailsType::Cert: {
const std::string peer_cert = connection.ssl()->urlEncodedPemEncodedPeerCertificate();
if (!peer_cert.empty()) {
client_cert_details.push_back("Cert=\"" + peer_cert + "\"");
}
break;
}
case ClientCertDetailsType::Subject:
// The "Subject" key still exists even if the subject is empty.
client_cert_details.push_back("Subject=\"" + connection.ssl()->subjectPeerCertificate() +
"\"");
break;
case ClientCertDetailsType::URI:
// The "URI" key still exists even if the URI is empty.
client_cert_details.push_back("URI=" + connection.ssl()->uriSanPeerCertificate());
break;
case ClientCertDetailsType::DNS: {
const std::vector<std::string> dns_sans = connection.ssl()->dnsSansPeerCertificate();
if (!dns_sans.empty()) {
for (const std::string& dns : dns_sans) {
client_cert_details.push_back("DNS=" + dns);
}
}
break;
}
}
}
}
const std::string client_cert_details_str = absl::StrJoin(client_cert_details, ";");
if (config.forwardClientCert() == ForwardClientCertType::AppendForward) {
HeaderMapImpl::appendToHeader(request_headers.insertForwardedClientCert().value(),
client_cert_details_str);
} else if (config.forwardClientCert() == ForwardClientCertType::SanitizeSet) {
request_headers.insertForwardedClientCert().value(client_cert_details_str);
} else {
NOT_REACHED_GCOVR_EXCL_LINE;
}
}