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