Ruby 1.9.3p327(2012-11-10revision37606)
ext/openssl/ossl_x509store.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_x509store.c 31165 2011-03-24 04:49:18Z naruse $
00003  * 'OpenSSL for Ruby' project
00004  * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
00005  * All rights reserved.
00006  */
00007 /*
00008  * This program is licenced under the same licence as Ruby.
00009  * (See the file 'LICENCE'.)
00010  */
00011 #include "ossl.h"
00012 
00013 #define WrapX509Store(klass, obj, st) do { \
00014     if (!(st)) { \
00015         ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
00016     } \
00017     (obj) = Data_Wrap_Struct((klass), 0, X509_STORE_free, (st)); \
00018 } while (0)
00019 #define GetX509Store(obj, st) do { \
00020     Data_Get_Struct((obj), X509_STORE, (st)); \
00021     if (!(st)) { \
00022         ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
00023     } \
00024 } while (0)
00025 #define SafeGetX509Store(obj, st) do { \
00026     OSSL_Check_Kind((obj), cX509Store); \
00027     GetX509Store((obj), (st)); \
00028 } while (0)
00029 
00030 #define WrapX509StCtx(klass, obj, ctx) do { \
00031     if (!(ctx)) { \
00032         ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
00033     } \
00034     (obj) = Data_Wrap_Struct((klass), 0, ossl_x509stctx_free, (ctx)); \
00035 } while (0)
00036 #define GetX509StCtx(obj, ctx) do { \
00037     Data_Get_Struct((obj), X509_STORE_CTX, (ctx)); \
00038     if (!(ctx)) { \
00039         ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
00040     } \
00041 } while (0)
00042 #define SafeGetX509StCtx(obj, storep) do { \
00043     OSSL_Check_Kind((obj), cX509StoreContext); \
00044     GetX509Store((obj), (ctx)); \
00045 } while (0)
00046 
00047 /*
00048  * Classes
00049  */
00050 VALUE cX509Store;
00051 VALUE cX509StoreContext;
00052 VALUE eX509StoreError;
00053 
00054 /*
00055  * Public functions
00056  */
00057 VALUE
00058 ossl_x509store_new(X509_STORE *store)
00059 {
00060     VALUE obj;
00061 
00062     WrapX509Store(cX509Store, obj, store);
00063 
00064     return obj;
00065 }
00066 
00067 X509_STORE *
00068 GetX509StorePtr(VALUE obj)
00069 {
00070     X509_STORE *store;
00071 
00072     SafeGetX509Store(obj, store);
00073 
00074     return store;
00075 }
00076 
00077 X509_STORE *
00078 DupX509StorePtr(VALUE obj)
00079 {
00080     X509_STORE *store;
00081 
00082     SafeGetX509Store(obj, store);
00083     CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
00084 
00085     return store;
00086 }
00087 
00088 /*
00089  * Private functions
00090  */
00091 static VALUE
00092 ossl_x509store_alloc(VALUE klass)
00093 {
00094     X509_STORE *store;
00095     VALUE obj;
00096 
00097     if((store = X509_STORE_new()) == NULL){
00098         ossl_raise(eX509StoreError, NULL);
00099     }
00100     WrapX509Store(klass, obj, store);
00101 
00102     return obj;
00103 }
00104 
00105 /*
00106  * General callback for OpenSSL verify
00107  */
00108 static VALUE
00109 ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
00110 {
00111     X509_STORE *store;
00112 
00113     GetX509Store(self, store);
00114     X509_STORE_set_ex_data(store, ossl_verify_cb_idx, (void*)cb);
00115     rb_iv_set(self, "@verify_callback", cb);
00116 
00117     return cb;
00118 }
00119 
00120 
00121 /*
00122  * call-seq:
00123  *    X509::Store.new => store
00124  *
00125  */
00126 static VALUE
00127 ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
00128 {
00129     X509_STORE *store;
00130 
00131 /* BUG: This method takes any number of arguments but appears to ignore them. */
00132     GetX509Store(self, store);
00133     store->ex_data.sk = NULL;
00134     X509_STORE_set_verify_cb_func(store, ossl_verify_cb);
00135     ossl_x509store_set_vfy_cb(self, Qnil);
00136 
00137 #if (OPENSSL_VERSION_NUMBER < 0x00907000L)
00138     rb_iv_set(self, "@flags", INT2NUM(0));
00139     rb_iv_set(self, "@purpose", INT2NUM(0));
00140     rb_iv_set(self, "@trust", INT2NUM(0));
00141 #endif
00142 
00143     /* last verification status */
00144     rb_iv_set(self, "@error", Qnil);
00145     rb_iv_set(self, "@error_string", Qnil);
00146     rb_iv_set(self, "@chain", Qnil);
00147     rb_iv_set(self, "@time", Qnil);
00148 
00149     return self;
00150 }
00151 
00152 static VALUE
00153 ossl_x509store_set_flags(VALUE self, VALUE flags)
00154 {
00155 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
00156     X509_STORE *store;
00157     long f = NUM2LONG(flags);
00158 
00159     GetX509Store(self, store);
00160     X509_STORE_set_flags(store, f);
00161 #else
00162     rb_iv_set(self, "@flags", flags);
00163 #endif
00164 
00165     return flags;
00166 }
00167 
00168 static VALUE
00169 ossl_x509store_set_purpose(VALUE self, VALUE purpose)
00170 {
00171 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
00172     X509_STORE *store;
00173     int p = NUM2INT(purpose);
00174 
00175     GetX509Store(self, store);
00176     X509_STORE_set_purpose(store, p);
00177 #else
00178     rb_iv_set(self, "@purpose", purpose);
00179 #endif
00180 
00181     return purpose;
00182 }
00183 
00184 static VALUE
00185 ossl_x509store_set_trust(VALUE self, VALUE trust)
00186 {
00187 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
00188     X509_STORE *store;
00189     int t = NUM2INT(trust);
00190 
00191     GetX509Store(self, store);
00192     X509_STORE_set_trust(store, t);
00193 #else
00194     rb_iv_set(self, "@trust", trust);
00195 #endif
00196 
00197     return trust;
00198 }
00199 
00200 static VALUE
00201 ossl_x509store_set_time(VALUE self, VALUE time)
00202 {
00203     rb_iv_set(self, "@time", time);
00204     return time;
00205 }
00206 
00207 static VALUE
00208 ossl_x509store_add_file(VALUE self, VALUE file)
00209 {
00210     X509_STORE *store;
00211     X509_LOOKUP *lookup;
00212     char *path = NULL;
00213 
00214     if(file != Qnil){
00215         SafeStringValue(file);
00216         path = RSTRING_PTR(file);
00217     }
00218     GetX509Store(self, store);
00219     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
00220     if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
00221     if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){
00222         ossl_raise(eX509StoreError, NULL);
00223     }
00224 
00225     return self;
00226 }
00227 
00228 static VALUE
00229 ossl_x509store_add_path(VALUE self, VALUE dir)
00230 {
00231     X509_STORE *store;
00232     X509_LOOKUP *lookup;
00233     char *path = NULL;
00234 
00235     if(dir != Qnil){
00236         SafeStringValue(dir);
00237         path = RSTRING_PTR(dir);
00238     }
00239     GetX509Store(self, store);
00240     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
00241     if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
00242     if(X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1){
00243         ossl_raise(eX509StoreError, NULL);
00244     }
00245 
00246     return self;
00247 }
00248 
00249 static VALUE
00250 ossl_x509store_set_default_paths(VALUE self)
00251 {
00252     X509_STORE *store;
00253 
00254     GetX509Store(self, store);
00255     if (X509_STORE_set_default_paths(store) != 1){
00256         ossl_raise(eX509StoreError, NULL);
00257     }
00258 
00259     return Qnil;
00260 }
00261 
00262 static VALUE
00263 ossl_x509store_add_cert(VALUE self, VALUE arg)
00264 {
00265     X509_STORE *store;
00266     X509 *cert;
00267 
00268     cert = GetX509CertPtr(arg); /* NO NEED TO DUP */
00269     GetX509Store(self, store);
00270     if (X509_STORE_add_cert(store, cert) != 1){
00271         ossl_raise(eX509StoreError, NULL);
00272     }
00273 
00274     return self;
00275 }
00276 
00277 static VALUE
00278 ossl_x509store_add_crl(VALUE self, VALUE arg)
00279 {
00280     X509_STORE *store;
00281     X509_CRL *crl;
00282 
00283     crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */
00284     GetX509Store(self, store);
00285     if (X509_STORE_add_crl(store, crl) != 1){
00286         ossl_raise(eX509StoreError, NULL);
00287     }
00288 
00289     return self;
00290 }
00291 
00292 static VALUE ossl_x509stctx_get_err(VALUE);
00293 static VALUE ossl_x509stctx_get_err_string(VALUE);
00294 static VALUE ossl_x509stctx_get_chain(VALUE);
00295 
00296 static VALUE
00297 ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
00298 {
00299     VALUE cert, chain;
00300     VALUE ctx, proc, result;
00301 
00302     rb_scan_args(argc, argv, "11", &cert, &chain);
00303     ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain);
00304     proc = rb_block_given_p() ?  rb_block_proc() :
00305            rb_iv_get(self, "@verify_callback");
00306     rb_iv_set(ctx, "@verify_callback", proc);
00307     result = rb_funcall(ctx, rb_intern("verify"), 0);
00308 
00309     rb_iv_set(self, "@error", ossl_x509stctx_get_err(ctx));
00310     rb_iv_set(self, "@error_string", ossl_x509stctx_get_err_string(ctx));
00311     rb_iv_set(self, "@chain", ossl_x509stctx_get_chain(ctx));
00312 
00313     return result;
00314 }
00315 
00316 /*
00317  * Public Functions
00318  */
00319 static void ossl_x509stctx_free(X509_STORE_CTX*);
00320 
00321 VALUE
00322 ossl_x509stctx_new(X509_STORE_CTX *ctx)
00323 {
00324     VALUE obj;
00325 
00326     WrapX509StCtx(cX509StoreContext, obj, ctx);
00327 
00328     return obj;
00329 }
00330 
00331 VALUE
00332 ossl_x509stctx_clear_ptr(VALUE obj)
00333 {
00334     OSSL_Check_Kind(obj, cX509StoreContext);
00335     RDATA(obj)->data = NULL;
00336 
00337     return obj;
00338 }
00339 
00340 /*
00341  * Private functions
00342  */
00343 static void
00344 ossl_x509stctx_free(X509_STORE_CTX *ctx)
00345 {
00346     if(ctx->untrusted)
00347         sk_X509_pop_free(ctx->untrusted, X509_free);
00348     if(ctx->cert)
00349         X509_free(ctx->cert);
00350     X509_STORE_CTX_free(ctx);
00351 }
00352 
00353 static VALUE
00354 ossl_x509stctx_alloc(VALUE klass)
00355 {
00356     X509_STORE_CTX *ctx;
00357     VALUE obj;
00358 
00359     if((ctx = X509_STORE_CTX_new()) == NULL){
00360         ossl_raise(eX509StoreError, NULL);
00361     }
00362     WrapX509StCtx(klass, obj, ctx);
00363 
00364     return obj;
00365 }
00366 
00367 static VALUE ossl_x509stctx_set_flags(VALUE, VALUE);
00368 static VALUE ossl_x509stctx_set_purpose(VALUE, VALUE);
00369 static VALUE ossl_x509stctx_set_trust(VALUE, VALUE);
00370 static VALUE ossl_x509stctx_set_time(VALUE, VALUE);
00371 
00372 static VALUE
00373 ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self)
00374 {
00375     VALUE store, cert, chain, t;
00376     X509_STORE_CTX *ctx;
00377     X509_STORE *x509st;
00378     X509 *x509 = NULL;
00379     STACK_OF(X509) *x509s = NULL;
00380 
00381     rb_scan_args(argc, argv, "12", &store, &cert, &chain);
00382     GetX509StCtx(self, ctx);
00383     SafeGetX509Store(store, x509st);
00384     if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */
00385     if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain);
00386 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
00387     if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){
00388         sk_X509_pop_free(x509s, X509_free);
00389         ossl_raise(eX509StoreError, NULL);
00390     }
00391 #else
00392     X509_STORE_CTX_init(ctx, x509st, x509, x509s);
00393     ossl_x509stctx_set_flags(self, rb_iv_get(store, "@flags"));
00394     ossl_x509stctx_set_purpose(self, rb_iv_get(store, "@purpose"));
00395     ossl_x509stctx_set_trust(self, rb_iv_get(store, "@trust"));
00396 #endif
00397     if (!NIL_P(t = rb_iv_get(store, "@time")))
00398         ossl_x509stctx_set_time(self, t);
00399     rb_iv_set(self, "@verify_callback", rb_iv_get(store, "@verify_callback"));
00400     rb_iv_set(self, "@cert", cert);
00401 
00402     return self;
00403 }
00404 
00405 static VALUE
00406 ossl_x509stctx_verify(VALUE self)
00407 {
00408     X509_STORE_CTX *ctx;
00409     int result;
00410 
00411     GetX509StCtx(self, ctx);
00412     X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx,
00413                                (void*)rb_iv_get(self, "@verify_callback"));
00414     result = X509_verify_cert(ctx);
00415 
00416     return result ? Qtrue : Qfalse;
00417 }
00418 
00419 static VALUE
00420 ossl_x509stctx_get_chain(VALUE self)
00421 {
00422     X509_STORE_CTX *ctx;
00423     STACK_OF(X509) *chain;
00424     X509 *x509;
00425     int i, num;
00426     VALUE ary;
00427 
00428     GetX509StCtx(self, ctx);
00429     if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){
00430         return Qnil;
00431     }
00432     if((num = sk_X509_num(chain)) < 0){
00433         OSSL_Debug("certs in chain < 0???");
00434         return rb_ary_new();
00435     }
00436     ary = rb_ary_new2(num);
00437     for(i = 0; i < num; i++) {
00438         x509 = sk_X509_value(chain, i);
00439         rb_ary_push(ary, ossl_x509_new(x509));
00440     }
00441 
00442     return ary;
00443 }
00444 
00445 static VALUE
00446 ossl_x509stctx_get_err(VALUE self)
00447 {
00448     X509_STORE_CTX *ctx;
00449 
00450     GetX509StCtx(self, ctx);
00451 
00452     return INT2FIX(X509_STORE_CTX_get_error(ctx));
00453 }
00454 
00455 static VALUE
00456 ossl_x509stctx_set_error(VALUE self, VALUE err)
00457 {
00458     X509_STORE_CTX *ctx;
00459 
00460     GetX509StCtx(self, ctx);
00461     X509_STORE_CTX_set_error(ctx, NUM2INT(err));
00462 
00463     return err;
00464 }
00465 
00466 static VALUE
00467 ossl_x509stctx_get_err_string(VALUE self)
00468 {
00469     X509_STORE_CTX *ctx;
00470     long err;
00471 
00472     GetX509StCtx(self, ctx);
00473     err = X509_STORE_CTX_get_error(ctx);
00474 
00475     return rb_str_new2(X509_verify_cert_error_string(err));
00476 }
00477 
00478 static VALUE
00479 ossl_x509stctx_get_err_depth(VALUE self)
00480 {
00481     X509_STORE_CTX *ctx;
00482 
00483     GetX509StCtx(self, ctx);
00484 
00485     return INT2FIX(X509_STORE_CTX_get_error_depth(ctx));
00486 }
00487 
00488 static VALUE
00489 ossl_x509stctx_get_curr_cert(VALUE self)
00490 {
00491     X509_STORE_CTX *ctx;
00492 
00493     GetX509StCtx(self, ctx);
00494 
00495     return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
00496 }
00497 
00498 static VALUE
00499 ossl_x509stctx_get_curr_crl(VALUE self)
00500 {
00501 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
00502     X509_STORE_CTX *ctx;
00503 
00504     GetX509StCtx(self, ctx);
00505     if(!ctx->current_crl) return Qnil;
00506 
00507     return ossl_x509crl_new(ctx->current_crl);
00508 #else
00509     return Qnil;
00510 #endif
00511 }
00512 
00513 static VALUE
00514 ossl_x509stctx_set_flags(VALUE self, VALUE flags)
00515 {
00516     X509_STORE_CTX *store;
00517     long f = NUM2LONG(flags);
00518 
00519     GetX509StCtx(self, store);
00520     X509_STORE_CTX_set_flags(store, f);
00521 
00522     return flags;
00523 }
00524 
00525 static VALUE
00526 ossl_x509stctx_set_purpose(VALUE self, VALUE purpose)
00527 {
00528     X509_STORE_CTX *store;
00529     int p = NUM2INT(purpose);
00530 
00531     GetX509StCtx(self, store);
00532     X509_STORE_CTX_set_purpose(store, p);
00533 
00534     return purpose;
00535 }
00536 
00537 static VALUE
00538 ossl_x509stctx_set_trust(VALUE self, VALUE trust)
00539 {
00540     X509_STORE_CTX *store;
00541     int t = NUM2INT(trust);
00542 
00543     GetX509StCtx(self, store);
00544     X509_STORE_CTX_set_trust(store, t);
00545 
00546     return trust;
00547 }
00548 
00549 /*
00550  * call-seq:
00551  *    storectx.time = time => time
00552  */
00553 static VALUE
00554 ossl_x509stctx_set_time(VALUE self, VALUE time)
00555 {
00556     X509_STORE_CTX *store;
00557     long t;
00558 
00559     t = NUM2LONG(rb_Integer(time));
00560     GetX509StCtx(self, store);
00561     X509_STORE_CTX_set_time(store, 0, t);
00562 
00563     return time;
00564 }
00565 
00566 /*
00567  * INIT
00568  */
00569 void
00570 Init_ossl_x509store()
00571 {
00572     VALUE x509stctx;
00573 
00574     eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError);
00575 
00576     cX509Store = rb_define_class_under(mX509, "Store", rb_cObject);
00577     rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse);
00578     rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse);
00579     rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse);
00580     rb_attr(cX509Store, rb_intern("chain"), 1, 0, Qfalse);
00581     rb_define_alloc_func(cX509Store, ossl_x509store_alloc);
00582     rb_define_method(cX509Store, "initialize",   ossl_x509store_initialize, -1);
00583     rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_vfy_cb, 1);
00584     rb_define_method(cX509Store, "flags=",       ossl_x509store_set_flags, 1);
00585     rb_define_method(cX509Store, "purpose=",     ossl_x509store_set_purpose, 1);
00586     rb_define_method(cX509Store, "trust=",       ossl_x509store_set_trust, 1);
00587     rb_define_method(cX509Store, "time=",        ossl_x509store_set_time, 1);
00588     rb_define_method(cX509Store, "add_path",     ossl_x509store_add_path, 1);
00589     rb_define_method(cX509Store, "add_file",     ossl_x509store_add_file, 1);
00590     rb_define_method(cX509Store, "set_default_paths", ossl_x509store_set_default_paths, 0);
00591     rb_define_method(cX509Store, "add_cert",     ossl_x509store_add_cert, 1);
00592     rb_define_method(cX509Store, "add_crl",      ossl_x509store_add_crl, 1);
00593     rb_define_method(cX509Store, "verify",       ossl_x509store_verify, -1);
00594 
00595     cX509StoreContext = rb_define_class_under(mX509,"StoreContext",rb_cObject);
00596     x509stctx = cX509StoreContext;
00597     rb_define_alloc_func(cX509StoreContext, ossl_x509stctx_alloc);
00598     rb_define_method(x509stctx,"initialize",  ossl_x509stctx_initialize, -1);
00599     rb_define_method(x509stctx,"verify",      ossl_x509stctx_verify, 0);
00600     rb_define_method(x509stctx,"chain",       ossl_x509stctx_get_chain,0);
00601     rb_define_method(x509stctx,"error",       ossl_x509stctx_get_err, 0);
00602     rb_define_method(x509stctx,"error=",      ossl_x509stctx_set_error, 1);
00603     rb_define_method(x509stctx,"error_string",ossl_x509stctx_get_err_string,0);
00604     rb_define_method(x509stctx,"error_depth", ossl_x509stctx_get_err_depth, 0);
00605     rb_define_method(x509stctx,"current_cert",ossl_x509stctx_get_curr_cert, 0);
00606     rb_define_method(x509stctx,"current_crl", ossl_x509stctx_get_curr_crl, 0);
00607     rb_define_method(x509stctx,"flags=",      ossl_x509stctx_set_flags, 1);
00608     rb_define_method(x509stctx,"purpose=",    ossl_x509stctx_set_purpose, 1);
00609     rb_define_method(x509stctx,"trust=",      ossl_x509stctx_set_trust, 1);
00610     rb_define_method(x509stctx,"time=",       ossl_x509stctx_set_time, 1);
00611 
00612 }
00613