Back to index

lightning-sunbird  0.9+nobinonly
berparse.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 #include "secutil.h"
00037 
00038 typedef enum {
00039     tagDone, lengthDone, leafDone, compositeDone,
00040     notDone,
00041     parseError, parseComplete
00042 } ParseState;
00043 
00044 typedef unsigned char Byte;
00045 typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len);
00046 typedef struct {
00047     SECArb arb;
00048     int pos;                /* length from global start to item start */
00049     SECArb *parent;
00050 } ParseStackElem;
00051 
00052 struct BERParseStr {
00053     PRArenaPool *his;
00054     PRArenaPool *mine;
00055     ParseProc proc;
00056     int stackDepth;
00057     ParseStackElem *stackPtr;
00058     ParseStackElem *stack;
00059     int pending;            /* bytes remaining to complete this part */
00060     int pos;                /* running length of consumed characters */
00061     ParseState state;
00062     PRBool keepLeaves;
00063     PRBool derOnly;
00064     BERFilterProc filter;
00065     void *filterArg;
00066     BERNotifyProc before;
00067     void *beforeArg;
00068     BERNotifyProc after;
00069     void *afterArg;
00070 };
00071 
00072 #define UNKNOWN -1
00073 
00074 static unsigned char NextChar(BERParse *h, unsigned char **buf, int *len)
00075 {
00076     unsigned char c = *(*buf)++;
00077     (*len)--;
00078     h->pos++;
00079     if (h->filter)
00080        (*h->filter)(h->filterArg, &c, 1);
00081     return c;
00082 }
00083 
00084 static void ParseTag(BERParse *h, unsigned char **buf, int *len)
00085 {
00086     SECArb* arb = &(h->stackPtr->arb);
00087     arb->tag = NextChar(h, buf, len);
00088 
00089     PORT_Assert(h->state == notDone);
00090 
00091   /*
00092    * NOTE: This does not handle the high-tag-number form
00093    */
00094     if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) {
00095         PORT_SetError(SEC_ERROR_BAD_DER);
00096        h->state = parseError;
00097        return;
00098     }
00099 
00100     h->pending = UNKNOWN;
00101     arb->length = UNKNOWN;
00102     if (arb->tag & DER_CONSTRUCTED) {
00103        arb->body.cons.numSubs = 0;
00104        arb->body.cons.subs = NULL;
00105     } else {
00106        arb->body.item.len = UNKNOWN;
00107        arb->body.item.data = NULL;
00108     }
00109 
00110     h->state = tagDone;
00111 }
00112 
00113 static void ParseLength(BERParse *h, unsigned char **buf, int *len)
00114 {
00115     Byte b;
00116     SECArb *arb = &(h->stackPtr->arb);
00117 
00118     PORT_Assert(h->state == notDone);
00119 
00120     if (h->pending == UNKNOWN) {
00121        b = NextChar(h, buf, len);
00122        if ((b & 0x80) == 0) {      /* short form */
00123            arb->length = b;
00124            /*
00125             * if the tag and the length are both zero bytes, then this
00126             * should be the marker showing end of list for the
00127             * indefinite length composite
00128             */
00129            if (arb->length == 0 && arb->tag == 0)
00130               h->state = compositeDone;
00131            else
00132               h->state = lengthDone;
00133            return;
00134        }
00135 
00136        h->pending = b & 0x7f;
00137        /* 0 implies this is an indefinite length */
00138        if (h->pending > 4) {
00139            PORT_SetError(SEC_ERROR_BAD_DER);
00140            h->state = parseError;
00141            return;
00142        }
00143        arb->length = 0;
00144     }
00145 
00146     while ((*len > 0) && (h->pending > 0)) {
00147        b = NextChar(h, buf, len);
00148        arb->length = (arb->length << 8) + b;
00149        h->pending--;
00150     }
00151     if (h->pending == 0) {
00152        if (h->derOnly && (arb->length == 0))
00153            h->state = parseError;
00154        else
00155            h->state = lengthDone;
00156     }
00157     return;
00158 }
00159 
00160 static void ParseLeaf(BERParse *h, unsigned char **buf, int *len)
00161 {
00162     int count;
00163     SECArb *arb = &(h->stackPtr->arb);
00164 
00165     PORT_Assert(h->state == notDone);
00166     PORT_Assert(h->pending >= 0);
00167 
00168     if (*len < h->pending)
00169        count = *len;
00170     else
00171        count = h->pending;
00172 
00173     if (h->keepLeaves)
00174        memcpy(arb->body.item.data + arb->body.item.len, *buf, count);
00175     if (h->filter)
00176        (*h->filter)(h->filterArg, *buf, count);
00177     *buf += count;
00178     *len -= count;
00179     arb->body.item.len += count;
00180     h->pending -= count;
00181     h->pos += count;
00182     if (h->pending == 0) {
00183        h->state = leafDone;
00184     }
00185     return;
00186 }
00187 
00188 static void CreateArbNode(BERParse *h)
00189 {
00190     SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
00191 
00192     *arb = h->stackPtr->arb;
00193 
00194     /* 
00195      * Special case closing the root
00196      */       
00197     if (h->stackPtr == h->stack) {
00198        PORT_Assert(arb->tag & DER_CONSTRUCTED);
00199        h->state = parseComplete;
00200     } else {
00201        SECArb *parent = h->stackPtr->parent;
00202        parent->body.cons.subs = DS_ArenaGrow(
00203            h->his, parent->body.cons.subs,
00204            (parent->body.cons.numSubs) * sizeof(SECArb*),
00205            (parent->body.cons.numSubs + 1) * sizeof(SECArb*));
00206        parent->body.cons.subs[parent->body.cons.numSubs] = arb;
00207        parent->body.cons.numSubs++;
00208        h->proc = ParseTag;
00209        h->state = notDone;
00210        h->pending = UNKNOWN;
00211     }
00212     if (h->after)
00213        (*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE);
00214 }
00215 
00216 SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len)
00217 {
00218     if (h->state == parseError) return PR_TRUE;
00219 
00220     while (len) {
00221         (*h->proc)(h, &buf, &len);
00222        if (h->state == parseComplete) {
00223            PORT_SetError(SEC_ERROR_BAD_DER);
00224            h->state = parseError;
00225            return PR_TRUE;
00226        }
00227        if (h->state == parseError) return PR_TRUE;
00228        PORT_Assert(h->state != parseComplete);
00229 
00230         if (h->state <= compositeDone) {
00231            if (h->proc == ParseTag) {
00232               PORT_Assert(h->state == tagDone);
00233               h->proc = ParseLength;
00234               h->state = notDone;
00235            } else if (h->proc == ParseLength) {
00236               SECArb *arb = &(h->stackPtr->arb);
00237               PORT_Assert(h->state == lengthDone || h->state == compositeDone);
00238 
00239               if (h->before)
00240                   (*h->before)(h->beforeArg, arb,
00241                              h->stackPtr - h->stack, PR_TRUE);
00242 
00243               /*
00244                * Check to see if this is the end of an indefinite
00245                * length composite
00246                */
00247               if (h->state == compositeDone) {
00248                   SECArb *parent = h->stackPtr->parent;
00249                   PORT_Assert(parent);
00250                   PORT_Assert(parent->tag & DER_CONSTRUCTED);
00251                   if (parent->length != 0) {
00252                      PORT_SetError(SEC_ERROR_BAD_DER);
00253                      h->state = parseError;
00254                      return PR_TRUE;
00255                   }
00256                   /*
00257                    * NOTE: This does not check for an indefinite length
00258                    * composite being contained inside a definite length
00259                    * composite. It is not clear that is legal.
00260                    */
00261                   h->stackPtr--;
00262                   CreateArbNode(h);
00263               } else {
00264                   h->stackPtr->pos = h->pos;
00265 
00266 
00267                   if (arb->tag & DER_CONSTRUCTED) {
00268                      SECArb *parent;
00269                      /*
00270                       * Make sure there is room on the stack before we
00271                       * stick anything else there.
00272                       */
00273                      PORT_Assert(h->stackPtr - h->stack < h->stackDepth);
00274                      if (h->stackPtr - h->stack == h->stackDepth - 1) {
00275                          int newDepth = h->stackDepth * 2;
00276                          h->stack = DS_ArenaGrow(h->mine, h->stack,
00277                             sizeof(ParseStackElem) * h->stackDepth,
00278                             sizeof(ParseStackElem) * newDepth);
00279                          h->stackPtr = h->stack + h->stackDepth + 1;
00280                          h->stackDepth = newDepth;
00281                      }
00282                      parent = &(h->stackPtr->arb);
00283                      h->stackPtr++;
00284                      h->stackPtr->parent = parent;
00285                      h->proc = ParseTag;
00286                      h->state = notDone;
00287                      h->pending = UNKNOWN;
00288                   } else {
00289                      if (arb->length < 0) {
00290                          PORT_SetError(SEC_ERROR_BAD_DER);
00291                          h->state = parseError;
00292                          return PR_TRUE;
00293                      }
00294                      arb->body.item.len = 0;
00295                      if (arb->length > 0 && h->keepLeaves) {
00296                          arb->body.item.data =
00297                             PORT_ArenaAlloc(h->his, arb->length);
00298                      } else {
00299                          arb->body.item.data = NULL;
00300                      }
00301                      h->proc = ParseLeaf;
00302                      h->state = notDone;
00303                      h->pending = arb->length;
00304                   }
00305               }
00306            } else {
00307               ParseStackElem *parent;
00308               PORT_Assert(h->state = leafDone);
00309               PORT_Assert(h->proc == ParseLeaf);
00310 
00311               for (;;) {
00312                   CreateArbNode(h);
00313                   if (h->stackPtr == h->stack)
00314                      break;
00315                   parent = (h->stackPtr - 1);
00316                   PORT_Assert(parent->arb.tag & DER_CONSTRUCTED);
00317                   if (parent->arb.length == 0) /* need explicit end */
00318                      break;
00319                   if (parent->pos + parent->arb.length > h->pos)
00320                      break;
00321                   if (parent->pos + parent->arb.length < h->pos) {
00322                      PORT_SetError(SEC_ERROR_BAD_DER);
00323                      h->state = parseError;
00324                      return PR_TRUE;
00325                   }
00326                   h->stackPtr = parent;
00327               }
00328            }
00329 
00330        }
00331     }
00332     return PR_FALSE;
00333 }
00334 BERParse *BER_ParseInit(PRArenaPool *arena, PRBool derOnly)
00335 {
00336     BERParse *h;
00337     PRArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00338     if (temp == NULL) {
00339        PORT_SetError(SEC_ERROR_NO_MEMORY);
00340        return NULL;
00341     }
00342     h = PORT_ArenaAlloc(temp, sizeof(BERParse));
00343     if (h == NULL) {
00344        PORT_FreeArena(temp, PR_FALSE);
00345        PORT_SetError(SEC_ERROR_NO_MEMORY);
00346        return NULL;
00347     }
00348     h->his = arena;
00349     h->mine = temp;
00350     h->proc = ParseTag;
00351     h->stackDepth = 20;
00352     h->stack = PORT_ArenaZAlloc(h->mine,
00353                            sizeof(ParseStackElem) * h->stackDepth);
00354     h->stackPtr = h->stack;
00355     h->state = notDone;
00356     h->pos = 0;
00357     h->keepLeaves = PR_TRUE;
00358     h->before = NULL;
00359     h->after = NULL;
00360     h->filter = NULL;
00361     h->derOnly = derOnly;
00362     return h;
00363 }
00364 
00365 SECArb *BER_ParseFini(BERParse *h)
00366 {
00367     PRArenaPool *myArena = h->mine;
00368     SECArb *arb;
00369 
00370     if (h->state != parseComplete) {
00371        arb = NULL;
00372     } else {
00373        arb = PORT_ArenaAlloc(h->his, sizeof(SECArb));
00374        *arb = h->stackPtr->arb;
00375     }
00376 
00377     PORT_FreeArena(myArena, PR_FALSE);
00378 
00379     return arb;
00380 }
00381 
00382 
00383 void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance)
00384 {
00385     h->filter = proc;
00386     h->filterArg = instance;
00387 }
00388 
00389 void BER_SetLeafStorage(BERParse *h, PRBool keep)
00390 {
00391     h->keepLeaves = keep;
00392 }
00393 
00394 void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance,
00395                            PRBool beforeData)
00396 {
00397     if (beforeData) {
00398        h->before = proc;
00399        h->beforeArg = instance;
00400     } else {
00401        h->after = proc;
00402        h->afterArg = instance;
00403     }
00404 }
00405 
00406 
00407