To insure system integrity, a module developer must create a set of digital credentials to be verified by CSSM when the module is attached.
The module developer will need to create an installation program to inform CSSM and applications of the module's identity and capabilities.
Finally, the module developer will need to insure that the appropriate sequence of component verification and module initialization steps occur prior to dynamic binding of the module with CSSM.
These three objects must be zipped to form a single set of credentials. Multiple implementations of standard zip algorithms interoperate on one or more platforms, hence a zipped, signed manifest retains a substantial degree of interoperability.
The module's certificate is the leaf in one or more certificate
chains. Each chain is rooted at one of a small number of known,
trusted public keys. A single chain is shown in
The manifest forms a complete description of an add-in module. A manifest includes a manifest section for each object code file that is part of a module's implementation. Each manifest section contains:
The object code files are standard OS-managed entities. Object files do not embed their digital signatures, instead, signatures are stored in a manifest separate from, but related to, the object files.
A digest of each manifest section is then computed and stored in the signature info file.
The signature file contains the PKCS#7 signature computed over the signature info file.
This set of credentials must be manufactured when the module is manufactured. Assuming a module manufacturer already has a certificate from a CSSM manufacturer, the module manufacturing process proceeds as follows:
It is of the utmost importance that the object code files and the manifest be signed using the private key associated with the product certificate. This tightly binds the identity in the certificate with "what the module is" (that is, the object code files themselves) and with "what the module claims it is" (that is, the capability descriptions in the manifest).
An add-in module that performs self-check and/or authenticates CSSM during module attach must:
The root of trust for self-check is the public key of the product certificate. The root of trust for authenticating a CSSM is the public root key of the CSSM vendor. Roots of trust can be presented as certificates or as keys. The add-in module should include the roots for all CSSM vendors that it trusts. This knowledge can be embedded as part of the module manufacturing process. Once the roots of trust are known, attach-time integrity checking is performed by invoking the Embedded Integrity Services Library (EISL).
CSSM invokes the module's AddInAuthenticate function to initiate the module's integrity check of CSSM. Although CSSM cannot determine that the add-in module has performed self-check and verified CSSM's credentials it is highly recommended that modules use EISL to perform these checks at attach-time and periodically during execution based on elapsed time or usage. Failure to perform these verifications during module attach processing compromises the integrity of the entire runtime environment.
After the roots of trust have been incorporated into the software component of the product and all product software components have been compiled and linked with EISL, the add-in module credentials should be created. These credentials are partitioned and persistently stored in three files:
The manifest file contains:
The capability description is mandatory for add-in modules that provide cryptographic services. It is highly recommended that all add-in modules, regardless of service type, include their capability description in their manifest file. The description is a flattened representation of the information defined by the CSSM_MODULE_INFO structure. This information is stored as an attribute value in the manifest. The hashes must be computed and included in the manifest file.
After the manifest file is created, the signer information file is created. The signer's information file must contain:
Finally the signature block file is created. The signature block file must contain:
The signing operation must be performed using the private key associated with the product certificate.
These credentials (three files) must be included with the add-in module that will be installed using CSSM_ModuleInstall. During installation these files should be placed in a subdirectory of the file system directory containing the add-in module object code files.
A GUID is defined as:
typedef struct cssm_guid {
uint32 Data1;
uint16 Data2;
uint16 Data3;
uint8 Data4[8];
} CSSM_GUID, *CSSM_GUID_PTR;
GUID generators are publicly available for Windows* 95, Windows NT*, and on many UNIX* platforms.
The Embedded Integrity Services Library (EISL) must be used to perform this verification. If verification fails, the add-in module is responsible for terminating the attach process. When EISL returns a failure condition, then either the CSSM has been tampered or the attaching add-in module does not recognize the certificate of the CSSM that is attempting to attach the add-in module. The add-in module must terminate the attach. The module should not register it service function table with the suspect CSSM. The add-in module should perform clean-up operations and exit voluntarily. The module has refused to provide service in an environment that it could not verify. If verification succeeds, then the add-in module should proceed to register with CSSM.
On registration, the add-in module registers its tables of service function pointers with CSSM and receives the application's memory management upcalls. CSSM then uses the module function table to call the module's Initialize function to confirm version compatibility and calls the module's EventNotify function to indicate that an attach operation is occurring. Once these steps have successfully completed, CSSM returns a handle to the calling application which will identify the application to module sub-service pairing in future function calls. CSSM will notify the module of subsequent attach requests from the application by using the module's EventNotify function. Subsequent attach operations do not require integrity verification.
The basic steps in bilateral authentication during module attach are defined as follows:
Each authenticating entity invokes ISL functions to carry out the steps in this process. The following ISL functions are used to carry out the seven step bilateral authentication protocol:
The ISL Verify functions check all aspects of a module's credentials, including the certificate chain, the signature on the manifest, the signature on the capability descriptions, and the signature on each object code file. The ISL Verify functions cannot check for secure linkage. CSSM and the add-in module must use the ISL address checking functions to verify secure linkage with the party being verified. The purpose of the secure linkage check is to verify that the object code just verified is either the code you are about to invoke or the code that invoked you. To free the data structures used in bilateral authentication, the ISL provides a Recycle function.
Memory management upcalls are pointers to the memory management functions used by the calling application. They are provided to a module via CSSM as a structure of function pointers. The functions will be the calling application's equivalent of malloc, free, calloc, and re-alloc and will be expected to have the same behavior as those functions. The function parameters will consist of the normal parameters for that function. The function return values should be interpreted in the standard manner. A module is responsible for making the memory management functions available to all of its internal functions.
The error number set by a module sub-service should fall into one of
two ranges. The first range of error numbers is pre-defined by CSSM.
These are errors that are common to all modules implementing a given
sub-service function. They are described in
the CSSM Cryptographic Service Provider Interface Specification as part of the function definitions.
They are defined in the header file
When no error has occurred, but the appropriate return value from a function is CSSM_FALSE, that function should call CSSM_ClearError before returning. When the application receives a CSSM_FALSE return value, it is responsible for checking whether an error has occurred by calling CSSM_GetError. If the module function has called CSSM_ClearError, the calling application receives a CSSM_OK response from the CSSM_GetError function, indicating no error has occurred.
#include "cssm.h"
CSSM_GUID clm_guid =
{ 0x5fc43dc1, 0x732, 0x11d0, { 0xbb, 0x14, 0x0, 0xaa, 0x0,
0x36, 0x67, 0x2d } };
CSSM_BOOL CLModuleInstall()
{
CSSM_VERSION cssm_version = { CSSM_MAJOR, CSSM_MINOR };
CSSM_VERSION cl_version = { CLM_MAJOR_VER, CLM_MINOR_VER };
CSSM_GUID cl_guid = clm_guid;
CSSM_CLSUBSERVICE sub_service;
CSSM_SERVICE_INFO service_info;
CSSM_MODULE_INFO module_info;
char SysDir[_MAX_PATH];
/* fill sub-service information */
sub_service.SubServiceId = 0;
strcpy(sub_service.Description, "X509v3 SubService");
sub_service.CertType = CSSM_CERT_X_509v3;
sub_service.CertEncoding = CSSM_CERT_ENCODING_DER;
sub_service.AuthenticationMechanism = CSSM_AUTHENTICATION_NONE;
sub_service.NumberOfTemplateFields = NUMBER_X509_CERT_OIDS;
sub_service.CertTemplates = X509_CERT_OIDS_ARRAY;
sub_service.NumberOfTranslationTypes = 0;
sub_service.CertTranslationTypes = NULL;
sub_service.WrappedProduct.EmbeddedEncoderProducts = NULL;
sub_service.WrappedProduct.NumberOfEncoderProducts = 0;
sub_service.WrappedProduct.AccessibleCAProducts = NULL;
sub_service.WrappedProduct.NumberOfCAProducts = 0;
/* fill service information */
strcpy(service_info.Description, "CL Service");
service_info.Type = CSSM_SERVICE_CL;
service_info.Flags = 0;
service_info.NumberOfSubServices = 1;
service_info.ClSubServiceList = &sub_service;
service_info.Reserved = NULL;
/* fill module information */
module_info.Version = cl_version;
module_info.CompatibleCSSMVersion = cssm_version;
strcpy(module_info.Description, "Vendor Module");
strcpy(module_info.Vendor, "Vendor Name");
module_info.Flags = 0;
module_info.ServiceMask = CSSM_SERVICE_CL;
module_info.NumberOfServices = 1;
module_info.ServiceList = &service_info;
module_info.Reserved = NULL;
/* get system dir path */
GetSystemDirectory(SysDir, _MAX_PATH);
/* Install the module */
if (CSSM_ModuleInstall(clm_fullname_string,
clm_filename_string,
SysDir,
&clm_guid,
&module_info,
NULL,
NULL) == CSSM_FAIL)
{
return CSSM_FALSE;
}
return CSSM_TRUE;
}
#include "cssm.h"
CSSM_GUID dl_guid =
{ 0x5fc43dc1, 0x732, 0x11d0, { 0xbb, 0x14, 0x0, 0xaa, 0x0,
0x36, 0x67, 0x2d } };
CSSM_SPI_DL_FUNCS FunctionTable;
CSSM_REGISTRATION_INFO DLRegInfo;
CSSM_MODULE_FUNCS Services;
CSSM_SPI_MEMORY_FUNCS DLMemoryFunctions;
BOOL WINAPI DllMain ( HANDLE hInstance, DWORD dwReason,
LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
{
ISL_VERIFIED_MODULE_PTR VerifiedDLModulePtr = NULL;
VerifiedDLModulePtr = ISL_SelfCheck();
if(VerifiedDLModulePtr == NULL) return FALSE;
ISL_RecycleVerifiedModuleCredentials
(VerifiedDLModulePtr);
break;
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
if (CSSM_DeregisterServices (&dl_guid) != CSSM_OK)
return FALSE;
break;
}
return TRUE;
}
CSSM_RETURN CSSMAPI AddInAuthenticate
(char* cssmCredentialPath,
char* cssmSection
char* appFileName,
char* appPathName)
{
ISL_VERIFIED_MODULE_PTR VerifiedCLModulePtr = NULL;
ISL_STATUS islret;
void* retAddress;
ISL_CONST_DATA ConstData = {0, NULL};
ISL_CONST_DATA ConstPathData = {0, NULL};
ISL_CONST_DATA ConstSectionData = {0, NULL};
ConstPathData.Length = strlen(cssmCredentialPath);
ConstPathData.Data = (uint8*) cssmCredentialPath;
ConstSectionData.Length = strlen(cssmSection);
ConstSectionData.Data = (uint8*) cssmSection;
/* Verify CSSM's static and dynamic footprint based on its
manifest */
VerifiedCSSMModulePtr =
ISL_VerifyLoadedModuleAndCredentials
(ConstPathDataConstSectionData,ConstData,ConstData);
if(VerifiedCSSMModulePtr == NULL)
return CSSM_FAIL;
/* Verify secure linkage with CSSM */
ISL_GetReturnAddress(retAddress);
islret = ISL_CheckAddressWithinModule
(VerifiedCSSMModulePtr, retAddress);
if(islret == ISL_FAIL)
{
ISL_RecycleVerifiedModuleCredentials(VerifiedCSSMModulePtr);
VerifiedCSSMModulePtr = NULL;
return CSSM_FAIL;
}
ISL_RecycleVerifiedModuleCredentials(VerifiedCSSMModulePtr);
/* Authenticate application credentials directly if required*/
if((appFileName == NULL) ]] (appPathName == NULL))
return CSSM_FAIL;
else
{
/* Verify the application's credentials */
}
/* Fill in Registration information and register services
with CSSM*/
DLRegInfo.Initialize = DL_Initialize;
DLRegInfo.Terminate = DL_Uninitialize;
DLRegInfo.EventNotify = DL_EventNotify;
DLRegInfo.GetModuleInfo = NULL;
DLRegInfo.FreeModuleInfo = NULL;
DLRegInfo.ThreadSafe = CSSM_TRUE;
DLRegInfo.ServiceSummary = CSSM_SERVICE_DL;
DLRegInfo.NumberOfServiceTables = 1;
DLRegInfo.Services = &Services;
/* Fill in Services */
Services.ServiceType = CSSM_SERVICE_DL;
Services.DlFuncs = &FunctionTable;
/* Fill in FunctionTable with function pointers */
FunctionTable.Authenticate = DL_Authenticate;
FunctionTable.DbOpen = DL_DbOpen;
FunctionTable.DbClose = DL_DbClose;
/* initialize all the other function pointers */
FunctionTable.PassThrough = DL_PassThrough;
/* Call CSSM_RegisterServices to
register the FunctionTable */
/* with CSSM and to receive the application's
memory upcall table*/
if (CSSM_RegisterServices (&dl_guid, &DLRegInfo,
&DLMemoryFunctions,NULL) != CSSM_OK)
return FALSE;
/* Make the upcall table available to all
functions in this library */
}
Contents | Next section | Index |