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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors