int ssl3_setup_read_buffer(SSL *s) { unsigned char *p; size_t len,align=0,headerlen; if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) headerlen = DTLS1_RT_HEADER_LENGTH; else headerlen = SSL3_RT_HEADER_LENGTH; #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 align = (-SSL3_RT_HEADER_LENGTH)&(SSL3_ALIGN_PAYLOAD-1); #endif if (s->s3->rbuf.buf == NULL) { if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) { len = SSL3_RT_DEFAULT_PACKET_SIZE; } else { len = SSL3_RT_MAX_PLAIN_LENGTH + SSL3_RT_MAX_ENCRYPTED_OVERHEAD + headerlen + align; if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) { s->s3->init_extra = 1; len += SSL3_RT_MAX_EXTRA; } } #ifndef OPENSSL_NO_COMP if (!(s->options & SSL_OP_NO_COMPRESSION)) len += SSL3_RT_MAX_COMPRESSED_OVERHEAD; #endif if ((p=freelist_extract(s->ctx, 1, len)) == NULL) goto err; s->s3->rbuf.buf = p; s->s3->rbuf.len = len; } s->packet= &(s->s3->rbuf.buf[0]); return 1; err: SSLerr(SSL_F_SSL3_SETUP_READ_BUFFER,ERR_R_MALLOC_FAILURE); return 0; }
static void print_ciphersuite_data(BIO *io, SSL *ssl, int js) { SSL_SESSION* session = SSL_get_session(ssl); long protocol = SSL_version(ssl); const char *protocol_name = get_protocol_name(protocol); const char *eol = js ? "\\n\\\n" : "\n"; if(BIO_printf(io, "Version: 0x%lx %s%s", protocol, protocol_name, eol) <= 0) err_exit("Write error"); if(BIO_printf(io, "Current cipher: %s%s", SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)), eol) <= 0) err_exit("Write error"); STACK_OF(SSL_CIPHER) *ciphers = session->ciphers; SSL_CIPHER *c; int n = sk_SSL_CIPHER_num(ciphers); if(BIO_printf(io, "client sent %d ciphers%s", n, eol) <= 0) err_exit("Write error"); int i; for (i = 0; i < n; i++) { c = sk_SSL_CIPHER_value(ciphers, i); if(BIO_printf(io, "client [%2d of %2d]: %s%s", i, n, SSL_CIPHER_get_name(c), eol) <= 0) err_exit("Write error"); } }
int ssl3_setup_write_buffer(SSL *s) { unsigned char *p; size_t len,align=0,headerlen; if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) headerlen = DTLS1_RT_HEADER_LENGTH + 1; else headerlen = SSL3_RT_HEADER_LENGTH; #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD!=0 align = (-SSL3_RT_HEADER_LENGTH)&(SSL3_ALIGN_PAYLOAD-1); #endif if (s->s3->wbuf.buf == NULL) { if (SSL_get_mode(s) & SSL_MODE_SMALL_BUFFERS) { len = SSL3_RT_DEFAULT_PACKET_SIZE; } else { len = s->max_send_fragment; } len += 0 + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + headerlen + align; #ifndef OPENSSL_NO_COMP if (!(s->options & SSL_OP_NO_COMPRESSION)) len += SSL3_RT_MAX_COMPRESSED_OVERHEAD; #endif if (!(s->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) len += headerlen + align + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; if ((p=freelist_extract(s->ctx, 0, len)) == NULL) goto err; s->s3->wbuf.buf = p; s->s3->wbuf.len = len; } return 1; err: SSLerr(SSL_F_SSL3_SETUP_WRITE_BUFFER,ERR_R_MALLOC_FAILURE); return 0; }
my_bool ma_tls_get_protocol_version(MARIADB_TLS *ctls, struct st_ssl_version *version) { SSL *ssl; if (!ctls || !ctls->ssl) return 1; ssl = (SSL *)ctls->ssl; version->iversion= SSL_version(ssl) - TLS1_VERSION; version->cversion= ssl_protocol_version[version->iversion]; return 0; }
int ssl3_setup_buffers(SSL *s) { unsigned char *p; unsigned int extra,headerlen; size_t len; if (SSL_version(s) == DTLS1_VERSION || SSL_version(s) == DTLS1_BAD_VER) headerlen = DTLS1_RT_HEADER_LENGTH; else headerlen = SSL3_RT_HEADER_LENGTH; if (s->s3->rbuf.buf == NULL) { if (s->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER) extra=SSL3_RT_MAX_EXTRA; else extra=0; len = SSL3_RT_MAX_PACKET_SIZE + extra; if ((p=OPENSSL_malloc(len)) == NULL) goto err; s->s3->rbuf.buf = p; s->s3->rbuf.len = len; } if (s->s3->wbuf.buf == NULL) { len = SSL3_RT_MAX_PACKET_SIZE; len += headerlen + 256; /* extra space for empty fragment */ if ((p=OPENSSL_malloc(len)) == NULL) goto err; s->s3->wbuf.buf = p; s->s3->wbuf.len = len; } s->packet= &(s->s3->rbuf.buf[0]); return(1); err: SSLerr(SSL_F_SSL3_SETUP_BUFFERS,ERR_R_MALLOC_FAILURE); return(0); }
/* * Called by OpenSSL when a new src SSL session is created. * Return 0 means remove session from internal session cache. */ #ifdef DISABLE_SSLV2_SESSION_CACHE #define MAYBE_UNUSED #else /* !DISABLE_SSLV2_SESSION_CACHE */ #define MAYBE_UNUSED UNUSED #endif /* !DISABLE_SSLV2_SESSION_CACHE */ static int pxy_ossl_sessnew_cb(MAYBE_UNUSED SSL *ssl, SSL_SESSION *sess) #undef MAYBE_UNUSED { #ifdef DEBUG_SESSION_CACHE log_dbg_printf("===> OpenSSL new session callback:\n"); if (sess) { log_dbg_print_free(ssl_session_to_str(sess)); } #endif /* DEBUG_SESSION_CACHE */ #ifdef DISABLE_SSLV2_SESSION_CACHE /* Session resumption seems to fail for SSLv2 with protocol * parsing errors, so we disable caching for SSLv2. */ if (SSL_version(ssl) == SSL2_VERSION) { log_err_printf("Warning: Session resumption denied to SSLv2" "client.\n"); return 0; } #endif /* DISABLE_SSLV2_SESSION_CACHE */ cachemgr_ssess_set(sess); return 0; }
void TLSSocket::Handshake(TCPSocket& socket, HandshakeRole role) { session = SSL_new(role == Client ? TLSClientContext::Get() : TLSServerContext::Get()); if (!session) throw TLSProtocolError(); if (SSL_set_fd(session, socket.Socket()) != 1) throw TLSProtocolError(); if (role == Client) SSL_set_connect_state(session); else SSL_set_accept_state(session); int result; while (true) { if (role == Client) result = SSL_connect(session); else result = SSL_accept(session); boost::this_thread::interruption_point(); if (result == 1) break; else EvaluateResult(result); } std::cout << SSL_version(session) << std::endl; }
static int dtls_connect (void) { struct timeval timeout; fd_set wfd; int width = 0; struct sockaddr peer; int peerlen = sizeof (struct sockaddr); ssl = SSL_new (ctx); if (DTLS1_VERSION == SSL_version (ssl)) fprintf (stderr, "%s: %s(): Yes: DTLS1_VERSION CLIENT\n", __FILE__, __func__); sbio = BIO_new_dgram (udpsock, BIO_NOCLOSE); if (getsockname (udpsock, &peer, (socklen_t *)&peerlen) < 0) { dtls_report_err ("%s: %s(): getsockname FAILED: %s\n", __FILE__, __func__, strerror (errno)); shutdown (udpsock, SHUT_RDWR); return -1; } BIO_ctrl_set_connected (sbio, 1, &peer); timeout.tv_sec = 10; timeout.tv_usec = 0; BIO_ctrl (sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); SSL_set_bio (ssl, sbio, sbio); SSL_set_connect_state (ssl); fprintf (stderr, "%s: %s(): Am now here @ %d\n", __FILE__, __func__, __LINE__); width = SSL_get_fd (ssl) + 1; FD_ZERO (&wfd); FD_SET (SSL_get_fd (ssl), &wfd); timeout.tv_sec = 10; timeout.tv_usec = 0; if (select (width, NULL, &wfd, NULL, &timeout) < 0) { return 1; } return 0; }
static int openssl_ssl_get(lua_State*L) { SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl"); int i; int top = lua_gettop(L); for (i = 2; i <= top; i++) { const char* what = luaL_checklstring(L, i, NULL); if (strcmp(what, "fd") == 0) { lua_pushinteger(L, SSL_get_fd(s)); } else if (strcmp(what, "rfd") == 0) { lua_pushinteger(L, SSL_get_rfd(s)); } else if (strcmp(what, "wfd") == 0) { lua_pushinteger(L, SSL_get_wfd(s)); } else if (strcmp(what, "client_CA_list") == 0) { STACK_OF(X509_NAME)* sn = SSL_get_client_CA_list(s); PUSH_OBJECT(sn, "openssl.sk_x509_name"); } else if (strcmp(what, "read_ahead") == 0) { lua_pushboolean(L, SSL_get_read_ahead(s)); } else if (strcmp(what, "shared_ciphers") == 0) { char buf[LUAL_BUFFERSIZE] = {0}; lua_pushstring(L, SSL_get_shared_ciphers(s, buf, sizeof(buf))); } else if (strcmp(what, "cipher_list") == 0) { //TODO FIX lua_pushstring(L, SSL_get_cipher_list(s, 0)); } else if (strcmp(what, "verify_mode") == 0) { //FIX lua_pushinteger(L, SSL_get_verify_mode(s)); } else if (strcmp(what, "verify_depth") == 0) { lua_pushinteger(L, SSL_get_verify_depth(s)); } else if (strcmp(what, "state_string") == 0) { lua_pushstring(L, SSL_state_string(s)); } else if (strcmp(what, "state_string_long") == 0) { lua_pushstring(L, SSL_state_string_long(s)); } else if (strcmp(what, "rstate_string") == 0) { lua_pushstring(L, SSL_rstate_string(s)); } else if (strcmp(what, "rstate_string_long") == 0) { lua_pushstring(L, SSL_rstate_string_long(s)); } else if (strcmp(what, "version") == 0) { lua_pushstring(L, SSL_get_version(s)); } else if (strcmp(what, "iversion") == 0) { lua_pushinteger(L, SSL_version(s)); } else if (strcmp(what, "default_timeout") == 0) { lua_pushinteger(L, SSL_get_default_timeout(s)); } else if (strcmp(what, "certificate") == 0) { X509* cert = SSL_get_certificate(s); PUSH_OBJECT(cert, "openssl.x509"); } else if (strcmp(what, "verify_result") == 0) { long l = SSL_get_verify_result(s); lua_pushinteger(L, l); } else if (strcmp(what, "version") == 0) { lua_pushstring(L, SSL_get_version(s)); } else if (strcmp(what, "state") == 0) { lua_pushinteger(L, SSL_state(s)); } else if (strcmp(what, "hostname") == 0) { lua_pushstring(L, SSL_get_servername(s, TLSEXT_NAMETYPE_host_name)); } else luaL_argerror(L, i, "can't understant"); } return top - 1; }
/*********************************************************************** * MAIN - main processing area for client * real name depends on MONOLITH */ int s_time_main(int argc, char **argv) { double totalTime = 0.0; int nConn = 0; SSL *scon = NULL; long finishtime = 0; int ret = 1, i; char buf[1024 * 8]; int ver; s_time_meth = SSLv23_client_method(); verify_depth = 0; verify_error = X509_V_OK; memset(&s_time_config, 0, sizeof(s_time_config)); s_time_config.host = SSL_CONNECT_NAME; s_time_config.maxtime = SECONDS; s_time_config.perform = 3; s_time_config.verify = SSL_VERIFY_NONE; s_time_config.verify_depth = -1; if (options_parse(argc, argv, s_time_options, NULL, NULL) != 0) { s_time_usage(); goto end; } if (s_time_config.verify_depth >= 0) { s_time_config.verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; verify_depth = s_time_config.verify_depth; BIO_printf(bio_err, "verify depth is %d\n", verify_depth); } if (s_time_config.www_path != NULL && strlen(s_time_config.www_path) > MYBUFSIZ - 100) { BIO_printf(bio_err, "-www option too long\n"); goto end; } if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL) return (1); SSL_CTX_set_quiet_shutdown(tm_ctx, 1); if (s_time_config.bugs) SSL_CTX_set_options(tm_ctx, SSL_OP_ALL); if (s_time_config.cipher != NULL) { if (!SSL_CTX_set_cipher_list(tm_ctx, s_time_config.cipher)) { BIO_printf(bio_err, "error setting cipher list\n"); ERR_print_errors(bio_err); goto end; } } if (!set_cert_stuff(tm_ctx, s_time_config.certfile, s_time_config.keyfile)) goto end; if ((!SSL_CTX_load_verify_locations(tm_ctx, s_time_config.CAfile, s_time_config.CApath)) || (!SSL_CTX_set_default_verify_paths(tm_ctx))) { /* * BIO_printf(bio_err,"error setting default verify * locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } if (!(s_time_config.perform & 1)) goto next; printf("Collecting connection statistics for %d seconds\n", s_time_config.maxtime); /* Loop and time how long it takes to make connections */ bytes_read = 0; finishtime = (long) time(NULL) + s_time_config.maxtime; tm_Time_F(START); for (;;) { if (finishtime < (long) time(NULL)) break; if ((scon = doConnection(NULL)) == NULL) goto end; if (s_time_config.www_path != NULL) { int retval = snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path); if ((size_t)retval >= sizeof buf) { fprintf(stderr, "URL too long\n"); goto end; } SSL_write(scon, buf, strlen(buf)); while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif shutdown(SSL_get_fd(scon), SHUT_RDWR); close(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else if (ver == SSL2_VERSION) ver = '2'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); SSL_free(scon); scon = NULL; } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ i = (int) ((long) time(NULL) - finishtime + s_time_config.maxtime); printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read); printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + s_time_config.maxtime, bytes_read / nConn); /* * Now loop and time connections using the same session id over and * over */ next: if (!(s_time_config.perform & 2)) goto end; printf("\n\nNow timing with session id reuse.\n"); /* Get an SSL object so we can reuse the session id */ if ((scon = doConnection(NULL)) == NULL) { fprintf(stderr, "Unable to get connection\n"); goto end; } if (s_time_config.www_path != NULL) { int retval = snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path); if ((size_t)retval >= sizeof buf) { fprintf(stderr, "URL too long\n"); goto end; } SSL_write(scon, buf, strlen(buf)); while (SSL_read(scon, buf, sizeof(buf)) > 0); } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif shutdown(SSL_get_fd(scon), SHUT_RDWR); close(SSL_get_fd(scon)); nConn = 0; totalTime = 0.0; finishtime = (long) time(NULL) + s_time_config.maxtime; printf("starting\n"); bytes_read = 0; tm_Time_F(START); for (;;) { if (finishtime < (long) time(NULL)) break; if ((doConnection(scon)) == NULL) goto end; if (s_time_config.www_path) { int retval = snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_time_config.www_path); if ((size_t)retval >= sizeof buf) { fprintf(stderr, "URL too long\n"); goto end; } SSL_write(scon, buf, strlen(buf)); while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif shutdown(SSL_get_fd(scon), SHUT_RDWR); close(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else if (ver == SSL2_VERSION) ver = '2'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ printf("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double) nConn / totalTime), bytes_read); printf("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long) time(NULL) - finishtime + s_time_config.maxtime, bytes_read / nConn); ret = 0; end: if (scon != NULL) SSL_free(scon); if (tm_ctx != NULL) { SSL_CTX_free(tm_ctx); tm_ctx = NULL; } return (ret); }
int s_time_main(int argc, char **argv) { char buf[1024 * 8]; SSL *scon = NULL; SSL_CTX *ctx = NULL; const SSL_METHOD *meth = NULL; char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *www_path = NULL; char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog; double totalTime = 0.0; int maxtime = SECONDS, nConn = 0, perform = 3, ret = 1, i, st_bugs = 0, ver; long bytes_read = 0, finishtime = 0; OPTION_CHOICE o; #ifdef OPENSSL_SYS_WIN32 int exitNow = 0; /* Set when it's time to exit main */ #endif meth = TLS_client_method(); verify_depth = 0; verify_error = X509_V_OK; prog = opt_init(argc, argv, s_time_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { case OPT_EOF: case OPT_ERR: opthelp: BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); goto end; case OPT_HELP: opt_help(s_time_options); ret = 0; goto end; case OPT_CONNECT: host = opt_arg(); break; case OPT_REUSE: perform = 2; break; case OPT_NEW: perform = 1; break; case OPT_VERIFY: if (!opt_int(opt_arg(), &verify_depth)) goto opthelp; BIO_printf(bio_err, "%s: verify depth is %d\n", prog, verify_depth); break; case OPT_CERT: certfile = opt_arg(); break; case OPT_KEY: keyfile = opt_arg(); break; case OPT_CAPATH: CApath = opt_arg(); break; case OPT_CAFILE: CAfile = opt_arg(); break; case OPT_CIPHER: cipher = opt_arg(); break; case OPT_BUGS: st_bugs = 1; break; case OPT_TIME: if (!opt_int(opt_arg(), &maxtime)) goto opthelp; break; case OPT_WWW: www_path = opt_arg(); if (strlen(www_path) > MYBUFSIZ - 100) { BIO_printf(bio_err, "%s: -www option too long\n", prog); goto end; } break; case OPT_SSL3: #ifndef OPENSSL_NO_SSL3 meth = SSLv3_client_method(); #endif break; } } argc = opt_num_rest(); argv = opt_rest(); if (cipher == NULL) cipher = getenv("SSL_CIPHER"); if (cipher == NULL) { BIO_printf(bio_err, "No CIPHER specified\n"); goto end; } if ((ctx = SSL_CTX_new(meth)) == NULL) goto end; SSL_CTX_set_quiet_shutdown(ctx, 1); if (st_bugs) SSL_CTX_set_options(ctx, SSL_OP_ALL); if (!SSL_CTX_set_cipher_list(ctx, cipher)) goto end; if (!set_cert_stuff(ctx, certfile, keyfile)) goto end; if (!ctx_set_verify_locations(ctx, CAfile, CApath)) { ERR_print_errors(bio_err); goto end; } if (!(perform & 1)) goto next; printf("Collecting connection statistics for %d seconds\n", maxtime); /* Loop and time how long it takes to make connections */ bytes_read = 0; finishtime = (long)time(NULL) + maxtime; tm_Time_F(START); for (;;) { if (finishtime < (long)time(NULL)) break; #ifdef WIN32_STUFF if (flushWinMsgs(0) == -1) goto end; if (waitingToDie || exitNow) /* we're dead */ goto end; #endif if ((scon = doConnection(NULL, host, ctx)) == NULL) goto end; if (www_path != NULL) { BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", www_path); if (SSL_write(scon, buf, strlen(buf)) <= 0) goto end; while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif SHUTDOWN2(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); SSL_free(scon); scon = NULL; } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ i = (int)((long)time(NULL) - finishtime + maxtime); printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); printf ("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); /* * Now loop and time connections using the same session id over and over */ next: if (!(perform & 2)) goto end; printf("\n\nNow timing with session id reuse.\n"); /* Get an SSL object so we can reuse the session id */ if ((scon = doConnection(NULL, host, ctx)) == NULL) { BIO_printf(bio_err, "Unable to get connection\n"); goto end; } if (www_path != NULL) { BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", www_path); if (SSL_write(scon, buf, strlen(buf)) <= 0) goto end; while (SSL_read(scon, buf, sizeof(buf)) > 0) continue; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif SHUTDOWN2(SSL_get_fd(scon)); nConn = 0; totalTime = 0.0; finishtime = (long)time(NULL) + maxtime; printf("starting\n"); bytes_read = 0; tm_Time_F(START); for (;;) { if (finishtime < (long)time(NULL)) break; #ifdef WIN32_STUFF if (flushWinMsgs(0) == -1) goto end; if (waitingToDie || exitNow) /* we're dead */ goto end; #endif if ((doConnection(scon, host, ctx)) == NULL) goto end; if (www_path) { BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", www_path); if (SSL_write(scon, buf, strlen(buf)) <= 0) goto end; while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif SHUTDOWN2(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); printf ("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); ret = 0; end: SSL_free(scon); SSL_CTX_free(ctx); return (ret); }
int MAIN(int argc, char **argv) { double totalTime = 0.0; int nConn = 0; SSL *scon = NULL; long finishtime = 0; int ret = 1, i; char buf[1024 * 8]; int ver; apps_startup(); s_time_init(); if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE); s_time_meth = SSLv23_client_method(); /* parse the command line arguments */ if (parseArgs(argc, argv) < 0) goto end; OpenSSL_add_ssl_algorithms(); if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL) return (1); SSL_CTX_set_quiet_shutdown(tm_ctx, 1); if (st_bugs) SSL_CTX_set_options(tm_ctx, SSL_OP_ALL); if(!SSL_CTX_set_cipher_list(tm_ctx, tm_cipher)) goto end; if (!set_cert_stuff(tm_ctx, t_cert_file, t_key_file)) goto end; SSL_load_error_strings(); if ((!SSL_CTX_load_verify_locations(tm_ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(tm_ctx))) { /* * BIO_printf(bio_err,"error setting default verify locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } if (tm_cipher == NULL) tm_cipher = getenv("SSL_CIPHER"); if (tm_cipher == NULL) { fprintf(stderr, "No CIPHER specified\n"); } if (!(perform & 1)) goto next; printf("Collecting connection statistics for %d seconds\n", maxTime); /* Loop and time how long it takes to make connections */ bytes_read = 0; finishtime = (long)time(NULL) + maxTime; tm_Time_F(START); for (;;) { if (finishtime < (long)time(NULL)) break; #ifdef WIN32_STUFF if (flushWinMsgs(0) == -1) goto end; if (waitingToDie || exitNow) /* we're dead */ goto end; #endif if ((scon = doConnection(NULL)) == NULL) goto end; if (s_www_path != NULL) { BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_www_path); if(SSL_write(scon, buf, strlen(buf)) <= 0) goto end; while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif SHUTDOWN2(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); SSL_free(scon); scon = NULL; } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ i = (int)((long)time(NULL) - finishtime + maxTime); printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); printf ("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long)time(NULL) - finishtime + maxTime, bytes_read / nConn); /* * Now loop and time connections using the same session id over and over */ next: if (!(perform & 2)) goto end; printf("\n\nNow timing with session id reuse.\n"); /* Get an SSL object so we can reuse the session id */ if ((scon = doConnection(NULL)) == NULL) { fprintf(stderr, "Unable to get connection\n"); goto end; } if (s_www_path != NULL) { BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_www_path); if(SSL_write(scon, buf, strlen(buf)) <= 0) goto end; while (SSL_read(scon, buf, sizeof(buf)) > 0) ; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif SHUTDOWN2(SSL_get_fd(scon)); nConn = 0; totalTime = 0.0; finishtime = (long)time(NULL) + maxTime; printf("starting\n"); bytes_read = 0; tm_Time_F(START); for (;;) { if (finishtime < (long)time(NULL)) break; #ifdef WIN32_STUFF if (flushWinMsgs(0) == -1) goto end; if (waitingToDie || exitNow) /* we're dead */ goto end; #endif if ((doConnection(scon)) == NULL) goto end; if (s_www_path) { BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n", s_www_path); if(SSL_write(scon, buf, strlen(buf)) <= 0) goto end; while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } #ifdef NO_SHUTDOWN SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(scon); #endif SHUTDOWN2(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) ver = 'r'; else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); printf ("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long)time(NULL) - finishtime + maxTime, bytes_read / (nConn?nConn:1)); ret = 0; end: if (scon != NULL) SSL_free(scon); if (tm_ctx != NULL) { SSL_CTX_free(tm_ctx); tm_ctx = NULL; } apps_shutdown(); OPENSSL_EXIT(ret); }
int SSL_usesDatagramSockets(SSL *ssl) { return SSL_version(ssl) == DTLS1_VERSION; }
int tls1_mac(SSL *ssl, unsigned char *md, int send) { SSL3_RECORD *rec; unsigned char *mac_sec,*seq; const EVP_MD *hash; unsigned int md_size; int i; HMAC_CTX hmac; unsigned char buf[5]; if (send) { rec= &(ssl->s3->wrec); mac_sec= &(ssl->s3->write_mac_secret[0]); seq= &(ssl->s3->write_sequence[0]); hash=ssl->write_hash; } else { rec= &(ssl->s3->rrec); mac_sec= &(ssl->s3->read_mac_secret[0]); seq= &(ssl->s3->read_sequence[0]); hash=ssl->read_hash; } md_size=EVP_MD_size(hash); buf[0]=rec->type; if (ssl->version == DTLS1_VERSION && ssl->client_version == DTLS1_BAD_VER) { buf[1]=TLS1_VERSION_MAJOR; buf[2]=TLS1_VERSION_MINOR; } else { buf[1]=(unsigned char)(ssl->version>>8); buf[2]=(unsigned char)(ssl->version); } buf[3]=rec->length>>8; buf[4]=rec->length&0xff; /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */ HMAC_CTX_init(&hmac); HMAC_Init_ex(&hmac,mac_sec,EVP_MD_size(hash),hash,NULL); if (ssl->version == DTLS1_VERSION && ssl->client_version != DTLS1_BAD_VER) { unsigned char dtlsseq[8],*p=dtlsseq; s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p); memcpy (p,&seq[2],6); HMAC_Update(&hmac,dtlsseq,8); } else HMAC_Update(&hmac,seq,8); HMAC_Update(&hmac,buf,5); HMAC_Update(&hmac,rec->input,rec->length); HMAC_Final(&hmac,md,&md_size); HMAC_CTX_cleanup(&hmac); #ifdef TLS_DEBUG printf("sec="); {unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",mac_sec[z]); printf("\n"); } printf("seq="); {int z; for (z=0; z<8; z++) printf("%02X ",seq[z]); printf("\n"); } printf("buf="); {int z; for (z=0; z<5; z++) printf("%02X ",buf[z]); printf("\n"); } printf("rec="); {unsigned int z; for (z=0; z<rec->length; z++) printf("%02X ",buf[z]); printf("\n"); } #endif if ( SSL_version(ssl) != DTLS1_VERSION) { for (i=7; i>=0; i--) { ++seq[i]; if (seq[i] != 0) break; } } #ifdef TLS_DEBUG {unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",md[z]); printf("\n"); } #endif return(md_size); }
/* * Note that |extra| points to the correct client/server configuration * within |test_ctx|. When configuring the handshake, general mode settings * are taken from |test_ctx|, and client/server-specific settings should be * taken from |extra|. * * The configuration code should never reach into |test_ctx->extra| or * |test_ctx->resume_extra| directly. * * (We could refactor test mode settings into a substructure. This would result * in cleaner argument passing but would complicate the test configuration * parsing.) */ static HANDSHAKE_RESULT *do_handshake_internal( SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx, const SSL_TEST_CTX *test_ctx, const SSL_TEST_EXTRA_CONF *extra, SSL_SESSION *session_in, SSL_SESSION **session_out) { PEER server, client; BIO *client_to_server, *server_to_client; HANDSHAKE_EX_DATA server_ex_data, client_ex_data; CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data; HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new(); int client_turn = 1; connect_phase_t phase = HANDSHAKE; handshake_status_t status = HANDSHAKE_RETRY; const unsigned char* tick = NULL; size_t tick_len = 0; SSL_SESSION* sess = NULL; const unsigned char *proto = NULL; /* API dictates unsigned int rather than size_t. */ unsigned int proto_len = 0; memset(&server_ctx_data, 0, sizeof(server_ctx_data)); memset(&server2_ctx_data, 0, sizeof(server2_ctx_data)); memset(&client_ctx_data, 0, sizeof(client_ctx_data)); memset(&server, 0, sizeof(server)); memset(&client, 0, sizeof(client)); configure_handshake_ctx(server_ctx, server2_ctx, client_ctx, test_ctx, extra, &server_ctx_data, &server2_ctx_data, &client_ctx_data); /* Setup SSL and buffers; additional configuration happens below. */ create_peer(&server, server_ctx); create_peer(&client, client_ctx); server.bytes_to_write = client.bytes_to_read = test_ctx->app_data_size; client.bytes_to_write = server.bytes_to_read = test_ctx->app_data_size; configure_handshake_ssl(server.ssl, client.ssl, extra); if (session_in != NULL) { /* In case we're testing resumption without tickets. */ TEST_check(SSL_CTX_add_session(server_ctx, session_in)); TEST_check(SSL_set_session(client.ssl, session_in)); } memset(&server_ex_data, 0, sizeof(server_ex_data)); memset(&client_ex_data, 0, sizeof(client_ex_data)); ret->result = SSL_TEST_INTERNAL_ERROR; client_to_server = BIO_new(BIO_s_mem()); server_to_client = BIO_new(BIO_s_mem()); TEST_check(client_to_server != NULL); TEST_check(server_to_client != NULL); /* Non-blocking bio. */ BIO_set_nbio(client_to_server, 1); BIO_set_nbio(server_to_client, 1); SSL_set_connect_state(client.ssl); SSL_set_accept_state(server.ssl); /* The bios are now owned by the SSL object. */ SSL_set_bio(client.ssl, server_to_client, client_to_server); TEST_check(BIO_up_ref(server_to_client) > 0); TEST_check(BIO_up_ref(client_to_server) > 0); SSL_set_bio(server.ssl, client_to_server, server_to_client); ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL); TEST_check(ex_data_idx >= 0); TEST_check(SSL_set_ex_data(server.ssl, ex_data_idx, &server_ex_data) == 1); TEST_check(SSL_set_ex_data(client.ssl, ex_data_idx, &client_ex_data) == 1); SSL_set_info_callback(server.ssl, &info_cb); SSL_set_info_callback(client.ssl, &info_cb); client.status = server.status = PEER_RETRY; /* * Half-duplex handshake loop. * Client and server speak to each other synchronously in the same process. * We use non-blocking BIOs, so whenever one peer blocks for read, it * returns PEER_RETRY to indicate that it's the other peer's turn to write. * The handshake succeeds once both peers have succeeded. If one peer * errors out, we also let the other peer retry (and presumably fail). */ for(;;) { if (client_turn) { do_connect_step(&client, phase); status = handshake_status(client.status, server.status, 1 /* client went last */); } else { do_connect_step(&server, phase); status = handshake_status(server.status, client.status, 0 /* server went last */); } switch (status) { case HANDSHAKE_SUCCESS: phase = next_phase(phase); if (phase == CONNECTION_DONE) { ret->result = SSL_TEST_SUCCESS; goto err; } else { client.status = server.status = PEER_RETRY; /* * For now, client starts each phase. Since each phase is * started separately, we can later control this more * precisely, for example, to test client-initiated and * server-initiated shutdown. */ client_turn = 1; break; } case CLIENT_ERROR: ret->result = SSL_TEST_CLIENT_FAIL; goto err; case SERVER_ERROR: ret->result = SSL_TEST_SERVER_FAIL; goto err; case INTERNAL_ERROR: ret->result = SSL_TEST_INTERNAL_ERROR; goto err; case HANDSHAKE_RETRY: /* Continue. */ client_turn ^= 1; break; } } err: ret->server_alert_sent = server_ex_data.alert_sent; ret->server_num_fatal_alerts_sent = server_ex_data.num_fatal_alerts_sent; ret->server_alert_received = client_ex_data.alert_received; ret->client_alert_sent = client_ex_data.alert_sent; ret->client_num_fatal_alerts_sent = client_ex_data.num_fatal_alerts_sent; ret->client_alert_received = server_ex_data.alert_received; ret->server_protocol = SSL_version(server.ssl); ret->client_protocol = SSL_version(client.ssl); ret->servername = server_ex_data.servername; if ((sess = SSL_get0_session(client.ssl)) != NULL) SSL_SESSION_get0_ticket(sess, &tick, &tick_len); if (tick == NULL || tick_len == 0) ret->session_ticket = SSL_TEST_SESSION_TICKET_NO; else ret->session_ticket = SSL_TEST_SESSION_TICKET_YES; ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call; #ifndef OPENSSL_NO_NEXTPROTONEG SSL_get0_next_proto_negotiated(client.ssl, &proto, &proto_len); ret->client_npn_negotiated = dup_str(proto, proto_len); SSL_get0_next_proto_negotiated(server.ssl, &proto, &proto_len); ret->server_npn_negotiated = dup_str(proto, proto_len); #endif SSL_get0_alpn_selected(client.ssl, &proto, &proto_len); ret->client_alpn_negotiated = dup_str(proto, proto_len); SSL_get0_alpn_selected(server.ssl, &proto, &proto_len); ret->server_alpn_negotiated = dup_str(proto, proto_len); ret->client_resumed = SSL_session_reused(client.ssl); ret->server_resumed = SSL_session_reused(server.ssl); if (session_out != NULL) *session_out = SSL_get1_session(client.ssl); ctx_data_free_data(&server_ctx_data); ctx_data_free_data(&server2_ctx_data); ctx_data_free_data(&client_ctx_data); peer_free_data(&server); peer_free_data(&client); return ret; }
int s_client_main(int argc, char **argv) { unsigned int off = 0, clr = 0; SSL *con = NULL; int s, k, width, state = 0, af = AF_UNSPEC; char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; int cbuf_len, cbuf_off; int sbuf_len, sbuf_off; fd_set readfds, writefds; char *port = PORT_STR; int full_log = 1; char *host = SSL_HOST_NAME; char *cert_file = NULL, *key_file = NULL; int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; char *passarg = NULL, *pass = NULL; X509 *cert = NULL; EVP_PKEY *key = NULL; char *CApath = NULL, *CAfile = NULL, *cipher = NULL; int reconnect = 0, badop = 0, verify = SSL_VERIFY_NONE, bugs = 0; int crlf = 0; 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 = PROTO_OFF; int prexit = 0; X509_VERIFY_PARAM *vpm = NULL; int badarg = 0; const SSL_METHOD *meth = NULL; int socket_type = SOCK_STREAM; BIO *sbio; int mbuf_len = 0; struct timeval timeout, *timeoutp; const char *errstr = NULL; #ifndef OPENSSL_NO_ENGINE char *engine_id = NULL; char *ssl_client_engine_id = NULL; ENGINE *ssl_client_engine = NULL; #endif ENGINE *e = NULL; #ifndef OPENSSL_NO_TLSEXT char *servername = NULL; tlsextctx tlsextcbp = {NULL, 0}; #ifndef OPENSSL_NO_NEXTPROTONEG const char *next_proto_neg_in = NULL; #endif #endif char *sess_in = NULL; char *sess_out = NULL; struct sockaddr peer; int peerlen = sizeof(peer); int enable_timeouts = 0; long socket_mtu = 0; meth = SSLv23_client_method(); c_Pause = 0; c_quiet = 0; c_ign_eof = 0; c_debug = 0; c_msg = 0; c_showcerts = 0; if (((cbuf = malloc(BUFSIZZ)) == NULL) || ((sbuf = malloc(BUFSIZZ)) == NULL) || ((mbuf = malloc(BUFSIZZ + 1)) == NULL)) { /* NUL byte */ BIO_printf(bio_err, "out of memory\n"); goto end; } verify_depth = 0; verify_error = X509_V_OK; c_nbio = 0; argc--; argv++; while (argc >= 1) { if (strcmp(*argv, "-host") == 0) { if (--argc < 1) goto bad; host = *(++argv); } else if (strcmp(*argv, "-port") == 0) { if (--argc < 1) goto bad; port = *(++argv); if (port == NULL || *port == '\0') goto bad; } else if (strcmp(*argv, "-connect") == 0) { if (--argc < 1) goto bad; if (!extract_host_port(*(++argv), &host, NULL, &port)) goto bad; } else if (strcmp(*argv, "-verify") == 0) { verify = SSL_VERIFY_PEER; if (--argc < 1) goto bad; verify_depth = strtonum(*(++argv), 0, INT_MAX, &errstr); if (errstr) goto bad; BIO_printf(bio_err, "verify depth is %d\n", verify_depth); } else if (strcmp(*argv, "-cert") == 0) { if (--argc < 1) goto bad; cert_file = *(++argv); } else if (strcmp(*argv, "-sess_out") == 0) { if (--argc < 1) goto bad; sess_out = *(++argv); } else if (strcmp(*argv, "-sess_in") == 0) { if (--argc < 1) goto bad; sess_in = *(++argv); } else if (strcmp(*argv, "-certform") == 0) { if (--argc < 1) goto bad; cert_format = str2fmt(*(++argv)); } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { if (badarg) goto bad; continue; } 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) crlf = 1; else if (strcmp(*argv, "-quiet") == 0) { c_quiet = 1; c_ign_eof = 1; } else if (strcmp(*argv, "-ign_eof") == 0) c_ign_eof = 1; else if (strcmp(*argv, "-no_ign_eof") == 0) c_ign_eof = 0; else if (strcmp(*argv, "-pause") == 0) c_Pause = 1; else if (strcmp(*argv, "-debug") == 0) c_debug = 1; #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-tlsextdebug") == 0) c_tlsextdebug = 1; else if (strcmp(*argv, "-status") == 0) c_status_req = 1; #endif else if (strcmp(*argv, "-msg") == 0) c_msg = 1; else if (strcmp(*argv, "-showcerts") == 0) c_showcerts = 1; else if (strcmp(*argv, "-nbio_test") == 0) nbio_test = 1; else if (strcmp(*argv, "-state") == 0) state = 1; else if (strcmp(*argv, "-ssl3") == 0) meth = SSLv3_client_method(); else if (strcmp(*argv, "-tls1_2") == 0) meth = TLSv1_2_client_method(); else if (strcmp(*argv, "-tls1_1") == 0) meth = TLSv1_1_client_method(); else if (strcmp(*argv, "-tls1") == 0) meth = TLSv1_client_method(); #ifndef OPENSSL_NO_DTLS1 else if (strcmp(*argv, "-dtls1") == 0) { meth = DTLSv1_client_method(); socket_type = SOCK_DGRAM; } else if (strcmp(*argv, "-timeout") == 0) enable_timeouts = 1; else if (strcmp(*argv, "-mtu") == 0) { if (--argc < 1) goto bad; socket_mtu = strtonum(*(++argv), 0, LONG_MAX, &errstr); if (errstr) goto bad; } #endif else if (strcmp(*argv, "-bugs") == 0) bugs = 1; else if (strcmp(*argv, "-keyform") == 0) { if (--argc < 1) goto bad; key_format = str2fmt(*(++argv)); } else if (strcmp(*argv, "-pass") == 0) { if (--argc < 1) goto bad; passarg = *(++argv); } else if (strcmp(*argv, "-key") == 0) { if (--argc < 1) goto bad; key_file = *(++argv); } else if (strcmp(*argv, "-reconnect") == 0) { reconnect = 5; } else if (strcmp(*argv, "-CApath") == 0) { if (--argc < 1) goto bad; CApath = *(++argv); } else if (strcmp(*argv, "-CAfile") == 0) { if (--argc < 1) goto bad; CAfile = *(++argv); } else if (strcmp(*argv, "-no_tls1_2") == 0) off |= SSL_OP_NO_TLSv1_2; else if (strcmp(*argv, "-no_tls1_1") == 0) off |= SSL_OP_NO_TLSv1_1; else if (strcmp(*argv, "-no_tls1") == 0) off |= SSL_OP_NO_TLSv1; else if (strcmp(*argv, "-no_ssl3") == 0) off |= SSL_OP_NO_SSLv3; else if (strcmp(*argv, "-no_ssl2") == 0) off |= SSL_OP_NO_SSLv2; else if (strcmp(*argv, "-no_comp") == 0) { off |= SSL_OP_NO_COMPRESSION; } #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-no_ticket") == 0) { off |= SSL_OP_NO_TICKET; } #ifndef OPENSSL_NO_NEXTPROTONEG else if (strcmp(*argv, "-nextprotoneg") == 0) { if (--argc < 1) goto bad; next_proto_neg_in = *(++argv); } #endif #endif else if (strcmp(*argv, "-serverpref") == 0) off |= SSL_OP_CIPHER_SERVER_PREFERENCE; else if (strcmp(*argv, "-legacy_renegotiation") == 0) ; /* no-op */ else if (strcmp(*argv, "-legacy_server_connect") == 0) { off |= SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv, "-no_legacy_server_connect") == 0) { clr |= SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv, "-cipher") == 0) { if (--argc < 1) goto bad; cipher = *(++argv); } else if (strcmp(*argv, "-nbio") == 0) { c_nbio = 1; } else if (strcmp(*argv, "-starttls") == 0) { if (--argc < 1) goto bad; ++argv; if (strcmp(*argv, "smtp") == 0) starttls_proto = PROTO_SMTP; else if (strcmp(*argv, "lmtp") == 0) starttls_proto = PROTO_LMTP; else if (strcmp(*argv, "pop3") == 0) 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 if (strcmp(*argv, "xmpp") == 0) starttls_proto = PROTO_XMPP; else goto bad; } #ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv, "-engine") == 0) { if (--argc < 1) goto bad; engine_id = *(++argv); } else if (strcmp(*argv, "-ssl_client_engine") == 0) { if (--argc < 1) goto bad; ssl_client_engine_id = *(++argv); } #endif else if (strcmp(*argv, "-4") == 0) { af = AF_INET; } else if (strcmp(*argv, "-6") == 0) { af = AF_INET6; } #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-servername") == 0) { if (--argc < 1) goto bad; servername = *(++argv); /* meth=TLSv1_client_method(); */ } #endif #ifndef OPENSSL_NO_SRTP else if (strcmp(*argv, "-use_srtp") == 0) { if (--argc < 1) goto bad; srtp_profiles = *(++argv); } #endif else if (strcmp(*argv, "-keymatexport") == 0) { if (--argc < 1) goto bad; keymatexportlabel = *(++argv); } else if (strcmp(*argv, "-keymatexportlen") == 0) { const char *errstr; if (--argc < 1) goto bad; keymatexportlen = strtonum(*(++argv), 1, INT_MAX, &errstr); if (errstr) goto bad; } else { BIO_printf(bio_err, "unknown option %s\n", *argv); badop = 1; break; } argc--; argv++; } if (badop) { bad: if (errstr) BIO_printf(bio_err, "invalid argument %s: %s\n", *argv, errstr); else sc_usage(); goto end; } #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) next_proto.status = -1; if (next_proto_neg_in) { next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in); if (next_proto.data == NULL) { BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n"); goto end; } } else next_proto.data = NULL; #endif #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine_id, 1); if (ssl_client_engine_id) { ssl_client_engine = ENGINE_by_id(ssl_client_engine_id); if (!ssl_client_engine) { BIO_printf(bio_err, "Error getting client auth engine\n"); goto end; } } #endif if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } if (key_file == NULL) key_file = cert_file; if (key_file) { key = load_key(bio_err, key_file, key_format, 0, pass, e, "client certificate private key file"); if (!key) { ERR_print_errors(bio_err); goto end; } } if (cert_file) { cert = load_cert(bio_err, cert_file, cert_format, NULL, e, "client certificate file"); if (!cert) { ERR_print_errors(bio_err); goto end; } } if (bio_c_out == NULL) { if (c_quiet && !c_debug && !c_msg) { bio_c_out = BIO_new(BIO_s_null()); } else { if (bio_c_out == NULL) bio_c_out = BIO_new_fp(stdout, BIO_NOCLOSE); } } ctx = SSL_CTX_new(meth); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; } if (vpm) SSL_CTX_set1_param(ctx, vpm); #ifndef OPENSSL_NO_ENGINE if (ssl_client_engine) { if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) { BIO_puts(bio_err, "Error setting client auth engine\n"); ERR_print_errors(bio_err); ENGINE_free(ssl_client_engine); goto end; } ENGINE_free(ssl_client_engine); } #endif #ifndef OPENSSL_NO_SRTP if (srtp_profiles != NULL) SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles); #endif if (bugs) SSL_CTX_set_options(ctx, SSL_OP_ALL | off); else SSL_CTX_set_options(ctx, off); if (clr) SSL_CTX_clear_options(ctx, clr); /* * DTLS: partial reads end up discarding unread UDP bytes :-( Setting * read ahead solves this problem. */ if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.data) SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); #endif if (state) SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); if (cipher != NULL) if (!SSL_CTX_set_cipher_list(ctx, cipher)) { BIO_printf(bio_err, "error setting cipher list\n"); ERR_print_errors(bio_err); goto end; } SSL_CTX_set_verify(ctx, verify, verify_callback); if (!set_cert_key_stuff(ctx, cert, key)) goto end; if ((!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(ctx))) { /* * BIO_printf(bio_err,"error setting default verify * locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } #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); if (sess_in) { SSL_SESSION *sess; BIO *stmp = BIO_new_file(sess_in, "r"); if (!stmp) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; } sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); BIO_free(stmp); if (!sess) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; } SSL_set_session(con, sess); SSL_SESSION_free(sess); } #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 /* SSL_set_cipher_list(con,"RC4-MD5"); */ re_start: if (init_client(&s, host, port, socket_type, af) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", errno); shutdown(s, SHUT_RD); close(s); goto end; } BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); if (c_nbio) { unsigned long l = 1; BIO_printf(bio_c_out, "turning on non blocking io\n"); if (BIO_socket_ioctl(s, FIONBIO, &l) < 0) { ERR_print_errors(bio_err); goto end; } } if (c_Pause & 0x01) SSL_set_debug(con, 1); if (SSL_version(con) == DTLS1_VERSION) { sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (getsockname(s, &peer, (void *) &peerlen) < 0) { BIO_printf(bio_err, "getsockname:errno=%d\n", errno); shutdown(s, SHUT_RD); close(s); goto end; } (void) BIO_ctrl_set_connected(sbio, 1, &peer); if (enable_timeouts) { timeout.tv_sec = 0; timeout.tv_usec = DGRAM_RCV_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); timeout.tv_sec = 0; timeout.tv_usec = DGRAM_SND_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } if (socket_mtu > 28) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); SSL_set_mtu(con, socket_mtu - 28); } else /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); } else sbio = BIO_new_socket(s, BIO_NOCLOSE); if (nbio_test) { BIO *test; test = BIO_new(BIO_f_nbio_test()); sbio = BIO_push(test, sbio); } if (c_debug) { SSL_set_debug(con, 1); BIO_set_callback(sbio, bio_dump_callback); BIO_set_callback_arg(sbio, (char *) bio_c_out); } if (c_msg) { SSL_set_msg_callback(con, msg_cb); SSL_set_msg_callback_arg(con, bio_c_out); } #ifndef OPENSSL_NO_TLSEXT if (c_tlsextdebug) { SSL_set_tlsext_debug_callback(con, tlsext_cb); SSL_set_tlsext_debug_arg(con, bio_c_out); } if (c_status_req) { SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp); SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb); SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out); } #endif SSL_set_bio(con, sbio, sbio); SSL_set_connect_state(con); /* ok, lets connect */ width = SSL_get_fd(con) + 1; read_tty = 1; write_tty = 0; tty_on = 0; read_ssl = 1; write_ssl = 1; cbuf_len = 0; cbuf_off = 0; sbuf_len = 0; sbuf_off = 0; /* This is an ugly hack that does a lot of assumptions */ /* * 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 || starttls_proto == PROTO_LMTP) { 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, "%cHLO openssl.client.net\r\n", starttls_proto == PROTO_SMTP ? 'E' : 'L'); (void) 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] == '-'); (void) 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_POP3) { mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ); if (mbuf_len == -1) { BIO_printf(bio_err, "BIO_read failed\n"); goto end; } 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"); (void) 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] != '.'); (void) 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] == '-'); (void) BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); BIO_printf(sbio, "AUTH TLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } if (starttls_proto == PROTO_XMPP) { int seen = 0; BIO_printf(sbio, "<stream:stream " "xmlns:stream='http://etherx.jabber.org/streams' " "xmlns='jabber:client' to='%s' version='1.0'>", host); seen = BIO_read(sbio, mbuf, BUFSIZZ); mbuf[seen] = 0; while (!strstr(mbuf, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'")) { if (strstr(mbuf, "/stream:features>")) goto shut; seen = BIO_read(sbio, mbuf, BUFSIZZ); mbuf[seen] = 0; } BIO_printf(sbio, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); seen = BIO_read(sbio, sbuf, BUFSIZZ); sbuf[seen] = 0; if (!strstr(sbuf, "<proceed")) goto shut; mbuf[0] = 0; } for (;;) { FD_ZERO(&readfds); FD_ZERO(&writefds); if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_get_timeout(con, &timeout)) timeoutp = &timeout; else timeoutp = NULL; if (SSL_in_init(con) && !SSL_total_renegotiations(con)) { in_init = 1; tty_on = 0; } else { tty_on = 1; if (in_init) { in_init = 0; if (sess_out) { BIO *stmp = BIO_new_file(sess_out, "w"); if (stmp) { PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con)); BIO_free(stmp); } else BIO_printf(bio_err, "Error writing session file %s\n", sess_out); } print_stuff(bio_c_out, con, full_log); if (full_log > 0) full_log--; if (starttls_proto) { BIO_write(bio_err, mbuf, mbuf_len); /* We don't need to know any more */ starttls_proto = PROTO_OFF; } if (reconnect) { reconnect--; BIO_printf(bio_c_out, "drop connection and then reconnect\n"); SSL_shutdown(con); SSL_set_connect_state(con); shutdown(SSL_get_fd(con), SHUT_RD); close(SSL_get_fd(con)); goto re_start; } } } ssl_pending = read_ssl && SSL_pending(con); /* XXX should add tests for fd_set overflow */ if (!ssl_pending) { if (tty_on) { if (read_tty) FD_SET(fileno(stdin), &readfds); if (write_tty) FD_SET(fileno(stdout), &writefds); } if (read_ssl) FD_SET(SSL_get_fd(con), &readfds); if (write_ssl) FD_SET(SSL_get_fd(con), &writefds); /* printf("mode tty(%d %d%d) ssl(%d%d)\n", tty_on,read_tty,write_tty,read_ssl,write_ssl);*/ i = select(width, &readfds, &writefds, NULL, timeoutp); if (i < 0) { BIO_printf(bio_err, "bad select %d\n", errno); goto shut; /* goto end; */ } } if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0) { BIO_printf(bio_err, "TIMEOUT occured\n"); } if (!ssl_pending && FD_ISSET(SSL_get_fd(con), &writefds)) { k = SSL_write(con, &(cbuf[cbuf_off]), (unsigned int) cbuf_len); switch (SSL_get_error(con, k)) { case SSL_ERROR_NONE: cbuf_off += k; cbuf_len -= k; if (k <= 0) goto end; /* we have done a write(con,NULL,0); */ if (cbuf_len <= 0) { read_tty = 1; write_ssl = 0; } else { /* if (cbuf_len > 0) */ read_tty = 0; write_ssl = 1; } break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out, "write W BLOCK\n"); write_ssl = 1; read_tty = 0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out, "write R BLOCK\n"); write_tty = 0; read_ssl = 1; write_ssl = 0; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out, "write X BLOCK\n"); break; case SSL_ERROR_ZERO_RETURN: if (cbuf_len != 0) { BIO_printf(bio_c_out, "shutdown\n"); ret = 0; goto shut; } else { read_tty = 1; write_ssl = 0; break; } case SSL_ERROR_SYSCALL: if ((k != 0) || (cbuf_len != 0)) { BIO_printf(bio_err, "write:errno=%d\n", errno); goto shut; } else { read_tty = 1; write_ssl = 0; } break; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; } } else if (!ssl_pending && FD_ISSET(fileno(stdout), &writefds)) { i = write(fileno(stdout), &(sbuf[sbuf_off]), sbuf_len); if (i <= 0) { BIO_printf(bio_c_out, "DONE\n"); ret = 0; goto shut; /* goto end; */ } sbuf_len -= i; sbuf_off += i; if (sbuf_len <= 0) { read_ssl = 1; write_tty = 0; } } else if (ssl_pending || FD_ISSET(SSL_get_fd(con), &readfds)) { #ifdef RENEG { static int iiii; if (++iiii == 52) { SSL_renegotiate(con); iiii = 0; } } #endif k = SSL_read(con, sbuf, 1024 /* BUFSIZZ */ ); switch (SSL_get_error(con, k)) { case SSL_ERROR_NONE: if (k <= 0) goto end; sbuf_off = 0; sbuf_len = k; read_ssl = 0; write_tty = 1; break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out, "read W BLOCK\n"); write_ssl = 1; read_tty = 0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out, "read R BLOCK\n"); write_tty = 0; read_ssl = 1; if ((read_tty == 0) && (write_ssl == 0)) write_ssl = 1; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out, "read X BLOCK\n"); break; case SSL_ERROR_SYSCALL: ret = errno; BIO_printf(bio_err, "read:errno=%d\n", ret); goto shut; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_c_out, "closed\n"); ret = 0; goto shut; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; /* break; */ } } else if (FD_ISSET(fileno(stdin), &readfds)) { if (crlf) { int j, lf_num; i = read(fileno(stdin), cbuf, BUFSIZZ / 2); lf_num = 0; /* both loops are skipped when i <= 0 */ for (j = 0; j < i; j++) if (cbuf[j] == '\n') lf_num++; for (j = i - 1; j >= 0; j--) { cbuf[j + lf_num] = cbuf[j]; if (cbuf[j] == '\n') { lf_num--; i++; cbuf[j + lf_num] = '\r'; } } assert(lf_num == 0); } else i = read(fileno(stdin), cbuf, BUFSIZZ); if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { BIO_printf(bio_err, "DONE\n"); ret = 0; goto shut; } if ((!c_ign_eof) && (cbuf[0] == 'R')) { BIO_printf(bio_err, "RENEGOTIATING\n"); SSL_renegotiate(con); cbuf_len = 0; } else { cbuf_len = i; cbuf_off = 0; } write_ssl = 1; read_tty = 0; } } ret = 0; shut: if (in_init) print_stuff(bio_c_out, con, full_log); SSL_shutdown(con); shutdown(SSL_get_fd(con), SHUT_RD); close(SSL_get_fd(con)); end: if (con != NULL) { if (prexit != 0) print_stuff(bio_c_out, con, 1); SSL_free(con); } #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) free(next_proto.data); #endif if (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert); if (key) EVP_PKEY_free(key); free(pass); if (vpm) X509_VERIFY_PARAM_free(vpm); if (cbuf != NULL) { OPENSSL_cleanse(cbuf, BUFSIZZ); free(cbuf); } if (sbuf != NULL) { OPENSSL_cleanse(sbuf, BUFSIZZ); free(sbuf); } if (mbuf != NULL) { OPENSSL_cleanse(mbuf, BUFSIZZ); free(mbuf); } if (bio_c_out != NULL) { BIO_free(bio_c_out); bio_c_out = NULL; } return (ret); }
static void transfer(CLI * c) { int watchdog = 0; int num, err; int sock_open_rd = 1, sock_open_wr = 1; int shutdown_wants_read = 0, shutdown_wants_write = 0; int read_wants_read, read_wants_write = 0; int write_wants_read = 0, write_wants_write; int sock_can_rd, sock_can_wr, ssl_can_rd, ssl_can_wr; c->sock_ptr = c->ssl_ptr = 0; do { read_wants_read = !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN) && c->ssl_ptr < BUFFSIZE && !read_wants_write; write_wants_write = !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; s_poll_init(c->fds); if (sock_open_rd) s_poll_add(c->fds, c->sock_rfd->fd, c->sock_ptr < BUFFSIZE, 0); if (sock_open_wr) s_poll_add(c->fds, c->sock_wfd->fd, 0, c->ssl_ptr); if (read_wants_read || write_wants_read || shutdown_wants_read) s_poll_add(c->fds, c->ssl_rfd->fd, 1, 0); if (read_wants_write || write_wants_write || shutdown_wants_write) s_poll_add(c->fds, c->ssl_wfd->fd, 0, 1); err = s_poll_wait(c->fds, (sock_open_rd && !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr || c->sock_ptr ? c->opt->timeout_idle : c->opt->timeout_close, 0); switch (err) { case -1: sockerror("transfer: s_poll_wait"); longjmp(c->err, 1); case 0: if ((sock_open_rd && !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr || c->sock_ptr) { s_log(LOG_INFO, "transfer: s_poll_wait:" " TIMEOUTidle exceeded: sending reset"); longjmp(c->err, 1); } else { s_log(LOG_ERR, "transfer: s_poll_wait:" " TIMEOUTclose exceeded: closing"); return; } } err = s_poll_error(c->fds, c->sock_rfd); if (err) { s_log(LOG_NOTICE, "Error detected on socket (read) file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } if (c->sock_wfd->fd != c->sock_rfd->fd) { err = s_poll_error(c->fds, c->sock_wfd); if (err) { s_log(LOG_NOTICE, "Error detected on socket write file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } } err = s_poll_error(c->fds, c->ssl_rfd); if (err) { s_log(LOG_NOTICE, "Error detected on SSL (read) file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } if (c->ssl_wfd->fd != c->ssl_rfd->fd) { err = s_poll_error(c->fds, c->ssl_wfd); if (err) { s_log(LOG_NOTICE, "Error detected on SSL write file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } } sock_can_rd = s_poll_canread(c->fds, c->sock_rfd->fd); sock_can_wr = s_poll_canwrite(c->fds, c->sock_wfd->fd); ssl_can_rd = s_poll_canread(c->fds, c->ssl_rfd->fd); ssl_can_wr = s_poll_canwrite(c->fds, c->ssl_wfd->fd); if (!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) { s_log(LOG_ERR, "INTERNAL ERROR: " "s_poll_wait returned %d, but no descriptor is ready", err); longjmp(c->err, 1); } if (shutdown_wants_read || shutdown_wants_write) { num = SSL_shutdown(c->ssl); if (num < 0) err = SSL_get_error(c->ssl, num); else err = SSL_ERROR_NONE; switch (err) { case SSL_ERROR_NONE: s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify alert"); shutdown_wants_read = shutdown_wants_write = 0; break; case SSL_ERROR_SYSCALL: if (parse_socket_error(c, "SSL_shutdown")) break; SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); shutdown_wants_read = shutdown_wants_write = 0; break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_WRITE: retrying"); shutdown_wants_read = 0; shutdown_wants_write = 1; break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_READ: retrying"); shutdown_wants_read = 1; shutdown_wants_write = 0; break; case SSL_ERROR_SSL: sslerror("SSL_shutdown"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err); longjmp(c->err, 1); } } if (sock_open_rd && sock_can_rd) { num = readsocket(c->sock_rfd->fd, c->sock_buff + c->sock_ptr, BUFFSIZE - c->sock_ptr); switch (num) { case -1: if (parse_socket_error(c, "readsocket")) break; case 0: s_log(LOG_DEBUG, "Socket closed on read"); sock_open_rd = 0; break; default: c->sock_ptr += num; watchdog = 0; } } if (sock_open_wr && sock_can_wr) { num = writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr); switch (num) { case -1: if (parse_socket_error(c, "writesocket")) break; case 0: s_log(LOG_DEBUG, "Socket closed on write"); sock_open_rd = sock_open_wr = 0; break; default: memmove(c->ssl_buff, c->ssl_buff + num, c->ssl_ptr - num); c->ssl_ptr -= num; c->sock_bytes += num; watchdog = 0; } } read_wants_read = !(SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN) && c->ssl_ptr < BUFFSIZE && !read_wants_write; write_wants_write = !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; if ((read_wants_read && (ssl_can_rd || SSL_pending(c->ssl))) || (read_wants_write && ssl_can_wr)) { read_wants_write = 0; num = SSL_read(c->ssl, c->ssl_buff + c->ssl_ptr, BUFFSIZE - c->ssl_ptr); switch (err = SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: if (num == 0) s_log(LOG_DEBUG, "SSL_read returned 0"); c->ssl_ptr += num; watchdog = 0; break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying"); read_wants_write = 1; break; case SSL_ERROR_WANT_READ: break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_read returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if (num && parse_socket_error(c, "SSL_read")) break; if (c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed on SSL_read with %d unsent byte(s)", c->sock_ptr); longjmp(c->err, 1); } s_log(LOG_DEBUG, "SSL socket closed on SSL_read"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: s_log(LOG_DEBUG, "SSL closed on SSL_read"); if (SSL_version(c->ssl) == SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_SSL: sslerror("SSL_read"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); longjmp(c->err, 1); } } if ((write_wants_read && ssl_can_rd) || (write_wants_write && ssl_can_wr)) { write_wants_read = 0; num = SSL_write(c->ssl, c->sock_buff, c->sock_ptr); switch (err = SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: if (num == 0) s_log(LOG_DEBUG, "SSL_write returned 0"); memmove(c->sock_buff, c->sock_buff + num, c->sock_ptr - num); c->sock_ptr -= num; c->ssl_bytes += num; watchdog = 0; break; case SSL_ERROR_WANT_WRITE: break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying"); write_wants_read = 1; break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_write returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if (num && parse_socket_error(c, "SSL_write")) break; if (c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed on SSL_write with %d unsent byte(s)", c->sock_ptr); longjmp(c->err, 1); } s_log(LOG_DEBUG, "SSL socket closed on SSL_write"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: s_log(LOG_DEBUG, "SSL closed on SSL_write"); if (SSL_version(c->ssl) == SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_SSL: sslerror("SSL_write"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); longjmp(c->err, 1); } } if (sock_open_wr && SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN && !c->ssl_ptr) { sock_open_wr = 0; if (!c->sock_wfd->is_socket) { s_log(LOG_DEBUG, "Closing the socket file descriptor"); sock_open_rd = 0; } else if (!shutdown(c->sock_wfd->fd, SHUT_WR)) { s_log(LOG_DEBUG, "Sent socket write shutdown"); } else { s_log(LOG_DEBUG, "Failed to send socket write shutdown"); sock_open_rd = 0; } } if (!(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) && !sock_open_rd && !c->sock_ptr) { if (SSL_version(c->ssl) != SSL2_VERSION) { s_log(LOG_DEBUG, "Sending close_notify alert"); shutdown_wants_write = 1; } else { s_log(LOG_DEBUG, "Closing SSLv2 socket"); if (c->ssl_rfd->is_socket) shutdown(c->ssl_rfd->fd, SHUT_RD); if (c->ssl_wfd->is_socket) shutdown(c->ssl_wfd->fd, SHUT_WR); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); } } if (++watchdog > 100) { s_log(LOG_ERR, "transfer() loop executes not transferring any data"); wifisec_info(LOG_ERR); s_log(LOG_ERR, "protocol=%s, SSL_pending=%d", SSL_get_version(c->ssl), SSL_pending(c->ssl)); s_log(LOG_ERR, "sock_open_rd=%s, sock_open_wr=%s", sock_open_rd ? "Y" : "n", sock_open_wr ? "Y" : "n"); s_log(LOG_ERR, "SSL_RECEIVED_SHUTDOWN=%s, SSL_SENT_SHUTDOWN=%s", SSL_get_shutdown(c->ssl) & SSL_RECEIVED_SHUTDOWN ? "Y" : "n", SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN ? "Y" : "n"); s_log(LOG_ERR, "sock_can_rd=%s, sock_can_wr=%s", sock_can_rd ? "Y" : "n", sock_can_wr ? "Y" : "n"); s_log(LOG_ERR, "ssl_can_rd=%s, ssl_can_wr=%s", ssl_can_rd ? "Y" : "n", ssl_can_wr ? "Y" : "n"); s_log(LOG_ERR, "read_wants_read=%s, read_wants_write=%s", read_wants_read ? "Y" : "n", read_wants_write ? "Y" : "n"); s_log(LOG_ERR, "write_wants_read=%s, write_wants_write=%s", write_wants_read ? "Y" : "n", write_wants_write ? "Y" : "n"); s_log(LOG_ERR, "shutdown_wants_read=%s, shutdown_wants_write=%s", shutdown_wants_read ? "Y" : "n", shutdown_wants_write ? "Y" : "n"); s_log(LOG_ERR, "socket input buffer: %d byte(s), " "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr); longjmp(c->err, 1); } } while (sock_open_wr || !(SSL_get_shutdown(c->ssl) & SSL_SENT_SHUTDOWN) || shutdown_wants_read || shutdown_wants_write); }
static HANDSHAKE_RESULT *do_handshake_internal( SSL_CTX *server_ctx, SSL_CTX *server2_ctx, SSL_CTX *client_ctx, const SSL_TEST_CTX *test_ctx, SSL_SESSION *session_in, SSL_SESSION **session_out) { SSL *server, *client; BIO *client_to_server, *server_to_client; HANDSHAKE_EX_DATA server_ex_data, client_ex_data; CTX_DATA client_ctx_data, server_ctx_data, server2_ctx_data; HANDSHAKE_RESULT *ret = HANDSHAKE_RESULT_new(); int client_turn = 1, shutdown = 0; peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY; handshake_status_t status = HANDSHAKE_RETRY; unsigned char* tick = NULL; size_t tick_len = 0; SSL_SESSION* sess = NULL; const unsigned char *proto = NULL; /* API dictates unsigned int rather than size_t. */ unsigned int proto_len = 0; memset(&server_ctx_data, 0, sizeof(server_ctx_data)); memset(&server2_ctx_data, 0, sizeof(server2_ctx_data)); memset(&client_ctx_data, 0, sizeof(client_ctx_data)); configure_handshake_ctx(server_ctx, server2_ctx, client_ctx, test_ctx, &server_ctx_data, &server2_ctx_data, &client_ctx_data); server = SSL_new(server_ctx); client = SSL_new(client_ctx); OPENSSL_assert(server != NULL && client != NULL); configure_handshake_ssl(server, client, test_ctx); if (session_in != NULL) { /* In case we're testing resumption without tickets. */ OPENSSL_assert(SSL_CTX_add_session(server_ctx, session_in)); OPENSSL_assert(SSL_set_session(client, session_in)); } memset(&server_ex_data, 0, sizeof(server_ex_data)); memset(&client_ex_data, 0, sizeof(client_ex_data)); ret->result = SSL_TEST_INTERNAL_ERROR; client_to_server = BIO_new(BIO_s_mem()); server_to_client = BIO_new(BIO_s_mem()); OPENSSL_assert(client_to_server != NULL && server_to_client != NULL); /* Non-blocking bio. */ BIO_set_nbio(client_to_server, 1); BIO_set_nbio(server_to_client, 1); SSL_set_connect_state(client); SSL_set_accept_state(server); /* The bios are now owned by the SSL object. */ SSL_set_bio(client, server_to_client, client_to_server); OPENSSL_assert(BIO_up_ref(server_to_client) > 0); OPENSSL_assert(BIO_up_ref(client_to_server) > 0); SSL_set_bio(server, client_to_server, server_to_client); ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL); OPENSSL_assert(ex_data_idx >= 0); OPENSSL_assert(SSL_set_ex_data(server, ex_data_idx, &server_ex_data) == 1); OPENSSL_assert(SSL_set_ex_data(client, ex_data_idx, &client_ex_data) == 1); SSL_set_info_callback(server, &info_cb); SSL_set_info_callback(client, &info_cb); /* * Half-duplex handshake loop. * Client and server speak to each other synchronously in the same process. * We use non-blocking BIOs, so whenever one peer blocks for read, it * returns PEER_RETRY to indicate that it's the other peer's turn to write. * The handshake succeeds once both peers have succeeded. If one peer * errors out, we also let the other peer retry (and presumably fail). */ for(;;) { if (client_turn) { client_status = do_handshake_step(client, shutdown); status = handshake_status(client_status, server_status, 1 /* client went last */); } else { server_status = do_handshake_step(server, shutdown); status = handshake_status(server_status, client_status, 0 /* server went last */); } switch (status) { case HANDSHAKE_SUCCESS: if (shutdown) { ret->result = SSL_TEST_SUCCESS; goto err; } else { client_status = server_status = PEER_RETRY; shutdown = 1; client_turn = 1; break; } case CLIENT_ERROR: ret->result = SSL_TEST_CLIENT_FAIL; goto err; case SERVER_ERROR: ret->result = SSL_TEST_SERVER_FAIL; goto err; case INTERNAL_ERROR: ret->result = SSL_TEST_INTERNAL_ERROR; goto err; case HANDSHAKE_RETRY: /* Continue. */ client_turn ^= 1; break; } } err: ret->server_alert_sent = server_ex_data.alert_sent; ret->server_alert_received = client_ex_data.alert_received; ret->client_alert_sent = client_ex_data.alert_sent; ret->client_alert_received = server_ex_data.alert_received; ret->server_protocol = SSL_version(server); ret->client_protocol = SSL_version(client); ret->servername = server_ex_data.servername; if ((sess = SSL_get0_session(client)) != NULL) SSL_SESSION_get0_ticket(sess, &tick, &tick_len); if (tick == NULL || tick_len == 0) ret->session_ticket = SSL_TEST_SESSION_TICKET_NO; else ret->session_ticket = SSL_TEST_SESSION_TICKET_YES; ret->session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call; SSL_get0_next_proto_negotiated(client, &proto, &proto_len); ret->client_npn_negotiated = dup_str(proto, proto_len); SSL_get0_next_proto_negotiated(server, &proto, &proto_len); ret->server_npn_negotiated = dup_str(proto, proto_len); SSL_get0_alpn_selected(client, &proto, &proto_len); ret->client_alpn_negotiated = dup_str(proto, proto_len); SSL_get0_alpn_selected(server, &proto, &proto_len); ret->server_alpn_negotiated = dup_str(proto, proto_len); ret->client_resumed = SSL_session_reused(client); ret->server_resumed = SSL_session_reused(server); if (session_out != NULL) *session_out = SSL_get1_session(client); ctx_data_free_data(&server_ctx_data); ctx_data_free_data(&server2_ctx_data); ctx_data_free_data(&client_ctx_data); SSL_free(server); SSL_free(client); return ret; }
/****************************** transfer data */ static void transfer(CLI *c) { int watchdog=0; /* a counter to detect an infinite loop */ int num, err; /* logical channels (not file descriptors!) open for read or write */ int sock_open_rd=1, sock_open_wr=1; /* awaited conditions on SSL file descriptors */ int shutdown_wants_read=0, shutdown_wants_write=0; int read_wants_read, read_wants_write=0; int write_wants_read=0, write_wants_write; /* actual conditions on file descriptors */ int sock_can_rd, sock_can_wr, ssl_can_rd, ssl_can_wr; c->sock_ptr=c->ssl_ptr=0; do { /* main loop of client data transfer */ /****************************** initialize *_wants_* */ read_wants_read=!(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN) && c->ssl_ptr<BUFFSIZE && !read_wants_write; write_wants_write=!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; /****************************** setup c->fds structure */ s_poll_init(c->fds); /* initialize the structure */ /* for plain socket open data strem = open file descriptor */ /* make sure to add each open socket to receive exceptions! */ if(sock_open_rd) s_poll_add(c->fds, c->sock_rfd->fd, c->sock_ptr<BUFFSIZE, 0); if(sock_open_wr) s_poll_add(c->fds, c->sock_wfd->fd, 0, c->ssl_ptr); /* for SSL assume that sockets are open if there any pending requests */ if(read_wants_read || write_wants_read || shutdown_wants_read) s_poll_add(c->fds, c->ssl_rfd->fd, 1, 0); if(read_wants_write || write_wants_write || shutdown_wants_write) s_poll_add(c->fds, c->ssl_wfd->fd, 0, 1); /****************************** wait for an event */ err=s_poll_wait(c->fds, (sock_open_rd && /* both peers open */ !(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr /* data buffered to write to socket */ || c->sock_ptr /* data buffered to write to SSL */ ? c->opt->timeout_idle : c->opt->timeout_close, 0); switch(err) { case -1: sockerror("transfer: s_poll_wait"); longjmp(c->err, 1); case 0: /* timeout */ if((sock_open_rd && !(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN)) || c->ssl_ptr || c->sock_ptr) { s_log(LOG_INFO, "transfer: s_poll_wait:" " TIMEOUTidle exceeded: sending reset"); longjmp(c->err, 1); } else { /* already closing connection */ s_log(LOG_ERR, "transfer: s_poll_wait:" " TIMEOUTclose exceeded: closing"); return; /* OK */ } } /****************************** check for errors on sockets */ err=s_poll_error(c->fds, c->sock_rfd); if(err) { s_log(LOG_NOTICE, "Error detected on socket (read) file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } if(c->sock_wfd->fd != c->sock_rfd->fd) { /* performance optimization */ err=s_poll_error(c->fds, c->sock_wfd); if(err) { s_log(LOG_NOTICE, "Error detected on socket write file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } } err=s_poll_error(c->fds, c->ssl_rfd); if(err) { s_log(LOG_NOTICE, "Error detected on SSL (read) file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } if(c->ssl_wfd->fd != c->ssl_rfd->fd) { /* performance optimization */ err=s_poll_error(c->fds, c->ssl_wfd); if(err) { s_log(LOG_NOTICE, "Error detected on SSL write file descriptor: %s (%d)", s_strerror(err), err); longjmp(c->err, 1); } } /****************************** retrieve results from c->fds */ sock_can_rd=s_poll_canread(c->fds, c->sock_rfd->fd); sock_can_wr=s_poll_canwrite(c->fds, c->sock_wfd->fd); ssl_can_rd=s_poll_canread(c->fds, c->ssl_rfd->fd); ssl_can_wr=s_poll_canwrite(c->fds, c->ssl_wfd->fd); /****************************** checks for internal failures */ /* please report any internal errors to stunnel-users mailing list */ if(!(sock_can_rd || sock_can_wr || ssl_can_rd || ssl_can_wr)) { s_log(LOG_ERR, "INTERNAL ERROR: " "s_poll_wait returned %d, but no descriptor is ready", err); longjmp(c->err, 1); } /****************************** send SSL close_notify alert */ if(shutdown_wants_read || shutdown_wants_write) { num=SSL_shutdown(c->ssl); /* send close_notify alert */ if(num<0) /* -1 - not completed */ err=SSL_get_error(c->ssl, num); else /* 0 or 1 - success */ err=SSL_ERROR_NONE; switch(err) { case SSL_ERROR_NONE: /* the shutdown was successfully completed */ s_log(LOG_INFO, "SSL_shutdown successfully sent close_notify alert"); shutdown_wants_read=shutdown_wants_write=0; break; case SSL_ERROR_SYSCALL: /* socket error */ if(parse_socket_error(c, "SSL_shutdown")) break; /* a non-critical error: retry */ SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); shutdown_wants_read=shutdown_wants_write=0; break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_WRITE: retrying"); shutdown_wants_read=0; shutdown_wants_write=1; break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_shutdown returned WANT_READ: retrying"); shutdown_wants_read=1; shutdown_wants_write=0; break; case SSL_ERROR_SSL: /* SSL error */ sslerror("SSL_shutdown"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_shutdown/SSL_get_error returned %d", err); longjmp(c->err, 1); } } /****************************** read from socket */ if(sock_open_rd && sock_can_rd) { num=readsocket(c->sock_rfd->fd, c->sock_buff+c->sock_ptr, BUFFSIZE-c->sock_ptr); switch(num) { case -1: if(parse_socket_error(c, "readsocket")) break; /* a non-critical error: retry */ case 0: /* close */ s_log(LOG_DEBUG, "Socket closed on read"); sock_open_rd=0; break; default: c->sock_ptr+=num; watchdog=0; /* reset watchdog */ } } /****************************** write to socket */ if(sock_open_wr && sock_can_wr) { num=writesocket(c->sock_wfd->fd, c->ssl_buff, c->ssl_ptr); switch(num) { case -1: /* error */ if(parse_socket_error(c, "writesocket")) break; /* a non-critical error: retry */ case 0: s_log(LOG_DEBUG, "Socket closed on write"); sock_open_rd=sock_open_wr=0; break; default: memmove(c->ssl_buff, c->ssl_buff+num, c->ssl_ptr-num); c->ssl_ptr-=num; c->sock_bytes+=num; watchdog=0; /* reset watchdog */ } } /****************************** update *_wants_* based on new *_ptr */ /* this update is also required for SSL_pending() to be used */ read_wants_read=!(SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN) && c->ssl_ptr<BUFFSIZE && !read_wants_write; write_wants_write=!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) && c->sock_ptr && !write_wants_read; /****************************** read from SSL */ if((read_wants_read && (ssl_can_rd || SSL_pending(c->ssl))) || /* it may be possible to read some pending data after * writesocket() above made some room in c->ssl_buff */ (read_wants_write && ssl_can_wr)) { read_wants_write=0; num=SSL_read(c->ssl, c->ssl_buff+c->ssl_ptr, BUFFSIZE-c->ssl_ptr); switch(err=SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: if(num==0) s_log(LOG_DEBUG, "SSL_read returned 0"); c->ssl_ptr+=num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: s_log(LOG_DEBUG, "SSL_read returned WANT_WRITE: retrying"); read_wants_write=1; break; case SSL_ERROR_WANT_READ: /* nothing unexpected */ break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_read returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: if(num && parse_socket_error(c, "SSL_read")) break; /* a non-critical error: retry */ /* EOF -> buggy (e.g. Microsoft) peer: * SSL socket closed without close_notify alert */ if(c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed on SSL_read with %d unsent byte(s)", c->sock_ptr); longjmp(c->err, 1); /* reset the socket */ } s_log(LOG_DEBUG, "SSL socket closed on SSL_read"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: /* close_notify alert received */ s_log(LOG_DEBUG, "SSL closed on SSL_read"); #ifndef HAVE_LIB_CYASSL if(SSL_version(c->ssl)==SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); #endif break; case SSL_ERROR_SSL: sslerror("SSL_read"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_read/SSL_get_error returned %d", err); longjmp(c->err, 1); } } /****************************** write to SSL */ if((write_wants_read && ssl_can_rd) || (write_wants_write && ssl_can_wr)) { write_wants_read=0; num=SSL_write(c->ssl, c->sock_buff, c->sock_ptr); switch(err=SSL_get_error(c->ssl, num)) { case SSL_ERROR_NONE: if(num==0) s_log(LOG_DEBUG, "SSL_write returned 0"); memmove(c->sock_buff, c->sock_buff+num, c->sock_ptr-num); c->sock_ptr-=num; c->ssl_bytes+=num; watchdog=0; /* reset watchdog */ break; case SSL_ERROR_WANT_WRITE: /* nothing unexpected */ break; case SSL_ERROR_WANT_READ: s_log(LOG_DEBUG, "SSL_write returned WANT_READ: retrying"); write_wants_read=1; break; case SSL_ERROR_WANT_X509_LOOKUP: s_log(LOG_DEBUG, "SSL_write returned WANT_X509_LOOKUP: retrying"); break; case SSL_ERROR_SYSCALL: /* socket error */ if(num && parse_socket_error(c, "SSL_write")) break; /* a non-critical error: retry */ /* EOF -> buggy (e.g. Microsoft) peer: * SSL socket closed without close_notify alert */ if(c->sock_ptr) { s_log(LOG_ERR, "SSL socket closed on SSL_write with %d unsent byte(s)", c->sock_ptr); longjmp(c->err, 1); /* reset the socket */ } s_log(LOG_DEBUG, "SSL socket closed on SSL_write"); SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); break; case SSL_ERROR_ZERO_RETURN: /* close_notify alert received */ s_log(LOG_DEBUG, "SSL closed on SSL_write"); #ifndef HAVE_LIB_CYASSL if(SSL_version(c->ssl)==SSL2_VERSION) SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); #endif break; case SSL_ERROR_SSL: sslerror("SSL_write"); longjmp(c->err, 1); default: s_log(LOG_ERR, "SSL_write/SSL_get_error returned %d", err); longjmp(c->err, 1); } } /****************************** check write shutdown conditions */ if(sock_open_wr && SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN && !c->ssl_ptr) { sock_open_wr=0; /* no further write allowed */ if(!c->sock_wfd->is_socket) { s_log(LOG_DEBUG, "Closing the socket file descriptor"); sock_open_rd=0; /* file descriptor is ready to be closed */ } else if(!shutdown(c->sock_wfd->fd, SHUT_WR)) { /* send TCP FIN */ s_log(LOG_DEBUG, "Sent socket write shutdown"); } else { s_log(LOG_DEBUG, "Failed to send socket write shutdown"); sock_open_rd=0; /* file descriptor is ready to be closed */ } } if(!(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) && !sock_open_rd && !c->sock_ptr) { #ifndef HAVE_LIB_CYASSL if(SSL_version(c->ssl)!=SSL2_VERSION) { /* SSLv3, TLSv1 */ #endif s_log(LOG_DEBUG, "Sending close_notify alert"); shutdown_wants_write=1; #ifndef HAVE_LIB_CYASSL } else { /* no alerts in SSLv2, including the close_notify alert */ s_log(LOG_DEBUG, "Closing SSLv2 socket"); if(c->ssl_rfd->is_socket) shutdown(c->ssl_rfd->fd, SHUT_RD); /* notify the kernel */ if(c->ssl_wfd->is_socket) shutdown(c->ssl_wfd->fd, SHUT_WR); /* send TCP FIN */ /* notify the OpenSSL library */ SSL_set_shutdown(c->ssl, SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); } #endif } /****************************** check watchdog */ if(++watchdog>100) { /* loop executes without transferring any data */ s_log(LOG_ERR, "transfer() loop executes not transferring any data"); s_log(LOG_ERR, "please report the problem to [email protected]"); stunnel_info(LOG_ERR); s_log(LOG_ERR, "protocol=%s, SSL_pending=%d", SSL_get_version(c->ssl), SSL_pending(c->ssl)); s_log(LOG_ERR, "sock_open_rd=%s, sock_open_wr=%s", sock_open_rd ? "Y" : "n", sock_open_wr ? "Y" : "n"); s_log(LOG_ERR, "SSL_RECEIVED_SHUTDOWN=%s, SSL_SENT_SHUTDOWN=%s", SSL_get_shutdown(c->ssl)&SSL_RECEIVED_SHUTDOWN ? "Y" : "n", SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN ? "Y" : "n"); s_log(LOG_ERR, "sock_can_rd=%s, sock_can_wr=%s", sock_can_rd ? "Y" : "n", sock_can_wr ? "Y" : "n"); s_log(LOG_ERR, "ssl_can_rd=%s, ssl_can_wr=%s", ssl_can_rd ? "Y" : "n", ssl_can_wr ? "Y" : "n"); s_log(LOG_ERR, "read_wants_read=%s, read_wants_write=%s", read_wants_read ? "Y" : "n", read_wants_write ? "Y" : "n"); s_log(LOG_ERR, "write_wants_read=%s, write_wants_write=%s", write_wants_read ? "Y" : "n", write_wants_write ? "Y" : "n"); s_log(LOG_ERR, "shutdown_wants_read=%s, shutdown_wants_write=%s", shutdown_wants_read ? "Y" : "n", shutdown_wants_write ? "Y" : "n"); s_log(LOG_ERR, "socket input buffer: %d byte(s), " "ssl input buffer: %d byte(s)", c->sock_ptr, c->ssl_ptr); longjmp(c->err, 1); } } while(sock_open_wr || !(SSL_get_shutdown(c->ssl)&SSL_SENT_SHUTDOWN) || shutdown_wants_read || shutdown_wants_write); }
static int http_serve(SSL *ssl, int s) { char buf[BUFSIZZ]; int r,len; BIO *io,*ssl_bio; io=BIO_new(BIO_f_buffer()); ssl_bio=BIO_new(BIO_f_ssl()); BIO_set_ssl(ssl_bio,ssl,BIO_CLOSE); BIO_push(io,ssl_bio); r=BIO_gets(io,buf,BUFSIZZ-1); switch(SSL_get_error(ssl,r)){ case SSL_ERROR_NONE: len=r; break; default: berr_exit("SSL read problem"); } char *saveptr; char resource[512] = {'\0'}; char *token = strtok_r(buf, " ", &saveptr); if (token && strcasecmp(token, "GET") == 0) { token = strtok_r(NULL, " ", &saveptr); if (token) { strncpy(resource, token, sizeof(resource)); } } if (resource[0]) { while(1){ r=BIO_gets(io,buf,BUFSIZZ-1); switch(SSL_get_error(ssl,r)){ case SSL_ERROR_NONE: len=r; break; default: berr_exit("SSL read problem"); } /* Look for the blank line that signals the end of the HTTP headers */ if(!strcmp(buf,"\r\n") || !strcmp(buf,"\n")) break; } } if (strcasecmp(resource, "/ciphersuites.txt") == 0) { http_serve_headers(io, 200, "OK", "text/plain"); print_ciphersuite_data(io, ssl, 0); } else if (strcasecmp(resource, "/ciphersuites.js") == 0) { long protocol = SSL_version(ssl); http_serve_headers(io, 200, "OK", "text/javascript"); if(BIO_printf(io, "$(function() {\n insert_text('%s', '", get_protocol_name(protocol)) <= 0) err_exit("Write error"); print_ciphersuite_data(io, ssl, 1); if(BIO_printf(io, "');\n});") <= 0) err_exit("Write error"); } else { http_serve_headers(io, 404, "Not Found", "text/plain"); if(BIO_puts(io, "Not found.") <= 0) err_exit("Write error"); } if((r=BIO_flush(io))<0) err_exit("Error flushing BIO"); r=SSL_shutdown(ssl); if(!r){ /* If we called SSL_shutdown() first then we always get return value of '0'. In this case, try again, but first send a TCP FIN to trigger the other side's close_notify*/ shutdown(s,1); r=SSL_shutdown(ssl); } switch(r){ case 1: break; /* Success */ case 0: case -1: default: berr_exit("Shutdown failed"); } SSL_free(ssl); close(s); return(0); }
MONO_API int mono_btls_ssl_get_version (MonoBtlsSsl *ptr) { return SSL_version (ptr->ssl); }
int s_time_main(int argc, char **argv) { char buf[1024 * 8]; SSL *scon = NULL; SSL_CTX *ctx = NULL; const SSL_METHOD *meth = NULL; char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *ciphersuites = NULL; char *www_path = NULL; char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog; double totalTime = 0.0; int noCApath = 0, noCAfile = 0; int maxtime = SECONDS, nConn = 0, perform = 3, ret = 1, i, st_bugs = 0; long bytes_read = 0, finishtime = 0; OPTION_CHOICE o; int max_version = 0, ver, buf_len; size_t buf_size; meth = TLS_client_method(); prog = opt_init(argc, argv, s_time_options); while ((o = opt_next()) != OPT_EOF) { switch (o) { case OPT_EOF: case OPT_ERR: opthelp: BIO_printf(bio_err, "%s: Use -help for summary.\n", prog); goto end; case OPT_HELP: opt_help(s_time_options); ret = 0; goto end; case OPT_CONNECT: host = opt_arg(); break; case OPT_REUSE: perform = 2; break; case OPT_NEW: perform = 1; break; case OPT_VERIFY: if (!opt_int(opt_arg(), &verify_args.depth)) goto opthelp; BIO_printf(bio_err, "%s: verify depth is %d\n", prog, verify_args.depth); break; case OPT_CERT: certfile = opt_arg(); break; case OPT_NAMEOPT: if (!set_nameopt(opt_arg())) goto end; break; case OPT_KEY: keyfile = opt_arg(); break; case OPT_CAPATH: CApath = opt_arg(); break; case OPT_CAFILE: CAfile = opt_arg(); break; case OPT_NOCAPATH: noCApath = 1; break; case OPT_NOCAFILE: noCAfile = 1; break; case OPT_CIPHER: cipher = opt_arg(); break; case OPT_CIPHERSUITES: ciphersuites = opt_arg(); break; case OPT_BUGS: st_bugs = 1; break; case OPT_TIME: if (!opt_int(opt_arg(), &maxtime)) goto opthelp; break; case OPT_WWW: www_path = opt_arg(); buf_size = strlen(www_path) + fmt_http_get_cmd_size; if (buf_size > sizeof(buf)) { BIO_printf(bio_err, "%s: -www option is too long\n", prog); goto end; } break; case OPT_SSL3: max_version = SSL3_VERSION; break; } } argc = opt_num_rest(); if (argc != 0) goto opthelp; if (cipher == NULL) cipher = getenv("SSL_CIPHER"); if ((ctx = SSL_CTX_new(meth)) == NULL) goto end; SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_quiet_shutdown(ctx, 1); if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0) goto end; if (st_bugs) SSL_CTX_set_options(ctx, SSL_OP_ALL); if (cipher != NULL && !SSL_CTX_set_cipher_list(ctx, cipher)) goto end; if (ciphersuites != NULL && !SSL_CTX_set_ciphersuites(ctx, ciphersuites)) goto end; if (!set_cert_stuff(ctx, certfile, keyfile)) goto end; if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) { ERR_print_errors(bio_err); goto end; } if (!(perform & 1)) goto next; printf("Collecting connection statistics for %d seconds\n", maxtime); /* Loop and time how long it takes to make connections */ bytes_read = 0; finishtime = (long)time(NULL) + maxtime; tm_Time_F(START); for (;;) { if (finishtime < (long)time(NULL)) break; if ((scon = doConnection(NULL, host, ctx)) == NULL) goto end; if (www_path != NULL) { buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, www_path); if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) goto end; while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); BIO_closesocket(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) { ver = 'r'; } else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); SSL_free(scon); scon = NULL; } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ i = (int)((long)time(NULL) - finishtime + maxtime); printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); printf ("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); /* * Now loop and time connections using the same session id over and over */ next: if (!(perform & 2)) goto end; printf("\n\nNow timing with session id reuse.\n"); /* Get an SSL object so we can reuse the session id */ if ((scon = doConnection(NULL, host, ctx)) == NULL) { BIO_printf(bio_err, "Unable to get connection\n"); goto end; } if (www_path != NULL) { buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, www_path); if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) goto end; while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) continue; } SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); BIO_closesocket(SSL_get_fd(scon)); nConn = 0; totalTime = 0.0; finishtime = (long)time(NULL) + maxtime; printf("starting\n"); bytes_read = 0; tm_Time_F(START); for (;;) { if (finishtime < (long)time(NULL)) break; if ((doConnection(scon, host, ctx)) == NULL) goto end; if (www_path != NULL) { buf_len = BIO_snprintf(buf, sizeof(buf), fmt_http_get_cmd, www_path); if (buf_len <= 0 || SSL_write(scon, buf, buf_len) <= 0) goto end; while ((i = SSL_read(scon, buf, sizeof(buf))) > 0) bytes_read += i; } SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); BIO_closesocket(SSL_get_fd(scon)); nConn += 1; if (SSL_session_reused(scon)) { ver = 'r'; } else { ver = SSL_version(scon); if (ver == TLS1_VERSION) ver = 't'; else if (ver == SSL3_VERSION) ver = '3'; else ver = '*'; } fputc(ver, stdout); fflush(stdout); } totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ printf ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn / totalTime), bytes_read); printf ("%d connections in %ld real seconds, %ld bytes read per connection\n", nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn); ret = 0; end: SSL_free(scon); SSL_CTX_free(ctx); return ret; }
HANDSHAKE_RESULT do_handshake(SSL_CTX *server_ctx, SSL_CTX *client_ctx, const SSL_TEST_CTX *test_ctx) { SSL *server, *client; BIO *client_to_server, *server_to_client; HANDSHAKE_EX_DATA server_ex_data, client_ex_data; HANDSHAKE_RESULT ret; int client_turn = 1; peer_status_t client_status = PEER_RETRY, server_status = PEER_RETRY; handshake_status_t status = HANDSHAKE_RETRY; unsigned char* tick = NULL; size_t len = 0; SSL_SESSION* sess = NULL; configure_handshake_ctx(server_ctx, client_ctx, test_ctx); server = SSL_new(server_ctx); client = SSL_new(client_ctx); OPENSSL_assert(server != NULL && client != NULL); configure_handshake_ssl(server, client, test_ctx); memset(&server_ex_data, 0, sizeof(server_ex_data)); memset(&client_ex_data, 0, sizeof(client_ex_data)); memset(&ret, 0, sizeof(ret)); ret.result = SSL_TEST_INTERNAL_ERROR; client_to_server = BIO_new(BIO_s_mem()); server_to_client = BIO_new(BIO_s_mem()); OPENSSL_assert(client_to_server != NULL && server_to_client != NULL); /* Non-blocking bio. */ BIO_set_nbio(client_to_server, 1); BIO_set_nbio(server_to_client, 1); SSL_set_connect_state(client); SSL_set_accept_state(server); /* The bios are now owned by the SSL object. */ SSL_set_bio(client, server_to_client, client_to_server); OPENSSL_assert(BIO_up_ref(server_to_client) > 0); OPENSSL_assert(BIO_up_ref(client_to_server) > 0); SSL_set_bio(server, client_to_server, server_to_client); ex_data_idx = SSL_get_ex_new_index(0, "ex data", NULL, NULL, NULL); OPENSSL_assert(ex_data_idx >= 0); OPENSSL_assert(SSL_set_ex_data(server, ex_data_idx, &server_ex_data) == 1); OPENSSL_assert(SSL_set_ex_data(client, ex_data_idx, &client_ex_data) == 1); SSL_set_info_callback(server, &info_callback); SSL_set_info_callback(client, &info_callback); /* * Half-duplex handshake loop. * Client and server speak to each other synchronously in the same process. * We use non-blocking BIOs, so whenever one peer blocks for read, it * returns PEER_RETRY to indicate that it's the other peer's turn to write. * The handshake succeeds once both peers have succeeded. If one peer * errors out, we also let the other peer retry (and presumably fail). */ for(;;) { if (client_turn) { client_status = do_handshake_step(client); status = handshake_status(client_status, server_status, 1 /* client went last */); } else { server_status = do_handshake_step(server); status = handshake_status(server_status, client_status, 0 /* server went last */); } switch (status) { case HANDSHAKE_SUCCESS: ret.result = SSL_TEST_SUCCESS; goto err; case CLIENT_ERROR: ret.result = SSL_TEST_CLIENT_FAIL; goto err; case SERVER_ERROR: ret.result = SSL_TEST_SERVER_FAIL; goto err; case INTERNAL_ERROR: ret.result = SSL_TEST_INTERNAL_ERROR; goto err; case HANDSHAKE_RETRY: /* Continue. */ client_turn ^= 1; break; } } err: ret.server_alert_sent = server_ex_data.alert_sent; ret.server_alert_received = client_ex_data.alert_received; ret.client_alert_sent = client_ex_data.alert_sent; ret.client_alert_received = server_ex_data.alert_received; ret.server_protocol = SSL_version(server); ret.client_protocol = SSL_version(client); ret.servername = ((SSL_get_SSL_CTX(server) == server_ctx) ? SSL_TEST_SERVERNAME_SERVER1 : SSL_TEST_SERVERNAME_SERVER2); if ((sess = SSL_get0_session(client)) != NULL) SSL_SESSION_get0_ticket(sess, &tick, &len); if (tick == NULL || len == 0) ret.session_ticket = SSL_TEST_SESSION_TICKET_NO; else ret.session_ticket = SSL_TEST_SESSION_TICKET_YES; ret.session_ticket_do_not_call = server_ex_data.session_ticket_do_not_call; SSL_free(server); SSL_free(client); return ret; }
int MAIN(int argc, char **argv) { int off=0; SSL *con=NULL,*con2=NULL; X509_STORE *store = NULL; int s,k,width,state=0; char *cbuf=NULL,*sbuf=NULL,*mbuf=NULL; int cbuf_len,cbuf_off; int sbuf_len,sbuf_off; fd_set readfds,writefds; short port=PORT; int full_log=1; char *host=SSL_HOST_NAME; char *cert_file=NULL,*key_file=NULL; int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; char *passarg = NULL, *pass = NULL; X509 *cert = NULL; EVP_PKEY *key = NULL; char *CApath=NULL,*CAfile=NULL,*cipher=NULL; int reconnect=0,badop=0,verify=SSL_VERIFY_NONE,bugs=0; int crlf=0; 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 = PROTO_OFF; int prexit = 0, vflags = 0; SSL_METHOD *meth=NULL; #ifdef sock_type #undef sock_type #endif int sock_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) struct timeval tv; #endif struct sockaddr peer; int peerlen = sizeof(peer); int enable_timeouts = 0 ; long mtu = 0; #if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) meth=SSLv23_client_method(); #elif !defined(OPENSSL_NO_SSL3) meth=SSLv3_client_method(); #elif !defined(OPENSSL_NO_SSL2) meth=SSLv2_client_method(); #endif apps_startup(); c_Pause=0; c_quiet=0; c_ign_eof=0; c_debug=0; c_msg=0; c_showcerts=0; if (bio_err == NULL) bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); if (!load_config(bio_err, NULL)) goto end; if ( ((cbuf=OPENSSL_malloc(BUFSIZZ)) == NULL) || ((sbuf=OPENSSL_malloc(BUFSIZZ)) == NULL) || ((mbuf=OPENSSL_malloc(BUFSIZZ)) == NULL)) { BIO_printf(bio_err,"out of memory\n"); goto end; } verify_depth=0; verify_error=X509_V_OK; #ifdef FIONBIO c_nbio=0; #endif argc--; argv++; while (argc >= 1) { if (strcmp(*argv,"-host") == 0) { if (--argc < 1) goto bad; host= *(++argv); } else if (strcmp(*argv,"-port") == 0) { if (--argc < 1) goto bad; port=atoi(*(++argv)); if (port == 0) goto bad; } else if (strcmp(*argv,"-connect") == 0) { if (--argc < 1) goto bad; if (!extract_host_port(*(++argv),&host,NULL,&port)) goto bad; } else if (strcmp(*argv,"-verify") == 0) { verify=SSL_VERIFY_PEER; if (--argc < 1) goto bad; verify_depth=atoi(*(++argv)); BIO_printf(bio_err,"verify depth is %d\n",verify_depth); } else if (strcmp(*argv,"-cert") == 0) { if (--argc < 1) goto bad; cert_file= *(++argv); } else if (strcmp(*argv,"-certform") == 0) { if (--argc < 1) goto bad; cert_format = str2fmt(*(++argv)); } else if (strcmp(*argv,"-crl_check") == 0) 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,"-prexit") == 0) prexit=1; else if (strcmp(*argv,"-crlf") == 0) crlf=1; else if (strcmp(*argv,"-quiet") == 0) { c_quiet=1; c_ign_eof=1; } else if (strcmp(*argv,"-ign_eof") == 0) c_ign_eof=1; else if (strcmp(*argv,"-pause") == 0) c_Pause=1; else if (strcmp(*argv,"-debug") == 0) c_debug=1; #ifdef WATT32 else if (strcmp(*argv,"-wdebug") == 0) dbug_init(); #endif else if (strcmp(*argv,"-msg") == 0) c_msg=1; else if (strcmp(*argv,"-showcerts") == 0) c_showcerts=1; else if (strcmp(*argv,"-nbio_test") == 0) nbio_test=1; else if (strcmp(*argv,"-state") == 0) state=1; #ifndef OPENSSL_NO_SSL2 else if (strcmp(*argv,"-ssl2") == 0) meth=SSLv2_client_method(); #endif #ifndef OPENSSL_NO_SSL3 else if (strcmp(*argv,"-ssl3") == 0) meth=SSLv3_client_method(); #endif #ifndef OPENSSL_NO_TLS1 else if (strcmp(*argv,"-tls1") == 0) meth=TLSv1_client_method(); #endif #ifndef OPENSSL_NO_DTLS1 else if (strcmp(*argv,"-dtls1") == 0) { meth=DTLSv1_client_method(); sock_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)); } #endif else if (strcmp(*argv,"-bugs") == 0) bugs=1; else if (strcmp(*argv,"-keyform") == 0) { if (--argc < 1) goto bad; key_format = str2fmt(*(++argv)); } else if (strcmp(*argv,"-pass") == 0) { if (--argc < 1) goto bad; passarg = *(++argv); } else if (strcmp(*argv,"-key") == 0) { if (--argc < 1) goto bad; key_file= *(++argv); } else if (strcmp(*argv,"-reconnect") == 0) { reconnect=5; } else if (strcmp(*argv,"-CApath") == 0) { if (--argc < 1) goto bad; CApath= *(++argv); } else if (strcmp(*argv,"-CAfile") == 0) { if (--argc < 1) goto bad; CAfile= *(++argv); } else if (strcmp(*argv,"-no_tls1") == 0) off|=SSL_OP_NO_TLSv1; else if (strcmp(*argv,"-no_ssl3") == 0) off|=SSL_OP_NO_SSLv3; else if (strcmp(*argv,"-no_ssl2") == 0) off|=SSL_OP_NO_SSLv2; else if (strcmp(*argv,"-serverpref") == 0) off|=SSL_OP_CIPHER_SERVER_PREFERENCE; else if (strcmp(*argv,"-cipher") == 0) { if (--argc < 1) goto bad; cipher= *(++argv); } #ifdef FIONBIO else if (strcmp(*argv,"-nbio") == 0) { c_nbio=1; } #endif else if (strcmp(*argv,"-starttls") == 0) { if (--argc < 1) goto bad; ++argv; if (strcmp(*argv,"smtp") == 0) starttls_proto = PROTO_SMTP; else if (strcmp(*argv,"pop3") == 0) 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; } #ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv,"-engine") == 0) { if (--argc < 1) goto bad; engine_id = *(++argv); } #endif else if (strcmp(*argv,"-rand") == 0) { if (--argc < 1) goto bad; inrand= *(++argv); } else { BIO_printf(bio_err,"unknown option %s\n",*argv); badop=1; break; } argc--; argv++; } if (badop) { bad: sc_usage(); goto end; } OpenSSL_add_ssl_algorithms(); SSL_load_error_strings(); #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine_id, 1); #endif if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } if (key_file == NULL) key_file = cert_file; if (key_file) { key = load_key(bio_err, key_file, key_format, 0, pass, e, "client certificate private key file"); if (!key) { ERR_print_errors(bio_err); goto end; } } if (cert_file) { cert = load_cert(bio_err,cert_file,cert_format, NULL, e, "client certificate file"); if (!cert) { ERR_print_errors(bio_err); goto end; } } if (!app_RAND_load_file(NULL, bio_err, 1) && inrand == NULL && !RAND_status()) { BIO_printf(bio_err,"warning, not much extra random data, consider using the -rand option\n"); } if (inrand != NULL) BIO_printf(bio_err,"%ld semi-random bytes loaded\n", app_RAND_load_files(inrand)); if (bio_c_out == NULL) { if (c_quiet && !c_debug && !c_msg) { bio_c_out=BIO_new(BIO_s_null()); } else { if (bio_c_out == NULL) bio_c_out=BIO_new_fp(stdout,BIO_NOCLOSE); } } ctx=SSL_CTX_new(meth); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; } if (bugs) SSL_CTX_set_options(ctx,SSL_OP_ALL|off); else SSL_CTX_set_options(ctx,off); /* 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 (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); if (cipher != NULL) if(!SSL_CTX_set_cipher_list(ctx,cipher)) { BIO_printf(bio_err,"error setting cipher list\n"); ERR_print_errors(bio_err); goto end; } #if 0 else SSL_CTX_set_cipher_list(ctx,getenv("SSL_CIPHER")); #endif SSL_CTX_set_verify(ctx,verify,verify_callback); if (!set_cert_key_stuff(ctx,cert,key)) goto end; if ((!SSL_CTX_load_verify_locations(ctx,CAfile,CApath)) || (!SSL_CTX_set_default_verify_paths(ctx))) { /* BIO_printf(bio_err,"error setting default verify locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } store = SSL_CTX_get_cert_store(ctx); X509_STORE_set_flags(store, vflags); con=SSL_new(ctx); #ifndef OPENSSL_NO_KRB5 if (con && (con->kssl_ctx = kssl_ctx_new()) != NULL) { kssl_ctx_setstring(con->kssl_ctx, KSSL_SERVER, host); } #endif /* OPENSSL_NO_KRB5 */ /* SSL_set_cipher_list(con,"RC4-MD5"); */ re_start: if (init_client(&s,host,port,sock_type) == 0) { BIO_printf(bio_err,"connect:errno=%d\n",get_last_socket_error()); SHUTDOWN(s); goto end; } BIO_printf(bio_c_out,"CONNECTED(%08X)\n",s); #ifdef FIONBIO if (c_nbio) { unsigned long l=1; BIO_printf(bio_c_out,"turning on non blocking io\n"); if (BIO_socket_ioctl(s,FIONBIO,&l) < 0) { ERR_print_errors(bio_err); goto end; } } #endif if (c_Pause & 0x01) con->debug=1; if ( SSL_version(con) == DTLS1_VERSION) { struct timeval timeout; sbio=BIO_new_dgram(s,BIO_NOCLOSE); if (getsockname(s, &peer, (void *)&peerlen) < 0) { BIO_printf(bio_err, "getsockname:errno=%d\n", get_last_socket_error()); SHUTDOWN(s); goto end; } (void)BIO_ctrl_set_connected(sbio, 1, &peer); if ( enable_timeouts) { timeout.tv_sec = 0; timeout.tv_usec = DGRAM_RCV_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); timeout.tv_sec = 0; timeout.tv_usec = DGRAM_SND_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } if ( mtu > 0) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); SSL_set_mtu(con, mtu); } else /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); } else sbio=BIO_new_socket(s,BIO_NOCLOSE); if (nbio_test) { BIO *test; test=BIO_new(BIO_f_nbio_test()); sbio=BIO_push(test,sbio); } if (c_debug) { con->debug=1; BIO_set_callback(sbio,bio_dump_callback); BIO_set_callback_arg(sbio,(char *)bio_c_out); } if (c_msg) { SSL_set_msg_callback(con, msg_cb); SSL_set_msg_callback_arg(con, bio_c_out); } SSL_set_bio(con,sbio,sbio); SSL_set_connect_state(con); /* ok, lets connect */ width=SSL_get_fd(con)+1; read_tty=1; write_tty=0; tty_on=0; read_ssl=1; write_ssl=1; cbuf_len=0; cbuf_off=0; sbuf_len=0; sbuf_off=0; /* This is an ugly hack that does a lot of assumptions */ /* 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) { 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"); (void)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]=='-'); (void)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_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"); (void)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]!='.'); (void)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]=='-'); (void)BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); BIO_printf(sbio,"AUTH TLS\r\n"); BIO_read(sbio,sbuf,BUFSIZZ); } for (;;) { FD_ZERO(&readfds); FD_ZERO(&writefds); if (SSL_in_init(con) && !SSL_total_renegotiations(con)) { in_init=1; tty_on=0; } else { tty_on=1; if (in_init) { in_init=0; print_stuff(bio_c_out,con,full_log); if (full_log > 0) full_log--; if (starttls_proto) { BIO_printf(bio_err,"%s",mbuf); /* We don't need to know any more */ starttls_proto = PROTO_OFF; } if (reconnect) { reconnect--; BIO_printf(bio_c_out,"drop connection and then reconnect\n"); SSL_shutdown(con); SSL_set_connect_state(con); SHUTDOWN(SSL_get_fd(con)); goto re_start; } } } ssl_pending = read_ssl && SSL_pending(con); if (!ssl_pending) { #if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_NETWARE) if (tty_on) { if (read_tty) FD_SET(fileno(stdin),&readfds); if (write_tty) FD_SET(fileno(stdout),&writefds); } if (read_ssl) FD_SET(SSL_get_fd(con),&readfds); if (write_ssl) FD_SET(SSL_get_fd(con),&writefds); #else if(!tty_on || !write_tty) { if (read_ssl) FD_SET(SSL_get_fd(con),&readfds); if (write_ssl) FD_SET(SSL_get_fd(con),&writefds); } #endif /* printf("mode tty(%d %d%d) ssl(%d%d)\n", tty_on,read_tty,write_tty,read_ssl,write_ssl);*/ /* Note: under VMS with SOCKETSHR the second parameter * is currently of type (int *) whereas under other * systems it is (void *) if you don't have a cast it * will choke the compiler: if you do have a cast then * you can either go for (int *) or (void *). */ #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) /* Under Windows/DOS we make the assumption that we can * always write to the tty: therefore if we need to * write to the tty we just fall through. Otherwise * we timeout the select every second and see if there * are any keypresses. Note: this is a hack, in a proper * Windows application we wouldn't do this. */ i=0; if(!write_tty) { if(read_tty) { tv.tv_sec = 1; tv.tv_usec = 0; i=select(width,(void *)&readfds,(void *)&writefds, NULL,&tv); #if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS) if(!i && (!_kbhit() || !read_tty) ) continue; #else if(!i && (!((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !read_tty) ) continue; #endif } else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); } #elif defined(OPENSSL_SYS_NETWARE) if(!write_tty) { if(read_tty) { tv.tv_sec = 1; tv.tv_usec = 0; i=select(width,(void *)&readfds,(void *)&writefds, NULL,&tv); } else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); } #else i=select(width,(void *)&readfds,(void *)&writefds, NULL,NULL); #endif if ( i < 0) { BIO_printf(bio_err,"bad select %d\n", get_last_socket_error()); goto shut; /* goto end; */ } } if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds)) { k=SSL_write(con,&(cbuf[cbuf_off]), (unsigned int)cbuf_len); switch (SSL_get_error(con,k)) { case SSL_ERROR_NONE: cbuf_off+=k; cbuf_len-=k; if (k <= 0) goto end; /* we have done a write(con,NULL,0); */ if (cbuf_len <= 0) { read_tty=1; write_ssl=0; } else /* if (cbuf_len > 0) */ { read_tty=0; write_ssl=1; } break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out,"write W BLOCK\n"); write_ssl=1; read_tty=0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out,"write R BLOCK\n"); write_tty=0; read_ssl=1; write_ssl=0; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out,"write X BLOCK\n"); break; case SSL_ERROR_ZERO_RETURN: if (cbuf_len != 0) { BIO_printf(bio_c_out,"shutdown\n"); goto shut; } else { read_tty=1; write_ssl=0; break; } case SSL_ERROR_SYSCALL: if ((k != 0) || (cbuf_len != 0)) { BIO_printf(bio_err,"write:errno=%d\n", get_last_socket_error()); goto shut; } else { read_tty=1; write_ssl=0; } break; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; } } #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_NETWARE) /* Assume Windows/DOS can always write */ else if (!ssl_pending && write_tty) #else else if (!ssl_pending && FD_ISSET(fileno(stdout),&writefds)) #endif { #ifdef CHARSET_EBCDIC ascii2ebcdic(&(sbuf[sbuf_off]),&(sbuf[sbuf_off]),sbuf_len); #endif i=write(fileno(stdout),&(sbuf[sbuf_off]),sbuf_len); if (i <= 0) { BIO_printf(bio_c_out,"DONE\n"); goto shut; /* goto end; */ } sbuf_len-=i;; sbuf_off+=i; if (sbuf_len <= 0) { read_ssl=1; write_tty=0; } } else if (ssl_pending || FD_ISSET(SSL_get_fd(con),&readfds)) { #ifdef RENEG { static int iiii; if (++iiii == 52) { SSL_renegotiate(con); iiii=0; } } #endif #if 1 k=SSL_read(con,sbuf,1024 /* BUFSIZZ */ ); #else /* Demo for pending and peek :-) */ k=SSL_read(con,sbuf,16); { char zbuf[10240]; printf("read=%d pending=%d peek=%d\n",k,SSL_pending(con),SSL_peek(con,zbuf,10240)); } #endif switch (SSL_get_error(con,k)) { case SSL_ERROR_NONE: if (k <= 0) goto end; sbuf_off=0; sbuf_len=k; read_ssl=0; write_tty=1; break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out,"read W BLOCK\n"); write_ssl=1; read_tty=0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out,"read R BLOCK\n"); write_tty=0; read_ssl=1; if ((read_tty == 0) && (write_ssl == 0)) write_ssl=1; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out,"read X BLOCK\n"); break; case SSL_ERROR_SYSCALL: BIO_printf(bio_err,"read:errno=%d\n",get_last_socket_error()); goto shut; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_c_out,"closed\n"); goto shut; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; /* break; */ } } #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) #if defined(OPENSSL_SYS_WINCE) || defined(OPENSSL_SYS_MSDOS) else if (_kbhit()) #else else if ((_kbhit()) || (WAIT_OBJECT_0 == WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) #endif #elif defined (OPENSSL_SYS_NETWARE) else if (_kbhit()) #else else if (FD_ISSET(fileno(stdin),&readfds)) #endif { if (crlf) { int j, lf_num; i=read(fileno(stdin),cbuf,BUFSIZZ/2); lf_num = 0; /* both loops are skipped when i <= 0 */ for (j = 0; j < i; j++) if (cbuf[j] == '\n') lf_num++; for (j = i-1; j >= 0; j--) { cbuf[j+lf_num] = cbuf[j]; if (cbuf[j] == '\n') { lf_num--; i++; cbuf[j+lf_num] = '\r'; } } assert(lf_num == 0); } else i=read(fileno(stdin),cbuf,BUFSIZZ); if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { BIO_printf(bio_err,"DONE\n"); goto shut; } if ((!c_ign_eof) && (cbuf[0] == 'R')) { BIO_printf(bio_err,"RENEGOTIATING\n"); SSL_renegotiate(con); cbuf_len=0; } else { cbuf_len=i; cbuf_off=0; #ifdef CHARSET_EBCDIC ebcdic2ascii(cbuf, cbuf, i); #endif } write_ssl=1; read_tty=0; } } shut: 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 (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert); if (key) EVP_PKEY_free(key); if (pass) OPENSSL_free(pass); if (cbuf != NULL) { OPENSSL_cleanse(cbuf,BUFSIZZ); OPENSSL_free(cbuf); } if (sbuf != NULL) { OPENSSL_cleanse(sbuf,BUFSIZZ); OPENSSL_free(sbuf); } if (mbuf != NULL) { OPENSSL_cleanse(mbuf,BUFSIZZ); OPENSSL_free(mbuf); } if (bio_c_out != NULL) { BIO_free(bio_c_out); bio_c_out=NULL; } apps_shutdown(); OPENSSL_EXIT(ret); }
int dtls_get_data (int s, SSL_CTX *ctx) { char *buf = NULL; fd_set readfds; int ret = 1, width = 0; int i = 0; SSL *con = NULL; BIO *sbio = NULL; int bufsize = BUFSIZ; bio_err = BIO_new_fp (stderr, BIO_NOCLOSE); bio_s_out = BIO_new_fp (stderr, BIO_NOCLOSE); if ((buf = OPENSSL_malloc (bufsize)) == NULL) { BIO_printf (bio_err, "out of memory\n"); goto ERR; } if (con == NULL) { con = SSL_new(ctx); } SSL_clear (con); if (SSL_version (con) == DTLS1_VERSION) { struct timeval timeout; sbio = BIO_new_dgram (s, BIO_NOCLOSE); timeout.tv_sec = 5; timeout.tv_usec = 0; BIO_ctrl (sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); timeout.tv_sec = 5; timeout.tv_usec = 0; BIO_ctrl (sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); /* want to do MTU discovery */ BIO_ctrl (sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); /* turn on cookie exchange */ SSL_set_options (con, SSL_OP_COOKIE_EXCHANGE); // fprintf (stderr, "%s: %s(): DTLSv1 Initialization done\n", __FILE__, __func__); } SSL_set_bio (con, sbio, sbio); SSL_set_accept_state (con); /* SSL_set_fd(con,s); */ width = s + 1; for (;;) { int read_from_terminal; int read_from_sslcon; read_from_terminal = 0; read_from_sslcon = SSL_pending (con); if (!read_from_sslcon) { struct timeval tv; FD_ZERO(&readfds); FD_SET(s, &readfds); tv.tv_sec = 1; tv.tv_usec = 0; i = select(width, (void *)&readfds, NULL, NULL, &tv); if (i < 0) { continue; } if (FD_ISSET (s, &readfds)) { read_from_sslcon = 1; } else { ret = 2; goto shut; } } if (read_from_sslcon) { if (!SSL_is_init_finished(con)) { i = init_ssl_connection(con); if (i < 0) { ret = 0; goto ERR; } else if (i == 0) { ret = 1; goto ERR; } } else { AGAIN: i = SSL_read (con, (char *) buf, bufsize); switch (SSL_get_error (con, i)) { case SSL_ERROR_NONE: write (fileno (stdout), buf, (unsigned int) i); if (SSL_pending(con)) { fprintf (stderr, "%s: %s(): Some more seems to be coming... "\ "letz wait for that\n", __FILE__, __func__); goto AGAIN; } else fprintf (stderr, "%s(): Hey, itz all over boss... do finishing "\ "ceremony\n", __func__); ret = 0; goto ERR; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_s_out,"Read BLOCK\n"); break; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: BIO_printf(bio_s_out,"ERROR\n"); ERR_print_errors(bio_err); ret = 1; goto ERR; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_s_out,"\nDONE\n"); ret = 0; goto ERR; } } } } ERR: if (0 == ret) { char temp [] = "ACK from SERVER: READ SUCCESSFULLY DONE\n"; for (;;) { i = SSL_write (con, temp, strlen (temp)); switch (SSL_get_error (con, i)) { case SSL_ERROR_NONE: if (SSL_pending (con)) break; else goto WRITEDONE; case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf (bio_s_out, "Write BLOCK\n"); break; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: BIO_printf (bio_s_out, "ERROR\n"); ERR_print_errors (bio_err); ret = 1; goto WRITEDONE; case SSL_ERROR_ZERO_RETURN: BIO_printf (bio_s_out, "\nDONE\n"); ret = 1; goto WRITEDONE; } } } WRITEDONE: #ifdef DEBUG BIO_printf (bio_s_out, "shutting down SSL\n"); print_stats (bio_s_out, ctx); #endif #if 1 SSL_set_shutdown (con, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN); #else SSL_shutdown(con); #endif shut: if (con != NULL) SSL_free (con); if (2 != ret) BIO_printf(bio_s_out,"CONNECTION CLOSED\n"); if (buf != NULL) { OPENSSL_cleanse (buf, bufsize); OPENSSL_free (buf); } if ((ret >= 0) && (2 != ret)) BIO_printf (bio_s_out, "ACCEPT\n"); return(ret); }