security/nss/lib/util/quickder.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6     Optimized ASN.1 DER decoder
     8 */
    10 #include "secerr.h"
    11 #include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
    12 #include "secitem.h"
    14 /*
    15  * simple definite-length ASN.1 decoder
    16  */
    18 static unsigned char* definite_length_decoder(const unsigned char *buf,
    19                                               const unsigned int length,
    20                                               unsigned int *data_length,
    21                                               PRBool includeTag)
    22 {
    23     unsigned char tag;
    24     unsigned int used_length= 0;
    25     unsigned int data_len;
    27     if (used_length >= length)
    28     {
    29         return NULL;
    30     }
    31     tag = buf[used_length++];
    33     /* blow out when we come to the end */
    34     if (tag == 0)
    35     {
    36         return NULL;
    37     }
    39     if (used_length >= length)
    40     {
    41         return NULL;
    42     }
    43     data_len = buf[used_length++];
    45     if (data_len&0x80)
    46     {
    47         int  len_count = data_len & 0x7f;
    49         data_len = 0;
    51         while (len_count-- > 0)
    52         {
    53             if (used_length >= length)
    54             {
    55                 return NULL;
    56             }
    57             data_len = (data_len << 8) | buf[used_length++];
    58         }
    59     }
    61     if (data_len > (length-used_length) )
    62     {
    63         return NULL;
    64     }
    65     if (includeTag) data_len += used_length;
    67     *data_length = data_len;
    68     return ((unsigned char*)buf + (includeTag ? 0 : used_length));
    69 }
    71 static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
    72 {
    73     if ( (!src) || (!dest) || (!src->data && src->len) )
    74     {
    75         PORT_SetError(SEC_ERROR_INVALID_ARGS);
    76         return SECFailure;
    77     }
    79     if (!src->len)
    80     {
    81         /* reaching the end of the buffer is not an error */
    82         dest->data = NULL;
    83         dest->len = 0;
    84         return SECSuccess;
    85     }
    87     dest->data = definite_length_decoder(src->data,  src->len, &dest->len,
    88         includeTag);
    89     if (dest->data == NULL)
    90     {
    91         PORT_SetError(SEC_ERROR_BAD_DER);
    92         return SECFailure;
    93     }
    94     src->len -= (dest->data - src->data) + dest->len;
    95     src->data = dest->data + dest->len;
    96     return SECSuccess;
    97 }
    99 /* check if the actual component's type matches the type in the template */
   101 static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
   102                                     SECItem* item, PRBool* match, void* dest)
   103 {
   104     unsigned long kind = 0;
   105     unsigned char tag = 0;
   107     if ( (!item) || (!item->data && item->len) || (!templateEntry) || (!match) )
   108     {
   109         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   110         return SECFailure;
   111     }
   113     if (!item->len)
   114     {
   115         *match = PR_FALSE;
   116         return SECSuccess;
   117     }
   119     kind = templateEntry->kind;
   120     tag = *(unsigned char*) item->data;
   122     if ( ( (kind & SEC_ASN1_INLINE) ||
   123            (kind & SEC_ASN1_POINTER) ) &&
   124            (0 == (kind & SEC_ASN1_TAG_MASK) ) )
   125     {
   126         /* These cases are special because the template's "kind" does not
   127            give us the information for the ASN.1 tag of the next item. It can
   128            only be figured out from the subtemplate. */
   129         if (!(kind & SEC_ASN1_OPTIONAL))
   130         {
   131             /* This is a required component. If there is a type mismatch,
   132                the decoding of the subtemplate will fail, so assume this
   133                is a match at the parent level and let it fail later. This
   134                avoids a redundant check in matching cases */
   135             *match = PR_TRUE;
   136             return SECSuccess;
   137         }
   138         else
   139         {
   140             /* optional component. This is the hard case. Now we need to
   141                look at the subtemplate to get the expected kind */
   142             const SEC_ASN1Template* subTemplate = 
   143                 SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
   144             if (!subTemplate)
   145             {
   146                 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
   147                 return SECFailure;
   148             }
   149             if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
   150                  (subTemplate->kind & SEC_ASN1_POINTER) )
   151             {
   152                 /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
   153                    otherwise you may get a false positive due to the recursion
   154                    optimization above that always matches the type if the
   155                    component is required . Nesting these should never be
   156                    required, so that no one should miss this ability */
   157                 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
   158                 return SECFailure;
   159             }
   160             return MatchComponentType(subTemplate, item, match,
   161                                       (void*)((char*)dest + templateEntry->offset));
   162         }
   163     }
   165     if (kind & SEC_ASN1_CHOICE)
   166     {
   167         /* we need to check the component's tag against each choice's tag */
   168         /* XXX it would be nice to save the index of the choice here so that
   169            DecodeChoice wouldn't have to do this again. However, due to the
   170            recursivity of MatchComponentType, we don't know if we are in a
   171            required or optional component, so we can't write anywhere in
   172            the destination within this function */
   173         unsigned choiceIndex = 1;
   174         const SEC_ASN1Template* choiceEntry;
   175         while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
   176         {
   177             if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
   178                                 (void*)((char*)dest + choiceEntry->offset))) &&
   179                  (PR_TRUE == *match) )
   180             {
   181                 return SECSuccess;
   182             }
   183         }
   184 	/* no match, caller must decide if this is BAD DER, or not. */
   185         *match = PR_FALSE;
   186         return SECSuccess;
   187     }
   189     if (kind & SEC_ASN1_ANY)
   190     {
   191         /* SEC_ASN1_ANY always matches */
   192         *match = PR_TRUE;
   193         return SECSuccess;
   194     }
   196     if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
   197          (!(kind & SEC_ASN1_EXPLICIT)) &&
   198          ( ( (kind & SEC_ASN1_SAVE) ||
   199              (kind & SEC_ASN1_SKIP) ) &&
   200            (!(kind & SEC_ASN1_OPTIONAL)) 
   201          )
   202        )
   203     {
   204         /* when saving or skipping a required component,  a type is not
   205            required in the template. This is for legacy support of
   206            SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
   207            deprecate these usages and always require a type, as this
   208            disables type checking, and effectively forbids us from
   209            transparently ignoring optional components we aren't aware of */
   210         *match = PR_TRUE;
   211         return SECSuccess;
   212     }
   214     /* first, do a class check */
   215     if ( (tag & SEC_ASN1_CLASS_MASK) !=
   216          (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
   217     {
   218 #ifdef DEBUG
   219         /* this is only to help debugging of the decoder in case of problems */
   220         unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
   221         unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
   222         tagclass = tagclass;
   223         expectedclass = expectedclass;
   224 #endif
   225         *match = PR_FALSE;
   226         return SECSuccess;
   227     }
   229     /* now do a tag check */
   230     if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
   231          (tag & SEC_ASN1_TAGNUM_MASK))
   232     {
   233         *match = PR_FALSE;
   234         return SECSuccess;
   235     }
   237     /* now, do a method check. This depends on the class */
   238     switch (tag & SEC_ASN1_CLASS_MASK)
   239     {
   240     case SEC_ASN1_UNIVERSAL:
   241         /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
   242            primitive or constructed based on the tag */
   243         switch (tag & SEC_ASN1_TAGNUM_MASK)
   244         {
   245         case SEC_ASN1_SEQUENCE:
   246         case SEC_ASN1_SET:
   247         case SEC_ASN1_EMBEDDED_PDV:
   248             /* this component must be a constructed type */
   249             /* XXX add any new universal constructed type here */
   250             if (tag & SEC_ASN1_CONSTRUCTED)
   251             {
   252                 *match = PR_TRUE;
   253                 return SECSuccess;
   254             }
   255             break;
   257         default:
   258             /* this component must be a primitive type */
   259             if (! (tag & SEC_ASN1_CONSTRUCTED))
   260             {
   261                 *match = PR_TRUE;
   262                 return SECSuccess;
   263             }
   264             break;
   265         }
   266         break;
   268     default:
   269         /* for all other classes, we check the method based on the template */
   270         if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
   271              (tag & SEC_ASN1_METHOD_MASK) )
   272         {
   273             *match = PR_TRUE;
   274             return SECSuccess;
   275         }
   276         /* method does not match between template and component */
   277         break;
   278     }
   280     *match = PR_FALSE;
   281     return SECSuccess;
   282 }
   284 #ifdef DEBUG
   286 static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
   287 {
   288     SECStatus rv = SECSuccess;
   289     const SEC_ASN1Template* sequenceEntry = NULL;
   290     unsigned long seqIndex = 0;
   291     unsigned long lastEntryIndex = 0;
   292     unsigned long ambiguityIndex = 0;
   293     PRBool foundAmbiguity = PR_FALSE;
   295     do
   296     {
   297         sequenceEntry = &sequenceTemplate[seqIndex++];
   298         if (sequenceEntry->kind)
   299         {
   300             /* ensure that we don't have an optional component of SEC_ASN1_ANY
   301                in the middle of the sequence, since we could not handle it */
   302             /* XXX this function needs to dig into the subtemplates to find
   303                the next tag */
   304             if ( (PR_FALSE == foundAmbiguity) &&
   305                  (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
   306                  (sequenceEntry->kind & SEC_ASN1_ANY) )
   307             {
   308                 foundAmbiguity = PR_TRUE;
   309                 ambiguityIndex = seqIndex - 1;
   310             }
   311         }
   312     } while (sequenceEntry->kind);
   314     lastEntryIndex = seqIndex - 2;
   316     if (PR_FALSE != foundAmbiguity)
   317     {
   318         if (ambiguityIndex < lastEntryIndex)
   319         {
   320             /* ambiguity can only be tolerated on the last entry */
   321             PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
   322             rv = SECFailure;
   323         }
   324     }
   326     /* XXX also enforce ASN.1 requirement that tags be
   327        distinct for consecutive optional components */
   329     return rv;
   330 }
   332 #endif
   334 static SECStatus DecodeItem(void* dest,
   335                      const SEC_ASN1Template* templateEntry,
   336                      SECItem* src, PLArenaPool* arena, PRBool checkTag);
   338 static SECStatus DecodeSequence(void* dest,
   339                      const SEC_ASN1Template* templateEntry,
   340                      SECItem* src, PLArenaPool* arena)
   341 {
   342     SECStatus rv = SECSuccess;
   343     SECItem source;
   344     SECItem sequence;
   345     const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
   346     const SEC_ASN1Template* sequenceEntry = NULL;
   347     unsigned long seqindex = 0;
   349 #ifdef DEBUG
   350     /* for a sequence, we need to validate the template. */
   351     rv = CheckSequenceTemplate(sequenceTemplate);
   352 #endif
   354     source = *src;
   356     /* get the sequence */
   357     if (SECSuccess == rv)
   358     {
   359         rv = GetItem(&source, &sequence, PR_FALSE);
   360     }
   362     /* process it */
   363     if (SECSuccess == rv)
   364     do
   365     {
   366         sequenceEntry = &sequenceTemplate[seqindex++];
   367         if ( (sequenceEntry && sequenceEntry->kind) &&
   368              (sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
   369         {
   370             rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
   371         }
   372     } while ( (SECSuccess == rv) &&
   373               (sequenceEntry->kind &&
   374                sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
   375     /* we should have consumed all the bytes in the sequence by now
   376        unless the caller doesn't care about the rest of the sequence */
   377     if (SECSuccess == rv && sequence.len &&
   378         sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
   379     {
   380         /* it isn't 100% clear whether this is a bad DER or a bad template.
   381            The problem is that logically, they don't match - there is extra
   382            data in the DER that the template doesn't know about */
   383         PORT_SetError(SEC_ERROR_BAD_DER);
   384         rv = SECFailure;
   385     }
   387     return rv;
   388 }
   390 static SECStatus DecodeInline(void* dest,
   391                      const SEC_ASN1Template* templateEntry,
   392                      SECItem* src, PLArenaPool* arena, PRBool checkTag)
   393 {
   394     const SEC_ASN1Template* inlineTemplate = 
   395         SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
   396     return DecodeItem((void*)((char*)dest + templateEntry->offset),
   397                             inlineTemplate, src, arena, checkTag);
   398 }
   400 static SECStatus DecodePointer(void* dest,
   401                      const SEC_ASN1Template* templateEntry,
   402                      SECItem* src, PLArenaPool* arena, PRBool checkTag)
   403 {
   404     const SEC_ASN1Template* ptrTemplate = 
   405         SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
   406     void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
   407     *(void**)((char*)dest + templateEntry->offset) = subdata;
   408     if (subdata)
   409     {
   410         return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
   411     }
   412     else
   413     {
   414         PORT_SetError(SEC_ERROR_NO_MEMORY);
   415         return SECFailure;
   416     }
   417 }
   419 static SECStatus DecodeImplicit(void* dest,
   420                      const SEC_ASN1Template* templateEntry,
   421                      SECItem* src, PLArenaPool* arena)
   422 {
   423     if (templateEntry->kind & SEC_ASN1_POINTER)
   424     {
   425         return DecodePointer((void*)((char*)dest ),
   426                              templateEntry, src, arena, PR_FALSE);
   427     }
   428     else
   429     {
   430         return DecodeInline((void*)((char*)dest ),
   431                              templateEntry, src, arena, PR_FALSE);
   432     }
   433 }
   435 static SECStatus DecodeChoice(void* dest,
   436                      const SEC_ASN1Template* templateEntry,
   437                      SECItem* src, PLArenaPool* arena)
   438 {
   439     SECStatus rv = SECSuccess;
   440     SECItem choice;
   441     const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
   442     const SEC_ASN1Template* choiceEntry = NULL;
   443     unsigned long choiceindex = 0;
   445     /* XXX for a choice component, we should validate the template to make
   446        sure the tags are distinct, in debug builds. This hasn't been
   447        implemented yet */
   448     /* rv = CheckChoiceTemplate(sequenceTemplate); */
   450     /* process it */
   451     do
   452     {
   453         choice = *src;
   454         choiceEntry = &choiceTemplate[choiceindex++];
   455         if (choiceEntry->kind)
   456         {
   457             rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
   458         }
   459     } while ( (SECFailure == rv) && (choiceEntry->kind));
   461     if (SECFailure == rv)
   462     {
   463         /* the component didn't match any of the choices */
   464         PORT_SetError(SEC_ERROR_BAD_DER);
   465     }
   466     else
   467     {
   468         /* set the type in the union here */
   469         int *which = (int *)((char *)dest + templateEntry->offset);
   470         *which = (int)choiceEntry->size;
   471     }
   473     /* we should have consumed all the bytes by now */
   474     /* fail if we have not */
   475     if (SECSuccess == rv && choice.len)
   476     {
   477         /* there is extra data that isn't listed in the template */
   478         PORT_SetError(SEC_ERROR_BAD_DER);
   479         rv = SECFailure;
   480     }
   481     return rv;
   482 }
   484 static SECStatus DecodeGroup(void* dest,
   485                      const SEC_ASN1Template* templateEntry,
   486                      SECItem* src, PLArenaPool* arena)
   487 {
   488     SECStatus rv = SECSuccess;
   489     SECItem source;
   490     SECItem group;
   491     PRUint32 totalEntries = 0;
   492     PRUint32 entryIndex = 0;
   493     void** entries = NULL;
   495     const SEC_ASN1Template* subTemplate =
   496         SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
   498     source = *src;
   500     /* get the group */
   501     if (SECSuccess == rv)
   502     {
   503         rv = GetItem(&source, &group, PR_FALSE);
   504     }
   506     /* XXX we should check the subtemplate in debug builds */
   507     if (SECSuccess == rv)
   508     {
   509         /* first, count the number of entries. Benchmarking showed that this
   510            counting pass is more efficient than trying to allocate entries as
   511            we read the DER, even if allocating many entries at a time
   512         */
   513         SECItem counter = group;
   514         do
   515         {
   516             SECItem anitem;
   517             rv = GetItem(&counter, &anitem, PR_TRUE);
   518             if (SECSuccess == rv && (anitem.len) )
   519             {
   520                 totalEntries++;
   521             }
   522         }  while ( (SECSuccess == rv) && (counter.len) );
   524         if (SECSuccess == rv)
   525         {
   526             /* allocate room for pointer array and entries */
   527             /* we want to allocate the array even if there is 0 entry */
   528             entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
   529                                           (totalEntries + 1 ) + /* the extra one is for NULL termination */
   530                                           subTemplate->size*totalEntries); 
   532             if (entries)
   533             {
   534                 entries[totalEntries] = NULL; /* terminate the array */
   535             }
   536             else
   537             {
   538                 PORT_SetError(SEC_ERROR_NO_MEMORY);
   539                 rv = SECFailure;
   540             }
   541             if (SECSuccess == rv)
   542             {
   543                 void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
   544                 /* and fix the pointers in the array */
   545                 PRUint32 entriesIndex = 0;
   546                 for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
   547                 {
   548                     entries[entriesIndex] =
   549                         (char*)entriesData + (subTemplate->size*entriesIndex);
   550                 }
   551             }
   552         }
   553     }
   555     if (SECSuccess == rv && totalEntries)
   556     do
   557     {
   558         if (!(entryIndex<totalEntries))
   559         {
   560             rv = SECFailure;
   561             break;
   562         }
   563         rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
   564     } while ( (SECSuccess == rv) && (group.len) );
   565     /* we should be at the end of the set by now */    
   566     /* save the entries where requested */
   567     memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
   569     return rv;
   570 }
   572 static SECStatus DecodeExplicit(void* dest,
   573                      const SEC_ASN1Template* templateEntry,
   574                      SECItem* src, PLArenaPool* arena)
   575 {
   576     SECStatus rv = SECSuccess;
   577     SECItem subItem;
   578     SECItem constructed = *src;
   580     rv = GetItem(&constructed, &subItem, PR_FALSE);
   582     if (SECSuccess == rv)
   583     {
   584         if (templateEntry->kind & SEC_ASN1_POINTER)
   585         {
   586             rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
   587         }
   588         else
   589         {
   590             rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
   591         }
   592     }
   594     return rv;
   595 }
   597 /* new decoder implementation. This is a recursive function */
   599 static SECStatus DecodeItem(void* dest,
   600                      const SEC_ASN1Template* templateEntry,
   601                      SECItem* src, PLArenaPool* arena, PRBool checkTag)
   602 {
   603     SECStatus rv = SECSuccess;
   604     SECItem temp;
   605     SECItem mark;
   606     PRBool pop = PR_FALSE;
   607     PRBool decode = PR_TRUE;
   608     PRBool save = PR_FALSE;
   609     unsigned long kind;
   610     PRBool match = PR_TRUE;
   611     PRBool optional = PR_FALSE;
   613     PR_ASSERT(src && dest && templateEntry && arena);
   614 #if 0
   615     if (!src || !dest || !templateEntry || !arena)
   616     {
   617         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   618         rv = SECFailure;
   619     }
   620 #endif
   622     if (SECSuccess == rv)
   623     {
   624         /* do the template validation */
   625         kind = templateEntry->kind;
   626         optional = (0 != (kind & SEC_ASN1_OPTIONAL));
   627         if (!kind)
   628         {
   629             PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
   630             rv = SECFailure;
   631         }
   632     }
   634     if (SECSuccess == rv)
   635     {
   636 #ifdef DEBUG
   637         if (kind & SEC_ASN1_DEBUG_BREAK)
   638         {
   639             /* when debugging the decoder or a template that fails to
   640             decode, put SEC_ASN1_DEBUG in the component that gives you
   641             trouble. The decoder will then get to this block and assert.
   642             If you want to debug the rest of the code, you can set a
   643             breakpoint and set dontassert to PR_TRUE, which will let
   644             you skip over the assert and continue the debugging session
   645             past it. */
   646             PRBool dontassert = PR_FALSE;
   647             PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
   648         }
   649 #endif
   651         if ((kind & SEC_ASN1_SKIP) ||
   652             (kind & SEC_ASN1_SAVE))
   653         {
   654             /* if skipping or saving this component, don't decode it */
   655             decode = PR_FALSE;
   656         }
   658         if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
   659         {
   660             /* if saving this component, or if it is optional, we may not want to
   661                move past it, so save the position in case we have to rewind */
   662             mark = *src;
   663             if (kind & SEC_ASN1_SAVE)
   664             {
   665                 save = PR_TRUE;
   666                 if (0 == (kind & SEC_ASN1_SKIP))
   667                 {
   668                     /* we will for sure have to rewind when saving this
   669                        component and not skipping it. This is true for all
   670                        legacy uses of SEC_ASN1_SAVE where the following entry
   671                        in the template would causes the same component to be
   672                        processed again */
   673                     pop = PR_TRUE;
   674                 }
   675             }
   676         }
   678         rv = GetItem(src, &temp, PR_TRUE);
   679     }
   681     if (SECSuccess == rv)
   682     {
   683         /* now check if the component matches what we expect in the template */
   685         if (PR_TRUE == checkTag)
   687         {
   688             rv = MatchComponentType(templateEntry, &temp, &match, dest);
   689         }
   691         if ( (SECSuccess == rv) && (PR_TRUE != match) )
   692         {
   693             if (kind & SEC_ASN1_OPTIONAL)
   694             {
   696                 /* the optional component is missing. This is not fatal. */
   697                 /* Rewind, don't decode, and don't save */
   698                 pop = PR_TRUE;
   699                 decode = PR_FALSE;
   700                 save = PR_FALSE;
   701             }
   702             else
   703             {
   704                 /* a required component is missing. abort */
   705                 PORT_SetError(SEC_ERROR_BAD_DER);
   706                 rv = SECFailure;
   707             }
   708         }
   709     }
   711     if ((SECSuccess == rv) && (PR_TRUE == decode))
   712     {
   713         /* the order of processing here is is the tricky part */
   714         /* we start with our special cases */
   715         /* first, check the component class */
   716         if (kind & SEC_ASN1_INLINE)
   717         {
   718             /* decode inline template */
   719             rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
   720         }
   722         else
   723         if (kind & SEC_ASN1_EXPLICIT)
   724         {
   725             rv = DecodeExplicit(dest, templateEntry, &temp, arena);
   726         }
   727         else
   728         if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
   730               (!(kind & SEC_ASN1_EXPLICIT)))
   731         {
   733             /* decode implicitly tagged components */
   734             rv = DecodeImplicit(dest, templateEntry, &temp , arena);
   735         }
   736         else
   737         if (kind & SEC_ASN1_POINTER)
   738         {
   739             rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
   740         }
   741         else
   742         if (kind & SEC_ASN1_CHOICE)
   743         {
   744             rv = DecodeChoice(dest, templateEntry, &temp, arena);
   745         }
   746         else
   747         if (kind & SEC_ASN1_ANY)
   748         {
   749             /* catch-all ANY type, don't decode */
   750             save = PR_TRUE;
   751             if (kind & SEC_ASN1_INNER)
   752             {
   753                 /* skip the tag and length */
   754                 SECItem newtemp = temp;
   755                 rv = GetItem(&newtemp, &temp, PR_FALSE);
   756             }
   757         }
   758         else
   759         if (kind & SEC_ASN1_GROUP)
   760         {
   761             if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
   762                  (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
   763             {
   764                 rv = DecodeGroup(dest, templateEntry, &temp , arena);
   765             }
   766             else
   767             {
   768                 /* a group can only be a SET OF or SEQUENCE OF */
   769                 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
   770                 rv = SECFailure;
   771             }
   772         }
   773         else
   774         if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
   775         {
   776             /* plain SEQUENCE */
   777             rv = DecodeSequence(dest, templateEntry, &temp , arena);
   778         }
   779         else
   780         {
   781             /* handle all other types as "save" */
   782             /* we should only get here for primitive universal types */
   783             SECItem newtemp = temp;
   784             rv = GetItem(&newtemp, &temp, PR_FALSE);
   785             save = PR_TRUE;
   786             if ((SECSuccess == rv) &&
   787                 SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
   788             {
   789                 unsigned long tagnum = kind & SEC_ASN1_TAGNUM_MASK;
   790                 if ( temp.len == 0 && (tagnum == SEC_ASN1_BOOLEAN ||
   791                                        tagnum == SEC_ASN1_INTEGER ||
   792                                        tagnum == SEC_ASN1_BIT_STRING ||
   793                                        tagnum == SEC_ASN1_OBJECT_ID ||
   794                                        tagnum == SEC_ASN1_ENUMERATED ||
   795                                        tagnum == SEC_ASN1_UTC_TIME ||
   796                                        tagnum == SEC_ASN1_GENERALIZED_TIME) )
   797                 {
   798                     /* these types MUST have at least one content octet */
   799                     PORT_SetError(SEC_ERROR_BAD_DER);
   800                     rv = SECFailure;
   801                 }
   802                 else
   803                 switch (tagnum)
   804                 {
   805                 /* special cases of primitive types */
   806                 case SEC_ASN1_INTEGER:
   807                     {
   808                         /* remove leading zeroes if the caller requested
   809                            siUnsignedInteger
   810                            This is to allow RSA key operations to work */
   811                         SECItem* destItem = (SECItem*) ((char*)dest +
   812                                             templateEntry->offset);
   813                         if (destItem && (siUnsignedInteger == destItem->type))
   814                         {
   815                             while (temp.len > 1 && temp.data[0] == 0)
   816                             {              /* leading 0 */
   817                                 temp.data++;
   818                                 temp.len--;
   819                             }
   820                         }
   821                         break;
   822                     }
   824                 case SEC_ASN1_BIT_STRING:
   825                     {
   826                         /* change the length in the SECItem to be the number
   827                            of bits */
   828                         temp.len = (temp.len-1)*8 - (temp.data[0] & 0x7);
   829                         temp.data++;
   830                         break;
   831                     }
   833                 default:
   834                     {
   835                         break;
   836                     }
   837                 }
   838             }
   839         }
   840     }
   842     if ((SECSuccess == rv) && (PR_TRUE == save))
   843     {
   844         SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
   845         if (destItem)
   846         {
   847             /* we leave the type alone in the destination SECItem.
   848                If part of the destination was allocated by the decoder, in
   849                cases of POINTER, SET OF and SEQUENCE OF, then type is set to
   850                siBuffer due to the use of PORT_ArenaZAlloc*/
   851             destItem->data = temp.len ? temp.data : NULL;
   852             destItem->len = temp.len;
   853         }
   854         else
   855         {
   856             PORT_SetError(SEC_ERROR_INVALID_ARGS);
   857             rv = SECFailure;
   858         }
   859     }
   861     if (PR_TRUE == pop)
   862     {
   863         /* we don't want to move ahead, so restore the position */
   864         *src = mark;
   865     }
   866     return rv;
   867 }
   869 /* the function below is the public one */
   871 SECStatus SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
   872                      const SEC_ASN1Template* templateEntry,
   873                      const SECItem* src)
   874 {
   875     SECStatus rv = SECSuccess;
   876     SECItem newsrc;
   878     if (!arena || !templateEntry || !src)
   879     {
   880         PORT_SetError(SEC_ERROR_INVALID_ARGS);
   881         rv = SECFailure;
   882     }
   884     if (SECSuccess == rv)
   885     {
   886         newsrc = *src;
   887         rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
   888         if (SECSuccess == rv && newsrc.len)
   889         {
   890             rv = SECFailure;
   891             PORT_SetError(SEC_ERROR_EXTRA_INPUT);
   892         }
   893     }
   895     return rv;
   896 }

mercurial