2 #include "ssl/ErrorDetail.h"
4 struct SslErrorDetailEntry
{
5 Ssl::ssl_error_t value
;
10 // TODO: optimize by replacing with std::map or similar
11 static SslErrorDetailEntry TheSslDetailMap
[] = {
12 { SQUID_X509_V_ERR_DOMAIN_MISMATCH
,
13 "SQUID_X509_V_ERR_DOMAIN_MISMATCH",
14 "%err_name: The hostname you are connecting to (%H), does not match any of the Certificate valid names: %ssl_cn"},
15 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
,
16 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT",
17 "%err_name: SSL Certficate error: certificate issuer (CA) not known: %ssl_ca_name" },
18 { X509_V_ERR_CERT_NOT_YET_VALID
,
19 "X509_V_ERR_CERT_NOT_YET_VALID",
20 "%err_name: SSL Certficate is not valid before: %ssl_notbefore" },
21 { X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD
,
22 "X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD",
23 "%err_name: SSL Certificate has invalid start date (the 'not before' field): %subject" },
24 { X509_V_ERR_CERT_HAS_EXPIRED
,
25 "X509_V_ERR_CERT_HAS_EXPIRED",
26 "%err_name: SSL Certificate expired on %ssl_notafter" },
27 { X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD
,
28 "X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD",
29 "%err_name: SSL Certificate has invalid expiration date (the 'not after' field): %ssl_subject" },
30 {X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
,
31 "X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT",
32 "%err_name: Self-signed SSL Certificate: %ssl_subject"},
33 { X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
,
34 "X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
35 "%err_name: SSL Certficate error: certificate issuer (CA) not known: %ssl_ca_name" },
36 { SSL_ERROR_NONE
, "SSL_ERROR_NONE", "%err_name: No error" },
37 {SSL_ERROR_NONE
, NULL
, NULL
}
41 Ssl::parseErrorString(const char *name
)
45 for (int i
= 0; TheSslDetailMap
[i
].name
; ++i
) {
46 if (strcmp(name
, TheSslDetailMap
[i
].name
) == 0)
47 return TheSslDetailMap
[i
].value
;
50 if (xisdigit(*name
)) {
51 const long int value
= strtol(name
, NULL
, 0);
52 if (SQUID_SSL_ERROR_MIN
<= value
&& value
<= SQUID_SSL_ERROR_MAX
)
54 fatalf("Too small or too bug SSL error code '%s'", name
);
57 fatalf("Unknown SSL error name '%s'", name
);
58 return SSL_ERROR_SSL
; // not reached
62 Ssl::getErrorName(Ssl::ssl_error_t value
)
65 for (int i
= 0; TheSslDetailMap
[i
].name
; ++i
) {
66 if (TheSslDetailMap
[i
].value
== value
)
67 return TheSslDetailMap
[i
].name
;
73 static const char *getErrorDetail(Ssl::ssl_error_t value
)
75 for (int i
= 0; TheSslDetailMap
[i
].name
; ++i
) {
76 if (TheSslDetailMap
[i
].value
== value
)
77 return TheSslDetailMap
[i
].detail
;
83 Ssl::ErrorDetail::err_frm_code
Ssl::ErrorDetail::ErrorFormatingCodes
[] = {
84 {"ssl_subject", &Ssl::ErrorDetail::subject
},
85 {"ssl_ca_name", &Ssl::ErrorDetail::ca_name
},
86 {"ssl_cn", &Ssl::ErrorDetail::cn
},
87 {"ssl_notbefore", &Ssl::ErrorDetail::notbefore
},
88 {"ssl_notafter", &Ssl::ErrorDetail::notafter
},
89 {"err_name", &Ssl::ErrorDetail::err_code
},
94 * The subject of the current certification in text form
96 const char *Ssl::ErrorDetail::subject() const
99 return "[Not available]";
101 static char tmpBuffer
[256]; // A temporary buffer
102 X509_NAME_oneline(X509_get_subject_name(peer_cert
.get()), tmpBuffer
,
107 // helper function to be used with Ssl::matchX509CommonNames
108 static int copy_cn(void *check_data
, ASN1_STRING
*cn_data
)
110 String
*str
= (String
*)check_data
;
111 if (!str
) // no data? abort
115 str
->append((const char *)cn_data
->data
, cn_data
->length
);
120 * The list with certificates cn and alternate names
122 const char *Ssl::ErrorDetail::cn() const
125 return "[Not available]";
127 static String tmpStr
; ///< A temporary string buffer
129 Ssl::matchX509CommonNames(peer_cert
.get(), &tmpStr
, copy_cn
);
130 return tmpStr
.termedBuf();
136 const char *Ssl::ErrorDetail::ca_name() const
139 return "[Not available]";
141 static char tmpBuffer
[256]; // A temporary buffer
142 X509_NAME_oneline(X509_get_issuer_name(peer_cert
.get()), tmpBuffer
, sizeof(tmpBuffer
));
147 * The certificate "not before" field
149 const char *Ssl::ErrorDetail::notbefore() const
152 return "[Not available]";
154 static char tmpBuffer
[256]; // A temporary buffer
155 ASN1_UTCTIME
* tm
= X509_get_notBefore(peer_cert
.get());
156 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
161 * The certificate "not after" field
163 const char *Ssl::ErrorDetail::notafter() const
166 return "[Not available]";
168 static char tmpBuffer
[256]; // A temporary buffer
169 ASN1_UTCTIME
* tm
= X509_get_notAfter(peer_cert
.get());
170 Ssl::asn1timeToString(tm
, tmpBuffer
, sizeof(tmpBuffer
));
175 * The string representation of the error_no
177 const char *Ssl::ErrorDetail::err_code() const
179 const char *err
= getErrorName(error_no
);
181 return "[Not available]";
186 * It converts the code to a string value. Currently the following
187 * formating codes are supported:
188 * %err_name: The name of the SSL error
189 * %ssl_cn: The comma-separated list of common and alternate names
190 * %ssl_subject: The certificate subject
191 * %ssl_ca_name: The certificate issuer name
192 * %ssl_notbefore: The certificate "not before" field
193 * %ssl_notafter: The certificate "not after" field
194 \retval the length of the code (the number of characters will be replaced by value)
196 int Ssl::ErrorDetail::convert(const char *code
, const char **value
) const
199 for (int i
=0; ErrorFormatingCodes
[i
].code
!=NULL
; i
++) {
200 const int len
= strlen(ErrorFormatingCodes
[i
].code
);
201 if (strncmp(code
,ErrorFormatingCodes
[i
].code
, len
)==0) {
202 ErrorDetail::fmt_action_t action
= ErrorFormatingCodes
[i
].fmt_action
;
203 *value
= (this->*action
)();
211 * It uses the convert method to build the string errDetailStr using
212 * a template message for the current SSL error. The template messages
213 * can also contain normal error pages formating codes.
214 * Currently the error template messages are hard-coded
216 void Ssl::ErrorDetail::buildDetail() const
218 char const *s
= getErrorDetail(error_no
);
223 if (!s
) //May be add a default detail string?
226 while ((p
= strchr(s
, '%'))) {
227 errDetailStr
.append(s
, p
- s
);
228 code_len
= convert(++p
, &t
);
230 errDetailStr
.append(t
);
232 errDetailStr
.append("%");
235 errDetailStr
.append(s
, strlen(s
));
238 const String
&Ssl::ErrorDetail::toString() const
240 if (!errDetailStr
.defined())
245 /* We may do not want to use X509_dup but instead
246 internal SSL locking:
247 CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509);
248 peer_cert.reset(cert);
250 Ssl::ErrorDetail::ErrorDetail( Ssl::ssl_error_t err_no
, X509
*cert
): error_no (err_no
)
252 peer_cert
.reset(X509_dup(cert
));
255 Ssl::ErrorDetail::ErrorDetail(Ssl::ErrorDetail
const &anErrDetail
)
257 error_no
= anErrDetail
.error_no
;
258 if (anErrDetail
.peer_cert
.get()) {
259 peer_cert
.reset(X509_dup(anErrDetail
.peer_cert
.get()));