"Fossies" - the Fresh Open Source Software Archive

Member "nss-3.37.3/nss/lib/certdb/alg1485.c" (5 Jun 2018, 50279 Bytes) of package /linux/misc/nss-3.37.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "alg1485.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.34.1_vs_3.35.

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