cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
sess_iattr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Session-specific Attribute Support Routines *
4 * Copyright Peter Gutmann 1998-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "session.h"
11 #else
12  #include "crypt.h"
13  #include "session/session.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_SESSIONS
17 
18 /****************************************************************************
19 * *
20 * Utility Functions *
21 * *
22 ****************************************************************************/
23 
24 /* Helper function used to access internal attributes within an attribute
25  group */
26 
27 #if 0 /* Currently unused, may be enabled in 3.4 with the move to
28  composite attributes for host/client information */
29 
30 /* Reset the internal virtual cursor in a attribute-list item after we've
31  moved the attribute cursor */
32 
33 #define resetVirtualCursor( attributeListPtr ) \
34  if( attributeListPtr != NULL ) \
35  attributeListPtr->flags |= ATTR_FLAG_CURSORMOVED
36 
39  IN_ENUM( ATTR ) const ATTR_TYPE attrGetType )
40  {
41  static const CRYPT_ATTRIBUTE_TYPE attributeOrderList[] = {
42  CRYPT_SESSINFO_NAME, CRYPT_SESSINFO_PASSWORD,
43  CRYPT_SESSINFO_KEY, CRYPT_ATTRIBUTE_NONE,
44  CRYPT_ATTRIBUTE_NONE };
45  USER_INFO *userInfoPtr = attributeListPtr->value;
46  CRYPT_ATTRIBUTE_TYPE attributeID = userInfoPtr->cursorPos;
47  BOOLEAN doContinue;
48  int iterationCount = 0;
49 
50  assert( isWritePtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
51 
52  REQUIRES( attrGetType > ATTR_NONE && attrGetType < ATTR_LAST );
53 
54  /* If we've just moved the cursor onto this attribute, reset the
55  position to the first internal attribute */
56  if( attributeListPtr->flags & ATTR_FLAG_CURSORMOVED )
57  {
58  attributeID = userInfoPtr->cursorPos = \
59  CRYPT_ENVINFO_SIGNATURE_RESULT;
60  attributeListPtr->flags &= ~ATTR_FLAG_CURSORMOVED;
61  }
62 
63  /* If it's an information fetch, return the currently-selected
64  attribute */
65  if( attrGetType == ATTR_NONE )
66  return( attributeID );
67 
68  do
69  {
70  int i;
71 
72  /* Find the position of the current sub-attribute in the attribute
73  order list and use that to get its successor/predecessor sub-
74  attribute */
75  for( i = 0;
76  attributeOrderList[ i ] != attributeID && \
77  attributeOrderList[ i ] != CRYPT_ATTRIBUTE_NONE && \
78  i < FAILSAFE_ARRAYSIZE( attributeOrderList, CRYPT_ATTRIBUTE_TYPE );
79  i++ );
80  ENSURES_B( i < FAILSAFE_ARRAYSIZE( attributeOrderList, \
82  if( attributeOrderList[ i ] == CRYPT_ATTRIBUTE_NONE )
83  attributeID = CRYPT_ATTRIBUTE_NONE;
84  else
85  {
86  if( attrGetType == ATTR_PREV )
87  {
88  attributeID = ( i < 1 ) ? CRYPT_ATTRIBUTE_NONE : \
89  attributeOrderList[ i - 1 ];
90  }
91  else
92  attributeID = attributeOrderList[ i + 1 ];
93  }
94  if( attributeID == CRYPT_ATTRIBUTE_NONE )
95  {
96  /* We've reached the first/last sub-attribute within the current
97  item/group, tell the caller that there are no more sub-
98  attributes present and they have to move on to the next
99  group */
100  return( FALSE );
101  }
102 
103  /* Check whether the required sub-attribute is present. If not, we
104  continue and try the next one */
105  doContinue = FALSE;
106  switch( attributeID )
107  {
108  case CRYPT_SESSINFO_NAME:
109  break; /* Always present */
110 
112  if( userInfoPtr->passwordLen <= 0 )
113  doContinue = TRUE;
114  break;
115 
116  case CRYPT_SESSINFO_KEY:
117  if( userInfoPtr->key == CRYPT_ERROR )
118  doContinue = TRUE;
119  break;
120 
121  default:
123  }
124  }
125  while( doContinue && iterationCount++ < FAILSAFE_ITERATIONS_SMALL );
126  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_SMALL );
127  attributeListPtr->attributeCursorEntry = attributeID;
128 
129  return( TRUE );
130  }
131 #else
132  #define resetVirtualCursor( attributeListPtr )
133 #endif /* 0 */
134 
135 /* Callback function used to provide external access to attribute list-
136  internal fields */
137 
138 CHECK_RETVAL_PTR \
139 static const void *getAttrFunction( IN_OPT TYPECAST( ATTRIBUTE_LIST * ) \
140  const void *attributePtr,
142  CRYPT_ATTRIBUTE_TYPE *groupID,
144  CRYPT_ATTRIBUTE_TYPE *attributeID,
146  CRYPT_ATTRIBUTE_TYPE *instanceID,
147  IN_ENUM( ATTR ) const ATTR_TYPE attrGetType )
148  {
149  ATTRIBUTE_LIST *attributeListPtr = ( ATTRIBUTE_LIST * ) attributePtr;
150  BOOLEAN subGroupMove;
151  int value, status;
152 
153  assert( attributeListPtr == NULL || \
154  isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
155  assert( groupID == NULL || \
156  isWritePtr( groupID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
157  assert( attributeID == NULL || \
158  isWritePtr( attributeID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
159  assert( instanceID == NULL || \
160  isWritePtr( instanceID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
161 
162  REQUIRES_N( attrGetType > ATTR_NONE && attrGetType < ATTR_LAST );
163 
164  /* Clear return values */
165  if( groupID != NULL )
166  *groupID = CRYPT_ATTRIBUTE_NONE;
167  if( attributeID != NULL )
168  *attributeID = CRYPT_ATTRIBUTE_NONE;
169  if( instanceID != NULL )
170  *instanceID = CRYPT_ATTRIBUTE_NONE;
171 
172  /* Move to the next or previous attribute if required. This isn't just a
173  case of following the previous/next links because some attribute-list
174  items contain an entire attribute group so that positioning by
175  attribute merely changes the current selection within the group
176  (== attribute-list item) rather than moving to the previous/next
177  entry. Because of this we have to special-case the code for
178  composite items and allow virtual positioning within the item */
179  if( attributeListPtr == NULL )
180  return( NULL );
181  subGroupMove = ( attrGetType == ATTR_PREV || \
182  attrGetType == ATTR_NEXT ) && \
183  ( attributeListPtr->flags & ATTR_FLAG_COMPOSITE );
184  if( subGroupMove )
185  {
186  REQUIRES_N( attrGetType == ATTR_NEXT || attrGetType == ATTR_PREV );
187  REQUIRES_N( attributeListPtr->flags & ATTR_FLAG_COMPOSITE );
188  REQUIRES_N( attributeListPtr->accessFunction != NULL );
189 
190  status = attributeListPtr->accessFunction( attributeListPtr,
191  attrGetType, &value );
192  if( cryptStatusError( status ) )
193  return( NULL );
194  subGroupMove = value;
195  }
196 
197  /* If we're moving by group, move to the next/previous attribute list
198  item and reset the internal virtual cursor. Note that we always
199  advance the cursor to the next/previous attribute, it's up to the
200  calling code to manage attribute-by-attribute vs. group-by-group
201  moves */
202  if( !subGroupMove && attrGetType != ATTR_CURRENT )
203  {
204  attributeListPtr = ( attrGetType == ATTR_PREV ) ? \
205  attributeListPtr->prev : attributeListPtr->next;
206  resetVirtualCursor( attributeListPtr );
207  }
208  if( attributeListPtr == NULL )
209  return( NULL );
210 
211  /* Return ID information to the caller. We only return the group ID if
212  we've moved within the attribute group, if we've moved from one group
213  to another we leave it cleared because sessions can contain multiple
214  groups with the same ID and returning an ID identical to the one from
215  the group that we've moved out of would make it look as if we're still
216  within the same group. Note that this relies somewhat on the
217  implementation behaviour of the attribute-move functions, which first
218  get the current group using ATTR_CURRENT and then move to the next or
219  previous using ATTR_NEXT/PREV */
220  if( groupID != NULL && ( attrGetType == ATTR_CURRENT || subGroupMove ) )
221  *groupID = attributeListPtr->groupID;
222  if( attributeID != NULL )
223  {
224  if( attributeListPtr->flags & ATTR_FLAG_COMPOSITE )
225  {
226  status = attributeListPtr->accessFunction( attributeListPtr,
227  ATTR_NONE, &value );
228  if( cryptStatusError( status ) )
229  return( NULL );
230  *attributeID = value;
231  }
232  else
233  *attributeID = attributeListPtr->attributeID;
234  }
235 
236  return( attributeListPtr );
237  }
238 
239 /* Lock ephemeral attributes so that they can't be deleted any more by
240  resetEphemeralAttributes(). This just clears the ephemeral flag so that
241  they're treated as normal attributes */
242 
243 STDC_NONNULL_ARG( ( 1 ) ) \
244 void lockEphemeralAttributes( INOUT ATTRIBUTE_LIST *attributeListHead )
245  {
247  int iterationCount;
248 
249  assert( isWritePtr( attributeListHead, sizeof( ATTRIBUTE_LIST * ) ) );
250 
251  /* Clear the ATTR_FLAG_EPHEMERAL flag on all attributes */
252  for( attributeListCursor = attributeListHead, iterationCount = 0;
253  attributeListCursor != NULL && \
254  iterationCount < FAILSAFE_ITERATIONS_MAX;
255  attributeListCursor = attributeListCursor->next, iterationCount++ )
256  {
257  attributeListCursor->flags &= ~ATTR_FLAG_EPHEMERAL;
258  }
259  ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MAX );
260  }
261 
262 /* Check that a set of attributes is well-formed. We can perform most of
263  the checking as the attributes are added but some checks (for example
264  whether each username has a corresponding password) aren't possible
265  until all of the attributes are present */
266 
267 CHECK_RETVAL_ENUM( CRYPT_ATTRIBUTE ) \
268 CRYPT_ATTRIBUTE_TYPE checkMissingInfo( IN_OPT const ATTRIBUTE_LIST *attributeListHead,
269  const BOOLEAN isServer )
270  {
271  const ATTRIBUTE_LIST *attributeListPtr = attributeListHead;
272 
273  assert( attributeListHead == NULL || \
274  isReadPtr( attributeListHead, sizeof( ATTRIBUTE_LIST * ) ) );
275 
276  if( attributeListPtr == NULL )
277  return( CRYPT_ATTRIBUTE_NONE );
278 
279  /* Make sure that every username attribute is paired up with a
280  corresponding authentication attribute. This only applies to
281  servers because clients use a session-wide private key for
282  authentication, the presence of which is checked elsewhere */
283  if( isServer )
284  {
285  int iterationCount;
286 
287  for( iterationCount = 0;
288  ( attributeListPtr = \
289  attributeFind( attributeListPtr, getAttrFunction,
290  CRYPT_SESSINFO_USERNAME ) ) != NULL && \
291  iterationCount < FAILSAFE_ITERATIONS_MAX;
292  iterationCount++ )
293  {
294  /* Make sure that there's a matching authentication attribute.
295  This is currently a password but in future versions could
296  also be a public key */
297  attributeListPtr = attributeListPtr->next;
298  if( attributeListPtr == NULL || \
299  attributeListPtr->attributeID != CRYPT_SESSINFO_PASSWORD )
300  return( CRYPT_SESSINFO_PASSWORD );
301 
302  /* Move on to the next attribute */
303  attributeListPtr = attributeListPtr->next;
304  }
305  ENSURES_EXT( ( iterationCount < FAILSAFE_ITERATIONS_MAX ), \
307  }
308 
309  return( CRYPT_ATTRIBUTE_NONE );
310  }
311 
312 /****************************************************************************
313 * *
314 * Attribute Cursor Management Routines *
315 * *
316 ****************************************************************************/
317 
318 /* Get/set the attribute cursor */
319 
321 int getSessionAttributeCursor( IN_OPT ATTRIBUTE_LIST *attributeListHead,
322  IN_OPT ATTRIBUTE_LIST *attributeListCursor,
325  {
326  BOOLEAN initAttributeList = FALSE;
327 
328  assert( attributeListHead == NULL || \
329  isWritePtr( attributeListHead, sizeof( ATTRIBUTE_LIST ) ) );
330  assert( attributeListCursor == NULL || \
331  isWritePtr( attributeListCursor, sizeof( ATTRIBUTE_LIST ) ) );
332  assert( isWritePtr( valuePtr, sizeof( int ) ) );
333 
334  REQUIRES( sessionInfoType == CRYPT_ATTRIBUTE_CURRENT || \
335  sessionInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
336  ( sessionInfoType > CRYPT_SESSINFO_FIRST && \
337  sessionInfoType < CRYPT_SESSINFO_LAST ) );
338 
339  /* Clear return value */
340  *valuePtr = CRYPT_ATTRIBUTE_NONE;
341 
342  /* We're querying something that resides in the attribute list, make
343  sure that there's an attribute list present. If it's present but
344  nothing is selected, select the first entry */
345  if( attributeListCursor == NULL )
346  {
347  if( attributeListHead == NULL )
348  return( CRYPT_ERROR_NOTFOUND );
349  attributeListCursor = attributeListHead;
350  resetVirtualCursor( attributeListCursor );
351  initAttributeList = TRUE;
352  }
353 
354  /* If we're reading the group, return the group type */
355  if( sessionInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP )
356  *valuePtr = attributeListCursor->groupID;
357  else
358  {
359  /* If it's a single-attribute group, return the attribute type */
360  if( !( attributeListCursor->flags & ATTR_FLAG_COMPOSITE ) )
361  *valuePtr = attributeListCursor->groupID;
362  else
363  {
364  int value, status;
365 
366  /* It's a composite type, get the currently-selected sub-attribute */
367  status = attributeListCursor->accessFunction( attributeListCursor,
368  ATTR_NONE, &value );
369  if( cryptStatusError( status ) )
370  return( status );
371  *valuePtr = value;
372  }
373  }
374  return( initAttributeList ? OK_SPECIAL : CRYPT_OK );
375  }
376 
378 int setSessionAttributeCursor( IN_OPT const ATTRIBUTE_LIST *attributeListHead,
380  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE sessionInfoType,
382  CRYPT_CURSOR_FIRST ) /* Values are -ve */
383  const int position )
384  {
385  const ATTRIBUTE_LIST *attributeListPtr = *attributeListCursorPtr;
386 
387  assert( attributeListHead == NULL || \
388  isReadPtr( attributeListHead, sizeof( ATTRIBUTE_LIST ) ) );
389  assert( isWritePtr( attributeListCursorPtr, sizeof( ATTRIBUTE_LIST * ) ) );
390 
391  REQUIRES( sessionInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
392  sessionInfoType == CRYPT_ATTRIBUTE_CURRENT || \
393  sessionInfoType == CRYPT_ATTRIBUTE_CURRENT_INSTANCE );
394  REQUIRES( position <= CRYPT_CURSOR_FIRST && \
395  position >= CRYPT_CURSOR_LAST );
396 
397  /* If it's an absolute positioning code, pre-set the attribute cursor if
398  required */
399  if( position == CRYPT_CURSOR_FIRST || position == CRYPT_CURSOR_LAST )
400  {
401  if( attributeListHead == NULL )
402  return( CRYPT_ERROR_NOTFOUND );
403 
404  /* If it's an absolute attribute positioning code reset the
405  attribute cursor to the start of the list before we try to move
406  it, and if it's an attribute positioning code initialise the
407  attribute cursor if necessary */
408  if( sessionInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
409  attributeListPtr == NULL )
410  {
411  attributeListPtr = attributeListHead;
412  resetVirtualCursor( attributeListPtr );
413  }
414 
415  /* If there are no attributes present return the appropriate error
416  code */
417  if( attributeListPtr == NULL )
418  {
419  return( ( position == CRYPT_CURSOR_FIRST || \
420  position == CRYPT_CURSOR_LAST ) ? \
422  }
423  }
424  else
425  {
426  /* It's a relative positioning code, return a not-inited error
427  rather than a not-found error if the cursor isn't set since there
428  may be attributes present but the cursor hasn't been initialised
429  yet by selecting the first or last absolute attribute */
430  if( attributeListPtr == NULL )
431  return( CRYPT_ERROR_NOTINITED );
432  }
433 
434  /* Move the cursor */
435  attributeListPtr = ( const ATTRIBUTE_LIST * ) \
436  attributeMoveCursor( attributeListPtr, getAttrFunction,
437  sessionInfoType, position );
438  if( attributeListPtr == NULL )
439  return( CRYPT_ERROR_NOTFOUND );
440  *attributeListCursorPtr = ( ATTRIBUTE_LIST * ) attributeListPtr;
441  return( CRYPT_OK );
442  }
443 
444 /****************************************************************************
445 * *
446 * Find an Attribute *
447 * *
448 ****************************************************************************/
449 
450 /* Find a session attribute by type */
451 
452 CHECK_RETVAL_PTR \
453 const ATTRIBUTE_LIST *findSessionInfo( IN_OPT const ATTRIBUTE_LIST *attributeListPtr,
454  IN_ATTRIBUTE \
455  const CRYPT_ATTRIBUTE_TYPE attributeID )
456  {
457  assert( attributeListPtr == NULL || \
458  isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
459 
460  REQUIRES_N( attributeID > CRYPT_SESSINFO_FIRST && \
461  attributeID < CRYPT_SESSINFO_LAST );
462 
463  return( attributeFind( attributeListPtr, getAttrFunction, attributeID ) );
464  }
465 
466 /* Find a session attribute by type and content */
467 
469 const ATTRIBUTE_LIST *findSessionInfoEx( IN_OPT const ATTRIBUTE_LIST *attributeListPtr,
470  IN_ATTRIBUTE \
471  const CRYPT_ATTRIBUTE_TYPE attributeID,
472  IN_BUFFER( valueLength ) const void *value,
473  IN_LENGTH_SHORT const int valueLength )
474  {
476  int iterationCount;
477 
478  assert( attributeListPtr == NULL || \
479  isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
480  assert( isReadPtr( value, valueLength ) );
481 
482  REQUIRES_N( attributeID > CRYPT_SESSINFO_FIRST && \
483  attributeID < CRYPT_SESSINFO_LAST );
484  REQUIRES_N( valueLength > 0 && valueLength < MAX_INTLENGTH_SHORT );
485 
486  /* Find the first attribute of this type */
487  attributeListCursor = attributeFind( attributeListPtr, getAttrFunction,
488  attributeID );
489  if( attributeListCursor == NULL )
490  return( NULL );
491 
492  /* Walk down the rest of the list looking for an attribute entry whose
493  contents match the requested contents. Unfortunately we can't use
494  attributeFindNextInstance() to help us because that finds the next
495  instance of the current attribute in an attribute group, not the next
496  instance in an interleaved set of attributes */
497  for( iterationCount = 0;
498  attributeListCursor != NULL && \
499  iterationCount < FAILSAFE_ITERATIONS_MAX;
500  iterationCount++ )
501  {
502  if( attributeListCursor->attributeID == attributeID && \
503  attributeListCursor->valueLength == valueLength && \
504  !memcmp( attributeListCursor->value, value, valueLength ) )
505  break;
506  attributeListCursor = attributeListCursor->next;
507  }
508  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MAX );
509 
510  return( attributeListCursor );
511  }
512 
513 /****************************************************************************
514 * *
515 * Add an Attribute *
516 * *
517 ****************************************************************************/
518 
519 /* Add a session attribute. There are three versions of this function, the
520  standard version and two extended versions that allow the caller to
521  specify an access function to access session subtype-specific internal
522  attributes when the data being added is structured session-type-specific
523  data, and that allow the use of a set of ATTR_FLAG_xxx flags to provide
524  precise control over the attribute handling */
525 
527 static int addInfo( INOUT_PTR ATTRIBUTE_LIST **listHeadPtr,
528  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE groupID,
529  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,
530  IN_BUFFER_OPT( dataLength ) const void *data,
531  IN_LENGTH_SHORT const int dataLength,
532  IN_LENGTH_SHORT const int dataMaxLength,
533  IN_OPT const ATTRACCESSFUNCTION accessFunction,
534  IN_FLAGS( ATTR ) const int flags )
535  {
536  ATTRIBUTE_LIST *newElement, *insertPoint = NULL;
537 
538  assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
539  assert( ( data == NULL ) || \
540  ( isReadPtr( data, dataLength ) && \
541  dataLength <= dataMaxLength ) );
542 
543  REQUIRES( groupID > CRYPT_SESSINFO_FIRST && \
544  groupID < CRYPT_SESSINFO_LAST );
545  REQUIRES( attributeID > CRYPT_SESSINFO_FIRST && \
546  attributeID < CRYPT_SESSINFO_LAST );
547  REQUIRES( ( data == NULL && dataMaxLength == 0 ) || \
548  ( data != NULL && \
549  dataLength > 0 && dataLength <= dataMaxLength && \
550  dataMaxLength > 0 && dataMaxLength < MAX_INTLENGTH_SHORT ) );
551  /* String = { data, dataLength, dataMaxLength },
552  int = dataLength */
553  REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
554  REQUIRES( !( flags & ATTR_FLAG_COMPOSITE ) || \
555  accessFunction != NULL );
556 
557  /* Find the correct insertion point and make sure that the attribute
558  isn't already present */
559  if( *listHeadPtr != NULL )
560  {
561  ATTRIBUTE_LIST *prevElement = NULL;
562  int iterationCount;
563 
564  for( insertPoint = *listHeadPtr, iterationCount = 0;
565  insertPoint != NULL && \
566  iterationCount < FAILSAFE_ITERATIONS_MAX;
567  insertPoint = insertPoint->next, iterationCount++ )
568  {
569  /* If this is a non-multivalued attribute, make sure that it
570  isn't already present */
571  if( !( flags & ATTR_FLAG_MULTIVALUED ) && \
572  insertPoint->attributeID == attributeID )
573  return( CRYPT_ERROR_INITED );
574 
575  prevElement = insertPoint;
576  }
577  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MAX );
578  insertPoint = prevElement;
579  }
580 
581  /* Allocate memory for the new element and copy the information across.
582  The data is stored in storage ... storage + dataLength, with storage
583  reserved up to dataMaxLength (if it's greater than dataLength) to
584  allow the contents to be replaced with a new fixed-length value */
585  if( ( newElement = ( ATTRIBUTE_LIST * ) \
586  clAlloc( "addSessionAttribute", sizeof( ATTRIBUTE_LIST ) + \
587  dataMaxLength ) ) == NULL )
588  return( CRYPT_ERROR_MEMORY );
589  initVarStruct( newElement, ATTRIBUTE_LIST, dataMaxLength );
590  newElement->groupID = groupID;
591  newElement->attributeID = attributeID;
592  newElement->accessFunction = accessFunction;
593  newElement->flags = flags;
594  if( data == NULL )
595  newElement->intValue = dataLength;
596  else
597  {
598  assert( isReadPtr( data, dataLength ) );
599 
600  memcpy( newElement->value, data, dataLength );
601  newElement->valueLength = dataLength;
602  }
603  insertDoubleListElement( listHeadPtr, insertPoint, newElement );
604 
605  return( CRYPT_OK );
606  }
607 
609 int addSessionInfo( INOUT_PTR ATTRIBUTE_LIST **listHeadPtr,
610  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,
611  IN_INT_Z const int value )
612  {
613  assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
614 
615  REQUIRES( attributeID > CRYPT_SESSINFO_FIRST && \
616  attributeID < CRYPT_SESSINFO_LAST );
617  REQUIRES( value >= 0 && value < MAX_INTLENGTH );
618 
619  /* Pre-3.3 kludge: Set the groupID to the attributeID since groups
620  aren't defined yet */
621  return( addInfo( listHeadPtr, attributeID, attributeID, NULL,
622  value, 0, NULL, ATTR_FLAG_NONE ) );
623  }
624 
625 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
626 int addSessionInfoS( INOUT_PTR ATTRIBUTE_LIST **listHeadPtr,
627  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,
628  IN_BUFFER( dataLength ) const void *data,
629  IN_LENGTH_SHORT const int dataLength )
630  {
631  assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
632  assert( isReadPtr( data, dataLength ) );
633 
634  REQUIRES( attributeID > CRYPT_SESSINFO_FIRST && \
635  attributeID < CRYPT_SESSINFO_LAST );
636  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
637 
638  /* Pre-3.3 kludge: Set the groupID to the attributeID since groups
639  aren't defined yet */
640  return( addInfo( listHeadPtr, attributeID, attributeID, data,
641  dataLength, dataLength, NULL, ATTR_FLAG_NONE ) );
642  }
643 
644 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
645 int addSessionInfoEx( INOUT_PTR ATTRIBUTE_LIST **listHeadPtr,
646  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,
647  IN_BUFFER( dataLength ) const void *data,
648  IN_LENGTH_SHORT const int dataLength,
649  IN_FLAGS( ATTR ) const int flags )
650  {
651  assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
652  assert( isReadPtr( data, dataLength ) );
653 
654  REQUIRES( attributeID > CRYPT_SESSINFO_FIRST && \
655  attributeID < CRYPT_SESSINFO_LAST );
656  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
657 assert( ( flags & ~( ATTR_FLAG_NONE | ATTR_FLAG_ENCODEDVALUE | ATTR_FLAG_MULTIVALUED ) ) == 0 );
658  REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
659 
660  /* Pre-3.3 kludge: Set the groupID to the attributeID since groups
661  aren't defined yet */
662  return( addInfo( listHeadPtr, attributeID, attributeID, data,
663  dataLength, dataLength, NULL, flags ) );
664  }
665 
666 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
667 int addSessionInfoComposite( INOUT_PTR ATTRIBUTE_LIST **listHeadPtr,
668  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,
669  const ATTRACCESSFUNCTION accessFunction,
670  IN_BUFFER( dataLength ) const void *data,
671  IN_LENGTH_SHORT const int dataLength,
672  IN_FLAGS( ATTR ) const int flags )
673  {
674  assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
675  assert( isReadPtr( data, dataLength ) );
676 
677  REQUIRES( attributeID > CRYPT_SESSINFO_FIRST && \
678  attributeID < CRYPT_SESSINFO_LAST );
679  REQUIRES( accessFunction != NULL );
680  REQUIRES( dataLength > 0 && dataLength < MAX_INTLENGTH_SHORT );
681 assert( flags == ATTR_FLAG_MULTIVALUED || flags == ATTR_FLAG_COMPOSITE || \
683  REQUIRES( flags > ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
684 
685  /* For composite attributes the groupID is the attributeID, with the
686  actual attributeID being returned by the accessFunction */
687  return( addInfo( listHeadPtr, attributeID, attributeID, data,
688  dataLength, dataLength, accessFunction, flags ) );
689  }
690 
691 /* Update a session attribute, either by replacing an existing entry if it
692  already exists or by adding a new entry. Since we can potentially update
693  the entry later we specify two length values, the length of the data
694  currently being added and the maximum length that this value may take in
695  the future */
696 
697 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
698 int updateSessionInfo( INOUT_PTR ATTRIBUTE_LIST **listHeadPtr,
699  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,
700  IN_BUFFER( dataLength ) const void *data,
701  IN_LENGTH_SHORT const int dataLength,
702  IN_LENGTH_SHORT const int dataMaxLength,
703  IN_FLAGS( ATTR ) const int flags )
704  {
705  ATTRIBUTE_LIST *attributeListPtr = *listHeadPtr;
706 
707  assert( isWritePtr( listHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
708  assert( isReadPtr( data, dataLength ) );
709 
710  REQUIRES( attributeID > CRYPT_SESSINFO_FIRST && \
711  attributeID < CRYPT_SESSINFO_LAST );
712  REQUIRES( dataLength > 0 && dataLength <= dataMaxLength && \
713  dataLength < MAX_INTLENGTH_SHORT );
714  REQUIRES( dataMaxLength > 0 && dataMaxLength < MAX_INTLENGTH_SHORT );
715 assert( ( flags & ~( ATTR_FLAG_NONE | ATTR_FLAG_EPHEMERAL | ATTR_FLAG_ENCODEDVALUE ) ) == 0 );
716  REQUIRES( flags >= ATTR_FLAG_NONE && flags <= ATTR_FLAG_MAX );
717  REQUIRES( !( flags & ATTR_FLAG_MULTIVALUED ) );
718 
719  /* Find the first attribute of this type */
720  attributeListPtr = attributeFind( attributeListPtr, getAttrFunction,
721  attributeID );
722 
723  /* If the attribute is already present, update the value */
724  if( attributeListPtr != NULL )
725  {
726  REQUIRES( attributeListPtr->attributeID == attributeID );
727  REQUIRES( ( attributeListPtr->valueLength == 0 && \
728  !memcmp( attributeListPtr->value, \
729  "\x00\x00\x00\x00", 4 ) ) || \
730  ( attributeListPtr->valueLength > 0 ) );
731 
732  assert( isReadPtr( data, dataLength ) );
733 
734  REQUIRES( dataLength <= sizeofVarStruct( attributeListPtr, \
735  ATTRIBUTE_LIST ) - \
736  sizeof( ATTRIBUTE_LIST ) );
737  zeroise( attributeListPtr->value, attributeListPtr->valueLength );
738  memcpy( attributeListPtr->value, data, dataLength );
739  attributeListPtr->valueLength = dataLength;
740  return( CRYPT_OK );
741  }
742 
743  /* The attribute isn't already present, it's a straight add */
744  return( addInfo( listHeadPtr, attributeID, attributeID, data,
745  dataLength, dataMaxLength, NULL, flags ) );
746  }
747 
748 /****************************************************************************
749 * *
750 * Delete an Attribute *
751 * *
752 ****************************************************************************/
753 
754 /* Delete a complete set of session attributes */
755 
756 STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
757 int deleteSessionInfo( INOUT ATTRIBUTE_LIST **attributeListHead,
759  INOUT ATTRIBUTE_LIST *attributeListPtr )
760  {
761  assert( isWritePtr( attributeListHead, sizeof( ATTRIBUTE_LIST * ) ) );
762  assert( isWritePtr( attributeListCurrent, sizeof( ATTRIBUTE_LIST * ) ) );
763  assert( isWritePtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
764 
765  /* If we're about to delete the attribute that's pointed to by the
766  current-attribute pointer, advance it to the next attribute. If
767  there's no next attribute, move it to the previous attribute. This
768  behaviour is the most logically consistent, it means that we can do
769  things like deleting an entire attribute list by repeatedly deleting
770  a single attribute */
771  if( *attributeListCurrent == attributeListPtr )
772  {
773  *attributeListCurrent = ( attributeListPtr->next != NULL ) ? \
774  attributeListPtr->next : \
775  attributeListPtr->prev;
776  }
777 
778  /* Remove the item from the list */
779  deleteDoubleListElement( attributeListHead, attributeListPtr );
780 
781  /* Clear all data in the list item and free the memory */
782  endVarStruct( attributeListPtr, ATTRIBUTE_LIST );
783  clFree( "deleteSessionInfo", attributeListPtr );
784 
785  return( CRYPT_OK );
786  }
787 
788 STDC_NONNULL_ARG( ( 1, 2 ) ) \
789 void deleteSessionInfoAll( INOUT ATTRIBUTE_LIST **attributeListHead,
790  INOUT ATTRIBUTE_LIST **attributeListCurrent )
791  {
792  ATTRIBUTE_LIST *attributeListCursor = *attributeListHead;
793  int iterationCount;
794 
795  assert( isWritePtr( attributeListHead, sizeof( ATTRIBUTE_LIST * ) ) );
796  assert( isWritePtr( attributeListCurrent, sizeof( ATTRIBUTE_LIST * ) ) );
797 
798  /* If the list was empty, return now */
799  if( attributeListCursor == NULL )
800  {
801  REQUIRES_V( *attributeListCurrent == NULL );
802  return;
803  }
804 
805  /* Destroy any remaining list items */
806  for( iterationCount = 0;
807  attributeListCursor != NULL && \
808  iterationCount < FAILSAFE_ITERATIONS_MAX;
809  iterationCount++ )
810  {
811  ATTRIBUTE_LIST *itemToFree = attributeListCursor;
812 
813  attributeListCursor = attributeListCursor->next;
814  deleteSessionInfo( attributeListHead, attributeListCurrent,
815  itemToFree );
816  }
817  ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MAX );
818  *attributeListCurrent = NULL;
819 
820  ENSURES_V( *attributeListHead == NULL );
821  }
822 #endif /* USE_SESSIONS */