1 /* apps/s_time.c */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #define NO_SHUTDOWN 60 61 /*----------------------------------------- 62 s_time - SSL client connection timer program 63 Written and donated by Larry Streepy <streepy@healthcare.com> 64 -----------------------------------------*/ 65 66 #include <stdio.h> 67 #include <stdlib.h> 68 #include <string.h> 69 70 #define USE_SOCKETS 71 #include "apps.h" 72 #ifdef OPENSSL_NO_STDIO 73 #define APPS_WIN16 74 #endif 75 #include <openssl/x509.h> 76 #include <openssl/ssl.h> 77 #include <openssl/pem.h> 78 #include "s_apps.h" 79 #include <openssl/err.h> 80 #ifdef WIN32_STUFF 81 #include "winmain.h" 82 #include "wintext.h" 83 #endif 84 #if !defined(OPENSSL_SYS_MSDOS) 85 #include OPENSSL_UNISTD 86 #endif 87 88 #if !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VXWORKS) && (!defined(OPENSSL_SYS_VMS) || defined(__DECC)) 89 #define TIMES 90 #endif 91 92 #ifndef _IRIX 93 #include <time.h> 94 #endif 95 #ifdef TIMES 96 #include <sys/types.h> 97 #include <sys/times.h> 98 #endif 99 100 /* Depending on the VMS version, the tms structure is perhaps defined. 101 The __TMS macro will show if it was. If it wasn't defined, we should 102 undefine TIMES, since that tells the rest of the program how things 103 should be handled. -- Richard Levitte */ 104 #if defined(OPENSSL_SYS_VMS_DECC) && !defined(__TMS) 105 #undef TIMES 106 #endif 107 108 #if !defined(TIMES) && !defined(OPENSSL_SYS_VXWORKS) 109 #include <sys/timeb.h> 110 #endif 111 112 #if defined(sun) || defined(__ultrix) 113 #define _POSIX_SOURCE 114 #include <limits.h> 115 #include <sys/param.h> 116 #endif 117 118 /* The following if from times(3) man page. It may need to be changed 119 */ 120 #ifndef HZ 121 # ifdef _SC_CLK_TCK 122 # define HZ ((double)sysconf(_SC_CLK_TCK)) 123 # else 124 # ifndef CLK_TCK 125 # ifndef _BSD_CLK_TCK_ /* FreeBSD hack */ 126 # define HZ 100.0 127 # else /* _BSD_CLK_TCK_ */ 128 # define HZ ((double)_BSD_CLK_TCK_) 129 # endif 130 # else /* CLK_TCK */ 131 # define HZ ((double)CLK_TCK) 132 # endif 133 # endif 134 #endif 135 136 #undef PROG 137 #define PROG s_time_main 138 139 #undef ioctl 140 #define ioctl ioctlsocket 141 142 #define SSL_CONNECT_NAME "localhost:4433" 143 144 /*#define TEST_CERT "client.pem" */ /* no default cert. */ 145 146 #undef BUFSIZZ 147 #define BUFSIZZ 1024*10 148 149 #define MYBUFSIZ 1024*8 150 151 #undef min 152 #undef max 153 #define min(a,b) (((a) < (b)) ? (a) : (b)) 154 #define max(a,b) (((a) > (b)) ? (a) : (b)) 155 156 #undef SECONDS 157 #define SECONDS 30 158 extern int verify_depth; 159 extern int verify_error; 160 161 static void s_time_usage(void); 162 static int parseArgs( int argc, char **argv ); 163 static SSL *doConnection( SSL *scon ); 164 static void s_time_init(void); 165 166 /*********************************************************************** 167 * Static data declarations 168 */ 169 170 /* static char *port=PORT_STR;*/ 171 static char *host=SSL_CONNECT_NAME; 172 static char *t_cert_file=NULL; 173 static char *t_key_file=NULL; 174 static char *CApath=NULL; 175 static char *CAfile=NULL; 176 static char *tm_cipher=NULL; 177 static int tm_verify = SSL_VERIFY_NONE; 178 static int maxTime = SECONDS; 179 static SSL_CTX *tm_ctx=NULL; 180 static SSL_METHOD *s_time_meth=NULL; 181 static char *s_www_path=NULL; 182 static long bytes_read=0; 183 static int st_bugs=0; 184 static int perform=0; 185 #ifdef FIONBIO 186 static int t_nbio=0; 187 #endif 188 #ifdef OPENSSL_SYS_WIN32 189 static int exitNow = 0; /* Set when it's time to exit main */ 190 #endif 191 192 static void s_time_init(void) 193 { 194 host=SSL_CONNECT_NAME; 195 t_cert_file=NULL; 196 t_key_file=NULL; 197 CApath=NULL; 198 CAfile=NULL; 199 tm_cipher=NULL; 200 tm_verify = SSL_VERIFY_NONE; 201 maxTime = SECONDS; 202 tm_ctx=NULL; 203 s_time_meth=NULL; 204 s_www_path=NULL; 205 bytes_read=0; 206 st_bugs=0; 207 perform=0; 208 209 #ifdef FIONBIO 210 t_nbio=0; 211 #endif 212 #ifdef OPENSSL_SYS_WIN32 213 exitNow = 0; /* Set when it's time to exit main */ 214 #endif 215 } 216 217 /*********************************************************************** 218 * usage - display usage message 219 */ 220 static void s_time_usage(void) 221 { 222 static char umsg[] = "\ 223 -time arg - max number of seconds to collect data, default %d\n\ 224 -verify arg - turn on peer certificate verification, arg == depth\n\ 225 -cert arg - certificate file to use, PEM format assumed\n\ 226 -key arg - RSA file to use, PEM format assumed, key is in cert file\n\ 227 file if not specified by this option\n\ 228 -CApath arg - PEM format directory of CA's\n\ 229 -CAfile arg - PEM format file of CA's\n\ 230 -cipher - preferred cipher to use, play with 'openssl ciphers'\n\n"; 231 232 printf( "usage: s_time <args>\n\n" ); 233 234 printf("-connect host:port - host:port to connect to (default is %s)\n",SSL_CONNECT_NAME); 235 #ifdef FIONBIO 236 printf("-nbio - Run with non-blocking IO\n"); 237 printf("-ssl2 - Just use SSLv2\n"); 238 printf("-ssl3 - Just use SSLv3\n"); 239 printf("-bugs - Turn on SSL bug compatibility\n"); 240 printf("-new - Just time new connections\n"); 241 printf("-reuse - Just time connection reuse\n"); 242 printf("-www page - Retrieve 'page' from the site\n"); 243 #endif 244 printf( umsg,SECONDS ); 245 } 246 247 /*********************************************************************** 248 * parseArgs - Parse command line arguments and initialize data 249 * 250 * Returns 0 if ok, -1 on bad args 251 */ 252 static int parseArgs(int argc, char **argv) 253 { 254 int badop = 0; 255 256 verify_depth=0; 257 verify_error=X509_V_OK; 258 259 argc--; 260 argv++; 261 262 while (argc >= 1) { 263 if (strcmp(*argv,"-connect") == 0) 264 { 265 if (--argc < 1) goto bad; 266 host= *(++argv); 267 } 268 #if 0 269 else if( strcmp(*argv,"-host") == 0) 270 { 271 if (--argc < 1) goto bad; 272 host= *(++argv); 273 } 274 else if( strcmp(*argv,"-port") == 0) 275 { 276 if (--argc < 1) goto bad; 277 port= *(++argv); 278 } 279 #endif 280 else if (strcmp(*argv,"-reuse") == 0) 281 perform=2; 282 else if (strcmp(*argv,"-new") == 0) 283 perform=1; 284 else if( strcmp(*argv,"-verify") == 0) { 285 286 tm_verify=SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE; 287 if (--argc < 1) goto bad; 288 verify_depth=atoi(*(++argv)); 289 BIO_printf(bio_err,"verify depth is %d\n",verify_depth); 290 291 } else if( strcmp(*argv,"-cert") == 0) { 292 293 if (--argc < 1) goto bad; 294 t_cert_file= *(++argv); 295 296 } else if( strcmp(*argv,"-key") == 0) { 297 298 if (--argc < 1) goto bad; 299 t_key_file= *(++argv); 300 301 } else if( strcmp(*argv,"-CApath") == 0) { 302 303 if (--argc < 1) goto bad; 304 CApath= *(++argv); 305 306 } else if( strcmp(*argv,"-CAfile") == 0) { 307 308 if (--argc < 1) goto bad; 309 CAfile= *(++argv); 310 311 } else if( strcmp(*argv,"-cipher") == 0) { 312 313 if (--argc < 1) goto bad; 314 tm_cipher= *(++argv); 315 } 316 #ifdef FIONBIO 317 else if(strcmp(*argv,"-nbio") == 0) { 318 t_nbio=1; 319 } 320 #endif 321 else if(strcmp(*argv,"-www") == 0) 322 { 323 if (--argc < 1) goto bad; 324 s_www_path= *(++argv); 325 if(strlen(s_www_path) > MYBUFSIZ-100) 326 { 327 BIO_printf(bio_err,"-www option too long\n"); 328 badop=1; 329 } 330 } 331 else if(strcmp(*argv,"-bugs") == 0) 332 st_bugs=1; 333 #ifndef OPENSSL_NO_SSL2 334 else if(strcmp(*argv,"-ssl2") == 0) 335 s_time_meth=SSLv2_client_method(); 336 #endif 337 #ifndef OPENSSL_NO_SSL3 338 else if(strcmp(*argv,"-ssl3") == 0) 339 s_time_meth=SSLv3_client_method(); 340 #endif 341 else if( strcmp(*argv,"-time") == 0) { 342 343 if (--argc < 1) goto bad; 344 maxTime= atoi(*(++argv)); 345 } 346 else { 347 BIO_printf(bio_err,"unknown option %s\n",*argv); 348 badop=1; 349 break; 350 } 351 352 argc--; 353 argv++; 354 } 355 356 if (perform == 0) perform=3; 357 358 if(badop) { 359 bad: 360 s_time_usage(); 361 return -1; 362 } 363 364 return 0; /* Valid args */ 365 } 366 367 /*********************************************************************** 368 * TIME - time functions 369 */ 370 #define START 0 371 #define STOP 1 372 373 static double tm_Time_F(int s) 374 { 375 static double ret; 376 #ifdef TIMES 377 static struct tms tstart,tend; 378 379 if(s == START) { 380 times(&tstart); 381 return(0); 382 } else { 383 times(&tend); 384 ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ; 385 return((ret == 0.0)?1e-6:ret); 386 } 387 #elif defined(OPENSSL_SYS_VXWORKS) 388 { 389 static unsigned long tick_start, tick_end; 390 391 if( s == START ) 392 { 393 tick_start = tickGet(); 394 return 0; 395 } 396 else 397 { 398 tick_end = tickGet(); 399 ret = (double)(tick_end - tick_start) / (double)sysClkRateGet(); 400 return((ret == 0.0)?1e-6:ret); 401 } 402 } 403 #else /* !times() */ 404 static struct timeb tstart,tend; 405 long i; 406 407 if(s == START) { 408 ftime(&tstart); 409 return(0); 410 } else { 411 ftime(&tend); 412 i=(long)tend.millitm-(long)tstart.millitm; 413 ret=((double)(tend.time-tstart.time))+((double)i)/1000.0; 414 return((ret == 0.0)?1e-6:ret); 415 } 416 #endif 417 } 418 419 /*********************************************************************** 420 * MAIN - main processing area for client 421 * real name depends on MONOLITH 422 */ 423 int MAIN(int, char **); 424 425 int MAIN(int argc, char **argv) 426 { 427 double totalTime = 0.0; 428 int nConn = 0; 429 SSL *scon=NULL; 430 long finishtime=0; 431 int ret=1,i; 432 MS_STATIC char buf[1024*8]; 433 int ver; 434 435 apps_startup(); 436 s_time_init(); 437 438 if (bio_err == NULL) 439 bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); 440 441 #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) 442 s_time_meth=SSLv23_client_method(); 443 #elif !defined(OPENSSL_NO_SSL3) 444 s_time_meth=SSLv3_client_method(); 445 #elif !defined(OPENSSL_NO_SSL2) 446 s_time_meth=SSLv2_client_method(); 447 #endif 448 449 /* parse the command line arguments */ 450 if( parseArgs( argc, argv ) < 0 ) 451 goto end; 452 453 OpenSSL_add_ssl_algorithms(); 454 if ((tm_ctx=SSL_CTX_new(s_time_meth)) == NULL) return(1); 455 456 SSL_CTX_set_quiet_shutdown(tm_ctx,1); 457 458 if (st_bugs) SSL_CTX_set_options(tm_ctx,SSL_OP_ALL); 459 SSL_CTX_set_cipher_list(tm_ctx,tm_cipher); 460 if(!set_cert_stuff(tm_ctx,t_cert_file,t_key_file)) 461 goto end; 462 463 SSL_load_error_strings(); 464 465 if ((!SSL_CTX_load_verify_locations(tm_ctx,CAfile,CApath)) || 466 (!SSL_CTX_set_default_verify_paths(tm_ctx))) 467 { 468 /* BIO_printf(bio_err,"error setting default verify locations\n"); */ 469 ERR_print_errors(bio_err); 470 /* goto end; */ 471 } 472 473 if (tm_cipher == NULL) 474 tm_cipher = getenv("SSL_CIPHER"); 475 476 if (tm_cipher == NULL ) { 477 fprintf( stderr, "No CIPHER specified\n" ); 478 } 479 480 if (!(perform & 1)) goto next; 481 printf( "Collecting connection statistics for %d seconds\n", maxTime ); 482 483 /* Loop and time how long it takes to make connections */ 484 485 bytes_read=0; 486 finishtime=(long)time(NULL)+maxTime; 487 tm_Time_F(START); 488 for (;;) 489 { 490 if (finishtime < (long)time(NULL)) break; 491 #ifdef WIN32_STUFF 492 493 if( flushWinMsgs(0) == -1 ) 494 goto end; 495 496 if( waitingToDie || exitNow ) /* we're dead */ 497 goto end; 498 #endif 499 500 if( (scon = doConnection( NULL )) == NULL ) 501 goto end; 502 503 if (s_www_path != NULL) 504 { 505 BIO_snprintf(buf,sizeof buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 506 SSL_write(scon,buf,strlen(buf)); 507 while ((i=SSL_read(scon,buf,sizeof(buf))) > 0) 508 bytes_read+=i; 509 } 510 511 #ifdef NO_SHUTDOWN 512 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 513 #else 514 SSL_shutdown(scon); 515 #endif 516 SHUTDOWN2(SSL_get_fd(scon)); 517 518 nConn += 1; 519 if (SSL_session_reused(scon)) 520 ver='r'; 521 else 522 { 523 ver=SSL_version(scon); 524 if (ver == TLS1_VERSION) 525 ver='t'; 526 else if (ver == SSL3_VERSION) 527 ver='3'; 528 else if (ver == SSL2_VERSION) 529 ver='2'; 530 else 531 ver='*'; 532 } 533 fputc(ver,stdout); 534 fflush(stdout); 535 536 SSL_free( scon ); 537 scon=NULL; 538 } 539 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 540 541 i=(int)((long)time(NULL)-finishtime+maxTime); 542 printf( "\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn/totalTime),bytes_read); 543 printf( "%d connections in %ld real seconds, %ld bytes read per connection\n",nConn,(long)time(NULL)-finishtime+maxTime,bytes_read/nConn); 544 545 /* Now loop and time connections using the same session id over and over */ 546 547 next: 548 if (!(perform & 2)) goto end; 549 printf( "\n\nNow timing with session id reuse.\n" ); 550 551 /* Get an SSL object so we can reuse the session id */ 552 if( (scon = doConnection( NULL )) == NULL ) 553 { 554 fprintf( stderr, "Unable to get connection\n" ); 555 goto end; 556 } 557 558 if (s_www_path != NULL) 559 { 560 BIO_snprintf(buf,sizeof buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 561 SSL_write(scon,buf,strlen(buf)); 562 while (SSL_read(scon,buf,sizeof(buf)) > 0) 563 ; 564 } 565 #ifdef NO_SHUTDOWN 566 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 567 #else 568 SSL_shutdown(scon); 569 #endif 570 SHUTDOWN2(SSL_get_fd(scon)); 571 572 nConn = 0; 573 totalTime = 0.0; 574 575 finishtime=(long)time(NULL)+maxTime; 576 577 printf( "starting\n" ); 578 bytes_read=0; 579 tm_Time_F(START); 580 581 for (;;) 582 { 583 if (finishtime < (long)time(NULL)) break; 584 585 #ifdef WIN32_STUFF 586 if( flushWinMsgs(0) == -1 ) 587 goto end; 588 589 if( waitingToDie || exitNow ) /* we're dead */ 590 goto end; 591 #endif 592 593 if( (doConnection( scon )) == NULL ) 594 goto end; 595 596 if (s_www_path) 597 { 598 BIO_snprintf(buf,sizeof buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 599 SSL_write(scon,buf,strlen(buf)); 600 while ((i=SSL_read(scon,buf,sizeof(buf))) > 0) 601 bytes_read+=i; 602 } 603 604 #ifdef NO_SHUTDOWN 605 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 606 #else 607 SSL_shutdown(scon); 608 #endif 609 SHUTDOWN2(SSL_get_fd(scon)); 610 611 nConn += 1; 612 if (SSL_session_reused(scon)) 613 ver='r'; 614 else 615 { 616 ver=SSL_version(scon); 617 if (ver == TLS1_VERSION) 618 ver='t'; 619 else if (ver == SSL3_VERSION) 620 ver='3'; 621 else if (ver == SSL2_VERSION) 622 ver='2'; 623 else 624 ver='*'; 625 } 626 fputc(ver,stdout); 627 fflush(stdout); 628 } 629 totalTime += tm_Time_F(STOP); /* Add the time for this iteration*/ 630 631 632 printf( "\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn/totalTime),bytes_read); 633 printf( "%d connections in %ld real seconds, %ld bytes read per connection\n",nConn,(long)time(NULL)-finishtime+maxTime,bytes_read/nConn); 634 635 ret=0; 636 end: 637 if (scon != NULL) SSL_free(scon); 638 639 if (tm_ctx != NULL) 640 { 641 SSL_CTX_free(tm_ctx); 642 tm_ctx=NULL; 643 } 644 apps_shutdown(); 645 OPENSSL_EXIT(ret); 646 } 647 648 /*********************************************************************** 649 * doConnection - make a connection 650 * Args: 651 * scon = earlier ssl connection for session id, or NULL 652 * Returns: 653 * SSL * = the connection pointer. 654 */ 655 static SSL *doConnection(SSL *scon) 656 { 657 BIO *conn; 658 SSL *serverCon; 659 int width, i; 660 fd_set readfds; 661 662 if ((conn=BIO_new(BIO_s_connect())) == NULL) 663 return(NULL); 664 665 /* BIO_set_conn_port(conn,port);*/ 666 BIO_set_conn_hostname(conn,host); 667 668 if (scon == NULL) 669 serverCon=SSL_new(tm_ctx); 670 else 671 { 672 serverCon=scon; 673 SSL_set_connect_state(serverCon); 674 } 675 676 SSL_set_bio(serverCon,conn,conn); 677 678 #if 0 679 if( scon != NULL ) 680 SSL_set_session(serverCon,SSL_get_session(scon)); 681 #endif 682 683 /* ok, lets connect */ 684 for(;;) { 685 i=SSL_connect(serverCon); 686 if (BIO_sock_should_retry(i)) 687 { 688 BIO_printf(bio_err,"DELAY\n"); 689 690 i=SSL_get_fd(serverCon); 691 width=i+1; 692 FD_ZERO(&readfds); 693 FD_SET(i,&readfds); 694 /* Note: under VMS with SOCKETSHR the 2nd parameter 695 * is currently of type (int *) whereas under other 696 * systems it is (void *) if you don't have a cast it 697 * will choke the compiler: if you do have a cast then 698 * you can either go for (int *) or (void *). 699 */ 700 select(width,(void *)&readfds,NULL,NULL,NULL); 701 continue; 702 } 703 break; 704 } 705 if(i <= 0) 706 { 707 BIO_printf(bio_err,"ERROR\n"); 708 if (verify_error != X509_V_OK) 709 BIO_printf(bio_err,"verify error:%s\n", 710 X509_verify_cert_error_string(verify_error)); 711 else 712 ERR_print_errors(bio_err); 713 if (scon == NULL) 714 SSL_free(serverCon); 715 return NULL; 716 } 717 718 return serverCon; 719 } 720 721 722