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