Skip to content
Merged
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
258 changes: 109 additions & 149 deletions ext/openssl/ossl_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,6 @@ asn1_to_der(void *template, int (*i2d)(void *template, unsigned char **pp))
return str;
}

static VALUE
obj_to_asn1obj_i(VALUE obj)
{
return (VALUE)ossl_to_asn1obj(obj);
}

static VALUE
ossl_ts_req_alloc(VALUE klass)
{
Expand Down Expand Up @@ -1062,42 +1056,119 @@ ossl_ts_token_info_to_text(VALUE self)
return ossl_membio2str(out);
}

struct tsfac_create_ts_args {
VALUE self, key, certificate, request;
TS_RESP_CTX *ctx;
ASN1_INTEGER *asn1_serial;
long lgen_time;
ASN1_OBJECT *def_policy_id_obj;
STACK_OF(X509) *inter_certs;
VALUE md_holders;
};

static ASN1_INTEGER *
ossl_tsfac_serial_cb(struct TS_resp_ctx *ctx, void *data)
ossl_tsfac_serial_cb(TS_RESP_CTX *ctx, void *args_)
{
ASN1_INTEGER **snptr = (ASN1_INTEGER **)data;
ASN1_INTEGER *sn = *snptr;
*snptr = NULL;
struct tsfac_create_ts_args *args = args_;
ASN1_INTEGER *sn = args->asn1_serial;
// Will be freed by TS_RESP_create_response()
args->asn1_serial = NULL;
return sn;
}

static int
#if !defined(LIBRESSL_VERSION_NUMBER)
ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, long *sec, long *usec)
ossl_tsfac_time_cb(TS_RESP_CTX *ctx, void *args_, long *sec, long *usec)
#else
ossl_tsfac_time_cb(struct TS_resp_ctx *ctx, void *data, time_t *sec, long *usec)
ossl_tsfac_time_cb(TS_RESP_CTX *ctx, void *args_, time_t *sec, long *usec)
#endif
{
*sec = *((long *)data);
struct tsfac_create_ts_args *args = args_;
*sec = args->lgen_time;
*usec = 0;
return 1;
}

static VALUE
ossl_evp_md_fetch_i(VALUE args_)
tsfac_create_ts_i(VALUE args_)
{
VALUE *args = (VALUE *)args_, md_holder;
const EVP_MD *md;
struct tsfac_create_ts_args *args = (void *)args_;
TS_RESP_CTX *ctx;

md = ossl_evp_md_fetch(args[1], &md_holder);
rb_ary_push(args[0], md_holder);
return (VALUE)md;
}
ctx = args->ctx = TS_RESP_CTX_new();
if (!ctx)
ossl_raise(eTimestampError, "TS_RESP_CTX_new");

