Skip to content

Instantly share code, notes, and snippets.

@Asmod4n
Last active August 29, 2015 14:12
Show Gist options
  • Save Asmod4n/28e9902421642096a4d0 to your computer and use it in GitHub Desktop.
Save Asmod4n/28e9902421642096a4d0 to your computer and use it in GitHub Desktop.
SecureBuffer for mruby
#include <stdio.h>
#include <sodium.h>
#include <mruby.h>
#include <mruby/data.h>
#include <mruby/class.h>
#include <mruby/string.h>
#include <mruby/array.h>
#include "picohttpparser.h"
static mrb_value
pico_parse(mrb_state *mrb, mrb_value self)
{
mrb_int i;
char *request;
mrb_int request_len;
mrb_value block;
int ret;
const char *method;
size_t method_len;
const char *path;
size_t path_len;
int minor_version;
size_t num_headers = 32;
struct phr_header headers[num_headers];
mrb_value yield_array, headers_array, body;
i = mrb_get_args(mrb, "s&", &request, &request_len, &block);
ret = phr_parse_request(request, request_len,
&method, &method_len, &path, &path_len, &minor_version, headers,
&num_headers, 0);
yield_array = mrb_ary_new_capa(mrb, 5);
mrb_ary_set(mrb, yield_array, 0, mrb_str_new_static(mrb, method, method_len));
mrb_ary_set(mrb, yield_array, 1, mrb_str_new_static(mrb, path, path_len));
mrb_ary_set(mrb, yield_array, 2, mrb_fixnum_value(minor_version));
headers_array = mrb_ary_new_capa(mrb, (mrb_int)num_headers);
for(i=0;i != num_headers;i++) {
mrb_value tmp = mrb_ary_new_capa(mrb, 2);
mrb_ary_set(mrb, tmp, 0,
mrb_str_new_static(mrb, headers[i].name, headers[i].name_len));
mrb_ary_set(mrb, tmp, 1,
mrb_str_new_static(mrb, headers[i].value, headers[i].value_len));
mrb_ary_set(mrb, headers_array, i, tmp);
}
mrb_ary_set(mrb, yield_array, 3, headers_array);
body = mrb_str_new_static(mrb, request + ret, request_len - ret);
mrb_ary_set(mrb, yield_array, 4, body);
return mrb_yield(mrb, block, yield_array);
}
static mrb_value
mrb_sodium_init(mrb_state *mrb, mrb_value self)
{
if (sodium_init () == -1) {
mrb_raise(mrb, E_RUNTIME_ERROR, "Could nit initalize libsodium");
} else {
return mrb_true_value();
}
}
typedef struct {
void *ptr;
mrb_int size;
} secret_buffer_t;
static void
secret_buffer_free(mrb_state *mrb, void *p)
{
secret_buffer_t *buffer;
buffer = (secret_buffer_t *) p;
if (sodium_mprotect_readonly (buffer->ptr) == 0)
sodium_free(buffer->ptr);
}
static const struct mrb_data_type secret_buffer_type = {
"$i_secret_buffer", secret_buffer_free,
};
static mrb_value
secret_buffer_init(mrb_state *mrb, mrb_value self)
{
secret_buffer_t *buffer;
mrb_int size;
buffer = (secret_buffer_t *) DATA_PTR(self);
if(buffer)
mrb_free(mrb, buffer);
mrb_data_init(self, NULL, &secret_buffer_type);
mrb_get_args(mrb, "i", &size);
if (size >= 0) {
buffer = (secret_buffer_t *) mrb_calloc(mrb, 1, sizeof(buffer));
buffer->ptr = sodium_malloc ((size_t)size);
if (buffer->ptr == NULL) {
mrb->out_of_memory = TRUE;
mrb_exc_raise(mrb, mrb_obj_value(mrb->nomem_err));
} else {
buffer->size = size;
mrb_data_init(self, buffer, &secret_buffer_type);
}
} else {
mrb_raise(mrb, E_RANGE_ERROR, "size musn't be negative");
}
return self;
}
static mrb_value
secret_buffer_ptr(mrb_state *mrb, mrb_value self)
{
secret_buffer_t *buffer;
buffer = (secret_buffer_t *) DATA_PTR(self);
return mrb_cptr_value(mrb, buffer->ptr);
}
static mrb_value
secret_buffer_size(mrb_state *mrb, mrb_value self)
{
secret_buffer_t *buffer;
buffer = (secret_buffer_t *) DATA_PTR(self);
return mrb_fixnum_value(buffer->size);
}
static mrb_value
secret_buffer_noaccess(mrb_state *mrb, mrb_value self)
{
secret_buffer_t *buffer;
int rc;
buffer = (secret_buffer_t *) DATA_PTR(self);
rc = sodium_mprotect_noaccess (buffer->ptr);
if (rc == 0)
return mrb_true_value();
else
return mrb_false_value();
}
static mrb_value
secret_buffer_readonly(mrb_state *mrb, mrb_value self)
{
secret_buffer_t *buffer;
int rc;
buffer = (secret_buffer_t *) DATA_PTR(self);
rc = sodium_mprotect_readonly (buffer->ptr);
if (rc == 0)
return mrb_true_value();
else
return mrb_false_value();
}
static mrb_value
secret_buffer_readwrite(mrb_state *mrb, mrb_value self)
{
secret_buffer_t *buffer;
int rc;
buffer = (secret_buffer_t *) DATA_PTR(self);
rc = sodium_mprotect_readwrite (buffer->ptr);
if (rc == 0)
return mrb_true_value();
else
return mrb_false_value();
}
static mrb_value
mrb_randombytes_random(mrb_state *mrb, mrb_value self)
{
uint32_t ran;
ran = randombytes_random ();
if (ran > MRB_INT_MAX)
return mrb_float_value(mrb, ran);
else
return mrb_fixnum_value(ran);
}
static mrb_value
mrb_randombytes_uniform(mrb_state *mrb, mrb_value self)
{
mrb_float upper_bound;
uint32_t ran;
mrb_get_args(mrb, "f", &upper_bound);
if (upper_bound >= 0 && upper_bound <= UINT32_MAX) {
ran = randombytes_uniform ((uint32_t)upper_bound);
if (ran > MRB_INT_MAX)
return mrb_float_value(mrb, ran);
else
return mrb_fixnum_value(ran);
} else {
mrb_raise(mrb, E_RANGE_ERROR, "upper_bound is out of range");
}
}
static mrb_value
mrb_randombytes_buf(mrb_state *mrb, mrb_value self)
{
mrb_value buf_obj;
void *buf;
mrb_int size;
mrb_get_args(mrb, "o", &buf_obj);
switch (mrb_type(buf_obj)) {
case MRB_TT_STRING:
buf = RSTRING_PTR(buf_obj);
size = RSTRING_LEN(buf_obj);
break;
case MRB_TT_DATA:
if (DATA_TYPE(buf_obj) == &secret_buffer_type) {
secret_buffer_t *buffer;
buffer = (secret_buffer_t *) DATA_PTR(buf_obj);
buf = buffer->ptr;
size = buffer->size;
}
else
mrb_raise(mrb, E_TYPE_ERROR, "only works with Strings or SecureBuffers");
break;
default:
mrb_raise(mrb, E_TYPE_ERROR, "only works with Strings or SecureBuffers");
}
randombytes_buf(buf, (size_t)size);
return buf_obj;
}
void
mrb_c_extension_example_gem_init(mrb_state* mrb) {
struct RClass *sodium_class;
sodium_class = mrb_define_module(mrb, "Sodium");
mrb_define_module_function(mrb, sodium_class, "init", mrb_sodium_init, MRB_ARGS_NONE());
struct RClass *secret_buffer_class;
secret_buffer_class = mrb_define_class_under(mrb, sodium_class, "SecretBuffer", mrb->object_class);
MRB_SET_INSTANCE_TT(secret_buffer_class, MRB_TT_DATA);
mrb_define_method(mrb, secret_buffer_class, "initialize", secret_buffer_init, MRB_ARGS_REQ(1));
mrb_define_method(mrb, secret_buffer_class, "ptr", secret_buffer_ptr, MRB_ARGS_NONE());
mrb_define_method(mrb, secret_buffer_class, "size", secret_buffer_size, MRB_ARGS_NONE());
mrb_define_method(mrb, secret_buffer_class, "noaccess", secret_buffer_noaccess, MRB_ARGS_NONE());
mrb_define_method(mrb, secret_buffer_class, "readonly", secret_buffer_readonly, MRB_ARGS_NONE());
mrb_define_method(mrb, secret_buffer_class, "readwrite", secret_buffer_readwrite, MRB_ARGS_NONE());
struct RClass *random_bytes_class;
random_bytes_class = mrb_define_module(mrb, "RandomBytes");
mrb_define_module_function(mrb, random_bytes_class, "random", mrb_randombytes_random, MRB_ARGS_NONE());
mrb_define_module_function(mrb, random_bytes_class, "uniform", mrb_randombytes_uniform, MRB_ARGS_REQ(1));
mrb_define_module_function(mrb, random_bytes_class, "buf", mrb_randombytes_buf, MRB_ARGS_REQ(1));
mrb_define_module_function(mrb, random_bytes_class, "parse", pico_parse, MRB_ARGS_REQ(2));
}
void
mrb_c_extension_example_gem_final(mrb_state* mrb) {
/* finalizer */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment