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 SECStatus
00217 DER_Lengths(SECItem *item, int *header_len_p, uint32 *contents_len_p)
00218 {
00219     return(der_capture(item->data, &item->data[item->len], header_len_p,
00220                      contents_len_p));
00221 }