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