nss: import at 3.0.1 beta 1
[mozilla-nss.git] / security / nss / lib / libpkix / pkix_pl_nss / pki / pkix_pl_infoaccess.c
blob0b7aa43b77fbd5c3dcbd57980e4d2b3f709b1568
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the PKIX-C library.
16 * The Initial Developer of the Original Code is
17 * Sun Microsystems, Inc.
18 * Portions created by the Initial Developer are
19 * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
21 * Contributor(s):
22 * Sun Microsystems, Inc.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 * pkix_pl_infoaccess.c
40 * InfoAccess Object Definitions
44 #include "pkix_pl_infoaccess.h"
46 /* XXX Following SEC_OID_PKIX defines should be merged in NSS */
47 #define SEC_OID_PKIX_CA_REPOSITORY 1003
48 #define SEC_OID_PKIX_TIMESTAMPING 1005
49 /* XXX Following OID defines hould be moved to NSS */
50 static const unsigned char siaTimeStampingOID[] = {0x2b, 0x06, 0x01, 0x05,
51 0x05, 0x07, 0x030, 0x03};
52 static const unsigned char siaCaRepositoryOID[] = {0x2b, 0x06, 0x01, 0x05,
53 0x05, 0x07, 0x030, 0x05};
56 /* --Private-InfoAccess-Functions----------------------------------*/
59 * FUNCTION: pkix_pl_InfoAccess_Create
60 * DESCRIPTION:
62 * This function creates an InfoAccess from the method provided in "method" and
63 * the GeneralName provided in "generalName" and stores the result at
64 * "pInfoAccess".
66 * PARAMETERS
67 * "method"
68 * The UInt32 value to be stored as the method field of the InfoAccess.
69 * "generalName"
70 * The GeneralName to be stored as the generalName field of the InfoAccess.
71 * Must be non-NULL.
72 * "pInfoAccess"
73 * Address where the result is stored. Must be non-NULL.
74 * "plContext"
75 * Platform-specific context pointer.
76 * THREAD SAFETY:
77 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
78 * RETURNS:
79 * Returns NULL if the function succeeds.
80 * Returns a Fatal Error if the function fails in an unrecoverable way.
82 static PKIX_Error *
83 pkix_pl_InfoAccess_Create(
84 PKIX_UInt32 method,
85 PKIX_PL_GeneralName *generalName,
86 PKIX_PL_InfoAccess **pInfoAccess,
87 void *plContext)
90 PKIX_PL_InfoAccess *infoAccess = NULL;
92 PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Create");
93 PKIX_NULLCHECK_TWO(generalName, pInfoAccess);
95 PKIX_CHECK(PKIX_PL_Object_Alloc
96 (PKIX_INFOACCESS_TYPE,
97 sizeof (PKIX_PL_InfoAccess),
98 (PKIX_PL_Object **)&infoAccess,
99 plContext),
100 PKIX_COULDNOTCREATEINFOACCESSOBJECT);
102 infoAccess->method = method;
104 PKIX_INCREF(generalName);
105 infoAccess->location = generalName;
107 *pInfoAccess = infoAccess;
108 infoAccess = NULL;
110 cleanup:
111 PKIX_DECREF(infoAccess);
113 PKIX_RETURN(INFOACCESS);
117 * FUNCTION: pkix_pl_InfoAccess_Destroy
118 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
120 static PKIX_Error *
121 pkix_pl_InfoAccess_Destroy(
122 PKIX_PL_Object *object,
123 void *plContext)
125 PKIX_PL_InfoAccess *infoAccess = NULL;
127 PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Destroy");
128 PKIX_NULLCHECK_ONE(object);
130 PKIX_CHECK(pkix_CheckType(object, PKIX_INFOACCESS_TYPE, plContext),
131 PKIX_OBJECTNOTANINFOACCESS);
133 infoAccess = (PKIX_PL_InfoAccess *)object;
135 PKIX_DECREF(infoAccess->location);
137 cleanup:
139 PKIX_RETURN(INFOACCESS);
143 * FUNCTION: pkix_pl_InfoAccess_ToString
144 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_pki.h)
146 static PKIX_Error *
147 pkix_pl_InfoAccess_ToString(
148 PKIX_PL_Object *object,
149 PKIX_PL_String **pString,
150 void *plContext)
152 PKIX_PL_InfoAccess *infoAccess;
153 PKIX_PL_String *infoAccessString = NULL;
154 char *asciiFormat = NULL;
155 char *asciiMethod = NULL;
156 PKIX_PL_String *formatString = NULL;
157 PKIX_PL_String *methodString = NULL;
158 PKIX_PL_String *locationString = NULL;
160 PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ToString");
161 PKIX_NULLCHECK_TWO(object, pString);
163 PKIX_CHECK(pkix_CheckType
164 (object, PKIX_INFOACCESS_TYPE, plContext),
165 PKIX_OBJECTNOTINFOACCESS);
167 infoAccess = (PKIX_PL_InfoAccess *)object;
169 asciiFormat =
171 "method:%s, "
172 "location:%s"
173 "]";
175 PKIX_CHECK(PKIX_PL_String_Create
176 (PKIX_ESCASCII,
177 asciiFormat,
179 &formatString,
180 plContext),
181 PKIX_STRINGCREATEFAILED);
183 switch(infoAccess->method) {
184 case PKIX_INFOACCESS_CA_ISSUERS:
185 asciiMethod = "caIssuers";
186 break;
187 case PKIX_INFOACCESS_OCSP:
188 asciiMethod = "ocsp";
189 break;
190 case PKIX_INFOACCESS_TIMESTAMPING:
191 asciiMethod = "timestamping";
192 break;
193 case PKIX_INFOACCESS_CA_REPOSITORY:
194 asciiMethod = "caRepository";
195 break;
196 default:
197 asciiMethod = "unknown";
200 PKIX_CHECK(PKIX_PL_String_Create
201 (PKIX_ESCASCII,
202 asciiMethod,
204 &methodString,
205 plContext),
206 PKIX_STRINGCREATEFAILED);
208 PKIX_TOSTRING(infoAccess->location, &locationString, plContext,
209 PKIX_GENERALNAMETOSTRINGFAILED);
211 PKIX_CHECK(PKIX_PL_Sprintf
212 (&infoAccessString,
213 plContext,
214 formatString,
215 methodString,
216 locationString),
217 PKIX_SPRINTFFAILED);
219 *pString = infoAccessString;
221 cleanup:
223 PKIX_DECREF(formatString);
224 PKIX_DECREF(methodString);
225 PKIX_DECREF(locationString);
227 PKIX_RETURN(INFOACCESS);
231 * FUNCTION: pkix_pl_InfoAccess_Hashcode
232 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_pki.h)
234 static PKIX_Error *
235 pkix_pl_InfoAccess_Hashcode(
236 PKIX_PL_Object *object,
237 PKIX_UInt32 *pHashcode,
238 void *plContext)
240 PKIX_PL_InfoAccess *infoAccess = NULL;
241 PKIX_UInt32 infoAccessHash;
243 PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Hashcode");
244 PKIX_NULLCHECK_TWO(object, pHashcode);
246 PKIX_CHECK(pkix_CheckType
247 (object, PKIX_INFOACCESS_TYPE, plContext),
248 PKIX_OBJECTNOTINFOACCESS);
250 infoAccess = (PKIX_PL_InfoAccess *)object;
252 PKIX_HASHCODE(infoAccess->location, &infoAccessHash, plContext,
253 PKIX_OBJECTHASHCODEFAILED);
255 infoAccessHash += (infoAccess->method << 7);
257 *pHashcode = infoAccessHash;
259 cleanup:
261 PKIX_RETURN(INFOACCESS);
266 * FUNCTION: pkix_pl_InfoAccess_Equals
267 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_pki.h)
269 static PKIX_Error *
270 pkix_pl_InfoAccess_Equals(
271 PKIX_PL_Object *firstObject,
272 PKIX_PL_Object *secondObject,
273 PKIX_Boolean *pResult,
274 void *plContext)
276 PKIX_PL_InfoAccess *firstInfoAccess = NULL;
277 PKIX_PL_InfoAccess *secondInfoAccess = NULL;
278 PKIX_UInt32 secondType;
279 PKIX_Boolean cmpResult;
281 PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Equals");
282 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
284 /* test that firstObject is a InfoAccess */
285 PKIX_CHECK(pkix_CheckType
286 (firstObject, PKIX_INFOACCESS_TYPE, plContext),
287 PKIX_FIRSTOBJECTNOTINFOACCESS);
290 * Since we know firstObject is a InfoAccess, if both references are
291 * identical, they must be equal
293 if (firstObject == secondObject){
294 *pResult = PKIX_TRUE;
295 goto cleanup;
299 * If secondObject isn't a InfoAccess, we don't throw an error.
300 * We simply return a Boolean result of FALSE
302 *pResult = PKIX_FALSE;
303 PKIX_CHECK(PKIX_PL_Object_GetType
304 (secondObject, &secondType, plContext),
305 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
306 if (secondType != PKIX_INFOACCESS_TYPE) goto cleanup;
308 firstInfoAccess = (PKIX_PL_InfoAccess *)firstObject;
309 secondInfoAccess = (PKIX_PL_InfoAccess *)secondObject;
311 *pResult = PKIX_FALSE;
313 if (firstInfoAccess->method != secondInfoAccess->method) {
314 goto cleanup;
317 PKIX_EQUALS(firstInfoAccess, secondInfoAccess, &cmpResult, plContext,
318 PKIX_OBJECTEQUALSFAILED);
320 *pResult = cmpResult;
322 cleanup:
324 PKIX_RETURN(INFOACCESS);
328 * FUNCTION: pkix_pl_InfoAccess_RegisterSelf
329 * DESCRIPTION:
330 * Registers PKIX_INFOACCESS_TYPE and its related functions with systemClasses[]
331 * THREAD SAFETY:
332 * Not Thread Safe - for performance and complexity reasons
334 * Since this function is only called by PKIX_PL_Initialize, which should
335 * only be called once, it is acceptable that this function is not
336 * thread-safe.
338 PKIX_Error *
339 pkix_pl_InfoAccess_RegisterSelf(void *plContext)
341 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
342 pkix_ClassTable_Entry entry;
344 PKIX_ENTER(INFOACCESS,
345 "pkix_pl_InfoAccess_RegisterSelf");
347 entry.description = "InfoAccess";
348 entry.objCounter = 0;
349 entry.typeObjectSize = sizeof(PKIX_PL_InfoAccess);
350 entry.destructor = pkix_pl_InfoAccess_Destroy;
351 entry.equalsFunction = pkix_pl_InfoAccess_Equals;
352 entry.hashcodeFunction = pkix_pl_InfoAccess_Hashcode;
353 entry.toStringFunction = pkix_pl_InfoAccess_ToString;
354 entry.comparator = NULL;
355 entry.duplicateFunction = pkix_duplicateImmutable;
357 systemClasses[PKIX_INFOACCESS_TYPE] = entry;
359 PKIX_RETURN(INFOACCESS);
363 * FUNCTION: pkix_pl_InfoAccess_CreateList
364 * DESCRIPTION:
366 * Based on data in CERTAuthInfoAccess array "nssInfoAccess", this function
367 * creates and returns a PKIX_List of PKIX_PL_InfoAccess at "pInfoAccessList".
369 * PARAMETERS
370 * "nssInfoAccess"
371 * The pointer array of CERTAuthInfoAccess that contains access data.
372 * May be NULL.
373 * "pInfoAccessList"
374 * Address where a list of PKIX_PL_InfoAccess is returned.
375 * Must be non-NULL.
376 * "plContext"
377 * Platform-specific context pointer.
378 * THREAD SAFETY:
379 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
380 * RETURNS:
381 * Returns NULL if the function succeeds.
382 * Returns a Fatal Error if the function fails in an unrecoverable way.
384 PKIX_Error *
385 pkix_pl_InfoAccess_CreateList(
386 CERTAuthInfoAccess **nssInfoAccess,
387 PKIX_List **pInfoAccessList, /* of PKIX_PL_InfoAccess */
388 void *plContext)
390 PKIX_List *infoAccessList = NULL;
391 PKIX_PL_InfoAccess *infoAccess = NULL;
392 PKIX_PL_GeneralName *location = NULL;
393 PKIX_UInt32 method;
394 int i;
396 PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_CreateList");
397 PKIX_NULLCHECK_ONE(pInfoAccessList);
399 PKIX_CHECK(PKIX_List_Create(&infoAccessList, plContext),
400 PKIX_LISTCREATEFAILED);
402 if (nssInfoAccess == NULL) {
403 goto cleanup;
406 for (i = 0; nssInfoAccess[i] != NULL; i++) {
408 if (nssInfoAccess[i]->location == NULL) {
409 continue;
412 PKIX_CHECK(pkix_pl_GeneralName_Create
413 (nssInfoAccess[i]->location, &location, plContext),
414 PKIX_GENERALNAMECREATEFAILED);
416 PKIX_CERT_DEBUG("\t\tCalling SECOID_FindOIDTag).\n");
417 method = SECOID_FindOIDTag(&nssInfoAccess[i]->method);
419 if (method == 0) {
421 /* XXX
422 * This part of code is definitely hacking, need NSS decode
423 * support. We can reuse the CERT_DecodeAuthInfoAccessExtension
424 * since SIA and AIA are all the same type. However NSS need
425 * to add SIA, CaRepository, TimeStamping OID definitions and
426 * the numerical method, timeStamping and caRepository values.
428 * We assume now, since method is 0, implies the method for SIA
429 * was not decoded by CERT_DecodeAuthInfoAccessExtension()
430 * so we compare and put value in. This part should be taken
431 * out eventually if CERT_DecodeInfoAccessExtension (*renamed*)
432 * is doing the job.
435 PKIX_CERT_DEBUG("\t\tCalling PORT_Strncmp).\n");
436 if (PORT_Strncmp
437 ((char *)nssInfoAccess[i]->method.data,
438 (char *)siaTimeStampingOID,
439 nssInfoAccess[i]->method.len) == 0) {
440 method = SEC_OID_PKIX_TIMESTAMPING;
441 } else if (PORT_Strncmp
442 ((char *)nssInfoAccess[i]->method.data,
443 (char *)siaCaRepositoryOID,
444 nssInfoAccess[i]->method.len) == 0) {
445 method = SEC_OID_PKIX_CA_REPOSITORY;
449 /* Map NSS access method value into PKIX constant */
450 switch(method) {
451 case SEC_OID_PKIX_CA_ISSUERS:
452 method = PKIX_INFOACCESS_CA_ISSUERS;
453 break;
454 case SEC_OID_PKIX_OCSP:
455 method = PKIX_INFOACCESS_OCSP;
456 break;
457 case SEC_OID_PKIX_TIMESTAMPING:
458 method = PKIX_INFOACCESS_TIMESTAMPING;
459 break;
460 case SEC_OID_PKIX_CA_REPOSITORY:
461 method = PKIX_INFOACCESS_CA_REPOSITORY;
462 break;
463 default:
464 break;
467 PKIX_CHECK(pkix_pl_InfoAccess_Create
468 (method, location, &infoAccess, plContext),
469 PKIX_INFOACCESSCREATEFAILED);
471 PKIX_CHECK(PKIX_List_AppendItem
472 (infoAccessList,
473 (PKIX_PL_Object *)infoAccess,
474 plContext),
475 PKIX_LISTAPPENDITEMFAILED);
476 PKIX_DECREF(infoAccess);
477 PKIX_DECREF(location);
480 *pInfoAccessList = infoAccessList;
481 infoAccessList = NULL;
483 cleanup:
485 PKIX_DECREF(infoAccessList);
486 PKIX_DECREF(infoAccess);
487 PKIX_DECREF(location);
489 PKIX_RETURN(INFOACCESS);
492 /* --Public-Functions------------------------------------------------------- */
495 * FUNCTION: PKIX_PL_InfoAccess_GetMethod (see comments in pkix_pl_pki.h)
497 PKIX_Error *
498 PKIX_PL_InfoAccess_GetMethod(
499 PKIX_PL_InfoAccess *infoAccess,
500 PKIX_UInt32 *pMethod,
501 void *plContext)
503 PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetMethod");
504 PKIX_NULLCHECK_TWO(infoAccess, pMethod);
506 *pMethod = infoAccess->method;
508 PKIX_RETURN(INFOACCESS);
512 * FUNCTION: PKIX_PL_InfoAccess_GetLocation (see comments in pkix_pl_pki.h)
514 PKIX_Error *
515 PKIX_PL_InfoAccess_GetLocation(
516 PKIX_PL_InfoAccess *infoAccess,
517 PKIX_PL_GeneralName **pLocation,
518 void *plContext)
520 PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocation");
521 PKIX_NULLCHECK_TWO(infoAccess, pLocation);
523 PKIX_INCREF(infoAccess->location);
525 *pLocation = infoAccess->location;
527 cleanup:
528 PKIX_RETURN(INFOACCESS);
532 * FUNCTION: PKIX_PL_InfoAccess_GetLocationType (see comments in pkix_pl_pki.h)
534 PKIX_Error *
535 PKIX_PL_InfoAccess_GetLocationType(
536 PKIX_PL_InfoAccess *infoAccess,
537 PKIX_UInt32 *pType,
538 void *plContext)
540 PKIX_PL_String *locationString = NULL;
541 PKIX_UInt32 type = PKIX_INFOACCESS_LOCATION_UNKNOWN;
542 PKIX_UInt32 len = 0;
543 void *location = NULL;
545 PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocationType");
546 PKIX_NULLCHECK_TWO(infoAccess, pType);
548 if (infoAccess->location != NULL) {
550 PKIX_TOSTRING(infoAccess->location, &locationString, plContext,
551 PKIX_GENERALNAMETOSTRINGFAILED);
553 PKIX_CHECK(PKIX_PL_String_GetEncoded
554 (locationString, PKIX_ESCASCII, &location, &len, plContext),
555 PKIX_STRINGGETENCODEDFAILED);
557 PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n");
558 if (PORT_Strncmp(location, "ldap:", 5) == 0){
559 type = PKIX_INFOACCESS_LOCATION_LDAP;
560 } else
561 if (PORT_Strncmp(location, "http:", 5) == 0){
562 type = PKIX_INFOACCESS_LOCATION_HTTP;
566 *pType = type;
568 cleanup:
570 PKIX_PL_Free(location, plContext);
571 PKIX_DECREF(locationString);
573 PKIX_RETURN(INFOACCESS);
577 * FUNCTION: pkix_pl_InfoAccess_ParseTokens
578 * DESCRIPTION:
580 * This function parses the string beginning at "startPos" into tokens using
581 * the separator contained in "separator" and the terminator contained in
582 * "terminator", copying the tokens into space allocated from the arena
583 * pointed to by "arena". It stores in "tokens" a null-terminated array of
584 * pointers to those tokens.
586 * PARAMETERS
587 * "arena"
588 * Address of a PRArenaPool to be used in populating the LDAPLocation.
589 * Must be non-NULL.
590 * "startPos"
591 * The address of char string that contains a subset of ldap location.
592 * "tokens"
593 * The address of an array of char string for storing returned tokens.
594 * Must be non-NULL.
595 * "separator"
596 * The character that is taken as token separator. Must be non-NULL.
597 * "terminator"
598 * The character that is taken as parsing terminator. Must be non-NULL.
599 * "plContext"
600 * Platform-specific context pointer.
601 * THREAD SAFETY:
602 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
603 * RETURNS:
604 * Returns NULL if the function succeeds.
605 * Returns an InfoAccess Error if the function fails in a non-fatal way.
606 * Returns a Fatal Error if the function fails in an unrecoverable way.
608 static PKIX_Error *
609 pkix_pl_InfoAccess_ParseTokens(
610 PRArenaPool *arena,
611 char **startPos, /* return update */
612 char ***tokens,
613 char separator,
614 char terminator,
615 void *plContext)
617 PKIX_UInt32 len = 0;
618 PKIX_UInt32 numFilters = 0;
619 PKIX_Int32 cmpResult = -1;
620 char *endPos = NULL;
621 char *p = NULL;
622 char **filterP = NULL;
624 PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseTokens");
625 PKIX_NULLCHECK_THREE(arena, startPos, tokens);
627 endPos = *startPos;
629 /* First pass: parse to <terminator> to count number of components */
630 numFilters = 0;
631 while (*endPos != terminator && *endPos != '\0') {
632 endPos++;
633 if (*endPos == separator) {
634 numFilters++;
638 if (*endPos != terminator) {
639 PKIX_ERROR(PKIX_LOCATIONSTRINGNOTPROPERLYTERMINATED);
642 /* Last one doesn't have a "," as separator, although we allow it */
643 if (*(endPos-1) != ',') {
644 numFilters++;
648 * If string is a=xx, b=yy, c=zz, etc., use a=xx for filter,
649 * and everything else for the base
651 if (numFilters > 2) numFilters = 2;
653 PKIX_PL_NSSCALLRV
654 (INFOACCESS, *tokens, PORT_ArenaZAlloc,
655 (arena, (numFilters+1)*sizeof(void *)));
657 /* Second pass: parse to fill in components in token array */
658 filterP = *tokens;
659 endPos = *startPos;
661 while (numFilters) {
662 if (*endPos == separator || *endPos == terminator) {
663 len = endPos - *startPos;
664 PKIX_PL_NSSCALLRV(INFOACCESS, p, PORT_ArenaZAlloc,
665 (arena, (len+1)));
667 *filterP = p;
669 while (len) {
670 if (**startPos == '%') {
671 /* replace %20 by blank */
672 PKIX_PL_NSSCALLRV(INFOACCESS, cmpResult,
673 strncmp, ((void *)*startPos, "%20", 3));
674 if (cmpResult == 0) {
675 *p = ' ';
676 *startPos += 3;
677 len -= 3;
679 } else {
680 *p = **startPos;
681 (*startPos)++;
682 len--;
684 p++;
687 *p = '\0';
688 filterP++;
689 numFilters--;
691 separator = terminator;
693 if (endPos == '\0') {
694 break;
695 } else {
696 endPos++;
697 *startPos = endPos;
698 continue;
701 endPos++;
704 *filterP = NULL;
706 cleanup:
708 PKIX_RETURN(INFOACCESS);
712 * FUNCTION: pkix_pl_InfoAccess_ParseLocation
713 * DESCRIPTION:
715 * This function parses the GeneralName pointed to by "generalName" into the
716 * fields of the LDAPRequestParams pointed to by "request" and a domainName
717 * pointed to by "pDomainName", using the PRArenaPool pointed to by "arena" to
718 * allocate storage for the request components and for the domainName string.
720 * The expected GeneralName string should be in the format described by the
721 * following BNF:
723 * ldap://<ldap-server-site>/[cn=<cname>][,o=<org>][,c=<country>]?
724 * [caCertificate|crossCertificatPair|certificateRevocationList];
725 * [binary|<other-type>]
726 * [[,caCertificate|crossCertificatPair|certificateRevocationList]
727 * [binary|<other-type>]]*
729 * PARAMETERS
730 * "generalName"
731 * Address of the GeneralName whose LDAPLocation is to be parsed. Must be
732 * non-NULL.
733 * "arena"
734 * Address of PRArenaPool to be used for the domainName and for components
735 * of the LDAPRequest. Must be non-NULL.
736 * "request"
737 * Address of the LDAPRequestParams into which request components are
738 * stored. Must be non-NULL.
739 * *pDomainName"
740 * Address at which the domainName is stored. Must be non-NULL.
741 * "plContext"
742 * Platform-specific context pointer.
743 * THREAD SAFETY:
744 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
745 * RETURNS:
746 * Returns NULL if the function succeeds.
747 * Returns an InfoAccess Error if the function fails in a non-fatal way.
748 * Returns a Fatal Error if the function fails in an unrecoverable way.
750 PKIX_Error *
751 pkix_pl_InfoAccess_ParseLocation(
752 PKIX_PL_GeneralName *generalName,
753 PRArenaPool *arena,
754 LDAPRequestParams *request,
755 char **pDomainName,
756 void *plContext)
758 PKIX_PL_String *locationString = NULL;
759 PKIX_UInt32 len = 0;
760 PKIX_UInt32 ncIndex = 0;
761 char *domainName = NULL;
762 char **avaArray = NULL;
763 char **attrArray = NULL;
764 char *attr = NULL;
765 char *locationAscii = NULL;
766 char *startPos = NULL;
767 char *endPos = NULL;
768 char *avaPtr = NULL;
769 LdapAttrMask attrBit = 0;
770 LDAPNameComponent **setOfNameComponent = NULL;
771 LDAPNameComponent *nameComponent = NULL;
772 void *v = NULL;
774 PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseLocation");
775 PKIX_NULLCHECK_FOUR(generalName, arena, request, pDomainName);
777 PKIX_TOSTRING(generalName, &locationString, plContext,
778 PKIX_GENERALNAMETOSTRINGFAILED);
780 PKIX_CHECK(PKIX_PL_String_GetEncoded
781 (locationString,
782 PKIX_ESCASCII,
783 (void **)&locationAscii,
784 &len,
785 plContext),
786 PKIX_STRINGGETENCODEDFAILED);
788 #if 0
789 /* For testing inside the firewall... */
790 locationAscii = "ldap://nss.red.iplanet.com:1389/cn=Good%20CA,o="
791 "Test%20Certificates,c=US?caCertificate;binary";
792 #endif
794 /* Skip "ldap:" */
795 endPos = locationAscii;
796 while (*endPos != ':' && *endPos != '\0') {
797 endPos++;
799 if (*endPos == '\0') {
800 PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGLOCATIONTYPE);
803 /* Skip "//" */
804 endPos++;
805 if (*endPos != '\0' && *(endPos+1) != '0' &&
806 *endPos == '/' && *(endPos+1) == '/') {
807 endPos += 2;
808 } else {
809 PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGDOUBLESLASH);
812 /* Get the server-site */
813 startPos = endPos;
814 while(*endPos != '/' && *(endPos) != '\0') {
815 endPos++;
817 if (*endPos == '\0') {
818 PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGSERVERSITE);
821 len = endPos - startPos;
822 endPos++;
824 PKIX_PL_NSSCALLRV(INFOACCESS, domainName, PORT_ArenaZAlloc,
825 (arena, len + 1));
827 PKIX_PL_NSSCALL(INFOACCESS, PORT_Memcpy, (domainName, startPos, len));
829 domainName[len] = '\0';
831 *pDomainName = domainName;
834 * Get a list of AttrValueAssertions (such as
835 * "cn=CommonName, o=Organization, c=US" into a null-terminated array
837 startPos = endPos;
838 PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens
839 (arena,
840 &startPos,
841 (char ***) &avaArray,
842 ',',
843 '?',
844 plContext),
845 PKIX_INFOACCESSPARSETOKENSFAILED);
847 /* Count how many AVAs we have */
848 for (len = 0; avaArray[len] != NULL; len++) {}
850 if (len < 2) {
851 PKIX_ERROR(PKIX_NOTENOUGHNAMECOMPONENTSINGENERALNAME);
854 /* Use last name component for baseObject */
855 request->baseObject = avaArray[len - 1];
857 /* Use only one component for filter. LDAP servers aren't too smart. */
858 len = 2; /* Eliminate this when servers get smarter. */
860 avaArray[len - 1] = NULL;
862 /* Get room for null-terminated array of (LdapNameComponent *) */
863 PKIX_PL_NSSCALLRV
864 (INFOACCESS, v, PORT_ArenaZAlloc,
865 (arena, len*sizeof(LDAPNameComponent *)));
867 setOfNameComponent = (LDAPNameComponent **)v;
869 /* Get room for the remaining LdapNameComponents */
870 PKIX_PL_NSSCALLRV
871 (INFOACCESS, v, PORT_ArenaZNewArray,
872 (arena, LDAPNameComponent, --len));
874 nameComponent = (LDAPNameComponent *)v;
876 /* Convert remaining AVAs to LDAPNameComponents */
877 for (ncIndex = 0; ncIndex < len; ncIndex ++) {
878 setOfNameComponent[ncIndex] = nameComponent;
879 avaPtr = avaArray[ncIndex];
880 nameComponent->attrType = (unsigned char *)avaPtr;
881 while ((*avaPtr != '=') && (*avaPtr != '\0')) {
882 avaPtr++;
883 if (avaPtr == '\0') {
884 PKIX_ERROR(PKIX_NAMECOMPONENTWITHNOEQ);
887 *(avaPtr++) = '\0';
888 nameComponent->attrValue = (unsigned char *)avaPtr;
889 nameComponent++;
892 setOfNameComponent[len] = NULL;
893 request->nc = setOfNameComponent;
896 * Get a list of AttrTypes (such as
897 * "caCertificate;binary, crossCertificatePair;binary") into
898 * a null-terminated array
901 PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens
902 (arena,
903 (char **) &startPos,
904 (char ***) &attrArray,
905 ',',
906 '\0',
907 plContext),
908 PKIX_INFOACCESSPARSETOKENSFAILED);
910 /* Convert array of Attr Types into a bit mask */
911 request->attributes = 0;
912 attr = attrArray[0];
913 while (attr != NULL) {
914 PKIX_CHECK(pkix_pl_LdapRequest_AttrStringToBit
915 (attr, &attrBit, plContext),
916 PKIX_LDAPREQUESTATTRSTRINGTOBITFAILED);
917 request->attributes |= attrBit;
918 attr = *(++attrArray);
921 cleanup:
923 PKIX_PL_Free(locationAscii, plContext);
924 PKIX_DECREF(locationString);
926 PKIX_RETURN(INFOACCESS);