summaryrefslogtreecommitdiff
path: root/spec/ruby/library/openssl
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/library/openssl')
-rw-r--r--spec/ruby/library/openssl/config/freeze_spec.rb22
-rw-r--r--spec/ruby/library/openssl/digest/append_spec.rb6
-rw-r--r--spec/ruby/library/openssl/digest/block_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_spec.rb (renamed from spec/ruby/library/openssl/digest_spec.rb)13
-rw-r--r--spec/ruby/library/openssl/digest/initialize_spec.rb141
-rw-r--r--spec/ruby/library/openssl/digest/name_spec.rb16
-rw-r--r--spec/ruby/library/openssl/digest/reset_spec.rb36
-rw-r--r--spec/ruby/library/openssl/digest/shared/update.rb123
-rw-r--r--spec/ruby/library/openssl/digest/update_spec.rb6
-rw-r--r--spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb42
-rw-r--r--spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb168
-rw-r--r--spec/ruby/library/openssl/kdf/scrypt_spec.rb209
-rw-r--r--spec/ruby/library/openssl/random/shared/random_bytes.rb2
-rw-r--r--spec/ruby/library/openssl/secure_compare_spec.rb38
-rw-r--r--spec/ruby/library/openssl/x509/store/verify_spec.rb (renamed from spec/ruby/library/openssl/x509/name/verify_spec.rb)10
16 files changed, 885 insertions, 35 deletions
diff --git a/spec/ruby/library/openssl/config/freeze_spec.rb b/spec/ruby/library/openssl/config/freeze_spec.rb
deleted file mode 100644
index c814341b86..0000000000
--- a/spec/ruby/library/openssl/config/freeze_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../shared/constants'
-
-require 'openssl'
-
-version_is(OpenSSL::VERSION, ""..."2.2") do
- describe "OpenSSL::Config#freeze" do
- it "needs to be reviewed for completeness"
-
- it "freezes" do
- c = OpenSSL::Config.new
- -> {
- c['foo'] = [ ['key', 'value'] ]
- }.should_not raise_error
- c.freeze
- c.frozen?.should be_true
- -> {
- c['foo'] = [ ['key', 'value'] ]
- }.should raise_error(TypeError)
- end
- end
-end
diff --git a/spec/ruby/library/openssl/digest/append_spec.rb b/spec/ruby/library/openssl/digest/append_spec.rb
new file mode 100644
index 0000000000..08802b7253
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/append_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/update'
+
+describe "OpenSSL::Digest#<<" do
+ it_behaves_like :openssl_digest_update, :<<
+end
diff --git a/spec/ruby/library/openssl/digest/block_length_spec.rb b/spec/ruby/library/openssl/digest/block_length_spec.rb
new file mode 100644
index 0000000000..444ed9d20d
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/block_length_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#block_length" do
+ context "when the digest object is created via a name argument" do
+ it "returns a SHA1 block length" do
+ OpenSSL::Digest.new('sha1').block_length.should == SHA1Constants::BlockLength
+ end
+
+ it "returns a SHA256 block length" do
+ OpenSSL::Digest.new('sha256').block_length.should == SHA256Constants::BlockLength
+ end
+
+ it "returns a SHA384 block length" do
+ OpenSSL::Digest.new('sha384').block_length.should == SHA384Constants::BlockLength
+ end
+
+ it "returns a SHA512 block length" do
+ OpenSSL::Digest.new('sha512').block_length.should == SHA512Constants::BlockLength
+ end
+ end
+
+ context "when the digest object is created via a subclass" do
+ it "returns a SHA1 block length" do
+ OpenSSL::Digest::SHA1.new.block_length.should == SHA1Constants::BlockLength
+ end
+
+ it "returns a SHA256 block length" do
+ OpenSSL::Digest::SHA256.new.block_length.should == SHA256Constants::BlockLength
+ end
+
+ it "returns a SHA384 block length" do
+ OpenSSL::Digest::SHA384.new.block_length.should == SHA384Constants::BlockLength
+ end
+
+ it "returns a SHA512 block length" do
+ OpenSSL::Digest::SHA512.new.block_length.should == SHA512Constants::BlockLength
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/digest_length_spec.rb b/spec/ruby/library/openssl/digest/digest_length_spec.rb
new file mode 100644
index 0000000000..37d1cba9a7
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/digest_length_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#digest_length" do
+ context "when the digest object is created via a name argument" do
+ it "returns a SHA1 digest length" do
+ OpenSSL::Digest.new('sha1').digest_length.should == SHA1Constants::DigestLength
+ end
+
+ it "returns a SHA256 digest length" do
+ OpenSSL::Digest.new('sha256').digest_length.should == SHA256Constants::DigestLength
+ end
+
+ it "returns a SHA384 digest length" do
+ OpenSSL::Digest.new('sha384').digest_length.should == SHA384Constants::DigestLength
+ end
+
+ it "returns a SHA512 digest length" do
+ OpenSSL::Digest.new('sha512').digest_length.should == SHA512Constants::DigestLength
+ end
+ end
+
+ context "when the digest object is created via a subclass" do
+ it "returns a SHA1 digest length" do
+ OpenSSL::Digest::SHA1.new.digest_length.should == SHA1Constants::DigestLength
+ end
+
+ it "returns a SHA256 digest length" do
+ OpenSSL::Digest::SHA256.new.digest_length.should == SHA256Constants::DigestLength
+ end
+
+ it "returns a SHA384 digest length" do
+ OpenSSL::Digest::SHA384.new.digest_length.should == SHA384Constants::DigestLength
+ end
+
+ it "returns a SHA512 digest length" do
+ OpenSSL::Digest::SHA512.new.digest_length.should == SHA512Constants::DigestLength
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest_spec.rb b/spec/ruby/library/openssl/digest/digest_spec.rb
index b8e82d073f..cf27d01b6d 100644
--- a/spec/ruby/library/openssl/digest_spec.rb
+++ b/spec/ruby/library/openssl/digest/digest_spec.rb
@@ -1,12 +1,11 @@
-require_relative '../../spec_helper'
-require_relative '../../library/digest/sha1/shared/constants'
-require_relative '../../library/digest/sha256/shared/constants'
-require_relative '../../library/digest/sha384/shared/constants'
-require_relative '../../library/digest/sha512/shared/constants'
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
require 'openssl'
-describe "OpenSSL::Digest" do
-
+describe "OpenSSL::Digest class methods" do
describe ".digest" do
it "returns a SHA1 digest" do
OpenSSL::Digest.digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Digest
diff --git a/spec/ruby/library/openssl/digest/initialize_spec.rb b/spec/ruby/library/openssl/digest/initialize_spec.rb
new file mode 100644
index 0000000000..1cd0409c4d
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/initialize_spec.rb
@@ -0,0 +1,141 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#initialize" do
+ describe "can be called with a digest name" do
+ it "returns a SHA1 object" do
+ OpenSSL::Digest.new("sha1").name.should == "SHA1"
+ end
+
+ it "returns a SHA256 object" do
+ OpenSSL::Digest.new("sha256").name.should == "SHA256"
+ end
+
+ it "returns a SHA384 object" do
+ OpenSSL::Digest.new("sha384").name.should == "SHA384"
+ end
+
+ it "returns a SHA512 object" do
+ OpenSSL::Digest.new("sha512").name.should == "SHA512"
+ end
+
+ it "throws an error when called with an unknown digest" do
+ -> { OpenSSL::Digest.new("wd40") }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
+ end
+
+ it "cannot be called with a symbol" do
+ -> { OpenSSL::Digest.new(:SHA1) }.should raise_error(TypeError, /wrong argument type Symbol/)
+ end
+
+ it "does not call #to_str on the argument" do
+ name = mock("digest name")
+ name.should_not_receive(:to_str)
+ -> { OpenSSL::Digest.new(name) }.should raise_error(TypeError, /wrong argument type/)
+ end
+ end
+
+ describe "can be called with a digest object" do
+ it "returns a SHA1 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA1.new).name.should == "SHA1"
+ end
+
+ it "returns a SHA256 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA256.new).name.should == "SHA256"
+ end
+
+ it "returns a SHA384 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA384.new).name.should == "SHA384"
+ end
+
+ it "returns a SHA512 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA512.new).name.should == "SHA512"
+ end
+
+ it "ignores the state of the digest object" do
+ sha1 = OpenSSL::Digest.new('sha1', SHA1Constants::Contents)
+ OpenSSL::Digest.new(sha1).digest.should == SHA1Constants::BlankDigest
+ end
+ end
+
+ it "cannot be called with a digest class" do
+ -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should raise_error(TypeError, /wrong argument type Class/)
+ end
+
+ context "when called without an initial String argument" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest.new("sha1").digest.should == SHA1Constants::BlankDigest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest.new("sha256").digest.should == SHA256Constants::BlankDigest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest.new("sha384").digest.should == SHA384Constants::BlankDigest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest.new("sha512").digest.should == SHA512Constants::BlankDigest
+ end
+ end
+
+ context "when called with an initial String argument" do
+ it "returns a SHA1 digest of that argument" do
+ OpenSSL::Digest.new("sha1", SHA1Constants::Contents).digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest of that argument" do
+ OpenSSL::Digest.new("sha256", SHA256Constants::Contents).digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest of that argument" do
+ OpenSSL::Digest.new("sha384", SHA384Constants::Contents).digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest of that argument" do
+ OpenSSL::Digest.new("sha512", SHA512Constants::Contents).digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "can be called on subclasses" do
+ describe "can be called without an initial String argument on subclasses" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest::SHA1.new.digest.should == SHA1Constants::BlankDigest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest::SHA256.new.digest.should == SHA256Constants::BlankDigest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest::SHA384.new.digest.should == SHA384Constants::BlankDigest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest::SHA512.new.digest.should == SHA512Constants::BlankDigest
+ end
+ end
+
+ describe "can be called with an initial String argument on subclasses" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest::SHA1.new(SHA1Constants::Contents).digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest::SHA256.new(SHA256Constants::Contents).digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest::SHA384.new(SHA384Constants::Contents).digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest::SHA512.new(SHA512Constants::Contents).digest.should == SHA512Constants::Digest
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/name_spec.rb b/spec/ruby/library/openssl/digest/name_spec.rb
new file mode 100644
index 0000000000..b379f35c1c
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/name_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL::Digest#name" do
+ it "returns the name of digest" do
+ OpenSSL::Digest.new('SHA1').name.should == 'SHA1'
+ end
+
+ it "converts the name to the internal representation of OpenSSL" do
+ OpenSSL::Digest.new('sha1').name.should == 'SHA1'
+ end
+
+ it "works on subclasses too" do
+ OpenSSL::Digest::SHA1.new.name.should == 'SHA1'
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/reset_spec.rb b/spec/ruby/library/openssl/digest/reset_spec.rb
new file mode 100644
index 0000000000..c19bf46633
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/reset_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#reset" do
+ it "works for a SHA1 digest" do
+ digest = OpenSSL::Digest.new('sha1', SHA1Constants::Contents)
+ digest.reset
+ digest.update(SHA1Constants::Contents)
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "works for a SHA256 digest" do
+ digest = OpenSSL::Digest.new('sha256', SHA256Constants::Contents)
+ digest.reset
+ digest.update(SHA256Constants::Contents)
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "works for a SHA384 digest" do
+ digest = OpenSSL::Digest.new('sha384', SHA384Constants::Contents)
+ digest.reset
+ digest.update(SHA384Constants::Contents)
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "works for a SHA512 digest" do
+ digest = OpenSSL::Digest.new('sha512', SHA512Constants::Contents)
+ digest.reset
+ digest.update(SHA512Constants::Contents)
+ digest.digest.should == SHA512Constants::Digest
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/shared/update.rb b/spec/ruby/library/openssl/digest/shared/update.rb
new file mode 100644
index 0000000000..e5ff9dcb16
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/shared/update.rb
@@ -0,0 +1,123 @@
+require_relative '../../../../library/digest/sha1/shared/constants'
+require_relative '../../../../library/digest/sha256/shared/constants'
+require_relative '../../../../library/digest/sha384/shared/constants'
+require_relative '../../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe :openssl_digest_update, shared: true do
+ context "when given input as a single string" do
+ it "returns a SHA1 digest" do
+ digest = OpenSSL::Digest.new('sha1')
+ digest.send(@method, SHA1Constants::Contents)
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ digest = OpenSSL::Digest.new('sha256')
+ digest.send(@method, SHA256Constants::Contents)
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ digest = OpenSSL::Digest.new('sha384')
+ digest.send(@method, SHA384Constants::Contents)
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ digest = OpenSSL::Digest.new('sha512')
+ digest.send(@method, SHA512Constants::Contents)
+ digest.digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "when given input as multiple smaller substrings" do
+ it "returns a SHA1 digest" do
+ digest = OpenSSL::Digest.new('sha1')
+ SHA1Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ digest = OpenSSL::Digest.new('sha256')
+ SHA256Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ digest = OpenSSL::Digest.new('sha384')
+ SHA384Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ digest = OpenSSL::Digest.new('sha512')
+ SHA512Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "when input is not a String and responds to #to_str" do
+ it "returns a SHA1 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA1Constants::Contents)
+ digest = OpenSSL::Digest.new('sha1')
+ digest.send(@method, str)
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA256Constants::Contents)
+ digest = OpenSSL::Digest.new('sha256')
+ digest.send(@method, str)
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA384Constants::Contents)
+ digest = OpenSSL::Digest.new('sha384')
+ digest.send(@method, str)
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA512Constants::Contents)
+ digest = OpenSSL::Digest.new('sha512')
+ digest.send(@method, str)
+ digest.digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "when input is not a String and does not respond to #to_str" do
+ it "raises a TypeError with SHA1" do
+ digest = OpenSSL::Digest.new('sha1')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises a TypeError with SHA256" do
+ digest = OpenSSL::Digest.new('sha256')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises a TypeError with SHA384" do
+ digest = OpenSSL::Digest.new('sha384')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises a TypeError with SHA512" do
+ digest = OpenSSL::Digest.new('sha512')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/update_spec.rb b/spec/ruby/library/openssl/digest/update_spec.rb
new file mode 100644
index 0000000000..3a90b06c6b
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/update_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/update'
+
+describe "OpenSSL::Digest#update" do
+ it_behaves_like :openssl_digest_update, :update
+end
diff --git a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
new file mode 100644
index 0000000000..5a2ca168b5
--- /dev/null
+++ b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL.fixed_length_secure_compare" do
+ it "returns true for two strings with the same content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the quick brown fox jumps over the lazy dog"
+ OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
+ end
+
+ it "returns false for two strings of equal size with different content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the lazy dog jumps over the quick brown fox"
+ OpenSSL.fixed_length_secure_compare(input1, input2).should be_false
+ end
+
+ it "converts both arguments to strings using #to_str" do
+ input1 = mock("input1")
+ input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ input2 = mock("input2")
+ input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
+ end
+
+ it "does not accept arguments that are not string and cannot be coerced into strings" do
+ -> {
+ OpenSSL.fixed_length_secure_compare("input1", :input2)
+ }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
+
+ -> {
+ OpenSSL.fixed_length_secure_compare(Object.new, "input2")
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises an ArgumentError for two strings of different size" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the quick brown fox"
+ -> {
+ OpenSSL.fixed_length_secure_compare(input1, input2)
+ }.should raise_error(ArgumentError, 'inputs must be of equal length')
+ end
+end
diff --git a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
new file mode 100644
index 0000000000..40f8597275
--- /dev/null
+++ b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
@@ -0,0 +1,168 @@
+require_relative '../../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL::KDF.pbkdf2_hmac" do
+ before :each do
+ @defaults = {
+ salt: "\x00".b * 16,
+ iterations: 20_000,
+ length: 16,
+ hash: "sha1"
+ }
+ end
+
+ it "creates the same value with the same input" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "supports nullbytes embedded in the password" do
+ key = OpenSSL::KDF.pbkdf2_hmac("sec\x00ret".b, **@defaults)
+ key.should == "\xB9\x7F\xB0\xC2\th\xC8<\x86\xF3\x94Ij7\xEF\xF1".b
+ end
+
+ it "coerces the password into a String using #to_str" do
+ pass = mock("pass")
+ pass.should_receive(:to_str).and_return("secret")
+ key = OpenSSL::KDF.pbkdf2_hmac(pass, **@defaults)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "coerces the salt into a String using #to_str" do
+ salt = mock("salt")
+ salt.should_receive(:to_str).and_return("\x00".b * 16)
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: salt)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "coerces the iterations into an Integer using #to_int" do
+ iterations = mock("iterations")
+ iterations.should_receive(:to_int).and_return(20_000)
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: iterations)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "coerces the length into an Integer using #to_int" do
+ length = mock("length")
+ length.should_receive(:to_int).and_return(16)
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: length)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "accepts a OpenSSL::Digest object as hash" do
+ hash = OpenSSL::Digest.new("sha1")
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "accepts an empty password" do
+ key = OpenSSL::KDF.pbkdf2_hmac("", **@defaults)
+ key.should == "k\x9F-\xB1\xF7\x9A\v\xA1(C\xF9\x85!P\xEF\x8C".b
+ end
+
+ it "accepts an empty salt" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: "")
+ key.should == "\xD5f\xE5\xEA\xF91\x1D\xD3evD\xED\xDB\xE80\x80".b
+ end
+
+ it "accepts an empty length" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 0)
+ key.should.empty?
+ end
+
+ it "accepts an arbitrary length" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 19)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0\xCF\xBB\x7F".b
+ end
+
+ it "accepts any hash function known to OpenSSL" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "sha512")
+ key.should == "N\x12}D\xCE\x99\xDBC\x8E\xEC\xAAr\xEA1\xDF\xFF".b
+ end
+
+ it "raises a TypeError when password is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac(Object.new, **@defaults)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when salt is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when iterations is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: Object.new)
+ }.should raise_error(TypeError, "wrong argument type Object (expected OpenSSL/Digest)")
+ end
+
+ it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest, it does not try to call #to_str" do
+ hash = mock("hash")
+ hash.should_not_receive(:to_str)
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash)
+ }.should raise_error(TypeError, "wrong argument type MockObject (expected OpenSSL/Digest)")
+ end
+
+ it "raises a RuntimeError for unknown digest algorithms" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40")
+ }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
+ end
+
+ it "treats salt as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:salt))
+ }.should raise_error(ArgumentError, 'missing keyword: :salt')
+ end
+
+ it "treats iterations as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:iterations))
+ }.should raise_error(ArgumentError, 'missing keyword: :iterations')
+ end
+
+ it "treats length as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:length))
+ }.should raise_error(ArgumentError, 'missing keyword: :length')
+ end
+
+ it "treats hash as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:hash))
+ }.should raise_error(ArgumentError, 'missing keyword: :hash')
+ end
+
+ it "treats all keywords as required" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret")
+ }.should raise_error(ArgumentError, 'missing keywords: :salt, :iterations, :length, :hash')
+ end
+
+ guard -> { OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 } do
+ it "raises an OpenSSL::KDF::KDFError for 0 or less iterations" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, "PKCS5_PBKDF2_HMAC: invalid iteration count")
+
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /PKCS5_PBKDF2_HMAC/)
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/kdf/scrypt_spec.rb b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
new file mode 100644
index 0000000000..5dc9f2f281
--- /dev/null
+++ b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
@@ -0,0 +1,209 @@
+require_relative '../../../spec_helper'
+require 'openssl'
+
+guard -> { OpenSSL::KDF.respond_to?(:scrypt) } do
+ describe "OpenSSL::KDF.scrypt" do
+ before :each do
+ @defaults = {
+ salt: "\x00".b * 16,
+ N: 2**14,
+ r: 8,
+ p: 1,
+ length: 32
+ }
+ end
+
+ it "creates the same value with the same input" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "supports nullbytes embedded into the password" do
+ key = OpenSSL::KDF.scrypt("sec\x00ret".b, **@defaults)
+ key.should == "\xF9\xA4\xA0\xF1p\xF4\xF0\xCAT\xB4v\xEB\r7\x88N\xF7\x15]Ns\xFCwt4a\xC9\xC6\xA7\x13\x81&".b
+ end
+
+ it "coerces the password into a String using #to_str" do
+ pass = mock("pass")
+ pass.should_receive(:to_str).and_return("secret")
+ key = OpenSSL::KDF.scrypt(pass, **@defaults)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the salt into a String using #to_str" do
+ salt = mock("salt")
+ salt.should_receive(:to_str).and_return("\x00".b * 16)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: salt)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the N into an Integer using #to_int" do
+ n = mock("N")
+ n.should_receive(:to_int).and_return(2**14)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, N: n)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the r into an Integer using #to_int" do
+ r = mock("r")
+ r.should_receive(:to_int).and_return(8)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, r: r)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the p into an Integer using #to_int" do
+ p = mock("p")
+ p.should_receive(:to_int).and_return(1)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, p: p)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the length into an Integer using #to_int" do
+ length = mock("length")
+ length.should_receive(:to_int).and_return(32)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, length: length)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "accepts an empty password" do
+ key = OpenSSL::KDF.scrypt("", **@defaults)
+ key.should == "\xAA\xFC\xF5^E\x94v\xFFk\xE6\xF0vR\xE7\x13\xA7\xF5\x15'\x9A\xE4C\x9Dn\x18F_E\xD2\v\e\xB3".b
+ end
+
+ it "accepts an empty salt" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: "")
+ key.should == "\x96\xACDl\xCB3/aN\xB0F\x8A#\xD7\x92\xD2O\x1E\v\xBB\xCE\xC0\xAA\xB9\x0F]\xB09\xEA8\xDD\e".b
+ end
+
+ it "accepts a zero length" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 0)
+ key.should.empty?
+ end
+
+ it "accepts an arbitrary length" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 19)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D".b
+ end
+
+ it "raises a TypeError when password is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.scrypt(Object.new, **@defaults)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when salt is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, salt: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when N is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when r is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, r: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when p is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, p: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, length: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "treats salt as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:salt))
+ }.should raise_error(ArgumentError, 'missing keyword: :salt')
+ end
+
+ it "treats N as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:N))
+ }.should raise_error(ArgumentError, 'missing keyword: :N')
+ end
+
+ it "treats r as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:r))
+ }.should raise_error(ArgumentError, 'missing keyword: :r')
+ end
+
+ it "treats p as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:p))
+ }.should raise_error(ArgumentError, 'missing keyword: :p')
+ end
+
+ it "treats length as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:length))
+ }.should raise_error(ArgumentError, 'missing keyword: :length')
+ end
+
+ it "treats all keywords as required" do
+ -> {
+ OpenSSL::KDF.scrypt("secret")
+ }.should raise_error(ArgumentError, 'missing keywords: :salt, :N, :r, :p, :length')
+ end
+
+ it "requires N to be a power of 2" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: 2**14 - 1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires N to be at least 2" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, N: 2)
+ key.should == "\x06A$a\xA9!\xBE\x01\x85\xA7\x18\xBCEa\x82\xC5\xFEl\x93\xAB\xBD\xF7\x8B\x84\v\xFC\eN\xEBQ\xE6\xD2".b
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: 1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires r to be positive" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, r: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, r: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires p to be positive" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, p: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, p: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires length to be not negative" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, length: -1)
+ }.should raise_error(ArgumentError, "negative string size (or size too big)")
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/random/shared/random_bytes.rb b/spec/ruby/library/openssl/random/shared/random_bytes.rb
index 037f10d409..f97ccd9974 100644
--- a/spec/ruby/library/openssl/random/shared/random_bytes.rb
+++ b/spec/ruby/library/openssl/random/shared/random_bytes.rb
@@ -1,7 +1,7 @@
require_relative '../../../../spec_helper'
require 'openssl'
-describe :openssl_random_bytes, shared: true do |cmd|
+describe :openssl_random_bytes, shared: true do
it "generates a random binary string of specified length" do
(1..64).each do |idx|
bytes = OpenSSL::Random.send(@method, idx)
diff --git a/spec/ruby/library/openssl/secure_compare_spec.rb b/spec/ruby/library/openssl/secure_compare_spec.rb
new file mode 100644
index 0000000000..cec48e01e7
--- /dev/null
+++ b/spec/ruby/library/openssl/secure_compare_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL.secure_compare" do
+ it "returns true for two strings with the same content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the quick brown fox jumps over the lazy dog"
+ OpenSSL.secure_compare(input1, input2).should be_true
+ end
+
+ it "returns false for two strings with different content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the lazy dog jumps over the quick brown fox"
+ OpenSSL.secure_compare(input1, input2).should be_false
+ end
+
+ it "converts both arguments to strings using #to_str, but adds equality check for the original objects" do
+ input1 = mock("input1")
+ input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ input2 = mock("input2")
+ input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ OpenSSL.secure_compare(input1, input2).should be_false
+
+ input = mock("input")
+ input.should_receive(:to_str).twice.and_return("the quick brown fox jumps over the lazy dog")
+ OpenSSL.secure_compare(input, input).should be_true
+ end
+
+ it "does not accept arguments that are not string and cannot be coerced into strings" do
+ -> {
+ OpenSSL.secure_compare("input1", :input2)
+ }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
+
+ -> {
+ OpenSSL.secure_compare(Object.new, "input2")
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+end
diff --git a/spec/ruby/library/openssl/x509/name/verify_spec.rb b/spec/ruby/library/openssl/x509/store/verify_spec.rb
index f5384f5764..6a6a53d992 100644
--- a/spec/ruby/library/openssl/x509/name/verify_spec.rb
+++ b/spec/ruby/library/openssl/x509/store/verify_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../../../spec_helper'
require 'openssl'
-describe "OpenSSL::X509::Name.verify" do
+describe "OpenSSL::X509::Store#verify" do
it "returns true for valid certificate" do
key = OpenSSL::PKey::RSA.new 2048
cert = OpenSSL::X509::Certificate.new
@@ -10,12 +10,12 @@ describe "OpenSSL::X509::Name.verify" do
cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
cert.issuer = cert.subject
cert.public_key = key.public_key
- cert.not_before = Time.now
+ cert.not_before = Time.now - 10
cert.not_after = cert.not_before + 365 * 24 * 60 * 60
- cert.sign key, OpenSSL::Digest.new('SHA1')
+ cert.sign key, OpenSSL::Digest.new('SHA256')
store = OpenSSL::X509::Store.new
store.add_cert(cert)
- store.verify(cert).should == true
+ [store.verify(cert), store.error, store.error_string].should == [true, 0, "ok"]
end
it "returns false for an expired certificate" do
@@ -28,7 +28,7 @@ describe "OpenSSL::X509::Name.verify" do
cert.public_key = key.public_key
cert.not_before = Time.now - 10
cert.not_after = Time.now - 5
- cert.sign key, OpenSSL::Digest.new('SHA1')
+ cert.sign key, OpenSSL::Digest.new('SHA256')
store = OpenSSL::X509::Store.new
store.add_cert(cert)
store.verify(cert).should == false