Back to index

lightning-sunbird  0.9+nobinonly
quickder.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038     Optimized ASN.1 DER decoder
00039     
00040 */
00041 
00042 #include "secerr.h"
00043 #include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
00044 #include "secitem.h"
00045 
00046 /*
00047  * simple definite-length ASN.1 decoder
00048  */
00049 
00050 static unsigned char* definite_length_decoder(const unsigned char *buf,
00051                                               const unsigned int length,
00052                                               unsigned int *data_length,
00053                                               PRBool includeTag)
00054 {
00055     unsigned char tag;
00056     unsigned int used_length= 0;
00057     unsigned int data_len;
00058 
00059     if (used_length >= length)
00060     {
00061         return NULL;
00062     }
00063     tag = buf[used_length++];
00064 
00065     /* blow out when we come to the end */
00066     if (tag == 0)
00067     {
00068         return NULL;
00069     }
00070 
00071     if (used_length >= length)
00072     {
00073         return NULL;
00074     }
00075     data_len = buf[used_length++];
00076 
00077     if (data_len&0x80)
00078     {
00079         int  len_count = data_len & 0x7f;
00080 
00081         data_len = 0;
00082 
00083         while (len_count-- > 0)
00084         {
00085             if (used_length >= length)
00086             {
00087                 return NULL;
00088             }
00089             data_len = (data_len << 8) | buf[used_length++];
00090         }
00091     }
00092 
00093     if (data_len > (length-used_length) )
00094     {
00095         return NULL;
00096     }
00097     if (includeTag) data_len += used_length;
00098 
00099     *data_length = data_len;
00100     return ((unsigned char*)buf + (includeTag ? 0 : used_length));
00101 }
00102 
00103 static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
00104 {
00105     if ( (!src) || (!dest) || (!src->data) )
00106     {
00107         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00108         return SECFailure;
00109     }
00110 
00111     if (!src->len)
00112     {
00113         /* reaching the end of the buffer is not an error */
00114         dest->data = NULL;
00115         dest->len = 0;
00116         return SECSuccess;
00117     }
00118 
00119     dest->data = definite_length_decoder(src->data,  src->len, &dest->len,
00120         includeTag);
00121     if (dest->data == NULL)
00122     {
00123         PORT_SetError(SEC_ERROR_BAD_DER);
00124         return SECFailure;
00125     }
00126     src->len -= (dest->data - src->data) + dest->len;
00127     src->data = dest->data + dest->len;
00128     return SECSuccess;
00129 }
00130 
00131 /* check if the actual component's type matches the type in the template */
00132 
00133 static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
00134                                     SECItem* item, PRBool* match, void* dest)
00135 {
00136     unsigned long kind = 0;
00137     unsigned char tag = 0;
00138 
00139     if ( (!item) || (!templateEntry) || (!match) )
00140     {
00141         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00142         return SECFailure;
00143     }
00144 
00145     if (!item->len || !item->data)
00146     {
00147         *match = PR_FALSE;
00148         return SECSuccess;
00149     }
00150 
00151     kind = templateEntry->kind;
00152     tag = *(unsigned char*) item->data;
00153 
00154     if ( ( (kind & SEC_ASN1_INLINE) ||
00155            (kind & SEC_ASN1_POINTER) ) &&
00156            (0 == (kind & SEC_ASN1_TAG_MASK) ) )
00157     {
00158         /* These cases are special because the template's "kind" does not
00159            give us the information for the ASN.1 tag of the next item. It can
00160            only be figured out from the subtemplate. */
00161         if (!(kind & SEC_ASN1_OPTIONAL))
00162         {
00163             /* This is a required component. If there is a type mismatch,
00164                the decoding of the subtemplate will fail, so assume this
00165                is a match at the parent level and let it fail later. This
00166                avoids a redundant check in matching cases */
00167             *match = PR_TRUE;
00168             return SECSuccess;
00169         }
00170         else
00171         {
00172             /* optional component. This is the hard case. Now we need to
00173                look at the subtemplate to get the expected kind */
00174             const SEC_ASN1Template* subTemplate = 
00175                 SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
00176             if (!subTemplate)
00177             {
00178                 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
00179                 return SECFailure;
00180             }
00181             if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
00182                  (subTemplate->kind & SEC_ASN1_POINTER) )
00183             {
00184                 /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
00185                    otherwise you may get a false positive due to the recursion
00186                    optimization above that always matches the type if the
00187                    component is required . Nesting these should never be
00188                    required, so that no one should miss this ability */
00189                 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
00190                 return SECFailure;
00191             }
00192             return MatchComponentType(subTemplate, item, match,
00193                                       (void*)((char*)dest + templateEntry->offset));
00194         }
00195     }
00196 
00197     if (kind & SEC_ASN1_CHOICE)
00198     {
00199         /* we need to check the component's tag against each choice's tag */
00200         /* XXX it would be nice to save the index of the choice here so that
00201            DecodeChoice wouldn't have to do this again. However, due to the
00202            recursivity of MatchComponentType, we don't know if we are in a
00203            required or optional component, so we can't write anywhere in
00204            the destination within this function */
00205         unsigned choiceIndex = 1;
00206         const SEC_ASN1Template* choiceEntry;
00207         while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
00208         {
00209             if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
00210                                 (void*)((char*)dest + choiceEntry->offset))) &&
00211                  (PR_TRUE == *match) )
00212             {
00213                 return SECSuccess;
00214             }
00215         }
00216        /* no match, caller must decide if this is BAD DER, or not. */
00217         *match = PR_FALSE;
00218         return SECSuccess;
00219     }
00220 
00221     if (kind & SEC_ASN1_ANY)
00222     {
00223         /* SEC_ASN1_ANY always matches */
00224         *match = PR_TRUE;
00225         return SECSuccess;
00226     }
00227 
00228     if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
00229          (!(kind & SEC_ASN1_EXPLICIT)) &&
00230          ( ( (kind & SEC_ASN1_SAVE) ||
00231              (kind & SEC_ASN1_SKIP) ) &&
00232            (!(kind & SEC_ASN1_OPTIONAL)) 
00233          )
00234        )
00235     {
00236         /* when saving or skipping a required component,  a type is not
00237            required in the template. This is for legacy support of
00238            SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
00239            deprecate these usages and always require a type, as this
00240            disables type checking, and effectively forbids us from
00241            transparently ignoring optional components we aren't aware of */
00242         *match = PR_TRUE;
00243         return SECSuccess;
00244     }
00245 
00246     /* first, do a class check */
00247     if ( (tag & SEC_ASN1_CLASS_MASK) !=
00248          (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
00249     {
00250 #ifdef DEBUG
00251         /* this is only to help debugging of the decoder in case of problems */
00252         unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
00253         unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
00254         tagclass = tagclass;
00255         expectedclass = expectedclass;
00256 #endif
00257         *match = PR_FALSE;
00258         return SECSuccess;
00259     }
00260 
00261     /* now do a tag check */
00262     if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
00263          (tag & SEC_ASN1_TAGNUM_MASK))
00264     {
00265         *match = PR_FALSE;
00266         return SECSuccess;
00267     }
00268 
00269     /* now, do a method check. This depends on the class */
00270     switch (tag & SEC_ASN1_CLASS_MASK)
00271     {
00272     case SEC_ASN1_UNIVERSAL:
00273         /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
00274            primitive or constructed based on the tag */
00275         switch (tag & SEC_ASN1_TAGNUM_MASK)
00276         {
00277         case SEC_ASN1_SEQUENCE:
00278         case SEC_ASN1_SET:
00279         case SEC_ASN1_EMBEDDED_PDV:
00280             /* this component must be a constructed type */
00281             /* XXX add any new universal constructed type here */
00282             if (tag & SEC_ASN1_CONSTRUCTED)
00283             {
00284                 *match = PR_TRUE;
00285                 return SECSuccess;
00286             }
00287             break;
00288 
00289         default:
00290             /* this component must be a primitive type */
00291             if (! (tag & SEC_ASN1_CONSTRUCTED))
00292             {
00293                 *match = PR_TRUE;
00294                 return SECSuccess;
00295             }
00296             break;
00297         }
00298         break;
00299 
00300     default:
00301         /* for all other classes, we check the method based on the template */
00302         if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
00303              (tag & SEC_ASN1_METHOD_MASK) )
00304         {
00305             *match = PR_TRUE;
00306             return SECSuccess;
00307         }
00308         /* method does not match between template and component */
00309         break;
00310     }
00311 
00312     *match = PR_FALSE;
00313     return SECSuccess;
00314 }
00315 
00316 #ifdef DEBUG
00317 
00318 static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
00319 {
00320     SECStatus rv = SECSuccess;
00321     const SEC_ASN1Template* sequenceEntry = NULL;
00322     unsigned long seqIndex = 0;
00323     unsigned long lastEntryIndex = 0;
00324     unsigned long ambiguityIndex = 0;
00325     PRBool foundAmbiguity = PR_FALSE;
00326 
00327     do
00328     {
00329         sequenceEntry = &sequenceTemplate[seqIndex++];
00330         if (sequenceEntry->kind)
00331         {
00332             /* ensure that we don't have an optional component of SEC_ASN1_ANY
00333                in the middle of the sequence, since we could not handle it */
00334             /* XXX this function needs to dig into the subtemplates to find
00335                the next tag */
00336             if ( (PR_FALSE == foundAmbiguity) &&
00337                  (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
00338                  (sequenceEntry->kind & SEC_ASN1_ANY) )
00339             {
00340                 foundAmbiguity = PR_TRUE;
00341                 ambiguityIndex = seqIndex - 1;
00342             }
00343         }
00344     } while (sequenceEntry->kind);
00345 
00346     lastEntryIndex = seqIndex - 2;
00347 
00348     if (PR_FALSE != foundAmbiguity)
00349     {
00350         if (ambiguityIndex < lastEntryIndex)
00351         {
00352             /* ambiguity can only be tolerated on the last entry */
00353             PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
00354             rv = SECFailure;
00355         }
00356     }
00357 
00358     /* XXX also enforce ASN.1 requirement that tags be
00359        distinct for consecutive optional components */
00360 
00361     return rv;
00362 }
00363 
00364 #endif
00365 
00366 static SECStatus DecodeItem(void* dest,
00367                      const SEC_ASN1Template* templateEntry,
00368                      SECItem* src, PRArenaPool* arena, PRBool checkTag);
00369 
00370 static SECStatus DecodeSequence(void* dest,
00371                      const SEC_ASN1Template* templateEntry,
00372                      SECItem* src, PRArenaPool* arena)
00373 {
00374     SECStatus rv = SECSuccess;
00375     SECItem source;
00376     SECItem sequence;
00377     const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
00378     const SEC_ASN1Template* sequenceEntry = NULL;
00379     unsigned long seqindex = 0;
00380 
00381 #ifdef DEBUG
00382     /* for a sequence, we need to validate the template. */
00383     rv = CheckSequenceTemplate(sequenceTemplate);
00384 #endif
00385 
00386     source = *src;
00387 
00388     /* get the sequence */
00389     if (SECSuccess == rv)
00390     {
00391         rv = GetItem(&source, &sequence, PR_FALSE);
00392     }
00393 
00394     /* process it */
00395     if (SECSuccess == rv)
00396     do
00397     {
00398         sequenceEntry = &sequenceTemplate[seqindex++];
00399         if ( (sequenceEntry && sequenceEntry->kind) &&
00400              (sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
00401         {
00402             rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
00403         }
00404     } while ( (SECSuccess == rv) &&
00405               (sequenceEntry->kind &&
00406                sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
00407     /* we should have consumed all the bytes in the sequence by now
00408        unless the caller doesn't care about the rest of the sequence */
00409     if (SECSuccess == rv && sequence.len &&
00410         sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
00411     {
00412         /* it isn't 100% clear whether this is a bad DER or a bad template.
00413            The problem is that logically, they don't match - there is extra
00414            data in the DER that the template doesn't know about */
00415         PORT_SetError(SEC_ERROR_BAD_DER);
00416         rv = SECFailure;
00417     }
00418 
00419     return rv;
00420 }
00421 
00422 static SECStatus DecodeInline(void* dest,
00423                      const SEC_ASN1Template* templateEntry,
00424                      SECItem* src, PRArenaPool* arena, PRBool checkTag)
00425 {
00426     const SEC_ASN1Template* inlineTemplate = 
00427         SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
00428     return DecodeItem((void*)((char*)dest + templateEntry->offset),
00429                             inlineTemplate, src, arena, checkTag);
00430 }
00431 
00432 static SECStatus DecodePointer(void* dest,
00433                      const SEC_ASN1Template* templateEntry,
00434                      SECItem* src, PRArenaPool* arena, PRBool checkTag)
00435 {
00436     const SEC_ASN1Template* ptrTemplate = 
00437         SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
00438     void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
00439     *(void**)((char*)dest + templateEntry->offset) = subdata;
00440     if (subdata)
00441     {
00442         return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
00443     }
00444     else
00445     {
00446         PORT_SetError(SEC_ERROR_NO_MEMORY);
00447         return SECFailure;
00448     }
00449 }
00450 
00451 static SECStatus DecodeImplicit(void* dest,
00452                      const SEC_ASN1Template* templateEntry,
00453                      SECItem* src, PRArenaPool* arena)
00454 {
00455     if (templateEntry->kind & SEC_ASN1_POINTER)
00456     {
00457         return DecodePointer((void*)((char*)dest ),
00458                              templateEntry, src, arena, PR_FALSE);
00459     }
00460     else
00461     {
00462         return DecodeInline((void*)((char*)dest ),
00463                              templateEntry, src, arena, PR_FALSE);
00464     }
00465 }
00466 
00467 static SECStatus DecodeChoice(void* dest,
00468                      const SEC_ASN1Template* templateEntry,
00469                      SECItem* src, PRArenaPool* arena)
00470 {
00471     SECStatus rv = SECSuccess;
00472     SECItem choice;
00473     const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
00474     const SEC_ASN1Template* choiceEntry = NULL;
00475     unsigned long choiceindex = 0;
00476 
00477     /* XXX for a choice component, we should validate the template to make
00478        sure the tags are distinct, in debug builds. This hasn't been
00479        implemented yet */
00480     /* rv = CheckChoiceTemplate(sequenceTemplate); */
00481 
00482     /* process it */
00483     do
00484     {
00485         choice = *src;
00486         choiceEntry = &choiceTemplate[choiceindex++];
00487         if (choiceEntry->kind)
00488         {
00489             rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
00490         }
00491     } while ( (SECFailure == rv) && (choiceEntry->kind));
00492 
00493     if (SECFailure == rv)
00494     {
00495         /* the component didn't match any of the choices */
00496         PORT_SetError(SEC_ERROR_BAD_DER);
00497     }
00498     else
00499     {
00500         /* set the type in the union here */
00501         int *which = (int *)((char *)dest + templateEntry->offset);
00502         *which = (int)choiceEntry->size;
00503     }
00504 
00505     /* we should have consumed all the bytes by now */
00506     /* fail if we have not */
00507     if (SECSuccess == rv && choice.len)
00508     {
00509         /* there is extra data that isn't listed in the template */
00510         PORT_SetError(SEC_ERROR_BAD_DER);
00511         rv = SECFailure;
00512     }
00513     return rv;
00514 }
00515 
00516 static SECStatus DecodeGroup(void* dest,
00517                      const SEC_ASN1Template* templateEntry,
00518                      SECItem* src, PRArenaPool* arena)
00519 {
00520     SECStatus rv = SECSuccess;
00521     SECItem source;
00522     SECItem group;
00523     PRUint32 totalEntries = 0;
00524     PRUint32 entryIndex = 0;
00525     void** entries = NULL;
00526 
00527     const SEC_ASN1Template* subTemplate =
00528         SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
00529 
00530     source = *src;
00531 
00532     /* get the group */
00533     if (SECSuccess == rv)
00534     {
00535         rv = GetItem(&source, &group, PR_FALSE);
00536     }
00537 
00538     /* XXX we should check the subtemplate in debug builds */
00539     if (SECSuccess == rv)
00540     {
00541         /* first, count the number of entries. Benchmarking showed that this
00542            counting pass is more efficient than trying to allocate entries as
00543            we read the DER, even if allocating many entries at a time
00544         */
00545         SECItem counter = group;
00546         do
00547         {
00548             SECItem anitem;
00549             rv = GetItem(&counter, &anitem, PR_TRUE);
00550             if (SECSuccess == rv && (anitem.len) )
00551             {
00552                 totalEntries++;
00553             }
00554         }  while ( (SECSuccess == rv) && (counter.len) );
00555 
00556         if (SECSuccess == rv)
00557         {
00558             /* allocate room for pointer array and entries */
00559             /* we want to allocate the array even if there is 0 entry */
00560             entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
00561                                           (totalEntries + 1 ) + /* the extra one is for NULL termination */
00562                                           subTemplate->size*totalEntries); 
00563 
00564             if (entries)
00565             {
00566                 entries[totalEntries] = NULL; /* terminate the array */
00567             }
00568             else
00569             {
00570                 PORT_SetError(SEC_ERROR_NO_MEMORY);
00571                 rv = SECFailure;
00572             }
00573             if (SECSuccess == rv)
00574             {
00575                 void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
00576                 /* and fix the pointers in the array */
00577                 PRUint32 entriesIndex = 0;
00578                 for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
00579                 {
00580                     entries[entriesIndex] =
00581                         (char*)entriesData + (subTemplate->size*entriesIndex);
00582                 }
00583             }
00584         }
00585     }
00586 
00587     if (SECSuccess == rv && totalEntries)
00588     do
00589     {
00590         if (!(entryIndex<totalEntries))
00591         {
00592             rv = SECFailure;
00593             break;
00594         }
00595         rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
00596     } while ( (SECSuccess == rv) && (group.len) );
00597     /* we should be at the end of the set by now */    
00598     /* save the entries where requested */
00599     memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
00600 
00601     return rv;
00602 }
00603 
00604 static SECStatus DecodeExplicit(void* dest,
00605                      const SEC_ASN1Template* templateEntry,
00606                      SECItem* src, PRArenaPool* arena)
00607 {
00608     SECStatus rv = SECSuccess;
00609     SECItem subItem;
00610     SECItem constructed = *src;
00611 
00612     rv = GetItem(&constructed, &subItem, PR_FALSE);
00613 
00614     if (SECSuccess == rv)
00615     {
00616         if (templateEntry->kind & SEC_ASN1_POINTER)
00617         {
00618             rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
00619         }
00620         else
00621         {
00622             rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
00623         }
00624     }
00625 
00626     return rv;
00627 }
00628 
00629 /* new decoder implementation. This is a recursive function */
00630 
00631 static SECStatus DecodeItem(void* dest,
00632                      const SEC_ASN1Template* templateEntry,
00633                      SECItem* src, PRArenaPool* arena, PRBool checkTag)
00634 {
00635     SECStatus rv = SECSuccess;
00636     SECItem temp;
00637     SECItem mark;
00638     PRBool pop = PR_FALSE;
00639     PRBool decode = PR_TRUE;
00640     PRBool save = PR_FALSE;
00641     unsigned long kind;
00642     PRBool match = PR_TRUE;
00643     PRBool optional = PR_FALSE;
00644 
00645     PR_ASSERT(src && dest && templateEntry && arena);
00646 #if 0
00647     if (!src || !dest || !templateEntry || !arena)
00648     {
00649         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00650         rv = SECFailure;
00651     }
00652 #endif
00653 
00654     if (SECSuccess == rv)
00655     {
00656         /* do the template validation */
00657         kind = templateEntry->kind;
00658         optional = (0 != (kind & SEC_ASN1_OPTIONAL));
00659         if (!kind)
00660         {
00661             PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
00662             rv = SECFailure;
00663         }
00664     }
00665 
00666     if (SECSuccess == rv)
00667     {
00668 #ifdef DEBUG
00669         if (kind & SEC_ASN1_DEBUG_BREAK)
00670         {
00671             /* when debugging the decoder or a template that fails to
00672             decode, put SEC_ASN1_DEBUG in the component that gives you
00673             trouble. The decoder will then get to this block and assert.
00674             If you want to debug the rest of the code, you can set a
00675             breakpoint and set dontassert to PR_TRUE, which will let
00676             you skip over the assert and continue the debugging session
00677             past it. */
00678             PRBool dontassert = PR_FALSE;
00679             PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
00680         }
00681 #endif
00682 
00683         if ((kind & SEC_ASN1_SKIP) ||
00684             (kind & SEC_ASN1_SAVE))
00685         {
00686             /* if skipping or saving this component, don't decode it */
00687             decode = PR_FALSE;
00688         }
00689     
00690         if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
00691         {
00692             /* if saving this component, or if it is optional, we may not want to
00693                move past it, so save the position in case we have to rewind */
00694             mark = *src;
00695             if (kind & SEC_ASN1_SAVE)
00696             {
00697                 save = PR_TRUE;
00698                 if (0 == (kind & SEC_ASN1_SKIP))
00699                 {
00700                     /* we will for sure have to rewind when saving this
00701                        component and not skipping it. This is true for all
00702                        legacy uses of SEC_ASN1_SAVE where the following entry
00703                        in the template would causes the same component to be
00704                        processed again */
00705                     pop = PR_TRUE;
00706                 }
00707             }
00708         }
00709 
00710         rv = GetItem(src, &temp, PR_TRUE);
00711     }
00712 
00713     if (SECSuccess == rv)
00714     {
00715         /* now check if the component matches what we expect in the template */
00716 
00717         if (PR_TRUE == checkTag)
00718 
00719         {
00720             rv = MatchComponentType(templateEntry, &temp, &match, dest);
00721         }
00722 
00723         if ( (SECSuccess == rv) && (PR_TRUE != match) )
00724         {
00725             if (kind & SEC_ASN1_OPTIONAL)
00726             {
00727 
00728                 /* the optional component is missing. This is not fatal. */
00729                 /* Rewind, don't decode, and don't save */
00730                 pop = PR_TRUE;
00731                 decode = PR_FALSE;
00732                 save = PR_FALSE;
00733             }
00734             else
00735             {
00736                 /* a required component is missing. abort */
00737                 PORT_SetError(SEC_ERROR_BAD_DER);
00738                 rv = SECFailure;
00739             }
00740         }
00741     }
00742 
00743     if ((SECSuccess == rv) && (PR_TRUE == decode))
00744     {
00745         /* the order of processing here is is the tricky part */
00746         /* we start with our special cases */
00747         /* first, check the component class */
00748         if (kind & SEC_ASN1_INLINE)
00749         {
00750             /* decode inline template */
00751             rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
00752         }
00753 
00754         else
00755         if (kind & SEC_ASN1_EXPLICIT)
00756         {
00757             rv = DecodeExplicit(dest, templateEntry, &temp, arena);
00758         }
00759         else
00760         if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
00761 
00762               (!(kind & SEC_ASN1_EXPLICIT)))
00763         {
00764 
00765             /* decode implicitly tagged components */
00766             rv = DecodeImplicit(dest, templateEntry, &temp , arena);
00767         }
00768         else
00769         if (kind & SEC_ASN1_POINTER)
00770         {
00771             rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
00772         }
00773         else
00774         if (kind & SEC_ASN1_CHOICE)
00775         {
00776             rv = DecodeChoice(dest, templateEntry, &temp, arena);
00777         }
00778         else
00779         if (kind & SEC_ASN1_ANY)
00780         {
00781             /* catch-all ANY type, don't decode */
00782             save = PR_TRUE;
00783             if (kind & SEC_ASN1_INNER)
00784             {
00785                 /* skip the tag and length */
00786                 SECItem newtemp = temp;
00787                 rv = GetItem(&newtemp, &temp, PR_FALSE);
00788             }
00789         }
00790         else
00791         if (kind & SEC_ASN1_GROUP)
00792         {
00793             if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
00794                  (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
00795             {
00796                 rv = DecodeGroup(dest, templateEntry, &temp , arena);
00797             }
00798             else
00799             {
00800                 /* a group can only be a SET OF or SEQUENCE OF */
00801                 PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
00802                 rv = SECFailure;
00803             }
00804         }
00805         else
00806         if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
00807         {
00808             /* plain SEQUENCE */
00809             rv = DecodeSequence(dest, templateEntry, &temp , arena);
00810         }
00811         else
00812         {
00813             /* handle all other types as "save" */
00814             /* we should only get here for primitive universal types */
00815             SECItem newtemp = temp;
00816             rv = GetItem(&newtemp, &temp, PR_FALSE);
00817             save = PR_TRUE;
00818             if ((SECSuccess == rv) && SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
00819             switch (kind & SEC_ASN1_TAGNUM_MASK)
00820             {
00821             /* special cases of primitive types */
00822             case SEC_ASN1_INTEGER:
00823                 {
00824                     /* remove leading zeroes if the caller requested siUnsignedInteger
00825                        This is to allow RSA key operations to work */
00826                     SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
00827                     if (destItem && (siUnsignedInteger == destItem->type))
00828                     {
00829                         while (temp.len > 1 && temp.data[0] == 0)
00830                         {              /* leading 0 */
00831                             temp.data++;
00832                             temp.len--;
00833                         }
00834                     }
00835                     break;
00836                 }
00837 
00838             case SEC_ASN1_BIT_STRING:
00839                 {
00840                     /* change the length in the SECItem to be the number of bits */
00841                     if (temp.len && temp.data)
00842                     {
00843                         temp.len = (temp.len-1)*8 - ((*(unsigned char*)temp.data) & 0x7);
00844                         temp.data = (unsigned char*)(temp.data+1);
00845                     }
00846                     break;
00847                 }
00848 
00849             default:
00850                 {
00851                     break;
00852                 }
00853             }
00854         }
00855     }
00856 
00857     if ((SECSuccess == rv) && (PR_TRUE == save))
00858     {
00859         SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
00860         if (destItem)
00861         {
00862             /* we leave the type alone in the destination SECItem.
00863                If part of the destination was allocated by the decoder, in
00864                cases of POINTER, SET OF and SEQUENCE OF, then type is set to
00865                siBuffer due to the use of PORT_ArenaZAlloc*/
00866             destItem->data = temp.data;
00867             destItem->len = temp.len;
00868         }
00869         else
00870         {
00871             PORT_SetError(SEC_ERROR_INVALID_ARGS);
00872             rv = SECFailure;
00873         }
00874     }
00875 
00876     if (PR_TRUE == pop)
00877     {
00878         /* we don't want to move ahead, so restore the position */
00879         *src = mark;
00880     }
00881     return rv;
00882 }
00883 
00884 /* the function below is the public one */
00885 
00886 SECStatus SEC_QuickDERDecodeItem(PRArenaPool* arena, void* dest,
00887                      const SEC_ASN1Template* templateEntry,
00888                      const SECItem* src)
00889 {
00890     SECStatus rv = SECSuccess;
00891     SECItem newsrc;
00892 
00893     if (!arena || !templateEntry || !src)
00894     {
00895         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00896         rv = SECFailure;
00897     }
00898 
00899     if (SECSuccess == rv)
00900     {
00901         newsrc = *src;
00902         rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
00903         if (SECSuccess == rv && newsrc.len)
00904         {
00905             rv = SECFailure;
00906             PORT_SetError(SEC_ERROR_EXTRA_INPUT);
00907         }
00908     }
00909 
00910     return rv;
00911 }
00912