Ruby 1.9.3p327(2012-11-10revision37606)
ext/openssl/ossl_engine.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_engine.c 34505 2012-02-09 03:25:07Z 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_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 /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
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         /* Need a ref count of two here because of ENGINE_free being
00119          * called internally by OpenSSL when moving to the next ENGINE
00120          * and by us when releasing the ENGINE reference */
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     VALUE str;
00351     const char *cname = rb_class2name(rb_obj_class(self));
00352 
00353     str = rb_str_new2("#<");
00354     rb_str_cat2(str, cname);
00355     rb_str_cat2(str, " id=\"");
00356     rb_str_append(str, ossl_engine_get_id(self));
00357     rb_str_cat2(str, "\" name=\"");
00358     rb_str_append(str, ossl_engine_get_name(self));
00359     rb_str_cat2(str, "\">");
00360 
00361     return str;
00362 }
00363 
00364 #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
00365 
00366 void
00367 Init_ossl_engine()
00368 {
00369     cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
00370     eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
00371 
00372     rb_define_alloc_func(cEngine, ossl_engine_s_alloc);
00373     rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1);
00374     rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0);
00375     rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0);
00376     rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1);
00377     rb_undef_method(CLASS_OF(cEngine), "new");
00378 
00379     rb_define_method(cEngine, "id", ossl_engine_get_id, 0);
00380     rb_define_method(cEngine, "name", ossl_engine_get_name, 0);
00381     rb_define_method(cEngine, "finish", ossl_engine_finish, 0);
00382     rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1);
00383     rb_define_method(cEngine, "digest",  ossl_engine_get_digest, 1);
00384     rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1);
00385     rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1);
00386     rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1);
00387     rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1);
00388     rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0);
00389     rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0);
00390 
00391     DefEngineConst(METHOD_RSA);
00392     DefEngineConst(METHOD_DSA);
00393     DefEngineConst(METHOD_DH);
00394     DefEngineConst(METHOD_RAND);
00395 #ifdef ENGINE_METHOD_BN_MOD_EXP
00396     DefEngineConst(METHOD_BN_MOD_EXP);
00397 #endif
00398 #ifdef ENGINE_METHOD_BN_MOD_EXP_CRT
00399     DefEngineConst(METHOD_BN_MOD_EXP_CRT);
00400 #endif
00401 #ifdef ENGINE_METHOD_CIPHERS
00402     DefEngineConst(METHOD_CIPHERS);
00403 #endif
00404 #ifdef ENGINE_METHOD_DIGESTS
00405     DefEngineConst(METHOD_DIGESTS);
00406 #endif
00407     DefEngineConst(METHOD_ALL);
00408     DefEngineConst(METHOD_NONE);
00409 }
00410 #else
00411 void
00412 Init_ossl_engine()
00413 {
00414 }
00415 #endif
00416