cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
ca_rev.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib DBMS CA Certificate Revocation Interface *
4 * Copyright Peter Gutmann 1996-2007 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "crypt.h"
10  #include "keyset.h"
11  #include "dbms.h"
12 #else
13  #include "crypt.h"
14  #include "keyset/keyset.h"
15  #include "keyset/dbms.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_DBMS
19 
20 /****************************************************************************
21 * *
22 * Utility Functions *
23 * *
24 ****************************************************************************/
25 
26 /* Get the certificate indicated in a revocation request */
27 
28 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
29 static int getCertToRevoke( INOUT DBMS_INFO *dbmsInfo,
33  {
34  char issuerID[ ENCODED_DBXKEYID_SIZE + 8 ];
35  int dummy, issuerIDlength, status;
36 
37  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
38  assert( isWritePtr( iCertificate, sizeof( CRYPT_CERTIFICATE ) ) );
39 
40  REQUIRES( isHandleRangeValid( iCertRequest ) );
41  REQUIRES( errorInfo != NULL );
42 
43  /* Clear return value */
44  *iCertificate = CRYPT_ERROR;
45 
46  /* Extract the certificate identity information from the request and try
47  and fetch it from the certificate store */
48  status = getKeyID( issuerID, ENCODED_DBXKEYID_SIZE, &issuerIDlength,
49  iCertRequest, CRYPT_IATTRIBUTE_ISSUERANDSERIALNUMBER );
50  if( cryptStatusError( status ) )
51  return( status );
52  return( getItemData( dbmsInfo, iCertificate, &dummy,
53  KEYMGMT_ITEM_PUBLICKEY, CRYPT_IKEYID_ISSUERID,
54  issuerID, issuerIDlength, KEYMGMT_FLAG_NONE,
55  errorInfo ) );
56  }
57 
58 /****************************************************************************
59 * *
60 * Certificate Revocation Functions *
61 * *
62 ****************************************************************************/
63 
64 /* Handle an indirect certificate revocation (one where we need to reverse a
65  certificate issue or otherwise remove the certificate without obtaining a
66  direct revocation request from the user). The various revocation
67  situations are:
68 
69  Complete cert renewal original certificate supplied
70  CERTACTION_REVOKE_CERT reason = superseded
71  fail -> straight delete
72 
73  Reverse issue due to cancel in CMP original certificate supplied
74  CERTACTION_CREATION_REVERSE reason = neverValid
75  date = certificate issue date
76  fail -> straight delete
77 
78  Undo issue after restart original certificate supplied
79  CERTACTION_CREATION_REVERSE reason = neverValid
80  date = certificate issue date
81  fail -> straight delete
82 
83  ( Standard revocation original certificate not supplied
84  CERTACTION_REVOKE_CERT reason = <in request>
85  delete request
86  fail -> no action ) */
87 
88 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
89 int revokeCertDirect( INOUT DBMS_INFO *dbmsInfo,
90  IN_HANDLE const CRYPT_CERTIFICATE iCertificate,
91  IN_ENUM( CRYPT_CERTACTION ) \
92  const CRYPT_CERTACTION_TYPE action,
93  INOUT ERROR_INFO *errorInfo )
94  {
95  CRYPT_CERTIFICATE iLocalCRL;
96  MESSAGE_CREATEOBJECT_INFO createInfo;
97  time_t certDate;
98  int status;
99 
100  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
101 
102  REQUIRES( isHandleRangeValid( iCertificate ) );
103  REQUIRES( action == CRYPT_CERTACTION_REVOKE_CERT || \
105  REQUIRES( errorInfo != NULL );
106 
107  /* Get any information needed for the revocation from the certificate */
109  {
111 
112  setMessageData( &msgData, &certDate, sizeof( time_t ) );
113  status = krnlSendMessage( iCertificate, IMESSAGE_GETATTRIBUTE_S,
114  &msgData, CRYPT_CERTINFO_VALIDFROM );
115  if( cryptStatusError( status ) )
116  return( status );
117  }
118 
119  /* Create a (single-entry) CRL to contain the revocation information for
120  the certificate and revoke it via the standard channels. We go
121  directly to a CRL rather than doing it via a revocation request
122  because we need to add information that can only be added by a CA and
123  only to a CRL */
127  &createInfo, OBJECT_TYPE_CERTIFICATE );
128  if( cryptStatusError( status ) )
129  return( status );
130  iLocalCRL = createInfo.cryptHandle;
131  status = krnlSendMessage( iLocalCRL, IMESSAGE_SETATTRIBUTE,
132  ( MESSAGE_CAST ) &iCertificate,
134  if( cryptStatusError( status ) )
135  {
137  retExt( status,
138  ( status, errorInfo,
139  "Couldn't create CRL entry from certificate to be "
140  "revoked" ) );
141  }
142  if( action == CRYPT_CERTACTION_REVOKE_CERT )
143  {
144  static const int crlReason = CRYPT_CRLREASON_SUPERSEDED;
145 
146  /* We're revoking the certificate because we're about to replace it,
147  set the revocation reason to superseded */
148  status = krnlSendMessage( iLocalCRL, IMESSAGE_SETATTRIBUTE,
149  ( MESSAGE_CAST ) &crlReason,
151  }
152  else
153  {
154  static const int crlReason = CRYPT_CRLREASON_NEVERVALID;
156 
157  /* We're revoking a certificate issued in error, set the revocation
158  and invalidity dates to the same value (the time of certificate
159  issue) in the hope of ensuring that it's regarded as never being
160  valid. This isn't too accurate but since X.509 makes the
161  assumption that all CAs are perfect and never make mistakes
162  there's no other way to indicate that a certificate was issued in
163  error. In addition to this we set the extended reason to
164  neverValid, but not too many implementations will check this */
165  setMessageData( &msgData, &certDate, sizeof( time_t ) );
166  status = krnlSendMessage( iLocalCRL, IMESSAGE_SETATTRIBUTE_S,
167  &msgData, CRYPT_CERTINFO_REVOCATIONDATE );
168  if( cryptStatusOK( status ) )
169  status = krnlSendMessage( iLocalCRL, IMESSAGE_SETATTRIBUTE_S,
170  &msgData, CRYPT_CERTINFO_INVALIDITYDATE );
171  if( cryptStatusOK( status ) )
172  status = krnlSendMessage( iLocalCRL, IMESSAGE_SETATTRIBUTE,
173  ( MESSAGE_CAST ) &crlReason,
175  }
176  if( cryptStatusOK( status ) )
177  status = krnlSendMessage( iLocalCRL, IMESSAGE_SETATTRIBUTE,
179  CRYPT_IATTRIBUTE_INITIALISED );
180  if( cryptStatusError( status ) )
181  {
183  retExt( status,
184  ( status, errorInfo,
185  "Couldn't add revocation status information to CRL for "
186  "certificate revocation" ) );
187  }
188  status = caRevokeCert( dbmsInfo, iLocalCRL, iCertificate, action,
189  errorInfo );
191  return( status );
192  }
193 
194 /* Revoke a certificate from a revocation request */
195 
196 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
197 int caRevokeCert( INOUT DBMS_INFO *dbmsInfo,
198  IN_HANDLE const CRYPT_CERTIFICATE iCertRequest,
199  IN_HANDLE_OPT const CRYPT_CERTIFICATE iCertificate,
200  IN_ENUM( CRYPT_CERTACTION ) const CRYPT_CERTACTION_TYPE action,
201  INOUT ERROR_INFO *errorInfo )
202  {
203  CRYPT_CERTIFICATE iLocalCertificate = iCertificate;
204  CRYPT_CERTIFICATE iLocalCRL = iCertRequest;
205  BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
206  BYTE certData[ MAX_CERT_SIZE + 8 ];
207  char reqCertID[ ENCODED_DBXKEYID_SIZE + 8 ], *reqCertIDptr = reqCertID;
208  char subjCertID[ ENCODED_DBXKEYID_SIZE + 8 ];
209  char specialCertID[ ENCODED_DBXKEYID_SIZE + 8 ];
210  const BOOLEAN reqPresent = \
211  ( action == CRYPT_CERTACTION_RESTART_REVOKE_CERT || \
212  ( action == CRYPT_CERTACTION_REVOKE_CERT && \
213  iCertificate == CRYPT_UNUSED ) ) ? TRUE : FALSE;
215  int specialCertIDlength = DUMMY_INIT, status = CRYPT_OK;
216 
217  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
218 
219  REQUIRES( isHandleRangeValid( iCertRequest ) );
220  REQUIRES( iCertificate == CRYPT_UNUSED || \
221  isHandleRangeValid( iCertificate ) );
222  REQUIRES( action == CRYPT_CERTACTION_REVOKE_CERT || \
225  REQUIRES( errorInfo != NULL );
226 
227  /* This function handles a number of operations as summarised in the
228  table below:
229 
230  Operation Action Request On disk Cert
231  --------- ------ ------- ------- ----
232  Complete revocation RESTART_REVOKE_CERT Rev.req Yes --
233  on restart
234 
235  Standard revocation REVOKE_CERT Rev.req Yes --
236 
237  Complete renewal REVOKE_CERT crlEntry -- Supplied
238 
239  Reverse issue (CMP CREATION_REVERSE crlEntry -- Supplied
240  or due to restart)
241 
242  The following assertion checks that the certificate parameter is
243  correct. Checking the request parameter isn't so easy since it
244  requires multiple function calls, and is done as part of the code */
246  iCertificate == CRYPT_UNUSED ) || \
247  ( action == CRYPT_CERTACTION_REVOKE_CERT ) || \
249  isHandleRangeValid( iCertificate ) ) );
250 
251  /* If it's a standard revocation (rather than one done as part of an
252  internal certificate management operation, which passes in a single-
253  entry CRL) fetch the certificate that we're going to revoke and set
254  up a CRL object to contain the revocation information */
255  if( iCertificate == CRYPT_UNUSED )
256  {
257  MESSAGE_CREATEOBJECT_INFO createInfo;
258 
259  /* Get the certificate being revoked via the revocation request */
260  status = getKeyID( reqCertID, ENCODED_DBXKEYID_SIZE, &reqCertIDlength,
261  iCertRequest, CRYPT_CERTINFO_FINGERPRINT_SHA1 );
262  if( cryptStatusOK( status ) )
263  status = getCertToRevoke( dbmsInfo, &iLocalCertificate,
264  iCertRequest, errorInfo );
265  if( cryptStatusError( status ) )
266  {
267  retExtErr( status,
268  ( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
269  "Couldn't find certificate to revoke in "
270  "certificate store: " ) );
271  }
272 
273  /* Create the CRL to contain the revocation information */
276  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
278  if( cryptStatusOK( status ) )
279  {
280  /* Fill in the CRL from the revocation request */
281  iLocalCRL = createInfo.cryptHandle;
282  status = krnlSendMessage( iLocalCRL, IMESSAGE_SETATTRIBUTE,
283  ( MESSAGE_CAST ) &iCertRequest,
284  CRYPT_IATTRIBUTE_REVREQUEST );
285  if( cryptStatusError( status ) )
287  }
288  if( cryptStatusError( status ) )
289  {
290  krnlSendNotifier( iLocalCertificate, IMESSAGE_DECREFCOUNT );
291  retExt( status,
292  ( status, errorInfo,
293  "Couldn't create CRL from revocation request" ) );
294  }
295 
296  }
297  else
298  {
299  /* This is a direct revocation done as part of an internal
300  certificate management operation, there's no explicit request
301  for the revocation present and the caller has passed us a CRL
302  ready to use */
303  reqCertIDptr = NULL;
304  reqCertIDlength = 0;
305  }
306  status = getKeyID( subjCertID, ENCODED_DBXKEYID_SIZE, &subjCertIDlength,
307  iLocalCertificate, CRYPT_CERTINFO_FINGERPRINT_SHA1 );
308  if( cryptStatusOK( status ) )
309  status = extractCertData( iLocalCRL, CRYPT_IATTRIBUTE_CRLENTRY,
310  certData, MAX_CERT_SIZE, &certDataLength );
311  if( cryptStatusError( status ) )
312  {
313  /* If we created the necessary objects locally rather than having
314  them passed in by the caller we have to clean them up again
315  before we exit */
316  if( iCertificate == CRYPT_UNUSED )
317  {
318  krnlSendNotifier( iLocalCertificate, IMESSAGE_DECREFCOUNT );
320  }
321  retExt( status,
322  ( status, errorInfo,
323  "Couldn't extract CRL data to add to certificate store" ) );
324  }
325 
326  /* If it's a certificate creation reversal operation then the
327  certificate will be stored under a special temporary-status ID so we
328  turn the general subject certID into the form required for
329  special-case certificate data */
331  {
332  memcpy( specialCertID, subjCertID, subjCertIDlength );
333  memcpy( specialCertID, KEYID_ESC1, KEYID_ESC_SIZE );
334  specialCertIDlength = subjCertIDlength;
335  }
336 
337  /* Update the certificate store. This is the ugliest CA operation since
338  it touches every table, luckily it's performed only rarely.
339 
340  If this is a reversal operation or revocation of a certificate to be
341  replaced, which is a direct follow-on to a certificate creation,
342  there's no corresponding request present so we don't have to update
343  the requests table */
344  status = addCRL( dbmsInfo, iLocalCRL, iLocalCertificate,
345  DBMS_UPDATE_BEGIN, errorInfo );
346  if( cryptStatusOK( status ) )
347  {
348  status = updateCertLog( dbmsInfo, action, NULL, 0, reqCertIDptr,
349  reqCertIDlength, subjCertID,
350  subjCertIDlength, certData, certDataLength,
352  }
353  if( cryptStatusOK( status ) && reqPresent )
354  {
355  initBoundData( boundDataPtr );
356  setBoundData( boundDataPtr, 0, reqCertID, reqCertIDlength );
357  status = dbmsUpdate(
358  "DELETE FROM certRequests WHERE certID = ?",
359  boundDataPtr, DBMS_UPDATE_CONTINUE );
360  }
361  if( cryptStatusOK( status ) )
362  {
363  initBoundData( boundDataPtr );
365  {
366  setBoundData( boundDataPtr, 0, specialCertID,
367  specialCertIDlength );
368  status = dbmsUpdate(
369  "DELETE FROM certificates WHERE certID = ?",
370  boundDataPtr, DBMS_UPDATE_COMMIT );
371  }
372  else
373  {
374  setBoundData( boundDataPtr, 0, subjCertID, subjCertIDlength );
375  status = dbmsUpdate(
376  "DELETE FROM certificates WHERE certID = ?",
377  boundDataPtr, DBMS_UPDATE_COMMIT );
378  }
379  }
380  else
381  {
382  /* Something went wrong, abort the transaction */
383  dbmsUpdate( NULL, NULL, DBMS_UPDATE_ABORT );
384  }
385  if( iCertificate == CRYPT_UNUSED )
386  {
387  /* If we created the necessary objects locally rather than having
388  them passed in by the caller we have to clean them up again
389  before we exit */
390  krnlSendNotifier( iLocalCertificate, IMESSAGE_DECREFCOUNT );
392  }
393  if( cryptStatusOK( status ) )
394  return( CRYPT_OK );
395 
396  /* The operation failed, record the details */
397  updateCertErrorLog( dbmsInfo, status,
399  "Certificate issue reversal operation failed, "
400  "performing straight delete" : \
401  ( action == CRYPT_CERTACTION_REVOKE_CERT && \
402  iCertificate != CRYPT_UNUSED ) ? \
403  "Revocation of certificate to be replaced failed, "
404  "performing straight delete" :
405  "Certificate revocation operation failed",
406  NULL, 0, reqCertIDptr, reqCertIDlength, NULL, 0,
407  NULL, 0 );
408 
409  /* If it was a user-initiated operation we can't try and clean up the
410  operation internally */
411  if( reqPresent )
412  {
413  retExtErr( status,
414  ( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
416  "Certificate issue reversal operation failed: " : \
417  ( action == CRYPT_CERTACTION_REVOKE_CERT && \
418  iCertificate != CRYPT_UNUSED ) ? \
419  "Revocation of certificate to be replaced "
420  "failed: " :
421  "Certificate revocation operation failed: " ) );
422  }
423 
425  action == CRYPT_CERTACTION_REVOKE_CERT );
426 
427  /* It was a direct revocation done invisibly as part of an internal
428  certificate management operation, try again with a straight delete */
429  initBoundData( boundDataPtr );
431  {
432  setBoundData( boundDataPtr, 0, specialCertID, specialCertIDlength );
433  status = dbmsUpdate(
434  "DELETE FROM certificates WHERE certID = ?",
435  boundDataPtr, DBMS_UPDATE_NORMAL );
436  }
437  else
438  {
439  setBoundData( boundDataPtr, 0, subjCertID, subjCertIDlength );
440  status = dbmsUpdate(
441  "DELETE FROM certificates WHERE certID = ?",
442  boundDataPtr, DBMS_UPDATE_NORMAL );
443  }
444  if( cryptStatusOK( status ) )
445  {
446  /* The fallback straight delete succeeded, exit with a warning */
447  retExt( CRYPT_OK,
448  ( CRYPT_OK, errorInfo,
449  "Warning: Direct certificate revocation operation failed, "
450  "revocation was handled via straight delete" ) );
451  }
452 
453  /* The fallback failed as well, we've run out of options */
454  updateCertErrorLogMsg( dbmsInfo, status,
455  "Fallback straight delete failed" );
456  retExtErr( status,
457  ( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
459  "Certificate issue reversal operation failed: " : \
460  ( action == CRYPT_CERTACTION_REVOKE_CERT && \
461  iCertificate != CRYPT_UNUSED ) ? \
462  "Revocation of certificate to be replaced failed: " :
463  "Certificate revocation operation failed: " ) );
464  }
465 
466 /* Create a CRL from revocation entries in the certificate store */
467 
468 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
469 int caIssueCRL( INOUT DBMS_INFO *dbmsInfo,
472  INOUT ERROR_INFO *errorInfo )
473  {
474  MESSAGE_CREATEOBJECT_INFO createInfo;
475  BOUND_DATA boundData[ BOUND_DATA_MAXITEMS ], *boundDataPtr = boundData;
476  BYTE crlEntry[ MAX_QUERY_RESULT_SIZE + 8 ];
477  BOOLEAN crlEntryAdded = FALSE;
478  char crlEntryBuffer[ MAX_QUERY_RESULT_SIZE + 8 ];
479  void *crlEntryPtr = hasBinaryBlobs( dbmsInfo ) ? \
480  crlEntry : ( void * ) crlEntryBuffer;
481  /* Cast needed for gcc */
482  char nameID[ ENCODED_DBXKEYID_SIZE + 8 ];
483  char *operationString = "No error";
484  int operationStatus = CRYPT_OK, nameIDlength;
485  int errorCount, iterationCount, status;
486 
487  assert( isWritePtr( dbmsInfo, sizeof( DBMS_INFO ) ) );
488  assert( isWritePtr( iCryptCRL, sizeof( CRYPT_CERTIFICATE ) ) );
489 
490  REQUIRES( isHandleRangeValid( caKey ) );
491  REQUIRES( errorInfo != NULL );
492 
493  /* Extract the information that we need to build the CRL from the CA
494  certificate */
495  status = getKeyID( nameID, ENCODED_DBXKEYID_SIZE, &nameIDlength,
496  caKey, CRYPT_IATTRIBUTE_SUBJECT );
497  if( cryptStatusError( status ) )
498  return( status );
499 
500  /* Create the CRL object to hold the entries */
503  &createInfo, OBJECT_TYPE_CERTIFICATE );
504  if( cryptStatusError( status ) )
505  return( status );
506 
507  /* Submit a query to fetch every CRL entry for this CA. We don't have
508  to do a date check since the presence of revocation entries for
509  expired certificates is controlled by whether the CA's policy
510  involves removing entries for expired certificates or not */
511  initBoundData( boundDataPtr );
512  setBoundData( boundDataPtr, 0, nameID, nameIDlength );
513  status = dbmsQuery(
514  "SELECT certData FROM CRLs WHERE nameID = ?",
515  NULL, 0, NULL, boundDataPtr,
517  if( cryptStatusError( status ) )
518  {
520  retExtErr( status,
521  ( status, errorInfo, getDbmsErrorInfo( dbmsInfo ),
522  "Couldn't initiate CRL data fetch from certificate "
523  "store: " ) );
524  }
525 
526  /* Rumble through the certificate store fetching every entry and adding
527  it to the CRL. We only stop once we've run out of entries or we hit
528  too many errors which ensures that some minor error at some point
529  won't prevent the CRL from being issued, however if there was a
530  problem somewhere we create a log entry to record it */
531  for( errorCount = 0, iterationCount = 0;
532  status != CRYPT_ERROR_COMPLETE && \
533  errorCount < FAILSAFE_ITERATIONS_SMALL && \
534  iterationCount < FAILSAFE_ITERATIONS_LARGE;
535  iterationCount++ )
536  {
538  int crlEntryLength;
539 
540  /* Read the CRL entry data */
541  status = dbmsQuery( NULL, crlEntryPtr, MAX_QUERY_RESULT_SIZE,
542  &crlEntryLength, NULL, DBMS_CACHEDQUERY_NONE,
544  if( status == CRYPT_ERROR_COMPLETE )
545  {
546  /* We've got all the entries, complete the query and exit */
549  break;
550  }
551  if( cryptStatusOK( status ) && !hasBinaryBlobs( dbmsInfo ) )
552  {
553  status = base64decode( crlEntry, MAX_CERT_SIZE, &crlEntryLength,
554  crlEntryBuffer, crlEntryLength,
556  }
557  if( cryptStatusError( status ) )
558  {
559  /* Remember the error details for later if necessary */
560  if( cryptStatusOK( operationStatus ) )
561  {
562  operationStatus = status;
563  operationString = "Some CRL entries couldn't be read from "
564  "the certificate store";
565  }
566  errorCount++;
567  continue;
568  }
569 
570  /* Add the entry to the CRL */
571  setMessageData( &msgData, crlEntry, crlEntryLength );
572  status = krnlSendMessage( createInfo.cryptHandle,
573  IMESSAGE_SETATTRIBUTE_S, &msgData,
574  CRYPT_IATTRIBUTE_CRLENTRY );
575  if( cryptStatusError( status ) )
576  {
577  /* Remember the error details for later if necessary */
578  if( cryptStatusOK( operationStatus ) )
579  {
580  operationStatus = status;
581  operationString = "Some CRL entries couldn't be added to "
582  "the CRL";
583  }
584  errorCount++;
585  continue;
586  }
587 
588  crlEntryAdded = TRUE;
589  }
590  if( errorCount >= FAILSAFE_ITERATIONS_SMALL || \
591  iterationCount >= FAILSAFE_ITERATIONS_LARGE )
592  {
593  /* It's hard to tell what type of error an iterationCount-exceeded
594  situation really is, in theory it's a software error (either in
595  cryptlib's fetch logic or in the dabatase) but because of the
596  practice of creating mega-CRLs with thousands of entries it's
597  entirely possible that this is "normal", or at least "normal" in
598  the alternative reality of X.509. Because of this we don't flag
599  it as an internal error but simply warn in the debug build,
600  although we do bail out rather than trying to construct some
601  monster CRL */
602  DEBUG_DIAG(( "CRL-entry-fetch loop detected" ));
603  assert( DEBUG_WARN );
604  }
605  if( cryptStatusError( operationStatus ) )
606  {
607  /* If nothing could be added to the CRL something is wrong, don't
608  try and continue */
609  if( !crlEntryAdded )
610  {
611  updateCertErrorLogMsg( dbmsInfo, operationStatus,
612  "No CRL entries could be added to the "
613  "CRL" );
614  retExt( operationStatus,
615  ( operationStatus, errorInfo,
616  "No CRL entries could be added to the CRL" ) );
617  }
618 
619  /* At least some entries could be added to the CRL, record that there
620  was a problem but continue */
621  updateCertErrorLogMsg( dbmsInfo, operationStatus, operationString );
622  }
623 
624  /* We've got all the CRL entries, sign the CRL and return it to the
625  caller */
626  status = krnlSendMessage( createInfo.cryptHandle, IMESSAGE_CRT_SIGN,
627  NULL, caKey );
628  if( cryptStatusError( status ) )
629  {
630  if( status == CRYPT_ARGERROR_VALUE )
631  status = CAMGMT_ARGERROR_CAKEY; /* Map to correct error code */
633  updateCertErrorLogMsg( dbmsInfo, operationStatus,
634  "CRL creation failed" );
635  retExtArg( status,
636  ( status, errorInfo,
637  "Couldn't sign CRL to be issued" ) );
638  }
639  *iCryptCRL = createInfo.cryptHandle;
640  updateCertLog( dbmsInfo, CRYPT_CERTACTION_ISSUE_CRL,
641  NULL, 0, NULL, 0, NULL, 0, NULL, 0, DBMS_UPDATE_NORMAL );
642  return( CRYPT_OK );
643  }
644 #endif /* USE_DBMS */