diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2021-09-28 15:55:12 +0900 |
---|---|---|
committer | usa <usa@garbagecollect.jp> | 2021-11-24 16:45:46 +0900 |
commit | e0b323632f5ea07e2646a2ec0b72f56093348265 (patch) | |
tree | 6baf43a2c48b1de7d98235dc6d37e9a2f8eaf700 /ext | |
parent | 87378782483dd8fdd03ae9d6022979f1f8153416 (diff) |
openssl: import v2.1.3
Bring the local copy of ruby/openssl in sync with the upstream gem
release v2.1.3. The commits happened in the upstream repository can be
found at:
https://github.com/ruby/openssl/compare/v2.1.2...v2.1.3
Note that many of these have already been applied to ruby.git and don't
appear in the file changes of this commit.
Diffstat (limited to 'ext')
-rw-r--r-- | ext/openssl/History.md | 36 | ||||
-rw-r--r-- | ext/openssl/extconf.rb | 43 | ||||
-rw-r--r-- | ext/openssl/openssl.gemspec | 48 | ||||
-rw-r--r-- | ext/openssl/ossl.h | 1 | ||||
-rw-r--r-- | ext/openssl/ossl_bn.c | 34 | ||||
-rw-r--r-- | ext/openssl/ossl_digest.c | 8 | ||||
-rw-r--r-- | ext/openssl/ossl_pkcs7.c | 4 | ||||
-rw-r--r-- | ext/openssl/ossl_pkey_ec.c | 16 | ||||
-rw-r--r-- | ext/openssl/ossl_ssl.c | 119 | ||||
-rw-r--r-- | ext/openssl/ossl_version.h | 2 | ||||
-rw-r--r-- | ext/openssl/ossl_x509.c | 91 | ||||
-rw-r--r-- | ext/openssl/ossl_x509store.c | 59 |
12 files changed, 347 insertions, 114 deletions
diff --git a/ext/openssl/History.md b/ext/openssl/History.md index db5050014e..9e7ee53397 100644 --- a/ext/openssl/History.md +++ b/ext/openssl/History.md @@ -1,3 +1,39 @@ +Version 2.1.3 +============= + +Bug fixes +--------- + +* Fix deprecation warnings on Ruby 3.0. +* Add ".include" directive support in `OpenSSL::Config`. + [[GitHub #216]](https://github.com/ruby/openssl/pull/216) +* Fix handling of IPv6 address SANs. + [[GitHub #185]](https://github.com/ruby/openssl/pull/185) +* Hostname verification failure with `OpenSSL::SSL::SSLContext#verify_hostname=` + sets a proper error code. + [[GitHub #350]](https://github.com/ruby/openssl/pull/350) +* Fix crash with `OpenSSL::BN.new(nil, 2)`. + [[Bug #15760]](https://bugs.ruby-lang.org/issues/15760) +* `OpenSSL::SSL::SSLSocket#sys{read,write}` prevent internal string buffers from + being modified by another thread. + [[GitHub #453]](https://github.com/ruby/openssl/pull/453) +* Fix misuse of input record separator in `OpenSSL::Buffering` where it was + for output. +* Fix wrong interger casting in `OpenSSL::PKey::EC#dsa_verify_asn1`. + [[GitHub #460]](https://github.com/ruby/openssl/pull/460) +* `extconf.rb` explicitly checks that OpenSSL's version number is 1.0.1 or + newer but also less than 3.0. Ruby/OpenSSL v2.1.x and v2.2.x will not support + OpenSSL 3.0 API. + [[GitHub #458]](https://github.com/ruby/openssl/pull/458) +* Activate `digest` gem correctly. `digest` library could go into an + inconsistent state if there are multiple versions of `digest` is installed + and `openssl` is `require`d before `digest`. + [[GitHub #463]](https://github.com/ruby/openssl/pull/463) +* Fix GC.compact compatibility. + [[GitHub #464]](https://github.com/ruby/openssl/issues/464) + [[GitHub #465]](https://github.com/ruby/openssl/pull/465) + + Version 2.1.2 ============= diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index 264130bb51..7e817ae2da 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -37,9 +37,6 @@ if $mswin || $mingw have_library("ws2_32") end -Logging::message "=== Checking for required stuff... ===\n" -result = pkg_config("openssl") && have_header("openssl/ssl.h") - def find_openssl_library if $mswin || $mingw # required for static OpenSSL libraries @@ -90,19 +87,33 @@ def find_openssl_library return false end -unless result - unless find_openssl_library - Logging::message "=== Checking for required stuff failed. ===\n" - Logging::message "Makefile wasn't created. Fix the errors above.\n" - raise "OpenSSL library could not be found. You might want to use " \ - "--with-openssl-dir=<dir> option to specify the prefix where OpenSSL " \ - "is installed." - end +Logging::message "=== Checking for required stuff... ===\n" +pkg_config_found = pkg_config("openssl") && have_header("openssl/ssl.h") + +if !pkg_config_found && !find_openssl_library + Logging::message "=== Checking for required stuff failed. ===\n" + Logging::message "Makefile wasn't created. Fix the errors above.\n" + raise "OpenSSL library could not be found. You might want to use " \ + "--with-openssl-dir=<dir> option to specify the prefix where OpenSSL " \ + "is installed." end -unless checking_for("OpenSSL version is 1.0.1 or later") { - try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10001000L", "openssl/opensslv.h") } - raise "OpenSSL >= 1.0.1 or LibreSSL is required" +version_ok = if have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h") + is_libressl = true + checking_for("LibreSSL version >= 2.5.0") { + try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x20500000L", "openssl/opensslv.h") } +else + checking_for("OpenSSL version >= 1.0.1 and < 3.0.0") { + try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10001000L", "openssl/opensslv.h") && + !try_static_assert("OPENSSL_VERSION_MAJOR >= 3", "openssl/opensslv.h") } +end +unless version_ok + raise "OpenSSL >= 1.0.1, < 3.0.0 or LibreSSL >= 2.5.0 is required" +end + +# Prevent wincrypt.h from being included, which defines conflicting macro with openssl/x509.h +if is_libressl && ($mswin || $mingw) + $defs.push("-DNOCRYPT") end Logging::message "=== Checking for OpenSSL features... ===\n" @@ -114,10 +125,6 @@ engines.each { |name| OpenSSL.check_func_or_macro("ENGINE_load_#{name}", "openssl/engine.h") } -if ($mswin || $mingw) && have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h") - $defs.push("-DNOCRYPT") -end - # added in 1.0.2 have_func("EC_curve_nist2nid") have_func("X509_REVOKED_dup") diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec index 295379fb6c..c22eece7d6 100644 --- a/ext/openssl/openssl.gemspec +++ b/ext/openssl/openssl.gemspec @@ -1,29 +1,27 @@ -# -*- encoding: utf-8 -*- +Gem::Specification.new do |spec| + spec.name = "openssl" + spec.version = "2.1.3" + spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"] + spec.email = ["ruby-core@ruby-lang.org"] + spec.summary = %q{OpenSSL provides SSL, TLS and general purpose cryptography.} + spec.description = %q{It wraps the OpenSSL library.} + spec.homepage = "https://github.com/ruby/openssl" + spec.license = "Ruby" -Gem::Specification.new do |s| - s.name = "openssl" - s.version = "2.1.2" + spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "LICENSE.txt"] + spec.require_paths = ["lib"] + spec.extensions = ["ext/openssl/extconf.rb"] - s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= - s.metadata = { "msys2_mingw_dependencies" => "openssl" } if s.respond_to? :metadata= - s.require_paths = ["lib"] - s.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"] - s.date = "2018-10-17" - s.description = "It wraps the OpenSSL library." - s.email = ["ruby-core@ruby-lang.org"] - s.extensions = ["ext/openssl/extconf.rb"] - s.extra_rdoc_files = ["README.md", "CONTRIBUTING.md", "History.md"] - s.files = ["BSDL", "CONTRIBUTING.md", "History.md", "LICENSE.txt", "README.md", "ext/openssl/deprecation.rb", "ext/openssl/extconf.rb", "ext/openssl/openssl_missing.c", "ext/openssl/openssl_missing.h", "ext/openssl/ossl.c", "ext/openssl/ossl.h", "ext/openssl/ossl_asn1.c", "ext/openssl/ossl_asn1.h", "ext/openssl/ossl_bio.c", "ext/openssl/ossl_bio.h", "ext/openssl/ossl_bn.c", "ext/openssl/ossl_bn.h", "ext/openssl/ossl_cipher.c", "ext/openssl/ossl_cipher.h", "ext/openssl/ossl_config.c", "ext/openssl/ossl_config.h", "ext/openssl/ossl_digest.c", "ext/openssl/ossl_digest.h", "ext/openssl/ossl_engine.c", "ext/openssl/ossl_engine.h", "ext/openssl/ossl_hmac.c", "ext/openssl/ossl_hmac.h", "ext/openssl/ossl_kdf.c", "ext/openssl/ossl_kdf.h", "ext/openssl/ossl_ns_spki.c", "ext/openssl/ossl_ns_spki.h", "ext/openssl/ossl_ocsp.c", "ext/openssl/ossl_ocsp.h", "ext/openssl/ossl_pkcs12.c", "ext/openssl/ossl_pkcs12.h", "ext/openssl/ossl_pkcs7.c", "ext/openssl/ossl_pkcs7.h", "ext/openssl/ossl_pkey.c", "ext/openssl/ossl_pkey.h", "ext/openssl/ossl_pkey_dh.c", "ext/openssl/ossl_pkey_dsa.c", "ext/openssl/ossl_pkey_ec.c", "ext/openssl/ossl_pkey_rsa.c", "ext/openssl/ossl_rand.c", "ext/openssl/ossl_rand.h", "ext/openssl/ossl_ssl.c", "ext/openssl/ossl_ssl.h", "ext/openssl/ossl_ssl_session.c", "ext/openssl/ossl_version.h", "ext/openssl/ossl_x509.c", "ext/openssl/ossl_x509.h", "ext/openssl/ossl_x509attr.c", "ext/openssl/ossl_x509cert.c", "ext/openssl/ossl_x509crl.c", "ext/openssl/ossl_x509ext.c", "ext/openssl/ossl_x509name.c", "ext/openssl/ossl_x509req.c", "ext/openssl/ossl_x509revoked.c", "ext/openssl/ossl_x509store.c", "ext/openssl/ruby_missing.h", "lib/openssl.rb", "lib/openssl/bn.rb", "lib/openssl/buffering.rb", "lib/openssl/cipher.rb", "lib/openssl/config.rb", "lib/openssl/digest.rb", "lib/openssl/pkcs5.rb", "lib/openssl/pkey.rb", "lib/openssl/ssl.rb", "lib/openssl/x509.rb"] - s.homepage = "https://github.com/ruby/openssl" - s.licenses = ["Ruby"] - s.rdoc_options = ["--main", "README.md"] - s.required_ruby_version = Gem::Requirement.new(">= 2.3.0") - s.rubygems_version = "3.0.0.beta1" - s.summary = "OpenSSL provides SSL, TLS and general purpose cryptography." + spec.extra_rdoc_files = Dir["*.md"] + spec.rdoc_options = ["--main", "README.md"] - s.add_runtime_dependency("ipaddr", [">= 0"]) - s.add_development_dependency("rake", [">= 0"]) - s.add_development_dependency("rake-compiler", [">= 0"]) - s.add_development_dependency("test-unit", ["~> 3.0"]) - s.add_development_dependency("rdoc", [">= 0"]) + spec.required_ruby_version = ">= 2.3.0" + + spec.add_runtime_dependency "ipaddr" + spec.add_development_dependency "rake" + spec.add_development_dependency "rake-compiler" + spec.add_development_dependency "test-unit", "~> 3.0" + spec.add_development_dependency "rdoc" + + spec.metadata["msys2_mingw_dependencies"] = "openssl" end diff --git a/ext/openssl/ossl.h b/ext/openssl/ossl.h index 6af7ddd7d0..39699bd5e6 100644 --- a/ext/openssl/ossl.h +++ b/ext/openssl/ossl.h @@ -27,6 +27,7 @@ #include <openssl/hmac.h> #include <openssl/rand.h> #include <openssl/conf.h> +#include <openssl/conf_api.h> #include <openssl/crypto.h> #if !defined(OPENSSL_NO_ENGINE) # include <openssl/engine.h> diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index 6f0064e966..e3846d2df9 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -400,7 +400,7 @@ ossl_bn_is_negative(VALUE self) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn, ossl_bn_ctx)) { \ + if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -426,7 +426,7 @@ BIGNUM_1c(sqr) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn1, bn2)) { \ + if (BN_##func(result, bn1, bn2) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -459,7 +459,7 @@ BIGNUM_2(sub) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \ + if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -503,11 +503,21 @@ BIGNUM_2c(gcd) BIGNUM_2c(mod_sqr) /* - * Document-method: OpenSSL::BN#mod_inverse * call-seq: - * bn.mod_inverse(bn2) => aBN + * bn.mod_inverse(bn2) => aBN */ -BIGNUM_2c(mod_inverse) +static VALUE +ossl_bn_mod_inverse(VALUE self, VALUE other) +{ + BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; + VALUE obj; + GetBN(self, bn1); + obj = NewBN(rb_obj_class(self)); + if (!(result = BN_mod_inverse(NULL, bn1, bn2, ossl_bn_ctx))) + ossl_raise(eBNError, "BN_mod_inverse"); + SetBN(obj, result); + return obj; +} /* * call-seq: @@ -556,7 +566,7 @@ ossl_bn_div(VALUE self, VALUE other) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \ + if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -598,7 +608,7 @@ BIGNUM_3c(mod_exp) { \ BIGNUM *bn; \ GetBN(self, bn); \ - if (!BN_##func(bn, NUM2INT(bit))) { \ + if (BN_##func(bn, NUM2INT(bit)) <= 0) { \ ossl_raise(eBNError, NULL); \ } \ return self; \ @@ -658,7 +668,7 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, bn, b)) { \ + if (BN_##func(result, bn, b) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -688,7 +698,7 @@ BIGNUM_SHIFT(rshift) int b; \ b = NUM2INT(bits); \ GetBN(self, bn); \ - if (!BN_##func(bn, bn, b)) \ + if (BN_##func(bn, bn, b) <= 0) \ ossl_raise(eBNError, NULL); \ return self; \ } @@ -727,7 +737,7 @@ BIGNUM_SELF_SHIFT(rshift) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func(result, b, top, bottom)) { \ + if (BN_##func(result, b, top, bottom) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ @@ -756,7 +766,7 @@ BIGNUM_RAND(pseudo_rand) if (!(result = BN_new())) { \ ossl_raise(eBNError, NULL); \ } \ - if (!BN_##func##_range(result, bn)) { \ + if (BN_##func##_range(result, bn) <= 0) { \ BN_free(result); \ ossl_raise(eBNError, NULL); \ } \ diff --git a/ext/openssl/ossl_digest.c b/ext/openssl/ossl_digest.c index 112ce33647..8674a3947c 100644 --- a/ext/openssl/ossl_digest.c +++ b/ext/openssl/ossl_digest.c @@ -313,8 +313,6 @@ ossl_digest_block_length(VALUE self) void Init_ossl_digest(void) { - rb_require("digest"); - #if 0 mOSSL = rb_define_module("OpenSSL"); eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError); @@ -433,6 +431,12 @@ Init_ossl_digest(void) * digest2 = sha256.digest(data2) * */ + + /* + * Digest::Class is defined by the digest library. rb_require() cannot be + * used here because it bypasses RubyGems. + */ + rb_funcall(Qnil, rb_intern_const("require"), 1, rb_str_new_cstr("digest")); cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class")); /* Document-class: OpenSSL::Digest::DigestError * diff --git a/ext/openssl/ossl_pkcs7.c b/ext/openssl/ossl_pkcs7.c index 28010c81fb..79ba0bdf48 100644 --- a/ext/openssl/ossl_pkcs7.c +++ b/ext/openssl/ossl_pkcs7.c @@ -803,9 +803,9 @@ ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self) BIO *out; VALUE str; - rb_scan_args(argc, argv, "12", &pkey, &cert, &flags); + rb_scan_args(argc, argv, "21", &pkey, &cert, &flags); key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */ - x509 = NIL_P(cert) ? NULL : GetX509CertPtr(cert); /* NO NEED TO DUP */ + x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */ flg = NIL_P(flags) ? 0 : NUM2INT(flags); GetPKCS7(self, p7); if(!(out = BIO_new(BIO_s_mem()))) diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c index 8bb611248b..b47678dc1d 100644 --- a/ext/openssl/ossl_pkey_ec.c +++ b/ext/openssl/ossl_pkey_ec.c @@ -653,15 +653,15 @@ static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig) StringValue(data); StringValue(sig); - switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) { - case 1: return Qtrue; - case 0: return Qfalse; - default: break; + switch (ECDSA_verify(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data), + (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), ec)) { + case 1: + return Qtrue; + case 0: + return Qfalse; + default: + ossl_raise(eECError, "ECDSA_verify"); } - - ossl_raise(eECError, "ECDSA_verify"); - - UNREACHABLE; } /* diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index de0556f543..bfd80126c2 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -13,6 +13,12 @@ #define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0])) +#if !defined(TLS1_3_VERSION) && \ + defined(LIBRESSL_VERSION_NUMBER) && \ + LIBRESSL_VERSION_NUMBER >= 0x3020000fL +# define TLS1_3_VERSION 0x0304 +#endif + #ifdef _WIN32 # define TO_SOCKET(s) _get_osfhandle(s) #else @@ -33,7 +39,7 @@ static VALUE eSSLErrorWaitReadable; static VALUE eSSLErrorWaitWritable; static ID id_call, ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback, - id_npn_protocols_encoded; + id_npn_protocols_encoded, id_each; 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, @@ -54,6 +60,13 @@ static int ossl_sslctx_ex_store_p; #endif static void +ossl_sslctx_mark(void *ptr) +{ + SSL_CTX *ctx = ptr; + rb_gc_mark((VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx)); +} + +static void ossl_sslctx_free(void *ptr) { SSL_CTX *ctx = ptr; @@ -67,7 +80,7 @@ ossl_sslctx_free(void *ptr) static const rb_data_type_t ossl_sslctx_type = { "OpenSSL/SSL/CTX", { - 0, ossl_sslctx_free, + ossl_sslctx_mark, ossl_sslctx_free, }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; @@ -359,7 +372,14 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(status)); return 0; } - preverify_ok = ret == Qtrue; + if (ret != Qtrue) { + preverify_ok = 0; +#if defined(X509_V_ERR_HOSTNAME_MISMATCH) + X509_STORE_CTX_set_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH); +#else + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED); +#endif + } } return ossl_verify_cb_call(cb, preverify_ok, ctx); @@ -609,7 +629,7 @@ static VALUE ssl_encode_npn_protocols(VALUE protocols) { VALUE encoded = rb_str_new(NULL, 0); - rb_iterate(rb_each, protocols, ssl_npn_encode_protocol_i, encoded); + rb_block_call(protocols, id_each, 0, 0, ssl_npn_encode_protocol_i, encoded); return encoded; } @@ -679,7 +699,7 @@ static int ssl_npn_advertise_cb(SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) { - VALUE protocols = (VALUE)arg; + VALUE protocols = rb_attr_get((VALUE)arg, id_npn_protocols_encoded); *out = (const unsigned char *) RSTRING_PTR(protocols); *outlen = RSTRING_LENINT(protocols); @@ -897,7 +917,7 @@ ossl_sslctx_setup(VALUE self) if (!NIL_P(val)) { VALUE encoded = ssl_encode_npn_protocols(val); rb_ivar_set(self, id_npn_protocols_encoded, encoded); - SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)encoded); + SSL_CTX_set_next_protos_advertised_cb(ctx, ssl_npn_advertise_cb, (void *)self); OSSL_Debug("SSL NPN advertise callback added"); } if (RTEST(rb_attr_get(self, id_i_npn_select_cb))) { @@ -1516,6 +1536,14 @@ ssl_started(SSL *ssl) } static void +ossl_ssl_mark(void *ptr) +{ + SSL *ssl = ptr; + rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)); + rb_gc_mark((VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx)); +} + +static void ossl_ssl_free(void *ssl) { SSL_free(ssl); @@ -1524,7 +1552,7 @@ ossl_ssl_free(void *ssl) const rb_data_type_t ossl_ssl_type = { "OpenSSL/SSL", { - 0, ossl_ssl_free, + ossl_ssl_mark, ossl_ssl_free, }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; @@ -1680,6 +1708,11 @@ ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, VALUE opts) rb_io_wait_readable(fptr->fd); continue; case SSL_ERROR_SYSCALL: +#ifdef __APPLE__ + /* See ossl_ssl_write_internal() */ + if (errno == EPROTOTYPE) + continue; +#endif if (errno) rb_sys_fail(funcname); ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl)); #if defined(SSL_R_CERTIFICATE_VERIFY_FAILED) @@ -1836,26 +1869,36 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) io = rb_attr_get(self, id_i_io); GetOpenFile(io, fptr); if (ssl_started(ssl)) { - for (;;){ + rb_str_locktmp(str); + for (;;) { nread = SSL_read(ssl, RSTRING_PTR(str), ilen); switch(ssl_get_error(ssl, nread)){ case SSL_ERROR_NONE: + rb_str_unlocktmp(str); goto end; case SSL_ERROR_ZERO_RETURN: + rb_str_unlocktmp(str); if (no_exception_p(opts)) { return Qnil; } rb_eof_error(); case SSL_ERROR_WANT_WRITE: - if (no_exception_p(opts)) { return sym_wait_writable; } - write_would_block(nonblock); + if (nonblock) { + rb_str_unlocktmp(str); + if (no_exception_p(opts)) { return sym_wait_writable; } + write_would_block(nonblock); + } rb_io_wait_writable(fptr->fd); continue; case SSL_ERROR_WANT_READ: - if (no_exception_p(opts)) { return sym_wait_readable; } - read_would_block(nonblock); + if (nonblock) { + rb_str_unlocktmp(str); + if (no_exception_p(opts)) { return sym_wait_readable; } + read_would_block(nonblock); + } rb_io_wait_readable(fptr->fd); continue; case SSL_ERROR_SYSCALL: if (!ERR_peek_error()) { + rb_str_unlocktmp(str); if (errno) rb_sys_fail(0); else { @@ -1872,23 +1915,30 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) } /* fall through */ default: + rb_str_unlocktmp(str); ossl_raise(eSSLError, "SSL_read"); } } } else { - ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); + ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread"); - rb_warning("SSL session is not started yet."); - if (nonblock) { + rb_warning("SSL session is not started yet."); +#if defined(RB_PASS_KEYWORDS) + if (nonblock) { VALUE argv[3]; argv[0] = len; argv[1] = str; argv[2] = opts; return rb_funcallv_kw(io, meth, 3, argv, RB_PASS_KEYWORDS); } - else - return rb_funcall(io, meth, 2, len, str); +#else + if (nonblock) { + return rb_funcall(io, meth, 3, len, str, opts); + } +#endif + else + return rb_funcall(io, meth, 2, len, str); } end: @@ -1936,21 +1986,21 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) int nwrite = 0; rb_io_t *fptr; int nonblock = opts != Qfalse; - VALUE io; + VALUE tmp, io; - StringValue(str); + tmp = rb_str_new_frozen(StringValue(str)); GetSSL(self, ssl); io = rb_attr_get(self, id_i_io); GetOpenFile(io, fptr); if (ssl_started(ssl)) { - for (;;){ - int num = RSTRING_LENINT(str); + for (;;) { + int num = RSTRING_LENINT(tmp); /* SSL_write(3ssl) manpage states num == 0 is undefined */ if (num == 0) goto end; - nwrite = SSL_write(ssl, RSTRING_PTR(str), num); + nwrite = SSL_write(ssl, RSTRING_PTR(tmp), num); switch(ssl_get_error(ssl, nwrite)){ case SSL_ERROR_NONE: goto end; @@ -1965,6 +2015,16 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) rb_io_wait_readable(fptr->fd); continue; case SSL_ERROR_SYSCALL: +#ifdef __APPLE__ + /* + * It appears that send syscall can return EPROTOTYPE if the + * socket is being torn down. Retry to get a proper errno to + * make the error handling in line with the socket library. + * [Bug #14713] https://bugs.ruby-lang.org/issues/14713 + */ + if (errno == EPROTOTYPE) + continue; +#endif if (errno) rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_write"); @@ -1975,15 +2035,21 @@ ossl_ssl_write_internal(VALUE self, VALUE str, VALUE opts) ID meth = nonblock ? rb_intern("write_nonblock") : rb_intern("syswrite"); - rb_warning("SSL session is not started yet."); - if (nonblock) { + rb_warning("SSL session is not started yet."); +#if defined(RB_PASS_KEYWORDS) + if (nonblock) { VALUE argv[2]; argv[0] = str; argv[1] = opts; return rb_funcallv_kw(io, meth, 2, argv, RB_PASS_KEYWORDS); } - else - return rb_funcall(io, meth, 1, str); +#else + if (nonblock) { + return rb_funcall(io, meth, 2, str, opts); + } +#endif + else + return rb_funcall(io, meth, 1, str); } end: @@ -2926,6 +2992,7 @@ Init_ossl_ssl(void) id_tmp_dh_callback = rb_intern("tmp_dh_callback"); id_tmp_ecdh_callback = rb_intern("tmp_ecdh_callback"); id_npn_protocols_encoded = rb_intern("npn_protocols_encoded"); + id_each = rb_intern_const("each"); #define DefIVarID(name) do \ id_i_##name = rb_intern("@"#name); while (0) diff --git a/ext/openssl/ossl_version.h b/ext/openssl/ossl_version.h index c162f8c2a8..edbd8ce3fa 100644 --- a/ext/openssl/ossl_version.h +++ b/ext/openssl/ossl_version.h @@ -10,6 +10,6 @@ #if !defined(_OSSL_VERSION_H_) #define _OSSL_VERSION_H_ -#define OSSL_VERSION "2.1.2" +#define OSSL_VERSION "2.1.3" #endif /* _OSSL_VERSION_H_ */ diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c index 8a061b0687..4fc0648614 100644 --- a/ext/openssl/ossl_x509.c +++ b/ext/openssl/ossl_x509.c @@ -44,7 +44,13 @@ Init_ossl_x509(void) Init_ossl_x509revoked(); Init_ossl_x509store(); + /* Constants are up-to-date with 1.1.1. */ + + /* Certificate verification error code */ DefX509Const(V_OK); +#if defined(X509_V_ERR_UNSPECIFIED) /* 1.0.1r, 1.0.2f, 1.1.0 */ + DefX509Const(V_ERR_UNSPECIFIED); +#endif DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT); DefX509Const(V_ERR_UNABLE_TO_GET_CRL); DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE); @@ -76,8 +82,73 @@ Init_ossl_x509(void) DefX509Const(V_ERR_AKID_SKID_MISMATCH); DefX509Const(V_ERR_AKID_ISSUER_SERIAL_MISMATCH); DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN); + DefX509Const(V_ERR_UNABLE_TO_GET_CRL_ISSUER); + DefX509Const(V_ERR_UNHANDLED_CRITICAL_EXTENSION); + DefX509Const(V_ERR_KEYUSAGE_NO_CRL_SIGN); + DefX509Const(V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION); + DefX509Const(V_ERR_INVALID_NON_CA); + DefX509Const(V_ERR_PROXY_PATH_LENGTH_EXCEEDED); + DefX509Const(V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE); + DefX509Const(V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED); + DefX509Const(V_ERR_INVALID_EXTENSION); + DefX509Const(V_ERR_INVALID_POLICY_EXTENSION); + DefX509Const(V_ERR_NO_EXPLICIT_POLICY); + DefX509Const(V_ERR_DIFFERENT_CRL_SCOPE); + DefX509Const(V_ERR_UNSUPPORTED_EXTENSION_FEATURE); + DefX509Const(V_ERR_UNNESTED_RESOURCE); + DefX509Const(V_ERR_PERMITTED_VIOLATION); + DefX509Const(V_ERR_EXCLUDED_VIOLATION); + DefX509Const(V_ERR_SUBTREE_MINMAX); DefX509Const(V_ERR_APPLICATION_VERIFICATION); + DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_TYPE); + DefX509Const(V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX); + DefX509Const(V_ERR_UNSUPPORTED_NAME_SYNTAX); + DefX509Const(V_ERR_CRL_PATH_VALIDATION_ERROR); +#if defined(X509_V_ERR_PATH_LOOP) + DefX509Const(V_ERR_PATH_LOOP); +#endif +#if defined(X509_V_ERR_SUITE_B_INVALID_VERSION) + DefX509Const(V_ERR_SUITE_B_INVALID_VERSION); + DefX509Const(V_ERR_SUITE_B_INVALID_ALGORITHM); + DefX509Const(V_ERR_SUITE_B_INVALID_CURVE); + DefX509Const(V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM); + DefX509Const(V_ERR_SUITE_B_LOS_NOT_ALLOWED); + DefX509Const(V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256); +#endif +#if defined(X509_V_ERR_HOSTNAME_MISMATCH) + DefX509Const(V_ERR_HOSTNAME_MISMATCH); + DefX509Const(V_ERR_EMAIL_MISMATCH); + DefX509Const(V_ERR_IP_ADDRESS_MISMATCH); +#endif +#if defined(X509_V_ERR_DANE_NO_MATCH) + DefX509Const(V_ERR_DANE_NO_MATCH); +#endif +#if defined(X509_V_ERR_EE_KEY_TOO_SMALL) + DefX509Const(V_ERR_EE_KEY_TOO_SMALL); + DefX509Const(V_ERR_CA_KEY_TOO_SMALL); + DefX509Const(V_ERR_CA_MD_TOO_WEAK); +#endif +#if defined(X509_V_ERR_INVALID_CALL) + DefX509Const(V_ERR_INVALID_CALL); +#endif +#if defined(X509_V_ERR_STORE_LOOKUP) + DefX509Const(V_ERR_STORE_LOOKUP); +#endif +#if defined(X509_V_ERR_NO_VALID_SCTS) + DefX509Const(V_ERR_NO_VALID_SCTS); +#endif +#if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION) + DefX509Const(V_ERR_PROXY_SUBJECT_NAME_VIOLATION); +#endif +#if defined(X509_V_ERR_OCSP_VERIFY_NEEDED) + DefX509Const(V_ERR_OCSP_VERIFY_NEEDED); + DefX509Const(V_ERR_OCSP_VERIFY_FAILED); + DefX509Const(V_ERR_OCSP_CERT_UNKNOWN); +#endif + /* Certificate verify flags */ + /* Set by Store#flags= and StoreContext#flags=. */ + DefX509Const(V_FLAG_USE_CHECK_TIME); /* Set by Store#flags= and StoreContext#flags=. Enables CRL checking for the * certificate chain leaf. */ DefX509Const(V_FLAG_CRL_CHECK); @@ -122,6 +193,26 @@ Init_ossl_x509(void) * Enabled by default in OpenSSL >= 1.1.0. */ DefX509Const(V_FLAG_TRUSTED_FIRST); #endif +#if defined(X509_V_FLAG_SUITEB_128_LOS_ONLY) + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 128 bit only mode. */ + DefX509Const(V_FLAG_SUITEB_128_LOS_ONLY); +#endif +#if defined(X509_V_FLAG_SUITEB_192_LOS) + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 192 bit only mode. */ + DefX509Const(V_FLAG_SUITEB_192_LOS); +#endif +#if defined(X509_V_FLAG_SUITEB_128_LOS) + /* Set by Store#flags= and StoreContext#flags=. + * Enables Suite B 128 bit mode allowing 192 bit algorithms. */ + DefX509Const(V_FLAG_SUITEB_128_LOS); +#endif +#if defined(X509_V_FLAG_PARTIAL_CHAIN) + /* Set by Store#flags= and StoreContext#flags=. + * Allows partial chains if at least one certificate is in trusted store. */ + DefX509Const(V_FLAG_PARTIAL_CHAIN); +#endif #if defined(X509_V_FLAG_NO_ALT_CHAINS) /* Set by Store#flags= and StoreContext#flags=. Suppresses searching for * a alternative chain. No effect in OpenSSL >= 1.1.0. */ diff --git a/ext/openssl/ossl_x509store.c b/ext/openssl/ossl_x509store.c index 61543d44f6..9035a70aa9 100644 --- a/ext/openssl/ossl_x509store.c +++ b/ext/openssl/ossl_x509store.c @@ -106,6 +106,13 @@ VALUE cX509StoreContext; VALUE eX509StoreError; static void +ossl_x509store_mark(void *ptr) +{ + X509_STORE *store = ptr; + rb_gc_mark((VALUE)X509_STORE_get_ex_data(store, store_ex_verify_cb_idx)); +} + +static void ossl_x509store_free(void *ptr) { X509_STORE_free(ptr); @@ -114,7 +121,7 @@ ossl_x509store_free(void *ptr) static const rb_data_type_t ossl_x509store_type = { "OpenSSL/X509/STORE", { - 0, ossl_x509store_free, + ossl_x509store_mark, ossl_x509store_free, }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, }; @@ -457,23 +464,16 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self) } /* - * Public Functions - */ -static void ossl_x509stctx_free(void*); - - -static const rb_data_type_t ossl_x509stctx_type = { - "OpenSSL/X509/STORE_CTX", - { - 0, ossl_x509stctx_free, - }, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, -}; - -/* * Private functions */ static void +ossl_x509stctx_mark(void *ptr) +{ + X509_STORE_CTX *ctx = ptr; + rb_gc_mark((VALUE)X509_STORE_CTX_get_ex_data(ctx, stctx_ex_verify_cb_idx)); +} + +static void ossl_x509stctx_free(void *ptr) { X509_STORE_CTX *ctx = ptr; @@ -484,6 +484,14 @@ ossl_x509stctx_free(void *ptr) X509_STORE_CTX_free(ctx); } +static const rb_data_type_t ossl_x509stctx_type = { + "OpenSSL/X509/STORE_CTX", + { + ossl_x509stctx_mark, ossl_x509stctx_free, + }, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY, +}; + static VALUE ossl_x509stctx_alloc(VALUE klass) { @@ -517,7 +525,9 @@ static VALUE ossl_x509stctx_set_time(VALUE, VALUE); /* * call-seq: - * StoreContext.new(store, cert = nil, chain = nil) + * StoreContext.new(store, cert = nil, untrusted = nil) + * + * Sets up a StoreContext for a verification of the X.509 certificate _cert_. */ static VALUE ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) @@ -527,15 +537,24 @@ ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self) X509_STORE *x509st; X509 *x509 = NULL; STACK_OF(X509) *x509s = NULL; + int state; rb_scan_args(argc, argv, "12", &store, &cert, &chain); GetX509StCtx(self, ctx); GetX509Store(store, x509st); - if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */ - if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain); - if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ + if (!NIL_P(cert)) + x509 = DupX509CertPtr(cert); /* NEED TO DUP */ + if (!NIL_P(chain)) { + x509s = ossl_protect_x509_ary2sk(chain, &state); + if (state) { + X509_free(x509); + rb_jump_tag(state); + } + } + if (X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){ + X509_free(x509); sk_X509_pop_free(x509s, X509_free); - ossl_raise(eX509StoreError, NULL); + ossl_raise(eX509StoreError, "X509_STORE_CTX_init"); } if (!NIL_P(t = rb_iv_get(store, "@time"))) ossl_x509stctx_set_time(self, t); |