curl-library
[PATCH] add CURLINFO_SSL_VERIFYRESULT_STR providing a human-readable error string
From: Kamil Dudka <kdudka_at_redhat.com>
Date: Fri, 27 Apr 2012 16:08:41 +0200
Date: Fri, 27 Apr 2012 16:08:41 +0200
Bug: http://lists.baseurl.org/pipermail/yum-devel/2012-January/009002.html
---
RELEASE-NOTES | 1 +
docs/libcurl/curl_easy_getinfo.3 | 5 ++++
include/curl/curl.h | 3 +-
lib/getinfo.c | 3 ++
lib/nss.c | 14 +++++++++++-
lib/ssluse.c | 39 +++++++++++++++++++++++++++++++------
lib/url.c | 6 +++++
lib/urldata.h | 2 +
8 files changed, 63 insertions(+), 10 deletions(-)
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 0c92dfc..ca08648 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -11,6 +11,7 @@ This release includes the following changes:
o nss: the minimal supported version of NSS bumped to 3.12.x
o nss: human-readable names are now provided for NSS errors if available
+ o added CURLINFO_SSL_VERIFYRESULT_STR providing a human-readable error string
o
This release includes the following bugfixes:
diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index 0968136..4ad045c 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -127,6 +127,11 @@ than one request if FOLLOWLOCATION is true.
Pass a pointer to a long to receive the result of the certification
verification that was requested (using the CURLOPT_SSL_VERIFYPEER option to
\fIcurl_easy_setopt(3)\fP).
+.IP CURLINFO_SSL_VERIFYRESULT_STR
+Pass a pointer to a char pointer to receive a human-redable error string
+corresponding to the error code returned by \fICURLINFO_SSL_VERIFYRESULT\fP
+(if available). NOTE: this option works only if libcurl is built with OpenSSL
+or NSS support. (Added in 7.25.1)
.IP CURLINFO_SSL_ENGINES
Pass the address of a 'struct curl_slist *' to receive a linked-list of
OpenSSL crypto-engines supported. Note that engines are normally implemented
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 2cad282..c0a1db5 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1996,9 +1996,10 @@ typedef enum {
CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40,
CURLINFO_LOCAL_IP = CURLINFO_STRING + 41,
CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42,
+ CURLINFO_SSL_VERIFYRESULT_STR = CURLINFO_STRING + 43,
/* Fill in new entries below here! */
- CURLINFO_LASTONE = 42
+ CURLINFO_LASTONE = 43
} CURLINFO;
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
diff --git a/lib/getinfo.c b/lib/getinfo.c
index cd6feee..033ac26 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -175,6 +175,9 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
case CURLINFO_SSL_VERIFYRESULT:
*param_longp = data->set.ssl.certverifyresult;
break;
+ case CURLINFO_SSL_VERIFYRESULT_STR:
+ *param_charp = data->set.ssl.certverifyresult_str;
+ break;
case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
*param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
(double)data->progress.size_dl:-1;
diff --git a/lib/nss.c b/lib/nss.c
index 6b93893..6ae8e0e 100644
--- a/lib/nss.c
+++ b/lib/nss.c
@@ -612,6 +612,14 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
}
+/* assign verification result as error code together with a text description */
+static void assign_certverifyresult(struct SessionHandle *data,
+ PRErrorCode err)
+{
+ data->set.ssl.certverifyresult = err;
+ data->set.ssl.certverifyresult_str = PR_ErrorToString(err, PR_LANGUAGE_EN);
+}
+
static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
SECStatus result = SECFailure;
@@ -620,7 +628,8 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
CERTCertificate *cert = NULL;
char *subject, *subject_cn, *issuer;
- conn->data->set.ssl.certverifyresult=err;
+ assign_certverifyresult(conn->data, err);
+
cert = SSL_PeerCertificate(sock);
subject = CERT_NameToAscii(&cert->subject);
subject_cn = CERT_GetCommonName(&cert->subject);
@@ -1340,7 +1349,8 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
goto error;
- data->set.ssl.certverifyresult=0; /* not checked yet */
+ assign_certverifyresult(data, 0); /* not checked yet */
+
if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
!= SECSuccess) {
goto error;
diff --git a/lib/ssluse.c b/lib/ssluse.c
index a55ad3c..b69be47 100644
--- a/lib/ssluse.c
+++ b/lib/ssluse.c
@@ -1380,6 +1380,16 @@ static const char *tls_rt_type(int type)
"TLS Unknown, ");
}
+/*
+ * Free the previously allocated certverifyresult_str and allocate a new one
+ */
+static void assign_certverifyresult_str(struct SessionHandle *data,
+ const char *str)
+{
+ Curl_safefree(data->set.ssl.certverifyresult_str);
+ if(str)
+ data->set.ssl.certverifyresult_str = strdup(str);
+}
/*
* Our callback from the SSL/TLS layers.
@@ -1804,6 +1814,7 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
CURLcode rc;
const char *cert_problem = NULL;
long lerr;
+ const char *error_str;
connssl->connecting_state = ssl_connect_2; /* the connection failed,
we're not waiting for
@@ -1827,11 +1838,17 @@ ossl_connect_step2(struct connectdata *conn, int sockindex)
certificate verify failed */
rc = CURLE_SSL_CACERT;
+ /* store verification result as number */
lerr = SSL_get_verify_result(connssl->handle);
+ data->set.ssl.certverifyresult = lerr;
+
+ /* store verification result as text */
+ error_str = X509_verify_cert_error_string(lerr);
+ assign_certverifyresult_str(data, error_str);
+
if(lerr != X509_V_OK) {
snprintf(error_buffer, sizeof(error_buffer),
- "SSL certificate problem: %s",
- X509_verify_cert_error_string(lerr));
+ "SSL certificate problem: %s", error_str);
}
else
cert_problem = "SSL certificate problem, verify that the CA cert is"
@@ -2280,6 +2297,7 @@ static CURLcode servercert(struct connectdata *conn,
CURLcode retcode = CURLE_OK;
int rc;
long lerr;
+ const char *error_str;
ASN1_TIME *certdate;
struct SessionHandle *data = conn->data;
X509 *issuer;
@@ -2291,6 +2309,7 @@ static CURLcode servercert(struct connectdata *conn,
(void)get_cert_chain(conn, connssl);
data->set.ssl.certverifyresult = !X509_V_OK;
+ assign_certverifyresult_str(data, NULL);
connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
if(!connssl->server_cert) {
@@ -2377,21 +2396,27 @@ static CURLcode servercert(struct connectdata *conn,
X509_free(issuer);
}
- lerr = data->set.ssl.certverifyresult=
- SSL_get_verify_result(connssl->handle);
- if(data->set.ssl.certverifyresult != X509_V_OK) {
+ /* store verification result as number */
+ lerr = SSL_get_verify_result(connssl->handle);
+ data->set.ssl.certverifyresult = lerr;
+
+ /* store verification result as text */
+ error_str = X509_verify_cert_error_string(lerr);
+ assign_certverifyresult_str(data, error_str);
+
+ if(lerr != X509_V_OK) {
if(data->set.ssl.verifypeer) {
/* We probably never reach this, because SSL_connect() will fail
and we return earlier if verifypeer is set? */
if(strict)
failf(data, "SSL certificate verify result: %s (%ld)",
- X509_verify_cert_error_string(lerr), lerr);
+ error_str, lerr);
retcode = CURLE_PEER_FAILED_VERIFICATION;
}
else
infof(data, "\t SSL certificate verify result: %s (%ld),"
" continuing anyway.\n",
- X509_verify_cert_error_string(lerr), lerr);
+ error_str, lerr);
}
else
infof(data, "\t SSL certificate verify ok.\n");
diff --git a/lib/url.c b/lib/url.c
index b78c200..e16beaa 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -280,6 +280,12 @@ void Curl_freeset(struct SessionHandle * data)
data->change.referer_alloc = FALSE;
}
data->change.referer = NULL;
+
+#ifdef USE_SSLEAY
+ /* we have to duplicate the result of X509_verify_cert_error_string() but
+ * the duplicated string cannot be freed in Curl_ossl_close() */
+ Curl_safefree(data->set.ssl.certverifyresult_str);
+#endif
}
static CURLcode setstropt(char **charp, char * s)
diff --git a/lib/urldata.h b/lib/urldata.h
index 20519cf..4ff7933 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -287,6 +287,8 @@ struct ssl_connect_data {
struct ssl_config_data {
long version; /* what version the client wants to use */
long certverifyresult; /* result from the certificate verification */
+ const char *certverifyresult_str;
+ /* text describing certverifyresult or NULL */
long verifypeer; /* set TRUE if this is desired */
long verifyhost; /* 0: no verify
1: check that CN exists
--
1.7.1
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2012-04-27