Index: curl-7.18.1/include/curl/curl.h =================================================================== --- curl-7.18.1.orig/include/curl/curl.h 2008-06-02 08:04:13.326168892 +0200 +++ curl-7.18.1/include/curl/curl.h 2008-06-02 08:04:15.542170300 +0200 @@ -438,9 +438,10 @@ CURLE_SSH, /* 79 - error from the SSH layer, somewhat generic so the error message will be of interest when this has happened */ - CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL connection */ + CURLE_SSL_CRL_BADFILE, /* 81 - could not load CRL file, missing + or wrong format */ CURL_LAST /* never use! */ } CURLcode; @@ -1188,6 +1189,9 @@ CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167), CINIT(SEEKDATA, OBJECTPOINT, 168), + /* CRL file */ + CINIT(CRLFILE, OBJECTPOINT, 169), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; Index: curl-7.18.1/lib/ssluse.c =================================================================== --- curl-7.18.1.orig/lib/ssluse.c 2008-06-02 08:04:13.334166834 +0200 +++ curl-7.18.1/lib/ssluse.c 2008-06-02 08:04:15.542170300 +0200 @@ -1297,6 +1297,7 @@ struct SessionHandle *data = conn->data; SSL_METHOD_QUAL SSL_METHOD *req_method=NULL; void *ssl_sessionid=NULL; + X509_LOOKUP *lookup=NULL; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME @@ -1433,6 +1434,31 @@ data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: "none"); } + + if (data->set.str[STRING_SSL_CRLFILE]) { + /* tell SSL where to find CRL file that is used to check certificate + * revocation */ + lookup=X509_STORE_add_lookup(connssl->ctx->cert_store,X509_LOOKUP_file()); + if ( !lookup || + (X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE], + X509_FILETYPE_PEM)!=1) ) { + failf(data,"error loading CRL file :\n" + " CRLfile: %s\n", + data->set.str[STRING_SSL_CRLFILE]? + data->set.str[STRING_SSL_CRLFILE]: "none"); + return CURLE_SSL_CRL_BADFILE; + } + else { + /* Everything is fine. */ + infof(data, "successfully load CRL file:\n"); + X509_STORE_set_flags(connssl->ctx->cert_store, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + } + infof(data, + " CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ? + data->set.str[STRING_SSL_CRLFILE]: "none"); + } + /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue * anyway. In the latter case the result of the verification is checked with Index: curl-7.18.1/lib/url.c =================================================================== --- curl-7.18.1.orig/lib/url.c 2008-06-02 08:04:13.346184700 +0200 +++ curl-7.18.1/lib/url.c 2008-06-02 08:04:15.550160698 +0200 @@ -1803,6 +1803,14 @@ result = setstropt(&data->set.str[STRING_SSL_CAPATH], va_arg(param, char *)); break; + case CURLOPT_CRLFILE: + /* + * Set CRL file info for SSL connection. Specify file name of the CRL + * to check certificates revocation + */ + result = setstropt(&data->set.str[STRING_SSL_CRLFILE], + va_arg(param, char *)); + break; case CURLOPT_TELNETOPTIONS: /* * Set a linked list of telnet options @@ -3943,6 +3951,7 @@ */ data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH]; data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE]; + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE]; 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.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; Index: curl-7.18.1/lib/urldata.h =================================================================== --- curl-7.18.1.orig/lib/urldata.h 2008-06-02 08:04:13.354161339 +0200 +++ curl-7.18.1/lib/urldata.h 2008-06-02 08:04:15.550160698 +0200 @@ -210,6 +210,7 @@ 2: CN must match hostname */ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* cerficate to verify peer against */ + char *CRLfile; /* CRL to check cerficate revocation */ char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ @@ -1312,6 +1313,7 @@ STRING_USERAGENT, /* User-Agent string */ STRING_USERPWD, /* , if used */ STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */ + STRING_SSL_CRLFILE, /* crl file to check certificate */ /* -- end of strings -- */ STRING_LAST /* not used, just an end-of-list marker */ Index: curl-7.18.1/lib/gtls.c =================================================================== --- curl-7.18.1.orig/lib/gtls.c 2008-06-02 08:04:13.362168290 +0200 +++ curl-7.18.1/lib/gtls.c 2008-06-02 08:04:15.550160698 +0200 @@ -271,6 +271,21 @@ rc, data->set.ssl.CAfile); } + if(data->set.ssl.CRLfile) { + /* set the CRL list file */ + rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, + data->set.ssl.CRLfile, + GNUTLS_X509_FMT_PEM); + if(rc < 0) { + failf(data, "error reading crl file %s (%s)\n", + data->set.ssl.CRLfile, gnutls_strerror(rc)); + return CURLE_SSL_CRL_BADFILE; + } + else + infof(data, "found %d CRL in %s\n", + rc, data->set.ssl.CRLfile); + } + /* Initialize TLS session as a client */ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); if(rc) { Index: curl-7.18.1/lib/nss.c =================================================================== --- curl-7.18.1.orig/lib/nss.c 2008-06-02 08:04:13.374185945 +0200 +++ curl-7.18.1/lib/nss.c 2008-06-02 09:21:05.614160446 +0200 @@ -59,6 +59,9 @@ #include #include #include +#include +#include +#include #include "memory.h" #include "easyif.h" /* for Curl_convert_from_utf8 prototype */ @@ -366,6 +369,69 @@ return 1; } +static int nss_load_crl(char* crlfilename, PRBool ascii) +{ + PRFileDesc *infile; + PRStatus prstat; + PRFileInfo info; + PRInt32 nb; + int rv; + SECItem crlDER; + CERTSignedCrl *crl=NULL; + PK11SlotInfo *slot=NULL; + + infile = PR_Open(crlfilename,PR_RDONLY,0); + if (!infile) { + return 0; + } + crlDER.data = NULL; + prstat = PR_GetOpenFileInfo(infile,&info); + if (prstat!=PR_SUCCESS) return 0; + if (ascii) { + SECItem filedata; + char *asc,*body; + filedata.data = NULL; + if (!SECITEM_AllocItem(NULL,&filedata,info.size)) return 0; + nb = PR_Read(infile,filedata.data,info.size); + if (nb!=info.size) return 0; + asc = (char*)filedata.data; + if (!asc) { + return 0; + } + if ((body=strstr(asc,"-----BEGIN")) != NULL) { + char *trailer=NULL; + asc = body; + body = PORT_Strchr(asc,'\n'); + if (!body) body = PORT_Strchr(asc,'\r'); + if (body) trailer = strstr(++body,"-----END"); + if (trailer!=NULL) *trailer='\0'; + else return 0; + } + else { + body = asc; + } + rv = ATOB_ConvertAsciiToItem(&crlDER,body); + PORT_Free(filedata.data); + if (rv) return 0; + } + else { + if (!SECITEM_AllocItem(NULL,&crlDER,info.size)) return 0; + nb = PR_Read(infile,crlDER.data,info.size); + if (nb!=info.size) return 0; + } + + slot = PK11_GetInternalKeySlot(); + crl = PK11_ImportCRL(slot,&crlDER, + NULL,SEC_CRL_TYPE, + NULL,CRL_IMPORT_DEFAULT_OPTIONS, + NULL,(CRL_DECODE_DEFAULT_OPTIONS| + CRL_DECODE_DONT_COPY_DER)); + if (slot) PK11_FreeSlot(slot); + if (!crl) return 0; + SEC_DestroyCrl(crl); + return 1; +} + static int nss_load_key(struct connectdata *conn, char *key_file) { #ifdef HAVE_PK11_CREATEGENERICOBJECT @@ -959,6 +1025,17 @@ data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", data->set.ssl.CApath ? data->set.ssl.CApath : "none"); + if (data->set.ssl.CRLfile) { + int rc = nss_load_crl(data->set.ssl.CRLfile, PR_FALSE); + if (!rc) { + curlerr = CURLE_SSL_CRL_BADFILE; + goto error; + } + infof(data, + " CRLfile: %s\n", + data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none"); + } + if(data->set.str[STRING_CERT]) { char *n; char *nickname; Index: curl-7.18.1/lib/strerror.c =================================================================== --- curl-7.18.1.orig/lib/strerror.c 2008-06-02 08:04:13.386175873 +0200 +++ curl-7.18.1/lib/strerror.c 2008-06-02 08:04:15.550160698 +0200 @@ -222,6 +222,9 @@ case CURLE_SSL_SHUTDOWN_FAILED: return "Failed to shut down the SSL connection"; + case CURLE_SSL_CRL_BADFILE: + return "Failed to load CRL file (path? access rights?, format?)"; + case CURLE_SEND_FAIL_REWIND: return "Send failed since rewinding of the data stream failed";