X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/e0e0d90ebff497686991a933ae2f7db24e7d8e0f..07691282a056c4efea71e1e505527601e8cc166b:/OSX/libsecurity_asn1/lib/secasn1d.c diff --git a/OSX/libsecurity_asn1/lib/secasn1d.c b/OSX/libsecurity_asn1/lib/secasn1d.c index aa4e6c68..cd37fc4a 100644 --- a/OSX/libsecurity_asn1/lib/secasn1d.c +++ b/OSX/libsecurity_asn1/lib/secasn1d.c @@ -37,6 +37,7 @@ * * $Id: secasn1d.c,v 1.16 2004/05/13 15:29:13 dmitch Exp $ */ +#include #include "secasn1.h" #include "secerr.h" @@ -388,7 +389,7 @@ sec_asn1d_push_state (SEC_ASN1DecoderContext *cx, const SecAsn1Template *theTemplate, void *dest, PRBool new_depth) { - sec_asn1d_state *state, *new_state; + sec_asn1d_state *state, *new_state = NULL; state = cx->current; @@ -433,6 +434,9 @@ loser: PORT_ArenaRelease(cx->our_pool, state->our_mark); state->our_mark = NULL; } + if (new_state != NULL) { + PORT_Free(new_state); + } return NULL; } @@ -520,7 +524,8 @@ sec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth) 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 ) { @@ -579,7 +584,7 @@ sec_asn1d_init_state_based_on_template (sec_asn1d_state *state, state->dest, PR_FALSE); if (state != NULL) state = sec_asn1d_init_state_based_on_template (state, - buf /* __APPLE__ */); + buf /* __APPLE__ */, len /* __APPLE__ */); return state; } } @@ -708,7 +713,7 @@ sec_asn1d_init_state_based_on_template (sec_asn1d_state *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; @@ -722,7 +727,7 @@ sec_asn1d_init_state_based_on_template (sec_asn1d_state *state, #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 @@ -1067,7 +1072,9 @@ sec_asn1d_check_and_subtract_length (unsigned long *remaining, 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) { @@ -1083,7 +1090,8 @@ sec_asn1d_check_and_subtract_length (unsigned long *remaining, 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 ) { @@ -1206,11 +1214,12 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state, 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; } @@ -1237,7 +1246,7 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state, 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) @@ -1247,7 +1256,7 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state, */ 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 { /* @@ -1274,7 +1283,7 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state, */ 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; @@ -1425,8 +1434,10 @@ regular_string_type: 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; @@ -1508,7 +1519,7 @@ regular_string_type: 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) { /* @@ -1666,7 +1677,8 @@ sec_asn1d_reuse_encoding (sec_asn1d_state *state) * 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. @@ -1729,8 +1741,41 @@ sec_asn1d_parse_leaf (sec_asn1d_state *state, 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) @@ -1804,13 +1849,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) { - SecAsn1Item *item; - - item = (SecAsn1Item *)(state->dest); - if (item->Length) - item->Length = (item->Length << 3) - state->bit_string_unused_bits; - } return len; } @@ -1985,7 +2023,8 @@ sec_asn1d_next_substring (sec_asn1d_state *state) */ 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; @@ -2088,7 +2127,7 @@ sec_asn1d_next_in_group (sec_asn1d_state *state, 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; } @@ -2101,7 +2140,8 @@ sec_asn1d_next_in_group (sec_asn1d_state *state, */ 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; @@ -2227,7 +2267,8 @@ sec_asn1d_next_in_sequence (sec_asn1d_state *state, } 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; @@ -2282,7 +2323,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)) { dprintf("decodeError: sec_asn1d_concat_substrings align\n"); PORT_SetError (SEC_ERROR_BAD_DER); @@ -2568,7 +2609,9 @@ sec_asn1d_pop_state (sec_asn1d_state *state) } 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; @@ -2595,7 +2638,7 @@ sec_asn1d_before_choice (sec_asn1d_state *state, const char *buf /* __APPLE__ */ 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; } @@ -2608,7 +2651,9 @@ sec_asn1d_before_choice (sec_asn1d_state *state, const char *buf /* __APPLE__ */ } 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; @@ -2682,7 +2727,7 @@ sec_asn1d_during_choice (sec_asn1d_state *state, const char *buf /* __APPLE__ */ 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; } @@ -2860,7 +2905,7 @@ SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx, 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); @@ -2872,7 +2917,7 @@ SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx, 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); @@ -2892,7 +2937,7 @@ SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx, } 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); @@ -2923,10 +2968,10 @@ SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx, 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); @@ -3124,7 +3169,8 @@ SEC_ASN1DecoderStart (PRArenaPool *their_pool, void *dest, #ifdef __APPLE__ , /* only needed if first element will be SEC_ASN1_DYNAMIC */ - const char *buf + const char *buf, + size_t len /* __APPLE__ */ #endif ) { @@ -3153,7 +3199,7 @@ SEC_ASN1DecoderStart (PRArenaPool *their_pool, void *dest, 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. @@ -3227,7 +3273,7 @@ SEC_ASN1Decode (PRArenaPool *poolp, void *dest, SECStatus urv, frv; dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate, - buf /* __APPLE__ */); + buf /* __APPLE__ */, len /* __APPLE__ */); if (dcx == NULL) return SECFailure;