cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
certschk.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Certificate Signature Checking Routines *
4 * Copyright Peter Gutmann 1997-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "cert.h"
10  #include "asn1.h"
11 #else
12  #include "cert/cert.h"
13  #include "enc_dec/asn1.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_CERTIFICATES
17 
18 /****************************************************************************
19 * *
20 * Utility Routines *
21 * *
22 ****************************************************************************/
23 
24 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
25 
26 /* Generate an issuerID, a SHA-1 hash of the issuerAndSerialNumber needed
27  when storing/retrieving a certificate to/from a database keyset, which
28  can't handle the awkward heirarchical IDs usually used in certificates.
29  This is created by encoding the DN and serial number */
30 
31 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
32 static int generateCertID( IN_BUFFER( dnLength ) const void *dn,
33  IN_LENGTH_SHORT const int dnLength,
35  const void *serialNumber,
38  IN_LENGTH_FIXED( KEYID_SIZE ) const int certIdLength )
39  {
40  HASHFUNCTION_ATOMIC hashFunctionAtomic;
42  HASHINFO hashInfo;
43  STREAM stream;
44  BYTE buffer[ MAX_SERIALNO_SIZE + 8 + 8 ];
45  int status;
46 
47  assert( isReadPtr( dn, dnLength ) );
48  assert( isReadPtr( serialNumber, serialNumberLength ) && \
49  serialNumberLength > 0 && \
50  serialNumberLength <= MAX_SERIALNO_SIZE );
51  assert( isWritePtr( certID, certIdLength ) );
52 
53  REQUIRES( serialNumberLength > 0 && \
54  serialNumberLength <= MAX_SERIALNO_SIZE );
55  REQUIRES( certIdLength == KEYID_SIZE );
56 
57  /* Clear return value */
58  memset( certID, 0, min( 16, certIdLength ) );
59 
60  /* Get the hash algorithm information */
61  getHashAtomicParameters( CRYPT_ALGO_SHA1, 0, &hashFunctionAtomic, NULL );
62  getHashParameters( CRYPT_ALGO_SHA1, 0, &hashFunction, NULL );
63 
64  /* Write the relevant information to a buffer and hash the data to get
65  the ID:
66 
67  SEQUENCE {
68  issuer DN,
69  serial INTEGER
70  } */
71  sMemOpen( &stream, buffer, MAX_SERIALNO_SIZE + 8 );
72  status = writeSequence( &stream,
73  dnLength + sizeofInteger( serialNumber, \
74  serialNumberLength ) );
75  if( cryptStatusError( status ) )
76  {
77  sMemClose( &stream );
78  return( status );
79  }
80  hashFunction( hashInfo, NULL, 0, buffer, stell( &stream ),
82  hashFunction( hashInfo, NULL, 0, dn, dnLength, HASH_STATE_CONTINUE );
83  sseek( &stream, 0 );
84  status = writeInteger( &stream, serialNumber, serialNumberLength,
85  DEFAULT_TAG );
86  if( cryptStatusOK( status ) )
87  {
88  hashFunction( hashInfo, certID, certIdLength, buffer,
89  stell( &stream ), HASH_STATE_END );
90  }
91  sMemClose( &stream );
92 
93  return( status );
94  }
95 #endif /* USE_CERTREV || USE_CERTVAL */
96 
97 /****************************************************************************
98 * *
99 * Validity/Revocation Checking *
100 * *
101 ****************************************************************************/
102 
103 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
104 
105 /* Check a certificate using an RTCS or OCSP responder */
106 
108 static int checkResponder( INOUT CERT_INFO *certInfoPtr,
109  IN_HANDLE const CRYPT_SESSION iCryptSession )
110  {
111  CRYPT_CERTIFICATE cryptResponse = DUMMY_INIT;
112  MESSAGE_CREATEOBJECT_INFO createInfo;
113  int sessionType, status;
114 
115  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
116 
117  REQUIRES( isHandleRangeValid( iCryptSession) );
118 
119  status = krnlSendMessage( iCryptSession, IMESSAGE_GETATTRIBUTE,
120  &sessionType, CRYPT_IATTRIBUTE_SUBTYPE );
121  if( cryptStatusError( status ) )
122  return( status );
123 
124  REQUIRES( ( sessionType == SUBTYPE_SESSION_RTCS ) || \
125  ( sessionType == SUBTYPE_SESSION_OCSP ) );
126 
127  /* Create the request, add the certificate, and add the request to the
128  session */
129  setMessageCreateObjectInfo( &createInfo,
130  ( sessionType == SUBTYPE_SESSION_RTCS ) ? \
134  &createInfo, OBJECT_TYPE_CERTIFICATE );
135  if( cryptStatusError( status ) )
136  return( status );
137  status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_SETATTRIBUTE,
138  &certInfoPtr->objectHandle, CRYPT_CERTINFO_CERTIFICATE );
139  if( cryptStatusOK( status ) )
140  status = krnlSendMessage( iCryptSession, IMESSAGE_SETATTRIBUTE,
141  &createInfo.cryptHandle, CRYPT_SESSINFO_REQUEST );
143  if( cryptStatusError( status ) )
144  return( status );
145 
146  /* Activate the session and get the response information */
147  status = krnlSendMessage( iCryptSession, IMESSAGE_SETATTRIBUTE,
149  if( cryptStatusOK( status ) )
150  status = krnlSendMessage( iCryptSession, IMESSAGE_GETATTRIBUTE,
151  &cryptResponse, CRYPT_SESSINFO_RESPONSE );
152  if( cryptStatusError( status ) )
153  return( status );
154  if( sessionType == SUBTYPE_SESSION_RTCS )
155  {
156  int certStatus;
157 
158  status = krnlSendMessage( cryptResponse, IMESSAGE_GETATTRIBUTE,
159  &certStatus, CRYPT_CERTINFO_CERTSTATUS );
160  if( cryptStatusOK( status ) && \
161  ( certStatus != CRYPT_CERTSTATUS_VALID ) )
162  status = CRYPT_ERROR_INVALID;
163  }
164  else
165  {
166  int revocationStatus;
167 
168  status = krnlSendMessage( cryptResponse, IMESSAGE_GETATTRIBUTE,
169  &revocationStatus,
171  if( cryptStatusOK( status ) && \
172  ( revocationStatus != CRYPT_OCSPSTATUS_NOTREVOKED ) )
173  status = CRYPT_ERROR_INVALID;
174  }
175  krnlSendNotifier( cryptResponse, IMESSAGE_DECREFCOUNT );
176 
177  return( status );
178  }
179 
180 /* Check a certificate against a CRL stored in a keyset */
181 
183 static int checkKeyset( INOUT CERT_INFO *certInfoPtr,
185  {
186  MESSAGE_KEYMGMT_INFO getkeyInfo;
187  BYTE issuerID[ KEYID_SIZE + 8 ];
188  int status;
189 
190  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
191 
192  REQUIRES( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
193  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
194  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN );
195  REQUIRES( isHandleRangeValid( iCryptKeyset ) );
196 
197  /* Generate the issuerID for the certificate */
198  status = generateCertID( certInfoPtr->issuerDNptr,
199  certInfoPtr->issuerDNsize,
200  certInfoPtr->cCertCert->serialNumber,
201  certInfoPtr->cCertCert->serialNumberLength,
202  issuerID, KEYID_SIZE );
203  if( cryptStatusError( status ) )
204  return( status );
205 
206  /* Check whether the object with this issuerID is present in the CRL.
207  Since all that we're interested in is a yes/no answer we tell the
208  keyset to perform a check only */
209  setMessageKeymgmtInfo( &getkeyInfo, CRYPT_IKEYID_ISSUERID, issuerID,
211  status = krnlSendMessage( iCryptKeyset, IMESSAGE_KEY_GETKEY,
212  &getkeyInfo, KEYMGMT_ITEM_REVOCATIONINFO );
213  if( cryptStatusOK( status ) )
214  {
215  /* The certificate is present in the blacklist so it's an invalid
216  certificate */
217  return( CRYPT_ERROR_INVALID );
218  }
219  if( status == CRYPT_ERROR_NOTFOUND )
220  {
221  /* The certificate isn't present in the blacklist so it's not
222  revoked (although not necessarily valid either) */
223  return( CRYPT_OK );
224  }
225 
226  /* Some other type of error occurred */
227  return( status );
228  }
229 #endif /* USE_CERTREV || USE_CERTVAL */
230 
231 /****************************************************************************
232 * *
233 * Signature Checking Functions *
234 * *
235 ****************************************************************************/
236 
237 /* Check a certificate against an issuer certificate. The trustAnchorCheck
238  flag is used when we're checking an explicit trust anchor, for which we
239  only need to check the signature if it's self-signed. The
240  shortCircuitCheck flag is used when checking subject:issuer pairs inside
241  certificate chains, which have already been checked by the chain-handling
242  code so a full (re-)check isn't necessary any more */
243 
244 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 7, 8 ) ) \
245 int checkCertDetails( INOUT CERT_INFO *subjectCertInfoPtr,
251  OUT_ENUM_OPT( CRYPT_ATTRIBUTE ) \
252  CRYPT_ATTRIBUTE_TYPE *errorLocus,
253  OUT_ENUM_OPT( CRYPT_ERRTYPE ) \
254  CRYPT_ERRTYPE_TYPE *errorType )
255  {
256  int status;
257 
258  assert( isWritePtr( subjectCertInfoPtr, sizeof( CERT_INFO ) ) );
259  assert( issuerCertInfoPtr == NULL || \
260  isWritePtr( issuerCertInfoPtr, sizeof( CERT_INFO ) ) );
261  assert( formatInfo == NULL || \
262  isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
263  assert( isWritePtr( errorLocus, sizeof( CRYPT_ATTRIBUTE_TYPE ) ) );
264  assert( isWritePtr( errorType, sizeof( CRYPT_ERRTYPE_TYPE ) ) );
265 
266  REQUIRES( iIssuerPubKey == CRYPT_UNUSED || \
267  isHandleRangeValid( iIssuerPubKey ) );
268 
269  /* Perform a basic check for obvious invalidity issues */
270  if( subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
271  subjectCertInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
272  subjectCertInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
273  {
274  status = checkCertBasic( subjectCertInfoPtr );
275  if( cryptStatusError( status ) )
276  return( status );
277  }
278 
279  /* If there's an issuer certificate present check the validity of the
280  subject certificate based on it. If it's not present all that we can
281  do is perform a pure signature check with the context */
282  if( issuerCertInfoPtr != NULL )
283  {
284  status = checkCert( subjectCertInfoPtr, issuerCertInfoPtr,
285  shortCircuitCheck, errorLocus, errorType );
286  if( cryptStatusError( status ) )
287  return( status );
288  }
289 
290  /* If the signature has already been checked or there's no signature-
291  check key present we're done. The latter can occur when we're
292  checking a data-only certificate in a certificate chain. This is
293  safe because these certificates can only occur when we're reading
294  them from an (implicitly trusted) private key store */
295  if( ( subjectCertInfoPtr->flags & CERT_FLAG_SIGCHECKED ) || \
296  iIssuerPubKey == CRYPT_UNUSED )
297  return( CRYPT_OK );
298 
299  /* If we're checking an explicit trust anchor and the certificate isn't
300  self-signed there's nothing further left to check */
301  if( trustAnchorCheck && issuerCertInfoPtr != NULL && \
302  !( issuerCertInfoPtr->flags & CERT_FLAG_SELFSIGNED ) )
303  return( CRYPT_OK );
304 
305  /* If we're performing a standard check and it's an explicitly-trusted
306  certificate we're done. If we're performing a check of a certificate
307  chain then the chain-handling code will have performed its own
308  handling of trusted certificates/trust anchors so we don't peform a
309  second check here */
310  if( !shortCircuitCheck )
311  {
312  if( cryptStatusOK( \
313  krnlSendMessage( subjectCertInfoPtr->ownerHandle,
315  &subjectCertInfoPtr->objectHandle,
317  return( CRYPT_OK );
318  }
319 
320  /* Check the signature on the certificate. If there's a problem with
321  the issuer's public key it'll be reported as a CRYPT_ARGERROR_NUM1,
322  which the caller has to convert into an appropriate error code */
323  status = checkX509signature( subjectCertInfoPtr->certificate,
324  subjectCertInfoPtr->certificateSize,
325  iIssuerPubKey, formatInfo );
326  if( cryptStatusError( status ) )
327  {
328 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
330  BYTE subjectIssuerID[ CRYPT_MAX_HASHSIZE + 8 ];
331  BYTE issuerSubjectID[ CRYPT_MAX_HASHSIZE + 8 ];
332  int subjectIDlength, issuerIDlength;
333 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
334 
335  /* There's one special-case situation in which we can get a
336  signature-check failure that looks like data corruption and
337  that's when a CA quietly changes its issuing key without changing
338  anything else so that the certificates chain but the signature
339  check produces garbage as output due to the use of the incorrect
340  key. Although it could be argued that a CA that does this is
341  broken, we try and accomodate it by performing a backup check
342  using keyIDs if the signature check produces garbled output.
343  Because of the complete chaos present in keyIDs we can't do this
344  by default (it would result in far too many false positives) but
345  it's safe as a fallback at this point since we're about to report
346  an error anyway and the worst that can happen is that we return
347  a slightly inappropriate error message.
348 
349  If there's no issuer certificate provided we also have to exit at
350  this point because we can't go any further without it */
351  if( status != CRYPT_ERROR_BADDATA || issuerCertInfoPtr == NULL )
352  return( status );
353 
354 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
355  /* Get the subject certificate's issuerID and the issuer
356  certificate's subjectID. We don't bother with the alternative
357  awkward DN-based ID since what we're really interested in is the
358  ID of the signing key and it's not worth the extra pain of dealing
359  with these awkward cert IDs just to try and fix up a slight
360  difference in error codes. Since the overall error status at this
361  point is CRYPT_ERROR_BADDATA we return that instead of any
362  ephemeral status values returned from further function calls */
363  setMessageData( &msgData, subjectIssuerID, CRYPT_MAX_HASHSIZE );
364  status = krnlSendMessage( subjectCertInfoPtr->objectHandle,
365  IMESSAGE_GETATTRIBUTE_S, &msgData,
367  if( cryptStatusError( status ) )
368  return( CRYPT_ERROR_BADDATA );
369  issuerIDlength = msgData.length;
370  setMessageData( &msgData, issuerSubjectID, CRYPT_MAX_HASHSIZE );
371  status = krnlSendMessage( issuerCertInfoPtr->objectHandle,
372  IMESSAGE_GETATTRIBUTE_S, &msgData,
374  if( cryptStatusError( status ) )
375  return( CRYPT_ERROR_BADDATA );
376  subjectIDlength = msgData.length;
377 
378  /* If the keyIDs don't match then it's a signature error due to
379  false-positive chaining rather than a data corruption error */
380  return( ( ( issuerIDlength != subjectIDlength ) || \
381  memcmp( subjectIssuerID, issuerSubjectID, \
382  issuerIDlength ) ) ? \
384 #else
385  return( status );
386 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
387  }
388 
389  /* The signature is OK, we don't need to check it again. There is a
390  theoretical situation where this can lead to a false positive which
391  requires first checking the certificate using the correct issuing CA
392  (which will set the CERT_FLAG_SIGCHECKED flag) and then checking it
393  again using a second CA certificate identical to the first but with a
394  different key. In other words the issuer DN chains correctly but the
395  issuer key is different. The appropriate behaviour here is somewhat
396  unclear, it could be argued that a CA that uses two otherwise
397  identical certificates but with different keys is broken and therefore
398  behaviour in this situation is undefined. However we need to do
399  something and returning the result of the check with the correct CA
400  certificate even if we're later passed a second incorrect certificate
401  from the CA seems to be the most appropriate action since it has in
402  the past been validated by a certificate from the same CA. If we want
403  to force the check to be done with a specific CA key (rather than just
404  the issuing CA's certificate in general) we could store the
405  fingerprint of the signing key alongside the CERT_FLAG_SIGCHECKED
406  flag */
407  subjectCertInfoPtr->flags |= CERT_FLAG_SIGCHECKED;
408 
409  return( CRYPT_OK );
410  }
411 
412 /* Check a self-signed certificate object like a certificate request or a
413  self-signed certificate */
414 
416 static int checkSelfSignedCert( INOUT CERT_INFO *certInfoPtr,
417  IN_OPT const X509SIG_FORMATINFO *formatInfo )
418  {
421  BOOLEAN trustedCertAcquired = FALSE;
422  int status;
423 
424  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
425  assert( formatInfo == NULL || \
426  isReadPtr( formatInfo, sizeof( X509SIG_FORMATINFO ) ) );
427 
428  /* Perform a basic check for obvious invalidity issues */
429  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
430  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
431  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
432  {
433  status = checkCertBasic( certInfoPtr );
434  if( cryptStatusError( status ) )
435  return( status );
436  }
437 
438  /* Since there's no signer certificate provided it has to be either
439  explicitly self-signed or signed by a trusted certificate */
440  if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
441  {
442  if( certInfoPtr->iPubkeyContext != CRYPT_ERROR )
443  iCryptContext = certInfoPtr->iPubkeyContext;
444  issuerCertInfoPtr = certInfoPtr;
445  }
446  else
447  {
448  CRYPT_CERTIFICATE iCryptCert = certInfoPtr->objectHandle;
449 
450  /* If it's a certificate it may be implicitly trusted */
451  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
452  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT )
453  {
454  if( cryptStatusOK( \
455  krnlSendMessage( certInfoPtr->ownerHandle,
456  IMESSAGE_USER_TRUSTMGMT, &iCryptCert,
458  {
459  /* The certificate is implicitly trusted, we're done */
460  return( CRYPT_OK );
461  }
462  }
463 
464  /* If it's not self-signed it has to be signed by a trusted
465  certificate, try and get the trusted certificate */
466  status = krnlSendMessage( certInfoPtr->ownerHandle,
467  IMESSAGE_USER_TRUSTMGMT, &iCryptCert,
469  if( cryptStatusError( status ) )
470  {
471  /* There's no trusted signer present, indicate that we need
472  something to check the certificate with */
473  return( CRYPT_ARGERROR_VALUE );
474  }
475  status = krnlAcquireObject( iCryptCert, OBJECT_TYPE_CERTIFICATE,
476  ( void ** ) &issuerCertInfoPtr,
478  if( cryptStatusError( status ) )
479  return( status );
480  iCryptContext = iCryptCert;
481  trustedCertAcquired = TRUE;
482  }
483 
484  /* Check the certificate against the issuing certificate */
485  status = checkCertDetails( certInfoPtr, issuerCertInfoPtr,
486  iCryptContext, formatInfo, FALSE, FALSE,
487  &certInfoPtr->errorLocus,
488  &certInfoPtr->errorType );
489  if( trustedCertAcquired )
490  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
491  return( cryptArgError( status ) ? CRYPT_ARGERROR_OBJECT : status );
492  }
493 
494 /****************************************************************************
495 * *
496 * General Certificate Validity Checking Functions *
497 * *
498 ****************************************************************************/
499 
500 /* Check the validity of a certificate object, either against an issuing
501  key/certificate or against a CRL */
502 
504 int checkCertValidity( INOUT CERT_INFO *certInfoPtr,
506  {
508  CERT_INFO *issuerCertInfoPtr = NULL;
509  X509SIG_FORMATINFO formatInfo, *formatInfoPtr = NULL;
510  BOOLEAN issuerCertAcquired = FALSE;
511  int sigCheckObjectType, sigCheckKeyType = CRYPT_CERTTYPE_NONE, status;
512 
513  assert( isWritePtr( certInfoPtr, sizeof( CERT_INFO ) ) );
514 
515  REQUIRES( certInfoPtr->certificate != NULL || \
516  certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE || \
517  certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE );
518  REQUIRES( iSigCheckObject == CRYPT_UNUSED || \
519  isHandleRangeValid( iSigCheckObject ) );
520 
521  /* CRMF and OCSP use a b0rken signature format (the authors couldn't
522  quite manage a cut & paste of two lines of text) so if it's one of
523  these we have to use nonstandard formatting */
524  if( certInfoPtr->type == CRYPT_CERTTYPE_REQUEST_CERT )
525  {
526  /* [1] SEQUENCE */
527  setX509FormatInfo( &formatInfo, 1, FALSE );
528  formatInfoPtr = &formatInfo;
529  }
530  else
531  {
532  if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_REQUEST )
533  {
534  /* [0] EXPLICIT SEQUENCE */
535  setX509FormatInfo( &formatInfo, 0, TRUE );
536  formatInfoPtr = &formatInfo;
537  }
538  }
539 
540  /* If there's no signature checking key supplied then the certificate
541  must be self-signed, either an implicitly self-signed object like a
542  certificate chain or an explicitly self-signed object like a
543  certificate request or self-signed certificate */
544  if( iSigCheckObject == CRYPT_UNUSED )
545  {
546  /* If it's a certificate chain it's a (complex) self-signed object
547  containing more than one certificate so we need a special
548  function to check the entire chain */
549  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
550  return( checkCertChain( certInfoPtr ) );
551 
552  /* It's an explicitly self-signed object */
553  return( checkSelfSignedCert( certInfoPtr, formatInfoPtr ) );
554  }
555 
556  /* Find out what the signature check object is */
557  status = krnlSendMessage( iSigCheckObject, IMESSAGE_GETATTRIBUTE,
558  &sigCheckObjectType, CRYPT_IATTRIBUTE_TYPE );
559  if( cryptStatusOK( status ) && \
560  sigCheckObjectType == OBJECT_TYPE_CERTIFICATE )
561  {
562  status = krnlSendMessage( iSigCheckObject, IMESSAGE_GETATTRIBUTE,
563  &sigCheckKeyType,
565  }
566  if( cryptStatusError( status ) )
567  return( cryptArgError( status ) ? CRYPT_ARGERROR_VALUE : status );
568 
569  /* Perform a general validity check on the object being checked and the
570  associated verification object. This is somewhat more strict than
571  the kernel checks since the kernel only knows about valid subtypes
572  but not that some subtypes are only valid in combination with some
573  types of object being checked */
574  switch( sigCheckObjectType )
575  {
577  case OBJECT_TYPE_CONTEXT:
578  break;
579 
580  case OBJECT_TYPE_KEYSET:
581  /* A keyset can only be used as a source of revocation
582  information for checking a certificate or to populate the
583  status fields of an RTCS/OCSP response */
584  if( certInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
585  certInfoPtr->type != CRYPT_CERTTYPE_ATTRIBUTE_CERT && \
586  certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN && \
587  certInfoPtr->type != CRYPT_CERTTYPE_RTCS_RESPONSE && \
588  certInfoPtr->type != CRYPT_CERTTYPE_OCSP_RESPONSE )
589  return( CRYPT_ARGERROR_VALUE );
590  break;
591 
592  case OBJECT_TYPE_SESSION:
593  /* An (RTCS or OCSP) session can only be used as a source of
594  validity/revocation information for checking a certificate */
595  if( certInfoPtr->type != CRYPT_CERTTYPE_CERTIFICATE && \
596  certInfoPtr->type != CRYPT_CERTTYPE_ATTRIBUTE_CERT && \
597  certInfoPtr->type != CRYPT_CERTTYPE_CERTCHAIN )
598  return( CRYPT_ARGERROR_VALUE );
599  break;
600 
601  default:
602  return( CRYPT_ARGERROR_VALUE );
603  }
604 
605  /* Perform a basic check for obvious invalidity issues */
606  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTIFICATE || \
607  certInfoPtr->type == CRYPT_CERTTYPE_ATTRIBUTE_CERT || \
608  certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
609  {
610  status = checkCertBasic( certInfoPtr );
611  if( cryptStatusError( status ) )
612  return( status );
613  }
614 
615  /* If the checking key is a CRL, a keyset that may contain a CRL, or an
616  RTCS or OCSP session then this is a validity/revocation check that
617  works rather differently from a straight signature check */
618 #if defined( USE_CERTREV )
619  if( sigCheckObjectType == OBJECT_TYPE_CERTIFICATE && \
620  sigCheckKeyType == CRYPT_CERTTYPE_CRL )
621  return( checkCRL( certInfoPtr, iSigCheckObject ) );
622 #endif /* USE_CERTREV */
623  if( sigCheckObjectType == OBJECT_TYPE_KEYSET )
624  {
625  /* If it's an RTCS or OCSP response use the certificate store to fill
626  in the status information fields */
627 #if defined( USE_CERTVAL )
628  if( certInfoPtr->type == CRYPT_CERTTYPE_RTCS_RESPONSE )
629  return( checkRTCSResponse( certInfoPtr, iSigCheckObject ) );
630 #endif /* USE_CERTVAL */
631 #if defined( USE_CERTREV )
632  if( certInfoPtr->type == CRYPT_CERTTYPE_OCSP_RESPONSE )
633  return( checkOCSPResponse( certInfoPtr, iSigCheckObject ) );
634 
635  /* It's a keyset, check the certificate against the CRL blacklist in
636  the keyset */
637  return( checkKeyset( certInfoPtr, iSigCheckObject ) );
638 #else
639  return( CRYPT_ARGERROR_VALUE );
640 #endif /* USE_CERTREV */
641  }
642 #if defined( USE_CERTREV ) || defined( USE_CERTVAL )
643  if( sigCheckObjectType == OBJECT_TYPE_SESSION )
644  return( checkResponder( certInfoPtr, iSigCheckObject ) );
645 #endif /* USE_CERTREV || USE_CERTVAL */
646 
647  /* If we've been given a self-signed certificate make sure that the
648  signature check key is the same as the certificate's key. To test
649  this we have to compare both the signing key and if the signature
650  check object is a certificate, the certificate */
651  if( certInfoPtr->flags & CERT_FLAG_SELFSIGNED )
652  {
654  BYTE keyID[ KEYID_SIZE + 8 ];
655 
656  /* Check that the key in the certificate and the key in the
657  signature check object are identical */
658  setMessageData( &msgData, keyID, KEYID_SIZE );
659  status = krnlSendMessage( iSigCheckObject, IMESSAGE_GETATTRIBUTE_S,
660  &msgData, CRYPT_IATTRIBUTE_KEYID );
661  if( cryptStatusOK( status ) )
662  status = krnlSendMessage( certInfoPtr->objectHandle,
663  IMESSAGE_COMPARE, &msgData,
665  if( cryptStatusError( status ) )
666  return( CRYPT_ARGERROR_VALUE );
667 
668  /* If the signature check object is a certificate (even though
669  what's being checked is already a self-signed certificate) check
670  that it's identical to the certificate being checked (which it
671  must be if the certificate is self-signed). This may be somewhat
672  stricter than required but it'll weed out technically valid but
673  questionable combinations like a certificate request being used
674  to validate a certificate and misleading ones such as one
675  certificate chain being used to check a second chain */
676  if( sigCheckObjectType == OBJECT_TYPE_CERTIFICATE )
677  {
678  status = krnlSendMessage( certInfoPtr->objectHandle,
680  ( MESSAGE_CAST ) &iSigCheckObject,
682  if( cryptStatusError( status ) )
683  return( CRYPT_ARGERROR_VALUE );
684  }
685 
686  /* If it's a certificate chain it's a (complex) self-signed object
687  containing more than one certificate so we need a special
688  function to check the entire chain */
689  if( certInfoPtr->type == CRYPT_CERTTYPE_CERTCHAIN )
690  return( checkCertChain( certInfoPtr ) );
691 
692  return( checkSelfSignedCert( certInfoPtr, formatInfoPtr ) );
693  }
694 
695  /* The signature check key may be a certificate or a context. If it's
696  a certificate we get the issuer certificate information and extract
697  the context from it before continuing */
698  if( sigCheckObjectType == OBJECT_TYPE_CERTIFICATE )
699  {
700  /* Get the context from the issuer certificate */
701  status = krnlSendMessage( iSigCheckObject, IMESSAGE_GETDEPENDENT,
702  &iCryptContext, OBJECT_TYPE_CONTEXT );
703  if( cryptStatusError( status ) )
704  return( cryptArgError( status ) ? CRYPT_ARGERROR_VALUE : status );
705 
706  /* Get the issuer certificate information */
707  status = krnlAcquireObject( iSigCheckObject, OBJECT_TYPE_CERTIFICATE,
708  ( void ** ) &issuerCertInfoPtr,
710  if( cryptStatusError( status ) )
711  return( status );
712  issuerCertAcquired = TRUE;
713  }
714  else
715  {
716  CRYPT_CERTIFICATE localCert;
717 
718  iCryptContext = iSigCheckObject;
719 
720  /* It's a context, we may have a certificate present with it so we
721  try to extract that and use it as the issuer certificate if
722  possible. If the issuer certificate isn't present this isn't an
723  error since it could be just a raw context */
724  status = krnlSendMessage( iSigCheckObject, IMESSAGE_GETDEPENDENT,
725  &localCert, OBJECT_TYPE_CERTIFICATE );
726  if( cryptStatusOK( status ) )
727  {
728  status = krnlAcquireObject( localCert, OBJECT_TYPE_CERTIFICATE,
729  ( void ** ) &issuerCertInfoPtr,
731  if( cryptStatusError( status ) )
732  return( status );
733  issuerCertAcquired = TRUE;
734  }
735  }
736 
737  /* Check the certificate against the issuing certificate */
738  status = checkCertDetails( certInfoPtr, issuerCertAcquired ? \
739  issuerCertInfoPtr : NULL,
740  iCryptContext, formatInfoPtr, FALSE, FALSE,
741  &certInfoPtr->errorLocus,
742  &certInfoPtr->errorType );
743  if( issuerCertAcquired )
744  krnlReleaseObject( issuerCertInfoPtr->objectHandle );
745  return( cryptArgError( status ) ? CRYPT_ARGERROR_VALUE : status );
746  }
747 #endif /* USE_CERTIFICATES */