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/* 24 * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code 25 * but sslgen.c should ever call or use these functions. 26 * 27 */ 28 29#include "setup.h" 30#ifdef USE_CYASSL 31 32#include <string.h> 33#include <stdlib.h> 34#include <ctype.h> 35#ifdef HAVE_SYS_SOCKET_H 36#include <sys/socket.h> 37#endif 38 39 40#include "urldata.h" 41#include "sendf.h" 42#include "inet_pton.h" 43#include "cyassl.h" 44#include "sslgen.h" 45#include "parsedate.h" 46#include "connect.h" /* for the connect timeout */ 47#include "select.h" 48#include "rawstr.h" 49 50#define _MPRINTF_REPLACE /* use our functions only */ 51#include <curl/mprintf.h> 52#include "curl_memory.h" 53/* The last #include file should be: */ 54#include "memdebug.h" 55 56 57static Curl_recv cyassl_recv; 58static Curl_send cyassl_send; 59 60 61static int do_file_type(const char *type) 62{ 63 if(!type || !type[0]) 64 return SSL_FILETYPE_PEM; 65 if(Curl_raw_equal(type, "PEM")) 66 return SSL_FILETYPE_PEM; 67 if(Curl_raw_equal(type, "DER")) 68 return SSL_FILETYPE_ASN1; 69 return -1; 70} 71 72/* 73 * This function loads all the client/CA certificates and CRLs. Setup the TLS 74 * layer and do all necessary magic. 75 */ 76static CURLcode 77cyassl_connect_step1(struct connectdata *conn, 78 int sockindex) 79{ 80 struct SessionHandle *data = conn->data; 81 struct ssl_connect_data* conssl = &conn->ssl[sockindex]; 82 SSL_METHOD* req_method = NULL; 83 void* ssl_sessionid = NULL; 84 curl_socket_t sockfd = conn->sock[sockindex]; 85 86 if(conssl->state == ssl_connection_complete) 87 return CURLE_OK; 88 89 /* CyaSSL doesn't support SSLv2 */ 90 if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { 91 failf(data, "CyaSSL does not support SSLv2"); 92 return CURLE_SSL_CONNECT_ERROR; 93 } 94 95 /* check to see if we've been told to use an explicit SSL/TLS version */ 96 switch(data->set.ssl.version) { 97 case CURL_SSLVERSION_DEFAULT: 98 /* we try to figure out version */ 99 req_method = SSLv23_client_method(); 100 break; 101 case CURL_SSLVERSION_TLSv1: 102 req_method = TLSv1_client_method(); 103 break; 104 case CURL_SSLVERSION_SSLv3: 105 req_method = SSLv3_client_method(); 106 break; 107 default: 108 req_method = TLSv1_client_method(); 109 } 110 111 if(!req_method) { 112 failf(data, "SSL: couldn't create a method!"); 113 return CURLE_OUT_OF_MEMORY; 114 } 115 116 if(conssl->ctx) 117 SSL_CTX_free(conssl->ctx); 118 conssl->ctx = SSL_CTX_new(req_method); 119 120 if(!conssl->ctx) { 121 failf(data, "SSL: couldn't create a context!"); 122 return CURLE_OUT_OF_MEMORY; 123 } 124 125#ifndef NO_FILESYSTEM 126 /* load trusted cacert */ 127 if(data->set.str[STRING_SSL_CAFILE]) { 128 if(!SSL_CTX_load_verify_locations(conssl->ctx, 129 data->set.str[STRING_SSL_CAFILE], 130 data->set.str[STRING_SSL_CAPATH])) { 131 if(data->set.ssl.verifypeer) { 132 /* Fail if we insiste on successfully verifying the server. */ 133 failf(data,"error setting certificate verify locations:\n" 134 " CAfile: %s\n CApath: %s\n", 135 data->set.str[STRING_SSL_CAFILE]? 136 data->set.str[STRING_SSL_CAFILE]: "none", 137 data->set.str[STRING_SSL_CAPATH]? 138 data->set.str[STRING_SSL_CAPATH] : "none"); 139 return CURLE_SSL_CACERT_BADFILE; 140 } 141 else { 142 /* Just continue with a warning if no strict certificate 143 verification is required. */ 144 infof(data, "error setting certificate verify locations," 145 " continuing anyway:\n"); 146 } 147 } 148 else { 149 /* Everything is fine. */ 150 infof(data, "successfully set certificate verify locations:\n"); 151 } 152 infof(data, 153 " CAfile: %s\n" 154 " CApath: %s\n", 155 data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: 156 "none", 157 data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: 158 "none"); 159 } 160 161 /* Load the client certificate, and private key */ 162 if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) { 163 int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]); 164 165 if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT], 166 file_type) != 1) { 167 failf(data, "unable to use client certificate (no key or wrong pass" 168 " phrase?)"); 169 return CURLE_SSL_CONNECT_ERROR; 170 } 171 172 file_type = do_file_type(data->set.str[STRING_KEY_TYPE]); 173 if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY], 174 file_type) != 1) { 175 failf(data, "unable to set private key"); 176 return CURLE_SSL_CONNECT_ERROR; 177 } 178 } 179#else 180 if(CyaSSL_no_filesystem_verify(conssl->ctx)!= SSL_SUCCESS) { 181 return CURLE_SSL_CONNECT_ERROR; 182 } 183#endif /* NO_FILESYSTEM */ 184 185 /* SSL always tries to verify the peer, this only says whether it should 186 * fail to connect if the verification fails, or if it should continue 187 * anyway. In the latter case the result of the verification is checked with 188 * SSL_get_verify_result() below. */ 189 SSL_CTX_set_verify(conssl->ctx, 190 data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, 191 NULL); 192 193 /* Let's make an SSL structure */ 194 if(conssl->handle) 195 SSL_free(conssl->handle); 196 conssl->handle = SSL_new(conssl->ctx); 197 if(!conssl->handle) { 198 failf(data, "SSL: couldn't create a context (handle)!"); 199 return CURLE_OUT_OF_MEMORY; 200 } 201 202 /* Check if there's a cached ID we can/should use here! */ 203 if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { 204 /* we got a session id, use it! */ 205 if(!SSL_set_session(conssl->handle, ssl_sessionid)) { 206 failf(data, "SSL: SSL_set_session failed: %s", 207 ERR_error_string(SSL_get_error(conssl->handle, 0),NULL)); 208 return CURLE_SSL_CONNECT_ERROR; 209 } 210 /* Informational message */ 211 infof (data, "SSL re-using session ID\n"); 212 } 213 214 /* pass the raw socket into the SSL layer */ 215 if(!SSL_set_fd(conssl->handle, (int)sockfd)) { 216 failf(data, "SSL: SSL_set_fd failed"); 217 return CURLE_SSL_CONNECT_ERROR; 218 } 219 220 conssl->connecting_state = ssl_connect_2; 221 return CURLE_OK; 222} 223 224 225static CURLcode 226cyassl_connect_step2(struct connectdata *conn, 227 int sockindex) 228{ 229 int ret = -1; 230 struct SessionHandle *data = conn->data; 231 struct ssl_connect_data* conssl = &conn->ssl[sockindex]; 232 233 infof(data, "CyaSSL: Connecting to %s:%d\n", 234 conn->host.name, conn->remote_port); 235 236 conn->recv[sockindex] = cyassl_recv; 237 conn->send[sockindex] = cyassl_send; 238 239 ret = SSL_connect(conssl->handle); 240 if(ret != 1) { 241 char error_buffer[80]; 242 int detail = SSL_get_error(conssl->handle, ret); 243 244 if(SSL_ERROR_WANT_READ == detail) { 245 conssl->connecting_state = ssl_connect_2_reading; 246 return CURLE_OK; 247 } 248 249 if(SSL_ERROR_WANT_WRITE == detail) { 250 conssl->connecting_state = ssl_connect_2_writing; 251 return CURLE_OK; 252 } 253 254 failf(data, "SSL_connect failed with error %d: %s", detail, 255 ERR_error_string(detail, error_buffer)); 256 return CURLE_SSL_CONNECT_ERROR; 257 } 258 259 conssl->connecting_state = ssl_connect_3; 260 infof(data, "SSL connected"); 261 262 return CURLE_OK; 263} 264 265 266static CURLcode 267cyassl_connect_step3(struct connectdata *conn, 268 int sockindex) 269{ 270 CURLcode retcode = CURLE_OK; 271 void *old_ssl_sessionid=NULL; 272 struct SessionHandle *data = conn->data; 273 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 274 int incache; 275 SSL_SESSION *our_ssl_sessionid; 276 277 DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); 278 279 our_ssl_sessionid = SSL_get_session(connssl->handle); 280 281 incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); 282 if(incache) { 283 if(old_ssl_sessionid != our_ssl_sessionid) { 284 infof(data, "old SSL session ID is stale, removing\n"); 285 Curl_ssl_delsessionid(conn, old_ssl_sessionid); 286 incache = FALSE; 287 } 288 } 289 if(!incache) { 290 retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 291 0 /* unknown size */); 292 if(retcode) { 293 failf(data, "failed to store ssl session"); 294 return retcode; 295 } 296 } 297 298 connssl->connecting_state = ssl_connect_done; 299 300 return retcode; 301} 302 303 304static ssize_t cyassl_send(struct connectdata *conn, 305 int sockindex, 306 const void *mem, 307 size_t len, 308 CURLcode *curlcode) 309{ 310 char error_buffer[80]; 311 int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; 312 int rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen); 313 314 if(rc < 0) { 315 int err = SSL_get_error(conn->ssl[sockindex].handle, rc); 316 317 switch(err) { 318 case SSL_ERROR_WANT_READ: 319 case SSL_ERROR_WANT_WRITE: 320 /* there's data pending, re-invoke SSL_write() */ 321 *curlcode = CURLE_AGAIN; 322 return -1; 323 default: 324 failf(conn->data, "SSL write: %s, errno %d", 325 ERR_error_string(err, error_buffer), 326 SOCKERRNO); 327 *curlcode = CURLE_SEND_ERROR; 328 return -1; 329 } 330 } 331 return rc; 332} 333 334void Curl_cyassl_close_all(struct SessionHandle *data) 335{ 336 (void)data; 337} 338 339void Curl_cyassl_close(struct connectdata *conn, int sockindex) 340{ 341 struct ssl_connect_data *conssl = &conn->ssl[sockindex]; 342 343 if(conssl->handle) { 344 (void)SSL_shutdown(conssl->handle); 345 SSL_free (conssl->handle); 346 conssl->handle = NULL; 347 } 348 if(conssl->ctx) { 349 SSL_CTX_free (conssl->ctx); 350 conssl->ctx = NULL; 351 } 352} 353 354static ssize_t cyassl_recv(struct connectdata *conn, 355 int num, 356 char *buf, 357 size_t buffersize, 358 CURLcode *curlcode) 359{ 360 char error_buffer[80]; 361 int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize; 362 int nread = SSL_read(conn->ssl[num].handle, buf, buffsize); 363 364 if(nread < 0) { 365 int err = SSL_get_error(conn->ssl[num].handle, nread); 366 367 switch(err) { 368 case SSL_ERROR_ZERO_RETURN: /* no more data */ 369 break; 370 case SSL_ERROR_WANT_READ: 371 case SSL_ERROR_WANT_WRITE: 372 /* there's data pending, re-invoke SSL_read() */ 373 *curlcode = CURLE_AGAIN; 374 return -1; 375 default: 376 failf(conn->data, "SSL read: %s, errno %d", 377 ERR_error_string(err, error_buffer), 378 SOCKERRNO); 379 *curlcode = CURLE_RECV_ERROR; 380 return -1; 381 } 382 } 383 return nread; 384} 385 386 387void Curl_cyassl_session_free(void *ptr) 388{ 389 (void)ptr; 390 /* CyaSSL reuses sessions on own, no free */ 391} 392 393 394size_t Curl_cyassl_version(char *buffer, size_t size) 395{ 396#ifdef CYASSL_VERSION 397 return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION); 398#else 399 return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8"); 400#endif 401} 402 403 404int Curl_cyassl_init(void) 405{ 406 InitCyaSSL(); 407 408 return 1; 409} 410 411 412bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex) 413{ 414 if(conn->ssl[connindex].handle) /* SSL is in use */ 415 return (bool)(0 != SSL_pending(conn->ssl[connindex].handle)); 416 else 417 return FALSE; 418} 419 420 421/* 422 * This function is called to shut down the SSL layer but keep the 423 * socket open (CCC - Clear Command Channel) 424 */ 425int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex) 426{ 427 int retval = 0; 428 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 429 430 if(connssl->handle) { 431 SSL_free (connssl->handle); 432 connssl->handle = NULL; 433 } 434 return retval; 435} 436 437 438static CURLcode 439cyassl_connect_common(struct connectdata *conn, 440 int sockindex, 441 bool nonblocking, 442 bool *done) 443{ 444 CURLcode retcode; 445 struct SessionHandle *data = conn->data; 446 struct ssl_connect_data *connssl = &conn->ssl[sockindex]; 447 curl_socket_t sockfd = conn->sock[sockindex]; 448 long timeout_ms; 449 int what; 450 451 /* check if the connection has already been established */ 452 if(ssl_connection_complete == connssl->state) { 453 *done = TRUE; 454 return CURLE_OK; 455 } 456 457 if(ssl_connect_1==connssl->connecting_state) { 458 /* Find out how much more time we're allowed */ 459 timeout_ms = Curl_timeleft(data, NULL, TRUE); 460 461 if(timeout_ms < 0) { 462 /* no need to continue if time already is up */ 463 failf(data, "SSL connection timeout"); 464 return CURLE_OPERATION_TIMEDOUT; 465 } 466 retcode = cyassl_connect_step1(conn, sockindex); 467 if(retcode) 468 return retcode; 469 } 470 471 while(ssl_connect_2 == connssl->connecting_state || 472 ssl_connect_2_reading == connssl->connecting_state || 473 ssl_connect_2_writing == connssl->connecting_state) { 474 475 /* check allowed time left */ 476 timeout_ms = Curl_timeleft(data, NULL, TRUE); 477 478 if(timeout_ms < 0) { 479 /* no need to continue if time already is up */ 480 failf(data, "SSL connection timeout"); 481 return CURLE_OPERATION_TIMEDOUT; 482 } 483 484 /* if ssl is expecting something, check if it's available. */ 485 if(connssl->connecting_state == ssl_connect_2_reading 486 || connssl->connecting_state == ssl_connect_2_writing) { 487 488 curl_socket_t writefd = ssl_connect_2_writing== 489 connssl->connecting_state?sockfd:CURL_SOCKET_BAD; 490 curl_socket_t readfd = ssl_connect_2_reading== 491 connssl->connecting_state?sockfd:CURL_SOCKET_BAD; 492 493 what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); 494 if(what < 0) { 495 /* fatal error */ 496 failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); 497 return CURLE_SSL_CONNECT_ERROR; 498 } 499 else if(0 == what) { 500 if(nonblocking) { 501 *done = FALSE; 502 return CURLE_OK; 503 } 504 else { 505 /* timeout */ 506 failf(data, "SSL connection timeout"); 507 return CURLE_OPERATION_TIMEDOUT; 508 } 509 } 510 /* socket is readable or writable */ 511 } 512 513 /* Run transaction, and return to the caller if it failed or if 514 * this connection is part of a multi handle and this loop would 515 * execute again. This permits the owner of a multi handle to 516 * abort a connection attempt before step2 has completed while 517 * ensuring that a client using select() or epoll() will always 518 * have a valid fdset to wait on. 519 */ 520 retcode = cyassl_connect_step2(conn, sockindex); 521 if(retcode || (nonblocking && 522 (ssl_connect_2 == connssl->connecting_state || 523 ssl_connect_2_reading == connssl->connecting_state || 524 ssl_connect_2_writing == connssl->connecting_state))) 525 return retcode; 526 527 } /* repeat step2 until all transactions are done. */ 528 529 if(ssl_connect_3==connssl->connecting_state) { 530 retcode = cyassl_connect_step3(conn, sockindex); 531 if(retcode) 532 return retcode; 533 } 534 535 if(ssl_connect_done==connssl->connecting_state) { 536 connssl->state = ssl_connection_complete; 537 conn->recv[sockindex] = cyassl_recv; 538 conn->send[sockindex] = cyassl_send; 539 *done = TRUE; 540 } 541 else 542 *done = FALSE; 543 544 /* Reset our connect state machine */ 545 connssl->connecting_state = ssl_connect_1; 546 547 return CURLE_OK; 548} 549 550 551CURLcode 552Curl_cyassl_connect_nonblocking(struct connectdata *conn, 553 int sockindex, 554 bool *done) 555{ 556 return cyassl_connect_common(conn, sockindex, TRUE, done); 557} 558 559 560CURLcode 561Curl_cyassl_connect(struct connectdata *conn, 562 int sockindex) 563{ 564 CURLcode retcode; 565 bool done = FALSE; 566 567 retcode = cyassl_connect_common(conn, sockindex, FALSE, &done); 568 if(retcode) 569 return retcode; 570 571 DEBUGASSERT(done); 572 573 return CURLE_OK; 574} 575 576#endif 577