From d77b606edd788a52e40b27838c6b1b588c1f33cd Mon Sep 17 00:00:00 2001 From: gotoyuzo Date: Thu, 2 Oct 2003 08:47:11 +0000 Subject: * ext/openssl/ossl_engine.c: add a new module OpenSSL::Engine. it supports OpenSSL hardware cryptographic engine interface. * ext/openssl/ossl_engine.h: ditto. * ext/openssl/MANIFEST: add ossl_engine.c and ossl_engine.h. * ext/openssl/extconf.rb: add check for openssl/engine.h. * ext/openssl/ossl.c: call Init_ossl_engine(). * ext/openssl/ossl.h: include openssl/engine.h. * ext/openssl/ossl_pkey_{rsa,dsa,dh}.c: check if underlying EVP_PKEY referes engine. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4652 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 18 +++ ext/openssl/MANIFEST | 2 + ext/openssl/extconf.rb | 3 + ext/openssl/ossl.c | 1 + ext/openssl/ossl.h | 1 + ext/openssl/ossl_engine.c | 305 ++++++++++++++++++++++++++++++++++++++++++++ ext/openssl/ossl_engine.h | 20 +++ ext/openssl/ossl_pkey_dh.c | 9 +- ext/openssl/ossl_pkey_dsa.c | 11 +- ext/openssl/ossl_pkey_rsa.c | 10 +- 10 files changed, 375 insertions(+), 5 deletions(-) create mode 100644 ext/openssl/ossl_engine.c create mode 100644 ext/openssl/ossl_engine.h diff --git a/ChangeLog b/ChangeLog index 8f7d291731..b11cb76876 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +Thu Oct 2 17:39:38 2003 GOTOU Yuuzou + + * ext/openssl/ossl_engine.c: add a new module OpenSSL::Engine. + it supports OpenSSL hardware cryptographic engine interface. + + * ext/openssl/ossl_engine.h: ditto. + + * ext/openssl/MANIFEST: add ossl_engine.c and ossl_engine.h. + + * ext/openssl/extconf.rb: add check for openssl/engine.h. + + * ext/openssl/ossl.c: call Init_ossl_engine(). + + * ext/openssl/ossl.h: include openssl/engine.h. + + * ext/openssl/ossl_pkey_{rsa,dsa,dh}.c: check if underlying + EVP_PKEY referes engine. + Thu Oct 2 17:22:37 2003 Yukihiro Matsumoto * time.c (time_load): restore instance variables (if any) before diff --git a/ext/openssl/MANIFEST b/ext/openssl/MANIFEST index 78ac7e98b2..cdaf55c926 100644 --- a/ext/openssl/MANIFEST +++ b/ext/openssl/MANIFEST @@ -27,6 +27,8 @@ ossl_config.c ossl_config.h ossl_digest.c ossl_digest.h +ossl_engine.c +ossl_engine.h ossl_hmac.c ossl_hmac.h ossl_ns_spki.c diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index fe2469cfc4..eaf874e6bd 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -83,6 +83,9 @@ have_func("CONF_get1_default_config_file") if try_compile("#define FOO(a, ...) foo(a, ##__VA_ARGS__)\n int x(){FOO(1);FOO(1,2);FOO(1,2,3);}\n") $defs.push("-DHAVE_VA_ARGS_MACRO") end +if have_header("openssl/engine.h") + have_func("ENGINE_load_openbsd_dev_crypto") +end have_header("openssl/ocsp.h") have_struct_member("EVP_CIPHER_CTX", "flags", "openssl/evp.h") diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 497f2549f3..cc12a8fda8 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -433,6 +433,7 @@ Init_openssl() Init_ossl_ssl(); Init_ossl_x509(); Init_ossl_ocsp(); + Init_ossl_engine(); } #if defined(OSSL_DEBUG) diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index 33c2083311..bb9bd2a497 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -200,6 +200,7 @@ void ossl_debug(const char *, ...); #include "ossl_ssl.h" #include "ossl_version.h" #include "ossl_x509.h" +#include "ossl_engine.h" void Init_openssl(void); diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c new file mode 100644 index 0000000000..9e637aac03 --- /dev/null +++ b/ext/openssl/ossl_engine.c @@ -0,0 +1,305 @@ +/* + * $Id$ + * 'OpenSSL for Ruby' project + * Copyright (C) 2003 GOTOU Yuuzou + * All rights reserved. + */ +/* + * This program is licenced under the same licence as Ruby. + * (See the file 'LICENCE'.) + */ +#include "ossl.h" + +#if defined(OSSL_ENGINE_ENABLED) + +#define WrapEngine(klass, obj, engine) do { \ + if (!engine) { \ + ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ + } \ + obj = Data_Wrap_Struct(klass, 0, ENGINE_free, engine); \ +} while(0) +#define GetEngine(obj, engine) do { \ + Data_Get_Struct(obj, ENGINE, engine); \ + if (!engine) { \ + ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \ + } \ +} while (0) +#define SafeGetEngine(obj, engine) do { \ + OSSL_Check_Kind(obj, cEngine); \ + GetPKCS7(obj, engine); \ +} while (0) + +/* + * Classes + */ +VALUE cEngine; +VALUE eEngineError; + +/* + * Private + */ +#define OSSL_ENGINE_LOAD_IF_MATCH(x) \ +do{\ + if(!strcmp(#x, RSTRING(name)->ptr)){\ + ENGINE_load_##x();\ + return Qtrue;\ + }\ +}while(0) + +static VALUE +ossl_engine_s_load(int argc, VALUE *argv, VALUE klass) +{ + VALUE name; + + rb_scan_args(argc, argv, "01", &name); + if(NIL_P(name)) ENGINE_load_builtin_engines(); + StringValue(name); + OSSL_ENGINE_LOAD_IF_MATCH(openssl); + OSSL_ENGINE_LOAD_IF_MATCH(dynamic); + OSSL_ENGINE_LOAD_IF_MATCH(cswift); + OSSL_ENGINE_LOAD_IF_MATCH(chil); + OSSL_ENGINE_LOAD_IF_MATCH(atalla); + OSSL_ENGINE_LOAD_IF_MATCH(nuron); + OSSL_ENGINE_LOAD_IF_MATCH(ubsec); + OSSL_ENGINE_LOAD_IF_MATCH(aep); + OSSL_ENGINE_LOAD_IF_MATCH(sureware); + OSSL_ENGINE_LOAD_IF_MATCH(4758cca); +#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO + OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto); +#endif + rb_raise(eEngineError, "no such engine `%s'", RSTRING(name)->ptr); +} + +static VALUE +ossl_engine_s_cleanup(VALUE self) +{ + ENGINE_cleanup(); + return Qnil; +} + +static VALUE +ossl_engine_s_engines(VALUE klass) +{ + ENGINE *e; + VALUE ary, obj; + + ary = rb_ary_new(); + for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){ + WrapEngine(klass, obj, e); + rb_ary_push(ary, obj); + } + + return ary; +} + +static VALUE +ossl_engine_s_by_id(VALUE klass, VALUE id) +{ + ENGINE *e; + VALUE obj; + + StringValue(id); + ossl_engine_s_load(1, &id, klass); + if(!(e = ENGINE_by_id(RSTRING(id)->ptr))) + ossl_raise(eEngineError, NULL); + if(!ENGINE_init(e)) + ossl_raise(eEngineError, NULL); + ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK, + 0, NULL, (void(*)())ossl_pem_passwd_cb); + ERR_clear_error(); + WrapEngine(klass, obj, e); + + return obj; +} + +static VALUE +ossl_engine_s_alloc(VALUE klass) +{ + ENGINE *e; + VALUE obj; + + if (!(e = ENGINE_new())) { + ossl_raise(eEngineError, NULL); + } + WrapEngine(klass, obj, e); + + return obj; +} + +static VALUE +ossl_engine_get_id(VALUE self) +{ + ENGINE *e; + GetEngine(self, e); + return rb_str_new2(ENGINE_get_id(e)); +} + +static VALUE +ossl_engine_get_name(VALUE self) +{ + ENGINE *e; + GetEngine(self, e); + return rb_str_new2(ENGINE_get_name(e)); +} + +static VALUE +ossl_engine_finish(VALUE self) +{ + ENGINE *e; + + GetEngine(self, e); + if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL); + + return Qnil; +} + +static VALUE +ossl_engine_get_cipher(VALUE self, VALUE name) +{ + ENGINE *e; + const EVP_CIPHER *ciph, *tmp; + char *s; + int nid; + + s = StringValuePtr(name); + tmp = EVP_get_cipherbyname(s); + if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s); + nid = EVP_CIPHER_nid(tmp); + GetEngine(self, e); + ciph = ENGINE_get_cipher(e, nid); + if(!ciph) ossl_raise(eEngineError, NULL); + + return ossl_cipher_new(ciph); +} + +static VALUE +ossl_engine_get_digest(VALUE self, VALUE name) +{ + ENGINE *e; + const EVP_MD *md, *tmp; + char *s; + int nid; + + s = StringValuePtr(name); + tmp = EVP_get_digestbyname(s); + if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s); + nid = EVP_MD_nid(tmp); + GetEngine(self, e); + md = ENGINE_get_digest(e, nid); + if(!md) ossl_raise(eEngineError, NULL); + + return ossl_digest_new(md); +} + +static VALUE +ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self) +{ + ENGINE *e; + EVP_PKEY *pkey; + VALUE id, data; + char *sid, *sdata; + + rb_scan_args(argc, argv, "11", &id, &data); + sid = StringValuePtr(id); + sdata = NIL_P(data) ? NULL : StringValuePtr(data); + GetEngine(self, e); +#if OPENSSL_VERSION_NUMBER < 0x0090702fL + pkey = ENGINE_load_private_key(e, sid, sdata); +#else + pkey = ENGINE_load_private_key(e, sid, NULL, sdata); +#endif + if (!pkey) ossl_raise(eEngineError, NULL); + + return ossl_pkey_new(pkey); +} + +static VALUE +ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self) +{ + ENGINE *e; + EVP_PKEY *pkey; + VALUE id, data; + char *sid, *sdata; + + rb_scan_args(argc, argv, "11", &id, &data); + sid = StringValuePtr(id); + sdata = NIL_P(data) ? NULL : StringValuePtr(data); + GetEngine(self, e); +#if OPENSSL_VERSION_NUMBER < 0x0090702fL + pkey = ENGINE_load_public_key(e, sid, sdata); +#else + pkey = ENGINE_load_public_key(e, sid, NULL, sdata); +#endif + if (!pkey) ossl_raise(eEngineError, NULL); + + return ossl_pkey_new(pkey); +} + +static VALUE +ossl_engine_set_default(VALUE self, VALUE flag) +{ + ENGINE *e; + + GetEngine(self, e); + ENGINE_set_default(e, NUM2INT(flag)); + + return Qtrue; +} + +static VALUE +ossl_engine_inspect(VALUE self) +{ + VALUE str; + char *cname = rb_class2name(rb_obj_class(self)); + + str = rb_str_new2("#<"); + rb_str_cat2(str, cname); + rb_str_cat2(str, " id=\""); + rb_str_append(str, ossl_engine_get_id(self)); + rb_str_cat2(str, "\" name=\""); + rb_str_append(str, ossl_engine_get_name(self)); + rb_str_cat2(str, "\">"); + + return str; +} + +#define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x)) + +void +Init_ossl_engine() +{ + cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject); + eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError); + + rb_define_alloc_func(cEngine, ossl_engine_s_alloc); + rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1); + rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0); + rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0); + rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1); + rb_undef_method(CLASS_OF(cEngine), "new"); + + rb_define_method(cEngine, "id", ossl_engine_get_id, 0); + rb_define_method(cEngine, "name", ossl_engine_get_name, 0); + rb_define_method(cEngine, "finish", ossl_engine_finish, 0); + rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1); + rb_define_method(cEngine, "digest", ossl_engine_get_digest, 1); + rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1); + rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1); + rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1); + rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0); + + DefEngineConst(METHOD_RSA); + DefEngineConst(METHOD_DSA); + DefEngineConst(METHOD_DH); + DefEngineConst(METHOD_RAND); + DefEngineConst(METHOD_CIPHERS); + DefEngineConst(METHOD_DIGESTS); + DefEngineConst(METHOD_ALL); + DefEngineConst(METHOD_NONE); +} +#else +void +Init_ossl_engine() +{ +} +#endif diff --git a/ext/openssl/ossl_engine.h b/ext/openssl/ossl_engine.h new file mode 100644 index 0000000000..ea2f256912 --- /dev/null +++ b/ext/openssl/ossl_engine.h @@ -0,0 +1,20 @@ +/* + * $Id$ + * 'OpenSSL for Ruby' project + * Copyright (C) 2003 Michal Rokos + * Copyright (C) 2003 GOTOU Yuuzou + * All rights reserved. + */ +/* + * This program is licenced under the same licence as Ruby. + * (See the file 'LICENCE'.) + */ +#if !defined(OSSL_ENGINE_H) +#define OSSL_ENGINE_H + +extern VALUE cEngine; +extern VALUE eEngineError; + +void Init_ossl_engine(void); + +#endif /* OSSL_ENGINE_H */ diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index 80f7f2a5bf..e4823a2ec7 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -19,7 +19,14 @@ } \ } while (0) -#define DH_PRIVATE(dh) ((dh)->priv_key) +#define DH_HAS_PRIVATE(dh) ((dh)->priv_key) + +#ifdef OSSL_ENGINE_ENABLED +# define DH_PRIVATE(dh) (DH_HAS_PRIVATE(dh) || (dh)->engine) +#else +# define DH_PRIVATE(dh) DH_HAS_PRIVATE(dh) +#endif + /* * Classes diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index e20d155445..8da71a0867 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -19,7 +19,14 @@ } \ } while (0) -#define DSA_PRIVATE(dsa) ((dsa)->priv_key) +#define DSA_HAS_PRIVATE(dsa) ((dsa)->priv_key) + +#ifdef OSSL_ENGINE_ENABLED +# define DSA_PRIVATE(dsa) (DSA_HAS_PRIVATE(dsa) || (dsa)->engine) +#else +# define DSA_PRIVATE(dsa) DSA_HAS_PRIVATE(dsa) +#endif + /* * Classes @@ -203,7 +210,7 @@ ossl_dsa_export(int argc, VALUE *argv, VALUE self) if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eDSAError, NULL); } - if (DSA_PRIVATE(pkey->pkey.dsa)) { + if (DSA_HAS_PRIVATE(pkey->pkey.dsa)) { if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph, NULL, 0, ossl_pem_passwd_cb, passwd)){ BIO_free(out); diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 2d04bf8367..669e84efca 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -19,7 +19,13 @@ } \ } while (0) -#define RSA_PRIVATE(rsa) ((rsa)->p && (rsa)->q) +#define RSA_HAS_PRIVATE(rsa) ((rsa)->p && (rsa)->q) + +#ifdef OSSL_ENGINE_ENABLED +# define RSA_PRIVATE(rsa) (RSA_HAS_PRIVATE(rsa) || (rsa)->engine) +#else +# define RSA_PRIVATE(rsa) RSA_HAS_PRIVATE(rsa) +#endif /* * Classes @@ -199,7 +205,7 @@ ossl_rsa_export(int argc, VALUE *argv, VALUE self) if (!(out = BIO_new(BIO_s_mem()))) { ossl_raise(eRSAError, NULL); } - if (RSA_PRIVATE(pkey->pkey.rsa)) { + if (RSA_HAS_PRIVATE(pkey->pkey.rsa)) { if (!PEM_write_bio_RSAPrivateKey(out, pkey->pkey.rsa, ciph, NULL, 0, ossl_pem_passwd_cb, passwd)) { BIO_free(out); -- cgit v1.2.3