diff --color -Nuar ruby-3.0.2.orig/ext/openssl/extconf.rb ruby-3.0.2/ext/openssl/extconf.rb
--- ruby-3.0.2.orig/ext/openssl/extconf.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/extconf.rb	2021-09-09 18:27:58.352594254 +0800
@@ -33,9 +33,6 @@
   have_library("ws2_32")
 end
 
-Logging::message "=== Checking for required stuff... ===\n"
-result = pkg_config("openssl") && have_header("openssl/ssl.h")
-
 if $mingw
   append_cflags '-D_FORTIFY_SOURCE=2'
   append_ldflags '-fstack-protector'
@@ -92,19 +89,32 @@
   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
+
+version_ok = if have_macro("LIBRESSL_VERSION_NUMBER", "openssl/opensslv.h")
+  is_libressl = true
+  checking_for("LibreSSL version >= 3.1.0") {
+    try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x30100000L", "openssl/opensslv.h") }
+else
+  checking_for("OpenSSL version >= 1.0.2") {
+    try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10002000L", "openssl/opensslv.h") }
+end
+unless version_ok
+  raise "OpenSSL >= 1.0.2 or LibreSSL >= 3.1.0 is required"
 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"
+# 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"
@@ -116,33 +126,13 @@
   have_func("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")
-have_func("X509_STORE_CTX_get0_store")
-have_func("SSL_CTX_set_alpn_select_cb")
-have_func("SSL_CTX_set1_curves_list(NULL, NULL)", "openssl/ssl.h")
-have_func("SSL_CTX_set_ecdh_auto(NULL, 0)", "openssl/ssl.h")
-have_func("SSL_get_server_tmp_key(NULL, NULL)", "openssl/ssl.h")
-have_func("SSL_is_server")
-
 # added in 1.1.0
-if !have_struct_member("SSL", "ctx", "openssl/ssl.h") ||
-    try_static_assert("LIBRESSL_VERSION_NUMBER >= 0x2070000fL", "openssl/opensslv.h")
+if !have_struct_member("SSL", "ctx", "openssl/ssl.h") || is_libressl
   $defs.push("-DHAVE_OPAQUE_OPENSSL")
 end
-have_func("CRYPTO_lock") || $defs.push("-DHAVE_OPENSSL_110_THREADING_API")
-have_func("BN_GENCB_new")
-have_func("BN_GENCB_free")
-have_func("BN_GENCB_get_arg")
 have_func("EVP_MD_CTX_new")
 have_func("EVP_MD_CTX_free")
-have_func("HMAC_CTX_new")
-have_func("HMAC_CTX_free")
+have_func("EVP_MD_CTX_pkey_ctx")
 have_func("X509_STORE_get_ex_data")
 have_func("X509_STORE_set_ex_data")
 have_func("X509_STORE_get_ex_new_index")
@@ -161,7 +151,6 @@
 have_func("X509_STORE_up_ref")
 have_func("SSL_SESSION_up_ref")
 have_func("EVP_PKEY_up_ref")
-have_func("SSL_CTX_set_tmp_ecdh_callback(NULL, NULL)", "openssl/ssl.h") # removed
 have_func("SSL_CTX_set_min_proto_version(NULL, 0)", "openssl/ssl.h")
 have_func("SSL_CTX_get_security_level")
 have_func("X509_get0_notBefore")
@@ -169,13 +158,27 @@
 have_func("TS_STATUS_INFO_get0_status")
 have_func("TS_STATUS_INFO_get0_text")
 have_func("TS_STATUS_INFO_get0_failure_info")
-have_func("TS_VERIFY_CTS_set_certs")
+have_func("TS_VERIFY_CTS_set_certs(NULL, NULL)", "openssl/ts.h") # became a macro in 3.0.0
 have_func("TS_VERIFY_CTX_set_store")
 have_func("TS_VERIFY_CTX_add_flags")
 have_func("TS_RESP_CTX_set_time_cb")
 have_func("EVP_PBE_scrypt")
 have_func("SSL_CTX_set_post_handshake_auth")
 
+# added in 1.1.1
+have_func("EVP_PKEY_check")
+
+# added in 3.0.0
+have_func("ERR_get_error_all")
+have_func("TS_VERIFY_CTX_set_certs(NULL, NULL)", "openssl/ts.h")
+have_func("SSL_CTX_load_verify_file")
+have_func("BN_check_prime")
+have_func("EVP_MD_CTX_get0_md")
+have_func("EVP_MD_CTX_get_pkey_ctx")
+have_func("EVP_PKEY_todata")
+have_func("EVP_PKEY_dup")
+have_func("EVP_PKEY_eq")
+
 Logging::message "=== Checking done. ===\n"
 
 create_header
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/lib/openssl/buffering.rb ruby-3.0.2/ext/openssl/lib/openssl/buffering.rb
--- ruby-3.0.2.orig/ext/openssl/lib/openssl/buffering.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/lib/openssl/buffering.rb	2021-09-09 18:28:21.072148566 +0800
@@ -99,8 +99,27 @@
     end
   end
 
+  if "".respond_to?(:unpack1)
+    def unpack_byte(str)
+      str.unpack1("C")
+    end
+  else
+    def unpack_byte(str)
+      str.unpack("C").first
+    end
+  end
+
   public
 
+  # call-seq:
+  #   ssl.getbyte => 81
+  #
+  # Get the next 8bit byte from `ssl`.  Returns `nil` on EOF
+  def getbyte
+    byte = read(1)
+    byte && unpack_byte(byte)
+  end
+
   ##
   # Reads _size_ bytes from the stream.  If _buf_ is provided it must
   # reference a string which will receive the data.
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/lib/openssl/hmac.rb ruby-3.0.2/ext/openssl/lib/openssl/hmac.rb
--- ruby-3.0.2.orig/ext/openssl/lib/openssl/hmac.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/lib/openssl/hmac.rb	2021-09-09 18:28:21.072148566 +0800
@@ -9,5 +9,70 @@
 
       OpenSSL.fixed_length_secure_compare(self.digest, other.digest)
     end
+
+    # :call-seq:
+    #    hmac.base64digest -> string
+    #
+    # Returns the authentication code an a Base64-encoded string.
+    def base64digest
+      [digest].pack("m0")
+    end
+
+    class << self
+      # :call-seq:
+      #    HMAC.digest(digest, key, data) -> aString
+      #
+      # Returns the authentication code as a binary string. The _digest_ parameter
+      # specifies the digest algorithm to use. This may be a String representing
+      # the algorithm name or an instance of OpenSSL::Digest.
+      #
+      # === Example
+      #  key = 'key'
+      #  data = 'The quick brown fox jumps over the lazy dog'
+      #
+      #  hmac = OpenSSL::HMAC.digest('SHA1', key, data)
+      #  #=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9"
+      def digest(digest, key, data)
+        hmac = new(key, digest)
+        hmac << data
+        hmac.digest
+      end
+
+      # :call-seq:
+      #    HMAC.hexdigest(digest, key, data) -> aString
+      #
+      # Returns the authentication code as a hex-encoded string. The _digest_
+      # parameter specifies the digest algorithm to use. This may be a String
+      # representing the algorithm name or an instance of OpenSSL::Digest.
+      #
+      # === Example
+      #  key = 'key'
+      #  data = 'The quick brown fox jumps over the lazy dog'
+      #
+      #  hmac = OpenSSL::HMAC.hexdigest('SHA1', key, data)
+      #  #=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
+      def hexdigest(digest, key, data)
+        hmac = new(key, digest)
+        hmac << data
+        hmac.hexdigest
+      end
+
+      # :call-seq:
+      #    HMAC.base64digest(digest, key, data) -> aString
+      #
+      # Returns the authentication code as a Base64-encoded string. The _digest_
+      # parameter specifies the digest algorithm to use. This may be a String
+      # representing the algorithm name or an instance of OpenSSL::Digest.
+      #
+      # === Example
+      #  key = 'key'
+      #  data = 'The quick brown fox jumps over the lazy dog'
+      #
+      #  hmac = OpenSSL::HMAC.base64digest('SHA1', key, data)
+      #  #=> "3nybhbi3iqa8ino29wqQcBydtNk="
+      def base64digest(digest, key, data)
+        [digest(digest, key, data)].pack("m0")
+      end
+    end
   end
 end
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/lib/openssl/pkey.rb ruby-3.0.2/ext/openssl/lib/openssl/pkey.rb
--- ruby-3.0.2.orig/ext/openssl/lib/openssl/pkey.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/lib/openssl/pkey.rb	2021-09-09 18:28:21.072148566 +0800
@@ -9,16 +9,290 @@
 module OpenSSL::PKey
   class DH
     include OpenSSL::Marshal
+
+    def params
+      data = to_data
+      {
+        "p" => data[:p] || 0.to_bn,
+        "q" => data[:q] || 0.to_bn,
+        "g" => data[:g] || 0.to_bn,
+        "pub_key" => data[:pub] || 0.to_bn,
+        "priv_key" => data[:priv] || 0.to_bn,
+      }
+    end
+
+    def p; get_bn_param(:p) end
+    def q; get_bn_param(:q) end
+    def g; get_bn_param(:g) end
+    def pub_key; get_bn_param(:pub) end
+    def priv_key; get_bn_param(:priv) end
+    def get_pqg; [p, q, g] end
+    def get_key; [pub_key, priv_key] end
+
+    # :call-seq:
+    #    dh.public_key -> dhnew
+    #
+    # Returns a new DH instance that carries just the \DH parameters.
+    #
+    # Contrary to the method name, the returned DH object contains only
+    # parameters and not the public key.
+    #
+    # This method is provided for backwards compatibility. In most cases, there
+    # is no need to call this method.
+    #
+    # For the purpose of re-generating the key pair while keeping the
+    # parameters, check OpenSSL::PKey.generate_key.
+    #
+    # Example:
+    #   # OpenSSL::PKey::DH.generate by default generates a random key pair
+    #   dh1 = OpenSSL::PKey::DH.generate(2048)
+    #   p dh1.priv_key #=> #<OpenSSL::BN 1288347...>
+    #   dhcopy = dh1.public_key
+    #   p dhcopy.priv_key #=> nil
+    def public_key
+      DH.new(to_der)
+    end
+
+    # :call-seq:
+    #    dh.compute_key(pub_bn) -> string
+    #
+    # Returns a String containing a shared secret computed from the other
+    # party's public value.
+    #
+    # This method is provided for backwards compatibility, and calls #derive
+    # internally.
+    #
+    # === Parameters
+    # * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by
+    #   DH#public_key as that contains the DH parameters only.
+    def compute_key(pub_bn)
+      peer = dup
+      peer.set_key(pub_bn, nil)
+      derive(peer)
+    end
+
+    # :call-seq:
+    #    dh.generate_key! -> self
+    #
+    # Generates a private and public key unless a private key already exists.
+    # If this DH instance was generated from public \DH parameters (e.g. by
+    # encoding the result of DH#public_key), then this method needs to be
+    # called first in order to generate the per-session keys before performing
+    # the actual key exchange.
+    #
+    # See also OpenSSL::PKey.generate_key.
+    #
+    # Example:
+    #   dh = OpenSSL::PKey::DH.new(2048)
+    #   public_key = dh.public_key #contains no private/public key yet
+    #   public_key.generate_key!
+    #   puts public_key.private? # => true
+    def generate_key!
+      unless priv_key
+        tmp = OpenSSL::PKey.generate_key(self)
+        set_key(tmp.pub_key, tmp.priv_key)
+      end
+      self
+    end
+
+    class << self
+      # :call-seq:
+      #    DH.generate(size, generator = 2) -> dh
+      #
+      # Creates a new DH instance from scratch by generating random parameters
+      # and a key pair.
+      #
+      # See also OpenSSL::PKey.generate_parameters and
+      # OpenSSL::PKey.generate_key.
+      #
+      # +size+::
+      #   The desired key size in bits.
+      # +generator+::
+      #   The generator.
+      def generate(size, generator = 2, &blk)
+        dhparams = OpenSSL::PKey.generate_parameters("DH", {
+          "dh_paramgen_prime_len" => size,
+          "dh_paramgen_generator" => generator,
+        }, &blk)
+        OpenSSL::PKey.generate_key(dhparams)
+      end
+
+      # Handle DH.new(size, generator) form here; new(str) and new() forms
+      # are handled by #initialize
+      def new(*args, &blk) # :nodoc:
+        if args[0].is_a?(Integer)
+          generate(*args, &blk)
+        else
+          super
+        end
+      end
+    end
   end
 
   class DSA
     include OpenSSL::Marshal
+
+    def params
+      data = to_data
+      {
+        "p" => data[:p] || 0.to_bn,
+        "q" => data[:q] || 0.to_bn,
+        "g" => data[:g] || 0.to_bn,
+        "pub_key" => data[:pub] || 0.to_bn,
+        "priv_key" => data[:priv] || 0.to_bn,
+      }
+    end
+
+    def p; get_bn_param(:p) end
+    def q; get_bn_param(:q) end
+    def g; get_bn_param(:g) end
+    def pub_key; get_bn_param(:pub) end
+    def priv_key; get_bn_param(:priv) end
+    def get_pqg; [p, q, g] end
+    def get_key; [pub_key, priv_key] end
+
+    # :call-seq:
+    #    dsa.public_key -> dsanew
+    #
+    # Returns a new DSA instance that carries just the \DSA parameters and the
+    # public key.
+    #
+    # This method is provided for backwards compatibility. In most cases, there
+    # is no need to call this method.
+    #
+    # For the purpose of serializing the public key, to PEM or DER encoding of
+    # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and
+    # PKey#public_to_der.
+    def public_key
+      OpenSSL::PKey.read(public_to_der)
+    end
+
+    class << self
+      # :call-seq:
+      #    DSA.generate(size) -> dsa
+      #
+      # Creates a new DSA instance by generating a private/public key pair
+      # from scratch.
+      #
+      # See also OpenSSL::PKey.generate_parameters and
+      # OpenSSL::PKey.generate_key.
+      #
+      # +size+::
+      #   The desired key size in bits.
+      def generate(size, &blk)
+        dsaparams = OpenSSL::PKey.generate_parameters("DSA", {
+          "dsa_paramgen_bits" => size,
+        }, &blk)
+        OpenSSL::PKey.generate_key(dsaparams)
+      end
+
+      # Handle DSA.new(size) form here; new(str) and new() forms
+      # are handled by #initialize
+      def new(*args, &blk) # :nodoc:
+        if args[0].is_a?(Integer)
+          generate(*args, &blk)
+        else
+          super
+        end
+      end
+    end
+
+    # :call-seq:
+    #    dsa.syssign(string) -> string
+    #
+    # Computes and returns the \DSA signature of +string+, where +string+ is
+    # expected to be an already-computed message digest of the original input
+    # data. The signature is issued using the private key of this DSA instance.
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
+    #
+    # +string+::
+    #   A message digest of the original input data to be signed.
+    #
+    # Example:
+    #   dsa = OpenSSL::PKey::DSA.new(2048)
+    #   doc = "Sign me"
+    #   digest = OpenSSL::Digest.digest('SHA1', doc)
+    #
+    #   # With legacy #syssign and #sysverify:
+    #   sig = dsa.syssign(digest)
+    #   p dsa.sysverify(digest, sig) #=> true
+    #
+    #   # With #sign_raw and #verify_raw:
+    #   sig = dsa.sign_raw(nil, digest)
+    #   p dsa.verify_raw(nil, sig, digest) #=> true
+    def syssign(string)
+      q or raise OpenSSL::PKey::DSAError, "incomplete DSA"
+      private? or raise OpenSSL::PKey::DSAError, "Private DSA key needed!"
+      begin
+        sign_raw(nil, string)
+      rescue OpenSSL::PKey::PKeyError
+        raise OpenSSL::PKey::DSAError, $!.message
+      end
+    end
+
+    # :call-seq:
+    #    dsa.sysverify(digest, sig) -> true | false
+    #
+    # Verifies whether the signature is valid given the message digest input.
+    # It does so by validating +sig+ using the public key of this DSA instance.
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
+    #
+    # +digest+::
+    #   A message digest of the original input data to be signed.
+    # +sig+::
+    #   A \DSA signature value.
+    def sysverify(digest, sig)
+      verify_raw(nil, sig, digest)
+    rescue OpenSSL::PKey::PKeyError
+      raise OpenSSL::PKey::DSAError, $!.message
+    end
   end
 
   if defined?(EC)
   class EC
     include OpenSSL::Marshal
+
+    # :call-seq:
+    #    key.dsa_sign_asn1(data) -> String
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
+    def dsa_sign_asn1(data)
+      sign_raw(nil, data)
+    rescue OpenSSL::PKey::PKeyError
+      raise OpenSSL::PKey::ECError, $!.message
+    end
+
+    # :call-seq:
+    #    key.dsa_verify_asn1(data, sig) -> true | false
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw instead.
+    def dsa_verify_asn1(data, sig)
+      verify_raw(nil, sig, data)
+    rescue OpenSSL::PKey::PKeyError
+      raise OpenSSL::PKey::ECError, $!.message
+    end
+
+    # :call-seq:
+    #    ec.dh_compute_key(pubkey) -> string
+    #
+    # Derives a shared secret by ECDH. _pubkey_ must be an instance of
+    # OpenSSL::PKey::EC::Point and must belong to the same group.
+    #
+    # This method is provided for backwards compatibility, and calls #derive
+    # internally.
+    def dh_compute_key(pubkey)
+      peer = OpenSSL::PKey::EC.new(group)
+      peer.public_key = pubkey
+      derive(peer)
+    end
   end
+
   class EC::Point
     # :call-seq:
     #    point.to_bn([conversion_form]) -> OpenSSL::BN
@@ -38,5 +312,182 @@
 
   class RSA
     include OpenSSL::Marshal
+
+    def params
+      data = to_data
+      {
+        "n" => data[:n] || 0.to_bn,
+        "e" => data[:e] || 0.to_bn,
+        "d" => data[:d] || 0.to_bn,
+        "p" => data[:"rsa-factor1"] || 0.to_bn,
+        "q" => data[:"rsa-factor2"] || 0.to_bn,
+        "dmp1" => data[:"rsa-exponent1"] || 0.to_bn,
+        "dmq1" => data[:"rsa-exponent2"] || 0.to_bn,
+        "iqmp" => data[:"rsa-coefficient1"] || 0.to_bn,
+      }
+    end
+
+    def n; get_bn_param(:n) end
+    def e; get_bn_param(:e) end
+    def d; get_bn_param(:d) end
+    def p; get_bn_param(:"rsa-factor1") end
+    def q; get_bn_param(:"rsa-factor2") end
+    def dmp1; get_bn_param(:"rsa-exponent1") end
+    def dmq1; get_bn_param(:"rsa-exponent2") end
+    def iqmp; get_bn_param(:"rsa-coefficient1") end
+    def get_key; [n, e, d] end
+    def get_factors; [p, q] end
+    def get_crt_params; [dmp1, dmq1, iqmp] end
+
+    # :call-seq:
+    #    rsa.public_key -> rsanew
+    #
+    # Returns a new RSA instance that carries just the public key components.
+    #
+    # This method is provided for backwards compatibility. In most cases, there
+    # is no need to call this method.
+    #
+    # For the purpose of serializing the public key, to PEM or DER encoding of
+    # X.509 SubjectPublicKeyInfo format, check PKey#public_to_pem and
+    # PKey#public_to_der.
+    def public_key
+      OpenSSL::PKey.read(public_to_der)
+    end
+
+    class << self
+      # :call-seq:
+      #    RSA.generate(size, exponent = 65537) -> RSA
+      #
+      # Generates an \RSA keypair.
+      #
+      # See also OpenSSL::PKey.generate_key.
+      #
+      # +size+::
+      #   The desired key size in bits.
+      # +exponent+::
+      #   An odd Integer, normally 3, 17, or 65537.
+      def generate(size, exp = 0x10001, &blk)
+        OpenSSL::PKey.generate_key("RSA", {
+          "rsa_keygen_bits" => size,
+          "rsa_keygen_pubexp" => exp,
+        }, &blk)
+      end
+
+      # Handle RSA.new(size, exponent) form here; new(str) and new() forms
+      # are handled by #initialize
+      def new(*args, &blk) # :nodoc:
+        if args[0].is_a?(Integer)
+          generate(*args, &blk)
+        else
+          super
+        end
+      end
+    end
+
+    # :call-seq:
+    #    rsa.private_encrypt(string)          -> String
+    #    rsa.private_encrypt(string, padding) -> String
+    #
+    # Encrypt +string+ with the private key.  +padding+ defaults to
+    # PKCS1_PADDING. The encrypted string output can be decrypted using
+    # #public_decrypt.
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
+    # PKey::PKey#verify_recover instead.
+    def private_encrypt(string, padding = PKCS1_PADDING)
+      n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
+      private? or raise OpenSSL::PKey::RSAError, "private key needed."
+      begin
+        sign_raw(nil, string, {
+          "rsa_padding_mode" => translate_padding_mode(padding),
+        })
+      rescue OpenSSL::PKey::PKeyError
+        raise OpenSSL::PKey::RSAError, $!.message
+      end
+    end
+
+    # :call-seq:
+    #    rsa.public_decrypt(string)          -> String
+    #    rsa.public_decrypt(string, padding) -> String
+    #
+    # Decrypt +string+, which has been encrypted with the private key, with the
+    # public key.  +padding+ defaults to PKCS1_PADDING.
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#sign_raw and PKey::PKey#verify_raw, and
+    # PKey::PKey#verify_recover instead.
+    def public_decrypt(string, padding = PKCS1_PADDING)
+      n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
+      begin
+        verify_recover(nil, string, {
+          "rsa_padding_mode" => translate_padding_mode(padding),
+        })
+      rescue OpenSSL::PKey::PKeyError
+        raise OpenSSL::PKey::RSAError, $!.message
+      end
+    end
+
+    # :call-seq:
+    #    rsa.public_encrypt(string)          -> String
+    #    rsa.public_encrypt(string, padding) -> String
+    #
+    # Encrypt +string+ with the public key.  +padding+ defaults to
+    # PKCS1_PADDING. The encrypted string output can be decrypted using
+    # #private_decrypt.
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
+    def public_encrypt(data, padding = PKCS1_PADDING)
+      n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
+      begin
+        encrypt(data, {
+          "rsa_padding_mode" => translate_padding_mode(padding),
+        })
+      rescue OpenSSL::PKey::PKeyError
+        raise OpenSSL::PKey::RSAError, $!.message
+      end
+    end
+
+    # :call-seq:
+    #    rsa.private_decrypt(string)          -> String
+    #    rsa.private_decrypt(string, padding) -> String
+    #
+    # Decrypt +string+, which has been encrypted with the public key, with the
+    # private key. +padding+ defaults to PKCS1_PADDING.
+    #
+    # <b>Deprecated in version 3.0</b>.
+    # Consider using PKey::PKey#encrypt and PKey::PKey#decrypt instead.
+    def private_decrypt(data, padding = PKCS1_PADDING)
+      n or raise OpenSSL::PKey::RSAError, "incomplete RSA"
+      private? or raise OpenSSL::PKey::RSAError, "private key needed."
+      begin
+        decrypt(data, {
+          "rsa_padding_mode" => translate_padding_mode(padding),
+        })
+      rescue OpenSSL::PKey::PKeyError
+        raise OpenSSL::PKey::RSAError, $!.message
+      end
+    end
+
+    PKCS1_PADDING = 1
+    SSLV23_PADDING = 2
+    NO_PADDING = 3
+    PKCS1_OAEP_PADDING = 4
+
+    private def translate_padding_mode(num)
+      case num
+      when PKCS1_PADDING
+        "pkcs1"
+      when SSLV23_PADDING
+        "sslv23"
+      when NO_PADDING
+        "none"
+      when PKCS1_OAEP_PADDING
+        "oaep"
+      else
+        raise OpenSSL::PKey::PKeyError, "unsupported padding mode"
+      end
+    end
   end
 end
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/lib/openssl/ssl.rb ruby-3.0.2/ext/openssl/lib/openssl/ssl.rb
--- ruby-3.0.2.orig/ext/openssl/lib/openssl/ssl.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/lib/openssl/ssl.rb	2021-09-09 18:28:21.072148566 +0800
@@ -122,6 +122,8 @@
       def initialize(version = nil)
         self.options |= OpenSSL::SSL::OP_ALL
         self.ssl_version = version if version
+        self.verify_mode = OpenSSL::SSL::VERIFY_NONE
+        self.verify_hostname = false
       end
 
       ##
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/lib/openssl/x509.rb ruby-3.0.2/ext/openssl/lib/openssl/x509.rb
--- ruby-3.0.2.orig/ext/openssl/lib/openssl/x509.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/lib/openssl/x509.rb	2021-09-09 18:28:21.072148566 +0800
@@ -338,6 +338,10 @@
           q.text 'not_after='; q.pp self.not_after
         }
       end
+      
+      def self.load_file(path)
+        load(File.binread(path))
+      end
     end
 
     class CRL
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/lib/openssl.rb ruby-3.0.2/ext/openssl/lib/openssl.rb
--- ruby-3.0.2.orig/ext/openssl/lib/openssl.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/lib/openssl.rb	2021-09-09 18:28:21.072148566 +0800
@@ -15,7 +15,6 @@
 require_relative 'openssl/bn'
 require_relative 'openssl/pkey'
 require_relative 'openssl/cipher'
-require_relative 'openssl/config'
 require_relative 'openssl/digest'
 require_relative 'openssl/hmac'
 require_relative 'openssl/x509'
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/openssl_missing.c ruby-3.0.2/ext/openssl/openssl_missing.c
--- ruby-3.0.2.orig/ext/openssl/openssl_missing.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/openssl_missing.c	2021-09-09 18:27:58.353594278 +0800
@@ -10,77 +10,11 @@
 #include RUBY_EXTCONF_H
 
 #include <string.h> /* memcpy() */
-#if !defined(OPENSSL_NO_ENGINE)
-# include <openssl/engine.h>
-#endif
-#if !defined(OPENSSL_NO_HMAC)
-# include <openssl/hmac.h>
-#endif
 #include <openssl/x509_vfy.h>
 
 #include "openssl_missing.h"
 
-/* added in 1.0.2 */
-#if !defined(OPENSSL_NO_EC)
-#if !defined(HAVE_EC_CURVE_NIST2NID)
-static struct {
-    const char *name;
-    int nid;
-} nist_curves[] = {
-    {"B-163", NID_sect163r2},
-    {"B-233", NID_sect233r1},
-    {"B-283", NID_sect283r1},
-    {"B-409", NID_sect409r1},
-    {"B-571", NID_sect571r1},
-    {"K-163", NID_sect163k1},
-    {"K-233", NID_sect233k1},
-    {"K-283", NID_sect283k1},
-    {"K-409", NID_sect409k1},
-    {"K-571", NID_sect571k1},
-    {"P-192", NID_X9_62_prime192v1},
-    {"P-224", NID_secp224r1},
-    {"P-256", NID_X9_62_prime256v1},
-    {"P-384", NID_secp384r1},
-    {"P-521", NID_secp521r1}
-};
-
-int
-ossl_EC_curve_nist2nid(const char *name)
-{
-    size_t i;
-    for (i = 0; i < (sizeof(nist_curves) / sizeof(nist_curves[0])); i++) {
-	if (!strcmp(nist_curves[i].name, name))
-	    return nist_curves[i].nid;
-    }
-    return NID_undef;
-}
-#endif
-#endif
-
 /*** added in 1.1.0 ***/
-#if !defined(HAVE_HMAC_CTX_NEW)
-HMAC_CTX *
-ossl_HMAC_CTX_new(void)
-{
-    HMAC_CTX *ctx = OPENSSL_malloc(sizeof(HMAC_CTX));
-    if (!ctx)
-	return NULL;
-    HMAC_CTX_init(ctx);
-    return ctx;
-}
-#endif
-
-#if !defined(HAVE_HMAC_CTX_FREE)
-void
-ossl_HMAC_CTX_free(HMAC_CTX *ctx)
-{
-    if (ctx) {
-	HMAC_CTX_cleanup(ctx);
-	OPENSSL_free(ctx);
-    }
-}
-#endif
-
 #if !defined(HAVE_X509_CRL_GET0_SIGNATURE)
 void
 ossl_X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig,
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/openssl_missing.h ruby-3.0.2/ext/openssl/openssl_missing.h
--- ruby-3.0.2.orig/ext/openssl/openssl_missing.h	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/openssl_missing.h	2021-09-09 18:27:58.353594278 +0800
@@ -12,40 +12,7 @@
 
 #include "ruby/config.h"
 
-/* added in 1.0.2 */
-#if !defined(OPENSSL_NO_EC)
-#if !defined(HAVE_EC_CURVE_NIST2NID)
-int ossl_EC_curve_nist2nid(const char *);
-#  define EC_curve_nist2nid ossl_EC_curve_nist2nid
-#endif
-#endif
-
-#if !defined(HAVE_X509_REVOKED_DUP)
-# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((i2d_of_void *)i2d_X509_REVOKED, \
-	(d2i_of_void *)d2i_X509_REVOKED, (char *)(rev))
-#endif
-
-#if !defined(HAVE_X509_STORE_CTX_GET0_STORE)
-#  define X509_STORE_CTX_get0_store(x) ((x)->ctx)
-#endif
-
-#if !defined(HAVE_SSL_IS_SERVER)
-#  define SSL_is_server(s) ((s)->server)
-#endif
-
 /* added in 1.1.0 */
-#if !defined(HAVE_BN_GENCB_NEW)
-#  define BN_GENCB_new() ((BN_GENCB *)OPENSSL_malloc(sizeof(BN_GENCB)))
-#endif
-
-#if !defined(HAVE_BN_GENCB_FREE)
-#  define BN_GENCB_free(cb) OPENSSL_free(cb)
-#endif
-
-#if !defined(HAVE_BN_GENCB_GET_ARG)
-#  define BN_GENCB_get_arg(cb) (cb)->arg
-#endif
-
 #if !defined(HAVE_EVP_MD_CTX_NEW)
 #  define EVP_MD_CTX_new EVP_MD_CTX_create
 #endif
@@ -54,16 +21,6 @@
 #  define EVP_MD_CTX_free EVP_MD_CTX_destroy
 #endif
 
-#if !defined(HAVE_HMAC_CTX_NEW)
-HMAC_CTX *ossl_HMAC_CTX_new(void);
-#  define HMAC_CTX_new ossl_HMAC_CTX_new
-#endif
-
-#if !defined(HAVE_HMAC_CTX_FREE)
-void ossl_HMAC_CTX_free(HMAC_CTX *);
-#  define HMAC_CTX_free ossl_HMAC_CTX_free
-#endif
-
 #if !defined(HAVE_X509_STORE_GET_EX_DATA)
 #  define X509_STORE_get_ex_data(x, idx) \
 	CRYPTO_get_ex_data(&(x)->ex_data, (idx))
@@ -147,8 +104,7 @@
 	CRYPTO_add(&(x)->references, 1, CRYPTO_LOCK_EVP_PKEY);
 #endif
 
-#if !defined(HAVE_OPAQUE_OPENSSL) && \
-    (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL)
+#if !defined(HAVE_OPAQUE_OPENSSL)
 #define IMPL_PKEY_GETTER(_type, _name) \
 static inline _type *EVP_PKEY_get0_##_type(EVP_PKEY *pkey) { \
 	return pkey->pkey._name; }
@@ -254,4 +210,29 @@
     } while (0)
 #endif
 
+/* added in 3.0.0 */
+#if !defined(HAVE_TS_VERIFY_CTX_SET_CERTS)
+#  define TS_VERIFY_CTX_set_certs(ctx, crts) TS_VERIFY_CTS_set_certs(ctx, crts)
+#endif
+
+#ifndef HAVE_EVP_MD_CTX_GET0_MD
+#  define EVP_MD_CTX_get0_md(ctx) EVP_MD_CTX_md(ctx)
+#endif
+
+/*
+ * OpenSSL 1.1.0 added EVP_MD_CTX_pkey_ctx(), and then it was renamed to
+ * EVP_MD_CTX_get_pkey_ctx(x) in OpenSSL 3.0.
+ */
+#ifndef HAVE_EVP_MD_CTX_GET_PKEY_CTX
+# ifdef HAVE_EVP_MD_CTX_PKEY_CTX
+#  define EVP_MD_CTX_get_pkey_ctx(x) EVP_MD_CTX_pkey_ctx(x)
+# else
+#  define EVP_MD_CTX_get_pkey_ctx(x) (x)->pctx
+# endif
+#endif
+
+#ifndef HAVE_EVP_PKEY_EQ
+#  define EVP_PKEY_eq(a, b) EVP_PKEY_cmp(a, b)
+#endif
+
 #endif /* _OSSL_OPENSSL_MISSING_H_ */
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_asn1.c ruby-3.0.2/ext/openssl/ossl_asn1.c
--- ruby-3.0.2.orig/ext/openssl/ossl_asn1.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_asn1.c	2021-09-09 18:27:58.353594278 +0800
@@ -1510,7 +1510,7 @@
      *
      * An Array that stores the name of a given tag number. These names are
      * the same as the name of the tag constant that is additionally defined,
-     * e.g. UNIVERSAL_TAG_NAME[2] = "INTEGER" and OpenSSL::ASN1::INTEGER = 2.
+     * e.g. +UNIVERSAL_TAG_NAME[2] = "INTEGER"+ and +OpenSSL::ASN1::INTEGER = 2+.
      *
      * == Example usage
      *
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_bn.c ruby-3.0.2/ext/openssl/ossl_bn.c
--- ruby-3.0.2.orig/ext/openssl/ossl_bn.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_bn.c	2021-09-09 18:27:58.353594278 +0800
@@ -10,7 +10,7 @@
 /* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
 #include "ossl.h"
 
-#if HAVE_RB_EXT_RACTOR_SAFE
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
 #include <ruby/ractor.h>
 #endif
 
@@ -74,6 +74,23 @@
     return obj;
 }
 
+#ifdef HAVE_EVP_PKEY_TODATA
+VALUE
+ossl_bn_new_from_native(const void *data, size_t data_size)
+{
+    BIGNUM *bn;
+    VALUE obj;
+
+    obj = NewBN(cBN);
+    bn = BN_native2bn(data, data_size, NULL);
+    if (!bn)
+        ossl_raise(eBNError, "BN_native2bn");
+    SetBN(obj, bn);
+
+    return obj;
+}
+#endif
+
 static BIGNUM *
 integer_to_bnptr(VALUE obj, BIGNUM *orig)
 {
@@ -155,7 +172,7 @@
  * Private
  */
 
-#if HAVE_RB_EXT_RACTOR_SAFE
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
 void
 ossl_bn_ctx_free(void *ptr)
 {
@@ -223,12 +240,29 @@
 
 /*
  * call-seq:
- *    OpenSSL::BN.new(bn) => aBN
- *    OpenSSL::BN.new(integer) => aBN
- *    OpenSSL::BN.new(string) => aBN
- *    OpenSSL::BN.new(string, 0 | 2 | 10 | 16) => aBN
+ *    OpenSSL::BN.new(bn) -> aBN
+ *    OpenSSL::BN.new(integer) -> aBN
+ *    OpenSSL::BN.new(string, base = 10) -> aBN
  *
- * Construct a new OpenSSL BIGNUM object.
+ * Construct a new \OpenSSL BIGNUM object.
+ *
+ * If +bn+ is an Integer or OpenSSL::BN, a new instance of OpenSSL::BN
+ * representing the same value is returned. See also Integer#to_bn for the
+ * short-hand.
+ *
+ * If a String is given, the content will be parsed according to +base+.
+ *
+ * +string+::
+ *   The string to be parsed.
+ * +base+::
+ *   The format. Must be one of the following:
+ *   - +0+  - MPI format. See the man page BN_mpi2bn(3) for details.
+ *   - +2+  - Variable-length and big-endian binary encoding of a positive
+ *     number.
+ *   - +10+ - Decimal number representation, with a leading '-' for a negative
+ *     number.
+ *   - +16+ - Hexadeciaml number representation, with a leading '-' for a
+ *     negative number.
  */
 static VALUE
 ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
@@ -296,16 +330,21 @@
 
 /*
  * call-seq:
- *    bn.to_s => string
- *    bn.to_s(base) => string
+ *    bn.to_s(base = 10) -> string
  *
- * === Parameters
- * * _base_ - Integer
- *   Valid values:
- *   * 0 - MPI
- *   * 2 - binary
- *   * 10 - the default
- *   * 16 - hex
+ * Returns the string representation of the bignum.
+ *
+ * BN.new can parse the encoded string to convert back into an OpenSSL::BN.
+ *
+ * +base+::
+ *   The format. Must be one of the following:
+ *   - +0+  - MPI format. See the man page BN_bn2mpi(3) for details.
+ *   - +2+  - Variable-length and big-endian binary encoding. The sign of
+ *     the bignum is ignored.
+ *   - +10+ - Decimal number representation, with a leading '-' for a negative
+ *     bignum.
+ *   - +16+ - Hexadeciaml number representation, with a leading '-' for a
+ *     negative bignum.
  */
 static VALUE
 ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
@@ -453,7 +492,7 @@
 	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);			\
 	}						\
@@ -479,7 +518,7 @@
 	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);			\
 	}						\
@@ -512,7 +551,7 @@
 	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);				\
 	}							\
@@ -556,11 +595,21 @@
 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:
@@ -609,7 +658,7 @@
 	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);				\
 	}							\
@@ -651,7 +700,7 @@
     {							\
 	BIGNUM *bn;					\
 	GetBN(self, bn);				\
-	if (!BN_##func(bn, NUM2INT(bit))) {		\
+	if (BN_##func(bn, NUM2INT(bit)) <= 0) {		\
 	    ossl_raise(eBNError, NULL);			\
 	}						\
 	return self;					\
@@ -711,7 +760,7 @@
 	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);		\
 	}						\
@@ -741,7 +790,7 @@
 	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;					\
     }
@@ -780,7 +829,7 @@
 	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);				\
 	}							\
@@ -794,12 +843,6 @@
  */
 BIGNUM_RAND(rand)
 
-/*
- * Document-method: OpenSSL::BN.pseudo_rand
- *   BN.pseudo_rand(bits [, fill [, odd]]) -> aBN
- */
-BIGNUM_RAND(pseudo_rand)
-
 #define BIGNUM_RAND_RANGE(func)					\
     static VALUE						\
     ossl_bn_s_##func##_range(VALUE klass, VALUE range)		\
@@ -809,7 +852,7 @@
 	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);				\
 	}							\
@@ -826,14 +869,6 @@
 BIGNUM_RAND_RANGE(rand)
 
 /*
- * Document-method: OpenSSL::BN.pseudo_rand_range
- * call-seq:
- *   BN.pseudo_rand_range(range) -> aBN
- *
- */
-BIGNUM_RAND_RANGE(pseudo_rand)
-
-/*
  * call-seq:
  *    BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn
  *
@@ -926,7 +961,17 @@
 static VALUE
 ossl_bn_uplus(VALUE self)
 {
-    return self;
+    VALUE obj;
+    BIGNUM *bn1, *bn2;
+
+    GetBN(self, bn1);
+    obj = NewBN(cBN);
+    bn2 = BN_dup(bn1);
+    if (!bn2)
+	ossl_raise(eBNError, "BN_dup");
+    SetBN(obj, bn2);
+
+    return obj;
 }
 
 /*
@@ -950,6 +995,24 @@
     return obj;
 }
 
+/*
+ * call-seq:
+ *   bn.abs -> aBN
+ */
+static VALUE
+ossl_bn_abs(VALUE self)
+{
+    BIGNUM *bn1;
+
+    GetBN(self, bn1);
+    if (BN_is_negative(bn1)) {
+        return ossl_bn_uminus(self);
+    }
+    else {
+        return ossl_bn_uplus(self);
+    }
+}
+
 #define BIGNUM_CMP(func)				\
     static VALUE					\
     ossl_bn_##func(VALUE self, VALUE other)		\
@@ -1058,34 +1121,29 @@
  *    bn.prime? => true | false
  *    bn.prime?(checks) => true | false
  *
- * Performs a Miller-Rabin probabilistic primality test with _checks_
- * iterations. If _checks_ is not specified, a number of iterations is used
- * that yields a false positive rate of at most 2^-80 for random input.
+ * Performs Miller-Rabin primality test for _bn_.
  *
- * === Parameters
- * * _checks_ - integer
+ * As of Ruby/OpenSSL 2.3.0, the argument _checks_ is ignored.
  */
 static VALUE
 ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
 {
     BIGNUM *bn;
-    VALUE vchecks;
-    int checks = BN_prime_checks;
+    int ret;
 
-    if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {
-	checks = NUM2INT(vchecks);
-    }
+    rb_check_arity(argc, 0, 1);
     GetBN(self, bn);
-    switch (BN_is_prime_ex(bn, checks, ossl_bn_ctx, NULL)) {
-    case 1:
-	return Qtrue;
-    case 0:
-	return Qfalse;
-    default:
-	ossl_raise(eBNError, NULL);
-    }
-    /* not reachable */
-    return Qnil;
+
+#if defined(HAVE_BN_CHECK_PRIME)
+    ret = BN_check_prime(bn, ossl_bn_ctx, NULL);
+    if (ret < 0)
+        ossl_raise(eBNError, "BN_check_prime");
+#else
+    ret = BN_is_prime_fasttest_ex(bn, BN_prime_checks, ossl_bn_ctx, 1, NULL);
+    if (ret < 0)
+        ossl_raise(eBNError, "BN_is_prime_fasttest_ex");
+#endif
+    return ret ? Qtrue : Qfalse;
 }
 
 /*
@@ -1094,39 +1152,53 @@
  *    bn.prime_fasttest?(checks) => true | false
  *    bn.prime_fasttest?(checks, trial_div) => true | false
  *
- * Performs a Miller-Rabin primality test. This is same as #prime? except this
- * first attempts trial divisions with some small primes.
+ * Performs Miller-Rabin primality test for _bn_. This is an alias of #prime?.
  *
- * === Parameters
- * * _checks_ - integer
- * * _trial_div_ - boolean
+ * This method is deprecated. Use #prime? instead.
+ *
+ * As of Ruby/OpenSSL 2.3.0, the arguments _checks_ and _trial\_div_ are
+ * ignored.
  */
 static VALUE
 ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
 {
+    rb_check_arity(argc, 0, 2);
+    return ossl_bn_is_prime(0, argv, self);
+}
+
+/*
+ * call-seq:
+ *    bn.get_flags(flags) => flags
+ *
+ * Returns the flags on the BN object.
+ * The argument is used as a bit mask.
+ *
+ * === Parameters
+ * * _flags_ - integer
+ */
+static VALUE
+ossl_bn_get_flags(VALUE self, VALUE arg)
+{
     BIGNUM *bn;
-    VALUE vchecks, vtrivdiv;
-    int checks = BN_prime_checks, do_trial_division = 1;
+    GetBN(self, bn);
 
-    rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
+    return INT2NUM(BN_get_flags(bn, NUM2INT(arg)));
+}
 
-    if (!NIL_P(vchecks)) {
-	checks = NUM2INT(vchecks);
-    }
+/*
+ * call-seq:
+ *    bn.set_flags(flags) => nil
+ *
+ * Enables the flags on the BN object.
+ * Currently, the flags argument can contain zero of OpenSSL::BN::CONSTTIME.
+ */
+static VALUE
+ossl_bn_set_flags(VALUE self, VALUE arg)
+{
+    BIGNUM *bn;
     GetBN(self, bn);
-    /* handle true/false */
-    if (vtrivdiv == Qfalse) {
-	do_trial_division = 0;
-    }
-    switch (BN_is_prime_fasttest_ex(bn, checks, ossl_bn_ctx, do_trial_division, NULL)) {
-    case 1:
-	return Qtrue;
-    case 0:
-	return Qfalse;
-    default:
-	ossl_raise(eBNError, NULL);
-    }
-    /* not reachable */
+
+    BN_set_flags(bn, NUM2INT(arg));
     return Qnil;
 }
 
@@ -1166,6 +1238,7 @@
 
     rb_define_method(cBN, "+@", ossl_bn_uplus, 0);
     rb_define_method(cBN, "-@", ossl_bn_uminus, 0);
+    rb_define_method(cBN, "abs", ossl_bn_abs, 0);
 
     rb_define_method(cBN, "+", ossl_bn_add, 1);
     rb_define_method(cBN, "-", ossl_bn_sub, 1);
@@ -1209,9 +1282,9 @@
      * get_word */
 
     rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1);
-    rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
     rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
-    rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
+    rb_define_alias(rb_singleton_class(cBN), "pseudo_rand", "rand");
+    rb_define_alias(rb_singleton_class(cBN), "pseudo_rand_range", "rand_range");
 
     rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
     rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
@@ -1228,6 +1301,23 @@
     /* lshift1 - DON'T IMPL. */
     /* rshift1 - DON'T IMPL. */
 
+    rb_define_method(cBN, "get_flags", ossl_bn_get_flags, 1);
+    rb_define_method(cBN, "set_flags", ossl_bn_set_flags, 1);
+
+#ifdef BN_FLG_CONSTTIME
+    rb_define_const(cBN, "CONSTTIME", INT2NUM(BN_FLG_CONSTTIME));
+#endif
+    /* BN_FLG_MALLOCED and BN_FLG_STATIC_DATA seems for C programming.
+     * Allowing them leads to memory leak.
+     * So, for now, they are not exported
+#ifdef BN_FLG_MALLOCED
+    rb_define_const(cBN, "MALLOCED", INT2NUM(BN_FLG_MALLOCED));
+#endif
+#ifdef BN_FLG_STATIC_DATA
+    rb_define_const(cBN, "STATIC_DATA", INT2NUM(BN_FLG_STATIC_DATA));
+#endif
+    */
+
     /*
      * bn2bin
      * bin2bn
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_bn.h ruby-3.0.2/ext/openssl/ossl_bn.h
--- ruby-3.0.2.orig/ext/openssl/ossl_bn.h	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_bn.h	2021-09-09 18:27:58.353594278 +0800
@@ -19,6 +19,9 @@
 #define GetBNPtr(obj) ossl_bn_value_ptr(&(obj))
 
 VALUE ossl_bn_new(const BIGNUM *);
+#ifdef HAVE_EVP_PKEY_TODATA
+VALUE ossl_bn_new_from_native(const void *data, size_t data_size);
+#endif
 BIGNUM *ossl_bn_value_ptr(volatile VALUE *);
 void Init_ossl_bn(void);
 
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl.c ruby-3.0.2/ext/openssl/ossl.c
--- ruby-3.0.2.orig/ext/openssl/ossl.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl.c	2021-09-09 18:27:58.353594278 +0800
@@ -9,7 +9,13 @@
  */
 #include "ossl.h"
 #include <stdarg.h> /* for ossl_raise */
-#include <ruby/thread_native.h> /* for OpenSSL < 1.1.0 locks */
+
+/* OpenSSL >= 1.1.0 and LibreSSL >= 2.9.0 */
+#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER >= 0x10100000
+# define HAVE_OPENSSL_110_THREADING_API
+#else
+# include <ruby/thread_native.h>
+#endif
 
 /*
  * Data Conversion
@@ -304,27 +310,29 @@
 ossl_clear_error(void)
 {
     if (dOSSL == Qtrue) {
-	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);
-	    }
-	}
+        unsigned long e;
+        const char *file, *data;
+        int line, flags;
+
+#if defined(HAVE_ERR_GET_ERROR_ALL)
+        const char *func;
+        while ((e = ERR_get_error_all(&file, &line, &func, &data, &flags))) {
+#else
+            while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) {
+            const char *func = ERR_func_error_string(e);
+#endif
+            const char *lib = ERR_lib_error_string(e),
+                  *reason = ERR_reason_error_string(e);
+            char append[256] = "";
+
+            if (flags & ERR_TXT_STRING && data && strlen(data))
+                snprintf(append, sizeof(append), " (%s)", data);
+            rb_warn("error on stack: error:%08lX:%s:%s:%s%s", e, lib ? lib : "",
+                    func ? func : "", reason ? reason : "", append);
+        }
     }
     else {
-	ERR_clear_error();
+        ERR_clear_error();
     }
 }
 
@@ -386,7 +394,7 @@
  * call-seq:
  *   OpenSSL.debug = boolean -> boolean
  *
- * Turns on or off debug mode. With debug mode, all erros 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
@@ -667,7 +675,7 @@
  * ahold of the key may use it unless it is encrypted.  In order to securely
  * export a key you may export it with a pass phrase.
  *
- *   cipher = OpenSSL::Cipher.new 'AES-256-CBC'
+ *   cipher = OpenSSL::Cipher.new 'aes-256-cbc'
  *   pass_phrase = 'my secure pass phrase goes here'
  *
  *   key_secure = key.export cipher, pass_phrase
@@ -682,13 +690,13 @@
  *
  * A key can also be loaded from a file.
  *
- *   key2 = OpenSSL::PKey::RSA.new File.read 'private_key.pem'
+ *   key2 = OpenSSL::PKey.read File.read 'private_key.pem'
  *   key2.public? # => true
  *   key2.private? # => true
  *
  * or
  *
- *   key3 = OpenSSL::PKey::RSA.new File.read 'public_key.pem'
+ *   key3 = OpenSSL::PKey.read File.read 'public_key.pem'
  *   key3.public? # => true
  *   key3.private? # => false
  *
@@ -700,7 +708,7 @@
  *
  *   key4_pem = File.read 'private.secure.pem'
  *   pass_phrase = 'my secure pass phrase goes here'
- *   key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase
+ *   key4 = OpenSSL::PKey.read key4_pem, pass_phrase
  *
  * == RSA Encryption
  *
@@ -775,7 +783,7 @@
  * using PBKDF2. PKCS #5 v2.0 recommends at least 8 bytes for the salt,
  * the number of iterations largely depends on the hardware being used.
  *
- *   cipher = OpenSSL::Cipher.new 'AES-256-CBC'
+ *   cipher = OpenSSL::Cipher.new 'aes-256-cbc'
  *   cipher.encrypt
  *   iv = cipher.random_iv
  *
@@ -798,7 +806,7 @@
  * Use the same steps as before to derive the symmetric AES key, this time
  * setting the Cipher up for decryption.
  *
- *   cipher = OpenSSL::Cipher.new 'AES-256-CBC'
+ *   cipher = OpenSSL::Cipher.new 'aes-256-cbc'
  *   cipher.decrypt
  *   cipher.iv = iv # the one generated with #random_iv
  *
@@ -833,7 +841,7 @@
  *
  * First set up the cipher for encryption
  *
- *   encryptor = OpenSSL::Cipher.new 'AES-256-CBC'
+ *   encryptor = OpenSSL::Cipher.new 'aes-256-cbc'
  *   encryptor.encrypt
  *   encryptor.pkcs5_keyivgen pass_phrase, salt
  *
@@ -846,7 +854,7 @@
  *
  * Use a new Cipher instance set up for decryption
  *
- *   decryptor = OpenSSL::Cipher.new 'AES-256-CBC'
+ *   decryptor = OpenSSL::Cipher.new 'aes-256-cbc'
  *   decryptor.decrypt
  *   decryptor.pkcs5_keyivgen pass_phrase, salt
  *
@@ -934,7 +942,7 @@
  *   ca_key = OpenSSL::PKey::RSA.new 2048
  *   pass_phrase = 'my secure pass phrase goes here'
  *
- *   cipher = OpenSSL::Cipher.new 'AES-256-CBC'
+ *   cipher = OpenSSL::Cipher.new 'aes-256-cbc'
  *
  *   open 'ca_key.pem', 'w', 0400 do |io|
  *     io.write ca_key.export(cipher, pass_phrase)
@@ -1072,13 +1080,13 @@
  *   loop do
  *     ssl_connection = ssl_server.accept
  *
- *     data = connection.gets
+ *     data = ssl_connection.gets
  *
  *     response = "I got #{data.dump}"
  *     puts response
  *
- *     connection.puts "I got #{data.dump}"
- *     connection.close
+ *     ssl_connection.puts "I got #{data.dump}"
+ *     ssl_connection.close
  *   end
  *
  * === SSL client
@@ -1129,7 +1137,7 @@
 void
 Init_openssl(void)
 {
-#if HAVE_RB_EXT_RACTOR_SAFE
+#ifdef HAVE_RB_EXT_RACTOR_SAFE
     rb_ext_ractor_safe(true);
 #endif
 
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_cipher.c ruby-3.0.2/ext/openssl/ossl_cipher.c
--- ruby-3.0.2.orig/ext/openssl/ossl_cipher.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_cipher.c	2021-09-09 18:27:58.353594278 +0800
@@ -104,7 +104,7 @@
  *  call-seq:
  *     Cipher.new(string) -> cipher
  *
- *  The string must contain a valid cipher name like "AES-256-CBC".
+ *  The string must contain a valid cipher name like "aes-256-cbc".
  *
  *  A list of cipher names is available by calling OpenSSL::Cipher.ciphers.
  */
@@ -814,6 +814,31 @@
 }
 
 /*
+ *  call-seq:
+ *     cipher.ccm_data_len = integer -> integer
+ *
+ *  Sets the length of the plaintext / ciphertext message that will be
+ *  processed in CCM mode. Make sure to call this method after #key= and
+ *  #iv= have been set, and before #auth_data=.
+ *
+ *  Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ */
+static VALUE
+ossl_cipher_set_ccm_data_len(VALUE self, VALUE data_len)
+{
+    int in_len, out_len;
+    EVP_CIPHER_CTX *ctx;
+
+    in_len = NUM2INT(data_len);
+
+    GetCipher(self, ctx);
+    if (EVP_CipherUpdate(ctx, NULL, &out_len, NULL, in_len) != 1)
+        ossl_raise(eCipherError, NULL);
+
+    return data_len;
+}
+
+/*
  * INIT
  */
 void
@@ -849,7 +874,7 @@
      * individual components name, key length and mode. Either all uppercase
      * or all lowercase strings may be used, for example:
      *
-     *  cipher = OpenSSL::Cipher.new('AES-128-CBC')
+     *  cipher = OpenSSL::Cipher.new('aes-128-cbc')
      *
      * === Choosing either encryption or decryption mode
      *
@@ -879,7 +904,7 @@
      * without processing the password further. A simple and secure way to
      * create a key for a particular Cipher is
      *
-     *  cipher = OpenSSL::Cipher.new('AES-256-CFB')
+     *  cipher = OpenSSL::Cipher.new('aes-256-cfb')
      *  cipher.encrypt
      *  key = cipher.random_key # also sets the generated key on the Cipher
      *
@@ -947,14 +972,14 @@
      *
      *   data = "Very, very confidential data"
      *
-     *   cipher = OpenSSL::Cipher.new('AES-128-CBC')
+     *   cipher = OpenSSL::Cipher.new('aes-128-cbc')
      *   cipher.encrypt
      *   key = cipher.random_key
      *   iv = cipher.random_iv
      *
      *   encrypted = cipher.update(data) + cipher.final
      *   ...
-     *   decipher = OpenSSL::Cipher.new('AES-128-CBC')
+     *   decipher = OpenSSL::Cipher.new('aes-128-cbc')
      *   decipher.decrypt
      *   decipher.key = key
      *   decipher.iv = iv
@@ -990,7 +1015,7 @@
      * not to reuse the _key_ and _nonce_ pair. Reusing an nonce ruins the
      * security guarantees of GCM mode.
      *
-     *   cipher = OpenSSL::Cipher.new('AES-128-GCM').encrypt
+     *   cipher = OpenSSL::Cipher.new('aes-128-gcm').encrypt
      *   cipher.key = key
      *   cipher.iv = nonce
      *   cipher.auth_data = auth_data
@@ -1006,7 +1031,7 @@
      * ciphertext with a probability of 1/256.
      *
      *   raise "tag is truncated!" unless tag.bytesize == 16
-     *   decipher = OpenSSL::Cipher.new('AES-128-GCM').decrypt
+     *   decipher = OpenSSL::Cipher.new('aes-128-gcm').decrypt
      *   decipher.key = key
      *   decipher.iv = nonce
      *   decipher.auth_tag = tag
@@ -1043,6 +1068,7 @@
     rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0);
     rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
     rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
+    rb_define_method(cCipher, "ccm_data_len=", ossl_cipher_set_ccm_data_len, 1);
 
     id_auth_tag_len = rb_intern_const("auth_tag_len");
     id_key_set = rb_intern_const("key_set");
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_config.c ruby-3.0.2/ext/openssl/ossl_config.c
--- ruby-3.0.2.orig/ext/openssl/ossl_config.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_config.c	2021-09-09 18:27:58.353594278 +0800
@@ -9,81 +9,452 @@
  */
 #include "ossl.h"
 
+static VALUE cConfig, eConfigError;
+
+static void
+nconf_free(void *conf)
+{
+    NCONF_free(conf);
+}
+
+static const rb_data_type_t ossl_config_type = {
+    "OpenSSL/CONF",
+    {
+        0, nconf_free,
+    },
+    0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
+};
+
+CONF *
+GetConfig(VALUE obj)
+{
+    CONF *conf;
+
+    TypedData_Get_Struct(obj, CONF, &ossl_config_type, conf);
+    if (!conf)
+        rb_raise(rb_eRuntimeError, "CONF is not initialized");
+    return conf;
+}
+
+static VALUE
+config_s_alloc(VALUE klass)
+{
+    VALUE obj;
+    CONF *conf;
+
+    obj = TypedData_Wrap_Struct(klass, &ossl_config_type, 0);
+    conf = NCONF_new(NULL);
+    if (!conf)
+        ossl_raise(eConfigError, "NCONF_new");
+    RTYPEDDATA_DATA(obj) = conf;
+    return obj;
+}
+
+static void
+config_load_bio(CONF *conf, BIO *bio)
+{
+    long eline = -1;
+
+    if (!NCONF_load_bio(conf, bio, &eline)) {
+        BIO_free(bio);
+        if (eline <= 0)
+            ossl_raise(eConfigError, "wrong config format");
+        else
+            ossl_raise(eConfigError, "error in line %d", eline);
+    }
+    BIO_free(bio);
+
+    /*
+     * Clear the error queue even if it is parsed successfully.
+     * Particularly, when the .include directive refers to a non-existent file,
+     * it is only reported in the error queue.
+     */
+    ossl_clear_error();
+}
 
 /*
- * Classes
- */
-VALUE cConfig;
-/* Document-class: OpenSSL::ConfigError
+ * call-seq:
+ *    Config.parse(string) -> OpenSSL::Config
  *
- * General error for openssl library configuration files. Including formatting,
- * parsing errors, etc.
+ * Parses a given _string_ as a blob that contains configuration for OpenSSL.
  */
-VALUE eConfigError;
+static VALUE
+config_s_parse(VALUE klass, VALUE str)
+{
+    VALUE obj = config_s_alloc(klass);
+    CONF *conf = GetConfig(obj);
+    BIO *bio;
+
+    bio = ossl_obj2bio(&str);
+    config_load_bio(conf, bio); /* Consumes BIO */
+    return obj;
+}
+
+static VALUE config_get_sections(VALUE self);
+static VALUE config_get_section(VALUE self, VALUE section);
 
 /*
- * Public
+ * call-seq:
+ *    Config.parse_config(io) -> hash
+ *
+ * Parses the configuration data read from _io_ and returns the whole content
+ * as a Hash.
  */
+static VALUE
+config_s_parse_config(VALUE klass, VALUE io)
+{
+    VALUE obj, sections, ret;
+    long i;
+
+    obj = config_s_parse(klass, io);
+    sections = config_get_sections(obj);
+    ret = rb_hash_new();
+    for (i = 0; i < RARRAY_LEN(sections); i++) {
+        VALUE section = rb_ary_entry(sections, i);
+        rb_hash_aset(ret, section, config_get_section(obj, section));
+    }
+    return ret;
+}
 
 /*
- * DupConfigPtr is a public C-level function for getting OpenSSL CONF struct
- * from an OpenSSL::Config(eConfig) instance.  We decided to implement
- * OpenSSL::Config in Ruby level but we need to pass native CONF struct for
- * some OpenSSL features such as X509V3_EXT_*.
+ * call-seq:
+ *    Config.new(filename) -> OpenSSL::Config
+ *
+ * Creates an instance of OpenSSL::Config from the content of the file
+ * specified by _filename_.
+ *
+ * This can be used in contexts like OpenSSL::X509::ExtensionFactory.config=
+ *
+ * This can raise IO exceptions based on the access, or availability of the
+ * file. A ConfigError exception may be raised depending on the validity of
+ * the data being configured.
  */
-CONF *
-DupConfigPtr(VALUE obj)
+static VALUE
+config_initialize(int argc, VALUE *argv, VALUE self)
 {
-    CONF *conf;
+    CONF *conf = GetConfig(self);
+    VALUE filename;
+
+    /* 0-arguments call has no use-case, but is kept for compatibility */
+    rb_scan_args(argc, argv, "01", &filename);
+    rb_check_frozen(self);
+    if (!NIL_P(filename)) {
+        BIO *bio = BIO_new_file(StringValueCStr(filename), "rb");
+        if (!bio)
+            ossl_raise(eConfigError, "BIO_new_file");
+        config_load_bio(conf, bio); /* Consumes BIO */
+    }
+    return self;
+}
+
+static VALUE
+config_initialize_copy(VALUE self, VALUE other)
+{
+    CONF *conf = GetConfig(self);
     VALUE str;
     BIO *bio;
-    long eline = -1;
 
-    OSSL_Check_Kind(obj, cConfig);
-    str = rb_funcall(obj, rb_intern("to_s"), 0);
+    str = rb_funcall(other, rb_intern("to_s"), 0);
+    rb_check_frozen(self);
     bio = ossl_obj2bio(&str);
-    conf = NCONF_new(NULL);
-    if(!conf){
-	BIO_free(bio);
-	ossl_raise(eConfigError, NULL);
-    }
-    if(!NCONF_load_bio(conf, bio, &eline)){
-	BIO_free(bio);
-	NCONF_free(conf);
-	if (eline <= 0)
-	    ossl_raise(eConfigError, "wrong config format");
-	else
-	    ossl_raise(eConfigError, "error in line %d", eline);
+    config_load_bio(conf, bio); /* Consumes BIO */
+    return self;
+}
+
+/*
+ * call-seq:
+ *    config.get_value(section, key) -> string
+ *
+ * Gets the value of _key_ from the given _section_.
+ *
+ * Given the following configurating file being loaded:
+ *
+ *   config = OpenSSL::Config.load('foo.cnf')
+ *     #=> #<OpenSSL::Config sections=["default"]>
+ *   puts config.to_s
+ *     #=> [ default ]
+ *     #   foo=bar
+ *
+ * You can get a specific value from the config if you know the _section_
+ * and _key_ like so:
+ *
+ *   config.get_value('default','foo')
+ *     #=> "bar"
+ */
+static VALUE
+config_get_value(VALUE self, VALUE section, VALUE key)
+{
+    CONF *conf = GetConfig(self);
+    const char *str, *sectionp;
+
+    StringValueCStr(section);
+    StringValueCStr(key);
+    /* For compatibility; NULL means "default". */
+    sectionp = RSTRING_LEN(section) ? RSTRING_PTR(section) : NULL;
+    str = NCONF_get_string(conf, sectionp, RSTRING_PTR(key));
+    if (!str) {
+        ossl_clear_error();
+        return Qnil;
     }
-    BIO_free(bio);
+    return rb_str_new_cstr(str);
+}
 
-    return conf;
+/*
+ * call-seq:
+ *    config[section] -> hash
+ *
+ * Gets all key-value pairs in a specific _section_ from the current
+ * configuration.
+ *
+ * Given the following configurating file being loaded:
+ *
+ *   config = OpenSSL::Config.load('foo.cnf')
+ *     #=> #<OpenSSL::Config sections=["default"]>
+ *   puts config.to_s
+ *     #=> [ default ]
+ *     #   foo=bar
+ *
+ * You can get a hash of the specific section like so:
+ *
+ *   config['default']
+ *     #=> {"foo"=>"bar"}
+ *
+ */
+static VALUE
+config_get_section(VALUE self, VALUE section)
+{
+    CONF *conf = GetConfig(self);
+    STACK_OF(CONF_VALUE) *sk;
+    int i, entries;
+    VALUE hash;
+
+    hash = rb_hash_new();
+    StringValueCStr(section);
+    if (!(sk = NCONF_get_section(conf, RSTRING_PTR(section)))) {
+        ossl_clear_error();
+        return hash;
+    }
+    entries = sk_CONF_VALUE_num(sk);
+    for (i = 0; i < entries; i++) {
+        CONF_VALUE *entry = sk_CONF_VALUE_value(sk, i);
+        rb_hash_aset(hash, rb_str_new_cstr(entry->name),
+                     rb_str_new_cstr(entry->value));
+    }
+    return hash;
 }
 
-/* Document-const: DEFAULT_CONFIG_FILE
+static void
+get_conf_section_doall_arg(CONF_VALUE *cv, VALUE *aryp)
+{
+    if (cv->name)
+        return;
+    rb_ary_push(*aryp, rb_str_new_cstr(cv->section));
+}
+
+/* IMPLEMENT_LHASH_DOALL_ARG_CONST() requires >= OpenSSL 1.1.0 */
+static IMPLEMENT_LHASH_DOALL_ARG_FN(get_conf_section, CONF_VALUE, VALUE)
+
+/*
+ * call-seq:
+ *    config.sections -> array of string
  *
- * The default system configuration file for openssl
+ * Get the names of all sections in the current configuration.
  */
+static VALUE
+config_get_sections(VALUE self)
+{
+    CONF *conf = GetConfig(self);
+    VALUE ary;
+
+    ary = rb_ary_new();
+    lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(get_conf_section),
+                 &ary);
+    return ary;
+}
+
+static void
+dump_conf_value_doall_arg(CONF_VALUE *cv, VALUE *strp)
+{
+    VALUE str = *strp;
+    STACK_OF(CONF_VALUE) *sk;
+    int i, num;
+
+    if (cv->name)
+        return;
+    sk = (STACK_OF(CONF_VALUE) *)cv->value;
+    num = sk_CONF_VALUE_num(sk);
+    rb_str_cat_cstr(str, "[ ");
+    rb_str_cat_cstr(str, cv->section);
+    rb_str_cat_cstr(str, " ]\n");
+    for (i = 0; i < num; i++){
+        CONF_VALUE *v = sk_CONF_VALUE_value(sk, i);
+        rb_str_cat_cstr(str, v->name ? v->name : "None");
+        rb_str_cat_cstr(str, "=");
+        rb_str_cat_cstr(str, v->value ? v->value : "None");
+        rb_str_cat_cstr(str, "\n");
+    }
+    rb_str_cat_cstr(str, "\n");
+}
+
+static IMPLEMENT_LHASH_DOALL_ARG_FN(dump_conf_value, CONF_VALUE, VALUE)
 
 /*
- * INIT
+ * call-seq:
+ *    config.to_s -> string
+ *
+ *
+ * Gets the parsable form of the current configuration.
+ *
+ * Given the following configuration being created:
+ *
+ *   config = OpenSSL::Config.new
+ *     #=> #<OpenSSL::Config sections=[]>
+ *   config['default'] = {"foo"=>"bar","baz"=>"buz"}
+ *     #=> {"foo"=>"bar", "baz"=>"buz"}
+ *   puts config.to_s
+ *     #=> [ default ]
+ *     #   foo=bar
+ *     #   baz=buz
+ *
+ * You can parse get the serialized configuration using #to_s and then parse
+ * it later:
+ *
+ *   serialized_config = config.to_s
+ *   # much later...
+ *   new_config = OpenSSL::Config.parse(serialized_config)
+ *     #=> #<OpenSSL::Config sections=["default"]>
+ *   puts new_config
+ *     #=> [ default ]
+ *         foo=bar
+ *         baz=buz
  */
+static VALUE
+config_to_s(VALUE self)
+{
+    CONF *conf = GetConfig(self);
+    VALUE str;
+
+    str = rb_str_new(NULL, 0);
+    lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(dump_conf_value),
+                 &str);
+    return str;
+}
+
+static void
+each_conf_value_doall_arg(CONF_VALUE *cv, void *unused)
+{
+    STACK_OF(CONF_VALUE) *sk;
+    VALUE section;
+    int i, num;
+
+    if (cv->name)
+        return;
+    sk = (STACK_OF(CONF_VALUE) *)cv->value;
+    num = sk_CONF_VALUE_num(sk);
+    section = rb_str_new_cstr(cv->section);
+    for (i = 0; i < num; i++){
+        CONF_VALUE *v = sk_CONF_VALUE_value(sk, i);
+        VALUE name = v->name ? rb_str_new_cstr(v->name) : Qnil;
+        VALUE value = v->value ? rb_str_new_cstr(v->value) : Qnil;
+        rb_yield(rb_ary_new3(3, section, name, value));
+    }
+}
+
+static IMPLEMENT_LHASH_DOALL_ARG_FN(each_conf_value, CONF_VALUE, void)
+
+/*
+ * call-seq:
+ *    config.each { |section, key, value| }
+ *
+ * Retrieves the section and its pairs for the current configuration.
+ *
+ *    config.each do |section, key, value|
+ *      # ...
+ *    end
+ */
+static VALUE
+config_each(VALUE self)
+{
+    CONF *conf = GetConfig(self);
+
+    RETURN_ENUMERATOR(self, 0, 0);
+
+    lh_doall_arg((_LHASH *)conf->data, LHASH_DOALL_ARG_FN(each_conf_value),
+                 NULL);
+    return self;
+}
+
+/*
+ * call-seq:
+ *    config.inspect -> string
+ *
+ * String representation of this configuration object, including the class
+ * name and its sections.
+ */
+static VALUE
+config_inspect(VALUE self)
+{
+    VALUE str, ary = config_get_sections(self);
+    const char *cname = rb_class2name(rb_obj_class(self));
+
+    str = rb_str_new_cstr("#<");
+    rb_str_cat_cstr(str, cname);
+    rb_str_cat_cstr(str, " sections=");
+    rb_str_append(str, rb_inspect(ary));
+    rb_str_cat_cstr(str, ">");
+
+    return str;
+}
+
 void
 Init_ossl_config(void)
 {
-    char *default_config_file;
+    char *path;
+    VALUE path_str;
 
 #if 0
     mOSSL = rb_define_module("OpenSSL");
     eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
 #endif
 
-    eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError);
+    /* Document-class: OpenSSL::Config
+     *
+     * Configuration for the openssl library.
+     *
+     * Many system's installation of openssl library will depend on your system
+     * configuration. See the value of OpenSSL::Config::DEFAULT_CONFIG_FILE for
+     * the location of the file for your host.
+     *
+     * See also http://www.openssl.org/docs/apps/config.html
+     */
     cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject);
 
-    default_config_file = CONF_get1_default_config_file();
-    rb_define_const(cConfig, "DEFAULT_CONFIG_FILE",
-		    rb_str_new2(default_config_file));
-    OPENSSL_free(default_config_file);
-    /* methods are defined by openssl/config.rb */
+    /* Document-class: OpenSSL::ConfigError
+     *
+     * General error for openssl library configuration files. Including formatting,
+     * parsing errors, etc.
+     */
+    eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError);
+
+    rb_include_module(cConfig, rb_mEnumerable);
+    rb_define_singleton_method(cConfig, "parse", config_s_parse, 1);
+    rb_define_singleton_method(cConfig, "parse_config", config_s_parse_config, 1);
+    rb_define_alias(CLASS_OF(cConfig), "load", "new");
+    rb_define_alloc_func(cConfig, config_s_alloc);
+    rb_define_method(cConfig, "initialize", config_initialize, -1);
+    rb_define_method(cConfig, "initialize_copy", config_initialize_copy, 1);
+    rb_define_method(cConfig, "get_value", config_get_value, 2);
+    rb_define_method(cConfig, "[]", config_get_section, 1);
+    rb_define_method(cConfig, "sections", config_get_sections, 0);
+    rb_define_method(cConfig, "to_s", config_to_s, 0);
+    rb_define_method(cConfig, "each", config_each, 0);
+    rb_define_method(cConfig, "inspect", config_inspect, 0);
+
+    /* Document-const: DEFAULT_CONFIG_FILE
+     *
+     * The default system configuration file for OpenSSL.
+     */
+    path = CONF_get1_default_config_file();
+    path_str = ossl_buf2str(path, rb_long2int(strlen(path)));
+    rb_define_const(cConfig, "DEFAULT_CONFIG_FILE", path_str);
 }
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_config.h ruby-3.0.2/ext/openssl/ossl_config.h
--- ruby-3.0.2.orig/ext/openssl/ossl_config.h	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_config.h	2021-09-09 18:27:58.353594278 +0800
@@ -7,13 +7,10 @@
  * This program is licensed under the same licence as Ruby.
  * (See the file 'LICENCE'.)
  */
-#if !defined(_OSSL_CONFIG_H_)
-#define _OSSL_CONFIG_H_
+#ifndef OSSL_CONFIG_H
+#define OSSL_CONFIG_H
 
-extern VALUE cConfig;
-extern VALUE eConfigError;
-
-CONF* DupConfigPtr(VALUE obj);
+CONF *GetConfig(VALUE obj);
 void Init_ossl_config(void);
 
-#endif /* _OSSL_CONFIG_H_ */
+#endif /* OSSL_CONFIG_H */
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_digest.c ruby-3.0.2/ext/openssl/ossl_digest.c
--- ruby-3.0.2.orig/ext/openssl/ossl_digest.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_digest.c	2021-09-09 18:27:58.353594278 +0800
@@ -63,7 +63,7 @@
 
         GetDigest(obj, ctx);
 
-        md = EVP_MD_CTX_md(ctx);
+        md = EVP_MD_CTX_get0_md(ctx);
     }
 
     return md;
@@ -176,7 +176,7 @@
     EVP_MD_CTX *ctx;
 
     GetDigest(self, ctx);
-    if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL) != 1) {
+    if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_get0_md(ctx), NULL) != 1) {
 	ossl_raise(eDigestError, "Digest initialization failed.");
     }
 
@@ -259,7 +259,7 @@
 
     GetDigest(self, ctx);
 
-    return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
+    return rb_str_new_cstr(EVP_MD_name(EVP_MD_CTX_get0_md(ctx)));
 }
 
 /*
@@ -372,15 +372,15 @@
      *
      * === Hashing a file
      *
-     *   data = File.read('document')
+     *   data = File.binread('document')
      *   sha256 = OpenSSL::Digest.new('SHA256')
      *   digest = sha256.digest(data)
      *
      * === Hashing several pieces of data at once
      *
-     *   data1 = File.read('file1')
-     *   data2 = File.read('file2')
-     *   data3 = File.read('file3')
+     *   data1 = File.binread('file1')
+     *   data2 = File.binread('file2')
+     *   data3 = File.binread('file3')
      *   sha256 = OpenSSL::Digest.new('SHA256')
      *   sha256 << data1
      *   sha256 << data2
@@ -389,11 +389,11 @@
      *
      * === Reuse a Digest instance
      *
-     *   data1 = File.read('file1')
+     *   data1 = File.binread('file1')
      *   sha256 = OpenSSL::Digest.new('SHA256')
      *   digest1 = sha256.digest(data1)
      *
-     *   data2 = File.read('file2')
+     *   data2 = File.binread('file2')
      *   sha256.reset
      *   digest2 = sha256.digest(data2)
      *
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_engine.c ruby-3.0.2/ext/openssl/ossl_engine.c
--- ruby-3.0.2.orig/ext/openssl/ossl_engine.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_engine.c	2021-09-09 18:27:58.353594278 +0800
@@ -9,7 +9,8 @@
  */
 #include "ossl.h"
 
-#if !defined(OPENSSL_NO_ENGINE)
+#ifdef OSSL_USE_ENGINE
+# include <openssl/engine.h>
 
 #define NewEngine(klass) \
     TypedData_Wrap_Struct((klass), &ossl_engine_type, 0)
@@ -101,48 +102,48 @@
         return Qtrue;
     }
     StringValueCStr(name);
-#if HAVE_ENGINE_LOAD_DYNAMIC
+#ifdef HAVE_ENGINE_LOAD_DYNAMIC
     OSSL_ENGINE_LOAD_IF_MATCH(dynamic, DYNAMIC);
 #endif
 #ifndef OPENSSL_NO_STATIC_ENGINE
-#if HAVE_ENGINE_LOAD_4758CCA
+#ifdef HAVE_ENGINE_LOAD_4758CCA
     OSSL_ENGINE_LOAD_IF_MATCH(4758cca, 4758CCA);
 #endif
-#if HAVE_ENGINE_LOAD_AEP
+#ifdef HAVE_ENGINE_LOAD_AEP
     OSSL_ENGINE_LOAD_IF_MATCH(aep, AEP);
 #endif
-#if HAVE_ENGINE_LOAD_ATALLA
+#ifdef HAVE_ENGINE_LOAD_ATALLA
     OSSL_ENGINE_LOAD_IF_MATCH(atalla, ATALLA);
 #endif
-#if HAVE_ENGINE_LOAD_CHIL
+#ifdef HAVE_ENGINE_LOAD_CHIL
     OSSL_ENGINE_LOAD_IF_MATCH(chil, CHIL);
 #endif
-#if HAVE_ENGINE_LOAD_CSWIFT
+#ifdef HAVE_ENGINE_LOAD_CSWIFT
     OSSL_ENGINE_LOAD_IF_MATCH(cswift, CSWIFT);
 #endif
-#if HAVE_ENGINE_LOAD_NURON
+#ifdef HAVE_ENGINE_LOAD_NURON
     OSSL_ENGINE_LOAD_IF_MATCH(nuron, NURON);
 #endif
-#if HAVE_ENGINE_LOAD_SUREWARE
+#ifdef HAVE_ENGINE_LOAD_SUREWARE
     OSSL_ENGINE_LOAD_IF_MATCH(sureware, SUREWARE);
 #endif
-#if HAVE_ENGINE_LOAD_UBSEC
+#ifdef HAVE_ENGINE_LOAD_UBSEC
     OSSL_ENGINE_LOAD_IF_MATCH(ubsec, UBSEC);
 #endif
-#if HAVE_ENGINE_LOAD_PADLOCK
+#ifdef HAVE_ENGINE_LOAD_PADLOCK
     OSSL_ENGINE_LOAD_IF_MATCH(padlock, PADLOCK);
 #endif
-#if HAVE_ENGINE_LOAD_CAPI
+#ifdef HAVE_ENGINE_LOAD_CAPI
     OSSL_ENGINE_LOAD_IF_MATCH(capi, CAPI);
 #endif
-#if HAVE_ENGINE_LOAD_GMP
+#ifdef HAVE_ENGINE_LOAD_GMP
     OSSL_ENGINE_LOAD_IF_MATCH(gmp, GMP);
 #endif
-#if HAVE_ENGINE_LOAD_GOST
+#ifdef HAVE_ENGINE_LOAD_GOST
     OSSL_ENGINE_LOAD_IF_MATCH(gost, GOST);
 #endif
 #endif
-#if HAVE_ENGINE_LOAD_CRYPTODEV
+#ifdef HAVE_ENGINE_LOAD_CRYPTODEV
     OSSL_ENGINE_LOAD_IF_MATCH(cryptodev, CRYPTODEV);
 #endif
     OSSL_ENGINE_LOAD_IF_MATCH(openssl, OPENSSL);
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl.h ruby-3.0.2/ext/openssl/ossl.h
--- ruby-3.0.2.orig/ext/openssl/ossl.h	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl.h	2021-09-09 18:27:58.353594278 +0800
@@ -18,22 +18,24 @@
 #include <ruby/io.h>
 #include <ruby/thread.h>
 #include <openssl/opensslv.h>
+
+#if !defined(OPENSSL_NO_ENGINE) && \
+    !(defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3)
+# define OSSL_USE_ENGINE
+#endif
+
 #include <openssl/err.h>
 #include <openssl/asn1.h>
 #include <openssl/x509v3.h>
 #include <openssl/ssl.h>
 #include <openssl/pkcs12.h>
 #include <openssl/pkcs7.h>
-#include <openssl/hmac.h>
 #include <openssl/rand.h>
 #include <openssl/conf.h>
 #ifndef OPENSSL_NO_TS
   #include <openssl/ts.h>
 #endif
 #include <openssl/crypto.h>
-#if !defined(OPENSSL_NO_ENGINE)
-#  include <openssl/engine.h>
-#endif
 #if !defined(OPENSSL_NO_OCSP)
 #  include <openssl/ocsp.h>
 #endif
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_hmac.c ruby-3.0.2/ext/openssl/ossl_hmac.c
--- ruby-3.0.2.orig/ext/openssl/ossl_hmac.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_hmac.c	2021-09-09 18:27:58.353594278 +0800
@@ -7,14 +7,12 @@
  * This program is licensed under the same licence as Ruby.
  * (See the file 'LICENCE'.)
  */
-#if !defined(OPENSSL_NO_HMAC)
-
 #include "ossl.h"
 
 #define NewHMAC(klass) \
     TypedData_Wrap_Struct((klass), &ossl_hmac_type, 0)
 #define GetHMAC(obj, ctx) do { \
-    TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \
+    TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_hmac_type, (ctx)); \
     if (!(ctx)) { \
 	ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
     } \
@@ -36,7 +34,7 @@
 static void
 ossl_hmac_free(void *ctx)
 {
-    HMAC_CTX_free(ctx);
+    EVP_MD_CTX_free(ctx);
 }
 
 static const rb_data_type_t ossl_hmac_type = {
@@ -51,12 +49,12 @@
 ossl_hmac_alloc(VALUE klass)
 {
     VALUE obj;
-    HMAC_CTX *ctx;
+    EVP_MD_CTX *ctx;
 
     obj = NewHMAC(klass);
-    ctx = HMAC_CTX_new();
+    ctx = EVP_MD_CTX_new();
     if (!ctx)
-	ossl_raise(eHMACError, NULL);
+        ossl_raise(eHMACError, "EVP_MD_CTX");
     RTYPEDDATA_DATA(obj) = ctx;
 
     return obj;
@@ -76,8 +74,7 @@
  * === Example
  *
  *	key = 'key'
- * 	digest = OpenSSL::Digest.new('sha1')
- * 	instance = OpenSSL::HMAC.new(key, digest)
+ * 	instance = OpenSSL::HMAC.new(key, 'SHA1')
  * 	#=> f42bb0eeb018ebbd4597ae7213711ec60760843f
  * 	instance.class
  * 	#=> OpenSSL::HMAC
@@ -86,7 +83,7 @@
  *
  * Two instances can be securely compared with #== in constant time:
  *
- *	other_instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
+ *	other_instance = OpenSSL::HMAC.new('key', 'SHA1')
  *  #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
  *  instance == other_instance
  *  #=> true
@@ -95,12 +92,23 @@
 static VALUE
 ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
 {
-    HMAC_CTX *ctx;
+    EVP_MD_CTX *ctx;
+    EVP_PKEY *pkey;
 
-    StringValue(key);
     GetHMAC(self, ctx);
-    HMAC_Init_ex(ctx, RSTRING_PTR(key), RSTRING_LENINT(key),
-		 ossl_evp_get_digestbyname(digest), NULL);
+    StringValue(key);
+    pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL,
+                                (unsigned char *)RSTRING_PTR(key),
+                                RSTRING_LENINT(key));
+    if (!pkey)
+        ossl_raise(eHMACError, "EVP_PKEY_new_mac_key");
+    if (EVP_DigestSignInit(ctx, NULL, ossl_evp_get_digestbyname(digest),
+                           NULL, pkey) != 1) {
+        EVP_PKEY_free(pkey);
+        ossl_raise(eHMACError, "EVP_DigestSignInit");
+    }
+    /* Decrement reference counter; EVP_MD_CTX still keeps it */
+    EVP_PKEY_free(pkey);
 
     return self;
 }
@@ -108,16 +116,15 @@
 static VALUE
 ossl_hmac_copy(VALUE self, VALUE other)
 {
-    HMAC_CTX *ctx1, *ctx2;
+    EVP_MD_CTX *ctx1, *ctx2;
 
     rb_check_frozen(self);
     if (self == other) return self;
 
     GetHMAC(self, ctx1);
     GetHMAC(other, ctx2);
-
-    if (!HMAC_CTX_copy(ctx1, ctx2))
-	ossl_raise(eHMACError, "HMAC_CTX_copy");
+    if (EVP_MD_CTX_copy(ctx1, ctx2) != 1)
+        ossl_raise(eHMACError, "EVP_MD_CTX_copy");
     return self;
 }
 
@@ -142,33 +149,16 @@
 static VALUE
 ossl_hmac_update(VALUE self, VALUE data)
 {
-    HMAC_CTX *ctx;
+    EVP_MD_CTX *ctx;
 
     StringValue(data);
     GetHMAC(self, ctx);
-    HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data));
+    if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) != 1)
+        ossl_raise(eHMACError, "EVP_DigestSignUpdate");
 
     return self;
 }
 
-static void
-hmac_final(HMAC_CTX *ctx, unsigned char *buf, unsigned int *buf_len)
-{
-    HMAC_CTX *final;
-
-    final = HMAC_CTX_new();
-    if (!final)
-	ossl_raise(eHMACError, "HMAC_CTX_new");
-
-    if (!HMAC_CTX_copy(final, ctx)) {
-	HMAC_CTX_free(final);
-	ossl_raise(eHMACError, "HMAC_CTX_copy");
-    }
-
-    HMAC_Final(final, buf, buf_len);
-    HMAC_CTX_free(final);
-}
-
 /*
  *  call-seq:
  *     hmac.digest -> string
@@ -176,7 +166,7 @@
  * Returns the authentication code an instance represents as a binary string.
  *
  * === Example
- *  instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
+ *  instance = OpenSSL::HMAC.new('key', 'SHA1')
  *  #=> f42bb0eeb018ebbd4597ae7213711ec60760843f
  *  instance.digest
  *  #=> "\xF4+\xB0\xEE\xB0\x18\xEB\xBDE\x97\xAEr\x13q\x1E\xC6\a`\x84?"
@@ -184,15 +174,16 @@
 static VALUE
 ossl_hmac_digest(VALUE self)
 {
-    HMAC_CTX *ctx;
-    unsigned int buf_len;
+    EVP_MD_CTX *ctx;
+    size_t buf_len;
     VALUE ret;
 
     GetHMAC(self, ctx);
     ret = rb_str_new(NULL, EVP_MAX_MD_SIZE);
-    hmac_final(ctx, (unsigned char *)RSTRING_PTR(ret), &buf_len);
-    assert(buf_len <= EVP_MAX_MD_SIZE);
-    rb_str_set_len(ret, buf_len);
+    if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(ret),
+                            &buf_len) != 1)
+        ossl_raise(eHMACError, "EVP_DigestSignFinal");
+    rb_str_set_len(ret, (long)buf_len);
 
     return ret;
 }
@@ -207,13 +198,14 @@
 static VALUE
 ossl_hmac_hexdigest(VALUE self)
 {
-    HMAC_CTX *ctx;
+    EVP_MD_CTX *ctx;
     unsigned char buf[EVP_MAX_MD_SIZE];
-    unsigned int buf_len;
+    size_t buf_len;
     VALUE ret;
 
     GetHMAC(self, ctx);
-    hmac_final(ctx, buf, &buf_len);
+    if (EVP_DigestSignFinal(ctx, buf, &buf_len) != 1)
+        ossl_raise(eHMACError, "EVP_DigestSignFinal");
     ret = rb_str_new(NULL, buf_len * 2);
     ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
 
@@ -230,7 +222,7 @@
  * === Example
  *
  *	data = "The quick brown fox jumps over the lazy dog"
- * 	instance = OpenSSL::HMAC.new('key', OpenSSL::Digest.new('sha1'))
+ * 	instance = OpenSSL::HMAC.new('key', 'SHA1')
  * 	#=> f42bb0eeb018ebbd4597ae7213711ec60760843f
  *
  * 	instance.update(data)
@@ -242,85 +234,18 @@
 static VALUE
 ossl_hmac_reset(VALUE self)
 {
-    HMAC_CTX *ctx;
+    EVP_MD_CTX *ctx;
+    EVP_PKEY *pkey;
 
     GetHMAC(self, ctx);
-    HMAC_Init_ex(ctx, NULL, 0, NULL, NULL);
+    pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx));
+    if (EVP_DigestSignInit(ctx, NULL, EVP_MD_CTX_get0_md(ctx), NULL, pkey) != 1)
+        ossl_raise(eHMACError, "EVP_DigestSignInit");
 
     return self;
 }
 
 /*
- *  call-seq:
- *     HMAC.digest(digest, key, data) -> aString
- *
- * Returns the authentication code as a binary string. The _digest_ parameter
- * specifies the digest algorithm to use. This may be a String representing
- * the algorithm name or an instance of OpenSSL::Digest.
- *
- * === Example
- *
- *	key = 'key'
- * 	data = 'The quick brown fox jumps over the lazy dog'
- *
- * 	hmac = OpenSSL::HMAC.digest('sha1', key, data)
- * 	#=> "\xDE|\x9B\x85\xB8\xB7\x8A\xA6\xBC\x8Az6\xF7\n\x90p\x1C\x9D\xB4\xD9"
- *
- */
-static VALUE
-ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
-{
-    unsigned char *buf;
-    unsigned int buf_len;
-
-    StringValue(key);
-    StringValue(data);
-    buf = HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key),
-	       RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data),
-	       RSTRING_LEN(data), NULL, &buf_len);
-
-    return rb_str_new((const char *)buf, buf_len);
-}
-
-/*
- *  call-seq:
- *     HMAC.hexdigest(digest, key, data) -> aString
- *
- * Returns the authentication code as a hex-encoded string. The _digest_
- * parameter specifies the digest algorithm to use. This may be a String
- * representing the algorithm name or an instance of OpenSSL::Digest.
- *
- * === Example
- *
- *	key = 'key'
- * 	data = 'The quick brown fox jumps over the lazy dog'
- *
- * 	hmac = OpenSSL::HMAC.hexdigest('sha1', key, data)
- * 	#=> "de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
- *
- */
-static VALUE
-ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
-{
-    unsigned char buf[EVP_MAX_MD_SIZE];
-    unsigned int buf_len;
-    VALUE ret;
-
-    StringValue(key);
-    StringValue(data);
-
-    if (!HMAC(ossl_evp_get_digestbyname(digest), RSTRING_PTR(key),
-	      RSTRING_LENINT(key), (unsigned char *)RSTRING_PTR(data),
-	      RSTRING_LEN(data), buf, &buf_len))
-	ossl_raise(eHMACError, "HMAC");
-
-    ret = rb_str_new(NULL, buf_len * 2);
-    ossl_bin2hex(buf, RSTRING_PTR(ret), buf_len);
-
-    return ret;
-}
-
-/*
  * INIT
  */
 void
@@ -350,11 +275,10 @@
      *
      * === HMAC-SHA256 using incremental interface
      *
-     *   data1 = File.read("file1")
-     *   data2 = File.read("file2")
+     *   data1 = File.binread("file1")
+     *   data2 = File.binread("file2")
      *   key = "key"
-     *   digest = OpenSSL::Digest.new('SHA256')
-     *   hmac = OpenSSL::HMAC.new(key, digest)
+     *   hmac = OpenSSL::HMAC.new(key, 'SHA256')
      *   hmac << data1
      *   hmac << data2
      *   mac = hmac.digest
@@ -364,8 +288,6 @@
     cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
 
     rb_define_alloc_func(cHMAC, ossl_hmac_alloc);
-    rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3);
-    rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3);
 
     rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
     rb_define_method(cHMAC, "initialize_copy", ossl_hmac_copy, 1);
@@ -378,12 +300,3 @@
     rb_define_alias(cHMAC, "inspect", "hexdigest");
     rb_define_alias(cHMAC, "to_s", "hexdigest");
 }
-
-#else /* NO_HMAC */
-#  warning >>> OpenSSL is compiled without HMAC support <<<
-void
-Init_ossl_hmac(void)
-{
-    rb_warning("HMAC is not available: OpenSSL is compiled without HMAC.");
-}
-#endif /* NO_HMAC */
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_ocsp.c ruby-3.0.2/ext/openssl/ossl_ocsp.c
--- ruby-3.0.2.orig/ext/openssl/ossl_ocsp.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_ocsp.c	2021-09-09 18:27:58.354594302 +0800
@@ -157,7 +157,7 @@
 }
 
 /*
- * OCSP::Resquest
+ * OCSP::Request
  */
 static VALUE
 ossl_ocspreq_alloc(VALUE klass)
@@ -1069,55 +1069,7 @@
     x509st = GetX509StorePtr(store);
     flg = NIL_P(flags) ? 0 : NUM2INT(flags);
     x509s = ossl_x509_ary2sk(certs);
-#if (OPENSSL_VERSION_NUMBER < 0x1000202fL) || defined(LIBRESSL_VERSION_NUMBER)
-    /*
-     * OpenSSL had a bug that it doesn't use the certificates in x509s for
-     * verifying the chain. This can be a problem when the response is signed by
-     * a certificate issued by an intermediate CA.
-     *
-     *       root_ca
-     *         |
-     *   intermediate_ca
-     *         |-------------|
-     *     end_entity    ocsp_signer
-     *
-     * When the certificate hierarchy is like this, and the response contains
-     * only ocsp_signer certificate, the following code wrongly fails.
-     *
-     *   store = OpenSSL::X509::Store.new; store.add_cert(root_ca)
-     *   basic_response.verify([intermediate_ca], store)
-     *
-     * So add the certificates in x509s to the embedded certificates list first.
-     *
-     * This is fixed in OpenSSL 0.9.8zg, 1.0.0s, 1.0.1n, 1.0.2b. But it still
-     * exists in LibreSSL 2.1.10, 2.2.9, 2.3.6, 2.4.1.
-     */
-    if (!(flg & (OCSP_NOCHAIN | OCSP_NOVERIFY)) &&
-	sk_X509_num(x509s) && sk_X509_num(bs->certs)) {
-	int i;
-
-	bs = ASN1_item_dup(ASN1_ITEM_rptr(OCSP_BASICRESP), bs);
-	if (!bs) {
-	    sk_X509_pop_free(x509s, X509_free);
-	    ossl_raise(eOCSPError, "ASN1_item_dup");
-	}
-
-	for (i = 0; i < sk_X509_num(x509s); i++) {
-	    if (!OCSP_basic_add1_cert(bs, sk_X509_value(x509s, i))) {
-		sk_X509_pop_free(x509s, X509_free);
-		OCSP_BASICRESP_free(bs);
-		ossl_raise(eOCSPError, "OCSP_basic_add1_cert");
-	    }
-	}
-	result = OCSP_basic_verify(bs, x509s, x509st, flg);
-	OCSP_BASICRESP_free(bs);
-    }
-    else {
-	result = OCSP_basic_verify(bs, x509s, x509st, flg);
-    }
-#else
     result = OCSP_basic_verify(bs, x509s, x509st, flg);
-#endif
     sk_X509_pop_free(x509s, X509_free);
     if (result <= 0)
 	ossl_clear_error();
@@ -1787,7 +1739,7 @@
      *   single_response = basic_response.find_response(certificate_id)
      *
      *   unless single_response
-     *     raise 'basic_response does not have the status for the certificiate'
+     *     raise 'basic_response does not have the status for the certificate'
      *   end
      *
      * Then check the validity. A status issued in the future must be rejected.
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_pkcs7.c ruby-3.0.2/ext/openssl/ossl_pkcs7.c
--- ruby-3.0.2.orig/ext/openssl/ossl_pkcs7.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_pkcs7.c	2021-09-09 18:27:58.354594302 +0800
@@ -101,19 +101,24 @@
  * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM)
  */
 static PKCS7_SIGNER_INFO *
-ossl_PKCS7_SIGNER_INFO_dup(const PKCS7_SIGNER_INFO *si)
+ossl_PKCS7_SIGNER_INFO_dup(PKCS7_SIGNER_INFO *si)
 {
-    return (PKCS7_SIGNER_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO,
-					 (d2i_of_void *)d2i_PKCS7_SIGNER_INFO,
-					 (char *)si);
+    PKCS7_SIGNER_INFO *si_new = ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO,
+                                         (d2i_of_void *)d2i_PKCS7_SIGNER_INFO,
+                                         si);
+    if (si_new && si->pkey) {
+        EVP_PKEY_up_ref(si->pkey);
+        si_new->pkey = si->pkey;
+    }
+    return si_new;
 }
 
 static PKCS7_RECIP_INFO *
-ossl_PKCS7_RECIP_INFO_dup(const PKCS7_RECIP_INFO *si)
+ossl_PKCS7_RECIP_INFO_dup(PKCS7_RECIP_INFO *si)
 {
-    return (PKCS7_RECIP_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
-					(d2i_of_void *)d2i_PKCS7_RECIP_INFO,
-					(char *)si);
+    return ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO,
+                    (d2i_of_void *)d2i_PKCS7_RECIP_INFO,
+                    si);
 }
 
 static VALUE
@@ -130,19 +135,6 @@
     return obj;
 }
 
-static PKCS7_SIGNER_INFO *
-DupPKCS7SignerPtr(VALUE obj)
-{
-    PKCS7_SIGNER_INFO *p7si, *pkcs7;
-
-    GetPKCS7si(obj, p7si);
-    if (!(pkcs7 = ossl_PKCS7_SIGNER_INFO_dup(p7si))) {
-	ossl_raise(ePKCS7Error, NULL);
-    }
-
-    return pkcs7;
-}
-
 static VALUE
 ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri)
 {
@@ -157,19 +149,6 @@
     return obj;
 }
 
-static PKCS7_RECIP_INFO *
-DupPKCS7RecipientPtr(VALUE obj)
-{
-    PKCS7_RECIP_INFO *p7ri, *pkcs7;
-
-    GetPKCS7ri(obj, p7ri);
-    if (!(pkcs7 = ossl_PKCS7_RECIP_INFO_dup(p7ri))) {
-	ossl_raise(ePKCS7Error, NULL);
-    }
-
-    return pkcs7;
-}
-
 /*
  * call-seq:
  *    PKCS7.read_smime(string) => pkcs7
@@ -351,7 +330,7 @@
 static VALUE
 ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
 {
-    PKCS7 *p7, *pkcs = DATA_PTR(self);
+    PKCS7 *p7, *p7_orig = RTYPEDDATA_DATA(self);
     BIO *in;
     VALUE arg;
 
@@ -359,19 +338,17 @@
 	return self;
     arg = ossl_to_der_if_possible(arg);
     in = ossl_obj2bio(&arg);
-    p7 = PEM_read_bio_PKCS7(in, &pkcs, NULL, NULL);
+    p7 = d2i_PKCS7_bio(in, NULL);
     if (!p7) {
-	OSSL_BIO_reset(in);
-        p7 = d2i_PKCS7_bio(in, &pkcs);
-	if (!p7) {
-	    BIO_free(in);
-	    PKCS7_free(pkcs);
-	    DATA_PTR(self) = NULL;
-	    ossl_raise(rb_eArgError, "Could not parse the PKCS7");
-	}
+        OSSL_BIO_reset(in);
+        p7 = PEM_read_bio_PKCS7(in, NULL, NULL, NULL);
     }
-    DATA_PTR(self) = pkcs;
     BIO_free(in);
+    if (!p7)
+        ossl_raise(rb_eArgError, "Could not parse the PKCS7");
+
+    RTYPEDDATA_DATA(self) = p7;
+    PKCS7_free(p7_orig);
     ossl_pkcs7_set_data(self, Qnil);
     ossl_pkcs7_set_err_string(self, Qnil);
 
@@ -521,17 +498,18 @@
 ossl_pkcs7_add_signer(VALUE self, VALUE signer)
 {
     PKCS7 *pkcs7;
-    PKCS7_SIGNER_INFO *p7si;
+    PKCS7_SIGNER_INFO *si, *si_new;
 
-    p7si = DupPKCS7SignerPtr(signer); /* NEED TO DUP */
     GetPKCS7(self, pkcs7);
-    if (!PKCS7_add_signer(pkcs7, p7si)) {
-	PKCS7_SIGNER_INFO_free(p7si);
-	ossl_raise(ePKCS7Error, "Could not add signer.");
-    }
-    if (PKCS7_type_is_signed(pkcs7)){
-	PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
-				   V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
+    GetPKCS7si(signer, si);
+
+    si_new = ossl_PKCS7_SIGNER_INFO_dup(si);
+    if (!si_new)
+        ossl_raise(ePKCS7Error, "PKCS7_SIGNER_INFO_dup");
+
+    if (PKCS7_add_signer(pkcs7, si_new) != 1) {
+        PKCS7_SIGNER_INFO_free(si_new);
+        ossl_raise(ePKCS7Error, "PKCS7_add_signer");
     }
 
     return self;
@@ -567,13 +545,18 @@
 ossl_pkcs7_add_recipient(VALUE self, VALUE recip)
 {
     PKCS7 *pkcs7;
-    PKCS7_RECIP_INFO *ri;
+    PKCS7_RECIP_INFO *ri, *ri_new;
 
-    ri = DupPKCS7RecipientPtr(recip); /* NEED TO DUP */
     GetPKCS7(self, pkcs7);
-    if (!PKCS7_add_recipient_info(pkcs7, ri)) {
-	PKCS7_RECIP_INFO_free(ri);
-	ossl_raise(ePKCS7Error, "Could not add recipient.");
+    GetPKCS7ri(recip, ri);
+
+    ri_new = ossl_PKCS7_RECIP_INFO_dup(ri);
+    if (!ri_new)
+        ossl_raise(ePKCS7Error, "PKCS7_RECIP_INFO_dup");
+
+    if (PKCS7_add_recipient_info(pkcs7, ri_new) != 1) {
+        PKCS7_RECIP_INFO_free(ri_new);
+        ossl_raise(ePKCS7Error, "PKCS7_add_recipient_info");
     }
 
     return self;
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_pkey.c ruby-3.0.2/ext/openssl/ossl_pkey.c
--- ruby-3.0.2.orig/ext/openssl/ossl_pkey.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_pkey.c	2021-09-09 18:27:58.354594302 +0800
@@ -9,6 +9,10 @@
  */
 #include "ossl.h"
 
+#ifdef OSSL_USE_ENGINE
+# include <openssl/engine.h>
+#endif
+
 /*
  * Classes
  */
@@ -17,64 +21,6 @@
 VALUE ePKeyError;
 static ID id_private_q;
 
-/*
- * callback for generating keys
- */
-static VALUE
-call_check_ints0(VALUE arg)
-{
-    rb_thread_check_ints();
-    return Qnil;
-}
-
-static void *
-call_check_ints(void *arg)
-{
-    int state;
-    rb_protect(call_check_ints0, Qnil, &state);
-    return (void *)(VALUE)state;
-}
-
-int
-ossl_generate_cb_2(int p, int n, BN_GENCB *cb)
-{
-    VALUE ary;
-    struct ossl_generate_cb_arg *arg;
-    int state;
-
-    arg = (struct ossl_generate_cb_arg *)BN_GENCB_get_arg(cb);
-    if (arg->yield) {
-	ary = rb_ary_new2(2);
-	rb_ary_store(ary, 0, INT2NUM(p));
-	rb_ary_store(ary, 1, INT2NUM(n));
-
-	/*
-	* can be break by raising exception or 'break'
-	*/
-	rb_protect(rb_yield, ary, &state);
-	if (state) {
-	    arg->state = state;
-	    return 0;
-	}
-    }
-    if (arg->interrupted) {
-	arg->interrupted = 0;
-	state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
-	if (state) {
-	    arg->state = state;
-	    return 0;
-	}
-    }
-    return 1;
-}
-
-void
-ossl_generate_cb_stop(void *ptr)
-{
-    struct ossl_generate_cb_arg *arg = (struct ossl_generate_cb_arg *)ptr;
-    arg->interrupted = 1;
-}
-
 static void
 ossl_evp_pkey_free(void *ptr)
 {
@@ -95,34 +41,26 @@
 static VALUE
 pkey_new0(EVP_PKEY *pkey)
 {
-    VALUE obj;
-    int type;
+    VALUE klass, obj;
 
-    if (!pkey || (type = EVP_PKEY_base_id(pkey)) == EVP_PKEY_NONE)
-	ossl_raise(rb_eRuntimeError, "pkey is empty");
-
-    switch (type) {
+    switch (EVP_PKEY_base_id(pkey)) {
 #if !defined(OPENSSL_NO_RSA)
-    case EVP_PKEY_RSA:
-	return ossl_rsa_new(pkey);
+      case EVP_PKEY_RSA: klass = cRSA; break;
 #endif
 #if !defined(OPENSSL_NO_DSA)
-    case EVP_PKEY_DSA:
-	return ossl_dsa_new(pkey);
+      case EVP_PKEY_DSA: klass = cDSA; break;
 #endif
 #if !defined(OPENSSL_NO_DH)
-    case EVP_PKEY_DH:
-	return ossl_dh_new(pkey);
+      case EVP_PKEY_DH:  klass = cDH; break;
 #endif
 #if !defined(OPENSSL_NO_EC)
-    case EVP_PKEY_EC:
-	return ossl_ec_new(pkey);
+      case EVP_PKEY_EC:  klass = cEC; break;
 #endif
-    default:
-	obj = NewPKey(cPKey);
-	SetPKey(obj, pkey);
-	return obj;
+      default:           klass = cPKey; break;
     }
+    obj = rb_obj_alloc(klass);
+    RTYPEDDATA_DATA(obj) = pkey;
+    return obj;
 }
 
 VALUE
@@ -140,6 +78,70 @@
     return obj;
 }
 
+#if OPENSSL_VERSION_MAJOR+0 >= 3
+# include <openssl/decoder.h>
+static EVP_PKEY *
+ossl_pkey_read_decoder(BIO *bio, const char *input_type, void *ppass)
+{
+    OSSL_DECODER_CTX *dctx;
+    EVP_PKEY *pkey = NULL;
+
+    dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL, 0, NULL, NULL);
+    if (!dctx)
+        goto out;
+    if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
+        goto out;
+    if (OSSL_DECODER_from_bio(dctx, bio) != 1)
+        goto out;
+
+  out:
+    OSSL_DECODER_CTX_free(dctx);
+    return pkey;
+}
+#endif
+
+EVP_PKEY *
+ossl_pkey_read_generic(BIO *bio, VALUE pass)
+{
+    void *ppass = (void *)pass;
+    EVP_PKEY *pkey;
+
+#if OPENSSL_VERSION_MAJOR+0 >= 3
+    if ((pkey = ossl_pkey_read_decoder(bio, "DER", ppass)))
+        goto out;
+    OSSL_BIO_reset(bio);
+    if ((pkey = ossl_pkey_read_decoder(bio, "PEM", ppass)))
+        goto out;
+#else
+    if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
+	goto out;
+    OSSL_BIO_reset(bio);
+    if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, ppass)))
+	goto out;
+    OSSL_BIO_reset(bio);
+    if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
+	goto out;
+    OSSL_BIO_reset(bio);
+    /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
+    if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, ppass)))
+	goto out;
+    OSSL_BIO_reset(bio);
+    if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
+	goto out;
+    OSSL_BIO_reset(bio);
+    if ((pkey = PEM_read_bio_Parameters(bio, NULL)))
+	goto out;
+#endif
+
+  out:
+#if OPENSSL_VERSION_MAJOR+0 >= 3
+    /* FIXME: OpenSSL bug? */
+    if (pkey)
+        ossl_clear_error();
+#endif
+    return pkey;
+}
+
 /*
  *  call-seq:
  *     OpenSSL::PKey.read(string [, pwd ]) -> PKey
@@ -149,7 +151,7 @@
  * instance of the appropriate PKey class.
  *
  * === Parameters
- * * _string+ is a DER- or PEM-encoded string containing an arbitrary private
+ * * _string_ is a DER- or PEM-encoded string containing an arbitrary private
  *   or public key.
  * * _io_ is an instance of IO containing a DER- or PEM-encoded
  *   arbitrary private or public key.
@@ -164,36 +166,277 @@
     VALUE data, pass;
 
     rb_scan_args(argc, argv, "11", &data, &pass);
-    pass = ossl_pem_passwd_value(pass);
-
     bio = ossl_obj2bio(&data);
-    if ((pkey = d2i_PrivateKey_bio(bio, NULL)))
-	goto ok;
-    OSSL_BIO_reset(bio);
-    if ((pkey = d2i_PKCS8PrivateKey_bio(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
-	goto ok;
-    OSSL_BIO_reset(bio);
-    if ((pkey = d2i_PUBKEY_bio(bio, NULL)))
-	goto ok;
-    OSSL_BIO_reset(bio);
-    /* PEM_read_bio_PrivateKey() also parses PKCS #8 formats */
-    if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, (void *)pass)))
-	goto ok;
-    OSSL_BIO_reset(bio);
-    if ((pkey = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL)))
-	goto ok;
-
-    BIO_free(bio);
-    ossl_raise(ePKeyError, "Could not parse PKey");
-
-ok:
+    pkey = ossl_pkey_read_generic(bio, ossl_pem_passwd_value(pass));
     BIO_free(bio);
+    if (!pkey)
+	ossl_raise(ePKeyError, "Could not parse PKey");
     return ossl_pkey_new(pkey);
 }
 
+static VALUE
+pkey_ctx_apply_options_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ctx_v))
+{
+    VALUE key = rb_ary_entry(i, 0), value = rb_ary_entry(i, 1);
+    EVP_PKEY_CTX *ctx = (EVP_PKEY_CTX *)ctx_v;
+
+    if (SYMBOL_P(key))
+        key = rb_sym2str(key);
+    value = rb_String(value);
+
+    if (EVP_PKEY_CTX_ctrl_str(ctx, StringValueCStr(key), StringValueCStr(value)) <= 0)
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_ctrl_str(ctx, %+"PRIsVALUE", %+"PRIsVALUE")",
+                   key, value);
+    return Qnil;
+}
+
+static VALUE
+pkey_ctx_apply_options0(VALUE args_v)
+{
+    VALUE *args = (VALUE *)args_v;
+
+    rb_block_call(args[1], rb_intern("each"), 0, NULL,
+                  pkey_ctx_apply_options_i, args[0]);
+    return Qnil;
+}
+
+static void
+pkey_ctx_apply_options(EVP_PKEY_CTX *ctx, VALUE options, int *state)
+{
+    VALUE args[2];
+    args[0] = (VALUE)ctx;
+    args[1] = options;
+
+    rb_protect(pkey_ctx_apply_options0, (VALUE)args, state);
+}
+
+struct pkey_blocking_generate_arg {
+    EVP_PKEY_CTX *ctx;
+    EVP_PKEY *pkey;
+    int state;
+    int yield: 1;
+    int genparam: 1;
+    int interrupted: 1;
+};
+
+static VALUE
+pkey_gen_cb_yield(VALUE ctx_v)
+{
+    EVP_PKEY_CTX *ctx = (void *)ctx_v;
+    int i, info_num;
+    VALUE *argv;
+
+    info_num = EVP_PKEY_CTX_get_keygen_info(ctx, -1);
+    argv = ALLOCA_N(VALUE, info_num);
+    for (i = 0; i < info_num; i++)
+        argv[i] = INT2NUM(EVP_PKEY_CTX_get_keygen_info(ctx, i));
+
+    return rb_yield_values2(info_num, argv);
+}
+
+static VALUE
+call_check_ints0(VALUE arg)
+{
+    rb_thread_check_ints();
+    return Qnil;
+}
+
+static void *
+call_check_ints(void *arg)
+{
+    int state;
+    rb_protect(call_check_ints0, Qnil, &state);
+    return (void *)(VALUE)state;
+}
+
+static int
+pkey_gen_cb(EVP_PKEY_CTX *ctx)
+{
+    struct pkey_blocking_generate_arg *arg = EVP_PKEY_CTX_get_app_data(ctx);
+    int state;
+
+    if (arg->yield) {
+        rb_protect(pkey_gen_cb_yield, (VALUE)ctx, &state);
+        if (state) {
+            arg->state = state;
+            return 0;
+        }
+    }
+    if (arg->interrupted) {
+        arg->interrupted = 0;
+        state = (int)(VALUE)rb_thread_call_with_gvl(call_check_ints, NULL);
+        if (state) {
+            arg->state = state;
+            return 0;
+        }
+    }
+    return 1;
+}
+
+static void
+pkey_blocking_gen_stop(void *ptr)
+{
+    struct pkey_blocking_generate_arg *arg = ptr;
+    arg->interrupted = 1;
+}
+
+static void *
+pkey_blocking_gen(void *ptr)
+{
+    struct pkey_blocking_generate_arg *arg = ptr;
+
+    if (arg->genparam && EVP_PKEY_paramgen(arg->ctx, &arg->pkey) <= 0)
+        return NULL;
+    if (!arg->genparam && EVP_PKEY_keygen(arg->ctx, &arg->pkey) <= 0)
+        return NULL;
+    return arg->pkey;
+}
+
+static VALUE
+pkey_generate(int argc, VALUE *argv, VALUE self, int genparam)
+{
+    EVP_PKEY_CTX *ctx;
+    VALUE alg, options;
+    struct pkey_blocking_generate_arg gen_arg = { 0 };
+    int state;
+
+    rb_scan_args(argc, argv, "11", &alg, &options);
+    if (rb_obj_is_kind_of(alg, cPKey)) {
+        EVP_PKEY *base_pkey;
+
+        GetPKey(alg, base_pkey);
+        ctx = EVP_PKEY_CTX_new(base_pkey, NULL/* engine */);
+        if (!ctx)
+            ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
+    }
+    else {
+#if OPENSSL_VERSION_MAJOR+0 >= 3
+        ctx = EVP_PKEY_CTX_new_from_name(NULL, StringValueCStr(alg), NULL);
+        if (!ctx)
+            ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_from_name");
+#else
+        const EVP_PKEY_ASN1_METHOD *ameth;
+        ENGINE *tmpeng;
+        int pkey_id;
+
+        StringValue(alg);
+        ameth = EVP_PKEY_asn1_find_str(&tmpeng, RSTRING_PTR(alg),
+                                       RSTRING_LENINT(alg));
+        if (!ameth)
+            ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", alg);
+        EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
+# ifndef OPENSSL_NO_ENGINE
+        if (tmpeng)
+            ENGINE_finish(tmpeng);
+# endif
+
+        ctx = EVP_PKEY_CTX_new_id(pkey_id, NULL/* engine */);
+        if (!ctx)
+            ossl_raise(ePKeyError, "EVP_PKEY_CTX_new_id");
+#endif
+    }
+
+    if (genparam && EVP_PKEY_paramgen_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_paramgen_init");
+    }
+    if (!genparam && EVP_PKEY_keygen_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_keygen_init");
+    }
+
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(ctx, options, &state);
+        if (state) {
+            EVP_PKEY_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+
+    gen_arg.genparam = genparam;
+    gen_arg.ctx = ctx;
+    gen_arg.yield = rb_block_given_p();
+    EVP_PKEY_CTX_set_app_data(ctx, &gen_arg);
+    EVP_PKEY_CTX_set_cb(ctx, pkey_gen_cb);
+    if (gen_arg.yield)
+        pkey_blocking_gen(&gen_arg);
+    else
+        rb_thread_call_without_gvl(pkey_blocking_gen, &gen_arg,
+                                   pkey_blocking_gen_stop, &gen_arg);
+    EVP_PKEY_CTX_free(ctx);
+    if (!gen_arg.pkey) {
+        if (gen_arg.state) {
+            ossl_clear_error();
+            rb_jump_tag(gen_arg.state);
+        }
+        else {
+            ossl_raise(ePKeyError, genparam ? "EVP_PKEY_paramgen" : "EVP_PKEY_keygen");
+        }
+    }
+
+    return ossl_pkey_new(gen_arg.pkey);
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::PKey.generate_parameters(algo_name [, options]) -> pkey
+ *
+ * Generates new parameters for the algorithm. _algo_name_ is a String that
+ * represents the algorithm. The optional argument _options_ is a Hash that
+ * specifies the options specific to the algorithm. The order of the options
+ * can be important.
+ *
+ * A block can be passed optionally. The meaning of the arguments passed to
+ * the block varies depending on the implementation of the algorithm. The block
+ * may be called once or multiple times, or may not even be called.
+ *
+ * For the supported options, see the documentation for the 'openssl genpkey'
+ * utility command.
+ *
+ * == Example
+ *   pkey = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
+ *   p pkey.p.num_bits #=> 2048
+ */
+static VALUE
+ossl_pkey_s_generate_parameters(int argc, VALUE *argv, VALUE self)
+{
+    return pkey_generate(argc, argv, self, 1);
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::PKey.generate_key(algo_name [, options]) -> pkey
+ *    OpenSSL::PKey.generate_key(pkey [, options]) -> pkey
+ *
+ * Generates a new key (pair).
+ *
+ * If a String is given as the first argument, it generates a new random key
+ * for the algorithm specified by the name just as ::generate_parameters does.
+ * If an OpenSSL::PKey::PKey is given instead, it generates a new random key
+ * for the same algorithm as the key, using the parameters the key contains.
+ *
+ * See ::generate_parameters for the details of _options_ and the given block.
+ *
+ * == Example
+ *   pkey_params = OpenSSL::PKey.generate_parameters("DSA", "dsa_paramgen_bits" => 2048)
+ *   pkey_params.priv_key #=> nil
+ *   pkey = OpenSSL::PKey.generate_key(pkey_params)
+ *   pkey.priv_key #=> #<OpenSSL::BN 6277...
+ */
+static VALUE
+ossl_pkey_s_generate_key(int argc, VALUE *argv, VALUE self)
+{
+    return pkey_generate(argc, argv, self, 0);
+}
+
+/* FIXME: Should track key state instead */
 void
 ossl_pkey_check_public_key(const EVP_PKEY *pkey)
 {
+#if OPENSSL_VERSION_MAJOR+0 >= 3
+    if (EVP_PKEY_missing_parameters(pkey))
+	ossl_raise(ePKeyError, "parameters missing");
+#else
     void *ptr;
     const BIGNUM *n, *e, *pubkey;
 
@@ -229,6 +472,7 @@
 	return;
     }
     ossl_raise(ePKeyError, "public key missing");
+#endif
 }
 
 EVP_PKEY *
@@ -246,12 +490,19 @@
 {
     EVP_PKEY *pkey;
 
-    if (rb_funcallv(obj, id_private_q, 0, NULL) != Qtrue) {
-	ossl_raise(rb_eArgError, "Private key is needed.");
-    }
     GetPKey(obj, pkey);
+    if (OSSL_PKEY_IS_PRIVATE(obj))
+        return pkey;
+    /*
+     * The EVP API does not provide a way to check if the EVP_PKEY has private
+     * components. Assuming it does...
+     */
+    if (!rb_respond_to(obj, id_private_q))
+        return pkey;
+    if (RTEST(rb_funcallv(obj, id_private_q, 0, NULL)))
+        return pkey;
 
-    return pkey;
+    rb_raise(rb_eArgError, "private key is needed");
 }
 
 EVP_PKEY *
@@ -271,16 +522,7 @@
 static VALUE
 ossl_pkey_alloc(VALUE klass)
 {
-    EVP_PKEY *pkey;
-    VALUE obj;
-
-    obj = NewPKey(klass);
-    if (!(pkey = EVP_PKEY_new())) {
-	ossl_raise(ePKeyError, NULL);
-    }
-    SetPKey(obj, pkey);
-
-    return obj;
+    return TypedData_Wrap_Struct(klass, &ossl_evp_pkey_type, NULL);
 }
 
 /*
@@ -299,6 +541,24 @@
     return self;
 }
 
+#ifdef HAVE_EVP_PKEY_DUP
+static VALUE
+ossl_pkey_initialize_copy(VALUE self, VALUE other)
+{
+    EVP_PKEY *pkey, *pkey_other;
+
+    GetPKey0(self, pkey);
+    GetPKey(other, pkey_other);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
+    pkey = EVP_PKEY_dup(pkey_other);
+    if (!pkey)
+        ossl_raise(ePKeyError, "EVP_PKEY_dup");
+    RTYPEDDATA_DATA(self) = pkey;
+    return self;
+}
+#endif
+
 /*
  * call-seq:
  *    pkey.oid -> string
@@ -335,6 +595,203 @@
                       OBJ_nid2sn(nid));
 }
 
+/*
+ * call-seq:
+ *    pkey.to_text -> string
+ *
+ * Dumps key parameters, public key, and private key components contained in
+ * the key into a human-readable text.
+ *
+ * This is intended for debugging purpose.
+ *
+ * See also the man page EVP_PKEY_print_private(3).
+ */
+static VALUE
+ossl_pkey_to_text(VALUE self)
+{
+    EVP_PKEY *pkey;
+    BIO *bio;
+
+    GetPKey(self, pkey);
+    if (!(bio = BIO_new(BIO_s_mem())))
+        ossl_raise(ePKeyError, "BIO_new");
+
+    if (EVP_PKEY_print_private(bio, pkey, 0, NULL) == 1)
+        goto out;
+    OSSL_BIO_reset(bio);
+    if (EVP_PKEY_print_public(bio, pkey, 0, NULL) == 1)
+        goto out;
+    OSSL_BIO_reset(bio);
+    if (EVP_PKEY_print_params(bio, pkey, 0, NULL) == 1)
+        goto out;
+
+    BIO_free(bio);
+    ossl_raise(ePKeyError, "EVP_PKEY_print_params");
+
+  out:
+    return ossl_membio2str(bio);
+}
+
+#ifdef HAVE_EVP_PKEY_TODATA
+static VALUE
+ossl_params_to_hash(VALUE paramsv)
+{
+    const OSSL_PARAM *params = (void *)paramsv;
+    VALUE hash = rb_hash_new();
+    size_t i;
+
+    for (i = 0; params[i].key; i++) {
+        const OSSL_PARAM *p = &params[i];
+        VALUE key = ID2SYM(rb_intern(p->key));
+
+        switch (p->data_type) {
+          case OSSL_PARAM_INTEGER:
+            rb_hash_aset(hash, key,
+                         ossl_bn_new_from_native(p->data, p->data_size));
+            break;
+          case OSSL_PARAM_UNSIGNED_INTEGER:
+            rb_hash_aset(hash, key,
+                         ossl_bn_new_from_native(p->data, p->data_size));
+            break;
+          case OSSL_PARAM_UTF8_STRING:
+            rb_hash_aset(hash, key, rb_str_new(p->data, p->data_size));
+            break;
+          default:
+            OSSL_Debug("ossl_params_to_hash: unsupported data type %d",
+                       (int)p->data_type);
+            break;
+        }
+    }
+    return hash;
+}
+#endif
+
+/*
+ * call-seq:
+ *    pkey.to_data -> hash
+ *
+ * Returns all information about the key in a Hash. This includes the key
+ * parameters, public and private key components, and all other miscellaneous
+ * information returned by the algorithm implementation.
+ *
+ * The key names vary depending on the algorithm and also the implementation.
+ *
+ * See also the man page EVP_PKEY_todata(3).
+ */
+static VALUE
+ossl_pkey_to_data(VALUE self)
+{
+#ifdef HAVE_EVP_PKEY_TODATA
+    EVP_PKEY *pkey;
+    OSSL_PARAM *params;
+    VALUE hash;
+    int state;
+
+    GetPKey(self, pkey);
+    if (EVP_PKEY_todata(pkey, OSSL_KEYMGMT_SELECT_ALL, &params) != 1)
+        ossl_raise(ePKeyError, "EVP_PKEY_todata");
+    hash = rb_protect(ossl_params_to_hash, (VALUE)params, &state);
+    OSSL_PARAM_free(params);
+    if (state)
+        rb_jump_tag(state);
+    return hash;
+#else
+    return rb_hash_new();
+#endif
+}
+
+/*
+ * :nodoc:
+ *
+ * call-seq:
+ *    pkey.get_bn_param(key) -> bn
+ *
+ * Retrieves a BIGNUM value associated with a name of +key+.
+ *
+ * See also #to_data, which returns all available parameters.
+ *
+ * See also the man page EVP_PKEY_get_bn_param(3).
+ */
+static VALUE
+ossl_pkey_get_bn_param(VALUE self, VALUE key)
+{
+#ifdef HAVE_EVP_PKEY_TODATA
+    EVP_PKEY *pkey;
+    BIGNUM *bn;
+    VALUE ret;
+
+    GetPKey(self, pkey);
+    ret = ossl_bn_new(NULL);
+    bn = GetBNPtr(ret);
+    if (SYMBOL_P(key))
+        key = rb_sym2str(key);
+
+    // It might be actually an error: for example, memory allocation failure
+    // This must use OSSL_PARAM directly instead
+    if (EVP_PKEY_get_bn_param(pkey, StringValueCStr(key), &bn) != 1)
+        return Qnil;
+
+    return ret;
+#else
+    VALUE ret, hash;
+
+    /* Let's assume the subclass implements #to_data */
+    hash = rb_funcall(self, rb_intern("to_data"), 0);
+    Check_Type(hash, T_HASH);
+    ret = rb_hash_aref(hash, key);
+    if (!NIL_P(ret) && !rb_obj_is_kind_of(ret, cBN))
+        rb_raise(ePKeyError, "key not found");
+
+    return ret;
+#endif
+}
+
+VALUE
+ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self, int to_der)
+{
+    EVP_PKEY *pkey;
+    VALUE cipher, pass;
+    const EVP_CIPHER *enc = NULL;
+    BIO *bio;
+
+    GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "02", &cipher, &pass);
+    if (!NIL_P(cipher)) {
+	enc = ossl_evp_get_cipherbyname(cipher);
+	pass = ossl_pem_passwd_value(pass);
+    }
+
+    bio = BIO_new(BIO_s_mem());
+    if (!bio)
+	ossl_raise(ePKeyError, "BIO_new");
+    if (to_der) {
+	if (!i2d_PrivateKey_bio(bio, pkey)) {
+	    BIO_free(bio);
+	    ossl_raise(ePKeyError, "i2d_PrivateKey_bio");
+	}
+    }
+    else {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+	if (!PEM_write_bio_PrivateKey_traditional(bio, pkey, enc, NULL, 0,
+						  ossl_pem_passwd_cb,
+						  (void *)pass)) {
+#else
+	char pem_str[80];
+	const char *aname;
+
+	EVP_PKEY_asn1_get0_info(NULL, NULL, NULL, NULL, &aname, pkey->ameth);
+	snprintf(pem_str, sizeof(pem_str), "%s PRIVATE KEY", aname);
+	if (!PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, pem_str, bio,
+				pkey, enc, NULL, 0, ossl_pem_passwd_cb,
+				(void *)pass)) {
+#endif
+	    BIO_free(bio);
+	    ossl_raise(ePKeyError, "PEM_write_bio_PrivateKey_traditional");
+	}
+    }
+    return ossl_membio2str(bio);
+}
+
 static VALUE
 do_pkcs8_export(int argc, VALUE *argv, VALUE self, int to_der)
 {
@@ -404,8 +861,8 @@
     return do_pkcs8_export(argc, argv, self, 0);
 }
 
-static VALUE
-do_spki_export(VALUE self, int to_der)
+VALUE
+ossl_pkey_export_spki(VALUE self, int to_der)
 {
     EVP_PKEY *pkey;
     BIO *bio;
@@ -438,7 +895,7 @@
 static VALUE
 ossl_pkey_public_to_der(VALUE self)
 {
-    return do_spki_export(self, 1);
+    return ossl_pkey_export_spki(self, 1);
 }
 
 /*
@@ -450,119 +907,659 @@
 static VALUE
 ossl_pkey_public_to_pem(VALUE self)
 {
-    return do_spki_export(self, 0);
+    return ossl_pkey_export_spki(self, 0);
 }
 
 /*
  *  call-seq:
- *      pkey.sign(digest, data) -> String
+ *      pkey.compare?(another_pkey) -> true | false
  *
- * To sign the String _data_, _digest_, an instance of OpenSSL::Digest, must
- * be provided. The return value is again a String containing the signature.
- * A PKeyError is raised should errors occur.
- * Any previous state of the Digest instance is irrelevant to the signature
- * outcome, the digest instance is reset to its initial state during the
- * operation.
+ * Used primarily to check if an OpenSSL::X509::Certificate#public_key compares to its private key.
  *
  * == Example
- *   data = 'Sign me!'
- *   digest = OpenSSL::Digest.new('SHA256')
- *   pkey = OpenSSL::PKey::RSA.new(2048)
- *   signature = pkey.sign(digest, data)
+ *   x509 = OpenSSL::X509::Certificate.new(pem_encoded_certificate)
+ *   rsa_key = OpenSSL::PKey::RSA.new(pem_encoded_private_key)
+ *
+ *   rsa_key.compare?(x509.public_key) => true | false
  */
 static VALUE
-ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
+ossl_pkey_compare(VALUE self, VALUE other)
+{
+    int ret;
+    EVP_PKEY *selfPKey;
+    EVP_PKEY *otherPKey;
+
+    GetPKey(self, selfPKey);
+    GetPKey(other, otherPKey);
+
+    /* Explicitly check the key type given EVP_PKEY_ASN1_METHOD(3)
+     * docs param_cmp could return any negative number.
+     */
+    if (EVP_PKEY_id(selfPKey) != EVP_PKEY_id(otherPKey))
+        ossl_raise(rb_eTypeError, "cannot match different PKey types");
+
+    ret = EVP_PKEY_eq(selfPKey, otherPKey);
+
+    if (ret == 0)
+        return Qfalse;
+    else if (ret == 1)
+        return Qtrue;
+    else
+        ossl_raise(ePKeyError, "EVP_PKEY_eq");
+}
+
+/*
+ * call-seq:
+ *    pkey.sign(digest, data [, options]) -> string
+ *
+ * Hashes and signs the +data+ using a message digest algorithm +digest+ and
+ * a private key +pkey+.
+ *
+ * See #verify for the verification operation.
+ *
+ * See also the man page EVP_DigestSign(3).
+ *
+ * +digest+::
+ *   A String that represents the message digest algorithm name, or +nil+
+ *   if the PKey type requires no digest algorithm.
+ *   For backwards compatibility, this can be an instance of OpenSSL::Digest.
+ *   Its state will not affect the signature.
+ * +data+::
+ *   A String. The data to be hashed and signed.
+ * +options+::
+ *   A Hash that contains algorithm specific control operations to \OpenSSL.
+ *   See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
+ *   +options+ parameter was added in version 3.0.
+ *
+ * Example:
+ *   data = "Sign me!"
+ *   pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
+ *   signopts = { rsa_padding_mode: "pss" }
+ *   signature = pkey.sign("SHA256", data, signopts)
+ *
+ *   # Creates a copy of the RSA key pkey, but without the private components
+ *   pub_key = pkey.public_key
+ *   puts pub_key.verify("SHA256", signature, data, signopts) # => true
+ */
+static VALUE
+ossl_pkey_sign(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
-    const EVP_MD *md;
+    VALUE digest, data, options, sig;
+    const EVP_MD *md = NULL;
     EVP_MD_CTX *ctx;
-    unsigned int buf_len;
-    VALUE str;
-    int result;
+    EVP_PKEY_CTX *pctx;
+    size_t siglen;
+    int state;
 
     pkey = GetPrivPKeyPtr(self);
-    md = ossl_evp_get_digestbyname(digest);
+    rb_scan_args(argc, argv, "21", &digest, &data, &options);
+    if (!NIL_P(digest))
+        md = ossl_evp_get_digestbyname(digest);
     StringValue(data);
-    str = rb_str_new(0, EVP_PKEY_size(pkey));
 
     ctx = EVP_MD_CTX_new();
     if (!ctx)
-	ossl_raise(ePKeyError, "EVP_MD_CTX_new");
-    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");
+        ossl_raise(ePKeyError, "EVP_MD_CTX_new");
+    if (EVP_DigestSignInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestSignInit");
+    }
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(pctx, options, &state);
+        if (state) {
+            EVP_MD_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
+    if (EVP_DigestSign(ctx, NULL, &siglen, (unsigned char *)RSTRING_PTR(data),
+                       RSTRING_LEN(data)) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestSign");
+    }
+    if (siglen > LONG_MAX) {
+        EVP_MD_CTX_free(ctx);
+        rb_raise(ePKeyError, "signature would be too large");
+    }
+    sig = ossl_str_new(NULL, (long)siglen, &state);
+    if (state) {
+        EVP_MD_CTX_free(ctx);
+        rb_jump_tag(state);
+    }
+    if (EVP_DigestSign(ctx, (unsigned char *)RSTRING_PTR(sig), &siglen,
+                       (unsigned char *)RSTRING_PTR(data),
+                       RSTRING_LEN(data)) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestSign");
+    }
+#else
+    if (EVP_DigestSignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestSignUpdate");
+    }
+    if (EVP_DigestSignFinal(ctx, NULL, &siglen) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestSignFinal");
+    }
+    if (siglen > LONG_MAX) {
+        EVP_MD_CTX_free(ctx);
+        rb_raise(ePKeyError, "signature would be too large");
     }
-    result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
+    sig = ossl_str_new(NULL, (long)siglen, &state);
+    if (state) {
+        EVP_MD_CTX_free(ctx);
+        rb_jump_tag(state);
+    }
+    if (EVP_DigestSignFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
+                            &siglen) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestSignFinal");
+    }
+#endif
     EVP_MD_CTX_free(ctx);
-    if (!result)
-	ossl_raise(ePKeyError, "EVP_SignFinal");
-    rb_str_set_len(str, buf_len);
-
-    return str;
+    rb_str_set_len(sig, siglen);
+    return sig;
 }
 
 /*
- *  call-seq:
- *      pkey.verify(digest, signature, data) -> String
+ * call-seq:
+ *    pkey.verify(digest, signature, data [, options]) -> true or false
  *
- * To verify the String _signature_, _digest_, an instance of
- * OpenSSL::Digest, must be provided to re-compute the message digest of the
- * original _data_, also a String. The return value is +true+ if the
- * signature is valid, +false+ otherwise. A PKeyError is raised should errors
- * occur.
- * Any previous state of the Digest instance is irrelevant to the validation
- * outcome, the digest instance is reset to its initial state during the
- * operation.
+ * Verifies the +signature+ for the +data+ using a message digest algorithm
+ * +digest+ and a public key +pkey+.
  *
- * == Example
- *   data = 'Sign me!'
- *   digest = OpenSSL::Digest.new('SHA256')
- *   pkey = OpenSSL::PKey::RSA.new(2048)
- *   signature = pkey.sign(digest, data)
- *   pub_key = pkey.public_key
- *   puts pub_key.verify(digest, signature, data) # => true
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
+ * The caller must check the return value.
+ *
+ * See #sign for the signing operation and an example.
+ *
+ * See also the man page EVP_DigestVerify(3).
+ *
+ * +digest+::
+ *   See #sign.
+ * +signature+::
+ *   A String containing the signature to be verified.
+ * +data+::
+ *   See #sign.
+ * +options+::
+ *   See #sign. +options+ parameter was added in version 3.0.
  */
 static VALUE
-ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
+ossl_pkey_verify(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
-    const EVP_MD *md;
+    VALUE digest, sig, data, options;
+    const EVP_MD *md = NULL;
     EVP_MD_CTX *ctx;
-    int siglen, result;
+    EVP_PKEY_CTX *pctx;
+    int state, ret;
 
     GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
     ossl_pkey_check_public_key(pkey);
-    md = ossl_evp_get_digestbyname(digest);
+    if (!NIL_P(digest))
+        md = ossl_evp_get_digestbyname(digest);
     StringValue(sig);
-    siglen = RSTRING_LENINT(sig);
     StringValue(data);
 
     ctx = EVP_MD_CTX_new();
     if (!ctx)
-	ossl_raise(ePKeyError, "EVP_MD_CTX_new");
-    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");
+        ossl_raise(ePKeyError, "EVP_MD_CTX_new");
+    if (EVP_DigestVerifyInit(ctx, &pctx, md, /* engine */NULL, pkey) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestVerifyInit");
+    }
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(pctx, options, &state);
+        if (state) {
+            EVP_MD_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+#if OPENSSL_VERSION_NUMBER >= 0x10101000 && !defined(LIBRESSL_VERSION_NUMBER)
+    ret = EVP_DigestVerify(ctx, (unsigned char *)RSTRING_PTR(sig),
+                           RSTRING_LEN(sig), (unsigned char *)RSTRING_PTR(data),
+                           RSTRING_LEN(data));
+    EVP_MD_CTX_free(ctx);
+    if (ret < 0)
+        ossl_raise(ePKeyError, "EVP_DigestVerify");
+#else
+    if (EVP_DigestVerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data)) < 1) {
+        EVP_MD_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_DigestVerifyUpdate");
     }
-    result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
+    ret = EVP_DigestVerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig),
+                                RSTRING_LEN(sig));
     EVP_MD_CTX_free(ctx);
-    switch (result) {
-    case 0:
-	ossl_clear_error();
-	return Qfalse;
-    case 1:
-	return Qtrue;
-    default:
-	ossl_raise(ePKeyError, "EVP_VerifyFinal");
+    if (ret < 0)
+        ossl_raise(ePKeyError, "EVP_DigestVerifyFinal");
+#endif
+    if (ret)
+        return Qtrue;
+    else {
+        ossl_clear_error();
+        return Qfalse;
+    }
+}
+
+/*
+ * call-seq:
+ *    pkey.sign_raw(digest, data [, options]) -> string
+ *
+ * Signs +data+ using a private key +pkey+. Unlike #sign, +data+ will not be
+ * hashed by +digest+ automatically.
+ *
+ * See #verify_raw for the verification operation.
+ *
+ * Added in version 3.0. See also the man page EVP_PKEY_sign(3).
+ *
+ * +digest+::
+ *   A String that represents the message digest algorithm name, or +nil+
+ *   if the PKey type requires no digest algorithm.
+ *   Although this method will not hash +data+ with it, this parameter may still
+ *   be required depending on the signature algorithm.
+ * +data+::
+ *   A String. The data to be signed.
+ * +options+::
+ *   A Hash that contains algorithm specific control operations to \OpenSSL.
+ *   See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
+ *
+ * Example:
+ *   data = "Sign me!"
+ *   hash = OpenSSL::Digest.digest("SHA256", data)
+ *   pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
+ *   signopts = { rsa_padding_mode: "pss" }
+ *   signature = pkey.sign_raw("SHA256", hash, signopts)
+ *
+ *   # Creates a copy of the RSA key pkey, but without the private components
+ *   pub_key = pkey.public_key
+ *   puts pub_key.verify_raw("SHA256", signature, hash, signopts) # => true
+ */
+static VALUE
+ossl_pkey_sign_raw(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    VALUE digest, data, options, sig;
+    const EVP_MD *md = NULL;
+    EVP_PKEY_CTX *ctx;
+    size_t outlen;
+    int state;
+
+    GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "21", &digest, &data, &options);
+    if (!NIL_P(digest))
+        md = ossl_evp_get_digestbyname(digest);
+    StringValue(data);
+
+    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!ctx)
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
+    if (EVP_PKEY_sign_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_sign_init");
+    }
+    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
+    }
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(ctx, options, &state);
+        if (state) {
+            EVP_PKEY_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+    if (EVP_PKEY_sign(ctx, NULL, &outlen, (unsigned char *)RSTRING_PTR(data),
+                      RSTRING_LEN(data)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_sign");
+    }
+    if (outlen > LONG_MAX) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_raise(ePKeyError, "signature would be too large");
+    }
+    sig = ossl_str_new(NULL, (long)outlen, &state);
+    if (state) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_jump_tag(state);
+    }
+    if (EVP_PKEY_sign(ctx, (unsigned char *)RSTRING_PTR(sig), &outlen,
+                      (unsigned char *)RSTRING_PTR(data),
+                      RSTRING_LEN(data)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_sign");
     }
+    EVP_PKEY_CTX_free(ctx);
+    rb_str_set_len(sig, outlen);
+    return sig;
+}
+
+/*
+ * call-seq:
+ *    pkey.verify_raw(digest, signature, data [, options]) -> true or false
+ *
+ * Verifies the +signature+ for the +data+ using a public key +pkey+. Unlike
+ * #verify, this method will not hash +data+ with +digest+ automatically.
+ *
+ * Returns +true+ if the signature is successfully verified, +false+ otherwise.
+ * The caller must check the return value.
+ *
+ * See #sign_raw for the signing operation and an example code.
+ *
+ * Added in version 3.0. See also the man page EVP_PKEY_verify(3).
+ *
+ * +signature+::
+ *   A String containing the signature to be verified.
+ */
+static VALUE
+ossl_pkey_verify_raw(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    VALUE digest, sig, data, options;
+    const EVP_MD *md = NULL;
+    EVP_PKEY_CTX *ctx;
+    int state, ret;
+
+    GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "31", &digest, &sig, &data, &options);
+    ossl_pkey_check_public_key(pkey);
+    if (!NIL_P(digest))
+        md = ossl_evp_get_digestbyname(digest);
+    StringValue(sig);
+    StringValue(data);
+
+    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!ctx)
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
+    if (EVP_PKEY_verify_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_verify_init");
+    }
+    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
+    }
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(ctx, options, &state);
+        if (state) {
+            EVP_PKEY_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+    ret = EVP_PKEY_verify(ctx, (unsigned char *)RSTRING_PTR(sig),
+                          RSTRING_LEN(sig),
+                          (unsigned char *)RSTRING_PTR(data),
+                          RSTRING_LEN(data));
+    EVP_PKEY_CTX_free(ctx);
+    if (ret < 0)
+        ossl_raise(ePKeyError, "EVP_PKEY_verify");
+
+    if (ret)
+        return Qtrue;
+    else {
+        ossl_clear_error();
+        return Qfalse;
+    }
+}
+
+/*
+ * call-seq:
+ *    pkey.verify_recover(digest, signature [, options]) -> string
+ *
+ * Recovers the signed data from +signature+ using a public key +pkey+. Not all
+ * signature algorithms support this operation.
+ *
+ * Added in version 3.0. See also the man page EVP_PKEY_verify_recover(3).
+ *
+ * +signature+::
+ *   A String containing the signature to be verified.
+ */
+static VALUE
+ossl_pkey_verify_recover(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    VALUE digest, sig, options, out;
+    const EVP_MD *md = NULL;
+    EVP_PKEY_CTX *ctx;
+    int state;
+    size_t outlen;
+
+    GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "21", &digest, &sig, &options);
+    ossl_pkey_check_public_key(pkey);
+    if (!NIL_P(digest))
+        md = ossl_evp_get_digestbyname(digest);
+    StringValue(sig);
+
+    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!ctx)
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
+    if (EVP_PKEY_verify_recover_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_verify_recover_init");
+    }
+    if (md && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_set_signature_md");
+    }
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(ctx, options, &state);
+        if (state) {
+            EVP_PKEY_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+    if (EVP_PKEY_verify_recover(ctx, NULL, &outlen,
+                                (unsigned char *)RSTRING_PTR(sig),
+                                RSTRING_LEN(sig)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
+    }
+    out = ossl_str_new(NULL, (long)outlen, &state);
+    if (state) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_jump_tag(state);
+    }
+    if (EVP_PKEY_verify_recover(ctx, (unsigned char *)RSTRING_PTR(out), &outlen,
+                                (unsigned char *)RSTRING_PTR(sig),
+                                RSTRING_LEN(sig)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_verify_recover");
+    }
+    EVP_PKEY_CTX_free(ctx);
+    rb_str_set_len(out, outlen);
+    return out;
+}
+
+/*
+ * call-seq:
+ *    pkey.derive(peer_pkey) -> string
+ *
+ * Derives a shared secret from _pkey_ and _peer_pkey_. _pkey_ must contain
+ * the private components, _peer_pkey_ must contain the public components.
+ */
+static VALUE
+ossl_pkey_derive(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey, *peer_pkey;
+    EVP_PKEY_CTX *ctx;
+    VALUE peer_pkey_obj, str;
+    size_t keylen;
+    int state;
+
+    GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "1", &peer_pkey_obj);
+    GetPKey(peer_pkey_obj, peer_pkey);
+
+    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!ctx)
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
+    if (EVP_PKEY_derive_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_derive_init");
+    }
+    if (EVP_PKEY_derive_set_peer(ctx, peer_pkey) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_derive_set_peer");
+    }
+    if (EVP_PKEY_derive(ctx, NULL, &keylen) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_derive");
+    }
+    if (keylen > LONG_MAX)
+        rb_raise(ePKeyError, "derived key would be too large");
+    str = ossl_str_new(NULL, (long)keylen, &state);
+    if (state) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_jump_tag(state);
+    }
+    if (EVP_PKEY_derive(ctx, (unsigned char *)RSTRING_PTR(str), &keylen) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_derive");
+    }
+    EVP_PKEY_CTX_free(ctx);
+    rb_str_set_len(str, keylen);
+    return str;
+}
+
+/*
+ * call-seq:
+ *    pkey.encrypt(data [, options]) -> string
+ *
+ * Performs a public key encryption operation using +pkey+.
+ *
+ * See #decrypt for the reverse operation.
+ *
+ * Added in version 3.0. See also the man page EVP_PKEY_encrypt(3).
+ *
+ * +data+::
+ *   A String to be encrypted.
+ * +options+::
+ *   A Hash that contains algorithm specific control operations to \OpenSSL.
+ *   See OpenSSL's man page EVP_PKEY_CTX_ctrl_str(3) for details.
+ *
+ * Example:
+ *   pkey = OpenSSL::PKey.generate_key("RSA", rsa_keygen_bits: 2048)
+ *   data = "secret data"
+ *   encrypted = pkey.encrypt(data, rsa_padding_mode: "oaep")
+ *   decrypted = pkey.decrypt(data, rsa_padding_mode: "oaep")
+ *   p decrypted #=> "secret data"
+ */
+static VALUE
+ossl_pkey_encrypt(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    EVP_PKEY_CTX *ctx;
+    VALUE data, options, str;
+    size_t outlen;
+    int state;
+
+    GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "11", &data, &options);
+    StringValue(data);
+
+    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!ctx)
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
+    if (EVP_PKEY_encrypt_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_encrypt_init");
+    }
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(ctx, options, &state);
+        if (state) {
+            EVP_PKEY_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+    if (EVP_PKEY_encrypt(ctx, NULL, &outlen,
+                         (unsigned char *)RSTRING_PTR(data),
+                         RSTRING_LEN(data)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
+    }
+    if (outlen > LONG_MAX) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_raise(ePKeyError, "encrypted data would be too large");
+    }
+    str = ossl_str_new(NULL, (long)outlen, &state);
+    if (state) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_jump_tag(state);
+    }
+    if (EVP_PKEY_encrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
+                         (unsigned char *)RSTRING_PTR(data),
+                         RSTRING_LEN(data)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_encrypt");
+    }
+    EVP_PKEY_CTX_free(ctx);
+    rb_str_set_len(str, outlen);
+    return str;
+}
+
+/*
+ * call-seq:
+ *    pkey.decrypt(data [, options]) -> string
+ *
+ * Performs a public key decryption operation using +pkey+.
+ *
+ * See #encrypt for a description of the parameters and an example.
+ *
+ * Added in version 3.0. See also the man page EVP_PKEY_decrypt(3).
+ */
+static VALUE
+ossl_pkey_decrypt(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    EVP_PKEY_CTX *ctx;
+    VALUE data, options, str;
+    size_t outlen;
+    int state;
+
+    GetPKey(self, pkey);
+    rb_scan_args(argc, argv, "11", &data, &options);
+    StringValue(data);
+
+    ctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!ctx)
+        ossl_raise(ePKeyError, "EVP_PKEY_CTX_new");
+    if (EVP_PKEY_decrypt_init(ctx) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_decrypt_init");
+    }
+    if (!NIL_P(options)) {
+        pkey_ctx_apply_options(ctx, options, &state);
+        if (state) {
+            EVP_PKEY_CTX_free(ctx);
+            rb_jump_tag(state);
+        }
+    }
+    if (EVP_PKEY_decrypt(ctx, NULL, &outlen,
+                         (unsigned char *)RSTRING_PTR(data),
+                         RSTRING_LEN(data)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
+    }
+    if (outlen > LONG_MAX) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_raise(ePKeyError, "decrypted data would be too large");
+    }
+    str = ossl_str_new(NULL, (long)outlen, &state);
+    if (state) {
+        EVP_PKEY_CTX_free(ctx);
+        rb_jump_tag(state);
+    }
+    if (EVP_PKEY_decrypt(ctx, (unsigned char *)RSTRING_PTR(str), &outlen,
+                         (unsigned char *)RSTRING_PTR(data),
+                         RSTRING_LEN(data)) <= 0) {
+        EVP_PKEY_CTX_free(ctx);
+        ossl_raise(ePKeyError, "EVP_PKEY_decrypt");
+    }
+    EVP_PKEY_CTX_free(ctx);
+    rb_str_set_len(str, outlen);
+    return str;
 }
 
 /*
@@ -648,18 +1645,35 @@
     cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
 
     rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
+    rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
+    rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
 
     rb_define_alloc_func(cPKey, ossl_pkey_alloc);
     rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
+#ifdef HAVE_EVP_PKEY_DUP
+    rb_define_method(cPKey, "initialize_copy", ossl_pkey_initialize_copy, 1);
+#else
+    rb_undef_method(cPKey, "initialize_copy");
+#endif
     rb_define_method(cPKey, "oid", ossl_pkey_oid, 0);
     rb_define_method(cPKey, "inspect", ossl_pkey_inspect, 0);
+    rb_define_method(cPKey, "to_text", ossl_pkey_to_text, 0);
+    rb_define_method(cPKey, "to_data", ossl_pkey_to_data, 0);
+    rb_define_method(cPKey, "get_bn_param", ossl_pkey_get_bn_param, 1);
     rb_define_method(cPKey, "private_to_der", ossl_pkey_private_to_der, -1);
     rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
     rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
     rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
+    rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1);
 
-    rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
-    rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
+    rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
+    rb_define_method(cPKey, "verify", ossl_pkey_verify, -1);
+    rb_define_method(cPKey, "sign_raw", ossl_pkey_sign_raw, -1);
+    rb_define_method(cPKey, "verify_raw", ossl_pkey_verify_raw, -1);
+    rb_define_method(cPKey, "verify_recover", ossl_pkey_verify_recover, -1);
+    rb_define_method(cPKey, "derive", ossl_pkey_derive, -1);
+    rb_define_method(cPKey, "encrypt", ossl_pkey_encrypt, -1);
+    rb_define_method(cPKey, "decrypt", ossl_pkey_decrypt, -1);
 
     id_private_q = rb_intern("private?");
 
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_pkey_dh.c ruby-3.0.2/ext/openssl/ossl_pkey_dh.c
--- ruby-3.0.2.orig/ext/openssl/ossl_pkey_dh.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_pkey_dh.c	2021-09-09 18:27:58.354594302 +0800
@@ -30,216 +30,105 @@
 VALUE eDHError;
 
 /*
- * Public
- */
-static VALUE
-dh_instance(VALUE klass, DH *dh)
-{
-    EVP_PKEY *pkey;
-    VALUE obj;
-
-    if (!dh) {
-	return Qfalse;
-    }
-    obj = NewPKey(klass);
-    if (!(pkey = EVP_PKEY_new())) {
-	return Qfalse;
-    }
-    if (!EVP_PKEY_assign_DH(pkey, dh)) {
-	EVP_PKEY_free(pkey);
-	return Qfalse;
-    }
-    SetPKey(obj, pkey);
-
-    return obj;
-}
-
-VALUE
-ossl_dh_new(EVP_PKEY *pkey)
-{
-    VALUE obj;
-
-    if (!pkey) {
-	obj = dh_instance(cDH, DH_new());
-    } else {
-	obj = NewPKey(cDH);
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DH) {
-	    ossl_raise(rb_eTypeError, "Not a DH key!");
-	}
-	SetPKey(obj, pkey);
-    }
-    if (obj == Qfalse) {
-	ossl_raise(eDHError, NULL);
-    }
-
-    return obj;
-}
-
-/*
  * Private
  */
-struct dh_blocking_gen_arg {
-    DH *dh;
-    int size;
-    int gen;
-    BN_GENCB *cb;
-    int result;
-};
-
-static void *
-dh_blocking_gen(void *arg)
-{
-    struct dh_blocking_gen_arg *gen = (struct dh_blocking_gen_arg *)arg;
-    gen->result = DH_generate_parameters_ex(gen->dh, gen->size, gen->gen, gen->cb);
-    return 0;
-}
-
-static DH *
-dh_generate(int size, int gen)
-{
-    struct ossl_generate_cb_arg cb_arg = { 0 };
-    struct dh_blocking_gen_arg gen_arg;
-    DH *dh = DH_new();
-    BN_GENCB *cb = BN_GENCB_new();
-
-    if (!dh || !cb) {
-	DH_free(dh);
-	BN_GENCB_free(cb);
-	return NULL;
-    }
-
-    if (rb_block_given_p())
-	cb_arg.yield = 1;
-    BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg);
-    gen_arg.dh = dh;
-    gen_arg.size = size;
-    gen_arg.gen = gen;
-    gen_arg.cb = cb;
-    if (cb_arg.yield == 1) {
-	/* we cannot release GVL when callback proc is supplied */
-	dh_blocking_gen(&gen_arg);
-    } else {
-	/* there's a chance to unblock */
-	rb_thread_call_without_gvl(dh_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg);
-    }
-
-    BN_GENCB_free(cb);
-    if (!gen_arg.result) {
-	DH_free(dh);
-	if (cb_arg.state) {
-	    /* Clear OpenSSL error queue before re-raising. */
-	    ossl_clear_error();
-	    rb_jump_tag(cb_arg.state);
-	}
-	return NULL;
-    }
-
-    if (!DH_generate_key(dh)) {
-        DH_free(dh);
-        return NULL;
-    }
-
-    return dh;
-}
-
-/*
- *  call-seq:
- *     DH.generate(size [, generator]) -> dh
- *
- * Creates a new DH instance from scratch by generating the private and public
- * components alike.
- *
- * === Parameters
- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.
- * * _generator_ is a small number > 1, typically 2 or 5.
- *
- */
-static VALUE
-ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
-{
-    DH *dh ;
-    int g = 2;
-    VALUE size, gen, obj;
-
-    if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
-	g = NUM2INT(gen);
-    }
-    dh = dh_generate(NUM2INT(size), g);
-    obj = dh_instance(klass, dh);
-    if (obj == Qfalse) {
-	DH_free(dh);
-	ossl_raise(eDHError, NULL);
-    }
-
-    return obj;
-}
-
 /*
  * call-seq:
  *   DH.new -> dh
  *   DH.new(string) -> dh
  *   DH.new(size [, generator]) -> dh
  *
- * Either generates a DH instance from scratch or by reading already existing
- * DH parameters from _string_. Note that when reading a DH instance from
- * data that was encoded from a DH instance by using DH#to_pem or DH#to_der
- * the result will *not* contain a public/private key pair yet. This needs to
- * be generated using DH#generate_key! first.
- *
- * === Parameters
- * * _size_ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.
- * * _generator_ is a small number > 1, typically 2 or 5.
- * * _string_ contains the DER or PEM encoded key.
- *
- * === Examples
- *  DH.new # -> dh
- *  DH.new(1024) # -> dh
- *  DH.new(1024, 5) # -> dh
- *  #Reading DH parameters
- *  dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet
- *  dh.generate_key! # -> dh with public and private key
+ * Creates a new instance of OpenSSL::PKey::DH.
+ *
+ * If called without arguments, an empty instance without any parameter or key
+ * components is created. Use #set_pqg to manually set the parameters afterwards
+ * (and optionally #set_key to set private and public key components).
+ *
+ * If a String is given, tries to parse it as a DER- or PEM- encoded parameters.
+ * See also OpenSSL::PKey.read which can parse keys of any kinds.
+ *
+ * The DH.new(size [, generator]) form is an alias of DH.generate.
+ *
+ * +string+::
+ *   A String that contains the DER or PEM encoded key.
+ * +size+::
+ *   See DH.generate.
+ * +generator+::
+ *   See DH.generate.
+ *
+ * Examples:
+ *   # Creating an instance from scratch
+ *   dh = DH.new
+ *   dh.set_pqg(bn_p, nil, bn_g)
+ *
+ *   # Generating a parameters and a key pair
+ *   dh = DH.new(2048) # An alias of DH.generate(2048)
+ *
+ *   # Reading DH parameters
+ *   dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet
+ *   dh.generate_key! # -> dh with public and private key
  */
 static VALUE
 ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
 {
     EVP_PKEY *pkey;
     DH *dh;
-    int g = 2;
     BIO *in;
-    VALUE arg, gen;
+    VALUE arg;
 
-    GetPKey(self, pkey);
-    if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) {
-      dh = DH_new();
-    }
-    else if (RB_INTEGER_TYPE_P(arg)) {
-	if (!NIL_P(gen)) {
-	    g = NUM2INT(gen);
-	}
-	if (!(dh = dh_generate(NUM2INT(arg), g))) {
-	    ossl_raise(eDHError, NULL);
-	}
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
+
+    /* The DH.new(size, generator) form is handled by lib/openssl/pkey.rb */
+    if (rb_scan_args(argc, argv, "01", &arg) == 0) {
+        dh = DH_new();
+        if (!dh)
+            ossl_raise(eDHError, "DH_new");
     }
     else {
-	arg = ossl_to_der_if_possible(arg);
-	in = ossl_obj2bio(&arg);
-	dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
-	if (!dh){
-	    OSSL_BIO_reset(in);
-	    dh = d2i_DHparams_bio(in, NULL);
-	}
-	BIO_free(in);
-	if (!dh) {
-	    ossl_raise(eDHError, NULL);
-	}
-    }
-    if (!EVP_PKEY_assign_DH(pkey, dh)) {
-	DH_free(dh);
-	ossl_raise(eDHError, NULL);
+        int type;
+
+        arg = ossl_to_der_if_possible(arg);
+        in = ossl_obj2bio(&arg);
+
+        /* First try DER-encoded parameters */
+        dh = d2i_DHparams_bio(in, NULL);
+        OSSL_BIO_reset(in);
+        if (dh) {
+            BIO_free(in);
+            goto legacy;
+        }
+
+        /* Use the generic routine - parses PEM-encoded parameters */
+        pkey = ossl_pkey_read_generic(in, Qnil);
+        BIO_free(in);
+        if (!pkey)
+            ossl_raise(eDHError, "could not parse pkey");
+
+        type = EVP_PKEY_base_id(pkey);
+        if (type != EVP_PKEY_DH) {
+            EVP_PKEY_free(pkey);
+            rb_raise(eDHError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+        }
+        RTYPEDDATA_DATA(self) = pkey;
+        return self;
+    }
+
+  legacy:
+    if (dh) {
+        pkey = EVP_PKEY_new();
+        if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
+            EVP_PKEY_free(pkey);
+            DH_free(dh);
+            ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+        }
     }
+    RTYPEDDATA_DATA(self) = pkey;
     return self;
 }
 
+#ifndef HAVE_EVP_PKEY_DUP
 static VALUE
 ossl_dh_initialize_copy(VALUE self, VALUE other)
 {
@@ -247,15 +136,14 @@
     DH *dh, *dh_other;
     const BIGNUM *pub, *priv;
 
-    GetPKey(self, pkey);
-    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
-	ossl_raise(eDHError, "DH already initialized");
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
     GetDH(other, dh_other);
 
     dh = DHparams_dup(dh_other);
     if (!dh)
 	ossl_raise(eDHError, "DHparams_dup");
-    EVP_PKEY_assign_DH(pkey, dh);
 
     DH_get0_key(dh_other, &pub, &priv);
     if (pub) {
@@ -270,8 +158,16 @@
 	DH_set0_key(dh, pub2, priv2);
     }
 
+    pkey = EVP_PKEY_new();
+    if (!pkey || EVP_PKEY_assign_DH(pkey, dh) != 1) {
+        EVP_PKEY_free(pkey);
+        DH_free(dh);
+        ossl_raise(eDHError, "EVP_PKEY_assign_DH");
+    }
+    RTYPEDDATA_DATA(self) = pkey;
     return self;
 }
+#endif
 
 /*
  *  call-seq:
@@ -374,16 +270,10 @@
     return str;
 }
 
-/*
- *  call-seq:
- *     dh.params -> hash
- *
- * Stores all parameters of key to the hash
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
- * Don't use :-)) (I's up to you)
- */
+#ifndef HAVE_EVP_PKEY_TODATA
+/* :nodoc: */
 static VALUE
-ossl_dh_get_params(VALUE self)
+ossl_dh_to_data(VALUE self)
 {
     DH *dh;
     VALUE hash;
@@ -394,80 +284,15 @@
     DH_get0_key(dh, &pub_key, &priv_key);
 
     hash = rb_hash_new();
-    rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p));
-    rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q));
-    rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g));
-    rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key));
-    rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key));
+    rb_hash_aset(hash, ID2SYM(rb_intern("p")), p ? ossl_bn_new(p) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("q")), q ? ossl_bn_new(q) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("g")), g ? ossl_bn_new(g) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("pub")), pub_key ? ossl_bn_new(pub_key) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("priv")), priv_key ? ossl_bn_new(priv_key) : Qnil);
 
     return hash;
 }
-
-/*
- *  call-seq:
- *     dh.to_text -> aString
- *
- * Prints all parameters of key to buffer
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
- * Don't use :-)) (I's up to you)
- */
-static VALUE
-ossl_dh_to_text(VALUE self)
-{
-    DH *dh;
-    BIO *out;
-    VALUE str;
-
-    GetDH(self, dh);
-    if (!(out = BIO_new(BIO_s_mem()))) {
-	ossl_raise(eDHError, NULL);
-    }
-    if (!DHparams_print(out, dh)) {
-	BIO_free(out);
-	ossl_raise(eDHError, NULL);
-    }
-    str = ossl_membio2str(out);
-
-    return str;
-}
-
-/*
- *  call-seq:
- *     dh.public_key -> aDH
- *
- * Returns a new DH instance that carries just the public information, i.e.
- * the prime _p_ and the generator _g_, but no public/private key yet. Such
- * a pair may be generated using DH#generate_key!. The "public key" needed
- * for a key exchange with DH#compute_key is considered as per-session
- * information and may be retrieved with DH#pub_key once a key pair has
- * been generated.
- * If the current instance already contains private information (and thus a
- * valid public/private key pair), this information will no longer be present
- * in the new instance generated by DH#public_key. This feature is helpful for
- * publishing the Diffie-Hellman parameters without leaking any of the private
- * per-session information.
- *
- * === Example
- *  dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
- *  public_key = dh.public_key # contains only prime and generator
- *  parameters = public_key.to_der # it's safe to publish this
- */
-static VALUE
-ossl_dh_to_public_key(VALUE self)
-{
-    DH *orig_dh, *dh;
-    VALUE obj;
-
-    GetDH(self, orig_dh);
-    dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */
-    obj = dh_instance(rb_obj_class(self), dh);
-    if (obj == Qfalse) {
-	DH_free(dh);
-	ossl_raise(eDHError, NULL);
-    }
-
-    return obj;
-}
+#endif
 
 /*
  *  call-seq:
@@ -476,80 +301,38 @@
  * Validates the Diffie-Hellman parameters associated with this instance.
  * It checks whether a safe prime and a suitable generator are used. If this
  * is not the case, +false+ is returned.
+ *
+ * See also the man page EVP_PKEY_param_check(3).
  */
 static VALUE
 ossl_dh_check_params(VALUE self)
 {
-    DH *dh;
-    int codes;
-
-    GetDH(self, dh);
-    if (!DH_check(dh, &codes)) {
-	return Qfalse;
-    }
-
-    return codes == 0 ? Qtrue : Qfalse;
-}
+    int ret;
+#ifdef HAVE_EVP_PKEY_CHECK
+    EVP_PKEY *pkey;
+    EVP_PKEY_CTX *pctx;
 
-/*
- *  call-seq:
- *     dh.generate_key! -> self
- *
- * Generates a private and public key unless a private key already exists.
- * If this DH instance was generated from public DH parameters (e.g. by
- * encoding the result of DH#public_key), then this method needs to be
- * called first in order to generate the per-session keys before performing
- * the actual key exchange.
- *
- * === Example
- *   dh = OpenSSL::PKey::DH.new(2048)
- *   public_key = dh.public_key #contains no private/public key yet
- *   public_key.generate_key!
- *   puts public_key.private? # => true
- */
-static VALUE
-ossl_dh_generate_key(VALUE self)
-{
+    GetPKey(self, pkey);
+    pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!pctx)
+        ossl_raise(eDHError, "EVP_PKEY_CTX_new");
+    ret = EVP_PKEY_param_check(pctx);
+    EVP_PKEY_CTX_free(pctx);
+#else
     DH *dh;
+    int codes;
 
     GetDH(self, dh);
-    if (!DH_generate_key(dh))
-	ossl_raise(eDHError, "Failed to generate key");
-    return self;
-}
-
-/*
- *  call-seq:
- *     dh.compute_key(pub_bn) -> aString
- *
- * Returns a String containing a shared secret computed from the other party's public value.
- * See DH_compute_key() for further information.
- *
- * === Parameters
- * * _pub_bn_ is a OpenSSL::BN, *not* the DH instance returned by
- *   DH#public_key as that contains the DH parameters only.
- */
-static VALUE
-ossl_dh_compute_key(VALUE self, VALUE pub)
-{
-    DH *dh;
-    const BIGNUM *pub_key, *dh_p;
-    VALUE str;
-    int len;
+    ret = DH_check(dh, &codes) == 1 && codes == 0;
+#endif
 
-    GetDH(self, dh);
-    DH_get0_pqg(dh, &dh_p, NULL, NULL);
-    if (!dh_p)
-	ossl_raise(eDHError, "incomplete DH");
-    pub_key = GetBNPtr(pub);
-    len = DH_size(dh);
-    str = rb_str_new(0, len);
-    if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) {
-	ossl_raise(eDHError, NULL);
+    if (ret == 1)
+        return Qtrue;
+    else {
+        /* DH_check_ex() will put error entry on failure */
+        ossl_clear_error();
+        return Qfalse;
     }
-    rb_str_set_len(str, len);
-
-    return str;
 }
 
 /*
@@ -606,40 +389,40 @@
      *   The per-session private key, an OpenSSL::BN.
      *
      * === Example of a key exchange
-     *  dh1 = OpenSSL::PKey::DH.new(2048)
-     *  der = dh1.public_key.to_der #you may send this publicly to the participating party
-     *  dh2 = OpenSSL::PKey::DH.new(der)
-     *  dh2.generate_key! #generate the per-session key pair
-     *  symm_key1 = dh1.compute_key(dh2.pub_key)
-     *  symm_key2 = dh2.compute_key(dh1.pub_key)
+     *   # you may send the parameters (der) and own public key (pub1) publicly
+     *   # to the participating party
+     *   dh1 = OpenSSL::PKey::DH.new(2048)
+     *   der = dh1.to_der
+     *   pub1 = dh1.pub_key
+     *
+     *   # the other party generates its per-session key pair
+     *   dhparams = OpenSSL::PKey::DH.new(der)
+     *   dh2 = OpenSSL::PKey.generate_key(dhparams)
+     *   pub2 = dh2.pub_key
      *
-     *  puts symm_key1 == symm_key2 # => true
+     *   symm_key1 = dh1.compute_key(pub2)
+     *   symm_key2 = dh2.compute_key(pub1)
+     *   puts symm_key1 == symm_key2 # => true
      */
     cDH = rb_define_class_under(mPKey, "DH", cPKey);
-    rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
     rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
     rb_define_method(cDH, "initialize_copy", ossl_dh_initialize_copy, 1);
+#endif
     rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
     rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
-    rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
     rb_define_method(cDH, "export", ossl_dh_export, 0);
     rb_define_alias(cDH, "to_pem", "export");
     rb_define_alias(cDH, "to_s", "export");
     rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
-    rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
     rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
-    rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
-    rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
 
-    DEF_OSSL_PKEY_BN(cDH, dh, p);
-    DEF_OSSL_PKEY_BN(cDH, dh, q);
-    DEF_OSSL_PKEY_BN(cDH, dh, g);
-    DEF_OSSL_PKEY_BN(cDH, dh, pub_key);
-    DEF_OSSL_PKEY_BN(cDH, dh, priv_key);
     rb_define_method(cDH, "set_pqg", ossl_dh_set_pqg, 3);
     rb_define_method(cDH, "set_key", ossl_dh_set_key, 2);
 
-    rb_define_method(cDH, "params", ossl_dh_get_params, 0);
+#ifndef HAVE_EVP_PKEY_TODATA
+    rb_define_method(cDH, "to_data", ossl_dh_to_data, 0);
+#endif
 }
 
 #else /* defined NO_DH */
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_pkey_dsa.c ruby-3.0.2/ext/openssl/ossl_pkey_dsa.c
--- ruby-3.0.2.orig/ext/openssl/ossl_pkey_dsa.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_pkey_dsa.c	2021-09-09 18:27:58.354594302 +0800
@@ -44,170 +44,41 @@
 VALUE eDSAError;
 
 /*
- * Public
- */
-static VALUE
-dsa_instance(VALUE klass, DSA *dsa)
-{
-    EVP_PKEY *pkey;
-    VALUE obj;
-
-    if (!dsa) {
-	return Qfalse;
-    }
-    obj = NewPKey(klass);
-    if (!(pkey = EVP_PKEY_new())) {
-	return Qfalse;
-    }
-    if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
-	EVP_PKEY_free(pkey);
-	return Qfalse;
-    }
-    SetPKey(obj, pkey);
-
-    return obj;
-}
-
-VALUE
-ossl_dsa_new(EVP_PKEY *pkey)
-{
-    VALUE obj;
-
-    if (!pkey) {
-	obj = dsa_instance(cDSA, DSA_new());
-    } else {
-	obj = NewPKey(cDSA);
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_DSA) {
-	    ossl_raise(rb_eTypeError, "Not a DSA key!");
-	}
-	SetPKey(obj, pkey);
-    }
-    if (obj == Qfalse) {
-	ossl_raise(eDSAError, NULL);
-    }
-
-    return obj;
-}
-
-/*
  * Private
  */
-struct dsa_blocking_gen_arg {
-    DSA *dsa;
-    int size;
-    int *counter;
-    unsigned long *h;
-    BN_GENCB *cb;
-    int result;
-};
-
-static void *
-dsa_blocking_gen(void *arg)
-{
-    struct dsa_blocking_gen_arg *gen = (struct dsa_blocking_gen_arg *)arg;
-    gen->result = DSA_generate_parameters_ex(gen->dsa, gen->size, NULL, 0,
-					     gen->counter, gen->h, gen->cb);
-    return 0;
-}
-
-static DSA *
-dsa_generate(int size)
-{
-    struct ossl_generate_cb_arg cb_arg = { 0 };
-    struct dsa_blocking_gen_arg gen_arg;
-    DSA *dsa = DSA_new();
-    BN_GENCB *cb = BN_GENCB_new();
-    int counter;
-    unsigned long h;
-
-    if (!dsa || !cb) {
-	DSA_free(dsa);
-	BN_GENCB_free(cb);
-	return NULL;
-    }
-
-    if (rb_block_given_p())
-	cb_arg.yield = 1;
-    BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg);
-    gen_arg.dsa = dsa;
-    gen_arg.size = size;
-    gen_arg.counter = &counter;
-    gen_arg.h = &h;
-    gen_arg.cb = cb;
-    if (cb_arg.yield == 1) {
-	/* we cannot release GVL when callback proc is supplied */
-	dsa_blocking_gen(&gen_arg);
-    } else {
-	/* there's a chance to unblock */
-	rb_thread_call_without_gvl(dsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg);
-    }
-
-    BN_GENCB_free(cb);
-    if (!gen_arg.result) {
-	DSA_free(dsa);
-	if (cb_arg.state) {
-	    /* Clear OpenSSL error queue before re-raising. By the way, the
-	     * documentation of DSA_generate_parameters_ex() says the error code
-	     * can be obtained by ERR_get_error(), but the default
-	     * implementation, dsa_builtin_paramgen() doesn't put any error... */
-	    ossl_clear_error();
-	    rb_jump_tag(cb_arg.state);
-	}
-	return NULL;
-    }
-
-    if (!DSA_generate_key(dsa)) {
-	DSA_free(dsa);
-	return NULL;
-    }
-
-    return dsa;
-}
-
-/*
- *  call-seq:
- *    DSA.generate(size) -> dsa
- *
- * Creates a new DSA instance by generating a private/public key pair
- * from scratch.
- *
- * === Parameters
- * * _size_ is an integer representing the desired key size.
- *
- */
-static VALUE
-ossl_dsa_s_generate(VALUE klass, VALUE size)
-{
-    DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */
-    VALUE obj = dsa_instance(klass, dsa);
-
-    if (obj == Qfalse) {
-	DSA_free(dsa);
-	ossl_raise(eDSAError, NULL);
-    }
-
-    return obj;
-}
-
 /*
  *  call-seq:
  *    DSA.new -> dsa
- *    DSA.new(size) -> dsa
  *    DSA.new(string [, pass]) -> dsa
+ *    DSA.new(size) -> dsa
  *
  * Creates a new DSA instance by reading an existing key from _string_.
  *
- * === Parameters
- * * _size_ is an integer representing the desired key size.
- * * _string_ contains a DER or PEM encoded key.
- * * _pass_ is a string that contains an optional password.
+ * If called without arguments, creates a new instance with no key components
+ * set. They can be set individually by #set_pqg and #set_key.
  *
- * === Examples
- *  DSA.new -> dsa
- *  DSA.new(1024) -> dsa
- *  DSA.new(File.read('dsa.pem')) -> dsa
- *  DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa
+ * If called with a String, tries to parse as DER or PEM encoding of a \DSA key.
+ * See also OpenSSL::PKey.read which can parse keys of any kinds.
  *
+ * If called with a number, generates random parameters and a key pair. This
+ * form works as an alias of DSA.generate.
+ *
+ * +string+::
+ *   A String that contains a DER or PEM encoded key.
+ * +pass+::
+ *   A String that contains an optional password.
+ * +size+::
+ *   See DSA.generate.
+ *
+ * Examples:
+ *   p OpenSSL::PKey::DSA.new(1024)
+ *   #=> #<OpenSSL::PKey::DSA:0x000055a8d6025bf0 oid=DSA>
+ *
+ *   p OpenSSL::PKey::DSA.new(File.read('dsa.pem'))
+ *   #=> #<OpenSSL::PKey::DSA:0x000055555d6b8110 oid=DSA>
+ *
+ *   p OpenSSL::PKey::DSA.new(File.read('dsa.pem'), 'mypassword')
+ *   #=> #<OpenSSL::PKey::DSA:0x0000556f973c40b8 oid=DSA>
  */
 static VALUE
 ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
@@ -216,73 +87,87 @@
     DSA *dsa;
     BIO *in;
     VALUE arg, pass;
+    int type;
 
-    GetPKey(self, pkey);
-    if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
+
+    /* The DSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
+    rb_scan_args(argc, argv, "02", &arg, &pass);
+    if (argc == 0) {
         dsa = DSA_new();
-    }
-    else if (RB_INTEGER_TYPE_P(arg)) {
-	if (!(dsa = dsa_generate(NUM2INT(arg)))) {
-	    ossl_raise(eDSAError, NULL);
-	}
+        if (!dsa)
+            ossl_raise(eDSAError, "DSA_new");
     }
     else {
-	pass = ossl_pem_passwd_value(pass);
-	arg = ossl_to_der_if_possible(arg);
-	in = ossl_obj2bio(&arg);
-	dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
-	if (!dsa) {
-	    OSSL_BIO_reset(in);
-	    dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
-	}
-	if (!dsa) {
-	    OSSL_BIO_reset(in);
-	    dsa = d2i_DSAPrivateKey_bio(in, NULL);
-	}
-	if (!dsa) {
-	    OSSL_BIO_reset(in);
-	    dsa = d2i_DSA_PUBKEY_bio(in, NULL);
-	}
-	if (!dsa) {
-	    OSSL_BIO_reset(in);
-#define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
-	(d2i_of_void *)d2i_DSAPublicKey, PEM_STRING_DSA_PUBLIC, (bp), (void **)(x), (cb), (u))
-	    dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
-#undef PEM_read_bio_DSAPublicKey
-	}
-	BIO_free(in);
-	if (!dsa) {
-	    ossl_clear_error();
-	    ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
-	}
-    }
-    if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
-	DSA_free(dsa);
-	ossl_raise(eDSAError, NULL);
+        pass = ossl_pem_passwd_value(pass);
+        arg = ossl_to_der_if_possible(arg);
+        in = ossl_obj2bio(&arg);
+
+        dsa = (DSA *)PEM_ASN1_read_bio((d2i_of_void *)d2i_DSAPublicKey,
+                                       PEM_STRING_DSA_PUBLIC,
+                                       in, NULL, NULL, NULL);
+        OSSL_BIO_reset(in);
+        if (dsa)
+            goto legacy;
+
+        pkey = ossl_pkey_read_generic(in, pass);
+        BIO_free(in);
+        if (!pkey)
+            ossl_raise(eDSAError, "Neither PUB key nor PRIV key");
+
+        type = EVP_PKEY_base_id(pkey);
+        if (type != EVP_PKEY_DSA) {
+            EVP_PKEY_free(pkey);
+            rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+        }
+        RTYPEDDATA_DATA(self) = pkey;
+        return self;
+    }
+
+  legacy:
+    if (dsa) {
+        pkey = EVP_PKEY_new();
+        if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa) != 1) {
+            EVP_PKEY_free(pkey);
+            DSA_free(dsa);
+            ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+        }
     }
-
+    RTYPEDDATA_DATA(self) = pkey;
     return self;
 }
 
+#ifndef HAVE_EVP_PKEY_DUP
 static VALUE
 ossl_dsa_initialize_copy(VALUE self, VALUE other)
 {
     EVP_PKEY *pkey;
     DSA *dsa, *dsa_new;
 
-    GetPKey(self, pkey);
-    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
-	ossl_raise(eDSAError, "DSA already initialized");
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
     GetDSA(other, dsa);
 
-    dsa_new = ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, (d2i_of_void *)d2i_DSAPrivateKey, (char *)dsa);
+    dsa_new = (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey,
+                              (d2i_of_void *)d2i_DSAPrivateKey,
+                              (char *)dsa);
     if (!dsa_new)
 	ossl_raise(eDSAError, "ASN1_dup");
 
-    EVP_PKEY_assign_DSA(pkey, dsa_new);
+    pkey = EVP_PKEY_new();
+    if (!pkey || EVP_PKEY_assign_DSA(pkey, dsa_new) != 1) {
+        EVP_PKEY_free(pkey);
+        DSA_free(dsa_new);
+        ossl_raise(eDSAError, "EVP_PKEY_assign_DSA");
+    }
+    RTYPEDDATA_DATA(self) = pkey;
 
     return self;
 }
+#endif
 
 /*
  *  call-seq:
@@ -341,34 +226,12 @@
 ossl_dsa_export(int argc, VALUE *argv, VALUE self)
 {
     DSA *dsa;
-    BIO *out;
-    const EVP_CIPHER *ciph = NULL;
-    VALUE cipher, pass, str;
 
     GetDSA(self, dsa);
-    rb_scan_args(argc, argv, "02", &cipher, &pass);
-    if (!NIL_P(cipher)) {
-	ciph = ossl_evp_get_cipherbyname(cipher);
-	pass = ossl_pem_passwd_value(pass);
-    }
-    if (!(out = BIO_new(BIO_s_mem()))) {
-	ossl_raise(eDSAError, NULL);
-    }
-    if (DSA_HAS_PRIVATE(dsa)) {
-	if (!PEM_write_bio_DSAPrivateKey(out, dsa, ciph, NULL, 0,
-					 ossl_pem_passwd_cb, (void *)pass)){
-	    BIO_free(out);
-	    ossl_raise(eDSAError, NULL);
-	}
-    } else {
-	if (!PEM_write_bio_DSA_PUBKEY(out, dsa)) {
-	    BIO_free(out);
-	    ossl_raise(eDSAError, NULL);
-	}
-    }
-    str = ossl_membio2str(out);
-
-    return str;
+    if (DSA_HAS_PRIVATE(dsa))
+        return ossl_pkey_export_traditional(argc, argv, self, 0);
+    else
+        return ossl_pkey_export_spki(self, 0);
 }
 
 /*
@@ -382,38 +245,19 @@
 ossl_dsa_to_der(VALUE self)
 {
     DSA *dsa;
-    int (*i2d_func)(DSA *, unsigned char **);
-    unsigned char *p;
-    long len;
-    VALUE str;
 
     GetDSA(self, dsa);
-    if(DSA_HAS_PRIVATE(dsa))
-	i2d_func = (int (*)(DSA *,unsigned char **))i2d_DSAPrivateKey;
+    if (DSA_HAS_PRIVATE(dsa))
+        return ossl_pkey_export_traditional(0, NULL, self, 1);
     else
-	i2d_func = i2d_DSA_PUBKEY;
-    if((len = i2d_func(dsa, NULL)) <= 0)
-	ossl_raise(eDSAError, NULL);
-    str = rb_str_new(0, len);
-    p = (unsigned char *)RSTRING_PTR(str);
-    if(i2d_func(dsa, &p) < 0)
-	ossl_raise(eDSAError, NULL);
-    ossl_str_adjust(str, p);
-
-    return str;
+        return ossl_pkey_export_spki(self, 1);
 }
 
 
-/*
- *  call-seq:
- *    dsa.params -> hash
- *
- * Stores all parameters of key to the hash
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
- * Don't use :-)) (I's up to you)
- */
+#ifndef HAVE_EVP_PKEY_TODATA
+/* :nodoc: */
 static VALUE
-ossl_dsa_get_params(VALUE self)
+ossl_dsa_to_data(VALUE self)
 {
     DSA *dsa;
     VALUE hash;
@@ -424,166 +268,15 @@
     DSA_get0_key(dsa, &pub_key, &priv_key);
 
     hash = rb_hash_new();
-    rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p));
-    rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q));
-    rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(g));
-    rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pub_key));
-    rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(priv_key));
+    rb_hash_aset(hash, ID2SYM(rb_intern("p")), p ? ossl_bn_new(p) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("q")), q ? ossl_bn_new(q) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("g")), g ? ossl_bn_new(g) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("pub")), pub_key ? ossl_bn_new(pub_key) : Qnil);
+    rb_hash_aset(hash, ID2SYM(rb_intern("priv")), priv_key ? ossl_bn_new(priv_key) : Qnil);
 
     return hash;
 }
-
-/*
- *  call-seq:
- *    dsa.to_text -> aString
- *
- * Prints all parameters of key to buffer
- * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
- * Don't use :-)) (I's up to you)
- */
-static VALUE
-ossl_dsa_to_text(VALUE self)
-{
-    DSA *dsa;
-    BIO *out;
-    VALUE str;
-
-    GetDSA(self, dsa);
-    if (!(out = BIO_new(BIO_s_mem()))) {
-	ossl_raise(eDSAError, NULL);
-    }
-    if (!DSA_print(out, dsa, 0)) { /* offset = 0 */
-	BIO_free(out);
-	ossl_raise(eDSAError, NULL);
-    }
-    str = ossl_membio2str(out);
-
-    return str;
-}
-
-/*
- *  call-seq:
- *    dsa.public_key -> aDSA
- *
- * Returns a new DSA instance that carries just the public key information.
- * If the current instance has also private key information, this will no
- * longer be present in the new instance. This feature is helpful for
- * publishing the public key information without leaking any of the private
- * information.
- *
- * === Example
- *  dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information
- *  pub_key = dsa.public_key # has only the public part available
- *  pub_key_der = pub_key.to_der # it's safe to publish this
- *
- *
- */
-static VALUE
-ossl_dsa_to_public_key(VALUE self)
-{
-    EVP_PKEY *pkey;
-    DSA *dsa;
-    VALUE obj;
-
-    GetPKeyDSA(self, pkey);
-    /* err check performed by dsa_instance */
-#define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup( \
-	(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(rb_obj_class(self), dsa);
-    if (obj == Qfalse) {
-	DSA_free(dsa);
-	ossl_raise(eDSAError, NULL);
-    }
-    return obj;
-}
-
-/*
- *  call-seq:
- *    dsa.syssign(string) -> aString
- *
- * Computes and returns the DSA signature of _string_, where _string_ is
- * expected to be an already-computed message digest of the original input
- * data. The signature is issued using the private key of this DSA instance.
- *
- * === Parameters
- * * _string_ is a message digest of the original input data to be signed.
- *
- * === Example
- *  dsa = OpenSSL::PKey::DSA.new(2048)
- *  doc = "Sign me"
- *  digest = OpenSSL::Digest.digest('SHA1', doc)
- *  sig = dsa.syssign(digest)
- *
- *
- */
-static VALUE
-ossl_dsa_sign(VALUE self, VALUE data)
-{
-    DSA *dsa;
-    const BIGNUM *dsa_q;
-    unsigned int buf_len;
-    VALUE str;
-
-    GetDSA(self, dsa);
-    DSA_get0_pqg(dsa, NULL, &dsa_q, NULL);
-    if (!dsa_q)
-	ossl_raise(eDSAError, "incomplete DSA");
-    if (!DSA_PRIVATE(self, dsa))
-	ossl_raise(eDSAError, "Private DSA key needed!");
-    StringValue(data);
-    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) */
-	ossl_raise(eDSAError, NULL);
-    }
-    rb_str_set_len(str, buf_len);
-
-    return str;
-}
-
-/*
- *  call-seq:
- *    dsa.sysverify(digest, sig) -> true | false
- *
- * Verifies whether the signature is valid given the message digest input. It
- * does so by validating _sig_ using the public key of this DSA instance.
- *
- * === Parameters
- * * _digest_ is a message digest of the original input data to be signed
- * * _sig_ is a DSA signature value
- *
- * === Example
- *  dsa = OpenSSL::PKey::DSA.new(2048)
- *  doc = "Sign me"
- *  digest = OpenSSL::Digest.digest('SHA1', doc)
- *  sig = dsa.syssign(digest)
- *  puts dsa.sysverify(digest, sig) # => true
- *
- */
-static VALUE
-ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
-{
-    DSA *dsa;
-    int ret;
-
-    GetDSA(self, dsa);
-    StringValue(digest);
-    StringValue(sig);
-    /* type is ignored (0) */
-    ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest),
-		     (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), dsa);
-    if (ret < 0) {
-	ossl_raise(eDSAError, NULL);
-    }
-    else if (ret == 1) {
-	return Qtrue;
-    }
-
-    return Qfalse;
-}
+#endif
 
 /*
  * Document-method: OpenSSL::PKey::DSA#set_pqg
@@ -630,30 +323,24 @@
      */
     cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
 
-    rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
     rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
     rb_define_method(cDSA, "initialize_copy", ossl_dsa_initialize_copy, 1);
+#endif
 
     rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
     rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
-    rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
     rb_define_method(cDSA, "export", ossl_dsa_export, -1);
     rb_define_alias(cDSA, "to_pem", "export");
     rb_define_alias(cDSA, "to_s", "export");
     rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
-    rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
-    rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
-    rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
-
-    DEF_OSSL_PKEY_BN(cDSA, dsa, p);
-    DEF_OSSL_PKEY_BN(cDSA, dsa, q);
-    DEF_OSSL_PKEY_BN(cDSA, dsa, g);
-    DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key);
-    DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key);
+
     rb_define_method(cDSA, "set_pqg", ossl_dsa_set_pqg, 3);
     rb_define_method(cDSA, "set_key", ossl_dsa_set_key, 2);
 
-    rb_define_method(cDSA, "params", ossl_dsa_get_params, 0);
+#ifndef HAVE_EVP_PKEY_TODATA
+    rb_define_method(cDSA, "to_data", ossl_dsa_to_data, 0);
+#endif
 }
 
 #else /* defined NO_DSA */
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_pkey_ec.c ruby-3.0.2/ext/openssl/ossl_pkey_ec.c
--- ruby-3.0.2.orig/ext/openssl/ossl_pkey_ec.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_pkey_ec.c	2021-09-09 18:27:58.354594302 +0800
@@ -47,12 +47,7 @@
 VALUE cEC_POINT;
 VALUE eEC_POINT;
 
-static ID s_GFp;
-static ID s_GFp_simple;
-static ID s_GFp_mont;
-static ID s_GFp_nist;
-static ID s_GF2m;
-static ID s_GF2m_simple;
+static ID s_GFp, s_GF2m;
 
 static ID ID_uncompressed;
 static ID ID_compressed;
@@ -63,47 +58,6 @@
 static VALUE ec_group_new(const EC_GROUP *group);
 static VALUE ec_point_new(const EC_POINT *point, const EC_GROUP *group);
 
-static VALUE ec_instance(VALUE klass, EC_KEY *ec)
-{
-    EVP_PKEY *pkey;
-    VALUE obj;
-
-    if (!ec) {
-	return Qfalse;
-    }
-    obj = NewPKey(klass);
-    if (!(pkey = EVP_PKEY_new())) {
-	return Qfalse;
-    }
-    if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
-	EVP_PKEY_free(pkey);
-	return Qfalse;
-    }
-    SetPKey(obj, pkey);
-
-    return obj;
-}
-
-VALUE ossl_ec_new(EVP_PKEY *pkey)
-{
-    VALUE obj;
-
-    if (!pkey) {
-	obj = ec_instance(cEC, EC_KEY_new());
-    } else {
-	obj = NewPKey(cEC);
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) {
-	    ossl_raise(rb_eTypeError, "Not a EC key!");
-	}
-	SetPKey(obj, pkey);
-    }
-    if (obj == Qfalse) {
-	ossl_raise(eECError, NULL);
-    }
-
-    return obj;
-}
-
 /*
  * Creates a new EC_KEY on the EC group obj. arg can be an EC::Group or a String
  * representing an OID.
@@ -150,16 +104,20 @@
 static VALUE
 ossl_ec_key_s_generate(VALUE klass, VALUE arg)
 {
+    EVP_PKEY *pkey;
     EC_KEY *ec;
     VALUE obj;
 
-    ec = ec_key_new_from_group(arg);
+    obj = rb_obj_alloc(klass);
 
-    obj = ec_instance(klass, ec);
-    if (obj == Qfalse) {
-	EC_KEY_free(ec);
-	ossl_raise(eECError, NULL);
+    ec = ec_key_new_from_group(arg);
+    pkey = EVP_PKEY_new();
+    if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+        EVP_PKEY_free(pkey);
+        EC_KEY_free(ec);
+        ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
     }
+    RTYPEDDATA_DATA(obj) = pkey;
 
     if (!EC_KEY_generate_key(ec))
 	ossl_raise(eECError, "EC_KEY_generate_key");
@@ -182,81 +140,83 @@
 {
     EVP_PKEY *pkey;
     EC_KEY *ec;
+    BIO *in;
     VALUE arg, pass;
+    int type;
 
-    GetPKey(self, pkey);
-    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
-        ossl_raise(eECError, "EC_KEY already initialized");
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
 
     rb_scan_args(argc, argv, "02", &arg, &pass);
-
     if (NIL_P(arg)) {
         if (!(ec = EC_KEY_new()))
-	    ossl_raise(eECError, NULL);
-    } else if (rb_obj_is_kind_of(arg, cEC)) {
-	EC_KEY *other_ec = NULL;
-
-	GetEC(arg, other_ec);
-	if (!(ec = EC_KEY_dup(other_ec)))
-	    ossl_raise(eECError, NULL);
-    } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
-	ec = ec_key_new_from_group(arg);
-    } else {
-	BIO *in;
-
-	pass = ossl_pem_passwd_value(pass);
-	in = ossl_obj2bio(&arg);
-
-	ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
-	if (!ec) {
-	    OSSL_BIO_reset(in);
-	    ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, (void *)pass);
-	}
-	if (!ec) {
-	    OSSL_BIO_reset(in);
-	    ec = d2i_ECPrivateKey_bio(in, NULL);
-	}
-	if (!ec) {
-	    OSSL_BIO_reset(in);
-	    ec = d2i_EC_PUBKEY_bio(in, NULL);
-	}
-	BIO_free(in);
-
-	if (!ec) {
-	    ossl_clear_error();
-	    ec = ec_key_new_from_group(arg);
-	}
+            ossl_raise(eECError, "EC_KEY_new");
+    }
+    else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
+        ec = ec_key_new_from_group(arg);
     }
+    else {
+        pass = ossl_pem_passwd_value(pass);
+        arg = ossl_to_der_if_possible(arg);
+        in = ossl_obj2bio(&arg);
+
+        pkey = ossl_pkey_read_generic(in, pass);
+        BIO_free(in);
+        if (!pkey) {
+            ossl_clear_error();
+            ec = ec_key_new_from_group(arg);
+            goto legacy;
+        }
 
-    if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
-	EC_KEY_free(ec);
-	ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+        type = EVP_PKEY_base_id(pkey);
+        if (type != EVP_PKEY_EC) {
+            EVP_PKEY_free(pkey);
+            rb_raise(eDSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+        }
+        RTYPEDDATA_DATA(self) = pkey;
+        return self;
     }
 
+  legacy:
+    if (ec) {
+        pkey = EVP_PKEY_new();
+        if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec) != 1) {
+            EVP_PKEY_free(pkey);
+            EC_KEY_free(ec);
+            ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+        }
+    }
+    RTYPEDDATA_DATA(self) = pkey;
     return self;
 }
 
+#ifndef HAVE_EVP_PKEY_DUP
 static VALUE
 ossl_ec_key_initialize_copy(VALUE self, VALUE other)
 {
     EVP_PKEY *pkey;
     EC_KEY *ec, *ec_new;
 
-    GetPKey(self, pkey);
-    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
-	ossl_raise(eECError, "EC already initialized");
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
     GetEC(other, ec);
 
     ec_new = EC_KEY_dup(ec);
     if (!ec_new)
 	ossl_raise(eECError, "EC_KEY_dup");
-    if (!EVP_PKEY_assign_EC_KEY(pkey, ec_new)) {
-	EC_KEY_free(ec_new);
-	ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+
+    pkey = EVP_PKEY_new();
+    if (!pkey || EVP_PKEY_assign_EC_KEY(pkey, ec_new) != 1) {
+        EC_KEY_free(ec_new);
+        ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
     }
+    RTYPEDDATA_DATA(self) = pkey;
 
     return self;
 }
+#endif
 
 /*
  * call-seq:
@@ -425,66 +385,6 @@
     return EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse;
 }
 
-static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
-{
-    EC_KEY *ec;
-    BIO *out;
-    int i = -1;
-    int private = 0;
-    VALUE str;
-    const EVP_CIPHER *cipher = NULL;
-
-    GetEC(self, ec);
-
-    if (EC_KEY_get0_public_key(ec) == NULL)
-        ossl_raise(eECError, "can't export - no public key set");
-
-    if (EC_KEY_check_key(ec) != 1)
-	ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
-
-    if (EC_KEY_get0_private_key(ec))
-        private = 1;
-
-    if (!NIL_P(ciph)) {
-	cipher = ossl_evp_get_cipherbyname(ciph);
-	pass = ossl_pem_passwd_value(pass);
-    }
-
-    if (!(out = BIO_new(BIO_s_mem())))
-        ossl_raise(eECError, "BIO_new(BIO_s_mem())");
-
-    switch(format) {
-    case EXPORT_PEM:
-    	if (private) {
-            i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, ossl_pem_passwd_cb, (void *)pass);
-    	} else {
-            i = PEM_write_bio_EC_PUBKEY(out, ec);
-        }
-
-    	break;
-    case EXPORT_DER:
-        if (private) {
-            i = i2d_ECPrivateKey_bio(out, ec);
-        } else {
-            i = i2d_EC_PUBKEY_bio(out, ec);
-        }
-
-    	break;
-    default:
-        BIO_free(out);
-    	ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
-    }
-
-    if (i != 1) {
-        BIO_free(out);
-        ossl_raise(eECError, "outlen=%d", i);
-    }
-
-    str = ossl_membio2str(out);
-
-    return str;
-}
-
 /*
  *  call-seq:
  *     key.export([cipher, pass_phrase]) => String
@@ -495,11 +395,16 @@
  * instance. Note that encryption will only be effective for a private key,
  * public keys will always be encoded in plain text.
  */
-static VALUE ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
+static VALUE
+ossl_ec_key_export(int argc, VALUE *argv, VALUE self)
 {
-    VALUE cipher, passwd;
-    rb_scan_args(argc, argv, "02", &cipher, &passwd);
-    return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM);
+    EC_KEY *ec;
+
+    GetEC(self, ec);
+    if (EC_KEY_get0_private_key(ec))
+        return ossl_pkey_export_traditional(argc, argv, self, 0);
+    else
+        return ossl_pkey_export_spki(self, 0);
 }
 
 /*
@@ -508,36 +413,17 @@
  *
  *  See the OpenSSL documentation for i2d_ECPrivateKey_bio()
  */
-static VALUE ossl_ec_key_to_der(VALUE self)
-{
-    return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
-}
-
-/*
- *  call-seq:
- *     key.to_text   => String
- *
- *  See the OpenSSL documentation for EC_KEY_print()
- */
-static VALUE ossl_ec_key_to_text(VALUE self)
+static VALUE
+ossl_ec_key_to_der(VALUE self)
 {
     EC_KEY *ec;
-    BIO *out;
-    VALUE str;
 
     GetEC(self, ec);
-    if (!(out = BIO_new(BIO_s_mem()))) {
-	ossl_raise(eECError, "BIO_new(BIO_s_mem())");
-    }
-    if (!EC_KEY_print(out, ec, 0)) {
-	BIO_free(out);
-	ossl_raise(eECError, "EC_KEY_print");
-    }
-    str = ossl_membio2str(out);
-
-    return str;
+    if (EC_KEY_get0_private_key(ec))
+        return ossl_pkey_export_traditional(0, NULL, self, 1);
+    else
+        return ossl_pkey_export_spki(self, 1);
 }
-
 /*
  *  call-seq:
  *     key.generate_key!   => self
@@ -564,105 +450,63 @@
 }
 
 /*
- *  call-seq:
- *     key.check_key   => true
+ * call-seq:
+ *    key.check_key   => true
  *
- *  Raises an exception if the key is invalid.
+ * Raises an exception if the key is invalid.
  *
- *  See the OpenSSL documentation for EC_KEY_check_key()
+ * See also the man page EVP_PKEY_public_check(3).
  */
 static VALUE ossl_ec_key_check_key(VALUE self)
 {
+#ifdef HAVE_EVP_PKEY_CHECK
+    EVP_PKEY *pkey;
+    EVP_PKEY_CTX *pctx;
+    int ret;
+
+    GetPKey(self, pkey);
+    pctx = EVP_PKEY_CTX_new(pkey, /* engine */NULL);
+    if (!pctx)
+        ossl_raise(eDHError, "EVP_PKEY_CTX_new");
+    ret = EVP_PKEY_public_check(pctx);
+    EVP_PKEY_CTX_free(pctx);
+    if (ret != 1)
+        ossl_raise(eECError, "EVP_PKEY_public_check");
+#else
     EC_KEY *ec;
 
     GetEC(self, ec);
     if (EC_KEY_check_key(ec) != 1)
 	ossl_raise(eECError, "EC_KEY_check_key");
+#endif
 
     return Qtrue;
 }
 
-/*
- *  call-seq:
- *     key.dh_compute_key(pubkey)   => String
- *
- *  See the OpenSSL documentation for ECDH_compute_key()
- */
-static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey)
-{
-    EC_KEY *ec;
-    EC_POINT *point;
-    int buf_len;
-    VALUE str;
-
-    GetEC(self, ec);
-    GetECPoint(pubkey, point);
-
-/* BUG: need a way to figure out the maximum string size */
-    buf_len = 1024;
-    str = rb_str_new(0, buf_len);
-/* BUG: take KDF as a block */
-    buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL);
-    if (buf_len < 0)
-         ossl_raise(eECError, "ECDH_compute_key");
-
-    rb_str_resize(str, buf_len);
-
-    return str;
-}
-
-/* sign_setup */
-
-/*
- *  call-seq:
- *     key.dsa_sign_asn1(data)   => String
- *
- *  See the OpenSSL documentation for ECDSA_sign()
- */
-static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data)
-{
-    EC_KEY *ec;
-    unsigned int buf_len;
-    VALUE str;
-
-    GetEC(self, ec);
-    StringValue(data);
-
-    if (EC_KEY_get0_private_key(ec) == NULL)
-	ossl_raise(eECError, "Private EC key needed!");
-
-    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_set_len(str, buf_len);
-
-    return str;
-}
-
-/*
- *  call-seq:
- *     key.dsa_verify_asn1(data, sig)   => true or false
- *
- *  See the OpenSSL documentation for ECDSA_verify()
- */
-static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
+#ifndef HAVE_EVP_PKEY_TODATA
+/* :nodoc: */
+static VALUE
+ossl_ec_key_to_data(VALUE self)
 {
     EC_KEY *ec;
+    const EC_GROUP *group;
+    const BIGNUM *priv;
+    int nid;
+    VALUE hash;
 
+    /* FIXME: INCOMPLETE: What about non-named curves? Other components? */
     GetEC(self, ec);
-    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;
-    }
+    group = EC_KEY_get0_group(ec);
+    nid = EC_GROUP_get_curve_name(group);
+    priv = EC_KEY_get0_private_key(ec);
 
-    ossl_raise(eECError, "ECDSA_verify");
+    hash = rb_hash_new();
+    rb_hash_aset(hash, ID2SYM(rb_intern("group")), rb_str_new2(OBJ_nid2sn(nid)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("priv")), priv ? ossl_bn_new(priv) : Qnil);
 
-    UNREACHABLE;
+    return hash;
 }
+#endif
 
 /*
  * OpenSSL::PKey::EC::Group
@@ -670,7 +514,7 @@
 static void
 ossl_ec_group_free(void *ptr)
 {
-    EC_GROUP_clear_free(ptr);
+    EC_GROUP_free(ptr);
 }
 
 static const rb_data_type_t ossl_ec_group_type = {
@@ -706,20 +550,11 @@
  * call-seq:
  *   OpenSSL::PKey::EC::Group.new(ec_group)
  *   OpenSSL::PKey::EC::Group.new(pem_or_der_encoded)
- *   OpenSSL::PKey::EC::Group.new(ec_method)
  *   OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b)
  *   OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b)
  *
  * Creates a new EC::Group object.
  *
- * _ec_method_ is a symbol that represents an EC_METHOD. Currently the following
- * are supported:
- *
- * * :GFp_simple
- * * :GFp_mont
- * * :GFp_nist
- * * :GF2m_simple
- *
  * If the first argument is :GFp or :GF2m, creates a new curve with given
  * parameters.
  */
@@ -734,29 +569,7 @@
 
     switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
     case 1:
-        if (SYMBOL_P(arg1)) {
-            const EC_METHOD *method = NULL;
-            ID id = SYM2ID(arg1);
-
-            if (id == s_GFp_simple) {
-                method = EC_GFp_simple_method();
-            } else if (id == s_GFp_mont) {
-                method = EC_GFp_mont_method();
-            } else if (id == s_GFp_nist) {
-                method = EC_GFp_nist_method();
-#if !defined(OPENSSL_NO_EC2M)
-            } else if (id == s_GF2m_simple) {
-                method = EC_GF2m_simple_method();
-#endif
-            }
-
-            if (method) {
-                if ((group = EC_GROUP_new(method)) == NULL)
-                    ossl_raise(eEC_GROUP, "EC_GROUP_new");
-            } else {
-                ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
-            }
-        } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
+        if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
             const EC_GROUP *arg1_group;
 
             GetECGroup(arg1, arg1_group);
@@ -1475,6 +1288,8 @@
 /*
  * call-seq:
  *   point.make_affine! => self
+ *
+ * This method is deprecated and should not be used.
  */
 static VALUE ossl_ec_point_make_affine(VALUE self)
 {
@@ -1484,8 +1299,12 @@
     GetECPoint(self, point);
     GetECPointGroup(self, group);
 
+    rb_warn("OpenSSL::PKey::EC::Point#make_affine! is deprecated; " \
+            "the conversion is automatically performed when necessary");
+#if !(OPENSSL_VERSION_MAJOR+0 >= 3)
     if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
         ossl_raise(cEC_POINT, "EC_POINT_make_affine");
+#endif
 
     return self;
 }
@@ -1631,6 +1450,10 @@
 	if (EC_POINT_mul(group, point_result, bn_g, point_self, bn, ossl_bn_ctx) != 1)
 	    ossl_raise(eEC_POINT, NULL);
     } else {
+#if (defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3) || defined(LIBRESSL_VERSION_NUMBER)
+        rb_raise(rb_eNotImpError, "calling #mul with arrays is not" \
+                 "supported by this OpenSSL version");
+#else
 	/*
 	 * bignums | arg1[0] | arg1[1] | arg1[2] | ...
 	 * points  | self    | arg2[0] | arg2[1] | ...
@@ -1645,6 +1468,9 @@
 	if (RARRAY_LEN(arg1) != RARRAY_LEN(arg2) + 1) /* arg2 must be 1 larger */
 	    ossl_raise(rb_eArgError, "bns must be 1 longer than points; see the documentation");
 
+        rb_warning("OpenSSL::PKey::EC::Point#mul(ary, ary) is deprecated; " \
+                   "use #mul(bn) form instead");
+
 	num = RARRAY_LEN(arg1);
 	bns_tmp = rb_ary_tmp_new(num);
 	bignums = ALLOCV_N(const BIGNUM *, tmp_b, num);
@@ -1670,6 +1496,7 @@
 
 	ALLOCV_END(tmp_b);
 	ALLOCV_END(tmp_p);
+#endif
     }
 
     return result;
@@ -1710,10 +1537,6 @@
 
     s_GFp = rb_intern("GFp");
     s_GF2m = rb_intern("GF2m");
-    s_GFp_simple = rb_intern("GFp_simple");
-    s_GFp_mont = rb_intern("GFp_mont");
-    s_GFp_nist = rb_intern("GFp_nist");
-    s_GF2m_simple = rb_intern("GF2m_simple");
 
     ID_uncompressed = rb_intern("uncompressed");
     ID_compressed = rb_intern("compressed");
@@ -1728,8 +1551,9 @@
 
     rb_define_singleton_method(cEC, "generate", ossl_ec_key_s_generate, 1);
     rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
     rb_define_method(cEC, "initialize_copy", ossl_ec_key_initialize_copy, 1);
-/* copy/dup/cmp */
+#endif
 
     rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
     rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
@@ -1752,16 +1576,13 @@
     rb_define_alias(cEC, "generate_key", "generate_key!");
     rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
 
-    rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
-    rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
-    rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
-/* do_sign/do_verify */
-
     rb_define_method(cEC, "export", ossl_ec_key_export, -1);
     rb_define_alias(cEC, "to_pem", "export");
     rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
-    rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
 
+#ifndef HAVE_EVP_PKEY_TODATA
+    rb_define_method(cEC, "to_data", ossl_ec_key_to_data, 0);
+#endif
 
     rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
     rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_pkey.h ruby-3.0.2/ext/openssl/ossl_pkey.h
--- ruby-3.0.2.orig/ext/openssl/ossl_pkey.h	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_pkey.h	2021-09-09 18:27:58.354594302 +0800
@@ -7,47 +7,48 @@
  * This program is licensed under the same licence as Ruby.
  * (See the file 'LICENCE'.)
  */
-#if !defined(_OSSL_PKEY_H_)
-#define _OSSL_PKEY_H_
+#if !defined(OSSL_PKEY_H)
+#define OSSL_PKEY_H
 
 extern VALUE mPKey;
 extern VALUE cPKey;
 extern VALUE ePKeyError;
 extern const rb_data_type_t ossl_evp_pkey_type;
 
-#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue)
-#define OSSL_PKEY_SET_PUBLIC(obj)  rb_iv_set((obj), "private", Qfalse)
-#define OSSL_PKEY_IS_PRIVATE(obj)  (rb_iv_get((obj), "private") == Qtrue)
-
-#define NewPKey(klass) \
-    TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, 0)
-#define SetPKey(obj, pkey) do { \
-    if (!(pkey)) { \
-	rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \
-    } \
-    RTYPEDDATA_DATA(obj) = (pkey); \
-    OSSL_PKEY_SET_PUBLIC(obj); \
-} while (0)
+/* For ENGINE */
+#define OSSL_PKEY_SET_PRIVATE(obj) rb_ivar_set((obj), rb_intern("private"), Qtrue)
+#define OSSL_PKEY_IS_PRIVATE(obj)  (rb_attr_get((obj), rb_intern("private")) == Qtrue)
+
+#define GetPKey0(obj, pkey) \
+    TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey))
 #define GetPKey(obj, pkey) do {\
-    TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
+    GetPKey0((obj), (pkey)); \
     if (!(pkey)) { \
 	rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
     } \
 } while (0)
 
-struct ossl_generate_cb_arg {
-    int yield;
-    int interrupted;
-    int state;
-};
-int ossl_generate_cb_2(int p, int n, BN_GENCB *cb);
-void ossl_generate_cb_stop(void *ptr);
-
+/* Takes ownership of the EVP_PKEY */
 VALUE ossl_pkey_new(EVP_PKEY *);
 void ossl_pkey_check_public_key(const EVP_PKEY *);
+EVP_PKEY *ossl_pkey_read_generic(BIO *, VALUE);
 EVP_PKEY *GetPKeyPtr(VALUE);
 EVP_PKEY *DupPKeyPtr(VALUE);
 EVP_PKEY *GetPrivPKeyPtr(VALUE);
+
+/*
+ * Serializes _self_ in X.509 SubjectPublicKeyInfo format and returns the
+ * resulting String. Sub-classes use this when overriding #to_der.
+ */
+VALUE ossl_pkey_export_spki(VALUE self, int to_der);
+/*
+ * Serializes the private key _self_ in the traditional private key format
+ * and returns the resulting String. Sub-classes use this when overriding
+ * #to_der.
+ */
+VALUE ossl_pkey_export_traditional(int argc, VALUE *argv, VALUE self,
+				   int to_der);
+
 void Init_ossl_pkey(void);
 
 /*
@@ -56,7 +57,6 @@
 extern VALUE cRSA;
 extern VALUE eRSAError;
 
-VALUE ossl_rsa_new(EVP_PKEY *);
 void Init_ossl_rsa(void);
 
 /*
@@ -65,7 +65,6 @@
 extern VALUE cDSA;
 extern VALUE eDSAError;
 
-VALUE ossl_dsa_new(EVP_PKEY *);
 void Init_ossl_dsa(void);
 
 /*
@@ -74,7 +73,6 @@
 extern VALUE cDH;
 extern VALUE eDHError;
 
-VALUE ossl_dh_new(EVP_PKEY *);
 void Init_ossl_dh(void);
 
 /*
@@ -89,37 +87,6 @@
 VALUE ossl_ec_new(EVP_PKEY *);
 void Init_ossl_ec(void);
 
-#define OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, _name, _get)		\
-/*									\
- *  call-seq:								\
- *     _keytype##.##_name -> aBN					\
- */									\
-static VALUE ossl_##_keytype##_get_##_name(VALUE self)			\
-{									\
-	_type *obj;							\
-	const BIGNUM *bn;						\
-									\
-	Get##_type(self, obj);						\
-	_get;								\
-	if (bn == NULL)							\
-		return Qnil;						\
-	return ossl_bn_new(bn);						\
-}
-
-#define OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3)	\
-	OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1,			\
-		_type##_get0_##_group(obj, &bn, NULL, NULL))		\
-	OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2,			\
-		_type##_get0_##_group(obj, NULL, &bn, NULL))		\
-	OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a3,			\
-		_type##_get0_##_group(obj, NULL, NULL, &bn))
-
-#define OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2)	\
-	OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a1,			\
-		_type##_get0_##_group(obj, &bn, NULL))			\
-	OSSL_PKEY_BN_DEF_GETTER0(_keytype, _type, a2,			\
-		_type##_get0_##_group(obj, NULL, &bn))
-
 #define OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)	\
 /*									\
  *  call-seq:								\
@@ -132,6 +99,8 @@
 	BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
 	BIGNUM *bn3 = NULL, *orig_bn3 = NIL_P(v3) ? NULL : GetBNPtr(v3);\
 									\
+        rb_warning(#_keytype"#set_"#_group"= is incompatible with "	\
+                   "OpenSSL 3.0; check OpenSSL::PKey.from_data");	\
 	Get##_type(self, obj);						\
         if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) ||			\
             (orig_bn2 && !(bn2 = BN_dup(orig_bn2))) ||			\
@@ -162,6 +131,8 @@
 	BIGNUM *bn1 = NULL, *orig_bn1 = NIL_P(v1) ? NULL : GetBNPtr(v1);\
 	BIGNUM *bn2 = NULL, *orig_bn2 = NIL_P(v2) ? NULL : GetBNPtr(v2);\
 									\
+        rb_warning(#_keytype"#set_"#_group"= is incompatible with "	\
+                   "OpenSSL 3.0; check OpenSSL::PKey.from_data");	\
 	Get##_type(self, obj);						\
         if ((orig_bn1 && !(bn1 = BN_dup(orig_bn1))) ||			\
             (orig_bn2 && !(bn2 = BN_dup(orig_bn2)))) {			\
@@ -178,64 +149,10 @@
 	return self;							\
 }
 
-#define OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, _name)	\
-/*									\
- *  call-seq:								\
- *     _keytype##.##_name = bn -> bn					\
- */									\
-static VALUE ossl_##_keytype##_set_##_name(VALUE self, VALUE bignum)	\
-{									\
-	_type *obj;							\
-	BIGNUM *bn;							\
-									\
-	rb_warning("#"#_name"= is deprecated; use #set_"#_group);	\
-	Get##_type(self, obj);						\
-	if (NIL_P(bignum)) {						\
-		BN_clear_free(obj->_name);				\
-		obj->_name = NULL;					\
-		return Qnil;						\
-	}								\
-									\
-	bn = GetBNPtr(bignum);						\
-	if (obj->_name == NULL)						\
-		obj->_name = BN_new();					\
-	if (obj->_name == NULL)						\
-		ossl_raise(eBNError, NULL);				\
-	if (BN_copy(obj->_name, bn) == NULL)				\
-		ossl_raise(eBNError, NULL);				\
-	return bignum;							\
-}
-
-#if defined(HAVE_OPAQUE_OPENSSL) /* OpenSSL 1.1.0 */
 #define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3)		\
-	OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3)	\
 	OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)
 
 #define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2)		\
-	OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2)	\
 	OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)
 
-#define DEF_OSSL_PKEY_BN(class, keytype, name)				\
-	rb_define_method((class), #name, ossl_##keytype##_get_##name, 0)
-
-#else
-#define OSSL_PKEY_BN_DEF3(_keytype, _type, _group, a1, a2, a3)		\
-	OSSL_PKEY_BN_DEF_GETTER3(_keytype, _type, _group, a1, a2, a3)	\
-	OSSL_PKEY_BN_DEF_SETTER3(_keytype, _type, _group, a1, a2, a3)	\
-	OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a1)	\
-	OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a2)	\
-	OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a3)
-
-#define OSSL_PKEY_BN_DEF2(_keytype, _type, _group, a1, a2)		\
-	OSSL_PKEY_BN_DEF_GETTER2(_keytype, _type, _group, a1, a2)	\
-	OSSL_PKEY_BN_DEF_SETTER2(_keytype, _type, _group, a1, a2)	\
-	OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a1)	\
-	OSSL_PKEY_BN_DEF_SETTER_OLD(_keytype, _type, _group, a2)
-
-#define DEF_OSSL_PKEY_BN(class, keytype, name) do {			\
-	rb_define_method((class), #name, ossl_##keytype##_get_##name, 0);\
-	rb_define_method((class), #name "=", ossl_##keytype##_set_##name, 1);\
-} while (0)
-#endif /* HAVE_OPAQUE_OPENSSL */
-
-#endif /* _OSSL_PKEY_H_ */
+#endif /* OSSL_PKEY_H */
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_pkey_rsa.c ruby-3.0.2/ext/openssl/ossl_pkey_rsa.c
--- ruby-3.0.2.orig/ext/openssl/ossl_pkey_rsa.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_pkey_rsa.c	2021-09-09 18:27:58.354594302 +0800
@@ -45,174 +45,30 @@
 VALUE eRSAError;
 
 /*
- * Public
- */
-static VALUE
-rsa_instance(VALUE klass, RSA *rsa)
-{
-    EVP_PKEY *pkey;
-    VALUE obj;
-
-    if (!rsa) {
-	return Qfalse;
-    }
-    obj = NewPKey(klass);
-    if (!(pkey = EVP_PKEY_new())) {
-	return Qfalse;
-    }
-    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
-	EVP_PKEY_free(pkey);
-	return Qfalse;
-    }
-    SetPKey(obj, pkey);
-
-    return obj;
-}
-
-VALUE
-ossl_rsa_new(EVP_PKEY *pkey)
-{
-    VALUE obj;
-
-    if (!pkey) {
-	obj = rsa_instance(cRSA, RSA_new());
-    }
-    else {
-	obj = NewPKey(cRSA);
-	if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
-	    ossl_raise(rb_eTypeError, "Not a RSA key!");
-	}
-	SetPKey(obj, pkey);
-    }
-    if (obj == Qfalse) {
-	ossl_raise(eRSAError, NULL);
-    }
-
-    return obj;
-}
-
-/*
  * Private
  */
-struct rsa_blocking_gen_arg {
-    RSA *rsa;
-    BIGNUM *e;
-    int size;
-    BN_GENCB *cb;
-    int result;
-};
-
-static void *
-rsa_blocking_gen(void *arg)
-{
-    struct rsa_blocking_gen_arg *gen = (struct rsa_blocking_gen_arg *)arg;
-    gen->result = RSA_generate_key_ex(gen->rsa, gen->size, gen->e, gen->cb);
-    return 0;
-}
-
-static RSA *
-rsa_generate(int size, unsigned long exp)
-{
-    int i;
-    struct ossl_generate_cb_arg cb_arg = { 0 };
-    struct rsa_blocking_gen_arg gen_arg;
-    RSA *rsa = RSA_new();
-    BIGNUM *e = BN_new();
-    BN_GENCB *cb = BN_GENCB_new();
-
-    if (!rsa || !e || !cb) {
-	RSA_free(rsa);
-	BN_free(e);
-	BN_GENCB_free(cb);
-	return NULL;
-    }
-    for (i = 0; i < (int)sizeof(exp) * 8; ++i) {
-	if (exp & (1UL << i)) {
-	    if (BN_set_bit(e, i) == 0) {
-		BN_free(e);
-		RSA_free(rsa);
-		BN_GENCB_free(cb);
-		return NULL;
-	    }
-	}
-    }
-
-    if (rb_block_given_p())
-	cb_arg.yield = 1;
-    BN_GENCB_set(cb, ossl_generate_cb_2, &cb_arg);
-    gen_arg.rsa = rsa;
-    gen_arg.e = e;
-    gen_arg.size = size;
-    gen_arg.cb = cb;
-    if (cb_arg.yield == 1) {
-	/* we cannot release GVL when callback proc is supplied */
-	rsa_blocking_gen(&gen_arg);
-    } else {
-	/* there's a chance to unblock */
-	rb_thread_call_without_gvl(rsa_blocking_gen, &gen_arg, ossl_generate_cb_stop, &cb_arg);
-    }
-
-    BN_GENCB_free(cb);
-    BN_free(e);
-    if (!gen_arg.result) {
-	RSA_free(rsa);
-	if (cb_arg.state) {
-	    /* must clear OpenSSL error stack */
-	    ossl_clear_error();
-	    rb_jump_tag(cb_arg.state);
-	}
-	return NULL;
-    }
-
-    return rsa;
-}
-
-/*
- * call-seq:
- *   RSA.generate(size)           => RSA instance
- *   RSA.generate(size, exponent) => RSA instance
- *
- * Generates an RSA keypair.  _size_ is an integer representing the desired key
- * size.  Keys smaller than 1024 should be considered insecure.  _exponent_ is
- * an odd number normally 3, 17, or 65537.
- */
-static VALUE
-ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
-{
-/* why does this method exist?  why can't initialize take an optional exponent? */
-    RSA *rsa;
-    VALUE size, exp;
-    VALUE obj;
-
-    rb_scan_args(argc, argv, "11", &size, &exp);
-
-    rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2ULONG(exp)); /* err handled by rsa_instance */
-    obj = rsa_instance(klass, rsa);
-
-    if (obj == Qfalse) {
-	RSA_free(rsa);
-	ossl_raise(eRSAError, NULL);
-    }
-
-    return obj;
-}
-
 /*
  * call-seq:
- *   RSA.new(key_size)                 => RSA instance
- *   RSA.new(encoded_key)              => RSA instance
- *   RSA.new(encoded_key, pass_phrase) => RSA instance
- *
- * Generates or loads an RSA keypair.  If an integer _key_size_ is given it
- * represents the desired key size.  Keys less than 1024 bits should be
- * considered insecure.
- *
- * A key can instead be loaded from an _encoded_key_ which must be PEM or DER
- * encoded.  A _pass_phrase_ can be used to decrypt the key.  If none is given
- * OpenSSL will prompt for the pass phrase.
+ *   RSA.new -> rsa
+ *   RSA.new(encoded_key [, passphrase]) -> rsa
+ *   RSA.new(encoded_key) { passphrase } -> rsa
+ *   RSA.new(size [, exponent]) -> rsa
+ *
+ * Generates or loads an \RSA keypair.
+ *
+ * If called without arguments, creates a new instance with no key components
+ * set. They can be set individually by #set_key, #set_factors, and
+ * #set_crt_params.
+ *
+ * If called with a String, tries to parse as DER or PEM encoding of an \RSA key.
+ * Note that, if _passphrase_ is not specified but the key is encrypted with a
+ * passphrase, \OpenSSL will prompt for it.
+ * See also OpenSSL::PKey.read which can parse keys of any kinds.
  *
- * = Examples
+ * If called with a number, generates a new key pair. This form works as an
+ * alias of RSA.generate.
  *
+ * Examples:
  *   OpenSSL::PKey::RSA.new 2048
  *   OpenSSL::PKey::RSA.new File.read 'rsa.pem'
  *   OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase'
@@ -224,72 +80,90 @@
     RSA *rsa;
     BIO *in;
     VALUE arg, pass;
+    int type;
 
-    GetPKey(self, pkey);
-    if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
+
+    /* The RSA.new(size, generator) form is handled by lib/openssl/pkey.rb */
+    rb_scan_args(argc, argv, "02", &arg, &pass);
+    if (argc == 0) {
 	rsa = RSA_new();
-    }
-    else if (RB_INTEGER_TYPE_P(arg)) {
-	rsa = rsa_generate(NUM2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2ULONG(pass));
-	if (!rsa) ossl_raise(eRSAError, NULL);
+        if (!rsa)
+            ossl_raise(eRSAError, "RSA_new");
     }
     else {
-	pass = ossl_pem_passwd_value(pass);
-	arg = ossl_to_der_if_possible(arg);
-	in = ossl_obj2bio(&arg);
-	rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, (void *)pass);
-	if (!rsa) {
-	    OSSL_BIO_reset(in);
-	    rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL);
-	}
-	if (!rsa) {
-	    OSSL_BIO_reset(in);
-	    rsa = d2i_RSAPrivateKey_bio(in, NULL);
-	}
-	if (!rsa) {
-	    OSSL_BIO_reset(in);
-	    rsa = d2i_RSA_PUBKEY_bio(in, NULL);
-	}
-	if (!rsa) {
-	    OSSL_BIO_reset(in);
-	    rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
-	}
-	if (!rsa) {
-	    OSSL_BIO_reset(in);
-	    rsa = d2i_RSAPublicKey_bio(in, NULL);
-	}
-	BIO_free(in);
-	if (!rsa) {
-	    ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
-	}
+        pass = ossl_pem_passwd_value(pass);
+        arg = ossl_to_der_if_possible(arg);
+        in = ossl_obj2bio(&arg);
+
+        /* First try RSAPublicKey format */
+        rsa = d2i_RSAPublicKey_bio(in, NULL);
+        OSSL_BIO_reset(in);
+        if (rsa)
+            goto legacy;
+        rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
+        OSSL_BIO_reset(in);
+        if (rsa)
+            goto legacy;
+
+        /* Use the generic routine */
+        pkey = ossl_pkey_read_generic(in, pass);
+        BIO_free(in);
+        if (!pkey)
+            ossl_raise(eRSAError, "Neither PUB key nor PRIV key");
+
+        type = EVP_PKEY_base_id(pkey);
+        if (type != EVP_PKEY_RSA) {
+            EVP_PKEY_free(pkey);
+            rb_raise(eRSAError, "incorrect pkey type: %s", OBJ_nid2sn(type));
+        }
+        RTYPEDDATA_DATA(self) = pkey;
+        return self;
+    }
+
+  legacy:
+    if (rsa) {
+        pkey = EVP_PKEY_new();
+        if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
+            EVP_PKEY_free(pkey);
+            RSA_free(rsa);
+            ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+        }
     }
-    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
-	RSA_free(rsa);
-	ossl_raise(eRSAError, NULL);
-    }
-
+    RTYPEDDATA_DATA(self) = pkey;
     return self;
 }
 
+#ifndef HAVE_EVP_PKEY_DUP
 static VALUE
 ossl_rsa_initialize_copy(VALUE self, VALUE other)
 {
     EVP_PKEY *pkey;
     RSA *rsa, *rsa_new;
 
-    GetPKey(self, pkey);
-    if (EVP_PKEY_base_id(pkey) != EVP_PKEY_NONE)
-	ossl_raise(eRSAError, "RSA already initialized");
+    GetPKey0(self, pkey);
+    if (pkey)
+        rb_raise(rb_eTypeError, "pkey already initialized");
     GetRSA(other, rsa);
 
-    rsa_new = ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey, (d2i_of_void *)d2i_RSAPrivateKey, (char *)rsa);
+    rsa_new = (RSA *)ASN1_dup((i2d_of_void *)i2d_RSAPrivateKey,
+                              (d2i_of_void *)d2i_RSAPrivateKey,
+                              (char *)rsa);
     if (!rsa_new)
 	ossl_raise(eRSAError, "ASN1_dup");
 
-    EVP_PKEY_assign_RSA(pkey, rsa_new);
+    pkey = EVP_PKEY_new();
+    if (!pkey || EVP_PKEY_assign_RSA(pkey, rsa_new) != 1) {
+        RSA_free(rsa_new);
+        ossl_raise(eRSAError, "EVP_PKEY_assign_RSA");
+    }
+    RTYPEDDATA_DATA(self) = pkey;
 
     return self;
 }
+#endif
 
 /*
  * call-seq:
@@ -327,221 +201,53 @@
     return RSA_PRIVATE(self, rsa) ? Qtrue : Qfalse;
 }
 
-/*
- * call-seq:
- *   rsa.export([cipher, pass_phrase]) => PEM-format String
- *   rsa.to_pem([cipher, pass_phrase]) => PEM-format String
- *   rsa.to_s([cipher, pass_phrase]) => PEM-format String
- *
- * Outputs this keypair in PEM encoding.  If _cipher_ and _pass_phrase_ are
- * given they will be used to encrypt the key.  _cipher_ must be an
- * OpenSSL::Cipher instance.
- */
-static VALUE
-ossl_rsa_export(int argc, VALUE *argv, VALUE self)
+static int
+can_export_rsaprivatekey(VALUE self)
 {
     RSA *rsa;
     const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
-    BIO *out;
-    const EVP_CIPHER *ciph = NULL;
-    VALUE cipher, pass, str;
 
     GetRSA(self, rsa);
 
-    rb_scan_args(argc, argv, "02", &cipher, &pass);
-
-    if (!NIL_P(cipher)) {
-	ciph = ossl_evp_get_cipherbyname(cipher);
-	pass = ossl_pem_passwd_value(pass);
-    }
-    if (!(out = BIO_new(BIO_s_mem()))) {
-	ossl_raise(eRSAError, NULL);
-    }
     RSA_get0_key(rsa, &n, &e, &d);
     RSA_get0_factors(rsa, &p, &q);
     RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
-    if (n && e && d && p && q && dmp1 && dmq1 && iqmp) {
-	if (!PEM_write_bio_RSAPrivateKey(out, rsa, ciph, NULL, 0,
-					 ossl_pem_passwd_cb, (void *)pass)) {
-	    BIO_free(out);
-	    ossl_raise(eRSAError, NULL);
-	}
-    } else {
-	if (!PEM_write_bio_RSA_PUBKEY(out, rsa)) {
-	    BIO_free(out);
-	    ossl_raise(eRSAError, NULL);
-	}
-    }
-    str = ossl_membio2str(out);
 
-    return str;
+    return n && e && d && p && q && dmp1 && dmq1 && iqmp;
 }
 
 /*
  * call-seq:
- *   rsa.to_der => DER-format String
+ *   rsa.export([cipher, pass_phrase]) => PEM-format String
+ *   rsa.to_pem([cipher, pass_phrase]) => PEM-format String
+ *   rsa.to_s([cipher, pass_phrase]) => PEM-format String
  *
- * Outputs this keypair in DER encoding.
+ * Outputs this keypair in PEM encoding.  If _cipher_ and _pass_phrase_ are
+ * given they will be used to encrypt the key.  _cipher_ must be an
+ * OpenSSL::Cipher instance.
  */
 static VALUE
-ossl_rsa_to_der(VALUE self)
+ossl_rsa_export(int argc, VALUE *argv, VALUE self)
 {
-    RSA *rsa;
-    const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
-    int (*i2d_func)(const RSA *, unsigned char **);
-    unsigned char *ptr;
-    long len;
-    VALUE str;
-
-    GetRSA(self, rsa);
-    RSA_get0_key(rsa, &n, &e, &d);
-    RSA_get0_factors(rsa, &p, &q);
-    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
-    if (n && e && d && p && q && dmp1 && dmq1 && iqmp)
-	i2d_func = i2d_RSAPrivateKey;
+    if (can_export_rsaprivatekey(self))
+        return ossl_pkey_export_traditional(argc, argv, self, 0);
     else
-	i2d_func = (int (*)(const RSA *, unsigned char **))i2d_RSA_PUBKEY;
-    if((len = i2d_func(rsa, NULL)) <= 0)
-	ossl_raise(eRSAError, NULL);
-    str = rb_str_new(0, len);
-    ptr = (unsigned char *)RSTRING_PTR(str);
-    if(i2d_func(rsa, &ptr) < 0)
-	ossl_raise(eRSAError, NULL);
-    ossl_str_adjust(str, ptr);
-
-    return str;
-}
-
-/*
- * call-seq:
- *   rsa.public_encrypt(string)          => String
- *   rsa.public_encrypt(string, padding) => String
- *
- * Encrypt _string_ with the public key.  _padding_ defaults to PKCS1_PADDING.
- * The encrypted string output can be decrypted using #private_decrypt.
- */
-static VALUE
-ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
-{
-    RSA *rsa;
-    const BIGNUM *rsa_n;
-    int buf_len, pad;
-    VALUE str, buffer, padding;
-
-    GetRSA(self, rsa);
-    RSA_get0_key(rsa, &rsa_n, NULL, NULL);
-    if (!rsa_n)
-	ossl_raise(eRSAError, "incomplete RSA");
-    rb_scan_args(argc, argv, "11", &buffer, &padding);
-    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
-    StringValue(buffer);
-    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);
-    rb_str_set_len(str, buf_len);
-
-    return str;
+        return ossl_pkey_export_spki(self, 0);
 }
 
 /*
  * call-seq:
- *   rsa.public_decrypt(string)          => String
- *   rsa.public_decrypt(string, padding) => String
- *
- * Decrypt _string_, which has been encrypted with the private key, with the
- * public key.  _padding_ defaults to PKCS1_PADDING.
- */
-static VALUE
-ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
-{
-    RSA *rsa;
-    const BIGNUM *rsa_n;
-    int buf_len, pad;
-    VALUE str, buffer, padding;
-
-    GetRSA(self, rsa);
-    RSA_get0_key(rsa, &rsa_n, NULL, NULL);
-    if (!rsa_n)
-	ossl_raise(eRSAError, "incomplete RSA");
-    rb_scan_args(argc, argv, "11", &buffer, &padding);
-    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
-    StringValue(buffer);
-    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);
-    rb_str_set_len(str, buf_len);
-
-    return str;
-}
-
-/*
- * call-seq:
- *   rsa.private_encrypt(string)          => String
- *   rsa.private_encrypt(string, padding) => String
- *
- * Encrypt _string_ with the private key.  _padding_ defaults to PKCS1_PADDING.
- * The encrypted string output can be decrypted using #public_decrypt.
- */
-static VALUE
-ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
-{
-    RSA *rsa;
-    const BIGNUM *rsa_n;
-    int buf_len, pad;
-    VALUE str, buffer, padding;
-
-    GetRSA(self, rsa);
-    RSA_get0_key(rsa, &rsa_n, NULL, NULL);
-    if (!rsa_n)
-	ossl_raise(eRSAError, "incomplete RSA");
-    if (!RSA_PRIVATE(self, rsa))
-	ossl_raise(eRSAError, "private key needed.");
-    rb_scan_args(argc, argv, "11", &buffer, &padding);
-    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
-    StringValue(buffer);
-    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);
-    rb_str_set_len(str, buf_len);
-
-    return str;
-}
-
-/*
- * call-seq:
- *   rsa.private_decrypt(string)          => String
- *   rsa.private_decrypt(string, padding) => String
+ *   rsa.to_der => DER-format String
  *
- * Decrypt _string_, which has been encrypted with the public key, with the
- * private key.  _padding_ defaults to PKCS1_PADDING.
+ * Outputs this keypair in DER encoding.
  */
 static VALUE
-ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
+ossl_rsa_to_der(VALUE self)
 {
-    RSA *rsa;
-    const BIGNUM *rsa_n;
-    int buf_len, pad;
-    VALUE str, buffer, padding;
-
-    GetRSA(self, rsa);
-    RSA_get0_key(rsa, &rsa_n, NULL, NULL);
-    if (!rsa_n)
-	ossl_raise(eRSAError, "incomplete RSA");
-    if (!RSA_PRIVATE(self, rsa))
-	ossl_raise(eRSAError, "private key needed.");
-    rb_scan_args(argc, argv, "11", &buffer, &padding);
-    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
-    StringValue(buffer);
-    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);
-    rb_str_set_len(str, buf_len);
-
-    return str;
+    if (can_export_rsaprivatekey(self))
+        return ossl_pkey_export_traditional(0, NULL, self, 1);
+    else
+        return ossl_pkey_export_spki(self, 1);
 }
 
 /*
@@ -573,7 +279,7 @@
  *   data = "Sign me!"
  *   pkey = OpenSSL::PKey::RSA.new(2048)
  *   signature = pkey.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA256")
- *   pub_key = pkey.public_key
+ *   pub_key = OpenSSL::PKey.read(pkey.public_to_der)
  *   puts pub_key.verify_pss("SHA256", signature, data,
  *                           salt_length: :auto, mgf1_hash: "SHA256") # => true
  */
@@ -734,19 +440,10 @@
     ossl_raise(eRSAError, NULL);
 }
 
-/*
- * call-seq:
- *   rsa.params => hash
- *
- * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
- *
- * Stores all parameters of key to the hash.  The hash has keys 'n', 'e', 'd',
- * 'p', 'q', 'dmp1', 'dmq1', 'iqmp'.
- *
- * Don't use :-)) (It's up to you)
- */
+#ifndef HAVE_EVP_PKEY_TODATA
+/* :nodoc: */
 static VALUE
-ossl_rsa_get_params(VALUE self)
+ossl_rsa_to_data(VALUE self)
 {
     RSA *rsa;
     VALUE hash;
@@ -758,99 +455,26 @@
     RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
 
     hash = rb_hash_new();
-    rb_hash_aset(hash, rb_str_new2("n"), ossl_bn_new(n));
-    rb_hash_aset(hash, rb_str_new2("e"), ossl_bn_new(e));
-    rb_hash_aset(hash, rb_str_new2("d"), ossl_bn_new(d));
-    rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(p));
-    rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(q));
-    rb_hash_aset(hash, rb_str_new2("dmp1"), ossl_bn_new(dmp1));
-    rb_hash_aset(hash, rb_str_new2("dmq1"), ossl_bn_new(dmq1));
-    rb_hash_aset(hash, rb_str_new2("iqmp"), ossl_bn_new(iqmp));
+    if (n)
+        rb_hash_aset(hash, ID2SYM(rb_intern("n")), ossl_bn_new(n));
+    if (e)
+        rb_hash_aset(hash, ID2SYM(rb_intern("e")), ossl_bn_new(e));
+    if (d)
+        rb_hash_aset(hash, ID2SYM(rb_intern("d")), ossl_bn_new(d));
+    if (p)
+        rb_hash_aset(hash, ID2SYM(rb_intern("rsa-factor1")), ossl_bn_new(p));
+    if (q)
+        rb_hash_aset(hash, ID2SYM(rb_intern("rsa-factor2")), ossl_bn_new(q));
+    if (dmp1)
+        rb_hash_aset(hash, ID2SYM(rb_intern("rsa-exponent1")), ossl_bn_new(dmp1));
+    if (dmq1)
+        rb_hash_aset(hash, ID2SYM(rb_intern("rsa-exponent2")), ossl_bn_new(dmq1));
+    if (iqmp)
+        rb_hash_aset(hash, ID2SYM(rb_intern("rsa-coefficient1")), ossl_bn_new(iqmp));
 
     return hash;
 }
-
-/*
- * call-seq:
- *   rsa.to_text => String
- *
- * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
- *
- * Dumps all parameters of a keypair to a String
- *
- * Don't use :-)) (It's up to you)
- */
-static VALUE
-ossl_rsa_to_text(VALUE self)
-{
-    RSA *rsa;
-    BIO *out;
-    VALUE str;
-
-    GetRSA(self, rsa);
-    if (!(out = BIO_new(BIO_s_mem()))) {
-	ossl_raise(eRSAError, NULL);
-    }
-    if (!RSA_print(out, rsa, 0)) { /* offset = 0 */
-	BIO_free(out);
-	ossl_raise(eRSAError, NULL);
-    }
-    str = ossl_membio2str(out);
-
-    return str;
-}
-
-/*
- * call-seq:
- *    rsa.public_key -> RSA
- *
- * Makes new RSA instance containing the public key from the private key.
- */
-static VALUE
-ossl_rsa_to_public_key(VALUE self)
-{
-    EVP_PKEY *pkey;
-    RSA *rsa;
-    VALUE obj;
-
-    GetPKeyRSA(self, pkey);
-    /* err check performed by rsa_instance */
-    rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey));
-    obj = rsa_instance(rb_obj_class(self), rsa);
-    if (obj == Qfalse) {
-	RSA_free(rsa);
-	ossl_raise(eRSAError, NULL);
-    }
-    return obj;
-}
-
-/*
- * TODO: Test me
-
-static VALUE
-ossl_rsa_blinding_on(VALUE self)
-{
-    RSA *rsa;
-
-    GetRSA(self, rsa);
-
-    if (RSA_blinding_on(rsa, ossl_bn_ctx) != 1) {
-	ossl_raise(eRSAError, NULL);
-    }
-    return self;
-}
-
-static VALUE
-ossl_rsa_blinding_off(VALUE self)
-{
-    RSA *rsa;
-
-    GetRSA(self, rsa);
-    RSA_blinding_off(rsa);
-
-    return self;
-}
- */
+#endif
 
 /*
  * Document-method: OpenSSL::PKey::RSA#set_key
@@ -913,43 +537,27 @@
      */
     cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
 
-    rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1);
     rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1);
+#ifndef HAVE_EVP_PKEY_DUP
     rb_define_method(cRSA, "initialize_copy", ossl_rsa_initialize_copy, 1);
+#endif
 
     rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
     rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);
-    rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0);
     rb_define_method(cRSA, "export", ossl_rsa_export, -1);
     rb_define_alias(cRSA, "to_pem", "export");
     rb_define_alias(cRSA, "to_s", "export");
     rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0);
-    rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0);
-    rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1);
-    rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1);
-    rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1);
-    rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1);
     rb_define_method(cRSA, "sign_pss", ossl_rsa_sign_pss, -1);
     rb_define_method(cRSA, "verify_pss", ossl_rsa_verify_pss, -1);
 
-    DEF_OSSL_PKEY_BN(cRSA, rsa, n);
-    DEF_OSSL_PKEY_BN(cRSA, rsa, e);
-    DEF_OSSL_PKEY_BN(cRSA, rsa, d);
-    DEF_OSSL_PKEY_BN(cRSA, rsa, p);
-    DEF_OSSL_PKEY_BN(cRSA, rsa, q);
-    DEF_OSSL_PKEY_BN(cRSA, rsa, dmp1);
-    DEF_OSSL_PKEY_BN(cRSA, rsa, dmq1);
-    DEF_OSSL_PKEY_BN(cRSA, rsa, iqmp);
     rb_define_method(cRSA, "set_key", ossl_rsa_set_key, 3);
     rb_define_method(cRSA, "set_factors", ossl_rsa_set_factors, 2);
     rb_define_method(cRSA, "set_crt_params", ossl_rsa_set_crt_params, 3);
 
-    rb_define_method(cRSA, "params", ossl_rsa_get_params, 0);
-
-    DefRSAConst(PKCS1_PADDING);
-    DefRSAConst(SSLV23_PADDING);
-    DefRSAConst(NO_PADDING);
-    DefRSAConst(PKCS1_OAEP_PADDING);
+#ifndef HAVE_EVP_PKEY_TODATA
+    rb_define_method(cRSA, "to_data", ossl_rsa_to_data, 0);
+#endif
 
 /*
  * TODO: Test it
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_ssl.c ruby-3.0.2/ext/openssl/ossl_ssl.c
--- ruby-3.0.2.orig/ext/openssl/ossl_ssl.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_ssl.c	2021-09-09 18:27:58.354594302 +0800
@@ -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
@@ -32,14 +38,14 @@
 static VALUE eSSLErrorWaitReadable;
 static VALUE eSSLErrorWaitWritable;
 
-static ID id_call, ID_callback_state, id_tmp_dh_callback, id_tmp_ecdh_callback,
+static ID id_call, ID_callback_state, id_tmp_dh_callback,
 	  id_npn_protocols_encoded;
 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,
 	  id_i_verify_depth, id_i_verify_callback, id_i_client_ca,
 	  id_i_renegotiation_cb, id_i_cert, id_i_key, id_i_extra_chain_cert,
-	  id_i_client_cert_cb, id_i_tmp_ecdh_callback, id_i_timeout,
+	  id_i_client_cert_cb, id_i_timeout,
 	  id_i_session_id_context, id_i_session_get_cb, id_i_session_new_cb,
 	  id_i_session_remove_cb, id_i_npn_select_cb, id_i_npn_protocols,
 	  id_i_alpn_select_cb, id_i_alpn_protocols, id_i_servername_cb,
@@ -49,19 +55,11 @@
 static int ossl_ssl_ex_vcb_idx;
 static int ossl_ssl_ex_ptr_idx;
 static int ossl_sslctx_ex_ptr_idx;
-#if !defined(HAVE_X509_STORE_UP_REF)
-static int ossl_sslctx_ex_store_p;
-#endif
 
 static void
 ossl_sslctx_free(void *ptr)
 {
-    SSL_CTX *ctx = ptr;
-#if !defined(HAVE_X509_STORE_UP_REF)
-    if (ctx && SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_store_p))
-	ctx->cert_store = NULL;
-#endif
-    SSL_CTX_free(ctx);
+    SSL_CTX_free(ptr);
 }
 
 static const rb_data_type_t ossl_sslctx_type = {
@@ -83,7 +81,7 @@
     VALUE obj;
 
     obj = TypedData_Wrap_Struct(klass, &ossl_sslctx_type, 0);
-#if OPENSSL_VERSION_NUMBER >= 0x10100000 && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000 || defined(LIBRESSL_VERSION_NUMBER)
     ctx = SSL_CTX_new(TLS_method());
 #else
     ctx = SSL_CTX_new(SSLv23_method());
@@ -95,14 +93,15 @@
     RTYPEDDATA_DATA(obj) = ctx;
     SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_ptr_idx, (void *)obj);
 
-#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
+#if !defined(OPENSSL_NO_EC) && OPENSSL_VERSION_NUMBER < 0x10100000 && \
+    !defined(LIBRESSL_VERSION_NUMBER)
     /* We use SSL_CTX_set1_curves_list() to specify the curve used in ECDH. It
      * allows to specify multiple curve names and OpenSSL will select
      * automatically from them. In OpenSSL 1.0.2, the automatic selection has to
-     * be enabled explicitly. But OpenSSL 1.1.0 removed the knob and it is
-     * always enabled. To uniform the behavior, we enable the automatic
-     * selection also in 1.0.2. Users can still disable ECDH by removing ECDH
-     * cipher suites by SSLContext#ciphers=. */
+     * be enabled explicitly. OpenSSL 1.1.0 and LibreSSL 2.6.1 removed the knob
+     * and it is always enabled. To uniform the behavior, we enable the
+     * automatic selection also in 1.0.2. Users can still disable ECDH by
+     * removing ECDH cipher suites by SSLContext#ciphers=. */
     if (!SSL_CTX_set_ecdh_auto(ctx, 1))
 	ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
 #endif
@@ -231,8 +230,7 @@
     return 1;
 }
 
-#if !defined(OPENSSL_NO_DH) || \
-    !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
+#if !defined(OPENSSL_NO_DH)
 struct tmp_dh_callback_args {
     VALUE ssl_obj;
     ID id;
@@ -289,35 +287,6 @@
 }
 #endif /* OPENSSL_NO_DH */
 
-#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
-static EC_KEY *
-ossl_tmp_ecdh_callback(SSL *ssl, int is_export, int keylength)
-{
-    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;
-
-    return EVP_PKEY_get0_EC_KEY(pkey);
-}
-#endif
-
 static VALUE
 call_verify_certificate_identity(VALUE ctx_v)
 {
@@ -387,7 +356,7 @@
 }
 
 static SSL_SESSION *
-#if (!defined(LIBRESSL_VERSION_NUMBER) ? OPENSSL_VERSION_NUMBER >= 0x10100000 : LIBRESSL_VERSION_NUMBER >= 0x2080000f)
+#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER >= 0x10100000
 ossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy)
 #else
 ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy)
@@ -596,8 +565,6 @@
     rb_funcallv(cb, id_call, 1, &ssl_obj);
 }
 
-#if !defined(OPENSSL_NO_NEXTPROTONEG) || \
-    defined(HAVE_SSL_CTX_SET_ALPN_SELECT_CB)
 static VALUE
 ssl_npn_encode_protocol_i(RB_BLOCK_CALL_FUNC_ARGLIST(cur, encoded))
 {
@@ -679,7 +646,6 @@
 
     return SSL_TLSEXT_ERR_OK;
 }
-#endif
 
 #ifndef OPENSSL_NO_NEXTPROTONEG
 static int
@@ -708,7 +674,6 @@
 }
 #endif
 
-#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
 static int
 ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outlen,
 		   const unsigned char *in, unsigned int inlen, void *arg)
@@ -720,7 +685,6 @@
 
     return ssl_npn_select_cb_common(ssl, cb, out, outlen, in, inlen);
 }
-#endif
 
 /* This function may serve as the entry point to support further callbacks. */
 static void
@@ -797,26 +761,6 @@
     SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
 #endif
 
-#if !defined(OPENSSL_NO_EC)
-    /* We added SSLContext#tmp_ecdh_callback= in Ruby 2.3.0,
-     * but SSL_CTX_set_tmp_ecdh_callback() was removed in OpenSSL 1.1.0. */
-    if (RTEST(rb_attr_get(self, id_i_tmp_ecdh_callback))) {
-# if defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
-	rb_warn("#tmp_ecdh_callback= is deprecated; use #ecdh_curves= instead");
-	SSL_CTX_set_tmp_ecdh_callback(ctx, ossl_tmp_ecdh_callback);
-#  if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
-	/* tmp_ecdh_callback and ecdh_auto conflict; OpenSSL ignores
-	 * tmp_ecdh_callback. So disable ecdh_auto. */
-	if (!SSL_CTX_set_ecdh_auto(ctx, 0))
-	    ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
-#  endif
-# else
-	ossl_raise(eSSLError, "OpenSSL does not support tmp_ecdh_callback; "
-		   "use #ecdh_curves= instead");
-# endif
-    }
-#endif /* OPENSSL_NO_EC */
-
 #ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
     SSL_CTX_set_post_handshake_auth(ctx, 1);
 #endif
@@ -825,17 +769,7 @@
     if (!NIL_P(val)) {
 	X509_STORE *store = GetX509StorePtr(val); /* NO NEED TO DUP */
 	SSL_CTX_set_cert_store(ctx, store);
-#if !defined(HAVE_X509_STORE_UP_REF)
-	/*
-         * WORKAROUND:
-	 *   X509_STORE can count references, but
-	 *   X509_STORE_free() doesn't care it.
-	 *   So we won't increment it but mark it by ex_data.
-	 */
-        SSL_CTX_set_ex_data(ctx, ossl_sslctx_ex_store_p, ctx);
-#else /* Fixed in OpenSSL 1.0.2; bff9ce4db38b (master), 5b4b9ce976fc (1.0.2) */
 	X509_STORE_up_ref(store);
-#endif
     }
 
     val = rb_attr_get(self, id_i_extra_chain_cert);
@@ -886,10 +820,17 @@
     ca_file = NIL_P(val) ? NULL : StringValueCStr(val);
     val = rb_attr_get(self, id_i_ca_path);
     ca_path = NIL_P(val) ? NULL : StringValueCStr(val);
+#ifdef HAVE_SSL_CTX_LOAD_VERIFY_FILE
+    if (ca_file && !SSL_CTX_load_verify_file(ctx, ca_file))
+        ossl_raise(eSSLError, "SSL_CTX_load_verify_file");
+    if (ca_path && !SSL_CTX_load_verify_dir(ctx, ca_path))
+        ossl_raise(eSSLError, "SSL_CTX_load_verify_dir");
+#else
     if(ca_file || ca_path){
 	if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
 	    rb_warning("can't set verify locations");
     }
+#endif
 
     val = rb_attr_get(self, id_i_verify_mode);
     verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
@@ -917,7 +858,6 @@
     }
 #endif
 
-#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
     val = rb_attr_get(self, id_i_alpn_protocols);
     if (!NIL_P(val)) {
 	VALUE rprotos = ssl_encode_npn_protocols(val);
@@ -932,7 +872,6 @@
 	SSL_CTX_set_alpn_select_cb(ctx, ssl_alpn_select_cb, (void *) self);
 	OSSL_Debug("SSL ALPN select callback added");
     }
-#endif
 
     rb_obj_freeze(self);
 
@@ -1065,9 +1004,6 @@
  * Extension. For a server, the list is used by OpenSSL to determine the set of
  * shared curves. OpenSSL will pick the most appropriate one from it.
  *
- * Note that this works differently with old OpenSSL (<= 1.0.1). Only one curve
- * can be set, and this has no effect for TLS clients.
- *
  * === Example
  *   ctx1 = OpenSSL::SSL::SSLContext.new
  *   ctx1.ecdh_curves = "X25519:P-256:P-224"
@@ -1091,48 +1027,8 @@
     GetSSLCTX(self, ctx);
     StringValueCStr(arg);
 
-#if defined(HAVE_SSL_CTX_SET1_CURVES_LIST)
     if (!SSL_CTX_set1_curves_list(ctx, RSTRING_PTR(arg)))
 	ossl_raise(eSSLError, NULL);
-#else
-    /* OpenSSL does not have SSL_CTX_set1_curves_list()... Fallback to
-     * SSL_CTX_set_tmp_ecdh(). So only the first curve is used. */
-    {
-	VALUE curve, splitted;
-	EC_KEY *ec;
-	int nid;
-
-	splitted = rb_str_split(arg, ":");
-	if (!RARRAY_LEN(splitted))
-	    ossl_raise(eSSLError, "invalid input format");
-	curve = RARRAY_AREF(splitted, 0);
-	StringValueCStr(curve);
-
-	/* SSL_CTX_set1_curves_list() accepts NIST names */
-	nid = EC_curve_nist2nid(RSTRING_PTR(curve));
-	if (nid == NID_undef)
-	    nid = OBJ_txt2nid(RSTRING_PTR(curve));
-	if (nid == NID_undef)
-	    ossl_raise(eSSLError, "unknown curve name");
-
-	ec = EC_KEY_new_by_curve_name(nid);
-	if (!ec)
-	    ossl_raise(eSSLError, NULL);
-	EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
-	if (!SSL_CTX_set_tmp_ecdh(ctx, ec)) {
-	    EC_KEY_free(ec);
-	    ossl_raise(eSSLError, "SSL_CTX_set_tmp_ecdh");
-	}
-	EC_KEY_free(ec);
-# if defined(HAVE_SSL_CTX_SET_ECDH_AUTO)
-	/* tmp_ecdh and ecdh_auto conflict. tmp_ecdh is ignored when ecdh_auto
-	 * is enabled. So disable ecdh_auto. */
-	if (!SSL_CTX_set_ecdh_auto(ctx, 0))
-	    ossl_raise(eSSLError, "SSL_CTX_set_ecdh_auto");
-# endif
-    }
-#endif
-
     return arg;
 }
 #else
@@ -1223,7 +1119,7 @@
 
 /*
  * call-seq:
- *    ctx.add_certificate(certiticate, pkey [, extra_certs]) -> self
+ *    ctx.add_certificate(certificate, pkey [, extra_certs]) -> self
  *
  * Adds a certificate to the context. _pkey_ must be a corresponding private
  * key with _certificate_.
@@ -1255,10 +1151,6 @@
  *   ecdsa_pkey = ...
  *   another_ca_cert = ...
  *   ctx.add_certificate(ecdsa_cert, ecdsa_pkey, [another_ca_cert])
- *
- * === Note
- * OpenSSL before the version 1.0.2 could handle only one extra chain across
- * all key types. Calling this method discards the chain set previously.
  */
 static VALUE
 ossl_sslctx_add_certificate(int argc, VALUE *argv, VALUE self)
@@ -1283,7 +1175,7 @@
     EVP_PKEY_free(pub_pkey);
     if (!pub_pkey)
 	rb_raise(rb_eArgError, "certificate does not contain public key");
-    if (EVP_PKEY_cmp(pub_pkey, pkey) != 1)
+    if (EVP_PKEY_eq(pub_pkey, pkey) != 1)
 	rb_raise(rb_eArgError, "public key mismatch");
 
     if (argc >= 3)
@@ -1297,34 +1189,9 @@
 	sk_X509_pop_free(extra_chain, X509_free);
 	ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey");
     }
-
-    if (extra_chain) {
-#if OPENSSL_VERSION_NUMBER >= 0x10002000 && !defined(LIBRESSL_VERSION_NUMBER)
-	if (!SSL_CTX_set0_chain(ctx, extra_chain)) {
-	    sk_X509_pop_free(extra_chain, X509_free);
-	    ossl_raise(eSSLError, "SSL_CTX_set0_chain");
-	}
-#else
-	STACK_OF(X509) *orig_extra_chain;
-	X509 *x509_tmp;
-
-	/* First, clear the existing chain */
-	SSL_CTX_get_extra_chain_certs(ctx, &orig_extra_chain);
-	if (orig_extra_chain && sk_X509_num(orig_extra_chain)) {
-	    rb_warning("SSL_CTX_set0_chain() is not available; " \
-		       "clearing previously set certificate chain");
-	    SSL_CTX_clear_extra_chain_certs(ctx);
-	}
-	while ((x509_tmp = sk_X509_shift(extra_chain))) {
-	    /* Transfers ownership */
-	    if (!SSL_CTX_add_extra_chain_cert(ctx, x509_tmp)) {
-		X509_free(x509_tmp);
-		sk_X509_pop_free(extra_chain, X509_free);
-		ossl_raise(eSSLError, "SSL_CTX_add_extra_chain_cert");
-	    }
-	}
-	sk_X509_free(extra_chain);
-#endif
+    if (extra_chain && !SSL_CTX_set0_chain(ctx, extra_chain)) {
+        sk_X509_pop_free(extra_chain, X509_free);
+        ossl_raise(eSSLError, "SSL_CTX_set0_chain");
     }
     return self;
 }
@@ -1522,8 +1389,8 @@
 static inline int
 ssl_started(SSL *ssl)
 {
-    /* the FD is set in ossl_ssl_setup(), called by #connect or #accept */
-    return SSL_get_fd(ssl) >= 0;
+    /* BIO is created through ossl_ssl_setup(), called by #connect or #accept */
+    return SSL_get_rbio(ssl) != NULL;
 }
 
 static void
@@ -1546,6 +1413,29 @@
     return TypedData_Wrap_Struct(klass, &ossl_ssl_type, NULL);
 }
 
+static VALUE
+peer_ip_address(VALUE self)
+{
+    VALUE remote_address = rb_funcall(rb_attr_get(self, id_i_io), rb_intern("remote_address"), 0);
+    
+    return rb_funcall(remote_address, rb_intern("inspect_sockaddr"), 0);
+}
+
+static VALUE
+fallback_peer_ip_address(VALUE self, VALUE args)
+{
+    return rb_str_new_cstr("(null)");
+}
+
+static VALUE
+peeraddr_ip_str(VALUE self)
+{
+    VALUE rb_mErrno = rb_const_get(rb_cObject, rb_intern("Errno"));
+    VALUE rb_eSystemCallError = rb_const_get(rb_mErrno, rb_intern("SystemCallError"));
+
+    return rb_rescue2(peer_ip_address, self, fallback_peer_ip_address, (VALUE)0, rb_eSystemCallError, NULL);
+}
+
 /*
  * call-seq:
  *    SSLSocket.new(io) => aSSLSocket
@@ -1691,8 +1581,15 @@
             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));
+	    ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s",
+                funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl));
+
 #if defined(SSL_R_CERTIFICATE_VERIFY_FAILED)
 	case SSL_ERROR_SSL:
 	    err = ERR_peek_last_error();
@@ -1705,13 +1602,14 @@
 		if (!verify_msg)
 		    verify_msg = "(null)";
 		ossl_clear_error(); /* let ossl_raise() not append message */
-		ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s: %s (%s)",
-			   funcname, ret2, errno, SSL_state_string_long(ssl),
+		ossl_raise(eSSLError, "%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s: %s (%s)",
+			   funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl),
 			   err_msg, verify_msg);
 	    }
 #endif
 	default:
-	    ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl));
+	    ossl_raise(eSSLError, "%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s",
+                funcname, ret2, errno, peeraddr_ip_str(self), SSL_state_string_long(ssl));
 	}
     }
 
@@ -1982,6 +1880,16 @@
                 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");
@@ -2410,7 +2318,6 @@
 }
 # endif
 
-# ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
 /*
  * call-seq:
  *    ssl.alpn_protocol => String | nil
@@ -2433,9 +2340,7 @@
     else
 	return rb_str_new((const char *) out, outlen);
 }
-# endif
 
-# ifdef HAVE_SSL_GET_SERVER_TMP_KEY
 /*
  * call-seq:
  *    ssl.tmp_key => PKey or nil
@@ -2453,7 +2358,6 @@
 	return Qnil;
     return ossl_pkey_new(key);
 }
-# endif /* defined(HAVE_SSL_GET_SERVER_TMP_KEY) */
 #endif /* !defined(OPENSSL_NO_SOCK) */
 
 void
@@ -2478,11 +2382,6 @@
     ossl_sslctx_ex_ptr_idx = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_ptr_idx", 0, 0, 0);
     if (ossl_sslctx_ex_ptr_idx < 0)
 	ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
-#if !defined(HAVE_X509_STORE_UP_REF)
-    ossl_sslctx_ex_store_p = SSL_CTX_get_ex_new_index(0, (void *)"ossl_sslctx_ex_store_p", 0, 0, 0);
-    if (ossl_sslctx_ex_store_p < 0)
-	ossl_raise(rb_eRuntimeError, "SSL_CTX_get_ex_new_index");
-#endif
 
     /* Document-module: OpenSSL::SSL
      *
@@ -2630,20 +2529,6 @@
      */
     rb_attr(cSSLContext, rb_intern_const("client_cert_cb"), 1, 1, Qfalse);
 
-#if !defined(OPENSSL_NO_EC) && defined(HAVE_SSL_CTX_SET_TMP_ECDH_CALLBACK)
-    /*
-     * A callback invoked when ECDH parameters are required.
-     *
-     * The callback is invoked with the Session for the key exchange, an
-     * flag indicating the use of an export cipher and the keylength
-     * required.
-     *
-     * The callback is deprecated. This does not work with recent versions of
-     * OpenSSL. Use OpenSSL::SSL::SSLContext#ecdh_curves= instead.
-     */
-    rb_attr(cSSLContext, rb_intern_const("tmp_ecdh_callback"), 1, 1, Qfalse);
-#endif
-
     /*
      * Sets the context in which a session can be reused.  This allows
      * sessions for multiple applications to be distinguished, for example, by
@@ -2733,7 +2618,6 @@
     rb_attr(cSSLContext, rb_intern_const("npn_select_cb"), 1, 1, Qfalse);
 #endif
 
-#ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
     /*
      * An Enumerable of Strings. Each String represents a protocol to be
      * advertised as the list of supported protocols for Application-Layer
@@ -2763,7 +2647,6 @@
      *   end
      */
     rb_attr(cSSLContext, rb_intern_const("alpn_select_cb"), 1, 1, Qfalse);
-#endif
 
     rb_define_alias(cSSLContext, "ssl_timeout", "timeout");
     rb_define_alias(cSSLContext, "ssl_timeout=", "timeout=");
@@ -2877,12 +2760,8 @@
     rb_define_method(cSSLSocket, "hostname=", ossl_ssl_set_hostname, 1);
     rb_define_method(cSSLSocket, "finished_message", ossl_ssl_get_finished, 0);
     rb_define_method(cSSLSocket, "peer_finished_message", ossl_ssl_get_peer_finished, 0);
-# ifdef HAVE_SSL_GET_SERVER_TMP_KEY
     rb_define_method(cSSLSocket, "tmp_key", ossl_ssl_tmp_key, 0);
-# endif
-# ifdef HAVE_SSL_CTX_SET_ALPN_SELECT_CB
     rb_define_method(cSSLSocket, "alpn_protocol", ossl_ssl_alpn_protocol, 0);
-# endif
 # ifndef OPENSSL_NO_NEXTPROTONEG
     rb_define_method(cSSLSocket, "npn_protocol", ossl_ssl_npn_protocol, 0);
 # endif
@@ -2895,12 +2774,8 @@
 
     rb_define_const(mSSL, "OP_ALL", ULONG2NUM(SSL_OP_ALL));
     rb_define_const(mSSL, "OP_LEGACY_SERVER_CONNECT", ULONG2NUM(SSL_OP_LEGACY_SERVER_CONNECT));
-#ifdef SSL_OP_TLSEXT_PADDING /* OpenSSL 1.0.1h and OpenSSL 1.0.2 */
     rb_define_const(mSSL, "OP_TLSEXT_PADDING", ULONG2NUM(SSL_OP_TLSEXT_PADDING));
-#endif
-#ifdef SSL_OP_SAFARI_ECDHE_ECDSA_BUG /* OpenSSL 1.0.1f and OpenSSL 1.0.2 */
     rb_define_const(mSSL, "OP_SAFARI_ECDHE_ECDSA_BUG", ULONG2NUM(SSL_OP_SAFARI_ECDHE_ECDSA_BUG));
-#endif
 #ifdef SSL_OP_ALLOW_NO_DHE_KEX /* OpenSSL 1.1.1 */
     rb_define_const(mSSL, "OP_ALLOW_NO_DHE_KEX", ULONG2NUM(SSL_OP_ALLOW_NO_DHE_KEX));
 #endif
@@ -2995,7 +2870,6 @@
     sym_wait_writable = ID2SYM(rb_intern_const("wait_writable"));
 
     id_tmp_dh_callback = rb_intern_const("tmp_dh_callback");
-    id_tmp_ecdh_callback = rb_intern_const("tmp_ecdh_callback");
     id_npn_protocols_encoded = rb_intern_const("npn_protocols_encoded");
 
 #define DefIVarID(name) do \
@@ -3013,7 +2887,6 @@
     DefIVarID(key);
     DefIVarID(extra_chain_cert);
     DefIVarID(client_cert_cb);
-    DefIVarID(tmp_ecdh_callback);
     DefIVarID(timeout);
     DefIVarID(session_id_context);
     DefIVarID(session_get_cb);
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_ssl_session.c ruby-3.0.2/ext/openssl/ossl_ssl_session.c
--- ruby-3.0.2.orig/ext/openssl/ossl_ssl_session.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_ssl_session.c	2021-09-09 18:27:58.355594327 +0800
@@ -34,43 +34,38 @@
  * Creates a new Session object from an instance of SSLSocket or DER/PEM encoded
  * String.
  */
-static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1)
+static VALUE
+ossl_ssl_session_initialize(VALUE self, VALUE arg1)
 {
-	SSL_SESSION *ctx = NULL;
-
-	if (RDATA(self)->data)
-		ossl_raise(eSSLSession, "SSL Session already initialized");
-
-	if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
-		SSL *ssl;
-
-		GetSSL(arg1, ssl);
-
-		if ((ctx = SSL_get1_session(ssl)) == NULL)
-			ossl_raise(eSSLSession, "no session available");
-	} else {
-		BIO *in = ossl_obj2bio(&arg1);
-
-		ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
-
-		if (!ctx) {
-		        OSSL_BIO_reset(in);
-			ctx = d2i_SSL_SESSION_bio(in, NULL);
-		}
+    SSL_SESSION *ctx;
 
-		BIO_free(in);
+    if (RTYPEDDATA_DATA(self))
+        ossl_raise(eSSLSession, "SSL Session already initialized");
 
-		if (!ctx)
-			ossl_raise(rb_eArgError, "unknown type");
-	}
+    if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
+        SSL *ssl;
 
-	/* should not happen */
-	if (ctx == NULL)
-		ossl_raise(eSSLSession, "ctx not set - internal error");
+        GetSSL(arg1, ssl);
+
+        if ((ctx = SSL_get1_session(ssl)) == NULL)
+            ossl_raise(eSSLSession, "no session available");
+    }
+    else {
+        BIO *in = ossl_obj2bio(&arg1);
+
+        ctx = d2i_SSL_SESSION_bio(in, NULL);
+        if (!ctx) {
+            OSSL_BIO_reset(in);
+            ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
+        }
+        BIO_free(in);
+        if (!ctx)
+            ossl_raise(rb_eArgError, "unknown type");
+    }
 
-	RDATA(self)->data = ctx;
+    RTYPEDDATA_DATA(self) = ctx;
 
-	return self;
+    return self;
 }
 
 static VALUE
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_ts.c ruby-3.0.2/ext/openssl/ossl_ts.c
--- ruby-3.0.2.orig/ext/openssl/ossl_ts.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_ts.c	2021-09-09 18:27:58.355594327 +0800
@@ -816,17 +816,14 @@
         X509_up_ref(cert);
     }
 
-    TS_VERIFY_CTS_set_certs(ctx, x509inter);
+    TS_VERIFY_CTX_set_certs(ctx, x509inter);
     TS_VERIFY_CTX_add_flags(ctx, TS_VFY_SIGNATURE);
     TS_VERIFY_CTX_set_store(ctx, x509st);
 
     ok = TS_RESP_verify_response(ctx, resp);
-
-    /* WORKAROUND:
-     *   X509_STORE can count references, but X509_STORE_free() doesn't check
-     *   this. To prevent our X509_STORE from being freed with our
-     *   TS_VERIFY_CTX we set the store to NULL first.
-     *   Fixed in OpenSSL 1.0.2; bff9ce4db38b (master), 5b4b9ce976fc (1.0.2)
+    /*
+     * TS_VERIFY_CTX_set_store() call above does not increment the reference
+     * counter, so it must be unset before TS_VERIFY_CTX_free() is called.
      */
     TS_VERIFY_CTX_set_store(ctx, NULL);
     TS_VERIFY_CTX_free(ctx);
@@ -1280,7 +1277,7 @@
      * ===Create a Response:
      *      #Assumes ts.p12 is a PKCS#12-compatible file with a private key
      *      #and a certificate that has an extended key usage of 'timeStamping'
-     *      p12 = OpenSSL::PKCS12.new(File.open('ts.p12', 'rb'), 'pwd')
+     *      p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd')
      *      md = OpenSSL::Digest.new('SHA1')
      *      hash = md.digest(data) #some binary data to be timestamped
      *      req = OpenSSL::Timestamp::Request.new
@@ -1295,16 +1292,16 @@
      *
      * ===Verify a timestamp response:
      *      #Assume we have a timestamp token in a file called ts.der
-     *      ts = OpenSSL::Timestamp::Response.new(File.open('ts.der', 'rb')
+     *      ts = OpenSSL::Timestamp::Response.new(File.binread('ts.der'))
      *      #Assume we have the Request for this token in a file called req.der
-     *      req = OpenSSL::Timestamp::Request.new(File.open('req.der', 'rb')
+     *      req = OpenSSL::Timestamp::Request.new(File.binread('req.der'))
      *      # Assume the associated root CA certificate is contained in a
      *      # DER-encoded file named root.cer
-     *      root = OpenSSL::X509::Certificate.new(File.open('root.cer', 'rb')
+     *      root = OpenSSL::X509::Certificate.new(File.binread('root.cer'))
      *      # get the necessary intermediate certificates, available in
      *      # DER-encoded form in inter1.cer and inter2.cer
-     *      inter1 = OpenSSL::X509::Certificate.new(File.open('inter1.cer', 'rb')
-     *      inter2 = OpenSSL::X509::Certificate.new(File.open('inter2.cer', 'rb')
+     *      inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer'))
+     *      inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer'))
      *      ts.verify(req, root, inter1, inter2) -> ts or raises an exception if validation fails
      *
      */
@@ -1437,9 +1434,9 @@
      * timestamping certificate.
      *
      *      req = OpenSSL::Timestamp::Request.new(raw_bytes)
-     *      p12 = OpenSSL::PKCS12.new(File.open('ts.p12', 'rb'), 'pwd')
-     *      inter1 = OpenSSL::X509::Certificate.new(File.open('inter1.cer', 'rb')
-     *      inter2 = OpenSSL::X509::Certificate.new(File.open('inter2.cer', 'rb')
+     *      p12 = OpenSSL::PKCS12.new(File.binread('ts.p12'), 'pwd')
+     *      inter1 = OpenSSL::X509::Certificate.new(File.binread('inter1.cer'))
+     *      inter2 = OpenSSL::X509::Certificate.new(File.binread('inter2.cer'))
      *      fac = OpenSSL::Timestamp::Factory.new
      *      fac.gen_time = Time.now
      *      fac.serial_number = 1
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_x509.c ruby-3.0.2/ext/openssl/ossl_x509.c
--- ruby-3.0.2.orig/ext/openssl/ossl_x509.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_x509.c	2021-09-09 18:27:58.355594327 +0800
@@ -115,11 +115,9 @@
     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
@@ -187,12 +185,10 @@
     /* Set by Store#flags= and StoreContext#flags=. Enables checking of the
      * signature of the root self-signed CA. */
     DefX509Const(V_FLAG_CHECK_SS_SIGNATURE);
-#if defined(X509_V_FLAG_TRUSTED_FIRST)
     /* Set by Store#flags= and StoreContext#flags=. When constructing a
      * certificate chain, search the Store first for the issuer certificate.
      * 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. */
@@ -208,11 +204,9 @@
      * 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 --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_x509cert.c ruby-3.0.2/ext/openssl/ossl_x509cert.c
--- ruby-3.0.2.orig/ext/openssl/ossl_x509cert.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_x509cert.c	2021-09-09 18:27:58.355594327 +0800
@@ -115,24 +115,27 @@
 ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
 {
     BIO *in;
-    X509 *x509, *x = DATA_PTR(self);
+    X509 *x509, *x509_orig = RTYPEDDATA_DATA(self);
     VALUE arg;
 
+    rb_check_frozen(self);
     if (rb_scan_args(argc, argv, "01", &arg) == 0) {
 	/* create just empty X509Cert */
 	return self;
     }
     arg = ossl_to_der_if_possible(arg);
     in = ossl_obj2bio(&arg);
-    x509 = PEM_read_bio_X509(in, &x, NULL, NULL);
-    DATA_PTR(self) = x;
+    x509 = d2i_X509_bio(in, NULL);
     if (!x509) {
-	OSSL_BIO_reset(in);
-	x509 = d2i_X509_bio(in, &x);
-	DATA_PTR(self) = x;
+        OSSL_BIO_reset(in);
+        x509 = PEM_read_bio_X509(in, NULL, NULL, NULL);
     }
     BIO_free(in);
-    if (!x509) ossl_raise(eX509CertError, NULL);
+    if (!x509)
+        ossl_raise(eX509CertError, "PEM_read_bio_X509");
+
+    RTYPEDDATA_DATA(self) = x509;
+    X509_free(x509_orig);
 
     return self;
 }
@@ -704,6 +707,157 @@
     return !X509_cmp(a, b) ? Qtrue : Qfalse;
 }
 
+struct load_chained_certificates_arguments {
+    VALUE certificates;
+    X509 *certificate;
+};
+
+static VALUE
+load_chained_certificates_append_push(VALUE _arguments) {
+    struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments;
+
+    if (arguments->certificates == Qnil) {
+        arguments->certificates = rb_ary_new();
+    }
+
+    rb_ary_push(arguments->certificates, ossl_x509_new(arguments->certificate));
+
+    return Qnil;
+}
+
+static VALUE
+load_chained_certificate_append_ensure(VALUE _arguments) {
+    struct load_chained_certificates_arguments *arguments = (struct load_chained_certificates_arguments*)_arguments;
+
+    X509_free(arguments->certificate);
+
+    return Qnil;
+}
+
+inline static VALUE
+load_chained_certificates_append(VALUE certificates, X509 *certificate) {
+    struct load_chained_certificates_arguments arguments;
+    arguments.certificates = certificates;
+    arguments.certificate = certificate;
+
+    rb_ensure(load_chained_certificates_append_push, (VALUE)&arguments, load_chained_certificate_append_ensure, (VALUE)&arguments);
+    
+    return arguments.certificates;
+}
+
+static VALUE
+load_chained_certificates_PEM(BIO *in) {
+    VALUE certificates = Qnil;
+    X509 *certificate = PEM_read_bio_X509(in, NULL, NULL, NULL);
+
+    /* If we cannot read even one certificate: */
+    if (certificate == NULL) {
+        /* If we cannot read one certificate because we could not read the PEM encoding: */
+        if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
+            ossl_clear_error();
+        }
+
+        if (ERR_peek_last_error())
+            ossl_raise(eX509CertError, NULL);
+        else
+            return Qnil;
+    }
+
+    certificates = load_chained_certificates_append(Qnil, certificate);
+
+    while ((certificate = PEM_read_bio_X509(in, NULL, NULL, NULL))) {
+      load_chained_certificates_append(certificates, certificate);
+    }
+
+    /* We tried to read one more certificate but could not read start line: */
+    if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
+        /* This is not an error, it means we are finished: */
+        ossl_clear_error();
+
+        return certificates;
+    }
+
+    /* Alternatively, if we reached the end of the file and there was no error: */
+    if (BIO_eof(in) && !ERR_peek_last_error()) {
+        return certificates;
+    } else {
+        /* Otherwise, we tried to read a certificate but failed somewhere: */
+        ossl_raise(eX509CertError, NULL);
+    }
+}
+
+static VALUE
+load_chained_certificates_DER(BIO *in) {
+    X509 *certificate = d2i_X509_bio(in, NULL);
+
+    /* If we cannot read one certificate: */
+    if (certificate == NULL) {
+        /* Ignore error. We could not load. */
+        ossl_clear_error();
+
+        return Qnil;
+    }
+
+    return load_chained_certificates_append(Qnil, certificate);
+}
+
+static VALUE
+load_chained_certificates(VALUE _io) {
+    BIO *in = (BIO*)_io;
+    VALUE certificates = Qnil;
+
+    /*
+      DER is a binary format and it may contain octets within it that look like
+      PEM encoded certificates. So we need to check DER first.
+    */
+    certificates = load_chained_certificates_DER(in);
+
+    if (certificates != Qnil)
+        return certificates;
+
+    OSSL_BIO_reset(in);
+
+    certificates = load_chained_certificates_PEM(in);
+
+    if (certificates != Qnil)
+        return certificates;
+
+    /* Otherwise we couldn't read the output correctly so fail: */
+    ossl_raise(eX509CertError, "Could not detect format of certificate data!");
+}
+
+static VALUE
+load_chained_certificates_ensure(VALUE _io) {
+    BIO *in = (BIO*)_io;
+
+    BIO_free(in);
+
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::X509::Certificate.load(string) -> [certs...]
+ *    OpenSSL::X509::Certificate.load(file) -> [certs...]
+ *
+ * Read the chained certificates from the given input. Supports both PEM
+ * and DER encoded certificates.
+ *
+ * PEM is a text format and supports more than one certificate.
+ *
+ * DER is a binary format and only supports one certificate.
+ *
+ * If the file is empty, or contains only unrelated data, an
+ * +OpenSSL::X509::CertificateError+ exception will be raised.
+ */
+static VALUE
+ossl_x509_load(VALUE klass, VALUE buffer)
+{
+    BIO *in = ossl_obj2bio(&buffer);
+
+    return rb_ensure(load_chained_certificates, (VALUE)in, load_chained_certificates_ensure, (VALUE)in);
+}
+
 /*
  * INIT
  */
@@ -730,7 +884,7 @@
      * Certificate is capable of handling DER-encoded certificates and
      * certificates encoded in OpenSSL's PEM format.
      *
-     *   raw = File.read "cert.cer" # DER- or PEM-encoded
+     *   raw = File.binread "cert.cer" # DER- or PEM-encoded
      *   certificate = OpenSSL::X509::Certificate.new raw
      *
      * === Saving a certificate to a file
@@ -812,6 +966,8 @@
      */
     cX509Cert = rb_define_class_under(mX509, "Certificate", rb_cObject);
 
+    rb_define_singleton_method(cX509Cert, "load", ossl_x509_load, 1);
+
     rb_define_alloc_func(cX509Cert, ossl_x509_alloc);
     rb_define_method(cX509Cert, "initialize", ossl_x509_initialize, -1);
     rb_define_method(cX509Cert, "initialize_copy", ossl_x509_copy, 1);
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_x509crl.c ruby-3.0.2/ext/openssl/ossl_x509crl.c
--- ruby-3.0.2.orig/ext/openssl/ossl_x509crl.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_x509crl.c	2021-09-09 18:27:58.355594327 +0800
@@ -93,23 +93,26 @@
 ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
 {
     BIO *in;
-    X509_CRL *crl, *x = DATA_PTR(self);
+    X509_CRL *crl, *crl_orig = RTYPEDDATA_DATA(self);
     VALUE arg;
 
+    rb_check_frozen(self);
     if (rb_scan_args(argc, argv, "01", &arg) == 0) {
 	return self;
     }
     arg = ossl_to_der_if_possible(arg);
     in = ossl_obj2bio(&arg);
-    crl = PEM_read_bio_X509_CRL(in, &x, NULL, NULL);
-    DATA_PTR(self) = x;
+    crl = d2i_X509_CRL_bio(in, NULL);
     if (!crl) {
-	OSSL_BIO_reset(in);
-	crl = d2i_X509_CRL_bio(in, &x);
-	DATA_PTR(self) = x;
+        OSSL_BIO_reset(in);
+        crl = PEM_read_bio_X509_CRL(in, NULL, NULL, NULL);
     }
     BIO_free(in);
-    if (!crl) ossl_raise(eX509CRLError, NULL);
+    if (!crl)
+        ossl_raise(eX509CRLError, "PEM_read_bio_X509_CRL");
+
+    RTYPEDDATA_DATA(self) = crl;
+    X509_CRL_free(crl_orig);
 
     return self;
 }
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_x509ext.c ruby-3.0.2/ext/openssl/ossl_x509ext.c
--- ruby-3.0.2.orig/ext/openssl/ossl_x509ext.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_x509ext.c	2021-09-09 18:27:58.355594327 +0800
@@ -226,11 +226,10 @@
     GetX509ExtFactory(self, ctx);
     obj = NewX509Ext(cX509Ext);
     rconf = rb_iv_get(self, "@config");
-    conf = NIL_P(rconf) ? NULL : DupConfigPtr(rconf);
+    conf = NIL_P(rconf) ? NULL : GetConfig(rconf);
     X509V3_set_nconf(ctx, conf);
     ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr));
     X509V3_set_ctx_nodb(ctx);
-    NCONF_free(conf);
     if (!ext){
 	ossl_raise(eX509ExtError, "%"PRIsVALUE" = %"PRIsVALUE, oid, valstr);
     }
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_x509req.c ruby-3.0.2/ext/openssl/ossl_x509req.c
--- ruby-3.0.2.orig/ext/openssl/ossl_x509req.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_x509req.c	2021-09-09 18:27:58.355594327 +0800
@@ -79,23 +79,26 @@
 ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
 {
     BIO *in;
-    X509_REQ *req, *x = DATA_PTR(self);
+    X509_REQ *req, *req_orig = RTYPEDDATA_DATA(self);
     VALUE arg;
 
+    rb_check_frozen(self);
     if (rb_scan_args(argc, argv, "01", &arg) == 0) {
 	return self;
     }
     arg = ossl_to_der_if_possible(arg);
     in = ossl_obj2bio(&arg);
-    req = PEM_read_bio_X509_REQ(in, &x, NULL, NULL);
-    DATA_PTR(self) = x;
+    req = d2i_X509_REQ_bio(in, NULL);
     if (!req) {
-	OSSL_BIO_reset(in);
-	req = d2i_X509_REQ_bio(in, &x);
-	DATA_PTR(self) = x;
+        OSSL_BIO_reset(in);
+        req = PEM_read_bio_X509_REQ(in, NULL, NULL, NULL);
     }
     BIO_free(in);
-    if (!req) ossl_raise(eX509ReqError, NULL);
+    if (!req)
+        ossl_raise(eX509ReqError, "PEM_read_bio_X509_REQ");
+
+    RTYPEDDATA_DATA(self) = req;
+    X509_REQ_free(req_orig);
 
     return self;
 }
diff --color -Nuar ruby-3.0.2.orig/ext/openssl/ossl_x509store.c ruby-3.0.2/ext/openssl/ossl_x509store.c
--- ruby-3.0.2.orig/ext/openssl/ossl_x509store.c	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/ext/openssl/ossl_x509store.c	2021-09-09 18:27:58.355594327 +0800
@@ -157,9 +157,8 @@
     VALUE obj;
 
     obj = NewX509Store(klass);
-    if((store = X509_STORE_new()) == NULL){
-        ossl_raise(eX509StoreError, NULL);
-    }
+    if ((store = X509_STORE_new()) == NULL)
+        ossl_raise(eX509StoreError, "X509_STORE_new");
     SetX509Store(obj, store);
 
     return obj;
@@ -192,8 +191,9 @@
 {
     X509_STORE *store;
 
-/* BUG: This method takes any number of arguments but appears to ignore them. */
     GetX509Store(self, store);
+    if (argc != 0)
+        rb_warn("OpenSSL::X509::Store.new does not take any arguments");
 #if !defined(HAVE_OPAQUE_OPENSSL)
     /* [Bug #405] [Bug #1678] [Bug #3000]; already fixed? */
     store->ex_data.sk = NULL;
@@ -214,8 +214,16 @@
  * call-seq:
  *   store.flags = flags
  *
- * Sets _flags_ to the Store. _flags_ consists of zero or more of the constants
- * defined in with name V_FLAG_* or'ed together.
+ * Sets the default flags used by certificate chain verification performed with
+ * the Store.
+ *
+ * _flags_ consists of zero or more of the constants defined in OpenSSL::X509
+ * with name V_FLAG_* or'ed together.
+ *
+ * OpenSSL::X509::StoreContext#flags= can be used to change the flags for a
+ * single verification operation.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_flags(3).
  */
 static VALUE
 ossl_x509store_set_flags(VALUE self, VALUE flags)
@@ -233,9 +241,9 @@
  * call-seq:
  *   store.purpose = purpose
  *
- * Sets the store's purpose to _purpose_. If specified, the verifications on
- * the store will check every untrusted certificate's extensions are consistent
- * with the purpose. The purpose is specified by constants:
+ * Sets the store's default verification purpose. If specified,
+ * the verifications on the store will check every certificate's extensions are
+ * consistent with the purpose. The purpose is specified by constants:
  *
  * * X509::PURPOSE_SSL_CLIENT
  * * X509::PURPOSE_SSL_SERVER
@@ -246,6 +254,11 @@
  * * X509::PURPOSE_ANY
  * * X509::PURPOSE_OCSP_HELPER
  * * X509::PURPOSE_TIMESTAMP_SIGN
+ *
+ * OpenSSL::X509::StoreContext#purpose= can be used to change the value for a
+ * single verification operation.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_purpose(3).
  */
 static VALUE
 ossl_x509store_set_purpose(VALUE self, VALUE purpose)
@@ -262,6 +275,14 @@
 /*
  * call-seq:
  *   store.trust = trust
+ *
+ * Sets the default trust settings used by the certificate verification with
+ * the store.
+ *
+ * OpenSSL::X509::StoreContext#trust= can be used to change the value for a
+ * single verification operation.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_trust(3).
  */
 static VALUE
 ossl_x509store_set_trust(VALUE self, VALUE trust)
@@ -279,7 +300,13 @@
  * call-seq:
  *   store.time = time
  *
- * Sets the time to be used in verifications.
+ * Sets the time to be used in the certificate verifications with the store.
+ * By default, if not specified, the current system time is used.
+ *
+ * OpenSSL::X509::StoreContext#time= can be used to change the value for a
+ * single verification operation.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_time(3).
  */
 static VALUE
 ossl_x509store_set_time(VALUE self, VALUE time)
@@ -295,23 +322,23 @@
  * Adds the certificates in _file_ to the certificate store. _file_ is the path
  * to the file, and the file contains one or more certificates in PEM format
  * concatenated together.
+ *
+ * See also the man page X509_LOOKUP_file(3).
  */
 static VALUE
 ossl_x509store_add_file(VALUE self, VALUE file)
 {
     X509_STORE *store;
     X509_LOOKUP *lookup;
-    char *path = NULL;
+    const char *path;
 
-    if(file != Qnil){
-	path = StringValueCStr(file);
-    }
     GetX509Store(self, store);
+    path = StringValueCStr(file);
     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
-    if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
-    if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){
-        ossl_raise(eX509StoreError, NULL);
-    }
+    if (!lookup)
+        ossl_raise(eX509StoreError, "X509_STORE_add_lookup");
+    if (X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1)
+        ossl_raise(eX509StoreError, "X509_LOOKUP_load_file");
 #if OPENSSL_VERSION_NUMBER < 0x10101000 || defined(LIBRESSL_VERSION_NUMBER)
     /*
      * X509_load_cert_crl_file() which is called from X509_LOOKUP_load_file()
@@ -330,23 +357,23 @@
  *   store.add_path(path) -> self
  *
  * Adds _path_ as the hash dir to be looked up by the store.
+ *
+ * See also the man page X509_LOOKUP_hash_dir(3).
  */
 static VALUE
 ossl_x509store_add_path(VALUE self, VALUE dir)
 {
     X509_STORE *store;
     X509_LOOKUP *lookup;
-    char *path = NULL;
+    const char *path;
 
-    if(dir != Qnil){
-	path = StringValueCStr(dir);
-    }
     GetX509Store(self, store);
+    path = StringValueCStr(dir);
     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
-    if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
-    if(X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1){
-        ossl_raise(eX509StoreError, NULL);
-    }
+    if (!lookup)
+        ossl_raise(eX509StoreError, "X509_STORE_add_lookup");
+    if (X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1)
+        ossl_raise(eX509StoreError, "X509_LOOKUP_add_dir");
 
     return self;
 }
@@ -361,6 +388,8 @@
  *
  * * OpenSSL::X509::DEFAULT_CERT_FILE
  * * OpenSSL::X509::DEFAULT_CERT_DIR
+ *
+ * See also the man page X509_STORE_set_default_paths(3).
  */
 static VALUE
 ossl_x509store_set_default_paths(VALUE self)
@@ -368,18 +397,19 @@
     X509_STORE *store;
 
     GetX509Store(self, store);
-    if (X509_STORE_set_default_paths(store) != 1){
-        ossl_raise(eX509StoreError, NULL);
-    }
+    if (X509_STORE_set_default_paths(store) != 1)
+        ossl_raise(eX509StoreError, "X509_STORE_set_default_paths");
 
     return Qnil;
 }
 
 /*
  * call-seq:
- *   store.add_cert(cert)
+ *   store.add_cert(cert) -> self
  *
  * Adds the OpenSSL::X509::Certificate _cert_ to the certificate store.
+ *
+ * See also the man page X509_STORE_add_cert(3).
  */
 static VALUE
 ossl_x509store_add_cert(VALUE self, VALUE arg)
@@ -389,9 +419,8 @@
 
     cert = GetX509CertPtr(arg); /* NO NEED TO DUP */
     GetX509Store(self, store);
-    if (X509_STORE_add_cert(store, cert) != 1){
-        ossl_raise(eX509StoreError, NULL);
-    }
+    if (X509_STORE_add_cert(store, cert) != 1)
+        ossl_raise(eX509StoreError, "X509_STORE_add_cert");
 
     return self;
 }
@@ -401,6 +430,8 @@
  *   store.add_crl(crl) -> self
  *
  * Adds the OpenSSL::X509::CRL _crl_ to the store.
+ *
+ * See also the man page X509_STORE_add_crl(3).
  */
 static VALUE
 ossl_x509store_add_crl(VALUE self, VALUE arg)
@@ -410,9 +441,8 @@
 
     crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */
     GetX509Store(self, store);
-    if (X509_STORE_add_crl(store, crl) != 1){
-        ossl_raise(eX509StoreError, NULL);
-    }
+    if (X509_STORE_add_crl(store, crl) != 1)
+        ossl_raise(eX509StoreError, "X509_STORE_add_crl");
 
     return self;
 }
@@ -491,9 +521,8 @@
     VALUE obj;
 
     obj = NewX509StCtx(klass);
-    if((ctx = X509_STORE_CTX_new()) == NULL){
-        ossl_raise(eX509StoreError, NULL);
-    }
+    if ((ctx = X509_STORE_CTX_new()) == NULL)
+        ossl_raise(eX509StoreError, "X509_STORE_CTX_new");
     SetX509StCtx(obj, ctx);
 
     return obj;
@@ -517,7 +546,9 @@
 
 /*
  * 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 +558,24 @@
     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);
@@ -548,6 +588,10 @@
 /*
  * call-seq:
  *   stctx.verify -> true | false
+ *
+ * Performs the certificate verification using the parameters set to _stctx_.
+ *
+ * See also the man page X509_verify_cert(3).
  */
 static VALUE
 ossl_x509stctx_verify(VALUE self)
@@ -560,48 +604,45 @@
 
     switch (X509_verify_cert(ctx)) {
       case 1:
-	return Qtrue;
+        return Qtrue;
       case 0:
-	ossl_clear_error();
-	return Qfalse;
+        ossl_clear_error();
+        return Qfalse;
       default:
-	ossl_raise(eX509CertError, NULL);
+        ossl_raise(eX509CertError, "X509_verify_cert");
     }
 }
 
 /*
  * call-seq:
- *   stctx.chain -> Array of X509::Certificate
+ *   stctx.chain -> nil | Array of X509::Certificate
+ *
+ * Returns the verified chain.
+ *
+ * See also the man page X509_STORE_CTX_set0_verified_chain(3).
  */
 static VALUE
 ossl_x509stctx_get_chain(VALUE self)
 {
     X509_STORE_CTX *ctx;
-    STACK_OF(X509) *chain;
-    X509 *x509;
-    int i, num;
-    VALUE ary;
+    const STACK_OF(X509) *chain;
 
     GetX509StCtx(self, ctx);
-    if((chain = X509_STORE_CTX_get0_chain(ctx)) == NULL){
-        return Qnil;
-    }
-    if((num = sk_X509_num(chain)) < 0){
-	OSSL_Debug("certs in chain < 0???");
-	return rb_ary_new();
-    }
-    ary = rb_ary_new2(num);
-    for(i = 0; i < num; i++) {
-	x509 = sk_X509_value(chain, i);
-	rb_ary_push(ary, ossl_x509_new(x509));
-    }
-
-    return ary;
+    chain = X509_STORE_CTX_get0_chain(ctx);
+    if (!chain)
+        return Qnil; /* Could be an empty array instead? */
+    return ossl_x509_sk2ary(chain);
 }
 
 /*
  * call-seq:
  *   stctx.error -> Integer
+ *
+ * Returns the error code of _stctx_. This is typically called after #verify
+ * is done, or from the verification callback set to
+ * OpenSSL::X509::Store#verify_callback=.
+ *
+ * See also the man page X509_STORE_CTX_get_error(3).
  */
 static VALUE
 ossl_x509stctx_get_err(VALUE self)
@@ -616,6 +657,11 @@
 /*
  * call-seq:
  *   stctx.error = error_code
+ *
+ * Sets the error code of _stctx_. This is used by the verification callback
+ * set to OpenSSL::X509::Store#verify_callback=.
+ *
+ * See also the man page X509_STORE_CTX_set_error(3).
  */
 static VALUE
 ossl_x509stctx_set_error(VALUE self, VALUE err)
@@ -632,7 +678,10 @@
  * call-seq:
  *   stctx.error_string -> String
  *
- * Returns the error string corresponding to the error code retrieved by #error.
+ * Returns the human readable error string corresponding to the error code
+ * retrieved by #error.
+ *
+ * See also the man page X509_verify_cert_error_string(3).
  */
 static VALUE
 ossl_x509stctx_get_err_string(VALUE self)
@@ -649,6 +698,10 @@
 /*
  * call-seq:
  *   stctx.error_depth -> Integer
+ *
+ * Returns the depth of the chain. This is used in combination with #error.
+ *
+ * See also the man page X509_STORE_CTX_get_error_depth(3).
  */
 static VALUE
 ossl_x509stctx_get_err_depth(VALUE self)
@@ -663,6 +716,10 @@
 /*
  * call-seq:
  *   stctx.current_cert -> X509::Certificate
+ *
+ * Returns the certificate which caused the error.
+ *
+ * See also the man page X509_STORE_CTX_get_current_cert(3).
  */
 static VALUE
 ossl_x509stctx_get_curr_cert(VALUE self)
@@ -677,6 +734,10 @@
 /*
  * call-seq:
  *   stctx.current_crl -> X509::CRL
+ *
+ * Returns the CRL which caused the error.
+ *
+ * See also the man page X509_STORE_CTX_get_current_crl(3).
  */
 static VALUE
 ossl_x509stctx_get_curr_crl(VALUE self)
@@ -696,7 +757,10 @@
  * call-seq:
  *   stctx.flags = flags
  *
- * Sets the verification flags to the context. See Store#flags=.
+ * Sets the verification flags to the context. This overrides the default value
+ * set by Store#flags=.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_flags(3).
  */
 static VALUE
 ossl_x509stctx_set_flags(VALUE self, VALUE flags)
@@ -714,7 +778,10 @@
  * call-seq:
  *   stctx.purpose = purpose
  *
- * Sets the purpose of the context. See Store#purpose=.
+ * Sets the purpose of the context. This overrides the default value set by
+ * Store#purpose=.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_purpose(3).
  */
 static VALUE
 ossl_x509stctx_set_purpose(VALUE self, VALUE purpose)
@@ -731,6 +798,11 @@
 /*
  * call-seq:
  *   stctx.trust = trust
+ *
+ * Sets the trust settings of the context. This overrides the default value set
+ * by Store#trust=.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_trust(3).
  */
 static VALUE
 ossl_x509stctx_set_trust(VALUE self, VALUE trust)
@@ -749,6 +821,8 @@
  *   stctx.time = time
  *
  * Sets the time used in the verification. If not set, the current time is used.
+ *
+ * See also the man page X509_VERIFY_PARAM_set_time(3).
  */
 static VALUE
 ossl_x509stctx_set_time(VALUE self, VALUE time)
@@ -824,23 +898,37 @@
     cX509Store = rb_define_class_under(mX509, "Store", rb_cObject);
     /*
      * The callback for additional certificate verification. It is invoked for
-     * each untrusted certificate in the chain.
+     * each certificate in the chain and can be used to implement custom
+     * certificate verification conditions.
      *
      * The callback is invoked with two values, a boolean that indicates if the
      * pre-verification by OpenSSL has succeeded or not, and the StoreContext in
-     * use. The callback must return either true or false.
+     * use.
+     *
+     * The callback can use StoreContext#error= to change the error code as
+     * needed. The callback must return either true or false.
+     *
+     * NOTE: any exception raised within the callback will be ignored.
+     *
+     * See also the man page X509_STORE_CTX_set_verify_cb(3).
      */
     rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse);
     /*
      * The error code set by the last call of #verify.
+     *
+     * See also StoreContext#error.
      */
     rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse);
     /*
      * The description for the error code set by the last call of #verify.
+     *
+     * See also StoreContext#error_string.
      */
     rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse);
     /*
      * The certificate chain constructed by the last call of #verify.
+     *
+     * See also StoreContext#chain.
      */
     rb_attr(cX509Store, rb_intern("chain"), 1, 0, Qfalse);
     rb_define_alloc_func(cX509Store, ossl_x509store_alloc);
diff --color -Nuar ruby-3.0.2.orig/test/openssl/envutil.rb ruby-3.0.2/test/openssl/envutil.rb
--- ruby-3.0.2.orig/test/openssl/envutil.rb	1970-01-01 08:00:00.000000000 +0800
+++ ruby-3.0.2/test/openssl/envutil.rb	2021-09-09 18:29:40.442077897 +0800
@@ -0,0 +1,339 @@
+# -*- coding: us-ascii -*-
+require "timeout"
+require "rbconfig"
+require "pp"
+
+module EnvUtil
+  def rubybin
+    ENV["RUBY"] || RbConfig.ruby
+  end
+  module_function :rubybin
+
+  LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
+
+  def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false,
+                  encoding: nil, timeout: 10, reprieve: 1,
+                  stdout_filter: nil, stderr_filter: nil,
+                  rubybin: EnvUtil.rubybin,
+                  **opt)
+    in_c, in_p = IO.pipe
+    out_p, out_c = IO.pipe if capture_stdout
+    err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
+    opt[:in] = in_c
+    opt[:out] = out_c if capture_stdout
+    opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr
+    if encoding
+      out_p.set_encoding(encoding) if out_p
+      err_p.set_encoding(encoding) if err_p
+    end
+    c = "C"
+    child_env = {}
+    LANG_ENVS.each {|lc| child_env[lc] = c}
+    if Array === args and Hash === args.first
+      child_env.update(args.shift)
+    end
+    args = [args] if args.kind_of?(String)
+    pid = spawn(child_env, rubybin, *args, **opt)
+    in_c.close
+    out_c.close if capture_stdout
+    err_c.close if capture_stderr && capture_stderr != :merge_to_stdout
+    if block_given?
+      return yield in_p, out_p, err_p, pid
+    else
+      th_stdout = Thread.new { out_p.read } if capture_stdout
+      th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout
+      in_p.write stdin_data.to_str unless stdin_data.empty?
+      in_p.close
+      if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
+        stdout = th_stdout.value if capture_stdout
+        stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
+      else
+        signal = /mswin|mingw/ =~ RUBY_PLATFORM ? :KILL : :TERM
+        case pgroup = opt[:pgroup]
+        when 0, true
+          pgroup = -pid
+        when nil, false
+          pgroup = pid
+        end
+        begin
+          Process.kill signal, pgroup
+          Timeout.timeout((reprieve unless signal == :KILL)) do
+            Process.wait(pid)
+          end
+        rescue Errno::ESRCH
+          break
+        rescue Timeout::Error
+          raise if signal == :KILL
+          signal = :KILL
+        else
+          break
+        end while true
+        bt = caller_locations
+        raise Timeout::Error, "execution of #{bt.shift.label} expired", bt.map(&:to_s)
+      end
+      out_p.close if capture_stdout
+      err_p.close if capture_stderr && capture_stderr != :merge_to_stdout
+      Process.wait pid
+      status = $?
+      stdout = stdout_filter.call(stdout) if stdout_filter
+      stderr = stderr_filter.call(stderr) if stderr_filter
+      return stdout, stderr, status
+    end
+  ensure
+    [th_stdout, th_stderr].each do |th|
+      th.kill if th
+    end
+    [in_c, in_p, out_c, out_p, err_c, err_p].each do |io|
+      io.close if io && !io.closed?
+    end
+    [th_stdout, th_stderr].each do |th|
+      th.join if th
+    end
+  end
+  module_function :invoke_ruby
+
+  def verbose_warning
+    class << (stderr = "".dup)
+      alias write <<
+    end
+    stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
+    yield stderr
+    return $stderr
+  ensure
+    stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
+  end
+  module_function :verbose_warning
+
+  def suppress_warning
+    verbose, $VERBOSE = $VERBOSE, nil
+    yield
+  ensure
+    $VERBOSE = verbose
+  end
+  module_function :suppress_warning
+
+  if /darwin/ =~ RUBY_PLATFORM
+    DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports")
+    DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S'
+    def self.diagnostic_reports(signame, cmd, pid, now)
+      return unless %w[ABRT QUIT SEGV ILL].include?(signame)
+      cmd = File.basename(cmd)
+      path = DIAGNOSTIC_REPORTS_PATH
+      timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT
+      pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.crash"
+      first = true
+      30.times do
+        first ? (first = false) : sleep(0.1)
+        Dir.glob(pat) do |name|
+          log = File.read(name) rescue next
+          if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log
+            File.unlink(name)
+            File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil
+            return log
+          end
+        end
+      end
+      nil
+    end
+  else
+    def self.diagnostic_reports(signame, cmd, pid, now)
+    end
+  end
+end
+
+module Test
+  module Unit
+    module Assertions
+      FailDesc = proc do |status, message = "", out = ""|
+        pid = status.pid
+        now = Time.now
+        faildesc = proc do
+          if signo = status.termsig
+            signame = Signal.signame(signo)
+            sigdesc = "signal #{signo}"
+          end
+          log = EnvUtil.diagnostic_reports(signame, EnvUtil.rubybin, pid, now)
+          if signame
+            sigdesc = "SIG#{signame} (#{sigdesc})"
+          end
+          if status.coredump?
+            sigdesc << " (core dumped)"
+          end
+          full_message = ''
+          if message and !message.empty?
+            full_message << message << "\n"
+          end
+          full_message << "pid #{pid} killed by #{sigdesc}"
+          if out and !out.empty?
+            full_message << "\n#{out.gsub(/^/, '| ')}"
+            full_message << "\n" if /\n\z/ !~ full_message
+          end
+          if log
+            full_message << "\n#{log.gsub(/^/, '| ')}"
+          end
+          full_message
+        end
+        faildesc
+      end
+
+      ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV")
+
+      def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt)
+        unless file and line
+          loc, = caller_locations(1,1)
+          file ||= loc.path
+          line ||= loc.lineno
+        end
+        line -= 6 # lines until src
+        src = <<eom
+# -*- coding: #{src.encoding}; -*-
+  require 'test/unit';include Test::Unit::Assertions
+  END {
+    puts [Marshal.dump($!)].pack('m')#, "assertions=\#{self._assertions}"
+    exit
+  }
+  def pend(msg = nil) $stdout.syswrite [Marshal.dump(msg.to_s)].pack("m"); exit! 0 end
+#{src}
+  class Test::Unit::Runner
+    @@stop_auto_run = true
+  end
+eom
+        args = args.dup
+        args.insert((Hash === args.first ? 1 : 0), "--disable=gems", *$:.map {|l| "-I#{l}"})
+        stdout, stderr, status = EnvUtil.invoke_ruby(args, src, true, true, **opt)
+        abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig))
+        assert(!abort, FailDesc[status, nil, stderr])
+        #self._assertions += stdout[/^assertions=(\d+)/, 1].to_i
+        begin
+          res = Marshal.load(stdout.unpack("m")[0])
+        rescue => marshal_error
+          ignore_stderr = nil
+        end
+        if res.is_a?(String)
+          pend res
+        elsif res
+          if bt = res.backtrace
+            bt.each do |l|
+              l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"}
+            end
+            bt.concat(caller)
+          else
+            res.set_backtrace(caller)
+          end
+          raise res
+        end
+
+        # really is it succeed?
+        unless ignore_stderr
+          # the body of assert_separately must not output anything to detect error
+          assert_equal("", stderr, "assert_separately failed with error message")
+        end
+        assert_equal(0, status, "assert_separately failed: '#{stderr}'")
+        raise marshal_error if marshal_error
+      end
+
+      def assert_warning(pat, msg = nil)
+        stderr = EnvUtil.verbose_warning {
+          yield
+        }
+        if Regexp === pat
+          assert_match pat, stderr, msg
+        else
+          assert_equal pat, stderr, msg
+        end
+      end
+
+      def message msg = nil, ending = ".", &default
+        proc {
+          msg = msg.call.chomp(".") if Proc === msg
+          custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
+          "#{custom_message}#{default.call}#{ending}"
+        }
+      end
+
+      # threads should respond to shift method.
+      # Array can be used.
+      def assert_join_threads(threads, message = nil)
+        errs = []
+        values = []
+        while th = threads.shift
+          begin
+            values << th.value
+          rescue Exception
+            errs << [th, $!]
+          end
+        end
+        if !errs.empty?
+          msg = "exceptions on #{errs.length} threads:\n" +
+            errs.map {|t, err|
+            "#{t.inspect}:\n" +
+            err.backtrace.map.with_index {|line, i|
+              if i == 0
+                "#{line}: #{err.message} (#{err.class})"
+              else
+                "\tfrom #{line}"
+              end
+            }.join("\n")
+          }.join("\n---\n")
+          if message
+            msg = "#{message}\n#{msg}"
+          end
+          raise Test::Unit::AssertionFailedError, msg
+        end
+        values
+      end
+
+      def mu_pp(obj) #:nodoc:
+        obj.pretty_inspect.chomp
+      end
+
+      # :call-seq:
+      #   assert_raise_with_message(exception, expected, msg = nil, &block)
+      #
+      #Tests if the given block raises an exception with the expected
+      #message.
+      #
+      #    assert_raise_with_message(RuntimeError, "foo") do
+      #      nil #Fails, no Exceptions are raised
+      #    end
+      #
+      #    assert_raise_with_message(RuntimeError, "foo") do
+      #      raise ArgumentError, "foo" #Fails, different Exception is raised
+      #    end
+      #
+      #    assert_raise_with_message(RuntimeError, "foo") do
+      #      raise "bar" #Fails, RuntimeError is raised but the message differs
+      #    end
+      #
+      #    assert_raise_with_message(RuntimeError, "foo") do
+      #      raise "foo" #Raises RuntimeError with the message, so assertion succeeds
+      #    end
+      def assert_raise_with_message(exception, expected, msg = nil, &block)
+        case expected
+        when String
+          assert = :assert_equal
+        when Regexp
+          assert = :assert_match
+        else
+          raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}"
+        end
+
+        ex = m = nil
+        ex = assert_raise(exception, msg || "Exception(#{exception}) with message matches to #{expected.inspect}") do
+          yield
+        end
+        m = ex.message
+        msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"}
+
+        if assert == :assert_equal
+          assert_equal(expected, m, msg)
+        else
+          msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp m}" }
+          assert expected =~ m, msg
+          block.binding.eval("proc{|_|$~=_}").call($~)
+        end
+        ex
+      end
+    end
+  end
+end
diff --color -Nuar ruby-3.0.2.orig/test/openssl/fixtures/pkey/certificate.der ruby-3.0.2/test/openssl/fixtures/pkey/certificate.der
--- ruby-3.0.2.orig/test/openssl/fixtures/pkey/certificate.der	1970-01-01 08:00:00.000000000 +0800
+++ ruby-3.0.2/test/openssl/fixtures/pkey/certificate.der	2021-09-09 18:29:40.442077897 +0800
@@ -0,0 +1,8 @@
+0�)0��[)?�I}��k��xF�J0
	*�H��
0210	UUS10U
+
Let's Encrypt10	UR30
210417024319Z
210716024319Z010Uwww.codeotaku.com0�"0
	*�H��
�0�
+�Ǩy��ߒJ�alg����@±�e�>�cR�7�_��K<=}lf+�Ȑ((%"�|QR<�2�}�J�+n_��"W*h�PWE�&C�_��g�*B�ֈQ彭3
����,�V��<n�b�Y�~&�Wj2T@D9��v�Z��>$v�皠Y:��Y��j�Z�ό
*|����DG�eO!���=��zB��{�GPeK���{���Zp��)`���O����J�ʹr�YE����eCnV^��pwI���!π�)��M0�I0U��0U%0++0U�00Uʉ!���R m�=�Re�S�˹Y0U#0�.��XVˮP	@������0U+I0G0!+0�http://r3.o.lencr.org0"+0�http://r3.i.lencr.org/0U0�www.codeotaku.com0LU E0C0g�07+��0(0&+http://cps.letsencrypt.org0�
++�y�����w� ��Սl�s��",
��M^lO�=a�N/XM��x���XH0F!�XC��{|�x�Ɵ$T��.��O?=}��abq!�O�u�c���x~��Ű�_�j�u(6
+pFf
+v�\�/�w0"T0�V��M3��/ �N�d�x���NG0E!�w�~�f����rn�_y����7��T�J!兘 
&z���
*<�W�R )g��2#݄������0
	*�H��
�r!1���RŘ��q� ��D�S]i���ʛ���f�2���=Ӿ��}�M��uʆO����R�W>	�`�]�vgӲH.X��ROSR���]5`���
+B[���$��1)GBtS�L�;�-g.�x��!�>����-��X��;]�H����CA�o��L�kOU�݈�J�[{���o����BMY��ʹ�L�/�~����YxrW�i��_����)�N�!�"^��m �PTE��M�GU��
+�e�K��	
\ 文件尾没有换行符
diff --color -Nuar ruby-3.0.2.orig/test/openssl/fixtures/pkey/fullchain.pem ruby-3.0.2/test/openssl/fixtures/pkey/fullchain.pem
--- ruby-3.0.2.orig/test/openssl/fixtures/pkey/fullchain.pem	1970-01-01 08:00:00.000000000 +0800
+++ ruby-3.0.2/test/openssl/fixtures/pkey/fullchain.pem	2021-09-09 18:29:40.443077922 +0800
@@ -0,0 +1,56 @@
+-----BEGIN CERTIFICATE-----
+MIIFKTCCBBGgAwIBAgISBFspP+tJfRaC6xprreB4Rp9KMA0GCSqGSIb3DQEBCwUA
+MDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD
+EwJSMzAeFw0yMTA0MTcwMjQzMTlaFw0yMTA3MTYwMjQzMTlaMBwxGjAYBgNVBAMT
+EXd3dy5jb2Rlb3Rha3UuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAx6h5vNPfkkrtYWxn1PWDDLRAwrGmZbkYPttjHBRSwTcd7rsIX4PcSzw9fWxm
+K4vIkAYoKAElIvsSE3xRUjyzMrACfdhK5J8rG25fq94iVyoYaNBQV0WMJkO6X47s
+hGeIKkK91ohR5b2tMw3/z9zELP0TVo2TPG7rYsBZm34myldqDA8yVEBEOa+Qdpda
+9xewPhkkdpAU55qgWTrD21m7vGq9WpsBz4wNKnwVsaugtkRH82VPIfaL4ZI9kox6
+QoPWe/tHUBdlDkuT7ud77eLAWnC/5Clg28/9GU/Z8Nj8SrrKuXL6WUXmxxaAhWUR
+Qx4VblZeuIpwd0nHyP0hz4CWKQIDAQABo4ICTTCCAkkwDgYDVR0PAQH/BAQDAgWg
+MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0G
+A1UdDgQWBBTKiSGZuLFSIG2JPbFSZa9TxMu5WTAfBgNVHSMEGDAWgBQULrMXt1hW
+y65QCUDmH6+dixTCxjBVBggrBgEFBQcBAQRJMEcwIQYIKwYBBQUHMAGGFWh0dHA6
+Ly9yMy5vLmxlbmNyLm9yZzAiBggrBgEFBQcwAoYWaHR0cDovL3IzLmkubGVuY3Iu
+b3JnLzAcBgNVHREEFTATghF3d3cuY29kZW90YWt1LmNvbTBMBgNVHSAERTBDMAgG
+BmeBDAECATA3BgsrBgEEAYLfEwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3Bz
+LmxldHNlbmNyeXB0Lm9yZzCCAQUGCisGAQQB1nkCBAIEgfYEgfMA8QB3AJQgvB6O
+1Y1siHMfgosiLA3R2k1ebE+UPWHbTi9YTaLCAAABeN3s/lgAAAQDAEgwRgIhAKFY
+Q+vBe3zyeBazxp8kVN7oLvcQ6Y9PPz199tVhYnEbAiEAhU/xdbQaY/6b93h+7NTF
+sPG7X4lq/3UoNgoXcAVGZgoAdgD2XJQv0XcwIhRUGAgwlFaO400TGTO/3wwvIAvM
+TvFk4wAAAXjd7P5OAAAEAwBHMEUCIQDWd79+jWaGuf3acm5/yV95jL2KvzeGFfdU
+HZlKIeWFmAIgDSZ6ug7AyhYNKjzFV4ZSICln+L4yI92EpOa+8gDG6/0wDQYJKoZI
+hvcNAQELBQADggEBAHIhMYm06lLFmJL+cfIg5fFEmFNdHmmZn88Hypv4/MtmqTKv
+5asF/z3TvhW4hX2+TY+NdcqGT7cZFo/ZF/tS6oBXPgmBYM1dEfp2FAdnGNOySC5Y
+7RC4Uk9TUpP2g101YBmj6dQKQluAwIQk+gO4MSlHE0J0U/lMpjvrLWcuHbV4/xWJ
+IdM+iPq8GeYt5epYmNc7XeRIgv7V3RxDQdBv2OVM5mtPVerdiO0ISrdbe5mvz2+Z
+rhSg+EJNHlmMwcq5HqtMwS8M8Ax+vLmWCOkPWXhyV8wQaQcFjZJfpIGUvCnMTqsh
+kSIYXq2CbSDUUFRFssNN6EdVms0KnmW3BUu0xAk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEZTCCA02gAwIBAgIQQAF1BIMUpMghjISpDBbN3zANBgkqhkiG9w0BAQsFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTIwMTAwNzE5MjE0MFoXDTIxMDkyOTE5MjE0MFow
+MjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxCzAJBgNVBAMT
+AlIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuwIVKMz2oJTTDxLs
+jVWSw/iC8ZmmekKIp10mqrUrucVMsa+Oa/l1yKPXD0eUFFU1V4yeqKI5GfWCPEKp
+Tm71O8Mu243AsFzzWTjn7c9p8FoLG77AlCQlh/o3cbMT5xys4Zvv2+Q7RVJFlqnB
+U840yFLuta7tj95gcOKlVKu2bQ6XpUA0ayvTvGbrZjR8+muLj1cpmfgwF126cm/7
+gcWt0oZYPRfH5wm78Sv3htzB2nFd1EbjzK0lwYi8YGd1ZrPxGPeiXOZT/zqItkel
+/xMY6pgJdz+dU/nPAeX1pnAXFK9jpP+Zs5Od3FOnBv5IhR2haa4ldbsTzFID9e1R
+oYvbFQIDAQABo4IBaDCCAWQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8E
+BAMCAYYwSwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5p
+ZGVudHJ1c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTE
+p7Gkeyxx+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEE
+AYLfEwEBATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2Vu
+Y3J5cHQub3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0
+LmNvbS9EU1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYf
+r52LFMLGMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjANBgkqhkiG9w0B
+AQsFAAOCAQEA2UzgyfWEiDcx27sT4rP8i2tiEmxYt0l+PAK3qB8oYevO4C5z70kH
+ejWEHx2taPDY/laBL21/WKZuNTYQHHPD5b1tXgHXbnL7KqC401dk5VvCadTQsvd8
+S8MXjohyc9z9/G2948kLjmE6Flh9dDYrVYA9x2O+hEPGOaEOa1eePynBgPayvUfL
+qjBstzLhWVQLGAkXXmNs+5ZnPBxzDJOLxhF2JIbeQAcH5H0tZrUlo5ZYyOqA7s9p
+O5b85o3AM/OJ+CktFBQtfvBhcJVd9wvlwPsk+uyOy2HI7mNxKKgsBTt375teA2Tw
+UdHkhVNcsAKX1H7GNNLOEADksd86wuoXvg==
+-----END CERTIFICATE-----
diff --color -Nuar ruby-3.0.2.orig/test/openssl/fixtures/pkey/garbage.txt ruby-3.0.2/test/openssl/fixtures/pkey/garbage.txt
--- ruby-3.0.2.orig/test/openssl/fixtures/pkey/garbage.txt	1970-01-01 08:00:00.000000000 +0800
+++ ruby-3.0.2/test/openssl/fixtures/pkey/garbage.txt	2021-09-09 18:29:40.443077922 +0800
@@ -0,0 +1 @@
+Hello World
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_asn1.rb ruby-3.0.2/test/openssl/test_asn1.rb
--- ruby-3.0.2.orig/test/openssl/test_asn1.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_asn1.rb	2021-09-09 18:29:40.443077922 +0800
@@ -265,10 +265,9 @@
     assert_raise(OpenSSL::ASN1::ASN1Error) {
       OpenSSL::ASN1.decode(B(%w{ 03 00 }))
     }
-    # OpenSSL < OpenSSL_1_0_1k and LibreSSL ignore the error
-    # assert_raise(OpenSSL::ASN1::ASN1Error) {
-    #   OpenSSL::ASN1.decode(B(%w{ 03 03 08 FF 00 }))
-    # }
+    assert_raise(OpenSSL::ASN1::ASN1Error) {
+      OpenSSL::ASN1.decode(B(%w{ 03 03 08 FF 00 }))
+    }
     # OpenSSL does not seem to prohibit this, though X.690 8.6.2.3 (15/08) does
     # assert_raise(OpenSSL::ASN1::ASN1Error) {
     #   OpenSSL::ASN1.decode(B(%w{ 03 01 04 }))
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_bn.rb ruby-3.0.2/test/openssl/test_bn.rb
--- ruby-3.0.2.orig/test/openssl/test_bn.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_bn.rb	2021-09-09 18:29:40.443077922 +0800
@@ -131,6 +131,27 @@
     assert_equal(-999, +@e2)
     assert_equal(-999, -@e1)
     assert_equal(+999, -@e2)
+
+    # These methods create new BN instances due to BN mutability
+    # Ensure that the instance isn't the same
+    e1_plus = +@e1
+    e1_minus = -@e1
+    assert_equal(false, @e1.equal?(e1_plus))
+    assert_equal(true, @e1 == e1_plus)
+    assert_equal(false, @e1.equal?(e1_minus))
+  end
+
+  def test_abs
+    assert_equal(@e1, @e2.abs)
+    assert_equal(@e3, @e4.abs)
+    assert_not_equal(@e2, @e2.abs)
+    assert_not_equal(@e4, @e4.abs)
+    assert_equal(false, @e2.abs.negative?)
+    assert_equal(false, @e4.abs.negative?)
+    assert_equal(true, (-@e1.abs).negative?)
+    assert_equal(true, (-@e2.abs).negative?)
+    assert_equal(true, (-@e3.abs).negative?)
+    assert_equal(true, (-@e4.abs).negative?)
   end
 
   def test_mod
@@ -228,6 +249,10 @@
       r5 = OpenSSL::BN.rand_range(256)
       assert_include(0..255, r5)
     }
+
+    # Aliases
+    assert_include(128..255, OpenSSL::BN.pseudo_rand(8))
+    assert_include(0..255, OpenSSL::BN.pseudo_rand_range(256))
   end
 
   def test_prime
@@ -281,6 +306,29 @@
     bug15760 = '[ruby-core:92231] [Bug #15760]'
     assert_raise(ArgumentError, bug15760) { OpenSSL::BN.new(nil, 2) }
   end
+
+  def test_get_flags_and_set_flags
+    e = OpenSSL::BN.new(999)
+
+    assert_equal(0, e.get_flags(OpenSSL::BN::CONSTTIME))
+
+    e.set_flags(OpenSSL::BN::CONSTTIME)
+    assert_equal(OpenSSL::BN::CONSTTIME, e.get_flags(OpenSSL::BN::CONSTTIME))
+
+    b = OpenSSL::BN.new(2)
+    m = OpenSSL::BN.new(99)
+    assert_equal("17", b.mod_exp(e, m).to_s)
+
+    # mod_exp fails when m is even and any argument has CONSTTIME flag
+    m = OpenSSL::BN.new(98)
+    assert_raise(OpenSSL::BNError) do
+      b.mod_exp(e, m)
+    end
+
+    # It looks like flags cannot be removed once enabled
+    e.set_flags(0)
+    assert_equal(4, e.get_flags(OpenSSL::BN::CONSTTIME))
+  end
 end
 
 end
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_cipher.rb ruby-3.0.2/test/openssl/test_cipher.rb
--- ruby-3.0.2.orig/test/openssl/test_cipher.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_cipher.rb	2021-09-09 18:29:40.443077922 +0800
@@ -147,13 +147,13 @@
 
   def test_AES
     pt = File.read(__FILE__)
-    %w(ECB CBC CFB OFB).each{|mode|
-      c1 = OpenSSL::Cipher.new("AES-256-#{mode}")
+    %w(ecb cbc cfb ofb).each{|mode|
+      c1 = OpenSSL::Cipher.new("aes-256-#{mode}")
       c1.encrypt
       c1.pkcs5_keyivgen("passwd")
       ct = c1.update(pt) + c1.final
 
-      c2 = OpenSSL::Cipher.new("AES-256-#{mode}")
+      c2 = OpenSSL::Cipher.new("aes-256-#{mode}")
       c2.decrypt
       c2.pkcs5_keyivgen("passwd")
       assert_equal(pt, c2.update(ct) + c2.final)
@@ -163,7 +163,7 @@
   def test_update_raise_if_key_not_set
     assert_raise(OpenSSL::Cipher::CipherError) do
       # it caused OpenSSL SEGV by uninitialized key [Bug #2768]
-      OpenSSL::Cipher.new("AES-128-ECB").update "." * 17
+      OpenSSL::Cipher.new("aes-128-ecb").update "." * 17
     end
   end
 
@@ -174,6 +174,48 @@
     assert_not_predicate(cipher, :authenticated?)
   end
 
+  def test_aes_ccm
+    # RFC 3610 Section 8, Test Case 1
+    key = ["c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"].pack("H*")
+    iv =  ["00000003020100a0a1a2a3a4a5"].pack("H*")
+    aad = ["0001020304050607"].pack("H*")
+    pt =  ["08090a0b0c0d0e0f101112131415161718191a1b1c1d1e"].pack("H*")
+    ct =  ["588c979a61c663d2f066d0c2c0f989806d5f6b61dac384"].pack("H*")
+    tag = ["17e8d12cfdf926e0"].pack("H*")
+
+    kwargs = {auth_tag_len: 8, iv_len: 13, key: key, iv: iv}
+    cipher = new_encryptor("aes-128-ccm", **kwargs, ccm_data_len: pt.length, auth_data: aad)
+    assert_equal ct, cipher.update(pt) << cipher.final
+    assert_equal tag, cipher.auth_tag
+    cipher = new_decryptor("aes-128-ccm", **kwargs, ccm_data_len: ct.length, auth_tag: tag, auth_data: aad)
+    assert_equal pt, cipher.update(ct) << cipher.final
+
+    # truncated tag is accepted
+    cipher = new_encryptor("aes-128-ccm", **kwargs, ccm_data_len: pt.length, auth_data: aad)
+    assert_equal ct, cipher.update(pt) << cipher.final
+    assert_equal tag[0, 8], cipher.auth_tag(8)
+    cipher = new_decryptor("aes-128-ccm", **kwargs, ccm_data_len: ct.length, auth_tag: tag[0, 8], auth_data: aad)
+    assert_equal pt, cipher.update(ct) << cipher.final
+
+    # wrong tag is rejected
+    tag2 = tag.dup
+    tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff)
+    cipher = new_decryptor("aes-128-ccm", **kwargs, ccm_data_len: ct.length, auth_tag: tag2, auth_data: aad)
+    assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(ct) }
+
+    # wrong aad is rejected
+    aad2 = aad[0..-2] << aad[-1].succ
+    cipher = new_decryptor("aes-128-ccm", **kwargs, ccm_data_len: ct.length, auth_tag: tag, auth_data: aad2)
+    assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(ct) }
+
+    # wrong ciphertext is rejected
+    ct2 = ct[0..-2] << ct[-1].succ
+    cipher = new_decryptor("aes-128-ccm", **kwargs, ccm_data_len: ct2.length, auth_tag: tag, auth_data: aad)
+    assert_raise(OpenSSL::Cipher::CipherError) { cipher.update(ct2) }
+  end if has_cipher?("aes-128-ccm") &&
+         OpenSSL::Cipher.new("aes-128-ccm").authenticated? &&
+         OpenSSL::OPENSSL_VERSION_NUMBER >= 0x1010103f # version >= 1.1.1c
+
   def test_aes_gcm
     # GCM spec Appendix B Test Case 4
     key = ["feffe9928665731c6d6a8f9467308308"].pack("H*")
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_config.rb ruby-3.0.2/test/openssl/test_config.rb
--- ruby-3.0.2.orig/test/openssl/test_config.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_config.rb	2021-09-09 18:29:40.443077922 +0800
@@ -121,6 +121,11 @@
   end
 
   def test_s_parse_include
+    if !openssl?(1, 1, 1, 2)
+      # OpenSSL < 1.1.1 parses .include directive as a normal assignment
+      pend ".include directive is not supported"
+    end
+
     in_tmpdir("ossl-config-include-test") do |dir|
       Dir.mkdir("child")
       File.write("child/a.conf", <<~__EOC__)
@@ -151,15 +156,15 @@
       # Include a file by relative path
       c1 = OpenSSL::Config.parse(include_file)
       assert_equal(["default", "sec-a", "sec-b", "sec-main"], c1.sections.sort)
-      assert_equal(["file-main", "file-a", "file-b"], c1["default"].keys)
+      assert_equal(["file-a", "file-b", "file-main"], c1["default"].keys.sort)
       assert_equal({"a" => "123"}, c1["sec-a"])
       assert_equal({"b" => "123"}, c1["sec-b"])
       assert_equal({"main" => "123", "key_outside_section" => "value_a"}, c1["sec-main"])
 
       # Relative paths are from the working directory
-      assert_raise(OpenSSL::ConfigError) do
-        Dir.chdir("child") { OpenSSL::Config.parse(include_file) }
-      end
+      # Inclusion fails, but the error is ignored silently
+      c2 = Dir.chdir("child") { OpenSSL::Config.parse(include_file) }
+      assert_equal(["default", "sec-main"], c2.sections.sort)
     end
   end
 
@@ -177,6 +182,12 @@
     }
   end
 
+  def test_s_parse_config
+    ret = OpenSSL::Config.parse_config(@it.to_s)
+    assert_equal(@it.sections.sort, ret.keys.sort)
+    assert_equal(@it["default"], ret["default"])
+  end
+
   def test_initialize
     c = OpenSSL::Config.new
     assert_equal("", c.to_s)
@@ -209,33 +220,14 @@
   end
 
   def test_get_value_ENV
+    # LibreSSL removed support for NCONF_get_string(conf, "ENV", str)
+    return if libressl?
+
     key = ENV.keys.first
     assert_not_nil(key) # make sure we have at least one ENV var.
     assert_equal(ENV[key], @it.get_value('ENV', key))
   end
 
-  def test_value
-    # suppress deprecation warnings
-    EnvUtil.suppress_warning do
-      assert_equal('CA_default', @it.value('ca', 'default_ca'))
-      assert_equal(nil, @it.value('ca', 'no such key'))
-      assert_equal(nil, @it.value('no such section', 'no such key'))
-      assert_equal('.', @it.value('', 'HOME'))
-      assert_equal('.', @it.value(nil, 'HOME'))
-      assert_equal('.', @it.value('HOME'))
-      # fallback to 'default' ugly...
-      assert_equal('.', @it.value('unknown', 'HOME'))
-    end
-  end
-
-  def test_value_ENV
-    EnvUtil.suppress_warning do
-      key = ENV.keys.first
-      assert_not_nil(key) # make sure we have at least one ENV var.
-      assert_equal(ENV[key], @it.value('ENV', key))
-    end
-  end
-
   def test_aref
     assert_equal({'HOME' => '.'}, @it['default'])
     assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it['CA_default'])
@@ -243,65 +235,19 @@
     assert_equal({}, @it[''])
   end
 
-  def test_section
-    EnvUtil.suppress_warning do
-      assert_equal({'HOME' => '.'}, @it.section('default'))
-      assert_equal({'dir' => './demoCA', 'certs' => './certs'}, @it.section('CA_default'))
-      assert_equal({}, @it.section('no_such_section'))
-      assert_equal({}, @it.section(''))
-    end
-  end
-
   def test_sections
     assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
-    # OpenSSL::Config#[]= is deprecated
-    EnvUtil.suppress_warning do
-      @it['new_section'] = {'foo' => 'bar'}
-      assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
-      @it['new_section'] = {}
-      assert_equal(['CA_default', 'ca', 'default', 'new_section'], @it.sections.sort)
-    end
-  end
-
-  def test_add_value
-    # OpenSSL::Config#add_value is deprecated
-    EnvUtil.suppress_warning do
-      c = OpenSSL::Config.new
-      assert_equal("", c.to_s)
-      # add key
-      c.add_value('default', 'foo', 'bar')
-      assert_equal("[ default ]\nfoo=bar\n\n", c.to_s)
-      # add another key
-      c.add_value('default', 'baz', 'qux')
-      assert_equal('bar', c['default']['foo'])
-      assert_equal('qux', c['default']['baz'])
-      # update the value
-      c.add_value('default', 'baz', 'quxxx')
-      assert_equal('bar', c['default']['foo'])
-      assert_equal('quxxx', c['default']['baz'])
-      # add section and key
-      c.add_value('section', 'foo', 'bar')
-      assert_equal('bar', c['default']['foo'])
-      assert_equal('quxxx', c['default']['baz'])
-      assert_equal('bar', c['section']['foo'])
-    end
-  end
-
-  def test_aset
-    # OpenSSL::Config#[]= is deprecated
-    EnvUtil.suppress_warning do
-      @it['foo'] = {'bar' => 'baz'}
-      assert_equal({'bar' => 'baz'}, @it['foo'])
-      @it['foo'] = {'bar' => 'qux', 'baz' => 'quxx'}
-      assert_equal({'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
-
-      # OpenSSL::Config is add only for now.
-      @it['foo'] = {'foo' => 'foo'}
-      assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
-      # you cannot override or remove any section and key.
-      @it['foo'] = {}
-      assert_equal({'foo' => 'foo', 'bar' => 'qux', 'baz' => 'quxx'}, @it['foo'])
-    end
+    Tempfile.create("openssl.cnf") { |f|
+      f.write File.read(@tmpfile.path)
+      f.puts "[ new_section ]"
+      f.puts "foo = bar"
+      f.puts "[ empty_section ]"
+      f.close
+
+      c = OpenSSL::Config.new(f.path)
+      assert_equal(['CA_default', 'ca', 'default', 'empty_section', 'new_section'],
+                   c.sections.sort)
+    }
   end
 
   def test_each
@@ -323,40 +269,12 @@
     assert_match(/#<OpenSSL::Config sections=\[.*\]>/, @it.inspect)
   end
 
-  def test_freeze
-    @it.freeze
-
-    # Modifying OpenSSL::Config produces a warning
-    EnvUtil.suppress_warning do
-      bug = '[ruby-core:18377]'
-      # RuntimeError for 1.9, TypeError for 1.8
-      e = assert_raise(TypeError, bug) do
-        @it['foo'] = [['key', 'wrong']]
-      end
-      assert_match(/can't modify/, e.message, bug)
-    end
-  end
-
   def test_dup
-    assert(!@it.sections.empty?)
-    c = @it.dup
-    assert_equal(@it.sections.sort, c.sections.sort)
-    # OpenSSL::Config#[]= is deprecated
-    EnvUtil.suppress_warning do
-      @it['newsection'] = {'a' => 'b'}
-      assert_not_equal(@it.sections.sort, c.sections.sort)
-    end
-  end
-
-  def test_clone
-    assert(!@it.sections.empty?)
-    c = @it.clone
-    assert_equal(@it.sections.sort, c.sections.sort)
-    # OpenSSL::Config#[]= is deprecated
-    EnvUtil.suppress_warning do
-      @it['newsection'] = {'a' => 'b'}
-      assert_not_equal(@it.sections.sort, c.sections.sort)
-    end
+    assert_equal(['CA_default', 'ca', 'default'], @it.sections.sort)
+    c1 = @it.dup
+    assert_equal(@it.sections.sort, c1.sections.sort)
+    c2 = @it.clone
+    assert_equal(@it.sections.sort, c2.sections.sort)
   end
 
   private
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_digest.rb ruby-3.0.2/test/openssl/test_digest.rb
--- ruby-3.0.2.orig/test/openssl/test_digest.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_digest.rb	2021-09-09 18:29:40.443077922 +0800
@@ -54,7 +54,7 @@
   end
 
   def test_digest_constants
-    %w{MD4 MD5 RIPEMD160 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name|
+    %w{MD5 SHA1 SHA224 SHA256 SHA384 SHA512}.each do |name|
       assert_not_nil(OpenSSL::Digest.new(name))
       klass = OpenSSL::Digest.const_get(name.tr('-', '_'))
       assert_not_nil(klass.new)
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_hmac.rb ruby-3.0.2/test/openssl/test_hmac.rb
--- ruby-3.0.2.orig/test/openssl/test_hmac.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_hmac.rb	2021-09-09 18:29:40.443077922 +0800
@@ -10,12 +10,14 @@
     hmac.update("Hi There")
     assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), hmac.digest
     assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hmac.hexdigest
+    assert_equal "kpRyejY4uxwT9I74FYv8nQ==", hmac.base64digest
 
     # RFC 4231 4.2. Test Case 1
     hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "SHA224")
     hmac.update("Hi There")
     assert_equal ["896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"].pack("H*"), hmac.digest
     assert_equal "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", hmac.hexdigest
+    assert_equal "iW+xEoq73xloMhB81J3zP0e0sRaZErpPU2hLIg==", hmac.base64digest
   end
 
   def test_dup
@@ -49,6 +51,17 @@
     refute_equal h1, h2.digest
     refute_equal h1, h3
   end
+
+  def test_singleton_methods
+    # RFC 2202 2. Test Cases for HMAC-MD5
+    key = ["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*")
+    digest = OpenSSL::HMAC.digest("MD5", key, "Hi There")
+    assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), digest
+    hexdigest = OpenSSL::HMAC.hexdigest("MD5", key, "Hi There")
+    assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hexdigest
+    b64digest = OpenSSL::HMAC.base64digest("MD5", key, "Hi There")
+    assert_equal "kpRyejY4uxwT9I74FYv8nQ==", b64digest
+  end
 end
 
 end
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_ocsp.rb ruby-3.0.2/test/openssl/test_ocsp.rb
--- ruby-3.0.2.orig/test/openssl/test_ocsp.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_ocsp.rb	2021-09-09 18:29:40.443077922 +0800
@@ -123,14 +123,7 @@
 
     assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN)
     ret = req.verify([@cert], store)
-    if ret || openssl?(1, 0, 2)
-      assert_equal true, ret
-    else
-      # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when
-      # OCSP_NOINTERN is not specified.
-      # fixed by OpenSSL 1.0.1j, 1.0.2
-      pend "RT2560: ocsp_req_find_signer"
-    end
+    assert_equal true, ret
 
     # not signed
     req = OpenSSL::OCSP::Request.new.add_certid(cid)
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_pkcs12.rb ruby-3.0.2/test/openssl/test_pkcs12.rb
--- ruby-3.0.2.orig/test/openssl/test_pkcs12.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_pkcs12.rb	2021-09-09 18:29:40.443077922 +0800
@@ -5,6 +5,9 @@
 
 module OpenSSL
   class TestPKCS12 < OpenSSL::TestCase
+    DEFAULT_PBE_PKEYS = "PBE-SHA1-3DES"
+    DEFAULT_PBE_CERTS = "PBE-SHA1-3DES"
+
     def setup
       super
       ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
@@ -14,47 +17,41 @@
         ["subjectKeyIdentifier","hash",false],
         ["authorityKeyIdentifier","keyid:always",false],
       ]
-      @cacert = issue_cert(ca, Fixtures.pkey("rsa2048"), 1, ca_exts, nil, nil)
+      ca_key = Fixtures.pkey("rsa-1")
+      @cacert = issue_cert(ca, ca_key, 1, ca_exts, nil, nil)
 
       inter_ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Intermediate CA")
-      inter_ca_key = OpenSSL::PKey.read <<-_EOS_
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDp7hIG0SFMG/VWv1dBUWziAPrNmkMXJgTCAoB7jffzRtyyN04K
-oq/89HAszTMStZoMigQURfokzKsjpUp8OYCAEsBtt9d5zPndWMz/gHN73GrXk3LT
-ZsxEn7Xv5Da+Y9F/Hx2QZUHarV5cdZixq2NbzWGwrToogOQMh2pxN3Z/0wIDAQAB
-AoGBAJysUyx3olpsGzv3OMRJeahASbmsSKTXVLZvoIefxOINosBFpCIhZccAG6UV
-5c/xCvS89xBw8aD15uUfziw3AuT8QPEtHCgfSjeT7aWzBfYswEgOW4XPuWr7EeI9
-iNHGD6z+hCN/IQr7FiEBgTp6A+i/hffcSdR83fHWKyb4M7TRAkEA+y4BNd668HmC
-G5MPRx25n6LixuBxrNp1umfjEI6UZgEFVpYOg4agNuimN6NqM253kcTR94QNTUs5
-Kj3EhG1YWwJBAO5rUjiOyCNVX2WUQrOMYK/c1lU7fvrkdygXkvIGkhsPoNRzLPeA
-HGJszKtrKD8bNihWpWNIyqKRHfKVD7yXT+kCQGCAhVCIGTRoypcDghwljHqLnysf
-ci0h5ZdPcIqc7ODfxYhFsJ/Rql5ONgYsT5Ig/+lOQAkjf+TRYM4c2xKx2/8CQBvG
-jv6dy70qDgIUgqzONtlmHeYyFzn9cdBO5sShdVYHvRHjFSMEXsosqK9zvW2UqvuK
-FJx7d3f29gkzynCLJDkCQGQZlEZJC4vWmWJGRKJ24P6MyQn3VsPfErSKOg4lvyM3
-Li8JsX5yIiuVYaBg/6ha3tOg4TCa5K/3r3tVliRZ2Es=
------END RSA PRIVATE KEY-----
-      _EOS_
-      @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, Fixtures.pkey("rsa2048"))
+      inter_ca_key = Fixtures.pkey("rsa-2")
+      @inter_cacert = issue_cert(inter_ca, inter_ca_key, 2, ca_exts, @cacert, ca_key)
 
       exts = [
         ["keyUsage","digitalSignature",true],
         ["subjectKeyIdentifier","hash",false],
       ]
       ee = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=Ruby PKCS12 Test Certificate")
-      @mykey = Fixtures.pkey("rsa1024")
+      @mykey = Fixtures.pkey("rsa-3")
       @mycert = issue_cert(ee, @mykey, 3, exts, @inter_cacert, inter_ca_key)
     end
 
-    def test_create
+    def test_create_single_key_single_cert
       pkcs12 = OpenSSL::PKCS12.create(
         "omg",
         "hello",
         @mykey,
-        @mycert
+        @mycert,
+        nil,
+        DEFAULT_PBE_PKEYS,
+        DEFAULT_PBE_CERTS,
       )
-      assert_equal @mycert.to_der, pkcs12.certificate.to_der
+      assert_equal @mycert, pkcs12.certificate
       assert_equal @mykey.to_der, pkcs12.key.to_der
       assert_nil pkcs12.ca_certs
+
+      der = pkcs12.to_der
+      decoded = OpenSSL::PKCS12.new(der, "omg")
+      assert_equal @mykey.to_der, decoded.key.to_der
+      assert_equal @mycert, decoded.certificate
+      assert_equal [], Array(decoded.ca_certs)
     end
 
     def test_create_no_pass
@@ -62,14 +59,17 @@
         nil,
         "hello",
         @mykey,
-        @mycert
+        @mycert,
+        nil,
+        DEFAULT_PBE_PKEYS,
+        DEFAULT_PBE_CERTS,
       )
-      assert_equal @mycert.to_der, pkcs12.certificate.to_der
+      assert_equal @mycert, pkcs12.certificate
       assert_equal @mykey.to_der, pkcs12.key.to_der
       assert_nil pkcs12.ca_certs
 
       decoded = OpenSSL::PKCS12.new(pkcs12.to_der)
-      assert_cert @mycert, decoded.certificate
+      assert_equal @mycert, decoded.certificate
     end
 
     def test_create_with_chain
@@ -80,7 +80,9 @@
         "hello",
         @mykey,
         @mycert,
-        chain
+        chain,
+        DEFAULT_PBE_PKEYS,
+        DEFAULT_PBE_CERTS,
       )
       assert_equal chain, pkcs12.ca_certs
     end
@@ -95,14 +97,16 @@
         "hello",
         @mykey,
         @mycert,
-        chain
+        chain,
+        DEFAULT_PBE_PKEYS,
+        DEFAULT_PBE_CERTS,
       )
 
       decoded = OpenSSL::PKCS12.new(pkcs12.to_der, passwd)
       assert_equal chain.size, decoded.ca_certs.size
-      assert_include_cert @cacert, decoded.ca_certs
-      assert_include_cert @inter_cacert, decoded.ca_certs
-      assert_cert @mycert, decoded.certificate
+      assert_include decoded.ca_certs, @cacert
+      assert_include decoded.ca_certs, @inter_cacert
+      assert_equal @mycert, decoded.certificate
       assert_equal @mykey.to_der, decoded.key.to_der
     end
 
@@ -126,8 +130,8 @@
         @mykey,
         @mycert,
         [],
-        nil,
-        nil,
+        DEFAULT_PBE_PKEYS,
+        DEFAULT_PBE_CERTS,
         2048
       )
 
@@ -138,8 +142,8 @@
           @mykey,
           @mycert,
           [],
-          nil,
-          nil,
+          DEFAULT_PBE_PKEYS,
+          DEFAULT_PBE_CERTS,
           "omg"
         )
       end
@@ -152,7 +156,8 @@
         @mykey,
         @mycert,
         [],
-        nil,
+        DEFAULT_PBE_PKEYS,
+        DEFAULT_PBE_CERTS,
         nil,
         nil,
         2048
@@ -165,148 +170,144 @@
           @mykey,
           @mycert,
           [],
-          nil,
-          nil,
+          DEFAULT_PBE_PKEYS,
+          DEFAULT_PBE_CERTS,
           nil,
           "omg"
         )
       end
     end
 
-    def test_new_with_one_key_and_one_cert
-      # generated with:
-      #   openssl version #=> OpenSSL 1.0.2h  3 May 2016
-      #   openssl pkcs12 -in <@mycert> -inkey <RSA1024> -export -out <out>
-      str = <<~EOF.unpack("m").first
-MIIGQQIBAzCCBgcGCSqGSIb3DQEHAaCCBfgEggX0MIIF8DCCAu8GCSqGSIb3DQEH
-BqCCAuAwggLcAgEAMIIC1QYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIeZPM
-Rh6KiXgCAggAgIICqL6O+LCZmBzdIg6mozPF3FpY0hVbWHvTNMiDHieW3CrAanhN
-YCH2/wHqH8WpFpEWwF0qEEXAWjHsIlYB4Cfqo6b7XpuZe5eVESsjNTOTMF1JCUJj
-A6iNefXmCFLync1JK5LUodRDhTlKLU1WPK20X9X4vuEwHn8wt5RUb8P0E+Xh6rpS
-XC4LkZKT45zF3cJa/n5+dW65ohVGNVnF9D1bCNEKHMOllK1V9omutQ9slW88hpga
-LGiFsJoFOb/ESGb78KO+bd6zbX1MdKdBV+WD6t1uF/cgU65y+2A4nXs1urda+MJ7
-7iVqiB7Vnc9cANTbAkTSGNyoUDVM/NZde782/8IvddLAzUZ2EftoRDke6PvuBOVL
-ljBhNWmdamrtBqzuzVZCRdWq44KZkF2Xoc9asepwIkdVmntzQF7f1Z+Ta5yg6HFp
-xnr7CuM+MlHEShXkMgYtHnwAq10fDMSXIvjhi/AA5XUAusDO3D+hbtcRDcJ4uUes
-dm5dhQE2qJ02Ysn4aH3o1F3RYNOzrxejHJwl0D2TCE8Ww2X342xib57+z9u03ufj
-jswhiMKxy67f1LhUMq3XrT3uV6kCVXk/KUOUPcXPlPVNA5JmZeFhMp6GrtB5xJJ9
-wwBZD8UL5A2U2Mxi2OZsdUBv8eo3jnjZ284aFpt+mCjIHrLW5O0jwY8OCwSlYUoY
-IY00wlabX0s82kBcIQNZbC1RSV2267ro/7A0MClc8YQ/zWN0FKY6apgtUkHJI1cL
-1dc77mhnjETjwW94iLMDFy4zQfVu7IfCBqOBzygRNnqqUG66UhTs1xFnWM0mWXl/
-Zh9+AMpbRLIPaKCktIjl5juzzm+KEgkhD+707XRCFIGUYGP5bSHzGaz8PK9hj0u1
-E2SpZHUvYOcawmxtA7pmpSxl5uQjMIIC+QYJKoZIhvcNAQcBoIIC6gSCAuYwggLi
-MIIC3gYLKoZIhvcNAQwKAQKgggKmMIICojAcBgoqhkiG9w0BDAEDMA4ECKB338m8
-qSzHAgIIAASCAoACFhJeqA3xx+s1qIH6udNQYY5hAL6oz7SXoGwFhDiceSyJjmAD
-Dby9XWM0bPl1Gj5nqdsuI/lAM++fJeoETk+rxw8q6Ofk2zUaRRE39qgpwBwSk44o
-0SAFJ6bzHpc5CFh6sZmDaUX5Lm9GtjnGFmmsPTSJT5an5JuJ9WczGBEd0nSBQhJq
-xHbTGZiN8i3SXcIH531Sub+CBIFWy5lyCKgDYh/kgJFGQAaWUOjLI+7dCEESonXn
-F3Jh2uPbnDF9MGJyAFoNgWFhgSpi1cf6AUi87GY4Oyur88ddJ1o0D0Kz2uw8/bpG
-s3O4PYnIW5naZ8mozzbnYByEFk7PoTwM7VhoFBfYNtBoAI8+hBnPY/Y71YUojEXf
-SeX6QbtkIANfzS1XuFNKElShC3DPQIHpKzaatEsfxHfP+8VOav6zcn4mioao7NHA
-x7Dp6R1enFGoQOq4UNjBT8YjnkG5vW8zQHW2dAHLTJBq6x2Fzm/4Pjo/8vM1FiGl
-BQdW5vfDeJ/l6NgQm3xR9ka2E2HaDqIcj1zWbN8jy/bHPFJYuF/HH8MBV/ngMIXE
-vFEW/ToYv8eif0+EpUtzBsCKD4a7qYYYh87RmEVoQU96q6m+UbhpD2WztYfAPkfo
-OSL9j2QHhVczhL7OAgqNeM95pOsjA9YMe7exTeqK31LYnTX8oH8WJD1xGbRSJYgu
-SY6PQbumcJkc/TFPn0GeVUpiDdf83SeG50lo/i7UKQi2l1hi5Y51fQhnBnyMr68D
-llSZEvSWqfDxBJkBpeg6PIYvkTpEwKRJpVQoM3uYvdqVSSnW6rydqIb+snfOrlhd
-f+xCtq9xr+kHeTSqLIDRRAnMfgFRhY3IBlj6MSUwIwYJKoZIhvcNAQkVMRYEFBdb
-8XGWehZ6oPj56Pf/uId46M9AMDEwITAJBgUrDgMCGgUABBRvSCB04/f8f13pp2PF
-vyl2WuMdEwQIMWFFphPkIUICAggA
-      EOF
-      p12 = OpenSSL::PKCS12.new(str, "abc123")
-
-      assert_equal @mykey.to_der, p12.key.to_der
-      assert_equal @mycert.subject.to_der, p12.certificate.subject.to_der
-      assert_equal [], Array(p12.ca_certs)
-    end
-
     def test_new_with_no_keys
       # generated with:
-      #   openssl pkcs12 -in <@mycert> -nokeys -export -out <out>
+      #   openssl pkcs12 -certpbe PBE-SHA1-3DES -in <@mycert> -nokeys -export
       str = <<~EOF.unpack("m").first
-MIIDHAIBAzCCAuIGCSqGSIb3DQEHAaCCAtMEggLPMIICyzCCAscGCSqGSIb3DQEH
-BqCCArgwggK0AgEAMIICrQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIX4+W
-irqwH40CAggAgIICgOaCyo+5+6IOVoGCCL80c50bkkzAwqdXxvkKExJSdcJz2uMU
-0gRrKnZEjL5wrUsN8RwZu8DvgQTEhNEkKsUgM7AWainmN/EnwohIdHZAHpm6WD67
-I9kLGp0/DHrqZrV9P2dLfhXLUSQE8PI0tqZPZ8UEABhizkViw4eISTkrOUN7pGbN
-Qtx/oqgitXDuX2polbxYYDwt9vfHZhykHoKgew26SeJyZfeMs/WZ6olEI4cQUAFr
-mvYGuC1AxEGTo9ERmU8Pm16j9Hr9PFk50WYe+rnk9oX3wJogQ7XUWS5kYf7XRycd
-NDkNiwV/ts94bbuaGZp1YA6I48FXpIc8b5fX7t9tY0umGaWy0bARe1L7o0Y89EPe
-lMg25rOM7j3uPtFG8whbSfdETSy57UxzzTcJ6UwexeaK6wb2jqEmj5AOoPLWeaX0
-LyOAszR3v7OPAcjIDYZGdrbb3MZ2f2vo2pdQfu9698BrWhXuM7Odh73RLhJVreNI
-aezNOAtPyBlvGiBQBGTzRIYHSLL5Y5aVj2vWLAa7hjm5qTL5C5mFdDIo6TkEMr6I
-OsexNQofEGs19kr8nARXDlcbEimk2VsPj4efQC2CEXZNzURsKca82pa62MJ8WosB
-DTFd8X06zZZ4nED50vLopZvyW4fyW60lELwOyThAdG8UchoAaz2baqP0K4de44yM
-Y5/yPFDu4+GoimipJfbiYviRwbzkBxYW8+958ILh0RtagLbvIGxbpaym9PqGjOzx
-ShNXjLK2aAFZsEizQ8kd09quJHU/ogq2cUXdqqhmOqPnUWrJVi/VCoRB3Pv1/lE4
-mrUgr2YZ11rYvBw6g5XvNvFcSc53OKyV7SLn0dwwMTAhMAkGBSsOAwIaBQAEFEWP
-1WRQykaoD4uJCpTx/wv0SLLBBAiDKI26LJK7xgICCAA=
+MIIGJAIBAzCCBeoGCSqGSIb3DQEHAaCCBdsEggXXMIIF0zCCBc8GCSqGSIb3
+DQEHBqCCBcAwggW8AgEAMIIFtQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQMw
+DgQIjv5c3OHvnBgCAggAgIIFiMJa8Z/w7errRvCQPXh9dGQz3eJaFq3S2gXD
+rh6oiwsgIRJZvYAWgU6ll9NV7N5SgvS2DDNVuc3tsP8TPWjp+bIxzS9qmGUV
+kYWuURWLMKhpF12ZRDab8jcIwBgKoSGiDJk8xHjx6L613/XcRM6ln3VeQK+C
+hlW5kXniNAUAgTft25Fn61Xa8xnhmsz/fk1ycGnyGjKCnr7Mgy7KV0C1vs23
+18n8+b1ktDWLZPYgpmXuMFVh0o+HJTV3O86mkIhJonMcnOMgKZ+i8KeXaocN
+JQlAPBG4+HOip7FbQT/h6reXv8/J+hgjLfqAb5aV3m03rUX9mXx66nR1tQU0
+Jq+XPfDh5+V4akIczLlMyyo/xZjI1/qupcMjr+giOGnGd8BA3cuXW+ueLQiA
+PpTp+DQLVHRfz9XTZbyqOReNEtEXvO9gOlKSEY5lp65ItXVEs2Oqyf9PfU9y
+DUltN6fCMilwPyyrsIBKXCu2ZLM5h65KVCXAYEX9lNqj9zrQ7vTqvCNN8RhS
+ScYouTX2Eqa4Z+gTZWLHa8RCQFoyP6hd+97/Tg2Gv2UTH0myQxIVcnpdi1wy
+cqb+er7tyKbcO96uSlUjpj/JvjlodtjJcX+oinEqGb/caj4UepbBwiG3vv70
+63bS3jTsOLNjDRsR9if3LxIhLa6DW8zOJiGC+EvMD1o4dzHcGVpQ/pZWCHZC
++YiNJpQOBApiZluE+UZ0m3XrtHFQYk7xblTrh+FJF91wBsok0rZXLAKd8m4p
+OJsc7quCq3cuHRRTzJQ4nSe01uqbwGDAYwLvi6VWy3svU5qa05eDRmgzEFTG
+e84Gp/1LQCtpQFr4txkjFchO2whWS80KoQKqmLPyGm1D9Lv53Q4ZsKMgNihs
+rEepuaOZMKHl4yMAYFoOXZCAYzfbhN6b2phcFAHjMUHUw9e3F0QuDk9D0tsr
+riYTrkocqlOKfK4QTomx27O0ON2J6f1rtEojGgfl9RNykN7iKGzjS3914QjW
+W6gGiZejxHsDPEAa4gUp0WiSUSXtD5WJgoyAzLydR2dKWsQ4WlaUXi01CuGy
++xvncSn2nO3bbot8VD5H6XU1CjREVtnIfbeRYO/uofyLUP3olK5RqN6ne6Xo
+eXnJ/bjYphA8NGuuuvuW1SCITmINkZDLC9cGlER9+K65RR/DR3TigkexXMeN
+aJ70ivZYAl0OuhZt3TGIlAzS64TIoyORe3z7Ta1Pp9PZQarYJpF9BBIZIFor
+757PHHuQKRuugiRkp8B7v4eq1BQ+VeAxCKpyZ7XrgEtbY/AWDiaKcGPKPjc3
+AqQraVeQm7kMBT163wFmZArCphzkDOI3bz2oEO8YArMgLq2Vto9jAZlqKyWr
+pi2bSJxuoP1aoD58CHcWMrf8/j1LVdQhKgHQXSik2ID0H2Wc/XnglhzlVFuJ
+JsNIW/EGJlZh/5WDez9U0bXqnBlu3uasPEOezdoKlcCmQlmTO5+uLHYLEtNA
+EH9MtnGZebi9XS5meTuS6z5LILt8O9IHZxmT3JRPHYj287FEzotlLdcJ4Ee5
+enW41UHjLrfv4OaITO1hVuoLRGdzjESx/fHMWmxroZ1nVClxECOdT42zvIYJ
+J3xBZ0gppzQ5fjoYiKjJpxTflRxUuxshk3ih6VUoKtqj/W18tBQ3g5SOlkgT
+yCW8r74yZlfYmNrPyDMUQYpLUPWj2n71GF0KyPfTU5yOatRgvheh262w5BG3
+omFY7mb3tCv8/U2jdMIoukRKacpZiagofz3SxojOJq52cHnCri+gTHBMX0cO
+j58ygfntHWRzst0pV7Ze2X3fdCAJ4DokH6bNJNthcgmolFJ/y3V1tJjgsdtQ
+7Pjn/vE6xUV0HXE2x4yoVYNirbAMIvkN/X+atxrN0dA4AchN+zGp8TAxMCEw
+CQYFKw4DAhoFAAQUQ+6XXkyhf6uYgtbibILN2IjKnOAECLiqoY45MPCrAgII
+AA==
       EOF
       p12 = OpenSSL::PKCS12.new(str, "abc123")
 
       assert_equal nil, p12.key
       assert_equal nil, p12.certificate
       assert_equal 1, p12.ca_certs.size
-      assert_equal @mycert.subject.to_der, p12.ca_certs[0].subject.to_der
+      assert_equal @mycert.subject, p12.ca_certs[0].subject
     end
 
     def test_new_with_no_certs
       # generated with:
-      #   openssl pkcs12 -inkey <RSA1024> -nocerts -export -out <out>
+      #   openssl pkcs12 -inkey fixtures/openssl/pkey/rsa-1.pem -nocerts -export
       str = <<~EOF.unpack("m").first
-MIIDJwIBAzCCAu0GCSqGSIb3DQEHAaCCAt4EggLaMIIC1jCCAtIGCSqGSIb3DQEH
-AaCCAsMEggK/MIICuzCCArcGCyqGSIb3DQEMCgECoIICpjCCAqIwHAYKKoZIhvcN
-AQwBAzAOBAg6AaYnJs84SwICCAAEggKAQzZH+fWSpcQYD1J7PsGSune85A++fLCQ
-V7tacp2iv95GJkxwYmfTP176pJdgs00mceB9UJ/u9EX5nD0djdjjQjwo6sgKjY0q
-cpVhZw8CMxw7kBD2dhtui0zT8z5hy03LePxsjEKsGiSbeVeeGbSfw/I6AAYbv+Uh
-O/YPBGumeHj/D2WKnfsHJLQ9GAV3H6dv5VKYNxjciK7f/JEyZCuUQGIN64QFHDhJ
-7fzLqd/ul3FZzJZO6a+dwvcgux09SKVXDRSeFmRCEX4b486iWhJJVspCo9P2KNne
-ORrpybr3ZSwxyoICmjyo8gj0OSnEfdx9790Ej1takPqSA1wIdSdBLekbZqB0RBQg
-DEuPOsXNo3QFi8ji1vu0WBRJZZSNC2hr5NL6lNR+DKxG8yzDll2j4W4BBIp22mAE
-7QRX7kVxu17QJXQhOUac4Dd1qXmzebP8t6xkAxD9L7BWEN5OdiXWwSWGjVjMBneX
-nYObi/3UT/aVc5WHMHK2BhCI1bwH51E6yZh06d5m0TQpYGUTWDJdWGBSrp3A+8jN
-N2PMQkWBFrXP3smHoTEN4oZC4FWiPsIEyAkQsfKRhcV9lGKl2Xgq54ROTFLnwKoj
-Z3zJScnq9qmNzvVZSMmDLkjLyDq0pxRxGKBvgouKkWY7VFFIwwBIJM39iDJ5NbBY
-i1AQFTRsRSsZrNVPasCXrIq7bhMoJZb/YZOGBLNyJVqKUoYXhtwsajzSq54VlWft
-JxsPayEd4Vi6O9EU1ahnj6qFEZiKFzsicgK2J1Rb8cYagrp0XWjHW0SBn5GVUWCg
-GUokSFG/0JTdeYTo/sQuG4qNgJkOolRjpeI48Fciq5VUWLvVdKioXzAxMCEwCQYF
-Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA==
+MIIJ7wIBAzCCCbUGCSqGSIb3DQEHAaCCCaYEggmiMIIJnjCCCZoGCSqGSIb3
+DQEHAaCCCYsEggmHMIIJgzCCCX8GCyqGSIb3DQEMCgECoIIJbjCCCWowHAYK
+KoZIhvcNAQwBAzAOBAjX5nN8jyRKwQICCAAEgglIBIRLHfiY1mNHpl3FdX6+
+72L+ZOVXnlZ1MY9HSeg0RMkCJcm0mJ2UD7INUOGXvwpK9fr6WJUZM1IqTihQ
+1dM0crRC2m23aP7KtAlXh2DYD3otseDtwoN/NE19RsiJzeIiy5TSW1d47weU
++D4Ig/9FYVFPTDgMzdCxXujhvO/MTbZIjqtcS+IOyF+91KkXrHkfkGjZC7KS
+WRmYw9BBuIPQEewdTI35sAJcxT8rK7JIiL/9mewbSE+Z28Wq1WXwmjL3oZm9
+lw6+f515b197GYEGomr6LQqJJamSYpwQbTGHonku6Tf3ylB4NLFqOnRCKE4K
+zRSSYIqJBlKHmQ4pDm5awoupHYxMZLZKZvXNYyYN3kV8r1iiNVlY7KBR4CsX
+rqUkXehRmcPnuqEMW8aOpuYe/HWf8PYI93oiDZjcEZMwW2IZFFrgBbqUeNCM
+CQTkjAYxi5FyoaoTnHrj/aRtdLOg1xIJe4KKcmOXAVMmVM9QEPNfUwiXJrE7
+n42gl4NyzcZpxqwWBT++9TnQGZ/lEpwR6dzkZwICNQLdQ+elsdT7mumywP+1
+WaFqg9kpurimaiBu515vJNp9Iqv1Nmke6R8Lk6WVRKPg4Akw0fkuy6HS+LyN
+ofdCfVUkPGN6zkjAxGZP9ZBwvXUbLRC5W3N5qZuAy5WcsS75z+oVeX9ePV63
+cue23sClu8JSJcw3HFgPaAE4sfkQ4MoihPY5kezgT7F7Lw/j86S0ebrDNp4N
+Y685ec81NRHJ80CAM55f3kGCOEhoifD4VZrvr1TdHZY9Gm3b1RYaJCit2huF
+nlOfzeimdcv/tkjb6UsbpXx3JKkF2NFFip0yEBERRCdWRYMUpBRcl3ad6XHy
+w0pVTgIjTxGlbbtOCi3siqMOK0GNt6UgjoEFc1xqjsgLwU0Ta2quRu7RFPGM
+GoEwoC6VH23p9Hr4uTFOL0uHfkKWKunNN+7YPi6LT6IKmTQwrp+fTO61N6Xh
+KlqTpwESKsIJB2iMnc8wBkjXJtmG/e2n5oTqfhICIrxYmEb7zKDyK3eqeTj3
+FhQh2t7cUIiqcT52AckUqniPmlE6hf82yBjhaQUPfi/ExTBtTDSmFfRPUzq+
+Rlla4OHllPRzUXJExyansgCxZbPqlw46AtygSWRGcWoYAKUKwwoYjerqIV5g
+JoZICV9BOU9TXco1dHXZQTs/nnTwoRmYiL/Ly5XpvUAnQOhYeCPjBeFnPSBR
+R/hRNqrDH2MOV57v5KQIH2+mvy26tRG+tVGHmLMaOJeQkjLdxx+az8RfXIrH
+7hpAsoBb+g9jUDY1mUVavPk1T45GMpQH8u3kkzRvChfOst6533GyIZhE7FhN
+KanC6ACabVFDUs6P9pK9RPQMp1qJfpA0XJFx5TCbVbPkvnkZd8K5Tl/tzNM1
+n32eRao4MKr9KDwoDL93S1yJgYTlYjy1XW/ewdedtX+B4koAoz/wSXDYO+GQ
+Zu6ZSpKSEHTRPhchsJ4oICvpriVaJkn0/Z7H3YjNMB9U5RR9+GiIg1wY1Oa1
+S3WfuwrrI6eqfbQwj6PDNu3IKy6srEgvJwaofQALNBPSYWbauM2brc8qsD+t
+n8jC/aD1aMcy00+9t3H/RVCjEOb3yKfUpAldIkEA2NTTnZpoDQDXeNYU2F/W
+yhmFjJy8A0O4QOk2xnZK9kcxSRs0v8vI8HivvgWENoVPscsDC4742SSIe6SL
+f/T08reIX11f0K70rMtLhtFMQdHdYOTNl6JzhkHPLr/f9MEZsBEQx52depnF
+ARb3gXGbCt7BAi0OeCEBSbLr2yWuW4r55N0wRZSOBtgqgjsiHP7CDQSkbL6p
+FPlQS1do9gBSHiNYvsmN1LN5bG+mhcVb0UjZub4mL0EqGadjDfDdRJmWqlX0
+r5dyMcOWQVy4O2cPqYFlcP9lk8buc5otcyVI2isrAFdlvBK29oK6jc52Aq5Q
+0b2ESDlgX8WRgiOPPxK8dySKEeuIwngCtJyNTecP9Ug06TDsu0znZGCXJ+3P
+8JOpykgA8EQdOZOYHbo76ZfB2SkklI5KeRA5IBjGs9G3TZ4PHLy2DIwsbWzS
+H1g01o1x264nx1cJ+eEgUN/KIiGFIib42RS8Af4D5e+Vj54Rt3axq+ag3kI+
+53p8uotyu+SpvvXUP7Kv4xpQ/L6k41VM0rfrd9+DrlDVvSfxP2uh6I1TKF7A
+CT5n8zguMbng4PGjxvyPBM5k62t6hN5fuw6Af0aZFexh+IjB/5wFQ6onSz23
+fBzMW4St7RgSs8fDg3lrM+5rwXiey1jxY1ddaxOoUsWRMvvdd7rZxRZQoN5v
+AcI5iMkK/vvpQgC/sfzhtXtrJ2XOPZ+GVgi7VcuDLKSkdFMcPbGzO8SdxUnS
+SLV5XTKqKND+Lrfx7DAoKi5wbDFHu5496/MHK5qP4tBe6sJ5bZc+KDJIH46e
+wTV1oWtB5tV4q46hOb5WRcn/Wjz3HSKaGZgx5QbK1MfKTzD5CTUn+ArMockX
+2wJhPnFK85U4rgv8iBuh9bRjyw+YaKf7Z3loXRiE1eRG6RzuPF0ZecFiDumk
+AC/VUXynJhzePBLqzrQj0exanACdullN+pSfHiRWBxR2VFUkjoFP5X45GK3z
+OstSH6FOkMVU4afqEmjsIwozDFIyin5EyWTtdhJe3szdJSGY23Tut+9hUatx
+9FDFLESOd8z3tyQSNiLk/Hib+e/lbjxqbXBG/p/oyvP3N999PLUPtpKqtYkV
+H0+18sNh9CVfojiJl44fzxe8yCnuefBjut2PxEN0EFRBPv9P2wWlmOxkPKUq
+NrCJP0rDj5aONLrNZPrR8bZNdIShkZ/rKkoTuA0WMZ+xUlDRxAupdMkWAlrz
+8IcwNcdDjPnkGObpN5Ctm3vK7UGSBmPeNqkXOYf3QTJ9gStJEd0F6+DzTN5C
+KGt1IyuGwZqL2Yk51FDIIkr9ykEnBMaA39LS7GFHEDNGlW+fKC7AzA0zfoOr
+fXZlHMBuqHtXqk3zrsHRqGGoocigg4ctrhD1UREYKj+eIj1TBiRdf7c6+COf
+NIOmej8pX3FmZ4ui+dDA8r2ctgsWHrb4A6iiH+v1DRA61GtoaA/tNRggewXW
+VXCZCGWyyTuyHGOqq5ozrv5MlzZLWD/KV/uDsAWmy20RAed1C4AzcXlpX25O
+M4SNl47g5VRNJRtMqokc8j6TjZrzMDEwITAJBgUrDgMCGgUABBRrkIRuS5qg
+BC8fv38mue8LZVcbHQQIUNrWKEnskCoCAggA
       EOF
       p12 = OpenSSL::PKCS12.new(str, "abc123")
 
-      assert_equal @mykey.to_der, p12.key.to_der
+      assert_equal Fixtures.pkey("rsa-1").to_der, p12.key.to_der
       assert_equal nil, p12.certificate
       assert_equal [], Array(p12.ca_certs)
     end
 
     def test_dup
-      p12 = OpenSSL::PKCS12.create("pass", "name", @mykey, @mycert)
+      p12 = OpenSSL::PKCS12.create(
+        "pass",
+        "name",
+        @mykey,
+        @mycert,
+        nil,
+        DEFAULT_PBE_PKEYS,
+        DEFAULT_PBE_CERTS,
+      )
       assert_equal p12.to_der, p12.dup.to_der
     end
-
-    private
-    def assert_cert expected, actual
-      [
-        :subject,
-        :issuer,
-        :serial,
-        :not_before,
-        :not_after,
-      ].each do |attribute|
-        assert_equal expected.send(attribute), actual.send(attribute)
-      end
-      assert_equal expected.to_der, actual.to_der
-    end
-
-    def assert_include_cert cert, ary
-      der = cert.to_der
-      ary.each do |candidate|
-        if candidate.to_der == der
-          return true
-        end
-      end
-      false
-    end
   end
 end
 
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_pkcs7.rb ruby-3.0.2/test/openssl/test_pkcs7.rb
--- ruby-3.0.2.orig/test/openssl/test_pkcs7.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_pkcs7.rb	2021-09-09 18:29:40.443077922 +0800
@@ -89,6 +89,24 @@
     assert_equal(@ee2_cert.issuer.to_s, signers[1].issuer.to_s)
   end
 
+  def test_signed_add_signer
+    data = "aaaaa\nbbbbb\nccccc\n"
+    psi = OpenSSL::PKCS7::SignerInfo.new(@ee1_cert, @rsa1024, "sha256")
+    p7 = OpenSSL::PKCS7.new
+    p7.type = :signed
+    p7.add_signer(psi)
+    p7.add_certificate(@ee1_cert)
+    p7.add_certificate(@ca_cert)
+    p7.add_data(data)
+
+    store = OpenSSL::X509::Store.new
+    store.add_cert(@ca_cert)
+
+    assert_equal(true, p7.verify([], store))
+    assert_equal(true, OpenSSL::PKCS7.new(p7.to_der).verify([], store))
+    assert_equal(1, p7.signers.size)
+  end
+
   def test_detached_sign
     store = OpenSSL::X509::Store.new
     store.add_cert(@ca_cert)
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_pkey_dh.rb ruby-3.0.2/test/openssl/test_pkey_dh.rb
--- ruby-3.0.2.orig/test/openssl/test_pkey_dh.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_pkey_dh.rb	2021-09-09 18:29:40.443077922 +0800
@@ -4,12 +4,19 @@
 if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH)
 
 class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
-  NEW_KEYLEN = 256
+  NEW_KEYLEN = 2048
 
-  def test_new
+  def test_new_empty
+    dh = OpenSSL::PKey::DH.new
+    assert_equal nil, dh.p
+    assert_equal nil, dh.priv_key
+  end
+
+  def test_new_generate
+    # This test is slow
     dh = OpenSSL::PKey::DH.new(NEW_KEYLEN)
     assert_key(dh)
-  end
+  end if ENV["OSSL_TEST_ALL"]
 
   def test_new_break
     assert_nil(OpenSSL::PKey::DH.new(NEW_KEYLEN) { break })
@@ -18,14 +25,29 @@
     end
   end
 
+  def test_derive_key
+    dh1 = Fixtures.pkey("dh1024").generate_key!
+    dh2 = Fixtures.pkey("dh1024").generate_key!
+    dh1_pub = OpenSSL::PKey.read(dh1.public_to_der)
+    dh2_pub = OpenSSL::PKey.read(dh2.public_to_der)
+    z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2)
+    assert_equal z, dh1.derive(dh2_pub)
+    assert_equal z, dh2.derive(dh1_pub)
+
+    assert_equal z, dh1.compute_key(dh2.pub_key)
+    assert_equal z, dh2.compute_key(dh1.pub_key)
+  end
+
   def test_DHparams
     dh1024 = Fixtures.pkey("dh1024")
+    dh1024params = dh1024.public_key
+
     asn1 = OpenSSL::ASN1::Sequence([
       OpenSSL::ASN1::Integer(dh1024.p),
       OpenSSL::ASN1::Integer(dh1024.g)
     ])
     key = OpenSSL::PKey::DH.new(asn1.to_der)
-    assert_same_dh dup_public(dh1024), key
+    assert_same_dh dh1024params, key
 
     pem = <<~EOF
     -----BEGIN DH PARAMETERS-----
@@ -35,7 +57,9 @@
     -----END DH PARAMETERS-----
     EOF
     key = OpenSSL::PKey::DH.new(pem)
-    assert_same_dh dup_public(dh1024), key
+    assert_same_dh dh1024params, key
+    key = OpenSSL::PKey.read(pem)
+    assert_same_dh dh1024params, key
 
     assert_equal asn1.to_der, dh1024.to_der
     assert_equal pem, dh1024.export
@@ -64,16 +88,38 @@
     assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key))
   end
 
+  def test_params_ok?
+    dh0 = Fixtures.pkey("dh1024")
+
+    dh1 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([
+      OpenSSL::ASN1::Integer(dh0.p),
+      OpenSSL::ASN1::Integer(dh0.g)
+    ]))
+    assert_equal(true, dh1.params_ok?)
+
+    dh2 = OpenSSL::PKey::DH.new(OpenSSL::ASN1::Sequence([
+      OpenSSL::ASN1::Integer(dh0.p + 1),
+      OpenSSL::ASN1::Integer(dh0.g)
+    ]))
+    assert_equal(false, dh2.params_ok?)
+  end
+
   def test_dup
-    dh = OpenSSL::PKey::DH.new(NEW_KEYLEN)
+    dh = Fixtures.pkey("dh1024")
     dh2 = dh.dup
-    assert_equal dh.to_der, dh2.to_der # params
-    assert_equal_params dh, dh2 # keys
-    dh2.set_pqg(dh2.p + 1, nil, dh2.g)
-    assert_not_equal dh2.p, dh.p
-    assert_equal dh2.g, dh.g
+    assert_equal dh.to_der, dh2.to_der # encodes params only
+    assert_equal dh.to_data, dh2.to_data # all components
   end
 
+  def test_set_components
+    dh1 = Fixtures.pkey("dh-1")
+    dh2 = Fixtures.pkey("dh1024")
+    assert_not_equal dh1.to_der, dh2.to_der
+
+    dh2.set_pqg(dh1.p, dh1.q, dh1.g)
+    assert_equal dh1.to_der, dh2.to_der
+  end if !openssl?(3, 0, 0)
+
   def test_marshal
     dh = Fixtures.pkey("dh1024")
     deserialized = Marshal.load(Marshal.dump(dh))
@@ -81,13 +127,38 @@
     assert_equal dh.to_der, deserialized.to_der
   end
 
-  private
-
-  def assert_equal_params(dh1, dh2)
-    assert_equal(dh1.g, dh2.g)
-    assert_equal(dh1.p, dh2.p)
+  def test_to_data
+    # PKCS #3 DH - q does not exist
+    dh = OpenSSL::PKey.generate_key(Fixtures.pkey("dh1024"))
+
+    # #params
+    params_keys = %w{p g pub_key priv_key}
+    params = dh.params
+    assert_equal [], params_keys - params.keys
+
+    # #to_data; may contain additional entries
+    data_keys = %w{p g pub priv}
+    data = dh.to_data
+    assert_equal [], data_keys.map(&:intern) - data.keys
+
+    # Check value
+    assert_equal dh.p, params["p"]
+    assert_equal dh.p, data[:p]
+    assert_equal 1024, dh.p.num_bits
+    assert_equal true, dh.p.prime?
+
+    params_keys.each_with_index do |pk, i|
+      dk = data_keys[i]
+      getter_value = dh.public_send(pk)
+
+      assert_kind_of OpenSSL::BN, getter_value
+      assert_equal getter_value, params[pk]
+      assert_equal getter_value, data[dk.intern]
+    end
   end
 
+  private
+
   def assert_no_key(dh)
     assert_equal(false, dh.public?)
     assert_equal(false, dh.private?)
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_pkey_dsa.rb ruby-3.0.2/test/openssl/test_pkey_dsa.rb
--- ruby-3.0.2.orig/test/openssl/test_pkey_dsa.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_pkey_dsa.rb	2021-09-09 18:29:40.443077922 +0800
@@ -5,31 +5,26 @@
 
 class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
   def test_private
-    key = OpenSSL::PKey::DSA.new(256)
-    assert(key.private?)
+    key = Fixtures.pkey("dsa1024")
+    assert_equal true, key.private?
     key2 = OpenSSL::PKey::DSA.new(key.to_der)
-    assert(key2.private?)
+    assert_equal true, key2.private?
     key3 = key.public_key
-    assert(!key3.private?)
+    assert_equal false, key3.private?
     key4 = OpenSSL::PKey::DSA.new(key3.to_der)
-    assert(!key4.private?)
+    assert_equal false, key4.private?
   end
 
   def test_new
-    key = OpenSSL::PKey::DSA.new 256
+    key = OpenSSL::PKey::DSA.new(2048)
     pem  = key.public_key.to_pem
     OpenSSL::PKey::DSA.new pem
-    if $0 == __FILE__
-      assert_nothing_raised {
-        key = OpenSSL::PKey::DSA.new 2048
-      }
-    end
   end
 
   def test_new_break
-    assert_nil(OpenSSL::PKey::DSA.new(512) { break })
+    assert_nil(OpenSSL::PKey::DSA.new(2048) { break })
     assert_raise(RuntimeError) do
-      OpenSSL::PKey::DSA.new(512) { raise }
+      OpenSSL::PKey::DSA.new(2048) { raise }
     end
   end
 
@@ -53,12 +48,31 @@
     assert_equal false, dsa512.verify("SHA256", signature1, data)
   end
 
-  def test_sys_sign_verify
-    key = Fixtures.pkey("dsa256")
+  def test_sign_verify_raw
+    key = Fixtures.pkey("dsa512")
     data = 'Sign me!'
     digest = OpenSSL::Digest.digest('SHA1', data)
+
+    invalid_sig = key.sign_raw(nil, digest.succ)
+    malformed_sig = "*" * invalid_sig.bytesize
+
+    # Sign by #syssign
     sig = key.syssign(digest)
-    assert(key.sysverify(digest, sig))
+    assert_equal true, key.sysverify(digest, sig)
+    assert_equal false, key.sysverify(digest, invalid_sig)
+    assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) }
+    assert_equal true, key.verify_raw(nil, sig, digest)
+    assert_equal false, key.verify_raw(nil, invalid_sig, digest)
+    assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) }
+
+    # Sign by #sign_raw
+    sig = key.sign_raw(nil, digest)
+    assert_equal true, key.sysverify(digest, sig)
+    assert_equal false, key.sysverify(digest, invalid_sig)
+    assert_raise(OpenSSL::PKey::DSAError) { key.sysverify(digest, malformed_sig) }
+    assert_equal true, key.verify_raw(nil, sig, digest)
+    assert_equal false, key.verify_raw(nil, invalid_sig, digest)
+    assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, digest) }
   end
 
   def test_DSAPrivateKey
@@ -124,6 +138,8 @@
 
   def test_PUBKEY
     dsa512 = Fixtures.pkey("dsa512")
+    dsa512pub = OpenSSL::PKey::DSA.new(dsa512.public_to_der)
+
     asn1 = OpenSSL::ASN1::Sequence([
       OpenSSL::ASN1::Sequence([
         OpenSSL::ASN1::ObjectId("DSA"),
@@ -139,7 +155,7 @@
     ])
     key = OpenSSL::PKey::DSA.new(asn1.to_der)
     assert_not_predicate key, :private?
-    assert_same_dsa dup_public(dsa512), key
+    assert_same_dsa dsa512pub, key
 
     pem = <<~EOF
     -----BEGIN PUBLIC KEY-----
@@ -152,10 +168,15 @@
     -----END PUBLIC KEY-----
     EOF
     key = OpenSSL::PKey::DSA.new(pem)
-    assert_same_dsa dup_public(dsa512), key
+    assert_same_dsa dsa512pub, key
 
-    assert_equal asn1.to_der, dup_public(dsa512).to_der
-    assert_equal pem, dup_public(dsa512).export
+    assert_equal asn1.to_der, key.to_der
+    assert_equal pem, key.export
+
+    assert_equal asn1.to_der, dsa512.public_to_der
+    assert_equal asn1.to_der, key.public_to_der
+    assert_equal pem, dsa512.public_to_pem
+    assert_equal pem, key.public_to_pem
   end
 
   def test_read_DSAPublicKey_pem
@@ -184,11 +205,15 @@
   end
 
   def test_dup
-    key = OpenSSL::PKey::DSA.new(256)
-    key2 = key.dup
-    assert_equal key.params, key2.params
-    key2.set_pqg(key2.p + 1, key2.q, key2.g)
-    assert_not_equal key.params, key2.params
+    key1 = Fixtures.pkey("dsa1024")
+    key1dup = key1.dup
+    key2 = Fixtures.pkey("dsa512")
+    key2dup = key2.dup
+
+    assert_kind_of OpenSSL::PKey::DSA, key1dup
+    assert_equal key1.to_data, key1dup.to_data
+    assert_not_equal key1.to_data, key2dup.to_data
+    assert_not_equal key1dup.to_data, key2dup.to_data
   end
 
   def test_marshal
@@ -198,6 +223,35 @@
     assert_equal key.to_der, deserialized.to_der
   end
 
+  def test_to_data
+    dsa = Fixtures.pkey("dsa1024")
+
+    # #params and gettters
+    params_keys = %w{p q g pub_key priv_key}
+    params = dsa.params
+    assert_equal [], params_keys - params.keys
+
+    # #to_data; may contain additional entries
+    data_keys = %w{p q g pub priv}
+    data = dsa.to_data
+    assert_equal [], data_keys.map(&:intern) - data.keys
+
+    # Check value
+    assert_equal dsa.p, params["p"]
+    assert_equal dsa.p, data[:p]
+    assert_equal 1024, dsa.p.num_bits
+    assert_equal true, dsa.p.prime?
+
+    params_keys.each_with_index do |pk, i|
+      dk = data_keys[i]
+      getter_value = dsa.public_send(pk)
+
+      assert_kind_of OpenSSL::BN, getter_value
+      assert_equal getter_value, params[pk]
+      assert_equal getter_value, data[dk.intern]
+    end
+  end
+
   private
   def assert_same_dsa(expected, key)
     check_component(expected, key, [:p, :q, :g, :pub_key, :priv_key])
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_pkey_ec.rb ruby-3.0.2/test/openssl/test_pkey_ec.rb
--- ruby-3.0.2.orig/test/openssl/test_pkey_ec.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_pkey_ec.rb	2021-09-09 18:29:40.443077922 +0800
@@ -59,6 +59,14 @@
     assert_equal key.to_der, deserialized.to_der
   end
 
+  def test_to_data
+    p256 = Fixtures.pkey("p256")
+
+    data = p256.to_data
+    assert_equal "prime256v1", data[:group]
+    assert_equal p256.private_key, data[:priv]
+  end
+
   def test_check_key
     key = OpenSSL::PKey::EC.new("prime256v1").generate_key!
     assert_equal(true, key.check_key)
@@ -93,13 +101,46 @@
     assert_equal false, p256.verify("SHA256", signature1, data)
   end
 
-  def test_dsa_sign_verify
+  def test_derive_key
+    # NIST CAVP, KAS_ECC_CDH_PrimitiveTest.txt, P-256 COUNT = 0
+    qCAVSx = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287"
+    qCAVSy = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac"
+    dIUT = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534"
+    zIUT = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b"
+    a = OpenSSL::PKey::EC.new("prime256v1")
+    a.private_key = OpenSSL::BN.new(dIUT, 16)
+    b = OpenSSL::PKey::EC.new("prime256v1")
+    uncompressed = OpenSSL::BN.new("04" + qCAVSx + qCAVSy, 16)
+    b.public_key = OpenSSL::PKey::EC::Point.new(b.group, uncompressed)
+    assert_equal [zIUT].pack("H*"), a.derive(b)
+
+    assert_equal a.derive(b), a.dh_compute_key(b.public_key)
+  end
+
+  def test_sign_verify_raw
+    key = Fixtures.pkey("p256")
     data1 = "foo"
     data2 = "bar"
-    key = OpenSSL::PKey::EC.new("prime256v1").generate_key!
+
+    malformed_sig = "*" * 30
+
+    # Sign by #dsa_sign_asn1
     sig = key.dsa_sign_asn1(data1)
     assert_equal true, key.dsa_verify_asn1(data1, sig)
     assert_equal false, key.dsa_verify_asn1(data2, sig)
+    assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) }
+    assert_equal true, key.verify_raw(nil, sig, data1)
+    assert_equal false, key.verify_raw(nil, sig, data2)
+    assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) }
+
+    # Sign by #sign_raw
+    sig = key.sign_raw(nil, data1)
+    assert_equal true, key.dsa_verify_asn1(data1, sig)
+    assert_equal false, key.dsa_verify_asn1(data2, sig)
+    assert_raise(OpenSSL::PKey::ECError) { key.dsa_verify_asn1(data1, malformed_sig) }
+    assert_equal true, key.verify_raw(nil, sig, data1)
+    assert_equal false, key.verify_raw(nil, sig, data2)
+    assert_raise(OpenSSL::PKey::PKeyError) { key.verify_raw(nil, malformed_sig, data1) }
   end
 
   def test_dsa_sign_asn1_FIPS186_3
@@ -177,6 +218,8 @@
 
   def test_PUBKEY
     p256 = Fixtures.pkey("p256")
+    p256pub = OpenSSL::PKey::EC.new(p256.public_to_der)
+
     asn1 = OpenSSL::ASN1::Sequence([
       OpenSSL::ASN1::Sequence([
         OpenSSL::ASN1::ObjectId("id-ecPublicKey"),
@@ -188,7 +231,7 @@
     ])
     key = OpenSSL::PKey::EC.new(asn1.to_der)
     assert_not_predicate key, :private?
-    assert_same_ec dup_public(p256), key
+    assert_same_ec p256pub, key
 
     pem = <<~EOF
     -----BEGIN PUBLIC KEY-----
@@ -197,10 +240,15 @@
     -----END PUBLIC KEY-----
     EOF
     key = OpenSSL::PKey::EC.new(pem)
-    assert_same_ec dup_public(p256), key
+    assert_same_ec p256pub, key
+
+    assert_equal asn1.to_der, key.to_der
+    assert_equal pem, key.export
 
-    assert_equal asn1.to_der, dup_public(p256).to_der
-    assert_equal pem, dup_public(p256).export
+    assert_equal asn1.to_der, p256.public_to_der
+    assert_equal asn1.to_der, key.public_to_der
+    assert_equal pem, p256.public_to_pem
+    assert_equal pem, key.public_to_pem
   end
 
   def test_ec_group
@@ -333,21 +381,28 @@
       # 3 * (6, 3) + 3 * (5, 1) = (7, 6)
       result_a2 = point_a.mul(3, 3)
       assert_equal B(%w{ 04 07 06 }), result_a2.to_octet_string(:uncompressed)
-      # 3 * point_a = 3 * (6, 3) = (16, 13)
-      result_b1 = point_a.mul([3], [])
-      assert_equal B(%w{ 04 10 0D }), result_b1.to_octet_string(:uncompressed)
-      # 3 * point_a + 2 * point_a = 3 * (6, 3) + 2 * (6, 3) = (7, 11)
-      begin
+      EnvUtil.suppress_warning do # Point#mul(ary, ary [, bn]) is deprecated
+        begin
+          result_b1 = point_a.mul([3], [])
+        rescue NotImplementedError
+          # LibreSSL and OpenSSL 3.0 do no longer support this form of calling
+          next
+        end
+
+        # 3 * point_a = 3 * (6, 3) = (16, 13)
+        result_b1 = point_a.mul([3], [])
+        assert_equal B(%w{ 04 10 0D }), result_b1.to_octet_string(:uncompressed)
+        # 3 * point_a + 2 * point_a = 3 * (6, 3) + 2 * (6, 3) = (7, 11)
         result_b1 = point_a.mul([3, 2], [point_a])
-      rescue OpenSSL::PKey::EC::Point::Error
-        # LibreSSL doesn't support multiple entries in first argument
-        raise if $!.message !~ /called a function you should not call/
-      else
         assert_equal B(%w{ 04 07 0B }), result_b1.to_octet_string(:uncompressed)
+        # 3 * point_a + 5 * point_a.group.generator = 3 * (6, 3) + 5 * (5, 1) = (13, 10)
+        result_b1 = point_a.mul([3], [], 5)
+        assert_equal B(%w{ 04 0D 0A }), result_b1.to_octet_string(:uncompressed)
+
+        assert_raise(ArgumentError) { point_a.mul([1], [point_a]) }
+        assert_raise(TypeError) { point_a.mul([1], nil) }
+        assert_raise(TypeError) { point_a.mul([nil], []) }
       end
-      # 3 * point_a + 5 * point_a.group.generator = 3 * (6, 3) + 5 * (5, 1) = (13, 10)
-      result_b1 = point_a.mul([3], [], 5)
-      assert_equal B(%w{ 04 0D 0A }), result_b1.to_octet_string(:uncompressed)
     rescue OpenSSL::PKey::EC::Group::Error
       # CentOS patches OpenSSL to reject curves defined over Fp where p < 256 bits
       raise if $!.message !~ /unsupported field/
@@ -360,9 +415,6 @@
     # invalid argument
     point = p256_key.public_key
     assert_raise(TypeError) { point.mul(nil) }
-    assert_raise(ArgumentError) { point.mul([1], [point]) }
-    assert_raise(TypeError) { point.mul([1], nil) }
-    assert_raise(TypeError) { point.mul([nil], []) }
   end
 
 # test Group: asn1_flag, point_conversion
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_pkey.rb ruby-3.0.2/test/openssl/test_pkey.rb
--- ruby-3.0.2.orig/test/openssl/test_pkey.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_pkey.rb	2021-09-09 18:29:40.443077922 +0800
@@ -25,4 +25,152 @@
     assert_equal "X25519", x25519.oid
     assert_match %r{oid=X25519}, x25519.inspect
   end
+
+  def test_s_generate_parameters
+    pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)
+
+    pkey = OpenSSL::PKey.generate_parameters("EC", {
+      "ec_paramgen_curve" => "secp384r1",
+    })
+    assert_instance_of OpenSSL::PKey::EC, pkey
+    assert_equal "secp384r1", pkey.group.curve_name
+    assert_equal nil, pkey.private_key
+
+    # Invalid options are checked
+    assert_raise(OpenSSL::PKey::PKeyError) {
+      OpenSSL::PKey.generate_parameters("EC", "invalid" => "option")
+    }
+
+    # Parameter generation callback is called
+    cb_called = []
+    assert_raise(RuntimeError) {
+      OpenSSL::PKey.generate_parameters("DSA") { |*args|
+        cb_called << args
+        raise "exit!" if cb_called.size == 3
+      }
+    }
+    assert_not_empty cb_called
+  end
+
+  def test_s_generate_key
+    pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)
+
+    assert_raise(OpenSSL::PKey::PKeyError) {
+      # DSA key pair cannot be generated without parameters
+      OpenSSL::PKey.generate_key("DSA")
+    }
+    pkey_params = OpenSSL::PKey.generate_parameters("EC", {
+      "ec_paramgen_curve" => "secp384r1",
+    })
+    pkey = OpenSSL::PKey.generate_key(pkey_params)
+    assert_instance_of OpenSSL::PKey::EC, pkey
+    assert_equal "secp384r1", pkey.group.curve_name
+    assert_not_equal nil, pkey.private_key
+  end
+
+  def test_hmac_sign_verify
+    pkey = OpenSSL::PKey.generate_key("HMAC", { "key" => "abcd" })
+
+    hmac = OpenSSL::HMAC.new("abcd", "SHA256").update("data").digest
+    assert_equal hmac, pkey.sign("SHA256", "data")
+
+    # EVP_PKEY_HMAC does not support verify
+    assert_raise(OpenSSL::PKey::PKeyError) {
+      pkey.verify("SHA256", "data", hmac)
+    }
+  end
+
+  def test_ed25519
+    # Test vector from RFC 8032 Section 7.1 TEST 2
+    priv_pem = <<~EOF
+    -----BEGIN PRIVATE KEY-----
+    MC4CAQAwBQYDK2VwBCIEIEzNCJso/5banbbDRuwRTg9bijGfNaumJNqM9u1PuKb7
+    -----END PRIVATE KEY-----
+    EOF
+    pub_pem = <<~EOF
+    -----BEGIN PUBLIC KEY-----
+    MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw=
+    -----END PUBLIC KEY-----
+    EOF
+    begin
+      priv = OpenSSL::PKey.read(priv_pem)
+      pub = OpenSSL::PKey.read(pub_pem)
+    rescue OpenSSL::PKey::PKeyError
+      # OpenSSL < 1.1.1
+      pend "Ed25519 is not implemented"
+    end
+    assert_instance_of OpenSSL::PKey::PKey, priv
+    assert_instance_of OpenSSL::PKey::PKey, pub
+    assert_equal priv_pem, priv.private_to_pem
+    assert_equal pub_pem, priv.public_to_pem
+    assert_equal pub_pem, pub.public_to_pem
+
+    sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*")
+    92a009a9f0d4cab8720e820b5f642540
+    a2b27b5416503f8fb3762223ebdb69da
+    085ac1e43e15996e458f3613d0f11d8c
+    387b2eaeb4302aeeb00d291612bb0c00
+    EOF
+    data = ["72"].pack("H*")
+    assert_equal sig, priv.sign(nil, data)
+    assert_equal true, priv.verify(nil, sig, data)
+    assert_equal true, pub.verify(nil, sig, data)
+    assert_equal false, pub.verify(nil, sig, data.succ)
+
+    # PureEdDSA wants nil as the message digest
+    assert_raise(OpenSSL::PKey::PKeyError) { priv.sign("SHA512", data) }
+    assert_raise(OpenSSL::PKey::PKeyError) { pub.verify("SHA512", sig, data) }
+
+    # Ed25519 pkey type does not support key derivation
+    assert_raise(OpenSSL::PKey::PKeyError) { priv.derive(pub) }
+  end
+
+  def test_x25519
+    # Test vector from RFC 7748 Section 6.1
+    alice_pem = <<~EOF
+    -----BEGIN PRIVATE KEY-----
+    MC4CAQAwBQYDK2VuBCIEIHcHbQpzGKV9PBbBclGyZkXfTC+H68CZKrF3+6UduSwq
+    -----END PRIVATE KEY-----
+    EOF
+    bob_pem = <<~EOF
+    -----BEGIN PUBLIC KEY-----
+    MCowBQYDK2VuAyEA3p7bfXt9wbTTW2HC7OQ1Nz+DQ8hbeGdNrfx+FG+IK08=
+    -----END PUBLIC KEY-----
+    EOF
+    shared_secret = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"
+    begin
+      alice = OpenSSL::PKey.read(alice_pem)
+      bob = OpenSSL::PKey.read(bob_pem)
+    rescue OpenSSL::PKey::PKeyError
+      # OpenSSL < 1.1.0
+      pend "X25519 is not implemented"
+    end
+    assert_instance_of OpenSSL::PKey::PKey, alice
+    assert_equal alice_pem, alice.private_to_pem
+    assert_equal bob_pem, bob.public_to_pem
+    assert_equal [shared_secret].pack("H*"), alice.derive(bob)
+  end
+
+  def test_compare?
+    key1 = Fixtures.pkey("rsa1024")
+    key2 = Fixtures.pkey("rsa1024")
+    key3 = Fixtures.pkey("rsa2048")
+    key4 = Fixtures.pkey("dh-1")
+
+    assert_equal(true, key1.compare?(key2))
+    assert_equal(true, key1.public_key.compare?(key2))
+    assert_equal(true, key2.compare?(key1))
+    assert_equal(true, key2.public_key.compare?(key1))
+
+    assert_equal(false, key1.compare?(key3))
+
+    assert_raise(TypeError) do
+      key1.compare?(key4)
+    end
+  end
+
+  def test_to_text
+    rsa = Fixtures.pkey("rsa1024")
+    assert_include rsa.to_text, "publicExponent"
+  end
 end
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_pkey_rsa.rb ruby-3.0.2/test/openssl/test_pkey_rsa.rb
--- ruby-3.0.2.orig/test/openssl/test_pkey_rsa.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_pkey_rsa.rb	2021-09-09 18:29:40.443077922 +0800
@@ -11,33 +11,7 @@
     key.set_factors(rsa.p, rsa.q)
     assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt("foo") }
     assert_raise(OpenSSL::PKey::RSAError){ key.private_decrypt("foo") }
-  end
-
-  def test_padding
-    key = OpenSSL::PKey::RSA.new(512, 3)
-
-    # Need right size for raw mode
-    plain0 = "x" * (512/8)
-    cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING)
-    plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING)
-    assert_equal(plain0, plain1)
-
-    # Need smaller size for pkcs1 mode
-    plain0 = "x" * (512/8 - 11)
-    cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING)
-    plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING)
-    assert_equal(plain0, plain1)
-
-    cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default
-    plain1 = key.public_decrypt(cipherdef)
-    assert_equal(plain0, plain1)
-    assert_equal(cipher1, cipherdef)
-
-    # Failure cases
-    assert_raise(ArgumentError){ key.private_encrypt() }
-    assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) }
-    assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) }
-  end
+  end if !openssl?(3, 0, 0) # Impossible state in OpenSSL 3.0
 
   def test_private
     # Generated by key size and public exponent
@@ -69,29 +43,28 @@
   end
 
   def test_new
-    key = OpenSSL::PKey::RSA.new 512
-    pem  = key.public_key.to_pem
-    OpenSSL::PKey::RSA.new pem
-    assert_equal([], OpenSSL.errors)
-  end
-
-  def test_new_exponent_default
-    assert_equal(65537, OpenSSL::PKey::RSA.new(512).e)
-  end
-
-  def test_new_with_exponent
-    1.upto(30) do |idx|
-      e = (2 ** idx) + 1
-      key = OpenSSL::PKey::RSA.new(512, e)
-      assert_equal(e, key.e)
-    end
-  end
-
-  def test_generate
-    key = OpenSSL::PKey::RSA.generate(512, 17)
+    key = OpenSSL::PKey::RSA.new(512)
     assert_equal 512, key.n.num_bits
-    assert_equal 17, key.e
+    assert_equal 65537, key.e
     assert_not_nil key.d
+
+    # Specify public exponent
+    key2 = OpenSSL::PKey::RSA.new(512, 3)
+    assert_equal 512, key2.n.num_bits
+    assert_equal 3, key2.e
+    assert_not_nil key2.d
+  end
+
+  def test_s_generate
+    key1 = OpenSSL::PKey::RSA.generate(512)
+    assert_equal 512, key1.n.num_bits
+    assert_equal 65537, key1.e
+
+    # Specify public exponent
+    key2 = OpenSSL::PKey::RSA.generate(512, 3)
+    assert_equal 512, key2.n.num_bits
+    assert_equal 3, key2.e
+    assert_not_nil key2.d
   end
 
   def test_new_break
@@ -117,29 +90,75 @@
     assert_equal false, rsa1024.verify("SHA256", signature1, data)
   end
 
-  def test_digest_state_irrelevant_sign
+  def test_sign_verify_options
     key = Fixtures.pkey("rsa1024")
-    digest1 = OpenSSL::Digest.new('SHA1')
-    digest2 = OpenSSL::Digest.new('SHA1')
-    data = 'Sign me!'
-    digest1 << 'Change state of digest1'
-    sig1 = key.sign(digest1, data)
-    sig2 = key.sign(digest2, data)
-    assert_equal(sig1, sig2)
+    data = "Sign me!"
+    pssopts = {
+      "rsa_padding_mode" => "pss",
+      "rsa_pss_saltlen" => 20,
+      "rsa_mgf1_md" => "SHA1"
+    }
+    sig_pss = key.sign("SHA256", data, pssopts)
+    assert_equal 128, sig_pss.bytesize
+    assert_equal true, key.verify("SHA256", sig_pss, data, pssopts)
+    assert_equal true, key.verify_pss("SHA256", sig_pss, data,
+                                      salt_length: 20, mgf1_hash: "SHA1")
+    # Defaults to PKCS #1 v1.5 padding => verification failure
+    assert_equal false, key.verify("SHA256", sig_pss, data)
   end
 
-  def test_digest_state_irrelevant_verify
-    key = Fixtures.pkey("rsa1024")
-    digest1 = OpenSSL::Digest.new('SHA1')
-    digest2 = OpenSSL::Digest.new('SHA1')
-    data = 'Sign me!'
-    sig = key.sign(digest1, data)
-    digest1.reset
-    digest1 << 'Change state of digest1'
-    assert(key.verify(digest1, sig, data))
-    assert(key.verify(digest2, sig, data))
+  def test_sign_verify_raw
+    key = Fixtures.pkey("rsa-1")
+    data = "Sign me!"
+    hash = OpenSSL::Digest.digest("SHA1", data)
+    signature = key.sign_raw("SHA1", hash)
+    assert_equal true, key.verify_raw("SHA1", signature, hash)
+    assert_equal true, key.verify("SHA1", signature, data)
+
+    # Too long data
+    assert_raise(OpenSSL::PKey::PKeyError) {
+      key.sign_raw("SHA1", "x" * (key.n.num_bytes + 1))
+    }
+
+    # With options
+    pssopts = {
+      "rsa_padding_mode" => "pss",
+      "rsa_pss_saltlen" => 20,
+      "rsa_mgf1_md" => "SHA256"
+    }
+    sig_pss = key.sign_raw("SHA1", hash, pssopts)
+    assert_equal true, key.verify("SHA1", sig_pss, data, pssopts)
+    assert_equal true, key.verify_raw("SHA1", sig_pss, hash, pssopts)
   end
 
+  def test_sign_verify_raw_legacy
+    key = Fixtures.pkey("rsa-1")
+    bits = key.n.num_bits
+
+    # Need right size for raw mode
+    plain0 = "x" * (bits/8)
+    cipher = key.private_encrypt(plain0, OpenSSL::PKey::RSA::NO_PADDING)
+    plain1 = key.public_decrypt(cipher, OpenSSL::PKey::RSA::NO_PADDING)
+    assert_equal(plain0, plain1)
+
+    # Need smaller size for pkcs1 mode
+    plain0 = "x" * (bits/8 - 11)
+    cipher1 = key.private_encrypt(plain0, OpenSSL::PKey::RSA::PKCS1_PADDING)
+    plain1 = key.public_decrypt(cipher1, OpenSSL::PKey::RSA::PKCS1_PADDING)
+    assert_equal(plain0, plain1)
+
+    cipherdef = key.private_encrypt(plain0) # PKCS1_PADDING is default
+    plain1 = key.public_decrypt(cipherdef)
+    assert_equal(plain0, plain1)
+    assert_equal(cipher1, cipherdef)
+
+    # Failure cases
+    assert_raise(ArgumentError){ key.private_encrypt() }
+    assert_raise(ArgumentError){ key.private_encrypt("hi", 1, nil) }
+    assert_raise(OpenSSL::PKey::RSAError){ key.private_encrypt(plain0, 666) }
+  end
+
+
   def test_verify_empty_rsa
     rsa = OpenSSL::PKey::RSA.new
     assert_raise(OpenSSL::PKey::PKeyError, "[Bug #12783]") {
@@ -180,6 +199,40 @@
     }
   end
 
+  def test_encrypt_decrypt
+    rsapriv = Fixtures.pkey("rsa-1")
+    rsapub = OpenSSL::PKey.read(rsapriv.public_to_der)
+
+    # Defaults to PKCS #1 v1.5
+    raw = "data"
+    enc = rsapub.encrypt(raw)
+    assert_equal raw, rsapriv.decrypt(enc)
+
+    # Invalid options
+    assert_raise(OpenSSL::PKey::PKeyError) {
+      rsapub.encrypt(raw, { "nonexistent" => "option" })
+    }
+  end
+
+  def test_encrypt_decrypt_legacy
+    rsapriv = Fixtures.pkey("rsa-1")
+    rsapub = OpenSSL::PKey.read(rsapriv.public_to_der)
+
+    # Defaults to PKCS #1 v1.5
+    raw = "data"
+    enc_legacy = rsapub.public_encrypt(raw)
+    assert_equal raw, rsapriv.decrypt(enc_legacy)
+    enc_new = rsapub.encrypt(raw)
+    assert_equal raw, rsapriv.private_decrypt(enc_new)
+
+    # OAEP with default parameters
+    raw = "data"
+    enc_legacy = rsapub.public_encrypt(raw, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
+    assert_equal raw, rsapriv.decrypt(enc_legacy, { "rsa_padding_mode" => "oaep" })
+    enc_new = rsapub.encrypt(raw, { "rsa_padding_mode" => "oaep" })
+    assert_equal raw, rsapriv.private_decrypt(enc_legacy, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
+  end
+
   def test_export
     rsa1024 = Fixtures.pkey("rsa1024")
     key = OpenSSL::PKey::RSA.new
@@ -293,13 +346,15 @@
 
   def test_RSAPublicKey
     rsa1024 = Fixtures.pkey("rsa1024")
+    rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der)
+
     asn1 = OpenSSL::ASN1::Sequence([
       OpenSSL::ASN1::Integer(rsa1024.n),
       OpenSSL::ASN1::Integer(rsa1024.e)
     ])
     key = OpenSSL::PKey::RSA.new(asn1.to_der)
     assert_not_predicate key, :private?
-    assert_same_rsa dup_public(rsa1024), key
+    assert_same_rsa rsa1024pub, key
 
     pem = <<~EOF
     -----BEGIN RSA PUBLIC KEY-----
@@ -309,11 +364,13 @@
     -----END RSA PUBLIC KEY-----
     EOF
     key = OpenSSL::PKey::RSA.new(pem)
-    assert_same_rsa dup_public(rsa1024), key
+    assert_same_rsa rsa1024pub, key
   end
 
   def test_PUBKEY
     rsa1024 = Fixtures.pkey("rsa1024")
+    rsa1024pub = OpenSSL::PKey::RSA.new(rsa1024.public_to_der)
+
     asn1 = OpenSSL::ASN1::Sequence([
       OpenSSL::ASN1::Sequence([
         OpenSSL::ASN1::ObjectId("rsaEncryption"),
@@ -328,7 +385,7 @@
     ])
     key = OpenSSL::PKey::RSA.new(asn1.to_der)
     assert_not_predicate key, :private?
-    assert_same_rsa dup_public(rsa1024), key
+    assert_same_rsa rsa1024pub, key
 
     pem = <<~EOF
     -----BEGIN PUBLIC KEY-----
@@ -339,10 +396,15 @@
     -----END PUBLIC KEY-----
     EOF
     key = OpenSSL::PKey::RSA.new(pem)
-    assert_same_rsa dup_public(rsa1024), key
+    assert_same_rsa rsa1024pub, key
 
-    assert_equal asn1.to_der, dup_public(rsa1024).to_der
-    assert_equal pem, dup_public(rsa1024).export
+    assert_equal asn1.to_der, key.to_der
+    assert_equal pem, key.export
+
+    assert_equal asn1.to_der, rsa1024.public_to_der
+    assert_equal asn1.to_der, key.public_to_der
+    assert_equal pem, rsa1024.public_to_pem
+    assert_equal pem, key.public_to_pem
   end
 
   def test_pem_passwd
@@ -429,18 +491,16 @@
     assert_same_rsa rsa1024, OpenSSL::PKey.read(pem, "abcdef")
   end
 
-  def test_public_encoding
-    rsa1024 = Fixtures.pkey("rsa1024")
-    assert_equal dup_public(rsa1024).to_der, rsa1024.public_to_der
-    assert_equal dup_public(rsa1024).to_pem, rsa1024.public_to_pem
-  end
-
   def test_dup
-    key = Fixtures.pkey("rsa1024")
-    key2 = key.dup
-    assert_equal key.params, key2.params
-    key2.set_key(key2.n, 3, key2.d)
-    assert_not_equal key.params, key2.params
+    key1 = Fixtures.pkey("rsa-1")
+    key1dup = key1.dup
+    key2 = Fixtures.pkey("rsa-2")
+    key2dup = key2.dup
+
+    assert_kind_of OpenSSL::PKey::RSA, key1dup
+    assert_equal key1.to_data, key1dup.to_data
+    assert_not_equal key1.to_data, key2dup.to_data
+    assert_not_equal key1dup.to_data, key2dup.to_data
   end
 
   def test_marshal
@@ -450,6 +510,54 @@
     assert_equal key.to_der, deserialized.to_der
   end
 
+  def test_to_data
+    rsa = Fixtures.pkey("rsa2048")
+
+    # #params
+    params_keys = %w{n e d p q dmp1 dmq1 iqmp}
+    params = rsa.params
+    assert_equal [], params_keys - params.keys
+
+    # #to_data; may contain additional keys
+    data_keys = %w{n e d rsa-factor1 rsa-factor2 rsa-exponent1 rsa-exponent2 rsa-coefficient1}
+    data = rsa.to_data
+    assert_equal [], data_keys.map(&:intern) - data.keys
+
+    # Check value
+    assert_equal rsa.n, params["n"]
+    assert_equal rsa.n, data[:n]
+    assert_equal 2048, rsa.n.num_bits
+
+    params_keys.each_with_index do |pk, i|
+      dk = data_keys[i]
+      getter_value = rsa.public_send(pk)
+
+      assert_kind_of OpenSSL::BN, getter_value
+      assert_equal getter_value, params[pk]
+      assert_equal getter_value, data[dk.intern]
+    end
+  end
+
+  def test_to_data_public
+    rsa = OpenSSL::PKey.read(Fixtures.pkey("rsa2048").public_to_der)
+
+    # params: missing components will be BN 0
+    params = rsa.params
+    assert_equal %w{n e d p q dmp1 dmq1 iqmp}, params.keys
+    assert_equal 65537.to_bn, params["e"]
+    assert_equal 0.to_bn, params["d"]
+
+    # to_data
+    data = rsa.to_data
+    assert_equal [], %i{n e} - data.keys
+    assert_not_include data.keys, :d
+    assert_equal 65537.to_bn, data[:e]
+
+    # #d returns nil
+    assert_equal 65537.to_bn, rsa.e
+    assert_equal nil, rsa.d
+  end
+
   private
   def assert_same_rsa(expected, key)
     check_component(expected, key, [:n, :e, :d, :p, :q, :dmp1, :dmq1, :iqmp])
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_ssl.rb ruby-3.0.2/test/openssl/test_ssl.rb
--- ruby-3.0.2.orig/test/openssl/test_ssl.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_ssl.rb	2021-09-09 18:29:40.443077922 +0800
@@ -99,7 +99,7 @@
         assert_equal ctx, ssl.context
         assert_equal random_port, ssl.io.local_address.ip_port
         ssl.puts "abc"; assert_equal "abc\n", ssl.gets
-      rescue Errno::EADDRINUSE
+      rescue Errno::EADDRINUSE, Errno::EACCES
       ensure
         ssl&.close
       end
@@ -127,21 +127,13 @@
     pend "EC is not supported" unless defined?(OpenSSL::PKey::EC)
     pend "TLS 1.2 is not supported" unless tls12_supported?
 
-    # SSL_CTX_set0_chain() is needed for setting multiple certificate chains
-    add0_chain_supported = openssl?(1, 0, 2)
-
-    if add0_chain_supported
-      ca2_key = Fixtures.pkey("rsa-3")
-      ca2_exts = [
-        ["basicConstraints", "CA:TRUE", true],
-        ["keyUsage", "cRLSign, keyCertSign", true],
-      ]
-      ca2_dn = OpenSSL::X509::Name.parse_rfc2253("CN=CA2")
-      ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil)
-    else
-      # Use the same CA as @svr_cert
-      ca2_key = @ca_key; ca2_cert = @ca_cert
-    end
+    ca2_key = Fixtures.pkey("rsa-3")
+    ca2_exts = [
+      ["basicConstraints", "CA:TRUE", true],
+      ["keyUsage", "cRLSign, keyCertSign", true],
+    ]
+    ca2_dn = OpenSSL::X509::Name.parse_rfc2253("CN=CA2")
+    ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil)
 
     ecdsa_key = Fixtures.pkey("p256")
     exts = [
@@ -150,23 +142,11 @@
     ecdsa_dn = OpenSSL::X509::Name.parse_rfc2253("CN=localhost2")
     ecdsa_cert = issue_cert(ecdsa_dn, ecdsa_key, 456, exts, ca2_cert, ca2_key)
 
-    if !add0_chain_supported
-      # Testing the warning emitted when 'extra' chain is replaced
-      tctx = OpenSSL::SSL::SSLContext.new
-      tctx.add_certificate(@svr_cert, @svr_key, [@ca_cert])
-      assert_warning(/set0_chain/) {
-        tctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert])
-      }
-    end
-
     ctx_proc = -> ctx {
       # Unset values set by start_server
       ctx.cert = ctx.key = ctx.extra_chain_cert = nil
-      ctx.ecdh_curves = "P-256" unless openssl?(1, 0, 2)
       ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA
-      EnvUtil.suppress_warning do # !add0_chain_supported
-        ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert])
-      end
+      ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert])
     }
     start_server(ctx_proc: ctx_proc) do |port|
       ctx = OpenSSL::SSL::SSLContext.new
@@ -205,6 +185,19 @@
     }
   end
 
+  def test_getbyte
+    start_server { |port|
+      server_connect(port) { |ssl|
+        str = +("x" * 100 + "\n")
+        ssl.syswrite(str)
+        newstr = str.bytesize.times.map { |i|
+          ssl.getbyte
+        }.pack("C*")
+        assert_equal(str, newstr)
+      }
+    }
+  end
+
   def test_sync_close
     start_server do |port|
       begin
@@ -246,7 +239,56 @@
     end
   end
 
-  def test_client_auth_failure
+  def test_verify_mode_default
+    ctx = OpenSSL::SSL::SSLContext.new
+    assert_equal OpenSSL::SSL::VERIFY_NONE, ctx.verify_mode
+  end
+
+  def test_verify_mode_server_cert
+    start_server(ignore_listener_error: true) { |port|
+      populated_store = OpenSSL::X509::Store.new
+      populated_store.add_cert(@ca_cert)
+      empty_store = OpenSSL::X509::Store.new
+
+      # Valid certificate, SSL_VERIFY_PEER
+      assert_nothing_raised {
+        ctx = OpenSSL::SSL::SSLContext.new
+        ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
+        ctx.cert_store = populated_store
+        server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets }
+      }
+
+      # Invalid certificate, SSL_VERIFY_NONE
+      assert_nothing_raised {
+        ctx = OpenSSL::SSL::SSLContext.new
+        ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
+        ctx.cert_store = empty_store
+        server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets }
+      }
+
+      # Invalid certificate, SSL_VERIFY_PEER
+      assert_handshake_error {
+        ctx = OpenSSL::SSL::SSLContext.new
+        ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
+        ctx.cert_store = empty_store
+        server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets }
+      }
+    }
+  end
+
+  def test_verify_mode_client_cert_required
+    # Optional, client certificate not supplied
+    vflag = OpenSSL::SSL::VERIFY_PEER
+    accept_proc = -> ssl {
+      assert_equal nil, ssl.peer_cert
+    }
+    start_server(verify_mode: vflag, accept_proc: accept_proc) { |port|
+      assert_nothing_raised {
+        server_connect(port) { |ssl| ssl.puts("abc"); ssl.gets }
+      }
+    }
+
+    # Required, client certificate not supplied
     vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
     start_server(verify_mode: vflag, ignore_listener_error: true) { |port|
       assert_handshake_error {
@@ -257,7 +299,10 @@
 
   def test_client_auth_success
     vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
-    start_server(verify_mode: vflag) { |port|
+    start_server(verify_mode: vflag,
+      ctx_proc: proc { |ctx|
+        ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
+    }) { |port|
       ctx = OpenSSL::SSL::SSLContext.new
       ctx.key = @cli_key
       ctx.cert = @cli_cert
@@ -282,20 +327,16 @@
     }
   end
 
-  def test_client_auth_public_key
+  def test_client_cert_cb_ignore_error
     vflag = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
     start_server(verify_mode: vflag, ignore_listener_error: true) do |port|
-      assert_raise(ArgumentError) {
-        ctx = OpenSSL::SSL::SSLContext.new
-        ctx.key = @cli_key.public_key
-        ctx.cert = @cli_cert
-        server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets }
-      }
-
       ctx = OpenSSL::SSL::SSLContext.new
-      ctx.client_cert_cb = Proc.new{ |ssl|
-        [@cli_cert, @cli_key.public_key]
+      ctx.client_cert_cb = -> ssl {
+        raise "exception in client_cert_cb must be suppressed"
       }
+      # 1. Exception in client_cert_cb is suppressed
+      # 2. No client certificate will be sent to the server
+      # 3. SSL_VERIFY_FAIL_IF_NO_PEER_CERT causes the handshake to fail
       assert_handshake_error {
         server_connect(port, ctx) { |ssl| ssl.puts("abc"); ssl.gets }
       }
@@ -303,6 +344,8 @@
   end
 
   def test_client_ca
+    pend "LibreSSL 3.2 has broken client CA support" if libressl?(3, 2, 0)
+
     ctx_proc = Proc.new do |ctx|
       ctx.client_ca = [@ca_cert]
     end
@@ -478,6 +521,8 @@
     start_server(accept_proc: proc { |server|
       server_finished = server.finished_message
       server_peer_finished = server.peer_finished_message
+    }, ctx_proc: proc { |ctx|
+      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
     }) { |port|
       ctx = OpenSSL::SSL::SSLContext.new
       ctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -551,8 +596,7 @@
 
     exts = [
       ["keyUsage","keyEncipherment,digitalSignature",true],
-      ["subjectAltName","DNS:localhost.localdomain",false],
-      ["subjectAltName","IP:127.0.0.1",false],
+      ["subjectAltName","DNS:localhost.localdomain,IP:127.0.0.1",false],
     ]
     @svr_cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key)
     start_server { |port|
@@ -866,19 +910,49 @@
     sock2.close if sock2
   end
 
+  def test_accept_errors_include_peeraddr
+    context = OpenSSL::SSL::SSLContext.new
+    context.cert = @svr_cert
+    context.key = @svr_key
+
+    server = TCPServer.new("127.0.0.1", 0)
+    port = server.connect_address.ip_port
+
+    ssl_server = OpenSSL::SSL::SSLServer.new(server, context)
+
+    t = Thread.new do
+      assert_raise_with_message(OpenSSL::SSL::SSLError, /peeraddr=127\.0\.0\.1/) do
+        ssl_server.accept
+      end
+    end
+
+    begin
+      sock = TCPSocket.new("127.0.0.1", port)
+      sock.puts "abc"
+    ensure
+      sock&.close
+    end
+
+    assert t.join
+    server.close
+  end
+
   def test_verify_hostname_on_connect
     ctx_proc = proc { |ctx|
+      san = "DNS:a.example.com,DNS:*.b.example.com"
+      san += ",DNS:c*.example.com,DNS:d.*.example.com" unless libressl?(3, 2, 2)
       exts = [
         ["keyUsage", "keyEncipherment,digitalSignature", true],
-        ["subjectAltName", "DNS:a.example.com,DNS:*.b.example.com," \
-                           "DNS:c*.example.com,DNS:d.*.example.com"],
+        ["subjectAltName", san],
       ]
+
       ctx.cert = issue_cert(@svr, @svr_key, 4, exts, @ca_cert, @ca_key)
       ctx.key = @svr_key
     }
 
     start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
       ctx = OpenSSL::SSL::SSLContext.new
+      assert_equal false, ctx.verify_hostname
       ctx.verify_hostname = true
       ctx.cert_store = OpenSSL::X509::Store.new
       ctx.cert_store.add_cert(@ca_cert)
@@ -893,6 +967,7 @@
         ["cx.example.com", true],
         ["d.x.example.com", false],
       ].each do |name, expected_ok|
+        next if name.start_with?('cx') if libressl?(3, 2, 2)
         begin
           sock = TCPSocket.new("127.0.0.1", port)
           ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
@@ -941,10 +1016,7 @@
         ssl.hostname = "b.example.com"
         assert_handshake_error { ssl.connect }
         assert_equal false, verify_callback_ok
-        code_expected = openssl?(1, 0, 2) || defined?(OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH) ?
-          OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH :
-          OpenSSL::X509::V_ERR_CERT_REJECTED
-        assert_equal code_expected, verify_callback_err
+        assert_equal OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH, verify_callback_err
       ensure
         sock&.close
       end
@@ -955,7 +1027,9 @@
     start_server(ignore_listener_error: true) { |port|
       ctx = OpenSSL::SSL::SSLContext.new
       ctx.set_params
-      assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) {
+      # OpenSSL <= 1.1.0: "self signed certificate in certificate chain"
+      # OpenSSL >= 3.0.0: "self-signed certificate in certificate chain"
+      assert_raise_with_message(OpenSSL::SSL::SSLError, /self.signed/) {
         server_connect(port, ctx)
       }
     }
@@ -1234,7 +1308,6 @@
     }
   end
 
-if openssl?(1, 0, 2) || libressl?
   def test_alpn_protocol_selection_ary
     advertised = ["http/1.1", "spdy/2"]
     ctx_proc = Proc.new { |ctx|
@@ -1280,7 +1353,6 @@
     t&.kill
     t&.join
   end
-end
 
   def test_npn_protocol_selection_ary
     pend "TLS 1.2 is not supported" unless tls12_supported?
@@ -1398,11 +1470,6 @@
   end
 
   def test_get_ephemeral_key
-    # OpenSSL >= 1.0.2
-    unless OpenSSL::SSL::SSLSocket.method_defined?(:tmp_key)
-      pend "SSL_get_server_tmp_key() is not supported"
-    end
-
     if tls12_supported?
       # kRSA
       ctx_proc1 = proc { |ctx|
@@ -1533,9 +1600,7 @@
     start_server(ctx_proc: ctx_proc) do |port|
       server_connect(port) { |ssl|
         assert called, "dh callback should be called"
-        if ssl.respond_to?(:tmp_key)
-          assert_equal dh.to_der, ssl.tmp_key.to_der
-        end
+        assert_equal dh.to_der, ssl.tmp_key.to_der
       }
     end
   end
@@ -1557,71 +1622,60 @@
     end
   end
 
-  def test_tmp_ecdh_callback
-    pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)
-    pend "tmp_ecdh_callback is not supported" unless \
-      OpenSSL::SSL::SSLContext.method_defined?(:tmp_ecdh_callback)
-    pend "LibreSSL 2.6 has broken SSL_CTX_set_tmp_ecdh_callback()" \
-      if libressl?(2, 6, 1)
-
-    EnvUtil.suppress_warning do # tmp_ecdh_callback is deprecated (2016-05)
-      called = false
-      ctx_proc = -> ctx {
-        ctx.ciphers = "DEFAULT:!kRSA:!kEDH"
-        ctx.tmp_ecdh_callback = -> (*args) {
-          called = true
-          OpenSSL::PKey::EC.new "prime256v1"
-        }
-      }
-      start_server(ctx_proc: ctx_proc) do |port|
-        server_connect(port) { |s|
-          assert called, "tmp_ecdh_callback should be called"
-        }
-      end
-    end
-  end
-
-  def test_ecdh_curves
+  def test_ecdh_curves_tls12
     pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)
 
     ctx_proc = -> ctx {
       # Enable both ECDHE (~ TLS 1.2) cipher suites and TLS 1.3
-      ctx.ciphers = "DEFAULT:!kRSA:!kEDH"
+      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION
+      ctx.ciphers = "kEECDH"
       ctx.ecdh_curves = "P-384:P-521"
     }
     start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
+      # Test 1: Client=P-256:P-384, Server=P-384:P-521 --> P-384
       ctx = OpenSSL::SSL::SSLContext.new
-      ctx.ecdh_curves = "P-256:P-384" # disable P-521 for OpenSSL >= 1.0.2
-
+      ctx.ecdh_curves = "P-256:P-384"
       server_connect(port, ctx) { |ssl|
         cs = ssl.cipher[0]
-        if /\ATLS/ =~ cs # Is TLS 1.3 is used?
-          assert_equal "secp384r1", ssl.tmp_key.group.curve_name
-        else
-          assert_match (/\AECDH/), cs
-          if ssl.respond_to?(:tmp_key)
-            assert_equal "secp384r1", ssl.tmp_key.group.curve_name
-          end
-        end
+        assert_match (/\AECDH/), cs
+        assert_equal "secp384r1", ssl.tmp_key.group.curve_name
         ssl.puts "abc"; assert_equal "abc\n", ssl.gets
       }
 
-      if openssl?(1, 0, 2) || libressl?(2, 5, 1)
-        ctx = OpenSSL::SSL::SSLContext.new
-        ctx.ecdh_curves = "P-256"
+      # Test 2: Client=P-256, Server=P-521:P-384 --> Fail
+      ctx = OpenSSL::SSL::SSLContext.new
+      ctx.ecdh_curves = "P-256"
+      assert_raise(OpenSSL::SSL::SSLError) {
+        server_connect(port, ctx) { }
+      }
 
-        assert_raise(OpenSSL::SSL::SSLError) {
-          server_connect(port, ctx) { }
-        }
+      # Test 3: Client=P-521:P-384, Server=P-521:P-384 --> P-521
+      ctx = OpenSSL::SSL::SSLContext.new
+      ctx.ecdh_curves = "P-521:P-384"
+      server_connect(port, ctx) { |ssl|
+        assert_equal "secp521r1", ssl.tmp_key.group.curve_name
+        ssl.puts "abc"; assert_equal "abc\n", ssl.gets
+      }
+    end
+  end
 
-        ctx = OpenSSL::SSL::SSLContext.new
-        ctx.ecdh_curves = "P-521:P-384"
+  def test_ecdh_curves_tls13
+    pend "EC is disabled" unless defined?(OpenSSL::PKey::EC)
+    pend "TLS 1.3 not supported" unless tls13_supported?
 
-        server_connect(port, ctx) { |ssl|
-          assert_equal "secp521r1", ssl.tmp_key.group.curve_name
-          ssl.puts "abc"; assert_equal "abc\n", ssl.gets
-        }
-      end
+    ctx_proc = -> ctx {
+      # Assume TLS 1.3 is enabled and chosen by default
+      ctx.ecdh_curves = "P-384:P-521"
+    }
+    start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port|
+      ctx = OpenSSL::SSL::SSLContext.new
+      ctx.ecdh_curves = "P-256:P-384" # disable P-521
+
+      server_connect(port, ctx) { |ssl|
+        assert_equal "TLSv1.3", ssl.ssl_version
+        assert_equal "secp384r1", ssl.tmp_key.group.curve_name
+        ssl.puts "abc"; assert_equal "abc\n", ssl.gets
+      }
     end
   end
 
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_ssl_session.rb ruby-3.0.2/test/openssl/test_ssl_session.rb
--- ruby-3.0.2.orig/test/openssl/test_ssl_session.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_ssl_session.rb	2021-09-09 18:29:40.445077970 +0800
@@ -122,6 +122,7 @@
       ctx.options &= ~OpenSSL::SSL::OP_NO_TICKET
       # Disable server-side session cache which is enabled by default
       ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_OFF
+      ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION if libressl?(3, 2, 0)
     }
     start_server(ctx_proc: ctx_proc) do |port|
       sess1 = server_connect_with_session(port, nil, nil) { |ssl|
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_x509cert.rb ruby-3.0.2/test/openssl/test_x509cert.rb
--- ruby-3.0.2.orig/test/openssl/test_x509cert.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_x509cert.rb	2021-09-09 18:29:40.445077970 +0800
@@ -245,6 +245,18 @@
     }
   end
 
+  def test_read_der_then_pem
+    cert1 = issue_cert(@ca, @rsa2048, 1, [], nil, nil)
+    exts = [
+      # A new line before PEM block
+      ["nsComment", "Another certificate:\n" + cert1.to_pem],
+    ]
+    cert2 = issue_cert(@ca, @rsa2048, 2, exts, nil, nil)
+
+    assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_der)
+    assert_equal cert2, OpenSSL::X509::Certificate.new(cert2.to_pem)
+  end
+
   def test_eq
     now = Time.now
     cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil,
@@ -276,6 +288,38 @@
     assert_equal cert.to_der, deserialized.to_der
   end
 
+  def test_load_file_empty_pem
+    empty_path = Fixtures.file_path("pkey", "empty.pem")
+    assert_raise(OpenSSL::X509::CertificateError) do
+      OpenSSL::X509::Certificate.load_file(empty_path)
+    end
+  end
+
+  def test_load_file_fullchain_pem
+    fullchain_path = Fixtures.file_path("pkey", "fullchain.pem")
+    certificates = OpenSSL::X509::Certificate.load_file(fullchain_path)
+    assert_equal 2, certificates.size
+    assert_equal "/CN=www.codeotaku.com", certificates[0].subject.to_s
+    assert_equal "/C=US/O=Let's Encrypt/CN=R3", certificates[1].subject.to_s
+  end
+
+  def test_load_file_certificate_der
+    fullchain_path = Fixtures.file_path("pkey", "certificate.der")
+    certificates = OpenSSL::X509::Certificate.load_file(fullchain_path)
+
+    # DER encoding can only contain one certificate:
+    assert_equal 1, certificates.size
+    assert_equal "/CN=www.codeotaku.com", certificates[0].subject.to_s
+  end
+
+  def test_load_file_fullchain_garbage
+    fullchain_path = Fixtures.file_path("pkey", "garbage.txt")
+
+    assert_raise(OpenSSL::X509::CertificateError) do
+      certificates = OpenSSL::X509::Certificate.load_file(fullchain_path)
+    end
+  end
+
   private
 
   def certificate_error_returns_false
diff --color -Nuar ruby-3.0.2.orig/test/openssl/test_x509store.rb ruby-3.0.2/test/openssl/test_x509store.rb
--- ruby-3.0.2.orig/test/openssl/test_x509store.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/test_x509store.rb	2021-09-09 18:29:40.445077970 +0800
@@ -4,37 +4,27 @@
 if defined?(OpenSSL)
 
 class OpenSSL::TestX509Store < OpenSSL::TestCase
-  def setup
-    super
-    @rsa1024 = Fixtures.pkey("rsa1024")
-    @rsa2048 = Fixtures.pkey("rsa2048")
-    @dsa256  = Fixtures.pkey("dsa256")
-    @dsa512  = Fixtures.pkey("dsa512")
-    @ca1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA1")
-    @ca2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA2")
-    @ee1 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE1")
-    @ee2 = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=EE2")
-  end
-
-  def test_nosegv_on_cleanup
-    cert  = OpenSSL::X509::Certificate.new
-    store = OpenSSL::X509::Store.new
-    ctx   = OpenSSL::X509::StoreContext.new(store, cert, [])
-    EnvUtil.suppress_warning do
-      ctx.cleanup
-    end
-    ctx.verify
+  def test_store_new
+    # v2.3.0 emits explicit warning
+    assert_warning(/new does not take any arguments/) {
+      OpenSSL::X509::Store.new(123)
+    }
   end
 
-  def test_add_file
+  def test_add_file_path
     ca_exts = [
       ["basicConstraints", "CA:TRUE", true],
       ["keyUsage", "cRLSign,keyCertSign", true],
     ]
-    cert1 = issue_cert(@ca1, @rsa1024, 1, ca_exts, nil, nil)
-    cert2 = issue_cert(@ca2, @rsa2048, 1, ca_exts, nil, nil)
-    tmpfile = Tempfile.open { |f| f << cert1.to_pem << cert2.to_pem; f }
+    cert1_subj = OpenSSL::X509::Name.parse_rfc2253("CN=Cert 1")
+    cert1_key = Fixtures.pkey("rsa-1")
+    cert1 = issue_cert(cert1_subj, cert1_key, 1, ca_exts, nil, nil)
+    cert2_subj = OpenSSL::X509::Name.parse_rfc2253("CN=Cert 2")
+    cert2_key = Fixtures.pkey("rsa-2")
+    cert2 = issue_cert(cert2_subj, cert2_key, 1, ca_exts, nil, nil)
 
+    # X509::Store#add_file reads concatenated PEM file
+    tmpfile = Tempfile.open { |f| f << cert1.to_pem << cert2.to_pem; f }
     store = OpenSSL::X509::Store.new
     assert_equal false, store.verify(cert1)
     assert_equal false, store.verify(cert2)
@@ -42,188 +32,322 @@
     assert_equal true, store.verify(cert1)
     assert_equal true, store.verify(cert2)
 
+    # X509::Store#add_path
+    Dir.mktmpdir do |dir|
+      hash1 = "%08x.%d" % [cert1_subj.hash, 0]
+      File.write(File.join(dir, hash1), cert1.to_pem)
+      store = OpenSSL::X509::Store.new
+      store.add_path(dir)
+
+      assert_equal true, store.verify(cert1)
+      assert_equal false, store.verify(cert2)
+    end
+
     # OpenSSL < 1.1.1 leaks an error on a duplicate certificate
     assert_nothing_raised { store.add_file(tmpfile.path) }
     assert_equal [], OpenSSL.errors
+
+    # Non-String is given
+    assert_raise(TypeError) { store.add_file(nil) }
   ensure
     tmpfile and tmpfile.close!
   end
 
-  def test_verify
-    # OpenSSL uses time(2) while Time.now uses clock_gettime(CLOCK_REALTIME),
-    # and there may be difference.
-    now = Time.now - 3
+  def test_verify_simple
     ca_exts = [
-      ["basicConstraints","CA:TRUE",true],
-      ["keyUsage","cRLSign,keyCertSign",true],
+      ["basicConstraints", "CA:TRUE", true],
+      ["keyUsage", "cRLSign,keyCertSign", true],
     ]
+    ca1 = OpenSSL::X509::Name.parse_rfc2253("CN=Root CA")
+    ca1_key = Fixtures.pkey("rsa-1")
+    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)
+    ca2 = OpenSSL::X509::Name.parse_rfc2253("CN=Intermediate CA")
+    ca2_key = Fixtures.pkey("rsa-2")
+    ca2_cert = issue_cert(ca2, ca2_key, 2, ca_exts, ca1_cert, ca1_key)
+
     ee_exts = [
-      ["keyUsage","keyEncipherment,digitalSignature",true],
+      ["keyUsage", "keyEncipherment,digitalSignature", true],
     ]
-    ca1_cert = issue_cert(@ca1, @rsa2048, 1, ca_exts, nil, nil)
-    ca2_cert = issue_cert(@ca2, @rsa1024, 2, ca_exts, ca1_cert, @rsa2048,
-                          not_after: now+1800)
-    ee1_cert = issue_cert(@ee1, @dsa256, 10, ee_exts, ca2_cert, @rsa1024)
-    ee2_cert = issue_cert(@ee2, @dsa512, 20, ee_exts, ca2_cert, @rsa1024)
-    ee3_cert = issue_cert(@ee2, @dsa512, 30,  ee_exts, ca2_cert, @rsa1024,
-                          not_before: now-100, not_after: now-50)
-    ee4_cert = issue_cert(@ee2, @dsa512, 40, ee_exts, ca2_cert, @rsa1024,
-                          not_before: now+1000, not_after: now+2000,)
+    ee1 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 1")
+    ee1_key = Fixtures.pkey("rsa-3")
+    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca2_cert, ca2_key)
 
-    revoke_info = []
-    crl1   = issue_crl(revoke_info, 1, now, now+1800, [],
-                       ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
-    revoke_info = [ [2, now, 1], ]
-    crl1_2 = issue_crl(revoke_info, 2, now, now+1800, [],
-                       ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
-    revoke_info = [ [20, now, 1], ]
-    crl2   = issue_crl(revoke_info, 1, now, now+1800, [],
-                       ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA1'))
-    revoke_info = []
-    crl2_2 = issue_crl(revoke_info, 2, now-100, now-1, [],
-                       ca2_cert, @rsa1024, OpenSSL::Digest.new('SHA1'))
+    # Nothing trusted
+    store = OpenSSL::X509::Store.new
+    assert_equal(false, store.verify(ee1_cert, [ca2_cert, ca1_cert]))
+    assert_equal(OpenSSL::X509::V_ERR_SELF_SIGNED_CERT_IN_CHAIN, store.error)
+    assert_match(/self.signed/i, store.error_string)
 
-    assert_equal(true, ca1_cert.verify(ca1_cert.public_key))   # self signed
-    assert_equal(true, ca2_cert.verify(ca1_cert.public_key))   # issued by ca1
-    assert_equal(true, ee1_cert.verify(ca2_cert.public_key))   # issued by ca2
-    assert_equal(true, ee2_cert.verify(ca2_cert.public_key))   # issued by ca2
-    assert_equal(true, ee3_cert.verify(ca2_cert.public_key))   # issued by ca2
-    assert_equal(true, crl1.verify(ca1_cert.public_key))       # issued by ca1
-    assert_equal(true, crl1_2.verify(ca1_cert.public_key))     # issued by ca1
-    assert_equal(true, crl2.verify(ca2_cert.public_key))       # issued by ca2
-    assert_equal(true, crl2_2.verify(ca2_cert.public_key))     # issued by ca2
+    # CA1 trusted, CA2 missing
+    store = OpenSSL::X509::Store.new
+    store.add_cert(ca1_cert)
+    assert_equal(false, store.verify(ee1_cert))
+    assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, store.error)
 
+    # CA1 trusted, CA2 supplied
     store = OpenSSL::X509::Store.new
-    assert_equal(false, store.verify(ca1_cert))
-    assert_not_equal(OpenSSL::X509::V_OK, store.error)
+    store.add_cert(ca1_cert)
+    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))
+    assert_match(/ok/i, store.error_string)
+    assert_equal(OpenSSL::X509::V_OK, store.error)
+    assert_equal([ee1_cert, ca2_cert, ca1_cert], store.chain)
+  end
 
-    assert_equal(false, store.verify(ca2_cert))
-    assert_not_equal(OpenSSL::X509::V_OK, store.error)
+  def test_verify_callback
+    ca_exts = [
+      ["basicConstraints", "CA:TRUE", true],
+      ["keyUsage", "cRLSign,keyCertSign", true],
+    ]
+    ca1 = OpenSSL::X509::Name.parse_rfc2253("CN=Root CA")
+    ca1_key = Fixtures.pkey("rsa-1")
+    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)
+    ca2 = OpenSSL::X509::Name.parse_rfc2253("CN=Intermediate CA")
+    ca2_key = Fixtures.pkey("rsa-2")
+    ca2_cert = issue_cert(ca2, ca2_key, 2, ca_exts, ca1_cert, ca1_key)
+
+    ee_exts = [
+      ["keyUsage", "keyEncipherment,digitalSignature", true],
+    ]
+    ee1 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 1")
+    ee1_key = Fixtures.pkey("rsa-3")
+    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca2_cert, ca2_key)
 
+    # verify_callback on X509::Store is called with proper arguments
+    cb_calls = []
+    store = OpenSSL::X509::Store.new
+    store.verify_callback = -> (preverify_ok, sctx) {
+      cb_calls << [preverify_ok, sctx.current_cert]
+      preverify_ok
+    }
     store.add_cert(ca1_cert)
-    assert_equal(true, store.verify(ca2_cert))
-    assert_equal(OpenSSL::X509::V_OK, store.error)
-    assert_equal("ok", store.error_string)
-    chain = store.chain
-    assert_equal(2, chain.size)
-    assert_equal(@ca2.to_der, chain[0].subject.to_der)
-    assert_equal(@ca1.to_der, chain[1].subject.to_der)
+    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))
+    assert_include([2, 3, 4, 5], cb_calls.size)
+    cb_calls.each do |pre_ok, cert|
+      assert_equal(true, pre_ok)
+      assert_include([ca1_cert, ca2_cert, ee1_cert], cert)
+    end
 
-    store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
-    assert_equal(false, store.verify(ca2_cert))
-    assert_not_equal(OpenSSL::X509::V_OK, store.error)
+    # verify_callback can change verification result
+    store = OpenSSL::X509::Store.new
+    store.verify_callback = -> (preverify_ok, sctx) {
+      next preverify_ok if sctx.current_cert != ee1_cert
+      sctx.error = OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION
+      false
+    }
+    store.add_cert(ca1_cert)
+    assert_equal(false, store.verify(ee1_cert, [ca2_cert]))
+    assert_equal(OpenSSL::X509::V_ERR_APPLICATION_VERIFICATION, store.error)
 
-    store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN
-    assert_equal(true, store.verify(ca2_cert))
-    assert_equal(OpenSSL::X509::V_OK, store.error)
+    # Exception raised by verify_callback is currently suppressed, and is
+    # treated as a non-truthy return (with warning)
+    store = OpenSSL::X509::Store.new
+    store.verify_callback = -> (preverify_ok, sctx) {
+      raise "suppressed"
+    }
+    store.add_cert(ca1_cert)
+    assert_warning(/exception in verify_callback/) {
+      assert_equal(false, store.verify(ee1_cert, [ca2_cert]))
+    }
 
-    store.add_cert(ca2_cert)
-    store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
-    assert_equal(true, store.verify(ee1_cert))
-    assert_equal(true, store.verify(ee2_cert))
-    assert_equal(OpenSSL::X509::V_OK, store.error)
-    assert_equal("ok", store.error_string)
-    chain = store.chain
-    assert_equal(3, chain.size)
-    assert_equal(@ee2.to_der, chain[0].subject.to_der)
-    assert_equal(@ca2.to_der, chain[1].subject.to_der)
-    assert_equal(@ca1.to_der, chain[2].subject.to_der)
-    assert_equal(false, store.verify(ee3_cert), "now=#{now.inspect} Time.now=#{Time.now.inspect} store=#{store.inspect} ee3_cert=#{ee3_cert.inspect}")
-    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
-    assert_match(/expire/i, store.error_string)
-    assert_equal(false, store.verify(ee4_cert))
-    assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)
-    assert_match(/not yet valid/i, store.error_string)
+    # The block given to X509::Store#verify replaces it
+    called = nil
+    store = OpenSSL::X509::Store.new
+    store.verify_callback = -> (preverify_ok, sctx) { called = :store; preverify_ok }
+    store.add_cert(ca1_cert)
+    blk = proc { |preverify_ok, sctx| called = :block; preverify_ok }
+    assert_equal(true, store.verify(ee1_cert, [ca2_cert], &blk))
+    assert_equal(:block, called)
+  end
+
+  def test_verify_purpose
+    ca_exts = [
+      ["basicConstraints", "CA:TRUE", true],
+      ["keyUsage", "cRLSign,keyCertSign", true],
+    ]
+    ca1 = OpenSSL::X509::Name.parse_rfc2253("CN=Root CA")
+    ca1_key = Fixtures.pkey("rsa-1")
+    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)
 
+    ee_exts = [
+      ["keyUsage", "keyEncipherment,digitalSignature", true],
+    ]
+    ee1 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 1")
+    ee1_key = Fixtures.pkey("rsa-3")
+    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca1_cert, ca1_key)
+
+    # Purpose not set
     store = OpenSSL::X509::Store.new
     store.add_cert(ca1_cert)
-    store.add_cert(ca2_cert)
-    store.time = now + 1500
     assert_equal(true, store.verify(ca1_cert))
-    assert_equal(true, store.verify(ca2_cert))
-    assert_equal(true, store.verify(ee4_cert))
-    store.time = now + 1900
+    assert_equal(true, store.verify(ee1_cert))
+
+    # Purpose set to X509::PURPOSE_SSL_CLIENT; keyUsage is checked
+    store = OpenSSL::X509::Store.new
+    store.purpose = OpenSSL::X509::PURPOSE_CRL_SIGN
+    store.add_cert(ca1_cert)
     assert_equal(true, store.verify(ca1_cert))
-    assert_equal(false, store.verify(ca2_cert))
-    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
-    assert_equal(false, store.verify(ee4_cert))
-    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
-    store.time = now + 4000
     assert_equal(false, store.verify(ee1_cert))
-    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
-    assert_equal(false, store.verify(ee4_cert))
-    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
+  end
+
+  def test_verify_validity_period
+    # Creating test certificates with validity periods:
+    #
+    #  now-5000                 now-1000    now+1000                  now+5000
+    # CA1:|---------------------------------------------------------------|
+    # EE1:|---------------------------------------------------------------|
+    # EE2:|-------------------------|
+    # EE3:                                      |-------------------------|
+    now = Time.now
+    ca_exts = [
+      ["basicConstraints", "CA:TRUE", true],
+      ["keyUsage", "cRLSign,keyCertSign", true],
+    ]
+    ca1 = OpenSSL::X509::Name.parse_rfc2253("CN=Root CA")
+    ca1_key = Fixtures.pkey("rsa-1")
+    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil,
+                          not_before: now - 5000, not_after: now + 5000)
 
-    # the underlying X509 struct caches the result of the last
-    # verification for signature and not-before. so the following code
-    # rebuilds new objects to avoid site effect.
-    store.time = Time.now - 4000
-    assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ca2_cert)))
+    ee_exts = [
+      ["keyUsage", "keyEncipherment,digitalSignature", true],
+    ]
+    ee1 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 1")
+    ee1_key = Fixtures.pkey("rsa-1")
+    ee1_cert = issue_cert(ee1, ee1_key, 11, ee_exts, ca1_cert, ca1_key,
+                          not_before: now - 5000, not_after: now + 5000)
+    ee2 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 2")
+    ee2_key = Fixtures.pkey("rsa-2")
+    ee2_cert = issue_cert(ee2, ee2_key, 12, ee_exts, ca1_cert, ca1_key,
+                          not_before: now - 5000, not_after: now - 1000)
+    ee3 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 3")
+    ee3_key = Fixtures.pkey("rsa-3")
+    ee3_cert = issue_cert(ee3, ee3_key, 13, ee_exts, ca1_cert, ca1_key,
+                          not_before: now + 1000, not_after: now + 5000)
+
+    # Using system time
+    store = OpenSSL::X509::Store.new
+    store.add_cert(ca1_cert)
+    assert_equal(true, store.verify(ee1_cert))
+    assert_equal(false, store.verify(ee2_cert))
+    assert_equal(OpenSSL::X509::V_ERR_CERT_HAS_EXPIRED, store.error)
+    assert_equal(false, store.verify(ee3_cert))
     assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)
-    assert_equal(false, store.verify(OpenSSL::X509::Certificate.new(ee1_cert)))
+
+    # Time set to now-2000; EE2 is still valid
+    store = OpenSSL::X509::Store.new
+    store.time = now - 2000
+    store.add_cert(ca1_cert)
+    assert_equal(true, store.verify(ee1_cert))
+    assert_equal(true, store.verify(ee2_cert))
+    assert_equal(false, store.verify(ee3_cert))
     assert_equal(OpenSSL::X509::V_ERR_CERT_NOT_YET_VALID, store.error)
+  end
+
+  def test_verify_with_crl
+    ca_exts = [
+      ["basicConstraints", "CA:TRUE", true],
+      ["keyUsage", "cRLSign,keyCertSign", true],
+    ]
+    ca1 = OpenSSL::X509::Name.parse_rfc2253("CN=Root CA")
+    ca1_key = Fixtures.pkey("rsa-1")
+    ca1_cert = issue_cert(ca1, ca1_key, 1, ca_exts, nil, nil)
+    ca2 = OpenSSL::X509::Name.parse_rfc2253("CN=Intermediate CA")
+    ca2_key = Fixtures.pkey("rsa-2")
+    ca2_cert = issue_cert(ca2, ca2_key, 2, ca_exts, ca1_cert, ca1_key)
+
+    ee_exts = [
+      ["keyUsage", "keyEncipherment,digitalSignature", true],
+    ]
+    ee1 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 1")
+    ee1_key = Fixtures.pkey("rsa-3")
+    ee1_cert = issue_cert(ee1, ee1_key, 10, ee_exts, ca2_cert, ca2_key)
+    ee2 = OpenSSL::X509::Name.parse_rfc2253("CN=EE 2")
+    ee2_key = Fixtures.pkey("rsa-3")
+    ee2_cert = issue_cert(ee2, ee2_key, 20, ee_exts, ca2_cert, ca2_key)
 
+    # OpenSSL uses time(2) while Time.now uses clock_gettime(CLOCK_REALTIME),
+    # and there may be difference, so giving 50 seconds margin.
+    now = Time.now - 50
+    revoke_info = []
+    ca1_crl1 = issue_crl(revoke_info, 1, now, now+1800, [], ca1_cert, ca1_key, "sha256")
+    revoke_info = [ [2, now, 1], ]
+    ca1_crl2 = issue_crl(revoke_info, 2, now, now+1800, [], ca1_cert, ca1_key, "sha256")
+
+    revoke_info = [ [20, now, 1], ]
+    ca2_crl1 = issue_crl(revoke_info, 1, now, now+1800, [], ca2_cert, ca2_key, "sha256")
+    revoke_info = []
+    ca2_crl2 = issue_crl(revoke_info, 2, now-100, now-1, [], ca2_cert, ca2_key, "sha256")
+
+    # CRL check required, but no CRL supplied
     store = OpenSSL::X509::Store.new
-    store.purpose = OpenSSL::X509::PURPOSE_ANY
     store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK
     store.add_cert(ca1_cert)
-    store.add_crl(crl1)   # revoke no cert
-    store.add_crl(crl2)   # revoke ee2_cert
-    assert_equal(true,  store.verify(ca1_cert))
-    assert_equal(true,  store.verify(ca2_cert))
-    assert_equal(true,  store.verify(ee1_cert, [ca2_cert]))
+    assert_equal(false, store.verify(ca2_cert))
+    assert_equal(OpenSSL::X509::V_ERR_UNABLE_TO_GET_CRL, store.error)
+
+    # Intermediate CA revoked EE2
+    store = OpenSSL::X509::Store.new
+    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK
+    store.add_cert(ca1_cert)
+    store.add_crl(ca1_crl1) # revoke no cert
+    store.add_crl(ca2_crl1) # revoke ee2_cert
+    assert_equal(true, store.verify(ca2_cert))
+    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))
     assert_equal(false, store.verify(ee2_cert, [ca2_cert]))
 
+    # Root CA revoked Intermediate CA; Intermediate CA revoked EE2
     store = OpenSSL::X509::Store.new
-    store.purpose = OpenSSL::X509::PURPOSE_ANY
     store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK
     store.add_cert(ca1_cert)
-    store.add_crl(crl1_2) # revoke ca2_cert
-    store.add_crl(crl2)   # revoke ee2_cert
-    assert_equal(true,  store.verify(ca1_cert))
+    store.add_crl(ca1_crl2) # revoke ca2_cert
+    store.add_crl(ca2_crl1) # revoke ee2_cert
     assert_equal(false, store.verify(ca2_cert))
-    assert_equal(true,  store.verify(ee1_cert, [ca2_cert]),
-      "This test is expected to be success with OpenSSL 0.9.7c or later.")
+    # Validity of intermediate CAs is not checked by default
+    assert_equal(true, store.verify(ee1_cert, [ca2_cert]))
     assert_equal(false, store.verify(ee2_cert, [ca2_cert]))
 
-    store.flags =
-      OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
-    assert_equal(true,  store.verify(ca1_cert))
+    # Same as above, but with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
+    store = OpenSSL::X509::Store.new
+    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
+    store.add_cert(ca1_cert)
+    store.add_crl(ca1_crl2) # revoke ca2_cert
+    store.add_crl(ca2_crl1) # revoke ee2_cert
     assert_equal(false, store.verify(ca2_cert))
     assert_equal(false, store.verify(ee1_cert, [ca2_cert]))
     assert_equal(false, store.verify(ee2_cert, [ca2_cert]))
 
+    # Expired CRL supplied
     store = OpenSSL::X509::Store.new
-    store.purpose = OpenSSL::X509::PURPOSE_ANY
-    store.flags =
-      OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
+    store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK|OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
     store.add_cert(ca1_cert)
     store.add_cert(ca2_cert)
-    store.add_crl(crl1)
-    store.add_crl(crl2_2) # issued by ca2 but expired.
-    assert_equal(true, store.verify(ca1_cert))
+    store.add_crl(ca1_crl1)
+    store.add_crl(ca2_crl2) # issued by ca2 but expired
     assert_equal(true, store.verify(ca2_cert))
     assert_equal(false, store.verify(ee1_cert))
     assert_equal(OpenSSL::X509::V_ERR_CRL_HAS_EXPIRED, store.error)
     assert_equal(false, store.verify(ee2_cert))
   end
 
-  def test_set_errors
+  def test_add_cert_duplicate
+    # Up until OpenSSL 1.1.0, X509_STORE_add_{cert,crl}() returned an error
+    # if the given certificate is already in the X509_STORE
     return if openssl?(1, 1, 0) || libressl?
-    now = Time.now
-    ca1_cert = issue_cert(@ca1, @rsa2048, 1, [], nil, nil)
+    ca1 = OpenSSL::X509::Name.parse_rfc2253("CN=Root CA")
+    ca1_key = Fixtures.pkey("rsa-1")
+    ca1_cert = issue_cert(ca1, ca1_key, 1, [], nil, nil)
     store = OpenSSL::X509::Store.new
     store.add_cert(ca1_cert)
     assert_raise(OpenSSL::X509::StoreError){
       store.add_cert(ca1_cert)  # add same certificate twice
     }
 
+    now = Time.now
     revoke_info = []
     crl1 = issue_crl(revoke_info, 1, now, now+1800, [],
-                     ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+                     ca1_cert, ca1_key, "sha256")
     revoke_info = [ [2, now, 1], ]
     crl2 = issue_crl(revoke_info, 2, now+1800, now+3600, [],
-                     ca1_cert, @rsa2048, OpenSSL::Digest.new('SHA1'))
+                     ca1_cert, ca1_key, "sha256")
     store.add_crl(crl1)
     assert_raise(OpenSSL::X509::StoreError){
       store.add_crl(crl2) # add CRL issued by same CA twice.
@@ -236,6 +360,14 @@
     ctx = OpenSSL::X509::StoreContext.new(store)
     assert_raise(NoMethodError) { ctx.dup }
   end
+
+  def test_ctx_cleanup
+    # Deprecated in Ruby 1.9.3
+    cert  = OpenSSL::X509::Certificate.new
+    store = OpenSSL::X509::Store.new
+    ctx   = OpenSSL::X509::StoreContext.new(store, cert, [])
+    assert_warning(/cleanup/) { ctx.cleanup }
+  end
 end
 
 end
diff --color -Nuar ruby-3.0.2.orig/test/openssl/ut_eof.rb ruby-3.0.2/test/openssl/ut_eof.rb
--- ruby-3.0.2.orig/test/openssl/ut_eof.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/ut_eof.rb	2021-09-09 18:29:40.445077970 +0800
@@ -4,6 +4,10 @@
 if defined?(OpenSSL)
 
 module OpenSSL::TestEOF
+  def test_getbyte_eof
+    open_file("") {|f| assert_nil f.getbyte }
+  end
+
   def test_eof_0
     open_file("") {|f|
       assert_equal("", f.read(0))
diff --color -Nuar ruby-3.0.2.orig/test/openssl/utils.rb ruby-3.0.2/test/openssl/utils.rb
--- ruby-3.0.2.orig/test/openssl/utils.rb	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/openssl/utils.rb	2021-09-09 18:29:40.445077970 +0800
@@ -42,9 +42,6 @@
 
     def pkey(name)
       OpenSSL::PKey.read(read_file("pkey", name))
-    rescue OpenSSL::PKey::PKeyError
-      # TODO: DH parameters can be read by OpenSSL::PKey.read atm
-      OpenSSL::PKey::DH.new(read_file("pkey", name))
     end
 
     def read_file(category, name)
@@ -199,6 +196,14 @@
   rescue
   end
 
+  def tls13_supported?
+    return false unless defined?(OpenSSL::SSL::TLS1_3_VERSION)
+    ctx = OpenSSL::SSL::SSLContext.new
+    ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_3_VERSION
+    true
+  rescue
+  end
+
   def readwrite_loop(ctx, ssl)
     while line = ssl.gets
       ssl.write(line)
@@ -308,32 +313,6 @@
       assert_equal base.send(comp), test.send(comp)
     }
   end
-
-  def dup_public(key)
-    case key
-    when OpenSSL::PKey::RSA
-      rsa = OpenSSL::PKey::RSA.new
-      rsa.set_key(key.n, key.e, nil)
-      rsa
-    when OpenSSL::PKey::DSA
-      dsa = OpenSSL::PKey::DSA.new
-      dsa.set_pqg(key.p, key.q, key.g)
-      dsa.set_key(key.pub_key, nil)
-      dsa
-    when OpenSSL::PKey::DH
-      dh = OpenSSL::PKey::DH.new
-      dh.set_pqg(key.p, nil, key.g)
-      dh
-    else
-      if defined?(OpenSSL::PKey::EC) && OpenSSL::PKey::EC === key
-        ec = OpenSSL::PKey::EC.new(key.group)
-        ec.public_key = key.public_key
-        ec
-      else
-        raise "unknown key type"
-      end
-    end
-  end
 end
 
 module OpenSSL::Certs
diff --color -Nuar ruby-3.0.2.orig/test/rubygems/encrypted_private_key.pem ruby-3.0.2/test/rubygems/encrypted_private_key.pem
--- ruby-3.0.2.orig/test/rubygems/encrypted_private_key.pem	2021-07-07 18:08:35.000000000 +0800
+++ ruby-3.0.2/test/rubygems/encrypted_private_key.pem	2021-09-09 18:58:55.604228096 +0800
@@ -1,30 +1,30 @@
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-CBC,4E38D58B5A059DB6
-
-IgWLfnHVnkErKkhysrUMoE0ubkRDtJXZv9KR02jGGFk/kGqWyTqPk08uzhwVNM+l
-eOk0qfPykkJM3KZgqTsD6xfA1D5WqFp5mLoFXVVTn9I3acSZsqOY0FweCipwdVpI
-x+9Fl+v62kIW06dOjyWLE1abed9hHiXesGGsD87/RJSywy4OBxOcrhR1fJLK4ElR
-ya0UzI7rWnmZMChjaZBssfzT1DR79/dARXhon2m5EiIJDjMpc8BKGYlQy5RHCHwA
-cnrhUTTvsggZbQtmLZ/yVx8FSJ273XpYR0pmwbw4j1R+zeXQRK5MroBnCfOGcYa7
-rmpERmDW3VAuxXR20SUAGdo1XOMTDe1uLbaotn6e56pXghIaYROTPS+HsuOkAZGY
-OYWEkUoyog4l4n+h/C1umFfTFGvKNATLgDugONFvTw/PLbjvl+sWMy2QfqH0MlNB
-DIUPxhEVCFD9oB4nfB86WDAmPp1DH9/IBet/21kbQ2eTIzakTdG3XiC+xzAQRu68
-EOCTbasFWGxlCix66gt4xWMLksEg8UhWSpjS3/HsifrKyNMB8sfUFYmZmOYMW4mf
-NuEtpBL3AdHNObN8nQ75HfehukzNpbYVRsLzWrVgtxvXHVpnvoCCpCvQBMHeRZxK
-6m028mhH1m6yYE/uGFiRKLrN7BKAttbUiqnGgVIg/lQQilFWwylxQ6aXqJGmNgxa
-oihzWZRlXivIhhrM7VMnLoKAF/YfmWpP3zahGpBQGfObtPtm44R0ezXPdtsivnyu
-CmFOPGzRNMKZtH/lwVhuIIK3AFIGDsRRP9ySN4YfjQZnTdu2sRlxBnANP9m8W9T2
-p+C4zVkDYAbsuWq2HpHwsdL8gqIiXeptsHLqkNw+ulSSLyeBCgM9fpV3RsNGjwqu
-k8QLb1CYp2VX46CE8UKvOd/nyFnEsD+EAc3WangEwA41m2IaXcbs9Au7xsG9oacZ
-DrxlJVNxlxO9YyP9dNOTfP0fHIiygKQQY2aU3y3oRneu7ogYES5V2mUNH7cYUWVL
-CHPXAoUXJErvDQ/opW2DroA9Eqv9sST6WqBf6LXRcWU0ntfzcFUbEqgmCmB7Cbu2
-8udEn6iWilQahLyDoAShLkU7+Tk78Z1c6RuqjyY4VboZPzxrTYK8YIXzwX+jj9bG
-KIIGS5eghK185+AjlwtzJ7MBdoL323YIik6uOZluhnJHLaxjxUXGa1VqDgsyqGi7
-ISRMTpVTrbR+UtoEi4ZhMjobtFUr7lGkt24VkXwBKdoyryj4RPHGdp7Tf6XDJufQ
-+KKhqt8QrpOTPiMskFN2disOSF5/YZCmtT84nkhU7Hf1lkQ2kfx1zfNk0GqYYXOW
-zHOAczy8gWBRetDMnhRYohDzQGWn//b+2Wr2n1RD8D9kyjMRhpFMYfQGfRcuPGjW
-91k/T0XFcjcjeZPL9s+HITmrh7zg5WxbCfTEp91j3Oy1bns196SY77TE0BzUsqR2
-geJggcUMEfyvHiiCMtijmSSD9nf8tNIxLVL8Jaf1coA6e1CrlHnYAu2f/Q3GIcvU
-EEEmw+cZRwsk4fffYzh5psxxGdXKBv1KcQ/CeBhZL0WJsCp2y5oxwg==
------END RSA PRIVATE KEY-----
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI/hRgqHwssPgCAggA
+MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAECBBCGeetYsy5jvm09r6glISLDBIIE
+0Dub6HMbkDr7yYoTxM/ktX3J4b8LWSJHx6bhI1E/ZI+DThKwCWN3w3RBxY7413e0
+R6USkiiwDbAXDftunaDKh3+FDHLtdMKdT3iRelBMgzuW1/dlRL7qYx69cowysKoP
+WIrRqzenzqfE+YiyL9vETZFqZJEnr447wbIkqw88crlu4WNVZBlacbR/4OVCXztC
+tszCuptvAPThRnZA2wdbFxOeUmIXFWH38XyvOqlzL8NdfIsLBOQzqW6XXTuu1xzL
+RT8fH8EBZ2NXi6qwtBw0dGB8zhKXpnAJCJEhXTn+6oYYKC0AVAIy95pUlzhwVvuw
+bxd/TeN81i4dfnkkw00y9kOF27F2YMyTNsW+MGV4FptASTh5/7CK9DKKmaVlflcy
+DS8IPm2sPVCDIdf4tyNFIJK1MK3VitD7+l6qAfUMDPuVf3Z9idPYRg3XjmfzAz2i
+kix3IlSGUGxiIaP+surT1Xgg5YnbOJtcZLwb/j3OwyIowr7c3MMlpzBQHPFW8mh7
+ZALuDnUgRSCRXDXjomfLGYgEqmMK3Gp8a57H3SCdAQ42Gs9G/lLBQeDnIxkc7A2Q
+Dhf1u62+11PDpCV0+pZxH/10dNJTCmT+7Hv2hn6sBhrR1Fy4nrhLuo3/DpcH/+rW
+ZFXZkqYpGqKvFS+miy+oacNl9oSZduy1P3U4d67DVGH/K7NEgaMzlkL+L1bMGWGO
+UgTN0lCJDhv6+T1iJLde1NDPlBMsHgIoiVDdTvPHYXTZpyF3/EXcQCPcz+IgovG6
+dJqjSiFLRUXN5NKAKd+x6WWSaTmsS49hb92Xz9QyGlyF6n5Pt4FseQpiFaifQeqy
+F0lee59xBY6TRwdzaNGYwuJzDmHDJv1HGoxQJTmb8TNyd+vkGasPDeeuYLpXCSne
+j58CDOAF1kZCmA6IzGneJ7eHOrF6Xd4z7tNntqJ+0gefb0gUZRxefrQxLh7YPqV7
+wxO4DrDG+GmUJGQ9YdSFOvfx0H3t6DeWOE5MPlZtnn+lteU9LVo1HdOSVHmGTrQL
+GHj/j/U1tSvKpPzDeHbVoYnlU091HUfZ3Lmt/TuY5JODEI87o6BIqaJCsx1q1zUH
+y1PY9hOdTje8h9IAn7bB3xJniXwSTDZQVGtltXnOo02SwFHE0DjiWdLet+4/1rIE
+JlFCUVm/91e7e43yGIH59RcBi6MzUOlMmuKhn9MVVJhrXQuCWmg2ZaNka63yRAUQ
+pJr0LbmRTvhBvR/EgD2sPg0iUcSc1qvNv28dyFuiBT/aeC4/vYEehYz8jFpUVPN3
+/KMK+e91W6tyWUoBW7QxPGFYnJrIhtbmUMv/RBBwTG7SIdTFzmI0REEKHspnRMBa
+TRbsHtpdcaXX4qGhhW0pk7YmZbPD2f1k/lCfixeLFQkVORFDGRumGMegI0t2osHR
+P3MVvs0JBYtgdSJp4Ms/jlaCC8jm6qeRAIioYvJoiC7XwdYmbMEQFXiHZ2NhxkWa
+uxYT5OwzeLOEuWj1zNHJMkCXY08hF5Fjb1rdlrlxulR1fMwN4/XKCOaZvsLOHMUX
+6PHlYUPBsqNhk9xRrpEzE2B2UnfOuv2+3pOonWo8a/gbtfsm6KLY+kdNRrKib2XF
+Vam1yKitxZ4X0RQHRGKK5e9oce9uRNvshlMK74TET/7l
+-----END ENCRYPTED PRIVATE KEY-----
