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