diff -u lib/ssluse.c ../curl-7.10.test/lib/ssluse.c --- lib/ssluse.c 2003-03-11 19:55:34.000000000 +0100 +++ ../curl-7.10.test/lib/ssluse.c 2003-03-17 13:11:08.000000000 +0100 @@ -725,6 +725,90 @@ } /* ====================================================== */ +static CURLcode cert_check(struct connectdata *conn) +{ + CURLcode retcode = CURLE_OK; + struct SessionHandle *data = conn->data; + char * str; + ASN1_TIME *certdate; + + if(!conn->ssl.server_cert) { + failf(data, "SSL: couldn't get peer certificate!"); + return CURLE_SSL_PEER_CERTIFICATE; + } + infof (data, "Server certificate:\n"); + + str = X509_NAME_oneline (X509_get_subject_name (conn->ssl.server_cert), + NULL, 0); + if(!str) { + failf(data, "SSL: couldn't get X509-subject!"); + X509_free(conn->ssl.server_cert); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "\t subject: %s\n", str); + CRYPTO_free(str); + + certdate = X509_get_notBefore(conn->ssl.server_cert); + Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate); + + certdate = X509_get_notAfter(conn->ssl.server_cert); + Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); + + if (data->set.ssl.verifyhost) { + char peer_CN[257]; + if (X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert), + NID_commonName, + peer_CN, + sizeof(peer_CN)) < 0) { + failf(data, "SSL: unable to obtain common name from peer certificate"); + X509_free(conn->ssl.server_cert); + return CURLE_SSL_PEER_CERTIFICATE; + } + + if (!cert_hostcheck(peer_CN, conn->hostname)) { + if (data->set.ssl.verifyhost > 1) { + failf(data, "SSL: certificate subject name '%s' does not match " + "target host name '%s'", + peer_CN, conn->hostname); + X509_free(conn->ssl.server_cert); + return CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, + "\t common name: %s (does not match '%s')\n", + peer_CN, conn->hostname); + } + else + infof(data, "\t common name: %s (matched)\n", peer_CN); + } + + str = X509_NAME_oneline (X509_get_issuer_name (conn->ssl.server_cert), + NULL, 0); + if(!str) { + failf(data, "SSL: couldn't get X509-issuer name!"); + X509_free(conn->ssl.server_cert); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "\t issuer: %s\n", str); + CRYPTO_free(str); + + /* We could do all sorts of certificate verification stuff here before + deallocating the certificate. */ + + if(data->set.ssl.verifypeer) { + data->set.ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle); + if (data->set.ssl.certverifyresult != X509_V_OK) { + failf(data, "SSL certificate verify result: %d", + data->set.ssl.certverifyresult); + retcode = CURLE_SSL_PEER_CERTIFICATE; + } + } + else + data->set.ssl.certverifyresult=0; + return retcode; +} + +/* ====================================================== */ CURLcode Curl_SSLConnect(struct connectdata *conn) { @@ -734,10 +818,8 @@ struct SessionHandle *data = conn->data; int err; int what; - char * str; SSL_METHOD *req_method; SSL_SESSION *ssl_sessionid=NULL; - ASN1_TIME *certdate; /* mark this is being ssl enabled from here on out. */ conn->ssl.use = TRUE; @@ -940,81 +1022,16 @@ */ conn->ssl.server_cert = SSL_get_peer_certificate (conn->ssl.handle); - if(!conn->ssl.server_cert) { - failf(data, "SSL: couldn't get peer certificate!"); - return CURLE_SSL_PEER_CERTIFICATE; - } - infof (data, "Server certificate:\n"); - - str = X509_NAME_oneline (X509_get_subject_name (conn->ssl.server_cert), - NULL, 0); - if(!str) { - failf(data, "SSL: couldn't get X509-subject!"); - X509_free(conn->ssl.server_cert); - return CURLE_SSL_CONNECT_ERROR; - } - infof(data, "\t subject: %s\n", str); - CRYPTO_free(str); - - certdate = X509_get_notBefore(conn->ssl.server_cert); - Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate); - - certdate = X509_get_notAfter(conn->ssl.server_cert); - Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); - - if (data->set.ssl.verifyhost) { - char peer_CN[257]; - if (X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert), - NID_commonName, - peer_CN, - sizeof(peer_CN)) < 0) { - failf(data, "SSL: unable to obtain common name from peer certificate"); - X509_free(conn->ssl.server_cert); - return CURLE_SSL_PEER_CERTIFICATE; - } - - if (!cert_hostcheck(peer_CN, conn->hostname)) { - if (data->set.ssl.verifyhost > 1) { - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", - peer_CN, conn->hostname); - X509_free(conn->ssl.server_cert); - return CURLE_SSL_PEER_CERTIFICATE; - } - else - infof(data, - "\t common name: %s (does not match '%s')\n", - peer_CN, conn->hostname); - } - else - infof(data, "\t common name: %s (matched)\n", peer_CN); - } - - str = X509_NAME_oneline (X509_get_issuer_name (conn->ssl.server_cert), - NULL, 0); - if(!str) { - failf(data, "SSL: couldn't get X509-issuer name!"); - X509_free(conn->ssl.server_cert); - return CURLE_SSL_CONNECT_ERROR; - } - infof(data, "\t issuer: %s\n", str); - CRYPTO_free(str); - - /* We could do all sorts of certificate verification stuff here before - deallocating the certificate. */ - - if(data->set.ssl.verifypeer) { - data->set.ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle); - if (data->set.ssl.certverifyresult != X509_V_OK) { - failf(data, "SSL certificate verify result: %d", - data->set.ssl.certverifyresult); - retcode = CURLE_SSL_PEER_CERTIFICATE; - } + if(conn->data->set.check_certificate) + { + if(conn->data->set.check_certificate(conn->ssl.server_cert, conn->fread)) + retcode = CURLE_SSL_PEER_CERTIFICATE; } else - data->set.ssl.certverifyresult=0; + retcode = cert_check(conn); - X509_free(conn->ssl.server_cert); + if(conn->ssl.server_cert) + X509_free(conn->ssl.server_cert); #else /* USE_SSLEAY */ /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */ (void) conn; diff -u lib/url.c ../curl-7.10.test/lib/url.c --- lib/url.c 2003-03-11 19:58:22.000000000 +0100 +++ ../curl-7.10.test/lib/url.c 2003-03-17 11:58:20.000000000 +0100 @@ -935,6 +935,14 @@ */ data->set.fread = va_arg(param, curl_read_callback); break; +#ifdef USE_SSLEAY + case CURLOPT_CERTFUNCTION: + /* + * Certificate checking function + */ + data->set.check_certificate = va_arg(param, curl_cert_callback); + break; +#endif case CURLOPT_SSLCERT: /* * String that holds file name of the SSL certificate to use diff -u lib/urldata.h ../curl-7.10.test/lib/urldata.h --- lib/urldata.h 2003-02-24 17:53:57.000000000 +0100 +++ ../curl-7.10.test/lib/urldata.h 2003-03-17 11:43:03.000000000 +0100 @@ -674,6 +674,9 @@ char *device; /* network interface to use */ curl_write_callback fwrite; /* function that stores the output */ curl_write_callback fwrite_header; /* function that stores headers */ +#ifdef USE_SSLEAY + curl_cert_callback check_certificate; /* function that checks the server cert */ +#endif curl_read_callback fread; /* function that reads the input */ curl_progress_callback fprogress; /* function for progress information */ curl_debug_callback fdebug; /* function that write informational data */ diff -u include/curl/curl.h ../curl-7.10.test/include/curl/curl.h --- include/curl/curl.h 2003-03-13 19:07:07.000000000 +0100 +++ ../curl-7.10.test/include/curl/curl.h 2003-03-17 11:42:37.000000000 +0100 @@ -42,6 +42,28 @@ # endif #endif /* defined (vms) */ +#ifdef USE_SSLEAY +/* SSLeay stuff usually in /usr/local/ssl/include */ +#ifdef USE_OPENSSL +#include "openssl/rsa.h" +#include "openssl/crypto.h" +#include "openssl/x509.h" +#include "openssl/pem.h" +#include "openssl/ssl.h" +#include "openssl/err.h" +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#endif +#else +#include "rsa.h" +#include "crypto.h" +#include "x509.h" +#include "pem.h" +#include "ssl.h" +#include "err.h" +#endif +#endif + #ifndef TRUE #define TRUE 1 #endif @@ -105,6 +127,11 @@ size_t nitems, void *outstream); +#ifdef USE_SSLEAY +typedef int (*curl_cert_callback)(X509 *server_cert, + void *outstream); +#endif + typedef size_t (*curl_read_callback)(char *buffer, size_t size, size_t nitems, @@ -618,6 +645,8 @@ /* Set aliases for HTTP 200 in the HTTP Response header */ CINIT(HTTP200ALIASES, OBJECTPOINT, 104), + + CINIT(CERTFUNCTION, LONG, 105), CURLOPT_LASTENTRY /* the last unused */ } CURLoption;