tor-browser

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

dersubr.c (5824B)


      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 <limits.h>
      7 #include "secerr.h"
      8 
      9 int
     10 DER_LengthLength(PRUint32 len)
     11 {
     12    if (len > 127) {
     13        if (len > 255) {
     14            if (len > 65535L) {
     15                if (len > 16777215L) {
     16                    return 5;
     17                } else {
     18                    return 4;
     19                }
     20            } else {
     21                return 3;
     22            }
     23        } else {
     24            return 2;
     25        }
     26    } else {
     27        return 1;
     28    }
     29 }
     30 
     31 unsigned char *
     32 DER_StoreHeader(unsigned char *buf, unsigned int code, PRUint32 len)
     33 {
     34    unsigned char b[4];
     35 
     36    b[0] = (unsigned char)(len >> 24);
     37    b[1] = (unsigned char)(len >> 16);
     38    b[2] = (unsigned char)(len >> 8);
     39    b[3] = (unsigned char)len;
     40    if ((code & DER_TAGNUM_MASK) == DER_SET || (code & DER_TAGNUM_MASK) == DER_SEQUENCE)
     41        code |= DER_CONSTRUCTED;
     42    *buf++ = code;
     43    if (len > 127) {
     44        if (len > 255) {
     45            if (len > 65535) {
     46                if (len > 16777215) {
     47                    *buf++ = 0x84;
     48                    *buf++ = b[0];
     49                    *buf++ = b[1];
     50                    *buf++ = b[2];
     51                    *buf++ = b[3];
     52                } else {
     53                    *buf++ = 0x83;
     54                    *buf++ = b[1];
     55                    *buf++ = b[2];
     56                    *buf++ = b[3];
     57                }
     58            } else {
     59                *buf++ = 0x82;
     60                *buf++ = b[2];
     61                *buf++ = b[3];
     62            }
     63        } else {
     64            *buf++ = 0x81;
     65            *buf++ = b[3];
     66        }
     67    } else {
     68        *buf++ = b[3];
     69    }
     70    return buf;
     71 }
     72 
     73 /*
     74 * XXX This should be rewritten, generalized, to take a long instead
     75 * of a PRInt32.
     76 */
     77 SECStatus
     78 DER_SetInteger(PLArenaPool *arena, SECItem *it, PRInt32 i)
     79 {
     80    unsigned char bb[4];
     81    unsigned len;
     82 
     83    bb[0] = (unsigned char)(i >> 24);
     84    bb[1] = (unsigned char)(i >> 16);
     85    bb[2] = (unsigned char)(i >> 8);
     86    bb[3] = (unsigned char)(i);
     87 
     88    /*
     89    ** Small integers are encoded in a single byte. Larger integers
     90    ** require progressively more space.
     91    */
     92    if (i < -128) {
     93        if (i < -32768L) {
     94            if (i < -8388608L) {
     95                len = 4;
     96            } else {
     97                len = 3;
     98            }
     99        } else {
    100            len = 2;
    101        }
    102    } else if (i > 127) {
    103        if (i > 32767L) {
    104            if (i > 8388607L) {
    105                len = 4;
    106            } else {
    107                len = 3;
    108            }
    109        } else {
    110            len = 2;
    111        }
    112    } else {
    113        len = 1;
    114    }
    115    it->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
    116    if (!it->data) {
    117        return SECFailure;
    118    }
    119    it->len = len;
    120    PORT_Memcpy(it->data, bb + (4 - len), len);
    121    return SECSuccess;
    122 }
    123 
    124 /*
    125 * XXX This should be rewritten, generalized, to take an unsigned long instead
    126 * of a PRUint32.
    127 */
    128 SECStatus
    129 DER_SetUInteger(PLArenaPool *arena, SECItem *it, PRUint32 ui)
    130 {
    131    unsigned char bb[5];
    132    int len;
    133 
    134    bb[0] = 0;
    135    bb[1] = (unsigned char)(ui >> 24);
    136    bb[2] = (unsigned char)(ui >> 16);
    137    bb[3] = (unsigned char)(ui >> 8);
    138    bb[4] = (unsigned char)(ui);
    139 
    140    /*
    141    ** Small integers are encoded in a single byte. Larger integers
    142    ** require progressively more space.
    143    */
    144    if (ui > 0x7f) {
    145        if (ui > 0x7fff) {
    146            if (ui > 0x7fffffL) {
    147                if (ui >= 0x80000000L) {
    148                    len = 5;
    149                } else {
    150                    len = 4;
    151                }
    152            } else {
    153                len = 3;
    154            }
    155        } else {
    156            len = 2;
    157        }
    158    } else {
    159        len = 1;
    160    }
    161 
    162    it->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
    163    if (it->data == NULL) {
    164        return SECFailure;
    165    }
    166 
    167    it->len = len;
    168    PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len);
    169 
    170    return SECSuccess;
    171 }
    172 
    173 /*
    174 ** Convert a der encoded *signed* integer into a machine integral value.
    175 ** If an underflow/overflow occurs, sets error code and returns min/max.
    176 */
    177 long
    178 DER_GetInteger(const SECItem *it)
    179 {
    180    unsigned long ival;
    181    PRBool negative;
    182    unsigned int len = it->len;
    183    unsigned char *cp = it->data;
    184    size_t lsize = sizeof(ival);
    185 
    186    PORT_Assert(len);
    187    if (!len) {
    188        PORT_SetError(SEC_ERROR_INPUT_LEN);
    189        return 0;
    190    }
    191 
    192    negative = (PRBool)(*cp & 0x80);
    193    ival = negative ? ~0 : 0;
    194 
    195    /* Ignore leading zeros/ones. */
    196    while (len && *cp == (unsigned char)ival) {
    197        len--;
    198        cp++;
    199    }
    200 
    201    /* Check for overflow/underflow. */
    202    if (len > lsize || (len == lsize && (*cp & 0x80) != negative)) {
    203        PORT_SetError(SEC_ERROR_BAD_DER);
    204        return negative ? LONG_MIN : LONG_MAX;
    205    }
    206 
    207    while (len--) {
    208        ival <<= 8;
    209        ival |= *cp++;
    210    }
    211 
    212    return ival;
    213 }
    214 
    215 /*
    216 ** Convert a der encoded *unsigned* integer into a machine integral value.
    217 ** If an overflow occurs, sets error code and returns max.
    218 */
    219 unsigned long
    220 DER_GetUInteger(SECItem *it)
    221 {
    222    unsigned long ival = 0;
    223    unsigned len = it->len;
    224    unsigned char *cp = it->data;
    225    unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8);
    226 
    227    PORT_Assert(len);
    228    if (!len) {
    229        PORT_SetError(SEC_ERROR_INPUT_LEN);
    230        return 0;
    231    }
    232 
    233    /* Cannot put a negative value into an unsigned container. */
    234    if (*cp & 0x80) {
    235        PORT_SetError(SEC_ERROR_BAD_DER);
    236        return 0;
    237    }
    238 
    239    while (len) {
    240        if (ival & overflow) {
    241            PORT_SetError(SEC_ERROR_BAD_DER);
    242            return ULONG_MAX;
    243        }
    244        ival = ival << 8;
    245        ival |= *cp++;
    246        --len;
    247    }
    248    return ival;
    249 }