See attached. OpenSSL can't actually represent large universal tags because
it collides with the V_ASN1_NEG flag, yet it happily parses them in high
tag number form. d2i_ASN1_TYPE interprets 1f82020100 as a negative zero,
rather than an element with tag [UNIVERSAL 258].

I've intentionally made the patch very conservative, so it only limits
universal tags, in case there is worry about someone actually using tag
number 258 of another class. (Although I've never seen anything go beyond
31 into high tag number form at all.)

Our version of the change has a test:
https://boringssl.googlesource.com/boringssl/+/fb2c6f8c8565e1e2d85c24408050c96521acbcdc%5E%21/
It should be straight-forward to adapt (the test barely does anything). I'm
not sure how adding a test in OpenSSL works these days, so I leave that to
you.

David

-- 
Ticket here: http://rt.openssl.org/Ticket/Display.html?id=4364
Please log in as guest with password guest if prompted

>From be074e3369ee0754f1413be82d0fa0f5effc8b27 Mon Sep 17 00:00:00 2001
From: David Benjamin <david...@google.com>
Date: Tue, 1 Mar 2016 13:58:04 -0500
Subject: [PATCH] ASN1_get_object should not accept large universal tags.

The high bits of the type get used for the V_ASN1_NEG bit, so when used with
ASN1_ANY/ASN1_TYPE, universal tags become ambiguous. This allows one to create
a negative zero, which should be impossible. Impose an upper bound on universal
tags accepted by crypto/asn1.

See also BoringSSL's
https://boringssl.googlesource.com/boringssl/+/fb2c6f8c8565e1e2d85c24408050c96521acbcdc.
---
 crypto/asn1/asn1_lib.c | 4 ++++
 include/openssl/asn1.h | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
index da1ac78..fe1473f 100644
--- a/crypto/asn1/asn1_lib.c
+++ b/crypto/asn1/asn1_lib.c
@@ -126,6 +126,10 @@ int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
         if (--max == 0)
             goto err;
     }
+
+    if (xclass == V_ASN1_UNIVERSAL && tag > V_ASN1_MAX_UNIVERSAL)
+        goto err;
+
     *ptag = tag;
     *pclass = xclass;
     if (!asn1_get_length(&p, &inf, plength, (int)max))
diff --git a/include/openssl/asn1.h b/include/openssl/asn1.h
index 360914d..aa064d2 100644
--- a/include/openssl/asn1.h
+++ b/include/openssl/asn1.h
@@ -95,6 +95,9 @@ extern "C" {
 # define V_ASN1_ANY                      -4/* used in ASN1 template code */
 
 # define V_ASN1_NEG                      0x100/* negative flag */
+/* No supported universal tags may exceed this value, to avoid ambiguity with
+ * V_ASN1_NEG. */
+# define V_ASN1_MAX_UNIVERSAL            0xff
 
 # define V_ASN1_UNDEF                    -1
 # define V_ASN1_EOC                      0
-- 
2.7.0.rc3.207.g0ac5344

-- 
openssl-dev mailing list
To unsubscribe: https://mta.openssl.org/mailman/listinfo/openssl-dev

Reply via email to