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