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