| Index: nss/lib/util/quickder.c
|
| diff --git a/nss/lib/util/quickder.c b/nss/lib/util/quickder.c
|
| index 6f518ddfd172e5236052e6dec0c42e7fa4c0a11a..f9776bb9d581c8e816204651545b26fa2aff3ef8 100644
|
| --- a/nss/lib/util/quickder.c
|
| +++ b/nss/lib/util/quickder.c
|
| @@ -16,55 +16,110 @@
|
| */
|
|
|
| static unsigned char* definite_length_decoder(const unsigned char *buf,
|
| - const unsigned int length,
|
| - unsigned int *data_length,
|
| + const unsigned int buf_length,
|
| + unsigned int *out_data_length,
|
| PRBool includeTag)
|
| {
|
| unsigned char tag;
|
| - unsigned int used_length= 0;
|
| - unsigned int data_len;
|
| + unsigned int used_length = 0;
|
| + unsigned int data_length = 0;
|
| + unsigned char length_field_len = 0;
|
| + unsigned char byte;
|
| + unsigned int i;
|
|
|
| - if (used_length >= length)
|
| + if (used_length >= buf_length)
|
| {
|
| + /* Tag field was not found! */
|
| return NULL;
|
| }
|
| tag = buf[used_length++];
|
|
|
| - /* blow out when we come to the end */
|
| if (tag == 0)
|
| {
|
| + /* End-of-contents octects should not be present in DER because
|
| + DER doesn't use the indefinite length form. */
|
| return NULL;
|
| }
|
|
|
| - if (used_length >= length)
|
| + if ((tag & 0x1F) == 0x1F)
|
| {
|
| + /* High tag number (a tag number > 30) is not supported */
|
| return NULL;
|
| }
|
| - data_len = buf[used_length++];
|
|
|
| - if (data_len&0x80)
|
| + if (used_length >= buf_length)
|
| {
|
| - int len_count = data_len & 0x7f;
|
| + /* Length field was not found! */
|
| + return NULL;
|
| + }
|
| + byte = buf[used_length++];
|
|
|
| - data_len = 0;
|
| + if (!(byte & 0x80))
|
| + {
|
| + /* Short form: The high bit is not set. */
|
| + data_length = byte; /* clarity; we're returning a 32-bit int. */
|
| + }
|
| + else
|
| + {
|
| + /* Long form. Extract the field length */
|
| + length_field_len = byte & 0x7F;
|
| + if (length_field_len == 0)
|
| + {
|
| + /* DER doesn't use the indefinite length form. */
|
| + return NULL;
|
| + }
|
| +
|
| + if (length_field_len > sizeof(data_length))
|
| + {
|
| + /* We don't support an extended length field longer than
|
| + 4 bytes (2^32) */
|
| + return NULL;
|
| + }
|
|
|
| - while (len_count-- > 0)
|
| + if (length_field_len > (buf_length - used_length))
|
| {
|
| - if (used_length >= length)
|
| + /* Extended length field was not found */
|
| + return NULL;
|
| + }
|
| +
|
| + /* Iterate across the extended length field */
|
| + for (i = 0; i < length_field_len; i++)
|
| + {
|
| + byte = buf[used_length++];
|
| + data_length = (data_length << 8) | byte;
|
| +
|
| + if (i == 0)
|
| {
|
| - return NULL;
|
| + PRBool too_long = PR_FALSE;
|
| + if (length_field_len == 1)
|
| + {
|
| + too_long = ((byte & 0x80) == 0); /* Short form suffices */
|
| + }
|
| + else
|
| + {
|
| + too_long = (byte == 0); /* This zero byte can be omitted */
|
| + }
|
| + if (too_long)
|
| + {
|
| + /* The length is longer than needed. */
|
| + return NULL;
|
| + }
|
| }
|
| - data_len = (data_len << 8) | buf[used_length++];
|
| }
|
| }
|
|
|
| - if (data_len > (length-used_length) )
|
| + if (data_length > (buf_length - used_length))
|
| {
|
| + /* The decoded length exceeds the available buffer */
|
| return NULL;
|
| }
|
| - if (includeTag) data_len += used_length;
|
|
|
| - *data_length = data_len;
|
| + if (includeTag)
|
| + {
|
| + data_length += used_length;
|
| + }
|
| +
|
| + *out_data_length = data_length;
|
| return ((unsigned char*)buf + (includeTag ? 0 : used_length));
|
| }
|
|
|
|
|