Ruby  1.9.3p484(2013-11-22revision43786)
ossl_engine.c
Go to the documentation of this file.
1 /*
2  * $Id: ossl_engine.c 34505 2012-02-09 03:25:07Z nobu $
3  * 'OpenSSL for Ruby' project
4  * Copyright (C) 2003 GOTOU Yuuzou <gotoyuzo@notwork.org>
5  * All rights reserved.
6  */
7 /*
8  * This program is licenced under the same licence as Ruby.
9  * (See the file 'LICENCE'.)
10  */
11 #include "ossl.h"
12 
13 #if defined(OSSL_ENGINE_ENABLED)
14 
15 #define WrapEngine(klass, obj, engine) do { \
16  if (!(engine)) { \
17  ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
18  } \
19  (obj) = Data_Wrap_Struct((klass), 0, ENGINE_free, (engine)); \
20 } while(0)
21 #define GetEngine(obj, engine) do { \
22  Data_Get_Struct((obj), ENGINE, (engine)); \
23  if (!(engine)) { \
24  ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
25  } \
26 } while (0)
27 #define SafeGetEngine(obj, engine) do { \
28  OSSL_Check_Kind((obj), cEngine); \
29  GetPKCS7((obj), (engine)); \
30 } while (0)
31 
32 /*
33  * Classes
34  */
37 
38 /*
39  * Private
40  */
41 #define OSSL_ENGINE_LOAD_IF_MATCH(x) \
42 do{\
43  if(!strcmp(#x, RSTRING_PTR(name))){\
44  ENGINE_load_##x();\
45  return Qtrue;\
46  }\
47 }while(0)
48 
49 static VALUE
50 ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
51 {
52 #if !defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES)
53  return Qnil;
54 #else
55  VALUE name;
56 
57  rb_scan_args(argc, argv, "01", &name);
58  if(NIL_P(name)){
59  ENGINE_load_builtin_engines();
60  return Qtrue;
61  }
62  StringValue(name);
63 #ifndef OPENSSL_NO_STATIC_ENGINE
64 #if HAVE_ENGINE_LOAD_DYNAMIC
65  OSSL_ENGINE_LOAD_IF_MATCH(dynamic);
66 #endif
67 #if HAVE_ENGINE_LOAD_CSWIFT
68  OSSL_ENGINE_LOAD_IF_MATCH(cswift);
69 #endif
70 #if HAVE_ENGINE_LOAD_CHIL
71  OSSL_ENGINE_LOAD_IF_MATCH(chil);
72 #endif
73 #if HAVE_ENGINE_LOAD_ATALLA
74  OSSL_ENGINE_LOAD_IF_MATCH(atalla);
75 #endif
76 #if HAVE_ENGINE_LOAD_NURON
77  OSSL_ENGINE_LOAD_IF_MATCH(nuron);
78 #endif
79 #if HAVE_ENGINE_LOAD_UBSEC
80  OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
81 #endif
82 #if HAVE_ENGINE_LOAD_AEP
83  OSSL_ENGINE_LOAD_IF_MATCH(aep);
84 #endif
85 #if HAVE_ENGINE_LOAD_SUREWARE
86  OSSL_ENGINE_LOAD_IF_MATCH(sureware);
87 #endif
88 #if HAVE_ENGINE_LOAD_4758CCA
89  OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
90 #endif
91 #endif
92 #ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
93  OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
94 #endif
95  OSSL_ENGINE_LOAD_IF_MATCH(openssl);
96  rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name));
97  return Qnil;
98 #endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
99 }
100 
101 static VALUE
102 ossl_engine_s_cleanup(VALUE self)
103 {
104 #if defined(HAVE_ENGINE_CLEANUP)
105  ENGINE_cleanup();
106 #endif
107  return Qnil;
108 }
109 
110 static VALUE
111 ossl_engine_s_engines(VALUE klass)
112 {
113  ENGINE *e;
114  VALUE ary, obj;
115 
116  ary = rb_ary_new();
117  for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
118  /* Need a ref count of two here because of ENGINE_free being
119  * called internally by OpenSSL when moving to the next ENGINE
120  * and by us when releasing the ENGINE reference */
121  ENGINE_up_ref(e);
122  WrapEngine(klass, obj, e);
123  rb_ary_push(ary, obj);
124  }
125 
126  return ary;
127 }
128 
129 static VALUE
130 ossl_engine_s_by_id(VALUE klass, VALUE id)
131 {
132  ENGINE *e;
133  VALUE obj;
134 
135  StringValue(id);
136  ossl_engine_s_load(1, &id, klass);
137  if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
138  ossl_raise(eEngineError, NULL);
139  WrapEngine(klass, obj, e);
140  if(rb_block_given_p()) rb_yield(obj);
141  if(!ENGINE_init(e))
142  ossl_raise(eEngineError, NULL);
143  ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
144  0, NULL, (void(*)(void))ossl_pem_passwd_cb);
145  ERR_clear_error();
146 
147  return obj;
148 }
149 
150 static VALUE
151 ossl_engine_s_alloc(VALUE klass)
152 {
153  ENGINE *e;
154  VALUE obj;
155 
156  if (!(e = ENGINE_new())) {
157  ossl_raise(eEngineError, NULL);
158  }
159  WrapEngine(klass, obj, e);
160 
161  return obj;
162 }
163 
164 static VALUE
165 ossl_engine_get_id(VALUE self)
166 {
167  ENGINE *e;
168  GetEngine(self, e);
169  return rb_str_new2(ENGINE_get_id(e));
170 }
171 
172 static VALUE
173 ossl_engine_get_name(VALUE self)
174 {
175  ENGINE *e;
176  GetEngine(self, e);
177  return rb_str_new2(ENGINE_get_name(e));
178 }
179 
180 static VALUE
181 ossl_engine_finish(VALUE self)
182 {
183  ENGINE *e;
184 
185  GetEngine(self, e);
186  if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL);
187 
188  return Qnil;
189 }
190 
191 #if defined(HAVE_ENGINE_GET_CIPHER)
192 static VALUE
193 ossl_engine_get_cipher(VALUE self, VALUE name)
194 {
195  ENGINE *e;
196  const EVP_CIPHER *ciph, *tmp;
197  char *s;
198  int nid;
199 
200  s = StringValuePtr(name);
201  tmp = EVP_get_cipherbyname(s);
202  if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s);
203  nid = EVP_CIPHER_nid(tmp);
204  GetEngine(self, e);
205  ciph = ENGINE_get_cipher(e, nid);
206  if(!ciph) ossl_raise(eEngineError, NULL);
207 
208  return ossl_cipher_new(ciph);
209 }
210 #else
211 #define ossl_engine_get_cipher rb_f_notimplement
212 #endif
213 
214 #if defined(HAVE_ENGINE_GET_DIGEST)
215 static VALUE
216 ossl_engine_get_digest(VALUE self, VALUE name)
217 {
218  ENGINE *e;
219  const EVP_MD *md, *tmp;
220  char *s;
221  int nid;
222 
223  s = StringValuePtr(name);
224  tmp = EVP_get_digestbyname(s);
225  if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s);
226  nid = EVP_MD_nid(tmp);
227  GetEngine(self, e);
228  md = ENGINE_get_digest(e, nid);
229  if(!md) ossl_raise(eEngineError, NULL);
230 
231  return ossl_digest_new(md);
232 }
233 #else
234 #define ossl_engine_get_digest rb_f_notimplement
235 #endif
236 
237 static VALUE
238 ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
239 {
240  ENGINE *e;
241  EVP_PKEY *pkey;
242  VALUE id, data, obj;
243  char *sid, *sdata;
244 
245  rb_scan_args(argc, argv, "02", &id, &data);
246  sid = NIL_P(id) ? NULL : StringValuePtr(id);
247  sdata = NIL_P(data) ? NULL : StringValuePtr(data);
248  GetEngine(self, e);
249 #if OPENSSL_VERSION_NUMBER < 0x00907000L
250  pkey = ENGINE_load_private_key(e, sid, sdata);
251 #else
252  pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
253 #endif
254  if (!pkey) ossl_raise(eEngineError, NULL);
255  obj = ossl_pkey_new(pkey);
257 
258  return obj;
259 }
260 
261 static VALUE
262 ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
263 {
264  ENGINE *e;
265  EVP_PKEY *pkey;
266  VALUE id, data;
267  char *sid, *sdata;
268 
269  rb_scan_args(argc, argv, "02", &id, &data);
270  sid = NIL_P(id) ? NULL : StringValuePtr(id);
271  sdata = NIL_P(data) ? NULL : StringValuePtr(data);
272  GetEngine(self, e);
273 #if OPENSSL_VERSION_NUMBER < 0x00907000L
274  pkey = ENGINE_load_public_key(e, sid, sdata);
275 #else
276  pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
277 #endif
278  if (!pkey) ossl_raise(eEngineError, NULL);
279 
280  return ossl_pkey_new(pkey);
281 }
282 
283 static VALUE
284 ossl_engine_set_default(VALUE self, VALUE flag)
285 {
286  ENGINE *e;
287  int f = NUM2INT(flag);
288 
289  GetEngine(self, e);
290  ENGINE_set_default(e, f);
291 
292  return Qtrue;
293 }
294 
295 static VALUE
296 ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
297 {
298  ENGINE *e;
299  VALUE cmd, val;
300  int ret;
301 
302  GetEngine(self, e);
303  rb_scan_args(argc, argv, "11", &cmd, &val);
304  StringValue(cmd);
305  if (!NIL_P(val)) StringValue(val);
306  ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd),
307  NIL_P(val) ? NULL : RSTRING_PTR(val), 0);
308  if (!ret) ossl_raise(eEngineError, NULL);
309 
310  return self;
311 }
312 
313 static VALUE
314 ossl_engine_cmd_flag_to_name(int flag)
315 {
316  switch(flag){
317  case ENGINE_CMD_FLAG_NUMERIC: return rb_str_new2("NUMERIC");
318  case ENGINE_CMD_FLAG_STRING: return rb_str_new2("STRING");
319  case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
320  case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
321  default: return rb_str_new2("UNKNOWN");
322  }
323 }
324 
325 static VALUE
326 ossl_engine_get_cmds(VALUE self)
327 {
328  ENGINE *e;
329  const ENGINE_CMD_DEFN *defn, *p;
330  VALUE ary, tmp;
331 
332  GetEngine(self, e);
333  ary = rb_ary_new();
334  if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
335  for (p = defn; p->cmd_num > 0; p++){
336  tmp = rb_ary_new();
337  rb_ary_push(tmp, rb_str_new2(p->cmd_name));
338  rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
339  rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
340  rb_ary_push(ary, tmp);
341  }
342  }
343 
344  return ary;
345 }
346 
347 static VALUE
348 ossl_engine_inspect(VALUE self)
349 {
350  VALUE str;
351  const char *cname = rb_class2name(rb_obj_class(self));
352 
353  str = rb_str_new2("#<");
354  rb_str_cat2(str, cname);
355  rb_str_cat2(str, " id=\"");
356  rb_str_append(str, ossl_engine_get_id(self));
357  rb_str_cat2(str, "\" name=\"");
358  rb_str_append(str, ossl_engine_get_name(self));
359  rb_str_cat2(str, "\">");
360 
361  return str;
362 }
363 
364 #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
365 
366 void
368 {
370  eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
371 
372  rb_define_alloc_func(cEngine, ossl_engine_s_alloc);
373  rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1);
374  rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0);
375  rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0);
376  rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1);
377  rb_undef_method(CLASS_OF(cEngine), "new");
378 
379  rb_define_method(cEngine, "id", ossl_engine_get_id, 0);
380  rb_define_method(cEngine, "name", ossl_engine_get_name, 0);
381  rb_define_method(cEngine, "finish", ossl_engine_finish, 0);
382  rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1);
383  rb_define_method(cEngine, "digest", ossl_engine_get_digest, 1);
384  rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1);
385  rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1);
386  rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1);
387  rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1);
388  rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0);
389  rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0);
390 
391  DefEngineConst(METHOD_RSA);
392  DefEngineConst(METHOD_DSA);
393  DefEngineConst(METHOD_DH);
394  DefEngineConst(METHOD_RAND);
395 #ifdef ENGINE_METHOD_BN_MOD_EXP
396  DefEngineConst(METHOD_BN_MOD_EXP);
397 #endif
398 #ifdef ENGINE_METHOD_BN_MOD_EXP_CRT
399  DefEngineConst(METHOD_BN_MOD_EXP_CRT);
400 #endif
401 #ifdef ENGINE_METHOD_CIPHERS
402  DefEngineConst(METHOD_CIPHERS);
403 #endif
404 #ifdef ENGINE_METHOD_DIGESTS
405  DefEngineConst(METHOD_DIGESTS);
406 #endif
407  DefEngineConst(METHOD_ALL);
408  DefEngineConst(METHOD_NONE);
409 }
410 #else
411 void
413 {
414 }
415 #endif
416