diff options
Diffstat (limited to 'test')
33 files changed, 1604 insertions, 665 deletions
diff --git a/test/envutil.rb b/test/envutil.rb index 89332b35..05d6fe27 100644 --- a/test/envutil.rb +++ b/test/envutil.rb @@ -92,6 +92,18 @@ module EnvUtil end module_function :invoke_ruby + def verbose_warning + class << (stderr = "".dup) + alias write << + end + stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true + yield stderr + return $stderr + ensure + stderr, $stderr, $VERBOSE = $stderr, stderr, verbose + end + module_function :verbose_warning + def suppress_warning verbose, $VERBOSE = $VERBOSE, nil yield @@ -220,6 +232,17 @@ eom raise marshal_error if marshal_error end + def assert_warning(pat, msg = nil) + stderr = EnvUtil.verbose_warning { + yield + } + if Regexp === pat + assert_match pat, stderr, msg + else + assert_equal pat, stderr, msg + end + end + def message msg = nil, ending = ".", &default proc { msg = msg.call.chomp(".") if Proc === msg diff --git a/test/test_asn1.rb b/test/test_asn1.rb index 55cb1f0b..11707037 100644 --- a/test/test_asn1.rb +++ b/test/test_asn1.rb @@ -1,10 +1,10 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestASN1 < OpenSSL::TestCase - def test_decode + def test_decode_x509_certificate subj = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=TestCA") key = Fixtures.pkey("rsa1024") now = Time.at(Time.now.to_i) # suppress usec @@ -130,9 +130,9 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase assert_equal(OpenSSL::ASN1::Sequence, spkey.class) assert_equal(2, spkey.value.size) assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class) - assert_equal(143085709396403084580358323862163416700436550432664688288860593156058579474547937626086626045206357324274536445865308750491138538454154232826011964045825759324933943290377903384882276841880081931690695505836279972214003660451338124170055999155993192881685495391496854691199517389593073052473319331505702779271, spkey.value[0].value) + assert_equal(cert.public_key.n, spkey.value[0].value) assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class) - assert_equal(65537, spkey.value[1].value) + assert_equal(cert.public_key.e, spkey.value[1].value) extensions = tbs_cert.value[7] assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class) @@ -193,66 +193,8 @@ class OpenSSL::TestASN1 < OpenSSL::TestCase assert_equal(cululated_sig, sig_val.value) end - def test_encode_boolean - encode_decode_test(OpenSSL::ASN1::Boolean, [true, false]) - end - - def test_encode_integer - encode_decode_test(OpenSSL::ASN1::Integer, [72, -127, -128, 128, -1, 0, 1, -(2**12345), 2**12345]) - end - - def test_encode_nil - m = OpenSSL::ASN1 - [ - m::Boolean, m::Integer, m::BitString, m::OctetString, - m::ObjectId, m::Enumerated, m::UTF8String, m::UTCTime, - m::GeneralizedTime, m::Sequence, m::Set - ].each do |klass| - #Primitives raise TypeError, Constructives NoMethodError - assert_raise(TypeError, NoMethodError) { klass.send(:new, nil).to_der } - end - end - - def encode_decode_test(type, values) - values.each do |v| - assert_equal(v, OpenSSL::ASN1.decode(type.new(v).to_der).value) - end - end - - def test_decode_pem #should fail gracefully (cf. [ruby-dev:44542]) - pem = <<-_EOS_ ------BEGIN CERTIFICATE----- -MIIC8zCCAdugAwIBAgIBATANBgkqhkiG9w0BAQUFADA9MRMwEQYKCZImiZPyLGQB -GRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMQswCQYDVQQDDAJDQTAe -Fw0xMTA5MjUxMzQ4MjZaFw0xMTA5MjUxNDQ4MjZaMD0xEzARBgoJkiaJk/IsZAEZ -FgNvcmcxGTAXBgoJkiaJk/IsZAEZFglydWJ5LWxhbmcxCzAJBgNVBAMMAkNBMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuV9ht9J7k4NBs38jOXvvTKY9 -gW8nLICSno5EETR1cuF7i4pNs9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enen -fzq/t/e/1IRW0wkJUJUFQign4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWm -qbjs07JbuS4QQGGXLc+Su96DkYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v6 -8JkRFIhdGlb6JL8fllf/A/blNwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX -9KZYcU00mOX+fdxOSnGqS/8JDRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wID -AQABMA0GCSqGSIb3DQEBBQUAA4IBAQAiAtrIr1pLX4GYN5klviWKb8HC9ICYuAFI -NfE3FwqzErEVXotuMe3yPVyB3Bv6rjYY/x5EtS5+WPTbHlvHZTkfcsnTpizcn4mW -dJ6dDRaFCHt1YKKjUxqBt9lvvrc3nReYZN/P+s1mrDhWzGf8iPZgf8sFUHgnaK7W -CXRVXmPFgCDRNpDDVQ0MQkr509yYfTH+dujNzqTCwSvkyZFyQ7Oe8Yj0VR6kquG3 -rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm -/93PnPG1IvPjYNd5VlV+sXSnaxQn974HRCsMv7jA8BD6IgSaX6WK ------END CERTIFICATE----- - _EOS_ - assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1.decode(pem) } - assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1.decode_all(pem) } - end - - def test_primitive_cannot_set_infinite_length - prim = OpenSSL::ASN1::Integer.new(50) - assert_equal false, prim.infinite_length - assert_not_respond_to prim, :infinite_length= - end - def test_decode_all - expected = %w{ 02 01 01 02 01 02 02 01 03 } - raw = [expected.join('')].pack('H*') + raw = B(%w{ 02 01 01 02 01 02 02 01 03 }) ary = OpenSSL::ASN1.decode_all(raw) assert_equal(3, ary.size) ary.each_with_index do |asn1, i| @@ -261,288 +203,406 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm end end - def test_decode_utctime - expected = Time.at 1374535380 - assert_equal expected, OpenSSL::ASN1.decode("\x17\v1307222323Z").value - - expected += 17 - assert_equal expected, OpenSSL::ASN1.decode("\x17\r130722232317Z").value + def test_object_id_register + oid = "1.2.34.56789" + pend "OID 1.2.34.56789 is already registered" if OpenSSL::ASN1::ObjectId(oid).sn + assert_equal true, OpenSSL::ASN1::ObjectId.register(oid, "ossl-test-sn", "ossl-test-ln") + obj = OpenSSL::ASN1::ObjectId(oid) + assert_equal oid, obj.oid + assert_equal "ossl-test-sn", obj.sn + assert_equal "ossl-test-ln", obj.ln + obj = encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId("ossl-test-ln") + assert_equal "ossl-test-sn", obj.value end - def test_encode_utctime_2k38 - encoded = OpenSSL::ASN1::UTCTime(2 ** 31 - 1).to_der - assert_equal 2 ** 31 - 1, OpenSSL::ASN1.decode(encoded).value.to_i - - encoded = OpenSSL::ASN1::UTCTime(2 ** 31).to_der - assert_equal 2 ** 31, OpenSSL::ASN1.decode(encoded).value.to_i + def test_end_of_content + encode_decode_test B(%w{ 00 00 }), OpenSSL::ASN1::EndOfContent.new + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 00 01 00 })) + } end - def test_decode_generalisedtime - expected = Time.at 1481225640 - assert_equal expected, OpenSSL::ASN1.decode("\x18\x0D201612081934Z").value - - expected += 29 - assert_equal expected, OpenSSL::ASN1.decode("\x18\x0F20161208193429Z").value + def test_boolean + encode_decode_test B(%w{ 01 01 00 }), OpenSSL::ASN1::Boolean.new(false) + encode_decode_test B(%w{ 01 01 FF }), OpenSSL::ASN1::Boolean.new(true) + decode_test B(%w{ 01 01 01 }), OpenSSL::ASN1::Boolean.new(true) + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 01 02 00 00 })) + } end - def test_decode_enumerated - encoded = OpenSSL::ASN1.Enumerated(0).to_der - assert_equal "\x0a\x01\x00".b, encoded - assert_equal encoded, OpenSSL::ASN1.decode(encoded).to_der + def test_integer + encode_decode_test B(%w{ 02 01 00 }), OpenSSL::ASN1::Integer.new(0) + encode_decode_test B(%w{ 02 01 48 }), OpenSSL::ASN1::Integer.new(72) + encode_decode_test B(%w{ 02 02 00 80 }), OpenSSL::ASN1::Integer.new(128) + encode_decode_test B(%w{ 02 01 81 }), OpenSSL::ASN1::Integer.new(-127) + encode_decode_test B(%w{ 02 01 80 }), OpenSSL::ASN1::Integer.new(-128) + encode_decode_test B(%w{ 02 01 FF }), OpenSSL::ASN1::Integer.new(-1) + encode_decode_test B(%w{ 02 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(2 ** 64) + encode_decode_test B(%w{ 02 09 FF 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Integer.new(-(2 ** 64)) + # FIXME: OpenSSL < 1.1.0 does not fail + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 02 02 00 7F })) + # } + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 02 02 FF 80 })) + # } + end + + def test_enumerated + encode_decode_test B(%w{ 0A 01 00 }), OpenSSL::ASN1::Enumerated.new(0) + encode_decode_test B(%w{ 0A 01 48 }), OpenSSL::ASN1::Enumerated.new(72) + encode_decode_test B(%w{ 0A 02 00 80 }), OpenSSL::ASN1::Enumerated.new(128) + encode_decode_test B(%w{ 0A 09 01 00 00 00 00 00 00 00 00 }), OpenSSL::ASN1::Enumerated.new(2 ** 64) + end + + def test_bitstring + encode_decode_test B(%w{ 03 01 00 }), OpenSSL::ASN1::BitString.new(B(%w{})) + encode_decode_test B(%w{ 03 02 00 01 }), OpenSSL::ASN1::BitString.new(B(%w{ 01 })) + obj = OpenSSL::ASN1::BitString.new(B(%w{ F0 })) + obj.unused_bits = 4 + encode_decode_test B(%w{ 03 02 04 F0 }), obj + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 03 00 })) + } + # OpenSSL < OpenSSL_1_0_1k and LibreSSL ignore the error + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 03 03 08 FF 00 })) + # } + # OpenSSL does not seem to prohibit this, though X.690 8.6.2.3 (15/08) does + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 03 01 04 })) + # } + assert_raise(OpenSSL::ASN1::ASN1Error) { + obj = OpenSSL::ASN1::BitString.new(B(%w{ FF FF })) + obj.unused_bits = 8 + obj.to_der + } end - def test_create_inf_length_primitive - expected = %w{ 24 80 04 01 61 00 00 } - raw = [expected.join('')].pack('H*') - 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) - asn1 = OpenSSL::ASN1.decode(raw) - assert(asn1.infinite_length) - assert_equal(raw, asn1.to_der) + def test_string_basic + test = -> (tag, klass) { + encode_decode_test tag.chr + B(%w{ 00 }), klass.new(B(%w{})) + encode_decode_test tag.chr + B(%w{ 02 00 01 }), klass.new(B(%w{ 00 01 })) + } + test.(4, OpenSSL::ASN1::OctetString) + test.(12, OpenSSL::ASN1::UTF8String) + test.(18, OpenSSL::ASN1::NumericString) + test.(19, OpenSSL::ASN1::PrintableString) + test.(20, OpenSSL::ASN1::T61String) + test.(21, OpenSSL::ASN1::VideotexString) + test.(22, OpenSSL::ASN1::IA5String) + test.(25, OpenSSL::ASN1::GraphicString) + test.(26, OpenSSL::ASN1::ISO64String) + test.(27, OpenSSL::ASN1::GeneralString) + test.(28, OpenSSL::ASN1::UniversalString) + test.(30, OpenSSL::ASN1::BMPString) + end + + def test_null + encode_decode_test B(%w{ 05 00 }), OpenSSL::ASN1::Null.new(nil) + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 05 01 00 })) + } end - 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.to_der + def test_object_identifier + encode_decode_test B(%w{ 06 01 00 }), OpenSSL::ASN1::ObjectId.new("0.0".b) + encode_decode_test B(%w{ 06 01 28 }), OpenSSL::ASN1::ObjectId.new("1.0".b) + encode_decode_test B(%w{ 06 03 88 37 03 }), OpenSSL::ASN1::ObjectId.new("2.999.3".b) + encode_decode_test B(%w{ 06 05 2A 22 83 BB 55 }), OpenSSL::ASN1::ObjectId.new("1.2.34.56789".b) + obj = encode_decode_test B(%w{ 06 09 60 86 48 01 65 03 04 02 01 }), OpenSSL::ASN1::ObjectId.new("sha256") + assert_equal "2.16.840.1.101.3.4.2.1", obj.oid + assert_equal "SHA256", obj.sn + assert_equal "sha256", obj.ln + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 06 00 })) + } + assert_raise(OpenSSL::ASN1::ASN1Error) { + OpenSSL::ASN1.decode(B(%w{ 06 01 80 })) + } + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("3.0".b).to_der } + assert_raise(OpenSSL::ASN1::ASN1Error) { OpenSSL::ASN1::ObjectId.new("0.40".b).to_der } + + begin + oid = (0...100).to_a.join(".").b + obj = OpenSSL::ASN1::ObjectId.new(oid) + assert_equal oid, obj.oid + rescue OpenSSL::ASN1::ASN1Error + pend "OBJ_obj2txt() not working (LibreSSL?)" if $!.message =~ /OBJ_obj2txt/ + raise end end - 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.infinite_length = true - cons.to_der + def test_sequence + encode_decode_test B(%w{ 30 00 }), OpenSSL::ASN1::Sequence.new([]) + encode_decode_test B(%w{ 30 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::Sequence.new([]), + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) + ]) + + expected = OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) + expected.indefinite_length = true + encode_decode_test B(%w{ 30 80 04 01 00 00 00 }), expected + + # OpenSSL::ASN1::EndOfContent can only be at the end + obj = OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::EndOfContent.new, + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), + OpenSSL::ASN1::EndOfContent.new, + ]) + obj.indefinite_length = true + assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } + + # The last EOC in value is ignored if indefinite length form is used + expected = OpenSSL::ASN1::Sequence.new([ + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })), + OpenSSL::ASN1::EndOfContent.new + ]) + expected.indefinite_length = true + encode_test B(%w{ 30 80 04 01 00 00 00 }), expected + end + + def test_set + encode_decode_test B(%w{ 31 00 }), OpenSSL::ASN1::Set.new([]) + encode_decode_test B(%w{ 31 07 05 00 30 00 04 01 00 }), OpenSSL::ASN1::Set.new([ + OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::Sequence.new([]), + OpenSSL::ASN1::OctetString.new(B(%w{ 00 })) + ]) + expected = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::OctetString.new(B(%w{ 00 }))]) + expected.indefinite_length = true + encode_decode_test B(%w{ 31 80 04 01 00 00 00 }), expected + end + + def test_utctime + encode_decode_test B(%w{ 17 0D }) + "160908234339Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 39)) + # Seconds is omitted + decode_test B(%w{ 17 0B }) + "1609082343Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(2016, 9, 8, 23, 43, 0)) + begin + # possible range of UTCTime is 1969-2068 currently + encode_decode_test B(%w{ 17 0D }) + "690908234339Z".b, + OpenSSL::ASN1::UTCTime.new(Time.utc(1969, 9, 8, 23, 43, 39)) + rescue OpenSSL::ASN1::ASN1Error + pend "No negative time_t support?" end - end + # not implemented + # decode_test B(%w{ 17 11 }) + "500908234339+0930".b, + # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 39, "+09:30")) + # decode_test B(%w{ 17 0F }) + "5009082343-0930".b, + # OpenSSL::ASN1::UTCTime.new(Time.new(1950, 9, 8, 23, 43, 0, "-09:30")) + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 17 0C }) + "500908234339".b) + # } + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 17 0D }) + "500908234339Y".b) + # } + end + + def test_generalizedtime + encode_decode_test B(%w{ 18 0F }) + "20161208193429Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 29)) + encode_decode_test B(%w{ 18 0F }) + "99990908234339Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(9999, 9, 8, 23, 43, 39)) + decode_test B(%w{ 18 0D }) + "201612081934Z".b, + OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 0)) + # not implemented + # decode_test B(%w{ 18 13 }) + "20161208193439+0930".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 39, "+09:30")) + # decode_test B(%w{ 18 11 }) + "201612081934-0930".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:30")) + # decode_test B(%w{ 18 11 }) + "201612081934-09".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.new(2016, 12, 8, 19, 34, 0, "-09:00")) + # decode_test B(%w{ 18 0D }) + "2016120819.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) + # decode_test B(%w{ 18 0D }) + "2016120819,5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 30, 0)) + # decode_test B(%w{ 18 0F }) + "201612081934.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 30)) + # decode_test B(%w{ 18 11 }) + "20161208193439.5Z".b, + # OpenSSL::ASN1::GeneralizedTime.new(Time.utc(2016, 12, 8, 19, 34, 39.5)) + # assert_raise(OpenSSL::ASN1::ASN1Error) { + # OpenSSL::ASN1.decode(B(%w{ 18 0D }) + "201612081934Y".b) + # } + end + + def test_basic_asn1data + encode_test B(%w{ 00 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 0, :UNIVERSAL) + encode_test B(%w{ 01 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :UNIVERSAL) + encode_decode_test B(%w{ 41 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :APPLICATION) + encode_decode_test B(%w{ 81 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :CONTEXT_SPECIFIC) + encode_decode_test B(%w{ C1 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 1, :PRIVATE) + encode_decode_test B(%w{ 1F 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 32, :UNIVERSAL) + encode_decode_test B(%w{ 1F C0 20 00 }), OpenSSL::ASN1::ASN1Data.new(B(%w{}), 8224, :UNIVERSAL) + encode_decode_test B(%w{ 41 02 AB CD }), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :APPLICATION) + encode_decode_test B(%w{ 41 81 80 } + %w{ AB CD } * 64), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 64), 1, :APPLICATION) + encode_decode_test B(%w{ 41 82 01 00 } + %w{ AB CD } * 128), OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD } * 128), 1, :APPLICATION) + encode_decode_test B(%w{ 61 00 }), OpenSSL::ASN1::ASN1Data.new([], 1, :APPLICATION) + obj = OpenSSL::ASN1::ASN1Data.new([OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE)], 1, :APPLICATION) + obj.indefinite_length = true + encode_decode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::ASN1Data.new([ + OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 2, :PRIVATE), + OpenSSL::ASN1::EndOfContent.new + ], 1, :APPLICATION) + obj.indefinite_length = true + encode_test B(%w{ 61 80 C2 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::ASN1Data.new(B(%w{ AB CD }), 1, :UNIVERSAL) + obj.indefinite_length = true + assert_raise(OpenSSL::ASN1::ASN1Error) { obj.to_der } + end + + def test_basic_primitive + encode_test B(%w{ 00 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 0) + encode_test B(%w{ 01 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :UNIVERSAL) + encode_test B(%w{ 81 00 }), OpenSSL::ASN1::Primitive.new(B(%w{}), 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 01 02 AB CD }), OpenSSL::ASN1::Primitive.new(B(%w{ AB CD }), 1) + assert_raise(TypeError) { OpenSSL::ASN1::Primitive.new([], 1).to_der } - def test_parse_empty_sequence - expected = %w{ A0 07 30 02 30 00 02 01 00 } - raw = [expected.join('')].pack('H*') - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(raw, asn1.to_der) - assert_equal(2, asn1.value.size) - seq = asn1.value[0] - assert_equal(1, seq.value.size) - inner_seq = seq.value[0] - assert_equal(0, inner_seq.value.size) - end - - def test_parse_tagged_0_infinite - expected = %w{ 30 80 02 01 01 80 01 02 00 00 } - raw = [expected.join('')].pack('H*') - asn1 = OpenSSL::ASN1.decode(raw) - assert_equal(3, asn1.value.size) - int = asn1.value[0] - assert_universal(OpenSSL::ASN1::INTEGER, int) - tagged = asn1.value[1] - assert_equal(0, tagged.tag) - assert_universal(OpenSSL::ASN1::EOC, asn1.value[2]) - assert_equal(raw, asn1.to_der) - end - - def test_seq_infinite_length - 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) + prim = OpenSSL::ASN1::Integer.new(50) + assert_equal false, prim.indefinite_length + assert_not_respond_to prim, :indefinite_length= end - def test_set_infinite_length - 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 - 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) + def test_basic_constructed + octet_string = OpenSSL::ASN1::OctetString.new(B(%w{ AB CD })) + encode_test B(%w{ 20 00 }), OpenSSL::ASN1::Constructive.new([], 0) + encode_test B(%w{ 21 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :UNIVERSAL) + encode_test B(%w{ A1 00 }), OpenSSL::ASN1::Constructive.new([], 1, nil, :CONTEXT_SPECIFIC) + encode_test B(%w{ 21 04 04 02 AB CD }), OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj = OpenSSL::ASN1::Constructive.new([octet_string], 1) + obj.indefinite_length = true + encode_decode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj + obj = OpenSSL::ASN1::Constructive.new([octet_string, OpenSSL::ASN1::EndOfContent.new], 1) + obj.indefinite_length = true + encode_test B(%w{ 21 80 04 02 AB CD 00 00 }), obj end def test_prim_explicit_tagging 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 + encode_test B(%w{ A0 03 04 01 61 }), oct_str + oct_str2 = OpenSSL::ASN1::OctetString.new("a", 1, :EXPLICIT, :APPLICATION) + encode_test B(%w{ 61 03 04 01 61 }), oct_str2 - def test_prim_explicit_tagging_tag_class - 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) + decoded = OpenSSL::ASN1.decode(oct_str2.to_der) + assert_equal :APPLICATION, decoded.tag_class + assert_equal 1, decoded.tag + assert_equal 1, decoded.value.size + inner = decoded.value[0] + assert_equal OpenSSL::ASN1::OctetString, inner.class + assert_equal B(%w{ 61 }), inner.value end def test_prim_implicit_tagging 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 + encode_test B(%w{ 80 01 01 }), int + int2 = OpenSSL::ASN1::Integer.new(1, 1, :IMPLICIT, :APPLICATION) + encode_test B(%w{ 41 01 01 }), int2 + decoded = OpenSSL::ASN1.decode(int2.to_der) + assert_equal :APPLICATION, decoded.tag_class + assert_equal 1, decoded.tag + assert_equal B(%w{ 01 }), decoded.value - def test_prim_implicit_tagging_tag_class - 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) + # Special behavior: Encoding universal types with non-default 'tag' + # attribute and nil tagging method. + int3 = OpenSSL::ASN1::Integer.new(1, 1) + encode_test B(%w{ 01 01 01 }), int3 end def test_cons_explicit_tagging 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 + encode_test B(%w{ A2 07 30 05 13 03 61 62 63 }), seq + seq2 = OpenSSL::ASN1::Sequence.new(content, 3, :EXPLICIT, :APPLICATION) + encode_test B(%w{ 63 07 30 05 13 03 61 62 63 }), seq2 - def test_cons_explicit_tagging_inf_length - 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) + content3 = [ OpenSSL::ASN1::PrintableString.new('abc'), + OpenSSL::ASN1::EndOfContent.new() ] + seq3 = OpenSSL::ASN1::Sequence.new(content3, 2, :EXPLICIT) + seq3.indefinite_length = true + encode_test B(%w{ A2 80 30 80 13 03 61 62 63 00 00 00 00 }), seq3 end def test_cons_implicit_tagging 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 + encode_test B(%w{ A1 02 05 00 }), seq + seq2 = OpenSSL::ASN1::Sequence.new(content, 1, :IMPLICIT, :APPLICATION) + encode_test B(%w{ 61 02 05 00 }), seq2 - def test_cons_implicit_tagging_inf_length - 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 + content3 = [ OpenSSL::ASN1::Null.new(nil), + OpenSSL::ASN1::EndOfContent.new() ] + seq3 = OpenSSL::ASN1::Sequence.new(content3, 1, :IMPLICIT) + seq3.indefinite_length = true + encode_test B(%w{ A1 80 05 00 00 00 }), seq3 - def test_octet_string_infinite_length_explicit_tagging - 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) + # Special behavior: Encoding universal types with non-default 'tag' + # attribute and nil tagging method. + seq4 = OpenSSL::ASN1::Sequence.new([], 1) + encode_test B(%w{ 21 00 }), seq4 end - def test_octet_string_infinite_length_implicit_tagging + def test_octet_string_constructed_tagging + octets = [ OpenSSL::ASN1::OctetString.new('aaa') ] + cons = OpenSSL::ASN1::Constructive.new(octets, 0, :IMPLICIT) + encode_test B(%w{ A0 05 04 03 61 61 61 }), cons + 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) + cons.indefinite_length = true + encode_test B(%w{ A0 80 04 03 61 61 61 00 00 }), cons end - def test_recursive_octet_string_infinite_length + def test_recursive_octet_string_indefinite_length 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 + container1.indefinite_length = true container2 = OpenSSL::ASN1::Constructive.new(octets_sub2, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL) - container2.infinite_length = true + container2.indefinite_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*') + cons.indefinite_length = true + raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) assert_equal(raw, cons.to_der) assert_equal(raw, OpenSSL::ASN1.decode(raw).to_der) end - def test_bit_string_infinite_length - 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 - assert_raise(OpenSSL::ASN1::ASN1Error) do - spec = %w{ 02 80 02 01 01 00 00 } - raw = [spec.join('')].pack('H*') - OpenSSL::ASN1.decode(raw) - OpenSSL::ASN1.decode_all(raw) - end - end - def test_recursive_octet_string_parse - test = %w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 } - raw = [test.join('')].pack('H*') + raw = B(%w{ 24 80 24 80 04 01 01 00 00 24 80 04 01 02 00 00 04 01 03 00 00 }) asn1 = OpenSSL::ASN1.decode(raw) assert_equal(OpenSSL::ASN1::Constructive, asn1.class) assert_universal(OpenSSL::ASN1::OCTET_STRING, asn1) - assert_equal(true, asn1.infinite_length) - assert_equal(4, asn1.value.size) + assert_equal(true, asn1.indefinite_length) + assert_equal(3, asn1.value.size) nested1 = asn1.value[0] assert_equal(OpenSSL::ASN1::Constructive, nested1.class) assert_universal(OpenSSL::ASN1::OCTET_STRING, nested1) - assert_equal(true, nested1.infinite_length) - assert_equal(2, nested1.value.size) + assert_equal(true, nested1.indefinite_length) + assert_equal(1, nested1.value.size) oct1 = nested1.value[0] assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1) - assert_equal(false, oct1.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, nested1.value[1]) - assert_equal(false, nested1.value[1].infinite_length) + assert_equal(false, oct1.indefinite_length) nested2 = asn1.value[1] assert_equal(OpenSSL::ASN1::Constructive, nested2.class) assert_universal(OpenSSL::ASN1::OCTET_STRING, nested2) - assert_equal(true, nested2.infinite_length) - assert_equal(2, nested2.value.size) + assert_equal(true, nested2.indefinite_length) + assert_equal(1, nested2.value.size) oct2 = nested2.value[0] assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2) - assert_equal(false, oct2.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, nested2.value[1]) - assert_equal(false, nested2.value[1].infinite_length) + assert_equal(false, oct2.indefinite_length) oct3 = asn1.value[2] assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3) - assert_equal(false, oct3.infinite_length) - assert_universal(OpenSSL::ASN1::EOC, asn1.value[3]) - assert_equal(false, asn1.value[3].infinite_length) + assert_equal(false, oct3.indefinite_length) end def test_decode_constructed_overread @@ -577,6 +637,46 @@ rEzBQ0F9dUyqQ9gyRg8KHhDfv9HzT1d/rnUZMkoombwYBRIUChGCYV0GnJcan2Zm private + def B(ary) + [ary.join].pack("H*") + end + + def assert_asn1_equal(a, b) + assert_equal a.class, b.class + assert_equal a.tag, b.tag + assert_equal a.tag_class, b.tag_class + assert_equal a.indefinite_length, b.indefinite_length + assert_equal a.unused_bits, b.unused_bits if a.respond_to?(:unused_bits) + case a.value + when Array + a.value.each_with_index { |ai, i| + assert_asn1_equal ai, b.value[i] + } + else + if OpenSSL::ASN1::ObjectId === a + assert_equal a.oid, b.oid + else + assert_equal a.value, b.value + end + end + assert_equal a.to_der, b.to_der + end + + def encode_test(der, obj) + assert_equal der, obj.to_der + end + + def decode_test(der, obj) + decoded = OpenSSL::ASN1.decode(der) + assert_asn1_equal obj, decoded + decoded + end + + def encode_decode_test(der, obj) + encode_test(der, obj) + decode_test(der, obj) + end + def assert_universal(tag, asn1) assert_equal(tag, asn1.tag) if asn1.respond_to?(:tagging) diff --git a/test/test_bn.rb b/test/test_bn.rb index 5f3ae2b4..274afba3 100644 --- a/test/test_bn.rb +++ b/test/test_bn.rb @@ -1,61 +1,276 @@ +# coding: us-ascii # frozen_string_literal: false require_relative 'utils' +require "prime" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestBN < OpenSSL::TestCase - def test_new_str - e1 = OpenSSL::BN.new(999.to_s(16), 16) # OpenSSL::BN.new(str, 16) must be most stable - e2 = OpenSSL::BN.new((2**107-1).to_s(16), 16) - assert_equal(e1, OpenSSL::BN.new("999")) - assert_equal(e2, OpenSSL::BN.new((2**107-1).to_s)) - assert_equal(e1, OpenSSL::BN.new("999", 10)) - assert_equal(e2, OpenSSL::BN.new((2**107-1).to_s, 10)) - assert_equal(e1, OpenSSL::BN.new("\x03\xE7", 2)) - assert_equal(e2, OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2)) - assert_equal(e1, OpenSSL::BN.new("\x00\x00\x00\x02\x03\xE7", 0)) - assert_equal(e2, OpenSSL::BN.new("\x00\x00\x00\x0E\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) - end - - def test_new_bn - e1 = OpenSSL::BN.new(999.to_s(16), 16) - e2 = OpenSSL::BN.new((2**107-1).to_s(16), 16) - assert_equal(e1, OpenSSL::BN.new(e1)) - assert_equal(e2, OpenSSL::BN.new(e2)) - end - - def test_new_integer - assert_equal(999.to_bn, OpenSSL::BN.new(999)) - assert_equal((2 ** 107 - 1).to_bn, OpenSSL::BN.new(2 ** 107 - 1)) - assert_equal(-999.to_bn, OpenSSL::BN.new(-999)) - assert_equal((-(2 ** 107 - 1)).to_bn, OpenSSL::BN.new(-(2 ** 107 - 1))) - end - - def test_to_bn - e1 = OpenSSL::BN.new(999.to_s(16), 16) - e2 = OpenSSL::BN.new((2**107-1).to_s(16), 16) - assert_equal(e1, 999.to_bn) - assert_equal(e2, (2**107-1).to_bn) - end - - def test_prime_p - assert_equal(true, OpenSSL::BN.new((2 ** 107 - 1).to_s(16), 16).prime?) - assert_equal(true, OpenSSL::BN.new((2 ** 127 - 1).to_s(16), 16).prime?(1)) - end - - def test_cmp - bn1 = OpenSSL::BN.new('1') - bn2 = OpenSSL::BN.new('1') - bn3 = OpenSSL::BN.new('2') - assert_equal(false, bn1 == nil) - assert_equal(true, bn1 != nil) - assert_equal(true, bn1 == bn2) - assert_equal(false, bn1 == bn3) - assert_equal(true, bn1.eql?(bn2)) - assert_equal(false, bn1.eql?(bn3)) - assert_equal(bn1.hash, bn2.hash) - assert_not_equal(bn3.hash, bn1.hash) - assert_instance_of(String, bn1.hash.to_s) + def setup + super + @e1 = OpenSSL::BN.new(999.to_s(16), 16) # OpenSSL::BN.new(str, 16) must be most stable + @e2 = OpenSSL::BN.new("-" + 999.to_s(16), 16) + @e3 = OpenSSL::BN.new((2**107-1).to_s(16), 16) + @e4 = OpenSSL::BN.new("-" + (2**107-1).to_s(16), 16) + end + + def test_new + assert_equal(@e1, OpenSSL::BN.new("999")) + assert_equal(@e1, OpenSSL::BN.new("999", 10)) + assert_equal(@e1, OpenSSL::BN.new("\x03\xE7", 2)) + assert_equal(@e1, OpenSSL::BN.new("\x00\x00\x00\x02\x03\xE7", 0)) + assert_equal(@e2, OpenSSL::BN.new("-999")) + assert_equal(@e2, OpenSSL::BN.new("-999", 10)) + assert_equal(@e2, OpenSSL::BN.new("\x00\x00\x00\x02\x83\xE7", 0)) + assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s)) + assert_equal(@e3, OpenSSL::BN.new((2**107-1).to_s, 10)) + assert_equal(@e3, OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2)) + assert_equal(@e3, OpenSSL::BN.new("\x00\x00\x00\x0E\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) + assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s)) + assert_equal(@e4, OpenSSL::BN.new("-" + (2**107-1).to_s, 10)) + assert_equal(@e4, OpenSSL::BN.new("\x00\x00\x00\x0E\x87\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 0)) + + e1copy = OpenSSL::BN.new(@e1) + assert_equal(@e1, e1copy) + e1copy.clear_bit!(0) #=> 998 + assert_not_equal(@e1, e1copy) + + assert_equal(@e1, OpenSSL::BN.new(999)) + assert_equal(@e2, OpenSSL::BN.new(-999)) + assert_equal(@e3, OpenSSL::BN.new(2**107-1)) + assert_equal(@e4, OpenSSL::BN.new(-(2**107-1))) + + assert_equal(@e1, 999.to_bn) + assert_equal(@e2, -999.to_bn) + assert_equal(@e3, (2**107-1).to_bn) + assert_equal(@e4, (-(2**107-1)).to_bn) + end + + def test_to_str + assert_equal("999", @e1.to_s(10)) + assert_equal("-999", @e2.to_s(10)) + assert_equal((2**107-1).to_s, @e3.to_s(10)) + assert_equal((-(2**107-1)).to_s, @e4.to_s(10)) + assert_equal("999", @e1.to_s) + + assert_equal("03E7", @e1.to_s(16)) + assert_equal("-03E7", @e2.to_s(16)) + assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e3.to_s(16)) + assert_equal("-07FFFFFFFFFFFFFFFFFFFFFFFFFF", @e4.to_s(16)) + + assert_equal("\x03\xe7", @e1.to_s(2)) + assert_equal("\x03\xe7", @e2.to_s(2)) + assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(2)) + assert_equal("\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(2)) + + assert_equal("\x00\x00\x00\x02\x03\xe7", @e1.to_s(0)) + assert_equal("\x00\x00\x00\x02\x83\xe7", @e2.to_s(0)) + assert_equal("\x00\x00\x00\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e3.to_s(0)) + assert_equal("\x00\x00\x00\x0e\x87\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", @e4.to_s(0)) + end + + def test_to_int + assert_equal(999, @e1.to_i) + assert_equal(-999, @e2.to_i) + assert_equal(2**107-1, @e3.to_i) + assert_equal(-(2**107-1), @e4.to_i) + + assert_equal(999, @e1.to_int) + end + + def test_coerce + assert_equal(["", "-999"], @e2.coerce("")) + assert_equal([1000, -999], @e2.coerce(1000)) + assert_raise(TypeError) { @e2.coerce(Class.new.new) } + end + + def test_zero_p + assert_equal(true, 0.to_bn.zero?) + assert_equal(false, 1.to_bn.zero?) + end + + def test_one_p + assert_equal(true, 1.to_bn.one?) + assert_equal(false, 2.to_bn.one?) + end + + def test_odd_p + assert_equal(true, 1.to_bn.odd?) + assert_equal(false, 2.to_bn.odd?) + end + + def test_negative_p + assert_equal(false, 0.to_bn.negative?) + assert_equal(false, @e1.negative?) + assert_equal(true, @e2.negative?) + end + + def test_sqr + assert_equal(1, 1.to_bn.sqr) + assert_equal(100, 10.to_bn.sqr) + end + + def test_four_ops + assert_equal(3, 1.to_bn + 2) + assert_equal(-1, 1.to_bn + -2) + assert_equal(-1, 1.to_bn - 2) + assert_equal(3, 1.to_bn - -2) + assert_equal(2, 1.to_bn * 2) + assert_equal(-2, 1.to_bn * -2) + assert_equal([0, 1], 1.to_bn / 2) + assert_equal([2, 0], 2.to_bn / 1) + assert_raise(OpenSSL::BNError) { 1.to_bn / 0 } + end + + def test_unary_plus_minus + assert_equal(999, +@e1) + assert_equal(-999, +@e2) + assert_equal(-999, -@e1) + assert_equal(+999, -@e2) + end + + def test_mod + assert_equal(1, 1.to_bn % 2) + assert_equal(0, 2.to_bn % 1) + assert_equal(-2, -2.to_bn % 7) + end + + def test_exp + assert_equal(1, 1.to_bn ** 5) + assert_equal(32, 2.to_bn ** 5) + end + + def test_gcd + assert_equal(1, 7.to_bn.gcd(5)) + assert_equal(8, 24.to_bn.gcd(16)) + end + + def test_mod_sqr + assert_equal(4, 3.to_bn.mod_sqr(5)) + assert_equal(0, 59.to_bn.mod_sqr(59)) + end + + def test_mod_inverse + assert_equal(2, 3.to_bn.mod_inverse(5)) + assert_raise(OpenSSL::BNError) { 3.to_bn.mod_inverse(6) } + end + + def test_mod_add + assert_equal(1, 3.to_bn.mod_add(5, 7)) + assert_equal(2, 3.to_bn.mod_add(5, 3)) + assert_equal(5, 3.to_bn.mod_add(-5, 7)) + end + + def test_mod_sub + assert_equal(1, 11.to_bn.mod_sub(3, 7)) + assert_equal(2, 11.to_bn.mod_sub(3, 3)) + assert_equal(5, 3.to_bn.mod_sub(5, 7)) + end + + def test_mod_mul + assert_equal(1, 2.to_bn.mod_mul(4, 7)) + assert_equal(5, 2.to_bn.mod_mul(-1, 7)) + end + + def test_mod_exp + assert_equal(1, 3.to_bn.mod_exp(2, 8)) + assert_equal(4, 2.to_bn.mod_exp(5, 7)) + end + + def test_bit_operations + e = 0b10010010.to_bn + assert_equal(0b10010011, e.set_bit!(0)) + assert_equal(0b10010011, e.set_bit!(1)) + assert_equal(0b1010010011, e.set_bit!(9)) + + e = 0b10010010.to_bn + assert_equal(0b10010010, e.clear_bit!(0)) + assert_equal(0b10010000, e.clear_bit!(1)) + + e = 0b10010010.to_bn + assert_equal(0b10010010, e.mask_bits!(8)) + assert_equal(0b10, e.mask_bits!(3)) + + e = 0b10010010.to_bn + assert_equal(false, e.bit_set?(0)) + assert_equal(true, e.bit_set?(1)) + assert_equal(false, e.bit_set?(1000)) + + e = 0b10010010.to_bn + assert_equal(0b1001001000, e << 2) + assert_equal(0b10010010, e) + assert_equal(0b1001001000, e.lshift!(2)) + assert_equal(0b1001001000, e) + + e = 0b10010010.to_bn + assert_equal(0b100100, e >> 2) + assert_equal(0b10010010, e) + assert_equal(0b100100, e.rshift!(2)) + assert_equal(0b100100, e) + end + + def test_random + 10.times { + r1 = OpenSSL::BN.rand(8) + assert_include(128..255, r1) + r2 = OpenSSL::BN.rand(8, -1) + assert_include(0..255, r2) + r3 = OpenSSL::BN.rand(8, 1) + assert_include(192..255, r3) + r4 = OpenSSL::BN.rand(8, 1, true) + assert_include(192..255, r4) + assert_equal(true, r4.odd?) + + r5 = OpenSSL::BN.rand_range(256) + assert_include(0..255, r5) + } + end + + def test_prime + p1 = OpenSSL::BN.generate_prime(32) + assert_include(0...2**32, p1) + assert_equal(true, Prime.prime?(p1.to_i)) + p2 = OpenSSL::BN.generate_prime(32, true) + assert_equal(true, Prime.prime?((p2.to_i - 1) / 2)) + p3 = OpenSSL::BN.generate_prime(32, false, 4) + assert_equal(1, p3 % 4) + p4 = OpenSSL::BN.generate_prime(32, false, 4, 3) + assert_equal(3, p4 % 4) + + assert_equal(true, p1.prime?) + assert_equal(true, p2.prime?) + assert_equal(true, p3.prime?) + assert_equal(true, p4.prime?) + assert_equal(true, @e3.prime?) + assert_equal(true, @e3.prime_fasttest?) + end + + def test_num_bits_bytes + assert_equal(10, @e1.num_bits) + assert_equal(2, @e1.num_bytes) + assert_equal(107, @e3.num_bits) + assert_equal(14, @e3.num_bytes) + assert_equal(0, 0.to_bn.num_bits) + assert_equal(0, 0.to_bn.num_bytes) + assert_equal(9, -256.to_bn.num_bits) + assert_equal(2, -256.to_bn.num_bytes) + end + + def test_comparison + assert_equal(false, @e1 == nil) + assert_equal(false, @e1 == -999) + assert_equal(true, @e1 == 999) + assert_equal(true, @e1 == 999.to_bn) + assert_equal(false, @e1.eql?(nil)) + assert_equal(false, @e1.eql?(999)) + assert_equal(true, @e1.eql?(999.to_bn)) + assert_equal(@e1.hash, 999.to_bn.hash) + assert_not_equal(@e1.hash, @e3.hash) + assert_equal(0, @e1.cmp(999)) + assert_equal(1, @e1.cmp(-999)) + assert_equal(0, @e1.ucmp(999)) + assert_equal(0, @e1.ucmp(-999)) + assert_instance_of(String, @e1.hash.to_s) end end diff --git a/test/test_buffering.rb b/test/test_buffering.rb index 08735add..c85a6f02 100644 --- a/test/test_buffering.rb +++ b/test/test_buffering.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestBuffering < OpenSSL::TestCase class IO diff --git a/test/test_cipher.rb b/test/test_cipher.rb index 732b4fdd..d83fa4ec 100644 --- a/test/test_cipher.rb +++ b/test/test_cipher.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestCipher < OpenSSL::TestCase module Helper @@ -132,7 +132,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase 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') + end def test_ciphers OpenSSL::Cipher.ciphers.each{|name| @@ -168,10 +168,8 @@ class OpenSSL::TestCipher < OpenSSL::TestCase end def test_authenticated - if has_cipher?('aes-128-gcm') - cipher = OpenSSL::Cipher.new('aes-128-gcm') - assert_predicate(cipher, :authenticated?) - end + cipher = OpenSSL::Cipher.new('aes-128-gcm') + assert_predicate(cipher, :authenticated?) cipher = OpenSSL::Cipher.new('aes-128-cbc') assert_not_predicate(cipher, :authenticated?) end @@ -223,7 +221,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase cipher = new_decryptor("aes-128-gcm", key: key, iv: iv, auth_tag: tag, auth_data: aad) cipher.update(ct2) assert_raise(OpenSSL::Cipher::CipherError) { cipher.final } - end if has_cipher?("aes-128-gcm") + end def test_aes_gcm_variable_iv_len # GCM spec Appendix B Test Case 5 @@ -246,7 +244,7 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal tag, cipher.auth_tag cipher = new_decryptor("aes-128-gcm", key: key, iv_len: 8, iv: iv, auth_tag: tag, auth_data: aad) assert_equal pt, cipher.update(ct) << cipher.final - end if has_cipher?("aes-128-gcm") + end def test_aes_ocb_tag_len # RFC 7253 Appendix A; the second sample @@ -298,14 +296,14 @@ class OpenSSL::TestCipher < OpenSSL::TestCase assert_equal ct1, ct2 assert_equal tag1, tag2 - end if has_cipher?("aes-128-gcm") + end def test_non_aead_cipher_set_auth_data assert_raise(OpenSSL::Cipher::CipherError) { cipher = OpenSSL::Cipher.new("aes-128-cfb").encrypt cipher.auth_data = "123" } - end if has_cipher?("aes-128-gcm") + end private @@ -322,7 +320,6 @@ class OpenSSL::TestCipher < OpenSSL::TestCase kwargs.each {|k, v| cipher.send(:"#{k}=", v) } end end - end end diff --git a/test/test_config.rb b/test/test_config.rb index 99dcc497..8096375c 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestConfig < OpenSSL::TestCase def setup diff --git a/test/test_digest.rb b/test/test_digest.rb index c8817395..2cb878b6 100644 --- a/test/test_digest.rb +++ b/test/test_digest.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestDigest < OpenSSL::TestCase def setup diff --git a/test/test_engine.rb b/test/test_engine.rb index 801d1c8e..bb1123d5 100644 --- a/test/test_engine.rb +++ b/test/test_engine.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) && defined?(OpenSSL::Engine) +if defined?(OpenSSL) && defined?(OpenSSL::Engine) class OpenSSL::TestEngine < OpenSSL::TestCase def test_engines_free # [ruby-dev:44173] diff --git a/test/test_fips.rb b/test/test_fips.rb index 534dade0..a577d789 100644 --- a/test/test_fips.rb +++ b/test/test_fips.rb @@ -1,15 +1,30 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestFIPS < OpenSSL::TestCase - def test_fips_mode_is_reentrant OpenSSL.fips_mode = false OpenSSL.fips_mode = false end + def test_fips_mode_get + return unless OpenSSL::OPENSSL_FIPS + assert_separately([{ "OSSL_MDEBUG" => nil }, "-ropenssl"], <<~"end;") + require #{__FILE__.dump} + + begin + OpenSSL.fips_mode = true + assert OpenSSL.fips_mode == true, ".fips_mode returns true when .fips_mode=true" + + OpenSSL.fips_mode = false + assert OpenSSL.fips_mode == false, ".fips_mode returns false when .fips_mode=false" + rescue OpenSSL::OpenSSLError + pend "Could not set FIPS mode (OpenSSL::OpenSSLError: \#$!); skipping" + end + end; + end end end diff --git a/test/test_hmac.rb b/test/test_hmac.rb index 4d06e476..831a5b6b 100644 --- a/test/test_hmac.rb +++ b/test/test_hmac.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestHMAC < OpenSSL::TestCase def test_hmac diff --git a/test/test_kdf.rb b/test/test_kdf.rb new file mode 100644 index 00000000..5e1db80c --- /dev/null +++ b/test/test_kdf.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: false +require_relative 'utils' + +if defined?(OpenSSL) + +class OpenSSL::TestKDF < OpenSSL::TestCase + def test_pkcs5_pbkdf2_hmac_compatibility + expected = OpenSSL::KDF.pbkdf2_hmac("password", salt: "salt", iterations: 1, length: 20, hash: "sha1") + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac("password", "salt", 1, 20, "sha1")) + assert_equal(expected, OpenSSL::PKCS5.pbkdf2_hmac_sha1("password", "salt", 1, 20)) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 + p ="password" + s = "salt" + c = 1 + dk_len = 20 + raw = %w{ 0c 60 c8 0f 96 1f 0e 71 + f3 a9 b5 24 af 60 12 06 + 2f e0 37 a6 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 + p ="password" + s = "salt" + c = 2 + dk_len = 20 + raw = %w{ ea 6c 01 4d c7 2d 6f 8c + cd 1e d9 2a ce 1d 41 f0 + d8 de 89 57 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 + p ="password" + s = "salt" + c = 4096 + dk_len = 20 + raw = %w{ 4b 00 79 01 b7 65 48 9a + be ad 49 d9 26 f7 21 d0 + 65 a4 29 c1 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + +# takes too long! +# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20 +# p ="password" +# s = "salt" +# c = 16777216 +# dk_len = 20 +# raw = %w{ ee fe 3d 61 cd 4d a4 e4 +# e9 94 5b 3d 6b a2 15 8c +# 26 34 e9 84 } +# expected = [raw.join('')].pack('H*') +# value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") +# assert_equal(expected, value) +# end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 + p ="passwordPASSWORDpassword" + s = "saltSALTsaltSALTsaltSALTsaltSALTsalt" + c = 4096 + dk_len = 25 + + raw = %w{ 3d 2e ec 4f e4 1c 84 9b + 80 c8 d8 36 62 c0 e4 4a + 8b 29 1a 96 4c f2 f0 70 + 38 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 + p ="pass\0word" + s = "sa\0lt" + c = 4096 + dk_len = 16 + raw = %w{ 56 fa 6a a7 55 48 09 9d + cc 37 d7 f0 34 25 e0 c3 } + expected = [raw.join('')].pack('H*') + value = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha1") + assert_equal(expected, value) + end + + def test_pbkdf2_hmac_sha256_c_20000_len_32 + #unfortunately no official test vectors available yet for SHA-2 + p ="password" + s = OpenSSL::Random.random_bytes(16) + c = 20000 + dk_len = 32 + value1 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") + value2 = OpenSSL::KDF.pbkdf2_hmac(p, salt: s, iterations: c, length: dk_len, hash: "sha256") + assert_equal(value1, value2) + end + + def test_scrypt_rfc7914_first + pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + pass = "" + salt = "" + n = 16 + r = 1 + p = 1 + dklen = 64 + expected = B(%w{ 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 + f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 + fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 + e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 }) + assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) + end + + def test_scrypt_rfc7914_second + pend "scrypt is not implemented" unless OpenSSL::KDF.respond_to?(:scrypt) # OpenSSL >= 1.1.0 + pass = "password" + salt = "NaCl" + n = 1024 + r = 8 + p = 16 + dklen = 64 + expected = B(%w{ fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe + 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 + 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da + c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 }) + assert_equal(expected, OpenSSL::KDF.scrypt(pass, salt: salt, N: n, r: r, p: p, length: dklen)) + end + + def test_hkdf_rfc5869_test_case_1 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha256" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + salt = B("000102030405060708090a0b0c") + info = B("f0f1f2f3f4f5f6f7f8f9") + l = 42 + + okm = B("3cb25f25faacd57a90434f64d0362f2a" \ + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" \ + "34007208d5b887185865") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + def test_hkdf_rfc5869_test_case_3 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha256" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") + salt = B("") + info = B("") + l = 42 + + okm = B("8da4e775a563c18f715f802a063c5a31" \ + "b8a11f5c5ee1879ec3454e5f3c738d2d" \ + "9d201395faa4b61a96c8") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + def test_hkdf_rfc5869_test_case_4 + pend "HKDF is not implemented" unless OpenSSL::KDF.respond_to?(:hkdf) # OpenSSL >= 1.1.0 + hash = "sha1" + ikm = B("0b0b0b0b0b0b0b0b0b0b0b") + salt = B("000102030405060708090a0b0c") + info = B("f0f1f2f3f4f5f6f7f8f9") + l = 42 + + okm = B("085a01ea1b10f36933068b56efa5ad81" \ + "a4f14b822f5b091568a9cdd4f155fda2" \ + "c22e422478d305f3f896") + assert_equal(okm, OpenSSL::KDF.hkdf(ikm, salt: salt, info: info, length: l, hash: hash)) + end + + private + + def B(ary) + [Array(ary).join].pack("H*") + end +end + +end diff --git a/test/test_ns_spki.rb b/test/test_ns_spki.rb index 58e0f649..aa1e6182 100644 --- a/test/test_ns_spki.rb +++ b/test/test_ns_spki.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestNSSPI < OpenSSL::TestCase def setup diff --git a/test/test_ocsp.rb b/test/test_ocsp.rb index 0440634a..50ad6c31 100644 --- a/test/test_ocsp.rb +++ b/test/test_ocsp.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestOCSP < OpenSSL::TestCase def setup @@ -122,14 +122,29 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal true, req.verify([@cert], store, OpenSSL::OCSP::NOINTERN) ret = req.verify([@cert], store) - if ret || openssl?(1, 0, 2) || libressl?(2, 4, 2) + if ret || openssl?(1, 0, 2) assert_equal true, ret else # RT2560; OCSP_request_verify() does not find signer cert from 'certs' when # OCSP_NOINTERN is not specified. - # fixed by OpenSSL 1.0.1j, 1.0.2 and LibreSSL 2.4.2 + # fixed by OpenSSL 1.0.1j, 1.0.2 pend "RT2560: ocsp_req_find_signer" end + + # not signed + req = OpenSSL::OCSP::Request.new.add_certid(cid) + assert_equal false, req.verify([], store) + end + + def test_request_is_signed + cid = OpenSSL::OCSP::CertificateId.new(@cert, @ca_cert) + req = OpenSSL::OCSP::Request.new + req.add_certid(cid) + assert_equal false, req.signed? + assert_equal false, OpenSSL::OCSP::Request.new(req.to_der).signed? + req.sign(@cert, @cert_key, []) + assert_equal true, req.signed? + assert_equal true, OpenSSL::OCSP::Request.new(req.to_der).signed? end def test_request_nonce @@ -247,11 +262,6 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_REVOKED, OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED, -400, -300, nil, []) bres.add_status(cid2, OpenSSL::OCSP::V_CERTSTATUS_GOOD, nil, nil, Time.now + 100, nil, nil) - if bres.responses[2].check_validity # thisUpdate is in future; must fail - # LibreSSL bug; skip for now - pend "OCSP_check_validity() is broken" - end - single1 = bres.responses[0] assert_equal false, single1.check_validity assert_equal false, single1.check_validity(30) @@ -260,6 +270,8 @@ class OpenSSL::TestOCSP < OpenSSL::TestCase assert_equal true, single2.check_validity assert_equal true, single2.check_validity(0, 500) assert_equal false, single2.check_validity(0, 200) + single3 = bres.responses[2] + assert_equal false, single3.check_validity end def test_response diff --git a/test/test_pair.rb b/test/test_pair.rb index ea5f0dcf..29d5c9bb 100644 --- a/test/test_pair.rb +++ b/test/test_pair.rb @@ -2,7 +2,7 @@ require_relative 'utils' require_relative 'ut_eof' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) module OpenSSL::SSLPairM def setup @@ -362,6 +362,15 @@ module OpenSSL::TestPairM } end + def test_write_multiple_arguments + ssl_pair {|s1, s2| + str1 = "foo"; str2 = "bar" + assert_equal 6, s1.write(str1, str2) + s1.close + assert_equal "foobar", s2.read + } + end + def test_partial_tls_record_read_nonblock ssl_pair { |s1, s2| # the beginning of a TLS record diff --git a/test/test_pkcs12.rb b/test/test_pkcs12.rb index 30888234..de8e35ed 100644 --- a/test/test_pkcs12.rb +++ b/test/test_pkcs12.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) module OpenSSL class TestPKCS12 < OpenSSL::TestCase @@ -307,7 +307,6 @@ Kw4DAhoFAAQUYAuwVtGD1TdgbFK4Yal2XBgwUR4ECEawsN3rNaa6AgIIAA== end false end - end end diff --git a/test/test_pkcs5.rb b/test/test_pkcs5.rb deleted file mode 100644 index 0919b9ce..00000000 --- a/test/test_pkcs5.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: false -require_relative 'utils' - -if defined?(OpenSSL::TestUtils) - -class OpenSSL::TestPKCS5 < OpenSSL::TestCase - def test_pbkdf2_hmac_sha1_rfc6070_c_1_len_20 - p ="password" - s = "salt" - c = 1 - dk_len = 20 - raw = %w{ 0c 60 c8 0f 96 1f 0e 71 - f3 a9 b5 24 af 60 12 06 - 2f e0 37 a6 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_2_len_20 - p ="password" - s = "salt" - c = 2 - dk_len = 20 - raw = %w{ ea 6c 01 4d c7 2d 6f 8c - cd 1e d9 2a ce 1d 41 f0 - d8 de 89 57 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_20 - p ="password" - s = "salt" - c = 4096 - dk_len = 20 - raw = %w{ 4b 00 79 01 b7 65 48 9a - be ad 49 d9 26 f7 21 d0 - 65 a4 29 c1 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - -# takes too long! -# def test_pbkdf2_hmac_sha1_rfc6070_c_16777216_len_20 -# p ="password" -# s = "salt" -# c = 16777216 -# dk_len = 20 -# raw = %w{ ee fe 3d 61 cd 4d a4 e4 -# e9 94 5b 3d 6b a2 15 8c -# 26 34 e9 84 } -# expected = [raw.join('')].pack('H*') -# value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) -# assert_equal(expected, value) -# end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_25 - p ="passwordPASSWORDpassword" - s = "saltSALTsaltSALTsaltSALTsaltSALTsalt" - c = 4096 - dk_len = 25 - - raw = %w{ 3d 2e ec 4f e4 1c 84 9b - 80 c8 d8 36 62 c0 e4 4a - 8b 29 1a 96 4c f2 f0 70 - 38 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha1_rfc6070_c_4096_len_16 - p ="pass\0word" - s = "sa\0lt" - c = 4096 - dk_len = 16 - raw = %w{ 56 fa 6a a7 55 48 09 9d - cc 37 d7 f0 34 25 e0 c3 } - expected = [raw.join('')].pack('H*') - value = OpenSSL::PKCS5.pbkdf2_hmac_sha1(p, s, c, dk_len) - assert_equal(expected, value) - end - - def test_pbkdf2_hmac_sha256_c_20000_len_32 - #unfortunately no official test vectors available yet for SHA-2 - p ="password" - s = OpenSSL::Random.random_bytes(16) - c = 20000 - dk_len = 32 - digest = OpenSSL::Digest::SHA256.new - value1 = OpenSSL::PKCS5.pbkdf2_hmac(p, s, c, dk_len, digest) - value2 = OpenSSL::PKCS5.pbkdf2_hmac(p, s, c, dk_len, digest) - assert_equal(value1, value2) - end if OpenSSL::PKCS5.respond_to?(:pbkdf2_hmac) -end - -end diff --git a/test/test_pkcs7.rb b/test/test_pkcs7.rb index 026fe847..149d3b9b 100644 --- a/test/test_pkcs7.rb +++ b/test/test_pkcs7.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestPKCS7 < OpenSSL::TestCase def setup diff --git a/test/test_pkey_dh.rb b/test/test_pkey_dh.rb index fb713813..77cdb0ab 100644 --- a/test/test_pkey_dh.rb +++ b/test/test_pkey_dh.rb @@ -1,27 +1,11 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) && defined?(OpenSSL::PKey::DH) class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase NEW_KEYLEN = 256 - def test_DEFAULT_parameters - list = { - 1024 => OpenSSL::PKey::DH::DEFAULT_1024, - 2048 => OpenSSL::PKey::DH::DEFAULT_2048, - } - - list.each do |expected_size, dh| - assert_equal expected_size, dh.p.num_bits - assert_predicate dh.p, :prime? - result, remainder = (dh.p - 1) / 2 - assert_predicate result, :prime? - assert_equal 0, remainder - assert_no_key dh - end - end - def test_new dh = OpenSSL::PKey::DH.new(NEW_KEYLEN) assert_key(dh) diff --git a/test/test_pkey_dsa.rb b/test/test_pkey_dsa.rb index 474f2388..d6519498 100644 --- a/test/test_pkey_dsa.rb +++ b/test/test_pkey_dsa.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) && defined?(OpenSSL::PKey::DSA) class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase def test_private @@ -41,7 +41,6 @@ class OpenSSL::TestPKeyDSA < OpenSSL::PKeyTestCase assert_equal true, dsa512.verify(OpenSSL::Digest::DSS1.new, signature, data) end - return unless openssl?(1, 0, 0) signature = dsa512.sign("SHA1", data) assert_equal true, dsa512.verify("SHA1", signature, data) diff --git a/test/test_pkey_ec.rb b/test/test_pkey_ec.rb index 8119b77c..dc5a14e6 100644 --- a/test/test_pkey_ec.rb +++ b/test/test_pkey_ec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) && defined?(OpenSSL::PKey::EC) +if defined?(OpenSSL) && defined?(OpenSSL::PKey::EC) class OpenSSL::TestEC < OpenSSL::PKeyTestCase def test_ec_key @@ -99,16 +99,9 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase key = OpenSSL::PKey::EC.new("prime256v1").generate_key! size = key.group.order.num_bits / 8 + 1 dgst = (1..size).to_a.pack('C*') - begin - sig = key.dsa_sign_asn1(dgst) - # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m - assert(key.dsa_verify_asn1(dgst + "garbage", sig)) - rescue OpenSSL::PKey::ECError => e - # just an exception for longer dgst before openssl-0.9.8m - assert_equal('ECDSA_sign: data too large for key size', e.message) - # no need to do following tests - return - end + sig = key.dsa_sign_asn1(dgst) + # dgst is auto-truncated according to FIPS186-3 after openssl-0.9.8m + assert(key.dsa_verify_asn1(dgst + "garbage", sig)) end def test_dh_compute_key @@ -127,14 +120,9 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase asn1 = OpenSSL::ASN1::Sequence([ OpenSSL::ASN1::Integer(1), OpenSSL::ASN1::OctetString(p256.private_key.to_s(2)), - OpenSSL::ASN1::ASN1Data.new( - [OpenSSL::ASN1::ObjectId("prime256v1")], - 0, :CONTEXT_SPECIFIC - ), - OpenSSL::ASN1::ASN1Data.new( - [OpenSSL::ASN1::BitString(p256.public_key.to_bn.to_s(2))], - 1, :CONTEXT_SPECIFIC - ) + OpenSSL::ASN1::ObjectId("prime256v1", 0, :EXPLICIT), + OpenSSL::ASN1::BitString(p256.public_key.to_octet_string(:uncompressed), + 1, :EXPLICIT) ]) key = OpenSSL::PKey::EC.new(asn1.to_der) assert_predicate key, :private? @@ -188,7 +176,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase OpenSSL::ASN1::ObjectId("prime256v1") ]), OpenSSL::ASN1::BitString( - p256.public_key.to_bn.to_s(2) + p256.public_key.to_octet_string(:uncompressed) ) ]) key = OpenSSL::PKey::EC.new(asn1.to_der) @@ -231,7 +219,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase assert_equal :uncompressed, group4.point_conversion_form assert_equal group1, group4 assert_equal group1.curve_name, group4.curve_name - assert_equal group1.generator.to_bn, group4.generator.to_bn + assert_equal group1.generator.to_octet_string(:uncompressed), + group4.generator.to_octet_string(:uncompressed) assert_equal group1.order, group4.order assert_equal group1.cofactor, group4.cofactor assert_equal group1.seed, group4.seed @@ -246,34 +235,57 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase point2 = OpenSSL::PKey::EC::Point.new(group, point.to_bn) assert_equal point, point2 assert_equal point.to_bn, point2.to_bn + assert_equal point.to_octet_string(:uncompressed), + point2.to_octet_string(:uncompressed) + + point3 = OpenSSL::PKey::EC::Point.new(group, + point.to_octet_string(:uncompressed)) + assert_equal point, point3 + assert_equal point.to_bn, point3.to_bn + assert_equal point.to_octet_string(:uncompressed), + point3.to_octet_string(:uncompressed) + point2.invert! - assert_not_equal point.to_bn, point2.to_bn + point3.invert! + assert_not_equal point.to_octet_string(:uncompressed), + point2.to_octet_string(:uncompressed) + assert_equal point2.to_octet_string(:uncompressed), + point3.to_octet_string(:uncompressed) begin group = OpenSSL::PKey::EC::Group.new(:GFp, 17, 2, 2) group.point_conversion_form = :uncompressed - generator = OpenSSL::PKey::EC::Point.new(group, 0x040501.to_bn) + generator = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 05 01 })) group.set_generator(generator, 19, 1) - point = OpenSSL::PKey::EC::Point.new(group, 0x040603.to_bn) + point = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 })) rescue OpenSSL::PKey::EC::Group::Error pend "Patched OpenSSL rejected curve" if /unsupported field/ =~ $!.message raise end + assert_equal 0x040603.to_bn, point.to_bn 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 + group2 = group.dup; group2.point_conversion_form = :compressed + point2 = OpenSSL::PKey::EC::Point.new(group2, B(%w{ 04 06 03 })) + assert_equal 0x0306.to_bn, point2.to_bn + + assert_equal B(%w{ 04 06 03 }), point.to_octet_string(:uncompressed) + assert_equal B(%w{ 03 06 }), point.to_octet_string(:compressed) + assert_equal B(%w{ 07 06 03 }), point.to_octet_string(:hybrid) + assert_equal true, point.on_curve? point.invert! # 8.5 - assert_equal 0x04060E.to_bn, point.to_bn + assert_equal B(%w{ 04 06 0E }), point.to_octet_string(:uncompressed) assert_equal true, point.on_curve? assert_equal false, point.infinity? point.set_to_infinity! assert_equal true, point.infinity? assert_equal 0.to_bn, point.to_bn + assert_equal B(%w{ 00 }), point.to_octet_string(:uncompressed) assert_equal true, point.on_curve? end @@ -283,25 +295,25 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase # generator is (5, 1) group = OpenSSL::PKey::EC::Group.new(:GFp, 17, 2, 2) group.point_conversion_form = :uncompressed - gen = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new("040501", 16)) + gen = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 05 01 })) group.set_generator(gen, 19, 1) # 3 * (6, 3) = (16, 13) - point_a = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new("040603", 16)) + point_a = OpenSSL::PKey::EC::Point.new(group, B(%w{ 04 06 03 })) result_a1 = point_a.mul(3) - assert_equal("04100D", result_a1.to_bn.to_s(16)) + assert_equal B(%w{ 04 10 0D }), result_a1.to_octet_string(:uncompressed) # 3 * (6, 3) + 3 * (5, 1) = (7, 6) result_a2 = point_a.mul(3, 3) - assert_equal("040706", result_a2.to_bn.to_s(16)) + assert_equal B(%w{ 04 07 06 }), result_a2.to_octet_string(:uncompressed) # 3 * point_a = 3 * (6, 3) = (16, 13) result_b1 = point_a.mul([3], []) - assert_equal("04100D", result_b1.to_bn.to_s(16)) + assert_equal B(%w{ 04 10 0D }), result_b1.to_octet_string(:uncompressed) # 3 * point_a + 2 * point_a = 3 * (6, 3) + 2 * (6, 3) = (7, 11) result_b1 = point_a.mul([3, 2], [point_a]) - assert_equal("04070B", result_b1.to_bn.to_s(16)) + assert_equal B(%w{ 04 07 0B }), result_b1.to_octet_string(:uncompressed) # 3 * point_a + 5 * point_a.group.generator = 3 * (6, 3) + 5 * (5, 1) = (13, 10) result_b1 = point_a.mul([3], [], 5) - assert_equal("040D0A", result_b1.to_bn.to_s(16)) + assert_equal B(%w{ 04 0D 0A }), result_b1.to_octet_string(:uncompressed) rescue OpenSSL::PKey::EC::Group::Error # CentOS patches OpenSSL to reject curves defined over Fp where p < 256 bits raise if $!.message !~ /unsupported field/ @@ -323,6 +335,10 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase private + def B(ary) + [Array(ary).join].pack("H*") + end + def assert_same_ec(expected, key) check_component(expected, key, [:group, :public_key, :private_key]) end diff --git a/test/test_pkey_rsa.rb b/test/test_pkey_rsa.rb index b4393e68..ef02717d 100644 --- a/test/test_pkey_rsa.rb +++ b/test/test_pkey_rsa.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase def test_padding @@ -120,6 +120,39 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase } end + def test_sign_verify_pss + key = Fixtures.pkey("rsa1024") + data = "Sign me!" + invalid_data = "Sign me?" + + signature = key.sign_pss("SHA256", data, salt_length: 20, mgf1_hash: "SHA1") + assert_equal 128, signature.bytesize + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1") + assert_equal false, + key.verify_pss("SHA256", signature, invalid_data, salt_length: 20, mgf1_hash: "SHA1") + + signature = key.sign_pss("SHA256", data, salt_length: :digest, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: 32, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1") + assert_equal false, + key.verify_pss("SHA256", signature, data, salt_length: 20, mgf1_hash: "SHA1") + + signature = key.sign_pss("SHA256", data, salt_length: :max, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: 94, mgf1_hash: "SHA1") + assert_equal true, + key.verify_pss("SHA256", signature, data, salt_length: :auto, mgf1_hash: "SHA1") + + assert_raise(OpenSSL::PKey::RSAError) { + key.sign_pss("SHA256", data, salt_length: 95, mgf1_hash: "SHA1") + } + end + def test_RSAPrivateKey rsa1024 = Fixtures.pkey("rsa1024") asn1 = OpenSSL::ASN1::Sequence([ diff --git a/test/test_random.rb b/test/test_random.rb index c0160f9a..d5a37454 100644 --- a/test/test_random.rb +++ b/test/test_random.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestRandom < OpenSSL::TestCase def test_random_bytes diff --git a/test/test_ssl.rb b/test/test_ssl.rb index 408c7d82..060c1f1c 100644 --- a/test/test_ssl.rb +++ b/test/test_ssl.rb @@ -1,10 +1,9 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestSSL < OpenSSL::SSLTestCase - def test_ctx_options ctx = OpenSSL::SSL::SSLContext.new @@ -57,6 +56,89 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end + def test_add_certificate + ctx_proc = -> ctx { + # Unset values set by start_server + ctx.cert = ctx.key = ctx.extra_chain_cert = nil + ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA + } + start_server(ctx_proc: ctx_proc) do |port| + server_connect(port) { |ssl| + assert_equal @svr_cert.subject, ssl.peer_cert.subject + assert_equal [@svr_cert.subject, @ca_cert.subject], + ssl.peer_cert_chain.map(&:subject) + + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + end + end + + def test_add_certificate_multiple_certs + pend "EC is not supported" unless defined?(OpenSSL::PKey::EC) + pend "TLS 1.2 is not supported" unless tls12_supported? + + # SSL_CTX_set0_chain() is needed for setting multiple certificate chains + add0_chain_supported = openssl?(1, 0, 2) + + if add0_chain_supported + ca2_key = Fixtures.pkey("rsa1024") + ca2_exts = [ + ["basicConstraints", "CA:TRUE", true], + ["keyUsage", "cRLSign, keyCertSign", true], + ] + ca2_dn = OpenSSL::X509::Name.parse_rfc2253("CN=CA2") + ca2_cert = issue_cert(ca2_dn, ca2_key, 123, ca2_exts, nil, nil) + else + # Use the same CA as @svr_cert + ca2_key = @ca_key; ca2_cert = @ca_cert + end + + ecdsa_key = Fixtures.pkey("p256") + exts = [ + ["keyUsage", "digitalSignature", false], + ] + ecdsa_dn = OpenSSL::X509::Name.parse_rfc2253("CN=localhost2") + ecdsa_cert = issue_cert(ecdsa_dn, ecdsa_key, 456, exts, ca2_cert, ca2_key) + + if !add0_chain_supported + # Testing the warning emitted when 'extra' chain is replaced + tctx = OpenSSL::SSL::SSLContext.new + tctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) + assert_warning(/set0_chain/) { + tctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) + } + end + + ctx_proc = -> ctx { + # Unset values set by start_server + ctx.cert = ctx.key = ctx.extra_chain_cert = nil + ctx.ecdh_curves = "P-256" unless openssl?(1, 0, 2) + ctx.add_certificate(@svr_cert, @svr_key, [@ca_cert]) # RSA + EnvUtil.suppress_warning do # !add0_chain_supported + ctx.add_certificate(ecdsa_cert, ecdsa_key, [ca2_cert]) + end + } + start_server(ctx_proc: ctx_proc) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = :TLS1_2 # TODO: We need this to force certificate type + ctx.ciphers = "aECDSA" + server_connect(port, ctx) { |ssl| + assert_equal ecdsa_cert.subject, ssl.peer_cert.subject + assert_equal [ecdsa_cert.subject, ca2_cert.subject], + ssl.peer_cert_chain.map(&:subject) + } + + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = :TLS1_2 + ctx.ciphers = "aRSA" + server_connect(port, ctx) { |ssl| + assert_equal @svr_cert.subject, ssl.peer_cert.subject + assert_equal [@svr_cert.subject, @ca_cert.subject], + ssl.peer_cert_chain.map(&:subject) + } + end + end + def test_sysread_and_syswrite start_server { |port| server_connect(port) { |ssl| @@ -346,10 +428,8 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase assert ciphers_names.all?{|v| /A(EC)?DH/ !~ v }, "anon ciphers are disabled" assert ciphers_names.all?{|v| /(RC4|MD5|EXP|DES(?!-EDE|-CBC3))/ !~ v }, "weak ciphers are disabled" assert_equal 0, ctx.options & OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS - if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) # >= 1.0.0 - assert_equal OpenSSL::SSL::OP_NO_COMPRESSION, - ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION - end + assert_equal OpenSSL::SSL::OP_NO_COMPRESSION, + ctx.options & OpenSSL::SSL::OP_NO_COMPRESSION end def test_post_connect_check_with_anon_ciphers @@ -752,6 +832,30 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end + def test_connect_certificate_verify_failed_exception_message + start_server(ignore_listener_error: true) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params + assert_raise_with_message(OpenSSL::SSL::SSLError, /self signed/) { + server_connect(port, ctx) + } + } + + ctx_proc = proc { |ctx| + ctx.cert = issue_cert(@svr, @svr_key, 30, [], @ca_cert, @ca_key, + not_before: Time.now-100, not_after: Time.now-10) + } + start_server(ignore_listener_error: true, ctx_proc: ctx_proc) { |port| + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params(cert_store: store) + assert_raise_with_message(OpenSSL::SSL::SSLError, /expired/) { + server_connect(port, ctx) + } + } + end + def test_unset_OP_ALL ctx_proc = Proc.new { |ctx| # If OP_DONT_INSERT_EMPTY_FRAGMENTS is not defined, this test is @@ -767,100 +871,237 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase } end -if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) && OpenSSL::SSL::SSLContext::METHODS.include?(:SSLv3) + def check_supported_protocol_versions + possible_versions = [ + OpenSSL::SSL::SSL3_VERSION, + OpenSSL::SSL::TLS1_VERSION, + OpenSSL::SSL::TLS1_1_VERSION, + OpenSSL::SSL::TLS1_2_VERSION, + # OpenSSL 1.1.1 + defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION, + ].compact + + # Prepare for testing & do sanity check + supported = [] + possible_versions.each do |ver| + catch(:unsupported) { + ctx_proc = proc { |ctx| + begin + ctx.min_version = ctx.max_version = ver + rescue ArgumentError, OpenSSL::SSL::SSLError + throw :unsupported + end + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) do |port| + begin + server_connect(port) { |ssl| + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + rescue OpenSSL::SSL::SSLError, Errno::ECONNRESET + else + supported << ver + end + end + } + end + assert_not_empty supported - def test_forbid_ssl_v3_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3 } - start_server_version(:SSLv23, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :SSLv3 - assert_handshake_error { server_connect(port, ctx) } - } + supported end - def test_forbid_ssl_v3_from_server - start_server_version(:SSLv3) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv3 - assert_handshake_error { server_connect(port, ctx) } - } + def test_set_params_min_version + supported = check_supported_protocol_versions + store = OpenSSL::X509::Store.new + store.add_cert(@ca_cert) + + if supported.include?(OpenSSL::SSL::SSL3_VERSION) + # SSLContext#set_params properly disables SSL 3.0 by default + ctx_proc = proc { |ctx| + ctx.min_version = ctx.max_version = OpenSSL::SSL::SSL3_VERSION + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.set_params(cert_store: store, verify_hostname: false) + assert_handshake_error { server_connect(port, ctx) { } } + } + end end -end + def test_minmax_version + supported = check_supported_protocol_versions + + # name: The string that would be returned by SSL_get_version() + # method: The version-specific method name (if any) + vmap = { + OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, + OpenSSL::SSL::SSL3_VERSION => { name: "SSLv3", method: "SSLv3" }, + OpenSSL::SSL::TLS1_VERSION => { name: "TLSv1", method: "TLSv1" }, + OpenSSL::SSL::TLS1_1_VERSION => { name: "TLSv1.1", method: "TLSv1_1" }, + OpenSSL::SSL::TLS1_2_VERSION => { name: "TLSv1.2", method: "TLSv1_2" }, + # OpenSSL 1.1.1 + defined?(OpenSSL::SSL::TLS1_3_VERSION) && OpenSSL::SSL::TLS1_3_VERSION => + { name: "TLSv1.3", method: nil }, + } -if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1) + # Server enables a single version + supported.each do |ver| + ctx_proc = proc { |ctx| ctx.min_version = ctx.max_version = ver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client enables a single version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = cver + if ver == cver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx1) { } } + end - def test_tls_v1_1 - start_server_version(:TLSv1_1) { |port| - ctx = OpenSSL::SSL::SSLContext.new(:TLSv1_1) - server_connect(port, ctx) { |ssl| assert_equal("TLSv1.1", ssl.ssl_version) } - } - end + # There is no version-specific SSL methods for TLS 1.3 + if cver <= OpenSSL::SSL::TLS1_2_VERSION + # Client enables a single version using #ssl_version= + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.ssl_version = vmap[cver][:method] + if ver == cver + server_connect(port, ctx2) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx2) { } } + end + end + end - def test_forbid_tls_v1_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1 } - start_server_version(:SSLv23, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1 - assert_handshake_error { server_connect(port, ctx) } - } - end + # Client enables all supported versions + ctx3 = OpenSSL::SSL::SSLContext.new + ctx3.min_version = ctx3.max_version = nil + server_connect(port, ctx3) { |ssl| + assert_equal vmap[ver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + } + end - def test_forbid_tls_v1_from_server - start_server_version(:TLSv1) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1 - assert_handshake_error { server_connect(port, ctx) } - } - end + if supported.size == 1 + pend "More than one protocol version must be supported" + end -end + # Server sets min_version (earliest is disabled) + sver = supported[1] + ctx_proc = proc { |ctx| ctx.min_version = sver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client sets min_version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = cver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[supported.last][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + + # Client sets max_version + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.max_version = cver + if cver >= sver + server_connect(port, ctx2) { |ssl| + assert_equal vmap[cver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx2) { } } + end + end + } -if OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) && OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_1) + # Server sets max_version (latest is disabled) + sver = supported[-2] + ctx_proc = proc { |ctx| ctx.max_version = sver } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + supported.each do |cver| + # Client sets min_version + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = cver + if cver <= sver + server_connect(port, ctx1) { |ssl| + assert_equal vmap[sver][:name], ssl.ssl_version + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + else + assert_handshake_error { server_connect(port, ctx1) { } } + end - def test_tls_v1_2 - start_server_version(:TLSv1_2) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2_client - server_connect(port, ctx) { |ssl| assert_equal("TLSv1.2", ssl.ssl_version) } + # Client sets max_version + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.max_version = cver + server_connect(port, ctx2) { |ssl| + if cver >= sver + assert_equal vmap[sver][:name], ssl.ssl_version + else + assert_equal vmap[cver][:name], ssl.ssl_version + end + ssl.puts "abc"; assert_equal "abc\n", ssl.gets + } + end } end - def test_forbid_tls_v1_1_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_1 } - start_server_version(:SSLv23, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_1 - assert_handshake_error { server_connect(port, ctx) } - } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) + def test_options_disable_versions + # Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0. + supported = check_supported_protocol_versions - def test_forbid_tls_v1_1_from_server - start_server_version(:TLSv1_1) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_1 - assert_handshake_error { server_connect(port, ctx) } - } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) + if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) && + supported.include?(OpenSSL::SSL::TLS1_2_VERSION) + # Server disables ~ TLS 1.1 + ctx_proc = proc { |ctx| + ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | + OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client only supports TLS 1.1 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION + assert_handshake_error { server_connect(port, ctx1) { } } + + # Client only supports TLS 1.2 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION + assert_nothing_raised { server_connect(port, ctx2) { } } + } - def test_forbid_tls_v1_2_for_client - ctx_proc = Proc.new { |ctx| ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_2 } - start_server_version(:SSLv23, ctx_proc) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.ssl_version = :TLSv1_2 - assert_handshake_error { server_connect(port, ctx) } - } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) + # Server only supports TLS 1.1 + ctx_proc = proc { |ctx| + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client disables TLS 1.1 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1 + assert_handshake_error { server_connect(port, ctx1) { } } + + # Client disables TLS 1.2 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2 + assert_nothing_raised { server_connect(port, ctx2) { } } + } + else + pend "TLS 1.1 and TLS 1.2 must be supported; skipping" + end + end - def test_forbid_tls_v1_2_from_server - start_server_version(:TLSv1_2) { |port| - ctx = OpenSSL::SSL::SSLContext.new - ctx.options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_TLSv1_2 - assert_handshake_error { server_connect(port, ctx) } + def test_ssl_methods_constant + EnvUtil.suppress_warning { # Deprecated in v2.1.0 + base = [:TLSv1_2, :TLSv1_1, :TLSv1, :SSLv3, :SSLv2, :SSLv23] + base.each do |name| + assert_include OpenSSL::SSL::SSLContext::METHODS, name + assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_client" + assert_include OpenSSL::SSL::SSLContext::METHODS, :"#{name}_server" + end } - end if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) - -end + end def test_renegotiation_cb num_handshakes = 0 @@ -1086,6 +1327,58 @@ end end end + def test_fallback_scsv + pend "Fallback SCSV is not supported" unless \ + OpenSSL::SSL::SSLContext.method_defined?(:enable_fallback_scsv) + + start_server do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + # Here is OK + # TLS1.2 supported and this is what we ask the first time + server_connect(port, ctx) + end + + ctx_proc = proc { |ctx| + ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + } + start_server(ctx_proc: ctx_proc) do |port| + ctx = OpenSSL::SSL::SSLContext.new + ctx.enable_fallback_scsv + ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION + # Here is OK too + # TLS1.2 not supported, fallback to TLS1.1 and signaling the fallback + # Server doesn't support better, so connection OK + server_connect(port, ctx) + end + + # Here is not OK + # TLS1.2 is supported, fallback to TLS1.1 (downgrade attack) and signaling the fallback + # Server support better, so refuse the connection + sock1, sock2 = socketpair + begin + ctx1 = OpenSSL::SSL::SSLContext.new + s1 = OpenSSL::SSL::SSLSocket.new(sock1, ctx1) + + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.enable_fallback_scsv + ctx2.max_version = OpenSSL::SSL::TLS1_1_VERSION + s2 = OpenSSL::SSL::SSLSocket.new(sock2, ctx2) + t = Thread.new { + assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { + s2.connect + } + } + assert_raise_with_message(OpenSSL::SSL::SSLError, /inappropriate fallback/) { + s1.accept + } + t.join + ensure + sock1.close + sock2.close + end + end + def test_dh_callback pend "TLS 1.2 is not supported" unless tls12_supported? @@ -1202,11 +1495,24 @@ end return end assert_equal(1, ctx.security_level) - # assert_raise(OpenSSL::SSL::SSLError) { ctx.key = Fixtures.pkey("dsa512") } - # ctx.key = Fixtures.pkey("rsa1024") - # ctx.security_level = 2 - # assert_raise(OpenSSL::SSL::SSLError) { ctx.key = Fixtures.pkey("rsa1024") } - pend "FIXME: SSLContext#key= currently does not raise because SSL_CTX_use_certificate() is delayed" + + dsa512 = Fixtures.pkey("dsa512") + dsa512_cert = issue_cert(@svr, dsa512, 50, [], @ca_cert, @ca_key) + rsa1024 = Fixtures.pkey("rsa1024") + rsa1024_cert = issue_cert(@svr, rsa1024, 51, [], @ca_cert, @ca_key) + + assert_raise(OpenSSL::SSL::SSLError) { + # 512 bit DSA key is rejected because it offers < 80 bits of security + ctx.add_certificate(dsa512_cert, dsa512) + } + assert_nothing_raised { + ctx.add_certificate(rsa1024_cert, rsa1024) + } + ctx.security_level = 2 + assert_raise(OpenSSL::SSL::SSLError) { + # < 112 bits of security + ctx.add_certificate(rsa1024_cert, rsa1024) + } end def test_dup diff --git a/test/test_ssl_session.rb b/test/test_ssl_session.rb index 78b160ed..e199f86d 100644 --- a/test/test_ssl_session.rb +++ b/test/test_ssl_session.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestSSLSession < OpenSSL::SSLTestCase def test_session diff --git a/test/test_x509attr.rb b/test/test_x509attr.rb index d7473f1a..c6c48e86 100644 --- a/test/test_x509attr.rb +++ b/test/test_x509attr.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Attribute < OpenSSL::TestCase def test_new @@ -62,6 +62,23 @@ class OpenSSL::TestX509Attribute < OpenSSL::TestCase attr = OpenSSL::X509::Attribute.new("challengePassword", val) assert_equal(attr.to_der, attr.dup.to_der) end + + def test_eq + val1 = OpenSSL::ASN1::Set([ + OpenSSL::ASN1::UTF8String("abc123") + ]) + attr1 = OpenSSL::X509::Attribute.new("challengePassword", val1) + attr2 = OpenSSL::X509::Attribute.new("challengePassword", val1) + ef = OpenSSL::X509::ExtensionFactory.new + val2 = OpenSSL::ASN1::Set.new([OpenSSL::ASN1::Sequence.new([ + ef.create_extension("keyUsage", "keyCertSign", true) + ])]) + attr3 = OpenSSL::X509::Attribute.new("extReq", val2) + + assert_equal false, attr1 == 12345 + assert_equal true, attr1 == attr2 + assert_equal false, attr1 == attr3 + end end end diff --git a/test/test_x509cert.rb b/test/test_x509cert.rb index 03650402..40a5b0ad 100644 --- a/test/test_x509cert.rb +++ b/test/test_x509cert.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Certificate < OpenSSL::TestCase def setup @@ -30,13 +30,10 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase ["authorityKeyIdentifier","keyid:always",false], ] - sha1 = OpenSSL::Digest::SHA1.new - dsa_digest = OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new - [ - [@rsa1024, sha1], [@rsa2048, sha1], [@dsa256, dsa_digest], [@dsa512, dsa_digest] - ].each{|pk, digest| - cert = issue_cert(@ca, pk, 1, exts, nil, nil, digest: digest) + @rsa1024, @rsa2048, @dsa256, @dsa512, + ].each{|pk| + cert = issue_cert(@ca, pk, 1, exts, nil, nil) assert_equal(cert.extensions.sort_by(&:to_s)[2].value, OpenSSL::TestUtils.get_subject_key_id(cert)) cert = OpenSSL::X509::Certificate.new(cert.to_der) @@ -148,26 +145,15 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase } end - def test_dsig_algorithm_mismatch - assert_raise(OpenSSL::X509::CertificateError) do - issue_cert(@ca, @rsa2048, 1, [], nil, nil, digest: OpenSSL::Digest::DSS1.new) - end if OpenSSL::OPENSSL_VERSION_NUMBER < 0x10001000 # [ruby-core:42949] - end - def test_dsa_with_sha2 - begin - cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha256") - assert_equal("dsa_with_SHA256", cert.signature_algorithm) - rescue OpenSSL::X509::CertificateError - # dsa_with_sha2 not supported. skip following test. - return - end + cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha256") + assert_equal("dsa_with_SHA256", cert.signature_algorithm) # TODO: need more tests for dsa + sha2 # SHA1 is allowed from OpenSSL 1.0.0 (0.9.8 requires DSS1) cert = issue_cert(@ca, @dsa256, 1, [], nil, nil, digest: "sha1") assert_equal("dsaWithSHA1", cert.signature_algorithm) - end if defined?(OpenSSL::Digest::SHA256) + end def test_check_private_key cert = issue_cert(@ca, @rsa2048, 1, [], nil, nil) @@ -183,6 +169,26 @@ class OpenSSL::TestX509Certificate < OpenSSL::TestCase } end + def test_eq + now = Time.now + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil, + not_before: now, not_after: now + 3600) + cert1 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert2 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert3 = issue_cert(@ee1, @rsa2048, 3, [], cacert, @rsa1024, + not_before: now, not_after: now + 3600) + cert4 = issue_cert(@ee1, @rsa2048, 2, [], cacert, @rsa1024, + digest: "sha512", not_before: now, not_after: now + 3600) + + assert_equal false, cert1 == 12345 + assert_equal true, cert1 == cert2 + assert_equal false, cert1 == cert3 + assert_equal false, cert1 == cert4 + assert_equal false, cert3 == cert4 + end + private def certificate_error_returns_false diff --git a/test/test_x509crl.rb b/test/test_x509crl.rb index 7d55e3c1..03fdf64d 100644 --- a/test/test_x509crl.rb +++ b/test/test_x509crl.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509CRL < OpenSSL::TestCase def setup @@ -188,7 +188,7 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase cert = issue_cert(@ca, @dsa512, 1, [], nil, nil) crl = issue_crl([], 1, Time.now, Time.now+1600, [], - cert, @dsa512, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) + cert, @dsa512, OpenSSL::Digest::SHA1.new) assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) }) assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) }) assert_equal(false, crl.verify(@dsa256)) @@ -197,6 +197,58 @@ class OpenSSL::TestX509CRL < OpenSSL::TestCase assert_equal(false, crl.verify(@dsa512)) end + def test_revoked_to_der + # revokedCertificates SEQUENCE OF SEQUENCE { + # userCertificate CertificateSerialNumber, + # revocationDate Time, + # crlEntryExtensions Extensions OPTIONAL + # -- if present, version MUST be v2 + # } OPTIONAL, + + now = Time.utc(2000, 1, 1) + rev1 = OpenSSL::X509::Revoked.new + rev1.serial = 123 + rev1.time = now + ext = OpenSSL::X509::Extension.new("CRLReason", OpenSSL::ASN1::Enumerated(1)) + rev1.extensions = [ext] + asn1 = OpenSSL::ASN1::Sequence([ + OpenSSL::ASN1::Integer(123), + OpenSSL::ASN1::UTCTime(now), + OpenSSL::ASN1::Sequence([ext.to_der]) + ]) + + assert_equal asn1.to_der, rev1.to_der + end + + def test_eq + now = Time.now + + cacert = issue_cert(@ca, @rsa1024, 1, [], nil, nil) + crl1 = issue_crl([], 1, now, now + 3600, [], cacert, @rsa1024, "sha256") + rev1 = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 1 + rev.time = now + } + crl1.add_revoked(rev1) + crl2 = OpenSSL::X509::CRL.new(crl1.to_der) + + # CRL + assert_equal false, crl1 == 12345 + assert_equal true, crl1 == crl2 + rev2 = OpenSSL::X509::Revoked.new.tap { |rev| + rev.serial = 2 + rev.time = now + } + crl2.add_revoked(rev2) + assert_equal false, crl1 == crl2 + + # Revoked + assert_equal false, rev1 == 12345 + assert_equal true, rev1 == crl2.revoked[0] + assert_equal false, rev1 == crl2.revoked[1] + assert_equal true, rev2 == crl2.revoked[1] + end + private def crl_error_returns_false diff --git a/test/test_x509ext.rb b/test/test_x509ext.rb index 58f03168..91ce202f 100644 --- a/test/test_x509ext.rb +++ b/test/test_x509ext.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Extension < OpenSSL::TestCase def setup @@ -75,6 +75,17 @@ class OpenSSL::TestX509Extension < OpenSSL::TestCase assert_equal(@basic_constraints.to_der, ext.to_der) assert_equal(ext.to_der, ext.dup.to_der) end + + def test_eq + ext1 = OpenSSL::X509::Extension.new(@basic_constraints.to_der) + ef = OpenSSL::X509::ExtensionFactory.new + ext2 = ef.create_extension("basicConstraints", "critical, CA:TRUE, pathlen:2") + ext3 = ef.create_extension("basicConstraints", "critical, CA:TRUE") + + assert_equal false, ext1 == 12345 + assert_equal true, ext1 == ext2 + assert_equal false, ext1 == ext3 + end end end diff --git a/test/test_x509name.rb b/test/test_x509name.rb index c1dacf4f..2d92e645 100644 --- a/test/test_x509name.rb +++ b/test/test_x509name.rb @@ -1,8 +1,8 @@ -# coding: US-ASCII +# coding: ASCII-8BIT # frozen_string_literal: false require_relative 'utils' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Name < OpenSSL::TestCase def setup @@ -148,33 +148,28 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase end def test_s_parse - dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org" + dn = "/DC=org/DC=ruby-lang/CN=www.ruby-lang.org/1.2.3.4.5.6=A=BCD" name = OpenSSL::X509::Name.parse(dn) assert_equal(dn, name.to_s) ary = name.to_a - assert_equal("DC", ary[0][0]) - assert_equal("DC", ary[1][0]) - assert_equal("CN", ary[2][0]) - assert_equal("org", ary[0][1]) - assert_equal("ruby-lang", ary[1][1]) - assert_equal("www.ruby-lang.org", ary[2][1]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) - assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) - assert_equal(OpenSSL::ASN1::UTF8STRING, ary[2][2]) - - dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org" + assert_equal [ + ["DC", "org", OpenSSL::ASN1::IA5STRING], + ["DC", "ruby-lang", OpenSSL::ASN1::IA5STRING], + ["CN", "www.ruby-lang.org", OpenSSL::ASN1::UTF8STRING], + ["1.2.3.4.5.6", "A=BCD", OpenSSL::ASN1::UTF8STRING], + ], ary + + dn2 = "DC=org, DC=ruby-lang, CN=www.ruby-lang.org, 1.2.3.4.5.6=A=BCD" name = OpenSSL::X509::Name.parse(dn2) - ary = name.to_a assert_equal(dn, name.to_s) - assert_equal("org", ary[0][1]) - assert_equal("ruby-lang", ary[1][1]) - assert_equal("www.ruby-lang.org", ary[2][1]) + assert_equal ary, name.to_a name = OpenSSL::X509::Name.parse(dn2, @obj_type_tmpl) ary = name.to_a assert_equal(OpenSSL::ASN1::IA5STRING, ary[0][2]) assert_equal(OpenSSL::ASN1::IA5STRING, ary[1][2]) assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[2][2]) + assert_equal(OpenSSL::ASN1::PRINTABLESTRING, ary[3][2]) end def test_s_parse_rfc2253 @@ -322,16 +317,87 @@ class OpenSSL::TestX509Name < OpenSSL::TestCase assert_equal("Namiki", ary[5][1]) end + def test_add_entry_placing + der = %w{ 30 2A + 31 12 + 30 10 06 03 55 04 0A 0C 09 72 75 62 79 2D 6C 61 6E 67 + 31 14 + 30 08 06 03 55 04 0B 0C 01 61 + 30 08 06 03 55 04 0B 0C 01 62 } + orig = OpenSSL::X509::Name.new([der.join].pack("H*")) + assert_equal("OU=b+OU=a,O=ruby-lang", orig.to_s(OpenSSL::X509::Name::RFC2253)) + # Skip for now; they do not work + # + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 0, set: 0) + # assert_equal("OU=b+OU=a,O=ruby-lang,CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 0, set: 1) + # assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: 1, set: -1) + assert_equal("OU=b+OU=a,O=ruby-lang+CN=unya", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + # dn = orig.dup + # dn.add_entry("CN", "unya", loc: 1, set: 0) + # assert_equal("OU=b+OU=a,CN=unya,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: 1, set: 1) + assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: -1, set: -1) + assert_equal("CN=unya+OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + dn = orig.dup + dn.add_entry("CN", "unya", loc: -1, set: 0) + assert_equal("CN=unya,OU=b+OU=a,O=ruby-lang", dn.dup.to_s(OpenSSL::X509::Name::RFC2253)) + end + + def test_to_s + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "フー, バー"], + ] + name = OpenSSL::X509::Name.new + dn.each { |x| name.add_entry(*x) } + + assert_equal "/DC=org/DC=ruby-lang/" \ + "CN=\\xE3\\x83\\x95\\xE3\\x83\\xBC, \\xE3\\x83\\x90\\xE3\\x83\\xBC", + name.to_s + # OpenSSL escapes characters with MSB by default + assert_equal \ + "CN=\\E3\\83\\95\\E3\\83\\BC\\, \\E3\\83\\90\\E3\\83\\BC," \ + "DC=ruby-lang,DC=org", + name.to_s(OpenSSL::X509::Name::RFC2253) + assert_equal "DC = org, DC = ruby-lang, " \ + "CN = \"\\E3\\83\\95\\E3\\83\\BC, \\E3\\83\\90\\E3\\83\\BC\"", + name.to_s(OpenSSL::X509::Name::ONELINE) + end + + def test_to_utf8 + dn = [ + ["DC", "org"], + ["DC", "ruby-lang"], + ["CN", "フー, バー"], + ] + name = OpenSSL::X509::Name.new + dn.each { |x| name.add_entry(*x) } + + str = name.to_utf8 + expected = "CN=フー\\, バー,DC=ruby-lang,DC=org".force_encoding("UTF-8") + assert_equal expected, str + assert_equal Encoding.find("UTF-8"), str.encoding + end + def test_equals2 - n1 = OpenSSL::X509::Name.parse 'CN=a' - n2 = OpenSSL::X509::Name.parse 'CN=a' + n1 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' + n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' assert_equal n1, n2 end def test_spaceship - n1 = OpenSSL::X509::Name.parse 'CN=a' - n2 = OpenSSL::X509::Name.parse 'CN=b' + n1 = OpenSSL::X509::Name.parse_rfc2253 'CN=a' + n2 = OpenSSL::X509::Name.parse_rfc2253 'CN=b' assert_equal(-1, n1 <=> n2) end diff --git a/test/test_x509req.rb b/test/test_x509req.rb index fcc3e2f1..2c447ccd 100644 --- a/test/test_x509req.rb +++ b/test/test_x509req.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Request < OpenSSL::TestCase def setup @@ -28,7 +28,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase req = OpenSSL::X509::Request.new(req.to_der) assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) - req = issue_csr(0, @dn, @dsa512, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) req = OpenSSL::X509::Request.new(req.to_der) assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) @@ -122,7 +122,7 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase end def test_sign_and_verify_dsa - req = issue_csr(0, @dn, @dsa512, OpenSSL::TestUtils::DSA_SIGNATURE_DIGEST.new) + req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest::SHA1.new) assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) assert_equal(false, req.verify(@dsa256)) @@ -131,18 +131,6 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase assert_equal(false, req.verify(@dsa512)) end - def test_sign_and_verify_rsa_dss1 - req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest::DSS1.new) - assert_equal(true, req.verify(@rsa1024)) - assert_equal(false, req.verify(@rsa2048)) - assert_equal(false, request_error_returns_false { req.verify(@dsa256) }) - assert_equal(false, request_error_returns_false { req.verify(@dsa512) }) - req.version = 1 - assert_equal(false, req.verify(@rsa1024)) - rescue OpenSSL::X509::RequestError - pend - end if defined?(OpenSSL::Digest::DSS1) - def test_sign_and_verify_dsa_md5 assert_raise(OpenSSL::X509::RequestError){ issue_csr(0, @dn, @dsa512, OpenSSL::Digest::MD5.new) } @@ -153,6 +141,16 @@ class OpenSSL::TestX509Request < OpenSSL::TestCase assert_equal(req.to_der, req.dup.to_der) end + def test_eq + req1 = issue_csr(0, @dn, @rsa1024, "sha1") + req2 = issue_csr(0, @dn, @rsa1024, "sha1") + req3 = issue_csr(0, @dn, @rsa1024, "sha256") + + assert_equal false, req1 == 12345 + assert_equal true, req1 == req2 + assert_equal false, req1 == req3 + end + private def request_error_returns_false diff --git a/test/test_x509store.rb b/test/test_x509store.rb index b40534c6..6412249b 100644 --- a/test/test_x509store.rb +++ b/test/test_x509store.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative "utils" -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) class OpenSSL::TestX509Store < OpenSSL::TestCase def setup diff --git a/test/ut_eof.rb b/test/ut_eof.rb index a49ad513..bd62fd50 100644 --- a/test/ut_eof.rb +++ b/test/ut_eof.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require 'test/unit' -if defined?(OpenSSL::TestUtils) +if defined?(OpenSSL) module OpenSSL::TestEOF def test_eof_0 diff --git a/test/utils.rb b/test/utils.rb index b7ddd891..6318246d 100644 --- a/test/utils.rb +++ b/test/utils.rb @@ -34,7 +34,7 @@ require "tempfile" require "socket" require "envutil" -if defined?(OpenSSL) && OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10000000 +if defined?(OpenSSL) module OpenSSL::TestUtils module Fixtures @@ -56,14 +56,10 @@ module OpenSSL::TestUtils end end - DSA_SIGNATURE_DIGEST = OpenSSL::OPENSSL_VERSION_NUMBER > 0x10000000 ? - OpenSSL::Digest::SHA1 : - OpenSSL::Digest::DSS1 - module_function def issue_cert(dn, key, serial, extensions, issuer, issuer_key, - not_before: nil, not_after: nil, digest: nil) + not_before: nil, not_after: nil, digest: "sha256") cert = OpenSSL::X509::Certificate.new issuer = cert unless issuer issuer_key = key unless issuer_key @@ -71,7 +67,7 @@ module OpenSSL::TestUtils cert.serial = serial cert.subject = dn cert.issuer = issuer.subject - cert.public_key = key.public_key + cert.public_key = key now = Time.now cert.not_before = not_before || now - 3600 cert.not_after = not_after || now + 3600 @@ -81,7 +77,6 @@ module OpenSSL::TestUtils extensions.each{|oid, value, critical| cert.add_extension(ef.create_extension(oid, value, critical)) } - digest ||= OpenSSL::PKey::DSA === issuer_key ? DSA_SIGNATURE_DIGEST.new : "sha256" cert.sign(issuer_key, digest) cert end @@ -182,7 +177,10 @@ class OpenSSL::SSLTestCase < OpenSSL::TestCase end def tls12_supported? - OpenSSL::SSL::SSLContext::METHODS.include?(:TLSv1_2) + ctx = OpenSSL::SSL::SSLContext.new + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + true + rescue end def readwrite_loop(ctx, ssl) |