Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1540 lines
43 KiB

/*++
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;
}