From aab0d67a1ff5190ff7a951e40cee742210302aed Mon Sep 17 00:00:00 2001 From: rhe Date: Wed, 30 Nov 2016 14:41:46 +0000 Subject: openssl: import v2.0.0 Import Ruby/OpenSSL 2.0.0. The full commit history since 2.0.0 beta.2 (imported at r56098) can be found at: https://github.com/ruby/openssl/compare/v2.0.0.beta.2...v2.0.0 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56946 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/openssl/History.md | 137 ++++++++++++++++++++++++ ext/openssl/extconf.rb | 6 -- ext/openssl/lib/openssl/buffering.rb | 8 ++ ext/openssl/lib/openssl/ssl.rb | 20 ++-- ext/openssl/openssl.gemspec | 28 ++--- ext/openssl/ossl.c | 115 +++++--------------- ext/openssl/ossl.h | 42 +------- ext/openssl/ossl_asn1.c | 198 ++++++++++++----------------------- ext/openssl/ossl_bio.c | 3 - ext/openssl/ossl_bn.c | 17 +-- ext/openssl/ossl_cipher.c | 77 +++++++------- ext/openssl/ossl_digest.c | 37 ++++--- ext/openssl/ossl_engine.c | 19 +--- ext/openssl/ossl_ns_spki.c | 7 +- ext/openssl/ossl_pkcs7.c | 2 +- ext/openssl/ossl_pkey.c | 107 +++++++++++++------ ext/openssl/ossl_pkey.h | 1 - ext/openssl/ossl_pkey_dh.c | 2 +- ext/openssl/ossl_pkey_dsa.c | 6 +- ext/openssl/ossl_pkey_ec.c | 62 ++++++----- ext/openssl/ossl_pkey_rsa.c | 12 +-- ext/openssl/ossl_ssl.c | 178 +++++++++++++++++-------------- ext/openssl/ossl_ssl_session.c | 55 ++++------ ext/openssl/ossl_x509.h | 9 +- ext/openssl/ossl_x509cert.c | 2 +- ext/openssl/ossl_x509crl.c | 29 +---- ext/openssl/ossl_x509name.c | 8 +- ext/openssl/ossl_x509req.c | 22 +--- ext/openssl/ossl_x509store.c | 108 ++++++++++++++----- ext/openssl/ruby_missing.h | 9 -- 30 files changed, 680 insertions(+), 646 deletions(-) create mode 100644 ext/openssl/History.md (limited to 'ext/openssl') diff --git a/ext/openssl/History.md b/ext/openssl/History.md new file mode 100644 index 0000000000..029426fb8c --- /dev/null +++ b/ext/openssl/History.md @@ -0,0 +1,137 @@ +Version 2.0.0 +============= + +This is the first release of openssl gem, formerly a standard library of Ruby, +ext/openssl. This is the successor of the version included in Ruby 2.3. + +Compatibility notes +------------------- + +* Support for OpenSSL version 0.9.6 and 0.9.7 is completely removed. openssl gem + still works with OpenSSL 0.9.8, but users are strongly encouraged to upgrade + to at least 1.0.1, as OpenSSL < 1.0.1 will not receive any security fixes from + the OpenSSL development team. + +Supported platforms +------------------- + +* OpenSSL 1.0.0, 1.0.1, 1.0.2, 1.1.0 +* OpenSSL < 0.9.8 is no longer supported. +* LibreSSL 2.3, 2.4, 2.5 +* Ruby 2.3, 2.4 + +Notable changes +--------------- + +* Add support for OpenSSL 1.1.0. [[Feature #12324]](https://bugs.ruby-lang.org/issues/12324) +* Add support for LibreSSL + +* OpenSSL::Cipher + + - OpenSSL::Cipher#key= and #iv= reject too long inputs. They used to truncate + silently. [[Bug #12561]](https://bugs.ruby-lang.org/issues/12561) + + - OpenSSL::Cipher#iv_len= is added. It allows changing IV (nonce) length if + using AEAD ciphers. + [[Bug #8667]](https://bugs.ruby-lang.org/issues/8667), + [[Bug #10420]](https://bugs.ruby-lang.org/issues/10420), + [[GH ruby/ruby#569]](https://github.com/ruby/ruby/pull/569), + [[GH ruby/openssl#58]](https://github.com/ruby/openssl/pull/58) + + - OpenSSL::Cipher#auth_tag_len= is added. This sets the authentication tag + length to be generated by an AEAD cipher. + +* OpenSSL::OCSP + + - Accessor methods are added to OpenSSL::OCSP::CertificateId. + [[Feature #7181]](https://bugs.ruby-lang.org/issues/7181) + + - OpenSSL::OCSP::Request and BasicResponse can be signed with non-SHA-1 hash + algorithm. [[Feature #11552]](https://bugs.ruby-lang.org/issues/11552) + + - OpenSSL::OCSP::CertificateId and BasicResponse can be encoded into DER. + + - A new class OpenSSL::OCSP::SingleResponse is added for convenience. + + - OpenSSL::OCSP::BasicResponse#add_status accepts absolute times. They used to + accept only relative seconds from the current time. + +* OpenSSL::PKey + + - OpenSSL::PKey::EC follows the general PKey interface. + [[Bug #6567]](https://bugs.ruby-lang.org/issues/6567) + + - OpenSSL::PKey.read raises OpenSSL::PKey::PKeyError instead of ArgumentError + for consistency with OpenSSL::PKey::{DH,DSA,RSA,EC}#new. + [[Bug #11774]](https://bugs.ruby-lang.org/issues/11774), + [[GH ruby/openssl#55]](https://github.com/ruby/openssl/pull/55) + + - OpenSSL::PKey::EC::Group retrieved by OpenSSL::PKey::EC#group is no longer + linked with the EC key. Modifications to the EC::Group have no effect on the + key. [[GH ruby/openssl#71]](https://github.com/ruby/openssl/pull/71) + + - OpenSSL::PKey::EC::Point#to_bn allows specifying the point conversion form + by the optional argument. + +* OpenSSL::SSL + + - OpenSSL::SSL::SSLSocket#tmp_key is added. A client can call it after the + connection is established to retrieve the ephemeral key. + [[GH ruby/ruby#1318]](https://github.com/ruby/ruby/pull/1318) + + - The automatic ephemeral ECDH curve selection is enabled by default when + built with OpenSSL >= 1.0.2 or LibreSSL. + + - OpenSSL::SSL::SSLContext#security_level= is added. You can set the "security + level" of the SSL context. This is effective only when built with OpenSSL + 1.1.0. + + - A new option 'verify_hostname' is added to OpenSSL::SSL::SSLContext. When it + is enabled, and the SNI hostname is also set, the hostname verification on + the server certificate is automatically performed. It is now enabled by + OpenSSL::SSL::Context#set_params. + [[GH ruby/openssl#60]](https://github.com/ruby/openssl/pull/60) + +Removals +-------- + +* OpenSSL::Engine + + - OpenSSL::Engine.cleanup does nothing when built with OpenSSL 1.1.0. + +* OpenSSL::SSL + + - OpenSSL::PKey::DH::DEFAULT_512 is removed. Hence servers no longer use + 512-bit DH group by default. It is considered too weak nowadays. + [[Bug #11968]](https://bugs.ruby-lang.org/issues/11968), + [[GH ruby/ruby#1196]](https://github.com/ruby/ruby/pull/1196) + + - RC4 cipher suites are removed from OpenSSL::SSL::SSLContext::DEFAULT_PARAMS. + RC4 is now considered to be weak. + [[GH ruby/openssl#50]](https://github.com/ruby/openssl/pull/50) + +Deprecations +------------ + +* OpenSSL::PKey + + - OpenSSL::PKey::RSA#n=, #e=, #d=, #p=, #q=, #dmp1=, #dmq1=, #iqmp=, + OpenSSL::PKey::DSA#p=, #q=, #g=, #priv_key=, #pub_key=, + OpenSSL::PKey::DH#p=, #g=, #priv_key= and #pub_key= are deprecated. They are + disabled when built with OpenSSL 1.1.0, due to its API change. Instead, + OpenSSL::PKey::RSA#set_key, #set_factors, #set_crt_params, + OpenSSL::PKey::DSA#set_pqg, #set_key, OpenSSL::PKey::DH#set_pqg and #set_key + are added. + +* OpenSSL::Random + + - OpenSSL::Random.pseudo_bytes is deprecated, and not defined when built with + OpenSSL 1.1.0. Use OpenSSL::Random.random_bytes instead. + +* OpenSSL::SSL + + - OpenSSL::SSL::SSLContext#tmp_ecdh_callback is deprecated, as the underlying + API SSL_CTX_set_tmp_ecdh_callback() is removed in OpenSSL 1.1.0. It was + first added in Ruby 2.3.0. To specify the curve to be used in ephemeral + ECDH, use OpenSSL::SSL::SSLContext#ecdh_curves=. The automatic curve + selection is also now enabled by default when built with a capable OpenSSL. diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 20c67c6b50..a812e59dc4 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -33,14 +33,8 @@ end Logging::message "=== Checking for system dependent stuff... ===\n" have_library("nsl", "t_open") have_library("socket", "socket") -have_header("assert.h") Logging::message "=== Checking for required stuff... ===\n" -if $mingw - have_library("wsock32") - have_library("gdi32") -end - result = pkg_config("openssl") && have_header("openssl/ssl.h") unless result result = have_header("openssl/ssl.h") diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb index 94aba3520b..7fd647caad 100644 --- a/ext/openssl/lib/openssl/buffering.rb +++ b/ext/openssl/lib/openssl/buffering.rb @@ -163,6 +163,10 @@ module OpenSSL::Buffering # Note that one reason that read_nonblock writes to the underlying IO is # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for # more details. http://www.openssl.org/support/faq.html + # + # By specifying `exception: false`, the options hash allows you to indicate + # that read_nonblock should not raise an IO::Wait*able exception, but + # return the symbol :wait_writable or :wait_readable instead. def read_nonblock(maxlen, buf=nil, exception: true) if maxlen == 0 @@ -371,6 +375,10 @@ module OpenSSL::Buffering # Note that one reason that write_nonblock reads from the underlying IO # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ # for more details. http://www.openssl.org/support/faq.html + # + # By specifying `exception: false`, the options hash allows you to indicate + # that write_nonblock should not raise an IO::Wait*able exception, but + # return the symbol :wait_writable or :wait_readable instead. def write_nonblock(s, exception: true) flush diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index 190f504276..f40a451439 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -16,8 +16,7 @@ require "io/nonblock" module OpenSSL module SSL class SSLContext - # :nodoc: - DEFAULT_PARAMS = { + DEFAULT_PARAMS = { # :nodoc: :ssl_version => "SSLv23", :verify_mode => OpenSSL::SSL::VERIFY_PEER, :verify_hostname => true, @@ -68,8 +67,7 @@ module OpenSSL ) end - # :nodoc: - DEFAULT_CERT_STORE = OpenSSL::X509::Store.new + DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc: DEFAULT_CERT_STORE.set_default_paths DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL @@ -84,14 +82,12 @@ module OpenSSL attr_accessor :tmp_dh_callback - if ExtConfig::HAVE_TLSEXT_HOST_NAME - # A callback invoked at connect time to distinguish between multiple - # server names. - # - # The callback is invoked with an SSLSocket and a server name. The - # callback must return an SSLContext for the server name or nil. - attr_accessor :servername_cb - end + # A callback invoked at connect time to distinguish between multiple + # server names. + # + # The callback is invoked with an SSLSocket and a server name. The + # callback must return an SSLContext for the server name or nil. + attr_accessor :servername_cb if ExtConfig::HAVE_TLSEXT_HOST_NAME # call-seq: # SSLContext.new => ctx diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec index 48191fa0e9..2390da4e22 100644 --- a/ext/openssl/openssl.gemspec +++ b/ext/openssl/openssl.gemspec @@ -1,15 +1,15 @@ # -*- encoding: utf-8 -*- -# stub: openssl 2.0.0.beta.2 ruby lib +# stub: openssl 2.0.0 ruby lib # stub: ext/openssl/extconf.rb Gem::Specification.new do |s| s.name = "openssl".freeze - s.version = "2.0.0.beta.2" + s.version = "2.0.0" - s.required_rubygems_version = Gem::Requirement.new("> 1.3.1".freeze) if s.respond_to? :required_rubygems_version= + s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] s.authors = ["Martin Bosslet".freeze, "SHIBATA Hiroshi".freeze, "Zachary Scott".freeze, "Kazuki Yamaguchi".freeze] - s.date = "2016-09-08" + s.date = "2016-11-30" s.description = "It wraps the OpenSSL library.".freeze s.email = ["ruby-core@ruby-lang.org".freeze] s.extensions = ["ext/openssl/extconf.rb".freeze] @@ -19,27 +19,27 @@ Gem::Specification.new do |s| s.licenses = ["Ruby".freeze] s.rdoc_options = ["--main".freeze, "README.md".freeze] s.required_ruby_version = Gem::Requirement.new(">= 2.3.0".freeze) - s.rubygems_version = "2.6.6".freeze + s.rubygems_version = "2.6.8".freeze s.summary = "OpenSSL provides SSL, TLS and general purpose cryptography.".freeze if s.respond_to? :specification_version then s.specification_version = 4 if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then - s.add_development_dependency(%q.freeze, ["~> 10.3"]) - s.add_development_dependency(%q.freeze, ["~> 0.9"]) + s.add_development_dependency(%q.freeze, [">= 0"]) + s.add_development_dependency(%q.freeze, [">= 0"]) s.add_development_dependency(%q.freeze, ["~> 3.0"]) - s.add_development_dependency(%q.freeze, ["~> 4.2"]) + s.add_development_dependency(%q.freeze, [">= 0"]) else - s.add_dependency(%q.freeze, ["~> 10.3"]) - s.add_dependency(%q.freeze, ["~> 0.9"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 3.0"]) - s.add_dependency(%q.freeze, ["~> 4.2"]) + s.add_dependency(%q.freeze, [">= 0"]) end else - s.add_dependency(%q.freeze, ["~> 10.3"]) - s.add_dependency(%q.freeze, ["~> 0.9"]) + s.add_dependency(%q.freeze, [">= 0"]) + s.add_dependency(%q.freeze, [">= 0"]) s.add_dependency(%q.freeze, ["~> 3.0"]) - s.add_dependency(%q.freeze, ["~> 4.2"]) + s.add_dependency(%q.freeze, [">= 0"]) end end diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index a9000f25a3..8269599fff 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -149,7 +149,7 @@ ossl_pem_passwd_value(VALUE pass) /* PEM_BUFSIZE is currently used as the second argument of pem_password_cb, * that is +max_len+ of ossl_pem_passwd_cb() */ if (RSTRING_LEN(pass) > PEM_BUFSIZE) - ossl_raise(eOSSLError, "password must be shorter than %d bytes", PEM_BUFSIZE); + ossl_raise(eOSSLError, "password must not be longer than %d bytes", PEM_BUFSIZE); return pass; } @@ -168,7 +168,8 @@ ossl_pem_passwd_cb0(VALUE flag) int ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) { - int len, status; + long len; + int status; VALUE rflag, pass = (VALUE)pwd_; if (RTEST(pass)) { @@ -176,7 +177,7 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) * work because it does not allow NUL characters and truncates to 1024 * bytes silently if the input is over 1024 bytes */ if (RB_TYPE_P(pass, T_STRING)) { - len = RSTRING_LENINT(pass); + len = RSTRING_LEN(pass); if (len >= OSSL_MIN_PWD_LEN && len <= max_len) { memcpy(buf, RSTRING_PTR(pass), len); return len; @@ -203,78 +204,19 @@ ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd_) rb_set_errinfo(Qnil); return -1; } - len = RSTRING_LENINT(pass); + len = RSTRING_LEN(pass); if (len < OSSL_MIN_PWD_LEN) { rb_warning("password must be at least %d bytes", OSSL_MIN_PWD_LEN); continue; } if (len > max_len) { - rb_warning("password must be shorter than %d bytes", max_len); + rb_warning("password must not be longer than %d bytes", max_len); continue; } memcpy(buf, RSTRING_PTR(pass), len); break; } - return len; -} - -/* - * Verify callback - */ -int ossl_store_ctx_ex_verify_cb_idx; -int ossl_store_ex_verify_cb_idx; - -struct ossl_verify_cb_args { - VALUE proc; - VALUE preverify_ok; - VALUE store_ctx; -}; - -static VALUE -ossl_call_verify_cb_proc(struct ossl_verify_cb_args *args) -{ - return rb_funcall(args->proc, rb_intern("call"), 2, - args->preverify_ok, args->store_ctx); -} - -int -ossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx) -{ - VALUE rctx, ret; - struct ossl_verify_cb_args args; - int state; - - if (NIL_P(proc)) - return ok; - - ret = Qfalse; - rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new, (VALUE)ctx, &state); - if (state) { - rb_set_errinfo(Qnil); - rb_warn("StoreContext initialization failure"); - } - else { - args.proc = proc; - args.preverify_ok = ok ? Qtrue : Qfalse; - args.store_ctx = rctx; - ret = rb_protect((VALUE(*)(VALUE))ossl_call_verify_cb_proc, (VALUE)&args, &state); - if (state) { - rb_set_errinfo(Qnil); - rb_warn("exception in verify_callback is ignored"); - } - ossl_x509stctx_clear_ptr(rctx); - } - if (ret == Qtrue) { - X509_STORE_CTX_set_error(ctx, X509_V_OK); - ok = 1; - } - else { - if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) - X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); - ok = 0; - } - - return ok; + return (int)len; } /* @@ -355,27 +297,32 @@ ossl_raise(VALUE exc, const char *fmt, ...) rb_exc_raise(err); } -VALUE -ossl_exc_new(VALUE exc, const char *fmt, ...) -{ - va_list args; - VALUE err; - va_start(args, fmt); - err = ossl_make_error(exc, fmt, args); - va_end(args); - return err; -} - void ossl_clear_error(void) { if (dOSSL == Qtrue) { - long e; - while ((e = ERR_get_error())) { - rb_warn("error on stack: %s", ERR_error_string(e, NULL)); + unsigned long e; + const char *file, *data, *errstr; + int line, flags; + + while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) { + errstr = ERR_error_string(e, NULL); + if (!errstr) + errstr = "(null)"; + + if (flags & ERR_TXT_STRING) { + if (!data) + data = "(null)"; + rb_warn("error on stack: %s (%s)", errstr, data); + } + else { + rb_warn("error on stack: %s", errstr); + } } } - ERR_clear_error(); + else { + ERR_clear_error(); + } } /* @@ -1151,14 +1098,6 @@ Init_openssl(void) rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1); rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0); - /* - * Verify callback Proc index for ext-data - */ - if ((ossl_store_ctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"ossl_store_ctx_ex_verify_cb_idx", 0, 0, 0)) < 0) - ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); - if ((ossl_store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)"ossl_store_ex_verify_cb_idx", 0, 0, 0)) < 0) - ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index"); - /* * Get ID of to_der */ diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index 864d068342..78eddd09b4 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -12,37 +12,12 @@ #include RUBY_EXTCONF_H -#if 0 - mOSSL = rb_define_module("OpenSSL"); - mX509 = rb_define_module_under(mOSSL, "X509"); -#endif - -/* -* OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it! -*/ -#if defined(RFILE) /*&& !defined(OSSL_DEBUG)*/ -# undef RFILE -#endif +#include +#include #include #include #include - #include - -#ifdef HAVE_ASSERT_H -# include -#else -# define assert(condition) -#endif - -#if defined(_WIN32) && !defined(LIBRESSL_VERSION_NUMBER) -# include -# if !defined(OPENSSL_SYS_WIN32) -# define OPENSSL_SYS_WIN32 1 -# endif -# include -#endif -#include #include #include #include @@ -53,9 +28,7 @@ #include #include #include -#if !defined(_WIN32) -# include -#endif +#include #if !defined(OPENSSL_NO_ENGINE) # include #endif @@ -144,18 +117,9 @@ int ossl_pem_passwd_cb(char *, int, int, void *); */ #define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error()) NORETURN(void ossl_raise(VALUE, const char *, ...)); -VALUE ossl_exc_new(VALUE, const char *, ...); /* Clear OpenSSL error queue. If dOSSL is set, rb_warn() them. */ void ossl_clear_error(void); -/* - * Verify callback - */ -extern int ossl_store_ctx_ex_verify_cb_idx; -extern int ossl_store_ex_verify_cb_idx; - -int ossl_verify_cb_call(VALUE, int, X509_STORE_CTX *); - /* * String to DER String */ diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index 85b1f02e62..af8ae2a68d 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -9,15 +9,6 @@ */ #include "ossl.h" -#if defined(HAVE_SYS_TIME_H) -# include -#elif !defined(NT) && !defined(_WIN32) -struct timeval { - long tv_sec; /* seconds */ - long tv_usec; /* and microseconds */ -}; -#endif - static VALUE join_der(VALUE enumerable); static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, int yield, long *num_read); @@ -110,16 +101,11 @@ asn1str_to_str(const ASN1_STRING *str) /* * ASN1_INTEGER conversions - * TODO: Make a decision what's the right way to do this. */ -#define DO_IT_VIA_RUBY 0 VALUE asn1integer_to_num(const ASN1_INTEGER *ai) { BIGNUM *bn; -#if DO_IT_VIA_RUBY - char *txt; -#endif VALUE num; if (!ai) { @@ -133,43 +119,12 @@ asn1integer_to_num(const ASN1_INTEGER *ai) if (!bn) ossl_raise(eOSSLError, NULL); -#if DO_IT_VIA_RUBY - if (!(txt = BN_bn2dec(bn))) { - BN_free(bn); - ossl_raise(eOSSLError, NULL); - } - num = rb_cstr_to_inum(txt, 10, Qtrue); - OPENSSL_free(txt); -#else num = ossl_bn_new(bn); -#endif BN_free(bn); return num; } -#if DO_IT_VIA_RUBY -ASN1_INTEGER * -num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) -{ - BIGNUM *bn = NULL; - - if (RTEST(rb_obj_is_kind_of(obj, cBN))) { - bn = GetBNPtr(obj); - } else { - obj = rb_String(obj); - if (!BN_dec2bn(&bn, StringValueCStr(obj))) { - ossl_raise(eOSSLError, NULL); - } - } - if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) { - BN_free(bn); - ossl_raise(eOSSLError, NULL); - } - BN_free(bn); - return ai; -} -#else ASN1_INTEGER * num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) { @@ -185,7 +140,6 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai) return ai; } -#endif /********/ /* @@ -225,9 +179,10 @@ VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */ VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */ VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */ -static ID sIMPLICIT, sEXPLICIT; -static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE; +static VALUE sym_IMPLICIT, sym_EXPLICIT; +static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE; static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINFINITE_LENGTH, sivUNUSED_BITS; +static ID id_each; /* * Ruby to ASN1 converters @@ -364,13 +319,12 @@ decode_bool(unsigned char* der, long length) { const unsigned char *p = der; - assert(length == 3); - if (*p++ != 1) - ossl_raise(eASN1Error, "not a boolean"); - if (*p++ != 1) - ossl_raise(eASN1Error, "length is not 1"); + if (length != 3) + ossl_raise(eASN1Error, "invalid length for BOOLEAN"); + if (p[0] != 1 || p[1] != 1) + ossl_raise(eASN1Error, "invalid BOOLEAN"); - return *p ? Qtrue : Qfalse; + return p[2] ? Qtrue : Qfalse; } static VALUE @@ -632,17 +586,14 @@ ossl_asn1_default_tag(VALUE obj) VALUE tmp_class, tag; tmp_class = CLASS_OF(obj); - while (tmp_class) { + while (!NIL_P(tmp_class)) { tag = rb_hash_lookup(class_tag_map, tmp_class); - if (tag != Qnil) { - return NUM2INT(tag); - } - tmp_class = rb_class_superclass(tmp_class); + if (tag != Qnil) + return NUM2INT(tag); + tmp_class = rb_class_superclass(tmp_class); } ossl_raise(eASN1Error, "universal tag for %"PRIsVALUE" not found", rb_obj_class(obj)); - - return -1; /* dummy */ } static int @@ -661,59 +612,45 @@ static int ossl_asn1_is_explicit(VALUE obj) { VALUE s; - int ret = -1; s = ossl_asn1_get_tagging(obj); - if(NIL_P(s)) return 0; - else if(SYMBOL_P(s)){ - if (SYM2ID(s) == sIMPLICIT) - ret = 0; - else if (SYM2ID(s) == sEXPLICIT) - ret = 1; - } - if(ret < 0){ + if (NIL_P(s) || s == sym_IMPLICIT) + return 0; + else if (s == sym_EXPLICIT) + return 1; + else ossl_raise(eASN1Error, "invalid tag default"); - } - - return ret; } static int ossl_asn1_tag_class(VALUE obj) { VALUE s; - int ret = -1; s = ossl_asn1_get_tag_class(obj); - if(NIL_P(s)) ret = V_ASN1_UNIVERSAL; - else if(SYMBOL_P(s)){ - if (SYM2ID(s) == sUNIVERSAL) - ret = V_ASN1_UNIVERSAL; - else if (SYM2ID(s) == sAPPLICATION) - ret = V_ASN1_APPLICATION; - else if (SYM2ID(s) == sCONTEXT_SPECIFIC) - ret = V_ASN1_CONTEXT_SPECIFIC; - else if (SYM2ID(s) == sPRIVATE) - ret = V_ASN1_PRIVATE; - } - if(ret < 0){ + if (NIL_P(s) || s == sym_UNIVERSAL) + return V_ASN1_UNIVERSAL; + else if (s == sym_APPLICATION) + return V_ASN1_APPLICATION; + else if (s == sym_CONTEXT_SPECIFIC) + return V_ASN1_CONTEXT_SPECIFIC; + else if (s == sym_PRIVATE) + return V_ASN1_PRIVATE; + else ossl_raise(eASN1Error, "invalid tag class"); - } - - return ret; } static VALUE ossl_asn1_class2sym(int tc) { if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) - return ID2SYM(sPRIVATE); + return sym_PRIVATE; else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) - return ID2SYM(sCONTEXT_SPECIFIC); + return sym_CONTEXT_SPECIFIC; else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) - return ID2SYM(sAPPLICATION); + return sym_APPLICATION; else - return ID2SYM(sUNIVERSAL); + return sym_UNIVERSAL; } /* @@ -737,7 +674,7 @@ ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class) { if(!SYMBOL_P(tag_class)) ossl_raise(eASN1Error, "invalid tag class"); - if((SYM2ID(tag_class) == sUNIVERSAL) && NUM2INT(tag) > 31) + if (tag_class == sym_UNIVERSAL && NUM2INT(tag) > 31) ossl_raise(eASN1Error, "tag number for Universal too large"); ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); @@ -760,7 +697,7 @@ static VALUE join_der(VALUE enumerable) { VALUE str = rb_str_new(0, 0); - rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str); + rb_block_call(enumerable, id_each, 0, 0, join_der_i, str); return str; } @@ -816,7 +753,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, p = *pp; - if(tc == sUNIVERSAL && tag < ossl_asn1_info_size) { + if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) { switch(tag){ case V_ASN1_EOC: value = decode_eoc(p, hlen+length); @@ -858,13 +795,14 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, *pp += hlen + length; *num_read = hlen + length; - if (tc == sUNIVERSAL && tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) { + if (tc == sym_UNIVERSAL && + tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) { VALUE klass = *ossl_asn1_info[tag].klass; VALUE args[4]; args[0] = value; args[1] = INT2NUM(tag); args[2] = Qnil; - args[3] = ID2SYM(tc); + args[3] = tc; asn1data = rb_obj_alloc(klass); ossl_asn1_initialize(4, args, asn1data); if(tag == V_ASN1_BIT_STRING){ @@ -873,7 +811,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag, } else { asn1data = rb_obj_alloc(cASN1Data); - ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), ID2SYM(tc)); + ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc); } return asn1data; @@ -886,28 +824,27 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, { VALUE value, asn1data, ary; int infinite; - long off = *offset; + long available_len, off = *offset; infinite = (j == 0x21); ary = rb_ary_new(); - while (length > 0 || infinite) { + available_len = infinite ? max_len : length; + while (available_len > 0) { long inner_read = 0; - value = ossl_asn1_decode0(pp, max_len, &off, depth + 1, yield, &inner_read); + value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read); *num_read += inner_read; - max_len -= inner_read; + available_len -= inner_read; rb_ary_push(ary, value); - if (length > 0) - length -= inner_read; if (infinite && NUM2INT(ossl_asn1_get_tag(value)) == V_ASN1_EOC && - SYM2ID(ossl_asn1_get_tag_class(value)) == sUNIVERSAL) { + ossl_asn1_get_tag_class(value) == sym_UNIVERSAL) { break; } } - if (tc == sUNIVERSAL) { + if (tc == sym_UNIVERSAL) { VALUE args[4]; int not_sequence_or_set; @@ -929,12 +866,12 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, args[0] = ary; args[1] = INT2NUM(tag); args[2] = Qnil; - args[3] = ID2SYM(tc); + args[3] = tc; ossl_asn1_initialize(4, args, asn1data); } else { asn1data = rb_obj_alloc(cASN1Data); - ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), ID2SYM(tc)); + ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc); } if (infinite) @@ -964,13 +901,13 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, if(j & 0x80) ossl_raise(eASN1Error, NULL); if(len > length) ossl_raise(eASN1Error, "value is too short"); if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) - tag_class = sPRIVATE; + tag_class = sym_PRIVATE; else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) - tag_class = sCONTEXT_SPECIFIC; + tag_class = sym_CONTEXT_SPECIFIC; else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) - tag_class = sAPPLICATION; + tag_class = sym_APPLICATION; else - tag_class = sUNIVERSAL; + tag_class = sym_UNIVERSAL; hlen = p - start; @@ -989,7 +926,7 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, if(j & V_ASN1_CONSTRUCTED) { *pp += hlen; off += hlen; - asn1data = int_ossl_asn1_decode0_cons(pp, length, len, &off, depth, yield, j, tag, tag_class, &inner_read); + asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read); inner_read += hlen; } else { @@ -1162,19 +1099,19 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self) ossl_raise(eASN1Error, "invalid tagging method"); if(NIL_P(tag_class)) { if (NIL_P(tagging)) - tag_class = ID2SYM(sUNIVERSAL); + tag_class = sym_UNIVERSAL; else - tag_class = ID2SYM(sCONTEXT_SPECIFIC); + tag_class = sym_CONTEXT_SPECIFIC; } if(!SYMBOL_P(tag_class)) ossl_raise(eASN1Error, "invalid tag class"); - if(!NIL_P(tagging) && SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31) + if (tagging == sym_IMPLICIT && NUM2INT(tag) > 31) ossl_raise(eASN1Error, "tag number for Universal too large"); } else{ tag = INT2NUM(ossl_asn1_default_tag(self)); tagging = Qnil; - tag_class = ID2SYM(sUNIVERSAL); + tag_class = sym_UNIVERSAL; } ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); @@ -1190,7 +1127,7 @@ ossl_asn1eoc_initialize(VALUE self) { VALUE tag, tagging, tag_class, value; tag = INT2NUM(ossl_asn1_default_tag(self)); tagging = Qnil; - tag_class = ID2SYM(sUNIVERSAL); + tag_class = sym_UNIVERSAL; value = rb_str_new("", 0); ossl_asn1_set_tag(self, tag); ossl_asn1_set_value(self, value); @@ -1264,8 +1201,8 @@ ossl_asn1cons_to_der(VALUE self) if (inf_length == Qtrue) { VALUE ary, example; constructed = 2; - if (CLASS_OF(self) == cASN1Sequence || - CLASS_OF(self) == cASN1Set) { + if (rb_obj_class(self) == cASN1Sequence || + rb_obj_class(self) == cASN1Set) { tag = ossl_asn1_default_tag(self); } else { /* must be a constructive encoding of a primitive value */ @@ -1294,7 +1231,7 @@ ossl_asn1cons_to_der(VALUE self) } } else { - if (CLASS_OF(self) == cASN1Constructive) + if (rb_obj_class(self) == cASN1Constructive) ossl_raise(eASN1Error, "Constructive shall only be used with infinite length"); tag = ossl_asn1_default_tag(self); } @@ -1348,7 +1285,8 @@ ossl_asn1cons_to_der(VALUE self) static VALUE ossl_asn1cons_each(VALUE self) { - rb_ary_each(ossl_asn1_get_value(self)); + rb_funcall(ossl_asn1_get_value(self), id_each, 0); + return self; } @@ -1476,12 +1414,12 @@ Init_ossl_asn1(void) eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); #endif - sUNIVERSAL = rb_intern("UNIVERSAL"); - sCONTEXT_SPECIFIC = rb_intern("CONTEXT_SPECIFIC"); - sAPPLICATION = rb_intern("APPLICATION"); - sPRIVATE = rb_intern("PRIVATE"); - sEXPLICIT = rb_intern("EXPLICIT"); - sIMPLICIT = rb_intern("IMPLICIT"); + sym_UNIVERSAL = ID2SYM(rb_intern_const("UNIVERSAL")); + sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const("CONTEXT_SPECIFIC")); + sym_APPLICATION = ID2SYM(rb_intern_const("APPLICATION")); + sym_PRIVATE = ID2SYM(rb_intern_const("PRIVATE")); + sym_EXPLICIT = ID2SYM(rb_intern_const("EXPLICIT")); + sym_IMPLICIT = ID2SYM(rb_intern_const("IMPLICIT")); sivVALUE = rb_intern("@value"); sivTAG = rb_intern("@tag"); @@ -1989,4 +1927,6 @@ do{\ rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING)); rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING)); rb_global_variable(&class_tag_map); + + id_each = rb_intern_const("each"); } diff --git a/ext/openssl/ossl_bio.c b/ext/openssl/ossl_bio.c index feaf229604..1609b097c0 100644 --- a/ext/openssl/ossl_bio.c +++ b/ext/openssl/ossl_bio.c @@ -8,9 +8,6 @@ * (See the file 'LICENCE'.) */ #include "ossl.h" -#ifdef HAVE_UNISTD_H -#include -#endif BIO * ossl_obj2bio(VALUE obj) diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index 19a868c334..eaf62543a1 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -380,7 +380,7 @@ BIGNUM_BOOL1(is_odd) BIGNUM *bn, *result; \ VALUE obj; \ GetBN(self, bn); \ - obj = NewBN(CLASS_OF(self)); \ + obj = NewBN(rb_obj_class(self)); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ @@ -406,7 +406,7 @@ BIGNUM_1c(sqr) BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ VALUE obj; \ GetBN(self, bn1); \ - obj = NewBN(CLASS_OF(self)); \ + obj = NewBN(rb_obj_class(self)); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ @@ -439,7 +439,7 @@ BIGNUM_2(sub) BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \ VALUE obj; \ GetBN(self, bn1); \ - obj = NewBN(CLASS_OF(self)); \ + obj = NewBN(rb_obj_class(self)); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ @@ -504,12 +504,13 @@ static VALUE ossl_bn_div(VALUE self, VALUE other) { BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2; - VALUE obj1, obj2; + VALUE klass, obj1, obj2; GetBN(self, bn1); - obj1 = NewBN(CLASS_OF(self)); - obj2 = NewBN(CLASS_OF(self)); + klass = rb_obj_class(self); + obj1 = NewBN(klass); + obj2 = NewBN(klass); if (!(r1 = BN_new())) { ossl_raise(eBNError, NULL); } @@ -536,7 +537,7 @@ ossl_bn_div(VALUE self, VALUE other) BIGNUM *bn3 = GetBNPtr(other2), *result; \ VALUE obj; \ GetBN(self, bn1); \ - obj = NewBN(CLASS_OF(self)); \ + obj = NewBN(rb_obj_class(self)); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ @@ -639,7 +640,7 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit) VALUE obj; \ b = NUM2INT(bits); \ GetBN(self, bn); \ - obj = NewBN(CLASS_OF(self)); \ + obj = NewBN(rb_obj_class(self)); \ if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c index 57bc3cfa08..73b667b2c3 100644 --- a/ext/openssl/ossl_cipher.c +++ b/ext/openssl/ossl_cipher.c @@ -36,7 +36,7 @@ */ VALUE cCipher; VALUE eCipherError; -static ID id_auth_tag_len; +static ID id_auth_tag_len, id_key_set; static VALUE ossl_cipher_alloc(VALUE klass); static void ossl_cipher_free(void *ptr); @@ -118,7 +118,6 @@ ossl_cipher_initialize(VALUE self, VALUE str) EVP_CIPHER_CTX *ctx; const EVP_CIPHER *cipher; char *name; - unsigned char dummy_key[EVP_MAX_KEY_LENGTH] = { 0 }; name = StringValueCStr(str); GetCipherInit(self, ctx); @@ -129,16 +128,7 @@ ossl_cipher_initialize(VALUE self, VALUE str) if (!(cipher = EVP_get_cipherbyname(name))) { ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str); } - /* - * EVP_CipherInit_ex() allows to specify NULL to key and IV, however some - * ciphers don't handle well (OpenSSL's bug). [Bug #2768] - * - * The EVP which has EVP_CIPH_RAND_KEY flag (such as DES3) allows - * uninitialized key, but other EVPs (such as AES) does not allow it. - * Calling EVP_CipherUpdate() without initializing key causes SEGV so we - * set the data filled with "\0" as the key by default. - */ - if (EVP_CipherInit_ex(ctx, cipher, NULL, dummy_key, NULL, -1) != 1) + if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1) ossl_raise(eCipherError, NULL); return self; @@ -251,6 +241,9 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode) ossl_raise(eCipherError, NULL); } + if (p_key) + rb_ivar_set(self, id_key_set, Qtrue); + return self; } @@ -337,6 +330,8 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self) OPENSSL_cleanse(key, sizeof key); OPENSSL_cleanse(iv, sizeof iv); + rb_ivar_set(self, id_key_set, Qtrue); + return Qnil; } @@ -387,6 +382,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &data, &str); + if (!RTEST(rb_attr_get(self, id_key_set))) + ossl_raise(eCipherError, "key not set"); + StringValue(data); in = (unsigned char *)RSTRING_PTR(data); if ((in_len = RSTRING_LEN(data)) == 0) @@ -488,6 +486,8 @@ ossl_cipher_set_key(VALUE self, VALUE key) if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1) ossl_raise(eCipherError, NULL); + rb_ivar_set(self, id_key_set, Qtrue); + return key; } @@ -502,9 +502,6 @@ ossl_cipher_set_key(VALUE self, VALUE key) * Cipher#random_iv to create a secure random IV. * * Only call this method after calling Cipher#encrypt or Cipher#decrypt. - * - * If not explicitly set, the OpenSSL default of an all-zeroes ("\\0") IV is - * used. */ static VALUE ossl_cipher_set_iv(VALUE self, VALUE iv) @@ -530,6 +527,27 @@ ossl_cipher_set_iv(VALUE self, VALUE iv) return iv; } +/* + * call-seq: + * cipher.authenticated? -> true | false + * + * Indicated whether this Cipher instance uses an Authenticated Encryption + * mode. + */ +static VALUE +ossl_cipher_is_authenticated(VALUE self) +{ + EVP_CIPHER_CTX *ctx; + + GetCipher(self, ctx); + +#if defined(HAVE_AUTHENTICATED_ENCRYPTION) + return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse; +#else + return Qfalse; +#endif +} + #ifdef HAVE_AUTHENTICATED_ENCRYPTION /* * call-seq: @@ -675,23 +693,6 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen) return vlen; } -/* - * call-seq: - * cipher.authenticated? -> boolean - * - * Indicated whether this Cipher instance uses an Authenticated Encryption - * mode. - */ -static VALUE -ossl_cipher_is_authenticated(VALUE self) -{ - EVP_CIPHER_CTX *ctx; - - GetCipher(self, ctx); - - return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse; -} - /* * call-seq: * cipher.iv_len = integer -> integer @@ -726,7 +727,6 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length) #define ossl_cipher_get_auth_tag rb_f_notimplement #define ossl_cipher_set_auth_tag rb_f_notimplement #define ossl_cipher_set_auth_tag_len rb_f_notimplement -#define ossl_cipher_is_authenticated rb_f_notimplement #define ossl_cipher_set_iv_length rb_f_notimplement #endif @@ -939,12 +939,10 @@ Init_ossl_cipher(void) * you absolutely need it * * Because of this, you will end up with a mode that explicitly requires - * an IV in any case. Note that for backwards compatibility reasons, - * setting an IV is not explicitly mandated by the Cipher API. If not - * set, OpenSSL itself defaults to an all-zeroes IV ("\\0", not the - * character). Although the IV can be seen as public information, i.e. - * it may be transmitted in public once generated, it should still stay - * unpredictable to prevent certain kinds of attacks. Therefore, ideally + * an IV in any case. Although the IV can be seen as public information, + * i.e. it may be transmitted in public once generated, it should still + * stay unpredictable to prevent certain kinds of attacks. Therefore, + * ideally * * Always create a secure random IV for every encryption of your * Cipher @@ -1082,4 +1080,5 @@ Init_ossl_cipher(void) rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1); id_auth_tag_len = rb_intern_const("auth_tag_len"); + id_key_set = rb_intern_const("key_set"); } diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c index 44d961833d..fdafda0074 100644 --- a/ext/openssl/ossl_digest.c +++ b/ext/openssl/ossl_digest.c @@ -80,10 +80,13 @@ ossl_digest_new(const EVP_MD *md) EVP_MD_CTX *ctx; ret = ossl_digest_alloc(cDigest); - GetDigest(ret, ctx); - if (EVP_DigestInit_ex(ctx, md, NULL) != 1) { - ossl_raise(eDigestError, "Digest initialization failed."); - } + ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(eDigestError, "EVP_MD_CTX_new"); + RTYPEDDATA_DATA(ret) = ctx; + + if (!EVP_DigestInit_ex(ctx, md, NULL)) + ossl_raise(eDigestError, "Digest initialization failed"); return ret; } @@ -94,13 +97,7 @@ ossl_digest_new(const EVP_MD *md) static VALUE ossl_digest_alloc(VALUE klass) { - VALUE obj = TypedData_Wrap_Struct(klass, &ossl_digest_type, 0); - EVP_MD_CTX *ctx = EVP_MD_CTX_create(); - if (ctx == NULL) - ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed"); - RTYPEDDATA_DATA(obj) = ctx; - - return obj; + return TypedData_Wrap_Struct(klass, &ossl_digest_type, 0); } VALUE ossl_digest_update(VALUE, VALUE); @@ -133,11 +130,16 @@ ossl_digest_initialize(int argc, VALUE *argv, VALUE self) md = GetDigestPtr(type); if (!NIL_P(data)) StringValue(data); - GetDigest(self, ctx); - if (EVP_DigestInit_ex(ctx, md, NULL) != 1) { - ossl_raise(eDigestError, "Digest initialization failed."); + TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx); + if (!ctx) { + RTYPEDDATA_DATA(self) = ctx = EVP_MD_CTX_new(); + if (!ctx) + ossl_raise(eDigestError, "EVP_MD_CTX_new"); } + if (!EVP_DigestInit_ex(ctx, md, NULL)) + ossl_raise(eDigestError, "Digest initialization failed"); + if (!NIL_P(data)) return ossl_digest_update(self, data); return self; } @@ -150,7 +152,12 @@ ossl_digest_copy(VALUE self, VALUE other) rb_check_frozen(self); if (self == other) return self; - GetDigest(self, ctx1); + TypedData_Get_Struct(self, EVP_MD_CTX, &ossl_digest_type, ctx1); + if (!ctx1) { + RTYPEDDATA_DATA(self) = ctx1 = EVP_MD_CTX_new(); + if (!ctx1) + ossl_raise(eDigestError, "EVP_MD_CTX_new"); + } SafeGetDigest(other, ctx2); if (!EVP_MD_CTX_copy(ctx1, ctx2)) { diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c index f4863b36a4..e73bfb30f5 100644 --- a/ext/openssl/ossl_engine.c +++ b/ext/openssl/ossl_engine.c @@ -227,21 +227,6 @@ ossl_engine_s_by_id(VALUE klass, VALUE id) return obj; } -static VALUE -ossl_engine_s_alloc(VALUE klass) -{ - ENGINE *e; - VALUE obj; - - obj = NewEngine(klass); - if (!(e = ENGINE_new())) { - ossl_raise(eEngineError, NULL); - } - SetEngine(obj, e); - - return obj; -} - /* Document-method: OpenSSL::Engine#id * * Get the id for this engine @@ -537,13 +522,11 @@ Init_ossl_engine(void) 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_undef_alloc_func(cEngine); 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_undef_method(cEngine, "initialize_copy"); rb_define_method(cEngine, "id", ossl_engine_get_id, 0); rb_define_method(cEngine, "name", ossl_engine_get_name, 0); diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c index 2f7845b685..98f6552ec7 100644 --- a/ext/openssl/ossl_ns_spki.c +++ b/ext/openssl/ossl_ns_spki.c @@ -159,8 +159,6 @@ ossl_spki_print(VALUE self) { NETSCAPE_SPKI *spki; BIO *out; - BUF_MEM *buf; - VALUE str; GetSPKI(self, spki); if (!(out = BIO_new(BIO_s_mem()))) { @@ -170,11 +168,8 @@ ossl_spki_print(VALUE self) BIO_free(out); ossl_raise(eSPKIError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + return ossl_membio2str(out); } /* diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index fd58b48be8..4040355f99 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -795,7 +795,7 @@ ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self) BIO_free(in); sk_X509_pop_free(x509s, X509_free); if (ok < 0) ossl_raise(ePKCS7Error, "PKCS7_verify"); - msg = ERR_reason_error_string(ERR_get_error()); + msg = ERR_reason_error_string(ERR_peek_error()); ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil); ossl_clear_error(); data = ossl_membio2str(out); diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 3c7c5e1781..9e6c615781 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -70,12 +70,12 @@ const rb_data_type_t ossl_evp_pkey_type = { 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; -VALUE -ossl_pkey_new(EVP_PKEY *pkey) +static VALUE +pkey_new0(EVP_PKEY *pkey) { - if (!pkey) { - ossl_raise(ePKeyError, "Cannot make new key from NULL."); - } + if (!pkey) + ossl_raise(ePKeyError, "cannot make new key from NULL"); + switch (EVP_PKEY_base_id(pkey)) { #if !defined(OPENSSL_NO_RSA) case EVP_PKEY_RSA: @@ -96,29 +96,21 @@ ossl_pkey_new(EVP_PKEY *pkey) default: ossl_raise(ePKeyError, "unsupported key type"); } - - UNREACHABLE; } VALUE -ossl_pkey_new_from_file(VALUE filename) +ossl_pkey_new(EVP_PKEY *pkey) { - FILE *fp; - EVP_PKEY *pkey; - - rb_check_safe_obj(filename); - if (!(fp = fopen(StringValueCStr(filename), "r"))) { - ossl_raise(ePKeyError, "%s", strerror(errno)); - } - rb_fd_fix_cloexec(fileno(fp)); + VALUE obj; + int status; - pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL); - fclose(fp); - if (!pkey) { - ossl_raise(ePKeyError, NULL); + obj = rb_protect((VALUE (*)(VALUE))pkey_new0, (VALUE)pkey, &status); + if (status) { + EVP_PKEY_free(pkey); + rb_jump_tag(status); } - return ossl_pkey_new(pkey); + return obj; } /* @@ -166,6 +158,45 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self) return ossl_pkey_new(pkey); } +static void +pkey_check_public_key(EVP_PKEY *pkey) +{ + void *ptr; + const BIGNUM *n, *e, *pubkey; + + if (EVP_PKEY_missing_parameters(pkey)) + ossl_raise(ePKeyError, "parameters missing"); + + ptr = EVP_PKEY_get0(pkey); + switch (EVP_PKEY_base_id(pkey)) { + case EVP_PKEY_RSA: + RSA_get0_key(ptr, &n, &e, NULL); + if (n && e) + return; + break; + case EVP_PKEY_DSA: + DSA_get0_key(ptr, &pubkey, NULL); + if (pubkey) + return; + break; + case EVP_PKEY_DH: + DH_get0_key(ptr, &pubkey, NULL); + if (pubkey) + return; + break; +#if !defined(OPENSSL_NO_EC) + case EVP_PKEY_EC: + if (EC_KEY_get0_public_key(ptr)) + return; + break; +#endif + default: + /* unsupported type; assuming ok */ + return; + } + ossl_raise(ePKeyError, "public key missing"); +} + EVP_PKEY * GetPKeyPtr(VALUE obj) { @@ -264,18 +295,23 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data) pkey = GetPrivPKeyPtr(self); md = GetDigestPtr(digest); StringValue(data); - str = rb_str_new(0, EVP_PKEY_size(pkey)+16); + str = rb_str_new(0, EVP_PKEY_size(pkey)); ctx = EVP_MD_CTX_new(); if (!ctx) ossl_raise(ePKeyError, "EVP_MD_CTX_new"); - EVP_SignInit(ctx, md); - EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); + if (!EVP_SignInit_ex(ctx, md, NULL)) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_SignInit_ex"); + } + if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_SignUpdate"); + } result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey); EVP_MD_CTX_free(ctx); if (!result) - ossl_raise(ePKeyError, NULL); - assert((long)buf_len <= RSTRING_LEN(str)); + ossl_raise(ePKeyError, "EVP_SignFinal"); rb_str_set_len(str, buf_len); return str; @@ -308,19 +344,27 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) EVP_PKEY *pkey; const EVP_MD *md; EVP_MD_CTX *ctx; - int result; + int siglen, result; GetPKey(self, pkey); + pkey_check_public_key(pkey); md = GetDigestPtr(digest); StringValue(sig); + siglen = RSTRING_LENINT(sig); StringValue(data); ctx = EVP_MD_CTX_new(); if (!ctx) ossl_raise(ePKeyError, "EVP_MD_CTX_new"); - EVP_VerifyInit(ctx, md); - EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)); - result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey); + if (!EVP_VerifyInit_ex(ctx, md, NULL)) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_VerifyInit_ex"); + } + if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) { + EVP_MD_CTX_free(ctx); + ossl_raise(ePKeyError, "EVP_VerifyUpdate"); + } + result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey); EVP_MD_CTX_free(ctx); switch (result) { case 0: @@ -329,9 +373,8 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data) case 1: return Qtrue; default: - ossl_raise(ePKeyError, NULL); + ossl_raise(ePKeyError, "EVP_VerifyFinal"); } - return Qnil; /* dummy */ } /* diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h index 218f2ebbae..e3b723cd68 100644 --- a/ext/openssl/ossl_pkey.h +++ b/ext/openssl/ossl_pkey.h @@ -48,7 +48,6 @@ int ossl_generate_cb_2(int p, int n, BN_GENCB *cb); void ossl_generate_cb_stop(void *ptr); VALUE ossl_pkey_new(EVP_PKEY *); -VALUE ossl_pkey_new_from_file(VALUE); EVP_PKEY *GetPKeyPtr(VALUE); EVP_PKEY *DupPKeyPtr(VALUE); EVP_PKEY *GetPrivPKeyPtr(VALUE); diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c index 938efe1abc..dd85b7b9b6 100644 --- a/ext/openssl/ossl_pkey_dh.c +++ b/ext/openssl/ossl_pkey_dh.c @@ -460,7 +460,7 @@ ossl_dh_to_public_key(VALUE self) GetDH(self, orig_dh); dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */ - obj = dh_instance(CLASS_OF(self), dh); + obj = dh_instance(rb_obj_class(self), dh); if (obj == Qfalse) { DH_free(dh); ossl_raise(eDHError, NULL); diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c index 3821cd813c..85085419c6 100644 --- a/ext/openssl/ossl_pkey_dsa.c +++ b/ext/openssl/ossl_pkey_dsa.c @@ -491,7 +491,7 @@ ossl_dsa_to_public_key(VALUE self) (i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa)) dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey)); #undef DSAPublicKey_dup - obj = dsa_instance(CLASS_OF(self), dsa); + obj = dsa_instance(rb_obj_class(self), dsa); if (obj == Qfalse) { DSA_free(dsa); ossl_raise(eDSAError, NULL); @@ -499,8 +499,6 @@ ossl_dsa_to_public_key(VALUE self) return obj; } -#define ossl_dsa_buf_size(dsa) (DSA_size(dsa) + 16) - /* * call-seq: * dsa.syssign(string) -> aString @@ -535,7 +533,7 @@ ossl_dsa_sign(VALUE self, VALUE data) if (!DSA_PRIVATE(self, dsa)) ossl_raise(eDSAError, "Private DSA key needed!"); StringValue(data); - str = rb_str_new(0, ossl_dsa_buf_size(dsa)); + str = rb_str_new(0, DSA_size(dsa)); if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *)RSTRING_PTR(str), &buf_len, dsa)) { /* type is ignored (0) */ diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index 20a7222384..5191c0f457 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -643,11 +643,10 @@ static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data) if (EC_KEY_get0_private_key(ec) == NULL) ossl_raise(eECError, "Private EC key needed!"); - str = rb_str_new(0, ECDSA_size(ec) + 16); + str = rb_str_new(0, ECDSA_size(ec)); if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1) - ossl_raise(eECError, "ECDSA_sign"); - - rb_str_resize(str, buf_len); + ossl_raise(eECError, "ECDSA_sign"); + rb_str_set_len(str, buf_len); return str; } @@ -1106,6 +1105,22 @@ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) return ID2SYM(ret); } +static point_conversion_form_t +parse_point_conversion_form_symbol(VALUE sym) +{ + ID id = SYM2ID(sym); + + if (id == ID_uncompressed) + return POINT_CONVERSION_UNCOMPRESSED; + else if (id == ID_compressed) + return POINT_CONVERSION_COMPRESSED; + else if (id == ID_hybrid) + return POINT_CONVERSION_HYBRID; + else + ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE + " (expected :compressed, :uncompressed, or :hybrid)", sym); +} + /* * call-seq: * group.point_conversion_form = form @@ -1125,23 +1140,14 @@ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self) * * See the OpenSSL documentation for EC_GROUP_set_point_conversion_form() */ -static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v) +static VALUE +ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v) { - EC_GROUP *group = NULL; + EC_GROUP *group; point_conversion_form_t form; - ID form_id = SYM2ID(form_v); GetECGroup(self, group); - - if (form_id == ID_uncompressed) { - form = POINT_CONVERSION_UNCOMPRESSED; - } else if (form_id == ID_compressed) { - form = POINT_CONVERSION_COMPRESSED; - } else if (form_id == ID_hybrid) { - form = POINT_CONVERSION_HYBRID; - } else { - ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid"); - } + form = parse_point_conversion_form_symbol(form_v); EC_GROUP_set_point_conversion_form(group, form); @@ -1549,22 +1555,30 @@ static VALUE ossl_ec_point_set_to_infinity(VALUE self) /* * call-seq: - * point.to_bn => OpenSSL::BN + * point.to_bn(conversion_form = nil) => OpenSSL::BN + * + * Convert the EC point into an octet string and store in an OpenSSL::BN. If + * +conversion_form+ is given, the point data is converted using the specified + * form. If not given, the default form set in the EC::Group object is used. * - * See the OpenSSL documentation for EC_POINT_point2bn() + * See also EC::Point#point_conversion_form=. */ -static VALUE ossl_ec_point_to_bn(VALUE self) +static VALUE +ossl_ec_point_to_bn(int argc, VALUE *argv, VALUE self) { EC_POINT *point; - VALUE bn_obj; + VALUE form_obj, bn_obj; const EC_GROUP *group; point_conversion_form_t form; BIGNUM *bn; GetECPoint(self, point); GetECPointGroup(self, group); - - form = EC_GROUP_get_point_conversion_form(group); + rb_scan_args(argc, argv, "01", &form_obj); + if (NIL_P(form_obj)) + form = EC_GROUP_get_point_conversion_form(group); + else + form = parse_point_conversion_form_symbol(form_obj); bn_obj = rb_obj_alloc(cBN); bn = GetBNPtr(bn_obj); @@ -1793,7 +1807,7 @@ void Init_ossl_ec(void) rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0); /* all the other methods */ - rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0); + rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, -1); rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1); id_i_group = rb_intern("@group"); diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c index 17a7494992..cea228d6d8 100644 --- a/ext/openssl/ossl_pkey_rsa.c +++ b/ext/openssl/ossl_pkey_rsa.c @@ -404,8 +404,6 @@ ossl_rsa_to_der(VALUE self) return str; } -#define ossl_rsa_buf_size(rsa) (RSA_size(rsa)+16) - /* * call-seq: * rsa.public_encrypt(string) => String @@ -429,7 +427,7 @@ ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); - str = rb_str_new(0, ossl_rsa_buf_size(rsa)); + str = rb_str_new(0, RSA_size(rsa)); buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), (unsigned char *)RSTRING_PTR(str), rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); @@ -461,7 +459,7 @@ ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); - str = rb_str_new(0, ossl_rsa_buf_size(rsa)); + str = rb_str_new(0, RSA_size(rsa)); buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), (unsigned char *)RSTRING_PTR(str), rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); @@ -495,7 +493,7 @@ ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); - str = rb_str_new(0, ossl_rsa_buf_size(rsa)); + str = rb_str_new(0, RSA_size(rsa)); buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), (unsigned char *)RSTRING_PTR(str), rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); @@ -529,7 +527,7 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self) rb_scan_args(argc, argv, "11", &buffer, &padding); pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding); StringValue(buffer); - str = rb_str_new(0, ossl_rsa_buf_size(rsa)); + str = rb_str_new(0, RSA_size(rsa)); buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer), (unsigned char *)RSTRING_PTR(str), rsa, pad); if (buf_len < 0) ossl_raise(eRSAError, NULL); @@ -620,7 +618,7 @@ ossl_rsa_to_public_key(VALUE self) GetPKeyRSA(self, pkey); /* err check performed by rsa_instance */ rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey)); - obj = rsa_instance(CLASS_OF(self), rsa); + obj = rsa_instance(rb_obj_class(self), rsa); if (obj == Qfalse) { RSA_free(rsa); ossl_raise(eRSAError, NULL); diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 861f820dbd..609ffdc643 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -11,10 +11,6 @@ */ #include "ossl.h" -#if defined(HAVE_UNISTD_H) -# include /* for read(), and write() */ -#endif - #define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0])) #ifdef _WIN32 @@ -36,7 +32,7 @@ VALUE cSSLSocket; static VALUE eSSLErrorWaitReadable; static VALUE eSSLErrorWaitWritable; -static ID ID_callback_state; +static ID ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback; static VALUE sym_exception, sym_wait_readable, sym_wait_writable; static ID id_i_cert_store, id_i_ca_file, id_i_ca_path, id_i_verify_mode, @@ -223,69 +219,90 @@ ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) return 1; } -#if !defined(OPENSSL_NO_DH) -static VALUE -ossl_call_tmp_dh_callback(VALUE args) +#if !defined(OPENSSL_NO_DH) || \ + !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK) +struct tmp_dh_callback_args { + VALUE ssl_obj; + ID id; + int type; + int is_export; + int keylength; +}; + +static EVP_PKEY * +ossl_call_tmp_dh_callback(struct tmp_dh_callback_args *args) { VALUE cb, dh; EVP_PKEY *pkey; - cb = rb_funcall(rb_ary_entry(args, 0), rb_intern("tmp_dh_callback"), 0); - - if (NIL_P(cb)) return Qfalse; - dh = rb_apply(cb, rb_intern("call"), args); + cb = rb_funcall(args->ssl_obj, args->id, 0); + if (NIL_P(cb)) + return NULL; + dh = rb_funcall(cb, rb_intern("call"), 3, + args->ssl_obj, INT2NUM(args->is_export), INT2NUM(args->keylength)); pkey = GetPKeyPtr(dh); - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) return Qfalse; + if (EVP_PKEY_base_id(pkey) != args->type) + return NULL; - return dh; + return pkey; } +#endif -static DH* +#if !defined(OPENSSL_NO_DH) +static DH * ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength) { - VALUE args, dh, rb_ssl; + VALUE rb_ssl; + EVP_PKEY *pkey; + struct tmp_dh_callback_args args; + int state; rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + args.ssl_obj = rb_ssl; + args.id = id_tmp_dh_callback; + args.is_export = is_export; + args.keylength = keylength; + args.type = EVP_PKEY_DH; + + pkey = (EVP_PKEY *)rb_protect((VALUE (*)(VALUE))ossl_call_tmp_dh_callback, + (VALUE)&args, &state); + if (state) { + rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state)); + return NULL; + } + if (!pkey) + return NULL; - args = rb_ary_new_from_args(3, rb_ssl, INT2NUM(is_export), INT2NUM(keylength)); - - dh = rb_protect(ossl_call_tmp_dh_callback, args, NULL); - if (!RTEST(dh)) return NULL; - - return EVP_PKEY_get0_DH(GetPKeyPtr(dh)); + return EVP_PKEY_get0_DH(pkey); } #endif /* OPENSSL_NO_DH */ #if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK) -static VALUE -ossl_call_tmp_ecdh_callback(VALUE args) -{ - VALUE cb, ecdh; - EVP_PKEY *pkey; - - cb = rb_funcall(rb_ary_entry(args, 0), rb_intern("tmp_ecdh_callback"), 0); - - if (NIL_P(cb)) return Qfalse; - ecdh = rb_apply(cb, rb_intern("call"), args); - pkey = GetPKeyPtr(ecdh); - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) return Qfalse; - - return ecdh; -} - -static EC_KEY* +static EC_KEY * ossl_tmp_ecdh_callback(SSL *ssl, int is_export, int keylength) { - VALUE args, ecdh, rb_ssl; + VALUE rb_ssl; + EVP_PKEY *pkey; + struct tmp_dh_callback_args args; + int state; rb_ssl = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx); + args.ssl_obj = rb_ssl; + args.id = id_tmp_ecdh_callback; + args.is_export = is_export; + args.keylength = keylength; + args.type = EVP_PKEY_EC; + + pkey = (EVP_PKEY *)rb_protect((VALUE (*)(VALUE))ossl_call_tmp_dh_callback, + (VALUE)&args, &state); + if (state) { + rb_ivar_set(rb_ssl, ID_callback_state, INT2NUM(state)); + return NULL; + } + if (!pkey) + return NULL; - args = rb_ary_new_from_args(3, rb_ssl, INT2NUM(is_export), INT2NUM(keylength)); - - ecdh = rb_protect(ossl_call_tmp_ecdh_callback, args, NULL); - if (!RTEST(ecdh)) return NULL; - - return EVP_PKEY_get0_EC_KEY(GetPKeyPtr(ecdh)); + return EVP_PKEY_get0_EC_KEY(pkey); } #endif @@ -1376,24 +1393,6 @@ ssl_started(SSL *ssl) return SSL_get_fd(ssl) >= 0; } -static void -ossl_ssl_shutdown(SSL *ssl) -{ - int i; - - /* 4 is from SSL_smart_shutdown() of mod_ssl.c (v2.2.19) */ - /* It says max 2x pending + 2x data = 4 */ - for (i = 0; i < 4; ++i) { - /* - * Ignore the case SSL_shutdown returns -1. Empty handshake_func - * must not happen. - */ - if (SSL_shutdown(ssl) != 0) - break; - } - ossl_clear_error(); -} - static void ossl_ssl_free(void *ssl) { @@ -1496,19 +1495,15 @@ ossl_ssl_setup(VALUE self) static void write_would_block(int nonblock) { - if (nonblock) { - VALUE exc = ossl_exc_new(eSSLErrorWaitWritable, "write would block"); - rb_exc_raise(exc); - } + if (nonblock) + ossl_raise(eSSLErrorWaitWritable, "write would block"); } static void read_would_block(int nonblock) { - if (nonblock) { - VALUE exc = ossl_exc_new(eSSLErrorWaitReadable, "read would block"); - rb_exc_raise(exc); - } + if (nonblock) + ossl_raise(eSSLErrorWaitReadable, "read would block"); } static int @@ -1714,11 +1709,21 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: - if(ERR_peek_error() == 0 && nread == 0) { - if (no_exception_p(opts)) { return Qnil; } - rb_eof_error(); + if (!ERR_peek_error()) { + if (errno) + rb_sys_fail(0); + else { + /* + * The underlying BIO returned 0. This is actually a + * protocol error. But unfortunately, not all + * implementations cleanly shutdown the TLS connection + * but just shutdown/close the TCP connection. So report + * EOF for now... + */ + if (no_exception_p(opts)) { return Qnil; } + rb_eof_error(); + } } - rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_read"); } @@ -1871,11 +1876,24 @@ static VALUE ossl_ssl_stop(VALUE self) { SSL *ssl; + int ret; GetSSL(self, ssl); + if (!ssl_started(ssl)) + return Qnil; + ret = SSL_shutdown(ssl); + if (ret == 1) /* Have already received close_notify */ + return Qnil; + if (ret == 0) /* Sent close_notify, but we don't wait for reply */ + return Qnil; - ossl_ssl_shutdown(ssl); - + /* + * XXX: Something happened. Possibly it failed because the underlying socket + * is not writable/readable, since it is in non-blocking mode. We should do + * some proper error handling using SSL_get_error() and maybe retry, but we + * can't block here. Give up for now. + */ + ossl_clear_error(); return Qnil; } @@ -2525,6 +2543,7 @@ Init_ossl_ssl(void) rb_define_method(cSSLContext, "security_level=", ossl_sslctx_set_security_level, 1); rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0); + rb_define_alias(cSSLContext, "freeze", "setup"); /* * No session caching for client or server @@ -2691,6 +2710,9 @@ Init_ossl_ssl(void) sym_wait_readable = ID2SYM(rb_intern("wait_readable")); sym_wait_writable = ID2SYM(rb_intern("wait_writable")); + id_tmp_dh_callback = rb_intern("tmp_dh_callback"); + id_tmp_ecdh_callback = rb_intern("tmp_ecdh_callback"); + #define DefIVarID(name) do \ id_i_##name = rb_intern("@"#name); while (0) diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c index fb7c0fb611..7abb8671f8 100644 --- a/ext/openssl/ossl_ssl_session.c +++ b/ext/openssl/ossl_ssl_session.c @@ -108,11 +108,7 @@ int SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b) if (a_len != b_len) return 1; -#if defined(_WIN32) - return memcmp(a_sid, b_sid, a_len); -#else return CRYPTO_memcmp(a_sid, b_sid, a_len); -#endif } #endif @@ -141,19 +137,18 @@ static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2) * * Returns the time at which the session was established. */ -static VALUE ossl_ssl_session_get_time(VALUE self) +static VALUE +ossl_ssl_session_get_time(VALUE self) { - SSL_SESSION *ctx; - time_t t; - - GetSSLSession(self, ctx); - - t = SSL_SESSION_get_time(ctx); + SSL_SESSION *ctx; + long t; - if (t == 0) - return Qnil; + GetSSLSession(self, ctx); + t = SSL_SESSION_get_time(ctx); + if (t == 0) + return Qnil; - return rb_funcall(rb_cTime, rb_intern("at"), 1, TIMET2NUM(t)); + return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t)); } /* @@ -164,16 +159,16 @@ static VALUE ossl_ssl_session_get_time(VALUE self) * established time. * */ -static VALUE ossl_ssl_session_get_timeout(VALUE self) +static VALUE +ossl_ssl_session_get_timeout(VALUE self) { - SSL_SESSION *ctx; - time_t t; + SSL_SESSION *ctx; + long t; - GetSSLSession(self, ctx); - - t = SSL_SESSION_get_timeout(ctx); + GetSSLSession(self, ctx); + t = SSL_SESSION_get_timeout(ctx); - return TIMET2NUM(t); + return LONG2NUM(t); } /* @@ -270,9 +265,6 @@ static VALUE ossl_ssl_session_to_pem(VALUE self) { SSL_SESSION *ctx; BIO *out; - BUF_MEM *buf; - VALUE str; - int i; GetSSLSession(self, ctx); @@ -280,16 +272,13 @@ static VALUE ossl_ssl_session_to_pem(VALUE self) ossl_raise(eSSLSession, "BIO_s_mem()"); } - if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) { + if (!PEM_write_bio_SSL_SESSION(out, ctx)) { BIO_free(out); ossl_raise(eSSLSession, "SSL_SESSION_print()"); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + return ossl_membio2str(out); } @@ -303,8 +292,6 @@ static VALUE ossl_ssl_session_to_text(VALUE self) { SSL_SESSION *ctx; BIO *out; - BUF_MEM *buf; - VALUE str; GetSSLSession(self, ctx); @@ -317,11 +304,7 @@ static VALUE ossl_ssl_session_to_text(VALUE self) ossl_raise(eSSLSession, "SSL_SESSION_print()"); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - - return str; + return ossl_membio2str(out); } diff --git a/ext/openssl/ossl_x509.h b/ext/openssl/ossl_x509.h index c26da73897..a60f7c3da3 100644 --- a/ext/openssl/ossl_x509.h +++ b/ext/openssl/ossl_x509.h @@ -110,10 +110,13 @@ VALUE ossl_x509store_new(X509_STORE *); X509_STORE *GetX509StorePtr(VALUE); X509_STORE *DupX509StorePtr(VALUE); -VALUE ossl_x509stctx_new(X509_STORE_CTX *); -VALUE ossl_x509stctx_clear_ptr(VALUE); X509_STORE_CTX *GetX509StCtxtPtr(VALUE); - void Init_ossl_x509store(void); +/* + * Calls the verify callback Proc (the first parameter) with given pre-verify + * result and the X509_STORE_CTX. + */ +int ossl_verify_cb_call(VALUE, int, X509_STORE_CTX *); + #endif /* _OSSL_X509_H_ */ diff --git a/ext/openssl/ossl_x509cert.c b/ext/openssl/ossl_x509cert.c index ad1126d465..cecc3ca09a 100644 --- a/ext/openssl/ossl_x509cert.c +++ b/ext/openssl/ossl_x509cert.c @@ -624,7 +624,7 @@ ossl_x509_check_private_key(VALUE self, VALUE key) pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ GetX509(self, x509); if (!X509_check_private_key(x509, pkey)) { - OSSL_Warning("Check private key:%s", OSSL_ErrMsg()); + ossl_clear_error(); return Qfalse; } diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index 0ff5d2f8ea..f9819f5824 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -182,8 +182,6 @@ ossl_x509crl_get_signature_algorithm(VALUE self) X509_CRL *crl; const X509_ALGOR *alg; BIO *out; - BUF_MEM *buf; - VALUE str; GetX509CRL(self, crl); if (!(out = BIO_new(BIO_s_mem()))) { @@ -194,10 +192,8 @@ ossl_x509crl_get_signature_algorithm(VALUE self) BIO_free(out); ossl_raise(eX509CRLError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + + return ossl_membio2str(out); } static VALUE @@ -388,8 +384,6 @@ ossl_x509crl_to_der(VALUE self) { X509_CRL *crl; BIO *out; - BUF_MEM *buf; - VALUE str; GetX509CRL(self, crl); if (!(out = BIO_new(BIO_s_mem()))) { @@ -399,11 +393,8 @@ ossl_x509crl_to_der(VALUE self) BIO_free(out); ossl_raise(eX509CRLError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + return ossl_membio2str(out); } static VALUE @@ -411,8 +402,6 @@ ossl_x509crl_to_pem(VALUE self) { X509_CRL *crl; BIO *out; - BUF_MEM *buf; - VALUE str; GetX509CRL(self, crl); if (!(out = BIO_new(BIO_s_mem()))) { @@ -422,11 +411,8 @@ ossl_x509crl_to_pem(VALUE self) BIO_free(out); ossl_raise(eX509CRLError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + return ossl_membio2str(out); } static VALUE @@ -434,8 +420,6 @@ ossl_x509crl_to_text(VALUE self) { X509_CRL *crl; BIO *out; - BUF_MEM *buf; - VALUE str; GetX509CRL(self, crl); if (!(out = BIO_new(BIO_s_mem()))) { @@ -445,11 +429,8 @@ ossl_x509crl_to_text(VALUE self) BIO_free(out); ossl_raise(eX509CRLError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + return ossl_membio2str(out); } /* diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c index abbdc3b11e..4523e0d71e 100644 --- a/ext/openssl/ossl_x509name.c +++ b/ext/openssl/ossl_x509name.c @@ -372,12 +372,10 @@ ossl_x509name_cmp(VALUE self, VALUE other) static VALUE ossl_x509name_eql(VALUE self, VALUE other) { - int result; - - if(CLASS_OF(other) != cX509Name) return Qfalse; - result = ossl_x509name_cmp0(self, other); + if (!rb_obj_is_kind_of(other, cX509Name)) + return Qfalse; - return (result == 0) ? Qtrue : Qfalse; + return ossl_x509name_cmp0(self, other) ? Qtrue : Qfalse; } /* diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c index d2619971d1..220d2f40d5 100644 --- a/ext/openssl/ossl_x509req.c +++ b/ext/openssl/ossl_x509req.c @@ -160,8 +160,6 @@ ossl_x509req_to_pem(VALUE self) { X509_REQ *req; BIO *out; - BUF_MEM *buf; - VALUE str; GetX509Req(self, req); if (!(out = BIO_new(BIO_s_mem()))) { @@ -171,11 +169,8 @@ ossl_x509req_to_pem(VALUE self) BIO_free(out); ossl_raise(eX509ReqError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + return ossl_membio2str(out); } static VALUE @@ -203,8 +198,6 @@ ossl_x509req_to_text(VALUE self) { X509_REQ *req; BIO *out; - BUF_MEM *buf; - VALUE str; GetX509Req(self, req); if (!(out = BIO_new(BIO_s_mem()))) { @@ -214,11 +207,8 @@ ossl_x509req_to_text(VALUE self) BIO_free(out); ossl_raise(eX509ReqError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + return ossl_membio2str(out); } #if 0 @@ -304,8 +294,6 @@ ossl_x509req_get_signature_algorithm(VALUE self) X509_REQ *req; const X509_ALGOR *alg; BIO *out; - BUF_MEM *buf; - VALUE str; GetX509Req(self, req); @@ -317,10 +305,8 @@ ossl_x509req_get_signature_algorithm(VALUE self) BIO_free(out); ossl_raise(eX509ReqError, NULL); } - BIO_get_mem_ptr(out, &buf); - str = rb_str_new(buf->data, buf->length); - BIO_free(out); - return str; + + return ossl_membio2str(out); } static VALUE diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 75f8238b01..eb81e0d473 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -47,6 +47,65 @@ GetX509Store((obj), (ctx)); \ } while (0) +/* + * Verify callback stuff + */ +static int stctx_ex_verify_cb_idx, store_ex_verify_cb_idx; +static VALUE ossl_x509stctx_new(X509_STORE_CTX *); + +struct ossl_verify_cb_args { + VALUE proc; + VALUE preverify_ok; + VALUE store_ctx; +}; + +static VALUE +call_verify_cb_proc(struct ossl_verify_cb_args *args) +{ + return rb_funcall(args->proc, rb_intern("call"), 2, + args->preverify_ok, args->store_ctx); +} + +int +ossl_verify_cb_call(VALUE proc, int ok, X509_STORE_CTX *ctx) +{ + VALUE rctx, ret; + struct ossl_verify_cb_args args; + int state; + + if (NIL_P(proc)) + return ok; + + ret = Qfalse; + rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new, (VALUE)ctx, &state); + if (state) { + rb_set_errinfo(Qnil); + rb_warn("StoreContext initialization failure"); + } + else { + args.proc = proc; + args.preverify_ok = ok ? Qtrue : Qfalse; + args.store_ctx = rctx; + ret = rb_protect((VALUE(*)(VALUE))call_verify_cb_proc, (VALUE)&args, &state); + if (state) { + rb_set_errinfo(Qnil); + rb_warn("exception in verify_callback is ignored"); + } + RTYPEDDATA_DATA(rctx) = NULL; + } + if (ret == Qtrue) { + X509_STORE_CTX_set_error(ctx, X509_V_OK); + ok = 1; + } + else { + if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); + ok = 0; + } + + return ok; +} + /* * Classes */ @@ -111,9 +170,10 @@ x509store_verify_cb(int ok, X509_STORE_CTX *ctx) { VALUE proc; - proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_store_ctx_ex_verify_cb_idx); + proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx); if (!proc) - proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx), ossl_store_ex_verify_cb_idx); + proc = (VALUE)X509_STORE_get_ex_data(X509_STORE_CTX_get0_store(ctx), + store_ex_verify_cb_idx); if (!proc) return ok; @@ -144,7 +204,7 @@ ossl_x509store_set_vfy_cb(VALUE self, VALUE cb) X509_STORE *store; GetX509Store(self, store); - X509_STORE_set_ex_data(store, ossl_store_ex_verify_cb_idx, (void *)cb); + X509_STORE_set_ex_data(store, store_ex_verify_cb_idx, (void *)cb); rb_iv_set(self, "@verify_callback", cb); return cb; @@ -432,27 +492,6 @@ static const rb_data_type_t ossl_x509stctx_type = { 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; - -VALUE -ossl_x509stctx_new(X509_STORE_CTX *ctx) -{ - VALUE obj; - - obj = NewX509StCtx(cX509StoreContext); - SetX509StCtx(obj, ctx); - - return obj; -} - -VALUE -ossl_x509stctx_clear_ptr(VALUE obj) -{ - OSSL_Check_Kind(obj, cX509StoreContext); - RDATA(obj)->data = NULL; - - return obj; -} - /* * Private functions */ @@ -482,6 +521,17 @@ ossl_x509stctx_alloc(VALUE klass) return obj; } +static VALUE +ossl_x509stctx_new(X509_STORE_CTX *ctx) +{ + VALUE obj; + + obj = NewX509StCtx(cX509StoreContext); + SetX509StCtx(obj, ctx); + + return obj; +} + static VALUE ossl_x509stctx_set_flags(VALUE, VALUE); static VALUE ossl_x509stctx_set_purpose(VALUE, VALUE); static VALUE ossl_x509stctx_set_trust(VALUE, VALUE); @@ -527,7 +577,7 @@ ossl_x509stctx_verify(VALUE self) X509_STORE_CTX *ctx; GetX509StCtx(self, ctx); - X509_STORE_CTX_set_ex_data(ctx, ossl_store_ctx_ex_verify_cb_idx, + X509_STORE_CTX_set_ex_data(ctx, stctx_ex_verify_cb_idx, (void *)rb_iv_get(self, "@verify_callback")); switch (X509_verify_cert(ctx)) { @@ -747,6 +797,14 @@ Init_ossl_x509store(void) mX509 = rb_define_module_under(mOSSL, "X509"); #endif + /* Register ext_data slot for verify callback Proc */ + stctx_ex_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"stctx_ex_verify_cb_idx", 0, 0, 0); + if (stctx_ex_verify_cb_idx < 0) + ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index"); + store_ex_verify_cb_idx = X509_STORE_get_ex_new_index(0, (void *)"store_ex_verify_cb_idx", 0, 0, 0); + if (store_ex_verify_cb_idx < 0) + ossl_raise(eOSSLError, "X509_STORE_get_ex_new_index"); + eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError); /* Document-class: OpenSSL::X509::Store diff --git a/ext/openssl/ruby_missing.h b/ext/openssl/ruby_missing.h index f076b1757d..8dacc8266e 100644 --- a/ext/openssl/ruby_missing.h +++ b/ext/openssl/ruby_missing.h @@ -13,16 +13,7 @@ #define rb_define_copy_func(klass, func) \ rb_define_method((klass), "initialize_copy", (func), 1) - -#ifndef GetReadFile #define FPTR_TO_FD(fptr) ((fptr)->fd) -#else -#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr))) -#endif - -#ifndef HAVE_RB_IO_T -#define rb_io_t OpenFile -#endif #ifndef RB_INTEGER_TYPE_P /* for Ruby 2.3 compatibility */ -- cgit v1.2.3