|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
cert.c
Abstract:
Implements the certificates type module, which abstracts physical access to certificates
Author:
Calin Negreanu (calinn) 03 Oct 2001
Revision History:
--*/
//
// Includes
//
#include "pch.h"
#include "v1p.h"
#include "logmsg.h"
#include <wincrypt.h>
#define DBG_CERT "Certificates"
//
// Strings
//
#define S_CERT_POOL_NAME "Certificates"
#define S_CERT_NAME TEXT("Certificates")
//
// Constants
//
// None
//
// Macros
//
// None
//
// Types
//
typedef struct { HCERTSTORE StoreHandle; PCTSTR CertStore; PCTSTR CertPattern; PCCERT_CONTEXT CertContext; } CERT_ENUM, *PCERT_ENUM;
// Certificate APIs
// NT4 SP3
// Win95 OSR2
typedef HCERTSTORE(WINAPI CERTOPENSTORE) ( IN LPCSTR lpszStoreProvider, IN DWORD dwMsgAndCertEncodingType, IN HCRYPTPROV hCryptProv, IN DWORD dwFlags, IN const void *pvPara ); typedef CERTOPENSTORE *PCERTOPENSTORE;
// NT4 SP3
// Win95 OSR2
typedef PCCERT_CONTEXT(WINAPI CERTENUMCERTIFICATESINSTORE) ( IN HCERTSTORE hCertStore, IN PCCERT_CONTEXT pPrevCertContext ); typedef CERTENUMCERTIFICATESINSTORE *PCERTENUMCERTIFICATESINSTORE;
// NT4 SP3
// Win95 OSR2
typedef BOOL(WINAPI CERTGETCERTIFICATECONTEXTPROPERTY) ( IN PCCERT_CONTEXT pCertContext, IN DWORD dwPropId, OUT void *pvData, IN OUT DWORD *pcbData ); typedef CERTGETCERTIFICATECONTEXTPROPERTY *PCERTGETCERTIFICATECONTEXTPROPERTY;
// NT4 SP3
// Win95 OSR2
typedef BOOL(WINAPI CERTCLOSESTORE) ( IN HCERTSTORE hCertStore, IN DWORD dwFlags ); typedef CERTCLOSESTORE *PCERTCLOSESTORE;
// NT4 SP3
typedef BOOL(WINAPI CRYPTACQUIRECERTIFICATEPRIVATEKEY) ( IN PCCERT_CONTEXT pCert, IN DWORD dwFlags, IN void *pvReserved, OUT HCRYPTPROV *phCryptProv, OUT DWORD *pdwKeySpec, OUT BOOL *pfCallerFreeProv ); typedef CRYPTACQUIRECERTIFICATEPRIVATEKEY *PCRYPTACQUIRECERTIFICATEPRIVATEKEY;
// NT4 SP3
// Win95 OSR2
typedef BOOL(WINAPI CERTADDCERTIFICATECONTEXTTOSTORE) ( IN HCERTSTORE hCertStore, IN PCCERT_CONTEXT pCertContext, IN DWORD dwAddDisposition, OUT PCCERT_CONTEXT *ppStoreContext ); typedef CERTADDCERTIFICATECONTEXTTOSTORE *PCERTADDCERTIFICATECONTEXTTOSTORE;
// NT4 SP3
// Win95 OSR2
typedef BOOL(WINAPI CERTFREECERTIFICATECONTEXT) ( IN PCCERT_CONTEXT pCertContext ); typedef CERTFREECERTIFICATECONTEXT *PCERTFREECERTIFICATECONTEXT;
// NT4 SP3
// Win95 OSR2
typedef BOOL(WINAPI CERTDELETECERTIFICATEFROMSTORE) ( IN PCCERT_CONTEXT pCertContext ); typedef CERTDELETECERTIFICATEFROMSTORE *PCERTDELETECERTIFICATEFROMSTORE;
// Win2k?
// Win98?
typedef BOOL(WINAPI PFXEXPORTCERTSTORE) ( IN HCERTSTORE hStore, IN OUT CRYPT_DATA_BLOB* pPFX, IN LPCWSTR szPassword, IN DWORD dwFlags ); typedef PFXEXPORTCERTSTORE *PPFXEXPORTCERTSTORE;
// Win2k?
// Win98?
typedef HCERTSTORE(WINAPI PFXIMPORTCERTSTORE) ( IN CRYPT_DATA_BLOB* pPFX, IN PCWSTR szPassword, IN DWORD dwFlags ); typedef PFXIMPORTCERTSTORE *PPFXIMPORTCERTSTORE;
//
// Globals
//
PMHANDLE g_CertPool = NULL; BOOL g_DelayCertOp; MIG_OBJECTTYPEID g_CertType = 0; GROWBUFFER g_CertConversionBuff = INIT_GROWBUFFER;
PCERTOPENSTORE g_CertOpenStore = NULL; PCERTENUMCERTIFICATESINSTORE g_CertEnumCertificatesInStore = NULL; PCERTGETCERTIFICATECONTEXTPROPERTY g_CertGetCertificateContextProperty = NULL; PCERTCLOSESTORE g_CertCloseStore = NULL; PCRYPTACQUIRECERTIFICATEPRIVATEKEY g_CryptAcquireCertificatePrivateKey = NULL; PCERTADDCERTIFICATECONTEXTTOSTORE g_CertAddCertificateContextToStore = NULL; PCERTFREECERTIFICATECONTEXT g_CertFreeCertificateContext = NULL; PCERTDELETECERTIFICATEFROMSTORE g_CertDeleteCertificateFromStore = NULL; PPFXEXPORTCERTSTORE g_PFXExportCertStore = NULL; PPFXIMPORTCERTSTORE g_PFXImportCertStore = NULL;
//
// Types
//
// None
//
// Macro expansion list
//
// None
//
// Private function prototypes
//
// None
//
// Macro expansion definition
//
// None
//
// Private prototypes
//
TYPE_ENUMFIRSTPHYSICALOBJECT EnumFirstCertificate; TYPE_ENUMNEXTPHYSICALOBJECT EnumNextCertificate; TYPE_ABORTENUMPHYSICALOBJECT AbortCertificateEnum; TYPE_CONVERTOBJECTTOMULTISZ ConvertCertificateToMultiSz; TYPE_CONVERTMULTISZTOOBJECT ConvertMultiSzToCertificate; TYPE_GETNATIVEOBJECTNAME GetNativeCertificateName; TYPE_ACQUIREPHYSICALOBJECT AcquireCertificate; TYPE_RELEASEPHYSICALOBJECT ReleaseCertificate; TYPE_DOESPHYSICALOBJECTEXIST DoesCertificateExist; TYPE_REMOVEPHYSICALOBJECT RemoveCertificate; TYPE_CREATEPHYSICALOBJECT CreateCertificate; TYPE_CONVERTOBJECTCONTENTTOUNICODE ConvertCertificateContentToUnicode; TYPE_CONVERTOBJECTCONTENTTOANSI ConvertCertificateContentToAnsi; TYPE_FREECONVERTEDOBJECTCONTENT FreeConvertedCertificateContent;
//
// Code
//
BOOL CertificatesInitialize ( VOID )
/*++
Routine Description:
CertificateInitialize is the ModuleInitialize entry point for the certificates module.
Arguments:
None.
Return Value:
TRUE if init succeeded, FALSE otherwise.
--*/
{ g_CertPool = PmCreateNamedPool (S_CERT_POOL_NAME); return (g_CertPool != NULL); }
VOID CertificatesTerminate ( VOID )
/*++
Routine Description:
CertificatesTerminate is the ModuleTerminate entry point for the certificates module.
Arguments:
None.
Return Value:
None.
--*/
{ GbFree (&g_CertConversionBuff);
if (g_CertPool) { PmDestroyPool (g_CertPool); g_CertPool = NULL; } }
VOID WINAPI CertificatesEtmNewUserCreated ( IN PCTSTR UserName, IN PCTSTR DomainName, IN PCTSTR UserProfileRoot, IN PSID UserSid )
/*++
Routine Description:
CertificatesEtmNewUserCreated is a callback that gets called when a new user account is created. In this case, we must delay the apply of certificates, because we can only apply to the current user.
Arguments:
UserName - Specifies the name of the user being created DomainName - Specifies the NT domain name for the user (or NULL for no domain) UserProfileRoot - Specifies the root path to the user profile directory UserSid - Specifies the user's SID
Return Value:
None.
--*/
{ // a new user was created, the certificate operations need to be delayed
g_DelayCertOp = TRUE; }
BOOL pLoadCertEntries ( VOID ) { HMODULE cryptDll = NULL; BOOL result = FALSE;
__try { cryptDll = LoadLibrary (TEXT("CRYPT32.DLL")); } __except (EXCEPTION_EXECUTE_HANDLER) { cryptDll = NULL; } if (cryptDll) { g_CertOpenStore = (PCERTOPENSTORE) GetProcAddress (cryptDll, "CertOpenStore"); g_CertEnumCertificatesInStore = (PCERTENUMCERTIFICATESINSTORE) GetProcAddress (cryptDll, "CertEnumCertificatesInStore"); g_CertGetCertificateContextProperty = (PCERTGETCERTIFICATECONTEXTPROPERTY) GetProcAddress (cryptDll, "CertGetCertificateContextProperty"); g_CertCloseStore = (PCERTCLOSESTORE) GetProcAddress (cryptDll, "CertCloseStore"); g_CryptAcquireCertificatePrivateKey = (PCRYPTACQUIRECERTIFICATEPRIVATEKEY) GetProcAddress (cryptDll, "CryptAcquireCertificatePrivateKey"); g_CertAddCertificateContextToStore = (PCERTADDCERTIFICATECONTEXTTOSTORE) GetProcAddress (cryptDll, "CertAddCertificateContextToStore"); g_CertFreeCertificateContext = (PCERTFREECERTIFICATECONTEXT) GetProcAddress (cryptDll, "CertFreeCertificateContext"); g_PFXExportCertStore = (PPFXEXPORTCERTSTORE) GetProcAddress (cryptDll, "PFXExportCertStore"); g_CertDeleteCertificateFromStore = (PCERTDELETECERTIFICATEFROMSTORE) GetProcAddress (cryptDll, "CertDeleteCertificateFromStore"); g_PFXImportCertStore = (PPFXIMPORTCERTSTORE) GetProcAddress (cryptDll, "PFXImportCertStore");
// BUGBUG - verify that all functions are installed
} else { DEBUGMSG ((DBG_CERT, "Crypt APIs are not installed on this computer.")); } return result; }
BOOL WINAPI CertificatesEtmInitialize ( IN MIG_PLATFORMTYPEID Platform, IN PMIG_LOGCALLBACK LogCallback, IN PVOID Reserved )
/*++
Routine Description:
CertificatesEtmInitialize initializes the physical type module aspect of this code. The ETM module is responsible for abstracting all access to certificates.
Arguments:
Platform - Specifies the platform that the type is running on (PLATFORM_SOURCE or PLATFORM_DESTINATION) LogCallback - Specifies the arg to pass to the central logging mechanism Reserved - Unused
Return Value:
TRUE if initialization succeeded, FALSE otherwise.
--*/
{ TYPE_REGISTER certTypeData;
LogReInit (NULL, NULL, NULL, (PLOGCALLBACK) LogCallback);
//
// Register the type module callbacks
//
ZeroMemory (&certTypeData, sizeof (TYPE_REGISTER)); certTypeData.Priority = PRIORITY_CERTIFICATES;
if (Platform != PLATFORM_SOURCE) { certTypeData.RemovePhysicalObject = RemoveCertificate; certTypeData.CreatePhysicalObject = CreateCertificate; }
certTypeData.DoesPhysicalObjectExist = DoesCertificateExist; certTypeData.EnumFirstPhysicalObject = EnumFirstCertificate; certTypeData.EnumNextPhysicalObject = EnumNextCertificate; certTypeData.AbortEnumPhysicalObject = AbortCertificateEnum; certTypeData.ConvertObjectToMultiSz = ConvertCertificateToMultiSz; certTypeData.ConvertMultiSzToObject = ConvertMultiSzToCertificate; certTypeData.GetNativeObjectName = GetNativeCertificateName; certTypeData.AcquirePhysicalObject = AcquireCertificate; certTypeData.ReleasePhysicalObject = ReleaseCertificate; certTypeData.ConvertObjectContentToUnicode = ConvertCertificateContentToUnicode; certTypeData.ConvertObjectContentToAnsi = ConvertCertificateContentToAnsi; certTypeData.FreeConvertedObjectContent = FreeConvertedCertificateContent;
g_CertType = IsmRegisterObjectType ( S_CERT_NAME, TRUE, FALSE, &certTypeData );
MYASSERT (g_CertType);
pLoadCertEntries ();
return TRUE; }
BOOL pFillCertEnumPtr ( IN OUT PMIG_TYPEOBJECTENUM EnumPtr, IN PCERT_ENUM CertEnum, IN PCTSTR CertName ) { BOOL result = FALSE;
if (EnumPtr->ObjectName) { IsmDestroyObjectHandle (EnumPtr->ObjectName); EnumPtr->ObjectName = NULL; } if (EnumPtr->ObjectLeaf) { IsmReleaseMemory (EnumPtr->ObjectLeaf); EnumPtr->ObjectLeaf = NULL; } if (EnumPtr->NativeObjectName) { IsmReleaseMemory (EnumPtr->NativeObjectName); EnumPtr->NativeObjectName = NULL; }
EnumPtr->ObjectLeaf = IsmDuplicateString (CertName);
EnumPtr->ObjectName = IsmCreateObjectHandle (CertEnum->CertStore, EnumPtr->ObjectLeaf); EnumPtr->ObjectNode = CertEnum->CertStore; EnumPtr->NativeObjectName = GetNativeCertificateName (EnumPtr->ObjectName); GetNodePatternMinMaxLevels (CertEnum->CertStore, NULL, &EnumPtr->Level, NULL); EnumPtr->SubLevel = 0; EnumPtr->IsLeaf = TRUE; EnumPtr->IsNode = TRUE; EnumPtr->Details.DetailsSize = 0; EnumPtr->Details.DetailsData = NULL;
return TRUE; }
PCTSTR pGetCertName ( IN PCCERT_CONTEXT CertContext ) { PTSTR result = NULL; PTSTR resultPtr = NULL; UINT i;
if (!CertContext) { return NULL; } if (!CertContext->pCertInfo) { return NULL; } if (!CertContext->pCertInfo->SerialNumber.cbData) { return NULL; } result = PmGetMemory (g_CertPool, CertContext->pCertInfo->SerialNumber.cbData * 3 * sizeof (TCHAR)); if (result) { resultPtr = result; *resultPtr = 0; for (i = CertContext->pCertInfo->SerialNumber.cbData; i > 0; i--) { wsprintf (resultPtr, TEXT("%02x"), CertContext->pCertInfo->SerialNumber.pbData[i - 1]); resultPtr = GetEndOfString (resultPtr); if (i > 1) { _tcscat (resultPtr, TEXT(" ")); resultPtr = GetEndOfString (resultPtr); } } } return result; }
BOOL pGetNextCertFromStore ( IN OUT PMIG_TYPEOBJECTENUM EnumPtr, IN PCERT_ENUM CertEnum ) { PCTSTR name = NULL; DWORD nameSize = 0; BOOL result = FALSE;
do { // do we have the API?
if (g_CertEnumCertificatesInStore == NULL) { return FALSE; }
CertEnum->CertContext = g_CertEnumCertificatesInStore (CertEnum->StoreHandle, CertEnum->CertContext); if (!CertEnum->CertContext) { return FALSE; }
// let's get the certificate "name". This is actually the serial number made
// into a string. This is the only unique thing that I could see.
name = pGetCertName (CertEnum->CertContext); if (!name) { return FALSE; }
if (IsPatternMatchEx (CertEnum->CertPattern, name)) { break; }
} while (TRUE);
result = pFillCertEnumPtr (EnumPtr, CertEnum, name);
PmReleaseMemory (g_CertPool, name); name = NULL;
return result; }
HCERTSTORE pOpenCertStore ( IN PCTSTR CertStore, IN BOOL Create ) { PCWSTR certStoreW = NULL; HCERTSTORE result = NULL;
__try { // let's do the UNICODE conversion if needed
#ifndef UNICODE
certStoreW = ConvertAtoW (CertStore); #endif
// do we have the API?
if (g_CertOpenStore != NULL) { // now let's understand what kind of store is this
// First we try to see if this is a file
if (DoesFileExist (CertStore)) { // it is a file, open it
// first we try current user
result = g_CertOpenStore ( CERT_STORE_PROV_FILENAME, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, Create?CERT_SYSTEM_STORE_CURRENT_USER:CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_OPEN_EXISTING_FLAG, #ifdef UNICODE
CertStore #else
certStoreW #endif
); } else { // we assume it's a system store
result = g_CertOpenStore ( CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, Create?CERT_SYSTEM_STORE_CURRENT_USER:CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_OPEN_EXISTING_FLAG, #ifdef UNICODE
CertStore #else
certStoreW #endif
); if (result == NULL) { // now we try HKLM
result = g_CertOpenStore ( CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, Create?CERT_SYSTEM_STORE_LOCAL_MACHINE:CERT_SYSTEM_STORE_LOCAL_MACHINE|CERT_STORE_OPEN_EXISTING_FLAG, #ifdef UNICODE
CertStore #else
certStoreW #endif
); } } } } __finally { if (certStoreW) { FreeConvertedStr (certStoreW); certStoreW = NULL; } } return result; }
BOOL EnumFirstCertificate ( IN OUT PMIG_TYPEOBJECTENUM EnumPtr, CALLER_INITIALIZED IN MIG_OBJECTSTRINGHANDLE Pattern, IN UINT MaxLevel ) { PCTSTR certStore, certPattern; PCWSTR certStoreW = NULL; PCERT_ENUM certEnum = NULL; BOOL result = FALSE;
if (!IsmCreateObjectStringsFromHandle ( Pattern, &certStore, &certPattern )) { return FALSE; }
if (certStore && certPattern) {
__try {
certEnum = (PCERT_ENUM) PmGetMemory (g_CertPool, sizeof (CERT_ENUM)); if (!certEnum) { __leave; } ZeroMemory (certEnum, sizeof (CERT_ENUM)); certEnum->CertStore = PmDuplicateString (g_CertPool, certStore); certEnum->CertPattern = PmDuplicateString (g_CertPool, certPattern); EnumPtr->EtmHandle = (LONG_PTR) certEnum;
certEnum->StoreHandle = pOpenCertStore (certStore, FALSE); if (certEnum->StoreHandle == NULL) { __leave; }
result = pGetNextCertFromStore (EnumPtr, certEnum); } __finally { if (certStoreW) { FreeConvertedStr (certStoreW); certStoreW = NULL; } } }
IsmDestroyObjectString (certStore); IsmDestroyObjectString (certPattern);
if (!result) { AbortCertificateEnum (EnumPtr); }
return result; }
BOOL EnumNextCertificate ( IN OUT PMIG_TYPEOBJECTENUM EnumPtr ) { PCERT_ENUM certEnum = NULL; BOOL result = FALSE;
certEnum = (PCERT_ENUM)(EnumPtr->EtmHandle); if (!certEnum) { return FALSE; }
result = pGetNextCertFromStore (EnumPtr, certEnum);
return result; }
VOID AbortCertificateEnum ( IN PMIG_TYPEOBJECTENUM EnumPtr ZEROED ) { PCERT_ENUM certEnum;
if (EnumPtr->ObjectName) { IsmDestroyObjectHandle (EnumPtr->ObjectName); EnumPtr->ObjectName = NULL; } if (EnumPtr->ObjectLeaf) { IsmReleaseMemory (EnumPtr->ObjectLeaf); EnumPtr->ObjectLeaf = NULL; } if (EnumPtr->NativeObjectName) { IsmReleaseMemory (EnumPtr->NativeObjectName); EnumPtr->NativeObjectName = NULL; }
certEnum = (PCERT_ENUM)(EnumPtr->EtmHandle); if (certEnum) { if (certEnum->StoreHandle && g_CertCloseStore) { g_CertCloseStore (certEnum->StoreHandle, CERT_CLOSE_STORE_FORCE_FLAG); } if (certEnum->CertStore) { PmReleaseMemory (g_CertPool, certEnum->CertStore); certEnum->CertStore = NULL; } if (certEnum->CertPattern) { PmReleaseMemory (g_CertPool, certEnum->CertPattern); certEnum->CertPattern = NULL; } if (certEnum->CertContext) { if (g_CertFreeCertificateContext) { g_CertFreeCertificateContext (certEnum->CertContext); } } PmReleaseMemory (g_CertPool, certEnum); }
ZeroMemory (EnumPtr, sizeof (MIG_TYPEOBJECTENUM)); }
/*++
The next set of functions implement the ETM entry points to acquire, test, create and remove certificates.
--*/
BOOL pDoesPrivateKeyExist ( IN PCCERT_CONTEXT CertContext ) { DWORD data = 0; BOOL result = FALSE;
// do we have the API?
if (!g_CertGetCertificateContextProperty) { return FALSE; }
result = g_CertGetCertificateContextProperty ( CertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &data ); return result; }
BOOL pIsPrivateKeyExportable ( IN PCCERT_CONTEXT CertContext ) { HCRYPTPROV cryptProv = 0; DWORD keySpec = 0; HCRYPTKEY keyHandle = 0; BOOL callerFreeProv = FALSE; DWORD permissions = 0; DWORD size = 0; BOOL result = FALSE;
// do we have the API?
if (!g_CryptAcquireCertificatePrivateKey) { // we don't have the API, let's assume it is
// exportable.
return TRUE; }
if (g_CryptAcquireCertificatePrivateKey ( CertContext, CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &cryptProv, &keySpec, &callerFreeProv )) {
if (CryptGetUserKey (cryptProv, keySpec, &keyHandle)) {
size = sizeof (permissions); if (CryptGetKeyParam (keyHandle, KP_PERMISSIONS, (PBYTE)&permissions, &size, 0)) { result = ((permissions & CRYPT_EXPORT) != 0); }
if (keyHandle != 0) { CryptDestroyKey(keyHandle); keyHandle = 0; } }
if (callerFreeProv != 0) { CryptReleaseContext(cryptProv, 0); cryptProv = 0; } } return result; }
PCBYTE pGetCertificateData ( IN PCCERT_CONTEXT CertContext, IN BOOL ExportPrivateKey, IN PCWSTR Password, OUT PDWORD DataSize ) { HCERTSTORE memoryStore; CRYPT_DATA_BLOB dataBlob; PCBYTE result = NULL;
if (!DataSize) { return NULL; }
__try {
// do we have the API?
if (!g_CertOpenStore) { __leave; }
// first we create a memory store and put this certificate there
memoryStore = g_CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL ); if (memoryStore == NULL) { __leave; }
// do we have the API?
if (!g_CertAddCertificateContextToStore) { __leave; }
if (!g_CertAddCertificateContextToStore ( memoryStore, CertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL )) { __leave; }
// now we export the store using PFXExportCertStore
ZeroMemory (&dataBlob, sizeof (CRYPT_DATA_BLOB));
// do we have the API?
if (!g_PFXExportCertStore) { __leave; }
// get the needed size
if (!g_PFXExportCertStore ( memoryStore, &dataBlob, Password, ExportPrivateKey?EXPORT_PRIVATE_KEYS:0 )) { __leave; }
dataBlob.pbData = PmGetMemory (g_CertPool, dataBlob.cbData); if (!dataBlob.pbData) { SetLastError (ERROR_NOT_ENOUGH_MEMORY); __leave; }
// now get the actual data
if (!g_PFXExportCertStore ( memoryStore, &dataBlob, Password, ExportPrivateKey?EXPORT_PRIVATE_KEYS:0 )) { __leave; }
// now we have the data
*DataSize = dataBlob.cbData; result = dataBlob.pbData;
} __finally { PushError (); if (memoryStore && g_CertCloseStore) { g_CertCloseStore (memoryStore, CERT_CLOSE_STORE_FORCE_FLAG); memoryStore = NULL; } if (!result) { if (dataBlob.pbData) { PmReleaseMemory (g_CertPool, dataBlob.pbData); dataBlob.pbData = NULL; } } PopError (); }
return result; }
PCCERT_CONTEXT pGetCertContext ( IN HCERTSTORE StoreHandle, IN PCTSTR CertName ) { PCTSTR certName; PCCERT_CONTEXT result = NULL;
// do we have the API?
if (!g_CertEnumCertificatesInStore) { return FALSE; }
// basically we are going to enumerate the certificates until we find the one
// that we need
result = g_CertEnumCertificatesInStore (StoreHandle, result); while (result) { certName = pGetCertName (result); if (StringIMatch (CertName, certName)) { PmReleaseMemory (g_CertPool, certName); break; } PmReleaseMemory (g_CertPool, certName); result = g_CertEnumCertificatesInStore (StoreHandle, result); } return result; }
BOOL pAcquireCertFromStore ( IN HCERTSTORE StoreHandle, IN PCTSTR CertName, OUT PMIG_CONTENT ObjectContent, IN UINT MemoryContentLimit ) { PCCERT_CONTEXT certContext = NULL; PCTSTR certName; BOOL exportPrivateKey = FALSE; DWORD dataSize = 0; PCBYTE dataBytes = NULL; BOOL result = FALSE;
certContext = pGetCertContext (StoreHandle, CertName); if (!certContext) { return FALSE; }
// we found it. Let's build the data.
exportPrivateKey = pDoesPrivateKeyExist (certContext) && pIsPrivateKeyExportable (certContext);
dataBytes = pGetCertificateData (certContext, exportPrivateKey, L"USMT", &dataSize); if (dataBytes) { // let's build the object content
ObjectContent->MemoryContent.ContentSize = dataSize; ObjectContent->MemoryContent.ContentBytes = dataBytes; result = TRUE; }
if (g_CertFreeCertificateContext) { g_CertFreeCertificateContext (certContext); }
return result; }
BOOL AcquireCertificate ( IN MIG_OBJECTSTRINGHANDLE ObjectName, OUT PMIG_CONTENT ObjectContent, CALLER_INITIALIZED IN MIG_CONTENTTYPE ContentType, IN UINT MemoryContentLimit ) { HCERTSTORE storeHandle = NULL; PCTSTR certStore = NULL, certName = NULL; PCCERT_CONTEXT certContext; BOOL result = FALSE;
if (!ObjectContent) { return FALSE; }
if (ContentType == CONTENTTYPE_FILE) { // nobody should request this as a file
MYASSERT (FALSE); return FALSE; }
if (!IsmCreateObjectStringsFromHandle ( ObjectName, &certStore, &certName )) { return FALSE; }
if (certStore && certName) {
__try {
storeHandle = pOpenCertStore (certStore, FALSE); if (!storeHandle) { __leave; }
result = pAcquireCertFromStore (storeHandle, certName, ObjectContent, MemoryContentLimit); } __finally { if (storeHandle && g_CertCloseStore) { g_CertCloseStore (storeHandle, CERT_CLOSE_STORE_FORCE_FLAG); storeHandle = NULL; } } }
IsmDestroyObjectString (certStore); IsmDestroyObjectString (certName);
return result; }
BOOL ReleaseCertificate ( IN PMIG_CONTENT ObjectContent ZEROED ) { if (ObjectContent) { if (ObjectContent->MemoryContent.ContentBytes) { PmReleaseMemory (g_CertPool, ObjectContent->MemoryContent.ContentBytes); } ZeroMemory (ObjectContent, sizeof (MIG_CONTENT)); } return TRUE; }
BOOL DoesCertificateExist ( IN MIG_OBJECTSTRINGHANDLE ObjectName ) { HCERTSTORE storeHandle = NULL; PCCERT_CONTEXT certContext = NULL; PCTSTR certStore = NULL, certName = NULL; BOOL result = FALSE;
if (g_DelayCertOp) { return FALSE; }
if (!IsmCreateObjectStringsFromHandle ( ObjectName, &certStore, &certName )) { return FALSE; }
if (certStore && certName) {
__try {
storeHandle = pOpenCertStore (certStore, FALSE); if (!storeHandle) { __leave; }
certContext = pGetCertContext (storeHandle, certName); if (!certContext) { __leave; } result = TRUE; } __finally { if (certContext && g_CertFreeCertificateContext) { g_CertFreeCertificateContext (certContext); certContext = NULL; } if (storeHandle && g_CertCloseStore) { g_CertCloseStore (storeHandle, CERT_CLOSE_STORE_FORCE_FLAG); storeHandle = NULL; } } }
IsmDestroyObjectString (certStore); IsmDestroyObjectString (certName);
return result; }
BOOL RemoveCertificate ( IN MIG_OBJECTSTRINGHANDLE ObjectName ) { HCERTSTORE storeHandle = NULL; PCCERT_CONTEXT certContext; PCTSTR certStore = NULL, certName = NULL; BOOL result = FALSE;
if (g_DelayCertOp) {
//
// delay this certificate create because cert apis do not work
// for non-logged on users
//
IsmRecordDelayedOperation ( JRNOP_DELETE, g_CertType, ObjectName, NULL ); result = TRUE;
} else { //
// add journal entry, then perform certificate deletion
//
IsmRecordOperation ( JRNOP_DELETE, g_CertType, ObjectName );
if (IsmCreateObjectStringsFromHandle ( ObjectName, &certStore, &certName )) {
if (certStore && certName) {
__try {
storeHandle = pOpenCertStore (certStore, FALSE); if (!storeHandle) { __leave; }
certContext = pGetCertContext (storeHandle, certName); if (!certContext) { __leave; }
if (g_CertDeleteCertificateFromStore && g_CertDeleteCertificateFromStore (certContext) ) { // certContext is not valid any more
certContext = NULL; result = TRUE; } } __finally { if (certContext && g_CertFreeCertificateContext) { g_CertFreeCertificateContext (certContext); certContext = NULL; } if (storeHandle && g_CertCloseStore) { g_CertCloseStore (storeHandle, CERT_CLOSE_STORE_FORCE_FLAG); storeHandle = NULL; } } }
IsmDestroyObjectString (certStore); IsmDestroyObjectString (certName); } }
return result; }
HCERTSTORE pBuildStoreFromData ( PCRYPT_DATA_BLOB DataBlob, PCWSTR Password ) { HCERTSTORE result;
// Do we have the API?
if (!g_PFXImportCertStore) { return NULL; }
result = g_PFXImportCertStore ( DataBlob, Password, CRYPT_EXPORTABLE );
return result; }
BOOL CreateCertificate ( IN MIG_OBJECTSTRINGHANDLE ObjectName, IN PMIG_CONTENT ObjectContent ) { CRYPT_DATA_BLOB dataBlob; HCERTSTORE srcStoreHandle = NULL; HCERTSTORE destStoreHandle = NULL; PCCERT_CONTEXT certContext = NULL; PCTSTR certStore = NULL, certName = NULL; PTSTR certFile = NULL, certFileNode, certFilePtr; MIG_OBJECTSTRINGHANDLE certFileHandle, destCertFileHandle; BOOL result = FALSE;
if (g_DelayCertOp) {
//
// delay this certificate create because cert apis do not work
// for non-logged on users
//
IsmRecordDelayedOperation ( JRNOP_CREATE, g_CertType, ObjectName, ObjectContent ); result = TRUE;
} else { //
// add journal entry, then create the certificate
//
IsmRecordOperation ( JRNOP_CREATE, g_CertType, ObjectName );
if (ObjectContent && ObjectContent->MemoryContent.ContentSize && ObjectContent->MemoryContent.ContentBytes) {
if (!IsmCreateObjectStringsFromHandle ( ObjectName, &certStore, &certName )) { return FALSE; }
if (certStore && certName) {
__try {
// let's create the store from this data
dataBlob.cbData = ObjectContent->MemoryContent.ContentSize; dataBlob.pbData = (PBYTE)ObjectContent->MemoryContent.ContentBytes;
srcStoreHandle = pBuildStoreFromData (&dataBlob, L"USMT"); if (!srcStoreHandle) { __leave; }
// now we need to figure out where the destination store is
// If it's a file we will filter it out and find out where
// the file is supposed to go.
if (IsValidFileSpec (certStore)) { // looks like a file.
certFile = PmDuplicateString (g_CertPool, certStore); if (certFile) { certFilePtr = _tcsrchr (certFile, TEXT('\\')); if (certFilePtr) { *certFilePtr = 0; certFilePtr ++; certFileHandle = IsmCreateObjectHandle (certFile, certFilePtr); if (certFileHandle) { destCertFileHandle = IsmFilterObject (MIG_FILE_TYPE, certFileHandle, NULL, NULL, NULL); if (destCertFileHandle) { PmReleaseMemory (g_CertPool, certFile); certFile = NULL; if (IsmCreateObjectStringsFromHandle (destCertFileHandle, &certFileNode, &certFilePtr)) { certFile = JoinPaths (certFileNode, certFilePtr); IsmDestroyObjectString (certFileNode); IsmDestroyObjectString (certFilePtr); } } IsmDestroyObjectHandle (certFileHandle); } else { PmReleaseMemory (g_CertPool, certFile); certFile = NULL; } } else { PmReleaseMemory (g_CertPool, certFile); certFile = NULL; } } }
destStoreHandle = pOpenCertStore (certFile?certFile:certStore, TRUE); if (!destStoreHandle) { __leave; }
// Do we have the APIs?
if (g_CertEnumCertificatesInStore && g_CertAddCertificateContextToStore) {
// now let's enumerate the store and add the certificates into the
// system store
certContext = g_CertEnumCertificatesInStore (srcStoreHandle, certContext); while (certContext) {
if (!g_CertAddCertificateContextToStore ( destStoreHandle, certContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL )) { __leave; }
certContext = g_CertEnumCertificatesInStore (srcStoreHandle, certContext); } result = TRUE; } } __finally { if (certContext && g_CertFreeCertificateContext) { g_CertFreeCertificateContext (certContext); certContext = NULL; } if (srcStoreHandle && g_CertCloseStore) { g_CertCloseStore (srcStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG); srcStoreHandle = NULL; } if (destStoreHandle && g_CertCloseStore) { g_CertCloseStore (destStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG); destStoreHandle = NULL; } } }
IsmDestroyObjectString (certStore); IsmDestroyObjectString (certName); } }
return result; }
/*++
The next group of functions converts a certificate object into a string format, suitable for output to an INF file. The reverse conversion is also implemented.
--*/
PCTSTR ConvertCertificateToMultiSz ( IN MIG_OBJECTSTRINGHANDLE ObjectName, IN PMIG_CONTENT ObjectContent ) { PCTSTR certStore = NULL, certName = NULL; TCHAR tmpStr[3]; UINT index; PTSTR result = NULL;
if (IsmCreateObjectStringsFromHandle (ObjectName, &certStore, &certName)) { g_CertConversionBuff.End = 0; GbCopyQuotedString (&g_CertConversionBuff, certStore); GbCopyQuotedString (&g_CertConversionBuff, certName); if (ObjectContent && (!ObjectContent->ContentInFile) && ObjectContent->MemoryContent.ContentBytes) { index = 0; while (index < ObjectContent->MemoryContent.ContentSize) { wsprintf (tmpStr, TEXT("%02X"), ObjectContent->MemoryContent.ContentBytes [index]); GbCopyString (&g_CertConversionBuff, tmpStr); index ++; } GbCopyString (&g_CertConversionBuff, TEXT("")); result = IsmGetMemory (g_CertConversionBuff.End); CopyMemory (result, g_CertConversionBuff.Buf, g_CertConversionBuff.End); } }
return result; }
BOOL ConvertMultiSzToCertificate ( IN PCTSTR ObjectMultiSz, OUT MIG_OBJECTSTRINGHANDLE *ObjectName, OUT PMIG_CONTENT ObjectContent OPTIONAL CALLER_INITIALIZED ) { MULTISZ_ENUM multiSzEnum; PCTSTR certStore = NULL; PCTSTR certName = NULL; DWORD dummy; UINT index;
g_CertConversionBuff.End = 0;
if (ObjectContent) { ZeroMemory (ObjectContent, sizeof (MIG_CONTENT)); }
if (EnumFirstMultiSz (&multiSzEnum, ObjectMultiSz)) { index = 0; do { if (index == 0) { certStore = multiSzEnum.CurrentString; } if (index == 1) { certName = multiSzEnum.CurrentString; } if (index >= 2) { _stscanf (multiSzEnum.CurrentString, TEXT("%lx"), &dummy); *((PBYTE)GbGrow (&g_CertConversionBuff, sizeof (BYTE))) = (BYTE)dummy; } index ++; } while (EnumNextMultiSz (&multiSzEnum)); }
if (!certStore) { return FALSE; }
if (!certName) { return FALSE; }
if (ObjectContent) {
ObjectContent->ObjectTypeId = g_CertType;
ObjectContent->ContentInFile = FALSE; ObjectContent->MemoryContent.ContentSize = g_CertConversionBuff.End; if (ObjectContent->MemoryContent.ContentSize) { ObjectContent->MemoryContent.ContentBytes = IsmGetMemory (ObjectContent->MemoryContent.ContentSize); CopyMemory ( (PBYTE)ObjectContent->MemoryContent.ContentBytes, g_CertConversionBuff.Buf, ObjectContent->MemoryContent.ContentSize ); g_CertConversionBuff.End = 0; } } *ObjectName = IsmCreateObjectHandle (certStore, certName);
return TRUE; }
PCTSTR GetNativeCertificateName ( IN MIG_OBJECTSTRINGHANDLE ObjectName )
/*++
Routine Description:
GetNativeCertificateName converts the standard Cobra object into a more friendly format. The Cobra object comes in the form of ^a<node>^b^c<leaf>, where <node> is the URL, and <leaf> is the certificate name. The Certificate native name is in the format of <CertificateStore>:<CertificateName>.
Arguments:
ObjectName - Specifies the encoded object name
Return Value:
A string that is equivalent to ObjectName, but is in a friendly format. This string must be freed with IsmReleaseMemory.
--*/
{ PCTSTR certStore, certName, tmp; PCTSTR result = NULL;
if (IsmCreateObjectStringsFromHandle (ObjectName, &certStore, &certName)) { if (certStore && certName) { tmp = JoinTextEx (NULL, certStore, certName, TEXT(":"), 0, NULL); if (tmp) { result = IsmDuplicateString (tmp); FreeText (tmp); } } IsmDestroyObjectString (certStore); IsmDestroyObjectString (certName); } return result; }
PMIG_CONTENT ConvertCertificateContentToUnicode ( IN MIG_OBJECTSTRINGHANDLE ObjectName, IN PMIG_CONTENT ObjectContent ) { // we don't need to convert the content
return NULL; }
PMIG_CONTENT ConvertCertificateContentToAnsi ( IN MIG_OBJECTSTRINGHANDLE ObjectName, IN PMIG_CONTENT ObjectContent ) { // we don't need to convert the content
return NULL; }
BOOL FreeConvertedCertificateContent ( IN PMIG_CONTENT ObjectContent ) { // there is nothing to do
return TRUE; }
|