1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23/* This file is for implementing all "generic" SSL functions that all libcurl 24 internals should use. It is then responsible for calling the proper 25 "backend" function. 26 27 SSL-functions in libcurl should call functions in this source file, and not 28 to any specific SSL-layer. 29 30 Curl_ssl_ - prefix for generic ones 31 Curl_ossl_ - prefix for OpenSSL ones 32 Curl_gtls_ - prefix for GnuTLS ones 33 Curl_nss_ - prefix for NSS ones 34 Curl_polarssl_ - prefix for PolarSSL ones 35 Curl_cyassl_ - prefix for CyaSSL ones 36 37 Note that this source code uses curlssl_* functions, and they are all 38 defines/macros #defined by the lib-specific header files. 39 40 "SSL/TLS Strong Encryption: An Introduction" 41 http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html 42*/ 43 44#include "setup.h" 45 46#ifdef HAVE_SYS_SOCKET_H 47#include <sys/socket.h> 48#endif 49 50#include "urldata.h" 51#define SSLGEN_C 52#include "sslgen.h" /* generic SSL protos etc */ 53#include "ssluse.h" /* OpenSSL versions */ 54#include "gtls.h" /* GnuTLS versions */ 55#include "nssg.h" /* NSS versions */ 56#include "qssl.h" /* QSOSSL versions */ 57#include "polarssl.h" /* PolarSSL versions */ 58#include "axtls.h" /* axTLS versions */ 59#include "cyassl.h" /* CyaSSL versions */ 60#include "sendf.h" 61#include "rawstr.h" 62#include "url.h" 63#include "curl_memory.h" 64#include "progress.h" 65#include "share.h" 66/* The last #include file should be: */ 67#include "memdebug.h" 68 69static bool safe_strequal(char* str1, char* str2) 70{ 71 if(str1 && str2) 72 /* both pointers point to something then compare them */ 73 return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE; 74 else 75 /* if both pointers are NULL then treat them as equal */ 76 return (!str1 && !str2) ? TRUE : FALSE; 77} 78 79bool 80Curl_ssl_config_matches(struct ssl_config_data* data, 81 struct ssl_config_data* needle) 82{ 83 if((data->version == needle->version) && 84 (data->verifypeer == needle->verifypeer) && 85 (data->verifyhost == needle->verifyhost) && 86 safe_strequal(data->CApath, needle->CApath) && 87 safe_strequal(data->CAfile, needle->CAfile) && 88 safe_strequal(data->random_file, needle->random_file) && 89 safe_strequal(data->egdsocket, needle->egdsocket) && 90 safe_strequal(data->cipher_list, needle->cipher_list)) 91 return TRUE; 92 93 return FALSE; 94} 95 96bool 97Curl_clone_ssl_config(struct ssl_config_data *source, 98 struct ssl_config_data *dest) 99{ 100 dest->sessionid = source->sessionid; 101 dest->verifyhost = source->verifyhost; 102 dest->verifypeer = source->verifypeer; 103 dest->version = source->version; 104 105 if(source->CAfile) { 106 dest->CAfile = strdup(source->CAfile); 107 if(!dest->CAfile) 108 return FALSE; 109 } 110 else 111 dest->CAfile = NULL; 112 113 if(source->CApath) { 114 dest->CApath = strdup(source->CApath); 115 if(!dest->CApath) 116 return FALSE; 117 } 118 else 119 dest->CApath = NULL; 120 121 if(source->cipher_list) { 122 dest->cipher_list = strdup(source->cipher_list); 123 if(!dest->cipher_list) 124 return FALSE; 125 } 126 else 127 dest->cipher_list = NULL; 128 129 if(source->egdsocket) { 130 dest->egdsocket = strdup(source->egdsocket); 131 if(!dest->egdsocket) 132 return FALSE; 133 } 134 else 135 dest->egdsocket = NULL; 136 137 if(source->random_file) { 138 dest->random_file = strdup(source->random_file); 139 if(!dest->random_file) 140 return FALSE; 141 } 142 else 143 dest->random_file = NULL; 144 145 return TRUE; 146} 147 148void Curl_free_ssl_config(struct ssl_config_data* sslc) 149{ 150 Curl_safefree(sslc->CAfile); 151 Curl_safefree(sslc->CApath); 152 Curl_safefree(sslc->cipher_list); 153 Curl_safefree(sslc->egdsocket); 154 Curl_safefree(sslc->random_file); 155} 156 157#ifdef USE_SSL 158 159/* "global" init done? */ 160static bool init_ssl=FALSE; 161 162/** 163 * Global SSL init 164 * 165 * @retval 0 error initializing SSL 166 * @retval 1 SSL initialized successfully 167 */ 168int Curl_ssl_init(void) 169{ 170 /* make sure this is only done once */ 171 if(init_ssl) 172 return 1; 173 init_ssl = TRUE; /* never again */ 174 175 return curlssl_init(); 176} 177 178 179/* Global cleanup */ 180void Curl_ssl_cleanup(void) 181{ 182 if(init_ssl) { 183 /* only cleanup if we did a previous init */ 184 curlssl_cleanup(); 185 init_ssl = FALSE; 186 } 187} 188 189CURLcode 190Curl_ssl_connect(struct connectdata *conn, int sockindex) 191{ 192 CURLcode res; 193 /* mark this is being ssl-enabled from here on. */ 194 conn->ssl[sockindex].use = TRUE; 195 conn->ssl[sockindex].state = ssl_connection_negotiating; 196 197 res = curlssl_connect(conn, sockindex); 198 199 if(!res) 200 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ 201 202 return res; 203} 204 205CURLcode 206Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, 207 bool *done) 208{ 209#ifdef curlssl_connect_nonblocking 210 CURLcode res; 211 /* mark this is being ssl requested from here on. */ 212 conn->ssl[sockindex].use = TRUE; 213 res = curlssl_connect_nonblocking(conn, sockindex, done); 214 if(!res && *done) 215 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ 216 return res; 217#else 218 *done = TRUE; /* fallback to BLOCKING */ 219 conn->ssl[sockindex].use = TRUE; 220 return curlssl_connect(conn, sockindex); 221#endif /* non-blocking connect support */ 222} 223 224/* 225 * Check if there's a session ID for the given connection in the cache, and if 226 * there's one suitable, it is provided. Returns TRUE when no entry matched. 227 */ 228int Curl_ssl_getsessionid(struct connectdata *conn, 229 void **ssl_sessionid, 230 size_t *idsize) /* set 0 if unknown */ 231{ 232 struct curl_ssl_session *check; 233 struct SessionHandle *data = conn->data; 234 long i; 235 236 if(!conn->ssl_config.sessionid) 237 /* session ID re-use is disabled */ 238 return TRUE; 239 240 /* Lock for reading if shared */ 241 if(data->share && data->share->sslsession == data->state.session) 242 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SHARED); 243 244 for(i=0; i< data->set.ssl.numsessions; i++) { 245 check = &data->state.session[i]; 246 if(!check->sessionid) 247 /* not session ID means blank entry */ 248 continue; 249 if(Curl_raw_equal(conn->host.name, check->name) && 250 (conn->remote_port == check->remote_port) && 251 Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { 252 /* yes, we have a session ID! */ 253 data->state.sessionage++; /* increase general age */ 254 check->age = data->state.sessionage; /* set this as used in this age */ 255 *ssl_sessionid = check->sessionid; 256 if(idsize) 257 *idsize = check->idsize; 258 return FALSE; 259 } 260 } 261 *ssl_sessionid = NULL; 262 263 /* Unlock for reading */ 264 if(data->share && data->share->sslsession == data->state.session) 265 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); 266 267 268 return TRUE; 269} 270 271/* 272 * Kill a single session ID entry in the cache. 273 */ 274int Curl_ssl_kill_session(struct curl_ssl_session *session) 275{ 276 if(session->sessionid) { 277 /* defensive check */ 278 279 /* free the ID the SSL-layer specific way */ 280 curlssl_session_free(session->sessionid); 281 282 session->sessionid=NULL; 283 session->age = 0; /* fresh */ 284 285 Curl_free_ssl_config(&session->ssl_config); 286 287 Curl_safefree(session->name); 288 session->name = NULL; /* no name */ 289 290 return 0; /* ok */ 291 } 292 else 293 return 1; 294} 295 296/* 297 * Delete the given session ID from the cache. 298 */ 299void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) 300{ 301 int i; 302 struct SessionHandle *data=conn->data; 303 304 if(data->share && data->share->sslsession == data->state.session) 305 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, 306 CURL_LOCK_ACCESS_SINGLE); 307 308 for(i=0; i< data->set.ssl.numsessions; i++) { 309 struct curl_ssl_session *check = &data->state.session[i]; 310 311 if(check->sessionid == ssl_sessionid) { 312 Curl_ssl_kill_session(check); 313 break; 314 } 315 } 316 317 if(data->share && data->share->sslsession == data->state.session) 318 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); 319} 320 321/* 322 * Store session id in the session cache. The ID passed on to this function 323 * must already have been extracted and allocated the proper way for the SSL 324 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID 325 * later on. 326 */ 327CURLcode Curl_ssl_addsessionid(struct connectdata *conn, 328 void *ssl_sessionid, 329 size_t idsize) 330{ 331 long i; 332 struct SessionHandle *data=conn->data; /* the mother of all structs */ 333 struct curl_ssl_session *store = &data->state.session[0]; 334 long oldest_age=data->state.session[0].age; /* zero if unused */ 335 char *clone_host; 336 337 /* Even though session ID re-use might be disabled, that only disables USING 338 IT. We still store it here in case the re-using is again enabled for an 339 upcoming transfer */ 340 341 clone_host = strdup(conn->host.name); 342 if(!clone_host) 343 return CURLE_OUT_OF_MEMORY; /* bail out */ 344 345 /* Now we should add the session ID and the host name to the cache, (remove 346 the oldest if necessary) */ 347 348 /* If using shared SSL session, lock! */ 349 if(data->share && data->share->sslsession == data->state.session) 350 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); 351 352 /* find an empty slot for us, or find the oldest */ 353 for(i=1; (i<data->set.ssl.numsessions) && 354 data->state.session[i].sessionid; i++) { 355 if(data->state.session[i].age < oldest_age) { 356 oldest_age = data->state.session[i].age; 357 store = &data->state.session[i]; 358 } 359 } 360 if(i == data->set.ssl.numsessions) 361 /* cache is full, we must "kill" the oldest entry! */ 362 Curl_ssl_kill_session(store); 363 else 364 store = &data->state.session[i]; /* use this slot */ 365 366 /* now init the session struct wisely */ 367 store->sessionid = ssl_sessionid; 368 store->idsize = idsize; 369 store->age = data->state.sessionage; /* set current age */ 370 if(store->name) 371 /* free it if there's one already present */ 372 free(store->name); 373 store->name = clone_host; /* clone host name */ 374 store->remote_port = conn->remote_port; /* port number */ 375 376 377 /* Unlock */ 378 if(data->share && data->share->sslsession == data->state.session) 379 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); 380 381 if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { 382 store->sessionid = NULL; /* let caller free sessionid */ 383 free(clone_host); 384 return CURLE_OUT_OF_MEMORY; 385 } 386 387 return CURLE_OK; 388} 389 390 391void Curl_ssl_close_all(struct SessionHandle *data) 392{ 393 long i; 394 /* kill the session ID cache */ 395 if(data->state.session && 396 !(data->share && data->share->sslsession == data->state.session)) { 397 398 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); 399 400 for(i=0; i< data->set.ssl.numsessions; i++) 401 /* the single-killer function handles empty table slots */ 402 Curl_ssl_kill_session(&data->state.session[i]); 403 404 /* free the cache data */ 405 free(data->state.session); 406 data->state.session = NULL; 407 408 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); 409 } 410 411 curlssl_close_all(data); 412} 413 414void Curl_ssl_close(struct connectdata *conn, int sockindex) 415{ 416 DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); 417 curlssl_close(conn, sockindex); 418} 419 420CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) 421{ 422 if(curlssl_shutdown(conn, sockindex)) 423 return CURLE_SSL_SHUTDOWN_FAILED; 424 425 conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */ 426 conn->ssl[sockindex].state = ssl_connection_none; 427 428 conn->recv[sockindex] = Curl_recv_plain; 429 conn->send[sockindex] = Curl_send_plain; 430 431 return CURLE_OK; 432} 433 434/* Selects an SSL crypto engine 435 */ 436CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) 437{ 438 return curlssl_set_engine(data, engine); 439} 440 441/* Selects the default SSL crypto engine 442 */ 443CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) 444{ 445 return curlssl_set_engine_default(data); 446} 447 448/* Return list of OpenSSL crypto engine names. */ 449struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) 450{ 451 return curlssl_engines_list(data); 452} 453 454/* 455 * This sets up a session ID cache to the specified size. Make sure this code 456 * is agnostic to what underlying SSL technology we use. 457 */ 458CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount) 459{ 460 struct curl_ssl_session *session; 461 462 if(data->state.session) 463 /* this is just a precaution to prevent multiple inits */ 464 return CURLE_OK; 465 466 session = calloc(amount, sizeof(struct curl_ssl_session)); 467 if(!session) 468 return CURLE_OUT_OF_MEMORY; 469 470 /* store the info in the SSL section */ 471 data->set.ssl.numsessions = amount; 472 data->state.session = session; 473 data->state.sessionage = 1; /* this is brand new */ 474 return CURLE_OK; 475} 476 477size_t Curl_ssl_version(char *buffer, size_t size) 478{ 479 return curlssl_version(buffer, size); 480} 481 482/* 483 * This function tries to determine connection status. 484 * 485 * Return codes: 486 * 1 means the connection is still in place 487 * 0 means the connection has been closed 488 * -1 means the connection status is unknown 489 */ 490int Curl_ssl_check_cxn(struct connectdata *conn) 491{ 492 return curlssl_check_cxn(conn); 493} 494 495bool Curl_ssl_data_pending(const struct connectdata *conn, 496 int connindex) 497{ 498 return curlssl_data_pending(conn, connindex); 499} 500 501void Curl_ssl_free_certinfo(struct SessionHandle *data) 502{ 503 int i; 504 struct curl_certinfo *ci = &data->info.certs; 505 if(ci->num_of_certs) { 506 /* free all individual lists used */ 507 for(i=0; i<ci->num_of_certs; i++) { 508 curl_slist_free_all(ci->certinfo[i]); 509 ci->certinfo[i] = NULL; 510 } 511 free(ci->certinfo); /* free the actual array too */ 512 ci->certinfo = NULL; 513 ci->num_of_certs = 0; 514 } 515} 516#endif /* USE_SSL */ 517