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 *
pkix_pl_InfoAccess_Create(PKIX_UInt32 method,PKIX_PL_GeneralName * gName,PKIX_PL_InfoAccess ** pInfoAccess,void * plContext)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 *
pkix_pl_InfoAccess_Destroy(PKIX_PL_Object * object,void * plContext)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 *
pkix_pl_InfoAccess_ToString(PKIX_PL_Object * object,PKIX_PL_String ** pString,void * plContext)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 *
pkix_pl_InfoAccess_Hashcode(PKIX_PL_Object * object,PKIX_UInt32 * pHashcode,void * plContext)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 *
pkix_pl_InfoAccess_Equals(PKIX_PL_Object * firstObject,PKIX_PL_Object * secondObject,PKIX_Boolean * pResult,void * plContext)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 *
pkix_pl_InfoAccess_RegisterSelf(void * plContext)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 *
pkix_pl_InfoAccess_CreateList(CERTAuthInfoAccess ** nssInfoAccess,PKIX_List ** pInfoAccessList,void * plContext)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 *
PKIX_PL_InfoAccess_GetMethod(PKIX_PL_InfoAccess * infoAccess,PKIX_UInt32 * pMethod,void * plContext)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 *
PKIX_PL_InfoAccess_GetLocation(PKIX_PL_InfoAccess * infoAccess,PKIX_PL_GeneralName ** pLocation,void * plContext)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 *
PKIX_PL_InfoAccess_GetLocationType(PKIX_PL_InfoAccess * infoAccess,PKIX_UInt32 * pType,void * plContext)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 *
pkix_pl_InfoAccess_ParseTokens(PLArenaPool * arena,char ** startPos,char *** tokens,char separator,char terminator,void * plContext)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
pkix_pl_HexDigitToInt(int ch)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
pkix_pl_UnescapeURL(char * location)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 *
pkix_pl_InfoAccess_ParseLocation(PKIX_PL_GeneralName * gName,PLArenaPool * arena,LDAPRequestParams * request,char ** pDomainName,void * plContext)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 */
875