]> git.ipfire.org Git - thirdparty/squid.git/blob - src/ssl/cert_validate_message.cc
Send selected SSL version and cipher to the certificate validation helper.
[thirdparty/squid.git] / src / ssl / cert_validate_message.cc
1 /*
2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
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
9 #include "squid.h"
10 #include "acl/FilledChecklist.h"
11 #include "globals.h"
12 #include "helper.h"
13 #include "ssl/cert_validate_message.h"
14 #include "ssl/ErrorDetail.h"
15 #include "ssl/support.h"
16
17 void
18 Ssl::CertValidationMsg::composeRequest(CertValidationRequest const &vcert)
19 {
20 body.clear();
21 body += Ssl::CertValidationMsg::param_host + "=" + vcert.domainName;
22 STACK_OF(X509) *peerCerts = static_cast<STACK_OF(X509) *>(SSL_get_ex_data(vcert.ssl, ssl_ex_index_ssl_cert_chain));
23
24 if (const char *sslVersion = SSL_get_version(vcert.ssl))
25 body += "\n" + Ssl::CertValidationMsg::param_proto_version + "=" + sslVersion;
26
27 if (const char *cipherName = SSL_CIPHER_get_name(SSL_get_current_cipher(vcert.ssl)))
28 body += "\n" + Ssl::CertValidationMsg::param_cipher + "=" + cipherName;
29
30 if (!peerCerts)
31 peerCerts = SSL_get_peer_cert_chain(vcert.ssl);
32
33 if (peerCerts) {
34 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
35 for (int i = 0; i < sk_X509_num(peerCerts); ++i) {
36 X509 *cert = sk_X509_value(peerCerts, i);
37 PEM_write_bio_X509(bio.get(), cert);
38 body = body + "\n" + param_cert + xitoa(i) + "=";
39 char *ptr;
40 long len = BIO_get_mem_data(bio.get(), &ptr);
41 body.append(ptr, (ptr[len-1] == '\n' ? len - 1 : len));
42 if (!BIO_reset(bio.get())) {
43 // print an error?
44 }
45 }
46 }
47
48 if (vcert.errors) {
49 int i = 0;
50 for (const Ssl::CertErrors *err = vcert.errors; err; err = err->next, ++i) {
51 body +="\n";
52 body = body + param_error_name + xitoa(i) + "=" + GetErrorName(err->element.code) + "\n";
53 int errorCertPos = -1;
54 if (err->element.cert.get())
55 errorCertPos = sk_X509_find(peerCerts, err->element.cert.get());
56 if (errorCertPos < 0) {
57 // assert this error ?
58 debugs(83, 4, "WARNING: wrong cert in cert validator request");
59 }
60 body += param_error_cert + xitoa(i) + "=";
61 body += param_cert + xitoa((errorCertPos >= 0 ? errorCertPos : 0));
62 }
63 }
64 }
65
66 static int
67 get_error_id(const char *label, size_t len)
68 {
69 const char *e = label + len -1;
70 while (e != label && xisdigit(*e)) --e;
71 if (e != label) ++e;
72 return strtol(e, 0 , 10);
73 }
74
75 bool
76 Ssl::CertValidationMsg::parseResponse(CertValidationResponse &resp, STACK_OF(X509) *peerCerts, std::string &error)
77 {
78 std::vector<CertItem> certs;
79
80 const char *param = body.c_str();
81 while (*param) {
82 while (xisspace(*param)) param++;
83 if (! *param)
84 break;
85
86 size_t param_len = strcspn(param, "=\r\n");
87 if (param[param_len] != '=') {
88 debugs(83, DBG_IMPORTANT, "WARNING: cert validator response parse error: " << param);
89 return false;
90 }
91 const char *value=param+param_len+1;
92
93 if (param_len > param_cert.length() &&
94 strncmp(param, param_cert.c_str(), param_cert.length()) == 0) {
95 CertItem ci;
96 ci.name.assign(param, param_len);
97 X509_Pointer x509;
98 readCertFromMemory(x509, value);
99 ci.setCert(x509.get());
100 certs.push_back(ci);
101
102 const char *b = strstr(value, "-----END CERTIFICATE-----");
103 if (b == NULL) {
104 debugs(83, DBG_IMPORTANT, "WARNING: cert Validator response parse error: Failed to find certificate boundary " << value);
105 return false;
106 }
107 b += strlen("-----END CERTIFICATE-----");
108 param = b + 1;
109 continue;
110 }
111
112 size_t value_len = strcspn(value, "\r\n");
113 std::string v(value, value_len);
114
115 debugs(83, 5, "Returned value: " << std::string(param, param_len).c_str() << ": " <<
116 v.c_str());
117
118 int errorId = get_error_id(param, param_len);
119 Ssl::CertValidationResponse::RecvdError &currentItem = resp.getError(errorId);
120
121 if (param_len > param_error_name.length() &&
122 strncmp(param, param_error_name.c_str(), param_error_name.length()) == 0) {
123 currentItem.error_no = Ssl::GetErrorCode(v.c_str());
124 if (currentItem.error_no == SSL_ERROR_NONE) {
125 debugs(83, DBG_IMPORTANT, "WARNING: cert validator response parse error: Unknown SSL Error: " << v);
126 return false;
127 }
128 } else if (param_len > param_error_reason.length() &&
129 strncmp(param, param_error_reason.c_str(), param_error_reason.length()) == 0) {
130 currentItem.error_reason = v;
131 } else if (param_len > param_error_cert.length() &&
132 strncmp(param, param_error_cert.c_str(), param_error_cert.length()) == 0) {
133
134 if (X509 *cert = getCertByName(certs, v)) {
135 debugs(83, 6, "The certificate with id \"" << v << "\" found.");
136 currentItem.setCert(cert);
137 } else {
138 //In this case we assume that the certID is one of the certificates sent
139 // to cert validator. The certificates sent to cert validator have names in
140 // form "cert_xx" where the "xx" is an integer represents the position of
141 // the certificate inside peer certificates list.
142 const int certId = get_error_id(v.c_str(), v.length());
143 debugs(83, 6, "Cert index in peer certificates list:" << certId);
144 //if certId is not correct sk_X509_value returns NULL
145 currentItem.setCert(sk_X509_value(peerCerts, certId));
146 }
147 } else {
148 debugs(83, DBG_IMPORTANT, "WARNING: cert validator response parse error: Unknown parameter name " << std::string(param, param_len).c_str());
149 return false;
150 }
151
152 param = value + value_len +1;
153 }
154
155 /*Run through parsed errors to check for errors*/
156 typedef Ssl::CertValidationResponse::RecvdErrors::const_iterator SVCRECI;
157 for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
158 if (i->error_no == SSL_ERROR_NONE) {
159 debugs(83, DBG_IMPORTANT, "WARNING: cert validator incomplete response: Missing error name from error_id: " << i->id);
160 return false;
161 }
162 }
163
164 return true;
165 }
166
167 X509 *
168 Ssl::CertValidationMsg::getCertByName(std::vector<CertItem> const &certs, std::string const & name)
169 {
170 typedef std::vector<CertItem>::const_iterator SVCI;
171 for (SVCI ci = certs.begin(); ci != certs.end(); ++ci) {
172 if (ci->name.compare(name) == 0)
173 return ci->cert.get();
174 }
175 return NULL;
176 }
177
178 Ssl::CertValidationResponse::RecvdError &
179 Ssl::CertValidationResponse::getError(int errorId)
180 {
181 typedef Ssl::CertValidationResponse::RecvdErrors::iterator SVCREI;
182 for (SVCREI i = errors.begin(); i != errors.end(); ++i) {
183 if (i->id == errorId)
184 return *i;
185 }
186 Ssl::CertValidationResponse::RecvdError errItem;
187 errItem.id = errorId;
188 errors.push_back(errItem);
189 return errors.back();
190 }
191
192 Ssl::CertValidationResponse::RecvdError::RecvdError(const RecvdError &old)
193 {
194 id = old.id;
195 error_no = old.error_no;
196 error_reason = old.error_reason;
197 setCert(old.cert.get());
198 }
199
200 Ssl::CertValidationResponse::RecvdError & Ssl::CertValidationResponse::RecvdError::operator = (const RecvdError &old)
201 {
202 id = old.id;
203 error_no = old.error_no;
204 error_reason = old.error_reason;
205 setCert(old.cert.get());
206 return *this;
207 }
208
209 void
210 Ssl::CertValidationResponse::RecvdError::setCert(X509 *aCert)
211 {
212 cert.resetAndLock(aCert);
213 }
214
215 Ssl::CertValidationMsg::CertItem::CertItem(const CertItem &old)
216 {
217 name = old.name;
218 setCert(old.cert.get());
219 }
220
221 Ssl::CertValidationMsg::CertItem & Ssl::CertValidationMsg::CertItem::operator = (const CertItem &old)
222 {
223 name = old.name;
224 setCert(old.cert.get());
225 return *this;
226 }
227
228 void
229 Ssl::CertValidationMsg::CertItem::setCert(X509 *aCert)
230 {
231 cert.resetAndLock(aCert);
232 }
233
234 const std::string Ssl::CertValidationMsg::code_cert_validate("cert_validate");
235 const std::string Ssl::CertValidationMsg::param_domain("domain");
236 const std::string Ssl::CertValidationMsg::param_cert("cert_");
237 const std::string Ssl::CertValidationMsg::param_error_name("error_name_");
238 const std::string Ssl::CertValidationMsg::param_error_reason("error_reason_");
239 const std::string Ssl::CertValidationMsg::param_error_cert("error_cert_");
240 const std::string Ssl::CertValidationMsg::param_proto_version("proto_version");
241 const std::string Ssl::CertValidationMsg::param_cipher("cipher");