tor-browser

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

alg1485.c (51116B)


      1 /* alg1485.c - implementation of RFCs 1485, 1779 and 2253.
      2 *
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include <limits.h>
      8 #include "prprf.h"
      9 #include "cert.h"
     10 #include "certi.h"
     11 #include "xconst.h"
     12 #include "genname.h"
     13 #include "secitem.h"
     14 #include "secerr.h"
     15 
     16 typedef struct NameToKindStr {
     17    const char* name;
     18    unsigned int maxLen; /* max bytes in UTF8 encoded string value */
     19    SECOidTag kind;
     20    int valueType;
     21 } NameToKind;
     22 
     23 /* local type for directory string--could be printable_string or utf8 */
     24 #define SEC_ASN1_DS SEC_ASN1_HIGH_TAG_NUMBER
     25 
     26 /* clang-format off */
     27 
     28 /* Add new entries to this table, and maybe to function ParseRFC1485AVA */
     29 static const NameToKind name2kinds[] = {
     30 /* IANA registered type names
     31 * (See: http://www.iana.org/assignments/ldap-parameters)
     32 */
     33 /* RFC 3280, 4630 MUST SUPPORT */
     34    { "CN",            640, SEC_OID_AVA_COMMON_NAME,    SEC_ASN1_DS},
     35    { "ST",            128, SEC_OID_AVA_STATE_OR_PROVINCE,
     36                                                        SEC_ASN1_DS},
     37    { "O",             128, SEC_OID_AVA_ORGANIZATION_NAME,
     38                                                        SEC_ASN1_DS},
     39    { "OU",            128, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
     40                                                        SEC_ASN1_DS},
     41    { "dnQualifier", 32767, SEC_OID_AVA_DN_QUALIFIER, SEC_ASN1_PRINTABLE_STRING},
     42    { "C",               2, SEC_OID_AVA_COUNTRY_NAME, SEC_ASN1_PRINTABLE_STRING},
     43    { "serialNumber",   64, SEC_OID_AVA_SERIAL_NUMBER,SEC_ASN1_PRINTABLE_STRING},
     44 
     45 /* RFC 3280, 4630 SHOULD SUPPORT */
     46    { "L",             128, SEC_OID_AVA_LOCALITY,       SEC_ASN1_DS},
     47    { "title",          64, SEC_OID_AVA_TITLE,          SEC_ASN1_DS},
     48    { "SN",             64, SEC_OID_AVA_SURNAME,        SEC_ASN1_DS},
     49    { "givenName",      64, SEC_OID_AVA_GIVEN_NAME,     SEC_ASN1_DS},
     50    { "initials",       64, SEC_OID_AVA_INITIALS,       SEC_ASN1_DS},
     51    { "generationQualifier",
     52                        64, SEC_OID_AVA_GENERATION_QUALIFIER,
     53                                                        SEC_ASN1_DS},
     54 /* RFC 3280, 4630 MAY SUPPORT */
     55    { "DC",            128, SEC_OID_AVA_DC,             SEC_ASN1_IA5_STRING},
     56    { "MAIL",          256, SEC_OID_RFC1274_MAIL,       SEC_ASN1_IA5_STRING},
     57    { "UID",           256, SEC_OID_RFC1274_UID,        SEC_ASN1_DS},
     58 
     59 /* ------------------ "strict" boundary ---------------------------------
     60 * In strict mode, cert_NameToAscii does not encode any of the attributes
     61 * below this line. The first SECOidTag below this line must be used to
     62 * conditionally define the "endKind" in function AppendAVA() below.
     63 * Most new attribute names should be added below this line.
     64 * Maybe this line should be up higher?  Say, after the 3280 MUSTs and
     65 * before the 3280 SHOULDs?
     66 */
     67 
     68 /* values from draft-ietf-ldapbis-user-schema-05 (not in RFC 3280) */
     69    { "postalAddress", 128, SEC_OID_AVA_POSTAL_ADDRESS, SEC_ASN1_DS},
     70    { "postalCode",     40, SEC_OID_AVA_POSTAL_CODE,    SEC_ASN1_DS},
     71    { "postOfficeBox",  40, SEC_OID_AVA_POST_OFFICE_BOX,SEC_ASN1_DS},
     72    { "houseIdentifier",64, SEC_OID_AVA_HOUSE_IDENTIFIER,SEC_ASN1_DS},
     73 /* end of IANA registered type names */
     74 
     75 /* legacy keywords */
     76    { "E",             128, SEC_OID_PKCS9_EMAIL_ADDRESS,SEC_ASN1_IA5_STRING},
     77    { "STREET",        128, SEC_OID_AVA_STREET_ADDRESS, SEC_ASN1_DS},
     78    { "pseudonym",      64, SEC_OID_AVA_PSEUDONYM,      SEC_ASN1_DS},
     79 
     80 /* values defined by the CAB Forum for EV */
     81    { "incorporationLocality", 128, SEC_OID_EV_INCORPORATION_LOCALITY,
     82                                    SEC_ASN1_DS},
     83    { "incorporationState",    128, SEC_OID_EV_INCORPORATION_STATE,
     84                                    SEC_ASN1_DS},
     85    { "incorporationCountry",    2, SEC_OID_EV_INCORPORATION_COUNTRY,
     86                                    SEC_ASN1_PRINTABLE_STRING},
     87    { "businessCategory",       64, SEC_OID_BUSINESS_CATEGORY, SEC_ASN1_DS},
     88 
     89 /* values defined in X.520 */
     90    { "name",           64, SEC_OID_AVA_NAME,           SEC_ASN1_DS},
     91 
     92    { 0,               256, SEC_OID_UNKNOWN,            0},
     93 };
     94 
     95 /* Table facilitates conversion of ASCII hex to binary. */
     96 static const PRInt16 x2b[256] = {
     97 /* #0x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     98 /* #1x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     99 /* #2x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    100 /* #3x */  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
    101 /* #4x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    102 /* #5x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    103 /* #6x */ -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    104 /* #7x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    105 /* #8x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    106 /* #9x */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    107 /* #ax */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    108 /* #bx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    109 /* #cx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    110 /* #dx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    111 /* #ex */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    112 /* #fx */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
    113 };
    114 
    115 #define IS_HEX(c) (x2b[(PRUint8)(c)] >= 0)
    116 
    117 #define C_DOUBLE_QUOTE '\042'
    118 
    119 #define C_BACKSLASH '\134'
    120 
    121 #define C_EQUAL '='
    122 
    123 #define OPTIONAL_SPACE(c)                                                      \
    124    (((c) == ' ') || ((c) == '\r') || ((c) == '\n'))
    125 
    126 #define SPECIAL_CHAR(c)                                                        \
    127    (((c) == ',') || ((c) == '=') || ((c) == C_DOUBLE_QUOTE) ||                \
    128     ((c) == '\r') || ((c) == '\n') || ((c) == '+') ||                         \
    129     ((c) == '<') || ((c) == '>') || ((c) == '#') ||                           \
    130     ((c) == ';') || ((c) == C_BACKSLASH))
    131 
    132 
    133 #define IS_PRINTABLE(c)                                                        \
    134    ((((c) >= 'a') && ((c) <= 'z')) ||                                         \
    135     (((c) >= 'A') && ((c) <= 'Z')) ||                                         \
    136     (((c) >= '0') && ((c) <= '9')) ||                                         \
    137     ((c) == ' ') ||                                                           \
    138     ((c) == '\'') ||                                                          \
    139     ((c) == '\050') ||                     /* ( */                            \
    140     ((c) == '\051') ||                     /* ) */                            \
    141     (((c) >= '+') && ((c) <= '/')) ||      /* + , - . / */                    \
    142     ((c) == ':') ||                                                           \
    143     ((c) == '=') ||                                                           \
    144     ((c) == '?'))
    145 
    146 /* clang-format on */
    147 
    148 /* RFC 2253 says we must escape ",+\"\\<>;=" EXCEPT inside a quoted string.
    149 * Inside a quoted string, we only need to escape " and \
    150 * We choose to quote strings containing any of those special characters,
    151 * so we only need to escape " and \
    152 */
    153 #define NEEDS_ESCAPE(c) (c == C_DOUBLE_QUOTE || c == C_BACKSLASH)
    154 
    155 #define NEEDS_HEX_ESCAPE(c) ((PRUint8)c < 0x20 || c == 0x7f)
    156 
    157 int
    158 cert_AVAOidTagToMaxLen(SECOidTag tag)
    159 {
    160    const NameToKind* n2k = name2kinds;
    161 
    162    while (n2k->kind != tag && n2k->kind != SEC_OID_UNKNOWN) {
    163        ++n2k;
    164    }
    165    return (n2k->kind != SEC_OID_UNKNOWN) ? n2k->maxLen : -1;
    166 }
    167 
    168 static PRBool
    169 IsPrintable(unsigned char* data, unsigned len)
    170 {
    171    unsigned char ch, *end;
    172 
    173    end = data + len;
    174    while (data < end) {
    175        ch = *data++;
    176        if (!IS_PRINTABLE(ch)) {
    177            return PR_FALSE;
    178        }
    179    }
    180    return PR_TRUE;
    181 }
    182 
    183 static void
    184 skipSpace(const char** pbp, const char* endptr)
    185 {
    186    const char* bp = *pbp;
    187    while (bp < endptr && OPTIONAL_SPACE(*bp)) {
    188        bp++;
    189    }
    190    *pbp = bp;
    191 }
    192 
    193 static SECStatus
    194 scanTag(const char** pbp, const char* endptr, char* tagBuf, int tagBufSize)
    195 {
    196    const char* bp;
    197    char* tagBufp;
    198    int taglen;
    199 
    200    PORT_Assert(tagBufSize > 0);
    201 
    202    /* skip optional leading space */
    203    skipSpace(pbp, endptr);
    204    if (*pbp == endptr) {
    205        /* nothing left */
    206        return SECFailure;
    207    }
    208 
    209    /* fill tagBuf */
    210    taglen = 0;
    211    bp = *pbp;
    212    tagBufp = tagBuf;
    213    while (bp < endptr && !OPTIONAL_SPACE(*bp) && (*bp != C_EQUAL)) {
    214        if (++taglen >= tagBufSize) {
    215            *pbp = bp;
    216            return SECFailure;
    217        }
    218        *tagBufp++ = *bp++;
    219    }
    220    /* null-terminate tagBuf -- guaranteed at least one space left */
    221    *tagBufp++ = 0;
    222    *pbp = bp;
    223 
    224    /* skip trailing spaces till we hit something - should be an equal sign */
    225    skipSpace(pbp, endptr);
    226    if (*pbp == endptr) {
    227        /* nothing left */
    228        return SECFailure;
    229    }
    230    if (**pbp != C_EQUAL) {
    231        /* should be an equal sign */
    232        return SECFailure;
    233    }
    234    /* skip over the equal sign */
    235    (*pbp)++;
    236 
    237    return SECSuccess;
    238 }
    239 
    240 /* Returns the number of bytes in the value. 0 means failure. */
    241 static int
    242 scanVal(const char** pbp, const char* endptr, char* valBuf, int valBufSize)
    243 {
    244    const char* bp;
    245    char* valBufp;
    246    int vallen = 0;
    247    PRBool isQuoted;
    248 
    249    PORT_Assert(valBufSize > 0);
    250 
    251    /* skip optional leading space */
    252    skipSpace(pbp, endptr);
    253    if (*pbp == endptr) {
    254        /* nothing left */
    255        return 0;
    256    }
    257 
    258    bp = *pbp;
    259 
    260    /* quoted? */
    261    if (*bp == C_DOUBLE_QUOTE) {
    262        isQuoted = PR_TRUE;
    263        /* skip over it */
    264        bp++;
    265    } else {
    266        isQuoted = PR_FALSE;
    267    }
    268 
    269    valBufp = valBuf;
    270    while (bp < endptr) {
    271        char c = *bp;
    272        if (c == C_BACKSLASH) {
    273            /* escape character */
    274            bp++;
    275            if (bp >= endptr) {
    276                /* escape charater must appear with paired char */
    277                *pbp = bp;
    278                return 0;
    279            }
    280            c = *bp;
    281            if (IS_HEX(c) && (endptr - bp) >= 2 && IS_HEX(bp[1])) {
    282                bp++;
    283                c = (char)((x2b[(PRUint8)c] << 4) | x2b[(PRUint8)*bp]);
    284            }
    285        } else if (c == '#' && bp == *pbp) {
    286            /* ignore leading #, quotation not required for it. */
    287        } else if (!isQuoted && SPECIAL_CHAR(c)) {
    288            /* unescaped special and not within quoted value */
    289            break;
    290        } else if (c == C_DOUBLE_QUOTE) {
    291            /* reached unescaped double quote */
    292            break;
    293        }
    294        /* append character */
    295        vallen++;
    296        if (vallen >= valBufSize) {
    297            *pbp = bp;
    298            return 0;
    299        }
    300        *valBufp++ = c;
    301        bp++;
    302    }
    303 
    304    /* strip trailing spaces from unquoted values */
    305    if (!isQuoted) {
    306        while (valBufp > valBuf) {
    307            char c = valBufp[-1];
    308            if (!OPTIONAL_SPACE(c))
    309                break;
    310            --valBufp;
    311        }
    312        vallen = valBufp - valBuf;
    313    }
    314 
    315    if (isQuoted) {
    316        /* insist that we stopped on a double quote */
    317        if (*bp != C_DOUBLE_QUOTE) {
    318            *pbp = bp;
    319            return 0;
    320        }
    321        /* skip over the quote and skip optional space */
    322        bp++;
    323        skipSpace(&bp, endptr);
    324    }
    325 
    326    *pbp = bp;
    327 
    328    /* null-terminate valBuf -- guaranteed at least one space left */
    329    *valBufp = 0;
    330 
    331    return vallen;
    332 }
    333 
    334 /* Caller must set error code upon failure */
    335 static SECStatus
    336 hexToBin(PLArenaPool* pool, SECItem* destItem, const char* src, int len)
    337 {
    338    PRUint8* dest;
    339 
    340    destItem->data = NULL;
    341    if (len <= 0 || (len & 1)) {
    342        goto loser;
    343    }
    344    len >>= 1;
    345    if (!SECITEM_AllocItem(pool, destItem, len)) {
    346        goto loser;
    347    }
    348    dest = destItem->data;
    349    for (; len > 0; len--, src += 2) {
    350        PRUint16 bin = ((PRUint16)x2b[(PRUint8)src[0]] << 4);
    351        bin |= (PRUint16)x2b[(PRUint8)src[1]];
    352        if (bin >> 15) { /* is negative */
    353            goto loser;
    354        }
    355        *dest++ = (PRUint8)bin;
    356    }
    357    return SECSuccess;
    358 loser:
    359    if (!pool)
    360        SECITEM_FreeItem(destItem, PR_FALSE);
    361    return SECFailure;
    362 }
    363 
    364 /* Parses one AVA, starting at *pbp.  Stops at endptr.
    365 * Advances *pbp past parsed AVA and trailing separator (if present).
    366 * On any error, returns NULL and *pbp is undefined.
    367 * On success, returns CERTAVA allocated from arena, and (*pbp)[-1] was
    368 * the last character parsed.  *pbp is either equal to endptr or
    369 * points to first character after separator.
    370 */
    371 static CERTAVA*
    372 ParseRFC1485AVA(PLArenaPool* arena, const char** pbp, const char* endptr)
    373 {
    374    CERTAVA* a;
    375    const NameToKind* n2k;
    376    const char* bp;
    377    int vt = -1;
    378    int valLen;
    379    PRBool isDottedOid = PR_FALSE;
    380    SECOidTag kind = SEC_OID_UNKNOWN;
    381    SECStatus rv = SECFailure;
    382    SECItem derOid = { 0, NULL, 0 };
    383    SECItem derVal = { 0, NULL, 0 };
    384    char sep = 0;
    385 
    386    char tagBuf[32];
    387    char valBuf[1024];
    388 
    389    PORT_Assert(arena);
    390    if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) ||
    391        !(valLen = scanVal(pbp, endptr, valBuf, sizeof valBuf))) {
    392        goto loser;
    393    }
    394 
    395    bp = *pbp;
    396    if (bp < endptr) {
    397        sep = *bp++; /* skip over separator */
    398    }
    399    *pbp = bp;
    400    /* if we haven't finished, insist that we've stopped on a separator */
    401    if (sep && sep != ',' && sep != ';' && sep != '+') {
    402        goto loser;
    403    }
    404 
    405    /* is this a dotted decimal OID attribute type ? */
    406    if (!PL_strncasecmp("oid.", tagBuf, 4) || isdigit((unsigned char)tagBuf[0])) {
    407        rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf));
    408        isDottedOid = (PRBool)(rv == SECSuccess);
    409    } else {
    410        for (n2k = name2kinds; n2k->name; n2k++) {
    411            SECOidData* oidrec;
    412            if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) {
    413                kind = n2k->kind;
    414                vt = n2k->valueType;
    415                oidrec = SECOID_FindOIDByTag(kind);
    416                if (oidrec == NULL)
    417                    goto loser;
    418                derOid = oidrec->oid;
    419                break;
    420            }
    421        }
    422    }
    423    if (kind == SEC_OID_UNKNOWN && rv != SECSuccess)
    424        goto loser;
    425 
    426    /* Is this a hex encoding of a DER attribute value ? */
    427    if ('#' == valBuf[0]) {
    428        /* convert attribute value from hex to binary */
    429        rv = hexToBin(arena, &derVal, valBuf + 1, valLen - 1);
    430        if (rv)
    431            goto loser;
    432        a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
    433    } else {
    434        if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2)
    435            goto loser;
    436        if (vt == SEC_ASN1_PRINTABLE_STRING &&
    437            !IsPrintable((unsigned char*)valBuf, valLen))
    438            goto loser;
    439        if (vt == SEC_ASN1_DS) {
    440            /* RFC 4630: choose PrintableString or UTF8String */
    441            if (IsPrintable((unsigned char*)valBuf, valLen))
    442                vt = SEC_ASN1_PRINTABLE_STRING;
    443            else
    444                vt = SEC_ASN1_UTF8_STRING;
    445        }
    446 
    447        derVal.data = (unsigned char*)valBuf;
    448        derVal.len = valLen;
    449        if (kind == SEC_OID_UNKNOWN && isDottedOid) {
    450            a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal);
    451        } else {
    452            a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal);
    453        }
    454    }
    455    return a;
    456 
    457 loser:
    458    /* matched no kind -- invalid tag */
    459    PORT_SetError(SEC_ERROR_INVALID_AVA);
    460    return 0;
    461 }
    462 
    463 static CERTName*
    464 ParseRFC1485Name(const char* buf, int len)
    465 {
    466    SECStatus rv;
    467    CERTName* name;
    468    const char *bp, *e;
    469    CERTAVA* ava;
    470    CERTRDN* rdn = NULL;
    471 
    472    name = CERT_CreateName(NULL);
    473    if (name == NULL) {
    474        return NULL;
    475    }
    476 
    477    e = buf + len;
    478    bp = buf;
    479    while (bp < e) {
    480        ava = ParseRFC1485AVA(name->arena, &bp, e);
    481        if (ava == 0)
    482            goto loser;
    483        if (!rdn) {
    484            rdn = CERT_CreateRDN(name->arena, ava, (CERTAVA*)0);
    485            if (rdn == 0)
    486                goto loser;
    487            rv = CERT_AddRDN(name, rdn);
    488        } else {
    489            rv = CERT_AddAVA(name->arena, rdn, ava);
    490        }
    491        if (rv)
    492            goto loser;
    493        if (bp[-1] != '+')
    494            rdn = NULL; /* done with this RDN */
    495        skipSpace(&bp, e);
    496    }
    497 
    498    if (name->rdns[0] == 0) {
    499        /* empty name -- illegal */
    500        goto loser;
    501    }
    502 
    503    /* Reverse order of RDNS to comply with RFC */
    504    {
    505        CERTRDN** firstRdn;
    506        CERTRDN** lastRdn;
    507        CERTRDN* tmp;
    508 
    509        /* get first one */
    510        firstRdn = name->rdns;
    511 
    512        /* find last one */
    513        lastRdn = name->rdns;
    514        while (*lastRdn)
    515            lastRdn++;
    516        lastRdn--;
    517 
    518        /* reverse list */
    519        for (; firstRdn < lastRdn; firstRdn++, lastRdn--) {
    520            tmp = *firstRdn;
    521            *firstRdn = *lastRdn;
    522            *lastRdn = tmp;
    523        }
    524    }
    525 
    526    /* return result */
    527    return name;
    528 
    529 loser:
    530    CERT_DestroyName(name);
    531    return NULL;
    532 }
    533 
    534 CERTName*
    535 CERT_AsciiToName(const char* string)
    536 {
    537    CERTName* name;
    538    name = ParseRFC1485Name(string, PORT_Strlen(string));
    539    return name;
    540 }
    541 
    542 /************************************************************************/
    543 
    544 typedef struct stringBufStr {
    545    char* buffer;
    546    unsigned offset;
    547    unsigned size;
    548 } stringBuf;
    549 
    550 #define DEFAULT_BUFFER_SIZE 200
    551 
    552 static SECStatus
    553 AppendStr(stringBuf* bufp, char* str)
    554 {
    555    char* buf;
    556    unsigned bufLen, bufSize, len;
    557    int size = 0;
    558 
    559    /* Figure out how much to grow buf by (add in the '\0') */
    560    buf = bufp->buffer;
    561    bufLen = bufp->offset;
    562    len = PORT_Strlen(str);
    563    bufSize = bufLen + len;
    564    if (!buf) {
    565        bufSize++;
    566        size = PR_MAX(DEFAULT_BUFFER_SIZE, bufSize * 2);
    567        buf = (char*)PORT_Alloc(size);
    568        bufp->size = size;
    569    } else if (bufp->size < bufSize) {
    570        size = bufSize * 2;
    571        buf = (char*)PORT_Realloc(buf, size);
    572        bufp->size = size;
    573    }
    574    if (!buf) {
    575        PORT_SetError(SEC_ERROR_NO_MEMORY);
    576        return SECFailure;
    577    }
    578    bufp->buffer = buf;
    579    bufp->offset = bufSize;
    580 
    581    /* Concatenate str onto buf */
    582    buf = buf + bufLen;
    583    if (bufLen)
    584        buf--;                      /* stomp on old '\0' */
    585    PORT_Memcpy(buf, str, len + 1); /* put in new null */
    586    return SECSuccess;
    587 }
    588 
    589 typedef enum {
    590    minimalEscape = 0,     /* only hex escapes, and " and \ */
    591    minimalEscapeAndQuote, /* as above, plus quoting        */
    592    fullEscape             /* no quoting, full escaping     */
    593 } EQMode;
    594 
    595 /* Some characters must be escaped as a hex string, e.g. c -> \nn .
    596 * Others must be escaped by preceding with a '\', e.g. c -> \c , but
    597 * there are certain "special characters" that may be handled by either
    598 * escaping them, or by enclosing the entire attribute value in quotes.
    599 * A NULL value for pEQMode implies selecting minimalEscape mode.
    600 * Some callers will do quoting when needed, others will not.
    601 * If a caller selects minimalEscapeAndQuote, and the string does not
    602 * need quoting, then this function changes it to minimalEscape.
    603 * Limit source to 16K, which avoids any possibility of overflow.
    604 * Maximum output size would be 3*srclen+2.
    605 */
    606 static int
    607 cert_RFC1485_GetRequiredLen(const char* src, int srclen, EQMode* pEQMode)
    608 {
    609    int i, reqLen = 0;
    610    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
    611    PRBool needsQuoting = PR_FALSE;
    612    char lastC = 0;
    613 
    614    /* avoids needing to check for overflow */
    615    if (srclen > 16384) {
    616        return -1;
    617    }
    618    /* need to make an initial pass to determine if quoting is needed */
    619    for (i = 0; i < srclen; i++) {
    620        char c = src[i];
    621        reqLen++;
    622        if (NEEDS_HEX_ESCAPE(c)) { /* c -> \xx  */
    623            reqLen += 2;
    624        } else if (NEEDS_ESCAPE(c)) { /* c -> \c   */
    625            reqLen++;
    626        } else if (SPECIAL_CHAR(c)) {
    627            if (mode == minimalEscapeAndQuote) /* quoting is allowed */
    628                needsQuoting = PR_TRUE;        /* entirety will need quoting */
    629            else if (mode == fullEscape)
    630                reqLen++; /* MAY escape this character */
    631        } else if (OPTIONAL_SPACE(c) && OPTIONAL_SPACE(lastC)) {
    632            if (mode == minimalEscapeAndQuote) /* quoting is allowed */
    633                needsQuoting = PR_TRUE;        /* entirety will need quoting */
    634        }
    635        lastC = c;
    636    }
    637    /* if it begins or ends in optional space it needs quoting */
    638    if (!needsQuoting && srclen > 0 && mode == minimalEscapeAndQuote &&
    639        (OPTIONAL_SPACE(src[srclen - 1]) || OPTIONAL_SPACE(src[0]))) {
    640        needsQuoting = PR_TRUE;
    641    }
    642 
    643    if (needsQuoting)
    644        reqLen += 2;
    645    if (pEQMode && mode == minimalEscapeAndQuote && !needsQuoting)
    646        *pEQMode = minimalEscape;
    647    /* Maximum output size would be 3*srclen+2 */
    648    return reqLen;
    649 }
    650 
    651 static const char hexChars[16] = { "0123456789abcdef" };
    652 
    653 static SECStatus
    654 escapeAndQuote(char* dst, int dstlen, char* src, int srclen, EQMode* pEQMode)
    655 {
    656    int i, reqLen = 0;
    657    EQMode mode = pEQMode ? *pEQMode : minimalEscape;
    658 
    659    reqLen = cert_RFC1485_GetRequiredLen(src, srclen, &mode);
    660    /* reqLen is max 16384*3 + 2 */
    661    /* space for terminal null */
    662    if (reqLen < 0 || reqLen + 1 > dstlen) {
    663        PORT_SetError(SEC_ERROR_OUTPUT_LEN);
    664        return SECFailure;
    665    }
    666 
    667    if (mode == minimalEscapeAndQuote)
    668        *dst++ = C_DOUBLE_QUOTE;
    669    for (i = 0; i < srclen; i++) {
    670        char c = src[i];
    671        if (NEEDS_HEX_ESCAPE(c)) {
    672            *dst++ = C_BACKSLASH;
    673            *dst++ = hexChars[(c >> 4) & 0x0f];
    674            *dst++ = hexChars[c & 0x0f];
    675        } else {
    676            if (NEEDS_ESCAPE(c) || (SPECIAL_CHAR(c) && mode == fullEscape)) {
    677                *dst++ = C_BACKSLASH;
    678            }
    679            *dst++ = c;
    680        }
    681    }
    682    if (mode == minimalEscapeAndQuote)
    683        *dst++ = C_DOUBLE_QUOTE;
    684    *dst++ = 0;
    685    if (pEQMode)
    686        *pEQMode = mode;
    687    return SECSuccess;
    688 }
    689 
    690 SECStatus
    691 CERT_RFC1485_EscapeAndQuote(char* dst, int dstlen, char* src, int srclen)
    692 {
    693    EQMode mode = minimalEscapeAndQuote;
    694    return escapeAndQuote(dst, dstlen, src, srclen, &mode);
    695 }
    696 
    697 /* convert an OID to dotted-decimal representation */
    698 /* Returns a string that must be freed with PR_smprintf_free(), */
    699 char*
    700 CERT_GetOidString(const SECItem* oid)
    701 {
    702    PRUint8* stop;  /* points to first byte after OID string */
    703    PRUint8* first; /* byte of an OID component integer      */
    704    PRUint8* last;  /* byte of an OID component integer      */
    705    char* rvString = NULL;
    706    char* prefix = NULL;
    707 
    708 #define MAX_OID_LEN 1024 /* bytes */
    709 
    710    if (oid->len > MAX_OID_LEN) {
    711        PORT_SetError(SEC_ERROR_INPUT_LEN);
    712        return NULL;
    713    }
    714 
    715    /* If the OID has length 1, we bail. */
    716    if (oid->len < 2) {
    717        return NULL;
    718    }
    719 
    720    /* first will point to the next sequence of bytes to decode */
    721    first = (PRUint8*)oid->data;
    722    /* stop points to one past the legitimate data */
    723    stop = &first[oid->len];
    724 
    725    /*
    726     * Check for our pseudo-encoded single-digit OIDs
    727     */
    728    if ((*first == 0x80) && (2 == oid->len)) {
    729        /* Funky encoding.  The second byte is the number */
    730        rvString = PR_smprintf("%lu", (PRUint32)first[1]);
    731        if (!rvString) {
    732            PORT_SetError(SEC_ERROR_NO_MEMORY);
    733        }
    734        return rvString;
    735    }
    736 
    737    for (; first < stop; first = last + 1) {
    738        unsigned int bytesBeforeLast;
    739 
    740        for (last = first; last < stop; last++) {
    741            if (0 == (*last & 0x80)) {
    742                break;
    743            }
    744        }
    745        /* There's no first bit set, so this isn't valid. Bail.*/
    746        if (last == stop) {
    747            goto unsupported;
    748        }
    749        bytesBeforeLast = (unsigned int)(last - first);
    750        if (bytesBeforeLast <= 3U) { /* 0-28 bit number */
    751            PRUint32 n = 0;
    752            PRUint32 c;
    753 
    754 #define CGET(i, m)    \
    755    c = last[-i] & m; \
    756    n |= c << (7 * i)
    757 
    758 #define CASE(i, m)  \
    759    case i:         \
    760        CGET(i, m); \
    761        if (!n)     \
    762        goto unsupported /* fall-through */
    763 
    764            switch (bytesBeforeLast) {
    765                CASE(3, 0x7f);
    766                CASE(2, 0x7f);
    767                CASE(1, 0x7f);
    768                case 0:
    769                    n |= last[0] & 0x7f;
    770                    break;
    771            }
    772            if (last[0] & 0x80) {
    773                goto unsupported;
    774            }
    775 
    776            if (!rvString) {
    777                /* This is the first number.. decompose it */
    778                PRUint32 one = PR_MIN(n / 40, 2); /* never > 2 */
    779                PRUint32 two = n - (one * 40);
    780 
    781                rvString = PR_smprintf("OID.%lu.%lu", one, two);
    782            } else {
    783                prefix = rvString;
    784                rvString = PR_smprintf("%s.%lu", prefix, n);
    785            }
    786        } else if (bytesBeforeLast <= 9U) { /* 29-64 bit number */
    787            PRUint64 n = 0;
    788            PRUint64 c;
    789 
    790            switch (bytesBeforeLast) {
    791                CASE(9, 0x01);
    792                CASE(8, 0x7f);
    793                CASE(7, 0x7f);
    794                CASE(6, 0x7f);
    795                CASE(5, 0x7f);
    796                CASE(4, 0x7f);
    797                CGET(3, 0x7f);
    798                CGET(2, 0x7f);
    799                CGET(1, 0x7f);
    800                CGET(0, 0x7f);
    801                break;
    802            }
    803            if (last[0] & 0x80)
    804                goto unsupported;
    805 
    806            if (!rvString) {
    807                /* This is the first number.. decompose it */
    808                PRUint64 one = PR_MIN(n / 40, 2); /* never > 2 */
    809                PRUint64 two = n - (one * 40);
    810 
    811                rvString = PR_smprintf("OID.%llu.%llu", one, two);
    812            } else {
    813                prefix = rvString;
    814                rvString = PR_smprintf("%s.%llu", prefix, n);
    815            }
    816        } else {
    817        /* More than a 64-bit number, or not minimal encoding. */
    818        unsupported:
    819            if (!rvString)
    820                rvString = PR_smprintf("OID.UNSUPPORTED");
    821            else {
    822                prefix = rvString;
    823                rvString = PR_smprintf("%s.UNSUPPORTED", prefix);
    824            }
    825        }
    826 
    827        if (prefix) {
    828            PR_smprintf_free(prefix);
    829            prefix = NULL;
    830        }
    831        if (!rvString) {
    832            PORT_SetError(SEC_ERROR_NO_MEMORY);
    833            break;
    834        }
    835    }
    836    return rvString;
    837 }
    838 
    839 /* convert DER-encoded hex to a string */
    840 static SECItem*
    841 get_hex_string(SECItem* data)
    842 {
    843    SECItem* rv;
    844    unsigned int i, j;
    845    static const char hex[] = { "0123456789ABCDEF" };
    846 
    847    /* '#' + 2 chars per octet + terminator */
    848    rv = SECITEM_AllocItem(NULL, NULL, data->len * 2 + 2);
    849    if (!rv) {
    850        return NULL;
    851    }
    852    rv->data[0] = '#';
    853    rv->len = 1 + 2 * data->len;
    854    for (i = 0; i < data->len; i++) {
    855        j = data->data[i];
    856        rv->data[2 * i + 1] = hex[j >> 4];
    857        rv->data[2 * i + 2] = hex[j & 15];
    858    }
    859    rv->data[rv->len] = 0;
    860    return rv;
    861 }
    862 
    863 /* For compliance with RFC 2253, RFC 3280 and RFC 4630, we choose to
    864 * use the NAME=STRING form, rather than the OID.N.N=#hexXXXX form,
    865 * when both of these conditions are met:
    866 *  1) The attribute name OID (kind) has a known name string that is
    867 *     defined in one of those RFCs, or in RFCs that they cite, AND
    868 *  2) The attribute's value encoding is RFC compliant for the kind
    869 *     (e.g., the value's encoding tag is correct for the kind, and
    870 *     the value's length is in the range allowed for the kind, and
    871 *     the value's contents are appropriate for the encoding tag).
    872 *  Otherwise, we use the OID.N.N=#hexXXXX form.
    873 *
    874 *  If the caller prefers maximum human readability to RFC compliance,
    875 *  then
    876 *  - We print the kind in NAME= string form if we know the name
    877 *    string for the attribute type OID, regardless of whether the
    878 *    value is correctly encoded or not. else we use the OID.N.N= form.
    879 *  - We use the non-hex STRING form for the attribute value if the
    880 *    value can be represented in such a form.  Otherwise, we use
    881 *    the hex string form.
    882 *  This implies that, for maximum human readability, in addition to
    883 *  the two forms allowed by the RFC, we allow two other forms of output:
    884 *  - the OID.N.N=STRING form, and
    885 *  - the NAME=#hexXXXX form
    886 *  When the caller prefers maximum human readability, we do not allow
    887 *  the value of any attribute to exceed the length allowed by the RFC.
    888 *  If the attribute value exceeds the allowed length, we truncate it to
    889 *  the allowed length and append "...".
    890 *  Also in this case, we arbitrarily impose a limit on the length of the
    891 *  entire AVA encoding, regardless of the form, of 384 bytes per AVA.
    892 *  This limit includes the trailing NULL character.  If the encoded
    893 *  AVA length exceeds that limit, this function reports failure to encode
    894 *  the AVA.
    895 *
    896 *  An ASCII representation of an AVA is said to be "invertible" if
    897 *  conversion back to DER reproduces the original DER encoding exactly.
    898 *  The RFC 2253 rules do not ensure that all ASCII AVAs derived according
    899 *  to its rules are invertible. That is because the RFCs allow some
    900 *  attribute values to be encoded in any of a number of encodings,
    901 *  and the encoding type information is lost in the non-hex STRING form.
    902 *  This is particularly true of attributes of type DirectoryString.
    903 *  The encoding type information is always preserved in the hex string
    904 *  form, because the hex includes the entire DER encoding of the value.
    905 *
    906 *  So, when the caller perfers maximum invertibility, we apply the
    907 *  RFC compliance rules stated above, and add a third required
    908 *  condition on the use of the NAME=STRING form.
    909 *   3) The attribute's kind is not is allowed to be encoded in any of
    910 *      several different encodings, such as DirectoryStrings.
    911 *
    912 * The chief difference between CERT_N2A_STRICT and CERT_N2A_INVERTIBLE
    913 * is that the latter forces DirectoryStrings to be hex encoded.
    914 *
    915 * As a simplification, we assume the value is correctly encoded for
    916 * its encoding type.  That is, we do not test that all the characters
    917 * in a string encoded type are allowed by that type.  We assume it.
    918 */
    919 static SECStatus
    920 AppendAVA(stringBuf* bufp, CERTAVA* ava, CertStrictnessLevel strict)
    921 {
    922 #define TMPBUF_LEN 2048
    923    const NameToKind* pn2k = name2kinds;
    924    SECItem* avaValue = NULL;
    925    char* unknownTag = NULL;
    926    char* encodedAVA = NULL;
    927    PRBool useHex = PR_FALSE; /* use =#hexXXXX form */
    928    PRBool truncateName = PR_FALSE;
    929    PRBool truncateValue = PR_FALSE;
    930    SECOidTag endKind;
    931    SECStatus rv;
    932    unsigned int len;
    933    unsigned int nameLen, valueLen;
    934    unsigned int maxName, maxValue;
    935    EQMode mode = minimalEscapeAndQuote;
    936    NameToKind n2k = { NULL, 32767, SEC_OID_UNKNOWN, SEC_ASN1_DS };
    937    char tmpBuf[TMPBUF_LEN];
    938 
    939 #define tagName n2k.name /* non-NULL means use NAME= form */
    940 #define maxBytes n2k.maxLen
    941 #define tag n2k.kind
    942 #define vt n2k.valueType
    943 
    944    /* READABLE mode recognizes more names from the name2kinds table
    945     * than do STRICT or INVERTIBLE modes.  This assignment chooses the
    946     * point in the table where the attribute type name scanning stops.
    947     */
    948    endKind = (strict == CERT_N2A_READABLE) ? SEC_OID_UNKNOWN
    949                                            : SEC_OID_AVA_POSTAL_ADDRESS;
    950    tag = CERT_GetAVATag(ava);
    951    while (pn2k->kind != tag && pn2k->kind != endKind) {
    952        ++pn2k;
    953    }
    954 
    955    if (pn2k->kind != endKind) {
    956        n2k = *pn2k;
    957    } else if (strict != CERT_N2A_READABLE) {
    958        useHex = PR_TRUE;
    959    }
    960    /* For invertable form, force Directory Strings to use hex form. */
    961    if (strict == CERT_N2A_INVERTIBLE && vt == SEC_ASN1_DS) {
    962        tagName = NULL;   /* must use OID.N form */
    963        useHex = PR_TRUE; /* must use hex string */
    964    }
    965    if (!useHex) {
    966        avaValue = CERT_DecodeAVAValue(&ava->value);
    967        if (!avaValue) {
    968            useHex = PR_TRUE;
    969            if (strict != CERT_N2A_READABLE) {
    970                tagName = NULL; /* must use OID.N form */
    971            }
    972        }
    973    }
    974    if (!tagName) {
    975        /* handle unknown attribute types per RFC 2253 */
    976        tagName = unknownTag = CERT_GetOidString(&ava->type);
    977        if (!tagName) {
    978            if (avaValue)
    979                SECITEM_FreeItem(avaValue, PR_TRUE);
    980            return SECFailure;
    981        }
    982    }
    983    if (useHex) {
    984        avaValue = get_hex_string(&ava->value);
    985        if (!avaValue) {
    986            if (unknownTag)
    987                PR_smprintf_free(unknownTag);
    988            return SECFailure;
    989        }
    990    }
    991 
    992    nameLen = strlen(tagName);
    993 
    994    if (useHex) {
    995        valueLen = avaValue->len;
    996    } else {
    997        int reqLen = cert_RFC1485_GetRequiredLen((char*)avaValue->data, avaValue->len, &mode);
    998        if (reqLen < 0) {
    999            SECITEM_FreeItem(avaValue, PR_TRUE);
   1000            return SECFailure;
   1001        }
   1002        valueLen = reqLen;
   1003    }
   1004    if (UINT_MAX - nameLen < 2 ||
   1005        valueLen > UINT_MAX - nameLen - 2) {
   1006        SECITEM_FreeItem(avaValue, PR_TRUE);
   1007        return SECFailure;
   1008    }
   1009    len = nameLen + valueLen + 2; /* Add 2 for '=' and trailing NUL */
   1010 
   1011    maxName = nameLen;
   1012    maxValue = valueLen;
   1013    if (len <= sizeof(tmpBuf)) {
   1014        encodedAVA = tmpBuf;
   1015    } else if (strict != CERT_N2A_READABLE) {
   1016        encodedAVA = PORT_Alloc(len);
   1017        if (!encodedAVA) {
   1018            SECITEM_FreeItem(avaValue, PR_TRUE);
   1019            if (unknownTag)
   1020                PR_smprintf_free(unknownTag);
   1021            return SECFailure;
   1022        }
   1023    } else {
   1024        /* Must make output fit in tmpbuf */
   1025        unsigned int fair = (sizeof tmpBuf) / 2 - 1; /* for = and \0 */
   1026 
   1027        if (nameLen < fair) {
   1028            /* just truncate the value */
   1029            maxValue = (sizeof tmpBuf) - (nameLen + 6); /* for "=...\0",
   1030                                                     and possibly '"' */
   1031        } else if (valueLen < fair) {
   1032            /* just truncate the name */
   1033            maxName = (sizeof tmpBuf) - (valueLen + 5); /* for "=...\0" */
   1034        } else {
   1035            /* truncate both */
   1036            maxName = maxValue = fair - 3; /* for "..." */
   1037        }
   1038        if (nameLen > maxName) {
   1039            PORT_Assert(unknownTag && unknownTag == tagName);
   1040            truncateName = PR_TRUE;
   1041            nameLen = maxName;
   1042        }
   1043        encodedAVA = tmpBuf;
   1044    }
   1045 
   1046    memcpy(encodedAVA, tagName, nameLen);
   1047    if (truncateName) {
   1048        /* If tag name is too long, we know it is an OID form that was
   1049         * allocated from the heap, so we can modify it in place
   1050         */
   1051        encodedAVA[nameLen - 1] = '.';
   1052        encodedAVA[nameLen - 2] = '.';
   1053        encodedAVA[nameLen - 3] = '.';
   1054    }
   1055    encodedAVA[nameLen++] = '=';
   1056    if (unknownTag)
   1057        PR_smprintf_free(unknownTag);
   1058 
   1059    if (strict == CERT_N2A_READABLE && maxValue > maxBytes)
   1060        maxValue = maxBytes;
   1061    if (valueLen > maxValue) {
   1062        valueLen = maxValue;
   1063        truncateValue = PR_TRUE;
   1064    }
   1065    /* escape and quote as necessary - don't quote hex strings */
   1066    if (useHex) {
   1067        char* end = encodedAVA + nameLen + valueLen;
   1068        memcpy(encodedAVA + nameLen, (char*)avaValue->data, valueLen);
   1069        end[0] = '\0';
   1070        if (truncateValue) {
   1071            end[-1] = '.';
   1072            end[-2] = '.';
   1073            end[-3] = '.';
   1074        }
   1075        rv = SECSuccess;
   1076    } else if (!truncateValue) {
   1077        rv = escapeAndQuote(encodedAVA + nameLen, len - nameLen,
   1078                            (char*)avaValue->data, avaValue->len, &mode);
   1079    } else {
   1080        /* must truncate the escaped and quoted value */
   1081        char bigTmpBuf[TMPBUF_LEN * 3 + 3];
   1082        PORT_Assert(valueLen < sizeof tmpBuf);
   1083        rv = escapeAndQuote(bigTmpBuf, sizeof bigTmpBuf, (char*)avaValue->data,
   1084                            PR_MIN(avaValue->len, valueLen), &mode);
   1085 
   1086        bigTmpBuf[valueLen--] = '\0'; /* hard stop here */
   1087        /* See if we're in the middle of a multi-byte UTF8 character */
   1088        while (((bigTmpBuf[valueLen] & 0xc0) == 0x80) && valueLen > 0) {
   1089            bigTmpBuf[valueLen--] = '\0';
   1090        }
   1091        /* add ellipsis to signify truncation. */
   1092        bigTmpBuf[++valueLen] = '.';
   1093        bigTmpBuf[++valueLen] = '.';
   1094        bigTmpBuf[++valueLen] = '.';
   1095        if (bigTmpBuf[0] == '"')
   1096            bigTmpBuf[++valueLen] = '"';
   1097        bigTmpBuf[++valueLen] = '\0';
   1098        PORT_Assert(nameLen + valueLen <= (sizeof tmpBuf) - 1);
   1099        memcpy(encodedAVA + nameLen, bigTmpBuf, valueLen + 1);
   1100    }
   1101 
   1102    SECITEM_FreeItem(avaValue, PR_TRUE);
   1103    if (rv == SECSuccess)
   1104        rv = AppendStr(bufp, encodedAVA);
   1105    if (encodedAVA != tmpBuf)
   1106        PORT_Free(encodedAVA);
   1107    return rv;
   1108 }
   1109 
   1110 #undef tagName
   1111 #undef maxBytes
   1112 #undef tag
   1113 #undef vt
   1114 
   1115 char*
   1116 CERT_NameToAsciiInvertible(CERTName* name, CertStrictnessLevel strict)
   1117 {
   1118    CERTRDN** rdns;
   1119    CERTRDN** lastRdn;
   1120    CERTRDN** rdn;
   1121    PRBool first = PR_TRUE;
   1122    stringBuf strBuf = { NULL, 0, 0 };
   1123 
   1124    rdns = name->rdns;
   1125    if (rdns == NULL) {
   1126        return NULL;
   1127    }
   1128 
   1129    /* find last RDN */
   1130    lastRdn = rdns;
   1131    while (*lastRdn)
   1132        lastRdn++;
   1133    lastRdn--;
   1134 
   1135    /*
   1136     * Loop over name contents in _reverse_ RDN order appending to string
   1137     */
   1138    for (rdn = lastRdn; rdn >= rdns; rdn--) {
   1139        CERTAVA** avas = (*rdn)->avas;
   1140        CERTAVA* ava;
   1141        PRBool newRDN = PR_TRUE;
   1142 
   1143        /*
   1144         * XXX Do we need to traverse the AVAs in reverse order, too?
   1145         */
   1146        while (avas && (ava = *avas++) != NULL) {
   1147            SECStatus rv;
   1148            /* Put in comma or plus separator */
   1149            if (!first) {
   1150                /* Use of spaces is deprecated in RFC 2253. */
   1151                rv = AppendStr(&strBuf, newRDN ? "," : "+");
   1152                if (rv)
   1153                    goto loser;
   1154            } else {
   1155                first = PR_FALSE;
   1156            }
   1157 
   1158            /* Add in tag type plus value into strBuf */
   1159            rv = AppendAVA(&strBuf, ava, strict);
   1160            if (rv)
   1161                goto loser;
   1162            newRDN = PR_FALSE;
   1163        }
   1164    }
   1165    return strBuf.buffer;
   1166 loser:
   1167    if (strBuf.buffer) {
   1168        PORT_Free(strBuf.buffer);
   1169    }
   1170    return NULL;
   1171 }
   1172 
   1173 char*
   1174 CERT_NameToAscii(CERTName* name)
   1175 {
   1176    return CERT_NameToAsciiInvertible(name, CERT_N2A_READABLE);
   1177 }
   1178 
   1179 /*
   1180 * Return the string representation of a DER encoded distinguished name
   1181 * "dername" - The DER encoded name to convert
   1182 */
   1183 char*
   1184 CERT_DerNameToAscii(SECItem* dername)
   1185 {
   1186    int rv;
   1187    PLArenaPool* arena = NULL;
   1188    CERTName name;
   1189    char* retstr = NULL;
   1190 
   1191    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1192 
   1193    if (arena == NULL) {
   1194        goto loser;
   1195    }
   1196 
   1197    rv = SEC_QuickDERDecodeItem(arena, &name, CERT_NameTemplate, dername);
   1198 
   1199    if (rv != SECSuccess) {
   1200        goto loser;
   1201    }
   1202 
   1203    retstr = CERT_NameToAscii(&name);
   1204 
   1205 loser:
   1206    if (arena != NULL) {
   1207        PORT_FreeArena(arena, PR_FALSE);
   1208    }
   1209 
   1210    return (retstr);
   1211 }
   1212 
   1213 static char*
   1214 avaToString(PLArenaPool* arena, CERTAVA* ava)
   1215 {
   1216    char* buf = NULL;
   1217    SECItem* avaValue;
   1218    int valueLen;
   1219 
   1220    avaValue = CERT_DecodeAVAValue(&ava->value);
   1221    if (!avaValue) {
   1222        return buf;
   1223    }
   1224    int reqLen = cert_RFC1485_GetRequiredLen((char*)avaValue->data, avaValue->len, NULL);
   1225    /* reqLen is max 16384*3 + 2 */
   1226    if (reqLen >= 0) {
   1227        valueLen = reqLen + 1;
   1228        if (arena) {
   1229            buf = (char*)PORT_ArenaZAlloc(arena, valueLen);
   1230        } else {
   1231            buf = (char*)PORT_ZAlloc(valueLen);
   1232        }
   1233        if (buf) {
   1234            SECStatus rv =
   1235                escapeAndQuote(buf, valueLen, (char*)avaValue->data, avaValue->len, NULL);
   1236            if (rv != SECSuccess) {
   1237                if (!arena)
   1238                    PORT_Free(buf);
   1239                buf = NULL;
   1240            }
   1241        }
   1242    }
   1243    SECITEM_FreeItem(avaValue, PR_TRUE);
   1244    return buf;
   1245 }
   1246 
   1247 /* RDNs are sorted from most general to most specific.
   1248 * This code returns the FIRST one found, the most general one found.
   1249 */
   1250 static char*
   1251 CERT_GetNameElement(PLArenaPool* arena, const CERTName* name, int wantedTag)
   1252 {
   1253    CERTRDN** rdns = name->rdns;
   1254    CERTRDN* rdn;
   1255    CERTAVA* ava = NULL;
   1256 
   1257    while (rdns && (rdn = *rdns++) != 0) {
   1258        CERTAVA** avas = rdn->avas;
   1259        while (avas && (ava = *avas++) != 0) {
   1260            int tag = CERT_GetAVATag(ava);
   1261            if (tag == wantedTag) {
   1262                avas = NULL;
   1263                rdns = NULL; /* break out of all loops */
   1264            }
   1265        }
   1266    }
   1267    return ava ? avaToString(arena, ava) : NULL;
   1268 }
   1269 
   1270 /* RDNs are sorted from most general to most specific.
   1271 * This code returns the LAST one found, the most specific one found.
   1272 * This is particularly appropriate for Common Name.  See RFC 2818.
   1273 */
   1274 static char*
   1275 CERT_GetLastNameElement(PLArenaPool* arena, const CERTName* name, int wantedTag)
   1276 {
   1277    CERTRDN** rdns = name->rdns;
   1278    CERTRDN* rdn;
   1279    CERTAVA* lastAva = NULL;
   1280 
   1281    while (rdns && (rdn = *rdns++) != 0) {
   1282        CERTAVA** avas = rdn->avas;
   1283        CERTAVA* ava;
   1284        while (avas && (ava = *avas++) != 0) {
   1285            int tag = CERT_GetAVATag(ava);
   1286            if (tag == wantedTag) {
   1287                lastAva = ava;
   1288            }
   1289        }
   1290    }
   1291    return lastAva ? avaToString(arena, lastAva) : NULL;
   1292 }
   1293 
   1294 char*
   1295 CERT_GetCertificateEmailAddress(CERTCertificate* cert)
   1296 {
   1297    char* rawEmailAddr = NULL;
   1298    SECItem subAltName;
   1299    SECStatus rv;
   1300    CERTGeneralName* nameList = NULL;
   1301    CERTGeneralName* current;
   1302    PLArenaPool* arena = NULL;
   1303    int i;
   1304 
   1305    subAltName.data = NULL;
   1306 
   1307    rawEmailAddr = CERT_GetNameElement(cert->arena, &(cert->subject),
   1308                                       SEC_OID_PKCS9_EMAIL_ADDRESS);
   1309    if (rawEmailAddr == NULL) {
   1310        rawEmailAddr =
   1311            CERT_GetNameElement(cert->arena, &(cert->subject), SEC_OID_RFC1274_MAIL);
   1312    }
   1313    if (rawEmailAddr == NULL) {
   1314 
   1315        rv =
   1316            CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName);
   1317        if (rv != SECSuccess) {
   1318            goto finish;
   1319        }
   1320        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1321        if (!arena) {
   1322            goto finish;
   1323        }
   1324        nameList = current = CERT_DecodeAltNameExtension(arena, &subAltName);
   1325        if (!nameList) {
   1326            goto finish;
   1327        }
   1328        if (nameList != NULL) {
   1329            do {
   1330                if (current->type == certDirectoryName) {
   1331                    rawEmailAddr =
   1332                        CERT_GetNameElement(cert->arena, &(current->name.directoryName),
   1333                                            SEC_OID_PKCS9_EMAIL_ADDRESS);
   1334                    if (rawEmailAddr ==
   1335                        NULL) {
   1336                        rawEmailAddr =
   1337                            CERT_GetNameElement(cert->arena, &(current->name.directoryName),
   1338                                                SEC_OID_RFC1274_MAIL);
   1339                    }
   1340                } else if (current->type == certRFC822Name) {
   1341                    rawEmailAddr =
   1342                        (char*)PORT_ArenaZAlloc(cert->arena, current->name.other.len + 1);
   1343                    if (!rawEmailAddr) {
   1344                        goto finish;
   1345                    }
   1346                    PORT_Memcpy(rawEmailAddr, current->name.other.data,
   1347                                current->name.other.len);
   1348                    rawEmailAddr[current->name.other.len] =
   1349                        '\0';
   1350                }
   1351                if (rawEmailAddr) {
   1352                    break;
   1353                }
   1354                current = CERT_GetNextGeneralName(current);
   1355            } while (current != nameList);
   1356        }
   1357    }
   1358    if (rawEmailAddr) {
   1359        for (i = 0; i <= (int)PORT_Strlen(rawEmailAddr); i++) {
   1360            rawEmailAddr[i] = tolower((unsigned char)rawEmailAddr[i]);
   1361        }
   1362    }
   1363 
   1364 finish:
   1365 
   1366    /* Don't free nameList, it's part of the arena. */
   1367 
   1368    if (arena) {
   1369        PORT_FreeArena(arena, PR_FALSE);
   1370    }
   1371 
   1372    if (subAltName.data) {
   1373        SECITEM_FreeItem(&subAltName, PR_FALSE);
   1374    }
   1375 
   1376    return (rawEmailAddr);
   1377 }
   1378 
   1379 static char*
   1380 appendStringToBuf(char* dest, char* src, PRUint32* pRemaining)
   1381 {
   1382    PRUint32 len;
   1383    if (dest && src && src[0] && *pRemaining > (len = PL_strlen(src))) {
   1384        PRUint32 i;
   1385        for (i = 0; i < len; ++i)
   1386            dest[i] = tolower((unsigned char)src[i]);
   1387        dest[len] = 0;
   1388        dest += len + 1;
   1389        *pRemaining -= len + 1;
   1390    }
   1391    return dest;
   1392 }
   1393 
   1394 #undef NEEDS_HEX_ESCAPE
   1395 #define NEEDS_HEX_ESCAPE(c) (c < 0x20)
   1396 
   1397 static char*
   1398 appendItemToBuf(char* dest, SECItem* src, PRUint32* pRemaining)
   1399 {
   1400    if (dest && src && src->data && src->len && src->data[0]) {
   1401        PRUint32 len = src->len;
   1402        PRUint32 i;
   1403        PRUint32 reqLen = len + 1;
   1404        /* are there any embedded control characters ? */
   1405        for (i = 0; i < len; i++) {
   1406            if (NEEDS_HEX_ESCAPE(src->data[i]))
   1407                reqLen += 2;
   1408        }
   1409        if (*pRemaining > reqLen) {
   1410            for (i = 0; i < len; ++i) {
   1411                PRUint8 c = src->data[i];
   1412                if (NEEDS_HEX_ESCAPE(c)) {
   1413                    *dest++ =
   1414                        C_BACKSLASH;
   1415                    *dest++ =
   1416                        hexChars[(c >> 4) & 0x0f];
   1417                    *dest++ =
   1418                        hexChars[c & 0x0f];
   1419                } else {
   1420                    *dest++ =
   1421                        tolower(c);
   1422                }
   1423            }
   1424            *dest++ = '\0';
   1425            *pRemaining -= reqLen;
   1426        }
   1427    }
   1428    return dest;
   1429 }
   1430 
   1431 /* Returns a pointer to an environment-like string, a series of
   1432 ** null-terminated strings, terminated by a zero-length string.
   1433 ** This function is intended to be internal to NSS.
   1434 */
   1435 char*
   1436 cert_GetCertificateEmailAddresses(CERTCertificate* cert)
   1437 {
   1438    char* rawEmailAddr = NULL;
   1439    char* addrBuf = NULL;
   1440    char* pBuf = NULL;
   1441    PORTCheapArenaPool tmpArena;
   1442    PRUint32 maxLen = 0;
   1443    PRInt32 finalLen = 0;
   1444    SECStatus rv;
   1445    SECItem subAltName;
   1446 
   1447    PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE);
   1448 
   1449    subAltName.data = NULL;
   1450    maxLen = cert->derCert.len;
   1451    PORT_Assert(maxLen);
   1452    if (!maxLen)
   1453        maxLen = 2000; /* a guess, should never happen */
   1454 
   1455    pBuf = addrBuf = (char*)PORT_ArenaZAlloc(&tmpArena.arena, maxLen + 1);
   1456    if (!addrBuf)
   1457        goto loser;
   1458 
   1459    rawEmailAddr = CERT_GetNameElement(&tmpArena.arena, &cert->subject,
   1460                                       SEC_OID_PKCS9_EMAIL_ADDRESS);
   1461    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
   1462 
   1463    rawEmailAddr = CERT_GetNameElement(&tmpArena.arena, &cert->subject,
   1464                                       SEC_OID_RFC1274_MAIL);
   1465    pBuf = appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
   1466 
   1467    rv = CERT_FindCertExtension(cert, SEC_OID_X509_SUBJECT_ALT_NAME, &subAltName);
   1468    if (rv == SECSuccess && subAltName.data) {
   1469        CERTGeneralName* nameList = NULL;
   1470 
   1471        if (!!(nameList = CERT_DecodeAltNameExtension(&tmpArena.arena, &subAltName))) {
   1472            CERTGeneralName* current = nameList;
   1473            do {
   1474                if (current->type == certDirectoryName) {
   1475                    rawEmailAddr =
   1476                        CERT_GetNameElement(&tmpArena.arena,
   1477                                            &current->name.directoryName,
   1478                                            SEC_OID_PKCS9_EMAIL_ADDRESS);
   1479                    pBuf =
   1480                        appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
   1481 
   1482                    rawEmailAddr =
   1483                        CERT_GetNameElement(&tmpArena.arena,
   1484                                            &current->name.directoryName,
   1485                                            SEC_OID_RFC1274_MAIL);
   1486                    pBuf =
   1487                        appendStringToBuf(pBuf, rawEmailAddr, &maxLen);
   1488                } else if (current->type == certRFC822Name) {
   1489                    pBuf =
   1490                        appendItemToBuf(pBuf, &current->name.other, &maxLen);
   1491                }
   1492                current = CERT_GetNextGeneralName(current);
   1493            } while (current != nameList);
   1494        }
   1495        SECITEM_FreeItem(&subAltName, PR_FALSE);
   1496        /* Don't free nameList, it's part of the tmpArena. */
   1497    }
   1498    /* now copy superstring to cert's arena */
   1499    finalLen = (pBuf - addrBuf) + 1;
   1500    pBuf = NULL;
   1501    if (finalLen > 1) {
   1502        pBuf = PORT_ArenaAlloc(cert->arena, finalLen);
   1503        if (pBuf) {
   1504            PORT_Memcpy(pBuf, addrBuf, finalLen);
   1505        }
   1506    }
   1507 loser:
   1508    PORT_DestroyCheapArena(&tmpArena);
   1509 
   1510    return pBuf;
   1511 }
   1512 
   1513 /* returns pointer to storage in cert's arena.  Storage remains valid
   1514 ** as long as cert's reference count doesn't go to zero.
   1515 ** Caller should strdup or otherwise copy.
   1516 */
   1517 const char* /* const so caller won't muck with it. */
   1518 CERT_GetFirstEmailAddress(CERTCertificate* cert)
   1519 {
   1520    if (cert && cert->emailAddr && cert->emailAddr[0])
   1521        return (const char*)cert->emailAddr;
   1522    return NULL;
   1523 }
   1524 
   1525 /* returns pointer to storage in cert's arena.  Storage remains valid
   1526 ** as long as cert's reference count doesn't go to zero.
   1527 ** Caller should strdup or otherwise copy.
   1528 */
   1529 const char* /* const so caller won't muck with it. */
   1530 CERT_GetNextEmailAddress(CERTCertificate* cert, const char* prev)
   1531 {
   1532    if (cert && prev && prev[0]) {
   1533        PRUint32 len = PL_strlen(prev);
   1534        prev += len + 1;
   1535        if (prev && prev[0])
   1536            return prev;
   1537    }
   1538    return NULL;
   1539 }
   1540 
   1541 /* This is seriously bogus, now that certs store their email addresses in
   1542 ** subject Alternative Name extensions.
   1543 ** Returns a string allocated by PORT_StrDup, which the caller must free.
   1544 */
   1545 char*
   1546 CERT_GetCertEmailAddress(const CERTName* name)
   1547 {
   1548    char* rawEmailAddr;
   1549    char* emailAddr;
   1550 
   1551    rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_PKCS9_EMAIL_ADDRESS);
   1552    if (rawEmailAddr == NULL) {
   1553        rawEmailAddr = CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_MAIL);
   1554    }
   1555    emailAddr = CERT_FixupEmailAddr(rawEmailAddr);
   1556    if (rawEmailAddr) {
   1557        PORT_Free(rawEmailAddr);
   1558    }
   1559    return (emailAddr);
   1560 }
   1561 
   1562 /* The return value must be freed with PORT_Free. */
   1563 char*
   1564 CERT_GetCommonName(const CERTName* name)
   1565 {
   1566    return (CERT_GetLastNameElement(NULL, name, SEC_OID_AVA_COMMON_NAME));
   1567 }
   1568 
   1569 char*
   1570 CERT_GetCountryName(const CERTName* name)
   1571 {
   1572    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_COUNTRY_NAME));
   1573 }
   1574 
   1575 char*
   1576 CERT_GetLocalityName(const CERTName* name)
   1577 {
   1578    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_LOCALITY));
   1579 }
   1580 
   1581 char*
   1582 CERT_GetStateName(const CERTName* name)
   1583 {
   1584    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_STATE_OR_PROVINCE));
   1585 }
   1586 
   1587 char*
   1588 CERT_GetOrgName(const CERTName* name)
   1589 {
   1590    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATION_NAME));
   1591 }
   1592 
   1593 char*
   1594 CERT_GetDomainComponentName(const CERTName* name)
   1595 {
   1596    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_DC));
   1597 }
   1598 
   1599 char*
   1600 CERT_GetOrgUnitName(const CERTName* name)
   1601 {
   1602    return (
   1603        CERT_GetNameElement(NULL, name, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME));
   1604 }
   1605 
   1606 char*
   1607 CERT_GetDnQualifier(const CERTName* name)
   1608 {
   1609    return (CERT_GetNameElement(NULL, name, SEC_OID_AVA_DN_QUALIFIER));
   1610 }
   1611 
   1612 char*
   1613 CERT_GetCertUid(const CERTName* name)
   1614 {
   1615    return (CERT_GetNameElement(NULL, name, SEC_OID_RFC1274_UID));
   1616 }