000022485 - How to implement path validation processing based on validate.c using CryptoAPI database instead of IM database

Document created by RSA Customer Support Employee on Jun 16, 2016Last modified by RSA Customer Support Employee on Apr 21, 2017
Version 3Show Document
  • View in full screen mode

Article Content

Article Number000022485
Applies ToRSA BSAFE Cert-C
IssueHow to implement path validation processing based on validate.c using CryptoAPI database instead of IM database
How to retrieve root and intermediate certificates through CAPI, a handle of the CryptoAPI database provider must be set as the 2nd argument of C_ValidateCert
How to provide 2 SERVICE handles for both "ROOT" and "CA" to the argument
The second argument to C_ValidateCert is not a SERVICE, but a CERT_PATH_CTX *.  The original question is probably refering to the CERT_PATH_CTX.database field, which is a SERVICE handle.
The validate.c sample does not call C_ValidateCert.
Also, rarely is calling C_ValidateCert effective.  That is more of an internal routine that is made public and is badly named.  C_BuildCertPath is probably what you want to use to validate a certificate.  C_BuildCertPath calls C_ValidateCert.  When you use C_ValidateCert, it is the caller's responsibility to do the chaining and locate the appropriate public key, for example.  Most of the time, users want the toolkit to figure out the chaining, so 99% of the time people think about calling C_ValidateCert, they should actually be considering C_BuildCertPath.
ResolutionInstead of providing 2 SERVICE handles, the main idea is to use C_BindServices to bind multiple database instances to a single SERVICE.

/*  The number of service providers used in this example.  */
#define SP_COUNT 2

/*  Number of cert sources.  */

 char *dbNames[CERT_SOURCE_COUNT];

 MS_CAPI_DB_PARAMS capiRootDbParams, capiCaDbParams;

 spTable[0].type = SPT_DATABASE;
 spTable[0].name = "CAPI Root Database";
 spTable[0].Initialize = S_InitializeCryptoAPIDB;

 spTable[1].type = SPT_DATABASE;
 spTable[1].name = "CAPI CA Database";
 spTable[1].Initialize = S_InitializeCryptoAPIDB;

 dbNames[0] = spTable[0].name;
 dbNames[1] = spTable[1].name;


 spParams[0] = (POINTER)&capiRootDbParams;  
 spParams[1] = (POINTER)&capiCaDbParams;  

 capiRootDbParams.pCryptoProviderName =
   "Microsoft Enhanced Cryptographic Provider v1.0";
 capiRootDbParams.pKeyContainerName = "";
 capiRootDbParams.pCertSystemStoreName = "ROOT";
 capiRootDbParams.dwProviderType = 1;
 capiRootDbParams.dwKeySpec = 0;

 capiCaDbParams.pCryptoProviderName =
   "Microsoft Enhanced Cryptographic Provider v1.0";
 capiCaDbParams.pKeyContainerName = "";
 capiCaDbParams.pCertSystemStoreName = "CA";
 capiCaDbParams.dwProviderType = 1;
 capiCaDbParams.dwKeySpec = 0;

 status = C_InitializeCertC (spTable, spParams, SP_COUNT, &ctx);
 if (status != 0)
   goto CLEANUP;

 status = C_BindServices (ctx, SPT_DATABASE, dbNames,
                          CERT_SOURCE_COUNT, &db);
 if (status != 0)
   goto CLEANUP;

 C_UnbindService (&db);

See the samples/db/mscapiroots.c sample in Cert-C 2.5 and later versions for more details.

Use C_BuildCertPath and see the Library Reference Manual Entry for C_BuildCertPath for usage information.

If you would like to use the certs in the "ROOT" store as trused certs, you need to retrieve them and put them into a LIST_OBJ so that the CERT_PATH_CTX.trustedCerts can be set to that LIST_OBJ.  This can be accomplished by calling C_SelectFirstCert and C_SelectNextCert.  As an example, note the behavior of the DumpDatabaseContents() routine in the samples/db/mscapicert.c sample code file to move the certs in a given SERVICE into a LIST_OBJ.  That routine populates the certList LIST_OBJ and prints out the contents.

Note: If you are not seeing as many certs as you expect, you may need to How to skip invalid certificates when using the RSA BSAFE Cert-C CryptoAPI Service Provider which patches the CAPI database provider so that it does not stop at the first bad cert it encounters when enumerating the database.
Legacy Article IDa6306