- Axel Tillequin and Arnaud Ebalard added support for CURLOPT_ISSUERCERT, for
OpenSSL, NSS and GnuTLS-built libcurls.
This commit is contained in:
3
CHANGES
3
CHANGES
@@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
|
|
||||||
Daniel Stenberg (6 Jun 2008)
|
Daniel Stenberg (6 Jun 2008)
|
||||||
|
- Axel Tillequin and Arnaud Ebalard added support for CURLOPT_ISSUERCERT, for
|
||||||
|
OpenSSL, NSS and GnuTLS-built libcurls.
|
||||||
|
|
||||||
- Axel Tillequin and Arnaud Ebalard added support for CURLOPT_CRLFILE, for
|
- Axel Tillequin and Arnaud Ebalard added support for CURLOPT_CRLFILE, for
|
||||||
OpenSSL, NSS and GnuTLS-built libcurls.
|
OpenSSL, NSS and GnuTLS-built libcurls.
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@ Curl and libcurl 7.18.3
|
|||||||
|
|
||||||
Public curl releases: 106
|
Public curl releases: 106
|
||||||
Command line options: 126
|
Command line options: 126
|
||||||
curl_easy_setopt() options: 151
|
curl_easy_setopt() options: 152
|
||||||
Public functions in libcurl: 58
|
Public functions in libcurl: 58
|
||||||
Public web site mirrors: 37
|
Public web site mirrors: 37
|
||||||
Known libcurl bindings: 36
|
Known libcurl bindings: 36
|
||||||
@@ -11,7 +11,8 @@ Curl and libcurl 7.18.3
|
|||||||
This release includes the following changes:
|
This release includes the following changes:
|
||||||
|
|
||||||
o Added CURLINFO_PRIMARY_IP
|
o Added CURLINFO_PRIMARY_IP
|
||||||
o Added CURLOPT_CRLFILE
|
o Added CURLOPT_CRLFILE and CURLE_SSL_CRL_BADFILE
|
||||||
|
o Added CURLOPT_ISSUERCERT and CURLE_SSL_ISSUER_ERROR
|
||||||
|
|
||||||
This release includes the following bugfixes:
|
This release includes the following bugfixes:
|
||||||
|
|
||||||
|
@@ -3,8 +3,6 @@ To be addressed before 7.18.3 (planned release: August 2008)
|
|||||||
|
|
||||||
139 - Christopher Palow's CURLM_EASY_HANDLE_EXISTS patch
|
139 - Christopher Palow's CURLM_EASY_HANDLE_EXISTS patch
|
||||||
|
|
||||||
140 - Arnaud Ebalard and Axel Tillequin's CRL support and issuer check patches
|
|
||||||
|
|
||||||
144 - Help apps use 64bit/LFS libcurl!
|
144 - Help apps use 64bit/LFS libcurl!
|
||||||
|
|
||||||
145 -
|
145 -
|
||||||
|
@@ -1443,6 +1443,22 @@ bundle is assumed to be stored, as established at build time.
|
|||||||
|
|
||||||
When built against NSS this is the directory that the NSS certificate
|
When built against NSS this is the directory that the NSS certificate
|
||||||
database resides in.
|
database resides in.
|
||||||
|
.IP CURLOPT_ISSUERCERT
|
||||||
|
Pass a char * to a zero terminated string naming a file holding a CA
|
||||||
|
certificate in PEM format. If the option is set, an additional check against
|
||||||
|
the peer certificate is performed to verify the issuer is indeed the one
|
||||||
|
associated with the certificate provided by the option. This additional check
|
||||||
|
is useful in multi-level PKI where one need to enforce the peer certificate is
|
||||||
|
from a specific branch of the tree.
|
||||||
|
|
||||||
|
This option makes sense only when used in combination with the
|
||||||
|
\fICURLOPT_SSL_VERIFYPEER\fP option. Otherwise, the result of the check is not
|
||||||
|
considered as failure.
|
||||||
|
|
||||||
|
A specific error code (CURLE_SSL_ISSUER_ERROR) is defined with the option,
|
||||||
|
which is returned if the setup of the SSL/TLS session has failed due to a
|
||||||
|
mismatch with the issuer of peer certificate (\fICURLOPT_SSL_VERIFYPEER\fP has
|
||||||
|
to be set too for the check to fail). (Added in 7.18.3)
|
||||||
.IP CURLOPT_CAPATH
|
.IP CURLOPT_CAPATH
|
||||||
Pass a char * to a zero terminated string naming a directory holding multiple
|
Pass a char * to a zero terminated string naming a directory holding multiple
|
||||||
CA certificates to verify the peer with. The certificate directory must be
|
CA certificates to verify the peer with. The certificate directory must be
|
||||||
|
@@ -214,6 +214,8 @@ return code is only returned from \fIcurl_easy_recv(3)\fP and
|
|||||||
\fIcurl_easy_send(3)\fP (Added in 7.18.2)
|
\fIcurl_easy_send(3)\fP (Added in 7.18.2)
|
||||||
.IP "CURLE_SSL_CRL_BADFILE (82)"
|
.IP "CURLE_SSL_CRL_BADFILE (82)"
|
||||||
Failed to load CRL file (Added in 7.18.3)
|
Failed to load CRL file (Added in 7.18.3)
|
||||||
|
.IP "CURLE_SSL_ISSUER_ERROR (83)"
|
||||||
|
Issuer check failed (Added in 7.18.3)
|
||||||
.IP "CURLE_OBSOLETE*"
|
.IP "CURLE_OBSOLETE*"
|
||||||
These error codes will never be returned. They used to be used in an old libcurl
|
These error codes will never be returned. They used to be used in an old libcurl
|
||||||
version and are currently unused.
|
version and are currently unused.
|
||||||
|
@@ -456,6 +456,8 @@ typedef enum {
|
|||||||
in 7.18.2) */
|
in 7.18.2) */
|
||||||
CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or
|
CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or
|
||||||
wrong format (Added in 7.18.3) */
|
wrong format (Added in 7.18.3) */
|
||||||
|
CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
|
||||||
|
7.18.3) */
|
||||||
CURL_LAST /* never use! */
|
CURL_LAST /* never use! */
|
||||||
} CURLcode;
|
} CURLcode;
|
||||||
|
|
||||||
@@ -1206,6 +1208,9 @@ typedef enum {
|
|||||||
/* CRL file */
|
/* CRL file */
|
||||||
CINIT(CRLFILE, OBJECTPOINT, 169),
|
CINIT(CRLFILE, OBJECTPOINT, 169),
|
||||||
|
|
||||||
|
/* Issuer certificate */
|
||||||
|
CINIT(ISSUERCERT, OBJECTPOINT, 170),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
|
53
lib/gtls.c
53
lib/gtls.c
@@ -143,6 +143,32 @@ static void showtime(struct SessionHandle *data,
|
|||||||
infof(data, "%s", data->state.buffer);
|
infof(data, "%s", data->state.buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gnutls_datum load_file (const char *file)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
gnutls_datum loaded_file = { NULL, 0 };
|
||||||
|
long filelen;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if (!(f = fopen(file, "r"))
|
||||||
|
|| fseek(f, 0, SEEK_END) != 0
|
||||||
|
|| (filelen = ftell(f)) < 0
|
||||||
|
|| fseek(f, 0, SEEK_SET) != 0
|
||||||
|
|| !(ptr = malloc((size_t)filelen))
|
||||||
|
|| fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
|
||||||
|
return loaded_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded_file.data = ptr;
|
||||||
|
loaded_file.size = (unsigned int)filelen;
|
||||||
|
return loaded_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unload_file(gnutls_datum data) {
|
||||||
|
free(data.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* this function does a BLOCKING SSL/TLS (re-)handshake */
|
/* this function does a BLOCKING SSL/TLS (re-)handshake */
|
||||||
static CURLcode handshake(struct connectdata *conn,
|
static CURLcode handshake(struct connectdata *conn,
|
||||||
gnutls_session session,
|
gnutls_session session,
|
||||||
@@ -221,7 +247,8 @@ Curl_gtls_connect(struct connectdata *conn,
|
|||||||
unsigned int cert_list_size;
|
unsigned int cert_list_size;
|
||||||
const gnutls_datum *chainp;
|
const gnutls_datum *chainp;
|
||||||
unsigned int verify_status;
|
unsigned int verify_status;
|
||||||
gnutls_x509_crt x509_cert;
|
gnutls_x509_crt x509_cert,x509_issuer;
|
||||||
|
gnutls_datum issuerp;
|
||||||
char certbuf[256]; /* big enough? */
|
char certbuf[256]; /* big enough? */
|
||||||
size_t size;
|
size_t size;
|
||||||
unsigned int algo;
|
unsigned int algo;
|
||||||
@@ -375,7 +402,9 @@ Curl_gtls_connect(struct connectdata *conn,
|
|||||||
|
|
||||||
chainp = gnutls_certificate_get_peers(session, &cert_list_size);
|
chainp = gnutls_certificate_get_peers(session, &cert_list_size);
|
||||||
if(!chainp) {
|
if(!chainp) {
|
||||||
if(data->set.ssl.verifypeer) {
|
if(data->set.ssl.verifypeer ||
|
||||||
|
data->set.ssl.verifyhost ||
|
||||||
|
data->set.ssl.issuercert) {
|
||||||
failf(data, "failed to get server cert");
|
failf(data, "failed to get server cert");
|
||||||
return CURLE_PEER_FAILED_VERIFICATION;
|
return CURLE_PEER_FAILED_VERIFICATION;
|
||||||
}
|
}
|
||||||
@@ -399,8 +428,9 @@ Curl_gtls_connect(struct connectdata *conn,
|
|||||||
/* verify_status is a bitmask of gnutls_certificate_status bits */
|
/* verify_status is a bitmask of gnutls_certificate_status bits */
|
||||||
if(verify_status & GNUTLS_CERT_INVALID) {
|
if(verify_status & GNUTLS_CERT_INVALID) {
|
||||||
if(data->set.ssl.verifypeer) {
|
if(data->set.ssl.verifypeer) {
|
||||||
failf(data, "server certificate verification failed. CAfile: %s",
|
failf(data, "server certificate verification failed. CAfile: %s "
|
||||||
data->set.ssl.CAfile?data->set.ssl.CAfile:"none");
|
"CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
|
||||||
|
data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
|
||||||
return CURLE_SSL_CACERT;
|
return CURLE_SSL_CACERT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -419,6 +449,21 @@ Curl_gtls_connect(struct connectdata *conn,
|
|||||||
gnutls_x509_crt_t format */
|
gnutls_x509_crt_t format */
|
||||||
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
|
gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
|
||||||
|
|
||||||
|
if (data->set.ssl.issuercert) {
|
||||||
|
gnutls_x509_crt_init(&x509_issuer);
|
||||||
|
issuerp = load_file(data->set.ssl.issuercert);
|
||||||
|
gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
|
||||||
|
rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
|
||||||
|
unload_file(issuerp);
|
||||||
|
if (rc <= 0) {
|
||||||
|
failf(data, "server certificate issuer check failed (IssuerCert: %s)",
|
||||||
|
data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
|
||||||
|
return CURLE_SSL_ISSUER_ERROR;
|
||||||
|
}
|
||||||
|
infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
|
||||||
|
data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
|
||||||
|
}
|
||||||
|
|
||||||
size=sizeof(certbuf);
|
size=sizeof(certbuf);
|
||||||
rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
|
rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
|
||||||
0, /* the first and only one */
|
0, /* the first and only one */
|
||||||
|
69
lib/nss.c
69
lib/nss.c
@@ -721,6 +721,43 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Check that the Peer certificate's issuer certificate matches the one found
|
||||||
|
* by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
|
||||||
|
* issuer check, so we provide comments that mimic the OpenSSL
|
||||||
|
* X509_check_issued function (in x509v3/v3_purp.c)
|
||||||
|
*/
|
||||||
|
static SECStatus check_issuer_cert(struct connectdata *conn, PRFileDesc *sock, char* issuer_nickname)
|
||||||
|
{
|
||||||
|
CERTCertificate *cert,*cert_issuer,*issuer;
|
||||||
|
SECStatus res=SECSuccess;
|
||||||
|
void *proto_win = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
PRArenaPool *tmpArena = NULL;
|
||||||
|
CERTAuthKeyID *authorityKeyID = NULL;
|
||||||
|
SECITEM *caname = NULL;
|
||||||
|
*/
|
||||||
|
|
||||||
|
cert = SSL_PeerCertificate(sock);
|
||||||
|
cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
|
||||||
|
|
||||||
|
proto_win = SSL_RevealPinArg(sock);
|
||||||
|
issuer = NULL;
|
||||||
|
issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
|
||||||
|
|
||||||
|
if ((!cert_issuer) || (!issuer))
|
||||||
|
res = SECFailure;
|
||||||
|
else if (CERT_CompareCerts(cert_issuer,issuer)==PR_FALSE)
|
||||||
|
res = SECFailure;
|
||||||
|
|
||||||
|
CERT_DestroyCertificate(cert);
|
||||||
|
CERT_DestroyCertificate(issuer);
|
||||||
|
CERT_DestroyCertificate(cert_issuer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Callback to pick the SSL client certificate.
|
* Callback to pick the SSL client certificate.
|
||||||
@@ -853,7 +890,7 @@ int Curl_nss_close_all(struct SessionHandle *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex)
|
CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
|
||||||
{
|
{
|
||||||
PRInt32 err;
|
PRInt32 err;
|
||||||
PRFileDesc *model = NULL;
|
PRFileDesc *model = NULL;
|
||||||
@@ -1046,6 +1083,7 @@ CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
strncpy(nickname, data->set.str[STRING_CERT], PATH_MAX);
|
strncpy(nickname, data->set.str[STRING_CERT], PATH_MAX);
|
||||||
|
nickname[PATH_MAX-1]=0; /* make sure this is zero terminated */
|
||||||
}
|
}
|
||||||
if(nss_Init_Tokens(conn) != SECSuccess) {
|
if(nss_Init_Tokens(conn) != SECSuccess) {
|
||||||
free(nickname);
|
free(nickname);
|
||||||
@@ -1061,7 +1099,7 @@ CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex)
|
|||||||
connssl->client_nickname = strdup(nickname);
|
connssl->client_nickname = strdup(nickname);
|
||||||
if(SSL_GetClientAuthDataHook(model,
|
if(SSL_GetClientAuthDataHook(model,
|
||||||
(SSLGetClientAuthData) SelectClientCert,
|
(SSLGetClientAuthData) SelectClientCert,
|
||||||
(void *)connssl->client_nickname) !=
|
(void *)connssl) !=
|
||||||
SECSuccess) {
|
SECSuccess) {
|
||||||
curlerr = CURLE_SSL_CERTPROBLEM;
|
curlerr = CURLE_SSL_CERTPROBLEM;
|
||||||
goto error;
|
goto error;
|
||||||
@@ -1074,6 +1112,7 @@ CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex)
|
|||||||
else
|
else
|
||||||
connssl->client_nickname = NULL;
|
connssl->client_nickname = NULL;
|
||||||
|
|
||||||
|
|
||||||
/* Import our model socket onto the existing file descriptor */
|
/* Import our model socket onto the existing file descriptor */
|
||||||
connssl->handle = PR_ImportTCPSocket(sockfd);
|
connssl->handle = PR_ImportTCPSocket(sockfd);
|
||||||
connssl->handle = SSL_ImportFD(model, connssl->handle);
|
connssl->handle = SSL_ImportFD(model, connssl->handle);
|
||||||
@@ -1099,6 +1138,32 @@ CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex)
|
|||||||
|
|
||||||
display_conn_info(conn, connssl->handle);
|
display_conn_info(conn, connssl->handle);
|
||||||
|
|
||||||
|
if (data->set.str[STRING_SSL_ISSUERCERT]) {
|
||||||
|
char *n;
|
||||||
|
char *nickname;
|
||||||
|
nickname = (char *)malloc(PATH_MAX);
|
||||||
|
if(is_file(data->set.str[STRING_SSL_ISSUERCERT])) {
|
||||||
|
n = strrchr(data->set.str[STRING_SSL_ISSUERCERT], '/');
|
||||||
|
if (n) {
|
||||||
|
n++; /* skip last slash */
|
||||||
|
snprintf(nickname, PATH_MAX, "PEM Token #%ld:%s", 1, n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
strncpy(nickname, data->set.str[STRING_SSL_ISSUERCERT], PATH_MAX);
|
||||||
|
nickname[PATH_MAX-1]=0; /* make sure this is zero terminated */
|
||||||
|
}
|
||||||
|
if (check_issuer_cert(conn,connssl->handle,nickname)==SECFailure) {
|
||||||
|
infof(data,"SSL certificate issuer check failed\n");
|
||||||
|
free(nickname);
|
||||||
|
curlerr = CURLE_SSL_ISSUER_ERROR;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
infof("SSL certificate issuer check ok\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
42
lib/ssluse.c
42
lib/ssluse.c
@@ -1629,6 +1629,9 @@ static CURLcode servercert(struct connectdata *conn,
|
|||||||
long lerr;
|
long lerr;
|
||||||
ASN1_TIME *certdate;
|
ASN1_TIME *certdate;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
|
X509 *issuer;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
|
connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
|
||||||
if(!connssl->server_cert) {
|
if(!connssl->server_cert) {
|
||||||
if(strict)
|
if(strict)
|
||||||
@@ -1678,6 +1681,41 @@ static CURLcode servercert(struct connectdata *conn,
|
|||||||
/* We could do all sorts of certificate verification stuff here before
|
/* We could do all sorts of certificate verification stuff here before
|
||||||
deallocating the certificate. */
|
deallocating the certificate. */
|
||||||
|
|
||||||
|
/* e.g. match issuer name with provided issuer certificate */
|
||||||
|
if (data->set.str[STRING_SSL_ISSUERCERT]) {
|
||||||
|
if (! (fp=fopen(data->set.str[STRING_SSL_ISSUERCERT],"r"))) {
|
||||||
|
if (strict)
|
||||||
|
failf(data, "SSL: Unable to open issuer cert (%s)\n",
|
||||||
|
data->set.str[STRING_SSL_ISSUERCERT]);
|
||||||
|
X509_free(connssl->server_cert);
|
||||||
|
connssl->server_cert = NULL;
|
||||||
|
return CURLE_SSL_ISSUER_ERROR;
|
||||||
|
}
|
||||||
|
issuer = PEM_read_X509(fp,NULL,NULL,NULL);
|
||||||
|
if (!issuer) {
|
||||||
|
if (strict)
|
||||||
|
failf(data, "SSL: Unable to read issuer cert (%s)\n",
|
||||||
|
data->set.str[STRING_SSL_ISSUERCERT]);
|
||||||
|
X509_free(connssl->server_cert);
|
||||||
|
X509_free(issuer);
|
||||||
|
fclose(fp);
|
||||||
|
return CURLE_SSL_ISSUER_ERROR;
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
if (X509_check_issued(issuer,connssl->server_cert) != X509_V_OK) {
|
||||||
|
if (strict)
|
||||||
|
failf(data, "SSL: Certificate issuer check failed (%s)\n",
|
||||||
|
data->set.str[STRING_SSL_ISSUERCERT]);
|
||||||
|
X509_free(connssl->server_cert);
|
||||||
|
X509_free(issuer);
|
||||||
|
connssl->server_cert = NULL;
|
||||||
|
return CURLE_SSL_ISSUER_ERROR;
|
||||||
|
}
|
||||||
|
infof(data, "\t SSL certificate issuer check ok (%s)\n",
|
||||||
|
data->set.str[STRING_SSL_ISSUERCERT]);
|
||||||
|
X509_free(issuer);
|
||||||
|
}
|
||||||
|
|
||||||
lerr = data->set.ssl.certverifyresult=
|
lerr = data->set.ssl.certverifyresult=
|
||||||
SSL_get_verify_result(connssl->handle);
|
SSL_get_verify_result(connssl->handle);
|
||||||
if(data->set.ssl.certverifyresult != X509_V_OK) {
|
if(data->set.ssl.certverifyresult != X509_V_OK) {
|
||||||
@@ -1690,12 +1728,12 @@ static CURLcode servercert(struct connectdata *conn,
|
|||||||
retcode = CURLE_PEER_FAILED_VERIFICATION;
|
retcode = CURLE_PEER_FAILED_VERIFICATION;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
infof(data, "SSL certificate verify result: %s (%ld),"
|
infof(data, "\t SSL certificate verify result: %s (%ld),"
|
||||||
" continuing anyway.\n",
|
" continuing anyway.\n",
|
||||||
X509_verify_cert_error_string(lerr), lerr);
|
X509_verify_cert_error_string(lerr), lerr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
infof(data, "SSL certificate verify ok.\n");
|
infof(data, "\t SSL certificate verify ok.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
X509_free(connssl->server_cert);
|
X509_free(connssl->server_cert);
|
||||||
|
@@ -225,6 +225,9 @@ curl_easy_strerror(CURLcode error)
|
|||||||
case CURLE_SSL_CRL_BADFILE:
|
case CURLE_SSL_CRL_BADFILE:
|
||||||
return "Failed to load CRL file (path? access rights?, format?)";
|
return "Failed to load CRL file (path? access rights?, format?)";
|
||||||
|
|
||||||
|
case CURLE_SSL_ISSUER_ERROR:
|
||||||
|
return "Issuer check against peer certificate failed";
|
||||||
|
|
||||||
case CURLE_SEND_FAIL_REWIND:
|
case CURLE_SEND_FAIL_REWIND:
|
||||||
return "Send failed since rewinding of the data stream failed";
|
return "Send failed since rewinding of the data stream failed";
|
||||||
|
|
||||||
|
@@ -1819,6 +1819,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
|||||||
result = setstropt(&data->set.str[STRING_SSL_CRLFILE],
|
result = setstropt(&data->set.str[STRING_SSL_CRLFILE],
|
||||||
va_arg(param, char *));
|
va_arg(param, char *));
|
||||||
break;
|
break;
|
||||||
|
case CURLOPT_ISSUERCERT:
|
||||||
|
/*
|
||||||
|
* Set Issuer certificate file
|
||||||
|
* to check certificates issuer
|
||||||
|
*/
|
||||||
|
result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
|
||||||
|
va_arg(param, char *));
|
||||||
|
break;
|
||||||
case CURLOPT_TELNETOPTIONS:
|
case CURLOPT_TELNETOPTIONS:
|
||||||
/*
|
/*
|
||||||
* Set a linked list of telnet options
|
* Set a linked list of telnet options
|
||||||
@@ -3960,6 +3968,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
|
data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
|
||||||
data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE];
|
data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE];
|
||||||
data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
|
data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
|
||||||
|
data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
|
||||||
data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
|
data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
|
||||||
data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
|
data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
|
||||||
data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
|
data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
|
||||||
|
@@ -213,6 +213,7 @@ struct ssl_config_data {
|
|||||||
char *CApath; /* certificate dir (doesn't work on windows) */
|
char *CApath; /* certificate dir (doesn't work on windows) */
|
||||||
char *CAfile; /* cerficate to verify peer against */
|
char *CAfile; /* cerficate to verify peer against */
|
||||||
char *CRLfile; /* CRL to check cerficate revocation */
|
char *CRLfile; /* CRL to check cerficate revocation */
|
||||||
|
char *issuercert; /* optional issuer cerficate filename */
|
||||||
char *random_file; /* path to file containing "random" data */
|
char *random_file; /* path to file containing "random" data */
|
||||||
char *egdsocket; /* path to file containing the EGD daemon socket */
|
char *egdsocket; /* path to file containing the EGD daemon socket */
|
||||||
char *cipher_list; /* list of ciphers to use */
|
char *cipher_list; /* list of ciphers to use */
|
||||||
@@ -1319,6 +1320,7 @@ enum dupstring {
|
|||||||
STRING_USERPWD, /* <user:password>, if used */
|
STRING_USERPWD, /* <user:password>, if used */
|
||||||
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
|
STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
|
||||||
STRING_SSL_CRLFILE, /* crl file to check certificate */
|
STRING_SSL_CRLFILE, /* crl file to check certificate */
|
||||||
|
STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
|
||||||
|
|
||||||
/* -- end of strings -- */
|
/* -- end of strings -- */
|
||||||
STRING_LAST /* not used, just an end-of-list marker */
|
STRING_LAST /* not used, just an end-of-list marker */
|
||||||
|
Reference in New Issue
Block a user