cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
int_attr.c
Go to the documentation of this file.
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 */
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 
43 void *attributeFindStart( IN_OPT const void *attributePtr,
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 
84 void *attributeFindEnd( IN_OPT const void *attributePtr,
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 
128 void *attributeFind( IN_OPT const void *attributePtr,
129  IN GETATTRFUNCTION getAttrFunction,
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 
170 void *attributeFindEx( IN_OPT const void *attributePtr,
171  IN GETATTRFUNCTION 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 
271 void *attributeFindNextInstance( IN_OPT const void *attributePtr,
272  IN GETATTRFUNCTION getAttrFunction )
273  {
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 
335 static const void *moveCursorByGroup( const void *currentCursor,
336  IN GETATTRFUNCTION 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 
416 static const void *moveCursorByAttribute( const void *currentCursor,
417  GETATTRFUNCTION 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 
488 static const void *moveCursorByInstance( const void *currentCursor,
489  GETATTRFUNCTION 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 
569 const void *attributeMoveCursor( IN_OPT const void *currentCursor,
570  IN GETATTRFUNCTION getAttrFunction,
571  IN_ATTRIBUTE \
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[] = {
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  {
629  return( moveCursorByGroup( currentCursor, getAttrFunction,
630  moveType, count, absMove ) );
631 
633  return( moveCursorByAttribute( currentCursor, getAttrFunction,
634  moveType, count, absMove ) );
635 
637  return( moveCursorByInstance( currentCursor, getAttrFunction,
638  moveType, count, absMove ) );
639  }
640 
641  /* Everything else is an error */
643  }