cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
trustmgr.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate Trust Management Routines *
4 * Copyright Peter Gutmann 1998-2008 *
5 * *
6 ****************************************************************************/
7 
8 /* The following code is actually part of the user rather than certificate
9  routines but it pertains to certificates so we include it here. Trust
10  information mutex handling is done in the user object so there are no
11  mutexes required here.
12 
13  The interpretation of what represents a "trusted certificate" is somewhat
14  complex and open-ended, it's not clear whether what's being trusted is
15  the key in the certificate, the certificate, or the owner of the
16  certificate (corresponding to subjectKeyIdentifier, issuerAndSerialNumber/
17  certHash, or subject DN). The generally accepted form is to trust the
18  subject so we check for this in the certificate. The modification for
19  trusting the key is fairly simple to make if required */
20 
21 #if defined( INC_ALL )
22  #include "cert.h"
23  #include "trustmgr.h"
24  #include "asn1.h"
25 #else
26  #include "cert/cert.h"
27  #include "cert/trustmgr.h"
28  #include "enc_dec/asn1.h"
29 #endif /* Compiler-specific includes */
30 
31 /* The size of the table of trust information. This must be a power of 2 */
32 
33 #define TRUSTINFO_SIZE 256
34 
35 /* Trusted certificate information */
36 
37 typedef struct TI {
38  /* Identification information, the checksum and hash of the
39  certificate's subjectName and subjectKeyIdentifier */
40  int sCheck;
42 #if 0 /* sKID lookup isn't used at present */
43  int kCheck;
44  BYTE kHash[ HASH_DATA_SIZE + 4 ];
45 #endif /* 0 */
46 
47  /* The trusted certificate. When we read trusted certificates from a
48  configuration file the certificate is stored in the encoded form to
49  save creating a pile of certificate objects that'll never be used.
50  When it's needed the certificate is created on the fly from the
51  encoded form. Conversely, when we get the trust information directly
52  from the user the certificate object already exists and the encoded
53  form isn't used */
55  void *certObject;
56  int certObjectLength;
58 
59  /* Pointer to the next entry */
60  struct TI *next; /* Next trustInfo record in the chain */
61  } TRUST_INFO;
62 
63 #ifdef USE_CERTIFICATES
64 
65 /****************************************************************************
66 * *
67 * Utility Routines *
68 * *
69 ****************************************************************************/
70 
71 /* Extract ID fields from an encoded certificate. Since this isn't a
72  certificate object we have to parse the encoded data to locate the fields
73  that we're interested in */
74 
75 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
76 static int getCertIdInfo( IN_BUFFER( certObjectLength ) const void *certObject,
78  const int certObjectLength,
79  OUT_PTR void **subjectDNptrPtr,
80  OUT_LENGTH_SHORT_Z int *subjectDNsizePtr )
81  {
82  STREAM stream;
83  void *subjectDNptr = DUMMY_INIT_PTR;
84  int subjectDNsize, status;
85 
86  assert( isReadPtr( certObject, certObjectLength ) );
87  assert( isWritePtr( subjectDNptrPtr, sizeof( void * ) ) );
88  assert( isWritePtr( subjectDNsizePtr, sizeof( int ) ) );
89 
90  REQUIRES( certObjectLength >= MIN_CRYPT_OBJECTSIZE && \
91  certObjectLength < MAX_INTLENGTH_SHORT );
92 
93  /* Clear return values */
94  *subjectDNptrPtr = NULL;
95  *subjectDNsizePtr = 0;
96 
97  /* Parse the certificate to locate the start of the encoded subject DN
98  and certificate extensions (if present) */
99  sMemConnect( &stream, certObject, certObjectLength );
100  readSequence( &stream, NULL ); /* Outer wrapper */
101  readSequence( &stream, NULL ); /* Inner wrapper */
102  if( peekTag( &stream ) == MAKE_CTAG( 0 ) )
103  readUniversal( &stream ); /* Version */
104  readUniversal( &stream ); /* Serial number */
105  readUniversal( &stream ); /* Signature algo */
106  readUniversal( &stream ); /* Issuer DN */
107  readUniversal( &stream ); /* Validity */
108  status = getStreamObjectLength( &stream, &subjectDNsize );
109  if( cryptStatusOK( status ) )
110  status = sMemGetDataBlock( &stream, &subjectDNptr, subjectDNsize );
111  if( cryptStatusError( status ) )
112  {
113  sMemDisconnect( &stream );
114  return( status );
115  }
116  *subjectDNptrPtr = subjectDNptr;
117  *subjectDNsizePtr = subjectDNsize;
118  status = sSkip( &stream, subjectDNsize );/* Subject DN */
119 #if 0 /* sKID lookup isn't used at present. Also this code should use the
120  parsing mechanism from dbx_rd.c to provide better checking */
121  const BYTE *extensionPtr;
122  int extensionSize = 0;
123  status = readUniversal( &stream ); /* Public key */
124  if( cryptStatusOK( status ) && \
125  peekTag( &stream ) == MAKE_CTAG( 3 ) )
126  {
127  status = readConstructed( &stream, &extensionSize, 3 );
128  if( cryptStatusOK( status ) )
129  {
130  extensionPtr = sMemBufPtr( &stream );
131  sSkip( &stream, extensionSize );
132  }
133  }
134  if( cryptStatusOK( status ) ) /* Signature */
135  status = readUniversal( &stream );
136 #endif /* 0 */
137  sMemDisconnect( &stream );
138  if( cryptStatusError( status ) )
139  return( status );
140 
141 #if 0 /* sKID lookup isn't used at present. Also this code should use the
142  parsing mechanism from dbx_rd.c to provide better checking */
143  /* Look for the subjectKeyID in the extensions. It's easier to do a
144  pattern match than to try and parse the extensions */
145  subjectKeyIDptr = NULL;
146  subjectKeyIDsize = 0;
147  for( i = 0; i < extensionSize - 64; i++ )
148  {
149  /* Look for the OID. This potentially skips two bytes at a time,
150  but this is safe since the preceding bytes can never contain
151  either of these two values (they're 0x30, len) */
152  if( extensionPtr[ i++ ] != BER_OBJECT_IDENTIFIER || \
153  extensionPtr[ i++ ] != 3 )
154  continue;
155  if( memcmp( extensionPtr + i, "\x55\x1D\x0E", 3 ) )
156  continue;
157  i += 3;
158 
159  /* We've found the OID (with 1.1e-12 error probability), skip the
160  critical flag if necessary */
161  if( extensionPtr[ i ] == BER_BOOLEAN )
162  i += 3;
163 
164  /* Check for the OCTET STRING and a reasonable length */
165  if( extensionPtr[ i++ ] != BER_OCTETSTRING || \
166  extensionPtr[ i ] & 0x80 )
167  continue;
168 
169  /* Extract the key ID */
170  if( i + extensionPtr[ i ] <= extensionSize )
171  {
172  subjectKeyIDsize = extensionPtr[ i++ ];
173  subjectKeyIDptr = extensionPtr + i;
174  }
175  }
176 #endif /* 0 */
177 
178  return( CRYPT_OK );
179  }
180 
181 /****************************************************************************
182 * *
183 * Retrieve Trusted Certificate Information *
184 * *
185 ****************************************************************************/
186 
187 /* Find the trust information entry for a given certificate. Since this
188  function is called from external code that doesn't know about trust
189  information internals the pointer is a void *, as it is for all other
190  externally-accessible trust management functions */
191 
193 void *findTrustEntry( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr,
195  const BOOLEAN getIssuerEntry )
196  {
197  TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtrPtr;
198  const TRUST_INFO *trustInfoCursor;
199  DYNBUF nameDB;
200  BYTE sHash[ HASH_DATA_SIZE + 8 ];
201  BOOLEAN nameHashed = FALSE;
202  int sCheck, trustInfoEntry, iterationCount, status;
203 
204  assert( isWritePtr( trustInfoPtrPtr, \
205  sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
206 
207  REQUIRES_N( isHandleRangeValid( iCryptCert ) );
208 
209  /* If we're trying to get a trusted issuer certificate and we're already
210  at a self-signed (CA root) certificate, don't return it. This check
211  is necessary because self-signed certificates have issuer name ==
212  subject name so once we get to a self-signed certificate's subject DN
213  an attempt to fetch its issuer would just repeatedly fetch the same
214  certificate */
215  if( getIssuerEntry )
216  {
217  int value;
218 
219  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE, &value,
221  if( cryptStatusError( status ) || value )
222  return( NULL );
223  }
224 
225  /* Set up the information needed to find the trusted certificate */
226  status = dynCreate( &nameDB, iCryptCert, getIssuerEntry ? \
227  CRYPT_IATTRIBUTE_ISSUER : CRYPT_IATTRIBUTE_SUBJECT );
228  if( cryptStatusError( status ) )
229  return( NULL );
230  sCheck = checksumData( dynData( nameDB ), dynLength( nameDB ) );
231  trustInfoEntry = sCheck & ( TRUSTINFO_SIZE - 1 );
232  ENSURES_N( trustInfoEntry >= 0 && trustInfoEntry < TRUSTINFO_SIZE );
233 
234  /* Check to see whether something with the requested DN is present */
235  for( trustInfoCursor = trustInfoIndex[ trustInfoEntry ], \
236  iterationCount = 0; \
237  trustInfoCursor != NULL && \
238  iterationCount < FAILSAFE_ITERATIONS_MED; \
239  trustInfoCursor = trustInfoCursor->next, iterationCount++ )
240  {
241  /* Perform a quick check using a checksum of the name to weed out
242  most entries */
243  if( trustInfoCursor->sCheck == sCheck )
244  {
245  if( !nameHashed )
246  {
247  hashData( sHash, HASH_DATA_SIZE, dynData( nameDB ),
248  dynLength( nameDB ) );
249  nameHashed = TRUE;
250  }
251  if( !memcmp( trustInfoCursor->sHash, sHash, HASH_DATA_SIZE ) )
252  {
253  dynDestroy( &nameDB );
254  return( ( TRUST_INFO * ) trustInfoCursor );
255  }
256  }
257  }
258  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );
259  dynDestroy( &nameDB );
260 
261  return( NULL );
262  }
263 
264 /* Retrieve trusted certificates */
265 
268  void *trustInfoPtrPtr )
269  {
270  TRUST_INFO *trustInfo = trustInfoPtrPtr;
271  int status;
272 
273  assert( isWritePtr( trustInfoPtrPtr, sizeof( TRUST_INFO ) ) );
274 
275  /* If the certificate hasn't already been instantiated yet, do so now */
276  if( trustInfo->iCryptCert == CRYPT_ERROR )
277  {
278  MESSAGE_CREATEOBJECT_INFO createInfo;
279 
280  /* Instantiate the certificate */
281  setMessageCreateObjectIndirectInfo( &createInfo, trustInfo->certObject,
282  trustInfo->certObjectLength,
286  &createInfo, OBJECT_TYPE_CERTIFICATE );
287  if( cryptStatusError( status ) )
288  {
289  DEBUG_DIAG(( "Couldn't instantiate trusted certificate" ));
290  assert( DEBUG_WARN );
291  return( status );
292  }
293 
294  /* The certificate was successfully instantiated, free its stored
295  encoded form */
296  zeroise( trustInfo->certObject, trustInfo->certObjectLength );
297  clFree( "getTrustedCert", trustInfo->certObject );
298  trustInfo->certObject = NULL;
299  trustInfo->certObjectLength = 0;
300  trustInfo->iCryptCert = createInfo.cryptHandle;
301  }
302 
303  /* Return the trusted certificate */
304  return( trustInfo->iCryptCert );
305  }
306 
308 BOOLEAN trustedCertsPresent( TYPECAST( TRUST_INFO ** ) const void *trustInfoPtrPtr )
309  {
310  const TRUST_INFO **trustInfoIndex = ( const TRUST_INFO ** ) trustInfoPtrPtr;
311  int i;
312 
313  assert( isReadPtr( trustInfoPtrPtr, \
314  sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
315 
316  for( i = 0; i < TRUSTINFO_SIZE; i++ )
317  {
318  if( trustInfoIndex[ i ] != NULL )
319  return( TRUE );
320  }
321 
322  return( FALSE );
323  }
324 
326 int enumTrustedCerts( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr,
329  {
330  TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtrPtr;
331  int i;
332 
333  assert( isWritePtr( trustInfoPtrPtr, \
334  sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
335 
336  REQUIRES( ( iCryptCtl == CRYPT_UNUSED && \
337  isHandleRangeValid( iCryptKeyset ) ) || \
338  ( isHandleRangeValid( iCryptCtl ) && \
339  iCryptKeyset == CRYPT_UNUSED ) );
340 
341  /* Send each trusted certificate to the given object, either a
342  certificate trust list or a keyset */
343  for( i = 0; i < TRUSTINFO_SIZE; i++ )
344  {
345  TRUST_INFO *trustInfoCursor;
346  int iterationCount;
347 
348  for( trustInfoCursor = trustInfoIndex[ i ], iterationCount = 0; \
349  trustInfoCursor != NULL && \
350  iterationCount < FAILSAFE_ITERATIONS_MED; \
351  trustInfoCursor = trustInfoCursor->next, iterationCount++ )
352  {
353  const CRYPT_CERTIFICATE iCryptCert = \
354  getTrustedCert( trustInfoCursor );
355  int status;
356 
357  if( cryptStatusError( iCryptCert ) )
358  return( iCryptCert );
359  if( iCryptCtl != CRYPT_UNUSED )
360  {
361  /* We're sending trusted certificates to a certificate trust
362  list */
363  status = krnlSendMessage( iCryptCtl, IMESSAGE_SETATTRIBUTE,
364  ( MESSAGE_CAST ) &iCryptCert,
365  CRYPT_IATTRIBUTE_CERTCOLLECTION );
366  }
367  else
368  {
369  MESSAGE_KEYMGMT_INFO setkeyInfo;
370 
371  /* We're sending trusted certificates to a keyset */
372  setMessageKeymgmtInfo( &setkeyInfo, CRYPT_KEYID_NONE, NULL, 0,
373  NULL, 0, KEYMGMT_FLAG_NONE );
374  setkeyInfo.cryptHandle = iCryptCert;
375  status = krnlSendMessage( iCryptKeyset, IMESSAGE_KEY_SETKEY,
376  &setkeyInfo,
378  }
379  if( cryptStatusError( status ) )
380  return( status );
381  }
382  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
383  }
384 
385  return( CRYPT_OK );
386  }
387 
388 /****************************************************************************
389 * *
390 * Add/Update Trusted Certificate Information *
391 * *
392 ****************************************************************************/
393 
394 /* Add and delete a trust entry */
395 
397 static int addEntry( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr,
398  IN_HANDLE_OPT const CRYPT_CERTIFICATE iCryptCert,
399  IN_BUFFER_OPT( certObjectLength ) const void *certObject,
400  IN_LENGTH_SHORT_Z const int certObjectLength )
401  {
402  TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtrPtr;
403  TRUST_INFO *newElement, *trustInfoCursor, *trustInfoLast;
404  BYTE sHash[ HASH_DATA_SIZE + 8 ];
405  BOOLEAN recreateCert = FALSE;
406  int sCheck, trustInfoEntry, iterationCount, status;
407 
408  assert( isWritePtr( trustInfoPtrPtr, \
409  sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
410  assert( ( certObject == NULL && certObjectLength == 0 && \
411  isHandleRangeValid( iCryptCert ) ) || \
412  ( isReadPtr( certObject, certObjectLength ) && \
413  iCryptCert == CRYPT_UNUSED ) );
414 
415  REQUIRES( ( certObject == NULL && certObjectLength == 0 && \
416  isHandleRangeValid( iCryptCert ) ) || \
417  ( certObject != NULL && \
418  certObjectLength >= MIN_CRYPT_OBJECTSIZE && \
419  certObjectLength < MAX_INTLENGTH_SHORT && \
420  iCryptCert == CRYPT_UNUSED ) );
421 
422  /* If we're adding a certificate, check whether it has a context
423  attached and if it does, whether it's a public-key context. If
424  there's no context attached (it's a data-only certificate) or the
425  attached context is a private-key context (which we don't want to
426  leave hanging around in memory, or which could be in a removable
427  crypto device) we don't try and use the certificate but instead add
428  the certificate data and then later re-instantiate a new certificate
429  with attached public-key context if required */
430  if( certObject == NULL )
431  {
433 
434  status = krnlSendMessage( iCryptCert, IMESSAGE_GETDEPENDENT,
435  &iCryptContext, OBJECT_TYPE_CONTEXT );
436  if( cryptStatusError( status ) )
437  {
438  /* There's no context associated with this certificate, we'll
439  have to recreate it later */
440  recreateCert = TRUE;
441  }
442  else
443  {
444  status = krnlSendMessage( iCryptContext, IMESSAGE_CHECK, NULL,
446  if( cryptStatusOK( status ) )
447  {
448  /* The context associated with the certificate is a private-
449  key context, recreate it later as a public-key context */
450  recreateCert = TRUE;
451  }
452  }
453  }
454 
455  /* Get the ID information for the certificate */
456  if( certObject == NULL )
457  {
458  DYNBUF subjectDB;
459 
460  /* Generate the checksum and hash of the certificate object's
461  subject name and key ID */
462  status = dynCreate( &subjectDB, iCryptCert,
463  CRYPT_IATTRIBUTE_SUBJECT );
464  if( cryptStatusError( status ) )
465  return( status );
466  sCheck = checksumData( dynData( subjectDB ),
467  dynLength( subjectDB ) );
468  hashData( sHash, HASH_DATA_SIZE, dynData( subjectDB ),
469  dynLength( subjectDB ) );
470 #if 0 /* sKID lookup isn't used at present */
471  DYNBUF subjectKeyDB;
472  status = dynCreate( &subjectKeyDB, iCryptCert,
474  if( cryptStatusOK( status ) )
475  {
476  kCheck = checksumData( dynData( subjectKeyDB ),
477  dynLength( subjectKeyDB ) );
478  hashData( kHash, HASH_DATA_SIZE, dynData( subjectKeyDB ),
479  dynLength( subjectKeyDB ) );
480  dynDestroy( &subjectKeyDB );
481  }
482 #endif /* 0 */
483  dynDestroy( &subjectDB );
484  }
485  else
486  {
487  void *subjectDNptr;
488  int subjectDNsize;
489 
490  /* Get the ID information from the encoded certificate */
491  status = getCertIdInfo( certObject, certObjectLength,
492  &subjectDNptr, &subjectDNsize );
493  ENSURES( cryptStatusOK( status ) );
494 
495  /* Generate the checksum and hash of the encoded certificate's
496  subject name and key ID */
497  sCheck = checksumData( subjectDNptr, subjectDNsize );
498  hashData( sHash, HASH_DATA_SIZE, subjectDNptr, subjectDNsize );
499 #if 0 /* sKID lookup isn't used at present */
500  kCheck = checksumData( subjectKeyIDptr, subjectKeyIDsize );
501  hashData( kHash, HASH_DATA_SIZE, subjectKeyIDptr, subjectKeyIDsize );
502 #endif /* 0 */
503  }
504 
505  /* Find the insertion point and make sure that this entry isn't already
506  present */
507  trustInfoEntry = sCheck & ( TRUSTINFO_SIZE - 1 );
508  ENSURES( trustInfoEntry >= 0 && trustInfoEntry < TRUSTINFO_SIZE );
509  for( trustInfoCursor = trustInfoLast = trustInfoIndex[ trustInfoEntry ], \
510  iterationCount = 0; \
511  trustInfoCursor != NULL && \
512  iterationCount < FAILSAFE_ITERATIONS_MED; \
513  trustInfoCursor = trustInfoCursor->next, iterationCount++ )
514  {
515  /* Perform a quick check using a checksum of the name to weed out
516  most entries */
517  if( trustInfoCursor->sCheck == sCheck && \
518  !memcmp( trustInfoCursor->sHash, sHash, HASH_DATA_SIZE ) )
519  return( CRYPT_ERROR_DUPLICATE );
520  trustInfoLast = trustInfoCursor;
521  }
522  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
523  trustInfoCursor = trustInfoLast;
524 
525  /* Allocate memory for the new element and copy the information across */
526  if( ( newElement = ( TRUST_INFO * ) \
527  clAlloc( "addEntry", sizeof( TRUST_INFO ) ) ) == NULL )
528  return( CRYPT_ERROR_MEMORY );
529  memset( newElement, 0, sizeof( TRUST_INFO ) );
530  newElement->sCheck = sCheck;
531  memcpy( newElement->sHash, sHash, HASH_DATA_SIZE );
532  if( certObject != NULL || recreateCert )
533  {
534  DYNBUF certDB;
536 
537  /* If we're using the data from an existing certificate object we
538  need to extract the encoded data */
539  if( recreateCert )
540  {
541  /* Get the encoded certificate */
542  status = dynCreateCert( &certDB, iCryptCert,
544  if( cryptStatusError( status ) )
545  {
546  clFree( "addEntry", newElement );
547  return( status );
548  }
549  certObject = dynData( certDB );
550  objectLength = dynLength( certDB );
551  }
552 
553  /* Remember the trusted certificate data for later use */
554  if( ( newElement->certObject = clAlloc( "addEntry",
555  objectLength ) ) == NULL )
556  {
557  clFree( "addEntry", newElement );
558  if( recreateCert )
559  dynDestroy( &certDB );
560  return( CRYPT_ERROR_MEMORY );
561  }
562  memcpy( newElement->certObject, certObject, objectLength );
563  newElement->certObjectLength = objectLength;
564  newElement->iCryptCert = CRYPT_ERROR;
565 
566  /* Clean up */
567  if( recreateCert )
568  dynDestroy( &certDB );
569  }
570  else
571  {
572  /* The trusted key exists as a standard certificate with a public-
573  key context attached, remember it for later */
574  krnlSendNotifier( iCryptCert, IMESSAGE_INCREFCOUNT );
575  newElement->iCryptCert = iCryptCert;
576  }
577 
578  /* Add the new entry to the list */
579  if( trustInfoCursor == NULL )
580  trustInfoIndex[ trustInfoEntry ] = newElement;
581  else
582  trustInfoCursor->next = newElement;
583 
584  return( CRYPT_OK );
585  }
586 
588 int addTrustEntry( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr,
589  IN_HANDLE_OPT const CRYPT_CERTIFICATE iCryptCert,
590  IN_BUFFER_OPT( certObjectLength ) const void *certObject,
591  IN_LENGTH_SHORT_Z const int certObjectLength,
592  const BOOLEAN addSingleCert )
593  {
594  BOOLEAN seenNonDuplicate = FALSE;
595  int iterationCount = 0, status;
596 
597  assert( isWritePtr( trustInfoPtrPtr, \
598  sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
599  assert( ( certObject == NULL && certObjectLength == 0 && \
600  isHandleRangeValid( iCryptCert ) ) || \
601  ( isReadPtr( certObject, certObjectLength ) && \
602  iCryptCert == CRYPT_UNUSED ) );
603 
604  REQUIRES( ( certObject == NULL && certObjectLength == 0 && \
605  isHandleRangeValid( iCryptCert ) ) || \
606  ( certObject != NULL && \
607  certObjectLength >= MIN_CRYPT_OBJECTSIZE && \
608  certObjectLength < MAX_INTLENGTH_SHORT && \
609  iCryptCert == CRYPT_UNUSED ) );
610 
611  /* If we're adding encoded certificate data we can add it directly */
612  if( certObject != NULL )
613  {
614  return( addEntry( trustInfoPtrPtr, CRYPT_UNUSED, certObject,
615  certObjectLength ) );
616  }
617 
618  /* Add the certificate/each certificate in the trust list */
619  status = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
620  MESSAGE_VALUE_TRUE, CRYPT_IATTRIBUTE_LOCKED );
621  if( cryptStatusError( status ) )
622  return( status );
623  if( !addSingleCert )
624  {
625  /* It's a trust list, move to the start of the list */
626  status = krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
629  if( cryptStatusError( status ) )
630  {
631  ( void ) krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
633  CRYPT_IATTRIBUTE_LOCKED );
634  return( status );
635  }
636  }
637  do
638  {
639  /* An item being added may already be present, however we can't fail
640  immediately because what's being added may be a chain containing
641  further certificates so we keep track of whether we've
642  successfully added at least one item and clear data duplicate
643  errors */
644  status = addEntry( trustInfoPtrPtr, iCryptCert, NULL, 0 );
645  if( status == CRYPT_OK )
646  seenNonDuplicate = TRUE;
647  else
648  {
649  if( status == CRYPT_ERROR_DUPLICATE )
650  status = CRYPT_OK;
651  }
652  }
653  while( cryptStatusOK( status ) && !addSingleCert && \
657  iterationCount++ < FAILSAFE_ITERATIONS_LARGE );
658  ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
659  ( void ) krnlSendMessage( iCryptCert, IMESSAGE_SETATTRIBUTE,
660  MESSAGE_VALUE_FALSE, CRYPT_IATTRIBUTE_LOCKED );
661  if( cryptStatusOK( status ) && !seenNonDuplicate )
662  {
663  /* There were no new certificates to add present, return an already-
664  initialised error */
665  status = CRYPT_ERROR_INITED;
666  }
667 
668  return( status );
669  }
670 
671 STDC_NONNULL_ARG( ( 1, 2 ) ) \
672 void deleteTrustEntry( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr,
674  {
675  TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtrPtr;
676  TRUST_INFO *entryToDelete = ( TRUST_INFO * ) entryToDeletePtr, *prevInfoPtr;
677  const int trustInfoEntry = entryToDelete->sCheck & ( TRUSTINFO_SIZE - 1 );
678 
679  assert( isWritePtr( trustInfoPtrPtr, \
680  sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
681  assert( isWritePtr( entryToDeletePtr, sizeof( TRUST_INFO ) ) );
682 
683  REQUIRES_V( trustInfoEntry >= 0 && trustInfoEntry < TRUSTINFO_SIZE );
684 
685  /* Unlink the trust information index */
686  prevInfoPtr = trustInfoIndex[ trustInfoEntry ];
687  ENSURES_V( prevInfoPtr != NULL );
688  if( prevInfoPtr == entryToDelete )
689  {
690  /* Unlink from the start of the list */
691  trustInfoIndex[ trustInfoEntry ] = entryToDelete->next;
692  }
693  else
694  {
695  int iterationCount;
696 
697  /* Unlink from the middle/end of the list */
698  for( iterationCount = 0;
699  prevInfoPtr->next != entryToDelete && \
700  iterationCount < FAILSAFE_ITERATIONS_MED;
701  prevInfoPtr = prevInfoPtr->next, iterationCount++ )
702  {
703  ENSURES_V( prevInfoPtr != NULL );
704  }
705  ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MED );
706  prevInfoPtr->next = entryToDelete->next;
707  }
708 
709  /* Free the trust information entry */
710  if( entryToDelete->iCryptCert != CRYPT_ERROR )
711  krnlSendNotifier( entryToDelete->iCryptCert, IMESSAGE_DECREFCOUNT );
712  if( entryToDelete->certObject != NULL )
713  {
714  zeroise( entryToDelete->certObject, entryToDelete->certObjectLength );
715  clFree( "deleteTrustEntry", entryToDelete->certObject );
716  }
717  memset( entryToDelete, 0, sizeof( TRUST_INFO ) );
718  clFree( "deleteTrustEntry", entryToDelete );
719  }
720 
721 /****************************************************************************
722 * *
723 * Init/Shut down Trusted Certificate Information *
724 * *
725 ****************************************************************************/
726 
727 /* Initialise and shut down the trust information */
728 
730 int initTrustInfo( OUT_PTR TYPECAST( TRUST_INFO ** ) void **trustInfoPtrPtr )
731  {
732  TRUST_INFO **trustInfoIndex;
733 
734  assert( isWritePtr( trustInfoPtrPtr, sizeof( void * ) ) );
735 
736  /* Initialise the trust information table */
737  if( ( trustInfoIndex = \
738  clAlloc( "initTrustInfo", TRUSTINFO_SIZE * \
739  sizeof( TRUST_INFO * ) ) ) == NULL )
740  return( CRYPT_ERROR_MEMORY );
741  memset( trustInfoIndex, 0, sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE );
742  *trustInfoPtrPtr = trustInfoIndex;
743 
744  return( CRYPT_OK );
745  }
746 
747 STDC_NONNULL_ARG( ( 1 ) ) \
748 void endTrustInfo( INOUT TYPECAST( TRUST_INFO ** ) void *trustInfoPtrPtr )
749  {
750  TRUST_INFO **trustInfoIndex = ( TRUST_INFO ** ) trustInfoPtrPtr;
751  int i;
752 
753  assert( isWritePtr( trustInfoPtrPtr, \
754  sizeof( TRUST_INFO * ) * TRUSTINFO_SIZE ) );
755 
756  /* Destroy the chain of items at each table position */
757  for( i = 0; i < TRUSTINFO_SIZE; i++ )
758  {
759  TRUST_INFO *trustInfoCursor;
760  int iterationCount;
761 
762  /* Destroy any items in the list */
763  for( trustInfoCursor = trustInfoIndex[ i ], iterationCount = 0;
764  trustInfoCursor != NULL && \
765  iterationCount < FAILSAFE_ITERATIONS_MED; iterationCount++ )
766  {
767  TRUST_INFO *itemToFree = trustInfoCursor;
768 
769  trustInfoCursor = trustInfoCursor->next;
770  deleteTrustEntry( trustInfoIndex, itemToFree );
771  }
772  ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MED );
773  }
774  memset( trustInfoIndex, 0, TRUSTINFO_SIZE * sizeof( TRUST_INFO * ) );
775  clFree( "endTrustInfo", trustInfoIndex );
776  }
777 #endif /* USE_CERTIFICATES */