cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
write_pre.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate Write Preparation 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 #else
13  #include "cert/cert.h"
14  #include "enc_dec/asn1.h"
15  #include "enc_dec/asn1_ext.h"
16 #endif /* Compiler-specific includes */
17 
18 /* Before we encode a certificate object we have to perform various final
19  setup actions and check that the object is ready for encoding. The setup
20  operations and checks for the different object types are:
21 
22  | Cert | Attr | P10 |Cr.Req |Rv.Req
23  ------------+-------+-------+-------+-------+-------+
24  STDATTR | X[1]| | | | | Setup
25  ISSUERATTR | X | X | | | | action
26  ISSUERDN | X | X | | | |
27  VALPERIOD | X | X | | | |
28  VALINFO | | | | | |
29  REVINFO | | | | | |
30  ------------+-------+-------+-------+-------+-------+
31  SPKI | X | | X | X | | Check
32  DN | X | X | | | |
33  DN_PART | | | X | X | |
34  ISSUERDN | X | X | | | X |
35  ISSUERCRTDN | | | | | |
36  NON_SELFSD | X | X | | | |
37  SERIALNO | X | X | | | X |
38  REVENTRIES | | | | | |
39  ------------+-------+-------+-------+-------+-------+
40 
41  |RTCS Rq|RTCS Rs|OCSP Rq|OCSP Rs| CRL |CRLentr|
42  ------------+-------+-------+-------+-------+-------+-------+
43  STDATTR | | | | | | | Setup
44  ISSUERATTR | | | | | X | | action
45  ISSUERDN | | | | | X | |
46  VALPERIOD | | | | | | |
47  VALINFO | X | | | | | |
48  REVINFO | | | X | | X | X |
49  ------------+-------+-------+-------+-------+-------+-------+
50  SPKI | | | | | | | Check
51  DN | | | | X | | |
52  DN_PART | | | | | | |
53  ISSUERDN | | | | | X | |
54  ISSUERCRTDN | | | | | X | |
55  NON_SELFSD | | | | | | |
56  SERIALNO | | | | | | |
57  VALENTRIES | X | | | | | |
58  REVENTRIES | | | X | X | | |
59  ------------+-------+-------+-------+-------+-------+-------+
60 
61  We have to be careful here to avoid race conditions when some of the
62  checks depend on setup actions having been performed first but some of
63  the setup actions require that checks be performed first. The noted
64  exceptions are:
65 
66  [1] Requires that the SPKI check be performed first since STDATTR
67  evaluates keyUsage from the SPKI */
68 
69 #ifdef USE_CERTIFICATES
70 
71 /****************************************************************************
72 * *
73 * Utility Functions *
74 * *
75 ****************************************************************************/
76 
77 /* Add standard X.509v3 extensions to a certificate if they're not already
78  present. This function simply adds the required extensions, it doesn't
79  check for consistency with existing extensions which is done later by
80  checkAttributes() and checkCert() */
81 
83 static int addStandardExtensions( INOUT CERT_INFO *certInfoPtr )
84  {
85  BOOLEAN isCA = FALSE;
86  int keyUsage, extKeyUsage, value, status;
87 
88  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
89 
90  /* Get the implicit keyUsage flags (based on any extended key usage
91  extensions present) and explicit key usage flags, which we use to
92  extend the basic keyUsage flags if required */
93  status = getKeyUsageFromExtKeyUsage( certInfoPtr, &extKeyUsage,
94  &certInfoPtr->errorLocus, &certInfoPtr->errorType );
95  if( cryptStatusError( status ) )
96  return( status );
97  status = getAttributeFieldValue( certInfoPtr->attributes,
99  CRYPT_ATTRIBUTE_NONE, &keyUsage );
100  if( cryptStatusError( status ) )
101  {
102  if( status != CRYPT_ERROR_NOTFOUND )
103  return( status );
104 
105  /* There's no keyUsage attribute present, mark the value as being
106  not set so that we explicitly set it later */
107  keyUsage = CRYPT_ERROR;
108  }
109 
110  /* If there's an explicit key usage present, make sure that it's
111  consistent with the implicit key usage flags derived from the
112  extended key usage. We mask out the nonRepudiation bit for reasons
113  given in chk_cert.c.
114 
115  This check is also performed by checkCert(), however we need to
116  explicitly perform it here as well since we need to add a key usage
117  to match the extKeyUsage before calling checkCert() if one wasn't
118  explicitly set or checkCert() will reject the certificate because of
119  the inconsistent keyUsage */
120  if( keyUsage > 0 )
121  {
122  const int effectiveKeyUsage = \
123  extKeyUsage & ~CRYPT_KEYUSAGE_NONREPUDIATION;
124 
125  if( ( keyUsage & effectiveKeyUsage ) != effectiveKeyUsage )
126  {
129  return( CRYPT_ERROR_INVALID );
130  }
131  }
132 
133  /* Check whether this is a CA certificate. If there's no
134  basicConstraints attribute present, add one and make it a non-CA
135  certificate */
136  status = getAttributeFieldValue( certInfoPtr->attributes,
138  &value );
139  if( cryptStatusOK( status ) )
140  isCA = ( value > 0 ) ? TRUE : FALSE;
141  else
142  {
143  status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_CA, FALSE );
144  if( cryptStatusError( status ) )
145  return( status );
146  }
147 
148  /* If there's no explicit keyUsage information present add it based on
149  various implicit information. We also add key feature information
150  which is used to help automate key management, for example to inhibit
151  speculative reads of keys held in removable tokens, which can result
152  in spurious insert-token dialogs being presented to the user outside
153  the control of cryptlib if the token isn't present */
154  if( keyUsage <= 0 )
155  {
156  /* If there's no implicit key usage present and it's not a CA (for
157  which we don't want to set things like encryption flags for the
158  CA certificate), set the key usage flags based on the
159  capabilities of the associated context. Because no-one can
160  figure out what the nonRepudiation flag signifies we don't set
161  this, if the user wants it they have to specify it explicitly.
162  Similarly we don't try and set the keyAgreement encipher/decipher-
163  only flags, which were tacked on as variants of keyAgreement long
164  after the basic keyAgreement flag was defined */
165  if( extKeyUsage <= 0 && !isCA )
166  {
167  keyUsage = 0; /* Reset key usage */
168  if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
169  {
170  /* There's a context present, check its capabilities. This
171  has the advantage that it takes into account any ACLs
172  that may exist for the key */
173  if( cryptStatusOK( \
174  krnlSendMessage( certInfoPtr->iPubkeyContext,
175  IMESSAGE_CHECK, NULL,
178  if( cryptStatusOK( \
179  krnlSendMessage( certInfoPtr->iPubkeyContext,
180  IMESSAGE_CHECK, NULL,
182  keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
183  if( cryptStatusOK( \
184  krnlSendMessage( certInfoPtr->iPubkeyContext,
185  IMESSAGE_CHECK, NULL,
187  cryptStatusOK( \
188  krnlSendMessage( certInfoPtr->iPubkeyContext,
189  IMESSAGE_CHECK, NULL,
191  keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
192  }
193  else
194  {
195  /* There's no context present (the key is present as encoded
196  data), assume we can do whatever the algorithm allows */
197  if( isSigAlgo( certInfoPtr->publicKeyAlgo ) )
199  if( isCryptAlgo( certInfoPtr->publicKeyAlgo ) )
200  keyUsage |= CRYPT_KEYUSAGE_KEYENCIPHERMENT;
201  if( isKeyxAlgo( certInfoPtr->publicKeyAlgo ) )
202  keyUsage |= CRYPT_KEYUSAGE_KEYAGREEMENT;
203  }
204  }
205  else
206  {
207  /* There's an extended key usage set but no basic keyUsage, make
208  the keyUsage consistent with the usage flags derived from the
209  extended usage */
210  keyUsage = extKeyUsage;
211 
212  /* If it's a CA key, make sure that it's a signing key and
213  enable its use for certification-related purposes*/
214  if( isCA )
215  {
216  BOOLEAN usageOK;
217 
218  if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
219  {
220  usageOK = cryptStatusOK( \
221  krnlSendMessage( certInfoPtr->iPubkeyContext,
222  IMESSAGE_CHECK, NULL,
224  }
225  else
226  usageOK = isSigAlgo( certInfoPtr->publicKeyAlgo );
227  if( !usageOK )
228  {
229  setErrorInfo( certInfoPtr, CRYPT_CERTINFO_CA,
231  return( CRYPT_ERROR_INVALID );
232  }
233  keyUsage |= KEYUSAGE_CA;
234  }
235  }
236  ENSURES( keyUsage > CRYPT_KEYUSAGE_NONE && \
237  keyUsage < CRYPT_KEYUSAGE_LAST );
238  status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYUSAGE,
239  keyUsage );
240  if( cryptStatusError( status ) )
241  return( status );
242  }
243  if( certInfoPtr->publicKeyFeatures > 0 )
244  {
245  /* This is a bitstring so we only add it if there are feature flags
246  present to avoid writing zero-length values */
247  status = addCertComponent( certInfoPtr, CRYPT_CERTINFO_KEYFEATURES,
248  certInfoPtr->publicKeyFeatures );
249  if( cryptStatusError( status ) && status != CRYPT_ERROR_INITED )
250  return( status );
251  }
252 
253  /* Add the subjectKeyIdentifier */
254  return( addCertComponentString( certInfoPtr,
256  certInfoPtr->publicKeyID, KEYID_SIZE ) );
257  }
258 
259 /****************************************************************************
260 * *
261 * Pre-encode Checking Functions *
262 * *
263 ****************************************************************************/
264 
265 /* Check whether an empty DN is permitted in a certificate. This is a PKIX
266  peculiarity that causes severe problems for virtually all certificate-
267  using protocols so we only allow it at a compliance level of
268  CRYPT_COMPLIANCELEVEL_PKIX_FULL */
269 
270 #ifdef USE_CERTLEVEL_PKIX_FULL
271 
273 static BOOLEAN checkEmptyDnOK( INOUT CERT_INFO *subjectCertInfoPtr )
274  {
276  int value, complianceLevel, status;
277 
278  assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
279 
280  /* PKIX allows empty subject DNs if a subject altName is present,
281  however creating certificates like this breaks every certificate-
282  using protocol supported by cryptlib so we only allow it at the
283  highest compliance level */
284  if( cryptStatusError( \
285  krnlSendMessage( subjectCertInfoPtr->ownerHandle,
286  IMESSAGE_GETATTRIBUTE, &complianceLevel,
288  complianceLevel < CRYPT_COMPLIANCELEVEL_PKIX_FULL )
289  {
290  /* We only allow this behaviour at the highest compliance level */
291  return( FALSE );
292  }
293 
294  /* We also have to be very careful to ensure that the empty subject
295  DN can't end up becoming an empty issuer DN, which can occur if it's
296  a self-signed certificate */
297  if( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED )
298  {
299  /* We can't have an empty issuer (== subject) DN */
300  return( FALSE );
301  }
302 
303  /* In addition if it's a CA certificate then the subject DN can't be
304  empty, for obvious reasons */
305  status = getAttributeFieldValue( subjectCertInfoPtr->attributes,
307  &value );
308  if( cryptStatusOK( status ) && value > 0 )
309  {
310  /* It's a CA certificate, the subject DN can't be empty */
311  return( FALSE );
312  }
313 
314  /* Finally, if there's no subject DN present then there has to be an
315  altName present to take its place */
316  attributePtr = findAttributeField( subjectCertInfoPtr->attributes,
319  if( attributePtr == NULL )
320  {
321  /* Either a subject DN or subject altName must be present */
322  return( FALSE );
323  }
324 
325  /* There's a subject altName present but no subject DN, mark the altName
326  as critical */
327  setAttributeProperty( attributePtr, ATTRIBUTE_PROPERTY_CRITICAL, 0 );
328 
329  return( TRUE );
330  }
331 #endif /* USE_CERTLEVEL_PKIX_FULL */
332 
333 /* Perform any final setup actions that add default and issuer-contributed
334  attributes */
335 
337 int preEncodeCertificate( INOUT CERT_INFO *subjectCertInfoPtr,
339  IN_FLAGS( PRE_SET ) const int actions )
340  {
341  int status;
342 
343  assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
344  assert( ( issuerCertInfoPtr == NULL ) || \
345  isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
346 
347  REQUIRES( actions >= PRE_SET_NONE && \
348  actions <= PRE_SET_FLAG_MAX );
349  REQUIRES( ( ( actions & ( PRE_SET_ISSUERATTR | PRE_SET_ISSUERDN | \
350  PRE_SET_VALIDITYPERIOD ) ) && \
351  issuerCertInfoPtr != NULL ) || \
352  !( actions & ( PRE_SET_ISSUERATTR | PRE_SET_ISSUERDN | \
354 
355  /* If it's a >= v3 certificate add the standard X.509v3 extensions if
356  these aren't already present */
357  if( actions & PRE_SET_STANDARDATTR )
358  {
359  /* Setting the standard attributes requires the presence of a public
360  key to get keyUsage information from, so we have to check this
361  before we can add any attributes. This would normally be checked
362  as part of the range of checking performedin
363  preCheckCertificate(), but that isn't called until the pre-
364  encoding functions here have been performed */
365  if( subjectCertInfoPtr->publicKeyInfo == NULL )
366  {
367  setErrorInfo( subjectCertInfoPtr,
370  return( CRYPT_ERROR_NOTINITED );
371  }
372 
373  /* Attributes are only allowed with version 3 certificates */
374  if( subjectCertInfoPtr->version >= 3 )
375  {
376  status = addStandardExtensions( subjectCertInfoPtr );
377  if( cryptStatusError( status ) )
378  return( status );
379  }
380  }
381 
382  /* Copy any required extensions from the issuer to the subject
383  certificate if necessary */
384  if( actions & PRE_SET_ISSUERATTR )
385  {
386  ANALYSER_HINT( issuerCertInfoPtr != NULL );
387 
388  if( !( subjectCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
389  {
390  status = copyIssuerAttributes( &subjectCertInfoPtr->attributes,
391  issuerCertInfoPtr->attributes,
392  subjectCertInfoPtr->type,
393  &subjectCertInfoPtr->errorLocus,
394  &subjectCertInfoPtr->errorType );
395  if( cryptStatusError( status ) )
396  return( status );
397  }
398  }
399 
400  /* Copy the issuer DN if this isn't already present */
401  if( actions & PRE_SET_ISSUERDN )
402  {
403  ANALYSER_HINT( issuerCertInfoPtr != NULL );
404 
405  if( subjectCertInfoPtr->issuerName == NULL )
406  {
407  status = copyDN( &subjectCertInfoPtr->issuerName,
408  issuerCertInfoPtr->subjectName );
409  if( cryptStatusError( status ) )
410  return( status );
411  }
412  }
413 
414  /* Constrain the subject validity period to be within the issuer
415  validity period */
416  if( actions & PRE_SET_VALIDITYPERIOD )
417  {
418  ANALYSER_HINT( issuerCertInfoPtr != NULL );
419 
420  if( subjectCertInfoPtr->startTime < issuerCertInfoPtr->startTime )
421  subjectCertInfoPtr->startTime = issuerCertInfoPtr->startTime;
422  if( subjectCertInfoPtr->endTime > issuerCertInfoPtr->endTime )
423  subjectCertInfoPtr->endTime = issuerCertInfoPtr->endTime;
424  }
425 
426 #ifdef USE_CERTVAL
427  /* If it's an RTCS response, prepare the certificate status list entries
428  prior to encoding them */
429  if( actions & PRE_SET_VALINFO )
430  {
431  status = prepareValidityEntries( subjectCertInfoPtr->cCertVal->validityInfo,
432  &subjectCertInfoPtr->cCertVal->currentValidity,
433  &subjectCertInfoPtr->errorLocus,
434  &subjectCertInfoPtr->errorType );
435  if( cryptStatusError( status ) )
436  return( status );
437  }
438 #endif /* USE_CERTVAL */
439 
440 #ifdef USE_CERTREV
441  /* If it's a CRL or OCSP response, prepare the revocation list entries
442  prior to encoding them */
443  if( actions & PRE_SET_REVINFO )
444  {
445  REVOCATION_INFO *revocationErrorEntry;
446  const BOOLEAN isCrlEntry = ( actions & PRE_SET_ISSUERDN ) ? FALSE : TRUE;
447 
448  status = prepareRevocationEntries( subjectCertInfoPtr->cCertRev->revocations,
449  subjectCertInfoPtr->cCertRev->revocationTime,
450  &revocationErrorEntry, isCrlEntry,
451  &subjectCertInfoPtr->errorLocus,
452  &subjectCertInfoPtr->errorType );
453  if( cryptStatusError( status ) )
454  {
455  /* If there was an error and we're processing an entire
456  revocation list, select the entry that caused the problem */
457  if( !isCrlEntry )
458  {
459  subjectCertInfoPtr->cCertRev->currentRevocation = \
460  revocationErrorEntry;
461  }
462  return( status );
463  }
464  }
465 #endif /* USE_CERTREV */
466 
467  return( CRYPT_OK );
468  }
469 
470 /* Check that a certificate object is reading for encoding */
471 
473 int preCheckCertificate( INOUT CERT_INFO *subjectCertInfoPtr,
474  IN_OPT const CERT_INFO *issuerCertInfoPtr,
475  IN_FLAGS( PRE_CHECK ) const int actions,
476  IN_FLAGS( PRE ) const int flags )
477  {
478  int status;
479 
480  assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
481  assert( ( issuerCertInfoPtr == NULL ) || \
482  isReadPtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
483 
484  REQUIRES( actions >= PRE_CHECK_NONE && \
485  actions <= PRE_CHECK_FLAG_MAX );
486  REQUIRES( flags == PRE_FLAG_NONE || \
487  flags == PRE_FLAG_DN_IN_ISSUERCERT );
488  REQUIRES( ( ( actions & ( PRE_CHECK_ISSUERCERTDN | \
490  issuerCertInfoPtr != NULL ) || \
491  !( actions & ( PRE_CHECK_ISSUERCERTDN | \
493  /* We can't impose a complete set of preconditions on the
494  issuer certificate because some issuer attributes like the
495  issuer DN may already be present in the subject
496  certificate */
497 
498  /* Make sure that there's public-key information present */
499  if( actions & PRE_CHECK_SPKI )
500  {
501  if( subjectCertInfoPtr->publicKeyInfo == NULL )
502  {
503  setErrorInfo( subjectCertInfoPtr,
506  return( CRYPT_ERROR_NOTINITED );
507  }
508  }
509 
510  /* Make sure that there's a full DN present */
511  if( actions & PRE_CHECK_DN )
512  {
513  status = checkDN( subjectCertInfoPtr->subjectName,
515  &subjectCertInfoPtr->errorLocus,
516  &subjectCertInfoPtr->errorType );
517  if( cryptStatusError( status ) )
518  {
519 #ifdef USE_CERTLEVEL_PKIX_FULL
520  /* In some very special cases an empty DN is permitted so we
521  only return an error if this really isn't allowed */
522  if( status != CRYPT_ERROR_NOTINITED || \
523  !checkEmptyDnOK( subjectCertInfoPtr ) )
524 #endif /* USE_CERTLEVEL_PKIX_FULL */
525  return( status );
526  }
527  }
528 
529  /* Make sure that there's at least a partial DN present (some CA's will
530  fill the upper portion of the DN themselves so at a minimum all that
531  we really need is a CommonName) */
532  if( actions & PRE_CHECK_DN_PARTIAL )
533  {
534  status = checkDN( subjectCertInfoPtr->subjectName,
536  &subjectCertInfoPtr->errorLocus,
537  &subjectCertInfoPtr->errorType );
538  if( cryptStatusError( status ) )
539  return( status );
540  }
541 
542  /* Make sure that there's an issuer DN present */
543  if( actions & PRE_CHECK_ISSUERDN )
544  {
545  if( flags & PRE_FLAG_DN_IN_ISSUERCERT )
546  {
547  if( issuerCertInfoPtr == NULL || \
548  issuerCertInfoPtr->subjectDNptr == NULL || \
549  issuerCertInfoPtr->subjectDNsize < 1 )
550  {
551  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
553  return( CRYPT_ERROR_NOTINITED );
554  }
555  }
556  else
557  {
558  /* The issuer DN can be present either in pre-encoded form (if
559  it was copied from an issuer certificate) or as a full DN (if
560  it's a self-signed certificate), so we check for the presence
561  of either */
562  if( ( subjectCertInfoPtr->issuerName == NULL ) &&
563  ( subjectCertInfoPtr->issuerDNptr == NULL || \
564  subjectCertInfoPtr->issuerDNsize < 1 ) )
565  {
566  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
568  return( CRYPT_ERROR_NOTINITED );
569  }
570  }
571  }
572 
573  /* If it's a CRL, compare the revoked certificate issuer DN and signer
574  DN to make sure that we're not trying to revoke someone else's
575  certificates, and prepare the revocation entries */
576  if( actions & PRE_CHECK_ISSUERCERTDN )
577  {
578  ANALYSER_HINT( issuerCertInfoPtr != NULL );
579 
580  if( !compareDN( subjectCertInfoPtr->issuerName,
581  issuerCertInfoPtr->subjectName, FALSE, NULL ) )
582  {
583  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_ISSUERNAME,
585  return( CRYPT_ERROR_INVALID );
586  }
587  }
588 
589  /* If we're creating a non-self-signed certificate check whether the
590  subject's DN is the same as the issuer's DN. If this is the case
591  then the resulting object would appear to be self-signed so we
592  disallow it */
593  if( actions & PRE_CHECK_NONSELFSIGNED_DN )
594  {
595  ANALYSER_HINT( issuerCertInfoPtr != NULL );
596 
597  if( compareDN( issuerCertInfoPtr->subjectName,
598  subjectCertInfoPtr->subjectName, FALSE, NULL ) )
599  {
600  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SUBJECTNAME,
602  return( CRYPT_ERROR_INVALID );
603  }
604  }
605 
606  /* Check that the serial number is present */
607  if( actions & PRE_CHECK_SERIALNO )
608  {
609 #ifdef USE_CERTREQ
610  if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_REQUEST_REVOCATION )
611  {
612  if( subjectCertInfoPtr->cCertReq->serialNumberLength <= 0 )
613  {
614  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
616  return( CRYPT_ERROR_NOTINITED );
617  }
618  }
619  else
620 #endif /* USE_CERTREQ */
621  {
622  if( subjectCertInfoPtr->cCertCert->serialNumberLength <= 0 )
623  {
624  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_SERIALNUMBER,
626  return( CRYPT_ERROR_NOTINITED );
627  }
628  }
629  }
630 
631  /* Check that the validity/revocation information is present */
632 #ifdef USE_CERTVAL
633  if( actions & PRE_CHECK_VALENTRIES )
634  {
635  if( subjectCertInfoPtr->cCertVal->validityInfo == NULL )
636  {
637  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
639  return( CRYPT_ERROR_NOTINITED );
640  }
641  }
642 #endif /* USE_CERTVAL */
643 #ifdef USE_CERTREV
644  if( actions & PRE_CHECK_REVENTRIES )
645  {
646  if( subjectCertInfoPtr->cCertRev->revocations == NULL )
647  {
648  setErrorInfo( subjectCertInfoPtr, CRYPT_CERTINFO_CERTIFICATE,
650  return( CRYPT_ERROR_NOTINITED );
651  }
652  }
653 #endif /* USE_CERTREV */
654 
655  /* Now that we've set up the attributes, perform the remainder of the
656  checks. Because RTCS is a CMS standard rather than PKIX the RTCS
657  attributes are CMS rather than certificate attributes */
658  if( subjectCertInfoPtr->attributes != NULL )
659  {
660  status = checkAttributes( ( subjectCertInfoPtr->type == \
663  subjectCertInfoPtr->attributes,
664  &subjectCertInfoPtr->errorLocus,
665  &subjectCertInfoPtr->errorType );
666  if( cryptStatusError( status ) )
667  return( status );
668  }
669  status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr, FALSE,
670  &subjectCertInfoPtr->errorLocus,
671  &subjectCertInfoPtr->errorType );
672  if( cryptStatusError( status ) )
673  return( status );
674 
675  /* If it's a certificate or certificate chain remember that it's been
676  checked at full compliance level (or at least as full as we're
677  configured for). This short-circuits the need to perform excessive
678  levels of checking if the caller wants to re-check it after it's
679  been signed */
680  if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
681  subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
682  {
683  subjectCertInfoPtr->cCertCert->maxCheckLevel = \
684  CRYPT_COMPLIANCELEVEL_PKIX_FULL;
685  }
686 
687  return( status );
688  }
689 #endif /* USE_CERTIFICATES */