andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * pkix_pl_infoaccess.c andre@0: * andre@0: * InfoAccess Object Definitions andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_pl_infoaccess.h" andre@0: andre@0: /* --Private-InfoAccess-Functions----------------------------------*/ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_Create andre@0: * DESCRIPTION: andre@0: * andre@0: * This function creates an InfoAccess from the method provided in "method" and andre@0: * the GeneralName provided in "generalName" and stores the result at andre@0: * "pInfoAccess". andre@0: * andre@0: * PARAMETERS andre@0: * "method" andre@0: * The UInt32 value to be stored as the method field of the InfoAccess. andre@0: * "generalName" andre@0: * The GeneralName to be stored as the generalName field of the InfoAccess. andre@0: * Must be non-NULL. andre@0: * "pInfoAccess" andre@0: * Address where the result is stored. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_InfoAccess_Create( andre@0: PKIX_UInt32 method, andre@0: PKIX_PL_GeneralName *generalName, andre@0: PKIX_PL_InfoAccess **pInfoAccess, andre@0: void *plContext) andre@0: { andre@0: andre@0: PKIX_PL_InfoAccess *infoAccess = NULL; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Create"); andre@0: PKIX_NULLCHECK_TWO(generalName, pInfoAccess); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_INFOACCESS_TYPE, andre@0: sizeof (PKIX_PL_InfoAccess), andre@0: (PKIX_PL_Object **)&infoAccess, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEINFOACCESSOBJECT); andre@0: andre@0: infoAccess->method = method; andre@0: andre@0: PKIX_INCREF(generalName); andre@0: infoAccess->location = generalName; andre@0: andre@0: *pInfoAccess = infoAccess; andre@0: infoAccess = NULL; andre@0: andre@0: cleanup: andre@0: PKIX_DECREF(infoAccess); andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_InfoAccess_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_InfoAccess *infoAccess = NULL; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Destroy"); andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_INFOACCESS_TYPE, plContext), andre@0: PKIX_OBJECTNOTANINFOACCESS); andre@0: andre@0: infoAccess = (PKIX_PL_InfoAccess *)object; andre@0: andre@0: PKIX_DECREF(infoAccess->location); andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_ToString andre@0: * (see comments for PKIX_PL_ToStringCallback in pkix_pl_pki.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_InfoAccess_ToString( andre@0: PKIX_PL_Object *object, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_InfoAccess *infoAccess; andre@0: PKIX_PL_String *infoAccessString = NULL; andre@0: char *asciiFormat = NULL; andre@0: char *asciiMethod = NULL; andre@0: PKIX_PL_String *formatString = NULL; andre@0: PKIX_PL_String *methodString = NULL; andre@0: PKIX_PL_String *locationString = NULL; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ToString"); andre@0: PKIX_NULLCHECK_TWO(object, pString); andre@0: andre@0: PKIX_CHECK(pkix_CheckType andre@0: (object, PKIX_INFOACCESS_TYPE, plContext), andre@0: PKIX_OBJECTNOTINFOACCESS); andre@0: andre@0: infoAccess = (PKIX_PL_InfoAccess *)object; andre@0: andre@0: asciiFormat = andre@0: "[" andre@0: "method:%s, " andre@0: "location:%s" andre@0: "]"; andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: asciiFormat, andre@0: 0, andre@0: &formatString, andre@0: plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: switch(infoAccess->method) { andre@0: case PKIX_INFOACCESS_CA_ISSUERS: andre@0: asciiMethod = "caIssuers"; andre@0: break; andre@0: case PKIX_INFOACCESS_OCSP: andre@0: asciiMethod = "ocsp"; andre@0: break; andre@0: case PKIX_INFOACCESS_TIMESTAMPING: andre@0: asciiMethod = "timestamping"; andre@0: break; andre@0: case PKIX_INFOACCESS_CA_REPOSITORY: andre@0: asciiMethod = "caRepository"; andre@0: break; andre@0: default: andre@0: asciiMethod = "unknown"; andre@0: } andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: asciiMethod, andre@0: 0, andre@0: &methodString, andre@0: plContext), andre@0: PKIX_STRINGCREATEFAILED); andre@0: andre@0: PKIX_TOSTRING(infoAccess->location, &locationString, plContext, andre@0: PKIX_GENERALNAMETOSTRINGFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (&infoAccessString, andre@0: plContext, andre@0: formatString, andre@0: methodString, andre@0: locationString), andre@0: PKIX_SPRINTFFAILED); andre@0: andre@0: *pString = infoAccessString; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_DECREF(formatString); andre@0: PKIX_DECREF(methodString); andre@0: PKIX_DECREF(locationString); andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_Hashcode andre@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_pki.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_InfoAccess_Hashcode( andre@0: PKIX_PL_Object *object, andre@0: PKIX_UInt32 *pHashcode, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_InfoAccess *infoAccess = NULL; andre@0: PKIX_UInt32 infoAccessHash; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(object, pHashcode); andre@0: andre@0: PKIX_CHECK(pkix_CheckType andre@0: (object, PKIX_INFOACCESS_TYPE, plContext), andre@0: PKIX_OBJECTNOTINFOACCESS); andre@0: andre@0: infoAccess = (PKIX_PL_InfoAccess *)object; andre@0: andre@0: PKIX_HASHCODE(infoAccess->location, &infoAccessHash, plContext, andre@0: PKIX_OBJECTHASHCODEFAILED); andre@0: andre@0: infoAccessHash += (infoAccess->method << 7); andre@0: andre@0: *pHashcode = infoAccessHash; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_Equals andre@0: * (see comments for PKIX_PL_Equals_Callback in pkix_pl_pki.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_InfoAccess_Equals( andre@0: PKIX_PL_Object *firstObject, andre@0: PKIX_PL_Object *secondObject, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_InfoAccess *firstInfoAccess = NULL; andre@0: PKIX_PL_InfoAccess *secondInfoAccess = NULL; andre@0: PKIX_UInt32 secondType; andre@0: PKIX_Boolean cmpResult; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); andre@0: andre@0: /* test that firstObject is a InfoAccess */ andre@0: PKIX_CHECK(pkix_CheckType andre@0: (firstObject, PKIX_INFOACCESS_TYPE, plContext), andre@0: PKIX_FIRSTOBJECTNOTINFOACCESS); andre@0: andre@0: /* andre@0: * Since we know firstObject is a InfoAccess, if both references are andre@0: * identical, they must be equal andre@0: */ andre@0: if (firstObject == secondObject){ andre@0: *pResult = PKIX_TRUE; andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * If secondObject isn't a InfoAccess, we don't throw an error. andre@0: * We simply return a Boolean result of FALSE andre@0: */ andre@0: *pResult = PKIX_FALSE; andre@0: PKIX_CHECK(PKIX_PL_Object_GetType andre@0: (secondObject, &secondType, plContext), andre@0: PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); andre@0: if (secondType != PKIX_INFOACCESS_TYPE) goto cleanup; andre@0: andre@0: firstInfoAccess = (PKIX_PL_InfoAccess *)firstObject; andre@0: secondInfoAccess = (PKIX_PL_InfoAccess *)secondObject; andre@0: andre@0: *pResult = PKIX_FALSE; andre@0: andre@0: if (firstInfoAccess->method != secondInfoAccess->method) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: PKIX_EQUALS(firstInfoAccess, secondInfoAccess, &cmpResult, plContext, andre@0: PKIX_OBJECTEQUALSFAILED); andre@0: andre@0: *pResult = cmpResult; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_INFOACCESS_TYPE and its related functions with systemClasses[] andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, which should andre@0: * only be called once, it is acceptable that this function is not andre@0: * thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_InfoAccess_RegisterSelf(void *plContext) andre@0: { andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry entry; andre@0: andre@0: PKIX_ENTER(INFOACCESS, andre@0: "pkix_pl_InfoAccess_RegisterSelf"); andre@0: andre@0: entry.description = "InfoAccess"; andre@0: entry.objCounter = 0; andre@0: entry.typeObjectSize = sizeof(PKIX_PL_InfoAccess); andre@0: entry.destructor = pkix_pl_InfoAccess_Destroy; andre@0: entry.equalsFunction = pkix_pl_InfoAccess_Equals; andre@0: entry.hashcodeFunction = pkix_pl_InfoAccess_Hashcode; andre@0: entry.toStringFunction = pkix_pl_InfoAccess_ToString; andre@0: entry.comparator = NULL; andre@0: entry.duplicateFunction = pkix_duplicateImmutable; andre@0: andre@0: systemClasses[PKIX_INFOACCESS_TYPE] = entry; andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_CreateList andre@0: * DESCRIPTION: andre@0: * andre@0: * Based on data in CERTAuthInfoAccess array "nssInfoAccess", this function andre@0: * creates and returns a PKIX_List of PKIX_PL_InfoAccess at "pInfoAccessList". andre@0: * andre@0: * PARAMETERS andre@0: * "nssInfoAccess" andre@0: * The pointer array of CERTAuthInfoAccess that contains access data. andre@0: * May be NULL. andre@0: * "pInfoAccessList" andre@0: * Address where a list of PKIX_PL_InfoAccess is returned. andre@0: * Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_InfoAccess_CreateList( andre@0: CERTAuthInfoAccess **nssInfoAccess, andre@0: PKIX_List **pInfoAccessList, /* of PKIX_PL_InfoAccess */ andre@0: void *plContext) andre@0: { andre@0: PKIX_List *infoAccessList = NULL; andre@0: PKIX_PL_InfoAccess *infoAccess = NULL; andre@0: PKIX_PL_GeneralName *location = NULL; andre@0: PKIX_UInt32 method; andre@0: int i; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_CreateList"); andre@0: PKIX_NULLCHECK_ONE(pInfoAccessList); andre@0: andre@0: PKIX_CHECK(PKIX_List_Create(&infoAccessList, plContext), andre@0: PKIX_LISTCREATEFAILED); andre@0: andre@0: if (nssInfoAccess == NULL) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: for (i = 0; nssInfoAccess[i] != NULL; i++) { andre@0: andre@0: if (nssInfoAccess[i]->location == NULL) { andre@0: continue; andre@0: } andre@0: andre@0: PKIX_CHECK(pkix_pl_GeneralName_Create andre@0: (nssInfoAccess[i]->location, &location, plContext), andre@0: PKIX_GENERALNAMECREATEFAILED); andre@0: andre@0: PKIX_CERT_DEBUG("\t\tCalling SECOID_FindOIDTag).\n"); andre@0: method = SECOID_FindOIDTag(&nssInfoAccess[i]->method); andre@0: /* Map NSS access method value into PKIX constant */ andre@0: switch(method) { andre@0: case SEC_OID_PKIX_CA_ISSUERS: andre@0: method = PKIX_INFOACCESS_CA_ISSUERS; andre@0: break; andre@0: case SEC_OID_PKIX_OCSP: andre@0: method = PKIX_INFOACCESS_OCSP; andre@0: break; andre@0: case SEC_OID_PKIX_TIMESTAMPING: andre@0: method = PKIX_INFOACCESS_TIMESTAMPING; andre@0: break; andre@0: case SEC_OID_PKIX_CA_REPOSITORY: andre@0: method = PKIX_INFOACCESS_CA_REPOSITORY; andre@0: break; andre@0: default: andre@0: PKIX_ERROR(PKIX_UNKNOWNINFOACCESSMETHOD); andre@0: } andre@0: andre@0: PKIX_CHECK(pkix_pl_InfoAccess_Create andre@0: (method, location, &infoAccess, plContext), andre@0: PKIX_INFOACCESSCREATEFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_List_AppendItem andre@0: (infoAccessList, andre@0: (PKIX_PL_Object *)infoAccess, andre@0: plContext), andre@0: PKIX_LISTAPPENDITEMFAILED); andre@0: PKIX_DECREF(infoAccess); andre@0: PKIX_DECREF(location); andre@0: } andre@0: andre@0: *pInfoAccessList = infoAccessList; andre@0: infoAccessList = NULL; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_DECREF(infoAccessList); andre@0: PKIX_DECREF(infoAccess); andre@0: PKIX_DECREF(location); andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* --Public-Functions------------------------------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_InfoAccess_GetMethod (see comments in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_InfoAccess_GetMethod( andre@0: PKIX_PL_InfoAccess *infoAccess, andre@0: PKIX_UInt32 *pMethod, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetMethod"); andre@0: PKIX_NULLCHECK_TWO(infoAccess, pMethod); andre@0: andre@0: *pMethod = infoAccess->method; andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_InfoAccess_GetLocation (see comments in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_InfoAccess_GetLocation( andre@0: PKIX_PL_InfoAccess *infoAccess, andre@0: PKIX_PL_GeneralName **pLocation, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocation"); andre@0: PKIX_NULLCHECK_TWO(infoAccess, pLocation); andre@0: andre@0: PKIX_INCREF(infoAccess->location); andre@0: andre@0: *pLocation = infoAccess->location; andre@0: andre@0: cleanup: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_PL_InfoAccess_GetLocationType (see comments in pkix_pl_pki.h) andre@0: */ andre@0: PKIX_Error * andre@0: PKIX_PL_InfoAccess_GetLocationType( andre@0: PKIX_PL_InfoAccess *infoAccess, andre@0: PKIX_UInt32 *pType, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *locationString = NULL; andre@0: PKIX_UInt32 type = PKIX_INFOACCESS_LOCATION_UNKNOWN; andre@0: PKIX_UInt32 len = 0; andre@0: void *location = NULL; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocationType"); andre@0: PKIX_NULLCHECK_TWO(infoAccess, pType); andre@0: andre@0: if (infoAccess->location != NULL) { andre@0: andre@0: PKIX_TOSTRING(infoAccess->location, &locationString, plContext, andre@0: PKIX_GENERALNAMETOSTRINGFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_GetEncoded andre@0: (locationString, PKIX_ESCASCII, &location, &len, plContext), andre@0: PKIX_STRINGGETENCODEDFAILED); andre@0: andre@0: PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n"); andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: if (PORT_Strncmp(location, "ldap:", 5) == 0){ andre@0: type = PKIX_INFOACCESS_LOCATION_LDAP; andre@0: } else andre@0: #endif andre@0: if (PORT_Strncmp(location, "http:", 5) == 0){ andre@0: type = PKIX_INFOACCESS_LOCATION_HTTP; andre@0: } andre@0: } andre@0: andre@0: *pType = type; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_PL_Free(location, plContext); andre@0: PKIX_DECREF(locationString); andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: #ifndef NSS_PKIX_NO_LDAP andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_ParseTokens andre@0: * DESCRIPTION: andre@0: * andre@0: * This function parses the string beginning at "startPos" into tokens using andre@0: * the separator contained in "separator" and the terminator contained in andre@0: * "terminator", copying the tokens into space allocated from the arena andre@0: * pointed to by "arena". It stores in "tokens" a null-terminated array of andre@0: * pointers to those tokens. andre@0: * andre@0: * PARAMETERS andre@0: * "arena" andre@0: * Address of a PLArenaPool to be used in populating the LDAPLocation. andre@0: * Must be non-NULL. andre@0: * "startPos" andre@0: * The address of char string that contains a subset of ldap location. andre@0: * "tokens" andre@0: * The address of an array of char string for storing returned tokens. andre@0: * Must be non-NULL. andre@0: * "separator" andre@0: * The character that is taken as token separator. Must be non-NULL. andre@0: * "terminator" andre@0: * The character that is taken as parsing terminator. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an InfoAccess Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_pl_InfoAccess_ParseTokens( andre@0: PLArenaPool *arena, andre@0: char **startPos, /* return update */ andre@0: char ***tokens, andre@0: char separator, andre@0: char terminator, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 numFilters = 0; andre@0: char *endPos = NULL; andre@0: char **filterP = NULL; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseTokens"); andre@0: PKIX_NULLCHECK_THREE(arena, startPos, tokens); andre@0: andre@0: endPos = *startPos; andre@0: andre@0: /* First pass: parse to to count number of components */ andre@0: numFilters = 0; andre@0: while (*endPos != terminator && *endPos != '\0') { andre@0: endPos++; andre@0: if (*endPos == separator) { andre@0: numFilters++; andre@0: } andre@0: } andre@0: andre@0: if (*endPos != terminator) { andre@0: PKIX_ERROR(PKIX_LOCATIONSTRINGNOTPROPERLYTERMINATED); andre@0: } andre@0: andre@0: /* Last component doesn't need a separator, although we allow it */ andre@0: if (endPos > *startPos && *(endPos-1) != separator) { andre@0: numFilters++; andre@0: } andre@0: andre@0: /* andre@0: * If string is a=xx, b=yy, c=zz, etc., use a=xx for filter, andre@0: * and everything else for the base andre@0: */ andre@0: if (numFilters > 2) numFilters = 2; andre@0: andre@0: filterP = PORT_ArenaZNewArray(arena, char*, numFilters+1); andre@0: if (filterP == NULL) { andre@0: PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); andre@0: } andre@0: andre@0: /* Second pass: parse to fill in components in token array */ andre@0: *tokens = filterP; andre@0: endPos = *startPos; andre@0: andre@0: while (numFilters) { andre@0: if (*endPos == separator || *endPos == terminator) { andre@0: PKIX_UInt32 len = endPos - *startPos; andre@0: char *p = PORT_ArenaZAlloc(arena, len+1); andre@0: if (p == NULL) { andre@0: PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); andre@0: } andre@0: andre@0: PORT_Memcpy(p, *startPos, len); andre@0: p[len] = '\0'; andre@0: andre@0: *filterP = p; andre@0: filterP++; andre@0: numFilters--; andre@0: andre@0: separator = terminator; andre@0: andre@0: if (*endPos == '\0') { andre@0: *startPos = endPos; andre@0: break; andre@0: } else { andre@0: endPos++; andre@0: *startPos = endPos; andre@0: continue; andre@0: } andre@0: } andre@0: endPos++; andre@0: } andre@0: andre@0: *filterP = NULL; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: andre@0: static int andre@0: pkix_pl_HexDigitToInt( andre@0: int ch) andre@0: { andre@0: if (isdigit(ch)) { andre@0: ch = ch - '0'; andre@0: } else if (isupper(ch)) { andre@0: ch = ch - 'A' + 10; andre@0: } else { andre@0: ch = ch - 'a' + 10; andre@0: } andre@0: return ch; andre@0: } andre@0: andre@0: /* andre@0: * Convert the "%" hex hex escape sequences in the URL 'location' in place. andre@0: */ andre@0: static void andre@0: pkix_pl_UnescapeURL( andre@0: char *location) andre@0: { andre@0: const char *src; andre@0: char *dst; andre@0: andre@0: for (src = dst = location; *src != '\0'; src++, dst++) { andre@0: if (*src == '%' && isxdigit((unsigned char)*(src+1)) && andre@0: isxdigit((unsigned char)*(src+2))) { andre@0: *dst = pkix_pl_HexDigitToInt((unsigned char)*(src+1)); andre@0: *dst *= 16; andre@0: *dst += pkix_pl_HexDigitToInt((unsigned char)*(src+2)); andre@0: src += 2; andre@0: } else { andre@0: *dst = *src; andre@0: } andre@0: } andre@0: *dst = *src; /* the terminating null */ andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_InfoAccess_ParseLocation andre@0: * DESCRIPTION: andre@0: * andre@0: * This function parses the GeneralName pointed to by "generalName" into the andre@0: * fields of the LDAPRequestParams pointed to by "request" and a domainName andre@0: * pointed to by "pDomainName", using the PLArenaPool pointed to by "arena" to andre@0: * allocate storage for the request components and for the domainName string. andre@0: * andre@0: * The expected GeneralName string should be in the format described by the andre@0: * following BNF: andre@0: * andre@0: * ldap:///[cn=][,o=][,c=]? andre@0: * [caCertificate|crossCertificatPair|certificateRevocationList]; andre@0: * [binary|] andre@0: * [[,caCertificate|crossCertificatPair|certificateRevocationList] andre@0: * [binary|]]* andre@0: * andre@0: * PARAMETERS andre@0: * "generalName" andre@0: * Address of the GeneralName whose LDAPLocation is to be parsed. Must be andre@0: * non-NULL. andre@0: * "arena" andre@0: * Address of PLArenaPool to be used for the domainName and for components andre@0: * of the LDAPRequest. Must be non-NULL. andre@0: * "request" andre@0: * Address of the LDAPRequestParams into which request components are andre@0: * stored. Must be non-NULL. andre@0: * *pDomainName" andre@0: * Address at which the domainName is stored. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns an InfoAccess Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_InfoAccess_ParseLocation( andre@0: PKIX_PL_GeneralName *generalName, andre@0: PLArenaPool *arena, andre@0: LDAPRequestParams *request, andre@0: char **pDomainName, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *locationString = NULL; andre@0: PKIX_UInt32 len = 0; andre@0: PKIX_UInt32 ncIndex = 0; andre@0: char *domainName = NULL; andre@0: char **avaArray = NULL; andre@0: char **attrArray = NULL; andre@0: char *attr = NULL; andre@0: char *locationAscii = NULL; andre@0: char *startPos = NULL; andre@0: char *endPos = NULL; andre@0: char *avaPtr = NULL; andre@0: LdapAttrMask attrBit = 0; andre@0: LDAPNameComponent **setOfNameComponent = NULL; andre@0: LDAPNameComponent *nameComponent = NULL; andre@0: andre@0: PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseLocation"); andre@0: PKIX_NULLCHECK_FOUR(generalName, arena, request, pDomainName); andre@0: andre@0: PKIX_TOSTRING(generalName, &locationString, plContext, andre@0: PKIX_GENERALNAMETOSTRINGFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_GetEncoded andre@0: (locationString, andre@0: PKIX_ESCASCII, andre@0: (void **)&locationAscii, andre@0: &len, andre@0: plContext), andre@0: PKIX_STRINGGETENCODEDFAILED); andre@0: andre@0: pkix_pl_UnescapeURL(locationAscii); andre@0: andre@0: /* Skip "ldap:" */ andre@0: endPos = locationAscii; andre@0: while (*endPos != ':' && *endPos != '\0') { andre@0: endPos++; andre@0: } andre@0: if (*endPos == '\0') { andre@0: PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGLOCATIONTYPE); andre@0: } andre@0: andre@0: /* Skip "//" */ andre@0: endPos++; andre@0: if (*endPos != '\0' && *(endPos+1) != '0' && andre@0: *endPos == '/' && *(endPos+1) == '/') { andre@0: endPos += 2; andre@0: } else { andre@0: PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGDOUBLESLASH); andre@0: } andre@0: andre@0: /* Get the server-site */ andre@0: startPos = endPos; andre@0: while(*endPos != '/' && *(endPos) != '\0') { andre@0: endPos++; andre@0: } andre@0: if (*endPos == '\0') { andre@0: PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGSERVERSITE); andre@0: } andre@0: andre@0: len = endPos - startPos; andre@0: endPos++; andre@0: andre@0: domainName = PORT_ArenaZAlloc(arena, len + 1); andre@0: if (!domainName) { andre@0: PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); andre@0: } andre@0: andre@0: PORT_Memcpy(domainName, startPos, len); andre@0: andre@0: domainName[len] = '\0'; andre@0: andre@0: *pDomainName = domainName; andre@0: andre@0: /* andre@0: * Get a list of AttrValueAssertions (such as andre@0: * "cn=CommonName, o=Organization, c=US" into a null-terminated array andre@0: */ andre@0: startPos = endPos; andre@0: PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens andre@0: (arena, andre@0: &startPos, andre@0: (char ***) &avaArray, andre@0: ',', andre@0: '?', andre@0: plContext), andre@0: PKIX_INFOACCESSPARSETOKENSFAILED); andre@0: andre@0: /* Count how many AVAs we have */ andre@0: for (len = 0; avaArray[len] != NULL; len++) {} andre@0: andre@0: if (len < 2) { andre@0: PKIX_ERROR(PKIX_NOTENOUGHNAMECOMPONENTSINGENERALNAME); andre@0: } andre@0: andre@0: /* Use last name component for baseObject */ andre@0: request->baseObject = avaArray[len - 1]; andre@0: andre@0: /* Use only one component for filter. LDAP servers aren't too smart. */ andre@0: len = 2; /* Eliminate this when servers get smarter. */ andre@0: andre@0: avaArray[len - 1] = NULL; andre@0: andre@0: /* Get room for null-terminated array of (LdapNameComponent *) */ andre@0: setOfNameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent *, len); andre@0: if (setOfNameComponent == NULL) { andre@0: PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); andre@0: } andre@0: andre@0: /* Get room for the remaining LdapNameComponents */ andre@0: nameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent, --len); andre@0: if (nameComponent == NULL) { andre@0: PKIX_ERROR(PKIX_PORTARENAALLOCFAILED); andre@0: } andre@0: andre@0: /* Convert remaining AVAs to LDAPNameComponents */ andre@0: for (ncIndex = 0; ncIndex < len; ncIndex ++) { andre@0: setOfNameComponent[ncIndex] = nameComponent; andre@0: avaPtr = avaArray[ncIndex]; andre@0: nameComponent->attrType = (unsigned char *)avaPtr; andre@0: while ((*avaPtr != '=') && (*avaPtr != '\0')) { andre@0: avaPtr++; andre@0: if (*avaPtr == '\0') { andre@0: PKIX_ERROR(PKIX_NAMECOMPONENTWITHNOEQ); andre@0: } andre@0: } andre@0: *(avaPtr++) = '\0'; andre@0: nameComponent->attrValue = (unsigned char *)avaPtr; andre@0: nameComponent++; andre@0: } andre@0: andre@0: setOfNameComponent[len] = NULL; andre@0: request->nc = setOfNameComponent; andre@0: andre@0: /* andre@0: * Get a list of AttrTypes (such as andre@0: * "caCertificate;binary, crossCertificatePair;binary") into andre@0: * a null-terminated array andre@0: */ andre@0: andre@0: PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens andre@0: (arena, andre@0: (char **) &startPos, andre@0: (char ***) &attrArray, andre@0: ',', andre@0: '\0', andre@0: plContext), andre@0: PKIX_INFOACCESSPARSETOKENSFAILED); andre@0: andre@0: /* Convert array of Attr Types into a bit mask */ andre@0: request->attributes = 0; andre@0: attr = attrArray[0]; andre@0: while (attr != NULL) { andre@0: PKIX_CHECK(pkix_pl_LdapRequest_AttrStringToBit andre@0: (attr, &attrBit, plContext), andre@0: PKIX_LDAPREQUESTATTRSTRINGTOBITFAILED); andre@0: request->attributes |= attrBit; andre@0: attr = *(++attrArray); andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_PL_Free(locationAscii, plContext); andre@0: PKIX_DECREF(locationString); andre@0: andre@0: PKIX_RETURN(INFOACCESS); andre@0: } andre@0: #endif /* !NSS_PKIX_NO_LDAP */