static void respond_to_number(struct bufferevent *bev, void *ctx) { struct evbuffer *b = bufferevent_get_input(bev); char *line; int n; line = evbuffer_readln(b, NULL, EVBUFFER_EOL_LF); if (! line) return; n = atoi(line); if (n <= 0) TT_FAIL(("Bad number: %s", line)); TT_BLATHER(("The number was %d", n)); if (n == 1001) { ++test_is_done; bufferevent_free(bev); /* Should trigger close on other side. */ return; } if (!strcmp(ctx, "client") && n == renegotiate_at) { SSL_renegotiate(bufferevent_openssl_get_ssl(bev)); } ++n; evbuffer_add_printf(bufferevent_get_output(bev), "%d\n", n); TT_BLATHER(("Done reading; now writing.")); bufferevent_enable(bev, EV_WRITE); bufferevent_disable(bev, EV_READ); }
bool CHECK_RESULT renegotiatefull(SSL *ssl, bool server) { if (debuglevel > 2) fprintf(stderr,"Renegotiating\n"); CHECK(SSL_renegotiate(ssl) == SSL_OK); // On server, this results in "HelloRequest" being sent to server. // Allow SSL to do this in its own time on client. if (!LOGCHECK(sslDoHandshake(ssl) == SSL_OK)) { return false; } #if defined LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10100000L // [Now, mercifully, seems to be unnecessary in the main OpenSSL branch] // [Just as well, as it doesn't compile any more] if (server) { // Nasty hack - this makes SSL expect an immediate // handshake and we get an error otherwise. See: // http://www.mail-archive.com/[email protected]/msg20802.html ssl->state = SSL_ST_ACCEPT; // Complete the handshake. // This fails if there is unread data from the client // This can also fail eg. if the client fails to send a certificate. // Should change to softer error. if (!LOGCHECK(sslDoHandshake(ssl) == SSL_OK)) { return false; } } #endif return true; }
int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl) { int r; SSL_renegotiate(ssl); r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0); if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r; /* this is for the server only */ ssl->state = SSL_ST_ACCEPT; return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0); }
void net_step_up(netc_t *netc) { if (netc->conn_type == NET_SERVER) { // Server send HelloRequest krypt_set_rsa(netc->kconn); // set security level to RSA SSL_renegotiate(netc->kconn->ssl); // move the SSL connection into renegotiation state krypt_do_handshake(netc->kconn, NULL, 0); // call SSL_do_handshake (1st time) net_do_krypt(netc); krypt_set_renegotiate(netc->kconn); // set handshake mode } }
// Initiate an asynchronous renegotiation bool CHECK_RESULT renegotiate(SSL *ssl, bool server) { if (debuglevel > 2) fprintf(stderr,"Renegotiating\n"); CHECK(SSL_renegotiate(ssl) == SSL_OK); // On server, this results in "HelloRequest" being sent to client. // Allow SSL to do this in its own time on client. if (server) { if (!LOGCHECK(sslDoHandshake(ssl) == SSL_OK)) { return false; } } return true; }
static PyObject * ssl_Connection_renegotiate(ssl_ConnectionObj *self, PyObject *args) { int ret; if (!PyArg_ParseTuple(args, ":renegotiate")) { return NULL; } MY_BEGIN_ALLOW_THREADS(self->tstate); ret = SSL_renegotiate(self->ssl); MY_END_ALLOW_THREADS(self->tstate); if (PyErr_Occurred()) { flush_error_queue(); return NULL; } return PyLong_FromLong((long)ret); }
// Tries to renegotiate SSL values (session, keys) on this connection. void SSLSocket::renegotitate() throw(IOException) { /* assume ssl is connected and error free up to here */ //set_blocking(ssl); /* this is unnecessary if it is already blocking */ SSL_renegotiate(_ssl); SSL_do_handshake(_ssl); if (_ssl->state != SSL_ST_OK) throw IOException("SSLSocket: Failed to send renegotiation request"); _ssl->state |= SSL_ST_ACCEPT; SSL_do_handshake(_ssl); if (_ssl->state != SSL_ST_OK) throw IOException("SSLSocket: Failed to complete renegotiation"); /* our renegotiation is complete */ }
void SecuredServerSession::messageComplete() { if (!m_renegotiate || !m_readYield) return; m_renegotiate = false; SSL_set_options(m_SSL, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); SSL_renegotiate(m_SSL); int ret; int step = 0; while ( (ret = SSL_do_handshake(m_SSL)) != 1) { if (ret < 0) { auto err = SSL_get_error(m_SSL, ret); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { if (++step > 5) { (*m_readYield)(); step = 0; } continue; } } return; } step = 0; while ( (ret = SSL_do_handshake(m_SSL)) != 1) { if (ret < 0) { auto err = SSL_get_error(m_SSL, ret); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { if (++step > 5) { (*m_readYield)(); step = 0; } continue; } } break; } }
bool CHECK_RESULT renegotiatefull(SSL *ssl, bool server) { if (debuglevel > 2) fprintf(stderr,"Renegotiating\n"); CHECK(SSL_renegotiate(ssl) == SSL_OK); // On server, this results in "HelloRequest" being sent to server. // Allow SSL to do this in its own time on client. if (!LOGCHECK(sslDoHandshake(ssl) == SSL_OK)) { return false; } if (server) { // Nasty hack - this makes SSL expect an immediate // handshake and we get an error otherwise. See: // http://www.mail-archive.com/[email protected]/msg20802.html ssl->state = SSL_ST_ACCEPT; // Complete the handshake. // This fails if there is unread data from the client // This can also fail eg. if the client fails to send a certificate. // Should change to softer error. if (!LOGCHECK(sslDoHandshake(ssl) == SSL_OK)) { return false; } } return true; }
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); }
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); while(1){ r=BIO_gets(io,buf,BUFSIZZ-1); switch(SSL_get_error(ssl,r)){ case SSL_ERROR_NONE: len=r; break; case SSL_ERROR_ZERO_RETURN: goto shutdown; 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; } /* Now perform renegotiation if requested */ if(client_auth==CLIENT_AUTH_REHANDSHAKE){ SSL_set_verify(ssl,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0); /* Stop the client from just resuming the un-authenticated session */ SSL_set_session_id_context(ssl, (void *)&s_server_auth_session_id_context, sizeof(s_server_auth_session_id_context)); if(SSL_renegotiate(ssl)<=0) berr_exit("SSL renegotiation error"); if(SSL_do_handshake(ssl)<=0) berr_exit("SSL renegotiation error"); ssl->state=SSL_ST_ACCEPT; if(SSL_do_handshake(ssl)<=0) berr_exit("SSL renegotiation error"); } if((r=BIO_puts (io,"HTTP/1.0 200 OK\r\n"))<=0) err_exit("Write error"); if((r=BIO_puts (io,"Server: EKRServer\r\n\r\n"))<=0) err_exit("Write error"); if((r=BIO_puts (io,"Server test page\r\n"))<=0) err_exit("Write error"); if((r=BIO_flush(io))<0) err_exit("Error flushing BIO"); shutdown: 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); }
/* * Write data to a secure connection. */ ssize_t secure_write(Port *port, void *ptr, size_t len) { ssize_t n; #ifdef USE_SSL if (port->ssl) { if (port->count > RENEGOTIATION_LIMIT) { SSL_set_session_id_context(port->ssl, (void *) &SSL_context, sizeof(SSL_context)); if (SSL_renegotiate(port->ssl) <= 0) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL renegotiation failure"))); if (SSL_do_handshake(port->ssl) <= 0) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL renegotiation failure"))); if (port->ssl->state != SSL_ST_OK) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL failed to send renegotiation request"))); port->ssl->state |= SSL_ST_ACCEPT; SSL_do_handshake(port->ssl); if (port->ssl->state != SSL_ST_OK) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL renegotiation failure"))); port->count = 0; } wloop: n = SSL_write(port->ssl, ptr, len); switch (SSL_get_error(port->ssl, n)) { case SSL_ERROR_NONE: port->count += n; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: goto wloop; case SSL_ERROR_SYSCALL: if (n == -1) ereport(COMMERROR, (errcode_for_socket_access(), errmsg("SSL SYSCALL error: %m"))); else { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL SYSCALL error: EOF detected"))); errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL error: %s", SSLerrmessage()))); /* fall through */ case SSL_ERROR_ZERO_RETURN: errno = ECONNRESET; n = -1; break; default: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unrecognized SSL error code %d", SSL_get_error(port->ssl, n)))); n = -1; break; } } else #endif n = send(port->sock, ptr, len, 0); return n; }
static int ssl_read(BIO *b, char *out, int outl) { int ret=1; BIO_SSL *sb; SSL *ssl; int retry_reason=0; int r=0; if (out == NULL) return(0); sb=(BIO_SSL *)b->ptr; ssl=sb->ssl; BIO_clear_retry_flags(b); #if 0 if (!SSL_is_init_finished(ssl)) { /* ret=SSL_do_handshake(ssl); */ if (ret > 0) { outflags=(BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY); ret= -1; goto end; } } #endif /* if (ret > 0) */ ret=SSL_read(ssl,out,outl); switch (SSL_get_error(ssl,ret)) { case SSL_ERROR_NONE: if (ret <= 0) break; if (sb->renegotiate_count > 0) { sb->byte_count+=ret; if (sb->byte_count > sb->renegotiate_count) { sb->byte_count=0; sb->num_renegotiates++; SSL_renegotiate(ssl); r=1; } } if ((sb->renegotiate_timeout > 0) && (!r)) { unsigned long tm; tm=(unsigned long)time(NULL); if (tm > sb->last_time+sb->renegotiate_timeout) { sb->last_time=tm; sb->num_renegotiates++; SSL_renegotiate(ssl); } } break; case SSL_ERROR_WANT_READ: BIO_set_retry_read(b); break; case SSL_ERROR_WANT_WRITE: BIO_set_retry_write(b); break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_set_retry_special(b); retry_reason=BIO_RR_SSL_X509_LOOKUP; break; case SSL_ERROR_WANT_ACCEPT: BIO_set_retry_special(b); retry_reason=BIO_RR_ACCEPT; break; case SSL_ERROR_WANT_CONNECT: BIO_set_retry_special(b); retry_reason=BIO_RR_CONNECT; break; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: break; } b->retry_reason=retry_reason; return(ret); }
static int ssl_write(BIO *b, const char *out, int outl) { int ret,r=0; int retry_reason=0; SSL *ssl; BIO_SSL *bs; if (out == NULL) return(0); bs=(BIO_SSL *)b->ptr; ssl=bs->ssl; BIO_clear_retry_flags(b); /* ret=SSL_do_handshake(ssl); if (ret > 0) */ ret=SSL_write(ssl,out,outl); switch (SSL_get_error(ssl,ret)) { case SSL_ERROR_NONE: if (ret <= 0) break; if (bs->renegotiate_count > 0) { bs->byte_count+=ret; if (bs->byte_count > bs->renegotiate_count) { bs->byte_count=0; bs->num_renegotiates++; SSL_renegotiate(ssl); r=1; } } if ((bs->renegotiate_timeout > 0) && (!r)) { unsigned long tm; tm=(unsigned long)time(NULL); if (tm > bs->last_time+bs->renegotiate_timeout) { bs->last_time=tm; bs->num_renegotiates++; SSL_renegotiate(ssl); } } break; case SSL_ERROR_WANT_WRITE: BIO_set_retry_write(b); break; case SSL_ERROR_WANT_READ: BIO_set_retry_read(b); break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_set_retry_special(b); retry_reason=BIO_RR_SSL_X509_LOOKUP; break; case SSL_ERROR_WANT_CONNECT: BIO_set_retry_special(b); retry_reason=BIO_RR_CONNECT; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: default: break; } b->retry_reason=retry_reason; return(ret); }
static int ssl_write(BIO *b, const char *buf, size_t size, size_t *written) { int ret, r = 0; int retry_reason = 0; SSL *ssl; BIO_SSL *bs; if (buf == NULL) return 0; bs = BIO_get_data(b); ssl = bs->ssl; BIO_clear_retry_flags(b); ret = ssl_write_internal(ssl, buf, size, written); switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_NONE: if (bs->renegotiate_count > 0) { bs->byte_count += *written; if (bs->byte_count > bs->renegotiate_count) { bs->byte_count = 0; bs->num_renegotiates++; SSL_renegotiate(ssl); r = 1; } } if ((bs->renegotiate_timeout > 0) && (!r)) { unsigned long tm; tm = (unsigned long)time(NULL); if (tm > bs->last_time + bs->renegotiate_timeout) { bs->last_time = tm; bs->num_renegotiates++; SSL_renegotiate(ssl); } } break; case SSL_ERROR_WANT_WRITE: BIO_set_retry_write(b); break; case SSL_ERROR_WANT_READ: BIO_set_retry_read(b); break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_set_retry_special(b); retry_reason = BIO_RR_SSL_X509_LOOKUP; break; case SSL_ERROR_WANT_CONNECT: BIO_set_retry_special(b); retry_reason = BIO_RR_CONNECT; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: default: break; } BIO_set_retry_reason(b, retry_reason); return ret; }
static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer) { int ret; char buf; TEST_check(peer->status == PEER_RETRY); TEST_check(test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER || test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT); /* Check if we are the peer that is going to initiate */ if ((test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_SERVER && SSL_is_server(peer->ssl)) || (test_ctx->handshake_mode == SSL_TEST_HANDSHAKE_RENEG_CLIENT && !SSL_is_server(peer->ssl))) { /* * If we already asked for a renegotiation then fall through to the * SSL_read() below. */ if (!SSL_renegotiate_pending(peer->ssl)) { /* * If we are the client we will always attempt to resume the * session. The server may or may not resume dependant on the * setting of SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION */ if (SSL_is_server(peer->ssl)) ret = SSL_renegotiate(peer->ssl); else ret = SSL_renegotiate_abbreviated(peer->ssl); if (!ret) { peer->status = PEER_ERROR; return; } do_handshake_step(peer); /* * If status is PEER_RETRY it means we're waiting on the peer to * continue the handshake. As far as setting up the renegotiation is * concerned that is a success. The next step will continue the * handshake to its conclusion. * * If status is PEER_SUCCESS then we are the server and we have * successfully sent the HelloRequest. We need to continue to wait * until the handshake arrives from the client. */ if (peer->status == PEER_RETRY) peer->status = PEER_SUCCESS; else if (peer->status == PEER_SUCCESS) peer->status = PEER_RETRY; return; } } /* * The SSL object is still expecting app data, even though it's going to * get a handshake message. We try to read, and it should fail - after which * we should be in a handshake */ ret = SSL_read(peer->ssl, &buf, sizeof(buf)); if (ret >= 0) { /* * We're not actually expecting data - we're expecting a reneg to * start */ peer->status = PEER_ERROR; return; } else { int error = SSL_get_error(peer->ssl, ret); if (error != SSL_ERROR_WANT_READ) { peer->status = PEER_ERROR; return; } /* If we're no in init yet then we're not done with setup yet */ if (!SSL_in_init(peer->ssl)) return; } peer->status = PEER_SUCCESS; }
/* * Write data to a secure connection. */ ssize_t secure_write(Port *port, void *ptr, size_t len) { ssize_t n; #ifdef USE_SSL if (port->ssl) { int err; if (ssl_renegotiation_limit && port->count > ssl_renegotiation_limit * 1024L) { SSL_set_session_id_context(port->ssl, (void *) &SSL_context, sizeof(SSL_context)); if (SSL_renegotiate(port->ssl) <= 0) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL renegotiation failure"))); if (SSL_do_handshake(port->ssl) <= 0) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL renegotiation failure"))); if (port->ssl->state != SSL_ST_OK) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL failed to send renegotiation request"))); port->ssl->state |= SSL_ST_ACCEPT; SSL_do_handshake(port->ssl); if (port->ssl->state != SSL_ST_OK) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL renegotiation failure"))); port->count = 0; } wloop: errno = 0; n = SSL_write(port->ssl, ptr, len); err = SSL_get_error(port->ssl, n); switch (err) { case SSL_ERROR_NONE: port->count += n; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: #ifdef WIN32 pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), (err == SSL_ERROR_WANT_READ) ? FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE, INFINITE); #endif goto wloop; case SSL_ERROR_SYSCALL: /* leave it to caller to ereport the value of errno */ if (n != -1) { errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL error: %s", SSLerrmessage()))); /* fall through */ case SSL_ERROR_ZERO_RETURN: errno = ECONNRESET; n = -1; break; default: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unrecognized SSL error code: %d", err))); n = -1; break; } } else #endif n = send(port->sock, ptr, len, 0); return n; }
static int openssl_ssl_renegotiate(lua_State*L) { SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl"); int ret = SSL_renegotiate(s); return openssl_ssl_pushresult(L, s, ret); }
static int ssl_read(BIO *b, char *buf, size_t size, size_t *readbytes) { int ret = 1; BIO_SSL *sb; SSL *ssl; int retry_reason = 0; int r = 0; if (buf == NULL) return 0; sb = BIO_get_data(b); ssl = sb->ssl; BIO_clear_retry_flags(b); ret = ssl_read_internal(ssl, buf, size, readbytes); switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_NONE: if (sb->renegotiate_count > 0) { sb->byte_count += *readbytes; if (sb->byte_count > sb->renegotiate_count) { sb->byte_count = 0; sb->num_renegotiates++; SSL_renegotiate(ssl); r = 1; } } if ((sb->renegotiate_timeout > 0) && (!r)) { unsigned long tm; tm = (unsigned long)time(NULL); if (tm > sb->last_time + sb->renegotiate_timeout) { sb->last_time = tm; sb->num_renegotiates++; SSL_renegotiate(ssl); } } break; case SSL_ERROR_WANT_READ: BIO_set_retry_read(b); break; case SSL_ERROR_WANT_WRITE: BIO_set_retry_write(b); break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_set_retry_special(b); retry_reason = BIO_RR_SSL_X509_LOOKUP; break; case SSL_ERROR_WANT_ACCEPT: BIO_set_retry_special(b); retry_reason = BIO_RR_ACCEPT; break; case SSL_ERROR_WANT_CONNECT: BIO_set_retry_special(b); retry_reason = BIO_RR_CONNECT; break; case SSL_ERROR_SYSCALL: case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: break; } BIO_set_retry_reason(b, retry_reason); return ret; }
void ServiceTask::run() { //logger << dlib << endl; string ip = "invalid session"; string alldatlg = "\ngot fd from parent"; SSL *ssl=NULL; BIO *sbio=NULL; BIO *io=NULL,*ssl_bio=NULL; try { int cntlen = 0; char buf[MAXBUFLENM]; strVec results; stringstream ss; string temp; //int bytes = -1; if(isSSLEnabled) { sbio=BIO_new_socket(fd,BIO_NOCLOSE); ssl=SSL_new(ctx); SSL_set_bio(ssl,sbio,sbio); 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); int r = SSL_accept(ssl); cout << r << endl; int bser = SSL_get_error(ssl,r); cout << bser << endl; if(r<=0) { sslHandler.error_occurred((char*)"SSL accept error",fd,ssl); return; } int er=-1; bool flag = true; while(flag) { er = BIO_gets(io,buf,BUFSIZZ-1); cout << er << endl; int bser = SSL_get_error(ssl,er); cout << bser << endl; switch(bser) { case SSL_ERROR_WANT_READ: { logger << "more to read error" << endl; break; } case SSL_ERROR_WANT_WRITE: { logger << "more to write error" << endl; break; } case SSL_ERROR_NONE: { break; } case SSL_ERROR_ZERO_RETURN: { sslHandler.error_occurred((char*)"SSL error problem",fd,ssl); if(io!=NULL)BIO_free(io); return; } default: { sslHandler.error_occurred((char*)"SSL read problem",fd,ssl); if(io!=NULL)BIO_free(io); return; } } ss << buf; //logger <<buf <<endl; if(!strcmp(buf,"\r\n") || !strcmp(buf,"\n")) break; string temp(buf); if(temp=="")continue; temp = temp.substr(0,temp.length()-1); results.push_back(temp); //logger << temp <<endl; if(temp.find("Content-Length:")!=string::npos) { std::string cntle = temp.substr(temp.find(": ")+2); cntle = cntle.substr(0,cntle.length()-1); //logger << "contne-length="<<cntle <<endl; try { cntlen = CastUtil::lexical_cast<int>(cntle); } catch(const char* ex) { logger << "bad lexical cast" <<endl; } } memset(&buf[0], 0, sizeof(buf)); } } else { int er=-1; bool flag = true; sbio=BIO_new_socket(fd,BIO_CLOSE); io=BIO_new(BIO_f_buffer()); BIO_push(io,sbio); logger << "into run method" << endl; while(flag) { er = BIO_gets(io,buf,BUFSIZZ-1); if(er==0) { close(fd); logger << "\nsocket closed before being serviced" <<flush; return; } ss << buf; if(!strcmp(buf,"\r\n") || !strcmp(buf,"\n") || er<0) break; string temp(buf); temp = temp.substr(0,temp.length()-1); results.push_back(temp); //logger << temp <<endl; if(temp.find("Content-Length:")!=string::npos) { std::string cntle = temp.substr(temp.find(": ")+2); cntle = cntle.substr(0,cntle.length()-1); //logger << "contne-length="<<cntle <<endl; try { cntlen = CastUtil::lexical_cast<int>(cntle); } catch(const char* ex) { logger << "bad lexical cast" <<endl; } } memset(&buf[0], 0, sizeof(buf)); } } ss.clear(); if(isSSLEnabled && cntlen>0) { int er=-1; if(cntlen>0) { //logger << "reading conetnt " << cntlen << endl; er = BIO_read(io,buf,cntlen); switch(SSL_get_error(ssl,er)) { case SSL_ERROR_NONE: cntlen -= er; break; case SSL_ERROR_ZERO_RETURN: { sslHandler.error_occurred((char*)"SSL error problem",fd,ssl); if(io!=NULL)BIO_free(io); return; } default: { sslHandler.error_occurred((char*)"SSL read problem",fd,ssl); if(io!=NULL)BIO_free(io); return; } } string temp(buf); results.push_back("\r"); results.push_back(temp); //logger <<buf <<endl; memset(&buf[0], 0, sizeof(buf)); } } else if(cntlen>0) { int er=-1; if(cntlen>0) { //logger << "reading conetnt " << cntlen << endl; er = BIO_read(io,buf,cntlen); if(er==0) { close(fd); logger << "\nsocket closed before being serviced" <<flush; return; } else if(er>0) { string temp(buf); results.push_back("\r"); results.push_back(temp); //logger << temp <<endl; memset(&buf[0], 0, sizeof(buf)); } } } alldatlg += "--read data"; map<string,string> params1 = *params; string webpath = serverRootDirectory + "web/"; HttpRequest* req= new HttpRequest(results,webpath); //logger << req->toString() << endl; if(req->getFile()=="") { logger << req->getFile() << endl; req->setFile("index.html"); } if(req->hasCookie()) { logger << "has the session id" << endl; if(!configData.sessatserv) req->getSession()->setSessionAttributes(req->getCookieInfo()); else { string id = req->getCookieInfoAttribute("FFEADID"); logger << id << endl; map<string,string> values = readFromSharedMemeory(id); req->getSession()->setSessionAttributes(values); } } if(configData.cntMap[req->getCntxt_name()]!="true") { req->setCntxt_name("default"); req->setCntxt_root(webpath+"default"); req->setUrl(webpath+"default"+req->getActUrl()); } //logger << req->getCntxt_name() << req->getCntxt_root() << req->getUrl() << endl; if(configData.appMap[req->getCntxt_name()]!="false") { if(dlib == NULL) { cerr << dlerror() << endl; exit(-1); } string meth1 = (req->getCntxt_name()+"checkRules"); string path1; void *mkr1 = dlsym(dlib, meth1.c_str()); if(mkr1!=NULL) { typedef string (*DCPPtr1) (string,HttpSession); DCPPtr1 f = (DCPPtr1)mkr1; path1 = f(req->getUrl(),*(req->getSession())); //logger << path1 << flush; if(path1=="FAILED") { req->setUrl(""); } else if(path1!="" && path1!=req->getUrl()) { req->setUrl(path1); } } } HttpResponse res; string ext = getFileExtension(req->getUrl()); vector<unsigned char> test; string content; string claz; bool isoAuthRes = false; long sessionTimeoutVar = configData.sessionTimeout; bool isContrl = securityHandler.handle(configData.ip_address, req, res, configData.securityObjectMap, sessionTimeoutVar, dlib, configData.cntMap); filterHandler.handleIn(req, res, configData.filterMap, dlib, ext); if(!isContrl) { isContrl = authHandler.handle(configData.autMap, configData.autpattMap, req, res, configData.filterMap, dlib, ext); } string pthwofile = req->getCntxt_name()+req->getActUrl(); if(req->getCntxt_name()!="default" && configData.cntMap[req->getCntxt_name()]=="true") { pthwofile = req->getActUrl(); } if(!isContrl) { isContrl = controllerHandler.handle(req, res, configData.urlpattMap, configData.mappattMap, dlib, ext, configData.rstCntMap, configData.mapMap, configData.urlMap, pthwofile); } /*After going through the controller the response might be blank, just set the HTTP version*/ res.setHttpVersion(req->getHttpVersion()); //logger << req->toString() << endl; if(req->getMethod()!="TRACE") { if(isContrl) { } else if(ext==".form") { formHandler.handle(req, res, configData.formMap, dlib); } else if((req->getContent_type().find("application/soap+xml")!=string::npos || req->getContent_type().find("text/xml")!=string::npos) && (req->getContent().find("<soap:Envelope")!=string::npos || req->getContent().find("<soapenv:Envelope")!=string::npos) && configData.wsdlmap[req->getFile()]==req->getCntxt_name()) { soapHandler.handle(req, res, dlib, configData.props[".xml"]); } else { bool cntrlit = scriptHandler.handle(req, res, configData.handoffs, dlib, ext, configData.props); logger << "html page requested" <<endl; if(cntrlit) { } else { cntrlit = extHandler.handle(req, res, dlib, configData.resourcePath, configData.tmplMap, configData.vwMap, ext, configData.props); } if(!cntrlit && ext==".fview") { content = fviewHandler.handle(req, res, configData.fviewmap); } else { if(res.getContent_str()=="") content = getContentStr(req->getUrl(),configData.lprops[req->getDefaultLocale()],ext); else content = res.getContent_str(); } if(content.length()==0) { res.setStatusCode("404"); res.setStatusMsg("Not Found"); //res.setContent_len(CastUtil::lexical_cast<string>(0)); } else { res.setStatusCode("200"); res.setStatusMsg("OK"); if(res.getContent_type()=="")res.setContent_type(configData.props[ext]); res.setContent_str(content); //res.setContent_len(CastUtil::lexical_cast<string>(content.length())); //sess.setAttribute("CURR",req->getUrl()); } } filterHandler.handleOut(req, res, configData.filterMap, dlib, ext); } alldatlg += "--processed data"; string h1; bool sessionchanged = !req->hasCookie(); sessionchanged |= req->getSession()->isDirty(); if(req->getConnection()!="") res.setConnection("close"); createResponse(res,sessionchanged,req->getSession()->getSessionAttributes(),req->getCookieInfoAttribute("FFEADID"), sessionTimeoutVar, configData.sessatserv); //Head should behave exactly as Get but there should be no entity body if(req->getMethod()=="HEAD") { h1 = res.generateHeadResponse(); } else if(req->getMethod()=="OPTIONS") { h1 = res.generateOptionsResponse(); } else if(req->getMethod()=="TRACE") { h1 = res.generateTraceResponse(req); } else { h1 = res.generateResponse(); } //logger << h1 << endl; if(isSSLEnabled) { int r; /* Now perform renegotiation if requested */ if(configData.client_auth==CLIENT_AUTH_REHANDSHAKE){ SSL_set_verify(ssl,SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,0); /* Stop the client from just resuming the un-authenticated session */ SSL_set_session_id_context(ssl, (const unsigned char*)&SSLHandler::s_server_auth_session_id_context, sizeof(SSLHandler::s_server_auth_session_id_context)); if(SSL_renegotiate(ssl)<=0) { sslHandler.error_occurred((char*)"SSL renegotiation error",fd,ssl); if(io!=NULL)BIO_free(io); return; } if(SSL_do_handshake(ssl)<=0) { sslHandler.error_occurred((char*)"SSL renegotiation error",fd,ssl); if(io!=NULL)BIO_free(io); return; } ssl->state=SSL_ST_ACCEPT; if(SSL_do_handshake(ssl)<=0) { sslHandler.error_occurred((char*)"SSL renegotiation error",fd,ssl); if(io!=NULL)BIO_free(io); return; } } if((r=BIO_puts(io,h1.c_str()))<=0) { sslHandler.error_occurred((char*)"send failed",fd,ssl); if(io!=NULL)BIO_free(io); return; } if((r=BIO_flush(io))<0) { sslHandler.error_occurred((char*)"Error flushing BIO",fd,ssl); if(io!=NULL)BIO_free(io); return; } sslHandler.closeSSL(fd,ssl,io); } else { int size; if ((size=send(fd,&h1[0] , h1.length(), 0)) == -1) logger << "send failed" << flush; else if(size==0) { close(fd); memset(&buf[0], 0, sizeof(buf)); logger << "socket closed for writing" << flush; return; } if(io!=NULL)BIO_free_all(io); } close(fd); memset(&buf[0], 0, sizeof(buf)); ss.clear(); //Logger::info("got new connection to process\n"+req->getFile()+" :: " + res.getStatusCode() + "\n"+req->getCntxt_name() + "\n"+req->getCntxt_root() + "\n"+req->getUrl()); delete req; logger << alldatlg << "--sent data--DONE" << flush; //sessionMap[sessId] = sess; } catch(...) { logger << "Standard exception: " << endl; } }
/* * Write data to a secure connection. */ ssize_t secure_write(Port *port, void *ptr, size_t len) { ssize_t n; #ifdef USE_SSL if (port->ssl) { int err; if (ssl_renegotiation_limit && port->count > ssl_renegotiation_limit * 1024L) { SSL_set_session_id_context(port->ssl, (void *) &SSL_context, sizeof(SSL_context)); if (SSL_renegotiate(port->ssl) <= 0) { report_commerror("SSL renegotiation failure"); } if (SSL_do_handshake(port->ssl) <= 0) { report_commerror("SSL renegotiation failure"); } if (port->ssl->state != SSL_ST_OK) { report_commerror("SSL failed to send renegotiation request"); } port->ssl->state |= SSL_ST_ACCEPT; SSL_do_handshake(port->ssl); if (port->ssl->state != SSL_ST_OK) { report_commerror("SSL renegotiation failure"); } port->count = 0; } wloop: errno = 0; n = SSL_write(port->ssl, ptr, len); err = SSL_get_error(port->ssl, n); const int ERR_MSG_LEN = ERROR_BUF_SIZE + 20; char err_msg[ERR_MSG_LEN]; switch (err) { case SSL_ERROR_NONE: port->count += n; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: #ifdef WIN32 pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), (err == SSL_ERROR_WANT_READ) ? FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE, INFINITE); #endif goto wloop; case SSL_ERROR_SYSCALL: /* leave it to caller to ereport the value of errno */ if (n != -1) { errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: snprintf((char *)&err_msg, ERR_MSG_LEN, "SSL error: %s", SSLerrmessage()); report_commerror(err_msg); /* fall through */ case SSL_ERROR_ZERO_RETURN: errno = ECONNRESET; n = -1; break; default: snprintf((char *)&err_msg, ERR_MSG_LEN, "unrecognized SSL error code: %d", err); report_commerror(err_msg); n = -1; break; } } else #endif { prepare_for_client_write(); n = send(port->sock, ptr, len, 0); client_write_ended(); } return n; }
void CreateSslSocket(int argc, char **argv) { struct hostent *hp; unsigned long hostAddr = 0; int serverport = atoi(argv[2]); int fd = 0; struct sockaddr_in inaddr; SSL_CTX *ssl_ctx = NULL; SSL *ssl = NULL; // create ip socket // if((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { printf("unable to create a socket %s\n", strerror(errno)); exit(0); } // reuse the socket address if possible // int yes = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,(char*) &yes, sizeof(yes)) == -1) { printf("couldn't set the SO_REUSEADDR: %s\n", strerror(errno)); } // connect to the server // if((hp = gethostbyname(argv[1])) == NULL) { printf("unable to resolve host address(%s)\n", argv[1]); exit(0); } hostAddr = ((struct in_addr*)hp->h_addr)->s_addr; inaddr.sin_family = AF_INET; inaddr.sin_addr.s_addr = hostAddr; inaddr.sin_port = htons(serverport); if(connect(fd, (struct sockaddr*)&inaddr, sizeof(inaddr)) == -1) { printf("unable to connect to the server(%s)\n", strerror(errno)); close(fd); exit(0); } // Create SSL context and setup with fd // ssl_ctx = SSL_CTX_new(TLSv1_client_method()); ssl = SSL_new(ssl_ctx); // set the servername per ssl context // if (strlen(argv[3])) { if (!SSL_set_tlsext_host_name(ssl, argv[3])) { char buf[160]; printf("Error with SSL_set_tlsext_host_name: %s\n", ERR_error_string(ERR_get_error(), buf)); exit(0); } } SSL_set_fd(ssl, fd); int ret = SSL_connect(ssl); if (ret <=0) { char buf[250]; printf("Error connecting via SSL: %s\n", ERR_error_string(SSL_get_error(ssl, ret), buf)); SSL_free(ssl); SSL_CTX_free(ssl_ctx); close(fd); return; } // print out the CN, OU, emailAddress // // get the server cert // X509* servercert = SSL_get_peer_certificate(ssl); // get the subject // X509_NAME* subject = X509_get_subject_name(servercert); // get the various components within subject // char sbuf[256]; int sbuflen = sizeof(sbuf); printf("Server certificate\n"); if (X509_NAME_get_text_by_NID(subject, NID_commonName, sbuf, sbuflen) != -1) { printf("CN: %s\n", sbuf); } else { printf("CN: NOT FOUND\n"); } if (X509_NAME_get_text_by_NID(subject, NID_organizationName, sbuf, sbuflen) != -1) { printf("O: %s\n", sbuf); } else { printf("O: NOT FOUND\n"); } if (X509_NAME_get_text_by_NID(subject, NID_organizationalUnitName, sbuf, sbuflen) != -1) { printf("OU: %s\n", sbuf); } else { printf("OU: NOT FOUND\n"); } if (X509_NAME_get_text_by_NID(subject, NID_pkcs9_emailAddress, sbuf, sbuflen) != -1) { printf("emailAddress: %s\n", sbuf); } else { printf("emailAddress: NOT FOUND\n"); } if (X509_NAME_oneline(X509_get_subject_name(servercert), sbuf, sbuflen) != NULL) { printf("subject: %s\n", sbuf); } else { printf("subject: NOT FOUND\n"); } // write some random data before closing it // static char getbuf[] = "GET /index.html HTTP/1.0\r\nHost: foo\r\nConnection: close\r\n\r\n"; printf("sending sizeof:%d strlen:%d bytes\n", (int)sizeof(getbuf), (int)strlen(getbuf)); #if 1 // Renegotiate with different servername // NOTE: this means we can change the sni server name at any time. // if (!SSL_set_tlsext_host_name(ssl, "www.foo.com")) { char buf[160]; printf("Error with SSL_set_tlsext_host_name: %s\n", ERR_error_string(ERR_get_error(), buf)); exit(0); } if (SSL_renegotiate(ssl) <=0) { char buf[160]; printf("Error with SSL_renegotiate: %s\n", ERR_error_string(ERR_get_error(), buf)); exit(0); } if (SSL_do_handshake(ssl) <=0) { char buf[160]; printf("Error with SSL_do_handshake: %s\n", ERR_error_string(ERR_get_error(), buf)); exit(0); } #endif SSL_write(ssl, getbuf, strlen(getbuf)); // Read the data back until the socket closes // char readBuf[256]; int out = 0; printf("Reading response\n"); while ((out = SSL_read(ssl, readBuf, sizeof(readBuf))) > 0) { printf("Read: %d bytes\n", out); write(1, readBuf, out); } printf("conn closed: %d\n", out); SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ssl_ctx); close(fd); }
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); }
/* * Write data to a secure connection. */ ssize_t be_tls_write(Port *port, void *ptr, size_t len, int *waitfor) { ssize_t n; int err; /* * If SSL renegotiations are enabled and we're getting close to the * limit, start one now; but avoid it if there's one already in * progress. Request the renegotiation 1kB before the limit has * actually expired. */ if (ssl_renegotiation_limit && !in_ssl_renegotiation && port->count > (ssl_renegotiation_limit - 1) * 1024L) { in_ssl_renegotiation = true; /* * The way we determine that a renegotiation has completed is by * observing OpenSSL's internal renegotiation counter. Make sure * we start out at zero, and assume that the renegotiation is * complete when the counter advances. * * OpenSSL provides SSL_renegotiation_pending(), but this doesn't * seem to work in testing. */ SSL_clear_num_renegotiations(port->ssl); /* without this, renegotiation fails when a client cert is used */ SSL_set_session_id_context(port->ssl, (void *) &SSL_context, sizeof(SSL_context)); if (SSL_renegotiate(port->ssl) <= 0) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL failure during renegotiation start"))); } errno = 0; n = SSL_write(port->ssl, ptr, len); err = SSL_get_error(port->ssl, n); switch (err) { case SSL_ERROR_NONE: port->count += n; break; case SSL_ERROR_WANT_READ: *waitfor = WL_SOCKET_READABLE; errno = EWOULDBLOCK; n = -1; break; case SSL_ERROR_WANT_WRITE: *waitfor = WL_SOCKET_WRITEABLE; errno = EWOULDBLOCK; n = -1; break; case SSL_ERROR_SYSCALL: /* leave it to caller to ereport the value of errno */ if (n != -1) { errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL error: %s", SSLerrmessage()))); /* fall through */ case SSL_ERROR_ZERO_RETURN: errno = ECONNRESET; n = -1; break; default: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unrecognized SSL error code: %d", err))); errno = ECONNRESET; n = -1; break; } if (n >= 0) { /* is renegotiation complete? */ if (in_ssl_renegotiation && SSL_num_renegotiations(port->ssl) >= 1) { in_ssl_renegotiation = false; port->count = 0; } /* * if renegotiation is still ongoing, and we've gone beyond the * limit, kill the connection now -- continuing to use it can be * considered a security problem. */ if (in_ssl_renegotiation && port->count > ssl_renegotiation_limit * 1024L) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL failed to renegotiate connection before limit expired"))); } return n; }
/* * Write data to a secure connection. */ ssize_t secure_write(Port *port, void *ptr, size_t len) { ssize_t n; #ifdef USE_SSL if (port->ssl) { int err; /* * If SSL renegotiations are enabled and we're getting close to the * limit, start one now; but avoid it if there's one already in * progress. Request the renegotiation 1kB before the limit has * actually expired. */ if (ssl_renegotiation_limit && !in_ssl_renegotiation && port->count > (ssl_renegotiation_limit - 1) * 1024L) { in_ssl_renegotiation = true; /* * The way we determine that a renegotiation has completed is by * observing OpenSSL's internal renegotiation counter. Make sure * we start out at zero, and assume that the renegotiation is * complete when the counter advances. * * OpenSSL provides SSL_renegotiation_pending(), but this doesn't * seem to work in testing. */ SSL_clear_num_renegotiations(port->ssl); SSL_set_session_id_context(port->ssl, (void *) &SSL_context, sizeof(SSL_context)); if (SSL_renegotiate(port->ssl) <= 0) ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL failure during renegotiation start"))); else { int retries; /* * A handshake can fail, so be prepared to retry it, but only * a few times. */ for (retries = 0; retries++;) { if (SSL_do_handshake(port->ssl) > 0) break; /* done */ ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL handshake failure on renegotiation, retrying"))); if (retries >= 20) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unable to complete SSL handshake"))); } } } wloop: errno = 0; n = SSL_write(port->ssl, ptr, len); err = SSL_get_error(port->ssl, n); switch (err) { case SSL_ERROR_NONE: port->count += n; break; case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: #ifdef WIN32 pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), (err == SSL_ERROR_WANT_READ) ? FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE, INFINITE); #endif goto wloop; case SSL_ERROR_SYSCALL: /* leave it to caller to ereport the value of errno */ if (n != -1) { errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL error: %s", SSLerrmessage()))); /* fall through */ case SSL_ERROR_ZERO_RETURN: errno = ECONNRESET; n = -1; break; default: ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unrecognized SSL error code: %d", err))); errno = ECONNRESET; n = -1; break; } if (n >= 0) { /* is renegotiation complete? */ if (in_ssl_renegotiation && SSL_num_renegotiations(port->ssl) >= 1) { in_ssl_renegotiation = false; port->count = 0; } /* * if renegotiation is still ongoing, and we've gone beyond the * limit, kill the connection now -- continuing to use it can be * considered a security problem. */ if (in_ssl_renegotiation && port->count > ssl_renegotiation_limit * 1024L) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL failed to renegotiate connection before limit expired"))); } } else #endif n = send(port->sock, ptr, len, 0); return n; }