Back to index

lightning-sunbird  0.9+nobinonly
derenc.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  * Generic templates for individual/simple items.
00041  */
00042 
00043 DERTemplate SECAnyTemplate[] = {
00044     { DER_ANY,
00045          0, NULL, sizeof(SECItem) }
00046 };
00047 
00048 DERTemplate SECBitStringTemplate[] = {
00049     { DER_BIT_STRING,
00050          0, NULL, sizeof(SECItem) }
00051 };
00052 
00053 DERTemplate SECBooleanTemplate[] = {
00054     { DER_BOOLEAN,
00055          0, NULL, sizeof(SECItem) }
00056 };
00057 
00058 DERTemplate SECIA5StringTemplate[] = {
00059     { DER_IA5_STRING,
00060          0, NULL, sizeof(SECItem) }
00061 };
00062 
00063 DERTemplate SECIntegerTemplate[] = {
00064     { DER_INTEGER,
00065          0, NULL, sizeof(SECItem) }
00066 };
00067 
00068 DERTemplate SECNullTemplate[] = {
00069     { DER_NULL,
00070          0, NULL, sizeof(SECItem) }
00071 };
00072 
00073 DERTemplate SECObjectIDTemplate[] = {
00074     { DER_OBJECT_ID,
00075          0, NULL, sizeof(SECItem) }
00076 };
00077 
00078 DERTemplate SECOctetStringTemplate[] = {
00079     { DER_OCTET_STRING,
00080          0, NULL, sizeof(SECItem) }
00081 };
00082 
00083 DERTemplate SECPrintableStringTemplate[] = {
00084     { DER_PRINTABLE_STRING,
00085          0, NULL, sizeof(SECItem) }
00086 };
00087 
00088 DERTemplate SECT61StringTemplate[] = {
00089     { DER_T61_STRING,
00090          0, NULL, sizeof(SECItem) }
00091 };
00092 
00093 DERTemplate SECUTCTimeTemplate[] = {
00094     { DER_UTC_TIME,
00095          0, NULL, sizeof(SECItem) }
00096 };
00097 
00098 
00099 static int
00100 header_length(DERTemplate *dtemplate, uint32 contents_len)
00101 {
00102     uint32 len;
00103     unsigned long encode_kind, under_kind;
00104     PRBool explicit, optional, universal;
00105 
00106     encode_kind = dtemplate->kind;
00107 
00108     explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
00109     optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
00110     universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
00111               ? PR_TRUE : PR_FALSE;
00112 
00113     PORT_Assert (!(explicit && universal));      /* bad templates */
00114 
00115     if (encode_kind & DER_POINTER) {
00116        if (dtemplate->sub != NULL) {
00117            under_kind = dtemplate->sub->kind;
00118            if (universal) {
00119               encode_kind = under_kind;
00120            }
00121        } else if (universal) {
00122            under_kind = encode_kind & ~DER_POINTER;
00123        } else {
00124            under_kind = dtemplate->arg;
00125        }
00126     } else if (encode_kind & DER_INLINE) {
00127        PORT_Assert (dtemplate->sub != NULL);
00128        under_kind = dtemplate->sub->kind;
00129        if (universal) {
00130            encode_kind = under_kind;
00131        }
00132     } else if (universal) {
00133        under_kind = encode_kind;
00134     } else {
00135        under_kind = dtemplate->arg;
00136     }
00137 
00138     /* This is only used in decoding; it plays no part in encoding.  */
00139     if (under_kind & DER_DERPTR)
00140        return 0;
00141 
00142     /* No header at all for an "empty" optional.  */
00143     if ((contents_len == 0) && optional)
00144        return 0;
00145 
00146     /* And no header for a full DER_ANY.  */
00147     if (encode_kind & DER_ANY)
00148        return 0;
00149 
00150     /*
00151      * The common case: one octet for identifier and as many octets
00152      * as necessary to hold the content length.
00153      */
00154     len = 1 + DER_LengthLength(contents_len);
00155 
00156     /* Account for the explicit wrapper, if necessary.  */
00157     if (explicit) {
00158 #if 0         /*
00159                * Well, I was trying to do something useful, but these
00160                * assertions are too restrictive on valid templates.
00161                * I wanted to make sure that the top-level "kind" of
00162                * a template does not also specify DER_EXPLICIT, which
00163                * should only modify a component field.  Maybe later
00164                * I can figure out a better way to detect such a problem,
00165                * but for now I must remove these checks altogether.
00166                */
00167        /*
00168         * This modifier applies only to components of a set or sequence;
00169         * it should never be used on a set/sequence itself -- confirm.
00170         */
00171        PORT_Assert (under_kind != DER_SEQUENCE);
00172        PORT_Assert (under_kind != DER_SET);
00173 #endif
00174 
00175        len += 1 + DER_LengthLength(len + contents_len);
00176     }
00177 
00178     return len;
00179 }
00180 
00181 
00182 static uint32
00183 contents_length(DERTemplate *dtemplate, void *src)
00184 {
00185     uint32 len;
00186     unsigned long encode_kind, under_kind;
00187     PRBool universal;
00188 
00189 
00190     PORT_Assert (src != NULL);
00191 
00192     encode_kind = dtemplate->kind;
00193 
00194     universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
00195               ? PR_TRUE : PR_FALSE;
00196     encode_kind &= ~DER_OPTIONAL;
00197 
00198     if (encode_kind & DER_POINTER) {
00199        src = *(void **)src;
00200        if (src == NULL) {
00201            return 0;
00202        }
00203        if (dtemplate->sub != NULL) {
00204            dtemplate = dtemplate->sub;
00205            under_kind = dtemplate->kind;
00206            src = (void *)((char *)src + dtemplate->offset);
00207        } else if (universal) {
00208            under_kind = encode_kind & ~DER_POINTER;
00209        } else {
00210            under_kind = dtemplate->arg;
00211        }
00212     } else if (encode_kind & DER_INLINE) {
00213        PORT_Assert (dtemplate->sub != NULL);
00214        dtemplate = dtemplate->sub;
00215        under_kind = dtemplate->kind;
00216        src = (void *)((char *)src + dtemplate->offset);
00217     } else if (universal) {
00218        under_kind = encode_kind;
00219     } else {
00220        under_kind = dtemplate->arg;
00221     }
00222 
00223     /* Having any of these bits is not expected here...  */
00224     PORT_Assert ((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL
00225                             | DER_POINTER | DER_SKIP)) == 0);
00226 
00227     /* This is only used in decoding; it plays no part in encoding.  */
00228     if (under_kind & DER_DERPTR)
00229        return 0;
00230 
00231     if (under_kind & DER_INDEFINITE) {
00232        uint32 sub_len;
00233        void   **indp = *(void ***)src;
00234 
00235        if (indp == NULL)
00236            return 0;
00237 
00238        len = 0;
00239        under_kind &= ~DER_INDEFINITE;
00240 
00241        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
00242            DERTemplate *tmpt = dtemplate->sub;
00243            PORT_Assert (tmpt != NULL);
00244 
00245            for (; *indp != NULL; indp++) {
00246               void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
00247               sub_len = contents_length (tmpt, sub_src);
00248               len += sub_len + header_length (tmpt, sub_len);
00249            }
00250        } else {
00251            /*
00252             * XXX Lisa is not sure this code (for handling, for example,
00253             * DER_INDEFINITE | DER_OCTET_STRING) is right.
00254             */
00255            for (; *indp != NULL; indp++) {
00256               SECItem *item = (SECItem *)(*indp);
00257               sub_len = item->len;
00258               if (under_kind == DER_BIT_STRING) {
00259                   sub_len = (sub_len + 7) >> 3;
00260                   /* bit string contents involve an extra octet */
00261                   if (sub_len)
00262                      sub_len++;
00263               }
00264               if (under_kind != DER_ANY)
00265                   len += 1 + DER_LengthLength (sub_len);
00266            }
00267        }
00268 
00269        return len;
00270     }
00271 
00272     switch (under_kind) {
00273       case DER_SEQUENCE:
00274       case DER_SET:
00275        {
00276            DERTemplate *tmpt;
00277            void *sub_src;
00278            uint32 sub_len;
00279 
00280            len = 0;
00281            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
00282               sub_src = (void *)((char *)src + tmpt->offset);
00283               sub_len = contents_length (tmpt, sub_src);
00284               len += sub_len + header_length (tmpt, sub_len);
00285            }
00286        }
00287        break;
00288 
00289       case DER_BIT_STRING:
00290        len = (((SECItem *)src)->len + 7) >> 3;
00291        /* bit string contents involve an extra octet */
00292        if (len)
00293            len++;
00294        break;
00295 
00296       default:
00297        len = ((SECItem *)src)->len;
00298        break;
00299     }
00300 
00301     return len;
00302 }
00303 
00304 
00305 static unsigned char *
00306 der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
00307 {
00308     int header_len;
00309     uint32 contents_len;
00310     unsigned long encode_kind, under_kind;
00311     PRBool explicit, optional, universal;
00312 
00313 
00314     /*
00315      * First figure out how long the encoding will be.  Do this by
00316      * traversing the template from top to bottom and accumulating
00317      * the length of each leaf item.
00318      */
00319     contents_len = contents_length (dtemplate, src);
00320     header_len = header_length (dtemplate, contents_len);
00321 
00322     /*
00323      * Enough smarts was involved already, so that if both the
00324      * header and the contents have a length of zero, then we
00325      * are not doing any encoding for this element.
00326      */
00327     if (header_len == 0 && contents_len == 0)
00328        return buf;
00329 
00330     encode_kind = dtemplate->kind;
00331 
00332     explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
00333     optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
00334     encode_kind &= ~DER_OPTIONAL;
00335     universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
00336               ? PR_TRUE : PR_FALSE;
00337 
00338     if (encode_kind & DER_POINTER) {
00339        if (contents_len) {
00340            src = *(void **)src;
00341            PORT_Assert (src != NULL);
00342        }
00343        if (dtemplate->sub != NULL) {
00344            dtemplate = dtemplate->sub;
00345            under_kind = dtemplate->kind;
00346            if (universal) {
00347               encode_kind = under_kind;
00348            }
00349            src = (void *)((char *)src + dtemplate->offset);
00350        } else if (universal) {
00351            under_kind = encode_kind & ~DER_POINTER;
00352        } else {
00353            under_kind = dtemplate->arg;
00354        }
00355     } else if (encode_kind & DER_INLINE) {
00356        dtemplate = dtemplate->sub;
00357        under_kind = dtemplate->kind;
00358        if (universal) {
00359            encode_kind = under_kind;
00360        }
00361        src = (void *)((char *)src + dtemplate->offset);
00362     } else if (universal) {
00363        under_kind = encode_kind;
00364     } else {
00365        under_kind = dtemplate->arg;
00366     }
00367 
00368     if (explicit) {
00369        buf = DER_StoreHeader (buf, encode_kind,
00370                             (1 + DER_LengthLength(contents_len)
00371                             + contents_len));
00372        encode_kind = under_kind;
00373     }
00374 
00375     if ((encode_kind & DER_ANY) == 0) {   /* DER_ANY already contains header */
00376        buf = DER_StoreHeader (buf, encode_kind, contents_len);
00377     }
00378 
00379     /* If no real contents to encode, then we are done.  */
00380     if (contents_len == 0)
00381        return buf;
00382 
00383     if (under_kind & DER_INDEFINITE) {
00384        void **indp;
00385 
00386        indp = *(void ***)src;
00387        PORT_Assert (indp != NULL);
00388 
00389        under_kind &= ~DER_INDEFINITE;
00390        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
00391            DERTemplate *tmpt = dtemplate->sub;
00392            PORT_Assert (tmpt != NULL);
00393            for (; *indp != NULL; indp++) {
00394               void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
00395               buf = der_encode (buf, tmpt, sub_src);
00396            }
00397        } else {
00398            for (; *indp != NULL; indp++) {
00399               SECItem *item;
00400               int sub_len;
00401 
00402               item = (SECItem *)(*indp);
00403               sub_len = item->len;
00404               if (under_kind == DER_BIT_STRING) {
00405                   if (sub_len) {
00406                      int rem;
00407 
00408                      sub_len = (sub_len + 7) >> 3;
00409                      buf = DER_StoreHeader (buf, under_kind, sub_len + 1);
00410                      rem = (sub_len << 3) - item->len;
00411                      *buf++ = rem;        /* remaining bits */
00412                   } else {
00413                      buf = DER_StoreHeader (buf, under_kind, 0);
00414                   }
00415               } else if (under_kind != DER_ANY) {
00416                   buf = DER_StoreHeader (buf, under_kind, sub_len);
00417               }
00418               PORT_Memcpy (buf, item->data, sub_len);
00419               buf += sub_len;
00420            }
00421        }
00422        return buf;
00423     }
00424 
00425     switch (under_kind) {
00426       case DER_SEQUENCE:
00427       case DER_SET:
00428        {
00429            DERTemplate *tmpt;
00430            void *sub_src;
00431 
00432            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
00433               sub_src = (void *)((char *)src + tmpt->offset);
00434               buf = der_encode (buf, tmpt, sub_src);
00435            }
00436        }
00437        break;
00438 
00439       case DER_BIT_STRING:
00440        {
00441            SECItem *item;
00442            int rem;
00443 
00444            /*
00445             * The contents length includes our extra octet; subtract
00446             * it off so we just have the real string length there.
00447             */
00448            contents_len--;
00449            item = (SECItem *)src;
00450            PORT_Assert (contents_len == ((item->len + 7) >> 3));
00451            rem = (contents_len << 3) - item->len;
00452            *buf++ = rem;           /* remaining bits */
00453            PORT_Memcpy (buf, item->data, contents_len);
00454            buf += contents_len;
00455        }
00456        break;
00457 
00458       default:
00459        {
00460            SECItem *item;
00461 
00462            item = (SECItem *)src;
00463            PORT_Assert (contents_len == item->len);
00464            PORT_Memcpy (buf, item->data, contents_len);
00465            buf += contents_len;
00466        }
00467        break;
00468     }
00469 
00470     return buf;
00471 }
00472 
00473 
00474 SECStatus
00475 DER_Encode(PRArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
00476 {
00477     unsigned int contents_len, header_len;
00478 
00479     src = (void **)((char *)src + dtemplate->offset);
00480 
00481     /*
00482      * First figure out how long the encoding will be. Do this by
00483      * traversing the template from top to bottom and accumulating
00484      * the length of each leaf item.
00485      */
00486     contents_len = contents_length (dtemplate, src);
00487     header_len = header_length (dtemplate, contents_len);
00488 
00489     dest->len = contents_len + header_len;
00490 
00491     /* Allocate storage to hold the encoding */
00492     dest->data = (unsigned char*) PORT_ArenaAlloc(arena, dest->len);
00493     if (dest->data == NULL) {
00494        PORT_SetError(SEC_ERROR_NO_MEMORY);
00495        return SECFailure;
00496     }
00497 
00498     /* Now encode into the buffer */
00499     (void) der_encode (dest->data, dtemplate, src);
00500 
00501     return SECSuccess;
00502 }