*
* $Id: secasn1d.c,v 1.16 2004/05/13 15:29:13 dmitch Exp $
*/
+#include <limits.h>
#include "secasn1.h"
#include "secerr.h"
const SecAsn1Template *theTemplate,
void *dest, PRBool new_depth)
{
- sec_asn1d_state *state, *new_state;
+ sec_asn1d_state *state, *new_state = NULL;
state = cx->current;
PORT_ArenaRelease(cx->our_pool, state->our_mark);
state->our_mark = NULL;
}
+ if (new_state != NULL) {
+ PORT_Free(new_state);
+ }
return NULL;
}
static sec_asn1d_state *
sec_asn1d_init_state_based_on_template (sec_asn1d_state *state,
#ifdef __APPLE__
- const char *buf /* for SEC_ASN1GetSubtemplate() */
+ const char *buf, /* for SEC_ASN1GetSubtemplate() */
+ size_t len
#endif
)
{
state->dest, PR_FALSE);
if (state != NULL)
state = sec_asn1d_init_state_based_on_template (state,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
return state;
}
}
}
#endif /* __APPLE__ */
subt = SEC_ASN1GetSubtemplate (state->theTemplate, subDest,
- PR_FALSE, buf /* __APPLE__ */);
+ PR_FALSE, buf /* __APPLE__ */, len /* __APPLE__ */);
state = sec_asn1d_push_state (state->top, subt, dest, PR_FALSE);
if (state == NULL)
return NULL;
#endif
) {
state = sec_asn1d_init_state_based_on_template (state,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
if (state != NULL) {
/*
* If this field is optional, we need to record that on
PORT_Assert(cx);
if (!remaining || !cx) {
PORT_SetError (SEC_ERROR_INVALID_ARGS);
- cx->status = decodeError;
+ if(cx) {
+ cx->status = decodeError;
+ }
return PR_FALSE;
}
if (*remaining < consumed) {
static void
sec_asn1d_prepare_for_contents (sec_asn1d_state *state,
#ifdef __APPLE__
- const char *buf /* needed for SEC_ASN1GetSubtemplate */
+ const char *buf, /* needed for SEC_ASN1GetSubtemplate */
+ size_t len
#endif
)
{
SEC_ASN1GetSubtemplate(state->theTemplate,
state->dest,
PR_FALSE,
- buf /* __APPLE__ */),
+ buf /* __APPLE__ */,
+ len /* __APPLE__ */),
state->dest, PR_TRUE);
if (state != NULL)
state = sec_asn1d_init_state_based_on_template (state,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
(void) state;
return;
}
state->place = duringGroup;
subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest,
- PR_FALSE, buf /* __APPLE__ */);
+ PR_FALSE, buf /* __APPLE__ */, len /* __APPLE__ */);
state = sec_asn1d_push_state (state->top, subt, NULL, PR_TRUE);
if (state != NULL) {
if (!state->top->filter_only)
*/
sec_asn1d_notify_before (state->top, state->dest, state->depth);
state = sec_asn1d_init_state_based_on_template (state,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
}
} else {
/*
*/
sec_asn1d_notify_before (state->top, state->dest, state->depth);
state = sec_asn1d_init_state_based_on_template (state,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
}
(void) state;
break;
alloc_len += subitem->len;
}
- item->Data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len);
- if (item->Data == NULL) {
+ if (item) {
+ item->Data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len);
+ }
+ if (item == NULL || item->Data == NULL) {
dprintf("decodeError: prepare for contents zalloc\n");
state->top->status = decodeError;
break;
if (state != NULL) {
state->substring = PR_TRUE; /* XXX propogate? */
state = sec_asn1d_init_state_based_on_template (state,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
}
} else if (state->indefinite) {
/*
* And initialize it so it is ready to parse.
*/
(void) sec_asn1d_init_state_based_on_template(child,
- (char *) item->Data /* __APPLE__ */);
+ (char *) item->Data /* __APPLE__ */,
+ item->Length /* __APPLE__ */);
/*
* Now parse that out of our data.
len--;
}
}
- PORT_Memcpy (item->Data + item->Length, buf, len);
- item->Length += len;
+ unsigned long offset = item->Length;
+ if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
+ // The previous bit string must have no unused bits.
+ if (item->Length & 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->Length >> 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->Length < len_in_bits) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+ item->Length += len_in_bits;
+ } else {
+ if (UINT_MAX - item->Length < len) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+ item->Length += len;
+ }
+ PORT_Memcpy (item->Data + offset, buf, len);
}
state->pending -= bufLen;
if (state->pending == 0)
}
len = sec_asn1d_parse_leaf (state, buf, len);
- if (state->place == beforeEndOfContents && state->dest != NULL) {
- SecAsn1Item *item;
-
- item = (SecAsn1Item *)(state->dest);
- if (item->Length)
- item->Length = (item->Length << 3) - state->bit_string_unused_bits;
- }
return len;
}
*/
static void
sec_asn1d_next_in_group (sec_asn1d_state *state,
- const char *buf /* __APPLE__ */)
+ const char *buf, /* __APPLE__ */
+ size_t len /* __APPLE__ */)
{
sec_asn1d_state *child;
unsigned long child_consumed;
sec_asn1d_scrub_state (child);
/* Initialize child state from the template */
- sec_asn1d_init_state_based_on_template(child, buf /* __APPLE__ */);
+ sec_asn1d_init_state_based_on_template(child, buf /* __APPLE__ */, len /* __APPLE__ */);
state->top->current = child;
}
*/
static void
sec_asn1d_next_in_sequence (sec_asn1d_state *state,
- const char *buf /* __APPLE__ */)
+ const char *buf /* __APPLE__ */,
+ size_t len /*__APPLE__*/)
{
sec_asn1d_state *child;
unsigned long child_consumed;
}
state->top->current = child;
child = sec_asn1d_init_state_based_on_template (child,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */,
+ len /* __APPLE__ */);
if (child_missing && child) {
child->place = afterIdentifier;
child->found_tag_modifiers = child_found_tag_modifiers;
* 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)) {
dprintf("decodeError: sec_asn1d_concat_substrings align\n");
PORT_SetError (SEC_ERROR_BAD_DER);
}
static sec_asn1d_state *
-sec_asn1d_before_choice (sec_asn1d_state *state, const char *buf /* __APPLE__ */)
+sec_asn1d_before_choice (sec_asn1d_state *state,
+ const char *buf /* __APPLE__ */,
+ size_t len /* __APPLE__ */)
{
sec_asn1d_state *child;
sec_asn1d_scrub_state(child);
child = sec_asn1d_init_state_based_on_template(child,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
if( (sec_asn1d_state *)NULL == child ) {
return (sec_asn1d_state *)NULL;
}
}
static sec_asn1d_state *
-sec_asn1d_during_choice (sec_asn1d_state *state, const char *buf /* __APPLE__ */)
+sec_asn1d_during_choice (sec_asn1d_state *state,
+ const char *buf, /* __APPLE__ */
+ size_t len /* __APPLE__ */)
{
sec_asn1d_state *child = state->child;
child_found_tag_modifiers = child->found_tag_modifiers;
child_found_tag_number = child->found_tag_number;
- child = sec_asn1d_init_state_based_on_template(child, buf /* __APPLE__*/);
+ child = sec_asn1d_init_state_based_on_template(child, buf /* __APPLE__*/, len /* __APPLE__ */);
if( (sec_asn1d_state *)NULL == child ) {
return (sec_asn1d_state *)NULL;
}
what = SEC_ASN1_Length;
break;
case afterLength:
- sec_asn1d_prepare_for_contents (state, buf);
+ sec_asn1d_prepare_for_contents (state, buf, len);
break;
case beforeBitString:
consumed = sec_asn1d_parse_bit_string (state, buf, len);
sec_asn1d_next_substring (state);
break;
case duringGroup:
- sec_asn1d_next_in_group (state, buf);
+ sec_asn1d_next_in_group (state, buf, len);
break;
case duringLeaf:
consumed = sec_asn1d_parse_leaf (state, buf, len);
}
break;
case duringSequence:
- sec_asn1d_next_in_sequence (state, buf);
+ sec_asn1d_next_in_sequence (state, buf, len);
break;
case afterConstructedString:
sec_asn1d_concat_substrings (state);
sec_asn1d_pop_state (state);
break;
case beforeChoice:
- state = sec_asn1d_before_choice(state, buf);
+ state = sec_asn1d_before_choice(state, buf, len);
break;
case duringChoice:
- state = sec_asn1d_during_choice(state, buf);
+ state = sec_asn1d_during_choice(state, buf, len);
break;
case afterChoice:
sec_asn1d_after_choice(state);
#ifdef __APPLE__
,
/* only needed if first element will be SEC_ASN1_DYNAMIC */
- const char *buf
+ const char *buf,
+ size_t len /* __APPLE__ */
#endif
)
{
if (sec_asn1d_push_state(cx, theTemplate, dest, PR_FALSE) == NULL
|| sec_asn1d_init_state_based_on_template (cx->current,
- buf /* __APPLE__ */) == NULL) {
+ buf /* __APPLE__ */, len /* __APPLE__ */) == NULL) {
/*
* Trouble initializing (probably due to failed allocations)
* requires that we just give up.
SECStatus urv, frv;
dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate,
- buf /* __APPLE__ */);
+ buf /* __APPLE__ */, len /* __APPLE__ */);
if (dcx == NULL)
return SECFailure;