aboutsummaryrefslogtreecommitdiffstats
path: root/ossl_x509store.c
diff options
context:
space:
mode:
authorMichal Rokos <m.rokos@sh.cvut.cz>2002-06-04 06:44:42 +0000
committerMichal Rokos <m.rokos@sh.cvut.cz>2002-06-04 06:44:42 +0000
commit55dda5d77323c8100fa87e681893df83b451e131 (patch)
treecd2cea7862bed69939cb64d20346a3f975b5a9cc /ossl_x509store.c
downloadruby-openssl-history-55dda5d77323c8100fa87e681893df83b451e131.tar.gz
Initial revision
Diffstat (limited to 'ossl_x509store.c')
-rw-r--r--ossl_x509store.c529
1 files changed, 529 insertions, 0 deletions
diff --git a/ossl_x509store.c b/ossl_x509store.c
new file mode 100644
index 0000000..00ee0c8
--- /dev/null
+++ b/ossl_x509store.c
@@ -0,0 +1,529 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+#include <rubysig.h>
+
+#define MakeX509Store(obj, storep) obj = Data_Make_Struct(cX509Store, ossl_x509store, 0, ossl_x509store_free, storep)
+#define GetX509Store_unsafe(obj, storep) Data_Get_Struct(obj, ossl_x509store, storep)
+#define GetX509Store(obj, storep) do {\
+ GetX509Store_unsafe(obj, storep);\
+ if (!storep->store) rb_raise(eX509StoreError, "not initialized!");\
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Store;
+VALUE eX509StoreError;
+
+/*
+ * General callback for OpenSSL verify
+ */
+int ossl_x509store_verify_cb(int, X509_STORE_CTX *);
+
+/*
+ * Struct
+ */
+typedef struct ossl_x509store_st {
+ char protect;
+ X509_STORE_CTX *store;
+} ossl_x509store;
+
+static void
+ossl_x509store_free(ossl_x509store *storep)
+{
+ if (storep) {
+ if (storep->store && storep->protect == 0)
+ X509_STORE_CTX_free(storep->store);
+
+ storep->store = NULL;
+ free(storep);
+ }
+}
+
+/*
+ * Public functions
+ */
+VALUE
+ossl_x509store_new(X509_STORE_CTX *ctx)
+{
+ ossl_x509store *storep = NULL;
+ VALUE obj;
+
+ MakeX509Store(obj, storep);
+
+ /*
+ * Is there any way to _dup X509_STORE_CTX?
+ */
+ /*
+ if (!(ctx2 = X509_STORE_CTX_new())) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_STORE_CTX_init(ctx2, X509_STORE_dup(ctx->ctx), X509_dup(ctx->cert), NULL);
+ */
+ storep->store = ctx;
+ storep->protect = 1; /* we're using pointer without DUP - don't free this one */
+
+ return obj;
+}
+
+X509_STORE *
+ossl_x509store_get_X509_STORE(VALUE obj)
+{
+ ossl_x509store *storep = NULL;
+
+ OSSL_Check_Type(obj, cX509Store);
+ GetX509Store(obj, storep);
+
+ storep->protect = 1; /* we gave out internal pointer without DUP - don't free this one */
+ return storep->store->ctx;
+}
+
+/*
+ * verify_cb DATABASE for Stores
+ * TODO:
+ * clean entries when garbage collecting
+ */
+typedef struct ossl_session_db_st {
+ void *key;
+ VALUE data;
+ struct ossl_session_db_st *next;
+} ossl_session_db;
+
+ossl_session_db *db_root;
+
+static VALUE
+ossl_session_db_get(void *key)
+{
+ ossl_session_db *item = db_root;
+
+ rb_thread_critical = 1;
+ while (item) {
+ if (item->key == key) {
+ rb_thread_critical = 0;
+ return item->data;
+ }
+ item = item->next;
+ }
+ rb_thread_critical = 0;
+ return Qnil;
+}
+
+static VALUE
+ossl_session_db_set(void *key, VALUE data)
+{
+ ossl_session_db *item = db_root, *last = NULL;
+
+ rb_thread_critical = 1;
+ while (item) {
+ if (item->key == key) {
+ item->data = data;
+ rb_thread_critical = 0;
+ return data;
+ }
+ last = item;
+ item = last->next;
+ }
+ if (!(item = (ossl_session_db *)OPENSSL_malloc(sizeof(ossl_session_db)))) {
+ rb_thread_critical = 0;
+ OSSL_Raise(eX509StoreError, "");
+ }
+ item->key = key;
+ item->data = data;
+ item->next = NULL;
+ if (last)
+ last->next = item;
+ else
+ db_root = item;
+ rb_thread_critical = 0;
+
+ return data;
+}
+
+/*
+ * Private functions
+ */
+static VALUE
+ossl_x509store_s_new(int argc, VALUE *argv, VALUE klass)
+{
+ ossl_x509store *storep = NULL;
+ VALUE obj;
+
+ MakeX509Store(obj, storep);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+}
+
+static VALUE
+ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
+{
+ ossl_x509store *storep = NULL;
+ X509_STORE *store = NULL;
+
+ GetX509Store_unsafe(self, storep);
+
+ if (!(store = X509_STORE_new())) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+ if (!(storep->store = X509_STORE_CTX_new())) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_STORE_set_verify_cb_func(store, ossl_x509store_verify_cb);
+ /* OpenSSL 0.9.6c
+ * X509_STORE_CTX_set_verify_cb(ctx, func);
+ */
+ X509_STORE_CTX_init(storep->store, store, NULL, NULL);
+
+ /*
+ * instance variable
+ */
+ rb_ivar_set(self, rb_intern("@verify_callback"), Qnil);
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_add_trusted(VALUE self, VALUE cert)
+{
+ ossl_x509store *storep = NULL;
+ X509 *x509 = NULL;
+
+ GetX509Store(self, storep);
+
+ OSSL_Check_Type(cert, cX509Certificate);
+ x509 = ossl_x509_get_X509(cert);
+
+ if (!X509_STORE_add_cert(storep->store->ctx, x509)) {
+ X509_free(x509);
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_free(x509);
+
+ return cert;
+}
+
+static VALUE
+ossl_x509store_get_chain(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+ X509 *x509 = NULL;
+ int i, num;
+ VALUE ary;
+
+ GetX509Store(self, storep);
+
+ num = sk_X509_num(storep->store->chain);
+
+ if (num < 0) {
+ rb_warning("certs in chain < 0???");
+ return rb_ary_new();
+ }
+
+ ary = rb_ary_new2(num);
+
+ for(i=0; i<num; i++) {
+ x509 = sk_X509_value(storep->store->chain, i);
+ rb_ary_push(ary, ossl_x509_new(x509));
+ X509_free(x509);
+ }
+
+ return ary;
+}
+
+static VALUE
+ossl_x509store_add_crl(VALUE self, VALUE crlst)
+{
+ ossl_x509store *storep = NULL;
+ X509_CRL *crl = NULL;
+
+ GetX509Store(self, storep);
+
+ OSSL_Check_Type(crlst, cX509CRL);
+
+ crl = ossl_x509crl_get_X509_CRL(crlst);
+
+ if (!X509_STORE_add_crl(storep->store->ctx, crl)) {
+ X509_CRL_free(crl);
+ OSSL_Raise(eX509StoreError, "");
+ }
+ X509_CRL_free(crl);
+
+ return crlst;
+}
+
+static VALUE
+ossl_x509store_call_verify_cb_proc(VALUE args)
+{
+ VALUE proc, ok, store_ctx;
+
+ proc = rb_ary_entry(args, 0);
+ ok = rb_ary_entry(args, 1);
+ store_ctx = rb_ary_entry(args, 2);
+
+ return rb_funcall(proc, rb_intern("call"), 2, ok, store_ctx);
+}
+
+/*
+ * rescue!
+ */
+static VALUE
+ossl_x509store_verify_false(VALUE dummy)
+{
+ return Qfalse;
+}
+
+int
+ossl_x509store_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+ VALUE proc, store_ctx, args, ret = Qnil;
+
+ /*
+ * Get Proc from verify_cb Database
+ */
+ proc = ossl_session_db_get((void *)ctx->ctx);
+
+ if (!NIL_P(proc)) {
+ store_ctx = ossl_x509store_new(ctx);
+ /* rb_funcall(store_ctx, rb_intern("protect"), 0, NULL); -- called default by ossl_..new */
+ args = rb_ary_new2(3);
+ rb_ary_store(args, 0, proc);
+ rb_ary_store(args, 1, ok ? Qtrue : Qfalse);
+ rb_ary_store(args, 2, store_ctx);
+ ret = rb_rescue(ossl_x509store_call_verify_cb_proc, args, ossl_x509store_verify_false, Qnil);
+
+ if (ret == Qtrue) {
+ ok = 1;
+ X509_STORE_CTX_set_error(ctx, X509_V_OK);
+ } else {
+ ok = 0;
+ if (X509_STORE_CTX_get_error(ctx) == X509_V_OK)
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
+ }
+ }
+
+ return ok;
+}
+
+static VALUE
+ossl_x509store_verify(VALUE self, VALUE cert)
+{
+ ossl_x509store *storep = NULL;
+ X509 *x509 = NULL;
+ int result = 0;
+
+ GetX509Store(self, storep);
+
+ OSSL_Check_Type(cert, cX509Certificate);
+ x509 = ossl_x509_get_X509(cert);
+ X509_STORE_CTX_set_cert(storep->store, x509);
+
+ result = X509_verify_cert(storep->store);
+ /*X509_STORE_CTX_cleanup(storep->store); *clears chain*/
+
+ if (result == 1) return Qtrue;
+ return Qfalse;
+}
+
+static VALUE
+ossl_x509store_get_verify_status(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return INT2FIX(X509_STORE_CTX_get_error(storep->store));
+}
+
+static VALUE
+ossl_x509store_set_verify_status(VALUE self, VALUE err)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ X509_STORE_CTX_set_error(storep->store, FIX2INT(err));
+
+ return err;
+}
+
+static VALUE
+ossl_x509store_get_verify_message(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return rb_str_new2(X509_verify_cert_error_string(storep->store->error));
+}
+
+static VALUE
+ossl_x509store_get_verify_depth(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return INT2FIX(X509_STORE_CTX_get_error_depth(storep->store));
+}
+
+static VALUE
+ossl_x509store_get_cert(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ return ossl_x509_new(X509_STORE_CTX_get_current_cert(storep->store));
+}
+
+static VALUE
+ossl_x509store_protect(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+ storep->protect = 1;
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_set_default_paths(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ if (!X509_STORE_set_default_paths(storep->store->ctx)) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_load_locations(VALUE self, VALUE path)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ Check_SafeStr(path);
+
+ if (!X509_STORE_load_locations(storep->store->ctx, NULL, RSTRING(path)->ptr)) {
+ OSSL_Raise(eX509StoreError, "");
+ }
+
+ return self;
+}
+
+static VALUE
+ossl_x509store_set_verify_cb(VALUE self, VALUE proc)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ /*
+ * Associate verify_cb with Store in DB
+ */
+ ossl_session_db_set((void *)storep->store->ctx, proc);
+ rb_ivar_set(self, rb_intern("@verify_callback"), proc);
+
+ return proc;
+}
+
+static VALUE
+ossl_x509store_cleanup(VALUE self)
+{
+ ossl_x509store *storep = NULL;
+
+ GetX509Store(self, storep);
+
+ X509_STORE_CTX_cleanup(storep->store);
+
+ return self;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509store(VALUE module)
+{
+ /*
+ * INIT verify_cb DB
+ */
+ db_root = NULL;
+
+ eX509StoreError = rb_define_class_under(module, "StoreError", eOSSLError);
+
+ cX509Store = rb_define_class_under(module, "Store", rb_cObject);
+ rb_define_singleton_method(cX509Store, "new", ossl_x509store_s_new, -1);
+ rb_define_method(cX509Store, "initialize", ossl_x509store_initialize, -1);
+
+ rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse);
+ rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_verify_cb, 1);
+
+ rb_define_method(cX509Store, "add_trusted", ossl_x509store_add_trusted, 1);
+ rb_define_method(cX509Store, "add_crl", ossl_x509store_add_crl, 1);
+
+ rb_define_method(cX509Store, "verify", ossl_x509store_verify, 1);
+ rb_define_method(cX509Store, "verify_status", ossl_x509store_get_verify_status, 0);
+ rb_define_method(cX509Store, "verify_status=", ossl_x509store_set_verify_status, 1);
+ rb_define_method(cX509Store, "verify_message", ossl_x509store_get_verify_message, 0);
+ rb_define_method(cX509Store, "verify_depth", ossl_x509store_get_verify_depth, 0);
+ rb_define_method(cX509Store, "chain", ossl_x509store_get_chain, 0);
+ rb_define_method(cX509Store, "cert", ossl_x509store_get_cert, 0);
+ rb_define_method(cX509Store, "protect", ossl_x509store_protect, 0);
+ rb_define_method(cX509Store, "set_default_paths", ossl_x509store_set_default_paths, 0);
+ rb_define_method(cX509Store, "load_locations", ossl_x509store_load_locations, 1);
+
+ rb_define_method(cX509Store, "cleanup!", ossl_x509store_cleanup, 0);
+
+#define DefX509StoreConst(x) rb_define_const(cX509Store, #x, INT2FIX(X509_V_ERR_##x))
+
+ DefX509StoreConst(UNABLE_TO_GET_ISSUER_CERT);
+ DefX509StoreConst(UNABLE_TO_GET_CRL);
+ DefX509StoreConst(UNABLE_TO_DECRYPT_CERT_SIGNATURE);
+ DefX509StoreConst(UNABLE_TO_DECRYPT_CRL_SIGNATURE);
+ DefX509StoreConst(UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
+ DefX509StoreConst(CERT_SIGNATURE_FAILURE);
+ DefX509StoreConst(CRL_SIGNATURE_FAILURE);
+ DefX509StoreConst(CERT_NOT_YET_VALID);
+ DefX509StoreConst(CERT_HAS_EXPIRED);
+ DefX509StoreConst(CRL_NOT_YET_VALID);
+ DefX509StoreConst(CRL_HAS_EXPIRED);
+ DefX509StoreConst(ERROR_IN_CERT_NOT_BEFORE_FIELD);
+ DefX509StoreConst(ERROR_IN_CERT_NOT_AFTER_FIELD);
+ DefX509StoreConst(ERROR_IN_CRL_LAST_UPDATE_FIELD);
+ DefX509StoreConst(ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+ DefX509StoreConst(OUT_OF_MEM);
+ DefX509StoreConst(DEPTH_ZERO_SELF_SIGNED_CERT);
+ DefX509StoreConst(SELF_SIGNED_CERT_IN_CHAIN);
+ DefX509StoreConst(UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+ DefX509StoreConst(UNABLE_TO_VERIFY_LEAF_SIGNATURE);
+ DefX509StoreConst(CERT_CHAIN_TOO_LONG);
+ DefX509StoreConst(CERT_REVOKED);
+ DefX509StoreConst(INVALID_CA);
+ DefX509StoreConst(PATH_LENGTH_EXCEEDED);
+ DefX509StoreConst(INVALID_PURPOSE);
+ DefX509StoreConst(CERT_UNTRUSTED);
+ DefX509StoreConst(CERT_REJECTED);
+ DefX509StoreConst(SUBJECT_ISSUER_MISMATCH);
+ DefX509StoreConst(AKID_SKID_MISMATCH);
+ DefX509StoreConst(AKID_ISSUER_SERIAL_MISMATCH);
+ DefX509StoreConst(KEYUSAGE_NO_CERTSIGN);
+ DefX509StoreConst(APPLICATION_VERIFICATION);
+}
+