1 /****************************************************************************
2 *																			*
3 *						Certificate Attribute Copy 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 /* When replicating attributes from one type of certificate object to
17    another (for example from an issuer certificate to a subject certificate
18    when issuing a new certificate) we may have to adjust the attribute
19    information based on the source and destination object roles.  The
20    following values denote the different copy types that we have to handle.
21    Usually this is a direct copy, however if we're copying from subject to
22    issuer we have to adjust attribute IDs such as the altName
23    (subjectAltName -> issuerAltName), if we're copying from issuer to
24    subject we have to adjust path length-based contraints since the new
25    subject is one further down the chain than the issuer */
26 
27 typedef enum {
28 	COPY_NONE,				/* No copy type */
29 	COPY_DIRECT,			/* Direct attribute copy */
30 	COPY_SUBJECT_TO_ISSUER,	/* Copy of subject attributes to issuer cert */
31 	COPY_ISSUER_TO_SUBJECT,	/* Copy of issuer attributes to subject cert */
32 	COPY_LAST				/* Last valid copy type */
33 	} COPY_TYPE;
34 
35 #ifdef USE_CERTIFICATES
36 
37 /****************************************************************************
38 *																			*
39 *								Utility Functions							*
40 *																			*
41 ****************************************************************************/
42 
43 /* Copy an attribute field */
44 
45 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyAttributeField(OUT_PTR_COND ATTRIBUTE_LIST ** destAttributeField,const ATTRIBUTE_LIST * srcAttributeField)46 static int copyAttributeField( OUT_PTR_COND ATTRIBUTE_LIST **destAttributeField,
47 							   const ATTRIBUTE_LIST *srcAttributeField )
48 	{
49 	ATTRIBUTE_LIST *newElement;
50 	int status = CRYPT_OK;
51 
52 	assert( isWritePtr( destAttributeField, sizeof( ATTRIBUTE_LIST * ) ) );
53 	assert( isReadPtr( srcAttributeField, sizeof( ATTRIBUTE_LIST ) ) );
54 
55 	/* Allocate memory for the new element and copy the information across */
56 	*destAttributeField = NULL;
57 	if( ( newElement = ( ATTRIBUTE_LIST * ) \
58 					   clAlloc( "copyAttributeField", \
59 								sizeofVarStruct( srcAttributeField, \
60 												 ATTRIBUTE_LIST ) ) ) == NULL )
61 		return( CRYPT_ERROR_MEMORY );
62 	copyVarStruct( newElement, srcAttributeField, ATTRIBUTE_LIST );
63 	if( srcAttributeField->fieldType == FIELDTYPE_DN )
64 		{
65 		/* If the field contains a DN, copy that across as well */
66 		status = copyDN( ( DN_PTR ** ) &newElement->value,
67 						 srcAttributeField->value );
68 		if( cryptStatusError( status ) )
69 			{
70 			endVarStruct( newElement, ATTRIBUTE_LIST );
71 			clFree( "copyAttributeField", newElement );
72 			return( status );
73 			}
74 		}
75 	newElement->next = newElement->prev = NULL;
76 	*destAttributeField = newElement;
77 
78 	return( CRYPT_OK );
79 	}
80 
81 /* Copy an attribute from one attribute list to another */
82 
83 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyAttribute(INOUT_PTR ATTRIBUTE_LIST ** destListHeadPtr,const ATTRIBUTE_LIST * srcListPtr,IN_ENUM (COPY)const COPY_TYPE copyType)84 static int copyAttribute( INOUT_PTR ATTRIBUTE_LIST **destListHeadPtr,
85 						  const ATTRIBUTE_LIST *srcListPtr,
86 						  IN_ENUM( COPY ) const COPY_TYPE copyType )
87 	{
88 	const CRYPT_ATTRIBUTE_TYPE attributeID = srcListPtr->attributeID;
89 	CRYPT_ATTRIBUTE_TYPE newAttributeID = attributeID;
90 	ATTRIBUTE_LIST *newAttributeListHead = NULL;
91 	ATTRIBUTE_LIST *newAttributeListTail DUMMY_INIT_PTR;
92 	ATTRIBUTE_LIST *insertPoint, *prevElement = NULL;
93 	int iterationCount;
94 
95 	assert( isWritePtr( destListHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
96 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
97 
98 	REQUIRES( copyType > COPY_NONE && copyType < COPY_LAST );
99 
100 	/* If we're re-mapping the destination attribute ID (see the comment
101 	   further down) we have to insert it at a point corresponding to the
102 	   re-mapped ID, not the original ID, to maintain the list's sorted
103 	   property.  The CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER is only
104 	   copied at CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL or above so we'll never
105 	   see this attribute copied at lower compliance levels (this is
106 	   enforced in the caller) */
107 	if( copyType == COPY_SUBJECT_TO_ISSUER )
108 		{
109 		if( attributeID == CRYPT_CERTINFO_SUBJECTALTNAME )
110 			newAttributeID = CRYPT_CERTINFO_ISSUERALTNAME;
111 		if( attributeID == CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER )
112 			newAttributeID = CRYPT_CERTINFO_AUTHORITYKEYIDENTIFIER;
113 		}
114 
115 	/* Find the location at which to insert this attribute (this assumes
116 	   that the fieldIDs are defined in sorted order) */
117 	for( insertPoint = *destListHeadPtr, iterationCount = 0;
118 		 insertPoint != NULL && \
119 			insertPoint->attributeID < newAttributeID && \
120 			insertPoint->fieldID != CRYPT_ATTRIBUTE_NONE && \
121 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
122 		 insertPoint = insertPoint->next, iterationCount++ )
123 		{
124 		prevElement = insertPoint;
125 		}
126 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
127 	insertPoint = prevElement;
128 
129 	/* Build a new attribute list containing the attribute fields */
130 	for( iterationCount = 0;
131 		 srcListPtr != NULL && srcListPtr->attributeID == attributeID && \
132 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
133 		 iterationCount++ )
134 		{
135 		ATTRIBUTE_LIST *newAttributeField;
136 		int status;
137 
138 		/* Copy the field across */
139 		status = copyAttributeField( &newAttributeField, srcListPtr );
140 		if( cryptStatusError( status ) )
141 			{
142 			if( newAttributeListHead != NULL )
143 				{
144 				deleteAttributes( ( ATTRIBUTE_PTR ** ) \
145 											&newAttributeListHead );
146 				}
147 			return( status );
148 			}
149 
150 		/* If we're copying from an issuer to a subject attribute list and
151 		   the field is an altName or keyIdentifier, change the field type
152 		   from issuer.subjectAltName to subject.issuerAltName or
153 		   issuer.subjectKeyIdentifier to subject.authorityKeyIdentifier */
154 		if( copyType == COPY_SUBJECT_TO_ISSUER )
155 			{
156 			if( attributeID == CRYPT_CERTINFO_SUBJECTALTNAME )
157 				{
158 				newAttributeField->attributeID = \
159 					newAttributeField->fieldID = \
160 						CRYPT_CERTINFO_ISSUERALTNAME;
161 				}
162 			if( attributeID == CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER )
163 				{
164 				newAttributeField->attributeID = \
165 						CRYPT_CERTINFO_AUTHORITYKEYIDENTIFIER;
166 				newAttributeField->fieldID = \
167 						CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER;
168 				}
169 			}
170 
171 		/* If we're copying from a subject to an issuer attribute list and
172 		   it's a path length-based constraint, adjust the constraint value
173 		   by one since we're now one further down the chain */
174 		if( copyType == COPY_ISSUER_TO_SUBJECT && \
175 			( newAttributeField->fieldID == \
176 							CRYPT_CERTINFO_PATHLENCONSTRAINT || \
177 			  newAttributeField->fieldID == \
178 							CRYPT_CERTINFO_REQUIREEXPLICITPOLICY || \
179 			  newAttributeField->fieldID == \
180 							CRYPT_CERTINFO_INHIBITPOLICYMAPPING ) )
181 			{
182 			/* If we're already at a path length of zero we can't reduce it
183 			   any further, the best that we can do is to not copy the
184 			   attribute */
185 			if( newAttributeField->intValue <= 0 )
186 				{
187 				deleteAttributeField( ( ATTRIBUTE_PTR ** ) &newAttributeField,
188 									  NULL, newAttributeField, NULL );
189 				}
190 			else
191 				newAttributeField->intValue--;
192 			}
193 
194 		/* Append the new field to the new attribute list */
195 		insertDoubleListElement( &newAttributeListHead, newAttributeListTail,
196 								 newAttributeField );
197 		newAttributeListTail = newAttributeField;
198 
199 		/* Move on to the next field */
200 		srcListPtr = srcListPtr->next;
201 		}
202 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
203 	ENSURES( newAttributeListHead != NULL );
204 
205 	/* Link the new list into the existing list at the appropriate position */
206 	insertDoubleListElements( destListHeadPtr, insertPoint,
207 							  newAttributeListHead, newAttributeListTail );
208 
209 	return( CRYPT_OK );
210 	}
211 
212 /* Copy a length constraint from an issuer CA certificate to a subject CA
213    certificate, decrementing the value by one */
214 
215 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
copyLengthConstraint(INOUT ATTRIBUTE_LIST ** destListHeadPtr,const ATTRIBUTE_LIST * srcListPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,OUT_ENUM_OPT (CRYPT_ATTRIBUTE)CRYPT_ATTRIBUTE_TYPE * errorLocus)216 static int copyLengthConstraint( INOUT ATTRIBUTE_LIST **destListHeadPtr,
217 								 const ATTRIBUTE_LIST *srcListPtr,
218 								 IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE fieldID,
219 								 OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
220 									CRYPT_ATTRIBUTE_TYPE *errorLocus )
221 
222 	{
223 	ATTRIBUTE_LIST *destListPtr;
224 	int status;
225 
226 	assert( isWritePtr( destListHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
227 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
228 	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
229 
230 	REQUIRES( fieldID > CRYPT_ATTRIBUTE_NONE && \
231 			  fieldID < CRYPT_ATTRIBUTE_LAST );
232 
233 	/* Clear return value */
234 	*errorLocus = CRYPT_ATTRIBUTE_NONE;
235 
236 	/* If there's nothing to copy, we're done */
237 	srcListPtr = findAttributeField( srcListPtr, fieldID,
238 									 CRYPT_ATTRIBUTE_NONE );
239 	if( srcListPtr == NULL )
240 		return( CRYPT_OK );
241 
242 	/* There's a length constraint present, if the value is already at zero
243 	   then the next certificate must be an EE certificate rather than a
244 	   CA certificate */
245 	if( srcListPtr->intValue <= 0 )
246 		{
247 		*errorLocus = fieldID;
248 		return( CRYPT_ERROR_INVALID );
249 		}
250 
251 	/* There's something to copy, if it's not already present in the
252 	   destination just copy it across */
253 	destListPtr = findAttributeField( *destListHeadPtr, fieldID,
254 									  CRYPT_ATTRIBUTE_NONE );
255 	if( destListPtr == NULL )
256 		{
257 		status = copyAttributeField( destListHeadPtr, srcListPtr );
258 		if( cryptStatusError( status ) )
259 			return( status );
260 		destListPtr = findAttributeField( *destListHeadPtr, fieldID,
261 										  CRYPT_ATTRIBUTE_NONE );
262 		ENSURES( destListPtr != NULL && destListPtr->intValue > 0 );
263 		destListPtr->intValue--;
264 
265 		return( CRYPT_OK );
266 		}
267 
268 	/* The same constraint exists in source and destination, set the result
269 	   value to the lesser of the two, with the necessary decrement applied */
270 	if( srcListPtr->intValue <= destListPtr->intValue )
271 		destListPtr->intValue = srcListPtr->intValue - 1;
272 	ENSURES( destListPtr->intValue >= 0 );
273 
274 	return( CRYPT_OK );
275 	}
276 
277 /****************************************************************************
278 *																			*
279 *							Copy a Complete Attribute List					*
280 *																			*
281 ****************************************************************************/
282 
283 /* Copy a complete attribute list */
284 
285 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
copyAttributes(INOUT ATTRIBUTE_PTR ** destHeadPtr,const ATTRIBUTE_PTR * srcPtr,OUT_ENUM_OPT (CRYPT_ATTRIBUTE)CRYPT_ATTRIBUTE_TYPE * errorLocus,OUT_ENUM_OPT (CRYPT_ERRTYPE)CRYPT_ERRTYPE_TYPE * errorType)286 int copyAttributes( INOUT ATTRIBUTE_PTR **destHeadPtr,
287 					const ATTRIBUTE_PTR *srcPtr,
288 					OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
289 						CRYPT_ATTRIBUTE_TYPE *errorLocus,
290 					OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
291 						CRYPT_ERRTYPE_TYPE *errorType )
292 	{
293 	const ATTRIBUTE_LIST *srcListPtr = ( ATTRIBUTE_LIST * ) srcPtr;
294 	int iterationCount;
295 
296 	assert( isWritePtr( destHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
297 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
298 	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
299 	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
300 
301 	/* Clear return values */
302 	*errorLocus = CRYPT_ATTRIBUTE_NONE;
303 	*errorType = CRYPT_ERRTYPE_NONE;
304 
305 	/* If there are destination attributes present make a first pass down
306 	   the list checking that the attribute to copy isn't already present in
307 	   the destination attributes, first for recognised attributes and then
308 	   for unrecognised ones.  We have to do this separately since once we
309 	   begin the copy process it's rather hard to undo it.  There are two
310 	   special cases that we could in theory allow:
311 
312 		1. Some composite attributes could have non-overlapping fields in
313 		   the source and destination.
314 
315 		2. Some attributes can have multiple instances of a field present.
316 
317 	   This means that we could allow them to appear in both the source and
318 	   destination lists, however if this occurs it's more likely to be an
319 	   error than a desire to merge two disparate collections of fields or
320 	   attributes so we report them as (disallowed) duplicates */
321 	if( *destHeadPtr != NULL )
322 		{
323 		const ATTRIBUTE_LIST *attributeListCursor;
324 
325 		/* Check the non-blob attributes */
326 		for( attributeListCursor = srcListPtr, iterationCount = 0;
327 			 attributeListCursor != NULL && \
328 				!checkAttributeProperty( attributeListCursor,
329 										 ATTRIBUTE_PROPERTY_BLOBATTRIBUTE ) && \
330 				iterationCount < FAILSAFE_ITERATIONS_LARGE;
331 			 attributeListCursor = attributeListCursor->next, iterationCount++ )
332 			{
333 			ENSURES( attributeListCursor->next == NULL || \
334 					 !isValidAttributeField( attributeListCursor->next ) || \
335 					 attributeListCursor->attributeID <= \
336 							attributeListCursor->next->attributeID );
337 			if( findAttributeField( *destHeadPtr,
338 									attributeListCursor->fieldID,
339 									CRYPT_ATTRIBUTE_NONE ) != NULL )
340 				{
341 				*errorLocus = attributeListCursor->fieldID;
342 				*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
343 				return( CRYPT_ERROR_DUPLICATE );
344 				}
345 			}
346 		ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
347 
348 		/* Check the blob attributes */
349 		for( ; attributeListCursor != NULL && \
350 			   iterationCount < FAILSAFE_ITERATIONS_LARGE;
351 			 attributeListCursor = attributeListCursor->next, iterationCount++ )
352 			{
353 			ENSURES( checkAttributeProperty( attributeListCursor,
354 											 ATTRIBUTE_PROPERTY_BLOBATTRIBUTE ) );
355 			if( findAttributeByOID( *destHeadPtr,
356 									attributeListCursor->oid,
357 									sizeofOID( attributeListCursor->oid ) ) != NULL )
358 				{
359 				/* We can't set the locus for blob-type attributes since
360 				   it's not a known attribute */
361 				*errorLocus = CRYPT_ATTRIBUTE_NONE;
362 				*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
363 				return( CRYPT_ERROR_DUPLICATE );
364 				}
365 			}
366 		ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
367 		}
368 
369 	/* Make a second pass copying everything across, first the non-blob
370 	   attributes */
371 	for( iterationCount = 0;
372 		 srcListPtr != NULL && \
373 			!checkAttributeProperty( srcListPtr,
374 									 ATTRIBUTE_PROPERTY_BLOBATTRIBUTE ) && \
375 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
376 		 iterationCount++ )
377 		{
378 		CRYPT_ATTRIBUTE_TYPE attributeID = srcListPtr->attributeID;
379 		const ATTRIBUTE_INFO *attributeInfoPtr;
380 		int status;
381 
382 		/* Get the attribute information for the attribute to be copied */
383 		if( srcListPtr->attributeInfoPtr != NULL )
384 			attributeInfoPtr = srcListPtr->attributeInfoPtr;
385 		else
386 			{
387 			attributeInfoPtr = \
388 				fieldIDToAttribute( ( attributeID >= CRYPT_CERTINFO_FIRST_CMS ) ? \
389 										ATTRIBUTE_CMS : ATTRIBUTE_CERTIFICATE,
390 									attributeID, CRYPT_ATTRIBUTE_NONE, NULL );
391 			}
392 		ENSURES( attributeInfoPtr != NULL );
393 
394 		assert( isReadPtr( attributeInfoPtr, sizeof( ATTRIBUTE_INFO ) ) );
395 
396 		/* Copy the complete attribute across unless it's one that we
397 		   explicitly don't propagate from source to destination */
398 		if( !( attributeInfoPtr->typeInfoFlags & FL_ATTR_NOCOPY ) )
399 			{
400 			status = copyAttribute( ( ATTRIBUTE_LIST ** ) destHeadPtr,
401 									srcListPtr, COPY_DIRECT );
402 			if( cryptStatusError( status ) )
403 				return( status );
404 			}
405 
406 		/* Move on to the next attribute.  We retain the loop bounds-check
407 		   value from the outer loop to bound it at n rather than 2*n */
408 		for( ;
409 			 srcListPtr != NULL && \
410 				srcListPtr->attributeID == attributeID && \
411 				iterationCount < FAILSAFE_ITERATIONS_LARGE;
412 			 srcListPtr = srcListPtr->next, iterationCount++ );
413 		}
414 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
415 
416 	/* If there are blob-type attributes left at the end of the list, copy
417 	   them across last */
418 	if( srcListPtr != NULL )
419 		{
420 		ATTRIBUTE_LIST *insertPoint;
421 
422 		/* Find the end of the destination list */
423 		for( insertPoint = *destHeadPtr, iterationCount = 0;
424 			 insertPoint != NULL && insertPoint->next != NULL && \
425 				iterationCount < FAILSAFE_ITERATIONS_LARGE;
426 			 insertPoint = insertPoint->next, iterationCount++ );
427 		ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
428 
429 		/* Copy all remaining attributes across */
430 		for( ; srcListPtr != NULL && \
431 			   iterationCount < FAILSAFE_ITERATIONS_LARGE;
432 			srcListPtr = srcListPtr->next, iterationCount++ )
433 			{
434 			ATTRIBUTE_LIST *newAttribute;
435 			int status;
436 
437 			status = copyAttributeField( &newAttribute, srcListPtr );
438 			if( cryptStatusError( status ) )
439 				return( status );
440 			insertDoubleListElement( ( ATTRIBUTE_LIST ** ) destHeadPtr,
441 									 insertPoint, newAttribute );
442 
443 			}
444 		ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
445 		}
446 
447 	return( CRYPT_OK );
448 	}
449 
450 /****************************************************************************
451 *																			*
452 *							Copy Specific Attributes						*
453 *																			*
454 ****************************************************************************/
455 
456 /* Copy attributes that are propagated down certificate chains from an
457    issuer to a subject certificate, changing the field types from subject
458    to issuer and adjusting constraint values at the same time if required */
459 
460 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
copyIssuerAttributes(INOUT ATTRIBUTE_PTR ** destListHeadPtr,const ATTRIBUTE_PTR * srcListPtr,const CRYPT_CERTTYPE_TYPE type,OUT_ENUM_OPT (CRYPT_ATTRIBUTE)CRYPT_ATTRIBUTE_TYPE * errorLocus,OUT_ENUM_OPT (CRYPT_ERRTYPE)CRYPT_ERRTYPE_TYPE * errorType)461 int copyIssuerAttributes( INOUT ATTRIBUTE_PTR **destListHeadPtr,
462 						  const ATTRIBUTE_PTR *srcListPtr,
463 						  const CRYPT_CERTTYPE_TYPE type,
464 						  OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
465 							CRYPT_ATTRIBUTE_TYPE *errorLocus,
466 						  OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
467 							CRYPT_ERRTYPE_TYPE *errorType )
468 	{
469 	ATTRIBUTE_LIST *attributeListPtr;
470 	int status = CRYPT_OK;
471 
472 	assert( isWritePtr( destListHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
473 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
474 	assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
475 	assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
476 
477 	REQUIRES( type > CRYPT_CERTTYPE_NONE && type < CRYPT_CERTTYPE_LAST );
478 
479 	/* Clear return values */
480 	*errorLocus = CRYPT_ATTRIBUTE_NONE;
481 	*errorType = CRYPT_ERRTYPE_NONE;
482 
483 	/* If the destination is a CA certificate and the source has constraint
484 	   extensions, copy them over to the destination.  The reason why we
485 	   copy the constraints even though they're already present in the
486 	   source is to ensure that they're still present in a certificate chain
487 	   even if the parent isn't available.  This can occur for example when
488 	   a chain-internal certificate is marked as implicitly trusted and the
489 	   chain is only available up to the implicitly-trusted certificate with
490 	   the contraint-imposing parent not present */
491 	attributeListPtr = findAttributeField( *destListHeadPtr,
492 										   CRYPT_CERTINFO_CA,
493 										   CRYPT_ATTRIBUTE_NONE );
494 	if( attributeListPtr != NULL && attributeListPtr->intValue > 0 )
495 		{
496 #ifdef USE_CERTLEVEL_PKIX_FULL
497 		ATTRIBUTE_LIST *srcPermittedSubtrees, *srcExcludedSubtrees;
498 
499 		srcPermittedSubtrees = findAttributeField( srcListPtr,
500 												   CRYPT_CERTINFO_PERMITTEDSUBTREES,
501 												   CRYPT_ATTRIBUTE_NONE );
502 		srcExcludedSubtrees = findAttributeField( srcListPtr,
503 												  CRYPT_CERTINFO_EXCLUDEDSUBTREES,
504 												  CRYPT_ATTRIBUTE_NONE );
505 
506 		/* If we're copying permitted or excluded subtrees they can't
507 		   already be present.  We check the two separately rather than just
508 		   checking for the overall presence of name constraints since in
509 		   theory it's possible to merge permitted and excluded constraints,
510 		   so that permitted constraints in the destination don't clash with
511 		   excluded constraints in the source (yet another one of X.509's
512 		   semantic holes) */
513 		if( srcPermittedSubtrees != NULL && \
514 			findAttributeField( *destListHeadPtr, \
515 								CRYPT_CERTINFO_PERMITTEDSUBTREES,
516 								CRYPT_ATTRIBUTE_NONE ) != NULL )
517 			{
518 			*errorLocus = CRYPT_CERTINFO_PERMITTEDSUBTREES;
519 			*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
520 			return( CRYPT_ERROR_DUPLICATE );
521 			}
522 		if( srcExcludedSubtrees != NULL && \
523 			findAttributeField( *destListHeadPtr, \
524 								CRYPT_CERTINFO_EXCLUDEDSUBTREES,
525 								CRYPT_ATTRIBUTE_NONE ) != NULL )
526 			{
527 			*errorLocus = CRYPT_CERTINFO_EXCLUDEDSUBTREES;
528 			*errorType = CRYPT_ERRTYPE_ATTR_PRESENT;
529 			return( CRYPT_ERROR_DUPLICATE );
530 			}
531 
532 		/* Copy the fields across */
533 		if( srcPermittedSubtrees != NULL )
534 			{
535 			status = copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
536 									srcPermittedSubtrees,
537 									COPY_SUBJECT_TO_ISSUER );
538 			if( cryptStatusError( status ) )
539 				return( status );
540 			}
541 		if( srcExcludedSubtrees != NULL )
542 			{
543 			status = copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
544 									srcExcludedSubtrees,
545 									COPY_SUBJECT_TO_ISSUER );
546 			if( cryptStatusError( status ) )
547 				return( status );
548 			}
549 
550 		/* The path-length constraints are a bit easier to handle, if
551 		   they're already present we just use the smaller of the two */
552 		status = copyLengthConstraint( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
553 									   srcListPtr,
554 									   CRYPT_CERTINFO_REQUIREEXPLICITPOLICY,
555 									   errorLocus );
556 		if( cryptStatusOK( status ) )
557 			status = copyLengthConstraint( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
558 										   srcListPtr,
559 										   CRYPT_CERTINFO_INHIBITPOLICYMAPPING,
560 										   errorLocus );
561 		if( cryptStatusError( status ) )
562 			{
563 			*errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
564 			return( status );
565 			}
566 #endif /* USE_CERTLEVEL_PKIX_FULL */
567 
568 		/* Finally, copy the CA basic constraints across */
569 		status = copyLengthConstraint( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
570 									   srcListPtr,
571 									   CRYPT_CERTINFO_PATHLENCONSTRAINT,
572 									   errorLocus );
573 		if( cryptStatusError( status ) )
574 			{
575 			*errorType = CRYPT_ERRTYPE_ISSUERCONSTRAINT;
576 			return( status );
577 			}
578 		}
579 
580 	/* If it's an attribute certificate, that's all that we can copy */
581 	if( type == CRYPT_CERTTYPE_ATTRIBUTE_CERT )
582 		return( CRYPT_OK );
583 
584 	/* Copy the altName and keyIdentifier if these are present.  We don't
585 	   have to check for their presence in the destination certificate since
586 	   they're read-only fields and can't be added by the user.  The
587 	   CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER becomes the
588 	   CRYPT_CERTINFO_AUTHORITYKEYIDENTIFIER when copied from the issuer to
589 	   the subject so we only copy it at a compliance level of
590 	   CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL or above, since it's not enforced
591 	   below that level */
592 	attributeListPtr = findAttribute( srcListPtr,
593 									  CRYPT_CERTINFO_SUBJECTALTNAME,
594 									  TRUE );
595 	if( attributeListPtr != NULL )
596 		{
597 		status = copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
598 								attributeListPtr, COPY_SUBJECT_TO_ISSUER );
599 		if( cryptStatusError( status ) )
600 			return( status );
601 		}
602 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
603 	attributeListPtr = findAttribute( srcListPtr,
604 									  CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER,
605 									  TRUE );
606 	if( attributeListPtr != NULL )
607 		{
608 		status = copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
609 								attributeListPtr, COPY_SUBJECT_TO_ISSUER );
610 		if( cryptStatusError( status ) )
611 			return( status );
612 		}
613 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
614 
615 	/* Copy the authorityInfoAccess if it's present.  This one is a bit
616 	   tricky both because it's a multi-valued attribute and some values
617 	   may already be present in the destination certificate and because
618 	   it's not certain that the issuer certificate's AIA should be the same
619 	   as the subject certificate's AIA.  At the moment with monolithic CAs
620 	   (i.e. ones that control all the certificates down to the EE) this is
621 	   always the case and if it isn't then it's assumed that the CA will
622 	   set the EE's AIA to the appropriate value before trying to sign the
623 	   certificate.  Because of this we copy the issuer AIA if there's no
624 	   subject AIA present, otherwise we assume that the CA has set the
625 	   subject AIA to its own choice of value and don't try and copy
626 	   anything */
627 	attributeListPtr = findAttribute( srcListPtr,
628 									  CRYPT_CERTINFO_AUTHORITYINFOACCESS, FALSE );
629 	if( attributeListPtr != NULL && \
630 		findAttribute( *destListHeadPtr,
631 					   CRYPT_CERTINFO_AUTHORITYINFOACCESS, FALSE ) == NULL )
632 		{
633 		status = copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
634 								attributeListPtr, COPY_SUBJECT_TO_ISSUER );
635 		if( cryptStatusError( status ) )
636 			return( status );
637 		}
638 
639 	return( CRYPT_OK );
640 	}
641 
642 #ifdef USE_CERTREQ
643 
644 /* Copy attributes that are propagated from a CRMF certificate request
645    template to the issued certificate */
646 
647 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyCRMFRequestAttributes(INOUT ATTRIBUTE_PTR ** destListHeadPtr,const ATTRIBUTE_PTR * srcListPtr)648 int copyCRMFRequestAttributes( INOUT ATTRIBUTE_PTR **destListHeadPtr,
649 							   const ATTRIBUTE_PTR *srcListPtr )
650 	{
651 	ATTRIBUTE_LIST *attributeListPtr;
652 	int status;
653 
654 	assert( isWritePtr( destListHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
655 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
656 
657 	/* Copy the altName across, needed for the additional identification
658 	   that it provides */
659 	attributeListPtr = findAttribute( srcListPtr,
660 									  CRYPT_CERTINFO_SUBJECTALTNAME,
661 									  TRUE );
662 	if( attributeListPtr != NULL )
663 		{
664 		status = copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
665 								attributeListPtr, COPY_DIRECT );
666 		if( cryptStatusError( status ) )
667 			return( status );
668 		}
669 
670 	return( CRYPT_OK );
671 	}
672 #endif /* USE_CERTREQ */
673 
674 #if defined( USE_CERTVAL ) || defined( USE_CERTREV )
675 
676 /* Copy attributes that are propagated from an RTCS or OCSP request to a
677    response.  Since only one attribute, the nonce, is copied across we can
678    use the same function for both operations */
679 
680 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyRTCSRequestAttributes(INOUT ATTRIBUTE_PTR ** destListHeadPtr,const ATTRIBUTE_PTR * srcListPtr)681 int copyRTCSRequestAttributes( INOUT ATTRIBUTE_PTR **destListHeadPtr,
682 							   const ATTRIBUTE_PTR *srcListPtr )
683 	{
684 	ATTRIBUTE_LIST *attributeListPtr;
685 
686 	assert( isWritePtr( destListHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
687 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
688 
689 	/* If the nonce attribute is already present in the destination, delete
690 	   it */
691 	attributeListPtr = findAttributeField( *destListHeadPtr,
692 							CRYPT_CERTINFO_OCSP_NONCE, CRYPT_ATTRIBUTE_NONE );
693 	if( attributeListPtr != NULL )
694 		deleteAttributeField( destListHeadPtr, NULL, attributeListPtr, NULL );
695 
696 	/* Copy the nonce attribute from the source to the destination.  We don't
697 	   copy anything else (i.e. we default to deny-all) to prevent the
698 	   requester from being able to insert arbitrary attributes into the
699 	   response */
700 	attributeListPtr = findAttributeField( srcListPtr,
701 							CRYPT_CERTINFO_OCSP_NONCE, CRYPT_ATTRIBUTE_NONE );
702 	if( attributeListPtr != NULL )
703 		{
704 		return( copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
705 							   attributeListPtr, COPY_DIRECT ) );
706 		}
707 
708 	return( CRYPT_OK );
709 	}
710 #endif /* USE_CERTVAL || USE_CERTREV */
711 
712 #ifdef USE_CERTREV
713 
714 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyOCSPRequestAttributes(INOUT ATTRIBUTE_PTR ** destListHeadPtr,const ATTRIBUTE_PTR * srcListPtr)715 int copyOCSPRequestAttributes( INOUT ATTRIBUTE_PTR **destListHeadPtr,
716 							   const ATTRIBUTE_PTR *srcListPtr )
717 	{
718 	assert( isWritePtr( destListHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
719 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
720 
721 	return( copyRTCSRequestAttributes( destListHeadPtr, srcListPtr ) );
722 	}
723 
724 /* Copy attributes that are propagated from a revocation request to a CRL */
725 
726 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
copyRevocationAttributes(INOUT ATTRIBUTE_PTR ** destListHeadPtr,const ATTRIBUTE_PTR * srcListPtr)727 int copyRevocationAttributes( INOUT ATTRIBUTE_PTR **destListHeadPtr,
728 							  const ATTRIBUTE_PTR *srcListPtr )
729 	{
730 	ATTRIBUTE_LIST *attributeListPtr;
731 	int status;
732 
733 	assert( isWritePtr( destListHeadPtr, sizeof( ATTRIBUTE_LIST * ) ) );
734 	assert( isReadPtr( srcListPtr, sizeof( ATTRIBUTE_LIST ) ) );
735 
736 	/* Copy the CRL reason and invalidity date attributes from the source to
737 	   the destination.  We don't copy anything else (i.e. we default to
738 	   deny-all) to prevent the requester from being able to insert arbitrary
739 	   attributes into the CRL */
740 	attributeListPtr = findAttribute( srcListPtr,
741 									  CRYPT_CERTINFO_CRLREASON, FALSE );
742 	if( attributeListPtr != NULL )
743 		{
744 		status = copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
745 								attributeListPtr, COPY_DIRECT );
746 		if( cryptStatusError( status ) )
747 			return( status );
748 		}
749 	attributeListPtr = findAttribute( srcListPtr,
750 									  CRYPT_CERTINFO_INVALIDITYDATE, FALSE );
751 	if( attributeListPtr != NULL )
752 		{
753 		return( copyAttribute( ( ATTRIBUTE_LIST ** ) destListHeadPtr,
754 							   attributeListPtr, COPY_DIRECT ) );
755 		}
756 
757 	return( CRYPT_OK );
758 	}
759 #endif /* USE_CERTREV */
760 #endif /* USE_CERTIFICATES */
761