1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel (at) 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_gskit_ - prefix for GSKit ones 35 Curl_polarssl_ - prefix for PolarSSL ones 36 Curl_cyassl_ - prefix for CyaSSL ones 37 Curl_schannel_ - prefix for Schannel SSPI ones 38 Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones 39 40 Note that this source code uses curlssl_* functions, and they are all 41 defines/macros #defined by the lib-specific header files. 42 43 "SSL/TLS Strong Encryption: An Introduction" 44 http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html 45 */ 46 47 #include "curl_setup.h" 48 49 #ifdef HAVE_SYS_TYPES_H 50 #include <sys/types.h> 51 #endif 52 #ifdef HAVE_SYS_STAT_H 53 #include <sys/stat.h> 54 #endif 55 #ifdef HAVE_FCNTL_H 56 #include <fcntl.h> 57 #endif 58 59 #include "urldata.h" 60 61 #include "vtls.h" /* generic SSL protos etc */ 62 #include "slist.h" 63 #include "sendf.h" 64 #include "rawstr.h" 65 #include "url.h" 66 #include "progress.h" 67 #include "share.h" 68 #include "timeval.h" 69 #include "curl_md5.h" 70 #include "warnless.h" 71 #include "curl_base64.h" 72 #include "curl_printf.h" 73 74 /* The last #include files should be: */ 75 #include "curl_memory.h" 76 #include "memdebug.h" 77 78 /* convenience macro to check if this handle is using a shared SSL session */ 79 #define SSLSESSION_SHARED(data) (data->share && \ 80 (data->share->specifier & \ 81 (1<<CURL_LOCK_DATA_SSL_SESSION))) 82 83 static bool safe_strequal(char* str1, char* str2) 84 { 85 if(str1 && str2) 86 /* both pointers point to something then compare them */ 87 return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE; 88 else 89 /* if both pointers are NULL then treat them as equal */ 90 return (!str1 && !str2) ? TRUE : FALSE; 91 } 92 93 bool 94 Curl_ssl_config_matches(struct ssl_config_data* data, 95 struct ssl_config_data* needle) 96 { 97 if((data->version == needle->version) && 98 (data->verifypeer == needle->verifypeer) && 99 (data->verifyhost == needle->verifyhost) && 100 safe_strequal(data->CApath, needle->CApath) && 101 safe_strequal(data->CAfile, needle->CAfile) && 102 safe_strequal(data->random_file, needle->random_file) && 103 safe_strequal(data->egdsocket, needle->egdsocket) && 104 safe_strequal(data->cipher_list, needle->cipher_list)) 105 return TRUE; 106 107 return FALSE; 108 } 109 110 bool 111 Curl_clone_ssl_config(struct ssl_config_data *source, 112 struct ssl_config_data *dest) 113 { 114 dest->sessionid = source->sessionid; 115 dest->verifyhost = source->verifyhost; 116 dest->verifypeer = source->verifypeer; 117 dest->version = source->version; 118 119 if(source->CAfile) { 120 dest->CAfile = strdup(source->CAfile); 121 if(!dest->CAfile) 122 return FALSE; 123 } 124 else 125 dest->CAfile = NULL; 126 127 if(source->CApath) { 128 dest->CApath = strdup(source->CApath); 129 if(!dest->CApath) 130 return FALSE; 131 } 132 else 133 dest->CApath = NULL; 134 135 if(source->cipher_list) { 136 dest->cipher_list = strdup(source->cipher_list); 137 if(!dest->cipher_list) 138 return FALSE; 139 } 140 else 141 dest->cipher_list = NULL; 142 143 if(source->egdsocket) { 144 dest->egdsocket = strdup(source->egdsocket); 145 if(!dest->egdsocket) 146 return FALSE; 147 } 148 else 149 dest->egdsocket = NULL; 150 151 if(source->random_file) { 152 dest->random_file = strdup(source->random_file); 153 if(!dest->random_file) 154 return FALSE; 155 } 156 else 157 dest->random_file = NULL; 158 159 return TRUE; 160 } 161 162 void Curl_free_ssl_config(struct ssl_config_data* sslc) 163 { 164 Curl_safefree(sslc->CAfile); 165 Curl_safefree(sslc->CApath); 166 Curl_safefree(sslc->cipher_list); 167 Curl_safefree(sslc->egdsocket); 168 Curl_safefree(sslc->random_file); 169 } 170 171 172 /* 173 * Curl_rand() returns a random unsigned integer, 32bit. 174 * 175 * This non-SSL function is put here only because this file is the only one 176 * with knowledge of what the underlying SSL libraries provide in terms of 177 * randomizers. 178 * 179 * NOTE: 'data' may be passed in as NULL when coming from external API without 180 * easy handle! 181 * 182 */ 183 184 unsigned int Curl_rand(struct SessionHandle *data) 185 { 186 unsigned int r = 0; 187 static unsigned int randseed; 188 static bool seeded = FALSE; 189 190 #ifdef CURLDEBUG 191 char *force_entropy = getenv("CURL_ENTROPY"); 192 if(force_entropy) { 193 if(!seeded) { 194 size_t elen = strlen(force_entropy); 195 size_t clen = sizeof(randseed); 196 size_t min = elen < clen ? elen : clen; 197 memcpy((char *)&randseed, force_entropy, min); 198 seeded = TRUE; 199 } 200 else 201 randseed++; 202 return randseed; 203 } 204 #endif 205 206 /* data may be NULL! */ 207 if(!Curl_ssl_random(data, (unsigned char *)&r, sizeof(r))) 208 return r; 209 210 /* If Curl_ssl_random() returns non-zero it couldn't offer randomness and we 211 instead perform a "best effort" */ 212 213 #ifdef RANDOM_FILE 214 if(!seeded) { 215 /* if there's a random file to read a seed from, use it */ 216 int fd = open(RANDOM_FILE, O_RDONLY); 217 if(fd > -1) { 218 /* read random data into the randseed variable */ 219 ssize_t nread = read(fd, &randseed, sizeof(randseed)); 220 if(nread == sizeof(randseed)) 221 seeded = TRUE; 222 close(fd); 223 } 224 } 225 #endif 226 227 if(!seeded) { 228 struct timeval now = curlx_tvnow(); 229 infof(data, "WARNING: Using weak random seed\n"); 230 randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; 231 randseed = randseed * 1103515245 + 12345; 232 randseed = randseed * 1103515245 + 12345; 233 randseed = randseed * 1103515245 + 12345; 234 seeded = TRUE; 235 } 236 237 /* Return an unsigned 32-bit pseudo-random number. */ 238 r = randseed = randseed * 1103515245 + 12345; 239 return (r << 16) | ((r >> 16) & 0xFFFF); 240 } 241 242 int Curl_ssl_backend(void) 243 { 244 return (int)CURL_SSL_BACKEND; 245 } 246 247 #ifdef USE_SSL 248 249 /* "global" init done? */ 250 static bool init_ssl=FALSE; 251 252 /** 253 * Global SSL init 254 * 255 * @retval 0 error initializing SSL 256 * @retval 1 SSL initialized successfully 257 */ 258 int Curl_ssl_init(void) 259 { 260 /* make sure this is only done once */ 261 if(init_ssl) 262 return 1; 263 init_ssl = TRUE; /* never again */ 264 265 return curlssl_init(); 266 } 267 268 269 /* Global cleanup */ 270 void Curl_ssl_cleanup(void) 271 { 272 if(init_ssl) { 273 /* only cleanup if we did a previous init */ 274 curlssl_cleanup(); 275 init_ssl = FALSE; 276 } 277 } 278 279 static bool ssl_prefs_check(struct SessionHandle *data) 280 { 281 /* check for CURLOPT_SSLVERSION invalid parameter value */ 282 if((data->set.ssl.version < 0) 283 || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) { 284 failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); 285 return FALSE; 286 } 287 return TRUE; 288 } 289 290 CURLcode 291 Curl_ssl_connect(struct connectdata *conn, int sockindex) 292 { 293 CURLcode result; 294 295 if(!ssl_prefs_check(conn->data)) 296 return CURLE_SSL_CONNECT_ERROR; 297 298 /* mark this is being ssl-enabled from here on. */ 299 conn->ssl[sockindex].use = TRUE; 300 conn->ssl[sockindex].state = ssl_connection_negotiating; 301 302 result = curlssl_connect(conn, sockindex); 303 304 if(!result) 305 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ 306 307 return result; 308 } 309 310 CURLcode 311 Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, 312 bool *done) 313 { 314 CURLcode result; 315 316 if(!ssl_prefs_check(conn->data)) 317 return CURLE_SSL_CONNECT_ERROR; 318 319 /* mark this is being ssl requested from here on. */ 320 conn->ssl[sockindex].use = TRUE; 321 #ifdef curlssl_connect_nonblocking 322 result = curlssl_connect_nonblocking(conn, sockindex, done); 323 #else 324 *done = TRUE; /* fallback to BLOCKING */ 325 result = curlssl_connect(conn, sockindex); 326 #endif /* non-blocking connect support */ 327 if(!result && *done) 328 Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ 329 return result; 330 } 331 332 /* 333 * Check if there's a session ID for the given connection in the cache, and if 334 * there's one suitable, it is provided. Returns TRUE when no entry matched. 335 */ 336 bool Curl_ssl_getsessionid(struct connectdata *conn, 337 void **ssl_sessionid, 338 size_t *idsize) /* set 0 if unknown */ 339 { 340 struct curl_ssl_session *check; 341 struct SessionHandle *data = conn->data; 342 size_t i; 343 long *general_age; 344 bool no_match = TRUE; 345 346 *ssl_sessionid = NULL; 347 348 if(!conn->ssl_config.sessionid) 349 /* session ID re-use is disabled */ 350 return TRUE; 351 352 /* Lock if shared */ 353 if(SSLSESSION_SHARED(data)) { 354 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); 355 general_age = &data->share->sessionage; 356 } 357 else 358 general_age = &data->state.sessionage; 359 360 for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { 361 check = &data->state.session[i]; 362 if(!check->sessionid) 363 /* not session ID means blank entry */ 364 continue; 365 if(Curl_raw_equal(conn->host.name, check->name) && 366 (conn->remote_port == check->remote_port) && 367 Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { 368 /* yes, we have a session ID! */ 369 (*general_age)++; /* increase general age */ 370 check->age = *general_age; /* set this as used in this age */ 371 *ssl_sessionid = check->sessionid; 372 if(idsize) 373 *idsize = check->idsize; 374 no_match = FALSE; 375 break; 376 } 377 } 378 379 /* Unlock */ 380 if(SSLSESSION_SHARED(data)) 381 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); 382 383 return no_match; 384 } 385 386 /* 387 * Kill a single session ID entry in the cache. 388 */ 389 void Curl_ssl_kill_session(struct curl_ssl_session *session) 390 { 391 if(session->sessionid) { 392 /* defensive check */ 393 394 /* free the ID the SSL-layer specific way */ 395 curlssl_session_free(session->sessionid); 396 397 session->sessionid = NULL; 398 session->age = 0; /* fresh */ 399 400 Curl_free_ssl_config(&session->ssl_config); 401 402 Curl_safefree(session->name); 403 } 404 } 405 406 /* 407 * Delete the given session ID from the cache. 408 */ 409 void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) 410 { 411 size_t i; 412 struct SessionHandle *data=conn->data; 413 414 if(SSLSESSION_SHARED(data)) 415 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); 416 417 for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { 418 struct curl_ssl_session *check = &data->state.session[i]; 419 420 if(check->sessionid == ssl_sessionid) { 421 Curl_ssl_kill_session(check); 422 break; 423 } 424 } 425 426 if(SSLSESSION_SHARED(data)) 427 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); 428 } 429 430 /* 431 * Store session id in the session cache. The ID passed on to this function 432 * must already have been extracted and allocated the proper way for the SSL 433 * layer. Curl_XXXX_session_free() will be called to free/kill the session ID 434 * later on. 435 */ 436 CURLcode Curl_ssl_addsessionid(struct connectdata *conn, 437 void *ssl_sessionid, 438 size_t idsize) 439 { 440 size_t i; 441 struct SessionHandle *data=conn->data; /* the mother of all structs */ 442 struct curl_ssl_session *store = &data->state.session[0]; 443 long oldest_age=data->state.session[0].age; /* zero if unused */ 444 char *clone_host; 445 long *general_age; 446 447 /* Even though session ID re-use might be disabled, that only disables USING 448 IT. We still store it here in case the re-using is again enabled for an 449 upcoming transfer */ 450 451 clone_host = strdup(conn->host.name); 452 if(!clone_host) 453 return CURLE_OUT_OF_MEMORY; /* bail out */ 454 455 /* Now we should add the session ID and the host name to the cache, (remove 456 the oldest if necessary) */ 457 458 /* If using shared SSL session, lock! */ 459 if(SSLSESSION_SHARED(data)) { 460 Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); 461 general_age = &data->share->sessionage; 462 } 463 else { 464 general_age = &data->state.sessionage; 465 } 466 467 /* find an empty slot for us, or find the oldest */ 468 for(i = 1; (i < data->set.ssl.max_ssl_sessions) && 469 data->state.session[i].sessionid; i++) { 470 if(data->state.session[i].age < oldest_age) { 471 oldest_age = data->state.session[i].age; 472 store = &data->state.session[i]; 473 } 474 } 475 if(i == data->set.ssl.max_ssl_sessions) 476 /* cache is full, we must "kill" the oldest entry! */ 477 Curl_ssl_kill_session(store); 478 else 479 store = &data->state.session[i]; /* use this slot */ 480 481 /* now init the session struct wisely */ 482 store->sessionid = ssl_sessionid; 483 store->idsize = idsize; 484 store->age = *general_age; /* set current age */ 485 /* free it if there's one already present */ 486 free(store->name); 487 store->name = clone_host; /* clone host name */ 488 store->remote_port = conn->remote_port; /* port number */ 489 490 491 /* Unlock */ 492 if(SSLSESSION_SHARED(data)) 493 Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); 494 495 if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { 496 store->sessionid = NULL; /* let caller free sessionid */ 497 free(clone_host); 498 return CURLE_OUT_OF_MEMORY; 499 } 500 501 return CURLE_OK; 502 } 503 504 505 void Curl_ssl_close_all(struct SessionHandle *data) 506 { 507 size_t i; 508 /* kill the session ID cache if not shared */ 509 if(data->state.session && !SSLSESSION_SHARED(data)) { 510 for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) 511 /* the single-killer function handles empty table slots */ 512 Curl_ssl_kill_session(&data->state.session[i]); 513 514 /* free the cache data */ 515 Curl_safefree(data->state.session); 516 } 517 518 curlssl_close_all(data); 519 } 520 521 void Curl_ssl_close(struct connectdata *conn, int sockindex) 522 { 523 DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); 524 curlssl_close(conn, sockindex); 525 } 526 527 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) 528 { 529 if(curlssl_shutdown(conn, sockindex)) 530 return CURLE_SSL_SHUTDOWN_FAILED; 531 532 conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */ 533 conn->ssl[sockindex].state = ssl_connection_none; 534 535 conn->recv[sockindex] = Curl_recv_plain; 536 conn->send[sockindex] = Curl_send_plain; 537 538 return CURLE_OK; 539 } 540 541 /* Selects an SSL crypto engine 542 */ 543 CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) 544 { 545 return curlssl_set_engine(data, engine); 546 } 547 548 /* Selects the default SSL crypto engine 549 */ 550 CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) 551 { 552 return curlssl_set_engine_default(data); 553 } 554 555 /* Return list of OpenSSL crypto engine names. */ 556 struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) 557 { 558 return curlssl_engines_list(data); 559 } 560 561 /* 562 * This sets up a session ID cache to the specified size. Make sure this code 563 * is agnostic to what underlying SSL technology we use. 564 */ 565 CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount) 566 { 567 struct curl_ssl_session *session; 568 569 if(data->state.session) 570 /* this is just a precaution to prevent multiple inits */ 571 return CURLE_OK; 572 573 session = calloc(amount, sizeof(struct curl_ssl_session)); 574 if(!session) 575 return CURLE_OUT_OF_MEMORY; 576 577 /* store the info in the SSL section */ 578 data->set.ssl.max_ssl_sessions = amount; 579 data->state.session = session; 580 data->state.sessionage = 1; /* this is brand new */ 581 return CURLE_OK; 582 } 583 584 size_t Curl_ssl_version(char *buffer, size_t size) 585 { 586 return curlssl_version(buffer, size); 587 } 588 589 /* 590 * This function tries to determine connection status. 591 * 592 * Return codes: 593 * 1 means the connection is still in place 594 * 0 means the connection has been closed 595 * -1 means the connection status is unknown 596 */ 597 int Curl_ssl_check_cxn(struct connectdata *conn) 598 { 599 return curlssl_check_cxn(conn); 600 } 601 602 bool Curl_ssl_data_pending(const struct connectdata *conn, 603 int connindex) 604 { 605 return curlssl_data_pending(conn, connindex); 606 } 607 608 void Curl_ssl_free_certinfo(struct SessionHandle *data) 609 { 610 int i; 611 struct curl_certinfo *ci = &data->info.certs; 612 613 if(ci->num_of_certs) { 614 /* free all individual lists used */ 615 for(i=0; i<ci->num_of_certs; i++) { 616 curl_slist_free_all(ci->certinfo[i]); 617 ci->certinfo[i] = NULL; 618 } 619 620 free(ci->certinfo); /* free the actual array too */ 621 ci->certinfo = NULL; 622 ci->num_of_certs = 0; 623 } 624 } 625 626 CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num) 627 { 628 struct curl_certinfo *ci = &data->info.certs; 629 struct curl_slist **table; 630 631 /* Free any previous certificate information structures */ 632 Curl_ssl_free_certinfo(data); 633 634 /* Allocate the required certificate information structures */ 635 table = calloc((size_t) num, sizeof(struct curl_slist *)); 636 if(!table) 637 return CURLE_OUT_OF_MEMORY; 638 639 ci->num_of_certs = num; 640 ci->certinfo = table; 641 642 return CURLE_OK; 643 } 644 645 /* 646 * 'value' is NOT a zero terminated string 647 */ 648 CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, 649 int certnum, 650 const char *label, 651 const char *value, 652 size_t valuelen) 653 { 654 struct curl_certinfo * ci = &data->info.certs; 655 char * output; 656 struct curl_slist * nl; 657 CURLcode result = CURLE_OK; 658 size_t labellen = strlen(label); 659 size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ 660 661 output = malloc(outlen); 662 if(!output) 663 return CURLE_OUT_OF_MEMORY; 664 665 /* sprintf the label and colon */ 666 snprintf(output, outlen, "%s:", label); 667 668 /* memcpy the value (it might not be zero terminated) */ 669 memcpy(&output[labellen+1], value, valuelen); 670 671 /* zero terminate the output */ 672 output[labellen + 1 + valuelen] = 0; 673 674 nl = Curl_slist_append_nodup(ci->certinfo[certnum], output); 675 if(!nl) { 676 free(output); 677 curl_slist_free_all(ci->certinfo[certnum]); 678 result = CURLE_OUT_OF_MEMORY; 679 } 680 681 ci->certinfo[certnum] = nl; 682 return result; 683 } 684 685 /* 686 * This is a convenience function for push_certinfo_len that takes a zero 687 * terminated value. 688 */ 689 CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data, 690 int certnum, 691 const char *label, 692 const char *value) 693 { 694 size_t valuelen = strlen(value); 695 696 return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); 697 } 698 699 int Curl_ssl_random(struct SessionHandle *data, 700 unsigned char *entropy, 701 size_t length) 702 { 703 return curlssl_random(data, entropy, length); 704 } 705 706 /* 707 * Public key pem to der conversion 708 */ 709 710 static CURLcode pubkey_pem_to_der(const char *pem, 711 unsigned char **der, size_t *der_len) 712 { 713 char *stripped_pem, *begin_pos, *end_pos; 714 size_t pem_count, stripped_pem_count = 0, pem_len; 715 CURLcode result; 716 717 /* if no pem, exit. */ 718 if(!pem) 719 return CURLE_BAD_CONTENT_ENCODING; 720 721 begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----"); 722 if(!begin_pos) 723 return CURLE_BAD_CONTENT_ENCODING; 724 725 pem_count = begin_pos - pem; 726 /* Invalid if not at beginning AND not directly following \n */ 727 if(0 != pem_count && '\n' != pem[pem_count - 1]) 728 return CURLE_BAD_CONTENT_ENCODING; 729 730 /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ 731 pem_count += 26; 732 733 /* Invalid if not directly following \n */ 734 end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----"); 735 if(!end_pos) 736 return CURLE_BAD_CONTENT_ENCODING; 737 738 pem_len = end_pos - pem; 739 740 stripped_pem = malloc(pem_len - pem_count + 1); 741 if(!stripped_pem) 742 return CURLE_OUT_OF_MEMORY; 743 744 /* 745 * Here we loop through the pem array one character at a time between the 746 * correct indices, and place each character that is not '\n' or '\r' 747 * into the stripped_pem array, which should represent the raw base64 string 748 */ 749 while(pem_count < pem_len) { 750 if('\n' != pem[pem_count] && '\r' != pem[pem_count]) 751 stripped_pem[stripped_pem_count++] = pem[pem_count]; 752 ++pem_count; 753 } 754 /* Place the null terminator in the correct place */ 755 stripped_pem[stripped_pem_count] = '\0'; 756 757 result = Curl_base64_decode(stripped_pem, der, der_len); 758 759 Curl_safefree(stripped_pem); 760 761 return result; 762 } 763 764 /* 765 * Generic pinned public key check. 766 */ 767 768 CURLcode Curl_pin_peer_pubkey(const char *pinnedpubkey, 769 const unsigned char *pubkey, size_t pubkeylen) 770 { 771 FILE *fp; 772 unsigned char *buf = NULL, *pem_ptr = NULL; 773 long filesize; 774 size_t size, pem_len; 775 CURLcode pem_read; 776 CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; 777 778 /* if a path wasn't specified, don't pin */ 779 if(!pinnedpubkey) 780 return CURLE_OK; 781 if(!pubkey || !pubkeylen) 782 return result; 783 fp = fopen(pinnedpubkey, "rb"); 784 if(!fp) 785 return result; 786 787 do { 788 /* Determine the file's size */ 789 if(fseek(fp, 0, SEEK_END)) 790 break; 791 filesize = ftell(fp); 792 if(fseek(fp, 0, SEEK_SET)) 793 break; 794 if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE) 795 break; 796 797 /* 798 * if the size of our certificate is bigger than the file 799 * size then it can't match 800 */ 801 size = curlx_sotouz((curl_off_t) filesize); 802 if(pubkeylen > size) 803 break; 804 805 /* 806 * Allocate buffer for the pinned key 807 * With 1 additional byte for null terminator in case of PEM key 808 */ 809 buf = malloc(size + 1); 810 if(!buf) 811 break; 812 813 /* Returns number of elements read, which should be 1 */ 814 if((int) fread(buf, size, 1, fp) != 1) 815 break; 816 817 /* If the sizes are the same, it can't be base64 encoded, must be der */ 818 if(pubkeylen == size) { 819 if(!memcmp(pubkey, buf, pubkeylen)) 820 result = CURLE_OK; 821 break; 822 } 823 824 /* 825 * Otherwise we will assume it's PEM and try to decode it 826 * after placing null terminator 827 */ 828 buf[size] = '\0'; 829 pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len); 830 /* if it wasn't read successfully, exit */ 831 if(pem_read) 832 break; 833 834 /* 835 * if the size of our certificate doesn't match the size of 836 * the decoded file, they can't be the same, otherwise compare 837 */ 838 if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen)) 839 result = CURLE_OK; 840 } while(0); 841 842 Curl_safefree(buf); 843 Curl_safefree(pem_ptr); 844 fclose(fp); 845 846 return result; 847 } 848 849 #ifndef CURL_DISABLE_CRYPTO_AUTH 850 CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ 851 size_t tmplen, 852 unsigned char *md5sum, /* output */ 853 size_t md5len) 854 { 855 #ifdef curlssl_md5sum 856 curlssl_md5sum(tmp, tmplen, md5sum, md5len); 857 #else 858 MD5_context *MD5pw; 859 860 (void) md5len; 861 862 MD5pw = Curl_MD5_init(Curl_DIGEST_MD5); 863 if(!MD5pw) 864 return CURLE_OUT_OF_MEMORY; 865 Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen)); 866 Curl_MD5_final(MD5pw, md5sum); 867 #endif 868 return CURLE_OK; 869 } 870 #endif 871 872 /* 873 * Check whether the SSL backend supports the status_request extension. 874 */ 875 bool Curl_ssl_cert_status_request(void) 876 { 877 #ifdef curlssl_cert_status_request 878 return curlssl_cert_status_request(); 879 #else 880 return FALSE; 881 #endif 882 } 883 884 /* 885 * Check whether the SSL backend supports false start. 886 */ 887 bool Curl_ssl_false_start(void) 888 { 889 #ifdef curlssl_false_start 890 return curlssl_false_start(); 891 #else 892 return FALSE; 893 #endif 894 } 895 896 #endif /* USE_SSL */ 897