1 |
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c |
2 |
index 6d564a312f35..719063c551e5 100644 |
3 |
--- a/ext/openssl/ossl_asn1.c |
4 |
+++ b/ext/openssl/ossl_asn1.c |
5 |
@@ -871,19 +871,18 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length, |
6 |
{ |
7 |
VALUE value, asn1data, ary; |
8 |
int infinite; |
9 |
- long off = *offset; |
10 |
+ long available_len, off = *offset; |
11 |
|
12 |
infinite = (j == 0x21); |
13 |
ary = rb_ary_new(); |
14 |
|
15 |
- while (length > 0 || infinite) { |
16 |
+ available_len = infinite ? max_len : length; |
17 |
+ while (available_len > 0) { |
18 |
long inner_read = 0; |
19 |
- value = ossl_asn1_decode0(pp, max_len, &off, depth + 1, yield, &inner_read); |
20 |
+ value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read); |
21 |
*num_read += inner_read; |
22 |
- max_len -= inner_read; |
23 |
+ available_len -= inner_read; |
24 |
rb_ary_push(ary, value); |
25 |
- if (length > 0) |
26 |
- length -= inner_read; |
27 |
|
28 |
if (infinite && |
29 |
NUM2INT(ossl_asn1_get_tag(value)) == V_ASN1_EOC && |
30 |
@@ -974,7 +973,7 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth, |
31 |
if(j & V_ASN1_CONSTRUCTED) { |
32 |
*pp += hlen; |
33 |
off += hlen; |
34 |
- asn1data = int_ossl_asn1_decode0_cons(pp, length, len, &off, depth, yield, j, tag, tag_class, &inner_read); |
35 |
+ asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read); |
36 |
inner_read += hlen; |
37 |
} |
38 |
else { |
39 |
diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb |
40 |
index 9fb5a551c66d..a6d7c2c14e00 100644 |
41 |
--- a/test/openssl/test_asn1.rb |
42 |
+++ b/test/openssl/test_asn1.rb |
43 |
@@ -595,6 +595,29 @@ def test_recursive_octet_string_parse |
44 |
assert_equal(false, asn1.value[3].infinite_length) |
45 |
end |
46 |
|
47 |
+ def test_decode_constructed_overread |
48 |
+ test = %w{ 31 06 31 02 30 02 05 00 } |
49 |
+ # ^ <- invalid |
50 |
+ raw = [test.join].pack("H*") |
51 |
+ ret = [] |
52 |
+ assert_raise(OpenSSL::ASN1::ASN1Error) { |
53 |
+ OpenSSL::ASN1.traverse(raw) { |x| ret << x } |
54 |
+ } |
55 |
+ assert_equal 2, ret.size |
56 |
+ assert_equal 17, ret[0][6] |
57 |
+ assert_equal 17, ret[1][6] |
58 |
+ |
59 |
+ test = %w{ 31 80 30 03 00 00 } |
60 |
+ # ^ <- invalid |
61 |
+ raw = [test.join].pack("H*") |
62 |
+ ret = [] |
63 |
+ assert_raise(OpenSSL::ASN1::ASN1Error) { |
64 |
+ OpenSSL::ASN1.traverse(raw) { |x| ret << x } |
65 |
+ } |
66 |
+ assert_equal 1, ret.size |
67 |
+ assert_equal 17, ret[0][6] |
68 |
+ end |
69 |
+ |
70 |
private |
71 |
|
72 |
def assert_universal(tag, asn1) |