Ruby  2.0.0p247(2013-06-27revision41674)
ext/openssl/ossl_engine.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_engine.c 33634 2011-11-04 07:19:23Z nobu $
00003  * 'OpenSSL for Ruby' project
00004  * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>
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 #if defined(OSSL_ENGINE_ENABLED)
00014 
00015 #define WrapEngine(klass, obj, engine) do { \
00016     if (!(engine)) { \
00017         ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
00018     } \
00019     (obj) = Data_Wrap_Struct((klass), 0, ENGINE_free, (engine)); \
00020 } while(0)
00021 #define GetEngine(obj, engine) do { \
00022     Data_Get_Struct((obj), ENGINE, (engine)); \
00023     if (!(engine)) { \
00024         ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
00025     } \
00026 } while (0)
00027 #define SafeGetEngine(obj, engine) do { \
00028     OSSL_Check_Kind((obj), cEngine); \
00029     GetPKCS7((obj), (engine)); \
00030 } while (0)
00031 
00032 /*
00033  * Classes
00034  */
00035 VALUE cEngine;
00036 VALUE eEngineError;
00037 
00038 /*
00039  * Private
00040  */
00041 #define OSSL_ENGINE_LOAD_IF_MATCH(x) \
00042 do{\
00043   if(!strcmp(#x, RSTRING_PTR(name))){\
00044     ENGINE_load_##x();\
00045     return Qtrue;\
00046   }\
00047 }while(0)
00048 
00049 static VALUE
00050 ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
00051 {
00052 #if !defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES)
00053     return Qnil;
00054 #else
00055     VALUE name;
00056 
00057     rb_scan_args(argc, argv, "01", &name);
00058     if(NIL_P(name)){
00059         ENGINE_load_builtin_engines();
00060         return Qtrue;
00061     }
00062     StringValue(name);
00063 #ifndef OPENSSL_NO_STATIC_ENGINE
00064 #if HAVE_ENGINE_LOAD_DYNAMIC
00065     OSSL_ENGINE_LOAD_IF_MATCH(dynamic);
00066 #endif
00067 #if HAVE_ENGINE_LOAD_4758CCA
00068     OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
00069 #endif
00070 #if HAVE_ENGINE_LOAD_AEP
00071     OSSL_ENGINE_LOAD_IF_MATCH(aep);
00072 #endif
00073 #if HAVE_ENGINE_LOAD_ATALLA
00074     OSSL_ENGINE_LOAD_IF_MATCH(atalla);
00075 #endif
00076 #if HAVE_ENGINE_LOAD_CHIL
00077     OSSL_ENGINE_LOAD_IF_MATCH(chil);
00078 #endif
00079 #if HAVE_ENGINE_LOAD_CSWIFT
00080     OSSL_ENGINE_LOAD_IF_MATCH(cswift);
00081 #endif
00082 #if HAVE_ENGINE_LOAD_NURON
00083     OSSL_ENGINE_LOAD_IF_MATCH(nuron);
00084 #endif
00085 #if HAVE_ENGINE_LOAD_SUREWARE
00086     OSSL_ENGINE_LOAD_IF_MATCH(sureware);
00087 #endif
00088 #if HAVE_ENGINE_LOAD_UBSEC
00089     OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
00090 #endif
00091 #if HAVE_ENGINE_LOAD_PADLOCK
00092     OSSL_ENGINE_LOAD_IF_MATCH(padlock);
00093 #endif
00094 #if HAVE_ENGINE_LOAD_CAPI
00095     OSSL_ENGINE_LOAD_IF_MATCH(capi);
00096 #endif
00097 #if HAVE_ENGINE_LOAD_GMP
00098     OSSL_ENGINE_LOAD_IF_MATCH(gmp);
00099 #endif
00100 #if HAVE_ENGINE_LOAD_GOST
00101     OSSL_ENGINE_LOAD_IF_MATCH(gost);
00102 #endif
00103 #if HAVE_ENGINE_LOAD_CRYPTODEV
00104     OSSL_ENGINE_LOAD_IF_MATCH(cryptodev);
00105 #endif
00106 #if HAVE_ENGINE_LOAD_AESNI
00107     OSSL_ENGINE_LOAD_IF_MATCH(aesni);
00108 #endif
00109 #endif
00110 #ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
00111     OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
00112 #endif
00113     OSSL_ENGINE_LOAD_IF_MATCH(openssl);
00114     rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name));
00115     return Qnil;
00116 #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
00117 }
00118 
00119 static VALUE
00120 ossl_engine_s_cleanup(VALUE self)
00121 {
00122 #if defined(HAVE_ENGINE_CLEANUP)
00123     ENGINE_cleanup();
00124 #endif
00125     return Qnil;
00126 }
00127 
00128 static VALUE
00129 ossl_engine_s_engines(VALUE klass)
00130 {
00131     ENGINE *e;
00132     VALUE ary, obj;
00133 
00134     ary = rb_ary_new();
00135     for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
00136         /* Need a ref count of two here because of ENGINE_free being
00137          * called internally by OpenSSL when moving to the next ENGINE
00138          * and by us when releasing the ENGINE reference */
00139         ENGINE_up_ref(e);
00140         WrapEngine(klass, obj, e);
00141         rb_ary_push(ary, obj);
00142     }
00143 
00144     return ary;
00145 }
00146 
00147 static VALUE
00148 ossl_engine_s_by_id(VALUE klass, VALUE id)
00149 {
00150     ENGINE *e;
00151     VALUE obj;
00152 
00153     StringValue(id);
00154     ossl_engine_s_load(1, &id, klass);
00155     if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
00156         ossl_raise(eEngineError, NULL);
00157     WrapEngine(klass, obj, e);
00158     if(rb_block_given_p()) rb_yield(obj);
00159     if(!ENGINE_init(e))
00160         ossl_raise(eEngineError, NULL);
00161     ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
00162                 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
00163     ERR_clear_error();
00164 
00165     return obj;
00166 }
00167 
00168 static VALUE
00169 ossl_engine_s_alloc(VALUE klass)
00170 {
00171     ENGINE *e;
00172     VALUE obj;
00173 
00174     if (!(e = ENGINE_new())) {
00175        ossl_raise(eEngineError, NULL);
00176     }
00177     WrapEngine(klass, obj, e);
00178 
00179     return obj;
00180 }
00181 
00182 static VALUE
00183 ossl_engine_get_id(VALUE self)
00184 {
00185     ENGINE *e;
00186     GetEngine(self, e);
00187     return rb_str_new2(ENGINE_get_id(e));
00188 }
00189 
00190 static VALUE
00191 ossl_engine_get_name(VALUE self)
00192 {
00193     ENGINE *e;
00194     GetEngine(self, e);
00195     return rb_str_new2(ENGINE_get_name(e));
00196 }
00197 
00198 static VALUE
00199 ossl_engine_finish(VALUE self)
00200 {
00201     ENGINE *e;
00202 
00203     GetEngine(self, e);
00204     if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL);
00205 
00206     return Qnil;
00207 }
00208 
00209 #if defined(HAVE_ENGINE_GET_CIPHER)
00210 static VALUE
00211 ossl_engine_get_cipher(VALUE self, VALUE name)
00212 {
00213     ENGINE *e;
00214     const EVP_CIPHER *ciph, *tmp;
00215     char *s;
00216     int nid;
00217 
00218     s = StringValuePtr(name);
00219     tmp = EVP_get_cipherbyname(s);
00220     if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s);
00221     nid = EVP_CIPHER_nid(tmp);
00222     GetEngine(self, e);
00223     ciph = ENGINE_get_cipher(e, nid);
00224     if(!ciph) ossl_raise(eEngineError, NULL);
00225 
00226     return ossl_cipher_new(ciph);
00227 }
00228 #else
00229 #define ossl_engine_get_cipher rb_f_notimplement
00230 #endif
00231 
00232 #if defined(HAVE_ENGINE_GET_DIGEST)
00233 static VALUE
00234 ossl_engine_get_digest(VALUE self, VALUE name)
00235 {
00236     ENGINE *e;
00237     const EVP_MD *md, *tmp;
00238     char *s;
00239     int nid;
00240 
00241     s = StringValuePtr(name);
00242     tmp = EVP_get_digestbyname(s);
00243     if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s);
00244     nid = EVP_MD_nid(tmp);
00245     GetEngine(self, e);
00246     md = ENGINE_get_digest(e, nid);
00247     if(!md) ossl_raise(eEngineError, NULL);
00248 
00249     return ossl_digest_new(md);
00250 }
00251 #else
00252 #define ossl_engine_get_digest rb_f_notimplement
00253 #endif
00254 
00255 static VALUE
00256 ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
00257 {
00258     ENGINE *e;
00259     EVP_PKEY *pkey;
00260     VALUE id, data, obj;
00261     char *sid, *sdata;
00262 
00263     rb_scan_args(argc, argv, "02", &id, &data);
00264     sid = NIL_P(id) ? NULL : StringValuePtr(id);
00265     sdata = NIL_P(data) ? NULL : StringValuePtr(data);
00266     GetEngine(self, e);
00267 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00268     pkey = ENGINE_load_private_key(e, sid, sdata);
00269 #else
00270     pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
00271 #endif
00272     if (!pkey) ossl_raise(eEngineError, NULL);
00273     obj = ossl_pkey_new(pkey);
00274     OSSL_PKEY_SET_PRIVATE(obj);
00275 
00276     return obj;
00277 }
00278 
00279 static VALUE
00280 ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
00281 {
00282     ENGINE *e;
00283     EVP_PKEY *pkey;
00284     VALUE id, data;
00285     char *sid, *sdata;
00286 
00287     rb_scan_args(argc, argv, "02", &id, &data);
00288     sid = NIL_P(id) ? NULL : StringValuePtr(id);
00289     sdata = NIL_P(data) ? NULL : StringValuePtr(data);
00290     GetEngine(self, e);
00291 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00292     pkey = ENGINE_load_public_key(e, sid, sdata);
00293 #else
00294     pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
00295 #endif
00296     if (!pkey) ossl_raise(eEngineError, NULL);
00297 
00298     return ossl_pkey_new(pkey);
00299 }
00300 
00301 static VALUE
00302 ossl_engine_set_default(VALUE self, VALUE flag)
00303 {
00304     ENGINE *e;
00305     int f = NUM2INT(flag);
00306 
00307     GetEngine(self, e);
00308     ENGINE_set_default(e, f);
00309 
00310     return Qtrue;
00311 }
00312 
00313 static VALUE
00314 ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
00315 {
00316     ENGINE *e;
00317     VALUE cmd, val;
00318     int ret;
00319 
00320     GetEngine(self, e);
00321     rb_scan_args(argc, argv, "11", &cmd, &val);
00322     StringValue(cmd);
00323     if (!NIL_P(val)) StringValue(val);
00324     ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd),
00325                                  NIL_P(val) ? NULL : RSTRING_PTR(val), 0);
00326     if (!ret) ossl_raise(eEngineError, NULL);
00327 
00328     return self;
00329 }
00330 
00331 static VALUE
00332 ossl_engine_cmd_flag_to_name(int flag)
00333 {
00334     switch(flag){
00335     case ENGINE_CMD_FLAG_NUMERIC:  return rb_str_new2("NUMERIC");
00336     case ENGINE_CMD_FLAG_STRING:   return rb_str_new2("STRING");
00337     case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
00338     case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
00339     default: return rb_str_new2("UNKNOWN");
00340     }
00341 }
00342 
00343 static VALUE
00344 ossl_engine_get_cmds(VALUE self)
00345 {
00346     ENGINE *e;
00347     const ENGINE_CMD_DEFN *defn, *p;
00348     VALUE ary, tmp;
00349 
00350     GetEngine(self, e);
00351     ary = rb_ary_new();
00352     if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
00353         for (p = defn; p->cmd_num > 0; p++){
00354             tmp = rb_ary_new();
00355             rb_ary_push(tmp, rb_str_new2(p->cmd_name));
00356             rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
00357             rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
00358             rb_ary_push(ary, tmp);
00359         }
00360     }
00361 
00362     return ary;
00363 }
00364 
00365 static VALUE
00366 ossl_engine_inspect(VALUE self)
00367 {
00368     VALUE str;
00369     const char *cname = rb_class2name(rb_obj_class(self));
00370 
00371     str = rb_str_new2("#<");
00372     rb_str_cat2(str, cname);
00373     rb_str_cat2(str, " id=\"");
00374     rb_str_append(str, ossl_engine_get_id(self));
00375     rb_str_cat2(str, "\" name=\"");
00376     rb_str_append(str, ossl_engine_get_name(self));
00377     rb_str_cat2(str, "\">");
00378 
00379     return str;
00380 }
00381 
00382 #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
00383 
00384 void
00385 Init_ossl_engine()
00386 {
00387     cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
00388     eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
00389 
00390     rb_define_alloc_func(cEngine, ossl_engine_s_alloc);
00391     rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1);
00392     rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0);
00393     rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0);
00394     rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1);
00395     rb_undef_method(CLASS_OF(cEngine), "new");
00396 
00397     rb_define_method(cEngine, "id", ossl_engine_get_id, 0);
00398     rb_define_method(cEngine, "name", ossl_engine_get_name, 0);
00399     rb_define_method(cEngine, "finish", ossl_engine_finish, 0);
00400     rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1);
00401     rb_define_method(cEngine, "digest",  ossl_engine_get_digest, 1);
00402     rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1);
00403     rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1);
00404     rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1);
00405     rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1);
00406     rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0);
00407     rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0);
00408 
00409     DefEngineConst(METHOD_RSA);
00410     DefEngineConst(METHOD_DSA);
00411     DefEngineConst(METHOD_DH);
00412     DefEngineConst(METHOD_RAND);
00413 #ifdef ENGINE_METHOD_BN_MOD_EXP
00414     DefEngineConst(METHOD_BN_MOD_EXP);
00415 #endif
00416 #ifdef ENGINE_METHOD_BN_MOD_EXP_CRT
00417     DefEngineConst(METHOD_BN_MOD_EXP_CRT);
00418 #endif
00419 #ifdef ENGINE_METHOD_CIPHERS
00420     DefEngineConst(METHOD_CIPHERS);
00421 #endif
00422 #ifdef ENGINE_METHOD_DIGESTS
00423     DefEngineConst(METHOD_DIGESTS);
00424 #endif
00425     DefEngineConst(METHOD_ALL);
00426     DefEngineConst(METHOD_NONE);
00427 }
00428 #else
00429 void
00430 Init_ossl_engine()
00431 {
00432 }
00433 #endif
00434