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