tor-browser

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

derprint.c (13791B)


      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 #include "secutil.h"
      5 #include "secoid.h"
      6 
      7 #include <stdint.h>
      8 
      9 #ifdef __sun
     10 extern int fprintf(FILE *strm, const char *format, ... /* args */);
     11 extern int fflush(FILE *stream);
     12 #endif
     13 
     14 #define RIGHT_MARGIN 24
     15 /*#define RAW_BYTES 1 */
     16 
     17 static int prettyColumn = 0;
     18 
     19 static int
     20 getInteger256(const unsigned char *data, unsigned int nb)
     21 {
     22    int val;
     23 
     24    switch (nb) {
     25        case 1:
     26            val = data[0];
     27            break;
     28        case 2:
     29            val = (data[0] << 8) | data[1];
     30            break;
     31        case 3:
     32            val = (data[0] << 16) | (data[1] << 8) | data[2];
     33            break;
     34        case 4:
     35            /* If the most significant bit of data[0] is 1, val would be negative.
     36             * Treat it as an error.
     37             */
     38            if (data[0] & 0x80) {
     39                PORT_SetError(SEC_ERROR_BAD_DER);
     40                return -1;
     41            }
     42            val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
     43            break;
     44        default:
     45            PORT_SetError(SEC_ERROR_BAD_DER);
     46            return -1;
     47    }
     48 
     49    return val;
     50 }
     51 
     52 static int
     53 prettyNewline(FILE *out)
     54 {
     55    int rv;
     56 
     57    if (prettyColumn != -1) {
     58        rv = fprintf(out, "\n");
     59        prettyColumn = -1;
     60        if (rv < 0) {
     61            PORT_SetError(SEC_ERROR_IO);
     62            return rv;
     63        }
     64    }
     65    return 0;
     66 }
     67 
     68 static int
     69 prettyIndent(FILE *out, unsigned level)
     70 {
     71    unsigned int i;
     72    int rv;
     73 
     74    if (prettyColumn == -1) {
     75        prettyColumn = level;
     76        for (i = 0; i < level; i++) {
     77            rv = fprintf(out, "   ");
     78            if (rv < 0) {
     79                PORT_SetError(SEC_ERROR_IO);
     80                return rv;
     81            }
     82        }
     83    }
     84 
     85    return 0;
     86 }
     87 
     88 static int
     89 prettyPrintByte(FILE *out, unsigned char item, unsigned int level)
     90 {
     91    int rv;
     92 
     93    rv = prettyIndent(out, level);
     94    if (rv < 0)
     95        return rv;
     96 
     97    rv = fprintf(out, "%02x ", item);
     98    if (rv < 0) {
     99        PORT_SetError(SEC_ERROR_IO);
    100        return rv;
    101    }
    102 
    103    prettyColumn++;
    104    if (prettyColumn >= RIGHT_MARGIN) {
    105        return prettyNewline(out);
    106    }
    107 
    108    return 0;
    109 }
    110 
    111 static int
    112 prettyPrintLeaf(FILE *out, const unsigned char *data,
    113                unsigned int len, unsigned int lv)
    114 {
    115    unsigned int i;
    116    int rv;
    117 
    118    for (i = 0; i < len; i++) {
    119        rv = prettyPrintByte(out, *data++, lv);
    120        if (rv < 0)
    121            return rv;
    122    }
    123    return prettyNewline(out);
    124 }
    125 
    126 static int
    127 prettyPrintStringStart(FILE *out, const unsigned char *str,
    128                       unsigned int len, unsigned int level)
    129 {
    130 #define BUF_SIZE 100
    131    unsigned char buf[BUF_SIZE];
    132    int rv;
    133 
    134    if (len >= BUF_SIZE)
    135        len = BUF_SIZE - 1;
    136 
    137    rv = prettyNewline(out);
    138    if (rv < 0)
    139        return rv;
    140 
    141    rv = prettyIndent(out, level);
    142    if (rv < 0)
    143        return rv;
    144 
    145    memcpy(buf, str, len);
    146    buf[len] = '\000';
    147 
    148    rv = fprintf(out, "\"%s\"", buf);
    149    if (rv < 0) {
    150        PORT_SetError(SEC_ERROR_IO);
    151        return rv;
    152    }
    153 
    154    return 0;
    155 #undef BUF_SIZE
    156 }
    157 
    158 static int
    159 prettyPrintString(FILE *out, const unsigned char *str,
    160                  unsigned int len, unsigned int level, PRBool raw)
    161 {
    162    int rv;
    163 
    164    rv = prettyPrintStringStart(out, str, len, level);
    165    if (rv < 0)
    166        return rv;
    167 
    168    rv = prettyNewline(out);
    169    if (rv < 0)
    170        return rv;
    171 
    172    if (raw) {
    173        rv = prettyPrintLeaf(out, str, len, level);
    174        if (rv < 0)
    175            return rv;
    176    }
    177 
    178    return 0;
    179 }
    180 
    181 static int
    182 prettyPrintTime(FILE *out, const unsigned char *str,
    183                unsigned int len, unsigned int level, PRBool raw, PRBool utc)
    184 {
    185    SECItem time_item;
    186    int rv;
    187 
    188    rv = prettyPrintStringStart(out, str, len, level);
    189    if (rv < 0)
    190        return rv;
    191 
    192    time_item.data = (unsigned char *)str;
    193    time_item.len = len;
    194 
    195    rv = fprintf(out, " (");
    196    if (rv < 0) {
    197        PORT_SetError(SEC_ERROR_IO);
    198        return rv;
    199    }
    200 
    201    if (utc)
    202        SECU_PrintUTCTime(out, &time_item, NULL, 0);
    203    else
    204        SECU_PrintGeneralizedTime(out, &time_item, NULL, 0);
    205 
    206    rv = fprintf(out, ")");
    207    if (rv < 0) {
    208        PORT_SetError(SEC_ERROR_IO);
    209        return rv;
    210    }
    211 
    212    rv = prettyNewline(out);
    213    if (rv < 0)
    214        return rv;
    215 
    216    if (raw) {
    217        rv = prettyPrintLeaf(out, str, len, level);
    218        if (rv < 0)
    219            return rv;
    220    }
    221 
    222    return 0;
    223 }
    224 
    225 static int
    226 prettyPrintObjectID(FILE *out, const unsigned char *data,
    227                    unsigned int len, unsigned int level, PRBool raw)
    228 {
    229    SECOidData *oiddata;
    230    SECItem oiditem;
    231    unsigned int i;
    232    unsigned long val;
    233    int rv;
    234 
    235    /*
    236     * First print the Object Id in numeric format
    237     */
    238 
    239    rv = prettyIndent(out, level);
    240    if (rv < 0)
    241        return rv;
    242 
    243    if (len == 0) {
    244        PORT_SetError(SEC_ERROR_BAD_DER);
    245        return -1;
    246    }
    247    val = data[0];
    248    i = val % 40;
    249    val = val / 40;
    250    rv = fprintf(out, "%lu %u ", val, i);
    251    if (rv < 0) {
    252        PORT_SetError(SEC_ERROR_IO);
    253        return rv;
    254    }
    255 
    256    val = 0;
    257    for (i = 1; i < len; ++i) {
    258        unsigned long j;
    259 
    260        j = data[i];
    261        val = (val << 7) | (j & 0x7f);
    262        if (j & 0x80)
    263            continue;
    264        rv = fprintf(out, "%lu ", val);
    265        if (rv < 0) {
    266            PORT_SetError(SEC_ERROR_IO);
    267            return rv;
    268        }
    269        val = 0;
    270    }
    271 
    272    /*
    273     * Now try to look it up and print a symbolic version.
    274     */
    275    oiditem.data = (unsigned char *)data;
    276    oiditem.len = len;
    277    oiddata = SECOID_FindOID(&oiditem);
    278    if (oiddata != NULL) {
    279        i = PORT_Strlen(oiddata->desc);
    280        if ((prettyColumn + 1 + (i / 3)) > RIGHT_MARGIN) {
    281            rv = prettyNewline(out);
    282            if (rv < 0)
    283                return rv;
    284        }
    285 
    286        rv = prettyIndent(out, level);
    287        if (rv < 0)
    288            return rv;
    289 
    290        rv = fprintf(out, "(%s)", oiddata->desc);
    291        if (rv < 0) {
    292            PORT_SetError(SEC_ERROR_IO);
    293            return rv;
    294        }
    295    }
    296 
    297    rv = prettyNewline(out);
    298    if (rv < 0)
    299        return rv;
    300 
    301    if (raw) {
    302        rv = prettyPrintLeaf(out, data, len, level);
    303        if (rv < 0)
    304            return rv;
    305    }
    306 
    307    return 0;
    308 }
    309 
    310 static char *prettyTagType[32] = {
    311    "End of Contents",
    312    "Boolean",
    313    "Integer",
    314    "Bit String",
    315    "Octet String",
    316    "NULL",
    317    "Object Identifier",
    318    "0x07",
    319    "0x08",
    320    "0x09",
    321    "Enumerated",
    322    "0x0B",
    323    "UTF8 String",
    324    "0x0D",
    325    "0x0E",
    326    "0x0F",
    327    "Sequence",
    328    "Set",
    329    "0x12",
    330    "Printable String",
    331    "T61 String",
    332    "0x15",
    333    "IA5 String",
    334    "UTC Time",
    335    "Generalized Time",
    336    "0x19",
    337    "Visible String",
    338    "0x1B",
    339    "Universal String",
    340    "0x1D",
    341    "BMP String",
    342    "High-Tag-Number"
    343 };
    344 
    345 static int
    346 prettyPrintTag(FILE *out, const unsigned char *src, const unsigned char *end,
    347               unsigned char *codep, unsigned int level, PRBool raw)
    348 {
    349    int rv;
    350    unsigned char code, tagnum;
    351 
    352    if (src >= end) {
    353        PORT_SetError(SEC_ERROR_BAD_DER);
    354        return -1;
    355    }
    356 
    357    code = *src;
    358    tagnum = code & SEC_ASN1_TAGNUM_MASK;
    359 
    360    /*
    361     * NOTE: This code does not (yet) handle the high-tag-number form!
    362     */
    363    if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) {
    364        PORT_SetError(SEC_ERROR_BAD_DER);
    365        return -1;
    366    }
    367 
    368    if (raw)
    369        rv = prettyPrintByte(out, code, level);
    370    else
    371        rv = prettyIndent(out, level);
    372 
    373    if (rv < 0)
    374        return rv;
    375 
    376    if (code & SEC_ASN1_CONSTRUCTED) {
    377        rv = fprintf(out, "C-");
    378        if (rv < 0) {
    379            PORT_SetError(SEC_ERROR_IO);
    380            return rv;
    381        }
    382    }
    383 
    384    switch (code & SEC_ASN1_CLASS_MASK) {
    385        case SEC_ASN1_UNIVERSAL:
    386            rv = fprintf(out, "%s ", prettyTagType[tagnum]);
    387            break;
    388        case SEC_ASN1_APPLICATION:
    389            rv = fprintf(out, "Application: %d ", tagnum);
    390            break;
    391        case SEC_ASN1_CONTEXT_SPECIFIC:
    392            rv = fprintf(out, "[%d] ", tagnum);
    393            break;
    394        case SEC_ASN1_PRIVATE:
    395            rv = fprintf(out, "Private: %d ", tagnum);
    396            break;
    397    }
    398 
    399    if (rv < 0) {
    400        PORT_SetError(SEC_ERROR_IO);
    401        return rv;
    402    }
    403 
    404    *codep = code;
    405 
    406    return 1;
    407 }
    408 
    409 static int
    410 prettyPrintLength(FILE *out, const unsigned char *data, const unsigned char *end,
    411                  int *lenp, PRBool *indefinitep, unsigned int lv, PRBool raw)
    412 {
    413    unsigned char lbyte;
    414    int lenLen;
    415    int rv;
    416 
    417    if (data >= end) {
    418        PORT_SetError(SEC_ERROR_BAD_DER);
    419        return -1;
    420    }
    421 
    422    rv = fprintf(out, " ");
    423    if (rv < 0) {
    424        PORT_SetError(SEC_ERROR_IO);
    425        return rv;
    426    }
    427 
    428    *indefinitep = PR_FALSE;
    429 
    430    lbyte = *data++;
    431    lenLen = 1;
    432    if (lbyte >= 0x80) {
    433        /* Multibyte length */
    434        unsigned nb = (unsigned)(lbyte & 0x7f);
    435        if (nb > 4) {
    436            PORT_SetError(SEC_ERROR_BAD_DER);
    437            return -1;
    438        }
    439        if (nb > 0) {
    440            int il;
    441 
    442            if ((data + nb) > end) {
    443                PORT_SetError(SEC_ERROR_BAD_DER);
    444                return -1;
    445            }
    446            il = getInteger256(data, nb);
    447            if (il < 0)
    448                return -1;
    449            *lenp = (unsigned)il;
    450        } else {
    451            *lenp = 0;
    452            *indefinitep = PR_TRUE;
    453        }
    454        lenLen += nb;
    455        if (raw) {
    456            unsigned int i;
    457 
    458            rv = prettyPrintByte(out, lbyte, lv);
    459            if (rv < 0)
    460                return rv;
    461            for (i = 0; i < nb; i++) {
    462                rv = prettyPrintByte(out, data[i], lv);
    463                if (rv < 0)
    464                    return rv;
    465            }
    466        }
    467    } else {
    468        *lenp = lbyte;
    469        if (raw) {
    470            rv = prettyPrintByte(out, lbyte, lv);
    471            if (rv < 0)
    472                return rv;
    473        }
    474    }
    475    if (*indefinitep)
    476        rv = fprintf(out, "(indefinite)\n");
    477    else
    478        rv = fprintf(out, "(%d)\n", *lenp);
    479    if (rv < 0) {
    480        PORT_SetError(SEC_ERROR_IO);
    481        return rv;
    482    }
    483 
    484    prettyColumn = -1;
    485    return lenLen;
    486 }
    487 
    488 static int
    489 prettyPrintItem(FILE *out, const unsigned char *data, const unsigned char *end,
    490                unsigned int lv, PRBool raw)
    491 {
    492    int slen;
    493    int lenLen;
    494    const unsigned char *orig = data;
    495    int rv;
    496 
    497    while (data < end) {
    498        unsigned char code;
    499        PRBool indefinite;
    500 
    501        slen = prettyPrintTag(out, data, end, &code, lv, raw);
    502        if (slen < 0)
    503            return slen;
    504        data += slen;
    505 
    506        lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw);
    507        if (lenLen < 0)
    508            return lenLen;
    509        data += lenLen;
    510 
    511        /*
    512         * Just quit now if slen more bytes puts us off the end.
    513         */
    514        if (data > end || slen > (end - data)) {
    515            PORT_SetError(SEC_ERROR_BAD_DER);
    516            return -1;
    517        }
    518 
    519        if (code & SEC_ASN1_CONSTRUCTED) {
    520            if (slen > 0 || indefinite) {
    521                slen = prettyPrintItem(out, data,
    522                                       slen == 0 ? end : data + slen,
    523                                       lv + 1, raw);
    524                if (slen < 0)
    525                    return slen;
    526                data += slen;
    527            }
    528        } else if (code == 0) {
    529            if (slen != 0 || lenLen != 1) {
    530                PORT_SetError(SEC_ERROR_BAD_DER);
    531                return -1;
    532            }
    533            break;
    534        } else {
    535            switch (code) {
    536                case SEC_ASN1_PRINTABLE_STRING:
    537                case SEC_ASN1_IA5_STRING:
    538                case SEC_ASN1_VISIBLE_STRING:
    539                    rv = prettyPrintString(out, data, slen, lv + 1, raw);
    540                    if (rv < 0)
    541                        return rv;
    542                    break;
    543                case SEC_ASN1_UTC_TIME:
    544                    rv = prettyPrintTime(out, data, slen, lv + 1, raw, PR_TRUE);
    545                    if (rv < 0)
    546                        return rv;
    547                    break;
    548                case SEC_ASN1_GENERALIZED_TIME:
    549                    rv = prettyPrintTime(out, data, slen, lv + 1, raw, PR_FALSE);
    550                    if (rv < 0)
    551                        return rv;
    552                    break;
    553                case SEC_ASN1_OBJECT_ID:
    554                    rv = prettyPrintObjectID(out, data, slen, lv + 1, raw);
    555                    if (rv < 0)
    556                        return rv;
    557                    break;
    558                case SEC_ASN1_BOOLEAN:    /* could do nicer job */
    559                case SEC_ASN1_INTEGER:    /* could do nicer job */
    560                case SEC_ASN1_BIT_STRING: /* could do nicer job */
    561                case SEC_ASN1_OCTET_STRING:
    562                case SEC_ASN1_NULL:
    563                case SEC_ASN1_ENUMERATED: /* could do nicer job, as INTEGER */
    564                case SEC_ASN1_UTF8_STRING:
    565                case SEC_ASN1_T61_STRING: /* print as printable string? */
    566                case SEC_ASN1_UNIVERSAL_STRING:
    567                case SEC_ASN1_BMP_STRING:
    568                default:
    569                    rv = prettyPrintLeaf(out, data, slen, lv + 1);
    570                    if (rv < 0)
    571                        return rv;
    572                    break;
    573            }
    574            data += slen;
    575        }
    576    }
    577 
    578    rv = prettyNewline(out);
    579    if (rv < 0)
    580        return rv;
    581 
    582    return data - orig;
    583 }
    584 
    585 SECStatus
    586 DER_PrettyPrint(FILE *out, const SECItem *it, PRBool raw)
    587 {
    588    int rv;
    589 
    590    prettyColumn = -1;
    591 
    592    rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw);
    593    if (rv < 0)
    594        return SECFailure;
    595    return SECSuccess;
    596 }