]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_asn1/lib/secasn1d.c
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_asn1 / lib / secasn1d.c
index aa4e6c68f8ddf80cc9d5da863fe47547d7c4bf9c..cd37fc4abc83adaf95c7cac36f235081ae3f547e 100644 (file)
@@ -37,6 +37,7 @@
  *
  * $Id: secasn1d.c,v 1.16 2004/05/13 15:29:13 dmitch Exp $
  */
  *
  * $Id: secasn1d.c,v 1.16 2004/05/13 15:29:13 dmitch Exp $
  */
+#include <limits.h>
 
 #include "secasn1.h"
 #include "secerr.h"
 
 #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)
 {
                      const SecAsn1Template *theTemplate,
                      void *dest, PRBool new_depth)
 {
-    sec_asn1d_state *state, *new_state;
+    sec_asn1d_state *state, *new_state = NULL;
 
     state = cx->current;
 
 
     state = cx->current;
 
@@ -433,6 +434,9 @@ loser:
         PORT_ArenaRelease(cx->our_pool, state->our_mark);
         state->our_mark = NULL;
     }
         PORT_ArenaRelease(cx->our_pool, state->our_mark);
         state->our_mark = NULL;
     }
+    if (new_state != NULL) {
+        PORT_Free(new_state);
+    }
     return NULL;
 }
 
     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__
 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
        )
 {
        #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,
                                                state->dest, PR_FALSE);
                        if (state != NULL)
                                state = sec_asn1d_init_state_based_on_template (state,
-                                       buf /* __APPLE__ */);
+                                       buf /* __APPLE__ */, len /* __APPLE__ */);
                        return state;
                }
     }
                        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,
                }
                #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;
                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,
                        #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
                        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);
     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) {
         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__
 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
        )
 {
        #endif
        )
 {
@@ -1206,11 +1214,12 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state,
                                      SEC_ASN1GetSubtemplate(state->theTemplate,
                                                             state->dest,
                                                             PR_FALSE,
                                      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,
                                      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;
     }
         (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,
 
            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)
            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,
                        */
                        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 {
            /*
            }
        } 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,
             */
            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;
        }
     (void) state;
        break;
@@ -1425,8 +1434,10 @@ regular_string_type:
                    alloc_len += subitem->len;
            }
 
                    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;
                    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,
            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) {
            /*
            }
        } 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,
      * 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.
 
     /*
      * Now parse that out of our data.
@@ -1729,8 +1741,41 @@ sec_asn1d_parse_leaf (sec_asn1d_state *state,
                                len--;
                        }
                }
                                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)
     }
     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);
     }
 
     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;
 }
 
     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,
  */
 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_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_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;
 }
 
     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,
  */
 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;
 {
     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, 
        }
        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;
        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.
             */
             * 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);
                              && (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 *
 }
 
 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_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, 
        
        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;
        }
        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 *
 }
 
 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;
   
 {
   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_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;
     }
     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:
                        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);
                        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_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 duringLeaf:
                        consumed = sec_asn1d_parse_leaf (state, buf, len);
@@ -2892,7 +2937,7 @@ SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx,
                        }
                        break;
                case duringSequence:
                        }
                        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);
                        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:
                        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:
                                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);
                                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 */
                          #ifdef        __APPLE__
                          ,
                          /* only needed if first element will be SEC_ASN1_DYNAMIC */
-                         const char *buf
+                         const char *buf,
+                         size_t len /* __APPLE__ */
                          #endif        
                          )
 {
                          #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, 
 
     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.
                /*
                 * 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,
     SECStatus urv, frv;
 
     dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate,
-               buf /* __APPLE__ */);
+               buf /* __APPLE__ */, len /* __APPLE__ */);
     if (dcx == NULL)
        return SECFailure;
 
     if (dcx == NULL)
        return SECFailure;