]>
Commit | Line | Data |
---|---|---|
bbc27441 | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors |
bbc27441 AJ |
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 | ||
582c2af2 | 9 | #include "squid.h" |
02259ff8 | 10 | #include "errorpage.h" |
ed6e9fb9 | 11 | #include "fatal.h" |
4e143970 | 12 | #include "sbuf/SBuf.h" |
4d16918e | 13 | #include "ssl/ErrorDetail.h" |
83b053a0 | 14 | #include "ssl/ErrorDetailManager.h" |
074d6a40 | 15 | |
074d6a40 | 16 | #include <map> |
4d16918e | 17 | |
645deacc CT |
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", | |
1dcb1d49 CT |
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", | |
aee3523a | 61 | nullptr |
645deacc CT |
62 | }; |
63 | ||
cf1c09f6 CT |
64 | struct SslErrorAlias { |
65 | const char *name; | |
13cd7dee | 66 | const Security::ErrorCode *errors; |
cf1c09f6 CT |
67 | }; |
68 | ||
13cd7dee AJ |
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, | |
83317b32 SM |
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 | |
78 | }; | |
13cd7dee | 79 | static const Security::ErrorCode certSelfSigned[] = {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, SSL_ERROR_NONE}; |
cf1c09f6 CT |
80 | |
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 | |
7a957a93 | 84 | // carefully stripping the scope prefix in Ssl::ParseErrorString(). |
cf1c09f6 CT |
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}, | |
aee3523a | 96 | {nullptr, nullptr} |
cf1c09f6 CT |
97 | }; |
98 | ||
7a957a93 | 99 | // Use std::map to optimize search. |
13cd7dee | 100 | typedef std::map<std::string, const Security::ErrorCode *> SslErrorShortcuts; |
cf1c09f6 CT |
101 | SslErrorShortcuts TheSslErrorShortcuts; |
102 | ||
cf1c09f6 CT |
103 | static void loadSslErrorShortcutsMap() |
104 | { | |
105 | assert(TheSslErrorShortcuts.empty()); | |
a38ec4b1 | 106 | for (int i = 0; TheSslErrorShortcutsArray[i].name; ++i) |
cf1c09f6 CT |
107 | TheSslErrorShortcuts[TheSslErrorShortcutsArray[i].name] = TheSslErrorShortcutsArray[i].errors; |
108 | } | |
109 | ||
83f8d8f9 AJ |
110 | bool |
111 | Ssl::ParseErrorString(const char *name, Security::Errors &errors) | |
4d16918e CT |
112 | { |
113 | assert(name); | |
114 | ||
13cd7dee | 115 | const Security::ErrorCode ssl_error = GetErrorCode(name); |
83f8d8f9 AJ |
116 | if (ssl_error != SSL_ERROR_NONE) { |
117 | errors.emplace(ssl_error); | |
118 | return true; | |
119 | } | |
4d16918e CT |
120 | |
121 | if (xisdigit(*name)) { | |
aee3523a | 122 | const long int value = strtol(name, nullptr, 0); |
83b053a0 CT |
123 | if ((SQUID_TLS_ERR_OFFSET < value && value < SQUID_TLS_ERR_END) || // custom |
124 | (value >= 0)) { // an official error, including SSL_ERROR_NONE | |
83f8d8f9 AJ |
125 | errors.emplace(value); |
126 | return true; | |
127 | } | |
128 | fatalf("Too small or too big TLS error code '%s'", name); | |
4d16918e CT |
129 | } |
130 | ||
cf1c09f6 CT |
131 | if (TheSslErrorShortcuts.empty()) |
132 | loadSslErrorShortcutsMap(); | |
133 | ||
134 | const SslErrorShortcuts::const_iterator it = TheSslErrorShortcuts.find(name); | |
135 | if (it != TheSslErrorShortcuts.end()) { | |
136 | // Should not be empty... | |
87f237a9 | 137 | assert(it->second[0] != SSL_ERROR_NONE); |
83f8d8f9 AJ |
138 | for (int i = 0; it->second[i] != SSL_ERROR_NONE; ++i) { |
139 | errors.emplace(it->second[i]); | |
cf1c09f6 | 140 | } |
83f8d8f9 | 141 | return true; |
cf1c09f6 CT |
142 | } |
143 | ||
83f8d8f9 AJ |
144 | fatalf("Unknown TLS error name '%s'", name); |
145 | return false; // not reached | |
4d16918e CT |
146 | } |
147 | ||
645deacc CT |
148 | bool |
149 | Ssl::ErrorIsOptional(const char *name) | |
150 | { | |
aee3523a | 151 | for (int i = 0; OptionalSslErrors[i] != nullptr; ++i) { |
645deacc CT |
152 | if (strcmp(name, OptionalSslErrors[i]) == 0) |
153 | return true; | |
154 | } | |
155 | return false; | |
156 | } | |
157 | ||
4e143970 | 158 | std::optional<SBuf> |
13cd7dee | 159 | Ssl::GetErrorDescr(Security::ErrorCode value) |
cf09bec7 | 160 | { |
4e143970 FC |
161 | if (const auto detail = ErrorDetailsManager::GetInstance().findDefaultDetail(value)) |
162 | return detail->descr; | |
163 | return std::nullopt; | |
cf09bec7 CT |
164 | } |
165 |