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.
7464 lines
167 KiB
7464 lines
167 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: certreq.cpp
|
|
//
|
|
// Contents: Cert Store API Tests: Create and Add a chain of certificates
|
|
// and CRLs to the store.
|
|
//
|
|
// See Usage() for a list of test options.
|
|
//
|
|
//
|
|
// Functions: main
|
|
//
|
|
// History: 07-Mar-96 philh created
|
|
// 10-Oct-96 jerryk modified
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#define __DIR__ "certreq"
|
|
|
|
#define CMSG_SIGNER_ENCODE_INFO_HAS_CMS_FIELDS
|
|
#define CMSG_SIGNED_ENCODE_INFO_HAS_CMS_FIELDS
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <locale.h>
|
|
#include <io.h>
|
|
#include <fcntl.h>
|
|
#include <tchar.h>
|
|
#include <assert.h>
|
|
#include <wincrypt.h>
|
|
#include "certlib.h"
|
|
#include <certsrv.h>
|
|
#include <certca.h>
|
|
#include <commdlg.h>
|
|
#include <xenroll.h>
|
|
#include <common.ver>
|
|
#include "resource.h"
|
|
#include "csdisp.h"
|
|
#include "cscsp.h"
|
|
#include "csprop.h"
|
|
#include "clibres.h"
|
|
#include "csresstr.h"
|
|
|
|
|
|
#define __dwFILE__ __dwFILE_CERTREQ_CERTREQ_CPP__
|
|
|
|
|
|
#define CR_IN_CERT CR_IN_FORMATMASK
|
|
|
|
#define wprintf myConsolePrintf
|
|
|
|
#define WM_DOCERTREQDIALOGS WM_USER+0
|
|
|
|
HINSTANCE g_hInstance;
|
|
|
|
typedef struct _IDSUSAGE {
|
|
DWORD idsVerb;
|
|
DWORD idsOptions;
|
|
WCHAR const *pwszVerb;
|
|
} IDSUSAGE;
|
|
|
|
#define cmdNONE MAXDWORD
|
|
|
|
IDSUSAGE g_aidsUsage[] = {
|
|
#define cmdSUBMITREQUEST 0
|
|
{ IDS_USAGE_VERB_DEFAULT, IDS_USAGE_OPTIONS_DEFAULT, L"Submit" },
|
|
|
|
#define cmdRETRIEVEPENDING 1
|
|
{ IDS_USAGE_VERB_RETRIEVE, IDS_USAGE_OPTIONS_RETRIEVE, L"Retrieve" },
|
|
|
|
#define cmdNEWREQUEST 2
|
|
{ IDS_USAGE_VERB_NEW, IDS_USAGE_OPTIONS_NEW, L"New" },
|
|
|
|
#define cmdACCEPTRESPONSE 3
|
|
{ IDS_USAGE_VERB_ACCEPT, IDS_USAGE_OPTIONS_ACCEPT, L"Accept" },
|
|
|
|
#define cmdQUALIFIEDREQUEST 4
|
|
{ IDS_USAGE_VERB_POLICY, IDS_USAGE_OPTIONS_POLICY, L"Policy" },
|
|
|
|
#define cmdSIGNREQUEST 5
|
|
{ IDS_USAGE_VERB_SIGN, IDS_USAGE_OPTIONS_SIGN, L"Sign" },
|
|
};
|
|
|
|
|
|
WCHAR *g_apwszOptionStrings[] = {
|
|
L"any", // %1
|
|
L"attrib", // %2
|
|
L"binary", // %3
|
|
L"cert", // %4
|
|
L"config", // %5
|
|
L"crl", // %6
|
|
L"f", // %7
|
|
L"q", // %8
|
|
L"rpc", // %9
|
|
L"v", // %10
|
|
L"?", // %11
|
|
L"v1", // %12
|
|
L"idispatch", // %13
|
|
};
|
|
|
|
|
|
|
|
DWORD g_dwCommand = cmdNONE;
|
|
|
|
BOOL g_fAny = FALSE;
|
|
BOOL g_fRPC = FALSE;
|
|
BOOL g_fIDispatch = FALSE;
|
|
BOOL g_fForce = FALSE;
|
|
BOOL g_fQuiet = FALSE;
|
|
BOOL g_fV1Interface = FALSE;
|
|
BOOL g_fFullUsage = FALSE;
|
|
BOOL g_fVerbose = FALSE;
|
|
BOOL g_idError = 0;
|
|
LONG g_dwOutFormat = CV_OUT_BASE64REQUESTHEADER;
|
|
DWORD g_dwUIFlag = CC_UIPICKCONFIG;
|
|
DWORD g_dwCRLIn = 0;
|
|
DWORD g_dwCRLOut = 0;
|
|
|
|
WCHAR *g_pwszInfErrorString = NULL;
|
|
WCHAR *g_pwszErrorString = NULL;
|
|
WCHAR *g_pwszUnreferencedSectionNames = NULL;
|
|
|
|
WCHAR *g_pwszConfig = NULL;
|
|
WCHAR *g_pwszCertCN = NULL;
|
|
WCHAR const g_wszNewLine[] = L"\n";
|
|
CHAR const *g_pszObjIdHash = szOID_OIWSEC_sha1;
|
|
|
|
|
|
#define wszINFSECTION_NEWREQUEST L"NewRequest"
|
|
#define wszINFKEY_SUBJECT L"Subject"
|
|
#define wszINFKEY_PRIVATEKEYARCHIVE L"PrivateKeyArchive"
|
|
#define wszINFKEY_KEYSPEC L"KeySpec"
|
|
#define wszINFKEY_KEYLENGTH L"KeyLength"
|
|
#define wszINFKEY_RENEWALCERT L"RenewalCert"
|
|
#define wszINFKEY_SMIME L"SMIME"
|
|
#define wszINFKEY_EXPORTABLE L"Exportable"
|
|
#define wszINFKEY_USERPROTECTED L"UserProtected"
|
|
#define wszINFKEY_KEYCONTAINER L"KeyContainer"
|
|
#define wszINFKEY_HASHALGID L"HashAlgId"
|
|
#define wszINFKEY_HASHALGORITHM L"HashAlgorithm"
|
|
#define wszINFKEY_MACHINEKEYSET L"MachineKeySet"
|
|
#define wszINFKEY_SILENT L"Silent"
|
|
#define wszINFKEY_PROVIDERNAME L"ProviderName"
|
|
#define wszINFKEY_PROVIDERTYPE L"ProviderType"
|
|
#define wszINFKEY_USEEXISTINGKEYSET L"UseExistingKeySet"
|
|
#define wszINFKEY_REQUESTERNAME wszPROPREQUESTERNAME
|
|
#define wszINFKEY_REQUESTTYPE L"RequestType"
|
|
#define wszINFKEY_KEYUSAGE L"KeyUsage"
|
|
#define wszINFKEY_ENCIPHERONLY L"EncipherOnly"
|
|
|
|
#define wszINFVALUE_REQUESTTYPE_PKCS101 L"PKCS10-"
|
|
#define wszINFVALUE_REQUESTTYPE_PKCS10 L"PKCS10"
|
|
#define wszINFVALUE_REQUESTTYPE_PKCS7 L"PKCS7"
|
|
#define wszINFVALUE_REQUESTTYPE_CMC L"CMC"
|
|
|
|
|
|
typedef struct _INFUSAGE
|
|
{
|
|
WCHAR const *pwszKey;
|
|
} INFUSAGE;
|
|
|
|
WCHAR const *g_apwszInfKeyNewRequest[] = {
|
|
wszINFKEY_SUBJECT L" = \"CN=..,OU=...,DC=...\"",
|
|
wszINFKEY_PRIVATEKEYARCHIVE L" = TRUE",
|
|
wszINFKEY_KEYSPEC L" = 1",
|
|
wszINFKEY_KEYLENGTH L" = 1024",
|
|
wszINFKEY_RENEWALCERT L" = CertId",
|
|
wszINFKEY_SMIME L" = TRUE",
|
|
wszINFKEY_EXPORTABLE L" = TRUE",
|
|
wszINFKEY_USERPROTECTED L" = TRUE",
|
|
wszINFKEY_KEYCONTAINER L" = \"...\"",
|
|
#if 0
|
|
wszINFKEY_HASHALGID L" = ???",
|
|
wszINFKEY_HASHALGORITHM L" = ???",
|
|
#endif
|
|
wszINFKEY_MACHINEKEYSET L" = TRUE",
|
|
wszINFKEY_SILENT L" = TRUE",
|
|
wszINFKEY_PROVIDERNAME L" = \"" MS_ENHANCED_PROV_W L"\"",
|
|
wszINFKEY_PROVIDERTYPE L" = 1",
|
|
wszINFKEY_USEEXISTINGKEYSET L" = TRUE",
|
|
wszINFKEY_REQUESTERNAME L" = DOMAIN\\User",
|
|
wszINFKEY_REQUESTTYPE L" = " wszINFVALUE_REQUESTTYPE_PKCS10
|
|
L" | " wszINFVALUE_REQUESTTYPE_PKCS101
|
|
L" | " wszINFVALUE_REQUESTTYPE_PKCS7
|
|
L" | " wszINFVALUE_REQUESTTYPE_CMC,
|
|
wszINFKEY_KEYUSAGE L" = 0x80",
|
|
wszINFKEY_ENCIPHERONLY L" = TRUE",
|
|
};
|
|
|
|
HRESULT
|
|
GetCMCTemplateName(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
IN OUT BOOL *pfCA,
|
|
OUT WCHAR **ppwszTemplateName);
|
|
|
|
|
|
// Save eror string: "foo.inf" or "foo.inf(key = "value", "value")"
|
|
|
|
HRESULT
|
|
SetErrorStringInf(
|
|
IN WCHAR const *pwszString,
|
|
OPTIONAL IN INFVALUES *pInfValues)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (NULL == g_pwszErrorString && NULL != pwszString)
|
|
{
|
|
DWORD cwc = wcslen(pwszString);
|
|
DWORD i;
|
|
|
|
if (NULL != pInfValues && NULL != pInfValues->pwszKey)
|
|
{
|
|
cwc += 1 + wcslen(pInfValues->pwszKey) + 2 + 1;
|
|
|
|
for (i = 0; i < pInfValues->cValues; i++)
|
|
{
|
|
if (NULL == pInfValues->rgpwszValues[i])
|
|
{
|
|
break;
|
|
}
|
|
if (0 != i)
|
|
{
|
|
cwc++;
|
|
}
|
|
cwc += 2 + wcslen(pInfValues->rgpwszValues[i]) + 1;
|
|
}
|
|
}
|
|
g_pwszErrorString = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(cwc + 1) * sizeof(WCHAR));
|
|
if (NULL == g_pwszErrorString)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(g_pwszErrorString, pwszString);
|
|
|
|
if (NULL != pInfValues && NULL != pInfValues->pwszKey)
|
|
{
|
|
wcscat(g_pwszErrorString, wszLPAREN);
|
|
wcscat(g_pwszErrorString, pInfValues->pwszKey);
|
|
wcscat(g_pwszErrorString, L" =");
|
|
|
|
for (i = 0; i < pInfValues->cValues; i++)
|
|
{
|
|
if (NULL == pInfValues->rgpwszValues[i])
|
|
{
|
|
break;
|
|
}
|
|
if (0 != i)
|
|
{
|
|
wcscat(g_pwszErrorString, L",");
|
|
}
|
|
wcscat(g_pwszErrorString, L" \"");
|
|
wcscat(g_pwszErrorString, pInfValues->rgpwszValues[i]);
|
|
wcscat(g_pwszErrorString, L"\"");
|
|
}
|
|
wcscat(g_pwszErrorString, wszRPAREN);
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
SetErrorString(
|
|
IN WCHAR const *pwszString)
|
|
{
|
|
SetErrorStringInf(pwszString, NULL);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DisplayResourceString(
|
|
IN DWORD idsMsg,
|
|
OPTIONAL IN WCHAR const * const *papwszString,
|
|
OPTIONAL OUT WCHAR **ppwszFormatted)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszRaw = NULL;
|
|
WCHAR *pwszFormatted = NULL;
|
|
|
|
if (NULL != ppwszFormatted)
|
|
{
|
|
*ppwszFormatted = NULL;
|
|
}
|
|
hr = myLoadRCString(g_hInstance, idsMsg, &pwszRaw);
|
|
_JumpIfError(hr, error, "myLoadRCString");
|
|
|
|
if (0 == FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_STRING |
|
|
FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
|
(VOID *) pwszRaw,
|
|
0, // dwMessageID
|
|
0, // dwLanguageID
|
|
(LPWSTR) &pwszFormatted,
|
|
0,
|
|
(va_list *) papwszString))
|
|
{
|
|
hr = myHLastError();
|
|
wprintf(pwszRaw);
|
|
_JumpError(hr, error, "FormatMessage");
|
|
}
|
|
if (NULL != ppwszFormatted)
|
|
{
|
|
*ppwszFormatted = pwszFormatted;
|
|
pwszFormatted = NULL;
|
|
}
|
|
else
|
|
{
|
|
wprintf(pwszFormatted);
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszRaw)
|
|
{
|
|
LocalFree(pwszRaw);
|
|
}
|
|
if (NULL != pwszFormatted)
|
|
{
|
|
LocalFree(pwszFormatted);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
DWORD g_aidsOptions[] =
|
|
{
|
|
IDS_USAGE_OPTION_ANY,
|
|
IDS_USAGE_OPTION_ATTRIB,
|
|
IDS_USAGE_OPTION_BINARY,
|
|
IDS_USAGE_OPTION_CERT,
|
|
IDS_USAGE_OPTION_CONFIG,
|
|
IDS_USAGE_OPTION_CRL,
|
|
IDS_USAGE_OPTION_F,
|
|
IDS_USAGE_OPTION_Q,
|
|
IDS_USAGE_OPTION_RPC,
|
|
IDS_USAGE_OPTION_VERBOSE,
|
|
IDS_USAGE_OPTION_QUESTION,
|
|
};
|
|
|
|
|
|
DWORD g_aidsOptionsFull[] =
|
|
{
|
|
IDS_USAGE_OPTION_V1,
|
|
IDS_USAGE_OPTION_IDISPATCH,
|
|
};
|
|
|
|
|
|
// Option description formatting:
|
|
// Resource string contains "%2 <Arg>\nDescription\nMore description\n"
|
|
// To format:
|
|
// insert " -" in front of the first line and skip the newline,
|
|
// insert space to pad out to N-2 columns and "- " before the second line,
|
|
// insert space to pad out to N columns before all additional lines.
|
|
|
|
#define cwcINDENT 28 // ----+
|
|
// |
|
|
/* v
|
|
-Optiom <Arg> - Description\n
|
|
More description\n
|
|
*/
|
|
|
|
|
|
VOID
|
|
DisplayOptionList(
|
|
IN DWORD cOpt,
|
|
IN DWORD *aidsOpt)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < cOpt; i++)
|
|
{
|
|
WCHAR *pwszFormatted = NULL;
|
|
WCHAR const *pwszPrefix;
|
|
WCHAR *pwsz;
|
|
DWORD j;
|
|
DWORD iLine;
|
|
DWORD cwc0;
|
|
|
|
DisplayResourceString(aidsOpt[i], g_apwszOptionStrings, &pwszFormatted);
|
|
if (NULL == pwszFormatted)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
pwsz = pwszFormatted;
|
|
iLine = 0;
|
|
cwc0 = 0;
|
|
while (L'\0' != *pwsz)
|
|
{
|
|
WCHAR const *pwszNewLine = L"\n";
|
|
DWORD cwcPad;
|
|
|
|
j = wcscspn(pwsz, L"\r\n");
|
|
|
|
switch (iLine)
|
|
{
|
|
WCHAR wc;
|
|
|
|
case 0:
|
|
cwcPad = 2;
|
|
pwszPrefix = L"-";
|
|
wc = pwsz[j];
|
|
pwsz[j] = L'\0';
|
|
cwc0 = cwcPad +
|
|
wcslen(pwszPrefix) +
|
|
myGetDisplayLength(pwsz);
|
|
pwsz[j] = wc;
|
|
pwszNewLine = L"";
|
|
break;
|
|
|
|
case 1:
|
|
cwcPad = 1;
|
|
if (cwcINDENT > 2 + cwc0)
|
|
{
|
|
cwcPad = cwcINDENT - (2 + cwc0);
|
|
}
|
|
pwszPrefix = L"- ";
|
|
break;
|
|
|
|
default:
|
|
cwcPad = cwcINDENT;
|
|
pwszPrefix = L"";
|
|
break;
|
|
}
|
|
wprintf(
|
|
L"%*ws%ws%.*ws%ws",
|
|
cwcPad,
|
|
L"",
|
|
pwszPrefix,
|
|
j,
|
|
pwsz,
|
|
pwszNewLine);
|
|
|
|
pwsz += j;
|
|
if (L'\r' == *pwsz)
|
|
{
|
|
pwsz++;
|
|
}
|
|
if (L'\n' == *pwsz)
|
|
{
|
|
pwsz++;
|
|
}
|
|
iLine++;
|
|
}
|
|
LocalFree(pwszFormatted);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
Usage(
|
|
IN BOOL fError)
|
|
{
|
|
IDSUSAGE *pidsUsage;
|
|
IDSUSAGE *pidsUsageEnd;
|
|
BOOL fShowOptions;
|
|
|
|
DisplayResourceString(IDS_USAGE_GENERAL, NULL, NULL);
|
|
wprintf(L"\n");
|
|
switch (g_dwCommand)
|
|
{
|
|
case cmdSUBMITREQUEST:
|
|
case cmdRETRIEVEPENDING:
|
|
case cmdNEWREQUEST:
|
|
case cmdACCEPTRESPONSE:
|
|
case cmdQUALIFIEDREQUEST:
|
|
case cmdSIGNREQUEST:
|
|
pidsUsage = &g_aidsUsage[g_dwCommand];
|
|
pidsUsageEnd = &pidsUsage[1];
|
|
fShowOptions = TRUE;
|
|
break;
|
|
|
|
case cmdNONE:
|
|
default:
|
|
pidsUsage = g_aidsUsage;
|
|
pidsUsageEnd = &g_aidsUsage[ARRAYSIZE(g_aidsUsage)];
|
|
fShowOptions = g_fVerbose;
|
|
break;
|
|
}
|
|
if (fError)
|
|
{
|
|
fShowOptions = FALSE;
|
|
}
|
|
for ( ; pidsUsage < pidsUsageEnd; pidsUsage++)
|
|
{
|
|
DisplayResourceString(pidsUsage->idsVerb, &pidsUsage->pwszVerb, NULL);
|
|
if (fShowOptions)
|
|
{
|
|
DisplayResourceString(pidsUsage->idsOptions, g_apwszOptionStrings, NULL);
|
|
}
|
|
wprintf(L"\n");
|
|
}
|
|
if (fShowOptions)
|
|
{
|
|
DisplayResourceString(IDS_USAGE_OPTIONS_DESCRIPTION, NULL, NULL);
|
|
DisplayOptionList(ARRAYSIZE(g_aidsOptions), g_aidsOptions);
|
|
if (g_fFullUsage)
|
|
{
|
|
DisplayOptionList(ARRAYSIZE(g_aidsOptionsFull), g_aidsOptionsFull);
|
|
}
|
|
wprintf(L"\n");
|
|
DisplayResourceString(IDS_USAGE_DESCRIPTION, g_apwszOptionStrings, NULL);
|
|
}
|
|
if (!fError)
|
|
{
|
|
if ((cmdNEWREQUEST == g_dwCommand ||
|
|
(cmdNONE == g_dwCommand && g_fVerbose)))
|
|
{
|
|
DWORD i;
|
|
|
|
wprintf(L"[%ws]\n", wszINFSECTION_NEWREQUEST);
|
|
for (i = 0; i < ARRAYSIZE(g_apwszInfKeyNewRequest); i++)
|
|
{
|
|
wprintf(L" %ws\n", g_apwszInfKeyNewRequest[i]);
|
|
}
|
|
}
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
|
|
VOID
|
|
AppendAttributeString(
|
|
IN OUT WCHAR *pwszOut,
|
|
IN WCHAR const *pwszIn)
|
|
{
|
|
pwszOut += wcslen(pwszOut);
|
|
while (L'\0' != *pwszIn)
|
|
{
|
|
switch (*pwszIn)
|
|
{
|
|
case L';':
|
|
*pwszOut = L'\n';
|
|
break;
|
|
|
|
case L'\\':
|
|
if (L'n' == pwszIn[1])
|
|
{
|
|
*pwszOut = L'\n';
|
|
pwszIn++;
|
|
break;
|
|
}
|
|
if (L'r' == pwszIn[1])
|
|
{
|
|
*pwszOut = L'\r';
|
|
pwszIn++;
|
|
break;
|
|
}
|
|
// else FALLTHROUGH
|
|
|
|
default:
|
|
*pwszOut = *pwszIn;
|
|
break;
|
|
}
|
|
pwszOut++;
|
|
pwszIn++;
|
|
}
|
|
*pwszOut = L'\0';
|
|
}
|
|
|
|
|
|
HRESULT
|
|
crCombineAttributes(
|
|
IN WCHAR const *pwszAttributesAdd,
|
|
IN OUT WCHAR **ppwszAttributesExisting)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cwc;
|
|
WCHAR *pwszAttributesExisting = *ppwszAttributesExisting;
|
|
WCHAR *pwsz;
|
|
|
|
cwc = wcslen(pwszAttributesAdd) + 1;
|
|
if (NULL != pwszAttributesExisting)
|
|
{
|
|
cwc += wcslen(pwszAttributesExisting) + 1;
|
|
}
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, cwc * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
|
|
pwsz[0] = L'\0';
|
|
if (NULL != pwszAttributesExisting)
|
|
{
|
|
AppendAttributeString(pwsz, pwszAttributesExisting);
|
|
AppendAttributeString(pwsz, L"\\n");
|
|
LocalFree(pwszAttributesExisting);
|
|
}
|
|
AppendAttributeString(pwsz, pwszAttributesAdd);
|
|
*ppwszAttributesExisting = pwsz;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
crMissingFileArg()
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszMsg = NULL;
|
|
|
|
hr = myLoadRCString(g_hInstance, IDS_ERROR_NO_FILENAME, &pwszMsg);
|
|
_JumpIfError(hr, error, "myLoadRCString");
|
|
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(pwszMsg);
|
|
wprintf(g_wszNewLine);
|
|
|
|
error:
|
|
if (NULL != pwszMsg)
|
|
{
|
|
LocalFree(pwszMsg);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
crGetOpenFileName(
|
|
IN HWND hWndOwner,
|
|
IN UINT idsOpenTitle,
|
|
IN UINT idsFileFilter,
|
|
IN UINT idsFileDefExt,
|
|
OUT WCHAR **ppwszOFN)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (g_fQuiet)
|
|
{
|
|
crMissingFileArg();
|
|
Usage(TRUE);
|
|
}
|
|
|
|
// Put up a file dialog to prompt the user for Inf File
|
|
// 0 == hr means dialog was cancelled, we cheat because S_OK == 0
|
|
|
|
hr = myGetOpenFileName(
|
|
hWndOwner,
|
|
NULL, // hInstance
|
|
idsOpenTitle,
|
|
idsFileFilter,
|
|
idsFileDefExt,
|
|
OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY,
|
|
NULL, // no default file
|
|
ppwszOFN);
|
|
_JumpIfError(hr, error, "myGetOpenFileName");
|
|
|
|
if (NULL == *ppwszOFN)
|
|
{
|
|
// cancelled:
|
|
// see public\sdk\inc\cderr.h for real CommDlgExtendedError errors
|
|
|
|
hr = myHError(CommDlgExtendedError());
|
|
if (S_OK == hr)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
}
|
|
_JumpError(hr, error, "myGetOpenFileName");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
crOverwriteFileAllowed(
|
|
IN HWND hWndOwner,
|
|
IN WCHAR const *pwszfnOut)
|
|
{
|
|
HRESULT hr;
|
|
int rc = IDCANCEL;
|
|
WCHAR *pwszTitle = NULL;
|
|
WCHAR *pwszMessage = NULL;
|
|
WCHAR *pwsz = NULL;
|
|
|
|
if (!g_fForce && myDoesFileExist(pwszfnOut))
|
|
{
|
|
if (!g_fQuiet)
|
|
{
|
|
DWORD cwc;
|
|
|
|
hr = myLoadRCString(g_hInstance, IDS_CERTREQ_TITLE, &pwszTitle);
|
|
_JumpIfError(hr, error, "myLoadRCString");
|
|
|
|
hr = myLoadRCString(g_hInstance, IDS_OVERWRITE_FILE, &pwszMessage);
|
|
_JumpIfError(hr, error, "myLoadRCString");
|
|
|
|
cwc = wcslen(pwszMessage) + 2 + wcslen(pwszfnOut);
|
|
pwsz = (WCHAR *) LocalAlloc(LMEM_FIXED, (1 + cwc) * sizeof(WCHAR));
|
|
if (NULL == pwsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(pwsz, pwszMessage);
|
|
wcscat(pwsz, L"\r\n");
|
|
wcscat(pwsz, pwszfnOut);
|
|
|
|
rc = MessageBox(
|
|
hWndOwner,
|
|
pwsz,
|
|
pwszTitle,
|
|
MB_OKCANCEL |
|
|
MB_DEFBUTTON2 |
|
|
MB_ICONWARNING |
|
|
MB_SETFOREGROUND);
|
|
}
|
|
if (IDOK != rc)
|
|
{
|
|
SetErrorString(pwszfnOut);
|
|
hr = g_fQuiet?
|
|
HRESULT_FROM_WIN32(ERROR_FILE_EXISTS) :
|
|
HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
_JumpErrorStr(hr, error, "File Exists", pwszfnOut);
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwsz)
|
|
{
|
|
LocalFree(pwsz);
|
|
}
|
|
if (NULL != pwszTitle)
|
|
{
|
|
LocalFree(pwszTitle);
|
|
}
|
|
if (NULL != pwszMessage)
|
|
{
|
|
LocalFree(pwszMessage);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
WriteCertificateOrRequest(
|
|
IN HWND hWndOwner,
|
|
OPTIONAL IN DISPATCHINTERFACE *pdiRequest,
|
|
OPTIONAL IN BYTE const *pbOut,
|
|
IN DWORD cbOut,
|
|
IN DWORD Flags,
|
|
IN DWORD idsTitle,
|
|
IN DWORD idsFilter,
|
|
IN DWORD idsDefExt,
|
|
OPTIONAL IN WCHAR const *pwszfnOut)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszOFN = NULL;
|
|
BSTR strCert = NULL;
|
|
CHAR *pszCert = NULL;
|
|
DWORD decFlags = CRYPT_STRING_BINARY;
|
|
BOOL fCheckFileOverwriteOK = TRUE; // careful not to overwrite without prompting user
|
|
|
|
if (NULL == pwszfnOut)
|
|
{
|
|
if (g_fQuiet)
|
|
{
|
|
crMissingFileArg();
|
|
Usage(TRUE);
|
|
}
|
|
|
|
// Put up a file dialog to prompt the user for Cert file
|
|
// 0 == hr means dialog was cancelled, we cheat because S_OK == 0
|
|
|
|
hr = myGetSaveFileName(
|
|
hWndOwner,
|
|
NULL, // hInstance
|
|
idsTitle,
|
|
idsFilter,
|
|
idsDefExt,
|
|
OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT,
|
|
NULL, // no default file
|
|
&pwszOFN);
|
|
_JumpIfError(hr, error, "myGetSaveFileName");
|
|
|
|
fCheckFileOverwriteOK = FALSE; // OFN_OVERWRITEPROMPT should have prompted if necessary
|
|
|
|
if (NULL == pwszOFN)
|
|
{
|
|
// cancelled:
|
|
// see public\sdk\inc\cderr.h for real CommDlgExtendedError errors
|
|
|
|
hr = myHError(CommDlgExtendedError());
|
|
_JumpError(hr, error, "myGetSaveFileName");
|
|
}
|
|
pwszfnOut = pwszOFN;
|
|
|
|
hr = myIsDirWriteable(pwszfnOut, TRUE);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnOut);
|
|
_JumpErrorStr(hr, error, "IsDirWriteable", pwszfnOut);
|
|
}
|
|
}
|
|
|
|
if (NULL == pbOut)
|
|
{
|
|
hr = Request_GetCertificate(pdiRequest, Flags, &strCert);
|
|
_JumpIfError(hr, error, "Request_GetCertificate");
|
|
|
|
if (CR_OUT_BINARY == (CR_OUT_ENCODEMASK & Flags))
|
|
{
|
|
cbOut = SysStringByteLen(strCert);
|
|
pbOut = (BYTE const *) strCert;
|
|
}
|
|
else
|
|
{
|
|
if (!ConvertWszToSz(&pszCert, strCert, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToSz(cert)");
|
|
}
|
|
cbOut = strlen(pszCert);
|
|
pbOut = (BYTE const *) pszCert;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
decFlags = CR_OUT_ENCODEMASK & Flags;
|
|
CSASSERT(CSExpr(CR_OUT_BASE64HEADER == CRYPT_STRING_BASE64HEADER));
|
|
CSASSERT(CSExpr(CR_OUT_BINARY == CRYPT_STRING_BINARY));
|
|
}
|
|
|
|
if (fCheckFileOverwriteOK)
|
|
{
|
|
hr = crOverwriteFileAllowed(hWndOwner, pwszfnOut);
|
|
_JumpIfError(hr, error, "crOverwriteFileAllowed");
|
|
}
|
|
|
|
hr = EncodeToFileW(
|
|
pwszfnOut,
|
|
pbOut,
|
|
cbOut,
|
|
DECF_FORCEOVERWRITE | decFlags);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnOut);
|
|
_JumpErrorStr(hr, error, "EncodeToFileW", pwszfnOut);
|
|
}
|
|
|
|
error:
|
|
if (NULL != strCert)
|
|
{
|
|
SysFreeString(strCert);
|
|
}
|
|
if (NULL != pszCert)
|
|
{
|
|
LocalFree(pszCert);
|
|
}
|
|
if (NULL != pwszOFN)
|
|
{
|
|
LocalFree(pwszOFN);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetLong(
|
|
WCHAR const *pwszIn,
|
|
LONG *pLong)
|
|
{
|
|
HRESULT hr = E_INVALIDARG;
|
|
WCHAR const *pwsz;
|
|
LONG l;
|
|
|
|
pwsz = pwszIn;
|
|
if (NULL == pwsz)
|
|
{
|
|
_JumpError(hr, error, "NULL parm");
|
|
}
|
|
if (L'\0' == *pwsz)
|
|
{
|
|
_JumpError(hr, error, "empty string");
|
|
}
|
|
if (L'0' == *pwsz && (L'x' == pwsz[1] || L'X' == pwsz[1]))
|
|
{
|
|
l = 0;
|
|
pwsz += 2;
|
|
for ( ; L'\0' != *pwsz; pwsz++)
|
|
{
|
|
if (!iswxdigit(*pwsz))
|
|
{
|
|
_JumpErrorStr(hr, error, "Non-hex digit", pwszIn);
|
|
}
|
|
if (0xf0000000 & l)
|
|
{
|
|
_JumpErrorStr(hr, error, "overflow", pwszIn);
|
|
}
|
|
l <<= 4;
|
|
if (iswdigit(*pwsz))
|
|
{
|
|
l |= *pwsz - L'0';
|
|
}
|
|
else if (L'A' <= *pwsz && L'F' >= *pwsz)
|
|
{
|
|
l |= *pwsz - L'A' + 10;
|
|
}
|
|
else
|
|
{
|
|
l |= *pwsz - L'a' + 10;
|
|
}
|
|
}
|
|
*pLong = l;
|
|
}
|
|
else
|
|
{
|
|
LARGE_INTEGER li;
|
|
|
|
li.QuadPart = 0;
|
|
for ( ; L'\0' != *pwsz; pwsz++)
|
|
{
|
|
if (!iswdigit(*pwsz))
|
|
{
|
|
_JumpErrorStr2(hr, error, "Non-decimal digit", pwszIn, hr);
|
|
}
|
|
li.QuadPart *= 10;
|
|
li.QuadPart += *pwsz - L'0';
|
|
if (0 != li.HighPart || 0 > (LONG) li.LowPart)
|
|
{
|
|
_JumpErrorStr2(hr, error, "overflow", pwszIn, hr);
|
|
}
|
|
}
|
|
*pLong = li.LowPart;
|
|
}
|
|
hr = S_OK;
|
|
//wprintf(L"GetLong(%ws) --> %x (%d)\n", pwszIn, *pLong, *pLong);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
IsSubjectTypeCA(
|
|
IN CERT_EXTENSION const *pExt,
|
|
OUT BOOL *pfCA)
|
|
{
|
|
HRESULT hr;
|
|
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
|
DWORD cb;
|
|
|
|
*pfCA = FALSE;
|
|
cb = sizeof(Constraints);
|
|
if (!CryptDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
pExt->Value.pbData,
|
|
pExt->Value.cbData,
|
|
0,
|
|
&Constraints,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptDecodeObject");
|
|
}
|
|
if (Constraints.fCA)
|
|
{
|
|
*pfCA = TRUE;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetExtensionsTemplateName(
|
|
IN CERT_EXTENSION const *rgExtension,
|
|
IN DWORD cExtension,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
CERT_EXTENSION const *pExt;
|
|
CERT_EXTENSION const *pExtEnd;
|
|
CERT_TEMPLATE_EXT *pTemplate = NULL;
|
|
CERT_NAME_VALUE *pName = NULL;
|
|
DWORD cb;
|
|
|
|
pExtEnd = &rgExtension[cExtension];
|
|
for (pExt = rgExtension; pExt < pExtEnd; pExt++)
|
|
{
|
|
if (NULL == *ppwszTemplateName)
|
|
{
|
|
if (0 == strcmp(pExt->pszObjId, szOID_CERTIFICATE_TEMPLATE))
|
|
{
|
|
// V2 template info extension
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERTIFICATE_TEMPLATE,
|
|
pExt->Value.pbData,
|
|
pExt->Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pTemplate,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myDecodeObject");
|
|
}
|
|
if (!myConvertSzToWsz(ppwszTemplateName, pTemplate->pszObjId, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "Policy:myConvertSzToBstr");
|
|
}
|
|
}
|
|
else
|
|
if (0 == strcmp(pExt->pszObjId, szOID_ENROLL_CERTTYPE_EXTENSION))
|
|
{
|
|
// V1 template name extension
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_UNICODE_ANY_STRING,
|
|
pExt->Value.pbData,
|
|
pExt->Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pName,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
hr = myDupString(
|
|
(WCHAR const *) pName->Value.pbData,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
}
|
|
if (!*pfCA)
|
|
{
|
|
if (0 == strcmp(pExt->pszObjId, szOID_BASIC_CONSTRAINTS2))
|
|
{
|
|
hr = IsSubjectTypeCA(pExt, pfCA);
|
|
_JumpIfError(hr, error, "IsSubjectTypeCA");
|
|
}
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pTemplate)
|
|
{
|
|
LocalFree(pTemplate);
|
|
}
|
|
if (NULL != pName)
|
|
{
|
|
LocalFree(pName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetAttributesTemplateName(
|
|
IN CRYPT_ATTRIBUTE const *rgAttrib,
|
|
IN DWORD cAttrib,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_ATTRIBUTE const *pAttrib;
|
|
CRYPT_ATTRIBUTE const *pAttribEnd;
|
|
CRYPT_ATTR_BLOB *pAttrBlob;
|
|
CERT_EXTENSIONS *pCertExtensions = NULL;
|
|
CRYPT_ENROLLMENT_NAME_VALUE_PAIR *pInfo = NULL;
|
|
DWORD cb;
|
|
DWORD i;
|
|
|
|
pAttribEnd = &rgAttrib[cAttrib];
|
|
for (pAttrib = rgAttrib; pAttrib < pAttribEnd; pAttrib++)
|
|
{
|
|
if (0 == strcmp(pAttrib->pszObjId, szOID_CERT_EXTENSIONS) ||
|
|
0 == strcmp(pAttrib->pszObjId, szOID_RSA_certExtensions))
|
|
{
|
|
if (1 != pAttrib->cValue)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Attribute Value count != 1");
|
|
}
|
|
if (NULL != pCertExtensions)
|
|
{
|
|
LocalFree(pCertExtensions);
|
|
pCertExtensions = NULL;
|
|
}
|
|
|
|
pAttrBlob = pAttrib->rgValue;
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_EXTENSIONS,
|
|
pAttrBlob->pbData,
|
|
pAttrBlob->cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pCertExtensions,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
hr = GetExtensionsTemplateName(
|
|
pCertExtensions->rgExtension,
|
|
pCertExtensions->cExtension,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetExtensionsTemplateName");
|
|
}
|
|
else
|
|
if (0 == strcmp(pAttrib->pszObjId, szOID_ENROLLMENT_NAME_VALUE_PAIR))
|
|
{
|
|
for (i = 0; i < pAttrib->cValue; i++)
|
|
{
|
|
if (NULL != pInfo)
|
|
{
|
|
LocalFree(pInfo);
|
|
pInfo = NULL;
|
|
}
|
|
pAttrBlob = &pAttrib->rgValue[i];
|
|
if (!myDecodeNameValuePair(
|
|
X509_ASN_ENCODING,
|
|
pAttrBlob->pbData,
|
|
pAttrBlob->cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pInfo,
|
|
&cb))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "myDecodeNameValuePair");
|
|
|
|
// if the attribute name & value are both non-empty ...
|
|
}
|
|
if (0 == LSTRCMPIS(pInfo->pwszName, wszPROPCERTTEMPLATE))
|
|
{
|
|
if (NULL == *ppwszTemplateName)
|
|
{
|
|
hr = myDupString(pInfo->pwszValue, ppwszTemplateName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pCertExtensions)
|
|
{
|
|
LocalFree(pCertExtensions);
|
|
}
|
|
if (NULL != pInfo)
|
|
{
|
|
LocalFree(pInfo);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetPKCS10TemplateName(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
CERT_REQUEST_INFO *pRequestInfo = NULL;
|
|
DWORD cb;
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
pbIn,
|
|
cbIn,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pRequestInfo,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
|
|
hr = GetAttributesTemplateName(
|
|
pRequestInfo->rgAttribute,
|
|
pRequestInfo->cAttribute,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetAttributesTemplateName");
|
|
|
|
error:
|
|
if (NULL != pRequestInfo)
|
|
{
|
|
LocalFree(pRequestInfo);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetCMCRequestTemplateName(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbContents = NULL;
|
|
DWORD cbContents;
|
|
char *pszInnerContentObjId = NULL;
|
|
|
|
hr = myDecodePKCS7(
|
|
pbIn,
|
|
cbIn,
|
|
&pbContents,
|
|
&cbContents,
|
|
NULL, // pdwMsgType
|
|
&pszInnerContentObjId,
|
|
NULL, // pcSigner
|
|
NULL, // pcRecipient
|
|
NULL, // phStore
|
|
NULL); // phMsg
|
|
_JumpIfError(hr, error, "myDecodePKCS7");
|
|
|
|
if (NULL != pszInnerContentObjId &&
|
|
0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA))
|
|
{
|
|
hr = GetCMCTemplateName(
|
|
pbContents,
|
|
cbContents,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetCMCTemplateName");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pszInnerContentObjId)
|
|
{
|
|
LocalFree(pszInnerContentObjId);
|
|
}
|
|
if (NULL != pbContents)
|
|
{
|
|
LocalFree(pbContents);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetCMCExtensionsTemplateName(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
CMC_ADD_EXTENSIONS_INFO *pcmcExt = NULL;
|
|
DWORD cb;
|
|
|
|
*ppwszTemplateName = NULL;
|
|
|
|
// Decode CMC_ADD_EXTENSIONS_INFO from Attribute Blob
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
CMC_ADD_EXTENSIONS,
|
|
pbIn,
|
|
cbIn,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pcmcExt,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
hr = GetExtensionsTemplateName(
|
|
pcmcExt->rgExtension,
|
|
pcmcExt->cExtension,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetExtensionsTemplateName");
|
|
|
|
error:
|
|
if (NULL != pcmcExt)
|
|
{
|
|
LocalFree(pcmcExt);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetCMCAttributesTemplateName(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
CMC_ADD_ATTRIBUTES_INFO *pcmcAttrib = NULL;
|
|
DWORD cb;
|
|
|
|
// Decode CMC_ADD_ATTRIBUTES_INFO from Attribute Blob
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
CMC_ADD_ATTRIBUTES,
|
|
pbIn,
|
|
cbIn,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pcmcAttrib,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
hr = GetAttributesTemplateName(
|
|
pcmcAttrib->rgAttribute,
|
|
pcmcAttrib->cAttribute,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetAttributesTemplateName");
|
|
|
|
error:
|
|
if (NULL != pcmcAttrib)
|
|
{
|
|
LocalFree(pcmcAttrib);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetRequestAttributesTemplateName(
|
|
IN WCHAR const *pwszAttributes,
|
|
IN BOOL fRegInfo,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszDup = NULL;
|
|
WCHAR *pwszBuf;
|
|
WCHAR const *pwszName;
|
|
WCHAR const *pwszValue;
|
|
WCHAR *pwszNameAlloc = NULL;
|
|
WCHAR *pwszValueAlloc = NULL;
|
|
|
|
if (NULL == pwszAttributes)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // silently ignore empty string
|
|
}
|
|
|
|
hr = myDupString(pwszAttributes, &pwszDup);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pwszBuf = pwszDup;
|
|
|
|
for (;;)
|
|
{
|
|
hr = myParseNextAttribute(&pwszBuf, fRegInfo, &pwszName, &pwszValue);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "myParseNextAttribute");
|
|
|
|
if (fRegInfo)
|
|
{
|
|
if (NULL != pwszNameAlloc)
|
|
{
|
|
LocalFree(pwszNameAlloc);
|
|
pwszNameAlloc = NULL;
|
|
}
|
|
if (NULL != pwszValueAlloc)
|
|
{
|
|
LocalFree(pwszValueAlloc);
|
|
pwszValueAlloc = NULL;
|
|
}
|
|
hr = myUncanonicalizeURLParm(pwszName, &pwszNameAlloc);
|
|
_JumpIfError(hr, error, "myUncanonicalizeURLParm");
|
|
|
|
hr = myUncanonicalizeURLParm(pwszValue, &pwszValueAlloc);
|
|
_JumpIfError(hr, error, "myUncanonicalizeURLParm");
|
|
|
|
pwszName = pwszNameAlloc;
|
|
pwszValue = pwszValueAlloc;
|
|
}
|
|
if (0 == LSTRCMPIS(pwszName, wszPROPCERTTEMPLATE))
|
|
{
|
|
if (NULL == *ppwszTemplateName)
|
|
{
|
|
hr = myDupString(pwszValue, ppwszTemplateName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszNameAlloc)
|
|
{
|
|
LocalFree(pwszNameAlloc);
|
|
}
|
|
if (NULL != pwszValueAlloc)
|
|
{
|
|
LocalFree(pwszValueAlloc);
|
|
}
|
|
if (NULL != pwszDup)
|
|
{
|
|
LocalFree(pwszDup);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetCMCRegInfoTemplateName(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszRA = NULL;
|
|
|
|
hr = myDecodeCMCRegInfo(pbIn, cbIn, &pwszRA);
|
|
_JumpIfError(hr, error, "myDecodeCMCRegInfo");
|
|
|
|
hr = GetRequestAttributesTemplateName(pwszRA, TRUE, ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetRequestAttributesTemplateName");
|
|
|
|
error:
|
|
if (NULL != pwszRA)
|
|
{
|
|
LocalFree(pwszRA);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetTaggedAttributeTemplateName(
|
|
IN CMC_TAGGED_ATTRIBUTE const *pTaggedAttribute,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
CRYPT_ATTRIBUTE const *pAttribute = &pTaggedAttribute->Attribute;
|
|
|
|
for (i = 0; i < pAttribute->cValue; i++)
|
|
{
|
|
if (0 == strcmp(szOID_CMC_ADD_EXTENSIONS, pAttribute->pszObjId))
|
|
{
|
|
hr = GetCMCExtensionsTemplateName(
|
|
pAttribute->rgValue[i].pbData,
|
|
pAttribute->rgValue[i].cbData,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetCMCExtensionsTemplateName");
|
|
}
|
|
else
|
|
if (0 == strcmp(szOID_CMC_ADD_ATTRIBUTES, pAttribute->pszObjId))
|
|
{
|
|
hr = GetCMCAttributesTemplateName(
|
|
pAttribute->rgValue[i].pbData,
|
|
pAttribute->rgValue[i].cbData,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetCMCAttributesTemplateName");
|
|
}
|
|
else
|
|
if (0 == strcmp(szOID_CMC_REG_INFO, pAttribute->pszObjId))
|
|
{
|
|
hr = GetCMCRegInfoTemplateName(
|
|
pAttribute->rgValue[i].pbData,
|
|
pAttribute->rgValue[i].cbData,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetCMCRegInfoTemplateName");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
// Just find the first template indicator available, and return it.
|
|
|
|
HRESULT
|
|
GetCMCTemplateName(
|
|
IN BYTE const *pbIn,
|
|
IN DWORD cbIn,
|
|
IN OUT BOOL *pfCA,
|
|
IN OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cb;
|
|
CMC_DATA_INFO *pcmcData = NULL;
|
|
DWORD i;
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
CMC_DATA,
|
|
pbIn,
|
|
cbIn,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pcmcData,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
|
|
// Process extensions and attributes
|
|
|
|
for (i = 0; i < pcmcData->cTaggedAttribute; i++)
|
|
{
|
|
hr = GetTaggedAttributeTemplateName(
|
|
&pcmcData->rgTaggedAttribute[i],
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "pkcsSetTaggedAttributes");
|
|
}
|
|
|
|
// Process nested CMC messages
|
|
|
|
if (0 != pcmcData->cTaggedContentInfo)
|
|
{
|
|
CMC_TAGGED_CONTENT_INFO const *pTaggedContentInfo;
|
|
|
|
// Recurse on the nested CMC message
|
|
// Only handle one request at a time for now.
|
|
|
|
pTaggedContentInfo = &pcmcData->rgTaggedContentInfo[0];
|
|
|
|
hr = GetCMCRequestTemplateName(
|
|
pTaggedContentInfo->EncodedContentInfo.pbData,
|
|
pTaggedContentInfo->EncodedContentInfo.cbData,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetCMCRequestTemplateName");
|
|
}
|
|
|
|
// Process nested PKCS10 requests
|
|
|
|
if (0 != pcmcData->cTaggedRequest)
|
|
{
|
|
CMC_TAGGED_REQUEST const *pTaggedRequest;
|
|
CMC_TAGGED_CERT_REQUEST const *pTaggedCertRequest;
|
|
|
|
// Only handle one request at a time for now.
|
|
|
|
pTaggedRequest = &pcmcData->rgTaggedRequest[0];
|
|
|
|
// The request must be a PKCS10 request
|
|
|
|
if (CMC_TAGGED_CERT_REQUEST_CHOICE ==
|
|
pTaggedRequest->dwTaggedRequestChoice)
|
|
{
|
|
pTaggedCertRequest = pTaggedRequest->pTaggedCertRequest;
|
|
|
|
hr = GetPKCS10TemplateName(
|
|
pTaggedCertRequest->SignedCertRequest.pbData,
|
|
pTaggedCertRequest->SignedCertRequest.cbData,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetPKCS10TemplateName");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pcmcData)
|
|
{
|
|
LocalFree(pcmcData);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CheckRequestType(
|
|
IN WCHAR const *pwszfnReq,
|
|
OUT BYTE **ppbReq,
|
|
OUT DWORD *pcbReq,
|
|
OUT LONG *pFlags,
|
|
OUT BOOL *pfSigned,
|
|
OPTIONAL OUT BOOL *pfCA,
|
|
OPTIONAL OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbReq = NULL;
|
|
DWORD cbReq;
|
|
BYTE *pbContents = NULL;
|
|
DWORD cbContents;
|
|
DWORD cb;
|
|
LONG EncodingType;
|
|
LONG RequestType;
|
|
BYTE *pbDecoded = NULL;
|
|
char *pszInnerContentObjId = NULL;
|
|
CERT_CONTEXT const *pcc = NULL;
|
|
CERT_SIGNED_CONTENT_INFO *pcsci = NULL;
|
|
DWORD cbcsci;
|
|
DWORD cSigner;
|
|
DWORD cRecipient;
|
|
BOOL fCAT;
|
|
WCHAR *pwszTemplateNameT = NULL;
|
|
|
|
*ppbReq = NULL;
|
|
*pcbReq = NULL;
|
|
*pFlags = 0;
|
|
*pfSigned = FALSE;
|
|
if (NULL == pfCA)
|
|
{
|
|
pfCA = &fCAT;
|
|
}
|
|
*pfCA = FALSE;
|
|
if (NULL == ppwszTemplateName)
|
|
{
|
|
ppwszTemplateName = &pwszTemplateNameT;
|
|
}
|
|
*ppwszTemplateName = NULL;
|
|
|
|
EncodingType = CR_IN_BASE64HEADER;
|
|
hr = DecodeFileW(pwszfnReq, &pbReq, &cbReq, CRYPT_STRING_BASE64HEADER);
|
|
if (S_OK != hr)
|
|
{
|
|
//_PrintError(hr, "DecodeFileW(CRYPT_STRING_BASE64HEADER)");
|
|
CSASSERT(NULL == pbReq);
|
|
|
|
EncodingType = CR_IN_BASE64;
|
|
hr = DecodeFileW(pwszfnReq, &pbReq, &cbReq, CRYPT_STRING_BASE64);
|
|
if (S_OK != hr)
|
|
{
|
|
//_PrintError(hr, "DecodeFileW(CRYPT_STRING_BASE64)");
|
|
CSASSERT(NULL == pbReq);
|
|
|
|
EncodingType = CR_IN_BINARY;
|
|
hr = DecodeFileW(pwszfnReq, &pbReq, &cbReq, CRYPT_STRING_BINARY);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnReq);
|
|
_JumpErrorStr(hr, error, "DecodeFileW", pwszfnReq);
|
|
}
|
|
}
|
|
}
|
|
CSASSERT(NULL != pbReq);
|
|
|
|
RequestType = CR_IN_PKCS10;
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
pbReq,
|
|
cbReq,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pbDecoded,
|
|
&cb))
|
|
{
|
|
//_PrintError(myHLastError(), "myDecodeObject(PKCS10)");
|
|
CSASSERT(NULL == pbDecoded);
|
|
|
|
RequestType = CR_IN_CERT;
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_TO_BE_SIGNED,
|
|
pbReq,
|
|
cbReq,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pbDecoded,
|
|
&cb))
|
|
{
|
|
//_PrintError(myHLastError(), "myDecodeObject(Cert)");
|
|
CSASSERT(NULL == pbDecoded);
|
|
|
|
RequestType = CR_IN_KEYGEN;
|
|
if (!myDecodeKeyGenRequest(
|
|
pbReq,
|
|
cbReq,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(CERT_KEYGEN_REQUEST_INFO **) &pbDecoded,
|
|
&cb))
|
|
{
|
|
//_PrintError(myHLastError(), "myDecodeKeyGenRequest");
|
|
CSASSERT(NULL == pbDecoded);
|
|
|
|
RequestType = CR_IN_PKCS7; // PKCS 7 renewal request?
|
|
hr = myDecodePKCS7(
|
|
pbReq,
|
|
cbReq,
|
|
&pbContents,
|
|
&cbContents,
|
|
NULL, // pdwMsgType
|
|
&pszInnerContentObjId,
|
|
&cSigner,
|
|
&cRecipient,
|
|
NULL, // phStore
|
|
NULL); // phMsg
|
|
_JumpIfError(hr, error, "myDecodePKCS7");
|
|
|
|
if (NULL != pszInnerContentObjId &&
|
|
0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_DATA))
|
|
{
|
|
RequestType = CR_IN_CMC;
|
|
hr = GetCMCTemplateName(
|
|
pbContents,
|
|
cbContents,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetCMCTemplateName");
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTREQ,
|
|
"TemplateName = %ws\n",
|
|
*ppwszTemplateName));
|
|
}
|
|
if (0 < cSigner)
|
|
{
|
|
*pfSigned = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (CR_IN_CERT == RequestType ||
|
|
CR_IN_PKCS10 == RequestType ||
|
|
CR_IN_KEYGEN == RequestType)
|
|
{
|
|
if (CR_IN_CERT == RequestType)
|
|
{
|
|
pcc = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
pbReq,
|
|
cbReq);
|
|
if (NULL == pcc)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
hr = GetExtensionsTemplateName(
|
|
pcc->pCertInfo->rgExtension,
|
|
pcc->pCertInfo->cExtension,
|
|
pfCA,
|
|
ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetExtensionsTemplateName");
|
|
}
|
|
else if (CR_IN_PKCS10 == RequestType)
|
|
{
|
|
hr = GetPKCS10TemplateName(pbReq, cbReq, pfCA, ppwszTemplateName);
|
|
_JumpIfError(hr, error, "GetPKCS10TemplateName");
|
|
}
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT,
|
|
pbReq,
|
|
cbReq,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pcsci,
|
|
&cbcsci))
|
|
{
|
|
hr = myHLastError();
|
|
_PrintError2(hr, "myDecodeObject", CRYPT_E_ASN1_BADTAG);
|
|
}
|
|
else
|
|
{
|
|
*pfSigned = TRUE; // has a signature
|
|
}
|
|
}
|
|
*ppbReq = pbReq;
|
|
pbReq = NULL;
|
|
*pcbReq = cbReq;
|
|
*pFlags = EncodingType | RequestType;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszTemplateNameT)
|
|
{
|
|
LocalFree(pwszTemplateNameT);
|
|
}
|
|
if (NULL != pcc)
|
|
{
|
|
CertFreeCertificateContext(pcc);
|
|
}
|
|
if (NULL != pcsci)
|
|
{
|
|
LocalFree(pcsci);
|
|
}
|
|
if (NULL != pszInnerContentObjId)
|
|
{
|
|
LocalFree(pszInnerContentObjId);
|
|
}
|
|
if (NULL != pbDecoded)
|
|
{
|
|
LocalFree(pbDecoded);
|
|
}
|
|
if (NULL != pbContents)
|
|
{
|
|
LocalFree(pbContents);
|
|
}
|
|
if (NULL != pbReq)
|
|
{
|
|
LocalFree(pbReq);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
WCHAR *
|
|
wszDisposition(
|
|
DWORD disposition)
|
|
{
|
|
HRESULT hr;
|
|
UINT iRsc = 0;
|
|
WCHAR *pwszDisposition = NULL;
|
|
|
|
switch (disposition)
|
|
{
|
|
case CR_DISP_INCOMPLETE:
|
|
iRsc = IDS_DISPOSITION_INCOMPLETE;
|
|
break;
|
|
|
|
case CR_DISP_ERROR:
|
|
iRsc = IDS_DISPOSITION_ERROR;
|
|
break;
|
|
|
|
case CR_DISP_DENIED:
|
|
iRsc = IDS_DISPOSITION_DENIED;
|
|
break;
|
|
|
|
case CR_DISP_ISSUED:
|
|
iRsc = IDS_DISPOSITION_ISSUED;
|
|
break;
|
|
|
|
case CR_DISP_ISSUED_OUT_OF_BAND:
|
|
iRsc = IDS_DISPOSITION_ISSUED_OOB;
|
|
break;
|
|
|
|
case CR_DISP_UNDER_SUBMISSION:
|
|
iRsc = IDS_DISPOSITION_UNDER_SUBMISSION;
|
|
break;
|
|
|
|
case CR_DISP_REVOKED:
|
|
iRsc = IDS_DISPOSITION_REVOKED;
|
|
break;
|
|
|
|
default:
|
|
iRsc = IDS_DISPOSITION_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
hr = myLoadRCString(g_hInstance, iRsc, &pwszDisposition);
|
|
_PrintIfError(hr, "myLoadRCString");
|
|
|
|
return(pwszDisposition);
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpProperty(
|
|
IN DISPATCHINTERFACE *pdiRequest,
|
|
IN LONG PropId,
|
|
IN WCHAR const *pwszPropId,
|
|
IN LONG PropIndex,
|
|
IN LONG PropType,
|
|
OPTIONAL OUT LONG *pCount)
|
|
{
|
|
HRESULT hr;
|
|
LONG Flags;
|
|
VOID *pvOut;
|
|
BSTR str = NULL;
|
|
LONG val;
|
|
DATE date;
|
|
WCHAR wszInfo[128];
|
|
|
|
if (NULL != pCount)
|
|
{
|
|
*pCount = 0;
|
|
}
|
|
Flags = CV_OUT_BINARY;
|
|
val = 0;
|
|
date = 0.0;
|
|
pvOut = NULL;
|
|
switch (PropType)
|
|
{
|
|
case PROPTYPE_BINARY:
|
|
Flags = CV_OUT_BASE64HEADER;
|
|
pvOut = &str;
|
|
break;
|
|
|
|
case PROPTYPE_STRING:
|
|
pvOut = &str;
|
|
break;
|
|
|
|
case PROPTYPE_DATE:
|
|
pvOut = &date;
|
|
break;
|
|
|
|
case PROPTYPE_LONG:
|
|
pvOut = &val;
|
|
break;
|
|
}
|
|
wsprintf(wszInfo, L"%ws[%u] %u", pwszPropId, PropIndex, PropType);
|
|
hr = Request2_GetFullResponseProperty(
|
|
pdiRequest,
|
|
PropId,
|
|
PropIndex,
|
|
PropType,
|
|
Flags,
|
|
pvOut);
|
|
if (CERTSRV_E_PROPERTY_EMPTY == hr)
|
|
{
|
|
wprintf(L"%ws: CERTSRV_E_PROPERTY_EMPTY\n", wszInfo);
|
|
}
|
|
_JumpIfErrorStr2(
|
|
hr,
|
|
error,
|
|
"Request2_GetFullResponseProperty",
|
|
wszInfo,
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
|
|
wprintf(L"%ws:", wszInfo);
|
|
|
|
switch (PropType)
|
|
{
|
|
case PROPTYPE_BINARY:
|
|
wprintf(L"\n%ws\n", str);
|
|
break;
|
|
|
|
case PROPTYPE_STRING:
|
|
wprintf(L" \"%ws\"\n", str);
|
|
break;
|
|
|
|
case PROPTYPE_DATE:
|
|
wprintf(L" %f\n", date);
|
|
break;
|
|
|
|
case PROPTYPE_LONG:
|
|
wprintf(L" 0x%x(%u)\n", val, val);
|
|
if (NULL != pCount)
|
|
{
|
|
*pCount = val;
|
|
}
|
|
break;
|
|
}
|
|
|
|
error:
|
|
if (NULL != str)
|
|
{
|
|
SysFreeString(str);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpIndexedProperty(
|
|
IN DISPATCHINTERFACE *pdiRequest,
|
|
IN LONG PropId,
|
|
IN WCHAR const *pwszPropId,
|
|
IN LONG PropType,
|
|
LONG Count)
|
|
{
|
|
LONG PropIndex;
|
|
|
|
for (PropIndex = 0; PropIndex < Count; PropIndex++)
|
|
{
|
|
DumpProperty(pdiRequest, PropId, pwszPropId, PropIndex, PropType, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
typedef struct _FRPROP
|
|
{
|
|
LONG PropId;
|
|
WCHAR *pwszPropId;
|
|
LONG PropType;
|
|
} FRPROP;
|
|
|
|
|
|
#define _PROPARG(pt) (pt), L#pt
|
|
|
|
FRPROP s_afrp[] =
|
|
{
|
|
{ _PROPARG(FR_PROP_BODYPARTSTRING), PROPTYPE_STRING },
|
|
{ _PROPARG(FR_PROP_STATUS), PROPTYPE_LONG },
|
|
{ _PROPARG(FR_PROP_STATUSSTRING), PROPTYPE_STRING },
|
|
{ _PROPARG(FR_PROP_OTHERINFOCHOICE), PROPTYPE_LONG },
|
|
{ _PROPARG(FR_PROP_FAILINFO), PROPTYPE_LONG },
|
|
{ _PROPARG(FR_PROP_PENDINFOTOKEN), PROPTYPE_BINARY },
|
|
{ _PROPARG(FR_PROP_PENDINFOTIME), PROPTYPE_DATE },
|
|
{ _PROPARG(FR_PROP_ISSUEDCERTIFICATEHASH), PROPTYPE_BINARY },
|
|
{ _PROPARG(FR_PROP_ENCRYPTEDKEYHASH), PROPTYPE_BINARY },
|
|
{ _PROPARG(FR_PROP_ISSUEDCERTIFICATE), PROPTYPE_BINARY },
|
|
{ _PROPARG(FR_PROP_ISSUEDCERTIFICATECHAIN), PROPTYPE_BINARY },
|
|
{ _PROPARG(FR_PROP_ISSUEDCERTIFICATECRLCHAIN), PROPTYPE_BINARY },
|
|
};
|
|
|
|
|
|
VOID
|
|
DumpFullResponseProperties(
|
|
IN DISPATCHINTERFACE *pdiRequest)
|
|
{
|
|
LONG cResponse = 0;
|
|
DWORD i;
|
|
|
|
DumpProperty(
|
|
pdiRequest,
|
|
_PROPARG(FR_PROP_FULLRESPONSE),
|
|
0,
|
|
PROPTYPE_BINARY,
|
|
NULL);
|
|
|
|
DumpProperty(
|
|
pdiRequest,
|
|
_PROPARG(FR_PROP_FULLRESPONSENOPKCS7),
|
|
0,
|
|
PROPTYPE_BINARY,
|
|
NULL);
|
|
|
|
DumpProperty(
|
|
pdiRequest,
|
|
_PROPARG(FR_PROP_STATUSINFOCOUNT),
|
|
0,
|
|
PROPTYPE_LONG,
|
|
&cResponse);
|
|
|
|
for (i = 0; i < ARRAYSIZE(s_afrp); i++)
|
|
{
|
|
DumpIndexedProperty(
|
|
pdiRequest,
|
|
s_afrp[i].PropId,
|
|
s_afrp[i].pwszPropId,
|
|
s_afrp[i].PropType,
|
|
cResponse);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SaveFullResponse(
|
|
IN HWND hWndOwner,
|
|
IN DISPATCHINTERFACE *pdiRequest,
|
|
IN WCHAR const *pwszfnFullResponse)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strFullResponse = NULL;
|
|
|
|
hr = Request2_GetFullResponseProperty(
|
|
pdiRequest,
|
|
FR_PROP_FULLRESPONSENOPKCS7,
|
|
0, // PropIndex
|
|
PROPTYPE_BINARY,
|
|
CV_OUT_BINARY,
|
|
&strFullResponse);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
_JumpIfError(hr, error, "Request2_GetFullResponseProperty");
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
hr = WriteCertificateOrRequest(
|
|
hWndOwner,
|
|
pdiRequest,
|
|
(BYTE const *) strFullResponse,
|
|
SysStringByteLen(strFullResponse),
|
|
g_dwOutFormat,
|
|
IDS_RESPONSE_OUTFILE_TITLE,
|
|
IDS_RESPONSE_FILE_FILTER,
|
|
IDS_RESPONSE_FILE_DEFEXT,
|
|
pwszfnFullResponse);
|
|
_JumpIfError(hr, error, "WriteCertificateOrRequest");
|
|
}
|
|
hr = S_OK;
|
|
goto error;
|
|
|
|
error:
|
|
if (NULL != strFullResponse)
|
|
{
|
|
SysFreeString(strFullResponse);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CallServerAndStoreCert(
|
|
IN HWND hWndOwner,
|
|
IN WCHAR const *pwszConfig,
|
|
IN DWORD RequestId,
|
|
OPTIONAL IN WCHAR const *pwszSerialNumber,
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
OPTIONAL IN WCHAR const *pwszfnReq,
|
|
OPTIONAL IN WCHAR const *pwszfnCert,
|
|
OPTIONAL IN WCHAR const *pwszfnCertChain,
|
|
OPTIONAL IN WCHAR const *pwszfnFullResponse)
|
|
{
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
BYTE *pbReq = NULL;
|
|
DWORD cbReq;
|
|
LONG dwFlags;
|
|
BOOL fSigned;
|
|
BSTR strRequest = NULL;
|
|
DISPATCHINTERFACE diRequest;
|
|
BOOL fMustRelease = FALSE;
|
|
BSTR strMessage = NULL;
|
|
WCHAR const *pwszMessage;
|
|
CERTSERVERENROLL csEnroll;
|
|
CERTSERVERENROLL *pcsEnroll = NULL;
|
|
WCHAR *pwszServer = NULL;
|
|
WCHAR *pwszAuthority = NULL;
|
|
WCHAR awchr[cwcHRESULTSTRING];
|
|
char const *pszMethod;
|
|
WCHAR *pwszMsg = NULL;
|
|
WCHAR *pwszDispMsg = NULL;
|
|
WCHAR *pwszConfigPlusSerial = NULL;
|
|
BOOL fV1 = g_fV1Interface;
|
|
|
|
// If submitting a new request:
|
|
|
|
|
|
cbReq = 0;
|
|
if (NULL != pwszfnReq)
|
|
{
|
|
// Read the request from a file, convert it to binary, and return
|
|
// dwFlags to indicate the orignal encoding and the detected format.
|
|
|
|
hr = CheckRequestType(
|
|
pwszfnReq,
|
|
&pbReq,
|
|
&cbReq,
|
|
&dwFlags,
|
|
&fSigned,
|
|
NULL, // pfCA
|
|
NULL); // ppwszTemplateName
|
|
_JumpIfError(hr, error, "CheckRequestType");
|
|
|
|
if (!fSigned || CR_IN_CERT == (CR_IN_FORMATMASK & dwFlags))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorString(pwszfnReq);
|
|
_JumpError(hr, error, "not a signed request");
|
|
}
|
|
}
|
|
|
|
pszMethod = "";
|
|
if (1 < g_fRPC)
|
|
{
|
|
hr = mySplitConfigString(pwszConfig, &pwszServer, &pwszAuthority);
|
|
_JumpIfError(hr, error, "mySplitConfigString");
|
|
|
|
if (NULL != pwszfnReq)
|
|
{
|
|
// Since CertServerSubmitRequest can only handle binary requests,
|
|
// pass the request in binary form, and set dwFlags to so indicate.
|
|
|
|
dwFlags = CR_IN_BINARY | (~CR_IN_ENCODEMASK & dwFlags);
|
|
|
|
pszMethod = "CertServerSubmitRequest";
|
|
hr = CertServerSubmitRequest(
|
|
dwFlags | g_dwCRLIn,
|
|
pbReq,
|
|
cbReq,
|
|
pwszAttributes,
|
|
pwszServer,
|
|
pwszAuthority,
|
|
&pcsEnroll);
|
|
_JumpIfError(hr, error, "CertServerSubmitRequest");
|
|
}
|
|
else
|
|
{
|
|
pszMethod = "CertServerRetrievePending";
|
|
hr = CertServerRetrievePending(
|
|
RequestId,
|
|
pwszSerialNumber,
|
|
pwszServer,
|
|
pwszAuthority,
|
|
&pcsEnroll);
|
|
_JumpIfError(hr, error, "CertServerRetrievePending");
|
|
}
|
|
CSASSERT(NULL != pcsEnroll);
|
|
pwszMessage = pcsEnroll->pwszDispositionMessage;
|
|
}
|
|
else
|
|
{
|
|
ZeroMemory(&csEnroll, sizeof(csEnroll));
|
|
|
|
hr = Request_Init(g_fIDispatch, &diRequest);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "Request_Init");
|
|
if (E_ACCESSDENIED == hr) // try for a clearer error message
|
|
{
|
|
hr = CO_E_REMOTE_COMMUNICATION_FAILURE;
|
|
}
|
|
_JumpError(hr, error, "Request_Init");
|
|
}
|
|
fMustRelease = TRUE;
|
|
|
|
if (NULL != pwszfnReq)
|
|
{
|
|
assert(NULL != pbReq && 0 != cbReq);
|
|
|
|
// We could always pass the binary ASN.1 encoded request, since
|
|
// we've already decoded it above, but in the interest of fully
|
|
// exercising the ICertRequest interface, we choose to submit the
|
|
// request in its original form.
|
|
|
|
if (CR_IN_BINARY == (CR_IN_ENCODEMASK & dwFlags))
|
|
{
|
|
// Convert the binary ASN.1 blob into a BSTR blob.
|
|
|
|
if (!ConvertWszToBstr(&strRequest, (WCHAR const *) pbReq, cbReq))
|
|
{
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_ERROR_STRCONVERSION,
|
|
&pwszMsg))
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(pwszMsg);
|
|
wprintf(g_wszNewLine);
|
|
}
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
}
|
|
else // !CR_IN_BINARY
|
|
{
|
|
// Since ICertRequest::Submit can handle any encoding type,
|
|
// re-read the ansi base64 request from the file without
|
|
// decoding it to binary, then convert the ansi base64 text
|
|
// into a Unicode base64 text BSTR.
|
|
// Free the request's binary image first.
|
|
|
|
LocalFree(pbReq);
|
|
pbReq = NULL;
|
|
|
|
hr = DecodeFileW(pwszfnReq, &pbReq, &cbReq, CRYPT_STRING_BINARY);
|
|
if (S_OK != hr)
|
|
{
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_FORMATSTR_DECODE_ERR,
|
|
&pwszMsg))
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(pwszMsg, myHResultToString(awchr, hr));
|
|
wprintf(g_wszNewLine);
|
|
}
|
|
goto error;
|
|
}
|
|
if (!ConvertSzToBstr(&strRequest, (CHAR const *) pbReq, cbReq))
|
|
{
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_ERROR_STRCONVERSION,
|
|
&pwszMsg))
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(pwszMsg);
|
|
}
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertSzToBstr");
|
|
}
|
|
}
|
|
pszMethod = "ICertRequest::Submit";
|
|
if (g_fRPC)
|
|
{
|
|
pszMethod = "ICertRequest::Submit+RPC";
|
|
dwFlags |= CR_IN_RPC;
|
|
}
|
|
if (g_fAny)
|
|
{
|
|
dwFlags = CR_IN_ENCODEANY |
|
|
CR_IN_FORMATANY |
|
|
(~(CR_IN_ENCODEMASK | CR_IN_FORMATMASK) & dwFlags);
|
|
}
|
|
hr = Request_Submit(
|
|
&diRequest,
|
|
dwFlags | g_dwCRLIn,
|
|
strRequest,
|
|
SysStringByteLen(strRequest),
|
|
pwszAttributes,
|
|
pwszConfig,
|
|
(LONG *) &csEnroll.Disposition);
|
|
}
|
|
else
|
|
{
|
|
if (!fV1)
|
|
{
|
|
pszMethod = "ICertRequest2::GetIssuedCertificate";
|
|
hr = Request2_GetIssuedCertificate(
|
|
&diRequest,
|
|
pwszConfig,
|
|
RequestId,
|
|
pwszSerialNumber,
|
|
(LONG *) &csEnroll.Disposition);
|
|
if (E_NOTIMPL == hr)
|
|
{
|
|
fV1 = TRUE;
|
|
}
|
|
}
|
|
if (fV1)
|
|
{
|
|
if (NULL != pwszSerialNumber)
|
|
{
|
|
CSASSERT(0 == RequestId);
|
|
pwszConfigPlusSerial = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(pwszConfig) +
|
|
1 +
|
|
wcslen(pwszSerialNumber) +
|
|
1) * sizeof(WCHAR));
|
|
if (NULL == pwszConfigPlusSerial)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
wcscpy(pwszConfigPlusSerial, pwszConfig);
|
|
wcscat(pwszConfigPlusSerial, L"\\");
|
|
wcscat(pwszConfigPlusSerial, pwszSerialNumber);
|
|
pwszConfig = pwszConfigPlusSerial;
|
|
}
|
|
pszMethod = "ICertRequest::RetrievePending";
|
|
hr = Request_RetrievePending(
|
|
&diRequest,
|
|
RequestId,
|
|
pwszConfig,
|
|
(LONG *) &csEnroll.Disposition);
|
|
}
|
|
}
|
|
|
|
hr2 = Request_GetLastStatus(&diRequest, &csEnroll.hrLastStatus);
|
|
if (S_OK != hr2)
|
|
{
|
|
_PrintError(hr2, "Request_GetLastStatus");
|
|
if (S_OK == hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
_JumpError(hr, error, "Request_GetLastStatus");
|
|
}
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, pszMethod);
|
|
if (E_ACCESSDENIED == hr) // try for a clearer error message
|
|
{
|
|
hr = CO_E_REMOTE_COMMUNICATION_FAILURE;
|
|
}
|
|
_JumpError(hr, error, pszMethod);
|
|
}
|
|
|
|
if (fMustRelease && !fV1)
|
|
{
|
|
if (g_fVerbose)
|
|
{
|
|
DumpFullResponseProperties(&diRequest);
|
|
}
|
|
if (NULL != pwszfnFullResponse)
|
|
{
|
|
hr = SaveFullResponse(
|
|
hWndOwner,
|
|
&diRequest,
|
|
pwszfnFullResponse);
|
|
_JumpIfError(hr, error, "SaveFullResponse");
|
|
}
|
|
}
|
|
|
|
hr = Request_GetDispositionMessage(&diRequest, &strMessage);
|
|
_JumpIfError(hr, error, "Request_GetDispositionMessage");
|
|
|
|
hr = Request_GetRequestId(&diRequest, (LONG *) &csEnroll.RequestId);
|
|
_JumpIfError(hr, error, "Request_GetRequestId");
|
|
|
|
pcsEnroll = &csEnroll;
|
|
pwszMessage = strMessage;
|
|
}
|
|
|
|
CSASSERT(NULL != pcsEnroll);
|
|
if (NULL == pwszMessage)
|
|
{
|
|
pwszMessage = L"";
|
|
}
|
|
if (0 != pcsEnroll->RequestId)
|
|
{
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_FORMATSTR_REQUESTID,
|
|
&pwszMsg))
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(pwszMsg, pcsEnroll->RequestId);
|
|
wprintf(g_wszNewLine);
|
|
LocalFree(pwszMsg);
|
|
pwszMsg = NULL;
|
|
}
|
|
}
|
|
|
|
if (CR_DISP_UNDER_SUBMISSION == pcsEnroll->Disposition)
|
|
{
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_FORMATSTR_CERTPENDING,
|
|
&pwszMsg))
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(
|
|
pwszMsg,
|
|
pwszMessage,
|
|
pcsEnroll->hrLastStatus);
|
|
wprintf(g_wszNewLine);
|
|
}
|
|
}
|
|
else if (CR_DISP_ISSUED == pcsEnroll->Disposition ||
|
|
CR_DISP_REVOKED == pcsEnroll->Disposition)
|
|
{
|
|
pwszDispMsg = wszDisposition(pcsEnroll->Disposition);
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTREQ,
|
|
"%hs(%ws) --> %ws\n",
|
|
pszMethod,
|
|
NULL != pwszDispMsg ? pwszDispMsg : L"",
|
|
pwszMessage));
|
|
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_FORMATSTR_CERTRETRIEVED,
|
|
&pwszMsg))
|
|
{
|
|
wprintf(
|
|
pwszMsg,
|
|
NULL != pwszDispMsg ? pwszDispMsg : L"",
|
|
pwszMessage);
|
|
wprintf(g_wszNewLine);
|
|
}
|
|
|
|
hr = WriteCertificateOrRequest(
|
|
hWndOwner,
|
|
&diRequest,
|
|
pcsEnroll->pbCert,
|
|
pcsEnroll->cbCert,
|
|
g_dwOutFormat,
|
|
IDS_CERT_OUTFILE_TITLE,
|
|
IDS_CERT_FILE_FILTER,
|
|
IDS_CERT_FILE_DEFEXT,
|
|
pwszfnCert);
|
|
_JumpIfError(hr, error, "WriteCertificateOrRequest");
|
|
|
|
if (NULL != pwszfnCertChain)
|
|
{
|
|
hr = WriteCertificateOrRequest(
|
|
hWndOwner,
|
|
&diRequest,
|
|
pcsEnroll->pbCertChain,
|
|
pcsEnroll->cbCertChain,
|
|
CR_OUT_CHAIN | g_dwCRLOut | g_dwOutFormat,
|
|
0,
|
|
0,
|
|
0,
|
|
pwszfnCertChain);
|
|
_JumpIfError(hr, error, "WriteCertificateOrRequest(chain)");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WCHAR const *pwszError = NULL;
|
|
|
|
if (S_OK != pcsEnroll->hrLastStatus)
|
|
{
|
|
pwszError = myGetErrorMessageText(pcsEnroll->hrLastStatus, TRUE);
|
|
}
|
|
SetErrorString(pwszMessage);
|
|
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_FORMATSTR_CERTNOTISSUED,
|
|
&pwszMsg))
|
|
{
|
|
pwszDispMsg = wszDisposition(pcsEnroll->Disposition);
|
|
|
|
wprintf(
|
|
pwszMsg,
|
|
NULL != pwszDispMsg ? pwszDispMsg : L"",
|
|
pwszMessage);
|
|
if (NULL != pwszError && NULL == wcsstr(pwszMessage, pwszError))
|
|
{
|
|
wprintf(L" %ws", pwszError);
|
|
}
|
|
wprintf(g_wszNewLine);
|
|
}
|
|
if (NULL != pwszError)
|
|
{
|
|
LocalFree(const_cast<WCHAR *>(pwszError));
|
|
}
|
|
|
|
hr = pcsEnroll->hrLastStatus;
|
|
_PrintIfError(hr, "Denied(LastStatus)");
|
|
goto error;
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszMsg)
|
|
{
|
|
LocalFree(pwszMsg);
|
|
}
|
|
if (NULL != pwszDispMsg)
|
|
{
|
|
LocalFree(pwszDispMsg);
|
|
}
|
|
if (NULL != pwszConfigPlusSerial)
|
|
{
|
|
LocalFree(pwszConfigPlusSerial);
|
|
}
|
|
if (NULL != pwszServer)
|
|
{
|
|
LocalFree(pwszServer);
|
|
}
|
|
if (NULL != pwszAuthority)
|
|
{
|
|
LocalFree(pwszAuthority);
|
|
}
|
|
if (NULL != pcsEnroll && &csEnroll != pcsEnroll)
|
|
{
|
|
CertServerFreeMemory(pcsEnroll);
|
|
}
|
|
if (NULL != strMessage)
|
|
{
|
|
SysFreeString(strMessage);
|
|
}
|
|
if (fMustRelease)
|
|
{
|
|
Request_Release(&diRequest);
|
|
}
|
|
if (NULL != strRequest)
|
|
{
|
|
SysFreeString(strRequest);
|
|
}
|
|
if (NULL != pbReq)
|
|
{
|
|
LocalFree(pbReq);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
crGetConfig(
|
|
IN OUT BSTR *pstrConfig)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR awchr[cwcHRESULTSTRING];
|
|
|
|
hr = ConfigGetConfig(g_fIDispatch, g_dwUIFlag, pstrConfig);
|
|
if (S_OK != hr)
|
|
{
|
|
WCHAR *pwszMsg = NULL;
|
|
|
|
if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
|
|
{
|
|
g_idError = IDS_NOMORE_CAS;
|
|
}
|
|
if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr)
|
|
{
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_FORMATSTR_ERRCONFIG,
|
|
&pwszMsg))
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(
|
|
pwszMsg,
|
|
myHResultToString(awchr, hr));
|
|
wprintf(g_wszNewLine);
|
|
LocalFree(pwszMsg);
|
|
}
|
|
}
|
|
goto error;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SubmitRequest(
|
|
IN HWND hWndOwner,
|
|
IN LONG RequestId,
|
|
OPTIONAL IN WCHAR const *pwszSerialNumber,
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
IN WCHAR const *pwszfnReq,
|
|
OPTIONAL IN WCHAR const *pwszfnCert,
|
|
OPTIONAL IN WCHAR const *pwszfnCertChain,
|
|
OPTIONAL IN WCHAR const *pwszfnFullResponse)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fCoInit = FALSE;
|
|
WCHAR *pwszConfig;
|
|
BSTR strConfig = NULL;
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
_JumpError(hr, error, "CoInitialize");
|
|
}
|
|
fCoInit = TRUE;
|
|
|
|
pwszConfig = g_pwszConfig;
|
|
if (NULL == pwszConfig)
|
|
{
|
|
hr = crGetConfig(&strConfig);
|
|
_JumpIfError(hr, error, "crGetConfig");
|
|
|
|
pwszConfig = strConfig;
|
|
}
|
|
|
|
// If submitting a new request:
|
|
|
|
hr = CallServerAndStoreCert(
|
|
hWndOwner,
|
|
pwszConfig,
|
|
RequestId,
|
|
pwszSerialNumber,
|
|
pwszAttributes,
|
|
pwszfnReq,
|
|
pwszfnCert,
|
|
pwszfnCertChain,
|
|
pwszfnFullResponse);
|
|
_JumpIfError(hr, error, "CallServerAndStoreCert");
|
|
|
|
error:
|
|
if (NULL != strConfig)
|
|
{
|
|
SysFreeString(strConfig);
|
|
}
|
|
if (fCoInit)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
FNMYINFGETEXTENSION *g_apfnGetExtension[] = {
|
|
myInfGetPolicyConstraintsExtension,
|
|
myInfGetPolicyMappingExtension,
|
|
myInfGetPolicyStatementExtension,
|
|
myInfGetApplicationPolicyConstraintsExtension,
|
|
myInfGetApplicationPolicyMappingExtension,
|
|
myInfGetApplicationPolicyStatementExtension,
|
|
myInfGetNameConstraintsExtension,
|
|
myInfGetEnhancedKeyUsageExtension,
|
|
myInfGetBasicConstraints2CAExtension,
|
|
myInfGetCrossCertDistributionPointsExtension,
|
|
};
|
|
#define CINFEXT ARRAYSIZE(g_apfnGetExtension)
|
|
|
|
|
|
HRESULT
|
|
DumpRequestAttributeBlobs(
|
|
IN DWORD cAttribute,
|
|
IN CRYPT_ATTR_BLOB const *paAttribute)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
CRYPT_ENROLLMENT_NAME_VALUE_PAIR *pNamePair = NULL;
|
|
DWORD cb;
|
|
|
|
if (g_fVerbose)
|
|
{
|
|
for (i = 0; i < cAttribute; i++)
|
|
{
|
|
if (NULL != paAttribute[i].pbData)
|
|
{
|
|
if (NULL != pNamePair)
|
|
{
|
|
LocalFree(pNamePair);
|
|
pNamePair = NULL;
|
|
}
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
//X509_ENROLLMENT_NAME_VALUE_PAIR,
|
|
szOID_ENROLLMENT_NAME_VALUE_PAIR,
|
|
paAttribute[i].pbData,
|
|
paAttribute[i].cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pNamePair,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
wprintf(
|
|
L"%u: %ws = %ws\n",
|
|
i,
|
|
pNamePair->pwszName,
|
|
pNamePair->pwszValue);
|
|
}
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pNamePair)
|
|
{
|
|
LocalFree(pNamePair);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeExtensions(
|
|
IN BOOL fFreeObjIds,
|
|
IN DWORD cExt,
|
|
IN OUT CERT_EXTENSION *rgExt)
|
|
{
|
|
IN DWORD i;
|
|
|
|
if (NULL != rgExt)
|
|
{
|
|
for (i = 0; i < cExt; i++)
|
|
{
|
|
if (fFreeObjIds && NULL != rgExt[i].pszObjId)
|
|
{
|
|
LocalFree(rgExt[i].pszObjId);
|
|
}
|
|
if (NULL != rgExt[i].Value.pbData)
|
|
{
|
|
LocalFree(rgExt[i].Value.pbData);
|
|
}
|
|
}
|
|
LocalFree(rgExt);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeAttributes(
|
|
IN DWORD cAttributes,
|
|
IN OUT CRYPT_ATTRIBUTES *rgAttributes)
|
|
{
|
|
DWORD i;
|
|
DWORD j;
|
|
|
|
if (NULL != rgAttributes)
|
|
{
|
|
for (i = 0; i < cAttributes; i++)
|
|
{
|
|
CRYPT_ATTRIBUTE *pAttribute = rgAttributes[i].rgAttr;
|
|
|
|
if (NULL != pAttribute)
|
|
{
|
|
if (NULL != pAttribute->rgValue)
|
|
{
|
|
for (j = 0; j < pAttribute->cValue; j++)
|
|
{
|
|
CRYPT_ATTR_BLOB *pValue = &pAttribute->rgValue[j];
|
|
|
|
if (NULL != pValue->pbData)
|
|
{
|
|
LocalFree(pValue->pbData);
|
|
}
|
|
}
|
|
LocalFree(pAttribute->rgValue);
|
|
}
|
|
LocalFree(pAttribute);
|
|
}
|
|
}
|
|
LocalFree(rgAttributes);
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ParseInfFile(
|
|
IN WCHAR const *pwszfnPolicy,
|
|
OPTIONAL OUT INFVALUES **prgInfValues,
|
|
OPTIONAL OUT DWORD *pcInfValues,
|
|
OUT CRYPT_ATTR_BLOB **ppaAttribute,
|
|
OUT DWORD *pcAttribute,
|
|
OUT CERT_EXTENSION **ppExt,
|
|
OUT DWORD *pcExt,
|
|
OUT WCHAR **ppwszTemplateNameInf)
|
|
{
|
|
HRESULT hr;
|
|
HINF hInf = INVALID_HANDLE_VALUE;
|
|
DWORD ErrorLine;
|
|
DWORD i;
|
|
INFVALUES *rgInfValues = NULL;
|
|
DWORD cInfValues;
|
|
DWORD cExt = 0;
|
|
DWORD cAttribute = 0;
|
|
CRYPT_ATTR_BLOB *paAttribute = NULL;
|
|
CERT_EXTENSION aext[CINFEXT];
|
|
FNMYINFGETEXTENSION **ppfnGetExtension;
|
|
CERT_EXTENSION *rgExt = NULL;
|
|
DWORD cExtInf = 0;
|
|
CERT_EXTENSION *rgExtInf = NULL;
|
|
WCHAR *pwszInfError = NULL;
|
|
WCHAR *pwszzSectionNames;
|
|
|
|
if (NULL != prgInfValues)
|
|
{
|
|
*prgInfValues = NULL;
|
|
}
|
|
if (NULL != pcInfValues)
|
|
{
|
|
*pcInfValues = 0;
|
|
}
|
|
*ppaAttribute = NULL;
|
|
*pcAttribute = 0;
|
|
*ppExt = NULL;
|
|
*pcExt = 0;
|
|
*ppwszTemplateNameInf = NULL;
|
|
cInfValues = 0;
|
|
|
|
ZeroMemory(aext, sizeof(aext));
|
|
|
|
hr = myInfOpenFile(pwszfnPolicy, &hInf, &ErrorLine);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnPolicy);
|
|
_JumpError(hr, error, "myInfOpenFile");
|
|
}
|
|
|
|
if (NULL != prgInfValues && NULL != pcInfValues)
|
|
{
|
|
hr = myInfGetSectionValues(
|
|
hInf,
|
|
wszINFSECTION_NEWREQUEST,
|
|
&cInfValues,
|
|
&rgInfValues);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnPolicy);
|
|
_JumpError(hr, error, "myInfGetSectionValues");
|
|
}
|
|
}
|
|
for (ppfnGetExtension = g_apfnGetExtension;
|
|
ppfnGetExtension < &g_apfnGetExtension[CINFEXT];
|
|
ppfnGetExtension++)
|
|
{
|
|
hr = (**ppfnGetExtension)(hInf, &aext[cExt]);
|
|
CSASSERT((NULL == aext[cExt].Value.pbData) ^ (S_OK == hr));
|
|
if (S_OK != hr)
|
|
{
|
|
char achIndex[64];
|
|
|
|
if (NULL != pwszInfError)
|
|
{
|
|
LocalFree(pwszInfError);
|
|
pwszInfError = NULL;
|
|
}
|
|
sprintf(
|
|
achIndex,
|
|
"*ppfnGetExtension[%u]",
|
|
SAFE_SUBTRACT_POINTERS(ppfnGetExtension, g_apfnGetExtension));
|
|
|
|
pwszInfError = myInfGetError();
|
|
if (S_FALSE == hr || (HRESULT) ERROR_LINE_NOT_FOUND == hr)
|
|
{
|
|
//_PrintErrorStr2(hr, achIndex, pwszInfError, S_FALSE);
|
|
continue;
|
|
}
|
|
_JumpIfErrorStr(hr, error, achIndex, pwszInfError);
|
|
}
|
|
cExt++;
|
|
}
|
|
|
|
hr = myInfGetExtensions(hInf, &cExtInf, &rgExtInf);
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr && S_FALSE != hr)
|
|
{
|
|
_JumpIfError(hr, error, "myInfGetExtensions");
|
|
}
|
|
|
|
hr = myInfGetRequestAttributes(
|
|
hInf,
|
|
&cAttribute,
|
|
&paAttribute,
|
|
ppwszTemplateNameInf);
|
|
if ((HRESULT) ERROR_LINE_NOT_FOUND != hr && S_FALSE != hr)
|
|
{
|
|
_JumpIfError(hr, error, "myInfGetRequestAttributes");
|
|
}
|
|
|
|
DumpRequestAttributeBlobs(cAttribute, paAttribute);
|
|
|
|
hr = myInfGetUnreferencedSectionNames(&pwszzSectionNames);
|
|
_JumpIfError(hr, error, "myInfGetUnreferencedSectionNames");
|
|
|
|
if (NULL != pwszzSectionNames)
|
|
{
|
|
WCHAR *pwsz;
|
|
|
|
pwsz = pwszzSectionNames;
|
|
while (L'\0' != *pwsz)
|
|
{
|
|
pwsz += wcslen(pwsz);
|
|
*pwsz++ = L'\n';
|
|
}
|
|
g_pwszUnreferencedSectionNames = pwszzSectionNames;
|
|
}
|
|
|
|
if (0 != cExt + cExtInf)
|
|
{
|
|
rgExt = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
(cExt + cExtInf) * sizeof(**ppExt));
|
|
if (NULL == rgExt)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
if (0 != cExt)
|
|
{
|
|
CopyMemory(&rgExt[0], &aext[0], cExt * sizeof(rgExt[0]));
|
|
for (i = 0; i < cExt; i++)
|
|
{
|
|
rgExt[i].pszObjId = NULL;
|
|
}
|
|
for (i = 0; i < cExt; i++)
|
|
{
|
|
hr = myDupStringA(aext[i].pszObjId, &rgExt[i].pszObjId);
|
|
_JumpIfError(hr, error, "myDupStringA");
|
|
}
|
|
}
|
|
if (0 != cExtInf)
|
|
{
|
|
CopyMemory(&rgExt[cExt], rgExtInf, cExtInf * sizeof(rgExtInf[0]));
|
|
ZeroMemory(rgExtInf, cExtInf * sizeof(rgExtInf[0]));
|
|
}
|
|
if (g_fVerbose)
|
|
{
|
|
for (i = 0; i < cExt + cExtInf; i++)
|
|
{
|
|
WCHAR *pwszCritMsg = NULL;
|
|
|
|
myLoadRCString(
|
|
g_hInstance,
|
|
rgExt[i].fCritical? IDS_CRITICAL : IDS_NON_CRITICAL,
|
|
&pwszCritMsg);
|
|
wprintf(
|
|
L"%u: %hs(%ws) %ws cb=%x\n",
|
|
i,
|
|
rgExt[i].pszObjId,
|
|
myGetOIDNameA(rgExt[i].pszObjId),
|
|
pwszCritMsg,
|
|
rgExt[i].Value.cbData);
|
|
if (NULL != pwszCritMsg)
|
|
{
|
|
LocalFree(pwszCritMsg);
|
|
}
|
|
}
|
|
}
|
|
*pcExt = cExt + cExtInf;
|
|
*ppExt = rgExt;
|
|
rgExt = NULL;
|
|
}
|
|
if (NULL != prgInfValues && NULL != pcInfValues)
|
|
{
|
|
*prgInfValues = rgInfValues;
|
|
rgInfValues = NULL;
|
|
*pcInfValues = cInfValues;
|
|
}
|
|
*ppaAttribute = paAttribute;
|
|
*pcAttribute = cAttribute;
|
|
paAttribute = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != rgInfValues)
|
|
{
|
|
myInfFreeSectionValues(cInfValues, rgInfValues);
|
|
}
|
|
if (NULL != pwszInfError)
|
|
{
|
|
LocalFree(pwszInfError);
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
for (i = 0; i < ARRAYSIZE(aext); i++)
|
|
{
|
|
if (NULL != aext[i].Value.pbData)
|
|
{
|
|
LocalFree(aext[i].Value.pbData);
|
|
}
|
|
}
|
|
if (NULL != *ppwszTemplateNameInf)
|
|
{
|
|
LocalFree(*ppwszTemplateNameInf);
|
|
*ppwszTemplateNameInf = NULL;
|
|
}
|
|
if (NULL != rgExt)
|
|
{
|
|
FreeExtensions(TRUE, cExt, rgExt);
|
|
}
|
|
}
|
|
myInfFreeExtensions(cExtInf, rgExtInf);
|
|
if (NULL != paAttribute)
|
|
{
|
|
myInfFreeRequestAttributes(cAttribute, paAttribute);
|
|
}
|
|
if (INVALID_HANDLE_VALUE != hInf)
|
|
{
|
|
g_pwszInfErrorString = myInfGetError();
|
|
myInfCloseFile(hInf);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DeleteMsgCerts(
|
|
IN HCRYPTMSG hMsg)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pCert = NULL;
|
|
BYTE *pbCert = NULL;
|
|
|
|
CSASSERT(NULL == pCert);
|
|
for (;;)
|
|
{
|
|
BOOL fFirst = FALSE;
|
|
DWORD cCert;
|
|
DWORD cb;
|
|
DWORD i;
|
|
|
|
cb = sizeof(cCert);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CERT_COUNT_PARAM,
|
|
0,
|
|
&cCert,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgGetParam(Cert count)");
|
|
}
|
|
for (i = 0; i < cCert; i++)
|
|
{
|
|
CSASSERT(NULL == pbCert);
|
|
hr = myCryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CERT_PARAM,
|
|
i,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pbCert,
|
|
&cb);
|
|
_JumpIfError(hr, error, "myCryptMsgGetParam");
|
|
|
|
CSASSERT(NULL == pCert);
|
|
pCert = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
pbCert,
|
|
cb);
|
|
if (NULL == pCert)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
|
|
hr = myIsFirstSigner(&pCert->pCertInfo->Subject, &fFirst);
|
|
_JumpIfError(hr, error, "myIsFirstSigner");
|
|
|
|
LocalFree(pbCert);
|
|
pbCert = NULL;
|
|
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
|
|
if (!fFirst)
|
|
{
|
|
DWORD j = i;
|
|
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_DEL_CERT,
|
|
&j))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgControl(delCert)");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (i == cCert)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pbCert)
|
|
{
|
|
LocalFree(pbCert);
|
|
}
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DeleteMsgCRLs(
|
|
IN HCRYPTMSG hMsg)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cCRLPrev;
|
|
|
|
for (cCRLPrev = MAXDWORD; ; )
|
|
{
|
|
DWORD cCRL;
|
|
DWORD cb;
|
|
DWORD i;
|
|
|
|
cb = sizeof(cCRL);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CRL_COUNT_PARAM,
|
|
0,
|
|
&cCRL,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgGetParam(CRL count)");
|
|
}
|
|
if (0 == cCRL)
|
|
{
|
|
break; // we're done
|
|
}
|
|
i = 0; // delete the first CRL
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_DEL_CRL,
|
|
&i))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgControl(delCRL)");
|
|
}
|
|
if (cCRL >= cCRLPrev)
|
|
{
|
|
break; // give up after one retry
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddMsgCert(
|
|
IN HCRYPTMSG hMsg,
|
|
IN HCERTSTORE hStore,
|
|
IN CERT_CONTEXT const *pCertAdd)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pCert = NULL;
|
|
|
|
for (;;)
|
|
{
|
|
pCert = CertEnumCertificatesInStore(hStore, pCert);
|
|
if (NULL == pCert)
|
|
{
|
|
break;
|
|
}
|
|
if (pCertAdd->cbCertEncoded == pCert->cbCertEncoded &&
|
|
0 == memcmp(
|
|
pCertAdd->pbCertEncoded,
|
|
pCert->pbCertEncoded,
|
|
pCert->cbCertEncoded))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (NULL == pCert)
|
|
{
|
|
CERT_BLOB Blob;
|
|
|
|
Blob.pbData = pCertAdd->pbCertEncoded;
|
|
Blob.cbData = pCertAdd->cbCertEncoded;
|
|
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_ADD_CERT,
|
|
&Blob))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgControl(addCert)");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddMsgCRL(
|
|
IN HCRYPTMSG hMsg,
|
|
IN HCERTSTORE hStore,
|
|
IN CRL_CONTEXT const *pCRLAdd)
|
|
{
|
|
HRESULT hr;
|
|
CRL_CONTEXT const *pCRL = NULL;
|
|
|
|
for (;;)
|
|
{
|
|
pCRL = CertEnumCRLsInStore(hStore, pCRL);
|
|
if (NULL == pCRL)
|
|
{
|
|
break;
|
|
}
|
|
if (pCRLAdd->cbCrlEncoded == pCRL->cbCrlEncoded &&
|
|
0 == memcmp(
|
|
pCRLAdd->pbCrlEncoded,
|
|
pCRL->pbCrlEncoded,
|
|
pCRL->cbCrlEncoded))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (NULL == pCRL)
|
|
{
|
|
CERT_BLOB Blob;
|
|
|
|
Blob.pbData = pCRLAdd->pbCrlEncoded;
|
|
Blob.cbData = pCRLAdd->cbCrlEncoded;
|
|
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_ADD_CRL,
|
|
&Blob))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgControl(addCRL)");
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pCRL)
|
|
{
|
|
CertFreeCRLContext(pCRL);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddMsgCertsAndCRLs(
|
|
IN HCRYPTMSG hMsg,
|
|
IN HCERTSTORE hStore,
|
|
IN CERT_CHAIN_CONTEXT const *pChainContext,
|
|
IN BOOL fIncludeCRLs)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cElement;
|
|
CERT_CHAIN_ELEMENT **ppElement;
|
|
DWORD i;
|
|
|
|
CSASSERT(NULL != pChainContext);
|
|
if (NULL == pChainContext ||
|
|
0 == pChainContext->cChain ||
|
|
0 == pChainContext->rgpChain[0]->cElement)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "no chain");
|
|
}
|
|
cElement = pChainContext->rgpChain[0]->cElement;
|
|
ppElement = pChainContext->rgpChain[0]->rgpElement;
|
|
|
|
for (i = 0; i < cElement; ppElement++, i++)
|
|
{
|
|
hr = AddMsgCert(hMsg, hStore, (*ppElement)->pCertContext);
|
|
_JumpIfError(hr, error, "AddMsgCert");
|
|
|
|
if (fIncludeCRLs)
|
|
{
|
|
CERT_REVOCATION_INFO *pRevocationInfo;
|
|
|
|
pRevocationInfo = (*ppElement)->pRevocationInfo;
|
|
|
|
if (NULL != pRevocationInfo &&
|
|
CCSIZEOF_STRUCT(CERT_REVOCATION_INFO, pCrlInfo) <=
|
|
pRevocationInfo->cbSize &&
|
|
NULL != pRevocationInfo->pCrlInfo)
|
|
{
|
|
CERT_REVOCATION_CRL_INFO *pCrlInfo;
|
|
|
|
pCrlInfo = pRevocationInfo->pCrlInfo;
|
|
if (NULL != pCrlInfo)
|
|
{
|
|
if (NULL != pCrlInfo->pBaseCrlContext)
|
|
{
|
|
hr = AddMsgCRL(
|
|
hMsg,
|
|
hStore,
|
|
pCrlInfo->pBaseCrlContext);
|
|
_JumpIfError(hr, error, "AddMsgCRL");
|
|
}
|
|
if (NULL != pCrlInfo->pDeltaCrlContext)
|
|
{
|
|
hr = AddMsgCRL(
|
|
hMsg,
|
|
hStore,
|
|
pCrlInfo->pDeltaCrlContext);
|
|
_JumpIfError(hr, error, "AddMsgCRL");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddOrDeleteMsgCertsAndCRLs(
|
|
IN BYTE const *pbPKCS7,
|
|
IN DWORD cbPKCS7,
|
|
IN HCRYPTMSG hMsg,
|
|
IN BOOL fDelete, // else add Certs and CRLs
|
|
OPTIONAL IN CERT_CHAIN_CONTEXT const *pChainContext,
|
|
IN BOOL fIncludeCRLs)
|
|
{
|
|
HRESULT hr;
|
|
CRYPT_DATA_BLOB blobPKCS7;
|
|
HCERTSTORE hStore = NULL;
|
|
|
|
blobPKCS7.pbData = const_cast<BYTE *>(pbPKCS7);
|
|
blobPKCS7.cbData = cbPKCS7;
|
|
|
|
hStore = CertOpenStore(
|
|
CERT_STORE_PROV_PKCS7,
|
|
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
|
NULL, // hCryptProv
|
|
0, // dwFlags
|
|
&blobPKCS7);
|
|
if (NULL == hStore)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertOpenStore");
|
|
}
|
|
|
|
if (fDelete)
|
|
{
|
|
CSASSERT(NULL == pChainContext);
|
|
|
|
hr = DeleteMsgCerts(hMsg);
|
|
_JumpIfError(hr, error, "DeleteMsgCerts");
|
|
|
|
hr = DeleteMsgCRLs(hMsg);
|
|
_JumpIfError(hr, error, "DeleteMsgCRLs");
|
|
}
|
|
else
|
|
{
|
|
CSASSERT(NULL != pChainContext);
|
|
|
|
hr = AddMsgCertsAndCRLs(hMsg, hStore, pChainContext, fIncludeCRLs);
|
|
_JumpIfError(hr, error, "AddMsgCertsAndCRLs");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hStore)
|
|
{
|
|
CertCloseStore(hStore, 0);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SignCMCContent(
|
|
OPTIONAL IN CERT_CONTEXT const *pCertSigner,
|
|
IN char const *pszInnerContentObjId,
|
|
IN BYTE const *pbPKCS7Old,
|
|
IN DWORD cbPKCS7Old,
|
|
IN BOOL fIncludeCRLs,
|
|
OUT BYTE **ppbPKCS7New,
|
|
OUT DWORD *pcbPKCS7New)
|
|
{
|
|
HRESULT hr;
|
|
HCRYPTPROV hProv = NULL;
|
|
DWORD dwKeySpec;
|
|
BOOL fCallerFreeProv;
|
|
DWORD cb;
|
|
HCRYPTMSG hMsg = NULL;
|
|
CMSG_SIGNER_ENCODE_INFO SignerEncodeInfo;
|
|
CRYPT_ATTRIBUTE AttributeRequestClient;
|
|
CRYPT_ATTR_BLOB BlobRequestClient;
|
|
CERT_BLOB SignerCertBlob;
|
|
DWORD cSigner;
|
|
DWORD i;
|
|
CERT_CONTEXT const *pCert = NULL;
|
|
CERT_CHAIN_CONTEXT const *pChainContext = NULL;
|
|
DWORD iElement;
|
|
CMSG_CMS_SIGNER_INFO *pcsi = NULL;
|
|
DWORD cFirstSigner;
|
|
BOOL fFirst;
|
|
CERT_REQUEST_INFO *pRequest = NULL;
|
|
|
|
BlobRequestClient.pbData = NULL;
|
|
fCallerFreeProv = FALSE;
|
|
|
|
// decode existing PKCS 7 wrapper, and add or delete signatures
|
|
|
|
hMsg = CryptMsgOpenToDecode(
|
|
PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
|
|
0, // dwFlags
|
|
0, // dwMsgType
|
|
//CMSG_SIGNED,
|
|
NULL, // hCryptProv
|
|
NULL, // pRecipientInfo
|
|
NULL); // pStreamInfo
|
|
if (NULL == hMsg)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgOpenToDecode");
|
|
}
|
|
|
|
// Update the message with the old PKCS 7 signed message
|
|
|
|
if (!CryptMsgUpdate(hMsg, pbPKCS7Old, cbPKCS7Old, TRUE))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgUpdate");
|
|
}
|
|
|
|
cb = sizeof(cSigner);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_SIGNER_COUNT_PARAM,
|
|
0,
|
|
&cSigner,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgGetParam(signer count)");
|
|
}
|
|
|
|
cFirstSigner = 0;
|
|
if (NULL != pCertSigner)
|
|
{
|
|
CERT_CHAIN_PARA ChainParams;
|
|
|
|
ZeroMemory(&SignerEncodeInfo, sizeof(SignerEncodeInfo));
|
|
SignerEncodeInfo.cbSize = sizeof(SignerEncodeInfo);
|
|
|
|
hr = myEncodeRequestClientAttributeFromClientId(
|
|
XECI_CERTREQ,
|
|
&BlobRequestClient.pbData,
|
|
&BlobRequestClient.cbData);
|
|
_JumpIfError(hr, error, "myEncodeRequestClientAttributeFromClientId");
|
|
|
|
AttributeRequestClient.pszObjId = szOID_REQUEST_CLIENT_INFO;
|
|
AttributeRequestClient.cValue = 1;
|
|
AttributeRequestClient.rgValue = &BlobRequestClient;
|
|
|
|
// Search for and load the cryptographic provider and private key.
|
|
|
|
hr = myLoadPrivateKey(
|
|
&pCertSigner->pCertInfo->SubjectPublicKeyInfo,
|
|
CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_MYSTORE | CUCS_ARCHIVED,
|
|
&hProv,
|
|
&dwKeySpec,
|
|
&fCallerFreeProv);
|
|
_JumpIfError(hr, error, "myLoadPrivateKey");
|
|
|
|
// Get the cert chain
|
|
|
|
ZeroMemory(&ChainParams, sizeof(ChainParams));
|
|
ChainParams.cbSize = sizeof(ChainParams);
|
|
ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
|
|
//ChainParams.RequestedUsage.Usage.cUsageIdentifier = 0;
|
|
//ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = NULL;
|
|
|
|
if (!CertGetCertificateChain(
|
|
NULL, // hChainEngine
|
|
pCertSigner, // pCertContext
|
|
NULL, // pTime
|
|
NULL, // hAdditionalStore
|
|
&ChainParams, // pChainPara
|
|
CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,
|
|
NULL, // pvReserved
|
|
&pChainContext)) // ppChainContext
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertGetCertificateChain");
|
|
}
|
|
|
|
// Initialize the CMSG_SIGNER_ENCODE_INFO structure.
|
|
// Note: handles only a single signer.
|
|
|
|
SignerCertBlob.cbData = pCertSigner->cbCertEncoded;
|
|
SignerCertBlob.pbData = pCertSigner->pbCertEncoded;
|
|
SignerEncodeInfo.pCertInfo = pCertSigner->pCertInfo;
|
|
|
|
SignerEncodeInfo.hCryptProv = hProv;
|
|
SignerEncodeInfo.dwKeySpec = dwKeySpec;
|
|
SignerEncodeInfo.HashAlgorithm.pszObjId = const_cast<CHAR *>(g_pszObjIdHash);
|
|
//SignerEncodeInfo.pvHashAuxInfo = NULL;
|
|
SignerEncodeInfo.cAuthAttr = 1;
|
|
SignerEncodeInfo.rgAuthAttr = &AttributeRequestClient;
|
|
|
|
// fail if any existing signing cert matches the new signing cert.
|
|
|
|
for (i = 0; i < cSigner; i++)
|
|
{
|
|
if (NULL != pcsi)
|
|
{
|
|
LocalFree(pcsi);
|
|
pcsi = NULL;
|
|
}
|
|
hr = myCryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CMS_SIGNER_INFO_PARAM,
|
|
i,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pcsi,
|
|
&cb);
|
|
_JumpIfError(hr, error, "myCryptMsgGetParam");
|
|
|
|
if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice ||
|
|
(NULL != pcsi->HashEncryptionAlgorithm.pszObjId &&
|
|
0 == strcmp(
|
|
szOID_PKIX_NO_SIGNATURE,
|
|
pcsi->HashEncryptionAlgorithm.pszObjId)))
|
|
{
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA cvse;
|
|
|
|
ZeroMemory(&cvse, sizeof(cvse));
|
|
cvse.cbSize = sizeof(cvse);
|
|
cvse.dwSignerIndex = i;
|
|
|
|
if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice)
|
|
{
|
|
if (NULL == pRequest)
|
|
{
|
|
hr = myGetInnerPKCS10(
|
|
hMsg,
|
|
pszInnerContentObjId,
|
|
&pRequest);
|
|
_JumpIfError(hr, error, "myGetInnerPKCS10");
|
|
}
|
|
cvse.dwSignerType = CMSG_VERIFY_SIGNER_PUBKEY;
|
|
cvse.pvSigner = &pRequest->SubjectPublicKeyInfo;
|
|
}
|
|
else
|
|
{
|
|
cvse.dwSignerType = CMSG_VERIFY_SIGNER_NULL;
|
|
}
|
|
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_VERIFY_SIGNATURE_EX,
|
|
&cvse))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgControl(VerifySig)");
|
|
}
|
|
cFirstSigner++;
|
|
}
|
|
else
|
|
{
|
|
iElement = i;
|
|
|
|
if (!CryptMsgGetAndVerifySigner(
|
|
hMsg,
|
|
0, // cSignerStore
|
|
NULL, // rghSignerStore
|
|
CMSG_USE_SIGNER_INDEX_FLAG,
|
|
&pCert,
|
|
&iElement))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgGetAndVerifySigner");
|
|
}
|
|
if (pCertSigner->cbCertEncoded == pCert->cbCertEncoded &&
|
|
0 == memcmp(
|
|
pCertSigner->pbCertEncoded,
|
|
pCert->pbCertEncoded,
|
|
pCert->cbCertEncoded))
|
|
{
|
|
hr = CRYPT_E_EXISTS;
|
|
_JumpError(hr, error, "duplicate signing cert");
|
|
}
|
|
hr = myIsFirstSigner(&pCert->pCertInfo->Subject, &fFirst);
|
|
_JumpIfError(hr, error, "myIsFirstSigner");
|
|
|
|
if (fFirst)
|
|
{
|
|
cFirstSigner++;
|
|
}
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
}
|
|
}
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_ADD_SIGNER,
|
|
&SignerEncodeInfo))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgControl(addSigner)");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// delete all existing signers -- except the first signer
|
|
|
|
for (;;)
|
|
{
|
|
BOOL fDeleteSigner = FALSE;
|
|
|
|
for (i = 0; i < cSigner; i++)
|
|
{
|
|
if (NULL != pcsi)
|
|
{
|
|
LocalFree(pcsi);
|
|
pcsi = NULL;
|
|
}
|
|
hr = myCryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_CMS_SIGNER_INFO_PARAM,
|
|
i,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pcsi,
|
|
&cb);
|
|
_JumpIfError(hr, error, "myCryptMsgGetParam");
|
|
|
|
if (CERT_ID_KEY_IDENTIFIER == pcsi->SignerId.dwIdChoice ||
|
|
(NULL != pcsi->HashEncryptionAlgorithm.pszObjId &&
|
|
0 == strcmp(
|
|
szOID_PKIX_NO_SIGNATURE,
|
|
pcsi->HashEncryptionAlgorithm.pszObjId)))
|
|
{
|
|
cFirstSigner++;
|
|
continue;
|
|
}
|
|
iElement = i;
|
|
|
|
if (!CryptMsgGetAndVerifySigner(
|
|
hMsg,
|
|
0, // cSignerStore
|
|
NULL, // rghSignerStore
|
|
CMSG_USE_SIGNER_INDEX_FLAG |
|
|
CMSG_SIGNER_ONLY_FLAG,
|
|
&pCert,
|
|
&iElement))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgGetAndVerifySigner");
|
|
}
|
|
|
|
hr = myIsFirstSigner(&pCert->pCertInfo->Subject, &fFirst);
|
|
_JumpIfError(hr, error, "myIsFirstSigner");
|
|
|
|
CertFreeCertificateContext(pCert);
|
|
pCert = NULL;
|
|
|
|
if (!fFirst)
|
|
{
|
|
fDeleteSigner = TRUE;
|
|
break;
|
|
}
|
|
cFirstSigner++;
|
|
}
|
|
if (!fDeleteSigner)
|
|
{
|
|
break;
|
|
}
|
|
if (!CryptMsgControl(
|
|
hMsg,
|
|
0, // dwFlags
|
|
CMSG_CTRL_DEL_SIGNER,
|
|
&iElement))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgControl(delSigner)");
|
|
}
|
|
cb = sizeof(cSigner);
|
|
if (!CryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_SIGNER_COUNT_PARAM,
|
|
0,
|
|
&cSigner,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptMsgGetParam(signer count)");
|
|
}
|
|
}
|
|
}
|
|
if (1 != cFirstSigner)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "cFirstSigner");
|
|
}
|
|
|
|
// Add or delete signing cert chain certs and CRLs in the message.
|
|
|
|
hr = AddOrDeleteMsgCertsAndCRLs(
|
|
pbPKCS7Old,
|
|
cbPKCS7Old,
|
|
hMsg,
|
|
NULL == pChainContext, // fDelete
|
|
pChainContext,
|
|
fIncludeCRLs);
|
|
_JumpIfError(hr, error, "AddOrDeleteMsgCertsAndCRLs");
|
|
|
|
// Get the signed message. Force reencoding with the changed signatures.
|
|
|
|
hr = myCryptMsgGetParam(
|
|
hMsg,
|
|
CMSG_ENCODED_MESSAGE,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) ppbPKCS7New,
|
|
pcbPKCS7New);
|
|
_JumpIfError(hr, error, "myCryptMsgGetParam");
|
|
|
|
error:
|
|
if (NULL != pRequest)
|
|
{
|
|
LocalFree(pRequest);
|
|
}
|
|
if (NULL != pcsi)
|
|
{
|
|
LocalFree(pcsi);
|
|
}
|
|
if (NULL != BlobRequestClient.pbData)
|
|
{
|
|
LocalFree(BlobRequestClient.pbData);
|
|
}
|
|
if (NULL != pChainContext)
|
|
{
|
|
CertFreeCertificateChain(pChainContext);
|
|
}
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
if (NULL != hMsg)
|
|
{
|
|
CryptMsgClose(hMsg);
|
|
}
|
|
if (NULL != hProv && fCallerFreeProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsCATemplate(
|
|
IN WCHAR const *pwszExtensionName)
|
|
{
|
|
BOOL fCA;
|
|
DWORD i;
|
|
|
|
static WCHAR const * const s_apwszCATemplate[] = {
|
|
wszCERTTYPE_CA,
|
|
wszCERTTYPE_SUBORDINATE_CA,
|
|
wszCERTTYPE_CROSS_CA,
|
|
};
|
|
|
|
fCA = FALSE;
|
|
for (i = 0; i < ARRAYSIZE(s_apwszCATemplate); i++)
|
|
{
|
|
if (0 == mylstrcmpiL(pwszExtensionName, s_apwszCATemplate[i]))
|
|
{
|
|
fCA = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return(fCA);
|
|
}
|
|
|
|
|
|
// AddCAExtensions -- add Basic Constraints & KeyUsage extensions if missing
|
|
|
|
HRESULT
|
|
AddCAExtensions(
|
|
IN OUT CERT_EXTENSION **prgExt,
|
|
IN OUT DWORD *pcExt)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cExt;
|
|
|
|
BOOL fAddBasicConstraints = TRUE;
|
|
BOOL fAddKeyUsage = TRUE;
|
|
|
|
if (NULL != *prgExt)
|
|
{
|
|
cExt = *pcExt;
|
|
if (NULL != CertFindExtension(
|
|
szOID_BASIC_CONSTRAINTS2,
|
|
cExt,
|
|
*prgExt))
|
|
{
|
|
fAddBasicConstraints = FALSE;
|
|
}
|
|
if (NULL == CertFindExtension(szOID_KEY_USAGE, cExt, *prgExt))
|
|
{
|
|
fAddKeyUsage = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*pcExt = 0;
|
|
cExt = *pcExt;
|
|
}
|
|
|
|
if (fAddBasicConstraints || fAddKeyUsage)
|
|
{
|
|
CERT_EXTENSION *rgExt;
|
|
CERT_EXTENSION *pExt;
|
|
if (fAddBasicConstraints)
|
|
{
|
|
cExt++;
|
|
}
|
|
if (fAddKeyUsage)
|
|
{
|
|
cExt++;
|
|
}
|
|
rgExt = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(rgExt[0]) * cExt);
|
|
if (NULL == rgExt)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
if (NULL != *prgExt)
|
|
{
|
|
CopyMemory(rgExt, *prgExt, *pcExt * sizeof(rgExt[0]));
|
|
LocalFree(*prgExt);
|
|
}
|
|
*prgExt = rgExt;
|
|
|
|
pExt = &rgExt[*pcExt];
|
|
if (fAddBasicConstraints)
|
|
{
|
|
CERT_BASIC_CONSTRAINTS2_INFO Constraints;
|
|
|
|
Constraints.fCA = TRUE;
|
|
Constraints.fPathLenConstraint = FALSE;
|
|
Constraints.dwPathLenConstraint = 0;
|
|
|
|
(*pcExt)++; // increment now to free memory on error
|
|
|
|
hr = myDupStringA(szOID_BASIC_CONSTRAINTS2, &pExt->pszObjId);
|
|
_JumpIfError(hr, error, "myDupStringA");
|
|
|
|
pExt->fCritical = TRUE;
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_BASIC_CONSTRAINTS2,
|
|
&Constraints,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pExt->Value.pbData,
|
|
&pExt->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
pExt++;
|
|
}
|
|
if (fAddKeyUsage)
|
|
{
|
|
CRYPT_BIT_BLOB KeyUsage;
|
|
BYTE bKeyUsage = myCASIGN_KEY_USAGE;
|
|
|
|
KeyUsage.cbData = sizeof(bKeyUsage);
|
|
KeyUsage.pbData = &bKeyUsage;
|
|
KeyUsage.cUnusedBits = 0;
|
|
|
|
(*pcExt)++; // increment now to free memory on error
|
|
|
|
hr = myDupStringA(szOID_KEY_USAGE, &pExt->pszObjId);
|
|
_JumpIfError(hr, error, "myDupStringA");
|
|
|
|
pExt->fCritical = FALSE;
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_KEY_USAGE,
|
|
&KeyUsage,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pExt->Value.pbData,
|
|
&pExt->Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
pExt++;
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
MergeAndEncodeExtensions(
|
|
IN BOOL fCA,
|
|
OPTIONAL IN CERT_EXTENSION *rgExtInf,
|
|
IN DWORD cExtInf,
|
|
OPTIONAL IN CERT_EXTENSION *rgExtReq,
|
|
IN DWORD cExtReq,
|
|
OUT BYTE **ppbOut,
|
|
OUT DWORD *pcbOut)
|
|
{
|
|
HRESULT hr;
|
|
CERT_EXTENSIONS Extensions;
|
|
CERT_EXTENSION *rgExtCA = NULL;
|
|
DWORD cExtCA;
|
|
CERT_EXTENSION *rgrgExt[3];
|
|
DWORD rgcExt[3];
|
|
DWORD cExt;
|
|
DWORD i;
|
|
|
|
Extensions.rgExtension = NULL;
|
|
*ppbOut = NULL;
|
|
cExtCA = 0;
|
|
|
|
if (fCA)
|
|
{
|
|
hr = AddCAExtensions(&rgExtCA, &cExtCA);
|
|
_JumpIfError(hr, error, "AddCAExtensions");
|
|
}
|
|
|
|
ZeroMemory(rgrgExt, sizeof(rgrgExt));
|
|
ZeroMemory(rgcExt, sizeof(rgcExt));
|
|
cExt = 0;
|
|
if (NULL != rgExtInf) // INF & template extensions take precedence
|
|
{
|
|
rgrgExt[0] = rgExtInf;
|
|
rgcExt[0] = cExtInf;
|
|
cExt += cExtInf;
|
|
}
|
|
if (NULL != rgExtReq) // Then come Cert & other request extensions
|
|
{
|
|
rgrgExt[1] = rgExtReq;
|
|
rgcExt[1] = cExtReq;
|
|
cExt += cExtReq;
|
|
}
|
|
if (NULL != rgExtCA) // Added CA extensions are lowest priority
|
|
{
|
|
rgrgExt[2] = rgExtCA;
|
|
rgcExt[2] = cExtCA;
|
|
cExt += cExtCA;
|
|
}
|
|
if (0 == cExt)
|
|
{
|
|
hr = S_FALSE; // no extensions to encode
|
|
goto error;
|
|
}
|
|
Extensions.cExtension = 0;
|
|
Extensions.rgExtension = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
sizeof(Extensions.rgExtension[0]) * cExt);
|
|
if (NULL == Extensions.rgExtension)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
for (i = 0; i < ARRAYSIZE(rgrgExt); i++)
|
|
{
|
|
CERT_EXTENSION *pExt = rgrgExt[i];
|
|
CERT_EXTENSION *pExtEnd;
|
|
|
|
for (pExtEnd = &pExt[rgcExt[i]]; pExt < pExtEnd; pExt++)
|
|
{
|
|
if (NULL == CertFindExtension(
|
|
pExt->pszObjId,
|
|
Extensions.cExtension,
|
|
Extensions.rgExtension))
|
|
{
|
|
Extensions.rgExtension[Extensions.cExtension] = *pExt;
|
|
Extensions.cExtension++;
|
|
}
|
|
}
|
|
}
|
|
CSASSERT(Extensions.cExtension <= cExt);
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_EXTENSIONS,
|
|
&Extensions,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
ppbOut,
|
|
pcbOut))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != rgExtCA)
|
|
{
|
|
FreeExtensions(TRUE, cExtCA, rgExtCA);
|
|
}
|
|
if (NULL != Extensions.rgExtension)
|
|
{
|
|
LocalFree(Extensions.rgExtension);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ConvertCertToPKCS10Request(
|
|
OPTIONAL IN WCHAR const *pwszExtensionName,
|
|
IN OUT BOOL *pfCA,
|
|
OPTIONAL IN CERT_EXTENSION *rgExtInf,
|
|
IN DWORD cExtInf,
|
|
IN OUT BYTE **ppbReq,
|
|
IN OUT DWORD *pcbReq)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pCert = NULL;
|
|
BYTE *pbReqUnsigned = NULL;
|
|
DWORD cbReqUnsigned;
|
|
BYTE *pbReq = NULL;
|
|
DWORD cbReq;
|
|
CERT_REQUEST_INFO Request;
|
|
CRYPT_ATTR_BLOB ExtBlob;
|
|
CRYPT_ATTR_BLOB VersionBlob;
|
|
CERT_EXTENSIONS Extensions;
|
|
CRYPT_ATTRIBUTE aAttrib[2];
|
|
HCRYPTPROV hProv = NULL;
|
|
DWORD dwKeySpec;
|
|
BOOL fCallerFreeProv;
|
|
CERT_EXTENSION *pExt;
|
|
CERT_EXTENSION *pExtKeyId;
|
|
CHAR *pszObjId = NULL;
|
|
#define CEXT_ADD 4 // SKI, Template Name, Basic Constraints, KeyUsage
|
|
CERT_EXTENSION aExtAdd[CEXT_ADD];
|
|
DWORD i;
|
|
|
|
ZeroMemory(aExtAdd, sizeof(aExtAdd));
|
|
|
|
// Certificate extensions to strip out of the request:
|
|
|
|
static char const * const s_apszObjIdFilter[] = {
|
|
szOID_BASIC_CONSTRAINTS2, // must be first!
|
|
szOID_CERTSRV_CA_VERSION,
|
|
szOID_AUTHORITY_INFO_ACCESS,
|
|
szOID_CRL_DIST_POINTS,
|
|
szOID_AUTHORITY_KEY_IDENTIFIER2,
|
|
szOID_CERTSRV_PREVIOUS_CERT_HASH,
|
|
szOID_ENROLL_CERTTYPE_EXTENSION,
|
|
szOID_CERTIFICATE_TEMPLATE,
|
|
NULL
|
|
};
|
|
char const * const *apszObjIdFilter = &s_apszObjIdFilter[1];
|
|
|
|
ExtBlob.pbData = NULL;
|
|
VersionBlob.pbData = NULL;
|
|
Extensions.rgExtension = NULL;
|
|
fCallerFreeProv = FALSE;
|
|
|
|
pCert = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
*ppbReq,
|
|
*pcbReq);
|
|
if (NULL == pCert)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
|
|
if (NULL != pwszExtensionName && IsCATemplate(pwszExtensionName))
|
|
{
|
|
*pfCA = TRUE;
|
|
}
|
|
pExt = CertFindExtension(
|
|
szOID_BASIC_CONSTRAINTS2,
|
|
pCert->pCertInfo->cExtension,
|
|
pCert->pCertInfo->rgExtension);
|
|
if (NULL != pExt)
|
|
{
|
|
BOOL fCAT;
|
|
|
|
hr = IsSubjectTypeCA(pExt, &fCAT);
|
|
_JumpIfError(hr, error, "IsSubjectTypeCA");
|
|
|
|
if (fCAT)
|
|
{
|
|
*pfCA = TRUE;
|
|
}
|
|
else if (*pfCA)
|
|
{
|
|
// filter out non-CA Basic Constraints -- add a new one below.
|
|
|
|
apszObjIdFilter = s_apszObjIdFilter;
|
|
}
|
|
}
|
|
ZeroMemory(&Request, sizeof(Request));
|
|
Request.dwVersion = CERT_REQUEST_V1;
|
|
Request.Subject = pCert->pCertInfo->Subject;
|
|
Request.SubjectPublicKeyInfo = pCert->pCertInfo->SubjectPublicKeyInfo;
|
|
|
|
Extensions.cExtension = 0;
|
|
Extensions.rgExtension = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
sizeof(Extensions.rgExtension[0]) *
|
|
(CEXT_ADD + pCert->pCertInfo->cExtension));
|
|
if (NULL == Extensions.rgExtension)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
pExtKeyId = NULL;
|
|
if (0 < pCert->pCertInfo->cExtension)
|
|
{
|
|
DWORD j;
|
|
|
|
pExt = pCert->pCertInfo->rgExtension;
|
|
for (i = 0; i < pCert->pCertInfo->cExtension; i++)
|
|
{
|
|
if (0 == strcmp(szOID_SUBJECT_KEY_IDENTIFIER, pExt->pszObjId))
|
|
{
|
|
pExtKeyId = pExt;
|
|
}
|
|
for (j = 0; ; j++)
|
|
{
|
|
if (NULL == apszObjIdFilter[j])
|
|
{
|
|
Extensions.rgExtension[Extensions.cExtension] =
|
|
pCert->pCertInfo->rgExtension[i];
|
|
Extensions.cExtension++;
|
|
break;
|
|
}
|
|
if (0 == strcmp(apszObjIdFilter[j], pExt->pszObjId))
|
|
{
|
|
break; // skip this extension
|
|
}
|
|
}
|
|
pExt++;
|
|
}
|
|
}
|
|
if (NULL == pExtKeyId)
|
|
{
|
|
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
|
|
CRYPT_DATA_BLOB Blob;
|
|
|
|
Blob.pbData = abHash;
|
|
Blob.cbData = sizeof(abHash);
|
|
if (!CryptHashPublicKeyInfo(
|
|
NULL, // hCryptProv
|
|
CALG_SHA1,
|
|
0, // dwFlags,
|
|
X509_ASN_ENCODING,
|
|
&Request.SubjectPublicKeyInfo,
|
|
Blob.pbData,
|
|
&Blob.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptHashPublicKeyInfo");
|
|
}
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_OCTET_STRING,
|
|
&Blob,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&aExtAdd[0].Value.pbData,
|
|
&aExtAdd[0].Value.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
aExtAdd[0].pszObjId = szOID_SUBJECT_KEY_IDENTIFIER;
|
|
pExtKeyId = &Extensions.rgExtension[Extensions.cExtension];
|
|
*pExtKeyId = aExtAdd[0];
|
|
Extensions.cExtension++;
|
|
}
|
|
|
|
if (NULL != pwszExtensionName)
|
|
{
|
|
hr = myBuildCertTypeExtension(pwszExtensionName, &aExtAdd[1]);
|
|
_JumpIfError(hr, error, "myBuildCertTypeExtension");
|
|
|
|
Extensions.rgExtension[Extensions.cExtension] = aExtAdd[1];
|
|
Extensions.cExtension++;
|
|
}
|
|
|
|
// get the OS Version
|
|
|
|
hr = myBuildOSVersionAttribute(&VersionBlob.pbData, &VersionBlob.cbData);
|
|
_JumpIfError(hr, error, "myBuildOSVersionAttribute");
|
|
|
|
hr = MergeAndEncodeExtensions(
|
|
*pfCA,
|
|
rgExtInf,
|
|
cExtInf,
|
|
Extensions.rgExtension,
|
|
Extensions.cExtension,
|
|
&ExtBlob.pbData,
|
|
&ExtBlob.cbData);
|
|
if (S_FALSE != hr)
|
|
{
|
|
_JumpIfError(hr, error, "MergeAndEncodeExtensions");
|
|
}
|
|
|
|
Request.cAttribute = 0;
|
|
Request.rgAttribute = aAttrib;
|
|
if (NULL != ExtBlob.pbData)
|
|
{
|
|
aAttrib[Request.cAttribute].pszObjId = szOID_RSA_certExtensions;
|
|
aAttrib[Request.cAttribute].cValue = 1;
|
|
aAttrib[Request.cAttribute].rgValue = &ExtBlob;
|
|
Request.cAttribute++;
|
|
}
|
|
|
|
aAttrib[Request.cAttribute].pszObjId = szOID_OS_VERSION;
|
|
aAttrib[Request.cAttribute].cValue = 1;
|
|
aAttrib[Request.cAttribute].rgValue = &VersionBlob;
|
|
Request.cAttribute++;
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
&Request,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbReqUnsigned,
|
|
&cbReqUnsigned))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
// Search for and load the cryptographic provider and private key.
|
|
|
|
hr = myLoadPrivateKey(
|
|
&pCert->pCertInfo->SubjectPublicKeyInfo,
|
|
CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_MYSTORE | CUCS_ARCHIVED,
|
|
&hProv,
|
|
&dwKeySpec,
|
|
&fCallerFreeProv);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "myLoadPrivateKey");
|
|
CSASSERT(NULL == hProv);
|
|
|
|
// private key is unavailable -- sign the PKCS10 with a NULL signature.
|
|
|
|
hr = myDupStringA(g_pszObjIdHash, &pszObjId);
|
|
_JumpIfError(hr, error, "myDupStringA");
|
|
}
|
|
else
|
|
{
|
|
if (AT_SIGNATURE != dwKeySpec)
|
|
{
|
|
hr = NTE_BAD_KEY_STATE;
|
|
DBGPRINT((DBG_SS_CERTREQ, "dwKeySpec = %u\n", dwKeySpec));
|
|
_JumpError(hr, error, "dwKeySpec");
|
|
}
|
|
|
|
// The private key is available -- use it to sign the PKCS10.
|
|
|
|
hr = myGetSigningOID(hProv, NULL, 0, CALG_SHA1, &pszObjId);
|
|
_JumpIfError(hr, error, "myGetSigningOID");
|
|
}
|
|
|
|
// Sign the request and encode the signed info.
|
|
|
|
hr = myEncodeSignedContent(
|
|
hProv,
|
|
X509_ASN_ENCODING,
|
|
pszObjId,
|
|
pbReqUnsigned,
|
|
cbReqUnsigned,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbReq,
|
|
&cbReq);
|
|
_JumpIfError(hr, error, "myEncodeSignedContent");
|
|
|
|
LocalFree(*ppbReq);
|
|
*ppbReq = pbReq;
|
|
*pcbReq = cbReq;
|
|
pbReq = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pszObjId)
|
|
{
|
|
LocalFree(pszObjId);
|
|
}
|
|
if (NULL != hProv && fCallerFreeProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
if (NULL != Extensions.rgExtension)
|
|
{
|
|
LocalFree(Extensions.rgExtension);
|
|
}
|
|
for (i = 0; i < CEXT_ADD; i++)
|
|
{
|
|
if (NULL != aExtAdd[i].Value.pbData)
|
|
{
|
|
LocalFree(aExtAdd[i].Value.pbData);
|
|
}
|
|
}
|
|
if (NULL != ExtBlob.pbData)
|
|
{
|
|
LocalFree(ExtBlob.pbData);
|
|
}
|
|
if (NULL != VersionBlob.pbData)
|
|
{
|
|
LocalFree(VersionBlob.pbData);
|
|
}
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
if (NULL != pbReq)
|
|
{
|
|
LocalFree(pbReq);
|
|
}
|
|
if (NULL != pbReqUnsigned)
|
|
{
|
|
LocalFree(pbReqUnsigned);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetPKCS10PrivateKey(
|
|
IN BYTE const *pbReq,
|
|
IN DWORD cbReq,
|
|
OUT HCRYPTPROV *phProv,
|
|
OUT DWORD *pdwKeySpec,
|
|
OUT BOOL *pfCallerFreeProv,
|
|
OUT BYTE **ppbKeyId,
|
|
OUT DWORD *pcbKeyId)
|
|
{
|
|
HRESULT hr;
|
|
CERT_REQUEST_INFO *pRequest = NULL;
|
|
HCRYPTPROV hProv = NULL;
|
|
CERT_EXTENSIONS *pExtensions = NULL;
|
|
CRYPT_ATTRIBUTE *pAttr;
|
|
BYTE *pbKeyId = NULL;
|
|
DWORD cbKeyId;
|
|
DWORD dwKeySpec;
|
|
DWORD cb;
|
|
DWORD i;
|
|
|
|
*phProv = NULL;
|
|
*pdwKeySpec = 0;
|
|
*ppbKeyId = NULL;
|
|
*pcbKeyId = 0;
|
|
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_REQUEST_TO_BE_SIGNED,
|
|
pbReq,
|
|
cbReq,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pRequest,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
|
|
// Search for and load the cryptographic provider and private key.
|
|
|
|
hr = myLoadPrivateKey(
|
|
&pRequest->SubjectPublicKeyInfo,
|
|
CUCS_MACHINESTORE | CUCS_USERSTORE | CUCS_MYSTORE | CUCS_ARCHIVED,
|
|
&hProv,
|
|
&dwKeySpec,
|
|
pfCallerFreeProv);
|
|
_JumpIfError(hr, error, "myLoadPrivateKey");
|
|
|
|
if (AT_SIGNATURE != dwKeySpec)
|
|
{
|
|
hr = NTE_BAD_KEY_STATE;
|
|
DBGPRINT((DBG_SS_CERTREQ, "dwKeySpec = %u\n", dwKeySpec));
|
|
_JumpError(hr, error, "dwKeySpec");
|
|
}
|
|
|
|
// Fetch or construct the KeyId hash
|
|
|
|
cbKeyId = 0;
|
|
pAttr = pRequest->rgAttribute;
|
|
for (i = 0; i < pRequest->cAttribute && NULL != pbKeyId; i++, pAttr++)
|
|
{
|
|
DWORD j;
|
|
|
|
if (0 == strcmp(szOID_RSA_certExtensions, pAttr->pszObjId) ||
|
|
0 == strcmp(szOID_CERT_EXTENSIONS, pAttr->pszObjId))
|
|
{
|
|
for (j = 0; j < pAttr->cValue; j++)
|
|
{
|
|
DWORD k;
|
|
CERT_EXTENSION *pExt;
|
|
|
|
if (NULL != pExtensions)
|
|
{
|
|
LocalFree(pExtensions);
|
|
pExtensions = NULL;
|
|
}
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_EXTENSIONS,
|
|
pAttr->rgValue[j].pbData,
|
|
pAttr->rgValue[j].cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pExtensions,
|
|
&cb))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
|
|
pExt = pExtensions->rgExtension;
|
|
for (k = 0; k < pExtensions->cExtension; k++, pExt++)
|
|
{
|
|
if (0 == strcmp(
|
|
pExt->pszObjId,
|
|
szOID_SUBJECT_KEY_IDENTIFIER))
|
|
{
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_OCTET_STRING,
|
|
pExt->Value.pbData,
|
|
pExt->Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pbKeyId,
|
|
&cbKeyId))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (NULL == pbKeyId)
|
|
{
|
|
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
|
|
|
|
cbKeyId = sizeof(abHash);
|
|
if (!CryptHashPublicKeyInfo(
|
|
NULL, // hCryptProv
|
|
CALG_SHA1,
|
|
0, // dwFlags,
|
|
X509_ASN_ENCODING,
|
|
&pRequest->SubjectPublicKeyInfo,
|
|
abHash,
|
|
&cbKeyId))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CryptHashPublicKeyInfo");
|
|
}
|
|
pbKeyId = (BYTE *) LocalAlloc(LMEM_FIXED, cbKeyId);
|
|
if (NULL == pbKeyId)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(pbKeyId, abHash, cbKeyId);
|
|
}
|
|
*phProv = hProv;
|
|
hProv = NULL;
|
|
*ppbKeyId = pbKeyId;
|
|
pbKeyId = NULL;
|
|
*pcbKeyId = cbKeyId;
|
|
*pdwKeySpec = dwKeySpec;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != hProv && *pfCallerFreeProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
if (NULL != pRequest)
|
|
{
|
|
LocalFree(pRequest);
|
|
}
|
|
if (NULL != pExtensions)
|
|
{
|
|
LocalFree(pExtensions);
|
|
}
|
|
if (NULL != pbKeyId)
|
|
{
|
|
LocalFree(pbKeyId);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
BuildNameValuePairs(
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
IN OUT DWORD *pcValue,
|
|
OPTIONAL OUT CRYPT_ATTR_BLOB *pValue,
|
|
OPTIONAL OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cValue = 0;
|
|
WCHAR *pwszDup = NULL;
|
|
WCHAR *pwszBuf;
|
|
WCHAR const *pwszName;
|
|
WCHAR const *pwszValue;
|
|
WCHAR *pwszTemplateName = NULL;
|
|
|
|
if (NULL != ppwszTemplateName)
|
|
{
|
|
*ppwszTemplateName = NULL;
|
|
}
|
|
if (NULL == pwszAttributes)
|
|
{
|
|
hr = S_OK;
|
|
goto error; // silently ignore empty string
|
|
}
|
|
hr = myDupString(pwszAttributes, &pwszDup);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pwszBuf = pwszDup;
|
|
|
|
for (;;)
|
|
{
|
|
hr = myParseNextAttribute(&pwszBuf, FALSE, &pwszName, &pwszValue);
|
|
if (S_FALSE == hr)
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "myParseNextAttribute");
|
|
|
|
DBGPRINT((DBG_SS_CERTREQI, "'%ws' = '%ws'\n", pwszName, pwszValue));
|
|
if (NULL != pValue)
|
|
{
|
|
CRYPT_ENROLLMENT_NAME_VALUE_PAIR NamePair;
|
|
|
|
CSASSERT(cValue < *pcValue);
|
|
NamePair.pwszName = const_cast<WCHAR *>(pwszName);
|
|
NamePair.pwszValue = const_cast<WCHAR *>(pwszValue);
|
|
|
|
if (NULL != ppwszTemplateName &&
|
|
0 == LSTRCMPIS(pwszName, wszPROPCERTTEMPLATE))
|
|
{
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
_JumpError(hr, error, "Duplicate cert template");
|
|
}
|
|
hr = myDupString(pwszValue, &pwszTemplateName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
//X509_ENROLLMENT_NAME_VALUE_PAIR,
|
|
szOID_ENROLLMENT_NAME_VALUE_PAIR,
|
|
&NamePair,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pValue[cValue].pbData,
|
|
&pValue[cValue].cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
}
|
|
cValue++;
|
|
}
|
|
if (NULL != ppwszTemplateName)
|
|
{
|
|
*ppwszTemplateName = pwszTemplateName;
|
|
pwszTemplateName = NULL;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
LocalFree(pwszTemplateName);
|
|
}
|
|
*pcValue = cValue;
|
|
if (NULL != pwszDup)
|
|
{
|
|
LocalFree(pwszDup);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
ConvertPolicesToSz(
|
|
IN DWORD cPolicies,
|
|
IN WCHAR const * const *rgpwszPolicies,
|
|
OUT CHAR ***prgpszPolicies)
|
|
{
|
|
HRESULT hr;
|
|
DWORD i;
|
|
DWORD cch = 0;
|
|
CHAR **ppsz;
|
|
CHAR *pch;
|
|
|
|
*prgpszPolicies = NULL;
|
|
for (i = 0; i < cPolicies; i++)
|
|
{
|
|
cch += wcslen(rgpwszPolicies[i]) + 1;
|
|
}
|
|
ppsz = (CHAR **) LocalAlloc(
|
|
LMEM_FIXED,
|
|
cch + (cPolicies + 1) * sizeof(CHAR *));
|
|
if (NULL == ppsz)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
*prgpszPolicies = ppsz;
|
|
pch = (CHAR *) &ppsz[cPolicies + 1];
|
|
|
|
for (i = 0; i < cPolicies; i++)
|
|
{
|
|
WCHAR const *pwc;
|
|
|
|
*ppsz++ = pch;
|
|
pwc = rgpwszPolicies[i];
|
|
while ('\0' != (*pch++ = (char) *pwc++))
|
|
;
|
|
}
|
|
*ppsz = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
PickCertAndSignRequest(
|
|
IN BYTE const *pbReq,
|
|
IN DWORD cbReq,
|
|
IN BOOL fSkipSignerDeletion,
|
|
OPTIONAL IN WCHAR const *pwszTemplateName,
|
|
OUT BYTE **ppbPKCS7Out,
|
|
OUT DWORD *pcbPKCS7Out)
|
|
{
|
|
HRESULT hr;
|
|
HCERTTYPE hCertType = NULL;
|
|
CERT_CONTEXT const *pCertSigner = NULL;
|
|
WCHAR **rgpwszPolicies = NULL;
|
|
CHAR **rgpszPolicies = NULL;
|
|
WCHAR **ppwsz;
|
|
DWORD cPolicies = 0;
|
|
|
|
if (NULL == g_pwszCertCN || !myIsMinusSignString(g_pwszCertCN))
|
|
{
|
|
if (!g_fQuiet || NULL != g_pwszCertCN)
|
|
{
|
|
WCHAR const *pwszCommonName;
|
|
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
hr = CAFindCertTypeByName(
|
|
pwszTemplateName,
|
|
NULL,
|
|
CT_FIND_LOCAL_SYSTEM |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES,
|
|
&hCertType);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = CAFindCertTypeByName(
|
|
pwszTemplateName,
|
|
NULL,
|
|
CT_FIND_LOCAL_SYSTEM |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES |
|
|
CT_FIND_BY_OID,
|
|
&hCertType);
|
|
_PrintIfErrorStr(hr, "CAFindCertTypeByName", pwszTemplateName);
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
DWORD cSig;
|
|
|
|
hr = CAGetCertTypePropertyEx(
|
|
hCertType,
|
|
CERTTYPE_PROP_RA_SIGNATURE,
|
|
&cSig);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "CAGetCertTypePropertyEx");
|
|
cSig = 0;
|
|
}
|
|
if (0 != cSig)
|
|
{
|
|
hr = CAGetCertTypePropertyEx(
|
|
hCertType,
|
|
CERTTYPE_PROP_RA_APPLICATION_POLICY,
|
|
&rgpwszPolicies);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "CAGetCertTypePropertyEx");
|
|
rgpwszPolicies = NULL;
|
|
}
|
|
}
|
|
if (NULL != rgpwszPolicies)
|
|
{
|
|
for (ppwsz = rgpwszPolicies; NULL != *ppwsz; ppwsz++)
|
|
{
|
|
cPolicies++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pwszCommonName = NULL;
|
|
if (L'\0' != g_pwszCertCN && 0 != lstrcmp(L"*", g_pwszCertCN))
|
|
{
|
|
pwszCommonName = g_pwszCertCN;
|
|
}
|
|
if (0 != cPolicies)
|
|
{
|
|
hr = ConvertPolicesToSz(
|
|
cPolicies,
|
|
rgpwszPolicies,
|
|
&rgpszPolicies);
|
|
_JumpIfError(hr, error, "ConvertPolicesToSz");
|
|
|
|
hr = myGetCertificateFromPicker(
|
|
g_hInstance,
|
|
NULL, // hwndParent
|
|
IDS_GETERACERT_TITLE,
|
|
IDS_GETERACERT_SUBTITLE,
|
|
CUCS_MYSTORE |
|
|
CUCS_PRIVATEKEYREQUIRED |
|
|
CUCS_USAGEREQUIRED |
|
|
(g_fQuiet? CUCS_SILENT : 0),
|
|
pwszCommonName,
|
|
0, // cStore
|
|
NULL, // rghStore
|
|
cPolicies, // cpszObjId
|
|
rgpszPolicies, // apszObjId
|
|
&pCertSigner);
|
|
_JumpIfError(hr, error, "myGetCertificateFromPicker");
|
|
}
|
|
else
|
|
{
|
|
hr = myGetERACertificateFromPicker(
|
|
g_hInstance,
|
|
NULL, // hwndParent
|
|
IDS_GETERACERT_TITLE,
|
|
IDS_GETERACERT_SUBTITLE,
|
|
pwszCommonName,
|
|
g_fQuiet,
|
|
&pCertSigner);
|
|
_JumpIfError(hr, error, "myGetERACertificateFromPicker");
|
|
}
|
|
}
|
|
|
|
// pCertSigner is NULL if the user cancelled out of the cert picker U/I.
|
|
// NULL pCertSigner means delete existing signatures.
|
|
|
|
if (NULL == pCertSigner)
|
|
{
|
|
if (fSkipSignerDeletion)
|
|
{
|
|
hr = S_FALSE;
|
|
_JumpError2(hr, error, "no signer selected", S_FALSE);
|
|
}
|
|
if (g_fQuiet || NULL != g_pwszCertCN)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "no matching signer CN");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DWORD dwCertValidityFlags;
|
|
|
|
// be sure the cert picked isn't already expired - that'd be silly
|
|
|
|
dwCertValidityFlags = CERT_STORE_TIME_VALIDITY_FLAG;
|
|
if (!CertVerifySubjectCertificateContext(
|
|
pCertSigner,
|
|
NULL,
|
|
&dwCertValidityFlags))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "CertVerifySubjectCertificateContext");
|
|
}
|
|
if (0 != dwCertValidityFlags)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(CERT_E_EXPIRED);
|
|
_JumpError(hr, error, "CertVerifySubjectCertificateContext");
|
|
}
|
|
}
|
|
}
|
|
hr = SignCMCContent(
|
|
pCertSigner,
|
|
szOID_CT_PKI_DATA,
|
|
pbReq,
|
|
cbReq,
|
|
0 != (CR_OUT_CRLS & g_dwCRLOut),
|
|
ppbPKCS7Out,
|
|
pcbPKCS7Out);
|
|
_JumpIfError(hr, error, "SignCMCContent");
|
|
|
|
error:
|
|
if (NULL != rgpwszPolicies)
|
|
{
|
|
CAFreeCertTypeProperty(hCertType, rgpwszPolicies);
|
|
}
|
|
if (NULL != rgpszPolicies)
|
|
{
|
|
LocalFree(rgpszPolicies);
|
|
}
|
|
if (NULL != hCertType)
|
|
{
|
|
CACloseCertType(hCertType);
|
|
}
|
|
if (NULL != pCertSigner)
|
|
{
|
|
CertFreeCertificateContext(pCertSigner);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SignQualifiedRequest(
|
|
IN HWND hWndOwner,
|
|
IN WCHAR const *pwszfnReq,
|
|
OPTIONAL IN WCHAR const *pwszfnOut)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbReq = NULL;
|
|
DWORD cbReq;
|
|
BYTE *pbPKCS7Out = NULL;
|
|
DWORD cbPKCS7Out;
|
|
LONG dwFlags;
|
|
BOOL fSigned;
|
|
WCHAR *pwszTemplateName = NULL;
|
|
|
|
// Read the request from a file, convert it to binary, and return
|
|
// dwFlags to indicate the orignal encoding and the detected format.
|
|
|
|
hr = CheckRequestType(
|
|
pwszfnReq,
|
|
&pbReq,
|
|
&cbReq,
|
|
&dwFlags,
|
|
&fSigned,
|
|
NULL, // pfCA
|
|
&pwszTemplateName);
|
|
_JumpIfError(hr, error, "CheckRequestType");
|
|
|
|
if (CR_IN_CMC != (CR_IN_FORMATMASK & dwFlags))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorString(pwszfnReq);
|
|
_JumpError(hr, error, "not a CMC request");
|
|
}
|
|
|
|
hr = PickCertAndSignRequest(
|
|
pbReq,
|
|
cbReq,
|
|
FALSE,
|
|
pwszTemplateName,
|
|
&pbPKCS7Out,
|
|
&cbPKCS7Out);
|
|
_JumpIfError(hr, error, "PickCertAndSignRequest");
|
|
|
|
hr = WriteCertificateOrRequest(
|
|
hWndOwner,
|
|
NULL, // pdiRequest
|
|
pbPKCS7Out,
|
|
cbPKCS7Out,
|
|
g_dwOutFormat,
|
|
IDS_REQUEST_OUTFILE_TITLE,
|
|
IDS_REQUEST_FILE_FILTER,
|
|
IDS_REQUEST_FILE_DEFEXT,
|
|
pwszfnOut);
|
|
_JumpIfError(hr, error, "WriteCertificateOrRequest");
|
|
|
|
error:
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
LocalFree(pwszTemplateName);
|
|
}
|
|
if (NULL != pbReq)
|
|
{
|
|
LocalFree(pbReq);
|
|
}
|
|
if (NULL != pbPKCS7Out)
|
|
{
|
|
LocalFree(pbPKCS7Out);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ParseRequestInfo(
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
IN WCHAR const *pwszfnPolicy,
|
|
OPTIONAL OUT INFVALUES **prgInfValues,
|
|
OPTIONAL OUT DWORD *pcInfValues,
|
|
OUT CRYPT_ATTRIBUTES **prgAttributes,
|
|
OUT DWORD *pcAttributes,
|
|
OUT CERT_EXTENSION **prgExt,
|
|
OUT DWORD *pcExt,
|
|
OUT WCHAR **ppwszTemplateName)
|
|
{
|
|
HRESULT hr;
|
|
CERT_EXTENSION *rgExtT;
|
|
CERT_EXTENSION *rgExt = NULL;
|
|
DWORD cExt;
|
|
CRYPT_ATTR_BLOB *argValue[2] = { NULL, NULL };
|
|
DWORD acValue[2];
|
|
DWORD i;
|
|
DWORD j;
|
|
CRYPT_ATTRIBUTES *rgAttributes = NULL;
|
|
DWORD cAttributes = 0;
|
|
WCHAR *pwszTemplateNameInf = NULL;
|
|
WCHAR *pwszTemplateName = NULL;
|
|
HCERTTYPE hCertType = NULL;
|
|
CERT_EXTENSIONS *pExtensions = NULL;
|
|
|
|
if (NULL != prgInfValues)
|
|
{
|
|
*prgInfValues = NULL;
|
|
}
|
|
if (NULL != pcInfValues)
|
|
{
|
|
*pcInfValues = 0;
|
|
}
|
|
*prgAttributes = NULL;
|
|
*pcAttributes = 0;
|
|
*prgExt = NULL;
|
|
*pcExt = 0;
|
|
*ppwszTemplateName = NULL;
|
|
|
|
hr = ParseInfFile(
|
|
pwszfnPolicy,
|
|
prgInfValues,
|
|
pcInfValues,
|
|
&argValue[0],
|
|
&acValue[0],
|
|
&rgExt,
|
|
&cExt,
|
|
&pwszTemplateNameInf);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnPolicy);
|
|
_JumpError(hr, error, "ParseInfFile");
|
|
}
|
|
if (0 != acValue[0])
|
|
{
|
|
cAttributes++;
|
|
}
|
|
|
|
// Count the command line request attributes
|
|
|
|
hr = BuildNameValuePairs(pwszAttributes, &acValue[1], NULL, NULL);
|
|
_JumpIfError(hr, error, "BuildNameValuePairs");
|
|
|
|
if (0 != acValue[1])
|
|
{
|
|
cAttributes++;
|
|
|
|
argValue[1] = (CRYPT_ATTR_BLOB *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
acValue[1] * sizeof(argValue[1][0]));
|
|
if (NULL == argValue[1])
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
hr = BuildNameValuePairs(
|
|
pwszAttributes,
|
|
&acValue[1],
|
|
argValue[1],
|
|
&pwszTemplateName);
|
|
_JumpIfError(hr, error, "BuildNameValuePairs");
|
|
}
|
|
|
|
if (0 != cAttributes)
|
|
{
|
|
rgAttributes = (CRYPT_ATTRIBUTES *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
cAttributes * sizeof(rgAttributes[0]));
|
|
if (NULL == rgAttributes)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
for (i = j = 0; i < cAttributes; i++, j++)
|
|
{
|
|
CRYPT_ATTRIBUTE *rgAttr;
|
|
|
|
rgAttr = (CRYPT_ATTRIBUTE *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(rgAttributes[i].rgAttr[0]));
|
|
if (NULL == rgAttr)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
while (0 == acValue[j])
|
|
{
|
|
j++;
|
|
}
|
|
rgAttributes[i].cAttr = 1;
|
|
rgAttributes[i].rgAttr = rgAttr;
|
|
|
|
rgAttr[0].pszObjId = szOID_ENROLLMENT_NAME_VALUE_PAIR;
|
|
rgAttr[0].cValue = acValue[j];
|
|
rgAttr[0].rgValue = argValue[j];
|
|
argValue[j] = NULL;
|
|
}
|
|
}
|
|
|
|
if (NULL != pwszTemplateName || NULL != pwszTemplateNameInf)
|
|
{
|
|
WCHAR const *pwsz;
|
|
|
|
pwsz = pwszTemplateNameInf;
|
|
if (NULL == pwsz)
|
|
{
|
|
pwsz = pwszTemplateName;
|
|
CSASSERT(NULL != pwsz);
|
|
}
|
|
else if (NULL != pwszTemplateName &&
|
|
0 != mylstrcmpiL(pwszTemplateName, pwszTemplateNameInf))
|
|
{
|
|
hr = CERTSRV_E_TEMPLATE_CONFLICT;
|
|
SetErrorString(wszPROPCERTTEMPLATE);
|
|
_JumpError(hr, error, "Template name conflict");
|
|
}
|
|
|
|
// Include the specified cert template's extensions
|
|
|
|
hr = CAFindCertTypeByName(
|
|
pwsz,
|
|
NULL,
|
|
CT_FIND_LOCAL_SYSTEM |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES,
|
|
&hCertType);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = CAFindCertTypeByName(
|
|
pwsz,
|
|
NULL,
|
|
CT_FIND_LOCAL_SYSTEM |
|
|
CT_ENUM_MACHINE_TYPES |
|
|
CT_ENUM_USER_TYPES |
|
|
CT_FIND_BY_OID,
|
|
&hCertType);
|
|
_PrintIfErrorStr(hr, "CAFindCertTypeByName", pwsz);
|
|
}
|
|
if (S_OK == hr)
|
|
{
|
|
hr = CAGetCertTypeExtensions(hCertType, &pExtensions);
|
|
_PrintIfError(hr, "CAGetCertTypeExtensions");
|
|
}
|
|
if (S_OK == hr && NULL != pExtensions && 0 != pExtensions->cExtension)
|
|
{
|
|
CERT_EXTENSION *pExtSrc;
|
|
CERT_EXTENSION *pExtSrcEnd;
|
|
CERT_EXTENSION *pExtDst;
|
|
|
|
rgExtT = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
(pExtensions->cExtension + cExt) * sizeof(rgExtT[0]));
|
|
if (NULL == rgExtT)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
if (NULL != rgExt)
|
|
{
|
|
CopyMemory(&rgExtT[0], &rgExt[0], cExt * sizeof(rgExtT[0]));
|
|
LocalFree(rgExt);
|
|
}
|
|
rgExt = rgExtT;
|
|
|
|
pExtSrc = pExtensions->rgExtension;
|
|
pExtSrcEnd = &pExtSrc[pExtensions->cExtension];
|
|
pExtDst = &rgExt[cExt];
|
|
for ( ; pExtSrc < pExtSrcEnd; pExtSrc++, pExtDst++)
|
|
{
|
|
pExtDst->fCritical = pExtSrc->fCritical;
|
|
pExtDst->Value.cbData = pExtSrc->Value.cbData;
|
|
|
|
hr = myDupStringA(pExtSrc->pszObjId, &pExtDst->pszObjId);
|
|
_JumpIfError(hr, error, "myDupStringA");
|
|
|
|
pExtDst->Value.pbData = (BYTE *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
pExtSrc->Value.cbData);
|
|
if (NULL == pExtDst->Value.pbData)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
CopyMemory(
|
|
pExtDst->Value.pbData,
|
|
pExtSrc->Value.pbData,
|
|
pExtSrc->Value.cbData);
|
|
}
|
|
cExt += pExtensions->cExtension;
|
|
}
|
|
else
|
|
{
|
|
CHAR const *pszObjId;
|
|
|
|
// Grow extension array to make room for the cert type extension
|
|
|
|
rgExtT = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
(cExt + 1) * sizeof(rgExtT[0]));
|
|
if (NULL == rgExtT)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
if (0 != cExt)
|
|
{
|
|
CSASSERT(NULL != rgExt);
|
|
CopyMemory(&rgExtT[1], rgExt, cExt * sizeof(rgExt[0]));
|
|
LocalFree(rgExt);
|
|
}
|
|
rgExt = rgExtT;
|
|
cExt++;
|
|
|
|
hr = myBuildCertTypeExtension(pwsz, &rgExt[0]);
|
|
_JumpIfError(hr, error, "myBuildCertTypeExtension");
|
|
|
|
pszObjId = rgExt[0].pszObjId;
|
|
rgExt[0].pszObjId = NULL;
|
|
|
|
hr = myDupStringA(pszObjId, &rgExt[0].pszObjId);
|
|
_JumpIfError(hr, error, "myDupStringA");
|
|
}
|
|
}
|
|
myPackExtensionArray(TRUE, &cExt, &rgExt);
|
|
|
|
*prgAttributes = rgAttributes;
|
|
rgAttributes = NULL;
|
|
*pcAttributes = cAttributes;
|
|
|
|
*prgExt = rgExt;
|
|
rgExt = NULL;
|
|
*pcExt = cExt;
|
|
|
|
if (NULL != pwszTemplateNameInf)
|
|
{
|
|
*ppwszTemplateName = pwszTemplateNameInf;
|
|
pwszTemplateNameInf = NULL;
|
|
}
|
|
else
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
*ppwszTemplateName = pwszTemplateName;
|
|
pwszTemplateName = NULL;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (S_OK != hr && NULL != prgInfValues)
|
|
{
|
|
myInfFreeSectionValues(*pcInfValues, *prgInfValues);
|
|
*prgInfValues = NULL;
|
|
*pcInfValues = 0;
|
|
}
|
|
if (NULL != rgAttributes)
|
|
{
|
|
FreeAttributes(cAttributes, rgAttributes);
|
|
}
|
|
for (i = 0; i < ARRAYSIZE(argValue); i++)
|
|
{
|
|
if (NULL != argValue[i])
|
|
{
|
|
myInfFreeRequestAttributes(acValue[i], argValue[i]);
|
|
}
|
|
}
|
|
if (NULL != rgExt)
|
|
{
|
|
FreeExtensions(TRUE, cExt, rgExt);
|
|
}
|
|
if (NULL != pwszTemplateNameInf)
|
|
{
|
|
LocalFree(pwszTemplateNameInf);
|
|
}
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
LocalFree(pwszTemplateName);
|
|
}
|
|
if (NULL != hCertType)
|
|
{
|
|
if (NULL != pExtensions)
|
|
{
|
|
CAFreeCertTypeExtensions(hCertType, pExtensions);
|
|
}
|
|
CACloseCertType(hCertType);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CreateQualifiedRequest(
|
|
IN HWND hWndOwner,
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
IN WCHAR const *pwszfnReq,
|
|
IN WCHAR const *pwszfnPolicy,
|
|
OPTIONAL IN WCHAR const *pwszfnOut,
|
|
OPTIONAL IN WCHAR const *pwszfnPKCS10)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbReq = NULL;
|
|
DWORD cbReq;
|
|
BYTE *pbKeyId = NULL;
|
|
DWORD cbKeyId = 0;
|
|
BYTE *pbReqCMCFirstSigned = NULL;
|
|
DWORD cbReqCMCFirstSigned;
|
|
BYTE *pbReqCMCOut = NULL;
|
|
DWORD cbReqCMCOut;
|
|
LONG dwFlags;
|
|
BOOL fNestedCMCRequest = FALSE;
|
|
BOOL fSigned;
|
|
CRYPT_ATTRIBUTES *rgAttributes = NULL;
|
|
DWORD cAttributes;
|
|
CERT_EXTENSION *rgExt = NULL;
|
|
DWORD cExt;
|
|
WCHAR *pwszTemplateName = NULL;
|
|
WCHAR *pwszTemplateNameRequest = NULL;
|
|
HCRYPTPROV hProv = NULL;
|
|
DWORD dwKeySpec = 0;
|
|
BOOL fCallerFreeProv;
|
|
BOOL fCA;
|
|
|
|
cAttributes = 0;
|
|
cExt = 0;
|
|
fCallerFreeProv = FALSE;
|
|
|
|
// Read the request from a file, convert it to binary, and return
|
|
// dwFlags to indicate the orignal encoding and the detected format.
|
|
|
|
hr = CheckRequestType(
|
|
pwszfnReq,
|
|
&pbReq,
|
|
&cbReq,
|
|
&dwFlags,
|
|
&fSigned,
|
|
&fCA,
|
|
&pwszTemplateNameRequest);
|
|
_JumpIfError(hr, error, "CheckRequestType");
|
|
|
|
hr = ParseRequestInfo(
|
|
pwszAttributes,
|
|
pwszfnPolicy,
|
|
NULL, // prgInfValues
|
|
NULL, // pcInfValues
|
|
&rgAttributes,
|
|
&cAttributes,
|
|
&rgExt,
|
|
&cExt,
|
|
&pwszTemplateName);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnPolicy);
|
|
_JumpError(hr, error, "ParseRequestInfo");
|
|
}
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
switch (CR_IN_FORMATMASK & dwFlags)
|
|
{
|
|
case CR_IN_CMC:
|
|
fNestedCMCRequest = TRUE;
|
|
break;
|
|
|
|
case CR_IN_CERT:
|
|
hr = ConvertCertToPKCS10Request(
|
|
NULL != pwszTemplateName?
|
|
pwszTemplateName : pwszTemplateNameRequest,
|
|
&fCA,
|
|
rgExt,
|
|
cExt,
|
|
&pbReq,
|
|
&cbReq);
|
|
_JumpIfError(hr, error, "ConvertCertToPKCS10Request");
|
|
|
|
if (NULL != rgExt)
|
|
{
|
|
FreeExtensions(TRUE, cExt, rgExt);
|
|
rgExt = NULL;
|
|
cExt = 0;
|
|
}
|
|
dwFlags = CR_IN_PKCS10 | (~CR_IN_FORMATMASK & dwFlags);
|
|
break;
|
|
|
|
case CR_IN_PKCS10:
|
|
break;
|
|
|
|
default:
|
|
_JumpError(hr, error, "not a CMC or PKCS10 request");
|
|
}
|
|
fCallerFreeProv = FALSE;
|
|
if (CR_IN_PKCS10 == (CR_IN_FORMATMASK & dwFlags))
|
|
{
|
|
if (NULL != pwszfnPKCS10)
|
|
{
|
|
hr = crOverwriteFileAllowed(hWndOwner, pwszfnPKCS10);
|
|
_JumpIfError(hr, error, "crOverwriteFileAllowed");
|
|
|
|
hr = EncodeToFileW(
|
|
pwszfnPKCS10,
|
|
pbReq,
|
|
cbReq,
|
|
DECF_FORCEOVERWRITE | g_dwOutFormat);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnPKCS10);
|
|
_JumpErrorStr(hr, error, "EncodeToFileW", pwszfnPKCS10);
|
|
}
|
|
}
|
|
|
|
hr = GetPKCS10PrivateKey(
|
|
pbReq,
|
|
cbReq,
|
|
&hProv,
|
|
&dwKeySpec,
|
|
&fCallerFreeProv,
|
|
&pbKeyId,
|
|
&cbKeyId);
|
|
_PrintIfError(hr, "GetPKCS10PrivateKey");
|
|
}
|
|
|
|
if (fCA)
|
|
{
|
|
hr = AddCAExtensions(&rgExt, &cExt);
|
|
_JumpIfError(hr, error, "AddCAExtensions");
|
|
}
|
|
|
|
hr = BuildCMCRequest(
|
|
XECI_CERTREQ,
|
|
fNestedCMCRequest,
|
|
pbReq,
|
|
cbReq,
|
|
rgExt,
|
|
cExt,
|
|
rgAttributes,
|
|
cAttributes,
|
|
NULL, // rgAttributeUnauth
|
|
0, // cAttributeUnauth
|
|
pbKeyId,
|
|
cbKeyId,
|
|
hProv,
|
|
dwKeySpec,
|
|
NULL == hProv? NULL : g_pszObjIdHash,
|
|
NULL, // pCertSigner
|
|
NULL, // hProvSigner
|
|
0, // dwKeySpecSigner
|
|
NULL, // pszObjIdHashSigner
|
|
&pbReqCMCFirstSigned,
|
|
&cbReqCMCFirstSigned);
|
|
_JumpIfError(hr, error, "BuildCMCRequest");
|
|
|
|
hr = PickCertAndSignRequest(
|
|
pbReqCMCFirstSigned,
|
|
cbReqCMCFirstSigned,
|
|
TRUE,
|
|
NULL != pwszTemplateName?
|
|
pwszTemplateName : pwszTemplateNameRequest,
|
|
&pbReqCMCOut,
|
|
&cbReqCMCOut);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError2(hr, "PickCertAndSignRequest", S_FALSE);
|
|
if (S_FALSE != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
// The user cancelled out of the cert picker U/I, so just save the
|
|
// unsigned request.
|
|
|
|
pbReqCMCOut = pbReqCMCFirstSigned;
|
|
cbReqCMCOut = cbReqCMCFirstSigned;
|
|
}
|
|
|
|
hr = WriteCertificateOrRequest(
|
|
hWndOwner,
|
|
NULL, // pdiRequest
|
|
pbReqCMCOut,
|
|
cbReqCMCOut,
|
|
g_dwOutFormat,
|
|
IDS_REQUEST_OUTFILE_TITLE,
|
|
IDS_REQUEST_FILE_FILTER,
|
|
IDS_REQUEST_FILE_DEFEXT,
|
|
pwszfnOut);
|
|
_JumpIfError(hr, error, "WriteCertificateOrRequest");
|
|
|
|
error:
|
|
if (NULL != hProv && fCallerFreeProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
if (NULL != pwszTemplateNameRequest)
|
|
{
|
|
LocalFree(pwszTemplateNameRequest);
|
|
}
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
LocalFree(pwszTemplateName);
|
|
}
|
|
if (NULL != rgExt)
|
|
{
|
|
FreeExtensions(TRUE, cExt, rgExt);
|
|
}
|
|
if (NULL != rgAttributes)
|
|
{
|
|
FreeAttributes(cAttributes, rgAttributes);
|
|
}
|
|
if (NULL != pbReqCMCOut && pbReqCMCFirstSigned != pbReqCMCOut)
|
|
{
|
|
LocalFree(pbReqCMCOut);
|
|
}
|
|
if (NULL != pbReqCMCFirstSigned)
|
|
{
|
|
LocalFree(pbReqCMCFirstSigned);
|
|
}
|
|
if (NULL != pbKeyId)
|
|
{
|
|
LocalFree(pbKeyId);
|
|
}
|
|
if (NULL != pbReq)
|
|
{
|
|
LocalFree(pbReq);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetCAXchgCert(
|
|
IN WCHAR const *pwszValue,
|
|
OUT CERT_CONTEXT const **ppccXchg)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fEnabled;
|
|
BSTR strConfig = NULL;
|
|
BSTR strCert = NULL;
|
|
WCHAR const *pwszConfig;
|
|
DISPATCHINTERFACE diRequest;
|
|
BOOL fMustRelease = FALSE;
|
|
|
|
*ppccXchg = NULL;
|
|
|
|
hr = myInfParseBooleanValue(pwszValue, &fEnabled);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
if (fEnabled)
|
|
{
|
|
pwszConfig = g_pwszConfig;
|
|
if (NULL == pwszConfig)
|
|
{
|
|
hr = crGetConfig(&strConfig);
|
|
_JumpIfError(hr, error, "crGetConfig");
|
|
|
|
pwszConfig = strConfig;
|
|
}
|
|
|
|
hr = Request_Init(g_fIDispatch, &diRequest);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintError(hr, "Request_Init");
|
|
if (E_ACCESSDENIED == hr) // try for a clearer error message
|
|
{
|
|
hr = CO_E_REMOTE_COMMUNICATION_FAILURE;
|
|
}
|
|
_JumpError(hr, error, "Request_Init");
|
|
}
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Request2_GetCAProperty(
|
|
&diRequest,
|
|
pwszConfig,
|
|
CR_PROP_CAXCHGCERT,
|
|
0, // Index
|
|
PROPTYPE_BINARY,
|
|
CV_OUT_BINARY,
|
|
(VOID *) &strCert);
|
|
_JumpIfError(hr, error, "Request2_GetCAProperty");
|
|
|
|
*ppccXchg = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
(BYTE const *) strCert,
|
|
SysStringByteLen(strCert));
|
|
if (NULL == *ppccXchg)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != strConfig)
|
|
{
|
|
SysFreeString(strConfig);
|
|
}
|
|
if (NULL != strCert)
|
|
{
|
|
SysFreeString(strCert);
|
|
}
|
|
if (fMustRelease)
|
|
{
|
|
Request_Release(&diRequest);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetRenewalCert(
|
|
IN WCHAR const *pwszValue,
|
|
OUT CERT_CONTEXT const **ppccRenewal)
|
|
{
|
|
HRESULT hr;
|
|
BSTR strConfig = NULL;
|
|
BSTR strCert = NULL;
|
|
DISPATCHINTERFACE diRequest;
|
|
BOOL fMustRelease = FALSE;
|
|
|
|
*ppccRenewal = NULL;
|
|
|
|
hr = myGetCertificateFromPicker(
|
|
g_hInstance,
|
|
NULL, // hwndParent
|
|
IDS_GETRENEWALCERT_TITLE,
|
|
IDS_GETRENEWALCERT_SUBTITLE,
|
|
CUCS_MYSTORE |
|
|
CUCS_MACHINESTORE | CUCS_USERSTORE |
|
|
CUCS_DSSTORE |
|
|
CUCS_PRIVATEKEYREQUIRED |
|
|
(g_fVerbose? CUCS_ARCHIVED : 0) |
|
|
(g_fQuiet? CUCS_SILENT : 0),
|
|
(L'\0' == pwszValue || 0 == lstrcmp(L"*", pwszValue))?
|
|
NULL : pwszValue, // pwszCommonName
|
|
0, // cStore
|
|
NULL, // rghStore
|
|
0, // cpszObjId
|
|
NULL, // apszObjId
|
|
ppccRenewal);
|
|
_JumpIfError(hr, error, "myGetCertificateFromPicker");
|
|
|
|
if (NULL == *ppccRenewal)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
_JumpError(hr, error, "myGetCertificateFromPicker");
|
|
}
|
|
|
|
error:
|
|
if (NULL != strConfig)
|
|
{
|
|
SysFreeString(strConfig);
|
|
}
|
|
if (NULL != strCert)
|
|
{
|
|
SysFreeString(strCert);
|
|
}
|
|
if (fMustRelease)
|
|
{
|
|
Request_Release(&diRequest);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
CreateNewRequest(
|
|
IN HWND hWndOwner,
|
|
OPTIONAL IN WCHAR const *pwszAttributes,
|
|
IN WCHAR const *pwszfnPolicy,
|
|
OPTIONAL IN WCHAR const *pwszfnOut)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fCoInit = FALSE;
|
|
IEnroll4 *pEnroll = NULL;
|
|
CRYPT_DATA_BLOB blobRequest;
|
|
WCHAR *pwszObjId = NULL;
|
|
DWORD cInfValues;
|
|
INFVALUES *rgInfValues = NULL;
|
|
CRYPT_ATTRIBUTES *rgAttributes = NULL;
|
|
DWORD cAttributes;
|
|
CERT_EXTENSION *rgExt = NULL;
|
|
WCHAR *pwszTemplateName = NULL;
|
|
CERT_CONTEXT const *pccXchg = NULL;
|
|
CERT_CONTEXT const *pccRenewal = NULL;
|
|
CERT_CONTEXT const *pccSigner = NULL;
|
|
CERT_NAME_BLOB NameBlob;
|
|
WCHAR *pwszDN = NULL;
|
|
DWORD cExt = 0;
|
|
DWORD i;
|
|
DWORD j;
|
|
DWORD k;
|
|
DWORD RequestTypeFlags;
|
|
BOOL fRequestTypeSet;
|
|
BOOL fKeyUsageSet;
|
|
|
|
blobRequest.pbData = NULL;
|
|
NameBlob.pbData = NULL;
|
|
cAttributes = 0;
|
|
|
|
hr = ParseRequestInfo(
|
|
pwszAttributes,
|
|
pwszfnPolicy,
|
|
&rgInfValues,
|
|
&cInfValues,
|
|
&rgAttributes,
|
|
&cAttributes,
|
|
&rgExt,
|
|
&cExt,
|
|
&pwszTemplateName);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnPolicy);
|
|
_JumpError(hr, error, "ParseRequestInfo");
|
|
}
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
_JumpError(hr, error, "CoInitialize");
|
|
}
|
|
fCoInit = TRUE;
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_CEnroll,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IEnroll4,
|
|
(VOID **) &pEnroll);
|
|
_JumpIfError(hr, error, "CoCreateInstance");
|
|
|
|
fKeyUsageSet = FALSE;
|
|
fRequestTypeSet = FALSE;
|
|
RequestTypeFlags = XECR_PKCS10_V2_0;
|
|
for (i = 0; i < cInfValues; i++)
|
|
{
|
|
INFVALUES *pInfValues = &rgInfValues[i];
|
|
WCHAR const *pwszInfValue;
|
|
LONG lFlagsT;
|
|
BOOL fT;
|
|
BOOL fValid;
|
|
|
|
if (1 != pInfValues->cValues)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorStringInf(pwszfnPolicy, pInfValues);
|
|
_JumpError(hr, error, "Wrong value count");
|
|
}
|
|
|
|
pwszInfValue = pInfValues->rgpwszValues[0];
|
|
if (NULL == pwszDN &&
|
|
0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_SUBJECT))
|
|
{
|
|
// Reverse the name for XEnroll!?
|
|
|
|
hr = myCertStrToName(
|
|
X509_ASN_ENCODING,
|
|
pwszInfValue, // pszX500
|
|
0, // CERT_NAME_STR_REVERSE_FLAG,
|
|
NULL, // pvReserved
|
|
&NameBlob.pbData,
|
|
&NameBlob.cbData,
|
|
NULL); // ppszError
|
|
_JumpIfError(hr, error, "myCertStrToName");
|
|
|
|
hr = myCertNameToStr(
|
|
X509_ASN_ENCODING,
|
|
&NameBlob,
|
|
CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
|
|
&pwszDN);
|
|
_JumpIfError(hr, error, "myCertNameToStr");
|
|
}
|
|
else
|
|
if (NULL == pccXchg &&
|
|
0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_PRIVATEKEYARCHIVE))
|
|
{
|
|
hr = GetCAXchgCert(pwszInfValue, &pccXchg);
|
|
_JumpIfError(hr, error, "GetCAXchgCert");
|
|
}
|
|
else
|
|
if (NULL == pccRenewal &&
|
|
0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_RENEWALCERT))
|
|
{
|
|
hr = GetRenewalCert(pwszInfValue, &pccRenewal);
|
|
_JumpIfError(hr, error, "GetRenewalCert");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_KEYSPEC))
|
|
{
|
|
DWORD dwKeySpec;
|
|
|
|
dwKeySpec = myWtoI(pwszInfValue, &fValid);
|
|
if (!fValid ||
|
|
(AT_SIGNATURE != dwKeySpec && AT_KEYEXCHANGE != dwKeySpec))
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorStringInf(pwszfnPolicy, pInfValues);
|
|
_JumpError(hr, error, "Bad KeySpec value");
|
|
}
|
|
hr = pEnroll->put_KeySpec(dwKeySpec);
|
|
_JumpIfError(hr, error, "put_KeySpec");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_KEYLENGTH))
|
|
{
|
|
DWORD dwKeyLength;
|
|
|
|
dwKeyLength = myWtoI(pwszInfValue, &fValid);
|
|
if (!fValid || 0 == dwKeyLength || 64 * 1024 <= dwKeyLength)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorStringInf(pwszfnPolicy, pInfValues);
|
|
_JumpError(hr, error, "Bad KeyLength value");
|
|
}
|
|
hr = pEnroll->get_GenKeyFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_GenKeyFlags");
|
|
|
|
lFlagsT &= ~KEY_LENGTH_MASK;
|
|
lFlagsT |= dwKeyLength << 16;
|
|
|
|
hr = pEnroll->put_GenKeyFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_GenKeyFlags");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_EXPORTABLE))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->get_GenKeyFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_GenKeyFlags");
|
|
|
|
lFlagsT &= ~CRYPT_EXPORTABLE;
|
|
lFlagsT |= fT? CRYPT_EXPORTABLE : 0;
|
|
|
|
hr = pEnroll->put_GenKeyFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_GenKeyFlags");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_USERPROTECTED))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->get_GenKeyFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_GenKeyFlags");
|
|
|
|
lFlagsT &= ~CRYPT_USER_PROTECTED;
|
|
lFlagsT |= fT? CRYPT_USER_PROTECTED : 0;
|
|
|
|
hr = pEnroll->put_GenKeyFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_GenKeyFlags");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_KEYCONTAINER))
|
|
{
|
|
hr = pEnroll->put_ContainerNameWStr(
|
|
const_cast<WCHAR *>(pwszInfValue));
|
|
_JumpIfError(hr, error, "put_ContainerNameWStr");
|
|
}
|
|
#if 0
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_HASHALGID))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->get_GenKeyFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_GenKeyFlags");
|
|
|
|
lFlagsT &= ~CRYPT_EXPORTABLE;
|
|
lFlagsT |= fT? CRYPT_EXPORTABLE : 0;
|
|
|
|
hr = pEnroll->put_GenKeyFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_GenKeyFlags");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_HASHALGORITHM))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->get_GenKeyFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_GenKeyFlags");
|
|
|
|
lFlagsT &= ~CRYPT_EXPORTABLE;
|
|
lFlagsT |= fT? CRYPT_EXPORTABLE : 0;
|
|
|
|
hr = pEnroll->put_GenKeyFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_GenKeyFlags");
|
|
}
|
|
#endif
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_MACHINEKEYSET))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->get_ProviderFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_ProviderFlags");
|
|
|
|
lFlagsT &= ~CRYPT_MACHINE_KEYSET;
|
|
lFlagsT |= fT? CRYPT_MACHINE_KEYSET : 0;
|
|
|
|
hr = pEnroll->put_ProviderFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_ProviderFlags");
|
|
|
|
hr = pEnroll->get_MyStoreFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_MyStoreFlags");
|
|
|
|
lFlagsT &= ~(CERT_SYSTEM_STORE_CURRENT_USER |
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE);
|
|
lFlagsT |= fT? CERT_SYSTEM_STORE_LOCAL_MACHINE :
|
|
CERT_SYSTEM_STORE_CURRENT_USER;
|
|
|
|
hr = pEnroll->put_MyStoreFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_MyStoreFlags");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_SILENT))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->get_ProviderFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_ProviderFlags");
|
|
|
|
lFlagsT &= ~CRYPT_SILENT;
|
|
lFlagsT |= fT? CRYPT_SILENT : 0;
|
|
|
|
hr = pEnroll->put_ProviderFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_ProviderFlags");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_PROVIDERNAME))
|
|
{
|
|
hr = pEnroll->put_ProviderNameWStr(
|
|
const_cast<WCHAR *>(pwszInfValue));
|
|
_JumpIfError(hr, error, "put_ProviderNameWStr");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_PROVIDERTYPE))
|
|
{
|
|
lFlagsT = myWtoI(pwszInfValue, &fValid);
|
|
if (!fValid)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorStringInf(pwszfnPolicy, pInfValues);
|
|
_JumpError(hr, error, "Bad ProviderType value");
|
|
}
|
|
hr = pEnroll->put_ProviderType(lFlagsT);
|
|
_JumpIfError(hr, error, "put_ProviderType");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_USEEXISTINGKEYSET))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->put_UseExistingKeySet(fT);
|
|
_JumpIfError(hr, error, "put_UseExistingKeySet");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_SMIME))
|
|
{
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fT);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->put_EnableSMIMECapabilities(fT);
|
|
_JumpIfError(hr, error, "put_EnableSMIMECapabilities");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_REQUESTERNAME))
|
|
{
|
|
hr = pEnroll->AddNameValuePairToSignatureWStr(
|
|
wszINFKEY_REQUESTERNAME,
|
|
const_cast<WCHAR *>(pwszInfValue));
|
|
_JumpIfError(hr, error, "AddNameValuePairToSignatureWStr");
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_REQUESTTYPE))
|
|
{
|
|
if (0 == LSTRCMPIS(pwszInfValue, wszINFVALUE_REQUESTTYPE_PKCS101))
|
|
{
|
|
RequestTypeFlags = XECR_PKCS10_V1_5;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszInfValue, wszINFVALUE_REQUESTTYPE_PKCS10))
|
|
{
|
|
RequestTypeFlags = XECR_PKCS10_V2_0;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszInfValue, wszINFVALUE_REQUESTTYPE_PKCS7))
|
|
{
|
|
RequestTypeFlags = XECR_PKCS7;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pwszInfValue, wszINFVALUE_REQUESTTYPE_CMC))
|
|
{
|
|
RequestTypeFlags = XECR_CMC;
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorStringInf(pwszfnPolicy, pInfValues);
|
|
_JumpErrorStr(hr, error, "Bad RequestType value", pwszInfValue);
|
|
}
|
|
fRequestTypeSet = TRUE;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_KEYUSAGE))
|
|
{
|
|
CRYPT_BIT_BLOB KeyUsage;
|
|
CRYPT_DATA_BLOB BlobKeyUsage;
|
|
|
|
lFlagsT = myWtoI(pwszInfValue, &fValid);
|
|
if (!fValid)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorStringInf(pwszfnPolicy, pInfValues);
|
|
_JumpError(hr, error, "Bad KeyUsage value");
|
|
}
|
|
KeyUsage.cbData = sizeof(lFlagsT);
|
|
KeyUsage.pbData = (BYTE *) &lFlagsT;
|
|
KeyUsage.cUnusedBits = 0;
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_KEY_USAGE,
|
|
&KeyUsage,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&BlobKeyUsage.pbData,
|
|
&BlobKeyUsage.cbData))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "Policy:myEncodeObject");
|
|
}
|
|
|
|
hr = pEnroll->addExtensionToRequestWStr(
|
|
0,
|
|
TEXT(szOID_KEY_USAGE),
|
|
&BlobKeyUsage);
|
|
LocalFree(BlobKeyUsage.pbData);
|
|
_JumpIfError(hr, error, "addExtensionToRequestWStr");
|
|
|
|
fKeyUsageSet = TRUE;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(pInfValues->pwszKey, wszINFKEY_ENCIPHERONLY))
|
|
{
|
|
BOOL fEnciperOnly;
|
|
|
|
hr = myInfParseBooleanValue(pwszInfValue, &fEnciperOnly);
|
|
_JumpIfError(hr, error, "myInfParseBooleanValue");
|
|
|
|
hr = pEnroll->put_LimitExchangeKeyToEncipherment(fEnciperOnly);
|
|
_JumpIfError(hr, error, "put_LimitExchangeKeyToEncipherment");
|
|
}
|
|
else
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
SetErrorStringInf(pwszfnPolicy, pInfValues);
|
|
_JumpErrorStr(hr, error, "bad Inf key", pInfValues->pwszKey);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < cAttributes; i++)
|
|
{
|
|
CRYPT_ATTRIBUTES *pAttributes = &rgAttributes[i];
|
|
|
|
for (j = 0; j < pAttributes->cAttr; j++)
|
|
{
|
|
CRYPT_ATTRIBUTE *pAttr = &pAttributes->rgAttr[j];
|
|
|
|
if (NULL != pwszObjId)
|
|
{
|
|
LocalFree(pwszObjId);
|
|
pwszObjId = NULL;
|
|
}
|
|
if (!ConvertSzToWsz(&pwszObjId, pAttr->pszObjId, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertSzToWsz");
|
|
}
|
|
for (k = 0; k < pAttr->cValue; k++)
|
|
{
|
|
hr = pEnroll->addAttributeToRequestWStr(
|
|
0, // Flags
|
|
pwszObjId,
|
|
&pAttr->rgValue[k]);
|
|
_JumpIfError(hr, error, "addAttributeToRequestWStr");
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < cExt; i++)
|
|
{
|
|
CERT_EXTENSION *pExt = &rgExt[i];
|
|
|
|
if (fKeyUsageSet && 0 == strcmp(szOID_KEY_USAGE, pExt->pszObjId))
|
|
{
|
|
continue;
|
|
}
|
|
if (NULL != pwszObjId)
|
|
{
|
|
LocalFree(pwszObjId);
|
|
pwszObjId = NULL;
|
|
}
|
|
if (!ConvertSzToWsz(&pwszObjId, pExt->pszObjId, -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertSzToWsz");
|
|
}
|
|
hr = pEnroll->addExtensionToRequestWStr(
|
|
pExt->fCritical,
|
|
pwszObjId,
|
|
&pExt->Value);
|
|
_JumpIfError(hr, error, "addExtensionToRequestWStr");
|
|
}
|
|
|
|
if (NULL != g_pwszCertCN)
|
|
{
|
|
if (!g_fQuiet || NULL != g_pwszCertCN)
|
|
{
|
|
hr = myGetCertificateFromPicker(
|
|
g_hInstance,
|
|
NULL, // hwndParent
|
|
IDS_GETSIGNINGCERT_TITLE,
|
|
IDS_GETSIGNINGCERT_SUBTITLE,
|
|
CUCS_MYSTORE |
|
|
CUCS_PRIVATEKEYREQUIRED |
|
|
(g_fQuiet? CUCS_SILENT : 0),
|
|
(L'\0' == g_pwszCertCN || 0 == lstrcmp(L"*", g_pwszCertCN))?
|
|
NULL : g_pwszCertCN, // pwszCommonName
|
|
0, // cStore
|
|
NULL, // rghStore
|
|
0, // cpszObjId
|
|
NULL, // apszObjId
|
|
&pccSigner);
|
|
_JumpIfError(hr, error, "myGetCertificateFromPicker");
|
|
}
|
|
|
|
// pccSigner is NULL if the user cancelled out of the cert picker U/I.
|
|
|
|
if (NULL == pccSigner)
|
|
{
|
|
if (g_fQuiet || NULL != g_pwszCertCN)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpError(hr, error, "no matching signer CN");
|
|
}
|
|
}
|
|
hr = pEnroll->SetSignerCertificate(pccSigner);
|
|
_JumpIfError(hr, error, "SetSignerCertificate");
|
|
}
|
|
if (NULL != pccXchg)
|
|
{
|
|
LONG lGenKeyFlags;
|
|
|
|
hr = pEnroll->SetPrivateKeyArchiveCertificate(pccXchg);
|
|
_JumpIfError(hr, error, "SetPrivateKeyArchiveCertificate");
|
|
|
|
hr = pEnroll->get_GenKeyFlags(&lGenKeyFlags);
|
|
_JumpIfError(hr, error, "getGenKeyFlags");
|
|
|
|
if (0 == (CRYPT_EXPORTABLE & lGenKeyFlags))
|
|
{
|
|
hr = pEnroll->put_GenKeyFlags(CRYPT_EXPORTABLE | lGenKeyFlags);
|
|
_JumpIfError(hr, error, "putGenKeyFlags");
|
|
}
|
|
}
|
|
if (NULL != pccRenewal)
|
|
{
|
|
hr = pEnroll->put_RenewalCertificate(pccRenewal);
|
|
_JumpIfError(hr, error, "put_RenewalCertificate");
|
|
}
|
|
if (!fRequestTypeSet)
|
|
{
|
|
if (NULL != pccXchg)
|
|
{
|
|
RequestTypeFlags = XECR_CMC;
|
|
}
|
|
else if (NULL != pccRenewal)
|
|
{
|
|
RequestTypeFlags = XECR_PKCS7;
|
|
}
|
|
}
|
|
hr = pEnroll->createRequestWStr(
|
|
RequestTypeFlags,
|
|
pwszDN,
|
|
NULL,
|
|
&blobRequest);
|
|
_JumpIfError(hr, error, "createRequestWStr");
|
|
|
|
myRegisterMemAlloc(blobRequest.pbData, blobRequest.cbData, CSM_LOCALALLOC);
|
|
|
|
hr = WriteCertificateOrRequest(
|
|
hWndOwner,
|
|
NULL, // pdiRequest
|
|
blobRequest.pbData,
|
|
blobRequest.cbData,
|
|
g_dwOutFormat,
|
|
IDS_REQUEST_OUTFILE_TITLE,
|
|
IDS_REQUEST_FILE_FILTER,
|
|
IDS_REQUEST_FILE_DEFEXT,
|
|
pwszfnOut);
|
|
_JumpIfError(hr, error, "WriteCertificateOrRequest");
|
|
|
|
error:
|
|
if (NULL != pwszDN)
|
|
{
|
|
LocalFree(pwszDN);
|
|
}
|
|
if (NULL != NameBlob.pbData)
|
|
{
|
|
LocalFree(NameBlob.pbData);
|
|
}
|
|
if (NULL != pccXchg)
|
|
{
|
|
CertFreeCertificateContext(pccXchg);
|
|
}
|
|
if (NULL != pccRenewal)
|
|
{
|
|
CertFreeCertificateContext(pccRenewal);
|
|
}
|
|
if (NULL != pccSigner)
|
|
{
|
|
CertFreeCertificateContext(pccSigner);
|
|
}
|
|
if (NULL != rgInfValues)
|
|
{
|
|
myInfFreeSectionValues(cInfValues, rgInfValues);
|
|
}
|
|
if (NULL != rgAttributes)
|
|
{
|
|
FreeAttributes(cAttributes, rgAttributes);
|
|
}
|
|
if (NULL != rgExt)
|
|
{
|
|
FreeExtensions(TRUE, cExt, rgExt);
|
|
}
|
|
if (NULL != pwszTemplateName)
|
|
{
|
|
LocalFree(pwszTemplateName);
|
|
}
|
|
if (NULL != pwszObjId)
|
|
{
|
|
LocalFree(pwszObjId);
|
|
}
|
|
if (NULL != blobRequest.pbData)
|
|
{
|
|
LocalFree(blobRequest.pbData);
|
|
}
|
|
if (NULL != pEnroll)
|
|
{
|
|
pEnroll->Release();
|
|
}
|
|
if (fCoInit)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
MakePKCS7FromCert(
|
|
IN BYTE const *pbCert,
|
|
IN DWORD cbCert,
|
|
OUT BYTE **ppbChain,
|
|
OUT DWORD *pcbChain)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pcc = NULL;
|
|
CRYPT_SIGN_MESSAGE_PARA csmp;
|
|
CRYPT_ALGORITHM_IDENTIFIER DigestAlgorithm = { szOID_OIWSEC_sha1, 0, 0 };
|
|
|
|
*ppbChain = NULL;
|
|
pcc = CertCreateCertificateContext(X509_ASN_ENCODING, pbCert, cbCert);
|
|
if (NULL == pcc)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
|
|
// init csmp for empty signature
|
|
|
|
ZeroMemory(&csmp, sizeof(csmp));
|
|
csmp.cbSize = sizeof(csmp);
|
|
csmp.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
|
|
//csmp.pSigningCert = NULL;
|
|
csmp.HashAlgorithm = DigestAlgorithm;
|
|
csmp.cMsgCert = 1;
|
|
csmp.rgpMsgCert = &pcc;
|
|
//csmp.cMsgCrl = 0;
|
|
//csmp.rgpMsgCrl = NULL;
|
|
|
|
if (!myCryptSignMessage(
|
|
&csmp,
|
|
pbCert, // pbToBeSigned
|
|
cbCert, // cbToBeSigned
|
|
CERTLIB_USE_LOCALALLOC,
|
|
ppbChain,
|
|
pcbChain))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myCryptSignMessage");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pcc)
|
|
{
|
|
CertFreeCertificateContext(pcc);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AcceptResponse(
|
|
IN WCHAR const *pwszfnIn)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszMsg = NULL;
|
|
WCHAR awchr[cwcHRESULTSTRING];
|
|
CRYPT_DATA_BLOB blobIn;
|
|
CRYPT_DATA_BLOB blobCert7;
|
|
char *pszInnerContentObjId = NULL;
|
|
DWORD dwType;
|
|
BYTE *pbDecoded = NULL;
|
|
DWORD cb;
|
|
BOOL fCoInit = FALSE;
|
|
IEnroll4 *pEnroll = NULL;
|
|
|
|
blobIn.pbData = NULL;
|
|
blobCert7.pbData = NULL;
|
|
hr = DecodeFileW(
|
|
pwszfnIn,
|
|
&blobIn.pbData,
|
|
&blobIn.cbData,
|
|
CRYPT_STRING_BASE64_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
if (S_OK == myLoadRCString(
|
|
g_hInstance,
|
|
IDS_FORMATSTR_DECODE_ERR,
|
|
&pwszMsg))
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(pwszMsg, myHResultToString(awchr, hr));
|
|
wprintf(g_wszNewLine);
|
|
}
|
|
goto error;
|
|
}
|
|
|
|
dwType = CR_IN_CERT;
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_TO_BE_SIGNED,
|
|
blobIn.pbData,
|
|
blobIn.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pbDecoded,
|
|
&cb))
|
|
{
|
|
//_PrintError(myHLastError(), "myDecodeObject(Cert)");
|
|
CSASSERT(NULL == pbDecoded);
|
|
|
|
dwType = CR_IN_PKCS7; // PKCS 7 renewal request?
|
|
hr = myDecodePKCS7(
|
|
blobIn.pbData,
|
|
blobIn.cbData,
|
|
NULL, // ppbContents
|
|
NULL, // pcbContents
|
|
NULL, // pdwMsgType
|
|
&pszInnerContentObjId,
|
|
NULL, // pcSigner
|
|
NULL, // pcRecipient
|
|
NULL, // phStore
|
|
NULL); // phMsg
|
|
_JumpIfError(hr, error, "myDecodePKCS7");
|
|
|
|
if (NULL != pszInnerContentObjId &&
|
|
0 == strcmp(pszInnerContentObjId, szOID_CT_PKI_RESPONSE))
|
|
{
|
|
dwType = CR_IN_CMC;
|
|
}
|
|
}
|
|
if (CR_IN_CERT == dwType)
|
|
{
|
|
hr = MakePKCS7FromCert(
|
|
blobIn.pbData,
|
|
blobIn.cbData,
|
|
&blobCert7.pbData,
|
|
&blobCert7.cbData);
|
|
_JumpIfError(hr, error, "MakePKCS7FromCert");
|
|
}
|
|
|
|
hr = CoInitialize(NULL);
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
_JumpError(hr, error, "CoInitialize");
|
|
}
|
|
fCoInit = TRUE;
|
|
|
|
hr = CoCreateInstance(
|
|
CLSID_CEnroll,
|
|
NULL, // pUnkOuter
|
|
CLSCTX_INPROC_SERVER,
|
|
IID_IEnroll4,
|
|
(VOID **) &pEnroll);
|
|
_JumpIfError(hr, error, "CoCreateInstance");
|
|
|
|
if (CR_IN_CMC == dwType)
|
|
{
|
|
hr = pEnroll->acceptResponseBlob(&blobIn);
|
|
_PrintIfError2(hr, "acceptResponseBlob", CRYPT_E_NOT_FOUND);
|
|
}
|
|
else
|
|
{
|
|
hr = pEnroll->acceptPKCS7Blob(
|
|
NULL != blobCert7.pbData? &blobCert7 : &blobIn);
|
|
_PrintIfError2(hr, "acceptPKCS7Blob", CRYPT_E_NOT_FOUND);
|
|
}
|
|
if (S_OK != hr)
|
|
{
|
|
HRESULT hr2 = hr;
|
|
LONG lFlagsT;
|
|
BOOL fT;
|
|
|
|
hr = pEnroll->get_ProviderFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_ProviderFlags");
|
|
|
|
fT = 0 == (CRYPT_MACHINE_KEYSET & lFlagsT);
|
|
lFlagsT &= ~CRYPT_MACHINE_KEYSET;
|
|
lFlagsT |= fT? CRYPT_MACHINE_KEYSET : 0;
|
|
|
|
hr = pEnroll->put_ProviderFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_ProviderFlags");
|
|
|
|
hr = pEnroll->get_MyStoreFlags(&lFlagsT);
|
|
_JumpIfError(hr, error, "get_MyStoreFlags");
|
|
|
|
lFlagsT &= ~(CERT_SYSTEM_STORE_CURRENT_USER |
|
|
CERT_SYSTEM_STORE_LOCAL_MACHINE);
|
|
lFlagsT |= fT? CERT_SYSTEM_STORE_LOCAL_MACHINE :
|
|
CERT_SYSTEM_STORE_CURRENT_USER;
|
|
|
|
hr = pEnroll->put_MyStoreFlags(lFlagsT);
|
|
_JumpIfError(hr, error, "put_MyStoreFlags");
|
|
|
|
if (CR_IN_CMC == dwType)
|
|
{
|
|
hr = pEnroll->acceptResponseBlob(&blobIn);
|
|
_PrintIfError(hr, "acceptResponseBlob");
|
|
}
|
|
else
|
|
{
|
|
hr = pEnroll->acceptPKCS7Blob(
|
|
NULL != blobCert7.pbData? &blobCert7 : &blobIn);
|
|
_PrintIfError(hr, "acceptPKCS7Blob");
|
|
}
|
|
|
|
// If accepting the response in machine context didn't work, return the
|
|
// first error (the user context error).
|
|
|
|
if (S_OK != hr)
|
|
{
|
|
hr = hr2;
|
|
}
|
|
_JumpIfError(hr, error, "AcceptResponse");
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszMsg)
|
|
{
|
|
LocalFree(pwszMsg);
|
|
}
|
|
if (NULL != blobIn.pbData)
|
|
{
|
|
LocalFree(blobIn.pbData);
|
|
}
|
|
if (NULL != blobCert7.pbData)
|
|
{
|
|
LocalFree(blobCert7.pbData);
|
|
}
|
|
if (NULL != pszInnerContentObjId)
|
|
{
|
|
LocalFree(pszInnerContentObjId);
|
|
}
|
|
if (NULL != pbDecoded)
|
|
{
|
|
LocalFree(pbDecoded);
|
|
}
|
|
if (NULL != pEnroll)
|
|
{
|
|
pEnroll->Release();
|
|
}
|
|
if (fCoInit)
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
ArgvMain(
|
|
int argc,
|
|
WCHAR *argv[],
|
|
HWND hWndOwner)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszOFN = NULL;
|
|
WCHAR *pwszOFN2 = NULL;
|
|
WCHAR const *pwszfnIn;
|
|
WCHAR const *pwszfnOut;
|
|
WCHAR const *pwszfnPKCS10;
|
|
WCHAR const *pwszfnCertChain;
|
|
WCHAR const *pwszfnFullResponse;
|
|
WCHAR const *pwszfnPolicy;
|
|
LONG RequestId;
|
|
WCHAR *pwszAttributes = NULL;
|
|
WCHAR const *pwszSerialNumber = NULL;
|
|
DWORD cCommand = 0;
|
|
int cArgMax = 0;
|
|
WCHAR *rgpwszArg[4];
|
|
UINT idsFileFilter;
|
|
UINT idsFileDefExt;
|
|
|
|
myVerifyResourceStrings(g_hInstance);
|
|
while (1 < argc && myIsSwitchChar(argv[1][0]))
|
|
{
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"config"))
|
|
{
|
|
if (2 >= argc)
|
|
{
|
|
_PrintError(E_INVALIDARG, "missing -config arg");
|
|
Usage(TRUE);
|
|
}
|
|
if (myIsMinusSignString(argv[2]) || 0 == wcscmp(argv[2], L"*"))
|
|
{
|
|
g_dwUIFlag = CC_LOCALACTIVECONFIG;
|
|
}
|
|
else
|
|
{
|
|
g_pwszConfig = argv[2];
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"any"))
|
|
{
|
|
g_fAny = TRUE;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"crl"))
|
|
{
|
|
g_dwCRLIn = CR_IN_CRLS;
|
|
g_dwCRLOut = CR_OUT_CRLS;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"rpc"))
|
|
{
|
|
g_fRPC++;
|
|
if (0 == lstrcmp(&argv[1][1], L"RPC"))
|
|
{
|
|
g_fRPC++;
|
|
}
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"binary"))
|
|
{
|
|
g_dwOutFormat = CR_OUT_BINARY;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"idispatch"))
|
|
{
|
|
g_fIDispatch = TRUE;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"submit"))
|
|
{
|
|
g_dwCommand = cmdSUBMITREQUEST;
|
|
cArgMax = 4;
|
|
cCommand++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"retrieve"))
|
|
{
|
|
g_dwCommand = cmdRETRIEVEPENDING;
|
|
cArgMax = 4;
|
|
cCommand++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"policy"))
|
|
{
|
|
g_dwCommand = cmdQUALIFIEDREQUEST;
|
|
cArgMax = 4;
|
|
cCommand++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"new"))
|
|
{
|
|
g_dwCommand = cmdNEWREQUEST;
|
|
cArgMax = 2;
|
|
cCommand++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"accept"))
|
|
{
|
|
g_dwCommand = cmdACCEPTRESPONSE;
|
|
cArgMax = 1;
|
|
cCommand++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"sign"))
|
|
{
|
|
g_dwCommand = cmdSIGNREQUEST;
|
|
cArgMax = 2;
|
|
cCommand++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"v1"))
|
|
{
|
|
g_fV1Interface = TRUE;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"v"))
|
|
{
|
|
g_fVerbose = TRUE;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"f"))
|
|
{
|
|
g_fForce++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"q"))
|
|
{
|
|
g_fQuiet = TRUE;
|
|
g_dwUIFlag = CC_LOCALACTIVECONFIG;
|
|
}
|
|
else
|
|
if (0 == lstrcmp(&argv[1][1], L"?") ||
|
|
0 == LSTRCMPIS(&argv[1][1], L"usage"))
|
|
{
|
|
g_fFullUsage = 0 == lstrcmp(&argv[1][1], L"uSAGE");
|
|
Usage(FALSE);
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"attrib"))
|
|
{
|
|
if (2 >= argc)
|
|
{
|
|
_PrintError(E_INVALIDARG, "missing -attrib arg");
|
|
Usage(TRUE);
|
|
}
|
|
hr = crCombineAttributes(argv[2], &pwszAttributes);
|
|
_JumpIfError(hr, error, "crCombineAttributes");
|
|
|
|
argc--;
|
|
argv++;
|
|
}
|
|
else
|
|
if (0 == LSTRCMPIS(&argv[1][1], L"cert"))
|
|
{
|
|
if (2 >= argc)
|
|
{
|
|
_PrintError(E_INVALIDARG, "missing -cert arg");
|
|
Usage(TRUE);
|
|
}
|
|
g_pwszCertCN = argv[2];
|
|
argc--;
|
|
argv++;
|
|
}
|
|
else
|
|
{
|
|
_PrintError(E_INVALIDARG, "Unknown arg");
|
|
Usage(TRUE);
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
|
|
if (1 < cCommand)
|
|
{
|
|
_PrintError(E_INVALIDARG, "multiple commands");
|
|
Usage(TRUE);
|
|
}
|
|
if (cmdNONE == g_dwCommand)
|
|
{
|
|
g_dwCommand = cmdSUBMITREQUEST;
|
|
cArgMax = 4;
|
|
}
|
|
if (NULL != pwszAttributes &&
|
|
cmdSUBMITREQUEST != g_dwCommand &&
|
|
cmdNEWREQUEST != g_dwCommand &&
|
|
cmdQUALIFIEDREQUEST != g_dwCommand)
|
|
{
|
|
_PrintError(E_INVALIDARG, "unexpected -attrib arg");
|
|
Usage(TRUE);
|
|
}
|
|
if (NULL != g_pwszCertCN &&
|
|
cmdSIGNREQUEST != g_dwCommand &&
|
|
cmdQUALIFIEDREQUEST != g_dwCommand &&
|
|
cmdNEWREQUEST != g_dwCommand)
|
|
{
|
|
_PrintError(E_INVALIDARG, "unexpected -cert arg");
|
|
Usage(TRUE);
|
|
}
|
|
|
|
if (1 + cArgMax < argc)
|
|
{
|
|
_PrintError(E_INVALIDARG, "Extra args");
|
|
Usage(TRUE);
|
|
}
|
|
|
|
CSASSERT(ARRAYSIZE(rgpwszArg) >= cArgMax);
|
|
ZeroMemory(rgpwszArg, sizeof(rgpwszArg));
|
|
|
|
if (1 < argc)
|
|
{
|
|
rgpwszArg[0] = argv[1];
|
|
if (2 < argc)
|
|
{
|
|
rgpwszArg[1] = argv[2];
|
|
if (3 < argc)
|
|
{
|
|
rgpwszArg[2] = argv[3];
|
|
if (4 < argc)
|
|
{
|
|
rgpwszArg[3] = argv[4];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// cmdSUBMITREQUEST:
|
|
// [RequestFile [CertFile [CertChainFile [FullResponseFile]]]]
|
|
//
|
|
// cmdRETRIEVEPENDING:
|
|
// [RequestId [CertFile [CertChainFile [FullResponseFile]]]]
|
|
//
|
|
// cmdNEWREQUEST
|
|
// [PolicyFile [RequestFileOut]]
|
|
//
|
|
// cmdACCEPTRESPONSE
|
|
// [CertFile | CertChainFile | FullResponseFile]
|
|
//
|
|
// cmdQUALIFIEDREQUEST (accept RequestFile and PolicyFile in either order)
|
|
// [RequestFile [PolicyFile [RequestFileOut [PKCS10FileOut]]]
|
|
//
|
|
// cmdSIGNREQUEST:
|
|
// [RequestFile [RequestFileOut]]
|
|
//
|
|
|
|
pwszfnIn = NULL;
|
|
pwszfnOut = NULL;
|
|
pwszfnPKCS10 = NULL;
|
|
pwszfnCertChain = NULL;
|
|
pwszfnFullResponse = NULL;
|
|
pwszfnPolicy = NULL;
|
|
|
|
pwszfnIn = rgpwszArg[0];
|
|
idsFileFilter = IDS_REQUEST_FILE_FILTER;
|
|
idsFileDefExt = IDS_REQUEST_FILE_DEFEXT;
|
|
|
|
switch (g_dwCommand)
|
|
{
|
|
case cmdRETRIEVEPENDING:
|
|
idsFileFilter = 0; // disable file open dialog
|
|
// FALLTHROUGH
|
|
case cmdSUBMITREQUEST:
|
|
pwszfnOut = rgpwszArg[1];
|
|
pwszfnCertChain = rgpwszArg[2];
|
|
pwszfnFullResponse = rgpwszArg[3];
|
|
break;
|
|
|
|
case cmdNEWREQUEST:
|
|
pwszfnIn = NULL;
|
|
pwszfnPolicy = rgpwszArg[0];
|
|
pwszfnOut = rgpwszArg[1];
|
|
CSASSERT(NULL == rgpwszArg[2]);
|
|
idsFileFilter = 0; // disable file open dialog
|
|
break;
|
|
|
|
case cmdACCEPTRESPONSE:
|
|
CSASSERT(NULL == rgpwszArg[1]);
|
|
idsFileFilter = IDS_RESPONSE_FILE_FILTER;
|
|
idsFileDefExt = IDS_RESPONSE_FILE_DEFEXT;
|
|
break;
|
|
|
|
case cmdQUALIFIEDREQUEST:
|
|
pwszfnPolicy = rgpwszArg[1];
|
|
pwszfnOut = rgpwszArg[2];
|
|
pwszfnPKCS10 = rgpwszArg[3];
|
|
idsFileFilter = IDS_REQUEST_FILE_FILTER;
|
|
break;
|
|
|
|
default:
|
|
CSASSERT(cmdSIGNREQUEST == g_dwCommand);
|
|
pwszfnOut = rgpwszArg[1];
|
|
CSASSERT(NULL == rgpwszArg[2]);
|
|
CSASSERT(NULL == rgpwszArg[3]);
|
|
break;
|
|
}
|
|
|
|
RequestId = 0;
|
|
if (cmdRETRIEVEPENDING == g_dwCommand)
|
|
{
|
|
if (NULL == pwszfnIn)
|
|
{
|
|
WCHAR *pwszMsg = NULL;
|
|
hr = myLoadRCString(
|
|
g_hInstance,
|
|
IDS_ERROR_NO_REQUESTID,
|
|
&pwszMsg);
|
|
if (S_OK == hr)
|
|
{
|
|
CSASSERT(NULL != pwszMsg);
|
|
wprintf(pwszMsg);
|
|
wprintf(g_wszNewLine);
|
|
LocalFree(pwszMsg);
|
|
}
|
|
_PrintError(E_INVALIDARG, "missing RequestId");
|
|
Usage(TRUE);
|
|
}
|
|
hr = GetLong(pwszfnIn, &RequestId);
|
|
if (S_OK != hr || 0 == RequestId)
|
|
{
|
|
RequestId = 0;
|
|
pwszSerialNumber = pwszfnIn;
|
|
}
|
|
pwszfnIn = NULL;
|
|
}
|
|
else
|
|
if (NULL != pwszfnIn && cmdQUALIFIEDREQUEST == g_dwCommand)
|
|
{
|
|
BYTE *pbReq;
|
|
DWORD cbReq;
|
|
LONG dwFlags;
|
|
BOOL fSigned;
|
|
|
|
// accept RequestFile and PolicyFile in either order:
|
|
|
|
hr = CheckRequestType(
|
|
pwszfnIn,
|
|
&pbReq,
|
|
&cbReq,
|
|
&dwFlags,
|
|
&fSigned,
|
|
NULL, // pfCA
|
|
NULL); // ppwszTemplateName
|
|
if (S_OK != hr)
|
|
{
|
|
WCHAR const *pwsz = pwszfnPolicy;
|
|
|
|
pwszfnPolicy = pwszfnIn;
|
|
pwszfnIn = pwsz;
|
|
}
|
|
else
|
|
{
|
|
LocalFree(pbReq);
|
|
}
|
|
}
|
|
if (NULL == pwszfnIn && 0 != idsFileFilter)
|
|
{
|
|
// Put up a file open dialog to get Response, Request or cert file
|
|
|
|
hr = crGetOpenFileName(
|
|
hWndOwner,
|
|
IDS_REQUEST_OPEN_TITLE,
|
|
idsFileFilter,
|
|
idsFileDefExt,
|
|
&pwszOFN);
|
|
_JumpIfError(hr, error, "crGetOpenFileName");
|
|
|
|
pwszfnIn = pwszOFN;
|
|
}
|
|
|
|
if (NULL != pwszfnIn)
|
|
{
|
|
if (!myDoesFileExist(pwszfnIn))
|
|
{
|
|
SetErrorString(pwszfnIn);
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpErrorStr(hr, error, "myDoesFileExist", pwszfnIn);
|
|
}
|
|
}
|
|
if (NULL != pwszfnOut)
|
|
{
|
|
hr = myIsDirWriteable(pwszfnOut, TRUE);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnOut);
|
|
_JumpErrorStr(hr, error, "IsDirWriteable", pwszfnOut);
|
|
}
|
|
}
|
|
|
|
switch (g_dwCommand)
|
|
{
|
|
case cmdRETRIEVEPENDING:
|
|
case cmdSUBMITREQUEST:
|
|
if (CV_OUT_BASE64REQUESTHEADER == g_dwOutFormat)
|
|
{
|
|
g_dwOutFormat = CV_OUT_BASE64HEADER;
|
|
}
|
|
if (NULL != pwszfnCertChain)
|
|
{
|
|
hr = myIsDirWriteable(pwszfnCertChain, TRUE);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnCertChain);
|
|
_JumpErrorStr(hr, error, "IsDirWriteable", pwszfnCertChain);
|
|
}
|
|
}
|
|
if (NULL != pwszfnFullResponse)
|
|
{
|
|
hr = myIsDirWriteable(pwszfnFullResponse, TRUE);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnFullResponse);
|
|
_JumpErrorStr(hr, error, "IsDirWriteable", pwszfnFullResponse);
|
|
}
|
|
}
|
|
hr = SubmitRequest(
|
|
hWndOwner,
|
|
RequestId,
|
|
pwszSerialNumber,
|
|
pwszAttributes,
|
|
pwszfnIn,
|
|
pwszfnOut,
|
|
pwszfnCertChain,
|
|
pwszfnFullResponse);
|
|
_JumpIfError(hr, error, "SubmitRequest");
|
|
|
|
break;
|
|
|
|
case cmdACCEPTRESPONSE:
|
|
hr = AcceptResponse(pwszfnIn);
|
|
_JumpIfError(hr, error, "AcceptResponse");
|
|
|
|
break;
|
|
|
|
case cmdNEWREQUEST:
|
|
case cmdQUALIFIEDREQUEST:
|
|
if (NULL != pwszfnPKCS10)
|
|
{
|
|
hr = myIsDirWriteable(pwszfnPKCS10, TRUE);
|
|
if (S_OK != hr)
|
|
{
|
|
SetErrorString(pwszfnPKCS10);
|
|
_JumpErrorStr(hr, error, "IsDirWriteable", pwszfnPKCS10);
|
|
}
|
|
}
|
|
if (NULL == pwszfnPolicy)
|
|
{
|
|
// Put up a file dialog to prompt the user for Inf File
|
|
|
|
hr = crGetOpenFileName(
|
|
hWndOwner,
|
|
IDS_INF_OPEN_TITLE,
|
|
IDS_INF_FILE_FILTER,
|
|
IDS_INF_FILE_DEFEXT,
|
|
&pwszOFN2);
|
|
_JumpIfError(hr, error, "crGetOpenFileName");
|
|
|
|
pwszfnPolicy = pwszOFN2;
|
|
}
|
|
CSASSERT(NULL != pwszfnPolicy);
|
|
if (!myDoesFileExist(pwszfnPolicy))
|
|
{
|
|
SetErrorString(pwszfnPolicy);
|
|
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
|
|
_JumpErrorStr(hr, error, "myDoesFileExist", pwszfnPolicy);
|
|
}
|
|
if (cmdNEWREQUEST == g_dwCommand)
|
|
{
|
|
hr = CreateNewRequest(
|
|
hWndOwner,
|
|
pwszAttributes,
|
|
pwszfnPolicy,
|
|
pwszfnOut);
|
|
_JumpIfError(hr, error, "CreateNewRequest");
|
|
}
|
|
else
|
|
{
|
|
hr = CreateQualifiedRequest(
|
|
hWndOwner,
|
|
pwszAttributes,
|
|
pwszfnIn,
|
|
pwszfnPolicy,
|
|
pwszfnOut,
|
|
pwszfnPKCS10);
|
|
_JumpIfError(hr, error, "CreateQualifiedRequest");
|
|
}
|
|
break;
|
|
|
|
default:
|
|
CSASSERT(cmdSIGNREQUEST == g_dwCommand);
|
|
if (NULL != pwszfnFullResponse)
|
|
{
|
|
Usage(TRUE);
|
|
}
|
|
hr = SignQualifiedRequest(hWndOwner, pwszfnIn, pwszfnOut);
|
|
_JumpIfError(hr, error, "SignQualifiedRequest");
|
|
|
|
break;
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszAttributes)
|
|
{
|
|
LocalFree(pwszAttributes);
|
|
}
|
|
if (NULL != pwszOFN)
|
|
{
|
|
LocalFree(pwszOFN);
|
|
}
|
|
if (NULL != pwszOFN2)
|
|
{
|
|
LocalFree(pwszOFN2);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
//**************************************************************************
|
|
// FUNCTION: CertReqPreMain
|
|
// NOTES: Based on vich's MkRootMain function; takes an LPSTR command
|
|
// line and chews it up into argc/argv form so that it can be
|
|
// passed on to a traditional C style main.
|
|
//**************************************************************************
|
|
|
|
#define ISBLANK(wc) (L' ' == (wc) || L'\t' == (wc))
|
|
|
|
HRESULT
|
|
CertReqPreMain(
|
|
LPTSTR pszCmdLine,
|
|
HWND hWndOwner)
|
|
{
|
|
WCHAR *pbuf;
|
|
LPTSTR apszArg[20];
|
|
int cArg = 0;
|
|
LPTSTR p;
|
|
WCHAR *pchQuote;
|
|
HRESULT hr;
|
|
|
|
pbuf = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
(wcslen(pszCmdLine) + 1) * sizeof(WCHAR));
|
|
if (NULL == pbuf)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
p = pbuf;
|
|
|
|
apszArg[cArg++] = TEXT("CertReq");
|
|
while (*pszCmdLine != TEXT('\0'))
|
|
{
|
|
while (ISBLANK(*pszCmdLine))
|
|
{
|
|
pszCmdLine++;
|
|
}
|
|
if (*pszCmdLine != TEXT('\0'))
|
|
{
|
|
apszArg[cArg++] = p;
|
|
if (sizeof(apszArg)/sizeof(apszArg[0]) <= cArg)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Too many args");
|
|
}
|
|
|
|
pchQuote = NULL;
|
|
while (*pszCmdLine != L'\0')
|
|
{
|
|
if (NULL != pchQuote)
|
|
{
|
|
if (*pszCmdLine == *pchQuote)
|
|
{
|
|
pszCmdLine++;
|
|
pchQuote = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ISBLANK(*pszCmdLine))
|
|
{
|
|
break;
|
|
}
|
|
if (L'"' == *pszCmdLine)
|
|
{
|
|
pchQuote = pszCmdLine++;
|
|
continue;
|
|
}
|
|
}
|
|
*p++ = *pszCmdLine++;
|
|
}
|
|
|
|
*p++ = TEXT('\0');
|
|
if (*pszCmdLine != TEXT('\0'))
|
|
{
|
|
pszCmdLine++; // skip whitespace or quote character
|
|
}
|
|
}
|
|
}
|
|
apszArg[cArg] = NULL;
|
|
|
|
hr = ArgvMain(cArg, apszArg, hWndOwner);
|
|
_JumpIfError(hr, error, "ArgvMain");
|
|
|
|
error:
|
|
if (NULL != pbuf)
|
|
{
|
|
LocalFree(pbuf);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
CertReqErrorDisplay(
|
|
IN HRESULT hr,
|
|
IN HWND hWnd)
|
|
{
|
|
WCHAR *pwszTitle = NULL;
|
|
WCHAR *pwszMessage = NULL;
|
|
WCHAR *pwszMessage2 = NULL;
|
|
WCHAR const *pwszError = NULL;
|
|
WCHAR *pwszCombinedError = NULL;
|
|
WCHAR const *pwsz;
|
|
|
|
myLoadRCString(g_hInstance, IDS_CERTREQ_TITLE, &pwszTitle);
|
|
if (g_idError)
|
|
{
|
|
myLoadRCString(g_hInstance, g_idError, &pwszMessage);
|
|
}
|
|
pwszError = myGetErrorMessageText(hr, S_OK != hr);
|
|
if (NULL != g_pwszUnreferencedSectionNames)
|
|
{
|
|
myLoadRCString(
|
|
g_hInstance,
|
|
IDS_UNREFERENCED_INF_SECTIONS,
|
|
&pwszMessage2);
|
|
}
|
|
|
|
// Eliminate redundant error message text. If the client and server
|
|
// localized error message text differ, both will still be displayed.
|
|
|
|
if (NULL != pwszError && NULL != g_pwszErrorString)
|
|
{
|
|
if (NULL != wcsstr(g_pwszErrorString, pwszError))
|
|
{
|
|
LocalFree(const_cast<WCHAR *>(pwszError));
|
|
pwszError = NULL;
|
|
}
|
|
}
|
|
|
|
pwsz = NULL;
|
|
if (NULL != pwszMessage ||
|
|
NULL != pwszError ||
|
|
NULL != g_pwszErrorString ||
|
|
NULL != g_pwszInfErrorString ||
|
|
NULL != g_pwszUnreferencedSectionNames)
|
|
{
|
|
DWORD cwc = 1;
|
|
|
|
if (NULL != pwszMessage)
|
|
{
|
|
cwc += wcslen(pwszMessage) + 1;
|
|
}
|
|
if (NULL != pwszError)
|
|
{
|
|
cwc += wcslen(pwszError) + 1;
|
|
}
|
|
if (NULL != g_pwszErrorString)
|
|
{
|
|
cwc += wcslen(g_pwszErrorString) + 1;
|
|
}
|
|
if (S_OK != hr && NULL != g_pwszInfErrorString)
|
|
{
|
|
cwc += wcslen(g_pwszInfErrorString) + 1;
|
|
}
|
|
if (NULL != pwszMessage2)
|
|
{
|
|
cwc += wcslen(pwszMessage2) + 1;
|
|
}
|
|
if (NULL != g_pwszUnreferencedSectionNames)
|
|
{
|
|
cwc += wcslen(g_pwszUnreferencedSectionNames) + 1;
|
|
}
|
|
|
|
pwszCombinedError = (WCHAR *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
cwc * sizeof(WCHAR));
|
|
if (NULL != pwszCombinedError)
|
|
{
|
|
*pwszCombinedError = L'\0';
|
|
if (NULL != pwszMessage)
|
|
{
|
|
wcscat(pwszCombinedError, pwszMessage);
|
|
}
|
|
if (NULL != pwszError)
|
|
{
|
|
if (L'\0' != *pwszCombinedError)
|
|
{
|
|
wcscat(pwszCombinedError, g_wszNewLine);
|
|
}
|
|
wcscat(pwszCombinedError, pwszError);
|
|
}
|
|
if (NULL != g_pwszErrorString)
|
|
{
|
|
if (L'\0' != *pwszCombinedError)
|
|
{
|
|
wcscat(pwszCombinedError, g_wszNewLine);
|
|
}
|
|
wcscat(pwszCombinedError, g_pwszErrorString);
|
|
}
|
|
if (S_OK != hr && NULL != g_pwszInfErrorString)
|
|
{
|
|
if (L'\0' != *pwszCombinedError)
|
|
{
|
|
wcscat(pwszCombinedError, g_wszNewLine);
|
|
}
|
|
wcscat(pwszCombinedError, g_pwszInfErrorString);
|
|
}
|
|
if (NULL != pwszMessage2)
|
|
{
|
|
if (L'\0' != *pwszCombinedError)
|
|
{
|
|
wcscat(pwszCombinedError, g_wszNewLine);
|
|
}
|
|
wcscat(pwszCombinedError, pwszMessage2);
|
|
}
|
|
if (NULL != g_pwszUnreferencedSectionNames)
|
|
{
|
|
if (L'\0' != *pwszCombinedError)
|
|
{
|
|
wcscat(pwszCombinedError, g_wszNewLine);
|
|
}
|
|
wcscat(pwszCombinedError, g_pwszUnreferencedSectionNames);
|
|
}
|
|
pwsz = pwszCombinedError;
|
|
}
|
|
}
|
|
if (NULL == pwsz)
|
|
{
|
|
pwsz = pwszError;
|
|
if (NULL == pwsz)
|
|
{
|
|
pwsz = g_pwszErrorString;
|
|
if (NULL == pwsz)
|
|
{
|
|
pwsz = L"";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!g_fQuiet)
|
|
{
|
|
MessageBox(
|
|
hWnd,
|
|
pwsz,
|
|
pwszTitle,
|
|
MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
|
|
}
|
|
wprintf(L"%ws: %ws\n",
|
|
NULL != pwszTitle? pwszTitle : L"",
|
|
NULL != pwsz? pwsz : L"");
|
|
|
|
if (NULL != pwszCombinedError)
|
|
{
|
|
LocalFree(pwszCombinedError);
|
|
}
|
|
if (NULL != pwszError)
|
|
{
|
|
LocalFree(const_cast<WCHAR *>(pwszError));
|
|
}
|
|
if (NULL != pwszMessage)
|
|
{
|
|
LocalFree(pwszMessage);
|
|
}
|
|
if (NULL != pwszMessage2)
|
|
{
|
|
LocalFree(pwszMessage2);
|
|
}
|
|
if (NULL != pwszTitle)
|
|
{
|
|
LocalFree(pwszTitle);
|
|
}
|
|
}
|
|
|
|
|
|
//**************************************************************************
|
|
// FUNCTION: MainWndProc(...)
|
|
// ARGUMENTS:
|
|
//**************************************************************************
|
|
|
|
LRESULT APIENTRY
|
|
MainWndProc(
|
|
HWND hWnd,
|
|
UINT msg,
|
|
WPARAM wParam,
|
|
LPARAM lParam)
|
|
{
|
|
WCHAR *pwszCmdLine = NULL;
|
|
HRESULT hr;
|
|
LRESULT lr = 0;
|
|
|
|
switch(msg)
|
|
{
|
|
case WM_CREATE:
|
|
case WM_SIZE:
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_DOCERTREQDIALOGS:
|
|
pwszCmdLine = (WCHAR*)lParam;
|
|
hr = CertReqPreMain(pwszCmdLine, hWnd);
|
|
if ((S_OK != hr && HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) ||
|
|
NULL != g_pwszUnreferencedSectionNames)
|
|
{
|
|
CertReqErrorDisplay(hr, hWnd);
|
|
}
|
|
PostQuitMessage(hr);
|
|
break;
|
|
|
|
default:
|
|
lr = DefWindowProc(hWnd, msg, wParam, lParam);
|
|
break;
|
|
}
|
|
return(lr);
|
|
}
|
|
|
|
|
|
static BOOL s_fLogOpened = FALSE;
|
|
|
|
VOID
|
|
LogOpen(
|
|
IN BOOL fForceOpen)
|
|
{
|
|
BOOL fOpenLog;
|
|
|
|
DbgPrintfInit("+"); // reinitialize debug print mask first
|
|
fOpenLog = DbgIsSSActive(DBG_SS_OPENLOG);
|
|
|
|
if (fOpenLog || fForceOpen)
|
|
{
|
|
if (!s_fLogOpened)
|
|
{
|
|
DbgPrintfInit("+certreq.log"); // open the log file
|
|
s_fLogOpened = TRUE;
|
|
DbgLogFileVersion("certreq.exe", szCSVER_STR);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
LogClose()
|
|
{
|
|
if (s_fLogOpened)
|
|
{
|
|
DbgPrintfInit("-"); // close the log file
|
|
s_fLogOpened = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function: wWinMain()
|
|
//
|
|
// Synopsis: Entry Point
|
|
//
|
|
// Arguments: [hInstance] -- Instance handle
|
|
// [hPrevInstance] -- Obsolete
|
|
// [pwszCmdLine] -- App command line
|
|
// [nCmdShow] -- Starting show state
|
|
//
|
|
// History: 12/07/96 JerryK Added this Comment
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
extern "C" int APIENTRY
|
|
wWinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE, // hPrevInstance
|
|
LPWSTR pwszCmdLine,
|
|
int /* nCmdShow */ )
|
|
{
|
|
HRESULT hr;
|
|
MSG msg;
|
|
WNDCLASS wcApp;
|
|
HWND hWndMain;
|
|
|
|
WCHAR *pwszAppName = NULL;
|
|
WCHAR *pwszWindowName = NULL;
|
|
|
|
_setmode(_fileno(stdout), _O_TEXT);
|
|
_wsetlocale(LC_ALL, L".OCP");
|
|
mySetThreadUILanguage(0);
|
|
|
|
LogOpen(FALSE);
|
|
|
|
hr = myLoadRCString(hInstance, IDS_APP_NAME, &pwszAppName);
|
|
_PrintIfError(hr, "myLoadRCString(IDS_APP_NAME)");
|
|
|
|
hr = myLoadRCString(hInstance, IDS_WINDOW_NAME, &pwszWindowName);
|
|
_PrintIfError(hr, "myLoadRCString(IDS_WINDOW_NAME)");
|
|
|
|
// Save the current instance
|
|
g_hInstance = hInstance;
|
|
|
|
// Set up the application's window class
|
|
wcApp.style = 0;
|
|
wcApp.lpfnWndProc = MainWndProc;
|
|
wcApp.cbClsExtra = 0;
|
|
wcApp.cbWndExtra = 0;
|
|
wcApp.hInstance = hInstance;
|
|
wcApp.hIcon = LoadIcon(NULL,IDI_APPLICATION);
|
|
wcApp.hCursor = LoadCursor(NULL,IDC_ARROW);
|
|
wcApp.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
|
|
wcApp.lpszMenuName = NULL;
|
|
wcApp.lpszClassName = pwszAppName;
|
|
|
|
if (!RegisterClass(&wcApp))
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Create Main Window
|
|
hWndMain = CreateWindow(
|
|
pwszAppName,
|
|
pwszWindowName,
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
CW_USEDEFAULT,
|
|
NULL,
|
|
NULL,
|
|
hInstance,
|
|
NULL);
|
|
if (NULL == hWndMain)
|
|
{
|
|
return(FALSE);
|
|
}
|
|
|
|
// Make window visible
|
|
// ShowWindow(hWndMain,nCmdShow);
|
|
|
|
// Update window client area
|
|
UpdateWindow(hWndMain);
|
|
|
|
// Send off the message to get things started
|
|
PostMessage(hWndMain,WM_DOCERTREQDIALOGS,0,(LPARAM)pwszCmdLine);
|
|
|
|
// Message Loop
|
|
while (GetMessage(&msg,NULL,0,0))
|
|
{
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
if (NULL != g_pwszErrorString)
|
|
{
|
|
LocalFree(g_pwszErrorString);
|
|
}
|
|
if (NULL != g_pwszInfErrorString)
|
|
{
|
|
LocalFree(g_pwszInfErrorString);
|
|
}
|
|
if (NULL != g_pwszUnreferencedSectionNames)
|
|
{
|
|
LocalFree(g_pwszUnreferencedSectionNames);
|
|
}
|
|
if (NULL != pwszAppName)
|
|
{
|
|
LocalFree(pwszAppName);
|
|
}
|
|
if (NULL != pwszWindowName)
|
|
{
|
|
LocalFree(pwszWindowName);
|
|
}
|
|
myInfClearError();
|
|
myFreeResourceStrings("certreq.exe");
|
|
myFreeColumnDisplayNames();
|
|
myRegisterMemDump();
|
|
LogClose();
|
|
return((int)msg.wParam);
|
|
}
|