3 #include "ssl/ErrorDetail.h"
9 Ssl::ssl_error_t value
;
13 static const char *SslErrorDetailDefaultStr
= "SSL certificate validation error (%err_name): %ssl_subject";
14 //Use std::map to optimize search
15 typedef std::map
<Ssl::ssl_error_t
, const SslErrorEntry
*> SslErrors
;
16 SslErrors TheSslErrors
;
18 static SslErrorEntry TheSslErrorArray
[] = {
19 {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
,
20 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT"},
21 {X509_V_ERR_UNABLE_TO_GET_CRL
,
22 "X509_V_ERR_UNABLE_TO_GET_CRL"},
23 {X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE
,
24 "X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE"},
25 {X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE
,
26 "X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE"},
27 {X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
,
28 "X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY"},
29 {X509_V_ERR_CERT_SIGNATURE_FAILURE
,
30 "X509_V_ERR_CERT_SIGNATURE_FAILURE"},
31 {X509_V_ERR_CRL_SIGNATURE_FAILURE
,
32 "X509_V_ERR_CRL_SIGNATURE_FAILURE"},
33 {X509_V_ERR_CERT_NOT_YET_VALID
,
34 "X509_V_ERR_CERT_NOT_YET_VALID"},
35 {X509_V_ERR_CERT_HAS_EXPIRED
,
36 "X509_V_ERR_CERT_HAS_EXPIRED"},
37 {X509_V_ERR_CRL_NOT_YET_VALID
,
38 "X509_V_ERR_CRL_NOT_YET_VALID"},
39 {X509_V_ERR_CRL_HAS_EXPIRED
,
40 "X509_V_ERR_CRL_HAS_EXPIRED"},
41 {X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD
,
42 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD"},
43 {X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD
,
44 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD"},
45 {X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD
,
46 "X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD"},
47 {X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD
,
48 "X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD"},
49 {X509_V_ERR_OUT_OF_MEM
,
50 "X509_V_ERR_OUT_OF_MEM"},
51 {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
,
52 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT"},
53 {X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
,
54 "X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN"},
55 {X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,
56 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY"},
57 {X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE
,
58 "X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE"},
59 {X509_V_ERR_CERT_CHAIN_TOO_LONG
,
60 "X509_V_ERR_CERT_CHAIN_TOO_LONG"},
61 {X509_V_ERR_CERT_REVOKED
,
62 "X509_V_ERR_CERT_REVOKED"},
63 {X509_V_ERR_INVALID_CA
,
64 "X509_V_ERR_INVALID_CA"},
65 {X509_V_ERR_PATH_LENGTH_EXCEEDED
,
66 "X509_V_ERR_PATH_LENGTH_EXCEEDED"},
67 {X509_V_ERR_INVALID_PURPOSE
,
68 "X509_V_ERR_INVALID_PURPOSE"},
69 {X509_V_ERR_CERT_UNTRUSTED
,
70 "X509_V_ERR_CERT_UNTRUSTED"},
71 {X509_V_ERR_CERT_REJECTED
,
72 "X509_V_ERR_CERT_REJECTED"},
73 {X509_V_ERR_SUBJECT_ISSUER_MISMATCH
,
74 "X509_V_ERR_SUBJECT_ISSUER_MISMATCH"},
75 {X509_V_ERR_AKID_SKID_MISMATCH
,
76 "X509_V_ERR_AKID_SKID_MISMATCH"},
77 {X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH
,
78 "X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH"},
79 {X509_V_ERR_KEYUSAGE_NO_CERTSIGN
,
80 "X509_V_ERR_KEYUSAGE_NO_CERTSIGN"},
81 {X509_V_ERR_APPLICATION_VERIFICATION
,
82 "X509_V_ERR_APPLICATION_VERIFICATION"},
83 { SSL_ERROR_NONE
, "SSL_ERROR_NONE"},
84 {SSL_ERROR_NONE
, NULL
}
87 static void loadSslErrorMap()
89 assert(TheSslErrors
.empty());
90 for (int i
= 0; TheSslErrorArray
[i
].name
; ++i
) {
91 TheSslErrors
[TheSslErrorArray
[i
].value
] = &TheSslErrorArray
[i
];
95 Ssl::ssl_error_t
Ssl::GetErrorCode(const char *name
)
97 for (int i
= 0; TheSslErrorArray
[i
].name
!= NULL
; i
++) {
98 if (strcmp(name
, TheSslErrorArray
[i
].name
) == 0)
99 return TheSslErrorArray
[i
].value
;
101 return SSL_ERROR_NONE
;
105 Ssl::ParseErrorString(const char *name
)
109 const Ssl::ssl_error_t ssl_error
= GetErrorCode(name
);
110 if (ssl_error
!= SSL_ERROR_NONE
)
113 if (xisdigit(*name
)) {
114 const long int value
= strtol(name
, NULL
, 0);
115 if (SQUID_SSL_ERROR_MIN
<= value
&& value
<= SQUID_SSL_ERROR_MAX
)
117 fatalf("Too small or too bug SSL error code '%s'", name
);
120 fatalf("Unknown SSL error name '%s'", name
);
121 return SSL_ERROR_SSL
; // not reached
124 const char *Ssl::GetErrorName(Ssl::ssl_error_t value
)
126 if (TheSslErrors
.empty())
129 const SslErrors::const_iterator it
= TheSslErrors
.find(value
);
130 if (it
!= TheSslErrors
.end())
131 return it
->second
->name
;
137 Ssl::GetErrorDescr(Ssl::ssl_error_t value
)
139 return ErrorDetailsManager::GetInstance().getDefaultErrorDescr(value
);
142 Ssl::ErrorDetail::err_frm_code
Ssl::ErrorDetail::ErrorFormatingCodes
[] = {
143 {"ssl_subject", &Ssl::ErrorDetail::subject
},
144 {"ssl_ca_name", &Ssl::ErrorDetail::ca_name
},
145 {"ssl_cn", &Ssl::ErrorDetail::cn
},
146 {"ssl_notbefore", &Ssl::ErrorDetail::notbefore
},
147 {"ssl_notafter", &Ssl::ErrorDetail::notafter
},
148 {"err_name", &Ssl::ErrorDetail::err_code
},
149 {"ssl_error_descr", &Ssl::ErrorDetail::err_descr
},
154 * The subject of the current certification in text form
156 const char *Ssl::ErrorDetail::subject() const
159 return "[Not available]";
161 static char tmpBuffer
[256]; // A temporary buffer
162 X509_NAME_oneline(X509_get_subject_name(peer_cert
.get()), tmpBuffer
,
167 // helper function to be used with Ssl::matchX509CommonNames
168 static int copy_cn(void *check_data
, ASN1_STRING
*cn_data
)
170 String
*str
= (String
*)check_data
;
171 if (!str
) // no data? abort
175 str
->append((const char *)cn_data
->data
, cn_data
->length
);
180 * The list with certificates cn and alternate names
182 const char *Ssl::ErrorDetail::cn() const
185 return "[Not available]";
187 static String tmpStr
; ///< A temporary string buffer
189 Ssl::matchX509CommonNames(peer_cert
.get(), &tmpStr
, copy_cn
);
190 return tmpStr
.termedBuf();
196 const char *Ssl::ErrorDetail::ca_name() const
199 return "[Not available]";
201 static char tmpBuffer
[256]; // A temporary buffer
202 X509_NAME_oneline(X509_get_issuer_name(peer_cert
.get()), tmpBuffer
, sizeof(tmpBuffer
));
207 * The certificate "not before" field
209 const char *Ssl::ErrorDetail::notbefore() const
212 return "[Not available]";
214 static char tmpBuffer
[256]; // A temporary buffer
215 ASN1_UTCTIME
* tm
= X509_get_notBefore(peer_cert
.get());
216 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
221 * The certificate "not after" field
223 const char *Ssl::ErrorDetail::notafter() const
226 return "[Not available]";
228 static char tmpBuffer
[256]; // A temporary buffer
229 ASN1_UTCTIME
* tm
= X509_get_notAfter(peer_cert
.get());
230 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
235 * The string representation of the error_no
237 const char *Ssl::ErrorDetail::err_code() const
239 static char tmpBuffer
[64];
240 // We can use the GetErrorName but using the detailEntry is faster,
242 const char *err
= detailEntry
.name
.termedBuf();
244 // error details not loaded yet or not defined in error_details.txt,
245 // try the GetErrorName...
247 err
= GetErrorName(error_no
);
250 snprintf(tmpBuffer
, 64, "%d", (int)error_no
);
257 * A short description of the error_no
259 const char *Ssl::ErrorDetail::err_descr() const
261 if (error_no
== SSL_ERROR_NONE
)
263 if (const char *err
= detailEntry
.descr
.termedBuf())
265 return "[Not available]";
269 * It converts the code to a string value. Currently the following
270 * formating codes are supported:
271 * %err_name: The name of the SSL error
272 * %ssl_error_descr: A short description of the SSL error
273 * %ssl_cn: The comma-separated list of common and alternate names
274 * %ssl_subject: The certificate subject
275 * %ssl_ca_name: The certificate issuer name
276 * %ssl_notbefore: The certificate "not before" field
277 * %ssl_notafter: The certificate "not after" field
278 \retval the length of the code (the number of characters will be replaced by value)
280 int Ssl::ErrorDetail::convert(const char *code
, const char **value
) const
283 for (int i
=0; ErrorFormatingCodes
[i
].code
!=NULL
; i
++) {
284 const int len
= strlen(ErrorFormatingCodes
[i
].code
);
285 if (strncmp(code
,ErrorFormatingCodes
[i
].code
, len
)==0) {
286 ErrorDetail::fmt_action_t action
= ErrorFormatingCodes
[i
].fmt_action
;
287 *value
= (this->*action
)();
295 * It uses the convert method to build the string errDetailStr using
296 * a template message for the current SSL error. The template messages
297 * can also contain normal error pages formating codes.
298 * Currently the error template messages are hard-coded
300 void Ssl::ErrorDetail::buildDetail() const
302 char const *s
= NULL
;
307 if (ErrorDetailsManager::GetInstance().getErrorDetail(error_no
, request
.raw(), detailEntry
))
308 s
= detailEntry
.detail
.termedBuf();
311 s
= SslErrorDetailDefaultStr
;
314 while ((p
= strchr(s
, '%'))) {
315 errDetailStr
.append(s
, p
- s
);
316 code_len
= convert(++p
, &t
);
318 errDetailStr
.append(t
);
320 errDetailStr
.append("%");
323 errDetailStr
.append(s
, strlen(s
));
326 const String
&Ssl::ErrorDetail::toString() const
328 if (!errDetailStr
.defined())
333 /* We may do not want to use X509_dup but instead
334 internal SSL locking:
335 CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
336 peer_cert.reset(cert);
338 Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no
, X509
*cert
): error_no (err_no
)
340 peer_cert
.reset(X509_dup(cert
));
341 detailEntry
.error_no
= SSL_ERROR_NONE
;
344 Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail
const &anErrDetail
)
346 error_no
= anErrDetail
.error_no
;
347 request
= anErrDetail
.request
;
349 if (anErrDetail
.peer_cert
.get()) {
350 peer_cert
.reset(X509_dup(anErrDetail
.peer_cert
.get()));
353 detailEntry
= anErrDetail
.detailEntry
;