2 * $Id: ossl_x509store.c 11708 2007-02-12 23:01:19Z shyouhei $
3 * 'OpenSSL for Ruby' project
4 * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
8 * This program is licenced under the same licence as Ruby.
9 * (See the file 'LICENCE'.)
14 #define WrapX509Store(klass, obj, st) do { \
16 ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
18 obj = Data_Wrap_Struct(klass, 0, X509_STORE_free, st); \
20 #define GetX509Store(obj, st) do { \
21 Data_Get_Struct(obj, X509_STORE, st); \
23 ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
26 #define SafeGetX509Store(obj, st) do { \
27 OSSL_Check_Kind(obj, cX509Store); \
28 GetX509Store(obj, st); \
31 #define WrapX509StCtx(klass, obj, ctx) do { \
33 ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
35 obj = Data_Wrap_Struct(klass, 0, ossl_x509stctx_free, ctx); \
37 #define GetX509StCtx(obj, ctx) do { \
38 Data_Get_Struct(obj, X509_STORE_CTX, ctx); \
40 ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
43 #define SafeGetX509StCtx(obj, storep) do { \
44 OSSL_Check_Kind(obj, cX509StoreContext); \
45 GetX509Store(obj, ctx); \
52 VALUE cX509StoreContext
;
53 VALUE eX509StoreError
;
59 ossl_x509store_new(X509_STORE
*store
)
63 WrapX509Store(cX509Store
, obj
, store
);
69 GetX509StorePtr(VALUE obj
)
73 SafeGetX509Store(obj
, store
);
79 DupX509StorePtr(VALUE obj
)
83 SafeGetX509Store(obj
, store
);
84 CRYPTO_add(&store
->references
, 1, CRYPTO_LOCK_X509_STORE
);
93 ossl_x509store_alloc(VALUE klass
)
98 if((store
= X509_STORE_new()) == NULL
){
99 ossl_raise(eX509StoreError
, NULL
);
101 WrapX509Store(klass
, obj
, store
);
107 * General callback for OpenSSL verify
110 ossl_x509store_set_vfy_cb(VALUE self
, VALUE cb
)
114 GetX509Store(self
, store
);
115 X509_STORE_set_ex_data(store
, ossl_verify_cb_idx
, (void*)cb
);
116 rb_iv_set(self
, "@verify_callback", cb
);
122 ossl_x509store_initialize(int argc
, VALUE
*argv
, VALUE self
)
126 GetX509Store(self
, store
);
127 X509_STORE_set_verify_cb_func(store
, ossl_verify_cb
);
128 ossl_x509store_set_vfy_cb(self
, Qnil
);
130 #if (OPENSSL_VERSION_NUMBER < 0x00907000L)
131 rb_iv_set(self
, "@flags", INT2NUM(0));
132 rb_iv_set(self
, "@purpose", INT2NUM(0));
133 rb_iv_set(self
, "@trust", INT2NUM(0));
136 /* last verification status */
137 rb_iv_set(self
, "@error", Qnil
);
138 rb_iv_set(self
, "@error_string", Qnil
);
139 rb_iv_set(self
, "@chain", Qnil
);
140 rb_iv_set(self
, "@time", Qnil
);
146 ossl_x509store_set_flags(VALUE self
, VALUE flags
)
148 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
150 long f
= NUM2LONG(flags
);
152 GetX509Store(self
, store
);
153 X509_STORE_set_flags(store
, f
);
155 rb_iv_set(self
, "@flags", flags
);
162 ossl_x509store_set_purpose(VALUE self
, VALUE purpose
)
164 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
166 long p
= NUM2LONG(purpose
);
168 GetX509Store(self
, store
);
169 X509_STORE_set_purpose(store
, p
);
171 rb_iv_set(self
, "@purpose", purpose
);
178 ossl_x509store_set_trust(VALUE self
, VALUE trust
)
180 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
182 long t
= NUM2LONG(trust
);
184 GetX509Store(self
, store
);
185 X509_STORE_set_trust(store
, t
);
187 rb_iv_set(self
, "@trust", trust
);
194 ossl_x509store_set_time(VALUE self
, VALUE time
)
196 rb_iv_set(self
, "@time", time
);
201 ossl_x509store_add_file(VALUE self
, VALUE file
)
209 path
= RSTRING(file
)->ptr
;
211 GetX509Store(self
, store
);
212 lookup
= X509_STORE_add_lookup(store
, X509_LOOKUP_file());
213 if(lookup
== NULL
) ossl_raise(eX509StoreError
, NULL
);
214 if(X509_LOOKUP_load_file(lookup
, path
, X509_FILETYPE_PEM
) != 1){
215 ossl_raise(eX509StoreError
, NULL
);
222 ossl_x509store_add_path(VALUE self
, VALUE dir
)
230 path
= RSTRING(dir
)->ptr
;
232 GetX509Store(self
, store
);
233 lookup
= X509_STORE_add_lookup(store
, X509_LOOKUP_hash_dir());
234 if(lookup
== NULL
) ossl_raise(eX509StoreError
, NULL
);
235 if(X509_LOOKUP_add_dir(lookup
, path
, X509_FILETYPE_PEM
) != 1){
236 ossl_raise(eX509StoreError
, NULL
);
243 ossl_x509store_set_default_paths(VALUE self
)
247 GetX509Store(self
, store
);
248 if (X509_STORE_set_default_paths(store
) != 1){
249 ossl_raise(eX509StoreError
, NULL
);
256 ossl_x509store_add_cert(VALUE self
, VALUE arg
)
261 cert
= GetX509CertPtr(arg
); /* NO NEED TO DUP */
262 GetX509Store(self
, store
);
263 if (X509_STORE_add_cert(store
, cert
) != 1){
264 ossl_raise(eX509StoreError
, NULL
);
271 ossl_x509store_add_crl(VALUE self
, VALUE arg
)
276 crl
= GetX509CRLPtr(arg
); /* NO NEED TO DUP */
277 GetX509Store(self
, store
);
278 if (X509_STORE_add_crl(store
, crl
) != 1){
279 ossl_raise(eX509StoreError
, NULL
);
285 static VALUE
ossl_x509stctx_get_err(VALUE
);
286 static VALUE
ossl_x509stctx_get_err_string(VALUE
);
287 static VALUE
ossl_x509stctx_get_chain(VALUE
);
290 ossl_x509store_verify(int argc
, VALUE
*argv
, VALUE self
)
293 VALUE ctx
, proc
, result
;
295 rb_scan_args(argc
, argv
, "11", &cert
, &chain
);
296 ctx
= rb_funcall(cX509StoreContext
, rb_intern("new"), 3, self
, cert
, chain
);
297 proc
= rb_block_given_p() ? rb_block_proc() :
298 rb_iv_get(self
, "@verify_callback");
299 rb_iv_set(ctx
, "@verify_callback", proc
);
300 result
= rb_funcall(ctx
, rb_intern("verify"), 0);
302 rb_iv_set(self
, "@error", ossl_x509stctx_get_err(ctx
));
303 rb_iv_set(self
, "@error_string", ossl_x509stctx_get_err_string(ctx
));
304 rb_iv_set(self
, "@chain", ossl_x509stctx_get_chain(ctx
));
312 static void ossl_x509stctx_free(X509_STORE_CTX
*);
315 ossl_x509stctx_new(X509_STORE_CTX
*ctx
)
319 WrapX509StCtx(cX509StoreContext
, obj
, ctx
);
325 ossl_x509stctx_clear_ptr(VALUE obj
)
327 OSSL_Check_Kind(obj
, cX509StoreContext
);
328 RDATA(obj
)->data
= NULL
;
337 ossl_x509stctx_free(X509_STORE_CTX
*ctx
)
340 sk_X509_pop_free(ctx
->untrusted
, X509_free
);
342 X509_free(ctx
->cert
);
343 X509_STORE_CTX_free(ctx
);
347 ossl_x509stctx_alloc(VALUE klass
)
352 if((ctx
= X509_STORE_CTX_new()) == NULL
){
353 ossl_raise(eX509StoreError
, NULL
);
355 WrapX509StCtx(klass
, obj
, ctx
);
360 static VALUE
ossl_x509stctx_set_flags(VALUE
, VALUE
);
361 static VALUE
ossl_x509stctx_set_purpose(VALUE
, VALUE
);
362 static VALUE
ossl_x509stctx_set_trust(VALUE
, VALUE
);
363 static VALUE
ossl_x509stctx_set_time(VALUE
, VALUE
);
366 ossl_x509stctx_initialize(int argc
, VALUE
*argv
, VALUE self
)
368 VALUE store
, cert
, chain
, t
;
372 STACK_OF(X509
) *x509s
= NULL
;
374 rb_scan_args(argc
, argv
, "12", &store
, &cert
, &chain
);
375 GetX509StCtx(self
, ctx
);
376 SafeGetX509Store(store
, x509st
);
377 if(!NIL_P(cert
)) x509
= DupX509CertPtr(cert
); /* NEED TO DUP */
378 if(!NIL_P(chain
)) x509s
= ossl_x509_ary2sk(chain
);
379 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
380 if(X509_STORE_CTX_init(ctx
, x509st
, x509
, x509s
) != 1){
381 sk_X509_pop_free(x509s
, X509_free
);
382 ossl_raise(eX509StoreError
, NULL
);
385 X509_STORE_CTX_init(ctx
, x509st
, x509
, x509s
);
386 ossl_x509stctx_set_flags(self
, rb_iv_get(store
, "@flags"));
387 ossl_x509stctx_set_purpose(self
, rb_iv_get(store
, "@purpose"));
388 ossl_x509stctx_set_trust(self
, rb_iv_get(store
, "@trust"));
390 if (!NIL_P(t
= rb_iv_get(store
, "@time")))
391 ossl_x509stctx_set_time(self
, t
);
392 rb_iv_set(self
, "@verify_callback", rb_iv_get(store
, "@verify_callback"));
393 rb_iv_set(self
, "@cert", cert
);
399 ossl_x509stctx_verify(VALUE self
)
404 GetX509StCtx(self
, ctx
);
405 X509_STORE_CTX_set_ex_data(ctx
, ossl_verify_cb_idx
,
406 (void*)rb_iv_get(self
, "@verify_callback"));
407 result
= X509_verify_cert(ctx
);
409 return result
? Qtrue
: Qfalse
;
413 ossl_x509stctx_get_chain(VALUE self
)
416 STACK_OF(X509
) *chain
;
421 GetX509StCtx(self
, ctx
);
422 if((chain
= X509_STORE_CTX_get_chain(ctx
)) == NULL
){
425 if((num
= sk_X509_num(chain
)) < 0){
426 OSSL_Debug("certs in chain < 0???");
429 ary
= rb_ary_new2(num
);
430 for(i
= 0; i
< num
; i
++) {
431 x509
= sk_X509_value(chain
, i
);
432 rb_ary_push(ary
, ossl_x509_new(x509
));
439 ossl_x509stctx_get_err(VALUE self
)
443 GetX509StCtx(self
, ctx
);
445 return INT2FIX(X509_STORE_CTX_get_error(ctx
));
449 ossl_x509stctx_set_error(VALUE self
, VALUE err
)
453 GetX509StCtx(self
, ctx
);
454 X509_STORE_CTX_set_error(ctx
, FIX2INT(err
));
460 ossl_x509stctx_get_err_string(VALUE self
)
465 GetX509StCtx(self
, ctx
);
466 err
= X509_STORE_CTX_get_error(ctx
);
468 return rb_str_new2(X509_verify_cert_error_string(err
));
472 ossl_x509stctx_get_err_depth(VALUE self
)
476 GetX509StCtx(self
, ctx
);
478 return INT2FIX(X509_STORE_CTX_get_error_depth(ctx
));
482 ossl_x509stctx_get_curr_cert(VALUE self
)
486 GetX509StCtx(self
, ctx
);
488 return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx
));
492 ossl_x509stctx_get_curr_crl(VALUE self
)
494 #if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
497 GetX509StCtx(self
, ctx
);
498 if(!ctx
->current_crl
) return Qnil
;
500 return ossl_x509crl_new(ctx
->current_crl
);
507 ossl_x509stctx_cleanup(VALUE self
)
511 GetX509StCtx(self
, ctx
);
512 X509_STORE_CTX_cleanup(ctx
);
518 ossl_x509stctx_set_flags(VALUE self
, VALUE flags
)
520 X509_STORE_CTX
*store
;
521 long f
= NUM2LONG(flags
);
523 GetX509StCtx(self
, store
);
524 X509_STORE_CTX_set_flags(store
, f
);
530 ossl_x509stctx_set_purpose(VALUE self
, VALUE purpose
)
532 X509_STORE_CTX
*store
;
533 long p
= NUM2LONG(purpose
);
535 GetX509StCtx(self
, store
);
536 X509_STORE_CTX_set_purpose(store
, p
);
542 ossl_x509stctx_set_trust(VALUE self
, VALUE trust
)
544 X509_STORE_CTX
*store
;
545 long t
= NUM2LONG(trust
);
547 GetX509StCtx(self
, store
);
548 X509_STORE_CTX_set_trust(store
, t
);
554 ossl_x509stctx_set_time(VALUE self
, VALUE time
)
556 X509_STORE_CTX
*store
;
559 t
= NUM2LONG(rb_Integer(time
));
560 GetX509StCtx(self
, store
);
561 X509_STORE_CTX_set_time(store
, 0, t
);
570 Init_ossl_x509store()
574 eX509StoreError
= rb_define_class_under(mX509
, "StoreError", eOSSLError
);
576 cX509Store
= rb_define_class_under(mX509
, "Store", rb_cObject
);
577 rb_attr(cX509Store
, rb_intern("verify_callback"), 1, 0, Qfalse
);
578 rb_attr(cX509Store
, rb_intern("error"), 1, 0, Qfalse
);
579 rb_attr(cX509Store
, rb_intern("error_string"), 1, 0, Qfalse
);
580 rb_attr(cX509Store
, rb_intern("chain"), 1, 0, Qfalse
);
581 rb_define_alloc_func(cX509Store
, ossl_x509store_alloc
);
582 rb_define_method(cX509Store
, "initialize", ossl_x509store_initialize
, -1);
583 rb_define_method(cX509Store
, "verify_callback=", ossl_x509store_set_vfy_cb
, 1);
584 rb_define_method(cX509Store
, "flags=", ossl_x509store_set_flags
, 1);
585 rb_define_method(cX509Store
, "purpose=", ossl_x509store_set_purpose
, 1);
586 rb_define_method(cX509Store
, "trust=", ossl_x509store_set_trust
, 1);
587 rb_define_method(cX509Store
, "time=", ossl_x509store_set_time
, 1);
588 rb_define_method(cX509Store
, "add_path", ossl_x509store_add_path
, 1);
589 rb_define_method(cX509Store
, "add_file", ossl_x509store_add_file
, 1);
590 rb_define_method(cX509Store
, "set_default_paths", ossl_x509store_set_default_paths
, 0);
591 rb_define_method(cX509Store
, "add_cert", ossl_x509store_add_cert
, 1);
592 rb_define_method(cX509Store
, "add_crl", ossl_x509store_add_crl
, 1);
593 rb_define_method(cX509Store
, "verify", ossl_x509store_verify
, -1);
595 cX509StoreContext
= rb_define_class_under(mX509
,"StoreContext",rb_cObject
);
596 x509stctx
= cX509StoreContext
;
597 rb_define_alloc_func(cX509StoreContext
, ossl_x509stctx_alloc
);
598 rb_define_method(x509stctx
,"initialize", ossl_x509stctx_initialize
, -1);
599 rb_define_method(x509stctx
,"verify", ossl_x509stctx_verify
, 0);
600 rb_define_method(x509stctx
,"chain", ossl_x509stctx_get_chain
,0);
601 rb_define_method(x509stctx
,"error", ossl_x509stctx_get_err
, 0);
602 rb_define_method(x509stctx
,"error=", ossl_x509stctx_set_error
, 1);
603 rb_define_method(x509stctx
,"error_string",ossl_x509stctx_get_err_string
,0);
604 rb_define_method(x509stctx
,"error_depth", ossl_x509stctx_get_err_depth
, 0);
605 rb_define_method(x509stctx
,"current_cert",ossl_x509stctx_get_curr_cert
, 0);
606 rb_define_method(x509stctx
,"current_crl", ossl_x509stctx_get_curr_crl
, 0);
607 rb_define_method(x509stctx
,"cleanup", ossl_x509stctx_cleanup
, 0);
608 rb_define_method(x509stctx
,"flags=", ossl_x509stctx_set_flags
, 1);
609 rb_define_method(x509stctx
,"purpose=", ossl_x509stctx_set_purpose
, 1);
610 rb_define_method(x509stctx
,"trust=", ossl_x509stctx_set_trust
, 1);
611 rb_define_method(x509stctx
,"time=", ossl_x509stctx_set_time
, 1);