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