]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/ErrorDetail.cc
Remove useless checks and debug. size_t is guaranteed to be signed
[thirdparty/squid.git] / src / ssl / ErrorDetail.cc
CommitLineData
4d16918e
CT
1#include "squid.h"
2#include "ssl/ErrorDetail.h"
3
4struct SslErrorDetailEntry {
461b9576 5 Ssl::ssl_error_t value;
4d16918e
CT
6 const char *name;
7 const char *detail;
8};
9
8211c314 10static const char *SslErrorDetailDefaultStr = "SSL certificate validation error (%err_name): %ssl_subject";
4d16918e
CT
11// TODO: optimize by replacing with std::map or similar
12static SslErrorDetailEntry TheSslDetailMap[] = {
e34763f4
A
13 { SQUID_X509_V_ERR_DOMAIN_MISMATCH,
14 "SQUID_X509_V_ERR_DOMAIN_MISMATCH",
15 "%err_name: The hostname you are connecting to (%H), does not match any of the Certificate valid names: %ssl_cn"},
4d16918e
CT
16 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
17 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT",
18 "%err_name: SSL Certficate error: certificate issuer (CA) not known: %ssl_ca_name" },
19 { X509_V_ERR_CERT_NOT_YET_VALID,
20 "X509_V_ERR_CERT_NOT_YET_VALID",
21 "%err_name: SSL Certficate is not valid before: %ssl_notbefore" },
22 { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
23 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD",
78d04f8f 24 "%err_name: SSL Certificate has invalid start date (the 'not before' field): %ssl_subject" },
4d16918e
CT
25 { X509_V_ERR_CERT_HAS_EXPIRED,
26 "X509_V_ERR_CERT_HAS_EXPIRED",
27 "%err_name: SSL Certificate expired on %ssl_notafter" },
28 { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
29 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD",
30 "%err_name: SSL Certificate has invalid expiration date (the 'not after' field): %ssl_subject" },
31 {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
32 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT",
33 "%err_name: Self-signed SSL Certificate: %ssl_subject"},
34 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
35 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
36 "%err_name: SSL Certficate error: certificate issuer (CA) not known: %ssl_ca_name" },
37 { SSL_ERROR_NONE, "SSL_ERROR_NONE", "%err_name: No error" },
38 {SSL_ERROR_NONE, NULL, NULL }
39};
40
461b9576 41Ssl::ssl_error_t
4d16918e
CT
42Ssl::parseErrorString(const char *name)
43{
44 assert(name);
45
46 for (int i = 0; TheSslDetailMap[i].name; ++i) {
47 if (strcmp(name, TheSslDetailMap[i].name) == 0)
48 return TheSslDetailMap[i].value;
49 }
50
51 if (xisdigit(*name)) {
52 const long int value = strtol(name, NULL, 0);
53 if (SQUID_SSL_ERROR_MIN <= value && value <= SQUID_SSL_ERROR_MAX)
54 return value;
55 fatalf("Too small or too bug SSL error code '%s'", name);
56 }
57
58 fatalf("Unknown SSL error name '%s'", name);
59 return SSL_ERROR_SSL; // not reached
60}
61
62const char *
461b9576 63Ssl::getErrorName(Ssl::ssl_error_t value)
4d16918e
CT
64{
65
66 for (int i = 0; TheSslDetailMap[i].name; ++i) {
67 if (TheSslDetailMap[i].value == value)
68 return TheSslDetailMap[i].name;
69 }
70
71 return NULL;
72}
73
461b9576 74static const char *getErrorDetail(Ssl::ssl_error_t value)
4d16918e
CT
75{
76 for (int i = 0; TheSslDetailMap[i].name; ++i) {
77 if (TheSslDetailMap[i].value == value)
78 return TheSslDetailMap[i].detail;
79 }
80
8211c314
CT
81 // we must always return something because ErrorDetail::buildDetail
82 // will hit an assertion
83 return SslErrorDetailDefaultStr;
4d16918e
CT
84}
85
e34763f4 86Ssl::ErrorDetail::err_frm_code Ssl::ErrorDetail::ErrorFormatingCodes[] = {
4d16918e
CT
87 {"ssl_subject", &Ssl::ErrorDetail::subject},
88 {"ssl_ca_name", &Ssl::ErrorDetail::ca_name},
89 {"ssl_cn", &Ssl::ErrorDetail::cn},
90 {"ssl_notbefore", &Ssl::ErrorDetail::notbefore},
91 {"ssl_notafter", &Ssl::ErrorDetail::notafter},
92 {"err_name", &Ssl::ErrorDetail::err_code},
93 {NULL,NULL}
94};
95
96/**
97 * The subject of the current certification in text form
98 */
99const char *Ssl::ErrorDetail::subject() const
100{
101 if (!peer_cert)
102 return "[Not available]";
103
104 static char tmpBuffer[256]; // A temporary buffer
105 X509_NAME_oneline(X509_get_subject_name(peer_cert.get()), tmpBuffer,
e34763f4
A
106 sizeof(tmpBuffer));
107 return tmpBuffer;
4d16918e
CT
108}
109
110// helper function to be used with Ssl::matchX509CommonNames
111static int copy_cn(void *check_data, ASN1_STRING *cn_data)
112{
113 String *str = (String *)check_data;
114 if (!str) // no data? abort
115 return 0;
116 if (str->defined())
117 str->append(", ");
118 str->append((const char *)cn_data->data, cn_data->length);
119 return 1;
120}
121
122/**
123 * The list with certificates cn and alternate names
124 */
125const char *Ssl::ErrorDetail::cn() const
126{
127 if (!peer_cert)
128 return "[Not available]";
129
130 static String tmpStr; ///< A temporary string buffer
131 tmpStr.clean();
132 Ssl::matchX509CommonNames(peer_cert.get(), &tmpStr, copy_cn);
133 return tmpStr.termedBuf();
134}
135
136/**
137 * The issuer name
138 */
139const char *Ssl::ErrorDetail::ca_name() const
140{
141 if (!peer_cert)
142 return "[Not available]";
143
144 static char tmpBuffer[256]; // A temporary buffer
145 X509_NAME_oneline(X509_get_issuer_name(peer_cert.get()), tmpBuffer, sizeof(tmpBuffer));
146 return tmpBuffer;
147}
148
149/**
150 * The certificate "not before" field
151 */
152const char *Ssl::ErrorDetail::notbefore() const
153{
154 if (!peer_cert)
155 return "[Not available]";
156
157 static char tmpBuffer[256]; // A temporary buffer
158 ASN1_UTCTIME * tm = X509_get_notBefore(peer_cert.get());
159 Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
160 return tmpBuffer;
161}
162
163/**
164 * The certificate "not after" field
165 */
166const char *Ssl::ErrorDetail::notafter() const
167{
168 if (!peer_cert)
169 return "[Not available]";
170
171 static char tmpBuffer[256]; // A temporary buffer
172 ASN1_UTCTIME * tm = X509_get_notAfter(peer_cert.get());
173 Ssl::asn1timeToString(tm, tmpBuffer, sizeof(tmpBuffer));
174 return tmpBuffer;
175}
176
177/**
178 * The string representation of the error_no
179 */
180const char *Ssl::ErrorDetail::err_code() const
181{
8211c314 182 static char tmpBuffer[64];
4d16918e 183 const char *err = getErrorName(error_no);
8211c314
CT
184 if (!err) {
185 snprintf(tmpBuffer, 64, "%d", (int)error_no);
186 err = tmpBuffer;
187 }
4d16918e
CT
188 return err;
189}
190
191/**
192 * It converts the code to a string value. Currently the following
193 * formating codes are supported:
194 * %err_name: The name of the SSL error
195 * %ssl_cn: The comma-separated list of common and alternate names
196 * %ssl_subject: The certificate subject
197 * %ssl_ca_name: The certificate issuer name
198 * %ssl_notbefore: The certificate "not before" field
199 * %ssl_notafter: The certificate "not after" field
200 \retval the length of the code (the number of characters will be replaced by value)
201*/
202int Ssl::ErrorDetail::convert(const char *code, const char **value) const
203{
204 *value = "-";
205 for (int i=0; ErrorFormatingCodes[i].code!=NULL; i++) {
206 const int len = strlen(ErrorFormatingCodes[i].code);
207 if (strncmp(code,ErrorFormatingCodes[i].code, len)==0) {
208 ErrorDetail::fmt_action_t action = ErrorFormatingCodes[i].fmt_action;
209 *value = (this->*action)();
210 return len;
211 }
e34763f4 212 }
4d16918e
CT
213 return 0;
214}
215
216/**
e34763f4
A
217 * It uses the convert method to build the string errDetailStr using
218 * a template message for the current SSL error. The template messages
4d16918e
CT
219 * can also contain normal error pages formating codes.
220 * Currently the error template messages are hard-coded
221 */
222void Ssl::ErrorDetail::buildDetail() const
223{
224 char const *s = getErrorDetail(error_no);
225 char const *p;
226 char const *t;
227 int code_len = 0;
228
8211c314 229 assert(s);
4d16918e
CT
230 while ((p = strchr(s, '%'))) {
231 errDetailStr.append(s, p - s);
232 code_len = convert(++p, &t);
233 if (code_len)
234 errDetailStr.append(t);
235 else
236 errDetailStr.append("%");
237 s = p + code_len;
238 }
239 errDetailStr.append(s, strlen(s));
240}
241
e34763f4
A
242const String &Ssl::ErrorDetail::toString() const
243{
4d16918e
CT
244 if (!errDetailStr.defined())
245 buildDetail();
246 return errDetailStr;
247}
248
e34763f4 249/* We may do not want to use X509_dup but instead
4d16918e 250 internal SSL locking:
e34763f4 251 CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
4d16918e
CT
252 peer_cert.reset(cert);
253*/
461b9576 254Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no, X509 *cert): error_no (err_no)
4d16918e
CT
255{
256 peer_cert.reset(X509_dup(cert));
257}
258
259Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail const &anErrDetail)
260{
261 error_no = anErrDetail.error_no;
262 if (anErrDetail.peer_cert.get()) {
263 peer_cert.reset(X509_dup(anErrDetail.peer_cert.get()));
264 }
265}