Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / libpkix / pkix / results / pkix_policynode.c
blob0ab071083cede0eb3744df4fe8b9a261813ce2a2
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 Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Sun Microsystems
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_policynode.c
40 * Policy Node Object Type Definition
44 #include "pkix_policynode.h"
46 /* --Private-PolicyNode-Functions---------------------------------- */
49 * FUNCTION: pkix_PolicyNode_GetChildrenMutable
50 * DESCRIPTION:
52 * Retrieves the List of PolicyNodes representing the child nodes of the
53 * Policy Node pointed to by "node" and stores it at "pChildren". If "node"
54 * has no List of child nodes, this function stores NULL at "pChildren".
56 * Note that the List returned by this function may be mutable. This function
57 * differs from the public function PKIX_PolicyNode_GetChildren in that
58 * respect. (It also differs in that the public function creates an empty
59 * List, if necessary, rather than storing NULL.)
61 * During certificate processing, children Lists are created and modified.
62 * Once the list is accessed using the public call, the List is set immutable.
64 * PARAMETERS:
65 * "node"
66 * Address of PolicyNode whose child nodes are to be stored.
67 * Must be non-NULL.
68 * "pChildren"
69 * Address where object pointer will be stored. Must be non-NULL.
70 * "plContext"
71 * Platform-specific context pointer.
72 * THREAD SAFETY:
73 * Conditionally Thread Safe
74 * (see Thread Safety Definitions in Programmer's Guide)
75 * RETURNS:
76 * Returns NULL if the function succeeds.
77 * Returns a PolicyNode Error if the function fails in a non-fatal way.
78 * Returns a Fatal Error if the function fails in an unrecoverable way.
80 PKIX_Error *
81 pkix_PolicyNode_GetChildrenMutable(
82 PKIX_PolicyNode *node,
83 PKIX_List **pChildren, /* list of PKIX_PolicyNode */
84 void *plContext)
87 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_GetChildrenMutable");
89 PKIX_NULLCHECK_TWO(node, pChildren);
91 PKIX_INCREF(node->children);
93 *pChildren = node->children;
95 PKIX_RETURN(CERTPOLICYNODE);
99 * FUNCTION: pkix_PolicyNode_Create
100 * DESCRIPTION:
102 * Creates a new PolicyNode using the OID pointed to by "validPolicy", the List
103 * of CertPolicyQualifiers pointed to by "qualifierSet", the criticality
104 * indicated by the Boolean value of "criticality", and the List of OIDs
105 * pointed to by "expectedPolicySet", and stores the result at "pObject". The
106 * criticality should be derived from whether the certificate policy extension
107 * was marked as critical in the certificate that led to creation of this
108 * PolicyNode. The "qualifierSet" and "expectedPolicySet" Lists are made
109 * immutable. The PolicyNode pointers to parent and to children are initialized
110 * to NULL, and the depth is set to zero; those values should be set by using
111 * the pkix_PolicyNode_AddToParent function.
113 * PARAMETERS
114 * "validPolicy"
115 * Address of OID of the valid policy for the path. Must be non-NULL
116 * "qualifierSet"
117 * Address of List of CertPolicyQualifiers associated with the validpolicy.
118 * May be NULL
119 * "criticality"
120 * Boolean indicator of whether the criticality should be set in this
121 * PolicyNode
122 * "expectedPolicySet"
123 * Address of List of OIDs that would satisfy this policy in the next
124 * certificate. Must be non-NULL
125 * "pObject"
126 * Address where the PolicyNode pointer will be stored. Must be non-NULL.
127 * "plContext"
128 * Platform-specific context pointer.
129 * THREAD SAFETY:
130 * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
131 * RETURNS:
132 * Returns NULL if the function succeeds.
133 * Returns a PolicyNode Error if the function fails in a non-fatal way.
134 * Returns a Fatal Error if the function fails in an unrecoverable way.
136 PKIX_Error *
137 pkix_PolicyNode_Create(
138 PKIX_PL_OID *validPolicy,
139 PKIX_List *qualifierSet,
140 PKIX_Boolean criticality,
141 PKIX_List *expectedPolicySet,
142 PKIX_PolicyNode **pObject,
143 void *plContext)
145 PKIX_PolicyNode *node = NULL;
147 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Create");
149 PKIX_NULLCHECK_THREE(validPolicy, expectedPolicySet, pObject);
151 PKIX_CHECK(PKIX_PL_Object_Alloc
152 (PKIX_CERTPOLICYNODE_TYPE,
153 sizeof (PKIX_PolicyNode),
154 (PKIX_PL_Object **)&node,
155 plContext),
156 PKIX_COULDNOTCREATEPOLICYNODEOBJECT);
158 PKIX_INCREF(validPolicy);
159 node->validPolicy = validPolicy;
161 PKIX_INCREF(qualifierSet);
162 node->qualifierSet = qualifierSet;
163 if (qualifierSet) {
164 PKIX_CHECK(PKIX_List_SetImmutable(qualifierSet, plContext),
165 PKIX_LISTSETIMMUTABLEFAILED);
168 node->criticality = criticality;
170 PKIX_INCREF(expectedPolicySet);
171 node->expectedPolicySet = expectedPolicySet;
172 PKIX_CHECK(PKIX_List_SetImmutable(expectedPolicySet, plContext),
173 PKIX_LISTSETIMMUTABLEFAILED);
175 node->parent = NULL;
176 node->children = NULL;
177 node->depth = 0;
179 *pObject = node;
181 cleanup:
182 if (PKIX_ERROR_RECEIVED) {
183 PKIX_DECREF(node);
186 PKIX_RETURN(CERTPOLICYNODE);
190 * FUNCTION: pkix_PolicyNode_AddToParent
191 * DESCRIPTION:
193 * Adds the PolicyNode pointed to by "child" to the List of children of
194 * the PolicyNode pointed to by "parentNode". If "parentNode" had a
195 * NULL pointer for the List of children, a new List is created containing
196 * "child". Otherwise "child" is appended to the existing List. The
197 * parent field in "child" is set to "parent", and the depth field is
198 * set to one more than the corresponding value in "parent".
200 * Depth, in this context, means distance from the root node, which
201 * is at depth zero.
203 * PARAMETERS:
204 * "parentNode"
205 * Address of PolicyNode whose List of child PolicyNodes is to be
206 * created or appended to. Must be non-NULL.
207 * "child"
208 * Address of PolicyNode to be added to parentNode's List. Must be
209 * non-NULL.
210 * "plContext"
211 * Platform-specific context pointer.
212 * THREAD SAFETY:
213 * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
214 * RETURNS:
215 * Returns NULL if the function succeeds.
216 * Returns a PolicyNode Error if the function fails in a non-fatal way.
217 * Returns a Fatal Error if the function fails in an unrecoverable way.
219 PKIX_Error *
220 pkix_PolicyNode_AddToParent(
221 PKIX_PolicyNode *parentNode,
222 PKIX_PolicyNode *child,
223 void *plContext)
225 PKIX_List *listOfChildren = NULL;
227 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_AddToParent");
229 PKIX_NULLCHECK_TWO(parentNode, child);
231 listOfChildren = parentNode->children;
232 if (listOfChildren == NULL) {
233 PKIX_CHECK(PKIX_List_Create(&listOfChildren, plContext),
234 PKIX_LISTCREATEFAILED);
235 parentNode->children = listOfChildren;
239 * Note: this link is not reference-counted. The link from parent
240 * to child is counted (actually, the parent "owns" a List which
241 * "owns" children), but the children do not "own" the parent.
242 * Otherwise, there would be loops.
244 child->parent = parentNode;
246 child->depth = 1 + (parentNode->depth);
248 PKIX_CHECK(PKIX_List_AppendItem
249 (listOfChildren, (PKIX_PL_Object *)child, plContext),
250 PKIX_COULDNOTAPPENDCHILDTOPARENTSPOLICYNODELIST);
252 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
253 ((PKIX_PL_Object *)parentNode, plContext),
254 PKIX_OBJECTINVALIDATECACHEFAILED);
256 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
257 ((PKIX_PL_Object *)child, plContext),
258 PKIX_OBJECTINVALIDATECACHEFAILED);
260 cleanup:
262 PKIX_RETURN(CERTPOLICYNODE);
266 * FUNCTION: pkix_PolicyNode_Prune
267 * DESCRIPTION:
269 * Prunes a tree below the PolicyNode whose address is pointed to by "node",
270 * using the UInt32 value of "height" as the distance from the leaf level,
271 * and storing at "pDelete" the Boolean value of whether this PolicyNode is,
272 * after pruning, childless and should be pruned.
274 * Any PolicyNode at height 0 is allowed to survive. If the height is greater
275 * than zero, pkix_PolicyNode_Prune is called recursively for each child of
276 * the current PolicyNode. After this process, a node with no children
277 * stores PKIX_TRUE in "pDelete" to indicate that it should be deleted.
279 * PARAMETERS:
280 * "node"
281 * Address of the PolicyNode to be pruned. Must be non-NULL.
282 * "height"
283 * UInt32 value for the distance from the leaf level
284 * "pDelete"
285 * Address to store the Boolean return value of PKIX_TRUE if this node
286 * should be pruned, or PKIX_FALSE if there remains at least one
287 * branch of the required height. Must be non-NULL.
288 * "plContext"
289 * Platform-specific context pointer.
290 * THREAD SAFETY:
291 * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
292 * RETURNS:
293 * Returns NULL if the function succeeds.
294 * Returns a PolicyNode Error if the function fails in a non-fatal way.
295 * Returns a Fatal Error if the function fails in an unrecoverable way.
297 PKIX_Error *
298 pkix_PolicyNode_Prune(
299 PKIX_PolicyNode *node,
300 PKIX_UInt32 height,
301 PKIX_Boolean *pDelete,
302 void *plContext)
304 PKIX_Boolean childless = PKIX_FALSE;
305 PKIX_Boolean shouldBePruned = PKIX_FALSE;
306 PKIX_UInt32 listSize = 0;
307 PKIX_UInt32 listIndex = 0;
308 PKIX_PolicyNode *candidate = NULL;
310 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Prune");
312 PKIX_NULLCHECK_TWO(node, pDelete);
314 /* Don't prune at the leaf */
315 if (height == 0) {
316 goto cleanup;
319 /* Above the bottom level, childless nodes get pruned */
320 if (!(node->children)) {
321 childless = PKIX_TRUE;
322 goto cleanup;
326 * This node has children. If they are leaf nodes,
327 * we know they will live. Otherwise, check them out.
329 if (height > 1) {
330 PKIX_CHECK(PKIX_List_GetLength
331 (node->children, &listSize, plContext),
332 PKIX_LISTGETLENGTHFAILED);
334 * By working backwards from the end of the list,
335 * we avoid having to worry about possible
336 * decreases in the size of the list, as we
337 * delete items. The only nuisance is that since the
338 * index is UInt32, we can't check for it to reach -1;
339 * we have to use the 1-based index, rather than the
340 * 0-based index that PKIX_List functions require.
342 for (listIndex = listSize; listIndex > 0; listIndex--) {
343 PKIX_CHECK(PKIX_List_GetItem
344 (node->children,
345 (listIndex - 1),
346 (PKIX_PL_Object **)&candidate,
347 plContext),
348 PKIX_LISTGETITEMFAILED);
350 PKIX_CHECK(pkix_PolicyNode_Prune
351 (candidate,
352 height - 1,
353 &shouldBePruned,
354 plContext),
355 PKIX_POLICYNODEPRUNEFAILED);
357 if (shouldBePruned == PKIX_TRUE) {
358 PKIX_CHECK(PKIX_List_DeleteItem
359 (node->children,
360 (listIndex - 1),
361 plContext),
362 PKIX_LISTDELETEITEMFAILED);
365 PKIX_DECREF(candidate);
369 /* Prune if this node has *become* childless */
370 PKIX_CHECK(PKIX_List_GetLength
371 (node->children, &listSize, plContext),
372 PKIX_LISTGETLENGTHFAILED);
373 if (listSize == 0) {
374 childless = PKIX_TRUE;
378 * Even if we did not change this node, or any of its children,
379 * maybe a [great-]*grandchild was pruned.
381 PKIX_CHECK(PKIX_PL_Object_InvalidateCache
382 ((PKIX_PL_Object *)node, plContext),
383 PKIX_OBJECTINVALIDATECACHEFAILED);
385 cleanup:
386 *pDelete = childless;
388 PKIX_DECREF(candidate);
390 PKIX_RETURN(CERTPOLICYNODE);
394 * FUNCTION: pkix_SinglePolicyNode_ToString
395 * DESCRIPTION:
397 * Creates a String representation of the attributes of the PolicyNode
398 * pointed to by "node", other than its parents or children, and
399 * stores the result at "pString".
401 * PARAMETERS:
402 * "node"
403 * Address of PolicyNode to be described by the string. Must be non-NULL.
404 * "pString"
405 * Address where object pointer will be stored. Must be non-NULL.
406 * "plContext"
407 * Platform-specific context pointer.
408 * THREAD SAFETY:
409 * Conditionally Thread Safe
410 * (see Thread Safety Definitions in Programmer's Guide)
411 * RETURNS:
412 * Returns NULL if function succeeds
413 * Returns a PolicyNode Error if the function fails in a non-fatal way.
414 * Returns a Fatal Error if the function fails in a fatal way
416 PKIX_Error *
417 pkix_SinglePolicyNode_ToString(
418 PKIX_PolicyNode *node,
419 PKIX_PL_String **pString,
420 void *plContext)
422 PKIX_PL_String *fmtString = NULL;
423 PKIX_PL_String *validString = NULL;
424 PKIX_PL_String *qualifierString = NULL;
425 PKIX_PL_String *criticalityString = NULL;
426 PKIX_PL_String *expectedString = NULL;
427 PKIX_PL_String *outString = NULL;
429 PKIX_ENTER(CERTPOLICYNODE, "pkix_SinglePolicyNode_ToString");
430 PKIX_NULLCHECK_TWO(node, pString);
431 PKIX_NULLCHECK_TWO(node->validPolicy, node->expectedPolicySet);
433 PKIX_CHECK(PKIX_PL_String_Create
434 (PKIX_ESCASCII,
435 "{%s,%s,%s,%s,%d}",
437 &fmtString,
438 plContext),
439 PKIX_CANTCREATESTRING);
441 PKIX_CHECK(PKIX_PL_Object_ToString
442 ((PKIX_PL_Object *)(node->validPolicy),
443 &validString,
444 plContext),
445 PKIX_OIDTOSTRINGFAILED);
447 PKIX_CHECK(PKIX_PL_Object_ToString
448 ((PKIX_PL_Object *)(node->expectedPolicySet),
449 &expectedString,
450 plContext),
451 PKIX_LISTTOSTRINGFAILED);
453 if (node->qualifierSet) {
454 PKIX_CHECK(PKIX_PL_Object_ToString
455 ((PKIX_PL_Object *)(node->qualifierSet),
456 &qualifierString,
457 plContext),
458 PKIX_LISTTOSTRINGFAILED);
459 } else {
460 PKIX_CHECK(PKIX_PL_String_Create
461 (PKIX_ESCASCII,
462 "{}",
464 &qualifierString,
465 plContext),
466 PKIX_CANTCREATESTRING);
469 PKIX_CHECK(PKIX_PL_String_Create
470 (PKIX_ESCASCII,
471 (node->criticality)?"Critical":"Not Critical",
473 &criticalityString,
474 plContext),
475 PKIX_CANTCREATESTRING);
477 PKIX_CHECK(PKIX_PL_Sprintf
478 (&outString,
479 plContext,
480 fmtString,
481 validString,
482 qualifierString,
483 criticalityString,
484 expectedString,
485 node->depth),
486 PKIX_SPRINTFFAILED);
488 *pString = outString;
490 cleanup:
492 PKIX_DECREF(fmtString);
493 PKIX_DECREF(validString);
494 PKIX_DECREF(qualifierString);
495 PKIX_DECREF(criticalityString);
496 PKIX_DECREF(expectedString);
497 PKIX_RETURN(CERTPOLICYNODE);
501 * FUNCTION: pkix_PolicyNode_ToString_Helper
502 * DESCRIPTION:
504 * Produces a String representation of a PolicyNode tree below the PolicyNode
505 * pointed to by "rootNode", with each line of output prefixed by the String
506 * pointed to by "indent", and stores the result at "pTreeString". It is
507 * called recursively, with ever-increasing indentation, for successively
508 * lower nodes on the tree.
510 * PARAMETERS:
511 * "rootNode"
512 * Address of PolicyNode subtree. Must be non-NULL.
513 * "indent"
514 * Address of String to be prefixed to each line of output. May be NULL
515 * if no indentation is desired
516 * "pTreeString"
517 * Address where the resulting String will be stored; must be non-NULL
518 * "plContext"
519 * Platform-specific context pointer.
520 * THREAD SAFETY:
521 * Conditionally Thread Safe
522 * (see Thread Safety Definitions in Programmer's Guide)
523 * RETURNS:
524 * Returns NULL if the function succeeds.
525 * Returns a PolicyNode Error if the function fails in a non-fatal way.
526 * Returns a Fatal Error if the function fails in an unrecoverable way.
528 static PKIX_Error *
529 pkix_PolicyNode_ToString_Helper(
530 PKIX_PolicyNode *rootNode,
531 PKIX_PL_String *indent,
532 PKIX_PL_String **pTreeString,
533 void *plContext)
535 PKIX_PL_String *nextIndentFormat = NULL;
536 PKIX_PL_String *thisNodeFormat = NULL;
537 PKIX_PL_String *childrenFormat = NULL;
538 PKIX_PL_String *nextIndentString = NULL;
539 PKIX_PL_String *resultString = NULL;
540 PKIX_PL_String *thisItemString = NULL;
541 PKIX_PL_String *childString = NULL;
542 PKIX_PolicyNode *childNode = NULL;
543 PKIX_UInt32 numberOfChildren = 0;
544 PKIX_UInt32 childIndex = 0;
546 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_ToString_Helper");
548 PKIX_NULLCHECK_TWO(rootNode, pTreeString);
550 /* Create a string for this node */
551 PKIX_CHECK(pkix_SinglePolicyNode_ToString
552 (rootNode, &thisItemString, plContext),
553 PKIX_ERRORINSINGLEPOLICYNODETOSTRING);
555 if (indent) {
556 PKIX_CHECK(PKIX_PL_String_Create
557 (PKIX_ESCASCII,
558 "%s%s",
560 &thisNodeFormat,
561 plContext),
562 PKIX_ERRORCREATINGFORMATSTRING);
564 PKIX_CHECK(PKIX_PL_Sprintf
565 (&resultString,
566 plContext,
567 thisNodeFormat,
568 indent,
569 thisItemString),
570 PKIX_ERRORINSPRINTF);
571 } else {
572 PKIX_CHECK(PKIX_PL_String_Create
573 (PKIX_ESCASCII,
574 "%s",
576 &thisNodeFormat,
577 plContext),
578 PKIX_ERRORCREATINGFORMATSTRING);
580 PKIX_CHECK(PKIX_PL_Sprintf
581 (&resultString,
582 plContext,
583 thisNodeFormat,
584 thisItemString),
585 PKIX_ERRORINSPRINTF);
588 PKIX_DECREF(thisItemString);
589 thisItemString = resultString;
591 /* if no children, we are done */
592 if (rootNode->children) {
593 PKIX_CHECK(PKIX_List_GetLength
594 (rootNode->children, &numberOfChildren, plContext),
595 PKIX_LISTGETLENGTHFAILED);
598 if (numberOfChildren != 0) {
600 * We create a string for each child in turn,
601 * concatenating them to thisItemString.
604 /* Prepare an indent string for each child */
605 if (indent) {
606 PKIX_CHECK(PKIX_PL_String_Create
607 (PKIX_ESCASCII,
608 "%s. ",
610 &nextIndentFormat,
611 plContext),
612 PKIX_ERRORCREATINGFORMATSTRING);
614 PKIX_CHECK(PKIX_PL_Sprintf
615 (&nextIndentString,
616 plContext,
617 nextIndentFormat,
618 indent),
619 PKIX_ERRORINSPRINTF);
620 } else {
621 PKIX_CHECK(PKIX_PL_String_Create
622 (PKIX_ESCASCII,
623 ". ",
625 &nextIndentString,
626 plContext),
627 PKIX_ERRORCREATINGINDENTSTRING);
630 /* Prepare the format for concatenation. */
631 PKIX_CHECK(PKIX_PL_String_Create
632 (PKIX_ESCASCII,
633 "%s\n%s",
635 &childrenFormat,
636 plContext),
637 PKIX_ERRORCREATINGFORMATSTRING);
639 for (childIndex = 0;
640 childIndex < numberOfChildren;
641 childIndex++) {
642 PKIX_CHECK(PKIX_List_GetItem
643 (rootNode->children,
644 childIndex,
645 (PKIX_PL_Object **)&childNode,
646 plContext),
647 PKIX_LISTGETITEMFAILED);
649 PKIX_CHECK(pkix_PolicyNode_ToString_Helper
650 (childNode,
651 nextIndentString,
652 &childString,
653 plContext),
654 PKIX_ERRORCREATINGCHILDSTRING);
657 PKIX_CHECK(PKIX_PL_Sprintf
658 (&resultString,
659 plContext,
660 childrenFormat,
661 thisItemString,
662 childString),
663 PKIX_ERRORINSPRINTF);
665 PKIX_DECREF(childNode);
666 PKIX_DECREF(childString);
667 PKIX_DECREF(thisItemString);
669 thisItemString = resultString;
673 *pTreeString = thisItemString;
675 cleanup:
676 if (PKIX_ERROR_RECEIVED) {
677 PKIX_DECREF(thisItemString);
680 PKIX_DECREF(nextIndentFormat);
681 PKIX_DECREF(thisNodeFormat);
682 PKIX_DECREF(childrenFormat);
683 PKIX_DECREF(nextIndentString);
684 PKIX_DECREF(childString);
685 PKIX_DECREF(childNode);
687 PKIX_RETURN(CERTPOLICYNODE);
691 * FUNCTION: pkix_PolicyNode_ToString
692 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
694 static PKIX_Error *
695 pkix_PolicyNode_ToString(
696 PKIX_PL_Object *object,
697 PKIX_PL_String **pTreeString,
698 void *plContext)
700 PKIX_PolicyNode *rootNode = NULL;
701 PKIX_PL_String *resultString = NULL;
703 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_ToString");
705 PKIX_NULLCHECK_TWO(object, pTreeString);
707 PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYNODE_TYPE, plContext),
708 PKIX_OBJECTNOTPOLICYNODE);
710 rootNode = (PKIX_PolicyNode *)object;
712 PKIX_CHECK(pkix_PolicyNode_ToString_Helper
713 (rootNode, NULL, &resultString, plContext),
714 PKIX_ERRORCREATINGSUBTREESTRING);
716 *pTreeString = resultString;
718 cleanup:
720 PKIX_RETURN(CERTPOLICYNODE);
724 * FUNCTION: pkix_PolicyNode_Destroy
725 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
727 static PKIX_Error *
728 pkix_PolicyNode_Destroy(
729 PKIX_PL_Object *object,
730 void *plContext)
732 PKIX_PolicyNode *node = NULL;
734 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Destroy");
736 PKIX_NULLCHECK_ONE(object);
738 PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYNODE_TYPE, plContext),
739 PKIX_OBJECTNOTPOLICYNODE);
741 node = (PKIX_PolicyNode*)object;
743 node->criticality = PKIX_FALSE;
744 PKIX_DECREF(node->validPolicy);
745 PKIX_DECREF(node->qualifierSet);
746 PKIX_DECREF(node->expectedPolicySet);
747 PKIX_DECREF(node->children);
750 * Note: the link to parent is not reference-counted. See comment
751 * in pkix_PolicyNode_AddToParent for more details.
753 node->parent = NULL;
754 node->depth = 0;
756 cleanup:
758 PKIX_RETURN(CERTPOLICYNODE);
762 * FUNCTION: pkix_SinglePolicyNode_Hashcode
763 * DESCRIPTION:
765 * Computes the hashcode of the attributes of the PolicyNode pointed to by
766 * "node", other than its parents and children, and stores the result at
767 * "pHashcode".
769 * PARAMETERS:
770 * "node"
771 * Address of PolicyNode to be hashcoded; must be non-NULL
772 * "pHashcode"
773 * Address where UInt32 result will be stored; must be non-NULL
774 * "plContext"
775 * Platform-specific context pointer.
776 * THREAD SAFETY:
777 * Conditionally Thread Safe
778 * (see Thread Safety Definitions in Programmer's Guide)
779 * RETURNS:
780 * Returns NULL if function succeeds
781 * Returns a PolicyNode Error if the function fails in a non-fatal way.
782 * Returns a Fatal Error if the function fails in a fatal way
784 static PKIX_Error *
785 pkix_SinglePolicyNode_Hashcode(
786 PKIX_PolicyNode *node,
787 PKIX_UInt32 *pHashcode,
788 void *plContext)
790 PKIX_UInt32 componentHash = 0;
791 PKIX_UInt32 nodeHash = 0;
793 PKIX_ENTER(CERTPOLICYNODE, "pkix_SinglePolicyNode_Hashcode");
794 PKIX_NULLCHECK_TWO(node, pHashcode);
795 PKIX_NULLCHECK_TWO(node->validPolicy, node->expectedPolicySet);
797 PKIX_HASHCODE
798 (node->qualifierSet,
799 &nodeHash,
800 plContext,
801 PKIX_FAILUREHASHINGLISTQUALIFIERSET);
803 if (PKIX_TRUE == (node->criticality)) {
804 nodeHash = 31*nodeHash + 0xff;
805 } else {
806 nodeHash = 31*nodeHash + 0x00;
809 PKIX_CHECK(PKIX_PL_Object_Hashcode
810 ((PKIX_PL_Object *)node->validPolicy,
811 &componentHash,
812 plContext),
813 PKIX_FAILUREHASHINGOIDVALIDPOLICY);
815 nodeHash = 31*nodeHash + componentHash;
817 PKIX_CHECK(PKIX_PL_Object_Hashcode
818 ((PKIX_PL_Object *)node->expectedPolicySet,
819 &componentHash,
820 plContext),
821 PKIX_FAILUREHASHINGLISTEXPECTEDPOLICYSET);
823 nodeHash = 31*nodeHash + componentHash;
825 *pHashcode = nodeHash;
827 cleanup:
829 PKIX_RETURN(CERTPOLICYNODE);
833 * FUNCTION: pkix_PolicyNode_Hashcode
834 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
836 static PKIX_Error *
837 pkix_PolicyNode_Hashcode(
838 PKIX_PL_Object *object,
839 PKIX_UInt32 *pHashcode,
840 void *plContext)
842 PKIX_PolicyNode *node = NULL;
843 PKIX_UInt32 childrenHash = 0;
844 PKIX_UInt32 nodeHash = 0;
846 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Hashcode");
847 PKIX_NULLCHECK_TWO(object, pHashcode);
849 PKIX_CHECK(pkix_CheckType
850 (object, PKIX_CERTPOLICYNODE_TYPE, plContext),
851 PKIX_OBJECTNOTPOLICYNODE);
853 node = (PKIX_PolicyNode *)object;
855 PKIX_CHECK(pkix_SinglePolicyNode_Hashcode
856 (node, &nodeHash, plContext),
857 PKIX_SINGLEPOLICYNODEHASHCODEFAILED);
859 nodeHash = 31*nodeHash + (PKIX_UInt32)(node->parent);
861 PKIX_HASHCODE
862 (node->children,
863 &childrenHash,
864 plContext,
865 PKIX_OBJECTHASHCODEFAILED);
867 nodeHash = 31*nodeHash + childrenHash;
869 *pHashcode = nodeHash;
871 cleanup:
873 PKIX_RETURN(CERTPOLICYNODE);
877 * FUNCTION: pkix_SinglePolicyNode_Equals
878 * DESCRIPTION:
880 * Compares for equality the components of the PolicyNode pointed to by
881 * "firstPN", other than its parents and children, with those of the
882 * PolicyNode pointed to by "secondPN" and stores the result at "pResult"
883 * (PKIX_TRUE if equal; PKIX_FALSE if not).
885 * PARAMETERS:
886 * "firstPN"
887 * Address of first of the PolicyNodes to be compared; must be non-NULL
888 * "secondPN"
889 * Address of second of the PolicyNodes to be compared; must be non-NULL
890 * "pResult"
891 * Address where Boolean will be stored; must be non-NULL
892 * "plContext"
893 * Platform-specific context pointer.
894 * THREAD SAFETY:
895 * Conditionally Thread Safe
896 * (see Thread Safety Definitions in Programmer's Guide)
897 * RETURNS:
898 * Returns NULL if function succeeds
899 * Returns a PolicyNode Error if the function fails in a non-fatal way.
900 * Returns a Fatal Error if the function fails in a fatal way
902 static PKIX_Error *
903 pkix_SinglePolicyNode_Equals(
904 PKIX_PolicyNode *firstPN,
905 PKIX_PolicyNode *secondPN,
906 PKIX_Boolean *pResult,
907 void *plContext)
909 PKIX_Boolean compResult = PKIX_FALSE;
911 PKIX_ENTER(CERTPOLICYNODE, "pkix_SinglePolicyNode_Equals");
912 PKIX_NULLCHECK_THREE(firstPN, secondPN, pResult);
914 /* If both references are identical, they must be equal */
915 if (firstPN == secondPN) {
916 compResult = PKIX_TRUE;
917 goto cleanup;
921 * It seems we have to do the comparisons. Do
922 * the easiest ones first.
924 if ((firstPN->criticality) != (secondPN->criticality)) {
925 goto cleanup;
927 if ((firstPN->depth) != (secondPN->depth)) {
928 goto cleanup;
931 PKIX_EQUALS
932 (firstPN->qualifierSet,
933 secondPN->qualifierSet,
934 &compResult,
935 plContext,
936 PKIX_OBJECTEQUALSFAILED);
938 if (compResult == PKIX_FALSE) {
939 goto cleanup;
942 /* These fields must be non-NULL */
943 PKIX_NULLCHECK_TWO(firstPN->validPolicy, secondPN->validPolicy);
945 PKIX_EQUALS
946 (firstPN->validPolicy,
947 secondPN->validPolicy,
948 &compResult,
949 plContext,
950 PKIX_OBJECTEQUALSFAILED);
952 if (compResult == PKIX_FALSE) {
953 goto cleanup;
956 /* These fields must be non-NULL */
957 PKIX_NULLCHECK_TWO
958 (firstPN->expectedPolicySet, secondPN->expectedPolicySet);
960 PKIX_EQUALS
961 (firstPN->expectedPolicySet,
962 secondPN->expectedPolicySet,
963 &compResult,
964 plContext,
965 PKIX_OBJECTEQUALSFAILEDONEXPECTEDPOLICYSETS);
967 cleanup:
969 *pResult = compResult;
971 PKIX_RETURN(CERTPOLICYNODE);
975 * FUNCTION: pkix_PolicyNode_Equals
976 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
978 static PKIX_Error *
979 pkix_PolicyNode_Equals(
980 PKIX_PL_Object *firstObject,
981 PKIX_PL_Object *secondObject,
982 PKIX_Boolean *pResult,
983 void *plContext)
985 PKIX_PolicyNode *firstPN = NULL;
986 PKIX_PolicyNode *secondPN = NULL;
987 PKIX_UInt32 secondType;
988 PKIX_Boolean compResult = PKIX_FALSE;
990 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Equals");
991 PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
993 /* test that firstObject is a PolicyNode */
994 PKIX_CHECK(pkix_CheckType
995 (firstObject, PKIX_CERTPOLICYNODE_TYPE, plContext),
996 PKIX_FIRSTOBJECTNOTPOLICYNODE);
999 * Since we know firstObject is a PolicyNode,
1000 * if both references are identical, they must be equal
1002 if (firstObject == secondObject){
1003 compResult = PKIX_TRUE;
1004 goto cleanup;
1008 * If secondObject isn't a PolicyNode, we
1009 * don't throw an error. We simply return FALSE.
1011 PKIX_CHECK(PKIX_PL_Object_GetType
1012 (secondObject, &secondType, plContext),
1013 PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
1015 if (secondType != PKIX_CERTPOLICYNODE_TYPE) {
1016 goto cleanup;
1020 * Oh, well, we have to do the comparisons. Do
1021 * the easiest ones first.
1023 firstPN = (PKIX_PolicyNode *)firstObject;
1024 secondPN = (PKIX_PolicyNode *)secondObject;
1027 * We don't require the parents to be identical. In the
1028 * course of traversing the tree, we will have checked the
1029 * attributes of the parent nodes, and checking the lists
1030 * of children will determine whether they match.
1033 PKIX_EQUALS
1034 (firstPN->children,
1035 secondPN->children,
1036 &compResult,
1037 plContext,
1038 PKIX_OBJECTEQUALSFAILEDONCHILDREN);
1040 if (compResult == PKIX_FALSE) {
1041 goto cleanup;
1044 PKIX_CHECK(pkix_SinglePolicyNode_Equals
1045 (firstPN, secondPN, &compResult, plContext),
1046 PKIX_SINGLEPOLICYNODEEQUALSFAILED);
1048 cleanup:
1050 *pResult = compResult;
1052 PKIX_RETURN(CERTPOLICYNODE);
1056 * FUNCTION: pkix_PolicyNode_DuplicateHelper
1057 * DESCRIPTION:
1059 * Duplicates the PolicyNode whose address is pointed to by "original",
1060 * and stores the result at "pNewNode", if a non-NULL pointer is provided
1061 * for "pNewNode". In addition, the created PolicyNode is added as a child
1062 * to "parent", if a non-NULL pointer is provided for "parent". Then this
1063 * function is called recursively to duplicate each of the children of
1064 * "original". At the top level this function is called with a null
1065 * "parent" and a non-NULL "pNewNode". Below the top level "parent" will
1066 * be non-NULL and "pNewNode" will be NULL.
1068 * PARAMETERS:
1069 * "original"
1070 * Address of PolicyNode to be copied; must be non-NULL
1071 * "parent"
1072 * Address of PolicyNode to which the created node is to be added as a
1073 * child; NULL for the top-level call and non-NULL below the top level
1074 * "pNewNode"
1075 * Address to store the node created; should be NULL if "parent" is
1076 * non-NULL and vice versa
1077 * "plContext"
1078 * Platform-specific context pointer.
1079 * THREAD SAFETY:
1080 * Conditionally Thread Safe
1081 * (see Thread Safety Definitions in Programmer's Guide)
1082 * RETURNS:
1083 * Returns NULL if function succeeds
1084 * Returns a PolicyNode Error if the function fails in a non-fatal way.
1085 * Returns a Fatal Error if the function fails in a fatal way
1087 static PKIX_Error *
1088 pkix_PolicyNode_DuplicateHelper(
1089 PKIX_PolicyNode *original,
1090 PKIX_PolicyNode *parent,
1091 PKIX_PolicyNode **pNewNode,
1092 void *plContext)
1094 PKIX_UInt32 numChildren = 0;
1095 PKIX_UInt32 childIndex = 0;
1096 PKIX_List *children = NULL; /* List of PKIX_PolicyNode */
1097 PKIX_PolicyNode *copy = NULL;
1098 PKIX_PolicyNode *child = NULL;
1100 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_DuplicateHelper");
1102 PKIX_NULLCHECK_THREE
1103 (original, original->validPolicy, original->expectedPolicySet);
1106 * These components are immutable, so copying the pointers
1107 * is sufficient. The create function increments the reference
1108 * counts as it stores the pointers into the new object.
1110 PKIX_CHECK(pkix_PolicyNode_Create
1111 (original->validPolicy,
1112 original->qualifierSet,
1113 original->criticality,
1114 original->expectedPolicySet,
1115 &copy,
1116 plContext),
1117 PKIX_POLICYNODECREATEFAILED);
1119 if (parent) {
1120 PKIX_CHECK(pkix_PolicyNode_AddToParent(parent, copy, plContext),
1121 PKIX_POLICYNODEADDTOPARENTFAILED);
1124 /* Are there any children to duplicate? */
1125 children = original->children;
1127 if (children) {
1128 PKIX_CHECK(PKIX_List_GetLength(children, &numChildren, plContext),
1129 PKIX_LISTGETLENGTHFAILED);
1132 for (childIndex = 0; childIndex < numChildren; childIndex++) {
1133 PKIX_CHECK(PKIX_List_GetItem
1134 (children,
1135 childIndex,
1136 (PKIX_PL_Object **)&child,
1137 plContext),
1138 PKIX_LISTGETITEMFAILED);
1140 PKIX_CHECK(pkix_PolicyNode_DuplicateHelper
1141 (child, copy, NULL, plContext),
1142 PKIX_POLICYNODEDUPLICATEHELPERFAILED);
1144 PKIX_DECREF(child);
1147 if (pNewNode) {
1148 *pNewNode = copy;
1149 copy = NULL; /* no DecRef if we give our handle away */
1152 cleanup:
1153 PKIX_DECREF(copy);
1154 PKIX_DECREF(child);
1156 PKIX_RETURN(CERTPOLICYNODE);
1160 * FUNCTION: pkix_PolicyNode_Duplicate
1161 * (see comments for PKIX_PL_Duplicate_Callback in pkix_pl_system.h)
1163 static PKIX_Error *
1164 pkix_PolicyNode_Duplicate(
1165 PKIX_PL_Object *object,
1166 PKIX_PL_Object **pNewObject,
1167 void *plContext)
1169 PKIX_PolicyNode *original = NULL;
1170 PKIX_PolicyNode *copy = NULL;
1172 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Duplicate");
1174 PKIX_NULLCHECK_TWO(object, pNewObject);
1176 PKIX_CHECK(pkix_CheckType
1177 (object, PKIX_CERTPOLICYNODE_TYPE, plContext),
1178 PKIX_OBJECTNOTPOLICYNODE);
1180 original = (PKIX_PolicyNode *)object;
1182 PKIX_CHECK(pkix_PolicyNode_DuplicateHelper
1183 (original, NULL, &copy, plContext),
1184 PKIX_POLICYNODEDUPLICATEHELPERFAILED);
1186 *pNewObject = (PKIX_PL_Object *)copy;
1188 cleanup:
1190 PKIX_RETURN(CERTPOLICYNODE);
1194 * FUNCTION: pkix_PolicyNode_RegisterSelf
1195 * DESCRIPTION:
1197 * Registers PKIX_CERTPOLICYNODE_TYPE and its related
1198 * functions with systemClasses[]
1200 * THREAD SAFETY:
1201 * Not Thread Safe - for performance and complexity reasons
1203 * Since this function is only called by PKIX_PL_Initialize,
1204 * which should only be called once, it is acceptable that
1205 * this function is not thread-safe.
1207 PKIX_Error *
1208 pkix_PolicyNode_RegisterSelf(void *plContext)
1211 extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
1212 pkix_ClassTable_Entry entry;
1214 PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_RegisterSelf");
1216 entry.description = "PolicyNode";
1217 entry.destructor = pkix_PolicyNode_Destroy;
1218 entry.equalsFunction = pkix_PolicyNode_Equals;
1219 entry.hashcodeFunction = pkix_PolicyNode_Hashcode;
1220 entry.toStringFunction = pkix_PolicyNode_ToString;
1221 entry.comparator = NULL;
1222 entry.duplicateFunction = pkix_PolicyNode_Duplicate;
1224 systemClasses[PKIX_CERTPOLICYNODE_TYPE] = entry;
1226 PKIX_RETURN(CERTPOLICYNODE);
1230 /* --Public-PolicyNode-Functions----------------------------------- */
1233 * FUNCTION: PKIX_PolicyNode_GetChildren
1234 * (see description of this function in pkix_results.h)
1236 PKIX_Error *
1237 PKIX_PolicyNode_GetChildren(
1238 PKIX_PolicyNode *node,
1239 PKIX_List **pChildren, /* list of PKIX_PolicyNode */
1240 void *plContext)
1242 PKIX_List *children = NULL;
1244 PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetChildren");
1246 PKIX_NULLCHECK_TWO(node, pChildren);
1248 PKIX_INCREF(node->children);
1249 children = node->children;
1251 if (!children) {
1252 PKIX_CHECK(PKIX_List_Create(&children, plContext),
1253 PKIX_LISTCREATEFAILED);
1256 PKIX_CHECK(PKIX_List_SetImmutable(children, plContext),
1257 PKIX_LISTSETIMMUTABLEFAILED);
1259 *pChildren = children;
1261 cleanup:
1262 if (PKIX_ERROR_RECEIVED) {
1263 PKIX_DECREF(children);
1266 PKIX_RETURN(CERTPOLICYNODE);
1270 * FUNCTION: PKIX_PolicyNode_GetParent
1271 * (see description of this function in pkix_results.h)
1273 PKIX_Error *
1274 PKIX_PolicyNode_GetParent(
1275 PKIX_PolicyNode *node,
1276 PKIX_PolicyNode **pParent,
1277 void *plContext)
1280 PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetParent");
1282 PKIX_NULLCHECK_TWO(node, pParent);
1284 PKIX_INCREF(node->parent);
1285 *pParent = node->parent;
1287 PKIX_RETURN(CERTPOLICYNODE);
1291 * FUNCTION: PKIX_PolicyNode_GetValidPolicy
1292 * (see description of this function in pkix_results.h)
1294 PKIX_Error *
1295 PKIX_PolicyNode_GetValidPolicy(
1296 PKIX_PolicyNode *node,
1297 PKIX_PL_OID **pValidPolicy,
1298 void *plContext)
1301 PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetValidPolicy");
1303 PKIX_NULLCHECK_TWO(node, pValidPolicy);
1305 PKIX_INCREF(node->validPolicy);
1306 *pValidPolicy = node->validPolicy;
1308 PKIX_RETURN(CERTPOLICYNODE);
1312 * FUNCTION: PKIX_PolicyNode_GetPolicyQualifiers
1313 * (see description of this function in pkix_results.h)
1315 PKIX_Error *
1316 PKIX_PolicyNode_GetPolicyQualifiers(
1317 PKIX_PolicyNode *node,
1318 PKIX_List **pQualifiers, /* list of PKIX_PL_CertPolicyQualifier */
1319 void *plContext)
1321 PKIX_List *qualifiers = NULL;
1323 PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetPolicyQualifiers");
1325 PKIX_NULLCHECK_TWO(node, pQualifiers);
1327 PKIX_INCREF(node->qualifierSet);
1328 qualifiers = node->qualifierSet;
1330 if (!qualifiers) {
1331 PKIX_CHECK(PKIX_List_Create(&qualifiers, plContext),
1332 PKIX_LISTCREATEFAILED);
1335 PKIX_CHECK(PKIX_List_SetImmutable(qualifiers, plContext),
1336 PKIX_LISTSETIMMUTABLEFAILED);
1338 *pQualifiers = qualifiers;
1340 cleanup:
1342 PKIX_RETURN(CERTPOLICYNODE);
1346 * FUNCTION: PKIX_PolicyNode_GetExpectedPolicies
1347 * (see description of this function in pkix_results.h)
1349 PKIX_Error *
1350 PKIX_PolicyNode_GetExpectedPolicies(
1351 PKIX_PolicyNode *node,
1352 PKIX_List **pExpPolicies, /* list of PKIX_PL_OID */
1353 void *plContext)
1356 PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetExpectedPolicies");
1358 PKIX_NULLCHECK_TWO(node, pExpPolicies);
1360 PKIX_INCREF(node->expectedPolicySet);
1361 *pExpPolicies = node->expectedPolicySet;
1363 PKIX_RETURN(CERTPOLICYNODE);
1367 * FUNCTION: PKIX_PolicyNode_IsCritical
1368 * (see description of this function in pkix_results.h)
1370 PKIX_Error *
1371 PKIX_PolicyNode_IsCritical(
1372 PKIX_PolicyNode *node,
1373 PKIX_Boolean *pCritical,
1374 void *plContext)
1377 PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_IsCritical");
1379 PKIX_NULLCHECK_TWO(node, pCritical);
1381 *pCritical = node->criticality;
1383 PKIX_RETURN(CERTPOLICYNODE);
1387 * FUNCTION: PKIX_PolicyNode_GetDepth
1388 * (see description of this function in pkix_results.h)
1390 PKIX_Error *
1391 PKIX_PolicyNode_GetDepth(
1392 PKIX_PolicyNode *node,
1393 PKIX_UInt32 *pDepth,
1394 void *plContext)
1397 PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetDepth");
1399 PKIX_NULLCHECK_TWO(node, pDepth);
1401 *pDepth = node->depth;
1403 PKIX_RETURN(CERTPOLICYNODE);