//depot/Lab03_N/DS/security/cryptoapi/common/keysvc/keysvcc.cpp#9 - edit change 6380 (text)
//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1997 - 1999
//
//  File:       keysvcc.cpp
//
//--------------------------------------------------------------------------

#include <windows.h>
#include <wincrypt.h>
#include "keysvc.h"
#include "cryptui.h"
#include "lenroll.h"
#include "keysvcc.h"

#include "unicode.h"
#include "waitsvc.h"

typedef struct _WZR_RPC_BINDING_LIST
{
    LPCSTR pszProtSeq;
    LPCSTR pszEndpoint;
} WZR_RPC_BINDING_LIST;

WZR_RPC_BINDING_LIST g_awzrBindingList[] =
{
    { KEYSVC_LOCAL_PROT_SEQ, KEYSVC_LOCAL_ENDPOINT },
    { KEYSVC_DEFAULT_PROT_SEQ, KEYSVC_DEFAULT_ENDPOINT},
    { KEYSVC_LEGACY_PROT_SEQ,   KEYSVC_LEGACY_ENDPOINT}
};

DWORD g_cwzrBindingList = sizeof(g_awzrBindingList)/sizeof(g_awzrBindingList[0]);

/****************************************
 * Client side Key Service handles
 ****************************************/

typedef struct _KEYSVCC_INFO_ {
    KEYSVC_HANDLE   hKeySvc;
    handle_t        hRPCBinding;
} KEYSVCC_INFO, *PKEYSVCC_INFO;


void InitUnicodeString(
                       PKEYSVC_UNICODE_STRING pUnicodeString,
                       LPCWSTR pszString
                       )
{
    pUnicodeString->Length = wcslen(pszString) * sizeof(WCHAR);
    pUnicodeString->MaximumLength = pUnicodeString->Length + sizeof(WCHAR);
    pUnicodeString->Buffer = (USHORT*)pszString;
}

//*****************************************************
//
//  Implementation of Client API for Key Service
//
//*****************************************************

ULONG KeyOpenKeyServiceEx
(/* [in] */ RPC_IF_HANDLE rpc_ifspec, 
 /* [in] */ LPSTR pszMachineName,
 /* [in] */ KEYSVC_TYPE OwnerType,
 /* [in] */ LPWSTR pwszOwnerName,
 /* [in] */ void *pAuthentication,
 /* [out][in] */ void *pReserved,
 /* [out] */ KEYSVCC_HANDLE *phKeySvcCli)

