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