tor-browser

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

pkix_pl_common.c (37447B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * pkix_common.c
      6 *
      7 * Common utility functions used by various PKIX_PL functions
      8 *
      9 */
     10 
     11 #include "pkix_pl_common.h"
     12 
     13 /* --Private-Functions-------------------------------------------- */
     14 
     15 /*
     16 * FUNCTION: pkix_LockObject
     17 * DESCRIPTION:
     18 *
     19 *  Locks the object pointed to by "object".
     20 *
     21 * PARAMETERS:
     22 *  "object"
     23 *      Address of object. Must be non-NULL
     24 *  "plContext"
     25 *      Platform-specific context pointer.
     26 * THREAD SAFETY:
     27 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
     28 * RETURNS:
     29 *  Returns NULL if the function succeeds
     30 *  Returns a Fatal Error if the function fails in an unrecoverable way.
     31 */
     32 PKIX_Error *
     33 pkix_LockObject(
     34        PKIX_PL_Object *object,
     35        void *plContext)
     36 {
     37        PKIX_PL_Object *objectHeader;
     38 
     39        PKIX_ENTER(OBJECT, "pkix_LockObject");
     40        PKIX_NULLCHECK_ONE(object);
     41 
     42        if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) {
     43                goto cleanup;
     44        }
     45 
     46        PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
     47        /* The header is sizeof(PKIX_PL_Object) before the object pointer */
     48 
     49        objectHeader = object-1;
     50 
     51        PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
     52        PR_Lock(objectHeader->lock);
     53 
     54 cleanup:
     55 
     56        PKIX_RETURN(OBJECT);
     57 }
     58 
     59 /*
     60 * FUNCTION: pkix_UnlockObject
     61 * DESCRIPTION:
     62 *
     63 *  Unlocks the object pointed to by "object".
     64 *
     65 * PARAMETERS:
     66 *  "object"
     67 *      Address of Object. Must be non-NULL
     68 *  "plContext"
     69 *      Platform-specific context pointer.
     70 * THREAD SAFETY:
     71 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
     72 * RETURNS:
     73 *  Returns NULL if the function succeeds.
     74 *  Returns a Fatal Error if the function fails in an unrecoverable way.
     75 */
     76 PKIX_Error *
     77 pkix_UnlockObject(
     78        PKIX_PL_Object *object,
     79        void *plContext)
     80 {
     81        PKIX_PL_Object *objectHeader;
     82        PRStatus result;
     83 
     84        PKIX_ENTER(OBJECT, "pkix_UnlockObject");
     85        PKIX_NULLCHECK_ONE(object);
     86 
     87        if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) {
     88                goto cleanup;
     89        }
     90 
     91        PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
     92        /* The header is sizeof(PKIX_PL_Object) before the object pointer */
     93 
     94        objectHeader = object-1;
     95 
     96        PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
     97        result = PR_Unlock(objectHeader->lock);
     98 
     99        if (result == PR_FAILURE) {
    100                PKIX_OBJECT_DEBUG("\tPR_Unlock failed.).\n");
    101                PKIX_ERROR_FATAL(PKIX_ERRORUNLOCKINGOBJECT);
    102        }
    103 
    104 cleanup:
    105 
    106        PKIX_RETURN(OBJECT);
    107 }
    108 
    109 /*
    110 * FUNCTION: pkix_pl_UInt32_Overflows
    111 * DESCRIPTION:
    112 *
    113 *  Returns a PKIX_Boolean indicating whether the unsigned integer
    114 *  represented by "string" is too large to fit in 32-bits (i.e.
    115 *  whether it overflows). With the exception of the string "0",
    116 *  all other strings are stripped of any leading zeros. It is assumed
    117 *  that every character in "string" is from the set {'0' - '9'}.
    118 *
    119 * PARAMETERS
    120 *  "string"
    121 *      Address of array of bytes representing PKIX_UInt32 that's being tested
    122 *      for 32-bit overflow
    123 * THREAD SAFETY:
    124 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    125 * RETURNS:
    126 *  PKIX_TRUE if PKIX_UInt32 represented by "string" overflows;
    127 *  PKIX_FALSE otherwise
    128 */
    129 PKIX_Boolean
    130 pkix_pl_UInt32_Overflows(char *string){
    131        char *firstNonZero = NULL;
    132        PKIX_UInt32 length, i;
    133        char *MAX_UINT32_STRING = "4294967295";
    134 
    135        PKIX_DEBUG_ENTER(OID);
    136 
    137        PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
    138        length = PL_strlen(string);
    139 
    140        if (length < MAX_DIGITS_32){
    141                return (PKIX_FALSE);
    142        }
    143 
    144        firstNonZero = string;
    145        for (i = 0; i < length; i++){
    146                if (*string == '0'){
    147                        firstNonZero++;
    148                }
    149        }
    150 
    151        PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
    152        length = PL_strlen(firstNonZero);
    153 
    154        if (length > MAX_DIGITS_32){
    155                return (PKIX_TRUE);
    156        }
    157 
    158        PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
    159        if (length == MAX_DIGITS_32){
    160                PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n");
    161                if (PORT_Strcmp(firstNonZero, MAX_UINT32_STRING) > 0){
    162                        return (PKIX_TRUE);
    163                }
    164        }
    165 
    166        return (PKIX_FALSE);
    167 }
    168 
    169 /*
    170 * FUNCTION: pkix_pl_getOIDToken
    171 * DESCRIPTION:
    172 *
    173 *  Takes the array of DER-encoded bytes pointed to by "derBytes"
    174 *  (representing an OID) and the value of "index" representing the index into
    175 *  the array, and decodes the bytes until an integer token is retrieved. If
    176 *  successful, this function stores the integer component at "pToken" and
    177 *  stores the index representing the next byte in the array at "pIndex"
    178 *  (following the last byte that was used in the decoding). This new output
    179 *  index can be used in subsequent calls as an input index, allowing each
    180 *  token of the OID to be retrieved consecutively. Note that there is a
    181 *  special case for the first byte, in that it encodes two separate integer
    182 *  tokens. For example, the byte {2a} represents the integer tokens {1,2}.
    183 *  This special case is not handled here and must be handled by the caller.
    184 *
    185 * PARAMETERS
    186 *  "derBytes"
    187 *      Address of array of bytes representing a DER-encoded OID.
    188 *      Must be non-NULL.
    189 *  "index"
    190 *      Index into the array that this function will begin decoding at.
    191 *  "pToken"
    192 *      Destination for decoded OID token. Must be non-NULL.
    193 *  "pIndex"
    194 *      Destination for index of next byte following last byte used.
    195 *      Must be non-NULL.
    196 *  "plContext"
    197 *      Platform-specific context pointer.
    198 * THREAD SAFETY:
    199 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    200 * RETURNS:
    201 *  Returns NULL if the function succeeds.
    202 *  Returns an Object Error if the function fails in a non-fatal way.
    203 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    204 */
    205 static PKIX_Error *
    206 pkix_pl_getOIDToken(
    207        char *derBytes,
    208        PKIX_UInt32 index,
    209        PKIX_UInt32 *pToken,
    210        PKIX_UInt32 *pIndex,
    211        void *plContext)
    212 {
    213        PKIX_UInt32 retval, i, tmp;
    214 
    215        PKIX_ENTER(OID, "pkix_pl_getOIDToken");
    216        PKIX_NULLCHECK_THREE(derBytes, pToken, pIndex);
    217 
    218        /*
    219         * We should only need to parse a maximum of four bytes, because
    220         * RFC 3280 "mandates support for OIDs which have arc elements
    221         * with values that are less than 2^28, that is, they MUST be between
    222         * 0 and 268,435,455, inclusive.  This allows each arc element to be
    223         * represented within a single 32 bit word."
    224         */
    225 
    226        for (i = 0, retval = 0; i < 4; i++) {
    227            retval <<= 7;
    228            tmp = derBytes[index];
    229            index++;
    230            retval |= (tmp & 0x07f);
    231            if ((tmp & 0x080) == 0){
    232                    *pToken = retval;
    233                    *pIndex = index;
    234                    goto cleanup;
    235            }
    236        }
    237 
    238        PKIX_ERROR(PKIX_INVALIDENCODINGOIDTOKENVALUETOOBIG);
    239 
    240 cleanup:
    241 
    242        PKIX_RETURN(OID);
    243 
    244 }
    245 
    246 /*
    247 * FUNCTION: pkix_pl_helperBytes2Ascii
    248 * DESCRIPTION:
    249 *
    250 *  Converts an array of integers pointed to by "tokens" with a length of
    251 *  "numTokens", to an ASCII string consisting of those integers with dots in
    252 *  between them and stores the result at "pAscii". The ASCII representation is
    253 *  guaranteed to end with a NUL character. This is particularly useful for
    254 *  OID's and IP Addresses.
    255 *
    256 *  The return value "pAscii" is not reference-counted and will need to
    257 *  be freed with PKIX_PL_Free.
    258 *
    259 * PARAMETERS
    260 *  "tokens"
    261 *      Address of array of integers. Must be non-NULL.
    262 *  "numTokens"
    263 *      Length of array of integers. Must be non-zero.
    264 *  "pAscii"
    265 *      Address where object pointer will be stored. Must be non-NULL.
    266 *  "plContext"
    267 *      Platform-specific context pointer.
    268 * THREAD SAFETY:
    269 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    270 * RETURNS:
    271 *  Returns NULL if the function succeeds.
    272 *  Returns an Object Error if the function fails in a non-fatal way.
    273 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    274 */
    275 PKIX_Error *
    276 pkix_pl_helperBytes2Ascii(
    277        PKIX_UInt32 *tokens,
    278        PKIX_UInt32 numTokens,
    279        char **pAscii,
    280        void *plContext)
    281 {
    282        char *tempString = NULL;
    283        char *outputString = NULL;
    284        char *format = "%d";
    285        PKIX_UInt32 i = 0;
    286        PKIX_UInt32 outputLen = 0;
    287        PKIX_Int32 error;
    288 
    289        PKIX_ENTER(OBJECT, "pkix_pl_helperBytes2Ascii");
    290        PKIX_NULLCHECK_TWO(tokens, pAscii);
    291 
    292        if (numTokens == 0) {
    293                PKIX_ERROR_FATAL(PKIX_HELPERBYTES2ASCIINUMTOKENSZERO);
    294        }
    295 
    296        /*
    297         * tempString will hold the string representation of a PKIX_UInt32 type
    298         * The maximum value that can be held by an unsigned 32-bit integer
    299         * is (2^32 - 1) = 4294967295 (which is ten digits long)
    300         * Since tempString will hold the string representation of a
    301         * PKIX_UInt32, we allocate 11 bytes for it (1 byte for '\0')
    302         */
    303 
    304        PKIX_CHECK(PKIX_PL_Malloc
    305                    (MAX_DIGITS_32 + 1, (void **)&tempString, plContext),
    306                    PKIX_MALLOCFAILED);
    307 
    308        for (i = 0; i < numTokens; i++){
    309                PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n");
    310                error = PR_snprintf(tempString,
    311                                    MAX_DIGITS_32 + 1,
    312                                    format,
    313                                    tokens[i]);
    314                if (error == -1){
    315                        PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
    316                }
    317 
    318                PKIX_OBJECT_DEBUG("\tCalling PL_strlen).\n");
    319                outputLen += PL_strlen(tempString);
    320 
    321                /* Include a dot to separate each number */
    322                outputLen++;
    323        }
    324 
    325        /* Allocate space for the destination string */
    326        PKIX_CHECK(PKIX_PL_Malloc
    327                    (outputLen, (void **)&outputString, plContext),
    328                    PKIX_MALLOCFAILED);
    329 
    330        *outputString = '\0';
    331 
    332        /* Concatenate all strings together */
    333        for (i = 0; i < numTokens; i++){
    334 
    335                PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n");
    336                error = PR_snprintf(tempString,
    337                                    MAX_DIGITS_32 + 1,
    338                                    format,
    339                                    tokens[i]);
    340                if (error == -1){
    341                        PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
    342                }
    343 
    344                PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n");
    345                (void) PL_strcat(outputString, tempString);
    346 
    347                /* we don't want to put a "." at the very end */
    348                if (i < (numTokens - 1)){
    349                        PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n");
    350                        (void) PL_strcat(outputString, ".");
    351                }
    352        }
    353 
    354        /* Ensure output string ends with terminating null */
    355        outputString[outputLen-1] = '\0';
    356 
    357        *pAscii = outputString;
    358        outputString = NULL;
    359 
    360 cleanup:
    361        
    362        PKIX_FREE(outputString);
    363        PKIX_FREE(tempString);
    364 
    365        PKIX_RETURN(OBJECT);
    366 
    367 }
    368 
    369 /*
    370 * FUNCTION: pkix_pl_ipAddrBytes2Ascii
    371 * DESCRIPTION:
    372 *
    373 *  Converts the DER encoding of an IPAddress pointed to by "secItem" to an
    374 *  ASCII representation and stores the result at "pAscii". The ASCII
    375 *  representation is guaranteed to end with a NUL character. The input
    376 *  SECItem must contain non-NULL data and must have a positive length.
    377 *
    378 *  The return value "pAscii" is not reference-counted and will need to
    379 *  be freed with PKIX_PL_Free.
    380 *  XXX this function assumes that IPv4 addresses are being used
    381 *  XXX what about IPv6? can NSS tell the difference
    382 *
    383 * PARAMETERS
    384 *  "secItem"
    385 *      Address of SECItem which contains bytes and length of DER encoding.
    386 *      Must be non-NULL.
    387 *  "pAscii"
    388 *      Address where object pointer will be stored. Must be non-NULL.
    389 *  "plContext"
    390 *      Platform-specific context pointer.
    391 * THREAD SAFETY:
    392 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    393 * RETURNS:
    394 *  Returns NULL if the function succeeds.
    395 *  Returns an Object Error if the function fails in a non-fatal way.
    396 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    397 */
    398 PKIX_Error *
    399 pkix_pl_ipAddrBytes2Ascii(
    400        SECItem *secItem,
    401        char **pAscii,
    402        void *plContext)
    403 {
    404        char *data = NULL;
    405        PKIX_UInt32 *tokens = NULL;
    406        PKIX_UInt32 numTokens = 0;
    407        PKIX_UInt32 i = 0;
    408        char *asciiString = NULL;
    409 
    410        PKIX_ENTER(OBJECT, "pkix_pl_ipAddrBytes2Ascii");
    411        PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data);
    412 
    413        if (secItem->len == 0) {
    414                PKIX_ERROR_FATAL(PKIX_IPADDRBYTES2ASCIIDATALENGTHZERO);
    415        }
    416 
    417        data = (char *)(secItem->data);
    418        numTokens = secItem->len;
    419 
    420        /* allocate space for array of integers */
    421        PKIX_CHECK(PKIX_PL_Malloc
    422                    (numTokens * sizeof (PKIX_UInt32),
    423                    (void **)&tokens,
    424                    plContext),
    425                    PKIX_MALLOCFAILED);
    426 
    427        /* populate array of integers */
    428        for (i = 0; i < numTokens; i++){
    429                tokens[i] = data[i];
    430        }
    431 
    432        /* convert array of integers to ASCII */
    433        PKIX_CHECK(pkix_pl_helperBytes2Ascii
    434                    (tokens, numTokens, &asciiString, plContext),
    435                    PKIX_HELPERBYTES2ASCIIFAILED);
    436 
    437        *pAscii = asciiString;
    438 
    439 cleanup:
    440 
    441        PKIX_FREE(tokens);
    442 
    443        PKIX_RETURN(OBJECT);
    444 }
    445 
    446 
    447 /*
    448 * FUNCTION: pkix_pl_oidBytes2Ascii
    449 * DESCRIPTION:
    450 *
    451 *  Converts the DER encoding of an OID pointed to by "secItem" to an ASCII
    452 *  representation and stores it at "pAscii". The ASCII representation is
    453 *  guaranteed to end with a NUL character. The input SECItem must contain
    454 *  non-NULL data and must have a positive length.
    455 *
    456 *  Example: the six bytes {2a 86 48 86 f7 0d} represent the
    457 *  four integer tokens {1, 2, 840, 113549}, which we will convert
    458 *  into ASCII yielding "1.2.840.113549"
    459 *
    460 *  The return value "pAscii" is not reference-counted and will need to
    461 *  be freed with PKIX_PL_Free.
    462 *
    463 * PARAMETERS
    464 *  "secItem"
    465 *      Address of SECItem which contains bytes and length of DER encoding.
    466 *      Must be non-NULL.
    467 *  "pAscii"
    468 *      Address where object pointer will be stored. Must be non-NULL.
    469 *  "plContext"
    470 *      Platform-specific context pointer.
    471 * THREAD SAFETY:
    472 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    473 * RETURNS:
    474 *  Returns NULL if the function succeeds.
    475 *  Returns an OID Error if the function fails in a non-fatal way.
    476 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    477 */
    478 PKIX_Error *
    479 pkix_pl_oidBytes2Ascii(
    480        SECItem *secItem,
    481        char **pAscii,
    482        void *plContext)
    483 {
    484        char *data = NULL;
    485        PKIX_UInt32 *tokens = NULL;
    486        PKIX_UInt32 token = 0;
    487        PKIX_UInt32 numBytes = 0;
    488        PKIX_UInt32 numTokens = 0;
    489        PKIX_UInt32 i = 0, x = 0, y = 0;
    490        PKIX_UInt32 index = 0;
    491        char *asciiString = NULL;
    492 
    493        PKIX_ENTER(OID, "pkix_pl_oidBytes2Ascii");
    494        PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data);
    495 
    496        if (secItem->len == 0) {
    497                PKIX_ERROR_FATAL(PKIX_OIDBYTES2ASCIIDATALENGTHZERO);
    498        }
    499 
    500        data = (char *)(secItem->data);
    501        numBytes = secItem->len;
    502        numTokens = 0;
    503 
    504        /* calculate how many integer tokens are represented by the bytes. */
    505        for (i = 0; i < numBytes; i++){
    506                if ((data[i] & 0x080) == 0){
    507                        numTokens++;
    508                }
    509        }
    510 
    511        /* if we are unable to retrieve any tokens at all, we throw an error */
    512        if (numTokens == 0){
    513                PKIX_ERROR(PKIX_INVALIDDERENCODINGFOROID);
    514        }
    515 
    516        /* add one more token b/c the first byte always contains two tokens */
    517        numTokens++;
    518 
    519        /* allocate space for array of integers */
    520        PKIX_CHECK(PKIX_PL_Malloc
    521                    (numTokens * sizeof (PKIX_UInt32),
    522                    (void **)&tokens,
    523                    plContext),
    524                    PKIX_MALLOCFAILED);
    525 
    526        /* populate array of integers */
    527        for (i = 0; i < numTokens; i++){
    528 
    529                /* retrieve integer token */
    530                PKIX_CHECK(pkix_pl_getOIDToken
    531                            (data, index, &token, &index, plContext),
    532                            PKIX_GETOIDTOKENFAILED);
    533 
    534                if (i == 0){
    535 
    536                        /*
    537                         * special case: the first DER-encoded byte represents
    538                         * two tokens. We take advantage of fact that first
    539                         * token must be 0, 1, or 2; and second token must be
    540                         * between {0, 39} inclusive if first token is 0 or 1.
    541                         */
    542 
    543                        if (token < 40)
    544                                x = 0;
    545                        else if (token < 80)
    546                                x = 1;
    547                        else
    548                                x = 2;
    549                        y = token - (x * 40);
    550 
    551                        tokens[0] = x;
    552                        tokens[1] = y;
    553                        i++;
    554                } else {
    555                        tokens[i] = token;
    556                }
    557        }
    558 
    559        /* convert array of integers to ASCII */
    560        PKIX_CHECK(pkix_pl_helperBytes2Ascii
    561                    (tokens, numTokens, &asciiString, plContext),
    562                    PKIX_HELPERBYTES2ASCIIFAILED);
    563 
    564        *pAscii = asciiString;
    565 
    566 cleanup:
    567 
    568        PKIX_FREE(tokens);
    569        PKIX_RETURN(OID);
    570 
    571 }
    572 
    573 /*
    574 * FUNCTION: pkix_UTF16_to_EscASCII
    575 * DESCRIPTION:
    576 *
    577 *  Converts array of bytes pointed to by "utf16String" with length of
    578 *  "utf16Length" (which must be even) into a freshly allocated Escaped ASCII
    579 *  string and stores a pointer to that string at "pDest" and stores the
    580 *  string's length at "pLength". The Escaped ASCII string's length does not
    581 *  include the final NUL character. The caller is responsible for freeing
    582 *  "pDest" using PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug
    583 *  encoding.
    584 *
    585 * PARAMETERS:
    586 *  "utf16String"
    587 *      Address of array of bytes representing data source. Must be non-NULL.
    588 *  "utf16Length"
    589 *      Length of data source. Must be even.
    590 *  "debug"
    591 *      Boolean value indicating whether debug mode is desired.
    592 *  "pDest"
    593 *      Address where data will be stored. Must be non-NULL.
    594 *  "pLength"
    595 *      Address where data length will be stored. Must be non-NULL.
    596 *  "plContext"
    597 *      Platform-specific context pointer.
    598 * THREAD SAFETY:
    599 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    600 * RETURNS:
    601 *  Returns NULL if the function succeeds.
    602 *  Returns a String Error if the function fails in a non-fatal way.
    603 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    604 */
    605 PKIX_Error *
    606 pkix_UTF16_to_EscASCII(
    607        const void *utf16String,
    608        PKIX_UInt32 utf16Length,
    609        PKIX_Boolean debug,
    610        char **pDest,
    611        PKIX_UInt32 *pLength,
    612        void *plContext)
    613 {
    614        char *destPtr = NULL;
    615        PKIX_UInt32 i, charLen;
    616        PKIX_UInt32 x = 0, y = 0, z = 0;
    617        unsigned char *utf16Char = (unsigned char *)utf16String;
    618 
    619        PKIX_ENTER(STRING, "pkix_UTF16_to_EscASCII");
    620        PKIX_NULLCHECK_THREE(utf16String, pDest, pLength);
    621 
    622        /* Assume every pair of bytes becomes &#xNNNN; */
    623        charLen = 4*utf16Length;
    624 
    625        /* utf16Lenght must be even */
    626        if ((utf16Length % 2) != 0){
    627                PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR);
    628        }
    629 
    630        /* Count how many bytes we need */
    631        for (i = 0; i < utf16Length; i += 2) {
    632                if ((utf16Char[i] == 0x00)&&
    633                        pkix_isPlaintext(utf16Char[i+1], debug)) {
    634                        if (utf16Char[i+1] == '&') {
    635                                /* Need to convert this to &amp; */
    636                                charLen -= 3;
    637                        } else {
    638                                /* We can fit this into one char */
    639                                charLen -= 7;
    640                        }
    641                } else if ((utf16Char[i] >= 0xD8) && (utf16Char[i] <= 0xDB)) {
    642                        if ((i+3) >= utf16Length) {
    643                                PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR);
    644                        } else if ((utf16Char[i+2] >= 0xDC)&&
    645                                (utf16Char[i+2] <= 0xDF)) {
    646                                /* Quartet of bytes will become &#xNNNNNNNN; */
    647                                charLen -= 4;
    648                                /* Quartet of bytes will produce 12 chars */
    649                                i += 2;
    650                        } else {
    651                                /* Second pair should be DC00-DFFF */
    652                                PKIX_ERROR(PKIX_UTF16LOWZONEERROR);
    653                        }
    654                }
    655        }
    656 
    657        *pLength = charLen;
    658 
    659        /* Ensure this string is null terminated */
    660        charLen++;
    661 
    662        /* Allocate space for character array */
    663        PKIX_CHECK(PKIX_PL_Malloc(charLen, (void **)pDest, plContext),
    664                    PKIX_MALLOCFAILED);
    665 
    666        destPtr = *pDest;
    667        for (i = 0; i < utf16Length; i += 2) {
    668                if ((utf16Char[i] == 0x00)&&
    669                    pkix_isPlaintext(utf16Char[i+1], debug)) {
    670                        /* Write a single character */
    671                        *destPtr++ = utf16Char[i+1];
    672                } else if ((utf16Char[i+1] == '&') && (utf16Char[i] == 0x00)){
    673                        *destPtr++ = '&';
    674                        *destPtr++ = 'a';
    675                        *destPtr++ = 'm';
    676                        *destPtr++ = 'p';
    677                        *destPtr++ = ';';
    678                } else if ((utf16Char[i] >= 0xD8)&&
    679                            (utf16Char[i] <= 0xDB)&&
    680                            (utf16Char[i+2] >= 0xDC)&&
    681                            (utf16Char[i+2] <= 0xDF)) {
    682                        /*
    683                         * Special UTF pairs are of the form:
    684                         * x = D800..DBFF; y = DC00..DFFF;
    685                         * The result is of the form:
    686                         * ((x - D800) * 400 + (y - DC00)) + 0001 0000
    687                         */
    688                        x = 0x0FFFF & ((utf16Char[i]<<8) | utf16Char[i+1]);
    689                        y = 0x0FFFF & ((utf16Char[i+2]<<8) | utf16Char[i+3]);
    690                        z = ((x - 0xD800) * 0x400 + (y - 0xDC00)) + 0x00010000;
    691 
    692                        /* Sprintf &#xNNNNNNNN; */
    693                        PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
    694                        if (PR_snprintf(destPtr, 13, "&#x%08X;", z) ==
    695                            (PKIX_UInt32)(-1)) {
    696                                PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
    697                        }
    698                        i += 2;
    699                        destPtr += 12;
    700                } else {
    701                        /* Sprintf &#xNNNN; */
    702                        PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
    703                        if (PR_snprintf
    704                            (destPtr,
    705                            9,
    706                            "&#x%02X%02X;",
    707                            utf16Char[i],
    708                            utf16Char[i+1]) ==
    709                            (PKIX_UInt32)(-1)) {
    710                                PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
    711                        }
    712                        destPtr += 8;
    713                }
    714        }
    715        *destPtr = '\0';
    716 
    717 cleanup:
    718 
    719        if (PKIX_ERROR_RECEIVED){
    720                PKIX_FREE(*pDest);
    721        }
    722 
    723        PKIX_RETURN(STRING);
    724 }
    725 
    726 /*
    727 * FUNCTION: pkix_EscASCII_to_UTF16
    728 * DESCRIPTION:
    729 *
    730 *  Converts array of bytes pointed to by "escAsciiString" with length of
    731 *  "escAsciiLength" into a freshly allocated UTF-16 string and stores a
    732 *  pointer to that string at "pDest" and stores the string's length at
    733 *  "pLength". The caller is responsible for freeing "pDest" using
    734 *  PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug encoding.
    735 *
    736 * PARAMETERS:
    737 *  "escAsciiString"
    738 *      Address of array of bytes representing data source. Must be non-NULL.
    739 *  "escAsciiLength"
    740 *      Length of data source. Must be even.
    741 *  "debug"
    742 *      Boolean value indicating whether debug mode is desired.
    743 *  "pDest"
    744 *      Address where data will be stored. Must be non-NULL.
    745 *  "pLength"
    746 *      Address where data length will be stored. Must be non-NULL.
    747 *  "plContext"
    748 *      Platform-specific context pointer.
    749 * THREAD SAFETY:
    750 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    751 * RETURNS:
    752 *  Returns NULL if the function succeeds.
    753 *  Returns a String Error if the function fails in a non-fatal way.
    754 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    755 */
    756 PKIX_Error *
    757 pkix_EscASCII_to_UTF16(
    758        const char *escAsciiString,
    759        PKIX_UInt32 escAsciiLen,
    760        PKIX_Boolean debug,
    761        void **pDest,
    762        PKIX_UInt32 *pLength,
    763        void *plContext)
    764 {
    765        PKIX_UInt32 newLen, i, j, charSize;
    766        PKIX_UInt32 x = 0, y = 0, z = 0;
    767        unsigned char *destPtr = NULL;
    768        unsigned char testChar, testChar2;
    769        unsigned char *stringData = (unsigned char *)escAsciiString;
    770 
    771        PKIX_ENTER(STRING, "pkix_EscASCII_to_UTF16");
    772        PKIX_NULLCHECK_THREE(escAsciiString, pDest, pLength);
    773 
    774        if (escAsciiLen == 0) {
    775                PKIX_CHECK(PKIX_PL_Malloc(escAsciiLen, pDest, plContext),
    776                            PKIX_MALLOCFAILED);
    777                goto cleanup;
    778        }
    779 
    780        /* Assume each unicode character takes two bytes */
    781        newLen = escAsciiLen*2;
    782 
    783        /* Count up number of unicode encoded  characters */
    784        for (i = 0; i < escAsciiLen; i++) {
    785                if (!pkix_isPlaintext(stringData[i], debug)&&
    786                    (stringData[i] != '&')) {
    787                        PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII);
    788                } else if (PL_strstr(escAsciiString+i, "&amp;") ==
    789                            escAsciiString+i) {
    790                        /* Convert EscAscii "&amp;" to two bytes */
    791                        newLen -= 8;
    792                        i += 4;
    793                } else if ((PL_strstr(escAsciiString+i, "&#x") ==
    794                            escAsciiString+i)||
    795                            (PL_strstr(escAsciiString+i, "&#X") ==
    796                            escAsciiString+i)) {
    797                        if (((i+7) <= escAsciiLen)&&
    798                            (escAsciiString[i+7] == ';')) {
    799                                /* Convert &#xNNNN; to two bytes */
    800                                newLen -= 14;
    801                                i += 7;
    802                        } else if (((i+11) <= escAsciiLen)&&
    803                                (escAsciiString[i+11] == ';')) {
    804                                /* Convert &#xNNNNNNNN; to four bytes */
    805                                newLen -= 20;
    806                                i += 11;
    807                        } else {
    808                                PKIX_ERROR(PKIX_ILLEGALUSEOFAMP);
    809                        }
    810                }
    811        }
    812 
    813        PKIX_CHECK(PKIX_PL_Malloc(newLen, pDest, plContext),
    814                    PKIX_MALLOCFAILED);
    815 
    816        /* Copy into newly allocated space */
    817        destPtr = (unsigned char *)*pDest;
    818 
    819        i = 0;
    820        while (i < escAsciiLen) {
    821                /* Copy each byte until you hit a &amp; */
    822                if (pkix_isPlaintext(escAsciiString[i], debug)) {
    823                        *destPtr++ = 0x00;
    824                        *destPtr++ = escAsciiString[i++];
    825                } else if (PL_strstr(escAsciiString+i, "&amp;") ==
    826                            escAsciiString+i) {
    827                        /* Convert EscAscii "&amp;" to two bytes */
    828                        *destPtr++ = 0x00;
    829                        *destPtr++ = '&';
    830                        i += 5;
    831                } else if (((PL_strstr(escAsciiString+i, "&#x") ==
    832                            escAsciiString+i)||
    833                            (PL_strstr(escAsciiString+i, "&#X") ==
    834                            escAsciiString+i))&&
    835                            ((i+7) <= escAsciiLen)) {
    836 
    837                        /* We're either looking at &#xNNNN; or &#xNNNNNNNN; */
    838                        charSize = (escAsciiString[i+7] == ';')?4:8;
    839 
    840                        /* Skip past the &#x */
    841                        i += 3;
    842 
    843                        /* Make sure there is a terminating semi-colon */
    844                        if (((i+charSize) > escAsciiLen)||
    845                            (escAsciiString[i+charSize] != ';')) {
    846                                PKIX_ERROR(PKIX_TRUNCATEDUNICODEINESCAPEDASCII);
    847                        }
    848 
    849                        for (j = 0; j < charSize; j++) {
    850                                if (!PKIX_ISXDIGIT
    851                                    (escAsciiString[i+j])) {
    852                                        PKIX_ERROR(PKIX_ILLEGALUNICODECHARACTER);
    853                                } else if (charSize == 8) {
    854                                        x |= (pkix_hex2i
    855                                                        (escAsciiString[i+j]))
    856                                                        <<(4*(7-j));
    857                                }
    858                        }
    859 
    860                        testChar =
    861                                (pkix_hex2i(escAsciiString[i])<<4)|
    862                                pkix_hex2i(escAsciiString[i+1]);
    863                        testChar2 =
    864                                (pkix_hex2i(escAsciiString[i+2])<<4)|
    865                                pkix_hex2i(escAsciiString[i+3]);
    866 
    867                        if (charSize == 4) {
    868                                if ((testChar >= 0xD8)&&
    869                                    (testChar <= 0xDF)) {
    870                                        PKIX_ERROR(PKIX_ILLEGALSURROGATEPAIR);
    871                                } else if ((testChar == 0x00)&&
    872                                  pkix_isPlaintext(testChar2, debug)) {
    873                                      PKIX_ERROR(
    874                                          PKIX_ILLEGALCHARACTERINESCAPEDASCII);
    875                                }
    876                                *destPtr++ = testChar;
    877                                *destPtr++ = testChar2;
    878                        } else if (charSize == 8) {
    879                                /* First two chars must be 0001-0010 */
    880                                if (!((testChar == 0x00)&&
    881                                    ((testChar2 >= 0x01)&&
    882                                    (testChar2 <= 0x10)))) {
    883                                      PKIX_ERROR(
    884                                          PKIX_ILLEGALCHARACTERINESCAPEDASCII);
    885                                }
    886                                /*
    887                                 * Unicode Strings of the form:
    888                                 * x =  0001 0000..0010 FFFF
    889                                 * Encoded as pairs of UTF-16 where
    890                                 * y = ((x - 0001 0000) / 400) + D800
    891                                 * z = ((x - 0001 0000) % 400) + DC00
    892                                 */
    893                                x -= 0x00010000;
    894                                y = (x/0x400)+ 0xD800;
    895                                z = (x%0x400)+ 0xDC00;
    896 
    897                                /* Copy four bytes */
    898                                *destPtr++ = (y&0xFF00)>>8;
    899                                *destPtr++ = (y&0x00FF);
    900                                *destPtr++ = (z&0xFF00)>>8;
    901                                *destPtr++ = (z&0x00FF);
    902                        }
    903                        /* Move past the Hex digits and the semi-colon */
    904                        i += charSize+1;
    905                } else {
    906                        /* Do not allow any other non-plaintext character */
    907                        PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII);
    908                }
    909        }
    910 
    911        *pLength = newLen;
    912 
    913 cleanup:
    914 
    915        if (PKIX_ERROR_RECEIVED){
    916                PKIX_FREE(*pDest);
    917        }
    918 
    919        PKIX_RETURN(STRING);
    920 }
    921 
    922 /*
    923 * FUNCTION: pkix_UTF16_to_UTF8
    924 * DESCRIPTION:
    925 *
    926 *  Converts array of bytes pointed to by "utf16String" with length of
    927 *  "utf16Length" into a freshly allocated UTF-8 string and stores a pointer
    928 *  to that string at "pDest" and stores the string's length at "pLength" (not
    929 *  counting the null terminator, if requested. The caller is responsible for
    930 *  freeing "pDest" using PKIX_PL_Free.
    931 *
    932 * PARAMETERS:
    933 *  "utf16String"
    934 *      Address of array of bytes representing data source. Must be non-NULL.
    935 *  "utf16Length"
    936 *      Length of data source. Must be even.
    937 *  "null-term"
    938 *      Boolean value indicating whether output should be null-terminated.
    939 *  "pDest"
    940 *      Address where data will be stored. Must be non-NULL.
    941 *  "pLength"
    942 *      Address where data length will be stored. Must be non-NULL.
    943 *  "plContext"
    944 *      Platform-specific context pointer.
    945 * THREAD SAFETY:
    946 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    947 * RETURNS:
    948 *  Returns NULL if the function succeeds.
    949 *  Returns a String Error if the function fails in a non-fatal way.
    950 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    951 */
    952 PKIX_Error *
    953 pkix_UTF16_to_UTF8(
    954        const void *utf16String,
    955        PKIX_UInt32 utf16Length,
    956        PKIX_Boolean null_term,
    957        void **pDest,
    958        PKIX_UInt32 *pLength,
    959        void *plContext)
    960 {
    961        PKIX_Boolean result;
    962        PKIX_UInt32 reallocLen;
    963        char *endPtr = NULL;
    964 
    965        PKIX_ENTER(STRING, "pkix_UTF16_to_UTF8");
    966        PKIX_NULLCHECK_THREE(utf16String, pDest, pLength);
    967 
    968        /* XXX How big can a UTF8 string be compared to a UTF16? */
    969        PKIX_CHECK(PKIX_PL_Calloc(1, utf16Length*2, pDest, plContext),
    970                    PKIX_CALLOCFAILED);
    971 
    972        PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n");
    973        result = PORT_UCS2_UTF8Conversion
    974                (PKIX_FALSE, /* False = From UCS2 */
    975                (unsigned char *)utf16String,
    976                utf16Length,
    977                (unsigned char *)*pDest,
    978                utf16Length*2, /* Max Size */
    979                pLength);
    980        if (result == PR_FALSE){
    981                PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED);
    982        }
    983 
    984        reallocLen = *pLength;
    985 
    986        if (null_term){
    987                reallocLen++;
    988        }
    989 
    990        PKIX_CHECK(PKIX_PL_Realloc(*pDest, reallocLen, pDest, plContext),
    991                    PKIX_REALLOCFAILED);
    992 
    993        if (null_term){
    994                endPtr = (char*)*pDest + reallocLen - 1;
    995                *endPtr = '\0';
    996        }
    997 
    998 cleanup:
    999 
   1000        if (PKIX_ERROR_RECEIVED){
   1001                PKIX_FREE(*pDest);
   1002        }
   1003 
   1004        PKIX_RETURN(STRING);
   1005 }
   1006 
   1007 /*
   1008 * FUNCTION: pkix_UTF8_to_UTF16
   1009 * DESCRIPTION:
   1010 *
   1011 *  Converts array of bytes pointed to by "utf8String" with length of
   1012 *  "utf8Length" into a freshly allocated UTF-16 string and stores a pointer
   1013 *  to that string at "pDest" and stores the string's length at "pLength". The
   1014 *  caller is responsible for freeing "pDest" using PKIX_PL_Free.
   1015 *
   1016 * PARAMETERS:
   1017 *  "utf8String"
   1018 *      Address of array of bytes representing data source. Must be non-NULL.
   1019 *  "utf8Length"
   1020 *      Length of data source. Must be even.
   1021 *  "pDest"
   1022 *      Address where data will be stored. Must be non-NULL.
   1023 *  "pLength"
   1024 *      Address where data length will be stored. Must be non-NULL.
   1025 *  "plContext"
   1026 *      Platform-specific context pointer.
   1027 * THREAD SAFETY:
   1028 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
   1029 * RETURNS:
   1030 *  Returns NULL if the function succeeds.
   1031 *  Returns a String Error if the function fails in a non-fatal way.
   1032 *  Returns a Fatal Error if the function fails in an unrecoverable way.
   1033 */
   1034 PKIX_Error *
   1035 pkix_UTF8_to_UTF16(
   1036        const void *utf8String,
   1037        PKIX_UInt32 utf8Length,
   1038        void **pDest,
   1039        PKIX_UInt32 *pLength,
   1040        void *plContext)
   1041 {
   1042        PKIX_Boolean result;
   1043 
   1044        PKIX_ENTER(STRING, "pkix_UTF8_to_UTF16");
   1045        PKIX_NULLCHECK_THREE(utf8String, pDest, pLength);
   1046 
   1047        /* XXX How big can a UTF8 string be compared to a UTF16? */
   1048        PKIX_CHECK(PKIX_PL_Calloc(1, utf8Length*2, pDest, plContext),
   1049                    PKIX_MALLOCFAILED);
   1050 
   1051        PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n");
   1052        result = PORT_UCS2_UTF8Conversion
   1053                (PKIX_TRUE, /* True = From UTF8 */
   1054                (unsigned char *)utf8String,
   1055                utf8Length,
   1056                (unsigned char *)*pDest,
   1057                utf8Length*2, /* Max Size */
   1058                pLength);
   1059        if (result == PR_FALSE){
   1060                PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED);
   1061        }
   1062 
   1063        PKIX_CHECK(PKIX_PL_Realloc(*pDest, *pLength, pDest, plContext),
   1064                    PKIX_REALLOCFAILED);
   1065 
   1066 cleanup:
   1067 
   1068        if (PKIX_ERROR_RECEIVED){
   1069                PKIX_FREE(*pDest);
   1070        }
   1071 
   1072        PKIX_RETURN(STRING);
   1073 }