summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Keeler <dkeeler@mozilla.com>2016-02-18 21:57:36 +0100
committerDavid Keeler <dkeeler@mozilla.com>2016-02-18 21:57:36 +0100
commitca04fe8d9bef865684e315b3fa11e9efed730423 (patch)
tree967ada3fcf56c6e8f0c383bb2901933ee6794b48
parent5bc722815ef219d3be2287bc1b125efbf3e386c3 (diff)
downloadnss-hg-ca04fe8d9bef865684e315b3fa11e9efed730423.tar.gz
bug 1245528 - fix bugs in ASN.1 decoding, r=ryan.sleevi
-rw-r--r--lib/util/secasn1d.c49
1 files changed, 38 insertions, 11 deletions
diff --git a/lib/util/secasn1d.c b/lib/util/secasn1d.c
index 7a5bcfd03..19a96e7b0 100644
--- a/lib/util/secasn1d.c
+++ b/lib/util/secasn1d.c
@@ -14,6 +14,8 @@
#define PR_Assert sec_asn1d_Assert
#endif
+#include <limits.h>
+
#include "secasn1.h"
#include "secerr.h"
@@ -1603,8 +1605,41 @@ sec_asn1d_parse_leaf (sec_asn1d_state *state,
len--;
}
}
- PORT_Memcpy (item->data + item->len, buf, len);
- item->len += len;
+ unsigned long 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) {
+ // 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;
+ }
+ unsigned long 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 +1706,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 +2235,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;