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)