Fix overflow checks when converting ASN.1 integers to long.

(Credit to libFuzzer for finding this.)

Change-Id: I0353d686d883703d39145c5bdd1e56368a587a35
Reviewed-on: https://boringssl-review.googlesource.com/22324
Reviewed-by: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/asn1/a_enum.c b/crypto/asn1/a_enum.c
index cc46905..4a77971 100644
--- a/crypto/asn1/a_enum.c
+++ b/crypto/asn1/a_enum.c
@@ -56,6 +56,7 @@
 
 #include <openssl/asn1.h>
 
+#include <limits.h>
 #include <string.h>
 
 #include <openssl/err.h>
@@ -110,7 +111,6 @@
 long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a)
 {
     int neg = 0, i;
-    long r = 0;
 
     if (a == NULL)
         return (0L);
@@ -120,20 +120,31 @@
     else if (i != V_ASN1_ENUMERATED)
         return -1;
 
-    if (a->length > (int)sizeof(long)) {
-        /* hmm... a bit ugly */
-        return (0xffffffffL);
-    }
-    if (a->data == NULL)
-        return 0;
+    OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
+                           long_larger_than_uint64_t);
 
-    for (i = 0; i < a->length; i++) {
-        r <<= 8;
-        r |= (unsigned char)a->data[i];
+    if (a->length > (int)sizeof(uint64_t)) {
+        /* hmm... a bit ugly */
+        return -1;
     }
+
+    uint64_t r64 = 0;
+    if (a->data != NULL) {
+      for (i = 0; i < a->length; i++) {
+          r64 <<= 8;
+          r64 |= (unsigned char)a->data[i];
+      }
+
+      if (r64 > LONG_MAX) {
+          return -1;
+      }
+    }
+
+    long r = (long) r64;
     if (neg)
         r = -r;
-    return (r);
+
+    return r;
 }
 
 ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai)
diff --git a/crypto/asn1/a_int.c b/crypto/asn1/a_int.c
index 617ba96..8a4edd6 100644
--- a/crypto/asn1/a_int.c
+++ b/crypto/asn1/a_int.c
@@ -57,6 +57,7 @@
 #include <openssl/asn1.h>
 
 #include <string.h>
+#include <limits.h>
 
 #include <openssl/err.h>
 #include <openssl/mem.h>
@@ -385,7 +386,6 @@
 long ASN1_INTEGER_get(const ASN1_INTEGER *a)
 {
     int neg = 0, i;
-    long r = 0;
 
     if (a == NULL)
         return (0L);
@@ -395,20 +395,31 @@
     else if (i != V_ASN1_INTEGER)
         return -1;
 
-    if (a->length > (int)sizeof(long)) {
+    OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long),
+                           long_larger_than_uint64_t);
+
+    if (a->length > (int)sizeof(uint64_t)) {
         /* hmm... a bit ugly, return all ones */
         return -1;
     }
-    if (a->data == NULL)
-        return 0;
 
-    for (i = 0; i < a->length; i++) {
-        r <<= 8;
-        r |= (unsigned char)a->data[i];
+    uint64_t r64 = 0;
+    if (a->data != NULL) {
+      for (i = 0; i < a->length; i++) {
+          r64 <<= 8;
+          r64 |= (unsigned char)a->data[i];
+      }
+
+      if (r64 > LONG_MAX) {
+          return -1;
+      }
     }
+
+    long r = (long) r64;
     if (neg)
         r = -r;
-    return (r);
+
+    return r;
 }
 
 ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai)