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.rb137
-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.rb162
-rw-r--r--spec/ruby/library/openssl/kdf/scrypt_spec.rb210
-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/shared/constants.rb2
-rw-r--r--spec/ruby/library/openssl/x509/store/verify_spec.rb (renamed from spec/ruby/library/openssl/x509/name/verify_spec.rb)2
17 files changed, 873 insertions, 32 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..b5911716ca
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/initialize_spec.rb
@@ -0,0 +1,137 @@
+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
+
+ version_is OpenSSL::VERSION, "4.0.0" do
+ it "throws an error when called with an unknown digest" do
+ -> { OpenSSL::Digest.new("wd40") }.should raise_error(OpenSSL::Digest::DigestError, /wd40/)
+ end
+ end
+
+ it "cannot be called with a symbol" do
+ -> { OpenSSL::Digest.new(:SHA1) }.should raise_error(TypeError)
+ 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)
+ 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..1112972060
--- /dev/null
+++ b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
@@ -0,0 +1,162 @@
+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)
+ end
+
+ version_is OpenSSL::VERSION, "4.0.0" do
+ it "raises a OpenSSL::Digest::DigestError for unknown digest algorithms" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40")
+ }.should raise_error(OpenSSL::Digest::DigestError, /wd40/)
+ end
+ 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..e01b8bca8a
--- /dev/null
+++ b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
@@ -0,0 +1,210 @@
+require_relative '../../../spec_helper'
+require 'openssl'
+
+# LibreSSL seems not to support scrypt
+guard -> { OpenSSL::OPENSSL_VERSION.start_with?('OpenSSL') and OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10100000 } 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/shared/constants.rb b/spec/ruby/library/openssl/shared/constants.rb
index 0bed4156a1..836f75011b 100644
--- a/spec/ruby/library/openssl/shared/constants.rb
+++ b/spec/ruby/library/openssl/shared/constants.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
module HMACConstants
Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
diff --git a/spec/ruby/library/openssl/x509/name/verify_spec.rb b/spec/ruby/library/openssl/x509/store/verify_spec.rb
index 6dcfc99466..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