|
|
8ca061 |
From 5450329ad1778d72f117b68e5edb97ae1bf4d438 Mon Sep 17 00:00:00 2001
|
|
|
8ca061 |
From: usa <usa@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
|
|
|
8ca061 |
Date: Thu, 14 Sep 2017 11:41:59 +0000
|
|
|
8ca061 |
Subject: [PATCH] asn1: fix out-of-bounds read in decoding constructed objects
|
|
|
8ca061 |
|
|
|
8ca061 |
* OpenSSL::ASN1.{decode,decode_all,traverse}: have a bug of
|
|
|
8ca061 |
out-of-bounds read. int_ossl_asn1_decode0_cons() does not give the
|
|
|
8ca061 |
correct available length to ossl_asn1_decode() when decoding the
|
|
|
8ca061 |
inner components of a constructed object. This can cause
|
|
|
8ca061 |
out-of-bounds read if a crafted input given.
|
|
|
8ca061 |
|
|
|
8ca061 |
Reference: https://hackerone.com/reports/170316
|
|
|
8ca061 |
https://github.com/ruby/openssl/commit/1648afef33c1d97fb203c82291b8a61269e85d3b
|
|
|
8ca061 |
|
|
|
8ca061 |
|
|
|
8ca061 |
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_2@59903 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
|
|
|
8ca061 |
---
|
|
|
8ca061 |
ChangeLog | 13 +++++++++++++
|
|
|
8ca061 |
ext/openssl/ossl_asn1.c | 13 ++++++-------
|
|
|
8ca061 |
test/openssl/test_asn1.rb | 23 +++++++++++++++++++++++
|
|
|
8ca061 |
3 files changed, 42 insertions(+), 7 deletions(-)
|
|
|
8ca061 |
|
|
|
8ca061 |
diff --git a/ChangeLog b/ChangeLog
|
|
|
8ca061 |
index 7561c35eb705..6288f67500fd 100644
|
|
|
8ca061 |
--- a/ChangeLog
|
|
|
8ca061 |
+++ b/ChangeLog
|
|
|
8ca061 |
@@ -17,6 +17,19 @@
|
|
|
8ca061 |
Thu Sep 14 20:44:26 2017 SHIBATA Hiroshi <hsbt@ruby-lang.org>
|
|
|
8ca061 |
|
|
|
8ca061 |
* ext/json: bump to version 1.8.1.1. [Backport #13853]
|
|
|
8ca061 |
+
|
|
|
8ca061 |
+Thu Sep 14 20:39:39 2017 Kazuki Yamaguchi <k@rhe.jp>
|
|
|
8ca061 |
+
|
|
|
8ca061 |
+ asn1: fix out-of-bounds read in decoding constructed objects
|
|
|
8ca061 |
+
|
|
|
8ca061 |
+ * OpenSSL::ASN1.{decode,decode_all,traverse}: have a bug of
|
|
|
8ca061 |
+ out-of-bounds read. int_ossl_asn1_decode0_cons() does not give the
|
|
|
8ca061 |
+ correct available length to ossl_asn1_decode() when decoding the
|
|
|
8ca061 |
+ inner components of a constructed object. This can cause
|
|
|
8ca061 |
+ out-of-bounds read if a crafted input given.
|
|
|
8ca061 |
+
|
|
|
8ca061 |
+ Reference: https://hackerone.com/reports/170316
|
|
|
8ca061 |
+ https://github.com/ruby/openssl/commit/1648afef33c1d97fb203c82291b8a61269e85d3b
|
|
|
8ca061 |
|
|
|
8ca061 |
Thu Sep 14 20:36:54 2017 Yusuke Endoh <mame@ruby-lang.org>
|
|
|
8ca061 |
|
|
|
8ca061 |
diff --git a/ext/openssl/ossl_asn1.c b/ext/openssl/ossl_asn1.c
|
|
|
8ca061 |
index 6d564a312f35..719063c551e5 100644
|
|
|
8ca061 |
--- a/ext/openssl/ossl_asn1.c
|
|
|
8ca061 |
+++ b/ext/openssl/ossl_asn1.c
|
|
|
8ca061 |
@@ -871,19 +871,18 @@ int_ossl_asn1_decode0_cons(unsigned char **pp, long max_len, long length,
|
|
|
8ca061 |
{
|
|
|
8ca061 |
VALUE value, asn1data, ary;
|
|
|
8ca061 |
int infinite;
|
|
|
8ca061 |
- long off = *offset;
|
|
|
8ca061 |
+ long available_len, off = *offset;
|
|
|
8ca061 |
|
|
|
8ca061 |
infinite = (j == 0x21);
|
|
|
8ca061 |
ary = rb_ary_new();
|
|
|
8ca061 |
|
|
|
8ca061 |
- while (length > 0 || infinite) {
|
|
|
8ca061 |
+ available_len = infinite ? max_len : length;
|
|
|
8ca061 |
+ while (available_len > 0) {
|
|
|
8ca061 |
long inner_read = 0;
|
|
|
8ca061 |
- value = ossl_asn1_decode0(pp, max_len, &off, depth + 1, yield, &inner_read);
|
|
|
8ca061 |
+ value = ossl_asn1_decode0(pp, available_len, &off, depth + 1, yield, &inner_read);
|
|
|
8ca061 |
*num_read += inner_read;
|
|
|
8ca061 |
- max_len -= inner_read;
|
|
|
8ca061 |
+ available_len -= inner_read;
|
|
|
8ca061 |
rb_ary_push(ary, value);
|
|
|
8ca061 |
- if (length > 0)
|
|
|
8ca061 |
- length -= inner_read;
|
|
|
8ca061 |
|
|
|
8ca061 |
if (infinite &&
|
|
|
8ca061 |
NUM2INT(ossl_asn1_get_tag(value)) == V_ASN1_EOC &&
|
|
|
8ca061 |
@@ -974,7 +973,7 @@ ossl_asn1_decode0(unsigned char **pp, long length, long *offset, int depth,
|
|
|
8ca061 |
if(j & V_ASN1_CONSTRUCTED) {
|
|
|
8ca061 |
*pp += hlen;
|
|
|
8ca061 |
off += hlen;
|
|
|
8ca061 |
- asn1data = int_ossl_asn1_decode0_cons(pp, length, len, &off, depth, yield, j, tag, tag_class, &inner_read);
|
|
|
8ca061 |
+ asn1data = int_ossl_asn1_decode0_cons(pp, length - hlen, len, &off, depth, yield, j, tag, tag_class, &inner_read);
|
|
|
8ca061 |
inner_read += hlen;
|
|
|
8ca061 |
}
|
|
|
8ca061 |
else {
|
|
|
8ca061 |
diff --git a/test/openssl/test_asn1.rb b/test/openssl/test_asn1.rb
|
|
|
8ca061 |
index 9fb5a551c66d..a6d7c2c14e00 100644
|
|
|
8ca061 |
--- a/test/openssl/test_asn1.rb
|
|
|
8ca061 |
+++ b/test/openssl/test_asn1.rb
|
|
|
8ca061 |
@@ -595,6 +595,29 @@ def test_recursive_octet_string_parse
|
|
|
8ca061 |
assert_equal(false, asn1.value[3].infinite_length)
|
|
|
8ca061 |
end
|
|
|
8ca061 |
|
|
|
8ca061 |
+ def test_decode_constructed_overread
|
|
|
8ca061 |
+ test = %w{ 31 06 31 02 30 02 05 00 }
|
|
|
8ca061 |
+ # ^ <- invalid
|
|
|
8ca061 |
+ raw = [test.join].pack("H*")
|
|
|
8ca061 |
+ ret = []
|
|
|
8ca061 |
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
|
|
|
8ca061 |
+ OpenSSL::ASN1.traverse(raw) { |x| ret << x }
|
|
|
8ca061 |
+ }
|
|
|
8ca061 |
+ assert_equal 2, ret.size
|
|
|
8ca061 |
+ assert_equal 17, ret[0][6]
|
|
|
8ca061 |
+ assert_equal 17, ret[1][6]
|
|
|
8ca061 |
+
|
|
|
8ca061 |
+ test = %w{ 31 80 30 03 00 00 }
|
|
|
8ca061 |
+ # ^ <- invalid
|
|
|
8ca061 |
+ raw = [test.join].pack("H*")
|
|
|
8ca061 |
+ ret = []
|
|
|
8ca061 |
+ assert_raise(OpenSSL::ASN1::ASN1Error) {
|
|
|
8ca061 |
+ OpenSSL::ASN1.traverse(raw) { |x| ret << x }
|
|
|
8ca061 |
+ }
|
|
|
8ca061 |
+ assert_equal 1, ret.size
|
|
|
8ca061 |
+ assert_equal 17, ret[0][6]
|
|
|
8ca061 |
+ end
|
|
|
8ca061 |
+
|
|
|
8ca061 |
private
|
|
|
8ca061 |
|
|
|
8ca061 |
def assert_universal(tag, asn1)
|