first-line work on SSLifying the HTTP client

doesn't work at all, because the encrypted buffer never gets written to the net
This commit is contained in:
~hatteb-mitlyd 2014-03-13 18:52:03 -07:00
parent 0d0d6e468a
commit 65aba238a8
4 changed files with 198 additions and 33 deletions

View File

@ -43,14 +43,14 @@ ifeq ($(OS),osx)
OSLIBS=-framework CoreServices -framework CoreFoundation OSLIBS=-framework CoreServices -framework CoreFoundation
endif endif
ifeq ($(OS),linux) ifeq ($(OS),linux)
OSLIBS=-lcrypto -lpthread -lrt -lcurses OSLIBS=-lpthread -lrt -lcurses
DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE DEFINES=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
endif endif
ifeq ($(OS),bsd) ifeq ($(OS),bsd)
OSLIBS=-lcrypto -lpthread -lncurses -lkvm OSLIBS=-lpthread -lncurses -lkvm
endif endif
LIBS=-lgmp -lncurses -lsigsegv $(OSLIBS) LIBS=-lssl -lcrypto -lgmp -lncurses -lsigsegv $(OSLIBS)
INCLUDE=include INCLUDE=include
GENERATED=generated GENERATED=generated

View File

@ -44,7 +44,9 @@
typedef enum { typedef enum {
u2_csat_dead = 0, // connection dead u2_csat_dead = 0, // connection dead
u2_csat_addr = 1, // connection addressed u2_csat_addr = 1, // connection addressed
u2_csat_live = 2, // connection open u2_csat_clyr = 2, // connection open in cleartext
u2_csat_shak = 3, // connection handshaking ssl
u2_csat_cryp = 4, // connection open and crypted
} u2_csat; } u2_csat;
/* u2_hmet: http method. Matches jhttp encoding. /* u2_hmet: http method. Matches jhttp encoding.
@ -139,12 +141,21 @@
struct _u2_creq* nex_u; // next in queue struct _u2_creq* nex_u; // next in queue
} u2_creq; } u2_creq;
/* u2_sslx: per-connection ssl context.
*/
typedef struct _u2_sslx {
void* ssl_u; // struct SSL*
void* rio_u; // struct BIO* for read
void* wio_u; // struct BIO* for write
} u2_sslx;
/* u2_ccon: outgoing http connection. /* u2_ccon: outgoing http connection.
*/ */
typedef struct _u2_ccon { // client connection typedef struct _u2_ccon { // client connection
uv_tcp_t wax_u; // i/o handler state uv_tcp_t wax_u; // i/o handler state
uv_connect_t cot_u; // connection handler state uv_connect_t cot_u; // connection handler state
uv_getaddrinfo_t adr_u; // resolver state uv_getaddrinfo_t adr_u; // resolver state
u2_sslx ssl; // ssl state
u2_csat sat_e; // connection state u2_csat sat_e; // connection state
c3_c* hot_c; // hostname c3_c* hot_c; // hostname
c3_s por_s; // port c3_s por_s; // port
@ -532,12 +543,14 @@
u2_unix unx_u; // sync and clay u2_unix unx_u; // sync and clay
u2_batz beh_u; // batz timer u2_batz beh_u; // batz timer
u2_bean liv; // if u2_no, shut down u2_bean liv; // if u2_no, shut down
void* ssl_u; // struct SSL_CTX*
u2_reck* arv_u; // runtime u2_reck* arv_u; // runtime
} u2_host; // host == computer == process } u2_host; // host == computer == process
# define u2L u2_Host.lup_u // global event loop # define u2L u2_Host.lup_u // global event loop
# define u2R (&(u2_Raft)) # define u2R (&(u2_Raft))
# define u2S u2_Host.ssl_u
/* u2_funk: standard system function. /* u2_funk: standard system function.
*/ */

208
v/cttp.c
View File

