2 #include "ssl/ErrorDetail.h"
7 struct SslErrorDetailEntry
{
8 Ssl::ssl_error_t value
;
10 const char *detail
; ///< for error page %D macro expansion; may contain macros
11 const char *descr
; ///< short error description (for use in debug messages or error pages)
14 static const char *SslErrorDetailDefaultStr
= "SSL certificate validation error (%err_name): %ssl_subject";
15 //Use std::map to optimize search
16 typedef std::map
<Ssl::ssl_error_t
, const SslErrorDetailEntry
*> SslErrorDetails
;
17 SslErrorDetails TheSslDetail
;
19 static SslErrorDetailEntry TheSslDetailArray
[] = {
20 {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
,
21 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT",
22 "%err_name: SSL Certficate error: certificate issuer (CA) not known: %ssl_ca_name",
23 "Unable to get issuer certificate"},
24 {X509_V_ERR_UNABLE_TO_GET_CRL
,
25 "X509_V_ERR_UNABLE_TO_GET_CRL",
26 "%err_name: %ssl_error_descr: %ssl_subject",
27 "Unable to get certificate CRL"},
28 {X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE
,
29 "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE",
30 "%err_name: %ssl_error_descr: %ssl_subject",
31 "Unable to decrypt certificate's signature"},
32 {X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE
,
33 "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE",
34 "%err_name: %ssl_error_descr: %ssl_subject",
35 "Unable to decrypt CRL's signature"},
36 {X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
,
37 "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY",
38 "%err_name: Unable to decode issuer (CA) public key: %ssl_ca_name",
39 "Unable to decode issuer public key"},
40 {X509_V_ERR_CERT_SIGNATURE_FAILURE
,
41 "X509_V_ERR_CERT_SIGNATURE_FAILURE",
42 "%err_name: %ssl_error_descr: %ssl_subject",
43 "Certificate signature failure"},
44 {X509_V_ERR_CRL_SIGNATURE_FAILURE
,
45 "X509_V_ERR_CRL_SIGNATURE_FAILURE",
46 "%err_name: %ssl_error_descr: %ssl_subject",
47 "CRL signature failure"},
48 {X509_V_ERR_CERT_NOT_YET_VALID
,
49 "X509_V_ERR_CERT_NOT_YET_VALID",
50 "%err_name: SSL Certficate is not valid before: %ssl_notbefore",
51 "Certificate is not yet valid"},
52 {X509_V_ERR_CERT_HAS_EXPIRED
,
53 "X509_V_ERR_CERT_HAS_EXPIRED",
54 "%err_name: SSL Certificate expired on: %ssl_notafter",
55 "Certificate has expired"},
56 {X509_V_ERR_CRL_NOT_YET_VALID
,
57 "X509_V_ERR_CRL_NOT_YET_VALID",
58 "%err_name: %ssl_error_descr: %ssl_subject",
59 "CRL is not yet valid"},
60 {X509_V_ERR_CRL_HAS_EXPIRED
,
61 "X509_V_ERR_CRL_HAS_EXPIRED",
62 "%err_name: %ssl_error_descr: %ssl_subject",
64 {X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD
,
65 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD",
66 "%err_name: SSL Certificate has invalid start date (the 'not before' field): %ssl_subject",
67 "Format error in certificate's notBefore field"},
68 {X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD
,
69 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD",
70 "%err_name: SSL Certificate has invalid expiration date (the 'not after' field): %ssl_subject",
71 "Format error in certificate's notAfter field"},
72 {X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD
,
73 "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD",
74 "%err_name: %ssl_error_descr: %ssl_subject",
75 "Format error in CRL's lastUpdate field"},
76 {X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD
,
77 "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD",
78 "%err_name: %ssl_error_descr: %ssl_subject",
79 "Format error in CRL's nextUpdate field"},
80 {X509_V_ERR_OUT_OF_MEM
,
81 "X509_V_ERR_OUT_OF_MEM",
82 "%err_name: %ssl_error_descr",
84 {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
,
85 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT",
86 "%err_name: Self-signed SSL Certificate: %ssl_subject",
87 "Self signed certificate"},
88 {X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
,
89 "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN",
90 "%err_name: Self-signed SSL Certificate in chain: %ssl_subject",
91 "Self signed certificate in certificate chain"},
92 {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,
93 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
94 "%err_name: SSL Certficate error: certificate issuer (CA) not known: %ssl_ca_name",
95 "Unable to get local issuer certificate"},
96 {X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
,
97 "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE",
98 "%err_name: %ssl_error_descr: %ssl_subject",
99 "Unable to verify the first certificate"},
100 {X509_V_ERR_CERT_CHAIN_TOO_LONG
,
101 "X509_V_ERR_CERT_CHAIN_TOO_LONG",
102 "%err_name: %ssl_error_descr: %ssl_subject",
103 "Certificate chain too long"},
104 {X509_V_ERR_CERT_REVOKED
,
105 "X509_V_ERR_CERT_REVOKED",
106 "%err_name: %ssl_error_descr: %ssl_subject",
107 "Certificate revoked"},
108 {X509_V_ERR_INVALID_CA
,
109 "X509_V_ERR_INVALID_CA",
110 "%err_name: %ssl_error_descr: %ssl_ca_name",
111 "Invalid CA certificate"},
112 {X509_V_ERR_PATH_LENGTH_EXCEEDED
,
113 "X509_V_ERR_PATH_LENGTH_EXCEEDED",
114 "%err_name: %ssl_error_descr: %ssl_subject",
115 "Path length constraint exceeded"},
116 {X509_V_ERR_INVALID_PURPOSE
,
117 "X509_V_ERR_INVALID_PURPOSE",
118 "%err_name: %ssl_error_descr: %ssl_subject",
119 "Unsupported certificate purpose"},
120 {X509_V_ERR_CERT_UNTRUSTED
,
121 "X509_V_ERR_CERT_UNTRUSTED",
122 "%err_name: %ssl_error_descr: %ssl_subject",
123 "Certificate not trusted"},
124 {X509_V_ERR_CERT_REJECTED
,
125 "X509_V_ERR_CERT_REJECTED",
126 "%err_name: %ssl_error_descr: %ssl_subject",
127 "Certificate rejected"},
128 {X509_V_ERR_SUBJECT_ISSUER_MISMATCH
,
129 "X509_V_ERR_SUBJECT_ISSUER_MISMATCH",
130 "%err_name: %ssl_error_descr: %ssl_ca_name",
131 "Subject issuer mismatch"},
132 {X509_V_ERR_AKID_SKID_MISMATCH
,
133 "X509_V_ERR_AKID_SKID_MISMATCH",
134 "%err_name: %ssl_error_descr: %ssl_subject",
135 "Authority and subject key identifier mismatch"},
136 {X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH
,
137 "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH",
138 "%err_name: %ssl_error_descr: %ssl_ca_name",
139 "Authority and issuer serial number mismatch"},
140 {X509_V_ERR_KEYUSAGE_NO_CERTSIGN
,
141 "X509_V_ERR_KEYUSAGE_NO_CERTSIGN",
142 "%err_name: %ssl_error_descr: %ssl_subject",
143 "Key usage does not include certificate signing"},
144 {X509_V_ERR_APPLICATION_VERIFICATION
,
145 "X509_V_ERR_APPLICATION_VERIFICATION",
146 "%err_name: %ssl_error_descr: %ssl_subject",
147 "Application verification failure"},
148 { SSL_ERROR_NONE
, "SSL_ERROR_NONE", "%err_name: No error", "No error" },
149 {SSL_ERROR_NONE
, NULL
, NULL
, NULL
}
152 static void loadSslDetailMap()
154 assert(TheSslDetail
.empty());
155 for (int i
= 0; TheSslDetailArray
[i
].name
; ++i
) {
156 TheSslDetail
[TheSslDetailArray
[i
].value
] = &TheSslDetailArray
[i
];
161 Ssl::ParseErrorString(const char *name
)
165 if (TheSslDetail
.empty())
168 typedef SslErrorDetails::const_iterator SEDCI
;
169 for (SEDCI i
= TheSslDetail
.begin(); i
!= TheSslDetail
.end(); ++i
) {
170 if (strcmp(name
, i
->second
->name
) == 0)
171 return i
->second
->value
;
174 if (xisdigit(*name
)) {
175 const long int value
= strtol(name
, NULL
, 0);
176 if (SQUID_SSL_ERROR_MIN
<= value
&& value
<= SQUID_SSL_ERROR_MAX
)
178 fatalf("Too small or too bug SSL error code '%s'", name
);
181 fatalf("Unknown SSL error name '%s'", name
);
182 return SSL_ERROR_SSL
; // not reached
185 static const SslErrorDetailEntry
*getErrorRecord(Ssl::ssl_error_t value
)
187 if (TheSslDetail
.empty())
190 const SslErrorDetails::const_iterator it
= TheSslDetail
.find(value
);
191 if (it
!= TheSslDetail
.end())
198 Ssl::GetErrorName(Ssl::ssl_error_t value
)
200 if (const SslErrorDetailEntry
*errorRecord
= getErrorRecord(value
))
201 return errorRecord
->name
;
206 static const char *getErrorDetail(Ssl::ssl_error_t value
)
208 if (const SslErrorDetailEntry
*errorRecord
= getErrorRecord(value
))
209 return errorRecord
->detail
;
211 // we must always return something because ErrorDetail::buildDetail
212 // will hit an assertion
213 return SslErrorDetailDefaultStr
;
217 Ssl::GetErrorDescr(Ssl::ssl_error_t value
)
219 if (const SslErrorDetailEntry
*errorRecord
= getErrorRecord(value
))
220 return errorRecord
->descr
;
225 Ssl::ErrorDetail::err_frm_code
Ssl::ErrorDetail::ErrorFormatingCodes
[] = {
226 {"ssl_subject", &Ssl::ErrorDetail::subject
},
227 {"ssl_ca_name", &Ssl::ErrorDetail::ca_name
},
228 {"ssl_cn", &Ssl::ErrorDetail::cn
},
229 {"ssl_notbefore", &Ssl::ErrorDetail::notbefore
},
230 {"ssl_notafter", &Ssl::ErrorDetail::notafter
},
231 {"err_name", &Ssl::ErrorDetail::err_code
},
232 {"ssl_error_descr", &Ssl::ErrorDetail::err_descr
},
237 * The subject of the current certification in text form
239 const char *Ssl::ErrorDetail::subject() const
242 return "[Not available]";
244 static char tmpBuffer
[256]; // A temporary buffer
245 X509_NAME_oneline(X509_get_subject_name(peer_cert
.get()), tmpBuffer
,
250 // helper function to be used with Ssl::matchX509CommonNames
251 static int copy_cn(void *check_data
, ASN1_STRING
*cn_data
)
253 String
*str
= (String
*)check_data
;
254 if (!str
) // no data? abort
258 str
->append((const char *)cn_data
->data
, cn_data
->length
);
263 * The list with certificates cn and alternate names
265 const char *Ssl::ErrorDetail::cn() const
268 return "[Not available]";
270 static String tmpStr
; ///< A temporary string buffer
272 Ssl::matchX509CommonNames(peer_cert
.get(), &tmpStr
, copy_cn
);
273 return tmpStr
.termedBuf();
279 const char *Ssl::ErrorDetail::ca_name() const
282 return "[Not available]";
284 static char tmpBuffer
[256]; // A temporary buffer
285 X509_NAME_oneline(X509_get_issuer_name(peer_cert
.get()), tmpBuffer
, sizeof(tmpBuffer
));
290 * The certificate "not before" field
292 const char *Ssl::ErrorDetail::notbefore() const
295 return "[Not available]";
297 static char tmpBuffer
[256]; // A temporary buffer
298 ASN1_UTCTIME
* tm
= X509_get_notBefore(peer_cert
.get());
299 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
304 * The certificate "not after" field
306 const char *Ssl::ErrorDetail::notafter() const
309 return "[Not available]";
311 static char tmpBuffer
[256]; // A temporary buffer
312 ASN1_UTCTIME
* tm
= X509_get_notAfter(peer_cert
.get());
313 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
318 * The string representation of the error_no
320 const char *Ssl::ErrorDetail::err_code() const
322 static char tmpBuffer
[64];
323 const char *err
= GetErrorName(error_no
);
325 snprintf(tmpBuffer
, 64, "%d", (int)error_no
);
332 * A short description of the error_no
334 const char *Ssl::ErrorDetail::err_descr() const
336 if (const char *err
= GetErrorDescr(error_no
))
338 return "[Not available]";
342 * It converts the code to a string value. Currently the following
343 * formating codes are supported:
344 * %err_name: The name of the SSL error
345 * %ssl_error_descr: A short description of the SSL error
346 * %ssl_cn: The comma-separated list of common and alternate names
347 * %ssl_subject: The certificate subject
348 * %ssl_ca_name: The certificate issuer name
349 * %ssl_notbefore: The certificate "not before" field
350 * %ssl_notafter: The certificate "not after" field
351 \retval the length of the code (the number of characters will be replaced by value)
353 int Ssl::ErrorDetail::convert(const char *code
, const char **value
) const
356 for (int i
=0; ErrorFormatingCodes
[i
].code
!=NULL
; i
++) {
357 const int len
= strlen(ErrorFormatingCodes
[i
].code
);
358 if (strncmp(code
,ErrorFormatingCodes
[i
].code
, len
)==0) {
359 ErrorDetail::fmt_action_t action
= ErrorFormatingCodes
[i
].fmt_action
;
360 *value
= (this->*action
)();
368 * It uses the convert method to build the string errDetailStr using
369 * a template message for the current SSL error. The template messages
370 * can also contain normal error pages formating codes.
371 * Currently the error template messages are hard-coded
373 void Ssl::ErrorDetail::buildDetail() const
375 char const *s
= getErrorDetail(error_no
);
381 while ((p
= strchr(s
, '%'))) {
382 errDetailStr
.append(s
, p
- s
);
383 code_len
= convert(++p
, &t
);
385 errDetailStr
.append(t
);
387 errDetailStr
.append("%");
390 errDetailStr
.append(s
, strlen(s
));
393 const String
&Ssl::ErrorDetail::toString() const
395 if (!errDetailStr
.defined())
400 /* We may do not want to use X509_dup but instead
401 internal SSL locking:
402 CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
403 peer_cert.reset(cert);
405 Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no
, X509
*cert
): error_no (err_no
)
407 peer_cert
.reset(X509_dup(cert
));
410 Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail
const &anErrDetail
)
412 error_no
= anErrDetail
.error_no
;
413 if (anErrDetail
.peer_cert
.get()) {
414 peer_cert
.reset(X509_dup(anErrDetail
.peer_cert
.get()));