Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Intermediate structure wrapping SSL on sockets #735

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 105 additions & 0 deletions ext/openssl/ossl_bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,108 @@ ossl_membio2str(BIO *bio)

return ret;
}

int
ossl_membio_sock_read(BIO* bio, VALUE io) {
VALUE nonblock_kwargs = rb_hash_new();
rb_hash_aset(nonblock_kwargs, ID2SYM(rb_intern("exception")), Qfalse);

printf("reading...\n");

VALUE fargs[] = { INT2NUM(4096), nonblock_kwargs };
VALUE ret = rb_funcallv_public_kw(io, rb_intern("read_nonblock"), 2, fargs, RB_PASS_KEYWORDS);
printf("just read...\n");
int len;
char *bstr;

if (RB_TYPE_P(ret, T_STRING)) {
len = RSTRING_LENINT(ret);
bstr = RSTRING_PTR(ret);
printf("read the nonblock: %d...\n", len);
}
else if (ret == ID2SYM(rb_intern("wait_readable"))) {
// BIO_set_retry_read(bio);
return SSL_ERROR_WANT_READ;
}
else if (ret == ID2SYM(rb_intern("wait_writable"))) {
// BIO_set_retry_write(bio);
return SSL_ERROR_WANT_WRITE;
}
else if (NIL_P(ret)) {
printf("fuck the nil\n");
return SSL_ERROR_ZERO_RETURN;
}
else {
printf("elsing\n");
rb_raise(rb_eTypeError, "write_nonblock must return an Integer, "
":wait_readable, or :wait_writable");
}

while (len > 0) {
int n = BIO_write(bio, bstr, len);
BIO_clear_retry_flags(bio);

if (n<=0)
return SSL_ERROR_SYSCALL; // unrecoverable

bstr += n;
len -= n;

// // finish handshake if required
// if (!SSL_is_init_finished(client.ssl)) {
// if (do_ssl_handshake() == SSLSTATUS_FAIL)
// return SSL_ERROR_SYSCALL;
// if (!SSL_is_init_finished(client.ssl))
// // assume there are bytes missing
// return SSL_ERROR_WANT_READ;
// }
}
return SSL_ERROR_NONE;
}

int
ossl_membio_sock_write(BIO* bio, VALUE io) {
char buf[4096];
char *p = buf;

int n = BIO_read(bio, p, 4096);
BIO_clear_retry_flags(bio);
if (n <= 0) {
if (!BIO_should_retry(bio))
// TODO: raise exception
return -1;
}

printf("writing to bio 2: %d\n", n);

VALUE nonblock_kwargs = rb_hash_new();
rb_hash_aset(nonblock_kwargs, ID2SYM(rb_intern("exception")), Qfalse);

VALUE fargs[] = { rb_str_new_static(buf, n), nonblock_kwargs };

// rb_io_write(rb_stdout ,rb_sprintf("%s\n", RSTRING_PTR(*biobuf)));
// rb_p(*biobuf);
VALUE ret = rb_funcallv_public_kw(io, rb_intern("write_nonblock"), 2, fargs, RB_PASS_KEYWORDS);

if (RB_INTEGER_TYPE_P(ret)) {
// TODO: resize buffer
return SSL_ERROR_NONE;
}
else if (ret == ID2SYM(rb_intern("wait_readable"))) {
printf("wred\n");
// BIO_set_retry_read(bio);
return SSL_ERROR_WANT_READ;
}
else if (ret == ID2SYM(rb_intern("wait_writable"))) {
printf("wwrit\n");
// BIO_set_retry_write(bio);
return SSL_ERROR_WANT_WRITE;
} else if (NIL_P(ret)) {
printf("closed\n");
return SSL_ERROR_ZERO_RETURN;
}
else {
rb_raise(rb_eTypeError, "write_nonblock must return an Integer, "
":wait_readable, or :wait_writable");
}
}
2 changes: 2 additions & 0 deletions ext/openssl/ossl_bio.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@

BIO *ossl_obj2bio(volatile VALUE *);
VALUE ossl_membio2str(BIO*);
int ossl_membio_sock_read(BIO *, VALUE);
int ossl_membio_sock_write(BIO * , VALUE);

#endif
143 changes: 129 additions & 14 deletions ext/openssl/ossl_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,15 @@ static ID id_i_io, id_i_context, id_i_hostname;

static int ossl_ssl_ex_vcb_idx;
static int ossl_ssl_ex_ptr_idx;
static int ossl_ssl_ex_rbio_idx;
static int ossl_ssl_ex_wbio_idx;
static int ossl_sslctx_ex_ptr_idx;


int IsSock(VALUE io) {
return RB_TYPE_P(io, T_FILE);
}

static void
ossl_sslctx_mark(void *ptr)
{
Expand Down Expand Up @@ -1639,7 +1646,7 @@ ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)

if (rb_respond_to(io, rb_intern("nonblock=")))
rb_funcall(io, rb_intern("nonblock="), 1, Qtrue);
Check_Type(io, T_FILE);
// Check_Type(io, T_FILE);
rb_ivar_set(self, id_i_io, io);

ssl = SSL_new(ctx);
Expand Down Expand Up @@ -1682,11 +1689,22 @@ ossl_ssl_setup(VALUE self)
return Qtrue;

io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
rb_io_check_writable(fptr);
if (!SSL_set_fd(ssl, TO_SOCKET(rb_io_descriptor(io))))
ossl_raise(eSSLError, "SSL_set_fd");

if (IsSock(io)) {
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
rb_io_check_writable(fptr);
if (!SSL_set_fd(ssl, TO_SOCKET(rb_io_descriptor(io))))
ossl_raise(eSSLError, "SSL_set_fd");
} else {
// something which quacks like an IO
// TODO: how to best ensure this from the C API??
BIO *rbio = BIO_new(BIO_s_mem());
BIO *wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
SSL_set_ex_data(ssl, ossl_ssl_ex_rbio_idx, (void *)rbio);
SSL_set_ex_data(ssl, ossl_ssl_ex_wbio_idx, (void *)wbio);
}

return Qtrue;
}
Expand Down Expand Up @@ -1732,6 +1750,22 @@ no_exception_p(VALUE opts)
#endif


int ossl_ssl_connect_impl(SSL *ssl)
{
return SSL_connect(ssl);
}

int ossl_ssl_read_impl(SSL *ssl, VALUE str, int ilen)
{
return SSL_read(ssl, RSTRING_PTR(str), ilen);
}

int ossl_ssl_write_impl(SSL *ssl, VALUE tmp, int num)
{
return SSL_write(ssl, RSTRING_PTR(tmp), num);
}


static void
io_wait_writable(VALUE io)
{
Expand Down Expand Up @@ -1773,6 +1807,15 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
GetSSL(self, ssl);

VALUE io = rb_attr_get(self, id_i_io);

int is_sock = IsSock(io);
BIO *rbio, *wbio;

if (!is_sock) {
rbio = (BIO *)SSL_get_ex_data(ssl, ossl_ssl_ex_rbio_idx);
wbio = (BIO *)SSL_get_ex_data(ssl, ossl_ssl_ex_wbio_idx);
}

for (;;) {
ret = func(ssl);

Expand All @@ -1782,11 +1825,35 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
ossl_clear_error();
rb_jump_tag(NUM2INT(cb_state));
}
printf("connect ret: %d\n", ret);

if (ret > 0)
break;

switch ((ret2 = ssl_get_error(ssl, ret))) {
ret2 = ssl_get_error(ssl, ret);
printf("WANT_READ: %d, WANT_WRITE. %d\n", SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE);
printf("connect ret2: %d\n", ret2);

if (!is_sock) {
if(ret2 == SSL_ERROR_WANT_WRITE) {
ret2 = ossl_membio_sock_read(rbio, io);
if (ret2 == SSL_ERROR_NONE) {
ret2 = SSL_ERROR_WANT_WRITE;
printf("out fuckerz\n");
break;
}
} else if (ret2 == SSL_ERROR_WANT_READ) {
ret2 = ossl_membio_sock_write(wbio, io);
if (ret2 == SSL_ERROR_NONE) {
printf("out fuckerz\n");
break;
// continue;
}
}
}
printf("connect after is_sock ret2: %d\n", ret2);

switch ((ret2)) {
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
Expand Down Expand Up @@ -1848,7 +1915,7 @@ ossl_ssl_connect(VALUE self)
{
ossl_ssl_setup(self);

return ossl_start_ssl(self, SSL_connect, "SSL_connect", Qfalse);
return ossl_start_ssl(self, ossl_ssl_connect_impl, "SSL_connect", Qfalse);
}

/*
Expand Down Expand Up @@ -1881,7 +1948,7 @@ ossl_ssl_connect_nonblock(int argc, VALUE *argv, VALUE self)

ossl_ssl_setup(self);

return ossl_start_ssl(self, SSL_connect, "SSL_connect", opts);
return ossl_start_ssl(self, ossl_ssl_connect_impl, "SSL_connect", opts);
}

/*
Expand Down Expand Up @@ -1938,6 +2005,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
int ilen;
VALUE len, str;
VALUE opts = Qnil;
BIO *rbio, *wbio;

if (nonblock) {
rb_scan_args(argc, argv, "11:", &len, &str, &opts);
Expand All @@ -1963,11 +2031,28 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
return str;

VALUE io = rb_attr_get(self, id_i_io);
int is_sock = IsSock(io);

if (!is_sock) {
rbio = (BIO *)SSL_get_ex_data(ssl, ossl_ssl_ex_rbio_idx);
wbio = (BIO *)SSL_get_ex_data(ssl, ossl_ssl_ex_wbio_idx);
}

rb_str_locktmp(str);
for (;;) {
int nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
switch (ssl_get_error(ssl, nread)) {
int ret, nread;

if (!is_sock) {
ret = ossl_membio_sock_read(rbio, io);
if (ret == SSL_ERROR_NONE) {
ret = ossl_membio_sock_write(wbio, io);
}
} else {
nread = ossl_ssl_read_impl(ssl, str, ilen);
ret = ssl_get_error(ssl, nread);
}

switch (ret) {
case SSL_ERROR_NONE:
rb_str_unlocktmp(str);
rb_str_set_len(str, nread);
Expand Down Expand Up @@ -2064,16 +2149,35 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts)

tmp = rb_str_new_frozen(StringValue(str));
VALUE io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
int is_sock = IsSock(io);
// BIO *rbio;
BIO *wbio;

if (!is_sock) {
// rbio = (BIO *)SSL_get_ex_data(ssl, ossl_ssl_ex_rbio_idx);
wbio = (BIO *)SSL_get_ex_data(ssl, ossl_ssl_ex_wbio_idx);
} else {
GetOpenFile(io, fptr);
}

/* SSL_write(3ssl) manpage states num == 0 is undefined */
num = RSTRING_LENINT(tmp);
if (num == 0)
return INT2FIX(0);

for (;;) {
int nwritten = SSL_write(ssl, RSTRING_PTR(tmp), num);
switch (ssl_get_error(ssl, nwritten)) {


int nwritten = ossl_ssl_write_impl(ssl, tmp, num);
int ret = ssl_get_error(ssl, nwritten);

if (!is_sock) {
if (ret == SSL_ERROR_NONE) {
ret = ossl_membio_sock_write(wbio, io);
}
}

switch (ret) {
case SSL_ERROR_NONE:
return INT2NUM(nwritten);
case SSL_ERROR_WANT_WRITE:
Expand Down Expand Up @@ -2607,6 +2711,12 @@ Init_ossl_ssl(void)
ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_ptr_idx", 0, 0, 0);
if (ossl_ssl_ex_ptr_idx < 0)
ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
ossl_ssl_ex_rbio_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_rbio_idx", 0, 0, 0);
if (ossl_ssl_ex_rbio_idx < 0)
ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
ossl_ssl_ex_wbio_idx = SSL_get_ex_new_index(0, (void *)"ossl_ssl_ex_wbio_idx", 0, 0, 0);
if (ossl_ssl_ex_wbio_idx < 0)
ossl_raise(rb_eRuntimeError, "SSL_get_ex_new_index");
ossl_sslctx_ex_ptr_idx = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_ptr_idx", 0, 0, 0);
if (ossl_sslctx_ex_ptr_idx < 0)
ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
Expand Down Expand Up @@ -3136,6 +3246,11 @@ Init_ossl_ssl(void)
id_npn_protocols_encoded = rb_intern_const("npn_protocols_encoded");
id_each = rb_intern_const("each");

nonblock_kwargs = rb_hash_new();
rb_hash_aset(nonblock_kwargs, sym_exception, Qfalse);
rb_obj_freeze(nonblock_kwargs);
rb_global_variable(&nonblock_kwargs);

#define DefIVarID(name) do \
id_i_##name = rb_intern_const("@"#name); while (0)

Expand Down
1 change: 1 addition & 0 deletions ext/openssl/ossl_ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ extern const rb_data_type_t ossl_ssl_session_type;
extern VALUE mSSL;
extern VALUE cSSLSocket;
extern VALUE cSSLSession;
static VALUE nonblock_kwargs;

void Init_ossl_ssl(void);
void Init_ossl_ssl_session(void);
Expand Down