@ -19,10 +19,19 @@
#include <termios.h> #include <termios.h>
#include <term.h> #include <term.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include "../outside/jhttp/http_parser.h" // Joyent HTTP #include "../outside/jhttp/http_parser.h" // Joyent HTTP
#include "all.h" #include "all.h"
#include "v/vere.h" #include "v/vere.h"
#ifdef U2_OS_osx
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
/* Forward declarations. /* Forward declarations.
*/ */
static void _cttp_ccon_kick(u2_ccon* coc_u); static void _cttp_ccon_kick(u2_ccon* coc_u);
@ -720,6 +729,9 @@ _cttp_ccon_waste(u2_ccon* coc_u, c3_c* msg_c)
if ( coc_u->nex_u ) { if ( coc_u->nex_u ) {
coc_u->nex_u->pre_u = coc_u->pre_u; coc_u->nex_u->pre_u = coc_u->pre_u;
} }
if ( coc_u->ssl.ssl_u ) {
SSL_free(coc_u->ssl.ssl_u);
}
free(coc_u); free(coc_u);
} }
@ -762,7 +774,13 @@ _cttp_ccon_reboot(u2_ccon* coc_u)
_cttp_ccon_waste(coc_u, "connection failed"); _cttp_ccon_waste(coc_u, "connection failed");
break; break;
} }
case u2_csat_live: { case u2_csat_shak: {
/* Got a connection, but SSL failed. Waste it.
*/
_cttp_ccon_waste(coc_u, "ssl handshake failed");
break;
}
case u2_csat_clyr: {
/* We had a connection but it broke. Either there are no /* We had a connection but it broke. Either there are no
** living requests, in which case waste; otherwise reset. ** living requests, in which case waste; otherwise reset.
*/ */
@ -803,7 +821,7 @@ _cttp_ccon_fail(u2_ccon* coc_u, u2_bean say)
uL(fprintf(uH, "cttp: %s\n", uv_strerror(uv_last_error(u2L)))); uL(fprintf(uH, "cttp: %s\n", uv_strerror(uv_last_error(u2L))));
} }
if ( coc_u->sat_e != u2_csat_live ) { if ( coc_u->sat_e < u2_csat_shak ) {
_cttp_ccon_reboot(coc_u); _cttp_ccon_reboot(coc_u);
} }
else { else {
@ -872,7 +890,9 @@ _cttp_ccon_kick_connect_cb(uv_connect_t* cot_u,
_cttp_ccon_fail(coc_u, u2_yes); _cttp_ccon_fail(coc_u, u2_yes);
} }
else { else {
coc_u->sat_e = u2_csat_live; coc_u->sat_e = (u2_yes == coc_u->sec) ?
u2_csat_shak :
u2_csat_clyr;
_cttp_ccon_kick(coc_u); _cttp_ccon_kick(coc_u);
} }
} }
@ -911,10 +931,10 @@ _cttp_ccon_kick_connect(u2_ccon* coc_u)
c3_y* buf_y; c3_y* buf_y;
} _u2_write_t; } _u2_write_t;
/* _cttp_ccon_kick_write_cb(): general write callback. /* _cttp_ccon_kick_write_clyr_cb(): general write callback for cleartext conn
*/ */
static void static void
_cttp_ccon_kick_write_cb(uv_write_t* wri_u, c3_i sas_i) _cttp_ccon_kick_write_clyr_cb(uv_write_t* wri_u, c3_i sas_i)
{ {
u2_lo_open(); u2_lo_open();
{ {
@ -942,7 +962,7 @@ _cttp_ccon_kick_write_buf(u2_ccon* coc_u, uv_buf_t buf_u)
if ( 0 != uv_write(&ruq_u->wri_u, if ( 0 != uv_write(&ruq_u->wri_u,
(uv_stream_t*)&(coc_u->wax_u), (uv_stream_t*)&(coc_u->wax_u),
&buf_u, 1, &buf_u, 1,
_cttp_ccon_kick_write_cb) ) _cttp_ccon_kick_write_clyr_cb) )
{ {
_cttp_ccon_fail(coc_u, u2_yes); _cttp_ccon_fail(coc_u, u2_yes);
} }
@ -986,13 +1006,68 @@ _cttp_ccon_kick_write(u2_ccon* coc_u)
} }
} }
/* _cttp_ccon_read_cb()
*/
static void static void
_cttp_ccon_kick_read_cb(uv_stream_t* tcp_u, _cttp_ccon_kick_cryp_hurr(SSL* ssl, int rev)
ssize_t siz_i,
uv_buf_t buf_u)
{ {
c3_i err = SSL_get_error(ssl, rev);
if ( SSL_ERROR_WANT_READ == err ) {
uL(fprintf(uH, ("ssl-hurr want read\n")));
}
else {
uL(fprintf(uH, ("ssl-hurr fucked\n")));
}
}
static void
_cttp_ccon_pars_shov(u2_ccon* coc_u, void* buf_u, ssize_t siz_i)
{
u2_creq* ceq_u = coc_u->ceq_u;
if ( !ceq_u ) { // spurious input
uL(fprintf(uH, "http: response to no request\n"));
}
else {
if ( !ceq_u->res_u ) {
_cttp_cres_start(ceq_u);
}
if ( siz_i != http_parser_execute(ceq_u->res_u->par_u,
&_cttp_settings,
(c3_c*)buf_u,
siz_i) )
{
uL(fprintf(uH, "http: parse error\n"));
_cttp_ccon_fail(coc_u, u2_no);
}
}
}
static void
_cttp_ccon_kick_cryp_pull(u2_ccon* coc_u)
{
uL(fprintf(uH, "cttp-cryp-pull\n"));
if ( SSL_is_init_finished(coc_u->ssl.ssl_u) ) {
static c3_c buf[1<<14];
c3_i ruf;
while ( 0 < (ruf = SSL_read(coc_u->ssl.ssl_u, &buf, sizeof(buf))) ) {
_cttp_ccon_pars_shov(coc_u, &buf, ruf);
}
}
else {
// not connected
c3_i r = SSL_connect(coc_u->ssl.ssl_u);
if ( 0 > r ) {
_cttp_ccon_kick_cryp_hurr(coc_u->ssl.ssl_u, r);
}
}
}
static void
_cttp_ccon_kick_read_cryp_cb(uv_stream_t* tcp_u,
ssize_t siz_i,
uv_buf_t buf_u)
{
uL(fprintf(uH, "cttp-cryp-read\n"));
u2_ccon *coc_u = _cttp_ccon_wax((uv_tcp_t*)tcp_u); u2_ccon *coc_u = _cttp_ccon_wax((uv_tcp_t*)tcp_u);
u2_lo_open(); u2_lo_open();
@ -1009,18 +1084,8 @@ _cttp_ccon_kick_read_cb(uv_stream_t* tcp_u,
uL(fprintf(uH, "http: response to no request\n")); uL(fprintf(uH, "http: response to no request\n"));
} }
else { else {
if ( !ceq_u->res_u ) { BIO_write(coc_u->ssl.rio_u, (c3_c*)buf_u.base, siz_i);
_cttp_cres_start(ceq_u); _cttp_ccon_kick_cryp_pull(coc_u);
}
if ( siz_i != http_parser_execute(ceq_u->res_u->par_u,
&_cttp_settings,
(c3_c*)buf_u.base,
siz_i) )
{
uL(fprintf(uH, "http: parse error\n"));
_cttp_ccon_fail(coc_u, u2_no);
}
} }
} }
if ( buf_u.base ) { if ( buf_u.base ) {
@ -1030,14 +1095,73 @@ _cttp_ccon_kick_read_cb(uv_stream_t* tcp_u,
u2_lo_shut(u2_yes); u2_lo_shut(u2_yes);
} }
/* _cttp_ccon_kick_read(): start reading. /* _cttp_ccon_read_clyr_cb()
*/ */
static void static void
_cttp_ccon_kick_read(u2_ccon* coc_u) _cttp_ccon_kick_read_clyr_cb(uv_stream_t* tcp_u,
ssize_t siz_i,
uv_buf_t buf_u)
{
u2_ccon *coc_u = _cttp_ccon_wax((uv_tcp_t*)tcp_u);
u2_lo_open();
{
if ( siz_i < 0 ) {
uv_err_t las_u = uv_last_error(u2L);
_cttp_ccon_fail(coc_u, (UV_EOF == las_u.code) ? u2_no : u2_yes);
}
else {
_cttp_ccon_pars_shov(coc_u, buf_u.base, siz_i);
}
if ( buf_u.base ) {
free(buf_u.base);
}
}
u2_lo_shut(u2_yes);
}
/* _cttp_ccon_kick_read_clyr(): start reading on insecure socket.
*/
static void
_cttp_ccon_kick_read_clyr(u2_ccon* coc_u)
{ {
uv_read_start((uv_stream_t*)&coc_u->wax_u, uv_read_start((uv_stream_t*)&coc_u->wax_u,
_cttp_alloc, _cttp_alloc,
_cttp_ccon_kick_read_cb); _cttp_ccon_kick_read_clyr_cb);
}
/* _cttp_ccon_kick_handshake(): start ssl handshake.
*/
static void
_cttp_ccon_kick_handshake(u2_ccon* coc_u)
{
uL(fprintf(uH, "cttp: shak\n"));
coc_u->ssl.ssl_u = SSL_new(u2S);
c3_assert(coc_u->ssl.ssl_u);
coc_u->ssl.rio_u = BIO_new(BIO_s_mem());
c3_assert(coc_u->ssl.rio_u);
coc_u->ssl.wio_u = BIO_new(BIO_s_mem());
c3_assert(coc_u->ssl.wio_u);
BIO_set_nbio(coc_u->ssl.rio_u, 1);
BIO_set_nbio(coc_u->ssl.wio_u, 1);
SSL_set_bio(coc_u->ssl.ssl_u,
coc_u->ssl.rio_u,
coc_u->ssl.wio_u);
SSL_set_connect_state(coc_u->ssl.ssl_u);
SSL_do_handshake(coc_u->ssl.ssl_u);
coc_u->sat_e = u2_csat_cryp;
uv_read_start((uv_stream_t*)&coc_u->wax_u,
_cttp_alloc,
_cttp_ccon_kick_read_cryp_cb);
_cttp_ccon_kick_cryp_pull(coc_u);
} }
/* _cttp_ccon_kick(): start appropriate I/O on client connection. /* _cttp_ccon_kick(): start appropriate I/O on client connection.
@ -1059,13 +1183,17 @@ _cttp_ccon_kick(u2_ccon* coc_u)
_cttp_ccon_kick_connect(coc_u); _cttp_ccon_kick_connect(coc_u);
break; break;
} }
case u2_csat_live: { case u2_csat_shak: {
_cttp_ccon_kick_handshake(coc_u);
break;
}
case u2_csat_clyr: {
_cttp_ccon_fill(coc_u); _cttp_ccon_fill(coc_u);
if ( coc_u->rub_u ) { if ( coc_u->rub_u ) {
_cttp_ccon_kick_write(coc_u); _cttp_ccon_kick_write(coc_u);
} }
_cttp_ccon_kick_read(coc_u); _cttp_ccon_kick_read_clyr(coc_u);
break; break;
} }
} }
@ -1320,12 +1448,33 @@ u2_cttp_ef_thus(c3_l num_l,
u2z(cuq); u2z(cuq);
} }
/* u2_cttp_io_init(): initialize http I/O. /* u2_cttp_io_init(): initialize http client I/O.
*/ */
void void
u2_cttp_io_init() u2_cttp_io_init()
{ {
c3_i rad;
c3_y buf[4096];
u2_Host.ctp_u.coc_u = 0; u2_Host.ctp_u.coc_u = 0;
SSL_library_init();
SSL_load_error_strings();
u2_Host.ssl_u = SSL_CTX_new(TLSv1_client_method());
SSL_CTX_set_options(u2S, SSL_OP_NO_SSLv2);
SSL_CTX_set_verify(u2S, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_session_cache_mode(u2S, SSL_SESS_CACHE_OFF);
// RAND_status, at least on OS X, never returns true.
// 4096 bytes should be enough entropy for anyone, right?
rad = open("/dev/urandom", O_RDONLY);
if ( 4096 != read(rad, &buf, 4096) ) {
perror("rand-seed");
exit(1);
}
RAND_seed(buf, 4096);
close(rad);
} }
/* u2_cttp_io_poll(): poll kernel for cttp I/O. /* u2_cttp_io_poll(): poll kernel for cttp I/O.
@ -1340,4 +1489,5 @@ u2_cttp_io_poll(void)
void void
u2_cttp_io_exit(void) u2_cttp_io_exit(void)
{ {
SSL_CTX_free(u2S);
} }

View File

@ -163,6 +163,7 @@ _lo_init()
u2_ames_io_init(); u2_ames_io_init();
u2_term_io_init(); u2_term_io_init();
u2_http_io_init(); u2_http_io_init();
u2_cttp_io_init();
u2_save_io_init(); u2_save_io_init();
u2_batz_io_init(); u2_batz_io_init();
} }
@ -186,6 +187,7 @@ u2_lo_exit(void)
u2_ames_io_exit(); u2_ames_io_exit();
u2_term_io_exit(); u2_term_io_exit();
u2_http_io_exit(); u2_http_io_exit();
u2_cttp_io_exit();
u2_save_io_exit(); u2_save_io_exit();
u2_batz_io_exit(); u2_batz_io_exit();
} }