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