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