Blame nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c

Packit 40b132
/* This Source Code Form is subject to the terms of the Mozilla Public
Packit 40b132
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit 40b132
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit 40b132
/*
Packit 40b132
 * pkix_common.c
Packit 40b132
 *
Packit 40b132
 * Common utility functions used by various PKIX_PL functions
Packit 40b132
 *
Packit 40b132
 */
Packit 40b132
Packit 40b132
#include "pkix_pl_common.h"
Packit 40b132
Packit 40b132
/* --Private-Functions-------------------------------------------- */
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_LockObject
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Locks the object pointed to by "object".
Packit 40b132
 *
Packit 40b132
 * PARAMETERS:
Packit 40b132
 *  "object"
Packit 40b132
 *      Address of object. Must be non-NULL
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_LockObject(
Packit 40b132
        PKIX_PL_Object *object,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        PKIX_PL_Object *objectHeader;
Packit 40b132
Packit 40b132
        PKIX_ENTER(OBJECT, "pkix_LockObject");
Packit 40b132
        PKIX_NULLCHECK_ONE(object);
Packit 40b132
Packit 40b132
        if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) {
Packit 40b132
                goto cleanup;
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
Packit 40b132
        /* The header is sizeof(PKIX_PL_Object) before the object pointer */
Packit 40b132
Packit 40b132
        objectHeader = object-1;
Packit 40b132
Packit 40b132
        PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
Packit 40b132
        PR_Lock(objectHeader->lock);
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        PKIX_RETURN(OBJECT);
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_UnlockObject
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Unlocks the object pointed to by "object".
Packit 40b132
 *
Packit 40b132
 * PARAMETERS:
Packit 40b132
 *  "object"
Packit 40b132
 *      Address of Object. Must be non-NULL
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_UnlockObject(
Packit 40b132
        PKIX_PL_Object *object,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        PKIX_PL_Object *objectHeader;
Packit 40b132
        PRStatus result;
Packit 40b132
Packit 40b132
        PKIX_ENTER(OBJECT, "pkix_UnlockObject");
Packit 40b132
        PKIX_NULLCHECK_ONE(object);
Packit 40b132
Packit 40b132
        if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) {
Packit 40b132
                goto cleanup;
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
Packit 40b132
        /* The header is sizeof(PKIX_PL_Object) before the object pointer */
Packit 40b132
Packit 40b132
        objectHeader = object-1;
Packit 40b132
Packit 40b132
        PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
Packit 40b132
        result = PR_Unlock(objectHeader->lock);
Packit 40b132
Packit 40b132
        if (result == PR_FAILURE) {
Packit 40b132
                PKIX_OBJECT_DEBUG("\tPR_Unlock failed.).\n");
Packit 40b132
                PKIX_ERROR_FATAL(PKIX_ERRORUNLOCKINGOBJECT);
Packit 40b132
        }
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        PKIX_RETURN(OBJECT);
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_pl_UInt32_Overflows
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Returns a PKIX_Boolean indicating whether the unsigned integer
Packit 40b132
 *  represented by "string" is too large to fit in 32-bits (i.e.
Packit 40b132
 *  whether it overflows). With the exception of the string "0",
Packit 40b132
 *  all other strings are stripped of any leading zeros. It is assumed
Packit 40b132
 *  that every character in "string" is from the set {'0' - '9'}.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS
Packit 40b132
 *  "string"
Packit 40b132
 *      Address of array of bytes representing PKIX_UInt32 that's being tested
Packit 40b132
 *      for 32-bit overflow
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  PKIX_TRUE if PKIX_UInt32 represented by "string" overflows;
Packit 40b132
 *  PKIX_FALSE otherwise
Packit 40b132
 */
Packit 40b132
PKIX_Boolean
Packit 40b132
pkix_pl_UInt32_Overflows(char *string){
Packit 40b132
        char *firstNonZero = NULL;
Packit 40b132
        PKIX_UInt32 length, i;
Packit 40b132
        char *MAX_UINT32_STRING = "4294967295";
Packit 40b132
Packit 40b132
        PKIX_DEBUG_ENTER(OID);
Packit 40b132
Packit 40b132
        PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
Packit 40b132
        length = PL_strlen(string);
Packit 40b132
Packit 40b132
        if (length < MAX_DIGITS_32){
Packit 40b132
                return (PKIX_FALSE);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        firstNonZero = string;
Packit 40b132
        for (i = 0; i < length; i++){
Packit 40b132
                if (*string == '0'){
Packit 40b132
                        firstNonZero++;
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
Packit 40b132
        length = PL_strlen(firstNonZero);
Packit 40b132
Packit 40b132
        if (length > MAX_DIGITS_32){
Packit 40b132
                return (PKIX_TRUE);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
Packit 40b132
        if (length == MAX_DIGITS_32){
Packit 40b132
                PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n");
Packit 40b132
                if (PORT_Strcmp(firstNonZero, MAX_UINT32_STRING) > 0){
Packit 40b132
                        return (PKIX_TRUE);
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        return (PKIX_FALSE);
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_pl_getOIDToken
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Takes the array of DER-encoded bytes pointed to by "derBytes"
Packit 40b132
 *  (representing an OID) and the value of "index" representing the index into
Packit 40b132
 *  the array, and decodes the bytes until an integer token is retrieved. If
Packit 40b132
 *  successful, this function stores the integer component at "pToken" and
Packit 40b132
 *  stores the index representing the next byte in the array at "pIndex"
Packit 40b132
 *  (following the last byte that was used in the decoding). This new output
Packit 40b132
 *  index can be used in subsequent calls as an input index, allowing each
Packit 40b132
 *  token of the OID to be retrieved consecutively. Note that there is a
Packit 40b132
 *  special case for the first byte, in that it encodes two separate integer
Packit 40b132
 *  tokens. For example, the byte {2a} represents the integer tokens {1,2}.
Packit 40b132
 *  This special case is not handled here and must be handled by the caller.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS
Packit 40b132
 *  "derBytes"
Packit 40b132
 *      Address of array of bytes representing a DER-encoded OID.
Packit 40b132
 *      Must be non-NULL.
Packit 40b132
 *  "index"
Packit 40b132
 *      Index into the array that this function will begin decoding at.
Packit 40b132
 *  "pToken"
Packit 40b132
 *      Destination for decoded OID token. Must be non-NULL.
Packit 40b132
 *  "pIndex"
Packit 40b132
 *      Destination for index of next byte following last byte used.
Packit 40b132
 *      Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns an Object Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
static PKIX_Error *
Packit 40b132
pkix_pl_getOIDToken(
Packit 40b132
        char *derBytes,
Packit 40b132
        PKIX_UInt32 index,
Packit 40b132
        PKIX_UInt32 *pToken,
Packit 40b132
        PKIX_UInt32 *pIndex,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        PKIX_UInt32 retval, i, tmp;
Packit 40b132
Packit 40b132
        PKIX_ENTER(OID, "pkix_pl_getOIDToken");
Packit 40b132
        PKIX_NULLCHECK_THREE(derBytes, pToken, pIndex);
Packit 40b132
Packit 40b132
        /*
Packit 40b132
         * We should only need to parse a maximum of four bytes, because
Packit 40b132
         * RFC 3280 "mandates support for OIDs which have arc elements
Packit 40b132
         * with values that are less than 2^28, that is, they MUST be between
Packit 40b132
         * 0 and 268,435,455, inclusive.  This allows each arc element to be
Packit 40b132
         * represented within a single 32 bit word."
Packit 40b132
         */
Packit 40b132
Packit 40b132
        for (i = 0, retval = 0; i < 4; i++) {
Packit 40b132
            retval <<= 7;
Packit 40b132
            tmp = derBytes[index];
Packit 40b132
            index++;
Packit 40b132
            retval |= (tmp & 0x07f);
Packit 40b132
            if ((tmp & 0x080) == 0){
Packit 40b132
                    *pToken = retval;
Packit 40b132
                    *pIndex = index;
Packit 40b132
                    goto cleanup;
Packit 40b132
            }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_ERROR(PKIX_INVALIDENCODINGOIDTOKENVALUETOOBIG);
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        PKIX_RETURN(OID);
Packit 40b132
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_pl_helperBytes2Ascii
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Converts an array of integers pointed to by "tokens" with a length of
Packit 40b132
 *  "numTokens", to an ASCII string consisting of those integers with dots in
Packit 40b132
 *  between them and stores the result at "pAscii". The ASCII representation is
Packit 40b132
 *  guaranteed to end with a NUL character. This is particularly useful for
Packit 40b132
 *  OID's and IP Addresses.
Packit 40b132
 *
Packit 40b132
 *  The return value "pAscii" is not reference-counted and will need to
Packit 40b132
 *  be freed with PKIX_PL_Free.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS
Packit 40b132
 *  "tokens"
Packit 40b132
 *      Address of array of integers. Must be non-NULL.
Packit 40b132
 *  "numTokens"
Packit 40b132
 *      Length of array of integers. Must be non-zero.
Packit 40b132
 *  "pAscii"
Packit 40b132
 *      Address where object pointer will be stored. Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns an Object Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_pl_helperBytes2Ascii(
Packit 40b132
        PKIX_UInt32 *tokens,
Packit 40b132
        PKIX_UInt32 numTokens,
Packit 40b132
        char **pAscii,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        char *tempString = NULL;
Packit 40b132
        char *outputString = NULL;
Packit 40b132
        char *format = "%d";
Packit 40b132
        PKIX_UInt32 i = 0;
Packit 40b132
        PKIX_UInt32 outputLen = 0;
Packit 40b132
        PKIX_Int32 error;
Packit 40b132
Packit 40b132
        PKIX_ENTER(OBJECT, "pkix_pl_helperBytes2Ascii");
Packit 40b132
        PKIX_NULLCHECK_TWO(tokens, pAscii);
Packit 40b132
Packit 40b132
        if (numTokens == 0) {
Packit 40b132
                PKIX_ERROR_FATAL(PKIX_HELPERBYTES2ASCIINUMTOKENSZERO);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /*
Packit 40b132
         * tempString will hold the string representation of a PKIX_UInt32 type
Packit 40b132
         * The maximum value that can be held by an unsigned 32-bit integer
Packit 40b132
         * is (2^32 - 1) = 4294967295 (which is ten digits long)
Packit 40b132
         * Since tempString will hold the string representation of a
Packit 40b132
         * PKIX_UInt32, we allocate 11 bytes for it (1 byte for '\0')
Packit 40b132
         */
Packit 40b132
Packit 40b132
        PKIX_CHECK(PKIX_PL_Malloc
Packit 40b132
                    (MAX_DIGITS_32 + 1, (void **)&tempString, plContext),
Packit 40b132
                    PKIX_MALLOCFAILED);
Packit 40b132
Packit 40b132
        for (i = 0; i < numTokens; i++){
Packit 40b132
                PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n");
Packit 40b132
                error = PR_snprintf(tempString,
Packit 40b132
                                    MAX_DIGITS_32 + 1,
Packit 40b132
                                    format,
Packit 40b132
                                    tokens[i]);
Packit 40b132
                if (error == -1){
Packit 40b132
                        PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
Packit 40b132
                }
Packit 40b132
Packit 40b132
                PKIX_OBJECT_DEBUG("\tCalling PL_strlen).\n");
Packit 40b132
                outputLen += PL_strlen(tempString);
Packit 40b132
Packit 40b132
                /* Include a dot to separate each number */
Packit 40b132
                outputLen++;
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* Allocate space for the destination string */
Packit 40b132
        PKIX_CHECK(PKIX_PL_Malloc
Packit 40b132
                    (outputLen, (void **)&outputString, plContext),
Packit 40b132
                    PKIX_MALLOCFAILED);
Packit 40b132
Packit 40b132
        *outputString = '\0';
Packit 40b132
Packit 40b132
        /* Concatenate all strings together */
Packit 40b132
        for (i = 0; i < numTokens; i++){
Packit 40b132
Packit 40b132
                PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n");
Packit 40b132
                error = PR_snprintf(tempString,
Packit 40b132
                                    MAX_DIGITS_32 + 1,
Packit 40b132
                                    format,
Packit 40b132
                                    tokens[i]);
Packit 40b132
                if (error == -1){
Packit 40b132
                        PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
Packit 40b132
                }
Packit 40b132
Packit 40b132
                PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n");
Packit 40b132
                (void) PL_strcat(outputString, tempString);
Packit 40b132
Packit 40b132
                /* we don't want to put a "." at the very end */
Packit 40b132
                if (i < (numTokens - 1)){
Packit 40b132
                        PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n");
Packit 40b132
                        (void) PL_strcat(outputString, ".");
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* Ensure output string ends with terminating null */
Packit 40b132
        outputString[outputLen-1] = '\0';
Packit 40b132
Packit 40b132
        *pAscii = outputString;
Packit 40b132
        outputString = NULL;
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
        
Packit 40b132
        PKIX_FREE(outputString);
Packit 40b132
        PKIX_FREE(tempString);
Packit 40b132
Packit 40b132
        PKIX_RETURN(OBJECT);
Packit 40b132
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_pl_ipAddrBytes2Ascii
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Converts the DER encoding of an IPAddress pointed to by "secItem" to an
Packit 40b132
 *  ASCII representation and stores the result at "pAscii". The ASCII
Packit 40b132
 *  representation is guaranteed to end with a NUL character. The input
Packit 40b132
 *  SECItem must contain non-NULL data and must have a positive length.
Packit 40b132
 *
Packit 40b132
 *  The return value "pAscii" is not reference-counted and will need to
Packit 40b132
 *  be freed with PKIX_PL_Free.
Packit 40b132
 *  XXX this function assumes that IPv4 addresses are being used
Packit 40b132
 *  XXX what about IPv6? can NSS tell the difference
Packit 40b132
 *
Packit 40b132
 * PARAMETERS
Packit 40b132
 *  "secItem"
Packit 40b132
 *      Address of SECItem which contains bytes and length of DER encoding.
Packit 40b132
 *      Must be non-NULL.
Packit 40b132
 *  "pAscii"
Packit 40b132
 *      Address where object pointer will be stored. Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns an Object Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_pl_ipAddrBytes2Ascii(
Packit 40b132
        SECItem *secItem,
Packit 40b132
        char **pAscii,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        char *data = NULL;
Packit 40b132
        PKIX_UInt32 *tokens = NULL;
Packit 40b132
        PKIX_UInt32 numTokens = 0;
Packit 40b132
        PKIX_UInt32 i = 0;
Packit 40b132
        char *asciiString = NULL;
Packit 40b132
Packit 40b132
        PKIX_ENTER(OBJECT, "pkix_pl_ipAddrBytes2Ascii");
Packit 40b132
        PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data);
Packit 40b132
Packit 40b132
        if (secItem->len == 0) {
Packit 40b132
                PKIX_ERROR_FATAL(PKIX_IPADDRBYTES2ASCIIDATALENGTHZERO);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        data = (char *)(secItem->data);
Packit 40b132
        numTokens = secItem->len;
Packit 40b132
Packit 40b132
        /* allocate space for array of integers */
Packit 40b132
        PKIX_CHECK(PKIX_PL_Malloc
Packit 40b132
                    (numTokens * sizeof (PKIX_UInt32),
Packit 40b132
                    (void **)&tokens,
Packit 40b132
                    plContext),
Packit 40b132
                    PKIX_MALLOCFAILED);
Packit 40b132
Packit 40b132
        /* populate array of integers */
Packit 40b132
        for (i = 0; i < numTokens; i++){
Packit 40b132
                tokens[i] = data[i];
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* convert array of integers to ASCII */
Packit 40b132
        PKIX_CHECK(pkix_pl_helperBytes2Ascii
Packit 40b132
                    (tokens, numTokens, &asciiString, plContext),
Packit 40b132
                    PKIX_HELPERBYTES2ASCIIFAILED);
Packit 40b132
Packit 40b132
        *pAscii = asciiString;
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        PKIX_FREE(tokens);
Packit 40b132
Packit 40b132
        PKIX_RETURN(OBJECT);
Packit 40b132
}
Packit 40b132
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_pl_oidBytes2Ascii
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Converts the DER encoding of an OID pointed to by "secItem" to an ASCII
Packit 40b132
 *  representation and stores it at "pAscii". The ASCII representation is
Packit 40b132
 *  guaranteed to end with a NUL character. The input SECItem must contain
Packit 40b132
 *  non-NULL data and must have a positive length.
Packit 40b132
 *
Packit 40b132
 *  Example: the six bytes {2a 86 48 86 f7 0d} represent the
Packit 40b132
 *  four integer tokens {1, 2, 840, 113549}, which we will convert
Packit 40b132
 *  into ASCII yielding "1.2.840.113549"
Packit 40b132
 *
Packit 40b132
 *  The return value "pAscii" is not reference-counted and will need to
Packit 40b132
 *  be freed with PKIX_PL_Free.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS
Packit 40b132
 *  "secItem"
Packit 40b132
 *      Address of SECItem which contains bytes and length of DER encoding.
Packit 40b132
 *      Must be non-NULL.
Packit 40b132
 *  "pAscii"
Packit 40b132
 *      Address where object pointer will be stored. Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns an OID Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_pl_oidBytes2Ascii(
Packit 40b132
        SECItem *secItem,
Packit 40b132
        char **pAscii,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        char *data = NULL;
Packit 40b132
        PKIX_UInt32 *tokens = NULL;
Packit 40b132
        PKIX_UInt32 token = 0;
Packit 40b132
        PKIX_UInt32 numBytes = 0;
Packit 40b132
        PKIX_UInt32 numTokens = 0;
Packit 40b132
        PKIX_UInt32 i = 0, x = 0, y = 0;
Packit 40b132
        PKIX_UInt32 index = 0;
Packit 40b132
        char *asciiString = NULL;
Packit 40b132
Packit 40b132
        PKIX_ENTER(OID, "pkix_pl_oidBytes2Ascii");
Packit 40b132
        PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data);
Packit 40b132
Packit 40b132
        if (secItem->len == 0) {
Packit 40b132
                PKIX_ERROR_FATAL(PKIX_OIDBYTES2ASCIIDATALENGTHZERO);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        data = (char *)(secItem->data);
Packit 40b132
        numBytes = secItem->len;
Packit 40b132
        numTokens = 0;
Packit 40b132
Packit 40b132
        /* calculate how many integer tokens are represented by the bytes. */
Packit 40b132
        for (i = 0; i < numBytes; i++){
Packit 40b132
                if ((data[i] & 0x080) == 0){
Packit 40b132
                        numTokens++;
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* if we are unable to retrieve any tokens at all, we throw an error */
Packit 40b132
        if (numTokens == 0){
Packit 40b132
                PKIX_ERROR(PKIX_INVALIDDERENCODINGFOROID);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* add one more token b/c the first byte always contains two tokens */
Packit 40b132
        numTokens++;
Packit 40b132
Packit 40b132
        /* allocate space for array of integers */
Packit 40b132
        PKIX_CHECK(PKIX_PL_Malloc
Packit 40b132
                    (numTokens * sizeof (PKIX_UInt32),
Packit 40b132
                    (void **)&tokens,
Packit 40b132
                    plContext),
Packit 40b132
                    PKIX_MALLOCFAILED);
Packit 40b132
Packit 40b132
        /* populate array of integers */
Packit 40b132
        for (i = 0; i < numTokens; i++){
Packit 40b132
Packit 40b132
                /* retrieve integer token */
Packit 40b132
                PKIX_CHECK(pkix_pl_getOIDToken
Packit 40b132
                            (data, index, &token, &index, plContext),
Packit 40b132
                            PKIX_GETOIDTOKENFAILED);
Packit 40b132
Packit 40b132
                if (i == 0){
Packit 40b132
Packit 40b132
                        /*
Packit 40b132
                         * special case: the first DER-encoded byte represents
Packit 40b132
                         * two tokens. We take advantage of fact that first
Packit 40b132
                         * token must be 0, 1, or 2; and second token must be
Packit 40b132
                         * between {0, 39} inclusive if first token is 0 or 1.
Packit 40b132
                         */
Packit 40b132
Packit 40b132
                        if (token < 40)
Packit 40b132
                                x = 0;
Packit 40b132
                        else if (token < 80)
Packit 40b132
                                x = 1;
Packit 40b132
                        else
Packit 40b132
                                x = 2;
Packit 40b132
                        y = token - (x * 40);
Packit 40b132
Packit 40b132
                        tokens[0] = x;
Packit 40b132
                        tokens[1] = y;
Packit 40b132
                        i++;
Packit 40b132
                } else {
Packit 40b132
                        tokens[i] = token;
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* convert array of integers to ASCII */
Packit 40b132
        PKIX_CHECK(pkix_pl_helperBytes2Ascii
Packit 40b132
                    (tokens, numTokens, &asciiString, plContext),
Packit 40b132
                    PKIX_HELPERBYTES2ASCIIFAILED);
Packit 40b132
Packit 40b132
        *pAscii = asciiString;
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        PKIX_FREE(tokens);
Packit 40b132
        PKIX_RETURN(OID);
Packit 40b132
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_UTF16_to_EscASCII
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Converts array of bytes pointed to by "utf16String" with length of
Packit 40b132
 *  "utf16Length" (which must be even) into a freshly allocated Escaped ASCII
Packit 40b132
 *  string and stores a pointer to that string at "pDest" and stores the
Packit 40b132
 *  string's length at "pLength". The Escaped ASCII string's length does not
Packit 40b132
 *  include the final NUL character. The caller is responsible for freeing
Packit 40b132
 *  "pDest" using PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug
Packit 40b132
 *  encoding.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS:
Packit 40b132
 *  "utf16String"
Packit 40b132
 *      Address of array of bytes representing data source. Must be non-NULL.
Packit 40b132
 *  "utf16Length"
Packit 40b132
 *      Length of data source. Must be even.
Packit 40b132
 *  "debug"
Packit 40b132
 *      Boolean value indicating whether debug mode is desired.
Packit 40b132
 *  "pDest"
Packit 40b132
 *      Address where data will be stored. Must be non-NULL.
Packit 40b132
 *  "pLength"
Packit 40b132
 *      Address where data length will be stored. Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns a String Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_UTF16_to_EscASCII(
Packit 40b132
        const void *utf16String,
Packit 40b132
        PKIX_UInt32 utf16Length,
Packit 40b132
        PKIX_Boolean debug,
Packit 40b132
        char **pDest,
Packit 40b132
        PKIX_UInt32 *pLength,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        char *destPtr = NULL;
Packit 40b132
        PKIX_UInt32 i, charLen;
Packit 40b132
        PKIX_UInt32 x = 0, y = 0, z = 0;
Packit 40b132
        unsigned char *utf16Char = (unsigned char *)utf16String;
Packit 40b132
Packit 40b132
        PKIX_ENTER(STRING, "pkix_UTF16_to_EscASCII");
Packit 40b132
        PKIX_NULLCHECK_THREE(utf16String, pDest, pLength);
Packit 40b132
Packit 40b132
        /* Assume every pair of bytes becomes &#xNNNN; */
Packit 40b132
        charLen = 4*utf16Length;
Packit 40b132
Packit 40b132
        /* utf16Lenght must be even */
Packit 40b132
        if ((utf16Length % 2) != 0){
Packit 40b132
                PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* Count how many bytes we need */
Packit 40b132
        for (i = 0; i < utf16Length; i += 2) {
Packit 40b132
                if ((utf16Char[i] == 0x00)&&
Packit 40b132
                        pkix_isPlaintext(utf16Char[i+1], debug)) {
Packit 40b132
                        if (utf16Char[i+1] == '&') {
Packit 40b132
                                /* Need to convert this to & */
Packit 40b132
                                charLen -= 3;
Packit 40b132
                        } else {
Packit 40b132
                                /* We can fit this into one char */
Packit 40b132
                                charLen -= 7;
Packit 40b132
                        }
Packit 40b132
                } else if ((utf16Char[i] >= 0xD8) && (utf16Char[i] <= 0xDB)) {
Packit 40b132
                        if ((i+3) >= utf16Length) {
Packit 40b132
                                PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR);
Packit 40b132
                        } else if ((utf16Char[i+2] >= 0xDC)&&
Packit 40b132
                                (utf16Char[i+2] <= 0xDF)) {
Packit 40b132
                                /* Quartet of bytes will become &#xNNNNNNNN; */
Packit 40b132
                                charLen -= 4;
Packit 40b132
                                /* Quartet of bytes will produce 12 chars */
Packit 40b132
                                i += 2;
Packit 40b132
                        } else {
Packit 40b132
                                /* Second pair should be DC00-DFFF */
Packit 40b132
                                PKIX_ERROR(PKIX_UTF16LOWZONEERROR);
Packit 40b132
                        }
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        *pLength = charLen;
Packit 40b132
Packit 40b132
        /* Ensure this string is null terminated */
Packit 40b132
        charLen++;
Packit 40b132
Packit 40b132
        /* Allocate space for character array */
Packit 40b132
        PKIX_CHECK(PKIX_PL_Malloc(charLen, (void **)pDest, plContext),
Packit 40b132
                    PKIX_MALLOCFAILED);
Packit 40b132
Packit 40b132
        destPtr = *pDest;
Packit 40b132
        for (i = 0; i < utf16Length; i += 2) {
Packit 40b132
                if ((utf16Char[i] == 0x00)&&
Packit 40b132
                    pkix_isPlaintext(utf16Char[i+1], debug)) {
Packit 40b132
                        /* Write a single character */
Packit 40b132
                        *destPtr++ = utf16Char[i+1];
Packit 40b132
                } else if ((utf16Char[i+1] == '&') && (utf16Char[i] == 0x00)){
Packit 40b132
                        *destPtr++ = '&';
Packit 40b132
                        *destPtr++ = 'a';
Packit 40b132
                        *destPtr++ = 'm';
Packit 40b132
                        *destPtr++ = 'p';
Packit 40b132
                        *destPtr++ = ';';
Packit 40b132
                } else if ((utf16Char[i] >= 0xD8)&&
Packit 40b132
                            (utf16Char[i] <= 0xDB)&&
Packit 40b132
                            (utf16Char[i+2] >= 0xDC)&&
Packit 40b132
                            (utf16Char[i+2] <= 0xDF)) {
Packit 40b132
                        /*
Packit 40b132
                         * Special UTF pairs are of the form:
Packit 40b132
                         * x = D800..DBFF; y = DC00..DFFF;
Packit 40b132
                         * The result is of the form:
Packit 40b132
                         * ((x - D800) * 400 + (y - DC00)) + 0001 0000
Packit 40b132
                         */
Packit 40b132
                        x = 0x0FFFF & ((utf16Char[i]<<8) | utf16Char[i+1]);
Packit 40b132
                        y = 0x0FFFF & ((utf16Char[i+2]<<8) | utf16Char[i+3]);
Packit 40b132
                        z = ((x - 0xD800) * 0x400 + (y - 0xDC00)) + 0x00010000;
Packit 40b132
Packit 40b132
                        /* Sprintf &#xNNNNNNNN; */
Packit 40b132
                        PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
Packit 40b132
                        if (PR_snprintf(destPtr, 13, "&#x%08X;", z) ==
Packit 40b132
                            (PKIX_UInt32)(-1)) {
Packit 40b132
                                PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
Packit 40b132
                        }
Packit 40b132
                        i += 2;
Packit 40b132
                        destPtr += 12;
Packit 40b132
                } else {
Packit 40b132
                        /* Sprintf &#xNNNN; */
Packit 40b132
                        PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
Packit 40b132
                        if (PR_snprintf
Packit 40b132
                            (destPtr,
Packit 40b132
                            9,
Packit 40b132
                            "&#x%02X%02X;",
Packit 40b132
                            utf16Char[i],
Packit 40b132
                            utf16Char[i+1]) ==
Packit 40b132
                            (PKIX_UInt32)(-1)) {
Packit 40b132
                                PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
Packit 40b132
                        }
Packit 40b132
                        destPtr += 8;
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
        *destPtr = '\0';
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        if (PKIX_ERROR_RECEIVED){
Packit 40b132
                PKIX_FREE(*pDest);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_RETURN(STRING);
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_EscASCII_to_UTF16
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Converts array of bytes pointed to by "escAsciiString" with length of
Packit 40b132
 *  "escAsciiLength" into a freshly allocated UTF-16 string and stores a
Packit 40b132
 *  pointer to that string at "pDest" and stores the string's length at
Packit 40b132
 *  "pLength". The caller is responsible for freeing "pDest" using
Packit 40b132
 *  PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug encoding.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS:
Packit 40b132
 *  "escAsciiString"
Packit 40b132
 *      Address of array of bytes representing data source. Must be non-NULL.
Packit 40b132
 *  "escAsciiLength"
Packit 40b132
 *      Length of data source. Must be even.
Packit 40b132
 *  "debug"
Packit 40b132
 *      Boolean value indicating whether debug mode is desired.
Packit 40b132
 *  "pDest"
Packit 40b132
 *      Address where data will be stored. Must be non-NULL.
Packit 40b132
 *  "pLength"
Packit 40b132
 *      Address where data length will be stored. Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns a String Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_EscASCII_to_UTF16(
Packit 40b132
        const char *escAsciiString,
Packit 40b132
        PKIX_UInt32 escAsciiLen,
Packit 40b132
        PKIX_Boolean debug,
Packit 40b132
        void **pDest,
Packit 40b132
        PKIX_UInt32 *pLength,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        PKIX_UInt32 newLen, i, j, charSize;
Packit 40b132
        PKIX_UInt32 x = 0, y = 0, z = 0;
Packit 40b132
        unsigned char *destPtr = NULL;
Packit 40b132
        unsigned char testChar, testChar2;
Packit 40b132
        unsigned char *stringData = (unsigned char *)escAsciiString;
Packit 40b132
Packit 40b132
        PKIX_ENTER(STRING, "pkix_EscASCII_to_UTF16");
Packit 40b132
        PKIX_NULLCHECK_THREE(escAsciiString, pDest, pLength);
Packit 40b132
Packit 40b132
        if (escAsciiLen == 0) {
Packit 40b132
                PKIX_CHECK(PKIX_PL_Malloc(escAsciiLen, pDest, plContext),
Packit 40b132
                            PKIX_MALLOCFAILED);
Packit 40b132
                goto cleanup;
Packit 40b132
        }
Packit 40b132
Packit 40b132
        /* Assume each unicode character takes two bytes */
Packit 40b132
        newLen = escAsciiLen*2;
Packit 40b132
Packit 40b132
        /* Count up number of unicode encoded  characters */
Packit 40b132
        for (i = 0; i < escAsciiLen; i++) {
Packit 40b132
                if (!pkix_isPlaintext(stringData[i], debug)&&
Packit 40b132
                    (stringData[i] != '&')) {
Packit 40b132
                        PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII);
Packit 40b132
                } else if (PL_strstr(escAsciiString+i, "&") ==
Packit 40b132
                            escAsciiString+i) {
Packit 40b132
                        /* Convert EscAscii "&" to two bytes */
Packit 40b132
                        newLen -= 8;
Packit 40b132
                        i += 4;
Packit 40b132
                } else if ((PL_strstr(escAsciiString+i, "&#x") ==
Packit 40b132
                            escAsciiString+i)||
Packit 40b132
                            (PL_strstr(escAsciiString+i, "&#X") ==
Packit 40b132
                            escAsciiString+i)) {
Packit 40b132
                        if (((i+7) <= escAsciiLen)&&
Packit 40b132
                            (escAsciiString[i+7] == ';')) {
Packit 40b132
                                /* Convert &#xNNNN; to two bytes */
Packit 40b132
                                newLen -= 14;
Packit 40b132
                                i += 7;
Packit 40b132
                        } else if (((i+11) <= escAsciiLen)&&
Packit 40b132
                                (escAsciiString[i+11] == ';')) {
Packit 40b132
                                /* Convert &#xNNNNNNNN; to four bytes */
Packit 40b132
                                newLen -= 20;
Packit 40b132
                                i += 11;
Packit 40b132
                        } else {
Packit 40b132
                                PKIX_ERROR(PKIX_ILLEGALUSEOFAMP);
Packit 40b132
                        }
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_CHECK(PKIX_PL_Malloc(newLen, pDest, plContext),
Packit 40b132
                    PKIX_MALLOCFAILED);
Packit 40b132
Packit 40b132
        /* Copy into newly allocated space */
Packit 40b132
        destPtr = (unsigned char *)*pDest;
Packit 40b132
Packit 40b132
        i = 0;
Packit 40b132
        while (i < escAsciiLen) {
Packit 40b132
                /* Copy each byte until you hit a & */
Packit 40b132
                if (pkix_isPlaintext(escAsciiString[i], debug)) {
Packit 40b132
                        *destPtr++ = 0x00;
Packit 40b132
                        *destPtr++ = escAsciiString[i++];
Packit 40b132
                } else if (PL_strstr(escAsciiString+i, "&") ==
Packit 40b132
                            escAsciiString+i) {
Packit 40b132
                        /* Convert EscAscii "&" to two bytes */
Packit 40b132
                        *destPtr++ = 0x00;
Packit 40b132
                        *destPtr++ = '&';
Packit 40b132
                        i += 5;
Packit 40b132
                } else if (((PL_strstr(escAsciiString+i, "&#x") ==
Packit 40b132
                            escAsciiString+i)||
Packit 40b132
                            (PL_strstr(escAsciiString+i, "&#X") ==
Packit 40b132
                            escAsciiString+i))&&
Packit 40b132
                            ((i+7) <= escAsciiLen)) {
Packit 40b132
Packit 40b132
                        /* We're either looking at &#xNNNN; or &#xNNNNNNNN; */
Packit 40b132
                        charSize = (escAsciiString[i+7] == ';')?4:8;
Packit 40b132
Packit 40b132
                        /* Skip past the &#x */
Packit 40b132
                        i += 3;
Packit 40b132
Packit 40b132
                        /* Make sure there is a terminating semi-colon */
Packit 40b132
                        if (((i+charSize) > escAsciiLen)||
Packit 40b132
                            (escAsciiString[i+charSize] != ';')) {
Packit 40b132
                                PKIX_ERROR(PKIX_TRUNCATEDUNICODEINESCAPEDASCII);
Packit 40b132
                        }
Packit 40b132
Packit 40b132
                        for (j = 0; j < charSize; j++) {
Packit 40b132
                                if (!PKIX_ISXDIGIT
Packit 40b132
                                    (escAsciiString[i+j])) {
Packit 40b132
                                        PKIX_ERROR(PKIX_ILLEGALUNICODECHARACTER);
Packit 40b132
                                } else if (charSize == 8) {
Packit 40b132
                                        x |= (pkix_hex2i
Packit 40b132
                                                        (escAsciiString[i+j]))
Packit 40b132
                                                        <<(4*(7-j));
Packit 40b132
                                }
Packit 40b132
                        }
Packit 40b132
Packit 40b132
                        testChar =
Packit 40b132
                                (pkix_hex2i(escAsciiString[i])<<4)|
Packit 40b132
                                pkix_hex2i(escAsciiString[i+1]);
Packit 40b132
                        testChar2 =
Packit 40b132
                                (pkix_hex2i(escAsciiString[i+2])<<4)|
Packit 40b132
                                pkix_hex2i(escAsciiString[i+3]);
Packit 40b132
Packit 40b132
                        if (charSize == 4) {
Packit 40b132
                                if ((testChar >= 0xD8)&&
Packit 40b132
                                    (testChar <= 0xDF)) {
Packit 40b132
                                        PKIX_ERROR(PKIX_ILLEGALSURROGATEPAIR);
Packit 40b132
                                } else if ((testChar == 0x00)&&
Packit 40b132
                                  pkix_isPlaintext(testChar2, debug)) {
Packit 40b132
                                      PKIX_ERROR(
Packit 40b132
                                          PKIX_ILLEGALCHARACTERINESCAPEDASCII);
Packit 40b132
                                }
Packit 40b132
                                *destPtr++ = testChar;
Packit 40b132
                                *destPtr++ = testChar2;
Packit 40b132
                        } else if (charSize == 8) {
Packit 40b132
                                /* First two chars must be 0001-0010 */
Packit 40b132
                                if (!((testChar == 0x00)&&
Packit 40b132
                                    ((testChar2 >= 0x01)&&
Packit 40b132
                                    (testChar2 <= 0x10)))) {
Packit 40b132
                                      PKIX_ERROR(
Packit 40b132
                                          PKIX_ILLEGALCHARACTERINESCAPEDASCII);
Packit 40b132
                                }
Packit 40b132
                                /*
Packit 40b132
                                 * Unicode Strings of the form:
Packit 40b132
                                 * x =  0001 0000..0010 FFFF
Packit 40b132
                                 * Encoded as pairs of UTF-16 where
Packit 40b132
                                 * y = ((x - 0001 0000) / 400) + D800
Packit 40b132
                                 * z = ((x - 0001 0000) % 400) + DC00
Packit 40b132
                                 */
Packit 40b132
                                x -= 0x00010000;
Packit 40b132
                                y = (x/0x400)+ 0xD800;
Packit 40b132
                                z = (x%0x400)+ 0xDC00;
Packit 40b132
Packit 40b132
                                /* Copy four bytes */
Packit 40b132
                                *destPtr++ = (y&0xFF00)>>8;
Packit 40b132
                                *destPtr++ = (y&0x00FF);
Packit 40b132
                                *destPtr++ = (z&0xFF00)>>8;
Packit 40b132
                                *destPtr++ = (z&0x00FF);
Packit 40b132
                        }
Packit 40b132
                        /* Move past the Hex digits and the semi-colon */
Packit 40b132
                        i += charSize+1;
Packit 40b132
                } else {
Packit 40b132
                        /* Do not allow any other non-plaintext character */
Packit 40b132
                        PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII);
Packit 40b132
                }
Packit 40b132
        }
Packit 40b132
Packit 40b132
        *pLength = newLen;
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        if (PKIX_ERROR_RECEIVED){
Packit 40b132
                PKIX_FREE(*pDest);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_RETURN(STRING);
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_UTF16_to_UTF8
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Converts array of bytes pointed to by "utf16String" with length of
Packit 40b132
 *  "utf16Length" into a freshly allocated UTF-8 string and stores a pointer
Packit 40b132
 *  to that string at "pDest" and stores the string's length at "pLength" (not
Packit 40b132
 *  counting the null terminator, if requested. The caller is responsible for
Packit 40b132
 *  freeing "pDest" using PKIX_PL_Free.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS:
Packit 40b132
 *  "utf16String"
Packit 40b132
 *      Address of array of bytes representing data source. Must be non-NULL.
Packit 40b132
 *  "utf16Length"
Packit 40b132
 *      Length of data source. Must be even.
Packit 40b132
 *  "null-term"
Packit 40b132
 *      Boolean value indicating whether output should be null-terminated.
Packit 40b132
 *  "pDest"
Packit 40b132
 *      Address where data will be stored. Must be non-NULL.
Packit 40b132
 *  "pLength"
Packit 40b132
 *      Address where data length will be stored. Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns a String Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_UTF16_to_UTF8(
Packit 40b132
        const void *utf16String,
Packit 40b132
        PKIX_UInt32 utf16Length,
Packit 40b132
        PKIX_Boolean null_term,
Packit 40b132
        void **pDest,
Packit 40b132
        PKIX_UInt32 *pLength,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        PKIX_Boolean result;
Packit 40b132
        PKIX_UInt32 reallocLen;
Packit 40b132
        char *endPtr = NULL;
Packit 40b132
Packit 40b132
        PKIX_ENTER(STRING, "pkix_UTF16_to_UTF8");
Packit 40b132
        PKIX_NULLCHECK_THREE(utf16String, pDest, pLength);
Packit 40b132
Packit 40b132
        /* XXX How big can a UTF8 string be compared to a UTF16? */
Packit 40b132
        PKIX_CHECK(PKIX_PL_Calloc(1, utf16Length*2, pDest, plContext),
Packit 40b132
                    PKIX_CALLOCFAILED);
Packit 40b132
Packit 40b132
        PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n");
Packit 40b132
        result = PORT_UCS2_UTF8Conversion
Packit 40b132
                (PKIX_FALSE, /* False = From UCS2 */
Packit 40b132
                (unsigned char *)utf16String,
Packit 40b132
                utf16Length,
Packit 40b132
                (unsigned char *)*pDest,
Packit 40b132
                utf16Length*2, /* Max Size */
Packit 40b132
                pLength);
Packit 40b132
        if (result == PR_FALSE){
Packit 40b132
                PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        reallocLen = *pLength;
Packit 40b132
Packit 40b132
        if (null_term){
Packit 40b132
                reallocLen++;
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_CHECK(PKIX_PL_Realloc(*pDest, reallocLen, pDest, plContext),
Packit 40b132
                    PKIX_REALLOCFAILED);
Packit 40b132
Packit 40b132
        if (null_term){
Packit 40b132
                endPtr = (char*)*pDest + reallocLen - 1;
Packit 40b132
                *endPtr = '\0';
Packit 40b132
        }
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        if (PKIX_ERROR_RECEIVED){
Packit 40b132
                PKIX_FREE(*pDest);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_RETURN(STRING);
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * FUNCTION: pkix_UTF8_to_UTF16
Packit 40b132
 * DESCRIPTION:
Packit 40b132
 *
Packit 40b132
 *  Converts array of bytes pointed to by "utf8String" with length of
Packit 40b132
 *  "utf8Length" into a freshly allocated UTF-16 string and stores a pointer
Packit 40b132
 *  to that string at "pDest" and stores the string's length at "pLength". The
Packit 40b132
 *  caller is responsible for freeing "pDest" using PKIX_PL_Free.
Packit 40b132
 *
Packit 40b132
 * PARAMETERS:
Packit 40b132
 *  "utf8String"
Packit 40b132
 *      Address of array of bytes representing data source. Must be non-NULL.
Packit 40b132
 *  "utf8Length"
Packit 40b132
 *      Length of data source. Must be even.
Packit 40b132
 *  "pDest"
Packit 40b132
 *      Address where data will be stored. Must be non-NULL.
Packit 40b132
 *  "pLength"
Packit 40b132
 *      Address where data length will be stored. Must be non-NULL.
Packit 40b132
 *  "plContext"
Packit 40b132
 *      Platform-specific context pointer.
Packit 40b132
 * THREAD SAFETY:
Packit 40b132
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
Packit 40b132
 * RETURNS:
Packit 40b132
 *  Returns NULL if the function succeeds.
Packit 40b132
 *  Returns a String Error if the function fails in a non-fatal way.
Packit 40b132
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
Packit 40b132
 */
Packit 40b132
PKIX_Error *
Packit 40b132
pkix_UTF8_to_UTF16(
Packit 40b132
        const void *utf8String,
Packit 40b132
        PKIX_UInt32 utf8Length,
Packit 40b132
        void **pDest,
Packit 40b132
        PKIX_UInt32 *pLength,
Packit 40b132
        void *plContext)
Packit 40b132
{
Packit 40b132
        PKIX_Boolean result;
Packit 40b132
Packit 40b132
        PKIX_ENTER(STRING, "pkix_UTF8_to_UTF16");
Packit 40b132
        PKIX_NULLCHECK_THREE(utf8String, pDest, pLength);
Packit 40b132
Packit 40b132
        /* XXX How big can a UTF8 string be compared to a UTF16? */
Packit 40b132
        PKIX_CHECK(PKIX_PL_Calloc(1, utf8Length*2, pDest, plContext),
Packit 40b132
                    PKIX_MALLOCFAILED);
Packit 40b132
Packit 40b132
        PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n");
Packit 40b132
        result = PORT_UCS2_UTF8Conversion
Packit 40b132
                (PKIX_TRUE, /* True = From UTF8 */
Packit 40b132
                (unsigned char *)utf8String,
Packit 40b132
                utf8Length,
Packit 40b132
                (unsigned char *)*pDest,
Packit 40b132
                utf8Length*2, /* Max Size */
Packit 40b132
                pLength);
Packit 40b132
        if (result == PR_FALSE){
Packit 40b132
                PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_CHECK(PKIX_PL_Realloc(*pDest, *pLength, pDest, plContext),
Packit 40b132
                    PKIX_REALLOCFAILED);
Packit 40b132
Packit 40b132
cleanup:
Packit 40b132
Packit 40b132
        if (PKIX_ERROR_RECEIVED){
Packit 40b132
                PKIX_FREE(*pDest);
Packit 40b132
        }
Packit 40b132
Packit 40b132
        PKIX_RETURN(STRING);
Packit 40b132
}