ext/openssl/ossl_engine.c

Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_engine.c 43742 2013-11-21 04:37:14Z zzak $
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 /* Document-class: OpenSSL::Engine
00036  *
00037  * This class is the access to openssl's ENGINE cryptographic module
00038  * implementation.
00039  *
00040  * See also, https://www.openssl.org/docs/crypto/engine.html
00041  */
00042 VALUE cEngine;
00043 /* Document-class: OpenSSL::Engine::EngineError
00044  *
00045  * This is the generic exception for OpenSSL::Engine related errors
00046  */
00047 VALUE eEngineError;
00048 
00049 /*
00050  * Private
00051  */
00052 #define OSSL_ENGINE_LOAD_IF_MATCH(x) \
00053 do{\
00054   if(!strcmp(#x, RSTRING_PTR(name))){\
00055     ENGINE_load_##x();\
00056     return Qtrue;\
00057   }\
00058 }while(0)
00059 
00060 /* Document-method: OpenSSL::Engine.load
00061  *
00062  * call-seq:
00063  *   load(enginename = nil)
00064  *
00065  * This method loads engines. If +name+ is nil, then all builtin engines are
00066  * loaded. Otherwise, the given +name+, as a string,  is loaded if available to
00067  * your runtime, and returns true. If +name+ is not found, then nil is
00068  * returned.
00069  *
00070  */
00071 static VALUE
00072 ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
00073 {
00074 #if !defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES)
00075     return Qnil;
00076 #else
00077     VALUE name;
00078 
00079     rb_scan_args(argc, argv, "01", &name);
00080     if(NIL_P(name)){
00081         ENGINE_load_builtin_engines();
00082         return Qtrue;
00083     }
00084     StringValue(name);
00085 #ifndef OPENSSL_NO_STATIC_ENGINE
00086 #if HAVE_ENGINE_LOAD_DYNAMIC
00087     OSSL_ENGINE_LOAD_IF_MATCH(dynamic);
00088 #endif
00089 #if HAVE_ENGINE_LOAD_4758CCA
00090     OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
00091 #endif
00092 #if HAVE_ENGINE_LOAD_AEP
00093     OSSL_ENGINE_LOAD_IF_MATCH(aep);
00094 #endif
00095 #if HAVE_ENGINE_LOAD_ATALLA
00096     OSSL_ENGINE_LOAD_IF_MATCH(atalla);
00097 #endif
00098 #if HAVE_ENGINE_LOAD_CHIL
00099     OSSL_ENGINE_LOAD_IF_MATCH(chil);
00100 #endif
00101 #if HAVE_ENGINE_LOAD_CSWIFT
00102     OSSL_ENGINE_LOAD_IF_MATCH(cswift);
00103 #endif
00104 #if HAVE_ENGINE_LOAD_NURON
00105     OSSL_ENGINE_LOAD_IF_MATCH(nuron);
00106 #endif
00107 #if HAVE_ENGINE_LOAD_SUREWARE
00108     OSSL_ENGINE_LOAD_IF_MATCH(sureware);
00109 #endif
00110 #if HAVE_ENGINE_LOAD_UBSEC
00111     OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
00112 #endif
00113 #if HAVE_ENGINE_LOAD_PADLOCK
00114     OSSL_ENGINE_LOAD_IF_MATCH(padlock);
00115 #endif
00116 #if HAVE_ENGINE_LOAD_CAPI
00117     OSSL_ENGINE_LOAD_IF_MATCH(capi);
00118 #endif
00119 #if HAVE_ENGINE_LOAD_GMP
00120     OSSL_ENGINE_LOAD_IF_MATCH(gmp);
00121 #endif
00122 #if HAVE_ENGINE_LOAD_GOST
00123     OSSL_ENGINE_LOAD_IF_MATCH(gost);
00124 #endif
00125 #if HAVE_ENGINE_LOAD_CRYPTODEV
00126     OSSL_ENGINE_LOAD_IF_MATCH(cryptodev);
00127 #endif
00128 #if HAVE_ENGINE_LOAD_AESNI
00129     OSSL_ENGINE_LOAD_IF_MATCH(aesni);
00130 #endif
00131 #endif
00132 #ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
00133     OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
00134 #endif
00135     OSSL_ENGINE_LOAD_IF_MATCH(openssl);
00136     rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name));
00137     return Qnil;
00138 #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
00139 }
00140 
00141 /* Document-method: OpenSSL::Engine.cleanup
00142  * call-seq:
00143  *  OpenSSL::Engine.cleanup
00144  *
00145  * It is only necessary to run cleanup when engines are loaded via
00146  * OpenSSL::Engine.load. However, running cleanup before exit is recommended.
00147  *
00148  * See also, https://www.openssl.org/docs/crypto/engine.html
00149  */
00150 static VALUE
00151 ossl_engine_s_cleanup(VALUE self)
00152 {
00153 #if defined(HAVE_ENGINE_CLEANUP)
00154     ENGINE_cleanup();
00155 #endif
00156     return Qnil;
00157 }
00158 
00159 /* Document-method: OpenSSL::Engine.engines
00160  *
00161  * Returns an array of currently loaded engines.
00162  */
00163 static VALUE
00164 ossl_engine_s_engines(VALUE klass)
00165 {
00166     ENGINE *e;
00167     VALUE ary, obj;
00168 
00169     ary = rb_ary_new();
00170     for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
00171         /* Need a ref count of two here because of ENGINE_free being
00172          * called internally by OpenSSL when moving to the next ENGINE
00173          * and by us when releasing the ENGINE reference */
00174         ENGINE_up_ref(e);
00175         WrapEngine(klass, obj, e);
00176         rb_ary_push(ary, obj);
00177     }
00178 
00179     return ary;
00180 }
00181 
00182 /* Document-method: OpenSSL::Engine.by_id
00183  *
00184  * call-seq:
00185  *   by_id(name) -> engine
00186  *
00187  * Fetch the engine as specified by the +id+ String
00188  *
00189  *   OpenSSL::Engine.by_id("openssl")
00190  *    => #<OpenSSL::Engine id="openssl" name="Software engine support">
00191  *
00192  * See OpenSSL::Engine.engines for the currently loaded engines
00193  */
00194 static VALUE
00195 ossl_engine_s_by_id(VALUE klass, VALUE id)
00196 {
00197     ENGINE *e;
00198     VALUE obj;
00199 
00200     StringValue(id);
00201     ossl_engine_s_load(1, &id, klass);
00202     if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
00203         ossl_raise(eEngineError, NULL);
00204     WrapEngine(klass, obj, e);
00205     if(rb_block_given_p()) rb_yield(obj);
00206     if(!ENGINE_init(e))
00207         ossl_raise(eEngineError, NULL);
00208     ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
00209                 0, NULL, (void(*)(void))ossl_pem_passwd_cb);
00210     ERR_clear_error();
00211 
00212     return obj;
00213 }
00214 
00215 static VALUE
00216 ossl_engine_s_alloc(VALUE klass)
00217 {
00218     ENGINE *e;
00219     VALUE obj;
00220 
00221     if (!(e = ENGINE_new())) {
00222        ossl_raise(eEngineError, NULL);
00223     }
00224     WrapEngine(klass, obj, e);
00225 
00226     return obj;
00227 }
00228 
00229 /* Document-method: OpenSSL::Engine#id
00230  *
00231  * Get the id for this engine
00232  *
00233  *    OpenSSL::Engine.load
00234  *    OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
00235  *    OpenSSL::Engine.engines.first.id
00236  *      #=> "rsax"
00237  */
00238 static VALUE
00239 ossl_engine_get_id(VALUE self)
00240 {
00241     ENGINE *e;
00242     GetEngine(self, e);
00243     return rb_str_new2(ENGINE_get_id(e));
00244 }
00245 
00246 /* Document-method: OpenSSL::Engine#name
00247  *
00248  * Get the descriptive name for this engine
00249  *
00250  *    OpenSSL::Engine.load
00251  *    OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
00252  *    OpenSSL::Engine.engines.first.name
00253  *      #=> "RSAX engine support"
00254  *
00255  */
00256 static VALUE
00257 ossl_engine_get_name(VALUE self)
00258 {
00259     ENGINE *e;
00260     GetEngine(self, e);
00261     return rb_str_new2(ENGINE_get_name(e));
00262 }
00263 
00264 /* Document-method: OpenSSL::Engine#finish
00265  *
00266  * Releases all internal structural references for this engine.
00267  *
00268  * May raise an EngineError if the engine is unavailable
00269  */
00270 static VALUE
00271 ossl_engine_finish(VALUE self)
00272 {
00273     ENGINE *e;
00274 
00275     GetEngine(self, e);
00276     if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL);
00277 
00278     return Qnil;
00279 }
00280 
00281 #if defined(HAVE_ENGINE_GET_CIPHER)
00282 /* Document-method: OpenSSL::Engine#cipher
00283  *
00284  * call-seq:
00285  *   engine.cipher(name) -> OpenSSL::Cipher
00286  *
00287  * This returns an OpenSSL::Cipher by +name+, if it is available in this
00288  * engine.
00289  *
00290  * A EngineError will be raised if the cipher is unavailable.
00291  *
00292  *    e = OpenSSL::Engine.by_id("openssl")
00293  *     => #<OpenSSL::Engine id="openssl" name="Software engine support">
00294  *    e.cipher("RC4")
00295  *     => #<OpenSSL::Cipher:0x007fc5cacc3048>
00296  *
00297  */
00298 static VALUE
00299 ossl_engine_get_cipher(VALUE self, VALUE name)
00300 {
00301     ENGINE *e;
00302     const EVP_CIPHER *ciph, *tmp;
00303     char *s;
00304     int nid;
00305 
00306     s = StringValuePtr(name);
00307     tmp = EVP_get_cipherbyname(s);
00308     if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s);
00309     nid = EVP_CIPHER_nid(tmp);
00310     GetEngine(self, e);
00311     ciph = ENGINE_get_cipher(e, nid);
00312     if(!ciph) ossl_raise(eEngineError, NULL);
00313 
00314     return ossl_cipher_new(ciph);
00315 }
00316 #else
00317 #define ossl_engine_get_cipher rb_f_notimplement
00318 #endif
00319 
00320 #if defined(HAVE_ENGINE_GET_DIGEST)
00321 /* Document-method: OpenSSL::Engine#digest
00322  *
00323  * call-seq:
00324  *   engine.digest(name) -> OpenSSL::Digest
00325  *
00326  * This returns an OpenSSL::Digest by +name+.
00327  *
00328  * Will raise an EngineError if the digest is unavailable.
00329  *
00330  *    e = OpenSSL::Engine.by_id("openssl")
00331  *      #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
00332  *    e.digest("SHA1")
00333  *      #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
00334  *    e.digest("zomg")
00335  *      #=> OpenSSL::Engine::EngineError: no such digest `zomg'
00336  */
00337 static VALUE
00338 ossl_engine_get_digest(VALUE self, VALUE name)
00339 {
00340     ENGINE *e;
00341     const EVP_MD *md, *tmp;
00342     char *s;
00343     int nid;
00344 
00345     s = StringValuePtr(name);
00346     tmp = EVP_get_digestbyname(s);
00347     if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s);
00348     nid = EVP_MD_nid(tmp);
00349     GetEngine(self, e);
00350     md = ENGINE_get_digest(e, nid);
00351     if(!md) ossl_raise(eEngineError, NULL);
00352 
00353     return ossl_digest_new(md);
00354 }
00355 #else
00356 #define ossl_engine_get_digest rb_f_notimplement
00357 #endif
00358 
00359 /* Document-method: OpenSSL::Engine#load_private_key
00360  *
00361  * call-seq:
00362  *    engine.load_private_key(id = nil, data = nil) -> OpenSSL::PKey
00363  *
00364  * Loads the given private key by +id+ and +data+.
00365  *
00366  * An EngineError is raised of the OpenSSL::PKey is unavailable.
00367  *
00368  */
00369 static VALUE
00370 ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
00371 {
00372     ENGINE *e;
00373     EVP_PKEY *pkey;
00374     VALUE id, data, obj;
00375     char *sid, *sdata;
00376 
00377     rb_scan_args(argc, argv, "02", &id, &data);
00378     sid = NIL_P(id) ? NULL : StringValuePtr(id);
00379     sdata = NIL_P(data) ? NULL : StringValuePtr(data);
00380     GetEngine(self, e);
00381 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00382     pkey = ENGINE_load_private_key(e, sid, sdata);
00383 #else
00384     pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
00385 #endif
00386     if (!pkey) ossl_raise(eEngineError, NULL);
00387     obj = ossl_pkey_new(pkey);
00388     OSSL_PKEY_SET_PRIVATE(obj);
00389 
00390     return obj;
00391 }
00392 
00393 /* Document-method: OpenSSL::Engine#load_public_key
00394  *
00395  * call-seq:
00396  *    engine.load_public_key(id = nil, data = nil) -> OpenSSL::PKey
00397  *
00398  * Loads the given private key by +id+ and +data+.
00399  *
00400  * An EngineError is raised of the OpenSSL::PKey is unavailable.
00401  *
00402  */
00403 static VALUE
00404 ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
00405 {
00406     ENGINE *e;
00407     EVP_PKEY *pkey;
00408     VALUE id, data;
00409     char *sid, *sdata;
00410 
00411     rb_scan_args(argc, argv, "02", &id, &data);
00412     sid = NIL_P(id) ? NULL : StringValuePtr(id);
00413     sdata = NIL_P(data) ? NULL : StringValuePtr(data);
00414     GetEngine(self, e);
00415 #if OPENSSL_VERSION_NUMBER < 0x00907000L
00416     pkey = ENGINE_load_public_key(e, sid, sdata);
00417 #else
00418     pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
00419 #endif
00420     if (!pkey) ossl_raise(eEngineError, NULL);
00421 
00422     return ossl_pkey_new(pkey);
00423 }
00424 
00425 /* Document-method: OpenSSL::Engine#set_default
00426  *
00427  * call-seq:
00428  *    engine.set_default(flag)
00429  *
00430  * Set the defaults for this engine with the given +flag+.
00431  *
00432  * These flags are used to control combinations of algorithm methods.
00433  *
00434  * +flag+ can be one of the following, other flags are available depending on
00435  * your OS.
00436  *
00437  * [All flags]  0xFFFF
00438  * [No flags]   0x0000
00439  *
00440  * See also <openssl/engine.h>
00441  */
00442 static VALUE
00443 ossl_engine_set_default(VALUE self, VALUE flag)
00444 {
00445     ENGINE *e;
00446     int f = NUM2INT(flag);
00447 
00448     GetEngine(self, e);
00449     ENGINE_set_default(e, f);
00450 
00451     return Qtrue;
00452 }
00453 
00454 /* Document-method: OpenSSL::Engine#ctrl_cmd
00455  *
00456  * call-seq:
00457  *    engine.ctrl_cmd(command, value = nil) -> engine
00458  *
00459  * Send the given +command+ to this engine.
00460  *
00461  * Raises an EngineError if the +command+ fails.
00462  */
00463 static VALUE
00464 ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
00465 {
00466     ENGINE *e;
00467     VALUE cmd, val;
00468     int ret;
00469 
00470     GetEngine(self, e);
00471     rb_scan_args(argc, argv, "11", &cmd, &val);
00472     StringValue(cmd);
00473     if (!NIL_P(val)) StringValue(val);
00474     ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd),
00475                                  NIL_P(val) ? NULL : RSTRING_PTR(val), 0);
00476     if (!ret) ossl_raise(eEngineError, NULL);
00477 
00478     return self;
00479 }
00480 
00481 static VALUE
00482 ossl_engine_cmd_flag_to_name(int flag)
00483 {
00484     switch(flag){
00485     case ENGINE_CMD_FLAG_NUMERIC:  return rb_str_new2("NUMERIC");
00486     case ENGINE_CMD_FLAG_STRING:   return rb_str_new2("STRING");
00487     case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
00488     case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
00489     default: return rb_str_new2("UNKNOWN");
00490     }
00491 }
00492 
00493 /* Document-method: OpenSSL::Engine#cmds
00494  *
00495  * Returns an array of command definitions for the current engine
00496  */
00497 static VALUE
00498 ossl_engine_get_cmds(VALUE self)
00499 {
00500     ENGINE *e;
00501     const ENGINE_CMD_DEFN *defn, *p;
00502     VALUE ary, tmp;
00503 
00504     GetEngine(self, e);
00505     ary = rb_ary_new();
00506     if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
00507         for (p = defn; p->cmd_num > 0; p++){
00508             tmp = rb_ary_new();
00509             rb_ary_push(tmp, rb_str_new2(p->cmd_name));
00510             rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
00511             rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
00512             rb_ary_push(ary, tmp);
00513         }
00514     }
00515 
00516     return ary;
00517 }
00518 
00519 /* Document-method: OpenSSL::Engine#inspect
00520  *
00521  * Pretty print this engine
00522  */
00523 static VALUE
00524 ossl_engine_inspect(VALUE self)
00525 {
00526     VALUE str;
00527     const char *cname = rb_class2name(rb_obj_class(self));
00528 
00529     str = rb_str_new2("#<");
00530     rb_str_cat2(str, cname);
00531     rb_str_cat2(str, " id=\"");
00532     rb_str_append(str, ossl_engine_get_id(self));
00533     rb_str_cat2(str, "\" name=\"");
00534     rb_str_append(str, ossl_engine_get_name(self));
00535     rb_str_cat2(str, "\">");
00536 
00537     return str;
00538 }
00539 
00540 #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
00541 
00542 void
00543 Init_ossl_engine()
00544 {
00545     cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
00546     eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
00547 
00548     rb_define_alloc_func(cEngine, ossl_engine_s_alloc);
00549     rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1);
00550     rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0);
00551     rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0);
00552     rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1);
00553     rb_undef_method(CLASS_OF(cEngine), "new");
00554 
00555     rb_define_method(cEngine, "id", ossl_engine_get_id, 0);
00556     rb_define_method(cEngine, "name", ossl_engine_get_name, 0);
00557     rb_define_method(cEngine, "finish", ossl_engine_finish, 0);
00558     rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1);
00559     rb_define_method(cEngine, "digest",  ossl_engine_get_digest, 1);
00560     rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1);
00561     rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1);
00562     rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1);
00563     rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1);
00564     rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0);
00565     rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0);
00566 
00567     DefEngineConst(METHOD_RSA);
00568     DefEngineConst(METHOD_DSA);
00569     DefEngineConst(METHOD_DH);
00570     DefEngineConst(METHOD_RAND);
00571 #ifdef ENGINE_METHOD_BN_MOD_EXP
00572     DefEngineConst(METHOD_BN_MOD_EXP);
00573 #endif
00574 #ifdef ENGINE_METHOD_BN_MOD_EXP_CRT
00575     DefEngineConst(METHOD_BN_MOD_EXP_CRT);
00576 #endif
00577 #ifdef ENGINE_METHOD_CIPHERS
00578     DefEngineConst(METHOD_CIPHERS);
00579 #endif
00580 #ifdef ENGINE_METHOD_DIGESTS
00581     DefEngineConst(METHOD_DIGESTS);
00582 #endif
00583     DefEngineConst(METHOD_ALL);
00584     DefEngineConst(METHOD_NONE);
00585 }
00586 #else
00587 void
00588 Init_ossl_engine()
00589 {
00590 }
00591 #endif
00592 

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7