ErrorDetail.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 "base/IoManip.h"
11 #include "error/SysErrorDetail.h"
12 #include "html_quote.h"
13 #include "sbuf/SBuf.h"
14 #include "sbuf/Stream.h"
15 #include "security/Certificate.h"
16 #include "security/ErrorDetail.h"
17 #include "security/forward.h"
18 #include "security/Io.h"
19 #include "util.h"
20 
21 #if USE_OPENSSL
22 #include "ssl/ErrorDetailManager.h"
23 #elif USE_GNUTLS
24 #if HAVE_GNUTLS_GNUTLS_H
25 #include <gnutls/gnutls.h>
26 #endif
27 #endif
28 #include <map>
29 
30 namespace Security {
31 
32 // we use std::map to optimize search; TODO: Use std::unordered_map instead?
33 typedef std::map<ErrorCode, const char *> ErrorCodeNames;
36  "SQUID_TLS_ERR_ACCEPT"
37  },
39  "SQUID_TLS_ERR_CONNECT"
40  },
42  "SQUID_X509_V_ERR_INFINITE_VALIDATION"
43  },
45  "SQUID_X509_V_ERR_CERT_CHANGE"
46  },
48  "SQUID_X509_V_ERR_DOMAIN_MISMATCH"
49  },
50 #if USE_OPENSSL
51  { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
52  "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"
53  },
54  { X509_V_ERR_UNABLE_TO_GET_CRL,
55  "X509_V_ERR_UNABLE_TO_GET_CRL"
56  },
57  { X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
58  "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"
59  },
60  { X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
61  "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"
62  },
63  { X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
64  "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"
65  },
66  { X509_V_ERR_CERT_SIGNATURE_FAILURE,
67  "X509_V_ERR_CERT_SIGNATURE_FAILURE"
68  },
69  { X509_V_ERR_CRL_SIGNATURE_FAILURE,
70  "X509_V_ERR_CRL_SIGNATURE_FAILURE"
71  },
72  { X509_V_ERR_CERT_NOT_YET_VALID,
73  "X509_V_ERR_CERT_NOT_YET_VALID"
74  },
75  { X509_V_ERR_CERT_HAS_EXPIRED,
76  "X509_V_ERR_CERT_HAS_EXPIRED"
77  },
78  { X509_V_ERR_CRL_NOT_YET_VALID,
79  "X509_V_ERR_CRL_NOT_YET_VALID"
80  },
81  { X509_V_ERR_CRL_HAS_EXPIRED,
82  "X509_V_ERR_CRL_HAS_EXPIRED"
83  },
84  { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
85  "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"
86  },
87  { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
88  "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"
89  },
90  { X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
91  "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"
92  },
93  { X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
94  "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"
95  },
96  { X509_V_ERR_OUT_OF_MEM,
97  "X509_V_ERR_OUT_OF_MEM"
98  },
99  { X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
100  "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"
101  },
102  { X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
103  "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"
104  },
105  { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
106  "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"
107  },
108  { X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
109  "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"
110  },
111  { X509_V_ERR_CERT_CHAIN_TOO_LONG,
112  "X509_V_ERR_CERT_CHAIN_TOO_LONG"
113  },
114  { X509_V_ERR_CERT_REVOKED,
115  "X509_V_ERR_CERT_REVOKED"
116  },
117  { X509_V_ERR_INVALID_CA,
118  "X509_V_ERR_INVALID_CA"
119  },
120  { X509_V_ERR_PATH_LENGTH_EXCEEDED,
121  "X509_V_ERR_PATH_LENGTH_EXCEEDED"
122  },
123  { X509_V_ERR_INVALID_PURPOSE,
124  "X509_V_ERR_INVALID_PURPOSE"
125  },
126  { X509_V_ERR_CERT_UNTRUSTED,
127  "X509_V_ERR_CERT_UNTRUSTED"
128  },
129  { X509_V_ERR_CERT_REJECTED,
130  "X509_V_ERR_CERT_REJECTED"
131  },
132  { X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
133  "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"
134  },
135  { X509_V_ERR_AKID_SKID_MISMATCH,
136  "X509_V_ERR_AKID_SKID_MISMATCH"
137  },
138  { X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
139  "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"
140  },
141  { X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
142  "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"
143  },
144 #if defined(X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER)
145  {
146  X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, // 33
147  "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER"
148  },
149 #endif
150 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION)
151  {
152  X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, // 34
153  "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION"
154  },
155 #endif
156 #if defined(X509_V_ERR_KEYUSAGE_NO_CRL_SIGN)
157  {
158  X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, // 35
159  "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN"
160  },
161 #endif
162 #if defined(X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION)
163  {
164  X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, // 36
165  "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION"
166  },
167 #endif
168 #if defined(X509_V_ERR_INVALID_NON_CA)
169  {
170  X509_V_ERR_INVALID_NON_CA, // 37
171  "X509_V_ERR_INVALID_NON_CA"
172  },
173 #endif
174 #if defined(X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED)
175  {
176  X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, // 38
177  "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED"
178  },
179 #endif
180 #if defined(X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE)
181  {
182  X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, // 39
183  "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE"
184  },
185 #endif
186 #if defined(X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED)
187  {
188  X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, // 40
189  "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED"
190  },
191 #endif
192 #if defined(X509_V_ERR_INVALID_EXTENSION)
193  {
194  X509_V_ERR_INVALID_EXTENSION, // 41
195  "X509_V_ERR_INVALID_EXTENSION"
196  },
197 #endif
198 #if defined(X509_V_ERR_INVALID_POLICY_EXTENSION)
199  {
200  X509_V_ERR_INVALID_POLICY_EXTENSION, // 42
201  "X509_V_ERR_INVALID_POLICY_EXTENSION"
202  },
203 #endif
204 #if defined(X509_V_ERR_NO_EXPLICIT_POLICY)
205  {
206  X509_V_ERR_NO_EXPLICIT_POLICY, // 43
207  "X509_V_ERR_NO_EXPLICIT_POLICY"
208  },
209 #endif
210 #if defined(X509_V_ERR_DIFFERENT_CRL_SCOPE)
211  {
212  X509_V_ERR_DIFFERENT_CRL_SCOPE, // 44
213  "X509_V_ERR_DIFFERENT_CRL_SCOPE"
214  },
215 #endif
216 #if defined(X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE)
217  {
218  X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, // 45
219  "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE"
220  },
221 #endif
222 #if defined(X509_V_ERR_UNNESTED_RESOURCE)
223  {
224  X509_V_ERR_UNNESTED_RESOURCE, // 46
225  "X509_V_ERR_UNNESTED_RESOURCE"
226  },
227 #endif
228 #if defined(X509_V_ERR_PERMITTED_VIOLATION)
229  {
230  X509_V_ERR_PERMITTED_VIOLATION, // 47
231  "X509_V_ERR_PERMITTED_VIOLATION"
232  },
233 #endif
234 #if defined(X509_V_ERR_EXCLUDED_VIOLATION)
235  {
236  X509_V_ERR_EXCLUDED_VIOLATION, // 48
237  "X509_V_ERR_EXCLUDED_VIOLATION"
238  },
239 #endif
240 #if defined(X509_V_ERR_SUBTREE_MINMAX)
241  {
242  X509_V_ERR_SUBTREE_MINMAX, // 49
243  "X509_V_ERR_SUBTREE_MINMAX"
244  },
245 #endif
246  { X509_V_ERR_APPLICATION_VERIFICATION, // 50
247  "X509_V_ERR_APPLICATION_VERIFICATION"
248  },
249 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE)
250  {
251  X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, // 51
252  "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE"
253  },
254 #endif
255 #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX)
256  {
257  X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, // 52
258  "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX"
259  },
260 #endif
261 #if defined(X509_V_ERR_UNSUPPORTED_NAME_SYNTAX)
262  {
263  X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, // 53
264  "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX"
265  },
266 #endif
267 #if defined(X509_V_ERR_CRL_PATH_VALIDATION_ERROR)
268  {
269  X509_V_ERR_CRL_PATH_VALIDATION_ERROR, // 54
270  "X509_V_ERR_CRL_PATH_VALIDATION_ERROR"
271  },
272 #endif
273 #if defined(X509_V_ERR_PATH_LOOP)
274  {
275  X509_V_ERR_PATH_LOOP, // 55
276  "X509_V_ERR_PATH_LOOP"
277  },
278 #endif
279 #if defined(X509_V_ERR_SUITE_B_INVALID_VERSION)
280  {
281  X509_V_ERR_SUITE_B_INVALID_VERSION, // 56
282  "X509_V_ERR_SUITE_B_INVALID_VERSION"
283  },
284 #endif
285 #if defined(X509_V_ERR_SUITE_B_INVALID_ALGORITHM)
286  {
287  X509_V_ERR_SUITE_B_INVALID_ALGORITHM, // 57
288  "X509_V_ERR_SUITE_B_INVALID_ALGORITHM"
289  },
290 #endif
291 #if defined(X509_V_ERR_SUITE_B_INVALID_CURVE)
292  {
293  X509_V_ERR_SUITE_B_INVALID_CURVE, // 58
294  "X509_V_ERR_SUITE_B_INVALID_CURVE"
295  },
296 #endif
297 #if defined(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM)
298  {
299  X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM, // 59
300  "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM"
301  },
302 #endif
303 #if defined(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED)
304  {
305  X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED, // 60
306  "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED"
307  },
308 #endif
309 #if defined(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256)
310  {
311  X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256, // 61
312  "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256"
313  },
314 #endif
315 #if defined(X509_V_ERR_HOSTNAME_MISMATCH)
316  {
317  X509_V_ERR_HOSTNAME_MISMATCH, // 62
318  "X509_V_ERR_HOSTNAME_MISMATCH"
319  },
320 #endif
321 #if defined(X509_V_ERR_EMAIL_MISMATCH)
322  {
323  X509_V_ERR_EMAIL_MISMATCH, // 63
324  "X509_V_ERR_EMAIL_MISMATCH"
325  },
326 #endif
327 #if defined(X509_V_ERR_IP_ADDRESS_MISMATCH)
328  {
329  X509_V_ERR_IP_ADDRESS_MISMATCH, // 64
330  "X509_V_ERR_IP_ADDRESS_MISMATCH"
331  },
332 #endif
333 #if defined(X509_V_ERR_DANE_NO_MATCH)
334  {
335  X509_V_ERR_DANE_NO_MATCH, // 65
336  "X509_V_ERR_DANE_NO_MATCH"
337  },
338 #endif
339 #if defined(X509_V_ERR_EE_KEY_TOO_SMALL)
340  {
341  X509_V_ERR_EE_KEY_TOO_SMALL, // 66
342  "X509_V_ERR_EE_KEY_TOO_SMALL"
343  },
344 #endif
345 #if defined(X509_V_ERR_CA_KEY_TOO_SMALL)
346  {
347  X509_V_ERR_CA_KEY_TOO_SMALL, // 67
348  "X509_V_ERR_CA_KEY_TOO_SMALL"
349  },
350 #endif
351 #if defined(X509_V_ERR_CA_MD_TOO_WEAK)
352  {
353  X509_V_ERR_CA_MD_TOO_WEAK, // 68
354  "X509_V_ERR_CA_MD_TOO_WEAK"
355  },
356 #endif
357 #if defined(X509_V_ERR_INVALID_CALL)
358  {
359  X509_V_ERR_INVALID_CALL, // 69
360  "X509_V_ERR_INVALID_CALL"
361  },
362 #endif
363 #if defined(X509_V_ERR_STORE_LOOKUP)
364  {
365  X509_V_ERR_STORE_LOOKUP, // 70
366  "X509_V_ERR_STORE_LOOKUP"
367  },
368 #endif
369 #if defined(X509_V_ERR_NO_VALID_SCTS)
370  {
371  X509_V_ERR_NO_VALID_SCTS, // 71
372  "X509_V_ERR_NO_VALID_SCTS"
373  },
374 #endif
375 #if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION)
376  {
377  X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION, // 72
378  "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION"
379  },
380 #endif
381 #if defined(X509_V_ERR_OCSP_VERIFY_NEEDED)
382  {
383  X509_V_ERR_OCSP_VERIFY_NEEDED, // 73
384  "X509_V_ERR_OCSP_VERIFY_NEEDED"
385  },
386 #endif
387 #if defined(X509_V_ERR_OCSP_VERIFY_FAILED)
388  {
389  X509_V_ERR_OCSP_VERIFY_FAILED, // 74
390  "X509_V_ERR_OCSP_VERIFY_FAILED"
391  },
392 #endif
393 #if defined(X509_V_ERR_OCSP_CERT_UNKNOWN)
394  {
395  X509_V_ERR_OCSP_CERT_UNKNOWN, // 75
396  "X509_V_ERR_OCSP_CERT_UNKNOWN"
397  },
398 #endif
399  {
400  SSL_ERROR_NONE,
401  "SSL_ERROR_NONE"
402  },
403 #endif // USE_OPENSSL
404 };
405 
406 } // namespace Security
407 
410 {
411  static auto TheCmp = [](const char *a, const char *b) {return strcmp(a, b) < 0;};
412  static std::map<const char *, ErrorCode, decltype(TheCmp)> TheErrorCodeByNameIndx(TheCmp);
413  if (TheErrorCodeByNameIndx.empty()) {
414  for (const auto &i: TheErrorCodeNames)
415  TheErrorCodeByNameIndx.insert(std::make_pair(i.second, i.first));
416 
417  // redirector to support legacy error translations
418  TheErrorCodeByNameIndx.insert(std::make_pair("SQUID_ERR_SSL_HANDSHAKE", SQUID_TLS_ERR_CONNECT));
419  }
420 
421  const auto it = TheErrorCodeByNameIndx.find(name);
422  if (it != TheErrorCodeByNameIndx.end())
423  return it->second;
424 
425  return 0;
426 }
427 
428 const char *
429 Security::ErrorNameFromCode(const ErrorCode err, const bool prefixRawCode)
430 {
431  const auto it = TheErrorCodeNames.find(err);
432  if (it != TheErrorCodeNames.end())
433  return it->second;
434 
435  static char tmpBuffer[128];
436  snprintf(tmpBuffer, sizeof(tmpBuffer), "%s%d",
437  (prefixRawCode ? "SSL_ERR=" : ""), static_cast<int>(err));
438  return tmpBuffer;
439 }
440 
441 /* Security::ErrorDetail */
442 
444 Security::ErrorDetail::ErrorDetail(const ErrorCode err, const int aSysErrorNo):
445  error_no(err),
446  // We could restrict errno(3) collection to cases where the TLS library
447  // explicitly talks about the errno being set, but correctly detecting those
448  // cases is difficult. We simplify in hope that all other cases will either
449  // have a useful errno or a zero errno.
450  sysErrorNo(aSysErrorNo)
451 {
452 #if USE_OPENSSL
453  if ((lib_error_no = ERR_get_error())) {
455  debugs(83, 7, "got " << asHex(lib_error_no));
456  // more errors may be stacked
457  // TODO: Save/detail all stacked errors by always flushing stale ones.
458  ForgetErrors();
459  }
460 #else
461  // other libraries return errors explicitly instead of auto-storing them
462 #endif
463 }
464 
465 Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode, const CertPointer &cert, const CertPointer &broken, const char *aReason):
466  ErrorDetail(anErrorCode, 0)
467 {
468  errReason = aReason;
469  peer_cert = cert;
470  broken_cert = broken ? broken : cert;
471 }
472 
473 #if USE_OPENSSL
474 Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode, const int anIoErrorNo, const int aSysErrorNo):
475  ErrorDetail(anErrorCode, aSysErrorNo)
476 {
477  ioErrorNo = anIoErrorNo;
478 }
479 
480 #elif USE_GNUTLS
481 Security::ErrorDetail::ErrorDetail(const ErrorCode anErrorCode, const LibErrorCode aLibErrorNo, const int aSysErrorNo):
482  ErrorDetail(anErrorCode, aSysErrorNo)
483 {
484  lib_error_no = aLibErrorNo;
485 }
486 #endif
487 
488 void
490 {
491  assert(cert);
492  assert(!peer_cert);
493  assert(!broken_cert);
494  peer_cert = cert;
495  // unlike the constructor, the supplied certificate is not a broken_cert
496 }
497 
498 SBuf
500 {
501  SBuf buf(err_code()); // TODO: Upgrade err_code()/etc. to return SBuf.
502 
503  if (lib_error_no) {
504 #if USE_OPENSSL
505  // TODO: Log ERR_error_string_n() instead, despite length, whitespace?
506  // Example: `error:1408F09C:SSL routines:ssl3_get_record:http request`.
507  buf.append(ToSBuf("+TLS_LIB_ERR=", std::hex, std::uppercase, lib_error_no));
508 #elif USE_GNUTLS
509  buf.append(ToSBuf("+", gnutls_strerror_name(lib_error_no)));
510 #endif
511  }
512 
513 #if USE_OPENSSL
514  // TODO: Consider logging long but human-friendly names (e.g.,
515  // SSL_ERROR_SYSCALL).
516  if (ioErrorNo)
517  buf.append(ToSBuf("+TLS_IO_ERR=", ioErrorNo));
518 #endif
519 
520  if (sysErrorNo) {
521  buf.append('+');
522  buf.append(SysErrorDetail::Brief(sysErrorNo));
523  }
524 
525  if (broken_cert)
526  buf.append("+broken_cert");
527 
528  return buf;
529 }
530 
531 SBuf
533 {
534  char const *format = nullptr;
535 #if USE_OPENSSL
536  if (Ssl::ErrorDetailsManager::GetInstance().getErrorDetail(error_no, request, detailEntry))
537  format = detailEntry.detail.termedBuf();
538 #else
539  (void)request;
540 #endif
541  if (!format)
542  format = "SSL handshake error (%err_name)";
543 
544  SBuf errDetailStr;
545  assert(format);
546  auto remainder = format;
547  while (auto p = strchr(remainder, '%')) {
548  errDetailStr.append(remainder, p - remainder);
549  char const *converted = nullptr;
550  const auto formattingCodeLen = convert(++p, &converted);
551  if (formattingCodeLen)
552  errDetailStr.append(converted);
553  else
554  errDetailStr.append("%");
555  remainder = p + formattingCodeLen;
556  }
557  errDetailStr.append(remainder, strlen(remainder));
558  return errDetailStr;
559 }
560 
562 const char *
564 {
565  if (broken_cert) {
566  auto buf = SubjectName(*broken_cert);
567  if (!buf.isEmpty()) {
568  // quote to avoid possible html code injection through
569  // certificate subject
570  return html_quote(buf.c_str());
571  }
572  }
573  return "[Not available]";
574 }
575 
576 #if USE_OPENSSL
577 static int
579 copy_cn(void *check_data, ASN1_STRING *cn_data)
580 {
581  const auto str = static_cast<String*>(check_data);
582  if (!str) // no data? abort
583  return 0;
584  if (cn_data && cn_data->length) {
585  if (str->size() > 0)
586  str->append(", ");
587  str->append(reinterpret_cast<const char *>(cn_data->data), cn_data->length);
588  }
589  return 1;
590 }
591 #endif // USE_OPENSSL
592 
594 const char *
596 {
597 #if USE_OPENSSL
598  if (broken_cert.get()) {
599  static String tmpStr;
600  tmpStr.clean();
601  Ssl::matchX509CommonNames(broken_cert.get(), &tmpStr, copy_cn);
602  if (tmpStr.size()) {
603  // quote to avoid possible HTML code injection through
604  // certificate subject
605  return html_quote(tmpStr.termedBuf());
606  }
607  }
608 #endif // USE_OPENSSL
609  return "[Not available]";
610 }
611 
613 const char *
615 {
616  if (broken_cert) {
617  auto buf = IssuerName(*broken_cert);
618  if (!buf.isEmpty()) {
619  // quote to avoid possible html code injection through
620  // certificate issuer subject
621  return html_quote(buf.c_str());
622  }
623  }
624  return "[Not available]";
625 }
626 
628 const char *
630 {
631 #if USE_OPENSSL
632  if (broken_cert.get()) {
633  if (const auto tm = X509_getm_notBefore(broken_cert.get())) {
634  static char tmpBuffer[256]; // A temporary buffer
635  Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
636  return tmpBuffer;
637  }
638  }
639 #endif // USE_OPENSSL
640  return "[Not available]";
641 }
642 
644 const char *
646 {
647 #if USE_OPENSSL
648  if (broken_cert.get()) {
649  if (const auto tm = X509_getm_notAfter(broken_cert.get())) {
650  static char tmpBuffer[256]; // A temporary buffer
651  Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
652  return tmpBuffer;
653  }
654  }
655 #endif // USE_OPENSSL
656  return "[Not available]";
657 }
658 
660 const char *
662 {
663 #if USE_OPENSSL
664  // try detailEntry first because it is faster
665  if (const char *err = detailEntry.name.termedBuf())
666  return err;
667 #endif
668 
669  return ErrorNameFromCode(error_no);
670 }
671 
673 const char *
675 {
676  if (!error_no)
677  return "[No Error]";
678 #if USE_OPENSSL
679  if (const char *err = detailEntry.descr.termedBuf())
680  return err;
681 #endif
682  return "[Not available]";
683 }
684 
686 const char *
688 {
689  if (errReason.size() > 0)
690  return errReason.termedBuf();
691  else if (lib_error_no)
692  return ErrorString(lib_error_no);
693  else
694  return "[No Error]";
695  return "[Not available]";
696 }
697 
716 size_t
717 Security::ErrorDetail::convert(const char *code, const char **value) const
718 {
719  typedef const char *(ErrorDetail::*PartDescriber)() const;
720  static const std::map<const char*, PartDescriber> PartDescriberByCode = {
721  {"ssl_subject", &ErrorDetail::subject},
722  {"ssl_ca_name", &ErrorDetail::ca_name},
723  {"ssl_cn", &ErrorDetail::cn},
724  {"ssl_notbefore", &ErrorDetail::notbefore},
725  {"ssl_notafter", &ErrorDetail::notafter},
726  {"err_name", &ErrorDetail::err_code},
727  {"ssl_error_descr", &ErrorDetail::err_descr},
728  {"ssl_lib_error", &ErrorDetail::err_lib_error}
729  };
730 
731  for (const auto &pair: PartDescriberByCode) {
732  const auto len = strlen(pair.first);
733  if (strncmp(code, pair.first, len) == 0) {
734  const auto method = pair.second;
735  *value = (this->*method)();
736  return len;
737  }
738  }
739 
740  // TODO: Support logformat %codes.
741  *value = ""; // unused with zero return
742  return 0;
743 }
744 
ErrorCode ErrorCodeFromName(const char *name)
Definition: ErrorDetail.cc:409
int ErrorCode
Squid-defined error code (<0), an error code returned by X.509 API, or zero.
Definition: forward.h:110
int asn1timeToString(ASN1_TIME *tm, char *buf, int len)
Definition: support.cc:181
virtual SBuf brief() const
Definition: ErrorDetail.cc:499
int matchX509CommonNames(X509 *peer_cert, void *check_data, int(*check_func)(void *check_data, ASN1_STRING *cn_data))
Definition: support.cc:195
static const ErrorCodeNames TheErrorCodeNames
Definition: ErrorDetail.cc:34
Definition: SBuf.h:94
char * html_quote(const char *)
Definition: html_quote.c:53
@ SQUID_TLS_ERR_CONNECT
failure to establish a connection with a TLS server
Definition: forward.h:220
const char * subject() const
textual representation of the subject of the broken certificate
Definition: ErrorDetail.cc:563
SBuf SubjectName(Certificate &)
The SubjectName field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:68
const char * cn() const
a list of the broken certificates CN and alternate names
Definition: ErrorDetail.cc:595
CertPointer broken_cert
A pointer to the broken certificate (peer or intermediate)
Definition: ErrorDetail.h:95
#define X509_getm_notBefore
Definition: openssl.h:248
void append(char const *buf, int len)
Definition: String.cc:149
void setPeerCertificate(const CertPointer &)
Definition: ErrorDetail.cc:489
const char * err_descr() const
short description of error_no
Definition: ErrorDetail.cc:674
unsigned char code
Definition: html_quote.c:20
AsHex< Integer > asHex(const Integer n)
a helper to ease AsHex object creation
Definition: IoManip.h:81
virtual SBuf verbose(const HttpRequestPointer &) const
Definition: ErrorDetail.cc:532
@ SQUID_X509_V_ERR_INFINITE_VALIDATION
Definition: forward.h:225
void ForgetErrors()
clear any errors that a TLS library has accumulated in its global storage
Definition: Io.cc:57
#define assert(EX)
Definition: assert.h:19
char const * termedBuf() const
Definition: SquidString.h:92
SBuf ErrorDetail
Definition: Esi.h:29
SBuf IssuerName(Certificate &)
The Issuer field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:28
const char * ErrorNameFromCode(ErrorCode err, bool prefixRawCode=false)
Definition: ErrorDetail.cc:429
static int copy_cn(void *check_data, ASN1_STRING *cn_data)
helper function to collect CNs using Ssl::matchX509CommonNames()
Definition: ErrorDetail.cc:579
@ SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: forward.h:224
static SBuf Brief(int errorNo)
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
ErrorDetail(ErrorCode err_no, const CertPointer &peer, const CertPointer &broken, const char *aReason=NULL)
Definition: ErrorDetail.cc:465
#define X509_getm_notAfter
Definition: openssl.h:247
@ SQUID_X509_V_ERR_CERT_CHANGE
Definition: forward.h:223
static ErrorDetailsManager & GetInstance()
Instance class.
String errReason
a custom reason for the error
Definition: ErrorDetail.h:119
const char * notafter() const
textual representation of the "not after" field of the broken certificate
Definition: ErrorDetail.cc:645
const char * err_code() const
textual representation of error_no
Definition: ErrorDetail.cc:661
size_type size() const
Definition: SquidString.h:73
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
const char * notbefore() const
textual representation of the "not before" field of the broken certificate
Definition: ErrorDetail.cc:629
@ SQUID_TLS_ERR_ACCEPT
failure to accept a connection from a TLS client
Definition: forward.h:219
size_t convert(const char *code, const char **value) const
Definition: ErrorDetail.cc:717
std::map< ErrorCode, const char * > ErrorCodeNames
Definition: ErrorDetail.cc:33
const char * ca_name() const
the issuer of the broken certificate
Definition: ErrorDetail.cc:614
CertPointer peer_cert
A pointer to the peer certificate.
Definition: ErrorDetail.h:94
Network/connection security abstraction layer.
Definition: Connection.h:34
const char * err_lib_error() const
textual representation of lib_error_no
Definition: ErrorDetail.cc:687
const char * ErrorString(const LibErrorCode code)
converts numeric LibErrorCode into a human-friendlier string
Definition: forward.h:131
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
LibErrorCode lib_error_no
TLS library-reported non-validation error or zero;.
Definition: ErrorDetail.h:101
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:196
unsigned long LibErrorCode
TLS library-reported non-validation error.
Definition: forward.h:120
void clean()
Definition: String.cc:118

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors