]>
Commit | Line | Data |
---|---|---|
582c2af2 | 1 | #include "squid.h" |
02259ff8 | 2 | #include "errorpage.h" |
4d16918e | 3 | #include "ssl/ErrorDetail.h" |
cf09bec7 CT |
4 | #if HAVE_MAP |
5 | #include <map> | |
6 | #endif | |
582c2af2 FC |
7 | #if HAVE_CLIMITS |
8 | #include <climits> | |
9 | #endif | |
4d16918e | 10 | |
dc49061a | 11 | struct SslErrorEntry { |
461b9576 | 12 | Ssl::ssl_error_t value; |
4d16918e | 13 | const char *name; |
4d16918e CT |
14 | }; |
15 | ||
8e9bae99 | 16 | static const char *SslErrorDetailDefaultStr = "SSL handshake error (%err_name)"; |
cf09bec7 | 17 | //Use std::map to optimize search |
02259ff8 CT |
18 | typedef std::map<Ssl::ssl_error_t, const SslErrorEntry *> SslErrors; |
19 | SslErrors TheSslErrors; | |
cf09bec7 | 20 | |
02259ff8 | 21 | static SslErrorEntry TheSslErrorArray[] = { |
0ad3ff51 | 22 | {SQUID_X509_V_ERR_INFINITE_VALIDATION, |
3cc296c4 | 23 | "SQUID_X509_V_ERR_INFINITE_VALIDATION"}, |
e7bcc25f | 24 | {SQUID_X509_V_ERR_CERT_CHANGE, |
3cc296c4 | 25 | "SQUID_X509_V_ERR_CERT_CHANGE"}, |
8e9bae99 | 26 | {SQUID_ERR_SSL_HANDSHAKE, |
87f237a9 | 27 | "SQUID_ERR_SSL_HANDSHAKE"}, |
7698a79c | 28 | {SQUID_X509_V_ERR_DOMAIN_MISMATCH, |
ef5fbcff | 29 | "SQUID_X509_V_ERR_DOMAIN_MISMATCH"}, |
2c3d5aec | 30 | {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, |
0db46e4f | 31 | "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"}, |
2c3d5aec | 32 | {X509_V_ERR_UNABLE_TO_GET_CRL, |
02259ff8 | 33 | "X509_V_ERR_UNABLE_TO_GET_CRL"}, |
2c3d5aec | 34 | {X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, |
02259ff8 | 35 | "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"}, |
2c3d5aec | 36 | {X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, |
02259ff8 | 37 | "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"}, |
2c3d5aec | 38 | {X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, |
02259ff8 | 39 | "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"}, |
2c3d5aec | 40 | {X509_V_ERR_CERT_SIGNATURE_FAILURE, |
02259ff8 | 41 | "X509_V_ERR_CERT_SIGNATURE_FAILURE"}, |
cf09bec7 | 42 | {X509_V_ERR_CRL_SIGNATURE_FAILURE, |
02259ff8 | 43 | "X509_V_ERR_CRL_SIGNATURE_FAILURE"}, |
cf09bec7 | 44 | {X509_V_ERR_CERT_NOT_YET_VALID, |
02259ff8 | 45 | "X509_V_ERR_CERT_NOT_YET_VALID"}, |
cf09bec7 | 46 | {X509_V_ERR_CERT_HAS_EXPIRED, |
02259ff8 | 47 | "X509_V_ERR_CERT_HAS_EXPIRED"}, |
cf09bec7 | 48 | {X509_V_ERR_CRL_NOT_YET_VALID, |
02259ff8 | 49 | "X509_V_ERR_CRL_NOT_YET_VALID"}, |
cf09bec7 | 50 | {X509_V_ERR_CRL_HAS_EXPIRED, |
02259ff8 | 51 | "X509_V_ERR_CRL_HAS_EXPIRED"}, |
cf09bec7 | 52 | {X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, |
02259ff8 | 53 | "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"}, |
cf09bec7 | 54 | {X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, |
02259ff8 | 55 | "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"}, |
cf09bec7 | 56 | {X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD, |
02259ff8 | 57 | "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"}, |
cf09bec7 | 58 | {X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, |
02259ff8 | 59 | "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"}, |
cf09bec7 | 60 | {X509_V_ERR_OUT_OF_MEM, |
02259ff8 | 61 | "X509_V_ERR_OUT_OF_MEM"}, |
4d16918e | 62 | {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, |
02259ff8 | 63 | "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"}, |
cf09bec7 | 64 | {X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, |
02259ff8 | 65 | "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"}, |
cf09bec7 | 66 | {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, |
02259ff8 | 67 | "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"}, |
cf09bec7 | 68 | {X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, |
02259ff8 | 69 | "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"}, |
cf09bec7 | 70 | {X509_V_ERR_CERT_CHAIN_TOO_LONG, |
02259ff8 | 71 | "X509_V_ERR_CERT_CHAIN_TOO_LONG"}, |
cf09bec7 | 72 | {X509_V_ERR_CERT_REVOKED, |
02259ff8 | 73 | "X509_V_ERR_CERT_REVOKED"}, |
cf09bec7 | 74 | {X509_V_ERR_INVALID_CA, |
02259ff8 | 75 | "X509_V_ERR_INVALID_CA"}, |
cf09bec7 | 76 | {X509_V_ERR_PATH_LENGTH_EXCEEDED, |
02259ff8 | 77 | "X509_V_ERR_PATH_LENGTH_EXCEEDED"}, |
cf09bec7 | 78 | {X509_V_ERR_INVALID_PURPOSE, |
02259ff8 | 79 | "X509_V_ERR_INVALID_PURPOSE"}, |
cf09bec7 | 80 | {X509_V_ERR_CERT_UNTRUSTED, |
02259ff8 | 81 | "X509_V_ERR_CERT_UNTRUSTED"}, |
cf09bec7 | 82 | {X509_V_ERR_CERT_REJECTED, |
02259ff8 | 83 | "X509_V_ERR_CERT_REJECTED"}, |
cf09bec7 | 84 | {X509_V_ERR_SUBJECT_ISSUER_MISMATCH, |
02259ff8 | 85 | "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"}, |
cf09bec7 | 86 | {X509_V_ERR_AKID_SKID_MISMATCH, |
02259ff8 | 87 | "X509_V_ERR_AKID_SKID_MISMATCH"}, |
cf09bec7 | 88 | {X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH, |
02259ff8 | 89 | "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"}, |
cf09bec7 | 90 | {X509_V_ERR_KEYUSAGE_NO_CERTSIGN, |
02259ff8 | 91 | "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"}, |
7a62af61 CT |
92 | #if defined(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER) |
93 | {X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, //33 | |
94 | "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"}, | |
95 | #endif | |
96 | #if defined(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) | |
97 | {X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, //34 | |
98 | "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"}, | |
99 | #endif | |
100 | #if defined(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN) | |
101 | {X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, //35 | |
102 | "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"}, | |
103 | #endif | |
104 | #if defined(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION) | |
105 | {X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, //36 | |
106 | "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"}, | |
107 | #endif | |
108 | #if defined(X509_V_ERR_INVALID_NON_CA) | |
109 | {X509_V_ERR_INVALID_NON_CA, //37 | |
110 | "X509_V_ERR_INVALID_NON_CA"}, | |
111 | #endif | |
112 | #if defined(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED) | |
113 | {X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, //38 | |
114 | "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"}, | |
115 | #endif | |
116 | #if defined(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE) | |
117 | {X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, //39 | |
118 | "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"}, | |
119 | #endif | |
120 | #if defined(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED) | |
121 | {X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, //40 | |
122 | "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"}, | |
123 | #endif | |
124 | #if defined(X509_V_ERR_INVALID_EXTENSION) | |
125 | {X509_V_ERR_INVALID_EXTENSION, //41 | |
126 | "X509_V_ERR_INVALID_EXTENSION"}, | |
127 | #endif | |
128 | #if defined(X509_V_ERR_INVALID_POLICY_EXTENSION) | |
129 | {X509_V_ERR_INVALID_POLICY_EXTENSION, //42 | |
130 | "X509_V_ERR_INVALID_POLICY_EXTENSION"}, | |
131 | #endif | |
132 | #if defined(X509_V_ERR_NO_EXPLICIT_POLICY) | |
133 | {X509_V_ERR_NO_EXPLICIT_POLICY, //43 | |
134 | "X509_V_ERR_NO_EXPLICIT_POLICY"}, | |
135 | #endif | |
136 | #if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE) | |
137 | {X509_V_ERR_DIFFERENT_CRL_SCOPE, //44 | |
138 | "X509_V_ERR_DIFFERENT_CRL_SCOPE"}, | |
139 | #endif | |
140 | #if defined(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE) | |
141 | {X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, //45 | |
142 | "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE"}, | |
143 | #endif | |
144 | #if defined(X509_V_ERR_UNNESTED_RESOURCE) | |
145 | {X509_V_ERR_UNNESTED_RESOURCE, //46 | |
146 | "X509_V_ERR_UNNESTED_RESOURCE"}, | |
147 | #endif | |
148 | #if defined(X509_V_ERR_PERMITTED_VIOLATION) | |
149 | {X509_V_ERR_PERMITTED_VIOLATION, //47 | |
150 | "X509_V_ERR_PERMITTED_VIOLATION"}, | |
151 | #endif | |
152 | #if defined(X509_V_ERR_EXCLUDED_VIOLATION) | |
153 | {X509_V_ERR_EXCLUDED_VIOLATION, //48 | |
154 | "X509_V_ERR_EXCLUDED_VIOLATION"}, | |
155 | #endif | |
156 | #if defined(X509_V_ERR_SUBTREE_MINMAX) | |
157 | {X509_V_ERR_SUBTREE_MINMAX, //49 | |
158 | "X509_V_ERR_SUBTREE_MINMAX"}, | |
159 | #endif | |
160 | #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE) | |
161 | {X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, //51 | |
162 | "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE"}, | |
163 | #endif | |
164 | #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX) | |
165 | {X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, //52 | |
166 | "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX"}, | |
167 | #endif | |
168 | #if defined(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX) | |
169 | {X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, //53 | |
170 | "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX"}, | |
171 | #endif | |
172 | #if defined(X509_V_ERR_CRL_PATH_VALIDATION_ERROR) | |
173 | {X509_V_ERR_CRL_PATH_VALIDATION_ERROR, //54 | |
174 | "X509_V_ERR_CRL_PATH_VALIDATION_ERROR"}, | |
175 | #endif | |
cf09bec7 | 176 | {X509_V_ERR_APPLICATION_VERIFICATION, |
02259ff8 CT |
177 | "X509_V_ERR_APPLICATION_VERIFICATION"}, |
178 | { SSL_ERROR_NONE, "SSL_ERROR_NONE"}, | |
179 | {SSL_ERROR_NONE, NULL} | |
4d16918e CT |
180 | }; |
181 | ||
cf1c09f6 CT |
182 | struct SslErrorAlias { |
183 | const char *name; | |
184 | const Ssl::ssl_error_t *errors; | |
185 | }; | |
186 | ||
187 | static const Ssl::ssl_error_t hasExpired[] = {X509_V_ERR_CERT_HAS_EXPIRED, SSL_ERROR_NONE}; | |
188 | static const Ssl::ssl_error_t notYetValid[] = {X509_V_ERR_CERT_NOT_YET_VALID, SSL_ERROR_NONE}; | |
189 | static const Ssl::ssl_error_t domainMismatch[] = {SQUID_X509_V_ERR_DOMAIN_MISMATCH, SSL_ERROR_NONE}; | |
190 | static const Ssl::ssl_error_t certUntrusted[] = {X509_V_ERR_INVALID_CA, | |
87f237a9 A |
191 | X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, |
192 | X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, | |
193 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, | |
194 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, | |
195 | X509_V_ERR_CERT_UNTRUSTED, SSL_ERROR_NONE | |
196 | }; | |
cf1c09f6 CT |
197 | static const Ssl::ssl_error_t certSelfSigned[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_ERROR_NONE}; |
198 | ||
199 | // The list of error name shortcuts for use with ssl_error acls. | |
200 | // The keys without the "ssl::" scope prefix allow shorter error | |
201 | // names within the SSL options scope. This is easier than | |
7a957a93 | 202 | // carefully stripping the scope prefix in Ssl::ParseErrorString(). |
cf1c09f6 CT |
203 | static SslErrorAlias TheSslErrorShortcutsArray[] = { |
204 | {"ssl::certHasExpired", hasExpired}, | |
205 | {"certHasExpired", hasExpired}, | |
206 | {"ssl::certNotYetValid", notYetValid}, | |
207 | {"certNotYetValid", notYetValid}, | |
208 | {"ssl::certDomainMismatch", domainMismatch}, | |
209 | {"certDomainMismatch", domainMismatch}, | |
210 | {"ssl::certUntrusted", certUntrusted}, | |
211 | {"certUntrusted", certUntrusted}, | |
212 | {"ssl::certSelfSigned", certSelfSigned}, | |
213 | {"certSelfSigned", certSelfSigned}, | |
214 | {NULL, NULL} | |
215 | }; | |
216 | ||
7a957a93 | 217 | // Use std::map to optimize search. |
cf1c09f6 CT |
218 | typedef std::map<std::string, const Ssl::ssl_error_t *> SslErrorShortcuts; |
219 | SslErrorShortcuts TheSslErrorShortcuts; | |
220 | ||
02259ff8 | 221 | static void loadSslErrorMap() |
cf09bec7 | 222 | { |
02259ff8 CT |
223 | assert(TheSslErrors.empty()); |
224 | for (int i = 0; TheSslErrorArray[i].name; ++i) { | |
225 | TheSslErrors[TheSslErrorArray[i].value] = &TheSslErrorArray[i]; | |
cf09bec7 CT |
226 | } |
227 | } | |
228 | ||
cf1c09f6 CT |
229 | static void loadSslErrorShortcutsMap() |
230 | { | |
231 | assert(TheSslErrorShortcuts.empty()); | |
a38ec4b1 | 232 | for (int i = 0; TheSslErrorShortcutsArray[i].name; ++i) |
cf1c09f6 CT |
233 | TheSslErrorShortcuts[TheSslErrorShortcutsArray[i].name] = TheSslErrorShortcutsArray[i].errors; |
234 | } | |
235 | ||
02259ff8 CT |
236 | Ssl::ssl_error_t Ssl::GetErrorCode(const char *name) |
237 | { | |
d7ae3534 FC |
238 | //TODO: use a std::map? |
239 | for (int i = 0; TheSslErrorArray[i].name != NULL; ++i) { | |
02259ff8 CT |
240 | if (strcmp(name, TheSslErrorArray[i].name) == 0) |
241 | return TheSslErrorArray[i].value; | |
242 | } | |
243 | return SSL_ERROR_NONE; | |
244 | } | |
245 | ||
cf1c09f6 | 246 | Ssl::Errors * |
5e430bf3 | 247 | Ssl::ParseErrorString(const char *name) |
4d16918e CT |
248 | { |
249 | assert(name); | |
250 | ||
02259ff8 CT |
251 | const Ssl::ssl_error_t ssl_error = GetErrorCode(name); |
252 | if (ssl_error != SSL_ERROR_NONE) | |
cf1c09f6 | 253 | return new Ssl::Errors(ssl_error); |
4d16918e CT |
254 | |
255 | if (xisdigit(*name)) { | |
256 | const long int value = strtol(name, NULL, 0); | |
257 | if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX) | |
cf1c09f6 | 258 | return new Ssl::Errors(value); |
4d16918e CT |
259 | fatalf("Too small or too bug SSL error code '%s'", name); |
260 | } | |
261 | ||
cf1c09f6 CT |
262 | if (TheSslErrorShortcuts.empty()) |
263 | loadSslErrorShortcutsMap(); | |
264 | ||
265 | const SslErrorShortcuts::const_iterator it = TheSslErrorShortcuts.find(name); | |
266 | if (it != TheSslErrorShortcuts.end()) { | |
267 | // Should not be empty... | |
87f237a9 | 268 | assert(it->second[0] != SSL_ERROR_NONE); |
cf1c09f6 | 269 | Ssl::Errors *errors = new Ssl::Errors(it->second[0]); |
a38ec4b1 | 270 | for (int i =1; it->second[i] != SSL_ERROR_NONE; ++i) { |
cf1c09f6 CT |
271 | errors->push_back_unique(it->second[i]); |
272 | } | |
273 | return errors; | |
274 | } | |
275 | ||
4d16918e | 276 | fatalf("Unknown SSL error name '%s'", name); |
cf1c09f6 | 277 | return NULL; // not reached |
4d16918e CT |
278 | } |
279 | ||
02259ff8 | 280 | const char *Ssl::GetErrorName(Ssl::ssl_error_t value) |
cf09bec7 | 281 | { |
02259ff8 CT |
282 | if (TheSslErrors.empty()) |
283 | loadSslErrorMap(); | |
cf09bec7 | 284 | |
02259ff8 CT |
285 | const SslErrors::const_iterator it = TheSslErrors.find(value); |
286 | if (it != TheSslErrors.end()) | |
287 | return it->second->name; | |
4d16918e CT |
288 | |
289 | return NULL; | |
290 | } | |
291 | ||
cf09bec7 CT |
292 | const char * |
293 | Ssl::GetErrorDescr(Ssl::ssl_error_t value) | |
294 | { | |
02259ff8 | 295 | return ErrorDetailsManager::GetInstance().getDefaultErrorDescr(value); |
cf09bec7 CT |
296 | } |
297 | ||
e34763f4 | 298 | Ssl::ErrorDetail::err_frm_code Ssl::ErrorDetail::ErrorFormatingCodes[] = { |
4d16918e CT |
299 | {"ssl_subject", &Ssl::ErrorDetail::subject}, |
300 | {"ssl_ca_name", &Ssl::ErrorDetail::ca_name}, | |
301 | {"ssl_cn", &Ssl::ErrorDetail::cn}, | |
302 | {"ssl_notbefore", &Ssl::ErrorDetail::notbefore}, | |
303 | {"ssl_notafter", &Ssl::ErrorDetail::notafter}, | |
304 | {"err_name", &Ssl::ErrorDetail::err_code}, | |
cf09bec7 | 305 | {"ssl_error_descr", &Ssl::ErrorDetail::err_descr}, |
8e9bae99 | 306 | {"ssl_lib_error", &Ssl::ErrorDetail::err_lib_error}, |
4d16918e CT |
307 | {NULL,NULL} |
308 | }; | |
309 | ||
310 | /** | |
311 | * The subject of the current certification in text form | |
312 | */ | |
313 | const char *Ssl::ErrorDetail::subject() const | |
314 | { | |
ff3bc018 | 315 | if (!broken_cert) |
4d16918e CT |
316 | return "[Not available]"; |
317 | ||
318 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 319 | X509_NAME_oneline(X509_get_subject_name(broken_cert.get()), tmpBuffer, |
e34763f4 A |
320 | sizeof(tmpBuffer)); |
321 | return tmpBuffer; | |
4d16918e CT |
322 | } |
323 | ||
324 | // helper function to be used with Ssl::matchX509CommonNames | |
325 | static int copy_cn(void *check_data, ASN1_STRING *cn_data) | |
326 | { | |
327 | String *str = (String *)check_data; | |
328 | if (!str) // no data? abort | |
329 | return 0; | |
330 | if (str->defined()) | |
331 | str->append(", "); | |
332 | str->append((const char *)cn_data->data, cn_data->length); | |
333 | return 1; | |
334 | } | |
335 | ||
336 | /** | |
337 | * The list with certificates cn and alternate names | |
338 | */ | |
339 | const char *Ssl::ErrorDetail::cn() const | |
340 | { | |
ff3bc018 | 341 | if (!broken_cert) |
4d16918e CT |
342 | return "[Not available]"; |
343 | ||
344 | static String tmpStr; ///< A temporary string buffer | |
345 | tmpStr.clean(); | |
ff3bc018 | 346 | Ssl::matchX509CommonNames(broken_cert.get(), &tmpStr, copy_cn); |
4d16918e CT |
347 | return tmpStr.termedBuf(); |
348 | } | |
349 | ||
350 | /** | |
351 | * The issuer name | |
352 | */ | |
353 | const char *Ssl::ErrorDetail::ca_name() const | |
354 | { | |
ff3bc018 | 355 | if (!broken_cert) |
4d16918e CT |
356 | return "[Not available]"; |
357 | ||
358 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 359 | X509_NAME_oneline(X509_get_issuer_name(broken_cert.get()), tmpBuffer, sizeof(tmpBuffer)); |
4d16918e CT |
360 | return tmpBuffer; |
361 | } | |
362 | ||
363 | /** | |
364 | * The certificate "not before" field | |
365 | */ | |
366 | const char *Ssl::ErrorDetail::notbefore() const | |
367 | { | |
ff3bc018 | 368 | if (!broken_cert) |
4d16918e CT |
369 | return "[Not available]"; |
370 | ||
371 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 372 | ASN1_UTCTIME * tm = X509_get_notBefore(broken_cert.get()); |
4d16918e CT |
373 | Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer)); |
374 | return tmpBuffer; | |
375 | } | |
376 | ||
377 | /** | |
378 | * The certificate "not after" field | |
379 | */ | |
380 | const char *Ssl::ErrorDetail::notafter() const | |
381 | { | |
ff3bc018 | 382 | if (!broken_cert) |
4d16918e CT |
383 | return "[Not available]"; |
384 | ||
385 | static char tmpBuffer[256]; // A temporary buffer | |
ff3bc018 | 386 | ASN1_UTCTIME * tm = X509_get_notAfter(broken_cert.get()); |
4d16918e CT |
387 | Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer)); |
388 | return tmpBuffer; | |
389 | } | |
390 | ||
391 | /** | |
392 | * The string representation of the error_no | |
393 | */ | |
394 | const char *Ssl::ErrorDetail::err_code() const | |
395 | { | |
8211c314 | 396 | static char tmpBuffer[64]; |
02259ff8 CT |
397 | // We can use the GetErrorName but using the detailEntry is faster, |
398 | // so try it first. | |
399 | const char *err = detailEntry.name.termedBuf(); | |
400 | ||
401 | // error details not loaded yet or not defined in error_details.txt, | |
402 | // try the GetErrorName... | |
403 | if (!err) | |
404 | err = GetErrorName(error_no); | |
405 | ||
8211c314 | 406 | if (!err) { |
605b80ca | 407 | snprintf(tmpBuffer, 64, "%d", (int)error_no); |
8211c314 CT |
408 | err = tmpBuffer; |
409 | } | |
4d16918e CT |
410 | return err; |
411 | } | |
412 | ||
cf09bec7 CT |
413 | /** |
414 | * A short description of the error_no | |
415 | */ | |
416 | const char *Ssl::ErrorDetail::err_descr() const | |
417 | { | |
02259ff8 CT |
418 | if (error_no == SSL_ERROR_NONE) |
419 | return "[No Error]"; | |
420 | if (const char *err = detailEntry.descr.termedBuf()) | |
cf09bec7 CT |
421 | return err; |
422 | return "[Not available]"; | |
423 | } | |
424 | ||
8e9bae99 CT |
425 | const char *Ssl::ErrorDetail::err_lib_error() const |
426 | { | |
2cef0ca6 AR |
427 | if (errReason.defined()) |
428 | return errReason.termedBuf(); | |
429 | else if (lib_error_no != SSL_ERROR_NONE) | |
8e9bae99 CT |
430 | return ERR_error_string(lib_error_no, NULL); |
431 | else | |
432 | return "[No Error]"; | |
433 | } | |
434 | ||
4d16918e | 435 | /** |
7a957a93 | 436 | * Converts the code to a string value. Supported formating codes are: |
ff3bc018 AR |
437 | * |
438 | * Error meta information: | |
8e9bae99 | 439 | * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*) |
cf09bec7 | 440 | * %ssl_error_descr: A short description of the SSL error |
ff3bc018 AR |
441 | * %ssl_lib_error: human-readable low-level error string by ERR_error_string(3SSL) |
442 | * | |
443 | * Certificate information extracted from broken (not necessarily peer!) cert | |
4d16918e CT |
444 | * %ssl_cn: The comma-separated list of common and alternate names |
445 | * %ssl_subject: The certificate subject | |
446 | * %ssl_ca_name: The certificate issuer name | |
447 | * %ssl_notbefore: The certificate "not before" field | |
448 | * %ssl_notafter: The certificate "not after" field | |
87f237a9 | 449 | * |
4d16918e CT |
450 | \retval the length of the code (the number of characters will be replaced by value) |
451 | */ | |
452 | int Ssl::ErrorDetail::convert(const char *code, const char **value) const | |
453 | { | |
454 | *value = "-"; | |
d7ae3534 | 455 | for (int i=0; ErrorFormatingCodes[i].code!=NULL; ++i) { |
4d16918e CT |
456 | const int len = strlen(ErrorFormatingCodes[i].code); |
457 | if (strncmp(code,ErrorFormatingCodes[i].code, len)==0) { | |
458 | ErrorDetail::fmt_action_t action = ErrorFormatingCodes[i].fmt_action; | |
459 | *value = (this->*action)(); | |
460 | return len; | |
461 | } | |
e34763f4 | 462 | } |
4d16918e CT |
463 | return 0; |
464 | } | |
465 | ||
466 | /** | |
e34763f4 A |
467 | * It uses the convert method to build the string errDetailStr using |
468 | * a template message for the current SSL error. The template messages | |
4d16918e CT |
469 | * can also contain normal error pages formating codes. |
470 | * Currently the error template messages are hard-coded | |
471 | */ | |
472 | void Ssl::ErrorDetail::buildDetail() const | |
473 | { | |
02259ff8 | 474 | char const *s = NULL; |
4d16918e CT |
475 | char const *p; |
476 | char const *t; | |
477 | int code_len = 0; | |
478 | ||
b248c2a3 | 479 | if (ErrorDetailsManager::GetInstance().getErrorDetail(error_no, request, detailEntry)) |
02259ff8 CT |
480 | s = detailEntry.detail.termedBuf(); |
481 | ||
482 | if (!s) | |
483 | s = SslErrorDetailDefaultStr; | |
484 | ||
8211c314 | 485 | assert(s); |
4d16918e CT |
486 | while ((p = strchr(s, '%'))) { |
487 | errDetailStr.append(s, p - s); | |
488 | code_len = convert(++p, &t); | |
489 | if (code_len) | |
490 | errDetailStr.append(t); | |
491 | else | |
492 | errDetailStr.append("%"); | |
493 | s = p + code_len; | |
494 | } | |
495 | errDetailStr.append(s, strlen(s)); | |
496 | } | |
497 | ||
e34763f4 A |
498 | const String &Ssl::ErrorDetail::toString() const |
499 | { | |
4d16918e CT |
500 | if (!errDetailStr.defined()) |
501 | buildDetail(); | |
502 | return errDetailStr; | |
503 | } | |
504 | ||
2cef0ca6 | 505 | Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert, X509 *broken, const char *aReason): error_no (err_no), lib_error_no(SSL_ERROR_NONE), errReason(aReason) |
4d16918e | 506 | { |
8e9bae99 | 507 | if (cert) |
de878a55 CT |
508 | peer_cert.resetAndLock(cert); |
509 | ||
510 | if (broken) | |
511 | broken_cert.resetAndLock(broken); | |
512 | else | |
513 | broken_cert.resetAndLock(cert); | |
8e9bae99 | 514 | |
02259ff8 | 515 | detailEntry.error_no = SSL_ERROR_NONE; |
4d16918e CT |
516 | } |
517 | ||
518 | Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail const &anErrDetail) | |
519 | { | |
520 | error_no = anErrDetail.error_no; | |
02259ff8 CT |
521 | request = anErrDetail.request; |
522 | ||
4d16918e | 523 | if (anErrDetail.peer_cert.get()) { |
de878a55 CT |
524 | peer_cert.resetAndLock(anErrDetail.peer_cert.get()); |
525 | } | |
526 | ||
527 | if (anErrDetail.broken_cert.get()) { | |
528 | broken_cert.resetAndLock(anErrDetail.broken_cert.get()); | |
4d16918e | 529 | } |
02259ff8 CT |
530 | |
531 | detailEntry = anErrDetail.detailEntry; | |
8e9bae99 CT |
532 | |
533 | lib_error_no = anErrDetail.lib_error_no; | |
4d16918e | 534 | } |