cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
chain.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate Chain Management Routines *
4 * Copyright Peter Gutmann 1996-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "cert.h"
10  #include "asn1.h"
11  #include "asn1_ext.h"
12  #include "misc_rw.h"
13 #else
14  #include "cert/cert.h"
15  #include "enc_dec/asn1.h"
16  #include "enc_dec/asn1_ext.h"
17  #include "enc_dec/misc_rw.h"
18 #endif /* Compiler-specific includes */
19 
20 /* When matching by subjectKeyIdentifier we don't use values less than 40
21  bits because some CAs use monotonically increasing sequence numbers for
22  the sKID, which can clash with the same values when used by other CAs */
23 
24 #define MIN_SKID_SIZE 5
25 
26 /* A structure for storing pointers to parent and child (issuer and subject)
27  names, key identifiers, and serial numbers (for finding a certificate by
28  issuerAndSerialNumber) and one for storing pointers to chaining
29  information */
30 
31 typedef struct {
32  BUFFER_FIXED( issuerDNsize ) \
33  const void *issuerDN;
34  BUFFER_FIXED( subjectDNsize ) \
35  const void *subjectDN;
36  int issuerDNsize, subjectDNsize;
37  BUFFER_FIXED( serialNumberSize ) \
38  const void *serialNumber;
39  int serialNumberSize;
40  BUFFER_OPT_FIXED( subjectKeyIDsize ) \
41  const void *subjectKeyIdentifier;
42  int subjectKeyIDsize;
43 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
44  BUFFER_OPT_FIXED( issuerKeyIDsize ) \
45  const void *issuerKeyIdentifier;
46  int issuerKeyIDsize;
47 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
48  } CHAIN_INFO;
49 
50 typedef struct {
51  BUFFER_FIXED( DNsize ) \
52  const void *DN;
53  int DNsize;
54 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
55  BUFFER_FIXED( keyIDsize ) \
56  const void *keyIdentifier;
57  int keyIDsize;
58 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
59  } CHAINING_INFO;
60 
61 /* Match an identifier in a chain information structure against a chaining
62  information structure */
63 
64 #define matchDN( chainingInfo, chainInfo, type ) \
65  ( ( chainingInfo )->DNsize > 0 && \
66  ( chainingInfo )->DNsize == ( chainInfo )->type##DNsize && \
67  !memcmp( ( chainingInfo )->DN, ( chainInfo )->type##DN, \
68  ( chainInfo )->type##DNsize ) )
69 
70 #define matchKeyID( chainingInfo, chainInfo, type ) \
71  ( ( chainingInfo )->keyIDsize > MIN_SKID_SIZE && \
72  ( chainingInfo )->keyIDsize == ( chainInfo )->type##KeyIDsize && \
73  !memcmp( ( chainingInfo )->keyIdentifier, \
74  ( chainInfo )->type##KeyIdentifier, \
75  ( chainInfo )->type##KeyIDsize ) )
76 
77 #ifdef USE_CERTIFICATES
78 
79 /****************************************************************************
80 * *
81 * Utility Routines *
82 * *
83 ****************************************************************************/
84 
85 /* Copy subject or issuer chaining values from the chaining information */
86 
87 STDC_NONNULL_ARG( ( 1, 2 ) ) \
88 static void getSubjectChainingInfo( OUT CHAINING_INFO *chainingInfo,
89  const CHAIN_INFO *chainInfo )
90  {
91  assert( isWritePtr( chainingInfo, sizeof( CHAINING_INFO ) ) );
92  assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) ) );
93 
94  memset( chainingInfo, 0, sizeof( CHAINING_INFO ) );
95  chainingInfo->DN = chainInfo->subjectDN;
96  chainingInfo->DNsize = chainInfo->subjectDNsize;
97 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
98  chainingInfo->keyIdentifier = chainInfo->subjectKeyIdentifier;
99  chainingInfo->keyIDsize = chainInfo->subjectKeyIDsize;
100 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
101  }
102 
103 STDC_NONNULL_ARG( ( 1, 2 ) ) \
104 static void getIssuerChainingInfo( OUT CHAINING_INFO *chainingInfo,
105  const CHAIN_INFO *chainInfo )
106  {
107  assert( isWritePtr( chainingInfo, sizeof( CHAINING_INFO ) ) );
108  assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) ) );
109 
110  memset( chainingInfo, 0, sizeof( CHAINING_INFO ) );
111  chainingInfo->DN = chainInfo->issuerDN;
112  chainingInfo->DNsize = chainInfo->issuerDNsize;
113 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
114  chainingInfo->keyIdentifier = chainInfo->issuerKeyIdentifier;
115  chainingInfo->keyIDsize = chainInfo->issuerKeyIDsize;
116 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
117  }
118 
119 /* Determine whether a given certificate is the subject or issuer for the
120  requested certificate based on the chaining information. We chain by
121  issuer DN if possible but if that fails we use the keyID. This is
122  somewhat dodgy since it can lead to the situation where a certificate
123  supposedly issued by Verisign Class 1 Public Primary Certification
124  Authority is actually issued by Honest Joe's Used Cars but the standard
125  requires this as a fallback (PKIX section 4.2.1.1).
126 
127  There are actually two different interpretations of chaining by keyID,
128  the first says that the keyID is a non-DN identifier that can survive
129  operations such as cross-certification and re-parenting so that if a
130  straight chain by DN fails then a chain by keyID is possible as a
131  fallback option. The second is that the keyID is a disambiguator if
132  multiple paths in a chain-by-DN scenario are present in a spaghetti PKI.
133  Since the latter is rather unlikely to occur in a standard PKCS #7/SSL
134  certificate chain (half the implementations around wouldn't be able to
135  assemble the chain any more) we use the former interpretation by default
136  but enable the latter if useStrictChaining is set.
137 
138  If useStrictChaining is enabled we require that the DN *and* the keyID
139  match, which (even without a spaghetti PKI being in effect) is required
140  to handle PKIX weirdness in which multiple potential issuers can be
141  present in a chain due to CA certificate renewals/reparenting. We don't
142  do this by default because too many CAs get keyID chaining wrong, leading
143  to apparent breaks in the chain when the keyID fails to match.
144 
145  We don't have to worry about strict chaining for the issuer match because
146  we only use it when we're walking down the chain looking for a leaf
147  certificate */
148 
150 static BOOLEAN isSubject( const CHAINING_INFO *chainingInfo,
151  const CHAIN_INFO *chainInfo,
152  const BOOLEAN useStrictChaining )
153  {
154  BOOLEAN dnChains = FALSE, keyIDchains = FALSE;
155 
156  assert( isReadPtr( chainingInfo, sizeof( CHAINING_INFO ) ) );
157  assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) ) );
158 
159  /* Check for chaining by DN and keyID */
160  if( matchDN( chainingInfo, chainInfo, subject ) )
161  dnChains = TRUE;
162 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
163  if( matchKeyID( chainingInfo, chainInfo, subject ) )
164  keyIDchains = TRUE;
165 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
166 
167  /* If we're using strict chaining both the DN and the keyID must chain */
168  if( useStrictChaining )
169  return( dnChains && keyIDchains );
170 
171  /* We're not using strict chaining, either can chain */
172  return( dnChains || keyIDchains );
173  }
174 
176 static BOOLEAN isIssuer( const CHAINING_INFO *chainingInfo,
177  const CHAIN_INFO *chainInfo )
178  {
179  assert( isReadPtr( chainingInfo, sizeof( CHAINING_INFO ) ) );
180  assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) ) );
181 
182  /* In the simplest case we chain by name. This works for almost all
183  certificates */
184  if( matchDN( chainingInfo, chainInfo, issuer ) )
185  return( TRUE );
186 
187 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
188  /* If that fails we chain by keyID */
189  if( matchKeyID( chainingInfo, chainInfo, issuer ) )
190  return( TRUE );
191 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
192 
193  return( FALSE );
194  }
195 
196 /* Get the location and size of certificate attribute data required for
197  chaining */
198 
199 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
200 static int getChainingAttribute( INOUT CERT_INFO *certInfoPtr,
201  IN_ATTRIBUTE \
204  const void **attributePtrPtr,
206  {
208 
209  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
210  assert( isReadPtr( attributePtrPtr, sizeof( void * ) ) );
211  assert( isWritePtr( attributeLength, sizeof( int * ) ) );
212 
213  ENSURES( attributeType == CRYPT_CERTINFO_SUBJECTKEYIDENTIFIER || \
214  attributeType == CRYPT_CERTINFO_AUTHORITY_KEYIDENTIFIER );
215 
216  /* Clear return values */
217  *attributePtrPtr = NULL;
218  *attributeLength = 0;
219 
220  /* Find the requested attribute and return a pointer to it */
221  attributePtr = findAttributeField( certInfoPtr->attributes,
222  attributeType, CRYPT_ATTRIBUTE_NONE );
223  if( attributePtr == NULL )
224  {
225  /* If the chaining attribute data isn't present this isn't an
226  error */
227  return( CRYPT_OK );
228  }
229  return( getAttributeDataPtr( attributePtr, ( void ** ) attributePtrPtr,
230  attributeLength ) );
231  }
232 
233 /* Free a certificate chain */
234 
235 STDC_NONNULL_ARG( ( 1 ) ) \
236 static void freeCertChain( IN_ARRAY( certChainSize ) \
238  IN_RANGE( 1, MAX_CHAINLENGTH ) \
239  const int certChainSize )
240  {
241  int i;
242 
243  assert( isWritePtr( iCertChain, sizeof( CRYPT_CERTIFICATE ) * certChainSize ) );
244 
245  REQUIRES_V( certChainSize > 0 && certChainSize <= MAX_CHAINLENGTH );
246 
247  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
248  {
249  krnlSendNotifier( iCertChain[ i ], IMESSAGE_DESTROY );
250  iCertChain[ i ] = CRYPT_ERROR;
251  }
252  }
253 
254 /****************************************************************************
255 * *
256 * Build a Certificate Chain *
257 * *
258 ****************************************************************************/
259 
260 /* Build up the parent/child pointers for a certificate chain */
261 
262 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
263 static int buildChainInfo( OUT_ARRAY( certChainSize ) CHAIN_INFO *chainInfo,
264  IN_ARRAY( certChainSize ) \
265  const CRYPT_CERTIFICATE *iCertChain,
266  IN_RANGE( 1, MAX_CHAINLENGTH ) \
267  const int certChainSize )
268  {
269  int i;
270 
271  assert( isWritePtr( chainInfo, sizeof( CHAIN_INFO ) * certChainSize ) );
272  assert( isReadPtr( iCertChain, sizeof( CRYPT_CERTIFICATE ) * certChainSize ) );
273 
274  REQUIRES( certChainSize > 0 && certChainSize <= MAX_CHAINLENGTH );
275 
276  /* Clear return value */
277  memset( chainInfo, 0, sizeof( CHAIN_INFO ) * certChainSize );
278 
279  /* Extract the subject and issuer DNs and key identifiers from each
280  certificate. Maintaining an external pointer into the internal
281  structure is safe since the objects are reference-counted and won't be
282  destroyed until the encapsulating certificate is destroyed */
283  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
284  {
285  CERT_INFO *certChainPtr;
286  int status;
287 
288  status = krnlAcquireObject( iCertChain[ i ], OBJECT_TYPE_CERTIFICATE,
289  ( void ** ) &certChainPtr,
291  if( cryptStatusError( status ) )
292  return( status );
293  ANALYSER_HINT( certChainPtr != NULL );
294  chainInfo[ i ].subjectDN = certChainPtr->subjectDNptr;
295  chainInfo[ i ].subjectDNsize = certChainPtr->subjectDNsize;
296  chainInfo[ i ].issuerDN = certChainPtr->issuerDNptr;
297  chainInfo[ i ].issuerDNsize = certChainPtr->issuerDNsize;
298  chainInfo[ i ].serialNumber = certChainPtr->cCertCert->serialNumber;
299  chainInfo[ i ].serialNumberSize = certChainPtr->cCertCert->serialNumberLength;
300  status = getChainingAttribute( certChainPtr,
302  &chainInfo[ i ].subjectKeyIdentifier,
303  &chainInfo[ i ].subjectKeyIDsize );
304  if( cryptStatusError( status ) )
305  {
306  krnlReleaseObject( certChainPtr->objectHandle );
307  return( status );
308  }
309 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
310  status = getChainingAttribute( certChainPtr,
312  &chainInfo[ i ].issuerKeyIdentifier,
313  &chainInfo[ i ].issuerKeyIDsize );
314  if( cryptStatusError( status ) )
315  {
316  krnlReleaseObject( certChainPtr->objectHandle );
317  return( status );
318  }
319 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
320  krnlReleaseObject( certChainPtr->objectHandle );
321  }
322  ENSURES( i < MAX_CHAINLENGTH );
323 
324  return( CRYPT_OK );
325  }
326 
327 /* Find the leaf node in a (possibly unordered) certificate chain by walking
328  down the chain as far as possible. The strategy we use is to pick an
329  initial certificate (which is often the leaf certificate anyway) and keep
330  looking for certificates it (or its successors) have issued until we
331  reach the end of the chain. Returns the position of the leaf node in the
332  chain */
333 
335 static int findLeafNode( IN_ARRAY( certChainSize ) const CHAIN_INFO *chainInfo,
336  IN_RANGE( 1, MAX_CHAINLENGTH ) const int certChainSize )
337  {
338  CHAINING_INFO chainingInfo;
339  BOOLEAN certUsed[ MAX_CHAINLENGTH + 8 ], moreMatches;
340  int lastCertPos, iterationCount;
341 
342  assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) * certChainSize ) );
343 
344  REQUIRES( certChainSize > 0 && certChainSize <= MAX_CHAINLENGTH );
345 
346  /* We start our search at the first certificate, which is often the leaf
347  certificate anyway */
348  memset( certUsed, 0, MAX_CHAINLENGTH * sizeof( BOOLEAN ) );
349  getSubjectChainingInfo( &chainingInfo, &chainInfo[ 0 ] );
350  certUsed[ 0 ] = TRUE;
351  lastCertPos = 0;
352 
353  /* Walk down the chain from the currently selected certificate checking
354  for certificates issued by it until we can't go any further. Note
355  that this algorithm handles chains with PKIX path-kludge certificates
356  as well as normal ones since it marks a certificate as used once it
357  processes it for the first time, avoiding potential endless loops on
358  subject == issuer path-kludge certificates */
359  for( moreMatches = TRUE, iterationCount = 0;
360  moreMatches && iterationCount < MAX_CHAINLENGTH;
361  iterationCount++ )
362  {
363  int i;
364 
365  /* We don't have a match until we discover otherwise */
366  moreMatches = FALSE;
367 
368  /* Try and find a certificate issued by the current certificate */
369  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
370  {
371  /* If there's another certificate below the current one in the
372  chain, mark the current one as used and move on to the next
373  one */
374  if( !certUsed[ i ] && \
375  isIssuer( &chainingInfo, &chainInfo[ i ] ) )
376  {
377  getSubjectChainingInfo( &chainingInfo, &chainInfo[ i ] );
378  certUsed[ i ] = TRUE;
379  moreMatches = TRUE;
380  lastCertPos = i;
381  break;
382  }
383  }
384  ENSURES( i < MAX_CHAINLENGTH );
385  }
386  ENSURES( iterationCount < MAX_CHAINLENGTH );
387 
388  return( lastCertPos );
389  }
390 
391 /* Find a leaf node as identified by issuerAndSerialNumber or
392  subjectKeyIdentifier. Returns the position of the leaf node in the
393  chain */
394 
395 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
396 static int findIdentifiedLeafNode( IN_ARRAY( certChainSize ) \
397  const CHAIN_INFO *chainInfo,
398  IN_RANGE( 1, MAX_CHAINLENGTH ) \
399  const int certChainSize,
401  IN_BUFFER( keyIDlength ) const void *keyID,
402  IN_LENGTH_KEYID const int keyIDlength )
403  {
404  STREAM stream;
405  void *serialNumber = DUMMY_INIT_PTR, *issuerDNptr = DUMMY_INIT_PTR;
406  int issuerDNsize, serialNumberSize;
407  int i, status;
408 
409  assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) * certChainSize ) );
410  assert( isReadPtr( keyID, keyIDlength ) );
411 
412  REQUIRES( certChainSize > 0 && certChainSize <= MAX_CHAINLENGTH );
413  REQUIRES( keyIDtype == CRYPT_IKEYID_KEYID || \
414  keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER );
415  REQUIRES( keyID != NULL && \
416  keyIDlength >= MIN_SKID_SIZE && \
417  keyIDlength < MAX_ATTRIBUTE_SIZE );
418 
419  /* If it's a subjectKeyIdentifier walk down the chain looking for a
420  match */
421  if( keyIDtype == CRYPT_IKEYID_KEYID )
422  {
423  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
424  {
425  if( chainInfo[ i ].subjectKeyIDsize > MIN_SKID_SIZE && \
426  chainInfo[ i ].subjectKeyIDsize == keyIDlength && \
427  !memcmp( chainInfo[ i ].subjectKeyIdentifier, keyID,
428  keyIDlength ) )
429  return( i );
430  }
431  ENSURES( i < MAX_CHAINLENGTH );
432  return( CRYPT_ERROR_NOTFOUND );
433  }
434 
435  /* It's an issuerAndSerialNumber, extract the issuer DN and serial
436  number */
437  sMemConnect( &stream, keyID, keyIDlength );
438  readSequence( &stream, NULL );
439  status = getStreamObjectLength( &stream, &issuerDNsize );
440  if( cryptStatusOK( status ) )
441  status = sMemGetDataBlock( &stream, &issuerDNptr, issuerDNsize );
442  if( cryptStatusError( status ) )
443  {
444  sMemDisconnect( &stream );
445  return( CRYPT_ERROR_NOTFOUND );
446  }
447  sSkip( &stream, issuerDNsize ); /* Issuer DN */
448  status = readGenericHole( &stream, &serialNumberSize, 1, BER_INTEGER );
449  if( cryptStatusOK( status ) ) /* Serial number */
450  status = sMemGetDataBlock( &stream, &serialNumber,
451  serialNumberSize );
452  sMemDisconnect( &stream );
453  if( cryptStatusError( status ) )
454  return( CRYPT_ERROR_NOTFOUND );
455  ANALYSER_HINT( issuerDNptr != NULL );
456  ANALYSER_HINT( serialNumber != NULL );
457 
458  /* Walk down the chain looking for the one identified by the
459  issuerAndSerialNumber */
460  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
461  {
462  if( chainInfo[ i ].issuerDNsize > 0 && \
463  chainInfo[ i ].issuerDNsize == issuerDNsize && \
464  !memcmp( chainInfo[ i ].issuerDN, issuerDNptr,
465  issuerDNsize ) && \
466  compareSerialNumber( chainInfo[ i ].serialNumber,
467  chainInfo[ i ].serialNumberSize,
468  serialNumber, serialNumberSize ) )
469  return( i );
470  }
471  ENSURES( i < MAX_CHAINLENGTH );
472 
473  return( CRYPT_ERROR_NOTFOUND );
474  }
475 
476 /* Sort the issuer certificates in a certificate chain, discarding any
477  unnecessary certificates. If we're canonicalising an existing chain then
478  the start point in the chain is given by certChainStart and the -1th
479  certificate is the end user certificate and isn't part of the ordering
480  process. If we're building a new chain from an arbitrary set of
481  certificates then the start point is given by the chaining information
482  for the leaf certificate.
483 
484  The canonicalisation of the chain can be handled in one of two ways, the
485  logical way and the PKIX way. The latter allows apparently self-signed
486  certificates in the middle of a chain due to certificate
487  renewals/reparenting, which completely breaks the standard certificate
488  convention that a self-signed certificate is a root CA. This means that
489  without special handling the chain will terminate at a certificate that
490  appears to be (but isn't) the CA root certificate. A sample chain of
491  this form (in this case involving an oldWithNew certificate) is as
492  follows:
493 
494  Issuer Subject Key/sKID Sig/aKID
495  ------ ------- -------- ----------
496  Root CA ca_new root
497  CA CA ca_old ca_new
498  CA EE ee ca_old
499 
500  In order to handle these chains we need to match by both DN *and* keyID,
501  however since so many CAs get keyIDs wrong enabling this by default
502  would break many certificate chains. To handle this we only enable the
503  extra-match behaviour if the compliance level is
504  CRYPT_COMPLIANCELEVEL_PKIX_FULL, for which people should be expecting all
505  sorts of bizarre behaviour anyway */
506 
507 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
508 static int sortCertChain( INOUT_ARRAY( certChainSize ) CRYPT_CERTIFICATE *iCertChain,
509  OUT_RANGE( 0, MAX_CHAINLENGTH ) int *orderedCertChainSize,
510  IN_ARRAY( certChainSize ) const CHAIN_INFO *chainInfo,
511  IN_RANGE( 1, MAX_CHAINLENGTH ) const int certChainSize,
512  IN_RANGE( 1, MAX_CHAINLENGTH ) const int leafCertEntry,
513  IN_HANDLE_OPT const CRYPT_CERTIFICATE certChainStart,
514  IN_OPT const CHAINING_INFO *chainingInfo,
515  const BOOLEAN useStrictChaining )
516  {
517  CRYPT_CERTIFICATE orderedChain[ MAX_CHAINLENGTH + 8 ];
518  CHAINING_INFO localChainingInfo;
519  BOOLEAN chainInfoValid[ MAX_CHAINLENGTH + 8 ], moreMatches;
520  const int maxMatchLevel = useStrictChaining ? 1 : 0;
521  int orderedChainIndex, iterationCount, i;
522 
523  assert( isWritePtr( iCertChain, sizeof( CRYPT_CERTIFICATE ) * certChainSize ) );
524  assert( isReadPtr( chainInfo, sizeof( CHAIN_INFO ) * certChainSize ) );
525  assert( ( isHandleRangeValid( certChainStart ) && \
526  chainingInfo == NULL ) || \
527  ( certChainStart == CRYPT_UNUSED && \
528  isReadPtr( chainingInfo, sizeof( CHAINING_INFO ) ) ) );
529 
530  REQUIRES( certChainSize > 0 && certChainSize <= MAX_CHAINLENGTH );
531  REQUIRES( leafCertEntry >= 0 && leafCertEntry <= certChainSize );
532  REQUIRES( ( isHandleRangeValid( certChainStart ) && \
533  chainingInfo == NULL ) || \
534  ( certChainStart == CRYPT_UNUSED && \
535  chainingInfo != NULL ) );
536 
537  /* Clear return value */
538  *orderedCertChainSize = 0;
539 
540  /* Initially all chain entries except the one for the leaf certificate
541  are valid */
542  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
543  chainInfoValid[ i ] = TRUE;
544  ENSURES( i < MAX_CHAINLENGTH );
545  chainInfoValid[ leafCertEntry ] = FALSE;
546 
547  /* If we're canonicalising an existing chain there's a predefined chain
548  start that we copy over and prepare to look for the next certificate
549  up the chain */
550  if( certChainStart != CRYPT_UNUSED )
551  {
552  getIssuerChainingInfo( &localChainingInfo, &chainInfo[ 0 ] );
553  orderedChain[ 0 ] = certChainStart;
554  chainInfoValid[ 0 ] = FALSE;
555  orderedChainIndex = 1;
556  }
557  else
558  {
559  /* We're building a new chain, the caller has supplied the chaining
560  information */
561  memcpy( &localChainingInfo, chainingInfo, sizeof( CHAINING_INFO ) );
562  orderedChainIndex = 0;
563  }
564 
565  /* Build an ordered chain of certificates from the leaf to the root */
566  for( moreMatches = TRUE, iterationCount = 0;
567  moreMatches && iterationCount < FAILSAFE_ITERATIONS_MED;
568  iterationCount++ )
569  {
570  int matchLevel;
571 
572  /* We don't have a match until we discover otherwise */
573  moreMatches = FALSE;
574 
575  /* Find the certificate with the current issuer as its subject. If
576  we're using strict chaining we first try a strict match
577  (matchLevel = TRUE), if that fails we fall back to a standard
578  match (matchLevel = FALSE). This is required to handle the
579  significant number of CAs that don't get chaining by keyID
580  right */
581  for( matchLevel = maxMatchLevel; \
582  !moreMatches && matchLevel >= 0; matchLevel-- )
583  {
584  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
585  {
586  /* If this isn't the issuer, continue */
587  if( !chainInfoValid[ i ] || \
588  !isSubject( &localChainingInfo, &chainInfo[ i ],
589  matchLevel ) )
590  continue;
591 
592  /* We've found the issuer, move the certificate to the
593  ordered chain and prepare to find its issuer */
594  orderedChain[ orderedChainIndex++ ] = iCertChain[ i ];
595  getIssuerChainingInfo( &localChainingInfo, &chainInfo[ i ] );
596  chainInfoValid[ i ] = FALSE;
597  moreMatches = TRUE; /* Exit outer loop as well */
598  break;
599  }
600  ENSURES( i < MAX_CHAINLENGTH );
601  }
602  ENSURES( orderedChainIndex <= certChainSize && \
603  orderedChainIndex < MAX_CHAINLENGTH );
604  }
605  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
606 
607  /* If there are any certificates left they're not needed for anything
608  so we can free the resources */
609  for( i = 0; i < certChainSize && i < MAX_CHAINLENGTH; i++ )
610  {
611  if( chainInfoValid[ i ] )
612  krnlSendNotifier( iCertChain[ i ], IMESSAGE_DECREFCOUNT );
613  }
614  ENSURES( i < MAX_CHAINLENGTH );
615 
616  /* Replace the existing chain with the ordered version */
617  memset( iCertChain, 0, sizeof( CRYPT_CERTIFICATE ) * certChainSize );
618  if( orderedChainIndex > 0 )
619  {
620  memcpy( iCertChain, orderedChain,
621  sizeof( CRYPT_CERTIFICATE ) * orderedChainIndex );
622  }
623  *orderedCertChainSize = orderedChainIndex;
624 
625  return( CRYPT_OK );
626  }
627 
628 /* Read a collection of certificates in a certificate chain into a
629  certificate object */
630 
631 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
632 static int buildCertChain( OUT_HANDLE_OPT CRYPT_CERTIFICATE *iLeafCert,
633  INOUT_ARRAY( certChainEnd ) CRYPT_CERTIFICATE *iCertChain,
634  IN_RANGE( 1, MAX_CHAINLENGTH ) const int certChainEnd,
635  IN_KEYID_OPT const CRYPT_KEYID_TYPE keyIDtype,
636  IN_BUFFER_OPT( keyIDlength ) const void *keyID,
637  IN_LENGTH_KEYID_Z const int keyIDlength )
638  {
639  CHAIN_INFO chainInfo[ MAX_CHAINLENGTH + 8 ];
640  CERT_INFO *certChainPtr;
641  CHAINING_INFO chainingInfo;
642  int leafNodePos, newCertChainEnd, complianceLevel, status;
643 
644  assert( isWritePtr( iLeafCert, sizeof( CRYPT_CERTIFICATE ) ) );
645  assert( isWritePtr( iCertChain, \
646  sizeof( CRYPT_CERTIFICATE ) * certChainEnd ) );
647  assert( ( keyIDtype == CRYPT_KEYID_NONE && \
648  keyID == NULL && keyIDlength == 0 ) || \
649  ( ( keyIDtype == CRYPT_IKEYID_KEYID || \
650  keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
651  isReadPtr( keyID, keyIDlength ) ) );
652 
653  REQUIRES( certChainEnd > 0 && certChainEnd <= MAX_CHAINLENGTH );
654  REQUIRES( ( keyIDtype == CRYPT_KEYID_NONE && \
655  keyID == NULL && keyIDlength == 0 ) || \
656  ( ( keyIDtype == CRYPT_IKEYID_KEYID || \
657  keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
658  keyID != NULL && \
659  keyIDlength >= MIN_SKID_SIZE && \
660  keyIDlength < MAX_ATTRIBUTE_SIZE ) );
661 
662  /* Clear return value */
663  *iLeafCert = CRYPT_ERROR;
664 
665  status = krnlSendMessage( iCertChain[ 0 ], IMESSAGE_GETATTRIBUTE,
666  &complianceLevel,
668  if( cryptStatusError( status ) )
669  return( status );
670 
671  /* We start with a collection of certificates in unknown order (although
672  it's common for the first certificate to be the leaf). First we
673  extract the chaining information and search the chain for the leaf
674  node */
675  status = buildChainInfo( chainInfo, iCertChain, certChainEnd );
676  if( cryptStatusError( status ) )
677  return( status );
678  if( keyID != NULL )
679  {
680  leafNodePos = findIdentifiedLeafNode( chainInfo, certChainEnd,
681  keyIDtype, keyID, keyIDlength );
682  }
683  else
684  leafNodePos = findLeafNode( chainInfo, certChainEnd );
685  if( cryptStatusError( leafNodePos ) )
686  return( leafNodePos );
687  ENSURES( leafNodePos >= 0 && leafNodePos < certChainEnd );
688 
689  /* We've got the leaf node, remember the leaf certificate */
690  *iLeafCert = iCertChain[ leafNodePos ];
691  getIssuerChainingInfo( &chainingInfo, &chainInfo[ leafNodePos ] );
692 
693  /* Order the remaining certificates up to the root and discard any
694  unneeded certificates */
695  status = sortCertChain( iCertChain, &newCertChainEnd, chainInfo,
696  certChainEnd, leafNodePos, CRYPT_UNUSED, &chainingInfo,
697  ( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_FULL ) ? \
698  TRUE : FALSE );
699  if( cryptStatusError( status ) )
700  return( status );
701  if( newCertChainEnd <= 0 )
702  {
703  /* There's only one certificate in the chain either due to the
704  chain containing only a single certificate or due to all other
705  certificates being discarded, leave it as a standalone
706  certificate rather than turning it into a chain */
707  return( CRYPT_OK );
708  }
709 
710 #ifdef USE_CERTLEVEL_PKIX_FULL
711  /* Walk up the chain re-setting the pseudo-selfsigned flag on any
712  chain-internal path-kludge certificates if necessary. This means
713  that if the chain contains n certificates we reset the flag on
714  certificates 0...n-1. This is required when there's a re-issued
715  certificate kludged into the middle of the path to connect a new CA
716  signing key with a certificate signed with the old key. Note that
717  this can't detect the case where the first certificate in the chain
718  is a path kludge certificate with further certificates held
719  externally, e.g. in the trusted certificate store, since it appears
720  as a self-signed CA root certificate */
721  if( complianceLevel >= CRYPT_COMPLIANCELEVEL_PKIX_FULL )
722  {
723  int i;
724 
725  for( i = 0; i < newCertChainEnd - 1 && i < MAX_CHAINLENGTH; i++ )
726  {
728  int value;
729 
730  /* Check whether this is a self-signed certificate */
731  status = krnlSendMessage( iCertChain[ i ], IMESSAGE_GETATTRIBUTE,
732  &value, CRYPT_CERTINFO_SELFSIGNED );
733  if( cryptStatusError( status ) || !value )
734  continue;
735 
736  /* Convert the self-signed flag into the pseudo self-signed/path
737  kludge flag */
738  status = krnlAcquireObject( iCertChain[ i ], OBJECT_TYPE_CERTIFICATE,
739  ( void ** ) &certInfoPtr,
741  if( cryptStatusError( status ) )
742  continue;
743  certInfoPtr->flags &= ~CERT_FLAG_SELFSIGNED;
744  certInfoPtr->flags |= CERT_FLAG_PATHKLUDGE;
745  krnlReleaseObject( certInfoPtr->objectHandle );
746  }
747  ENSURES( i < MAX_CHAINLENGTH );
748  }
749 #endif /* USE_CERTLEVEL_PKIX_FULL */
750 
751  /* Finally, we've got the leaf certificate and a chain up to the root.
752  Make the leaf a certificate-chain type and copy in the chain */
753  status = krnlAcquireObject( *iLeafCert, OBJECT_TYPE_CERTIFICATE,
754  ( void ** ) &certChainPtr,
756  if( cryptStatusError( status ) )
757  return( status );
758  memcpy( certChainPtr->cCertCert->chain, iCertChain,
759  sizeof( CRYPT_CERTIFICATE ) * newCertChainEnd );
760  certChainPtr->cCertCert->chainEnd = newCertChainEnd;
761  certChainPtr->type = CRYPT_CERTTYPE_CERTCHAIN;
762  krnlReleaseObject( certChainPtr->objectHandle );
763 
764  return( CRYPT_OK );
765  }
766 
767 /****************************************************************************
768 * *
769 * Copy a Certificate Chain *
770 * *
771 ****************************************************************************/
772 
773 /* Determine whether a certificate is present in a certificate collection
774  based on its fingerprint */
775 
777 static BOOLEAN isCertPresent( INOUT_ARRAY( certChainLen ) \
778  BYTE certChainHashes[][ CRYPT_MAX_HASHSIZE + 8 ],
779  IN_RANGE( 0, MAX_CHAINLENGTH ) const int certChainLen,
781  {
783  int i, status;
784 
785  assert( isWritePtr( certChainHashes, \
786  MAX_CHAINLENGTH * CRYPT_MAX_HASHSIZE ) );
787 
788  REQUIRES_B( certChainLen >= 0 && certChainLen <= MAX_CHAINLENGTH );
789  /* Apparent length may be zero for a chain of size 1 since
790  the leaf certificate has the effective index value -1 */
791  REQUIRES_B( isHandleRangeValid( iCryptCert ) );
792 
793  /* Get the fingerprint of the (potential) next certificate in the
794  collection. This leaves it at the end of the existing collection of
795  hashes so that if the certificate is then added to the chain its hash
796  will also be present */
797  setMessageData( &msgData, certChainHashes[ certChainLen ],
799  status = krnlSendMessage( iCryptCert, IMESSAGE_GETATTRIBUTE_S,
800  &msgData, CRYPT_CERTINFO_FINGERPRINT );
801  if( cryptStatusError( status ) )
802  return( status );
803 
804  /* Make sure that it isn't already present in the collection */
805  for( i = 0; i < certChainLen && i < MAX_CHAINLENGTH; i++ )
806  {
807  if( !memcmp( certChainHashes[ i ],
808  certChainHashes[ certChainLen ], msgData.length ) )
809  return( TRUE );
810  }
811  return( FALSE );
812  }
813 
814 /* Copy a certificate chain into a certificate object and canonicalise the
815  chain by ordering the certificates from the leaf certificate up to the
816  root. This function is used when signing a certificate with a certificate
817  chain and takes as input ( oldCert, oldCert.chain[ ... ] ) and produces
818  as output ( newCert, chain[ oldCert, oldCert.chain[ ... ] ], i.e. the
819  chain for the new certificate contains the old certificate and its
820  attached certificate chain */
821 
823 int copyCertChain( INOUT CERT_INFO *certInfoPtr,
825  const BOOLEAN isCertCollection )
826  {
827  CRYPT_CERTIFICATE iChainCert;
828  CERT_INFO *chainCertInfoPtr;
829  CERT_CERT_INFO *destCertChainInfo = certInfoPtr->cCertCert;
830  CERT_CERT_INFO *srcCertChainInfo;
831  CHAIN_INFO chainInfo[ MAX_CHAINLENGTH + 8 ];
832  BYTE certChainHashes[ MAX_CHAINLENGTH + 1 + 8 ][ CRYPT_MAX_HASHSIZE + 8 ];
833  const int oldChainEnd = destCertChainInfo->chainEnd;
834  int i, status;
835 
836  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
837 
838  REQUIRES( isHandleRangeValid( certChain ) );
839 
840  status = krnlSendMessage( certChain, IMESSAGE_GETDEPENDENT, &iChainCert,
842  if( cryptStatusError( status ) )
843  return( status );
844 
845  /* If we're building a certificate collection all that we need to ensure
846  is non-duplicate certificates rather than a strict chain. To handle
847  duplicate checking we build a list of the fingerprints for each
848  certificate in the chain */
849  if( isCertCollection )
850  {
851  for( i = 0; i < destCertChainInfo->chainEnd && i < MAX_CHAINLENGTH; i++ )
852  {
854 
855  setMessageData( &msgData, certChainHashes[ i ],
857  status = krnlSendMessage( destCertChainInfo->chain[ i ],
858  IMESSAGE_GETATTRIBUTE_S, &msgData,
860  if( cryptStatusError( status ) )
861  return( status );
862  }
863  ENSURES( i < MAX_CHAINLENGTH );
864  }
865 
866  /* Extract the base certificate from the chain and copy it over (the
867  isCertPresent() check also sets up the hash for the new certificate
868  in the certChainHashes array) */
869  status = krnlAcquireObject( iChainCert, OBJECT_TYPE_CERTIFICATE,
870  ( void ** ) &chainCertInfoPtr,
872  if( cryptStatusError( status ) )
873  return( status );
874  srcCertChainInfo = chainCertInfoPtr->cCertCert;
875  if( !isCertCollection || \
876  !isCertPresent( certChainHashes, destCertChainInfo->chainEnd, \
877  iChainCert ) )
878  {
879  if( destCertChainInfo->chainEnd >= MAX_CHAINLENGTH )
880  {
881  krnlReleaseObject( chainCertInfoPtr->objectHandle );
882  return( CRYPT_ERROR_OVERFLOW );
883  }
884  krnlSendNotifier( iChainCert, IMESSAGE_INCREFCOUNT );
885  destCertChainInfo->chain[ destCertChainInfo->chainEnd++ ] = iChainCert;
886  }
887 
888  /* Copy the rest of the chain. Because we're about to canonicalise it
889  (which re-orders the certificates and deletes unused ones) we copy
890  individual certificates over rather than copying only the base
891  certificate and relying on the chain held in that */
892  for( i = 0; i < srcCertChainInfo->chainEnd && i < MAX_CHAINLENGTH; i++ )
893  {
894  const CRYPT_CERTIFICATE iCopyCert = srcCertChainInfo->chain[ i ];
895 
896  /* If it's an (unordered) certificate collection, make sure that
897  there are no duplicates */
898  if( isCertCollection && \
899  isCertPresent( certChainHashes, destCertChainInfo->chainEnd,
900  srcCertChainInfo->chain[ i ] ) )
901  continue;
902 
903  /* Copy the next certificate from the source to the destination */
904  if( destCertChainInfo->chainEnd >= MAX_CHAINLENGTH )
905  {
906  status = CRYPT_ERROR_OVERFLOW;
907  break;
908  }
910  destCertChainInfo->chain[ destCertChainInfo->chainEnd++ ] = iCopyCert;
911  }
912  ENSURES( i < MAX_CHAINLENGTH );
913  srcCertChainInfo = NULL; /* Make the release explicit */
914  krnlReleaseObject( chainCertInfoPtr->objectHandle );
915  if( cryptStatusError( status ) )
916  {
917  /* An error at this point indicates that the upper limit on chain
918  length isn't sufficient so we throw a (debug) exception if we
919  get here */
920  DEBUG_DIAG(( "Maximum chain length %d exceeded", MAX_CHAINLENGTH ));
921  assert( DEBUG_WARN );
922 
923  /* Clean up the newly-copied certificates if necessary */
924  if( destCertChainInfo->chainEnd > oldChainEnd )
925  {
926  freeCertChain( &destCertChainInfo->chain[ oldChainEnd ],
927  destCertChainInfo->chainEnd - oldChainEnd );
928  }
929 
930  return( status );
931  }
932 
933  /* If we're building an unordered certificate collection, mark the
934  certificate chain object as a certificate collection only and exit.
935  This is a pure container object for which only the certificate chain
936  member contains certificates, the base certificate object doesn't
937  correspond to an actual certificate */
938  if( isCertCollection )
939  {
940  certInfoPtr->flags |= CERT_FLAG_CERTCOLLECTION;
941  return( CRYPT_OK );
942  }
943 
944  /* If the chain being attached consists of a single certificate (which
945  occurs when we're building a new chain by signing a certificate with
946  a CA certificate) we don't have to bother doing anything else */
947  if( oldChainEnd <= 0 )
948  return( CRYPT_OK );
949 
950  /* Extract the chaining information from each certificate and use it to
951  sort the chain. Since we know what the leaf certificate is and since
952  chaining information such as the encoded DN data in the certinfo
953  structure may not have been set up yet if it contains an unsigned
954  certificate we feed in the leaf certificate and omit the chaining
955  information */
956  status = buildChainInfo( chainInfo, destCertChainInfo->chain,
957  destCertChainInfo->chainEnd );
958  if( cryptStatusError( status ) )
959  {
960  /* Clean up the newly-copied certificates if necessary */
961  if( destCertChainInfo->chainEnd > oldChainEnd )
962  {
963  freeCertChain( &destCertChainInfo->chain[ oldChainEnd ],
964  destCertChainInfo->chainEnd - oldChainEnd );
965  }
966 
967  return( status );
968  }
969  return( sortCertChain( destCertChainInfo->chain, &destCertChainInfo->chainEnd,
970  chainInfo, destCertChainInfo->chainEnd, CRYPT_UNUSED,
971  iChainCert, NULL, FALSE ) );
972  }
973 
974 /****************************************************************************
975 * *
976 * Read Certificate-bagging Records *
977 * *
978 ****************************************************************************/
979 
980 /* Read the PKCS #7/CMS wrapper for a certificate chain */
981 
983 static int readCertChainWrapper( INOUT STREAM *stream )
984  {
985  BYTE oid[ MAX_OID_SIZE + 8 ];
986  long integer;
987  int length, oidLength, status;
988 
989  assert( isWritePtr( stream, sizeof( STREAM ) ) );
990 
991  /* Skip the contentType OID, read the content encapsulation and header
992  if necessary, and burrow down into the PKCS #7/CMS content. We use
993  readEncodedOID() when reading the wrapper rather than readUniversal()
994  to make sure that we're at least getting an OID at this point */
995  status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
997  if( cryptStatusError( status ) )
998  return( status );
999  readConstructed( stream, NULL, 0 );
1000  readSequence( stream, NULL );
1001 
1002  /* Read the version number (1 = PKCS #7 v1.5, 2 = PKCS #7 v1.6 (never
1003  proceeded beyond the draft stage), 3 = S/MIME with attribute
1004  certificate(s)), and (should be empty) SET OF
1005  DigestAlgorithmIdentifier */
1006  readShortInteger( stream, &integer );
1007  status = readSet( stream, &length );
1008  if( cryptStatusError( status ) )
1009  return( status );
1010  if( integer < 1 || integer > 3 )
1011  return( CRYPT_ERROR_BADDATA );
1012  if( length > 0 )
1013  sSkip( stream, length );
1014 
1015  /* Read the ContentInfo header, contentType OID (ignored) and the inner
1016  content encapsulation. We again use readEncodedOID() rather than
1017  readUniversal() to make sure that we're at least getting an OID at
1018  this point.
1019 
1020  Sometimes we may (incorrectly) get passed actual signed data rather
1021  than degenerate zero-length data signifying a pure certificate chain,
1022  if there's data present then we skip it */
1023  readSequenceI( stream, &length );
1024  status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength,
1026  if( cryptStatusError( status ) )
1027  return( status );
1028  if( length != CRYPT_UNUSED )
1029  {
1030  /* We've got definite-length data, see if there's any content
1031  present alongside the contentType OID. If it's a correctly-
1032  formatted certificate chain (i.e. the content is zero-length)
1033  we're done */
1034  length -= oidLength;
1035  if( length < 0 || length > MAX_INTLENGTH )
1036  return( CRYPT_ERROR_BADDATA );
1037  if( length == 0 )
1038  return( CRYPT_OK );
1039 
1040  /* The ContentInfo has the content field present, it may be signed
1041  data (with attached certificates) being passed in for use as a
1042  certificate chain, skip the content to get to the chain */
1043  return( readUniversal( stream ) );
1044  }
1045 
1046  /* It's an indefinite-length ContentInfo, check for the EOC. If there's
1047  no EOC present that means that there's indefinite-length inner data
1048  present and we have to dig down further */
1049  status = checkEOC( stream );
1050  if( cryptStatusError( status ) )
1051  return( status );
1052  if( status == FALSE )
1053  {
1054  int innerLength;
1055 
1056  /* Try and get the length from the ContentInfo. We're really
1057  reaching the point of diminishing returns here, if we can't get a
1058  length at this point we bail out since we're not even supposed to
1059  be getting down to this level */
1060  status = readConstructedI( stream, &innerLength, 0 );
1061  if( cryptStatusError( status ) )
1062  return( status );
1063  if( innerLength == CRYPT_UNUSED )
1064  return( CRYPT_ERROR_BADDATA );
1065  return( sSkip( stream, innerLength ) );
1066  }
1067 
1068  return( CRYPT_OK );
1069  }
1070 
1071 /* Read a single certificate in a chain */
1072 
1074 static int readSingleCert( INOUT STREAM *stream,
1075  OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCryptCert,
1077  IN_ENUM( CRYPT_CERTTYPE ) const CRYPT_CERTTYPE_TYPE type,
1078  const BOOLEAN dataOnlyCert,
1079  const BOOLEAN isIndefiniteLength )
1080  {
1081  int length, status;
1082 
1083  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1084  assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );
1085 
1086  REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
1087  isHandleRangeValid( iCryptOwner ) );
1088  REQUIRES( type == CRYPT_CERTTYPE_CERTCHAIN || \
1089  type == CRYPT_ICERTTYPE_CMS_CERTSET || \
1090  type == CRYPT_ICERTTYPE_SSL_CERTCHAIN );
1091 
1092  /* Clear return value */
1093  *iCryptCert = CRYPT_ERROR;
1094 
1095  /* If it's an SSL certificate chain then there's a 24-bit length field
1096  between certificates */
1097  if( type == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
1098  {
1099  status = sSkip( stream, 3 );
1100  if( cryptStatusError( status ) )
1101  return( status );
1102  }
1103 
1104  /* Find out how large the certificate data is */
1105  status = getStreamObjectLength( stream, &length );
1106  if( cryptStatusError( status ) )
1107  return( status );
1108 
1109  /* Since SSL certificate chains contain certificates interspersed with
1110  non-certificate SSL length data the higher-level code can't check the
1111  encoding, so we have to perform the check here. Technically this
1112  isn't really necessary since importCertFromStream() imports the
1113  certificate via a kernel message which means that the encoding is
1114  checked anyway, but this is an implementation-specific detail that we
1115  can't assume will hold for future versions so we make the check
1116  explicit here */
1117  if( type == CRYPT_ICERTTYPE_SSL_CERTCHAIN )
1118  {
1119  void *certDataPtr;
1120  int complianceLevel;
1121 
1122  status = krnlSendMessage( iCryptOwner, IMESSAGE_GETATTRIBUTE,
1123  &complianceLevel,
1125  if( cryptStatusError( status ) )
1126  return( status );
1127  if( complianceLevel > CRYPT_COMPLIANCELEVEL_OBLIVIOUS )
1128  {
1129  status = sMemGetDataBlock( stream, &certDataPtr, length );
1130  if( cryptStatusOK( status ) && \
1131  cryptStatusError( \
1132  checkObjectEncoding( certDataPtr, length ) ) )
1133  status = CRYPT_ERROR_BADDATA;
1134  }
1135  if( cryptStatusError( status ) )
1136  return( status );
1137  }
1138 
1139  /* Read the next certificate and add it to the chain. When importing
1140  the chain from an external (untrusted) source we create standard
1141  certificates so that we can check the signatures on each link in the
1142  chain. When importing from a trusted source we create data-only
1143  certificates, once we've got all of the certificates and know which
1144  certificate is the leaf we can go back and decode the public key
1145  information for it */
1146  status = importCertFromStream( stream, iCryptCert, iCryptOwner,
1147  dataOnlyCert ? \
1148  CRYPT_ICERTTYPE_DATAONLY : \
1149  CRYPT_CERTTYPE_CERTIFICATE, length );
1150  if( cryptStatusError( status ) )
1151  return( status );
1152 
1153  /* If the certificate chain is encoded using the indefinite form and we
1154  find the EOC octets following the certificate that we've just read,
1155  tell the caller */
1156  if( isIndefiniteLength )
1157  {
1158  status = checkEOC( stream );
1159  if( cryptStatusError( status ) )
1160  {
1161  krnlSendNotifier( *iCryptCert, IMESSAGE_DECREFCOUNT );
1162  *iCryptCert = CRYPT_ERROR;
1163  return( status );
1164  }
1165  if( status == TRUE )
1166  {
1167  /* We've seen EOC octets, tell the caller that we're done */
1168  return( OK_SPECIAL );
1169  }
1170  }
1171 
1172  return( CRYPT_OK );
1173  }
1174 
1175 /* Read certificate chain/sequence information */
1176 
1177 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1178 int readCertChain( INOUT STREAM *stream,
1179  OUT_HANDLE_OPT CRYPT_CERTIFICATE *iCryptCert,
1180  IN_HANDLE const CRYPT_USER iCryptOwner,
1181  IN_ENUM( CRYPT_CERTTYPE ) const CRYPT_CERTTYPE_TYPE type,
1182  IN_KEYID_OPT const CRYPT_KEYID_TYPE keyIDtype,
1183  IN_BUFFER_OPT( keyIDlength ) const void *keyID,
1184  IN_LENGTH_KEYID_Z const int keyIDlength,
1185  const BOOLEAN dataOnlyCert )
1186  {
1187  CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH + 8 ];
1188  int certSequenceLength = DUMMY_INIT, endPos = 0, certChainEnd = 0;
1189  int iterationCount, status;
1190 
1191  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1192  assert( isWritePtr( iCryptCert, sizeof( CRYPT_CERTIFICATE ) ) );
1193  assert( ( keyIDtype == CRYPT_KEYID_NONE && keyID == NULL && \
1194  keyIDlength == 0 ) || \
1195  ( ( keyIDtype == CRYPT_IKEYID_KEYID || \
1196  keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
1197  isReadPtr( keyID, keyIDlength ) && \
1198  keyIDlength >= MIN_SKID_SIZE ) );
1199 
1200  REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
1201  isHandleRangeValid( iCryptOwner ) );
1202  REQUIRES( type == CRYPT_CERTTYPE_CERTCHAIN || \
1203  type == CRYPT_ICERTTYPE_CMS_CERTSET || \
1204  type == CRYPT_ICERTTYPE_SSL_CERTCHAIN );
1205  REQUIRES( ( keyIDtype == CRYPT_KEYID_NONE && \
1206  keyID == NULL && keyIDlength == 0 ) || \
1207  ( ( keyIDtype == CRYPT_IKEYID_KEYID || \
1208  keyIDtype == CRYPT_IKEYID_ISSUERANDSERIALNUMBER ) && \
1209  keyID != NULL && \
1210  keyIDlength >= MIN_SKID_SIZE && \
1211  keyIDlength < MAX_ATTRIBUTE_SIZE ) );
1212 
1213  /* Clear return value */
1214  *iCryptCert = CRYPT_ERROR;
1215 
1216  switch( type )
1217  {
1219  status = readCertChainWrapper( stream );
1220  if( cryptStatusError( status ) )
1221  break;
1222  /* Fall through */
1223 
1224  case CRYPT_ICERTTYPE_CMS_CERTSET:
1225  status = readConstructedI( stream, &certSequenceLength, 0 );
1226  break;
1227 
1228  case CRYPT_ICERTTYPE_SSL_CERTCHAIN:
1229  /* There's no outer wrapper to give us length information for an
1230  SSL certificate chain, however the length will be equal to the
1231  total remaining stream size */
1232  certSequenceLength = sMemDataLeft( stream );
1233  status = CRYPT_OK;
1234  break;
1235 
1236  default:
1237  retIntError();
1238  }
1239  if( cryptStatusError( status ) )
1240  return( status );
1241 
1242  /* If it's a definite-length chain, determine where it ends */
1243  if( certSequenceLength != CRYPT_UNUSED )
1244  endPos = stell( stream ) + certSequenceLength;
1245 
1246  /* We've reached the certificate(s), read the collection of certificates
1247  into certificate objects. We allow for a bit of slop for software
1248  that gets the length encoding wrong by a few bytes. Note that the
1249  limit is given as FAILSAFE_ITERATIONS_MED since we're using it as a
1250  fallback check on the existing MAX_CHAINLENGTH check. In other words
1251  anything over MAX_CHAINLENGTH is handled as a normal error and it's
1252  only if we exceed this that we have an internal error */
1253  for( iterationCount = 0;
1254  ( certSequenceLength == CRYPT_UNUSED || \
1255  stell( stream ) <= endPos - MIN_ATTRIBUTE_SIZE ) && \
1256  iterationCount < FAILSAFE_ITERATIONS_MED;
1257  iterationCount++ )
1258  {
1259  CRYPT_CERTIFICATE iNewCert = DUMMY_INIT;
1260 
1261  /* Make sure that we don't overflow the chain */
1262  if( certChainEnd >= MAX_CHAINLENGTH )
1263  {
1264  freeCertChain( iCertChain, certChainEnd );
1265  return( CRYPT_ERROR_OVERFLOW );
1266  }
1267 
1268  /* Read the next certificate in the chain */
1269  status = readSingleCert( stream, &iNewCert, iCryptOwner, type,
1270  dataOnlyCert,
1271  ( certSequenceLength == CRYPT_UNUSED ) ? \
1272  TRUE : FALSE );
1273  if( cryptStatusError( status ) && status != OK_SPECIAL )
1274  {
1275  if( certChainEnd > 0 )
1276  freeCertChain( iCertChain, certChainEnd );
1277  return( status );
1278  }
1279  iCertChain[ certChainEnd++ ] = iNewCert;
1280  if( status == OK_SPECIAL )
1281  break; /* We've reached the end of the chain */
1282  }
1283  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
1284 
1285  /* We must have read at least one certificate in order to create a
1286  chain */
1287  if( certChainEnd <= 0 )
1288  return( CRYPT_ERROR_BADDATA );
1289 
1290  /* Build the complete chain from the individual certificates */
1291  status = buildCertChain( iCryptCert, iCertChain, certChainEnd,
1292  keyIDtype, keyID, keyIDlength );
1293  if( cryptStatusError( status ) )
1294  {
1295  freeCertChain( iCertChain, certChainEnd );
1296  return( status );
1297  }
1298 
1299  return( CRYPT_OK );
1300  }
1301 
1302 /* Fetch a sequence of certificates from an object to create a certificate
1303  chain */
1304 
1305 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
1306 int assembleCertChain( OUT CRYPT_CERTIFICATE *iCertificate,
1308  IN_KEYID const CRYPT_KEYID_TYPE keyIDtype,
1309  IN_BUFFER( keyIDlength ) const void *keyID,
1310  IN_LENGTH_KEYID const int keyIDlength,
1311  IN_FLAGS( KEYMGMT ) const int options )
1312  {
1313  CRYPT_CERTIFICATE iCertChain[ MAX_CHAINLENGTH + 8 ], lastCert;
1314  MESSAGE_KEYMGMT_INFO getnextcertInfo;
1315  const int chainOptions = options & KEYMGMT_FLAG_DATAONLY_CERT;
1316  int stateInfo = CRYPT_ERROR, certChainEnd = 1;
1317  int iterationCount, status;
1318 
1319  assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
1320  assert( isReadPtr( keyID, keyIDlength ) && \
1321  keyIDlength >= MIN_NAME_LENGTH && \
1322  keyIDlength < MAX_ATTRIBUTE_SIZE );
1323 
1324  REQUIRES( isHandleRangeValid( iCertSource ) );
1325  REQUIRES( keyIDtype > CRYPT_KEYID_NONE && \
1326  keyIDtype < CRYPT_KEYID_LAST );
1327  REQUIRES( keyIDlength >= MIN_NAME_LENGTH && \
1328  keyIDlength < MAX_ATTRIBUTE_SIZE );
1329  REQUIRES( options >= KEYMGMT_FLAG_NONE && options < KEYMGMT_FLAG_MAX && \
1330  ( options & ~KEYMGMT_MASK_CERTOPTIONS ) == 0 );
1331 
1332  /* Get the initial certificate based on the key ID */
1333  setMessageKeymgmtInfo( &getnextcertInfo, keyIDtype, keyID, keyIDlength,
1334  &stateInfo, sizeof( int ),
1335  options & KEYMGMT_MASK_CERTOPTIONS );
1336  status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETFIRSTCERT,
1337  &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
1338  if( cryptStatusError( status ) )
1339  return( status );
1340  iCertChain[ 0 ] = lastCert = getnextcertInfo.cryptHandle;
1341 
1342  /* Fetch subsequent certificates that make up the chain based on the
1343  state information. Since the basic options apply only to the leaf
1344  certificate we only allow the data-only certificate flag at this
1345  point. See the comment in readCertChain() for the use of
1346  FAILSAFE_ITERATIONS_MED for the bounds check */
1347  setMessageKeymgmtInfo( &getnextcertInfo, CRYPT_KEYID_NONE, NULL, 0,
1348  &stateInfo, sizeof( int ), chainOptions );
1349  for( iterationCount = 0;
1350  cryptStatusOK( status ) && \
1351  iterationCount < FAILSAFE_ITERATIONS_MED;
1352  iterationCount++ )
1353  {
1354  int selfSigned;
1355 
1356  /* If we've reached a self-signed (CA root) certificate, stop. Note
1357  that this can't detect PKIX path-kludge certificates which look
1358  identical to CA root certificates and can only be reliably
1359  identified if they're present in the middle of a pre-built
1360  chain */
1361  status = krnlSendMessage( lastCert, IMESSAGE_GETATTRIBUTE,
1362  &selfSigned, CRYPT_CERTINFO_SELFSIGNED );
1363  if( cryptStatusError( status ) || selfSigned > 0 )
1364  break;
1365 
1366  /* Get the next certificate in the chain from the source, import it,
1367  and add it to the collection */
1368  getnextcertInfo.cryptHandle = CRYPT_ERROR; /* Reset result handle */
1369  status = krnlSendMessage( iCertSource, IMESSAGE_KEY_GETNEXTCERT,
1370  &getnextcertInfo, KEYMGMT_ITEM_PUBLICKEY );
1371  if( cryptStatusError( status ) )
1372  {
1373  /* If we get a notfound error this is OK since it just means
1374  that we've reached the end of the chain */
1375  if( status == CRYPT_ERROR_NOTFOUND )
1376  status = CRYPT_OK;
1377 
1378  break;
1379  }
1380 
1381  /* Make sure that we don't overflow the chain */
1382  if( certChainEnd >= MAX_CHAINLENGTH )
1383  {
1384  krnlSendNotifier( getnextcertInfo.cryptHandle,
1386  status = CRYPT_ERROR_OVERFLOW;
1387  break;
1388  }
1389 
1390  iCertChain[ certChainEnd++ ] = lastCert = getnextcertInfo.cryptHandle;
1391  }
1392  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
1393  if( cryptStatusError( status ) )
1394  {
1395  freeCertChain( iCertChain, certChainEnd );
1396  return( status );
1397  }
1398 
1399  /* Build the complete chain from the individual certificates */
1400  status = buildCertChain( iCertificate, iCertChain, certChainEnd,
1401  CRYPT_KEYID_NONE, NULL, 0 );
1402  if( cryptStatusError( status ) )
1403  {
1404  freeCertChain( iCertChain, certChainEnd );
1405  return( status );
1406  }
1407 
1408  return( CRYPT_OK );
1409  }
1410 
1411 /****************************************************************************
1412 * *
1413 * Write Certificate-bagging Records *
1414 * *
1415 ****************************************************************************/
1416 
1417 /* Determine the size of and write a certificate path from a base
1418  certificate up to the root. This gets a bit complicated because
1419  alongside the overall length, SSL requires that we return component-by-
1420  component lengths that need to be inserted as 24-bit (3 byte) values
1421  between each certificate. To handle this we take as an optional
1422  parameter an array used to store the individual path component lengths */
1423 
1424 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1425 static int sizeofCertPath( const CERT_INFO *certInfoPtr,
1426  OUT_LENGTH_SHORT_Z int *certPathLength,
1427  OUT_ARRAY_OPT_C( MAX_CHAINLENGTH ) int *certSizeInfo )
1428  {
1429  CERT_CERT_INFO *certChainInfo = certInfoPtr->cCertCert;
1430  int length = 0, i;
1431 
1432  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1433  assert( isWritePtr( certPathLength, sizeof( int ) ) );
1434  assert( certSizeInfo == NULL || \
1435  isWritePtr( certSizeInfo, sizeof( int ) * MAX_CHAINLENGTH ) );
1436 
1437  /* Clear return values */
1438  *certPathLength = 0;
1439  if( certSizeInfo != NULL )
1440  memset( certSizeInfo, 0, sizeof( int ) * MAX_CHAINLENGTH );
1441 
1442  /* Evaluate the size of the current certificate and the issuer
1443  certificates in the chain. If it's a certificate collection it's
1444  just a container for random certificates but not a certificate in its
1445  own right so we skip the leaf certificate */
1446  if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
1447  {
1448  length = certInfoPtr->certificateSize;
1449  if( certSizeInfo != NULL )
1450  length += 3;
1451  }
1452  for( i = 0; i < certChainInfo->chainEnd && i < MAX_CHAINLENGTH; i++ )
1453  {
1455  int status;
1456 
1457  setMessageData( &msgData, NULL, 0 );
1458  status = krnlSendMessage( certChainInfo->chain[ i ],
1459  IMESSAGE_CRT_EXPORT, &msgData,
1461  if( cryptStatusError( status ) )
1462  return( status );
1463  length += msgData.length;
1464  if( certSizeInfo != NULL )
1465  {
1466  certSizeInfo[ i ] = msgData.length;
1467  length += 3;
1468  }
1469  }
1470  ENSURES( i < MAX_CHAINLENGTH );
1471  *certPathLength = length;
1472 
1473  return( CRYPT_OK );
1474  }
1475 
1476 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1477 static int writeCertPath( INOUT STREAM *stream,
1478  const CERT_INFO *certInfoPtr,
1479  IN_ARRAY_OPT_C( MAX_CHAINLENGTH ) \
1480  const int *certSizeInfo )
1481 
1482  {
1483  CERT_CERT_INFO *certChainInfo = certInfoPtr->cCertCert;
1484  int i, status = CRYPT_OK;
1485 
1486  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1487  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1488  assert( certSizeInfo == NULL || \
1489  isReadPtr( certSizeInfo, sizeof( int ) * MAX_CHAINLENGTH ) );
1490 
1491  /* Write the current certificate and the associated certificate chain up
1492  to the root. If it's a certificate collection it's just a container
1493  for random certificates but not a certificate in its own right so we
1494  skip the leaf certificate */
1495  if( !( certInfoPtr->flags & CERT_FLAG_CERTCOLLECTION ) )
1496  {
1497  if( certSizeInfo != NULL )
1498  {
1499  sputc( stream, 0 );
1500  writeUint16( stream, certInfoPtr->certificateSize );
1501  }
1502  status = swrite( stream, certInfoPtr->certificate,
1503  certInfoPtr->certificateSize );
1504  }
1505  for( i = 0; cryptStatusOK( status ) && \
1506  i < certChainInfo->chainEnd && \
1507  i < MAX_CHAINLENGTH; i++ )
1508  {
1509  if( certSizeInfo != NULL )
1510  {
1511  sputc( stream, 0 );
1512  writeUint16( stream, certSizeInfo[ i ] );
1513  }
1514  status = exportCertToStream( stream, certChainInfo->chain[ i ],
1516  }
1517  ENSURES( i < MAX_CHAINLENGTH );
1518 
1519  return( status );
1520  }
1521 
1522 /* Write certificate chain/sequence information:
1523 
1524  CertChain ::= SEQUENCE {
1525  contentType OBJECT IDENTIFIER, -- signedData
1526  content [ 0 ] EXPLICIT SEQUENCE {
1527  version INTEGER (1),
1528  digestAlgorithms SET OF AlgorithmIdentifier, -- SIZE(0)
1529  contentInfo SEQUENCE {
1530  signedData OBJECT IDENTIFIER -- data
1531  }
1532  certificates [ 0 ] SET OF {
1533  Certificate
1534  }
1535  }
1536  signerInfos SET OF SignerInfo -- SIZE(0)
1537  } */
1538 
1539 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
1540 int sizeofCertCollection( const CERT_INFO *certInfoPtr,
1541  IN_ENUM( CRYPT_CERTFORMAT ) \
1542  const CRYPT_CERTFORMAT_TYPE certFormatType )
1543  {
1544  int length, status;
1545 
1546  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1547 
1548  REQUIRES( certFormatType == CRYPT_ICERTFORMAT_CERTSET || \
1549  certFormatType == CRYPT_ICERTFORMAT_CERTSEQUENCE || \
1550  certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN );
1551 
1552  /* If it's an SSL certificate chain then we have to pass in a dummy
1553  component-length pointer to ensure that it's evaluated as an SSL
1554  chain with intermediate lengths rather than a straight PKCS #7/CMS
1555  chain */
1556  if( certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN )
1557  {
1558  int certSizeInfo[ MAX_CHAINLENGTH + 8 ];
1559 
1560  status = sizeofCertPath( certInfoPtr, &length, certSizeInfo );
1561  }
1562  else
1563  {
1564  /* It's a standard PKCS #7/CMS chain */
1565  status = sizeofCertPath( certInfoPtr, &length, NULL );
1566  if( cryptStatusError( status ) )
1567  return( status );
1568  status = length = sizeofObject( length );
1569  }
1570  if( cryptStatusError( status ) )
1571  return( status );
1572  return( length );
1573  }
1574 
1575 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1576 int writeCertCollection( INOUT STREAM *stream,
1577  const CERT_INFO *certInfoPtr,
1578  IN_ENUM( CRYPT_CERTFORMAT ) \
1579  const CRYPT_CERTFORMAT_TYPE certFormatType )
1580  {
1581  int certSizeInfo[ MAX_CHAINLENGTH + 8 ];
1582  int *certSizePtr = \
1583  ( certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN ) ? \
1584  certSizeInfo : NULL;
1585  int certCollectionLength, status;
1586 
1587  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1588  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1589 
1590  REQUIRES( certFormatType == CRYPT_ICERTFORMAT_CERTSET || \
1591  certFormatType == CRYPT_ICERTFORMAT_CERTSEQUENCE || \
1592  certFormatType == CRYPT_ICERTFORMAT_SSL_CERTCHAIN );
1593 
1594  status = sizeofCertPath( certInfoPtr, &certCollectionLength,
1595  certSizePtr );
1596  if( cryptStatusError( status ) )
1597  return( status );
1598  switch( certFormatType )
1599  {
1600  case CRYPT_ICERTFORMAT_CERTSET:
1601  writeConstructed( stream, certCollectionLength, 0 );
1602  break;
1603 
1604  case CRYPT_ICERTFORMAT_CERTSEQUENCE:
1605  writeSequence( stream, certCollectionLength );
1606  break;
1607 
1608  case CRYPT_ICERTFORMAT_SSL_CERTCHAIN:
1609  break;
1610 
1611  default:
1612  retIntError();
1613  }
1614  return( writeCertPath( stream, certInfoPtr, certSizePtr ) );
1615  }
1616 
1617 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
1618 int writeCertChain( INOUT STREAM *stream,
1619  const CERT_INFO *certInfoPtr )
1620  {
1621  int certSetLength, innerLength, status;
1622 
1623  assert( isWritePtr( stream, sizeof( STREAM ) ) );
1624  assert( isReadPtr( certInfoPtr, sizeof( CERT_INFO ) ) );
1625 
1626  status = sizeofCertPath( certInfoPtr, &certSetLength, NULL );
1627  if( cryptStatusError( status ) )
1628  return( status );
1629 
1630  /* Determine how big the encoded certificate chain/sequence will be */
1631  innerLength = sizeofShortInteger( 1 ) + ( int ) sizeofObject( 0 ) + \
1632  ( int ) sizeofObject( sizeofOID( OID_CMS_DATA ) ) + \
1633  ( int ) sizeofObject( certSetLength ) + \
1634  ( int ) sizeofObject( 0 );
1635 
1636  /* Write the outer SEQUENCE wrapper, contentType, and content wrapper */
1637  writeSequence( stream,
1639  ( int ) sizeofObject( sizeofObject( innerLength ) ) );
1640  swrite( stream, OID_CMS_SIGNEDDATA, sizeofOID( OID_CMS_SIGNEDDATA ) );
1641  writeConstructed( stream, sizeofObject( innerLength ), 0 );
1642  writeSequence( stream, innerLength );
1643 
1644  /* Write the inner content */
1645  writeShortInteger( stream, 1, DEFAULT_TAG );
1646  writeSet( stream, 0 );
1647  writeSequence( stream, sizeofOID( OID_CMS_DATA ) );
1648  swrite( stream, OID_CMS_DATA, sizeofOID( OID_CMS_DATA ) );
1649  writeConstructed( stream, certSetLength, 0 );
1650  status = writeCertPath( stream, certInfoPtr, NULL );
1651  if( cryptStatusOK( status ) )
1652  status = writeSet( stream, 0 );
1653  return( status );
1654  }
1655 #endif /* USE_CERTIFICATES */