2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
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.
10 #include "errorpage.h"
12 #include "sbuf/SBuf.h"
13 #include "ssl/ErrorDetail.h"
14 #include "ssl/ErrorDetailManager.h"
18 static const char *OptionalSslErrors
[] = {
19 "X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER",
20 "X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION",
21 "X509_V_ERR_KEYUSAGE_NO_CRL_SIGN",
22 "X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION",
23 "X509_V_ERR_INVALID_NON_CA",
24 "X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED",
25 "X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE",
26 "X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED",
27 "X509_V_ERR_INVALID_EXTENSION",
28 "X509_V_ERR_INVALID_POLICY_EXTENSION",
29 "X509_V_ERR_NO_EXPLICIT_POLICY",
30 "X509_V_ERR_DIFFERENT_CRL_SCOPE",
31 "X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE",
32 "X509_V_ERR_UNNESTED_RESOURCE",
33 "X509_V_ERR_PERMITTED_VIOLATION",
34 "X509_V_ERR_EXCLUDED_VIOLATION",
35 "X509_V_ERR_SUBTREE_MINMAX",
36 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE",
37 "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX",
38 "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX",
39 "X509_V_ERR_CRL_PATH_VALIDATION_ERROR",
40 "X509_V_ERR_PATH_LOOP",
41 "X509_V_ERR_SUITE_B_INVALID_VERSION",
42 "X509_V_ERR_SUITE_B_INVALID_ALGORITHM",
43 "X509_V_ERR_SUITE_B_INVALID_CURVE",
44 "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM",
45 "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED",
46 "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256",
47 "X509_V_ERR_HOSTNAME_MISMATCH",
48 "X509_V_ERR_EMAIL_MISMATCH",
49 "X509_V_ERR_IP_ADDRESS_MISMATCH",
50 "X509_V_ERR_DANE_NO_MATCH",
51 "X509_V_ERR_EE_KEY_TOO_SMALL",
52 "X509_V_ERR_CA_KEY_TOO_SMALL",
53 "X509_V_ERR_CA_MD_TOO_WEAK",
54 "X509_V_ERR_INVALID_CALL",
55 "X509_V_ERR_STORE_LOOKUP",
56 "X509_V_ERR_NO_VALID_SCTS",
57 "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION",
58 "X509_V_ERR_OCSP_VERIFY_NEEDED",
59 "X509_V_ERR_OCSP_VERIFY_FAILED",
60 "X509_V_ERR_OCSP_CERT_UNKNOWN",
64 struct SslErrorAlias
{
66 const Security::ErrorCode
*errors
;
69 static const Security::ErrorCode hasExpired
[] = {X509_V_ERR_CERT_HAS_EXPIRED
, SSL_ERROR_NONE
};
70 static const Security::ErrorCode notYetValid
[] = {X509_V_ERR_CERT_NOT_YET_VALID
, SSL_ERROR_NONE
};
71 static const Security::ErrorCode domainMismatch
[] = {SQUID_X509_V_ERR_DOMAIN_MISMATCH
, SSL_ERROR_NONE
};
72 static const Security::ErrorCode certUntrusted
[] = {X509_V_ERR_INVALID_CA
,
73 X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
,
74 X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
,
75 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
,
76 X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,
77 X509_V_ERR_CERT_UNTRUSTED
, SSL_ERROR_NONE
79 static const Security::ErrorCode certSelfSigned
[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
, SSL_ERROR_NONE
};
81 // The list of error name shortcuts for use with ssl_error acls.
82 // The keys without the "ssl::" scope prefix allow shorter error
83 // names within the SSL options scope. This is easier than
84 // carefully stripping the scope prefix in Ssl::ParseErrorString().
85 static SslErrorAlias TheSslErrorShortcutsArray
[] = {
86 {"ssl::certHasExpired", hasExpired
},
87 {"certHasExpired", hasExpired
},
88 {"ssl::certNotYetValid", notYetValid
},
89 {"certNotYetValid", notYetValid
},
90 {"ssl::certDomainMismatch", domainMismatch
},
91 {"certDomainMismatch", domainMismatch
},
92 {"ssl::certUntrusted", certUntrusted
},
93 {"certUntrusted", certUntrusted
},
94 {"ssl::certSelfSigned", certSelfSigned
},
95 {"certSelfSigned", certSelfSigned
},
99 // Use std::map to optimize search.
100 typedef std::map
<std::string
, const Security::ErrorCode
*> SslErrorShortcuts
;
101 SslErrorShortcuts TheSslErrorShortcuts
;
103 static void loadSslErrorShortcutsMap()
105 assert(TheSslErrorShortcuts
.empty());
106 for (int i
= 0; TheSslErrorShortcutsArray
[i
].name
; ++i
)
107 TheSslErrorShortcuts
[TheSslErrorShortcutsArray
[i
].name
] = TheSslErrorShortcutsArray
[i
].errors
;
111 Ssl::ParseErrorString(const char *name
, Security::Errors
&errors
)
115 const Security::ErrorCode ssl_error
= GetErrorCode(name
);
116 if (ssl_error
!= SSL_ERROR_NONE
) {
117 errors
.emplace(ssl_error
);
121 if (xisdigit(*name
)) {
122 const long int value
= strtol(name
, nullptr, 0);
123 if ((SQUID_TLS_ERR_OFFSET
< value
&& value
< SQUID_TLS_ERR_END
) || // custom
124 (value
>= 0)) { // an official error, including SSL_ERROR_NONE
125 errors
.emplace(value
);
128 fatalf("Too small or too big TLS error code '%s'", name
);
131 if (TheSslErrorShortcuts
.empty())
132 loadSslErrorShortcutsMap();
134 const SslErrorShortcuts::const_iterator it
= TheSslErrorShortcuts
.find(name
);
135 if (it
!= TheSslErrorShortcuts
.end()) {
136 // Should not be empty...
137 assert(it
->second
[0] != SSL_ERROR_NONE
);
138 for (int i
= 0; it
->second
[i
] != SSL_ERROR_NONE
; ++i
) {
139 errors
.emplace(it
->second
[i
]);
144 fatalf("Unknown TLS error name '%s'", name
);
145 return false; // not reached
149 Ssl::ErrorIsOptional(const char *name
)
151 for (int i
= 0; OptionalSslErrors
[i
] != nullptr; ++i
) {
152 if (strcmp(name
, OptionalSslErrors
[i
]) == 0)
159 Ssl::GetErrorDescr(Security::ErrorCode value
)
161 if (const auto detail
= ErrorDetailsManager::GetInstance().findDefaultDetail(value
))
162 return detail
->descr
;