#include "ssl/support.h"
#include "util.h"
+/// Retrieves the certificates chain used to verify the peer.
+/// This is the full chain built by OpenSSL while verifying the server
+/// certificate or, if this is not available, the chain sent by server.
+/// \return the certificates chain or nil
+static STACK_OF(X509) *
+PeerValidationCertificatesChain(const Security::SessionPointer &ssl)
+{
+ assert(ssl);
+ // The full chain built by openSSL while verifying the server cert,
+ // retrieved from verify callback:
+ if (const auto certs = static_cast<STACK_OF(X509) *>(SSL_get_ex_data(ssl.get(), ssl_ex_index_ssl_cert_chain)))
+ return certs;
+
+ /// Last resort: certificates chain sent by server
+ return SSL_get_peer_cert_chain(ssl.get()); // may be nil
+}
+
void
Ssl::CertValidationMsg::composeRequest(CertValidationRequest const &vcert)
{
body.clear();
body += Ssl::CertValidationMsg::param_host + "=" + vcert.domainName;
- STACK_OF(X509) *peerCerts = static_cast<STACK_OF(X509) *>(SSL_get_ex_data(vcert.ssl.get(), ssl_ex_index_ssl_cert_chain));
if (const char *sslVersion = SSL_get_version(vcert.ssl.get()))
body += "\n" + Ssl::CertValidationMsg::param_proto_version + "=" + sslVersion;
if (const char *cipherName = SSL_CIPHER_get_name(SSL_get_current_cipher(vcert.ssl.get())))
body += "\n" + Ssl::CertValidationMsg::param_cipher + "=" + cipherName;
- if (!peerCerts)
- peerCerts = SSL_get_peer_cert_chain(vcert.ssl.get());
-
+ STACK_OF(X509) *peerCerts = PeerValidationCertificatesChain(vcert.ssl);
if (peerCerts) {
Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
for (int i = 0; i < sk_X509_num(peerCerts); ++i) {
}
bool
-Ssl::CertValidationMsg::parseResponse(CertValidationResponse &resp, STACK_OF(X509) *peerCerts, std::string &error)
+Ssl::CertValidationMsg::parseResponse(CertValidationResponse &resp, std::string &error)
{
std::vector<CertItem> certs;
+ const STACK_OF(X509) *peerCerts = PeerValidationCertificatesChain(resp.ssl);
+
const char *param = body.c_str();
while (*param) {
while (xisspace(*param)) param++;
};
typedef std::vector<RecvdError> RecvdErrors;
-
+ explicit CertValidationResponse(const Security::SessionPointer &aSession) : ssl(aSession) {}
/// Search in errors list for the error item with id=errorId.
/// If none found a new RecvdError item added with the given id;
RecvdError &getError(int errorId);
RecvdErrors errors; ///< The list of parsed errors
Helper::ResultCode resultCode; ///< The helper result code
+ Security::SessionPointer ssl;
};
/**
void composeRequest(CertValidationRequest const &vcert);
/// Parse a response message and fill the resp object with parsed informations
- bool parseResponse(CertValidationResponse &resp, STACK_OF(X509) *peerCerts, std::string &error);
+ bool parseResponse(CertValidationResponse &resp, std::string &error);
/// Search a CertItems list for the certificate with ID "name"
X509 *getCertByName(std::vector<CertItem> const &, std::string const & name);
sslCrtvdHandleReplyWrapper(void *data, const ::Helper::Reply &reply)
{
Ssl::CertValidationMsg replyMsg(Ssl::CrtdMessage::REPLY);
- Ssl::CertValidationResponse::Pointer validationResponse = new Ssl::CertValidationResponse;
std::string error;
submitData *crtdvdData = static_cast<submitData *>(data);
- STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(crtdvdData->ssl.get());
+ assert(crtdvdData->ssl.get());
+ Ssl::CertValidationResponse::Pointer validationResponse = new Ssl::CertValidationResponse(crtdvdData->ssl);
if (reply.result == ::Helper::BrokenHelper) {
debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content());
validationResponse->resultCode = ::Helper::BrokenHelper;
debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper returned NULL response");
validationResponse->resultCode = ::Helper::BrokenHelper;
} else if (replyMsg.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK ||
- !replyMsg.parseResponse(*validationResponse, peerCerts, error) ) {
+ !replyMsg.parseResponse(*validationResponse, error) ) {
debugs(83, DBG_IMPORTANT, "WARNING: Reply from ssl_crtvd for " << " is incorrect");
debugs(83, DBG_IMPORTANT, "Certificate cannot be validated. ssl_crtvd response: " << replyMsg.getBody());
validationResponse->resultCode = ::Helper::BrokenHelper;
}
if (!ssl_crt_validator->trySubmit(crtdvdData->query.c_str(), sslCrtvdHandleReplyWrapper, crtdvdData)) {
- Ssl::CertValidationResponse::Pointer resp = new Ssl::CertValidationResponse;;
+ Ssl::CertValidationResponse::Pointer resp = new Ssl::CertValidationResponse(crtdvdData->ssl);
resp->resultCode = ::Helper::BrokenHelper;
Ssl::CertValidationHelper::CbDialer *dialer = dynamic_cast<Ssl::CertValidationHelper::CbDialer*>(callback->getDialer());
Must(dialer);