00001
00002
00003
00004
00005
00006
00007
00008
00009
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
00034
00035 VALUE cEngine;
00036 VALUE eEngineError;
00037
00038
00039
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_CSWIFT
00068 OSSL_ENGINE_LOAD_IF_MATCH(cswift);
00069 #endif
00070 #if HAVE_ENGINE_LOAD_CHIL
00071 OSSL_ENGINE_LOAD_IF_MATCH(chil);
00072 #endif
00073 #if HAVE_ENGINE_LOAD_ATALLA
00074 OSSL_ENGINE_LOAD_IF_MATCH(atalla);
00075 #endif
00076 #if HAVE_ENGINE_LOAD_NURON
00077 OSSL_ENGINE_LOAD_IF_MATCH(nuron);
00078 #endif
00079 #if HAVE_ENGINE_LOAD_UBSEC
00080 OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
00081 #endif
00082 #if HAVE_ENGINE_LOAD_AEP
00083 OSSL_ENGINE_LOAD_IF_MATCH(aep);
00084 #endif
00085 #if HAVE_ENGINE_LOAD_SUREWARE
00086 OSSL_ENGINE_LOAD_IF_MATCH(sureware);
00087 #endif
00088 #if HAVE_ENGINE_LOAD_4758CCA
00089 OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
00090 #endif
00091 #endif
00092 #ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
00093 OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
00094 #endif
00095 OSSL_ENGINE_LOAD_IF_MATCH(openssl);
00096 rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name));
00097 return Qnil;
00098 #endif
00099 }
00100
00101 static VALUE
00102 ossl_engine_s_cleanup(VALUE self)
00103 {
00104 #if defined(HAVE_ENGINE_CLEANUP)
00105 ENGINE_cleanup();
00106 #endif
00107 return Qnil;
00108 }
00109
00110 static VALUE
00111 ossl_engine_s_engines(VALUE klass)
00112 {
00113 ENGINE *e;
00114 VALUE ary, obj;
00115
00116 ary = rb_ary_new();
00117 for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
00118 WrapEngine(klass, obj, e);
00119 rb_ary_push(ary, obj);
00120 }
00121
00122 return ary;
00123 }
00124
00125 static VALUE
00126 ossl_engine_s_by_id(VALUE klass, VALUE id)
00127 {
00128 ENGINE *e;
00129 VALUE obj;
00130
00131 StringValue(id);
00132 ossl_engine_s_load(1, &id, klass);
00133 if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
00134 ossl_raise(eEngineError, NULL);
00135 WrapEngine(klass, obj, e);
00136 if(rb_block_given_p()) rb_yield(obj);
00137 if(!ENGINE_init(e))
00138 ossl_raise(eEngineError, NULL);
00139 ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
00140 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
00141 ERR_clear_error();
00142
00143 return obj;
00144 }
00145
00146 static VALUE
00147 ossl_engine_s_alloc(VALUE klass)
00148 {
00149 ENGINE *e;
00150 VALUE obj;
00151
00152 if (!(e = ENGINE_new())) {
00153 ossl_raise(eEngineError, NULL);
00154 }
00155 WrapEngine(klass, obj, e);
00156
00157 return obj;
00158 }
00159
00160 static VALUE
00161 ossl_engine_get_id(VALUE self)
00162 {
00163 ENGINE *e;
00164 GetEngine(self, e);
00165 return rb_str_new2(ENGINE_get_id(e));
00166 }
00167
00168 static VALUE
00169 ossl_engine_get_name(VALUE self)
00170 {
00171 ENGINE *e;
00172 GetEngine(self, e);
00173 return rb_str_new2(ENGINE_get_name(e));
00174 }
00175
00176 static VALUE
00177 ossl_engine_finish(VALUE self)
00178 {
00179 ENGINE *e;
00180
00181 GetEngine(self, e);
00182 if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL);
00183
00184 return Qnil;
00185 }
00186
00187 #if defined(HAVE_ENGINE_GET_CIPHER)
00188 static VALUE
00189 ossl_engine_get_cipher(VALUE self, VALUE name)
00190 {
00191 ENGINE *e;
00192 const EVP_CIPHER *ciph, *tmp;
00193 char *s;
00194 int nid;
00195
00196 s = StringValuePtr(name);
00197 tmp = EVP_get_cipherbyname(s);
00198 if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s);
00199 nid = EVP_CIPHER_nid(tmp);
00200 GetEngine(self, e);
00201 ciph = ENGINE_get_cipher(e, nid);
00202 if(!ciph) ossl_raise(eEngineError, NULL);
00203
00204 return ossl_cipher_new(ciph);
00205 }
00206 #else
00207 #define ossl_engine_get_cipher rb_f_notimplement
00208 #endif
00209
00210 #if defined(HAVE_ENGINE_GET_DIGEST)
00211 static VALUE
00212 ossl_engine_get_digest(VALUE self, VALUE name)
00213 {
00214 ENGINE *e;
00215 const EVP_MD *md, *tmp;
00216 char *s;
00217 int nid;
00218
00219 s = StringValuePtr(name);
00220 tmp = EVP_get_digestbyname(s);
00221 if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s);
00222 nid = EVP_MD_nid(tmp);
00223 GetEngine(self, e);
00224 md = ENGINE_get_digest(e, nid);
00225 if(!md) ossl_raise(eEngineError, NULL);
00226
00227 return ossl_digest_new(md);
00228 }
00229 #else
00230 #define ossl_engine_get_digest rb_f_notimplement
00231 #endif
00232
00233 static VALUE
00234 ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
00235 {
00236 ENGINE *e;
00237 EVP_PKEY *pkey;
00238 VALUE id, data, obj;
00239 char *sid, *sdata;
00240
00241 rb_scan_args(argc, argv, "02", &id, &data);
00242 sid = NIL_P(id) ? NULL : StringValuePtr(id);
00243 sdata = NIL_P(data) ? NULL : StringValuePtr(data);
00244 GetEngine(self, e);
00245 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00246 pkey = ENGINE_load_private_key(e, sid, sdata);
00247 #else
00248 pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
00249 #endif
00250 if (!pkey) ossl_raise(eEngineError, NULL);
00251 obj = ossl_pkey_new(pkey);
00252 OSSL_PKEY_SET_PRIVATE(obj);
00253
00254 return obj;
00255 }
00256
00257 static VALUE
00258 ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
00259 {
00260 ENGINE *e;
00261 EVP_PKEY *pkey;
00262 VALUE id, data;
00263 char *sid, *sdata;
00264
00265 rb_scan_args(argc, argv, "02", &id, &data);
00266 sid = NIL_P(id) ? NULL : StringValuePtr(id);
00267 sdata = NIL_P(data) ? NULL : StringValuePtr(data);
00268 GetEngine(self, e);
00269 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00270 pkey = ENGINE_load_public_key(e, sid, sdata);
00271 #else
00272 pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
00273 #endif
00274 if (!pkey) ossl_raise(eEngineError, NULL);
00275
00276 return ossl_pkey_new(pkey);
00277 }
00278
00279 static VALUE
00280 ossl_engine_set_default(VALUE self, VALUE flag)
00281 {
00282 ENGINE *e;
00283 int f = NUM2INT(flag);
00284
00285 GetEngine(self, e);
00286 ENGINE_set_default(e, f);
00287
00288 return Qtrue;
00289 }
00290
00291 static VALUE
00292 ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
00293 {
00294 ENGINE *e;
00295 VALUE cmd, val;
00296 int ret;
00297
00298 GetEngine(self, e);
00299 rb_scan_args(argc, argv, "11", &cmd, &val);
00300 StringValue(cmd);
00301 if (!NIL_P(val)) StringValue(val);
00302 ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd),
00303 NIL_P(val) ? NULL : RSTRING_PTR(val), 0);
00304 if (!ret) ossl_raise(eEngineError, NULL);
00305
00306 return self;
00307 }
00308
00309 static VALUE
00310 ossl_engine_cmd_flag_to_name(int flag)
00311 {
00312 switch(flag){
00313 case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
00314 case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
00315 case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
00316 case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
00317 default: return rb_str_new2("UNKNOWN");
00318 }
00319 }
00320
00321 static VALUE
00322 ossl_engine_get_cmds(VALUE self)
00323 {
00324 ENGINE *e;
00325 const ENGINE_CMD_DEFN *defn, *p;
00326 VALUE ary, tmp;
00327
00328 GetEngine(self, e);
00329 ary = rb_ary_new();
00330 if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
00331 for (p = defn; p->cmd_num > 0; p++){
00332 tmp = rb_ary_new();
00333 rb_ary_push(tmp, rb_str_new2(p->cmd_name));
00334 rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
00335 rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
00336 rb_ary_push(ary, tmp);
00337 }
00338 }
00339
00340 return ary;
00341 }
00342
00343 static VALUE
00344 ossl_engine_inspect(VALUE self)
00345 {
00346 VALUE str;
00347 const char *cname = rb_class2name(rb_obj_class(self));
00348
00349 str = rb_str_new2("#<");
00350 rb_str_cat2(str, cname);
00351 rb_str_cat2(str, " id=\"");
00352 rb_str_append(str, ossl_engine_get_id(self));
00353 rb_str_cat2(str, "\" name=\"");
00354 rb_str_append(str, ossl_engine_get_name(self));
00355 rb_str_cat2(str, "\">");
00356
00357 return str;
00358 }
00359
00360 #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
00361
00362 void
00363 Init_ossl_engine()
00364 {
00365 cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
00366 eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
00367
00368 rb_define_alloc_func(cEngine, ossl_engine_s_alloc);
00369 rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1);
00370 rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0);
00371 rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0);
00372 rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1);
00373 rb_undef_method(CLASS_OF(cEngine), "new");
00374
00375 rb_define_method(cEngine, "id", ossl_engine_get_id, 0);
00376 rb_define_method(cEngine, "name", ossl_engine_get_name, 0);
00377 rb_define_method(cEngine, "finish", ossl_engine_finish, 0);
00378 rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1);
00379 rb_define_method(cEngine, "digest", ossl_engine_get_digest, 1);
00380 rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1);
00381 rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1);
00382 rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1);
00383 rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1);
00384 rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0);
00385 rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0);
00386
00387 DefEngineConst(METHOD_RSA);
00388 DefEngineConst(METHOD_DSA);
00389 DefEngineConst(METHOD_DH);
00390 DefEngineConst(METHOD_RAND);
00391 #ifdef ENGINE_METHOD_BN_MOD_EXP
00392 DefEngineConst(METHOD_BN_MOD_EXP);
00393 #endif
00394 #ifdef ENGINE_METHOD_BN_MOD_EXP_CRT
00395 DefEngineConst(METHOD_BN_MOD_EXP_CRT);
00396 #endif
00397 #ifdef ENGINE_METHOD_CIPHERS
00398 DefEngineConst(METHOD_CIPHERS);
00399 #endif
00400 #ifdef ENGINE_METHOD_DIGESTS
00401 DefEngineConst(METHOD_DIGESTS);
00402 #endif
00403 DefEngineConst(METHOD_ALL);
00404 DefEngineConst(METHOD_NONE);
00405 }
00406 #else
00407 void
00408 Init_ossl_engine()
00409 {
00410 }
00411 #endif
00412