diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c index a3e4afe7c..517212b4d 100644 --- a/ext/openssl/ossl_asn1.c +++ b/ext/openssl/ossl_asn1.c @@ -895,6 +895,8 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, return asn1data; } +#define MAX_NESTING_DEPTH 200 + static VALUE ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, int yield, long *num_read) @@ -905,6 +907,10 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, int tag, tc, j; VALUE asn1data, tag_class; + if (depth > MAX_NESTING_DEPTH) { + ossl_raise(eASN1Error, "nesting depth %d exceeds limit", depth); + } + p = *pp; start = p; p0 = p; diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb index 5978ecf67..0293813a8 100644 --- a/test/openssl/test_asn1.rb +++ b/test/openssl/test_asn1.rb @@ -696,6 +696,20 @@ def test_decode_constructed_overread assert_equal 17, ret[0][6] end + def test_decode_constructed_deeply_nested + bool = OpenSSL::ASN1::Boolean.new(true) + nested_100 = B(%w{ 30 80 }) * 100 + bool.to_der + B(%w{ 00 00 }) * 100 + decoded = OpenSSL::ASN1.decode(nested_100) + assert_equal(nested_100, decoded.to_der) + content = 100.times.inject(decoded) { |a,| a.value[0] } + assert_kind_of(OpenSSL::ASN1::Boolean, content) + + nested_500 = B(%w{ 30 80 }) * 500 + bool.to_der + B(%w{ 00 00 }) * 500 + assert_raise_with_message(OpenSSL::ASN1::ASN1Error, /nesting depth/) { + OpenSSL::ASN1.decode(nested_500) + } + end + def test_constructive_each data = [OpenSSL::ASN1::Integer.new(0), OpenSSL::ASN1::Integer.new(1)] seq = OpenSSL::ASN1::Sequence.new data