Index: nss/lib/util/secasn1d.c |
diff --git a/nss/lib/util/secasn1d.c b/nss/lib/util/secasn1d.c |
index 7a5bcfd03a161c62c0c52716db164ae2db859aad..7628d65a55f0bf042d4effa540d41ae479da7945 100644 |
--- a/nss/lib/util/secasn1d.c |
+++ b/nss/lib/util/secasn1d.c |
@@ -14,6 +14,8 @@ |
#define PR_Assert sec_asn1d_Assert |
#endif |
+#include <limits.h> |
+ |
#include "secasn1.h" |
#include "secerr.h" |
@@ -1593,6 +1595,7 @@ sec_asn1d_parse_leaf (sec_asn1d_state *state, |
item = (SECItem *)(state->dest); |
if (item != NULL && item->data != NULL) { |
+ unsigned long offset; |
/* Strip leading zeroes when target is unsigned integer */ |
if (state->underlying_kind == SEC_ASN1_INTEGER && /* INTEGER */ |
item->len == 0 && /* MSB */ |
@@ -1603,8 +1606,42 @@ sec_asn1d_parse_leaf (sec_asn1d_state *state, |
len--; |
} |
} |
- PORT_Memcpy (item->data + item->len, buf, len); |
- item->len += len; |
+ offset = item->len; |
+ if (state->underlying_kind == SEC_ASN1_BIT_STRING) { |
+ // The previous bit string must have no unused bits. |
+ if (item->len & 0x7) { |
+ PORT_SetError (SEC_ERROR_BAD_DER); |
+ state->top->status = decodeError; |
+ return 0; |
+ } |
+ // If this is a bit string, the length is bits, not bytes. |
+ offset = item->len >> 3; |
+ } |
+ if (state->underlying_kind == SEC_ASN1_BIT_STRING) { |
+ unsigned long len_in_bits; |
+ // Protect against overflow during the bytes-to-bits conversion. |
+ if (len >= (ULONG_MAX >> 3) + 1) { |
+ PORT_SetError (SEC_ERROR_BAD_DER); |
+ state->top->status = decodeError; |
+ return 0; |
+ } |
+ len_in_bits = (len << 3) - state->bit_string_unused_bits; |
+ // Protect against overflow when computing the total length in bits. |
+ if (UINT_MAX - item->len < len_in_bits) { |
+ PORT_SetError (SEC_ERROR_BAD_DER); |
+ state->top->status = decodeError; |
+ return 0; |
+ } |
+ item->len += len_in_bits; |
+ } else { |
+ if (UINT_MAX - item->len < len) { |
+ PORT_SetError (SEC_ERROR_BAD_DER); |
+ state->top->status = decodeError; |
+ return 0; |
+ } |
+ item->len += len; |
+ } |
+ PORT_Memcpy (item->data + offset, buf, len); |
} |
state->pending -= bufLen; |
if (state->pending == 0) |
@@ -1671,14 +1708,6 @@ sec_asn1d_parse_more_bit_string (sec_asn1d_state *state, |
} |
len = sec_asn1d_parse_leaf (state, buf, len); |
- if (state->place == beforeEndOfContents && state->dest != NULL) { |
- SECItem *item; |
- |
- item = (SECItem *)(state->dest); |
- if (item->len) |
- item->len = (item->len << 3) - state->bit_string_unused_bits; |
- } |
- |
return len; |
} |
@@ -2208,7 +2237,7 @@ sec_asn1d_concat_substrings (sec_asn1d_state *state) |
* All bit-string substrings except the last one should be |
* a clean multiple of 8 bits. |
*/ |
- if (is_bit_string && (substring->next == NULL) |
+ if (is_bit_string && (substring->next != NULL) |
&& (substring->len & 0x7)) { |
PORT_SetError (SEC_ERROR_BAD_DER); |
state->top->status = decodeError; |