tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

derenc.c (13549B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "secder.h"
      6 #include "secerr.h"
      7 
      8 #if 0
      9 /*
     10 * Generic templates for individual/simple items.
     11 */
     12 
     13 DERTemplate SECAnyTemplate[] = {
     14    { DER_ANY,
     15   0, NULL, sizeof(SECItem) }
     16 };
     17 
     18 DERTemplate SECBitStringTemplate[] = {
     19    { DER_BIT_STRING,
     20   0, NULL, sizeof(SECItem) }
     21 };
     22 
     23 DERTemplate SECBooleanTemplate[] = {
     24    { DER_BOOLEAN,
     25   0, NULL, sizeof(SECItem) }
     26 };
     27 
     28 DERTemplate SECIA5StringTemplate[] = {
     29    { DER_IA5_STRING,
     30   0, NULL, sizeof(SECItem) }
     31 };
     32 
     33 DERTemplate SECIntegerTemplate[] = {
     34    { DER_INTEGER,
     35   0, NULL, sizeof(SECItem) }
     36 };
     37 
     38 DERTemplate SECNullTemplate[] = {
     39    { DER_NULL,
     40   0, NULL, sizeof(SECItem) }
     41 };
     42 
     43 DERTemplate SECObjectIDTemplate[] = {
     44    { DER_OBJECT_ID,
     45   0, NULL, sizeof(SECItem) }
     46 };
     47 
     48 DERTemplate SECOctetStringTemplate[] = {
     49    { DER_OCTET_STRING,
     50   0, NULL, sizeof(SECItem) }
     51 };
     52 
     53 DERTemplate SECPrintableStringTemplate[] = {
     54    { DER_PRINTABLE_STRING,
     55   0, NULL, sizeof(SECItem) }
     56 };
     57 
     58 DERTemplate SECT61StringTemplate[] = {
     59    { DER_T61_STRING,
     60   0, NULL, sizeof(SECItem) }
     61 };
     62 
     63 DERTemplate SECUTCTimeTemplate[] = {
     64    { DER_UTC_TIME,
     65   0, NULL, sizeof(SECItem) }
     66 };
     67 
     68 #endif
     69 
     70 static int
     71 header_length(DERTemplate *dtemplate, PRUint32 contents_len)
     72 {
     73    PRUint32 len;
     74    unsigned long encode_kind, under_kind;
     75    PRBool explicit, optional, universal;
     76 
     77    encode_kind = dtemplate->kind;
     78 
     79    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
     80    optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
     81    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
     82                    ? PR_TRUE
     83                    : PR_FALSE;
     84 
     85    PORT_Assert(!(explicit && universal)); /* bad templates */
     86 
     87    if (encode_kind & DER_POINTER) {
     88        if (dtemplate->sub != NULL) {
     89            under_kind = dtemplate->sub->kind;
     90            if (universal) {
     91                encode_kind = under_kind;
     92            }
     93        } else if (universal) {
     94            under_kind = encode_kind & ~DER_POINTER;
     95        } else {
     96            under_kind = dtemplate->arg;
     97        }
     98    } else if (encode_kind & DER_INLINE) {
     99        PORT_Assert(dtemplate->sub != NULL);
    100        under_kind = dtemplate->sub->kind;
    101        if (universal) {
    102            encode_kind = under_kind;
    103        }
    104    } else if (universal) {
    105        under_kind = encode_kind;
    106    } else {
    107        under_kind = dtemplate->arg;
    108    }
    109 
    110    /* This is only used in decoding; it plays no part in encoding.  */
    111    if (under_kind & DER_DERPTR)
    112        return 0;
    113 
    114    /* No header at all for an "empty" optional.  */
    115    if ((contents_len == 0) && optional)
    116        return 0;
    117 
    118    /* And no header for a full DER_ANY.  */
    119    if (encode_kind & DER_ANY)
    120        return 0;
    121 
    122    /*
    123     * The common case: one octet for identifier and as many octets
    124     * as necessary to hold the content length.
    125     */
    126    len = 1 + DER_LengthLength(contents_len);
    127 
    128    /* Account for the explicit wrapper, if necessary.  */
    129    if (explicit) {
    130 #if 0 /*                                                         \
    131       * Well, I was trying to do something useful, but these    \
    132       * assertions are too restrictive on valid templates.      \
    133       * I wanted to make sure that the top-level "kind" of      \
    134       * a template does not also specify DER_EXPLICIT, which    \
    135       * should only modify a component field.  Maybe later      \
    136       * I can figure out a better way to detect such a problem, \
    137       * but for now I must remove these checks altogether.      \
    138       */
    139 /*
    140  * This modifier applies only to components of a set or sequence;
    141  * it should never be used on a set/sequence itself -- confirm.
    142  */
    143 PORT_Assert (under_kind != DER_SEQUENCE);
    144 PORT_Assert (under_kind != DER_SET);
    145 #endif
    146 
    147        len += 1 + DER_LengthLength(len + contents_len);
    148    }
    149 
    150    return len;
    151 }
    152 
    153 static PRUint32
    154 contents_length(DERTemplate *dtemplate, void *src)
    155 {
    156    PRUint32 len;
    157    unsigned long encode_kind, under_kind;
    158    PRBool universal;
    159 
    160    PORT_Assert(src != NULL);
    161 
    162    encode_kind = dtemplate->kind;
    163 
    164    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
    165                    ? PR_TRUE
    166                    : PR_FALSE;
    167    encode_kind &= ~DER_OPTIONAL;
    168 
    169    if (encode_kind & DER_POINTER) {
    170        src = *(void **)src;
    171        if (src == NULL) {
    172            return 0;
    173        }
    174        if (dtemplate->sub != NULL) {
    175            dtemplate = dtemplate->sub;
    176            under_kind = dtemplate->kind;
    177            src = (void *)((char *)src + dtemplate->offset);
    178        } else if (universal) {
    179            under_kind = encode_kind & ~DER_POINTER;
    180        } else {
    181            under_kind = dtemplate->arg;
    182        }
    183    } else if (encode_kind & DER_INLINE) {
    184        PORT_Assert(dtemplate->sub != NULL);
    185        dtemplate = dtemplate->sub;
    186        under_kind = dtemplate->kind;
    187        src = (void *)((char *)src + dtemplate->offset);
    188    } else if (universal) {
    189        under_kind = encode_kind;
    190    } else {
    191        under_kind = dtemplate->arg;
    192    }
    193 
    194    /* Having any of these bits is not expected here...  */
    195    PORT_Assert((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL | DER_POINTER | DER_SKIP)) == 0);
    196 
    197    /* This is only used in decoding; it plays no part in encoding.  */
    198    if (under_kind & DER_DERPTR)
    199        return 0;
    200 
    201    if (under_kind & DER_INDEFINITE) {
    202        PRUint32 sub_len;
    203        void **indp = *(void ***)src;
    204 
    205        if (indp == NULL)
    206            return 0;
    207 
    208        len = 0;
    209        under_kind &= ~DER_INDEFINITE;
    210 
    211        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
    212            DERTemplate *tmpt = dtemplate->sub;
    213            PORT_Assert(tmpt != NULL);
    214 
    215            for (; *indp != NULL; indp++) {
    216                void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
    217                sub_len = contents_length(tmpt, sub_src);
    218                len += sub_len + header_length(tmpt, sub_len);
    219            }
    220        } else {
    221            /*
    222             * XXX Lisa is not sure this code (for handling, for example,
    223             * DER_INDEFINITE | DER_OCTET_STRING) is right.
    224             */
    225            for (; *indp != NULL; indp++) {
    226                SECItem *item = (SECItem *)(*indp);
    227                sub_len = item->len;
    228                if (under_kind == DER_BIT_STRING) {
    229                    sub_len = (sub_len + 7) >> 3;
    230                    /* bit string contents involve an extra octet */
    231                    if (sub_len)
    232                        sub_len++;
    233                }
    234                if (under_kind != DER_ANY)
    235                    len += 1 + DER_LengthLength(sub_len);
    236            }
    237        }
    238 
    239        return len;
    240    }
    241 
    242    switch (under_kind) {
    243        case DER_SEQUENCE:
    244        case DER_SET: {
    245            DERTemplate *tmpt;
    246            void *sub_src;
    247            PRUint32 sub_len;
    248 
    249            len = 0;
    250            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
    251                sub_src = (void *)((char *)src + tmpt->offset);
    252                sub_len = contents_length(tmpt, sub_src);
    253                len += sub_len + header_length(tmpt, sub_len);
    254            }
    255        } break;
    256 
    257        case DER_BIT_STRING:
    258            len = (((SECItem *)src)->len + 7) >> 3;
    259            /* bit string contents involve an extra octet */
    260            if (len)
    261                len++;
    262            break;
    263 
    264        default:
    265            len = ((SECItem *)src)->len;
    266            break;
    267    }
    268 
    269    return len;
    270 }
    271 
    272 static unsigned char *
    273 der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
    274 {
    275    int header_len;
    276    PRUint32 contents_len;
    277    unsigned long encode_kind, under_kind;
    278    PRBool explicit, universal;
    279 
    280    /*
    281     * First figure out how long the encoding will be.  Do this by
    282     * traversing the template from top to bottom and accumulating
    283     * the length of each leaf item.
    284     */
    285    contents_len = contents_length(dtemplate, src);
    286    header_len = header_length(dtemplate, contents_len);
    287 
    288    /*
    289     * Enough smarts was involved already, so that if both the
    290     * header and the contents have a length of zero, then we
    291     * are not doing any encoding for this element.
    292     */
    293    if (header_len == 0 && contents_len == 0)
    294        return buf;
    295 
    296    encode_kind = dtemplate->kind;
    297 
    298    explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
    299    encode_kind &= ~DER_OPTIONAL;
    300    universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
    301                    ? PR_TRUE
    302                    : PR_FALSE;
    303 
    304    if (encode_kind & DER_POINTER) {
    305        if (contents_len) {
    306            src = *(void **)src;
    307            PORT_Assert(src != NULL);
    308        }
    309        if (dtemplate->sub != NULL) {
    310            dtemplate = dtemplate->sub;
    311            under_kind = dtemplate->kind;
    312            if (universal) {
    313                encode_kind = under_kind;
    314            }
    315            src = (void *)((char *)src + dtemplate->offset);
    316        } else if (universal) {
    317            under_kind = encode_kind & ~DER_POINTER;
    318        } else {
    319            under_kind = dtemplate->arg;
    320        }
    321    } else if (encode_kind & DER_INLINE) {
    322        dtemplate = dtemplate->sub;
    323        under_kind = dtemplate->kind;
    324        if (universal) {
    325            encode_kind = under_kind;
    326        }
    327        src = (void *)((char *)src + dtemplate->offset);
    328    } else if (universal) {
    329        under_kind = encode_kind;
    330    } else {
    331        under_kind = dtemplate->arg;
    332    }
    333 
    334    if (explicit) {
    335        buf = DER_StoreHeader(buf, encode_kind,
    336                              (1 + DER_LengthLength(contents_len) + contents_len));
    337        encode_kind = under_kind;
    338    }
    339 
    340    if ((encode_kind & DER_ANY) == 0) { /* DER_ANY already contains header */
    341        buf = DER_StoreHeader(buf, encode_kind, contents_len);
    342    }
    343 
    344    /* If no real contents to encode, then we are done.  */
    345    if (contents_len == 0)
    346        return buf;
    347 
    348    if (under_kind & DER_INDEFINITE) {
    349        void **indp;
    350 
    351        indp = *(void ***)src;
    352        PORT_Assert(indp != NULL);
    353 
    354        under_kind &= ~DER_INDEFINITE;
    355        if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
    356            DERTemplate *tmpt = dtemplate->sub;
    357            PORT_Assert(tmpt != NULL);
    358            for (; *indp != NULL; indp++) {
    359                void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
    360                buf = der_encode(buf, tmpt, sub_src);
    361            }
    362        } else {
    363            for (; *indp != NULL; indp++) {
    364                SECItem *item;
    365                int sub_len;
    366 
    367                item = (SECItem *)(*indp);
    368                sub_len = item->len;
    369                if (under_kind == DER_BIT_STRING) {
    370                    if (sub_len) {
    371                        int rem;
    372 
    373                        sub_len = (sub_len + 7) >> 3;
    374                        buf = DER_StoreHeader(buf, under_kind, sub_len + 1);
    375                        rem = (sub_len << 3) - item->len;
    376                        *buf++ = rem; /* remaining bits */
    377                    } else {
    378                        buf = DER_StoreHeader(buf, under_kind, 0);
    379                    }
    380                } else if (under_kind != DER_ANY) {
    381                    buf = DER_StoreHeader(buf, under_kind, sub_len);
    382                }
    383                PORT_Memcpy(buf, item->data, sub_len);
    384                buf += sub_len;
    385            }
    386        }
    387        return buf;
    388    }
    389 
    390    switch (under_kind) {
    391        case DER_SEQUENCE:
    392        case DER_SET: {
    393            DERTemplate *tmpt;
    394            void *sub_src;
    395 
    396            for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
    397                sub_src = (void *)((char *)src + tmpt->offset);
    398                buf = der_encode(buf, tmpt, sub_src);
    399            }
    400        } break;
    401 
    402        case DER_BIT_STRING: {
    403            SECItem *item;
    404            int rem;
    405 
    406            /*
    407             * The contents length includes our extra octet; subtract
    408             * it off so we just have the real string length there.
    409             */
    410            contents_len--;
    411            item = (SECItem *)src;
    412            PORT_Assert(contents_len == ((item->len + 7) >> 3));
    413            rem = (contents_len << 3) - item->len;
    414            *buf++ = rem; /* remaining bits */
    415            PORT_Memcpy(buf, item->data, contents_len);
    416            buf += contents_len;
    417        } break;
    418 
    419        default: {
    420            SECItem *item;
    421 
    422            item = (SECItem *)src;
    423            PORT_Assert(contents_len == item->len);
    424            PORT_Memcpy(buf, item->data, contents_len);
    425            buf += contents_len;
    426        } break;
    427    }
    428 
    429    return buf;
    430 }
    431 
    432 SECStatus
    433 DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
    434 {
    435    unsigned int contents_len, header_len;
    436 
    437    src = (void **)((char *)src + dtemplate->offset);
    438 
    439    /*
    440     * First figure out how long the encoding will be. Do this by
    441     * traversing the template from top to bottom and accumulating
    442     * the length of each leaf item.
    443     */
    444    contents_len = contents_length(dtemplate, src);
    445    header_len = header_length(dtemplate, contents_len);
    446 
    447    dest->len = contents_len + header_len;
    448 
    449    /* Allocate storage to hold the encoding */
    450    dest->data = (unsigned char *)PORT_ArenaAlloc(arena, dest->len);
    451    if (dest->data == NULL) {
    452        PORT_SetError(SEC_ERROR_NO_MEMORY);
    453        return SECFailure;
    454    }
    455 
    456    /* Now encode into the buffer */
    457    (void)der_encode(dest->data, dtemplate, src);
    458 
    459    return SECSuccess;
    460 }