1 /****************************************************************************
2 * *
3 * cryptlib Internal Attribute-list Manipulation API *
4 * Copyright Peter Gutmann 1992-2008 *
5 * *
6 ****************************************************************************/
7
8 #if defined( INC_ALL )
9 #include "crypt.h"
10 #else
11 #include "crypt.h"
12 #endif /* Compiler-specific includes */
13
14 /* The minimum size of an attribute-list element (in this case for
15 sessions), used for error checking in debug mode. The values are various
16 ints and pointers, and the 'previous' and 'next' pointer for the list
17 itself */
18
19 #define MIN_ATTRLIST_SIZE ( ( 7 * sizeof( int ) ) + \
20 ( 2 * sizeof( void * ) ) )
21
22 /* Movement codes for the attribute cursor */
23
24 typedef enum {
25 CURSOR_MOVE_NONE, /* No movement type */
26 CURSOR_MOVE_START, /* Move to first attribute */
27 CURSOR_MOVE_PREV, /* Move to previous attribute */
28 CURSOR_MOVE_NEXT, /* Move to next attribute */
29 CURSOR_MOVE_END, /* Move to last attribute */
30 CURSOR_MOVE_LAST /* Last possible move type */
31 } CURSOR_MOVE_TYPE;
32
33 /****************************************************************************
34 * *
35 * Attribute Location Routines *
36 * *
37 ****************************************************************************/
38
39 /* Find the start and end of an attribute group from an attribute within
40 the group */
41
42 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
attributeFindStart(IN_OPT const void * attributePtr,IN GETATTR_FUNCTION getAttrFunction)43 void *attributeFindStart( IN_OPT const void *attributePtr,
44 IN GETATTR_FUNCTION getAttrFunction )
45 {
46 CRYPT_ATTRIBUTE_TYPE groupID;
47 int iterationCount;
48
49 assert( attributePtr == NULL || \
50 isReadPtr( attributePtr, MIN_ATTRLIST_SIZE ) );
51
52 REQUIRES_N( getAttrFunction != NULL );
53
54 if( attributePtr == NULL )
55 return( NULL );
56
57 /* Move backwards until we find the start of the attribute */
58 if( getAttrFunction( attributePtr, &groupID, NULL, NULL,
59 ATTR_CURRENT ) == NULL )
60 return( NULL );
61 ENSURES_N( groupID != CRYPT_ATTRIBUTE_NONE );
62 for( iterationCount = 0; iterationCount < FAILSAFE_ITERATIONS_MAX;
63 iterationCount++ )
64 {
65 CRYPT_ATTRIBUTE_TYPE prevGroupID;
66 const void *prevPtr;
67
68 prevPtr = getAttrFunction( attributePtr, &prevGroupID, NULL, NULL,
69 ATTR_PREV );
70 if( prevPtr == NULL || prevGroupID != groupID )
71 {
72 /* We've reached the start of the list or a different attribute
73 group, this is the start of the current group */
74 break;
75 }
76 attributePtr = prevPtr;
77 }
78 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
79
80 return( ( void * ) attributePtr );
81 }
82
83 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
attributeFindEnd(IN_OPT const void * attributePtr,IN GETATTR_FUNCTION getAttrFunction)84 void *attributeFindEnd( IN_OPT const void *attributePtr,
85 IN GETATTR_FUNCTION getAttrFunction )
86 {
87 CRYPT_ATTRIBUTE_TYPE groupID;
88 int iterationCount;
89
90 assert( attributePtr == NULL || \
91 isReadPtr( attributePtr, MIN_ATTRLIST_SIZE ) );
92
93 REQUIRES_N( getAttrFunction != NULL );
94
95 if( attributePtr == NULL )
96 return( NULL );
97
98 /* Move forwards until we're just before the start of the next
99 attribute */
100 if( getAttrFunction( attributePtr, &groupID, NULL, NULL,
101 ATTR_CURRENT ) == NULL )
102 return( NULL );
103 ENSURES_N( groupID != CRYPT_ATTRIBUTE_NONE );
104 for( iterationCount = 0; iterationCount < FAILSAFE_ITERATIONS_MAX;
105 iterationCount++ )
106 {
107 CRYPT_ATTRIBUTE_TYPE nextGroupID;
108 const void *nextPtr;
109
110 nextPtr = getAttrFunction( attributePtr, &nextGroupID, NULL, NULL,
111 ATTR_NEXT );
112 if( nextPtr == NULL || nextGroupID != groupID )
113 {
114 /* We've reached the end of the list or a different attribute
115 group, this is the end of the current group */
116 break;
117 }
118 attributePtr = nextPtr;
119 }
120 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
121
122 return( ( void * ) attributePtr );
123 }
124
125 /* Find an attribute in a list of attributes */
126
127 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
attributeFind(IN_OPT const void * attributePtr,IN GETATTR_FUNCTION getAttrFunction,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID)128 void *attributeFind( IN_OPT const void *attributePtr,
129 IN GETATTR_FUNCTION getAttrFunction,
130 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID )
131 {
132 CRYPT_ATTRIBUTE_TYPE currAttributeID;
133 int iterationCount;
134
135 assert( attributePtr == NULL || \
136 isReadPtr( attributePtr, MIN_ATTRLIST_SIZE ) );
137
138 REQUIRES_N( getAttrFunction != NULL );
139 REQUIRES_N( isAttribute( attributeID ) || \
140 isInternalAttribute( attributeID ) );
141
142 if( attributePtr == NULL )
143 return( NULL );
144
145 /* Find the attribute in the list */
146 if( getAttrFunction( attributePtr, NULL, &currAttributeID, NULL,
147 ATTR_CURRENT ) == NULL )
148 return( NULL );
149 ENSURES_N( currAttributeID != CRYPT_ATTRIBUTE_NONE );
150 for( iterationCount = 0;
151 attributePtr != NULL && currAttributeID != attributeID && \
152 iterationCount < FAILSAFE_ITERATIONS_MAX;
153 iterationCount++ )
154 {
155 attributePtr = getAttrFunction( attributePtr, NULL,
156 &currAttributeID, NULL,
157 ATTR_NEXT );
158 }
159 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
160
161 return( ( void * ) attributePtr );
162 }
163
164 /* An extended form of the standard find-attribute function that searches
165 either by attribute group or by attribute + attribute-instance (the
166 case of search-by-attribute is handled through findAttribute(), and the
167 other combinations aren't valid) */
168
169 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
attributeFindEx(IN_OPT const void * attributePtr,IN GETATTR_FUNCTION getAttrFunction,IN_ENUM_OPT (CRYPT_ATTRIBUTE)const CRYPT_ATTRIBUTE_TYPE groupID,IN_ENUM_OPT (CRYPT_ATTRIBUTE)const CRYPT_ATTRIBUTE_TYPE attributeID,IN_ENUM_OPT (CRYPT_ATTRIBUTE)const CRYPT_ATTRIBUTE_TYPE instanceID)170 void *attributeFindEx( IN_OPT const void *attributePtr,
171 IN GETATTR_FUNCTION getAttrFunction,
172 IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
173 const CRYPT_ATTRIBUTE_TYPE groupID,
174 IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
175 const CRYPT_ATTRIBUTE_TYPE attributeID,
176 IN_ENUM_OPT( CRYPT_ATTRIBUTE ) \
177 const CRYPT_ATTRIBUTE_TYPE instanceID )
178 {
179 CRYPT_ATTRIBUTE_TYPE currAttributeID, currInstanceID;
180 int iterationCount;
181
182 assert( attributePtr == NULL || \
183 isReadPtr( attributePtr, MIN_ATTRLIST_SIZE ) );
184
185 REQUIRES_N( getAttrFunction != NULL );
186 REQUIRES_N( groupID == CRYPT_ATTRIBUTE_NONE || \
187 isAttribute( groupID ) || \
188 isInternalAttribute( groupID ) );
189 REQUIRES_N( attributeID == CRYPT_ATTRIBUTE_NONE || \
190 isAttribute( attributeID ) || \
191 isInternalAttribute( attributeID ) );
192 REQUIRES_N( instanceID == CRYPT_ATTRIBUTE_NONE || \
193 isAttribute( instanceID ) || \
194 isInternalAttribute( instanceID ) );
195 REQUIRES_N( ( groupID != CRYPT_ATTRIBUTE_NONE && \
196 attributeID == CRYPT_ATTRIBUTE_NONE && \
197 instanceID == CRYPT_ATTRIBUTE_NONE ) || \
198 ( groupID == CRYPT_ATTRIBUTE_NONE && \
199 attributeID != CRYPT_ATTRIBUTE_NONE && \
200 instanceID != CRYPT_ATTRIBUTE_NONE ) );
201
202 if( attributePtr == NULL )
203 return( NULL );
204
205 /* Find the attribute group if required */
206 if( groupID != CRYPT_ATTRIBUTE_NONE )
207 {
208 CRYPT_ATTRIBUTE_TYPE currGroupID;
209
210 if( getAttrFunction( attributePtr, &currGroupID, NULL, NULL,
211 ATTR_CURRENT ) == NULL )
212 return( NULL );
213 ENSURES_N( currGroupID != CRYPT_ATTRIBUTE_NONE );
214 for( iterationCount = 0;
215 attributePtr != NULL && currGroupID != groupID && \
216 iterationCount < FAILSAFE_ITERATIONS_MAX;
217 iterationCount++ )
218 {
219 attributePtr = getAttrFunction( attributePtr, &currGroupID,
220 NULL, NULL, ATTR_NEXT );
221 }
222 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
223
224 return( ( void * ) attributePtr );
225 }
226
227 /* Find the attribute */
228 if( getAttrFunction( attributePtr, NULL, &currAttributeID, NULL,
229 ATTR_CURRENT ) == NULL )
230 return( NULL );
231 ENSURES_N( currAttributeID != CRYPT_ATTRIBUTE_NONE );
232 for( iterationCount = 0;
233 attributePtr != NULL && currAttributeID != attributeID && \
234 iterationCount < FAILSAFE_ITERATIONS_MAX;
235 iterationCount++ )
236 {
237 attributePtr = getAttrFunction( attributePtr, NULL,
238 &currAttributeID, NULL,
239 ATTR_NEXT );
240 }
241 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
242 if( attributePtr == NULL )
243 return( NULL );
244
245 /* Find the attribute instance */
246 if( getAttrFunction( attributePtr, NULL, &currAttributeID,
247 &currInstanceID, ATTR_CURRENT ) == NULL )
248 return( NULL );
249 ENSURES_N( currAttributeID != CRYPT_ATTRIBUTE_NONE );
250 for( iterationCount = 0;
251 attributePtr != NULL && currAttributeID == attributeID && \
252 iterationCount < FAILSAFE_ITERATIONS_MAX;
253 iterationCount++ )
254 {
255 if( currInstanceID == instanceID )
256 return( ( void * ) attributePtr );
257 attributePtr = getAttrFunction( attributePtr, NULL,
258 &currAttributeID, &currInstanceID,
259 ATTR_NEXT );
260 }
261 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
262
263 return( NULL );
264 }
265
266 /* Find the next instance of an attribute in an attribute group. This is
267 used to step through multiple instances of an attribute, for example in
268 a cert extension containing a SEQUENCE OF <attribute> */
269
270 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
attributeFindNextInstance(IN_OPT const void * attributePtr,IN GETATTR_FUNCTION getAttrFunction)271 void *attributeFindNextInstance( IN_OPT const void *attributePtr,
272 IN GETATTR_FUNCTION getAttrFunction )
273 {
274 CRYPT_ATTRIBUTE_TYPE groupID, attributeID;
275 CRYPT_ATTRIBUTE_TYPE currGroupID, currAttributeID;
276 int iterationCount;
277
278 assert( attributePtr == NULL || \
279 isReadPtr( attributePtr, MIN_ATTRLIST_SIZE ) );
280
281 REQUIRES_N( getAttrFunction != NULL );
282
283 if( attributePtr == NULL )
284 return( NULL );
285
286 /* Skip the current field */
287 if( getAttrFunction( attributePtr, &groupID, &attributeID, NULL,
288 ATTR_CURRENT ) == NULL )
289 return( NULL );
290 ENSURES_N( groupID != CRYPT_ATTRIBUTE_NONE && \
291 attributeID != CRYPT_ATTRIBUTE_NONE );
292 attributePtr = getAttrFunction( attributePtr, &currGroupID,
293 &currAttributeID, NULL, ATTR_NEXT );
294 if( attributePtr == NULL )
295 {
296 /* No next attribute, we're done */
297 return( NULL );
298 }
299 ENSURES_N( currGroupID != CRYPT_ATTRIBUTE_NONE );
300
301 /* Step through the remaining attributes in the group looking for
302 another occurrence of the current attribute */
303 for( iterationCount = 0; \
304 attributePtr != NULL && currGroupID == groupID && \
305 iterationCount < FAILSAFE_ITERATIONS_MAX;
306 iterationCount++ )
307 {
308 if( currAttributeID == attributeID )
309 return( ( void * ) attributePtr );
310 attributePtr = getAttrFunction( attributePtr, &currGroupID,
311 &currAttributeID, NULL,
312 ATTR_NEXT );
313 }
314 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
315
316 /* We couldn't find another instance of the attribute in this group */
317 return( NULL );
318 }
319
320 /****************************************************************************
321 * *
322 * Attribute Cursor Movement Routines *
323 * *
324 ****************************************************************************/
325
326 /* Moving the cursor by attribute group is a bit more complex than just
327 stepping forwards or backwards along the attribute list. First we have
328 to find the start or end of the current group. Then we move to the start
329 of the previous (via ATTR_PREV and attributeFindStart()), or start of the
330 next (via ATTR_NEXT) group beyond that. This has the effect of moving us
331 from anywhere in the current group to the start of the preceding or
332 following group. Finally, we repeat this as required */
333
334 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 2 ) ) \
moveCursorByGroup(const void * currentCursor,IN GETATTR_FUNCTION getAttrFunction,IN_ENUM (CURSOR_MOVE)const CURSOR_MOVE_TYPE cursorMoveType,IN_INT int count,const BOOLEAN absMove)335 static const void *moveCursorByGroup( const void *currentCursor,
336 IN GETATTR_FUNCTION getAttrFunction,
337 IN_ENUM( CURSOR_MOVE ) \
338 const CURSOR_MOVE_TYPE cursorMoveType,
339 IN_INT int count,
340 const BOOLEAN absMove )
341 {
342 const void *newCursor = currentCursor, *lastCursor = NULL;
343 int iterationCount;
344
345 assert( isReadPtr( currentCursor, MIN_ATTRLIST_SIZE ) );
346
347 REQUIRES_N( getAttrFunction != NULL );
348 REQUIRES_N( cursorMoveType > CURSOR_MOVE_NONE && \
349 cursorMoveType < CURSOR_MOVE_LAST );
350 REQUIRES_N( count > 0 && count <= MAX_INTLENGTH );
351
352 for( iterationCount = 0; \
353 count-- > 0 && newCursor != NULL && \
354 iterationCount < FAILSAFE_ITERATIONS_MAX;
355 iterationCount++ )
356 {
357 lastCursor = newCursor;
358 if( cursorMoveType == CURSOR_MOVE_START || \
359 cursorMoveType == CURSOR_MOVE_PREV )
360 {
361 /* Move from the start of the current group to the start of the
362 preceding group */
363 newCursor = attributeFindStart( newCursor, getAttrFunction );
364 if( newCursor != NULL )
365 newCursor = getAttrFunction( newCursor, NULL, NULL, NULL,
366 ATTR_PREV );
367 if( newCursor != NULL )
368 newCursor = attributeFindStart( newCursor, getAttrFunction );
369 }
370 else
371 {
372 REQUIRES_N( cursorMoveType == CURSOR_MOVE_NEXT || \
373 cursorMoveType == CURSOR_MOVE_END );
374
375 /* Move from the end of the current group to the start of the
376 next group */
377 newCursor = attributeFindEnd( newCursor, getAttrFunction );
378 if( newCursor != NULL )
379 newCursor = getAttrFunction( newCursor, NULL, NULL, NULL,
380 ATTR_NEXT );
381 }
382 }
383 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
384 ENSURES_N( lastCursor != NULL ); /* We went through the loop at least once */
385
386 /* If the new cursor is NULL, we've reached the start or end of the
387 attribute list */
388 if( newCursor == NULL )
389 {
390 /* If it's an absolute move we've reached our destination, otherwise
391 there's nowhere left to move to. We move to the start of the
392 first or last attribute that we got to before we ran out of
393 attributes to make sure that we don't fall off the start/end of
394 the list */
395 return( absMove ? \
396 attributeFindStart( lastCursor, getAttrFunction ) : NULL );
397 }
398
399 /* We've found what we were looking for */
400 return( newCursor );
401 }
402
403 /* Moving by attribute or attribute instance is rather simpler than moving by
404 group. For attributes we move backwards or forwards until we either run
405 out of attributes or the next attribute belongs to a different group. For
406 attribute instances we move similarly, except that we stop when we reach
407 an attribute whose group type, attribute type, and instance type don't
408 match the current one. We have to explicitly keep track of whether the
409 cursor was successfully moved rather than checking that its value has
410 changed because some object types implement composite attributes that
411 maintain an attribute-internal virtual cursor, which can return the same
412 attribute pointer multiple times if the move is internal to the
413 (composite) attribute */
414
415 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 2 ) ) \
moveCursorByAttribute(const void * currentCursor,GETATTR_FUNCTION getAttrFunction,IN_ENUM (CURSOR_MOVE)const CURSOR_MOVE_TYPE cursorMoveType,IN_INT int count,const BOOLEAN absMove)416 static const void *moveCursorByAttribute( const void *currentCursor,
417 GETATTR_FUNCTION getAttrFunction,
418 IN_ENUM( CURSOR_MOVE ) \
419 const CURSOR_MOVE_TYPE cursorMoveType,
420 IN_INT int count,
421 const BOOLEAN absMove )
422 {
423 CRYPT_ATTRIBUTE_TYPE groupID;
424 BOOLEAN cursorMoved = FALSE;
425 const void *newCursor = currentCursor;
426 int iterationCount;
427
428 assert( isReadPtr( currentCursor, MIN_ATTRLIST_SIZE ) );
429
430 REQUIRES_N( getAttrFunction != NULL );
431 REQUIRES_N( cursorMoveType > CURSOR_MOVE_NONE && \
432 cursorMoveType < CURSOR_MOVE_LAST );
433 REQUIRES_N( count > 0 && count <= MAX_INTLENGTH );
434
435 if( getAttrFunction( currentCursor, &groupID, NULL, NULL,
436 ATTR_CURRENT ) == NULL )
437 return( NULL );
438 ENSURES_N( groupID != CRYPT_ATTRIBUTE_NONE );
439 if( cursorMoveType == CURSOR_MOVE_START || \
440 cursorMoveType == CURSOR_MOVE_PREV )
441 {
442 CRYPT_ATTRIBUTE_TYPE prevGroupID;
443 const void *prevCursor;
444
445 prevCursor = getAttrFunction( newCursor, &prevGroupID, NULL,
446 NULL, ATTR_PREV );
447 for( iterationCount = 0; \
448 count-- > 0 && prevCursor != NULL && prevGroupID == groupID && \
449 iterationCount < FAILSAFE_ITERATIONS_MAX;
450 iterationCount++ )
451 {
452 newCursor = prevCursor;
453 prevCursor = getAttrFunction( newCursor, &prevGroupID, NULL,
454 NULL, ATTR_PREV );
455 cursorMoved = TRUE;
456 }
457 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
458 }
459 else
460 {
461 CRYPT_ATTRIBUTE_TYPE nextGroupID;
462 const void *nextCursor;
463
464 REQUIRES_N( cursorMoveType == CURSOR_MOVE_NEXT || \
465 cursorMoveType == CURSOR_MOVE_END );
466
467 nextCursor = getAttrFunction( newCursor, &nextGroupID, NULL,
468 NULL, ATTR_NEXT );
469 for( iterationCount = 0; \
470 count-- > 0 && nextCursor != NULL && nextGroupID == groupID && \
471 iterationCount < FAILSAFE_ITERATIONS_MAX;
472 iterationCount++ )
473 {
474 newCursor = nextCursor;
475 nextCursor = getAttrFunction( newCursor, &nextGroupID, NULL,
476 NULL, ATTR_NEXT );
477 cursorMoved = TRUE;
478 }
479 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
480 }
481
482 if( !absMove && !cursorMoved )
483 return( NULL );
484 return( newCursor );
485 }
486
487 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 2 ) ) \
moveCursorByInstance(const void * currentCursor,GETATTR_FUNCTION getAttrFunction,IN_ENUM (CURSOR_MOVE)const CURSOR_MOVE_TYPE cursorMoveType,IN_INT int count,const BOOLEAN absMove)488 static const void *moveCursorByInstance( const void *currentCursor,
489 GETATTR_FUNCTION getAttrFunction,
490 IN_ENUM( CURSOR_MOVE ) \
491 const CURSOR_MOVE_TYPE cursorMoveType,
492 IN_INT int count,
493 const BOOLEAN absMove )
494 {
495 CRYPT_ATTRIBUTE_TYPE groupID, attributeID, instanceID;
496 BOOLEAN cursorMoved = FALSE;
497 const void *newCursor = currentCursor;
498 int iterationCount;
499
500 assert( isReadPtr( currentCursor, MIN_ATTRLIST_SIZE ) );
501
502 REQUIRES_N( getAttrFunction != NULL );
503 REQUIRES_N( cursorMoveType > CURSOR_MOVE_NONE && \
504 cursorMoveType < CURSOR_MOVE_LAST );
505 REQUIRES_N( count > 0 && count <= MAX_INTLENGTH );
506
507 if( getAttrFunction( currentCursor, &groupID, &attributeID,
508 &instanceID, ATTR_CURRENT ) == NULL )
509 return( NULL );
510 ENSURES_N( groupID != CRYPT_ATTRIBUTE_NONE && \
511 attributeID != CRYPT_ATTRIBUTE_NONE );
512 if( cursorMoveType == CURSOR_MOVE_START || \
513 cursorMoveType == CURSOR_MOVE_PREV )
514 {
515 CRYPT_ATTRIBUTE_TYPE prevGroupID, prevAttrID, prevInstID;
516 const void *prevCursor;
517
518 prevCursor = getAttrFunction( newCursor, &prevGroupID,
519 &prevAttrID, &prevInstID,
520 ATTR_PREV );
521 for( iterationCount = 0; \
522 count-- > 0 && prevCursor != NULL && prevGroupID == groupID && \
523 prevAttrID == attributeID && prevInstID == instanceID && \
524 iterationCount < FAILSAFE_ITERATIONS_MAX;
525 iterationCount++ )
526 {
527 newCursor = prevCursor;
528 prevCursor = getAttrFunction( newCursor, &prevGroupID,
529 &prevAttrID, &prevInstID,
530 ATTR_PREV );
531 cursorMoved = TRUE;
532 }
533 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
534 }
535 else
536 {
537 CRYPT_ATTRIBUTE_TYPE nextGroupID, nextAttrID, nextInstID;
538 const void *nextCursor;
539
540 REQUIRES_N( cursorMoveType == CURSOR_MOVE_NEXT || \
541 cursorMoveType == CURSOR_MOVE_END );
542
543 nextCursor = getAttrFunction( newCursor, &nextGroupID,
544 &nextAttrID, &nextInstID,
545 ATTR_NEXT );
546 for( iterationCount = 0; \
547 count-- > 0 && nextCursor != NULL && nextGroupID == groupID && \
548 nextAttrID == attributeID && nextInstID == instanceID && \
549 iterationCount < FAILSAFE_ITERATIONS_MAX;
550 iterationCount++ )
551 {
552 newCursor = nextCursor;
553 nextCursor = getAttrFunction( newCursor, &nextGroupID,
554 &nextAttrID, &nextInstID,
555 ATTR_NEXT );
556 cursorMoved = TRUE;
557 }
558 ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
559 }
560
561 if( !absMove && !cursorMoved )
562 return( NULL );
563 return( newCursor );
564 }
565
566 /* Move the attribute cursor relative to the current cursor position */
567
568 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) )\
attributeMoveCursor(IN_OPT const void * currentCursor,IN GETATTR_FUNCTION getAttrFunction,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeMoveType,IN_RANGE (CRYPT_CURSOR_LAST,CRYPT_CURSOR_FIRST)const int cursorMoveType)569 const void *attributeMoveCursor( IN_OPT const void *currentCursor,
570 IN GETATTR_FUNCTION getAttrFunction,
571 IN_ATTRIBUTE \
572 const CRYPT_ATTRIBUTE_TYPE attributeMoveType,
573 IN_RANGE( CRYPT_CURSOR_LAST, \
574 CRYPT_CURSOR_FIRST ) /* Values are -ve */
575 const int cursorMoveType )
576 {
577 typedef struct {
578 const int moveCode;
579 const CURSOR_MOVE_TYPE cursorMoveType;
580 } MOVECODE_MAP_INFO;
581 static const MOVECODE_MAP_INFO moveCodeMap[] = {
582 { CRYPT_CURSOR_FIRST, CURSOR_MOVE_START },
583 { CRYPT_CURSOR_PREVIOUS, CURSOR_MOVE_PREV },
584 { CRYPT_CURSOR_NEXT, CURSOR_MOVE_NEXT },
585 { CRYPT_CURSOR_LAST, CURSOR_MOVE_END },
586 { 0, CURSOR_MOVE_NONE }, { 0, CURSOR_MOVE_NONE }
587 };
588 const BOOLEAN absMove = ( cursorMoveType == CRYPT_CURSOR_FIRST || \
589 cursorMoveType == CRYPT_CURSOR_LAST ) ? \
590 TRUE : FALSE;
591 CURSOR_MOVE_TYPE moveType;
592 int count, i;
593
594 assert( currentCursor == NULL || \
595 isReadPtr( currentCursor, MIN_ATTRLIST_SIZE ) );
596
597 REQUIRES_N( getAttrFunction != NULL );
598 REQUIRES_N( attributeMoveType == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
599 attributeMoveType == CRYPT_ATTRIBUTE_CURRENT || \
600 attributeMoveType == CRYPT_ATTRIBUTE_CURRENT_INSTANCE );
601 REQUIRES_N( cursorMoveType >= CRYPT_CURSOR_LAST && \
602 cursorMoveType <= CRYPT_CURSOR_FIRST ); /* Values are -ve */
603
604 /* Positioning in null attribute lists is always unsuccessful */
605 if( currentCursor == NULL )
606 return( NULL );
607
608 /* Convert the move type into a more logical cursor move code. We can't
609 use mapValue() for this because the move-type values overlap with the
610 end-of-table marker value expected by mapValue() */
611 for( i = 0;
612 moveCodeMap[ i ].moveCode != cursorMoveType && \
613 moveCodeMap[ i ].moveCode != 0 && \
614 i < FAILSAFE_ARRAYSIZE( moveCodeMap, MOVECODE_MAP_INFO );
615 i++ );
616 ENSURES_N( i < FAILSAFE_ARRAYSIZE( moveCodeMap, MOVECODE_MAP_INFO ) );
617 ENSURES_N( moveCodeMap[ i ].moveCode != 0 );
618 moveType = moveCodeMap[ i ].cursorMoveType;
619
620 /* Set the amount that we want to move by based on the position code.
621 This means that we can handle the movement in a simple while loop
622 instead of having to special-case it for moves by one item */
623 count = absMove ? MAX_INTLENGTH : 1;
624
625 /* Perform the appropriate attribute move type */
626 switch( attributeMoveType )
627 {
628 case CRYPT_ATTRIBUTE_CURRENT_GROUP:
629 return( moveCursorByGroup( currentCursor, getAttrFunction,
630 moveType, count, absMove ) );
631
632 case CRYPT_ATTRIBUTE_CURRENT:
633 return( moveCursorByAttribute( currentCursor, getAttrFunction,
634 moveType, count, absMove ) );
635
636 case CRYPT_ATTRIBUTE_CURRENT_INSTANCE:
637 return( moveCursorByInstance( currentCursor, getAttrFunction,
638 moveType, count, absMove ) );
639 }
640
641 /* Everything else is an error */
642 retIntError_Null();
643 }
644