diff --git a/NEWS.md b/NEWS.md
index 947d3d5eeee93f..cd038f08d0d563 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -82,6 +82,11 @@ Note: We're only listing outstanding class updates.
* A deprecated behavior, process creation by `Kernel#open` with a
leading `|`, was removed. [[Feature #19630]]
+* Array
+
+ * `Array#rfind` has been added as a more efficient alternative to `array.reverse_each.find` [[Feature #21678]]
+ * `Array#find` has been added as a more efficient override of `Enumerable#find` [[Feature #21678]]
+
* Binding
* `Binding#local_variables` does no longer include numbered parameters.
@@ -286,7 +291,7 @@ The following default gems are updated.
* ipaddr 1.2.8
* json 2.18.0
* net-http 0.8.0
-* openssl 4.0.0.pre
+* openssl 4.0.0
* optparse 0.8.1
* pp 0.6.3
* prism 1.6.0
@@ -478,4 +483,5 @@ A lot of work has gone into making Ractors more stable, performant, and usable.
[Feature #21550]: https://bugs.ruby-lang.org/issues/21550
[Feature #21557]: https://bugs.ruby-lang.org/issues/21557
[Bug #21654]: https://bugs.ruby-lang.org/issues/21654
+[Feature #21678]: https://bugs.ruby-lang.org/issues/21678
[Feature #21701]: https://bugs.ruby-lang.org/issues/21701
diff --git a/box.c b/box.c
index 7907e0ff632a1e..150a75700c9313 100644
--- a/box.c
+++ b/box.c
@@ -31,16 +31,8 @@ VALUE rb_cBox = 0;
VALUE rb_cBoxEntry = 0;
VALUE rb_mBoxLoader = 0;
-static rb_box_t root_box_data = {
- /* Initialize values lazily in Init_Box() */
- (VALUE)NULL, 0,
- (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL, (VALUE)NULL,
- (struct st_table *)NULL, (struct st_table *)NULL, (VALUE)NULL, (VALUE)NULL,
- false, false
-};
-
-static rb_box_t * root_box = &root_box_data;
-static rb_box_t * main_box = 0;
+static rb_box_t root_box[1]; /* Initialize in initialize_root_box() */
+static rb_box_t *main_box;
static char *tmp_dir;
static bool tmp_dir_has_dirsep;
@@ -290,7 +282,7 @@ box_entry_memsize(const void *ptr)
rb_st_memsize(box->loading_table);
}
-const rb_data_type_t rb_box_data_type = {
+static const rb_data_type_t rb_box_data_type = {
"Ruby::Box::Entry",
{
rb_box_entry_mark,
@@ -301,7 +293,7 @@ const rb_data_type_t rb_box_data_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY // TODO: enable RUBY_TYPED_WB_PROTECTED when inserting write barriers
};
-const rb_data_type_t rb_root_box_data_type = {
+static const rb_data_type_t rb_root_box_data_type = {
"Ruby::Box::Root",
{
rb_box_entry_mark,
@@ -838,8 +830,6 @@ rb_box_require_relative(VALUE box, VALUE fname)
static void
initialize_root_box(void)
{
- VALUE root_box, entry;
- ID id_box_entry;
rb_vm_t *vm = GET_VM();
rb_box_t *root = (rb_box_t *)rb_root_box();
@@ -864,6 +854,8 @@ initialize_root_box(void)
vm->root_box = root;
if (rb_box_available()) {
+ VALUE root_box, entry;
+ ID id_box_entry;
CONST_ID(id_box_entry, "__box_entry__");
root_box = rb_obj_alloc(rb_cBox);
diff --git a/ext/openssl/History.md b/ext/openssl/History.md
index 32a2c0b2fb6ea7..419237ff167f9a 100644
--- a/ext/openssl/History.md
+++ b/ext/openssl/History.md
@@ -1,3 +1,88 @@
+Version 4.0.0
+=============
+
+Compatibility
+-------------
+
+* Ruby >= 2.7
+* OpenSSL >= 1.1.1, LibreSSL >= 3.9, and AWS-LC 1.66.0
+ - Removed support for OpenSSL 1.0.2-1.1.0 and LibreSSL 3.1-3.8.
+ [[GitHub #835]](https://github.com/ruby/openssl/issues/835)
+ - Added support for AWS-LC.
+ [[GitHub #833]](https://github.com/ruby/openssl/issues/833)
+
+
+Notable changes
+---------------
+
+* `OpenSSL::SSL`
+ - Reduce overhead when writing to `OpenSSL::SSL::SSLSocket`. `#syswrite` no
+ longer creates a temporary String object.
+ [[GitHub #831]](https://github.com/ruby/openssl/pull/831)
+ - Make `OpenSSL::SSL::SSLContext#min_version=` and `#max_version=` wrap the
+ corresponding OpenSSL APIs directly, and remove the fallback to SSL options.
+ [[GitHub #849]](https://github.com/ruby/openssl/pull/849)
+ - Add `OpenSSL::SSL::SSLContext#sigalgs=` and `#client_sigalgs=` for
+ specifying signature algorithms to use for connections.
+ [[GitHub #895]](https://github.com/ruby/openssl/pull/895)
+ - Rename `OpenSSL::SSL::SSLContext#ecdh_curves=` to `#groups=` following
+ the underlying OpenSSL API rename. This method is no longer specific to
+ ECDHE. The old method remains as an alias.
+ [[GitHub #900]](https://github.com/ruby/openssl/pull/900)
+ - Add `OpenSSL::SSL::SSLSocket#sigalg`, `#peer_sigalg`, and `#group` for
+ getting the signature algorithm and the key agreement group used in the
+ current connection.
+ [[GitHub #908]](https://github.com/ruby/openssl/pull/908)
+ - Enable `SSL_CTX_set_dh_auto()` for servers by default.
+ [[GitHub #924]](https://github.com/ruby/openssl/pull/924)
+ - Improve Ractor compatibility. Note that the internal-use constant
+ `OpenSSL::SSL::SSLContext::DEFAULT_PARAMS` is now frozen.
+ [[GitHub #925]](https://github.com/ruby/openssl/pull/925)
+* `OpenSSL::PKey`
+ - Remove `OpenSSL::PKey::EC::Point#mul` support with array arguments. The
+ underlying OpenSSL API has been removed, and the method has been deprecated
+ since ruby/openssl v3.0.0.
+ [[GitHub #843]](https://github.com/ruby/openssl/pull/843)
+ - `OpenSSL::PKey::{RSA,DSA,DH}#params` uses `nil` to indicate missing fields
+ instead of the number `0`.
+ [[GitHub #774]](https://github.com/ruby/openssl/pull/774)
+ - Unify `OpenSSL::PKey::PKeyError` classes. The former subclasses
+ `OpenSSL::PKey::DHError`, `OpenSSL::PKey::DSAError`,
+ `OpenSSL::PKey::ECError`, and `OpenSSL::PKey::RSAError` have been merged
+ into a single class.
+ [[GitHub #929]](https://github.com/ruby/openssl/pull/929)
+* `OpenSSL::Cipher`
+ - `OpenSSL::Cipher#encrypt` and `#decrypt` no longer accept arguments.
+ Passing passwords has been deprecated since Ruby 1.8.2 (released in 2004).
+ [[GitHub #887]](https://github.com/ruby/openssl/pull/887)
+ - `OpenSSL::Cipher#final` raises `OpenSSL::Cipher::AuthTagError` when the
+ integrity check fails for AEAD ciphers. `OpenSSL::Cipher::AuthTagError` is a
+ new subclass of `OpenSSL::Cipher::CipherError`, which was previously raised.
+ [[GitHub #939]](https://github.com/ruby/openssl/pull/939)
+ - `OpenSSL::Cipher.new` now raises `OpenSSL::Cipher::CipherError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" cipher algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::Digest`
+ - `OpenSSL::Digest.new` now raises `OpenSSL::Digest::DigestError` instead of
+ `RuntimeError` when OpenSSL does not recognize the algorithm.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+ - Add support for "fetched" digest algorithms with OpenSSL 3.0 or later.
+ [[GitHub #958]](https://github.com/ruby/openssl/pull/958)
+* `OpenSSL::ASN1.decode` now assumes a 1950-2049 year range for `UTCTime`
+ according to RFC 5280. It previously used a 1969-2068 range. The encoder
+ has always used the 1950-2049 range.
+ [[GitHub #909]](https://github.com/ruby/openssl/pull/909)
+* `OpenSSL::OpenSSLError`, the base class for all ruby/openssl errors, carry
+ an additional attribute `#errors` to keep the content of OpenSSL's error
+ queue. Also, add `#detailed_message` for Ruby 3.2 or later.
+ [[GitHub #976]](https://github.com/ruby/openssl/pull/976)
+* `OpenSSL::PKCS7.new` raises `OpenSSL::PKCS7::PKCS7Error` instead of
+ `ArgumentError` on error to be consistent with other constructors.
+ [[GitHub #983]](https://github.com/ruby/openssl/pull/983)
+
+
Version 3.3.2
=============
diff --git a/ext/openssl/lib/openssl.rb b/ext/openssl/lib/openssl.rb
index 41927f32ae8238..98fa8d39f2aad6 100644
--- a/ext/openssl/lib/openssl.rb
+++ b/ext/openssl/lib/openssl.rb
@@ -23,12 +23,16 @@
require_relative 'openssl/x509'
module OpenSSL
- # call-seq:
- # OpenSSL.secure_compare(string, string) -> boolean
+ # :call-seq:
+ # OpenSSL.secure_compare(string, string) -> true or false
#
# Constant time memory comparison. Inputs are hashed using SHA-256 to mask
# the length of the secret. Returns +true+ if the strings are identical,
# +false+ otherwise.
+ #
+ # This method is expensive due to the SHA-256 hashing. In most cases, where
+ # the input lengths are known to be equal or are not sensitive,
+ # OpenSSL.fixed_length_secure_compare should be used instead.
def self.secure_compare(a, b)
hashed_a = OpenSSL::Digest.digest('SHA256', a)
hashed_b = OpenSSL::Digest.digest('SHA256', b)
diff --git a/ext/openssl/lib/openssl/digest.rb b/ext/openssl/lib/openssl/digest.rb
index 5cda1e931c8b44..46ddfd6021b7ea 100644
--- a/ext/openssl/lib/openssl/digest.rb
+++ b/ext/openssl/lib/openssl/digest.rb
@@ -57,7 +57,7 @@ class Digest < Digest; end # :nodoc:
# OpenSSL::Digest("MD5")
# # => OpenSSL::Digest::MD5
#
- # Digest("Foo")
+ # OpenSSL::Digest("Foo")
# # => NameError: wrong constant name Foo
def Digest(name)
diff --git a/ext/openssl/lib/openssl/version.rb b/ext/openssl/lib/openssl/version.rb
index 784f8885066091..88570562e255c3 100644
--- a/ext/openssl/lib/openssl/version.rb
+++ b/ext/openssl/lib/openssl/version.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
module OpenSSL
- VERSION = "4.0.0.pre"
+ # The version string of Ruby/OpenSSL.
+ VERSION = "4.0.0"
end
diff --git a/ext/openssl/openssl.gemspec b/ext/openssl/openssl.gemspec
index 061a9c5a6ab626..7072d599d86d69 100644
--- a/ext/openssl/openssl.gemspec
+++ b/ext/openssl/openssl.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |spec|
spec.name = "openssl"
- spec.version = "4.0.0.pre"
+ spec.version = "4.0.0"
spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"]
spec.email = ["ruby-core@ruby-lang.org"]
spec.summary = %q{SSL/TLS and general-purpose cryptography for Ruby}
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index 9c63d9451aa59d..98127fcba02314 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -388,10 +388,14 @@ osslerror_detailed_message(int argc, VALUE *argv, VALUE self)
* call-seq:
* OpenSSL.errors -> [String...]
*
- * See any remaining errors held in queue.
+ * Returns any remaining errors held in the \OpenSSL thread-local error queue
+ * and clears the queue. This should normally return an empty array.
*
- * Any errors you see here are probably due to a bug in Ruby's OpenSSL
- * implementation.
+ * This is intended for debugging Ruby/OpenSSL. If you see any errors here,
+ * it likely indicates a bug in the extension. Please file an issue at
+ * https://github.com/ruby/openssl.
+ *
+ * For debugging your program, OpenSSL.debug= may be useful.
*/
static VALUE
ossl_get_errors(VALUE _)
@@ -415,6 +419,8 @@ VALUE dOSSL;
/*
* call-seq:
* OpenSSL.debug -> true | false
+ *
+ * Returns whether Ruby/OpenSSL's debug mode is currently enabled.
*/
static VALUE
ossl_debug_get(VALUE self)
@@ -424,9 +430,9 @@ ossl_debug_get(VALUE self)
/*
* call-seq:
- * OpenSSL.debug = boolean -> boolean
+ * OpenSSL.debug = boolean
*
- * Turns on or off debug mode. With debug mode, all errors added to the OpenSSL
+ * Turns on or off debug mode. With debug mode, all errors added to the \OpenSSL
* error queue will be printed to stderr.
*/
static VALUE
@@ -440,6 +446,8 @@ ossl_debug_set(VALUE self, VALUE val)
/*
* call-seq:
* OpenSSL.fips_mode -> true | false
+ *
+ * Returns whether the FIPS mode is currently enabled.
*/
static VALUE
ossl_fips_mode_get(VALUE self)
@@ -460,10 +468,10 @@ ossl_fips_mode_get(VALUE self)
/*
* call-seq:
- * OpenSSL.fips_mode = boolean -> boolean
+ * OpenSSL.fips_mode = boolean
*
* Turns FIPS mode on or off. Turning on FIPS mode will obviously only have an
- * effect for FIPS-capable installations of the OpenSSL library. Trying to do
+ * effect for FIPS-capable installations of the \OpenSSL library. Trying to do
* so otherwise will result in an error.
*
* === Examples
@@ -503,13 +511,13 @@ ossl_fips_mode_set(VALUE self, VALUE enabled)
/*
* call-seq:
- * OpenSSL.fixed_length_secure_compare(string, string) -> boolean
+ * OpenSSL.fixed_length_secure_compare(string, string) -> true or false
*
* Constant time memory comparison for fixed length strings, such as results
- * of HMAC calculations.
+ * of \HMAC calculations.
*
* Returns +true+ if the strings are identical, +false+ if they are of the same
- * length but not identical. If the length is different, +ArgumentError+ is
+ * length but not identical. If the length is different, ArgumentError is
* raised.
*/
static VALUE
@@ -531,7 +539,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
}
/*
- * OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the
+ * OpenSSL provides \SSL, TLS and general purpose cryptography. It wraps the
* OpenSSL[https://www.openssl.org/] library.
*
* = Examples
@@ -586,7 +594,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Loading an Encrypted Key
*
- * OpenSSL will prompt you for your password when loading an encrypted key.
+ * \OpenSSL will prompt you for your password when loading an encrypted key.
* If you will not be able to type in the password you may provide it when
* loading the key:
*
@@ -649,7 +657,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* == PBKDF2 Password-based Encryption
*
- * If supported by the underlying OpenSSL version used, Password-based
+ * If supported by the underlying \OpenSSL version used, Password-based
* Encryption should use the features of PKCS5. If not supported or if
* required by legacy applications, the older, less secure methods specified
* in RFC 2898 are also supported (see below).
@@ -708,7 +716,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* decrypted = cipher.update encrypted
* decrypted << cipher.final
*
- * == X509 Certificates
+ * == \X509 Certificates
*
* === Creating a Certificate
*
@@ -745,7 +753,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* extension_factory.create_extension('subjectKeyIdentifier', 'hash')
*
* The list of supported extensions (and in some cases their possible values)
- * can be derived from the "objects.h" file in the OpenSSL source code.
+ * can be derived from the "objects.h" file in the \OpenSSL source code.
*
* === Signing a Certificate
*
@@ -899,23 +907,23 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* io.write csr_cert.to_pem
* end
*
- * == SSL and TLS Connections
+ * == \SSL and TLS Connections
*
- * Using our created key and certificate we can create an SSL or TLS connection.
- * An SSLContext is used to set up an SSL session.
+ * Using our created key and certificate we can create an \SSL or TLS
+ * connection. An OpenSSL::SSL::SSLContext is used to set up an \SSL session.
*
* context = OpenSSL::SSL::SSLContext.new
*
- * === SSL Server
+ * === \SSL Server
*
- * An SSL server requires the certificate and private key to communicate
+ * An \SSL server requires the certificate and private key to communicate
* securely with its clients:
*
* context.cert = cert
* context.key = key
*
- * Then create an SSLServer with a TCP server socket and the context. Use the
- * SSLServer like an ordinary TCP server.
+ * Then create an OpenSSL::SSL::SSLServer with a TCP server socket and the
+ * context. Use the SSLServer like an ordinary TCP server.
*
* require 'socket'
*
@@ -934,14 +942,15 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
* ssl_connection.close
* end
*
- * === SSL client
+ * === \SSL client
*
- * An SSL client is created with a TCP socket and the context.
- * SSLSocket#connect must be called to initiate the SSL handshake and start
- * encryption. A key and certificate are not required for the client socket.
+ * An \SSL client is created with a TCP socket and the context.
+ * OpenSSL::SSL::SSLSocket#connect must be called to initiate the \SSL handshake
+ * and start encryption. A key and certificate are not required for the client
+ * socket.
*
- * Note that SSLSocket#close doesn't close the underlying socket by default. Set
- * SSLSocket#sync_close to true if you want.
+ * Note that OpenSSL::SSL::SSLSocket#close doesn't close the underlying socket
+ * by default. Set OpenSSL::SSL::SSLSocket#sync_close to true if you want.
*
* require 'socket'
*
@@ -957,7 +966,7 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2)
*
* === Peer Verification
*
- * An unverified SSL connection does not provide much security. For enhanced
+ * An unverified \SSL connection does not provide much security. For enhanced
* security the client or server can verify the certificate of its peer.
*
* The client can be modified to verify the server's certificate against the
@@ -1008,22 +1017,34 @@ Init_openssl(void)
rb_define_singleton_method(mOSSL, "fixed_length_secure_compare", ossl_crypto_fixed_length_secure_compare, 2);
/*
- * Version of OpenSSL the ruby OpenSSL extension was built with
+ * \OpenSSL library version string used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
+ rb_define_const(mOSSL, "OPENSSL_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OPENSSL_VERSION_TEXT)));
/*
- * Version of OpenSSL the ruby OpenSSL extension is running with
+ * \OpenSSL library version string currently used at runtime.
*/
- rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(OpenSSL_version(OPENSSL_VERSION)));
+ rb_define_const(
+ mOSSL,
+ "OPENSSL_LIBRARY_VERSION",
+ rb_obj_freeze(rb_str_new_cstr(OpenSSL_version(OPENSSL_VERSION)))
+ );
/*
- * Version number of OpenSSL the ruby OpenSSL extension was built with
- * (base 16). The formats are below.
+ * \OpenSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
*
- * [OpenSSL 3] 0xMNN00PP0 (major minor 00 patch 0)
- * [OpenSSL before 3] 0xMNNFFPPS (major minor fix patch status)
- * [LibreSSL] 0x20000000 (fixed value)
+ * The version number is encoded into a single integer value. The number
+ * follows the format:
+ *
+ * [\OpenSSL 3.0.0 or later]
+ * 0xMNN00PP0 (major minor 00 patch 0)
+ * [\OpenSSL 1.1.1 or earlier]
+ * 0xMNNFFPPS (major minor fix patch status)
+ * [LibreSSL]
+ * 0x20000000 (a fixed value)
*
* See also the man page OPENSSL_VERSION_NUMBER(3).
*/
@@ -1031,9 +1052,12 @@ Init_openssl(void)
#if defined(LIBRESSL_VERSION_NUMBER)
/*
- * Version number of LibreSSL the ruby OpenSSL extension was built with
- * (base 16). The format is 0xMNNFF00f (major minor fix 00
- * status). This constant is only defined in LibreSSL cases.
+ * LibreSSL library version number used to compile the Ruby/OpenSSL
+ * extension. This may differ from the version used at runtime.
+ *
+ * This constant is only defined if the extension was compiled against
+ * LibreSSL. The number follows the format:
+ * 0xMNNFF00f (major minor fix 00 status).
*
* See also the man page LIBRESSL_VERSION_NUMBER(3).
*/
@@ -1041,7 +1065,11 @@ Init_openssl(void)
#endif
/*
- * Boolean indicating whether OpenSSL is FIPS-capable or not
+ * Boolean indicating whether the \OpenSSL library is FIPS-capable or not.
+ * Always true for \OpenSSL 3.0 and later.
+ *
+ * This is obsolete and will be removed in the future.
+ * See also OpenSSL.fips_mode.
*/
rb_define_const(mOSSL, "OPENSSL_FIPS",
/* OpenSSL 3 is FIPS-capable even when it is installed without fips option */
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 628140a75e3ea4..71a87f04636c98 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -1397,8 +1397,6 @@ void
Init_ossl_asn1(void)
{
#undef rb_intern
- VALUE ary;
- int i;
sym_UNIVERSAL = ID2SYM(rb_intern_const("UNIVERSAL"));
sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const("CONTEXT_SPECIFIC"));
@@ -1548,17 +1546,20 @@ Init_ossl_asn1(void)
rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1);
rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1);
rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1);
- ary = rb_ary_new();
+ VALUE ary = rb_ary_new_capa(ossl_asn1_info_size);
+ for (int i = 0; i < ossl_asn1_info_size; i++) {
+ const char *name = ossl_asn1_info[i].name;
+ if (name[0] == '[')
+ continue;
+ rb_define_const(mASN1, name, INT2NUM(i));
+ rb_ary_store(ary, i, rb_obj_freeze(rb_str_new_cstr(name)));
+ }
+ rb_obj_freeze(ary);
/*
* Array storing tag names at the tag's index.
*/
rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary);
- for(i = 0; i < ossl_asn1_info_size; i++){
- if(ossl_asn1_info[i].name[0] == '[') continue;
- rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i));
- rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name));
- }
/* Document-class: OpenSSL::ASN1::ASN1Data
*
@@ -1880,6 +1881,7 @@ do{\
rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
+ rb_obj_freeze(class_tag_map);
id_each = rb_intern_const("each");
}
diff --git a/ext/openssl/ossl_x509.c b/ext/openssl/ossl_x509.c
index e341ca1fbb4c1c..bc3914fda20d39 100644
--- a/ext/openssl/ossl_x509.c
+++ b/ext/openssl/ossl_x509.c
@@ -13,7 +13,8 @@ VALUE mX509;
#define DefX509Const(x) rb_define_const(mX509, #x, INT2NUM(X509_##x))
#define DefX509Default(x,i) \
- rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i()))
+ rb_define_const(mX509, "DEFAULT_" #x, \
+ rb_obj_freeze(rb_str_new_cstr(X509_get_default_##i())))
ASN1_TIME *
ossl_x509_time_adjust(ASN1_TIME *s, VALUE time)
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index b91c92c1ff9670..5b3c3f7261dc26 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -534,6 +534,7 @@ Init_ossl_x509name(void)
rb_hash_aset(hash, rb_str_new2("DC"), ia5str);
rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str);
rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str);
+ rb_obj_freeze(hash);
/*
* The default object type template for name entries.
diff --git a/prism/prism.c b/prism/prism.c
index 677e65056f8f74..06e692c95ea696 100644
--- a/prism/prism.c
+++ b/prism/prism.c
@@ -8613,7 +8613,7 @@ escape_hexadecimal_digit(const uint8_t value) {
* validated.
*/
static inline uint32_t
-escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
+escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length, const pm_location_t *error_location) {
uint32_t value = 0;
for (size_t index = 0; index < length; index++) {
if (index != 0) value <<= 4;
@@ -8623,7 +8623,11 @@ escape_unicode(pm_parser_t *parser, const uint8_t *string, size_t length) {
// Here we're going to verify that the value is actually a valid Unicode
// codepoint and not a surrogate pair.
if (value >= 0xD800 && value <= 0xDFFF) {
- pm_parser_err(parser, string, string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
+ if (error_location != NULL) {
+ pm_parser_err(parser, error_location->start, error_location->end, PM_ERR_ESCAPE_INVALID_UNICODE);
+ } else {
+ pm_parser_err(parser, string, string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
+ }
return 0xFFFD;
}
@@ -8923,7 +8927,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
extra_codepoints_start = unicode_start;
}
- uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
+ uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL);
escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
@@ -8964,7 +8968,7 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
PM_PARSER_ERR_FORMAT(parser, start, parser->current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
}
} else if (length == 4) {
- uint32_t value = escape_unicode(parser, parser->current.end, 4);
+ uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL);
if (flags & PM_ESCAPE_FLAG_REGEXP) {
pm_buffer_append_bytes(regular_expression_buffer, start, (size_t) (parser->current.end + 4 - start));
@@ -20368,7 +20372,7 @@ pm_named_capture_escape_octal(pm_buffer_t *unescaped, const uint8_t *cursor, con
}
static inline const uint8_t *
-pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end) {
+pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *cursor, const uint8_t *end, const pm_location_t *error_location) {
const uint8_t *start = cursor - 1;
cursor++;
@@ -20379,7 +20383,7 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
if (*cursor != '{') {
size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
- uint32_t value = escape_unicode(parser, cursor, length);
+ uint32_t value = escape_unicode(parser, cursor, length, error_location);
if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
pm_buffer_append_string(unescaped, (const char *) start, (size_t) ((cursor + length) - start));
@@ -20402,7 +20406,7 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
if (length == 0) {
break;
}
- uint32_t value = escape_unicode(parser, cursor, length);
+ uint32_t value = escape_unicode(parser, cursor, length, error_location);
(void) pm_buffer_append_unicode_codepoint(unescaped, value);
cursor += length;
@@ -20412,7 +20416,7 @@ pm_named_capture_escape_unicode(pm_parser_t *parser, pm_buffer_t *unescaped, con
}
static void
-pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *source, const size_t length, const uint8_t *cursor) {
+pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8_t *source, const size_t length, const uint8_t *cursor, const pm_location_t *error_location) {
const uint8_t *end = source + length;
pm_buffer_append_string(unescaped, (const char *) source, (size_t) (cursor - source));
@@ -20430,7 +20434,7 @@ pm_named_capture_escape(pm_parser_t *parser, pm_buffer_t *unescaped, const uint8
cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
break;
case 'u':
- cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
+ cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
break;
default:
pm_buffer_append_byte(unescaped, '\\');
@@ -20473,7 +20477,7 @@ parse_regular_expression_named_capture(const pm_string_t *capture, void *data) {
// unescaped, which is what we need.
const uint8_t *cursor = pm_memchr(source, '\\', length, parser->encoding_changed, parser->encoding);
if (PRISM_UNLIKELY(cursor != NULL)) {
- pm_named_capture_escape(parser, &unescaped, source, length, cursor);
+ pm_named_capture_escape(parser, &unescaped, source, length, cursor, callback_data->shared ? NULL : &call->receiver->location);
source = (const uint8_t *) pm_buffer_value(&unescaped);
length = pm_buffer_length(&unescaped);
}