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