aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-10-20 23:54:50 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-10-20 23:54:50 +0900
commit4881e4a8b5cdefdbbc0a259959e4967bab1d81b7 (patch)
tree63b7569e1a932b03c68bca821d15f5fc485c8c71
parentbc1a67dfa9975426cf239aa3cca970f55c273966 (diff)
parent41944f14ad191a7853c567c3807a711fa2c24226 (diff)
downloadruby-openssl-history-merged.tar.gz
Merge remote-tracking branch 'ossl/master' into mergedmerged
* ossl/master: (406 commits) Make OpenSSL.debug more verbose pkey: fix possible memory leak in ossl_pkey_new() pkey: remove unused ossl_pkey_new_from_file() function test/test_pkey_*: refine sign/verify tests pkey: fix possible memory leak in PKey#verify ssl: correct return type of SSL_SESSION_get_{time,timeout}() pkey: add missing return value check in PKey#{sign,verify} pkey: tighten buffer size for signature test/test_hmac: use static test vectors test/test_cipher: use static test vectors Add link to the documentation on README.md cipher: always define Cipher#authenticated? cipher: fix documentation regarding default IV Avoid memory leak on rb_str_new() test/test_digest: compare with literals cipher: don't set dummy encryption key in Cipher#initialize test/test_ssl: suppress syntax warning pkey: allow specifying conversion form in EC::Point#to_bn fid typos [ci skip] pkey: make PKey#verify check the existence of the public key ...
-rw-r--r--.gitignore10
-rw-r--r--.travis.yml28
-rw-r--r--BSDL22
-rw-r--r--CONTRIBUTING.md130
-rw-r--r--Dockerfile1
-rw-r--r--History.md137
-rw-r--r--LICENSE.txt56
-rw-r--r--README.md65
-rw-r--r--Rakefile55
-rw-r--r--docker-compose.yml13
-rw-r--r--ext/openssl/ossl.c24
-rw-r--r--ext/openssl/ossl_asn1.c168
-rw-r--r--ext/openssl/ossl_bn.c17
-rw-r--r--ext/openssl/ossl_cipher.c77
-rw-r--r--ext/openssl/ossl_ns_spki.c7
-rw-r--r--ext/openssl/ossl_pkey.c107
-rw-r--r--ext/openssl/ossl_pkey.h1
-rw-r--r--ext/openssl/ossl_pkey_dh.c2
-rw-r--r--ext/openssl/ossl_pkey_dsa.c6
-rw-r--r--ext/openssl/ossl_pkey_ec.c62
-rw-r--r--ext/openssl/ossl_pkey_rsa.c12
-rw-r--r--ext/openssl/ossl_ssl_session.c51
-rw-r--r--ext/openssl/ossl_x509crl.c29
-rw-r--r--ext/openssl/ossl_x509name.c8
-rw-r--r--ext/openssl/ossl_x509req.c22
-rw-r--r--lib/openssl/ssl.rb20
-rw-r--r--openssl.gemspec24
-rw-r--r--test/envutil.rb311
-rw-r--r--test/test_asn1.rb310
-rw-r--r--test/test_cipher.rb482
-rw-r--r--test/test_digest.rb36
-rw-r--r--test/test_hmac.rb44
-rw-r--r--test/test_pkey_dsa.rb20
-rw-r--r--test/test_pkey_ec.rb18
-rw-r--r--test/test_pkey_rsa.rb22
-rw-r--r--test/test_ssl.rb4
-rw-r--r--test/test_x509name.rb4
-rw-r--r--test/utils.rb1
-rw-r--r--tool/ruby-openssl-docker/Dockerfile92
-rw-r--r--tool/ruby-openssl-docker/README.md5
-rwxr-xr-xtool/ruby-openssl-docker/init.sh29
-rwxr-xr-xtool/sync-with-trunk105
-rwxr-xr-xtool/update-gh-pages22
43 files changed, 1835 insertions, 824 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1be0883
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+/doc/
+/pkg/
+/tmp/
+/html/
+*.bundle
+*.so
+*.o
+ext/openssl/mkmf.log
+ext/openssl/Makefile
+ext/openssl/extconf.h
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..30d967c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,28 @@
+language: c
+sudo: required
+group: edge
+dist: trusty
+services:
+ - docker
+before_install:
+ - sudo apt-get -qq update
+install:
+ - sudo sh -c "curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose"
+ - sudo chmod +x /usr/local/bin/docker-compose
+script:
+ - docker -v
+ - docker-compose -v
+ - docker-compose build --no-cache
+ - docker-compose run test
+matrix:
+ fast_finish: true
+ include:
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=openssl-1.0.0 OSSL_MDEBUG=1
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=openssl-1.0.1 OSSL_MDEBUG=1
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=openssl-1.0.2 OSSL_MDEBUG=1
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=openssl-1.1.0 OSSL_MDEBUG=1
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=libressl-2.1
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=libressl-2.2
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=libressl-2.3
+ - env: RUBY_VERSION=ruby-2.3 OPENSSL_VERSION=libressl-2.4
+ allow_failures:
diff --git a/BSDL b/BSDL
new file mode 100644
index 0000000..a009cae
--- /dev/null
+++ b/BSDL
@@ -0,0 +1,22 @@
+Copyright (C) 1993-2013 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/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..523c555
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,130 @@
+# Contributing to Ruby OpenSSL
+
+Thank you for your interest in contributing to Ruby OpenSSL!
+
+This documentation provides an overview how you can contribute.
+
+## Bugs and feature requests
+
+Bugs and feature requests are tracked on [GitHub].
+
+If you think you found a bug, file a ticket on GitHub. Please DO NOT report
+security issues here, there is a separate procedure which is described on
+["Security at ruby-lang.org"](https://www.ruby-lang.org/en/security/).
+
+When reporting a bug, please make sure you include the version of Ruby, the
+version of openssl gem, the version of the OpenSSL library, along with a sample
+file that illustrates the problem or link to repository or gem that is
+associated with the bug.
+
+There is a number of unresolved issues and feature requests for openssl that
+need review. Before submitting a new ticket, it is recommended to check
+[known issues] and [bugs.ruby-lang.org], the previous issue tracker.
+
+## Submitting patches
+
+Patches are also very welcome!
+
+Please submit a [pull request] with your changes.
+
+Make sure that your branch does:
+
+* Have good commit messages
+* Follow Ruby's coding style ([DeveloperHowTo])
+* Pass the test suite successfully (see "Testing")
+* Add an entry to [History.md] if necessary
+
+## Testing
+
+We have a test suite!
+
+Test cases are located under the
+[`test/`](https://github.com/ruby/openssl/tree/master/test) directory.
+
+You can run it with the following three commands:
+
+```
+$ gem install rake-compiler test-unit
+$ rake compile
+$ rake test
+```
+
+### Docker
+
+You can also use Docker Compose to run tests. It can be used to check that your
+changes work correctly with various supported versions of Ruby and OpenSSL.
+
+First, you need to install [Docker](https://www.docker.com/products/docker) and
+[Docker Compose](https://www.docker.com/products/docker-compose) on your
+computer.
+
+If you're on MacOS or Windows, we recommended to use the official [Docker
+Toolbox](https://www.docker.com/products/docker-toolbox). On Linux, follow the
+instructions for your package manager. For further information, please check
+the [official documentation](https://docs.docker.com/).
+
+Once you have Docker and Docker Compose, running the following commands will
+build the container and execute the openssl tests. In this example, we will use
+Ruby version 2.3 with OpenSSL version 1.0.2.
+
+```
+$ docker-compose build
+$ export RUBY_VERSION=ruby-2.3
+$ export OPENSSL_VERSION=openssl-1.0.2
+$ docker-compose run test
+
+# You may want an interactive shell for dubugging
+$ docker-compose run debug
+```
+
+All possible values for `RUBY_VERSION` and `OPENSSL_VERSION` can be found in
+[`.travis.yml`](https://github.com/ruby/openssl/tree/master/.travis.yml).
+
+**NOTE**: these commands must be run from the openssl repository root, in order
+to use the
+[`docker-compose.yml`](https://github.com/ruby/openssl/blob/master/docker-compose.yml)
+file we have provided.
+
+This Docker image is built using the
+[Dockerfile](https://github.com/ruby/openssl/tree/master/tool/ruby-openssl-docker)
+provided in the repository.
+
+
+## Relation with Ruby source tree
+
+After Ruby 2.3, `ext/openssl` was converted into a "default gem", a library
+which ships with standard Ruby builds but can be upgraded via RubyGems. This
+means the development of this gem has migrated to a [separate
+repository][GitHub] and will be released independently.
+
+The version included in the Ruby source tree (trunk branch) is synchronized with
+the latest release.
+
+## Release policy
+
+Bug fixes (including security fixes) will be made only for the version series
+included in a stable Ruby release.
+
+## Security
+
+If you discovered a security issue, please send us in private, using the
+security issue handling procedure for Ruby core.
+
+You can either use [HackerOne] or send an email to security@ruby-lang.org.
+
+Please see [Security] page on ruby-lang.org website for details.
+
+Reported problems will be published after a fix is released.
+
+_Thanks for your contributions!_
+
+ _\- The Ruby OpenSSL team_
+
+[GitHub]: https://github.com/ruby/openssl
+[known issues]: https://github.com/ruby/openssl/issues
+[bugs.ruby-lang.org]: https://bugs.ruby-lang.org/issues?utf8=%E2%9C%93&set_filter=1&f%5B%5D=status_id&op%5Bstatus_id%5D=o&f%5B%5D=assigned_to_id&op%5Bassigned_to_id%5D=%3D&v%5Bassigned_to_id%5D%5B%5D=7150&f%5B%5D=&c%5B%5D=project&c%5B%5D=tracker&c%5B%5D=status&c%5B%5D=subject&c%5B%5D=assigned_to&c%5B%5D=updated_on&group_by=&t%5B%5D=
+[DeveloperHowTo]: https://bugs.ruby-lang.org/projects/ruby/wiki/DeveloperHowto
+[HackerOne]: https://hackerone.com/ruby
+[Security]: https://www.ruby-lang.org/en/security/
+[pull request]: https://github.com/ruby/openssl/compare
+[History.md]: https://github.com/ruby/openssl/tree/master/History.md
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..ab7f09e
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1 @@
+FROM zzak/ruby-openssl-docker:2.0
diff --git a/History.md b/History.md
new file mode 100644
index 0000000..bd392da
--- /dev/null
+++ b/History.md
@@ -0,0 +1,137 @@
+Version 2.0.0
+=============
+
+This is the first release of openssl gem, formerly a standard library of Ruby,
+ext/openssl. This is the successor of the version included in Ruby 2.3.
+
+Compatibility notes
+-------------------
+
+* Support for OpenSSL version 0.9.6 and 0.9.7 is completely removed. openssl gem
+ still works with OpenSSL 0.9.8, but users are strongly encouraged to upgrade
+ to at least 1.0.1, as OpenSSL < 1.0.1 will not receive any security fixes from
+ the OpenSSL development team.
+
+Supported platforms
+-------------------
+
+* OpenSSL 1.0.0, 1.0.1, 1.0.2, 1.1.0
+* OpenSSL < 0.9.8 is no longer supported.
+* LibreSSL 2.1, 2.2, 2.3, 2.4
+* Ruby 2.3, 2.4
+
+Notable changes
+---------------
+
+* Add support for OpenSSL 1.1.0. [[Feature #12324]](https://bugs.ruby-lang.org/issues/12324)
+* Add support for LibreSSL
+
+* OpenSSL::Cipher
+
+ - OpenSSL::Cipher#key= and #iv= reject too long inputs. They used to truncate
+ silently. [[Bug #12561]](https://bugs.ruby-lang.org/issues/12561)
+
+ - OpenSSL::Cipher#iv_len= is added. It allows changing IV (nonce) length if
+ using AEAD ciphers.
+ [[Bug #8667]](https://bugs.ruby-lang.org/issues/8667),
+ [[Bug #10420]](https://bugs.ruby-lang.org/issues/10420),
+ [[GH ruby/ruby#569]](https://github.com/ruby/ruby/pull/569),
+ [[GH ruby/openssl#58]](https://github.com/ruby/openssl/pull/58)
+
+ - OpenSSL::Cipher#auth_tag_len= is added. This sets the authentication tag
+ length to be generated by an AEAD cipher.
+
+* OpenSSL::OCSP
+
+ - Accessor methods are added to OpenSSL::OCSP::CertificateId.
+ [[Feature #7181]](https://bugs.ruby-lang.org/issues/7181)
+
+ - OpenSSL::OCSP::Request and BasicResponse can be signed with non-SHA-1 hash
+ algorithm. [[Feature #11552]](https://bugs.ruby-lang.org/issues/11552)
+
+ - OpenSSL::OCSP::CertificateId and BasicResponse can be encoded into DER.
+
+ - A new class OpenSSL::OCSP::SingleResponse is added for convenience.
+
+ - OpenSSL::OCSP::BasicResponse#add_status accepts absolute times. They used to
+ accept only relative seconds from the current time.
+
+* OpenSSL::PKey
+
+ - OpenSSL::PKey::EC follows the general PKey interface.
+ [[Bug #6567]](https://bugs.ruby-lang.org/issues/6567)
+
+ - OpenSSL::PKey.read raises OpenSSL::PKey::PKeyError instead of ArgumentError
+ for consistency with OpenSSL::PKey::{DH,DSA,RSA,EC}#new.
+ [[Bug #11774]](https://bugs.ruby-lang.org/issues/11774),
+ [[GH ruby/openssl#55]](https://github.com/ruby/openssl/pull/55)
+
+ - OpenSSL::PKey::EC::Group retrieved by OpenSSL::PKey::EC#group is no longer
+ linked with the EC key. Modifications to the EC::Group have no effect on the
+ key. [[GH ruby/openssl#71]](https://github.com/ruby/openssl/pull/71)
+
+ - OpenSSL::PKey::EC::Point#to_bn allows specifying the point conversion form
+ by the optional argument.
+
+* OpenSSL::SSL
+
+ - OpenSSL::SSL::SSLSocket#tmp_key is added. A client can call it after the
+ connection is established to retrieve the ephemeral key.
+ [[GH ruby/ruby#1318]](https://github.com/ruby/ruby/pull/1318)
+
+ - The automatic ephemeral ECDH curve selection is enabled by default when
+ built with OpenSSL >= 1.0.2 or LibreSSL.
+
+ - OpenSSL::SSL::SSLContext#security_level= is added. You can set the "security
+ level" of the SSL context. This is effective only when built with OpenSSL
+ 1.1.0.
+
+ - A new option 'verify_hostname' is added to OpenSSL::SSL::SSLContext. When it
+ is enabled, and the SNI hostname is also set, the hostname verification on
+ the server certificate is automatically performed. It is now enabled by
+ OpenSSL::SSL::Context#set_params.
+ [[GH ruby/openssl#60]](https://github.com/ruby/openssl/pull/60)
+
+Removals
+--------
+
+* OpenSSL::Engine
+
+ - OpenSSL::Engine.cleanup does nothing when built with OpenSSL 1.1.0.
+
+* OpenSSL::SSL
+
+ - OpenSSL::PKey::DH::DEFAULT_512 is removed. Hence servers no longer use
+ 512-bit DH group by default. It is considered too weak nowadays.
+ [[Bug #11968]](https://bugs.ruby-lang.org/issues/11968),
+ [[GH ruby/ruby#1196]](https://github.com/ruby/ruby/pull/1196)
+
+ - RC4 cipher suites are removed from OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.
+ RC4 is now considered to be weak.
+ [[GH ruby/openssl#50]](https://github.com/ruby/openssl/pull/50)
+
+Deprecations
+------------
+
+* OpenSSL::PKey
+
+ - OpenSSL::PKey::RSA#n=, #e=, #d=, #p=, #q=, #dmp1=, #dmq1=, #iqmp=,
+ OpenSSL::PKey::DSA#p=, #q=, #g=, #priv_key=, #pub_key=,
+ OpenSSL::PKey::DH#p=, #g=, #priv_key= and #pub_key= are deprecated. They are
+ disabled when built with OpenSSL 1.1.0, due to its API change. Instead,
+ OpenSSL::PKey::RSA#set_key, #set_factors, #set_crt_params,
+ OpenSSL::PKey::DSA#set_pqg, #set_key, OpenSSL::PKey::DH#set_pqg and #set_key
+ are added.
+
+* OpenSSL::Random
+
+ - OpenSSL::Random.pseudo_bytes is deprecated, and not defined when built with
+ OpenSSL 1.1.0. Use OpenSSL::Random.random_bytes instead.
+
+* OpenSSL::SSL
+
+ - OpenSSL::SSL::SSLContext#tmp_ecdh_callback is deprecated, as the underlying
+ API SSL_CTX_set_tmp_ecdh_callback() is removed in OpenSSL 1.1.0. It was
+ first added in Ruby 2.3.0. To specify the curve to be used in ephemeral
+ ECDH, use OpenSSL::SSL::SSLContext#ecdh_curves=. The automatic curve
+ selection is also now enabled by default when built with a capable OpenSSL.
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..426810a
--- /dev/null
+++ b/LICENSE.txt
@@ -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/README.md b/README.md
new file mode 100644
index 0000000..42dd242
--- /dev/null
+++ b/README.md
@@ -0,0 +1,65 @@
+# OpenSSL
+
+[![Build Status](https://travis-ci.org/ruby/openssl.svg?branch=master)](https://travis-ci.org/ruby/openssl)
+
+OpenSSL provides SSL, TLS and general purpose cryptography. It wraps the
+OpenSSL library.
+
+## Installation
+
+The openssl gem is available at [rubygems.org](https://rubygems.org/gems/openssl).
+You can install with:
+
+```
+gem install openssl
+```
+
+You may need to specify the path where OpenSSL is installed.
+
+```
+gem install openssl -- --with-openssl-dir=/opt/openssl
+```
+
+Alternatively, you can install the gem with `bundler`:
+
+```ruby
+# Gemfile
+gem 'openssl'
+# or specify git master
+gem 'openssl', github: 'ruby/openssl'
+```
+
+After doing `bundle install`, you should have the gem installed in your bundle.
+
+## Usage
+
+Once installed, you can require "openssl" in your application.
+
+```ruby
+require "openssl"
+```
+
+**NOTE**: If you are using Ruby 2.3 (and not Bundler), you **must** activate
+the gem version of openssl, otherwise the default gem packaged with the Ruby
+installation will be used:
+
+```ruby
+gem "openssl"
+require "openssl"
+```
+
+## Documentation
+
+See https://ruby.github.io/openssl/.
+
+## Contributing
+
+Please read our [CONTRIBUTING.md] for instructions.
+
+## Security
+
+Security issues should be reported to ruby-core by following the process
+described on ["Security at ruby-lang.org"](https://www.ruby-lang.org/en/security/).
+
+
+[CONTRIBUTING.md]: https://github.com/ruby/openssl/tree/master/CONTRIBUTING.md
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..f3e7e3f
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,55 @@
+gem 'rake-compiler'
+
+require 'rake'
+require 'rake/extensiontask'
+require 'rake/testtask'
+require 'rdoc/task'
+
+Rake::ExtensionTask.new('openssl')
+
+Rake::TestTask.new do |t|
+ t.libs << 'test'
+ t.warning = true
+end
+
+RDoc::Task.new do |rdoc|
+ rdoc.main = "README.md"
+ rdoc.rdoc_files.include("*.md", "lib/**/*.rb", "ext/**/*.c")
+end
+
+task :test => :debug
+task :debug do
+ ruby "-I./lib -ropenssl -ve'puts OpenSSL::OPENSSL_VERSION, OpenSSL::OPENSSL_LIBRARY_VERSION'"
+end
+
+namespace :sync do
+ task :from_ruby do
+ sh "./tool/sync-with-trunk"
+ end
+
+ task :to_ruby do
+ trunk_path = ENV.fetch("RUBY_TRUNK_PATH", "../ruby")
+
+ rsync = "rsync -av --delete"
+ excludes = %w{Makefile extconf.h mkmf.log depend *.o *.so *.bundle}
+ excludes.each { |name| rsync << " --exclude #{name}" }
+
+ paths = [
+ ["ext/openssl/", "ext/openssl/"],
+ ["test/utils.rb", "test/openssl/"],
+ ["test/ut_eof.rb", "test/openssl/"],
+ ["test/test_*", "test/openssl/"],
+ ["lib/", "ext/openssl/lib/"],
+ ["sample/", "sample/openssl/"],
+ ]
+ paths.each do |src, dst|
+ sh "#{rsync} #{src} #{trunk_path}/#{dst}"
+ end
+
+ gemspec_file = File.expand_path("../openssl.gemspec", __FILE__)
+ gemspec = eval(File.read(gemspec_file), binding, gemspec_file)
+ File.write("#{trunk_path}/ext/openssl/openssl.gemspec", gemspec.to_ruby)
+
+ puts "Don't forget to update ext/openssl/depend"
+ end
+end
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..4289654
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,13 @@
+compile: &defaults
+ build: .
+ environment:
+ RUBY_VERSION:
+ OPENSSL_VERSION:
+ MDEBUG:
+ command: rake compile
+test:
+ <<: *defaults
+ command: rake compile test
+debug:
+ <<: *defaults
+ command: /bin/bash
diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c
index a9000f2..0723878 100644
--- a/ext/openssl/ossl.c
+++ b/ext/openssl/ossl.c
@@ -370,12 +370,28 @@ void
ossl_clear_error(void)
{
if (dOSSL == Qtrue) {
- long e;
- while ((e = ERR_get_error())) {
- rb_warn("error on stack: %s", ERR_error_string(e, NULL));
+ unsigned long e;
+ const char *file, *data, *errstr;
+ int line, flags;
+
+ while ((e = ERR_get_error_line_data(&file, &line, &data, &flags))) {
+ errstr = ERR_error_string(e, NULL);
+ if (!errstr)
+ errstr = "(null)";
+
+ if (flags & ERR_TXT_STRING) {
+ if (!data)
+ data = "(null)";
+ rb_warn("error on stack: %s (%s)", errstr, data);
+ }
+ else {
+ rb_warn("error on stack: %s", errstr);
+ }
}
}
- ERR_clear_error();
+ else {
+ ERR_clear_error();
+ }
}
/*
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
index 85b1f02..2b8a85f 100644
--- a/ext/openssl/ossl_asn1.c
+++ b/ext/openssl/ossl_asn1.c
@@ -110,16 +110,11 @@ asn1str_to_str(const ASN1_STRING *str)
/*
* 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(const ASN1_INTEGER *ai)
{
BIGNUM *bn;
-#if DO_IT_VIA_RUBY
- char *txt;
-#endif
VALUE num;
if (!ai) {
@@ -133,43 +128,12 @@ asn1integer_to_num(const ASN1_INTEGER *ai)
if (!bn)
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, StringValueCStr(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)
{
@@ -185,7 +149,6 @@ num_to_asn1integer(VALUE obj, ASN1_INTEGER *ai)
return ai;
}
-#endif
/********/
/*
@@ -225,8 +188,8 @@ VALUE cASN1ObjectId; /* OBJECT IDENTIFIER */
VALUE cASN1UTCTime, cASN1GeneralizedTime; /* TIME */
VALUE cASN1Sequence, cASN1Set; /* CONSTRUCTIVE */
-static ID sIMPLICIT, sEXPLICIT;
-static ID sUNIVERSAL, sAPPLICATION, sCONTEXT_SPECIFIC, sPRIVATE;
+static VALUE sym_IMPLICIT, sym_EXPLICIT;
+static VALUE sym_UNIVERSAL, sym_APPLICATION, sym_CONTEXT_SPECIFIC, sym_PRIVATE;
static ID sivVALUE, sivTAG, sivTAG_CLASS, sivTAGGING, sivINFINITE_LENGTH, sivUNUSED_BITS;
/*
@@ -364,13 +327,12 @@ decode_bool(unsigned char* der, long length)
{
const unsigned char *p = der;
- assert(length == 3);
- if (*p++ != 1)
- ossl_raise(eASN1Error, "not a boolean");
- if (*p++ != 1)
- ossl_raise(eASN1Error, "length is not 1");
+ if (length != 3)
+ ossl_raise(eASN1Error, "invalid length for BOOLEAN");
+ if (p[0] != 1 || p[1] != 1)
+ ossl_raise(eASN1Error, "invalid BOOLEAN");
- return *p ? Qtrue : Qfalse;
+ return p[2] ? Qtrue : Qfalse;
}
static VALUE
@@ -632,17 +594,14 @@ ossl_asn1_default_tag(VALUE obj)
VALUE tmp_class, tag;
tmp_class = CLASS_OF(obj);
- while (tmp_class) {
+ while (!NIL_P(tmp_class)) {
tag = rb_hash_lookup(class_tag_map, tmp_class);
- if (tag != Qnil) {
- return NUM2INT(tag);
- }
- tmp_class = rb_class_superclass(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_class(obj));
-
- return -1; /* dummy */
}
static int
@@ -661,59 +620,45 @@ 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){
+ if (NIL_P(s) || s == sym_IMPLICIT)
+ return 0;
+ else if (s == sym_EXPLICIT)
+ return 1;
+ else
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){
+ if (NIL_P(s) || s == sym_UNIVERSAL)
+ return V_ASN1_UNIVERSAL;
+ else if (s == sym_APPLICATION)
+ return V_ASN1_APPLICATION;
+ else if (s == sym_CONTEXT_SPECIFIC)
+ return V_ASN1_CONTEXT_SPECIFIC;
+ else if (s == sym_PRIVATE)
+ return V_ASN1_PRIVATE;
+ else
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);
+ return sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- return ID2SYM(sCONTEXT_SPECIFIC);
+ return sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- return ID2SYM(sAPPLICATION);
+ return sym_APPLICATION;
else
- return ID2SYM(sUNIVERSAL);
+ return sym_UNIVERSAL;
}
/*
@@ -737,7 +682,7 @@ 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)
+ if (tag_class == sym_UNIVERSAL && NUM2INT(tag) > 31)
ossl_raise(eASN1Error, "tag number for Universal too large");
ossl_asn1_set_tag(self, tag);
ossl_asn1_set_value(self, value);
@@ -816,7 +761,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
p = *pp;
- if(tc == sUNIVERSAL && tag < ossl_asn1_info_size) {
+ if(tc == sym_UNIVERSAL && tag < ossl_asn1_info_size) {
switch(tag){
case V_ASN1_EOC:
value = decode_eoc(p, hlen+length);
@@ -858,13 +803,14 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
*pp += hlen + length;
*num_read = hlen + length;
- if (tc == sUNIVERSAL && tag < ossl_asn1_info_size && ossl_asn1_info[tag].klass) {
+ if (tc == sym_UNIVERSAL &&
+ 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);
+ args[3] = tc;
asn1data = rb_obj_alloc(klass);
ossl_asn1_initialize(4, args, asn1data);
if(tag == V_ASN1_BIT_STRING){
@@ -873,7 +819,7 @@ int_ossl_asn1_decode0_prim(unsigned char **pp, long length, long hlen, int tag,
}
else {
asn1data = rb_obj_alloc(cASN1Data);
- ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), ID2SYM(tc));
+ ossl_asn1data_initialize(asn1data, value, INT2NUM(tag), tc);
}
return asn1data;
@@ -902,12 +848,12 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
if (infinite &&
NUM2INT(ossl_asn1_get_tag(value)) == V_ASN1_EOC &&
- SYM2ID(ossl_asn1_get_tag_class(value)) == sUNIVERSAL) {
+ ossl_asn1_get_tag_class(value) == sym_UNIVERSAL) {
break;
}
}
- if (tc == sUNIVERSAL) {
+ if (tc == sym_UNIVERSAL) {
VALUE args[4];
int not_sequence_or_set;
@@ -929,12 +875,12 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
args[0] = ary;
args[1] = INT2NUM(tag);
args[2] = Qnil;
- args[3] = ID2SYM(tc);
+ args[3] = tc;
ossl_asn1_initialize(4, args, asn1data);
}
else {
asn1data = rb_obj_alloc(cASN1Data);
- ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), ID2SYM(tc));
+ ossl_asn1data_initialize(asn1data, ary, INT2NUM(tag), tc);
}
if (infinite)
@@ -964,13 +910,13 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
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;
+ tag_class = sym_PRIVATE;
else if((tc & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
- tag_class = sCONTEXT_SPECIFIC;
+ tag_class = sym_CONTEXT_SPECIFIC;
else if((tc & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
- tag_class = sAPPLICATION;
+ tag_class = sym_APPLICATION;
else
- tag_class = sUNIVERSAL;
+ tag_class = sym_UNIVERSAL;
hlen = p - start;
@@ -1162,19 +1108,19 @@ ossl_asn1_initialize(int argc, VALUE *argv, VALUE self)
ossl_raise(eASN1Error, "invalid tagging method");
if(NIL_P(tag_class)) {
if (NIL_P(tagging))
- tag_class = ID2SYM(sUNIVERSAL);
+ tag_class = sym_UNIVERSAL;
else
- tag_class = ID2SYM(sCONTEXT_SPECIFIC);
+ tag_class = sym_CONTEXT_SPECIFIC;
}
if(!SYMBOL_P(tag_class))
ossl_raise(eASN1Error, "invalid tag class");
- if(!NIL_P(tagging) && SYM2ID(tagging) == sIMPLICIT && NUM2INT(tag) > 31)
+ if (tagging == sym_IMPLICIT && 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);
+ tag_class = sym_UNIVERSAL;
}
ossl_asn1_set_tag(self, tag);
ossl_asn1_set_value(self, value);
@@ -1190,7 +1136,7 @@ ossl_asn1eoc_initialize(VALUE self) {
VALUE tag, tagging, tag_class, value;
tag = INT2NUM(ossl_asn1_default_tag(self));
tagging = Qnil;
- tag_class = ID2SYM(sUNIVERSAL);
+ tag_class = sym_UNIVERSAL;
value = rb_str_new("", 0);
ossl_asn1_set_tag(self, tag);
ossl_asn1_set_value(self, value);
@@ -1264,8 +1210,8 @@ ossl_asn1cons_to_der(VALUE self)
if (inf_length == Qtrue) {
VALUE ary, example;
constructed = 2;
- if (CLASS_OF(self) == cASN1Sequence ||
- CLASS_OF(self) == cASN1Set) {
+ if (rb_obj_class(self) == cASN1Sequence ||
+ rb_obj_class(self) == cASN1Set) {
tag = ossl_asn1_default_tag(self);
}
else { /* must be a constructive encoding of a primitive value */
@@ -1294,7 +1240,7 @@ ossl_asn1cons_to_der(VALUE self)
}
}
else {
- if (CLASS_OF(self) == cASN1Constructive)
+ if (rb_obj_class(self) == cASN1Constructive)
ossl_raise(eASN1Error, "Constructive shall only be used with infinite length");
tag = ossl_asn1_default_tag(self);
}
@@ -1476,12 +1422,12 @@ Init_ossl_asn1(void)
eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
#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");
+ sym_UNIVERSAL = ID2SYM(rb_intern_const("UNIVERSAL"));
+ sym_CONTEXT_SPECIFIC = ID2SYM(rb_intern_const("CONTEXT_SPECIFIC"));
+ sym_APPLICATION = ID2SYM(rb_intern_const("APPLICATION"));
+ sym_PRIVATE = ID2SYM(rb_intern_const("PRIVATE"));
+ sym_EXPLICIT = ID2SYM(rb_intern_const("EXPLICIT"));
+ sym_IMPLICIT = ID2SYM(rb_intern_const("IMPLICIT"));
sivVALUE = rb_intern("@value");
sivTAG = rb_intern("@tag");
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c
index 19a868c..eaf6254 100644
--- a/ext/openssl/ossl_bn.c
+++ b/ext/openssl/ossl_bn.c
@@ -380,7 +380,7 @@ BIGNUM_BOOL1(is_odd)
BIGNUM *bn, *result; \
VALUE obj; \
GetBN(self, bn); \
- obj = NewBN(CLASS_OF(self)); \
+ obj = NewBN(rb_obj_class(self)); \
if (!(result = BN_new())) { \
ossl_raise(eBNError, NULL); \
} \
@@ -406,7 +406,7 @@ BIGNUM_1c(sqr)
BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
VALUE obj; \
GetBN(self, bn1); \
- obj = NewBN(CLASS_OF(self)); \
+ obj = NewBN(rb_obj_class(self)); \
if (!(result = BN_new())) { \
ossl_raise(eBNError, NULL); \
} \
@@ -439,7 +439,7 @@ BIGNUM_2(sub)
BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
VALUE obj; \
GetBN(self, bn1); \
- obj = NewBN(CLASS_OF(self)); \
+ obj = NewBN(rb_obj_class(self)); \
if (!(result = BN_new())) { \
ossl_raise(eBNError, NULL); \
} \
@@ -504,12 +504,13 @@ static VALUE
ossl_bn_div(VALUE self, VALUE other)
{
BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
- VALUE obj1, obj2;
+ VALUE klass, obj1, obj2;
GetBN(self, bn1);
- obj1 = NewBN(CLASS_OF(self));
- obj2 = NewBN(CLASS_OF(self));
+ klass = rb_obj_class(self);
+ obj1 = NewBN(klass);
+ obj2 = NewBN(klass);
if (!(r1 = BN_new())) {
ossl_raise(eBNError, NULL);
}
@@ -536,7 +537,7 @@ ossl_bn_div(VALUE self, VALUE other)
BIGNUM *bn3 = GetBNPtr(other2), *result; \
VALUE obj; \
GetBN(self, bn1); \
- obj = NewBN(CLASS_OF(self)); \
+ obj = NewBN(rb_obj_class(self)); \
if (!(result = BN_new())) { \
ossl_raise(eBNError, NULL); \
} \
@@ -639,7 +640,7 @@ ossl_bn_is_bit_set(VALUE self, VALUE bit)
VALUE obj; \
b = NUM2INT(bits); \
GetBN(self, bn); \
- obj = NewBN(CLASS_OF(self)); \
+ obj = NewBN(rb_obj_class(self)); \
if (!(result = BN_new())) { \
ossl_raise(eBNError, NULL); \
} \
diff --git a/ext/openssl/ossl_cipher.c b/ext/openssl/ossl_cipher.c
index 57bc3cf..73b667b 100644
--- a/ext/openssl/ossl_cipher.c
+++ b/ext/openssl/ossl_cipher.c
@@ -36,7 +36,7 @@
*/
VALUE cCipher;
VALUE eCipherError;
-static ID id_auth_tag_len;
+static ID id_auth_tag_len, id_key_set;
static VALUE ossl_cipher_alloc(VALUE klass);
static void ossl_cipher_free(void *ptr);
@@ -118,7 +118,6 @@ ossl_cipher_initialize(VALUE self, VALUE str)
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher;
char *name;
- unsigned char dummy_key[EVP_MAX_KEY_LENGTH] = { 0 };
name = StringValueCStr(str);
GetCipherInit(self, ctx);
@@ -129,16 +128,7 @@ ossl_cipher_initialize(VALUE self, VALUE str)
if (!(cipher = EVP_get_cipherbyname(name))) {
ossl_raise(rb_eRuntimeError, "unsupported cipher algorithm (%"PRIsVALUE")", str);
}
- /*
- * EVP_CipherInit_ex() allows to specify NULL to key and IV, however some
- * ciphers don't handle well (OpenSSL's bug). [Bug #2768]
- *
- * 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.
- */
- if (EVP_CipherInit_ex(ctx, cipher, NULL, dummy_key, NULL, -1) != 1)
+ if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, -1) != 1)
ossl_raise(eCipherError, NULL);
return self;
@@ -251,6 +241,9 @@ ossl_cipher_init(int argc, VALUE *argv, VALUE self, int mode)
ossl_raise(eCipherError, NULL);
}
+ if (p_key)
+ rb_ivar_set(self, id_key_set, Qtrue);
+
return self;
}
@@ -337,6 +330,8 @@ ossl_cipher_pkcs5_keyivgen(int argc, VALUE *argv, VALUE self)
OPENSSL_cleanse(key, sizeof key);
OPENSSL_cleanse(iv, sizeof iv);
+ rb_ivar_set(self, id_key_set, Qtrue);
+
return Qnil;
}
@@ -387,6 +382,9 @@ ossl_cipher_update(int argc, VALUE *argv, VALUE self)
rb_scan_args(argc, argv, "11", &data, &str);
+ if (!RTEST(rb_attr_get(self, id_key_set)))
+ ossl_raise(eCipherError, "key not set");
+
StringValue(data);
in = (unsigned char *)RSTRING_PTR(data);
if ((in_len = RSTRING_LEN(data)) == 0)
@@ -488,6 +486,8 @@ ossl_cipher_set_key(VALUE self, VALUE key)
if (EVP_CipherInit_ex(ctx, NULL, NULL, (unsigned char *)RSTRING_PTR(key), NULL, -1) != 1)
ossl_raise(eCipherError, NULL);
+ rb_ivar_set(self, id_key_set, Qtrue);
+
return key;
}
@@ -502,9 +502,6 @@ ossl_cipher_set_key(VALUE self, VALUE key)
* 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)
@@ -530,6 +527,27 @@ ossl_cipher_set_iv(VALUE self, VALUE iv)
return iv;
}
+/*
+ * call-seq:
+ * cipher.authenticated? -> true | false
+ *
+ * Indicated whether this Cipher instance uses an Authenticated Encryption
+ * mode.
+ */
+static VALUE
+ossl_cipher_is_authenticated(VALUE self)
+{
+ EVP_CIPHER_CTX *ctx;
+
+ GetCipher(self, ctx);
+
+#if defined(HAVE_AUTHENTICATED_ENCRYPTION)
+ return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
+#else
+ return Qfalse;
+#endif
+}
+
#ifdef HAVE_AUTHENTICATED_ENCRYPTION
/*
* call-seq:
@@ -676,23 +694,6 @@ ossl_cipher_set_auth_tag_len(VALUE self, VALUE vlen)
}
/*
- * call-seq:
- * cipher.authenticated? -> boolean
- *
- * Indicated whether this Cipher instance uses an Authenticated Encryption
- * mode.
- */
-static VALUE
-ossl_cipher_is_authenticated(VALUE self)
-{
- EVP_CIPHER_CTX *ctx;
-
- GetCipher(self, ctx);
-
- return (EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_FLAG_AEAD_CIPHER) ? Qtrue : Qfalse;
-}
-
-/*
* call-seq:
* cipher.iv_len = integer -> integer
*
@@ -726,7 +727,6 @@ ossl_cipher_set_iv_length(VALUE self, VALUE iv_length)
#define ossl_cipher_get_auth_tag rb_f_notimplement
#define ossl_cipher_set_auth_tag rb_f_notimplement
#define ossl_cipher_set_auth_tag_len rb_f_notimplement
-#define ossl_cipher_is_authenticated rb_f_notimplement
#define ossl_cipher_set_iv_length rb_f_notimplement
#endif
@@ -939,12 +939,10 @@ Init_ossl_cipher(void)
* 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
+ * an IV in any case. 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>
@@ -1082,4 +1080,5 @@ Init_ossl_cipher(void)
rb_define_method(cCipher, "padding=", ossl_cipher_set_padding, 1);
id_auth_tag_len = rb_intern_const("auth_tag_len");
+ id_key_set = rb_intern_const("key_set");
}
diff --git a/ext/openssl/ossl_ns_spki.c b/ext/openssl/ossl_ns_spki.c
index 2f7845b..98f6552 100644
--- a/ext/openssl/ossl_ns_spki.c
+++ b/ext/openssl/ossl_ns_spki.c
@@ -159,8 +159,6 @@ 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()))) {
@@ -170,11 +168,8 @@ ossl_spki_print(VALUE self)
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;
+ return ossl_membio2str(out);
}
/*
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 3c7c5e1..9e6c615 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -70,12 +70,12 @@ const rb_data_type_t ossl_evp_pkey_type = {
0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
};
-VALUE
-ossl_pkey_new(EVP_PKEY *pkey)
+static VALUE
+pkey_new0(EVP_PKEY *pkey)
{
- if (!pkey) {
- ossl_raise(ePKeyError, "Cannot make new key from NULL.");
- }
+ if (!pkey)
+ ossl_raise(ePKeyError, "cannot make new key from NULL");
+
switch (EVP_PKEY_base_id(pkey)) {
#if !defined(OPENSSL_NO_RSA)
case EVP_PKEY_RSA:
@@ -96,29 +96,21 @@ ossl_pkey_new(EVP_PKEY *pkey)
default:
ossl_raise(ePKeyError, "unsupported key type");
}
-
- UNREACHABLE;
}
VALUE
-ossl_pkey_new_from_file(VALUE filename)
+ossl_pkey_new(EVP_PKEY *pkey)
{
- FILE *fp;
- EVP_PKEY *pkey;
-
- rb_check_safe_obj(filename);
- if (!(fp = fopen(StringValueCStr(filename), "r"))) {
- ossl_raise(ePKeyError, "%s", strerror(errno));
- }
- rb_fd_fix_cloexec(fileno(fp));
+ VALUE obj;
+ int status;
- pkey = PEM_read_PrivateKey(fp, NULL, ossl_pem_passwd_cb, NULL);
- fclose(fp);
- if (!pkey) {
- ossl_raise(ePKeyError, NULL);
+ obj = rb_protect((VALUE (*)(VALUE))pkey_new0, (VALUE)pkey, &status);
+ if (status) {
+ EVP_PKEY_free(pkey);
+ rb_jump_tag(status);
}
- return ossl_pkey_new(pkey);
+ return obj;
}
/*
@@ -166,6 +158,45 @@ ossl_pkey_new_from_data(int argc, VALUE *argv, VALUE self)
return ossl_pkey_new(pkey);
}
+static void
+pkey_check_public_key(EVP_PKEY *pkey)
+{
+ void *ptr;
+ const BIGNUM *n, *e, *pubkey;
+
+ if (EVP_PKEY_missing_parameters(pkey))
+ ossl_raise(ePKeyError, "parameters missing");
+
+ ptr = EVP_PKEY_get0(pkey);
+ switch (EVP_PKEY_base_id(pkey)) {
+ case EVP_PKEY_RSA:
+ RSA_get0_key(ptr, &n, &e, NULL);
+ if (n && e)
+ return;
+ break;
+ case EVP_PKEY_DSA:
+ DSA_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
+ case EVP_PKEY_DH:
+ DH_get0_key(ptr, &pubkey, NULL);
+ if (pubkey)
+ return;
+ break;
+#if !defined(OPENSSL_NO_EC)
+ case EVP_PKEY_EC:
+ if (EC_KEY_get0_public_key(ptr))
+ return;
+ break;
+#endif
+ default:
+ /* unsupported type; assuming ok */
+ return;
+ }
+ ossl_raise(ePKeyError, "public key missing");
+}
+
EVP_PKEY *
GetPKeyPtr(VALUE obj)
{
@@ -264,18 +295,23 @@ ossl_pkey_sign(VALUE self, VALUE digest, VALUE data)
pkey = GetPrivPKeyPtr(self);
md = GetDigestPtr(digest);
StringValue(data);
- str = rb_str_new(0, EVP_PKEY_size(pkey)+16);
+ str = rb_str_new(0, EVP_PKEY_size(pkey));
ctx = EVP_MD_CTX_new();
if (!ctx)
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
- EVP_SignInit(ctx, md);
- EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data));
+ if (!EVP_SignInit_ex(ctx, md, NULL)) {
+ EVP_MD_CTX_free(ctx);
+ ossl_raise(ePKeyError, "EVP_SignInit_ex");
+ }
+ if (!EVP_SignUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
+ EVP_MD_CTX_free(ctx);
+ ossl_raise(ePKeyError, "EVP_SignUpdate");
+ }
result = EVP_SignFinal(ctx, (unsigned char *)RSTRING_PTR(str), &buf_len, pkey);
EVP_MD_CTX_free(ctx);
if (!result)
- ossl_raise(ePKeyError, NULL);
- assert((long)buf_len <= RSTRING_LEN(str));
+ ossl_raise(ePKeyError, "EVP_SignFinal");
rb_str_set_len(str, buf_len);
return str;
@@ -308,19 +344,27 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
EVP_PKEY *pkey;
const EVP_MD *md;
EVP_MD_CTX *ctx;
- int result;
+ int siglen, result;
GetPKey(self, pkey);
+ pkey_check_public_key(pkey);
md = GetDigestPtr(digest);
StringValue(sig);
+ siglen = RSTRING_LENINT(sig);
StringValue(data);
ctx = EVP_MD_CTX_new();
if (!ctx)
ossl_raise(ePKeyError, "EVP_MD_CTX_new");
- EVP_VerifyInit(ctx, md);
- EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data));
- result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), RSTRING_LENINT(sig), pkey);
+ if (!EVP_VerifyInit_ex(ctx, md, NULL)) {
+ EVP_MD_CTX_free(ctx);
+ ossl_raise(ePKeyError, "EVP_VerifyInit_ex");
+ }
+ if (!EVP_VerifyUpdate(ctx, RSTRING_PTR(data), RSTRING_LEN(data))) {
+ EVP_MD_CTX_free(ctx);
+ ossl_raise(ePKeyError, "EVP_VerifyUpdate");
+ }
+ result = EVP_VerifyFinal(ctx, (unsigned char *)RSTRING_PTR(sig), siglen, pkey);
EVP_MD_CTX_free(ctx);
switch (result) {
case 0:
@@ -329,9 +373,8 @@ ossl_pkey_verify(VALUE self, VALUE digest, VALUE sig, VALUE data)
case 1:
return Qtrue;
default:
- ossl_raise(ePKeyError, NULL);
+ ossl_raise(ePKeyError, "EVP_VerifyFinal");
}
- return Qnil; /* dummy */
}
/*
diff --git a/ext/openssl/ossl_pkey.h b/ext/openssl/ossl_pkey.h
index 218f2eb..e3b723c 100644
--- a/ext/openssl/ossl_pkey.h
+++ b/ext/openssl/ossl_pkey.h
@@ -48,7 +48,6 @@ int ossl_generate_cb_2(int p, int n, BN_GENCB *cb);
void ossl_generate_cb_stop(void *ptr);
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);
diff --git a/ext/openssl/ossl_pkey_dh.c b/ext/openssl/ossl_pkey_dh.c
index 938efe1..dd85b7b 100644
--- a/ext/openssl/ossl_pkey_dh.c
+++ b/ext/openssl/ossl_pkey_dh.c
@@ -460,7 +460,7 @@ ossl_dh_to_public_key(VALUE self)
GetDH(self, orig_dh);
dh = DHparams_dup(orig_dh); /* err check perfomed by dh_instance */
- obj = dh_instance(CLASS_OF(self), dh);
+ obj = dh_instance(rb_obj_class(self), dh);
if (obj == Qfalse) {
DH_free(dh);
ossl_raise(eDHError, NULL);
diff --git a/ext/openssl/ossl_pkey_dsa.c b/ext/openssl/ossl_pkey_dsa.c
index 3821cd8..8508541 100644
--- a/ext/openssl/ossl_pkey_dsa.c
+++ b/ext/openssl/ossl_pkey_dsa.c
@@ -491,7 +491,7 @@ ossl_dsa_to_public_key(VALUE self)
(i2d_of_void *)i2d_DSAPublicKey, (d2i_of_void *)d2i_DSAPublicKey, (char *)(dsa))
dsa = DSAPublicKey_dup(EVP_PKEY_get0_DSA(pkey));
#undef DSAPublicKey_dup
- obj = dsa_instance(CLASS_OF(self), dsa);
+ obj = dsa_instance(rb_obj_class(self), dsa);
if (obj == Qfalse) {
DSA_free(dsa);
ossl_raise(eDSAError, NULL);
@@ -499,8 +499,6 @@ ossl_dsa_to_public_key(VALUE self)
return obj;
}
-#define ossl_dsa_buf_size(dsa) (DSA_size(dsa) + 16)
-
/*
* call-seq:
* dsa.syssign(string) -> aString
@@ -535,7 +533,7 @@ ossl_dsa_sign(VALUE self, VALUE data)
if (!DSA_PRIVATE(self, dsa))
ossl_raise(eDSAError, "Private DSA key needed!");
StringValue(data);
- str = rb_str_new(0, ossl_dsa_buf_size(dsa));
+ str = rb_str_new(0, DSA_size(dsa));
if (!DSA_sign(0, (unsigned char *)RSTRING_PTR(data), RSTRING_LENINT(data),
(unsigned char *)RSTRING_PTR(str),
&buf_len, dsa)) { /* type is ignored (0) */
diff --git a/ext/openssl/ossl_pkey_ec.c b/ext/openssl/ossl_pkey_ec.c
index f0a3123..c795c07 100644
--- a/ext/openssl/ossl_pkey_ec.c
+++ b/ext/openssl/ossl_pkey_ec.c
@@ -643,11 +643,10 @@ static VALUE ossl_ec_key_dsa_sign_asn1(VALUE self, VALUE 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);
+ str = rb_str_new(0, ECDSA_size(ec));
if (ECDSA_sign(0, (unsigned char *) RSTRING_PTR(data), RSTRING_LENINT(data), (unsigned char *) RSTRING_PTR(str), &buf_len, ec) != 1)
- ossl_raise(eECError, "ECDSA_sign");
-
- rb_str_resize(str, buf_len);
+ ossl_raise(eECError, "ECDSA_sign");
+ rb_str_set_len(str, buf_len);
return str;
}
@@ -1106,6 +1105,22 @@ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
return ID2SYM(ret);
}
+static point_conversion_form_t
+parse_point_conversion_form_symbol(VALUE sym)
+{
+ ID id = SYM2ID(sym);
+
+ if (id == ID_uncompressed)
+ return POINT_CONVERSION_UNCOMPRESSED;
+ else if (id == ID_compressed)
+ return POINT_CONVERSION_COMPRESSED;
+ else if (id == ID_hybrid)
+ return POINT_CONVERSION_HYBRID;
+ else
+ ossl_raise(rb_eArgError, "unsupported point conversion form %+"PRIsVALUE
+ " (expected :compressed, :uncompressed, or :hybrid)", sym);
+}
+
/*
* call-seq:
* group.point_conversion_form = form
@@ -1125,23 +1140,14 @@ static VALUE ossl_ec_group_get_point_conversion_form(VALUE self)
*
* 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)
+static VALUE
+ossl_ec_group_set_point_conversion_form(VALUE self, VALUE form_v)
{
- EC_GROUP *group = NULL;
+ EC_GROUP *group;
point_conversion_form_t form;
- ID form_id = SYM2ID(form_v);
GetECGroup(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");
- }
+ form = parse_point_conversion_form_symbol(form_v);
EC_GROUP_set_point_conversion_form(group, form);
@@ -1549,22 +1555,30 @@ static VALUE ossl_ec_point_set_to_infinity(VALUE self)
/*
* call-seq:
- * point.to_bn => OpenSSL::BN
+ * point.to_bn(conversion_form = nil) => OpenSSL::BN
+ *
+ * Convert the EC point into an octet string and store in an OpenSSL::BN. If
+ * +conversion_form+ is given, the point data is converted using the specified
+ * form. If not given, the default form set in the EC::Group object is used.
*
- * See the OpenSSL documentation for EC_POINT_point2bn()
+ * See also EC::Point#point_conversion_form=.
*/
-static VALUE ossl_ec_point_to_bn(VALUE self)
+static VALUE
+ossl_ec_point_to_bn(int argc, VALUE *argv, VALUE self)
{
EC_POINT *point;
- VALUE bn_obj;
+ VALUE form_obj, bn_obj;
const EC_GROUP *group;
point_conversion_form_t form;
BIGNUM *bn;
GetECPoint(self, point);
GetECPointGroup(self, group);
-
- form = EC_GROUP_get_point_conversion_form(group);
+ rb_scan_args(argc, argv, "01", &form_obj);
+ if (NIL_P(form_obj))
+ form = EC_GROUP_get_point_conversion_form(group);
+ else
+ form = parse_point_conversion_form_symbol(form_obj);
bn_obj = rb_obj_alloc(cBN);
bn = GetBNPtr(bn_obj);
@@ -1793,7 +1807,7 @@ void Init_ossl_ec(void)
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);
+ rb_define_method(cEC_POINT, "to_bn", ossl_ec_point_to_bn, -1);
rb_define_method(cEC_POINT, "mul", ossl_ec_point_mul, -1);
id_i_group = rb_intern("@group");
diff --git a/ext/openssl/ossl_pkey_rsa.c b/ext/openssl/ossl_pkey_rsa.c
index 17a7494..cea228d 100644
--- a/ext/openssl/ossl_pkey_rsa.c
+++ b/ext/openssl/ossl_pkey_rsa.c
@@ -404,8 +404,6 @@ ossl_rsa_to_der(VALUE self)
return str;
}
-#define ossl_rsa_buf_size(rsa) (RSA_size(rsa)+16)
-
/*
* call-seq:
* rsa.public_encrypt(string) => String
@@ -429,7 +427,7 @@ ossl_rsa_public_encrypt(int argc, VALUE *argv, VALUE self)
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(rsa));
+ str = rb_str_new(0, RSA_size(rsa));
buf_len = RSA_public_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
(unsigned char *)RSTRING_PTR(str), rsa, pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
@@ -461,7 +459,7 @@ ossl_rsa_public_decrypt(int argc, VALUE *argv, VALUE self)
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(rsa));
+ str = rb_str_new(0, RSA_size(rsa));
buf_len = RSA_public_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
(unsigned char *)RSTRING_PTR(str), rsa, pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
@@ -495,7 +493,7 @@ ossl_rsa_private_encrypt(int argc, VALUE *argv, VALUE self)
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(rsa));
+ str = rb_str_new(0, RSA_size(rsa));
buf_len = RSA_private_encrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
(unsigned char *)RSTRING_PTR(str), rsa, pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
@@ -529,7 +527,7 @@ ossl_rsa_private_decrypt(int argc, VALUE *argv, VALUE self)
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(rsa));
+ str = rb_str_new(0, RSA_size(rsa));
buf_len = RSA_private_decrypt(RSTRING_LENINT(buffer), (unsigned char *)RSTRING_PTR(buffer),
(unsigned char *)RSTRING_PTR(str), rsa, pad);
if (buf_len < 0) ossl_raise(eRSAError, NULL);
@@ -620,7 +618,7 @@ ossl_rsa_to_public_key(VALUE self)
GetPKeyRSA(self, pkey);
/* err check performed by rsa_instance */
rsa = RSAPublicKey_dup(EVP_PKEY_get0_RSA(pkey));
- obj = rsa_instance(CLASS_OF(self), rsa);
+ obj = rsa_instance(rb_obj_class(self), rsa);
if (obj == Qfalse) {
RSA_free(rsa);
ossl_raise(eRSAError, NULL);
diff --git a/ext/openssl/ossl_ssl_session.c b/ext/openssl/ossl_ssl_session.c
index fb7c0fb..f3da25b 100644
--- a/ext/openssl/ossl_ssl_session.c
+++ b/ext/openssl/ossl_ssl_session.c
@@ -141,19 +141,18 @@ static VALUE ossl_ssl_session_eq(VALUE val1, VALUE val2)
*
* Returns the time at which the session was established.
*/
-static VALUE ossl_ssl_session_get_time(VALUE self)
+static VALUE
+ossl_ssl_session_get_time(VALUE self)
{
- SSL_SESSION *ctx;
- time_t t;
-
- GetSSLSession(self, ctx);
+ SSL_SESSION *ctx;
+ long t;
- t = SSL_SESSION_get_time(ctx);
+ GetSSLSession(self, ctx);
+ t = SSL_SESSION_get_time(ctx);
+ if (t == 0)
+ return Qnil;
- if (t == 0)
- return Qnil;
-
- return rb_funcall(rb_cTime, rb_intern("at"), 1, TIMET2NUM(t));
+ return rb_funcall(rb_cTime, rb_intern("at"), 1, LONG2NUM(t));
}
/*
@@ -164,16 +163,16 @@ static VALUE ossl_ssl_session_get_time(VALUE self)
* established time.
*
*/
-static VALUE ossl_ssl_session_get_timeout(VALUE self)
+static VALUE
+ossl_ssl_session_get_timeout(VALUE self)
{
- SSL_SESSION *ctx;
- time_t t;
+ SSL_SESSION *ctx;
+ long t;
- GetSSLSession(self, ctx);
-
- t = SSL_SESSION_get_timeout(ctx);
+ GetSSLSession(self, ctx);
+ t = SSL_SESSION_get_timeout(ctx);
- return TIMET2NUM(t);
+ return LONG2NUM(t);
}
/*
@@ -270,9 +269,6 @@ static VALUE ossl_ssl_session_to_pem(VALUE self)
{
SSL_SESSION *ctx;
BIO *out;
- BUF_MEM *buf;
- VALUE str;
- int i;
GetSSLSession(self, ctx);
@@ -280,16 +276,13 @@ static VALUE ossl_ssl_session_to_pem(VALUE self)
ossl_raise(eSSLSession, "BIO_s_mem()");
}
- if (!(i=PEM_write_bio_SSL_SESSION(out, ctx))) {
+ if (!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;
+ return ossl_membio2str(out);
}
@@ -303,8 +296,6 @@ static VALUE ossl_ssl_session_to_text(VALUE self)
{
SSL_SESSION *ctx;
BIO *out;
- BUF_MEM *buf;
- VALUE str;
GetSSLSession(self, ctx);
@@ -317,11 +308,7 @@ static VALUE ossl_ssl_session_to_text(VALUE self)
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;
+ return ossl_membio2str(out);
}
diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c
index 0ff5d2f..f9819f5 100644
--- a/ext/openssl/ossl_x509crl.c
+++ b/ext/openssl/ossl_x509crl.c
@@ -182,8 +182,6 @@ ossl_x509crl_get_signature_algorithm(VALUE self)
X509_CRL *crl;
const X509_ALGOR *alg;
BIO *out;
- BUF_MEM *buf;
- VALUE str;
GetX509CRL(self, crl);
if (!(out = BIO_new(BIO_s_mem()))) {
@@ -194,10 +192,8 @@ ossl_x509crl_get_signature_algorithm(VALUE self)
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;
+
+ return ossl_membio2str(out);
}
static VALUE
@@ -388,8 +384,6 @@ 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()))) {
@@ -399,11 +393,8 @@ ossl_x509crl_to_der(VALUE self)
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;
+ return ossl_membio2str(out);
}
static VALUE
@@ -411,8 +402,6 @@ 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()))) {
@@ -422,11 +411,8 @@ ossl_x509crl_to_pem(VALUE self)
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;
+ return ossl_membio2str(out);
}
static VALUE
@@ -434,8 +420,6 @@ 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()))) {
@@ -445,11 +429,8 @@ ossl_x509crl_to_text(VALUE self)
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;
+ return ossl_membio2str(out);
}
/*
diff --git a/ext/openssl/ossl_x509name.c b/ext/openssl/ossl_x509name.c
index abbdc3b..4523e0d 100644
--- a/ext/openssl/ossl_x509name.c
+++ b/ext/openssl/ossl_x509name.c
@@ -372,12 +372,10 @@ ossl_x509name_cmp(VALUE self, VALUE other)
static VALUE
ossl_x509name_eql(VALUE self, VALUE other)
{
- int result;
-
- if(CLASS_OF(other) != cX509Name) return Qfalse;
- result = ossl_x509name_cmp0(self, other);
+ if (!rb_obj_is_kind_of(other, cX509Name))
+ return Qfalse;
- return (result == 0) ? Qtrue : Qfalse;
+ return ossl_x509name_cmp0(self, other) ? Qtrue : Qfalse;
}
/*
diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c
index d261997..220d2f4 100644
--- a/ext/openssl/ossl_x509req.c
+++ b/ext/openssl/ossl_x509req.c
@@ -160,8 +160,6 @@ 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()))) {
@@ -171,11 +169,8 @@ ossl_x509req_to_pem(VALUE self)
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;
+ return ossl_membio2str(out);
}
static VALUE
@@ -203,8 +198,6 @@ 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()))) {
@@ -214,11 +207,8 @@ ossl_x509req_to_text(VALUE self)
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;
+ return ossl_membio2str(out);
}
#if 0
@@ -304,8 +294,6 @@ ossl_x509req_get_signature_algorithm(VALUE self)
X509_REQ *req;
const X509_ALGOR *alg;
BIO *out;
- BUF_MEM *buf;
- VALUE str;
GetX509Req(self, req);
@@ -317,10 +305,8 @@ ossl_x509req_get_signature_algorithm(VALUE self)
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;
+
+ return ossl_membio2str(out);
}
static VALUE
diff --git a/lib/openssl/ssl.rb b/lib/openssl/ssl.rb
index 190f504..f40a451 100644
--- a/lib/openssl/ssl.rb
+++ b/lib/openssl/ssl.rb
@@ -16,8 +16,7 @@ require "io/nonblock"
module OpenSSL
module SSL
class SSLContext
- # :nodoc:
- DEFAULT_PARAMS = {
+ DEFAULT_PARAMS = { # :nodoc:
:ssl_version => "SSLv23",
:verify_mode => OpenSSL::SSL::VERIFY_PEER,
:verify_hostname => true,
@@ -68,8 +67,7 @@ module OpenSSL
)
end
- # :nodoc:
- DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
+ DEFAULT_CERT_STORE = OpenSSL::X509::Store.new # :nodoc:
DEFAULT_CERT_STORE.set_default_paths
DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
@@ -84,14 +82,12 @@ module OpenSSL
attr_accessor :tmp_dh_callback
- if ExtConfig::HAVE_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.
- attr_accessor :servername_cb
- end
+ # 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.
+ attr_accessor :servername_cb if ExtConfig::HAVE_TLSEXT_HOST_NAME
# call-seq:
# SSLContext.new => ctx
diff --git a/openssl.gemspec b/openssl.gemspec
new file mode 100644
index 0000000..3080cb0
--- /dev/null
+++ b/openssl.gemspec
@@ -0,0 +1,24 @@
+Gem::Specification.new do |spec|
+ spec.name = "openssl"
+ spec.version = "2.0.0.beta.2"
+ spec.authors = ["Martin Bosslet", "SHIBATA Hiroshi", "Zachary Scott", "Kazuki Yamaguchi"]
+ spec.email = ["ruby-core@ruby-lang.org"]
+ spec.summary = %q{OpenSSL provides SSL, TLS and general purpose cryptography.}
+ spec.description = %q{It wraps the OpenSSL library.}
+ spec.homepage = "https://www.ruby-lang.org/"
+ spec.license = "Ruby"
+
+ spec.files = Dir["lib/**/*.rb", "ext/**/*.{c,h,rb}", "*.md", "BSDL", "LICENSE.txt"]
+ spec.require_paths = ["lib"]
+ spec.extensions = ["ext/openssl/extconf.rb"]
+
+ spec.extra_rdoc_files = Dir["*.md"]
+ spec.rdoc_options = ["--main", "README.md"]
+
+ spec.required_ruby_version = ">= 2.3.0"
+
+ spec.add_development_dependency "rake", "~> 10.3"
+ spec.add_development_dependency "rake-compiler", "~> 0.9"
+ spec.add_development_dependency "test-unit", "~> 3.0"
+ spec.add_development_dependency "rdoc", "~> 4.2"
+end
diff --git a/test/envutil.rb b/test/envutil.rb
new file mode 100644
index 0000000..da30410
--- /dev/null
+++ b/test/envutil.rb
@@ -0,0 +1,311 @@
+# -*- coding: us-ascii -*-
+require "timeout"
+require "rbconfig"
+
+module EnvUtil
+ def rubybin
+ ENV["RUBY"] || RbConfig.ruby
+ end
+ module_function :rubybin
+
+ LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
+
+ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false,
+ encoding: nil, timeout: 10, reprieve: 1,
+ stdout_filter: nil, stderr_filter: nil,
+ rubybin: EnvUtil.rubybin,
+ **opt)
+ in_c, in_p = IO.pipe
+ out_p, out_c = IO.pipe if capture_stdout
+ err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
+ opt[:in] = in_c
+ opt[:out] = out_c if capture_stdout
+ opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr
+ if encoding
+ out_p.set_encoding(encoding) if out_p
+ err_p.set_encoding(encoding) if err_p
+ end
+ c = "C"
+ child_env = {}
+ LANG_ENVS.each {|lc| child_env[lc] = c}
+ if Array === args and Hash === args.first
+ child_env.update(args.shift)
+ end
+ args = [args] if args.kind_of?(String)
+ pid = spawn(child_env, rubybin, *args, **opt)
+ in_c.close
+ out_c.close if capture_stdout
+ err_c.close if capture_stderr && capture_stderr != :merge_to_stdout
+ if block_given?
+ return yield in_p, out_p, err_p, pid
+ else
+ th_stdout = Thread.new { out_p.read } if capture_stdout
+ th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout
+ in_p.write stdin_data.to_str unless stdin_data.empty?
+ in_p.close
+ if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
+ stdout = th_stdout.value if capture_stdout
+ stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
+ else
+ signal = /mswin|mingw/ =~ RUBY_PLATFORM ? :KILL : :TERM
+ case pgroup = opt[:pgroup]
+ when 0, true
+ pgroup = -pid
+ when nil, false
+ pgroup = pid
+ end
+ begin
+ Process.kill signal, pgroup
+ Timeout.timeout((reprieve unless signal == :KILL)) do
+ Process.wait(pid)
+ end
+ rescue Errno::ESRCH
+ break
+ rescue Timeout::Error
+ raise if signal == :KILL
+ signal = :KILL
+ else
+ break
+ end while true
+ bt = caller_locations
+ raise Timeout::Error, "execution of #{bt.shift.label} expired", bt.map(&:to_s)
+ end
+ out_p.close if capture_stdout
+ err_p.close if capture_stderr && capture_stderr != :merge_to_stdout
+ Process.wait pid
+ status = $?
+ stdout = stdout_filter.call(stdout) if stdout_filter
+ stderr = stderr_filter.call(stderr) if stderr_filter
+ return stdout, stderr, status
+ end
+ ensure
+ [th_stdout, th_stderr].each do |th|
+ th.kill if th
+ end
+ [in_c, in_p, out_c, out_p, err_c, err_p].each do |io|
+ io.close if io && !io.closed?
+ end
+ [th_stdout, th_stderr].each do |th|
+ th.join if th
+ end
+ end
+ module_function :invoke_ruby
+
+ def suppress_warning
+ verbose, $VERBOSE = $VERBOSE, nil
+ yield
+ ensure
+ $VERBOSE = verbose
+ end
+ module_function :suppress_warning
+
+ if /darwin/ =~ RUBY_PLATFORM
+ DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports")
+ DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S'
+ def self.diagnostic_reports(signame, cmd, pid, now)
+ return unless %w[ABRT QUIT SEGV ILL].include?(signame)
+ cmd = File.basename(cmd)
+ path = DIAGNOSTIC_REPORTS_PATH
+ timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT
+ pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.crash"
+ first = true
+ 30.times do
+ first ? (first = false) : sleep(0.1)
+ Dir.glob(pat) do |name|
+ log = File.read(name) rescue next
+ if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log
+ File.unlink(name)
+ File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil
+ return log
+ end
+ end
+ end
+ nil
+ end
+ else
+ def self.diagnostic_reports(signame, cmd, pid, now)
+ end
+ end
+end
+
+module Test
+ module Unit
+ module Assertions
+ FailDesc = proc do |status, message = "", out = ""|
+ pid = status.pid
+ now = Time.now
+ faildesc = proc do
+ if signo = status.termsig
+ signame = Signal.signame(signo)
+ sigdesc = "signal #{signo}"
+ end
+ log = EnvUtil.diagnostic_reports(signame, EnvUtil.rubybin, pid, now)
+ if signame
+ sigdesc = "SIG#{signame} (#{sigdesc})"
+ end
+ if status.coredump?
+ sigdesc << " (core dumped)"
+ end
+ full_message = ''
+ if message and !message.empty?
+ full_message << message << "\n"
+ end
+ full_message << "pid #{pid} killed by #{sigdesc}"
+ if out and !out.empty?
+ full_message << "\n#{out.gsub(/^/, '| ')}"
+ full_message << "\n" if /\n\z/ !~ full_message
+ end
+ if log
+ full_message << "\n#{log.gsub(/^/, '| ')}"
+ end
+ full_message
+ end
+ faildesc
+ end
+
+ ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV")
+
+ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt)
+ unless file and line
+ loc, = caller_locations(1,1)
+ file ||= loc.path
+ line ||= loc.lineno
+ end
+ line -= 6 # lines until src
+ src = <<eom
+# -*- coding: #{src.encoding}; -*-
+ require 'test/unit';include Test::Unit::Assertions
+ END {
+ puts [Marshal.dump($!)].pack('m')#, "assertions=\#{self._assertions}"
+ exit
+ }
+ def pend(msg = nil) $stdout.syswrite [Marshal.dump(msg.to_s)].pack("m"); exit! 0 end
+#{src}
+ class Test::Unit::Runner
+ @@stop_auto_run = true
+ end
+eom
+ args = args.dup
+ args.insert((Hash === args.first ? 1 : 0), "--disable=gems", *$:.map {|l| "-I#{l}"})
+ stdout, stderr, status = EnvUtil.invoke_ruby(args, src, true, true, **opt)
+ abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig))
+ assert(!abort, FailDesc[status, nil, stderr])
+ #self._assertions += stdout[/^assertions=(\d+)/, 1].to_i
+ begin
+ res = Marshal.load(stdout.unpack("m")[0])
+ rescue => marshal_error
+ ignore_stderr = nil
+ end
+ if res.is_a?(String)
+ pend res
+ elsif res
+ if bt = res.backtrace
+ bt.each do |l|
+ l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"}
+ end
+ bt.concat(caller)
+ else
+ res.set_backtrace(caller)
+ end
+ raise res
+ end
+
+ # really is it succeed?
+ unless ignore_stderr
+ # the body of assert_separately must not output anything to detect error
+ assert_equal("", stderr, "assert_separately failed with error message")
+ end
+ assert_equal(0, status, "assert_separately failed: '#{stderr}'")
+ raise marshal_error if marshal_error
+ end
+
+ def message msg = nil, ending = ".", &default
+ proc {
+ msg = msg.call.chomp(".") if Proc === msg
+ custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty?
+ "#{custom_message}#{default.call}#{ending}"
+ }
+ end
+
+ # threads should respond to shift method.
+ # Array can be used.
+ def assert_join_threads(threads, message = nil)
+ errs = []
+ values = []
+ while th = threads.shift
+ begin
+ values << th.value
+ rescue Exception
+ errs << [th, $!]
+ end
+ end
+ if !errs.empty?
+ msg = "exceptions on #{errs.length} threads:\n" +
+ errs.map {|t, err|
+ "#{t.inspect}:\n" +
+ err.backtrace.map.with_index {|line, i|
+ if i == 0
+ "#{line}: #{err.message} (#{err.class})"
+ else
+ "\tfrom #{line}"
+ end
+ }.join("\n")
+ }.join("\n---\n")
+ if message
+ msg = "#{message}\n#{msg}"
+ end
+ raise Test::Unit::AssertionFailedError, msg
+ end
+ values
+ end
+
+ # :call-seq:
+ # assert_raise_with_message(exception, expected, msg = nil, &block)
+ #
+ #Tests if the given block raises an exception with the expected
+ #message.
+ #
+ # assert_raise_with_message(RuntimeError, "foo") do
+ # nil #Fails, no Exceptions are raised
+ # end
+ #
+ # assert_raise_with_message(RuntimeError, "foo") do
+ # raise ArgumentError, "foo" #Fails, different Exception is raised
+ # end
+ #
+ # assert_raise_with_message(RuntimeError, "foo") do
+ # raise "bar" #Fails, RuntimeError is raised but the message differs
+ # end
+ #
+ # assert_raise_with_message(RuntimeError, "foo") do
+ # raise "foo" #Raises RuntimeError with the message, so assertion succeeds
+ # end
+ def assert_raise_with_message(exception, expected, msg = nil, &block)
+ case expected
+ when String
+ assert = :assert_equal
+ when Regexp
+ assert = :assert_match
+ else
+ raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}"
+ end
+
+ ex = m = nil
+ ex = assert_raise(exception, msg || "Exception(#{exception}) with message matches to #{expected.inspect}") do
+ yield
+ end
+ m = ex.message
+ msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"}
+
+ if assert == :assert_equal
+ assert_equal(expected, m, msg)
+ else
+ msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp m}" }
+ assert expected =~ m, msg
+ block.binding.eval("proc{|_|$~=_}").call($~)
+ end
+ ex
+ end
+ end
+ end
+end
diff --git a/test/test_asn1.rb b/test/test_asn1.rb
index f226da5..612c59a 100644
--- a/test/test_asn1.rb
+++ b/test/test_asn1.rb
@@ -243,14 +243,9 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm
end
def test_primitive_cannot_set_infinite_length
- begin
- prim = OpenSSL::ASN1::Integer.new(50)
- assert_equal(false, prim.infinite_length)
- prim.infinite_length = true
- flunk('Could set infinite length on primitive value')
- rescue NoMethodError
- #ok
- end
+ prim = OpenSSL::ASN1::Integer.new(50)
+ assert_equal false, prim.infinite_length
+ assert_not_respond_to prim, :infinite_length=
end
def test_decode_all
@@ -289,12 +284,8 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm
def test_create_inf_length_primitive
expected = %w{ 24 80 04 01 61 00 00 }
raw = [expected.join('')].pack('H*')
- val = OpenSSL::ASN1::OctetString.new('a')
- cons = OpenSSL::ASN1::Constructive.new([val,
- OpenSSL::ASN1::EndOfContent.new],
- OpenSSL::ASN1::OCTET_STRING,
- nil,
- :UNIVERSAL)
+ content = [OpenSSL::ASN1::OctetString.new("a"), OpenSSL::ASN1::EndOfContent.new]
+ cons = OpenSSL::ASN1::Constructive.new(content, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
cons.infinite_length = true
assert_equal(nil, cons.tagging)
assert_equal(raw, cons.to_der)
@@ -306,10 +297,7 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm
def test_cons_without_inf_length_forbidden
assert_raise(OpenSSL::ASN1::ASN1Error) do
val = OpenSSL::ASN1::OctetString.new('a')
- cons = OpenSSL::ASN1::Constructive.new([val],
- OpenSSL::ASN1::OCTET_STRING,
- nil,
- :UNIVERSAL)
+ cons = OpenSSL::ASN1::Constructive.new([val], OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
cons.to_der
end
end
@@ -317,10 +305,7 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm
def test_cons_without_array_forbidden
assert_raise(OpenSSL::ASN1::ASN1Error) do
val = OpenSSL::ASN1::OctetString.new('a')
- cons = OpenSSL::ASN1::Constructive.new(val,
- OpenSSL::ASN1::OCTET_STRING,
- nil,
- :UNIVERSAL)
+ cons = OpenSSL::ASN1::Constructive.new(val, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
cons.infinite_length = true
cons.to_der
end
@@ -352,218 +337,158 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm
end
def test_seq_infinite_length
- begin
- content = [ OpenSSL::ASN1::Null.new(nil),
- OpenSSL::ASN1::EndOfContent.new ]
- cons = OpenSSL::ASN1::Sequence.new(content)
- cons.infinite_length = true
- expected = %w{ 30 80 05 00 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, cons.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ content = [ OpenSSL::ASN1::Null.new(nil),
+ OpenSSL::ASN1::EndOfContent.new ]
+ cons = OpenSSL::ASN1::Sequence.new(content)
+ cons.infinite_length = true
+ expected = %w{ 30 80 05 00 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, cons.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_set_infinite_length
- begin
- content = [ OpenSSL::ASN1::Null.new(nil),
- OpenSSL::ASN1::EndOfContent.new() ]
- cons = OpenSSL::ASN1::Set.new(content)
- cons.infinite_length = true
- expected = %w{ 31 80 05 00 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, cons.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ content = [ OpenSSL::ASN1::Null.new(nil),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ cons = OpenSSL::ASN1::Set.new(content)
+ cons.infinite_length = true
+ expected = %w{ 31 80 05 00 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, cons.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_octet_string_infinite_length
- begin
- octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
- OpenSSL::ASN1::EndOfContent.new() ]
- cons = OpenSSL::ASN1::Constructive.new(
- octets,
- OpenSSL::ASN1::OCTET_STRING,
- nil,
- :UNIVERSAL)
- cons.infinite_length = true
- expected = %w{ 24 80 04 03 61 61 61 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, cons.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ cons = OpenSSL::ASN1::Constructive.new(octets, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
+ cons.infinite_length = true
+ expected = %w{ 24 80 04 03 61 61 61 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, cons.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_prim_explicit_tagging
- begin
- oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT)
- expected = %w{ A0 03 04 01 61 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, oct_str.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT)
+ expected = %w{ A0 03 04 01 61 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, oct_str.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_prim_explicit_tagging_tag_class
- begin
- oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT)
- oct_str2 = OpenSSL::ASN1::OctetString.new(
- "a",
- 0,
- :EXPLICIT,
- :CONTEXT_SPECIFIC)
- assert_equal(oct_str.to_der, oct_str2.to_der)
- end
+ oct_str = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT)
+ oct_str2 = OpenSSL::ASN1::OctetString.new("a", 0, :EXPLICIT, :CONTEXT_SPECIFIC)
+ assert_equal(oct_str.to_der, oct_str2.to_der)
end
def test_prim_implicit_tagging
- begin
- int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)
- expected = %w{ 80 01 01 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, int.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)
+ expected = %w{ 80 01 01 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, int.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_prim_implicit_tagging_tag_class
- begin
- int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)
- int2 = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT, :CONTEXT_SPECIFIC);
- assert_equal(int.to_der, int2.to_der)
- end
+ int = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT)
+ int2 = OpenSSL::ASN1::Integer.new(1, 0, :IMPLICIT, :CONTEXT_SPECIFIC);
+ assert_equal(int.to_der, int2.to_der)
end
def test_cons_explicit_tagging
- begin
- content = [ OpenSSL::ASN1::PrintableString.new('abc') ]
- seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT)
- expected = %w{ A2 07 30 05 13 03 61 62 63 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, seq.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ content = [ OpenSSL::ASN1::PrintableString.new('abc') ]
+ seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT)
+ expected = %w{ A2 07 30 05 13 03 61 62 63 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, seq.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_cons_explicit_tagging_inf_length
- begin
- content = [ OpenSSL::ASN1::PrintableString.new('abc') ,
- OpenSSL::ASN1::EndOfContent.new() ]
- seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT)
- seq.infinite_length = true
- expected = %w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, seq.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ content = [ OpenSSL::ASN1::PrintableString.new('abc') ,
+ OpenSSL::ASN1::EndOfContent.new() ]
+ seq = OpenSSL::ASN1::Sequence.new(content, 2, :EXPLICIT)
+ seq.infinite_length = true
+ expected = %w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, seq.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_cons_implicit_tagging
- begin
- content = [ OpenSSL::ASN1::Null.new(nil) ]
- seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT)
- expected = %w{ A1 02 05 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, seq.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ content = [ OpenSSL::ASN1::Null.new(nil) ]
+ seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT)
+ expected = %w{ A1 02 05 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, seq.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_cons_implicit_tagging_inf_length
- begin
- content = [ OpenSSL::ASN1::Null.new(nil),
- OpenSSL::ASN1::EndOfContent.new() ]
- seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT)
- seq.infinite_length = true
- expected = %w{ A1 80 05 00 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, seq.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ content = [ OpenSSL::ASN1::Null.new(nil),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ seq = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT)
+ seq.infinite_length = true
+ expected = %w{ A1 80 05 00 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, seq.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_octet_string_infinite_length_explicit_tagging
- begin
- octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
- OpenSSL::ASN1::EndOfContent.new() ]
- cons = OpenSSL::ASN1::Constructive.new(
- octets,
- 1,
- :EXPLICIT)
- cons.infinite_length = true
- expected = %w{ A1 80 24 80 04 03 61 61 61 00 00 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, cons.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ cons = OpenSSL::ASN1::Constructive.new(octets, 1, :EXPLICIT)
+ cons.infinite_length = true
+ expected = %w{ A1 80 24 80 04 03 61 61 61 00 00 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, cons.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_octet_string_infinite_length_implicit_tagging
- begin
- octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
- OpenSSL::ASN1::EndOfContent.new() ]
- cons = OpenSSL::ASN1::Constructive.new(
- octets,
- 0,
- :IMPLICIT)
- cons.infinite_length = true
- expected = %w{ A0 80 04 03 61 61 61 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, cons.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ octets = [ OpenSSL::ASN1::OctetString.new('aaa'),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT)
+ cons.infinite_length = true
+ expected = %w{ A0 80 04 03 61 61 61 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, cons.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_recursive_octet_string_infinite_length
- begin
- octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"),
- OpenSSL::ASN1::EndOfContent.new() ]
- octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"),
- OpenSSL::ASN1::EndOfContent.new() ]
- container1 = OpenSSL::ASN1::Constructive.new(
- octets_sub1,
- OpenSSL::ASN1::OCTET_STRING,
- nil,
- :UNIVERSAL)
- container1.infinite_length = true
- container2 = OpenSSL::ASN1::Constructive.new(
- octets_sub2,
- OpenSSL::ASN1::OCTET_STRING,
- nil,
- :UNIVERSAL)
- container2.infinite_length = true
- octets3 = OpenSSL::ASN1::OctetString.new("\x03")
-
- octets = [ container1, container2, octets3,
- OpenSSL::ASN1::EndOfContent.new() ]
- cons = OpenSSL::ASN1::Constructive.new(
- octets,
- OpenSSL::ASN1::OCTET_STRING,
- nil,
- :UNIVERSAL)
- cons.infinite_length = true
- expected = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, cons.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ octets_sub1 = [ OpenSSL::ASN1::OctetString.new("\x01"),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ octets_sub2 = [ OpenSSL::ASN1::OctetString.new("\x02"),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ container1 = OpenSSL::ASN1::Constructive.new(octets_sub1, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
+ container1.infinite_length = true
+ container2 = OpenSSL::ASN1::Constructive.new(octets_sub2, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
+ container2.infinite_length = true
+ octets3 = OpenSSL::ASN1::OctetString.new("\x03")
+
+ octets = [ container1, container2, octets3,
+ OpenSSL::ASN1::EndOfContent.new() ]
+ cons = OpenSSL::ASN1::Constructive.new(octets, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
+ cons.infinite_length = true
+ expected = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, cons.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_bit_string_infinite_length
- begin
- content = [ OpenSSL::ASN1::BitString.new("\x01"),
- OpenSSL::ASN1::EndOfContent.new() ]
- cons = OpenSSL::ASN1::Constructive.new(
- content,
- OpenSSL::ASN1::BIT_STRING,
- nil,
- :UNIVERSAL)
- cons.infinite_length = true
- expected = %w{ 23 80 03 02 00 01 00 00 }
- raw = [expected.join('')].pack('H*')
- assert_equal(raw, cons.to_der)
- assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
- end
+ content = [ OpenSSL::ASN1::BitString.new("\x01"),
+ OpenSSL::ASN1::EndOfContent.new() ]
+ cons = OpenSSL::ASN1::Constructive.new(content, OpenSSL::ASN1::BIT_STRING, nil, :UNIVERSAL)
+ cons.infinite_length = true
+ expected = %w{ 23 80 03 02 00 01 00 00 }
+ raw = [expected.join('')].pack('H*')
+ assert_equal(raw, cons.to_der)
+ assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der)
end
def test_primitive_inf_length
@@ -621,4 +546,3 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm
end
end if defined?(OpenSSL::TestUtils)
-
diff --git a/test/test_cipher.rb b/test/test_cipher.rb
index 74c5394..8954cb6 100644
--- a/test/test_cipher.rb
+++ b/test/test_cipher.rb
@@ -4,110 +4,131 @@ require_relative 'utils'
if defined?(OpenSSL::TestUtils)
class OpenSSL::TestCipher < OpenSSL::TestCase
-
- @ciphers = OpenSSL::Cipher.ciphers
-
- class << self
-
+ module Helper
def has_cipher?(name)
+ @ciphers ||= OpenSSL::Cipher.ciphers
@ciphers.include?(name)
end
-
- def has_ciphers?(list)
- list.all? { |name| has_cipher?(name) }
- end
-
end
-
- def setup
- @c1 = OpenSSL::Cipher.new("DES-EDE3-CBC")
- @c2 = OpenSSL::Cipher::DES.new(:EDE3, "CBC")
- @key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
- @iv = "\0\0\0\0\0\0\0\0"
- @hexkey = "0000000000000000000000000000000000000000000000"
- @hexiv = "0000000000000000"
- @data = "DATA"
+ include Helper
+ extend Helper
+
+ def test_encrypt_decrypt
+ # NIST SP 800-38A F.2.1
+ key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*")
+ iv = ["000102030405060708090a0b0c0d0e0f"].pack("H*")
+ pt = ["6bc1bee22e409f96e93d7e117393172a" \
+ "ae2d8a571e03ac9c9eb76fac45af8e51"].pack("H*")
+ ct = ["7649abac8119b246cee98e9b12e9197d" \
+ "5086cb9b507219ee95db113a917678b2"].pack("H*")
+ cipher = new_encryptor("aes-128-cbc", key: key, iv: iv, padding: 0)
+ assert_equal ct, cipher.update(pt) << cipher.final
+ cipher = new_decryptor("aes-128-cbc", key: key, iv: iv, padding: 0)
+ assert_equal pt, cipher.update(ct) << cipher.final
end
- def teardown
- super
- @c1 = @c2 = nil
- end
-
- def test_crypt
- @c1.encrypt.pkcs5_keyivgen(@key, @iv)
- @c2.encrypt.pkcs5_keyivgen(@key, @iv)
- s1 = @c1.update(@data) + @c1.final
- s2 = @c2.update(@data) + @c2.final
- assert_equal(s1, s2, "encrypt")
-
- @c1.decrypt.pkcs5_keyivgen(@key, @iv)
- @c2.decrypt.pkcs5_keyivgen(@key, @iv)
- assert_equal(@data, @c1.update(s1)+@c1.final, "decrypt")
- assert_equal(@data, @c2.update(s2)+@c2.final, "decrypt")
+ def test_pkcs5_keyivgen
+ pass = "\x00" * 8
+ salt = "\x01" * 8
+ num = 2048
+ pt = "data to be encrypted"
+ cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
+ cipher.pkcs5_keyivgen(pass, salt, num, "MD5")
+ s1 = cipher.update(pt) << cipher.final
+
+ d1 = num.times.inject(pass + salt) {|out, _| OpenSSL::Digest::MD5.digest(out) }
+ d2 = num.times.inject(d1 + pass + salt) {|out, _| OpenSSL::Digest::MD5.digest(out) }
+ key = (d1 + d2)[0, 24]
+ iv = (d1 + d2)[24, 8]
+ cipher = new_encryptor("DES-EDE3-CBC", key: key, iv: iv)
+ s2 = cipher.update(pt) << cipher.final
+
+ assert_equal s1, s2
end
def test_info
- assert_equal("DES-EDE3-CBC", @c1.name, "name")
- assert_equal("DES-EDE3-CBC", @c2.name, "name")
- assert_kind_of(Integer, @c1.key_len, "key_len")
- assert_kind_of(Integer, @c1.iv_len, "iv_len")
+ cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
+ assert_equal "DES-EDE3-CBC", cipher.name
+ assert_equal 24, cipher.key_len
+ assert_equal 8, cipher.iv_len
end
def test_dup
- assert_equal(@c1.name, @c1.dup.name, "dup")
- assert_equal(@c1.name, @c1.clone.name, "clone")
- @c1.encrypt
- @c1.key = @key
- @c1.iv = @iv
- tmpc = @c1.dup
- s1 = @c1.update(@data) + @c1.final
- s2 = tmpc.update(@data) + tmpc.final
+ cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt
+ assert_equal cipher.name, cipher.dup.name
+ cipher.encrypt
+ cipher.random_key
+ cipher.random_iv
+ tmpc = cipher.dup
+ s1 = cipher.update("data") + cipher.final
+ s2 = tmpc.update("data") + tmpc.final
assert_equal(s1, s2, "encrypt dup")
end
def test_reset
- @c1.encrypt
- @c1.key = @key
- @c1.iv = @iv
- s1 = @c1.update(@data) + @c1.final
- @c1.reset
- s2 = @c1.update(@data) + @c1.final
+ cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt
+ cipher.encrypt
+ cipher.random_key
+ cipher.random_iv
+ s1 = cipher.update("data") + cipher.final
+ cipher.reset
+ s2 = cipher.update("data") + cipher.final
assert_equal(s1, s2, "encrypt reset")
end
def test_key_iv_set
- # default value for DES-EDE3-CBC
- assert_equal(24, @c1.key_len)
- assert_equal(8, @c1.iv_len)
- assert_raise(ArgumentError) { @c1.key = "\x01" * 23 }
- @c1.key = "\x01" * 24
- assert_raise(ArgumentError) { @c1.key = "\x01" * 25 }
- assert_raise(ArgumentError) { @c1.iv = "\x01" * 7 }
- @c1.iv = "\x01" * 8
- assert_raise(ArgumentError) { @c1.iv = "\x01" * 9 }
+ cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
+ assert_raise(ArgumentError) { cipher.key = "\x01" * 23 }
+ assert_nothing_raised { cipher.key = "\x01" * 24 }
+ assert_raise(ArgumentError) { cipher.key = "\x01" * 25 }
+ assert_raise(ArgumentError) { cipher.iv = "\x01" * 7 }
+ assert_nothing_raised { cipher.iv = "\x01" * 8 }
+ assert_raise(ArgumentError) { cipher.iv = "\x01" * 9 }
+ end
+
+ def test_random_key_iv
+ data = "data"
+ s1, s2 = 2.times.map do
+ cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt
+ cipher.random_key
+ cipher.iv = "\x01" * 16
+ cipher.update(data) << cipher.final
+ end
+ assert_not_equal s1, s2
+
+ s1, s2 = 2.times.map do
+ cipher = OpenSSL::Cipher.new("aes-128-cbc").encrypt
+ cipher.key = "\x01" * 16
+ cipher.random_iv
+ cipher.update(data) << cipher.final
+ end
+ assert_not_equal s1, s2
end
def test_empty_data
- @c1.encrypt
- assert_raise(ArgumentError){ @c1.update("") }
+ cipher = OpenSSL::Cipher.new("DES-EDE3-CBC").encrypt
+ cipher.random_key
+ assert_raise(ArgumentError) { cipher.update("") }
end
def test_initialize
- assert_raise(RuntimeError) {@c1.__send__(:initialize, "DES-EDE3-CBC")}
- assert_raise(RuntimeError) {OpenSSL::Cipher.allocate.final}
+ cipher = OpenSSL::Cipher.new("DES-EDE3-CBC")
+ assert_raise(RuntimeError) { cipher.__send__(:initialize, "DES-EDE3-CBC") }
+ assert_raise(RuntimeError) { OpenSSL::Cipher.allocate.final }
end
def test_ctr_if_exists
- begin
- cipher = OpenSSL::Cipher.new('aes-128-ctr')
- cipher.encrypt
- cipher.pkcs5_keyivgen('password')
- c = cipher.update('hello,world') + cipher.final
- cipher.decrypt
- cipher.pkcs5_keyivgen('password')
- assert_equal('hello,world', cipher.update(c) + cipher.final)
- end
+ # NIST SP 800-38A F.5.1
+ key = ["2b7e151628aed2a6abf7158809cf4f3c"].pack("H*")
+ iv = ["f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"].pack("H*")
+ pt = ["6bc1bee22e409f96e93d7e117393172a" \
+ "ae2d8a571e03ac9c9eb76fac45af8e51"].pack("H*")
+ ct = ["874d6191b620e3261bef6864990db6ce" \
+ "9806f66b7970fdff8617187bb9fffdff"].pack("H*")
+ cipher = new_encryptor("aes-128-ctr", key: key, iv: iv, padding: 0)
+ assert_equal ct, cipher.update(pt) << cipher.final
+ cipher = new_decryptor("aes-128-ctr", key: key, iv: iv, padding: 0)
+ assert_equal pt, cipher.update(ct) << cipher.final
end if has_cipher?('aes-128-ctr')
def test_ciphers
@@ -136,202 +157,159 @@ class OpenSSL::TestCipher < OpenSSL::TestCase
}
end
- def test_AES_crush
- 500.times do
- assert_nothing_raised("[Bug #2768]") do
- # it caused OpenSSL SEGV by uninitialized key
- OpenSSL::Cipher::AES128.new("ECB").update "." * 17
- end
+ def test_update_raise_if_key_not_set
+ assert_raise(OpenSSL::Cipher::CipherError) do
+ # it caused OpenSSL SEGV by uninitialized key [Bug #2768]
+ OpenSSL::Cipher::AES128.new("ECB").update "." * 17
end
end
- if has_ciphers?(['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])
-
- def test_authenticated
+ def test_authenticated
+ if has_cipher?('aes-128-gcm')
cipher = OpenSSL::Cipher.new('aes-128-gcm')
assert_predicate(cipher, :authenticated?)
- cipher = OpenSSL::Cipher.new('aes-128-cbc')
- assert_not_predicate(cipher, :authenticated?)
- end
-
- def test_aes_gcm
- ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'].each do |algo|
- pt = "You should all use Authenticated Encryption!"
- cipher, key, iv = new_encryptor(algo)
-
- cipher.auth_data = "aad"
- ct = cipher.update(pt) + cipher.final
- tag = cipher.auth_tag
- assert_equal(16, tag.size)
-
- decipher = new_decryptor(algo, key, iv)
- decipher.auth_tag = tag
- decipher.auth_data = "aad"
-
- assert_equal(pt, decipher.update(ct) + decipher.final)
- end
- end
-
- def test_aes_gcm_short_tag
- ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'].each do |algo|
- pt = "You should all use Authenticated Encryption!"
- cipher, key, iv = new_encryptor(algo)
-
- cipher.auth_data = "aad"
- ct = cipher.update(pt) + cipher.final
- tag = cipher.auth_tag(8)
- assert_equal(8, tag.size)
-
- decipher = new_decryptor(algo, key, iv)
- decipher.auth_tag = tag
- decipher.auth_data = "aad"
-
- assert_equal(pt, decipher.update(ct) + decipher.final)
- end
- end
-
- def test_aes_gcm_wrong_tag
- pt = "You should all use Authenticated Encryption!"
- cipher, key, iv = new_encryptor('aes-128-gcm')
-
- cipher.auth_data = "aad"
- ct = cipher.update(pt) + cipher.final
- tag = cipher.auth_tag
-
- decipher = new_decryptor('aes-128-gcm', key, iv)
- tag.setbyte(-1, (tag.getbyte(-1) + 1) & 0xff)
- decipher.auth_tag = tag
- decipher.auth_data = "aad"
-
- assert_raise OpenSSL::Cipher::CipherError do
- decipher.update(ct) + decipher.final
- end
- end
-
- def test_aes_gcm_wrong_auth_data
- pt = "You should all use Authenticated Encryption!"
- cipher, key, iv = new_encryptor('aes-128-gcm')
-
- cipher.auth_data = "aad"
- ct = cipher.update(pt) + cipher.final
- tag = cipher.auth_tag
-
- decipher = new_decryptor('aes-128-gcm', key, iv)
- decipher.auth_tag = tag
- decipher.auth_data = "daa"
-
- assert_raise OpenSSL::Cipher::CipherError do
- decipher.update(ct) + decipher.final
- end
end
+ cipher = OpenSSL::Cipher.new('aes-128-cbc')
+ assert_not_predicate(cipher, :authenticated?)
+ end
- def test_aes_gcm_wrong_ciphertext
- pt = "You should all use Authenticated Encryption!"
- cipher, key, iv = new_encryptor('aes-128-gcm')
+ def test_aes_gcm
+ # GCM spec Appendix B Test Case 4
+ key = ["feffe9928665731c6d6a8f9467308308"].pack("H*")
+ iv = ["cafebabefacedbaddecaf888"].pack("H*")
+ aad = ["feedfacedeadbeeffeedfacedeadbeef" \
+ "abaddad2"].pack("H*")
+ pt = ["d9313225f88406e5a55909c5aff5269a" \
+ "86a7a9531534f7da2e4c303d8a318a72" \
+ "1c3c0c95956809532fcf0e2449a6b525" \
+ "b16aedf5aa0de657ba637b39"].pack("H*")
+ ct = ["42831ec2217774244b7221b784d0d49c" \
+ "e3aa212f2c02a4e035c17e2329aca12e" \
+ "21d514b25466931c7d8f6a5aac84aa05" \
+ "1ba30b396a0aac973d58e091"].pack("H*")
+ tag = ["5bc94fbc3221a5db94fae95ae7121a47"].pack("H*")
+
+ cipher = new_encryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad)
+ assert_equal ct, cipher.update(pt) << cipher.final
+ assert_equal tag, cipher.auth_tag
+ cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad, auth_tag: tag)
+ assert_equal pt, cipher.update(ct) << cipher.final
+
+ # truncated tag is accepted
+ cipher = new_encryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad)
+ assert_equal ct, cipher.update(pt) << cipher.final
+ assert_equal tag[0, 8], cipher.auth_tag(8)
+ cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad, auth_tag: tag[0, 8])
+ assert_equal pt, cipher.update(ct) << cipher.final
+
+ # wrong tag is rejected
+ tag2 = tag.dup
+ tag2.setbyte(-1, (tag2.getbyte(-1) + 1) & 0xff)
+ cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad, auth_tag: tag2)
+ cipher.update(ct)
+ assert_raise(OpenSSL::Cipher::CipherError) { cipher.final }
+
+ # wrong aad is rejected
+ aad2 = aad[0..-2] << aad[-1].succ
+ cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad2, auth_tag: tag)
+ cipher.update(ct)
+ assert_raise(OpenSSL::Cipher::CipherError) { cipher.final }
+
+ # wrong ciphertext is rejected
+ ct2 = ct[0..-2] << ct[-1].succ
+ cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_data: aad, auth_tag: tag)
+ cipher.update(ct2)
+ assert_raise(OpenSSL::Cipher::CipherError) { cipher.final }
+ end if has_cipher?("aes-128-gcm")
+
+ def test_aes_gcm_variable_iv_len
+ # GCM spec Appendix B Test Case 5
+ key = ["feffe9928665731c6d6a8f9467308308"].pack("H*")
+ iv = ["cafebabefacedbad"].pack("H*")
+ aad = ["feedfacedeadbeeffeedfacedeadbeef" \
+ "abaddad2"].pack("H*")
+ pt = ["d9313225f88406e5a55909c5aff5269a" \
+ "86a7a9531534f7da2e4c303d8a318a72" \
+ "1c3c0c95956809532fcf0e2449a6b525" \
+ "b16aedf5aa0de657ba637b39"].pack("H*")
+ ct = ["61353b4c2806934a777ff51fa22a4755" \
+ "699b2a714fcdc6f83766e5f97b6c7423" \
+ "73806900e49f24b22b097544d4896b42" \
+ "4989b5e1ebac0f07c23f4598"].pack("H*")
+ tag = ["3612d2e79e3b0785561be14aaca2fccb"].pack("H*")
+
+ cipher = new_encryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_data: aad)
+ assert_equal ct, cipher.update(pt) << cipher.final
+ assert_equal tag, cipher.auth_tag
+ cipher = new_decryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_data: aad, auth_tag: tag)
+ assert_equal pt, cipher.update(ct) << cipher.final
+ end if has_cipher?("aes-128-gcm")
- cipher.auth_data = "aad"
- ct = cipher.update(pt) + cipher.final
- tag = cipher.auth_tag
+ def test_aes_ocb_tag_len
+ # RFC 7253 Appendix A; the second sample
+ key = ["000102030405060708090A0B0C0D0E0F"].pack("H*")
+ iv = ["BBAA99887766554433221101"].pack("H*")
+ aad = ["0001020304050607"].pack("H*")
+ pt = ["0001020304050607"].pack("H*")
+ ct = ["6820B3657B6F615A"].pack("H*")
+ tag = ["5725BDA0D3B4EB3A257C9AF1F8F03009"].pack("H*")
+
+ cipher = new_encryptor("aes-128-ocb", key: key, iv: iv, auth_data: aad)
+ assert_equal ct, cipher.update(pt) << cipher.final
+ assert_equal tag, cipher.auth_tag
+ cipher = new_decryptor("aes-128-ocb", key: key, iv: iv, auth_data: aad, auth_tag: tag)
+ assert_equal pt, cipher.update(ct) << cipher.final
+
+ # RFC 7253 Appendix A; with 96 bits tag length
+ key = ["0F0E0D0C0B0A09080706050403020100"].pack("H*")
+ iv = ["BBAA9988776655443322110D"].pack("H*")
+ aad = ["000102030405060708090A0B0C0D0E0F1011121314151617" \
+ "18191A1B1C1D1E1F2021222324252627"].pack("H*")
+ pt = ["000102030405060708090A0B0C0D0E0F1011121314151617" \
+ "18191A1B1C1D1E1F2021222324252627"].pack("H*")
+ ct = ["1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1" \
+ "A0124B0A55BAE884ED93481529C76B6A"].pack("H*")
+ tag = ["D0C515F4D1CDD4FDAC4F02AA"].pack("H*")
+
+ cipher = new_encryptor("aes-128-ocb", auth_tag_len: 12, key: key, iv: iv, auth_data: aad)
+ assert_equal ct, cipher.update(pt) << cipher.final
+ assert_equal tag, cipher.auth_tag
+ cipher = new_decryptor("aes-128-ocb", auth_tag_len: 12, key: key, iv: iv, auth_data: aad, auth_tag: tag)
+ assert_equal pt, cipher.update(ct) << cipher.final
- decipher = new_decryptor('aes-128-gcm', key, iv)
- decipher.auth_tag = tag
- decipher.auth_data = "aad"
+ end if has_cipher?("aes-128-ocb")
- assert_raise OpenSSL::Cipher::CipherError do
- decipher.update(ct[0..-2] << ct[-1].succ) + decipher.final
- end
- end
+ def test_aes_gcm_key_iv_order_issue
+ pt = "[ruby/openssl#49]"
+ cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt
+ cipher.key = "x" * 16
+ cipher.iv = "a" * 12
+ ct1 = cipher.update(pt) << cipher.final
+ tag1 = cipher.auth_tag
- def test_aes_gcm_variable_iv_len
- pt = "You should all use Authenticated Encryption!"
- cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt
- cipher.key = "x" * 16
- assert_equal(12, cipher.iv_len)
- cipher.iv = "a" * 12
- ct1 = cipher.update(pt) << cipher.final
- tag1 = cipher.auth_tag
-
- cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt
- cipher.key = "x" * 16
- cipher.iv_len = 10
- assert_equal(10, cipher.iv_len)
- cipher.iv = "a" * 10
- ct2 = cipher.update(pt) << cipher.final
- tag2 = cipher.auth_tag
-
- assert_not_equal ct1, ct2
- assert_not_equal tag1, tag2
-
- decipher = OpenSSL::Cipher.new("aes-128-gcm").decrypt
- decipher.auth_tag = tag1
- decipher.key = "x" * 16
- decipher.iv_len = 12
- decipher.iv = "a" * 12
- assert_equal(pt, decipher.update(ct1) << decipher.final)
-
- decipher.reset
- decipher.auth_tag = tag2
- assert_raise(OpenSSL::Cipher::CipherError) {
- decipher.update(ct2) << decipher.final
- }
-
- decipher.reset
- decipher.auth_tag = tag2
- decipher.iv_len = 10
- decipher.iv = "a" * 10
- assert_equal(pt, decipher.update(ct2) << decipher.final)
- end
+ cipher = OpenSSL::Cipher.new("aes-128-gcm").encrypt
+ cipher.iv = "a" * 12
+ cipher.key = "x" * 16
+ ct2 = cipher.update(pt) << cipher.final
+ tag2 = cipher.auth_tag
- end
-
- def test_aes_ocb_tag_len
- pt = "You should all use Authenticated Encryption!"
- cipher = OpenSSL::Cipher.new("aes-128-ocb").encrypt
- cipher.auth_tag_len = 14
- cipher.iv_len = 8
- key = cipher.random_key
- iv = cipher.random_iv
- cipher.auth_data = "aad"
- ct = cipher.update(pt) + cipher.final
- tag = cipher.auth_tag
- assert_equal(14, tag.size)
-
- decipher = OpenSSL::Cipher.new("aes-128-ocb").decrypt
- decipher.auth_tag_len = 14
- decipher.auth_tag = tag
- decipher.iv_len = 8
- decipher.key = key
- decipher.iv = iv
- decipher.auth_data = "aad"
- assert_equal(pt, decipher.update(ct) + decipher.final)
-
- decipher = OpenSSL::Cipher.new("aes-128-ocb").decrypt
- decipher.auth_tag_len = 9
- decipher.auth_tag = tag[0, 9]
- decipher.iv_len = 8
- decipher.key = key
- decipher.iv = iv
- decipher.auth_data = "aad"
- assert_raise(OpenSSL::Cipher::CipherError) {
- decipher.update(ct) + decipher.final
- }
- end if has_cipher?("aes-128-ocb")
+ assert_equal ct1, ct2
+ assert_equal tag1, tag2
+ end if has_cipher?("aes-128-gcm")
private
- def new_encryptor(algo)
- cipher = OpenSSL::Cipher.new(algo)
- cipher.encrypt
- key = cipher.random_key
- iv = cipher.random_iv
- [cipher, key, iv]
+ def new_encryptor(algo, **kwargs)
+ OpenSSL::Cipher.new(algo).tap do |cipher|
+ cipher.encrypt
+ kwargs.each {|k, v| cipher.send(:"#{k}=", v) }
+ end
end
- def new_decryptor(algo, key, iv)
+ def new_decryptor(algo, **kwargs)
OpenSSL::Cipher.new(algo).tap do |cipher|
cipher.decrypt
- cipher.key = key
- cipher.iv = iv
+ kwargs.each {|k, v| cipher.send(:"#{k}=", v) }
end
end
diff --git a/test/test_digest.rb b/test/test_digest.rb
index 51fc03b..028889c 100644
--- a/test/test_digest.rb
+++ b/test/test_digest.rb
@@ -7,27 +7,21 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
def setup
@d1 = OpenSSL::Digest.new("MD5")
@d2 = OpenSSL::Digest::MD5.new
- @md = Digest::MD5.new
- @data = "DATA"
- end
-
- def teardown
- super
- @d1 = @d2 = @md = nil
end
def test_digest
- assert_equal(@md.digest, @d1.digest)
- assert_equal(@md.hexdigest, @d1.hexdigest)
- @d1 << @data
- @d2 << @data
- @md << @data
- assert_equal(@md.digest, @d1.digest)
- assert_equal(@md.hexdigest, @d1.hexdigest)
- assert_equal(@d1.digest, @d2.digest)
- assert_equal(@d1.hexdigest, @d2.hexdigest)
- assert_equal(@md.digest, OpenSSL::Digest::MD5.digest(@data))
- assert_equal(@md.hexdigest, OpenSSL::Digest::MD5.hexdigest(@data))
+ null_hex = "d41d8cd98f00b204e9800998ecf8427e"
+ null_bin = [null_hex].pack("H*")
+ data = "DATA"
+ hex = "e44f9e348e41cb272efa87387728571b"
+ bin = [hex].pack("H*")
+ assert_equal(null_bin, @d1.digest)
+ assert_equal(null_hex, @d1.hexdigest)
+ @d1 << data
+ assert_equal(bin, @d1.digest)
+ assert_equal(hex, @d1.hexdigest)
+ assert_equal(bin, OpenSSL::Digest::MD5.digest(data))
+ assert_equal(hex, OpenSSL::Digest::MD5.hexdigest(data))
end
def test_eql
@@ -43,17 +37,17 @@ class OpenSSL::TestDigest < OpenSSL::TestCase
end
def test_dup
- @d1.update(@data)
+ @d1.update("DATA")
assert_equal(@d1.name, @d1.dup.name, "dup")
assert_equal(@d1.name, @d1.clone.name, "clone")
assert_equal(@d1.digest, @d1.clone.digest, "clone .digest")
end
def test_reset
- @d1.update(@data)
+ @d1.update("DATA")
dig1 = @d1.digest
@d1.reset
- @d1.update(@data)
+ @d1.update("DATA")
dig2 = @d1.digest
assert_equal(dig1, dig2, "reset")
end
diff --git a/test/test_hmac.rb b/test/test_hmac.rb
index dd58e4a..dbde97d 100644
--- a/test/test_hmac.rb
+++ b/test/test_hmac.rb
@@ -1,33 +1,26 @@
-# coding: UTF-8
# frozen_string_literal: false
-
require_relative 'utils'
class OpenSSL::TestHMAC < OpenSSL::TestCase
- def setup
- @digest = OpenSSL::Digest::MD5
- @key = "KEY"
- @data = "DATA"
- @h1 = OpenSSL::HMAC.new(@key, @digest.new)
- @h2 = OpenSSL::HMAC.new(@key, "MD5")
- end
-
def test_hmac
- @h1.update(@data)
- @h2.update(@data)
- assert_equal(@h1.digest, @h2.digest)
-
- assert_equal(OpenSSL::HMAC.digest(@digest.new, @key, @data), @h1.digest, "digest")
- assert_equal(OpenSSL::HMAC.hexdigest(@digest.new, @key, @data), @h1.hexdigest, "hexdigest")
-
- assert_equal(OpenSSL::HMAC.digest("MD5", @key, @data), @h2.digest, "digest")
- assert_equal(OpenSSL::HMAC.hexdigest("MD5", @key, @data), @h2.hexdigest, "hexdigest")
+ # RFC 2202 2. Test Cases for HMAC-MD5
+ hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "MD5")
+ hmac.update("Hi There")
+ assert_equal ["9294727a3638bb1c13f48ef8158bfc9d"].pack("H*"), hmac.digest
+ assert_equal "9294727a3638bb1c13f48ef8158bfc9d", hmac.hexdigest
+
+ # RFC 4231 4.2. Test Case 1
+ hmac = OpenSSL::HMAC.new(["0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"].pack("H*"), "SHA224")
+ hmac.update("Hi There")
+ assert_equal ["896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"].pack("H*"), hmac.digest
+ assert_equal "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", hmac.hexdigest
end
def test_dup
- @h1.update(@data)
- h = @h1.dup
- assert_equal(@h1.digest, h.digest, "dup digest")
+ h1 = OpenSSL::HMAC.new("KEY", "MD5")
+ h1.update("DATA")
+ h = h1.dup
+ assert_equal(h1.digest, h.digest, "dup digest")
end
def test_binary_update
@@ -38,9 +31,10 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase
end
def test_reset_keep_key
- first = @h1.update("test").hexdigest
- @h2.reset
- second = @h2.update("test").hexdigest
+ h1 = OpenSSL::HMAC.new("KEY", "MD5")
+ first = h1.update("test").hexdigest
+ h1.reset
+ second = h1.update("test").hexdigest
assert_equal first, second
end
end if defined?(OpenSSL::TestUtils)
diff --git a/test/test_pkey_dsa.rb b/test/test_pkey_dsa.rb
index d0ba8ec..a4ccd1d 100644
--- a/test/test_pkey_dsa.rb
+++ b/test/test_pkey_dsa.rb
@@ -36,6 +36,26 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase
end
end
+ def test_sign_verify
+ data = "Sign me!"
+ if defined?(OpenSSL::Digest::DSS1)
+ signature = DSA512.sign(OpenSSL::Digest::DSS1.new, data)
+ assert_equal true, DSA512.verify(OpenSSL::Digest::DSS1.new, signature, data)
+ end
+
+ return if OpenSSL::OPENSSL_VERSION_NUMBER <= 0x010000000
+ signature = DSA512.sign("SHA1", data)
+ assert_equal true, DSA512.verify("SHA1", signature, data)
+
+ signature0 = (<<~'end;').unpack("m")[0]
+ MCwCFH5h40plgU5Fh0Z4wvEEpz0eE9SnAhRPbkRB8ggsN/vsSEYMXvJwjGg/
+ 6g==
+ end;
+ assert_equal true, DSA512.verify("SHA256", signature0, data)
+ signature1 = signature0.succ
+ assert_equal false, DSA512.verify("SHA256", signature1, data)
+ end
+
def test_sys_sign_verify
key = OpenSSL::TestUtils::TEST_KEY_DSA256
data = 'Sign me!'
diff --git a/test/test_pkey_ec.rb b/test/test_pkey_ec.rb
index 53aa5a1..e281f80 100644
--- a/test/test_pkey_ec.rb
+++ b/test/test_pkey_ec.rb
@@ -73,6 +73,20 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
assert_raise(OpenSSL::PKey::ECError) { key2.check_key }
end
+ def test_sign_verify
+ data = "Sign me!"
+ signature = P256.sign("SHA1", data)
+ assert_equal true, P256.verify("SHA1", signature, data)
+
+ signature0 = (<<~'end;').unpack("m")[0]
+ MEQCIEOTY/hD7eI8a0qlzxkIt8LLZ8uwiaSfVbjX2dPAvN11AiAQdCYx56Fq
+ QdBp1B4sxJoA8jvODMMklMyBKVmudboA6A==
+ end;
+ assert_equal true, P256.verify("SHA256", signature0, data)
+ signature1 = signature0.succ
+ assert_equal false, P256.verify("SHA256", signature1, data)
+ end
+
def test_dsa_sign_verify
data1 = "foo"
data2 = "bar"
@@ -244,6 +258,10 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
raise
end
+ assert_equal 0x040603.to_bn, point.to_bn(:uncompressed)
+ assert_equal 0x0306.to_bn, point.to_bn(:compressed)
+ assert_equal 0x070603.to_bn, point.to_bn(:hybrid)
+
assert_equal 0x040603.to_bn, point.to_bn
assert_equal true, point.on_curve?
point.invert! # 8.5
diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb
index e211faa..b24f1d5 100644
--- a/test/test_pkey_rsa.rb
+++ b/test/test_pkey_rsa.rb
@@ -70,6 +70,21 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
end
end
+ def test_sign_verify
+ data = "Sign me!"
+ signature = RSA1024.sign("SHA1", data)
+ assert_equal true, RSA1024.verify("SHA1", signature, data)
+
+ signature0 = (<<~'end;').unpack("m")[0]
+ oLCgbprPvfhM4pjFQiDTFeWI9Sk+Og7Nh9TmIZ/xSxf2CGXQrptlwo7NQ28+
+ WA6YQo8jPH4hSuyWIM4Gz4qRYiYRkl5TDMUYob94zm8Si1HxEiS9354tzvqS
+ zS8MLW2BtNPuTubMxTItHGTnOzo9sUg0LAHVFt8kHG2NfKAw/gQ=
+ end;
+ assert_equal true, RSA1024.verify("SHA256", signature0, data)
+ signature1 = signature0.succ
+ assert_equal false, RSA1024.verify("SHA256", signature1, data)
+ end
+
def test_digest_state_irrelevant_sign
key = RSA1024
digest1 = OpenSSL::Digest::SHA1.new
@@ -93,6 +108,13 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase
assert(key.verify(digest2, sig, data))
end
+ def test_verify_empty_rsa
+ rsa = OpenSSL::PKey::RSA.new
+ assert_raise(OpenSSL::PKey::PKeyError, "[Bug #12783]") {
+ rsa.verify("SHA1", "a", "b")
+ }
+ end
+
def test_RSAPrivateKey
asn1 = OpenSSL::ASN1::Sequence([
OpenSSL::ASN1::Integer(0),
diff --git a/test/test_ssl.rb b/test/test_ssl.rb
index 8b4c090..7f0b939 100644
--- a/test/test_ssl.rb
+++ b/test/test_ssl.rb
@@ -656,7 +656,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.hostname = "foo.example.com"
ssl.connect
- assert_match /^ADH-/, ssl.cipher[0], "the context returned by servername_cb is used"
+ assert_match (/^ADH-/), ssl.cipher[0], "the context returned by servername_cb is used"
assert_predicate ctx3, :frozen?
ensure
sock.close
@@ -667,7 +667,7 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
ssl.hostname = "bar.example.com"
ssl.connect
- assert_not_match /^A(EC)?DH-/, ssl.cipher[0], "the original context is used"
+ assert_not_match (/^A(EC)?DH-/), ssl.cipher[0], "the original context is used"
ensure
sock.close
end
diff --git a/test/test_x509name.rb b/test/test_x509name.rb
index 250f1d0..78da4df 100644
--- a/test/test_x509name.rb
+++ b/test/test_x509name.rb
@@ -345,13 +345,13 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase
def test_hash
dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org"
name = OpenSSL::X509::Name.parse(dn)
- d = Digest::MD5.digest(name.to_der)
+ d = OpenSSL::Digest::MD5.digest(name.to_der)
expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24
assert_equal(expected, name_hash(name))
#
dn = "/DC=org/DC=ruby-lang/CN=baz.ruby-lang.org"
name = OpenSSL::X509::Name.parse(dn)
- d = Digest::MD5.digest(name.to_der)
+ d = OpenSSL::Digest::MD5.digest(name.to_der)
expected = (d[0].ord & 0xff) | (d[1].ord & 0xff) << 8 | (d[2].ord & 0xff) << 16 | (d[3].ord & 0xff) << 24
assert_equal(expected, name_hash(name))
end
diff --git a/test/utils.rb b/test/utils.rb
index 6f3a3c6..0016f5c 100644
--- a/test/utils.rb
+++ b/test/utils.rb
@@ -10,7 +10,6 @@ rescue LoadError
end
require "test/unit"
-require "digest/md5"
require 'tempfile'
require "rbconfig"
require "socket"
diff --git a/tool/ruby-openssl-docker/Dockerfile b/tool/ruby-openssl-docker/Dockerfile
new file mode 100644
index 0000000..4ecc393
--- /dev/null
+++ b/tool/ruby-openssl-docker/Dockerfile
@@ -0,0 +1,92 @@
+FROM ubuntu:14.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ autoconf \
+ bison \
+ build-essential \
+ bzip2 \
+ ca-certificates \
+ cpio \
+ curl \
+ file \
+ git \
+ gzip \
+ libreadline-dev \
+ make \
+ patch \
+ pkg-config \
+ sed \
+ xz-utils \
+ zlib1g-dev
+
+# Supported OpenSSL versions: 1.0.0, 1.0.1, 1.0.2, 1.1.0
+RUN mkdir -p /build/openssl
+RUN curl -s https://www.openssl.org/source/openssl-1.0.0t.tar.gz | tar -C /build/openssl -xzf - && \
+ cd /build/openssl/openssl-1.0.0t && \
+ ./Configure \
+ --openssldir=/opt/openssl/openssl-1.0.0 \
+ shared debug-linux-x86_64 && \
+ make && make install_sw
+
+RUN curl -s https://www.openssl.org/source/openssl-1.0.1t.tar.gz | tar -C /build/openssl -xzf - && \
+ cd /build/openssl/openssl-1.0.1t && \
+ ./Configure \
+ --openssldir=/opt/openssl/openssl-1.0.1 \
+ shared debug-linux-x86_64 && \
+ make && make install_sw
+
+RUN curl -s https://www.openssl.org/source/openssl-1.0.2h.tar.gz | tar -C /build/openssl -xzf - && \
+ cd /build/openssl/openssl-1.0.2h && \
+ ./Configure \
+ --openssldir=/opt/openssl/openssl-1.0.2 \
+ shared debug-linux-x86_64 && \
+ make && make install_sw
+
+RUN curl -s https://www.openssl.org/source/openssl-1.1.0.tar.gz | tar -C /build/openssl -xzf - && \
+ cd /build/openssl/openssl-1.1.0 && \
+ ./Configure \
+ --prefix=/opt/openssl/openssl-1.1.0 \
+ enable-crypto-mdebug enable-crypto-mdebug-backtrace \
+ debug-linux-x86_64 && \
+ make && make install_sw
+
+# Supported libressl versions: 2.1, 2.2, 2.3, 2.4
+RUN curl -s http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.1.10.tar.gz | tar -C /build/openssl -xzf -
+RUN cd /build/openssl/libressl-2.1.10 && \
+ ./configure \
+ --prefix=/opt/openssl/libressl-2.1 && \
+ make && make install
+
+RUN curl -s http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.2.9.tar.gz | tar -C /build/openssl -xzf -
+RUN cd /build/openssl/libressl-2.2.9 && \
+ ./configure \
+ --prefix=/opt/openssl/libressl-2.2 && \
+ make && make install
+
+RUN curl -s http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.3.7.tar.gz | tar -C /build/openssl -xzf -
+RUN cd /build/openssl/libressl-2.3.7 && \
+ ./configure \
+ --prefix=/opt/openssl/libressl-2.3 && \
+ make && make install
+
+RUN curl -s http://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.4.2.tar.gz | tar -C /build/openssl -xzf -
+RUN cd /build/openssl/libressl-2.4.2 && \
+ ./configure \
+ --prefix=/opt/openssl/libressl-2.4 && \
+ make && make install
+
+# Supported Ruby versions: 2.3
+RUN mkdir -p /build/ruby
+RUN curl -s https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz | tar -C /build/ruby -xzf - && \
+ cd /build/ruby/ruby-2.3.1 && \
+ autoconf && ./configure \
+ --without-openssl \
+ --prefix=/opt/ruby/ruby-2.3 \
+ --disable-install-doc && \
+ make && make install
+
+ONBUILD ADD . /home/openssl/code
+ONBUILD WORKDIR /home/openssl/code
+
+COPY init.sh /home/openssl/init.sh
+ENTRYPOINT ["/home/openssl/init.sh"]
diff --git a/tool/ruby-openssl-docker/README.md b/tool/ruby-openssl-docker/README.md
new file mode 100644
index 0000000..5211dd7
--- /dev/null
+++ b/tool/ruby-openssl-docker/README.md
@@ -0,0 +1,5 @@
+# ruby-openssl-docker
+
+Supports OpenSSL 1.0.0t, 1.0.1q, 1.0.2e and LibreSSL 2.1.9, 2.2.5 and 2.3.1.
+
+Currently only Ruby 2.3.0 is supported.
diff --git a/tool/ruby-openssl-docker/init.sh b/tool/ruby-openssl-docker/init.sh
new file mode 100755
index 0000000..3fa271c
--- /dev/null
+++ b/tool/ruby-openssl-docker/init.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+if [[ "$RUBY_VERSION" = "" ]]
+then
+ RUBY_VERSION=ruby-2.3
+fi
+
+if [[ "$OPENSSL_VERSION" = "" ]]
+then
+ OPENSSL_VERSION=openssl-1.0.2
+fi
+
+echo "Using Ruby ${RUBY_VERSION} with OpenSSL ${OPENSSL_VERSION}."
+export PATH="/opt/ruby/${RUBY_VERSION}/bin:$PATH"
+export LD_LIBRARY_PATH="/opt/openssl/${OPENSSL_VERSION}/lib"
+export PKG_CONFIG_PATH="/opt/openssl/${OPENSSL_VERSION}/lib/pkgconfig"
+
+ruby -e '
+ newsource = Gem::Source.new("http://rubygems.org")
+ Gem.sources.replace([newsource])
+ Gem.configuration.write
+
+ spec = eval(File.read("openssl.gemspec"))
+ spec.development_dependencies.each do |dep|
+ Gem.install(dep.name, dep.requirement, force: true)
+ end
+'
+
+exec $*
diff --git a/tool/sync-with-trunk b/tool/sync-with-trunk
new file mode 100755
index 0000000..699508c
--- /dev/null
+++ b/tool/sync-with-trunk
@@ -0,0 +1,105 @@
+#!/bin/sh
+set -e
+
+# Pick changes from Ruby trunk and apply on this repository.
+# Note that Git >= 2.5 is required.
+
+sha1_to_rev() { git show -s --format=format:%B $1 | tail -n1 | grep -Po '(?<=@)[0-9]+'; }
+rev_to_sha1() { git log --format=format:%H -n1 --grep '^git-svn-id: .*@'$2' ' $1; }
+
+echo "#### Step 0. Fetch Ruby trunk"
+git remote | grep '^ruby$' >/dev/null || git remote add ruby https://github.com/ruby/ruby.git
+git fetch ruby
+
+BRANCH_EXTRACT=sync/extract
+echo "#### Step 1. Sync '$BRANCH_EXTRACT' with 'ruby/trunk'"
+[ "$(git branch --list $BRANCH_EXTRACT)" ] || git branch $BRANCH_EXTRACT ruby/trunk
+[ ! -d tmp/sync-extract ] && git worktree add tmp/sync-extract $BRANCH_EXTRACT
+(
+ cd tmp/sync-extract
+ git checkout $BRANCH_EXTRACT
+
+ if [ $(git rev-parse HEAD) = $(git rev-parse ruby/trunk) ]; then
+ filter_range=
+ else
+ old_head=$(git rev-parse HEAD)
+ echo "Updating '$BRANCH_EXTRACT'... HEAD was $old_head."
+ graftpoint="$(rev_to_sha1 ruby/trunk $(sha1_to_rev $old_head)) $old_head"
+ grep "^$graftpoint$" $(git rev-parse --git-common-dir)/info/grafts >/dev/null 2>&1 ||
+ echo "$graftpoint" >> $(git rev-parse --git-common-dir)/info/grafts
+ git reset -q --hard ruby/trunk
+ filter_range=$old_head..$BRANCH_EXTRACT
+ fi
+
+ echo "## Remove unrelated commits"
+ git filter-branch -f --prune-empty --index-filter '
+ git rm --cached -qr --ignore-unmatch . &&
+ git reset -q $GIT_COMMIT -- ext/openssl test/openssl sample/openssl &&
+ git rm --cached -q --ignore-unmatch ext/openssl/depend ext/openssl/openssl.gemspec
+ ' -- $filter_range ||:
+
+ echo "## Adjust path"
+ git filter-branch -f --prune-empty --index-filter '
+ git ls-files --stage | \
+ sed "s:\ttest/openssl:\ttest:" | \
+ sed "s:\text/openssl/lib:\tlib:" | \
+ sed "s:\text/openssl/sample:\tsample/openssl:" | \
+ sed "s:\tsample/openssl:\tsample:" | \
+ GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
+ mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
+ :
+ ' -- $filter_range ||:
+
+ echo "## Fix author/committer email"
+ git filter-branch -f --env-filter '
+ export GIT_AUTHOR_EMAIL=${GIT_AUTHOR_EMAIL/b2dd03c8-39d4-4d8f-98ff-823fe69b080e/ruby-lang.org}
+ export GIT_COMMITTER_EMAIL=${GIT_COMMITTER_EMAIL/b2dd03c8-39d4-4d8f-98ff-823fe69b080e/ruby-lang.org}
+ ' -- $filter_range ||:
+
+ [ "$graftpoint" ] &&
+ sed -ie "/^$graftpoint$/d" $(git rev-parse --git-common-dir)/info/grafts
+)
+
+LASY_SYNC_COMMIT=$(git log --format=format:%H -n1 --grep '^Sync-with-trunk: r')
+LAST_SYNC_REV=$(git show --format=format:%B $LASY_SYNC_COMMIT | grep -Po '(?<=^Sync-with-trunk: r)[0-9]+$' | tail -n1)
+NEXT_SYNC_REV=$(sha1_to_rev $BRANCH_EXTRACT)
+
+[ "$LAST_SYNC_REV" = "$NEXT_SYNC_REV" ] && (
+ echo "No changes since last sync; aborting."
+ exit 1
+)
+
+BRANCH_MERGE=sync/merge-r$NEXT_SYNC_REV
+echo "#### Step 2. Rebase '$BRANCH_EXTRACT' on the last sync commit"
+[ "$(git branch --list $BRANCH_MERGE)" ] || git branch $BRANCH_MERGE $BRANCH_EXTRACT
+[ ! -d tmp/sync-merge ] && git worktree add tmp/sync-merge $BRANCH_MERGE
+(
+ cd tmp/sync-merge
+ git checkout $BRANCH_MERGE
+ git reset -q --hard $BRANCH_EXTRACT
+ git rebase --onto $LASY_SYNC_COMMIT $(rev_to_sha1 $BRANCH_EXTRACT $LAST_SYNC_REV) $BRANCH_MERGE
+)
+
+echo "#### Step 3. Merge '$BRANCH_MERGE' into '$(git rev-parse --abbrev-ref HEAD)'"
+commit_message=$(
+ commits=$(git log --oneline --format='%H %<(61,trunc)%s' $LASY_SYNC_COMMIT..$BRANCH_MERGE)
+ echo "Merge changes from Ruby trunk r$LAST_SYNC_REV..r$NEXT_SYNC_REV"
+ echo ""
+ echo "* ruby-trunk r$LAST_SYNC_REV..r$NEXT_SYNC_REV: ($(echo "$commits" | wc -l) commits)"
+ echo "$commits" | while read line; do
+ sha1=$(echo "$line" | cut -f1 -d' ')
+ cmsg=$(echo "$line" | cut -f2- -d' ')
+ echo " (r$(sha1_to_rev $sha1)) $cmsg"
+ done
+
+ echo ""
+ echo "Sync-with-trunk: r$NEXT_SYNC_REV"
+)
+if git merge --no-ff --no-commit $BRANCH_MERGE; then
+ git commit -m "$commit_message"
+else
+ echo "Merge failed; fix conflict and commit with message:"
+ echo ""
+ echo "$commit_message"
+ exit 1
+fi
diff --git a/tool/update-gh-pages b/tool/update-gh-pages
new file mode 100755
index 0000000..8eb546a
--- /dev/null
+++ b/tool/update-gh-pages
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -e
+
+# Generates RDoc HTML and update gh-pages branch.
+
+HEAD_DESCRIPTION=$(git describe --dirty --always --abbrev=12)
+
+[ -d html ] &&
+ rm -r html
+rake rdoc
+
+[ ! -d tmp/gh-pages ] &&
+ git worktree add tmp/gh-pages gh-pages
+(
+ cd tmp/gh-pages
+
+ git rm -r .
+ cp -r ../../html/* .
+ rm created.rid js/*.gz # to avoid unnecessary change :x
+ git add .
+ git commit -m "Sync with $HEAD_DESCRIPTION"
+)