[rubygem-openssl_cms] Add support for ruby 2.2.
František Dvořák
valtri at fedoraproject.org
Wed Jan 28 21:54:42 UTC 2015
commit 4655d8fd605649f9d3d9b1976558e1f386f3e7a9
Author: František Dvořák <valtri at civ.zcu.cz>
Date: Wed Jan 28 22:30:01 2015 +0100
Add support for ruby 2.2.
openssl_cms-ruby2.1.5.diff | 877 +++++++++++++
openssl_cms-ruby2.2.0.diff | 3135 ++++++++++++++++++++++++++++++++++++++++++++
rubygem-openssl_cms.spec | 39 +-
3 files changed, 4039 insertions(+), 12 deletions(-)
---
diff --git a/openssl_cms-ruby2.1.5.diff b/openssl_cms-ruby2.1.5.diff
new file mode 100644
index 0000000..4b68240
--- /dev/null
+++ b/openssl_cms-ruby2.1.5.diff
@@ -0,0 +1,877 @@
+commit b6bdfb4c3c61c77251b89f096b80234fab728731
+Author: František Dvořák <valtri at civ.zcu.cz>
+Date: Wed Jan 28 18:16:16 2015 +0100
+
+ Sync with ruby 2.1.5 (patch 285, release date 2015-01-22).
+
+diff --git a/ext/openssl_cms/ossl.c b/ext/openssl_cms/ossl.c
+index 64a93a4..34378e4 100644
+--- a/ext/openssl_cms/ossl.c
++++ b/ext/openssl_cms/ossl.c
+@@ -311,10 +311,11 @@ ossl_make_error(VALUE exc, const char *fmt, va_list args)
+ else
+ msg = ERR_reason_error_string(e);
+ if (NIL_P(str)) {
+- str = rb_str_new_cstr(msg);
++ if (msg) str = rb_str_new_cstr(msg);
+ }
+ else {
+- rb_str_cat2(rb_str_cat2(str, ": "), msg);
++ if (RSTRING_LEN(str)) rb_str_cat2(str, ": ");
++ rb_str_cat2(str, msg ? msg : "(null)");
+ }
+ }
+ if (dOSSL == Qtrue){ /* show all errors on the stack */
+@@ -1082,6 +1083,11 @@ Init_openssl_cms()
+ rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
+
+ /*
++ * Version of OpenSSL the ruby OpenSSL extension is running with
++ */
++ rb_define_const(mOSSL, "OPENSSL_LIBRARY_VERSION", rb_str_new2(SSLeay_version(SSLEAY_VERSION)));
++
++ /*
+ * Version number of OpenSSL the ruby OpenSSL extension was built with
+ * (base 16)
+ */
+diff --git a/ext/openssl_cms/ossl_asn1.c b/ext/openssl_cms/ossl_asn1.c
+index c2344af..efdfbfc 100644
+--- a/ext/openssl_cms/ossl_asn1.c
++++ b/ext/openssl_cms/ossl_asn1.c
+@@ -1150,7 +1150,7 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
+ }
+ if(!SYMBOL_P(tag_class))
+ ossl_raise(eASN1Error, "invalid tag class");
+- if(SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31)
++ if(!NIL_P(tagging) && SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31)
+ ossl_raise(eASN1Error, "tag number for Universal too large");
+ }
+ else{
+diff --git a/ext/openssl_cms/ossl_cipher.c b/ext/openssl_cms/ossl_cipher.c
+index df6fd10..0fa740e 100644
+--- a/ext/openssl_cms/ossl_cipher.c
++++ b/ext/openssl_cms/ossl_cipher.c
+@@ -329,6 +329,33 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
+ return Qnil;
+ }
+
++static int
++ossl_cipher_update_long(EVP_CIPHER_CTX *ctx, unsigned char *out, long *out_len_ptr,
++ const unsigned char *in, long in_len)
++{
++ int out_part_len;
++ long out_len = 0;
++#define UPDATE_LENGTH_LIMIT INT_MAX
++
++#if SIZEOF_LONG > UPDATE_LENGTH_LIMIT
++ if (in_len > UPDATE_LENGTH_LIMIT) {
++ const int in_part_len = (UPDATE_LENGTH_LIMIT / 2 + 1) & ~1;
++ do {
++ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
++ &out_part_len, in, in_part_len))
++ return 0;
++ out_len += out_part_len;
++ in += in_part_len;
++ } while ((in_len -= in_part_len) > UPDATE_LENGTH_LIMIT);
++ }
++#endif
++ if (!EVP_CipherUpdate(ctx, out ? (out + out_len) : 0,
++ &out_part_len, in, (int)in_len))
++ return 0;
++ if (out_len_ptr) *out_len_ptr = out_len += out_part_len;
++ return 1;
++}
++
+ /*
+ * call-seq:
+ * cipher.update(data [, buffer]) -> string or buffer
+@@ -347,17 +374,21 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
+ {
+ EVP_CIPHER_CTX *ctx;
+ unsigned char *in;
+- int in_len, out_len;
++ long in_len, out_len;
+ VALUE data, str;
+
+ rb_scan_args(argc, argv, "11", &data, &str);
+
+ StringValue(data);
+ in = (unsigned char *)RSTRING_PTR(data);
+- if ((in_len = RSTRING_LENINT(data)) == 0)
++ if ((in_len = RSTRING_LEN(data)) == 0)
+ ossl_raise(rb_eArgError, "data must not be empty");
+ GetCipher(self, ctx);
+ out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
++ if (out_len <= 0) {
++ ossl_raise(rb_eRangeError,
++ "data too big to make output buffer: %ld bytes", in_len);
++ }
+
+ if (NIL_P(str)) {
+ str = rb_str_new(0, out_len);
+@@ -366,7 +397,7 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
+ rb_str_resize(str, out_len);
+ }
+
+- if (!EVP_CipherUpdate(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
++ if (!ossl_cipher_update_long(ctx, (unsigned char *)RSTRING_PTR(str), &out_len, in, in_len))
+ ossl_raise(eCipherError, NULL);
+ assert(out_len < RSTRING_LEN(str));
+ rb_str_set_len(str, out_len);
+@@ -506,17 +537,16 @@ ossl_cipher_set_auth_data(VALUE self, VALUE data)
+ {
+ EVP_CIPHER_CTX *ctx;
+ unsigned char *in;
+- int in_len;
+- int out_len;
++ long in_len, out_len;
+
+ StringValue(data);
+
+ in = (unsigned char *) RSTRING_PTR(data);
+- in_len = RSTRING_LENINT(data);
++ in_len = RSTRING_LEN(data);
+
+ GetCipher(self, ctx);
+
+- if (!EVP_CipherUpdate(ctx, NULL, &out_len, in, in_len))
++ if (!ossl_cipher_update_long(ctx, NULL, &out_len, in, in_len))
+ ossl_raise(eCipherError, "couldn't set additional authenticated data");
+
+ return data;
+diff --git a/ext/openssl_cms/ossl_pkey.c b/ext/openssl_cms/ossl_pkey.c
+index 0004d9d..878b221 100644
+--- a/ext/openssl_cms/ossl_pkey.c
++++ b/ext/openssl_cms/ossl_pkey.c
+@@ -318,13 +318,16 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
+ {
+ EVP_PKEY *pkey;
+ EVP_MD_CTX ctx;
++ int result;
+
+ GetPKey(self, pkey);
+- EVP_VerifyInit(&ctx, GetDigestPtr(digest));
+ StringValue(sig);
+ StringValue(data);
++ EVP_VerifyInit(&ctx, GetDigestPtr(digest));
+ EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
+- switch (EVP_VerifyFinal(&ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey)) {
++ result = EVP_VerifyFinal(&ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey);
++ EVP_MD_CTX_cleanup(&ctx);
++ switch (result) {
+ case 0:
+ return Qfalse;
+ case 1:
+diff --git a/ext/openssl_cms/ossl_pkey_dh.c b/ext/openssl_cms/ossl_pkey_dh.c
+index a6ae006..011b6f0 100644
+--- a/ext/openssl_cms/ossl_pkey_dh.c
++++ b/ext/openssl_cms/ossl_pkey_dh.c
+@@ -621,7 +621,7 @@ Init_ossl_dh()
+ *
+ * === Example of a key exchange
+ * dh1 = OpenSSL::PKey::DH.new(2048)
+- * params = dh1.public_key.to_der #you may send this publicly to the participating party
++ * 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)
+@@ -664,4 +664,3 @@ Init_ossl_dh()
+ {
+ }
+ #endif /* NO_DH */
+-
+diff --git a/lib/openssl_cms/bn.rb b/lib/openssl_cms/bn.rb
+index b2fca16..0e19c20 100644
+--- a/lib/openssl_cms/bn.rb
++++ b/lib/openssl_cms/bn.rb
+@@ -3,16 +3,16 @@
+ # $RCSfile$
+ #
+ # = Ruby-space definitions that completes C-space funcs for BN
+-#
++#
+ # = Info
+ # 'OpenSSL for Ruby 2' project
+ # Copyright (C) 2002 Michal Rokos <m.rokos at sh.cvut.cz>
+ # All rights reserved.
+-#
++#
+ # = Licence
+ # This program is licenced under the same licence as Ruby.
+ # (See the file 'LICENCE'.)
+-#
++#
+ # = Version
+ # $Id$
+ #
+@@ -28,8 +28,11 @@ end # OpenSSL
+ # Add double dispatch to Integer
+ #
+ class Integer
++ # Casts an Integer as an OpenSSL::BN
++ #
++ # See `man bn` for more info.
+ def to_bn
+- OpenSSL::BN::new(self.to_s(16), 16)
++ OpenSSL::BN::new(self)
+ end
+ end # Integer
+
+diff --git a/lib/openssl_cms/buffering.rb b/lib/openssl_cms/buffering.rb
+index 51bc968..1223c5d 100644
+--- a/lib/openssl_cms/buffering.rb
++++ b/lib/openssl_cms/buffering.rb
+@@ -1,23 +1,27 @@
+-=begin
+-= $RCSfile$ -- Buffering mix-in module.
+-
+-= Info
+- 'OpenSSL for Ruby 2' project
+- Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo at notwork.org>
+- All rights reserved.
+-
+-= Licence
+- This program is licenced under the same licence as Ruby.
+- (See the file 'LICENCE'.)
+-
+-= Version
+- $Id$
+-=end
++# coding: binary
++#--
++#= $RCSfile$ -- Buffering mix-in module.
++#
++#= Info
++# 'OpenSSL for Ruby 2' project
++# Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo at notwork.org>
++# All rights reserved.
++#
++#= Licence
++# This program is licenced under the same licence as Ruby.
++# (See the file 'LICENCE'.)
++#
++#= Version
++# $Id$
++#++
+
+ ##
+ # OpenSSL IO buffering mix-in module.
+ #
+ # This module allows an OpenSSL::SSL::SSLSocket to behave like an IO.
++#
++# You typically won't use this module directly, you can see it implemented in
++# OpenSSL::SSL::SSLSocket.
+
+ module OpenSSL::Buffering
+ include Enumerable
+@@ -34,7 +38,11 @@ module OpenSSL::Buffering
+
+ BLOCK_SIZE = 1024*16
+
+- def initialize(*args)
++ ##
++ # Creates an instance of OpenSSL's buffering IO module.
++
++ def initialize(*)
++ super
+ @eof = false
+ @rbuffer = ""
+ @sync = @io.sync
+@@ -161,7 +169,7 @@ module OpenSSL::Buffering
+ # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for
+ # more details. http://www.openssl.org/support/faq.html
+
+- def read_nonblock(maxlen, buf=nil)
++ def read_nonblock(maxlen, buf=nil, exception: true)
+ if maxlen == 0
+ if buf
+ buf.clear
+@@ -171,7 +179,7 @@ module OpenSSL::Buffering
+ end
+ end
+ if @rbuffer.empty?
+- return sysread_nonblock(maxlen, buf)
++ return sysread_nonblock(maxlen, buf, exception: exception)
+ end
+ ret = consume_rbuff(maxlen)
+ if buf
+@@ -370,9 +378,9 @@ module OpenSSL::Buffering
+ # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ
+ # for more details. http://www.openssl.org/support/faq.html
+
+- def write_nonblock(s)
++ def write_nonblock(s, exception: true)
+ flush
+- syswrite_nonblock(s)
++ syswrite_nonblock(s, exception: exception)
+ end
+
+ ##
+diff --git a/lib/openssl_cms/cipher.rb b/lib/openssl_cms/cipher.rb
+index eb146fb..b3340ff 100644
+--- a/lib/openssl_cms/cipher.rb
++++ b/lib/openssl_cms/cipher.rb
+@@ -3,16 +3,16 @@
+ # $RCSfile$
+ #
+ # = Ruby-space predefined Cipher subclasses
+-#
++#
+ # = Info
+ # 'OpenSSL for Ruby 2' project
+ # Copyright (C) 2002 Michal Rokos <m.rokos at sh.cvut.cz>
+ # All rights reserved.
+-#
++#
+ # = Licence
+ # This program is licenced under the same licence as Ruby.
+ # (See the file 'LICENCE'.)
+-#
++#
+ # = Version
+ # $Id$
+ #
+diff --git a/lib/openssl_cms/config.rb b/lib/openssl_cms/config.rb
+index 24a54c9..5716d59 100644
+--- a/lib/openssl_cms/config.rb
++++ b/lib/openssl_cms/config.rb
+@@ -13,20 +13,41 @@
+ require 'stringio'
+
+ module OpenSSL
++ ##
++ # = 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
+ class Config
+ include Enumerable
+
+ class << self
+- def parse(str)
++
++ ##
++ # Parses a given +string+ as a blob that contains configuration for openssl.
++ #
++ # If the source of the IO is a file, then consider using #parse_config.
++ def parse(string)
+ c = new()
+- parse_config(StringIO.new(str)).each do |section, hash|
++ parse_config(StringIO.new(string)).each do |section, hash|
+ c[section] = hash
+ end
+ c
+ end
+
++ ##
++ # load is an alias to ::new
+ alias load new
+
++ ##
++ # Parses the configuration data read from +io+, see also #parse.
++ #
++ # Raises a ConfigError on invalid configuration data.
+ def parse_config(io)
+ begin
+ parse_config_lines(io)
+@@ -209,6 +230,18 @@ module OpenSSL
+ end
+ end
+
++ ##
++ # Creates an instance of OpenSSL's configuration class.
++ #
++ # This can be used in contexts like OpenSSL::X509::ExtensionFactory.config=
++ #
++ # If the optional +filename+ parameter is provided, then it is read in and
++ # parsed via #parse_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.
++ #
+ def initialize(filename = nil)
+ @data = {}
+ if filename
+@@ -220,6 +253,23 @@ module OpenSSL
+ end
+ end
+
++ ##
++ # 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"
++ #
+ def get_value(section, key)
+ if section.nil?
+ raise TypeError.new('nil not allowed')
+@@ -228,7 +278,12 @@ module OpenSSL
+ get_key_string(section, key)
+ end
+
+- def value(arg1, arg2 = nil)
++ ##
++ #
++ # *Deprecated*
++ #
++ # Use #get_value instead
++ def value(arg1, arg2 = nil) # :nodoc:
+ warn('Config#value is deprecated; use Config#get_value')
+ if arg2.nil?
+ section, key = 'default', arg1
+@@ -240,20 +295,84 @@ module OpenSSL
+ get_key_string(section, key)
+ end
+
++ ##
++ # Set the target +key+ with a given +value+ under a specific +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 set the value of +foo+ under the +default+ section to a new
++ # value:
++ #
++ # config.add_value('default', 'foo', 'buzz')
++ # #=> "buzz"
++ # puts config.to_s
++ # #=> [ default ]
++ # # foo=buzz
++ #
+ def add_value(section, key, value)
+ check_modify
+ (@data[section] ||= {})[key] = value
+ end
+
++ ##
++ # Get 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"}
++ #
+ def [](section)
+ @data[section] || {}
+ end
+
+- def section(name)
++ ##
++ # Deprecated
++ #
++ # Use #[] instead
++ def section(name) # :nodoc:
+ warn('Config#section is deprecated; use Config#[]')
+ @data[name] || {}
+ end
+
++ ##
++ # Sets a specific +section+ name with a Hash +pairs+
++ #
++ # 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
++ #
++ # It's important to note that this will essentially merge any of the keys
++ # in +pairs+ with the existing +section+. For example:
++ #
++ # config['default']
++ # #=> {"foo"=>"bar", "baz"=>"buz"}
++ # config['default'] = {"foo" => "changed"}
++ # #=> {"foo"=>"changed"}
++ # config['default']
++ # #=> {"foo"=>"changed", "baz"=>"buz"}
++ #
+ def []=(section, pairs)
+ check_modify
+ @data[section] ||= {}
+@@ -262,10 +381,38 @@ module OpenSSL
+ end
+ end
+
++ ##
++ # Get the names of all sections in the current configuration
+ def sections
+ @data.keys
+ end
+
++ ##
++ # Get 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
++ #
+ def to_s
+ ary = []
+ @data.keys.sort.each do |section|
+@@ -278,6 +425,15 @@ module OpenSSL
+ ary.join
+ end
+
++ ##
++ # For a block.
++ #
++ # Receive the section and its pairs for the current configuration.
++ #
++ # config.each do |section, key, value|
++ # # ...
++ # end
++ #
+ def each
+ @data.each do |section, hash|
+ hash.each do |key, value|
+@@ -286,13 +442,16 @@ module OpenSSL
+ end
+ end
+
++ ##
++ # String representation of this configuration object, including the class
++ # name and its sections.
+ def inspect
+ "#<#{self.class.name} sections=#{sections.inspect}>"
+ end
+
+ protected
+
+- def data
++ def data # :nodoc:
+ @data
+ end
+
+diff --git a/lib/openssl_cms/digest.rb b/lib/openssl_cms/digest.rb
+index b470071..a7b641f 100644
+--- a/lib/openssl_cms/digest.rb
++++ b/lib/openssl_cms/digest.rb
+@@ -3,16 +3,16 @@
+ # $RCSfile$
+ #
+ # = Ruby-space predefined Digest subclasses
+-#
++#
+ # = Info
+ # 'OpenSSL for Ruby 2' project
+ # Copyright (C) 2002 Michal Rokos <m.rokos at sh.cvut.cz>
+ # All rights reserved.
+-#
++#
+ # = Licence
+ # This program is licenced under the same licence as Ruby.
+ # (See the file 'LICENCE'.)
+-#
++#
+ # = Version
+ # $Id$
+ #
+@@ -31,42 +31,58 @@ module OpenSSL
+ #
+ # === Examples
+ #
+- # OpenSSL::Digest.digest("SHA256, "abc")
++ # OpenSSL::Digest.digest("SHA256", "abc")
+ #
+ # which is equivalent to:
+ #
+ # OpenSSL::Digest::SHA256.digest("abc")
+
+ def self.digest(name, data)
+- super(data, name)
++ super(data, name)
+ end
+
+ alg.each{|name|
+- klass = Class.new(Digest){
+- define_method(:initialize){|*data|
+- if data.length > 1
+- raise ArgumentError,
+- "wrong number of arguments (#{data.length} for 1)"
+- end
+- super(name, data.first)
+- }
++ klass = Class.new(self) {
++ define_method(:initialize, ->(data = nil) {super(name, data)})
+ }
+ singleton = (class << klass; self; end)
+ singleton.class_eval{
+- define_method(:digest){|data| Digest.digest(name, data) }
+- define_method(:hexdigest){|data| Digest.hexdigest(name, data) }
++ define_method(:digest){|data| new.digest(data) }
++ define_method(:hexdigest){|data| new.hexdigest(data) }
+ }
+ const_set(name, klass)
+ }
+
+- # This class is only provided for backwards compatibility. Use OpenSSL::Digest in the future.
+- class Digest < Digest
++ # Deprecated.
++ #
++ # This class is only provided for backwards compatibility.
++ class Digest < Digest # :nodoc:
++ # Deprecated.
++ #
++ # See OpenSSL::Digest.new
+ def initialize(*args)
+- # add warning
++ warn('Digest::Digest is deprecated; use Digest')
+ super(*args)
+ end
+ end
+
+ end # Digest
++
++ # Returns a Digest subclass by +name+.
++ #
++ # require 'openssl'
++ #
++ # OpenSSL::Digest("MD5")
++ # # => OpenSSL::Digest::MD5
++ #
++ # Digest("Foo")
++ # # => NameError: wrong constant name Foo
++
++ def Digest(name)
++ OpenSSL::Digest.const_get(name)
++ end
++
++ module_function :Digest
++
+ end # OpenSSL
+
+diff --git a/lib/openssl_cms/ssl-internal.rb b/lib/openssl_cms/ssl-internal.rb
+index ff8a898..cb5887e 100644
+--- a/lib/openssl_cms/ssl-internal.rb
++++ b/lib/openssl_cms/ssl-internal.rb
+@@ -23,8 +23,49 @@ module OpenSSL
+ DEFAULT_PARAMS = {
+ :ssl_version => "SSLv23",
+ :verify_mode => OpenSSL::SSL::VERIFY_PEER,
+- :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
+- :options => OpenSSL::SSL::OP_ALL,
++ :ciphers => %w{
++ ECDHE-ECDSA-AES128-GCM-SHA256
++ ECDHE-RSA-AES128-GCM-SHA256
++ ECDHE-ECDSA-AES256-GCM-SHA384
++ ECDHE-RSA-AES256-GCM-SHA384
++ DHE-RSA-AES128-GCM-SHA256
++ DHE-DSS-AES128-GCM-SHA256
++ DHE-RSA-AES256-GCM-SHA384
++ DHE-DSS-AES256-GCM-SHA384
++ ECDHE-ECDSA-AES128-SHA256
++ ECDHE-RSA-AES128-SHA256
++ ECDHE-ECDSA-AES128-SHA
++ ECDHE-RSA-AES128-SHA
++ ECDHE-ECDSA-AES256-SHA384
++ ECDHE-RSA-AES256-SHA384
++ ECDHE-ECDSA-AES256-SHA
++ ECDHE-RSA-AES256-SHA
++ DHE-RSA-AES128-SHA256
++ DHE-RSA-AES256-SHA256
++ DHE-RSA-AES128-SHA
++ DHE-RSA-AES256-SHA
++ DHE-DSS-AES128-SHA256
++ DHE-DSS-AES256-SHA256
++ DHE-DSS-AES128-SHA
++ DHE-DSS-AES256-SHA
++ AES128-GCM-SHA256
++ AES256-GCM-SHA384
++ AES128-SHA256
++ AES256-SHA256
++ AES128-SHA
++ AES256-SHA
++ ECDHE-ECDSA-RC4-SHA
++ ECDHE-RSA-RC4-SHA
++ RC4-SHA
++ }.join(":"),
++ :options => -> {
++ opts = OpenSSL::SSL::OP_ALL
++ opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
++ opts |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
++ opts |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
++ opts |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
++ opts
++ }.call
+ }
+
+ DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
+@@ -33,6 +74,14 @@ module OpenSSL
+ DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
+ end
+
++ ##
++ # Sets the parameters for this SSL context to the values in +params+.
++ # The keys in +params+ must be assignment methods on SSLContext.
++ #
++ # If the verify_mode is not VERIFY_NONE and ca_file, ca_path and
++ # cert_store are not set then the system default certificate store is
++ # used.
++
+ def set_params(params={})
+ params = DEFAULT_PARAMS.merge(params)
+ params.each{|name, value| self.__send__("#{name}=", value) }
+@@ -126,7 +175,7 @@ module OpenSSL
+
+ def post_connection_check(hostname)
+ unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
+- raise SSLError, "hostname does not match the server certificate"
++ raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
+ end
+ return true
+ end
+@@ -138,34 +187,49 @@ module OpenSSL
+ end
+ end
+
++ ##
++ # SSLServer represents a TCP/IP server socket with Secure Sockets Layer.
+ class SSLServer
+ include SocketForwarder
++ # When true then #accept works exactly the same as TCPServer#accept
+ attr_accessor :start_immediately
+
++ # Creates a new instance of SSLServer.
++ # * +srv+ is an instance of TCPServer.
++ # * +ctx+ is an instance of OpenSSL::SSL::SSLContext.
+ def initialize(svr, ctx)
+ @svr = svr
+ @ctx = ctx
+ unless ctx.session_id_context
+- session_id = OpenSSL::Digest::MD5.hexdigest($0)
++ # see #6137 - session id may not exceed 32 bytes
++ prng = ::Random.new($0.hash)
++ session_id = prng.bytes(16).unpack('H*')[0]
+ @ctx.session_id_context = session_id
+ end
+ @start_immediately = true
+ end
+
++ # Returns the TCPServer passed to the SSLServer when initialized.
+ def to_io
+ @svr
+ end
+
++ # See TCPServer#listen for details.
+ def listen(backlog=5)
+ @svr.listen(backlog)
+ end
+
++ # See BasicSocket#shutdown for details.
+ def shutdown(how=Socket::SHUT_RDWR)
+ @svr.shutdown(how)
+ end
+
++ # Works similar to TCPServer#accept.
+ def accept
+- sock = @svr.accept
++ # Socket#accept returns [socket, addrinfo].
++ # TCPServer#accept returns a socket.
++ # The following comma strips addrinfo.
++ sock, = @svr.accept
+ begin
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
+ ssl.sync_close = true
+@@ -177,6 +241,7 @@ module OpenSSL
+ end
+ end
+
++ # See IO#close for details.
+ def close
+ @svr.close
+ end
+diff --git a/lib/openssl_cms/x509-internal.rb b/lib/openssl_cms/x509-internal.rb
+index 47e3a6f..31a4381 100644
+--- a/lib/openssl_cms/x509-internal.rb
++++ b/lib/openssl_cms/x509-internal.rb
+@@ -1,18 +1,22 @@
+-=begin
+-= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses
+-
+-= Info
+- 'OpenSSL for Ruby 2' project
+- Copyright (C) 2002 Michal Rokos <m.rokos at sh.cvut.cz>
+- All rights reserved.
+-
+-= Licence
+- This program is licenced under the same licence as Ruby.
+- (See the file 'LICENCE'.)
+-
+-= Version
+- $Id$
+-=end
++#--
++#
++# $RCSfile$
++#
++# = Ruby-space definitions that completes C-space funcs for X509 and subclasses
++#
++# = Info
++# 'OpenSSL for Ruby 2' project
++# Copyright (C) 2002 Michal Rokos <m.rokos at sh.cvut.cz>
++# All rights reserved.
++#
++# = Licence
++# This program is licenced under the same licence as Ruby.
++# (See the file 'LICENCE'.)
++#
++# = Version
++# $Id$
++#
++#++
+
+ module OpenSSL
+ module X509
diff --git a/openssl_cms-ruby2.2.0.diff b/openssl_cms-ruby2.2.0.diff
new file mode 100644
index 0000000..930673f
--- /dev/null
+++ b/openssl_cms-ruby2.2.0.diff
@@ -0,0 +1,3135 @@
+commit 668b7abd28461836941ce2be4fe7703053aeb42e
+Author: František Dvořák <valtri at civ.zcu.cz>
+Date: Wed Jan 28 18:50:41 2015 +0100
+
+ Sync with ruby 2.2.0 (patch 37, release date 2015-01-26).
+
+diff --git a/ext/openssl_cms/ossl.c b/ext/openssl_cms/ossl.c
+index 34378e4..2e8f034 100644
+--- a/ext/openssl_cms/ossl.c
++++ b/ext/openssl_cms/ossl.c
+@@ -18,11 +18,12 @@ int
+ string2hex(const unsigned char *buf, int buf_len, char **hexbuf, int *hexbuf_len)
+ {
+ static const char hex[]="0123456789abcdef";
+- int i, len = 2 * buf_len;
++ int i, len;
+
+- if (buf_len < 0 || len < buf_len) { /* PARANOIA? */
++ if (buf_len < 0 || buf_len > INT_MAX / 2) { /* PARANOIA? */
+ return -1;
+ }
++ len = 2 * buf_len;
+ if (!hexbuf) { /* if no buf, return calculated len */
+ if (hexbuf_len) {
+ *hexbuf_len = len;
+@@ -360,7 +361,7 @@ ossl_exc_new(VALUE exc, const char *fmt, ...)
+ * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation.
+ */
+ VALUE
+-ossl_get_errors()
++ossl_get_errors(void)
+ {
+ VALUE ary;
+ long e;
+@@ -747,27 +748,27 @@ static void Init_ossl_locks(void)
+ *
+ * First set up the cipher for encryption
+ *
+- * encrypter = OpenSSL::Cipher.new 'AES-128-CBC'
+- * encrypter.encrypt
+- * encrypter.pkcs5_keyivgen pass_phrase, salt
++ * encryptor = OpenSSL::Cipher.new 'AES-128-CBC'
++ * encryptor.encrypt
++ * encryptor.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to encrypt through
+ *
+- * encrypted = encrypter.update 'top secret document'
+- * encrypted << encrypter.final
++ * encrypted = encryptor.update 'top secret document'
++ * encrypted << encryptor.final
+ *
+ * === Decryption
+ *
+ * Use a new Cipher instance set up for decryption
+ *
+- * decrypter = OpenSSL::Cipher.new 'AES-128-CBC'
+- * decrypter.decrypt
+- * decrypter.pkcs5_keyivgen pass_phrase, salt
++ * decryptor = OpenSSL::Cipher.new 'AES-128-CBC'
++ * decryptor.decrypt
++ * decryptor.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to decrypt through
+ *
+- * plain = decrypter.update encrypted
+- * plain << decrypter.final
++ * plain = decryptor.update encrypted
++ * plain << decryptor.final
+ *
+ * == X509 Certificates
+ *
+@@ -1033,7 +1034,7 @@ static void Init_ossl_locks(void)
+ *
+ */
+ void
+-Init_openssl_cms()
++Init_openssl_cms(void)
+ {
+ /*
+ * Init timezone info
+diff --git a/ext/openssl_cms/ossl.h b/ext/openssl_cms/ossl.h
+index 8ba08d7..6f1790e 100644
+--- a/ext/openssl_cms/ossl.h
++++ b/ext/openssl_cms/ossl.h
+@@ -138,8 +138,8 @@ VALUE ossl_x509name_sk2ary(STACK_OF(X509_NAME) *names);
+ VALUE ossl_buf2str(char *buf, int len);
+ #define ossl_str_adjust(str, p) \
+ do{\
+- int len = RSTRING_LENINT(str);\
+- int newlen = rb_long2int((p) - (unsigned char*)RSTRING_PTR(str));\
++ long len = RSTRING_LEN(str);\
++ long newlen = (long)((p) - (unsigned char*)RSTRING_PTR(str));\
+ assert(newlen <= len);\
+ rb_str_set_len((str), newlen);\
+ }while(0)
+diff --git a/ext/openssl_cms/ossl_asn1.c b/ext/openssl_cms/ossl_asn1.c
+index efdfbfc..3a24d17 100644
+--- a/ext/openssl_cms/ossl_asn1.c
++++ b/ext/openssl_cms/ossl_asn1.c
+@@ -495,7 +495,7 @@ typedef struct {
+ VALUE *klass;
+ } ossl_asn1_info_t;
+
+-static ossl_asn1_info_t ossl_asn1_info[] = {
++static const ossl_asn1_info_t ossl_asn1_info[] = {
+ { "EOC", &cASN1EndOfContent, }, /* 0 */
+ { "BOOLEAN", &cASN1Boolean, }, /* 1 */
+ { "INTEGER", &cASN1Integer, }, /* 2 */
+@@ -529,7 +529,7 @@ static ossl_asn1_info_t ossl_asn1_info[] = {
+ { "BMPSTRING", &cASN1BMPString, }, /* 30 */
+ };
+
+-int ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0]));
++enum {ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0]))};
+
+ static VALUE class_tag_map;
+
+@@ -1472,7 +1472,7 @@ OSSL_ASN1_IMPL_FACTORY_METHOD(Set)
+ OSSL_ASN1_IMPL_FACTORY_METHOD(EndOfContent)
+
+ void
+-Init_ossl_asn1()
++Init_ossl_asn1(void)
+ {
+ VALUE ary;
+ int i;
+diff --git a/ext/openssl_cms/ossl_bio.c b/ext/openssl_cms/ossl_bio.c
+index a11c08c..e150de0 100644
+--- a/ext/openssl_cms/ossl_bio.c
++++ b/ext/openssl_cms/ossl_bio.c
+@@ -18,7 +18,7 @@ ossl_obj2bio(VALUE obj)
+ {
+ BIO *bio;
+
+- if (TYPE(obj) == T_FILE) {
++ if (RB_TYPE_P(obj, T_FILE)) {
+ rb_io_t *fptr;
+ FILE *fp;
+ int fd;
+diff --git a/ext/openssl_cms/ossl_bn.c b/ext/openssl_cms/ossl_bn.c
+index 0547363..58796fe 100644
+--- a/ext/openssl_cms/ossl_bn.c
++++ b/ext/openssl_cms/ossl_bn.c
+@@ -15,11 +15,11 @@
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, BN_clear_free, (bn)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_bn_type, (bn)); \
+ } while (0)
+
+ #define GetBN(obj, bn) do { \
+- Data_Get_Struct((obj), BIGNUM, (bn)); \
++ TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
+ if (!(bn)) { \
+ ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+ } \
+@@ -30,6 +30,25 @@
+ GetBN((obj), (bn)); \
+ } while (0)
+
++static void
++ossl_bn_free(void *ptr)
++{
++ BN_clear_free(ptr);
++}
++
++static size_t
++ossl_bn_size(const void *ptr)
++{
++ return sizeof(BIGNUM);
++}
++
++static const rb_data_type_t ossl_bn_type = {
++ "OpenSSL/BN",
++ {0, ossl_bn_free, ossl_bn_size,},
++ 0, 0,
++ RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Classes
+ */
+@@ -140,26 +159,24 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+ else if (RB_TYPE_P(str, T_BIGNUM)) {
+- int i, j, len = RBIGNUM_LENINT(str);
+- BDIGIT *ds = RBIGNUM_DIGITS(str);
++ size_t len = rb_absint_size(str, NULL);
++ unsigned char *bin;
+ VALUE buf;
+- unsigned char *bin = (unsigned char*)ALLOCV_N(BDIGIT, buf, len);
+-
+- for (i = 0; len > i; i++) {
+- BDIGIT v = ds[i];
+- for (j = SIZEOF_BDIGITS - 1; 0 <= j; j--) {
+- bin[(len-1-i)*SIZEOF_BDIGITS+j] = v&0xff;
+- v >>= 8;
+- }
+- }
++ int sign;
++
++ if (INT_MAX < len) {
++ rb_raise(eBNError, "bignum too long");
++ }
++ bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
++ sign = rb_integer_pack(str, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
+
+ GetBN(self, bn);
+- if (!BN_bin2bn(bin, (int)SIZEOF_BDIGITS*len, bn)) {
++ if (!BN_bin2bn(bin, (int)len, bn)) {
+ ALLOCV_END(buf);
+ ossl_raise(eBNError, NULL);
+ }
+ ALLOCV_END(buf);
+- if (!RBIGNUM_SIGN(str)) BN_set_negative(bn, 1);
++ if (sign < 0) BN_set_negative(bn, 1);
+ return self;
+ }
+ if (RTEST(rb_obj_is_kind_of(str, cBN))) {
+@@ -775,7 +792,7 @@ ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
+ * (NOTE: ordering of methods is the same as in 'man bn')
+ */
+ void
+-Init_ossl_bn()
++Init_ossl_bn(void)
+ {
+ #if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+diff --git a/ext/openssl_cms/ossl_cipher.c b/ext/openssl_cms/ossl_cipher.c
+index 0fa740e..08fdacf 100644
+--- a/ext/openssl_cms/ossl_cipher.c
++++ b/ext/openssl_cms/ossl_cipher.c
+@@ -11,13 +11,13 @@
+ #include "ossl.h"
+
+ #define WrapCipher(obj, klass, ctx) \
+- (obj) = Data_Wrap_Struct((klass), 0, ossl_cipher_free, (ctx))
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_cipher_type, (ctx))
+ #define MakeCipher(obj, klass, ctx) \
+- (obj) = Data_Make_Struct((klass), EVP_CIPHER_CTX, 0, ossl_cipher_free, (ctx))
++ (obj) = TypedData_Make_Struct((klass), EVP_CIPHER_CTX, &ossl_cipher_type, (ctx))
+ #define AllocCipher(obj, ctx) \
+- memset(DATA_PTR(obj) = (ctx) = ALLOC(EVP_CIPHER_CTX), 0, sizeof(EVP_CIPHER_CTX))
++ (DATA_PTR(obj) = (ctx) = ZALLOC(EVP_CIPHER_CTX))
+ #define GetCipherInit(obj, ctx) do { \
+- Data_Get_Struct((obj), EVP_CIPHER_CTX, (ctx)); \
++ TypedData_Get_Struct((obj), EVP_CIPHER_CTX, &ossl_cipher_type, (ctx)); \
+ } while (0)
+ #define GetCipher(obj, ctx) do { \
+ GetCipherInit((obj), (ctx)); \
+@@ -37,6 +37,15 @@ VALUE cCipher;
+ VALUE eCipherError;
+
+ static VALUE ossl_cipher_alloc(VALUE klass);
++static void ossl_cipher_free(void *ptr);
++static size_t ossl_cipher_memsize(const void *ptr);
++
++static const rb_data_type_t ossl_cipher_type = {
++ "OpenSSL/Cipher",
++ {0, ossl_cipher_free, ossl_cipher_memsize,},
++ 0, 0,
++ RUBY_TYPED_FREE_IMMEDIATELY,
++};
+
+ /*
+ * PUBLIC
+@@ -70,14 +79,22 @@ ossl_cipher_new(const EVP_CIPHER *cipher)
+ * PRIVATE
+ */
+ static void
+-ossl_cipher_free(EVP_CIPHER_CTX *ctx)
++ossl_cipher_free(void *ptr)
+ {
++ EVP_CIPHER_CTX *ctx = ptr;
+ if (ctx) {
+ EVP_CIPHER_CTX_cleanup(ctx);
+ ruby_xfree(ctx);
+ }
+ }
+
++static size_t
++ossl_cipher_memsize(const void *ptr)
++{
++ const EVP_CIPHER_CTX *ctx = ptr;
++ return ctx ? sizeof(*ctx) : 0;
++}
++
+ static VALUE
+ ossl_cipher_alloc(VALUE klass)
+ {
+@@ -158,7 +175,7 @@ add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary)
+ #ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
+ /*
+ * call-seq:
+- * Cipher.ciphers -> array[string...]
++ * OpenSSL::Cipher.ciphers -> array[string...]
+ *
+ * Returns the names of all available ciphers in an array.
+ */
+@@ -183,7 +200,7 @@ ossl_s_ciphers(VALUE self)
+ * cipher.reset -> self
+ *
+ * Fully resets the internal state of the Cipher. By using this, the same
+- * Cipher instance may be used several times for en- or decryption tasks.
++ * Cipher instance may be used several times for encryption or decryption tasks.
+ *
+ * Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1).
+ */
+diff --git a/ext/openssl_cms/ossl_config.c b/ext/openssl_cms/ossl_config.c
+index 0f25a19..74a52f7 100644
+--- a/ext/openssl_cms/ossl_config.c
++++ b/ext/openssl_cms/ossl_config.c
+@@ -17,7 +17,7 @@
+ VALUE cConfig;
+ /* Document-class: OpenSSL::ConfigError
+ *
+- * General error for openssl library configuration files. Including formating,
++ * General error for openssl library configuration files. Including formatting,
+ * parsing errors, etc.
+ */
+ VALUE eConfigError;
+@@ -69,7 +69,7 @@ GetConfigPtr(VALUE obj)
+ * INIT
+ */
+ void
+-Init_ossl_config()
++Init_ossl_config(void)
+ {
+ char *default_config_file;
+ eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError);
+diff --git a/ext/openssl_cms/ossl_digest.c b/ext/openssl_cms/ossl_digest.c
+index fdf13e9..6ce5316 100644
+--- a/ext/openssl_cms/ossl_digest.c
++++ b/ext/openssl_cms/ossl_digest.c
+@@ -11,7 +11,7 @@
+ #include "ossl.h"
+
+ #define GetDigest(obj, ctx) do { \
+- Data_Get_Struct((obj), EVP_MD_CTX, (ctx)); \
++ TypedData_Get_Struct((obj), EVP_MD_CTX, &ossl_digest_type, (ctx)); \
+ if (!(ctx)) { \
+ ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+ } \
+@@ -29,6 +29,20 @@ VALUE eDigestError;
+
+ static VALUE ossl_digest_alloc(VALUE klass);
+
++static void
++ossl_digest_free(void *ctx)
++{
++ EVP_MD_CTX_destroy(ctx);
++}
++
++static const rb_data_type_t ossl_digest_type = {
++ "OpenSSL/Digest",
++ {
++ 0, ossl_digest_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public
+ */
+@@ -38,7 +52,7 @@ GetDigestPtr(VALUE obj)
+ const EVP_MD *md;
+ ASN1_OBJECT *oid = NULL;
+
+- if (TYPE(obj) == T_STRING) {
++ if (RB_TYPE_P(obj, T_STRING)) {
+ const char *name = StringValueCStr(obj);
+
+ md = EVP_get_digestbyname(name);
+@@ -87,7 +101,7 @@ ossl_digest_alloc(VALUE klass)
+ ctx = EVP_MD_CTX_create();
+ if (ctx == NULL)
+ ossl_raise(rb_eRuntimeError, "EVP_MD_CTX_create() failed");
+- obj = Data_Wrap_Struct(klass, 0, EVP_MD_CTX_destroy, ctx);
++ obj = TypedData_Wrap_Struct(klass, &ossl_digest_type, ctx);
+
+ return obj;
+ }
+@@ -294,7 +308,7 @@ ossl_digest_block_length(VALUE self)
+ * INIT
+ */
+ void
+-Init_ossl_digest()
++Init_ossl_digest(void)
+ {
+ rb_require("digest");
+
+diff --git a/ext/openssl_cms/ossl_engine.c b/ext/openssl_cms/ossl_engine.c
+index da1a3c7..04b5879 100644
+--- a/ext/openssl_cms/ossl_engine.c
++++ b/ext/openssl_cms/ossl_engine.c
+@@ -16,10 +16,10 @@
+ if (!(engine)) { \
+ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, ENGINE_free, (engine)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_engine_type, (engine)); \
+ } while(0)
+ #define GetEngine(obj, engine) do { \
+- Data_Get_Struct((obj), ENGINE, (engine)); \
++ TypedData_Get_Struct((obj), ENGINE, &ossl_engine_type, (engine)); \
+ if (!(engine)) { \
+ ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
+ } \
+@@ -57,6 +57,20 @@ do{\
+ }\
+ }while(0)
+
++static void
++ossl_engine_free(void *engine)
++{
++ ENGINE_free(engine);
++}
++
++static const rb_data_type_t ossl_engine_type = {
++ "OpenSSL/Engine",
++ {
++ 0, ossl_engine_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /* Document-method: OpenSSL::Engine.load
+ *
+ * call-seq:
+@@ -523,24 +537,17 @@ ossl_engine_get_cmds(VALUE self)
+ static VALUE
+ ossl_engine_inspect(VALUE self)
+ {
+- VALUE str;
+- const char *cname = rb_class2name(rb_obj_class(self));
+-
+- str = rb_str_new2("#<");
+- rb_str_cat2(str, cname);
+- rb_str_cat2(str, " id=\"");
+- rb_str_append(str, ossl_engine_get_id(self));
+- rb_str_cat2(str, "\" name=\"");
+- rb_str_append(str, ossl_engine_get_name(self));
+- rb_str_cat2(str, "\">");
+-
+- return str;
++ ENGINE *e;
++
++ GetEngine(self, e);
++ return rb_sprintf("#<%"PRIsVALUE" id=\"%s\" name=\"%s\">",
++ rb_obj_class(self), ENGINE_get_id(e), ENGINE_get_name(e));
+ }
+
+ #define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
+
+ void
+-Init_ossl_engine()
++Init_ossl_engine(void)
+ {
+ cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
+ eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
+@@ -585,7 +592,7 @@ Init_ossl_engine()
+ }
+ #else
+ void
+-Init_ossl_engine()
++Init_ossl_engine(void)
+ {
+ }
+ #endif
+diff --git a/ext/openssl_cms/ossl_hmac.c b/ext/openssl_cms/ossl_hmac.c
+index 0bba44d..74fc962 100644
+--- a/ext/openssl_cms/ossl_hmac.c
++++ b/ext/openssl_cms/ossl_hmac.c
+@@ -13,9 +13,9 @@
+ #include "ossl.h"
+
+ #define MakeHMAC(obj, klass, ctx) \
+- (obj) = Data_Make_Struct((klass), HMAC_CTX, 0, ossl_hmac_free, (ctx))
++ (obj) = TypedData_Make_Struct((klass), HMAC_CTX, &ossl_hmac_type, (ctx))
+ #define GetHMAC(obj, ctx) do { \
+- Data_Get_Struct((obj), HMAC_CTX, (ctx)); \
++ TypedData_Get_Struct((obj), HMAC_CTX, &ossl_hmac_type, (ctx)); \
+ if (!(ctx)) { \
+ ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
+ } \
+@@ -39,12 +39,20 @@ VALUE eHMACError;
+ * Private
+ */
+ static void
+-ossl_hmac_free(HMAC_CTX *ctx)
++ossl_hmac_free(void *ctx)
+ {
+ HMAC_CTX_cleanup(ctx);
+ ruby_xfree(ctx);
+ }
+
++static const rb_data_type_t ossl_hmac_type = {
++ "OpenSSL/HMAC",
++ {
++ 0, ossl_hmac_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE
+ ossl_hmac_alloc(VALUE klass)
+ {
+@@ -327,7 +335,7 @@ ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
+ * INIT
+ */
+ void
+-Init_ossl_hmac()
++Init_ossl_hmac(void)
+ {
+ #if 0
+ /* :nodoc: */
+@@ -357,8 +365,8 @@ Init_ossl_hmac()
+ #else /* NO_HMAC */
+ # warning >>> OpenSSL is compiled without HMAC support <<<
+ void
+-Init_ossl_hmac()
++Init_ossl_hmac(void)
+ {
+- rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC.");
++ rb_warning("HMAC is not available: OpenSSL is compiled without HMAC.");
+ }
+ #endif /* NO_HMAC */
+diff --git a/ext/openssl_cms/ossl_ns_spki.c b/ext/openssl_cms/ossl_ns_spki.c
+index b80984c..d2a52e6 100644
+--- a/ext/openssl_cms/ossl_ns_spki.c
++++ b/ext/openssl_cms/ossl_ns_spki.c
+@@ -14,10 +14,10 @@
+ if (!(spki)) { \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, NETSCAPE_SPKI_free, (spki)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_netscape_spki_type, (spki)); \
+ } while (0)
+ #define GetSPKI(obj, spki) do { \
+- Data_Get_Struct((obj), NETSCAPE_SPKI, (spki)); \
++ TypedData_Get_Struct((obj), NETSCAPE_SPKI, &ossl_netscape_spki_type, (spki)); \
+ if (!(spki)) { \
+ ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+ } \
+@@ -37,6 +37,21 @@ VALUE eSPKIError;
+ /*
+ * Private functions
+ */
++
++static void
++ossl_netscape_spki_free(void *spki)
++{
++ NETSCAPE_SPKI_free(spki);
++}
++
++static const rb_data_type_t ossl_netscape_spki_type = {
++ "OpenSSL/NETSCAPE_SPKI",
++ {
++ 0, ossl_netscape_spki_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE
+ ossl_spki_alloc(VALUE klass)
+ {
+@@ -360,7 +375,7 @@ ossl_spki_verify(VALUE self, VALUE key)
+ */
+
+ void
+-Init_ossl_ns_spki()
++Init_ossl_ns_spki(void)
+ {
+ #if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+diff --git a/ext/openssl_cms/ossl_ocsp.c b/ext/openssl_cms/ossl_ocsp.c
+index 4e2e839..dc31d79 100644
+--- a/ext/openssl_cms/ossl_ocsp.c
++++ b/ext/openssl_cms/ossl_ocsp.c
+@@ -15,10 +15,10 @@
+
+ #define WrapOCSPReq(klass, obj, req) do { \
+ if(!(req)) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \
+- (obj) = Data_Wrap_Struct((klass), 0, OCSP_REQUEST_free, (req)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_request_type, (req)); \
+ } while (0)
+ #define GetOCSPReq(obj, req) do { \
+- Data_Get_Struct((obj), OCSP_REQUEST, (req)); \
++ TypedData_Get_Struct((obj), OCSP_REQUEST, &ossl_ocsp_request_type, (req)); \
+ if(!(req)) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \
+ } while (0)
+ #define SafeGetOCSPReq(obj, req) do { \
+@@ -28,10 +28,10 @@
+
+ #define WrapOCSPRes(klass, obj, res) do { \
+ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
+- (obj) = Data_Wrap_Struct((klass), 0, OCSP_RESPONSE_free, (res)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_response_type, (res)); \
+ } while (0)
+ #define GetOCSPRes(obj, res) do { \
+- Data_Get_Struct((obj), OCSP_RESPONSE, (res)); \
++ TypedData_Get_Struct((obj), OCSP_RESPONSE, &ossl_ocsp_response_type, (res)); \
+ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
+ } while (0)
+ #define SafeGetOCSPRes(obj, res) do { \
+@@ -41,10 +41,10 @@
+
+ #define WrapOCSPBasicRes(klass, obj, res) do { \
+ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
+- (obj) = Data_Wrap_Struct((klass), 0, OCSP_BASICRESP_free, (res)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_basicresp_type, (res)); \
+ } while (0)
+ #define GetOCSPBasicRes(obj, res) do { \
+- Data_Get_Struct((obj), OCSP_BASICRESP, (res)); \
++ TypedData_Get_Struct((obj), OCSP_BASICRESP, &ossl_ocsp_basicresp_type, (res)); \
+ if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
+ } while (0)
+ #define SafeGetOCSPBasicRes(obj, res) do { \
+@@ -54,10 +54,10 @@
+
+ #define WrapOCSPCertId(klass, obj, cid) do { \
+ if(!(cid)) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \
+- (obj) = Data_Wrap_Struct((klass), 0, OCSP_CERTID_free, (cid)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_ocsp_certid_type, (cid)); \
+ } while (0)
+ #define GetOCSPCertId(obj, cid) do { \
+- Data_Get_Struct((obj), OCSP_CERTID, (cid)); \
++ TypedData_Get_Struct((obj), OCSP_CERTID, &ossl_ocsp_certid_type, (cid)); \
+ if(!(cid)) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \
+ } while (0)
+ #define SafeGetOCSPCertId(obj, cid) do { \
+@@ -72,6 +72,62 @@ VALUE cOCSPRes;
+ VALUE cOCSPBasicRes;
+ VALUE cOCSPCertId;
+
++static void
++ossl_ocsp_request_free(void *ptr)
++{
++ OCSP_REQUEST_free(ptr);
++}
++
++static const rb_data_type_t ossl_ocsp_request_type = {
++ "OpenSSL/OCSP/REQUEST",
++ {
++ 0, ossl_ocsp_request_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
++static void
++ossl_ocsp_response_free(void *ptr)
++{
++ OCSP_RESPONSE_free(ptr);
++}
++
++static const rb_data_type_t ossl_ocsp_response_type = {
++ "OpenSSL/OCSP/RESPONSE",
++ {
++ 0, ossl_ocsp_response_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
++static void
++ossl_ocsp_basicresp_free(void *ptr)
++{
++ OCSP_BASICRESP_free(ptr);
++}
++
++static const rb_data_type_t ossl_ocsp_basicresp_type = {
++ "OpenSSL/OCSP/BASICRESP",
++ {
++ 0, ossl_ocsp_basicresp_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
++static void
++ossl_ocsp_certid_free(void *ptr)
++{
++ OCSP_CERTID_free(ptr);
++}
++
++static const rb_data_type_t ossl_ocsp_certid_type = {
++ "OpenSSL/OCSP/CERTID",
++ {
++ 0, ossl_ocsp_certid_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public
+ */
+@@ -99,6 +155,15 @@ ossl_ocspreq_alloc(VALUE klass)
+ return obj;
+ }
+
++/*
++ * call-seq:
++ * OpenSSL::OCSP::Request.new -> request
++ * OpenSSL::OCSP::Request.new(request_der) -> request
++ *
++ * Creates a new OpenSSL::OCSP::Request. The request may be created empty or
++ * from a +request_der+ string.
++ */
++
+ static VALUE
+ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
+ {
+@@ -121,6 +186,17 @@ ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+
++/*
++ * call-seq:
++ * request.add_nonce(nonce = nil) -> request
++ *
++ * Adds a +nonce+ to the OCSP request. If no nonce is given a random one will
++ * be generated.
++ *
++ * The nonce is used to prevent replay attacks but some servers do not support
++ * it.
++ */
++
+ static VALUE
+ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
+ {
+@@ -143,18 +219,25 @@ ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+
+-/* Check nonce validity in a request and response.
+- * Return value reflects result:
+- * 1: nonces present and equal.
+- * 2: nonces both absent.
+- * 3: nonce present in response only.
+- * 0: nonces both present and not equal.
+- * -1: nonce in request only.
++/*
++ * call-seq:
++ * request.check_nonce(response) -> result
++ *
++ * Checks the nonce validity for this request and +response+.
++ *
++ * The return value is one of the following:
+ *
+- * For most responders clients can check return > 0.
+- * If responder doesn't handle nonces return != 0 may be
+- * necessary. return == 0 is always an error.
++ * -1 :: nonce in request only.
++ * 0 :: nonces both present and not equal.
++ * 1 :: nonces present and equal.
++ * 2 :: nonces both absent.
++ * 3 :: nonce present in response only.
++ *
++ * For most responses, clients can check +result+ > 0. If a responder doesn't
++ * handle nonces <code>result.nonzero?</code> may be necessary. A result of
++ * <code>0</code> is always an error.
+ */
++
+ static VALUE
+ ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp)
+ {
+@@ -169,6 +252,13 @@ ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp)
+ return INT2NUM(res);
+ }
+
++/*
++ * call-seq:
++ * request.add_certid(certificate_id) -> request
++ *
++ * Adds +certificate_id+ to the request.
++ */
++
+ static VALUE
+ ossl_ocspreq_add_certid(VALUE self, VALUE certid)
+ {
+@@ -183,6 +273,13 @@ ossl_ocspreq_add_certid(VALUE self, VALUE certid)
+ return self;
+ }
+
++/*
++ * call-seq:
++ * request.certid -> [certificate_id, ...]
++ *
++ * Returns all certificate IDs in this request.
++ */
++
+ static VALUE
+ ossl_ocspreq_get_certid(VALUE self)
+ {
+@@ -206,6 +303,17 @@ ossl_ocspreq_get_certid(VALUE self)
+ return ary;
+ }
+
++/*
++ * call-seq:
++ * request.sign(signer_cert, signer_key) -> self
++ * request.sign(signer_cert, signer_key, certificates) -> self
++ * request.sign(signer_cert, signer_key, certificates, flags) -> self
++ *
++ * Signs this OCSP request using +signer_cert+ and +signer_key+.
++ * +certificates+ is an optional Array of certificates that may be included in
++ * the request.
++ */
++
+ static VALUE
+ ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
+ {
+@@ -234,6 +342,14 @@ ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+
++/*
++ * call-seq:
++ * request.verify(certificates, store) -> true or false
++ * request.verify(certificates, store, flags) -> true or false
++ *
++ * Verifies this request using the given +certificates+ and X509 +store+.
++ */
++
+ static VALUE
+ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
+ {
+@@ -255,6 +371,10 @@ ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
+ return result ? Qtrue : Qfalse;
+ }
+
++/*
++ * Returns this request as a DER-encoded string
++ */
++
+ static VALUE
+ ossl_ocspreq_to_der(VALUE self)
+ {
+@@ -278,6 +398,13 @@ ossl_ocspreq_to_der(VALUE self)
+ /*
+ * OCSP::Response
+ */
++
++/* call-seq:
++ * OpenSSL::OCSP::Response.create(status, basic_response = nil) -> response
++ *
++ * Creates an OpenSSL::OCSP::Response from +status+ and +basic_response+.
++ */
++
+ static VALUE
+ ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)
+ {
+@@ -308,6 +435,15 @@ ossl_ocspres_alloc(VALUE klass)
+ return obj;
+ }
+
++/*
++ * call-seq:
++ * OpenSSL::OCSP::Response.new -> response
++ * OpenSSL::OCSP::Response.new(response_der) -> response
++ *
++ * Creates a new OpenSSL::OCSP::Response. The response may be created empty or
++ * from a +response_der+ string.
++ */
++
+ static VALUE
+ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
+ {
+@@ -330,6 +466,13 @@ ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+
++/*
++ * call-seq:
++ * response.status -> Integer
++ *
++ * Returns the status of the response.
++ */
++
+ static VALUE
+ ossl_ocspres_status(VALUE self)
+ {
+@@ -342,6 +485,13 @@ ossl_ocspres_status(VALUE self)
+ return INT2NUM(st);
+ }
+
++/*
++ * call-seq:
++ * response.status_string -> String
++ *
++ * Returns a status string for the response.
++ */
++
+ static VALUE
+ ossl_ocspres_status_string(VALUE self)
+ {
+@@ -354,6 +504,13 @@ ossl_ocspres_status_string(VALUE self)
+ return rb_str_new2(OCSP_response_status_str(st));
+ }
+
++/*
++ * call-seq:
++ * response.basic
++ *
++ * Returns a BasicResponse for this response
++ */
++
+ static VALUE
+ ossl_ocspres_get_basic(VALUE self)
+ {
+@@ -369,6 +526,13 @@ ossl_ocspres_get_basic(VALUE self)
+ return ret;
+ }
+
++/*
++ * call-seq:
++ * response.to_der -> String
++ *
++ * Returns this response as a DER-encoded string.
++ */
++
+ static VALUE
+ ossl_ocspres_to_der(VALUE self)
+ {
+@@ -405,12 +569,27 @@ ossl_ocspbres_alloc(VALUE klass)
+ return obj;
+ }
+
++/*
++ * call-seq:
++ * OpenSSL::OCSP::BasicResponse.new(*) -> basic_response
++ *
++ * Creates a new BasicResponse and ignores all arguments.
++ */
++
+ static VALUE
+ ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
+ {
+ return self;
+ }
+
++/*
++ * call-seq:
++ * basic_response.copy_nonce(request) -> Integer
++ *
++ * Copies the nonce from +request+ into this response. Returns 1 on success
++ * and 0 on failure.
++ */
++
+ static VALUE
+ ossl_ocspbres_copy_nonce(VALUE self, VALUE request)
+ {
+@@ -425,6 +604,14 @@ ossl_ocspbres_copy_nonce(VALUE self, VALUE request)
+ return INT2NUM(ret);
+ }
+
++/*
++ * call-seq:
++ * basic_response.add_nonce(nonce = nil)
++ *
++ * Adds +nonce+ to this response. If no nonce was provided a random nonce
++ * will be added.
++ */
++
+ static VALUE
+ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
+ {
+@@ -447,6 +634,22 @@ ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+
++/*
++ * call-seq:
++ * basic_response.add_status(certificate_id, status, reason, revocation_time, this_update, next_update, extensions) -> basic_response
++ *
++ * Adds a validation +status+ (0 for revoked, 1 for success) to this
++ * response for +certificate_id+. +reason+ describes the reason for the
++ * revocation, if any.
++ *
++ * The +revocation_time+, +this_update+ and +next_update+ are times for the
++ * certificate's revocation time, the time of this status and the next update
++ * time for a new status, respectively.
++ *
++ * +extensions+ may be an Array of OpenSSL::X509::Extension that will
++ * be added to this response or nil.
++ */
++
+ static VALUE
+ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
+ VALUE reason, VALUE revtime,
+@@ -515,6 +718,16 @@ ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
+ return self;
+ }
+
++/*
++ * call-seq:
++ * basic_response.status -> statuses
++ *
++ * Returns an Array of statuses for this response. Each status contains a
++ * CertificateId, the status (0 for success, 1 for revoked), the reason for
++ * the status, the revocation time, the time of this update, the time for the
++ * next update and a list of OpenSSL::X509::Extensions.
++ */
++
+ static VALUE
+ ossl_ocspbres_get_status(VALUE self)
+ {
+@@ -560,6 +773,16 @@ ossl_ocspbres_get_status(VALUE self)
+ return ret;
+ }
+
++/*
++ * call-seq:
++ * basic_response.sign(signer_cert, signer_key) -> self
++ * basic_response.sign(signer_cert, signer_key, certificates) -> self
++ * basic_response.sign(signer_cert, signer_key, certificates, flags) -> self
++ *
++ * Signs this response using the +signer_cert+ and +signer_key+. Additional
++ * +certificates+ may be added to the signature along with a set of +flags+.
++ */
++
+ static VALUE
+ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
+ {
+@@ -590,6 +813,14 @@ ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+
++/*
++ * call-seq:
++ * basic_response.verify(certificates, store) -> true or false
++ * basic_response.verify(certificates, store, flags) -> true or false
++ *
++ * Verifies the signature of the response using the given +certificates+,
++ * +store+ and +flags+.
++ */
+ static VALUE
+ ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
+ {
+@@ -627,6 +858,15 @@ ossl_ocspcid_alloc(VALUE klass)
+ return obj;
+ }
+
++/*
++ * call-seq:
++ * OpenSSL::OCSP::CertificateId.new(subject, issuer, digest = nil) -> certificate_id
++ *
++ * Creates a new OpenSSL::OCSP::CertificateId for the given +subject+ and
++ * +issuer+ X509 certificates. The +digest+ is used to compute the
++ * certificate ID and must be an OpenSSL::Digest instance.
++ */
++
+ static VALUE
+ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
+ {
+@@ -657,6 +897,13 @@ ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
+ return self;
+ }
+
++/*
++ * call-seq:
++ * certificate_id.cmp(other) -> true or false
++ *
++ * Compares this certificate id with +other+ and returns true if they are the
++ * same.
++ */
+ static VALUE
+ ossl_ocspcid_cmp(VALUE self, VALUE other)
+ {
+@@ -670,6 +917,14 @@ ossl_ocspcid_cmp(VALUE self, VALUE other)
+ return (result == 0) ? Qtrue : Qfalse;
+ }
+
++/*
++ * call-seq:
++ * certificate_id.cmp_issuer(other) -> true or false
++ *
++ * Compares this certificate id's issuer with +other+ and returns true if
++ * they are the same.
++ */
++
+ static VALUE
+ ossl_ocspcid_cmp_issuer(VALUE self, VALUE other)
+ {
+@@ -683,6 +938,13 @@ ossl_ocspcid_cmp_issuer(VALUE self, VALUE other)
+ return (result == 0) ? Qtrue : Qfalse;
+ }
+
++/*
++ * call-seq:
++ * certificate_id.get_serial -> Integer
++ *
++ * Returns the serial number of the issuing certificate.
++ */
++
+ static VALUE
+ ossl_ocspcid_get_serial(VALUE self)
+ {
+@@ -694,12 +956,132 @@ ossl_ocspcid_get_serial(VALUE self)
+ }
+
+ void
+-Init_ossl_ocsp()
++Init_ossl_ocsp(void)
+ {
++ /*
++ * OpenSSL::OCSP implements Online Certificate Status Protocol requests
++ * and responses.
++ *
++ * Creating and sending an OCSP request requires a subject certificate
++ * that contains an OCSP URL in an authorityInfoAccess extension and the
++ * issuer certificate for the subject certificate. First, load the issuer
++ * and subject certificates:
++ *
++ * subject = OpenSSL::X509::Certificate.new subject_pem
++ * issuer = OpenSSL::X509::Certificate.new issuer_pem
++ *
++ * To create the request we need to create a certificate ID for the
++ * subject certificate so the CA knows which certificate we are asking
++ * about:
++ *
++ * digest = OpenSSL::Digest::SHA1.new
++ * certificate_id =
++ * OpenSSL::OCSP::CertificateId.new subject, issuer, digest
++ *
++ * Then create a request and add the certificate ID to it:
++ *
++ * request = OpenSSL::OCSP::Request.new
++ * request.add_certid certificate_id
++ *
++ * Adding a nonce to the request protects against replay attacks but not
++ * all CA process the nonce.
++ *
++ * request.add_nonce
++ *
++ * To submit the request to the CA for verification we need to extract the
++ * OCSP URI from the subject certificate:
++ *
++ * authority_info_access = subject.extensions.find do |extension|
++ * extension.oid == 'authorityInfoAccess'
++ * end
++ *
++ * descriptions = authority_info_access.value.split "\n"
++ * ocsp = descriptions.find do |description|
++ * description.start_with? 'OCSP'
++ * end
++ *
++ * require 'uri'
++ *
++ * ocsp_uri = URI ocsp[/URI:(.*)/, 1]
++ *
++ * To submit the request we'll POST the request to the OCSP URI (per RFC
++ * 2560). Note that we only handle HTTP requests and don't handle any
++ * redirects in this example, so this is insufficient for serious use.
++ *
++ * require 'net/http'
++ *
++ * http_response =
++ * Net::HTTP.start ocsp_uri.hostname, ocsp.port do |http|
++ * http.post ocsp_uri.path, request.to_der,
++ * 'content-type' => 'application/ocsp-request'
++ * end
++ *
++ * response = OpenSSL::OCSP::Response.new http_response.body
++ * response_basic = response.basic
++ *
++ * First we check if the response has a valid signature. Without a valid
++ * signature we cannot trust it. If you get a failure here you may be
++ * missing a system certificate store or may be missing the intermediate
++ * certificates.
++ *
++ * store = OpenSSL::X509::Store.new
++ * store.set_default_paths
++ *
++ * unless response.verify [], store then
++ * raise 'response is not signed by a trusted certificate'
++ * end
++ *
++ * The response contains the status information (success/fail). We can
++ * display the status as a string:
++ *
++ * puts response.status_string #=> successful
++ *
++ * Next we need to know the response details to determine if the response
++ * matches our request. First we check the nonce. Again, not all CAs
++ * support a nonce. See Request#check_nonce for the meanings of the
++ * return values.
++ *
++ * p request.check_nonce basic_response #=> value from -1 to 3
++ *
++ * Then extract the status information from the basic response. (You can
++ * check multiple certificates in a request, but for this example we only
++ * submitted one.)
++ *
++ * response_certificate_id, status, reason, revocation_time,
++ * this_update, next_update, extensions = basic_response.status
++ *
++ * Then check the various fields.
++ *
++ * unless response_certificate_id == certificate_id then
++ * raise 'certificate id mismatch'
++ * end
++ *
++ * now = Time.now
++ *
++ * if this_update > now then
++ * raise 'update date is in the future'
++ * end
++ *
++ * if now > next_update then
++ * raise 'next update time has passed'
++ * end
++ */
++
+ mOCSP = rb_define_module_under(mOSSL, "OCSP");
+
++ /*
++ * OCSP error class.
++ */
++
+ eOCSPError = rb_define_class_under(mOCSP, "OCSPError", eOSSLError);
+
++ /*
++ * An OpenSSL::OCSP::Request contains the certificate information for
++ * determining if a certificate has been revoked or not. A Request can be
++ * created for a certificate or from a DER-encoded request created
++ * elsewhere.
++ */
++
+ cOCSPReq = rb_define_class_under(mOCSP, "Request", rb_cObject);
+ rb_define_alloc_func(cOCSPReq, ossl_ocspreq_alloc);
+ rb_define_method(cOCSPReq, "initialize", ossl_ocspreq_initialize, -1);
+@@ -711,6 +1093,11 @@ Init_ossl_ocsp()
+ rb_define_method(cOCSPReq, "verify", ossl_ocspreq_verify, -1);
+ rb_define_method(cOCSPReq, "to_der", ossl_ocspreq_to_der, 0);
+
++ /*
++ * An OpenSSL::OCSP::Response contains the status of a certificate check
++ * which is created from an OpenSSL::OCSP::Request.
++ */
++
+ cOCSPRes = rb_define_class_under(mOCSP, "Response", rb_cObject);
+ rb_define_singleton_method(cOCSPRes, "create", ossl_ocspres_s_create, 2);
+ rb_define_alloc_func(cOCSPRes, ossl_ocspres_alloc);
+@@ -720,6 +1107,12 @@ Init_ossl_ocsp()
+ rb_define_method(cOCSPRes, "basic", ossl_ocspres_get_basic, 0);
+ rb_define_method(cOCSPRes, "to_der", ossl_ocspres_to_der, 0);
+
++ /*
++ * An OpenSSL::OCSP::BasicResponse contains the status of a certificate
++ * check which is created from an OpenSSL::OCSP::Request. A
++ * BasicResponse is more detailed than a Response.
++ */
++
+ cOCSPBasicRes = rb_define_class_under(mOCSP, "BasicResponse", rb_cObject);
+ rb_define_alloc_func(cOCSPBasicRes, ossl_ocspbres_alloc);
+ rb_define_method(cOCSPBasicRes, "initialize", ossl_ocspbres_initialize, -1);
+@@ -730,6 +1123,11 @@ Init_ossl_ocsp()
+ rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1);
+ rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1);
+
++ /*
++ * An OpenSSL::OCSP::CertificateId identifies a certificate to the CA so
++ * that a status check can be performed.
++ */
++
+ cOCSPCertId = rb_define_class_under(mOCSP, "CertificateId", rb_cObject);
+ rb_define_alloc_func(cOCSPCertId, ossl_ocspcid_alloc);
+ rb_define_method(cOCSPCertId, "initialize", ossl_ocspcid_initialize, -1);
+@@ -737,50 +1135,110 @@ Init_ossl_ocsp()
+ rb_define_method(cOCSPCertId, "cmp_issuer", ossl_ocspcid_cmp_issuer, 1);
+ rb_define_method(cOCSPCertId, "serial", ossl_ocspcid_get_serial, 0);
+
+-#define DefOCSPConst(x) rb_define_const(mOCSP, #x, INT2NUM(OCSP_##x))
+-
+- DefOCSPConst(RESPONSE_STATUS_SUCCESSFUL);
+- DefOCSPConst(RESPONSE_STATUS_MALFORMEDREQUEST);
+- DefOCSPConst(RESPONSE_STATUS_INTERNALERROR);
+- DefOCSPConst(RESPONSE_STATUS_TRYLATER);
+- DefOCSPConst(RESPONSE_STATUS_SIGREQUIRED);
+- DefOCSPConst(RESPONSE_STATUS_UNAUTHORIZED);
+-
+- DefOCSPConst(REVOKED_STATUS_NOSTATUS);
+- DefOCSPConst(REVOKED_STATUS_UNSPECIFIED);
+- DefOCSPConst(REVOKED_STATUS_KEYCOMPROMISE);
+- DefOCSPConst(REVOKED_STATUS_CACOMPROMISE);
+- DefOCSPConst(REVOKED_STATUS_AFFILIATIONCHANGED);
+- DefOCSPConst(REVOKED_STATUS_SUPERSEDED);
+- DefOCSPConst(REVOKED_STATUS_CESSATIONOFOPERATION);
+- DefOCSPConst(REVOKED_STATUS_CERTIFICATEHOLD);
+- DefOCSPConst(REVOKED_STATUS_REMOVEFROMCRL);
+-
+- DefOCSPConst(NOCERTS);
+- DefOCSPConst(NOINTERN);
+- DefOCSPConst(NOSIGS);
+- DefOCSPConst(NOCHAIN);
+- DefOCSPConst(NOVERIFY);
+- DefOCSPConst(NOEXPLICIT);
+- DefOCSPConst(NOCASIGN);
+- DefOCSPConst(NODELEGATED);
+- DefOCSPConst(NOCHECKS);
+- DefOCSPConst(TRUSTOTHER);
+- DefOCSPConst(RESPID_KEY);
+- DefOCSPConst(NOTIME);
+-
+-#define DefOCSPVConst(x) rb_define_const(mOCSP, "V_" #x, INT2NUM(V_OCSP_##x))
+-
+- DefOCSPVConst(CERTSTATUS_GOOD);
+- DefOCSPVConst(CERTSTATUS_REVOKED);
+- DefOCSPVConst(CERTSTATUS_UNKNOWN);
+- DefOCSPVConst(RESPID_NAME);
+- DefOCSPVConst(RESPID_KEY);
++ /* Internal error in issuer */
++ rb_define_const(mOCSP, "RESPONSE_STATUS_INTERNALERROR", INT2NUM(OCSP_RESPONSE_STATUS_INTERNALERROR));
++
++ /* Illegal confirmation request */
++ rb_define_const(mOCSP, "RESPONSE_STATUS_MALFORMEDREQUEST", INT2NUM(OCSP_RESPONSE_STATUS_MALFORMEDREQUEST));
++
++ /* The certificate was revoked for an unknown reason */
++ rb_define_const(mOCSP, "REVOKED_STATUS_NOSTATUS", INT2NUM(OCSP_REVOKED_STATUS_NOSTATUS));
++
++ /* You must sign the request and resubmit */
++ rb_define_const(mOCSP, "RESPONSE_STATUS_SIGREQUIRED", INT2NUM(OCSP_RESPONSE_STATUS_SIGREQUIRED));
++
++ /* Response has valid confirmations */
++ rb_define_const(mOCSP, "RESPONSE_STATUS_SUCCESSFUL", INT2NUM(OCSP_RESPONSE_STATUS_SUCCESSFUL));
++
++ /* Try again later */
++ rb_define_const(mOCSP, "RESPONSE_STATUS_TRYLATER", INT2NUM(OCSP_RESPONSE_STATUS_TRYLATER));
++
++ /* The certificate subject's name or other information changed */
++ rb_define_const(mOCSP, "REVOKED_STATUS_AFFILIATIONCHANGED", INT2NUM(OCSP_REVOKED_STATUS_AFFILIATIONCHANGED));
++
++ /* This CA certificate was revoked due to a key compromise */
++ rb_define_const(mOCSP, "REVOKED_STATUS_CACOMPROMISE", INT2NUM(OCSP_REVOKED_STATUS_CACOMPROMISE));
++
++ /* The certificate is on hold */
++ rb_define_const(mOCSP, "REVOKED_STATUS_CERTIFICATEHOLD", INT2NUM(OCSP_REVOKED_STATUS_CERTIFICATEHOLD));
++
++ /* The certificate is no longer needed */
++ rb_define_const(mOCSP, "REVOKED_STATUS_CESSATIONOFOPERATION", INT2NUM(OCSP_REVOKED_STATUS_CESSATIONOFOPERATION));
++
++ /* The certificate was revoked due to a key compromise */
++ rb_define_const(mOCSP, "REVOKED_STATUS_KEYCOMPROMISE", INT2NUM(OCSP_REVOKED_STATUS_KEYCOMPROMISE));
++
++ /* The certificate was previously on hold and should now be removed from
++ * the CRL */
++ rb_define_const(mOCSP, "REVOKED_STATUS_REMOVEFROMCRL", INT2NUM(OCSP_REVOKED_STATUS_REMOVEFROMCRL));
++
++ /* The certificate was superseded by a new certificate */
++ rb_define_const(mOCSP, "REVOKED_STATUS_SUPERSEDED", INT2NUM(OCSP_REVOKED_STATUS_SUPERSEDED));
++
++ /* Your request is unauthorized. */
++ rb_define_const(mOCSP, "RESPONSE_STATUS_UNAUTHORIZED", INT2NUM(OCSP_RESPONSE_STATUS_UNAUTHORIZED));
++
++ /* The certificate was revoked for an unspecified reason */
++ rb_define_const(mOCSP, "REVOKED_STATUS_UNSPECIFIED", INT2NUM(OCSP_REVOKED_STATUS_UNSPECIFIED));
++
++ /* Do not include certificates in the response */
++ rb_define_const(mOCSP, "NOCERTS", INT2NUM(OCSP_NOCERTS));
++
++ /* Do not search certificates contained in the response for a signer */
++ rb_define_const(mOCSP, "NOINTERN", INT2NUM(OCSP_NOINTERN));
++
++ /* Do not check the signature on the response */
++ rb_define_const(mOCSP, "NOSIGS", INT2NUM(OCSP_NOSIGS));
++
++ /* Do not verify the certificate chain on the response */
++ rb_define_const(mOCSP, "NOCHAIN", INT2NUM(OCSP_NOCHAIN));
++
++ /* Do not verify the response at all */
++ rb_define_const(mOCSP, "NOVERIFY", INT2NUM(OCSP_NOVERIFY));
++
++ /* Do not check trust */
++ rb_define_const(mOCSP, "NOEXPLICIT", INT2NUM(OCSP_NOEXPLICIT));
++
++ /* (This flag is not used by OpenSSL 1.0.1g) */
++ rb_define_const(mOCSP, "NOCASIGN", INT2NUM(OCSP_NOCASIGN));
++
++ /* (This flag is not used by OpenSSL 1.0.1g) */
++ rb_define_const(mOCSP, "NODELEGATED", INT2NUM(OCSP_NODELEGATED));
++
++ /* Do not make additional signing certificate checks */
++ rb_define_const(mOCSP, "NOCHECKS", INT2NUM(OCSP_NOCHECKS));
++
++ /* Do not verify additional certificates */
++ rb_define_const(mOCSP, "TRUSTOTHER", INT2NUM(OCSP_TRUSTOTHER));
++
++ /* Identify the response by signing the certificate key ID */
++ rb_define_const(mOCSP, "RESPID_KEY", INT2NUM(OCSP_RESPID_KEY));
++
++ /* Do not include producedAt time in response */
++ rb_define_const(mOCSP, "NOTIME", INT2NUM(OCSP_NOTIME));
++
++ /* Indicates the certificate is not revoked but does not necessarily mean
++ * the certificate was issued or that this response is within the
++ * certificate's validity interval */
++ rb_define_const(mOCSP, "V_CERTSTATUS_GOOD", INT2NUM(V_OCSP_CERTSTATUS_GOOD));
++ /* Indicates the certificate has been revoked either permanently or
++ * temporarily (on hold). */
++ rb_define_const(mOCSP, "V_CERTSTATUS_REVOKED", INT2NUM(V_OCSP_CERTSTATUS_REVOKED));
++
++ /* Indicates the responder does not know about the certificate being
++ * requested. */
++ rb_define_const(mOCSP, "V_CERTSTATUS_UNKNOWN", INT2NUM(V_OCSP_CERTSTATUS_UNKNOWN));
++
++ /* The responder ID is based on the key name. */
++ rb_define_const(mOCSP, "V_RESPID_NAME", INT2NUM(V_OCSP_RESPID_NAME));
++
++ /* The responder ID is based on the public key. */
++ rb_define_const(mOCSP, "V_RESPID_KEY", INT2NUM(V_OCSP_RESPID_KEY));
+ }
+
+ #else /* ! OSSL_OCSP_ENABLED */
+ void
+-Init_ossl_ocsp()
++Init_ossl_ocsp(void)
+ {
+ }
+ #endif
+diff --git a/ext/openssl_cms/ossl_pkcs12.c b/ext/openssl_cms/ossl_pkcs12.c
+index 8a5f816..53e0e61 100644
+--- a/ext/openssl_cms/ossl_pkcs12.c
++++ b/ext/openssl_cms/ossl_pkcs12.c
+@@ -7,11 +7,11 @@
+
+ #define WrapPKCS12(klass, obj, p12) do { \
+ if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \
+- (obj) = Data_Wrap_Struct((klass), 0, PKCS12_free, (p12)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs12_type, (p12)); \
+ } while (0)
+
+ #define GetPKCS12(obj, p12) do { \
+- Data_Get_Struct((obj), PKCS12, (p12)); \
++ TypedData_Get_Struct((obj), PKCS12, &ossl_pkcs12_type, (p12)); \
+ if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \
+ } while (0)
+
+@@ -36,6 +36,20 @@ VALUE ePKCS12Error;
+ /*
+ * Private
+ */
++static void
++ossl_pkcs12_free(void *ptr)
++{
++ PKCS12_free(ptr);
++}
++
++static const rb_data_type_t ossl_pkcs12_type = {
++ "OpenSSL/PKCS12",
++ {
++ 0, ossl_pkcs12_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE
+ ossl_pkcs12_s_allocate(VALUE klass)
+ {
+@@ -192,7 +206,7 @@ ossl_pkcs12_to_der(VALUE self)
+ }
+
+ void
+-Init_ossl_pkcs12()
++Init_ossl_pkcs12(void)
+ {
+ /*
+ * Defines a file format commonly used to store private keys with
+diff --git a/ext/openssl_cms/ossl_pkcs5.c b/ext/openssl_cms/ossl_pkcs5.c
+index 3b615e4..6c7738a 100644
+--- a/ext/openssl_cms/ossl_pkcs5.c
++++ b/ext/openssl_cms/ossl_pkcs5.c
+@@ -87,7 +87,7 @@ ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALU
+ #endif
+
+ void
+-Init_ossl_pkcs5()
++Init_ossl_pkcs5(void)
+ {
+ /*
+ * Password-based Encryption
+diff --git a/ext/openssl_cms/ossl_pkcs7.c b/ext/openssl_cms/ossl_pkcs7.c
+index 553a580..f4a5088 100644
+--- a/ext/openssl_cms/ossl_pkcs7.c
++++ b/ext/openssl_cms/ossl_pkcs7.c
+@@ -14,10 +14,10 @@
+ if (!(pkcs7)) { \
+ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, PKCS7_free, (pkcs7)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs7_type, (pkcs7)); \
+ } while (0)
+ #define GetPKCS7(obj, pkcs7) do { \
+- Data_Get_Struct((obj), PKCS7, (pkcs7)); \
++ TypedData_Get_Struct((obj), PKCS7, &ossl_pkcs7_type, (pkcs7)); \
+ if (!(pkcs7)) { \
+ ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
+ } \
+@@ -31,10 +31,10 @@
+ if (!(p7si)) { \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, PKCS7_SIGNER_INFO_free, (p7si)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs7_signer_info_type, (p7si)); \
+ } while (0)
+ #define GetPKCS7si(obj, p7si) do { \
+- Data_Get_Struct((obj), PKCS7_SIGNER_INFO, (p7si)); \
++ TypedData_Get_Struct((obj), PKCS7_SIGNER_INFO, &ossl_pkcs7_signer_info_type, (p7si)); \
+ if (!(p7si)) { \
+ ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+ } \
+@@ -48,10 +48,10 @@
+ if (!(p7ri)) { \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, PKCS7_RECIP_INFO_free, (p7ri)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_pkcs7_recip_info_type, (p7ri)); \
+ } while (0)
+ #define GetPKCS7ri(obj, p7ri) do { \
+- Data_Get_Struct((obj), PKCS7_RECIP_INFO, (p7ri)); \
++ TypedData_Get_Struct((obj), PKCS7_RECIP_INFO, &ossl_pkcs7_recip_info_type, (p7ri)); \
+ if (!(p7ri)) { \
+ ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+ } \
+@@ -76,6 +76,48 @@ VALUE cPKCS7Signer;
+ VALUE cPKCS7Recipient;
+ VALUE ePKCS7Error;
+
++static void
++ossl_pkcs7_free(void *ptr)
++{
++ PKCS7_free(ptr);
++}
++
++static const rb_data_type_t ossl_pkcs7_type = {
++ "OpenSSL/PKCS7",
++ {
++ 0, ossl_pkcs7_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
++static void
++ossl_pkcs7_signer_info_free(void *ptr)
++{
++ PKCS7_SIGNER_INFO_free(ptr);
++}
++
++static const rb_data_type_t ossl_pkcs7_signer_info_type = {
++ "OpenSSL/PKCS7/SIGNER_INFO",
++ {
++ 0, ossl_pkcs7_signer_info_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
++static void
++ossl_pkcs7_recip_info_free(void *ptr)
++{
++ PKCS7_RECIP_INFO_free(ptr);
++}
++
++static const rb_data_type_t ossl_pkcs7_recip_info_type = {
++ "OpenSSL/PKCS7/RECIP_INFO",
++ {
++ 0, ossl_pkcs7_recip_info_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public
+ * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM)
+@@ -362,9 +404,10 @@ ossl_pkcs7_sym2typeid(VALUE sym)
+ {
+ int i, ret = Qnil;
+ const char *s;
++ size_t l;
+
+- static struct {
+- const char *name;
++ static const struct {
++ char name[20];
+ int nid;
+ } p7_type_tab[] = {
+ { "signed", NID_pkcs7_signed },
+@@ -373,14 +416,15 @@ ossl_pkcs7_sym2typeid(VALUE sym)
+ { "enveloped", NID_pkcs7_enveloped },
+ { "encrypted", NID_pkcs7_encrypted },
+ { "digest", NID_pkcs7_digest },
+- { NULL, 0 },
+ };
+
+- if(TYPE(sym) == T_SYMBOL) s = rb_id2name(SYM2ID(sym));
+- else s = StringValuePtr(sym);
+- for(i = 0; i < numberof(p7_type_tab); i++){
+- if(p7_type_tab[i].name == NULL)
++ if (RB_TYPE_P(sym, T_SYMBOL)) sym = rb_sym2str(sym);
++ else StringValue(sym);
++ RSTRING_GETMEM(sym, s, l);
++ for(i = 0; ; i++){
++ if(i == numberof(p7_type_tab))
+ ossl_raise(ePKCS7Error, "unknown type \"%s\"", s);
++ if(strlen(p7_type_tab[i].name) != l) continue;
+ if(strcmp(p7_type_tab[i].name, s) == 0){
+ ret = p7_type_tab[i].nid;
+ break;
+@@ -978,7 +1022,7 @@ ossl_pkcs7ri_get_enc_key(VALUE self)
+ * INIT
+ */
+ void
+-Init_ossl_pkcs7()
++Init_ossl_pkcs7(void)
+ {
+ cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
+ ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
+diff --git a/ext/openssl_cms/ossl_pkey.c b/ext/openssl_cms/ossl_pkey.c
+index 878b221..aa9b046 100644
+--- a/ext/openssl_cms/ossl_pkey.c
++++ b/ext/openssl_cms/ossl_pkey.c
+@@ -69,9 +69,23 @@ ossl_generate_cb_stop(void *ptr)
+ }
+ #endif
+
++static void
++ossl_evp_pkey_free(void *ptr)
++{
++ EVP_PKEY_free(ptr);
++}
++
+ /*
+ * Public
+ */
++const rb_data_type_t ossl_evp_pkey_type = {
++ "OpenSSL/EVP_PKEY",
++ {
++ 0, ossl_evp_pkey_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ VALUE
+ ossl_pkey_new(EVP_PKEY *pkey)
+ {
+@@ -342,7 +356,7 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
+ * INIT
+ */
+ void
+-Init_ossl_pkey()
++Init_ossl_pkey(void)
+ {
+ #if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+diff --git a/ext/openssl_cms/ossl_pkey.h b/ext/openssl_cms/ossl_pkey.h
+index 686e956..6c0b7fd 100644
+--- a/ext/openssl_cms/ossl_pkey.h
++++ b/ext/openssl_cms/ossl_pkey.h
+@@ -15,6 +15,7 @@ extern VALUE mPKey;
+ extern VALUE cPKey;
+ extern VALUE ePKeyError;
+ extern ID id_private_q;
++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)
+@@ -24,11 +25,11 @@ extern ID id_private_q;
+ if (!(pkey)) { \
+ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, EVP_PKEY_free, (pkey)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_evp_pkey_type, (pkey)); \
+ OSSL_PKEY_SET_PUBLIC(obj); \
+ } while (0)
+ #define GetPKey(obj, pkey) do {\
+- Data_Get_Struct((obj), EVP_PKEY, (pkey));\
++ TypedData_Get_Struct((obj), EVP_PKEY, &ossl_evp_pkey_type, (pkey)); \
+ if (!(pkey)) { \
+ rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
+ } \
+diff --git a/ext/openssl_cms/ossl_pkey_dh.c b/ext/openssl_cms/ossl_pkey_dh.c
+index 011b6f0..cf28326 100644
+--- a/ext/openssl_cms/ossl_pkey_dh.c
++++ b/ext/openssl_cms/ossl_pkey_dh.c
+@@ -588,7 +588,7 @@ ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen)
+ * INIT
+ */
+ void
+-Init_ossl_dh()
++Init_ossl_dh(void)
+ {
+ #if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
+@@ -660,7 +660,7 @@ Init_ossl_dh()
+
+ #else /* defined NO_DH */
+ void
+-Init_ossl_dh()
++Init_ossl_dh(void)
+ {
+ }
+ #endif /* NO_DH */
+diff --git a/ext/openssl_cms/ossl_pkey_dsa.c b/ext/openssl_cms/ossl_pkey_dsa.c
+index 823b9b6..979ae15 100644
+--- a/ext/openssl_cms/ossl_pkey_dsa.c
++++ b/ext/openssl_cms/ossl_pkey_dsa.c
+@@ -563,7 +563,7 @@ OSSL_PKEY_BN(dsa, priv_key)
+ * INIT
+ */
+ void
+-Init_ossl_dsa()
++Init_ossl_dsa(void)
+ {
+ #if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
+@@ -617,7 +617,7 @@ Init_ossl_dsa()
+
+ #else /* defined NO_DSA */
+ void
+-Init_ossl_dsa()
++Init_ossl_dsa(void)
+ {
+ }
+ #endif /* NO_DSA */
+diff --git a/ext/openssl_cms/ossl_pkey_ec.c b/ext/openssl_cms/ossl_pkey_ec.c
+index 5e419bd..d63f757 100644
+--- a/ext/openssl_cms/ossl_pkey_ec.c
++++ b/ext/openssl_cms/ossl_pkey_ec.c
+@@ -20,6 +20,8 @@ typedef struct {
+ #define EXPORT_PEM 0
+ #define EXPORT_DER 1
+
++static const rb_data_type_t ossl_ec_group_type;
++static const rb_data_type_t ossl_ec_point_type;
+
+ #define GetPKeyEC(obj, pkey) do { \
+ GetPKey((obj), (pkey)); \
+@@ -30,7 +32,7 @@ typedef struct {
+
+ #define SafeGet_ec_group(obj, group) do { \
+ OSSL_Check_Kind((obj), cEC_GROUP); \
+- Data_Get_Struct((obj), ossl_ec_group, (group)); \
++ TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, (group)); \
+ } while(0)
+
+ #define Get_EC_KEY(obj, key) do { \
+@@ -52,7 +54,7 @@ typedef struct {
+
+ #define Get_EC_GROUP(obj, g) do { \
+ ossl_ec_group *ec_group; \
+- Data_Get_Struct((obj), ossl_ec_group, ec_group); \
++ TypedData_Get_Struct((obj), ossl_ec_group, &ossl_ec_group_type, ec_group); \
+ if (ec_group == NULL) \
+ ossl_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
+ (g) = ec_group->group; \
+@@ -71,7 +73,7 @@ typedef struct {
+
+ #define Get_EC_POINT(obj, p) do { \
+ ossl_ec_point *ec_point; \
+- Data_Get_Struct((obj), ossl_ec_point, ec_point); \
++ TypedData_Get_Struct((obj), ossl_ec_point, &ossl_ec_point_type, ec_point); \
+ if (ec_point == NULL) \
+ ossl_raise(eEC_POINT, "missing ossl_ec_point structure"); \
+ (p) = ec_point->point; \
+@@ -369,7 +371,7 @@ static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v)
+ ossl_ec_point *new_point;
+
+ obj = rb_obj_alloc(cEC_POINT);
+- Data_Get_Struct(obj, ossl_ec_point, new_point);
++ TypedData_Get_Struct(obj, ossl_ec_point, &ossl_ec_point_type, new_point);
+
+ SafeRequire_EC_GROUP(group_v, group);
+
+@@ -707,19 +709,28 @@ static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
+ UNREACHABLE;
+ }
+
+-static void ossl_ec_group_free(ossl_ec_group *ec_group)
++static void ossl_ec_group_free(void *ptr)
+ {
++ ossl_ec_group *ec_group = ptr;
+ if (!ec_group->dont_free && ec_group->group)
+ EC_GROUP_clear_free(ec_group->group);
+ ruby_xfree(ec_group);
+ }
+
++static const rb_data_type_t ossl_ec_group_type = {
++ "OpenSSL/ec_group",
++ {
++ 0, ossl_ec_group_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE ossl_ec_group_alloc(VALUE klass)
+ {
+ ossl_ec_group *ec_group;
+ VALUE obj;
+
+- obj = Data_Make_Struct(klass, ossl_ec_group, 0, ossl_ec_group_free, ec_group);
++ obj = TypedData_Make_Struct(klass, ossl_ec_group, &ossl_ec_group_type, ec_group);
+
+ return obj;
+ }
+@@ -746,7 +757,7 @@ static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
+ ossl_ec_group *ec_group;
+ EC_GROUP *group = NULL;
+
+- Data_Get_Struct(self, ossl_ec_group, ec_group);
++ TypedData_Get_Struct(self, ossl_ec_group, &ossl_ec_group_type, ec_group);
+ if (ec_group->group != NULL)
+ ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
+
+@@ -1219,19 +1230,28 @@ static VALUE ossl_ec_group_to_text(VALUE self)
+ }
+
+
+-static void ossl_ec_point_free(ossl_ec_point *ec_point)
++static void ossl_ec_point_free(void *ptr)
+ {
++ ossl_ec_point *ec_point = ptr;
+ if (!ec_point->dont_free && ec_point->point)
+ EC_POINT_clear_free(ec_point->point);
+ ruby_xfree(ec_point);
+ }
+
++static const rb_data_type_t ossl_ec_point_type = {
++ "OpenSSL/ec_point",
++ {
++ 0, ossl_ec_point_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE ossl_ec_point_alloc(VALUE klass)
+ {
+ ossl_ec_point *ec_point;
+ VALUE obj;
+
+- obj = Data_Make_Struct(klass, ossl_ec_point, 0, ossl_ec_point_free, ec_point);
++ obj = TypedData_Make_Struct(klass, ossl_ec_point, &ossl_ec_point_type, ec_point);
+
+ return obj;
+ }
+@@ -1252,7 +1272,7 @@ static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
+ VALUE group_v = Qnil;
+ const EC_GROUP *group = NULL;
+
+- Data_Get_Struct(self, ossl_ec_point, ec_point);
++ TypedData_Get_Struct(self, ossl_ec_point, &ossl_ec_point_type, ec_point);
+ if (ec_point->point)
+ ossl_raise(eEC_POINT, "EC_POINT already initialized");
+
+@@ -1556,7 +1576,7 @@ static void no_copy(VALUE klass)
+ rb_undef_method(klass, "initialize_copy");
+ }
+
+-void Init_ossl_ec()
++void Init_ossl_ec(void)
+ {
+ #ifdef DONT_NEED_RDOC_WORKAROUND
+ mOSSL = rb_define_module("OpenSSL");
+@@ -1677,7 +1697,7 @@ void Init_ossl_ec()
+ }
+
+ #else /* defined NO_EC */
+-void Init_ossl_ec()
++void Init_ossl_ec(void)
+ {
+ }
+ #endif /* NO_EC */
+diff --git a/ext/openssl_cms/ossl_pkey_rsa.c b/ext/openssl_cms/ossl_pkey_rsa.c
+index 4c346a0..0fef10a 100644
+--- a/ext/openssl_cms/ossl_pkey_rsa.c
++++ b/ext/openssl_cms/ossl_pkey_rsa.c
+@@ -626,7 +626,7 @@ OSSL_PKEY_BN(rsa, iqmp)
+ #define DefRSAConst(x) rb_define_const(cRSA, #x,INT2FIX(RSA_##x))
+
+ void
+-Init_ossl_rsa()
++Init_ossl_rsa(void)
+ {
+ #if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
+@@ -694,7 +694,7 @@ Init_ossl_rsa()
+
+ #else /* defined NO_RSA */
+ void
+-Init_ossl_rsa()
++Init_ossl_rsa(void)
+ {
+ }
+ #endif /* NO_RSA */
+diff --git a/ext/openssl_cms/ossl_rand.c b/ext/openssl_cms/ossl_rand.c
+index 270a4b7..29cbf8c 100644
+--- a/ext/openssl_cms/ossl_rand.c
++++ b/ext/openssl_cms/ossl_rand.c
+@@ -2,36 +2,22 @@
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos at sh.cvut.cz>
++ *
+ * All rights reserved.
+- */
+-/*
++ *
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+ #include "ossl.h"
+
+-/*
+- * Classes
+- */
+ VALUE mRandom;
+ VALUE eRandomError;
+
+ /*
+- * Struct
+- */
+-
+-/*
+- * Public
+- */
+-
+-/*
+- * Private
+- */
+-
+-/*
+ * call-seq:
+ * seed(str) -> str
+ *
++ * ::seed is equivalent to ::add where +entropy+ is length of +str+.
+ */
+ static VALUE
+ ossl_rand_seed(VALUE self, VALUE str)
+@@ -46,6 +32,23 @@ ossl_rand_seed(VALUE self, VALUE str)
+ * call-seq:
+ * add(str, entropy) -> self
+ *
++ * Mixes the bytes from +str+ into the Pseudo Random Number Generator(PRNG)
++ * state.
++ *
++ * Thus, if the data from +str+ are unpredictable to an adversary, this
++ * increases the uncertainty about the state and makes the PRNG output less
++ * predictable.
++ *
++ * The +entropy+ argument is (the lower bound of) an estimate of how much
++ * randomness is contained in +str+, measured in bytes.
++ *
++ * Example:
++ *
++ * pid = $$
++ * now = Time.now
++ * ary = [now.to_i, now.nsec, 1000, pid]
++ * OpenSSL::Random.add(ary.join("").to_s, 0.0)
++ * OpenSSL::Random.seed(ary.join("").to_s)
+ */
+ static VALUE
+ ossl_rand_add(VALUE self, VALUE str, VALUE entropy)
+@@ -60,6 +63,7 @@ ossl_rand_add(VALUE self, VALUE str, VALUE entropy)
+ * call-seq:
+ * load_random_file(filename) -> true
+ *
++ * Reads bytes from +filename+ and adds them to the PRNG.
+ */
+ static VALUE
+ ossl_rand_load_file(VALUE self, VALUE filename)
+@@ -76,6 +80,9 @@ ossl_rand_load_file(VALUE self, VALUE filename)
+ * call-seq:
+ * write_random_file(filename) -> true
+ *
++ * Writes a number of random generated bytes (currently 1024) to +filename+
++ * which can be used to initialize the PRNG by calling ::load_random_file in a
++ * later session.
+ */
+ static VALUE
+ ossl_rand_write_file(VALUE self, VALUE filename)
+@@ -89,8 +96,15 @@ ossl_rand_write_file(VALUE self, VALUE filename)
+
+ /*
+ * call-seq:
+- * random_bytes(length) -> aString
++ * random_bytes(length) -> string
++ *
++ * Generates +string+ with +length+ number of cryptographically strong
++ * pseudo-random bytes.
+ *
++ * Example:
++ *
++ * OpenSSL::Random.random_bytes(12)
++ * => "..."
+ */
+ static VALUE
+ ossl_rand_bytes(VALUE self, VALUE len)
+@@ -108,8 +122,17 @@ ossl_rand_bytes(VALUE self, VALUE len)
+
+ /*
+ * call-seq:
+- * pseudo_bytes(length) -> aString
++ * pseudo_bytes(length) -> string
++ *
++ * Generates +string+ with +length+ number of pseudo-random bytes.
++ *
++ * Pseudo-random byte sequences generated by ::pseudo_bytes will be unique if
++ * they are of sufficient length, but are not necessarily unpredictable.
+ *
++ * Example:
++ *
++ * OpenSSL::Random.pseudo_bytes(12)
++ * => "..."
+ */
+ static VALUE
+ ossl_rand_pseudo_bytes(VALUE self, VALUE len)
+@@ -129,6 +152,7 @@ ossl_rand_pseudo_bytes(VALUE self, VALUE len)
+ * call-seq:
+ * egd(filename) -> true
+ *
++ * Same as ::egd_bytes but queries 255 bytes by default.
+ */
+ static VALUE
+ ossl_rand_egd(VALUE self, VALUE filename)
+@@ -145,6 +169,10 @@ ossl_rand_egd(VALUE self, VALUE filename)
+ * call-seq:
+ * egd_bytes(filename, length) -> true
+ *
++ * Queries the entropy gathering daemon EGD on socket path given by +filename+.
++ *
++ * Fetches +length+ number of bytes and uses ::add to seed the OpenSSL built-in
++ * PRNG.
+ */
+ static VALUE
+ ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
+@@ -171,15 +199,11 @@ ossl_rand_status(VALUE self)
+ return RAND_status() ? Qtrue : Qfalse;
+ }
+
+-#define DEFMETH(class, name, func, argc) \
+- rb_define_method((class), (name), (func), (argc)); \
+- rb_define_singleton_method((class), (name), (func), (argc));
+-
+ /*
+ * INIT
+ */
+ void
+-Init_ossl_rand()
++Init_ossl_rand(void)
+ {
+ #if 0
+ mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+@@ -189,14 +213,14 @@ Init_ossl_rand()
+
+ eRandomError = rb_define_class_under(mRandom, "RandomError", eOSSLError);
+
+- DEFMETH(mRandom, "seed", ossl_rand_seed, 1);
+- DEFMETH(mRandom, "random_add", ossl_rand_add, 2);
+- DEFMETH(mRandom, "load_random_file", ossl_rand_load_file, 1);
+- DEFMETH(mRandom, "write_random_file", ossl_rand_write_file, 1);
+- DEFMETH(mRandom, "random_bytes", ossl_rand_bytes, 1);
+- DEFMETH(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1);
+- DEFMETH(mRandom, "egd", ossl_rand_egd, 1);
+- DEFMETH(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2);
+- DEFMETH(mRandom, "status?", ossl_rand_status, 0)
++ rb_define_module_function(mRandom, "seed", ossl_rand_seed, 1);
++ rb_define_module_function(mRandom, "random_add", ossl_rand_add, 2);
++ rb_define_module_function(mRandom, "load_random_file", ossl_rand_load_file, 1);
++ rb_define_module_function(mRandom, "write_random_file", ossl_rand_write_file, 1);
++ rb_define_module_function(mRandom, "random_bytes", ossl_rand_bytes, 1);
++ rb_define_module_function(mRandom, "pseudo_bytes", ossl_rand_pseudo_bytes, 1);
++ rb_define_module_function(mRandom, "egd", ossl_rand_egd, 1);
++ rb_define_module_function(mRandom, "egd_bytes", ossl_rand_egd_bytes, 2);
++ rb_define_module_function(mRandom, "status?", ossl_rand_status, 0);
+ }
+
+diff --git a/ext/openssl_cms/ossl_ssl.c b/ext/openssl_cms/ossl_ssl.c
+index 206470c..af93252 100644
+--- a/ext/openssl_cms/ossl_ssl.c
++++ b/ext/openssl_cms/ossl_ssl.c
+@@ -24,6 +24,10 @@
+ # define TO_SOCKET(s) (s)
+ #endif
+
++#define GetSSLCTX(obj, ctx) do { \
++ TypedData_Get_Struct((obj), SSL_CTX, &ossl_sslctx_type, (ctx)); \
++} while (0)
++
+ VALUE mSSL;
+ VALUE eSSLError;
+ VALUE cSSLContext;
+@@ -108,7 +112,7 @@ static VALUE sym_exception;
+ /*
+ * SSLContext class
+ */
+-struct {
++static const struct {
+ const char *name;
+ SSL_METHOD *(*func)(void);
+ } ossl_ssl_method_tab[] = {
+@@ -150,13 +154,22 @@ int ossl_ssl_ex_client_cert_cb_idx;
+ int ossl_ssl_ex_tmp_dh_callback_idx;
+
+ static void
+-ossl_sslctx_free(SSL_CTX *ctx)
++ossl_sslctx_free(void *ptr)
+ {
++ SSL_CTX *ctx = ptr;
+ if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1)
+ ctx->cert_store = NULL;
+ SSL_CTX_free(ctx);
+ }
+
++static const rb_data_type_t ossl_sslctx_type = {
++ "OpenSSL/SSL/CTX",
++ {
++ 0, ossl_sslctx_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE
+ ossl_sslctx_s_alloc(VALUE klass)
+ {
+@@ -172,7 +185,7 @@ ossl_sslctx_s_alloc(VALUE klass)
+ ossl_raise(eSSLError, "SSL_CTX_new");
+ }
+ SSL_CTX_set_mode(ctx, mode);
+- return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx);
++ return TypedData_Wrap_Struct(klass, &ossl_sslctx_type, ctx);
+ }
+
+ /*
+@@ -190,7 +203,7 @@ ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
+ int i;
+
+ SSL_CTX *ctx;
+- if(TYPE(ssl_method) == T_SYMBOL)
++ if (RB_TYPE_P(ssl_method, T_SYMBOL))
+ s = rb_id2name(SYM2ID(ssl_method));
+ else
+ s = StringValuePtr(ssl_method);
+@@ -203,7 +216,7 @@ ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
+ if (!method) {
+ ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s);
+ }
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+ if (SSL_CTX_set_ssl_version(ctx, method) != 1) {
+ ossl_raise(eSSLError, "SSL_CTX_set_ssl_version");
+ }
+@@ -244,7 +257,7 @@ ossl_call_client_cert_cb(VALUE obj)
+ VALUE cb, ary, cert, key;
+ SSL *ssl;
+
+- Data_Get_Struct(obj, SSL, ssl);
++ GetSSL(obj, ssl);
+ cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx);
+ if (NIL_P(cb)) return Qfalse;
+ ary = rb_funcall(cb, rb_intern("call"), 1, obj);
+@@ -280,7 +293,7 @@ ossl_call_tmp_dh_callback(VALUE *args)
+ VALUE cb, dh;
+ EVP_PKEY *pkey;
+
+- Data_Get_Struct(args[0], SSL, ssl);
++ GetSSL(args[0], ssl);
+ cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx);
+ if (NIL_P(cb)) return Qfalse;
+ dh = rb_funcall(cb, rb_intern("call"), 3, args[0], args[1], args[2]);
+@@ -482,7 +495,7 @@ ossl_sslctx_add_extra_chain_cert_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, arg))
+ X509 *x509;
+ SSL_CTX *ctx;
+
+- Data_Get_Struct(arg, SSL_CTX, ctx);
++ GetSSLCTX(arg, ctx);
+ x509 = DupX509CertPtr(i);
+ if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){
+ ossl_raise(eSSLError, NULL);
+@@ -513,8 +526,8 @@ ossl_call_servername_cb(VALUE ary)
+ SSL_CTX *ctx2;
+
+ ossl_sslctx_setup(ret_obj);
+- Data_Get_Struct(ssl_obj, SSL, ssl);
+- Data_Get_Struct(ret_obj, SSL_CTX, ctx2);
++ GetSSL(ssl_obj, ssl);
++ GetSSLCTX(ret_obj, ctx2);
+ SSL_set_SSL_CTX(ssl, ctx2);
+ } else if (!NIL_P(ret_obj)) {
+ ossl_raise(rb_eArgError, "servername_cb must return an OpenSSL::SSL::SSLContext object or nil");
+@@ -665,7 +678,7 @@ ossl_sslctx_setup(VALUE self)
+ VALUE val;
+
+ if(OBJ_FROZEN(self)) return Qnil;
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+
+ #if !defined(OPENSSL_NO_DH)
+ if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){
+@@ -716,7 +729,7 @@ ossl_sslctx_setup(VALUE self)
+
+ val = ossl_sslctx_get_client_ca(self);
+ if(!NIL_P(val)){
+- if(TYPE(val) == T_ARRAY){
++ if (RB_TYPE_P(val, T_ARRAY)) {
+ for(i = 0; i < RARRAY_LEN(val); i++){
+ client_ca = GetX509CertPtr(RARRAY_PTR(val)[i]);
+ if (!SSL_CTX_add_client_CA(ctx, client_ca)){
+@@ -841,7 +854,7 @@ ossl_sslctx_get_ciphers(VALUE self)
+ VALUE ary;
+ int i, num;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+ if(!ctx){
+ rb_warning("SSL_CTX is not initialized.");
+ return Qnil;
+@@ -882,11 +895,11 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
+ rb_check_frozen(self);
+ if (NIL_P(v))
+ return v;
+- else if (TYPE(v) == T_ARRAY) {
++ else if (RB_TYPE_P(v, T_ARRAY)) {
+ str = rb_str_new(0, 0);
+ for (i = 0; i < RARRAY_LEN(v); i++) {
+ elem = rb_ary_entry(v, i);
+- if (TYPE(elem) == T_ARRAY) elem = rb_ary_entry(elem, 0);
++ if (RB_TYPE_P(elem, T_ARRAY)) elem = rb_ary_entry(elem, 0);
+ elem = rb_String(elem);
+ rb_str_append(str, elem);
+ if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
+@@ -896,7 +909,7 @@ ossl_sslctx_set_ciphers(VALUE self, VALUE v)
+ StringValue(str);
+ }
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+ if(!ctx){
+ ossl_raise(eSSLError, "SSL_CTX is not initialized.");
+ return Qnil;
+@@ -920,7 +933,7 @@ ossl_sslctx_session_add(VALUE self, VALUE arg)
+ SSL_CTX *ctx;
+ SSL_SESSION *sess;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+ SafeGetSSLSession(arg, sess);
+
+ return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;
+@@ -938,7 +951,7 @@ ossl_sslctx_session_remove(VALUE self, VALUE arg)
+ SSL_CTX *ctx;
+ SSL_SESSION *sess;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+ SafeGetSSLSession(arg, sess);
+
+ return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;
+@@ -955,7 +968,7 @@ ossl_sslctx_get_session_cache_mode(VALUE self)
+ {
+ SSL_CTX *ctx;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+
+ return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx));
+ }
+@@ -973,7 +986,7 @@ ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
+ {
+ SSL_CTX *ctx;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+
+ SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg));
+
+@@ -992,7 +1005,7 @@ ossl_sslctx_get_session_cache_size(VALUE self)
+ {
+ SSL_CTX *ctx;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+
+ return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx));
+ }
+@@ -1009,7 +1022,7 @@ ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
+ {
+ SSL_CTX *ctx;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+
+ SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg));
+
+@@ -1044,7 +1057,7 @@ ossl_sslctx_get_session_cache_stats(VALUE self)
+ SSL_CTX *ctx;
+ VALUE hash;
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+
+ hash = rb_hash_new();
+ rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
+@@ -1079,7 +1092,7 @@ ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
+
+ rb_scan_args(argc, argv, "01", &arg1);
+
+- Data_Get_Struct(self, SSL_CTX, ctx);
++ GetSSLCTX(self, ctx);
+
+ if (NIL_P(arg1)) {
+ tm = time(0);
+@@ -1120,15 +1133,23 @@ ossl_ssl_shutdown(SSL *ssl)
+ }
+
+ static void
+-ossl_ssl_free(SSL *ssl)
++ossl_ssl_free(void *ssl)
+ {
+ SSL_free(ssl);
+ }
+
++const rb_data_type_t ossl_ssl_type = {
++ "OpenSSL/SSL",
++ {
++ 0, ossl_ssl_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE
+ ossl_ssl_s_alloc(VALUE klass)
+ {
+- return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL);
++ return TypedData_Wrap_Struct(klass, &ossl_ssl_type, NULL);
+ }
+
+ /*
+@@ -1177,14 +1198,14 @@ ossl_ssl_setup(VALUE self)
+ SSL *ssl;
+ rb_io_t *fptr;
+
+- Data_Get_Struct(self, SSL, ssl);
++ GetSSL(self, ssl);
+ if(!ssl){
+ #ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+ VALUE hostname = rb_iv_get(self, "@hostname");
+ #endif
+
+ v_ctx = ossl_ssl_get_ctx(self);
+- Data_Get_Struct(v_ctx, SSL_CTX, ctx);
++ GetSSLCTX(v_ctx, ctx);
+
+ ssl = SSL_new(ctx);
+ if (!ssl) {
+@@ -1224,7 +1245,7 @@ ossl_ssl_setup(VALUE self)
+
+ #define ossl_ssl_data_get_struct(v, ssl) \
+ do { \
+- Data_Get_Struct((v), SSL, (ssl)); \
++ GetSSL((v), (ssl)); \
+ if (!(ssl)) { \
+ rb_warning("SSL session is not started yet."); \
+ return Qnil; \
+@@ -1394,7 +1415,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
+ }
+ if(ilen == 0) return str;
+
+- Data_Get_Struct(self, SSL, ssl);
++ GetSSL(self, ssl);
+ GetOpenFile(ossl_ssl_get_io(self), fptr);
+ if (ssl) {
+ if(!nonblock && SSL_pending(ssl) <= 0)
+@@ -1431,7 +1452,11 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
+ else {
+ ID meth = nonblock ? rb_intern("read_nonblock") : rb_intern("sysread");
+ rb_warning("SSL session is not started yet.");
+- return rb_funcall(ossl_ssl_get_io(self), meth, 2, len, str);
++ if (nonblock) {
++ return rb_funcall(ossl_ssl_get_io(self), meth, 3, len, str, opts);
++ } else {
++ return rb_funcall(ossl_ssl_get_io(self), meth, 2, len, str);
++ }
+ }
+
+ end:
+@@ -1482,7 +1507,7 @@ ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception)
+ rb_io_t *fptr;
+
+ StringValue(str);
+- Data_Get_Struct(self, SSL, ssl);
++ GetSSL(self, ssl);
+ GetOpenFile(ossl_ssl_get_io(self), fptr);
+
+ if (ssl) {
+@@ -1562,18 +1587,22 @@ static VALUE
+ ossl_ssl_close(VALUE self)
+ {
+ SSL *ssl;
++ VALUE io;
+
+- ossl_ssl_data_get_struct(self, ssl);
++ /* ossl_ssl_data_get_struct() is not usable here because it may return
++ * from this function; */
+
+- if (ssl) {
+- VALUE io = ossl_ssl_get_io(self);
+- if (!RTEST(rb_funcall(io, rb_intern("closed?"), 0))) {
+- ossl_ssl_shutdown(ssl);
+- SSL_free(ssl);
+- DATA_PTR(self) = NULL;
+- if (RTEST(ossl_ssl_get_sync_close(self)))
+- rb_funcall(io, rb_intern("close"), 0);
+- }
++ GetSSL(self, ssl);
++
++ io = ossl_ssl_get_io(self);
++ if (!RTEST(rb_funcall(io, rb_intern("closed?"), 0))) {
++ if (ssl) {
++ ossl_ssl_shutdown(ssl);
++ SSL_free(ssl);
++ }
++ DATA_PTR(self) = NULL;
++ if (RTEST(ossl_ssl_get_sync_close(self)))
++ rb_funcall(io, rb_intern("close"), 0);
+ }
+
+ return Qnil;
+@@ -1850,7 +1879,7 @@ ossl_ssl_npn_protocol(VALUE self)
+ #endif /* !defined(OPENSSL_NO_SOCK) */
+
+ void
+-Init_ossl_ssl()
++Init_ossl_ssl(void)
+ {
+ int i;
+ VALUE ary;
+@@ -2019,7 +2048,7 @@ Init_ossl_ssl()
+ rb_attr(cSSLContext, rb_intern("session_get_cb"), 1, 1, Qfalse);
+
+ /*
+- * A callback invoked when a new session was negotiatied.
++ * A callback invoked when a new session was negotiated.
+ *
+ * The callback is invoked with an SSLSocket. If false is returned the
+ * session will be removed from the internal cache.
+diff --git a/ext/openssl_cms/ossl_ssl.h b/ext/openssl_cms/ossl_ssl.h
+index 034762f..0c20b10 100644
+--- a/ext/openssl_cms/ossl_ssl.h
++++ b/ext/openssl_cms/ossl_ssl.h
+@@ -11,8 +11,12 @@
+ #if !defined(_OSSL_SSL_H_)
+ #define _OSSL_SSL_H_
+
++#define GetSSL(obj, ssl) do { \
++ TypedData_Get_Struct((obj), SSL, &ossl_ssl_type, (ssl)); \
++} while (0)
++
+ #define GetSSLSession(obj, sess) do { \
+- Data_Get_Struct((obj), SSL_SESSION, (sess)); \
++ TypedData_Get_Struct((obj), SSL_SESSION, &ossl_ssl_session_type, (sess)); \
+ if (!(sess)) { \
+ ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
+ } \
+@@ -23,6 +27,8 @@
+ GetSSLSession((obj), (sess)); \
+ } while (0)
+
++extern const rb_data_type_t ossl_ssl_type;
++extern const rb_data_type_t ossl_ssl_session_type;
+ extern VALUE mSSL;
+ extern VALUE eSSLError;
+ extern VALUE cSSLSocket;
+diff --git a/ext/openssl_cms/ossl_ssl_session.c b/ext/openssl_cms/ossl_ssl_session.c
+index a7437ca..5318f1a 100644
+--- a/ext/openssl_cms/ossl_ssl_session.c
++++ b/ext/openssl_cms/ossl_ssl_session.c
+@@ -4,25 +4,26 @@
+
+ #include "ossl.h"
+
+-#define GetSSLSession(obj, sess) do { \
+- Data_Get_Struct((obj), SSL_SESSION, (sess)); \
+- if (!(sess)) { \
+- ossl_raise(rb_eRuntimeError, "SSL Session wasn't initialized."); \
+- } \
+-} while (0)
+-
+-#define SafeGetSSLSession(obj, sess) do { \
+- OSSL_Check_Kind((obj), cSSLSession); \
+- GetSSLSession((obj), (sess)); \
+-} while (0)
+-
+-
+ VALUE cSSLSession;
+ static VALUE eSSLSession;
+
++static void
++ossl_ssl_session_free(void *ptr)
++{
++ SSL_SESSION_free(ptr);
++}
++
++const rb_data_type_t ossl_ssl_session_type = {
++ "OpenSSL/SSL/Session",
++ {
++ 0, ossl_ssl_session_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE ossl_ssl_session_alloc(VALUE klass)
+ {
+- return Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL);
++ return TypedData_Wrap_Struct(klass, &ossl_ssl_session_type, NULL);
+ }
+
+ /*
+@@ -43,7 +44,7 @@ static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1)
+ if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
+ SSL *ssl;
+
+- Data_Get_Struct(arg1, SSL, ssl);
++ GetSSL(arg1, ssl);
+
+ if (!ssl || (ctx = SSL_get1_session(ssl)) == NULL)
+ ossl_raise(eSSLSession, "no session available");
+diff --git a/ext/openssl_cms/ossl_x509.c b/ext/openssl_cms/ossl_x509.c
+index fd1d9b6..4de4545 100644
+--- a/ext/openssl_cms/ossl_x509.c
++++ b/ext/openssl_cms/ossl_x509.c
+@@ -17,7 +17,7 @@ VALUE mX509;
+ rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i()))
+
+ void
+-Init_ossl_x509()
++Init_ossl_x509(void)
+ {
+ mX509 = rb_define_module_under(mOSSL, "X509");
+
+diff --git a/ext/openssl_cms/ossl_x509attr.c b/ext/openssl_cms/ossl_x509attr.c
+index d50f88c..c9036ca 100644
+--- a/ext/openssl_cms/ossl_x509attr.c
++++ b/ext/openssl_cms/ossl_x509attr.c
+@@ -14,10 +14,10 @@
+ if (!(attr)) { \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_ATTRIBUTE_free, (attr)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509attr_type, (attr)); \
+ } while (0)
+ #define GetX509Attr(obj, attr) do { \
+- Data_Get_Struct((obj), X509_ATTRIBUTE, (attr)); \
++ TypedData_Get_Struct((obj), X509_ATTRIBUTE, &ossl_x509attr_type, (attr)); \
+ if (!(attr)) { \
+ ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+ } \
+@@ -33,6 +33,20 @@
+ VALUE cX509Attr;
+ VALUE eX509AttrError;
+
++static void
++ossl_x509attr_free(void *ptr)
++{
++ X509_ATTRIBUTE_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509attr_type = {
++ "OpenSSL/X509/ATTRIBUTE",
++ {
++ 0, ossl_x509attr_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public
+ */
+@@ -260,7 +274,7 @@ ossl_x509attr_to_der(VALUE self)
+ * X509_ATTRIBUTE init
+ */
+ void
+-Init_ossl_x509attr()
++Init_ossl_x509attr(void)
+ {
+ eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError);
+
+diff --git a/ext/openssl_cms/ossl_x509cert.c b/ext/openssl_cms/ossl_x509cert.c
+index 84cedc7..b76ea79 100644
+--- a/ext/openssl_cms/ossl_x509cert.c
++++ b/ext/openssl_cms/ossl_x509cert.c
+@@ -14,10 +14,10 @@
+ if (!(x509)) { \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_free, (x509)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509_type, (x509)); \
+ } while (0)
+ #define GetX509(obj, x509) do { \
+- Data_Get_Struct((obj), X509, (x509)); \
++ TypedData_Get_Struct((obj), X509, &ossl_x509_type, (x509)); \
+ if (!(x509)) { \
+ ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+ } \
+@@ -33,6 +33,20 @@
+ VALUE cX509Cert;
+ VALUE eX509CertError;
+
++static void
++ossl_x509_free(void *ptr)
++{
++ X509_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509_type = {
++ "OpenSSL/X509",
++ {
++ 0, ossl_x509_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public
+ */
+@@ -693,42 +707,22 @@ ossl_x509_add_extension(VALUE self, VALUE extension)
+ static VALUE
+ ossl_x509_inspect(VALUE self)
+ {
+- VALUE str;
+- const char *cname = rb_class2name(rb_obj_class(self));
+-
+- str = rb_str_new2("#<");
+- rb_str_cat2(str, cname);
+- rb_str_cat2(str, " ");
+-
+- rb_str_cat2(str, "subject=");
+- rb_str_append(str, rb_inspect(ossl_x509_get_subject(self)));
+- rb_str_cat2(str, ", ");
+-
+- rb_str_cat2(str, "issuer=");
+- rb_str_append(str, rb_inspect(ossl_x509_get_issuer(self)));
+- rb_str_cat2(str, ", ");
+-
+- rb_str_cat2(str, "serial=");
+- rb_str_append(str, rb_inspect(ossl_x509_get_serial(self)));
+- rb_str_cat2(str, ", ");
+-
+- rb_str_cat2(str, "not_before=");
+- rb_str_append(str, rb_inspect(ossl_x509_get_not_before(self)));
+- rb_str_cat2(str, ", ");
+-
+- rb_str_cat2(str, "not_after=");
+- rb_str_append(str, rb_inspect(ossl_x509_get_not_after(self)));
+-
+- str = rb_str_cat2(str, ">");
+-
+- return str;
++ return rb_sprintf("#<%"PRIsVALUE": subject=%+"PRIsVALUE", "
++ "issuer=%+"PRIsVALUE", serial=%+"PRIsVALUE", "
++ "not_before=%+"PRIsVALUE", not_after=%+"PRIsVALUE">",
++ rb_obj_class(self),
++ ossl_x509_get_subject(self),
++ ossl_x509_get_issuer(self),
++ ossl_x509_get_serial(self),
++ ossl_x509_get_not_before(self),
++ ossl_x509_get_not_after(self));
+ }
+
+ /*
+ * INIT
+ */
+ void
+-Init_ossl_x509cert()
++Init_ossl_x509cert(void)
+ {
+
+ #if 0
+diff --git a/ext/openssl_cms/ossl_x509crl.c b/ext/openssl_cms/ossl_x509crl.c
+index dec13c8..461c226 100644
+--- a/ext/openssl_cms/ossl_x509crl.c
++++ b/ext/openssl_cms/ossl_x509crl.c
+@@ -14,10 +14,10 @@
+ if (!(crl)) { \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_CRL_free, (crl)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509crl_type, (crl)); \
+ } while (0)
+ #define GetX509CRL(obj, crl) do { \
+- Data_Get_Struct((obj), X509_CRL, (crl)); \
++ TypedData_Get_Struct((obj), X509_CRL, &ossl_x509crl_type, (crl)); \
+ if (!(crl)) { \
+ ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+ } \
+@@ -33,6 +33,20 @@
+ VALUE cX509CRL;
+ VALUE eX509CRLError;
+
++static void
++ossl_x509crl_free(void *ptr)
++{
++ X509_CRL_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509crl_type = {
++ "OpenSSL/X509/CRL",
++ {
++ 0, ossl_x509crl_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * PUBLIC
+ */
+@@ -502,7 +516,7 @@ ossl_x509crl_add_extension(VALUE self, VALUE extension)
+ * INIT
+ */
+ void
+-Init_ossl_x509crl()
++Init_ossl_x509crl(void)
+ {
+ eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError);
+
+diff --git a/ext/openssl_cms/ossl_x509ext.c b/ext/openssl_cms/ossl_x509ext.c
+index bd2e1dd..faffe06 100644
+--- a/ext/openssl_cms/ossl_x509ext.c
++++ b/ext/openssl_cms/ossl_x509ext.c
+@@ -14,10 +14,10 @@
+ if (!(ext)) { \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_EXTENSION_free, (ext)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509ext_type, (ext)); \
+ } while (0)
+ #define GetX509Ext(obj, ext) do { \
+- Data_Get_Struct((obj), X509_EXTENSION, (ext)); \
++ TypedData_Get_Struct((obj), X509_EXTENSION, &ossl_x509ext_type, (ext)); \
+ if (!(ext)) { \
+ ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+ } \
+@@ -30,10 +30,10 @@
+ if (!((ctx) = OPENSSL_malloc(sizeof(X509V3_CTX)))) \
+ ossl_raise(rb_eRuntimeError, "CTX wasn't allocated!"); \
+ X509V3_set_ctx((ctx), NULL, NULL, NULL, NULL, 0); \
+- (obj) = Data_Wrap_Struct((klass), 0, ossl_x509extfactory_free, (ctx)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509extfactory_type, (ctx)); \
+ } while (0)
+ #define GetX509ExtFactory(obj, ctx) do { \
+- Data_Get_Struct((obj), X509V3_CTX, (ctx)); \
++ TypedData_Get_Struct((obj), X509V3_CTX, &ossl_x509extfactory_type, (ctx)); \
+ if (!(ctx)) { \
+ ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
+ } \
+@@ -46,6 +46,20 @@ VALUE cX509Ext;
+ VALUE cX509ExtFactory;
+ VALUE eX509ExtError;
+
++static void
++ossl_x509ext_free(void *ptr)
++{
++ X509_EXTENSION_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509ext_type = {
++ "OpenSSL/X509/EXTENSION",
++ {
++ 0, ossl_x509ext_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public
+ */
+@@ -98,11 +112,19 @@ DupX509ExtPtr(VALUE obj)
+ * Ext factory
+ */
+ static void
+-ossl_x509extfactory_free(X509V3_CTX *ctx)
++ossl_x509extfactory_free(void *ctx)
+ {
+ OPENSSL_free(ctx);
+ }
+
++static const rb_data_type_t ossl_x509extfactory_type = {
++ "OpenSSL/X509/EXTENSION/Factory",
++ {
++ 0, ossl_x509extfactory_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ static VALUE
+ ossl_x509extfactory_alloc(VALUE klass)
+ {
+@@ -436,7 +458,7 @@ ossl_x509ext_to_der(VALUE obj)
+ * INIT
+ */
+ void
+-Init_ossl_x509ext()
++Init_ossl_x509ext(void)
+ {
+ eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
+
+diff --git a/ext/openssl_cms/ossl_x509name.c b/ext/openssl_cms/ossl_x509name.c
+index 6de79d4..546cf3b 100644
+--- a/ext/openssl_cms/ossl_x509name.c
++++ b/ext/openssl_cms/ossl_x509name.c
+@@ -14,10 +14,10 @@
+ if (!(name)) { \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_NAME_free, (name)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509name_type, (name)); \
+ } while (0)
+ #define GetX509Name(obj, name) do { \
+- Data_Get_Struct((obj), X509_NAME, (name)); \
++ TypedData_Get_Struct((obj), X509_NAME, &ossl_x509name_type, (name)); \
+ if (!(name)) { \
+ ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+ } \
+@@ -38,6 +38,20 @@
+ VALUE cX509Name;
+ VALUE eX509NameError;
+
++static void
++ossl_x509name_free(void *ptr)
++{
++ X509_NAME_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509name_type = {
++ "OpenSSL/X509/NAME",
++ {
++ 0, ossl_x509name_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public
+ */
+@@ -183,13 +197,14 @@ VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
+ {
+ X509_NAME *name;
+ VALUE oid, value, type;
++ const char *oid_name;
+
+ rb_scan_args(argc, argv, "21", &oid, &value, &type);
+- StringValue(oid);
++ oid_name = StringValueCStr(oid);
+ StringValue(value);
+ if(NIL_P(type)) type = rb_aref(OBJECT_TYPE_TEMPLATE, oid);
+ GetX509Name(self, name);
+- if (!X509_NAME_add_entry_by_txt(name, RSTRING_PTR(oid), NUM2INT(type),
++ if (!X509_NAME_add_entry_by_txt(name, oid_name, NUM2INT(type),
+ (const unsigned char *)RSTRING_PTR(value), RSTRING_LENINT(value), -1, 0)) {
+ ossl_raise(eX509NameError, NULL);
+ }
+@@ -425,7 +440,7 @@ ossl_x509name_to_der(VALUE self)
+ */
+
+ void
+-Init_ossl_x509name()
++Init_ossl_x509name(void)
+ {
+ VALUE utf8str, ptrstr, ia5str, hash;
+
+diff --git a/ext/openssl_cms/ossl_x509req.c b/ext/openssl_cms/ossl_x509req.c
+index 5927f76..529b685 100644
+--- a/ext/openssl_cms/ossl_x509req.c
++++ b/ext/openssl_cms/ossl_x509req.c
+@@ -14,10 +14,10 @@
+ if (!(req)) { \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_REQ_free, (req)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509req_type, (req)); \
+ } while (0)
+ #define GetX509Req(obj, req) do { \
+- Data_Get_Struct((obj), X509_REQ, (req)); \
++ TypedData_Get_Struct((obj), X509_REQ, &ossl_x509req_type, (req)); \
+ if (!(req)) { \
+ ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+ } \
+@@ -33,6 +33,20 @@
+ VALUE cX509Req;
+ VALUE eX509ReqError;
+
++static void
++ossl_x509req_free(void *ptr)
++{
++ X509_REQ_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509req_type = {
++ "OpenSSL/X509/REQ",
++ {
++ 0, ossl_x509req_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public functions
+ */
+@@ -438,7 +452,7 @@ ossl_x509req_add_attribute(VALUE self, VALUE attr)
+ * X509_REQUEST init
+ */
+ void
+-Init_ossl_x509req()
++Init_ossl_x509req(void)
+ {
+ eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError);
+
+diff --git a/ext/openssl_cms/ossl_x509revoked.c b/ext/openssl_cms/ossl_x509revoked.c
+index 320abaa..30c362c 100644
+--- a/ext/openssl_cms/ossl_x509revoked.c
++++ b/ext/openssl_cms/ossl_x509revoked.c
+@@ -14,10 +14,10 @@
+ if (!(rev)) { \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_REVOKED_free, (rev)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509rev_type, (rev)); \
+ } while (0)
+ #define GetX509Rev(obj, rev) do { \
+- Data_Get_Struct((obj), X509_REVOKED, (rev)); \
++ TypedData_Get_Struct((obj), X509_REVOKED, &ossl_x509rev_type, (rev)); \
+ if (!(rev)) { \
+ ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+ } \
+@@ -33,6 +33,20 @@
+ VALUE cX509Rev;
+ VALUE eX509RevError;
+
++static void
++ossl_x509rev_free(void *ptr)
++{
++ X509_REVOKED_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509rev_type = {
++ "OpenSSL/X509/REV",
++ {
++ 0, ossl_x509rev_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * PUBLIC
+ */
+@@ -209,7 +223,7 @@ ossl_x509revoked_add_extension(VALUE self, VALUE ext)
+ * INIT
+ */
+ void
+-Init_ossl_x509revoked()
++Init_ossl_x509revoked(void)
+ {
+ eX509RevError = rb_define_class_under(mX509, "RevokedError", eOSSLError);
+
+diff --git a/ext/openssl_cms/ossl_x509store.c b/ext/openssl_cms/ossl_x509store.c
+index f59c376..3093e28 100644
+--- a/ext/openssl_cms/ossl_x509store.c
++++ b/ext/openssl_cms/ossl_x509store.c
+@@ -14,10 +14,10 @@
+ if (!(st)) { \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, X509_STORE_free, (st)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509store_type, (st)); \
+ } while (0)
+ #define GetX509Store(obj, st) do { \
+- Data_Get_Struct((obj), X509_STORE, (st)); \
++ TypedData_Get_Struct((obj), X509_STORE, &ossl_x509store_type, (st)); \
+ if (!(st)) { \
+ ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+ } \
+@@ -31,10 +31,10 @@
+ if (!(ctx)) { \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
+ } \
+- (obj) = Data_Wrap_Struct((klass), 0, ossl_x509stctx_free, (ctx)); \
++ (obj) = TypedData_Wrap_Struct((klass), &ossl_x509stctx_type, (ctx)); \
+ } while (0)
+ #define GetX509StCtx(obj, ctx) do { \
+- Data_Get_Struct((obj), X509_STORE_CTX, (ctx)); \
++ TypedData_Get_Struct((obj), X509_STORE_CTX, &ossl_x509stctx_type, (ctx)); \
+ if (!(ctx)) { \
+ ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
+ } \
+@@ -51,6 +51,20 @@ VALUE cX509Store;
+ VALUE cX509StoreContext;
+ VALUE eX509StoreError;
+
++static void
++ossl_x509store_free(void *ptr)
++{
++ X509_STORE_free(ptr);
++}
++
++static const rb_data_type_t ossl_x509store_type = {
++ "OpenSSL/X509/STORE",
++ {
++ 0, ossl_x509store_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+ /*
+ * Public functions
+ */
+@@ -342,7 +356,17 @@ ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
+ /*
+ * Public Functions
+ */
+-static void ossl_x509stctx_free(X509_STORE_CTX*);
++static void ossl_x509stctx_free(void*);
++
++
++static const rb_data_type_t ossl_x509stctx_type = {
++ "OpenSSL/X509/STORE_CTX",
++ {
++ 0, ossl_x509stctx_free,
++ },
++ 0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
++};
++
+
+ VALUE
+ ossl_x509stctx_new(X509_STORE_CTX *ctx)
+@@ -367,8 +391,9 @@ ossl_x509stctx_clear_ptr(VALUE obj)
+ * Private functions
+ */
+ static void
+-ossl_x509stctx_free(X509_STORE_CTX *ctx)
++ossl_x509stctx_free(void *ptr)
+ {
++ X509_STORE_CTX *ctx = ptr;
+ if(ctx->untrusted)
+ sk_X509_pop_free(ctx->untrusted, X509_free);
+ if(ctx->cert)
+@@ -593,7 +618,7 @@ ossl_x509stctx_set_time(VALUE self, VALUE time)
+ * INIT
+ */
+ void
+-Init_ossl_x509store()
++Init_ossl_x509store(void)
+ {
+ VALUE x509stctx;
+
+diff --git a/lib/openssl_cms/bn.rb b/lib/openssl_cms/bn.rb
+index 0e19c20..95babb4 100644
+--- a/lib/openssl_cms/bn.rb
++++ b/lib/openssl_cms/bn.rb
+@@ -21,6 +21,13 @@
+ module OpenSSL
+ class BN
+ include Comparable
++
++ def pretty_print(q)
++ q.object_group(self) {
++ q.text ' '
++ q.text to_i.to_s
++ }
++ end
+ end # BN
+ end # OpenSSL
+
+diff --git a/lib/openssl_cms/ssl-internal.rb b/lib/openssl_cms/ssl-internal.rb
+index cb5887e..83a2bf5 100644
+--- a/lib/openssl_cms/ssl-internal.rb
++++ b/lib/openssl_cms/ssl-internal.rb
+@@ -235,8 +235,12 @@ module OpenSSL
+ ssl.sync_close = true
+ ssl.accept if @start_immediately
+ ssl
+- rescue SSLError => ex
+- sock.close
++ rescue Exception => ex
++ if ssl
++ ssl.close
++ else
++ sock.close
++ end
+ raise ex
+ end
+ end
+diff --git a/lib/openssl_cms/x509-internal.rb b/lib/openssl_cms/x509-internal.rb
+index 31a4381..38b65c7 100644
+--- a/lib/openssl_cms/x509-internal.rb
++++ b/lib/openssl_cms/x509-internal.rb
+@@ -70,7 +70,7 @@ module OpenSSL
+ HexPair = /#{HexChar}#{HexChar}/
+ HexString = /#{HexPair}+/
+ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
+- StringChar = /[^#{Special}\\"]/
++ StringChar = /[^\\"#{Special}]/
+ QuoteChar = /[^\\"]/
+ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
+ AttributeValue = /
+@@ -151,6 +151,13 @@ module OpenSSL
+
+ alias parse parse_openssl
+ end
++
++ def pretty_print(q)
++ q.object_group(self) {
++ q.text ' '
++ q.text to_s(OpenSSL::X509::Name::RFC2253)
++ }
++ end
+ end
+
+ class StoreContext
+@@ -158,5 +165,18 @@ module OpenSSL
+ warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
+ end
+ end
++
++ class Certificate
++ def pretty_print(q)
++ q.object_group(self) {
++ q.breakable
++ q.text 'subject='; q.pp self.subject; q.text ','; q.breakable
++ q.text 'issuer='; q.pp self.issuer; q.text ','; q.breakable
++ q.text 'serial='; q.pp self.serial; q.text ','; q.breakable
++ q.text 'not_before='; q.pp self.not_before; q.text ','; q.breakable
++ q.text 'not_after='; q.pp self.not_after
++ }
++ end
++ end
+ end
+ end
diff --git a/rubygem-openssl_cms.spec b/rubygem-openssl_cms.spec
index 1caf0ae..96473cd 100644
--- a/rubygem-openssl_cms.spec
+++ b/rubygem-openssl_cms.spec
@@ -1,6 +1,7 @@
%global gem_basename openssl_cms
-%global gem_rubyver 2_1
+%global gem_rubyver 2_2
%global gem_name %{gem_basename}_%{gem_rubyver}
+%global gem_srcname %{gem_basename}_2_1
%global commit b789b696d821bd6563dd207fb6b562c06acc835b
%global shortcommit %(c=%{commit}; echo ${c:0:7})
@@ -24,25 +25,28 @@ URL: https://github.com/arax/openssl-cms
# gem build ${gem_basename}.gemspec
# gem spec ${gem_name}-${version}.gem -l --ruby > ${gem_basename}.gemspec
# gem build ${gem_basename}.gemspec
-Source0: %{gem_name}-%{version}.gem
+Source0: %{gem_srcname}-%{version}.gem
Source1: https://raw.githubusercontent.com/arax/openssl-cms/master/README.md
+# https://github.com/arax/openssl-cms/pull/1
+Patch0: openssl_cms-ruby2.1.5.diff
+Patch1: openssl_cms-ruby2.2.0.diff
BuildRequires: openssl-devel
BuildRequires: ruby(release)
BuildRequires: rubygems-devel
-BuildRequires: ruby-devel => 2.1
+BuildRequires: ruby-devel => 2.2
%description
OpenSSL with Cryptographic Message Syntax functions for Ruby.
%package -n rubygem-%{gem_name}
-Summary: OpenSSL with CMS functions for Ruby 2.1
+Summary: OpenSSL with CMS functions for Ruby 2.2
Group: Development/Languages
-Requires: ruby(release) >= 2.1
+Requires: ruby(release) >= 2.2
%description -n rubygem-%{gem_name}
-OpenSSL with Cryptographic Message Syntax functions for Ruby 2.1.
+OpenSSL with Cryptographic Message Syntax functions for Ruby 2.2.
%package -n rubygem-%{gem_name}-doc
@@ -57,10 +61,18 @@ Documentation for %{name}.
%prep
gem unpack %{SOURCE0}
-%setup -q -D -T -n %{gem_name}-%{version}
+%setup -q -D -T -n %{gem_srcname}-%{version}
+
+%patch0 -p1
+%patch1 -p1
gem spec %{SOURCE0} -l --ruby > %{gem_name}.gemspec
+# update for ruby 2.2
+sed -i %{gem_name}.gemspec \
+ -e 's,name = ".*",name = "openssl_cms_2_2",' \
+ -e 's,\(required_ruby_version.*\)"~> 2.1.0",\1"~> 2.2.0",'
+
# README.md
cp -p %{SOURCE1} .
@@ -90,21 +102,24 @@ rm -rf %{buildroot}%{gem_instdir}/ext/
%files -n rubygem-%{gem_name}
%license %{gem_instdir}/BSDL
%license %{gem_instdir}/LICENSE
-%dir %{gem_instdir}
-%{gem_libdir}
-%{gem_extdir_mri}
+%dir %{gem_instdir}/
+%{gem_libdir}/
+%{gem_extdir_mri}/
%exclude %{gem_cache}
%{gem_spec}
%exclude %{gem_instdir}/.gitignore
%files -n rubygem-%{gem_name}-doc
-%doc %{gem_docdir}
+%doc %{gem_docdir}/
%{gem_instdir}/README.md
%exclude %{gem_instdir}/%{gem_basename}.gemspec
%changelog
-* Sun Jan 18 2015 Mamoru TASAKA <mtasaka at fedoraproject.org> - 0.0.3-2.20140212git7fea071
+* Wed Jan 28 2015 František Dvořák <valtri at civ.zcu.cz> - 0.0.2-3.20140212gitb789b69
+- Add support for ruby 2.2
+
+* Sun Jan 18 2015 Mamoru TASAKA <mtasaka at fedoraproject.org> - 0.0.2-3.20140212git7fea071
- Rebuild for https://fedoraproject.org/wiki/Changes/Ruby_2.2
* Wed Oct 08 2014 František Dvořák <valtri at civ.zcu.cz> - 0.0.2-2.20140212git7fea071
More information about the scm-commits
mailing list