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