X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=apps%2Fs_client.c;h=66c0f8aa33edb786b9aeb2c0f375ba8b460cdcdd;hb=f03620ea15c4553de375258bc40bbf7a4092da90;hp=efd8b06fe6eea310ecccff3c1b111d0fb665f6d6;hpb=566dda07ba16f9d3b9774fd5c8d526d7cc93f179;p=openssl.git diff --git a/apps/s_client.c b/apps/s_client.c index efd8b06fe6..66c0f8aa33 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -56,7 +56,7 @@ * [including the GNU Public Licence.] */ /* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2006 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -108,8 +108,35 @@ * Hudson (tjh@cryptsoft.com). * */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ #include +#include #include #include #include @@ -137,20 +164,15 @@ typedef unsigned int u_int; #include "s_apps.h" #include "timeouts.h" -#ifdef OPENSSL_SYS_WINCE -/* Windows CE incorrectly defines fileno as returning void*, so to avoid problems below... */ -#ifdef fileno -#undef fileno -#endif -#define fileno(a) (int)_fileno(a) -#endif - - #if (defined(OPENSSL_SYS_VMS) && __VMS_VER < 70000000) /* FIONBIO used as a switch to enable ioctl, and that isn't in VMS < 7.0 */ #undef FIONBIO #endif +#if defined(OPENSSL_SYS_BEOS_R5) +#include +#endif + #undef PROG #define PROG s_client_main @@ -165,6 +187,7 @@ typedef unsigned int u_int; extern int verify_depth; extern int verify_error; +extern int verify_return_error; #ifdef FIONBIO static int c_nbio=0; @@ -180,6 +203,69 @@ static BIO *bio_c_out=NULL; static int c_quiet=0; static int c_ign_eof=0; +#ifndef OPENSSL_NO_PSK +/* Default PSK identity and key */ +static char *psk_identity="Client_identity"; +static char *psk_key=NULL; /* by default PSK is not used */ + +static unsigned int psk_client_cb(SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, unsigned char *psk, + unsigned int max_psk_len) + { + unsigned int psk_len = 0; + int ret; + BIGNUM *bn=NULL; + + if (c_debug) + BIO_printf(bio_c_out, "psk_client_cb\n"); + if (!hint) + { + /* no ServerKeyExchange message*/ + if (c_debug) + BIO_printf(bio_c_out,"NULL received PSK identity hint, continuing anyway\n"); + } + else if (c_debug) + BIO_printf(bio_c_out, "Received PSK identity hint '%s'\n", hint); + + /* lookup PSK identity and PSK key based on the given identity hint here */ + ret = BIO_snprintf(identity, max_identity_len, psk_identity); + if (ret < 0 || (unsigned int)ret > max_identity_len) + goto out_err; + if (c_debug) + BIO_printf(bio_c_out, "created identity '%s' len=%d\n", identity, ret); + ret=BN_hex2bn(&bn, psk_key); + if (!ret) + { + BIO_printf(bio_err,"Could not convert PSK key '%s' to BIGNUM\n", psk_key); + if (bn) + BN_free(bn); + return 0; + } + + if ((unsigned int)BN_num_bytes(bn) > max_psk_len) + { + BIO_printf(bio_err,"psk buffer of callback is too small (%d) for key (%d)\n", + max_psk_len, BN_num_bytes(bn)); + BN_free(bn); + return 0; + } + + psk_len=BN_bn2bin(bn, psk); + BN_free(bn); + if (psk_len == 0) + goto out_err; + + if (c_debug) + BIO_printf(bio_c_out, "created PSK len=%d\n", psk_len); + + return psk_len; + out_err: + if (c_debug) + BIO_printf(bio_err, "Error in PSK client callback\n"); + return 0; + } +#endif + static void sc_usage(void) { BIO_printf(bio_err,"usage: s_client args\n"); @@ -213,6 +299,10 @@ static void sc_usage(void) BIO_printf(bio_err," -crlf - convert LF from terminal into CRLF\n"); BIO_printf(bio_err," -quiet - no s_client output\n"); BIO_printf(bio_err," -ign_eof - ignore input eof (default when -quiet)\n"); +#ifndef OPENSSL_NO_PSK + BIO_printf(bio_err," -psk_identity arg - PSK identity\n"); + BIO_printf(bio_err," -psk arg - PSK in hex (without 0x)\n"); +#endif BIO_printf(bio_err," -ssl2 - just use SSLv2\n"); BIO_printf(bio_err," -ssl3 - just use SSLv3\n"); BIO_printf(bio_err," -tls1 - just use TLSv1\n"); @@ -226,20 +316,53 @@ static void sc_usage(void) BIO_printf(bio_err," -starttls prot - use the STARTTLS command before starting TLS\n"); BIO_printf(bio_err," for those protocols that support it, where\n"); BIO_printf(bio_err," 'prot' defines which one to assume. Currently,\n"); - BIO_printf(bio_err," only \"smtp\" and \"pop3\" are supported.\n"); + BIO_printf(bio_err," only \"smtp\", \"pop3\", \"imap\", and \"ftp\" are supported.\n"); #ifndef OPENSSL_NO_ENGINE BIO_printf(bio_err," -engine id - Initialise and use the specified engine\n"); #endif BIO_printf(bio_err," -rand file%cfile%c...\n", LIST_SEPARATOR_CHAR, LIST_SEPARATOR_CHAR); +#ifndef OPENSSL_NO_TLSEXT + BIO_printf(bio_err," -servername host - Set TLS extension servername in ClientHello\n"); +#endif + } + +#ifndef OPENSSL_NO_TLSEXT + +/* This is a context that we pass to callbacks */ +typedef struct tlsextctx_st { + BIO * biodebug; + int ack; +} tlsextctx; + +static int MS_CALLBACK ssl_servername_cb(SSL *s, int *ad, void *arg) + { + tlsextctx * p = (tlsextctx *) arg; + const char * hn= SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + if (SSL_get_servername_type(s) != -1) + p->ack = !SSL_session_reused(s) && hn != NULL; + else + BIO_printf(bio_err,"Can't use SSL_get_servername\n"); + + return SSL_TLSEXT_ERR_OK; } +#endif + +enum +{ + PROTO_OFF = 0, + PROTO_SMTP, + PROTO_POP3, + PROTO_IMAP, + PROTO_FTP +}; int MAIN(int, char **); int MAIN(int argc, char **argv) { int off=0; - SSL *con=NULL,*con2=NULL; + SSL *con=NULL; X509_STORE *store = NULL; int s,k,width,state=0; char *cbuf=NULL,*sbuf=NULL,*mbuf=NULL; @@ -260,27 +383,33 @@ int MAIN(int argc, char **argv) int write_tty,read_tty,write_ssl,read_ssl,tty_on,ssl_pending; SSL_CTX *ctx=NULL; int ret=1,in_init=1,i,nbio_test=0; - int starttls_proto = 0; + int starttls_proto = PROTO_OFF; int prexit = 0, vflags = 0; const SSL_METHOD *meth=NULL; -#ifdef sock_type -#undef sock_type -#endif - int sock_type=SOCK_STREAM; + int socket_type=SOCK_STREAM; BIO *sbio; char *inrand=NULL; + int mbuf_len=0; #ifndef OPENSSL_NO_ENGINE char *engine_id=NULL; ENGINE *e=NULL; #endif -#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) +#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5) struct timeval tv; +#if defined(OPENSSL_SYS_BEOS_R5) + int stdin_set = 0; +#endif #endif +#ifndef OPENSSL_NO_TLSEXT + char *servername = NULL; + tlsextctx tlsextcbp = + {NULL,0}; +#endif struct sockaddr peer; int peerlen = sizeof(peer); int enable_timeouts = 0 ; - long mtu = 0; + long socket_mtu = 0; #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) meth=SSLv23_client_method(); @@ -360,6 +489,8 @@ int MAIN(int argc, char **argv) vflags |= X509_V_FLAG_CRL_CHECK; else if (strcmp(*argv,"-crl_check_all") == 0) vflags |= X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL; + else if (strcmp(*argv,"-verify_return_error") == 0) + verify_return_error = 1; else if (strcmp(*argv,"-prexit") == 0) prexit=1; else if (strcmp(*argv,"-crlf") == 0) @@ -387,6 +518,27 @@ int MAIN(int argc, char **argv) nbio_test=1; else if (strcmp(*argv,"-state") == 0) state=1; +#ifndef OPENSSL_NO_PSK + else if (strcmp(*argv,"-psk_identity") == 0) + { + if (--argc < 1) goto bad; + psk_identity=*(++argv); + } + else if (strcmp(*argv,"-psk") == 0) + { + size_t j; + + if (--argc < 1) goto bad; + psk_key=*(++argv); + for (j = 0; j < strlen(psk_key); j++) + { + if (isxdigit((int)psk_key[j])) + continue; + BIO_printf(bio_err,"Not a hex number '%s'\n",*argv); + goto bad; + } + } +#endif #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv,"-ssl2") == 0) meth=SSLv2_client_method(); @@ -403,14 +555,14 @@ int MAIN(int argc, char **argv) else if (strcmp(*argv,"-dtls1") == 0) { meth=DTLSv1_client_method(); - sock_type=SOCK_DGRAM; + socket_type=SOCK_DGRAM; } else if (strcmp(*argv,"-timeout") == 0) enable_timeouts=1; else if (strcmp(*argv,"-mtu") == 0) { if (--argc < 1) goto bad; - mtu = atol(*(++argv)); + socket_mtu = atol(*(++argv)); } #endif else if (strcmp(*argv,"-bugs") == 0) @@ -468,9 +620,13 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; ++argv; if (strcmp(*argv,"smtp") == 0) - starttls_proto = 1; + starttls_proto = PROTO_SMTP; else if (strcmp(*argv,"pop3") == 0) - starttls_proto = 2; + starttls_proto = PROTO_POP3; + else if (strcmp(*argv,"imap") == 0) + starttls_proto = PROTO_IMAP; + else if (strcmp(*argv,"ftp") == 0) + starttls_proto = PROTO_FTP; else goto bad; } @@ -486,6 +642,14 @@ int MAIN(int argc, char **argv) if (--argc < 1) goto bad; inrand= *(++argv); } +#ifndef OPENSSL_NO_TLSEXT + else if (strcmp(*argv,"-servername") == 0) + { + if (--argc < 1) goto bad; + servername= *(++argv); + /* meth=TLSv1_client_method(); */ + } +#endif else { BIO_printf(bio_err,"unknown option %s\n",*argv); @@ -574,6 +738,14 @@ bad: goto end; } +#ifndef OPENSSL_NO_PSK + if (psk_key != NULL) + { + if (c_debug) + BIO_printf(bio_c_out, "PSK key given, setting client callback\n"); + SSL_CTX_set_psk_client_callback(ctx, psk_client_cb); + } +#endif if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL|off); else @@ -581,7 +753,7 @@ bad: /* DTLS: partial reads end up discarding unread UDP bytes :-( * Setting read ahead solves this problem. */ - if (sock_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); + if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); if (cipher != NULL) @@ -609,8 +781,27 @@ bad: store = SSL_CTX_get_cert_store(ctx); X509_STORE_set_flags(store, vflags); +#ifndef OPENSSL_NO_TLSEXT + if (servername != NULL) + { + tlsextcbp.biodebug = bio_err; + SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); + SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); + } +#endif con=SSL_new(ctx); +#ifndef OPENSSL_NO_TLSEXT + if (servername != NULL) + { + if (!SSL_set_tlsext_host_name(con,servername)) + { + BIO_printf(bio_err,"Unable to set TLS servername extension.\n"); + ERR_print_errors(bio_err); + goto end; + } + } +#endif #ifndef OPENSSL_NO_KRB5 if (con && (con->kssl_ctx = kssl_ctx_new()) != NULL) { @@ -621,7 +812,7 @@ bad: re_start: - if (init_client(&s,host,port,sock_type) == 0) + if (init_client(&s,host,port,socket_type) == 0) { BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error()); SHUTDOWN(s); @@ -658,7 +849,7 @@ re_start: BIO_ctrl_set_connected(sbio, 1, &peer); - if ( enable_timeouts) + if (enable_timeouts) { timeout.tv_sec = 0; timeout.tv_usec = DGRAM_RCV_TIMEOUT; @@ -669,10 +860,10 @@ re_start: BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } - if ( mtu > 0) + if (socket_mtu > 0) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); - SSL_set_mtu(con, mtu); + SSL_set_mtu(con, socket_mtu); } else /* want to do MTU discovery */ @@ -695,7 +886,7 @@ re_start: { con->debug=1; BIO_set_callback(sbio,bio_dump_callback); - BIO_set_callback_arg(sbio,bio_c_out); + BIO_set_callback_arg(sbio,(char *)bio_c_out); } if (c_msg) { @@ -721,18 +912,93 @@ re_start: sbuf_off=0; /* This is an ugly hack that does a lot of assumptions */ - if (starttls_proto == 1) + /* We do have to handle multi-line responses which may come + in a single packet or not. We therefore have to use + BIO_gets() which does need a buffering BIO. So during + the initial chitchat we do push a buffering BIO into the + chain that is removed again later on to not disturb the + rest of the s_client operation. */ + if (starttls_proto == PROTO_SMTP) { - BIO_read(sbio,mbuf,BUFSIZZ); + int foundit=0; + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + /* wait for multi-line response to end from SMTP */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + } + while (mbuf_len>3 && mbuf[3]=='-'); + /* STARTTLS command requires EHLO... */ + BIO_printf(fbio,"EHLO openssl.client.net\r\n"); + BIO_flush(fbio); + /* wait for multi-line response to end EHLO SMTP response */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + if (strstr(mbuf,"STARTTLS")) + foundit=1; + } + while (mbuf_len>3 && mbuf[3]=='-'); + BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't found starttls in server response," + " try anyway...\n"); BIO_printf(sbio,"STARTTLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } - if (starttls_proto == 2) + else if (starttls_proto == PROTO_POP3) { BIO_read(sbio,mbuf,BUFSIZZ); BIO_printf(sbio,"STLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } + else if (starttls_proto == PROTO_IMAP) + { + int foundit=0; + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + BIO_gets(fbio,mbuf,BUFSIZZ); + /* STARTTLS command requires CAPABILITY... */ + BIO_printf(fbio,". CAPABILITY\r\n"); + BIO_flush(fbio); + /* wait for multi-line CAPABILITY response */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + if (strstr(mbuf,"STARTTLS")) + foundit=1; + } + while (mbuf_len>3 && mbuf[0]!='.'); + BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + if (!foundit) + BIO_printf(bio_err, + "didn't found STARTTLS in server response," + " try anyway...\n"); + BIO_printf(sbio,". STARTTLS\r\n"); + BIO_read(sbio,sbuf,BUFSIZZ); + } + else if (starttls_proto == PROTO_FTP) + { + BIO *fbio = BIO_new(BIO_f_buffer()); + BIO_push(fbio, sbio); + /* wait for multi-line response to end from FTP */ + do + { + mbuf_len = BIO_gets(fbio,mbuf,BUFSIZZ); + } + while (mbuf_len>3 && mbuf[3]=='-'); + BIO_flush(fbio); + BIO_pop(fbio); + BIO_free(fbio); + BIO_printf(sbio,"AUTH TLS\r\n"); + BIO_read(sbio,sbuf,BUFSIZZ); + } for (;;) { @@ -750,6 +1016,12 @@ re_start: if (in_init) { in_init=0; +#ifndef OPENSSL_NO_TLSEXT + if (servername != NULL && !SSL_session_reused(con)) + { + BIO_printf(bio_c_out,"Server did %sacknowledge servername extension.\n",tlsextcbp.ack?"":"not "); + } +#endif print_stuff(bio_c_out,con,full_log); if (full_log > 0) full_log--; @@ -757,7 +1029,7 @@ re_start: { BIO_printf(bio_err,"%s",mbuf); /* We don't need to know any more */ - starttls_proto = 0; + starttls_proto = PROTO_OFF; } if (reconnect) @@ -776,22 +1048,22 @@ re_start: if (!ssl_pending) { -#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) +#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) && !defined (OPENSSL_SYS_BEOS_R5) if (tty_on) { - if (read_tty) FD_SET(fileno(stdin),&readfds); - if (write_tty) FD_SET(fileno(stdout),&writefds); + if (read_tty) openssl_fdset(fileno(stdin),&readfds); + if (write_tty) openssl_fdset(fileno(stdout),&writefds); } if (read_ssl) - FD_SET(SSL_get_fd(con),&readfds); + openssl_fdset(SSL_get_fd(con),&readfds); if (write_ssl) - FD_SET(SSL_get_fd(con),&writefds); + openssl_fdset(SSL_get_fd(con),&writefds); #else if(!tty_on || !write_tty) { if (read_ssl) - FD_SET(SSL_get_fd(con),&readfds); + openssl_fdset(SSL_get_fd(con),&readfds); if (write_ssl) - FD_SET(SSL_get_fd(con),&writefds); + openssl_fdset(SSL_get_fd(con),&writefds); } #endif /* printf("mode tty(%d %d%d) ssl(%d%d)\n", @@ -836,6 +1108,25 @@ re_start: } else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); } +#elif defined(OPENSSL_SYS_BEOS_R5) + /* Under BeOS-R5 the situation is similar to DOS */ + i=0; + stdin_set = 0; + (void)fcntl(fileno(stdin), F_SETFL, O_NONBLOCK); + if(!write_tty) { + if(read_tty) { + tv.tv_sec = 1; + tv.tv_usec = 0; + i=select(width,(void *)&readfds,(void *)&writefds, + NULL,&tv); + if (read(fileno(stdin), sbuf, 0) >= 0) + stdin_set = 1; + if (!i && (stdin_set != 1 || !read_tty)) + continue; + } else i=select(width,(void *)&readfds,(void *)&writefds, + NULL,NULL); + } + (void)fcntl(fileno(stdin), F_SETFL, 0); #else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); @@ -916,8 +1207,8 @@ re_start: goto shut; } } -#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) - /* Assume Windows/DOS can always write */ +#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5) + /* Assume Windows/DOS/BeOS can always write */ else if (!ssl_pending && write_tty) #else else if (!ssl_pending && FD_ISSET(fileno(stdout),&writefds)) @@ -926,7 +1217,7 @@ re_start: #ifdef CHARSET_EBCDIC ascii2ebcdic(&(sbuf[sbuf_off]),&(sbuf[sbuf_off]),sbuf_len); #endif - i=write(fileno(stdout),&(sbuf[sbuf_off]),sbuf_len); + i=raw_write_stdout(&(sbuf[sbuf_off]),sbuf_len); if (i <= 0) { @@ -1004,7 +1295,9 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 else if ((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) #endif #elif defined (OPENSSL_SYS_NETWARE) - else if (_kbhit()) + else if (_kbhit()) +#elif defined(OPENSSL_SYS_BEOS_R5) + else if (stdin_set) #else else if (FD_ISSET(fileno(stdin),&readfds)) #endif @@ -1013,7 +1306,7 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 { int j, lf_num; - i=read(fileno(stdin),cbuf,BUFSIZZ/2); + i=raw_read_stdin(cbuf,BUFSIZZ/2); lf_num = 0; /* both loops are skipped when i <= 0 */ for (j = 0; j < i; j++) @@ -1032,7 +1325,7 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 assert(lf_num == 0); } else - i=read(fileno(stdin),cbuf,BUFSIZZ); + i=raw_read_stdin(cbuf,BUFSIZZ); if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { @@ -1060,13 +1353,18 @@ printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240 } } shut: + if (in_init) + print_stuff(bio_c_out,con,full_log); SSL_shutdown(con); SHUTDOWN(SSL_get_fd(con)); ret=0; end: - if(prexit) print_stuff(bio_c_out,con,1); - if (con != NULL) SSL_free(con); - if (con2 != NULL) SSL_free(con2); + if (con != NULL) + { + if (prexit != 0) + print_stuff(bio_c_out,con,1); + SSL_free(con); + } if (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert);