Skip to content
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
137 changes: 109 additions & 28 deletions ext/openssl/ossl.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,88 @@ ossl_bin2hex(const unsigned char *in, char *out, size_t inlen)
}
}

static ID id_cb_state;

int
ossl_cb_state_get(void)
{
VALUE val = rb_thread_local_aref(rb_thread_current(), id_cb_state);
return FIXNUM_P(val) ? FIX2INT(val) : 0;
}

static VALUE
cb_state_set_i(VALUE vstate)
{
rb_thread_local_aset(rb_thread_current(), id_cb_state, vstate);
return Qnil;
}

void
ossl_cb_state_set(int state)
{
int s;
RUBY_ASSERT(!state || !ossl_cb_state_get());
rb_protect(cb_state_set_i, state ? INT2FIX(state) : Qnil, &s);
if (s) {
/* As a last resort */
rb_set_errinfo(Qnil);
return;
}
}

void
ossl_cb_state_begin(void)
{
RUBY_ASSERT(!ossl_cb_state_get());
}

int
ossl_cb_state_end(void)
{
int state = ossl_cb_state_get();
if (state)
ossl_cb_state_set(0);
return state;
}

struct suppress_args {
VALUE (*func)(VALUE args);
VALUE args;
};

static VALUE
do_nothing(VALUE unused)
{
return Qnil;
}

static VALUE
suppress_i(VALUE args_)
{
struct suppress_args *p = (struct suppress_args *)args_;
int state;
rb_set_errinfo(Qnil);
rb_protect(p->func, p->args, &state);
if (state) {
fprintf(stderr, "ossl_suppress: exception suppressed");
}
return Qnil;
}

void
ossl_suppress(VALUE (*func)(VALUE args), VALUE args)
{
struct suppress_args p = { func, args };
if (ossl_cb_state_get()) {
int state = ossl_cb_state_end();
rb_ensure(do_nothing, Qnil, suppress_i, (VALUE)&p);
ossl_cb_state_begin();
ossl_cb_state_set(state);
return;
}
rb_ensure(do_nothing, Qnil, suppress_i, (VALUE)&p);
}

/*
* our default PEM callback
*/
Expand Down Expand Up @@ -275,7 +357,7 @@ ossl_to_der_if_possible(VALUE obj)
*/
static ID id_i_errors;

static void collect_errors_into(VALUE ary);
static VALUE collect_errors_into(VALUE ary);

VALUE
ossl_make_error(VALUE exc, VALUE str)
Expand Down Expand Up @@ -326,46 +408,44 @@ ossl_raise(VALUE exc, const char *fmt, ...)
rb_exc_raise(ossl_make_error(exc, err));
}

static void
static VALUE
collect_errors_into(VALUE ary)
{
if (dOSSL == Qtrue || !NIL_P(ary)) {
unsigned long e;
const char *file, *data, *func, *lib, *reason;
int line, flags;
unsigned long e;
const char *file, *data, *func, *lib, *reason;
int line, flags;

#ifdef HAVE_ERR_GET_ERROR_ALL
while ((e = ERR_get_error_all(&file, &line, &func, &data, &flags))) {
while ((e = ERR_get_error_all(&file, &line, &func, &data, &flags))) {
#else
while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) {
func = ERR_func_error_string(e);
while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) {
func = ERR_func_error_string(e);
#endif
lib = ERR_lib_error_string(e);
reason = ERR_reason_error_string(e);

VALUE str = rb_sprintf("error:%08lX:%s:%s:%s", e, lib ? lib : "",
func ? func : "", reason ? reason : "");
if (flags & ERR_TXT_STRING) {
if (!data)
data = "(null)";
rb_str_catf(str, " (%s)", data);
}

if (dOSSL == Qtrue)
rb_warn("error on stack: %"PRIsVALUE, str);
if (!NIL_P(ary))
rb_ary_push(ary, str);
lib = ERR_lib_error_string(e);
reason = ERR_reason_error_string(e);

VALUE str = rb_sprintf("error:%08lX:%s:%s:%s", e, lib ? lib : "",
func ? func : "", reason ? reason : "");
if (flags & ERR_TXT_STRING) {
if (!data)
data = "(null)";
rb_str_catf(str, " (%s)", data);
}

if (dOSSL == Qtrue)
rb_warn("error on stack: %"PRIsVALUE, str);
if (!NIL_P(ary))
rb_ary_push(ary, str);
}
else {
ERR_clear_error();
}
return Qnil;
}

void
ossl_clear_error(void)
{
collect_errors_into(Qnil);
if (dOSSL == Qtrue)
ossl_suppress(collect_errors_into, Qnil);
ERR_clear_error();
}

/*
Expand Down Expand Up @@ -1155,6 +1235,7 @@ Init_openssl(void)
*/
ossl_s_to_der = rb_intern("to_der");
id_i_errors = rb_intern("@errors");
id_cb_state = rb_intern("__openssl_cb_state__");

/*
* Init components
Expand Down
17 changes: 17 additions & 0 deletions ext/openssl/ossl.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,23 @@ do{\
*/
void ossl_bin2hex(const unsigned char *in, char *out, size_t len);

/*
* Ractor-local storage for storing rb_protect() jump tag. Use this only if
* the OpenSSL API doesn't let you pass arbitrary data to the callback.
*
* _begin() expects that there's no currently pending jump.
* No context switch is expected between _set() and _end().
*/
void ossl_cb_state_begin(void);
int ossl_cb_state_end(void);
int ossl_cb_state_get(void);
void ossl_cb_state_set(int state);
/*
* Equivalent to rb_protect(func, args, NULL) except that this avoids
* clobbering the existing errinfo on the ec.
*/
void ossl_suppress(VALUE (*func)(VALUE args), VALUE args);

/*
* Our default PEM callback
*/
Expand Down
16 changes: 14 additions & 2 deletions ext/openssl/ossl_ocsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,15 +378,21 @@ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
OCSP_REQUEST *req;
STACK_OF(X509) *x509s;
X509_STORE *x509st;
int flg, result;
int flg, result, state;

rb_scan_args(argc, argv, "21", &certs, &store, &flags);
GetOCSPReq(self, req);
x509st = GetX509StorePtr(store);
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
x509s = ossl_x509_ary2sk(certs);
ossl_cb_state_begin();
result = OCSP_request_verify(req, x509s, x509st, flg);
state = ossl_cb_state_end();
sk_X509_pop_free(x509s, X509_free);
if (state) {
ossl_clear_error();
rb_jump_tag(state);
}
if (result <= 0)
ossl_clear_error();

Expand Down Expand Up @@ -989,15 +995,21 @@ ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
OCSP_BASICRESP *bs;
STACK_OF(X509) *x509s;
X509_STORE *x509st;
int flg, result;
int flg, result, state;

rb_scan_args(argc, argv, "21", &certs, &store, &flags);
GetOCSPBasicRes(self, bs);
x509st = GetX509StorePtr(store);
flg = NIL_P(flags) ? 0 : NUM2INT(flags);
x509s = ossl_x509_ary2sk(certs);
ossl_cb_state_begin();
result = OCSP_basic_verify(bs, x509s, x509st, flg);
state = ossl_cb_state_end();
sk_X509_pop_free(x509s, X509_free);
if (state) {
ossl_clear_error();
rb_jump_tag(state);
}
if (result <= 0)
ossl_clear_error();

Expand Down
7 changes: 7 additions & 0 deletions ext/openssl/ossl_pkcs7.c
Original file line number Diff line number Diff line change
Expand Up @@ -777,9 +777,16 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
sk_X509_pop_free(x509s, X509_free);
ossl_raise(ePKCS7Error, NULL);
}
ossl_cb_state_begin();
ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
status = ossl_cb_state_end();
BIO_free(in);
sk_X509_pop_free(x509s, X509_free);
if (status) {
BIO_free(out);
ossl_clear_error();
rb_jump_tag(status);
}
data = ossl_membio2str(out);
ossl_pkcs7_set_data(self, data);
if (ok != 1) {
Expand Down
Loading
Loading