tor-browser

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

pkix_pl_infoaccess.c (27207B)


      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_pl_infoaccess.c
      6 *
      7 * InfoAccess Object Definitions
      8 *
      9 */
     10 
     11 #include "pkix_pl_infoaccess.h"
     12 
     13 /* --Private-InfoAccess-Functions----------------------------------*/
     14 
     15 /*
     16 * FUNCTION: pkix_pl_InfoAccess_Create
     17 * DESCRIPTION:
     18 *
     19 *  This function creates an InfoAccess from the method provided in "method" and
     20 *  the GeneralName provided in "generalName" and stores the result at
     21 *  "pInfoAccess".
     22 *
     23 * PARAMETERS
     24 *  "method"
     25 *      The UInt32 value to be stored as the method field of the InfoAccess.
     26 *  "gName"
     27 *      The GeneralName to be stored as the gName field of the InfoAccess.
     28 *      Must be non-NULL.
     29 *  "pInfoAccess"
     30 *      Address where the result is stored. Must be non-NULL.
     31 *  "plContext"
     32 *      Platform-specific context pointer.
     33 * THREAD SAFETY:
     34 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
     35 * RETURNS:
     36 *  Returns NULL if the function succeeds.
     37 *  Returns a Fatal Error if the function fails in an unrecoverable way.
     38 */
     39 static PKIX_Error *
     40 pkix_pl_InfoAccess_Create(
     41        PKIX_UInt32 method,
     42        PKIX_PL_GeneralName *gName,
     43        PKIX_PL_InfoAccess **pInfoAccess,
     44        void *plContext)
     45 {
     46 
     47        PKIX_PL_InfoAccess *infoAccess = NULL;
     48 
     49        PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Create");
     50        PKIX_NULLCHECK_TWO(gName, pInfoAccess);
     51 
     52        PKIX_CHECK(PKIX_PL_Object_Alloc
     53                (PKIX_INFOACCESS_TYPE,
     54                sizeof (PKIX_PL_InfoAccess),
     55                (PKIX_PL_Object **)&infoAccess,
     56                plContext),
     57                PKIX_COULDNOTCREATEINFOACCESSOBJECT);
     58 
     59        infoAccess->method = method;
     60 
     61        PKIX_INCREF(gName);
     62        infoAccess->location = gName;
     63 
     64        *pInfoAccess = infoAccess;
     65        infoAccess = NULL;
     66 
     67 cleanup:
     68        PKIX_DECREF(infoAccess);
     69 
     70        PKIX_RETURN(INFOACCESS);
     71 }
     72 
     73 /*
     74 * FUNCTION: pkix_pl_InfoAccess_Destroy
     75 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
     76 */
     77 static PKIX_Error *
     78 pkix_pl_InfoAccess_Destroy(
     79        PKIX_PL_Object *object,
     80        void *plContext)
     81 {
     82        PKIX_PL_InfoAccess *infoAccess = NULL;
     83 
     84        PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Destroy");
     85        PKIX_NULLCHECK_ONE(object);
     86 
     87        PKIX_CHECK(pkix_CheckType(object, PKIX_INFOACCESS_TYPE, plContext),
     88                PKIX_OBJECTNOTANINFOACCESS);
     89 
     90        infoAccess = (PKIX_PL_InfoAccess *)object;
     91 
     92        PKIX_DECREF(infoAccess->location);
     93 
     94 cleanup:
     95 
     96        PKIX_RETURN(INFOACCESS);
     97 }
     98 
     99 /*
    100 * FUNCTION: pkix_pl_InfoAccess_ToString
    101 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_pki.h)
    102 */
    103 static PKIX_Error *
    104 pkix_pl_InfoAccess_ToString(
    105        PKIX_PL_Object *object,
    106        PKIX_PL_String **pString,
    107        void *plContext)
    108 {
    109        PKIX_PL_InfoAccess *infoAccess;
    110        PKIX_PL_String *infoAccessString = NULL;
    111        char *asciiFormat = NULL;
    112        char *asciiMethod = NULL;
    113        PKIX_PL_String *formatString = NULL;
    114        PKIX_PL_String *methodString = NULL;
    115        PKIX_PL_String *locationString = NULL;
    116 
    117        PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ToString");
    118        PKIX_NULLCHECK_TWO(object, pString);
    119 
    120        PKIX_CHECK(pkix_CheckType
    121                    (object, PKIX_INFOACCESS_TYPE, plContext),
    122                    PKIX_OBJECTNOTINFOACCESS);
    123 
    124        infoAccess = (PKIX_PL_InfoAccess *)object;
    125 
    126        asciiFormat =
    127                "["
    128                "method:%s, "
    129                "location:%s"
    130                "]";
    131 
    132        PKIX_CHECK(PKIX_PL_String_Create
    133                    (PKIX_ESCASCII,
    134                    asciiFormat,
    135                    0,
    136                    &formatString,
    137                    plContext),
    138                    PKIX_STRINGCREATEFAILED);
    139 
    140        switch(infoAccess->method) {
    141            case PKIX_INFOACCESS_CA_ISSUERS:
    142                    asciiMethod = "caIssuers";
    143                    break;
    144            case PKIX_INFOACCESS_OCSP:
    145                    asciiMethod = "ocsp";
    146                    break;
    147            case PKIX_INFOACCESS_TIMESTAMPING:
    148                    asciiMethod = "timestamping";
    149                    break;
    150            case PKIX_INFOACCESS_CA_REPOSITORY:
    151                    asciiMethod = "caRepository";
    152                    break;
    153            default:
    154                    asciiMethod = "unknown";
    155        }
    156 
    157        PKIX_CHECK(PKIX_PL_String_Create
    158                    (PKIX_ESCASCII,
    159                    asciiMethod,
    160                    0,
    161                    &methodString,
    162                    plContext),
    163                    PKIX_STRINGCREATEFAILED);
    164 
    165        PKIX_TOSTRING(infoAccess->location, &locationString, plContext,
    166                    PKIX_GENERALNAMETOSTRINGFAILED);
    167 
    168        PKIX_CHECK(PKIX_PL_Sprintf
    169                    (&infoAccessString,
    170                    plContext,
    171                    formatString,
    172                    methodString,
    173                    locationString),
    174                    PKIX_SPRINTFFAILED);
    175 
    176        *pString = infoAccessString;
    177 
    178 cleanup:
    179 
    180        PKIX_DECREF(formatString);
    181        PKIX_DECREF(methodString);
    182        PKIX_DECREF(locationString);
    183 
    184        PKIX_RETURN(INFOACCESS);
    185 }
    186 
    187 /*
    188 * FUNCTION: pkix_pl_InfoAccess_Hashcode
    189 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_pki.h)
    190 */
    191 static PKIX_Error *
    192 pkix_pl_InfoAccess_Hashcode(
    193        PKIX_PL_Object *object,
    194        PKIX_UInt32 *pHashcode,
    195        void *plContext)
    196 {
    197        PKIX_PL_InfoAccess *infoAccess = NULL;
    198        PKIX_UInt32 infoAccessHash;
    199 
    200        PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Hashcode");
    201        PKIX_NULLCHECK_TWO(object, pHashcode);
    202 
    203        PKIX_CHECK(pkix_CheckType
    204                    (object, PKIX_INFOACCESS_TYPE, plContext),
    205                    PKIX_OBJECTNOTINFOACCESS);
    206 
    207        infoAccess = (PKIX_PL_InfoAccess *)object;
    208 
    209        PKIX_HASHCODE(infoAccess->location, &infoAccessHash, plContext,
    210                    PKIX_OBJECTHASHCODEFAILED);
    211 
    212        infoAccessHash += (infoAccess->method << 7);
    213 
    214        *pHashcode = infoAccessHash;
    215 
    216 cleanup:
    217 
    218        PKIX_RETURN(INFOACCESS);
    219 
    220 }
    221 
    222 /*
    223 * FUNCTION: pkix_pl_InfoAccess_Equals
    224 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_pki.h)
    225 */
    226 static PKIX_Error *
    227 pkix_pl_InfoAccess_Equals(
    228        PKIX_PL_Object *firstObject,
    229        PKIX_PL_Object *secondObject,
    230        PKIX_Boolean *pResult,
    231        void *plContext)
    232 {
    233        PKIX_PL_InfoAccess *firstInfoAccess = NULL;
    234        PKIX_PL_InfoAccess *secondInfoAccess = NULL;
    235        PKIX_UInt32 secondType;
    236        PKIX_Boolean cmpResult;
    237 
    238        PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Equals");
    239        PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
    240 
    241        /* test that firstObject is a InfoAccess */
    242        PKIX_CHECK(pkix_CheckType
    243                (firstObject, PKIX_INFOACCESS_TYPE, plContext),
    244                PKIX_FIRSTOBJECTNOTINFOACCESS);
    245 
    246        /*
    247         * Since we know firstObject is a InfoAccess, if both references are
    248         * identical, they must be equal
    249         */
    250        if (firstObject == secondObject){
    251                *pResult = PKIX_TRUE;
    252                goto cleanup;
    253        }
    254 
    255        /*
    256         * If secondObject isn't a InfoAccess, we don't throw an error.
    257         * We simply return a Boolean result of FALSE
    258         */
    259        *pResult = PKIX_FALSE;
    260        PKIX_CHECK(PKIX_PL_Object_GetType
    261                    (secondObject, &secondType, plContext),
    262                    PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
    263        if (secondType != PKIX_INFOACCESS_TYPE) goto cleanup;
    264 
    265        firstInfoAccess = (PKIX_PL_InfoAccess *)firstObject;
    266        secondInfoAccess = (PKIX_PL_InfoAccess *)secondObject;
    267 
    268        *pResult = PKIX_FALSE;
    269 
    270        if (firstInfoAccess->method != secondInfoAccess->method) {
    271                goto cleanup;
    272        }
    273 
    274        PKIX_EQUALS(firstInfoAccess, secondInfoAccess, &cmpResult, plContext,
    275                PKIX_OBJECTEQUALSFAILED);
    276 
    277        *pResult = cmpResult;
    278 
    279 cleanup:
    280 
    281        PKIX_RETURN(INFOACCESS);
    282 }
    283 
    284 /*
    285 * FUNCTION: pkix_pl_InfoAccess_RegisterSelf
    286 * DESCRIPTION:
    287 *  Registers PKIX_INFOACCESS_TYPE and its related functions with systemClasses[]
    288 * THREAD SAFETY:
    289 *  Not Thread Safe - for performance and complexity reasons
    290 *
    291 *  Since this function is only called by PKIX_PL_Initialize, which should
    292 *  only be called once, it is acceptable that this function is not
    293 *  thread-safe.
    294 */
    295 PKIX_Error *
    296 pkix_pl_InfoAccess_RegisterSelf(void *plContext)
    297 {
    298        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
    299        pkix_ClassTable_Entry entry;
    300 
    301        PKIX_ENTER(INFOACCESS,
    302                "pkix_pl_InfoAccess_RegisterSelf");
    303 
    304        entry.description = "InfoAccess";
    305        entry.objCounter = 0;
    306        entry.typeObjectSize = sizeof(PKIX_PL_InfoAccess);
    307        entry.destructor = pkix_pl_InfoAccess_Destroy;
    308        entry.equalsFunction = pkix_pl_InfoAccess_Equals;
    309        entry.hashcodeFunction = pkix_pl_InfoAccess_Hashcode;
    310        entry.toStringFunction = pkix_pl_InfoAccess_ToString;
    311        entry.comparator = NULL;
    312        entry.duplicateFunction = pkix_duplicateImmutable;
    313 
    314        systemClasses[PKIX_INFOACCESS_TYPE] = entry;
    315 
    316        PKIX_RETURN(INFOACCESS);
    317 }
    318 
    319 /*
    320 * FUNCTION: pkix_pl_InfoAccess_CreateList
    321 * DESCRIPTION:
    322 *
    323 *  Based on data in CERTAuthInfoAccess array "nssInfoAccess", this function
    324 *  creates and returns a PKIX_List of PKIX_PL_InfoAccess at "pInfoAccessList".
    325 *
    326 * PARAMETERS
    327 *  "nssInfoAccess"
    328 *      The pointer array of CERTAuthInfoAccess that contains access data.
    329 *      May be NULL.
    330 *  "pInfoAccessList"
    331 *      Address where a list of PKIX_PL_InfoAccess is returned.
    332 *      Must be non-NULL.
    333 *  "plContext"
    334 *      Platform-specific context pointer.
    335 * THREAD SAFETY:
    336 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    337 * RETURNS:
    338 *  Returns NULL if the function succeeds.
    339 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    340 */
    341 PKIX_Error *
    342 pkix_pl_InfoAccess_CreateList(
    343        CERTAuthInfoAccess **nssInfoAccess,
    344        PKIX_List **pInfoAccessList, /* of PKIX_PL_InfoAccess */
    345        void *plContext)
    346 {
    347        PKIX_List *infoAccessList = NULL;
    348        PKIX_PL_InfoAccess *infoAccess = NULL;
    349        PKIX_PL_GeneralName *location = NULL;
    350        PKIX_UInt32 method;
    351        int i;
    352 
    353        PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_CreateList");
    354        PKIX_NULLCHECK_ONE(pInfoAccessList);
    355 
    356        PKIX_CHECK(PKIX_List_Create(&infoAccessList, plContext),
    357                PKIX_LISTCREATEFAILED);
    358 
    359        if (nssInfoAccess == NULL) {
    360                goto cleanup;
    361        }
    362 
    363        for (i = 0; nssInfoAccess[i] != NULL; i++) {
    364 
    365                if (nssInfoAccess[i]->location == NULL) {
    366                    continue;
    367                }
    368 
    369                PKIX_CHECK(pkix_pl_GeneralName_Create
    370                        (nssInfoAccess[i]->location, &location, plContext),
    371                        PKIX_GENERALNAMECREATEFAILED);
    372 
    373                PKIX_CERT_DEBUG("\t\tCalling SECOID_FindOIDTag).\n");
    374                method = SECOID_FindOIDTag(&nssInfoAccess[i]->method);
    375                /* Map NSS access method value into PKIX constant */
    376                switch(method) {
    377                        case SEC_OID_PKIX_CA_ISSUERS:
    378                                method = PKIX_INFOACCESS_CA_ISSUERS;
    379                                break;
    380                        case SEC_OID_PKIX_OCSP:
    381                                method = PKIX_INFOACCESS_OCSP;
    382                                break;
    383                        case SEC_OID_PKIX_TIMESTAMPING:
    384                                method = PKIX_INFOACCESS_TIMESTAMPING;
    385                                break;
    386                        case SEC_OID_PKIX_CA_REPOSITORY:
    387                                method = PKIX_INFOACCESS_CA_REPOSITORY;
    388                                break;
    389                        default:
    390                                PKIX_ERROR(PKIX_UNKNOWNINFOACCESSMETHOD);
    391                }
    392 
    393                PKIX_CHECK(pkix_pl_InfoAccess_Create
    394                        (method, location, &infoAccess, plContext),
    395                        PKIX_INFOACCESSCREATEFAILED);
    396 
    397                PKIX_CHECK(PKIX_List_AppendItem
    398                            (infoAccessList,
    399                            (PKIX_PL_Object *)infoAccess,
    400                            plContext),
    401                            PKIX_LISTAPPENDITEMFAILED);
    402                PKIX_DECREF(infoAccess);
    403                PKIX_DECREF(location);
    404        }
    405 
    406        *pInfoAccessList = infoAccessList;
    407        infoAccessList = NULL;
    408 
    409 cleanup:
    410 
    411        PKIX_DECREF(infoAccessList);
    412        PKIX_DECREF(infoAccess);
    413        PKIX_DECREF(location);
    414 
    415        PKIX_RETURN(INFOACCESS);
    416 }
    417 
    418 /* --Public-Functions------------------------------------------------------- */
    419 
    420 /*
    421 * FUNCTION: PKIX_PL_InfoAccess_GetMethod (see comments in pkix_pl_pki.h)
    422 */
    423 PKIX_Error *
    424 PKIX_PL_InfoAccess_GetMethod(
    425        PKIX_PL_InfoAccess *infoAccess,
    426        PKIX_UInt32 *pMethod,
    427        void *plContext)
    428 {
    429        PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetMethod");
    430        PKIX_NULLCHECK_TWO(infoAccess, pMethod);
    431 
    432        *pMethod = infoAccess->method;
    433 
    434        PKIX_RETURN(INFOACCESS);
    435 }
    436 
    437 /*
    438 * FUNCTION: PKIX_PL_InfoAccess_GetLocation (see comments in pkix_pl_pki.h)
    439 */
    440 PKIX_Error *
    441 PKIX_PL_InfoAccess_GetLocation(
    442        PKIX_PL_InfoAccess *infoAccess,
    443        PKIX_PL_GeneralName **pLocation,
    444        void *plContext)
    445 {
    446        PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocation");
    447        PKIX_NULLCHECK_TWO(infoAccess, pLocation);
    448 
    449        PKIX_INCREF(infoAccess->location);
    450 
    451        *pLocation = infoAccess->location;
    452 
    453 cleanup:
    454        PKIX_RETURN(INFOACCESS);
    455 }
    456 
    457 /*
    458 * FUNCTION: PKIX_PL_InfoAccess_GetLocationType (see comments in pkix_pl_pki.h)
    459 */
    460 PKIX_Error *
    461 PKIX_PL_InfoAccess_GetLocationType(
    462        PKIX_PL_InfoAccess *infoAccess,
    463        PKIX_UInt32 *pType,
    464        void *plContext)
    465 {
    466        PKIX_PL_String *locationString = NULL;
    467        PKIX_UInt32 type = PKIX_INFOACCESS_LOCATION_UNKNOWN;
    468        PKIX_UInt32 len = 0;
    469        void *location = NULL;
    470 
    471        PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocationType");
    472        PKIX_NULLCHECK_TWO(infoAccess, pType);
    473 
    474        if (infoAccess->location != NULL) {
    475 
    476                PKIX_TOSTRING(infoAccess->location, &locationString, plContext,
    477                    PKIX_GENERALNAMETOSTRINGFAILED);
    478 
    479                PKIX_CHECK(PKIX_PL_String_GetEncoded
    480                    (locationString, PKIX_ESCASCII, &location, &len, plContext),
    481                    PKIX_STRINGGETENCODEDFAILED);
    482 
    483                PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n");
    484 #ifndef NSS_PKIX_NO_LDAP
    485                if (PORT_Strncmp(location, "ldap:", 5) == 0){
    486                        type = PKIX_INFOACCESS_LOCATION_LDAP;
    487                } else
    488 #endif
    489                if (PORT_Strncmp(location, "http:", 5) == 0){
    490                        type = PKIX_INFOACCESS_LOCATION_HTTP;
    491                }
    492        }
    493 
    494        *pType = type;
    495 
    496 cleanup:
    497 
    498        PKIX_PL_Free(location, plContext);
    499        PKIX_DECREF(locationString);
    500 
    501        PKIX_RETURN(INFOACCESS);
    502 }
    503 
    504 #ifndef NSS_PKIX_NO_LDAP
    505 /*
    506 * FUNCTION: pkix_pl_InfoAccess_ParseTokens
    507 * DESCRIPTION:
    508 *
    509 *  This function parses the string beginning at "startPos" into tokens using
    510 *  the separator contained in "separator" and the terminator contained in
    511 *  "terminator", copying the tokens into space allocated from the arena
    512 *  pointed to by "arena". It stores in "tokens" a null-terminated array of
    513 *  pointers to those tokens.
    514 *
    515 * PARAMETERS
    516 *  "arena"
    517 *      Address of a PLArenaPool to be used in populating the LDAPLocation.
    518 *      Must be non-NULL.
    519 *  "startPos"
    520 *      The address of char string that contains a subset of ldap location.
    521 *  "tokens"
    522 *      The address of an array of char string for storing returned tokens.
    523 *      Must be non-NULL.
    524 *  "separator"
    525 *      The character that is taken as token separator. Must be non-NULL.
    526 *  "terminator"
    527 *      The character that is taken as parsing terminator. Must be non-NULL.
    528 *  "plContext"
    529 *      Platform-specific context pointer.
    530 * THREAD SAFETY:
    531 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    532 * RETURNS:
    533 *  Returns NULL if the function succeeds.
    534 *  Returns an InfoAccess Error if the function fails in a non-fatal way.
    535 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    536 */
    537 static PKIX_Error *
    538 pkix_pl_InfoAccess_ParseTokens(
    539        PLArenaPool *arena,
    540        char **startPos, /* return update */
    541        char ***tokens,
    542        char separator,
    543        char terminator,
    544        void *plContext)
    545 {
    546        PKIX_UInt32 numFilters = 0;
    547        char *endPos = NULL;
    548        char **filterP = NULL;
    549 
    550        PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseTokens");
    551        PKIX_NULLCHECK_THREE(arena, startPos, tokens);
    552 
    553        endPos = *startPos;
    554 
    555        /* First pass: parse to <terminator> to count number of components */
    556        numFilters = 0;
    557        while (*endPos != terminator && *endPos != '\0') {
    558                endPos++;
    559                if (*endPos == separator) {
    560                        numFilters++;
    561                }
    562        }
    563 
    564        if (*endPos != terminator) {
    565                PKIX_ERROR(PKIX_LOCATIONSTRINGNOTPROPERLYTERMINATED);
    566        }
    567 
    568        /* Last component doesn't need a separator, although we allow it */
    569        if (endPos > *startPos && *(endPos-1) != separator) {
    570                numFilters++;
    571        }
    572 
    573        /*
    574         * If string is a=xx, b=yy, c=zz, etc., use a=xx for filter,
    575         * and everything else for the base
    576         */
    577        if (numFilters > 2) numFilters = 2;
    578 
    579        filterP = PORT_ArenaZNewArray(arena, char*, numFilters+1);
    580        if (filterP == NULL) {
    581            PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
    582        }
    583 
    584        /* Second pass: parse to fill in components in token array */
    585        *tokens = filterP;
    586        endPos = *startPos;
    587 
    588        while (numFilters) {
    589            if (*endPos == separator || *endPos == terminator) {
    590                    PKIX_UInt32 len = endPos - *startPos;
    591                    char *p = PORT_ArenaZAlloc(arena, len+1);
    592                    if (p == NULL) {
    593                        PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
    594                    }
    595 
    596                    PORT_Memcpy(p, *startPos, len);
    597                    p[len] = '\0';
    598 
    599                    *filterP = p;
    600                    filterP++;
    601                    numFilters--;
    602 
    603                    separator = terminator;
    604 
    605                    if (*endPos == '\0') {
    606                        *startPos = endPos;
    607                        break;
    608                    } else {
    609                        endPos++;
    610                        *startPos = endPos;
    611                        continue;
    612                    }
    613            }
    614            endPos++;
    615        }
    616 
    617        *filterP = NULL;
    618 
    619 cleanup:
    620 
    621        PKIX_RETURN(INFOACCESS);
    622 }
    623 
    624 static int
    625 pkix_pl_HexDigitToInt(
    626        int ch)
    627 {
    628        if (isdigit(ch)) {
    629                ch = ch - '0';
    630        } else if (isupper(ch)) {
    631                ch = ch - 'A' + 10;
    632        } else {
    633                ch = ch - 'a' + 10;
    634        }
    635        return ch;
    636 }
    637 
    638 /*
    639 * Convert the "%" hex hex escape sequences in the URL 'location' in place.
    640 */
    641 static void
    642 pkix_pl_UnescapeURL(
    643        char *location)
    644 {
    645        const char *src;
    646        char *dst;
    647 
    648        for (src = dst = location; *src != '\0'; src++, dst++) {
    649                if (*src == '%' && isxdigit((unsigned char)*(src+1)) &&
    650                    isxdigit((unsigned char)*(src+2))) {
    651                        *dst = pkix_pl_HexDigitToInt((unsigned char)*(src+1));
    652                        *dst *= 16;
    653                        *dst += pkix_pl_HexDigitToInt((unsigned char)*(src+2));
    654                        src += 2;
    655                } else {
    656                        *dst = *src;
    657                }
    658        }
    659        *dst = *src;  /* the terminating null */
    660 }
    661 
    662 /*
    663 * FUNCTION: pkix_pl_InfoAccess_ParseLocation
    664 * DESCRIPTION:
    665 *
    666 *  This function parses the GeneralName pointed to by "generalName" into the
    667 *  fields of the LDAPRequestParams pointed to by "request" and a domainName
    668 *  pointed to by "pDomainName", using the PLArenaPool pointed to by "arena" to
    669 *  allocate storage for the request components and for the domainName string.
    670 *
    671 *  The expected GeneralName string should be in the format described by the
    672 *  following BNF:
    673 *
    674 *  ldap://<ldap-server-site>/[cn=<cname>][,o=<org>][,c=<country>]?
    675 *  [caCertificate|crossCertificatPair|certificateRevocationList];
    676 *  [binary|<other-type>]
    677 *  [[,caCertificate|crossCertificatPair|certificateRevocationList]
    678 *   [binary|<other-type>]]*
    679 *
    680 * PARAMETERS
    681 *  "gName"
    682 *      Address of the GeneralName whose LDAPLocation is to be parsed. Must be
    683 *      non-NULL.
    684 *  "arena"
    685 *      Address of PLArenaPool to be used for the domainName and for components
    686 *      of the LDAPRequest. Must be non-NULL.
    687 *  "request"
    688 *      Address of the LDAPRequestParams into which request components are
    689 *      stored. Must be non-NULL.
    690 *  *pDomainName"
    691 *      Address at which the domainName is stored. Must be non-NULL.
    692 *  "plContext"
    693 *      Platform-specific context pointer.
    694 * THREAD SAFETY:
    695 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
    696 * RETURNS:
    697 *  Returns NULL if the function succeeds.
    698 *  Returns an InfoAccess Error if the function fails in a non-fatal way.
    699 *  Returns a Fatal Error if the function fails in an unrecoverable way.
    700 */
    701 PKIX_Error *
    702 pkix_pl_InfoAccess_ParseLocation(
    703        PKIX_PL_GeneralName *gName,
    704        PLArenaPool *arena,
    705        LDAPRequestParams *request,
    706        char **pDomainName,
    707        void *plContext)
    708 {
    709        PKIX_PL_String *locationString = NULL;
    710        PKIX_UInt32 len = 0;
    711        PKIX_UInt32 ncIndex = 0;
    712        char *domainName = NULL;
    713        char **avaArray = NULL;
    714        char **attrArray = NULL;
    715        char *attr = NULL;
    716        char *locationAscii = NULL;
    717        char *startPos = NULL;
    718        char *endPos = NULL;
    719        char *avaPtr = NULL;
    720        LdapAttrMask attrBit = 0;
    721        LDAPNameComponent **setOfNameComponent = NULL;
    722        LDAPNameComponent *nameComponent = NULL;
    723 
    724        PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseLocation");
    725        PKIX_NULLCHECK_FOUR(gName, arena, request, pDomainName);
    726 
    727        PKIX_TOSTRING(gName, &locationString, plContext,
    728                PKIX_GENERALNAMETOSTRINGFAILED);
    729 
    730        PKIX_CHECK(PKIX_PL_String_GetEncoded
    731                (locationString,
    732                PKIX_ESCASCII,
    733                (void **)&locationAscii,
    734                &len,
    735                plContext),
    736                PKIX_STRINGGETENCODEDFAILED);
    737 
    738        pkix_pl_UnescapeURL(locationAscii);
    739 
    740        /* Skip "ldap:" */
    741        endPos = locationAscii;
    742        while (*endPos != ':' && *endPos != '\0') {
    743                endPos++;
    744        }
    745        if (*endPos == '\0') {
    746                PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGLOCATIONTYPE);
    747        }
    748 
    749        /* Skip "//" */
    750        endPos++;
    751        if (*endPos != '\0' && *(endPos+1) != '0' &&
    752            *endPos == '/' && *(endPos+1) == '/') {
    753                endPos += 2;
    754        } else {
    755                PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGDOUBLESLASH);
    756        }
    757 
    758        /* Get the server-site */
    759        startPos = endPos;
    760        while(*endPos != '/' && *(endPos) != '\0') {
    761                endPos++;
    762        }
    763        if (*endPos == '\0') {
    764                PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGSERVERSITE);
    765        }
    766 
    767        len = endPos - startPos;
    768        endPos++;
    769 
    770        domainName = PORT_ArenaZAlloc(arena, len + 1);
    771        if (!domainName) {
    772            PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
    773        }
    774 
    775        PORT_Memcpy(domainName, startPos, len);
    776 
    777        domainName[len] = '\0';
    778 
    779        *pDomainName = domainName;
    780 
    781        /*
    782         * Get a list of AttrValueAssertions (such as 
    783         * "cn=CommonName, o=Organization, c=US" into a null-terminated array
    784         */
    785        startPos = endPos;
    786        PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens
    787                (arena,
    788                &startPos,
    789                (char ***) &avaArray,
    790                ',',
    791                '?',
    792                plContext),
    793                PKIX_INFOACCESSPARSETOKENSFAILED);
    794 
    795        /* Count how many AVAs we have */
    796        for (len = 0; avaArray[len] != NULL; len++) {}
    797 
    798        if (len < 2) {
    799                PKIX_ERROR(PKIX_NOTENOUGHNAMECOMPONENTSINGENERALNAME);
    800        }
    801 
    802        /* Use last name component for baseObject */
    803        request->baseObject = avaArray[len - 1];
    804 
    805        /* Use only one component for filter. LDAP servers aren't too smart. */
    806        len = 2;   /* Eliminate this when servers get smarter. */
    807 
    808        avaArray[len - 1] = NULL;
    809 
    810        /* Get room for null-terminated array of (LdapNameComponent *) */
    811        setOfNameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent *, len);
    812        if (setOfNameComponent == NULL) {
    813            PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
    814        }
    815 
    816        /* Get room for the remaining LdapNameComponents */
    817        nameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent, --len);
    818        if (nameComponent == NULL) {
    819            PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
    820        }
    821 
    822        /* Convert remaining AVAs to LDAPNameComponents */
    823        for (ncIndex = 0; ncIndex < len; ncIndex ++) {
    824                setOfNameComponent[ncIndex] = nameComponent;
    825                avaPtr = avaArray[ncIndex];
    826                nameComponent->attrType = (unsigned char *)avaPtr;
    827                while ((*avaPtr != '=') && (*avaPtr != '\0')) {
    828                        avaPtr++;
    829                        if (*avaPtr == '\0') {
    830                                PKIX_ERROR(PKIX_NAMECOMPONENTWITHNOEQ);
    831                        }
    832                }
    833                *(avaPtr++) = '\0';
    834                nameComponent->attrValue = (unsigned char *)avaPtr;
    835                nameComponent++;
    836        }
    837 
    838        setOfNameComponent[len] = NULL;
    839        request->nc = setOfNameComponent;
    840                
    841        /*
    842         * Get a list of AttrTypes (such as 
    843         * "caCertificate;binary, crossCertificatePair;binary") into
    844         * a null-terminated array
    845         */
    846 
    847        PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens
    848                (arena,
    849                (char **) &startPos,
    850                (char ***) &attrArray,
    851                ',',
    852                '\0',
    853                plContext),
    854                PKIX_INFOACCESSPARSETOKENSFAILED);
    855 
    856        /* Convert array of Attr Types into a bit mask */
    857        request->attributes = 0;
    858        attr = attrArray[0];
    859        while (attr != NULL) {
    860                PKIX_CHECK(pkix_pl_LdapRequest_AttrStringToBit
    861                        (attr, &attrBit, plContext),
    862                        PKIX_LDAPREQUESTATTRSTRINGTOBITFAILED);
    863                request->attributes |= attrBit;
    864                attr = *(++attrArray);
    865        }
    866 
    867 cleanup:
    868 
    869        PKIX_PL_Free(locationAscii, plContext);
    870        PKIX_DECREF(locationString);
    871 
    872        PKIX_RETURN(INFOACCESS);
    873 }
    874 #endif /* !NSS_PKIX_NO_LDAP */