ruby-openssl-cms-1.9.3 - initial gem2deb package.
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Wed, 12 Mar 2014 15:57:06 +0000 (16:57 +0100)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Wed, 12 Mar 2014 16:16:52 +0000 (17:16 +0100)
80 files changed:
ruby-openssl-cms-1-9-3/.gitignore [new file with mode: 0644]
ruby-openssl-cms-1-9-3/BSDL [new file with mode: 0644]
ruby-openssl-cms-1-9-3/LICENSE [new file with mode: 0644]
ruby-openssl-cms-1-9-3/README.md [new file with mode: 0644]
ruby-openssl-cms-1-9-3/debian/changelog [new file with mode: 0644]
ruby-openssl-cms-1-9-3/debian/compat [new file with mode: 0644]
ruby-openssl-cms-1-9-3/debian/control [new file with mode: 0644]
ruby-openssl-cms-1-9-3/debian/copyright [new file with mode: 0644]
ruby-openssl-cms-1-9-3/debian/ruby-openssl-cms-1-9-3.docs [new file with mode: 0644]
ruby-openssl-cms-1-9-3/debian/rules [new file with mode: 0755]
ruby-openssl-cms-1-9-3/debian/source/format [new file with mode: 0644]
ruby-openssl-cms-1-9-3/debian/watch [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/extconf.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/openssl_missing.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/openssl_missing.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_asn1.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_asn1.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bio.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bio.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bn.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bn.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cipher.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cipher.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cms.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cms.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_config.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_config.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_digest.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_digest.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_engine.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_engine.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_hmac.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_hmac.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ns_spki.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ns_spki.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ocsp.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ocsp.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs12.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs12.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs5.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs5.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs7.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs7.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_dh.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_dsa.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_ec.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_rsa.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_rand.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_rand.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl_session.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_version.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509attr.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509cert.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509crl.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509ext.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509name.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509req.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509revoked.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509store.c [new file with mode: 0644]
ruby-openssl-cms-1-9-3/ext/openssl_cms/ruby_missing.h [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/bn.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/buffering.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/cipher.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/config.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/digest.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/ssl-internal.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/ssl.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/x509-internal.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/lib/openssl_cms/x509.rb [new file with mode: 0644]
ruby-openssl-cms-1-9-3/metadata.yml [new file with mode: 0644]
ruby-openssl-cms-1-9-3/openssl_cms.gemspec [new file with mode: 0644]

diff --git a/ruby-openssl-cms-1-9-3/.gitignore b/ruby-openssl-cms-1-9-3/.gitignore
new file mode 100644 (file)
index 0000000..1ff1b34
--- /dev/null
@@ -0,0 +1,22 @@
+# Object files
+*.o
+*.ko
+
+# Libraries
+*.lib
+*.a
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+
+# No Makefiles
+Makefile
+extconf.h
diff --git a/ruby-openssl-cms-1-9-3/BSDL b/ruby-openssl-cms-1-9-3/BSDL
new file mode 100644 (file)
index 0000000..8272553
--- /dev/null
@@ -0,0 +1,22 @@
+Copyright (C) 1993-2010 Yukihiro Matsumoto. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/ruby-openssl-cms-1-9-3/LICENSE b/ruby-openssl-cms-1-9-3/LICENSE
new file mode 100644 (file)
index 0000000..a1f19ff
--- /dev/null
@@ -0,0 +1,56 @@
+Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
+You can redistribute it and/or modify it under either the terms of the
+2-clause BSDL (see the file BSDL), or the conditions below:
+
+  1. You may make and give away verbatim copies of the source form of the
+     software without restriction, provided that you duplicate all of the
+     original copyright notices and associated disclaimers.
+
+  2. You may modify your copy of the software in any way, provided that
+     you do at least ONE of the following:
+
+       a) place your modifications in the Public Domain or otherwise
+          make them Freely Available, such as by posting said
+         modifications to Usenet or an equivalent medium, or by allowing
+         the author to include your modifications in the software.
+
+       b) use the modified software only within your corporation or
+          organization.
+
+       c) give non-standard binaries non-standard names, with
+          instructions on where to get the original software distribution.
+
+       d) make other distribution arrangements with the author.
+
+  3. You may distribute the software in object code or binary form,
+     provided that you do at least ONE of the following:
+
+       a) distribute the binaries and library files of the software,
+         together with instructions (in the manual page or equivalent)
+         on where to get the original distribution.
+
+       b) accompany the distribution with the machine-readable source of
+         the software.
+
+       c) give non-standard binaries non-standard names, with
+          instructions on where to get the original software distribution.
+
+       d) make other distribution arrangements with the author.
+
+  4. You may modify and include the part of the software into any other
+     software (possibly commercial).  But some files in the distribution
+     are not written by the author, so that they are not under these terms.
+
+     For the list of those files and their copying conditions, see the
+     file LEGAL.
+
+  5. The scripts and library files supplied as input to or produced as 
+     output from the software do not automatically fall under the
+     copyright of the software, but belong to whomever generated them, 
+     and may be sold commercially, and may be aggregated with this
+     software.
+
+  6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+     IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+     PURPOSE.
diff --git a/ruby-openssl-cms-1-9-3/README.md b/ruby-openssl-cms-1-9-3/README.md
new file mode 100644 (file)
index 0000000..682f40f
--- /dev/null
@@ -0,0 +1,2 @@
+OpenSSL-CMS for Ruby
+====================
diff --git a/ruby-openssl-cms-1-9-3/debian/changelog b/ruby-openssl-cms-1-9-3/debian/changelog
new file mode 100644 (file)
index 0000000..0588ca4
--- /dev/null
@@ -0,0 +1,5 @@
+ruby-openssl-cms-1-9-3 (0.0.2-1) UNRELEASED; urgency=medium
+
+  * Initial release (Closes: #nnnn)
+
+ -- MAINTAINER <valtri@myriad14.zcu.cz>  Wed, 12 Mar 2014 16:49:46 +0100
diff --git a/ruby-openssl-cms-1-9-3/debian/compat b/ruby-openssl-cms-1-9-3/debian/compat
new file mode 100644 (file)
index 0000000..7f8f011
--- /dev/null
@@ -0,0 +1 @@
+7
diff --git a/ruby-openssl-cms-1-9-3/debian/control b/ruby-openssl-cms-1-9-3/debian/control
new file mode 100644 (file)
index 0000000..9906ccc
--- /dev/null
@@ -0,0 +1,18 @@
+Source: ruby-openssl-cms-1-9-3
+Section: ruby
+Priority: optional
+Maintainer: Debian Ruby Extras Maintainers <pkg-ruby-extras-maintainers@lists.alioth.debian.org>
+Uploaders:  <>
+Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.6.1~)
+Standards-Version: 3.9.4
+#Vcs-Git: git://anonscm.debian.org/pkg-ruby-extras/ruby-openssl-cms-1-9-3.git
+#Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-ruby-extras/ruby-openssl-cms-1-9-3.git;a=summary
+Homepage: https://github.com/arax/openssl-cms
+XS-Ruby-Versions: all
+
+Package: ruby-openssl-cms-1-9-3
+Architecture: any
+XB-Ruby-Versions: ${ruby:Versions}
+Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter
+Description: OpenSSL with CMS functions for Ruby 1.9.3
+ OpenSSL with CMS functions for Ruby 1.9.3
diff --git a/ruby-openssl-cms-1-9-3/debian/copyright b/ruby-openssl-cms-1-9-3/debian/copyright
new file mode 100644 (file)
index 0000000..d7c83a8
--- /dev/null
@@ -0,0 +1,35 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: openssl_cms_1_9_3
+Source: FIXME <http://example.com/>
+
+Files: *
+Copyright: <years> <put author's name and email here>
+           <years> <likewise for another author>
+License: GPL-2+ (FIXME)
+
+Files: debian/*
+Copyright: 2014  <>
+License: GPL-2+ (FIXME)
+Comment: the Debian packaging is licensed under the same terms as the original package.
+
+License: GPL-2+ (FIXME)
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later
+ version.
+ .
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE.  See the GNU General Public License for more
+ details.
+ .
+ You should have received a copy of the GNU General Public
+ License along with this package; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ Boston, MA  02110-1301 USA
+ .
+ On Debian systems, the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2'.
diff --git a/ruby-openssl-cms-1-9-3/debian/ruby-openssl-cms-1-9-3.docs b/ruby-openssl-cms-1-9-3/debian/ruby-openssl-cms-1-9-3.docs
new file mode 100644 (file)
index 0000000..07b3c9e
--- /dev/null
@@ -0,0 +1,2 @@
+# FIXME: READMEs found
+# README.md
diff --git a/ruby-openssl-cms-1-9-3/debian/rules b/ruby-openssl-cms-1-9-3/debian/rules
new file mode 100755 (executable)
index 0000000..82ddc0c
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/make -f
+#export DH_VERBOSE=1
+#
+# Uncomment to ignore all test failures (but the tests will run anyway)
+#export DH_RUBY_IGNORE_TESTS=all
+#
+# Uncomment to ignore some test failures (but the tests will run anyway).
+# Valid values:
+#export DH_RUBY_IGNORE_TESTS=ruby1.9.1 ruby2.0 require-rubygems
+#
+# If you need to specify the .gemspec (eg there is more than one)
+#export DH_RUBY_GEMSPEC=gem.gemspec
+
+%:
+       dh $@ --buildsystem=ruby --with ruby
diff --git a/ruby-openssl-cms-1-9-3/debian/source/format b/ruby-openssl-cms-1-9-3/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/ruby-openssl-cms-1-9-3/debian/watch b/ruby-openssl-cms-1-9-3/debian/watch
new file mode 100644 (file)
index 0000000..2205fb7
--- /dev/null
@@ -0,0 +1,2 @@
+version=3
+http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/openssl_cms_1_9_3 .*/openssl_cms_1_9_3-(.*).tar.gz
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/extconf.rb b/ruby-openssl-cms-1-9-3/ext/openssl_cms/extconf.rb
new file mode 100644 (file)
index 0000000..27b9b45
--- /dev/null
@@ -0,0 +1,143 @@
+=begin
+= $RCSfile$ -- Generator for Makefile
+
+= Info
+  'OpenSSL for Ruby 2' project
+  Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>
+  All rights reserved.
+
+= Licence
+  This program is licenced under the same licence as Ruby.
+  (See the file 'LICENCE'.)
+
+= Version
+  $Id$
+=end
+
+require "mkmf"
+
+dir_config("openssl")
+dir_config("kerberos")
+
+message "=== OpenSSL for Ruby configurator ===\n"
+
+##
+# Adds -Wall -DOSSL_DEBUG for compilation and some more targets when GCC is used
+# To turn it on, use: --with-debug or --enable-debug
+#
+if with_config("debug") or enable_config("debug")
+  $defs.push("-DOSSL_DEBUG") unless $defs.include? "-DOSSL_DEBUG"
+
+  if CONFIG['GCC'] == 'yes'
+    $CPPFLAGS += " -Wall" unless $CPPFLAGS.split.include? "-Wall"
+  end
+end
+
+message "=== Checking for system dependent stuff... ===\n"
+have_library("nsl", "t_open")
+have_library("socket", "socket")
+have_header("assert.h")
+
+message "=== Checking for required stuff... ===\n"
+if $mingw
+  have_library("wsock32")
+  have_library("gdi32")
+end
+
+result = pkg_config("openssl") && have_header("openssl/ssl.h")
+
+unless result
+  result = have_header("openssl/ssl.h")
+  result &&= %w[crypto libeay32].any? {|lib| have_library(lib, "OpenSSL_add_all_digests")}
+  result &&= %w[ssl ssleay32].any? {|lib| have_library(lib, "SSL_library_init")}
+  unless result
+    message "=== Checking for required stuff failed. ===\n"
+    message "Makefile wasn't created. Fix the errors above.\n"
+    exit 1
+  end
+end
+
+unless have_header("openssl/conf_api.h")
+  raise "OpenSSL 0.9.6 or later required."
+end
+
+unless have_header("openssl/cms.h")
+  raise 'OpenSSL with CMS support is required!'
+end
+
+%w"rb_str_set_len rb_block_call".each {|func| have_func(func, "ruby.h")}
+
+message "=== Checking for OpenSSL features... ===\n"
+have_func("ERR_peek_last_error")
+have_func("ASN1_put_eoc")
+have_func("BN_mod_add")
+have_func("BN_mod_sqr")
+have_func("BN_mod_sub")
+have_func("BN_pseudo_rand_range")
+have_func("BN_rand_range")
+have_func("CONF_get1_default_config_file")
+have_func("EVP_CIPHER_CTX_copy")
+have_func("EVP_CIPHER_CTX_set_padding")
+have_func("EVP_CipherFinal_ex")
+have_func("EVP_CipherInit_ex")
+have_func("EVP_DigestFinal_ex")
+have_func("EVP_DigestInit_ex")
+have_func("EVP_MD_CTX_cleanup")
+have_func("EVP_MD_CTX_create")
+have_func("EVP_MD_CTX_destroy")
+have_func("EVP_MD_CTX_init")
+have_func("HMAC_CTX_cleanup")
+have_func("HMAC_CTX_copy")
+have_func("HMAC_CTX_init")
+have_func("PEM_def_callback")
+have_func("PKCS5_PBKDF2_HMAC")
+have_func("PKCS5_PBKDF2_HMAC_SHA1")
+have_func("X509V3_set_nconf")
+have_func("X509V3_EXT_nconf_nid")
+have_func("X509_CRL_add0_revoked")
+have_func("X509_CRL_set_issuer_name")
+have_func("X509_CRL_set_version")
+have_func("X509_CRL_sort")
+have_func("X509_NAME_hash_old")
+have_func("X509_STORE_get_ex_data")
+have_func("X509_STORE_set_ex_data")
+have_func("OBJ_NAME_do_all_sorted")
+have_func("SSL_SESSION_get_id")
+have_func("SSL_SESSION_cmp")
+have_func("OPENSSL_cleanse")
+have_func("SSLv2_method")
+have_func("SSLv2_server_method")
+have_func("SSLv2_client_method")
+unless have_func("SSL_set_tlsext_host_name", ['openssl/ssl.h'])
+  have_macro("SSL_set_tlsext_host_name", ['openssl/ssl.h']) && $defs.push("-DHAVE_SSL_SET_TLSEXT_HOST_NAME")
+end
+if have_header("openssl/engine.h")
+  have_func("ENGINE_add")
+  have_func("ENGINE_load_builtin_engines")
+  have_func("ENGINE_load_openbsd_dev_crypto")
+  have_func("ENGINE_get_digest")
+  have_func("ENGINE_get_cipher")
+  have_func("ENGINE_cleanup")
+  have_func("ENGINE_load_4758cca")
+  have_func("ENGINE_load_aep")
+  have_func("ENGINE_load_atalla")
+  have_func("ENGINE_load_chil")
+  have_func("ENGINE_load_cswift")
+  have_func("ENGINE_load_nuron")
+  have_func("ENGINE_load_sureware")
+  have_func("ENGINE_load_ubsec")
+end
+if checking_for('OpenSSL version is 0.9.7 or later') {
+    try_static_assert('OPENSSL_VERSION_NUMBER >= 0x00907000L', 'openssl/opensslv.h')
+  }
+  have_header("openssl/ocsp.h")
+end
+have_struct_member("EVP_CIPHER_CTX", "flags", "openssl/evp.h")
+have_struct_member("EVP_CIPHER_CTX", "engine", "openssl/evp.h")
+have_struct_member("X509_ATTRIBUTE", "single", "openssl/x509.h")
+
+message "=== Checking done. ===\n"
+
+create_header
+create_makefile("openssl_cms")
+message "Done.\n"
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/openssl_missing.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/openssl_missing.c
new file mode 100644 (file)
index 0000000..f88dd40
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include RUBY_EXTCONF_H
+
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ST_ENGINE)
+# include <openssl/engine.h>
+#endif
+#include <openssl/x509_vfy.h>
+
+#if !defined(OPENSSL_NO_HMAC)
+#include <string.h> /* memcpy() */
+#include <openssl/hmac.h>
+
+#include "openssl_missing.h"
+
+#if !defined(HAVE_HMAC_CTX_COPY)
+void
+HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in)
+{
+    if (!out || !in) return;
+    memcpy(out, in, sizeof(HMAC_CTX));
+
+    EVP_MD_CTX_copy(&out->md_ctx, &in->md_ctx);
+    EVP_MD_CTX_copy(&out->i_ctx, &in->i_ctx);
+    EVP_MD_CTX_copy(&out->o_ctx, &in->o_ctx);
+}
+#endif /* HAVE_HMAC_CTX_COPY */
+#endif /* NO_HMAC */
+
+#if !defined(HAVE_X509_STORE_SET_EX_DATA)
+int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data)
+{
+    return CRYPTO_set_ex_data(&str->ex_data, idx, data);
+}
+#endif
+
+#if !defined(HAVE_X509_STORE_GET_EX_DATA)
+void *X509_STORE_get_ex_data(X509_STORE *str, int idx)
+{
+    return CRYPTO_get_ex_data(&str->ex_data, idx);
+}
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_CREATE)
+EVP_MD_CTX *
+EVP_MD_CTX_create(void)
+{
+    EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX));
+    if (!ctx) return NULL;
+
+    memset(ctx, 0, sizeof(EVP_MD_CTX));
+
+    return ctx;
+}
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_CLEANUP)
+int
+EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
+{
+    /* FIXME!!! */
+    memset(ctx, 0, sizeof(EVP_MD_CTX));
+
+    return 1;
+}
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_DESTROY)
+void
+EVP_MD_CTX_destroy(EVP_MD_CTX *ctx)
+{
+    EVP_MD_CTX_cleanup(ctx);
+    OPENSSL_free(ctx);
+}
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_INIT)
+void
+EVP_MD_CTX_init(EVP_MD_CTX *ctx)
+{
+    memset(ctx, 0, sizeof(EVP_MD_CTX));
+}
+#endif
+
+#if !defined(HAVE_HMAC_CTX_INIT)
+void
+HMAC_CTX_init(HMAC_CTX *ctx)
+{
+    EVP_MD_CTX_init(&ctx->i_ctx);
+    EVP_MD_CTX_init(&ctx->o_ctx);
+    EVP_MD_CTX_init(&ctx->md_ctx);
+}
+#endif
+
+#if !defined(HAVE_HMAC_CTX_CLEANUP)
+void
+HMAC_CTX_cleanup(HMAC_CTX *ctx)
+{
+    EVP_MD_CTX_cleanup(&ctx->i_ctx);
+    EVP_MD_CTX_cleanup(&ctx->o_ctx);
+    EVP_MD_CTX_cleanup(&ctx->md_ctx);
+    memset(ctx, 0, sizeof(HMAC_CTX));
+}
+#endif
+
+#if !defined(HAVE_EVP_CIPHER_CTX_COPY)
+/*
+ * this function does not exist in OpenSSL yet... or ever?.
+ * a future version may break this function.
+ * tested on 0.9.7d.
+ */
+int
+EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in)
+{
+    memcpy(out, in, sizeof(EVP_CIPHER_CTX));
+
+#if defined(HAVE_ENGINE_ADD) && defined(HAVE_ST_ENGINE)
+    if (in->engine) ENGINE_add(out->engine);
+    if (in->cipher_data) {
+       out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size);
+       memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size);
+    }
+#endif
+
+    return 1;
+}
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_VERSION)
+int
+X509_CRL_set_version(X509_CRL *x, long version)
+{
+    if (x == NULL || x->crl == NULL) return 0;
+    if (x->crl->version == NULL) {
+       x->crl->version = M_ASN1_INTEGER_new();
+       if (x->crl->version == NULL) return 0;
+    }
+    return ASN1_INTEGER_set(x->crl->version, version);
+}
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME)
+int
+X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name)
+{
+    if (x == NULL || x->crl == NULL) return 0;
+    return X509_NAME_set(&x->crl->issuer, name);
+}
+#endif
+
+#if !defined(HAVE_X509_CRL_SORT)
+int
+X509_CRL_sort(X509_CRL *c)
+{
+    int i;
+    X509_REVOKED *r;
+    /* sort the data so it will be written in serial
+     * number order */
+    sk_X509_REVOKED_sort(c->crl->revoked);
+    for (i=0; i<sk_X509_REVOKED_num(c->crl->revoked); i++) {
+       r=sk_X509_REVOKED_value(c->crl->revoked, i);
+       r->sequence=i;
+    }
+    return 1;
+}
+#endif
+
+#if !defined(HAVE_X509_CRL_ADD0_REVOKED)
+static int
+OSSL_X509_REVOKED_cmp(const X509_REVOKED * const *a, const X509_REVOKED * const *b)
+{
+    return(ASN1_STRING_cmp(
+               (ASN1_STRING *)(*a)->serialNumber,
+               (ASN1_STRING *)(*b)->serialNumber));
+}
+
+int
+X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev)
+{
+    X509_CRL_INFO *inf;
+
+    inf = crl->crl;
+    if (!inf->revoked)
+       inf->revoked = sk_X509_REVOKED_new(OSSL_X509_REVOKED_cmp);
+    if (!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev))
+       return 0;
+    return 1;
+}
+#endif
+
+#if !defined(HAVE_BN_MOD_SQR)
+int
+BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx)
+{
+    if (!BN_sqr(r, (BIGNUM*)a, ctx)) return 0;
+    return BN_mod(r, r, m, ctx);
+}
+#endif
+
+#if !defined(HAVE_BN_MOD_ADD) || !defined(HAVE_BN_MOD_SUB)
+int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx)
+{
+    if (!BN_mod(r,m,d,ctx)) return 0;
+    if (!r->neg) return 1;
+    return (d->neg ? BN_sub : BN_add)(r, r, d);
+}
+#endif
+
+#if !defined(HAVE_BN_MOD_ADD)
+int
+BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx)
+{
+    if (!BN_add(r, a, b)) return 0;
+    return BN_nnmod(r, r, m, ctx);
+}
+#endif
+
+#if !defined(HAVE_BN_MOD_SUB)
+int
+BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx)
+{
+    if (!BN_sub(r, a, b)) return 0;
+    return BN_nnmod(r, r, m, ctx);
+}
+#endif
+
+#if !defined(HAVE_BN_RAND_RANGE) || !defined(HAVE_BN_PSEUDO_RAND_RANGE)
+static int
+bn_rand_range(int pseudo, BIGNUM *r, BIGNUM *range)
+{
+    int (*bn_rand)(BIGNUM *, int, int, int) = pseudo ? BN_pseudo_rand : BN_rand;
+    int n;
+
+    if (range->neg || BN_is_zero(range)) return 0;
+
+    n = BN_num_bits(range);
+
+    if (n == 1) {
+       if (!BN_zero(r)) return 0;
+    } else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) {
+       do {
+           if (!bn_rand(r, n + 1, -1, 0)) return 0;
+           if (BN_cmp(r ,range) >= 0) {
+               if (!BN_sub(r, r, range)) return 0;
+               if (BN_cmp(r, range) >= 0)
+                   if (!BN_sub(r, r, range)) return 0;
+           }
+       } while (BN_cmp(r, range) >= 0);
+    } else {
+       do {
+           if (!bn_rand(r, n, -1, 0)) return 0;
+       } while (BN_cmp(r, range) >= 0);
+    }
+
+    return 1;
+}
+#endif
+
+#if !defined(HAVE_BN_RAND_RANGE)
+int
+BN_rand_range(BIGNUM *r, BIGNUM *range)
+{
+    return bn_rand_range(0, r, range);
+}
+#endif
+
+#if !defined(HAVE_BN_PSEUDO_RAND_RANGE)
+int
+BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range)
+{
+    return bn_rand_range(1, r, range);
+}
+#endif
+
+#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE)
+#define OPENSSL_CONF "openssl.cnf"
+char *
+CONF_get1_default_config_file(void)
+{
+    char *file;
+    int len;
+
+    file = getenv("OPENSSL_CONF");
+    if (file) return BUF_strdup(file);
+    len = strlen(X509_get_default_cert_area());
+#ifndef OPENSSL_SYS_VMS
+    len++;
+#endif
+    len += strlen(OPENSSL_CONF);
+    file = OPENSSL_malloc(len + 1);
+    if (!file) return NULL;
+    strcpy(file,X509_get_default_cert_area());
+#ifndef OPENSSL_SYS_VMS
+    strcat(file,"/");
+#endif
+    strcat(file,OPENSSL_CONF);
+
+    return file;
+}
+#endif
+
+#if !defined(HAVE_PEM_DEF_CALLBACK)
+#define OSSL_PASS_MIN_LENGTH 4
+int
+PEM_def_callback(char *buf, int num, int w, void *key)
+{
+    int i,j;
+    const char *prompt;
+
+    if (key) {
+       i = strlen(key);
+       i = (i > num) ? num : i;
+       memcpy(buf, key, i);
+       return i;
+    }
+
+    prompt = EVP_get_pw_prompt();
+    if (prompt == NULL) prompt = "Enter PEM pass phrase:";
+    for (;;) {
+       i = EVP_read_pw_string(buf, num, prompt, w);
+       if (i != 0) {
+           memset(buf, 0, (unsigned int)num);
+           return(-1);
+       }
+       j = strlen(buf);
+       if (j < OSSL_PASS_MIN_LENGTH) {
+           fprintf(stderr,
+                   "phrase is too short, needs to be at least %d chars\n",
+                   OSSL_PASS_MIN_LENGTH);
+       }
+       else break;
+    }
+    return j;
+}
+#endif
+
+#if !defined(HAVE_ASN1_PUT_EOC)
+int
+ASN1_put_eoc(unsigned char **pp)
+{
+    unsigned char *p = *pp;
+    *p++ = 0;
+    *p++ = 0;
+    *pp = p;
+    return 2;
+}
+#endif
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/openssl_missing.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/openssl_missing.h
new file mode 100644 (file)
index 0000000..3635f88
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_OPENSSL_MISSING_H_)
+#define _OSSL_OPENSSL_MISSING_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifndef TYPEDEF_D2I_OF
+typedef char *d2i_of_void();
+#endif
+#ifndef TYPEDEF_I2D_OF
+typedef int i2d_of_void();
+#endif
+
+/*
+ * These functions are not included in headers of OPENSSL <= 0.9.6b
+ */
+
+#if !defined(PEM_read_bio_DSAPublicKey)
+# define PEM_read_bio_DSAPublicKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
+        (d2i_of_void *)d2i_DSAPublicKey,PEM_STRING_DSA_PUBLIC,(bp),(void **)(x),(cb),(u))
+#endif
+
+#if !defined(PEM_write_bio_DSAPublicKey)
+# define PEM_write_bio_DSAPublicKey(bp,x) \
+       PEM_ASN1_write_bio((i2d_of_void *)i2d_DSAPublicKey,\
+               PEM_STRING_DSA_PUBLIC,\
+               (bp),(char *)(x), NULL, NULL, 0, NULL, NULL)
+#endif
+
+#if !defined(DSAPrivateKey_dup)
+# define DSAPrivateKey_dup(dsa) (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPrivateKey, \
+       (d2i_of_void *)d2i_DSAPrivateKey,(char *)(dsa))
+#endif
+
+#if !defined(DSAPublicKey_dup)
+# define DSAPublicKey_dup(dsa) (DSA *)ASN1_dup((i2d_of_void *)i2d_DSAPublicKey, \
+       (d2i_of_void *)d2i_DSAPublicKey,(char *)(dsa))
+#endif
+
+#if !defined(X509_REVOKED_dup)
+# define X509_REVOKED_dup(rev) (X509_REVOKED *)ASN1_dup((i2d_of_void *)i2d_X509_REVOKED, \
+       (d2i_of_void *)d2i_X509_REVOKED, (char *)(rev))
+#endif
+
+#if !defined(PKCS7_SIGNER_INFO_dup)
+#  define PKCS7_SIGNER_INFO_dup(si) (PKCS7_SIGNER_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_SIGNER_INFO, \
+       (d2i_of_void *)d2i_PKCS7_SIGNER_INFO, (char *)(si))
+#endif
+
+#if !defined(PKCS7_RECIP_INFO_dup)
+#  define PKCS7_RECIP_INFO_dup(ri) (PKCS7_RECIP_INFO *)ASN1_dup((i2d_of_void *)i2d_PKCS7_RECIP_INFO, \
+       (d2i_of_void *)d2i_PKCS7_RECIP_INFO, (char *)(ri))
+#endif
+
+#if !defined(HAVE_HMAC_CTX_INIT)
+void HMAC_CTX_init(HMAC_CTX *ctx);
+#endif
+
+#if !defined(HAVE_HMAC_CTX_COPY)
+void HMAC_CTX_copy(HMAC_CTX *out, HMAC_CTX *in);
+#endif
+
+#if !defined(HAVE_HMAC_CTX_CLEANUP)
+void HMAC_CTX_cleanup(HMAC_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_CREATE)
+EVP_MD_CTX *EVP_MD_CTX_create(void);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_INIT)
+void EVP_MD_CTX_init(EVP_MD_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_CLEANUP)
+int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_MD_CTX_DESTROY)
+void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
+#endif
+
+#if !defined(HAVE_EVP_CIPHER_CTX_COPY)
+int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, EVP_CIPHER_CTX *in);
+#endif
+
+#if !defined(HAVE_EVP_DIGESTINIT_EX)
+#  define EVP_DigestInit_ex(ctx, md, engine) EVP_DigestInit((ctx), (md))
+#endif
+#if !defined(HAVE_EVP_DIGESTFINAL_EX)
+#  define EVP_DigestFinal_ex(ctx, buf, len) EVP_DigestFinal((ctx), (buf), (len))
+#endif
+
+#if !defined(HAVE_EVP_CIPHERINIT_EX)
+#  define EVP_CipherInit_ex(ctx, type, impl, key, iv, enc) EVP_CipherInit((ctx), (type), (key), (iv), (enc))
+#endif
+#if !defined(HAVE_EVP_CIPHERFINAL_EX)
+#  define EVP_CipherFinal_ex(ctx, outm, outl) EVP_CipherFinal((ctx), (outm), (outl))
+#endif
+
+#if !defined(EVP_CIPHER_name)
+#  define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e))
+#endif
+
+#if !defined(EVP_MD_name)
+#  define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e))
+#endif
+
+#if !defined(HAVE_EVP_HMAC_INIT_EX)
+#  define HMAC_Init_ex(ctx, key, len, digest, engine) HMAC_Init((ctx), (key), (len), (digest))
+#endif
+
+#if !defined(PKCS7_is_detached)
+#  define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7))
+#endif
+
+#if !defined(PKCS7_type_is_encrypted)
+#  define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
+#endif
+
+#if !defined(HAVE_OPENSSL_CLEANSE)
+#define OPENSSL_cleanse(p, l) memset((p), 0, (l))
+#endif
+
+#if !defined(HAVE_X509_STORE_GET_EX_DATA)
+void *X509_STORE_get_ex_data(X509_STORE *str, int idx);
+#endif
+
+#if !defined(HAVE_X509_STORE_SET_EX_DATA)
+int X509_STORE_set_ex_data(X509_STORE *str, int idx, void *data);
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_VERSION)
+int X509_CRL_set_version(X509_CRL *x, long version);
+#endif
+
+#if !defined(HAVE_X509_CRL_SET_ISSUER_NAME)
+int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
+#endif
+
+#if !defined(HAVE_X509_CRL_SORT)
+int X509_CRL_sort(X509_CRL *c);
+#endif
+
+#if !defined(HAVE_X509_CRL_ADD0_REVOKED)
+int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
+#endif
+
+#if !defined(HAVE_BN_MOD_SQR)
+int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_MOD_ADD)
+int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_MOD_SUB)
+int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+#endif
+
+#if !defined(HAVE_BN_RAND_RANGE)
+int BN_rand_range(BIGNUM *r, BIGNUM *range);
+#endif
+
+#if !defined(HAVE_BN_PSEUDO_RAND_RANGE)
+int BN_pseudo_rand_range(BIGNUM *r, BIGNUM *range);
+#endif
+
+#if !defined(HAVE_CONF_GET1_DEFAULT_CONFIG_FILE)
+char *CONF_get1_default_config_file(void);
+#endif
+
+#if !defined(HAVE_PEM_DEF_CALLBACK)
+int PEM_def_callback(char *buf, int num, int w, void *key);
+#endif
+
+#if !defined(HAVE_ASN1_PUT_EOC)
+int ASN1_put_eoc(unsigned char **pp);
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+#endif /* _OSSL_OPENSSL_MISSING_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl.c
new file mode 100644 (file)
index 0000000..020ad73
--- /dev/null
@@ -0,0 +1,906 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+#include <stdarg.h> /* for ossl_raise */
+
+/*
+ * String to HEXString conversion
+ */
+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;
+
+    if (buf_len < 0 || len < buf_len) { /* PARANOIA? */
+       return -1;
+    }
+    if (!hexbuf) { /* if no buf, return calculated len */
+       if (hexbuf_len) {
+           *hexbuf_len = len;
+       }
+       return len;
+    }
+    if (!(*hexbuf = OPENSSL_malloc(len + 1))) {
+       return -1;
+    }
+    for (i = 0; i < buf_len; i++) {
+       (*hexbuf)[2 * i] = hex[((unsigned char)buf[i]) >> 4];
+       (*hexbuf)[2 * i + 1] = hex[buf[i] & 0x0f];
+    }
+    (*hexbuf)[2 * i] = '\0';
+
+    if (hexbuf_len) {
+       *hexbuf_len = len;
+    }
+    return len;
+}
+
+/*
+ * Data Conversion
+ */
+#define OSSL_IMPL_ARY2SK(name, type, expected_class, dup)      \
+STACK_OF(type) *                                               \
+ossl_##name##_ary2sk0(VALUE ary)                               \
+{                                                              \
+    STACK_OF(type) *sk;                                                \
+    VALUE val;                                                 \
+    type *x;                                                   \
+    int i;                                                     \
+                                                               \
+    Check_Type(ary, T_ARRAY);                                  \
+    sk = sk_##type##_new_null();                               \
+    if (!sk) ossl_raise(eOSSLError, NULL);                     \
+                                                               \
+    for (i = 0; i < RARRAY_LEN(ary); i++) {                    \
+       val = rb_ary_entry(ary, i);                             \
+       if (!rb_obj_is_kind_of(val, expected_class)) {          \
+           sk_##type##_pop_free(sk, type##_free);              \
+           ossl_raise(eOSSLError, "object in array not"        \
+                      " of class ##type##");                   \
+       }                                                       \
+       x = dup(val); /* NEED TO DUP */                         \
+       sk_##type##_push(sk, x);                                \
+    }                                                          \
+    return sk;                                                 \
+}                                                              \
+                                                               \
+STACK_OF(type) *                                               \
+ossl_protect_##name##_ary2sk(VALUE ary, int *status)           \
+{                                                              \
+    return (STACK_OF(type)*)rb_protect(                                \
+           (VALUE(*)_((VALUE)))ossl_##name##_ary2sk0,          \
+           ary,                                                \
+           status);                                            \
+}                                                              \
+                                                               \
+STACK_OF(type) *                                               \
+ossl_##name##_ary2sk(VALUE ary)                                        \
+{                                                              \
+    STACK_OF(type) *sk;                                                \
+    int status = 0;                                            \
+                                                               \
+    sk = ossl_protect_##name##_ary2sk(ary, &status);           \
+    if (status) rb_jump_tag(status);                           \
+                                                               \
+    return sk;                                                 \
+}
+OSSL_IMPL_ARY2SK(x509, X509, cX509Cert, DupX509CertPtr)
+
+#define OSSL_IMPL_SK2ARY(name, type)           \
+VALUE                                          \
+ossl_##name##_sk2ary(STACK_OF(type) *sk)       \
+{                                              \
+    type *t;                                   \
+    int i, num;                                        \
+    VALUE ary;                                 \
+                                               \
+    if (!sk) {                                 \
+       OSSL_Debug("empty sk!");                \
+       return Qnil;                            \
+    }                                          \
+    num = sk_##type##_num(sk);                 \
+    if (num < 0) {                             \
+       OSSL_Debug("items in sk < -1???");      \
+       return rb_ary_new();                    \
+    }                                          \
+    ary = rb_ary_new2(num);                    \
+                                               \
+    for (i=0; i<num; i++) {                    \
+       t = sk_##type##_value(sk, i);           \
+       rb_ary_push(ary, ossl_##name##_new(t)); \
+    }                                          \
+    return ary;                                        \
+}
+OSSL_IMPL_SK2ARY(x509, X509)
+OSSL_IMPL_SK2ARY(x509crl, X509_CRL)
+OSSL_IMPL_SK2ARY(x509name, X509_NAME)
+
+static VALUE
+ossl_str_new(int size)
+{
+    return rb_str_new(0, size);
+}
+
+VALUE
+ossl_buf2str(char *buf, int len)
+{
+    VALUE str;
+    int status = 0;
+
+    str = rb_protect((VALUE(*)_((VALUE)))ossl_str_new, len, &status);
+    if(!NIL_P(str)) memcpy(RSTRING_PTR(str), buf, len);
+    OPENSSL_free(buf);
+    if(status) rb_jump_tag(status);
+
+    return str;
+}
+
+/*
+ * our default PEM callback
+ */
+static VALUE
+ossl_pem_passwd_cb0(VALUE flag)
+{
+    VALUE pass;
+
+    pass = rb_yield(flag);
+    SafeStringValue(pass);
+
+    return pass;
+}
+
+int
+ossl_pem_passwd_cb(char *buf, int max_len, int flag, void *pwd)
+{
+    int len, status = 0;
+    VALUE rflag, pass;
+
+    if (pwd || !rb_block_given_p())
+       return PEM_def_callback(buf, max_len, flag, pwd);
+
+    while (1) {
+       /*
+        * when the flag is nonzero, this passphrase
+        * will be used to perform encryption; otherwise it will
+        * be used to perform decryption.
+        */
+       rflag = flag ? Qtrue : Qfalse;
+       pass  = rb_protect(ossl_pem_passwd_cb0, rflag, &status);
+       if (status) return -1; /* exception was raised. */
+       len = RSTRING_LENINT(pass);
+       if (len < 4) { /* 4 is OpenSSL hardcoded limit */
+           rb_warning("password must be longer than 4 bytes");
+           continue;
+       }
+       if (len > max_len) {
+           rb_warning("password must be shorter then %d bytes", max_len-1);
+           continue;
+       }
+       memcpy(buf, RSTRING_PTR(pass), len);
+       break;
+    }
+    return len;
+}
+
+/*
+ * Verify callback
+ */
+int ossl_verify_cb_idx;
+
+VALUE
+ossl_call_verify_cb_proc(struct ossl_verify_cb_args *args)
+{
+    return rb_funcall(args->proc, rb_intern("call"), 2,
+                      args->preverify_ok, args->store_ctx);
+}
+
+int
+ossl_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+    VALUE proc, rctx, ret;
+    struct ossl_verify_cb_args args;
+    int state = 0;
+
+    proc = (VALUE)X509_STORE_CTX_get_ex_data(ctx, ossl_verify_cb_idx);
+    if ((void*)proc == 0)
+       proc = (VALUE)X509_STORE_get_ex_data(ctx->ctx, ossl_verify_cb_idx);
+    if ((void*)proc == 0)
+       return ok;
+    if (!NIL_P(proc)) {
+       rctx = rb_protect((VALUE(*)(VALUE))ossl_x509stctx_new,
+                         (VALUE)ctx, &state);
+       ret = Qfalse;
+       if (!state) {
+           args.proc = proc;
+           args.preverify_ok = ok ? Qtrue : Qfalse;
+           args.store_ctx = rctx;
+           ret = rb_protect((VALUE(*)(VALUE))ossl_call_verify_cb_proc, (VALUE)&args, &state);
+           ossl_x509stctx_clear_ptr(rctx);
+           if (state) {
+               rb_warn("exception in verify_callback is ignored");
+           }
+       }
+       if (ret == Qtrue) {
+           X509_STORE_CTX_set_error(ctx, X509_V_OK);
+           ok = 1;
+       }
+       else{
+           if (X509_STORE_CTX_get_error(ctx) == X509_V_OK) {
+               X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REJECTED);
+           }
+           ok = 0;
+       }
+    }
+
+    return ok;
+}
+
+/*
+ * main module
+ */
+VALUE mOSSL;
+
+/*
+ * OpenSSLError < StandardError
+ */
+VALUE eOSSLError;
+
+/*
+ * Convert to DER string
+ */
+ID ossl_s_to_der;
+
+VALUE
+ossl_to_der(VALUE obj)
+{
+    VALUE tmp;
+
+    tmp = rb_funcall(obj, ossl_s_to_der, 0);
+    StringValue(tmp);
+
+    return tmp;
+}
+
+VALUE
+ossl_to_der_if_possible(VALUE obj)
+{
+    if(rb_respond_to(obj, ossl_s_to_der))
+       return ossl_to_der(obj);
+    return obj;
+}
+
+/*
+ * Errors
+ */
+static VALUE
+ossl_make_error(VALUE exc, const char *fmt, va_list args)
+{
+    VALUE str = Qnil;
+    const char *msg;
+    long e;
+
+#ifdef HAVE_ERR_PEEK_LAST_ERROR
+    e = ERR_peek_last_error();
+#else
+    e = ERR_peek_error();
+#endif
+    if (fmt) {
+       str = rb_vsprintf(fmt, args);
+    }
+    if (e) {
+       if (dOSSL == Qtrue) /* FULL INFO */
+           msg = ERR_error_string(e, NULL);
+       else
+           msg = ERR_reason_error_string(e);
+       if (NIL_P(str)) {
+           str = rb_str_new_cstr(msg);
+       }
+       else {
+           rb_str_cat2(rb_str_cat2(str, ": "), msg);
+       }
+    }
+    if (dOSSL == Qtrue){ /* show all errors on the stack */
+       while ((e = ERR_get_error()) != 0){
+           rb_warn("error on stack: %s", ERR_error_string(e, NULL));
+       }
+    }
+    ERR_clear_error();
+
+    if (NIL_P(str)) str = rb_str_new(0, 0);
+    return rb_exc_new3(exc, str);
+}
+
+void
+ossl_raise(VALUE exc, const char *fmt, ...)
+{
+    va_list args;
+    VALUE err;
+    va_start(args, fmt);
+    err = ossl_make_error(exc, fmt, args);
+    va_end(args);
+    rb_exc_raise(err);
+}
+
+VALUE
+ossl_exc_new(VALUE exc, const char *fmt, ...)
+{
+    va_list args;
+    VALUE err;
+    va_start(args, fmt);
+    err = ossl_make_error(exc, fmt, args);
+    va_end(args);
+    return err;
+}
+
+/*
+ * call-seq:
+ *   OpenSSL.errors -> [String...]
+ *
+ * See any remaining errors held in queue.
+ *
+ * Any errors you see here are probably due to a bug in ruby's OpenSSL implementation.
+ */
+VALUE
+ossl_get_errors()
+{
+    VALUE ary;
+    long e;
+
+    ary = rb_ary_new();
+    while ((e = ERR_get_error()) != 0){
+        rb_ary_push(ary, rb_str_new2(ERR_error_string(e, NULL)));
+    }
+
+    return ary;
+}
+
+/*
+ * Debug
+ */
+VALUE dOSSL;
+
+#if !defined(HAVE_VA_ARGS_MACRO)
+void
+ossl_debug(const char *fmt, ...)
+{
+    va_list args;
+
+    if (dOSSL == Qtrue) {
+       fprintf(stderr, "OSSL_DEBUG: ");
+       va_start(args, fmt);
+       vfprintf(stderr, fmt, args);
+       va_end(args);
+       fprintf(stderr, " [CONTEXT N/A]\n");
+    }
+}
+#endif
+
+/*
+ * call-seq:
+ *   OpenSSL.debug -> true | false
+ */
+static VALUE
+ossl_debug_get(VALUE self)
+{
+    return dOSSL;
+}
+
+/*
+ * call-seq:
+ *   OpenSSL.debug = boolean -> boolean
+ *
+ * Turns on or off CRYPTO_MEM_CHECK.
+ * Also shows some debugging message on stderr.
+ */
+static VALUE
+ossl_debug_set(VALUE self, VALUE val)
+{
+    VALUE old = dOSSL;
+    dOSSL = val;
+
+    if (old != dOSSL) {
+       if (dOSSL == Qtrue) {
+           CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
+           fprintf(stderr, "OSSL_DEBUG: IS NOW ON!\n");
+       } else if (old == Qtrue) {
+           CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF);
+           fprintf(stderr, "OSSL_DEBUG: IS NOW OFF!\n");
+       }
+    }
+    return val;
+}
+
+/*
+ * OpenSSL provides SSL, TLS and general purpose cryptography.  It wraps the
+ * OpenSSL[http://www.openssl.org/] library.
+ *
+ * = Examples
+ *
+ * All examples assume you have loaded OpenSSL with:
+ *
+ *   require 'openssl'
+ *
+ * These examples build atop each other.  For example the key created in the
+ * next is used in throughout these examples.
+ *
+ * == Keys
+ *
+ * === Creating a Key
+ *
+ * This example creates a 2048 bit RSA keypair and writes it to the current
+ * directory.
+ *
+ *   key = OpenSSL::PKey::RSA.new 2048
+ *
+ *   open 'private_key.pem', 'w' do |io| io.write key.to_pem end
+ *   open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end
+ *
+ * === Exporting a Key
+ *
+ * Keys saved to disk without encryption are not secure as anyone who gets
+ * ahold of the key may use it unless it is encrypted.  In order to securely
+ * export a key you may export it with a pass phrase.
+ *
+ *   cipher = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
+ *   pass_phrase = 'my secure pass phrase goes here'
+ *
+ *   key_secure = key.export cipher, pass_phrase
+ *
+ *   open 'private.secure.pem', 'w' do |io|
+ *     io.write key_secure
+ *   end
+ *
+ * OpenSSL::Cipher.ciphers returns a list of available ciphers.
+ *
+ * === Loading a Key
+ *
+ * A key can also be loaded from a file.
+ *
+ *   key2 = OpenSSL::PKey::RSA.new File.read 'private_key.pem'
+ *   key2.public? # => true
+ *
+ * or
+ *
+ *   key3 = OpenSSL::PKey::RSA.new File.read 'public_key.pem'
+ *   key3.private? # => false
+ *
+ * === Loading an Encrypted Key
+ *
+ * OpenSSL will prompt you for your pass phrase when loading an encrypted key.
+ * If you will not be able to type in the pass phrase you may provide it when
+ * loading the key:
+ *
+ *   key4_pem = File.read 'private.secure.pem'
+ *   key4 = OpenSSL::PKey::RSA.new key4_pem, pass_phrase
+ *
+ * == RSA Encryption
+ *
+ * RSA provides ecryption and decryption using the public and private keys.
+ * You can use a variety of padding methods depending upon the intended use of
+ * encrypted data.
+ *
+ * === Encryption
+ *
+ * Documents encrypted with the public key can only be decrypted with the
+ * private key.
+ *
+ *   public_encrypted = key.public_encrypt 'top secret document'
+ *
+ * Documents encrypted with the private key can only be decrypted with the
+ * public key.
+ *
+ *   private_encrypted = key.private_encrypt 'public release document'
+ *
+ * === Decryption
+ *
+ * Use the opposite key type do decrypt the document
+ *
+ *   top_secret = key.public_decrypt public_encrypted
+ *
+ *   public_release = key.private_decrypt private_encrypted
+ *
+ * == PKCS #5 Password-based Encryption
+ *
+ * PKCS #5 is a password-based encryption standard documented at
+ * RFC2898[http://www.ietf.org/rfc/rfc2898.txt].  It allows a short password or
+ * passphrase to be used to create a secure encryption key.
+ *
+ * PKCS #5 uses a Cipher, a pass phrase and a salt to generate an encryption
+ * key.
+ *
+ *   pass_phrase = 'my secure pass phrase goes here'
+ *   salt = '8 octets'
+ *
+ * === Encryption
+ *
+ * First set up the cipher for encryption
+ *
+ *   encrypter = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
+ *   encrypter.encrypt
+ *   encrypter.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to encrypt through
+ *
+ *   encrypted = encrypter.update 'top secret document'
+ *   encrypted << encrypter.final
+ *
+ * === Decryption
+ *
+ * Use a new Cipher instance set up for decryption
+ *
+ *   decrypter = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
+ *   decrypter.decrypt
+ *   decrypter.pkcs5_keyivgen pass_phrase, salt
+ *
+ * Then pass the data you want to decrypt through
+ *
+ *   plain = decrypter.update encrypted
+ *   plain << decrypter.final
+ *
+ * == X509 Certificates
+ *
+ * === Creating a Certificate
+ *
+ * This example creates a self-signed certificate using an RSA key and a SHA1
+ * signature.
+ *
+ *   name = OpenSSL::X509::Name.parse 'CN=nobody/DC=example'
+ *
+ *   cert = OpenSSL::X509::Certificate.new
+ *   cert.version = 2
+ *   cert.serial = 0
+ *   cert.not_before = Time.now
+ *   cert.not_after = Time.now + 3600
+ *
+ *   cert.public_key = key.public_key
+ *   cert.subject = name
+ *
+ * === Certificate Extensions
+ *
+ * You can add extensions to the certificate with
+ * OpenSSL::SSL::ExtensionFactory to indicate the purpose of the certificate.
+ *
+ *   extension_factory = OpenSSL::X509::ExtensionFactory.new nil, cert
+ *
+ *   extension_factory.create_extension 'basicConstraints', 'CA:FALSE'
+ *   extension_factory.create_extension 'keyUsage',
+ *     'keyEncipherment,dataEncipherment,digitalSignature'
+ *   extension_factory.create_extension 'subjectKeyIdentifier', 'hash'
+ *
+ * === Signing a Certificate
+ *
+ * To sign a certificate set the issuer and use OpenSSL::X509::Certificate#sign
+ * with a digest algorithm.  This creates a self-signed cert because we're using
+ * the same name and key to sign the certificate as was used to create the
+ * certificate.
+ *
+ *   cert.issuer = name
+ *   cert.sign key, OpenSSL::Digest::SHA1.new
+ *
+ *   open 'certificate.pem', 'w' do |io| io.write cert.to_pem end
+ *
+ * === Loading a Certificate
+ *
+ * Like a key, a cert can also be loaded from a file.
+ *
+ *   cert2 = OpenSSL::X509::Certificate.new File.read 'certificate.pem'
+ *
+ * === Verifying a Certificate
+ *
+ * Certificate#verify will return true when a certificate was signed with the
+ * given public key.
+ *
+ *   raise 'certificate can not be verified' unless cert2.verify key
+ *
+ * == Certificate Authority
+ *
+ * A certificate authority (CA) is a trusted third party that allows you to
+ * verify the ownership of unknown certificates.  The CA issues key signatures
+ * that indicate it trusts the user of that key.  A user encountering the key
+ * can verify the signature by using the CA's public key.
+ *
+ * === CA Key
+ *
+ * CA keys are valuable, so we encrypt and save it to disk and make sure it is
+ * not readable by other users.
+ *
+ *   ca_key = OpenSSL::PKey::RSA.new 2048
+ *
+ *   cipher = OpenSSL::Cipher::Cipher.new 'AES-128-CBC'
+ *
+ *   open 'ca_key.pem', 'w', 0400 do |io|
+ *     io.write key.export(cipher, pass_phrase)
+ *   end
+ *
+ * === CA Certificate
+ *
+ * A CA certificate is created the same way we created a certificate above, but
+ * with different extensions.
+ *
+ *   ca_name = OpenSSL::X509::Name.parse 'CN=ca/DC=example'
+ *
+ *   ca_cert = OpenSSL::X509::Certificate.new
+ *   ca_cert.serial = 0
+ *   ca_cert.version = 2
+ *   ca_cert.not_before = Time.now
+ *   ca_cert.not_after = Time.now + 86400
+ *
+ *   ca_cert.public_key = ca_key.public_key
+ *   ca_cert.subject = ca_name
+ *   ca_cert.issuer = ca_name
+ *
+ *   extension_factory = OpenSSL::X509::ExtensionFactory.new
+ *   extension_factory.subject_certificate = ca_cert
+ *   extension_factory.issuer_certificate = ca_cert
+ *
+ *   extension_factory.create_extension 'subjectKeyIdentifier', 'hash'
+ *
+ * This extension indicates the CA's key may be used as a CA.
+ *
+ *   extension_factory.create_extension 'basicConstraints', 'CA:TRUE', true
+ *
+ * This extension indicates the CA's key may be used to verify signatures on
+ * both certificates and certificate revocations.
+ *
+ *   extension_factory.create_extension 'keyUsage', 'cRLSign,keyCertSign', true
+ *
+ * Root CA certificates are self-signed.
+ *
+ *   ca_cert.sign ca_key, OpenSSL::Digest::SHA1.new
+ *
+ * The CA certificate is saved to disk so it may be distributed to all the
+ * users of the keys this CA will sign.
+ *
+ *   open 'ca_cert.pem', 'w' do |io|
+ *     io.write ca_cert.to_pem
+ *   end
+ *
+ * === Certificate Signing Request
+ *
+ * The CA signs keys through a Certificate Signing Request (CSR).  The CSR
+ * contains the information necessary to identify the key.
+ *
+ *   csr = OpenSSL::X509::Request.new
+ *   csr.version = 0
+ *   csr.subject = name
+ *   csr.public_key = key.public_key
+ *   csr.sign key, OpenSSL::Digest::SHA1.new
+ *
+ * A CSR is saved to disk and sent to the CA for signing.
+ *
+ *   open 'csr.pem', 'w' do |io|
+ *     io.write csr.to_pem
+ *   end
+ *
+ * === Creating a Certificate from a CSR
+ *
+ * Upon receiving a CSR the CA will verify it before signing it.  A minimal
+ * verification would be to check the CSR's signature.
+ *
+ *   csr = OpenSSL::X509::Request.new File.read 'csr.pem'
+ *
+ *   raise 'CSR can not be verified' unless csr.verify csr.public_key
+ *
+ * After verification a certificate is created, marked for various usages,
+ * signed with the CA key and returned to the requester.
+ *
+ *   csr_cert = OpenSSL::X509::Certificate.new
+ *   csr_cert.serial = 0
+ *   csr_cert.version = 2
+ *   csr_cert.not_before = Time.now
+ *   csr_cert.not_after = Time.now + 600
+ *
+ *   csr_cert.subject = csr.subject
+ *   csr_cert.public_key = csr.public_key
+ *   csr_cert.issuer = ca_cert.subject
+ *
+ *   extension_factory = OpenSSL::X509::ExtensionFactory.new
+ *   extension_factory.subject_certificate = csr_cert
+ *   extension_factory.issuer_certificate = ca_cert
+ *
+ *   extension_factory.create_extension 'basicConstraints', 'CA:FALSE'
+ *   extension_factory.create_extension 'keyUsage',
+ *     'keyEncipherment,dataEncipherment,digitalSignature'
+ *   extension_factory.create_extension 'subjectKeyIdentifier', 'hash'
+ *
+ *   csr_cert.sign ca_key, OpenSSL::Digest::SHA1.new
+ *
+ *   open 'csr_cert.pem', 'w' do |io|
+ *     io.write csr_cert.to_pem
+ *   end
+ *
+ * == SSL and TLS Connections
+ *
+ * Using our created key and certificate we can create an SSL or TLS connection.
+ * An SSLContext is used to set up an SSL session.
+ *
+ *   context = OpenSSL::SSL::SSLContext.new
+ *
+ * === SSL Server
+ *
+ * An SSL server requires the certificate and private key to communicate
+ * securely with its clients:
+ *
+ *   context.cert = cert
+ *   context.key = key
+ *
+ * Then create an SSLServer with a TCP server socket and the context.  Use the
+ * SSLServer like an ordinary TCP server.
+ *
+ *   require 'socket'
+ *
+ *   tcp_server = TCPServer.new 5000
+ *   ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context
+ *
+ *   loop do
+ *     ssl_connection = ssl_server.accept
+ *
+ *     data = connection.gets
+ *
+ *     response = "I got #{data.dump}"
+ *     puts response
+ *
+ *     connection.puts "I got #{data.dump}"
+ *     connection.close
+ *   end
+ *
+ * === SSL client
+ *
+ * An SSL client is created with a TCP socket and the context.
+ * SSLSocket#connect must be called to initiate the SSL handshake and start
+ * encryption.  A key and certificate are not required for the client socket.
+ *
+ *   require 'socket'
+ *
+ *   tcp_client = TCPSocket.new 'localhost', 5000
+ *   ssl_client = OpenSSL::SSL::SSLSocket.new client_socket, context
+ *   ssl_client.connect
+ *
+ *   ssl_client.puts "hello server!"
+ *   puts ssl_client.gets
+ *
+ * === Peer Verification
+ *
+ * An unverified SSL connection does not provide much security.  For enhanced
+ * security the client or server can verify the certificate of its peer.
+ *
+ * The client can be modified to verify the server's certificate against the
+ * certificate authority's certificate:
+ *
+ *   context.ca_file = 'ca_cert.pem'
+ *   context.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ *
+ *   require 'socket'
+ *
+ *   tcp_client = TCPSocket.new 'localhost', 5000
+ *   ssl_client = OpenSSL::SSL::SSLSocket.new client_socket, context
+ *   ssl_client.connect
+ *
+ *   ssl_client.puts "hello server!"
+ *   puts ssl_client.gets
+ *
+ * If the server certificate is invalid or <tt>context.ca_file</tt> is not set
+ * when verifying peers an OpenSSL::SSL::SSLError will be raised.
+ *
+ */
+void
+Init_openssl_cms()
+{
+    /*
+     * Init timezone info
+     */
+#if 0
+    tzset();
+#endif
+
+    /*
+     * Init all digests, ciphers
+     */
+    /* CRYPTO_malloc_init(); */
+    /* ENGINE_load_builtin_engines(); */
+    OpenSSL_add_ssl_algorithms();
+    OpenSSL_add_all_algorithms();
+    ERR_load_crypto_strings();
+    SSL_load_error_strings();
+
+    /*
+     * FIXME:
+     * On unload do:
+     */
+#if 0
+    CONF_modules_unload(1);
+    destroy_ui_method();
+    EVP_cleanup();
+    ENGINE_cleanup();
+    CRYPTO_cleanup_all_ex_data();
+    ERR_remove_state(0);
+    ERR_free_strings();
+#endif
+
+    /*
+     * Init main module
+     */
+    mOSSL = rb_define_module("OpenSSL");
+
+    /*
+     * OpenSSL ruby extension version
+     */
+    rb_define_const(mOSSL, "VERSION", rb_str_new2(OSSL_VERSION));
+
+    /*
+     * Version of OpenSSL the ruby OpenSSL extension was built with
+     */
+    rb_define_const(mOSSL, "OPENSSL_VERSION", rb_str_new2(OPENSSL_VERSION_TEXT));
+    /*
+     * Version number of OpenSSL the ruby OpenSSL extension was built with
+     * (base 16)
+     */
+    rb_define_const(mOSSL, "OPENSSL_VERSION_NUMBER", INT2NUM(OPENSSL_VERSION_NUMBER));
+
+    /*
+     * Generic error,
+     * common for all classes under OpenSSL module
+     */
+    eOSSLError = rb_define_class_under(mOSSL,"OpenSSLError",rb_eStandardError);
+
+    /*
+     * Verify callback Proc index for ext-data
+     */
+    if ((ossl_verify_cb_idx = X509_STORE_CTX_get_ex_new_index(0, (void *)"ossl_verify_cb_idx", 0, 0, 0)) < 0)
+        ossl_raise(eOSSLError, "X509_STORE_CTX_get_ex_new_index");
+
+    /*
+     * Init debug core
+     */
+    dOSSL = Qfalse;
+    rb_define_module_function(mOSSL, "debug", ossl_debug_get, 0);
+    rb_define_module_function(mOSSL, "debug=", ossl_debug_set, 1);
+    rb_define_module_function(mOSSL, "errors", ossl_get_errors, 0);
+
+    /*
+     * Get ID of to_der
+     */
+    ossl_s_to_der = rb_intern("to_der");
+
+    /*
+     * Init components
+     */
+    Init_ossl_bn();
+    Init_ossl_cipher();
+    Init_ossl_config();
+    Init_ossl_digest();
+    Init_ossl_hmac();
+    Init_ossl_ns_spki();
+    Init_ossl_pkcs12();
+    Init_ossl_pkcs7();
+    Init_ossl_pkcs5();
+    Init_ossl_pkey();
+    Init_ossl_rand();
+    Init_ossl_ssl();
+    Init_ossl_x509();
+    Init_ossl_ocsp();
+    Init_ossl_engine();
+    Init_ossl_asn1();
+    Init_ossl_cms();
+}
+
+#if defined(OSSL_DEBUG)
+/*
+ * Check if all symbols are OK with 'make LDSHARED=gcc all'
+ */
+int
+main(int argc, char *argv[])
+{
+    return 0;
+}
+#endif /* OSSL_DEBUG */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl.h
new file mode 100644 (file)
index 0000000..cb11e75
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_H_)
+#define _OSSL_H_
+
+#include RUBY_EXTCONF_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#if 0
+  mOSSL = rb_define_module("OpenSSL");
+  mX509 = rb_define_module_under(mOSSL, "X509");
+#endif
+
+/*
+* OpenSSL has defined RFILE and Ruby has defined RFILE - so undef it!
+*/
+#if defined(RFILE) /*&& !defined(OSSL_DEBUG)*/
+#  undef RFILE
+#endif
+#include <ruby.h>
+#include <ruby/io.h>
+
+/*
+ * Check the OpenSSL version
+ * The only supported are:
+ *     OpenSSL >= 0.9.7
+ */
+#include <openssl/opensslv.h>
+
+#ifdef HAVE_ASSERT_H
+#  include <assert.h>
+#else
+#  define assert(condition)
+#endif
+
+#if defined(_WIN32)
+#  include <openssl/e_os2.h>
+#  define OSSL_NO_CONF_API 1
+#  if !defined(OPENSSL_SYS_WIN32)
+#    define OPENSSL_SYS_WIN32 1
+#  endif
+#  include <winsock2.h>
+#endif
+#include <errno.h>
+#include <openssl/err.h>
+#include <openssl/asn1_mac.h>
+#include <openssl/x509v3.h>
+#include <openssl/ssl.h>
+#include <openssl/pkcs12.h>
+#include <openssl/pkcs7.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#include <openssl/conf.h>
+#include <openssl/conf_api.h>
+#include <openssl/cms.h>
+#undef X509_NAME
+#undef PKCS7_SIGNER_INFO
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ST_ENGINE)
+#  define OSSL_ENGINE_ENABLED
+#  include <openssl/engine.h>
+#endif
+#if defined(HAVE_OPENSSL_OCSP_H)
+#  define OSSL_OCSP_ENABLED
+#  include <openssl/ocsp.h>
+#endif
+
+/*
+ * Common Module
+ */
+extern VALUE mOSSL;
+
+/*
+ * Common Error Class
+ */
+extern VALUE eOSSLError;
+
+/*
+ * CheckTypes
+ */
+#define OSSL_Check_Kind(obj, klass) do {\
+  if (!rb_obj_is_kind_of((obj), (klass))) {\
+    ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected kind of %s)",\
+               RB_OBJ_CLASSNAME(obj), rb_class2name(klass));\
+  }\
+} while (0)
+
+#define OSSL_Check_Instance(obj, klass) do {\
+  if (!rb_obj_is_instance_of((obj), (klass))) {\
+    ossl_raise(rb_eTypeError, "wrong argument (%"PRIsVALUE")! (Expected instance of %s)",\
+               RB_OBJ_CLASSNAME(obj), rb_class2name(klass));\
+  }\
+} while (0)
+
+#define OSSL_Check_Same_Class(obj1, obj2) do {\
+  if (!rb_obj_is_instance_of((obj1), rb_obj_class(obj2))) {\
+    ossl_raise(rb_eTypeError, "wrong argument type");\
+  }\
+} while (0)
+
+/*
+ * Compatibility
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#define STACK _STACK
+#endif
+
+/*
+ * String to HEXString conversion
+ */
+int string2hex(const unsigned char *, int, char **, int *);
+
+/*
+ * Data Conversion
+ */
+STACK_OF(X509) *ossl_x509_ary2sk0(VALUE);
+STACK_OF(X509) *ossl_x509_ary2sk(VALUE);
+STACK_OF(X509) *ossl_protect_x509_ary2sk(VALUE,int*);
+VALUE ossl_x509_sk2ary(STACK_OF(X509) *certs);
+VALUE ossl_x509crl_sk2ary(STACK_OF(X509_CRL) *crl);
+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));\
+    assert(newlen <= len);\
+    rb_str_set_len((str), newlen);\
+}while(0)
+
+/*
+ * our default PEM callback
+ */
+int ossl_pem_passwd_cb(char *, int, int, void *);
+
+/*
+ * Clear BIO* with this in PEM/DER fallback scenarios to avoid decoding
+ * errors piling up in OpenSSL::Errors
+ */
+#define OSSL_BIO_reset(bio)    (void)BIO_reset((bio)); \
+                               ERR_clear_error();
+
+/*
+ * ERRor messages
+ */
+#define OSSL_ErrMsg() ERR_reason_error_string(ERR_get_error())
+NORETURN(void ossl_raise(VALUE, const char *, ...));
+VALUE ossl_exc_new(VALUE, const char *, ...);
+
+/*
+ * Verify callback
+ */
+extern int ossl_verify_cb_idx;
+
+struct ossl_verify_cb_args {
+    VALUE proc;
+    VALUE preverify_ok;
+    VALUE store_ctx;
+};
+
+VALUE ossl_call_verify_cb_proc(struct ossl_verify_cb_args *);
+int ossl_verify_cb(int, X509_STORE_CTX *);
+
+/*
+ * String to DER String
+ */
+extern ID ossl_s_to_der;
+VALUE ossl_to_der(VALUE);
+VALUE ossl_to_der_if_possible(VALUE);
+
+/*
+ * Debug
+ */
+extern VALUE dOSSL;
+
+#if defined(HAVE_VA_ARGS_MACRO)
+#define OSSL_Debug(...) do { \
+  if (dOSSL == Qtrue) { \
+    fprintf(stderr, "OSSL_DEBUG: "); \
+    fprintf(stderr, __VA_ARGS__); \
+    fprintf(stderr, " [%s:%d]\n", __FILE__, __LINE__); \
+  } \
+} while (0)
+
+#define OSSL_Warning(fmt, ...) do { \
+  OSSL_Debug((fmt), ##__VA_ARGS__); \
+  rb_warning((fmt), ##__VA_ARGS__); \
+} while (0)
+
+#define OSSL_Warn(fmt, ...) do { \
+  OSSL_Debug((fmt), ##__VA_ARGS__); \
+  rb_warn((fmt), ##__VA_ARGS__); \
+} while (0)
+#else
+void ossl_debug(const char *, ...);
+#define OSSL_Debug ossl_debug
+#define OSSL_Warning rb_warning
+#define OSSL_Warn rb_warn
+#endif
+
+/*
+ * Include all parts
+ */
+#include "openssl_missing.h"
+#include "ruby_missing.h"
+#include "ossl_asn1.h"
+#include "ossl_bio.h"
+#include "ossl_bn.h"
+#include "ossl_cipher.h"
+#include "ossl_config.h"
+#include "ossl_digest.h"
+#include "ossl_hmac.h"
+#include "ossl_ns_spki.h"
+#include "ossl_ocsp.h"
+#include "ossl_pkcs12.h"
+#include "ossl_pkcs7.h"
+#include "ossl_pkcs5.h"
+#include "ossl_pkey.h"
+#include "ossl_rand.h"
+#include "ossl_ssl.h"
+#include "ossl_version.h"
+#include "ossl_x509.h"
+#include "ossl_engine.h"
+#include "ossl_cms.h"
+
+void Init_openssl_cms(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _OSSL_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_asn1.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_asn1.c
new file mode 100644 (file)
index 0000000..ae5e476
--- /dev/null
@@ -0,0 +1,1954 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' team members
+ * Copyright (C) 2003
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#if defined(HAVE_SYS_TIME_H)
+#  include <sys/time.h>
+#elif !defined(NT) && !defined(_WIN32)
+struct timeval {
+    long tv_sec;       /* seconds */
+    long tv_usec;      /* and microseconds */
+};
+#endif
+
+static VALUE join_der(VALUE enumerable);
+static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset,
+                              int depth, int yield, long *num_read);
+static VALUE ossl_asn1_initialize(int argc, VALUE *argv, VALUE self);
+static VALUE ossl_asn1eoc_initialize(VALUE self);
+
+/*
+ * DATE conversion
+ */
+VALUE
+asn1time_to_time(ASN1_TIME *time)
+{
+    struct tm tm;
+    VALUE argv[6];
+    int count;
+
+    if (!time || !time->data) return Qnil;
+    memset(&tm, 0, sizeof(struct tm));
+
+    switch (time->type) {
+    case V_ASN1_UTCTIME:
+       count = sscanf((const char *)time->data, "%2d%2d%2d%2d%2d%2dZ",
+               &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min,
+               &tm.tm_sec);
+
+       if (count == 5) {
+           tm.tm_sec = 0;
+       } else if (count != 6) {
+           ossl_raise(rb_eTypeError, "bad UTCTIME format: \"%s\"",
+                   time->data);
+       }
+       if (tm.tm_year < 69) {
+           tm.tm_year += 2000;
+       } else {
+           tm.tm_year += 1900;
+       }
+       break;
+    case V_ASN1_GENERALIZEDTIME:
+       if (sscanf((const char *)time->data, "%4d%2d%2d%2d%2d%2dZ", &tm.tm_year, &tm.tm_mon,
+               &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6) {
+           ossl_raise(rb_eTypeError, "bad GENERALIZEDTIME format" );
+       }
+       break;
+    default:
+       rb_warning("unknown time format");
+        return Qnil;
+    }
+    argv[0] = INT2NUM(tm.tm_year);
+    argv[1] = INT2NUM(tm.tm_mon);
+    argv[2] = INT2NUM(tm.tm_mday);
+    argv[3] = INT2NUM(tm.tm_hour);
+    argv[4] = INT2NUM(tm.tm_min);
+    argv[5] = INT2NUM(tm.tm_sec);
+
+    return rb_funcall2(rb_cTime, rb_intern("utc"), 6, argv);
+}
+
+/*
+ * This function is not exported in Ruby's *.h
+ */
+extern struct timeval rb_time_timeval(VALUE);
+
+time_t
+time_to_time_t(VALUE time)
+{
+    return (time_t)NUM2LONG(rb_Integer(time));
+}
+
+/*
+ * STRING conversion
+ */
+VALUE
+asn1str_to_str(ASN1_STRING *str)
+{
+    return rb_str_new((const char *)str->data, str->length);
+}
+
+/*
+ * ASN1_INTEGER conversions
+ * TODO: Make a decision what's the right way to do this.
+ */
+#define DO_IT_VIA_RUBY 0
+VALUE
+asn1integer_to_num(ASN1_INTEGER *ai)
+{
+    BIGNUM *bn;
+#if DO_IT_VIA_RUBY
+    char *txt;
+#endif
+    VALUE num;
+
+    if (!ai) {
+       ossl_raise(rb_eTypeError, "ASN1_INTEGER is NULL!");
+    }
+    if (!(bn = ASN1_INTEGER_to_BN(ai, NULL))) {
+       ossl_raise(eOSSLError, NULL);
+    }
+#if DO_IT_VIA_RUBY
+    if (!(txt = BN_bn2dec(bn))) {
+       BN_free(bn);
+       ossl_raise(eOSSLError, NULL);
+    }
+    num = rb_cstr_to_inum(txt, 10, Qtrue);
+    OPENSSL_free(txt);
+#else
+    num = ossl_bn_new(bn);
+#endif
+    BN_free(bn);
+
+    return num;
+}
+
+#if DO_IT_VIA_RUBY
+ASN1_INTEGER *
+num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
+{
+    BIGNUM *bn = NULL;
+
+    if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
+       bn = GetBNPtr(obj);
+    } else {
+       obj = rb_String(obj);
+       if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
+           ossl_raise(eOSSLError, NULL);
+       }
+    }
+    if (!(ai = BN_to_ASN1_INTEGER(bn, ai))) {
+       BN_free(bn);
+       ossl_raise(eOSSLError, NULL);
+    }
+    BN_free(bn);
+    return ai;
+}
+#else
+ASN1_INTEGER *
+num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
+{
+    BIGNUM *bn;
+   
+    if (NIL_P(obj)) 
+       ossl_raise(rb_eTypeError, "Can't convert nil into Integer");
+
+    bn = GetBNPtr(obj);
+
+    if (!(ai = BN_to_ASN1_INTEGER(bn, ai)))
+       ossl_raise(eOSSLError, NULL);
+
+    return ai;
+}
+#endif
+
+/********/
+/*
+ * ASN1 module
+ */
+#define ossl_asn1_get_value(o)           rb_attr_get((o),sivVALUE)
+#define ossl_asn1_get_tag(o)             rb_attr_get((o),sivTAG)
+#define ossl_asn1_get_tagging(o)         rb_attr_get((o),sivTAGGING)
+#define ossl_asn1_get_tag_class(o)       rb_attr_get((o),sivTAG_CLASS)
+#define ossl_asn1_get_infinite_length(o) rb_attr_get((o),sivINFINITE_LENGTH)
+
+#define ossl_asn1_set_value(o,v)           rb_ivar_set((o),sivVALUE,(v))
+#define ossl_asn1_set_tag(o,v)             rb_ivar_set((o),sivTAG,(v))
+#define ossl_asn1_set_tagging(o,v)         rb_ivar_set((o),sivTAGGING,(v))
+#define ossl_asn1_set_tag_class(o,v)       rb_ivar_set((o),sivTAG_CLASS,(v))
+#define ossl_asn1_set_infinite_length(o,v) rb_ivar_set((o),sivINFINITE_LENGTH,(v))
+
+VALUE mASN1;
+VALUE eASN1Error;
+
+VALUE cASN1Data;
+VALUE cASN1Primitive;
+VALUE cASN1Constructive;
+
+VALUE cASN1EndOfContent;
+VALUE cASN1Boolean;                           /* BOOLEAN           */
+VALUE cASN1Integer, cASN1Enumerated;          /* INTEGER           */
+VALUE cASN1BitString;                         /* BIT STRING        */
+VALUE cASN1OctetString, cASN1UTF8String;      /* STRINGs           */
+VALUE cASN1NumericString, cASN1PrintableString;
+VALUE cASN1T61String, cASN1VideotexString;
+VALUE cASN1IA5String, cASN1GraphicString;
+VALUE cASN1ISO64String, cASN1GeneralString;
+VALUE cASN1UniversalString, cASN1BMPString;
+VALUE cASN1Null;                              /* NULL              */
+VALUE cASN1ObjectId;                          /* OBJECT IDENTIFIER */
+VALUE cASN1UTCTime, cASN1GeneralizedTime;     /* TIME              */
+VALUE cASN1Sequence, cASN1Set;                /* CONSTRUCTIVE      */
+
+static ID sIMPLICIT, sEXPLICIT;
+static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE;
+static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINFINITE_LENGTH, sivUNUSED_BITS;
+
+/*
+ * We need to implement these for backward compatibility
+ * reasons, behavior of ASN1_put_object and ASN1_object_size
+ * for infinite length values is different in OpenSSL <= 0.9.7
+ */
+#if OPENSSL_VERSION_NUMBER < 0x00908000L
+#define ossl_asn1_object_size(cons, len, tag)          (cons) == 2 ? (len) + ASN1_object_size((cons), 0, (tag)) : ASN1_object_size((cons), (len), (tag))
+#define ossl_asn1_put_object(pp, cons, len, tag, xc)   (cons) == 2 ? ASN1_put_object((pp), (cons), 0, (tag), (xc)) : ASN1_put_object((pp), (cons), (len), (tag), (xc))
+#else
+#define ossl_asn1_object_size(cons, len, tag)          ASN1_object_size((cons), (len), (tag))
+#define ossl_asn1_put_object(pp, cons, len, tag, xc)   ASN1_put_object((pp), (cons), (len), (tag), (xc))
+#endif
+
+/*
+ * Ruby to ASN1 converters
+ */
+static ASN1_BOOLEAN
+obj_to_asn1bool(VALUE obj)
+{
+    if (NIL_P(obj))
+       ossl_raise(rb_eTypeError, "Can't convert nil into Boolean");
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+     return RTEST(obj) ? 0xff : 0x100;
+#else
+     return RTEST(obj) ? 0xff : 0x0;
+#endif
+}
+
+static ASN1_INTEGER*
+obj_to_asn1int(VALUE obj)
+{
+    return num_to_asn1integer(obj, NULL);
+}
+
+static ASN1_BIT_STRING*
+obj_to_asn1bstr(VALUE obj, long unused_bits)
+{
+    ASN1_BIT_STRING *bstr;
+
+    if(unused_bits < 0) unused_bits = 0;
+    StringValue(obj);
+    if(!(bstr = ASN1_BIT_STRING_new()))
+       ossl_raise(eASN1Error, NULL);
+    ASN1_BIT_STRING_set(bstr, (unsigned char *)RSTRING_PTR(obj), RSTRING_LENINT(obj));
+    bstr->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */
+    bstr->flags |= ASN1_STRING_FLAG_BITS_LEFT|(unused_bits&0x07);
+
+    return bstr;
+}
+
+static ASN1_STRING*
+obj_to_asn1str(VALUE obj)
+{
+    ASN1_STRING *str;
+
+    StringValue(obj);
+    if(!(str = ASN1_STRING_new()))
+       ossl_raise(eASN1Error, NULL);
+    ASN1_STRING_set(str, RSTRING_PTR(obj), RSTRING_LENINT(obj));
+
+    return str;
+}
+
+static ASN1_NULL*
+obj_to_asn1null(VALUE obj)
+{
+    ASN1_NULL *null;
+
+    if(!NIL_P(obj))
+       ossl_raise(eASN1Error, "nil expected");
+    if(!(null = ASN1_NULL_new()))
+       ossl_raise(eASN1Error, NULL);
+
+    return null;
+}
+
+static ASN1_OBJECT*
+obj_to_asn1obj(VALUE obj)
+{
+    ASN1_OBJECT *a1obj;
+
+    StringValue(obj);
+    a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 0);
+    if(!a1obj) a1obj = OBJ_txt2obj(RSTRING_PTR(obj), 1);
+    if(!a1obj) ossl_raise(eASN1Error, "invalid OBJECT ID");
+
+    return a1obj;
+}
+
+static ASN1_UTCTIME*
+obj_to_asn1utime(VALUE time)
+{
+    time_t sec;
+    ASN1_UTCTIME *t;
+
+    sec = time_to_time_t(time);
+    if(!(t = ASN1_UTCTIME_set(NULL, sec)))
+        ossl_raise(eASN1Error, NULL);
+
+    return t;
+}
+
+static ASN1_GENERALIZEDTIME*
+obj_to_asn1gtime(VALUE time)
+{
+    time_t sec;
+    ASN1_GENERALIZEDTIME *t;
+
+    sec = time_to_time_t(time);
+    if(!(t =ASN1_GENERALIZEDTIME_set(NULL, sec)))
+        ossl_raise(eASN1Error, NULL);
+
+    return t;
+}
+
+static ASN1_STRING*
+obj_to_asn1derstr(VALUE obj)
+{
+    ASN1_STRING *a1str;
+    VALUE str;
+
+    str = ossl_to_der(obj);
+    if(!(a1str = ASN1_STRING_new()))
+       ossl_raise(eASN1Error, NULL);
+    ASN1_STRING_set(a1str, RSTRING_PTR(str), RSTRING_LENINT(str));
+
+    return a1str;
+}
+
+/*
+ * DER to Ruby converters
+ */
+static VALUE
+decode_bool(unsigned char* der, int length)
+{
+    int val;
+    const unsigned char *p;
+
+    p = der;
+    if((val = d2i_ASN1_BOOLEAN(NULL, &p, length)) < 0)
+       ossl_raise(eASN1Error, NULL);
+
+    return val ? Qtrue : Qfalse;
+}
+
+static VALUE
+decode_int(unsigned char* der, int length)
+{
+    ASN1_INTEGER *ai;
+    const unsigned char *p;
+    VALUE ret;
+    int status = 0;
+
+    p = der;
+    if(!(ai = d2i_ASN1_INTEGER(NULL, &p, length)))
+       ossl_raise(eASN1Error, NULL);
+    ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num,
+                    (VALUE)ai, &status);
+    ASN1_INTEGER_free(ai);
+    if(status) rb_jump_tag(status);
+
+    return ret;
+}
+
+static VALUE
+decode_bstr(unsigned char* der, int length, long *unused_bits)
+{
+    ASN1_BIT_STRING *bstr;
+    const unsigned char *p;
+    long len;
+    VALUE ret;
+
+    p = der;
+    if(!(bstr = d2i_ASN1_BIT_STRING(NULL, &p, length)))
+       ossl_raise(eASN1Error, NULL);
+    len = bstr->length;
+    *unused_bits = 0;
+    if(bstr->flags & ASN1_STRING_FLAG_BITS_LEFT)
+       *unused_bits = bstr->flags & 0x07;
+    ret = rb_str_new((const char *)bstr->data, len);
+    ASN1_BIT_STRING_free(bstr);
+
+    return ret;
+}
+
+static VALUE
+decode_enum(unsigned char* der, int length)
+{
+    ASN1_ENUMERATED *ai;
+    const unsigned char *p;
+    VALUE ret;
+    int status = 0;
+
+    p = der;
+    if(!(ai = d2i_ASN1_ENUMERATED(NULL, &p, length)))
+       ossl_raise(eASN1Error, NULL);
+    ret = rb_protect((VALUE(*)_((VALUE)))asn1integer_to_num,
+                    (VALUE)ai, &status);
+    ASN1_ENUMERATED_free(ai);
+    if(status) rb_jump_tag(status);
+
+    return ret;
+}
+
+static VALUE
+decode_null(unsigned char* der, int length)
+{
+    ASN1_NULL *null;
+    const unsigned char *p;
+
+    p = der;
+    if(!(null = d2i_ASN1_NULL(NULL, &p, length)))
+       ossl_raise(eASN1Error, NULL);
+    ASN1_NULL_free(null);
+
+    return Qnil;
+}
+
+static VALUE
+decode_obj(unsigned char* der, int length)
+{
+    ASN1_OBJECT *obj;
+    const unsigned char *p;
+    VALUE ret;
+    int nid;
+    BIO *bio;
+
+    p = der;
+    if(!(obj = d2i_ASN1_OBJECT(NULL, &p, length)))
+       ossl_raise(eASN1Error, NULL);
+    if((nid = OBJ_obj2nid(obj)) != NID_undef){
+       ASN1_OBJECT_free(obj);
+       ret = rb_str_new2(OBJ_nid2sn(nid));
+    }
+    else{
+       if(!(bio = BIO_new(BIO_s_mem()))){
+           ASN1_OBJECT_free(obj);
+           ossl_raise(eASN1Error, NULL);
+       }
+       i2a_ASN1_OBJECT(bio, obj);
+       ASN1_OBJECT_free(obj);
+       ret = ossl_membio2str(bio);
+    }
+
+    return ret;
+}
+
+static VALUE
+decode_time(unsigned char* der, int length)
+{
+    ASN1_TIME *time;
+    const unsigned char *p;
+    VALUE ret;
+    int status = 0;
+
+    p = der;
+    if(!(time = d2i_ASN1_TIME(NULL, &p, length)))
+       ossl_raise(eASN1Error, NULL);
+    ret = rb_protect((VALUE(*)_((VALUE)))asn1time_to_time,
+                    (VALUE)time, &status);
+    ASN1_TIME_free(time);
+    if(status) rb_jump_tag(status);
+
+    return ret;
+}
+
+static VALUE
+decode_eoc(unsigned char *der, int length)
+{
+    if (length != 2 || !(der[0] == 0x00 && der[1] == 0x00))
+       ossl_raise(eASN1Error, NULL);
+
+    return rb_str_new("", 0);
+}
+
+/********/
+
+typedef struct {
+    const char *name;
+    VALUE *klass;
+} ossl_asn1_info_t;
+
+static ossl_asn1_info_t ossl_asn1_info[] = {
+    { "EOC",               &cASN1EndOfContent,    },  /*  0 */
+    { "BOOLEAN",           &cASN1Boolean,         },  /*  1 */
+    { "INTEGER",           &cASN1Integer,         },  /*  2 */
+    { "BIT_STRING",        &cASN1BitString,       },  /*  3 */
+    { "OCTET_STRING",      &cASN1OctetString,     },  /*  4 */
+    { "NULL",              &cASN1Null,            },  /*  5 */
+    { "OBJECT",            &cASN1ObjectId,        },  /*  6 */
+    { "OBJECT_DESCRIPTOR", NULL,                  },  /*  7 */
+    { "EXTERNAL",          NULL,                  },  /*  8 */
+    { "REAL",              NULL,                  },  /*  9 */
+    { "ENUMERATED",        &cASN1Enumerated,      },  /* 10 */
+    { "EMBEDDED_PDV",      NULL,                  },  /* 11 */
+    { "UTF8STRING",        &cASN1UTF8String,      },  /* 12 */
+    { "RELATIVE_OID",      NULL,                  },  /* 13 */
+    { "[UNIVERSAL 14]",    NULL,                  },  /* 14 */
+    { "[UNIVERSAL 15]",    NULL,                  },  /* 15 */
+    { "SEQUENCE",          &cASN1Sequence,        },  /* 16 */
+    { "SET",               &cASN1Set,             },  /* 17 */
+    { "NUMERICSTRING",     &cASN1NumericString,   },  /* 18 */
+    { "PRINTABLESTRING",   &cASN1PrintableString, },  /* 19 */
+    { "T61STRING",         &cASN1T61String,       },  /* 20 */
+    { "VIDEOTEXSTRING",    &cASN1VideotexString,  },  /* 21 */
+    { "IA5STRING",         &cASN1IA5String,       },  /* 22 */
+    { "UTCTIME",           &cASN1UTCTime,         },  /* 23 */
+    { "GENERALIZEDTIME",   &cASN1GeneralizedTime, },  /* 24 */
+    { "GRAPHICSTRING",     &cASN1GraphicString,   },  /* 25 */
+    { "ISO64STRING",       &cASN1ISO64String,     },  /* 26 */
+    { "GENERALSTRING",     &cASN1GeneralString,   },  /* 27 */
+    { "UNIVERSALSTRING",   &cASN1UniversalString, },  /* 28 */
+    { "CHARACTER_STRING",  NULL,                  },  /* 29 */
+    { "BMPSTRING",         &cASN1BMPString,       },  /* 30 */
+};
+
+int ossl_asn1_info_size = (sizeof(ossl_asn1_info)/sizeof(ossl_asn1_info[0]));
+
+static VALUE class_tag_map;
+
+static int ossl_asn1_default_tag(VALUE obj);
+
+ASN1_TYPE*
+ossl_asn1_get_asn1type(VALUE obj)
+{
+    ASN1_TYPE *ret;
+    VALUE value, rflag;
+    void *ptr;
+    void (*free_func)();
+    int tag, flag;
+
+    tag = ossl_asn1_default_tag(obj);
+    value = ossl_asn1_get_value(obj);
+    switch(tag){
+    case V_ASN1_BOOLEAN:
+       ptr = (void*)(VALUE)obj_to_asn1bool(value);
+       free_func = NULL;
+       break;
+    case V_ASN1_INTEGER:         /* FALLTHROUGH */
+    case V_ASN1_ENUMERATED:
+       ptr = obj_to_asn1int(value);
+       free_func = ASN1_INTEGER_free;
+       break;
+    case V_ASN1_BIT_STRING:
+        rflag = rb_attr_get(obj, sivUNUSED_BITS);
+        flag = NIL_P(rflag) ? -1 : NUM2INT(rflag);
+       ptr = obj_to_asn1bstr(value, flag);
+       free_func = ASN1_BIT_STRING_free;
+       break;
+    case V_ASN1_NULL:
+       ptr = obj_to_asn1null(value);
+       free_func = ASN1_NULL_free;
+       break;
+    case V_ASN1_OCTET_STRING:    /* FALLTHROUGH */
+    case V_ASN1_UTF8STRING:      /* FALLTHROUGH */
+    case V_ASN1_NUMERICSTRING:   /* FALLTHROUGH */
+    case V_ASN1_PRINTABLESTRING: /* FALLTHROUGH */
+    case V_ASN1_T61STRING:       /* FALLTHROUGH */
+    case V_ASN1_VIDEOTEXSTRING:  /* FALLTHROUGH */
+    case V_ASN1_IA5STRING:       /* FALLTHROUGH */
+    case V_ASN1_GRAPHICSTRING:   /* FALLTHROUGH */
+    case V_ASN1_ISO64STRING:     /* FALLTHROUGH */
+    case V_ASN1_GENERALSTRING:   /* FALLTHROUGH */
+    case V_ASN1_UNIVERSALSTRING: /* FALLTHROUGH */
+    case V_ASN1_BMPSTRING:
+       ptr = obj_to_asn1str(value);
+       free_func = ASN1_STRING_free;
+       break;
+    case V_ASN1_OBJECT:
+       ptr = obj_to_asn1obj(value);
+       free_func = ASN1_OBJECT_free;
+       break;
+    case V_ASN1_UTCTIME:
+       ptr = obj_to_asn1utime(value);
+       free_func = ASN1_TIME_free;
+       break;
+    case V_ASN1_GENERALIZEDTIME:
+       ptr = obj_to_asn1gtime(value);
+       free_func = ASN1_TIME_free;
+       break;
+    case V_ASN1_SET:             /* FALLTHROUGH */
+    case V_ASN1_SEQUENCE:
+       ptr = obj_to_asn1derstr(obj);
+       free_func = ASN1_STRING_free;
+       break;
+    default:
+       ossl_raise(eASN1Error, "unsupported ASN.1 type");
+    }
+    if(!(ret = OPENSSL_malloc(sizeof(ASN1_TYPE)))){
+       if(free_func) free_func(ptr);
+       ossl_raise(eASN1Error, "ASN1_TYPE alloc failure");
+    }
+    memset(ret, 0, sizeof(ASN1_TYPE));
+    ASN1_TYPE_set(ret, tag, ptr);
+
+    return ret;
+}
+
+static int
+ossl_asn1_default_tag(VALUE obj)
+{
+    VALUE tmp_class, tag;
+
+    tmp_class = CLASS_OF(obj);
+    while (tmp_class) {
+       tag = rb_hash_lookup(class_tag_map, tmp_class);
+       if (tag != Qnil) {
+                   return NUM2INT(tag);
+       }
+       tmp_class = rb_class_superclass(tmp_class);
+    }
+    ossl_raise(eASN1Error, "universal tag for %"PRIsVALUE" not found",
+              RB_OBJ_CLASSNAME(obj));
+
+    return -1; /* dummy */
+}
+
+static int
+ossl_asn1_tag(VALUE obj)
+{
+    VALUE tag;
+
+    tag = ossl_asn1_get_tag(obj);
+    if(NIL_P(tag))
+       ossl_raise(eASN1Error, "tag number not specified");
+
+    return NUM2INT(tag);
+}
+
+static int
+ossl_asn1_is_explicit(VALUE obj)
+{
+    VALUE s;
+    int ret = -1;
+
+    s = ossl_asn1_get_tagging(obj);
+    if(NIL_P(s)) return 0;
+    else if(SYMBOL_P(s)){
+       if (SYM2ID(s) == sIMPLICIT)
+           ret = 0;
+       else if (SYM2ID(s) == sEXPLICIT)
+           ret = 1;
+    }
+    if(ret < 0){
+       ossl_raise(eASN1Error, "invalid tag default");
+    }
+
+    return ret;
+}
+
+static int
+ossl_asn1_tag_class(VALUE obj)
+{
+    VALUE s;
+    int ret = -1;
+
+    s = ossl_asn1_get_tag_class(obj);
+    if(NIL_P(s)) ret = V_ASN1_UNIVERSAL;
+    else if(SYMBOL_P(s)){
+       if (SYM2ID(s) == sUNIVERSAL)
+           ret = V_ASN1_UNIVERSAL;
+       else if (SYM2ID(s) == sAPPLICATION)
+           ret = V_ASN1_APPLICATION;
+       else if (SYM2ID(s) == sCONTEXT_SPECIFIC)
+           ret = V_ASN1_CONTEXT_SPECIFIC;
+       else if (SYM2ID(s) == sPRIVATE)
+           ret = V_ASN1_PRIVATE;
+    }
+    if(ret < 0){
+       ossl_raise(eASN1Error, "invalid tag class");
+    }
+
+    return ret;
+}
+
+static VALUE
+ossl_asn1_class2sym(int tc)
+{
+    if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
+       return ID2SYM(sPRIVATE);
+    else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
+       return ID2SYM(sCONTEXT_SPECIFIC);
+    else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
+       return ID2SYM(sAPPLICATION);
+    else
+       return ID2SYM(sUNIVERSAL);
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::ASN1::ASN1Data.new(value, tag, tag_class) => ASN1Data
+ *
+ * +value+: Please have a look at Constructive and Primitive to see how Ruby
+ * types are mapped to ASN.1 types and vice versa.
+ *
+ * +tag+: A +Number+ indicating the tag number.
+ *
+ * +tag_class+: A +Symbol+ indicating the tag class. Please cf. ASN1 for
+ * possible values.
+ *
+ * == Example
+ *   asn1_int = OpenSSL::ASN1Data.new(42, 2, :UNIVERSAL) # => Same as OpenSSL::ASN1::Integer.new(42)
+ *   tagged_int = OpenSSL::ASN1Data.new(42, 0, :CONTEXT_SPECIFIC) # implicitly 0-tagged INTEGER
+ */
+static VALUE
+ossl_asn1data_initialize(VALUE self, VALUE value, VALUE tag, VALUE tag_class)
+{
+    if(!SYMBOL_P(tag_class))
+       ossl_raise(eASN1Error, "invalid tag class");
+    if((SYM2ID(tag_class) == sUNIVERSAL) && NUM2INT(tag) > 31)
+       ossl_raise(eASN1Error, "tag number for Universal too large");
+    ossl_asn1_set_tag(self, tag);
+    ossl_asn1_set_value(self, value);
+    ossl_asn1_set_tag_class(self, tag_class);
+    ossl_asn1_set_infinite_length(self, Qfalse);
+
+    return self;
+}
+
+static VALUE
+join_der_i(VALUE i, VALUE str)
+{
+    i = ossl_to_der_if_possible(i);
+    StringValue(i);
+    rb_str_append(str, i);
+    return Qnil;
+}
+
+static VALUE
+join_der(VALUE enumerable)
+{
+    VALUE str = rb_str_new(0, 0);
+    rb_block_call(enumerable, rb_intern("each"), 0, 0, join_der_i, str);
+    return str;
+}
+
+/*
+ * call-seq:
+ *    asn1.to_der => DER-encoded String
+ *
+ * Encodes this ASN1Data into a DER-encoded String value. The result is
+ * DER-encoded except for the possibility of infinite length encodings.
+ * Infinite length encodings are not allowed in strict DER, so strictly
+ * speaking the result of such an encoding would be a BER-encoding.
+ */
+static VALUE
+ossl_asn1data_to_der(VALUE self)
+{
+    VALUE value, der, inf_length;
+    int tag, tag_class, is_cons = 0;
+    long length;
+    unsigned char *p;
+
+    value = ossl_asn1_get_value(self);
+    if(rb_obj_is_kind_of(value, rb_cArray)){
+       is_cons = 1;
+       value = join_der(value);
+    }
+    StringValue(value);
+
+    tag = ossl_asn1_tag(self);
+    tag_class = ossl_asn1_tag_class(self);
+    inf_length = ossl_asn1_get_infinite_length(self);
+    if (inf_length == Qtrue) {
+       is_cons = 2;
+    }
+    if((length = ossl_asn1_object_size(is_cons, RSTRING_LENINT(value), tag)) <= 0)
+       ossl_raise(eASN1Error, NULL);
+    der = rb_str_new(0, length);
+    p = (unsigned char *)RSTRING_PTR(der);
+    ossl_asn1_put_object(&p, is_cons, RSTRING_LENINT(value), tag, tag_class);
+    memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
+    p += RSTRING_LEN(value);
+    ossl_str_adjust(der, p);
+
+    return der;
+}
+
+static VALUE
+int_ossl_asn1_decode0_prim(unsigned char **pp, long length, int hlen, int tag,
+                          VALUE tc, long *num_read)
+{
+    VALUE value, asn1data;
+    unsigned char *p;
+    long flag = 0;
+
+    p = *pp;
+
+    if(tc == sUNIVERSAL && tag < ossl_asn1_info_size) {
+       switch(tag){
+       case V_ASN1_EOC:
+           value = decode_eoc(p, hlen+length);
+           break;
+       case V_ASN1_BOOLEAN:
+           value = decode_bool(p, hlen+length);
+           break;
+       case V_ASN1_INTEGER:
+           value = decode_int(p, hlen+length);
+           break;
+       case V_ASN1_BIT_STRING:
+           value = decode_bstr(p, hlen+length, &flag);
+           break;
+       case V_ASN1_NULL:
+           value = decode_null(p, hlen+length);
+           break;
+       case V_ASN1_ENUMERATED:
+           value = decode_enum(p, hlen+length);
+           break;
+       case V_ASN1_OBJECT:
+           value = decode_obj(p, hlen+length);
+           break;
+       case V_ASN1_UTCTIME:           /* FALLTHROUGH */
+       case V_ASN1_GENERALIZEDTIME:
+           value = decode_time(p, hlen+length);
+           break;
+       default:
+           /* use original value */
+           p += hlen;
+           value = rb_str_new((const char *)p, length);
+           break;
+       }
+    }
+    else {
+       p += hlen;
+       value = rb_str_new((const char *)p, length);
+    }
+
+    *pp += hlen + length;
+    *num_read = hlen + length;
+
+    if (tc == sUNIVERSAL && tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
+       VALUE klass = *ossl_asn1_info[tag].klass;
+       VALUE args[4];
+       args[0] = value;
+       args[1] = INT2NUM(tag);
+       args[2] = Qnil;
+       args[3] = ID2SYM(tc);
+       asn1data = rb_obj_alloc(klass);
+       ossl_asn1_initialize(4, args, asn1data);
+       if(tag == V_ASN1_BIT_STRING){
+           rb_ivar_set(asn1data, sivUNUSED_BITS, LONG2NUM(flag));
+       }
+    }
+    else {
+       asn1data = rb_obj_alloc(cASN1Data);
+       ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), ID2SYM(tc));
+    }
+
+    return asn1data;
+}
+
+static VALUE
+int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
+                          long *offset, int depth, int yield, int j,
+                          int tag, VALUE tc, long *num_read)
+{
+    VALUE value, asn1data, ary;
+    int infinite;
+    long off = *offset;
+
+    infinite = (j == 0x21);
+    ary = rb_ary_new();
+
+    while (length > 0 || infinite) {
+       long inner_read = 0;
+       value = ossl_asn1_decode0(pp, max_len, &off, depth + 1, yield, &inner_read);
+       *num_read += inner_read;
+       max_len -= inner_read;
+       rb_ary_push(ary, value);
+       if (length > 0)
+           length -= inner_read;
+
+       if (infinite &&
+           NUM2INT(ossl_asn1_get_tag(value)) == V_ASN1_EOC &&
+           SYM2ID(ossl_asn1_get_tag_class(value)) == sUNIVERSAL) {
+           break;
+       }
+    }
+
+    if (tc == sUNIVERSAL) {
+       VALUE args[4];
+       int not_sequence_or_set;
+
+       not_sequence_or_set = tag != V_ASN1_SEQUENCE && tag != V_ASN1_SET;
+
+       if (not_sequence_or_set) {
+           if (infinite) {
+               asn1data = rb_obj_alloc(cASN1Constructive);
+           }
+           else {
+               ossl_raise(eASN1Error, "invalid non-infinite tag");
+               return Qnil;
+           }
+       }
+       else {
+           VALUE klass = *ossl_asn1_info[tag].klass;
+           asn1data = rb_obj_alloc(klass);
+       }
+       args[0] = ary;
+       args[1] = INT2NUM(tag);
+       args[2] = Qnil;
+       args[3] = ID2SYM(tc);
+       ossl_asn1_initialize(4, args, asn1data);
+    }
+    else {
+       asn1data = rb_obj_alloc(cASN1Data);
+       ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), ID2SYM(tc));
+    }
+
+    if (infinite)
+       ossl_asn1_set_infinite_length(asn1data, Qtrue);
+    else
+       ossl_asn1_set_infinite_length(asn1data, Qfalse);
+
+    *offset = off;
+    return asn1data;
+}
+
+static VALUE
+ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
+                 int yield, long *num_read)
+{
+    unsigned char *start, *p;
+    const unsigned char *p0;
+    long len = 0, inner_read = 0, off = *offset;
+    int hlen, tag, tc, j;
+    VALUE asn1data, tag_class;
+
+    p = *pp;
+    start = p;
+    p0 = p;
+    j = ASN1_get_object(&p0, &len, &tag, &tc, length);
+    p = (unsigned char *)p0;
+    if(j & 0x80) ossl_raise(eASN1Error, NULL);
+    if(len > length) ossl_raise(eASN1Error, "value is too short");
+    if((tc & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
+       tag_class = sPRIVATE;
+    else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
+       tag_class = sCONTEXT_SPECIFIC;
+    else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
+       tag_class = sAPPLICATION;
+    else
+       tag_class = sUNIVERSAL;
+
+    hlen = p - start;
+
+    if(yield) {
+       VALUE arg = rb_ary_new();
+       rb_ary_push(arg, LONG2NUM(depth));
+       rb_ary_push(arg, LONG2NUM(*offset));
+       rb_ary_push(arg, LONG2NUM(hlen));
+       rb_ary_push(arg, LONG2NUM(len));
+       rb_ary_push(arg, (j & V_ASN1_CONSTRUCTED) ? Qtrue : Qfalse);
+       rb_ary_push(arg, ossl_asn1_class2sym(tc));
+       rb_ary_push(arg, INT2NUM(tag));
+       rb_yield(arg);
+    }
+
+    if(j & V_ASN1_CONSTRUCTED) {
+       *pp += hlen;
+       off += hlen;
+       asn1data = int_ossl_asn1_decode0_cons(pp, length, len, &off, depth, yield, j, tag, tag_class, &inner_read);
+       inner_read += hlen;
+    }
+    else {
+       if ((j & 0x01) && (len == 0)) ossl_raise(eASN1Error, "Infinite length for primitive value");
+       asn1data = int_ossl_asn1_decode0_prim(pp, len, hlen, tag, tag_class, &inner_read);
+       off += hlen + len;
+    }
+    if (num_read)
+       *num_read = inner_read;
+    if (len != 0 && inner_read != hlen + len) {
+       ossl_raise(eASN1Error,
+                  "Type mismatch. Bytes read: %ld Bytes available: %ld",
+                  inner_read, hlen + len);
+    }
+
+    *offset = off;
+    return asn1data;
+}
+
+static void
+int_ossl_decode_sanity_check(long len, long read, long offset)
+{
+    if (len != 0 && (read != len || offset != len)) {
+       ossl_raise(eASN1Error,
+                  "Type mismatch. Total bytes read: %ld Bytes available: %ld Offset: %ld",
+                  read, len, offset);
+    }
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::ASN1.traverse(asn1) -> nil
+ *
+ * If a block is given, it prints out each of the elements encountered.
+ * Block parameters are (in that order):
+ * * depth: The recursion depth, plus one with each constructed value being encountered (Number)
+ * * offset: Current byte offset (Number)
+ * * header length: Combined length in bytes of the Tag and Length headers. (Number)
+ * * length: The overall remaining length of the entire data (Number)
+ * * constructed: Whether this value is constructed or not (Boolean)
+ * * tag_class: Current tag class (Symbol)
+ * * tag: The current tag (Number)
+ *
+ * == Example
+ *   der = File.binread('asn1data.der')
+ *   OpenSSL::ASN1.traverse(der) do | depth, offset, header_len, length, constructed, tag_class, tag|
+ *     puts "Depth: #{depth} Offset: #{offset} Length: #{length}"
+ *     puts "Header length: #{header_len} Tag: #{tag} Tag class: #{tag_class} Constructed: #{constructed}"
+ *   end
+ */
+static VALUE
+ossl_asn1_traverse(VALUE self, VALUE obj)
+{
+    unsigned char *p;
+    volatile VALUE tmp;
+    long len, read = 0, offset = 0;
+
+    obj = ossl_to_der_if_possible(obj);
+    tmp = rb_str_new4(StringValue(obj));
+    p = (unsigned char *)RSTRING_PTR(tmp);
+    len = RSTRING_LEN(tmp);
+    ossl_asn1_decode0(&p, len, &offset, 0, 1, &read);
+    int_ossl_decode_sanity_check(len, read, offset);
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::ASN1.decode(der) -> ASN1Data
+ *
+ * Decodes a BER- or DER-encoded value and creates an ASN1Data instance. +der+
+ * may be a +String+ or any object that features a +#to_der+ method transforming
+ * it into a BER-/DER-encoded +String+.
+ *
+ * == Example
+ *   der = File.binread('asn1data')
+ *   asn1 = OpenSSL::ASN1.decode(der)
+ */
+static VALUE
+ossl_asn1_decode(VALUE self, VALUE obj)
+{
+    VALUE ret;
+    unsigned char *p;
+    volatile VALUE tmp;
+    long len, read = 0, offset = 0;
+
+    obj = ossl_to_der_if_possible(obj);
+    tmp = rb_str_new4(StringValue(obj));
+    p = (unsigned char *)RSTRING_PTR(tmp);
+    len = RSTRING_LEN(tmp);
+    ret = ossl_asn1_decode0(&p, len, &offset, 0, 0, &read);
+    int_ossl_decode_sanity_check(len, read, offset);
+    return ret;
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::ASN1.decode_all(der) -> Array of ASN1Data
+ *
+ * Similar to +decode+ with the difference that +decode+ expects one
+ * distinct value represented in +der+. +decode_all+ on the contrary
+ * decodes a sequence of sequential BER/DER values lined up in +der+
+ * and returns them as an array.
+ *
+ * == Example
+ *   ders = File.binread('asn1data_seq')
+ *   asn1_ary = OpenSSL::ASN1.decode_all(ders)
+ */
+static VALUE
+ossl_asn1_decode_all(VALUE self, VALUE obj)
+{
+    VALUE ary, val;
+    unsigned char *p;
+    long len, tmp_len = 0, read = 0, offset = 0;
+    volatile VALUE tmp;
+
+    obj = ossl_to_der_if_possible(obj);
+    tmp = rb_str_new4(StringValue(obj));
+    p = (unsigned char *)RSTRING_PTR(tmp);
+    len = RSTRING_LEN(tmp);
+    tmp_len = len;
+    ary = rb_ary_new();
+    while (tmp_len > 0) {
+       long tmp_read = 0;
+       val = ossl_asn1_decode0(&p, tmp_len, &offset, 0, 0, &tmp_read);
+       rb_ary_push(ary, val);
+       read += tmp_read;
+       tmp_len -= tmp_read;
+    }
+    int_ossl_decode_sanity_check(len, read, offset);
+    return ary;
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::ASN1::Primitive.new( value [, tag, tagging, tag_class ]) => Primitive
+ *
+ * +value+: is mandatory.
+ *
+ * +tag+: optional, may be specified for tagged values. If no +tag+ is
+ * specified, the UNIVERSAL tag corresponding to the Primitive sub-class
+ * is used by default.
+ *
+ * +tagging+: may be used as an encoding hint to encode a value either
+ * explicitly or implicitly, see ASN1 for possible values.
+ *
+ * +tag_class+: if +tag+ and +tagging+ are +nil+ then this is set to
+ * +:UNIVERSAL+ by default. If either +tag+ or +tagging+ are set then
+ * +:CONTEXT_SPECIFIC+ is used as the default. For possible values please
+ * cf. ASN1.
+ *
+ * == Example
+ *   int = OpenSSL::ASN1::Integer.new(42)
+ *   zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :IMPLICIT)
+ *   private_explicit_zero_tagged_int = OpenSSL::ASN1::Integer.new(42, 0, :EXPLICIT, :PRIVATE)
+ */
+static VALUE
+ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE value, tag, tagging, tag_class;
+
+    rb_scan_args(argc, argv, "13", &value, &tag, &tagging, &tag_class);
+    if(argc > 1){
+       if(NIL_P(tag))
+           ossl_raise(eASN1Error, "must specify tag number");
+       if(!NIL_P(tagging) && !SYMBOL_P(tagging))
+           ossl_raise(eASN1Error, "invalid tagging method");
+       if(NIL_P(tag_class)) {
+           if (NIL_P(tagging))
+               tag_class = ID2SYM(sUNIVERSAL);
+           else
+               tag_class = ID2SYM(sCONTEXT_SPECIFIC);
+       }
+       if(!SYMBOL_P(tag_class))
+           ossl_raise(eASN1Error, "invalid tag class");
+       if(SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31)
+           ossl_raise(eASN1Error, "tag number for Universal too large");
+    }
+    else{
+       tag = INT2NUM(ossl_asn1_default_tag(self));
+       tagging = Qnil;
+       tag_class = ID2SYM(sUNIVERSAL);
+    }
+    ossl_asn1_set_tag(self, tag);
+    ossl_asn1_set_value(self, value);
+    ossl_asn1_set_tagging(self, tagging);
+    ossl_asn1_set_tag_class(self, tag_class);
+    ossl_asn1_set_infinite_length(self, Qfalse);
+
+    return self;
+}
+
+static VALUE
+ossl_asn1eoc_initialize(VALUE self) {
+    VALUE tag, tagging, tag_class, value;
+    tag = INT2NUM(ossl_asn1_default_tag(self));
+    tagging = Qnil;
+    tag_class = ID2SYM(sUNIVERSAL);
+    value = rb_str_new("", 0);
+    ossl_asn1_set_tag(self, tag);
+    ossl_asn1_set_value(self, value);
+    ossl_asn1_set_tagging(self, tagging);
+    ossl_asn1_set_tag_class(self, tag_class);
+    ossl_asn1_set_infinite_length(self, Qfalse);
+    return self;
+}
+
+static int
+ossl_i2d_ASN1_TYPE(ASN1_TYPE *a, unsigned char **pp)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+    if(!a) return 0;
+    if(a->type == V_ASN1_BOOLEAN)
+        return i2d_ASN1_BOOLEAN(a->value.boolean, pp);
+#endif
+    return i2d_ASN1_TYPE(a, pp);
+}
+
+static void
+ossl_ASN1_TYPE_free(ASN1_TYPE *a)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+    if(!a) return;
+    if(a->type == V_ASN1_BOOLEAN){
+        OPENSSL_free(a);
+        return;
+    }
+#endif
+    ASN1_TYPE_free(a);
+}
+
+/*
+ * call-seq:
+ *    asn1.to_der => DER-encoded String
+ *
+ * See ASN1Data#to_der for details. *
+ */
+static VALUE
+ossl_asn1prim_to_der(VALUE self)
+{
+    ASN1_TYPE *asn1;
+    int tn, tc, explicit;
+    long len, reallen;
+    unsigned char *buf, *p;
+    VALUE str;
+
+    tn = NUM2INT(ossl_asn1_get_tag(self));
+    tc = ossl_asn1_tag_class(self);
+    explicit = ossl_asn1_is_explicit(self);
+    asn1 = ossl_asn1_get_asn1type(self);
+
+    len = ossl_asn1_object_size(1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn);
+    if(!(buf = OPENSSL_malloc(len))){
+       ossl_ASN1_TYPE_free(asn1);
+       ossl_raise(eASN1Error, "cannot alloc buffer");
+    }
+    p = buf;
+    if (tc == V_ASN1_UNIVERSAL) {
+        ossl_i2d_ASN1_TYPE(asn1, &p);
+    } else if (explicit) {
+        ossl_asn1_put_object(&p, 1, ossl_i2d_ASN1_TYPE(asn1, NULL), tn, tc);
+        ossl_i2d_ASN1_TYPE(asn1, &p);
+    } else {
+        ossl_i2d_ASN1_TYPE(asn1, &p);
+        *buf = tc | tn | (*buf & V_ASN1_CONSTRUCTED);
+    }
+    ossl_ASN1_TYPE_free(asn1);
+    reallen = p - buf;
+    assert(reallen <= len);
+    str = ossl_buf2str((char *)buf, rb_long2int(reallen)); /* buf will be free in ossl_buf2str */
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    asn1.to_der => DER-encoded String
+ *
+ * See ASN1Data#to_der for details.
+ */
+static VALUE
+ossl_asn1cons_to_der(VALUE self)
+{
+    int tag, tn, tc, explicit, constructed = 1;
+    int found_prim = 0, seq_len;
+    long length;
+    unsigned char *p;
+    VALUE value, str, inf_length;
+
+    tn = NUM2INT(ossl_asn1_get_tag(self));
+    tc = ossl_asn1_tag_class(self);
+    inf_length = ossl_asn1_get_infinite_length(self);
+    if (inf_length == Qtrue) {
+       VALUE ary, example;
+       constructed = 2;
+       if (CLASS_OF(self) == cASN1Sequence ||
+           CLASS_OF(self) == cASN1Set) {
+           tag = ossl_asn1_default_tag(self);
+       }
+       else { /* must be a constructive encoding of a primitive value */
+           ary = ossl_asn1_get_value(self);
+           if (!rb_obj_is_kind_of(ary, rb_cArray))
+               ossl_raise(eASN1Error, "Constructive value must be an Array");
+           /* Recursively descend until a primitive value is found.
+           The overall value of the entire constructed encoding
+           is of the type of the first primitive encoding to be
+           found. */
+           while (!found_prim){
+               example = rb_ary_entry(ary, 0);
+               if (rb_obj_is_kind_of(example, cASN1Primitive)){
+                   found_prim = 1;
+               }
+               else {
+                   /* example is another ASN1Constructive */
+                   if (!rb_obj_is_kind_of(example, cASN1Constructive)){
+                       ossl_raise(eASN1Error, "invalid constructed encoding");
+                       return Qnil; /* dummy */
+                   }
+                   ary = ossl_asn1_get_value(example);
+               }
+           }
+           tag = ossl_asn1_default_tag(example);
+       }
+    }
+    else {
+       if (CLASS_OF(self) == cASN1Constructive)
+           ossl_raise(eASN1Error, "Constructive shall only be used with infinite length");
+       tag = ossl_asn1_default_tag(self);
+    }
+    explicit = ossl_asn1_is_explicit(self);
+    value = join_der(ossl_asn1_get_value(self));
+
+    seq_len = ossl_asn1_object_size(constructed, RSTRING_LENINT(value), tag);
+    length = ossl_asn1_object_size(constructed, seq_len, tn);
+    str = rb_str_new(0, length);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(tc == V_ASN1_UNIVERSAL)
+       ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc);
+    else{
+       if(explicit){
+           ossl_asn1_put_object(&p, constructed, seq_len, tn, tc);
+           ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tag, V_ASN1_UNIVERSAL);
+       }
+       else{
+           ossl_asn1_put_object(&p, constructed, RSTRING_LENINT(value), tn, tc);
+       }
+    }
+    memcpy(p, RSTRING_PTR(value), RSTRING_LEN(value));
+    p += RSTRING_LEN(value);
+
+    /* In this case we need an additional EOC (one for the explicit part and
+     * one for the Constructive itself. The EOC for the Constructive is
+     * supplied by the user, but that for the "explicit wrapper" must be
+     * added here.
+     */
+    if (explicit && inf_length == Qtrue) {
+       ASN1_put_eoc(&p);
+    }
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    asn1_ary.each { |asn1| block } => asn1_ary
+ *
+ * Calls <i>block</i> once for each element in +self+, passing that element
+ * as parameter +asn1+. If no block is given, an enumerator is returned
+ * instead.
+ *
+ * == Example
+ *   asn1_ary.each do |asn1|
+ *     puts asn1
+ *   end
+ */
+static VALUE
+ossl_asn1cons_each(VALUE self)
+{
+    rb_ary_each(ossl_asn1_get_value(self));
+    return self;
+}
+
+static VALUE
+ossl_asn1obj_s_register(VALUE self, VALUE oid, VALUE sn, VALUE ln)
+{
+    StringValue(oid);
+    StringValue(sn);
+    StringValue(ln);
+
+    if(!OBJ_create(RSTRING_PTR(oid), RSTRING_PTR(sn), RSTRING_PTR(ln)))
+       ossl_raise(eASN1Error, NULL);
+
+    return Qtrue;
+}
+
+static VALUE
+ossl_asn1obj_get_sn(VALUE self)
+{
+    VALUE val, ret = Qnil;
+    int nid;
+
+    val = ossl_asn1_get_value(self);
+    if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef)
+       ret = rb_str_new2(OBJ_nid2sn(nid));
+
+    return ret;
+}
+
+static VALUE
+ossl_asn1obj_get_ln(VALUE self)
+{
+    VALUE val, ret = Qnil;
+    int nid;
+
+    val = ossl_asn1_get_value(self);
+    if ((nid = OBJ_txt2nid(StringValuePtr(val))) != NID_undef)
+       ret = rb_str_new2(OBJ_nid2ln(nid));
+
+    return ret;
+}
+
+static VALUE
+ossl_asn1obj_get_oid(VALUE self)
+{
+    VALUE val;
+    ASN1_OBJECT *a1obj;
+    char buf[128];
+
+    val = ossl_asn1_get_value(self);
+    a1obj = obj_to_asn1obj(val);
+    OBJ_obj2txt(buf, sizeof(buf), a1obj, 1);
+    ASN1_OBJECT_free(a1obj);
+
+    return rb_str_new2(buf);
+}
+
+#define OSSL_ASN1_IMPL_FACTORY_METHOD(klass) \
+static VALUE ossl_asn1_##klass(int argc, VALUE *argv, VALUE self)\
+{ return rb_funcall3(cASN1##klass, rb_intern("new"), argc, argv); }
+
+OSSL_ASN1_IMPL_FACTORY_METHOD(Boolean)
+OSSL_ASN1_IMPL_FACTORY_METHOD(Integer)
+OSSL_ASN1_IMPL_FACTORY_METHOD(Enumerated)
+OSSL_ASN1_IMPL_FACTORY_METHOD(BitString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(OctetString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(UTF8String)
+OSSL_ASN1_IMPL_FACTORY_METHOD(NumericString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(PrintableString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(T61String)
+OSSL_ASN1_IMPL_FACTORY_METHOD(VideotexString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(IA5String)
+OSSL_ASN1_IMPL_FACTORY_METHOD(GraphicString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(ISO64String)
+OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(UniversalString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(BMPString)
+OSSL_ASN1_IMPL_FACTORY_METHOD(Null)
+OSSL_ASN1_IMPL_FACTORY_METHOD(ObjectId)
+OSSL_ASN1_IMPL_FACTORY_METHOD(UTCTime)
+OSSL_ASN1_IMPL_FACTORY_METHOD(GeneralizedTime)
+OSSL_ASN1_IMPL_FACTORY_METHOD(Sequence)
+OSSL_ASN1_IMPL_FACTORY_METHOD(Set)
+OSSL_ASN1_IMPL_FACTORY_METHOD(EndOfContent)
+
+void
+Init_ossl_asn1()
+{
+    VALUE ary;
+    int i;
+
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    sUNIVERSAL = rb_intern("UNIVERSAL");
+    sCONTEXT_SPECIFIC = rb_intern("CONTEXT_SPECIFIC");
+    sAPPLICATION = rb_intern("APPLICATION");
+    sPRIVATE = rb_intern("PRIVATE");
+    sEXPLICIT = rb_intern("EXPLICIT");
+    sIMPLICIT = rb_intern("IMPLICIT");
+
+    sivVALUE = rb_intern("@value");
+    sivTAG = rb_intern("@tag");
+    sivTAGGING = rb_intern("@tagging");
+    sivTAG_CLASS = rb_intern("@tag_class");
+    sivINFINITE_LENGTH = rb_intern("@infinite_length");
+    sivUNUSED_BITS = rb_intern("@unused_bits");
+
+    /*
+     * Document-module: OpenSSL::ASN1
+     *
+     * Abstract Syntax Notation One (or ASN.1) is a notation syntax to
+     * describe data structures and is defined in ITU-T X.680. ASN.1 itself
+     * does not mandate any encoding or parsing rules, but usually ASN.1 data
+     * structures are encoded using the Distinguished Encoding Rules (DER) or
+     * less often the Basic Encoding Rules (BER) described in ITU-T X.690. DER
+     * and BER encodings are binary Tag-Length-Value (TLV) encodings that are
+     * quite concise compared to other popular data description formats such
+     * as XML, JSON etc.
+     * ASN.1 data structures are very common in cryptographic applications,
+     * e.g. X.509 public key certificates or certificate revocation lists
+     * (CRLs) are all defined in ASN.1 and DER-encoded. ASN.1, DER and BER are
+     * the building blocks of applied cryptography.
+     * The ASN1 module provides the necessary classes that allow generation
+     * of ASN.1 data structures and the methods to encode them using a DER
+     * encoding. The decode method allows parsing arbitrary BER-/DER-encoded
+     * data to a Ruby object that can then be modified and re-encoded at will.
+     *
+     * == ASN.1 class hierarchy
+     *
+     * The base class representing ASN.1 structures is ASN1Data. ASN1Data offers
+     * attributes to read and set the +tag+, the +tag_class+ and finally the
+     * +value+ of a particular ASN.1 item. Upon parsing, any tagged values
+     * (implicit or explicit) will be represented by ASN1Data instances because
+     * their "real type" can only be determined using out-of-band information
+     * from the ASN.1 type declaration. Since this information is normally
+     * known when encoding a type, all sub-classes of ASN1Data offer an
+     * additional attribute +tagging+ that allows to encode a value implicitly
+     * (+:IMPLICIT+) or explicitly (+:EXPLICIT+).
+     *
+     * === Constructive
+     *
+     * Constructive is, as its name implies, the base class for all
+     * constructed encodings, i.e. those that consist of several values,
+     * opposed to "primitive" encodings with just one single value.
+     * Primitive values that are encoded with "infinite length" are typically
+     * constructed (their values come in multiple chunks) and are therefore
+     * represented by instances of Constructive. The value of an Constructive
+     * is always an Array.
+     *
+     * ==== ASN1::Set and ASN1::Sequence
+     *
+     * The most common constructive encodings are SETs and SEQUENCEs, which is
+     * why there are two sub-classes of Constructive representing each of
+     * them.
+     *
+     * === Primitive
+     *
+     * This is the super class of all primitive values. Primitive
+     * itself is not used when parsing ASN.1 data, all values are either
+     * instances of a corresponding sub-class of Primitive or they are
+     * instances of ASN1Data if the value was tagged implicitly or explicitly.
+     * Please cf. Primitive documentation for details on sub-classes and
+     * their respective mappings of ASN.1 data types to Ruby objects.
+     *
+     * == Possible values for +tagging+
+     *
+     * When constructing an ASN1Data object the ASN.1 type definition may
+     * require certain elements to be either implicitly or explicitly tagged.
+     * This can be achieved by setting the +tagging+ attribute manually for
+     * sub-classes of ASN1Data. Use the symbol +:IMPLICIT+ for implicit
+     * tagging and +:EXPLICIT+ if the element requires explicit tagging.
+     *
+     * == Possible values for +tag_class+
+     *
+     * It is possible to create arbitrary ASN1Data objects that also support
+     * a PRIVATE or APPLICATION tag class. Possible values for the +tag_class+
+     * attribute are:
+     * * +:UNIVERSAL+ (the default for untagged values)
+     * * +:CONTEXT_SPECIFIC+ (the default for tagged values)
+     * * +:APPLICATION+
+     * * +:PRIVATE+
+     *
+     * == Tag constants
+     *
+     * There is a constant defined for each universal tag:
+     * * OpenSSL::ASN1::EOC (0)
+     * * OpenSSL::ASN1::BOOLEAN (1)
+     * * OpenSSL::ASN1::INTEGER (2)
+     * * OpenSSL::ASN1::BIT_STRING (3)
+     * * OpenSSL::ASN1::OCTET_STRING (4)
+     * * OpenSSL::ASN1::NULL (5)
+     * * OpenSSL::ASN1::OBJECT (6)
+     * * OpenSSL::ASN1::ENUMERATED (10)
+     * * OpenSSL::ASN1::UTF8STRING (12)
+     * * OpenSSL::ASN1::SEQUENCE (16)
+     * * OpenSSL::ASN1::SET (17)
+     * * OpenSSL::ASN1::NUMERICSTRING (18)
+     * * OpenSSL::ASN1::PRINTABLESTRING (19)
+     * * OpenSSL::ASN1::T61STRING (20)
+     * * OpenSSL::ASN1::VIDEOTEXSTRING (21)
+     * * OpenSSL::ASN1::IA5STRING (22)
+     * * OpenSSL::ASN1::UTCTIME (23)
+     * * OpenSSL::ASN1::GENERALIZEDTIME (24)
+     * * OpenSSL::ASN1::GRAPHICSTRING (25)
+     * * OpenSSL::ASN1::ISO64STRING (26)
+     * * OpenSSL::ASN1::GENERALSTRING (27)
+     * * OpenSSL::ASN1::UNIVERSALSTRING (28)
+     * * OpenSSL::ASN1::BMPSTRING (30)
+     *
+     * == UNIVERSAL_TAG_NAME constant
+     *
+     * An Array that stores the name of a given tag number. These names are
+     * the same as the name of the tag constant that is additionally defined,
+     * e.g. UNIVERSAL_TAG_NAME[2] = "INTEGER" and OpenSSL::ASN1::INTEGER = 2.
+     *
+     * == Example usage
+     *
+     * === Decoding and viewing a DER-encoded file
+     *   require 'openssl'
+     *   require 'pp'
+     *   der = File.binread('data.der')
+     *   asn1 = OpenSSL::ASN1.decode(der)
+     *   pp der
+     *
+     * === Creating an ASN.1 structure and DER-encoding it
+     *   require 'openssl'
+     *   version = OpenSSL::ASN1::Integer.new(1)
+     *   # Explicitly 0-tagged implies context-specific tag class
+     *   serial = OpenSSL::ASN1::Integer.new(12345, 0, :EXPLICIT, :CONTEXT_SPECIFIC)
+     *   name = OpenSSL::ASN1::PrintableString.new('Data 1')
+     *   sequence = OpenSSL::ASN1::Sequence.new( [ version, serial, name ] )
+     *   der = sequence.to_der
+     */
+    mASN1 = rb_define_module_under(mOSSL, "ASN1");
+
+    /* Document-class: OpenSSL::ASN1::ASN1Error
+     *
+     * Generic error class for all errors raised in ASN1 and any of the
+     * classes defined in it.
+     */
+    eASN1Error = rb_define_class_under(mASN1, "ASN1Error", eOSSLError);
+    rb_define_module_function(mASN1, "traverse", ossl_asn1_traverse, 1);
+    rb_define_module_function(mASN1, "decode", ossl_asn1_decode, 1);
+    rb_define_module_function(mASN1, "decode_all", ossl_asn1_decode_all, 1);
+    ary = rb_ary_new();
+
+    /*
+     * Array storing tag names at the tag's index.
+     */
+    rb_define_const(mASN1, "UNIVERSAL_TAG_NAME", ary);
+    for(i = 0; i < ossl_asn1_info_size; i++){
+       if(ossl_asn1_info[i].name[0] == '[') continue;
+       rb_define_const(mASN1, ossl_asn1_info[i].name, INT2NUM(i));
+       rb_ary_store(ary, i, rb_str_new2(ossl_asn1_info[i].name));
+    }
+
+    /* Document-class: OpenSSL::ASN1::ASN1Data
+     *
+     * The top-level class representing any ASN.1 object. When parsed by
+     * ASN1.decode, tagged values are always represented by an instance
+     * of ASN1Data.
+     *
+     * == The role of ASN1Data for parsing tagged values
+     *
+     * When encoding an ASN.1 type it is inherently clear what original
+     * type (e.g. INTEGER, OCTET STRING etc.) this value has, regardless
+     * of its tagging.
+     * But opposed to the time an ASN.1 type is to be encoded, when parsing
+     * them it is not possible to deduce the "real type" of tagged
+     * values. This is why tagged values are generally parsed into ASN1Data
+     * instances, but with a different outcome for implicit and explicit
+     * tagging.
+     *
+     * === Example of a parsed implicitly tagged value
+     *
+     * An implicitly 1-tagged INTEGER value will be parsed as an
+     * ASN1Data with
+     * * +tag+ equal to 1
+     * * +tag_class+ equal to +:CONTEXT_SPECIFIC+
+     * * +value+ equal to a +String+ that carries the raw encoding
+     *   of the INTEGER.
+     * This implies that a subsequent decoding step is required to
+     * completely decode implicitly tagged values.
+     *
+     * === Example of a parsed explicitly tagged value
+     *
+     * An explicitly 1-tagged INTEGER value will be parsed as an
+     * ASN1Data with
+     * * +tag+ equal to 1
+     * * +tag_class+ equal to +:CONTEXT_SPECIFIC+
+     * * +value+ equal to an +Array+ with one single element, an
+     *   instance of OpenSSL::ASN1::Integer, i.e. the inner element
+     *   is the non-tagged primitive value, and the tagging is represented
+     *   in the outer ASN1Data
+     *
+     * == Example - Decoding an implicitly tagged INTEGER
+     *   int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT) # implicit 0-tagged
+     *   seq = OpenSSL::ASN1::Sequence.new( [int] )
+     *   der = seq.to_der
+     *   asn1 = OpenSSL::ASN1.decode(der)
+     *   # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0
+     *   #              @infinite_length=false,
+     *   #              @tag=16,
+     *   #              @tag_class=:UNIVERSAL,
+     *   #              @tagging=nil,
+     *   #              @value=
+     *   #                [#<OpenSSL::ASN1::ASN1Data:0x87326f4
+     *   #                   @infinite_length=false,
+     *   #                   @tag=0,
+     *   #                   @tag_class=:CONTEXT_SPECIFIC,
+     *   #                   @value="\x01">]>
+     *   raw_int = asn1.value[0]
+     *   # manually rewrite tag and tag class to make it an UNIVERSAL value
+     *   raw_int.tag = OpenSSL::ASN1::INTEGER
+     *   raw_int.tag_class = :UNIVERSAL
+     *   int2 = OpenSSL::ASN1.decode(raw_int)
+     *   puts int2.value # => 1
+     *
+     * == Example - Decoding an explicitly tagged INTEGER
+     *   int = OpenSSL::ASN1::Integer.new(1, 0, :EXPLICIT) # explicit 0-tagged
+     *   seq = OpenSSL::ASN1::Sequence.new( [int] )
+     *   der = seq.to_der
+     *   asn1 = OpenSSL::ASN1.decode(der)
+     *   # pp asn1 => #<OpenSSL::ASN1::Sequence:0x87326e0
+     *   #              @infinite_length=false,
+     *   #              @tag=16,
+     *   #              @tag_class=:UNIVERSAL,
+     *   #              @tagging=nil,
+     *   #              @value=
+     *   #                [#<OpenSSL::ASN1::ASN1Data:0x87326f4
+     *   #                   @infinite_length=false,
+     *   #                   @tag=0,
+     *   #                   @tag_class=:CONTEXT_SPECIFIC,
+     *   #                   @value=
+     *   #                     [#<OpenSSL::ASN1::Integer:0x85bf308
+     *   #                        @infinite_length=false,
+     *   #                        @tag=2,
+     *   #                        @tag_class=:UNIVERSAL
+     *   #                        @tagging=nil,
+     *   #                        @value=1>]>]>
+     *   int2 = asn1.value[0].value[0]
+     *   puts int2.value # => 1
+     */
+    cASN1Data = rb_define_class_under(mASN1, "ASN1Data", rb_cObject);
+    /*
+     * Carries the value of a ASN.1 type.
+     * Please confer Constructive and Primitive for the mappings between
+     * ASN.1 data types and Ruby classes.
+     */
+    rb_attr(cASN1Data, rb_intern("value"), 1, 1, 0);
+    /*
+     * A +Number+ representing the tag number of this ASN1Data. Never +nil+.
+     */
+    rb_attr(cASN1Data, rb_intern("tag"), 1, 1, 0);
+    /*
+     * A +Symbol+ representing the tag class of this ASN1Data. Never +nil+.
+     * See ASN1Data for possible values.
+     */
+    rb_attr(cASN1Data, rb_intern("tag_class"), 1, 1, 0);
+    /*
+     * Never +nil+. A +Boolean+ indicating whether the encoding was infinite
+     * length (in the case of parsing) or whether an infinite length encoding
+     * shall be used (in the encoding case).
+     * In DER, every value has a finite length associated with it. But in
+     * scenarios where large amounts of data need to be transferred it
+     * might be desirable to have some kind of streaming support available.
+     * For example, huge OCTET STRINGs are preferably sent in smaller-sized
+     * chunks, each at a time.
+     * This is possible in BER by setting the length bytes of an encoding
+     * to zero and by this indicating that the following value will be
+     * sent in chunks. Infinite length encodings are always constructed.
+     * The end of such a stream of chunks is indicated by sending a EOC
+     * (End of Content) tag. SETs and SEQUENCEs may use an infinite length
+     * encoding, but also primitive types such as e.g. OCTET STRINGS or
+     * BIT STRINGS may leverage this functionality (cf. ITU-T X.690).
+     */
+    rb_attr(cASN1Data, rb_intern("infinite_length"), 1, 1, 0);
+    rb_define_method(cASN1Data, "initialize", ossl_asn1data_initialize, 3);
+    rb_define_method(cASN1Data, "to_der", ossl_asn1data_to_der, 0);
+
+    /* Document-class: OpenSSL::ASN1::Primitive
+     *
+     * The parent class for all primitive encodings. Attributes are the same as
+     * for ASN1Data, with the addition of +tagging+.
+     * Primitive values can never be infinite length encodings, thus it is not
+     * possible to set the +infinite_length+ attribute for Primitive and its
+     * sub-classes.
+     *
+     * == Primitive sub-classes and their mapping to Ruby classes
+     * * OpenSSL::ASN1::EndOfContent    <=> +value+ is always +nil+
+     * * OpenSSL::ASN1::Boolean         <=> +value+ is a +Boolean+
+     * * OpenSSL::ASN1::Integer         <=> +value+ is a +Number+
+     * * OpenSSL::ASN1::BitString       <=> +value+ is a +String+
+     * * OpenSSL::ASN1::OctetString     <=> +value+ is a +String+
+     * * OpenSSL::ASN1::Null            <=> +value+ is always +nil+
+     * * OpenSSL::ASN1::Object          <=> +value+ is a +String+
+     * * OpenSSL::ASN1::Enumerated      <=> +value+ is a +Number+
+     * * OpenSSL::ASN1::UTF8String      <=> +value+ is a +String+
+     * * OpenSSL::ASN1::NumericString   <=> +value+ is a +String+
+     * * OpenSSL::ASN1::PrintableString <=> +value+ is a +String+
+     * * OpenSSL::ASN1::T61String       <=> +value+ is a +String+
+     * * OpenSSL::ASN1::VideotexString  <=> +value+ is a +String+
+     * * OpenSSL::ASN1::IA5String       <=> +value+ is a +String+
+     * * OpenSSL::ASN1::UTCTime         <=> +value+ is a +Time+
+     * * OpenSSL::ASN1::GeneralizedTime <=> +value+ is a +Time+
+     * * OpenSSL::ASN1::GraphicString   <=> +value+ is a +String+
+     * * OpenSSL::ASN1::ISO64String     <=> +value+ is a +String+
+     * * OpenSSL::ASN1::GeneralString   <=> +value+ is a +String+
+     * * OpenSSL::ASN1::UniversalString <=> +value+ is a +String+
+     * * OpenSSL::ASN1::BMPString       <=> +value+ is a +String+
+     *
+     * == OpenSSL::ASN1::BitString
+     *
+     * === Additional attributes
+     * +unused_bits+: if the underlying BIT STRING's
+     * length is a multiple of 8 then +unused_bits+ is 0. Otherwise
+     * +unused_bits+ indicates the number of bits that are to be ignored in
+     * the final octet of the +BitString+'s +value+.
+     *
+     * == OpenSSL::ASN1::ObjectId
+     *
+     * === Additional attributes
+     * * +sn+: the short name as defined in <openssl/objects.h>.
+     * * +ln+: the long name as defined in <openssl/objects.h>.
+     * * +oid+: the object identifier as a +String+, e.g. "1.2.3.4.5"
+     * * +short_name+: alias for +sn+.
+     * * +long_name+: alias for +ln+.
+     *
+     * == Examples
+     * With the Exception of OpenSSL::ASN1::EndOfContent, each Primitive class
+     * constructor takes at least one parameter, the +value+.
+     *
+     * === Creating EndOfContent
+     *   eoc = OpenSSL::ASN1::EndOfContent.new
+     *
+     * === Creating any other Primitive
+     *   prim = <class>.new(value) # <class> being one of the sub-classes except EndOfContent
+     *   prim_zero_tagged_implicit = <class>.new(value, 0, :IMPLICIT)
+     *   prim_zero_tagged_explicit = <class>.new(value, 0, :EXPLICIT)
+     */
+    cASN1Primitive = rb_define_class_under(mASN1, "Primitive", cASN1Data);
+    /*
+     * May be used as a hint for encoding a value either implicitly or
+     * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+     * +tagging+ is not set when a ASN.1 structure is parsed using
+     * OpenSSL::ASN1.decode.
+     */
+    rb_attr(cASN1Primitive, rb_intern("tagging"), 1, 1, Qtrue);
+    rb_undef_method(cASN1Primitive, "infinite_length=");
+    rb_define_method(cASN1Primitive, "initialize", ossl_asn1_initialize, -1);
+    rb_define_method(cASN1Primitive, "to_der", ossl_asn1prim_to_der, 0);
+
+    /* Document-class: OpenSSL::ASN1::Constructive
+     *
+     * The parent class for all constructed encodings. The +value+ attribute
+     * of a Constructive is always an +Array+. Attributes are the same as
+     * for ASN1Data, with the addition of +tagging+.
+     *
+     * == SET and SEQUENCE
+     *
+     * Most constructed encodings come in the form of a SET or a SEQUENCE.
+     * These encodings are represented by one of the two sub-classes of
+     * Constructive:
+     * * OpenSSL::ASN1::Set
+     * * OpenSSL::ASN1::Sequence
+     * Please note that tagged sequences and sets are still parsed as
+     * instances of ASN1Data. Find further details on tagged values
+     * there.
+     *
+     * === Example - constructing a SEQUENCE
+     *   int = OpenSSL::ASN1::Integer.new(1)
+     *   str = OpenSSL::ASN1::PrintableString.new('abc')
+     *   sequence = OpenSSL::ASN1::Sequence.new( [ int, str ] )
+     *
+     * === Example - constructing a SET
+     *   int = OpenSSL::ASN1::Integer.new(1)
+     *   str = OpenSSL::ASN1::PrintableString.new('abc')
+     *   set = OpenSSL::ASN1::Set.new( [ int, str ] )
+     *
+     * == Infinite length primitive values
+     *
+     * The only case where Constructive is used directly is for infinite
+     * length encodings of primitive values. These encodings are always
+     * constructed, with the contents of the +value+ +Array+ being either
+     * UNIVERSAL non-infinite length partial encodings of the actual value
+     * or again constructive encodings with infinite length (i.e. infinite
+     * length primitive encodings may be constructed recursively with another
+     * infinite length value within an already infinite length value). Each
+     * partial encoding must be of the same UNIVERSAL type as the overall
+     * encoding. The value of the overall encoding consists of the
+     * concatenation of each partial encoding taken in sequence. The +value+
+     * array of the outer infinite length value must end with a
+     * OpenSSL::ASN1::EndOfContent instance.
+     *
+     * Please note that it is not possible to encode Constructive without
+     * the +infinite_length+ attribute being set to +true+, use
+     * OpenSSL::ASN1::Sequence or OpenSSL::ASN1::Set in these cases instead.
+     *
+     * === Example - Infinite length OCTET STRING
+     *   partial1 = OpenSSL::ASN1::OctetString.new("\x01")
+     *   partial2 = OpenSSL::ASN1::OctetString.new("\x02")
+     *   inf_octets = OpenSSL::ASN1::Constructive.new( [ partial1,
+     *                                                   partial2,
+     *                                                   OpenSSL::ASN1::EndOfContent.new ],
+     *                                                 OpenSSL::ASN1::OCTET_STRING,
+     *                                                 nil,
+     *                                                 :UNIVERSAL )
+     *   # The real value of inf_octets is "\x01\x02", i.e. the concatenation
+     *   # of partial1 and partial2
+     *   inf_octets.infinite_length = true
+     *   der = inf_octets.to_der
+     *   asn1 = OpenSSL::ASN1.decode(der)
+     *   puts asn1.infinite_length # => true
+     */
+    cASN1Constructive = rb_define_class_under(mASN1,"Constructive", cASN1Data);
+    rb_include_module(cASN1Constructive, rb_mEnumerable);
+    /*
+     * May be used as a hint for encoding a value either implicitly or
+     * explicitly by setting it either to +:IMPLICIT+ or to +:EXPLICIT+.
+     * +tagging+ is not set when a ASN.1 structure is parsed using
+     * OpenSSL::ASN1.decode.
+     */
+    rb_attr(cASN1Constructive, rb_intern("tagging"), 1, 1, Qtrue);
+    rb_define_method(cASN1Constructive, "initialize", ossl_asn1_initialize, -1);
+    rb_define_method(cASN1Constructive, "to_der", ossl_asn1cons_to_der, 0);
+    rb_define_method(cASN1Constructive, "each", ossl_asn1cons_each, 0);
+
+#define OSSL_ASN1_DEFINE_CLASS(name, super) \
+do{\
+    cASN1##name = rb_define_class_under(mASN1, #name, cASN1##super);\
+    rb_define_module_function(mASN1, #name, ossl_asn1_##name, -1);\
+}while(0)
+
+    OSSL_ASN1_DEFINE_CLASS(Boolean, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(Integer, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(Enumerated, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(BitString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(OctetString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(UTF8String, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(NumericString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(PrintableString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(T61String, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(VideotexString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(IA5String, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(GraphicString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(ISO64String, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(GeneralString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(UniversalString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(BMPString, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(Null, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(ObjectId, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(UTCTime, Primitive);
+    OSSL_ASN1_DEFINE_CLASS(GeneralizedTime, Primitive);
+
+    OSSL_ASN1_DEFINE_CLASS(Sequence, Constructive);
+    OSSL_ASN1_DEFINE_CLASS(Set, Constructive);
+
+    OSSL_ASN1_DEFINE_CLASS(EndOfContent, Data);
+
+    rb_define_singleton_method(cASN1ObjectId, "register", ossl_asn1obj_s_register, 3);
+    rb_define_method(cASN1ObjectId, "sn", ossl_asn1obj_get_sn, 0);
+    rb_define_method(cASN1ObjectId, "ln", ossl_asn1obj_get_ln, 0);
+    rb_define_method(cASN1ObjectId, "oid", ossl_asn1obj_get_oid, 0);
+    rb_define_alias(cASN1ObjectId, "short_name", "sn");
+    rb_define_alias(cASN1ObjectId, "long_name", "ln");
+    rb_attr(cASN1BitString, rb_intern("unused_bits"), 1, 1, 0);
+
+    rb_define_method(cASN1EndOfContent, "initialize", ossl_asn1eoc_initialize, 0);
+
+    class_tag_map = rb_hash_new();
+    rb_hash_aset(class_tag_map, cASN1EndOfContent, INT2NUM(V_ASN1_EOC));
+    rb_hash_aset(class_tag_map, cASN1Boolean, INT2NUM(V_ASN1_BOOLEAN));
+    rb_hash_aset(class_tag_map, cASN1Integer, INT2NUM(V_ASN1_INTEGER));
+    rb_hash_aset(class_tag_map, cASN1BitString, INT2NUM(V_ASN1_BIT_STRING));
+    rb_hash_aset(class_tag_map, cASN1OctetString, INT2NUM(V_ASN1_OCTET_STRING));
+    rb_hash_aset(class_tag_map, cASN1Null, INT2NUM(V_ASN1_NULL));
+    rb_hash_aset(class_tag_map, cASN1ObjectId, INT2NUM(V_ASN1_OBJECT));
+    rb_hash_aset(class_tag_map, cASN1Enumerated, INT2NUM(V_ASN1_ENUMERATED));
+    rb_hash_aset(class_tag_map, cASN1UTF8String, INT2NUM(V_ASN1_UTF8STRING));
+    rb_hash_aset(class_tag_map, cASN1Sequence, INT2NUM(V_ASN1_SEQUENCE));
+    rb_hash_aset(class_tag_map, cASN1Set, INT2NUM(V_ASN1_SET));
+    rb_hash_aset(class_tag_map, cASN1NumericString, INT2NUM(V_ASN1_NUMERICSTRING));
+    rb_hash_aset(class_tag_map, cASN1PrintableString, INT2NUM(V_ASN1_PRINTABLESTRING));
+    rb_hash_aset(class_tag_map, cASN1T61String, INT2NUM(V_ASN1_T61STRING));
+    rb_hash_aset(class_tag_map, cASN1VideotexString, INT2NUM(V_ASN1_VIDEOTEXSTRING));
+    rb_hash_aset(class_tag_map, cASN1IA5String, INT2NUM(V_ASN1_IA5STRING));
+    rb_hash_aset(class_tag_map, cASN1UTCTime, INT2NUM(V_ASN1_UTCTIME));
+    rb_hash_aset(class_tag_map, cASN1GeneralizedTime, INT2NUM(V_ASN1_GENERALIZEDTIME));
+    rb_hash_aset(class_tag_map, cASN1GraphicString, INT2NUM(V_ASN1_GRAPHICSTRING));
+    rb_hash_aset(class_tag_map, cASN1ISO64String, INT2NUM(V_ASN1_ISO64STRING));
+    rb_hash_aset(class_tag_map, cASN1GeneralString, INT2NUM(V_ASN1_GENERALSTRING));
+    rb_hash_aset(class_tag_map, cASN1UniversalString, INT2NUM(V_ASN1_UNIVERSALSTRING));
+    rb_hash_aset(class_tag_map, cASN1BMPString, INT2NUM(V_ASN1_BMPSTRING));
+    rb_global_variable(&class_tag_map);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_asn1.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_asn1.h
new file mode 100644 (file)
index 0000000..718f43f
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' team members
+ * Copyright (C) 2003
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_ASN1_H_)
+#define _OSSL_ASN1_H_
+
+/*
+ * ASN1_DATE conversions
+ */
+VALUE asn1time_to_time(ASN1_TIME *);
+time_t time_to_time_t(VALUE);
+
+/*
+ * ASN1_STRING conversions
+ */
+VALUE asn1str_to_str(ASN1_STRING *);
+
+/*
+ * ASN1_INTEGER conversions
+ */
+VALUE asn1integer_to_num(ASN1_INTEGER *);
+ASN1_INTEGER *num_to_asn1integer(VALUE, ASN1_INTEGER *);
+
+/*
+ * ASN1 module
+ */
+extern VALUE mASN1;
+extern VALUE eASN1Error;
+
+extern VALUE cASN1Data;
+extern VALUE cASN1Primitive;
+extern VALUE cASN1Constructive;
+
+extern VALUE cASN1Boolean;                           /* BOOLEAN           */
+extern VALUE cASN1Integer, cASN1Enumerated;          /* INTEGER           */
+extern VALUE cASN1BitString;                         /* BIT STRING        */
+extern VALUE cASN1OctetString, cASN1UTF8String;      /* STRINGs           */
+extern VALUE cASN1NumericString, cASN1PrintableString;
+extern VALUE cASN1T61String, cASN1VideotexString;
+extern VALUE cASN1IA5String, cASN1GraphicString;
+extern VALUE cASN1ISO64String, cASN1GeneralString;
+extern VALUE cASN1UniversalString, cASN1BMPString;
+extern VALUE cASN1Null;                              /* NULL              */
+extern VALUE cASN1ObjectId;                          /* OBJECT IDENTIFIER */
+extern VALUE cASN1UTCTime, cASN1GeneralizedTime;     /* TIME              */
+extern VALUE cASN1Sequence, cASN1Set;                /* CONSTRUCTIVE      */
+
+ASN1_TYPE *ossl_asn1_get_asn1type(VALUE);
+
+void Init_ossl_asn1(void);
+
+#endif
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bio.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bio.c
new file mode 100644 (file)
index 0000000..ed7c0a7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' team members
+ * Copyright (C) 2003
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+BIO *
+ossl_obj2bio(VALUE obj)
+{
+    BIO *bio;
+
+    if (TYPE(obj) == T_FILE) {
+       rb_io_t *fptr;
+       FILE *fp;
+       int fd;
+
+       GetOpenFile(obj, fptr);
+       rb_io_check_readable(fptr);
+       if ((fd = dup(FPTR_TO_FD(fptr))) < 0){
+           rb_sys_fail(0);
+       }
+        rb_update_max_fd(fd);
+       if (!(fp = fdopen(fd, "r"))){
+           close(fd);
+           rb_sys_fail(0);
+       }
+       if (!(bio = BIO_new_fp(fp, BIO_CLOSE))){
+           fclose(fp);
+           ossl_raise(eOSSLError, NULL);
+       }
+    }
+    else {
+       StringValue(obj);
+       bio = BIO_new_mem_buf(RSTRING_PTR(obj), RSTRING_LENINT(obj));
+       if (!bio) ossl_raise(eOSSLError, NULL);
+    }
+
+    return bio;
+}
+
+BIO *
+ossl_protect_obj2bio(VALUE obj, int *status)
+{
+     BIO *ret = NULL;
+     ret = (BIO*)rb_protect((VALUE(*)_((VALUE)))ossl_obj2bio, obj, status);
+     return ret;
+}
+
+VALUE
+ossl_membio2str0(BIO *bio)
+{
+    VALUE ret;
+    BUF_MEM *buf;
+
+    BIO_get_mem_ptr(bio, &buf);
+    ret = rb_str_new(buf->data, buf->length);
+
+    return ret;
+}
+
+VALUE
+ossl_protect_membio2str(BIO *bio, int *status)
+{
+    return rb_protect((VALUE(*)_((VALUE)))ossl_membio2str0, (VALUE)bio, status);
+}
+
+VALUE
+ossl_membio2str(BIO *bio)
+{
+    VALUE ret;
+    int status = 0;
+
+    ret = ossl_protect_membio2str(bio, &status);
+    BIO_free(bio);
+    if(status) rb_jump_tag(status);
+
+    return ret;
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bio.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bio.h
new file mode 100644 (file)
index 0000000..2d8f675
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' team members
+ * Copyright (C) 2003
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_BIO_H_)
+#define _OSSL_BIO_H_
+
+BIO *ossl_obj2bio(VALUE);
+BIO *ossl_protect_obj2bio(VALUE,int*);
+VALUE ossl_membio2str0(BIO*);
+VALUE ossl_membio2str(BIO*);
+VALUE ossl_protect_membio2str(BIO*,int*);
+
+#endif
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bn.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bn.c
new file mode 100644 (file)
index 0000000..5d690af
--- /dev/null
@@ -0,0 +1,854 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Technorama team <oss-ruby@technorama.net>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+/* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
+#include "ossl.h"
+
+#define WrapBN(klass, obj, bn) do { \
+  if (!(bn)) { \
+    ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+  } \
+  (obj) = Data_Wrap_Struct((klass), 0, BN_clear_free, (bn)); \
+} while (0)
+
+#define GetBN(obj, bn) do { \
+  Data_Get_Struct((obj), BIGNUM, (bn)); \
+  if (!(bn)) { \
+    ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
+  } \
+} while (0)
+
+#define SafeGetBN(obj, bn) do { \
+  OSSL_Check_Kind((obj), cBN); \
+  GetBN((obj), (bn)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cBN;
+VALUE eBNError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_bn_new(const BIGNUM *bn)
+{
+    BIGNUM *newbn;
+    VALUE obj;
+
+    newbn = bn ? BN_dup(bn) : BN_new();
+    if (!newbn) {
+       ossl_raise(eBNError, NULL);
+    }
+    WrapBN(cBN, obj, newbn);
+
+    return obj;
+}
+
+BIGNUM *
+GetBNPtr(VALUE obj)
+{
+    BIGNUM *bn = NULL;
+
+    if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
+       GetBN(obj, bn);
+    } else switch (TYPE(obj)) {
+    case T_FIXNUM:
+    case T_BIGNUM:
+       obj = rb_String(obj);
+       if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
+           ossl_raise(eBNError, NULL);
+       }
+       WrapBN(cBN, obj, bn); /* Handle potencial mem leaks */
+       break;
+    case T_NIL:
+       break;
+    default:
+       ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
+    }
+    return bn;
+}
+
+/*
+ * Private
+ */
+/*
+ * BN_CTX - is used in more difficult math. ops
+ * (Why just 1? Because Ruby itself isn't thread safe,
+ *  we don't need to care about threads)
+ */
+BN_CTX *ossl_bn_ctx;
+
+static VALUE
+ossl_bn_alloc(VALUE klass)
+{
+    BIGNUM *bn;
+    VALUE obj;
+
+    if (!(bn = BN_new())) {
+       ossl_raise(eBNError, NULL);
+    }
+    WrapBN(klass, obj, bn);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    BN.new => aBN
+ *    BN.new(bn) => aBN
+ *    BN.new(string) => aBN
+ *    BN.new(string, 0 | 2 | 10 | 16) => aBN
+ */
+static VALUE
+ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
+{
+    BIGNUM *bn;
+    VALUE str, bs;
+    int base = 10;
+
+    if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
+       base = NUM2INT(bs);
+    }
+    StringValue(str);
+    GetBN(self, bn);
+    if (RTEST(rb_obj_is_kind_of(str, cBN))) {
+       BIGNUM *other;
+
+       GetBN(str, other); /* Safe - we checked kind_of? above */
+       if (!BN_copy(bn, other)) {
+           ossl_raise(eBNError, NULL);
+       }
+       return self;
+    }
+
+    switch (base) {
+    case 0:
+       if (!BN_mpi2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) {
+           ossl_raise(eBNError, NULL);
+       }
+       break;
+    case 2:
+       if (!BN_bin2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) {
+           ossl_raise(eBNError, NULL);
+       }
+       break;
+    case 10:
+       if (!BN_dec2bn(&bn, RSTRING_PTR(str))) {
+           ossl_raise(eBNError, NULL);
+       }
+       break;
+    case 16:
+       if (!BN_hex2bn(&bn, RSTRING_PTR(str))) {
+           ossl_raise(eBNError, NULL);
+       }
+       break;
+    default:
+       ossl_raise(rb_eArgError, "invalid radix %d", base);
+    }
+    return self;
+}
+
+/*
+ * call-seq:
+ *    bn.to_s => string
+ *    bn.to_s(base) => string
+ *
+ * === Parameters
+ * * +base+ - integer
+ * * * Valid values:
+ * * * * 0 - MPI
+ * * * * 2 - binary
+ * * * * 10 - the default
+ * * * * 16 - hex
+ */
+static VALUE
+ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
+{
+    BIGNUM *bn;
+    VALUE str, bs;
+    int base = 10, len;
+    char *buf;
+
+    if (rb_scan_args(argc, argv, "01", &bs) == 1) {
+       base = NUM2INT(bs);
+    }
+    GetBN(self, bn);
+    switch (base) {
+    case 0:
+       len = BN_bn2mpi(bn, NULL);
+        str = rb_str_new(0, len);
+       if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+           ossl_raise(eBNError, NULL);
+       break;
+    case 2:
+       len = BN_num_bytes(bn);
+        str = rb_str_new(0, len);
+       if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
+           ossl_raise(eBNError, NULL);
+       break;
+    case 10:
+       if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
+       str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+       break;
+    case 16:
+       if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
+       str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
+       break;
+    default:
+       ossl_raise(rb_eArgError, "invalid radix %d", base);
+    }
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    bn.to_i => integer
+ */
+static VALUE
+ossl_bn_to_i(VALUE self)
+{
+    BIGNUM *bn;
+    char *txt;
+    VALUE num;
+
+    GetBN(self, bn);
+
+    if (!(txt = BN_bn2dec(bn))) {
+       ossl_raise(eBNError, NULL);
+    }
+    num = rb_cstr_to_inum(txt, 10, Qtrue);
+    OPENSSL_free(txt);
+
+    return num;
+}
+
+static VALUE
+ossl_bn_to_bn(VALUE self)
+{
+    return self;
+}
+
+static VALUE
+ossl_bn_coerce(VALUE self, VALUE other)
+{
+    switch(TYPE(other)) {
+    case T_STRING:
+       self = ossl_bn_to_s(0, NULL, self);
+       break;
+    case T_FIXNUM:
+    case T_BIGNUM:
+       self = ossl_bn_to_i(self);
+       break;
+    default:
+       if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
+           ossl_raise(rb_eTypeError, "Don't know how to coerce");
+       }
+    }
+    return rb_assoc_new(other, self);
+}
+
+#define BIGNUM_BOOL1(func)                             \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func -> true | false                     \
+     *                                                 \
+     */                                                        \
+    static VALUE                                       \
+    ossl_bn_##func(VALUE self)                         \
+    {                                                  \
+       BIGNUM *bn;                                     \
+       GetBN(self, bn);                                \
+       if (BN_##func(bn)) {                            \
+           return Qtrue;                               \
+       }                                               \
+       return Qfalse;                                  \
+    }
+BIGNUM_BOOL1(is_zero)
+BIGNUM_BOOL1(is_one)
+BIGNUM_BOOL1(is_odd)
+
+#define BIGNUM_1c(func)                                        \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func -> aBN                              \
+     *                                                 \
+     */                                                        \
+    static VALUE                                       \
+    ossl_bn_##func(VALUE self)                         \
+    {                                                  \
+       BIGNUM *bn, *result;                            \
+       VALUE obj;                                      \
+       GetBN(self, bn);                                \
+       if (!(result = BN_new())) {                     \
+           ossl_raise(eBNError, NULL);                 \
+       }                                               \
+       if (!BN_##func(result, bn, ossl_bn_ctx)) {      \
+           BN_free(result);                            \
+           ossl_raise(eBNError, NULL);                 \
+       }                                               \
+       WrapBN(CLASS_OF(self), obj, result);            \
+       return obj;                                     \
+    }
+BIGNUM_1c(sqr)
+
+#define BIGNUM_2(func)                                 \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func(bn2) -> aBN                         \
+     *                                                 \
+     */                                                        \
+    static VALUE                                       \
+    ossl_bn_##func(VALUE self, VALUE other)            \
+    {                                                  \
+       BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;   \
+       VALUE obj;                                      \
+       GetBN(self, bn1);                               \
+       if (!(result = BN_new())) {                     \
+           ossl_raise(eBNError, NULL);                 \
+       }                                               \
+       if (!BN_##func(result, bn1, bn2)) {             \
+           BN_free(result);                            \
+           ossl_raise(eBNError, NULL);                 \
+       }                                               \
+       WrapBN(CLASS_OF(self), obj, result);            \
+       return obj;                                     \
+    }
+BIGNUM_2(add)
+BIGNUM_2(sub)
+
+#define BIGNUM_2c(func)                                                \
+    /*                                                         \
+     * call-seq:                                               \
+     *   bn.##func(bn2) -> aBN                                 \
+     *                                                         \
+     */                                                                \
+    static VALUE                                               \
+    ossl_bn_##func(VALUE self, VALUE other)                    \
+    {                                                          \
+       BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;           \
+       VALUE obj;                                              \
+       GetBN(self, bn1);                                       \
+       if (!(result = BN_new())) {                             \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) {        \
+           BN_free(result);                                    \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       WrapBN(CLASS_OF(self), obj, result);                    \
+       return obj;                                             \
+    }
+BIGNUM_2c(mul)
+BIGNUM_2c(mod)
+BIGNUM_2c(exp)
+BIGNUM_2c(gcd)
+BIGNUM_2c(mod_sqr)
+BIGNUM_2c(mod_inverse)
+
+/*
+ * call-seq:
+ *    bn1 / bn2 => [result, remainder]
+ */
+static VALUE
+ossl_bn_div(VALUE self, VALUE other)
+{
+    BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
+    VALUE obj1, obj2;
+
+    GetBN(self, bn1);
+
+    if (!(r1 = BN_new())) {
+       ossl_raise(eBNError, NULL);
+    }
+    if (!(r2 = BN_new())) {
+       BN_free(r1);
+       ossl_raise(eBNError, NULL);
+    }
+    if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
+       BN_free(r1);
+       BN_free(r2);
+       ossl_raise(eBNError, NULL);
+    }
+    WrapBN(CLASS_OF(self), obj1, r1);
+    WrapBN(CLASS_OF(self), obj2, r2);
+
+    return rb_ary_new3(2, obj1, obj2);
+}
+
+#define BIGNUM_3c(func)                                                \
+    /*                                                         \
+     * call-seq:                                               \
+     *   bn.##func(bn1, bn2) -> aBN                            \
+     *                                                         \
+     */                                                                \
+    static VALUE                                               \
+    ossl_bn_##func(VALUE self, VALUE other1, VALUE other2)     \
+    {                                                          \
+       BIGNUM *bn1, *bn2 = GetBNPtr(other1);                   \
+       BIGNUM *bn3 = GetBNPtr(other2), *result;                \
+       VALUE obj;                                              \
+       GetBN(self, bn1);                                       \
+       if (!(result = BN_new())) {                             \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) {   \
+           BN_free(result);                                    \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       WrapBN(CLASS_OF(self), obj, result);                    \
+       return obj;                                             \
+    }
+BIGNUM_3c(mod_add)
+BIGNUM_3c(mod_sub)
+BIGNUM_3c(mod_mul)
+BIGNUM_3c(mod_exp)
+
+#define BIGNUM_BIT(func)                               \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func(bit) -> self                                \
+     *                                                 \
+     */                                                        \
+    static VALUE                                       \
+    ossl_bn_##func(VALUE self, VALUE bit)              \
+    {                                                  \
+       BIGNUM *bn;                                     \
+       GetBN(self, bn);                                \
+       if (!BN_##func(bn, NUM2INT(bit))) {             \
+           ossl_raise(eBNError, NULL);                 \
+       }                                               \
+       return self;                                    \
+    }
+BIGNUM_BIT(set_bit)
+BIGNUM_BIT(clear_bit)
+BIGNUM_BIT(mask_bits)
+
+/*
+ * call-seq:
+ *    bn.bit_set?(bit) => true | false
+ */
+static VALUE
+ossl_bn_is_bit_set(VALUE self, VALUE bit)
+{
+    int b;
+    BIGNUM *bn;
+
+    b = NUM2INT(bit);
+    GetBN(self, bn);
+    if (BN_is_bit_set(bn, b)) {
+       return Qtrue;
+    }
+    return Qfalse;
+}
+
+#define BIGNUM_SHIFT(func)                             \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func(bits) -> aBN                                \
+     *                                                 \
+     */                                                        \
+    static VALUE                                       \
+    ossl_bn_##func(VALUE self, VALUE bits)             \
+    {                                                  \
+       BIGNUM *bn, *result;                            \
+       int b;                                          \
+       VALUE obj;                                      \
+       b = NUM2INT(bits);                              \
+       GetBN(self, bn);                                \
+       if (!(result = BN_new())) {                     \
+               ossl_raise(eBNError, NULL);             \
+       }                                               \
+       if (!BN_##func(result, bn, b)) {                \
+               BN_free(result);                        \
+               ossl_raise(eBNError, NULL);             \
+       }                                               \
+       WrapBN(CLASS_OF(self), obj, result);            \
+       return obj;                                     \
+    }
+BIGNUM_SHIFT(lshift)
+BIGNUM_SHIFT(rshift)
+
+#define BIGNUM_SELF_SHIFT(func)                                \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func!(bits) -> self                      \
+     *                                                 \
+     */                                                        \
+    static VALUE                                       \
+    ossl_bn_self_##func(VALUE self, VALUE bits)                \
+    {                                                  \
+       BIGNUM *bn;                                     \
+       int b;                                          \
+       b = NUM2INT(bits);                              \
+       GetBN(self, bn);                                \
+       if (!BN_##func(bn, bn, b))                      \
+               ossl_raise(eBNError, NULL);             \
+       return self;                                    \
+    }
+BIGNUM_SELF_SHIFT(lshift)
+BIGNUM_SELF_SHIFT(rshift)
+
+#define BIGNUM_RAND(func)                                      \
+    /*                                                         \
+     * call-seq:                                               \
+     *   BN.##func(bits [, fill [, odd]]) -> aBN               \
+     *                                                         \
+     */                                                                \
+    static VALUE                                               \
+    ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass)       \
+    {                                                          \
+       BIGNUM *result;                                         \
+       int bottom = 0, top = 0, b;                             \
+       VALUE bits, fill, odd, obj;                             \
+                                                               \
+       switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) {   \
+       case 3:                                                 \
+           bottom = (odd == Qtrue) ? 1 : 0;                    \
+           /* FALLTHROUGH */                                   \
+       case 2:                                                 \
+           top = NUM2INT(fill);                                \
+       }                                                       \
+       b = NUM2INT(bits);                                      \
+       if (!(result = BN_new())) {                             \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       if (!BN_##func(result, b, top, bottom)) {               \
+           BN_free(result);                                    \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       WrapBN(klass, obj, result);                             \
+       return obj;                                             \
+    }
+BIGNUM_RAND(rand)
+BIGNUM_RAND(pseudo_rand)
+
+#define BIGNUM_RAND_RANGE(func)                                        \
+    /*                                                         \
+     * call-seq:                                               \
+     *   BN.##func(range) -> aBN                               \
+     *                                                         \
+     */                                                                \
+    static VALUE                                               \
+    ossl_bn_s_##func##_range(VALUE klass, VALUE range)         \
+    {                                                          \
+       BIGNUM *bn = GetBNPtr(range), *result;                  \
+       VALUE obj;                                              \
+       if (!(result = BN_new())) {                             \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       if (!BN_##func##_range(result, bn)) {                   \
+           BN_free(result);                                    \
+           ossl_raise(eBNError, NULL);                         \
+       }                                                       \
+       WrapBN(klass, obj, result);                             \
+       return obj;                                             \
+    }
+BIGNUM_RAND_RANGE(rand)
+BIGNUM_RAND_RANGE(pseudo_rand)
+
+/*
+ * call-seq:
+ *    BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn
+ *
+ * === Parameters
+ * * +bits+ - integer
+ * * +safe+ - boolean
+ * * +add+ - BN
+ * * +rem+ - BN
+ */
+static VALUE
+ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
+{
+    BIGNUM *add = NULL, *rem = NULL, *result;
+    int safe = 1, num;
+    VALUE vnum, vsafe, vadd, vrem, obj;
+
+    rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
+
+    num = NUM2INT(vnum);
+
+    if (vsafe == Qfalse) {
+       safe = 0;
+    }
+    if (!NIL_P(vadd)) {
+       add = GetBNPtr(vadd);
+       rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
+    }
+    if (!(result = BN_new())) {
+       ossl_raise(eBNError, NULL);
+    }
+    if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) {
+       BN_free(result);
+       ossl_raise(eBNError, NULL);
+    }
+    WrapBN(klass, obj, result);
+
+    return obj;
+}
+
+#define BIGNUM_NUM(func)                       \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func -> integer                          \
+     *                                                 \
+     */                                                        \
+    static VALUE                               \
+    ossl_bn_##func(VALUE self)                 \
+    {                                          \
+       BIGNUM *bn;                             \
+       GetBN(self, bn);                        \
+       return INT2FIX(BN_##func(bn));          \
+    }
+BIGNUM_NUM(num_bytes)
+BIGNUM_NUM(num_bits)
+
+static VALUE
+ossl_bn_copy(VALUE self, VALUE other)
+{
+    BIGNUM *bn1, *bn2;
+
+    rb_check_frozen(self);
+
+    if (self == other) return self;
+
+    GetBN(self, bn1);
+    bn2 = GetBNPtr(other);
+
+    if (!BN_copy(bn1, bn2)) {
+       ossl_raise(eBNError, NULL);
+    }
+    return self;
+}
+
+#define BIGNUM_CMP(func)                               \
+    /*                                                 \
+     * call-seq:                                       \
+     *   bn.##func(bn2) -> integer                     \
+     *                                                 \
+     */                                                        \
+    static VALUE                                       \
+    ossl_bn_##func(VALUE self, VALUE other)            \
+    {                                                  \
+       BIGNUM *bn1, *bn2 = GetBNPtr(other);            \
+       GetBN(self, bn1);                               \
+       return INT2FIX(BN_##func(bn1, bn2));            \
+    }
+BIGNUM_CMP(cmp)
+BIGNUM_CMP(ucmp)
+
+static VALUE
+ossl_bn_eql(VALUE self, VALUE other)
+{
+    if (ossl_bn_cmp(self, other) == INT2FIX(0)) {
+       return Qtrue;
+    }
+    return Qfalse;
+}
+
+/*
+ * call-seq:
+ *    bn.prime? => true | false
+ *    bn.prime?(checks) => true | false
+ *
+ * === Parameters
+ * * +checks+ - integer
+ */
+static VALUE
+ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
+{
+    BIGNUM *bn;
+    VALUE vchecks;
+    int checks = BN_prime_checks;
+
+    if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {
+       checks = NUM2INT(vchecks);
+    }
+    GetBN(self, bn);
+    switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) {
+    case 1:
+       return Qtrue;
+    case 0:
+       return Qfalse;
+    default:
+       ossl_raise(eBNError, NULL);
+    }
+    /* not reachable */
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *    bn.prime_fasttest? => true | false
+ *    bn.prime_fasttest?(checks) => true | false
+ *    bn.prime_fasttest?(checks, trial_div) => true | false
+ *
+ * === Parameters
+ * * +checks+ - integer
+ * * +trial_div+ - boolean
+ */
+static VALUE
+ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
+{
+    BIGNUM *bn;
+    VALUE vchecks, vtrivdiv;
+    int checks = BN_prime_checks, do_trial_division = 1;
+
+    rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
+
+    if (!NIL_P(vchecks)) {
+       checks = NUM2INT(vchecks);
+    }
+    GetBN(self, bn);
+    /* handle true/false */
+    if (vtrivdiv == Qfalse) {
+       do_trial_division = 0;
+    }
+    switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) {
+    case 1:
+       return Qtrue;
+    case 0:
+       return Qfalse;
+    default:
+       ossl_raise(eBNError, NULL);
+    }
+    /* not reachable */
+    return Qnil;
+}
+
+/*
+ * INIT
+ * (NOTE: ordering of methods is the same as in 'man bn')
+ */
+void
+Init_ossl_bn()
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    if (!(ossl_bn_ctx = BN_CTX_new())) {
+       ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
+    }
+
+    eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError);
+
+    cBN = rb_define_class_under(mOSSL, "BN", rb_cObject);
+
+    rb_define_alloc_func(cBN, ossl_bn_alloc);
+    rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
+
+    rb_define_copy_func(cBN, ossl_bn_copy);
+    rb_define_method(cBN, "copy", ossl_bn_copy, 1);
+
+    /* swap (=coerce?) */
+
+    rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0);
+    rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0);
+    /* num_bits_word */
+
+    rb_define_method(cBN, "+", ossl_bn_add, 1);
+    rb_define_method(cBN, "-", ossl_bn_sub, 1);
+    rb_define_method(cBN, "*", ossl_bn_mul, 1);
+    rb_define_method(cBN, "sqr", ossl_bn_sqr, 0);
+    rb_define_method(cBN, "/", ossl_bn_div, 1);
+    rb_define_method(cBN, "%", ossl_bn_mod, 1);
+    /* nnmod */
+
+    rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 2);
+    rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2);
+    rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2);
+    rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1);
+    rb_define_method(cBN, "**", ossl_bn_exp, 1);
+    rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2);
+    rb_define_method(cBN, "gcd", ossl_bn_gcd, 1);
+
+    /* add_word
+     * sub_word
+     * mul_word
+     * div_word
+     * mod_word */
+
+    rb_define_method(cBN, "cmp", ossl_bn_cmp, 1);
+    rb_define_alias(cBN, "<=>", "cmp");
+    rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1);
+    rb_define_method(cBN, "eql?", ossl_bn_eql, 1);
+    rb_define_alias(cBN, "==", "eql?");
+    rb_define_alias(cBN, "===", "eql?");
+    rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0);
+    rb_define_method(cBN, "one?", ossl_bn_is_one, 0);
+    /* is_word */
+    rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0);
+
+    /* zero
+     * one
+     * value_one - DON'T IMPL.
+     * set_word
+     * get_word */
+
+    rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1);
+    rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
+    rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
+    rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
+
+    rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
+    rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
+
+    rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1);
+    rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1);
+    rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
+    rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
+    rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
+    rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
+    rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1);
+    rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1);
+    /* lshift1 - DON'T IMPL. */
+    /* rshift1 - DON'T IMPL. */
+
+    /*
+     * bn2bin
+     * bin2bn
+     * bn2hex
+     * bn2dec
+     * hex2bn
+     * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
+     * print - NOT IMPL.
+     * print_fp - NOT IMPL.
+     * bn2mpi
+     * mpi2bn
+     */
+    rb_define_method(cBN, "to_s", ossl_bn_to_s, -1);
+    rb_define_method(cBN, "to_i", ossl_bn_to_i, 0);
+    rb_define_alias(cBN, "to_int", "to_i");
+    rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0);
+    rb_define_method(cBN, "coerce", ossl_bn_coerce, 1);
+
+    /*
+     * TODO:
+     * But how to: from_bin, from_mpi? PACK?
+     * to_bin
+     * to_mpi
+     */
+
+    rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1);
+
+    /* RECiProcal
+     * MONTgomery */
+
+    /*
+     * TODO:
+     * Where to belong these?
+     */
+    rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bn.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_bn.h
new file mode 100644 (file)
index 0000000..d6c3962
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_BN_H_)
+#define _OSSL_BN_H_
+
+extern VALUE cBN;
+extern VALUE eBNError;
+
+extern BN_CTX *ossl_bn_ctx;
+
+VALUE ossl_bn_new(const BIGNUM *);
+BIGNUM *GetBNPtr(VALUE);
+void Init_ossl_bn(void);
+
+
+#endif /* _OSS_BN_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cipher.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cipher.c
new file mode 100644 (file)
index 0000000..c046518
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapCipher(obj, klass, ctx) \
+    (obj) = Data_Wrap_Struct((klass), 0, ossl_cipher_free, (ctx))
+#define MakeCipher(obj, klass, ctx) \
+    (obj) = Data_Make_Struct((klass), EVP_CIPHER_CTX, 0, ossl_cipher_free, (ctx))
+#define AllocCipher(obj, ctx) \
+    memset(DATA_PTR(obj) = (ctx) = ALLOC(EVP_CIPHER_CTX), 0, sizeof(EVP_CIPHER_CTX))
+#define GetCipherInit(obj, ctx) do { \
+    Data_Get_Struct((obj), EVP_CIPHER_CTX, (ctx)); \
+} while (0)
+#define GetCipher(obj, ctx) do { \
+    GetCipherInit((obj), (ctx)); \
+    if (!(ctx)) { \
+       ossl_raise(rb_eRuntimeError, "Cipher not inititalized!"); \
+    } \
+} while (0)
+#define SafeGetCipher(obj, ctx) do { \
+    OSSL_Check_Kind((obj), cCipher); \
+    GetCipher((obj), (ctx)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cCipher;
+VALUE eCipherError;
+
+static VALUE ossl_cipher_alloc(VALUE klass);
+
+/*
+ * PUBLIC
+ */
+const EVP_CIPHER *
+GetCipherPtr(VALUE obj)
+{
+    EVP_CIPHER_CTX *ctx;
+
+    SafeGetCipher(obj, ctx);
+
+    return EVP_CIPHER_CTX_cipher(ctx);
+}
+
+VALUE
+ossl_cipher_new(const EVP_CIPHER *cipher)
+{
+    VALUE ret;
+    EVP_CIPHER_CTX *ctx;
+
+    ret = ossl_cipher_alloc(cCipher);
+    AllocCipher(ret, ctx);
+    EVP_CIPHER_CTX_init(ctx);
+    if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
+       ossl_raise(eCipherError, NULL);
+
+    return ret;
+}
+
+/*
+ * PRIVATE
+ */
+static void
+ossl_cipher_free(EVP_CIPHER_CTX *ctx)
+{
+    if (ctx) {
+       EVP_CIPHER_CTX_cleanup(ctx);
+       ruby_xfree(ctx);
+    }
+}
+
+static VALUE
+ossl_cipher_alloc(VALUE klass)
+{
+    VALUE obj;
+
+    WrapCipher(obj, klass, 0);
+
+    return obj;
+}
+
+/*
+ *  call-seq:
+ *     Cipher.new(string) -> cipher
+ *
+ *  The string must contain a valid cipher name like "AES-128-CBC" or "3DES".
+ *
+ *  A list of cipher names is available by calling OpenSSL::Cipher.ciphers.
+ */
+static VALUE
+ossl_cipher_initialize(VALUE self, VALUE str)
+{
+    EVP_CIPHER_CTX *ctx;
+    const EVP_CIPHER *cipher;
+    char *name;
+    unsigned char key[EVP_MAX_KEY_LENGTH];
+
+    name = StringValuePtr(str);
+    GetCipherInit(self, ctx);
+    if (ctx) {
+       ossl_raise(rb_eRuntimeError, "Cipher already inititalized!");
+    }
+    AllocCipher(self, ctx);
+    EVP_CIPHER_CTX_init(ctx);
+    if (!(cipher = EVP_get_cipherbyname(name))) {
+       ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%s)", name);
+    }
+    /*
+     * The EVP which has EVP_CIPH_RAND_KEY flag (such as DES3) allows
+     * uninitialized key, but other EVPs (such as AES) does not allow it.
+     * Calling EVP_CipherUpdate() without initializing key causes SEGV so we
+     * set the data filled with "\0" as the key by default.
+     */
+    memset(key, 0, EVP_MAX_KEY_LENGTH);
+    if (EVP_CipherInit_ex(ctx, cipher, NULL, key, NULL, -1) != 1)
+       ossl_raise(eCipherError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_cipher_copy(VALUE self, VALUE other)
+{
+    EVP_CIPHER_CTX *ctx1, *ctx2;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+
+    GetCipherInit(self, ctx1);
+    if (!ctx1) {
+       AllocCipher(self, ctx1);
+    }
+    SafeGetCipher(other, ctx2);
+    if (EVP_CIPHER_CTX_copy(ctx1, ctx2) != 1)
+       ossl_raise(eCipherError, NULL);
+
+    return self;
+}
+
+#ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
+static void*
+add_cipher_name_to_ary(const OBJ_NAME *name, VALUE ary)
+{
+    rb_ary_push(ary, rb_str_new2(name->name));
+    return NULL;
+}
+#endif
+
+#ifdef HAVE_OBJ_NAME_DO_ALL_SORTED
+/*
+ *  call-seq:
+ *     Cipher.ciphers -> array[string...]
+ *
+ *  Returns the names of all available ciphers in an array.
+ */
+static VALUE
+ossl_s_ciphers(VALUE self)
+{
+    VALUE ary;
+
+    ary = rb_ary_new();
+    OBJ_NAME_do_all_sorted(OBJ_NAME_TYPE_CIPHER_METH,
+                    (void(*)(const OBJ_NAME*,void*))add_cipher_name_to_ary,
+                    (void*)ary);
+
+    return ary;
+}
+#else
+#define ossl_s_ciphers rb_f_notimplement
+#endif
+
+/*
+ *  call-seq:
+ *     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.
+ *
+ *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1).
+ */
+static VALUE
+ossl_cipher_reset(VALUE self)
+{
+    EVP_CIPHER_CTX *ctx;
+
+    GetCipher(self, ctx);
+    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, -1) != 1)
+       ossl_raise(eCipherError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
+{
+    EVP_CIPHER_CTX *ctx;
+    unsigned char key[EVP_MAX_KEY_LENGTH], *p_key = NULL;
+    unsigned char iv[EVP_MAX_IV_LENGTH], *p_iv = NULL;
+    VALUE pass, init_v;
+
+    if(rb_scan_args(argc, argv, "02", &pass, &init_v) > 0){
+       /*
+        * oops. this code mistakes salt for IV.
+        * We deprecated the arguments for this method, but we decided
+        * keeping this behaviour for backward compatibility.
+        */
+       VALUE cname  = rb_class_path(rb_obj_class(self));
+       rb_warn("arguments for %"PRIsVALUE"#encrypt and %"PRIsVALUE"#decrypt were deprecated; "
+                "use %"PRIsVALUE"#pkcs5_keyivgen to derive key and IV",
+                RB_OBJ_STRING(cname), RB_OBJ_STRING(cname), RB_OBJ_STRING(cname));
+       StringValue(pass);
+       GetCipher(self, ctx);
+       if (NIL_P(init_v)) memcpy(iv, "OpenSSL for Ruby rulez!", sizeof(iv));
+       else{
+           StringValue(init_v);
+           if (EVP_MAX_IV_LENGTH > RSTRING_LEN(init_v)) {
+               memset(iv, 0, EVP_MAX_IV_LENGTH);
+               memcpy(iv, RSTRING_PTR(init_v), RSTRING_LEN(init_v));
+           }
+           else memcpy(iv, RSTRING_PTR(init_v), sizeof(iv));
+       }
+       EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), EVP_md5(), iv,
+                      (unsigned char *)RSTRING_PTR(pass), RSTRING_LENINT(pass), 1, key, NULL);
+       p_key = key;
+       p_iv = iv;
+    }
+    else {
+       GetCipher(self, ctx);
+    }
+    if (EVP_CipherInit_ex(ctx, NULL, NULL, p_key, p_iv, mode) != 1) {
+       ossl_raise(eCipherError, NULL);
+    }
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     cipher.encrypt -> self
+ *
+ *  Initializes the Cipher for encryption.
+ *
+ *  Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
+ *  following methods:
+ *  * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
+ *
+ *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 1).
+ */
+static VALUE
+ossl_cipher_encrypt(int argc, VALUE *argv, VALUE self)
+{
+    return ossl_cipher_init(argc, argv, self, 1);
+}
+
+/*
+ *  call-seq:
+ *     cipher.decrypt -> self
+ *
+ *  Initializes the Cipher for decryption.
+ *
+ *  Make sure to call Cipher#encrypt or Cipher#decrypt before using any of the
+ *  following methods:
+ *  * [key=, iv=, random_key, random_iv, pkcs5_keyivgen]
+ *
+ *  Internally calls EVP_CipherInit_ex(ctx, NULL, NULL, NULL, NULL, 0).
+ */
+static VALUE
+ossl_cipher_decrypt(int argc, VALUE *argv, VALUE self)
+{
+    return ossl_cipher_init(argc, argv, self, 0);
+}
+
+/*
+ *  call-seq:
+ *     cipher.pkcs5_keyivgen(pass [, salt [, iterations [, digest]]] ) -> nil
+ *
+ *  Generates and sets the key/IV based on a password.
+ *
+ *  WARNING: This method is only PKCS5 v1.5 compliant when using RC2, RC4-40,
+ *  or DES with MD5 or SHA1. Using anything else (like AES) will generate the
+ *  key/iv using an OpenSSL specific method. This method is deprecated and
+ *  should no longer be used. Use a PKCS5 v2 key generation method from
+ *  OpenSSL::PKCS5 instead.
+ *
+ *  === Parameters
+ *  +salt+ must be an 8 byte string if provided.
+ *  +iterations+ is a integer with a default of 2048.
+ *  +digest+ is a Digest object that defaults to 'MD5'
+ *
+ *  A minimum of 1000 iterations is recommended.
+ *
+ */
+static VALUE
+ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
+{
+    EVP_CIPHER_CTX *ctx;
+    const EVP_MD *digest;
+    VALUE vpass, vsalt, viter, vdigest;
+    unsigned char key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH], *salt = NULL;
+    int iter;
+
+    rb_scan_args(argc, argv, "13", &vpass, &vsalt, &viter, &vdigest);
+    StringValue(vpass);
+    if(!NIL_P(vsalt)){
+       StringValue(vsalt);
+       if(RSTRING_LEN(vsalt) != PKCS5_SALT_LEN)
+           ossl_raise(eCipherError, "salt must be an 8-octet string");
+       salt = (unsigned char *)RSTRING_PTR(vsalt);
+    }
+    iter = NIL_P(viter) ? 2048 : NUM2INT(viter);
+    digest = NIL_P(vdigest) ? EVP_md5() : GetDigestPtr(vdigest);
+    GetCipher(self, ctx);
+    EVP_BytesToKey(EVP_CIPHER_CTX_cipher(ctx), digest, salt,
+                  (unsigned char *)RSTRING_PTR(vpass), RSTRING_LENINT(vpass), iter, key, iv);
+    if (EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, -1) != 1)
+       ossl_raise(eCipherError, NULL);
+    OPENSSL_cleanse(key, sizeof key);
+    OPENSSL_cleanse(iv, sizeof iv);
+
+    return Qnil;
+}
+
+
+/*
+ *  call-seq:
+ *     cipher.update(data [, buffer]) -> string or buffer
+ *
+ *  Encrypts data in a streaming fashion. Hand consecutive blocks of data
+ *  to the +update+ method in order to encrypt it. Returns the encrypted
+ *  data chunk. When done, the output of Cipher#final should be additionally
+ *  added to the result.
+ *
+ *  === Parameters
+ *  +data+ is a nonempty string.
+ *  +buffer+ is an optional string to store the result.
+ */
+static VALUE
+ossl_cipher_update(int argc, VALUE *argv, VALUE self)
+{
+    EVP_CIPHER_CTX *ctx;
+    unsigned char *in;
+    int 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)
+        ossl_raise(rb_eArgError, "data must not be empty");
+    GetCipher(self, ctx);
+    out_len = in_len+EVP_CIPHER_CTX_block_size(ctx);
+
+    if (NIL_P(str)) {
+        str = rb_str_new(0, out_len);
+    } else {
+        StringValue(str);
+        rb_str_resize(str, out_len);
+    }
+
+    if (!EVP_CipherUpdate(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);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     cipher.final -> string
+ *
+ *  Returns the remaining data held in the cipher object.  Further calls to
+ *  Cipher#update or Cipher#final will return garbage.
+ *
+ *  See EVP_CipherFinal_ex for further information.
+ */
+static VALUE
+ossl_cipher_final(VALUE self)
+{
+    EVP_CIPHER_CTX *ctx;
+    int out_len;
+    VALUE str;
+
+    GetCipher(self, ctx);
+    str = rb_str_new(0, EVP_CIPHER_CTX_block_size(ctx));
+    if (!EVP_CipherFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), &out_len))
+       ossl_raise(eCipherError, NULL);
+    assert(out_len <= RSTRING_LEN(str));
+    rb_str_set_len(str, out_len);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     cipher.name -> string
+ *
+ *  Returns the name of the cipher which may differ slightly from the original
+ *  name provided.
+ */
+static VALUE
+ossl_cipher_name(VALUE self)
+{
+    EVP_CIPHER_CTX *ctx;
+
+    GetCipher(self, ctx);
+
+    return rb_str_new2(EVP_CIPHER_name(EVP_CIPHER_CTX_cipher(ctx)));
+}
+
+/*
+ *  call-seq:
+ *     cipher.key = string -> string
+ *
+ *  Sets the cipher key. To generate a key, you should either use a secure
+ *  random byte string or, if the key is to be derived from a password, you
+ *  should rely on PBKDF2 functionality provided by OpenSSL::PKCS5. To
+ *  generate a secure random-based key, Cipher#random_key may be used.
+ *
+ *  Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ */
+static VALUE
+ossl_cipher_set_key(VALUE self, VALUE key)
+{
+    EVP_CIPHER_CTX *ctx;
+
+    StringValue(key);
+    GetCipher(self, ctx);
+
+    if (RSTRING_LEN(key) < EVP_CIPHER_CTX_key_length(ctx))
+        ossl_raise(eCipherError, "key length too short");
+
+    if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
+        ossl_raise(eCipherError, NULL);
+
+    return key;
+}
+
+/*
+ *  call-seq:
+ *     cipher.iv = string -> string
+ *
+ *  Sets the cipher IV. Please note that since you should never be using ECB
+ *  mode, an IV is always explicitly required and should be set prior to
+ *  encryption. The IV itself can be safely transmitted in public, but it
+ *  should be unpredictable to prevent certain kinds of attacks. You may use
+ *  Cipher#random_iv to create a secure random IV.
+ *
+ *  Only call this method after calling Cipher#encrypt or Cipher#decrypt.
+ *
+ *  If not explicitly set, the OpenSSL default of an all-zeroes ("\\0") IV is
+ *  used.
+ */
+static VALUE
+ossl_cipher_set_iv(VALUE self, VALUE iv)
+{
+    EVP_CIPHER_CTX *ctx;
+
+    StringValue(iv);
+    GetCipher(self, ctx);
+
+    if (RSTRING_LEN(iv) < EVP_CIPHER_CTX_iv_length(ctx))
+        ossl_raise(eCipherError, "iv length too short");
+
+    if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, (unsigned char *)RSTRING_PTR(iv), -1) != 1)
+       ossl_raise(eCipherError, NULL);
+
+    return iv;
+}
+
+
+/*
+ *  call-seq:
+ *     cipher.key_len = integer -> integer
+ *
+ *  Sets the key length of the cipher.  If the cipher is a fixed length cipher
+ *  then attempting to set the key length to any value other than the fixed
+ *  value is an error.
+ *
+ *  Under normal circumstances you do not need to call this method (and probably shouldn't).
+ *
+ *  See EVP_CIPHER_CTX_set_key_length for further information.
+ */
+static VALUE
+ossl_cipher_set_key_length(VALUE self, VALUE key_length)
+{
+    int len = NUM2INT(key_length);
+    EVP_CIPHER_CTX *ctx;
+
+    GetCipher(self, ctx);
+    if (EVP_CIPHER_CTX_set_key_length(ctx, len) != 1)
+        ossl_raise(eCipherError, NULL);
+
+    return key_length;
+}
+
+#if defined(HAVE_EVP_CIPHER_CTX_SET_PADDING)
+/*
+ *  call-seq:
+ *     cipher.padding = integer -> integer
+ *
+ *  Enables or disables padding. By default encryption operations are padded using standard block padding and the
+ *  padding is checked and removed when decrypting. If the pad parameter is zero then no padding is performed, the
+ *  total amount of data encrypted or decrypted must then be a multiple of the block size or an error will occur.
+ *
+ *  See EVP_CIPHER_CTX_set_padding for further information.
+ */
+static VALUE
+ossl_cipher_set_padding(VALUE self, VALUE padding)
+{
+    EVP_CIPHER_CTX *ctx;
+    int pad = NUM2INT(padding);
+
+    GetCipher(self, ctx);
+    if (EVP_CIPHER_CTX_set_padding(ctx, pad) != 1)
+       ossl_raise(eCipherError, NULL);
+    return padding;
+}
+#else
+#define ossl_cipher_set_padding rb_f_notimplement
+#endif
+
+#define CIPHER_0ARG_INT(func)                                  \
+    static VALUE                                               \
+    ossl_cipher_##func(VALUE self)                             \
+    {                                                          \
+       EVP_CIPHER_CTX *ctx;                                    \
+       GetCipher(self, ctx);                                   \
+       return INT2NUM(EVP_CIPHER_##func(EVP_CIPHER_CTX_cipher(ctx)));  \
+    }
+
+/*
+ *  call-seq:
+ *     cipher.key_len -> integer
+ *
+ *  Returns the key length in bytes of the Cipher.
+ */
+CIPHER_0ARG_INT(key_length)
+/*
+ *  call-seq:
+ *     cipher.iv_len -> integer
+ *
+ *  Returns the expected length in bytes for an IV for this Cipher.
+ */
+CIPHER_0ARG_INT(iv_length)
+/*
+ *  call-seq:
+ *     cipher.block_size -> integer
+ *
+ *  Returns the size in bytes of the blocks on which this Cipher operates on.
+ */
+CIPHER_0ARG_INT(block_size)
+
+/*
+ * INIT
+ */
+void
+Init_ossl_cipher(void)
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    /* Document-class: OpenSSL::Cipher
+     *
+     * Provides symmetric algorithms for encryption and decryption. The
+     * algorithms that are available depend on the particular version
+     * of OpenSSL that is installed.
+     *
+     * === Listing all supported algorithms
+     *
+     * A list of supported algorithms can be obtained by
+     *
+     *   puts OpenSSL::Cipher.ciphers
+     *
+     * === Instantiating a Cipher
+     *
+     * There are several ways to create a Cipher instance. Generally, a
+     * Cipher algorithm is categorized by its name, the key length in bits
+     * and the cipher mode to be used. The most generic way to create a
+     * Cipher is the following
+     *
+     *   cipher = OpenSSL::Cipher.new('<name>-<key length>-<mode>')
+     *
+     * That is, a string consisting of the hyphenated concatenation of the
+     * individual components name, key length and mode. Either all uppercase
+     * or all lowercase strings may be used, for example:
+     *
+     *  cipher = OpenSSL::Cipher.new('AES-128-CBC')
+     *
+     * For each algorithm supported, there is a class defined under the
+     * Cipher class that goes by the name of the cipher, e.g. to obtain an
+     * instance of AES, you could also use
+     *
+     *   # these are equivalent
+     *   cipher = OpenSSL::Cipher::AES.new(128, :CBC)
+     *   cipher = OpenSSL::Cipher::AES.new(128, 'CBC')
+     *   cipher = OpenSSL::Cipher::AES.new('128-CBC')
+     *
+     * Finally, due to its wide-spread use, there are also extra classes
+     * defined for the different key sizes of AES
+     *
+     *   cipher = OpenSSL::Cipher::AES128.new(:CBC)
+     *   cipher = OpenSSL::Cipher::AES192.new(:CBC)
+     *   cipher = OpenSSL::Cipher::AES256.new(:CBC)
+     *
+     * === Choosing either encryption or decryption mode
+     *
+     * Encryption and decryption are often very similar operations for
+     * symmetric algorithms, this is reflected by not having to choose
+     * different classes for either operation, both can be done using the
+     * same class. Still, after obtaining a Cipher instance, we need to
+     * tell the instance what it is that we intend to do with it, so we
+     * need to call either
+     *
+     *   cipher.encrypt
+     *
+     * or
+     *
+     *   cipher.decrypt
+     *
+     * on the Cipher instance. This should be the first call after creating
+     * the instance, otherwise configuration that has already been set could
+     * get lost in the process.
+     *
+     * === Choosing a key
+     *
+     * Symmetric encryption requires a key that is the same for the encrypting
+     * and for the decrypting party and after initial key establishment should
+     * be kept as private information. There are a lot of ways to create
+     * insecure keys, the most notable is to simply take a password as the key
+     * without processing the password further. A simple and secure way to
+     * create a key for a particular Cipher is
+     *
+     *  cipher = OpenSSL::AES256.new(:CFB)
+     *  cipher.encrypt
+     *  key = cipher.random_key # also sets the generated key on the Cipher
+     *
+     * If you absolutely need to use passwords as encryption keys, you
+     * should use Password-Based Key Derivation Function 2 (PBKDF2) by
+     * generating the key with the help of the functionality provided by
+     * OpenSSL::PKCS5.pbkdf2_hmac_sha1 or OpenSSL::PKCS5.pbkdf2_hmac.
+     *
+     * Although there is Cipher#pkcs5_keyivgen, its use is deprecated and
+     * it should only be used in legacy applications because it does not use
+     * the newer PKCS#5 v2 algorithms.
+     *
+     * === Choosing an IV
+     *
+     * The cipher modes CBC, CFB, OFB and CTR all need an "initialization
+     * vector", or short, IV. ECB mode is the only mode that does not require
+     * an IV, but there is almost no legitimate use case for this mode
+     * because of the fact that it does not sufficiently hide plaintext
+     * patterns. Therefore
+     *
+     * <b>You should never use ECB mode unless you are absolutely sure that
+     * you absolutely need it</b>
+     *
+     * Because of this, you will end up with a mode that explicitly requires
+     * an IV in any case. Note that for backwards compatibility reasons,
+     * setting an IV is not explicitly mandated by the Cipher API. If not
+     * set, OpenSSL itself defaults to an all-zeroes IV ("\\0", not the
+     * character). Although the IV can be seen as public information, i.e.
+     * it may be transmitted in public once generated, it should still stay
+     * unpredictable to prevent certain kinds of attacks. Therefore, ideally
+     *
+     * <b>Always create a secure random IV for every encryption of your
+     * Cipher</b>
+     *
+     * A new, random IV should be created for every encryption of data. Think
+     * of the IV as a nonce (number used once) - it's public but random and
+     * unpredictable. A secure random IV can be created as follows
+     *
+     *  cipher = ...
+     *  cipher.encrypt
+     *  key = cipher.random_key
+     *  iv = cipher.random_iv # also sets the generated IV on the Cipher
+     *
+     *  Although the key is generally a random value, too, it is a bad choice
+     *  as an IV. There are elaborate ways how an attacker can take advantage
+     *  of such an IV. As a general rule of thumb, exposing the key directly
+     *  or indirectly should be avoided at all cost and exceptions only be
+     *  made with good reason.
+     *
+     * === Calling Cipher#final
+     *
+     * ECB (which should not be used) and CBC are both block-based modes.
+     * This means that unlike for the other streaming-based modes, they
+     * operate on fixed-size blocks of data, and therefore they require a
+     * "finalization" step to produce or correctly decrypt the last block of
+     * data by appropriately handling some form of padding. Therefore it is
+     * essential to add the output of OpenSSL::Cipher#final to your
+     * encryption/decryption buffer or you will end up with decryption errors
+     * or truncated data.
+     *
+     * Although this is not really necessary for streaming-mode ciphers, it is
+     * still recommended to apply the same pattern of adding the output of
+     * Cipher#final there as well - it also enables you to switch between
+     * modes more easily in the future.
+     *
+     * === Encrypting and decrypting some data
+     *
+     *   data = "Very, very confidential data"
+     *
+     *   cipher = OpenSSL::Cipher::AES.new(128, :CBC)
+     *   cipher.encrypt
+     *   key = cipher.random_key
+     *   iv = cipher.random_iv
+     *
+     *   encrypted = cipher.update(data) + cipher.final
+     *   ...
+     *   decipher = OpenSSL::Cipher::AES.new(128, :CBC)
+     *   decipher.decrypt
+     *   decipher.key = key
+     *   decipher.iv = iv
+     *
+     *   plain = decipher.update(encrypted) + decipher.final
+     *
+     *   puts data == plain #=> true
+     *
+     */
+    cCipher = rb_define_class_under(mOSSL, "Cipher", rb_cObject);
+    eCipherError = rb_define_class_under(cCipher, "CipherError", eOSSLError);
+
+    rb_define_alloc_func(cCipher, ossl_cipher_alloc);
+    rb_define_copy_func(cCipher, ossl_cipher_copy);
+    rb_define_module_function(cCipher, "ciphers", ossl_s_ciphers, 0);
+    rb_define_method(cCipher, "initialize", ossl_cipher_initialize, 1);
+    rb_define_method(cCipher, "reset", ossl_cipher_reset, 0);
+    rb_define_method(cCipher, "encrypt", ossl_cipher_encrypt, -1);
+    rb_define_method(cCipher, "decrypt", ossl_cipher_decrypt, -1);
+    rb_define_method(cCipher, "pkcs5_keyivgen", ossl_cipher_pkcs5_keyivgen, -1);
+    rb_define_method(cCipher, "update", ossl_cipher_update, -1);
+    rb_define_method(cCipher, "final", ossl_cipher_final, 0);
+    rb_define_method(cCipher, "name", ossl_cipher_name, 0);
+    rb_define_method(cCipher, "key=", ossl_cipher_set_key, 1);
+    rb_define_method(cCipher, "key_len=", ossl_cipher_set_key_length, 1);
+    rb_define_method(cCipher, "key_len", ossl_cipher_key_length, 0);
+    rb_define_method(cCipher, "iv=", ossl_cipher_set_iv, 1);
+    rb_define_method(cCipher, "iv_len", ossl_cipher_iv_length, 0);
+    rb_define_method(cCipher, "block_size", ossl_cipher_block_size, 0);
+    rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cipher.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cipher.h
new file mode 100644 (file)
index 0000000..bed4fa8
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_CIPHER_H_)
+#define _OSSL_CIPHER_H_
+
+extern VALUE cCipher;
+extern VALUE eCipherError;
+
+const EVP_CIPHER *GetCipherPtr(VALUE);
+VALUE ossl_cipher_new(const EVP_CIPHER *);
+void Init_ossl_cipher(void);
+
+#endif /* _OSSL_CIPHER_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cms.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cms.c
new file mode 100644 (file)
index 0000000..a4574fc
--- /dev/null
@@ -0,0 +1,246 @@
+#include "ossl_cms.h"
+
+#define WrapCMS(klass, obj, cms) do { \
+    if (!(cms)) { \
+    ossl_raise(rb_eRuntimeError, "CMS wasn't initialized."); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, CMS_ContentInfo_free, (cms)); \
+} while (0)
+#define GetCMS(obj, cms) do { \
+    Data_Get_Struct((obj), CMS_ContentInfo, (cms)); \
+    if (!(cms)) { \
+    ossl_raise(rb_eRuntimeError, "CMS wasn't initialized."); \
+    } \
+} while (0)
+#define SafeGetCMS(obj, cms) do { \
+    OSSL_Check_Kind((obj), cCMS); \
+    GetCMS((obj), (cms)); \
+} while (0)
+
+#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
+
+#define ossl_cms_set_data(o,v)       rb_iv_set((o), "@data", (v))
+#define ossl_cms_get_data(o)         rb_iv_get((o), "@data")
+#define ossl_cms_set_err_string(o,v) rb_iv_set((o), "@error_string", (v))
+#define ossl_cms_get_err_string(o)   rb_iv_get((o), "@error_string")
+
+VALUE cCMS;
+VALUE eCMSError;
+
+static VALUE
+ossl_cms_s_read_cms(VALUE klass, VALUE arg)
+{
+    BIO *in;
+    CMS_ContentInfo *cms, *out;
+    VALUE ret;
+
+    arg = ossl_to_der_if_possible(arg);
+    in = ossl_obj2bio(arg);
+    out = CMS_ContentInfo_new();
+    cms = PEM_read_bio_CMS(in, &out, NULL, NULL);
+
+    if (!cms) {
+        OSSL_BIO_reset(in);
+        cms = d2i_CMS_bio(in, &out);
+
+        if (!cms) {
+            BIO_free(in);
+            CMS_ContentInfo_free(out);
+            ossl_raise(rb_eArgError, "Could not parse the CMS");
+        }
+    }
+
+    WrapCMS(cCMS, ret, cms);
+    BIO_free(in);
+    ossl_cms_set_data(ret, Qnil);
+    ossl_cms_set_err_string(ret, Qnil);
+
+    return ret;
+}
+
+static VALUE
+ossl_cms_alloc(VALUE klass)
+{
+    CMS_ContentInfo *cms;
+    VALUE obj;
+
+    if (!(cms = CMS_ContentInfo_new())) {
+        ossl_raise(eCMSError, NULL);
+    }
+    WrapCMS(klass, obj, cms);
+
+    return obj;
+}
+
+static VALUE
+ossl_cms_initialize(int argc, VALUE *argv, VALUE self)
+{
+    CMS_ContentInfo *cms, *out = DATA_PTR(self);
+    BIO *in;
+    VALUE arg;
+
+    if(rb_scan_args(argc, argv, "01", &arg) == 0)
+        return self;
+
+    arg = ossl_to_der_if_possible(arg);
+    in = ossl_obj2bio(arg);
+
+    cms = PEM_read_bio_CMS(in, &out, NULL, NULL);
+    if (!cms) {
+        OSSL_BIO_reset(in);
+        cms = d2i_CMS_bio(in, &out);
+
+        if (!cms) {
+            BIO_free(in);
+            CMS_ContentInfo_free(out);
+            DATA_PTR(self) = NULL;
+            ossl_raise(rb_eArgError, "Could not parse the CMS");
+        }
+    }
+
+    DATA_PTR(self) = out;
+    BIO_free(in);
+    ossl_cms_set_data(self, Qnil);
+    ossl_cms_set_err_string(self, Qnil);
+
+    return self;
+}
+
+static VALUE
+ossl_cms_copy(VALUE self, VALUE other)
+{
+    CMS_ContentInfo *a, *b, *cms;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+
+    GetCMS(self, a);
+    SafeGetCMS(other, b);
+
+    cms = CMS_ContentInfo_dup(b);
+    if (!cms) {
+        ossl_raise(eCMSError, NULL);
+    }
+    DATA_PTR(self) = cms;
+    CMS_ContentInfo_free(a);
+
+    return self;
+}
+
+static VALUE
+ossl_cms_verify(int argc, VALUE *argv, VALUE self)
+{
+    VALUE certs, store, indata, flags;
+    STACK_OF(X509) *x509s;
+    X509_STORE *x509st;
+    int flg, ok, status = 0;
+    BIO *in, *out;
+    CMS_ContentInfo *cms;
+    VALUE data;
+    const char *msg;
+
+    rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags);
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+
+    if(NIL_P(indata)) indata = ossl_cms_get_data(self);
+    in = NIL_P(indata) ? NULL : ossl_obj2bio(indata);
+
+    if(NIL_P(certs)) x509s = NULL;
+    else{
+        x509s = ossl_protect_x509_ary2sk(certs, &status);
+        if(status){
+            BIO_free(in);
+            rb_jump_tag(status);
+        }
+    }
+
+    x509st = GetX509StorePtr(store);
+    GetCMS(self, cms);
+
+    if(!(out = BIO_new(BIO_s_mem()))){
+        BIO_free(in);
+        sk_X509_pop_free(x509s, X509_free);
+        ossl_raise(eCMSError, NULL);
+    }
+
+    ok = CMS_verify(cms, x509s, x509st, in, out, flg);
+
+    BIO_free(in);
+    if (ok < 0) ossl_raise(eCMSError, NULL);
+
+    msg = ERR_reason_error_string(ERR_get_error());
+    ossl_cms_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
+    ERR_clear_error();
+
+    data = ossl_membio2str(out);
+
+    ossl_cms_set_data(self, data);
+    sk_X509_pop_free(x509s, X509_free);
+
+    return (ok == 1) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_cms_to_der(VALUE self)
+{
+    CMS_ContentInfo *cms;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetCMS(self, cms);
+    if((len = i2d_CMS_ContentInfo(cms, NULL)) <= 0)
+        ossl_raise(eCMSError, NULL);
+
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+
+    if(i2d_CMS_ContentInfo(cms, &p) <= 0)
+        ossl_raise(eCMSError, NULL);
+
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+static VALUE
+ossl_cms_to_pem(VALUE self)
+{
+    CMS_ContentInfo *cms;
+    VALUE str;
+    BIO *out;
+
+    GetCMS(self, cms);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+        ossl_raise(eCMSError, NULL);
+    }
+    if (!PEM_write_bio_CMS(out, cms)) {
+        BIO_free(out);
+        ossl_raise(eCMSError, NULL);
+    }
+
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+void
+Init_ossl_cms()
+{
+    cCMS = rb_define_class_under(mOSSL, "CMS", rb_cObject);
+    eCMSError = rb_define_class_under(cCMS, "CMSError", rb_eStandardError);
+
+    rb_define_singleton_method(cCMS, "read_cms", ossl_cms_s_read_cms, 1);
+
+    rb_attr(cCMS, rb_intern("data"), 1, 0, Qfalse);
+    rb_attr(cCMS, rb_intern("error_string"), 1, 1, Qfalse);
+
+    rb_define_alloc_func(cCMS, ossl_cms_alloc);
+    rb_define_copy_func(cCMS, ossl_cms_copy);
+
+    rb_define_method(cCMS, "initialize", ossl_cms_initialize, -1);
+    rb_define_method(cCMS, "verify", ossl_cms_verify, -1);
+    rb_define_method(cCMS, "to_pem", ossl_cms_to_pem, 0);
+    rb_define_alias(cCMS,  "to_s", "to_pem");
+    rb_define_method(cCMS, "to_der", ossl_cms_to_der, 0);
+}
\ No newline at end of file
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cms.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_cms.h
new file mode 100644 (file)
index 0000000..9e3cd4f
--- /dev/null
@@ -0,0 +1,29 @@
+#if !defined(_OSSL_CMS_H_)
+#define _OSSL_CMS_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+////////////////////////////
+//
+//     Ruby && OpenSSL stuff
+//
+////////////////////////////
+
+#include "ossl.h"
+
+//////////////////////////////
+//     rCMS stuff
+//////////////////////////////
+
+extern VALUE cCMS;
+extern VALUE eCMSError;
+
+void Init_ossl_cms(void);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _OSSL_CMS_H_ */
\ No newline at end of file
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_config.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_config.c
new file mode 100644 (file)
index 0000000..e700833
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@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 cConfig;
+VALUE eConfigError;
+
+/*
+ * Public
+ */
+
+/*
+ * GetConfigPtr is a public C-level function for getting OpenSSL CONF struct
+ * from an OpenSSL::Config(eConfig) instance.  We decided to implement
+ * OpenSSL::Config in Ruby level but we need to pass native CONF struct for
+ * some OpenSSL features such as X509V3_EXT_*.
+ */
+CONF *
+GetConfigPtr(VALUE obj)
+{
+    CONF *conf;
+    VALUE str;
+    BIO *bio;
+    long eline = -1;
+
+    OSSL_Check_Kind(obj, cConfig);
+    str = rb_funcall(obj, rb_intern("to_s"), 0);
+    bio = ossl_obj2bio(str);
+    conf = NCONF_new(NULL);
+    if(!conf){
+       BIO_free(bio);
+       ossl_raise(eConfigError, NULL);
+    }
+    if(!NCONF_load_bio(conf, bio, &eline)){
+       BIO_free(bio);
+       NCONF_free(conf);
+       if (eline <= 0) ossl_raise(eConfigError, "wrong config format");
+       else ossl_raise(eConfigError, "error in line %d", eline);
+       ossl_raise(eConfigError, NULL);
+    }
+    BIO_free(bio);
+
+    return conf;
+}
+
+
+/*
+ * INIT
+ */
+void
+Init_ossl_config()
+{
+    char *default_config_file;
+    eConfigError = rb_define_class_under(mOSSL, "ConfigError", eOSSLError);
+    cConfig = rb_define_class_under(mOSSL, "Config", rb_cObject);
+
+    default_config_file = CONF_get1_default_config_file();
+    rb_define_const(cConfig, "DEFAULT_CONFIG_FILE",
+                   rb_str_new2(default_config_file));
+    OPENSSL_free(default_config_file);
+    /* methods are defined by openssl/config.rb */
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_config.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_config.h
new file mode 100644 (file)
index 0000000..cb226b2
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_CONFIG_H_)
+#define _OSSL_CONFIG_H_
+
+extern VALUE cConfig;
+extern VALUE eConfigError;
+
+CONF* GetConfigPtr(VALUE obj);
+CONF* DupConfigPtr(VALUE obj);
+void Init_ossl_config(void);
+
+#endif /* _OSSL_CONFIG_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_digest.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_digest.c
new file mode 100644 (file)
index 0000000..fdf13e9
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define GetDigest(obj, ctx) do { \
+    Data_Get_Struct((obj), EVP_MD_CTX, (ctx)); \
+    if (!(ctx)) { \
+       ossl_raise(rb_eRuntimeError, "Digest CTX wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetDigest(obj, ctx) do { \
+    OSSL_Check_Kind((obj), cDigest); \
+    GetDigest((obj), (ctx)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cDigest;
+VALUE eDigestError;
+
+static VALUE ossl_digest_alloc(VALUE klass);
+
+/*
+ * Public
+ */
+const EVP_MD *
+GetDigestPtr(VALUE obj)
+{
+    const EVP_MD *md;
+    ASN1_OBJECT *oid = NULL;
+
+    if (TYPE(obj) == T_STRING) {
+       const char *name = StringValueCStr(obj);
+
+       md = EVP_get_digestbyname(name);
+       if (!md) {
+           oid = OBJ_txt2obj(name, 0);
+           md = EVP_get_digestbyobj(oid);
+           ASN1_OBJECT_free(oid);
+       }
+       if(!md)
+            ossl_raise(rb_eRuntimeError, "Unsupported digest algorithm (%s).", name);
+    } else {
+        EVP_MD_CTX *ctx;
+
+        SafeGetDigest(obj, ctx);
+
+        md = EVP_MD_CTX_md(ctx);
+    }
+
+    return md;
+}
+
+VALUE
+ossl_digest_new(const EVP_MD *md)
+{
+    VALUE ret;
+    EVP_MD_CTX *ctx;
+
+    ret = ossl_digest_alloc(cDigest);
+    GetDigest(ret, ctx);
+    if (EVP_DigestInit_ex(ctx, md, NULL) != 1) {
+       ossl_raise(eDigestError, "Digest initialization failed.");
+    }
+
+    return ret;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_digest_alloc(VALUE klass)
+{
+    EVP_MD_CTX *ctx;
+    VALUE obj;
+
+    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);
+
+    return obj;
+}
+
+VALUE ossl_digest_update(VALUE, VALUE);
+
+/*
+ *  call-seq:
+ *     Digest.new(string [, data]) -> Digest
+ *
+ * Creates a Digest instance based on +string+, which is either the ln
+ * (long name) or sn (short name) of a supported digest algorithm.
+ * If +data+ (a +String+) is given, it is used as the initial input to the
+ * Digest instance, i.e.
+ *   digest = OpenSSL::Digest.new('sha256', 'digestdata')
+ * is equal to
+ *   digest = OpenSSL::Digest.new('sha256')
+ *   digest.update('digestdata')
+ *
+ * === Example
+ *   digest = OpenSSL::Digest.new('sha1')
+ *
+ *
+ */
+static VALUE
+ossl_digest_initialize(int argc, VALUE *argv, VALUE self)
+{
+    EVP_MD_CTX *ctx;
+    const EVP_MD *md;
+    VALUE type, data;
+
+    rb_scan_args(argc, argv, "11", &type, &data);
+    md = GetDigestPtr(type);
+    if (!NIL_P(data)) StringValue(data);
+
+    GetDigest(self, ctx);
+    if (EVP_DigestInit_ex(ctx, md, NULL) != 1) {
+       ossl_raise(eDigestError, "Digest initialization failed.");
+    }
+
+    if (!NIL_P(data)) return ossl_digest_update(self, data);
+    return self;
+}
+
+static VALUE
+ossl_digest_copy(VALUE self, VALUE other)
+{
+    EVP_MD_CTX *ctx1, *ctx2;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+
+    GetDigest(self, ctx1);
+    SafeGetDigest(other, ctx2);
+
+    if (!EVP_MD_CTX_copy(ctx1, ctx2)) {
+       ossl_raise(eDigestError, NULL);
+    }
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     digest.reset -> self
+ *
+ * Resets the Digest in the sense that any Digest#update that has been
+ * performed is abandoned and the Digest is set to its initial state again.
+ *
+ */
+static VALUE
+ossl_digest_reset(VALUE self)
+{
+    EVP_MD_CTX *ctx;
+
+    GetDigest(self, ctx);
+    if (EVP_DigestInit_ex(ctx, EVP_MD_CTX_md(ctx), NULL) != 1) {
+       ossl_raise(eDigestError, "Digest initialization failed.");
+    }
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     digest.update(string) -> aString
+ *
+ * Not every message digest can be computed in one single pass. If a message
+ * digest is to be computed from several subsequent sources, then each may
+ * be passed individually to the Digest instance.
+ *
+ * === Example
+ *   digest = OpenSSL::Digest::SHA256.new
+ *   digest.update('First input')
+ *   digest << 'Second input' # equivalent to digest.update('Second input')
+ *   result = digest.digest
+ *
+ */
+VALUE
+ossl_digest_update(VALUE self, VALUE data)
+{
+    EVP_MD_CTX *ctx;
+
+    StringValue(data);
+    GetDigest(self, ctx);
+    EVP_DigestUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data));
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *      digest.finish -> aString
+ *
+ */
+static VALUE
+ossl_digest_finish(int argc, VALUE *argv, VALUE self)
+{
+    EVP_MD_CTX *ctx;
+    VALUE str;
+
+    rb_scan_args(argc, argv, "01", &str);
+
+    GetDigest(self, ctx);
+
+    if (NIL_P(str)) {
+        str = rb_str_new(NULL, EVP_MD_CTX_size(ctx));
+    } else {
+        StringValue(str);
+        rb_str_resize(str, EVP_MD_CTX_size(ctx));
+    }
+
+    EVP_DigestFinal_ex(ctx, (unsigned char *)RSTRING_PTR(str), NULL);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *      digest.name -> string
+ *
+ * Returns the sn of this Digest instance.
+ *
+ * === Example
+ *   digest = OpenSSL::Digest::SHA512.new
+ *   puts digest.name # => SHA512
+ *
+ */
+static VALUE
+ossl_digest_name(VALUE self)
+{
+    EVP_MD_CTX *ctx;
+
+    GetDigest(self, ctx);
+
+    return rb_str_new2(EVP_MD_name(EVP_MD_CTX_md(ctx)));
+}
+
+/*
+ *  call-seq:
+ *      digest.digest_length -> integer
+ *
+ * Returns the output size of the digest, i.e. the length in bytes of the
+ * final message digest result.
+ *
+ * === Example
+ *   digest = OpenSSL::Digest::SHA1.new
+ *   puts digest.digest_length # => 20
+ *
+ */
+static VALUE
+ossl_digest_size(VALUE self)
+{
+    EVP_MD_CTX *ctx;
+
+    GetDigest(self, ctx);
+
+    return INT2NUM(EVP_MD_CTX_size(ctx));
+}
+
+/*
+ *  call-seq:
+ *      digest.block_length -> integer
+ *
+ * Returns the block length of the digest algorithm, i.e. the length in bytes
+ * of an individual block. Most modern algorithms partition a message to be
+ * digested into a sequence of fix-sized blocks that are processed
+ * consecutively.
+ *
+ * === Example
+ *   digest = OpenSSL::Digest::SHA1.new
+ *   puts digest.block_length # => 64
+ */
+static VALUE
+ossl_digest_block_length(VALUE self)
+{
+    EVP_MD_CTX *ctx;
+
+    GetDigest(self, ctx);
+
+    return INT2NUM(EVP_MD_CTX_block_size(ctx));
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_digest()
+{
+    rb_require("digest");
+
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    /* Document-class: OpenSSL::Digest
+     *
+     * OpenSSL::Digest allows you to compute message digests (sometimes
+     * interchangeably called "hashes") of arbitrary data that are
+     * cryptographically secure, i.e. a Digest implements a secure one-way
+     * function.
+     *
+     * One-way functions offer some useful properties. E.g. given two
+     * distinct inputs the probability that both yield the same output
+     * is highly unlikely. Combined with the fact that every message digest
+     * algorithm has a fixed-length output of just a few bytes, digests are
+     * often used to create unique identifiers for arbitrary data. A common
+     * example is the creation of a unique id for binary documents that are
+     * stored in a database.
+     *
+     * Another useful characteristic of one-way functions (and thus the name)
+     * is that given a digest there is no indication about the original
+     * data that produced it, i.e. the only way to identify the original input
+     * is to "brute-force" through every possible combination of inputs.
+     *
+     * These characteristics make one-way functions also ideal companions
+     * for public key signature algorithms: instead of signing an entire
+     * document, first a hash of the document is produced with a considerably
+     * faster message digest algorithm and only the few bytes of its output
+     * need to be signed using the slower public key algorithm. To validate
+     * the integrity of a signed document, it suffices to re-compute the hash
+     * and verify that it is equal to that in the signature.
+     *
+     * Among the supported message digest algorithms are:
+     * * SHA, SHA1, SHA224, SHA256, SHA384 and SHA512
+     * * MD2, MD4, MDC2 and MD5
+     * * RIPEMD160
+     * * DSS, DSS1 (Pseudo algorithms to be used for DSA signatures. DSS is
+     *   equal to SHA and DSS1 is equal to SHA1)
+     *
+     * For each of these algorithms, there is a sub-class of Digest that
+     * can be instantiated as simply as e.g.
+     *
+     *   digest = OpenSSL::Digest::SHA1.new
+     *
+     * === Mapping between Digest class and sn/ln
+     *
+     * The sn (short names) and ln (long names) are defined in
+     * <openssl/object.h> and <openssl/obj_mac.h>. They are textual
+     * representations of ASN.1 OBJECT IDENTIFIERs. Each supported digest
+     * algorithm has an OBJECT IDENTIFIER associated to it and those again
+     * have short/long names assigned to them.
+     * E.g. the OBJECT IDENTIFIER for SHA-1 is 1.3.14.3.2.26 and its
+     * sn is "SHA1" and its ln is "sha1".
+     * ==== MD2
+     * * sn: MD2
+     * * ln: md2
+     * ==== MD4
+     * * sn: MD4
+     * * ln: md4
+     * ==== MD5
+     * * sn: MD5
+     * * ln: md5
+     * ==== SHA
+     * * sn: SHA
+     * * ln: SHA
+     * ==== SHA-1
+     * * sn: SHA1
+     * * ln: sha1
+     * ==== SHA-224
+     * * sn: SHA224
+     * * ln: sha224
+     * ==== SHA-256
+     * * sn: SHA256
+     * * ln: sha256
+     * ==== SHA-384
+     * * sn: SHA384
+     * * ln: sha384
+     * ==== SHA-512
+     * * sn: SHA512
+     * * ln: sha512
+     *
+     * "Breaking" a message digest algorithm means defying its one-way
+     * function characteristics, i.e. producing a collision or finding a way
+     * to get to the original data by means that are more efficient than
+     * brute-forcing etc. Most of the supported digest algorithms can be
+     * considered broken in this sense, even the very popular MD5 and SHA1
+     * algorithms. Should security be your highest concern, then you should
+     * probably rely on SHA224, SHA256, SHA384 or SHA512.
+     *
+     * === Hashing a file
+     *
+     *   data = File.read('document')
+     *   sha256 = OpenSSL::Digest::SHA256.new
+     *   digest = sha256.digest(data)
+     *
+     * === Hashing several pieces of data at once
+     *
+     *   data1 = File.read('file1')
+     *   data2 = File.read('file2')
+     *   data3 = File.read('file3')
+     *   sha256 = OpenSSL::Digest::SHA256.new
+     *   sha256 << data1
+     *   sha256 << data2
+     *   sha256 << data3
+     *   digest = sha256.digest
+     *
+     * === Reuse a Digest instance
+     *
+     *   data1 = File.read('file1')
+     *   sha256 = OpenSSL::Digest::SHA256.new
+     *   digest1 = sha256.digest(data1)
+     *
+     *   data2 = File.read('file2')
+     *   sha256.reset
+     *   digest2 = sha256.digest(data2)
+     *
+     */
+    cDigest = rb_define_class_under(mOSSL, "Digest", rb_path2class("Digest::Class"));
+    /* Document-class: OpenSSL::Digest::DigestError
+     *
+     * Generic Exception class that is raised if an error occurs during a
+     * Digest operation.
+     */
+    eDigestError = rb_define_class_under(cDigest, "DigestError", eOSSLError);
+
+    rb_define_alloc_func(cDigest, ossl_digest_alloc);
+
+    rb_define_method(cDigest, "initialize", ossl_digest_initialize, -1);
+    rb_define_copy_func(cDigest, ossl_digest_copy);
+    rb_define_method(cDigest, "reset", ossl_digest_reset, 0);
+    rb_define_method(cDigest, "update", ossl_digest_update, 1);
+    rb_define_alias(cDigest, "<<", "update");
+    rb_define_private_method(cDigest, "finish", ossl_digest_finish, -1);
+    rb_define_method(cDigest, "digest_length", ossl_digest_size, 0);
+    rb_define_method(cDigest, "block_length", ossl_digest_block_length, 0);
+
+    rb_define_method(cDigest, "name", ossl_digest_name, 0);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_digest.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_digest.h
new file mode 100644 (file)
index 0000000..8cc5b1b
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_DIGEST_H_)
+#define _OSSL_DIGEST_H_
+
+extern VALUE cDigest;
+extern VALUE eDigestError;
+
+const EVP_MD *GetDigestPtr(VALUE);
+VALUE ossl_digest_new(const EVP_MD *);
+void Init_ossl_digest(void);
+
+#endif /* _OSSL_DIGEST_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_engine.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_engine.c
new file mode 100644 (file)
index 0000000..51cfb08
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#if defined(OSSL_ENGINE_ENABLED)
+
+#define WrapEngine(klass, obj, engine) do { \
+    if (!(engine)) { \
+       ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, ENGINE_free, (engine)); \
+} while(0)
+#define GetEngine(obj, engine) do { \
+    Data_Get_Struct((obj), ENGINE, (engine)); \
+    if (!(engine)) { \
+        ossl_raise(rb_eRuntimeError, "ENGINE wasn't initialized."); \
+    } \
+} while (0)
+#define SafeGetEngine(obj, engine) do { \
+    OSSL_Check_Kind((obj), cEngine); \
+    GetPKCS7((obj), (engine)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cEngine;
+VALUE eEngineError;
+
+/*
+ * Private
+ */
+#define OSSL_ENGINE_LOAD_IF_MATCH(x) \
+do{\
+  if(!strcmp(#x, RSTRING_PTR(name))){\
+    ENGINE_load_##x();\
+    return Qtrue;\
+  }\
+}while(0)
+
+static VALUE
+ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)
+{
+#if !defined(HAVE_ENGINE_LOAD_BUILTIN_ENGINES)
+    return Qnil;
+#else
+    VALUE name;
+
+    rb_scan_args(argc, argv, "01", &name);
+    if(NIL_P(name)){
+        ENGINE_load_builtin_engines();
+        return Qtrue;
+    }
+    StringValue(name);
+#ifndef OPENSSL_NO_STATIC_ENGINE
+#if HAVE_ENGINE_LOAD_DYNAMIC
+    OSSL_ENGINE_LOAD_IF_MATCH(dynamic);
+#endif
+#if HAVE_ENGINE_LOAD_CSWIFT
+    OSSL_ENGINE_LOAD_IF_MATCH(cswift);
+#endif
+#if HAVE_ENGINE_LOAD_CHIL
+    OSSL_ENGINE_LOAD_IF_MATCH(chil);
+#endif
+#if HAVE_ENGINE_LOAD_ATALLA
+    OSSL_ENGINE_LOAD_IF_MATCH(atalla);
+#endif
+#if HAVE_ENGINE_LOAD_NURON
+    OSSL_ENGINE_LOAD_IF_MATCH(nuron);
+#endif
+#if HAVE_ENGINE_LOAD_UBSEC
+    OSSL_ENGINE_LOAD_IF_MATCH(ubsec);
+#endif
+#if HAVE_ENGINE_LOAD_AEP
+    OSSL_ENGINE_LOAD_IF_MATCH(aep);
+#endif
+#if HAVE_ENGINE_LOAD_SUREWARE
+    OSSL_ENGINE_LOAD_IF_MATCH(sureware);
+#endif
+#if HAVE_ENGINE_LOAD_4758CCA
+    OSSL_ENGINE_LOAD_IF_MATCH(4758cca);
+#endif
+#endif
+#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO
+    OSSL_ENGINE_LOAD_IF_MATCH(openbsd_dev_crypto);
+#endif
+    OSSL_ENGINE_LOAD_IF_MATCH(openssl);
+    rb_warning("no such builtin loader for `%s'", RSTRING_PTR(name));
+    return Qnil;
+#endif /* HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+}
+
+static VALUE
+ossl_engine_s_cleanup(VALUE self)
+{
+#if defined(HAVE_ENGINE_CLEANUP)
+    ENGINE_cleanup();
+#endif
+    return Qnil;
+}
+
+static VALUE
+ossl_engine_s_engines(VALUE klass)
+{
+    ENGINE *e;
+    VALUE ary, obj;
+
+    ary = rb_ary_new();
+    for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)){
+       /* Need a ref count of two here because of ENGINE_free being
+        * called internally by OpenSSL when moving to the next ENGINE
+        * and by us when releasing the ENGINE reference */
+       ENGINE_up_ref(e);
+       WrapEngine(klass, obj, e);
+        rb_ary_push(ary, obj);
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_engine_s_by_id(VALUE klass, VALUE id)
+{
+    ENGINE *e;
+    VALUE obj;
+
+    StringValue(id);
+    ossl_engine_s_load(1, &id, klass);
+    if(!(e = ENGINE_by_id(RSTRING_PTR(id))))
+       ossl_raise(eEngineError, NULL);
+    WrapEngine(klass, obj, e);
+    if(rb_block_given_p()) rb_yield(obj);
+    if(!ENGINE_init(e))
+       ossl_raise(eEngineError, NULL);
+    ENGINE_ctrl(e, ENGINE_CTRL_SET_PASSWORD_CALLBACK,
+               0, NULL, (void(*)(void))ossl_pem_passwd_cb);
+    ERR_clear_error();
+
+    return obj;
+}
+
+static VALUE
+ossl_engine_s_alloc(VALUE klass)
+{
+    ENGINE *e;
+    VALUE obj;
+
+    if (!(e = ENGINE_new())) {
+       ossl_raise(eEngineError, NULL);
+    }
+    WrapEngine(klass, obj, e);
+
+    return obj;
+}
+
+static VALUE
+ossl_engine_get_id(VALUE self)
+{
+    ENGINE *e;
+    GetEngine(self, e);
+    return rb_str_new2(ENGINE_get_id(e));
+}
+
+static VALUE
+ossl_engine_get_name(VALUE self)
+{
+    ENGINE *e;
+    GetEngine(self, e);
+    return rb_str_new2(ENGINE_get_name(e));
+}
+
+static VALUE
+ossl_engine_finish(VALUE self)
+{
+    ENGINE *e;
+
+    GetEngine(self, e);
+    if(!ENGINE_finish(e)) ossl_raise(eEngineError, NULL);
+
+    return Qnil;
+}
+
+#if defined(HAVE_ENGINE_GET_CIPHER)
+static VALUE
+ossl_engine_get_cipher(VALUE self, VALUE name)
+{
+    ENGINE *e;
+    const EVP_CIPHER *ciph, *tmp;
+    char *s;
+    int nid;
+
+    s = StringValuePtr(name);
+    tmp = EVP_get_cipherbyname(s);
+    if(!tmp) ossl_raise(eEngineError, "no such cipher `%s'", s);
+    nid = EVP_CIPHER_nid(tmp);
+    GetEngine(self, e);
+    ciph = ENGINE_get_cipher(e, nid);
+    if(!ciph) ossl_raise(eEngineError, NULL);
+
+    return ossl_cipher_new(ciph);
+}
+#else
+#define ossl_engine_get_cipher rb_f_notimplement
+#endif
+
+#if defined(HAVE_ENGINE_GET_DIGEST)
+static VALUE
+ossl_engine_get_digest(VALUE self, VALUE name)
+{
+    ENGINE *e;
+    const EVP_MD *md, *tmp;
+    char *s;
+    int nid;
+
+    s = StringValuePtr(name);
+    tmp = EVP_get_digestbyname(s);
+    if(!tmp) ossl_raise(eEngineError, "no such digest `%s'", s);
+    nid = EVP_MD_nid(tmp);
+    GetEngine(self, e);
+    md = ENGINE_get_digest(e, nid);
+    if(!md) ossl_raise(eEngineError, NULL);
+
+    return ossl_digest_new(md);
+}
+#else
+#define ossl_engine_get_digest rb_f_notimplement
+#endif
+
+static VALUE
+ossl_engine_load_privkey(int argc, VALUE *argv, VALUE self)
+{
+    ENGINE *e;
+    EVP_PKEY *pkey;
+    VALUE id, data, obj;
+    char *sid, *sdata;
+
+    rb_scan_args(argc, argv, "02", &id, &data);
+    sid = NIL_P(id) ? NULL : StringValuePtr(id);
+    sdata = NIL_P(data) ? NULL : StringValuePtr(data);
+    GetEngine(self, e);
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+    pkey = ENGINE_load_private_key(e, sid, sdata);
+#else
+    pkey = ENGINE_load_private_key(e, sid, NULL, sdata);
+#endif
+    if (!pkey) ossl_raise(eEngineError, NULL);
+    obj = ossl_pkey_new(pkey);
+    OSSL_PKEY_SET_PRIVATE(obj);
+
+    return obj;
+}
+
+static VALUE
+ossl_engine_load_pubkey(int argc, VALUE *argv, VALUE self)
+{
+    ENGINE *e;
+    EVP_PKEY *pkey;
+    VALUE id, data;
+    char *sid, *sdata;
+
+    rb_scan_args(argc, argv, "02", &id, &data);
+    sid = NIL_P(id) ? NULL : StringValuePtr(id);
+    sdata = NIL_P(data) ? NULL : StringValuePtr(data);
+    GetEngine(self, e);
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+    pkey = ENGINE_load_public_key(e, sid, sdata);
+#else
+    pkey = ENGINE_load_public_key(e, sid, NULL, sdata);
+#endif
+    if (!pkey) ossl_raise(eEngineError, NULL);
+
+    return ossl_pkey_new(pkey);
+}
+
+static VALUE
+ossl_engine_set_default(VALUE self, VALUE flag)
+{
+    ENGINE *e;
+    int f = NUM2INT(flag);
+
+    GetEngine(self, e);
+    ENGINE_set_default(e, f);
+
+    return Qtrue;
+}
+
+static VALUE
+ossl_engine_ctrl_cmd(int argc, VALUE *argv, VALUE self)
+{
+    ENGINE *e;
+    VALUE cmd, val;
+    int ret;
+
+    GetEngine(self, e);
+    rb_scan_args(argc, argv, "11", &cmd, &val);
+    StringValue(cmd);
+    if (!NIL_P(val)) StringValue(val);
+    ret = ENGINE_ctrl_cmd_string(e, RSTRING_PTR(cmd),
+                                NIL_P(val) ? NULL : RSTRING_PTR(val), 0);
+    if (!ret) ossl_raise(eEngineError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_engine_cmd_flag_to_name(int flag)
+{
+    switch(flag){
+    case ENGINE_CMD_FLAG_NUMERIC:  return rb_str_new2("NUMERIC");
+    case ENGINE_CMD_FLAG_STRING:   return rb_str_new2("STRING");
+    case ENGINE_CMD_FLAG_NO_INPUT: return rb_str_new2("NO_INPUT");
+    case ENGINE_CMD_FLAG_INTERNAL: return rb_str_new2("INTERNAL");
+    default: return rb_str_new2("UNKNOWN");
+    }
+}
+
+static VALUE
+ossl_engine_get_cmds(VALUE self)
+{
+    ENGINE *e;
+    const ENGINE_CMD_DEFN *defn, *p;
+    VALUE ary, tmp;
+
+    GetEngine(self, e);
+    ary = rb_ary_new();
+    if ((defn = ENGINE_get_cmd_defns(e)) != NULL){
+       for (p = defn; p->cmd_num > 0; p++){
+           tmp = rb_ary_new();
+           rb_ary_push(tmp, rb_str_new2(p->cmd_name));
+           rb_ary_push(tmp, rb_str_new2(p->cmd_desc));
+           rb_ary_push(tmp, ossl_engine_cmd_flag_to_name(p->cmd_flags));
+           rb_ary_push(ary, tmp);
+       }
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_engine_inspect(VALUE self)
+{
+    ENGINE *e;
+
+    GetEngine(self, e);
+    return rb_sprintf("#<%"PRIsVALUE" id=\"%s\" name=\"%s\">",
+                     RB_OBJ_CLASSNAME(self), ENGINE_get_id(e), ENGINE_get_name(e));
+}
+
+#define DefEngineConst(x) rb_define_const(cEngine, #x, INT2NUM(ENGINE_##x))
+
+void
+Init_ossl_engine()
+{
+    cEngine = rb_define_class_under(mOSSL, "Engine", rb_cObject);
+    eEngineError = rb_define_class_under(cEngine, "EngineError", eOSSLError);
+
+    rb_define_alloc_func(cEngine, ossl_engine_s_alloc);
+    rb_define_singleton_method(cEngine, "load", ossl_engine_s_load, -1);
+    rb_define_singleton_method(cEngine, "cleanup", ossl_engine_s_cleanup, 0);
+    rb_define_singleton_method(cEngine, "engines", ossl_engine_s_engines, 0);
+    rb_define_singleton_method(cEngine, "by_id", ossl_engine_s_by_id, 1);
+    rb_undef_method(CLASS_OF(cEngine), "new");
+
+    rb_define_method(cEngine, "id", ossl_engine_get_id, 0);
+    rb_define_method(cEngine, "name", ossl_engine_get_name, 0);
+    rb_define_method(cEngine, "finish", ossl_engine_finish, 0);
+    rb_define_method(cEngine, "cipher", ossl_engine_get_cipher, 1);
+    rb_define_method(cEngine, "digest",  ossl_engine_get_digest, 1);
+    rb_define_method(cEngine, "load_private_key", ossl_engine_load_privkey, -1);
+    rb_define_method(cEngine, "load_public_key", ossl_engine_load_pubkey, -1);
+    rb_define_method(cEngine, "set_default", ossl_engine_set_default, 1);
+    rb_define_method(cEngine, "ctrl_cmd", ossl_engine_ctrl_cmd, -1);
+    rb_define_method(cEngine, "cmds", ossl_engine_get_cmds, 0);
+    rb_define_method(cEngine, "inspect", ossl_engine_inspect, 0);
+
+    DefEngineConst(METHOD_RSA);
+    DefEngineConst(METHOD_DSA);
+    DefEngineConst(METHOD_DH);
+    DefEngineConst(METHOD_RAND);
+#ifdef ENGINE_METHOD_BN_MOD_EXP
+    DefEngineConst(METHOD_BN_MOD_EXP);
+#endif
+#ifdef ENGINE_METHOD_BN_MOD_EXP_CRT
+    DefEngineConst(METHOD_BN_MOD_EXP_CRT);
+#endif
+#ifdef ENGINE_METHOD_CIPHERS
+    DefEngineConst(METHOD_CIPHERS);
+#endif
+#ifdef ENGINE_METHOD_DIGESTS
+    DefEngineConst(METHOD_DIGESTS);
+#endif
+    DefEngineConst(METHOD_ALL);
+    DefEngineConst(METHOD_NONE);
+}
+#else
+void
+Init_ossl_engine()
+{
+}
+#endif
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_engine.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_engine.h
new file mode 100644 (file)
index 0000000..ea2f256
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2003  Michal Rokos <m.rokos@sh.cvut.cz>
+ * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OSSL_ENGINE_H)
+#define OSSL_ENGINE_H
+
+extern VALUE cEngine;
+extern VALUE eEngineError;
+
+void Init_ossl_engine(void);
+
+#endif /* OSSL_ENGINE_H */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_hmac.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_hmac.c
new file mode 100644 (file)
index 0000000..5220c9e
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_HMAC)
+
+#include "ossl.h"
+
+#define MakeHMAC(obj, klass, ctx) \
+    (obj) = Data_Make_Struct((klass), HMAC_CTX, 0, ossl_hmac_free, (ctx))
+#define GetHMAC(obj, ctx) do { \
+    Data_Get_Struct((obj), HMAC_CTX, (ctx)); \
+    if (!(ctx)) { \
+       ossl_raise(rb_eRuntimeError, "HMAC wasn't initialized"); \
+    } \
+} while (0)
+#define SafeGetHMAC(obj, ctx) do { \
+    OSSL_Check_Kind((obj), cHMAC); \
+    GetHMAC((obj), (ctx)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cHMAC;
+VALUE eHMACError;
+
+/*
+ * Public
+ */
+
+/*
+ * Private
+ */
+static void
+ossl_hmac_free(HMAC_CTX *ctx)
+{
+    HMAC_CTX_cleanup(ctx);
+    ruby_xfree(ctx);
+}
+
+static VALUE
+ossl_hmac_alloc(VALUE klass)
+{
+    HMAC_CTX *ctx;
+    VALUE obj;
+
+    MakeHMAC(obj, klass, ctx);
+    HMAC_CTX_init(ctx);
+
+    return obj;
+}
+
+
+/*
+ *  call-seq:
+ *     HMAC.new(key, digest) -> hmac
+ *
+ */
+static VALUE
+ossl_hmac_initialize(VALUE self, VALUE key, VALUE digest)
+{
+    HMAC_CTX *ctx;
+
+    StringValue(key);
+    GetHMAC(self, ctx);
+    HMAC_Init(ctx, RSTRING_PTR(key), RSTRING_LENINT(key),
+                GetDigestPtr(digest));
+
+    return self;
+}
+
+static VALUE
+ossl_hmac_copy(VALUE self, VALUE other)
+{
+    HMAC_CTX *ctx1, *ctx2;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+
+    GetHMAC(self, ctx1);
+    SafeGetHMAC(other, ctx2);
+
+    HMAC_CTX_copy(ctx1, ctx2);
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     hmac.update(string) -> self
+ *
+ */
+static VALUE
+ossl_hmac_update(VALUE self, VALUE data)
+{
+    HMAC_CTX *ctx;
+
+    StringValue(data);
+    GetHMAC(self, ctx);
+    HMAC_Update(ctx, (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data));
+
+    return self;
+}
+
+static void
+hmac_final(HMAC_CTX *ctx, unsigned char **buf, unsigned int *buf_len)
+{
+    HMAC_CTX final;
+
+    HMAC_CTX_copy(&final, ctx);
+    if (!(*buf = OPENSSL_malloc(HMAC_size(&final)))) {
+       HMAC_CTX_cleanup(&final);
+       OSSL_Debug("Allocating %d mem", HMAC_size(&final));
+       ossl_raise(eHMACError, "Cannot allocate memory for hmac");
+    }
+    HMAC_Final(&final, *buf, buf_len);
+    HMAC_CTX_cleanup(&final);
+}
+
+/*
+ *  call-seq:
+ *     hmac.digest -> aString
+ *
+ */
+static VALUE
+ossl_hmac_digest(VALUE self)
+{
+    HMAC_CTX *ctx;
+    unsigned char *buf;
+    unsigned int buf_len;
+    VALUE digest;
+
+    GetHMAC(self, ctx);
+    hmac_final(ctx, &buf, &buf_len);
+    digest = ossl_buf2str((char *)buf, buf_len);
+
+    return digest;
+}
+
+/*
+ *  call-seq:
+ *     hmac.hexdigest -> aString
+ *
+ */
+static VALUE
+ossl_hmac_hexdigest(VALUE self)
+{
+    HMAC_CTX *ctx;
+    unsigned char *buf;
+    char *hexbuf;
+    unsigned int buf_len;
+    VALUE hexdigest;
+
+    GetHMAC(self, ctx);
+    hmac_final(ctx, &buf, &buf_len);
+    if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) {
+       OPENSSL_free(buf);
+       ossl_raise(eHMACError, "Memory alloc error");
+    }
+    OPENSSL_free(buf);
+    hexdigest = ossl_buf2str(hexbuf, 2 * buf_len);
+
+    return hexdigest;
+}
+
+/*
+ *  call-seq:
+ *     hmac.reset -> self
+ *
+ */
+static VALUE
+ossl_hmac_reset(VALUE self)
+{
+    HMAC_CTX *ctx;
+
+    GetHMAC(self, ctx);
+    HMAC_Init(ctx, NULL, 0, NULL);
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     HMAC.digest(digest, key, data) -> aString
+ *
+ */
+static VALUE
+ossl_hmac_s_digest(VALUE klass, VALUE digest, VALUE key, VALUE data)
+{
+    unsigned char *buf;
+    unsigned int buf_len;
+
+    StringValue(key);
+    StringValue(data);
+    buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key),
+              (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len);
+
+    return rb_str_new((const char *)buf, buf_len);
+}
+
+/*
+ *  call-seq:
+ *     HMAC.digest(digest, key, data) -> aString
+ *
+ */
+static VALUE
+ossl_hmac_s_hexdigest(VALUE klass, VALUE digest, VALUE key, VALUE data)
+{
+    unsigned char *buf;
+    char *hexbuf;
+    unsigned int buf_len;
+    VALUE hexdigest;
+
+    StringValue(key);
+    StringValue(data);
+
+    buf = HMAC(GetDigestPtr(digest), RSTRING_PTR(key), RSTRING_LENINT(key),
+              (unsigned char *)RSTRING_PTR(data), RSTRING_LEN(data), NULL, &buf_len);
+    if (string2hex(buf, buf_len, &hexbuf, NULL) != 2 * (int)buf_len) {
+       ossl_raise(eHMACError, "Cannot convert buf to hexbuf");
+    }
+    hexdigest = ossl_buf2str(hexbuf, 2 * buf_len);
+
+    return hexdigest;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_hmac()
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    eHMACError = rb_define_class_under(mOSSL, "HMACError", eOSSLError);
+
+    cHMAC = rb_define_class_under(mOSSL, "HMAC", rb_cObject);
+
+    rb_define_alloc_func(cHMAC, ossl_hmac_alloc);
+    rb_define_singleton_method(cHMAC, "digest", ossl_hmac_s_digest, 3);
+    rb_define_singleton_method(cHMAC, "hexdigest", ossl_hmac_s_hexdigest, 3);
+
+    rb_define_method(cHMAC, "initialize", ossl_hmac_initialize, 2);
+    rb_define_copy_func(cHMAC, ossl_hmac_copy);
+
+    rb_define_method(cHMAC, "reset", ossl_hmac_reset, 0);
+    rb_define_method(cHMAC, "update", ossl_hmac_update, 1);
+    rb_define_alias(cHMAC, "<<", "update");
+    rb_define_method(cHMAC, "digest", ossl_hmac_digest, 0);
+    rb_define_method(cHMAC, "hexdigest", ossl_hmac_hexdigest, 0);
+    rb_define_alias(cHMAC, "inspect", "hexdigest");
+    rb_define_alias(cHMAC, "to_s", "hexdigest");
+}
+
+#else /* NO_HMAC */
+#  warning >>> OpenSSL is compiled without HMAC support <<<
+void
+Init_ossl_hmac()
+{
+    rb_warning("HMAC will NOT be avaible: OpenSSL is compiled without HMAC.");
+}
+#endif /* NO_HMAC */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_hmac.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_hmac.h
new file mode 100644 (file)
index 0000000..1a2978b
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_HMAC_H_)
+#define _OSSL_HMAC_H_
+
+extern VALUE cHMAC;
+extern VALUE eHMACError;
+
+void Init_ossl_hmac(void);
+
+#endif /* _OSSL_HMAC_H_ */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ns_spki.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ns_spki.c
new file mode 100644 (file)
index 0000000..bf828cb
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapSPKI(klass, obj, spki) do { \
+    if (!(spki)) { \
+       ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, NETSCAPE_SPKI_free, (spki)); \
+} while (0)
+#define GetSPKI(obj, spki) do { \
+    Data_Get_Struct((obj), NETSCAPE_SPKI, (spki)); \
+    if (!(spki)) { \
+       ossl_raise(rb_eRuntimeError, "SPKI wasn't initialized!"); \
+    } \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE mNetscape;
+VALUE cSPKI;
+VALUE eSPKIError;
+
+/*
+ * Public functions
+ */
+
+/*
+ * Private functions
+ */
+static VALUE
+ossl_spki_alloc(VALUE klass)
+{
+    NETSCAPE_SPKI *spki;
+    VALUE obj;
+
+    if (!(spki = NETSCAPE_SPKI_new())) {
+       ossl_raise(eSPKIError, NULL);
+    }
+    WrapSPKI(klass, obj, spki);
+
+    return obj;
+}
+
+static VALUE
+ossl_spki_initialize(int argc, VALUE *argv, VALUE self)
+{
+    NETSCAPE_SPKI *spki;
+    VALUE buffer;
+    const unsigned char *p;
+
+    if (rb_scan_args(argc, argv, "01", &buffer) == 0) {
+       return self;
+    }
+    StringValue(buffer);
+    if (!(spki = NETSCAPE_SPKI_b64_decode(RSTRING_PTR(buffer), -1))) {
+       p = (unsigned char *)RSTRING_PTR(buffer);
+       if (!(spki = d2i_NETSCAPE_SPKI(NULL, &p, RSTRING_LEN(buffer)))) {
+           ossl_raise(eSPKIError, NULL);
+       }
+    }
+    NETSCAPE_SPKI_free(DATA_PTR(self));
+    DATA_PTR(self) = spki;
+    ERR_clear_error();
+
+    return self;
+}
+
+static VALUE
+ossl_spki_to_der(VALUE self)
+{
+    NETSCAPE_SPKI *spki;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetSPKI(self, spki);
+    if ((len = i2d_NETSCAPE_SPKI(spki, NULL)) <= 0)
+        ossl_raise(eX509CertError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if (i2d_NETSCAPE_SPKI(spki, &p) <= 0)
+        ossl_raise(eX509CertError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+static VALUE
+ossl_spki_to_pem(VALUE self)
+{
+    NETSCAPE_SPKI *spki;
+    char *data;
+    VALUE str;
+
+    GetSPKI(self, spki);
+    if (!(data = NETSCAPE_SPKI_b64_encode(spki))) {
+       ossl_raise(eSPKIError, NULL);
+    }
+    str = ossl_buf2str(data, rb_long2int(strlen(data)));
+
+    return str;
+}
+
+static VALUE
+ossl_spki_print(VALUE self)
+{
+    NETSCAPE_SPKI *spki;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetSPKI(self, spki);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eSPKIError, NULL);
+    }
+    if (!NETSCAPE_SPKI_print(out, spki)) {
+       BIO_free(out);
+       ossl_raise(eSPKIError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+
+    return str;
+}
+
+static VALUE
+ossl_spki_get_public_key(VALUE self)
+{
+    NETSCAPE_SPKI *spki;
+    EVP_PKEY *pkey;
+
+    GetSPKI(self, spki);
+    if (!(pkey = NETSCAPE_SPKI_get_pubkey(spki))) { /* adds an reference */
+       ossl_raise(eSPKIError, NULL);
+    }
+
+    return ossl_pkey_new(pkey); /* NO DUP - OK */
+}
+
+static VALUE
+ossl_spki_set_public_key(VALUE self, VALUE key)
+{
+    NETSCAPE_SPKI *spki;
+
+    GetSPKI(self, spki);
+    if (!NETSCAPE_SPKI_set_pubkey(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
+       ossl_raise(eSPKIError, NULL);
+    }
+
+    return key;
+}
+
+static VALUE
+ossl_spki_get_challenge(VALUE self)
+{
+    NETSCAPE_SPKI *spki;
+
+    GetSPKI(self, spki);
+    if (spki->spkac->challenge->length <= 0) {
+       OSSL_Debug("Challenge.length <= 0?");
+       return rb_str_new(0, 0);
+    }
+
+    return rb_str_new((const char *)spki->spkac->challenge->data,
+                     spki->spkac->challenge->length);
+}
+
+static VALUE
+ossl_spki_set_challenge(VALUE self, VALUE str)
+{
+    NETSCAPE_SPKI *spki;
+
+    StringValue(str);
+    GetSPKI(self, spki);
+    if (!ASN1_STRING_set(spki->spkac->challenge, RSTRING_PTR(str),
+                        RSTRING_LENINT(str))) {
+       ossl_raise(eSPKIError, NULL);
+    }
+
+    return str;
+}
+
+static VALUE
+ossl_spki_sign(VALUE self, VALUE key, VALUE digest)
+{
+    NETSCAPE_SPKI *spki;
+    EVP_PKEY *pkey;
+    const EVP_MD *md;
+
+    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
+    md = GetDigestPtr(digest);
+    GetSPKI(self, spki);
+    if (!NETSCAPE_SPKI_sign(spki, pkey, md)) {
+       ossl_raise(eSPKIError, NULL);
+    }
+
+    return self;
+}
+
+/*
+ * Checks that cert signature is made with PRIVversion of this PUBLIC 'key'
+ */
+static VALUE
+ossl_spki_verify(VALUE self, VALUE key)
+{
+    NETSCAPE_SPKI *spki;
+
+    GetSPKI(self, spki);
+    switch (NETSCAPE_SPKI_verify(spki, GetPKeyPtr(key))) { /* NO NEED TO DUP */
+    case 0:
+       return Qfalse;
+    case 1:
+       return Qtrue;
+    default:
+       ossl_raise(eSPKIError, NULL);
+    }
+    return Qnil; /* dummy */
+}
+
+/*
+ * NETSCAPE_SPKI init
+ */
+void
+Init_ossl_ns_spki()
+{
+    mNetscape = rb_define_module_under(mOSSL, "Netscape");
+
+    eSPKIError = rb_define_class_under(mNetscape, "SPKIError", eOSSLError);
+
+    cSPKI = rb_define_class_under(mNetscape, "SPKI", rb_cObject);
+
+    rb_define_alloc_func(cSPKI, ossl_spki_alloc);
+    rb_define_method(cSPKI, "initialize", ossl_spki_initialize, -1);
+
+    rb_define_method(cSPKI, "to_der", ossl_spki_to_der, 0);
+    rb_define_method(cSPKI, "to_pem", ossl_spki_to_pem, 0);
+    rb_define_alias(cSPKI, "to_s", "to_pem");
+    rb_define_method(cSPKI, "to_text", ossl_spki_print, 0);
+    rb_define_method(cSPKI, "public_key", ossl_spki_get_public_key, 0);
+    rb_define_method(cSPKI, "public_key=", ossl_spki_set_public_key, 1);
+    rb_define_method(cSPKI, "sign", ossl_spki_sign, 2);
+    rb_define_method(cSPKI, "verify", ossl_spki_verify, 1);
+    rb_define_method(cSPKI, "challenge", ossl_spki_get_challenge, 0);
+    rb_define_method(cSPKI, "challenge=", ossl_spki_set_challenge, 1);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ns_spki.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ns_spki.h
new file mode 100644 (file)
index 0000000..9977035
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_NS_SPKI_H_)
+#define _OSSL_NS_SPKI_H_
+
+extern VALUE mNetscape;
+extern VALUE cSPKI;
+extern VALUE eSPKIError;
+
+void Init_ossl_ns_spki(void);
+
+#endif /* _OSSL_NS_SPKI_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ocsp.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ocsp.c
new file mode 100644 (file)
index 0000000..e82c2d8
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2003  Michal Rokos <m.rokos@sh.cvut.cz>
+ * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#if defined(OSSL_OCSP_ENABLED)
+
+#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)); \
+} while (0)
+#define GetOCSPReq(obj, req) do { \
+    Data_Get_Struct((obj), OCSP_REQUEST, (req)); \
+    if(!(req)) ossl_raise(rb_eRuntimeError, "Request wasn't initialized!"); \
+} while (0)
+#define SafeGetOCSPReq(obj, req) do { \
+    OSSL_Check_Kind((obj), cOCSPReq); \
+    GetOCSPReq((obj), (req)); \
+} while (0)
+
+#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)); \
+} while (0)
+#define GetOCSPRes(obj, res) do { \
+    Data_Get_Struct((obj), OCSP_RESPONSE, (res)); \
+    if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
+} while (0)
+#define SafeGetOCSPRes(obj, res) do { \
+    OSSL_Check_Kind((obj), cOCSPRes); \
+    GetOCSPRes((obj), (res)); \
+} while (0)
+
+#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)); \
+} while (0)
+#define GetOCSPBasicRes(obj, res) do { \
+    Data_Get_Struct((obj), OCSP_BASICRESP, (res)); \
+    if(!(res)) ossl_raise(rb_eRuntimeError, "Response wasn't initialized!"); \
+} while (0)
+#define SafeGetOCSPBasicRes(obj, res) do { \
+    OSSL_Check_Kind((obj), cOCSPBasicRes); \
+    GetOCSPBasicRes((obj), (res)); \
+} while (0)
+
+#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)); \
+} while (0)
+#define GetOCSPCertId(obj, cid) do { \
+    Data_Get_Struct((obj), OCSP_CERTID, (cid)); \
+    if(!(cid)) ossl_raise(rb_eRuntimeError, "Cert ID wasn't initialized!"); \
+} while (0)
+#define SafeGetOCSPCertId(obj, cid) do { \
+    OSSL_Check_Kind((obj), cOCSPCertId); \
+    GetOCSPCertId((obj), (cid)); \
+} while (0)
+
+VALUE mOCSP;
+VALUE eOCSPError;
+VALUE cOCSPReq;
+VALUE cOCSPRes;
+VALUE cOCSPBasicRes;
+VALUE cOCSPCertId;
+
+/*
+ * Public
+ */
+static VALUE
+ossl_ocspcertid_new(OCSP_CERTID *cid)
+{
+    VALUE obj;
+    WrapOCSPCertId(cOCSPCertId, obj, cid);
+    return obj;
+}
+
+/*
+ * OCSP::Resquest
+ */
+static VALUE
+ossl_ocspreq_alloc(VALUE klass)
+{
+    OCSP_REQUEST *req;
+    VALUE obj;
+
+    if (!(req = OCSP_REQUEST_new()))
+       ossl_raise(eOCSPError, NULL);
+    WrapOCSPReq(klass, obj, req);
+
+    return obj;
+}
+
+static VALUE
+ossl_ocspreq_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE arg;
+    const unsigned char *p;
+
+    rb_scan_args(argc, argv, "01", &arg);
+    if(!NIL_P(arg)){
+       OCSP_REQUEST *req = DATA_PTR(self), *x;
+       arg = ossl_to_der_if_possible(arg);
+       StringValue(arg);
+       p = (unsigned char*)RSTRING_PTR(arg);
+       x = d2i_OCSP_REQUEST(&req, &p, RSTRING_LEN(arg));
+       DATA_PTR(self) = req;
+       if(!x){
+           ossl_raise(eOCSPError, "cannot load DER encoded request");
+       }
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_ocspreq_add_nonce(int argc, VALUE *argv, VALUE self)
+{
+    OCSP_REQUEST *req;
+    VALUE val;
+    int ret;
+
+    rb_scan_args(argc, argv, "01", &val);
+    if(NIL_P(val)) {
+       GetOCSPReq(self, req);
+       ret = OCSP_request_add1_nonce(req, NULL, -1);
+    }
+    else{
+       StringValue(val);
+       GetOCSPReq(self, req);
+       ret = OCSP_request_add1_nonce(req, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+    }
+    if(!ret) ossl_raise(eOCSPError, NULL);
+
+    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.
+ *
+ *  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.
+ */
+static VALUE
+ossl_ocspreq_check_nonce(VALUE self, VALUE basic_resp)
+{
+    OCSP_REQUEST *req;
+    OCSP_BASICRESP *bs;
+    int res;
+
+    GetOCSPReq(self, req);
+    SafeGetOCSPBasicRes(basic_resp, bs);
+    res = OCSP_check_nonce(req, bs);
+
+    return INT2NUM(res);
+}
+
+static VALUE
+ossl_ocspreq_add_certid(VALUE self, VALUE certid)
+{
+    OCSP_REQUEST *req;
+    OCSP_CERTID *id;
+
+    GetOCSPReq(self, req);
+    GetOCSPCertId(certid, id);
+    if(!OCSP_request_add0_id(req, OCSP_CERTID_dup(id)))
+       ossl_raise(eOCSPError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_ocspreq_get_certid(VALUE self)
+{
+    OCSP_REQUEST *req;
+    OCSP_ONEREQ *one;
+    OCSP_CERTID *id;
+    VALUE ary, tmp;
+    int i, count;
+
+    GetOCSPReq(self, req);
+    count = OCSP_request_onereq_count(req);
+    ary = (count > 0) ? rb_ary_new() : Qnil;
+    for(i = 0; i < count; i++){
+       one = OCSP_request_onereq_get0(req, i);
+       if(!(id = OCSP_CERTID_dup(OCSP_onereq_get0_id(one))))
+           ossl_raise(eOCSPError, NULL);
+       WrapOCSPCertId(cOCSPCertId, tmp, id);
+       rb_ary_push(ary, tmp);
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_ocspreq_sign(int argc, VALUE *argv, VALUE self)
+{
+    VALUE signer_cert, signer_key, certs, flags;
+    OCSP_REQUEST *req;
+    X509 *signer;
+    EVP_PKEY *key;
+    STACK_OF(X509) *x509s;
+    unsigned long flg;
+    int ret;
+
+    rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
+    signer = GetX509CertPtr(signer_cert);
+    key = GetPrivPKeyPtr(signer_key);
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    if(NIL_P(certs)){
+       x509s = sk_X509_new_null();
+       flags |= OCSP_NOCERTS;
+    }
+    else x509s = ossl_x509_ary2sk(certs);
+    GetOCSPReq(self, req);
+    ret = OCSP_request_sign(req, signer, key, EVP_sha1(), x509s, flg);
+    sk_X509_pop_free(x509s, X509_free);
+    if(!ret) ossl_raise(eOCSPError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_ocspreq_verify(int argc, VALUE *argv, VALUE self)
+{
+    VALUE certs, store, flags;
+    OCSP_REQUEST *req;
+    STACK_OF(X509) *x509s;
+    X509_STORE *x509st;
+    int flg, result;
+
+    rb_scan_args(argc, argv, "21", &certs, &store, &flags);
+    x509st = GetX509StorePtr(store);
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    x509s = ossl_x509_ary2sk(certs);
+    GetOCSPReq(self, req);
+    result = OCSP_request_verify(req, x509s, x509st, flg);
+    sk_X509_pop_free(x509s, X509_free);
+    if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
+
+    return result ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_ocspreq_to_der(VALUE self)
+{
+    OCSP_REQUEST *req;
+    VALUE str;
+    unsigned char *p;
+    long len;
+
+    GetOCSPReq(self, req);
+    if((len = i2d_OCSP_REQUEST(req, NULL)) <= 0)
+       ossl_raise(eOCSPError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_OCSP_REQUEST(req, &p) <= 0)
+       ossl_raise(eOCSPError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ * OCSP::Response
+ */
+static VALUE
+ossl_ocspres_s_create(VALUE klass, VALUE status, VALUE basic_resp)
+{
+    OCSP_BASICRESP *bs;
+    OCSP_RESPONSE *res;
+    VALUE obj;
+    int st = NUM2INT(status);
+
+    if(NIL_P(basic_resp)) bs = NULL;
+    else GetOCSPBasicRes(basic_resp, bs); /* NO NEED TO DUP */
+    if(!(res = OCSP_response_create(st, bs)))
+       ossl_raise(eOCSPError, NULL);
+    WrapOCSPRes(klass, obj, res);
+
+    return obj;
+}
+
+static VALUE
+ossl_ocspres_alloc(VALUE klass)
+{
+    OCSP_RESPONSE *res;
+    VALUE obj;
+
+    if(!(res = OCSP_RESPONSE_new()))
+       ossl_raise(eOCSPError, NULL);
+    WrapOCSPRes(klass, obj, res);
+
+    return obj;
+}
+
+static VALUE
+ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE arg;
+    const unsigned char *p;
+
+    rb_scan_args(argc, argv, "01", &arg);
+    if(!NIL_P(arg)){
+       OCSP_RESPONSE *res = DATA_PTR(self), *x;
+       arg = ossl_to_der_if_possible(arg);
+       StringValue(arg);
+       p = (unsigned char *)RSTRING_PTR(arg);
+       x = d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg));
+       DATA_PTR(self) = res;
+       if(!x){
+           ossl_raise(eOCSPError, "cannot load DER encoded response");
+       }
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_ocspres_status(VALUE self)
+{
+    OCSP_RESPONSE *res;
+    int st;
+
+    GetOCSPRes(self, res);
+    st = OCSP_response_status(res);
+
+    return INT2NUM(st);
+}
+
+static VALUE
+ossl_ocspres_status_string(VALUE self)
+{
+    OCSP_RESPONSE *res;
+    int st;
+
+    GetOCSPRes(self, res);
+    st = OCSP_response_status(res);
+
+    return rb_str_new2(OCSP_response_status_str(st));
+}
+
+static VALUE
+ossl_ocspres_get_basic(VALUE self)
+{
+    OCSP_RESPONSE *res;
+    OCSP_BASICRESP *bs;
+    VALUE ret;
+
+    GetOCSPRes(self, res);
+    if(!(bs = OCSP_response_get1_basic(res)))
+       return Qnil;
+    WrapOCSPBasicRes(cOCSPBasicRes, ret, bs);
+
+    return ret;
+}
+
+static VALUE
+ossl_ocspres_to_der(VALUE self)
+{
+    OCSP_RESPONSE *res;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetOCSPRes(self, res);
+    if((len = i2d_OCSP_RESPONSE(res, NULL)) <= 0)
+       ossl_raise(eOCSPError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_OCSP_RESPONSE(res, &p) <= 0)
+       ossl_raise(eOCSPError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ * OCSP::BasicResponse
+ */
+static VALUE
+ossl_ocspbres_alloc(VALUE klass)
+{
+    OCSP_BASICRESP *bs;
+    VALUE obj;
+
+    if(!(bs = OCSP_BASICRESP_new()))
+       ossl_raise(eOCSPError, NULL);
+    WrapOCSPBasicRes(klass, obj, bs);
+
+    return obj;
+}
+
+static VALUE
+ossl_ocspbres_initialize(int argc, VALUE *argv, VALUE self)
+{
+    return self;
+}
+
+static VALUE
+ossl_ocspbres_copy_nonce(VALUE self, VALUE request)
+{
+    OCSP_BASICRESP *bs;
+    OCSP_REQUEST *req;
+    int ret;
+
+    GetOCSPBasicRes(self, bs);
+    SafeGetOCSPReq(request, req);
+    ret = OCSP_copy_nonce(bs, req);
+
+    return INT2NUM(ret);
+}
+
+static VALUE
+ossl_ocspbres_add_nonce(int argc, VALUE *argv, VALUE self)
+{
+    OCSP_BASICRESP *bs;
+    VALUE val;
+    int ret;
+
+    rb_scan_args(argc, argv, "01", &val);
+    if(NIL_P(val)) {
+       GetOCSPBasicRes(self, bs);
+       ret = OCSP_basic_add1_nonce(bs, NULL, -1);
+    }
+    else{
+       StringValue(val);
+       GetOCSPBasicRes(self, bs);
+       ret = OCSP_basic_add1_nonce(bs, (unsigned char *)RSTRING_PTR(val), RSTRING_LENINT(val));
+    }
+    if(!ret) ossl_raise(eOCSPError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_ocspbres_add_status(VALUE self, VALUE cid, VALUE status,
+                        VALUE reason, VALUE revtime,
+                        VALUE thisupd, VALUE nextupd, VALUE ext)
+{
+    OCSP_BASICRESP *bs;
+    OCSP_SINGLERESP *single;
+    OCSP_CERTID *id;
+    int st, rsn;
+    ASN1_TIME *ths, *nxt, *rev;
+    int error, i, rstatus = 0;
+    VALUE tmp;
+
+    st = NUM2INT(status);
+    rsn = NIL_P(status) ? 0 : NUM2INT(reason);
+    if(!NIL_P(ext)){
+       /* All ary's members should be X509Extension */
+       Check_Type(ext, T_ARRAY);
+       for (i = 0; i < RARRAY_LEN(ext); i++)
+           OSSL_Check_Kind(RARRAY_PTR(ext)[i], cX509Ext);
+    }
+
+    error = 0;
+    ths = nxt = rev = NULL;
+    if(!NIL_P(revtime)){
+       tmp = rb_protect(rb_Integer, revtime, &rstatus);
+       if(rstatus) goto err;
+       rev = X509_gmtime_adj(NULL, NUM2INT(tmp));
+    }
+    tmp = rb_protect(rb_Integer, thisupd, &rstatus);
+    if(rstatus) goto err;
+    ths = X509_gmtime_adj(NULL, NUM2INT(tmp));
+    tmp = rb_protect(rb_Integer, nextupd, &rstatus);
+    if(rstatus) goto err;
+    nxt = X509_gmtime_adj(NULL, NUM2INT(tmp));
+
+    GetOCSPBasicRes(self, bs);
+    SafeGetOCSPCertId(cid, id);
+    if(!(single = OCSP_basic_add1_status(bs, id, st, rsn, rev, ths, nxt))){
+       error = 1;
+       goto err;
+    }
+
+    if(!NIL_P(ext)){
+       X509_EXTENSION *x509ext;
+       sk_X509_EXTENSION_pop_free(single->singleExtensions, X509_EXTENSION_free);
+       single->singleExtensions = NULL;
+       for(i = 0; i < RARRAY_LEN(ext); i++){
+           x509ext = DupX509ExtPtr(RARRAY_PTR(ext)[i]);
+           if(!OCSP_SINGLERESP_add_ext(single, x509ext, -1)){
+               X509_EXTENSION_free(x509ext);
+               error = 1;
+               goto err;
+           }
+           X509_EXTENSION_free(x509ext);
+       }
+    }
+
+ err:
+    ASN1_TIME_free(ths);
+    ASN1_TIME_free(nxt);
+    ASN1_TIME_free(rev);
+    if(error) ossl_raise(eOCSPError, NULL);
+    if(rstatus) rb_jump_tag(rstatus);
+
+    return self;
+}
+
+static VALUE
+ossl_ocspbres_get_status(VALUE self)
+{
+    OCSP_BASICRESP *bs;
+    OCSP_SINGLERESP *single;
+    OCSP_CERTID *cid;
+    ASN1_TIME *revtime, *thisupd, *nextupd;
+    int status, reason;
+    X509_EXTENSION *x509ext;
+    VALUE ret, ary, ext;
+    int count, ext_count, i, j;
+
+    GetOCSPBasicRes(self, bs);
+    ret = rb_ary_new();
+    count = OCSP_resp_count(bs);
+    for(i = 0; i < count; i++){
+       single = OCSP_resp_get0(bs, i);
+       if(!single) continue;
+
+       revtime = thisupd = nextupd = NULL;
+       status = OCSP_single_get0_status(single, &reason, &revtime,
+                                        &thisupd, &nextupd);
+       if(status < 0) continue;
+       if(!(cid = OCSP_CERTID_dup(single->certId)))
+           ossl_raise(eOCSPError, NULL);
+       ary = rb_ary_new();
+       rb_ary_push(ary, ossl_ocspcertid_new(cid));
+       rb_ary_push(ary, INT2NUM(status));
+       rb_ary_push(ary, INT2NUM(reason));
+       rb_ary_push(ary, revtime ? asn1time_to_time(revtime) : Qnil);
+       rb_ary_push(ary, thisupd ? asn1time_to_time(thisupd) : Qnil);
+       rb_ary_push(ary, nextupd ? asn1time_to_time(nextupd) : Qnil);
+       ext = rb_ary_new();
+       ext_count = OCSP_SINGLERESP_get_ext_count(single);
+       for(j = 0; j < ext_count; j++){
+           x509ext = OCSP_SINGLERESP_get_ext(single, j);
+           rb_ary_push(ext, ossl_x509ext_new(x509ext));
+       }
+       rb_ary_push(ary, ext);
+       rb_ary_push(ret, ary);
+    }
+
+    return ret;
+}
+
+static VALUE
+ossl_ocspbres_sign(int argc, VALUE *argv, VALUE self)
+{
+    VALUE signer_cert, signer_key, certs, flags;
+    OCSP_BASICRESP *bs;
+    X509 *signer;
+    EVP_PKEY *key;
+    STACK_OF(X509) *x509s;
+    unsigned long flg;
+    int ret;
+
+    rb_scan_args(argc, argv, "22", &signer_cert, &signer_key, &certs, &flags);
+    signer = GetX509CertPtr(signer_cert);
+    key = GetPrivPKeyPtr(signer_key);
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    if(NIL_P(certs)){
+       x509s = sk_X509_new_null();
+       flg |= OCSP_NOCERTS;
+    }
+    else{
+       x509s = ossl_x509_ary2sk(certs);
+    }
+    GetOCSPBasicRes(self, bs);
+    ret = OCSP_basic_sign(bs, signer, key, EVP_sha1(), x509s, flg);
+    sk_X509_pop_free(x509s, X509_free);
+    if(!ret) ossl_raise(eOCSPError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_ocspbres_verify(int argc, VALUE *argv, VALUE self)
+{
+    VALUE certs, store, flags, result;
+    OCSP_BASICRESP *bs;
+    STACK_OF(X509) *x509s;
+    X509_STORE *x509st;
+    int flg;
+
+    rb_scan_args(argc, argv, "21", &certs, &store, &flags);
+    x509st = GetX509StorePtr(store);
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    x509s = ossl_x509_ary2sk(certs);
+    GetOCSPBasicRes(self, bs);
+    result = OCSP_basic_verify(bs, x509s, x509st, flg) > 0 ? Qtrue : Qfalse;
+    sk_X509_pop_free(x509s, X509_free);
+    if(!result) rb_warn("%s", ERR_error_string(ERR_peek_error(), NULL));
+
+    return result;
+}
+
+/*
+ * OCSP::CertificateId
+ */
+static VALUE
+ossl_ocspcid_alloc(VALUE klass)
+{
+    OCSP_CERTID *id;
+    VALUE obj;
+
+    if(!(id = OCSP_CERTID_new()))
+       ossl_raise(eOCSPError, NULL);
+    WrapOCSPCertId(klass, obj, id);
+
+    return obj;
+}
+
+static VALUE
+ossl_ocspcid_initialize(int argc, VALUE *argv, VALUE self)
+{
+    OCSP_CERTID *id, *newid;
+    X509 *x509s, *x509i;
+    VALUE subject, issuer, digest;
+    const EVP_MD *md;
+
+    if (rb_scan_args(argc, argv, "21", &subject, &issuer, &digest) == 0) {
+       return self;
+    }
+
+    x509s = GetX509CertPtr(subject); /* NO NEED TO DUP */
+    x509i = GetX509CertPtr(issuer); /* NO NEED TO DUP */
+
+    if (!NIL_P(digest)) {
+       md = GetDigestPtr(digest);
+       newid = OCSP_cert_to_id(md, x509s, x509i);
+    } else {
+       newid = OCSP_cert_to_id(NULL, x509s, x509i);
+    }
+    if(!newid)
+       ossl_raise(eOCSPError, NULL);
+    GetOCSPCertId(self, id);
+    OCSP_CERTID_free(id);
+    RDATA(self)->data = newid;
+
+    return self;
+}
+
+static VALUE
+ossl_ocspcid_cmp(VALUE self, VALUE other)
+{
+    OCSP_CERTID *id, *id2;
+    int result;
+
+    GetOCSPCertId(self, id);
+    SafeGetOCSPCertId(other, id2);
+    result = OCSP_id_cmp(id, id2);
+
+    return (result == 0) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_ocspcid_cmp_issuer(VALUE self, VALUE other)
+{
+    OCSP_CERTID *id, *id2;
+    int result;
+
+    GetOCSPCertId(self, id);
+    SafeGetOCSPCertId(other, id2);
+    result = OCSP_id_issuer_cmp(id, id2);
+
+    return (result == 0) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_ocspcid_get_serial(VALUE self)
+{
+    OCSP_CERTID *id;
+
+    GetOCSPCertId(self, id);
+
+    return asn1integer_to_num(id->serialNumber);
+}
+
+void
+Init_ossl_ocsp()
+{
+    mOCSP = rb_define_module_under(mOSSL, "OCSP");
+
+    eOCSPError = rb_define_class_under(mOCSP, "OCSPError", eOSSLError);
+
+    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);
+    rb_define_method(cOCSPReq, "add_nonce", ossl_ocspreq_add_nonce, -1);
+    rb_define_method(cOCSPReq, "check_nonce", ossl_ocspreq_check_nonce, 1);
+    rb_define_method(cOCSPReq, "add_certid", ossl_ocspreq_add_certid, 1);
+    rb_define_method(cOCSPReq, "certid", ossl_ocspreq_get_certid, 0);
+    rb_define_method(cOCSPReq, "sign", ossl_ocspreq_sign, -1);
+    rb_define_method(cOCSPReq, "verify", ossl_ocspreq_verify, -1);
+    rb_define_method(cOCSPReq, "to_der", ossl_ocspreq_to_der, 0);
+
+    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);
+    rb_define_method(cOCSPRes, "initialize", ossl_ocspres_initialize, -1);
+    rb_define_method(cOCSPRes, "status", ossl_ocspres_status, 0);
+    rb_define_method(cOCSPRes, "status_string", ossl_ocspres_status_string, 0);
+    rb_define_method(cOCSPRes, "basic", ossl_ocspres_get_basic, 0);
+    rb_define_method(cOCSPRes, "to_der", ossl_ocspres_to_der, 0);
+
+    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);
+    rb_define_method(cOCSPBasicRes, "copy_nonce", ossl_ocspbres_copy_nonce, 1);
+    rb_define_method(cOCSPBasicRes, "add_nonce", ossl_ocspbres_add_nonce, -1);
+    rb_define_method(cOCSPBasicRes, "add_status", ossl_ocspbres_add_status, 7);
+    rb_define_method(cOCSPBasicRes, "status", ossl_ocspbres_get_status, 0);
+    rb_define_method(cOCSPBasicRes, "sign", ossl_ocspbres_sign, -1);
+    rb_define_method(cOCSPBasicRes, "verify", ossl_ocspbres_verify, -1);
+
+    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);
+    rb_define_method(cOCSPCertId, "cmp", ossl_ocspcid_cmp, 1);
+    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);
+}
+
+#else /* ! OSSL_OCSP_ENABLED */
+void
+Init_ossl_ocsp()
+{
+}
+#endif
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ocsp.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ocsp.h
new file mode 100644 (file)
index 0000000..65b4f2e
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2003  Michal Rokos <m.rokos@sh.cvut.cz>
+ * Copyright (C) 2003  GOTOU Yuuzou <gotoyuzo@notwork.org>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_OCSP_H_)
+#define _OSSL_OCSP_H_
+
+#if defined(OSSL_OCSP_ENABLED)
+extern VALUE mOCSP;
+extern VALUE cOPCSReq;
+extern VALUE cOPCSRes;
+extern VALUE cOPCSBasicRes;
+#endif
+
+void Init_ossl_ocsp(void);
+
+#endif /* _OSSL_OCSP_H_ */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs12.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs12.c
new file mode 100644 (file)
index 0000000..8a5f816
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ * $Id$
+ */
+#include "ossl.h"
+
+#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)); \
+} while (0)
+
+#define GetPKCS12(obj, p12) do { \
+    Data_Get_Struct((obj), PKCS12, (p12)); \
+    if(!(p12)) ossl_raise(rb_eRuntimeError, "PKCS12 wasn't initialized."); \
+} while (0)
+
+#define SafeGetPKCS12(obj, p12) do { \
+    OSSL_Check_Kind((obj), cPKCS12); \
+    GetPKCS12((obj), (p12)); \
+} while (0)
+
+#define ossl_pkcs12_set_key(o,v)      rb_iv_set((o), "@key", (v))
+#define ossl_pkcs12_set_cert(o,v)     rb_iv_set((o), "@certificate", (v))
+#define ossl_pkcs12_set_ca_certs(o,v) rb_iv_set((o), "@ca_certs", (v))
+#define ossl_pkcs12_get_key(o)        rb_iv_get((o), "@key")
+#define ossl_pkcs12_get_cert(o)       rb_iv_get((o), "@certificate")
+#define ossl_pkcs12_get_ca_certs(o)   rb_iv_get((o), "@ca_certs")
+
+/*
+ * Classes
+ */
+VALUE cPKCS12;
+VALUE ePKCS12Error;
+
+/*
+ * Private
+ */
+static VALUE
+ossl_pkcs12_s_allocate(VALUE klass)
+{
+    PKCS12 *p12;
+    VALUE obj;
+
+    if(!(p12 = PKCS12_new())) ossl_raise(ePKCS12Error, NULL);
+    WrapPKCS12(klass, obj, p12);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    PKCS12.create(pass, name, key, cert [, ca, [, key_pbe [, cert_pbe [, key_iter [, mac_iter [, keytype]]]]]])
+ *
+ * === Parameters
+ * * +pass+ - string
+ * * +name+ - A string describing the key.
+ * * +key+ - Any PKey.
+ * * +cert+ - A X509::Certificate.
+ * * * The public_key portion of the certificate must contain a valid public key.
+ * * * The not_before and not_after fields must be filled in.
+ * * +ca+ - An optional array of X509::Certificate's.
+ * * +key_pbe+ - string
+ * * +cert_pbe+ - string
+ * * +key_iter+ - integer
+ * * +mac_iter+ - integer
+ * * +keytype+ - An integer representing an MSIE specific extension.
+ *
+ * Any optional arguments may be supplied as nil to preserve the OpenSSL defaults.
+ *
+ * See the OpenSSL documentation for PKCS12_create().
+ */
+static VALUE
+ossl_pkcs12_s_create(int argc, VALUE *argv, VALUE self)
+{
+    VALUE pass, name, pkey, cert, ca, key_nid, cert_nid, key_iter, mac_iter, keytype;
+    VALUE obj;
+    char *passphrase, *friendlyname;
+    EVP_PKEY *key;
+    X509 *x509;
+    STACK_OF(X509) *x509s;
+    int nkey = 0, ncert = 0, kiter = 0, miter = 0, ktype = 0;
+    PKCS12 *p12;
+
+    rb_scan_args(argc, argv, "46", &pass, &name, &pkey, &cert, &ca, &key_nid, &cert_nid, &key_iter, &mac_iter, &keytype);
+    passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass);
+    friendlyname = NIL_P(name) ? NULL : StringValuePtr(name);
+    key = GetPKeyPtr(pkey);
+    x509 = GetX509CertPtr(cert);
+    x509s = NIL_P(ca) ? NULL : ossl_x509_ary2sk(ca);
+/* TODO: make a VALUE to nid function */
+    if (!NIL_P(key_nid)) {
+        if ((nkey = OBJ_txt2nid(StringValuePtr(key_nid))) == NID_undef)
+            ossl_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(key_nid));
+    }
+    if (!NIL_P(cert_nid)) {
+        if ((ncert = OBJ_txt2nid(StringValuePtr(cert_nid))) == NID_undef)
+            ossl_raise(rb_eArgError, "Unknown PBE algorithm %s", StringValuePtr(cert_nid));
+    }
+    if (!NIL_P(key_iter))
+        kiter = NUM2INT(key_iter);
+    if (!NIL_P(mac_iter))
+        miter = NUM2INT(mac_iter);
+    if (!NIL_P(keytype))
+        ktype = NUM2INT(keytype);
+
+    p12 = PKCS12_create(passphrase, friendlyname, key, x509, x509s,
+                        nkey, ncert, kiter, miter, ktype);
+    sk_X509_pop_free(x509s, X509_free);
+    if(!p12) ossl_raise(ePKCS12Error, NULL);
+    WrapPKCS12(cPKCS12, obj, p12);
+
+    ossl_pkcs12_set_key(obj, pkey);
+    ossl_pkcs12_set_cert(obj, cert);
+    ossl_pkcs12_set_ca_certs(obj, ca);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    PKCS12.new -> pkcs12
+ *    PKCS12.new(str) -> pkcs12
+ *    PKCS12.new(str, pass) -> pkcs12
+ *
+ * === Parameters
+ * * +str+ - Must be a DER encoded PKCS12 string.
+ * * +pass+ - string
+ */
+static VALUE
+ossl_pkcs12_initialize(int argc, VALUE *argv, VALUE self)
+{
+    BIO *in;
+    VALUE arg, pass, pkey, cert, ca;
+    char *passphrase;
+    EVP_PKEY *key;
+    X509 *x509;
+    STACK_OF(X509) *x509s = NULL;
+    int st = 0;
+    PKCS12 *pkcs = DATA_PTR(self);
+
+    if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) return self;
+    passphrase = NIL_P(pass) ? NULL : StringValuePtr(pass);
+    in = ossl_obj2bio(arg);
+    d2i_PKCS12_bio(in, &pkcs);
+    DATA_PTR(self) = pkcs;
+    BIO_free(in);
+
+    pkey = cert = ca = Qnil;
+    if(!PKCS12_parse(pkcs, passphrase, &key, &x509, &x509s))
+       ossl_raise(ePKCS12Error, "PKCS12_parse");
+    pkey = rb_protect((VALUE(*)_((VALUE)))ossl_pkey_new, (VALUE)key,
+                     &st); /* NO DUP */
+    if(st) goto err;
+    cert = rb_protect((VALUE(*)_((VALUE)))ossl_x509_new, (VALUE)x509, &st);
+    if(st) goto err;
+    if(x509s){
+       ca =
+           rb_protect((VALUE(*)_((VALUE)))ossl_x509_sk2ary, (VALUE)x509s, &st);
+       if(st) goto err;
+    }
+
+  err:
+    X509_free(x509);
+    sk_X509_pop_free(x509s, X509_free);
+    ossl_pkcs12_set_key(self, pkey);
+    ossl_pkcs12_set_cert(self, cert);
+    ossl_pkcs12_set_ca_certs(self, ca);
+    if(st) rb_jump_tag(st);
+
+    return self;
+}
+
+static VALUE
+ossl_pkcs12_to_der(VALUE self)
+{
+    PKCS12 *p12;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetPKCS12(self, p12);
+    if((len = i2d_PKCS12(p12, NULL)) <= 0)
+       ossl_raise(ePKCS12Error, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_PKCS12(p12, &p) <= 0)
+       ossl_raise(ePKCS12Error, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+void
+Init_ossl_pkcs12()
+{
+    /*
+     * Defines a file format commonly used to store private keys with
+     * accompanying public key certificates, protected with a password-based
+     * symmetric key.
+     */
+    cPKCS12 = rb_define_class_under(mOSSL, "PKCS12", rb_cObject);
+    ePKCS12Error = rb_define_class_under(cPKCS12, "PKCS12Error", eOSSLError);
+    rb_define_singleton_method(cPKCS12, "create", ossl_pkcs12_s_create, -1);
+
+    rb_define_alloc_func(cPKCS12, ossl_pkcs12_s_allocate);
+    rb_attr(cPKCS12, rb_intern("key"), 1, 0, Qfalse);
+    rb_attr(cPKCS12, rb_intern("certificate"), 1, 0, Qfalse);
+    rb_attr(cPKCS12, rb_intern("ca_certs"), 1, 0, Qfalse);
+    rb_define_method(cPKCS12, "initialize", ossl_pkcs12_initialize, -1);
+    rb_define_method(cPKCS12, "to_der", ossl_pkcs12_to_der, 0);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs12.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs12.h
new file mode 100644 (file)
index 0000000..24d25d0
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ * $Id$
+ */
+#if !defined(_OSSL_PKCS12_H_)
+#define _OSSL_PKCS12_H_
+
+extern VALUE cPKCS12;
+extern VALUE ePKCS12Error;
+
+void Init_ossl_pkcs12(void);
+
+#endif /* _OSSL_PKCS12_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs5.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs5.c
new file mode 100644 (file)
index 0000000..d3eaf2d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * $Id$
+ * Copyright (C) 2007 Technorama Ltd. <oss-ruby@technorama.net>
+ */
+#include "ossl.h"
+
+VALUE mPKCS5;
+VALUE ePKCS5;
+
+#ifdef HAVE_PKCS5_PBKDF2_HMAC
+/*
+ * call-seq:
+ *    PKCS5.pbkdf2_hmac(pass, salt, iter, keylen, digest) => string
+ *
+ * === Parameters
+ * * +pass+ - string
+ * * +salt+ - string
+ * * +iter+ - integer - should be greater than 1000.  2000 is better.
+ * * +keylen+ - integer
+ * * +digest+ - a string or OpenSSL::Digest object.
+ *
+ * Available in OpenSSL 0.9.9?.
+ *
+ * Digests other than SHA1 may not be supported by other cryptography libraries.
+ */
+static VALUE
+ossl_pkcs5_pbkdf2_hmac(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen, VALUE digest)
+{
+    VALUE str;
+    const EVP_MD *md;
+    int len = NUM2INT(keylen);
+
+    StringValue(pass);
+    StringValue(salt);
+    md = GetDigestPtr(digest);
+
+    str = rb_str_new(0, len);
+
+    if (PKCS5_PBKDF2_HMAC(RSTRING_PTR(pass), RSTRING_LEN(pass),
+                         (unsigned char *)RSTRING_PTR(salt), RSTRING_LEN(salt),
+                         NUM2INT(iter), md, len,
+                         (unsigned char *)RSTRING_PTR(str)) != 1)
+        ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC");
+
+    return str;
+}
+#else
+#define ossl_pkcs5_pbkdf2_hmac rb_f_notimplement
+#endif
+
+
+#ifdef HAVE_PKCS5_PBKDF2_HMAC_SHA1
+/*
+ * call-seq:
+ *    PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, keylen) => string
+ *
+ * === Parameters
+ * * +pass+ - string
+ * * +salt+ - string
+ * * +iter+ - integer - should be greater than 1000.  2000 is better.
+ * * +keylen+ - integer
+ *
+ * This method is available almost any version OpenSSL.
+ *
+ * Conforms to rfc2898.
+ */
+static VALUE
+ossl_pkcs5_pbkdf2_hmac_sha1(VALUE self, VALUE pass, VALUE salt, VALUE iter, VALUE keylen)
+{
+    VALUE str;
+    int len = NUM2INT(keylen);
+
+    StringValue(pass);
+    StringValue(salt);
+
+    str = rb_str_new(0, len);
+
+    if (PKCS5_PBKDF2_HMAC_SHA1(RSTRING_PTR(pass), RSTRING_LENINT(pass),
+                              (const unsigned char *)RSTRING_PTR(salt), RSTRING_LENINT(salt), NUM2INT(iter),
+                              len, (unsigned char *)RSTRING_PTR(str)) != 1)
+        ossl_raise(ePKCS5, "PKCS5_PBKDF2_HMAC_SHA1");
+
+    return str;
+}
+#else
+#define ossl_pkcs5_pbkdf2_hmac_sha1 rb_f_notimplement
+#endif
+
+void
+Init_ossl_pkcs5()
+{
+    /*
+     * Password-based Encryption
+     *
+     */
+    mPKCS5 = rb_define_module_under(mOSSL, "PKCS5");
+    ePKCS5 = rb_define_class_under(mPKCS5, "PKCS5Error", eOSSLError);
+
+    rb_define_module_function(mPKCS5, "pbkdf2_hmac", ossl_pkcs5_pbkdf2_hmac, 5);
+    rb_define_module_function(mPKCS5, "pbkdf2_hmac_sha1", ossl_pkcs5_pbkdf2_hmac_sha1, 4);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs5.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs5.h
new file mode 100644 (file)
index 0000000..a3b132b
--- /dev/null
@@ -0,0 +1,6 @@
+#if !defined(_OSSL_PKCS5_H_)
+#define _OSSL_PKCS5_H_
+
+void Init_ossl_pkcs5(void);
+
+#endif /* _OSSL_PKCS5_H_ */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs7.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs7.c
new file mode 100644 (file)
index 0000000..b710280
--- /dev/null
@@ -0,0 +1,1046 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapPKCS7(klass, obj, pkcs7) do { \
+    if (!(pkcs7)) { \
+       ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, PKCS7_free, (pkcs7)); \
+} while (0)
+#define GetPKCS7(obj, pkcs7) do { \
+    Data_Get_Struct((obj), PKCS7, (pkcs7)); \
+    if (!(pkcs7)) { \
+       ossl_raise(rb_eRuntimeError, "PKCS7 wasn't initialized."); \
+    } \
+} while (0)
+#define SafeGetPKCS7(obj, pkcs7) do { \
+    OSSL_Check_Kind((obj), cPKCS7); \
+    GetPKCS7((obj), (pkcs7)); \
+} while (0)
+
+#define WrapPKCS7si(klass, obj, p7si) do { \
+    if (!(p7si)) { \
+       ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, PKCS7_SIGNER_INFO_free, (p7si)); \
+} while (0)
+#define GetPKCS7si(obj, p7si) do { \
+    Data_Get_Struct((obj), PKCS7_SIGNER_INFO, (p7si)); \
+    if (!(p7si)) { \
+       ossl_raise(rb_eRuntimeError, "PKCS7si wasn't initialized."); \
+    } \
+} while (0)
+#define SafeGetPKCS7si(obj, p7si) do { \
+    OSSL_Check_Kind((obj), cPKCS7Signer); \
+    GetPKCS7si((obj), (p7si)); \
+} while (0)
+
+#define WrapPKCS7ri(klass, obj, p7ri) do { \
+    if (!(p7ri)) { \
+       ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, PKCS7_RECIP_INFO_free, (p7ri)); \
+} while (0)
+#define GetPKCS7ri(obj, p7ri) do { \
+    Data_Get_Struct((obj), PKCS7_RECIP_INFO, (p7ri)); \
+    if (!(p7ri)) { \
+       ossl_raise(rb_eRuntimeError, "PKCS7ri wasn't initialized."); \
+    } \
+} while (0)
+#define SafeGetPKCS7ri(obj, p7ri) do { \
+    OSSL_Check_Kind((obj), cPKCS7Recipient); \
+    GetPKCS7ri((obj), (p7ri)); \
+} while (0)
+
+#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
+
+#define ossl_pkcs7_set_data(o,v)       rb_iv_set((o), "@data", (v))
+#define ossl_pkcs7_get_data(o)         rb_iv_get((o), "@data")
+#define ossl_pkcs7_set_err_string(o,v) rb_iv_set((o), "@error_string", (v))
+#define ossl_pkcs7_get_err_string(o)   rb_iv_get((o), "@error_string")
+
+/*
+ * Classes
+ */
+VALUE cPKCS7;
+VALUE cPKCS7Signer;
+VALUE cPKCS7Recipient;
+VALUE ePKCS7Error;
+
+/*
+ * Public
+ * (MADE PRIVATE UNTIL SOMEBODY WILL NEED THEM)
+ */
+static VALUE
+ossl_pkcs7si_new(PKCS7_SIGNER_INFO *p7si)
+{
+    PKCS7_SIGNER_INFO *pkcs7;
+    VALUE obj;
+
+    pkcs7 = p7si ? PKCS7_SIGNER_INFO_dup(p7si) : PKCS7_SIGNER_INFO_new();
+    if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
+    WrapPKCS7si(cPKCS7Signer, obj, pkcs7);
+
+    return obj;
+}
+
+static PKCS7_SIGNER_INFO *
+DupPKCS7SignerPtr(VALUE obj)
+{
+    PKCS7_SIGNER_INFO *p7si, *pkcs7;
+
+    SafeGetPKCS7si(obj, p7si);
+    if (!(pkcs7 = PKCS7_SIGNER_INFO_dup(p7si))) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return pkcs7;
+}
+
+static VALUE
+ossl_pkcs7ri_new(PKCS7_RECIP_INFO *p7ri)
+{
+    PKCS7_RECIP_INFO *pkcs7;
+    VALUE obj;
+
+    pkcs7 = p7ri ? PKCS7_RECIP_INFO_dup(p7ri) : PKCS7_RECIP_INFO_new();
+    if (!pkcs7) ossl_raise(ePKCS7Error, NULL);
+    WrapPKCS7ri(cPKCS7Recipient, obj, pkcs7);
+
+    return obj;
+}
+
+static PKCS7_RECIP_INFO *
+DupPKCS7RecipientPtr(VALUE obj)
+{
+    PKCS7_RECIP_INFO *p7ri, *pkcs7;
+
+    SafeGetPKCS7ri(obj, p7ri);
+    if (!(pkcs7 = PKCS7_RECIP_INFO_dup(p7ri))) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return pkcs7;
+}
+
+/*
+ * call-seq:
+ *    PKCS7.read_smime(string) => pkcs7
+ */
+static VALUE
+ossl_pkcs7_s_read_smime(VALUE klass, VALUE arg)
+{
+    BIO *in, *out;
+    PKCS7 *pkcs7;
+    VALUE ret, data;
+
+    in = ossl_obj2bio(arg);
+    out = NULL;
+    pkcs7 = SMIME_read_PKCS7(in, &out);
+    BIO_free(in);
+    if(!pkcs7) ossl_raise(ePKCS7Error, NULL);
+    data = out ? ossl_membio2str(out) : Qnil;
+    WrapPKCS7(cPKCS7, ret, pkcs7);
+    ossl_pkcs7_set_data(ret, data);
+    ossl_pkcs7_set_err_string(ret, Qnil);
+
+    return ret;
+}
+
+/*
+ * call-seq:
+ *    PKCS7.write_smime(pkcs7 [, data [, flags]]) => string
+ */
+static VALUE
+ossl_pkcs7_s_write_smime(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE pkcs7, data, flags;
+    BIO *out, *in;
+    PKCS7 *p7;
+    VALUE str;
+    int flg;
+
+    rb_scan_args(argc, argv, "12", &pkcs7, &data, &flags);
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    if(NIL_P(data)) data = ossl_pkcs7_get_data(pkcs7);
+    SafeGetPKCS7(pkcs7, p7);
+    if(!NIL_P(data) && PKCS7_is_detached(p7))
+       flg |= PKCS7_DETACHED;
+    in = NIL_P(data) ? NULL : ossl_obj2bio(data);
+    if(!(out = BIO_new(BIO_s_mem()))){
+        BIO_free(in);
+        ossl_raise(ePKCS7Error, NULL);
+    }
+    if(!SMIME_write_PKCS7(out, p7, in, flg)){
+        BIO_free(out);
+        BIO_free(in);
+        ossl_raise(ePKCS7Error, NULL);
+    }
+    BIO_free(in);
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    PKCS7.sign(cert, key, data, [, certs [, flags]]) => pkcs7
+ */
+static VALUE
+ossl_pkcs7_s_sign(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE cert, key, data, certs, flags;
+    X509 *x509;
+    EVP_PKEY *pkey;
+    BIO *in;
+    STACK_OF(X509) *x509s;
+    int flg, status = 0;
+    PKCS7 *pkcs7;
+    VALUE ret;
+
+    rb_scan_args(argc, argv, "32", &cert, &key, &data, &certs, &flags);
+    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
+    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    in = ossl_obj2bio(data);
+    if(NIL_P(certs)) x509s = NULL;
+    else{
+       x509s = ossl_protect_x509_ary2sk(certs, &status);
+       if(status){
+           BIO_free(in);
+           rb_jump_tag(status);
+       }
+    }
+    if(!(pkcs7 = PKCS7_sign(x509, pkey, x509s, in, flg))){
+       BIO_free(in);
+       sk_X509_pop_free(x509s, X509_free);
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    WrapPKCS7(cPKCS7, ret, pkcs7);
+    ossl_pkcs7_set_data(ret, data);
+    ossl_pkcs7_set_err_string(ret, Qnil);
+    BIO_free(in);
+    sk_X509_pop_free(x509s, X509_free);
+
+    return ret;
+}
+
+/*
+ * call-seq:
+ *    PKCS7.encrypt(certs, data, [, cipher [, flags]]) => pkcs7
+ */
+static VALUE
+ossl_pkcs7_s_encrypt(int argc, VALUE *argv, VALUE klass)
+{
+    VALUE certs, data, cipher, flags;
+    STACK_OF(X509) *x509s;
+    BIO *in;
+    const EVP_CIPHER *ciph;
+    int flg, status = 0;
+    VALUE ret;
+    PKCS7 *p7;
+
+    rb_scan_args(argc, argv, "22", &certs, &data, &cipher, &flags);
+    if(NIL_P(cipher)){
+#if !defined(OPENSSL_NO_RC2)
+       ciph = EVP_rc2_40_cbc();
+#elif !defined(OPENSSL_NO_DES)
+       ciph = EVP_des_ede3_cbc();
+#elif !defined(OPENSSL_NO_RC2)
+       ciph = EVP_rc2_40_cbc();
+#elif !defined(OPENSSL_NO_AES)
+       ciph = EVP_EVP_aes_128_cbc();
+#else
+       ossl_raise(ePKCS7Error, "Must specify cipher");
+#endif
+
+    }
+    else ciph = GetCipherPtr(cipher); /* NO NEED TO DUP */
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    in = ossl_obj2bio(data);
+    x509s = ossl_protect_x509_ary2sk(certs, &status);
+    if(status){
+       BIO_free(in);
+       rb_jump_tag(status);
+    }
+    if(!(p7 = PKCS7_encrypt(x509s, in, (EVP_CIPHER*)ciph, flg))){
+       BIO_free(in);
+       sk_X509_pop_free(x509s, X509_free);
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    BIO_free(in);
+    WrapPKCS7(cPKCS7, ret, p7);
+    ossl_pkcs7_set_data(ret, data);
+    sk_X509_pop_free(x509s, X509_free);
+
+    return ret;
+}
+
+static VALUE
+ossl_pkcs7_alloc(VALUE klass)
+{
+    PKCS7 *pkcs7;
+    VALUE obj;
+
+    if (!(pkcs7 = PKCS7_new())) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    WrapPKCS7(klass, obj, pkcs7);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    PKCS7.new => pkcs7
+ *    PKCS7.new(string) => pkcs7
+ *
+ * Many methods in this class aren't documented.
+ */
+static VALUE
+ossl_pkcs7_initialize(int argc, VALUE *argv, VALUE self)
+{
+    PKCS7 *p7, *pkcs = DATA_PTR(self);
+    BIO *in;
+    VALUE arg;
+
+    if(rb_scan_args(argc, argv, "01", &arg) == 0)
+       return self;
+    arg = ossl_to_der_if_possible(arg);
+    in = ossl_obj2bio(arg);
+    p7 = PEM_read_bio_PKCS7(in, &pkcs, NULL, NULL);
+    if (!p7) {
+       OSSL_BIO_reset(in);
+        p7 = d2i_PKCS7_bio(in, &pkcs);
+       if (!p7) {
+           BIO_free(in);
+           PKCS7_free(pkcs);
+           DATA_PTR(self) = NULL;
+           ossl_raise(rb_eArgError, "Could not parse the PKCS7");
+       }
+    }
+    DATA_PTR(self) = pkcs;
+    BIO_free(in);
+    ossl_pkcs7_set_data(self, Qnil);
+    ossl_pkcs7_set_err_string(self, Qnil);
+
+    return self;
+}
+
+static VALUE
+ossl_pkcs7_copy(VALUE self, VALUE other)
+{
+    PKCS7 *a, *b, *pkcs7;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+
+    GetPKCS7(self, a);
+    SafeGetPKCS7(other, b);
+
+    pkcs7 = PKCS7_dup(b);
+    if (!pkcs7) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    DATA_PTR(self) = pkcs7;
+    PKCS7_free(a);
+
+    return self;
+}
+
+static int
+ossl_pkcs7_sym2typeid(VALUE sym)
+{
+    int i, ret = Qnil;
+    const char *s;
+
+    static struct {
+        const char *name;
+        int nid;
+    } p7_type_tab[] = {
+        { "signed",             NID_pkcs7_signed },
+        { "data",               NID_pkcs7_data },
+        { "signedAndEnveloped", NID_pkcs7_signedAndEnveloped },
+        { "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)
+           ossl_raise(ePKCS7Error, "unknown type \"%s\"", s);
+       if(strcmp(p7_type_tab[i].name, s) == 0){
+           ret = p7_type_tab[i].nid;
+           break;
+       }
+    }
+
+    return ret;
+}
+
+/*
+ * call-seq:
+ *    pkcs7.type = type => type
+ */
+static VALUE
+ossl_pkcs7_set_type(VALUE self, VALUE type)
+{
+    PKCS7 *p7;
+
+    GetPKCS7(self, p7);
+    if(!PKCS7_set_type(p7, ossl_pkcs7_sym2typeid(type)))
+       ossl_raise(ePKCS7Error, NULL);
+
+    return type;
+}
+
+/*
+ * call-seq:
+ *    pkcs7.type => string or nil
+ */
+static VALUE
+ossl_pkcs7_get_type(VALUE self)
+{
+    PKCS7 *p7;
+
+    GetPKCS7(self, p7);
+    if(PKCS7_type_is_signed(p7))
+       return ID2SYM(rb_intern("signed"));
+    if(PKCS7_type_is_encrypted(p7))
+       return ID2SYM(rb_intern("encrypted"));
+    if(PKCS7_type_is_enveloped(p7))
+       return ID2SYM(rb_intern("enveloped"));
+    if(PKCS7_type_is_signedAndEnveloped(p7))
+       return ID2SYM(rb_intern("signedAndEnveloped"));
+    if(PKCS7_type_is_data(p7))
+       return ID2SYM(rb_intern("data"));
+    return Qnil;
+}
+
+static VALUE
+ossl_pkcs7_set_detached(VALUE self, VALUE flag)
+{
+    PKCS7 *p7;
+
+    GetPKCS7(self, p7);
+    if(flag != Qtrue && flag != Qfalse)
+       ossl_raise(ePKCS7Error, "must specify a boolean");
+    if(!PKCS7_set_detached(p7, flag == Qtrue ? 1 : 0))
+       ossl_raise(ePKCS7Error, NULL);
+
+    return flag;
+}
+
+static VALUE
+ossl_pkcs7_get_detached(VALUE self)
+{
+    PKCS7 *p7;
+    GetPKCS7(self, p7);
+    return PKCS7_get_detached(p7) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_pkcs7_detached_p(VALUE self)
+{
+    PKCS7 *p7;
+    GetPKCS7(self, p7);
+    return PKCS7_is_detached(p7) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_pkcs7_set_cipher(VALUE self, VALUE cipher)
+{
+    PKCS7 *pkcs7;
+
+    GetPKCS7(self, pkcs7);
+    if (!PKCS7_set_cipher(pkcs7, GetCipherPtr(cipher))) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return cipher;
+}
+
+static VALUE
+ossl_pkcs7_add_signer(VALUE self, VALUE signer)
+{
+    PKCS7 *pkcs7;
+    PKCS7_SIGNER_INFO *p7si;
+
+    p7si = DupPKCS7SignerPtr(signer); /* NEED TO DUP */
+    GetPKCS7(self, pkcs7);
+    if (!PKCS7_add_signer(pkcs7, p7si)) {
+       PKCS7_SIGNER_INFO_free(p7si);
+       ossl_raise(ePKCS7Error, "Could not add signer.");
+    }
+    if (PKCS7_type_is_signed(pkcs7)){
+       PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
+                                  V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data));
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_pkcs7_get_signer(VALUE self)
+{
+    PKCS7 *pkcs7;
+    STACK_OF(PKCS7_SIGNER_INFO) *sk;
+    PKCS7_SIGNER_INFO *si;
+    int num, i;
+    VALUE ary;
+
+    GetPKCS7(self, pkcs7);
+    if (!(sk = PKCS7_get_signer_info(pkcs7))) {
+       OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!");
+       return rb_ary_new();
+    }
+    if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) {
+       ossl_raise(ePKCS7Error, "Negative number of signers!");
+    }
+    ary = rb_ary_new2(num);
+    for (i=0; i<num; i++) {
+       si = sk_PKCS7_SIGNER_INFO_value(sk, i);
+       rb_ary_push(ary, ossl_pkcs7si_new(si));
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_pkcs7_add_recipient(VALUE self, VALUE recip)
+{
+    PKCS7 *pkcs7;
+    PKCS7_RECIP_INFO *ri;
+
+    ri = DupPKCS7RecipientPtr(recip); /* NEED TO DUP */
+    GetPKCS7(self, pkcs7);
+    if (!PKCS7_add_recipient_info(pkcs7, ri)) {
+       PKCS7_RECIP_INFO_free(ri);
+       ossl_raise(ePKCS7Error, "Could not add recipient.");
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_pkcs7_get_recipient(VALUE self)
+{
+    PKCS7 *pkcs7;
+    STACK_OF(PKCS7_RECIP_INFO) *sk;
+    PKCS7_RECIP_INFO *si;
+    int num, i;
+    VALUE ary;
+
+    GetPKCS7(self, pkcs7);
+    if (PKCS7_type_is_enveloped(pkcs7))
+       sk = pkcs7->d.enveloped->recipientinfo;
+    else if (PKCS7_type_is_signedAndEnveloped(pkcs7))
+       sk = pkcs7->d.signed_and_enveloped->recipientinfo;
+    else sk = NULL;
+    if (!sk) return rb_ary_new();
+    if ((num = sk_PKCS7_RECIP_INFO_num(sk)) < 0) {
+       ossl_raise(ePKCS7Error, "Negative number of recipient!");
+    }
+    ary = rb_ary_new2(num);
+    for (i=0; i<num; i++) {
+       si = sk_PKCS7_RECIP_INFO_value(sk, i);
+       rb_ary_push(ary, ossl_pkcs7ri_new(si));
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_pkcs7_add_certificate(VALUE self, VALUE cert)
+{
+    PKCS7 *pkcs7;
+    X509 *x509;
+
+    GetPKCS7(self, pkcs7);
+    x509 = GetX509CertPtr(cert);  /* NO NEED TO DUP */
+    if (!PKCS7_add_certificate(pkcs7, x509)){
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return self;
+}
+
+static STACK_OF(X509) *
+pkcs7_get_certs(VALUE self)
+{
+    PKCS7 *pkcs7;
+    STACK_OF(X509) *certs;
+    int i;
+
+    GetPKCS7(self, pkcs7);
+    i = OBJ_obj2nid(pkcs7->type);
+    switch(i){
+    case NID_pkcs7_signed:
+        certs = pkcs7->d.sign->cert;
+        break;
+    case NID_pkcs7_signedAndEnveloped:
+        certs = pkcs7->d.signed_and_enveloped->cert;
+        break;
+    default:
+        certs = NULL;
+    }
+
+    return certs;
+}
+
+static STACK_OF(X509_CRL) *
+pkcs7_get_crls(VALUE self)
+{
+    PKCS7 *pkcs7;
+    STACK_OF(X509_CRL) *crls;
+    int i;
+
+    GetPKCS7(self, pkcs7);
+    i = OBJ_obj2nid(pkcs7->type);
+    switch(i){
+    case NID_pkcs7_signed:
+        crls = pkcs7->d.sign->crl;
+        break;
+    case NID_pkcs7_signedAndEnveloped:
+        crls = pkcs7->d.signed_and_enveloped->crl;
+        break;
+    default:
+        crls = NULL;
+    }
+
+    return crls;
+}
+
+static VALUE
+ossl_pkcs7_set_certs_i(VALUE i, VALUE arg)
+{
+    return ossl_pkcs7_add_certificate(arg, i);
+}
+
+static VALUE
+ossl_pkcs7_set_certificates(VALUE self, VALUE ary)
+{
+    STACK_OF(X509) *certs;
+    X509 *cert;
+
+    certs = pkcs7_get_certs(self);
+    while((cert = sk_X509_pop(certs))) X509_free(cert);
+    rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_certs_i, self);
+
+    return ary;
+}
+
+static VALUE
+ossl_pkcs7_get_certificates(VALUE self)
+{
+    return ossl_x509_sk2ary(pkcs7_get_certs(self));
+}
+
+static VALUE
+ossl_pkcs7_add_crl(VALUE self, VALUE crl)
+{
+    PKCS7 *pkcs7;
+    X509_CRL *x509crl;
+
+    GetPKCS7(self, pkcs7); /* NO DUP needed! */
+    x509crl = GetX509CRLPtr(crl);
+    if (!PKCS7_add_crl(pkcs7, x509crl)) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_pkcs7_set_crls_i(VALUE i, VALUE arg)
+{
+    return ossl_pkcs7_add_crl(arg, i);
+}
+
+static VALUE
+ossl_pkcs7_set_crls(VALUE self, VALUE ary)
+{
+    STACK_OF(X509_CRL) *crls;
+    X509_CRL *crl;
+
+    crls = pkcs7_get_crls(self);
+    while((crl = sk_X509_CRL_pop(crls))) X509_CRL_free(crl);
+    rb_block_call(ary, rb_intern("each"), 0, 0, ossl_pkcs7_set_crls_i, self);
+
+    return ary;
+}
+
+static VALUE
+ossl_pkcs7_get_crls(VALUE self)
+{
+    return ossl_x509crl_sk2ary(pkcs7_get_crls(self));
+}
+
+static VALUE
+ossl_pkcs7_verify(int argc, VALUE *argv, VALUE self)
+{
+    VALUE certs, store, indata, flags;
+    STACK_OF(X509) *x509s;
+    X509_STORE *x509st;
+    int flg, ok, status = 0;
+    BIO *in, *out;
+    PKCS7 *p7;
+    VALUE data;
+    const char *msg;
+
+    rb_scan_args(argc, argv, "22", &certs, &store, &indata, &flags);
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    if(NIL_P(indata)) indata = ossl_pkcs7_get_data(self);
+    in = NIL_P(indata) ? NULL : ossl_obj2bio(indata);
+    if(NIL_P(certs)) x509s = NULL;
+    else{
+       x509s = ossl_protect_x509_ary2sk(certs, &status);
+       if(status){
+           BIO_free(in);
+           rb_jump_tag(status);
+       }
+    }
+    x509st = GetX509StorePtr(store);
+    GetPKCS7(self, p7);
+    if(!(out = BIO_new(BIO_s_mem()))){
+       BIO_free(in);
+       sk_X509_pop_free(x509s, X509_free);
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);
+    BIO_free(in);
+    if (ok < 0) ossl_raise(ePKCS7Error, NULL);
+    msg = ERR_reason_error_string(ERR_get_error());
+    ossl_pkcs7_set_err_string(self, msg ? rb_str_new2(msg) : Qnil);
+    ERR_clear_error();
+    data = ossl_membio2str(out);
+    ossl_pkcs7_set_data(self, data);
+    sk_X509_pop_free(x509s, X509_free);
+
+    return (ok == 1) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_pkcs7_decrypt(int argc, VALUE *argv, VALUE self)
+{
+    VALUE pkey, cert, flags;
+    EVP_PKEY *key;
+    X509 *x509;
+    int flg;
+    PKCS7 *p7;
+    BIO *out;
+    VALUE str;
+
+    rb_scan_args(argc, argv, "21", &pkey, &cert, &flags);
+    key = GetPrivPKeyPtr(pkey); /* NO NEED TO DUP */
+    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
+    flg = NIL_P(flags) ? 0 : NUM2INT(flags);
+    GetPKCS7(self, p7);
+    if(!(out = BIO_new(BIO_s_mem())))
+       ossl_raise(ePKCS7Error, NULL);
+    if(!PKCS7_decrypt(p7, key, x509, out, flg)){
+       BIO_free(out);
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    str = ossl_membio2str(out); /* out will be free */
+
+    return str;
+}
+
+static VALUE
+ossl_pkcs7_add_data(VALUE self, VALUE data)
+{
+    PKCS7 *pkcs7;
+    BIO *out, *in;
+    char buf[4096];
+    int len;
+
+    in = ossl_obj2bio(data);
+    GetPKCS7(self, pkcs7);
+    if(PKCS7_type_is_signed(pkcs7)){
+       if(!PKCS7_content_new(pkcs7, NID_pkcs7_data))
+           ossl_raise(ePKCS7Error, NULL);
+    }
+    if(!(out = PKCS7_dataInit(pkcs7, NULL))) goto err;
+    for(;;){
+       if((len = BIO_read(in, buf, sizeof(buf))) <= 0)
+           break;
+       if(BIO_write(out, buf, len) != len)
+           goto err;
+    }
+    if(!PKCS7_dataFinal(pkcs7, out)) goto err;
+    ossl_pkcs7_set_data(self, Qnil);
+
+ err:
+    BIO_free(out);
+    BIO_free(in);
+    if(ERR_peek_error()){
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return data;
+}
+
+static VALUE
+ossl_pkcs7_to_der(VALUE self)
+{
+    PKCS7 *pkcs7;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetPKCS7(self, pkcs7);
+    if((len = i2d_PKCS7(pkcs7, NULL)) <= 0)
+       ossl_raise(ePKCS7Error, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_PKCS7(pkcs7, &p) <= 0)
+       ossl_raise(ePKCS7Error, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+static VALUE
+ossl_pkcs7_to_pem(VALUE self)
+{
+    PKCS7 *pkcs7;
+    BIO *out;
+    VALUE str;
+
+    GetPKCS7(self, pkcs7);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    if (!PEM_write_bio_PKCS7(out, pkcs7)) {
+       BIO_free(out);
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ * SIGNER INFO
+ */
+static VALUE
+ossl_pkcs7si_alloc(VALUE klass)
+{
+    PKCS7_SIGNER_INFO *p7si;
+    VALUE obj;
+
+    if (!(p7si = PKCS7_SIGNER_INFO_new())) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    WrapPKCS7si(klass, obj, p7si);
+
+    return obj;
+}
+
+static VALUE
+ossl_pkcs7si_initialize(VALUE self, VALUE cert, VALUE key, VALUE digest)
+{
+    PKCS7_SIGNER_INFO *p7si;
+    EVP_PKEY *pkey;
+    X509 *x509;
+    const EVP_MD *md;
+
+    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
+    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
+    md = GetDigestPtr(digest);
+    GetPKCS7si(self, p7si);
+    if (!(PKCS7_SIGNER_INFO_set(p7si, x509, pkey, (EVP_MD*)md))) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_pkcs7si_get_issuer(VALUE self)
+{
+    PKCS7_SIGNER_INFO *p7si;
+
+    GetPKCS7si(self, p7si);
+
+    return ossl_x509name_new(p7si->issuer_and_serial->issuer);
+}
+
+static VALUE
+ossl_pkcs7si_get_serial(VALUE self)
+{
+    PKCS7_SIGNER_INFO *p7si;
+
+    GetPKCS7si(self, p7si);
+
+    return asn1integer_to_num(p7si->issuer_and_serial->serial);
+}
+
+static VALUE
+ossl_pkcs7si_get_signed_time(VALUE self)
+{
+    PKCS7_SIGNER_INFO *p7si;
+    ASN1_TYPE *asn1obj;
+
+    GetPKCS7si(self, p7si);
+
+    if (!(asn1obj = PKCS7_get_signed_attribute(p7si, NID_pkcs9_signingTime))) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    if (asn1obj->type == V_ASN1_UTCTIME) {
+       return asn1time_to_time(asn1obj->value.utctime);
+    }
+    /*
+     * OR
+     * ossl_raise(ePKCS7Error, "...");
+     * ?
+     */
+
+    return Qnil;
+}
+
+/*
+ * RECIPIENT INFO
+ */
+static VALUE
+ossl_pkcs7ri_alloc(VALUE klass)
+{
+    PKCS7_RECIP_INFO *p7ri;
+    VALUE obj;
+
+    if (!(p7ri = PKCS7_RECIP_INFO_new())) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+    WrapPKCS7ri(klass, obj, p7ri);
+
+    return obj;
+}
+
+static VALUE
+ossl_pkcs7ri_initialize(VALUE self, VALUE cert)
+{
+    PKCS7_RECIP_INFO *p7ri;
+    X509 *x509;
+
+    x509 = GetX509CertPtr(cert); /* NO NEED TO DUP */
+    GetPKCS7ri(self, p7ri);
+    if (!PKCS7_RECIP_INFO_set(p7ri, x509)) {
+       ossl_raise(ePKCS7Error, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_pkcs7ri_get_issuer(VALUE self)
+{
+    PKCS7_RECIP_INFO *p7ri;
+
+    GetPKCS7ri(self, p7ri);
+
+    return ossl_x509name_new(p7ri->issuer_and_serial->issuer);
+}
+
+static VALUE
+ossl_pkcs7ri_get_serial(VALUE self)
+{
+    PKCS7_RECIP_INFO *p7ri;
+
+    GetPKCS7ri(self, p7ri);
+
+    return asn1integer_to_num(p7ri->issuer_and_serial->serial);
+}
+
+static VALUE
+ossl_pkcs7ri_get_enc_key(VALUE self)
+{
+    PKCS7_RECIP_INFO *p7ri;
+
+    GetPKCS7ri(self, p7ri);
+
+    return asn1str_to_str(p7ri->enc_key);
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_pkcs7()
+{
+    cPKCS7 = rb_define_class_under(mOSSL, "PKCS7", rb_cObject);
+    ePKCS7Error = rb_define_class_under(cPKCS7, "PKCS7Error", eOSSLError);
+    rb_define_singleton_method(cPKCS7, "read_smime", ossl_pkcs7_s_read_smime, 1);
+    rb_define_singleton_method(cPKCS7, "write_smime", ossl_pkcs7_s_write_smime, -1);
+    rb_define_singleton_method(cPKCS7, "sign",  ossl_pkcs7_s_sign, -1);
+    rb_define_singleton_method(cPKCS7, "encrypt", ossl_pkcs7_s_encrypt, -1);
+    rb_attr(cPKCS7, rb_intern("data"), 1, 0, Qfalse);
+    rb_attr(cPKCS7, rb_intern("error_string"), 1, 1, Qfalse);
+    rb_define_alloc_func(cPKCS7, ossl_pkcs7_alloc);
+    rb_define_copy_func(cPKCS7, ossl_pkcs7_copy);
+    rb_define_method(cPKCS7, "initialize", ossl_pkcs7_initialize, -1);
+    rb_define_method(cPKCS7, "type=", ossl_pkcs7_set_type, 1);
+    rb_define_method(cPKCS7, "type", ossl_pkcs7_get_type, 0);
+    rb_define_method(cPKCS7, "detached=", ossl_pkcs7_set_detached, 1);
+    rb_define_method(cPKCS7, "detached", ossl_pkcs7_get_detached, 0);
+    rb_define_method(cPKCS7, "detached?", ossl_pkcs7_detached_p, 0);
+    rb_define_method(cPKCS7, "cipher=", ossl_pkcs7_set_cipher, 1);
+    rb_define_method(cPKCS7, "add_signer", ossl_pkcs7_add_signer, 1);
+    rb_define_method(cPKCS7, "signers", ossl_pkcs7_get_signer, 0);
+    rb_define_method(cPKCS7, "add_recipient", ossl_pkcs7_add_recipient, 1);
+    rb_define_method(cPKCS7, "recipients", ossl_pkcs7_get_recipient, 0);
+    rb_define_method(cPKCS7, "add_certificate", ossl_pkcs7_add_certificate, 1);
+    rb_define_method(cPKCS7, "certificates=", ossl_pkcs7_set_certificates, 1);
+    rb_define_method(cPKCS7, "certificates", ossl_pkcs7_get_certificates, 0);
+    rb_define_method(cPKCS7, "add_crl", ossl_pkcs7_add_crl, 1);
+    rb_define_method(cPKCS7, "crls=", ossl_pkcs7_set_crls, 1);
+    rb_define_method(cPKCS7, "crls", ossl_pkcs7_get_crls, 0);
+    rb_define_method(cPKCS7, "add_data", ossl_pkcs7_add_data, 1);
+    rb_define_alias(cPKCS7,  "data=", "add_data");
+    rb_define_method(cPKCS7, "verify", ossl_pkcs7_verify, -1);
+    rb_define_method(cPKCS7, "decrypt", ossl_pkcs7_decrypt, -1);
+    rb_define_method(cPKCS7, "to_pem", ossl_pkcs7_to_pem, 0);
+    rb_define_alias(cPKCS7,  "to_s", "to_pem");
+    rb_define_method(cPKCS7, "to_der", ossl_pkcs7_to_der, 0);
+
+    cPKCS7Signer = rb_define_class_under(cPKCS7, "SignerInfo", rb_cObject);
+    rb_define_const(cPKCS7, "Signer", cPKCS7Signer);
+    rb_define_alloc_func(cPKCS7Signer, ossl_pkcs7si_alloc);
+    rb_define_method(cPKCS7Signer, "initialize", ossl_pkcs7si_initialize,3);
+    rb_define_method(cPKCS7Signer, "issuer", ossl_pkcs7si_get_issuer, 0);
+    rb_define_alias(cPKCS7Signer, "name", "issuer");
+    rb_define_method(cPKCS7Signer, "serial", ossl_pkcs7si_get_serial,0);
+    rb_define_method(cPKCS7Signer,"signed_time",ossl_pkcs7si_get_signed_time,0);
+
+    cPKCS7Recipient = rb_define_class_under(cPKCS7,"RecipientInfo",rb_cObject);
+    rb_define_alloc_func(cPKCS7Recipient, ossl_pkcs7ri_alloc);
+    rb_define_method(cPKCS7Recipient, "initialize", ossl_pkcs7ri_initialize,1);
+    rb_define_method(cPKCS7Recipient, "issuer", ossl_pkcs7ri_get_issuer,0);
+    rb_define_method(cPKCS7Recipient, "serial", ossl_pkcs7ri_get_serial,0);
+    rb_define_method(cPKCS7Recipient, "enc_key", ossl_pkcs7ri_get_enc_key,0);
+
+#define DefPKCS7Const(x) rb_define_const(cPKCS7, #x, INT2NUM(PKCS7_##x))
+
+    DefPKCS7Const(TEXT);
+    DefPKCS7Const(NOCERTS);
+    DefPKCS7Const(NOSIGS);
+    DefPKCS7Const(NOCHAIN);
+    DefPKCS7Const(NOINTERN);
+    DefPKCS7Const(NOVERIFY);
+    DefPKCS7Const(DETACHED);
+    DefPKCS7Const(BINARY);
+    DefPKCS7Const(NOATTR);
+    DefPKCS7Const(NOSMIMECAP);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs7.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkcs7.h
new file mode 100644 (file)
index 0000000..371c421
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_PKCS7_H_)
+#define _OSSL_PKCS7_H_
+
+extern VALUE cPKCS7;
+extern VALUE cPKCS7Signer;
+extern VALUE cPKCS7Recipient;
+extern VALUE ePKCS7Error;
+
+void Init_ossl_pkcs7(void);
+
+#endif /* _OSSL_PKCS7_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey.c
new file mode 100644 (file)
index 0000000..f785e66
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@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 mPKey;
+VALUE cPKey;
+VALUE ePKeyError;
+ID id_private_q;
+
+/*
+ * callback for generating keys
+ */
+void
+ossl_generate_cb(int p, int n, void *arg)
+{
+    VALUE ary;
+
+    ary = rb_ary_new2(2);
+    rb_ary_store(ary, 0, INT2NUM(p));
+    rb_ary_store(ary, 1, INT2NUM(n));
+
+    rb_yield(ary);
+}
+
+/*
+ * Public
+ */
+VALUE
+ossl_pkey_new(EVP_PKEY *pkey)
+{
+    if (!pkey) {
+       ossl_raise(ePKeyError, "Cannot make new key from NULL.");
+    }
+    switch (EVP_PKEY_type(pkey->type)) {
+#if !defined(OPENSSL_NO_RSA)
+    case EVP_PKEY_RSA:
+       return ossl_rsa_new(pkey);
+#endif
+#if !defined(OPENSSL_NO_DSA)
+    case EVP_PKEY_DSA:
+       return ossl_dsa_new(pkey);
+#endif
+#if !defined(OPENSSL_NO_DH)
+    case EVP_PKEY_DH:
+       return ossl_dh_new(pkey);
+#endif
+#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
+    case EVP_PKEY_EC:
+       return ossl_ec_new(pkey);
+#endif
+    default:
+       ossl_raise(ePKeyError, "unsupported key type");
+    }
+    return Qnil; /* not reached */
+}
+
+VALUE
+ossl_pkey_new_from_file(VALUE filename)
+{
+    FILE *fp;
+    EVP_PKEY *pkey;
+
+    SafeStringValue(filename);
+    if (!(fp = fopen(RSTRING_PTR(filename), "r"))) {
+       ossl_raise(ePKeyError, "%s", strerror(errno));
+    }
+
+    pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL);
+    fclose(fp);
+    if (!pkey) {
+       ossl_raise(ePKeyError, NULL);
+    }
+
+    return ossl_pkey_new(pkey);
+}
+
+/*
+ *  call-seq:
+ *     OpenSSL::PKey.read(string [, pwd ] ) -> PKey
+ *     OpenSSL::PKey.read(file [, pwd ]) -> PKey
+ *
+ * === Parameters
+ * * +string+ is a DER- or PEM-encoded string containing an arbitrary private
+ * or public key.
+ * * +file+ is an instance of +File+ containing a DER- or PEM-encoded
+ * arbitrary private or public key.
+ * * +pwd+ is an optional password in case +string+ or +file+ is an encrypted
+ * PEM resource.
+ */
+static VALUE
+ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
+{
+     EVP_PKEY *pkey;
+     BIO *bio;
+     VALUE data, pass;
+     char *passwd = NULL;
+
+     rb_scan_args(argc, argv, "11", &data, &pass);
+
+     bio = ossl_obj2bio(data);
+     if (!(pkey = d2i_PrivateKey_bio(bio, NULL))) {
+       OSSL_BIO_reset(bio);
+       if (!NIL_P(pass)) {
+           passwd = StringValuePtr(pass);
+       }
+       if (!(pkey = PEM_read_bio_PrivateKey(bio, NULL, ossl_pem_passwd_cb, passwd))) {
+           OSSL_BIO_reset(bio);
+           if (!(pkey = d2i_PUBKEY_bio(bio, NULL))) {
+               OSSL_BIO_reset(bio);
+               if (!NIL_P(pass)) {
+                   passwd = StringValuePtr(pass);
+               }
+               pkey = PEM_read_bio_PUBKEY(bio, NULL, ossl_pem_passwd_cb, passwd);
+           }
+       }
+    }
+
+    BIO_free(bio);
+    if (!pkey)
+       ossl_raise(rb_eArgError, "Could not parse PKey");
+    return ossl_pkey_new(pkey);
+}
+
+EVP_PKEY *
+GetPKeyPtr(VALUE obj)
+{
+    EVP_PKEY *pkey;
+
+    SafeGetPKey(obj, pkey);
+
+    return pkey;
+}
+
+EVP_PKEY *
+GetPrivPKeyPtr(VALUE obj)
+{
+    EVP_PKEY *pkey;
+
+    if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) {
+       ossl_raise(rb_eArgError, "Private key is needed.");
+    }
+    SafeGetPKey(obj, pkey);
+
+    return pkey;
+}
+
+EVP_PKEY *
+DupPKeyPtr(VALUE obj)
+{
+    EVP_PKEY *pkey;
+
+    SafeGetPKey(obj, pkey);
+    CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+
+    return pkey;
+}
+
+EVP_PKEY *
+DupPrivPKeyPtr(VALUE obj)
+{
+    EVP_PKEY *pkey;
+
+    if (rb_funcall(obj, id_private_q, 0, NULL) != Qtrue) {
+       ossl_raise(rb_eArgError, "Private key is needed.");
+    }
+    SafeGetPKey(obj, pkey);
+    CRYPTO_add(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY);
+
+    return pkey;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_pkey_alloc(VALUE klass)
+{
+    EVP_PKEY *pkey;
+    VALUE obj;
+
+    if (!(pkey = EVP_PKEY_new())) {
+       ossl_raise(ePKeyError, NULL);
+    }
+    WrapPKey(klass, obj, pkey);
+
+    return obj;
+}
+
+/*
+ *  call-seq:
+ *      PKeyClass.new -> self
+ *
+ * Because PKey is an abstract class, actually calling this method explicitly
+ * will raise a +NotImplementedError+.
+ */
+static VALUE
+ossl_pkey_initialize(VALUE self)
+{
+    if (rb_obj_is_instance_of(self, cPKey)) {
+       ossl_raise(rb_eNotImpError, "OpenSSL::PKey::PKey is an abstract class.");
+    }
+    return self;
+}
+
+/*
+ *  call-seq:
+ *      pkey.sign(digest, data) -> String
+ *
+ * To sign the +String+ +data+, +digest+, an instance of OpenSSL::Digest, must
+ * be provided. The return value is again a +String+ containing the signature.
+ * A PKeyError is raised should errors occur.
+ * Any previous state of the +Digest+ instance is irrelevant to the signature
+ * outcome, the digest instance is reset to its initial state during the
+ * operation.
+ *
+ * == Example
+ *   data = 'Sign me!'
+ *   digest = OpenSSL::Digest::SHA256.new
+ *   pkey = OpenSSL::PKey::RSA.new(2048)
+ *   signature = pkey.sign(digest, data)
+ */
+static VALUE
+ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
+{
+    EVP_PKEY *pkey;
+    EVP_MD_CTX ctx;
+    unsigned int buf_len;
+    VALUE str;
+
+    if (rb_funcall(self, id_private_q, 0, NULL) != Qtrue) {
+       ossl_raise(rb_eArgError, "Private key is needed.");
+    }
+    GetPKey(self, pkey);
+    EVP_SignInit(&ctx, GetDigestPtr(digest));
+    StringValue(data);
+    EVP_SignUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
+    str = rb_str_new(0, EVP_PKEY_size(pkey)+16);
+    if (!EVP_SignFinal(&ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey))
+       ossl_raise(ePKeyError, NULL);
+    assert((long)buf_len <= RSTRING_LEN(str));
+    rb_str_set_len(str, buf_len);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *      pkey.verify(digest, signature, data) -> String
+ *
+ * To verify the +String+ +signature+, +digest+, an instance of
+ * OpenSSL::Digest, must be provided to re-compute the message digest of the
+ * original +data+, also a +String+. The return value is +true+ if the
+ * signature is valid, +false+ otherwise. A PKeyError is raised should errors
+ * occur.
+ * Any previous state of the +Digest+ instance is irrelevant to the validation
+ * outcome, the digest instance is reset to its initial state during the
+ * operation.
+ *
+ * == Example
+ *   data = 'Sign me!'
+ *   digest = OpenSSL::Digest::SHA256.new
+ *   pkey = OpenSSL::PKey::RSA.new(2048)
+ *   signature = pkey.sign(digest, data)
+ *   pub_key = pkey.public_key
+ *   puts pub_key.verify(digest, signature, data) # => true
+ */
+static VALUE
+ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
+{
+    EVP_PKEY *pkey;
+    EVP_MD_CTX ctx;
+
+    GetPKey(self, pkey);
+    EVP_VerifyInit(&ctx, GetDigestPtr(digest));
+    StringValue(sig);
+    StringValue(data);
+    EVP_VerifyUpdate(&ctx, RSTRING_PTR(data), RSTRING_LEN(data));
+    switch (EVP_VerifyFinal(&ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey)) {
+    case 0:
+       return Qfalse;
+    case 1:
+       return Qtrue;
+    default:
+       ossl_raise(ePKeyError, NULL);
+    }
+    return Qnil; /* dummy */
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_pkey()
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    /* Document-module: OpenSSL::PKey
+     *
+     * == Asymmetric Public Key Algorithms
+     *
+     * Asymmetric public key algorithms solve the problem of establishing and
+     * sharing secret keys to en-/decrypt messages. The key in such an
+     * algorithm consists of two parts: a public key that may be distributed
+     * to others and a private key that needs to remain secret.
+     *
+     * Messages encrypted with a public key can only be encrypted by
+     * recipients that are in possession of the associated private key.
+     * Since public key algorithms are considerably slower than symmetric
+     * key algorithms (cf. OpenSSL::Cipher) they are often used to establish
+     * a symmetric key shared between two parties that are in possession of
+     * each other's public key.
+     *
+     * Asymmetric algorithms offer a lot of nice features that are used in a
+     * lot of different areas. A very common application is the creation and
+     * validation of digital signatures. To sign a document, the signatory
+     * generally uses a message digest algorithm (cf. OpenSSL::Digest) to
+     * compute a digest of the document that is then encrypted (i.e. signed)
+     * using the private key. Anyone in possession of the public key may then
+     * verify the signature by computing the message digest of the original
+     * document on their own, decrypting the signature using the signatory's
+     * public key and comparing the result to the message digest they
+     * previously computed. The signature is valid if and only if the
+     * decrypted signature is equal to this message digest.
+     *
+     * The PKey module offers support for three popular public/private key
+     * algorithms:
+     * * RSA (OpenSSL::PKey::RSA)
+     * * DSA (OpenSSL::PKey::DSA)
+     * * Elliptic Curve Cryptography (OpenSSL::PKey::EC)
+     * Each of these implementations is in fact a sub-class of the abstract
+     * PKey class which offers the interface for supporting digital signatures
+     * in the form of PKey#sign and PKey#verify.
+     *
+     * == Diffie-Hellman Key Exchange
+     *
+     * Finally PKey also features OpenSSL::PKey::DH, an implementation of
+     * the Diffie-Hellman key exchange protocol based on discrete logarithms
+     * in finite fields, the same basis that DSA is built on.
+     * The Diffie-Hellman protocol can be used to exchange (symmetric) keys
+     * over insecure channels without needing any prior joint knowledge
+     * between the participating parties. As the security of DH demands
+     * relatively long "public keys" (i.e. the part that is overtly
+     * transmitted between participants) DH tends to be quite slow. If
+     * security or speed is your primary concern, OpenSSL::PKey::EC offers
+     * another implementation of the Diffie-Hellman protocol.
+     *
+     */
+    mPKey = rb_define_module_under(mOSSL, "PKey");
+
+    /* Document-class: OpenSSL::PKey::PKeyError
+     *
+     *Raised when errors occur during PKey#sign or PKey#verify.
+     */
+    ePKeyError = rb_define_class_under(mPKey, "PKeyError", eOSSLError);
+
+    /* Document-class: OpenSSL::PKey::PKey
+     *
+     * An abstract class that bundles signature creation (PKey#sign) and
+     * validation (PKey#verify) that is common to all implementations except
+     * OpenSSL::PKey::DH
+     * * OpenSSL::PKey::RSA
+     * * OpenSSL::PKey::DSA
+     * * OpenSSL::PKey::EC
+     */
+    cPKey = rb_define_class_under(mPKey, "PKey", rb_cObject);
+
+    rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
+
+    rb_define_alloc_func(cPKey, ossl_pkey_alloc);
+    rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
+
+    rb_define_method(cPKey, "sign", ossl_pkey_sign, 2);
+    rb_define_method(cPKey, "verify", ossl_pkey_verify, 3);
+
+    id_private_q = rb_intern("private?");
+
+    /*
+     * INIT rsa, dsa, dh, ec
+     */
+    Init_ossl_rsa();
+    Init_ossl_dsa();
+    Init_ossl_dh();
+    Init_ossl_ec();
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey.h
new file mode 100644 (file)
index 0000000..5e3329d
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_PKEY_H_)
+#define _OSSL_PKEY_H_
+
+extern VALUE mPKey;
+extern VALUE cPKey;
+extern VALUE ePKeyError;
+extern ID id_private_q;
+
+#define OSSL_PKEY_SET_PRIVATE(obj) rb_iv_set((obj), "private", Qtrue)
+#define OSSL_PKEY_SET_PUBLIC(obj)  rb_iv_set((obj), "private", Qfalse)
+#define OSSL_PKEY_IS_PRIVATE(obj)  (rb_iv_get((obj), "private") == Qtrue)
+
+#define WrapPKey(klass, obj, pkey) do { \
+    if (!(pkey)) { \
+       rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, EVP_PKEY_free, (pkey)); \
+    OSSL_PKEY_SET_PUBLIC(obj); \
+} while (0)
+#define GetPKey(obj, pkey) do {\
+    Data_Get_Struct((obj), EVP_PKEY, (pkey));\
+    if (!(pkey)) { \
+       rb_raise(rb_eRuntimeError, "PKEY wasn't initialized!");\
+    } \
+} while (0)
+#define SafeGetPKey(obj, pkey) do { \
+    OSSL_Check_Kind((obj), cPKey); \
+    GetPKey((obj), (pkey)); \
+} while (0)
+
+void ossl_generate_cb(int, int, void *);
+
+VALUE ossl_pkey_new(EVP_PKEY *);
+VALUE ossl_pkey_new_from_file(VALUE);
+EVP_PKEY *GetPKeyPtr(VALUE);
+EVP_PKEY *DupPKeyPtr(VALUE);
+EVP_PKEY *GetPrivPKeyPtr(VALUE);
+EVP_PKEY *DupPrivPKeyPtr(VALUE);
+void Init_ossl_pkey(void);
+
+/*
+ * RSA
+ */
+extern VALUE cRSA;
+extern VALUE eRSAError;
+
+VALUE ossl_rsa_new(EVP_PKEY *);
+void Init_ossl_rsa(void);
+
+/*
+ * DSA
+ */
+extern VALUE cDSA;
+extern VALUE eDSAError;
+
+VALUE ossl_dsa_new(EVP_PKEY *);
+void Init_ossl_dsa(void);
+
+/*
+ * DH
+ */
+extern VALUE cDH;
+extern VALUE eDHError;
+extern DH *OSSL_DEFAULT_DH_512;
+extern DH *OSSL_DEFAULT_DH_1024;
+
+VALUE ossl_dh_new(EVP_PKEY *);
+void Init_ossl_dh(void);
+
+/*
+ * EC
+ */
+extern VALUE cEC;
+extern VALUE eECError;
+extern VALUE cEC_GROUP;
+extern VALUE eEC_GROUP;
+extern VALUE cEC_POINT;
+extern VALUE eEC_POINT;
+VALUE ossl_ec_new(EVP_PKEY *);
+void Init_ossl_ec(void);
+
+
+#define OSSL_PKEY_BN(keytype, name)                                    \
+/*                                                                     \
+ *  call-seq:                                                          \
+ *     key.##name -> aBN                                               \
+ */                                                                    \
+static VALUE ossl_##keytype##_get_##name(VALUE self)                   \
+{                                                                      \
+       EVP_PKEY *pkey;                                                 \
+       BIGNUM *bn;                                                     \
+                                                                       \
+       GetPKey(self, pkey);                                            \
+       bn = pkey->pkey.keytype->name;                                  \
+       if (bn == NULL)                                                 \
+               return Qnil;                                            \
+       return ossl_bn_new(bn);                                         \
+}                                                                      \
+/*                                                                     \
+ *  call-seq:                                                          \
+ *     key.##name = bn -> bn                                           \
+ */                                                                    \
+static VALUE ossl_##keytype##_set_##name(VALUE self, VALUE bignum)     \
+{                                                                      \
+       EVP_PKEY *pkey;                                                 \
+       BIGNUM *bn;                                                     \
+                                                                       \
+       GetPKey(self, pkey);                                            \
+       if (NIL_P(bignum)) {                                            \
+               BN_clear_free(pkey->pkey.keytype->name);                \
+               pkey->pkey.keytype->name = NULL;                        \
+               return Qnil;                                            \
+       }                                                               \
+                                                                       \
+       bn = GetBNPtr(bignum);                                          \
+       if (pkey->pkey.keytype->name == NULL)                           \
+               pkey->pkey.keytype->name = BN_new();                    \
+       if (pkey->pkey.keytype->name == NULL)                           \
+               ossl_raise(eBNError, NULL);                             \
+       if (BN_copy(pkey->pkey.keytype->name, bn) == NULL)              \
+               ossl_raise(eBNError, NULL);                             \
+       return bignum;                                                  \
+}
+
+#define DEF_OSSL_PKEY_BN(class, keytype, name)                         \
+do {                                                                   \
+       rb_define_method((class), #name, ossl_##keytype##_get_##name, 0);       \
+       rb_define_method((class), #name "=", ossl_##keytype##_set_##name, 1);\
+} while (0)
+
+#endif /* _OSSL_PKEY_H_ */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_dh.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_dh.c
new file mode 100644 (file)
index 0000000..748d9c8
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_DH)
+
+#include "ossl.h"
+
+#define GetPKeyDH(obj, pkey) do { \
+    GetPKey((obj), (pkey)); \
+    if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_DH) { /* PARANOIA? */ \
+       ossl_raise(rb_eRuntimeError, "THIS IS NOT A DH!") ; \
+    } \
+} while (0)
+
+#define DH_HAS_PRIVATE(dh) ((dh)->priv_key)
+
+#ifdef OSSL_ENGINE_ENABLED
+#  define DH_PRIVATE(dh) (DH_HAS_PRIVATE(dh) || (dh)->engine)
+#else
+#  define DH_PRIVATE(dh) DH_HAS_PRIVATE(dh)
+#endif
+
+
+/*
+ * Classes
+ */
+VALUE cDH;
+VALUE eDHError;
+
+/*
+ * Public
+ */
+static VALUE
+dh_instance(VALUE klass, DH *dh)
+{
+    EVP_PKEY *pkey;
+    VALUE obj;
+
+    if (!dh) {
+       return Qfalse;
+    }
+    if (!(pkey = EVP_PKEY_new())) {
+       return Qfalse;
+    }
+    if (!EVP_PKEY_assign_DH(pkey, dh)) {
+       EVP_PKEY_free(pkey);
+       return Qfalse;
+    }
+    WrapPKey(klass, obj, pkey);
+
+    return obj;
+}
+
+VALUE
+ossl_dh_new(EVP_PKEY *pkey)
+{
+    VALUE obj;
+
+    if (!pkey) {
+       obj = dh_instance(cDH, DH_new());
+    } else {
+       if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) {
+           ossl_raise(rb_eTypeError, "Not a DH key!");
+       }
+       WrapPKey(cDH, obj, pkey);
+    }
+    if (obj == Qfalse) {
+       ossl_raise(eDHError, NULL);
+    }
+
+    return obj;
+}
+
+/*
+ * Private
+ */
+static DH *
+dh_generate(int size, int gen)
+{
+    DH *dh;
+
+    dh = DH_generate_parameters(size, gen,
+           rb_block_given_p() ? ossl_generate_cb : NULL,
+           NULL);
+    if (!dh) return 0;
+
+    if (!DH_generate_key(dh)) {
+       DH_free(dh);
+       return 0;
+    }
+
+    return dh;
+}
+
+/*
+ *  call-seq:
+ *     DH.generate(size [, generator]) -> dh
+ *
+ * Creates a new DH instance from scratch by generating the private and public
+ * components alike.
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.
+ * * +generator+ is a small number > 1, typically 2 or 5.
+ *
+ */
+static VALUE
+ossl_dh_s_generate(int argc, VALUE *argv, VALUE klass)
+{
+    DH *dh ;
+    int g = 2;
+    VALUE size, gen, obj;
+
+    if (rb_scan_args(argc, argv, "11", &size, &gen) == 2) {
+       g = NUM2INT(gen);
+    }
+    dh = dh_generate(NUM2INT(size), g);
+    obj = dh_instance(klass, dh);
+    if (obj == Qfalse) {
+       DH_free(dh);
+       ossl_raise(eDHError, NULL);
+    }
+
+    return obj;
+}
+
+/*
+ *  call-seq:
+ *     DH.new([size [, generator] | string]) -> dh
+ *
+ * Either generates a DH instance from scratch or by reading already existing
+ * DH parameters from +string+. Note that when reading a DH instance from
+ * data that was encoded from a DH instance by using DH#to_pem or DH#to_der
+ * the result will *not* contain a public/private key pair yet. This needs to
+ * be generated using DH#generate_key! first.
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size. Keys smaller than 1024 bits should be considered insecure.
+ * * +generator+ is a small number > 1, typically 2 or 5.
+ * * +string+ contains the DER or PEM encoded key.
+ *
+ * === Examples
+ *  DH.new # -> dh
+ *  DH.new(1024) # -> dh
+ *  DH.new(1024, 5) # -> dh
+ *  #Reading DH parameters
+ *  dh = DH.new(File.read('parameters.pem')) # -> dh, but no public/private key yet
+ *  dh.generate_key! # -> dh with public and private key
+ */
+static VALUE
+ossl_dh_initialize(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    DH *dh;
+    int g = 2;
+    BIO *in;
+    VALUE arg, gen;
+
+    GetPKey(self, pkey);
+    if(rb_scan_args(argc, argv, "02", &arg, &gen) == 0) {
+      dh = DH_new();
+    }
+    else if (FIXNUM_P(arg)) {
+       if (!NIL_P(gen)) {
+           g = NUM2INT(gen);
+       }
+       if (!(dh = dh_generate(FIX2INT(arg), g))) {
+           ossl_raise(eDHError, NULL);
+       }
+    }
+    else {
+       arg = ossl_to_der_if_possible(arg);
+       in = ossl_obj2bio(arg);
+       dh = PEM_read_bio_DHparams(in, NULL, NULL, NULL);
+       if (!dh){
+           OSSL_BIO_reset(in);
+           dh = d2i_DHparams_bio(in, NULL);
+       }
+       BIO_free(in);
+       if (!dh) {
+           ossl_raise(eDHError, NULL);
+       }
+    }
+    if (!EVP_PKEY_assign_DH(pkey, dh)) {
+       DH_free(dh);
+       ossl_raise(eDHError, NULL);
+    }
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     dh.public? -> true | false
+ *
+ * Indicates whether this DH instance has a public key associated with it or
+ * not. The public key may be retrieved with DH#pub_key.
+ */
+static VALUE
+ossl_dh_is_public(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyDH(self, pkey);
+
+    return (pkey->pkey.dh->pub_key) ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *     dh.private? -> true | false
+ *
+ * Indicates whether this DH instance has a private key associated with it or
+ * not. The private key may be retrieved with DH#priv_key.
+ */
+static VALUE
+ossl_dh_is_private(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyDH(self, pkey);
+
+    return (DH_PRIVATE(pkey->pkey.dh)) ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *     dh.to_pem -> aString
+ *
+ * Encodes this DH to its PEM encoding. Note that any existing per-session
+ * public/private keys will *not* get encoded, just the Diffie-Hellman
+ * parameters will be encoded.
+ */
+static VALUE
+ossl_dh_export(VALUE self)
+{
+    EVP_PKEY *pkey;
+    BIO *out;
+    VALUE str;
+
+    GetPKeyDH(self, pkey);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eDHError, NULL);
+    }
+    if (!PEM_write_bio_DHparams(out, pkey->pkey.dh)) {
+       BIO_free(out);
+       ossl_raise(eDHError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     dh.to_der -> aString
+ *
+ * Encodes this DH to its DER encoding. Note that any existing per-session
+ * public/private keys will *not* get encoded, just the Diffie-Hellman
+ * parameters will be encoded.
+
+ */
+static VALUE
+ossl_dh_to_der(VALUE self)
+{
+    EVP_PKEY *pkey;
+    unsigned char *p;
+    long len;
+    VALUE str;
+
+    GetPKeyDH(self, pkey);
+    if((len = i2d_DHparams(pkey->pkey.dh, NULL)) <= 0)
+       ossl_raise(eDHError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_DHparams(pkey->pkey.dh, &p) < 0)
+       ossl_raise(eDHError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     dh.params -> hash
+ *
+ * Stores all parameters of key to the hash
+ * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
+ * Don't use :-)) (I's up to you)
+ */
+static VALUE
+ossl_dh_get_params(VALUE self)
+{
+    EVP_PKEY *pkey;
+    VALUE hash;
+
+    GetPKeyDH(self, pkey);
+
+    hash = rb_hash_new();
+
+    rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dh->p));
+    rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dh->g));
+    rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dh->pub_key));
+    rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dh->priv_key));
+
+    return hash;
+}
+
+/*
+ *  call-seq:
+ *     dh.to_text -> aString
+ *
+ * Prints all parameters of key to buffer
+ * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
+ * Don't use :-)) (I's up to you)
+ */
+static VALUE
+ossl_dh_to_text(VALUE self)
+{
+    EVP_PKEY *pkey;
+    BIO *out;
+    VALUE str;
+
+    GetPKeyDH(self, pkey);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eDHError, NULL);
+    }
+    if (!DHparams_print(out, pkey->pkey.dh)) {
+       BIO_free(out);
+       ossl_raise(eDHError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     dh.public_key -> aDH
+ *
+ * Returns a new DH instance that carries just the public information, i.e.
+ * the prime +p+ and the generator +g+, but no public/private key yet. Such
+ * a pair may be generated using DH#generate_key!. The "public key" needed
+ * for a key exchange with DH#compute_key is considered as per-session
+ * information and may be retrieved with DH#pub_key once a key pair has
+ * been generated.
+ * If the current instance already contains private information (and thus a
+ * valid public/private key pair), this information will no longer be present
+ * in the new instance generated by DH#public_key. This feature is helpful for
+ * publishing the Diffie-Hellman parameters without leaking any of the private
+ * per-session information.
+ *
+ * === Example
+ *  dh = OpenSSL::PKey::DH.new(2048) # has public and private key set
+ *  public_key = dh.public_key # contains only prime and generator
+ *  parameters = public_key.to_der # it's safe to publish this
+ */
+static VALUE
+ossl_dh_to_public_key(VALUE self)
+{
+    EVP_PKEY *pkey;
+    DH *dh;
+    VALUE obj;
+
+    GetPKeyDH(self, pkey);
+    dh = DHparams_dup(pkey->pkey.dh); /* err check perfomed by dh_instance */
+    obj = dh_instance(CLASS_OF(self), dh);
+    if (obj == Qfalse) {
+       DH_free(dh);
+       ossl_raise(eDHError, NULL);
+    }
+
+    return obj;
+}
+
+/*
+ *  call-seq:
+ *     dh.check_params -> true | false
+ *
+ * Validates the Diffie-Hellman parameters associated with this instance.
+ * It checks whether a safe prime and a suitable generator are used. If this
+ * is not the case, +false+ is returned.
+ */
+static VALUE
+ossl_dh_check_params(VALUE self)
+{
+    DH *dh;
+    EVP_PKEY *pkey;
+    int codes;
+
+    GetPKeyDH(self, pkey);
+    dh = pkey->pkey.dh;
+
+    if (!DH_check(dh, &codes)) {
+       return Qfalse;
+    }
+
+    return codes == 0 ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *     dh.generate_key! -> self
+ *
+ * Generates a private and public key unless a private key already exists.
+ * If this DH instance was generated from public DH parameters (e.g. by
+ * encoding the result of DH#public_key), then this method needs to be
+ * called first in order to generate the per-session keys before performing
+ * the actual key exchange.
+ *
+ * === Example
+ *   dh = OpenSSL::PKey::DH.new(2048)
+ *   public_key = dh.public_key #contains no private/public key yet
+ *   public_key.generate_key!
+ *   puts public_key.private? # => true
+ */
+static VALUE
+ossl_dh_generate_key(VALUE self)
+{
+    DH *dh;
+    EVP_PKEY *pkey;
+
+    GetPKeyDH(self, pkey);
+    dh = pkey->pkey.dh;
+
+    if (!DH_generate_key(dh))
+       ossl_raise(eDHError, "Failed to generate key");
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     dh.compute_key(pub_bn) -> aString
+ *
+ * Returns a String containing a shared secret computed from the other party's public value.
+ * See DH_compute_key() for further information.
+ *
+ * === Parameters
+ * * +pub_bn+ is a OpenSSL::BN, *not* the DH instance returned by
+ * DH#public_key as that contains the DH parameters only.
+ */
+static VALUE
+ossl_dh_compute_key(VALUE self, VALUE pub)
+{
+    DH *dh;
+    EVP_PKEY *pkey;
+    BIGNUM *pub_key;
+    VALUE str;
+    int len;
+
+    GetPKeyDH(self, pkey);
+    dh = pkey->pkey.dh;
+    pub_key = GetBNPtr(pub);
+    len = DH_size(dh);
+    str = rb_str_new(0, len);
+    if ((len = DH_compute_key((unsigned char *)RSTRING_PTR(str), pub_key, dh)) < 0) {
+       ossl_raise(eDHError, NULL);
+    }
+    rb_str_set_len(str, len);
+
+    return str;
+}
+
+OSSL_PKEY_BN(dh, p)
+OSSL_PKEY_BN(dh, g)
+OSSL_PKEY_BN(dh, pub_key)
+OSSL_PKEY_BN(dh, priv_key)
+
+/*
+ * -----BEGIN DH PARAMETERS-----
+ * MEYCQQD0zXHljRg/mJ9PYLACLv58Cd8VxBxxY7oEuCeURMiTqEhMym16rhhKgZG2
+ * zk2O9uUIBIxSj+NKMURHGaFKyIvLAgEC
+ * -----END DH PARAMETERS-----
+ */
+static unsigned char DEFAULT_DH_512_PRIM[] = {
+    0xf4, 0xcd, 0x71, 0xe5, 0x8d, 0x18, 0x3f, 0x98,
+    0x9f, 0x4f, 0x60, 0xb0, 0x02, 0x2e, 0xfe, 0x7c,
+    0x09, 0xdf, 0x15, 0xc4, 0x1c, 0x71, 0x63, 0xba,
+    0x04, 0xb8, 0x27, 0x94, 0x44, 0xc8, 0x93, 0xa8,
+    0x48, 0x4c, 0xca, 0x6d, 0x7a, 0xae, 0x18, 0x4a,
+    0x81, 0x91, 0xb6, 0xce, 0x4d, 0x8e, 0xf6, 0xe5,
+    0x08, 0x04, 0x8c, 0x52, 0x8f, 0xe3, 0x4a, 0x31,
+    0x44, 0x47, 0x19, 0xa1, 0x4a, 0xc8, 0x8b, 0xcb,
+};
+static unsigned char DEFAULT_DH_512_GEN[] = { 0x02 };
+DH *OSSL_DEFAULT_DH_512 = NULL;
+
+/*
+ * -----BEGIN DH PARAMETERS-----
+ * MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ
+ * AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR
+ * T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC
+ * -----END DH PARAMETERS-----
+ */
+static unsigned char DEFAULT_DH_1024_PRIM[] = {
+    0x9d, 0x25, 0x39, 0x5c, 0xb4, 0x54, 0x8a, 0xff,
+    0x25, 0xe6, 0xd6, 0x9f, 0x4c, 0xc3, 0xc1, 0x8d,
+    0xa1, 0xfa, 0xba, 0x88, 0x4c, 0x53, 0xa9, 0x74,
+    0xda, 0xfa, 0xba, 0x0b, 0x20, 0xbe, 0x40, 0xd7,
+    0xba, 0xe7, 0x1d, 0x70, 0x28, 0x61, 0x60, 0x4c,
+    0x49, 0x01, 0x5f, 0xd9, 0x0f, 0x60, 0x16, 0x3d,
+    0xba, 0xd3, 0xa9, 0x5e, 0xfa, 0x98, 0x64, 0x60,
+    0x26, 0x0e, 0x04, 0x75, 0xd8, 0x13, 0xd7, 0x31,
+    0xb4, 0x8e, 0xad, 0xeb, 0x9c, 0x57, 0x4c, 0x8f,
+    0x65, 0xf3, 0x90, 0x16, 0x31, 0xdc, 0x15, 0x6f,
+    0x7d, 0x1d, 0x00, 0xae, 0x76, 0xf2, 0xd1, 0x11,
+    0xd1, 0x4f, 0x88, 0x7b, 0x29, 0x9f, 0xf6, 0xce,
+    0x68, 0xef, 0x57, 0xe7, 0x85, 0xf2, 0x40, 0x54,
+    0x1c, 0x12, 0x40, 0xa2, 0x35, 0x25, 0xcf, 0x12,
+    0xa3, 0xe1, 0x07, 0x8e, 0xdb, 0x1d, 0xb4, 0x14,
+    0xff, 0x57, 0xe7, 0x19, 0x8d, 0x51, 0x77, 0x83
+};
+static unsigned char DEFAULT_DH_1024_GEN[] = { 0x02 };
+DH *OSSL_DEFAULT_DH_1024 = NULL;
+
+static DH*
+ossl_create_dh(unsigned char *p, size_t plen, unsigned char *g, size_t glen)
+{
+    DH *dh;
+
+    if ((dh = DH_new()) == NULL) ossl_raise(eDHError, NULL);
+    dh->p = BN_bin2bn(p, rb_long2int(plen), NULL);
+    dh->g = BN_bin2bn(g, rb_long2int(glen), NULL);
+    if (dh->p == NULL || dh->g == NULL){
+        DH_free(dh);
+       ossl_raise(eDHError, NULL);
+    }
+
+    return dh;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_dh()
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
+    mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
+    /* Document-class: OpenSSL::PKey::DHError
+     *
+     * Generic exception that is raised if an operation on a DH PKey
+     * fails unexpectedly or in case an instantiation of an instance of DH
+     * fails due to non-conformant input data.
+     */
+    eDHError = rb_define_class_under(mPKey, "DHError", ePKeyError);
+    /* Document-class: OpenSSL::PKey::DH
+     *
+     * An implementation of the Diffie-Hellman key exchange protocol based on
+     * discrete logarithms in finite fields, the same basis that DSA is built
+     * on.
+     *
+     * === Accessor methods for the Diffie-Hellman parameters
+     * * DH#p
+     * The prime (an OpenSSL::BN) of the Diffie-Hellman parameters.
+     * * DH#g
+     * The generator (an OpenSSL::BN) g of the Diffie-Hellman parameters.
+     * * DH#pub_key
+     * The per-session public key (an OpenSSL::BN) matching the private key.
+     * This needs to be passed to DH#compute_key.
+     * * DH#priv_key
+     * The per-session private key, an OpenSSL::BN.
+     *
+     * === 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
+     *  dh2 = OpenSSL::PKey::DH.new(der)
+     *  dh2.generate_key! #generate the per-session key pair
+     *  symm_key1 = dh1.compute_key(dh2.pub_key)
+     *  symm_key2 = dh2.compute_key(dh1.pub_key)
+     *
+     *  puts symm_key1 == symm_key2 # => true
+     */
+    cDH = rb_define_class_under(mPKey, "DH", cPKey);
+    rb_define_singleton_method(cDH, "generate", ossl_dh_s_generate, -1);
+    rb_define_method(cDH, "initialize", ossl_dh_initialize, -1);
+    rb_define_method(cDH, "public?", ossl_dh_is_public, 0);
+    rb_define_method(cDH, "private?", ossl_dh_is_private, 0);
+    rb_define_method(cDH, "to_text", ossl_dh_to_text, 0);
+    rb_define_method(cDH, "export", ossl_dh_export, 0);
+    rb_define_alias(cDH, "to_pem", "export");
+    rb_define_alias(cDH, "to_s", "export");
+    rb_define_method(cDH, "to_der", ossl_dh_to_der, 0);
+    rb_define_method(cDH, "public_key", ossl_dh_to_public_key, 0);
+    rb_define_method(cDH, "params_ok?", ossl_dh_check_params, 0);
+    rb_define_method(cDH, "generate_key!", ossl_dh_generate_key, 0);
+    rb_define_method(cDH, "compute_key", ossl_dh_compute_key, 1);
+
+    DEF_OSSL_PKEY_BN(cDH, dh, p);
+    DEF_OSSL_PKEY_BN(cDH, dh, g);
+    DEF_OSSL_PKEY_BN(cDH, dh, pub_key);
+    DEF_OSSL_PKEY_BN(cDH, dh, priv_key);
+    rb_define_method(cDH, "params", ossl_dh_get_params, 0);
+
+    OSSL_DEFAULT_DH_512 = ossl_create_dh(
+       DEFAULT_DH_512_PRIM, sizeof(DEFAULT_DH_512_PRIM),
+       DEFAULT_DH_512_GEN, sizeof(DEFAULT_DH_512_GEN));
+    OSSL_DEFAULT_DH_1024 = ossl_create_dh(
+       DEFAULT_DH_1024_PRIM, sizeof(DEFAULT_DH_1024_PRIM),
+       DEFAULT_DH_1024_GEN, sizeof(DEFAULT_DH_1024_GEN));
+}
+
+#else /* defined NO_DH */
+void
+Init_ossl_dh()
+{
+}
+#endif /* NO_DH */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_dsa.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_dsa.c
new file mode 100644 (file)
index 0000000..6b10e8f
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_DSA)
+
+#include "ossl.h"
+
+#define GetPKeyDSA(obj, pkey) do { \
+    GetPKey((obj), (pkey)); \
+    if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_DSA) { /* PARANOIA? */ \
+       ossl_raise(rb_eRuntimeError, "THIS IS NOT A DSA!"); \
+    } \
+} while (0)
+
+#define DSA_HAS_PRIVATE(dsa) ((dsa)->priv_key)
+#define DSA_PRIVATE(obj,dsa) (DSA_HAS_PRIVATE(dsa)||OSSL_PKEY_IS_PRIVATE(obj))
+
+/*
+ * Classes
+ */
+VALUE cDSA;
+VALUE eDSAError;
+
+/*
+ * Public
+ */
+static VALUE
+dsa_instance(VALUE klass, DSA *dsa)
+{
+    EVP_PKEY *pkey;
+    VALUE obj;
+
+    if (!dsa) {
+       return Qfalse;
+    }
+    if (!(pkey = EVP_PKEY_new())) {
+       return Qfalse;
+    }
+    if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
+       EVP_PKEY_free(pkey);
+       return Qfalse;
+    }
+    WrapPKey(klass, obj, pkey);
+
+    return obj;
+}
+
+VALUE
+ossl_dsa_new(EVP_PKEY *pkey)
+{
+    VALUE obj;
+
+    if (!pkey) {
+       obj = dsa_instance(cDSA, DSA_new());
+    } else {
+       if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DSA) {
+           ossl_raise(rb_eTypeError, "Not a DSA key!");
+       }
+       WrapPKey(cDSA, obj, pkey);
+    }
+    if (obj == Qfalse) {
+       ossl_raise(eDSAError, NULL);
+    }
+
+    return obj;
+}
+
+/*
+ * Private
+ */
+static DSA *
+dsa_generate(int size)
+{
+    DSA *dsa;
+    unsigned char seed[20];
+    int seed_len = 20, counter;
+    unsigned long h;
+
+    if (!RAND_bytes(seed, seed_len)) {
+       return 0;
+    }
+    dsa = DSA_generate_parameters(size, seed, seed_len, &counter, &h,
+           rb_block_given_p() ? ossl_generate_cb : NULL,
+           NULL);
+    if(!dsa) return 0;
+
+    if (!DSA_generate_key(dsa)) {
+       DSA_free(dsa);
+       return 0;
+    }
+
+    return dsa;
+}
+
+/*
+ *  call-seq:
+ *    DSA.generate(size) -> dsa
+ *
+ * Creates a new DSA instance by generating a private/public key pair
+ * from scratch.
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size.
+ *
+ */
+static VALUE
+ossl_dsa_s_generate(VALUE klass, VALUE size)
+{
+    DSA *dsa = dsa_generate(NUM2INT(size)); /* err handled by dsa_instance */
+    VALUE obj = dsa_instance(klass, dsa);
+
+    if (obj == Qfalse) {
+       DSA_free(dsa);
+       ossl_raise(eDSAError, NULL);
+    }
+
+    return obj;
+}
+
+/*
+ *  call-seq:
+ *    DSA.new([size | string [, pass]) -> dsa
+ *
+ * Creates a new DSA instance by reading an existing key from +string+.
+ *
+ * === Parameters
+ * * +size+ is an integer representing the desired key size.
+ * * +string+ contains a DER or PEM encoded key.
+ * * +pass+ is a string that contains an optional password.
+ *
+ * === Examples
+ *  DSA.new -> dsa
+ *  DSA.new(1024) -> dsa
+ *  DSA.new(File.read('dsa.pem')) -> dsa
+ *  DSA.new(File.read('dsa.pem'), 'mypassword') -> dsa
+ *
+ */
+static VALUE
+ossl_dsa_initialize(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    DSA *dsa;
+    BIO *in;
+    char *passwd = NULL;
+    VALUE arg, pass;
+
+    GetPKey(self, pkey);
+    if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
+        dsa = DSA_new();
+    }
+    else if (FIXNUM_P(arg)) {
+       if (!(dsa = dsa_generate(FIX2INT(arg)))) {
+           ossl_raise(eDSAError, NULL);
+       }
+    }
+    else {
+       if (!NIL_P(pass)) passwd = StringValuePtr(pass);
+       arg = ossl_to_der_if_possible(arg);
+       in = ossl_obj2bio(arg);
+       dsa = PEM_read_bio_DSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
+       if (!dsa) {
+           OSSL_BIO_reset(in);
+           dsa = PEM_read_bio_DSA_PUBKEY(in, NULL, NULL, NULL);
+       }
+       if (!dsa) {
+           OSSL_BIO_reset(in);
+           dsa = d2i_DSAPrivateKey_bio(in, NULL);
+       }
+       if (!dsa) {
+           OSSL_BIO_reset(in);
+           dsa = d2i_DSA_PUBKEY_bio(in, NULL);
+       }
+       if (!dsa) {
+           OSSL_BIO_reset(in);
+           dsa = PEM_read_bio_DSAPublicKey(in, NULL, NULL, NULL);
+       }
+       BIO_free(in);
+       if (!dsa) {
+           ERR_clear_error();
+           ossl_raise(eDSAError, "Neither PUB key nor PRIV key:");
+       }
+    }
+    if (!EVP_PKEY_assign_DSA(pkey, dsa)) {
+       DSA_free(dsa);
+       ossl_raise(eDSAError, NULL);
+    }
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *    dsa.public? -> true | false
+ *
+ * Indicates whether this DSA instance has a public key associated with it or
+ * not. The public key may be retrieved with DSA#public_key.
+ */
+static VALUE
+ossl_dsa_is_public(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyDSA(self, pkey);
+
+    return (pkey->pkey.dsa->pub_key) ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *    dsa.private? -> true | false
+ *
+ * Indicates whether this DSA instance has a private key associated with it or
+ * not. The private key may be retrieved with DSA#private_key.
+ */
+static VALUE
+ossl_dsa_is_private(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyDSA(self, pkey);
+
+    return (DSA_PRIVATE(self, pkey->pkey.dsa)) ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *    dsa.to_pem([cipher, password]) -> aString
+ *
+ * Encodes this DSA to its PEM encoding.
+ *
+ * === Parameters
+ * * +cipher+ is an OpenSSL::Cipher.
+ * * +password+ is a string containing your password.
+ *
+ * === Examples
+ *  DSA.to_pem -> aString
+ *  DSA.to_pem(cipher, 'mypassword') -> aString
+ *
+ */
+static VALUE
+ossl_dsa_export(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    BIO *out;
+    const EVP_CIPHER *ciph = NULL;
+    char *passwd = NULL;
+    VALUE cipher, pass, str;
+
+    GetPKeyDSA(self, pkey);
+    rb_scan_args(argc, argv, "02", &cipher, &pass);
+    if (!NIL_P(cipher)) {
+       ciph = GetCipherPtr(cipher);
+       if (!NIL_P(pass)) {
+           passwd = StringValuePtr(pass);
+       }
+    }
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eDSAError, NULL);
+    }
+    if (DSA_HAS_PRIVATE(pkey->pkey.dsa)) {
+       if (!PEM_write_bio_DSAPrivateKey(out, pkey->pkey.dsa, ciph,
+                                        NULL, 0, ossl_pem_passwd_cb, passwd)){
+           BIO_free(out);
+           ossl_raise(eDSAError, NULL);
+       }
+    } else {
+       if (!PEM_write_bio_DSA_PUBKEY(out, pkey->pkey.dsa)) {
+           BIO_free(out);
+           ossl_raise(eDSAError, NULL);
+       }
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *    dsa.to_der -> aString
+ *
+ * Encodes this DSA to its DER encoding.
+ *
+ */
+static VALUE
+ossl_dsa_to_der(VALUE self)
+{
+    EVP_PKEY *pkey;
+    int (*i2d_func)_((DSA*, unsigned char**));
+    unsigned char *p;
+    long len;
+    VALUE str;
+
+    GetPKeyDSA(self, pkey);
+    if(DSA_HAS_PRIVATE(pkey->pkey.dsa))
+       i2d_func = (int(*)_((DSA*,unsigned char**)))i2d_DSAPrivateKey;
+    else
+       i2d_func = i2d_DSA_PUBKEY;
+    if((len = i2d_func(pkey->pkey.dsa, NULL)) <= 0)
+       ossl_raise(eDSAError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_func(pkey->pkey.dsa, &p) < 0)
+       ossl_raise(eDSAError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *    dsa.params -> hash
+ *
+ * Stores all parameters of key to the hash
+ * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
+ * Don't use :-)) (I's up to you)
+ */
+static VALUE
+ossl_dsa_get_params(VALUE self)
+{
+    EVP_PKEY *pkey;
+    VALUE hash;
+
+    GetPKeyDSA(self, pkey);
+
+    hash = rb_hash_new();
+
+    rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.dsa->p));
+    rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.dsa->q));
+    rb_hash_aset(hash, rb_str_new2("g"), ossl_bn_new(pkey->pkey.dsa->g));
+    rb_hash_aset(hash, rb_str_new2("pub_key"), ossl_bn_new(pkey->pkey.dsa->pub_key));
+    rb_hash_aset(hash, rb_str_new2("priv_key"), ossl_bn_new(pkey->pkey.dsa->priv_key));
+
+    return hash;
+}
+
+/*
+ *  call-seq:
+ *    dsa.to_text -> aString
+ *
+ * Prints all parameters of key to buffer
+ * INSECURE: PRIVATE INFORMATIONS CAN LEAK OUT!!!
+ * Don't use :-)) (I's up to you)
+ */
+static VALUE
+ossl_dsa_to_text(VALUE self)
+{
+    EVP_PKEY *pkey;
+    BIO *out;
+    VALUE str;
+
+    GetPKeyDSA(self, pkey);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eDSAError, NULL);
+    }
+    if (!DSA_print(out, pkey->pkey.dsa, 0)) { /* offset = 0 */
+       BIO_free(out);
+       ossl_raise(eDSAError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *    dsa.public_key -> aDSA
+ *
+ * Returns a new DSA instance that carries just the public key information.
+ * If the current instance has also private key information, this will no
+ * longer be present in the new instance. This feature is helpful for
+ * publishing the public key information without leaking any of the private
+ * information.
+ *
+ * === Example
+ *  dsa = OpenSSL::PKey::DSA.new(2048) # has public and private information
+ *  pub_key = dsa.public_key # has only the public part available
+ *  pub_key_der = pub_key.to_der # it's safe to publish this
+ *
+ *
+ */
+static VALUE
+ossl_dsa_to_public_key(VALUE self)
+{
+    EVP_PKEY *pkey;
+    DSA *dsa;
+    VALUE obj;
+
+    GetPKeyDSA(self, pkey);
+    /* err check performed by dsa_instance */
+    dsa = DSAPublicKey_dup(pkey->pkey.dsa);
+    obj = dsa_instance(CLASS_OF(self), dsa);
+    if (obj == Qfalse) {
+       DSA_free(dsa);
+       ossl_raise(eDSAError, NULL);
+    }
+    return obj;
+}
+
+#define ossl_dsa_buf_size(pkey) (DSA_size((pkey)->pkey.dsa)+16)
+
+/*
+ *  call-seq:
+ *    dsa.syssign(string) -> aString
+ *
+ * Computes and returns the DSA signature of +string+, where +string+ is
+ * expected to be an already-computed message digest of the original input
+ * data. The signature is issued using the private key of this DSA instance.
+ *
+ * === Parameters
+ * * +string+ is a message digest of the original input data to be signed
+ *
+ * === Example
+ *  dsa = OpenSSL::PKey::DSA.new(2048)
+ *  doc = "Sign me"
+ *  digest = OpenSSL::Digest::SHA1.digest(doc)
+ *  sig = dsa.syssign(digest)
+ *
+ *
+ */
+static VALUE
+ossl_dsa_sign(VALUE self, VALUE data)
+{
+    EVP_PKEY *pkey;
+    unsigned int buf_len;
+    VALUE str;
+
+    GetPKeyDSA(self, pkey);
+    StringValue(data);
+    if (!DSA_PRIVATE(self, pkey->pkey.dsa)) {
+       ossl_raise(eDSAError, "Private DSA key needed!");
+    }
+    str = rb_str_new(0, ossl_dsa_buf_size(pkey));
+    if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data),
+                 (unsigned char *)RSTRING_PTR(str),
+                 &buf_len, pkey->pkey.dsa)) { /* type is ignored (0) */
+       ossl_raise(eDSAError, NULL);
+    }
+    rb_str_set_len(str, buf_len);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *    dsa.sysverify(digest, sig) -> true | false
+ *
+ * Verifies whether the signature is valid given the message digest input. It
+ * does so by validating +sig+ using the public key of this DSA instance.
+ *
+ * === Parameters
+ * * +digest+ is a message digest of the original input data to be signed
+ * * +sig+ is a DSA signature value
+ *
+ * === Example
+ *  dsa = OpenSSL::PKey::DSA.new(2048)
+ *  doc = "Sign me"
+ *  digest = OpenSSL::Digest::SHA1.digest(doc)
+ *  sig = dsa.syssign(digest)
+ *  puts dsa.sysverify(digest, sig) # => true
+ *
+ */
+static VALUE
+ossl_dsa_verify(VALUE self, VALUE digest, VALUE sig)
+{
+    EVP_PKEY *pkey;
+    int ret;
+
+    GetPKeyDSA(self, pkey);
+    StringValue(digest);
+    StringValue(sig);
+    /* type is ignored (0) */
+    ret = DSA_verify(0, (unsigned char *)RSTRING_PTR(digest), RSTRING_LENINT(digest),
+                    (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey->pkey.dsa);
+    if (ret < 0) {
+       ossl_raise(eDSAError, NULL);
+    }
+    else if (ret == 1) {
+       return Qtrue;
+    }
+
+    return Qfalse;
+}
+
+OSSL_PKEY_BN(dsa, p)
+OSSL_PKEY_BN(dsa, q)
+OSSL_PKEY_BN(dsa, g)
+OSSL_PKEY_BN(dsa, pub_key)
+OSSL_PKEY_BN(dsa, priv_key)
+
+/*
+ * INIT
+ */
+void
+Init_ossl_dsa()
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
+    mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
+    /* Document-class: OpenSSL::PKey::DSAError
+     *
+     * Generic exception that is raised if an operation on a DSA PKey
+     * fails unexpectedly or in case an instantiation of an instance of DSA
+     * fails due to non-conformant input data.
+     */
+    eDSAError = rb_define_class_under(mPKey, "DSAError", ePKeyError);
+
+    /* Document-class: OpenSSL::PKey::DSA
+     *
+     * DSA, the Digital Signature Algorithm, is specified in NIST's
+     * FIPS 186-3. It is an asymmetric public key algorithm that may be used
+     * similar to e.g. RSA.
+     * Please note that for OpenSSL versions prior to 1.0.0 the digest
+     * algorithms OpenSSL::Digest::DSS (equivalent to SHA) or
+     * OpenSSL::Digest::DSS1 (equivalent to SHA-1) must be used for issuing
+     * signatures with a DSA key using OpenSSL::PKey#sign.
+     * Starting with OpenSSL 1.0.0, digest algorithms are no longer restricted,
+     * any Digest may be used for signing.
+     */
+    cDSA = rb_define_class_under(mPKey, "DSA", cPKey);
+
+    rb_define_singleton_method(cDSA, "generate", ossl_dsa_s_generate, 1);
+    rb_define_method(cDSA, "initialize", ossl_dsa_initialize, -1);
+
+    rb_define_method(cDSA, "public?", ossl_dsa_is_public, 0);
+    rb_define_method(cDSA, "private?", ossl_dsa_is_private, 0);
+    rb_define_method(cDSA, "to_text", ossl_dsa_to_text, 0);
+    rb_define_method(cDSA, "export", ossl_dsa_export, -1);
+    rb_define_alias(cDSA, "to_pem", "export");
+    rb_define_alias(cDSA, "to_s", "export");
+    rb_define_method(cDSA, "to_der", ossl_dsa_to_der, 0);
+    rb_define_method(cDSA, "public_key", ossl_dsa_to_public_key, 0);
+    rb_define_method(cDSA, "syssign", ossl_dsa_sign, 1);
+    rb_define_method(cDSA, "sysverify", ossl_dsa_verify, 2);
+
+    DEF_OSSL_PKEY_BN(cDSA, dsa, p);
+    DEF_OSSL_PKEY_BN(cDSA, dsa, q);
+    DEF_OSSL_PKEY_BN(cDSA, dsa, g);
+    DEF_OSSL_PKEY_BN(cDSA, dsa, pub_key);
+    DEF_OSSL_PKEY_BN(cDSA, dsa, priv_key);
+
+    rb_define_method(cDSA, "params", ossl_dsa_get_params, 0);
+}
+
+#else /* defined NO_DSA */
+void
+Init_ossl_dsa()
+{
+}
+#endif /* NO_DSA */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_ec.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_ec.c
new file mode 100644 (file)
index 0000000..dd491ef
--- /dev/null
@@ -0,0 +1,1598 @@
+/*
+ * Copyright (C) 2006-2007 Technorama Ltd. <oss-ruby@technorama.net>
+ */
+
+#include "ossl.h"
+
+#if !defined(OPENSSL_NO_EC) && (OPENSSL_VERSION_NUMBER >= 0x0090802fL)
+
+typedef struct {
+       EC_GROUP *group;
+       int dont_free;
+} ossl_ec_group;
+
+typedef struct {
+       EC_POINT *point;
+       int dont_free;
+} ossl_ec_point;
+
+
+#define EXPORT_PEM 0
+#define EXPORT_DER 1
+
+
+#define GetPKeyEC(obj, pkey) do { \
+    GetPKey((obj), (pkey)); \
+    if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_EC) { \
+       ossl_raise(rb_eRuntimeError, "THIS IS NOT A EC PKEY!"); \
+    } \
+} while (0)
+
+#define SafeGet_ec_group(obj, group) do { \
+    OSSL_Check_Kind((obj), cEC_GROUP); \
+    Data_Get_Struct((obj), ossl_ec_group, (group)); \
+} while(0)
+
+#define Get_EC_KEY(obj, key) do { \
+    EVP_PKEY *pkey; \
+    GetPKeyEC((obj), pkey); \
+    (key) = pkey->pkey.ec; \
+} while(0)
+
+#define Require_EC_KEY(obj, key) do { \
+    Get_EC_KEY((obj), (key)); \
+    if ((key) == NULL) \
+        ossl_raise(eECError, "EC_KEY is not initialized"); \
+} while(0)
+
+#define SafeRequire_EC_KEY(obj, key) do { \
+    OSSL_Check_Kind((obj), cEC); \
+    Require_EC_KEY((obj), (key)); \
+} while (0)
+
+#define Get_EC_GROUP(obj, g) do { \
+    ossl_ec_group *ec_group; \
+    Data_Get_Struct((obj), ossl_ec_group, ec_group); \
+    if (ec_group == NULL) \
+        ossl_raise(eEC_GROUP, "missing ossl_ec_group structure"); \
+    (g) = ec_group->group; \
+} while(0)
+
+#define Require_EC_GROUP(obj, group) do { \
+    Get_EC_GROUP((obj), (group)); \
+    if ((group) == NULL) \
+        ossl_raise(eEC_GROUP, "EC_GROUP is not initialized"); \
+} while(0)
+
+#define SafeRequire_EC_GROUP(obj, group) do { \
+    OSSL_Check_Kind((obj), cEC_GROUP); \
+    Require_EC_GROUP((obj), (group)); \
+} while(0)
+
+#define Get_EC_POINT(obj, p) do { \
+    ossl_ec_point *ec_point; \
+    Data_Get_Struct((obj), ossl_ec_point, ec_point); \
+    if (ec_point == NULL) \
+        ossl_raise(eEC_POINT, "missing ossl_ec_point structure"); \
+    (p) = ec_point->point; \
+} while(0)
+
+#define Require_EC_POINT(obj, point) do { \
+    Get_EC_POINT((obj), (point)); \
+    if ((point) == NULL) \
+        ossl_raise(eEC_POINT, "EC_POINT is not initialized"); \
+} while(0)
+
+#define SafeRequire_EC_POINT(obj, point) do { \
+    OSSL_Check_Kind((obj), cEC_POINT); \
+    Require_EC_POINT((obj), (point)); \
+} while(0)
+
+VALUE cEC;
+VALUE eECError;
+VALUE cEC_GROUP;
+VALUE eEC_GROUP;
+VALUE cEC_POINT;
+VALUE eEC_POINT;
+
+static ID s_GFp;
+static ID s_GFp_simple;
+static ID s_GFp_mont;
+static ID s_GFp_nist;
+static ID s_GF2m;
+static ID s_GF2m_simple;
+
+static ID ID_uncompressed;
+static ID ID_compressed;
+static ID ID_hybrid;
+
+static VALUE ec_instance(VALUE klass, EC_KEY *ec)
+{
+    EVP_PKEY *pkey;
+    VALUE obj;
+
+    if (!ec) {
+       return Qfalse;
+    }
+    if (!(pkey = EVP_PKEY_new())) {
+       return Qfalse;
+    }
+    if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
+       EVP_PKEY_free(pkey);
+       return Qfalse;
+    }
+    WrapPKey(klass, obj, pkey);
+
+    return obj;
+}
+
+VALUE ossl_ec_new(EVP_PKEY *pkey)
+{
+    VALUE obj;
+
+    if (!pkey) {
+       obj = ec_instance(cEC, EC_KEY_new());
+    } else {
+       if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
+           ossl_raise(rb_eTypeError, "Not a EC key!");
+       }
+       WrapPKey(cEC, obj, pkey);
+    }
+    if (obj == Qfalse) {
+       ossl_raise(eECError, NULL);
+    }
+
+    return obj;
+}
+
+
+/*  call-seq:
+ *     OpenSSL::PKey::EC.new()
+ *     OpenSSL::PKey::EC.new(ec_key)
+ *     OpenSSL::PKey::EC.new(ec_group)
+ *     OpenSSL::PKey::EC.new("secp112r1")
+ *     OpenSSL::PKey::EC.new(pem_string)
+ *     OpenSSL::PKey::EC.new(pem_string [, pwd])
+ *     OpenSSL::PKey::EC.new(der_string)
+ *
+ *  See the OpenSSL documentation for:
+ *     EC_KEY_*
+ */
+static VALUE ossl_ec_key_initialize(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    EC_KEY *ec = NULL;
+    VALUE arg, pass;
+    VALUE group = Qnil;
+    char *passwd = NULL;
+
+    GetPKey(self, pkey);
+    if (pkey->pkey.ec)
+        ossl_raise(eECError, "EC_KEY already initialized");
+
+    rb_scan_args(argc, argv, "02", &arg, &pass);
+
+    if (NIL_P(arg)) {
+        ec = EC_KEY_new();
+    } else {
+        if (rb_obj_is_kind_of(arg, cEC)) {
+            EC_KEY *other_ec = NULL;
+
+            SafeRequire_EC_KEY(arg, other_ec);
+            ec = EC_KEY_dup(other_ec);
+        } else if (rb_obj_is_kind_of(arg, cEC_GROUP)) {
+               ec = EC_KEY_new();
+               group = arg;
+        } else {
+            BIO *in = ossl_obj2bio(arg);
+
+            if (!NIL_P(pass)) {
+               passwd = StringValuePtr(pass);
+           }
+           ec = PEM_read_bio_ECPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
+            if (!ec) {
+               OSSL_BIO_reset(in);
+               ec = PEM_read_bio_EC_PUBKEY(in, NULL, ossl_pem_passwd_cb, passwd);
+            }
+            if (!ec) {
+               OSSL_BIO_reset(in);
+                ec = d2i_ECPrivateKey_bio(in, NULL);
+            }
+            if (!ec) {
+               OSSL_BIO_reset(in);
+                ec = d2i_EC_PUBKEY_bio(in, NULL);
+            }
+
+            BIO_free(in);
+
+            if (ec == NULL) {
+                const char *name = StringValueCStr(arg);
+                int nid = OBJ_sn2nid(name);
+
+                (void)ERR_get_error();
+                if (nid == NID_undef)
+                    ossl_raise(eECError, "unknown curve name (%s)\n", name);
+
+                if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL)
+                    ossl_raise(eECError, "unable to create curve (%s)\n", name);
+
+                EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE);
+                EC_KEY_set_conv_form(ec, POINT_CONVERSION_UNCOMPRESSED);
+            }
+        }
+    }
+
+    if (ec == NULL)
+        ossl_raise(eECError, NULL);
+
+    if (!EVP_PKEY_assign_EC_KEY(pkey, ec)) {
+       EC_KEY_free(ec);
+       ossl_raise(eECError, "EVP_PKEY_assign_EC_KEY");
+    }
+
+    rb_iv_set(self, "@group", Qnil);
+
+    if (!NIL_P(group))
+        rb_funcall(self, rb_intern("group="), 1, arg);
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     key.group   => group
+ *
+ *  Returns a constant <code>OpenSSL::EC::Group</code> that is tied to the key.
+ *  Modifying the returned group can make the key invalid.
+ */
+static VALUE ossl_ec_key_get_group(VALUE self)
+{
+    VALUE group_v;
+    EC_KEY *ec;
+    ossl_ec_group *ec_group;
+    EC_GROUP *group;
+
+    Require_EC_KEY(self, ec);
+
+    group_v = rb_iv_get(self, "@group");
+    if (!NIL_P(group_v))
+        return group_v;
+
+    if ((group = (EC_GROUP *)EC_KEY_get0_group(ec)) != NULL) {
+        group_v = rb_obj_alloc(cEC_GROUP);
+        SafeGet_ec_group(group_v, ec_group);
+        ec_group->group = group;
+        ec_group->dont_free = 1;
+        rb_iv_set(group_v, "@key", self);
+        rb_iv_set(self, "@group", group_v);
+        return group_v;
+    }
+
+    return Qnil;
+}
+
+/*
+ *  call-seq:
+ *     key.group = group   => group
+ *
+ *  Returns the same object passed, not the group object associated with the key.
+ *  If you wish to access the group object tied to the key call key.group after setting
+ *  the group.
+ *
+ *  Setting the group will immediately destroy any previously assigned group object.
+ *  The group is internally copied by OpenSSL.  Modifying the original group after
+ *  assignment will not effect the internal key structure.
+ *  (your changes may be lost).  BE CAREFUL.
+ *
+ *  EC_KEY_set_group calls EC_GROUP_free(key->group) then EC_GROUP_dup(), not EC_GROUP_copy.
+ *  This documentation is accurate for OpenSSL 0.9.8b.
+ */
+static VALUE ossl_ec_key_set_group(VALUE self, VALUE group_v)
+{
+    VALUE old_group_v;
+    EC_KEY *ec;
+    EC_GROUP *group;
+
+    Require_EC_KEY(self, ec);
+    SafeRequire_EC_GROUP(group_v, group);
+
+    old_group_v = rb_iv_get(self, "@group");
+    if (!NIL_P(old_group_v)) {
+        ossl_ec_group *old_ec_group;
+        SafeGet_ec_group(old_group_v, old_ec_group);
+
+        old_ec_group->group = NULL;
+        old_ec_group->dont_free = 0;
+        rb_iv_set(old_group_v, "@key", Qnil);
+    }
+
+    rb_iv_set(self, "@group", Qnil);
+
+    if (EC_KEY_set_group(ec, group) != 1)
+        ossl_raise(eECError, "EC_KEY_set_group");
+
+    return group_v;
+}
+
+/*
+ *  call-seq:
+ *     key.private_key   => OpenSSL::BN
+ *
+ *  See the OpenSSL documentation for EC_KEY_get0_private_key()
+ */
+static VALUE ossl_ec_key_get_private_key(VALUE self)
+{
+    EC_KEY *ec;
+    const BIGNUM *bn;
+
+    Require_EC_KEY(self, ec);
+
+    if ((bn = EC_KEY_get0_private_key(ec)) == NULL)
+        return Qnil;
+
+    return ossl_bn_new(bn);
+}
+
+/*
+ *  call-seq:
+ *     key.private_key = openssl_bn
+ *
+ *  See the OpenSSL documentation for EC_KEY_set_private_key()
+ */
+static VALUE ossl_ec_key_set_private_key(VALUE self, VALUE private_key)
+{
+    EC_KEY *ec;
+    BIGNUM *bn = NULL;
+
+    Require_EC_KEY(self, ec);
+    if (!NIL_P(private_key))
+        bn = GetBNPtr(private_key);
+
+    switch (EC_KEY_set_private_key(ec, bn)) {
+    case 1:
+        break;
+    case 0:
+        if (bn == NULL)
+            break;
+    default:
+        ossl_raise(eECError, "EC_KEY_set_private_key");
+    }
+
+    return private_key;
+}
+
+
+static VALUE ossl_ec_point_dup(const EC_POINT *point, VALUE group_v)
+{
+    VALUE obj;
+    const EC_GROUP *group;
+    ossl_ec_point *new_point;
+
+    obj = rb_obj_alloc(cEC_POINT);
+    Data_Get_Struct(obj, ossl_ec_point, new_point);
+
+    SafeRequire_EC_GROUP(group_v, group);
+
+    new_point->point = EC_POINT_dup(point, group);
+    if (new_point->point == NULL)
+        ossl_raise(eEC_POINT, "EC_POINT_dup");
+    rb_iv_set(obj, "@group", group_v);
+
+    return obj;
+}
+
+/*
+ *  call-seq:
+ *     key.public_key   => OpenSSL::PKey::EC::Point
+ *
+ *  See the OpenSSL documentation for EC_KEY_get0_public_key()
+ */
+static VALUE ossl_ec_key_get_public_key(VALUE self)
+{
+    EC_KEY *ec;
+    const EC_POINT *point;
+    VALUE group;
+
+    Require_EC_KEY(self, ec);
+
+    if ((point = EC_KEY_get0_public_key(ec)) == NULL)
+        return Qnil;
+
+    group = rb_funcall(self, rb_intern("group"), 0);
+    if (NIL_P(group))
+        ossl_raise(eECError, "EC_KEY_get0_get0_group (has public_key but no group???");
+
+    return ossl_ec_point_dup(point, group);
+}
+
+/*
+ *  call-seq:
+ *     key.public_key = ec_point
+ *
+ *  See the OpenSSL documentation for EC_KEY_set_public_key()
+ */
+static VALUE ossl_ec_key_set_public_key(VALUE self, VALUE public_key)
+{
+    EC_KEY *ec;
+    EC_POINT *point = NULL;
+
+    Require_EC_KEY(self, ec);
+    if (!NIL_P(public_key))
+        SafeRequire_EC_POINT(public_key, point);
+
+    switch (EC_KEY_set_public_key(ec, point)) {
+    case 1:
+        break;
+    case 0:
+        if (point == NULL)
+            break;
+    default:
+        ossl_raise(eECError, "EC_KEY_set_public_key");
+    }
+
+    return public_key;
+}
+
+/*
+ *  call-seq:
+ *     key.public_key? => true or false
+ *
+ *  Both public_key? and private_key? may return false at the same time unlike other PKey classes.
+ */
+static VALUE ossl_ec_key_is_public_key(VALUE self)
+{
+    EC_KEY *ec;
+
+    Require_EC_KEY(self, ec);
+
+    return (EC_KEY_get0_public_key(ec) ? Qtrue : Qfalse);
+}
+
+/*
+ *  call-seq:
+ *     key.private_key? => true or false
+ *
+ *  Both public_key? and private_key? may return false at the same time unlike other PKey classes.
+ */
+static VALUE ossl_ec_key_is_private_key(VALUE self)
+{
+    EC_KEY *ec;
+
+    Require_EC_KEY(self, ec);
+
+    return (EC_KEY_get0_private_key(ec) ? Qtrue : Qfalse);
+}
+
+static VALUE ossl_ec_key_to_string(VALUE self, VALUE ciph, VALUE pass, int format)
+{
+    EC_KEY *ec;
+    BIO *out;
+    int i = -1;
+    int private = 0;
+    char *password = NULL;
+    VALUE str;
+
+    Require_EC_KEY(self, ec);
+
+    if (EC_KEY_get0_public_key(ec) == NULL)
+        ossl_raise(eECError, "can't export - no public key set");
+
+    if (EC_KEY_check_key(ec) != 1)
+       ossl_raise(eECError, "can't export - EC_KEY_check_key failed");
+
+    if (EC_KEY_get0_private_key(ec))
+        private = 1;
+
+    if (!(out = BIO_new(BIO_s_mem())))
+        ossl_raise(eECError, "BIO_new(BIO_s_mem())");
+
+    switch(format) {
+    case EXPORT_PEM:
+       if (private) {
+           const EVP_CIPHER *cipher;
+           if (!NIL_P(ciph)) {
+               cipher = GetCipherPtr(ciph);
+               if (!NIL_P(pass)) {
+                   password = StringValuePtr(pass);
+               }
+           }
+           else {
+               cipher = NULL;
+           }
+            i = PEM_write_bio_ECPrivateKey(out, ec, cipher, NULL, 0, NULL, password);
+       } else {
+            i = PEM_write_bio_EC_PUBKEY(out, ec);
+        }
+
+       break;
+    case EXPORT_DER:
+        if (private) {
+            i = i2d_ECPrivateKey_bio(out, ec);
+        } else {
+            i = i2d_EC_PUBKEY_bio(out, ec);
+        }
+
+       break;
+    default:
+        BIO_free(out);
+       ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
+    }
+
+    if (i != 1) {
+        BIO_free(out);
+        ossl_raise(eECError, "outlen=%d", i);
+    }
+
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     key.to_pem   => String
+ *     key.to_pem(cipher, pass_phrase) => String
+ *
+ * Outputs the EC key in PEM encoding.  If +cipher+ and +pass_phrase+ are
+ * given they will be used to encrypt the key.  +cipher+ must be an
+ * OpenSSL::Cipher::Cipher instance. Note that encryption will only be
+ * effective for a private key, public keys will always be encoded in plain
+ * text.
+ *
+ */
+static VALUE ossl_ec_key_to_pem(int argc, VALUE *argv, VALUE self)
+{
+    VALUE cipher, passwd;
+    rb_scan_args(argc, argv, "02", &cipher, &passwd);
+    return ossl_ec_key_to_string(self, cipher, passwd, EXPORT_PEM);
+}
+
+/*
+ *  call-seq:
+ *     key.to_der   => String
+ *
+ *  See the OpenSSL documentation for i2d_ECPrivateKey_bio()
+ */
+static VALUE ossl_ec_key_to_der(VALUE self)
+{
+    return ossl_ec_key_to_string(self, Qnil, Qnil, EXPORT_DER);
+}
+
+/*
+ *  call-seq:
+ *     key.to_text   => String
+ *
+ *  See the OpenSSL documentation for EC_KEY_print()
+ */
+static VALUE ossl_ec_key_to_text(VALUE self)
+{
+    EC_KEY *ec;
+    BIO *out;
+    VALUE str;
+
+    Require_EC_KEY(self, ec);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eECError, "BIO_new(BIO_s_mem())");
+    }
+    if (!EC_KEY_print(out, ec, 0)) {
+       BIO_free(out);
+       ossl_raise(eECError, "EC_KEY_print");
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     key.generate_key   => self
+ *
+ *  See the OpenSSL documentation for EC_KEY_generate_key()
+ */
+static VALUE ossl_ec_key_generate_key(VALUE self)
+{
+    EC_KEY *ec;
+
+    Require_EC_KEY(self, ec);
+
+    if (EC_KEY_generate_key(ec) != 1)
+       ossl_raise(eECError, "EC_KEY_generate_key");
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     key.check_key   => true
+ *
+ *  Raises an exception if the key is invalid.
+ *
+ *  See the OpenSSL documentation for EC_KEY_check_key()
+ */
+static VALUE ossl_ec_key_check_key(VALUE self)
+{
+    EC_KEY *ec;
+
+    Require_EC_KEY(self, ec);
+
+    if (EC_KEY_check_key(ec) != 1)
+       ossl_raise(eECError, "EC_KEY_check_key");
+
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
+ *     key.dh_compute_key(pubkey)   => String
+ *
+ *  See the OpenSSL documentation for ECDH_compute_key()
+ */
+static VALUE ossl_ec_key_dh_compute_key(VALUE self, VALUE pubkey)
+{
+    EC_KEY *ec;
+    EC_POINT *point;
+    int buf_len;
+    VALUE str;
+
+    Require_EC_KEY(self, ec);
+    SafeRequire_EC_POINT(pubkey, point);
+
+/* BUG: need a way to figure out the maximum string size */
+    buf_len = 1024;
+    str = rb_str_new(0, buf_len);
+/* BUG: take KDF as a block */
+    buf_len = ECDH_compute_key(RSTRING_PTR(str), buf_len, point, ec, NULL);
+    if (buf_len < 0)
+         ossl_raise(eECError, "ECDH_compute_key");
+
+    rb_str_resize(str, buf_len);
+
+    return str;
+}
+
+/* sign_setup */
+
+/*
+ *  call-seq:
+ *     key.dsa_sign_asn1(data)   => String
+ *
+ *  See the OpenSSL documentation for ECDSA_sign()
+ */
+static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE data)
+{
+    EC_KEY *ec;
+    unsigned int buf_len;
+    VALUE str;
+
+    Require_EC_KEY(self, ec);
+    StringValue(data);
+
+    if (EC_KEY_get0_private_key(ec) == NULL)
+       ossl_raise(eECError, "Private EC key needed!");
+
+    str = rb_str_new(0, ECDSA_size(ec) + 16);
+    if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
+         ossl_raise(eECError, "ECDSA_sign");
+
+    rb_str_resize(str, buf_len);
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     key.dsa_verify_asn1(data, sig)   => true or false
+ *
+ *  See the OpenSSL documentation for ECDSA_verify()
+ */
+static VALUE ossl_ec_key_dsa_verify_asn1(VALUE self, VALUE data, VALUE sig)
+{
+    EC_KEY *ec;
+
+    Require_EC_KEY(self, ec);
+    StringValue(data);
+    StringValue(sig);
+
+    switch (ECDSA_verify(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(sig), (int)RSTRING_LEN(sig), ec)) {
+    case 1:    return Qtrue;
+    case 0:    return Qfalse;
+    default:   break;
+    }
+
+    ossl_raise(eECError, "ECDSA_verify");
+}
+
+static void ossl_ec_group_free(ossl_ec_group *ec_group)
+{
+    if (!ec_group->dont_free && ec_group->group)
+        EC_GROUP_clear_free(ec_group->group);
+    ruby_xfree(ec_group);
+}
+
+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);
+
+    return obj;
+}
+
+/*  call-seq:
+ *     OpenSSL::PKey::EC::Group.new("secp112r1")
+ *     OpenSSL::PKey::EC::Group.new(ec_group)
+ *     OpenSSL::PKey::EC::Group.new(pem_string)
+ *     OpenSSL::PKey::EC::Group.new(der_string)
+ *     OpenSSL::PKey::EC::Group.new(pem_file)
+ *     OpenSSL::PKey::EC::Group.new(der_file)
+ *     OpenSSL::PKey::EC::Group.new(:GFp_simple)
+ *     OpenSSL::PKey::EC::Group.new(:GFp_mult)
+ *     OpenSSL::PKey::EC::Group.new(:GFp_nist)
+ *     OpenSSL::PKey::EC::Group.new(:GF2m_simple)
+ *     OpenSSL::PKey::EC::Group.new(:GFp, bignum_p, bignum_a, bignum_b)
+ *     OpenSSL::PKey::EC::Group.new(:GF2m, bignum_p, bignum_a, bignum_b)
+ *
+ *  See the OpenSSL documentation for EC_GROUP_*
+ */
+static VALUE ossl_ec_group_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE arg1, arg2, arg3, arg4;
+    ossl_ec_group *ec_group;
+    EC_GROUP *group = NULL;
+
+    Data_Get_Struct(self, ossl_ec_group, ec_group);
+    if (ec_group->group != NULL)
+        ossl_raise(rb_eRuntimeError, "EC_GROUP is already initialized");
+
+    switch (rb_scan_args(argc, argv, "13", &arg1, &arg2, &arg3, &arg4)) {
+    case 1:
+        if (SYMBOL_P(arg1)) {
+            const EC_METHOD *method = NULL;
+            ID id = SYM2ID(arg1);
+
+            if (id == s_GFp_simple) {
+                method = EC_GFp_simple_method();
+            } else if (id == s_GFp_mont) {
+                method = EC_GFp_mont_method();
+            } else if (id == s_GFp_nist) {
+                method = EC_GFp_nist_method();
+#if !defined(OPENSSL_NO_EC2M)
+            } else if (id == s_GF2m_simple) {
+                method = EC_GF2m_simple_method();
+#endif
+            }
+
+            if (method) {
+                if ((group = EC_GROUP_new(method)) == NULL)
+                    ossl_raise(eEC_GROUP, "EC_GROUP_new");
+            } else {
+                ossl_raise(rb_eArgError, "unknown symbol, must be :GFp_simple, :GFp_mont, :GFp_nist or :GF2m_simple");
+            }
+        } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
+            const EC_GROUP *arg1_group;
+
+            SafeRequire_EC_GROUP(arg1, arg1_group);
+            if ((group = EC_GROUP_dup(arg1_group)) == NULL)
+                ossl_raise(eEC_GROUP, "EC_GROUP_dup");
+        } else {
+            BIO *in = ossl_obj2bio(arg1);
+
+            group = PEM_read_bio_ECPKParameters(in, NULL, NULL, NULL);
+            if (!group) {
+               OSSL_BIO_reset(in);
+                group = d2i_ECPKParameters_bio(in, NULL);
+            }
+
+            BIO_free(in);
+
+            if (!group) {
+                const char *name = StringValueCStr(arg1);
+                int nid = OBJ_sn2nid(name);
+
+               (void)ERR_get_error();
+                if (nid == NID_undef)
+                    ossl_raise(eEC_GROUP, "unknown curve name (%s)", name);
+
+                group = EC_GROUP_new_by_curve_name(nid);
+                if (group == NULL)
+                    ossl_raise(eEC_GROUP, "unable to create curve (%s)", name);
+
+                EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+                EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
+            }
+        }
+
+        break;
+    case 4:
+        if (SYMBOL_P(arg1)) {
+            ID id = SYM2ID(arg1);
+            EC_GROUP *(*new_curve)(const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
+            const BIGNUM *p = GetBNPtr(arg2);
+            const BIGNUM *a = GetBNPtr(arg3);
+            const BIGNUM *b = GetBNPtr(arg4);
+
+            if (id == s_GFp) {
+                new_curve = EC_GROUP_new_curve_GFp;
+#if !defined(OPENSSL_NO_EC2M)
+            } else if (id == s_GF2m) {
+                new_curve = EC_GROUP_new_curve_GF2m;
+#endif
+            } else {
+                ossl_raise(rb_eArgError, "unknown symbol, must be :GFp or :GF2m");
+            }
+
+            if ((group = new_curve(p, a, b, ossl_bn_ctx)) == NULL)
+                ossl_raise(eEC_GROUP, "EC_GROUP_new_by_GF*");
+        } else {
+             ossl_raise(rb_eArgError, "unknown argument, must be :GFp or :GF2m");
+        }
+
+        break;
+    default:
+        ossl_raise(rb_eArgError, "wrong number of arguments");
+    }
+
+    if (group == NULL)
+        ossl_raise(eEC_GROUP, "");
+
+    ec_group->group = group;
+
+    return self;
+}
+
+/*  call-seq:
+ *     group1 == group2   => true | false
+ *
+ */
+static VALUE ossl_ec_group_eql(VALUE a, VALUE b)
+{
+    EC_GROUP *group1 = NULL, *group2 = NULL;
+
+    Require_EC_GROUP(a, group1);
+    SafeRequire_EC_GROUP(b, group2);
+
+    if (EC_GROUP_cmp(group1, group2, ossl_bn_ctx) == 1)
+       return Qfalse;
+
+    return Qtrue;
+}
+
+/*  call-seq:
+ *     group.generator   => ec_point
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get0_generator()
+ */
+static VALUE ossl_ec_group_get_generator(VALUE self)
+{
+    VALUE point_obj;
+    EC_GROUP *group = NULL;
+
+    Require_EC_GROUP(self, group);
+
+    point_obj = ossl_ec_point_dup(EC_GROUP_get0_generator(group), self);
+
+    return point_obj;
+}
+
+/*  call-seq:
+ *     group.set_generator(generator, order, cofactor)   => self
+ *
+ *  See the OpenSSL documentation for EC_GROUP_set_generator()
+ */
+static VALUE ossl_ec_group_set_generator(VALUE self, VALUE generator, VALUE order, VALUE cofactor)
+{
+    EC_GROUP *group = NULL;
+    const EC_POINT *point;
+    const BIGNUM *o, *co;
+
+    Require_EC_GROUP(self, group);
+    SafeRequire_EC_POINT(generator, point);
+    o = GetBNPtr(order);
+    co = GetBNPtr(cofactor);
+
+    if (EC_GROUP_set_generator(group, point, o, co) != 1)
+        ossl_raise(eEC_GROUP, "EC_GROUP_set_generator");
+
+    return self;
+}
+
+/*  call-seq:
+ *     group.get_order   => order_bn
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get_order()
+ */
+static VALUE ossl_ec_group_get_order(VALUE self)
+{
+    VALUE bn_obj;
+    BIGNUM *bn;
+    EC_GROUP *group = NULL;
+
+    Require_EC_GROUP(self, group);
+
+    bn_obj = ossl_bn_new(NULL);
+    bn = GetBNPtr(bn_obj);
+
+    if (EC_GROUP_get_order(group, bn, ossl_bn_ctx) != 1)
+        ossl_raise(eEC_GROUP, "EC_GROUP_get_order");
+
+    return bn_obj;
+}
+
+/*  call-seq:
+ *     group.get_cofactor   => cofactor_bn
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get_cofactor()
+ */
+static VALUE ossl_ec_group_get_cofactor(VALUE self)
+{
+    VALUE bn_obj;
+    BIGNUM *bn;
+    EC_GROUP *group = NULL;
+
+    Require_EC_GROUP(self, group);
+
+    bn_obj = ossl_bn_new(NULL);
+    bn = GetBNPtr(bn_obj);
+
+    if (EC_GROUP_get_cofactor(group, bn, ossl_bn_ctx) != 1)
+        ossl_raise(eEC_GROUP, "EC_GROUP_get_cofactor");
+
+    return bn_obj;
+}
+
+/*  call-seq:
+ *     group.curve_name  => String
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get_curve_name()
+ */
+static VALUE ossl_ec_group_get_curve_name(VALUE self)
+{
+    EC_GROUP *group = NULL;
+    int nid;
+
+    Get_EC_GROUP(self, group);
+    if (group == NULL)
+        return Qnil;
+
+    nid = EC_GROUP_get_curve_name(group);
+
+/* BUG: an nid or asn1 object should be returned, maybe. */
+    return rb_str_new2(OBJ_nid2sn(nid));
+}
+
+/*  call-seq:
+ *     EC.builtin_curves => [[name, comment], ...]
+ *
+ *  See the OpenSSL documentation for EC_builtin_curves()
+ */
+static VALUE ossl_s_builtin_curves(VALUE self)
+{
+    EC_builtin_curve *curves = NULL;
+    int n;
+    int crv_len = rb_long2int(EC_get_builtin_curves(NULL, 0));
+    VALUE ary, ret;
+
+    curves = ALLOCA_N(EC_builtin_curve, crv_len);
+    if (curves == NULL)
+        return Qnil;
+    if (!EC_get_builtin_curves(curves, crv_len))
+        ossl_raise(rb_eRuntimeError, "EC_get_builtin_curves");
+
+    ret = rb_ary_new2(crv_len);
+
+    for (n = 0; n < crv_len; n++) {
+        const char *sname = OBJ_nid2sn(curves[n].nid);
+        const char *comment = curves[n].comment;
+
+        ary = rb_ary_new2(2);
+        rb_ary_push(ary, rb_str_new2(sname));
+        rb_ary_push(ary, comment ? rb_str_new2(comment) : Qnil);
+        rb_ary_push(ret, ary);
+    }
+
+    return ret;
+}
+
+/*  call-seq:
+ *     group.asn1_flag  => Fixnum
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get_asn1_flag()
+ */
+static VALUE ossl_ec_group_get_asn1_flag(VALUE self)
+{
+    EC_GROUP *group = NULL;
+    int flag;
+
+    Require_EC_GROUP(self, group);
+
+    flag = EC_GROUP_get_asn1_flag(group);
+
+    return INT2FIX(flag);
+}
+
+/*  call-seq:
+ *     group.asn1_flag = Fixnum   => Fixnum
+ *
+ *  See the OpenSSL documentation for EC_GROUP_set_asn1_flag()
+ */
+static VALUE ossl_ec_group_set_asn1_flag(VALUE self, VALUE flag_v)
+{
+    EC_GROUP *group = NULL;
+
+    Require_EC_GROUP(self, group);
+
+    EC_GROUP_set_asn1_flag(group, NUM2INT(flag_v));
+
+    return flag_v;
+}
+
+/*  call-seq:
+ *     group.point_conversion_form  => :uncompressed | :compressed | :hybrid
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get_point_conversion_form()
+ */
+static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
+{
+    EC_GROUP *group = NULL;
+    point_conversion_form_t form;
+    VALUE ret;
+
+    Require_EC_GROUP(self, group);
+
+    form = EC_GROUP_get_point_conversion_form(group);
+
+    switch (form) {
+    case POINT_CONVERSION_UNCOMPRESSED:        ret = ID_uncompressed; break;
+    case POINT_CONVERSION_COMPRESSED:  ret = ID_compressed; break;
+    case POINT_CONVERSION_HYBRID:      ret = ID_hybrid; break;
+    default:   ossl_raise(eEC_GROUP, "unsupported point conversion form: %d, this module should be updated", form);
+    }
+
+   return ID2SYM(ret);
+}
+
+/*  call-seq:
+ *     group.point_conversion_form = form => form
+ *
+ *  See the OpenSSL documentation for EC_GROUP_set_point_conversion_form()
+ */
+static VALUE ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
+{
+    EC_GROUP *group = NULL;
+    point_conversion_form_t form;
+    ID form_id = SYM2ID(form_v);
+
+    Require_EC_GROUP(self, group);
+
+    if (form_id == ID_uncompressed) {
+        form = POINT_CONVERSION_UNCOMPRESSED;
+    } else if (form_id == ID_compressed) {
+        form = POINT_CONVERSION_COMPRESSED;
+    } else if (form_id == ID_hybrid) {
+        form = POINT_CONVERSION_HYBRID;
+    } else {
+        ossl_raise(rb_eArgError, "form must be :compressed, :uncompressed, or :hybrid");
+    }
+
+    EC_GROUP_set_point_conversion_form(group, form);
+
+    return form_v;
+}
+
+/*  call-seq:
+ *     group.seed   => String or nil
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get0_seed()
+ */
+static VALUE ossl_ec_group_get_seed(VALUE self)
+{
+    EC_GROUP *group = NULL;
+    size_t seed_len;
+
+    Require_EC_GROUP(self, group);
+
+    seed_len = EC_GROUP_get_seed_len(group);
+
+    if (seed_len == 0)
+        return Qnil;
+
+    return rb_str_new((const char *)EC_GROUP_get0_seed(group), seed_len);
+}
+
+/*  call-seq:
+ *     group.seed = seed  => seed
+ *
+ *  See the OpenSSL documentation for EC_GROUP_set_seed()
+ */
+static VALUE ossl_ec_group_set_seed(VALUE self, VALUE seed)
+{
+    EC_GROUP *group = NULL;
+
+    Require_EC_GROUP(self, group);
+    StringValue(seed);
+
+    if (EC_GROUP_set_seed(group, (unsigned char *)RSTRING_PTR(seed), RSTRING_LEN(seed)) != (size_t)RSTRING_LEN(seed))
+        ossl_raise(eEC_GROUP, "EC_GROUP_set_seed");
+
+    return seed;
+}
+
+/* get/set curve GFp, GF2m */
+
+/*  call-seq:
+ *     group.degree   => Fixnum
+ *
+ *  See the OpenSSL documentation for EC_GROUP_get_degree()
+ */
+static VALUE ossl_ec_group_get_degree(VALUE self)
+{
+    EC_GROUP *group = NULL;
+
+    Require_EC_GROUP(self, group);
+
+    return INT2NUM(EC_GROUP_get_degree(group));
+}
+
+static VALUE ossl_ec_group_to_string(VALUE self, int format)
+{
+    EC_GROUP *group;
+    BIO *out;
+    int i = -1;
+    VALUE str;
+
+    Get_EC_GROUP(self, group);
+
+    if (!(out = BIO_new(BIO_s_mem())))
+        ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
+
+    switch(format) {
+    case EXPORT_PEM:
+        i = PEM_write_bio_ECPKParameters(out, group);
+       break;
+    case EXPORT_DER:
+        i = i2d_ECPKParameters_bio(out, group);
+       break;
+    default:
+        BIO_free(out);
+       ossl_raise(rb_eRuntimeError, "unknown format (internal error)");
+    }
+
+    if (i != 1) {
+        BIO_free(out);
+        ossl_raise(eECError, NULL);
+    }
+
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*  call-seq:
+ *     group.to_pem   => String
+ *
+ *  See the OpenSSL documentation for PEM_write_bio_ECPKParameters()
+ */
+static VALUE ossl_ec_group_to_pem(VALUE self)
+{
+    return ossl_ec_group_to_string(self, EXPORT_PEM);
+}
+
+/*  call-seq:
+ *     group.to_der   => String
+ *
+ *  See the OpenSSL documentation for i2d_ECPKParameters_bio()
+ */
+static VALUE ossl_ec_group_to_der(VALUE self)
+{
+    return ossl_ec_group_to_string(self, EXPORT_DER);
+}
+
+/*  call-seq:
+ *     group.to_text   => String
+ *
+ *  See the OpenSSL documentation for ECPKParameters_print()
+ */
+static VALUE ossl_ec_group_to_text(VALUE self)
+{
+    EC_GROUP *group;
+    BIO *out;
+    VALUE str;
+
+    Require_EC_GROUP(self, group);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eEC_GROUP, "BIO_new(BIO_s_mem())");
+    }
+    if (!ECPKParameters_print(out, group, 0)) {
+       BIO_free(out);
+       ossl_raise(eEC_GROUP, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+
+static void ossl_ec_point_free(ossl_ec_point *ec_point)
+{
+    if (!ec_point->dont_free && ec_point->point)
+        EC_POINT_clear_free(ec_point->point);
+    ruby_xfree(ec_point);
+}
+
+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);
+
+    return obj;
+}
+
+/*
+ *  call-seq:
+ *     OpenSSL::PKey::EC::Point.new(point)
+ *     OpenSSL::PKey::EC::Point.new(group)
+ *     OpenSSL::PKey::EC::Point.new(group, bn)
+ *
+ *  See the OpenSSL documentation for EC_POINT_*
+ */
+static VALUE ossl_ec_point_initialize(int argc, VALUE *argv, VALUE self)
+{
+    ossl_ec_point *ec_point;
+    EC_POINT *point = NULL;
+    VALUE arg1, arg2;
+    VALUE group_v = Qnil;
+    const EC_GROUP *group = NULL;
+
+    Data_Get_Struct(self, ossl_ec_point, ec_point);
+    if (ec_point->point)
+        ossl_raise(eEC_POINT, "EC_POINT already initialized");
+
+    switch (rb_scan_args(argc, argv, "11", &arg1, &arg2)) {
+    case 1:
+        if (rb_obj_is_kind_of(arg1, cEC_POINT)) {
+            const EC_POINT *arg_point;
+
+            group_v = rb_iv_get(arg1, "@group");
+            SafeRequire_EC_GROUP(group_v, group);
+            SafeRequire_EC_POINT(arg1, arg_point);
+
+            point = EC_POINT_dup(arg_point, group);
+        } else if (rb_obj_is_kind_of(arg1, cEC_GROUP)) {
+            group_v = arg1;
+            SafeRequire_EC_GROUP(group_v, group);
+
+            point = EC_POINT_new(group);
+        } else {
+            ossl_raise(eEC_POINT, "wrong argument type: must be OpenSSL::PKey::EC::Point or OpenSSL::Pkey::EC::Group");
+        }
+
+        break;
+     case 2:
+        if (!rb_obj_is_kind_of(arg1, cEC_GROUP))
+            ossl_raise(rb_eArgError, "1st argument must be OpenSSL::PKey::EC::Group");
+        group_v = arg1;
+        SafeRequire_EC_GROUP(group_v, group);
+
+        if (rb_obj_is_kind_of(arg2, cBN)) {
+            const BIGNUM *bn = GetBNPtr(arg2);
+
+            point = EC_POINT_bn2point(group, bn, NULL, ossl_bn_ctx);
+        } else {
+            BIO *in = ossl_obj2bio(arg1);
+
+/* BUG: finish me */
+
+            BIO_free(in);
+
+            if (point == NULL) {
+                ossl_raise(eEC_POINT, "unknown type for 2nd arg");
+            }
+        }
+        break;
+    default:
+        ossl_raise(rb_eArgError, "wrong number of arguments");
+    }
+
+    if (point == NULL)
+        ossl_raise(eEC_POINT, NULL);
+
+    if (NIL_P(group_v))
+        ossl_raise(rb_eRuntimeError, "missing group (internal error)");
+
+    ec_point->point = point;
+
+    rb_iv_set(self, "@group", group_v);
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     point1 == point2 => true | false
+ *
+ */
+static VALUE ossl_ec_point_eql(VALUE a, VALUE b)
+{
+    EC_POINT *point1, *point2;
+    VALUE group_v1 = rb_iv_get(a, "@group");
+    VALUE group_v2 = rb_iv_get(b, "@group");
+    const EC_GROUP *group;
+
+    if (ossl_ec_group_eql(group_v1, group_v2) == Qfalse)
+        return Qfalse;
+
+    Require_EC_POINT(a, point1);
+    SafeRequire_EC_POINT(b, point2);
+    SafeRequire_EC_GROUP(group_v1, group);
+
+    if (EC_POINT_cmp(group, point1, point2, ossl_bn_ctx) == 1)
+        return Qfalse;
+
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
+ *     point.infinity? => true | false
+ *
+ */
+static VALUE ossl_ec_point_is_at_infinity(VALUE self)
+{
+    EC_POINT *point;
+    VALUE group_v = rb_iv_get(self, "@group");
+    const EC_GROUP *group;
+
+    Require_EC_POINT(self, point);
+    SafeRequire_EC_GROUP(group_v, group);
+
+    switch (EC_POINT_is_at_infinity(group, point)) {
+    case 1: return Qtrue;
+    case 0: return Qfalse;
+    default: ossl_raise(cEC_POINT, "EC_POINT_is_at_infinity");
+    }
+}
+
+/*
+ *  call-seq:
+ *     point.on_curve? => true | false
+ *
+ */
+static VALUE ossl_ec_point_is_on_curve(VALUE self)
+{
+    EC_POINT *point;
+    VALUE group_v = rb_iv_get(self, "@group");
+    const EC_GROUP *group;
+
+    Require_EC_POINT(self, point);
+    SafeRequire_EC_GROUP(group_v, group);
+
+    switch (EC_POINT_is_on_curve(group, point, ossl_bn_ctx)) {
+    case 1: return Qtrue;
+    case 0: return Qfalse;
+    default: ossl_raise(cEC_POINT, "EC_POINT_is_on_curve");
+    }
+}
+
+/*
+ *  call-seq:
+ *     point.make_affine! => self
+ *
+ */
+static VALUE ossl_ec_point_make_affine(VALUE self)
+{
+    EC_POINT *point;
+    VALUE group_v = rb_iv_get(self, "@group");
+    const EC_GROUP *group;
+
+    Require_EC_POINT(self, point);
+    SafeRequire_EC_GROUP(group_v, group);
+
+    if (EC_POINT_make_affine(group, point, ossl_bn_ctx) != 1)
+        ossl_raise(cEC_POINT, "EC_POINT_make_affine");
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     point.invert! => self
+ *
+ */
+static VALUE ossl_ec_point_invert(VALUE self)
+{
+    EC_POINT *point;
+    VALUE group_v = rb_iv_get(self, "@group");
+    const EC_GROUP *group;
+
+    Require_EC_POINT(self, point);
+    SafeRequire_EC_GROUP(group_v, group);
+
+    if (EC_POINT_invert(group, point, ossl_bn_ctx) != 1)
+        ossl_raise(cEC_POINT, "EC_POINT_invert");
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     point.set_to_infinity! => self
+ *
+ */
+static VALUE ossl_ec_point_set_to_infinity(VALUE self)
+{
+    EC_POINT *point;
+    VALUE group_v = rb_iv_get(self, "@group");
+    const EC_GROUP *group;
+
+    Require_EC_POINT(self, point);
+    SafeRequire_EC_GROUP(group_v, group);
+
+    if (EC_POINT_set_to_infinity(group, point) != 1)
+        ossl_raise(cEC_POINT, "EC_POINT_set_to_infinity");
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     point.to_bn   => OpenSSL::BN
+ *
+ *  See the OpenSSL documentation for EC_POINT_point2bn()
+ */
+static VALUE ossl_ec_point_to_bn(VALUE self)
+{
+    EC_POINT *point;
+    VALUE bn_obj;
+    VALUE group_v = rb_iv_get(self, "@group");
+    const EC_GROUP *group;
+    point_conversion_form_t form;
+    BIGNUM *bn;
+
+    Require_EC_POINT(self, point);
+    SafeRequire_EC_GROUP(group_v, group);
+
+    form = EC_GROUP_get_point_conversion_form(group);
+
+    bn_obj = rb_obj_alloc(cBN);
+    bn = GetBNPtr(bn_obj);
+
+    if (EC_POINT_point2bn(group, point, form, bn, ossl_bn_ctx) == NULL)
+        ossl_raise(eEC_POINT, "EC_POINT_point2bn");
+
+    return bn_obj;
+}
+
+static void no_copy(VALUE klass)
+{
+    rb_undef_method(klass, "copy");
+    rb_undef_method(klass, "clone");
+    rb_undef_method(klass, "dup");
+    rb_undef_method(klass, "initialize_copy");
+}
+
+void Init_ossl_ec()
+{
+#ifdef DONT_NEED_RDOC_WORKAROUND
+    mOSSL = rb_define_module("OpenSSL");
+    mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
+    eECError = rb_define_class_under(mPKey, "ECError", ePKeyError);
+
+    cEC = rb_define_class_under(mPKey, "EC", cPKey);
+    cEC_GROUP = rb_define_class_under(cEC, "Group", rb_cObject);
+    cEC_POINT = rb_define_class_under(cEC, "Point", rb_cObject);
+    eEC_GROUP = rb_define_class_under(cEC_GROUP, "Error", eOSSLError);
+    eEC_POINT = rb_define_class_under(cEC_POINT, "Error", eOSSLError);
+
+    s_GFp = rb_intern("GFp");
+    s_GF2m = rb_intern("GF2m");
+    s_GFp_simple = rb_intern("GFp_simple");
+    s_GFp_mont = rb_intern("GFp_mont");
+    s_GFp_nist = rb_intern("GFp_nist");
+    s_GF2m_simple = rb_intern("GF2m_simple");
+
+    ID_uncompressed = rb_intern("uncompressed");
+    ID_compressed = rb_intern("compressed");
+    ID_hybrid = rb_intern("hybrid");
+
+#ifdef OPENSSL_EC_NAMED_CURVE
+    rb_define_const(cEC, "NAMED_CURVE", ULONG2NUM(OPENSSL_EC_NAMED_CURVE));
+#endif
+
+    rb_define_singleton_method(cEC, "builtin_curves", ossl_s_builtin_curves, 0);
+
+    rb_define_method(cEC, "initialize", ossl_ec_key_initialize, -1);
+/* copy/dup/cmp */
+
+    rb_define_method(cEC, "group", ossl_ec_key_get_group, 0);
+    rb_define_method(cEC, "group=", ossl_ec_key_set_group, 1);
+    rb_define_method(cEC, "private_key", ossl_ec_key_get_private_key, 0);
+    rb_define_method(cEC, "private_key=", ossl_ec_key_set_private_key, 1);
+    rb_define_method(cEC, "public_key", ossl_ec_key_get_public_key, 0);
+    rb_define_method(cEC, "public_key=", ossl_ec_key_set_public_key, 1);
+    rb_define_method(cEC, "private_key?", ossl_ec_key_is_private_key, 0);
+    rb_define_method(cEC, "public_key?", ossl_ec_key_is_public_key, 0);
+/*  rb_define_method(cEC, "", ossl_ec_key_get_, 0);
+    rb_define_method(cEC, "=", ossl_ec_key_set_ 1);
+    set/get enc_flags
+    set/get _conv_from
+    set/get asn1_flag (can use ruby to call self.group.asn1_flag)
+    set/get precompute_mult
+*/
+    rb_define_method(cEC, "generate_key", ossl_ec_key_generate_key, 0);
+    rb_define_method(cEC, "check_key", ossl_ec_key_check_key, 0);
+
+    rb_define_method(cEC, "dh_compute_key", ossl_ec_key_dh_compute_key, 1);
+    rb_define_method(cEC, "dsa_sign_asn1", ossl_ec_key_dsa_sign_asn1, 1);
+    rb_define_method(cEC, "dsa_verify_asn1", ossl_ec_key_dsa_verify_asn1, 2);
+/* do_sign/do_verify */
+
+    rb_define_method(cEC, "to_pem", ossl_ec_key_to_pem, -1);
+    rb_define_method(cEC, "to_der", ossl_ec_key_to_der, 0);
+    rb_define_method(cEC, "to_text", ossl_ec_key_to_text, 0);
+
+
+    rb_define_alloc_func(cEC_GROUP, ossl_ec_group_alloc);
+    rb_define_method(cEC_GROUP, "initialize", ossl_ec_group_initialize, -1);
+    rb_define_method(cEC_GROUP, "eql?", ossl_ec_group_eql, 1);
+    rb_define_alias(cEC_GROUP, "==", "eql?");
+/* copy/dup/cmp */
+
+    rb_define_method(cEC_GROUP, "generator", ossl_ec_group_get_generator, 0);
+    rb_define_method(cEC_GROUP, "set_generator", ossl_ec_group_set_generator, 3);
+    rb_define_method(cEC_GROUP, "order", ossl_ec_group_get_order, 0);
+    rb_define_method(cEC_GROUP, "cofactor", ossl_ec_group_get_cofactor, 0);
+
+    rb_define_method(cEC_GROUP, "curve_name", ossl_ec_group_get_curve_name, 0);
+/*    rb_define_method(cEC_GROUP, "curve_name=", ossl_ec_group_set_curve_name, 1); */
+
+    rb_define_method(cEC_GROUP, "asn1_flag", ossl_ec_group_get_asn1_flag, 0);
+    rb_define_method(cEC_GROUP, "asn1_flag=", ossl_ec_group_set_asn1_flag, 1);
+
+    rb_define_method(cEC_GROUP, "point_conversion_form", ossl_ec_group_get_point_conversion_form, 0);
+    rb_define_method(cEC_GROUP, "point_conversion_form=", ossl_ec_group_set_point_conversion_form, 1);
+
+    rb_define_method(cEC_GROUP, "seed", ossl_ec_group_get_seed, 0);
+    rb_define_method(cEC_GROUP, "seed=", ossl_ec_group_set_seed, 1);
+
+/* get/set GFp, GF2m */
+
+    rb_define_method(cEC_GROUP, "degree", ossl_ec_group_get_degree, 0);
+
+/* check* */
+
+
+    rb_define_method(cEC_GROUP, "to_pem", ossl_ec_group_to_pem, 0);
+    rb_define_method(cEC_GROUP, "to_der", ossl_ec_group_to_der, 0);
+    rb_define_method(cEC_GROUP, "to_text", ossl_ec_group_to_text, 0);
+
+
+    rb_define_alloc_func(cEC_POINT, ossl_ec_point_alloc);
+    rb_define_method(cEC_POINT, "initialize", ossl_ec_point_initialize, -1);
+    rb_attr(cEC_POINT, rb_intern("group"), 1, 0, 0);
+    rb_define_method(cEC_POINT, "eql?", ossl_ec_point_eql, 1);
+    rb_define_alias(cEC_POINT, "==", "eql?");
+
+    rb_define_method(cEC_POINT, "infinity?", ossl_ec_point_is_at_infinity, 0);
+    rb_define_method(cEC_POINT, "on_curve?", ossl_ec_point_is_on_curve, 0);
+    rb_define_method(cEC_POINT, "make_affine!", ossl_ec_point_make_affine, 0);
+    rb_define_method(cEC_POINT, "invert!", ossl_ec_point_invert, 0);
+    rb_define_method(cEC_POINT, "set_to_infinity!", ossl_ec_point_set_to_infinity, 0);
+/* all the other methods */
+
+    rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, 0);
+
+    no_copy(cEC);
+    no_copy(cEC_GROUP);
+    no_copy(cEC_POINT);
+}
+
+#else /* defined NO_EC */
+void Init_ossl_ec()
+{
+}
+#endif /* NO_EC */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_rsa.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_pkey_rsa.c
new file mode 100644 (file)
index 0000000..eba693b
--- /dev/null
@@ -0,0 +1,632 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(OPENSSL_NO_RSA)
+
+#include "ossl.h"
+
+#define GetPKeyRSA(obj, pkey) do { \
+    GetPKey((obj), (pkey)); \
+    if (EVP_PKEY_type((pkey)->type) != EVP_PKEY_RSA) { /* PARANOIA? */ \
+       ossl_raise(rb_eRuntimeError, "THIS IS NOT A RSA!") ; \
+    } \
+} while (0)
+
+#define RSA_HAS_PRIVATE(rsa) ((rsa)->p && (rsa)->q)
+#define RSA_PRIVATE(obj,rsa) (RSA_HAS_PRIVATE(rsa)||OSSL_PKEY_IS_PRIVATE(obj))
+
+/*
+ * Classes
+ */
+VALUE cRSA;
+VALUE eRSAError;
+
+/*
+ * Public
+ */
+static VALUE
+rsa_instance(VALUE klass, RSA *rsa)
+{
+    EVP_PKEY *pkey;
+    VALUE obj;
+
+    if (!rsa) {
+       return Qfalse;
+    }
+    if (!(pkey = EVP_PKEY_new())) {
+       return Qfalse;
+    }
+    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
+       EVP_PKEY_free(pkey);
+       return Qfalse;
+    }
+    WrapPKey(klass, obj, pkey);
+
+    return obj;
+}
+
+VALUE
+ossl_rsa_new(EVP_PKEY *pkey)
+{
+    VALUE obj;
+
+    if (!pkey) {
+       obj = rsa_instance(cRSA, RSA_new());
+    }
+    else {
+       if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
+           ossl_raise(rb_eTypeError, "Not a RSA key!");
+       }
+       WrapPKey(cRSA, obj, pkey);
+    }
+    if (obj == Qfalse) {
+       ossl_raise(eRSAError, NULL);
+    }
+
+    return obj;
+}
+
+/*
+ * Private
+ */
+static RSA *
+rsa_generate(int size, int exp)
+{
+    return RSA_generate_key(size, exp,
+           rb_block_given_p() ? ossl_generate_cb : NULL,
+           NULL);
+}
+
+/*
+ * call-seq:
+ *   RSA.generate(size)           => RSA instance
+ *   RSA.generate(size, exponent) => RSA instance
+ *
+ * Generates an RSA keypair.  +size+ is an integer representing the desired key
+ * size.  Keys smaller than 1024 should be considered insecure.  +exponent+ is
+ * an odd number normally 3, 17, or 65537.
+ */
+static VALUE
+ossl_rsa_s_generate(int argc, VALUE *argv, VALUE klass)
+{
+/* why does this method exist?  why can't initialize take an optional exponent? */
+    RSA *rsa;
+    VALUE size, exp;
+    VALUE obj;
+
+    rb_scan_args(argc, argv, "11", &size, &exp);
+
+    rsa = rsa_generate(NUM2INT(size), NIL_P(exp) ? RSA_F4 : NUM2INT(exp)); /* err handled by rsa_instance */
+    obj = rsa_instance(klass, rsa);
+
+    if (obj == Qfalse) {
+       RSA_free(rsa);
+       ossl_raise(eRSAError, NULL);
+    }
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *   RSA.new(key_size)                 => RSA instance
+ *   RSA.new(encoded_key)              => RSA instance
+ *   RSA.new(encoded_key, pass_phrase) => RSA instance
+ *
+ * Generates or loads an RSA keypair.  If an integer +key_size+ is given it
+ * represents the desired key size.  Keys less than 1024 bits should be
+ * considered insecure.
+ *
+ * A key can instead be loaded from an +encoded_key+ which must be PEM or DER
+ * encoded.  A +pass_phrase+ can be used to decrypt the key.  If none is given
+ * OpenSSL will prompt for the pass phrase.
+ *
+ * = Examples
+ *
+ *   OpenSSL::PKey::RSA.new 2048
+ *   OpenSSL::PKey::RSA.new File.read 'rsa.pem'
+ *   OpenSSL::PKey::RSA.new File.read('rsa.pem'), 'my pass phrase'
+ */
+static VALUE
+ossl_rsa_initialize(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    RSA *rsa;
+    BIO *in;
+    char *passwd = NULL;
+    VALUE arg, pass;
+
+    GetPKey(self, pkey);
+    if(rb_scan_args(argc, argv, "02", &arg, &pass) == 0) {
+       rsa = RSA_new();
+    }
+    else if (FIXNUM_P(arg)) {
+       rsa = rsa_generate(FIX2INT(arg), NIL_P(pass) ? RSA_F4 : NUM2INT(pass));
+       if (!rsa) ossl_raise(eRSAError, NULL);
+    }
+    else {
+       if (!NIL_P(pass)) passwd = StringValuePtr(pass);
+       arg = ossl_to_der_if_possible(arg);
+       in = ossl_obj2bio(arg);
+       rsa = PEM_read_bio_RSAPrivateKey(in, NULL, ossl_pem_passwd_cb, passwd);
+       if (!rsa) {
+           OSSL_BIO_reset(in);
+           rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL);
+       }
+       if (!rsa) {
+           OSSL_BIO_reset(in);
+           rsa = d2i_RSAPrivateKey_bio(in, NULL);
+       }
+       if (!rsa) {
+           OSSL_BIO_reset(in);
+           rsa = d2i_RSA_PUBKEY_bio(in, NULL);
+       }
+       if (!rsa) {
+           OSSL_BIO_reset(in);
+           rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
+       }
+       if (!rsa) {
+           OSSL_BIO_reset(in);
+           rsa = d2i_RSAPublicKey_bio(in, NULL);
+       }
+       BIO_free(in);
+       if (!rsa) {
+           ossl_raise(eRSAError, "Neither PUB key nor PRIV key:");
+       }
+    }
+    if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
+       RSA_free(rsa);
+       ossl_raise(eRSAError, NULL);
+    }
+
+    return self;
+}
+
+/*
+ * call-seq:
+ *   rsa.public? => true
+ *
+ * The return value is always true since every private key is also a public
+ * key.
+ */
+static VALUE
+ossl_rsa_is_public(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyRSA(self, pkey);
+    /*
+     * This method should check for n and e.  BUG.
+     */
+    return Qtrue;
+}
+
+/*
+ * call-seq:
+ *   rsa.private? => true | false
+ *
+ * Does this keypair contain a private key?
+ */
+static VALUE
+ossl_rsa_is_private(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyRSA(self, pkey);
+
+    return (RSA_PRIVATE(self, pkey->pkey.rsa)) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *   rsa.to_pem                      => PEM-format String
+ *   rsa.to_pem(cipher, pass_phrase) => PEM-format String
+ *
+ * Outputs this keypair in PEM encoding.  If +cipher+ and +pass_phrase+ are
+ * given they will be used to encrypt the key.  +cipher+ must be an
+ * OpenSSL::Cipher::Cipher instance.
+ */
+static VALUE
+ossl_rsa_export(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    BIO *out;
+    const EVP_CIPHER *ciph = NULL;
+    char *passwd = NULL;
+    VALUE cipher, pass, str;
+
+    GetPKeyRSA(self, pkey);
+
+    rb_scan_args(argc, argv, "02", &cipher, &pass);
+
+    if (!NIL_P(cipher)) {
+       ciph = GetCipherPtr(cipher);
+       if (!NIL_P(pass)) {
+           passwd = StringValuePtr(pass);
+       }
+    }
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eRSAError, NULL);
+    }
+    if (RSA_HAS_PRIVATE(pkey->pkey.rsa)) {
+       if (!PEM_write_bio_RSAPrivateKey(out, pkey->pkey.rsa, ciph,
+                                        NULL, 0, ossl_pem_passwd_cb, passwd)) {
+           BIO_free(out);
+           ossl_raise(eRSAError, NULL);
+       }
+    } else {
+       if (!PEM_write_bio_RSA_PUBKEY(out, pkey->pkey.rsa)) {
+           BIO_free(out);
+           ossl_raise(eRSAError, NULL);
+       }
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *   rsa.to_der => DER-format String
+ *
+ * Outputs this keypair in DER encoding.
+ */
+static VALUE
+ossl_rsa_to_der(VALUE self)
+{
+    EVP_PKEY *pkey;
+    int (*i2d_func)_((const RSA*, unsigned char**));
+    unsigned char *p;
+    long len;
+    VALUE str;
+
+    GetPKeyRSA(self, pkey);
+    if(RSA_HAS_PRIVATE(pkey->pkey.rsa))
+       i2d_func = i2d_RSAPrivateKey;
+    else
+       i2d_func = (int (*)(const RSA*, unsigned char**))i2d_RSA_PUBKEY;
+    if((len = i2d_func(pkey->pkey.rsa, NULL)) <= 0)
+       ossl_raise(eRSAError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_func(pkey->pkey.rsa, &p) < 0)
+       ossl_raise(eRSAError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+#define ossl_rsa_buf_size(pkey) (RSA_size((pkey)->pkey.rsa)+16)
+
+/*
+ * call-seq:
+ *   rsa.public_encrypt(string)          => String
+ *   rsa.public_encrypt(string, padding) => String
+ *
+ * Encrypt +string+ with the public key.  +padding+ defaults to PKCS1_PADDING.
+ * The encrypted string output can be decrypted using #private_decrypt.
+ */
+static VALUE
+ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    int buf_len, pad;
+    VALUE str, buffer, padding;
+
+    GetPKeyRSA(self, pkey);
+    rb_scan_args(argc, argv, "11", &buffer, &padding);
+    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
+    StringValue(buffer);
+    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
+                                (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa,
+                                pad);
+    if (buf_len < 0) ossl_raise(eRSAError, NULL);
+    rb_str_set_len(str, buf_len);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *   rsa.public_decrypt(string)          => String
+ *   rsa.public_decrypt(string, padding) => String
+ *
+ * Decrypt +string+, which has been encrypted with the private key, with the
+ * public key.  +padding+ defaults to PKCS1_PADDING.
+ */
+static VALUE
+ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    int buf_len, pad;
+    VALUE str, buffer, padding;
+
+    GetPKeyRSA(self, pkey);
+    rb_scan_args(argc, argv, "11", &buffer, &padding);
+    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
+    StringValue(buffer);
+    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
+                                (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa,
+                                pad);
+    if (buf_len < 0) ossl_raise(eRSAError, NULL);
+    rb_str_set_len(str, buf_len);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *   rsa.private_encrypt(string)          => String
+ *   rsa.private_encrypt(string, padding) => String
+ *
+ * Encrypt +string+ with the private key.  +padding+ defaults to PKCS1_PADDING.
+ * The encrypted string output can be decrypted using #public_decrypt.
+ */
+static VALUE
+ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    int buf_len, pad;
+    VALUE str, buffer, padding;
+
+    GetPKeyRSA(self, pkey);
+    if (!RSA_PRIVATE(self, pkey->pkey.rsa)) {
+       ossl_raise(eRSAError, "private key needed.");
+    }
+    rb_scan_args(argc, argv, "11", &buffer, &padding);
+    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
+    StringValue(buffer);
+    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
+                                 (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa,
+                                 pad);
+    if (buf_len < 0) ossl_raise(eRSAError, NULL);
+    rb_str_set_len(str, buf_len);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *   rsa.private_decrypt(string)          => String
+ *   rsa.private_decrypt(string, padding) => String
+ *
+ * Decrypt +string+, which has been encrypted with the public key, with the
+ * private key.  +padding+ defaults to PKCS1_PADDING.
+ */
+static VALUE
+ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
+{
+    EVP_PKEY *pkey;
+    int buf_len, pad;
+    VALUE str, buffer, padding;
+
+    GetPKeyRSA(self, pkey);
+    if (!RSA_PRIVATE(self, pkey->pkey.rsa)) {
+       ossl_raise(eRSAError, "private key needed.");
+    }
+    rb_scan_args(argc, argv, "11", &buffer, &padding);
+    pad = (argc == 1) ? RSA_PKCS1_PADDING : NUM2INT(padding);
+    StringValue(buffer);
+    str = rb_str_new(0, ossl_rsa_buf_size(pkey));
+    buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
+                                 (unsigned char *)RSTRING_PTR(str), pkey->pkey.rsa,
+                                 pad);
+    if (buf_len < 0) ossl_raise(eRSAError, NULL);
+    rb_str_set_len(str, buf_len);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *   rsa.params => hash
+ *
+ * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
+ *
+ * Stores all parameters of key to the hash.  The hash has keys 'n', 'e', 'd',
+ * 'p', 'q', 'dmp1', 'dmq1', 'iqmp'.
+ *
+ * Don't use :-)) (It's up to you)
+ */
+static VALUE
+ossl_rsa_get_params(VALUE self)
+{
+    EVP_PKEY *pkey;
+    VALUE hash;
+
+    GetPKeyRSA(self, pkey);
+
+    hash = rb_hash_new();
+
+    rb_hash_aset(hash, rb_str_new2("n"), ossl_bn_new(pkey->pkey.rsa->n));
+    rb_hash_aset(hash, rb_str_new2("e"), ossl_bn_new(pkey->pkey.rsa->e));
+    rb_hash_aset(hash, rb_str_new2("d"), ossl_bn_new(pkey->pkey.rsa->d));
+    rb_hash_aset(hash, rb_str_new2("p"), ossl_bn_new(pkey->pkey.rsa->p));
+    rb_hash_aset(hash, rb_str_new2("q"), ossl_bn_new(pkey->pkey.rsa->q));
+    rb_hash_aset(hash, rb_str_new2("dmp1"), ossl_bn_new(pkey->pkey.rsa->dmp1));
+    rb_hash_aset(hash, rb_str_new2("dmq1"), ossl_bn_new(pkey->pkey.rsa->dmq1));
+    rb_hash_aset(hash, rb_str_new2("iqmp"), ossl_bn_new(pkey->pkey.rsa->iqmp));
+
+    return hash;
+}
+
+/*
+ * call-seq:
+ *   rsa.to_text => String
+ *
+ * THIS METHOD IS INSECURE, PRIVATE INFORMATION CAN LEAK OUT!!!
+ *
+ * Dumps all parameters of a keypair to a String
+ *
+ * Don't use :-)) (It's up to you)
+ */
+static VALUE
+ossl_rsa_to_text(VALUE self)
+{
+    EVP_PKEY *pkey;
+    BIO *out;
+    VALUE str;
+
+    GetPKeyRSA(self, pkey);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eRSAError, NULL);
+    }
+    if (!RSA_print(out, pkey->pkey.rsa, 0)) { /* offset = 0 */
+       BIO_free(out);
+       ossl_raise(eRSAError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    rsa.public_key -> RSA
+ *
+ * Makes new RSA instance containing the public key from the private key.
+ */
+static VALUE
+ossl_rsa_to_public_key(VALUE self)
+{
+    EVP_PKEY *pkey;
+    RSA *rsa;
+    VALUE obj;
+
+    GetPKeyRSA(self, pkey);
+    /* err check performed by rsa_instance */
+    rsa = RSAPublicKey_dup(pkey->pkey.rsa);
+    obj = rsa_instance(CLASS_OF(self), rsa);
+    if (obj == Qfalse) {
+       RSA_free(rsa);
+       ossl_raise(eRSAError, NULL);
+    }
+    return obj;
+}
+
+/*
+ * TODO: Test me
+
+static VALUE
+ossl_rsa_blinding_on(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyRSA(self, pkey);
+
+    if (RSA_blinding_on(pkey->pkey.rsa, ossl_bn_ctx) != 1) {
+       ossl_raise(eRSAError, NULL);
+    }
+    return self;
+}
+
+static VALUE
+ossl_rsa_blinding_off(VALUE self)
+{
+    EVP_PKEY *pkey;
+
+    GetPKeyRSA(self, pkey);
+    RSA_blinding_off(pkey->pkey.rsa);
+
+    return self;
+}
+ */
+
+OSSL_PKEY_BN(rsa, n)
+OSSL_PKEY_BN(rsa, e)
+OSSL_PKEY_BN(rsa, d)
+OSSL_PKEY_BN(rsa, p)
+OSSL_PKEY_BN(rsa, q)
+OSSL_PKEY_BN(rsa, dmp1)
+OSSL_PKEY_BN(rsa, dmq1)
+OSSL_PKEY_BN(rsa, iqmp)
+
+/*
+ * INIT
+ */
+#define DefRSAConst(x) rb_define_const(cRSA, #x,INT2FIX(RSA_##x))
+
+void
+Init_ossl_rsa()
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL and mPKey */
+    mPKey = rb_define_module_under(mOSSL, "PKey");
+#endif
+
+    /* Document-class: OpenSSL::PKey::RSAError
+     *
+     * Generic exception that is raised if an operation on an RSA PKey
+     * fails unexpectedly or in case an instantiation of an instance of RSA
+     * fails due to non-conformant input data.
+     */
+    eRSAError = rb_define_class_under(mPKey, "RSAError", ePKeyError);
+
+    /* Document-class: OpenSSL::PKey::RSA
+     *
+     * RSA is an asymmetric public key algorithm that has been formalized in
+     * RFC 3447. It is in widespread use in public key infrastuctures (PKI)
+     * where certificates (cf. OpenSSL::X509::Certificate) often are issued
+     * on the basis of a public/private RSA key pair. RSA is used in a wide
+     * field of applications such as secure (symmetric) key exchange, e.g.
+     * when establishing a secure TLS/SSL connection. It is also used in
+     * various digital signature schemes.
+     */
+    cRSA = rb_define_class_under(mPKey, "RSA", cPKey);
+
+    rb_define_singleton_method(cRSA, "generate", ossl_rsa_s_generate, -1);
+    rb_define_method(cRSA, "initialize", ossl_rsa_initialize, -1);
+
+    rb_define_method(cRSA, "public?", ossl_rsa_is_public, 0);
+    rb_define_method(cRSA, "private?", ossl_rsa_is_private, 0);
+    rb_define_method(cRSA, "to_text", ossl_rsa_to_text, 0);
+    rb_define_method(cRSA, "export", ossl_rsa_export, -1);
+    rb_define_alias(cRSA, "to_pem", "export");
+    rb_define_alias(cRSA, "to_s", "export");
+    rb_define_method(cRSA, "to_der", ossl_rsa_to_der, 0);
+    rb_define_method(cRSA, "public_key", ossl_rsa_to_public_key, 0);
+    rb_define_method(cRSA, "public_encrypt", ossl_rsa_public_encrypt, -1);
+    rb_define_method(cRSA, "public_decrypt", ossl_rsa_public_decrypt, -1);
+    rb_define_method(cRSA, "private_encrypt", ossl_rsa_private_encrypt, -1);
+    rb_define_method(cRSA, "private_decrypt", ossl_rsa_private_decrypt, -1);
+
+    DEF_OSSL_PKEY_BN(cRSA, rsa, n);
+    DEF_OSSL_PKEY_BN(cRSA, rsa, e);
+    DEF_OSSL_PKEY_BN(cRSA, rsa, d);
+    DEF_OSSL_PKEY_BN(cRSA, rsa, p);
+    DEF_OSSL_PKEY_BN(cRSA, rsa, q);
+    DEF_OSSL_PKEY_BN(cRSA, rsa, dmp1);
+    DEF_OSSL_PKEY_BN(cRSA, rsa, dmq1);
+    DEF_OSSL_PKEY_BN(cRSA, rsa, iqmp);
+
+    rb_define_method(cRSA, "params", ossl_rsa_get_params, 0);
+
+    DefRSAConst(PKCS1_PADDING);
+    DefRSAConst(SSLV23_PADDING);
+    DefRSAConst(NO_PADDING);
+    DefRSAConst(PKCS1_OAEP_PADDING);
+
+/*
+ * TODO: Test it
+    rb_define_method(cRSA, "blinding_on!", ossl_rsa_blinding_on, 0);
+    rb_define_method(cRSA, "blinding_off!", ossl_rsa_blinding_off, 0);
+ */
+}
+
+#else /* defined NO_RSA */
+void
+Init_ossl_rsa()
+{
+}
+#endif /* NO_RSA */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_rand.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_rand.c
new file mode 100644 (file)
index 0000000..270a4b7
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@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
+ *
+ */
+static VALUE
+ossl_rand_seed(VALUE self, VALUE str)
+{
+    StringValue(str);
+    RAND_seed(RSTRING_PTR(str), RSTRING_LENINT(str));
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     add(str, entropy) -> self
+ *
+ */
+static VALUE
+ossl_rand_add(VALUE self, VALUE str, VALUE entropy)
+{
+    StringValue(str);
+    RAND_add(RSTRING_PTR(str), RSTRING_LENINT(str), NUM2DBL(entropy));
+
+    return self;
+}
+
+/*
+ *  call-seq:
+ *     load_random_file(filename) -> true
+ *
+ */
+static VALUE
+ossl_rand_load_file(VALUE self, VALUE filename)
+{
+    SafeStringValue(filename);
+
+    if(!RAND_load_file(RSTRING_PTR(filename), -1)) {
+       ossl_raise(eRandomError, NULL);
+    }
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
+ *     write_random_file(filename) -> true
+ *
+ */
+static VALUE
+ossl_rand_write_file(VALUE self, VALUE filename)
+{
+    SafeStringValue(filename);
+    if (RAND_write_file(RSTRING_PTR(filename)) == -1) {
+       ossl_raise(eRandomError, NULL);
+    }
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
+ *     random_bytes(length) -> aString
+ *
+ */
+static VALUE
+ossl_rand_bytes(VALUE self, VALUE len)
+{
+    VALUE str;
+    int n = NUM2INT(len);
+
+    str = rb_str_new(0, n);
+    if (!RAND_bytes((unsigned char *)RSTRING_PTR(str), n)) {
+       ossl_raise(eRandomError, NULL);
+    }
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     pseudo_bytes(length) -> aString
+ *
+ */
+static VALUE
+ossl_rand_pseudo_bytes(VALUE self, VALUE len)
+{
+    VALUE str;
+    int n = NUM2INT(len);
+
+    str = rb_str_new(0, n);
+    if (!RAND_pseudo_bytes((unsigned char *)RSTRING_PTR(str), n)) {
+       ossl_raise(eRandomError, NULL);
+    }
+
+    return str;
+}
+
+/*
+ *  call-seq:
+ *     egd(filename) -> true
+ *
+ */
+static VALUE
+ossl_rand_egd(VALUE self, VALUE filename)
+{
+    SafeStringValue(filename);
+
+    if(!RAND_egd(RSTRING_PTR(filename))) {
+       ossl_raise(eRandomError, NULL);
+    }
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
+ *     egd_bytes(filename, length) -> true
+ *
+ */
+static VALUE
+ossl_rand_egd_bytes(VALUE self, VALUE filename, VALUE len)
+{
+    int n = NUM2INT(len);
+
+    SafeStringValue(filename);
+
+    if (!RAND_egd_bytes(RSTRING_PTR(filename), n)) {
+       ossl_raise(eRandomError, NULL);
+    }
+    return Qtrue;
+}
+
+/*
+ *  call-seq:
+ *     status? => true | false
+ *
+ * Return true if the PRNG has been seeded with enough data, false otherwise.
+ */
+static VALUE
+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()
+{
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    mRandom = rb_define_module_under(mOSSL, "Random");
+
+    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)
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_rand.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_rand.h
new file mode 100644 (file)
index 0000000..ce2ae0d
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_RAND_H_)
+#define _OSSL_RAND_H_
+
+extern VALUE mRandom;
+extern VALUE eRandomError;
+
+void Init_ossl_rand(void);
+
+#endif /* _OSSL_RAND_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl.c
new file mode 100644 (file)
index 0000000..01e8c06
--- /dev/null
@@ -0,0 +1,2021 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2000-2002  GOTOU Yuuzou <gotoyuzo@notwork.org>
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * Copyright (C) 2001-2007  Technorama Ltd. <oss-ruby@technorama.net>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#if defined(HAVE_UNISTD_H)
+#  include <unistd.h> /* for read(), and write() */
+#endif
+
+#define numberof(ary) (int)(sizeof(ary)/sizeof((ary)[0]))
+
+#ifdef _WIN32
+#  define TO_SOCKET(s) _get_osfhandle(s)
+#else
+#  define TO_SOCKET(s) (s)
+#endif
+
+VALUE mSSL;
+VALUE eSSLError;
+VALUE cSSLContext;
+VALUE cSSLSocket;
+
+#define ossl_sslctx_set_cert(o,v)        rb_iv_set((o),"@cert",(v))
+#define ossl_sslctx_set_key(o,v)         rb_iv_set((o),"@key",(v))
+#define ossl_sslctx_set_client_ca(o,v)   rb_iv_set((o),"@client_ca",(v))
+#define ossl_sslctx_set_ca_file(o,v)     rb_iv_set((o),"@ca_file",(v))
+#define ossl_sslctx_set_ca_path(o,v)     rb_iv_set((o),"@ca_path",(v))
+#define ossl_sslctx_set_timeout(o,v)     rb_iv_set((o),"@timeout",(v))
+#define ossl_sslctx_set_verify_mode(o,v) rb_iv_set((o),"@verify_mode",(v))
+#define ossl_sslctx_set_verify_dep(o,v)  rb_iv_set((o),"@verify_depth",(v))
+#define ossl_sslctx_set_verify_cb(o,v)   rb_iv_set((o),"@verify_callback",(v))
+#define ossl_sslctx_set_options(o,v)     rb_iv_set((o),"@options",(v))
+#define ossl_sslctx_set_cert_store(o,v)  rb_iv_set((o),"@cert_store",(v))
+#define ossl_sslctx_set_extra_cert(o,v)  rb_iv_set((o),"@extra_chain_cert",(v))
+#define ossl_sslctx_set_client_cert_cb(o,v) rb_iv_set((o),"@client_cert_cb",(v))
+#define ossl_sslctx_set_tmp_dh_cb(o,v)   rb_iv_set((o),"@tmp_dh_callback",(v))
+#define ossl_sslctx_set_sess_id_ctx(o, v) rb_iv_get((o),"@session_id_context"(v))
+
+#define ossl_sslctx_get_cert(o)          rb_iv_get((o),"@cert")
+#define ossl_sslctx_get_key(o)           rb_iv_get((o),"@key")
+#define ossl_sslctx_get_client_ca(o)     rb_iv_get((o),"@client_ca")
+#define ossl_sslctx_get_ca_file(o)       rb_iv_get((o),"@ca_file")
+#define ossl_sslctx_get_ca_path(o)       rb_iv_get((o),"@ca_path")
+#define ossl_sslctx_get_timeout(o)       rb_iv_get((o),"@timeout")
+#define ossl_sslctx_get_verify_mode(o)   rb_iv_get((o),"@verify_mode")
+#define ossl_sslctx_get_verify_dep(o)    rb_iv_get((o),"@verify_depth")
+#define ossl_sslctx_get_verify_cb(o)     rb_iv_get((o),"@verify_callback")
+#define ossl_sslctx_get_options(o)       rb_iv_get((o),"@options")
+#define ossl_sslctx_get_cert_store(o)    rb_iv_get((o),"@cert_store")
+#define ossl_sslctx_get_extra_cert(o)    rb_iv_get((o),"@extra_chain_cert")
+#define ossl_sslctx_get_client_cert_cb(o) rb_iv_get((o),"@client_cert_cb")
+#define ossl_sslctx_get_tmp_dh_cb(o)     rb_iv_get((o),"@tmp_dh_callback")
+#define ossl_sslctx_get_sess_id_ctx(o)   rb_iv_get((o),"@session_id_context")
+
+static const char *ossl_sslctx_attrs[] = {
+    "cert", "key", "client_ca", "ca_file", "ca_path",
+    "timeout", "verify_mode", "verify_depth",
+    "verify_callback", "options", "cert_store", "extra_chain_cert",
+    "client_cert_cb", "tmp_dh_callback", "session_id_context",
+    "session_get_cb", "session_new_cb", "session_remove_cb",
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+    "servername_cb",
+#endif
+};
+
+#define ossl_ssl_get_io(o)           rb_iv_get((o),"@io")
+#define ossl_ssl_get_ctx(o)          rb_iv_get((o),"@context")
+#define ossl_ssl_get_sync_close(o)   rb_iv_get((o),"@sync_close")
+#define ossl_ssl_get_x509(o)         rb_iv_get((o),"@x509")
+#define ossl_ssl_get_key(o)          rb_iv_get((o),"@key")
+#define ossl_ssl_get_tmp_dh(o)       rb_iv_get((o),"@tmp_dh")
+
+#define ossl_ssl_set_io(o,v)         rb_iv_set((o),"@io",(v))
+#define ossl_ssl_set_ctx(o,v)        rb_iv_set((o),"@context",(v))
+#define ossl_ssl_set_sync_close(o,v) rb_iv_set((o),"@sync_close",(v))
+#define ossl_ssl_set_x509(o,v)       rb_iv_set((o),"@x509",(v))
+#define ossl_ssl_set_key(o,v)        rb_iv_set((o),"@key",(v))
+#define ossl_ssl_set_tmp_dh(o,v)     rb_iv_set((o),"@tmp_dh",(v))
+
+static const char *ossl_ssl_attr_readers[] = { "io", "context", };
+static const char *ossl_ssl_attrs[] = {
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+    "hostname",
+#endif
+    "sync_close",
+};
+
+ID ID_callback_state;
+
+/*
+ * SSLContext class
+ */
+struct {
+    const char *name;
+    SSL_METHOD *(*func)(void);
+} ossl_ssl_method_tab[] = {
+#define OSSL_SSL_METHOD_ENTRY(name) { #name, (SSL_METHOD *(*)(void))name##_method }
+    OSSL_SSL_METHOD_ENTRY(TLSv1),
+    OSSL_SSL_METHOD_ENTRY(TLSv1_server),
+    OSSL_SSL_METHOD_ENTRY(TLSv1_client),
+#if defined(HAVE_SSLV2_METHOD) && defined(HAVE_SSLV2_SERVER_METHOD) && \
+        defined(HAVE_SSLV2_CLIENT_METHOD)
+    OSSL_SSL_METHOD_ENTRY(SSLv2),
+    OSSL_SSL_METHOD_ENTRY(SSLv2_server),
+    OSSL_SSL_METHOD_ENTRY(SSLv2_client),
+#endif
+    OSSL_SSL_METHOD_ENTRY(SSLv3),
+    OSSL_SSL_METHOD_ENTRY(SSLv3_server),
+    OSSL_SSL_METHOD_ENTRY(SSLv3_client),
+    OSSL_SSL_METHOD_ENTRY(SSLv23),
+    OSSL_SSL_METHOD_ENTRY(SSLv23_server),
+    OSSL_SSL_METHOD_ENTRY(SSLv23_client),
+#undef OSSL_SSL_METHOD_ENTRY
+};
+
+int ossl_ssl_ex_vcb_idx;
+int ossl_ssl_ex_store_p;
+int ossl_ssl_ex_ptr_idx;
+int ossl_ssl_ex_client_cert_cb_idx;
+int ossl_ssl_ex_tmp_dh_callback_idx;
+
+static void
+ossl_sslctx_free(SSL_CTX *ctx)
+{
+    if(ctx && SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_store_p)== (void*)1)
+       ctx->cert_store = NULL;
+    SSL_CTX_free(ctx);
+}
+
+static VALUE
+ossl_sslctx_s_alloc(VALUE klass)
+{
+    SSL_CTX *ctx;
+    long mode = SSL_MODE_ENABLE_PARTIAL_WRITE;
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+    mode |= SSL_MODE_RELEASE_BUFFERS;
+#endif
+
+    ctx = SSL_CTX_new(SSLv23_method());
+    if (!ctx) {
+        ossl_raise(eSSLError, "SSL_CTX_new:");
+    }
+    SSL_CTX_set_mode(ctx, mode);
+    return Data_Wrap_Struct(klass, 0, ossl_sslctx_free, ctx);
+}
+
+/*
+ * call-seq:
+ *    ctx.ssl_version = :TLSv1
+ *    ctx.ssl_version = "SSLv23_client"
+ *
+ * You can get a list of valid versions with OpenSSL::SSL::SSLContext::METHODS
+ */
+static VALUE
+ossl_sslctx_set_ssl_version(VALUE self, VALUE ssl_method)
+{
+    SSL_METHOD *method = NULL;
+    const char *s;
+    int i;
+
+    SSL_CTX *ctx;
+    if(TYPE(ssl_method) == T_SYMBOL)
+       s = rb_id2name(SYM2ID(ssl_method));
+    else
+       s =  StringValuePtr(ssl_method);
+    for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
+        if (strcmp(ossl_ssl_method_tab[i].name, s) == 0) {
+            method = ossl_ssl_method_tab[i].func();
+            break;
+        }
+    }
+    if (!method) {
+        ossl_raise(rb_eArgError, "unknown SSL method `%s'.", s);
+    }
+    Data_Get_Struct(self, SSL_CTX, ctx);
+    if (SSL_CTX_set_ssl_version(ctx, method) != 1) {
+        ossl_raise(eSSLError, "SSL_CTX_set_ssl_version:");
+    }
+
+    return ssl_method;
+}
+
+/*
+ * call-seq:
+ *    SSLContext.new => ctx
+ *    SSLContext.new(:TLSv1) => ctx
+ *    SSLContext.new("SSLv23_client") => ctx
+ *
+ * You can get a list of valid methods with OpenSSL::SSL::SSLContext::METHODS
+ */
+static VALUE
+ossl_sslctx_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE ssl_method;
+    int i;
+
+    for(i = 0; i < numberof(ossl_sslctx_attrs); i++){
+       char buf[32];
+       snprintf(buf, sizeof(buf), "@%s", ossl_sslctx_attrs[i]);
+       rb_iv_set(self, buf, Qnil);
+    }
+    if (rb_scan_args(argc, argv, "01", &ssl_method) == 0){
+        return self;
+    }
+    ossl_sslctx_set_ssl_version(self, ssl_method);
+
+    return self;
+}
+
+static VALUE
+ossl_call_client_cert_cb(VALUE obj)
+{
+    VALUE cb, ary, cert, key;
+    SSL *ssl;
+
+    Data_Get_Struct(obj, SSL, 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);
+    Check_Type(ary, T_ARRAY);
+    GetX509CertPtr(cert = rb_ary_entry(ary, 0));
+    GetPKeyPtr(key = rb_ary_entry(ary, 1));
+    ossl_ssl_set_x509(obj, cert);
+    ossl_ssl_set_key(obj, key);
+
+    return Qtrue;
+}
+
+static int
+ossl_client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
+{
+    VALUE obj, success;
+
+    obj = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+    success = rb_protect((VALUE(*)_((VALUE)))ossl_call_client_cert_cb,
+                         obj, NULL);
+    if (!RTEST(success)) return 0;
+    *x509 = DupX509CertPtr(ossl_ssl_get_x509(obj));
+    *pkey = DupPKeyPtr(ossl_ssl_get_key(obj));
+
+    return 1;
+}
+
+#if !defined(OPENSSL_NO_DH)
+static VALUE
+ossl_call_tmp_dh_callback(VALUE *args)
+{
+    SSL *ssl;
+    VALUE cb, dh;
+    EVP_PKEY *pkey;
+
+    Data_Get_Struct(args[0], SSL, 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]);
+    pkey = GetPKeyPtr(dh);
+    if (EVP_PKEY_type(pkey->type) != EVP_PKEY_DH) return Qfalse;
+    ossl_ssl_set_tmp_dh(args[0], dh);
+
+    return Qtrue;
+}
+
+static DH*
+ossl_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
+{
+    VALUE args[3], success;
+
+    args[0] = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx);
+    args[1] = INT2FIX(is_export);
+    args[2] = INT2FIX(keylength);
+    success = rb_protect((VALUE(*)_((VALUE)))ossl_call_tmp_dh_callback,
+                         (VALUE)args, NULL);
+    if (!RTEST(success)) return NULL;
+
+    return GetPKeyPtr(ossl_ssl_get_tmp_dh(args[0]))->pkey.dh;
+}
+
+static DH*
+ossl_default_tmp_dh_callback(SSL *ssl, int is_export, int keylength)
+{
+    rb_warning("using default DH parameters.");
+
+    switch(keylength){
+    case 512:
+       return OSSL_DEFAULT_DH_512;
+    case 1024:
+       return OSSL_DEFAULT_DH_1024;
+    }
+    return NULL;
+}
+#endif /* OPENSSL_NO_DH */
+
+static int
+ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
+{
+    VALUE cb;
+    SSL *ssl;
+
+    ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+    cb = (VALUE)SSL_get_ex_data(ssl, ossl_ssl_ex_vcb_idx);
+    X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx, (void*)cb);
+    return ossl_verify_cb(preverify_ok, ctx);
+}
+
+static VALUE
+ossl_call_session_get_cb(VALUE ary)
+{
+    VALUE ssl_obj, sslctx_obj, cb;
+
+    Check_Type(ary, T_ARRAY);
+    ssl_obj = rb_ary_entry(ary, 0);
+
+    sslctx_obj = rb_iv_get(ssl_obj, "@context");
+    if (NIL_P(sslctx_obj)) return Qnil;
+    cb = rb_iv_get(sslctx_obj, "@session_get_cb");
+    if (NIL_P(cb)) return Qnil;
+
+    return rb_funcall(cb, rb_intern("call"), 1, ary);
+}
+
+/* this method is currently only called for servers (in OpenSSL <= 0.9.8e) */
+static SSL_SESSION *
+ossl_sslctx_session_get_cb(SSL *ssl, unsigned char *buf, int len, int *copy)
+{
+    VALUE ary, ssl_obj, ret_obj;
+    SSL_SESSION *sess;
+    void *ptr;
+    int state = 0;
+
+    OSSL_Debug("SSL SESSION get callback entered");
+    if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
+       return NULL;
+    ssl_obj = (VALUE)ptr;
+    ary = rb_ary_new2(2);
+    rb_ary_push(ary, ssl_obj);
+    rb_ary_push(ary, rb_str_new((const char *)buf, len));
+
+    ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_get_cb, ary, &state);
+    if (state) {
+        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
+        return NULL;
+    }
+    if (!rb_obj_is_instance_of(ret_obj, cSSLSession))
+        return NULL;
+
+    SafeGetSSLSession(ret_obj, sess);
+    *copy = 1;
+
+    return sess;
+}
+
+static VALUE
+ossl_call_session_new_cb(VALUE ary)
+{
+    VALUE ssl_obj, sslctx_obj, cb;
+
+    Check_Type(ary, T_ARRAY);
+    ssl_obj = rb_ary_entry(ary, 0);
+
+    sslctx_obj = rb_iv_get(ssl_obj, "@context");
+    if (NIL_P(sslctx_obj)) return Qnil;
+    cb = rb_iv_get(sslctx_obj, "@session_new_cb");
+    if (NIL_P(cb)) return Qnil;
+
+    return rb_funcall(cb, rb_intern("call"), 1, ary);
+}
+
+/* return 1 normal.  return 0 removes the session */
+static int
+ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess)
+{
+    VALUE ary, ssl_obj, sess_obj, ret_obj;
+    void *ptr;
+    int state = 0;
+
+    OSSL_Debug("SSL SESSION new callback entered");
+
+    if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
+       return 1;
+    ssl_obj = (VALUE)ptr;
+    sess_obj = rb_obj_alloc(cSSLSession);
+    CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION);
+    DATA_PTR(sess_obj) = sess;
+
+    ary = rb_ary_new2(2);
+    rb_ary_push(ary, ssl_obj);
+    rb_ary_push(ary, sess_obj);
+
+    ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_new_cb, ary, &state);
+    if (state) {
+        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
+    }
+
+    /*
+     * return 0 which means to OpenSSL that the the session is still
+     * valid (since we created Ruby Session object) and was not freed by us
+     * with SSL_SESSION_free(). Call SSLContext#remove_session(sess) in
+     * session_get_cb block if you don't want OpenSSL to cache the session
+     * internally.
+     */
+    return 0;
+}
+
+static VALUE
+ossl_call_session_remove_cb(VALUE ary)
+{
+    VALUE sslctx_obj, cb;
+
+    Check_Type(ary, T_ARRAY);
+    sslctx_obj = rb_ary_entry(ary, 0);
+
+    cb = rb_iv_get(sslctx_obj, "@session_remove_cb");
+    if (NIL_P(cb)) return Qnil;
+
+    return rb_funcall(cb, rb_intern("call"), 1, ary);
+}
+
+static void
+ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
+{
+    VALUE ary, sslctx_obj, sess_obj, ret_obj;
+    void *ptr;
+    int state = 0;
+
+    OSSL_Debug("SSL SESSION remove callback entered");
+
+    if ((ptr = SSL_CTX_get_ex_data(ctx, ossl_ssl_ex_ptr_idx)) == NULL)
+       return;
+    sslctx_obj = (VALUE)ptr;
+    sess_obj = rb_obj_alloc(cSSLSession);
+    CRYPTO_add(&sess->references, 1, CRYPTO_LOCK_SSL_SESSION);
+    DATA_PTR(sess_obj) = sess;
+
+    ary = rb_ary_new2(2);
+    rb_ary_push(ary, sslctx_obj);
+    rb_ary_push(ary, sess_obj);
+
+    ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_session_remove_cb, ary, &state);
+    if (state) {
+/*
+  the SSL_CTX is frozen, nowhere to save state.
+  there is no common accessor method to check it either.
+        rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state));
+*/
+    }
+}
+
+static VALUE
+ossl_sslctx_add_extra_chain_cert_i(VALUE i, VALUE arg)
+{
+    X509 *x509;
+    SSL_CTX *ctx;
+
+    Data_Get_Struct(arg, SSL_CTX, ctx);
+    x509 = DupX509CertPtr(i);
+    if(!SSL_CTX_add_extra_chain_cert(ctx, x509)){
+       ossl_raise(eSSLError, NULL);
+    }
+
+    return i;
+}
+
+static VALUE ossl_sslctx_setup(VALUE self);
+
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+static VALUE
+ossl_call_servername_cb(VALUE ary)
+{
+    VALUE ssl_obj, sslctx_obj, cb, ret_obj;
+
+    Check_Type(ary, T_ARRAY);
+    ssl_obj = rb_ary_entry(ary, 0);
+
+    sslctx_obj = rb_iv_get(ssl_obj, "@context");
+    if (NIL_P(sslctx_obj)) return Qnil;
+    cb = rb_iv_get(sslctx_obj, "@servername_cb");
+    if (NIL_P(cb)) return Qnil;
+
+    ret_obj = rb_funcall(cb, rb_intern("call"), 1, ary);
+    if (rb_obj_is_kind_of(ret_obj, cSSLContext)) {
+        SSL *ssl;
+        SSL_CTX *ctx2;
+
+        ossl_sslctx_setup(ret_obj);
+        Data_Get_Struct(ssl_obj, SSL, ssl);
+        Data_Get_Struct(ret_obj, SSL_CTX, 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");
+    }
+
+    return ret_obj;
+}
+
+static int
+ssl_servername_cb(SSL *ssl, int *ad, void *arg)
+{
+    VALUE ary, ssl_obj, ret_obj;
+    void *ptr;
+    int state = 0;
+    const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+
+    if (!servername)
+        return SSL_TLSEXT_ERR_OK;
+
+    if ((ptr = SSL_get_ex_data(ssl, ossl_ssl_ex_ptr_idx)) == NULL)
+       return SSL_TLSEXT_ERR_ALERT_FATAL;
+    ssl_obj = (VALUE)ptr;
+    ary = rb_ary_new2(2);
+    rb_ary_push(ary, ssl_obj);
+    rb_ary_push(ary, rb_str_new2(servername));
+
+    ret_obj = rb_protect((VALUE(*)_((VALUE)))ossl_call_servername_cb, ary, &state);
+    if (state) {
+        rb_ivar_set(ssl_obj, ID_callback_state, INT2NUM(state));
+        return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
+
+    return SSL_TLSEXT_ERR_OK;
+}
+#endif
+
+/*
+ * call-seq:
+ *    ctx.setup => Qtrue # first time
+ *    ctx.setup => nil # thereafter
+ *
+ * This method is called automatically when a new SSLSocket is created.
+ * Normally you do not need to call this method (unless you are writing an
+ * extension in C).
+ */
+static VALUE
+ossl_sslctx_setup(VALUE self)
+{
+    SSL_CTX *ctx;
+    X509 *cert = NULL, *client_ca = NULL;
+    X509_STORE *store;
+    EVP_PKEY *key = NULL;
+    char *ca_path = NULL, *ca_file = NULL;
+    int i, verify_mode;
+    VALUE val;
+
+    if(OBJ_FROZEN(self)) return Qnil;
+    Data_Get_Struct(self, SSL_CTX, ctx);
+
+#if !defined(OPENSSL_NO_DH)
+    if (RTEST(ossl_sslctx_get_tmp_dh_cb(self))){
+       SSL_CTX_set_tmp_dh_callback(ctx, ossl_tmp_dh_callback);
+    }
+    else{
+       SSL_CTX_set_tmp_dh_callback(ctx, ossl_default_tmp_dh_callback);
+    }
+#endif
+    SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_ptr_idx, (void*)self);
+
+    val = ossl_sslctx_get_cert_store(self);
+    if(!NIL_P(val)){
+       /*
+         * WORKAROUND:
+        *   X509_STORE can count references, but
+        *   X509_STORE_free() doesn't care it.
+        *   So we won't increment it but mark it by ex_data.
+        */
+        store = GetX509StorePtr(val); /* NO NEED TO DUP */
+        SSL_CTX_set_cert_store(ctx, store);
+        SSL_CTX_set_ex_data(ctx, ossl_ssl_ex_store_p, (void*)1);
+    }
+
+    val = ossl_sslctx_get_extra_cert(self);
+    if(!NIL_P(val)){
+       rb_block_call(val, rb_intern("each"), 0, 0, ossl_sslctx_add_extra_chain_cert_i, self);
+    }
+
+    /* private key may be bundled in certificate file. */
+    val = ossl_sslctx_get_cert(self);
+    cert = NIL_P(val) ? NULL : GetX509CertPtr(val); /* NO DUP NEEDED */
+    val = ossl_sslctx_get_key(self);
+    key = NIL_P(val) ? NULL : GetPKeyPtr(val); /* NO DUP NEEDED */
+    if (cert && key) {
+        if (!SSL_CTX_use_certificate(ctx, cert)) {
+            /* Adds a ref => Safe to FREE */
+            ossl_raise(eSSLError, "SSL_CTX_use_certificate:");
+        }
+        if (!SSL_CTX_use_PrivateKey(ctx, key)) {
+            /* Adds a ref => Safe to FREE */
+            ossl_raise(eSSLError, "SSL_CTX_use_PrivateKey:");
+        }
+        if (!SSL_CTX_check_private_key(ctx)) {
+            ossl_raise(eSSLError, "SSL_CTX_check_private_key:");
+        }
+    }
+
+    val = ossl_sslctx_get_client_ca(self);
+    if(!NIL_P(val)){
+       if(TYPE(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)){
+                   /* Copies X509_NAME => FREE it. */
+                   ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+               }
+           }
+        }
+       else{
+           client_ca = GetX509CertPtr(val); /* NO DUP NEEDED. */
+            if (!SSL_CTX_add_client_CA(ctx, client_ca)){
+               /* Copies X509_NAME => FREE it. */
+               ossl_raise(eSSLError, "SSL_CTX_add_client_CA");
+            }
+       }
+    }
+
+    val = ossl_sslctx_get_ca_file(self);
+    ca_file = NIL_P(val) ? NULL : StringValuePtr(val);
+    val = ossl_sslctx_get_ca_path(self);
+    ca_path = NIL_P(val) ? NULL : StringValuePtr(val);
+    if(ca_file || ca_path){
+       if (!SSL_CTX_load_verify_locations(ctx, ca_file, ca_path))
+           rb_warning("can't set verify locations");
+    }
+
+    val = ossl_sslctx_get_verify_mode(self);
+    verify_mode = NIL_P(val) ? SSL_VERIFY_NONE : NUM2INT(val);
+    SSL_CTX_set_verify(ctx, verify_mode, ossl_ssl_verify_callback);
+    if (RTEST(ossl_sslctx_get_client_cert_cb(self)))
+       SSL_CTX_set_client_cert_cb(ctx, ossl_client_cert_cb);
+
+    val = ossl_sslctx_get_timeout(self);
+    if(!NIL_P(val)) SSL_CTX_set_timeout(ctx, NUM2LONG(val));
+
+    val = ossl_sslctx_get_verify_dep(self);
+    if(!NIL_P(val)) SSL_CTX_set_verify_depth(ctx, NUM2INT(val));
+
+    val = ossl_sslctx_get_options(self);
+    if(!NIL_P(val)) {
+       SSL_CTX_set_options(ctx, NUM2LONG(val));
+    }
+    else {
+       SSL_CTX_set_options(ctx, SSL_OP_ALL);
+    }
+    rb_obj_freeze(self);
+
+    val = ossl_sslctx_get_sess_id_ctx(self);
+    if (!NIL_P(val)){
+       StringValue(val);
+       if (!SSL_CTX_set_session_id_context(ctx, (unsigned char *)RSTRING_PTR(val),
+                                           RSTRING_LENINT(val))){
+           ossl_raise(eSSLError, "SSL_CTX_set_session_id_context:");
+       }
+    }
+
+    if (RTEST(rb_iv_get(self, "@session_get_cb"))) {
+       SSL_CTX_sess_set_get_cb(ctx, ossl_sslctx_session_get_cb);
+       OSSL_Debug("SSL SESSION get callback added");
+    }
+    if (RTEST(rb_iv_get(self, "@session_new_cb"))) {
+       SSL_CTX_sess_set_new_cb(ctx, ossl_sslctx_session_new_cb);
+       OSSL_Debug("SSL SESSION new callback added");
+    }
+    if (RTEST(rb_iv_get(self, "@session_remove_cb"))) {
+       SSL_CTX_sess_set_remove_cb(ctx, ossl_sslctx_session_remove_cb);
+       OSSL_Debug("SSL SESSION remove callback added");
+    }
+
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+    val = rb_iv_get(self, "@servername_cb");
+    if (!NIL_P(val)) {
+        SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb);
+       OSSL_Debug("SSL TLSEXT servername callback added");
+    }
+#endif
+
+    return Qtrue;
+}
+
+static VALUE
+ossl_ssl_cipher_to_ary(SSL_CIPHER *cipher)
+{
+    VALUE ary;
+    int bits, alg_bits;
+
+    ary = rb_ary_new2(4);
+    rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_name(cipher)));
+    rb_ary_push(ary, rb_str_new2(SSL_CIPHER_get_version(cipher)));
+    bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
+    rb_ary_push(ary, INT2FIX(bits));
+    rb_ary_push(ary, INT2FIX(alg_bits));
+
+    return ary;
+}
+
+/*
+ * call-seq:
+ *    ctx.ciphers => [[name, version, bits, alg_bits], ...]
+ *
+ * The list of ciphers configured for this context.
+ */
+static VALUE
+ossl_sslctx_get_ciphers(VALUE self)
+{
+    SSL_CTX *ctx;
+    STACK_OF(SSL_CIPHER) *ciphers;
+    SSL_CIPHER *cipher;
+    VALUE ary;
+    int i, num;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+    if(!ctx){
+        rb_warning("SSL_CTX is not initialized.");
+        return Qnil;
+    }
+    ciphers = ctx->cipher_list;
+
+    if (!ciphers)
+        return rb_ary_new();
+
+    num = sk_SSL_CIPHER_num(ciphers);
+    ary = rb_ary_new2(num);
+    for(i = 0; i < num; i++){
+        cipher = sk_SSL_CIPHER_value(ciphers, i);
+        rb_ary_push(ary, ossl_ssl_cipher_to_ary(cipher));
+    }
+    return ary;
+}
+
+/*
+ * call-seq:
+ *    ctx.ciphers = "cipher1:cipher2:..."
+ *    ctx.ciphers = [name, ...]
+ *    ctx.ciphers = [[name, version, bits, alg_bits], ...]
+ *
+ * Sets the list of available ciphers for this context.  Note in a server
+ * context some ciphers require the appropriate certificates.  For example, an
+ * RSA cipher can only be chosen when an RSA certificate is available.
+ *
+ * See also OpenSSL::Cipher and OpenSSL::Cipher::ciphers
+ */
+static VALUE
+ossl_sslctx_set_ciphers(VALUE self, VALUE v)
+{
+    SSL_CTX *ctx;
+    VALUE str, elem;
+    int i;
+
+    rb_check_frozen(self);
+    if (NIL_P(v))
+       return v;
+    else if (TYPE(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);
+            elem = rb_String(elem);
+            rb_str_append(str, elem);
+            if (i < RARRAY_LEN(v)-1) rb_str_cat2(str, ":");
+        }
+    } else {
+        str = v;
+        StringValue(str);
+    }
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+    if(!ctx){
+        ossl_raise(eSSLError, "SSL_CTX is not initialized.");
+        return Qnil;
+    }
+    if (!SSL_CTX_set_cipher_list(ctx, RSTRING_PTR(str))) {
+        ossl_raise(eSSLError, "SSL_CTX_set_cipher_list:");
+    }
+
+    return v;
+}
+
+
+/*
+ *  call-seq:
+ *     ctx.session_add(session) -> true | false
+ *
+ * Adds +session+ to the session cache
+ */
+static VALUE
+ossl_sslctx_session_add(VALUE self, VALUE arg)
+{
+    SSL_CTX *ctx;
+    SSL_SESSION *sess;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+    SafeGetSSLSession(arg, sess);
+
+    return SSL_CTX_add_session(ctx, sess) == 1 ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *     ctx.session_remove(session) -> true | false
+ *
+ * Removes +session+ from the session cache
+ */
+static VALUE
+ossl_sslctx_session_remove(VALUE self, VALUE arg)
+{
+    SSL_CTX *ctx;
+    SSL_SESSION *sess;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+    SafeGetSSLSession(arg, sess);
+
+    return SSL_CTX_remove_session(ctx, sess) == 1 ? Qtrue : Qfalse;
+}
+
+/*
+ *  call-seq:
+ *     ctx.session_cache_mode -> Integer
+ *
+ * The current session cache mode.
+ */
+static VALUE
+ossl_sslctx_get_session_cache_mode(VALUE self)
+{
+    SSL_CTX *ctx;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+
+    return LONG2NUM(SSL_CTX_get_session_cache_mode(ctx));
+}
+
+/*
+ *  call-seq:
+ *     ctx.session_cache_mode=(integer) -> Integer
+ *
+ * Sets the SSL session cache mode.  Bitwise-or together the desired
+ * SESSION_CACHE_* constants to set.  See SSL_CTX_set_session_cache_mode(3) for
+ * details.
+ */
+static VALUE
+ossl_sslctx_set_session_cache_mode(VALUE self, VALUE arg)
+{
+    SSL_CTX *ctx;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+
+    SSL_CTX_set_session_cache_mode(ctx, NUM2LONG(arg));
+
+    return arg;
+}
+
+/*
+ *  call-seq:
+ *     ctx.session_cache_size -> Integer
+ *
+ * Returns the current session cache size.  Zero is used to represent an
+ * unlimited cache size.
+ */
+static VALUE
+ossl_sslctx_get_session_cache_size(VALUE self)
+{
+    SSL_CTX *ctx;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+
+    return LONG2NUM(SSL_CTX_sess_get_cache_size(ctx));
+}
+
+/*
+ *  call-seq:
+ *     ctx.session_cache_size=(integer) -> Integer
+ *
+ * Sets the session cache size.  Returns the previously valid session cache
+ * size.  Zero is used to represent an unlimited session cache size.
+ */
+static VALUE
+ossl_sslctx_set_session_cache_size(VALUE self, VALUE arg)
+{
+    SSL_CTX *ctx;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+
+    SSL_CTX_sess_set_cache_size(ctx, NUM2LONG(arg));
+
+    return arg;
+}
+
+/*
+ *  call-seq:
+ *     ctx.session_cache_stats -> Hash
+ *
+ * Returns a Hash containing the following keys:
+ *
+ * :accept:: Number of started SSL/TLS handshakes in server mode
+ * :accept_good:: Number of established SSL/TLS sessions in server mode
+ * :accept_renegotiate:: Number of start renegotiations in server mode
+ * :cache_full:: Number of sessions that were removed due to cache overflow
+ * :cache_hits:: Number of successfully reused connections
+ * :cache_misses:: Number of sessions proposed by clients that were not found
+ *                 in the cache
+ * :cache_num:: Number of sessions in the internal session cache
+ * :cb_hits:: Number of sessions retrieved from the external cache in server
+ *            mode
+ * :connect:: Number of started SSL/TLS handshakes in client mode
+ * :connect_good:: Number of established SSL/TLS sessions in client mode
+ * :connect_renegotiate:: Number of start renegotiations in client mode
+ * :timeouts:: Number of sessions proposed by clients that were found in the
+ *             cache but had expired due to timeouts
+ */
+static VALUE
+ossl_sslctx_get_session_cache_stats(VALUE self)
+{
+    SSL_CTX *ctx;
+    VALUE hash;
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+
+    hash = rb_hash_new();
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_num")), LONG2NUM(SSL_CTX_sess_number(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("connect")), LONG2NUM(SSL_CTX_sess_connect(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("connect_good")), LONG2NUM(SSL_CTX_sess_connect_good(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("connect_renegotiate")), LONG2NUM(SSL_CTX_sess_connect_renegotiate(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("accept")), LONG2NUM(SSL_CTX_sess_accept(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("accept_good")), LONG2NUM(SSL_CTX_sess_accept_good(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("accept_renegotiate")), LONG2NUM(SSL_CTX_sess_accept_renegotiate(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_hits")), LONG2NUM(SSL_CTX_sess_hits(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cb_hits")), LONG2NUM(SSL_CTX_sess_cb_hits(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_misses")), LONG2NUM(SSL_CTX_sess_misses(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("cache_full")), LONG2NUM(SSL_CTX_sess_cache_full(ctx)));
+    rb_hash_aset(hash, ID2SYM(rb_intern("timeouts")), LONG2NUM(SSL_CTX_sess_timeouts(ctx)));
+
+    return hash;
+}
+
+
+/*
+ *  call-seq:
+ *     ctx.flush_sessions(time | nil) -> self
+ *
+ * Removes sessions in the internal cache that have expired at +time+.
+ */
+static VALUE
+ossl_sslctx_flush_sessions(int argc, VALUE *argv, VALUE self)
+{
+    VALUE arg1;
+    SSL_CTX *ctx;
+    time_t tm = 0;
+
+    rb_scan_args(argc, argv, "01", &arg1);
+
+    Data_Get_Struct(self, SSL_CTX, ctx);
+
+    if (NIL_P(arg1)) {
+        tm = time(0);
+    } else if (rb_obj_is_instance_of(arg1, rb_cTime)) {
+        tm = NUM2LONG(rb_funcall(arg1, rb_intern("to_i"), 0));
+    } else {
+        ossl_raise(rb_eArgError, "arg must be Time or nil");
+    }
+
+    SSL_CTX_flush_sessions(ctx, (long)tm);
+
+    return self;
+}
+
+/*
+ * SSLSocket class
+ */
+static void
+ossl_ssl_shutdown(SSL *ssl)
+{
+    int i, rc;
+
+    if (ssl) {
+       /* 4 is from SSL_smart_shutdown() of mod_ssl.c (v2.2.19) */
+       /* It says max 2x pending + 2x data = 4 */
+       for (i = 0; i < 4; ++i) {
+           /*
+            * Ignore the case SSL_shutdown returns -1. Empty handshake_func
+            * must not happen.
+            */
+           if (rc = SSL_shutdown(ssl))
+               break;
+       }
+       ERR_clear_error();
+       SSL_clear(ssl);
+    }
+}
+
+static void
+ossl_ssl_free(SSL *ssl)
+{
+    SSL_free(ssl);
+}
+
+static VALUE
+ossl_ssl_s_alloc(VALUE klass)
+{
+    return Data_Wrap_Struct(klass, 0, ossl_ssl_free, NULL);
+}
+
+/*
+ * call-seq:
+ *    SSLSocket.new(io) => aSSLSocket
+ *    SSLSocket.new(io, ctx) => aSSLSocket
+ *
+ * Creates a new SSL socket from +io+ which must be a real ruby object (not an
+ * IO-like object that responds to read/write.
+ *
+ * If +ctx+ is provided the SSL Sockets initial params will be taken from
+ * the context.
+ *
+ * The OpenSSL::Buffering module provides additional IO methods.
+ *
+ * This method will freeze the SSLContext if one is provided;
+ * however, session management is still allowed in the frozen SSLContext.
+ */
+static VALUE
+ossl_ssl_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE io, ctx;
+
+    if (rb_scan_args(argc, argv, "11", &io, &ctx) == 1) {
+        ctx = rb_funcall(cSSLContext, rb_intern("new"), 0);
+    }
+    OSSL_Check_Kind(ctx, cSSLContext);
+    Check_Type(io, T_FILE);
+    ossl_ssl_set_io(self, io);
+    ossl_ssl_set_ctx(self, ctx);
+    ossl_ssl_set_sync_close(self, Qfalse);
+    ossl_sslctx_setup(ctx);
+
+    rb_iv_set(self, "@hostname", Qnil);
+
+    rb_call_super(0, 0);
+
+    return self;
+}
+
+static VALUE
+ossl_ssl_setup(VALUE self)
+{
+    VALUE io, v_ctx, cb;
+    SSL_CTX *ctx;
+    SSL *ssl;
+    rb_io_t *fptr;
+
+    Data_Get_Struct(self, SSL, 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);
+
+        ssl = SSL_new(ctx);
+        if (!ssl) {
+            ossl_raise(eSSLError, "SSL_new:");
+        }
+        DATA_PTR(self) = ssl;
+
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+        if (!NIL_P(hostname)) {
+           if (SSL_set_tlsext_host_name(ssl, StringValuePtr(hostname)) != 1)
+               ossl_raise(eSSLError, "SSL_set_tlsext_host_name:");
+        }
+#endif
+        io = ossl_ssl_get_io(self);
+        GetOpenFile(io, fptr);
+        rb_io_check_readable(fptr);
+        rb_io_check_writable(fptr);
+        SSL_set_fd(ssl, TO_SOCKET(FPTR_TO_FD(fptr)));
+       SSL_set_ex_data(ssl, ossl_ssl_ex_ptr_idx, (void*)self);
+       cb = ossl_sslctx_get_verify_cb(v_ctx);
+       SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void*)cb);
+       cb = ossl_sslctx_get_client_cert_cb(v_ctx);
+       SSL_set_ex_data(ssl, ossl_ssl_ex_client_cert_cb_idx, (void*)cb);
+       cb = ossl_sslctx_get_tmp_dh_cb(v_ctx);
+       SSL_set_ex_data(ssl, ossl_ssl_ex_tmp_dh_callback_idx, (void*)cb);
+    }
+
+    return Qtrue;
+}
+
+#ifdef _WIN32
+#define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error((ssl), (ret)))
+#else
+#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret))
+#endif
+
+static void
+write_would_block(int nonblock)
+{
+    if (nonblock) {
+        VALUE exc = ossl_exc_new(eSSLError, "write would block");
+        rb_extend_object(exc, rb_mWaitWritable);
+        rb_exc_raise(exc);
+    }
+}
+
+static void
+read_would_block(int nonblock)
+{
+    if (nonblock) {
+        VALUE exc = ossl_exc_new(eSSLError, "read would block");
+        rb_extend_object(exc, rb_mWaitReadable);
+        rb_exc_raise(exc);
+    }
+}
+
+static VALUE
+ossl_start_ssl(VALUE self, int (*func)(), const char *funcname, int nonblock)
+{
+    SSL *ssl;
+    rb_io_t *fptr;
+    int ret, ret2;
+    VALUE cb_state;
+
+    rb_ivar_set(self, ID_callback_state, Qnil);
+
+    Data_Get_Struct(self, SSL, ssl);
+    GetOpenFile(ossl_ssl_get_io(self), fptr);
+    for(;;){
+       ret = func(ssl);
+
+        cb_state = rb_ivar_get(self, ID_callback_state);
+        if (!NIL_P(cb_state))
+            rb_jump_tag(NUM2INT(cb_state));
+
+       if (ret > 0)
+           break;
+
+       switch((ret2 = ssl_get_error(ssl, ret))){
+       case SSL_ERROR_WANT_WRITE:
+            write_would_block(nonblock);
+            rb_io_wait_writable(FPTR_TO_FD(fptr));
+            continue;
+       case SSL_ERROR_WANT_READ:
+            read_would_block(nonblock);
+            rb_io_wait_readable(FPTR_TO_FD(fptr));
+            continue;
+       case SSL_ERROR_SYSCALL:
+           if (errno) rb_sys_fail(funcname);
+           ossl_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl));
+       default:
+           ossl_raise(eSSLError, "%s returned=%d errno=%d state=%s", funcname, ret2, errno, SSL_state_string_long(ssl));
+       }
+    }
+
+    return self;
+}
+
+/*
+ * call-seq:
+ *    ssl.connect => self
+ *
+ * Initiates an SSL/TLS handshake with a server.  The handshake may be started
+ * after unencrypted data has been sent over the socket.
+ */
+static VALUE
+ossl_ssl_connect(VALUE self)
+{
+    ossl_ssl_setup(self);
+    return ossl_start_ssl(self, SSL_connect, "SSL_connect", 0);
+}
+
+/*
+ * call-seq:
+ *    ssl.connect_nonblock => self
+ *
+ * Initiates the SSL/TLS handshake as a client in non-blocking manner.
+ *
+ *   # emulates blocking connect
+ *   begin
+ *     ssl.connect_nonblock
+ *   rescue IO::WaitReadable
+ *     IO.select([s2])
+ *     retry
+ *   rescue IO::WaitWritable
+ *     IO.select(nil, [s2])
+ *     retry
+ *   end
+ *
+ */
+static VALUE
+ossl_ssl_connect_nonblock(VALUE self)
+{
+    ossl_ssl_setup(self);
+    return ossl_start_ssl(self, SSL_connect, "SSL_connect", 1);
+}
+
+/*
+ * call-seq:
+ *    ssl.accept => self
+ *
+ * Waits for a SSL/TLS client to initiate a handshake.  The handshake may be
+ * started after unencrypted data has been sent over the socket.
+ */
+static VALUE
+ossl_ssl_accept(VALUE self)
+{
+    ossl_ssl_setup(self);
+    return ossl_start_ssl(self, SSL_accept, "SSL_accept", 0);
+}
+
+/*
+ * call-seq:
+ *    ssl.accept_nonblock => self
+ *
+ * Initiates the SSL/TLS handshake as a server in non-blocking manner.
+ *
+ *   # emulates blocking accept
+ *   begin
+ *     ssl.accept_nonblock
+ *   rescue IO::WaitReadable
+ *     IO.select([s2])
+ *     retry
+ *   rescue IO::WaitWritable
+ *     IO.select(nil, [s2])
+ *     retry
+ *   end
+ *
+ */
+static VALUE
+ossl_ssl_accept_nonblock(VALUE self)
+{
+    ossl_ssl_setup(self);
+    return ossl_start_ssl(self, SSL_accept, "SSL_accept", 1);
+}
+
+static VALUE
+ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
+{
+    SSL *ssl;
+    int ilen, nread = 0;
+    VALUE len, str;
+    rb_io_t *fptr;
+
+    rb_scan_args(argc, argv, "11", &len, &str);
+    ilen = NUM2INT(len);
+    if(NIL_P(str)) str = rb_str_new(0, ilen);
+    else{
+        StringValue(str);
+        rb_str_modify(str);
+        rb_str_resize(str, ilen);
+    }
+    if(ilen == 0) return str;
+
+    Data_Get_Struct(self, SSL, ssl);
+    GetOpenFile(ossl_ssl_get_io(self), fptr);
+    if (ssl) {
+       if(!nonblock && SSL_pending(ssl) <= 0)
+           rb_thread_wait_fd(FPTR_TO_FD(fptr));
+       for (;;){
+           nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LENINT(str));
+           switch(ssl_get_error(ssl, nread)){
+           case SSL_ERROR_NONE:
+               goto end;
+           case SSL_ERROR_ZERO_RETURN:
+               rb_eof_error();
+           case SSL_ERROR_WANT_WRITE:
+                write_would_block(nonblock);
+                rb_io_wait_writable(FPTR_TO_FD(fptr));
+                continue;
+           case SSL_ERROR_WANT_READ:
+                read_would_block(nonblock);
+                rb_io_wait_readable(FPTR_TO_FD(fptr));
+               continue;
+           case SSL_ERROR_SYSCALL:
+               if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
+               rb_sys_fail(0);
+           default:
+               ossl_raise(eSSLError, "SSL_read:");
+           }
+        }
+    }
+    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);
+    }
+
+  end:
+    rb_str_set_len(str, nread);
+    OBJ_TAINT(str);
+
+    return str;
+}
+
+
+/*
+ * call-seq:
+ *    ssl.sysread(length) => string
+ *    ssl.sysread(length, buffer) => buffer
+ *
+ * Reads +length+ bytes from the SSL connection.  If a pre-allocated +buffer+
+ * is provided the data will be written into it.
+ */
+static VALUE
+ossl_ssl_read(int argc, VALUE *argv, VALUE self)
+{
+    return ossl_ssl_read_internal(argc, argv, self, 0);
+}
+
+/*
+ * call-seq:
+ *    ssl.sysread_nonblock(length) => string
+ *    ssl.sysread_nonblock(length, buffer) => buffer
+ *
+ * A non-blocking version of #sysread.  Raises an SSLError if reading would
+ * block.
+ *
+ * Reads +length+ bytes from the SSL connection.  If a pre-allocated +buffer+
+ * is provided the data will be written into it.
+ */
+static VALUE
+ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
+{
+    return ossl_ssl_read_internal(argc, argv, self, 1);
+}
+
+static VALUE
+ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
+{
+    SSL *ssl;
+    int nwrite = 0;
+    rb_io_t *fptr;
+
+    StringValue(str);
+    Data_Get_Struct(self, SSL, ssl);
+    GetOpenFile(ossl_ssl_get_io(self), fptr);
+
+    if (ssl) {
+       for (;;){
+           nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LENINT(str));
+           switch(ssl_get_error(ssl, nwrite)){
+           case SSL_ERROR_NONE:
+               goto end;
+           case SSL_ERROR_WANT_WRITE:
+                write_would_block(nonblock);
+                rb_io_wait_writable(FPTR_TO_FD(fptr));
+                continue;
+           case SSL_ERROR_WANT_READ:
+                read_would_block(nonblock);
+                rb_io_wait_readable(FPTR_TO_FD(fptr));
+                continue;
+           case SSL_ERROR_SYSCALL:
+               if (errno) rb_sys_fail(0);
+           default:
+               ossl_raise(eSSLError, "SSL_write:");
+           }
+        }
+    }
+    else {
+        ID id_syswrite = rb_intern("syswrite");
+        rb_warning("SSL session is not started yet.");
+       return rb_funcall(ossl_ssl_get_io(self), id_syswrite, 1, str);
+    }
+
+  end:
+    return INT2NUM(nwrite);
+}
+
+/*
+ * call-seq:
+ *    ssl.syswrite(string) => Integer
+ *
+ * Writes +string+ to the SSL connection.
+ */
+static VALUE
+ossl_ssl_write(VALUE self, VALUE str)
+{
+    return ossl_ssl_write_internal(self, str, 0);
+}
+
+/*
+ * call-seq:
+ *    ssl.syswrite_nonblock(string) => Integer
+ *
+ * Writes +string+ to the SSL connection in a non-blocking manner.  Raises an
+ * SSLError if writing would block.
+ */
+static VALUE
+ossl_ssl_write_nonblock(VALUE self, VALUE str)
+{
+    return ossl_ssl_write_internal(self, str, 1);
+}
+
+/*
+ * call-seq:
+ *    ssl.sysclose => nil
+ *
+ * Shuts down the SSL connection and prepares it for another connection.
+ */
+static VALUE
+ossl_ssl_close(VALUE self)
+{
+    SSL *ssl;
+
+    Data_Get_Struct(self, SSL, ssl);
+    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);
+       }
+    }
+
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *    ssl.cert => cert or nil
+ *
+ * The X509 certificate for this socket endpoint.
+ */
+static VALUE
+ossl_ssl_get_cert(VALUE self)
+{
+    SSL *ssl;
+    X509 *cert = NULL;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+
+    /*
+     * Is this OpenSSL bug? Should add a ref?
+     * TODO: Ask for.
+     */
+    cert = SSL_get_certificate(ssl); /* NO DUPs => DON'T FREE. */
+
+    if (!cert) {
+        return Qnil;
+    }
+    return ossl_x509_new(cert);
+}
+
+/*
+ * call-seq:
+ *    ssl.peer_cert => cert or nil
+ *
+ * The X509 certificate for this socket's peer.
+ */
+static VALUE
+ossl_ssl_get_peer_cert(VALUE self)
+{
+    SSL *ssl;
+    X509 *cert = NULL;
+    VALUE obj;
+
+    Data_Get_Struct(self, SSL, ssl);
+
+    if (!ssl){
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+
+    cert = SSL_get_peer_certificate(ssl); /* Adds a ref => Safe to FREE. */
+
+    if (!cert) {
+        return Qnil;
+    }
+    obj = ossl_x509_new(cert);
+    X509_free(cert);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    ssl.peer_cert_chain => [cert, ...] or nil
+ *
+ * The X509 certificate chain for this socket's peer.
+ */
+static VALUE
+ossl_ssl_get_peer_cert_chain(VALUE self)
+{
+    SSL *ssl;
+    STACK_OF(X509) *chain;
+    X509 *cert;
+    VALUE ary;
+    int i, num;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if(!ssl){
+       rb_warning("SSL session is not started yet.");
+       return Qnil;
+    }
+    chain = SSL_get_peer_cert_chain(ssl);
+    if(!chain) return Qnil;
+    num = sk_X509_num(chain);
+    ary = rb_ary_new2(num);
+    for (i = 0; i < num; i++){
+       cert = sk_X509_value(chain, i);
+       rb_ary_push(ary, ossl_x509_new(cert));
+    }
+
+    return ary;
+}
+
+/*
+ * call-seq:
+ *    ssl.cipher => [name, version, bits, alg_bits]
+ *
+ * The cipher being used for the current connection
+ */
+static VALUE
+ossl_ssl_get_cipher(VALUE self)
+{
+    SSL *ssl;
+    SSL_CIPHER *cipher;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+    cipher = (SSL_CIPHER *)SSL_get_current_cipher(ssl);
+
+    return ossl_ssl_cipher_to_ary(cipher);
+}
+
+/*
+ * call-seq:
+ *    ssl.state => string
+ *
+ * A description of the current connection state.
+ */
+static VALUE
+ossl_ssl_get_state(VALUE self)
+{
+    SSL *ssl;
+    VALUE ret;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+    ret = rb_str_new2(SSL_state_string(ssl));
+    if (ruby_verbose) {
+        rb_str_cat2(ret, ": ");
+        rb_str_cat2(ret, SSL_state_string_long(ssl));
+    }
+    return ret;
+}
+
+/*
+ * call-seq:
+ *    ssl.pending => Integer
+ *
+ * The number of bytes that are immediately available for reading
+ */
+static VALUE
+ossl_ssl_pending(VALUE self)
+{
+    SSL *ssl;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+
+    return INT2NUM(SSL_pending(ssl));
+}
+
+/*
+ * call-seq:
+ *    ssl.session_reused? -> true | false
+ *
+ * Returns true if a reused session was negotiated during the handshake.
+ */
+static VALUE
+ossl_ssl_session_reused(VALUE self)
+{
+    SSL *ssl;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+
+    switch(SSL_session_reused(ssl)) {
+    case 1:    return Qtrue;
+    case 0:    return Qfalse;
+    default:   ossl_raise(eSSLError, "SSL_session_reused");
+    }
+}
+
+/*
+ * call-seq:
+ *    ssl.session = session -> session
+ *
+ * Sets the Session to be used when the connection is established.
+ */
+static VALUE
+ossl_ssl_set_session(VALUE self, VALUE arg1)
+{
+    SSL *ssl;
+    SSL_SESSION *sess;
+
+/* why is ossl_ssl_setup delayed? */
+    ossl_ssl_setup(self);
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+
+    SafeGetSSLSession(arg1, sess);
+
+    if (SSL_set_session(ssl, sess) != 1)
+        ossl_raise(eSSLError, "SSL_set_session");
+
+    return arg1;
+}
+
+/*
+ * call-seq:
+ *    ssl.verify_result => Integer
+ *
+ * Returns the result of the peer certificates verification.  See verify(1)
+ * for error values and descriptions.
+ *
+ * If no peer certificate was presented X509_V_OK is returned.
+ */
+static VALUE
+ossl_ssl_get_verify_result(VALUE self)
+{
+    SSL *ssl;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+        rb_warning("SSL session is not started yet.");
+        return Qnil;
+    }
+
+    return INT2FIX(SSL_get_verify_result(ssl));
+}
+
+/*
+ * call-seq:
+ *    ssl.client_ca => [x509name, ...]
+ *
+ * Returns the list of client CAs. Please note that in contrast to
+ * SSLContext#client_ca= no array of X509::Certificate is returned but
+ * X509::Name instances of the CA's subject distinguished name.
+ *
+ * In server mode, returns the list set by SSLContext#client_ca=.
+ * In client mode, returns the list of client CAs sent from the server.
+ */
+static VALUE
+ossl_ssl_get_client_ca_list(VALUE self)
+{
+    SSL *ssl;
+    STACK_OF(X509_NAME) *ca;
+
+    Data_Get_Struct(self, SSL, ssl);
+    if (!ssl) {
+       rb_warning("SSL session is not started yet.");
+       return Qnil;
+    }
+
+    ca = SSL_get_client_CA_list(ssl);
+    return ossl_x509name_sk2ary(ca);
+}
+
+void
+Init_ossl_ssl()
+{
+    int i;
+    VALUE ary;
+
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+#endif
+
+    ID_callback_state = rb_intern("@callback_state");
+
+    ossl_ssl_ex_vcb_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_vcb_idx",0,0,0);
+    ossl_ssl_ex_store_p = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_store_p",0,0,0);
+    ossl_ssl_ex_ptr_idx = SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_ptr_idx",0,0,0);
+    ossl_ssl_ex_client_cert_cb_idx =
+       SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_client_cert_cb_idx",0,0,0);
+    ossl_ssl_ex_tmp_dh_callback_idx =
+       SSL_get_ex_new_index(0,(void *)"ossl_ssl_ex_tmp_dh_callback_idx",0,0,0);
+
+    mSSL = rb_define_module_under(mOSSL, "SSL");
+    eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
+
+    Init_ossl_ssl_session();
+
+    /* Document-class: OpenSSL::SSL::SSLContext
+     *
+     * An SSLContext is used to set various options regarding certificates,
+     * algorithms, verification, session caching, etc.  The SSLContext is
+     * used to create an SSLSocket.
+     *
+     * All attributes must be set before creating an SSLSocket as the
+     * SSLContext will be frozen afterward.
+     *
+     * The following attributes are available but don't show up in rdoc:
+     * * ssl_version, cert, key, client_ca, ca_file, ca_path, timeout,
+     * * verify_mode, verify_depth client_cert_cb, tmp_dh_callback,
+     * * session_id_context, session_add_cb, session_new_cb, session_remove_cb
+     */
+    cSSLContext = rb_define_class_under(mSSL, "SSLContext", rb_cObject);
+    rb_define_alloc_func(cSSLContext, ossl_sslctx_s_alloc);
+
+    /*
+     * Context certificate
+     */
+    rb_attr(cSSLContext, rb_intern("cert"), 1, 1, Qfalse);
+
+    /*
+     * Context private key
+     */
+    rb_attr(cSSLContext, rb_intern("key"), 1, 1, Qfalse);
+
+    /*
+     * A certificate or Array of certificates that will be sent to the client.
+     */
+    rb_attr(cSSLContext, rb_intern("client_ca"), 1, 1, Qfalse);
+
+    /*
+     * The path to a file containing a PEM-format CA certificate
+     */
+    rb_attr(cSSLContext, rb_intern("ca_file"), 1, 1, Qfalse);
+
+    /*
+     * The path to a directory containing CA certificates in PEM format.
+     *
+     * Files are looked up by subject's X509 name's hash value.
+     */
+    rb_attr(cSSLContext, rb_intern("ca_path"), 1, 1, Qfalse);
+
+    /*
+     * Maximum session lifetime.
+     */
+    rb_attr(cSSLContext, rb_intern("timeout"), 1, 1, Qfalse);
+
+    /*
+     * Session verification mode.
+     *
+     * Valid modes are VERIFY_NONE, VERIFY_PEER, VERIFY_CLIENT_ONCE,
+     * VERIFY_FAIL_IF_NO_PEER_CERT and defined on OpenSSL::SSL
+     */
+    rb_attr(cSSLContext, rb_intern("verify_mode"), 1, 1, Qfalse);
+
+    /*
+     * Number of CA certificates to walk when verifying a certificate chain.
+     */
+    rb_attr(cSSLContext, rb_intern("verify_depth"), 1, 1, Qfalse);
+
+    /*
+     * A callback for additional certificate verification.  The callback is
+     * invoked for each certificate in the chain.
+     *
+     * The callback is invoked with two values.  +preverify_ok+ indicates
+     * indicates if the verification was passed (true) or not (false).
+     * +store_context+ is an OpenSSL::X509::StoreContext containing the
+     * context used for certificate verification.
+     *
+     * If the callback returns false verification is stopped.
+     */
+    rb_attr(cSSLContext, rb_intern("verify_callback"), 1, 1, Qfalse);
+
+    /*
+     * Sets various OpenSSL options.
+     */
+    rb_attr(cSSLContext, rb_intern("options"), 1, 1, Qfalse);
+
+    /*
+     * An OpenSSL::X509::Store used for certificate verification
+     */
+    rb_attr(cSSLContext, rb_intern("cert_store"), 1, 1, Qfalse);
+
+    /*
+     * An Array of extra X509 certificates to be added to the certificate
+     * chain.
+     */
+    rb_attr(cSSLContext, rb_intern("extra_chain_cert"), 1, 1, Qfalse);
+
+    /*
+     * A callback invoked when a client certificate is requested by a server
+     * and no certificate has been set.
+     *
+     * The callback is invoked with a Session and must return an Array
+     * containing an OpenSSL::X509::Certificate and an OpenSSL::PKey.  If any
+     * other value is returned the handshake is suspended.
+     */
+    rb_attr(cSSLContext, rb_intern("client_cert_cb"), 1, 1, Qfalse);
+
+    /*
+     * A callback invoked when DH parameters are required.
+     *
+     * The callback is invoked with the Session for the key exchange, an
+     * flag indicating the use of an export cipher and the keylength
+     * required.
+     *
+     * The callback must return an OpenSSL::PKey::DH instance of the correct
+     * key length.
+     */
+    rb_attr(cSSLContext, rb_intern("tmp_dh_callback"), 1, 1, Qfalse);
+
+    /*
+     * Sets the context in which a session can be reused.  This allows
+     * sessions for multiple applications to be distinguished, for exapmle, by
+     * name.
+     */
+    rb_attr(cSSLContext, rb_intern("session_id_context"), 1, 1, Qfalse);
+
+    /*
+     * A callback invoked on a server when a session is proposed by the client
+     * but the session could not be found in the server's internal cache.
+     *
+     * The callback is invoked with the SSLSocket and session id.  The
+     * callback may return a Session from an external cache.
+     */
+    rb_attr(cSSLContext, rb_intern("session_get_cb"), 1, 1, Qfalse);
+
+    /*
+     * A callback invoked when a new session was negotiatied.
+     *
+     * The callback is invoked with an SSLSocket.  If false is returned the
+     * session will be removed from the internal cache.
+     */
+    rb_attr(cSSLContext, rb_intern("session_new_cb"), 1, 1, Qfalse);
+
+    /*
+     * A callback invoked when a session is removed from the internal cache.
+     *
+     * The callback is invoked with an SSLContext and a Session.
+     */
+    rb_attr(cSSLContext, rb_intern("session_remove_cb"), 1, 1, Qfalse);
+
+#ifdef HAVE_SSL_SET_TLSEXT_HOST_NAME
+    /*
+     * A callback invoked at connect time to distinguish between multiple
+     * server names.
+     *
+     * The callback is invoked with an SSLSocket and a server name.  The
+     * callback must return an SSLContext for the server name or nil.
+     */
+    rb_attr(cSSLContext, rb_intern("servername_cb"), 1, 1, Qfalse);
+#endif
+
+    rb_define_alias(cSSLContext, "ssl_timeout", "timeout");
+    rb_define_alias(cSSLContext, "ssl_timeout=", "timeout=");
+    rb_define_method(cSSLContext, "initialize",  ossl_sslctx_initialize, -1);
+    rb_define_method(cSSLContext, "ssl_version=", ossl_sslctx_set_ssl_version, 1);
+    rb_define_method(cSSLContext, "ciphers",     ossl_sslctx_get_ciphers, 0);
+    rb_define_method(cSSLContext, "ciphers=",    ossl_sslctx_set_ciphers, 1);
+
+    rb_define_method(cSSLContext, "setup", ossl_sslctx_setup, 0);
+
+
+    /*
+     * No session caching for client or server
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_OFF", LONG2FIX(SSL_SESS_CACHE_OFF));
+
+    /*
+     * Client sessions are added to the session cache
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_CLIENT", LONG2FIX(SSL_SESS_CACHE_CLIENT)); /* doesn't actually do anything in 0.9.8e */
+
+    /*
+     * Server sessions are added to the session cache
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_SERVER", LONG2FIX(SSL_SESS_CACHE_SERVER));
+
+    /*
+     * Both client and server sessions are added to the session cache
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_BOTH", LONG2FIX(SSL_SESS_CACHE_BOTH)); /* no different than CACHE_SERVER in 0.9.8e */
+
+    /*
+     * Normally the sesison cache is checked for expired sessions every 255
+     * connections.  Since this may lead to a delay that cannot be controlled,
+     * the automatic flushing may be disabled and #flush_sessions can be
+     * called explicitly.
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_NO_AUTO_CLEAR", LONG2FIX(SSL_SESS_CACHE_NO_AUTO_CLEAR));
+
+    /*
+     * Always perform external lookups of sessions even if they are in the
+     * internal cache.
+     *
+     * This flag has no effect on clients
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_LOOKUP", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP));
+
+    /*
+     * Never automatically store sessions in the internal store.
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL_STORE", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL_STORE));
+
+    /*
+     * Enables both SESSION_CACHE_NO_INTERNAL_LOOKUP and
+     * SESSION_CACHE_NO_INTERNAL_STORE.
+     */
+    rb_define_const(cSSLContext, "SESSION_CACHE_NO_INTERNAL", LONG2FIX(SSL_SESS_CACHE_NO_INTERNAL));
+
+    rb_define_method(cSSLContext, "session_add",     ossl_sslctx_session_add, 1);
+    rb_define_method(cSSLContext, "session_remove",     ossl_sslctx_session_remove, 1);
+    rb_define_method(cSSLContext, "session_cache_mode",     ossl_sslctx_get_session_cache_mode, 0);
+    rb_define_method(cSSLContext, "session_cache_mode=",     ossl_sslctx_set_session_cache_mode, 1);
+    rb_define_method(cSSLContext, "session_cache_size",     ossl_sslctx_get_session_cache_size, 0);
+    rb_define_method(cSSLContext, "session_cache_size=",     ossl_sslctx_set_session_cache_size, 1);
+    rb_define_method(cSSLContext, "session_cache_stats",     ossl_sslctx_get_session_cache_stats, 0);
+    rb_define_method(cSSLContext, "flush_sessions",     ossl_sslctx_flush_sessions, -1);
+
+    ary = rb_ary_new2(numberof(ossl_ssl_method_tab));
+    for (i = 0; i < numberof(ossl_ssl_method_tab); i++) {
+        rb_ary_push(ary, ID2SYM(rb_intern(ossl_ssl_method_tab[i].name)));
+    }
+    rb_obj_freeze(ary);
+    /* The list of available SSL/TLS methods */
+    rb_define_const(cSSLContext, "METHODS", ary);
+
+    /*
+     * Document-class: OpenSSL::SSL::SSLSocket
+     *
+     * The following attributes are available but don't show up in rdoc.
+     * * io, context, sync_close
+     *
+     */
+    cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject);
+    rb_define_alloc_func(cSSLSocket, ossl_ssl_s_alloc);
+    for(i = 0; i < numberof(ossl_ssl_attr_readers); i++)
+        rb_attr(cSSLSocket, rb_intern(ossl_ssl_attr_readers[i]), 1, 0, Qfalse);
+    for(i = 0; i < numberof(ossl_ssl_attrs); i++)
+        rb_attr(cSSLSocket, rb_intern(ossl_ssl_attrs[i]), 1, 1, Qfalse);
+    rb_define_alias(cSSLSocket, "to_io", "io");
+    rb_define_method(cSSLSocket, "initialize", ossl_ssl_initialize, -1);
+    rb_define_method(cSSLSocket, "connect",    ossl_ssl_connect, 0);
+    rb_define_method(cSSLSocket, "connect_nonblock",    ossl_ssl_connect_nonblock, 0);
+    rb_define_method(cSSLSocket, "accept",     ossl_ssl_accept, 0);
+    rb_define_method(cSSLSocket, "accept_nonblock",     ossl_ssl_accept_nonblock, 0);
+    rb_define_method(cSSLSocket, "sysread",    ossl_ssl_read, -1);
+    rb_define_private_method(cSSLSocket, "sysread_nonblock",    ossl_ssl_read_nonblock, -1);
+    rb_define_method(cSSLSocket, "syswrite",   ossl_ssl_write, 1);
+    rb_define_private_method(cSSLSocket, "syswrite_nonblock",    ossl_ssl_write_nonblock, 1);
+    rb_define_method(cSSLSocket, "sysclose",   ossl_ssl_close, 0);
+    rb_define_method(cSSLSocket, "cert",       ossl_ssl_get_cert, 0);
+    rb_define_method(cSSLSocket, "peer_cert",  ossl_ssl_get_peer_cert, 0);
+    rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0);
+    rb_define_method(cSSLSocket, "cipher",     ossl_ssl_get_cipher, 0);
+    rb_define_method(cSSLSocket, "state",      ossl_ssl_get_state, 0);
+    rb_define_method(cSSLSocket, "pending",    ossl_ssl_pending, 0);
+    rb_define_method(cSSLSocket, "session_reused?",    ossl_ssl_session_reused, 0);
+    rb_define_method(cSSLSocket, "session=",    ossl_ssl_set_session, 1);
+    rb_define_method(cSSLSocket, "verify_result", ossl_ssl_get_verify_result, 0);
+    rb_define_method(cSSLSocket, "client_ca", ossl_ssl_get_client_ca_list, 0);
+
+#define ossl_ssl_def_const(x) rb_define_const(mSSL, #x, INT2NUM(SSL_##x))
+
+    ossl_ssl_def_const(VERIFY_NONE);
+    ossl_ssl_def_const(VERIFY_PEER);
+    ossl_ssl_def_const(VERIFY_FAIL_IF_NO_PEER_CERT);
+    ossl_ssl_def_const(VERIFY_CLIENT_ONCE);
+    /* Introduce constants included in OP_ALL.  These constants are mostly for
+     * unset some bits in OP_ALL such as:
+     *   ctx.options = OP_ALL & ~OP_DONT_INSERT_EMPTY_FRAGMENTS
+     */
+    ossl_ssl_def_const(OP_MICROSOFT_SESS_ID_BUG);
+    ossl_ssl_def_const(OP_NETSCAPE_CHALLENGE_BUG);
+    ossl_ssl_def_const(OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
+    ossl_ssl_def_const(OP_SSLREF2_REUSE_CERT_TYPE_BUG);
+    ossl_ssl_def_const(OP_MICROSOFT_BIG_SSLV3_BUFFER);
+#if defined(SSL_OP_MSIE_SSLV2_RSA_PADDING)
+    ossl_ssl_def_const(OP_MSIE_SSLV2_RSA_PADDING);
+#endif
+    ossl_ssl_def_const(OP_SSLEAY_080_CLIENT_DH_BUG);
+    ossl_ssl_def_const(OP_TLS_D5_BUG);
+    ossl_ssl_def_const(OP_TLS_BLOCK_PADDING_BUG);
+    ossl_ssl_def_const(OP_DONT_INSERT_EMPTY_FRAGMENTS);
+    ossl_ssl_def_const(OP_ALL);
+#if defined(SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION)
+    ossl_ssl_def_const(OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+#endif
+#if defined(SSL_OP_SINGLE_ECDH_USE)
+    ossl_ssl_def_const(OP_SINGLE_ECDH_USE);
+#endif
+    ossl_ssl_def_const(OP_SINGLE_DH_USE);
+    ossl_ssl_def_const(OP_EPHEMERAL_RSA);
+#if defined(SSL_OP_CIPHER_SERVER_PREFERENCE)
+    ossl_ssl_def_const(OP_CIPHER_SERVER_PREFERENCE);
+#endif
+    ossl_ssl_def_const(OP_TLS_ROLLBACK_BUG);
+    ossl_ssl_def_const(OP_NO_SSLv2);
+    ossl_ssl_def_const(OP_NO_SSLv3);
+    ossl_ssl_def_const(OP_NO_TLSv1);
+#if defined(SSL_OP_NO_TICKET)
+    ossl_ssl_def_const(OP_NO_TICKET);
+#endif
+#if defined(SSL_OP_NO_COMPRESSION)
+    ossl_ssl_def_const(OP_NO_COMPRESSION);
+#endif
+    ossl_ssl_def_const(OP_PKCS1_CHECK_1);
+    ossl_ssl_def_const(OP_PKCS1_CHECK_2);
+    ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG);
+    ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl.h
new file mode 100644 (file)
index 0000000..034762f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_SSL_H_)
+#define _OSSL_SSL_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)
+
+extern VALUE mSSL;
+extern VALUE eSSLError;
+extern VALUE cSSLSocket;
+extern VALUE cSSLContext;
+extern VALUE cSSLSession;
+
+void Init_ossl_ssl(void);
+void Init_ossl_ssl_session(void);
+
+#endif /* _OSSL_SSL_H_ */
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl_session.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_ssl_session.c
new file mode 100644 (file)
index 0000000..a7437ca
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *  Copyright (C) 2004-2007 Technorama Ltd. <oss-ruby@technorama.net>
+ */
+
+#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 VALUE ossl_ssl_session_alloc(VALUE klass)
+{
+       return Data_Wrap_Struct(klass, 0, SSL_SESSION_free, NULL);
+}
+
+/*
+ * call-seq:
+ *    Session.new(SSLSocket | string) => session
+ *
+ * === Parameters
+ * +SSLSocket+ is an OpenSSL::SSL::SSLSocket
+ * +string+ must be a DER or PEM encoded Session.
+*/
+static VALUE ossl_ssl_session_initialize(VALUE self, VALUE arg1)
+{
+       SSL_SESSION *ctx = NULL;
+
+       if (RDATA(self)->data)
+               ossl_raise(eSSLSession, "SSL Session already initialized");
+
+       if (rb_obj_is_instance_of(arg1, cSSLSocket)) {
+               SSL *ssl;
+
+               Data_Get_Struct(arg1, SSL, ssl);
+
+               if (!ssl || (ctx = SSL_get1_session(ssl)) == NULL)
+                       ossl_raise(eSSLSession, "no session available");
+       } else {
+               BIO *in = ossl_obj2bio(arg1);
+
+               ctx = PEM_read_bio_SSL_SESSION(in, NULL, NULL, NULL);
+
+               if (!ctx) {
+                       OSSL_BIO_reset(in);
+                       ctx = d2i_SSL_SESSION_bio(in, NULL);
+               }
+
+               BIO_free(in);
+
+               if (!ctx)
+                       ossl_raise(rb_eArgError, "unknown type");
+       }
+
+       /* should not happen */
+       if (ctx == NULL)
+               ossl_raise(eSSLSession, "ctx not set - internal error");
+
+       RDATA(self)->data = ctx;
+
+       return self;
+}
+
+#if HAVE_SSL_SESSION_CMP == 0
+int SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b)
+{
+    if (a->ssl_version != b->ssl_version ||
+       a->session_id_length != b->session_id_length)
+       return 1;
+    return memcmp(a->session_id,b-> session_id, a->session_id_length);
+}
+#endif
+
+/*
+ * call-seq:
+ *    session1 == session2 -> boolean
+ *
+*/
+static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2)
+{
+       SSL_SESSION *ctx1, *ctx2;
+
+       GetSSLSession(val1, ctx1);
+       SafeGetSSLSession(val2, ctx2);
+
+       switch (SSL_SESSION_cmp(ctx1, ctx2)) {
+       case 0:         return Qtrue;
+       default:        return Qfalse;
+       }
+}
+
+/*
+ * call-seq:
+ *    session.time -> Time
+ *
+ * Gets start time of the session.
+ *
+*/
+static VALUE ossl_ssl_session_get_time(VALUE self)
+{
+       SSL_SESSION *ctx;
+       time_t t;
+
+       GetSSLSession(self, ctx);
+
+       t = SSL_SESSION_get_time(ctx);
+
+       if (t == 0)
+               return Qnil;
+
+       return rb_funcall(rb_cTime, rb_intern("at"), 1, TIMET2NUM(t));
+}
+
+/*
+ * call-seq:
+ *    session.timeout -> integer
+ *
+ * Gets how long until the session expires in seconds.
+ *
+*/
+static VALUE ossl_ssl_session_get_timeout(VALUE self)
+{
+       SSL_SESSION *ctx;
+       time_t t;
+
+       GetSSLSession(self, ctx);
+
+       t = SSL_SESSION_get_timeout(ctx);
+
+       return TIMET2NUM(t);
+}
+
+/*
+ * call-seq:
+ *    session.time=(Time) -> Time
+ *    session.time=(integer) -> Time
+ *
+ * Sets start time of the session. Time resolution is in seconds.
+ *
+*/
+static VALUE ossl_ssl_session_set_time(VALUE self, VALUE time_v)
+{
+       SSL_SESSION *ctx;
+       long t;
+
+       GetSSLSession(self, ctx);
+       if (rb_obj_is_instance_of(time_v, rb_cTime)) {
+               time_v = rb_funcall(time_v, rb_intern("to_i"), 0);
+       }
+       t = NUM2LONG(time_v);
+       SSL_SESSION_set_time(ctx, t);
+       return ossl_ssl_session_get_time(self);
+}
+
+/*
+ * call-seq:
+ *    session.timeout=(integer) -> integer
+ *
+ * Sets how long until the session expires in seconds.
+ *
+*/
+static VALUE ossl_ssl_session_set_timeout(VALUE self, VALUE time_v)
+{
+       SSL_SESSION *ctx;
+       long t;
+
+       GetSSLSession(self, ctx);
+       t = NUM2LONG(time_v);
+       SSL_SESSION_set_timeout(ctx, t);
+       return ossl_ssl_session_get_timeout(self);
+}
+
+#ifdef HAVE_SSL_SESSION_GET_ID
+/*
+ * call-seq:
+ *    session.id -> aString
+ *
+ * Returns the Session ID.
+*/
+static VALUE ossl_ssl_session_get_id(VALUE self)
+{
+       SSL_SESSION *ctx;
+       const unsigned char *p = NULL;
+       unsigned int i = 0;
+
+       GetSSLSession(self, ctx);
+
+       p = SSL_SESSION_get_id(ctx, &i);
+
+       return rb_str_new((const char *) p, i);
+}
+#endif
+
+/*
+ * call-seq:
+ *    session.to_der -> aString
+ *
+ * Returns an ASN1 encoded String that contains the Session object.
+*/
+static VALUE ossl_ssl_session_to_der(VALUE self)
+{
+       SSL_SESSION *ctx;
+       unsigned char *p;
+       int len;
+       VALUE str;
+
+       GetSSLSession(self, ctx);
+       len = i2d_SSL_SESSION(ctx, NULL);
+       if (len <= 0) {
+               ossl_raise(eSSLSession, "i2d_SSL_SESSION");
+       }
+
+       str = rb_str_new(0, len);
+       p = (unsigned char *)RSTRING_PTR(str);
+       i2d_SSL_SESSION(ctx, &p);
+       ossl_str_adjust(str, p);
+       return str;
+}
+
+/*
+ * call-seq:
+ *    session.to_pem -> String
+ *
+ * Returns a PEM encoded String that contains the Session object.
+*/
+static VALUE ossl_ssl_session_to_pem(VALUE self)
+{
+       SSL_SESSION *ctx;
+       BIO *out;
+       BUF_MEM *buf;
+       VALUE str;
+       int i;
+
+       GetSSLSession(self, ctx);
+
+       if (!(out = BIO_new(BIO_s_mem()))) {
+               ossl_raise(eSSLSession, "BIO_s_mem()");
+       }
+
+       if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) {
+               BIO_free(out);
+               ossl_raise(eSSLSession, "SSL_SESSION_print()");
+       }
+
+       BIO_get_mem_ptr(out, &buf);
+       str = rb_str_new(buf->data, buf->length);
+       BIO_free(out);
+
+       return str;
+}
+
+
+/*
+ * call-seq:
+ *    session.to_text -> String
+ *
+ * Shows everything in the Session object.
+*/
+static VALUE ossl_ssl_session_to_text(VALUE self)
+{
+       SSL_SESSION *ctx;
+       BIO *out;
+       BUF_MEM *buf;
+       VALUE str;
+
+       GetSSLSession(self, ctx);
+
+       if (!(out = BIO_new(BIO_s_mem()))) {
+               ossl_raise(eSSLSession, "BIO_s_mem()");
+       }
+
+       if (!SSL_SESSION_print(out, ctx)) {
+               BIO_free(out);
+               ossl_raise(eSSLSession, "SSL_SESSION_print()");
+       }
+
+       BIO_get_mem_ptr(out, &buf);
+       str = rb_str_new(buf->data, buf->length);
+       BIO_free(out);
+
+       return str;
+}
+
+
+void Init_ossl_ssl_session(void)
+{
+#if 0
+       mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+       mSSL = rb_define_module_under(mOSSL, "SSL");
+#endif
+       cSSLSession = rb_define_class_under(mSSL, "Session", rb_cObject);
+       eSSLSession = rb_define_class_under(cSSLSession, "SessionError", eOSSLError);
+
+       rb_define_alloc_func(cSSLSession, ossl_ssl_session_alloc);
+       rb_define_method(cSSLSession, "initialize", ossl_ssl_session_initialize, 1);
+
+       rb_define_method(cSSLSession, "==", ossl_ssl_session_eq, 1);
+
+       rb_define_method(cSSLSession, "time", ossl_ssl_session_get_time, 0);
+       rb_define_method(cSSLSession, "time=", ossl_ssl_session_set_time, 1);
+       rb_define_method(cSSLSession, "timeout", ossl_ssl_session_get_timeout, 0);
+       rb_define_method(cSSLSession, "timeout=", ossl_ssl_session_set_timeout, 1);
+
+#ifdef HAVE_SSL_SESSION_GET_ID
+       rb_define_method(cSSLSession, "id", ossl_ssl_session_get_id, 0);
+#else
+       rb_undef_method(cSSLSession, "id");
+#endif
+       rb_define_method(cSSLSession, "to_der", ossl_ssl_session_to_der, 0);
+       rb_define_method(cSSLSession, "to_pem", ossl_ssl_session_to_pem, 0);
+       rb_define_method(cSSLSession, "to_text", ossl_ssl_session_to_text, 0);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_version.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_version.h
new file mode 100644 (file)
index 0000000..193ceab
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_VERSION_H_)
+#define _OSSL_VERSION_H_
+
+#define OSSL_VERSION "1.1.0"
+
+#endif /* _OSSL_VERSION_H_ */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509.c
new file mode 100644 (file)
index 0000000..fd1d9b6
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+VALUE mX509;
+
+#define DefX509Const(x) rb_define_const(mX509, #x,INT2FIX(X509_##x))
+#define DefX509Default(x,i) \
+  rb_define_const(mX509, "DEFAULT_" #x, rb_str_new2(X509_get_default_##i()))
+
+void
+Init_ossl_x509()
+{
+    mX509 = rb_define_module_under(mOSSL, "X509");
+
+    Init_ossl_x509attr();
+    Init_ossl_x509cert();
+    Init_ossl_x509crl();
+    Init_ossl_x509ext();
+    Init_ossl_x509name();
+    Init_ossl_x509req();
+    Init_ossl_x509revoked();
+    Init_ossl_x509store();
+
+    DefX509Const(V_OK);
+    DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT);
+    DefX509Const(V_ERR_UNABLE_TO_GET_CRL);
+    DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE);
+    DefX509Const(V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE);
+    DefX509Const(V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY);
+    DefX509Const(V_ERR_CERT_SIGNATURE_FAILURE);
+    DefX509Const(V_ERR_CRL_SIGNATURE_FAILURE);
+    DefX509Const(V_ERR_CERT_NOT_YET_VALID);
+    DefX509Const(V_ERR_CERT_HAS_EXPIRED);
+    DefX509Const(V_ERR_CRL_NOT_YET_VALID);
+    DefX509Const(V_ERR_CRL_HAS_EXPIRED);
+    DefX509Const(V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD);
+    DefX509Const(V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD);
+    DefX509Const(V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD);
+    DefX509Const(V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+    DefX509Const(V_ERR_OUT_OF_MEM);
+    DefX509Const(V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT);
+    DefX509Const(V_ERR_SELF_SIGNED_CERT_IN_CHAIN);
+    DefX509Const(V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+    DefX509Const(V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE);
+    DefX509Const(V_ERR_CERT_CHAIN_TOO_LONG);
+    DefX509Const(V_ERR_CERT_REVOKED);
+    DefX509Const(V_ERR_INVALID_CA);
+    DefX509Const(V_ERR_PATH_LENGTH_EXCEEDED);
+    DefX509Const(V_ERR_INVALID_PURPOSE);
+    DefX509Const(V_ERR_CERT_UNTRUSTED);
+    DefX509Const(V_ERR_CERT_REJECTED);
+    DefX509Const(V_ERR_SUBJECT_ISSUER_MISMATCH);
+    DefX509Const(V_ERR_AKID_SKID_MISMATCH);
+    DefX509Const(V_ERR_AKID_ISSUER_SERIAL_MISMATCH);
+    DefX509Const(V_ERR_KEYUSAGE_NO_CERTSIGN);
+    DefX509Const(V_ERR_APPLICATION_VERIFICATION);
+
+#if defined(X509_V_FLAG_CRL_CHECK)
+    DefX509Const(V_FLAG_CRL_CHECK);
+#endif
+#if defined(X509_V_FLAG_CRL_CHECK_ALL)
+    DefX509Const(V_FLAG_CRL_CHECK_ALL);
+#endif
+
+    DefX509Const(PURPOSE_SSL_CLIENT);
+    DefX509Const(PURPOSE_SSL_SERVER);
+    DefX509Const(PURPOSE_NS_SSL_SERVER);
+    DefX509Const(PURPOSE_SMIME_SIGN);
+    DefX509Const(PURPOSE_SMIME_ENCRYPT);
+    DefX509Const(PURPOSE_CRL_SIGN);
+    DefX509Const(PURPOSE_ANY);
+#if defined(X509_PURPOSE_OCSP_HELPER)
+    DefX509Const(PURPOSE_OCSP_HELPER);
+#endif
+
+    DefX509Const(TRUST_COMPAT);
+    DefX509Const(TRUST_SSL_CLIENT);
+    DefX509Const(TRUST_SSL_SERVER);
+    DefX509Const(TRUST_EMAIL);
+    DefX509Const(TRUST_OBJECT_SIGN);
+#if defined(X509_TRUST_OCSP_SIGN)
+    DefX509Const(TRUST_OCSP_SIGN);
+#endif
+#if defined(X509_TRUST_OCSP_REQUEST)
+    DefX509Const(TRUST_OCSP_REQUEST);
+#endif
+
+    DefX509Default(CERT_AREA, cert_area);
+    DefX509Default(CERT_DIR, cert_dir);
+    DefX509Default(CERT_FILE, cert_file);
+    DefX509Default(CERT_DIR_ENV, cert_dir_env);
+    DefX509Default(CERT_FILE_ENV, cert_file_env);
+    DefX509Default(PRIVATE_DIR, private_dir);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509.h
new file mode 100644 (file)
index 0000000..1a43569
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_X509_H_)
+#define _OSSL_X509_H_
+
+/*
+ * X509 main module
+ */
+extern VALUE mX509;
+
+void Init_ossl_x509(void);
+
+/*
+ * X509Attr
+ */
+extern VALUE cX509Attr;
+extern VALUE eX509AttrError;
+
+VALUE ossl_x509attr_new(X509_ATTRIBUTE *);
+X509_ATTRIBUTE *DupX509AttrPtr(VALUE);
+void Init_ossl_x509attr(void);
+
+/*
+ * X509Cert
+ */
+extern VALUE cX509Cert;
+extern VALUE eX509CertError;
+
+VALUE ossl_x509_new(X509 *);
+VALUE ossl_x509_new_from_file(VALUE);
+X509 *GetX509CertPtr(VALUE);
+X509 *DupX509CertPtr(VALUE);
+void Init_ossl_x509cert(void);
+
+/*
+ * X509CRL
+ */
+extern VALUE cX509CRL;
+extern VALUE eX509CRLError;
+
+VALUE ossl_x509crl_new(X509_CRL *);
+X509_CRL *GetX509CRLPtr(VALUE);
+X509_CRL *DupX509CRLPtr(VALUE);
+void Init_ossl_x509crl(void);
+
+/*
+ * X509Extension
+ */
+extern VALUE cX509Ext;
+extern VALUE cX509ExtFactory;
+extern VALUE eX509ExtError;
+
+VALUE ossl_x509ext_new(X509_EXTENSION *);
+X509_EXTENSION *GetX509ExtPtr(VALUE);
+X509_EXTENSION *DupX509ExtPtr(VALUE);
+void Init_ossl_x509ext(void);
+
+/*
+ * X509Name
+ */
+extern VALUE cX509Name;
+extern VALUE eX509NameError;
+
+VALUE ossl_x509name_new(X509_NAME *);
+X509_NAME *GetX509NamePtr(VALUE);
+void Init_ossl_x509name(void);
+
+/*
+ * X509Request
+ */
+extern VALUE cX509Req;
+extern VALUE eX509ReqError;
+
+VALUE ossl_x509req_new(X509_REQ *);
+X509_REQ *GetX509ReqPtr(VALUE);
+X509_REQ *DupX509ReqPtr(VALUE);
+void Init_ossl_x509req(void);
+
+/*
+ * X509Revoked
+ */
+extern VALUE cX509Rev;
+extern VALUE eX509RevError;
+
+VALUE ossl_x509revoked_new(X509_REVOKED *);
+X509_REVOKED *DupX509RevokedPtr(VALUE);
+void Init_ossl_x509revoked(void);
+
+/*
+ * X509Store and X509StoreContext
+ */
+extern VALUE cX509Store;
+extern VALUE cX509StoreContext;
+extern VALUE eX509StoreError;
+
+VALUE ossl_x509store_new(X509_STORE *);
+X509_STORE *GetX509StorePtr(VALUE);
+X509_STORE *DupX509StorePtr(VALUE);
+
+VALUE ossl_x509stctx_new(X509_STORE_CTX *);
+VALUE ossl_x509stctx_clear_ptr(VALUE);
+X509_STORE_CTX *GetX509StCtxtPtr(VALUE);
+
+void Init_ossl_x509store(void);
+
+#endif /* _OSSL_X509_H_ */
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509attr.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509attr.c
new file mode 100644 (file)
index 0000000..1f36ca8
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Attr(klass, obj, attr) do { \
+    if (!(attr)) { \
+       ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_ATTRIBUTE_free, (attr)); \
+} while (0)
+#define GetX509Attr(obj, attr) do { \
+    Data_Get_Struct((obj), X509_ATTRIBUTE, (attr)); \
+    if (!(attr)) { \
+       ossl_raise(rb_eRuntimeError, "ATTR wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetX509Attr(obj, attr) do { \
+    OSSL_Check_Kind((obj), cX509Attr); \
+    GetX509Attr((obj), (attr)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Attr;
+VALUE eX509AttrError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509attr_new(X509_ATTRIBUTE *attr)
+{
+    X509_ATTRIBUTE *new;
+    VALUE obj;
+
+    if (!attr) {
+       new = X509_ATTRIBUTE_new();
+    } else {
+       new = X509_ATTRIBUTE_dup(attr);
+    }
+    if (!new) {
+       ossl_raise(eX509AttrError, NULL);
+    }
+    WrapX509Attr(cX509Attr, obj, new);
+
+    return obj;
+}
+
+X509_ATTRIBUTE *
+DupX509AttrPtr(VALUE obj)
+{
+    X509_ATTRIBUTE *attr, *new;
+
+    SafeGetX509Attr(obj, attr);
+    if (!(new = X509_ATTRIBUTE_dup(attr))) {
+       ossl_raise(eX509AttrError, NULL);
+    }
+
+    return new;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_x509attr_alloc(VALUE klass)
+{
+    X509_ATTRIBUTE *attr;
+    VALUE obj;
+
+    if (!(attr = X509_ATTRIBUTE_new()))
+       ossl_raise(eX509AttrError, NULL);
+    WrapX509Attr(klass, obj, attr);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    Attribute.new(oid [, value]) => attr
+ */
+static VALUE
+ossl_x509attr_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE oid, value;
+    X509_ATTRIBUTE *attr, *x;
+    const unsigned char *p;
+
+    GetX509Attr(self, attr);
+    if(rb_scan_args(argc, argv, "11", &oid, &value) == 1){
+       oid = ossl_to_der_if_possible(oid);
+       StringValue(oid);
+       p = (unsigned char *)RSTRING_PTR(oid);
+       x = d2i_X509_ATTRIBUTE(&attr, &p, RSTRING_LEN(oid));
+       DATA_PTR(self) = attr;
+       if(!x){
+           ossl_raise(eX509AttrError, NULL);
+       }
+       return self;
+    }
+    rb_funcall(self, rb_intern("oid="), 1, oid);
+    rb_funcall(self, rb_intern("value="), 1, value);
+
+    return self;
+}
+
+/*
+ * call-seq:
+ *    attr.oid = string => string
+ */
+static VALUE
+ossl_x509attr_set_oid(VALUE self, VALUE oid)
+{
+    X509_ATTRIBUTE *attr;
+    ASN1_OBJECT *obj;
+    char *s;
+
+    s = StringValuePtr(oid);
+    obj = OBJ_txt2obj(s, 0);
+    if(!obj) obj = OBJ_txt2obj(s, 1);
+    if(!obj) ossl_raise(eX509AttrError, NULL);
+    GetX509Attr(self, attr);
+    X509_ATTRIBUTE_set1_object(attr, obj);
+
+    return oid;
+}
+
+/*
+ * call-seq:
+ *    attr.oid => string
+ */
+static VALUE
+ossl_x509attr_get_oid(VALUE self)
+{
+    X509_ATTRIBUTE *attr;
+    ASN1_OBJECT *oid;
+    BIO *out;
+    VALUE ret;
+    int nid;
+
+    GetX509Attr(self, attr);
+    oid = X509_ATTRIBUTE_get0_object(attr);
+    if ((nid = OBJ_obj2nid(oid)) != NID_undef)
+       ret = rb_str_new2(OBJ_nid2sn(nid));
+    else{
+       if (!(out = BIO_new(BIO_s_mem())))
+           ossl_raise(eX509AttrError, NULL);
+       i2a_ASN1_OBJECT(out, oid);
+       ret = ossl_membio2str(out);
+    }
+
+    return ret;
+}
+
+#if defined(HAVE_ST_X509_ATTRIBUTE_SINGLE) || defined(HAVE_ST_SINGLE)
+#  define OSSL_X509ATTR_IS_SINGLE(attr)  ((attr)->single)
+#  define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->single = 1)
+#else
+#  define OSSL_X509ATTR_IS_SINGLE(attr)  (!(attr)->set)
+#  define OSSL_X509ATTR_SET_SINGLE(attr) ((attr)->set = 0)
+#endif
+
+/*
+ * call-seq:
+ *    attr.value = asn1 => asn1
+ */
+static VALUE
+ossl_x509attr_set_value(VALUE self, VALUE value)
+{
+    X509_ATTRIBUTE *attr;
+    ASN1_TYPE *a1type;
+
+    if(!(a1type = ossl_asn1_get_asn1type(value)))
+       ossl_raise(eASN1Error, "could not get ASN1_TYPE");
+    if(ASN1_TYPE_get(a1type) == V_ASN1_SEQUENCE){
+       ASN1_TYPE_free(a1type);
+       ossl_raise(eASN1Error, "couldn't set SEQUENCE for attribute value.");
+    }
+    GetX509Attr(self, attr);
+    if(attr->value.set){
+       if(OSSL_X509ATTR_IS_SINGLE(attr)) ASN1_TYPE_free(attr->value.single);
+       else sk_ASN1_TYPE_free(attr->value.set);
+    }
+    OSSL_X509ATTR_SET_SINGLE(attr);
+    attr->value.single = a1type;
+
+    return value;
+}
+
+/*
+ * call-seq:
+ *    attr.value => asn1
+ */
+static VALUE
+ossl_x509attr_get_value(VALUE self)
+{
+    X509_ATTRIBUTE *attr;
+    VALUE str, asn1;
+    long length;
+    unsigned char *p;
+
+    GetX509Attr(self, attr);
+    if(attr->value.ptr == NULL) return Qnil;
+    if(OSSL_X509ATTR_IS_SINGLE(attr)){
+       length = i2d_ASN1_TYPE(attr->value.single, NULL);
+       str = rb_str_new(0, length);
+       p = (unsigned char *)RSTRING_PTR(str);
+       i2d_ASN1_TYPE(attr->value.single, &p);
+       ossl_str_adjust(str, p);
+    }
+    else{
+       length = i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set,
+                       (unsigned char **) NULL, i2d_ASN1_TYPE,
+                       V_ASN1_SET, V_ASN1_UNIVERSAL, 0);
+       str = rb_str_new(0, length);
+       p = (unsigned char *)RSTRING_PTR(str);
+       i2d_ASN1_SET_OF_ASN1_TYPE(attr->value.set, &p,
+                       i2d_ASN1_TYPE, V_ASN1_SET, V_ASN1_UNIVERSAL, 0);
+       ossl_str_adjust(str, p);
+    }
+    asn1 = rb_funcall(mASN1, rb_intern("decode"), 1, str);
+
+    return asn1;
+}
+
+/*
+ * call-seq:
+ *    attr.to_der => string
+ */
+static VALUE
+ossl_x509attr_to_der(VALUE self)
+{
+    X509_ATTRIBUTE *attr;
+    VALUE str;
+    int len;
+    unsigned char *p;
+
+    GetX509Attr(self, attr);
+    if((len = i2d_X509_ATTRIBUTE(attr, NULL)) <= 0)
+       ossl_raise(eX509AttrError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_X509_ATTRIBUTE(attr, &p) <= 0)
+       ossl_raise(eX509AttrError, NULL);
+    rb_str_set_len(str, p - (unsigned char*)RSTRING_PTR(str));
+
+    return str;
+}
+
+/*
+ * X509_ATTRIBUTE init
+ */
+void
+Init_ossl_x509attr()
+{
+    eX509AttrError = rb_define_class_under(mX509, "AttributeError", eOSSLError);
+
+    cX509Attr = rb_define_class_under(mX509, "Attribute", rb_cObject);
+    rb_define_alloc_func(cX509Attr, ossl_x509attr_alloc);
+    rb_define_method(cX509Attr, "initialize", ossl_x509attr_initialize, -1);
+    rb_define_method(cX509Attr, "oid=", ossl_x509attr_set_oid, 1);
+    rb_define_method(cX509Attr, "oid", ossl_x509attr_get_oid, 0);
+    rb_define_method(cX509Attr, "value=", ossl_x509attr_set_value, 1);
+    rb_define_method(cX509Attr, "value", ossl_x509attr_get_value, 0);
+    rb_define_method(cX509Attr, "to_der", ossl_x509attr_to_der, 0);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509cert.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509cert.c
new file mode 100644 (file)
index 0000000..80a0b76
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509(klass, obj, x509) do { \
+    if (!(x509)) { \
+       ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_free, (x509)); \
+} while (0)
+#define GetX509(obj, x509) do { \
+    Data_Get_Struct((obj), X509, (x509)); \
+    if (!(x509)) { \
+       ossl_raise(rb_eRuntimeError, "CERT wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetX509(obj, x509) do { \
+    OSSL_Check_Kind((obj), cX509Cert); \
+    GetX509((obj), (x509)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Cert;
+VALUE eX509CertError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509_new(X509 *x509)
+{
+    X509 *new;
+    VALUE obj;
+
+    if (!x509) {
+       new = X509_new();
+    } else {
+       new = X509_dup(x509);
+    }
+    if (!new) {
+       ossl_raise(eX509CertError, NULL);
+    }
+    WrapX509(cX509Cert, obj, new);
+
+    return obj;
+}
+
+VALUE
+ossl_x509_new_from_file(VALUE filename)
+{
+    X509 *x509;
+    FILE *fp;
+    VALUE obj;
+
+    SafeStringValue(filename);
+    if (!(fp = fopen(RSTRING_PTR(filename), "r"))) {
+       ossl_raise(eX509CertError, "%s", strerror(errno));
+    }
+    x509 = PEM_read_X509(fp, NULL, NULL, NULL);
+    /*
+     * prepare for DER...
+#if !defined(OPENSSL_NO_FP_API)
+    if (!x509) {
+       (void)ERR_get_error();
+       rewind(fp);
+
+       x509 = d2i_X509_fp(fp, NULL);
+    }
+#endif
+    */
+    fclose(fp);
+    if (!x509) {
+       ossl_raise(eX509CertError, NULL);
+    }
+    WrapX509(cX509Cert, obj, x509);
+
+    return obj;
+}
+
+X509 *
+GetX509CertPtr(VALUE obj)
+{
+    X509 *x509;
+
+    SafeGetX509(obj, x509);
+
+    return x509;
+}
+
+X509 *
+DupX509CertPtr(VALUE obj)
+{
+    X509 *x509;
+
+    SafeGetX509(obj, x509);
+
+    CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509);
+
+    return x509;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_x509_alloc(VALUE klass)
+{
+    X509 *x509;
+    VALUE obj;
+
+    x509 = X509_new();
+    if (!x509) ossl_raise(eX509CertError, NULL);
+
+    WrapX509(klass, obj, x509);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    Certificate.new => cert
+ *    Certificate.new(string) => cert
+ */
+static VALUE
+ossl_x509_initialize(int argc, VALUE *argv, VALUE self)
+{
+    BIO *in;
+    X509 *x509, *x = DATA_PTR(self);
+    VALUE arg;
+
+    if (rb_scan_args(argc, argv, "01", &arg) == 0) {
+       /* create just empty X509Cert */
+       return self;
+    }
+    arg = ossl_to_der_if_possible(arg);
+    in = ossl_obj2bio(arg);
+    x509 = PEM_read_bio_X509(in, &x, NULL, NULL);
+    DATA_PTR(self) = x;
+    if (!x509) {
+       OSSL_BIO_reset(in);
+       x509 = d2i_X509_bio(in, &x);
+       DATA_PTR(self) = x;
+    }
+    BIO_free(in);
+    if (!x509) ossl_raise(eX509CertError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_x509_copy(VALUE self, VALUE other)
+{
+    X509 *a, *b, *x509;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+
+    GetX509(self, a);
+    SafeGetX509(other, b);
+
+    x509 = X509_dup(b);
+    if (!x509) ossl_raise(eX509CertError, NULL);
+
+    DATA_PTR(self) = x509;
+    X509_free(a);
+
+    return self;
+}
+
+/*
+ * call-seq:
+ *    cert.to_der => string
+ */
+static VALUE
+ossl_x509_to_der(VALUE self)
+{
+    X509 *x509;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetX509(self, x509);
+    if ((len = i2d_X509(x509, NULL)) <= 0)
+       ossl_raise(eX509CertError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if (i2d_X509(x509, &p) <= 0)
+       ossl_raise(eX509CertError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    cert.to_pem => string
+ */
+static VALUE
+ossl_x509_to_pem(VALUE self)
+{
+    X509 *x509;
+    BIO *out;
+    VALUE str;
+
+    GetX509(self, x509);
+    out = BIO_new(BIO_s_mem());
+    if (!out) ossl_raise(eX509CertError, NULL);
+
+    if (!PEM_write_bio_X509(out, x509)) {
+       BIO_free(out);
+       ossl_raise(eX509CertError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    cert.to_text => string
+ */
+static VALUE
+ossl_x509_to_text(VALUE self)
+{
+    X509 *x509;
+    BIO *out;
+    VALUE str;
+
+    GetX509(self, x509);
+
+    out = BIO_new(BIO_s_mem());
+    if (!out) ossl_raise(eX509CertError, NULL);
+
+    if (!X509_print(out, x509)) {
+       BIO_free(out);
+       ossl_raise(eX509CertError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+#if 0
+/*
+ * Makes from X509 X509_REQuest
+ */
+static VALUE
+ossl_x509_to_req(VALUE self)
+{
+    X509 *x509;
+    X509_REQ *req;
+    VALUE obj;
+
+    GetX509(self, x509);
+    if (!(req = X509_to_X509_REQ(x509, NULL, EVP_md5()))) {
+       ossl_raise(eX509CertError, NULL);
+    }
+    obj = ossl_x509req_new(req);
+    X509_REQ_free(req);
+
+    return obj;
+}
+#endif
+
+/*
+ * call-seq:
+ *    cert.version => integer
+ */
+static VALUE
+ossl_x509_get_version(VALUE self)
+{
+    X509 *x509;
+
+    GetX509(self, x509);
+
+    return LONG2NUM(X509_get_version(x509));
+}
+
+/*
+ * call-seq:
+ *    cert.version = integer => integer
+ */
+static VALUE
+ossl_x509_set_version(VALUE self, VALUE version)
+{
+    X509 *x509;
+    long ver;
+
+    if ((ver = NUM2LONG(version)) < 0) {
+       ossl_raise(eX509CertError, "version must be >= 0!");
+    }
+    GetX509(self, x509);
+    if (!X509_set_version(x509, ver)) {
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return version;
+}
+
+/*
+ * call-seq:
+ *    cert.serial => integer
+ */
+static VALUE
+ossl_x509_get_serial(VALUE self)
+{
+    X509 *x509;
+
+    GetX509(self, x509);
+
+    return asn1integer_to_num(X509_get_serialNumber(x509));
+}
+
+/*
+ * call-seq:
+ *    cert.serial = integer => integer
+ */
+static VALUE
+ossl_x509_set_serial(VALUE self, VALUE num)
+{
+    X509 *x509;
+
+    GetX509(self, x509);
+
+    x509->cert_info->serialNumber =
+       num_to_asn1integer(num, X509_get_serialNumber(x509));
+
+    return num;
+}
+
+/*
+ * call-seq:
+ *    cert.signature_algorithm => string
+ */
+static VALUE
+ossl_x509_get_signature_algorithm(VALUE self)
+{
+    X509 *x509;
+    BIO *out;
+    VALUE str;
+
+    GetX509(self, x509);
+    out = BIO_new(BIO_s_mem());
+    if (!out) ossl_raise(eX509CertError, NULL);
+
+    if (!i2a_ASN1_OBJECT(out, x509->cert_info->signature->algorithm)) {
+       BIO_free(out);
+       ossl_raise(eX509CertError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    cert.subject => name
+ */
+static VALUE
+ossl_x509_get_subject(VALUE self)
+{
+    X509 *x509;
+    X509_NAME *name;
+
+    GetX509(self, x509);
+    if (!(name = X509_get_subject_name(x509))) { /* NO DUP - don't free! */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return ossl_x509name_new(name);
+}
+
+/*
+ * call-seq:
+ *    cert.subject = name => name
+ */
+static VALUE
+ossl_x509_set_subject(VALUE self, VALUE subject)
+{
+    X509 *x509;
+
+    GetX509(self, x509);
+    if (!X509_set_subject_name(x509, GetX509NamePtr(subject))) { /* DUPs name */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return subject;
+}
+
+/*
+ * call-seq:
+ *    cert.issuer => name
+ */
+static VALUE
+ossl_x509_get_issuer(VALUE self)
+{
+    X509 *x509;
+    X509_NAME *name;
+
+    GetX509(self, x509);
+    if(!(name = X509_get_issuer_name(x509))) { /* NO DUP - don't free! */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return ossl_x509name_new(name);
+}
+
+/*
+ * call-seq:
+ *    cert.issuer = name => name
+ */
+static VALUE
+ossl_x509_set_issuer(VALUE self, VALUE issuer)
+{
+    X509 *x509;
+
+    GetX509(self, x509);
+    if (!X509_set_issuer_name(x509, GetX509NamePtr(issuer))) { /* DUPs name */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return issuer;
+}
+
+/*
+ * call-seq:
+ *    cert.not_before => time
+ */
+static VALUE
+ossl_x509_get_not_before(VALUE self)
+{
+    X509 *x509;
+    ASN1_UTCTIME *asn1time;
+
+    GetX509(self, x509);
+    if (!(asn1time = X509_get_notBefore(x509))) { /* NO DUP - don't free! */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return asn1time_to_time(asn1time);
+}
+
+/*
+ * call-seq:
+ *    cert.not_before = time => time
+ */
+static VALUE
+ossl_x509_set_not_before(VALUE self, VALUE time)
+{
+    X509 *x509;
+    time_t sec;
+
+    sec = time_to_time_t(time);
+    GetX509(self, x509);
+    if (!X509_time_adj(X509_get_notBefore(x509), 0, &sec)) {
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return time;
+}
+
+/*
+ * call-seq:
+ *    cert.not_after => time
+ */
+static VALUE
+ossl_x509_get_not_after(VALUE self)
+{
+    X509 *x509;
+    ASN1_TIME *asn1time;
+
+    GetX509(self, x509);
+    if (!(asn1time = X509_get_notAfter(x509))) { /* NO DUP - don't free! */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return asn1time_to_time(asn1time);
+}
+
+/*
+ * call-seq:
+ *    cert.not_after = time => time
+ */
+static VALUE
+ossl_x509_set_not_after(VALUE self, VALUE time)
+{
+    X509 *x509;
+    time_t sec;
+
+    sec = time_to_time_t(time);
+    GetX509(self, x509);
+    if (!X509_time_adj(X509_get_notAfter(x509), 0, &sec)) {
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return time;
+}
+
+/*
+ * call-seq:
+ *    cert.public_key => key
+ */
+static VALUE
+ossl_x509_get_public_key(VALUE self)
+{
+    X509 *x509;
+    EVP_PKEY *pkey;
+
+    GetX509(self, x509);
+    if (!(pkey = X509_get_pubkey(x509))) { /* adds an reference */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return ossl_pkey_new(pkey); /* NO DUP - OK */
+}
+
+/*
+ * call-seq:
+ *    cert.public_key = key => key
+ */
+static VALUE
+ossl_x509_set_public_key(VALUE self, VALUE key)
+{
+    X509 *x509;
+
+    GetX509(self, x509);
+    if (!X509_set_pubkey(x509, GetPKeyPtr(key))) { /* DUPs pkey */
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return key;
+}
+
+/*
+ * call-seq:
+ *    cert.sign(key, digest) => self
+ */
+static VALUE
+ossl_x509_sign(VALUE self, VALUE key, VALUE digest)
+{
+    X509 *x509;
+    EVP_PKEY *pkey;
+    const EVP_MD *md;
+
+    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
+    md = GetDigestPtr(digest);
+    GetX509(self, x509);
+    if (!X509_sign(x509, pkey, md)) {
+       ossl_raise(eX509CertError, NULL);
+    }
+
+    return self;
+}
+
+/*
+ * call-seq:
+ *    cert.verify(key) => true | false
+ *
+ * Checks that cert signature is made with PRIVversion of this PUBLIC 'key'
+ */
+static VALUE
+ossl_x509_verify(VALUE self, VALUE key)
+{
+    X509 *x509;
+    EVP_PKEY *pkey;
+    int i;
+
+    pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
+    GetX509(self, x509);
+    if ((i = X509_verify(x509, pkey)) < 0) {
+       ossl_raise(eX509CertError, NULL);
+    }
+    if (i > 0) {
+       return Qtrue;
+    }
+
+    return Qfalse;
+}
+
+/*
+ * call-seq:
+ *    cert.check_private_key(key)
+ *
+ * Checks if 'key' is PRIV key for this cert
+ */
+static VALUE
+ossl_x509_check_private_key(VALUE self, VALUE key)
+{
+    X509 *x509;
+    EVP_PKEY *pkey;
+
+    /* not needed private key, but should be */
+    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
+    GetX509(self, x509);
+    if (!X509_check_private_key(x509, pkey)) {
+       OSSL_Warning("Check private key:%s", OSSL_ErrMsg());
+       return Qfalse;
+    }
+
+    return Qtrue;
+}
+
+/*
+ * call-seq:
+ *    cert.extensions => [extension...]
+ */
+static VALUE
+ossl_x509_get_extensions(VALUE self)
+{
+    X509 *x509;
+    int count, i;
+    X509_EXTENSION *ext;
+    VALUE ary;
+
+    GetX509(self, x509);
+    count = X509_get_ext_count(x509);
+    if (count < 0) {
+       return rb_ary_new();
+    }
+    ary = rb_ary_new2(count);
+    for (i=0; i<count; i++) {
+       ext = X509_get_ext(x509, i); /* NO DUP - don't free! */
+       rb_ary_push(ary, ossl_x509ext_new(ext));
+    }
+
+    return ary;
+}
+
+/*
+ * call-seq:
+ *    cert.extensions = [ext...] => [ext...]
+ */
+static VALUE
+ossl_x509_set_extensions(VALUE self, VALUE ary)
+{
+    X509 *x509;
+    X509_EXTENSION *ext;
+    int i;
+
+    Check_Type(ary, T_ARRAY);
+    /* All ary's members should be X509Extension */
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
+    }
+    GetX509(self, x509);
+    sk_X509_EXTENSION_pop_free(x509->cert_info->extensions, X509_EXTENSION_free);
+    x509->cert_info->extensions = NULL;
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
+
+       if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
+           X509_EXTENSION_free(ext);
+           ossl_raise(eX509CertError, NULL);
+       }
+       X509_EXTENSION_free(ext);
+    }
+
+    return ary;
+}
+
+/*
+ * call-seq:
+ *    cert.add_extension(extension) => extension
+ */
+static VALUE
+ossl_x509_add_extension(VALUE self, VALUE extension)
+{
+    X509 *x509;
+    X509_EXTENSION *ext;
+
+    GetX509(self, x509);
+    ext = DupX509ExtPtr(extension);
+    if (!X509_add_ext(x509, ext, -1)) { /* DUPs ext - FREE it */
+       X509_EXTENSION_free(ext);
+       ossl_raise(eX509CertError, NULL);
+    }
+    X509_EXTENSION_free(ext);
+
+    return extension;
+}
+
+static VALUE
+ossl_x509_inspect(VALUE self)
+{
+    VALUE subject = rb_inspect(ossl_x509_get_subject(self));
+    VALUE issuer = rb_inspect(ossl_x509_get_issuer(self));
+    VALUE serial = rb_inspect(ossl_x509_get_serial(self));
+    VALUE not_before = rb_inspect(ossl_x509_get_not_before(self));
+    VALUE not_after = rb_inspect(ossl_x509_get_not_after(self));
+    return rb_sprintf("#<%"PRIsVALUE": subject=%"PRIsVALUE", "
+                     "issuer=%"PRIsVALUE", serial=%"PRIsVALUE", "
+                     "not_before=%"PRIsVALUE", not_after=%"PRIsVALUE">",
+                     RB_OBJ_CLASSNAME(self),
+                     RB_OBJ_STRING(subject),
+                     RB_OBJ_STRING(issuer),
+                     RB_OBJ_STRING(serial),
+                     RB_OBJ_STRING(not_before),
+                     RB_OBJ_STRING(not_after));
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509cert()
+{
+
+#if 0
+    mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
+    mX509 = rb_define_module_under(mOSSL, "X509");
+#endif
+
+    eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError);
+
+    /* Document-class: OpenSSL::X509::Certificate
+     *
+     * Implementation of an X.509 certificate as specified in RFC 5280.
+     * Provides access to a certificate's attributes and allows certificates
+     * to be read from a string, but also supports the creation of new
+     * certificates from scratch.
+     *
+     * === Reading a certificate from a file
+     *
+     * Certificate is capable of handling DER-encoded certificates and
+     * certificates encoded in OpenSSL's PEM format.
+     *
+     *   raw = File.read "cert.cer" # DER- or PEM-encoded
+     *   certificate = OpenSSL::X509::Certificate.new raw
+     *
+     * === Saving a certificate to a file
+     *
+     * A certificate may be encoded in DER format
+     *
+     *   cert = ...
+     *   File.open("cert.cer", "wb") { |f| f.print cert.to_der }
+     *
+     * or in PEM format
+     *
+     *   cert = ...
+     *   File.open("cert.pem", "wb") { |f| f.print cert.to_pem }
+     *
+     * X.509 certificates are associated with a private/public key pair,
+     * typically a RSA, DSA or ECC key (see also OpenSSL::PKey::RSA,
+     * OpenSSL::PKey::DSA and OpenSSL::PKey::EC), the public key itself is
+     * stored within the certificate and can be accessed in form of an
+     * OpenSSL::PKey. Certificates are typically used to be able to associate
+     * some form of identity with a key pair, for example web servers serving
+     * pages over HTTPs use certificates to authenticate themselves to the user.
+     *
+     * The public key infrastructure (PKI) model relies on trusted certificate
+     * authorities ("root CAs") that issue these certificates, so that end
+     * users need to base their trust just on a selected few authorities
+     * that themselves again vouch for subordinate CAs issuing their
+     * certificates to end users.
+     *
+     * The OpenSSL::X509 module provides the tools to set up an independent
+     * PKI, similar to scenarios where the 'openssl' command line tool is
+     * used for issuing certificates in a private PKI.
+     *
+     * === Creating a root CA certificate and an end-entity certificate
+     *
+     * First, we need to create a "self-signed" root certificate. To do so,
+     * we need to generate a key first. Please note that the choice of "1"
+     * as a serial number is considered a security flaw for real certificates.
+     * Secure choices are integers in the two-digit byte range and ideally
+     * not sequential but secure random numbers, steps omitted here to keep
+     * the example concise.
+     *
+     *   root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key
+     *   root_ca = OpenSSL::X509::Certificate.new
+     *   root_ca.version = 2 # cf. RFC 5280 - to make it a "v3" certificate
+     *   root_ca.serial = 1
+     *   root_ca.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby CA"
+     *   root_ca.issuer = root_ca.subject # root CA's are "self-signed"
+     *   root_ca.public_key = root_key.public_key
+     *   root_ca.not_before = Time.now
+     *   root_ca.not_after = root_ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity
+     *   ef = OpenSSL::X509::ExtensionFactory.new
+     *   ef.subject_certificate = root_ca
+     *   ef.issuer_certificate = root_ca
+     *   root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
+     *   root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
+     *   root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
+     *   root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
+     *   root_ca.sign(root_key, OpenSSL::Digest::SHA256.new)
+     *
+     * The next step is to create the end-entity certificate using the root CA
+     * certificate.
+     *
+     *   key = OpenSSL::PKey::RSA.new 2048
+     *   cert = OpenSSL::X509::Certificate.new
+     *   cert.version = 2
+     *   cert.serial = 2
+     *   cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby certificate"
+     *   cert.issuer = root_ca.subject # root CA is the issuer
+     *   cert.public_key = key.public_key
+     *   cert.not_before = Time.now
+     *   cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 # 1 years validity
+     *   ef = OpenSSL::X509::ExtensionFactory.new
+     *   ef.subject_certificate = cert
+     *   ef.issuer_certificate = root_ca
+     *   cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true))
+     *   cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
+     *   cert.sign(root_key, OpenSSL::Digest::SHA256.new)
+     *
+     */
+
+    eX509CertError = rb_define_class_under(mX509, "CertificateError", eOSSLError);
+
+    cX509Cert = rb_define_class_under(mX509, "Certificate", rb_cObject);
+
+    rb_define_alloc_func(cX509Cert, ossl_x509_alloc);
+    rb_define_method(cX509Cert, "initialize", ossl_x509_initialize, -1);
+    rb_define_copy_func(cX509Cert, ossl_x509_copy);
+
+    rb_define_method(cX509Cert, "to_der", ossl_x509_to_der, 0);
+    rb_define_method(cX509Cert, "to_pem", ossl_x509_to_pem, 0);
+    rb_define_alias(cX509Cert, "to_s", "to_pem");
+    rb_define_method(cX509Cert, "to_text", ossl_x509_to_text, 0);
+    rb_define_method(cX509Cert, "version", ossl_x509_get_version, 0);
+    rb_define_method(cX509Cert, "version=", ossl_x509_set_version, 1);
+    rb_define_method(cX509Cert, "signature_algorithm", ossl_x509_get_signature_algorithm, 0);
+    rb_define_method(cX509Cert, "serial", ossl_x509_get_serial, 0);
+    rb_define_method(cX509Cert, "serial=", ossl_x509_set_serial, 1);
+    rb_define_method(cX509Cert, "subject", ossl_x509_get_subject, 0);
+    rb_define_method(cX509Cert, "subject=", ossl_x509_set_subject, 1);
+    rb_define_method(cX509Cert, "issuer", ossl_x509_get_issuer, 0);
+    rb_define_method(cX509Cert, "issuer=", ossl_x509_set_issuer, 1);
+    rb_define_method(cX509Cert, "not_before", ossl_x509_get_not_before, 0);
+    rb_define_method(cX509Cert, "not_before=", ossl_x509_set_not_before, 1);
+    rb_define_method(cX509Cert, "not_after", ossl_x509_get_not_after, 0);
+    rb_define_method(cX509Cert, "not_after=", ossl_x509_set_not_after, 1);
+    rb_define_method(cX509Cert, "public_key", ossl_x509_get_public_key, 0);
+    rb_define_method(cX509Cert, "public_key=", ossl_x509_set_public_key, 1);
+    rb_define_method(cX509Cert, "sign", ossl_x509_sign, 2);
+    rb_define_method(cX509Cert, "verify", ossl_x509_verify, 1);
+    rb_define_method(cX509Cert, "check_private_key", ossl_x509_check_private_key, 1);
+    rb_define_method(cX509Cert, "extensions", ossl_x509_get_extensions, 0);
+    rb_define_method(cX509Cert, "extensions=", ossl_x509_set_extensions, 1);
+    rb_define_method(cX509Cert, "add_extension", ossl_x509_add_extension, 1);
+    rb_define_method(cX509Cert, "inspect", ossl_x509_inspect, 0);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509crl.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509crl.c
new file mode 100644 (file)
index 0000000..dec13c8
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509CRL(klass, obj, crl) do { \
+    if (!(crl)) { \
+       ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_CRL_free, (crl)); \
+} while (0)
+#define GetX509CRL(obj, crl) do { \
+    Data_Get_Struct((obj), X509_CRL, (crl)); \
+    if (!(crl)) { \
+       ossl_raise(rb_eRuntimeError, "CRL wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetX509CRL(obj, crl) do { \
+    OSSL_Check_Kind((obj), cX509CRL); \
+    GetX509CRL((obj), (crl)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509CRL;
+VALUE eX509CRLError;
+
+/*
+ * PUBLIC
+ */
+X509_CRL *
+GetX509CRLPtr(VALUE obj)
+{
+    X509_CRL *crl;
+
+    SafeGetX509CRL(obj, crl);
+
+    return crl;
+}
+
+X509_CRL *
+DupX509CRLPtr(VALUE obj)
+{
+    X509_CRL *crl;
+
+    SafeGetX509CRL(obj, crl);
+    CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
+
+    return crl;
+}
+
+VALUE
+ossl_x509crl_new(X509_CRL *crl)
+{
+    X509_CRL *tmp;
+    VALUE obj;
+
+    tmp = crl ? X509_CRL_dup(crl) : X509_CRL_new();
+    if(!tmp) ossl_raise(eX509CRLError, NULL);
+    WrapX509CRL(cX509CRL, obj, tmp);
+
+    return obj;
+}
+
+/*
+ * PRIVATE
+ */
+static VALUE
+ossl_x509crl_alloc(VALUE klass)
+{
+    X509_CRL *crl;
+    VALUE obj;
+
+    if (!(crl = X509_CRL_new())) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+    WrapX509CRL(klass, obj, crl);
+
+    return obj;
+}
+
+static VALUE
+ossl_x509crl_initialize(int argc, VALUE *argv, VALUE self)
+{
+    BIO *in;
+    X509_CRL *crl, *x = DATA_PTR(self);
+    VALUE arg;
+
+    if (rb_scan_args(argc, argv, "01", &arg) == 0) {
+       return self;
+    }
+    arg = ossl_to_der_if_possible(arg);
+    in = ossl_obj2bio(arg);
+    crl = PEM_read_bio_X509_CRL(in, &x, NULL, NULL);
+    DATA_PTR(self) = x;
+    if (!crl) {
+       OSSL_BIO_reset(in);
+       crl = d2i_X509_CRL_bio(in, &x);
+       DATA_PTR(self) = x;
+    }
+    BIO_free(in);
+    if (!crl) ossl_raise(eX509CRLError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_x509crl_copy(VALUE self, VALUE other)
+{
+    X509_CRL *a, *b, *crl;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+    GetX509CRL(self, a);
+    SafeGetX509CRL(other, b);
+    if (!(crl = X509_CRL_dup(b))) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+    X509_CRL_free(a);
+    DATA_PTR(self) = crl;
+
+    return self;
+}
+
+static VALUE
+ossl_x509crl_get_version(VALUE self)
+{
+    X509_CRL *crl;
+    long ver;
+
+    GetX509CRL(self, crl);
+    ver = X509_CRL_get_version(crl);
+
+    return LONG2NUM(ver);
+}
+
+static VALUE
+ossl_x509crl_set_version(VALUE self, VALUE version)
+{
+    X509_CRL *crl;
+    long ver;
+
+    if ((ver = NUM2LONG(version)) < 0) {
+       ossl_raise(eX509CRLError, "version must be >= 0!");
+    }
+    GetX509CRL(self, crl);
+    if (!X509_CRL_set_version(crl, ver)) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+
+    return version;
+}
+
+static VALUE
+ossl_x509crl_get_signature_algorithm(VALUE self)
+{
+    X509_CRL *crl;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetX509CRL(self, crl);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+    if (!i2a_ASN1_OBJECT(out, crl->sig_alg->algorithm)) {
+       BIO_free(out);
+       ossl_raise(eX509CRLError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+    return str;
+}
+
+static VALUE
+ossl_x509crl_get_issuer(VALUE self)
+{
+    X509_CRL *crl;
+
+    GetX509CRL(self, crl);
+
+    return ossl_x509name_new(X509_CRL_get_issuer(crl)); /* NO DUP - don't free */
+}
+
+static VALUE
+ossl_x509crl_set_issuer(VALUE self, VALUE issuer)
+{
+    X509_CRL *crl;
+
+    GetX509CRL(self, crl);
+
+    if (!X509_CRL_set_issuer_name(crl, GetX509NamePtr(issuer))) { /* DUPs name */
+       ossl_raise(eX509CRLError, NULL);
+    }
+    return issuer;
+}
+
+static VALUE
+ossl_x509crl_get_last_update(VALUE self)
+{
+    X509_CRL *crl;
+
+    GetX509CRL(self, crl);
+
+    return asn1time_to_time(X509_CRL_get_lastUpdate(crl));
+}
+
+static VALUE
+ossl_x509crl_set_last_update(VALUE self, VALUE time)
+{
+    X509_CRL *crl;
+    time_t sec;
+
+    sec = time_to_time_t(time);
+    GetX509CRL(self, crl);
+    if (!X509_time_adj(crl->crl->lastUpdate, 0, &sec)) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+
+    return time;
+}
+
+static VALUE
+ossl_x509crl_get_next_update(VALUE self)
+{
+    X509_CRL *crl;
+
+    GetX509CRL(self, crl);
+
+    return asn1time_to_time(X509_CRL_get_nextUpdate(crl));
+}
+
+static VALUE
+ossl_x509crl_set_next_update(VALUE self, VALUE time)
+{
+    X509_CRL *crl;
+    time_t sec;
+
+    sec = time_to_time_t(time);
+    GetX509CRL(self, crl);
+    /* This must be some thinko in OpenSSL */
+    if (!(crl->crl->nextUpdate = X509_time_adj(crl->crl->nextUpdate, 0, &sec))){
+       ossl_raise(eX509CRLError, NULL);
+    }
+
+    return time;
+}
+
+static VALUE
+ossl_x509crl_get_revoked(VALUE self)
+{
+    X509_CRL *crl;
+    int i, num;
+    X509_REVOKED *rev;
+    VALUE ary, revoked;
+
+    GetX509CRL(self, crl);
+    num = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+    if (num < 0) {
+       OSSL_Debug("num < 0???");
+       return rb_ary_new();
+    }
+    ary = rb_ary_new2(num);
+    for(i=0; i<num; i++) {
+       /* NO DUP - don't free! */
+       rev = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+       revoked = ossl_x509revoked_new(rev);
+       rb_ary_push(ary, revoked);
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_x509crl_set_revoked(VALUE self, VALUE ary)
+{
+    X509_CRL *crl;
+    X509_REVOKED *rev;
+    int i;
+
+    Check_Type(ary, T_ARRAY);
+    /* All ary members should be X509 Revoked */
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Rev);
+    }
+    GetX509CRL(self, crl);
+    sk_X509_REVOKED_pop_free(crl->crl->revoked, X509_REVOKED_free);
+    crl->crl->revoked = NULL;
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       rev = DupX509RevokedPtr(RARRAY_PTR(ary)[i]);
+       if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
+           ossl_raise(eX509CRLError, NULL);
+       }
+    }
+    X509_CRL_sort(crl);
+
+    return ary;
+}
+
+static VALUE
+ossl_x509crl_add_revoked(VALUE self, VALUE revoked)
+{
+    X509_CRL *crl;
+    X509_REVOKED *rev;
+
+    GetX509CRL(self, crl);
+    rev = DupX509RevokedPtr(revoked);
+    if (!X509_CRL_add0_revoked(crl, rev)) { /* NO DUP - don't free! */
+       ossl_raise(eX509CRLError, NULL);
+    }
+    X509_CRL_sort(crl);
+
+    return revoked;
+}
+
+static VALUE
+ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest)
+{
+    X509_CRL *crl;
+    EVP_PKEY *pkey;
+    const EVP_MD *md;
+
+    GetX509CRL(self, crl);
+    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
+    md = GetDigestPtr(digest);
+    if (!X509_CRL_sign(crl, pkey, md)) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_x509crl_verify(VALUE self, VALUE key)
+{
+    X509_CRL *crl;
+    int ret;
+
+    GetX509CRL(self, crl);
+    if ((ret = X509_CRL_verify(crl, GetPKeyPtr(key))) < 0) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+    if (ret == 1) {
+       return Qtrue;
+    }
+
+    return Qfalse;
+}
+
+static VALUE
+ossl_x509crl_to_der(VALUE self)
+{
+    X509_CRL *crl;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetX509CRL(self, crl);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+    if (!i2d_X509_CRL_bio(out, crl)) {
+       BIO_free(out);
+       ossl_raise(eX509CRLError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+
+    return str;
+}
+
+static VALUE
+ossl_x509crl_to_pem(VALUE self)
+{
+    X509_CRL *crl;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetX509CRL(self, crl);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+    if (!PEM_write_bio_X509_CRL(out, crl)) {
+       BIO_free(out);
+       ossl_raise(eX509CRLError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+
+    return str;
+}
+
+static VALUE
+ossl_x509crl_to_text(VALUE self)
+{
+    X509_CRL *crl;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetX509CRL(self, crl);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eX509CRLError, NULL);
+    }
+    if (!X509_CRL_print(out, crl)) {
+       BIO_free(out);
+       ossl_raise(eX509CRLError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+
+    return str;
+}
+
+/*
+ * Gets X509v3 extensions as array of X509Ext objects
+ */
+static VALUE
+ossl_x509crl_get_extensions(VALUE self)
+{
+    X509_CRL *crl;
+    int count, i;
+    X509_EXTENSION *ext;
+    VALUE ary;
+
+    GetX509CRL(self, crl);
+    count = X509_CRL_get_ext_count(crl);
+    if (count < 0) {
+       OSSL_Debug("count < 0???");
+       return rb_ary_new();
+    }
+    ary = rb_ary_new2(count);
+    for (i=0; i<count; i++) {
+       ext = X509_CRL_get_ext(crl, i); /* NO DUP - don't free! */
+       rb_ary_push(ary, ossl_x509ext_new(ext));
+    }
+
+    return ary;
+}
+
+/*
+ * Sets X509_EXTENSIONs
+ */
+static VALUE
+ossl_x509crl_set_extensions(VALUE self, VALUE ary)
+{
+    X509_CRL *crl;
+    X509_EXTENSION *ext;
+    int i;
+
+    Check_Type(ary, T_ARRAY);
+    /* All ary members should be X509 Extensions */
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
+    }
+    GetX509CRL(self, crl);
+    sk_X509_EXTENSION_pop_free(crl->crl->extensions, X509_EXTENSION_free);
+    crl->crl->extensions = NULL;
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       ext = DupX509ExtPtr(RARRAY_PTR(ary)[i]);
+       if(!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
+           X509_EXTENSION_free(ext);
+           ossl_raise(eX509CRLError, NULL);
+       }
+       X509_EXTENSION_free(ext);
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_x509crl_add_extension(VALUE self, VALUE extension)
+{
+    X509_CRL *crl;
+    X509_EXTENSION *ext;
+
+    GetX509CRL(self, crl);
+    ext = DupX509ExtPtr(extension);
+    if (!X509_CRL_add_ext(crl, ext, -1)) { /* DUPs ext - FREE it */
+       X509_EXTENSION_free(ext);
+       ossl_raise(eX509CRLError, NULL);
+    }
+    X509_EXTENSION_free(ext);
+
+    return extension;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509crl()
+{
+    eX509CRLError = rb_define_class_under(mX509, "CRLError", eOSSLError);
+
+    cX509CRL = rb_define_class_under(mX509, "CRL", rb_cObject);
+
+    rb_define_alloc_func(cX509CRL, ossl_x509crl_alloc);
+    rb_define_method(cX509CRL, "initialize", ossl_x509crl_initialize, -1);
+    rb_define_copy_func(cX509CRL, ossl_x509crl_copy);
+
+    rb_define_method(cX509CRL, "version", ossl_x509crl_get_version, 0);
+    rb_define_method(cX509CRL, "version=", ossl_x509crl_set_version, 1);
+    rb_define_method(cX509CRL, "signature_algorithm", ossl_x509crl_get_signature_algorithm, 0);
+    rb_define_method(cX509CRL, "issuer", ossl_x509crl_get_issuer, 0);
+    rb_define_method(cX509CRL, "issuer=", ossl_x509crl_set_issuer, 1);
+    rb_define_method(cX509CRL, "last_update", ossl_x509crl_get_last_update, 0);
+    rb_define_method(cX509CRL, "last_update=", ossl_x509crl_set_last_update, 1);
+    rb_define_method(cX509CRL, "next_update", ossl_x509crl_get_next_update, 0);
+    rb_define_method(cX509CRL, "next_update=", ossl_x509crl_set_next_update, 1);
+    rb_define_method(cX509CRL, "revoked", ossl_x509crl_get_revoked, 0);
+    rb_define_method(cX509CRL, "revoked=", ossl_x509crl_set_revoked, 1);
+    rb_define_method(cX509CRL, "add_revoked", ossl_x509crl_add_revoked, 1);
+    rb_define_method(cX509CRL, "sign", ossl_x509crl_sign, 2);
+    rb_define_method(cX509CRL, "verify", ossl_x509crl_verify, 1);
+    rb_define_method(cX509CRL, "to_der", ossl_x509crl_to_der, 0);
+    rb_define_method(cX509CRL, "to_pem", ossl_x509crl_to_pem, 0);
+    rb_define_alias(cX509CRL, "to_s", "to_pem");
+    rb_define_method(cX509CRL, "to_text", ossl_x509crl_to_text, 0);
+    rb_define_method(cX509CRL, "extensions", ossl_x509crl_get_extensions, 0);
+    rb_define_method(cX509CRL, "extensions=", ossl_x509crl_set_extensions, 1);
+    rb_define_method(cX509CRL, "add_extension", ossl_x509crl_add_extension, 1);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509ext.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509ext.c
new file mode 100644 (file)
index 0000000..bd2e1dd
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Ext(klass, obj, ext) do { \
+    if (!(ext)) { \
+       ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_EXTENSION_free, (ext)); \
+} while (0)
+#define GetX509Ext(obj, ext) do { \
+    Data_Get_Struct((obj), X509_EXTENSION, (ext)); \
+    if (!(ext)) { \
+       ossl_raise(rb_eRuntimeError, "EXT wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetX509Ext(obj, ext) do { \
+    OSSL_Check_Kind((obj), cX509Ext); \
+    GetX509Ext((obj), (ext)); \
+} while (0)
+#define MakeX509ExtFactory(klass, obj, ctx) do { \
+    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)); \
+} while (0)
+#define GetX509ExtFactory(obj, ctx) do { \
+    Data_Get_Struct((obj), X509V3_CTX, (ctx)); \
+    if (!(ctx)) { \
+       ossl_raise(rb_eRuntimeError, "CTX wasn't initialized!"); \
+    } \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Ext;
+VALUE cX509ExtFactory;
+VALUE eX509ExtError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509ext_new(X509_EXTENSION *ext)
+{
+    X509_EXTENSION *new;
+    VALUE obj;
+
+    if (!ext) {
+       new = X509_EXTENSION_new();
+    } else {
+       new = X509_EXTENSION_dup(ext);
+    }
+    if (!new) {
+       ossl_raise(eX509ExtError, NULL);
+    }
+    WrapX509Ext(cX509Ext, obj, new);
+
+    return obj;
+}
+
+X509_EXTENSION *
+GetX509ExtPtr(VALUE obj)
+{
+    X509_EXTENSION *ext;
+
+    SafeGetX509Ext(obj, ext);
+
+    return ext;
+}
+
+X509_EXTENSION *
+DupX509ExtPtr(VALUE obj)
+{
+    X509_EXTENSION *ext, *new;
+
+    SafeGetX509Ext(obj, ext);
+    if (!(new = X509_EXTENSION_dup(ext))) {
+       ossl_raise(eX509ExtError, NULL);
+    }
+
+    return new;
+}
+
+/*
+ * Private
+ */
+/*
+ * Ext factory
+ */
+static void
+ossl_x509extfactory_free(X509V3_CTX *ctx)
+{
+    OPENSSL_free(ctx);
+}
+
+static VALUE
+ossl_x509extfactory_alloc(VALUE klass)
+{
+    X509V3_CTX *ctx;
+    VALUE obj;
+
+    MakeX509ExtFactory(klass, obj, ctx);
+    rb_iv_set(obj, "@config", Qnil);
+
+    return obj;
+}
+
+static VALUE
+ossl_x509extfactory_set_issuer_cert(VALUE self, VALUE cert)
+{
+    X509V3_CTX *ctx;
+
+    GetX509ExtFactory(self, ctx);
+    rb_iv_set(self, "@issuer_certificate", cert);
+    ctx->issuer_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */
+
+    return cert;
+}
+
+static VALUE
+ossl_x509extfactory_set_subject_cert(VALUE self, VALUE cert)
+{
+    X509V3_CTX *ctx;
+
+    GetX509ExtFactory(self, ctx);
+    rb_iv_set(self, "@subject_certificate", cert);
+    ctx->subject_cert = GetX509CertPtr(cert); /* NO DUP NEEDED */
+
+    return cert;
+}
+
+static VALUE
+ossl_x509extfactory_set_subject_req(VALUE self, VALUE req)
+{
+    X509V3_CTX *ctx;
+
+    GetX509ExtFactory(self, ctx);
+    rb_iv_set(self, "@subject_request", req);
+    ctx->subject_req = GetX509ReqPtr(req); /* NO DUP NEEDED */
+
+    return req;
+}
+
+static VALUE
+ossl_x509extfactory_set_crl(VALUE self, VALUE crl)
+{
+    X509V3_CTX *ctx;
+
+    GetX509ExtFactory(self, ctx);
+    rb_iv_set(self, "@crl", crl);
+    ctx->crl = GetX509CRLPtr(crl); /* NO DUP NEEDED */
+
+    return crl;
+}
+
+#ifdef HAVE_X509V3_SET_NCONF
+static VALUE
+ossl_x509extfactory_set_config(VALUE self, VALUE config)
+{
+    X509V3_CTX *ctx;
+    CONF *conf;
+
+    GetX509ExtFactory(self, ctx);
+    rb_iv_set(self, "@config", config);
+    conf = GetConfigPtr(config);  /* NO DUP NEEDED */
+    X509V3_set_nconf(ctx, conf);
+
+    return config;
+}
+#else
+#define ossl_x509extfactory_set_config rb_f_notimplement
+#endif
+
+static VALUE
+ossl_x509extfactory_initialize(int argc, VALUE *argv, VALUE self)
+{
+    /*X509V3_CTX *ctx;*/
+    VALUE issuer_cert, subject_cert, subject_req, crl;
+
+    /*GetX509ExtFactory(self, ctx);*/
+
+    rb_scan_args(argc, argv, "04",
+                &issuer_cert, &subject_cert, &subject_req, &crl);
+    if (!NIL_P(issuer_cert))
+       ossl_x509extfactory_set_issuer_cert(self, issuer_cert);
+    if (!NIL_P(subject_cert))
+       ossl_x509extfactory_set_subject_cert(self, subject_cert);
+    if (!NIL_P(subject_req))
+       ossl_x509extfactory_set_subject_req(self, subject_req);
+    if (!NIL_P(crl))
+       ossl_x509extfactory_set_crl(self, crl);
+
+    return self;
+}
+
+/*
+ * Array to X509_EXTENSION
+ * Structure:
+ * ["ln", "value", bool_critical] or
+ * ["sn", "value", bool_critical] or
+ * ["ln", "critical,value"] or the same for sn
+ * ["ln", "value"] => not critical
+ */
+static VALUE
+ossl_x509extfactory_create_ext(int argc, VALUE *argv, VALUE self)
+{
+    X509V3_CTX *ctx;
+    X509_EXTENSION *ext;
+    VALUE oid, value, critical, valstr, obj;
+    int nid;
+#ifdef HAVE_X509V3_EXT_NCONF_NID
+    VALUE rconf;
+    CONF *conf;
+#else
+    static LHASH *empty_lhash;
+#endif
+
+    rb_scan_args(argc, argv, "21", &oid, &value, &critical);
+    StringValue(oid);
+    StringValue(value);
+    if(NIL_P(critical)) critical = Qfalse;
+
+    nid = OBJ_ln2nid(RSTRING_PTR(oid));
+    if(!nid) nid = OBJ_sn2nid(RSTRING_PTR(oid));
+    if(!nid) ossl_raise(eX509ExtError, "unknown OID `%s'", RSTRING_PTR(oid));
+    valstr = rb_str_new2(RTEST(critical) ? "critical," : "");
+    rb_str_append(valstr, value);
+    GetX509ExtFactory(self, ctx);
+#ifdef HAVE_X509V3_EXT_NCONF_NID
+    rconf = rb_iv_get(self, "@config");
+    conf = NIL_P(rconf) ? NULL : GetConfigPtr(rconf);
+    ext = X509V3_EXT_nconf_nid(conf, ctx, nid, RSTRING_PTR(valstr));
+#else
+    if (!empty_lhash) empty_lhash = lh_new(NULL, NULL);
+    ext = X509V3_EXT_conf_nid(empty_lhash, ctx, nid, RSTRING_PTR(valstr));
+#endif
+    if (!ext){
+       ossl_raise(eX509ExtError, "%s = %s",
+                  RSTRING_PTR(oid), RSTRING_PTR(value));
+    }
+    WrapX509Ext(cX509Ext, obj, ext);
+
+    return obj;
+}
+
+/*
+ * Ext
+ */
+static VALUE
+ossl_x509ext_alloc(VALUE klass)
+{
+    X509_EXTENSION *ext;
+    VALUE obj;
+
+    if(!(ext = X509_EXTENSION_new())){
+       ossl_raise(eX509ExtError, NULL);
+    }
+    WrapX509Ext(klass, obj, ext);
+
+    return obj;
+}
+
+/*
+ * call-seq:
+ *    OpenSSL::X509::Extension.new asn1
+ *    OpenSSL::X509::Extension.new name, value
+ *    OpenSSL::X509::Extension.new name, value, critical
+ *
+ * Creates an X509 extension.
+ *
+ * The extension may be created from +asn1+ data or from an extension +name+
+ * and +value+.  The +name+ may be either an OID or an extension name.  If
+ * +critical+ is true the extension is marked critical.
+ */
+static VALUE
+ossl_x509ext_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE oid, value, critical;
+    const unsigned char *p;
+    X509_EXTENSION *ext, *x;
+
+    GetX509Ext(self, ext);
+    if(rb_scan_args(argc, argv, "12", &oid, &value, &critical) == 1){
+       oid = ossl_to_der_if_possible(oid);
+       StringValue(oid);
+       p = (unsigned char *)RSTRING_PTR(oid);
+       x = d2i_X509_EXTENSION(&ext, &p, RSTRING_LEN(oid));
+       DATA_PTR(self) = ext;
+       if(!x)
+           ossl_raise(eX509ExtError, NULL);
+       return self;
+    }
+    rb_funcall(self, rb_intern("oid="), 1, oid);
+    rb_funcall(self, rb_intern("value="), 1, value);
+    if(argc > 2) rb_funcall(self, rb_intern("critical="), 1, critical);
+
+    return self;
+}
+
+static VALUE
+ossl_x509ext_set_oid(VALUE self, VALUE oid)
+{
+    X509_EXTENSION *ext;
+    ASN1_OBJECT *obj;
+    char *s;
+
+    s = StringValuePtr(oid);
+    obj = OBJ_txt2obj(s, 0);
+    if(!obj) obj = OBJ_txt2obj(s, 1);
+    if(!obj) ossl_raise(eX509ExtError, NULL);
+    GetX509Ext(self, ext);
+    X509_EXTENSION_set_object(ext, obj);
+
+    return oid;
+}
+
+static VALUE
+ossl_x509ext_set_value(VALUE self, VALUE data)
+{
+    X509_EXTENSION *ext;
+    ASN1_OCTET_STRING *asn1s;
+    char *s;
+
+    data = ossl_to_der_if_possible(data);
+    StringValue(data);
+    if(!(s = OPENSSL_malloc(RSTRING_LEN(data))))
+       ossl_raise(eX509ExtError, "malloc error");
+    memcpy(s, RSTRING_PTR(data), RSTRING_LEN(data));
+    if(!(asn1s = ASN1_OCTET_STRING_new())){
+       OPENSSL_free(s);
+       ossl_raise(eX509ExtError, NULL);
+    }
+    if(!M_ASN1_OCTET_STRING_set(asn1s, s, RSTRING_LENINT(data))){
+       OPENSSL_free(s);
+       ASN1_OCTET_STRING_free(asn1s);
+       ossl_raise(eX509ExtError, NULL);
+    }
+    OPENSSL_free(s);
+    GetX509Ext(self, ext);
+    X509_EXTENSION_set_data(ext, asn1s);
+
+    return data;
+}
+
+static VALUE
+ossl_x509ext_set_critical(VALUE self, VALUE flag)
+{
+    X509_EXTENSION *ext;
+
+    GetX509Ext(self, ext);
+    X509_EXTENSION_set_critical(ext, RTEST(flag) ? 1 : 0);
+
+    return flag;
+}
+
+static VALUE
+ossl_x509ext_get_oid(VALUE obj)
+{
+    X509_EXTENSION *ext;
+    ASN1_OBJECT *extobj;
+    BIO *out;
+    VALUE ret;
+    int nid;
+
+    GetX509Ext(obj, ext);
+    extobj = X509_EXTENSION_get_object(ext);
+    if ((nid = OBJ_obj2nid(extobj)) != NID_undef)
+       ret = rb_str_new2(OBJ_nid2sn(nid));
+    else{
+       if (!(out = BIO_new(BIO_s_mem())))
+           ossl_raise(eX509ExtError, NULL);
+       i2a_ASN1_OBJECT(out, extobj);
+       ret = ossl_membio2str(out);
+    }
+
+    return ret;
+}
+
+static VALUE
+ossl_x509ext_get_value(VALUE obj)
+{
+    X509_EXTENSION *ext;
+    BIO *out;
+    VALUE ret;
+
+    GetX509Ext(obj, ext);
+    if (!(out = BIO_new(BIO_s_mem())))
+       ossl_raise(eX509ExtError, NULL);
+    if (!X509V3_EXT_print(out, ext, 0, 0))
+       M_ASN1_OCTET_STRING_print(out, ext->value);
+    ret = ossl_membio2str(out);
+
+    return ret;
+}
+
+static VALUE
+ossl_x509ext_get_critical(VALUE obj)
+{
+    X509_EXTENSION *ext;
+
+    GetX509Ext(obj, ext);
+    return X509_EXTENSION_get_critical(ext) ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_x509ext_to_der(VALUE obj)
+{
+    X509_EXTENSION *ext;
+    unsigned char *p;
+    long len;
+    VALUE str;
+
+    GetX509Ext(obj, ext);
+    if((len = i2d_X509_EXTENSION(ext, NULL)) <= 0)
+       ossl_raise(eX509ExtError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_X509_EXTENSION(ext, &p) < 0)
+       ossl_raise(eX509ExtError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509ext()
+{
+    eX509ExtError = rb_define_class_under(mX509, "ExtensionError", eOSSLError);
+
+    cX509ExtFactory = rb_define_class_under(mX509, "ExtensionFactory", rb_cObject);
+
+    rb_define_alloc_func(cX509ExtFactory, ossl_x509extfactory_alloc);
+    rb_define_method(cX509ExtFactory, "initialize", ossl_x509extfactory_initialize, -1);
+
+    rb_attr(cX509ExtFactory, rb_intern("issuer_certificate"), 1, 0, Qfalse);
+    rb_attr(cX509ExtFactory, rb_intern("subject_certificate"), 1, 0, Qfalse);
+    rb_attr(cX509ExtFactory, rb_intern("subject_request"), 1, 0, Qfalse);
+    rb_attr(cX509ExtFactory, rb_intern("crl"), 1, 0, Qfalse);
+    rb_attr(cX509ExtFactory, rb_intern("config"), 1, 0, Qfalse);
+
+    rb_define_method(cX509ExtFactory, "issuer_certificate=", ossl_x509extfactory_set_issuer_cert, 1);
+    rb_define_method(cX509ExtFactory, "subject_certificate=", ossl_x509extfactory_set_subject_cert, 1);
+    rb_define_method(cX509ExtFactory, "subject_request=", ossl_x509extfactory_set_subject_req, 1);
+    rb_define_method(cX509ExtFactory, "crl=", ossl_x509extfactory_set_crl, 1);
+    rb_define_method(cX509ExtFactory, "config=", ossl_x509extfactory_set_config, 1);
+    rb_define_method(cX509ExtFactory, "create_ext", ossl_x509extfactory_create_ext, -1);
+
+    cX509Ext = rb_define_class_under(mX509, "Extension", rb_cObject);
+    rb_define_alloc_func(cX509Ext, ossl_x509ext_alloc);
+    rb_define_method(cX509Ext, "initialize", ossl_x509ext_initialize, -1);
+    rb_define_method(cX509Ext, "oid=", ossl_x509ext_set_oid, 1);
+    rb_define_method(cX509Ext, "value=", ossl_x509ext_set_value, 1);
+    rb_define_method(cX509Ext, "critical=", ossl_x509ext_set_critical, 1);
+    rb_define_method(cX509Ext, "oid", ossl_x509ext_get_oid, 0);
+    rb_define_method(cX509Ext, "value", ossl_x509ext_get_value, 0);
+    rb_define_method(cX509Ext, "critical?", ossl_x509ext_get_critical, 0);
+    rb_define_method(cX509Ext, "to_der", ossl_x509ext_to_der, 0);
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509name.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509name.c
new file mode 100644 (file)
index 0000000..a8f288f
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001 Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Name(klass, obj, name) do { \
+    if (!(name)) { \
+       ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_NAME_free, (name)); \
+} while (0)
+#define GetX509Name(obj, name) do { \
+    Data_Get_Struct((obj), X509_NAME, (name)); \
+    if (!(name)) { \
+       ossl_raise(rb_eRuntimeError, "Name wasn't initialized."); \
+    } \
+} while (0)
+#define SafeGetX509Name(obj, name) do { \
+    OSSL_Check_Kind((obj), cX509Name); \
+    GetX509Name((obj), (name)); \
+} while (0)
+
+#define OBJECT_TYPE_TEMPLATE \
+  rb_const_get(cX509Name, rb_intern("OBJECT_TYPE_TEMPLATE"))
+#define DEFAULT_OBJECT_TYPE \
+  rb_const_get(cX509Name, rb_intern("DEFAULT_OBJECT_TYPE"))
+
+/*
+ * Classes
+ */
+VALUE cX509Name;
+VALUE eX509NameError;
+
+/*
+ * Public
+ */
+VALUE
+ossl_x509name_new(X509_NAME *name)
+{
+    X509_NAME *new;
+    VALUE obj;
+
+    if (!name) {
+       new = X509_NAME_new();
+    } else {
+       new = X509_NAME_dup(name);
+    }
+    if (!new) {
+       ossl_raise(eX509NameError, NULL);
+    }
+    WrapX509Name(cX509Name, obj, new);
+
+    return obj;
+}
+
+X509_NAME *
+GetX509NamePtr(VALUE obj)
+{
+    X509_NAME *name;
+
+    SafeGetX509Name(obj, name);
+
+    return name;
+}
+
+/*
+ * Private
+ */
+static VALUE
+ossl_x509name_alloc(VALUE klass)
+{
+    X509_NAME *name;
+    VALUE obj;
+
+    if (!(name = X509_NAME_new())) {
+       ossl_raise(eX509NameError, NULL);
+    }
+    WrapX509Name(klass, obj, name);
+
+    return obj;
+}
+
+static ID id_aref;
+static VALUE ossl_x509name_add_entry(int, VALUE*, VALUE);
+#define rb_aref(obj, key) rb_funcall((obj), id_aref, 1, (key))
+
+static VALUE
+ossl_x509name_init_i(VALUE i, VALUE args)
+{
+    VALUE self = rb_ary_entry(args, 0);
+    VALUE template = rb_ary_entry(args, 1);
+    VALUE entry[3];
+
+    Check_Type(i, T_ARRAY);
+    entry[0] = rb_ary_entry(i, 0);
+    entry[1] = rb_ary_entry(i, 1);
+    entry[2] = rb_ary_entry(i, 2);
+    if(NIL_P(entry[2])) entry[2] = rb_aref(template, entry[0]);
+    if(NIL_P(entry[2])) entry[2] = DEFAULT_OBJECT_TYPE;
+    ossl_x509name_add_entry(3, entry, self);
+
+    return Qnil;
+}
+
+/*
+ * call-seq:
+ *    X509::Name.new => name
+ *    X509::Name.new(string) => name
+ *    X509::Name.new(dn) => name
+ *    X509::Name.new(dn, template) => name
+ */
+static VALUE
+ossl_x509name_initialize(int argc, VALUE *argv, VALUE self)
+{
+    X509_NAME *name;
+    VALUE arg, template;
+
+    GetX509Name(self, name);
+    if (rb_scan_args(argc, argv, "02", &arg, &template) == 0) {
+       return self;
+    }
+    else {
+       VALUE tmp = rb_check_array_type(arg);
+       if (!NIL_P(tmp)) {
+           VALUE args;
+           if(NIL_P(template)) template = OBJECT_TYPE_TEMPLATE;
+           args = rb_ary_new3(2, self, template);
+           rb_block_call(tmp, rb_intern("each"), 0, 0, ossl_x509name_init_i, args);
+       }
+       else{
+           const unsigned char *p;
+           VALUE str = ossl_to_der_if_possible(arg);
+           X509_NAME *x;
+           StringValue(str);
+           p = (unsigned char *)RSTRING_PTR(str);
+           x = d2i_X509_NAME(&name, &p, RSTRING_LEN(str));
+           DATA_PTR(self) = name;
+           if(!x){
+               ossl_raise(eX509NameError, NULL);
+           }
+       }
+    }
+
+    return self;
+}
+
+/*
+ * call-seq:
+ *    name.add_entry(oid, value [, type]) => self
+ */
+static
+VALUE ossl_x509name_add_entry(int argc, VALUE *argv, VALUE self)
+{
+    X509_NAME *name;
+    VALUE oid, value, type;
+
+    rb_scan_args(argc, argv, "21", &oid, &value, &type);
+    StringValue(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),
+               (const unsigned char *)RSTRING_PTR(value), RSTRING_LENINT(value), -1, 0)) {
+       ossl_raise(eX509NameError, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_x509name_to_s_old(VALUE self)
+{
+    X509_NAME *name;
+    char *buf;
+    VALUE str;
+
+    GetX509Name(self, name);
+    buf = X509_NAME_oneline(name, NULL, 0);
+    str = rb_str_new2(buf);
+    OPENSSL_free(buf);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    name.to_s => string
+ *    name.to_s(integer) => string
+ */
+static VALUE
+ossl_x509name_to_s(int argc, VALUE *argv, VALUE self)
+{
+    X509_NAME *name;
+    VALUE flag, str;
+    BIO *out;
+    unsigned long iflag;
+
+    rb_scan_args(argc, argv, "01", &flag);
+    if (NIL_P(flag))
+       return ossl_x509name_to_s_old(self);
+    else iflag = NUM2ULONG(flag);
+    if (!(out = BIO_new(BIO_s_mem())))
+       ossl_raise(eX509NameError, NULL);
+    GetX509Name(self, name);
+    if (!X509_NAME_print_ex(out, name, 0, iflag)){
+       BIO_free(out);
+       ossl_raise(eX509NameError, NULL);
+    }
+    str = ossl_membio2str(out);
+
+    return str;
+}
+
+/*
+ * call-seq:
+ *    name.to_a => [[name, data, type], ...]
+ */
+static VALUE
+ossl_x509name_to_a(VALUE self)
+{
+    X509_NAME *name;
+    X509_NAME_ENTRY *entry;
+    int i,entries,nid;
+    char long_name[512];
+    const char *short_name;
+    VALUE ary, vname, ret;
+
+    GetX509Name(self, name);
+    entries = X509_NAME_entry_count(name);
+    if (entries < 0) {
+       OSSL_Debug("name entries < 0!");
+       return rb_ary_new();
+    }
+    ret = rb_ary_new2(entries);
+    for (i=0; i<entries; i++) {
+       if (!(entry = X509_NAME_get_entry(name, i))) {
+           ossl_raise(eX509NameError, NULL);
+       }
+       if (!i2t_ASN1_OBJECT(long_name, sizeof(long_name), entry->object)) {
+           ossl_raise(eX509NameError, NULL);
+       }
+       nid = OBJ_ln2nid(long_name);
+       if (nid == NID_undef) {
+           vname = rb_str_new2((const char *) &long_name);
+       } else {
+           short_name = OBJ_nid2sn(nid);
+           vname = rb_str_new2(short_name); /*do not free*/
+       }
+       ary = rb_ary_new3(3,
+                         vname,
+                         rb_str_new((const char *)entry->value->data, entry->value->length),
+                         INT2FIX(entry->value->type));
+       rb_ary_push(ret, ary);
+    }
+    return ret;
+}
+
+static int
+ossl_x509name_cmp0(VALUE self, VALUE other)
+{
+    X509_NAME *name1, *name2;
+
+    GetX509Name(self, name1);
+    SafeGetX509Name(other, name2);
+
+    return X509_NAME_cmp(name1, name2);
+}
+
+/*
+ * call-seq:
+ *    name.cmp other => integer
+ *    name.<=> other => integer
+ *
+ * Compares this Name with +other+ and returns 0 if they are the same and -1 or
+ * +1 if they are greater or less than each other respectively.
+ */
+static VALUE
+ossl_x509name_cmp(VALUE self, VALUE other)
+{
+    int result;
+
+    result = ossl_x509name_cmp0(self, other);
+    if (result < 0) return INT2FIX(-1);
+    if (result > 1) return INT2FIX(1);
+
+    return INT2FIX(0);
+}
+
+static VALUE
+ossl_x509name_eql(VALUE self, VALUE other)
+{
+    int result;
+
+    if(CLASS_OF(other) != cX509Name) return Qfalse;
+    result = ossl_x509name_cmp0(self, other);
+
+    return (result == 0) ? Qtrue : Qfalse;
+}
+
+/*
+ * call-seq:
+ *    name.hash => integer
+ *
+ * The hash value returned is suitable for use as a certificate's filename in
+ * a CA path.
+ */
+static VALUE
+ossl_x509name_hash(VALUE self)
+{
+    X509_NAME *name;
+    unsigned long hash;
+
+    GetX509Name(self, name);
+
+    hash = X509_NAME_hash(name);
+
+    return ULONG2NUM(hash);
+}
+
+#ifdef HAVE_X509_NAME_HASH_OLD
+/*
+ * call-seq:
+ *    name.hash_old => integer
+ *
+ * hash_old returns MD5 based hash used in OpenSSL 0.9.X.
+ */
+static VALUE
+ossl_x509name_hash_old(VALUE self)
+{
+    X509_NAME *name;
+    unsigned long hash;
+
+    GetX509Name(self, name);
+
+    hash = X509_NAME_hash_old(name);
+
+    return ULONG2NUM(hash);
+}
+#endif
+
+/*
+ * call-seq:
+ *    name.to_der => string
+ */
+static VALUE
+ossl_x509name_to_der(VALUE self)
+{
+    X509_NAME *name;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetX509Name(self, name);
+    if((len = i2d_X509_NAME(name, NULL)) <= 0)
+       ossl_raise(eX509NameError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if(i2d_X509_NAME(name, &p) <= 0)
+       ossl_raise(eX509NameError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509name()
+{
+    VALUE utf8str, ptrstr, ia5str, hash;
+
+    id_aref = rb_intern("[]");
+    eX509NameError = rb_define_class_under(mX509, "NameError", eOSSLError);
+    cX509Name = rb_define_class_under(mX509, "Name", rb_cObject);
+
+    rb_include_module(cX509Name, rb_mComparable);
+
+    rb_define_alloc_func(cX509Name, ossl_x509name_alloc);
+    rb_define_method(cX509Name, "initialize", ossl_x509name_initialize, -1);
+    rb_define_method(cX509Name, "add_entry", ossl_x509name_add_entry, -1);
+    rb_define_method(cX509Name, "to_s", ossl_x509name_to_s, -1);
+    rb_define_method(cX509Name, "to_a", ossl_x509name_to_a, 0);
+    rb_define_method(cX509Name, "cmp", ossl_x509name_cmp, 1);
+    rb_define_alias(cX509Name, "<=>", "cmp");
+    rb_define_method(cX509Name, "eql?", ossl_x509name_eql, 1);
+    rb_define_method(cX509Name, "hash", ossl_x509name_hash, 0);
+#ifdef HAVE_X509_NAME_HASH_OLD
+    rb_define_method(cX509Name, "hash_old", ossl_x509name_hash_old, 0);
+#endif
+    rb_define_method(cX509Name, "to_der", ossl_x509name_to_der, 0);
+
+    utf8str = INT2NUM(V_ASN1_UTF8STRING);
+    ptrstr = INT2NUM(V_ASN1_PRINTABLESTRING);
+    ia5str = INT2NUM(V_ASN1_IA5STRING);
+    rb_define_const(cX509Name, "DEFAULT_OBJECT_TYPE", utf8str);
+    hash = rb_hash_new();
+    RHASH(hash)->ifnone = utf8str;
+    rb_hash_aset(hash, rb_str_new2("C"), ptrstr);
+    rb_hash_aset(hash, rb_str_new2("countryName"), ptrstr);
+    rb_hash_aset(hash, rb_str_new2("serialNumber"), ptrstr);
+    rb_hash_aset(hash, rb_str_new2("dnQualifier"), ptrstr);
+    rb_hash_aset(hash, rb_str_new2("DC"), ia5str);
+    rb_hash_aset(hash, rb_str_new2("domainComponent"), ia5str);
+    rb_hash_aset(hash, rb_str_new2("emailAddress"), ia5str);
+    rb_define_const(cX509Name, "OBJECT_TYPE_TEMPLATE", hash);
+
+    rb_define_const(cX509Name, "COMPAT", ULONG2NUM(XN_FLAG_COMPAT));
+    rb_define_const(cX509Name, "RFC2253", ULONG2NUM(XN_FLAG_RFC2253));
+    rb_define_const(cX509Name, "ONELINE", ULONG2NUM(XN_FLAG_ONELINE));
+    rb_define_const(cX509Name, "MULTILINE", ULONG2NUM(XN_FLAG_MULTILINE));
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509req.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509req.c
new file mode 100644 (file)
index 0000000..5927f76
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Req(klass, obj, req) do { \
+    if (!(req)) { \
+       ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_REQ_free, (req)); \
+} while (0)
+#define GetX509Req(obj, req) do { \
+    Data_Get_Struct((obj), X509_REQ, (req)); \
+    if (!(req)) { \
+       ossl_raise(rb_eRuntimeError, "Req wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetX509Req(obj, req) do { \
+    OSSL_Check_Kind((obj), cX509Req); \
+    GetX509Req((obj), (req)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Req;
+VALUE eX509ReqError;
+
+/*
+ * Public functions
+ */
+VALUE
+ossl_x509req_new(X509_REQ *req)
+{
+    X509_REQ *new;
+    VALUE obj;
+
+    if (!req) {
+       new = X509_REQ_new();
+    } else {
+       new = X509_REQ_dup(req);
+    }
+    if (!new) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+    WrapX509Req(cX509Req, obj, new);
+
+    return obj;
+}
+
+X509_REQ *
+GetX509ReqPtr(VALUE obj)
+{
+    X509_REQ *req;
+
+    SafeGetX509Req(obj, req);
+
+    return req;
+}
+
+X509_REQ *
+DupX509ReqPtr(VALUE obj)
+{
+    X509_REQ *req, *new;
+
+    SafeGetX509Req(obj, req);
+    if (!(new = X509_REQ_dup(req))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return new;
+}
+
+/*
+ * Private functions
+ */
+static VALUE
+ossl_x509req_alloc(VALUE klass)
+{
+    X509_REQ *req;
+    VALUE obj;
+
+    if (!(req = X509_REQ_new())) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+    WrapX509Req(klass, obj, req);
+
+    return obj;
+}
+
+static VALUE
+ossl_x509req_initialize(int argc, VALUE *argv, VALUE self)
+{
+    BIO *in;
+    X509_REQ *req, *x = DATA_PTR(self);
+    VALUE arg;
+
+    if (rb_scan_args(argc, argv, "01", &arg) == 0) {
+       return self;
+    }
+    arg = ossl_to_der_if_possible(arg);
+    in = ossl_obj2bio(arg);
+    req = PEM_read_bio_X509_REQ(in, &x, NULL, NULL);
+    DATA_PTR(self) = x;
+    if (!req) {
+       OSSL_BIO_reset(in);
+       req = d2i_X509_REQ_bio(in, &x);
+       DATA_PTR(self) = x;
+    }
+    BIO_free(in);
+    if (!req) ossl_raise(eX509ReqError, NULL);
+
+    return self;
+}
+
+static VALUE
+ossl_x509req_copy(VALUE self, VALUE other)
+{
+    X509_REQ *a, *b, *req;
+
+    rb_check_frozen(self);
+    if (self == other) return self;
+    GetX509Req(self, a);
+    SafeGetX509Req(other, b);
+    if (!(req = X509_REQ_dup(b))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+    X509_REQ_free(a);
+    DATA_PTR(self) = req;
+
+    return self;
+}
+
+static VALUE
+ossl_x509req_to_pem(VALUE self)
+{
+    X509_REQ *req;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetX509Req(self, req);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+    if (!PEM_write_bio_X509_REQ(out, req)) {
+       BIO_free(out);
+       ossl_raise(eX509ReqError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+
+    return str;
+}
+
+static VALUE
+ossl_x509req_to_der(VALUE self)
+{
+    X509_REQ *req;
+    VALUE str;
+    long len;
+    unsigned char *p;
+
+    GetX509Req(self, req);
+    if ((len = i2d_X509_REQ(req, NULL)) <= 0)
+       ossl_raise(eX509ReqError, NULL);
+    str = rb_str_new(0, len);
+    p = (unsigned char *)RSTRING_PTR(str);
+    if (i2d_X509_REQ(req, &p) <= 0)
+       ossl_raise(eX509ReqError, NULL);
+    ossl_str_adjust(str, p);
+
+    return str;
+}
+
+static VALUE
+ossl_x509req_to_text(VALUE self)
+{
+    X509_REQ *req;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetX509Req(self, req);
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+    if (!X509_REQ_print(out, req)) {
+       BIO_free(out);
+       ossl_raise(eX509ReqError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+
+    return str;
+}
+
+#if 0
+/*
+ * Makes X509 from X509_REQuest
+ */
+static VALUE
+ossl_x509req_to_x509(VALUE self, VALUE days, VALUE key)
+{
+    X509_REQ *req;
+    X509 *x509;
+
+    GetX509Req(self, req);
+    ...
+    if (!(x509 = X509_REQ_to_X509(req, d, pkey))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return ossl_x509_new(x509);
+}
+#endif
+
+static VALUE
+ossl_x509req_get_version(VALUE self)
+{
+    X509_REQ *req;
+    long version;
+
+    GetX509Req(self, req);
+    version = X509_REQ_get_version(req);
+
+    return LONG2FIX(version);
+}
+
+static VALUE
+ossl_x509req_set_version(VALUE self, VALUE version)
+{
+    X509_REQ *req;
+    long ver;
+
+    if ((ver = FIX2LONG(version)) < 0) {
+       ossl_raise(eX509ReqError, "version must be >= 0!");
+    }
+    GetX509Req(self, req);
+    if (!X509_REQ_set_version(req, ver)) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return version;
+}
+
+static VALUE
+ossl_x509req_get_subject(VALUE self)
+{
+    X509_REQ *req;
+    X509_NAME *name;
+
+    GetX509Req(self, req);
+    if (!(name = X509_REQ_get_subject_name(req))) { /* NO DUP - don't free */
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return ossl_x509name_new(name);
+}
+
+static VALUE
+ossl_x509req_set_subject(VALUE self, VALUE subject)
+{
+    X509_REQ *req;
+
+    GetX509Req(self, req);
+    /* DUPs name */
+    if (!X509_REQ_set_subject_name(req, GetX509NamePtr(subject))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return subject;
+}
+
+static VALUE
+ossl_x509req_get_signature_algorithm(VALUE self)
+{
+    X509_REQ *req;
+    BIO *out;
+    BUF_MEM *buf;
+    VALUE str;
+
+    GetX509Req(self, req);
+
+    if (!(out = BIO_new(BIO_s_mem()))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+    if (!i2a_ASN1_OBJECT(out, req->sig_alg->algorithm)) {
+       BIO_free(out);
+       ossl_raise(eX509ReqError, NULL);
+    }
+    BIO_get_mem_ptr(out, &buf);
+    str = rb_str_new(buf->data, buf->length);
+    BIO_free(out);
+    return str;
+}
+
+static VALUE
+ossl_x509req_get_public_key(VALUE self)
+{
+    X509_REQ *req;
+    EVP_PKEY *pkey;
+
+    GetX509Req(self, req);
+    if (!(pkey = X509_REQ_get_pubkey(req))) { /* adds reference */
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return ossl_pkey_new(pkey); /* NO DUP - OK */
+}
+
+static VALUE
+ossl_x509req_set_public_key(VALUE self, VALUE key)
+{
+    X509_REQ *req;
+    EVP_PKEY *pkey;
+
+    GetX509Req(self, req);
+    pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
+    if (!X509_REQ_set_pubkey(req, pkey)) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return key;
+}
+
+static VALUE
+ossl_x509req_sign(VALUE self, VALUE key, VALUE digest)
+{
+    X509_REQ *req;
+    EVP_PKEY *pkey;
+    const EVP_MD *md;
+
+    GetX509Req(self, req);
+    pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */
+    md = GetDigestPtr(digest);
+    if (!X509_REQ_sign(req, pkey, md)) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return self;
+}
+
+/*
+ * Checks that cert signature is made with PRIVversion of this PUBLIC 'key'
+ */
+static VALUE
+ossl_x509req_verify(VALUE self, VALUE key)
+{
+    X509_REQ *req;
+    EVP_PKEY *pkey;
+    int i;
+
+    GetX509Req(self, req);
+    pkey = GetPKeyPtr(key); /* NO NEED TO DUP */
+    if ((i = X509_REQ_verify(req, pkey)) < 0) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+    if (i > 0) {
+       return Qtrue;
+    }
+
+    return Qfalse;
+}
+
+static VALUE
+ossl_x509req_get_attributes(VALUE self)
+{
+    X509_REQ *req;
+    int count, i;
+    X509_ATTRIBUTE *attr;
+    VALUE ary;
+
+    GetX509Req(self, req);
+
+    count = X509_REQ_get_attr_count(req);
+    if (count < 0) {
+       OSSL_Debug("count < 0???");
+       return rb_ary_new();
+    }
+    ary = rb_ary_new2(count);
+    for (i=0; i<count; i++) {
+       attr = X509_REQ_get_attr(req, i);
+       rb_ary_push(ary, ossl_x509attr_new(attr));
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_x509req_set_attributes(VALUE self, VALUE ary)
+{
+    X509_REQ *req;
+    X509_ATTRIBUTE *attr;
+    int i;
+    VALUE item;
+
+    Check_Type(ary, T_ARRAY);
+    for (i=0;i<RARRAY_LEN(ary); i++) {
+       OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Attr);
+    }
+    GetX509Req(self, req);
+    sk_X509_ATTRIBUTE_pop_free(req->req_info->attributes, X509_ATTRIBUTE_free);
+    req->req_info->attributes = NULL;
+    for (i=0;i<RARRAY_LEN(ary); i++) {
+       item = RARRAY_PTR(ary)[i];
+       attr = DupX509AttrPtr(item);
+       if (!X509_REQ_add1_attr(req, attr)) {
+           ossl_raise(eX509ReqError, NULL);
+       }
+    }
+    return ary;
+}
+
+static VALUE
+ossl_x509req_add_attribute(VALUE self, VALUE attr)
+{
+    X509_REQ *req;
+
+    GetX509Req(self, req);
+    if (!X509_REQ_add1_attr(req, DupX509AttrPtr(attr))) {
+       ossl_raise(eX509ReqError, NULL);
+    }
+
+    return attr;
+}
+
+/*
+ * X509_REQUEST init
+ */
+void
+Init_ossl_x509req()
+{
+    eX509ReqError = rb_define_class_under(mX509, "RequestError", eOSSLError);
+
+    cX509Req = rb_define_class_under(mX509, "Request", rb_cObject);
+
+    rb_define_alloc_func(cX509Req, ossl_x509req_alloc);
+    rb_define_method(cX509Req, "initialize", ossl_x509req_initialize, -1);
+    rb_define_copy_func(cX509Req, ossl_x509req_copy);
+
+    rb_define_method(cX509Req, "to_pem", ossl_x509req_to_pem, 0);
+    rb_define_method(cX509Req, "to_der", ossl_x509req_to_der, 0);
+    rb_define_alias(cX509Req, "to_s", "to_pem");
+    rb_define_method(cX509Req, "to_text", ossl_x509req_to_text, 0);
+    rb_define_method(cX509Req, "version", ossl_x509req_get_version, 0);
+    rb_define_method(cX509Req, "version=", ossl_x509req_set_version, 1);
+    rb_define_method(cX509Req, "subject", ossl_x509req_get_subject, 0);
+    rb_define_method(cX509Req, "subject=", ossl_x509req_set_subject, 1);
+    rb_define_method(cX509Req, "signature_algorithm", ossl_x509req_get_signature_algorithm, 0);
+    rb_define_method(cX509Req, "public_key", ossl_x509req_get_public_key, 0);
+    rb_define_method(cX509Req, "public_key=", ossl_x509req_set_public_key, 1);
+    rb_define_method(cX509Req, "sign", ossl_x509req_sign, 2);
+    rb_define_method(cX509Req, "verify", ossl_x509req_verify, 1);
+    rb_define_method(cX509Req, "attributes", ossl_x509req_get_attributes, 0);
+    rb_define_method(cX509Req, "attributes=", ossl_x509req_set_attributes, 1);
+    rb_define_method(cX509Req, "add_attribute", ossl_x509req_add_attribute, 1);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509revoked.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509revoked.c
new file mode 100644 (file)
index 0000000..320abaa
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Rev(klass, obj, rev) do { \
+    if (!(rev)) { \
+       ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_REVOKED_free, (rev)); \
+} while (0)
+#define GetX509Rev(obj, rev) do { \
+    Data_Get_Struct((obj), X509_REVOKED, (rev)); \
+    if (!(rev)) { \
+       ossl_raise(rb_eRuntimeError, "REV wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetX509Rev(obj, rev) do { \
+    OSSL_Check_Kind((obj), cX509Rev); \
+    GetX509Rev((obj), (rev)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Rev;
+VALUE eX509RevError;
+
+/*
+ * PUBLIC
+ */
+VALUE
+ossl_x509revoked_new(X509_REVOKED *rev)
+{
+    X509_REVOKED *new;
+    VALUE obj;
+
+    if (!rev) {
+       new = X509_REVOKED_new();
+    } else {
+       new = X509_REVOKED_dup(rev);
+    }
+    if (!new) {
+       ossl_raise(eX509RevError, NULL);
+    }
+    WrapX509Rev(cX509Rev, obj, new);
+
+    return obj;
+}
+
+X509_REVOKED *
+DupX509RevokedPtr(VALUE obj)
+{
+    X509_REVOKED *rev, *new;
+
+    SafeGetX509Rev(obj, rev);
+    if (!(new = X509_REVOKED_dup(rev))) {
+       ossl_raise(eX509RevError, NULL);
+    }
+
+    return new;
+}
+
+/*
+ * PRIVATE
+ */
+static VALUE
+ossl_x509revoked_alloc(VALUE klass)
+{
+    X509_REVOKED *rev;
+    VALUE obj;
+
+    if (!(rev = X509_REVOKED_new())) {
+       ossl_raise(eX509RevError, NULL);
+    }
+    WrapX509Rev(klass, obj, rev);
+
+    return obj;
+}
+
+static VALUE
+ossl_x509revoked_initialize(int argc, VALUE *argv, VALUE self)
+{
+    /* EMPTY */
+    return self;
+}
+
+static VALUE
+ossl_x509revoked_get_serial(VALUE self)
+{
+    X509_REVOKED *rev;
+
+    GetX509Rev(self, rev);
+
+    return asn1integer_to_num(rev->serialNumber);
+}
+
+static VALUE
+ossl_x509revoked_set_serial(VALUE self, VALUE num)
+{
+    X509_REVOKED *rev;
+
+    GetX509Rev(self, rev);
+    rev->serialNumber = num_to_asn1integer(num, rev->serialNumber);
+
+    return num;
+}
+
+static VALUE
+ossl_x509revoked_get_time(VALUE self)
+{
+    X509_REVOKED *rev;
+
+    GetX509Rev(self, rev);
+
+    return asn1time_to_time(rev->revocationDate);
+}
+
+static VALUE
+ossl_x509revoked_set_time(VALUE self, VALUE time)
+{
+    X509_REVOKED *rev;
+    time_t sec;
+
+    sec = time_to_time_t(time);
+    GetX509Rev(self, rev);
+    if (!X509_time_adj(rev->revocationDate, 0, &sec)) {
+       ossl_raise(eX509RevError, NULL);
+    }
+
+    return time;
+}
+/*
+ * Gets X509v3 extensions as array of X509Ext objects
+ */
+static VALUE
+ossl_x509revoked_get_extensions(VALUE self)
+{
+    X509_REVOKED *rev;
+    int count, i;
+    X509_EXTENSION *ext;
+    VALUE ary;
+
+    GetX509Rev(self, rev);
+    count = X509_REVOKED_get_ext_count(rev);
+    if (count < 0) {
+       OSSL_Debug("count < 0???");
+       return rb_ary_new();
+    }
+    ary = rb_ary_new2(count);
+    for (i=0; i<count; i++) {
+       ext = X509_REVOKED_get_ext(rev, i);
+       rb_ary_push(ary, ossl_x509ext_new(ext));
+    }
+
+    return ary;
+}
+
+/*
+ * Sets X509_EXTENSIONs
+ */
+static VALUE
+ossl_x509revoked_set_extensions(VALUE self, VALUE ary)
+{
+    X509_REVOKED *rev;
+    X509_EXTENSION *ext;
+    int i;
+    VALUE item;
+
+    Check_Type(ary, T_ARRAY);
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       OSSL_Check_Kind(RARRAY_PTR(ary)[i], cX509Ext);
+    }
+    GetX509Rev(self, rev);
+    sk_X509_EXTENSION_pop_free(rev->extensions, X509_EXTENSION_free);
+    rev->extensions = NULL;
+    for (i=0; i<RARRAY_LEN(ary); i++) {
+       item = RARRAY_PTR(ary)[i];
+       ext = DupX509ExtPtr(item);
+       if(!X509_REVOKED_add_ext(rev, ext, -1)) {
+           ossl_raise(eX509RevError, NULL);
+       }
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_x509revoked_add_extension(VALUE self, VALUE ext)
+{
+    X509_REVOKED *rev;
+
+    GetX509Rev(self, rev);
+    if(!X509_REVOKED_add_ext(rev, DupX509ExtPtr(ext), -1)) {
+       ossl_raise(eX509RevError, NULL);
+    }
+
+    return ext;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509revoked()
+{
+    eX509RevError = rb_define_class_under(mX509, "RevokedError", eOSSLError);
+
+    cX509Rev = rb_define_class_under(mX509, "Revoked", rb_cObject);
+
+    rb_define_alloc_func(cX509Rev, ossl_x509revoked_alloc);
+    rb_define_method(cX509Rev, "initialize", ossl_x509revoked_initialize, -1);
+
+    rb_define_method(cX509Rev, "serial", ossl_x509revoked_get_serial, 0);
+    rb_define_method(cX509Rev, "serial=", ossl_x509revoked_set_serial, 1);
+    rb_define_method(cX509Rev, "time", ossl_x509revoked_get_time, 0);
+    rb_define_method(cX509Rev, "time=", ossl_x509revoked_set_time, 1);
+    rb_define_method(cX509Rev, "extensions", ossl_x509revoked_get_extensions, 0);
+    rb_define_method(cX509Rev, "extensions=", ossl_x509revoked_set_extensions, 1);
+    rb_define_method(cX509Rev, "add_extension", ossl_x509revoked_add_extension, 1);
+}
+
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509store.c b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ossl_x509store.c
new file mode 100644 (file)
index 0000000..5d341c5
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2002  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#include "ossl.h"
+
+#define WrapX509Store(klass, obj, st) do { \
+    if (!(st)) { \
+       ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, X509_STORE_free, (st)); \
+} while (0)
+#define GetX509Store(obj, st) do { \
+    Data_Get_Struct((obj), X509_STORE, (st)); \
+    if (!(st)) { \
+       ossl_raise(rb_eRuntimeError, "STORE wasn't initialized!"); \
+    } \
+} while (0)
+#define SafeGetX509Store(obj, st) do { \
+    OSSL_Check_Kind((obj), cX509Store); \
+    GetX509Store((obj), (st)); \
+} while (0)
+
+#define WrapX509StCtx(klass, obj, ctx) do { \
+    if (!(ctx)) { \
+       ossl_raise(rb_eRuntimeError, "STORE_CTX wasn't initialized!"); \
+    } \
+    (obj) = Data_Wrap_Struct((klass), 0, ossl_x509stctx_free, (ctx)); \
+} while (0)
+#define GetX509StCtx(obj, ctx) do { \
+    Data_Get_Struct((obj), X509_STORE_CTX, (ctx)); \
+    if (!(ctx)) { \
+       ossl_raise(rb_eRuntimeError, "STORE_CTX is out of scope!"); \
+    } \
+} while (0)
+#define SafeGetX509StCtx(obj, storep) do { \
+    OSSL_Check_Kind((obj), cX509StoreContext); \
+    GetX509Store((obj), (ctx)); \
+} while (0)
+
+/*
+ * Classes
+ */
+VALUE cX509Store;
+VALUE cX509StoreContext;
+VALUE eX509StoreError;
+
+/*
+ * Public functions
+ */
+VALUE
+ossl_x509store_new(X509_STORE *store)
+{
+    VALUE obj;
+
+    WrapX509Store(cX509Store, obj, store);
+
+    return obj;
+}
+
+X509_STORE *
+GetX509StorePtr(VALUE obj)
+{
+    X509_STORE *store;
+
+    SafeGetX509Store(obj, store);
+
+    return store;
+}
+
+X509_STORE *
+DupX509StorePtr(VALUE obj)
+{
+    X509_STORE *store;
+
+    SafeGetX509Store(obj, store);
+    CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE);
+
+    return store;
+}
+
+/*
+ * Private functions
+ */
+static VALUE
+ossl_x509store_alloc(VALUE klass)
+{
+    X509_STORE *store;
+    VALUE obj;
+
+    if((store = X509_STORE_new()) == NULL){
+        ossl_raise(eX509StoreError, NULL);
+    }
+    WrapX509Store(klass, obj, store);
+
+    return obj;
+}
+
+/*
+ * General callback for OpenSSL verify
+ */
+static VALUE
+ossl_x509store_set_vfy_cb(VALUE self, VALUE cb)
+{
+    X509_STORE *store;
+
+    GetX509Store(self, store);
+    X509_STORE_set_ex_data(store, ossl_verify_cb_idx, (void*)cb);
+    rb_iv_set(self, "@verify_callback", cb);
+
+    return cb;
+}
+
+
+/*
+ * call-seq:
+ *    X509::Store.new => store
+ *
+ */
+static VALUE
+ossl_x509store_initialize(int argc, VALUE *argv, VALUE self)
+{
+    X509_STORE *store;
+
+/* BUG: This method takes any number of arguments but appears to ignore them. */
+    GetX509Store(self, store);
+    store->ex_data.sk = NULL;
+    X509_STORE_set_verify_cb_func(store, ossl_verify_cb);
+    ossl_x509store_set_vfy_cb(self, Qnil);
+
+#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
+    rb_iv_set(self, "@flags", INT2NUM(0));
+    rb_iv_set(self, "@purpose", INT2NUM(0));
+    rb_iv_set(self, "@trust", INT2NUM(0));
+#endif
+
+    /* last verification status */
+    rb_iv_set(self, "@error", Qnil);
+    rb_iv_set(self, "@error_string", Qnil);
+    rb_iv_set(self, "@chain", Qnil);
+    rb_iv_set(self, "@time", Qnil);
+
+    return self;
+}
+
+static VALUE
+ossl_x509store_set_flags(VALUE self, VALUE flags)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+    X509_STORE *store;
+    long f = NUM2LONG(flags);
+
+    GetX509Store(self, store);
+    X509_STORE_set_flags(store, f);
+#else
+    rb_iv_set(self, "@flags", flags);
+#endif
+
+    return flags;
+}
+
+static VALUE
+ossl_x509store_set_purpose(VALUE self, VALUE purpose)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+    X509_STORE *store;
+    int p = NUM2INT(purpose);
+
+    GetX509Store(self, store);
+    X509_STORE_set_purpose(store, p);
+#else
+    rb_iv_set(self, "@purpose", purpose);
+#endif
+
+    return purpose;
+}
+
+static VALUE
+ossl_x509store_set_trust(VALUE self, VALUE trust)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+    X509_STORE *store;
+    int t = NUM2INT(trust);
+
+    GetX509Store(self, store);
+    X509_STORE_set_trust(store, t);
+#else
+    rb_iv_set(self, "@trust", trust);
+#endif
+
+    return trust;
+}
+
+static VALUE
+ossl_x509store_set_time(VALUE self, VALUE time)
+{
+    rb_iv_set(self, "@time", time);
+    return time;
+}
+
+static VALUE
+ossl_x509store_add_file(VALUE self, VALUE file)
+{
+    X509_STORE *store;
+    X509_LOOKUP *lookup;
+    char *path = NULL;
+
+    if(file != Qnil){
+        SafeStringValue(file);
+       path = RSTRING_PTR(file);
+    }
+    GetX509Store(self, store);
+    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
+    if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
+    if(X509_LOOKUP_load_file(lookup, path, X509_FILETYPE_PEM) != 1){
+        ossl_raise(eX509StoreError, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_x509store_add_path(VALUE self, VALUE dir)
+{
+    X509_STORE *store;
+    X509_LOOKUP *lookup;
+    char *path = NULL;
+
+    if(dir != Qnil){
+        SafeStringValue(dir);
+       path = RSTRING_PTR(dir);
+    }
+    GetX509Store(self, store);
+    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir());
+    if(lookup == NULL) ossl_raise(eX509StoreError, NULL);
+    if(X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM) != 1){
+        ossl_raise(eX509StoreError, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_x509store_set_default_paths(VALUE self)
+{
+    X509_STORE *store;
+
+    GetX509Store(self, store);
+    if (X509_STORE_set_default_paths(store) != 1){
+        ossl_raise(eX509StoreError, NULL);
+    }
+
+    return Qnil;
+}
+
+static VALUE
+ossl_x509store_add_cert(VALUE self, VALUE arg)
+{
+    X509_STORE *store;
+    X509 *cert;
+
+    cert = GetX509CertPtr(arg); /* NO NEED TO DUP */
+    GetX509Store(self, store);
+    if (X509_STORE_add_cert(store, cert) != 1){
+        ossl_raise(eX509StoreError, NULL);
+    }
+
+    return self;
+}
+
+static VALUE
+ossl_x509store_add_crl(VALUE self, VALUE arg)
+{
+    X509_STORE *store;
+    X509_CRL *crl;
+
+    crl = GetX509CRLPtr(arg); /* NO NEED TO DUP */
+    GetX509Store(self, store);
+    if (X509_STORE_add_crl(store, crl) != 1){
+        ossl_raise(eX509StoreError, NULL);
+    }
+
+    return self;
+}
+
+static VALUE ossl_x509stctx_get_err(VALUE);
+static VALUE ossl_x509stctx_get_err_string(VALUE);
+static VALUE ossl_x509stctx_get_chain(VALUE);
+
+static VALUE
+ossl_x509store_verify(int argc, VALUE *argv, VALUE self)
+{
+    VALUE cert, chain;
+    VALUE ctx, proc, result;
+
+    rb_scan_args(argc, argv, "11", &cert, &chain);
+    ctx = rb_funcall(cX509StoreContext, rb_intern("new"), 3, self, cert, chain);
+    proc = rb_block_given_p() ?  rb_block_proc() :
+          rb_iv_get(self, "@verify_callback");
+    rb_iv_set(ctx, "@verify_callback", proc);
+    result = rb_funcall(ctx, rb_intern("verify"), 0);
+
+    rb_iv_set(self, "@error", ossl_x509stctx_get_err(ctx));
+    rb_iv_set(self, "@error_string", ossl_x509stctx_get_err_string(ctx));
+    rb_iv_set(self, "@chain", ossl_x509stctx_get_chain(ctx));
+
+    return result;
+}
+
+/*
+ * Public Functions
+ */
+static void ossl_x509stctx_free(X509_STORE_CTX*);
+
+VALUE
+ossl_x509stctx_new(X509_STORE_CTX *ctx)
+{
+    VALUE obj;
+
+    WrapX509StCtx(cX509StoreContext, obj, ctx);
+
+    return obj;
+}
+
+VALUE
+ossl_x509stctx_clear_ptr(VALUE obj)
+{
+    OSSL_Check_Kind(obj, cX509StoreContext);
+    RDATA(obj)->data = NULL;
+
+    return obj;
+}
+
+/*
+ * Private functions
+ */
+static void
+ossl_x509stctx_free(X509_STORE_CTX *ctx)
+{
+    if(ctx->untrusted)
+       sk_X509_pop_free(ctx->untrusted, X509_free);
+    if(ctx->cert)
+       X509_free(ctx->cert);
+    X509_STORE_CTX_free(ctx);
+}
+
+static VALUE
+ossl_x509stctx_alloc(VALUE klass)
+{
+    X509_STORE_CTX *ctx;
+    VALUE obj;
+
+    if((ctx = X509_STORE_CTX_new()) == NULL){
+        ossl_raise(eX509StoreError, NULL);
+    }
+    WrapX509StCtx(klass, obj, ctx);
+
+    return obj;
+}
+
+static VALUE ossl_x509stctx_set_flags(VALUE, VALUE);
+static VALUE ossl_x509stctx_set_purpose(VALUE, VALUE);
+static VALUE ossl_x509stctx_set_trust(VALUE, VALUE);
+static VALUE ossl_x509stctx_set_time(VALUE, VALUE);
+
+static VALUE
+ossl_x509stctx_initialize(int argc, VALUE *argv, VALUE self)
+{
+    VALUE store, cert, chain, t;
+    X509_STORE_CTX *ctx;
+    X509_STORE *x509st;
+    X509 *x509 = NULL;
+    STACK_OF(X509) *x509s = NULL;
+
+    rb_scan_args(argc, argv, "12", &store, &cert, &chain);
+    GetX509StCtx(self, ctx);
+    SafeGetX509Store(store, x509st);
+    if(!NIL_P(cert)) x509 = DupX509CertPtr(cert); /* NEED TO DUP */
+    if(!NIL_P(chain)) x509s = ossl_x509_ary2sk(chain);
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+    if(X509_STORE_CTX_init(ctx, x509st, x509, x509s) != 1){
+        sk_X509_pop_free(x509s, X509_free);
+        ossl_raise(eX509StoreError, NULL);
+    }
+#else
+    X509_STORE_CTX_init(ctx, x509st, x509, x509s);
+    ossl_x509stctx_set_flags(self, rb_iv_get(store, "@flags"));
+    ossl_x509stctx_set_purpose(self, rb_iv_get(store, "@purpose"));
+    ossl_x509stctx_set_trust(self, rb_iv_get(store, "@trust"));
+#endif
+    if (!NIL_P(t = rb_iv_get(store, "@time")))
+       ossl_x509stctx_set_time(self, t);
+    rb_iv_set(self, "@verify_callback", rb_iv_get(store, "@verify_callback"));
+    rb_iv_set(self, "@cert", cert);
+
+    return self;
+}
+
+static VALUE
+ossl_x509stctx_verify(VALUE self)
+{
+    X509_STORE_CTX *ctx;
+    int result;
+
+    GetX509StCtx(self, ctx);
+    X509_STORE_CTX_set_ex_data(ctx, ossl_verify_cb_idx,
+                               (void*)rb_iv_get(self, "@verify_callback"));
+    result = X509_verify_cert(ctx);
+
+    return result ? Qtrue : Qfalse;
+}
+
+static VALUE
+ossl_x509stctx_get_chain(VALUE self)
+{
+    X509_STORE_CTX *ctx;
+    STACK_OF(X509) *chain;
+    X509 *x509;
+    int i, num;
+    VALUE ary;
+
+    GetX509StCtx(self, ctx);
+    if((chain = X509_STORE_CTX_get_chain(ctx)) == NULL){
+        return Qnil;
+    }
+    if((num = sk_X509_num(chain)) < 0){
+       OSSL_Debug("certs in chain < 0???");
+       return rb_ary_new();
+    }
+    ary = rb_ary_new2(num);
+    for(i = 0; i < num; i++) {
+       x509 = sk_X509_value(chain, i);
+       rb_ary_push(ary, ossl_x509_new(x509));
+    }
+
+    return ary;
+}
+
+static VALUE
+ossl_x509stctx_get_err(VALUE self)
+{
+    X509_STORE_CTX *ctx;
+
+    GetX509StCtx(self, ctx);
+
+    return INT2FIX(X509_STORE_CTX_get_error(ctx));
+}
+
+static VALUE
+ossl_x509stctx_set_error(VALUE self, VALUE err)
+{
+    X509_STORE_CTX *ctx;
+
+    GetX509StCtx(self, ctx);
+    X509_STORE_CTX_set_error(ctx, NUM2INT(err));
+
+    return err;
+}
+
+static VALUE
+ossl_x509stctx_get_err_string(VALUE self)
+{
+    X509_STORE_CTX *ctx;
+    long err;
+
+    GetX509StCtx(self, ctx);
+    err = X509_STORE_CTX_get_error(ctx);
+
+    return rb_str_new2(X509_verify_cert_error_string(err));
+}
+
+static VALUE
+ossl_x509stctx_get_err_depth(VALUE self)
+{
+    X509_STORE_CTX *ctx;
+
+    GetX509StCtx(self, ctx);
+
+    return INT2FIX(X509_STORE_CTX_get_error_depth(ctx));
+}
+
+static VALUE
+ossl_x509stctx_get_curr_cert(VALUE self)
+{
+    X509_STORE_CTX *ctx;
+
+    GetX509StCtx(self, ctx);
+
+    return ossl_x509_new(X509_STORE_CTX_get_current_cert(ctx));
+}
+
+static VALUE
+ossl_x509stctx_get_curr_crl(VALUE self)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x00907000L)
+    X509_STORE_CTX *ctx;
+
+    GetX509StCtx(self, ctx);
+    if(!ctx->current_crl) return Qnil;
+
+    return ossl_x509crl_new(ctx->current_crl);
+#else
+    return Qnil;
+#endif
+}
+
+static VALUE
+ossl_x509stctx_set_flags(VALUE self, VALUE flags)
+{
+    X509_STORE_CTX *store;
+    long f = NUM2LONG(flags);
+
+    GetX509StCtx(self, store);
+    X509_STORE_CTX_set_flags(store, f);
+
+    return flags;
+}
+
+static VALUE
+ossl_x509stctx_set_purpose(VALUE self, VALUE purpose)
+{
+    X509_STORE_CTX *store;
+    int p = NUM2INT(purpose);
+
+    GetX509StCtx(self, store);
+    X509_STORE_CTX_set_purpose(store, p);
+
+    return purpose;
+}
+
+static VALUE
+ossl_x509stctx_set_trust(VALUE self, VALUE trust)
+{
+    X509_STORE_CTX *store;
+    int t = NUM2INT(trust);
+
+    GetX509StCtx(self, store);
+    X509_STORE_CTX_set_trust(store, t);
+
+    return trust;
+}
+
+/*
+ * call-seq:
+ *    storectx.time = time => time
+ */
+static VALUE
+ossl_x509stctx_set_time(VALUE self, VALUE time)
+{
+    X509_STORE_CTX *store;
+    long t;
+
+    t = NUM2LONG(rb_Integer(time));
+    GetX509StCtx(self, store);
+    X509_STORE_CTX_set_time(store, 0, t);
+
+    return time;
+}
+
+/*
+ * INIT
+ */
+void
+Init_ossl_x509store()
+{
+    VALUE x509stctx;
+
+    eX509StoreError = rb_define_class_under(mX509, "StoreError", eOSSLError);
+
+    cX509Store = rb_define_class_under(mX509, "Store", rb_cObject);
+    rb_attr(cX509Store, rb_intern("verify_callback"), 1, 0, Qfalse);
+    rb_attr(cX509Store, rb_intern("error"), 1, 0, Qfalse);
+    rb_attr(cX509Store, rb_intern("error_string"), 1, 0, Qfalse);
+    rb_attr(cX509Store, rb_intern("chain"), 1, 0, Qfalse);
+    rb_define_alloc_func(cX509Store, ossl_x509store_alloc);
+    rb_define_method(cX509Store, "initialize",   ossl_x509store_initialize, -1);
+    rb_define_method(cX509Store, "verify_callback=", ossl_x509store_set_vfy_cb, 1);
+    rb_define_method(cX509Store, "flags=",       ossl_x509store_set_flags, 1);
+    rb_define_method(cX509Store, "purpose=",     ossl_x509store_set_purpose, 1);
+    rb_define_method(cX509Store, "trust=",       ossl_x509store_set_trust, 1);
+    rb_define_method(cX509Store, "time=",        ossl_x509store_set_time, 1);
+    rb_define_method(cX509Store, "add_path",     ossl_x509store_add_path, 1);
+    rb_define_method(cX509Store, "add_file",     ossl_x509store_add_file, 1);
+    rb_define_method(cX509Store, "set_default_paths", ossl_x509store_set_default_paths, 0);
+    rb_define_method(cX509Store, "add_cert",     ossl_x509store_add_cert, 1);
+    rb_define_method(cX509Store, "add_crl",      ossl_x509store_add_crl, 1);
+    rb_define_method(cX509Store, "verify",       ossl_x509store_verify, -1);
+
+    cX509StoreContext = rb_define_class_under(mX509,"StoreContext",rb_cObject);
+    x509stctx = cX509StoreContext;
+    rb_define_alloc_func(cX509StoreContext, ossl_x509stctx_alloc);
+    rb_define_method(x509stctx,"initialize",  ossl_x509stctx_initialize, -1);
+    rb_define_method(x509stctx,"verify",      ossl_x509stctx_verify, 0);
+    rb_define_method(x509stctx,"chain",       ossl_x509stctx_get_chain,0);
+    rb_define_method(x509stctx,"error",       ossl_x509stctx_get_err, 0);
+    rb_define_method(x509stctx,"error=",      ossl_x509stctx_set_error, 1);
+    rb_define_method(x509stctx,"error_string",ossl_x509stctx_get_err_string,0);
+    rb_define_method(x509stctx,"error_depth", ossl_x509stctx_get_err_depth, 0);
+    rb_define_method(x509stctx,"current_cert",ossl_x509stctx_get_curr_cert, 0);
+    rb_define_method(x509stctx,"current_crl", ossl_x509stctx_get_curr_crl, 0);
+    rb_define_method(x509stctx,"flags=",      ossl_x509stctx_set_flags, 1);
+    rb_define_method(x509stctx,"purpose=",    ossl_x509stctx_set_purpose, 1);
+    rb_define_method(x509stctx,"trust=",      ossl_x509stctx_set_trust, 1);
+    rb_define_method(x509stctx,"time=",       ossl_x509stctx_set_time, 1);
+
+}
diff --git a/ruby-openssl-cms-1-9-3/ext/openssl_cms/ruby_missing.h b/ruby-openssl-cms-1-9-3/ext/openssl_cms/ruby_missing.h
new file mode 100644 (file)
index 0000000..9a537bb
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * $Id$
+ * 'OpenSSL for Ruby' project
+ * Copyright (C) 2001-2003  Michal Rokos <m.rokos@sh.cvut.cz>
+ * All rights reserved.
+ */
+/*
+ * This program is licenced under the same licence as Ruby.
+ * (See the file 'LICENCE'.)
+ */
+#if !defined(_OSSL_RUBY_MISSING_H_)
+#define _OSSL_RUBY_MISSING_H_
+
+#define rb_define_copy_func(klass, func) \
+       rb_define_method((klass), "initialize_copy", (func), 1)
+
+
+#ifndef GetReadFile
+#define FPTR_TO_FD(fptr) ((fptr)->fd)
+#else
+#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
+#endif
+
+#ifndef HAVE_RB_IO_T
+#define rb_io_t OpenFile
+#endif
+
+#ifndef HAVE_RB_STR_SET_LEN
+/* these methods should probably be backported to 1.8 */
+#define rb_str_set_len(str, length) do {       \
+       RSTRING(str)->ptr[(length)] = 0;                \
+       RSTRING(str)->len = (length);           \
+} while(0)
+#endif /* ! HAVE_RB_STR_SET_LEN */
+
+#ifndef HAVE_RB_BLOCK_CALL
+/* the openssl module doesn't use arg[3-4] and arg2 is always rb_each */
+#define rb_block_call(arg1, arg2, arg3, arg4, arg5, arg6) rb_iterate(rb_each, (arg1), (arg5), (arg6))
+#endif /* ! HAVE_RB_BLOCK_CALL */
+
+#ifdef PRIsVALUE
+# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
+# define RB_OBJ_STRING(obj) (obj)
+#else
+# define PRIsVALUE "s"
+# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
+# define RB_OBJ_STRING(obj) StringValueCStr(obj)
+#endif
+
+#endif /* _OSSL_RUBY_MISSING_H_ */
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms.rb
new file mode 100644 (file)
index 0000000..2769b83
--- /dev/null
@@ -0,0 +1,29 @@
+=begin
+= $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions
+
+= Info
+  'OpenSSL for Ruby 2' project
+  Copyright (C) 2002  Michal Rokos <m.rokos@sh.cvut.cz>
+  All rights reserved.
+
+= Licence
+  This program is licenced under the same licence as Ruby.
+  (See the file 'LICENCE'.)
+
+= Version
+  $Id$
+=end
+
+if Object.const_defined? :OpenSSL
+  Object.send(:remove_const, :OpenSSL)
+end
+
+require 'openssl_cms.so'
+
+require 'openssl_cms/bn'
+require 'openssl_cms/cipher'
+require 'openssl_cms/config'
+require 'openssl_cms/digest'
+require 'openssl_cms/ssl-internal'
+require 'openssl_cms/x509-internal'
+
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/bn.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/bn.rb
new file mode 100644 (file)
index 0000000..b2fca16
--- /dev/null
@@ -0,0 +1,35 @@
+#--
+#
+# $RCSfile$
+#
+# = Ruby-space definitions that completes C-space funcs for BN
+# 
+# = Info
+# 'OpenSSL for Ruby 2' project
+# Copyright (C) 2002  Michal Rokos <m.rokos@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
+  class BN
+    include Comparable
+  end # BN
+end # OpenSSL
+
+##
+# Add double dispatch to Integer
+#
+class Integer
+  def to_bn
+    OpenSSL::BN::new(self.to_s(16), 16)
+  end
+end # Integer
+
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/buffering.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/buffering.rb
new file mode 100644 (file)
index 0000000..51bc968
--- /dev/null
@@ -0,0 +1,449 @@
+=begin
+= $RCSfile$ -- Buffering mix-in module.
+
+= Info
+  'OpenSSL for Ruby 2' project
+  Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+  All rights reserved.
+
+= Licence
+  This program is licenced under the same licence as Ruby.
+  (See the file 'LICENCE'.)
+
+= Version
+  $Id$
+=end
+
+##
+# OpenSSL IO buffering mix-in module.
+#
+# This module allows an OpenSSL::SSL::SSLSocket to behave like an IO.
+
+module OpenSSL::Buffering
+  include Enumerable
+
+  ##
+  # The "sync mode" of the SSLSocket.
+  #
+  # See IO#sync for full details.
+
+  attr_accessor :sync
+
+  ##
+  # Default size to read from or write to the SSLSocket for buffer operations.
+
+  BLOCK_SIZE = 1024*16
+
+  def initialize(*args)
+    @eof = false
+    @rbuffer = ""
+    @sync = @io.sync
+  end
+
+  #
+  # for reading.
+  #
+  private
+
+  ##
+  # Fills the buffer from the underlying SSLSocket
+
+  def fill_rbuff
+    begin
+      @rbuffer << self.sysread(BLOCK_SIZE)
+    rescue Errno::EAGAIN
+      retry
+    rescue EOFError
+      @eof = true
+    end
+  end
+
+  ##
+  # Consumes +size+ bytes from the buffer
+
+  def consume_rbuff(size=nil)
+    if @rbuffer.empty?
+      nil
+    else
+      size = @rbuffer.size unless size
+      ret = @rbuffer[0, size]
+      @rbuffer[0, size] = ""
+      ret
+    end
+  end
+
+  public
+
+  ##
+  # Reads +size+ bytes from the stream.  If +buf+ is provided it must
+  # reference a string which will receive the data.
+  #
+  # See IO#read for full details.
+
+  def read(size=nil, buf=nil)
+    if size == 0
+      if buf
+        buf.clear
+        return buf
+      else
+        return ""
+      end
+    end
+    until @eof
+      break if size && size <= @rbuffer.size
+      fill_rbuff
+    end
+    ret = consume_rbuff(size) || ""
+    if buf
+      buf.replace(ret)
+      ret = buf
+    end
+    (size && ret.empty?) ? nil : ret
+  end
+
+  ##
+  # Reads at most +maxlen+ bytes from the stream.  If +buf+ is provided it
+  # must reference a string which will receive the data.
+  #
+  # See IO#readpartial for full details.
+
+  def readpartial(maxlen, buf=nil)
+    if maxlen == 0
+      if buf
+        buf.clear
+        return buf
+      else
+        return ""
+      end
+    end
+    if @rbuffer.empty?
+      begin
+        return sysread(maxlen, buf)
+      rescue Errno::EAGAIN
+        retry
+      end
+    end
+    ret = consume_rbuff(maxlen)
+    if buf
+      buf.replace(ret)
+      ret = buf
+    end
+    raise EOFError if ret.empty?
+    ret
+  end
+
+  ##
+  # Reads at most +maxlen+ bytes in the non-blocking manner.
+  #
+  # When no data can be read without blocking it raises
+  # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
+  #
+  # IO::WaitReadable means SSL needs to read internally so read_nonblock
+  # should be called again when the underlying IO is readable.
+  #
+  # IO::WaitWritable means SSL needs to write internally so read_nonblock
+  # should be called again after the underlying IO is writable.
+  #
+  # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows:
+  #
+  #   # emulates blocking read (readpartial).
+  #   begin
+  #     result = ssl.read_nonblock(maxlen)
+  #   rescue IO::WaitReadable
+  #     IO.select([io])
+  #     retry
+  #   rescue IO::WaitWritable
+  #     IO.select(nil, [io])
+  #     retry
+  #   end
+  #
+  # Note that one reason that read_nonblock writes to the underlying IO is
+  # when the peer requests a new TLS/SSL handshake.  See openssl the FAQ for
+  # more details.  http://www.openssl.org/support/faq.html
+
+  def read_nonblock(maxlen, buf=nil)
+    if maxlen == 0
+      if buf
+        buf.clear
+        return buf
+      else
+        return ""
+      end
+    end
+    if @rbuffer.empty?
+      return sysread_nonblock(maxlen, buf)
+    end
+    ret = consume_rbuff(maxlen)
+    if buf
+      buf.replace(ret)
+      ret = buf
+    end
+    raise EOFError if ret.empty?
+    ret
+  end
+
+  ##
+  # Reads the next "line+ from the stream.  Lines are separated by +eol+.  If
+  # +limit+ is provided the result will not be longer than the given number of
+  # bytes.
+  #
+  # +eol+ may be a String or Regexp.
+  #
+  # Unlike IO#gets the line read will not be assigned to +$_+.
+  #
+  # Unlike IO#gets the separator must be provided if a limit is provided.
+
+  def gets(eol=$/, limit=nil)
+    idx = @rbuffer.index(eol)
+    until @eof
+      break if idx
+      fill_rbuff
+      idx = @rbuffer.index(eol)
+    end
+    if eol.is_a?(Regexp)
+      size = idx ? idx+$&.size : nil
+    else
+      size = idx ? idx+eol.size : nil
+    end
+    if limit and limit >= 0
+      size = [size, limit].min
+    end
+    consume_rbuff(size)
+  end
+
+  ##
+  # Executes the block for every line in the stream where lines are separated
+  # by +eol+.
+  #
+  # See also #gets
+
+  def each(eol=$/)
+    while line = self.gets(eol)
+      yield line
+    end
+  end
+  alias each_line each
+
+  ##
+  # Reads lines from the stream which are separated by +eol+.
+  #
+  # See also #gets
+
+  def readlines(eol=$/)
+    ary = []
+    while line = self.gets(eol)
+      ary << line
+    end
+    ary
+  end
+
+  ##
+  # Reads a line from the stream which is separated by +eol+.
+  #
+  # Raises EOFError if at end of file.
+
+  def readline(eol=$/)
+    raise EOFError if eof?
+    gets(eol)
+  end
+
+  ##
+  # Reads one character from the stream.  Returns nil if called at end of
+  # file.
+
+  def getc
+    read(1)
+  end
+
+  ##
+  # Calls the given block once for each byte in the stream.
+
+  def each_byte # :yields: byte
+    while c = getc
+      yield(c.ord)
+    end
+  end
+
+  ##
+  # Reads a one-character string from the stream.  Raises an EOFError at end
+  # of file.
+
+  def readchar
+    raise EOFError if eof?
+    getc
+  end
+
+  ##
+  # Pushes character +c+ back onto the stream such that a subsequent buffered
+  # character read will return it.
+  #
+  # Unlike IO#getc multiple bytes may be pushed back onto the stream.
+  #
+  # Has no effect on unbuffered reads (such as #sysread).
+
+  def ungetc(c)
+    @rbuffer[0,0] = c.chr
+  end
+
+  ##
+  # Returns true if the stream is at file which means there is no more data to
+  # be read.
+
+  def eof?
+    fill_rbuff if !@eof && @rbuffer.empty?
+    @eof && @rbuffer.empty?
+  end
+  alias eof eof?
+
+  #
+  # for writing.
+  #
+  private
+
+  ##
+  # Writes +s+ to the buffer.  When the buffer is full or #sync is true the
+  # buffer is flushed to the underlying socket.
+
+  def do_write(s)
+    @wbuffer = "" unless defined? @wbuffer
+    @wbuffer << s
+    @wbuffer.force_encoding(Encoding::BINARY)
+    @sync ||= false
+    if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/)
+      remain = idx ? idx + $/.size : @wbuffer.length
+      nwritten = 0
+      while remain > 0
+        str = @wbuffer[nwritten,remain]
+        begin
+          nwrote = syswrite(str)
+        rescue Errno::EAGAIN
+          retry
+        end
+        remain -= nwrote
+        nwritten += nwrote
+      end
+      @wbuffer[0,nwritten] = ""
+    end
+  end
+
+  public
+
+  ##
+  # Writes +s+ to the stream.  If the argument is not a string it will be
+  # converted using String#to_s.  Returns the number of bytes written.
+
+  def write(s)
+    do_write(s)
+    s.bytesize
+  end
+
+  ##
+  # Writes +str+ in the non-blocking manner.
+  #
+  # If there is buffered data, it is flushed first.  This may block.
+  #
+  # write_nonblock returns number of bytes written to the SSL connection.
+  #
+  # When no data can be written without blocking it raises
+  # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
+  #
+  # IO::WaitReadable means SSL needs to read internally so write_nonblock
+  # should be called again after the underlying IO is readable.
+  #
+  # IO::WaitWritable means SSL needs to write internally so write_nonblock
+  # should be called again after underlying IO is writable.
+  #
+  # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows.
+  #
+  #   # emulates blocking write.
+  #   begin
+  #     result = ssl.write_nonblock(str)
+  #   rescue IO::WaitReadable
+  #     IO.select([io])
+  #     retry
+  #   rescue IO::WaitWritable
+  #     IO.select(nil, [io])
+  #     retry
+  #   end
+  #
+  # Note that one reason that write_nonblock reads from the underlying IO
+  # is when the peer requests a new TLS/SSL handshake.  See the openssl FAQ
+  # for more details.  http://www.openssl.org/support/faq.html
+
+  def write_nonblock(s)
+    flush
+    syswrite_nonblock(s)
+  end
+
+  ##
+  # Writes +s+ to the stream.  +s+ will be converted to a String using
+  # String#to_s.
+
+  def << (s)
+    do_write(s)
+    self
+  end
+
+  ##
+  # Writes +args+ to the stream along with a record separator.
+  #
+  # See IO#puts for full details.
+
+  def puts(*args)
+    s = ""
+    if args.empty?
+      s << "\n"
+    end
+    args.each{|arg|
+      s << arg.to_s
+      if $/ && /\n\z/ !~ s
+        s << "\n"
+      end
+    }
+    do_write(s)
+    nil
+  end
+
+  ##
+  # Writes +args+ to the stream.
+  #
+  # See IO#print for full details.
+
+  def print(*args)
+    s = ""
+    args.each{ |arg| s << arg.to_s }
+    do_write(s)
+    nil
+  end
+
+  ##
+  # Formats and writes to the stream converting parameters under control of
+  # the format string.
+  #
+  # See Kernel#sprintf for format string details.
+
+  def printf(s, *args)
+    do_write(s % args)
+    nil
+  end
+
+  ##
+  # Flushes buffered data to the SSLSocket.
+
+  def flush
+    osync = @sync
+    @sync = true
+    do_write ""
+    return self
+  ensure
+    @sync = osync
+  end
+
+  ##
+  # Closes the SSLSocket and flushes any unwritten data.
+
+  def close
+    flush rescue nil
+    sysclose
+  end
+end
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/cipher.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/cipher.rb
new file mode 100644 (file)
index 0000000..eb146fb
--- /dev/null
@@ -0,0 +1,65 @@
+#--
+#
+# $RCSfile$
+#
+# = Ruby-space predefined Cipher subclasses
+# 
+# = Info
+# 'OpenSSL for Ruby 2' project
+# Copyright (C) 2002  Michal Rokos <m.rokos@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
+  class Cipher
+    %w(AES CAST5 BF DES IDEA RC2 RC4 RC5).each{|name|
+      klass = Class.new(Cipher){
+        define_method(:initialize){|*args|
+          cipher_name = args.inject(name){|n, arg| "#{n}-#{arg}" }
+          super(cipher_name)
+        }
+      }
+      const_set(name, klass)
+    }
+
+    %w(128 192 256).each{|keylen|
+      klass = Class.new(Cipher){
+        define_method(:initialize){|mode|
+          mode ||= "CBC"
+          cipher_name = "AES-#{keylen}-#{mode}"
+          super(cipher_name)
+        }
+      }
+      const_set("AES#{keylen}", klass)
+    }
+
+    # Generate, set, and return a random key.
+    # You must call cipher.encrypt or cipher.decrypt before calling this method.
+    def random_key
+      str = OpenSSL::Random.random_bytes(self.key_len)
+      self.key = str
+      return str
+    end
+
+    # Generate, set, and return a random iv.
+    # You must call cipher.encrypt or cipher.decrypt before calling this method.
+    def random_iv
+      str = OpenSSL::Random.random_bytes(self.iv_len)
+      self.iv = str
+      return str
+    end
+
+    # This class is only provided for backwards compatibility.  Use OpenSSL::Cipher in the future.
+    class Cipher < Cipher
+      # add warning
+    end
+  end # Cipher
+end # OpenSSL
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/config.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/config.rb
new file mode 100644 (file)
index 0000000..24a54c9
--- /dev/null
@@ -0,0 +1,313 @@
+=begin
+= Ruby-space definitions that completes C-space funcs for Config
+
+= Info
+  Copyright (C) 2010  Hiroshi Nakamura <nahi@ruby-lang.org>
+
+= Licence
+  This program is licenced under the same licence as Ruby.
+  (See the file 'LICENCE'.)
+
+=end
+
+require 'stringio'
+
+module OpenSSL
+  class Config
+    include Enumerable
+
+    class << self
+      def parse(str)
+        c = new()
+        parse_config(StringIO.new(str)).each do |section, hash|
+          c[section] = hash
+        end
+        c
+      end
+
+      alias load new
+
+      def parse_config(io)
+        begin
+          parse_config_lines(io)
+        rescue ConfigError => e
+          e.message.replace("error in line #{io.lineno}: " + e.message)
+          raise
+        end
+      end
+
+      def get_key_string(data, section, key) # :nodoc:
+        if v = data[section] && data[section][key]
+          return v
+        elsif section == 'ENV'
+          if v = ENV[key]
+            return v
+          end
+        end
+        if v = data['default'] && data['default'][key]
+          return v
+        end
+      end
+
+    private
+
+      def parse_config_lines(io)
+        section = 'default'
+        data = {section => {}}
+        while definition = get_definition(io)
+          definition = clear_comments(definition)
+          next if definition.empty?
+          if definition[0] == ?[
+            if /\[([^\]]*)\]/ =~ definition
+              section = $1.strip
+              data[section] ||= {}
+            else
+              raise ConfigError, "missing close square bracket"
+            end
+          else
+            if /\A([^:\s]*)(?:::([^:\s]*))?\s*=(.*)\z/ =~ definition
+              if $2
+                section = $1
+                key = $2
+              else
+                key = $1
+              end
+              value = unescape_value(data, section, $3)
+              (data[section] ||= {})[key] = value.strip
+            else
+              raise ConfigError, "missing equal sign"
+            end
+          end
+        end
+        data
+      end
+
+      # escape with backslash
+      QUOTE_REGEXP_SQ = /\A([^'\\]*(?:\\.[^'\\]*)*)'/
+      # escape with backslash and doubled dq
+      QUOTE_REGEXP_DQ = /\A([^"\\]*(?:""[^"\\]*|\\.[^"\\]*)*)"/
+      # escaped char map
+      ESCAPE_MAP = {
+        "r" => "\r",
+        "n" => "\n",
+        "b" => "\b",
+        "t" => "\t",
+      }
+
+      def unescape_value(data, section, value)
+        scanned = []
+        while m = value.match(/['"\\$]/)
+          scanned << m.pre_match
+          c = m[0]
+          value = m.post_match
+          case c
+          when "'"
+            if m = value.match(QUOTE_REGEXP_SQ)
+              scanned << m[1].gsub(/\\(.)/, '\\1')
+              value = m.post_match
+            else
+              break
+            end
+          when '"'
+            if m = value.match(QUOTE_REGEXP_DQ)
+              scanned << m[1].gsub(/""/, '').gsub(/\\(.)/, '\\1')
+              value = m.post_match
+            else
+              break
+            end
+          when "\\"
+            c = value.slice!(0, 1)
+            scanned << (ESCAPE_MAP[c] || c)
+          when "$"
+            ref, value = extract_reference(value)
+            refsec = section
+            if ref.index('::')
+              refsec, ref = ref.split('::', 2)
+            end
+            if v = get_key_string(data, refsec, ref)
+              scanned << v
+            else
+              raise ConfigError, "variable has no value"
+            end
+          else
+            raise 'must not reaced'
+          end
+        end
+        scanned << value
+        scanned.join
+      end
+
+      def extract_reference(value)
+        rest = ''
+        if m = value.match(/\(([^)]*)\)|\{([^}]*)\}/)
+          value = m[1] || m[2]
+          rest = m.post_match
+        elsif [?(, ?{].include?(value[0])
+          raise ConfigError, "no close brace"
+        end
+        if m = value.match(/[a-zA-Z0-9_]*(?:::[a-zA-Z0-9_]*)?/)
+          return m[0], m.post_match + rest
+        else
+          raise
+        end
+      end
+
+      def clear_comments(line)
+        # FCOMMENT
+        if m = line.match(/\A([\t\n\f ]*);.*\z/)
+          return m[1]
+        end
+        # COMMENT
+        scanned = []
+        while m = line.match(/[#'"\\]/)
+          scanned << m.pre_match
+          c = m[0]
+          line = m.post_match
+          case c
+          when '#'
+            line = nil
+            break
+          when "'", '"'
+            regexp = (c == "'") ? QUOTE_REGEXP_SQ : QUOTE_REGEXP_DQ
+            scanned << c
+            if m = line.match(regexp)
+              scanned << m[0]
+              line = m.post_match
+            else
+              scanned << line
+              line = nil
+              break
+            end
+          when "\\"
+            scanned << c
+            scanned << line.slice!(0, 1)
+          else
+            raise 'must not reaced'
+          end
+        end
+        scanned << line
+        scanned.join
+      end
+
+      def get_definition(io)
+        if line = get_line(io)
+          while /[^\\]\\\z/ =~ line
+            if extra = get_line(io)
+              line += extra
+            else
+              break
+            end
+          end
+          return line.strip
+        end
+      end
+
+      def get_line(io)
+        if line = io.gets
+          line.gsub(/[\r\n]*/, '')
+        end
+      end
+    end
+
+    def initialize(filename = nil)
+      @data = {}
+      if filename
+        File.open(filename.to_s) do |file|
+          Config.parse_config(file).each do |section, hash|
+            self[section] = hash
+          end
+        end
+      end
+    end
+
+    def get_value(section, key)
+      if section.nil?
+        raise TypeError.new('nil not allowed')
+      end
+      section = 'default' if section.empty?
+      get_key_string(section, key)
+    end
+
+    def value(arg1, arg2 = nil)
+      warn('Config#value is deprecated; use Config#get_value')
+      if arg2.nil?
+        section, key = 'default', arg1
+      else
+        section, key = arg1, arg2
+      end
+      section ||= 'default'
+      section = 'default' if section.empty?
+      get_key_string(section, key)
+    end
+
+    def add_value(section, key, value)
+      check_modify
+      (@data[section] ||= {})[key] = value
+    end
+
+    def [](section)
+      @data[section] || {}
+    end
+
+    def section(name)
+      warn('Config#section is deprecated; use Config#[]')
+      @data[name] || {}
+    end
+
+    def []=(section, pairs)
+      check_modify
+      @data[section] ||= {}
+      pairs.each do |key, value|
+        self.add_value(section, key, value)
+      end
+    end
+
+    def sections
+      @data.keys
+    end
+
+    def to_s
+      ary = []
+      @data.keys.sort.each do |section|
+        ary << "[ #{section} ]\n"
+        @data[section].keys.each do |key|
+          ary << "#{key}=#{@data[section][key]}\n"
+        end
+        ary << "\n"
+      end
+      ary.join
+    end
+
+    def each
+      @data.each do |section, hash|
+        hash.each do |key, value|
+          yield [section, key, value]
+        end
+      end
+    end
+
+    def inspect
+      "#<#{self.class.name} sections=#{sections.inspect}>"
+    end
+
+  protected
+
+    def data
+      @data
+    end
+
+  private
+
+    def initialize_copy(other)
+      @data = other.data.dup
+    end
+
+    def check_modify
+      raise TypeError.new("Insecure: can't modify OpenSSL config") if frozen?
+    end
+
+    def get_key_string(section, key)
+      Config.get_key_string(@data, section, key)
+    end
+  end
+end
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/digest.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/digest.rb
new file mode 100644 (file)
index 0000000..b470071
--- /dev/null
@@ -0,0 +1,72 @@
+#--
+#
+# $RCSfile$
+#
+# = Ruby-space predefined Digest subclasses
+# 
+# = Info
+# 'OpenSSL for Ruby 2' project
+# Copyright (C) 2002  Michal Rokos <m.rokos@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
+  class Digest
+
+    alg = %w(DSS DSS1 MD2 MD4 MD5 MDC2 RIPEMD160 SHA SHA1)
+    if OPENSSL_VERSION_NUMBER > 0x00908000
+      alg += %w(SHA224 SHA256 SHA384 SHA512)
+    end
+
+    # Return the +data+ hash computed with +name+ Digest. +name+ is either the
+    # long name or short name of a supported digest algorithm.
+    #
+    # === Examples
+    #
+    #   OpenSSL::Digest.digest("SHA256, "abc")
+    #
+    # which is equivalent to:
+    #
+    #   OpenSSL::Digest::SHA256.digest("abc")
+
+    def self.digest(name, data)
+        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)
+        }
+      }
+      singleton = (class << klass; self; end)
+      singleton.class_eval{
+        define_method(:digest){|data| Digest.digest(name, data) }
+        define_method(:hexdigest){|data| Digest.hexdigest(name, data) }
+      }
+      const_set(name, klass)
+    }
+
+    # This class is only provided for backwards compatibility.  Use OpenSSL::Digest in the future.
+    class Digest < Digest
+      def initialize(*args)
+        # add warning
+        super(*args)
+      end
+    end
+
+  end # Digest
+end # OpenSSL
+
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/ssl-internal.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/ssl-internal.rb
new file mode 100644 (file)
index 0000000..ff8a898
--- /dev/null
@@ -0,0 +1,185 @@
+=begin
+= $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
+
+= Info
+  'OpenSSL for Ruby 2' project
+  Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
+  All rights reserved.
+
+= Licence
+  This program is licenced under the same licence as Ruby.
+  (See the file 'LICENCE'.)
+
+= Version
+  $Id$
+=end
+
+require "openssl_cms/buffering"
+require "fcntl"
+
+module OpenSSL
+  module SSL
+    class SSLContext
+      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,
+      }
+
+      DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
+      DEFAULT_CERT_STORE.set_default_paths
+      if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
+        DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
+      end
+
+      def set_params(params={})
+        params = DEFAULT_PARAMS.merge(params)
+        params.each{|name, value| self.__send__("#{name}=", value) }
+        if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
+          unless self.ca_file or self.ca_path or self.cert_store
+            self.cert_store = DEFAULT_CERT_STORE
+          end
+        end
+        return params
+      end
+    end
+
+    module SocketForwarder
+      def addr
+        to_io.addr
+      end
+
+      def peeraddr
+        to_io.peeraddr
+      end
+
+      def setsockopt(level, optname, optval)
+        to_io.setsockopt(level, optname, optval)
+      end
+
+      def getsockopt(level, optname)
+        to_io.getsockopt(level, optname)
+      end
+
+      def fcntl(*args)
+        to_io.fcntl(*args)
+      end
+
+      def closed?
+        to_io.closed?
+      end
+
+      def do_not_reverse_lookup=(flag)
+        to_io.do_not_reverse_lookup = flag
+      end
+    end
+
+    module Nonblock
+      def initialize(*args)
+        flag = File::NONBLOCK
+        flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
+        @io.fcntl(Fcntl::F_SETFL, flag)
+        super
+      end
+    end
+
+    def verify_certificate_identity(cert, hostname)
+      should_verify_common_name = true
+      cert.extensions.each{|ext|
+        next if ext.oid != "subjectAltName"
+        ostr = OpenSSL::ASN1.decode(ext.to_der).value.last
+        sequence = OpenSSL::ASN1.decode(ostr.value)
+        sequence.value.each{|san|
+          case san.tag
+          when 2 # dNSName in GeneralName (RFC5280)
+            should_verify_common_name = false
+            reg = Regexp.escape(san.value).gsub(/\\\*/, "[^.]+")
+            return true if /\A#{reg}\z/i =~ hostname
+          when 7 # iPAddress in GeneralName (RFC5280)
+            should_verify_common_name = false
+            # follows GENERAL_NAME_print() in x509v3/v3_alt.c
+            if san.value.size == 4
+              return true if san.value.unpack('C*').join('.') == hostname
+            elsif san.value.size == 16
+              return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
+            end
+          end
+        }
+      }
+      if should_verify_common_name
+        cert.subject.to_a.each{|oid, value|
+          if oid == "CN"
+            reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
+            return true if /\A#{reg}\z/i =~ hostname
+          end
+        }
+      end
+      return false
+    end
+    module_function :verify_certificate_identity
+
+    class SSLSocket
+      include Buffering
+      include SocketForwarder
+      include Nonblock
+
+      def post_connection_check(hostname)
+        unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
+          raise SSLError, "hostname does not match the server certificate"
+        end
+        return true
+      end
+
+      def session
+        SSL::Session.new(self)
+      rescue SSL::Session::SessionError
+        nil
+      end
+    end
+
+    class SSLServer
+      include SocketForwarder
+      attr_accessor :start_immediately
+
+      def initialize(svr, ctx)
+        @svr = svr
+        @ctx = ctx
+        unless ctx.session_id_context
+          session_id = OpenSSL::Digest::MD5.hexdigest($0)
+          @ctx.session_id_context = session_id
+        end
+        @start_immediately = true
+      end
+
+      def to_io
+        @svr
+      end
+
+      def listen(backlog=5)
+        @svr.listen(backlog)
+      end
+
+      def shutdown(how=Socket::SHUT_RDWR)
+        @svr.shutdown(how)
+      end
+
+      def accept
+        sock = @svr.accept
+        begin
+          ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
+          ssl.sync_close = true
+          ssl.accept if @start_immediately
+          ssl
+        rescue SSLError => ex
+          sock.close
+          raise ex
+        end
+      end
+
+      def close
+        @svr.close
+      end
+    end
+  end
+end
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/ssl.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/ssl.rb
new file mode 100644 (file)
index 0000000..35b0456
--- /dev/null
@@ -0,0 +1,2 @@
+warn 'deprecated openssl_cms/ssl use: require "openssl_cms" instead of "openssl_cms/ssl"'
+require 'openssl_cms'
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/x509-internal.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/x509-internal.rb
new file mode 100644 (file)
index 0000000..47e3a6f
--- /dev/null
@@ -0,0 +1,158 @@
+=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@sh.cvut.cz>
+  All rights reserved.
+
+= Licence
+  This program is licenced under the same licence as Ruby.
+  (See the file 'LICENCE'.)
+
+= Version
+  $Id$
+=end
+
+module OpenSSL
+  module X509
+    class ExtensionFactory
+      def create_extension(*arg)
+        if arg.size > 1
+          create_ext(*arg)
+        else
+          send("create_ext_from_"+arg[0].class.name.downcase, arg[0])
+        end
+      end
+
+      def create_ext_from_array(ary)
+        raise ExtensionError, "unexpected array form" if ary.size > 3
+        create_ext(ary[0], ary[1], ary[2])
+      end
+
+      def create_ext_from_string(str) # "oid = critical, value"
+        oid, value = str.split(/=/, 2)
+        oid.strip!
+        value.strip!
+        create_ext(oid, value)
+      end
+
+      def create_ext_from_hash(hash)
+        create_ext(hash["oid"], hash["value"], hash["critical"])
+      end
+    end
+
+    class Extension
+      def to_s # "oid = critical, value"
+        str = self.oid
+        str << " = "
+        str << "critical, " if self.critical?
+        str << self.value.gsub(/\n/, ", ")
+      end
+
+      def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
+        {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
+      end
+
+      def to_a
+        [ self.oid, self.value, self.critical? ]
+      end
+    end
+
+    class Name
+      module RFC2253DN
+        Special = ',=+<>#;'
+        HexChar = /[0-9a-fA-F]/
+        HexPair = /#{HexChar}#{HexChar}/
+        HexString = /#{HexPair}+/
+        Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
+        StringChar = /[^#{Special}\\"]/
+        QuoteChar = /[^\\"]/
+        AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
+        AttributeValue = /
+          (?!["#])((?:#{StringChar}|#{Pair})*)|
+          \#(#{HexString})|
+          "((?:#{QuoteChar}|#{Pair})*)"
+        /x
+        TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/
+
+        module_function
+
+        def expand_pair(str)
+          return nil unless str
+          return str.gsub(Pair){
+            pair = $&
+            case pair.size
+            when 2 then pair[1,1]
+            when 3 then Integer("0x#{pair[1,2]}").chr
+            else raise OpenSSL::X509::NameError, "invalid pair: #{str}"
+            end
+          }
+        end
+
+        def expand_hexstring(str)
+          return nil unless str
+          der = str.gsub(HexPair){$&.to_i(16).chr }
+          a1 = OpenSSL::ASN1.decode(der)
+          return a1.value, a1.tag
+        end
+
+        def expand_value(str1, str2, str3)
+          value = expand_pair(str1)
+          value, tag = expand_hexstring(str2) unless value
+          value = expand_pair(str3) unless value
+          return value, tag
+        end
+
+        def scan(dn)
+          str = dn
+          ary = []
+          while true
+            if md = TypeAndValue.match(str)
+              remain = md.post_match
+              type = md[1]
+              value, tag = expand_value(md[2], md[3], md[4]) rescue nil
+              if value
+                type_and_value = [type, value]
+                type_and_value.push(tag) if tag
+                ary.unshift(type_and_value)
+                if remain.length > 2 && remain[0] == ?,
+                  str = remain[1..-1]
+                  next
+                elsif remain.length > 2 && remain[0] == ?+
+                  raise OpenSSL::X509::NameError,
+                    "multi-valued RDN is not supported: #{dn}"
+                elsif remain.empty?
+                  break
+                end
+              end
+            end
+            msg_dn = dn[0, dn.length - str.length] + " =>" + str
+            raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}"
+          end
+          return ary
+        end
+      end
+
+      class << self
+        def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)
+          ary = OpenSSL::X509::Name::RFC2253DN.scan(str)
+          self.new(ary, template)
+        end
+
+        def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)
+          ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) }
+          self.new(ary, template)
+        end
+
+        alias parse parse_openssl
+      end
+    end
+
+    class StoreContext
+      def cleanup
+        warn "(#{caller.first}) OpenSSL::X509::StoreContext#cleanup is deprecated with no replacement" if $VERBOSE
+      end
+    end
+  end
+end
diff --git a/ruby-openssl-cms-1-9-3/lib/openssl_cms/x509.rb b/ruby-openssl-cms-1-9-3/lib/openssl_cms/x509.rb
new file mode 100644 (file)
index 0000000..c7962ce
--- /dev/null
@@ -0,0 +1,2 @@
+warn 'deprecated openssl_cms/x509 use: require "openssl_cms" instead of "openssl_cms/x509"'
+require 'openssl_cms'
diff --git a/ruby-openssl-cms-1-9-3/metadata.yml b/ruby-openssl-cms-1-9-3/metadata.yml
new file mode 100644 (file)
index 0000000..0aa2f9b
--- /dev/null
@@ -0,0 +1,119 @@
+--- !ruby/object:Gem::Specification
+name: openssl_cms_1_9_3
+version: !ruby/object:Gem::Version
+  version: 0.0.2
+  prerelease: 
+platform: ruby
+authors:
+- Zdenek Sustr
+- Boris Parak
+autorequire: 
+bindir: bin
+cert_chain: []
+date: 2014-03-12 00:00:00.000000000 Z
+dependencies: []
+description: OpenSSL with CMS functions for Ruby 1.9.3
+email:
+- parak@cesnet.cz
+executables: []
+extensions:
+- ext/openssl_cms/extconf.rb
+extra_rdoc_files: []
+files:
+- .gitignore
+- BSDL
+- LICENSE
+- README.md
+- ext/openssl_cms/extconf.rb
+- ext/openssl_cms/openssl_missing.c
+- ext/openssl_cms/openssl_missing.h
+- ext/openssl_cms/ossl.c
+- ext/openssl_cms/ossl.h
+- ext/openssl_cms/ossl_asn1.c
+- ext/openssl_cms/ossl_asn1.h
+- ext/openssl_cms/ossl_bio.c
+- ext/openssl_cms/ossl_bio.h
+- ext/openssl_cms/ossl_bn.c
+- ext/openssl_cms/ossl_bn.h
+- ext/openssl_cms/ossl_cipher.c
+- ext/openssl_cms/ossl_cipher.h
+- ext/openssl_cms/ossl_cms.c
+- ext/openssl_cms/ossl_cms.h
+- ext/openssl_cms/ossl_config.c
+- ext/openssl_cms/ossl_config.h
+- ext/openssl_cms/ossl_digest.c
+- ext/openssl_cms/ossl_digest.h
+- ext/openssl_cms/ossl_engine.c
+- ext/openssl_cms/ossl_engine.h
+- ext/openssl_cms/ossl_hmac.c
+- ext/openssl_cms/ossl_hmac.h
+- ext/openssl_cms/ossl_ns_spki.c
+- ext/openssl_cms/ossl_ns_spki.h
+- ext/openssl_cms/ossl_ocsp.c
+- ext/openssl_cms/ossl_ocsp.h
+- ext/openssl_cms/ossl_pkcs12.c
+- ext/openssl_cms/ossl_pkcs12.h
+- ext/openssl_cms/ossl_pkcs5.c
+- ext/openssl_cms/ossl_pkcs5.h
+- ext/openssl_cms/ossl_pkcs7.c
+- ext/openssl_cms/ossl_pkcs7.h
+- ext/openssl_cms/ossl_pkey.c
+- ext/openssl_cms/ossl_pkey.h
+- ext/openssl_cms/ossl_pkey_dh.c
+- ext/openssl_cms/ossl_pkey_dsa.c
+- ext/openssl_cms/ossl_pkey_ec.c
+- ext/openssl_cms/ossl_pkey_rsa.c
+- ext/openssl_cms/ossl_rand.c
+- ext/openssl_cms/ossl_rand.h
+- ext/openssl_cms/ossl_ssl.c
+- ext/openssl_cms/ossl_ssl.h
+- ext/openssl_cms/ossl_ssl_session.c
+- ext/openssl_cms/ossl_version.h
+- ext/openssl_cms/ossl_x509.c
+- ext/openssl_cms/ossl_x509.h
+- ext/openssl_cms/ossl_x509attr.c
+- ext/openssl_cms/ossl_x509cert.c
+- ext/openssl_cms/ossl_x509crl.c
+- ext/openssl_cms/ossl_x509ext.c
+- ext/openssl_cms/ossl_x509name.c
+- ext/openssl_cms/ossl_x509req.c
+- ext/openssl_cms/ossl_x509revoked.c
+- ext/openssl_cms/ossl_x509store.c
+- ext/openssl_cms/ruby_missing.h
+- lib/openssl_cms.rb
+- lib/openssl_cms/bn.rb
+- lib/openssl_cms/buffering.rb
+- lib/openssl_cms/cipher.rb
+- lib/openssl_cms/config.rb
+- lib/openssl_cms/digest.rb
+- lib/openssl_cms/ssl-internal.rb
+- lib/openssl_cms/ssl.rb
+- lib/openssl_cms/x509-internal.rb
+- lib/openssl_cms/x509.rb
+- openssl_cms.gemspec
+homepage: https://github.com/arax/openssl-cms
+licenses:
+- https://github.com/arax/openssl-cms/blob/master/LICENSE
+post_install_message: 
+rdoc_options: []
+require_paths:
+- lib
+required_ruby_version: !ruby/object:Gem::Requirement
+  none: false
+  requirements:
+  - - ~>
+    - !ruby/object:Gem::Version
+      version: 1.9.3
+required_rubygems_version: !ruby/object:Gem::Requirement
+  none: false
+  requirements:
+  - - ! '>='
+    - !ruby/object:Gem::Version
+      version: '0'
+requirements: []
+rubyforge_project: 
+rubygems_version: 1.8.23
+signing_key: 
+specification_version: 3
+summary: OpenSSL with CMS functions for Ruby 1.9.3
+test_files: []
diff --git a/ruby-openssl-cms-1-9-3/openssl_cms.gemspec b/ruby-openssl-cms-1-9-3/openssl_cms.gemspec
new file mode 100644 (file)
index 0000000..d8fe208
--- /dev/null
@@ -0,0 +1,18 @@
+Gem::Specification.new do |gem|
+  gem.name = "openssl_cms_1_9_3"
+  gem.version = "0.0.2"
+  gem.summary = "OpenSSL with CMS functions for Ruby 1.9.3"
+  gem.authors = ["Zdenek Sustr", "Boris Parak"]
+  gem.homepage = 'https://github.com/arax/openssl-cms'
+  gem.license = 'https://github.com/arax/openssl-cms/blob/master/LICENSE'
+  gem.description = "OpenSSL with CMS functions for Ruby 1.9.3"
+  gem.email = ['parak@cesnet.cz']
+  
+  gem.files = `git ls-files`.split("\n")
+  gem.require_paths = ['lib']
+  
+  gem.extensions << "ext/openssl_cms/extconf.rb"
+  
+  gem.required_ruby_version = '~> 1.9.3'
+end
+