34 #ifdef HAVE_SYS_TYPES_H
35 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
50 #include <openssl/rand.h>
51 #include <openssl/x509v3.h>
58 #if OPENSSL_VERSION_NUMBER >= 0x0090581fL
59 #define HAVE_SSL_GET1_SESSION 1
61 #undef HAVE_SSL_GET1_SESSION
64 #if OPENSSL_VERSION_NUMBER >= 0x00904100L
65 #define HAVE_USERDATA_IN_PWD_CALLBACK 1
67 #undef HAVE_USERDATA_IN_PWD_CALLBACK
70 #if OPENSSL_VERSION_NUMBER >= 0x00907001L
72 #define HAVE_ENGINE_LOAD_FOUR_ARGS
75 #undef HAVE_ENGINE_LOAD_FOUR_ARGS
79 #ifndef HAVE_USERDATA_IN_PWD_CALLBACK
80 static char global_passwd[64];
83 static int passwd_callback(
char *buf,
int num,
int verify
84 #
if HAVE_USERDATA_IN_PWD_CALLBACK
93 fprintf(stderr,
"%s\n", buf);
95 if(num > (
int)strlen((
char *)global_passwd)) {
96 strcpy(buf, global_passwd);
104 bool seed_enough(
int nread)
106 #ifdef HAVE_RAND_STATUS
133 #define RANDOM_FILE ""
140 if(seed_enough(nread))
144 #if defined(HAVE_RAND_EGD)
151 #define EGD_SOCKET ""
160 if(seed_enough(nread))
168 #ifdef HAVE_RAND_SCREEN
189 RAND_add(area, len, (len >> 1));
192 }
while (!RAND_status());
201 nread += RAND_load_file(buf, 16384);
202 if(seed_enough(nread))
206 infof(data,
"libcurl is now using a weak random seed!\n");
210 #ifndef SSL_FILETYPE_ENGINE
211 #define SSL_FILETYPE_ENGINE 42
213 static int do_file_type(
const char *
type)
215 if(!type || !type[0])
216 return SSL_FILETYPE_PEM;
218 return SSL_FILETYPE_PEM;
220 return SSL_FILETYPE_ASN1;
222 return SSL_FILETYPE_ENGINE;
230 const char *cert_type,
232 const char *key_type)
237 if(cert_file !=
NULL) {
242 #ifndef HAVE_USERDATA_IN_PWD_CALLBACK
252 SSL_CTX_set_default_passwd_cb_userdata(ctx,
256 SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
259 file_type = do_file_type(cert_type);
262 case SSL_FILETYPE_PEM:
264 if(SSL_CTX_use_certificate_chain_file(ctx,
266 failf(data,
"unable to set certificate file (wrong password?)");
271 case SSL_FILETYPE_ASN1:
275 if(SSL_CTX_use_certificate_file(ctx,
278 failf(data,
"unable to set certificate file (wrong password?)");
282 case SSL_FILETYPE_ENGINE:
283 failf(data,
"file type ENG for certificate not implemented");
287 failf(data,
"not supported file type '%s' for certificate", cert_type);
291 file_type = do_file_type(key_type);
294 case SSL_FILETYPE_PEM:
298 case SSL_FILETYPE_ASN1:
299 if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
300 failf(data,
"unable to set private key file: '%s' type %s\n",
301 key_file, key_type?key_type:
"PEM");
305 case SSL_FILETYPE_ENGINE:
306 #ifdef HAVE_OPENSSL_ENGINE_H
308 EVP_PKEY *priv_key =
NULL;
309 if(conn && conn->
data && conn->
data->engine) {
310 #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
311 UI_METHOD *ui_method = UI_OpenSSL();
313 if(!key_file || !key_file[0]) {
314 failf(data,
"no key set to load from crypto engine\n");
317 priv_key = ENGINE_load_private_key(conn->
data->engine,key_file,
318 #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
323 failf(data,
"failed to load private key from crypto engine\n");
326 if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
327 failf(data,
"unable to set private key\n");
328 EVP_PKEY_free(priv_key);
331 EVP_PKEY_free(priv_key);
334 failf(data,
"crypto engine not set, can't load private key\n");
339 failf(data,
"file type ENG for private key not supported\n");
344 failf(data,
"not supported file type for private key\n");
349 x509=SSL_get_certificate(ssl);
354 EVP_PKEY *pktmp = X509_get_pubkey(x509);
355 EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl));
356 EVP_PKEY_free(pktmp);
367 if(!SSL_CTX_check_private_key(ctx)) {
368 failf(data,
"Private key does not match the certificate public key");
371 #ifndef HAVE_USERDATA_IN_PWD_CALLBACK
373 memset(global_passwd, 0,
sizeof(global_passwd));
380 int cert_verify_callback(
int ok, X509_STORE_CTX *ctx)
385 err_cert=X509_STORE_CTX_get_current_cert(ctx);
386 X509_NAME_oneline(X509_get_subject_name(err_cert),buf,256);
395 static int init_ssl=0;
399 static bool ssl_seeded =
FALSE;
412 #ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
413 ENGINE_load_builtin_engines();
417 SSL_load_error_strings();
420 SSLeay_add_ssl_algorithms();
440 #ifdef HAVE_ENGINE_cleanup
444 #ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
447 CRYPTO_cleanup_all_ex_data();
487 if(connssl->handle) {
488 (
void)SSL_shutdown(connssl->handle);
489 SSL_set_connect_state(connssl->handle);
491 SSL_free (connssl->handle);
492 connssl->handle =
NULL;
495 SSL_CTX_free (connssl->ctx);
535 static int Get_SSL_Session(
struct connectdata *conn,
536 SSL_SESSION **ssl_sessionid)
557 *ssl_sessionid = (SSL_SESSION *)
NULL;
601 #ifdef HAVE_OPENSSL_ENGINE_H
604 ENGINE_free(data->engine);
614 static int Store_SSL_Session(
struct connectdata *conn,
617 SSL_SESSION *ssl_sessionid;
625 #ifdef HAVE_SSL_GET1_SESSION
626 ssl_sessionid = SSL_get1_session(ssl->handle);
633 ssl_sessionid = SSL_get_session(ssl->handle);
658 Kill_Single_Session(store);
673 static int Curl_ASN1_UTCTIME_output(
struct connectdata *conn,
680 int year=0,month=0,day=0,hour=0,minute=0,second=0;
687 asn1_string=(
char *)tm->data;
691 if(asn1_string[i-1] ==
'Z')
694 if((asn1_string[i] >
'9') || (asn1_string[
i] <
'0'))
697 year= (asn1_string[0]-
'0')*10+(asn1_string[1]-
'0');
701 month= (asn1_string[2]-
'0')*10+(asn1_string[3]-
'0');
702 if((month > 12) || (month < 1))
705 day= (asn1_string[4]-
'0')*10+(asn1_string[5]-
'0');
706 hour= (asn1_string[6]-
'0')*10+(asn1_string[7]-
'0');
707 minute= (asn1_string[8]-
'0')*10+(asn1_string[9]-
'0');
709 if((asn1_string[10] >=
'0') && (asn1_string[10] <=
'9') &&
710 (asn1_string[11] >=
'0') && (asn1_string[11] <=
'9'))
711 second= (asn1_string[10]-
'0')*10+(asn1_string[11]-
'0');
714 "%s%04d-%02d-%02d %02d:%02d:%02d %s\n",
715 prefix, year+1900, month, day, hour, minute, second, (gmt?
"GMT":
""));
725 cert_hostcheck(
const char *certname,
const char *hostname)
728 const char *certdomain;
731 strlen(certname)<3 ||
739 certdomain = certname + 1;
741 if((certname[0] !=
'*') || (certdomain[0] !=
'.'))
744 if(!strchr(certdomain+1,
'.'))
748 tmp = strstr(hostname, certdomain);
754 return tmp == strchr(hostname,
'.');
786 bool matched =
FALSE;
787 int target = GEN_DNS;
790 STACK_OF(GENERAL_NAME) *altnames;
792 struct in6_addr
addr;
801 addrlen =
sizeof(
struct in6_addr);
807 addrlen =
sizeof(
struct in_addr);
811 altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name,
NULL,
NULL);
820 if(GEN_DNS == target) {
822 domain = strchr(conn->
hostname,
'.');
824 domainlen = strlen(domain);
829 numalts = sk_GENERAL_NAME_num(altnames);
832 for (i=0; (i<numalts) && !matched; i++) {
834 const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
837 if(check->type == target) {
839 const char *altptr = (
char *)ASN1_STRING_data(check->d.ia5);
840 const int altlen = ASN1_STRING_length(check->d.ia5);
845 if((hostlen == altlen) &&
850 else if((altptr[0] ==
'*') &&
851 (domainlen == altlen-1) &&
859 if((altlen == addrlen) && !memcmp(altptr, &
addr, altlen))
865 GENERAL_NAMES_free(altnames);
870 infof(data,
"\t subjectAltName: %s matched\n", conn->
hostname);
873 if(X509_NAME_get_text_by_NID(X509_get_subject_name(server_cert),
876 sizeof(peer_CN)) < 0) {
879 "SSL: unable to obtain common name from peer certificate");
885 infof(data,
"\t common name: WARNING couldn't obtain\n");
892 if(!cert_hostcheck(peer_CN, conn->
hostname)) {
894 failf(data,
"SSL: certificate subject name '%s' does not match "
895 "target host name '%s'", peer_CN, conn->
hostname);
899 infof(data,
"\t common name: %s (does not match '%s')\n",
903 infof(data,
"\t common name: %s (matched)\n", peer_CN);
923 SSL_METHOD *req_method;
924 SSL_SESSION *ssl_sessionid=
NULL;
934 random_the_seed(data);
944 req_method = SSLv23_client_method();
947 req_method = TLSv1_client_method();
950 req_method = SSLv2_client_method();
953 req_method = SSLv3_client_method();
957 connssl->ctx = SSL_CTX_new(req_method);
960 failf(data,
"SSL: couldn't create a context!");
972 SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL);
987 if(!SSL_CTX_set_cipher_list(connssl->ctx,
989 failf(data,
"failed setting cipher list");
997 if (!SSL_CTX_load_verify_locations(connssl->ctx, data->
set.
ssl.
CAfile,
1001 failf(data,
"error setting certificate verify locations:\n"
1002 " CAfile: %s\n CApath: %s\n",
1010 infof(data,
"error setting certificate verify locations,"
1011 " continuing anyway:\n");
1016 infof(data,
"successfully set certificate verify locations:\n");
1028 SSL_CTX_set_verify(connssl->ctx,
1030 cert_verify_callback);
1037 failf(data,
"error signaled by ssl ctx callback");
1043 connssl->handle = SSL_new(connssl->ctx);
1044 SSL_set_connect_state(connssl->handle);
1046 connssl->server_cert = 0x0;
1051 if(!Get_SSL_Session(conn, &ssl_sessionid)) {
1053 SSL_set_session(connssl->handle, ssl_sessionid);
1055 infof (data,
"SSL re-using session ID\n");
1060 SSL_set_fd(connssl->handle, sockfd);
1079 #define min(a, b) ((a) < (b) ? (a) : (b))
1090 timeout_ms -= (long)has_passed;
1092 if(timeout_ms < 0) {
1094 failf(data,
"SSL connection timeout");
1106 err = SSL_connect(connssl->handle);
1112 int detail = SSL_get_error(connssl->handle, err);
1114 if(SSL_ERROR_WANT_READ == detail)
1115 FD_SET(sockfd, &readfd);
1116 else if(SSL_ERROR_WANT_WRITE == detail)
1117 FD_SET(sockfd, &writefd);
1120 char error_buffer[120];
1123 detail = ERR_get_error();
1139 "SSL certificate problem, verify that the CA cert is OK");
1143 failf(data,
"SSL: %s", ERR_error_string(detail, error_buffer));
1156 interval.
tv_sec = timeout_ms/1000;
1157 timeout_ms -= interval.
tv_sec*1000;
1159 interval.
tv_usec = timeout_ms*1000;
1162 what =
select(sockfd+1, &readfd, &writefd,
NULL, &interval);
1166 else if(0 == what) {
1168 failf(data,
"SSL connection timeout");
1172 #if !defined(WIN32) && defined(EINTR)
1185 infof (data,
"SSL connection using %s\n",
1186 SSL_get_cipher(connssl->handle));
1188 if(!ssl_sessionid) {
1191 Store_SSL_Session(conn, connssl);
1201 connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
1202 if(!connssl->server_cert) {
1203 failf(data,
"SSL: couldn't get peer certificate!");
1206 infof (data,
"Server certificate:\n");
1208 str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert),
1211 failf(data,
"SSL: couldn't get X509-subject!");
1212 X509_free(connssl->server_cert);
1215 infof(data,
"\t subject: %s\n", str);
1218 certdate = X509_get_notBefore(connssl->server_cert);
1219 Curl_ASN1_UTCTIME_output(conn,
"\t start date: ", certdate);
1221 certdate = X509_get_notAfter(connssl->server_cert);
1222 Curl_ASN1_UTCTIME_output(conn,
"\t expire date: ", certdate);
1225 retcode = verifyhost(conn, connssl->server_cert);
1227 X509_free(connssl->server_cert);
1232 str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert),
1235 failf(data,
"SSL: couldn't get X509-issuer name!");
1239 infof(data,
"\t issuer: %s\n", str);
1250 failf(data,
"SSL certificate verify result: %d",
1255 infof(data,
"SSL certificate verify result: %d, continuing anyway.\n",
1259 infof(data,
"SSL certificate verify ok.\n");
1262 X509_free(connssl->server_cert);
struct ssl_connect_data ssl[2]
struct ssl_config_data ssl
struct curl_ssl_session * session
bool Curl_clone_ssl_config(struct ssl_config_data *source, struct ssl_config_data *dest)
GLuint GLuint GLsizei GLenum type
unsigned short remote_port
struct ssl_config_data ssl_config
void Curl_SSL_cleanup(void)
struct ssl_config_data ssl_config
CURLcode Curl_SSL_InitSessions(struct SessionHandle *, long)
GLsizei GLsizei GLenum GLenum const GLvoid * data
int() curl_strnequal(const char *s1, const char *s2, size_t n)
curl_ssl_ctx_callback fsslctx
long Curl_tvdiff(struct timeval newer, struct timeval older)
GLenum const GLvoid * addr
struct SessionHandle * data
int Curl_inet_pton(int af, const char *src, void *dst)
static WindowRef ValidModeCallbackProc inCallback OSStatus err
bool Curl_ssl_config_matches(struct ssl_config_data *data, struct ssl_config_data *needle)
typedef void(APIENTRYP PFNGLBLENDCOLORPROC)(GLclampf red
struct timeval Curl_tvnow(void)
void Curl_free_ssl_config(struct ssl_config_data *sslc)
unsigned short remote_port
int Curl_SSL_Close_All(struct SessionHandle *data)
CURLcode Curl_SSLConnect(struct connectdata *conn, int sockindex)
void Curl_SSL_Close(struct connectdata *conn)
int() curl_strequal(const char *s1, const char *s2)
#define CURLE_OPERATION_TIMEDOUT