]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/cert_validate_message.cc
Source Format Enforcement (#532)
[thirdparty/squid.git] / src / ssl / cert_validate_message.cc
CommitLineData
bbc27441 1/*
77b1029d 2 * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
bbc27441
AJ
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
a1f04d64 9#include "squid.h"
77dce8a5 10#include "acl/FilledChecklist.h"
4747ea4c 11#include "globals.h"
a9b6afe1 12#include "helper.h"
92e3827b 13#include "security/CertError.h"
a1f04d64
AR
14#include "ssl/cert_validate_message.h"
15#include "ssl/ErrorDetail.h"
602d9612 16#include "ssl/support.h"
ed6e9fb9 17#include "util.h"
a1f04d64 18
8fe1a85a
CT
19/// Retrieves the certificates chain used to verify the peer.
20/// This is the full chain built by OpenSSL while verifying the server
21/// certificate or, if this is not available, the chain sent by server.
22/// \return the certificates chain or nil
23static STACK_OF(X509) *
24PeerValidationCertificatesChain(const Security::SessionPointer &ssl)
25{
26 assert(ssl);
27 // The full chain built by openSSL while verifying the server cert,
28 // retrieved from verify callback:
29 if (const auto certs = static_cast<STACK_OF(X509) *>(SSL_get_ex_data(ssl.get(), ssl_ex_index_ssl_cert_chain)))
30 return certs;
31
32 /// Last resort: certificates chain sent by server
33 return SSL_get_peer_cert_chain(ssl.get()); // may be nil
34}
35
3a7d782f 36void
b56756cb 37Ssl::CertValidationMsg::composeRequest(CertValidationRequest const &vcert)
a1f04d64
AR
38{
39 body.clear();
b56756cb 40 body += Ssl::CertValidationMsg::param_host + "=" + vcert.domainName;
4747ea4c 41
0b168d25 42 if (const char *sslVersion = SSL_get_version(vcert.ssl.get()))
6e325882
CT
43 body += "\n" + Ssl::CertValidationMsg::param_proto_version + "=" + sslVersion;
44
0b168d25 45 if (const char *cipherName = SSL_CIPHER_get_name(SSL_get_current_cipher(vcert.ssl.get())))
6e325882
CT
46 body += "\n" + Ssl::CertValidationMsg::param_cipher + "=" + cipherName;
47
8fe1a85a 48 STACK_OF(X509) *peerCerts = PeerValidationCertificatesChain(vcert.ssl);
14798e73 49 if (peerCerts) {
a1f04d64 50 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
14798e73
CT
51 for (int i = 0; i < sk_X509_num(peerCerts); ++i) {
52 X509 *cert = sk_X509_value(peerCerts, i);
a1f04d64 53 PEM_write_bio_X509(bio.get(), cert);
62a7607e 54 body = body + "\n" + param_cert + xitoa(i) + "=";
a1f04d64
AR
55 char *ptr;
56 long len = BIO_get_mem_data(bio.get(), &ptr);
62a7607e 57 body.append(ptr, (ptr[len-1] == '\n' ? len - 1 : len));
a1f04d64
AR
58 if (!BIO_reset(bio.get())) {
59 // print an error?
60 }
61 }
62 }
62a7607e
CT
63
64 if (vcert.errors) {
65 int i = 0;
92e3827b 66 for (const Security::CertErrors *err = vcert.errors; err; err = err->next, ++i) {
62a7607e
CT
67 body +="\n";
68 body = body + param_error_name + xitoa(i) + "=" + GetErrorName(err->element.code) + "\n";
69 int errorCertPos = -1;
170cb017 70 if (err->element.cert.get())
62a7607e
CT
71 errorCertPos = sk_X509_find(peerCerts, err->element.cert.get());
72 if (errorCertPos < 0) {
73 // assert this error ?
74 debugs(83, 4, "WARNING: wrong cert in cert validator request");
75 }
76 body += param_error_cert + xitoa(i) + "=";
77 body += param_cert + xitoa((errorCertPos >= 0 ? errorCertPos : 0));
78 }
79 }
a1f04d64
AR
80}
81
3a7d782f
CT
82static int
83get_error_id(const char *label, size_t len)
a1f04d64
AR
84{
85 const char *e = label + len -1;
86 while (e != label && xisdigit(*e)) --e;
87 if (e != label) ++e;
9e167fa2 88 return strtol(e, 0, 10);
a1f04d64
AR
89}
90
3a7d782f 91bool
8fe1a85a 92Ssl::CertValidationMsg::parseResponse(CertValidationResponse &resp, std::string &error)
a1f04d64 93{
3a7d782f 94 std::vector<CertItem> certs;
a1f04d64 95
8fe1a85a
CT
96 const STACK_OF(X509) *peerCerts = PeerValidationCertificatesChain(resp.ssl);
97
a1f04d64 98 const char *param = body.c_str();
22636a68
CT
99 while (*param) {
100 while (xisspace(*param)) param++;
a1f04d64
AR
101 if (! *param)
102 break;
103
104 size_t param_len = strcspn(param, "=\r\n");
105 if (param[param_len] != '=') {
4a77bb4e 106 debugs(83, DBG_IMPORTANT, "WARNING: cert validator response parse error: " << param);
a1f04d64
AR
107 return false;
108 }
109 const char *value=param+param_len+1;
110
22636a68
CT
111 if (param_len > param_cert.length() &&
112 strncmp(param, param_cert.c_str(), param_cert.length()) == 0) {
3a7d782f 113 CertItem ci;
22636a68 114 ci.name.assign(param, param_len);
f97700a0 115 Security::CertPointer x509;
a1f04d64
AR
116 readCertFromMemory(x509, value);
117 ci.setCert(x509.get());
118 certs.push_back(ci);
119
120 const char *b = strstr(value, "-----END CERTIFICATE-----");
121 if (b == NULL) {
4a77bb4e 122 debugs(83, DBG_IMPORTANT, "WARNING: cert Validator response parse error: Failed to find certificate boundary " << value);
a1f04d64
AR
123 return false;
124 }
125 b += strlen("-----END CERTIFICATE-----");
126 param = b + 1;
127 continue;
128 }
129
130 size_t value_len = strcspn(value, "\r\n");
131 std::string v(value, value_len);
132
4a77bb4e 133 debugs(83, 5, "Returned value: " << std::string(param, param_len).c_str() << ": " <<
a1f04d64
AR
134 v.c_str());
135
136 int errorId = get_error_id(param, param_len);
b56756cb 137 Ssl::CertValidationResponse::RecvdError &currentItem = resp.getError(errorId);
a1f04d64 138
22636a68
CT
139 if (param_len > param_error_name.length() &&
140 strncmp(param, param_error_name.c_str(), param_error_name.length()) == 0) {
a1f04d64 141 currentItem.error_no = Ssl::GetErrorCode(v.c_str());
3a7d782f 142 if (currentItem.error_no == SSL_ERROR_NONE) {
4a77bb4e 143 debugs(83, DBG_IMPORTANT, "WARNING: cert validator response parse error: Unknown SSL Error: " << v);
3a7d782f
CT
144 return false;
145 }
22636a68 146 } else if (param_len > param_error_reason.length() &&
a1f04d64
AR
147 strncmp(param, param_error_reason.c_str(), param_error_reason.length()) == 0) {
148 currentItem.error_reason = v;
149 } else if (param_len > param_error_cert.length() &&
150 strncmp(param, param_error_cert.c_str(), param_error_cert.length()) == 0) {
151
3a7d782f 152 if (X509 *cert = getCertByName(certs, v)) {
4a77bb4e 153 debugs(83, 6, "The certificate with id \"" << v << "\" found.");
3a7d782f
CT
154 currentItem.setCert(cert);
155 } else {
156 //In this case we assume that the certID is one of the certificates sent
157 // to cert validator. The certificates sent to cert validator have names in
158 // form "cert_xx" where the "xx" is an integer represents the position of
159 // the certificate inside peer certificates list.
b56756cb 160 const int certId = get_error_id(v.c_str(), v.length());
4a77bb4e 161 debugs(83, 6, "Cert index in peer certificates list:" << certId);
77dce8a5
CT
162 //if certId is not correct sk_X509_value returns NULL
163 currentItem.setCert(sk_X509_value(peerCerts, certId));
a1f04d64 164 }
b4e6a8d4
CT
165 } else if (param_len > param_error_depth.length() &&
166 strncmp(param, param_error_depth.c_str(), param_error_depth.length()) == 0 &&
167 std::all_of(v.begin(), v.end(), isdigit)) {
96e44f2e 168 currentItem.error_depth = atoi(v.c_str());
3a7d782f 169 } else {
4a77bb4e 170 debugs(83, DBG_IMPORTANT, "WARNING: cert validator response parse error: Unknown parameter name " << std::string(param, param_len).c_str());
3a7d782f
CT
171 return false;
172 }
a1f04d64 173
77da1d91 174 param = value + value_len;
a1f04d64
AR
175 }
176
3a7d782f 177 /*Run through parsed errors to check for errors*/
bc624572
CT
178 typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
179 for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
46901eed 180 if (i->error_no == SSL_ERROR_NONE) {
bc624572
CT
181 debugs(83, DBG_IMPORTANT, "WARNING: cert validator incomplete response: Missing error name from error_id: " << i->id);
182 return false;
183 }
184 }
a1f04d64
AR
185
186 return true;
187}
188
3a7d782f 189X509 *
b56756cb 190Ssl::CertValidationMsg::getCertByName(std::vector<CertItem> const &certs, std::string const & name)
3a7d782f 191{
6136ab56
CT
192 typedef std::vector<CertItem>::const_iterator SVCI;
193 for (SVCI ci = certs.begin(); ci != certs.end(); ++ci) {
3a7d782f 194 if (ci->name.compare(name) == 0)
4a77bb4e 195 return ci->cert.get();
3a7d782f
CT
196 }
197 return NULL;
198}
199
b56756cb
CT
200Ssl::CertValidationResponse::RecvdError &
201Ssl::CertValidationResponse::getError(int errorId)
3a7d782f 202{
6136ab56 203 typedef Ssl::CertValidationResponse::RecvdErrors::iterator SVCREI;
22636a68 204 for (SVCREI i = errors.begin(); i != errors.end(); ++i) {
3a7d782f
CT
205 if (i->id == errorId)
206 return *i;
207 }
b56756cb 208 Ssl::CertValidationResponse::RecvdError errItem;
3a7d782f
CT
209 errItem.id = errorId;
210 errors.push_back(errItem);
211 return errors.back();
212}
213
22636a68
CT
214Ssl::CertValidationResponse::RecvdError::RecvdError(const RecvdError &old)
215{
bc624572 216 id = old.id;
a1f04d64
AR
217 error_no = old.error_no;
218 error_reason = old.error_reason;
92862430 219 error_depth = old.error_depth;
4a77bb4e 220 setCert(old.cert.get());
a1f04d64
AR
221}
222
22636a68
CT
223Ssl::CertValidationResponse::RecvdError & Ssl::CertValidationResponse::RecvdError::operator = (const RecvdError &old)
224{
bc624572 225 id = old.id;
a1f04d64
AR
226 error_no = old.error_no;
227 error_reason = old.error_reason;
92862430 228 error_depth = old.error_depth;
4a77bb4e 229 setCert(old.cert.get());
a1f04d64
AR
230 return *this;
231}
232
233void
22636a68
CT
234Ssl::CertValidationResponse::RecvdError::setCert(X509 *aCert)
235{
4a77bb4e 236 cert.resetAndLock(aCert);
a1f04d64
AR
237}
238
b56756cb 239Ssl::CertValidationMsg::CertItem::CertItem(const CertItem &old)
a1f04d64
AR
240{
241 name = old.name;
4a77bb4e 242 setCert(old.cert.get());
a1f04d64
AR
243}
244
b56756cb 245Ssl::CertValidationMsg::CertItem & Ssl::CertValidationMsg::CertItem::operator = (const CertItem &old)
a1f04d64
AR
246{
247 name = old.name;
4a77bb4e 248 setCert(old.cert.get());
a1f04d64
AR
249 return *this;
250}
251
a1f04d64 252void
b56756cb 253Ssl::CertValidationMsg::CertItem::setCert(X509 *aCert)
a1f04d64 254{
4a77bb4e 255 cert.resetAndLock(aCert);
a1f04d64
AR
256}
257
b56756cb
CT
258const std::string Ssl::CertValidationMsg::code_cert_validate("cert_validate");
259const std::string Ssl::CertValidationMsg::param_domain("domain");
b56756cb 260const std::string Ssl::CertValidationMsg::param_cert("cert_");
22636a68 261const std::string Ssl::CertValidationMsg::param_error_name("error_name_");
b56756cb
CT
262const std::string Ssl::CertValidationMsg::param_error_reason("error_reason_");
263const std::string Ssl::CertValidationMsg::param_error_cert("error_cert_");
b4e6a8d4 264const std::string Ssl::CertValidationMsg::param_error_depth("error_depth_");
6e325882
CT
265const std::string Ssl::CertValidationMsg::param_proto_version("proto_version");
266const std::string Ssl::CertValidationMsg::param_cipher("cipher");
f53969cc 267