1 /****************************************************************************
2 *																			*
3 *					Certificate Attribute Management Routines				*
4 *						Copyright Peter Gutmann 1996-2008					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "cert.h"
10   #include "certattr.h"
11 #else
12   #include "cert/cert.h"
13   #include "cert/certattr.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_CERTIFICATES
17 
18 /* Special ATTRIBUTE_LIST values to indicate that an attribute field is a
19    blob attribute, a default-value field, or a complete attribute, see the
20    long comment for findAttributeFieldEx() in cert/ext.c for a detailed
21    description */
22 
23 #define ATTR_BLOB_ATTR		{ ( CRYPT_ATTRIBUTE_TYPE ) 0, \
24 							  ( CRYPT_ATTRIBUTE_TYPE ) 0, \
25 							  ( CRYPT_ATTRIBUTE_TYPE ) 0 }
26 #define ATTR_COMPLETE_ATTR	{ ( CRYPT_ATTRIBUTE_TYPE ) CRYPT_ERROR, \
27 							  ( CRYPT_ATTRIBUTE_TYPE ) 0, \
28 							  ( CRYPT_ATTRIBUTE_TYPE ) 0 }
29 #define ATTR_DEFAULT_FIELD	{ ( CRYPT_ATTRIBUTE_TYPE ) 0, \
30 							  ( CRYPT_ATTRIBUTE_TYPE ) CRYPT_ERROR, \
31 							  ( CRYPT_ATTRIBUTE_TYPE ) 0 }
32 
33 /****************************************************************************
34 *																			*
35 *								Utility Functions							*
36 *																			*
37 ****************************************************************************/
38 
39 /* Callback function used to provide external access to attribute list-
40    internal fields */
41 
42 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)43 static const void *getAttrFunction( IN_OPT TYPECAST( ATTRIBUTE_LIST * ) \
44 										const void *attributePtr,
45 									OUT_OPT_ATTRIBUTE_Z \
46 										CRYPT_ATTRIBUTE_TYPE *groupID,
47 									OUT_OPT_ATTRIBUTE_Z \
48 										CRYPT_ATTRIBUTE_TYPE *attributeID,
49 									OUT_OPT_ATTRIBUTE_Z \
50 										CRYPT_ATTRIBUTE_TYPE *instanceID,
51 									IN_ENUM( ATTR ) const ATTR_TYPE attrGetType )
52 	{
53 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
54 
55 	assert( attributeListPtr == NULL || \
56 			isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
57 	assert( groupID == NULL || \
58 			isWritePtr( groupID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
59 	assert( attributeID == NULL || \
60 			isWritePtr( attributeID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
61 	assert( instanceID == NULL || \
62 			isWritePtr( instanceID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
63 
64 	REQUIRES_N( attrGetType > ATTR_NONE && attrGetType < ATTR_LAST );
65 
66 	/* Clear return values */
67 	if( groupID != NULL )
68 		*groupID = CRYPT_ATTRIBUTE_NONE;
69 	if( attributeID != NULL )
70 		*attributeID = CRYPT_ATTRIBUTE_NONE;
71 	if( instanceID != NULL )
72 		*instanceID = CRYPT_ATTRIBUTE_NONE;
73 
74 	/* Move to the next or previous attribute if required */
75 	if( attributeListPtr == NULL || \
76 		!isValidAttributeField( attributeListPtr ) )
77 		return( NULL );
78 	if( attrGetType == ATTR_PREV )
79 		attributeListPtr = attributeListPtr->prev;
80 	else
81 		{
82 		if( attrGetType == ATTR_NEXT )
83 			attributeListPtr = attributeListPtr->next;
84 		}
85 	if( attributeListPtr == NULL || \
86 		!isValidAttributeField( attributeListPtr ) )
87 		return( NULL );
88 
89 	/* Return ID information to the caller */
90 	if( groupID != NULL )
91 		*groupID = attributeListPtr->attributeID;
92 	if( attributeID != NULL )
93 		*attributeID = attributeListPtr->fieldID;
94 	if( instanceID != NULL )
95 		*instanceID = attributeListPtr->subFieldID;
96 	return( attributeListPtr );
97 	}
98 
99 /****************************************************************************
100 *																			*
101 *								Attribute Type Mapping						*
102 *																			*
103 ****************************************************************************/
104 
105 /* Get the attribute information for a given OID.  Note that this function
106    looks up whole attributes by OID but won't match an OID that's internal
107    to an attribute */
108 
109 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
oidToAttribute(IN_ENUM (ATTRIBUTE)const ATTRIBUTE_TYPE attributeType,IN_BUFFER (oidLength)const BYTE * oid,IN_LENGTH_OID const int oidLength)110 const ATTRIBUTE_INFO *oidToAttribute( IN_ENUM( ATTRIBUTE ) \
111 										const ATTRIBUTE_TYPE attributeType,
112 									  IN_BUFFER( oidLength ) const BYTE *oid,
113 									  IN_LENGTH_OID const int oidLength )
114 	{
115 	const ATTRIBUTE_INFO *attributeInfoPtr;
116 	int attributeInfoSize, iterationCount, status;
117 
118 	assert( isReadPtr( oid, oidLength ) );
119 
120 	REQUIRES_N( attributeType == ATTRIBUTE_CERTIFICATE || \
121 				attributeType == ATTRIBUTE_CMS );
122 	REQUIRES_N( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE && \
123 				oidLength == sizeofOID( oid ) );
124 
125 	status = getAttributeInfo( attributeType, &attributeInfoPtr,
126 							   &attributeInfoSize );
127 	ENSURES_N( cryptStatusOK( status ) );
128 	for( iterationCount = 0;
129 		 !isAttributeTableEnd( attributeInfoPtr ) && \
130 			iterationCount < attributeInfoSize; \
131 		 attributeInfoPtr++, iterationCount++ )
132 		{
133 		assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
134 
135 		/* If it's an OID that's internal to an attribute, skip it */
136 		if( !isAttributeStart( attributeInfoPtr ) )
137 			continue;
138 
139 		/* Guaranteed by the initialisation sanity-check */
140 		ENSURES_N( attributeInfoPtr->oid != NULL );
141 
142 		/* If the OID matches the current attribute, we're done */
143 		if( oidLength == sizeofOID( attributeInfoPtr->oid ) && \
144 			!memcmp( attributeInfoPtr->oid, oid, oidLength ) )
145 			return( attributeInfoPtr );
146 		}
147 	ENSURES_N( iterationCount < attributeInfoSize );
148 
149 	/* It's an unknown attribute */
150 	return( NULL );
151 	}
152 
153 /* Get the attribute and attributeID for a field ID */
154 
155 CHECK_RETVAL_PTR \
fieldIDToAttribute(IN_ENUM (ATTRIBUTE)const ATTRIBUTE_TYPE attributeType,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,IN_ATTRIBUTE_OPT const CRYPT_ATTRIBUTE_TYPE subFieldID,OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE * attributeID)156 const ATTRIBUTE_INFO *fieldIDToAttribute( IN_ENUM( ATTRIBUTE ) \
157 											const ATTRIBUTE_TYPE attributeType,
158 										  IN_ATTRIBUTE \
159 											const CRYPT_ATTRIBUTE_TYPE fieldID,
160 										  IN_ATTRIBUTE_OPT \
161 											const CRYPT_ATTRIBUTE_TYPE subFieldID,
162 										  OUT_OPT_ATTRIBUTE_Z \
163 											CRYPT_ATTRIBUTE_TYPE *attributeID )
164 	{
165 	CRYPT_ATTRIBUTE_TYPE lastAttributeID = CRYPT_ATTRIBUTE_NONE;
166 	const ATTRIBUTE_INFO *attributeInfoPtr;
167 	int attributeInfoSize, iterationCount, status;
168 
169 	assert( attributeID == NULL || \
170 			isWritePtr( attributeID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
171 
172 	REQUIRES_N( attributeType == ATTRIBUTE_CERTIFICATE || \
173 				attributeType == ATTRIBUTE_CMS );
174 	REQUIRES_N( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
175 				fieldID <= CRYPT_CERTINFO_LAST );
176 	REQUIRES_N( subFieldID == CRYPT_ATTRIBUTE_NONE || \
177 				( subFieldID >= CRYPT_CERTINFO_FIRST_NAME && \
178 				  subFieldID <= CRYPT_CERTINFO_LAST_GENERALNAME ) );
179 
180 	/* Clear return value */
181 	if( attributeID != NULL )
182 		*attributeID = CRYPT_ATTRIBUTE_NONE;
183 
184 	/* Find the information on this attribute field */
185 	status = getAttributeInfo( attributeType, &attributeInfoPtr,
186 							   &attributeInfoSize );
187 	ENSURES_N( cryptStatusOK( status ) );
188 	for( iterationCount = 0;
189 		 !isAttributeTableEnd( attributeInfoPtr ) && \
190 			iterationCount < attributeInfoSize;
191 		 attributeInfoPtr++, iterationCount++ )
192 		{
193 		const ATTRIBUTE_INFO *altEncodingTable;
194 		int innerIterationCount;
195 
196 		assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
197 
198 		/* If we're looking for an attribute ID and this is the start of a
199 		   complete attribute, remember it so that we can report it to the
200 		   caller */
201 		if( attributeID != NULL && isAttributeStart( attributeInfoPtr ) )
202 			{
203 			/* Usually the attribute ID is the fieldID for the first entry,
204 			   however in some cases the attributeID is the same as the
205 			   fieldID and isn't specified until later on.  For example when
206 			   the attribute consists of a SEQUENCE OF field the first
207 			   entry is the SEQUENCE and the fieldID isn't given until the
208 			   second entry.  This case is denoted by the fieldID being
209 			   FIELDID_FOLLOWS, if this happens then the next entry contains
210 			   the fieldID (this requirement has been verified by the
211 			   startup self-check in ext_def.c) */
212 			if( attributeInfoPtr->fieldID == FIELDID_FOLLOWS )
213 				attributeInfoPtr++;
214 			ENSURES_N( attributeInfoPtr->fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
215 					   attributeInfoPtr->fieldID <= CRYPT_CERTINFO_LAST );
216 			lastAttributeID = attributeInfoPtr->fieldID;
217 			}
218 
219 		/* If the field ID for this entry isn't the one that we want,
220 		   continue */
221 		if( attributeInfoPtr->fieldID != fieldID )
222 			continue;
223 
224 		/* If we're not after a subfield match or there's no subfield
225 		   information present, we're done */
226 		if( subFieldID == CRYPT_ATTRIBUTE_NONE || \
227 			attributeInfoPtr->extraData == NULL )
228 			{
229 			if( attributeID != NULL )
230 				*attributeID = lastAttributeID;
231 			return( attributeInfoPtr );
232 			}
233 
234 		/* We're after a subfield match as well, try and match it.
235 		   Unfortunately we can't use the attributeInfoSize bounds check
236 		   limit here because we don't know the size of the alternative
237 		   encoding table so we have to use a generic large value (the
238 		   terminating condition has been verified by the startup self-
239 		   check in ext_def.c) */
240 		for( altEncodingTable = attributeInfoPtr->extraData, \
241 				innerIterationCount = 0;
242 			 !isAttributeTableEnd( altEncodingTable ) && \
243 				innerIterationCount < FAILSAFE_ITERATIONS_LARGE;
244 			 altEncodingTable++, innerIterationCount++ )
245 			{
246 			if( altEncodingTable->fieldID == subFieldID )
247 				{
248 				if( attributeID != NULL )
249 					*attributeID = lastAttributeID;
250 				return( altEncodingTable );
251 				}
252 			}
253 
254 		/* If we reach this point for any reason then it's an error so we
255 		   don't have to perform an explicit iteration-count check */
256 		retIntError_Null();
257 		}
258 	ENSURES_N( iterationCount < attributeInfoSize );
259 
260 	/* If the use of all attributes is enabled then we should never reach
261 	   this point, however since it's unlikely that we'll have every single
262 	   obscure, obsolete, and weird attribute enabled we simply return a not-
263 	   found error if we get to here */
264 	return( NULL );
265 	}
266 
267 /****************************************************************************
268 *																			*
269 *					Attribute Location/Cursor Movement Routines				*
270 *																			*
271 ****************************************************************************/
272 
273 /* Find the start of an attribute from a field within the attribute */
274 
275 CHECK_RETVAL_PTR \
findAttributeStart(IN_OPT const ATTRIBUTE_LIST * attributeListPtr)276 ATTRIBUTE_LIST *findAttributeStart( IN_OPT const ATTRIBUTE_LIST *attributeListPtr )
277 	{
278 	assert( attributeListPtr == NULL || \
279 			isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
280 
281 	return( attributeFindStart( attributeListPtr, getAttrFunction ) );
282 	}
283 
284 /* Find an attribute in a list of certificate attributes by object identifier
285    (for blob-type attributes) or by field and subfield ID (for known
286    attributes).  These are exact-match functions for which we need an
287    attribute with { fieldID, subFieldID } matching exactly.  It won't find,
288    for example, any match for CRYPT_CERTINFO_ISSUINGDISTRIBUTIONPOINT even
289    if one of the attribute fields such as CRYPT_CERTINFO_ISSUINGDIST_FULLNAME
290    is present */
291 
292 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 2 ) ) \
findAttributeByOID(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_BUFFER (oidLength)const BYTE * oid,IN_LENGTH_OID const int oidLength)293 ATTRIBUTE_PTR *findAttributeByOID( IN_OPT const ATTRIBUTE_PTR *attributePtr,
294 								   IN_BUFFER( oidLength ) const BYTE *oid,
295 								   IN_LENGTH_OID const int oidLength )
296 	{
297 	const ATTRIBUTE_LIST *attributeListPtr;
298 	int iterationCount;
299 
300 	assert( attributePtr == NULL || \
301 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
302 	assert( isReadPtr( oid, oidLength ) );
303 
304 	REQUIRES_N( oidLength >= MIN_OID_SIZE && oidLength <= MAX_OID_SIZE && \
305 				oidLength == sizeofOID( oid ) );
306 
307 	/* Early-out check for empty attribute lists */
308 	if( attributePtr == NULL )
309 		return( NULL );
310 
311 	/* Find the position of this component in the list */
312 	for( attributeListPtr = attributePtr, iterationCount = 0;
313 		 attributeListPtr != NULL && \
314 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
315 		 attributeListPtr = attributeListPtr->next, iterationCount++ )
316 		{
317 		/* If it's not a blob-type attribute, continue */
318 		if( !checkAttributeProperty( attributeListPtr,
319 									 ATTRIBUTE_PROPERTY_BLOBATTRIBUTE ) )
320 			continue;
321 
322 		/* If we've found the entry with the required OID, we're done */
323 		if( oidLength == sizeofOID( attributeListPtr->oid ) && \
324 			!memcmp( attributeListPtr->oid, oid, oidLength ) )
325 			return( ( ATTRIBUTE_PTR * ) attributeListPtr );
326 		}
327 	ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );
328 
329 	return( NULL );
330 	}
331 
332 CHECK_RETVAL_PTR \
findAttributeField(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,IN_ATTRIBUTE_OPT const CRYPT_ATTRIBUTE_TYPE subFieldID)333 ATTRIBUTE_PTR *findAttributeField( IN_OPT const ATTRIBUTE_PTR *attributePtr,
334 								   IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,
335 								   IN_ATTRIBUTE_OPT \
336 										const CRYPT_ATTRIBUTE_TYPE subFieldID )
337 	{
338 	assert( attributePtr == NULL || \
339 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
340 
341 	REQUIRES_N( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
342 				fieldID <= CRYPT_CERTINFO_LAST );
343 	REQUIRES_N( subFieldID == CRYPT_ATTRIBUTE_NONE || \
344 				( subFieldID >= CRYPT_CERTINFO_FIRST_NAME && \
345 				  subFieldID <= CRYPT_CERTINFO_LAST_GENERALNAME ) );
346 
347 	/* Early-out check for empty attribute lists */
348 	if( attributePtr == NULL )
349 		return( NULL );
350 
351 	if( subFieldID == CRYPT_ATTRIBUTE_NONE )
352 		return( attributeFind( attributePtr, getAttrFunction, fieldID ) );
353 	return( attributeFindEx( attributePtr, getAttrFunction,
354 							 CRYPT_ATTRIBUTE_NONE, fieldID, subFieldID ) );
355 	}
356 
357 /* Find an attribute in a list of certificate attributes by field ID, with
358    special handling for things that aren't direct matches.  These special
359    cases occur when:
360 
361 	We're searching via the overall attribute ID for a constructed attribute
362 	(e.g. CRYPT_CERTINFO_CA) for which only the individual fields (e.g.
363 	CRYPT_CERTINFO_BASICCONSTRAINTS) are present in the attribute list, in
364 	which case we return a special-case value to indicate that this is a
365 	complete attribute and not just one attribute field.
366 
367 	We're searching for a default-valued field which isn't explicitly
368 	present in the attribute list but for which the attribute that contains
369 	it is present, in which case we return a special-case value to indicate
370 	that this is a default-value field */
371 
372 CHECK_RETVAL_PTR \
findAttributeFieldEx(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID)373 ATTRIBUTE_PTR *findAttributeFieldEx( IN_OPT const ATTRIBUTE_PTR *attributePtr,
374 									 IN_ATTRIBUTE \
375 										const CRYPT_ATTRIBUTE_TYPE fieldID )
376 	{
377 	static const ATTRIBUTE_LIST completeAttribute = ATTR_COMPLETE_ATTR;
378 	static const ATTRIBUTE_LIST defaultField = ATTR_DEFAULT_FIELD;
379 	const ATTRIBUTE_LIST *attributeListCursor;
380 	const ATTRIBUTE_INFO *attributeInfoPtr;
381 	const ATTRIBUTE_TYPE attributeType = \
382 							( fieldID >= CRYPT_CERTINFO_FIRST_CMS ) ? \
383 							ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE;
384 	CRYPT_ATTRIBUTE_TYPE attributeID;
385 
386 	assert( attributePtr == NULL || \
387 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
388 
389 	REQUIRES_N( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
390 				fieldID <= CRYPT_CERTINFO_LAST );
391 
392 	/* Early-out check for empty attribute lists */
393 	if( attributePtr == NULL )
394 		return( NULL );
395 
396 	/* Find the position of this attribute component in the list */
397 	attributeListCursor = attributeFind( attributePtr,
398 										 getAttrFunction, fieldID );
399 	if( attributeListCursor != NULL )
400 		return( ( ATTRIBUTE_PTR * ) attributeListCursor );
401 
402 	/* This particular attribute field isn't present in the list of
403 	   attributes, check whether the overall attribute that contains this
404 	   field is present.  First we map the field to the attribute that
405 	   contains it, so for example CRYPT_CERTINFO_AUTHORITYINFO_CRLS
406 	   would become CRYPT_CERTINFO_AUTHORITYINFOACCESS.  If we're already
407 	   searching by overall attribute ID (e.g. searching for
408 	   CRYPT_CERTINFO_AUTHORITYINFOACCESS, which wouldn't result in a match
409 	   because only the component fields of
410 	   CRYPT_CERTINFO_AUTHORITYINFOACCESS are present) then this step is a
411 	   no-op */
412 	attributeInfoPtr = fieldIDToAttribute( attributeType, fieldID,
413 										   CRYPT_ATTRIBUTE_NONE, &attributeID );
414 	if( attributeInfoPtr == NULL )
415 		{
416 		/* There's no attribute containing this field, exit */
417 		return( NULL );
418 		}
419 
420 	/* We've now got the ID of the overall attribute that contains the
421 	   requested field, check whether any other part of the attribute that
422 	   contains the field is present in the list of attribute fields.  So
423 	   from the previous example of looking for the field
424 	   CRYPT_CERTINFO_AUTHORITYINFO_CRLS we'd get a match if e.g.
425 	   CRYPT_CERTINFO_AUTHORITYINFO_OCSP was present since they're both in
426 	   the same attribute CRYPT_CERTINFO_AUTHORITYINFOACCESS */
427 	attributeListCursor = attributeFindEx( attributePtr, getAttrFunction,
428 										   attributeID, CRYPT_ATTRIBUTE_NONE,
429 										   CRYPT_ATTRIBUTE_NONE );
430 	if( attributeListCursor == NULL || \
431 		!isValidAttributeField( attributeListCursor ) )
432 		return( NULL );
433 
434 	/* Some other part of the attribute containing the given field is
435 	   present in the attribute list.  If the attribute info indicates that
436 	   this field is a default-value one we return an entry that denotes
437 	   that this field is pseudo-present due to it having a default setting.
438 	   Note that this requires that the field be a BOOLEAN DEFAULT FALSE, or
439 	   at least a numeric value DEFAULT 0, since the returned 'defaultField'
440 	   reads as having a numeric value zero (this has been verified by the
441 	   startup self-check in ext_def.c).  If the attribute info indicates
442 	   that this is an ID for a complete attribute rather than an individual
443 	   field within it we return an entry to indicate this */
444 	if( attributeInfoPtr->encodingFlags & FL_DEFAULT )
445 		return( ( ATTRIBUTE_PTR * ) &defaultField );
446 	if( isAttributeStart( attributeInfoPtr ) )
447 		return( ( ATTRIBUTE_PTR * ) &completeAttribute );
448 
449 	return( NULL );
450 	}
451 
452 /* Find the next instance of an attribute field in an attribute.  This is
453    used to step through multiple instances of a field, for example where the
454    attribute is defined as containing a SEQUENCE OF <field> */
455 
456 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
findNextFieldInstance(const ATTRIBUTE_PTR * attributePtr)457 ATTRIBUTE_PTR *findNextFieldInstance( const ATTRIBUTE_PTR *attributePtr )
458 	{
459 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
460 
461 	return( attributeFindNextInstance( attributePtr, getAttrFunction ) );
462 	}
463 
464 /* Find a DN in an attribute, where the attribute will be a GeneralName */
465 
466 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
findDnInAttribute(IN_OPT const ATTRIBUTE_PTR * attributePtr)467 ATTRIBUTE_PTR *findDnInAttribute( IN_OPT const ATTRIBUTE_PTR *attributePtr )
468 	{
469 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
470 	CRYPT_ATTRIBUTE_TYPE attributeID, fieldID;
471 	int iterationCount;
472 
473 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
474 
475 	/* If it's an empty attribute list, there's nothing to do */
476 	if( attributePtr == NULL )
477 		return( NULL );
478 
479 	/* Remember the current GeneralName type so that we don't stray
480 	   outside it */
481 	attributeID = attributeListPtr->attributeID;
482 	fieldID = attributeListPtr->fieldID;
483 	REQUIRES_N( isGeneralNameSelectionComponent( fieldID ) );
484 
485 	/* Search for a DN in the current GeneralName */
486 	for( iterationCount = 0;
487 		 attributeListPtr != NULL && \
488 			attributeListPtr->attributeID == attributeID && \
489 			attributeListPtr->fieldID == fieldID && \
490 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
491 		 attributeListPtr = attributeListPtr->next, iterationCount++ )
492 		{
493 		if( attributeListPtr->fieldType == FIELDTYPE_DN )
494 			return( ( ATTRIBUTE_PTR * ) attributeListPtr );
495 		}
496 	ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );
497 
498 	return( NULL );
499 	}
500 
501 /* Find an overall attribute in a list of attributes.  This is almost always
502    used as a check for the presence of an overall attribute so we provide a
503    separate function checkAttributeXXXPresent() to make this explicit */
504 
505 CHECK_RETVAL_PTR \
findAttribute(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,const BOOLEAN isFieldID)506 ATTRIBUTE_PTR *findAttribute( IN_OPT const ATTRIBUTE_PTR *attributePtr,
507 							  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE attributeID,
508 							  const BOOLEAN isFieldID )
509 	{
510 	CRYPT_ATTRIBUTE_TYPE localAttributeID = attributeID;
511 
512 	assert( attributePtr == NULL || \
513 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
514 
515 	REQUIRES_N( attributeID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
516 				attributeID <= CRYPT_CERTINFO_LAST );
517 
518 	if( attributePtr == NULL )
519 		return( NULL );
520 
521 	/* If this is a (potential) fieldID rather than an attributeID, find the
522 	   attributeID for the attribute containing this field */
523 	if( isFieldID )
524 		{
525 		if( fieldIDToAttribute( ( attributeID >= CRYPT_CERTINFO_FIRST_CMS ) ? \
526 									ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE,
527 								attributeID, CRYPT_ATTRIBUTE_NONE,
528 								&localAttributeID ) == NULL )
529 			{
530 			/* There's no attribute containing this field, exit */
531 			return( NULL );
532 			}
533 		}
534 	else
535 		{
536 		/* Make sure that we're searching on an attribute ID rather than a
537 		   field ID */
538 		ENSURES_N( \
539 			fieldIDToAttribute( ( attributeID >= CRYPT_CERTINFO_FIRST_CMS ) ? \
540 									ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE,
541 								attributeID, CRYPT_ATTRIBUTE_NONE,
542 								&localAttributeID ) == NULL || \
543 			attributeID == localAttributeID );
544 		}
545 
546 	/* Check whether this attribute is present in the list of attribute
547 	   fields */
548 	return( attributeFindEx( attributePtr, getAttrFunction, localAttributeID,
549 							 CRYPT_ATTRIBUTE_NONE, CRYPT_ATTRIBUTE_NONE ) );
550 	}
551 
552 CHECK_RETVAL_BOOL \
checkAttributePresent(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID)553 BOOLEAN checkAttributePresent( IN_OPT const ATTRIBUTE_PTR *attributePtr,
554 							   IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID )
555 	{
556 	assert( attributePtr == NULL || \
557 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
558 
559 	REQUIRES_B( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
560 				fieldID <= CRYPT_CERTINFO_LAST );
561 
562 	return( findAttribute( attributePtr, fieldID, FALSE ) != NULL ? \
563 			TRUE : FALSE );
564 	}
565 
566 CHECK_RETVAL_BOOL \
checkAttributeFieldPresent(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID)567 BOOLEAN checkAttributeFieldPresent( IN_OPT const ATTRIBUTE_PTR *attributePtr,
568 									IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID )
569 	{
570 	assert( attributePtr == NULL || \
571 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
572 
573 	REQUIRES_B( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
574 				fieldID <= CRYPT_CERTINFO_LAST );
575 
576 	return( findAttributeField( attributePtr, fieldID, \
577 								CRYPT_ATTRIBUTE_NONE ) != NULL ? \
578 			TRUE : FALSE );
579 	}
580 
581 /* Move the attribute cursor relative to the current cursor position.  The
582    reason for the apparently-reversed values in the IN_RANGE() annotation
583    are because the values are -ve, so last comes before first */
584 
585 CHECK_RETVAL_PTR \
certMoveAttributeCursor(IN_OPT const ATTRIBUTE_PTR * currentCursor,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE certInfoType,IN_RANGE (CRYPT_CURSOR_LAST,CRYPT_CURSOR_FIRST)const int position)586 ATTRIBUTE_PTR *certMoveAttributeCursor( IN_OPT const ATTRIBUTE_PTR *currentCursor,
587 										IN_ATTRIBUTE \
588 											const CRYPT_ATTRIBUTE_TYPE certInfoType,
589 										IN_RANGE( CRYPT_CURSOR_LAST, \
590 												  CRYPT_CURSOR_FIRST) \
591 											const int position )
592 	{
593 	assert( currentCursor == NULL || \
594 			isReadPtr( currentCursor, sizeof( ATTRIBUTE_LIST ) ) );
595 
596 	REQUIRES_N( certInfoType == CRYPT_ATTRIBUTE_CURRENT_GROUP || \
597 				certInfoType == CRYPT_ATTRIBUTE_CURRENT || \
598 				certInfoType == CRYPT_ATTRIBUTE_CURRENT_INSTANCE );
599 	REQUIRES_N( position <= CRYPT_CURSOR_FIRST && \
600 				position >= CRYPT_CURSOR_LAST );
601 
602 	return( ( ATTRIBUTE_PTR * ) \
603 			attributeMoveCursor( currentCursor, getAttrFunction,
604 								 certInfoType, position ) );
605 	}
606 
607 /****************************************************************************
608 *																			*
609 *							Attribute Access Routines						*
610 *																			*
611 ****************************************************************************/
612 
613 /* Get/set information for an attribute */
614 
615 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
checkAttributeProperty(const ATTRIBUTE_PTR * attributePtr,IN_ENUM (ATTRIBUTE_PROPERTY)ATTRIBUTE_PROPERTY_TYPE property)616 BOOLEAN checkAttributeProperty( const ATTRIBUTE_PTR *attributePtr,
617 								IN_ENUM( ATTRIBUTE_PROPERTY ) \
618 									ATTRIBUTE_PROPERTY_TYPE property )
619 	{
620 	static const ATTRIBUTE_LIST blobAttribute = ATTR_BLOB_ATTR;
621 	static const ATTRIBUTE_LIST completeAttribute = ATTR_COMPLETE_ATTR;
622 	static const ATTRIBUTE_LIST defaultField = ATTR_DEFAULT_FIELD;
623 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
624 
625 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
626 
627 	REQUIRES_B( property > ATTRIBUTE_PROPERTY_NONE && \
628 				property < ATTRIBUTE_PROPERTY_LAST );
629 
630 	switch( property )
631 		{
632 		case ATTRIBUTE_PROPERTY_BLOBATTRIBUTE:
633 			return( ( attributeListPtr->fieldID == blobAttribute.fieldID && \
634 					  attributeListPtr->attributeID == blobAttribute.attributeID ) ? \
635 					TRUE : FALSE );
636 
637 		case ATTRIBUTE_PROPERTY_COMPLETEATRIBUTE:
638 			return( ( attributeListPtr->fieldID == completeAttribute.fieldID && \
639 					  attributeListPtr->attributeID == completeAttribute.attributeID ) ? \
640 					TRUE : FALSE );
641 
642 		case ATTRIBUTE_PROPERTY_CRITICAL:
643 			return( ( attributeListPtr->flags & ATTR_FLAG_CRITICAL ) ? \
644 					TRUE : FALSE );
645 
646 		case ATTRIBUTE_PROPERTY_DEFAULTVALUE:
647 			return( ( attributeListPtr->fieldID == defaultField.fieldID && \
648 					  attributeListPtr->attributeID == defaultField.attributeID ) ? \
649 					  TRUE : FALSE );
650 
651 		case ATTRIBUTE_PROPERTY_DN:
652 			return( ( attributeListPtr->fieldType == FIELDTYPE_DN ) ? \
653 					TRUE : FALSE );
654 
655 		case ATTRIBUTE_PROPERTY_IGNORED:
656 			return( ( attributeListPtr->flags & ATTR_FLAG_IGNORED ) ? \
657 					TRUE : FALSE );
658 
659 		case ATTRIBUTE_PROPERTY_LOCKED:
660 			return( ( attributeListPtr->flags & ATTR_FLAG_LOCKED ) ? \
661 					TRUE : FALSE );
662 
663 		case ATTRIBUTE_PROPERTY_OID:
664 			return( ( attributeListPtr->fieldType == BER_OBJECT_IDENTIFIER ) ? \
665 					TRUE : FALSE );
666 		}
667 
668 	retIntError_Boolean();
669 	}
670 
671 STDC_NONNULL_ARG( ( 1 ) ) \
setAttributeProperty(INOUT ATTRIBUTE_PTR * attributePtr,IN_ENUM (ATTRIBUTE_PROPERTY)ATTRIBUTE_PROPERTY_TYPE property,IN_INT_Z const int optValue)672 void setAttributeProperty( INOUT ATTRIBUTE_PTR *attributePtr,
673 						   IN_ENUM( ATTRIBUTE_PROPERTY ) \
674 								ATTRIBUTE_PROPERTY_TYPE property,
675 						   IN_INT_Z const int optValue )
676 	{
677 	ATTRIBUTE_LIST *attributeListPtr = attributePtr;
678 
679 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
680 
681 	REQUIRES_V( property > ATTRIBUTE_PROPERTY_NONE && \
682 				property < ATTRIBUTE_PROPERTY_LAST );
683 	REQUIRES_V( optValue >= 0 );
684 
685 	switch( property )
686 		{
687 		case ATTRIBUTE_PROPERTY_CRITICAL:
688 			REQUIRES_V( optValue == 0 );
689 
690 			attributeListPtr->flags |= ATTR_FLAG_CRITICAL;
691 			return;
692 
693 		case ATTRIBUTE_PROPERTY_VALUE:
694 			REQUIRES_V( optValue > 0 );
695 
696 			attributeListPtr->intValue = optValue;
697 			return;
698 
699 		case ATTRIBUTE_PROPERTY_LOCKED:
700 			REQUIRES_V( optValue == 0 );
701 
702 			attributeListPtr->flags |= ATTR_FLAG_LOCKED;
703 			return;
704 		}
705 
706 	retIntError_Void();
707 	}
708 
709 /* Get attribute ID information */
710 
711 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
getAttributeIdInfo(const ATTRIBUTE_PTR * attributePtr,OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE * attributeID,OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE * fieldID,OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE * subFieldID)712 int getAttributeIdInfo( const ATTRIBUTE_PTR *attributePtr,
713 						OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *attributeID,
714 						OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *fieldID,
715 						OUT_OPT_ATTRIBUTE_Z CRYPT_ATTRIBUTE_TYPE *subFieldID )
716 	{
717 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
718 
719 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
720 	assert( attributeID == NULL || \
721 			isWritePtr( attributeID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
722 	assert( fieldID == NULL || \
723 			isWritePtr( fieldID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
724 	assert( subFieldID == NULL || \
725 			isWritePtr( subFieldID, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
726 
727 	REQUIRES( attributeID != NULL || fieldID != NULL || subFieldID != NULL );
728 
729 	/* Return ID information to the caller */
730 	if( attributeID != NULL )
731 		*attributeID = attributeListPtr->attributeID;
732 	if( fieldID != NULL )
733 		*fieldID = attributeListPtr->fieldID;
734 	if( subFieldID != NULL )
735 		*subFieldID = attributeListPtr->subFieldID;
736 
737 	return( CRYPT_OK );
738 	}
739 
740 /* Enumerate entries in an attribute list.  Note that these two functions
741    must be called atomically since they record pointers within the list,
742    which would leave a dangling reference if (say) a delete occurred between
743    getNext()'s */
744 
745 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
getFirstAttribute(OUT ATTRIBUTE_ENUM_INFO * attrEnumInfo,IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ENUM (ATTRIBUTE_ENUM)const ATTRIBUTE_ENUM_TYPE enumType)746 const ATTRIBUTE_PTR *getFirstAttribute( OUT ATTRIBUTE_ENUM_INFO *attrEnumInfo,
747 										IN_OPT const ATTRIBUTE_PTR *attributePtr,
748 										IN_ENUM( ATTRIBUTE_ENUM ) \
749 											const ATTRIBUTE_ENUM_TYPE enumType )
750 	{
751 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
752 
753 	assert( isWritePtr( attrEnumInfo, sizeof( ATTRIBUTE_ENUM_INFO ) ) );
754 	assert( attributePtr == NULL || \
755 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
756 
757 	REQUIRES_N( enumType > ATTRIBUTE_ENUM_NONE && \
758 				enumType < ATTRIBUTE_ENUM_LAST );
759 
760 	/* Clear return value */
761 	memset( attrEnumInfo, 0, sizeof( ATTRIBUTE_ENUM_INFO ) );
762 	attrEnumInfo->attributePtr = attributePtr;
763 	attrEnumInfo->enumType = enumType;
764 
765 	if( attributePtr == NULL )
766 		return( NULL );
767 
768 	switch( enumType )
769 		{
770 		case ATTRIBUTE_ENUM_BLOB:
771 			{
772 			int iterationCount;
773 
774 			/* Blob attributes are a special case because they're preceded
775 			   in the attribute list by non-blob attributes so before we try
776 			   and enumerate blob attributes we have to skip any non-blob
777 			   ones that may be present */
778 			for( iterationCount = 0;
779 				 attributeListPtr != NULL && \
780 					!checkAttributeProperty( attributeListPtr,
781 											 ATTRIBUTE_PROPERTY_BLOBATTRIBUTE ) && \
782 					iterationCount < FAILSAFE_ITERATIONS_LARGE;
783 				 attributeListPtr = attributeListPtr->next, iterationCount++ );
784 			ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_LARGE );
785 			attrEnumInfo->attributePtr = attributeListPtr;
786 
787 			/* If there are no blob attributes, we're done */
788 			if( attributeListPtr == NULL )
789 				return( NULL );
790 
791 			break;
792 			}
793 
794 		case ATTRIBUTE_ENUM_NONBLOB:
795 			/* If there are no non-blob attributes, we're done */
796 			if( checkAttributeProperty( attributeListPtr,
797 										ATTRIBUTE_PROPERTY_BLOBATTRIBUTE ) )
798 				{
799 				attrEnumInfo->attributePtr = NULL;
800 				return( NULL );
801 				}
802 			break;
803 
804 		default:
805 			retIntError_Null();
806 		}
807 
808 	return( attrEnumInfo->attributePtr );
809 	}
810 
811 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
getNextAttribute(INOUT ATTRIBUTE_ENUM_INFO * attrEnumInfo)812 const ATTRIBUTE_PTR *getNextAttribute( INOUT ATTRIBUTE_ENUM_INFO *attrEnumInfo )
813 	{
814 	const ATTRIBUTE_LIST *attributeListPtr = attrEnumInfo->attributePtr;
815 
816 	assert( isWritePtr( attrEnumInfo, sizeof( ATTRIBUTE_ENUM_INFO ) ) );
817 	assert( isReadPtr( attributeListPtr, sizeof( ATTRIBUTE_LIST ) ) );
818 
819 	/* Move on to the next attribute in the list */
820 	ENSURES_N( attrEnumInfo->attributePtr != NULL );
821 	attrEnumInfo->attributePtr = \
822 		( ( ATTRIBUTE_LIST * ) attrEnumInfo->attributePtr )->next;
823 	if( attrEnumInfo->attributePtr == NULL )
824 		return( NULL );
825 
826 	switch( attrEnumInfo->enumType )
827 		{
828 		case ATTRIBUTE_ENUM_BLOB:
829 			break;
830 
831 		case ATTRIBUTE_ENUM_NONBLOB:
832 			/* If there are no more non-blob attributes, we're done */
833 			if( checkAttributeProperty( attributeListPtr,
834 										ATTRIBUTE_PROPERTY_BLOBATTRIBUTE ) )
835 				{
836 				attrEnumInfo->attributePtr = NULL;
837 				return( NULL );
838 				}
839 			break;
840 
841 		default:
842 			retIntError_Null();
843 		}
844 
845 	return( attrEnumInfo->attributePtr );
846 	}
847 
848 /* Get attribute data */
849 
850 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getAttributeDataValue(IN const ATTRIBUTE_PTR * attributePtr,OUT_INT_Z int * value)851 int getAttributeDataValue( IN const ATTRIBUTE_PTR *attributePtr,
852 						   OUT_INT_Z int *value )
853 	{
854 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
855 
856 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
857 
858 	REQUIRES( attributeListPtr->fieldType == BER_INTEGER || \
859 			  attributeListPtr->fieldType == BER_ENUMERATED || \
860 			  attributeListPtr->fieldType == BER_BITSTRING || \
861 			  attributeListPtr->fieldType == BER_BOOLEAN || \
862 			  attributeListPtr->fieldType == BER_NULL || \
863 			  attributeListPtr->fieldType == FIELDTYPE_CHOICE || \
864 			  attributeListPtr->fieldType == FIELDTYPE_IDENTIFIER );
865 
866 	*value = attributeListPtr->intValue;
867 
868 	return( CRYPT_OK );
869 	}
870 
871 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getAttributeDataTime(IN const ATTRIBUTE_PTR * attributePtr,OUT time_t * value)872 int getAttributeDataTime( IN const ATTRIBUTE_PTR *attributePtr,
873 						  OUT time_t *value )
874 	{
875 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
876 
877 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
878 
879 	REQUIRES( attributeListPtr->fieldType == BER_TIME_GENERALIZED || \
880 			  attributeListPtr->fieldType == BER_TIME_UTC );
881 
882 	*value = *( ( time_t * ) attributeListPtr->value );
883 
884 	return( CRYPT_OK );
885 	}
886 
887 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
getAttributeDataDN(IN const ATTRIBUTE_PTR * attributePtr,OUT_PTR DN_PTR *** dnPtr)888 int getAttributeDataDN( IN const ATTRIBUTE_PTR *attributePtr,
889 						OUT_PTR DN_PTR ***dnPtr )
890 	{
891 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
892 
893 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
894 
895 	REQUIRES( attributeListPtr->fieldType == FIELDTYPE_DN );
896 
897 	/* See the comment by the definition of SELECTION_INFO in cert.h for the
898 	   reason why we return the address of the pointer rather than the
899 	   pointer itself */
900 	*dnPtr = ( DN_PTR ** ) &attributeListPtr->value;
901 
902 	return( CRYPT_OK );
903 	}
904 
905 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
getAttributeDataPtr(IN const ATTRIBUTE_PTR * attributePtr,OUT_BUFFER_ALLOC (* dataLength)void ** dataPtrPtr,OUT_LENGTH_SHORT_Z int * dataLength)906 int getAttributeDataPtr( IN const ATTRIBUTE_PTR *attributePtr,
907 						 OUT_BUFFER_ALLOC( *dataLength ) void **dataPtrPtr,
908 						 OUT_LENGTH_SHORT_Z int *dataLength )
909 	{
910 	const ATTRIBUTE_LIST *attributeListPtr = attributePtr;
911 
912 	assert( isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
913 
914 	*dataPtrPtr = attributeListPtr->value;
915 	*dataLength = attributeListPtr->valueLength;
916 
917 	return( CRYPT_OK );
918 	}
919 
920 /* The pattern { findAttributeField(), getAttributeDataXXX() } where XXX ==
921    { Value, Time } is used frequently enough that we provide a standard
922    function for it */
923 
924 CHECK_RETVAL STDC_NONNULL_ARG( ( 4 ) ) \
getAttributeFieldValue(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,IN_ATTRIBUTE_OPT const CRYPT_ATTRIBUTE_TYPE subFieldID,OUT_INT_Z int * value)925 int getAttributeFieldValue( IN_OPT const ATTRIBUTE_PTR *attributePtr,
926 							IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,
927 							IN_ATTRIBUTE_OPT \
928 								const CRYPT_ATTRIBUTE_TYPE subFieldID,
929 							OUT_INT_Z int *value )
930 	{
931 	const ATTRIBUTE_LIST *attributeListPtr;
932 
933 	assert( attributePtr == NULL || \
934 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
935 
936 	REQUIRES( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
937 			  fieldID <= CRYPT_CERTINFO_LAST );
938 	REQUIRES( subFieldID == CRYPT_ATTRIBUTE_NONE || \
939 			  ( subFieldID >= CRYPT_CERTINFO_FIRST_NAME && \
940 				subFieldID <= CRYPT_CERTINFO_LAST_GENERALNAME ) );
941 
942 	/* Clear return value */
943 	*value = 0;
944 
945 	/* Find the required attribute field and return its value */
946 	attributeListPtr = findAttributeField( attributePtr, fieldID,
947 										   subFieldID );
948 	if( attributeListPtr == NULL )
949 		return( CRYPT_ERROR_NOTFOUND );
950 	return( getAttributeDataValue( attributeListPtr, value ) );
951 	}
952 
953 CHECK_RETVAL STDC_NONNULL_ARG( ( 4 ) ) \
getAttributeFieldTime(IN_OPT const ATTRIBUTE_PTR * attributePtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,IN_ATTRIBUTE_OPT const CRYPT_ATTRIBUTE_TYPE subFieldID,OUT time_t * value)954 int getAttributeFieldTime( IN_OPT const ATTRIBUTE_PTR *attributePtr,
955 						   IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,
956 						   IN_ATTRIBUTE_OPT \
957 								const CRYPT_ATTRIBUTE_TYPE subFieldID,
958 						   OUT time_t *value )
959 	{
960 	const ATTRIBUTE_LIST *attributeListPtr;
961 
962 	assert( attributePtr == NULL || \
963 			isReadPtr( attributePtr, sizeof( ATTRIBUTE_LIST ) ) );
964 
965 	REQUIRES( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
966 			  fieldID <= CRYPT_CERTINFO_LAST );
967 	REQUIRES( subFieldID == CRYPT_ATTRIBUTE_NONE || \
968 			  ( subFieldID >= CRYPT_CERTINFO_FIRST_NAME && \
969 				subFieldID <= CRYPT_CERTINFO_LAST_GENERALNAME ) );
970 
971 	/* Clear return value */
972 	*value = 0;
973 
974 	/* Find the required attribute field and return its value */
975 	attributeListPtr = findAttributeField( attributePtr, fieldID,
976 										   subFieldID );
977 	if( attributeListPtr == NULL )
978 		return( CRYPT_ERROR_NOTFOUND );
979 	return( getAttributeDataTime( attributeListPtr, value ) );
980 	}
981 
982 /* Get the default value for an optional field of an attribute */
983 
984 CHECK_RETVAL \
getDefaultFieldValue(IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID)985 int getDefaultFieldValue( IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID )
986 	{
987 	const ATTRIBUTE_INFO *attributeInfoPtr;
988 
989 	REQUIRES( fieldID >= CRYPT_CERTINFO_FIRST_EXTENSION && \
990 			  fieldID <= CRYPT_CERTINFO_LAST );
991 
992 	attributeInfoPtr = \
993 		fieldIDToAttribute( ( fieldID >= CRYPT_CERTINFO_FIRST_CMS ) ? \
994 							ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE, fieldID,
995 							CRYPT_ATTRIBUTE_NONE, NULL );
996 	ENSURES( attributeInfoPtr != NULL );
997 
998 	return( ( int ) attributeInfoPtr->defaultValue );
999 	}
1000 
1001 /****************************************************************************
1002 *																			*
1003 *							Attribute Compare Routines						*
1004 *																			*
1005 ****************************************************************************/
1006 
1007 /* Compare attribute fields */
1008 
1009 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
compareAttributeField(const ATTRIBUTE_LIST * attributeField1,const ATTRIBUTE_LIST * attributeField2)1010 static BOOLEAN compareAttributeField( const ATTRIBUTE_LIST *attributeField1,
1011 									  const ATTRIBUTE_LIST *attributeField2 )
1012 	{
1013 	assert( isReadPtr( attributeField1, sizeof( ATTRIBUTE_LIST ) ) );
1014 	assert( isReadPtr( attributeField2, sizeof( ATTRIBUTE_LIST ) ) );
1015 
1016 	REQUIRES_B( attributeField1->attributeID == attributeField2->attributeID );
1017 
1018 	/* Compare attribute IDs */
1019 	if( attributeField1->fieldID != attributeField2->fieldID || \
1020 		attributeField1->subFieldID != attributeField2->subFieldID )
1021 		return( FALSE );
1022 
1023 	/* Compare the field type and any relevant attribute flags */
1024 	if( attributeField1->fieldType != attributeField2->fieldType )
1025 		return( FALSE );
1026 	if( ( attributeField1->flags & ATTR_FLAGS_COMPARE_MASK ) != \
1027 				( attributeField2->flags & ATTR_FLAGS_COMPARE_MASK ) )
1028 		return( FALSE );
1029 
1030 	/* Compare field data */
1031 	if( attributeField1->fieldType == FIELDTYPE_DN )
1032 		{
1033 		/* DNs are structured data and need to be compared specially */
1034 		return( compareDN( attributeField1->value, attributeField2->value,
1035 						   FALSE, NULL ) );
1036 		}
1037 	if( attributeField1->intValue != attributeField2->intValue || \
1038 		attributeField1->valueLength != attributeField2->valueLength )
1039 		return( FALSE );
1040 	if( attributeField1->valueLength > 0 )
1041 		{
1042 		if( memcmp( attributeField1->value, attributeField2->value,
1043 					attributeField1->valueLength ) )
1044 			return( FALSE );
1045 		}
1046 
1047 	return( TRUE );
1048 	}
1049 
1050 /* Compare attributes */
1051 
1052 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1, 2 ) ) \
compareAttribute(const ATTRIBUTE_PTR * attribute1,const ATTRIBUTE_PTR * attribute2)1053 BOOLEAN compareAttribute( const ATTRIBUTE_PTR *attribute1,
1054 						  const ATTRIBUTE_PTR *attribute2 )
1055 	{
1056 	const ATTRIBUTE_LIST *attributeListPtr1 = ( ATTRIBUTE_LIST * ) attribute1;
1057 	const ATTRIBUTE_LIST *attributeListPtr2 = ( ATTRIBUTE_LIST * ) attribute2;
1058 	const CRYPT_ATTRIBUTE_TYPE attributeID = attributeListPtr1->attributeID;
1059 	int iterationCount;
1060 
1061 	assert( isReadPtr( attributeListPtr1, sizeof( ATTRIBUTE_LIST ) ) );
1062 	assert( isReadPtr( attributeListPtr2, sizeof( ATTRIBUTE_LIST ) ) );
1063 
1064 	REQUIRES_B( attributeListPtr1->attributeID == \
1065 										attributeListPtr2->attributeID );
1066 
1067 	/* Compare all of the fields in the attributes */
1068 	for( iterationCount = 0;
1069 		 attributeListPtr1 != NULL && attributeListPtr2 != NULL && \
1070 			attributeListPtr1->attributeID == attributeID && \
1071 			attributeListPtr2->attributeID == attributeID && \
1072 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
1073 		 attributeListPtr1 = attributeListPtr1->next, \
1074 			attributeListPtr2 = attributeListPtr2->next, \
1075 			iterationCount++ )
1076 		{
1077 		if( !compareAttributeField( attributeListPtr1, attributeListPtr2 ) )
1078 			return( FALSE );
1079 		}
1080 	ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1081 
1082 	/* We've reached the loop termination condition, if it was because
1083 	   either of the two attribute lists terminated make sure that it was
1084 	   at the end of the attribute being compared */
1085 	if( attributeListPtr1 == NULL || attributeListPtr2 == NULL )
1086 		{
1087 		/* One (or both) of the lists terminated, make sure that the
1088 		   attribute doesn't continue in the other */
1089 		if( attributeListPtr1 == NULL )
1090 			{
1091 			/* The first attribute list terminated, make sure that the
1092 			   attribute doesn't continue in the second list */
1093 			if( attributeListPtr2 != NULL && \
1094 				attributeListPtr2->attributeID == attributeID )
1095 				return( FALSE );
1096 			}
1097 		else
1098 			{
1099 			/* The second attribute list terminated, make sure that the
1100 			   attribute doesn't continue in the first list */
1101 			if( attributeListPtr1->attributeID == attributeID )
1102 				return( FALSE );
1103 			}
1104 
1105 		/* Both attribute lists terminated at the same point */
1106 		return( TRUE );
1107 		}
1108 
1109 	/* There are more attributes in the list, make sure that the current
1110 	   attribute ended at the same point in both lists */
1111 	if( attributeListPtr1->attributeID == attributeID || \
1112 		attributeListPtr2->attributeID == attributeID )
1113 		return( FALSE );
1114 
1115 	return( TRUE );
1116 	}
1117 
1118 /****************************************************************************
1119 *																			*
1120 *						Miscellaneous Attribute Routines					*
1121 *																			*
1122 ****************************************************************************/
1123 
1124 /* Fix up certificate attributes, mapping from incorrect values to standards-
1125    compliant ones */
1126 
1127 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
fixAttributes(INOUT CERT_INFO * certInfoPtr)1128 int fixAttributes( INOUT CERT_INFO *certInfoPtr )
1129 	{
1130 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
1131 	int complianceLevel;
1132 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
1133 	int status;
1134 
1135 	assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1136 
1137 	/* Try and locate email addresses wherever they might be stashed and move
1138 	   them to the certificate altNames */
1139 	status = convertEmail( certInfoPtr, &certInfoPtr->subjectName,
1140 						   CRYPT_CERTINFO_SUBJECTALTNAME );
1141 	if( cryptStatusOK( status ) )
1142 		status = convertEmail( certInfoPtr, &certInfoPtr->issuerName,
1143 							   CRYPT_CERTINFO_ISSUERALTNAME );
1144 	if( cryptStatusError( status ) )
1145 		return( status );
1146 
1147 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
1148 	/* If we're running at a compliance level of
1149 	   CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL or above don't try and compensate
1150 	   for dubious attributes */
1151 	status = krnlSendMessage( certInfoPtr->ownerHandle,
1152 							  IMESSAGE_GETATTRIBUTE, &complianceLevel,
1153 							  CRYPT_OPTION_CERT_COMPLIANCELEVEL );
1154 	if( cryptStatusError( status ) )
1155 		return( status );
1156 	if( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
1157 		return( CRYPT_OK );
1158 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
1159 
1160 	/* If the only key usage information present is the Netscape one,
1161 	   convert it into the X.509 equivalent */
1162 	if( !checkAttributePresent( certInfoPtr->attributes,
1163 								CRYPT_CERTINFO_KEYUSAGE ) && \
1164 		findAttributeField( certInfoPtr->attributes,
1165 							CRYPT_CERTINFO_NS_CERTTYPE,
1166 							CRYPT_ATTRIBUTE_NONE ) != NULL )
1167 		{
1168 		int keyUsage;
1169 
1170 		status = getKeyUsageFromExtKeyUsage( certInfoPtr, &keyUsage,
1171 											 &certInfoPtr->errorLocus,
1172 											 &certInfoPtr->errorType );
1173 		if( cryptStatusOK( status ) )
1174 			{
1175 			status = addAttributeField( &certInfoPtr->attributes,
1176 										CRYPT_CERTINFO_KEYUSAGE,
1177 										CRYPT_ATTRIBUTE_NONE, keyUsage,
1178 										ATTR_FLAG_NONE,
1179 										&certInfoPtr->errorLocus,
1180 										&certInfoPtr->errorType );
1181 			}
1182 		if( cryptStatusError( status ) )
1183 			return( status );
1184 		}
1185 
1186 	return( CRYPT_OK );
1187 	}
1188 #endif /* USE_CERTIFICATES */
1189