static VALUE
ossl_obj2bio_i(VALUE arg)
{
return (VALUE)ossl_obj2bio((VALUE *)arg);
X509 *tsa_cert = GetX509CertPtr(args->certificate);
if (!TS_RESP_CTX_set_signer_cert(ctx, tsa_cert))
ossl_raise(eTimestampError,
"Certificate does not contain the timestamping extension");

VALUE additional_certs = ossl_tsfac_get_additional_certs(args->self);
if (rb_obj_is_kind_of(additional_certs, rb_cArray)) {
args->inter_certs = ossl_x509_ary2sk(additional_certs);

/* this dups the sk_X509 and ups each cert's ref count */
if (!TS_RESP_CTX_set_certs(ctx, args->inter_certs))
ossl_raise(eTimestampError, "TS_RESP_CTX_set_certs");
}

EVP_PKEY *sign_key = GetPrivPKeyPtr(args->key);
if (!TS_RESP_CTX_set_signer_key(ctx, sign_key))
ossl_raise(eTimestampError, "TS_RESP_CTX_set_signer_key");

VALUE gen_time = ossl_tsfac_get_gen_time(args->self);
if (!rb_obj_is_instance_of(gen_time, rb_cTime))
ossl_raise(eTimestampError, "@gen_time must be a Time");
args->lgen_time = NUM2LONG(rb_funcall(gen_time, rb_intern("to_i"), 0));
TS_RESP_CTX_set_time_cb(ctx, ossl_tsfac_time_cb, args);

VALUE serial_number = ossl_tsfac_get_serial_number(args->self);
if (NIL_P(serial_number))
ossl_raise(eTimestampError, "@serial_number must be set");
args->asn1_serial = num_to_asn1integer(serial_number, NULL);
TS_RESP_CTX_set_serial_cb(ctx, ossl_tsfac_serial_cb, args);

TS_REQ *req;
GetTSRequest(args->request, req);
const ASN1_OBJECT *def_policy = TS_REQ_get_policy_id(req);
VALUE def_policy_id = ossl_tsfac_get_default_policy_id(args->self);
if (!def_policy) {
if (NIL_P(def_policy_id)) {
ossl_raise(eTimestampError,
"No policy id in the request and no default policy set");
}
def_policy = args->def_policy_id_obj = ossl_to_asn1obj(def_policy_id);
}
if (!TS_RESP_CTX_set_def_policy(ctx, def_policy))
ossl_raise(eTimestampError, "TS_RESP_CTX_set_def_policy");

VALUE allowed_digests = ossl_tsfac_get_allowed_digests(args->self);
if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) {
args->md_holders = rb_ary_new_capa(RARRAY_LEN(allowed_digests));
for (rb_len_t i = 0; i < RARRAY_LEN(allowed_digests); i++) {
VALUE digest = rb_ary_entry(allowed_digests, i), md_holder;
const EVP_MD *md = ossl_evp_md_fetch(digest, &md_holder);
rb_ary_push(args->md_holders, md_holder);
if (!TS_RESP_CTX_add_md(ctx, md))
ossl_raise(eTimestampError, "TS_RESP_CTX_add_md");
}
}

VALUE ret = ossl_ts_resp_alloc(cTimestampResponse);
VALUE str = ossl_to_der(args->request);
BIO *req_bio = ossl_obj2bio(&str);
TS_RESP *response = TS_RESP_create_response(ctx, req_bio);
BIO_free(req_bio);
if (!response)
ossl_raise(eTimestampError, "Error during response generation");
RTYPEDDATA_DATA(ret) = response;

/* bad responses aren't exceptional, but openssl still sets error
* information. */
ossl_clear_error();

return ret;
}

/*
Expand Down Expand Up @@ -1127,131 +1198,20 @@ ossl_obj2bio_i(VALUE arg)
static VALUE
ossl_tsfac_create_ts(VALUE self, VALUE key, VALUE certificate, VALUE request)
{
VALUE serial_number, def_policy_id, gen_time, additional_certs,
allowed_digests, allowed_digests_tmp = Qnil;
VALUE str;
STACK_OF(X509) *inter_certs;
VALUE tsresp, ret = Qnil;
EVP_PKEY *sign_key;
X509 *tsa_cert;
TS_REQ *req;
TS_RESP *response = NULL;
TS_RESP_CTX *ctx = NULL;
BIO *req_bio;
ASN1_INTEGER *asn1_serial = NULL;
ASN1_OBJECT *def_policy_id_obj = NULL;
long lgen_time;
const char * err_msg = NULL;
int status = 0;

tsresp = ossl_ts_resp_alloc(cTimestampResponse);
tsa_cert = GetX509CertPtr(certificate);
sign_key = GetPrivPKeyPtr(key);
GetTSRequest(request, req);

gen_time = ossl_tsfac_get_gen_time(self);
if (!rb_obj_is_instance_of(gen_time, rb_cTime)) {
err_msg = "@gen_time must be a Time.";
goto end;
}
lgen_time = NUM2LONG(rb_funcall(gen_time, rb_intern("to_i"), 0));

serial_number = ossl_tsfac_get_serial_number(self);
if (NIL_P(serial_number)) {
err_msg = "@serial_number must be set.";
goto end;
}
asn1_serial = num_to_asn1integer(serial_number, NULL);

def_policy_id = ossl_tsfac_get_default_policy_id(self);
if (NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) {
err_msg = "No policy id in the request and no default policy set";
goto end;
}
if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req)) {
def_policy_id_obj = (ASN1_OBJECT*)rb_protect(obj_to_asn1obj_i, (VALUE)def_policy_id, &status);
if (status)
goto end;
}

if (!(ctx = TS_RESP_CTX_new())) {
err_msg = "Memory allocation failed.";
goto end;
}

TS_RESP_CTX_set_serial_cb(ctx, ossl_tsfac_serial_cb, &asn1_serial);
if (!TS_RESP_CTX_set_signer_cert(ctx, tsa_cert)) {
err_msg = "Certificate does not contain the timestamping extension";
goto end;
}

additional_certs = ossl_tsfac_get_additional_certs(self);
if (rb_obj_is_kind_of(additional_certs, rb_cArray)) {
inter_certs = ossl_protect_x509_ary2sk(additional_certs, &status);
if (status)
goto end;

/* this dups the sk_X509 and ups each cert's ref count */
TS_RESP_CTX_set_certs(ctx, inter_certs);
sk_X509_pop_free(inter_certs, X509_free);
}

TS_RESP_CTX_set_signer_key(ctx, sign_key);
if (!NIL_P(def_policy_id) && !TS_REQ_get_policy_id(req))
TS_RESP_CTX_set_def_policy(ctx, def_policy_id_obj);
if (TS_REQ_get_policy_id(req))
TS_RESP_CTX_set_def_policy(ctx, TS_REQ_get_policy_id(req));
TS_RESP_CTX_set_time_cb(ctx, ossl_tsfac_time_cb, &lgen_time);

allowed_digests = ossl_tsfac_get_allowed_digests(self);
if (rb_obj_is_kind_of(allowed_digests, rb_cArray)) {
allowed_digests_tmp = rb_ary_new_capa(RARRAY_LEN(allowed_digests));
for (rb_len_t i = 0; i < RARRAY_LEN(allowed_digests); i++) {
VALUE args[] = {
allowed_digests_tmp,
rb_ary_entry(allowed_digests, i),
};
const EVP_MD *md = (const EVP_MD *)rb_protect(ossl_evp_md_fetch_i,
(VALUE)args, &status);
if (status)
goto end;
if (!TS_RESP_CTX_add_md(ctx, md))
goto end;
}
}

str = rb_protect(ossl_to_der, request, &status);
if (status)
goto end;

req_bio = (BIO*)rb_protect(ossl_obj2bio_i, (VALUE)&str, &status);
if (status)
goto end;

response = TS_RESP_create_response(ctx, req_bio);
BIO_free(req_bio);
RB_GC_GUARD(allowed_digests_tmp);

if (!response) {
err_msg = "Error during response generation";
goto end;
}

/* bad responses aren't exceptional, but openssl still sets error
* information. */
ossl_clear_error();

RTYPEDDATA_DATA(tsresp) = response;
ret = tsresp;

end:
ASN1_INTEGER_free(asn1_serial);
ASN1_OBJECT_free(def_policy_id_obj);
TS_RESP_CTX_free(ctx);
if (err_msg)
rb_exc_raise(ossl_make_error(eTimestampError, rb_str_new_cstr(err_msg)));
if (status)
rb_jump_tag(status);
struct tsfac_create_ts_args args = {
.self = self,
.key = key,
.certificate = certificate,
.request = request,
};
int state;
VALUE ret = rb_protect(tsfac_create_ts_i, (VALUE)&args, &state);
ASN1_INTEGER_free(args.asn1_serial);
ASN1_OBJECT_free(args.def_policy_id_obj);
TS_RESP_CTX_free(args.ctx);
sk_X509_pop_free(args.inter_certs, X509_free);
if (state)
rb_jump_tag(state);
return ret;
}

Expand Down
Loading