Ruby  2.5.0dev(2017-10-22revision60238)
ossl_engine.c
Go to the documentation of this file.
1 /*
2  * 'OpenSSL for Ruby' project
3  * Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
4  * All rights reserved.
5  */
6 /*
7  * This program is licensed under the same licence as Ruby.
8  * (See the file 'LICENCE'.)
9  */
10 #include "ossl.h"
11 
12 #if !defined(OPENSSL_NO_ENGINE)
13 
14 #define NewEngine(klass) \
15  TypedData_Wrap_Struct((klass), &ossl_engine_type, 0)
16 #define SetEngine(obj, engine) do { \
17  if (!(engine)) { \
18  ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
19  } \
20  RTYPEDDATA_DATA(obj) = (engine); \
21 } while(0)
22 #define GetEngine(obj, engine) do { \
23  TypedData_Get_Struct((obj), ENGINE, &ossl_engine_type, (engine)); \
24  if (!(engine)) { \
25  ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
26  } \
27 } while (0)
28 
29 /*
30  * Classes
31  */
32 /* Document-class: OpenSSL::Engine
33  *
34  * This class is the access to openssl's ENGINE cryptographic module
35  * implementation.
36  *
37  * See also, https://www.openssl.org/docs/crypto/engine.html
38  */
40 /* Document-class: OpenSSL::Engine::EngineError
41  *
42  * This is the generic exception for OpenSSL::Engine related errors
43  */
45 
46 /*
47  * Private
48  */
49 #define OSSL_ENGINE_LOAD_IF_MATCH(x) \
50 do{\
51  if(!strcmp(#x, RSTRING_PTR(name))){\
52  ENGINE_load_##x();\
53  return Qtrue;\
54  }\
55 }while(0)
56 
57 static void
58 ossl_engine_free(void *engine)
59 {
60  ENGINE_free(engine);
61 }
62 
63 static const rb_data_type_t ossl_engine_type = {
64  "OpenSSL/Engine",
65  {
66  0, ossl_engine_free,
67  },
69 };
70 
71 /*
72  * call-seq:
73  * OpenSSL::Engine.load(name = nil)
74  *
75  * This method loads engines. If _name_ is nil, then all builtin engines are
76  * loaded. Otherwise, the given _name_, as a String, is loaded if available to
77  * your runtime, and returns true. If _name_ is not found, then nil is
78  * returned.
79  *
80  */
81 static VALUE
82 ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
83 {
84 #if !defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES)
85  return Qnil;
86 #else
87  VALUE name;
88 
89  rb_scan_args(argc, argv, "01", &name);
90  if(NIL_P(name)){
91  ENGINE_load_builtin_engines();
92  return Qtrue;
93  }
94  StringValueCStr(name);
95 #ifndef OPENSSL_NO_STATIC_ENGINE
96 #if HAVE_ENGINE_LOAD_DYNAMIC
98 #endif
99 #if HAVE_ENGINE_LOAD_4758CCA
100  OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
101 #endif
102 #if HAVE_ENGINE_LOAD_AEP
104 #endif
105 #if HAVE_ENGINE_LOAD_ATALLA
107 #endif
108 #if HAVE_ENGINE_LOAD_CHIL
110 #endif
111 #if HAVE_ENGINE_LOAD_CSWIFT
113 #endif
114 #if HAVE_ENGINE_LOAD_NURON
116 #endif
117 #if HAVE_ENGINE_LOAD_SUREWARE
118  OSSL_ENGINE_LOAD_IF_MATCH(sureware);
119 #endif
120 #if HAVE_ENGINE_LOAD_UBSEC
122 #endif
123 #if HAVE_ENGINE_LOAD_PADLOCK
124  OSSL_ENGINE_LOAD_IF_MATCH(padlock);
125 #endif
126 #if HAVE_ENGINE_LOAD_CAPI
128 #endif
129 #if HAVE_ENGINE_LOAD_GMP
131 #endif
132 #if HAVE_ENGINE_LOAD_GOST
134 #endif
135 #if HAVE_ENGINE_LOAD_CRYPTODEV
136  OSSL_ENGINE_LOAD_IF_MATCH(cryptodev);
137 #endif
138 #if HAVE_ENGINE_LOAD_AESNI
140 #endif
141 #endif
142 #ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
143  OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
144 #endif
145  OSSL_ENGINE_LOAD_IF_MATCH(openssl);
146  rb_warning("no such builtin loader for `%"PRIsVALUE"'", name);
147  return Qnil;
148 #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
149 }
150 
151 /*
152  * call-seq:
153  * OpenSSL::Engine.cleanup
154  *
155  * It is only necessary to run cleanup when engines are loaded via
156  * OpenSSL::Engine.load. However, running cleanup before exit is recommended.
157  *
158  * Note that this is needed and works only in OpenSSL < 1.1.0.
159  */
160 static VALUE
161 ossl_engine_s_cleanup(VALUE self)
162 {
163  ENGINE_cleanup();
164  return Qnil;
165 }
166 
167 /*
168  * call-seq:
169  * OpenSSL::Engine.engines -> [engine, ...]
170  *
171  * Returns an array of currently loaded engines.
172  */
173 static VALUE
174 ossl_engine_s_engines(VALUE klass)
175 {
176  ENGINE *e;
177  VALUE ary, obj;
178 
179  ary = rb_ary_new();
180  for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
181  obj = NewEngine(klass);
182  /* Need a ref count of two here because of ENGINE_free being
183  * called internally by OpenSSL when moving to the next ENGINE
184  * and by us when releasing the ENGINE reference */
185  ENGINE_up_ref(e);
186  SetEngine(obj, e);
187  rb_ary_push(ary, obj);
188  }
189 
190  return ary;
191 }
192 
193 /*
194  * call-seq:
195  * OpenSSL::Engine.by_id(name) -> engine
196  *
197  * Fetches the engine as specified by the _id_ String.
198  *
199  * OpenSSL::Engine.by_id("openssl")
200  * => #<OpenSSL::Engine id="openssl" name="Software engine support">
201  *
202  * See OpenSSL::Engine.engines for the currently loaded engines.
203  */
204 static VALUE
205 ossl_engine_s_by_id(VALUE klass, VALUE id)
206 {
207  ENGINE *e;
208  VALUE obj;
209 
210  StringValueCStr(id);
211  ossl_engine_s_load(1, &id, klass);
212  obj = NewEngine(klass);
213  if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
215  SetEngine(obj, e);
216  if(rb_block_given_p()) rb_yield(obj);
217  if(!ENGINE_init(e))
219  ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
220  0, NULL, (void(*)(void))ossl_pem_passwd_cb);
222 
223  return obj;
224 }
225 
226 /*
227  * call-seq:
228  * engine.id -> string
229  *
230  * Gets the id for this engine.
231  *
232  * OpenSSL::Engine.load
233  * OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
234  * OpenSSL::Engine.engines.first.id
235  * #=> "rsax"
236  */
237 static VALUE
238 ossl_engine_get_id(VALUE self)
239 {
240  ENGINE *e;
241  GetEngine(self, e);
242  return rb_str_new2(ENGINE_get_id(e));
243 }
244 
245 /*
246  * call-seq:
247  * engine.name -> string
248  *
249  * Get the descriptive name for this engine.
250  *
251  * OpenSSL::Engine.load
252  * OpenSSL::Engine.engines #=> [#<OpenSSL::Engine#>, ...]
253  * OpenSSL::Engine.engines.first.name
254  * #=> "RSAX engine support"
255  *
256  */
257 static VALUE
258 ossl_engine_get_name(VALUE self)
259 {
260  ENGINE *e;
261  GetEngine(self, e);
262  return rb_str_new2(ENGINE_get_name(e));
263 }
264 
265 /*
266  * call-seq:
267  * engine.finish -> nil
268  *
269  * Releases all internal structural references for this engine.
270  *
271  * May raise an EngineError if the engine is unavailable
272  */
273 static VALUE
274 ossl_engine_finish(VALUE self)
275 {
276  ENGINE *e;
277 
278  GetEngine(self, e);
279  if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL);
280 
281  return Qnil;
282 }
283 
284 /*
285  * call-seq:
286  * engine.cipher(name) -> OpenSSL::Cipher
287  *
288  * Returns a new instance of OpenSSL::Cipher by _name_, if it is available in
289  * this engine.
290  *
291  * An EngineError will be raised if the cipher is unavailable.
292  *
293  * e = OpenSSL::Engine.by_id("openssl")
294  * => #<OpenSSL::Engine id="openssl" name="Software engine support">
295  * e.cipher("RC4")
296  * => #<OpenSSL::Cipher:0x007fc5cacc3048>
297  *
298  */
299 static VALUE
300 ossl_engine_get_cipher(VALUE self, VALUE name)
301 {
302  ENGINE *e;
303  const EVP_CIPHER *ciph, *tmp;
304  int nid;
305 
306  tmp = EVP_get_cipherbyname(StringValueCStr(name));
307  if(!tmp) ossl_raise(eEngineError, "no such cipher `%"PRIsVALUE"'", name);
308  nid = EVP_CIPHER_nid(tmp);
309  GetEngine(self, e);
310  ciph = ENGINE_get_cipher(e, nid);
311  if(!ciph) ossl_raise(eEngineError, NULL);
312 
313  return ossl_cipher_new(ciph);
314 }
315 
316 /*
317  * call-seq:
318  * engine.digest(name) -> OpenSSL::Digest
319  *
320  * Returns a new instance of OpenSSL::Digest by _name_.
321  *
322  * Will raise an EngineError if the digest is unavailable.
323  *
324  * e = OpenSSL::Engine.by_id("openssl")
325  * #=> #<OpenSSL::Engine id="openssl" name="Software engine support">
326  * e.digest("SHA1")
327  * #=> #<OpenSSL::Digest: da39a3ee5e6b4b0d3255bfef95601890afd80709>
328  * e.digest("zomg")
329  * #=> OpenSSL::Engine::EngineError: no such digest `zomg'
330  */
331 static VALUE
332 ossl_engine_get_digest(VALUE self, VALUE name)
333 {
334  ENGINE *e;
335  const EVP_MD *md, *tmp;
336  int nid;
337 
338  tmp = EVP_get_digestbyname(StringValueCStr(name));
339  if(!tmp) ossl_raise(eEngineError, "no such digest `%"PRIsVALUE"'", name);
340  nid = EVP_MD_nid(tmp);
341  GetEngine(self, e);
342  md = ENGINE_get_digest(e, nid);
343  if(!md) ossl_raise(eEngineError, NULL);
344 
345  return ossl_digest_new(md);
346 }
347 
348 /*
349  * call-seq:
350  * engine.load_private_key(id = nil, data = nil) -> OpenSSL::PKey
351  *
352  * Loads the given private key identified by _id_ and _data_.
353  *
354  * An EngineError is raised of the OpenSSL::PKey is unavailable.
355  *
356  */
357 static VALUE
358 ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
359 {
360  ENGINE *e;
361  EVP_PKEY *pkey;
362  VALUE id, data, obj;
363  char *sid, *sdata;
364 
365  rb_scan_args(argc, argv, "02", &id, &data);
366  sid = NIL_P(id) ? NULL : StringValueCStr(id);
367  sdata = NIL_P(data) ? NULL : StringValueCStr(data);
368  GetEngine(self, e);
369  pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
370  if (!pkey) ossl_raise(eEngineError, NULL);
371  obj = ossl_pkey_new(pkey);
373 
374  return obj;
375 }
376 
377 /*
378  * call-seq:
379  * engine.load_public_key(id = nil, data = nil) -> OpenSSL::PKey
380  *
381  * Loads the given public key identified by _id_ and _data_.
382  *
383  * An EngineError is raised of the OpenSSL::PKey is unavailable.
384  *
385  */
386 static VALUE
387 ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
388 {
389  ENGINE *e;
390  EVP_PKEY *pkey;
391  VALUE id, data;
392  char *sid, *sdata;
393 
394  rb_scan_args(argc, argv, "02", &id, &data);
395  sid = NIL_P(id) ? NULL : StringValueCStr(id);
396  sdata = NIL_P(data) ? NULL : StringValueCStr(data);
397  GetEngine(self, e);
398  pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
399  if (!pkey) ossl_raise(eEngineError, NULL);
400 
401  return ossl_pkey_new(pkey);
402 }
403 
404 /*
405  * call-seq:
406  * engine.set_default(flag)
407  *
408  * Set the defaults for this engine with the given _flag_.
409  *
410  * These flags are used to control combinations of algorithm methods.
411  *
412  * _flag_ can be one of the following, other flags are available depending on
413  * your OS.
414  *
415  * [All flags] 0xFFFF
416  * [No flags] 0x0000
417  *
418  * See also <openssl/engine.h>
419  */
420 static VALUE
421 ossl_engine_set_default(VALUE self, VALUE flag)
422 {
423  ENGINE *e;
424  int f = NUM2INT(flag);
425 
426  GetEngine(self, e);
427  ENGINE_set_default(e, f);
428 
429  return Qtrue;
430 }
431 
432 /*
433  * call-seq:
434  * engine.ctrl_cmd(command, value = nil) -> engine
435  *
436  * Sends the given _command_ to this engine.
437  *
438  * Raises an EngineError if the command fails.
439  */
440 static VALUE
441 ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
442 {
443  ENGINE *e;
444  VALUE cmd, val;
445  int ret;
446 
447  GetEngine(self, e);
448  rb_scan_args(argc, argv, "11", &cmd, &val);
449  ret = ENGINE_ctrl_cmd_string(e, StringValueCStr(cmd),
450  NIL_P(val) ? NULL : StringValueCStr(val), 0);
451  if (!ret) ossl_raise(eEngineError, NULL);
452 
453  return self;
454 }
455 
456 static VALUE
457 ossl_engine_cmd_flag_to_name(int flag)
458 {
459  switch(flag){
460  case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
461  case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
462  case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
463  case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
464  default: return rb_str_new2("UNKNOWN");
465  }
466 }
467 
468 /*
469  * call-seq:
470  * engine.cmds -> [["name", "description", "flags"], ...]
471  *
472  * Returns an array of command definitions for the current engine
473  */
474 static VALUE
475 ossl_engine_get_cmds(VALUE self)
476 {
477  ENGINE *e;
478  const ENGINE_CMD_DEFN *defn, *p;
479  VALUE ary, tmp;
480 
481  GetEngine(self, e);
482  ary = rb_ary_new();
483  if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
484  for (p = defn; p->cmd_num > 0; p++){
485  tmp = rb_ary_new();
486  rb_ary_push(tmp, rb_str_new2(p->cmd_name));
487  rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
488  rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
489  rb_ary_push(ary, tmp);
490  }
491  }
492 
493  return ary;
494 }
495 
496 /*
497  * call-seq:
498  * engine.inspect -> string
499  *
500  * Pretty prints this engine.
501  */
502 static VALUE
503 ossl_engine_inspect(VALUE self)
504 {
505  ENGINE *e;
506 
507  GetEngine(self, e);
508  return rb_sprintf("#<%"PRIsVALUE" id=\"%s\" name=\"%s\">",
509  rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
510 }
511 
512 #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
513 
514 void
516 {
517 #if 0
518  mOSSL = rb_define_module("OpenSSL");
520 #endif
521 
524 
526  rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1);
527  rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0);
528  rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0);
529  rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1);
530 
531  rb_define_method(cEngine, "id", ossl_engine_get_id, 0);
532  rb_define_method(cEngine, "name", ossl_engine_get_name, 0);
533  rb_define_method(cEngine, "finish", ossl_engine_finish, 0);
534  rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1);
535  rb_define_method(cEngine, "digest", ossl_engine_get_digest, 1);
536  rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1);
537  rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1);
538  rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1);
539  rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1);
540  rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0);
541  rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0);
542 
543  DefEngineConst(METHOD_RSA);
544  DefEngineConst(METHOD_DSA);
545  DefEngineConst(METHOD_DH);
546  DefEngineConst(METHOD_RAND);
547 #ifdef ENGINE_METHOD_BN_MOD_EXP
548  DefEngineConst(METHOD_BN_MOD_EXP);
549 #endif
550 #ifdef ENGINE_METHOD_BN_MOD_EXP_CRT
551  DefEngineConst(METHOD_BN_MOD_EXP_CRT);
552 #endif
553  DefEngineConst(METHOD_CIPHERS);
554  DefEngineConst(METHOD_DIGESTS);
555  DefEngineConst(METHOD_ALL);
556  DefEngineConst(METHOD_NONE);
557 }
558 #else
559 void
560 Init_ossl_engine(void)
561 {
562 }
563 #endif
#define SetEngine(obj, engine)
Definition: ossl_engine.c:16
VALUE mOSSL
Definition: ossl.c:231
#define RUBY_TYPED_FREE_IMMEDIATELY
Definition: ruby.h:1138
#define GetEngine(obj, engine)
Definition: ossl_engine.c:22
#define NUM2INT(x)
Definition: ruby.h:684
void rb_undef_alloc_func(VALUE)
Definition: vm_method.c:675
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1716
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:835
#define Qtrue
Definition: ruby.h:437
void Init_ossl_engine(void)
Definition: ossl_engine.c:515
const int id
Definition: nkf.c:209
VALUE cEngine
Definition: ossl_engine.c:39
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:924
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:693
VALUE ossl_pkey_new(EVP_PKEY *pkey)
Definition: ossl_pkey.c:107
#define DefEngineConst(x)
Definition: ossl_engine.c:512
VALUE rb_obj_class(VALUE)
call-seq: obj.class -> class
Definition: object.c:277
VALUE ossl_cipher_new(const EVP_CIPHER *cipher)
Definition: ossl_cipher.c:75
#define OSSL_PKEY_SET_PRIVATE(obj)
Definition: ossl_pkey.h:18
void ossl_clear_error(void)
Definition: ossl.c:304
#define val
RUBY_EXTERN VALUE rb_cObject
Definition: ruby.h:1893
#define NewEngine(klass)
Definition: ossl_engine.c:14
VALUE rb_ary_new(void)
Definition: array.c:499
VALUE ossl_digest_new(const EVP_MD *md)
Definition: ossl_digest.c:73
#define NIL_P(v)
Definition: ruby.h:451
VALUE eOSSLError
Definition: ossl.c:236
int argc
Definition: ruby.c:187
#define OSSL_ENGINE_LOAD_IF_MATCH(x)
Definition: ossl_engine.c:49
#define rb_str_new2
Definition: intern.h:835
int ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_)
Definition: ossl.c:177
VALUE rb_yield(VALUE)
Definition: vm_eval.c:973
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1452
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1908
#define PRIsVALUE
Definition: ruby.h:135
#define Qnil
Definition: ruby.h:438
VALUE rb_eStandardError
Definition: error.c:799
unsigned long VALUE
Definition: ruby.h:85
#define StringValueCStr(v)
Definition: ruby.h:571
#define RSTRING_PTR(str)
Definition: ruby.h:975
#define f
void rb_warning(const char *fmt,...)
Definition: error.c:267
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:293
const char * name
Definition: nkf.c:208
VALUE eEngineError
Definition: ossl_engine.c:44
int nid
VALUE rb_define_module(const char *name)
Definition: class.c:768
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
char ** argv
Definition: ruby.c:188