tor-browser

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

certhtml.c (9177B)


      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 /*
      6 * certhtml.c --- convert a cert to html
      7 */
      8 
      9 #include "seccomon.h"
     10 #include "secitem.h"
     11 #include "sechash.h"
     12 #include "cert.h"
     13 #include "keyhi.h"
     14 #include "secder.h"
     15 #include "prprf.h"
     16 #include "secport.h"
     17 #include "secasn1.h"
     18 #include "pk11func.h"
     19 
     20 static char *hex = "0123456789ABCDEF";
     21 
     22 /*
     23 ** Convert a der-encoded integer to a hex printable string form
     24 */
     25 char *
     26 CERT_Hexify(SECItem *i, int do_colon)
     27 {
     28    unsigned char *cp, *end;
     29    char *rv, *o;
     30 
     31    if (!i->len) {
     32        return PORT_Strdup("00");
     33    }
     34 
     35    rv = o = (char *)PORT_Alloc(i->len * 3);
     36    if (!rv)
     37        return rv;
     38 
     39    cp = i->data;
     40    end = cp + i->len;
     41    while (cp < end) {
     42        unsigned char ch = *cp++;
     43        *o++ = hex[(ch >> 4) & 0xf];
     44        *o++ = hex[ch & 0xf];
     45        if (cp != end) {
     46            if (do_colon) {
     47                *o++ = ':';
     48            }
     49        }
     50    }
     51    *o = 0; /* Null terminate the string */
     52    return rv;
     53 }
     54 
     55 #define BREAK "<br>"
     56 #define BREAKLEN 4
     57 #define COMMA ", "
     58 #define COMMALEN 2
     59 
     60 #define MAX_OUS 20
     61 #define MAX_DC MAX_OUS
     62 
     63 char *
     64 CERT_FormatName(CERTName *name)
     65 {
     66    CERTRDN **rdns;
     67    CERTRDN *rdn;
     68    CERTAVA **avas;
     69    CERTAVA *ava;
     70    char *buf = 0;
     71    char *tmpbuf = 0;
     72    SECItem *cn = 0;
     73    SECItem *email = 0;
     74    SECItem *org = 0;
     75    SECItem *loc = 0;
     76    SECItem *state = 0;
     77    SECItem *country = 0;
     78    SECItem *dq = 0;
     79 
     80    unsigned len = 0;
     81    int tag;
     82    int i;
     83    int ou_count = 0;
     84    int dc_count = 0;
     85    PRBool first;
     86    SECItem *orgunit[MAX_OUS];
     87    SECItem *dc[MAX_DC];
     88 
     89    /* Loop over name components and gather the interesting ones */
     90    rdns = name->rdns;
     91    while ((rdn = *rdns++) != 0) {
     92        avas = rdn->avas;
     93        while ((ava = *avas++) != 0) {
     94            tag = CERT_GetAVATag(ava);
     95            switch (tag) {
     96                case SEC_OID_AVA_COMMON_NAME:
     97                    if (cn) {
     98                        break;
     99                    }
    100                    cn = CERT_DecodeAVAValue(&ava->value);
    101                    if (!cn) {
    102                        goto loser;
    103                    }
    104                    len += cn->len;
    105                    // cn will always have BREAK after it
    106                    len += BREAKLEN;
    107                    break;
    108                case SEC_OID_AVA_COUNTRY_NAME:
    109                    if (country) {
    110                        break;
    111                    }
    112                    country = CERT_DecodeAVAValue(&ava->value);
    113                    if (!country) {
    114                        goto loser;
    115                    }
    116                    len += country->len;
    117                    // country may have COMMA after it (if we over-count len,
    118                    // that's fine - we'll just allocate a buffer larger than we
    119                    // need)
    120                    len += COMMALEN;
    121                    break;
    122                case SEC_OID_AVA_LOCALITY:
    123                    if (loc) {
    124                        break;
    125                    }
    126                    loc = CERT_DecodeAVAValue(&ava->value);
    127                    if (!loc) {
    128                        goto loser;
    129                    }
    130                    len += loc->len;
    131                    // loc may have COMMA after it
    132                    len += COMMALEN;
    133                    break;
    134                case SEC_OID_AVA_STATE_OR_PROVINCE:
    135                    if (state) {
    136                        break;
    137                    }
    138                    state = CERT_DecodeAVAValue(&ava->value);
    139                    if (!state) {
    140                        goto loser;
    141                    }
    142                    len += state->len;
    143                    // state currently won't have COMMA after it, but this is a
    144                    // (probably vain) attempt to future-proof this code
    145                    len += COMMALEN;
    146                    break;
    147                case SEC_OID_AVA_ORGANIZATION_NAME:
    148                    if (org) {
    149                        break;
    150                    }
    151                    org = CERT_DecodeAVAValue(&ava->value);
    152                    if (!org) {
    153                        goto loser;
    154                    }
    155                    len += org->len;
    156                    // org will have BREAK after it
    157                    len += BREAKLEN;
    158                    break;
    159                case SEC_OID_AVA_DN_QUALIFIER:
    160                    if (dq) {
    161                        break;
    162                    }
    163                    dq = CERT_DecodeAVAValue(&ava->value);
    164                    if (!dq) {
    165                        goto loser;
    166                    }
    167                    len += dq->len;
    168                    // dq will have BREAK after it
    169                    len += BREAKLEN;
    170                    break;
    171                case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME:
    172                    if (ou_count < MAX_OUS) {
    173                        orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value);
    174                        if (!orgunit[ou_count]) {
    175                            goto loser;
    176                        }
    177                        len += orgunit[ou_count++]->len;
    178                        // each ou will have BREAK after it
    179                        len += BREAKLEN;
    180                    }
    181                    break;
    182                case SEC_OID_AVA_DC:
    183                    if (dc_count < MAX_DC) {
    184                        dc[dc_count] = CERT_DecodeAVAValue(&ava->value);
    185                        if (!dc[dc_count]) {
    186                            goto loser;
    187                        }
    188                        len += dc[dc_count++]->len;
    189                        // each dc will have BREAK after it
    190                        len += BREAKLEN;
    191                    }
    192                    break;
    193                case SEC_OID_PKCS9_EMAIL_ADDRESS:
    194                case SEC_OID_RFC1274_MAIL:
    195                    if (email) {
    196                        break;
    197                    }
    198                    email = CERT_DecodeAVAValue(&ava->value);
    199                    if (!email) {
    200                        goto loser;
    201                    }
    202                    len += email->len;
    203                    // email will have BREAK after it
    204                    len += BREAKLEN;
    205                    break;
    206                default:
    207                    break;
    208            }
    209        }
    210    }
    211 
    212    // there may be a final BREAK
    213    len += BREAKLEN;
    214 
    215    /* allocate buffer */
    216    buf = (char *)PORT_Alloc(len);
    217    if (!buf) {
    218        goto loser;
    219    }
    220 
    221    tmpbuf = buf;
    222 
    223    if (cn) {
    224        PORT_Memcpy(tmpbuf, cn->data, cn->len);
    225        tmpbuf += cn->len;
    226        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
    227        tmpbuf += BREAKLEN;
    228    }
    229    if (email) {
    230        PORT_Memcpy(tmpbuf, email->data, email->len);
    231        tmpbuf += (email->len);
    232        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
    233        tmpbuf += BREAKLEN;
    234    }
    235    for (i = ou_count - 1; i >= 0; i--) {
    236        PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len);
    237        tmpbuf += (orgunit[i]->len);
    238        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
    239        tmpbuf += BREAKLEN;
    240    }
    241    if (dq) {
    242        PORT_Memcpy(tmpbuf, dq->data, dq->len);
    243        tmpbuf += (dq->len);
    244        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
    245        tmpbuf += BREAKLEN;
    246    }
    247    if (org) {
    248        PORT_Memcpy(tmpbuf, org->data, org->len);
    249        tmpbuf += (org->len);
    250        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
    251        tmpbuf += BREAKLEN;
    252    }
    253    for (i = dc_count - 1; i >= 0; i--) {
    254        PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len);
    255        tmpbuf += (dc[i]->len);
    256        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
    257        tmpbuf += BREAKLEN;
    258    }
    259    first = PR_TRUE;
    260    if (loc) {
    261        PORT_Memcpy(tmpbuf, loc->data, loc->len);
    262        tmpbuf += (loc->len);
    263        first = PR_FALSE;
    264    }
    265    if (state) {
    266        if (!first) {
    267            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
    268            tmpbuf += COMMALEN;
    269        }
    270        PORT_Memcpy(tmpbuf, state->data, state->len);
    271        tmpbuf += (state->len);
    272        first = PR_FALSE;
    273    }
    274    if (country) {
    275        if (!first) {
    276            PORT_Memcpy(tmpbuf, COMMA, COMMALEN);
    277            tmpbuf += COMMALEN;
    278        }
    279        PORT_Memcpy(tmpbuf, country->data, country->len);
    280        tmpbuf += (country->len);
    281        first = PR_FALSE;
    282    }
    283    if (!first) {
    284        PORT_Memcpy(tmpbuf, BREAK, BREAKLEN);
    285        tmpbuf += BREAKLEN;
    286    }
    287 
    288    *tmpbuf = 0;
    289 
    290 /* fall through and clean */
    291 loser:
    292    if (cn) {
    293        SECITEM_FreeItem(cn, PR_TRUE);
    294    }
    295    if (email) {
    296        SECITEM_FreeItem(email, PR_TRUE);
    297    }
    298    for (i = ou_count - 1; i >= 0; i--) {
    299        SECITEM_FreeItem(orgunit[i], PR_TRUE);
    300    }
    301    if (dq) {
    302        SECITEM_FreeItem(dq, PR_TRUE);
    303    }
    304    if (org) {
    305        SECITEM_FreeItem(org, PR_TRUE);
    306    }
    307    for (i = dc_count - 1; i >= 0; i--) {
    308        SECITEM_FreeItem(dc[i], PR_TRUE);
    309    }
    310    if (loc) {
    311        SECITEM_FreeItem(loc, PR_TRUE);
    312    }
    313    if (state) {
    314        SECITEM_FreeItem(state, PR_TRUE);
    315    }
    316    if (country) {
    317        SECITEM_FreeItem(country, PR_TRUE);
    318    }
    319 
    320    return (buf);
    321 }