Back to index

lightning-sunbird  0.9+nobinonly
derdec.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 #include "secder.h"
00038 #include "secerr.h"
00039 
00040 static uint32
00041 der_indefinite_length(unsigned char *buf, unsigned char *end)
00042 {
00043     uint32 len, ret, dataLen;
00044     unsigned char tag, lenCode;
00045     int dataLenLen;
00046 
00047     len = 0;
00048     while ( 1 ) {
00049        if ((buf + 2) > end) {
00050            return(0);
00051        }
00052        
00053        tag = *buf++;
00054        lenCode = *buf++;
00055        len += 2;
00056        
00057        if ( ( tag == 0 ) && ( lenCode == 0 ) ) {
00058            return(len);
00059        }
00060        
00061        if ( lenCode == 0x80 ) {    /* indefinite length */
00062            ret = der_indefinite_length(buf, end); /* recurse to find length */
00063            if (ret == 0)
00064               return 0;
00065            len += ret;
00066            buf += ret;
00067        } else {                    /* definite length */
00068            if (lenCode & 0x80) {
00069               /* Length of data is in multibyte format */
00070               dataLenLen = lenCode & 0x7f;
00071               switch (dataLenLen) {
00072                 case 1:
00073                   dataLen = buf[0];
00074                   break;
00075                 case 2:
00076                   dataLen = (buf[0]<<8)|buf[1];
00077                   break;
00078                 case 3:
00079                   dataLen = ((unsigned long)buf[0]<<16)|(buf[1]<<8)|buf[2];
00080                   break;
00081                 case 4:
00082                   dataLen = ((unsigned long)buf[0]<<24)|
00083                      ((unsigned long)buf[1]<<16)|(buf[2]<<8)|buf[3];
00084                   break;
00085                 default:
00086                   PORT_SetError(SEC_ERROR_BAD_DER);
00087                   return SECFailure;
00088               }
00089            } else {
00090               /* Length of data is in single byte */
00091               dataLen = lenCode;
00092               dataLenLen = 0;
00093            }
00094 
00095            /* skip this item */
00096            buf = buf + dataLenLen + dataLen;
00097            len = len + dataLenLen + dataLen;
00098        }
00099     }
00100 }
00101 
00102 /*
00103 ** Capture the next thing in the buffer.
00104 ** Returns the length of the header and the length of the contents.
00105 */
00106 static SECStatus
00107 der_capture(unsigned char *buf, unsigned char *end,
00108            int *header_len_p, uint32 *contents_len_p)
00109 {
00110     unsigned char *bp;
00111     unsigned char whole_tag;
00112     uint32 contents_len;
00113     int tag_number;
00114 
00115     if ((buf + 2) > end) {
00116        *header_len_p = 0;
00117        *contents_len_p = 0;
00118        if (buf == end)
00119            return SECSuccess;
00120        return SECFailure;
00121     }
00122 
00123     bp = buf;
00124 
00125     /* Get tag and verify that it is ok. */
00126     whole_tag = *bp++;
00127     tag_number = whole_tag & DER_TAGNUM_MASK;
00128 
00129     /*
00130      * XXX This code does not (yet) handle the high-tag-number form!
00131      */
00132     if (tag_number == DER_HIGH_TAG_NUMBER) {
00133        PORT_SetError(SEC_ERROR_BAD_DER);
00134        return SECFailure;
00135     }
00136 
00137     if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
00138        /* Check that the universal tag number is one we implement.  */
00139        switch (tag_number) {
00140          case DER_BOOLEAN:
00141          case DER_INTEGER:
00142          case DER_BIT_STRING:
00143          case DER_OCTET_STRING:
00144          case DER_NULL:
00145          case DER_OBJECT_ID:
00146          case DER_SEQUENCE:
00147          case DER_SET:
00148          case DER_PRINTABLE_STRING:
00149          case DER_T61_STRING:
00150          case DER_IA5_STRING:
00151          case DER_VISIBLE_STRING:
00152          case DER_UTC_TIME:
00153          case 0:                   /* end-of-contents tag */
00154            break;
00155          default:
00156            PORT_SetError(SEC_ERROR_BAD_DER);
00157            return SECFailure;
00158        }
00159     }
00160 
00161     /*
00162      * Get first byte of length code (might contain entire length, might not).
00163      */
00164     contents_len = *bp++;
00165 
00166     /*
00167      * If the high bit is set, then the length is in multibyte format,
00168      * or the thing has an indefinite-length.
00169      */
00170     if (contents_len & 0x80) {
00171        int bytes_of_encoded_len;
00172 
00173        bytes_of_encoded_len = contents_len & 0x7f;
00174        contents_len = 0;
00175 
00176        switch (bytes_of_encoded_len) {
00177          case 4:
00178            contents_len |= *bp++;
00179            contents_len <<= 8;
00180            /* fallthru */
00181          case 3:
00182            contents_len |= *bp++;
00183            contents_len <<= 8;
00184            /* fallthru */
00185          case 2:
00186            contents_len |= *bp++;
00187            contents_len <<= 8;
00188            /* fallthru */
00189          case 1:
00190            contents_len |= *bp++;
00191            break;
00192 
00193          case 0:
00194            contents_len = der_indefinite_length (bp, end);
00195            if (contents_len)
00196               break;
00197            /* fallthru */
00198          default:
00199            PORT_SetError(SEC_ERROR_BAD_DER);
00200            return SECFailure;
00201        }
00202     }
00203 
00204     if ((bp + contents_len) > end) {
00205        /* Ran past end of buffer */
00206        PORT_SetError(SEC_ERROR_BAD_DER);
00207        return SECFailure;
00208     }
00209 
00210     *header_len_p = bp - buf;
00211     *contents_len_p = contents_len;
00212 
00213     return SECSuccess;
00214 }
00215 
00216 static unsigned char *
00217 der_decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate,
00218           unsigned char *buf, int header_len, uint32 contents_len)
00219 {
00220     unsigned char *orig_buf, *end;
00221     unsigned long encode_kind, under_kind;
00222     PRBool explicit, optional, universal, check_tag;
00223     SECItem *item;
00224     SECStatus rv;
00225     PRBool indefinite_length, explicit_indefinite_length;
00226 
00227     encode_kind = dtemplate->kind;
00228     explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
00229     optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
00230     universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
00231               ? PR_TRUE : PR_FALSE;
00232 
00233     PORT_Assert (!(explicit && universal));      /* bad templates */
00234 
00235     if (header_len == 0) {
00236        if (optional || (encode_kind & DER_ANY))
00237            return buf;
00238        PORT_SetError(SEC_ERROR_BAD_DER);
00239        return NULL;
00240     }
00241 
00242     if (encode_kind & DER_POINTER) {
00243        void *place, **placep;
00244        int offset;
00245 
00246        if (dtemplate->sub != NULL) {
00247            dtemplate = dtemplate->sub;
00248            under_kind = dtemplate->kind;
00249            if (universal) {
00250               encode_kind = under_kind;
00251            }
00252            place = PORT_ArenaZAlloc(arena, dtemplate->arg);
00253            offset = dtemplate->offset;
00254        } else {
00255            if (universal) {
00256               under_kind = encode_kind & ~DER_POINTER;
00257            } else {
00258               under_kind = dtemplate->arg;
00259            }
00260            place = PORT_ArenaZAlloc(arena, sizeof(SECItem));
00261            offset = 0;
00262        }
00263        if (place == NULL) {
00264            PORT_SetError(SEC_ERROR_NO_MEMORY);
00265            return NULL;            /* Out of memory */
00266        }
00267        placep = (void **)dest;
00268        *placep = place;
00269        dest = (void *)((char *)place + offset);
00270     } else if (encode_kind & DER_INLINE) {
00271        PORT_Assert (dtemplate->sub != NULL);
00272        dtemplate = dtemplate->sub;
00273        under_kind = dtemplate->kind;
00274        if (universal) {
00275            encode_kind = under_kind;
00276        }
00277        dest = (void *)((char *)dest + dtemplate->offset);
00278     } else if (universal) {
00279        under_kind = encode_kind;
00280     } else {
00281        under_kind = dtemplate->arg;
00282     }
00283 
00284     orig_buf = buf;
00285     end = buf + header_len + contents_len;
00286 
00287     explicit_indefinite_length = PR_FALSE;
00288 
00289     if (explicit) {
00290        /*
00291         * This tag is expected to match exactly.
00292         * (The template has all of the bits specified.)
00293         */
00294        if (*buf != (encode_kind & DER_TAG_MASK)) {
00295            if (optional)
00296               return buf;
00297            PORT_SetError(SEC_ERROR_BAD_DER);
00298            return NULL;
00299        }
00300        if ((header_len == 2) && (*(buf + 1) == 0x80))
00301            explicit_indefinite_length = PR_TRUE;
00302        buf += header_len;
00303        rv = der_capture (buf, end, &header_len, &contents_len);
00304        if (rv != SECSuccess)
00305            return NULL;
00306        if (header_len == 0) {             /* XXX is this right? */
00307            PORT_SetError(SEC_ERROR_BAD_DER);
00308            return NULL;
00309        }
00310        optional = PR_FALSE;        /* can no longer be optional */
00311        encode_kind = under_kind;
00312     }
00313 
00314     check_tag = PR_TRUE;
00315     if (encode_kind & (DER_DERPTR | DER_ANY | DER_FORCE | DER_SKIP)) {
00316        PORT_Assert ((encode_kind & DER_ANY) || !optional);
00317        encode_kind = encode_kind & (~DER_FORCE);
00318        under_kind = under_kind & (~DER_FORCE);
00319        check_tag = PR_FALSE;
00320     }
00321 
00322     if (check_tag) {
00323        PRBool wrong;
00324        unsigned char expect_tag, expect_num;
00325 
00326        /*
00327         * This tag is expected to match, but the simple types
00328         * may or may not have the constructed bit set, so we
00329         * have to have all this extra logic.
00330         */
00331        wrong = PR_TRUE;
00332        expect_tag = (unsigned char)encode_kind & DER_TAG_MASK;
00333        expect_num = expect_tag & DER_TAGNUM_MASK;
00334        if (expect_num == DER_SET || expect_num == DER_SEQUENCE) {
00335            if (*buf == (expect_tag | DER_CONSTRUCTED))
00336               wrong = PR_FALSE;
00337        } else {
00338            if (*buf == expect_tag)
00339               wrong = PR_FALSE;
00340            else if (*buf == (expect_tag | DER_CONSTRUCTED))
00341               wrong = PR_FALSE;
00342        }
00343        if (wrong) {
00344            if (optional)
00345               return buf;
00346            PORT_SetError(SEC_ERROR_BAD_DER);
00347            return NULL;
00348        }
00349     }
00350 
00351     if (under_kind & DER_DERPTR) {
00352        item = (SECItem *)dest;
00353        if (under_kind & DER_OUTER) {
00354            item->data = buf;
00355            item->len = header_len + contents_len;
00356        } else {
00357            item->data = buf + header_len;
00358            item->len = contents_len;
00359        }
00360        return orig_buf;
00361     }
00362 
00363     if (encode_kind & DER_ANY) {
00364        contents_len += header_len;
00365        header_len = 0;
00366     }
00367 
00368     if ((header_len == 2) && (*(buf + 1) == 0x80))
00369        indefinite_length = PR_TRUE;
00370     else
00371        indefinite_length = PR_FALSE;
00372 
00373     buf += header_len;
00374 
00375     if (contents_len == 0)
00376        return buf;
00377 
00378     under_kind &= ~DER_OPTIONAL;
00379 
00380     if (under_kind & DER_INDEFINITE) {
00381        int count, thing_size;
00382        unsigned char *sub_buf;
00383        DERTemplate *tmpt;
00384        void *things, **indp, ***placep;
00385 
00386        under_kind &= ~DER_INDEFINITE;
00387 
00388        /*
00389         * Count items.
00390         */
00391        count = 0;
00392        sub_buf = buf;
00393        while (sub_buf < end) {
00394            if (indefinite_length && sub_buf[0] == 0 && sub_buf[1] == 0) {
00395               break; 
00396            }
00397            rv = der_capture (sub_buf, end, &header_len, &contents_len);
00398            if (rv != SECSuccess)
00399               return NULL;
00400            count++;
00401            sub_buf += header_len + contents_len;
00402        }
00403 
00404        /*
00405         * Allocate an array of pointers to items; extra one is for a NULL.
00406         */
00407        indp = (void**)PORT_ArenaZAlloc(arena, (count + 1) * sizeof(void *));
00408        if (indp == NULL) {
00409            PORT_SetError(SEC_ERROR_NO_MEMORY);
00410            return NULL;
00411        }
00412 
00413        /*
00414         * Prepare.
00415         */
00416        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
00417            tmpt = dtemplate->sub;
00418            PORT_Assert (tmpt != NULL);
00419            thing_size = tmpt->arg;
00420            PORT_Assert (thing_size != 0);
00421        } else {
00422            tmpt = NULL;
00423            thing_size = sizeof(SECItem);
00424        }
00425 
00426        /*
00427         * Allocate the items themselves.
00428         */
00429        things = PORT_ArenaZAlloc(arena, count * thing_size);
00430        if (things == NULL) {
00431            PORT_SetError(SEC_ERROR_NO_MEMORY);
00432            return NULL;
00433        }
00434 
00435        placep = (void ***)dest;
00436        *placep = indp;
00437 
00438        while (count) {
00439            /* ignore return value because we already did whole thing above */
00440            (void) der_capture (buf, end, &header_len, &contents_len);
00441            if (tmpt != NULL) {
00442               void *sub_thing;
00443 
00444               sub_thing = (void *)((char *)things + tmpt->offset);
00445               buf = der_decode (arena, sub_thing, tmpt,
00446                               buf, header_len, contents_len);
00447               if (buf == NULL)
00448                   return NULL;
00449            } else {
00450               item = (SECItem *)things;
00451               if (under_kind == DER_ANY) {
00452                   contents_len += header_len;
00453                   header_len = 0;
00454               }
00455               buf += header_len;
00456               if (under_kind == DER_BIT_STRING) {
00457                   item->data = buf + 1;
00458                   item->len = ((contents_len - 1) << 3) - *buf;
00459               } else {
00460                   item->data = buf;
00461                   item->len = contents_len;
00462               }
00463               buf += contents_len;
00464            }
00465            *indp++ = things;
00466            things = (void *)((char *)things + thing_size);
00467            count--;
00468        }
00469 
00470        *indp = NULL;
00471 
00472        goto der_decode_done;
00473     }
00474 
00475     switch (under_kind) {
00476       case DER_SEQUENCE:
00477       case DER_SET:
00478        {
00479            DERTemplate *tmpt;
00480            void *sub_dest;
00481 
00482            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
00483               sub_dest = (void *)((char *)dest + tmpt->offset);
00484               rv = der_capture (buf, end, &header_len, &contents_len);
00485               if (rv != SECSuccess)
00486                   return NULL;
00487               buf = der_decode (arena, sub_dest, tmpt,
00488                               buf, header_len, contents_len);
00489               if (buf == NULL)
00490                   return NULL;
00491            }
00492        }
00493        break;
00494 
00495       case DER_BIT_STRING:
00496        item = (SECItem *)dest;
00497        item->data = buf + 1;
00498        item->len = ((contents_len - 1) << 3) - *buf;
00499        buf += contents_len;
00500        break;
00501 
00502       case DER_SKIP:
00503        buf += contents_len;
00504        break;
00505 
00506       default:
00507        item = (SECItem *)dest;
00508        item->data = buf;
00509        item->len = contents_len;
00510        buf += contents_len;
00511        break;
00512     }
00513 
00514 der_decode_done:
00515 
00516     if (indefinite_length && buf[0] == 0 && buf[1] == 0) {
00517        buf += 2;
00518     }
00519 
00520     if (explicit_indefinite_length && buf[0] == 0 && buf[1] == 0) {
00521        buf += 2;
00522     }
00523 
00524     return buf;
00525 }
00526 
00527 SECStatus
00528 DER_Decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate, SECItem *src)
00529 {
00530     unsigned char *buf;
00531     uint32 buf_len, contents_len;
00532     int header_len;
00533     SECStatus rv;
00534 
00535     buf = src->data;
00536     buf_len = src->len;
00537 
00538     rv = der_capture (buf, buf + buf_len, &header_len, &contents_len);
00539     if (rv != SECSuccess)
00540        return rv;
00541 
00542     dest = (void *)((char *)dest + dtemplate->offset);
00543     buf = der_decode (arena, dest, dtemplate, buf, header_len, contents_len);
00544     if (buf == NULL)
00545        return SECFailure;
00546 
00547     return SECSuccess;
00548 }
00549 
00550 SECStatus
00551 DER_Lengths(SECItem *item, int *header_len_p, uint32 *contents_len_p)
00552 {
00553     return(der_capture(item->data, &item->data[item->len], header_len_p,
00554                      contents_len_p));
00555 }