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