ErrorDetail.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 #include "squid.h"
10 #include "errorpage.h"
11 #include "fatal.h"
12 #include "html_quote.h"
13 #include "ssl/ErrorDetail.h"
14 
15 #include <climits>
16 #include <map>
17 
18 struct SslErrorEntry {
20  const char *name;
21 };
22 
23 static const char *SslErrorDetailDefaultStr = "SSL handshake error (%err_name)";
24 //Use std::map to optimize search
25 typedef std::map<Security::ErrorCode, const SslErrorEntry *> SslErrors;
27 
30  "SQUID_X509_V_ERR_INFINITE_VALIDATION"
31  },
33  "SQUID_X509_V_ERR_CERT_CHANGE"
34  },
36  "SQUID_ERR_SSL_HANDSHAKE"
37  },
39  "SQUID_X509_V_ERR_DOMAIN_MISMATCH"
40  },
41  { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
42  "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"
43  },
44  { X509_V_ERR_UNABLE_TO_GET_CRL,
45  "X509_V_ERR_UNABLE_TO_GET_CRL"
46  },
47  { X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
48  "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"
49  },
50  { X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
51  "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"
52  },
53  { X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
54  "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"
55  },
56  { X509_V_ERR_CERT_SIGNATURE_FAILURE,
57  "X509_V_ERR_CERT_SIGNATURE_FAILURE"
58  },
59  { X509_V_ERR_CRL_SIGNATURE_FAILURE,
60  "X509_V_ERR_CRL_SIGNATURE_FAILURE"
61  },
62  { X509_V_ERR_CERT_NOT_YET_VALID,
63  "X509_V_ERR_CERT_NOT_YET_VALID"
64  },
65  { X509_V_ERR_CERT_HAS_EXPIRED,
66  "X509_V_ERR_CERT_HAS_EXPIRED"
67  },
68  { X509_V_ERR_CRL_NOT_YET_VALID,
69  "X509_V_ERR_CRL_NOT_YET_VALID"
70  },
71  { X509_V_ERR_CRL_HAS_EXPIRED,
72  "X509_V_ERR_CRL_HAS_EXPIRED"
73  },
74  { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
75  "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"
76  },
77  { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
78  "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"
79  },
80  { X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
81  "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"
82  },
83  { X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
84  "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"
85  },
86  { X509_V_ERR_OUT_OF_MEM,
87  "X509_V_ERR_OUT_OF_MEM"
88  },
89  { X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
90  "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"
91  },
92  { X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
93  "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"
94  },
95  { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
96  "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"
97  },
98  { X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
99  "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"
100  },
101  { X509_V_ERR_CERT_CHAIN_TOO_LONG,
102  "X509_V_ERR_CERT_CHAIN_TOO_LONG"
103  },
104  { X509_V_ERR_CERT_REVOKED,
105  "X509_V_ERR_CERT_REVOKED"
106  },
107  { X509_V_ERR_INVALID_CA,
108  "X509_V_ERR_INVALID_CA"
109  },
110  { X509_V_ERR_PATH_LENGTH_EXCEEDED,
111  "X509_V_ERR_PATH_LENGTH_EXCEEDED"
112  },
113  { X509_V_ERR_INVALID_PURPOSE,
114  "X509_V_ERR_INVALID_PURPOSE"
115  },
116  { X509_V_ERR_CERT_UNTRUSTED,
117  "X509_V_ERR_CERT_UNTRUSTED"
118  },
119  { X509_V_ERR_CERT_REJECTED,
120  "X509_V_ERR_CERT_REJECTED"
121  },
122  { X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
123  "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"
124  },
125  { X509_V_ERR_AKID_SKID_MISMATCH,
126  "X509_V_ERR_AKID_SKID_MISMATCH"
127  },
128  { X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
129  "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"
130  },
131  { X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
132  "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"
133  },
134 #if defined(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER)
135  {
136  X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, //33
137  "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"
138  },
139 #endif
140 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
141  {
142  X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, //34
143  "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"
144  },
145 #endif
146 #if defined(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN)
147  {
148  X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, //35
149  "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"
150  },
151 #endif
152 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION)
153  {
154  X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, //36
155  "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"
156  },
157 #endif
158 #if defined(X509_V_ERR_INVALID_NON_CA)
159  {
160  X509_V_ERR_INVALID_NON_CA, //37
161  "X509_V_ERR_INVALID_NON_CA"
162  },
163 #endif
164 #if defined(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)
165  {
166  X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, //38
167  "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"
168  },
169 #endif
170 #if defined(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE)
171  {
172  X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, //39
173  "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"
174  },
175 #endif
176 #if defined(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)
177  {
178  X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, //40
179  "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"
180  },
181 #endif
182 #if defined(X509_V_ERR_INVALID_EXTENSION)
183  {
184  X509_V_ERR_INVALID_EXTENSION, //41
185  "X509_V_ERR_INVALID_EXTENSION"
186  },
187 #endif
188 #if defined(X509_V_ERR_INVALID_POLICY_EXTENSION)
189  {
190  X509_V_ERR_INVALID_POLICY_EXTENSION, //42
191  "X509_V_ERR_INVALID_POLICY_EXTENSION"
192  },
193 #endif
194 #if defined(X509_V_ERR_NO_EXPLICIT_POLICY)
195  {
196  X509_V_ERR_NO_EXPLICIT_POLICY, //43
197  "X509_V_ERR_NO_EXPLICIT_POLICY"
198  },
199 #endif
200 #if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE)
201  {
202  X509_V_ERR_DIFFERENT_CRL_SCOPE, //44
203  "X509_V_ERR_DIFFERENT_CRL_SCOPE"
204  },
205 #endif
206 #if defined(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE)
207  {
208  X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, //45
209  "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE"
210  },
211 #endif
212 #if defined(X509_V_ERR_UNNESTED_RESOURCE)
213  {
214  X509_V_ERR_UNNESTED_RESOURCE, //46
215  "X509_V_ERR_UNNESTED_RESOURCE"
216  },
217 #endif
218 #if defined(X509_V_ERR_PERMITTED_VIOLATION)
219  {
220  X509_V_ERR_PERMITTED_VIOLATION, //47
221  "X509_V_ERR_PERMITTED_VIOLATION"
222  },
223 #endif
224 #if defined(X509_V_ERR_EXCLUDED_VIOLATION)
225  {
226  X509_V_ERR_EXCLUDED_VIOLATION, //48
227  "X509_V_ERR_EXCLUDED_VIOLATION"
228  },
229 #endif
230 #if defined(X509_V_ERR_SUBTREE_MINMAX)
231  {
232  X509_V_ERR_SUBTREE_MINMAX, //49
233  "X509_V_ERR_SUBTREE_MINMAX"
234  },
235 #endif
236  { X509_V_ERR_APPLICATION_VERIFICATION, //50
237  "X509_V_ERR_APPLICATION_VERIFICATION"
238  },
239 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE)
240  {
241  X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, //51
242  "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE"
243  },
244 #endif
245 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX)
246  {
247  X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, //52
248  "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX"
249  },
250 #endif
251 #if defined(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX)
252  {
253  X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, //53
254  "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX"
255  },
256 #endif
257 #if defined(X509_V_ERR_CRL_PATH_VALIDATION_ERROR)
258  {
259  X509_V_ERR_CRL_PATH_VALIDATION_ERROR, //54
260  "X509_V_ERR_CRL_PATH_VALIDATION_ERROR"
261  },
262 #endif
263 #if defined(X509_V_ERR_PATH_LOOP)
264  {
265  X509_V_ERR_PATH_LOOP, //55
266  "X509_V_ERR_PATH_LOOP"
267  },
268 #endif
269 #if defined(X509_V_ERR_SUITE_B_INVALID_VERSION)
270  {
271  X509_V_ERR_SUITE_B_INVALID_VERSION, //56
272  "X509_V_ERR_SUITE_B_INVALID_VERSION"
273  },
274 #endif
275 #if defined(X509_V_ERR_SUITE_B_INVALID_ALGORITHM)
276  {
277  X509_V_ERR_SUITE_B_INVALID_ALGORITHM, //57
278  "X509_V_ERR_SUITE_B_INVALID_ALGORITHM"
279  },
280 #endif
281 #if defined(X509_V_ERR_SUITE_B_INVALID_CURVE)
282  {
283  X509_V_ERR_SUITE_B_INVALID_CURVE, //58
284  "X509_V_ERR_SUITE_B_INVALID_CURVE"
285  },
286 #endif
287 #if defined(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM)
288  {
289  X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM, //59
290  "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM"
291  },
292 #endif
293 #if defined(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED)
294  {
295  X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED, //60
296  "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED"
297  },
298 #endif
299 #if defined(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256)
300  {
301  X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256, //61
302  "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256"
303  },
304 #endif
305 #if defined(X509_V_ERR_HOSTNAME_MISMATCH)
306  {
307  X509_V_ERR_HOSTNAME_MISMATCH, //62
308  "X509_V_ERR_HOSTNAME_MISMATCH"
309  },
310 #endif
311 #if defined(X509_V_ERR_EMAIL_MISMATCH)
312  {
313  X509_V_ERR_EMAIL_MISMATCH, //63
314  "X509_V_ERR_EMAIL_MISMATCH"
315  },
316 #endif
317 #if defined(X509_V_ERR_IP_ADDRESS_MISMATCH)
318  {
319  X509_V_ERR_IP_ADDRESS_MISMATCH, //64
320  "X509_V_ERR_IP_ADDRESS_MISMATCH"
321  },
322 #endif
323 #if defined(X509_V_ERR_DANE_NO_MATCH)
324  {
325  X509_V_ERR_DANE_NO_MATCH, //65
326  "X509_V_ERR_DANE_NO_MATCH"
327  },
328 #endif
329 #if defined(X509_V_ERR_EE_KEY_TOO_SMALL)
330  {
331  X509_V_ERR_EE_KEY_TOO_SMALL, //66
332  "X509_V_ERR_EE_KEY_TOO_SMALL"
333  },
334 #endif
335 #if defined(X509_V_ERR_CA_KEY_TOO_SMALL)
336  {
337  X509_V_ERR_CA_KEY_TOO_SMALL, //67
338  "X509_V_ERR_CA_KEY_TOO_SMALL"
339  },
340 #endif
341 #if defined(X509_V_ERR_CA_MD_TOO_WEAK)
342  {
343  X509_V_ERR_CA_MD_TOO_WEAK, //68
344  "X509_V_ERR_CA_MD_TOO_WEAK"
345  },
346 #endif
347 #if defined(X509_V_ERR_INVALID_CALL)
348  {
349  X509_V_ERR_INVALID_CALL, //69
350  "X509_V_ERR_INVALID_CALL"
351  },
352 #endif
353 #if defined(X509_V_ERR_STORE_LOOKUP)
354  {
355  X509_V_ERR_STORE_LOOKUP, //70
356  "X509_V_ERR_STORE_LOOKUP"
357  },
358 #endif
359 #if defined(X509_V_ERR_NO_VALID_SCTS)
360  {
361  X509_V_ERR_NO_VALID_SCTS, //71
362  "X509_V_ERR_NO_VALID_SCTS"
363  },
364 #endif
365 #if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION)
366  {
367  X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION, //72
368  "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION"
369  },
370 #endif
371 #if defined(X509_V_ERR_OCSP_VERIFY_NEEDED)
372  {
373  X509_V_ERR_OCSP_VERIFY_NEEDED, //73
374  "X509_V_ERR_OCSP_VERIFY_NEEDED"
375  },
376 #endif
377 #if defined(X509_V_ERR_OCSP_VERIFY_FAILED)
378  {
379  X509_V_ERR_OCSP_VERIFY_FAILED, //74
380  "X509_V_ERR_OCSP_VERIFY_FAILED"
381  },
382 #endif
383 #if defined(X509_V_ERR_OCSP_CERT_UNKNOWN)
384  {
385  X509_V_ERR_OCSP_CERT_UNKNOWN, //75
386  "X509_V_ERR_OCSP_CERT_UNKNOWN"
387  },
388 #endif
389  { SSL_ERROR_NONE, "SSL_ERROR_NONE"},
390  {SSL_ERROR_NONE, NULL}
391 };
392 
393 static const char *OptionalSslErrors[] = {
394  "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER",
395  "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION",
396  "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN",
397  "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION",
398  "X509_V_ERR_INVALID_NON_CA",
399  "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED",
400  "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE",
401  "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED",
402  "X509_V_ERR_INVALID_EXTENSION",
403  "X509_V_ERR_INVALID_POLICY_EXTENSION",
404  "X509_V_ERR_NO_EXPLICIT_POLICY",
405  "X509_V_ERR_DIFFERENT_CRL_SCOPE",
406  "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE",
407  "X509_V_ERR_UNNESTED_RESOURCE",
408  "X509_V_ERR_PERMITTED_VIOLATION",
409  "X509_V_ERR_EXCLUDED_VIOLATION",
410  "X509_V_ERR_SUBTREE_MINMAX",
411  "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE",
412  "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX",
413  "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX",
414  "X509_V_ERR_CRL_PATH_VALIDATION_ERROR",
415  "X509_V_ERR_PATH_LOOP",
416  "X509_V_ERR_SUITE_B_INVALID_VERSION",
417  "X509_V_ERR_SUITE_B_INVALID_ALGORITHM",
418  "X509_V_ERR_SUITE_B_INVALID_CURVE",
419  "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM",
420  "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED",
421  "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256",
422  "X509_V_ERR_HOSTNAME_MISMATCH",
423  "X509_V_ERR_EMAIL_MISMATCH",
424  "X509_V_ERR_IP_ADDRESS_MISMATCH",
425  "X509_V_ERR_DANE_NO_MATCH",
426  "X509_V_ERR_EE_KEY_TOO_SMALL",
427  "X509_V_ERR_CA_KEY_TOO_SMALL",
428  "X509_V_ERR_CA_MD_TOO_WEAK",
429  "X509_V_ERR_INVALID_CALL",
430  "X509_V_ERR_STORE_LOOKUP",
431  "X509_V_ERR_NO_VALID_SCTS",
432  "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION",
433  "X509_V_ERR_OCSP_VERIFY_NEEDED",
434  "X509_V_ERR_OCSP_VERIFY_FAILED",
435  "X509_V_ERR_OCSP_CERT_UNKNOWN",
436  NULL
437 };
438 
440  const char *name;
442 };
443 
444 static const Security::ErrorCode hasExpired[] = {X509_V_ERR_CERT_HAS_EXPIRED, SSL_ERROR_NONE};
445 static const Security::ErrorCode notYetValid[] = {X509_V_ERR_CERT_NOT_YET_VALID, SSL_ERROR_NONE};
447 static const Security::ErrorCode certUntrusted[] = {X509_V_ERR_INVALID_CA,
448  X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
449  X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
450  X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
451  X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
452  X509_V_ERR_CERT_UNTRUSTED, SSL_ERROR_NONE
453  };
454 static const Security::ErrorCode certSelfSigned[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_ERROR_NONE};
455 
456 // The list of error name shortcuts for use with ssl_error acls.
457 // The keys without the "ssl::" scope prefix allow shorter error
458 // names within the SSL options scope. This is easier than
459 // carefully stripping the scope prefix in Ssl::ParseErrorString().
461  {"ssl::certHasExpired", hasExpired},
462  {"certHasExpired", hasExpired},
463  {"ssl::certNotYetValid", notYetValid},
464  {"certNotYetValid", notYetValid},
465  {"ssl::certDomainMismatch", domainMismatch},
466  {"certDomainMismatch", domainMismatch},
467  {"ssl::certUntrusted", certUntrusted},
468  {"certUntrusted", certUntrusted},
469  {"ssl::certSelfSigned", certSelfSigned},
470  {"certSelfSigned", certSelfSigned},
471  {NULL, NULL}
472 };
473 
474 // Use std::map to optimize search.
475 typedef std::map<std::string, const Security::ErrorCode *> SslErrorShortcuts;
477 
478 static void loadSslErrorMap()
479 {
480  assert(TheSslErrors.empty());
481  for (int i = 0; TheSslErrorArray[i].name; ++i) {
483  }
484 }
485 
487 {
488  assert(TheSslErrorShortcuts.empty());
489  for (int i = 0; TheSslErrorShortcutsArray[i].name; ++i)
491 }
492 
494 {
495  //TODO: use a std::map?
496  for (int i = 0; TheSslErrorArray[i].name != NULL; ++i) {
497  if (strcmp(name, TheSslErrorArray[i].name) == 0)
498  return TheSslErrorArray[i].value;
499  }
500  return SSL_ERROR_NONE;
501 }
502 
503 bool
504 Ssl::ParseErrorString(const char *name, Security::Errors &errors)
505 {
506  assert(name);
507 
508  const Security::ErrorCode ssl_error = GetErrorCode(name);
509  if (ssl_error != SSL_ERROR_NONE) {
510  errors.emplace(ssl_error);
511  return true;
512  }
513 
514  if (xisdigit(*name)) {
515  const long int value = strtol(name, NULL, 0);
516  if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX) {
517  errors.emplace(value);
518  return true;
519  }
520  fatalf("Too small or too big TLS error code '%s'", name);
521  }
522 
523  if (TheSslErrorShortcuts.empty())
525 
526  const SslErrorShortcuts::const_iterator it = TheSslErrorShortcuts.find(name);
527  if (it != TheSslErrorShortcuts.end()) {
528  // Should not be empty...
529  assert(it->second[0] != SSL_ERROR_NONE);
530  for (int i = 0; it->second[i] != SSL_ERROR_NONE; ++i) {
531  errors.emplace(it->second[i]);
532  }
533  return true;
534  }
535 
536  fatalf("Unknown TLS error name '%s'", name);
537  return false; // not reached
538 }
539 
540 const char *Ssl::GetErrorName(Security::ErrorCode value, const bool prefixRawCode)
541 {
542  if (TheSslErrors.empty())
543  loadSslErrorMap();
544 
545  const SslErrors::const_iterator it = TheSslErrors.find(value);
546  if (it != TheSslErrors.end())
547  return it->second->name;
548 
549  static char tmpBuffer[128];
550  snprintf(tmpBuffer, sizeof(tmpBuffer), "%s%d", prefixRawCode ? "SSL_ERR=" : "", (int)value);
551  return tmpBuffer;
552 }
553 
554 bool
555 Ssl::ErrorIsOptional(const char *name)
556 {
557  for (int i = 0; OptionalSslErrors[i] != NULL; ++i) {
558  if (strcmp(name, OptionalSslErrors[i]) == 0)
559  return true;
560  }
561  return false;
562 }
563 
564 const char *
566 {
567  return ErrorDetailsManager::GetInstance().getDefaultErrorDescr(value);
568 }
569 
571  {"ssl_subject", &Ssl::ErrorDetail::subject},
572  {"ssl_ca_name", &Ssl::ErrorDetail::ca_name},
573  {"ssl_cn", &Ssl::ErrorDetail::cn},
574  {"ssl_notbefore", &Ssl::ErrorDetail::notbefore},
575  {"ssl_notafter", &Ssl::ErrorDetail::notafter},
576  {"err_name", &Ssl::ErrorDetail::err_code},
577  {"ssl_error_descr", &Ssl::ErrorDetail::err_descr},
578  {"ssl_lib_error", &Ssl::ErrorDetail::err_lib_error},
579  {NULL,NULL}
580 };
581 
585 const char *Ssl::ErrorDetail::subject() const
586 {
587  if (broken_cert.get()) {
588  static char tmpBuffer[256]; // A temporary buffer
589  if (X509_NAME_oneline(X509_get_subject_name(broken_cert.get()), tmpBuffer, sizeof(tmpBuffer))) {
590  // quote to avoid possible html code injection through
591  // certificate subject
592  return html_quote(tmpBuffer);
593  }
594  }
595  return "[Not available]";
596 }
597 
598 // helper function to be used with Ssl::matchX509CommonNames
599 static int copy_cn(void *check_data, ASN1_STRING *cn_data)
600 {
601  String *str = (String *)check_data;
602  if (!str) // no data? abort
603  return 0;
604  if (cn_data && cn_data->length) {
605  if (str->size() > 0)
606  str->append(", ");
607  str->append((const char *)cn_data->data, cn_data->length);
608  }
609  return 1;
610 }
611 
615 const char *Ssl::ErrorDetail::cn() const
616 {
617  if (broken_cert.get()) {
618  static String tmpStr;
619  tmpStr.clean();
620  Ssl::matchX509CommonNames(broken_cert.get(), &tmpStr, copy_cn);
621  if (tmpStr.size()) {
622  // quote to avoid possible html code injection through
623  // certificate subject
624  return html_quote(tmpStr.termedBuf());
625  }
626  }
627  return "[Not available]";
628 }
629 
633 const char *Ssl::ErrorDetail::ca_name() const
634 {
635  if (broken_cert.get()) {
636  static char tmpBuffer[256]; // A temporary buffer
637  if (X509_NAME_oneline(X509_get_issuer_name(broken_cert.get()), tmpBuffer, sizeof(tmpBuffer))) {
638  // quote to avoid possible html code injection through
639  // certificate issuer subject
640  return html_quote(tmpBuffer);
641  }
642  }
643  return "[Not available]";
644 }
645 
649 const char *Ssl::ErrorDetail::notbefore() const
650 {
651  if (broken_cert.get()) {
652  if (const auto tm = X509_getm_notBefore(broken_cert.get())) {
653  static char tmpBuffer[256]; // A temporary buffer
654  Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
655  return tmpBuffer;
656  }
657  }
658  return "[Not available]";
659 }
660 
664 const char *Ssl::ErrorDetail::notafter() const
665 {
666  if (broken_cert.get()) {
667  if (const auto tm = X509_getm_notAfter(broken_cert.get())) {
668  static char tmpBuffer[256]; // A temporary buffer
669  Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
670  return tmpBuffer;
671  }
672  }
673  return "[Not available]";
674 }
675 
679 const char *Ssl::ErrorDetail::err_code() const
680 {
681  // We can use the GetErrorName but using the detailEntry is faster,
682  // so try it first.
683  if (const char *err = detailEntry.name.termedBuf())
684  return err;
685 
686  // error details not loaded yet or not defined in error_details.txt,
687  // try the GetErrorName...
688  return GetErrorName(error_no);
689 }
690 
694 const char *Ssl::ErrorDetail::err_descr() const
695 {
696  if (error_no == SSL_ERROR_NONE)
697  return "[No Error]";
698  if (const char *err = detailEntry.descr.termedBuf())
699  return err;
700  return "[Not available]";
701 }
702 
704 {
705  if (errReason.size() > 0)
706  return errReason.termedBuf();
707  else if (lib_error_no != SSL_ERROR_NONE)
708  return Security::ErrorString(lib_error_no);
709  else
710  return "[No Error]";
711 }
712 
730 int Ssl::ErrorDetail::convert(const char *code, const char **value) const
731 {
732  *value = "-";
733  for (int i=0; ErrorFormatingCodes[i].code!=NULL; ++i) {
734  const int len = strlen(ErrorFormatingCodes[i].code);
735  if (strncmp(code,ErrorFormatingCodes[i].code, len)==0) {
736  ErrorDetail::fmt_action_t action = ErrorFormatingCodes[i].fmt_action;
737  *value = (this->*action)();
738  return len;
739  }
740  }
741  // TODO: Support logformat %codes.
742  return 0;
743 }
744 
752 {
753  char const *s = NULL;
754  char const *p;
755  char const *t;
756  int code_len = 0;
757 
758  if (ErrorDetailsManager::GetInstance().getErrorDetail(error_no, request, detailEntry))
759  s = detailEntry.detail.termedBuf();
760 
761  if (!s)
763 
764  assert(s);
765  while ((p = strchr(s, '%'))) {
766  errDetailStr.append(s, p - s);
767  code_len = convert(++p, &t);
768  if (code_len)
769  errDetailStr.append(t);
770  else
771  errDetailStr.append("%");
772  s = p + code_len;
773  }
774  errDetailStr.append(s, strlen(s));
775 }
776 
778 {
779  if (errDetailStr.size() == 0)
780  buildDetail();
781  return errDetailStr;
782 }
783 
784 Ssl::ErrorDetail::ErrorDetail( Security::ErrorCode err_no, X509 *cert, X509 *broken, const char *aReason): error_no (err_no), lib_error_no(SSL_ERROR_NONE), errReason(aReason)
785 {
786  if (cert)
787  peer_cert.resetAndLock(cert);
788 
789  if (broken)
790  broken_cert.resetAndLock(broken);
791  else
793 
794  detailEntry.error_no = SSL_ERROR_NONE;
795 }
796 
798 {
799  error_no = anErrDetail.error_no;
800  request = anErrDetail.request;
801 
802  if (anErrDetail.peer_cert.get()) {
803  peer_cert.resetAndLock(anErrDetail.peer_cert.get());
804  }
805 
806  if (anErrDetail.broken_cert.get()) {
807  broken_cert.resetAndLock(anErrDetail.broken_cert.get());
808  }
809 
810  detailEntry = anErrDetail.detailEntry;
811 
812  lib_error_no = anErrDetail.lib_error_no;
813 }
814 
Security::ErrorCode value
Definition: ErrorDetail.cc:19
int ErrorCode
Squid defined error code (<0), an error code returned by X.509 API, or SSL_ERROR_NONE.
Definition: forward.h:92
int asn1timeToString(ASN1_TIME *tm, char *buf, int len)
Definition: support.cc:178
const char * notafter() const
Definition: ErrorDetail.cc:664
static void loadSslErrorMap()
Definition: ErrorDetail.cc:478
SslErrors TheSslErrors
Definition: ErrorDetail.cc:26
#define SQUID_ERR_SSL_HANDSHAKE
Definition: support.h:43
#define SQUID_X509_V_ERR_CERT_CHANGE
Definition: support.h:42
Security::ErrorCode error_no
The SSL error code.
static SslErrorAlias TheSslErrorShortcutsArray[]
Definition: ErrorDetail.cc:460
#define SQUID_SSL_ERROR_MIN
Definition: support.h:46
const char * ca_name() const
Definition: ErrorDetail.cc:633
int matchX509CommonNames(X509 *peer_cert, void *check_data, int(*check_func)(void *check_data, ASN1_STRING *cn_data))
Definition: support.cc:192
const char * subject() const
Definition: ErrorDetail.cc:585
const char * name
Definition: ErrorDetail.cc:20
int convert(const char *code, const char **value) const
Definition: ErrorDetail.cc:730
char * html_quote(const char *)
Definition: html_quote.c:53
const char * cn() const
Definition: ErrorDetail.cc:615
static const Security::ErrorCode hasExpired[]
Definition: ErrorDetail.cc:444
ErrorDetailEntry detailEntry
Definition: ErrorDetail.h:92
#define SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: support.h:44
const char * name
Definition: ErrorDetail.cc:440
bool action(int fd, size_t metasize, const char *fn, const char *url, const SquidMetaList &meta)
Definition: purge.cc:311
static const char * SslErrorDetailDefaultStr
Definition: ErrorDetail.cc:23
static const char * OptionalSslErrors[]
Definition: ErrorDetail.cc:393
unsigned long lib_error_no
low-level error returned by OpenSSL ERR_get_error(3SSL)
Definition: ErrorDetail.h:88
bool ParseErrorString(const char *name, Security::Errors &)
Definition: ErrorDetail.cc:504
const char * ErrorString(const ErrorCode code)
Definition: forward.h:97
#define SQUID_X509_V_ERR_INFINITE_VALIDATION
Definition: support.h:41
void buildDetail() const
Definition: ErrorDetail.cc:751
const char * GetErrorDescr(Security::ErrorCode value)
A short description of the TLS error "value".
Definition: ErrorDetail.cc:565
#define NULL
Definition: types.h:166
#define X509_getm_notBefore
Definition: openssl.h:206
const Security::ErrorCode * errors
Definition: ErrorDetail.cc:441
void append(char const *buf, int len)
Definition: String.cc:161
SslErrorShortcuts TheSslErrorShortcuts
Definition: ErrorDetail.cc:476
std::map< Security::ErrorCode, const SslErrorEntry * > SslErrors
Definition: ErrorDetail.cc:25
static void loadSslErrorShortcutsMap()
Definition: ErrorDetail.cc:486
unsigned char code
Definition: html_quote.c:20
const String & toString() const
An error detail string to embed in squid error pages.
Definition: ErrorDetail.cc:777
#define assert(EX)
Definition: assert.h:19
const char * err_code() const
Definition: ErrorDetail.cc:679
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
static const Security::ErrorCode certUntrusted[]
Definition: ErrorDetail.cc:447
std::map< std::string, const Security::ErrorCode * > SslErrorShortcuts
Definition: ErrorDetail.cc:475
#define xisdigit(x)
Definition: xis.h:20
static const Security::ErrorCode notYetValid[]
Definition: ErrorDetail.cc:445
Security::ErrorCode GetErrorCode(const char *name)
The Security::ErrorCode code of the error described by "name".
Definition: ErrorDetail.cc:493
#define X509_getm_notAfter
Definition: openssl.h:205
static const Security::ErrorCode certSelfSigned[]
Definition: ErrorDetail.cc:454
static ErrorDetailsManager & GetInstance()
Instance class.
const char * notbefore() const
Definition: ErrorDetail.cc:649
const char * termedBuf() const
Definition: SquidString.h:91
Security::CertPointer broken_cert
A pointer to the broken certificate (peer or intermediate)
Definition: ErrorDetail.h:90
Security::CertPointer peer_cert
A pointer to the peer certificate.
Definition: ErrorDetail.h:89
const typedef char *(ErrorDetail::* fmt_action_t)() const
Definition: ErrorDetail.h:62
Security::ErrorCode error_no
The error code.
Definition: ErrorDetail.h:87
size_type size() const
Definition: SquidString.h:72
static SslErrorEntry TheSslErrorArray[]
Definition: ErrorDetail.cc:28
ErrorDetail(Security::ErrorCode err_no, X509 *peer, X509 *broken, const char *aReason=NULL)
Definition: ErrorDetail.cc:784
static const Security::ErrorCode domainMismatch[]
Definition: ErrorDetail.cc:446
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
std::unordered_set< Security::ErrorCode > Errors
Definition: forward.h:109
#define SQUID_SSL_ERROR_MAX
Definition: support.h:47
static int copy_cn(void *check_data, ASN1_STRING *cn_data)
Definition: ErrorDetail.cc:599
bool ErrorIsOptional(const char *name)
Definition: ErrorDetail.cc:555
const char * err_lib_error() const
Definition: ErrorDetail.cc:703
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
static err_frm_code ErrorFormatingCodes[]
The supported formatting codes.
Definition: ErrorDetail.h:72
const char * err_descr() const
Definition: ErrorDetail.cc:694
HttpRequest::Pointer request
Definition: ErrorDetail.h:93
const char * GetErrorName(Security::ErrorCode value, const bool prefixRawCode=false)
Definition: ErrorDetail.cc:540
T * get() const
Returns raw and possibly nullptr pointer.
void clean()
Definition: String.cc:125

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors