Ruby 1.9.3p327(2012-11-10revision37606)
|
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