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