mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
694 lines
29 KiB
Ruby
694 lines
29 KiB
Ruby
# frozen_string_literal: false
|
|
require_relative 'utils'
|
|
|
|
if defined?(OpenSSL)
|
|
|
|
class OpenSSL::TestASN1 < OpenSSL::TestCase
|
|
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
|
|
s = 0xdeadbeafdeadbeafdeadbeafdeadbeaf
|
|
exts = [
|
|
["basicConstraints","CA:TRUE,pathlen:1",true],
|
|
["keyUsage","keyCertSign, cRLSign",true],
|
|
["subjectKeyIdentifier","hash",false],
|
|
]
|
|
dgst = OpenSSL::Digest::SHA1.new
|
|
cert = OpenSSL::TestUtils.issue_cert(
|
|
subj, key, s, exts, nil, nil, digest: dgst, not_before: now, not_after: now+3600)
|
|
|
|
|
|
asn1 = OpenSSL::ASN1.decode(cert)
|
|
assert_equal(OpenSSL::ASN1::Sequence, asn1.class)
|
|
assert_equal(3, asn1.value.size)
|
|
tbs_cert, sig_alg, sig_val = *asn1.value
|
|
|
|
assert_equal(OpenSSL::ASN1::Sequence, tbs_cert.class)
|
|
assert_equal(8, tbs_cert.value.size)
|
|
|
|
version = tbs_cert.value[0]
|
|
assert_equal(:CONTEXT_SPECIFIC, version.tag_class)
|
|
assert_equal(0, version.tag)
|
|
assert_equal(1, version.value.size)
|
|
assert_equal(OpenSSL::ASN1::Integer, version.value[0].class)
|
|
assert_equal(2, version.value[0].value)
|
|
|
|
serial = tbs_cert.value[1]
|
|
assert_equal(OpenSSL::ASN1::Integer, serial.class)
|
|
assert_equal(0xdeadbeafdeadbeafdeadbeafdeadbeaf, serial.value)
|
|
|
|
sig = tbs_cert.value[2]
|
|
assert_equal(OpenSSL::ASN1::Sequence, sig.class)
|
|
assert_equal(2, sig.value.size)
|
|
assert_equal(OpenSSL::ASN1::ObjectId, sig.value[0].class)
|
|
assert_equal("1.2.840.113549.1.1.5", sig.value[0].oid)
|
|
assert_equal(OpenSSL::ASN1::Null, sig.value[1].class)
|
|
|
|
dn = tbs_cert.value[3] # issuer
|
|
assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.class)
|
|
assert_equal(3, dn.value.size)
|
|
assert_equal(OpenSSL::ASN1::Set, dn.value[0].class)
|
|
assert_equal(OpenSSL::ASN1::Set, dn.value[1].class)
|
|
assert_equal(OpenSSL::ASN1::Set, dn.value[2].class)
|
|
assert_equal(1, dn.value[0].value.size)
|
|
assert_equal(1, dn.value[1].value.size)
|
|
assert_equal(1, dn.value[2].value.size)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class)
|
|
assert_equal(2, dn.value[0].value[0].value.size)
|
|
assert_equal(2, dn.value[1].value[0].value.size)
|
|
assert_equal(2, dn.value[2].value[0].value.size)
|
|
oid, value = *dn.value[0].value[0].value
|
|
assert_equal(OpenSSL::ASN1::ObjectId, oid.class)
|
|
assert_equal("0.9.2342.19200300.100.1.25", oid.oid)
|
|
assert_equal(OpenSSL::ASN1::IA5String, value.class)
|
|
assert_equal("org", value.value)
|
|
oid, value = *dn.value[1].value[0].value
|
|
assert_equal(OpenSSL::ASN1::ObjectId, oid.class)
|
|
assert_equal("0.9.2342.19200300.100.1.25", oid.oid)
|
|
assert_equal(OpenSSL::ASN1::IA5String, value.class)
|
|
assert_equal("ruby-lang", value.value)
|
|
oid, value = *dn.value[2].value[0].value
|
|
assert_equal(OpenSSL::ASN1::ObjectId, oid.class)
|
|
assert_equal("2.5.4.3", oid.oid)
|
|
assert_equal(OpenSSL::ASN1::UTF8String, value.class)
|
|
assert_equal("TestCA", value.value)
|
|
|
|
validity = tbs_cert.value[4]
|
|
assert_equal(OpenSSL::ASN1::Sequence, validity.class)
|
|
assert_equal(2, validity.value.size)
|
|
assert_equal(OpenSSL::ASN1::UTCTime, validity.value[0].class)
|
|
assert_equal(now, validity.value[0].value)
|
|
assert_equal(OpenSSL::ASN1::UTCTime, validity.value[1].class)
|
|
assert_equal(now+3600, validity.value[1].value)
|
|
|
|
dn = tbs_cert.value[5] # subject
|
|
assert_equal(subj.hash, OpenSSL::X509::Name.new(dn).hash)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.class)
|
|
assert_equal(3, dn.value.size)
|
|
assert_equal(OpenSSL::ASN1::Set, dn.value[0].class)
|
|
assert_equal(OpenSSL::ASN1::Set, dn.value[1].class)
|
|
assert_equal(OpenSSL::ASN1::Set, dn.value[2].class)
|
|
assert_equal(1, dn.value[0].value.size)
|
|
assert_equal(1, dn.value[1].value.size)
|
|
assert_equal(1, dn.value[2].value.size)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.value[0].value[0].class)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.value[1].value[0].class)
|
|
assert_equal(OpenSSL::ASN1::Sequence, dn.value[2].value[0].class)
|
|
assert_equal(2, dn.value[0].value[0].value.size)
|
|
assert_equal(2, dn.value[1].value[0].value.size)
|
|
assert_equal(2, dn.value[2].value[0].value.size)
|
|
oid, value = *dn.value[0].value[0].value
|
|
assert_equal(OpenSSL::ASN1::ObjectId, oid.class)
|
|
assert_equal("0.9.2342.19200300.100.1.25", oid.oid)
|
|
assert_equal(OpenSSL::ASN1::IA5String, value.class)
|
|
assert_equal("org", value.value)
|
|
oid, value = *dn.value[1].value[0].value
|
|
assert_equal(OpenSSL::ASN1::ObjectId, oid.class)
|
|
assert_equal("0.9.2342.19200300.100.1.25", oid.oid)
|
|
assert_equal(OpenSSL::ASN1::IA5String, value.class)
|
|
assert_equal("ruby-lang", value.value)
|
|
oid, value = *dn.value[2].value[0].value
|
|
assert_equal(OpenSSL::ASN1::ObjectId, oid.class)
|
|
assert_equal("2.5.4.3", oid.oid)
|
|
assert_equal(OpenSSL::ASN1::UTF8String, value.class)
|
|
assert_equal("TestCA", value.value)
|
|
|
|
pkey = tbs_cert.value[6]
|
|
assert_equal(OpenSSL::ASN1::Sequence, pkey.class)
|
|
assert_equal(2, pkey.value.size)
|
|
assert_equal(OpenSSL::ASN1::Sequence, pkey.value[0].class)
|
|
assert_equal(2, pkey.value[0].value.size)
|
|
assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class)
|
|
assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid)
|
|
assert_equal(OpenSSL::ASN1::BitString, pkey.value[1].class)
|
|
assert_equal(0, pkey.value[1].unused_bits)
|
|
spkey = OpenSSL::ASN1.decode(pkey.value[1].value)
|
|
assert_equal(OpenSSL::ASN1::Sequence, spkey.class)
|
|
assert_equal(2, spkey.value.size)
|
|
assert_equal(OpenSSL::ASN1::Integer, spkey.value[0].class)
|
|
assert_equal(cert.public_key.n, spkey.value[0].value)
|
|
assert_equal(OpenSSL::ASN1::Integer, spkey.value[1].class)
|
|
assert_equal(cert.public_key.e, spkey.value[1].value)
|
|
|
|
extensions = tbs_cert.value[7]
|
|
assert_equal(:CONTEXT_SPECIFIC, extensions.tag_class)
|
|
assert_equal(3, extensions.tag)
|
|
assert_equal(1, extensions.value.size)
|
|
assert_equal(OpenSSL::ASN1::Sequence, extensions.value[0].class)
|
|
assert_equal(3, extensions.value[0].value.size)
|
|
|
|
ext = extensions.value[0].value[0] # basicConstraints
|
|
assert_equal(OpenSSL::ASN1::Sequence, ext.class)
|
|
assert_equal(3, ext.value.size)
|
|
assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class)
|
|
assert_equal("2.5.29.19", ext.value[0].oid)
|
|
assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class)
|
|
assert_equal(true, ext.value[1].value)
|
|
assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class)
|
|
extv = OpenSSL::ASN1.decode(ext.value[2].value)
|
|
assert_equal(OpenSSL::ASN1::Sequence, extv.class)
|
|
assert_equal(2, extv.value.size)
|
|
assert_equal(OpenSSL::ASN1::Boolean, extv.value[0].class)
|
|
assert_equal(true, extv.value[0].value)
|
|
assert_equal(OpenSSL::ASN1::Integer, extv.value[1].class)
|
|
assert_equal(1, extv.value[1].value)
|
|
|
|
ext = extensions.value[0].value[1] # keyUsage
|
|
assert_equal(OpenSSL::ASN1::Sequence, ext.class)
|
|
assert_equal(3, ext.value.size)
|
|
assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class)
|
|
assert_equal("2.5.29.15", ext.value[0].oid)
|
|
assert_equal(OpenSSL::ASN1::Boolean, ext.value[1].class)
|
|
assert_equal(true, ext.value[1].value)
|
|
assert_equal(OpenSSL::ASN1::OctetString, ext.value[2].class)
|
|
extv = OpenSSL::ASN1.decode(ext.value[2].value)
|
|
assert_equal(OpenSSL::ASN1::BitString, extv.class)
|
|
str = "\000"; str[0] = 0b00000110.chr
|
|
assert_equal(str, extv.value)
|
|
|
|
ext = extensions.value[0].value[2] # subjetKeyIdentifier
|
|
assert_equal(OpenSSL::ASN1::Sequence, ext.class)
|
|
assert_equal(2, ext.value.size)
|
|
assert_equal(OpenSSL::ASN1::ObjectId, ext.value[0].class)
|
|
assert_equal("2.5.29.14", ext.value[0].oid)
|
|
assert_equal(OpenSSL::ASN1::OctetString, ext.value[1].class)
|
|
extv = OpenSSL::ASN1.decode(ext.value[1].value)
|
|
assert_equal(OpenSSL::ASN1::OctetString, extv.class)
|
|
sha1 = OpenSSL::Digest::SHA1.new
|
|
sha1.update(pkey.value[1].value)
|
|
assert_equal(sha1.digest, extv.value)
|
|
|
|
assert_equal(OpenSSL::ASN1::Sequence, sig_alg.class)
|
|
assert_equal(2, sig_alg.value.size)
|
|
assert_equal(OpenSSL::ASN1::ObjectId, pkey.value[0].value[0].class)
|
|
assert_equal("1.2.840.113549.1.1.1", pkey.value[0].value[0].oid)
|
|
assert_equal(OpenSSL::ASN1::Null, pkey.value[0].value[1].class)
|
|
|
|
assert_equal(OpenSSL::ASN1::BitString, sig_val.class)
|
|
cululated_sig = key.sign(OpenSSL::Digest::SHA1.new, tbs_cert.to_der)
|
|
assert_equal(cululated_sig, sig_val.value)
|
|
end
|
|
|
|
def test_decode_all
|
|
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|
|
|
assert_universal(OpenSSL::ASN1::INTEGER, asn1)
|
|
assert_equal(i + 1, asn1.value)
|
|
end
|
|
end
|
|
|
|
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_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_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_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_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_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_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
|
|
# 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 }
|
|
|
|
prim = OpenSSL::ASN1::Integer.new(50)
|
|
assert_equal false, prim.indefinite_length
|
|
assert_not_respond_to prim, :indefinite_length=
|
|
end
|
|
|
|
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)
|
|
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
|
|
|
|
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)
|
|
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
|
|
|
|
# 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)
|
|
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
|
|
|
|
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)
|
|
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
|
|
|
|
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
|
|
|
|
# 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_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.indefinite_length = true
|
|
encode_test B(%w{ A0 80 04 03 61 61 61 00 00 }), cons
|
|
end
|
|
|
|
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.indefinite_length = true
|
|
container2 = OpenSSL::ASN1::Constructive.new(octets_sub2, OpenSSL::ASN1::OCTET_STRING, nil, :UNIVERSAL)
|
|
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.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_recursive_octet_string_parse
|
|
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.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.indefinite_length)
|
|
assert_equal(1, nested1.value.size)
|
|
oct1 = nested1.value[0]
|
|
assert_universal(OpenSSL::ASN1::OCTET_STRING, oct1)
|
|
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.indefinite_length)
|
|
assert_equal(1, nested2.value.size)
|
|
oct2 = nested2.value[0]
|
|
assert_universal(OpenSSL::ASN1::OCTET_STRING, oct2)
|
|
assert_equal(false, oct2.indefinite_length)
|
|
oct3 = asn1.value[2]
|
|
assert_universal(OpenSSL::ASN1::OCTET_STRING, oct3)
|
|
assert_equal(false, oct3.indefinite_length)
|
|
end
|
|
|
|
def test_decode_constructed_overread
|
|
test = %w{ 31 06 31 02 30 02 05 00 }
|
|
# ^ <- invalid
|
|
raw = [test.join].pack("H*")
|
|
ret = []
|
|
assert_raise(OpenSSL::ASN1::ASN1Error) {
|
|
OpenSSL::ASN1.traverse(raw) { |x| ret << x }
|
|
}
|
|
assert_equal 2, ret.size
|
|
assert_equal 17, ret[0][6]
|
|
assert_equal 17, ret[1][6]
|
|
|
|
test = %w{ 31 80 30 03 00 00 }
|
|
# ^ <- invalid
|
|
raw = [test.join].pack("H*")
|
|
ret = []
|
|
assert_raise(OpenSSL::ASN1::ASN1Error) {
|
|
OpenSSL::ASN1.traverse(raw) { |x| ret << x }
|
|
}
|
|
assert_equal 1, ret.size
|
|
assert_equal 17, ret[0][6]
|
|
end
|
|
|
|
def test_constructive_each
|
|
data = [OpenSSL::ASN1::Integer.new(0), OpenSSL::ASN1::Integer.new(1)]
|
|
seq = OpenSSL::ASN1::Sequence.new data
|
|
|
|
assert_equal data, seq.entries
|
|
end
|
|
|
|
def test_gc_stress
|
|
skip "very time consuming test"
|
|
assert_ruby_status(['--disable-gems', '-eGC.stress=true', '-erequire "openssl.so"'])
|
|
end
|
|
|
|
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)
|
|
assert_nil(asn1.tagging)
|
|
end
|
|
assert_equal(:UNIVERSAL, asn1.tag_class)
|
|
end
|
|
end
|
|
|
|
end
|