{
    PKEYSVC_BLOB            pVersion = NULL;
    KEYSVC_BLOB             Authentication;
    PKEYSVC_BLOB            pAuth;
    unsigned char           *pStringBinding = NULL;
    PKEYSVCC_INFO           pKeySvcCliInfo = NULL;
    KEYSVC_UNICODE_STRING   OwnerName;
    ULONG                   ulErr = 0;
    DWORD i;
    static BOOL             fDone = FALSE;


    memset(&Authentication, 0, sizeof(Authentication));
    memset(&OwnerName, 0, sizeof(OwnerName));

    if (NULL != pAuthentication)
    {
        ulErr = ERROR_INVALID_PARAMETER;
        goto Ret;
    }
    if (NULL != pwszOwnerName)
    {
        InitUnicodeString(&OwnerName, pwszOwnerName);
    }


    // allocate for the client key service handle
    if (NULL == (pKeySvcCliInfo =
        (PKEYSVCC_INFO)LocalAlloc(LMEM_ZEROINIT,
                                  sizeof(KEYSVCC_INFO))))
    {
        ulErr = ERROR_NOT_ENOUGH_MEMORY;
        goto Ret;
    }

    //
    // before doing the Bind operation, wait for the cryptography
    // service to be available.
    //

    WaitForCryptService(L"ProtectedStorage", &fDone);
    for (i = 0; i < g_cwzrBindingList; i++)
    {
        if (RPC_S_OK != RpcNetworkIsProtseqValid(
                                    (unsigned char *)g_awzrBindingList[i].pszProtSeq))
        {
            continue;
        }

        ulErr = RpcStringBindingComposeA(
                              NULL,
                              (unsigned char *)g_awzrBindingList[i].pszProtSeq,
                              (unsigned char *)pszMachineName,
                              (unsigned char *)g_awzrBindingList[i].pszEndpoint,
                              NULL,
                              &pStringBinding);
        if (RPC_S_OK != ulErr)
        {
            continue;
        }

        ulErr = RpcBindingFromStringBinding(
                                    pStringBinding,
                                    &pKeySvcCliInfo->hRPCBinding);
        if (NULL != pStringBinding)
        {
            RpcStringFree(&pStringBinding);
        }
        if (RPC_S_OK != ulErr)
        {
            continue;
        }

        ulErr = RpcEpResolveBinding(pKeySvcCliInfo->hRPCBinding, rpc_ifspec); 
        if (RPC_S_OK != ulErr)
        {
            continue;
        }


        __try
        {

            ulErr = KeyrOpenKeyService(pKeySvcCliInfo->hRPCBinding,
                                       OwnerType, &OwnerName,
                                       0, &Authentication,
                                       &pVersion, &pKeySvcCliInfo->hKeySvc);

            *phKeySvcCli = (KEYSVCC_HANDLE)pKeySvcCliInfo;
        }
        __except ( EXCEPTION_EXECUTE_HANDLER )
        {
            ulErr = _exception_code();
        }
        if (RPC_S_OK == ulErr)
        {
            break;
        }

    }

    if(RPC_S_OK != ulErr)
    {
        goto Ret;
    }

    if (NULL != pReserved)
    {
	PKEYSVC_OPEN_KEYSVC_INFO pOpenInfoCaller = (PKEYSVC_OPEN_KEYSVC_INFO)pReserved; 
	if (pOpenInfoCaller->ulSize != sizeof(KEYSVC_OPEN_KEYSVC_INFO))
	{
	    ulErr = ERROR_INVALID_PARAMETER;
	    goto Ret;
	}

	if (NULL == pVersion)
	{
	    pOpenInfoCaller->ulVersion = KEYSVC_VERSION_W2K; 
	}
	else
	{
	    if (NULL == pVersion->pb)
	    {
		ulErr = ERROR_INVALID_PARAMETER; 
		goto Ret;
	    }

	    PKEYSVC_OPEN_KEYSVC_INFO pOpenInfoCallee = (PKEYSVC_OPEN_KEYSVC_INFO)pVersion->pb;
	    if (pOpenInfoCallee->ulSize != sizeof(KEYSVC_OPEN_KEYSVC_INFO))
	    {
		ulErr = ERROR_INVALID_PARAMETER; 
		goto Ret;
	    }
		
	    pOpenInfoCaller->ulVersion = pOpenInfoCallee->ulVersion; 
	}
    }

Ret:
    __try
    {
	if (NULL != pVersion) 
	    midl_user_free(pVersion); 
        if (pStringBinding)
            RpcStringFree(&pStringBinding);
        if (0 != ulErr)
        {
            if (pKeySvcCliInfo)
            {
                // close the RPC binding
                if (pKeySvcCliInfo->hRPCBinding)
                    RpcBindingFree(&pKeySvcCliInfo->hRPCBinding);
                LocalFree(pKeySvcCliInfo);
            }
        }
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
    return ulErr;
}

ULONG KeyOpenKeyService
(/* [in] */ LPSTR pszMachineName,
 /* [in] */ KEYSVC_TYPE OwnerType,
 /* [in] */ LPWSTR pwszOwnerName,
 /* [in] */ void *pAuthentication,
 /* [out][in] */ void *pReserved,
 /* [out] */ KEYSVCC_HANDLE *phKeySvcCli)
{
    return KeyOpenKeyServiceEx
        (IKeySvc_v1_0_c_ifspec, 
         pszMachineName,
         OwnerType,
         pwszOwnerName,
         pAuthentication,
         pReserved,
         phKeySvcCli);
}
         
ULONG KeyEnumerateProviders(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [out][in] */ void *pReserved,
    /* [out][in] */ ULONG *pcProviderCount,
    /* [size_is][size_is][out][in] */ PKEYSVC_PROVIDER_INFO *ppProviders)
{
    PKEYSVC_BLOB    pTmpReserved = NULL;
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr =  KeyrEnumerateProviders(pKeySvcCliInfo->hRPCBinding,
                                        pKeySvcCliInfo->hKeySvc,
                                        &pTmpReserved,
                                        pcProviderCount, ppProviders);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG KeyEnumerateProviderTypes(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [out][in] */ void *pReserved,
    /* [out][in] */ ULONG *pcProviderCount,
    /* [size_is][size_is][out][in] */ PKEYSVC_PROVIDER_INFO *ppProviders)
{
    PKEYSVC_BLOB    pTmpReserved = NULL;
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = KeyrEnumerateProviderTypes(pKeySvcCliInfo->hRPCBinding,
                                          pKeySvcCliInfo->hKeySvc,
                                          &pTmpReserved,
                                          pcProviderCount, ppProviders);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG KeyEnumerateProvContainers(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [in] */ KEYSVC_PROVIDER_INFO Provider,
    /* [in, out] */ void *pReserved,
    /* [in, out] */ ULONG *pcContainerCount,
    /* [in, out][size_is(,*pcContainerCount)] */
               PKEYSVC_UNICODE_STRING *ppContainers)
{
    PKEYSVC_BLOB    pTmpReserved = NULL;
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        return KeyrEnumerateProvContainers(pKeySvcCliInfo->hRPCBinding,
                                           pKeySvcCliInfo->hKeySvc,
                                           Provider,
                                           &pTmpReserved, pcContainerCount,
                                           ppContainers);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG KeyCloseKeyService(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [out][in] */ void *pReserved)
{
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    PKEYSVC_BLOB    pTmpReserved = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = KeyrCloseKeyService(pKeySvcCliInfo->hRPCBinding,
                                   pKeySvcCliInfo->hKeySvc,
                                   &pTmpReserved);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG KeyGetDefaultProvider(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [in] */ ULONG ulProvType,
    /* [in] */ ULONG ulFlags,
    /* [out][in] */ void *pReserved,
    /* [out] */ ULONG *pulDefType,
    /* [out] */ PKEYSVC_PROVIDER_INFO *ppProvider)
{
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    PKEYSVC_BLOB    pTmpReserved = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = KeyrGetDefaultProvider(pKeySvcCliInfo->hRPCBinding,
                                       pKeySvcCliInfo->hKeySvc,
                                       ulProvType, ulFlags,
                                       &pTmpReserved, pulDefType,
                                       ppProvider);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG KeySetDefaultProvider(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [in] */ ULONG ulFlags,
    /* [out][in] */ void *pReserved,
    /* [in] */ KEYSVC_PROVIDER_INFO Provider)
{
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    PKEYSVC_BLOB    pTmpReserved = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = KeyrSetDefaultProvider(pKeySvcCliInfo->hRPCBinding,
                                       pKeySvcCliInfo->hKeySvc,
                                       ulFlags, &pTmpReserved,
                                       Provider);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG KeyEnroll
(/* [in] */ KEYSVCC_HANDLE hKeySvcCli, 
 /* [in] */ LPSTR pszMachineName,                    //IN Required: name of the remote machine
 /* [in] */ BOOL fKeyService,                        //IN Required: Whether the function is called remotely
 /* [in] */ DWORD dwPurpose,                         //IN Required: Indicates type of request - enroll/renew
 /* [in] */ LPWSTR pszAcctName,                      //IN Optional: Account name the service runs under
 /* [in] */ void *pAuthentication,                   //RESERVED must be NULL
 /* [in] */ BOOL fEnroll,                            //IN Required: Whether it is enrollment or renew
 /* [in] */ LPWSTR pszCALocation,                    //IN Required: The ca machine name
 /* [in] */ LPWSTR pszCAName,                        //IN Required: The ca name
 /* [in] */ BOOL fNewKey,                            //IN Required: Set the TRUE if new private key is needed
 /* [in] */ PCERT_REQUEST_PVK_NEW pKeyNew,           //IN Required: The private key information
 /* [in] */ CERT_BLOB *pCert,                        //IN Optional: The old certificate if renewing
 /* [in] */ PCERT_REQUEST_PVK_NEW pRenewKey,         //IN Optional: The new private key information
 /* [in] */ LPWSTR pszHashAlg,                       //IN Optional: The hash algorithm
 /* [in] */ LPWSTR pszDesStore,                      //IN Optional: The destination store
 /* [in] */ DWORD dwStoreFlags,                      //IN Optional: Flags for cert store.
 /* [in] */ PCERT_ENROLL_INFO pRequestInfo,          //IN Required: The information about the cert request
 /* [in] */ LPWSTR pszAttributes,                    //IN Optional: Attribute string for request
 /* [in] */ DWORD dwFlags,                           //RESERVED must be 0
 /* [in] */ BYTE *pReserved,                         //RESERVED must be NULL
 /* [out] */ CERT_BLOB *pPKCS7Blob,                  //OUT Optional: The PKCS7 from the CA
 /* [out] */ CERT_BLOB *pHashBlob,                   //OUT Optioanl: The SHA1 hash of the enrolled/renewed certificate
 /* [out] */ DWORD *pdwStatus)                       //OUT Optional: The status of the enrollment/renewal
{
    PKEYSVC_BLOB                pReservedBlob = NULL;
    KEYSVC_UNICODE_STRING       AcctName;
    KEYSVC_UNICODE_STRING       CALocation;
    KEYSVC_UNICODE_STRING       CAName;
    KEYSVC_UNICODE_STRING       DesStore;
    KEYSVC_UNICODE_STRING       HashAlg;
    KEYSVC_BLOB                 *pPKCS7KeySvcBlob = NULL;
    KEYSVC_BLOB                 *pHashKeySvcBlob = NULL;
    KEYSVC_CERT_ENROLL_INFO     EnrollInfo;
    KEYSVC_CERT_REQUEST_PVK_NEW NewKeyInfo;
    KEYSVC_CERT_REQUEST_PVK_NEW RenewKeyInfo;
    KEYSVC_BLOB                 CertBlob;
    DWORD                       i;
    DWORD                       j;
    PKEYSVCC_INFO               pKeySvcCliInfo = NULL;
    DWORD                       dwErr = 0;
    DWORD                       cbExtensions;
    PBYTE                       pbExtensions;

    __try
    {
        // initialize everything
        memset(pPKCS7Blob, 0, sizeof(CERT_BLOB));
        memset(pHashBlob, 0, sizeof(CERT_BLOB));
        memset(&AcctName, 0, sizeof(AcctName));
        memset(&CALocation, 0, sizeof(CALocation));
        memset(&CAName, 0, sizeof(CAName));
        memset(&HashAlg, 0, sizeof(HashAlg));
        memset(&DesStore, 0, sizeof(DesStore));
        memset(&NewKeyInfo, 0, sizeof(NewKeyInfo));
        memset(&EnrollInfo, 0, sizeof(EnrollInfo));
        memset(&RenewKeyInfo, 0, sizeof(RenewKeyInfo));
        memset(&CertBlob, 0, sizeof(CertBlob));

	if (NULL == hKeySvcCli)
	{
	    dwErr = ERROR_INVALID_PARAMETER; 
	    goto Ret;
	}

	pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli; 

        // set up the key service unicode structs
        if (pszAcctName)
            InitUnicodeString(&AcctName, pszAcctName);
        if (pszCALocation)
            InitUnicodeString(&CALocation, pszCALocation);
        if (pszCAName)
            InitUnicodeString(&CAName, pszCAName);
        if (pszHashAlg)
            InitUnicodeString(&HashAlg, pszHashAlg);
        if (pszDesStore)
            InitUnicodeString(&DesStore, pszDesStore);

        // set up the new key info structure for the remote call
        NewKeyInfo.ulProvType = pKeyNew->dwProvType;
        if (pKeyNew->pwszProvider)
        {
            InitUnicodeString(&NewKeyInfo.Provider, pKeyNew->pwszProvider);
        }
        NewKeyInfo.ulProviderFlags = pKeyNew->dwProviderFlags;
        if (pKeyNew->pwszKeyContainer)
        {
            InitUnicodeString(&NewKeyInfo.KeyContainer,
                              pKeyNew->pwszKeyContainer);
        }
        NewKeyInfo.ulKeySpec = pKeyNew->dwKeySpec;
        NewKeyInfo.ulGenKeyFlags = pKeyNew->dwGenKeyFlags;

        // set up the usage OIDs
        if (pRequestInfo->pwszUsageOID)
        {
            InitUnicodeString(&EnrollInfo.UsageOID, pRequestInfo->pwszUsageOID);
        }

        // set up the cert DN Name
        if (pRequestInfo->pwszCertDNName)
        {
            InitUnicodeString(&EnrollInfo.CertDNName, pRequestInfo->pwszCertDNName);
        }

        // set up the request info structure for the remote call
        EnrollInfo.ulPostOption = pRequestInfo->dwPostOption;
        if (pRequestInfo->pwszFriendlyName)
        {
            InitUnicodeString(&EnrollInfo.FriendlyName,
                              pRequestInfo->pwszFriendlyName);
        }
        if (pRequestInfo->pwszDescription)
        {
            InitUnicodeString(&EnrollInfo.Description,
                              pRequestInfo->pwszDescription);
        }
        if (pszAttributes)
        {
            InitUnicodeString(&EnrollInfo.Attributes, pszAttributes);
        }

        // convert the cert extensions
        // NOTE, the extensions structure cannot be simply cast,
        // as the structures have different packing behaviors in
        // 64 bit systems.


        EnrollInfo.cExtensions = pRequestInfo->dwExtensions;
        cbExtensions = EnrollInfo.cExtensions*(sizeof(PKEYSVC_CERT_EXTENSIONS) +
                                               sizeof(KEYSVC_CERT_EXTENSIONS));

        for(i=0; i < EnrollInfo.cExtensions; i++)
        {
            cbExtensions += pRequestInfo->prgExtensions[i]->cExtension*
	                    sizeof(KEYSVC_CERT_EXTENSION);
        }

        EnrollInfo.prgExtensions = (PKEYSVC_CERT_EXTENSIONS*)midl_user_allocate( cbExtensions);

        if(NULL == EnrollInfo.prgExtensions)
        {
            dwErr = ERROR_NOT_ENOUGH_MEMORY;
            goto Ret;
        }

        pbExtensions = (PBYTE)(EnrollInfo.prgExtensions + EnrollInfo.cExtensions);




        for(i=0; i < EnrollInfo.cExtensions; i++)
        {
            EnrollInfo.prgExtensions[i] = (PKEYSVC_CERT_EXTENSIONS)pbExtensions;
            pbExtensions += sizeof(KEYSVC_CERT_EXTENSIONS);
            EnrollInfo.prgExtensions[i]->cExtension = pRequestInfo->prgExtensions[i]->cExtension;

            EnrollInfo.prgExtensions[i]->rgExtension = (PKEYSVC_CERT_EXTENSION)pbExtensions;
            pbExtensions += sizeof(KEYSVC_CERT_EXTENSION)*EnrollInfo.prgExtensions[i]->cExtension;


            for(j=0; j < EnrollInfo.prgExtensions[i]->cExtension; j++)
            {

                EnrollInfo.prgExtensions[i]->rgExtension[j].pszObjId = 
                    pRequestInfo->prgExtensions[i]->rgExtension[j].pszObjId;

                EnrollInfo.prgExtensions[i]->rgExtension[j].fCritical = 
                    pRequestInfo->prgExtensions[i]->rgExtension[j].fCritical;

                EnrollInfo.prgExtensions[i]->rgExtension[j].cbData = 
                    pRequestInfo->prgExtensions[i]->rgExtension[j].Value.cbData;

                EnrollInfo.prgExtensions[i]->rgExtension[j].pbData = 
                    pRequestInfo->prgExtensions[i]->rgExtension[j].Value.pbData;
            }
        }

        // if doing renewal then make sure have everything needed
        if ((CRYPTUI_WIZ_CERT_RENEW == dwPurpose) &&
            ((NULL == pRenewKey) || (NULL == pCert)))
        {
            dwErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        // set up the new key info structure for the remote call
        if (pRenewKey)
        {
            RenewKeyInfo.ulProvType = pRenewKey->dwProvType;
            if (pRenewKey->pwszProvider)
            {
                InitUnicodeString(&RenewKeyInfo.Provider, pRenewKey->pwszProvider);
            }
            RenewKeyInfo.ulProviderFlags = pRenewKey->dwProviderFlags;
            if (pRenewKey->pwszKeyContainer)
            {
                InitUnicodeString(&RenewKeyInfo.KeyContainer,
                                  pRenewKey->pwszKeyContainer);
            }
            RenewKeyInfo.ulKeySpec = pRenewKey->dwKeySpec;
            RenewKeyInfo.ulGenKeyFlags = pRenewKey->dwGenKeyFlags;
        }

        // set up the cert blob for renewal
        if (pCert)
        {
            CertBlob.cb = pCert->cbData;
            CertBlob.pb = pCert->pbData;
        }

        // make the remote enrollment call
        if (0 != (dwErr = KeyrEnroll(pKeySvcCliInfo->hRPCBinding, fKeyService, dwPurpose,
                                    &AcctName, &CALocation, &CAName, fNewKey,
                                    &NewKeyInfo, &CertBlob, &RenewKeyInfo,
                                    &HashAlg, &DesStore, dwStoreFlags,
                                    &EnrollInfo, dwFlags, &pReservedBlob,
                                    &pPKCS7KeySvcBlob,
                                    &pHashKeySvcBlob, pdwStatus)))
            goto Ret;

        // allocate and copy the output parameters
        if (pPKCS7KeySvcBlob->cb)
        {
            pPKCS7Blob->cbData = pPKCS7KeySvcBlob->cb;
            if (NULL == (pPKCS7Blob->pbData =
                (BYTE*)midl_user_allocate(pPKCS7Blob->cbData)))
            {
                dwErr = ERROR_NOT_ENOUGH_MEMORY;
                goto Ret;
            }
            memcpy(pPKCS7Blob->pbData, pPKCS7KeySvcBlob->pb,
                   pPKCS7Blob->cbData);
        }
        if (pHashKeySvcBlob->cb)
        {
            pHashBlob->cbData = pHashKeySvcBlob->cb;
            if (NULL == (pHashBlob->pbData =
                (BYTE*)midl_user_allocate(pHashBlob->cbData)))
            {
                dwErr = ERROR_NOT_ENOUGH_MEMORY;
                goto Ret;
            }
            memcpy(pHashBlob->pbData, pHashKeySvcBlob->pb, pHashBlob->cbData);
        }
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        return _exception_code();
    }
Ret:
    __try
    {
        if (pPKCS7KeySvcBlob)
        {
            midl_user_free(pPKCS7KeySvcBlob);
        }
        if (pHashKeySvcBlob)
        {
            midl_user_free(pHashKeySvcBlob);
        }
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        return _exception_code();
    }
    return dwErr;
}

// Params needed for create:
// 
// Params not needed for submit:
//     all except pszMachineName, dwPurpose, dwFlags, fEnroll, dwStoreFlags, hRequest, and dwFlags. 
//
// Params not needed for free:
//     all except pszMachineName, hRequest, and dwFlags. 
//
ULONG KeyEnroll_V2
(/* [in] */ KEYSVCC_HANDLE hKeySvcCli, 
 /* [in] */ LPSTR pszMachineName,                    //IN Required: name of the remote machine
 /* [in] */ BOOL fKeyService,                        //IN Required: Whether the function is called remotely
 /* [in] */ DWORD dwPurpose,                         //IN Required: Indicates type of request - enroll/renew
 /* [in] */ DWORD dwFlags,                           //IN Required: Flags for enrollment
 /* [in] */ LPWSTR pszAcctName,                      //IN Optional: Account name the service runs under
 /* [in] */ void *pAuthentication,                   //RESERVED must be NULL
 /* [in] */ BOOL fEnroll,                            //IN Required: Whether it is enrollment or renew
 /* [in] */ LPWSTR pszCALocation,                    //IN Required: The ca machine names to attempt to enroll with
 /* [in] */ LPWSTR pszCAName,                        //IN Required: The ca names to attempt to enroll with
 /* [in] */ BOOL fNewKey,                            //IN Required: Set the TRUE if new private key is needed
 /* [in] */ PCERT_REQUEST_PVK_NEW pKeyNew,           //IN Required: The private key information
 /* [in] */ CERT_BLOB *pCert,                        //IN Optional: The old certificate if renewing
 /* [in] */ PCERT_REQUEST_PVK_NEW pRenewKey,         //IN Optional: The new private key information
 /* [in] */ LPWSTR pszHashAlg,                       //IN Optional: The hash algorithm
 /* [in] */ LPWSTR pszDesStore,                      //IN Optional: The destination store
 /* [in] */ DWORD dwStoreFlags,                      //IN Optional: Flags for cert store.
 /* [in] */ PCERT_ENROLL_INFO pRequestInfo,          //IN Required: The information about the cert request
 /* [in] */ LPWSTR pszAttributes,                    //IN Optional: Attribute string for request
 /* [in] */ DWORD dwReservedFlags,                   //RESERVED must be 0
 /* [in] */ BYTE *pReserved,                         //RESERVED must be NULL
 /* [in][out] */ HANDLE *phRequest,                      //IN OUT Optional: A handle to a created request
 /* [out] */ CERT_BLOB *pPKCS7Blob,                  //OUT Optional: The PKCS7 from the CA
 /* [out] */ CERT_BLOB *pHashBlob,                   //OUT Optioanl: The SHA1 hash of the enrolled/renewed certificate
 /* [out] */ DWORD *pdwStatus)                       //OUT Optional: The status of the enrollment/renewal
{
    PKEYSVC_BLOB                    pReservedBlob = NULL;
    KEYSVC_UNICODE_STRING           AcctName;
    KEYSVC_UNICODE_STRING           CALocation;
    KEYSVC_UNICODE_STRING           CAName;
    KEYSVC_UNICODE_STRING           DesStore;
    KEYSVC_UNICODE_STRING           HashAlg;
    KEYSVC_BLOB                     KeySvcRequest; 
    KEYSVC_BLOB                    *pKeySvcRequest   = NULL;
    KEYSVC_BLOB                    *pPKCS7KeySvcBlob = NULL;
    KEYSVC_BLOB                    *pHashKeySvcBlob  = NULL;
    ULONG                           ulKeySvcStatus   = 0; 
    KEYSVC_CERT_ENROLL_INFO         EnrollInfo;
    KEYSVC_CERT_REQUEST_PVK_NEW_V2  NewKeyInfo;
    KEYSVC_CERT_REQUEST_PVK_NEW_V2  RenewKeyInfo;
    KEYSVC_BLOB                     CertBlob;
    DWORD                           i;
    DWORD                           j;
    DWORD                           dwErr = 0;
    DWORD                           cbExtensions;
    PBYTE                           pbExtensions;
    BOOL                            fCreateRequest   = 0 == (dwFlags & (CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY)); 
    PKEYSVCC_INFO                   pKeySvcCliInfo = NULL;

    __try
    {
        //////////////////////////////////////////////////////////////
        // 
        // INITIALIZATION:
        //
        //////////////////////////////////////////////////////////////

        if (NULL != pPKCS7Blob) { memset(pPKCS7Blob, 0, sizeof(CERT_BLOB)); } 
        if (NULL != pHashBlob)  { memset(pHashBlob, 0, sizeof(CERT_BLOB)); } 
        if (NULL != phRequest && NULL != *phRequest)
        {
            pKeySvcRequest     = &KeySvcRequest; 
            pKeySvcRequest->cb = sizeof(*phRequest); 
            pKeySvcRequest->pb = (BYTE *)phRequest; 
        }

	memset(&AcctName, 0, sizeof(AcctName));
        memset(&CALocation, 0, sizeof(CALocation));
        memset(&CAName, 0, sizeof(CAName));
        memset(&HashAlg, 0, sizeof(HashAlg));
        memset(&DesStore, 0, sizeof(DesStore));
        memset(&NewKeyInfo, 0, sizeof(NewKeyInfo));
        memset(&EnrollInfo, 0, sizeof(EnrollInfo));
        memset(&RenewKeyInfo, 0, sizeof(RenewKeyInfo));
        memset(&CertBlob, 0, sizeof(CertBlob));



        //////////////////////////////////////////////////////////////
        //
        // PROCEDURE BODY:
        //
        //////////////////////////////////////////////////////////////

	if (NULL == hKeySvcCli)
	{
            dwErr = ERROR_INVALID_PARAMETER; 
            goto Ret;
	}

	pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli; 

        // set up the key service unicode structs
        if (pszAcctName)
            InitUnicodeString(&AcctName, pszAcctName);
        if (pszCALocation)
            InitUnicodeString(&CALocation, pszCALocation);
        if (pszCAName)
            InitUnicodeString(&CAName, pszCAName);
        if (pszHashAlg)
            InitUnicodeString(&HashAlg, pszHashAlg);
        if (pszDesStore)
            InitUnicodeString(&DesStore, pszDesStore);

        // set up the new key info structure for the remote call
        // This is only necessary if we are actually _creating_ a request. 
        // Submit-only and free-only operations can skip this operation. 
        // 
        if (TRUE == fCreateRequest)
        {
            NewKeyInfo.ulProvType = pKeyNew->dwProvType;
            if (pKeyNew->pwszProvider)
            {
                InitUnicodeString(&NewKeyInfo.Provider, pKeyNew->pwszProvider);
            }
            NewKeyInfo.ulProviderFlags = pKeyNew->dwProviderFlags;
            if (pKeyNew->pwszKeyContainer)
            {
                InitUnicodeString(&NewKeyInfo.KeyContainer,
                                  pKeyNew->pwszKeyContainer);
            }
            NewKeyInfo.ulKeySpec = pKeyNew->dwKeySpec;
            NewKeyInfo.ulGenKeyFlags = pKeyNew->dwGenKeyFlags;
            
            NewKeyInfo.ulEnrollmentFlags = pKeyNew->dwEnrollmentFlags; 
            NewKeyInfo.ulSubjectNameFlags = pKeyNew->dwSubjectNameFlags;
            NewKeyInfo.ulPrivateKeyFlags = pKeyNew->dwPrivateKeyFlags;
            NewKeyInfo.ulGeneralFlags = pKeyNew->dwGeneralFlags; 

            // set up the usage OIDs
            if (pRequestInfo->pwszUsageOID)
            {
                InitUnicodeString(&EnrollInfo.UsageOID, pRequestInfo->pwszUsageOID);
            }

            // set up the cert DN Name
            if (pRequestInfo->pwszCertDNName)
            {
                InitUnicodeString(&EnrollInfo.CertDNName, pRequestInfo->pwszCertDNName);
            }

            // set up the request info structure for the remote call
            EnrollInfo.ulPostOption = pRequestInfo->dwPostOption;
            if (pRequestInfo->pwszFriendlyName)
            {
                InitUnicodeString(&EnrollInfo.FriendlyName,
                                  pRequestInfo->pwszFriendlyName);
            }
            if (pRequestInfo->pwszDescription)
            {
                InitUnicodeString(&EnrollInfo.Description,
                                  pRequestInfo->pwszDescription);
            }
            if (pszAttributes)
            {
                InitUnicodeString(&EnrollInfo.Attributes, pszAttributes);
            }

            // convert the cert extensions
            // NOTE, the extensions structure cannot be simply cast,
            // as the structures have different packing behaviors in
            // 64 bit systems.
            
            
            EnrollInfo.cExtensions = pRequestInfo->dwExtensions;
            cbExtensions = EnrollInfo.cExtensions*(sizeof(PKEYSVC_CERT_EXTENSIONS) +
                                                   sizeof(KEYSVC_CERT_EXTENSIONS));
            
            for(i=0; i < EnrollInfo.cExtensions; i++)
            {
                cbExtensions += pRequestInfo->prgExtensions[i]->cExtension*
                    sizeof(KEYSVC_CERT_EXTENSION);
            }
            
            EnrollInfo.prgExtensions = (PKEYSVC_CERT_EXTENSIONS*)midl_user_allocate( cbExtensions);
            
            if(NULL == EnrollInfo.prgExtensions)
            {
                dwErr = ERROR_NOT_ENOUGH_MEMORY;
                goto Ret;
            }
            
            pbExtensions = (PBYTE)(EnrollInfo.prgExtensions + EnrollInfo.cExtensions);

            for(i=0; i < EnrollInfo.cExtensions; i++)
            {
                EnrollInfo.prgExtensions[i] = (PKEYSVC_CERT_EXTENSIONS)pbExtensions;
                pbExtensions += sizeof(KEYSVC_CERT_EXTENSIONS);
                EnrollInfo.prgExtensions[i]->cExtension = pRequestInfo->prgExtensions[i]->cExtension;
                
                EnrollInfo.prgExtensions[i]->rgExtension = (PKEYSVC_CERT_EXTENSION)pbExtensions;
                pbExtensions += sizeof(KEYSVC_CERT_EXTENSION)*EnrollInfo.prgExtensions[i]->cExtension;
                
                
                for(j=0; j < EnrollInfo.prgExtensions[i]->cExtension; j++)
                {
                    
                    EnrollInfo.prgExtensions[i]->rgExtension[j].pszObjId = 
                        pRequestInfo->prgExtensions[i]->rgExtension[j].pszObjId;
                    
                    EnrollInfo.prgExtensions[i]->rgExtension[j].fCritical = 
                        pRequestInfo->prgExtensions[i]->rgExtension[j].fCritical;
                    
                    EnrollInfo.prgExtensions[i]->rgExtension[j].cbData = 
                        pRequestInfo->prgExtensions[i]->rgExtension[j].Value.cbData;
                    
                    EnrollInfo.prgExtensions[i]->rgExtension[j].pbData = 
                        pRequestInfo->prgExtensions[i]->rgExtension[j].Value.pbData;
                }
            }

            // if doing renewal then make sure have everything needed
            if ((CRYPTUI_WIZ_CERT_RENEW == dwPurpose) &&
                ((NULL == pRenewKey) || (NULL == pCert)))
            {
                dwErr = ERROR_INVALID_PARAMETER;
                goto Ret;
            }
            
            // set up the new key info structure for the remote call
            if (pRenewKey)
            {
                RenewKeyInfo.ulProvType = pRenewKey->dwProvType;
                if (pRenewKey->pwszProvider)
                {
                    InitUnicodeString(&RenewKeyInfo.Provider, pRenewKey->pwszProvider);
                }
                RenewKeyInfo.ulProviderFlags = pRenewKey->dwProviderFlags;
                if (pRenewKey->pwszKeyContainer)
                {
                    InitUnicodeString(&RenewKeyInfo.KeyContainer,
                                      pRenewKey->pwszKeyContainer);
                }
                RenewKeyInfo.ulKeySpec = pRenewKey->dwKeySpec;
                RenewKeyInfo.ulGenKeyFlags = pRenewKey->dwGenKeyFlags;
                RenewKeyInfo.ulEnrollmentFlags = pRenewKey->dwEnrollmentFlags;
                RenewKeyInfo.ulSubjectNameFlags = pRenewKey->dwSubjectNameFlags;
                RenewKeyInfo.ulPrivateKeyFlags = pRenewKey->dwPrivateKeyFlags;
                RenewKeyInfo.ulGeneralFlags = pRenewKey->dwGeneralFlags;
            }
            
            // set up the cert blob for renewal
            if (pCert)
            {
                CertBlob.cb = pCert->cbData;
                CertBlob.pb = pCert->pbData;
            }
        }

        // make the remote enrollment call
        if (0 != (dwErr = KeyrEnroll_V2
                  (pKeySvcCliInfo->hRPCBinding, 
                   fKeyService, 
                   dwPurpose,
                   dwFlags, 
                   &AcctName, 
                   &CALocation, 
                   &CAName, 
                   fNewKey,
                   &NewKeyInfo, 
                   &CertBlob, 
                   &RenewKeyInfo,
                   &HashAlg, 
                   &DesStore, 
                   dwStoreFlags,
                   &EnrollInfo, 
                   dwReservedFlags, 
                   &pReservedBlob,
                   &pKeySvcRequest, 
                   &pPKCS7KeySvcBlob,
                   &pHashKeySvcBlob,
                   &ulKeySvcStatus)))
            goto Ret;

        // allocate and copy the output parameters.
	if ((NULL != pKeySvcRequest)     && 
	    (0     < pKeySvcRequest->cb) && 
	    (NULL != phRequest))
	{
	    memcpy(phRequest, pKeySvcRequest->pb, sizeof(*phRequest));
	}
	    
        if ((NULL != pPKCS7KeySvcBlob)     &&
	    (0     < pPKCS7KeySvcBlob->cb) && 
	    (NULL != pPKCS7Blob))
        {
            pPKCS7Blob->cbData = pPKCS7KeySvcBlob->cb;
            if (NULL == (pPKCS7Blob->pbData =
                (BYTE*)midl_user_allocate(pPKCS7Blob->cbData)))
            {
                dwErr = ERROR_NOT_ENOUGH_MEMORY;
                goto Ret;
            }
            memcpy(pPKCS7Blob->pbData, pPKCS7KeySvcBlob->pb,
                   pPKCS7Blob->cbData);
        }
        if ((NULL != pHashKeySvcBlob)     &&
	    (0     < pHashKeySvcBlob->cb) &&
	    (NULL != pHashBlob))
        {
            pHashBlob->cbData = pHashKeySvcBlob->cb;
            if (NULL == (pHashBlob->pbData =
                (BYTE*)midl_user_allocate(pHashBlob->cbData)))
            {
                dwErr = ERROR_NOT_ENOUGH_MEMORY;
                goto Ret;
            }
            memcpy(pHashBlob->pbData, pHashKeySvcBlob->pb, pHashBlob->cbData);
        }
	if (NULL != pdwStatus)
	{
	    *pdwStatus = (DWORD)ulKeySvcStatus; 
	}
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        return _exception_code();
    }
Ret:
    __try
    {
        if(EnrollInfo.prgExtensions)
        {
            midl_user_free(EnrollInfo.prgExtensions);
        }
	if (pKeySvcRequest)
	{
	    midl_user_free(pKeySvcRequest);
	}
        if (pPKCS7KeySvcBlob)
        {
            midl_user_free(pPKCS7KeySvcBlob);
        }
        if (pHashKeySvcBlob)
        {
            midl_user_free(pHashKeySvcBlob);
        }
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        return _exception_code();
    }
    return dwErr;
}

ULONG KeyExportCert(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [in] */ LPWSTR pwszPassword,
    /* [in] */ LPWSTR pwszCertStore,
    /* [in] */ ULONG cHashCount,
    /* [size_is][in] */ KEYSVC_CERT_HASH *pHashes,
    /* [in] */ ULONG ulFlags,
    /* [in, out] */ void *pReserved,
    /* [out] */ PKEYSVC_BLOB *ppPFXBlob)
{
    PKEYSVCC_INFO           pKeySvcCliInfo = NULL;
    PKEYSVC_BLOB            pTmpReserved = NULL;
    KEYSVC_UNICODE_STRING   Password;
    KEYSVC_UNICODE_STRING   CertStore;
    ULONG                   ulErr = 0;

    __try
    {
        memset(&Password, 0, sizeof(Password));
        memset(&CertStore, 0, sizeof(CertStore));

        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        InitUnicodeString(&Password, pwszPassword);
        InitUnicodeString(&CertStore, pwszCertStore);

        ulErr = KeyrExportCert(pKeySvcCliInfo->hRPCBinding,
                               pKeySvcCliInfo->hKeySvc,
                               &Password, &CertStore,
                               cHashCount, pHashes,
                               ulFlags, &pTmpReserved, ppPFXBlob);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG KeyImportCert(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [in] */ LPWSTR pwszPassword,
    /* [in] */ LPWSTR pwszCertStore,
    /* [in] */ PKEYSVC_BLOB pPFXBlob,
    /* [in] */ ULONG ulFlags,
    /* [in, out] */ void *pReserved)
{
    PKEYSVCC_INFO           pKeySvcCliInfo = NULL;
    PKEYSVC_BLOB            pTmpReserved = NULL;
    KEYSVC_UNICODE_STRING   Password;
    KEYSVC_UNICODE_STRING   CertStore;
    ULONG                   ulErr = 0;

    __try
    {
        memset(&Password, 0, sizeof(Password));
        memset(&CertStore, 0, sizeof(CertStore));

        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        InitUnicodeString(&Password, pwszPassword);
        InitUnicodeString(&CertStore, pwszCertStore);

        ulErr = KeyrImportCert(pKeySvcCliInfo->hRPCBinding,
                               pKeySvcCliInfo->hKeySvc,
                               &Password, &CertStore,
                               pPFXBlob, ulFlags, &pTmpReserved);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}


ULONG KeyEnumerateAvailableCertTypes(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [out][in] */ void *pReserved,
    /* [out][in] */ ULONG *pcCertTypeCount,
    /* [in, out][size_is(,*pcCertTypeCount)] */
               PKEYSVC_UNICODE_STRING *ppCertTypes)

{
    PKEYSVC_BLOB    pTmpReserved = NULL;
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = KeyrEnumerateAvailableCertTypes(pKeySvcCliInfo->hRPCBinding,
                                          pKeySvcCliInfo->hKeySvc,
                                          &pTmpReserved,
                                          pcCertTypeCount, 
                                          ppCertTypes);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}


ULONG KeyEnumerateCAs(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [out][in] */ void *pReserved,
    /* [in] */      ULONG  ulFlags,
    /* [out][in] */ ULONG *pcCACount,
    /* [in, out][size_is(,*pcCACount)] */
               PKEYSVC_UNICODE_STRING *ppCAs)

{
    PKEYSVC_BLOB    pTmpReserved = NULL;
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = KeyrEnumerateCAs(pKeySvcCliInfo->hRPCBinding,
                                 pKeySvcCliInfo->hKeySvc,
                                 &pTmpReserved,
                                 ulFlags,
                                 pcCACount, 
                                 ppCAs);
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}


extern "C" ULONG KeyQueryRequestStatus
(/* [in] */        KEYSVCC_HANDLE                        hKeySvcCli, 
 /* [in] */        HANDLE                                hRequest, 
 /* [out, ref] */  CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO  *pQueryInfo)
{
    KEYSVC_QUERY_CERT_REQUEST_INFO  ksQueryCertRequestInfo; 
    PKEYSVCC_INFO                   pKeySvcCliInfo          = NULL;
    ULONG                           ulErr                   = 0;

    __try
    {
        if (NULL == hKeySvcCli || NULL == pQueryInfo)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        ZeroMemory(&ksQueryCertRequestInfo, sizeof(ksQueryCertRequestInfo)); 

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = KeyrQueryRequestStatus
          (pKeySvcCliInfo->hRPCBinding,
           (unsigned __int64)hRequest, 
           &ksQueryCertRequestInfo); 
        if (ERROR_SUCCESS == ulErr) 
        {
            pQueryInfo->dwSize   = ksQueryCertRequestInfo.ulSize; 
            pQueryInfo->dwStatus = ksQueryCertRequestInfo.ulStatus; 
        }
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }
Ret:
    return ulErr;
}

ULONG RKeyOpenKeyService
(/* [in] */ LPSTR pszMachineName,
 /* [in] */ KEYSVC_TYPE OwnerType,
 /* [in] */ LPWSTR pwszOwnerName,
 /* [in] */ void *pAuthentication,
 /* [out][in] */ void *pReserved,
 /* [out] */ KEYSVCC_HANDLE *phKeySvcCli)
{
    BOOL           fMustCloseKeyService  = FALSE;  // TRUE if the cleanup code must close key service
    DWORD          dwResult; 
    LPWSTR         pwszServerPrincName   = NULL; 
    PKEYSVCC_INFO  pKeySvcCliInfo        = NULL;

    dwResult = KeyOpenKeyServiceEx
        (IKeySvcR_v1_0_c_ifspec, 
         pszMachineName,
         OwnerType,
         pwszOwnerName,
         pAuthentication,
         pReserved,
         phKeySvcCli);
    if (ERROR_SUCCESS != dwResult) 
        goto error; 
    fMustCloseKeyService = TRUE; 
    
    pKeySvcCliInfo = (PKEYSVCC_INFO)(*phKeySvcCli); 
    dwResult = RpcMgmtInqServerPrincNameW(pKeySvcCliInfo->hRPCBinding, RPC_C_AUTHN_GSS_NEGOTIATE, &pwszServerPrincName); 
    if (RPC_S_OK != dwResult) 
        goto error;

    dwResult = RpcBindingSetAuthInfoW
        (pKeySvcCliInfo->hRPCBinding, 
         pwszServerPrincName,            
         RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  // Calls are authenticated and encrypted
         RPC_C_AUTHN_GSS_NEGOTIATE,   
         NULL, 
         RPC_C_AUTHZ_NONE
         );
    if (ERROR_SUCCESS != dwResult)
        goto error;
    
    fMustCloseKeyService  = FALSE; 
    dwResult              = ERROR_SUCCESS; 
 error:
    if (fMustCloseKeyService)         { RKeyCloseKeyService(phKeySvcCli, 0); }
    if (NULL != pwszServerPrincName)  { RpcStringFreeW(&pwszServerPrincName); }
    return dwResult; 
}

ULONG RKeyCloseKeyService(
    /* [in] */ KEYSVCC_HANDLE hKeySvcCli,
    /* [out][in] */ void *pReserved)
{
    return KeyCloseKeyService(hKeySvcCli, pReserved); 
}


ULONG RKeyPFXInstall
(/* [in] */ KEYSVCC_HANDLE          hKeySvcCli,
 /* [in] */ PKEYSVC_BLOB            pPFX,
 /* [in] */ PKEYSVC_UNICODE_STRING  pPassword,
 /* [in] */ ULONG                   ulFlags)
{
    PKEYSVCC_INFO   pKeySvcCliInfo = NULL;
    PKEYSVC_BLOB    pTmpReserved = NULL;
    ULONG           ulErr = 0;

    __try
    {
        if (NULL == hKeySvcCli)
        {
            ulErr = ERROR_INVALID_PARAMETER;
            goto Ret;
        }

        pKeySvcCliInfo = (PKEYSVCC_INFO)hKeySvcCli;

        ulErr = RKeyrPFXInstall(pKeySvcCliInfo->hRPCBinding,
                                pPFX, 
                                pPassword, 
                                ulFlags); 
    }
    __except ( EXCEPTION_EXECUTE_HANDLER )
    {
        ulErr = _exception_code();
    }

Ret:
    return ulErr;
}