3072 lines
68 KiB
C++
3072 lines
68 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1995 - 1999
|
|
//
|
|
// File: admin.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include <pch.cpp>
|
|
|
|
#pragma hdrstop
|
|
|
|
#include <setupapi.h>
|
|
#include <ocmanage.h>
|
|
#include "initcert.h"
|
|
#include "cscsp.h"
|
|
|
|
|
|
HRESULT
|
|
verbDenyRequest(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszRequestId,
|
|
IN WCHAR const *pwszArg2,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
LONG RequestId;
|
|
BOOL fMustRelease = FALSE;
|
|
|
|
hr = cuGetLong(pwszRequestId, &RequestId);
|
|
_JumpIfError(hr, error, "RequestId must be a number");
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Admin_DenyRequest(&diAdmin, g_pwszConfig, RequestId);
|
|
_JumpIfError(hr, error, "Admin_DenyRequest");
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszFromSubmitDisposition(
|
|
LONG Disposition)
|
|
{
|
|
DWORD idMsg;
|
|
|
|
switch (Disposition)
|
|
{
|
|
case CR_DISP_INCOMPLETE: idMsg = IDS_CR_DISP_INCOMPLETE; break;
|
|
case CR_DISP_ERROR: idMsg = IDS_CR_DISP_ERROR; break;
|
|
case CR_DISP_DENIED: idMsg = IDS_CR_DISP_DENIED; break;
|
|
case CR_DISP_ISSUED: idMsg = IDS_CR_DISP_ISSUED; break;
|
|
case CR_DISP_ISSUED_OUT_OF_BAND:
|
|
idMsg = IDS_CR_DISP_ISSUED_OUT_OF_BAND; break;
|
|
case CR_DISP_UNDER_SUBMISSION:
|
|
idMsg = IDS_CR_DISP_UNDER_SUBMISSION; break;
|
|
case CR_DISP_REVOKED: idMsg = IDS_CR_DISP_REVOKED; break;
|
|
|
|
default: idMsg = IDS_UNKNOWN; break;
|
|
}
|
|
return(myLoadResourceString(idMsg));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbResubmitRequest(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszRequestId,
|
|
IN WCHAR const *pwszArg2,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
LONG RequestId;
|
|
LONG Disposition;
|
|
BOOL fMustRelease = FALSE;
|
|
|
|
hr = cuGetLong(pwszRequestId, &RequestId);
|
|
_JumpIfError(hr, error, "RequestId must be a number");
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Admin_ResubmitRequest(&diAdmin, g_pwszConfig, RequestId, &Disposition);
|
|
_JumpIfError(hr, error, "Admin_ResubmitRequest");
|
|
|
|
if (CR_DISP_UNDER_SUBMISSION == Disposition)
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_PENDING_REQUESTID), // "Certificate request is pending: RequestId: %u"
|
|
RequestId);
|
|
wprintf(wszNewLine);
|
|
}
|
|
else if (CR_DISP_ISSUED == Disposition)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_CERT_ISSUED)); // "Certificate issued."
|
|
wprintf(wszNewLine);
|
|
}
|
|
else
|
|
{
|
|
if (FAILED(Disposition))
|
|
{
|
|
hr = Disposition;
|
|
Disposition = CR_DISP_DENIED;
|
|
}
|
|
wprintf(
|
|
myLoadResourceString(IDS_CERT_NOT_ISSUED_DISPOSITION), // "Certificate has not been issued: Disposition: %d -- %ws"
|
|
Disposition,
|
|
wszFromSubmitDisposition(Disposition));
|
|
wprintf(wszNewLine);
|
|
if (S_OK != hr)
|
|
{
|
|
WCHAR const *pwszMessage;
|
|
|
|
pwszMessage = myGetErrorMessageText(hr, FALSE);
|
|
if (NULL != pwszMessage)
|
|
{
|
|
wprintf(L"%ws\n", pwszMessage);
|
|
LocalFree(const_cast<WCHAR *>(pwszMessage));
|
|
}
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
typedef struct _cuCRLREASON
|
|
{
|
|
WCHAR *pwszReason;
|
|
LONG lReason;
|
|
int idReason;
|
|
} cuCRLREASON;
|
|
|
|
#define cuREASON(r, id) { L#r, (r), (id) }
|
|
|
|
cuCRLREASON g_cuReason[] =
|
|
{
|
|
cuREASON(CRL_REASON_UNSPECIFIED, IDS_CRL_REASON_UNSPECIFIED),
|
|
cuREASON(CRL_REASON_KEY_COMPROMISE, IDS_CRL_REASON_KEY_COMPROMISE),
|
|
cuREASON(CRL_REASON_CA_COMPROMISE, IDS_CRL_REASON_CA_COMPROMISE),
|
|
cuREASON(CRL_REASON_AFFILIATION_CHANGED, IDS_CRL_REASON_AFFILIATION_CHANGED),
|
|
cuREASON(CRL_REASON_SUPERSEDED, IDS_CRL_REASON_SUPERSEDED),
|
|
cuREASON(CRL_REASON_CESSATION_OF_OPERATION,
|
|
IDS_CRL_REASON_CESSATION_OF_OPERATION),
|
|
cuREASON(CRL_REASON_CERTIFICATE_HOLD, IDS_CRL_REASON_CERTIFICATE_HOLD),
|
|
cuREASON(CRL_REASON_REMOVE_FROM_CRL, IDS_CRL_REASON_REMOVE_FROM_CRL),
|
|
{ L"Unrevoke", MAXDWORD, IDS_CRL_REASON_UNREVOKE },
|
|
{ NULL, MAXDWORD, IDS_CRL_REASON_UNRECOGNIZED },
|
|
};
|
|
|
|
#define wszCRLPREFIX L"CRL_REASON_"
|
|
|
|
HRESULT
|
|
cuParseReason(
|
|
IN WCHAR const *pwszReason,
|
|
OUT LONG *plReason)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = cuGetSignedLong(pwszReason, plReason);
|
|
if (S_OK != hr)
|
|
{
|
|
cuCRLREASON const *pr;
|
|
|
|
for (pr = g_cuReason; ; pr++)
|
|
{
|
|
if (NULL == pr->pwszReason)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpIfError(hr, error, "Invalid Reason string");
|
|
}
|
|
if (0 == lstrcmpi(pr->pwszReason, pwszReason))
|
|
{
|
|
break;
|
|
}
|
|
if (wcslen(pr->pwszReason) > WSZARRAYSIZE(wszCRLPREFIX) &&
|
|
0 == memcmp(
|
|
pr->pwszReason,
|
|
wszCRLPREFIX,
|
|
WSZARRAYSIZE(wszCRLPREFIX) * sizeof(WCHAR)) &&
|
|
0 == lstrcmpi(
|
|
&pr->pwszReason[WSZARRAYSIZE(wszCRLPREFIX)],
|
|
pwszReason))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
*plReason = pr->lReason;
|
|
hr = S_OK;
|
|
}
|
|
CSASSERT(S_OK == hr);
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
int
|
|
cuidCRLReason(
|
|
IN LONG Reason)
|
|
{
|
|
cuCRLREASON const *pr;
|
|
|
|
for (pr = g_cuReason; NULL != pr->pwszReason; pr++)
|
|
{
|
|
if (pr->lReason == Reason)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
return(pr->idReason);
|
|
}
|
|
|
|
|
|
WCHAR const *
|
|
wszCRLReason(
|
|
IN LONG Reason)
|
|
{
|
|
return(myLoadResourceString(cuidCRLReason(Reason)));
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbRevokeCertificate(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszSerialNumber,
|
|
IN WCHAR const *pwszReason,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
BSTR strSerialNumber = NULL;
|
|
LONG Reason = CRL_REASON_UNSPECIFIED;
|
|
SYSTEMTIME st;
|
|
FILETIME ft;
|
|
DATE Date;
|
|
BOOL fMustRelease = FALSE;
|
|
|
|
GetSystemTime(&st);
|
|
if (!SystemTimeToFileTime(&st, &ft))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpIfError(hr, error, "SystemTimeToFileTime");
|
|
}
|
|
hr = myFileTimeToDate(&ft, &Date);
|
|
_JumpIfError(hr, error, "myFileTimeToDate");
|
|
|
|
//Date -= 1.0; // Revoke effective yesterday
|
|
|
|
hr = myMakeSerialBstr(pwszSerialNumber, &strSerialNumber);
|
|
_JumpIfError(hr, error, "myMakeSerialBstr");
|
|
|
|
if (NULL != pwszReason)
|
|
{
|
|
hr = cuParseReason(pwszReason, &Reason);
|
|
_JumpIfError(hr, error, "Invalid Reason");
|
|
}
|
|
|
|
wprintf(myLoadResourceString(IDS_REVOKING), strSerialNumber); // "Revoking "%ws""
|
|
wprintf(L" -- %ws", wszCRLReason(Reason)); // "Reason: xxxx"
|
|
wprintf(wszNewLine);
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Admin_RevokeCertificate(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
strSerialNumber,
|
|
Reason,
|
|
Date);
|
|
_JumpIfError(hr, error, "Admin_DenyRequest");
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
if (NULL != strSerialNumber)
|
|
{
|
|
SysFreeString(strSerialNumber);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
cuParseDaysHours(
|
|
IN WCHAR const *pwszDaysHours,
|
|
OUT FILETIME *pft)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszDays = NULL;
|
|
WCHAR *pwszHours;
|
|
DWORD dwDays;
|
|
DWORD dwHours;
|
|
BOOL fValid;
|
|
LONGLONG delta;
|
|
|
|
hr = myDupString(pwszDaysHours, &pwszDays);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
hr = E_INVALIDARG;
|
|
pwszHours = wcschr(pwszDays, L':');
|
|
if (NULL == pwszHours)
|
|
{
|
|
_JumpError(hr, error, "missing colon");
|
|
}
|
|
*pwszHours++ = L'\0';
|
|
dwDays = myWtoI(pwszDays, &fValid);
|
|
if (!fValid)
|
|
{
|
|
_JumpError(hr, error, "bad day count");
|
|
}
|
|
dwHours = myWtoI(pwszHours, &fValid);
|
|
if (!fValid)
|
|
{
|
|
_JumpError(hr, error, "bad hour count");
|
|
}
|
|
if (0 == dwDays && 0 == dwHours)
|
|
{
|
|
_JumpError(hr, error, "zero day+hour counts");
|
|
}
|
|
GetSystemTimeAsFileTime(pft);
|
|
|
|
// add specified days and hours to compute expiration date
|
|
|
|
delta = dwDays * CVT_DAYS;
|
|
delta += dwHours * CVT_HOURS;
|
|
myAddToFileTime(pft, delta * CVT_BASE);
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pwszDays)
|
|
{
|
|
LocalFree(pwszDays);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbPublishCRL(
|
|
IN WCHAR const *pwszOption,
|
|
OPTIONAL IN WCHAR const *pwszDaysHours,
|
|
OPTIONAL IN WCHAR const *pwszDelta,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
BOOL fMustRelease = FALSE;
|
|
DATE Date;
|
|
DWORD Flags = 0;
|
|
|
|
if (NULL != pwszDaysHours && 0 == lstrcmpi(L"delta", pwszDaysHours))
|
|
{
|
|
WCHAR const *pwsz = pwszDaysHours;
|
|
|
|
pwszDaysHours = pwszDelta;
|
|
pwszDelta = pwsz;
|
|
}
|
|
Date = 0.0;
|
|
if (NULL != pwszDaysHours)
|
|
{
|
|
if (0 == lstrcmpi(L"republish", pwszDaysHours))
|
|
{
|
|
Flags |= CA_CRL_REPUBLISH;
|
|
}
|
|
else
|
|
{
|
|
FILETIME ft;
|
|
|
|
hr = cuParseDaysHours(pwszDaysHours, &ft);
|
|
_JumpIfError(hr, error, "cuParseDaysHours");
|
|
|
|
hr = myFileTimeToDate(&ft, &Date);
|
|
_JumpIfError(hr, error, "myFileTimeToDate");
|
|
}
|
|
}
|
|
if (NULL != pwszDelta)
|
|
{
|
|
if (0 != lstrcmpi(L"delta", pwszDelta))
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "bad delta arg");
|
|
}
|
|
Flags |= CA_CRL_DELTA;
|
|
}
|
|
if (0 == (CA_CRL_DELTA & Flags))
|
|
{
|
|
Flags |= CA_CRL_BASE;
|
|
}
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
if ((CA_CRL_DELTA | CA_CRL_REPUBLISH) & Flags)
|
|
{
|
|
hr = Admin2_PublishCRLs(&diAdmin, g_pwszConfig, Date, Flags);
|
|
_JumpIfError(hr, error, "Admin2_PublishCRLs");
|
|
}
|
|
else
|
|
{
|
|
BOOL fV1 = g_fV1Interface;
|
|
|
|
if (!fV1)
|
|
{
|
|
hr = Admin2_PublishCRLs(&diAdmin, g_pwszConfig, Date, Flags);
|
|
if (E_NOTIMPL != hr)
|
|
{
|
|
_JumpIfError(hr, error, "Admin2_PublishCRLs");
|
|
}
|
|
else
|
|
{
|
|
_PrintError(hr, "Admin2_PublishCRLs down level server");
|
|
fV1 = TRUE;
|
|
}
|
|
}
|
|
if (fV1)
|
|
{
|
|
hr = Admin_PublishCRL(&diAdmin, g_pwszConfig, Date);
|
|
_JumpIfError(hr, error, "Admin_PublishCRL");
|
|
}
|
|
}
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbGetCRL(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszfnOut,
|
|
OPTIONAL IN WCHAR const *pwszDelta,
|
|
OPTIONAL IN WCHAR const *pwszIndex,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
BOOL fMustRelease = FALSE;
|
|
BOOL fDelta = FALSE;
|
|
DWORD CertIndex = MAXDWORD; // default to latest CRL
|
|
BSTR strCRL = NULL;
|
|
|
|
if (NULL != pwszDelta && 0 != lstrcmpi(L"delta", pwszDelta))
|
|
{
|
|
WCHAR const *pwsz = pwszIndex;
|
|
|
|
pwszIndex = pwszDelta;
|
|
pwszDelta = pwsz;
|
|
}
|
|
if (NULL != pwszDelta && 0 == lstrcmpi(L"delta", pwszDelta))
|
|
{
|
|
fDelta = TRUE;
|
|
}
|
|
if (NULL != pwszIndex)
|
|
{
|
|
hr = cuGetSignedLong(pwszIndex, (LONG *) &CertIndex);
|
|
_JumpIfErrorStr(hr, error, "Cert index not a number", pwszIndex);
|
|
}
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
if (fDelta)
|
|
{
|
|
hr = Admin2_GetCAProperty(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
CR_PROP_DELTACRL,
|
|
CertIndex,
|
|
PROPTYPE_BINARY,
|
|
CR_OUT_BINARY,
|
|
&strCRL);
|
|
_JumpIfError(hr, error, "Admin2_GetCAProperty");
|
|
}
|
|
else
|
|
{
|
|
BOOL fV1 = g_fV1Interface;
|
|
|
|
if (!fV1)
|
|
{
|
|
hr = Admin2_GetCAProperty(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
CR_PROP_BASECRL,
|
|
CertIndex,
|
|
PROPTYPE_BINARY,
|
|
CR_OUT_BINARY,
|
|
&strCRL);
|
|
|
|
if (E_NOTIMPL != hr)
|
|
{
|
|
_JumpIfError(hr, error, "Admin2_GetCAProperty");
|
|
}
|
|
else
|
|
{
|
|
_PrintError(hr, "Admin2_CAProperty down level server");
|
|
fV1 = TRUE;
|
|
}
|
|
}
|
|
if (fV1)
|
|
{
|
|
if (NULL != pwszIndex)
|
|
{
|
|
hr = cuGetCAInfo(
|
|
pwszOption,
|
|
pwszfnOut,
|
|
g_wszCAInfoCRL,
|
|
pwszIndex);
|
|
_JumpIfError(hr, error, "cuGetCAInfo");
|
|
}
|
|
else
|
|
{
|
|
hr = Admin_GetCRL(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
CR_OUT_BINARY,
|
|
&strCRL);
|
|
_JumpIfError(hr, error, "Admin_GetCRL");
|
|
}
|
|
}
|
|
}
|
|
|
|
// if not already saved by cuGetCAInfo
|
|
|
|
if (NULL != strCRL)
|
|
{
|
|
hr = EncodeToFileW(
|
|
pwszfnOut,
|
|
(BYTE const *) strCRL,
|
|
SysStringByteLen(strCRL),
|
|
CRYPT_STRING_BINARY | g_EncodeFlags);
|
|
_JumpIfError(hr, error, "EncodeToFileW");
|
|
}
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
if (NULL != strCRL)
|
|
{
|
|
SysFreeString(strCRL);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
FindCertAndSign(
|
|
OPTIONAL IN CERT_EXTENSION const *pExtKeyId,
|
|
OPTIONAL IN BYTE const *pbHash,
|
|
IN DWORD cbHash,
|
|
IN BYTE const *pbUnsigned,
|
|
IN DWORD cbUnsigned,
|
|
OUT BYTE **ppbOut,
|
|
OUT DWORD *pcbOut)
|
|
{
|
|
HRESULT hr;
|
|
CERT_AUTHORITY_KEY_ID2_INFO *pKeyId = NULL;
|
|
DWORD cbKeyId;
|
|
WCHAR *strKeyId = NULL;
|
|
CERT_CONTEXT const *pCert = NULL;
|
|
HCRYPTPROV hProv = NULL;
|
|
DWORD dwKeySpec;
|
|
BOOL fCallerFreeProv;
|
|
CHAR *pszObjId = NULL;
|
|
|
|
*ppbOut = NULL;
|
|
if (NULL == pbHash && NULL != pExtKeyId)
|
|
{
|
|
if (!myDecodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_AUTHORITY_KEY_ID2,
|
|
pExtKeyId->Value.pbData,
|
|
pExtKeyId->Value.cbData,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
(VOID **) &pKeyId,
|
|
&cbKeyId))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myDecodeObject");
|
|
}
|
|
pbHash = pKeyId->KeyId.pbData;
|
|
cbHash = pKeyId->KeyId.cbData;
|
|
}
|
|
if (0 != cbHash && NULL != pbHash)
|
|
{
|
|
hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strKeyId);
|
|
_JumpIfError(hr, error, "MultiByteIntegerToBstr");
|
|
}
|
|
|
|
// Find CA cert by KeyId from the szOID_AUTHORITY_KEY_IDENTIFIER2 extension.
|
|
// Look in HKLM and HKCU My and CA stores.
|
|
|
|
hr = myGetCertificateFromPicker(
|
|
g_hInstance,
|
|
NULL, // hwndParent
|
|
IDS_GETCERT_TITLE,
|
|
IDS_GETCERT_SUBTITLE,
|
|
|
|
// dwFlags: HKLM+HKCU My store
|
|
CUCS_MYSTORE |
|
|
CUCS_MACHINESTORE |
|
|
CUCS_USERSTORE |
|
|
CUCS_PRIVATEKEYREQUIRED |
|
|
CUCS_ARCHIVED |
|
|
(g_fCryptSilent? CUCS_SILENT : 0),
|
|
strKeyId,
|
|
0,
|
|
NULL,
|
|
0, // cpszObjId
|
|
NULL, // apszObjId
|
|
&pCert);
|
|
_JumpIfError(hr, error, "myGetCertificateFromPicker");
|
|
|
|
if (NULL == pCert)
|
|
{
|
|
hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
|
|
_JumpError(hr, error, "no cert");
|
|
}
|
|
|
|
hr = cuDisplayCertName(
|
|
TRUE,
|
|
NULL,
|
|
myLoadResourceString(IDS_SIGNINGSUBJECT), // "Signing certificate Subject"
|
|
g_wszPad4,
|
|
&pCert->pCertInfo->Subject);
|
|
_JumpIfError(hr, error, "cuDisplayCertName(Subject)");
|
|
|
|
// 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);
|
|
_JumpIfError(hr, error, "myLoadPrivateKey");
|
|
|
|
if (AT_SIGNATURE != dwKeySpec)
|
|
{
|
|
hr = NTE_BAD_KEY_STATE;
|
|
DBGPRINT((DBG_SS_CERTUTIL, "dwKeySpec = %u\n", dwKeySpec));
|
|
_JumpError(hr, error, "dwKeySpec");
|
|
}
|
|
|
|
// The CA cert's private key is available -- use it to sign the data.
|
|
// Sign the Cert or CRL and encode the signed info.
|
|
|
|
hr = myGetSigningOID(hProv, NULL, 0, CALG_SHA1, &pszObjId);
|
|
_JumpIfError(hr, error, "myGetSigningOID");
|
|
|
|
hr = myEncodeSignedContent(
|
|
hProv,
|
|
X509_ASN_ENCODING,
|
|
pszObjId,
|
|
const_cast<BYTE *>(pbUnsigned),
|
|
cbUnsigned,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
ppbOut,
|
|
pcbOut);
|
|
_JumpIfError(hr, error, "myEncodeSignedContent");
|
|
|
|
error:
|
|
if (NULL != pszObjId)
|
|
{
|
|
LocalFree(pszObjId);
|
|
}
|
|
if (NULL != pKeyId)
|
|
{
|
|
LocalFree(pKeyId);
|
|
}
|
|
if (NULL != strKeyId)
|
|
{
|
|
SysFreeString(strKeyId);
|
|
}
|
|
if (NULL != pCert)
|
|
{
|
|
CertFreeCertificateContext(pCert);
|
|
}
|
|
if (NULL != hProv && fCallerFreeProv)
|
|
{
|
|
CryptReleaseContext(hProv, 0);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SignCRL(
|
|
IN CRL_CONTEXT const *pCRLContext,
|
|
OPTIONAL IN FILETIME const *pftNextUpdate,
|
|
IN BOOL fAdd,
|
|
IN WCHAR const * const *ppwszSerialList,
|
|
OUT BYTE **ppbOut,
|
|
OUT DWORD *pcbOut)
|
|
{
|
|
HRESULT hr;
|
|
CRL_INFO const *pCRLInfo;
|
|
CRL_INFO CRLInfoOut;
|
|
LLFILETIME llftDelta;
|
|
LLFILETIME llft;
|
|
BYTE *pbUnsigned = NULL;
|
|
DWORD cbUnsigned;
|
|
CERT_EXTENSION *pExtKeyId;
|
|
|
|
ZeroMemory(&CRLInfoOut, sizeof(CRLInfoOut));
|
|
|
|
*ppbOut = NULL;
|
|
|
|
// CRL extensions to strip out of the re-signed CRL:
|
|
|
|
static char const * const apszObjIdFilter[] = {
|
|
szOID_CRL_NEXT_PUBLISH,
|
|
};
|
|
|
|
pCRLInfo = pCRLContext->pCrlInfo;
|
|
CRLInfoOut = *pCRLInfo;
|
|
CRLInfoOut.rgExtension = NULL;
|
|
CRLInfoOut.cExtension = 0;
|
|
|
|
GetSystemTimeAsFileTime(&llft.ft);
|
|
llftDelta.ll = CCLOCKSKEWMINUTESDEFAULT * CVT_MINUTES;
|
|
llftDelta.ll *= CVT_BASE;
|
|
llft.ll -= llftDelta.ll;
|
|
CRLInfoOut.ThisUpdate = llft.ft;
|
|
|
|
if (NULL != pftNextUpdate)
|
|
{
|
|
CRLInfoOut.NextUpdate = *pftNextUpdate;
|
|
}
|
|
else
|
|
{
|
|
// NextUpdateOut = ThisUpdateOut + (NextUpdate - ThisUpdate);
|
|
|
|
llftDelta.ft = pCRLInfo->NextUpdate;
|
|
llft.ft = pCRLInfo->ThisUpdate;
|
|
llftDelta.ll -= llft.ll;
|
|
|
|
llft.ft = CRLInfoOut.ThisUpdate;
|
|
llftDelta.ll += llft.ll;
|
|
|
|
CRLInfoOut.NextUpdate = llftDelta.ft;
|
|
}
|
|
|
|
hr = cuDumpFileTime(IDS_THISUPDATE, NULL, &CRLInfoOut.ThisUpdate);
|
|
_JumpIfError(hr, error, "cuDumpFileTime");
|
|
|
|
hr = cuDumpFileTime(IDS_NEXTUPDATE, NULL, &CRLInfoOut.NextUpdate);
|
|
_JumpIfError(hr, error, "cuDumpFileTime");
|
|
|
|
wprintf(myLoadResourceString(IDS_CRLENTRIES)); // "CRL Entries:"
|
|
wprintf(L" %u\n", pCRLInfo->cCRLEntry);
|
|
|
|
wprintf(wszNewLine);
|
|
|
|
pExtKeyId = NULL;
|
|
if (0 != pCRLInfo->cExtension)
|
|
{
|
|
CERT_EXTENSION *pExt;
|
|
DWORD i;
|
|
DWORD j;
|
|
|
|
CRLInfoOut.rgExtension = (CERT_EXTENSION *) LocalAlloc(
|
|
LMEM_FIXED,
|
|
pCRLInfo->cExtension *
|
|
sizeof(CRLInfoOut.rgExtension[0]));
|
|
if (NULL == CRLInfoOut.rgExtension)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
pExt = pCRLInfo->rgExtension;
|
|
for (i = 0; i < pCRLInfo->cExtension; i++)
|
|
{
|
|
for (j = 0; ; j++)
|
|
{
|
|
if (j >= ARRAYSIZE(apszObjIdFilter))
|
|
{
|
|
CRLInfoOut.rgExtension[CRLInfoOut.cExtension++] = *pExt;
|
|
break;
|
|
}
|
|
if (0 == strcmp(apszObjIdFilter[j], pExt->pszObjId))
|
|
{
|
|
break; // skip this extension
|
|
}
|
|
}
|
|
if (0 == strcmp(szOID_AUTHORITY_KEY_IDENTIFIER2, pExt->pszObjId))
|
|
{
|
|
pExtKeyId = pExt;
|
|
}
|
|
pExt++;
|
|
}
|
|
}
|
|
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_CRL_TO_BE_SIGNED,
|
|
&CRLInfoOut,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbUnsigned, // pbEncoded
|
|
&cbUnsigned))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
hr = FindCertAndSign(
|
|
pExtKeyId,
|
|
NULL,
|
|
0,
|
|
pbUnsigned,
|
|
cbUnsigned,
|
|
ppbOut,
|
|
pcbOut);
|
|
_JumpIfError(hr, error, "FindCertAndSign");
|
|
|
|
error:
|
|
if (NULL != CRLInfoOut.rgExtension)
|
|
{
|
|
LocalFree(CRLInfoOut.rgExtension);
|
|
}
|
|
if (NULL != pbUnsigned)
|
|
{
|
|
LocalFree(pbUnsigned);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SignCert(
|
|
IN CERT_CONTEXT const *pCertContext,
|
|
OPTIONAL IN FILETIME const *pftNotAfter,
|
|
IN WCHAR const * const *ppwszObjIdList,
|
|
OUT BYTE **ppbOut,
|
|
OUT DWORD *pcbOut)
|
|
{
|
|
HRESULT hr;
|
|
CERT_INFO const *pCertInfo;
|
|
CERT_INFO CertInfoOut;
|
|
LLFILETIME llftCurrent;
|
|
LLFILETIME llftDelta;
|
|
LLFILETIME llft;
|
|
BYTE *pbUnsigned = NULL;
|
|
DWORD cbUnsigned;
|
|
BYTE const *pbHash;
|
|
BYTE abHash[CBMAX_CRYPT_HASH_LEN];
|
|
DWORD cbHash;
|
|
CERT_EXTENSION *pExtKeyId;
|
|
CERT_EXTENSION ExtKeyId;
|
|
|
|
ZeroMemory(&CertInfoOut, sizeof(CertInfoOut));
|
|
|
|
*ppbOut = NULL;
|
|
|
|
pCertInfo = pCertContext->pCertInfo;
|
|
CertInfoOut = *pCertInfo;
|
|
|
|
GetSystemTimeAsFileTime(&llftCurrent.ft);
|
|
llftDelta.ll = CCLOCKSKEWMINUTESDEFAULT * CVT_MINUTES;
|
|
llftDelta.ll *= CVT_BASE;
|
|
llftCurrent.ll -= llftDelta.ll;
|
|
|
|
if (0 < CompareFileTime(&CertInfoOut.NotBefore, &llftCurrent.ft))
|
|
{
|
|
CertInfoOut.NotBefore = llftCurrent.ft;
|
|
}
|
|
if (NULL != pftNotAfter)
|
|
{
|
|
CertInfoOut.NotAfter = *pftNotAfter;
|
|
}
|
|
else
|
|
{
|
|
// NotAfterOut = CurrentTime + (NotAfter - NotBefore);
|
|
|
|
llftDelta.ft = pCertInfo->NotAfter;
|
|
llft.ft = pCertInfo->NotBefore;
|
|
llftDelta.ll -= llft.ll;
|
|
|
|
llftDelta.ll += llftCurrent.ll;
|
|
|
|
CertInfoOut.NotAfter = llftDelta.ft;
|
|
}
|
|
|
|
hr = cuDumpFileTime(IDS_NOTBEFORE, NULL, &CertInfoOut.NotBefore);
|
|
_JumpIfError(hr, error, "cuDumpFileTime");
|
|
|
|
hr = cuDumpFileTime(IDS_NOTAFTER, NULL, &CertInfoOut.NotAfter);
|
|
_JumpIfError(hr, error, "cuDumpFileTime");
|
|
|
|
wprintf(wszNewLine);
|
|
|
|
pbHash = NULL;
|
|
pExtKeyId = CertFindExtension(
|
|
szOID_AUTHORITY_KEY_IDENTIFIER2,
|
|
pCertInfo->cExtension,
|
|
pCertInfo->rgExtension);
|
|
if (NULL == pExtKeyId)
|
|
{
|
|
hr = cuVerifySignature(
|
|
pCertContext->pbCertEncoded,
|
|
pCertContext->cbCertEncoded,
|
|
&pCertContext->pCertInfo->SubjectPublicKeyInfo,
|
|
TRUE);
|
|
if (S_OK == hr)
|
|
{
|
|
if (CertGetCertificateContextProperty(
|
|
pCertContext,
|
|
CERT_KEY_IDENTIFIER_PROP_ID,
|
|
abHash,
|
|
&cbHash))
|
|
{
|
|
pbHash = abHash;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ExtKeyId = *pExtKeyId; // in case it's deleted or moved.
|
|
pExtKeyId = &ExtKeyId;
|
|
}
|
|
if (NULL != ppwszObjIdList)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; NULL != ppwszObjIdList[i]; i++)
|
|
{
|
|
char *pszObjId;
|
|
CERT_EXTENSION *pExt;
|
|
|
|
hr = myVerifyObjId(ppwszObjIdList[i]);
|
|
_JumpIfError(hr, error, "myVerifyObjId");
|
|
|
|
if (!myConvertWszToSz(&pszObjId, ppwszObjIdList[i], -1))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "myConvertWszToSz");
|
|
}
|
|
pExt = CertFindExtension(
|
|
pszObjId,
|
|
CertInfoOut.cExtension,
|
|
CertInfoOut.rgExtension);
|
|
if (NULL != pExt)
|
|
{
|
|
DWORD iDel;
|
|
|
|
iDel = SAFE_SUBTRACT_POINTERS(pExt, CertInfoOut.rgExtension);
|
|
wprintf(L"iDel=%u cExt=%u\n", iDel, CertInfoOut.cExtension);
|
|
if (0 == --CertInfoOut.cExtension)
|
|
{
|
|
CertInfoOut.dwVersion = CERT_V1;
|
|
continue; // verify the rest of the ObjIds
|
|
}
|
|
if (iDel < CertInfoOut.cExtension)
|
|
{
|
|
wprintf(L"copy %u to %u, len=%u\n", iDel + 1, iDel, CertInfoOut.cExtension - iDel);
|
|
MoveMemory(
|
|
&CertInfoOut.rgExtension[iDel],
|
|
&CertInfoOut.rgExtension[iDel + 1],
|
|
(CertInfoOut.cExtension - iDel) *
|
|
sizeof(CertInfoOut.rgExtension[iDel]));
|
|
}
|
|
}
|
|
LocalFree(pszObjId);
|
|
}
|
|
}
|
|
if (!myEncodeObject(
|
|
X509_ASN_ENCODING,
|
|
X509_CERT_TO_BE_SIGNED,
|
|
&CertInfoOut,
|
|
0,
|
|
CERTLIB_USE_LOCALALLOC,
|
|
&pbUnsigned, // pbEncoded
|
|
&cbUnsigned))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "myEncodeObject");
|
|
}
|
|
|
|
hr = FindCertAndSign(
|
|
pExtKeyId,
|
|
pbHash,
|
|
cbHash,
|
|
pbUnsigned,
|
|
cbUnsigned,
|
|
ppbOut,
|
|
pcbOut);
|
|
_JumpIfError(hr, error, "FindCertAndSign");
|
|
|
|
error:
|
|
if (NULL != pbUnsigned)
|
|
{
|
|
LocalFree(pbUnsigned);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbSign(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszfnIn,
|
|
IN WCHAR const *pwszfnOut,
|
|
OPTIONAL IN WCHAR const *pwszDaysHours,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
FILETIME ftNextUpdate;
|
|
FILETIME *pftNextUpdate;
|
|
CRL_CONTEXT const *pCRLContext = NULL;
|
|
CERT_CONTEXT const *pCertContext = NULL;
|
|
BYTE *pbOut = NULL;
|
|
DWORD cbOut;
|
|
BOOL fAdd = FALSE;
|
|
WCHAR **ppwszList = NULL;
|
|
|
|
pftNextUpdate = NULL;
|
|
if (NULL != pwszDaysHours)
|
|
{
|
|
if (L'-' == *pwszDaysHours || L'+' == *pwszDaysHours)
|
|
{
|
|
fAdd = L'+' == *pwszDaysHours++;
|
|
hr = cuParseStrings(
|
|
pwszDaysHours,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
&ppwszList,
|
|
NULL);
|
|
_JumpIfError(hr, error, "cuParseStrings");
|
|
}
|
|
else
|
|
{
|
|
hr = cuParseDaysHours(pwszDaysHours, &ftNextUpdate);
|
|
_JumpIfError(hr, error, "cuParseDaysHours");
|
|
|
|
pftNextUpdate = &ftNextUpdate;
|
|
pwszDaysHours = NULL;
|
|
}
|
|
}
|
|
|
|
// Load and decode CRL and certificate
|
|
|
|
hr = cuLoadCRL(pwszfnIn, &pCRLContext);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = SignCRL(
|
|
pCRLContext,
|
|
pftNextUpdate,
|
|
fAdd,
|
|
ppwszList,
|
|
&pbOut,
|
|
&cbOut);
|
|
_JumpIfError(hr, error, "SignCRL");
|
|
}
|
|
else
|
|
{
|
|
hr = cuLoadCert(pwszfnIn, &pCertContext);
|
|
if (S_OK == hr)
|
|
{
|
|
if (fAdd)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "cannot add extensions to cert");
|
|
}
|
|
hr = SignCert(
|
|
pCertContext,
|
|
pftNextUpdate,
|
|
ppwszList,
|
|
&pbOut,
|
|
&cbOut);
|
|
_JumpIfError(hr, error, "SignCert");
|
|
}
|
|
else
|
|
{
|
|
cuPrintError(IDS_FORMAT_LOADTESTCRL, hr);
|
|
goto error;
|
|
}
|
|
|
|
}
|
|
|
|
// Write encoded & signed CRL or Cert to file
|
|
|
|
hr = EncodeToFileW(
|
|
pwszfnOut,
|
|
pbOut,
|
|
cbOut,
|
|
CRYPT_STRING_BINARY | g_EncodeFlags);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_ERR_FORMAT_ENCODETOFILE, hr);
|
|
goto error;
|
|
}
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_OUTPUT_LENGTH), // "Output Length = %d"
|
|
cuFileSize(pwszfnOut));
|
|
wprintf(wszNewLine);
|
|
|
|
hr = S_OK;
|
|
|
|
error:
|
|
cuFreeStringArray(ppwszList);
|
|
if (NULL != pbOut)
|
|
{
|
|
LocalFree(pbOut);
|
|
}
|
|
cuUnloadCRL(&pCRLContext);
|
|
cuUnloadCert(&pCertContext);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbShutDownServer(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszArg1,
|
|
IN WCHAR const *pwszArg2,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = CertSrvServerControl(g_pwszConfig, CSCONTROL_SHUTDOWN, NULL, NULL);
|
|
_JumpIfError(hr, error, "CertSrvServerControl");
|
|
|
|
error:
|
|
if (E_ACCESSDENIED == hr)
|
|
{
|
|
g_uiExtraErrorInfo = IDS_ERROR_ACCESSDENIED_CAUSE;
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbIsValidCertificate(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszSerialNumber,
|
|
IN WCHAR const *pwszArg2,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
BSTR strSerialNumber = NULL;
|
|
LONG Reason = CRL_REASON_KEY_COMPROMISE;
|
|
BOOL fMustRelease = FALSE;
|
|
LONG Disposition;
|
|
|
|
hr = myMakeSerialBstr(pwszSerialNumber, &strSerialNumber);
|
|
_JumpIfError(hr, error, "myMakeSerialBstr");
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Admin_IsValidCertificate(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
strSerialNumber,
|
|
&Disposition);
|
|
_JumpIfError(hr, error, "Admin_IsValidCertificate");
|
|
|
|
switch (Disposition)
|
|
{
|
|
case CA_DISP_INVALID:
|
|
wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_INVALID), strSerialNumber); // "Certificate disposition for "%ws" is invalid"
|
|
wprintf(wszNewLine);
|
|
break;
|
|
|
|
case CA_DISP_VALID:
|
|
wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_VALID), strSerialNumber); // "Certificate disposition for "%ws" is valid"
|
|
wprintf(wszNewLine);
|
|
break;
|
|
|
|
case CA_DISP_UNDER_SUBMISSION:
|
|
wprintf(myLoadResourceString(IDS_CERT_DISPOSITION_PENDING), strSerialNumber); // "Certificate request for "%ws" is pending"
|
|
wprintf(wszNewLine);
|
|
break;
|
|
|
|
case CA_DISP_REVOKED:
|
|
hr = Admin_GetRevocationReason(&diAdmin, &Reason);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintIfError(hr, "Admin_GetRevocationReason");
|
|
Reason = CRL_REASON_UNSPECIFIED;
|
|
}
|
|
wprintf(
|
|
myLoadResourceString(IDS_CERT_DISPOSITION_REVOKED), // "Certificate disposition for "%ws" is revoked (%ws)"
|
|
strSerialNumber,
|
|
wszCRLReason(Reason));
|
|
wprintf(wszNewLine);
|
|
break;
|
|
}
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
if (NULL != strSerialNumber)
|
|
{
|
|
SysFreeString(strSerialNumber);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
#define wszREQUEST L"Request"
|
|
#define wszCERT L"Cert"
|
|
|
|
HRESULT
|
|
verbDeleteRow(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszRowIdOrDate,
|
|
OPTIONAL IN WCHAR const *pwszTable,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszLocalTime = NULL;
|
|
DISPATCHINTERFACE diAdmin;
|
|
BOOL fMustRelease = FALSE;
|
|
DWORD Flags;
|
|
LONG RowId;
|
|
DATE date;
|
|
LONG Table;
|
|
LONG Count;
|
|
|
|
hr = cuGetLong(pwszRowIdOrDate, &RowId);
|
|
if (S_OK != hr)
|
|
{
|
|
FILETIME ftCurrent;
|
|
FILETIME ftQuery;
|
|
|
|
RowId = 0;
|
|
|
|
hr = myWszLocalTimeToGMTDate(pwszRowIdOrDate, &date);
|
|
_JumpIfError(hr, error, "invalid RowId or date");
|
|
|
|
hr = myGMTDateToWszLocalTime(&date, FALSE, &pwszLocalTime);
|
|
_JumpIfError(hr, error, "myGMTDateToWszLocalTime");
|
|
|
|
GetSystemTimeAsFileTime(&ftCurrent);
|
|
|
|
hr = myDateToFileTime(&date, &ftQuery);
|
|
_JumpIfError(hr, error, "myDateToFileTime");
|
|
|
|
if (0 > CompareFileTime(&ftCurrent, &ftQuery))
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_DATE_IN_FUTURE), // "The date specified is in the future: %ws"
|
|
pwszLocalTime);
|
|
wprintf(wszNewLine);
|
|
if (!g_fForce)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "date in future");
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (0 == RowId)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "zero RowId");
|
|
}
|
|
date = 0.0;
|
|
}
|
|
|
|
hr = E_INVALIDARG;
|
|
Table = CVRC_TABLE_REQCERT;
|
|
Flags = 0;
|
|
if (NULL == pwszTable)
|
|
{
|
|
if (0 == RowId)
|
|
{
|
|
wprintf(
|
|
myLoadResourceString(IDS_FORMAT_DATE_REQUIRES_TABLE), // "One of the following tables must be specified when deleting rows older than %ws:"
|
|
pwszLocalTime);
|
|
wprintf(wszNewLine);
|
|
wprintf(L" %ws\n", wszREQUEST);
|
|
wprintf(L" %ws\n", wszCERT);
|
|
wprintf(L" %ws\n", g_wszCRL);
|
|
_JumpError(hr, error, "date requires table");
|
|
}
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(wszREQUEST, pwszTable))
|
|
{
|
|
Flags = CDR_REQUEST_LAST_CHANGED; // assume date query
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(wszCERT, pwszTable))
|
|
{
|
|
Flags = CDR_EXPIRED; // assume date query
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(g_wszExt, pwszTable))
|
|
{
|
|
Table = CVRC_TABLE_EXTENSIONS;
|
|
if (0 == RowId)
|
|
{
|
|
_JumpError(hr, error, "no date in Extension table");
|
|
}
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(g_wszAttrib, pwszTable))
|
|
{
|
|
Table = CVRC_TABLE_ATTRIBUTES;
|
|
if (0 == RowId)
|
|
{
|
|
_JumpError(hr, error, "no date in Request Attribute table");
|
|
}
|
|
}
|
|
else
|
|
if (0 == lstrcmpi(g_wszCRL, pwszTable))
|
|
{
|
|
Table = CVRC_TABLE_CRL; // assume date query
|
|
}
|
|
else
|
|
{
|
|
_JumpError(hr, error, "bad table name");
|
|
}
|
|
if (0 != RowId)
|
|
{
|
|
Flags = 0; // not a date query
|
|
|
|
}
|
|
else if (g_fVerbose)
|
|
{
|
|
wprintf(L"%ws\n", pwszLocalTime);
|
|
}
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
Count = 0;
|
|
hr = Admin2_DeleteRow(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
Flags,
|
|
date,
|
|
Table,
|
|
RowId,
|
|
&Count);
|
|
wprintf(myLoadResourceString(IDS_FORMAT_DELETED_ROW_COUNT), Count);
|
|
wprintf(wszNewLine);
|
|
_JumpIfError(hr, error, "Admin2_DeleteRow");
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
if (NULL != pwszLocalTime)
|
|
{
|
|
LocalFree(pwszLocalTime);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbSetAttributes(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszRequestId,
|
|
IN WCHAR const *pwszAttributes,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
LONG RequestId;
|
|
BSTR strAttributes = NULL;
|
|
WCHAR *pwsz;
|
|
BOOL fMustRelease = FALSE;
|
|
|
|
if (!ConvertWszToBstr(&strAttributes, pwszAttributes, MAXDWORD))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
for (pwsz = strAttributes; L'\0' != *pwsz; pwsz++)
|
|
{
|
|
switch (*pwsz)
|
|
{
|
|
case L';':
|
|
*pwsz = L'\n';
|
|
break;
|
|
|
|
case L'\\':
|
|
if (L'n' == pwsz[1])
|
|
{
|
|
*pwsz++ = L'\r';
|
|
*pwsz = L'\n';
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
hr = cuGetLong(pwszRequestId, &RequestId);
|
|
_JumpIfError(hr, error, "RequestId must be a number");
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Admin_SetRequestAttributes(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
RequestId,
|
|
strAttributes);
|
|
_JumpIfError(hr, error, "Admin_SetAttributes");
|
|
|
|
error:
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
if (NULL != strAttributes)
|
|
{
|
|
SysFreeString(strAttributes);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbSetExtension(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszRequestId,
|
|
IN WCHAR const *pwszExtensionName,
|
|
IN WCHAR const *pwszFlags,
|
|
IN WCHAR const *pwszValue)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
LONG RequestId;
|
|
LONG Flags;
|
|
BSTR strExtensionName = NULL;
|
|
BSTR strValue = NULL;
|
|
LONG PropType;
|
|
VARIANT var;
|
|
BOOL fMustRelease = FALSE;
|
|
BYTE *pbValue = NULL;
|
|
DWORD cbValue;
|
|
|
|
hr = cuGetLong(pwszRequestId, &RequestId);
|
|
_JumpIfError(hr, error, "RequestId must be a number");
|
|
|
|
if (!ConvertWszToBstr(&strExtensionName, pwszExtensionName, MAXDWORD))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
hr = cuGetLong(pwszFlags, &Flags);
|
|
_JumpIfError(hr, error, "Flags must be a number");
|
|
|
|
if (~EXTENSION_POLICY_MASK & Flags)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "Flags must be <= 0xffff");
|
|
}
|
|
if (L'@' == *pwszValue)
|
|
{
|
|
pwszValue++;
|
|
|
|
// Read in and decode the extension from a file.
|
|
// Try Hex-Ascii, Base64 with and without a header, then binary.
|
|
hr = DecodeFileW(pwszValue, &pbValue, &cbValue, CRYPT_STRING_HEX_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
hr = DecodeFileW(pwszValue, &pbValue, &cbValue, CRYPT_STRING_ANY);
|
|
_JumpIfError(hr, error, "DecodeFileW");
|
|
}
|
|
|
|
CSASSERT(NULL != pbValue && 0 != cbValue);
|
|
|
|
var.vt = VT_BSTR;
|
|
PropType = PROPTYPE_BINARY;
|
|
|
|
DumpHex(0, pbValue, cbValue);
|
|
if (!ConvertWszToBstr(&strValue, (WCHAR const *) pbValue, cbValue))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
var.bstrVal = strValue;
|
|
}
|
|
else
|
|
{
|
|
hr = cuGetLong(pwszValue, &var.lVal);
|
|
if (S_OK == hr)
|
|
{
|
|
var.vt = VT_I4;
|
|
PropType = PROPTYPE_LONG;
|
|
}
|
|
else
|
|
{
|
|
hr = myWszLocalTimeToGMTDate(pwszValue, &var.date);
|
|
if (S_OK == hr)
|
|
{
|
|
var.vt = VT_DATE;
|
|
PropType = PROPTYPE_DATE;
|
|
}
|
|
else
|
|
{
|
|
var.vt = VT_BSTR;
|
|
PropType = PROPTYPE_STRING;
|
|
if (!ConvertWszToBstr(&strValue, pwszValue, MAXDWORD))
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "ConvertWszToBstr");
|
|
}
|
|
var.bstrVal = strValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
if (S_OK != hr)
|
|
{
|
|
_JumpError(hr, error, "Admin_Init");
|
|
}
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Admin_SetCertificateExtension(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
RequestId,
|
|
strExtensionName,
|
|
PropType,
|
|
Flags,
|
|
&var);
|
|
_JumpIfError(hr, error, "Admin_SetExtension");
|
|
|
|
error:
|
|
if (NULL != pbValue)
|
|
{
|
|
LocalFree(pbValue);
|
|
}
|
|
if (fMustRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
if (NULL != strExtensionName)
|
|
{
|
|
SysFreeString(strExtensionName);
|
|
}
|
|
if (NULL != strValue)
|
|
{
|
|
SysFreeString(strValue);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbImportCertificate(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszCertificateFile,
|
|
IN WCHAR const *pwszArg2,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
LONG dwReqID;
|
|
CERT_CONTEXT const *pCertContext = NULL;
|
|
DISPATCHINTERFACE diAdmin;
|
|
BOOL fRelease = FALSE;
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fRelease = TRUE;
|
|
|
|
hr = cuLoadCert(pwszCertificateFile, &pCertContext);
|
|
_JumpIfError(hr, error, "cuLoadCert");
|
|
|
|
hr = Admin_ImportCertificate(
|
|
&diAdmin,
|
|
g_pwszConfig,
|
|
(WCHAR const *) pCertContext->pbCertEncoded,
|
|
pCertContext->cbCertEncoded,
|
|
(g_fForce? ICF_ALLOWFOREIGN : 0) | CR_IN_BINARY,
|
|
&dwReqID);
|
|
_JumpIfError(hr, error, "Admin_ImportCertificate");
|
|
|
|
wprintf(myLoadResourceString(IDS_FORMAT_IMPORTCERT), dwReqID);
|
|
wprintf(wszNewLine);
|
|
|
|
error:
|
|
cuUnloadCert(&pCertContext);
|
|
if (fRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
GetArchivedKey(
|
|
IN WCHAR const *pwszConfig,
|
|
IN DWORD RequestId,
|
|
OPTIONAL IN WCHAR const *pwszfnRecoveryBlob)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diAdmin;
|
|
BOOL fRelease = FALSE;
|
|
BSTR strKey = NULL;
|
|
WCHAR *pwszT = NULL;
|
|
|
|
hr = Admin_Init(g_DispatchFlags, &diAdmin);
|
|
_JumpIfError(hr, error, "Admin_Init");
|
|
|
|
fRelease = TRUE;
|
|
|
|
hr = Admin2_GetArchivedKey(
|
|
&diAdmin,
|
|
pwszConfig,
|
|
RequestId,
|
|
CR_OUT_BINARY,
|
|
&strKey);
|
|
_JumpIfError(hr, error, "Admin_GetArchivedKey");
|
|
|
|
if (NULL == pwszfnRecoveryBlob)
|
|
{
|
|
hr = myCryptBinaryToString(
|
|
(BYTE const *) strKey,
|
|
SysStringByteLen(strKey),
|
|
CRYPT_STRING_BASE64HEADER,
|
|
&pwszT);
|
|
_JumpIfError(hr, error, "myCryptBinaryToString");
|
|
|
|
cuPrintCRLFString(NULL, pwszT);
|
|
}
|
|
else
|
|
{
|
|
hr = EncodeToFileW(
|
|
pwszfnRecoveryBlob,
|
|
(BYTE const *) strKey,
|
|
SysStringByteLen(strKey),
|
|
CRYPT_STRING_BINARY | g_EncodeFlags);
|
|
_JumpIfError(hr, error, "EncodeToFileW");
|
|
}
|
|
|
|
error:
|
|
if (NULL != pwszT)
|
|
{
|
|
LocalFree(pwszT);
|
|
}
|
|
if (NULL != strKey)
|
|
{
|
|
SysFreeString(strKey);
|
|
}
|
|
if (fRelease)
|
|
{
|
|
Admin_Release(&diAdmin);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
typedef struct _GETKEYSERIAL {
|
|
struct _GETKEYSERIAL *Next;
|
|
BSTR strConfig;
|
|
LONG RequestId;
|
|
BSTR strSerialNumber;
|
|
BSTR strCommonName;
|
|
BSTR strUPN;
|
|
BSTR strHash;
|
|
BSTR strCert;
|
|
} GETKEYSERIAL;
|
|
|
|
|
|
VOID
|
|
FreeKeySerialEntry(
|
|
IN OUT GETKEYSERIAL *pks)
|
|
{
|
|
if (NULL != pks->strConfig)
|
|
{
|
|
SysFreeString(pks->strConfig);
|
|
}
|
|
if (NULL != pks->strSerialNumber)
|
|
{
|
|
SysFreeString(pks->strSerialNumber);
|
|
}
|
|
if (NULL != pks->strCommonName)
|
|
{
|
|
SysFreeString(pks->strCommonName);
|
|
}
|
|
if (NULL != pks->strUPN)
|
|
{
|
|
SysFreeString(pks->strUPN);
|
|
}
|
|
if (NULL != pks->strHash)
|
|
{
|
|
SysFreeString(pks->strHash);
|
|
}
|
|
if (NULL != pks->strCert)
|
|
{
|
|
SysFreeString(pks->strCert);
|
|
}
|
|
LocalFree(pks);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
AddKeySerialList(
|
|
IN WCHAR const *pwszConfig,
|
|
IN LONG RequestId,
|
|
IN WCHAR const *pwszSerialNumber,
|
|
IN WCHAR const *pwszCommonName,
|
|
IN WCHAR const *pwszUPN,
|
|
IN WCHAR const *pwszHash,
|
|
IN BYTE const *pbCert,
|
|
IN DWORD cbCert,
|
|
IN OUT GETKEYSERIAL **ppksList)
|
|
{
|
|
HRESULT hr;
|
|
GETKEYSERIAL *pksNew = NULL;
|
|
GETKEYSERIAL *pksT;
|
|
GETKEYSERIAL *pksPrev;
|
|
BOOL fNewConfig = TRUE;
|
|
|
|
pksNew = (GETKEYSERIAL *) LocalAlloc(
|
|
LMEM_FIXED | LMEM_ZEROINIT,
|
|
sizeof(*pksNew));
|
|
if (NULL == pksNew)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
pksNew->RequestId = RequestId;
|
|
|
|
pksNew->strConfig = SysAllocString(pwszConfig);
|
|
pksNew->strSerialNumber = SysAllocString(pwszSerialNumber);
|
|
pksNew->strCommonName = SysAllocString(pwszCommonName);
|
|
pksNew->strUPN = SysAllocString(pwszUPN);
|
|
pksNew->strHash = SysAllocString(pwszHash);
|
|
pksNew->strCert = SysAllocStringByteLen((char const *) pbCert, cbCert);
|
|
if (NULL == pksNew->strConfig ||
|
|
NULL == pksNew->strSerialNumber ||
|
|
(NULL != pwszCommonName && NULL == pksNew->strCommonName) ||
|
|
(NULL != pwszUPN && NULL == pksNew->strUPN) ||
|
|
NULL == pksNew->strHash ||
|
|
NULL == pksNew->strCert)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "LocalAlloc");
|
|
}
|
|
pksPrev = NULL;
|
|
for (pksT = *ppksList; NULL != pksT; pksT = pksT->Next)
|
|
{
|
|
if (NULL != pksT->strConfig)
|
|
{
|
|
fNewConfig = 0 != lstrcmp(pksT->strConfig, pksNew->strConfig);
|
|
}
|
|
pksPrev = pksT;
|
|
}
|
|
if (NULL == pksPrev)
|
|
{
|
|
*ppksList = pksNew;
|
|
}
|
|
else
|
|
{
|
|
pksPrev->Next = pksNew;
|
|
}
|
|
if (!fNewConfig)
|
|
{
|
|
SysFreeString(pksNew->strConfig);
|
|
pksNew->strConfig = NULL;
|
|
}
|
|
pksNew = NULL;
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pksNew)
|
|
{
|
|
FreeKeySerialEntry(pksNew);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
cuViewQuery(
|
|
IN WCHAR const *pwszConfig,
|
|
IN WCHAR const *pwszColumn,
|
|
IN WCHAR const *pwszValue1,
|
|
OPTIONAL IN WCHAR const *pwszValue2,
|
|
IN OUT GETKEYSERIAL **ppksList,
|
|
OUT BOOL *pfConnectionFailed)
|
|
{
|
|
HRESULT hr;
|
|
DWORD cwc;
|
|
DISPATCHINTERFACE diView;
|
|
DISPATCHINTERFACE diViewRow;
|
|
DISPATCHINTERFACE diViewColumn;
|
|
BOOL fMustRelease = FALSE;
|
|
BOOL fMustReleaseRow = FALSE;
|
|
BOOL fMustReleaseColumn = FALSE;
|
|
LONG ColIndex;
|
|
LONG RowIndex;
|
|
DWORD cRow;
|
|
VARIANT var;
|
|
LONG RequestId;
|
|
DWORD i;
|
|
static WCHAR *apwszCol[] =
|
|
{
|
|
#define IV_REQUESTID 0
|
|
wszPROPCERTIFICATEREQUESTID,
|
|
|
|
#define IV_SERIALNUMBER 1
|
|
wszPROPCERTIFICATESERIALNUMBER,
|
|
|
|
#define IV_COMMONNAME 2
|
|
wszPROPCOMMONNAME,
|
|
|
|
#define IV_ARCHIVEDKEY 3
|
|
wszPROPREQUESTRAWARCHIVEDKEY,
|
|
|
|
#define IV_HASH 4
|
|
wszPROPCERTIFICATEHASH,
|
|
|
|
#define IV_CERT 5
|
|
wszPROPRAWCERTIFICATE,
|
|
|
|
#define IV_UPN 6
|
|
wszPROPCERTIFICATEUPN,
|
|
};
|
|
static LONG altype[] =
|
|
{
|
|
PROPTYPE_LONG,
|
|
PROPTYPE_STRING,
|
|
PROPTYPE_STRING,
|
|
PROPTYPE_BINARY,
|
|
PROPTYPE_STRING,
|
|
PROPTYPE_BINARY,
|
|
PROPTYPE_STRING,
|
|
};
|
|
BSTR astrValue[ARRAYSIZE(apwszCol)];
|
|
|
|
ZeroMemory(&astrValue, sizeof(astrValue));
|
|
VariantInit(&var);
|
|
*pfConnectionFailed = TRUE;
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTUTILI,
|
|
"Query(%ws, %ws == %ws + %ws)\n",
|
|
pwszConfig,
|
|
pwszColumn,
|
|
pwszValue1,
|
|
pwszValue2));
|
|
|
|
hr = View_Init(g_DispatchFlags, &diView);
|
|
_JumpIfError(hr, error, "View_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
hr = View_OpenConnection(&diView, pwszConfig);
|
|
_JumpIfError(hr, error, "View_OpenConnection");
|
|
|
|
*pfConnectionFailed = FALSE;
|
|
|
|
hr = View_GetColumnIndex(
|
|
&diView,
|
|
CVRC_COLUMN_SCHEMA,
|
|
pwszColumn,
|
|
&ColIndex);
|
|
_JumpIfErrorStr(hr, error, "View_GetColumnIndex", pwszColumn);
|
|
|
|
cwc = wcslen(pwszValue1);
|
|
if (NULL != pwszValue2)
|
|
{
|
|
cwc += wcslen(pwszValue2);
|
|
}
|
|
var.bstrVal = SysAllocStringLen(NULL, cwc);
|
|
if (NULL == var.bstrVal)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
_JumpError(hr, error, "SysAllocString");
|
|
}
|
|
var.vt = VT_BSTR;
|
|
wcscpy(var.bstrVal, pwszValue1);
|
|
if (NULL != pwszValue2)
|
|
{
|
|
wcscat(var.bstrVal, pwszValue2);
|
|
}
|
|
|
|
hr = View_SetRestriction(
|
|
&diView,
|
|
ColIndex, // Restriction ColumnIndex
|
|
CVR_SEEK_EQ,
|
|
CVR_SORT_ASCEND,
|
|
&var); // pvarValue
|
|
_JumpIfError(hr, error, "View_SetRestriction");
|
|
|
|
hr = View_SetResultColumnCount(&diView, ARRAYSIZE(apwszCol));
|
|
_JumpIfError(hr, error, "View_SetResultColumnCount");
|
|
|
|
for (i = 0; i < ARRAYSIZE(apwszCol); i++)
|
|
{
|
|
hr = View_GetColumnIndex(
|
|
&diView,
|
|
CVRC_COLUMN_SCHEMA,
|
|
apwszCol[i],
|
|
&ColIndex);
|
|
_JumpIfErrorStr(
|
|
hr,
|
|
error,
|
|
"View_GetColumnIndex",
|
|
apwszCol[i]);
|
|
|
|
hr = View_SetResultColumn(&diView, ColIndex);
|
|
_JumpIfError(hr, error, "View_SetResultColumn");
|
|
}
|
|
|
|
hr = View_OpenView(&diView, &diViewRow);
|
|
_JumpIfError(hr, error, "View_OpenView");
|
|
|
|
fMustReleaseRow = TRUE;
|
|
|
|
for (cRow = 0; ; cRow++)
|
|
{
|
|
hr = ViewRow_Next(&diViewRow, &RowIndex);
|
|
if (S_FALSE == hr || (S_OK == hr && -1 == RowIndex))
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "ViewRow_Next");
|
|
|
|
if (fMustReleaseColumn)
|
|
{
|
|
ViewColumn_Release(&diViewColumn);
|
|
fMustReleaseColumn = FALSE;
|
|
}
|
|
hr = ViewRow_EnumCertViewColumn(&diViewRow, &diViewColumn);
|
|
_JumpIfError(hr, error, "ViewRow_EnumCertViewColumn");
|
|
|
|
fMustReleaseColumn = TRUE;
|
|
|
|
for (i = 0; i < ARRAYSIZE(apwszCol); i++)
|
|
{
|
|
VOID *pv;
|
|
|
|
hr = ViewColumn_Next(&diViewColumn, &ColIndex);
|
|
if (S_FALSE == hr || (S_OK == hr && -1 == ColIndex))
|
|
{
|
|
break;
|
|
}
|
|
_JumpIfError(hr, error, "ViewColumn_Next");
|
|
|
|
pv = &RequestId;
|
|
if (PROPTYPE_LONG != altype[i])
|
|
{
|
|
pv = &astrValue[i];
|
|
}
|
|
|
|
hr = ViewColumn_GetValue(
|
|
&diViewColumn,
|
|
CV_OUT_BINARY,
|
|
altype[i],
|
|
pv);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintErrorStr2(
|
|
hr,
|
|
"ViewColumn_GetValue",
|
|
apwszCol[i],
|
|
CERTSRV_E_PROPERTY_EMPTY);
|
|
if (CERTSRV_E_PROPERTY_EMPTY != hr)
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBGPRINT((
|
|
DBG_SS_CERTUTILI,
|
|
"RequestId=%u Serial=%ws CN=%ws UPN=%ws Key=%u\n",
|
|
RequestId,
|
|
astrValue[IV_SERIALNUMBER],
|
|
astrValue[IV_COMMONNAME],
|
|
astrValue[IV_UPN],
|
|
NULL != astrValue[IV_ARCHIVEDKEY]));
|
|
|
|
if (NULL != astrValue[IV_SERIALNUMBER] &&
|
|
NULL != astrValue[IV_HASH] &&
|
|
NULL != astrValue[IV_CERT] &&
|
|
(g_fForce || NULL != astrValue[IV_ARCHIVEDKEY]))
|
|
{
|
|
hr = AddKeySerialList(
|
|
pwszConfig,
|
|
RequestId,
|
|
astrValue[IV_SERIALNUMBER],
|
|
astrValue[IV_COMMONNAME],
|
|
astrValue[IV_UPN],
|
|
astrValue[IV_HASH],
|
|
(BYTE const *) astrValue[IV_CERT],
|
|
SysStringByteLen(astrValue[IV_CERT]),
|
|
ppksList);
|
|
_JumpIfError(hr, error, "AddKeySerialList");
|
|
}
|
|
|
|
for (i = 0; i < ARRAYSIZE(astrValue); i++)
|
|
{
|
|
if (NULL != astrValue[i])
|
|
{
|
|
SysFreeString(astrValue[i]);
|
|
astrValue[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (fMustReleaseColumn)
|
|
{
|
|
ViewColumn_Release(&diViewColumn);
|
|
}
|
|
if (fMustReleaseRow)
|
|
{
|
|
ViewRow_Release(&diViewRow);
|
|
}
|
|
if (fMustRelease)
|
|
{
|
|
View_Release(&diView);
|
|
}
|
|
for (i = 0; i < ARRAYSIZE(astrValue); i++)
|
|
{
|
|
if (NULL != astrValue[i])
|
|
{
|
|
SysFreeString(astrValue[i]);
|
|
}
|
|
}
|
|
VariantClear(&var);
|
|
return(hr);
|
|
}
|
|
|
|
|
|
#define wszUSERS L"Users"
|
|
#define wszRECIPIENTS L"recipients"
|
|
|
|
#define wszUSERSNL wszUSERS L"\n"
|
|
#define wszRECIPIENTSNL wszRECIPIENTS L"\n"
|
|
#define wszNLRECIPIENTS L"\n" wszRECIPIENTS
|
|
|
|
HRESULT
|
|
GetKey(
|
|
IN WCHAR const *pwszConfig,
|
|
IN WCHAR const *pwszCommonName,
|
|
OPTIONAL IN WCHAR const *pwszRequesterName,
|
|
OPTIONAL IN WCHAR const *pwszUPN,
|
|
OPTIONAL IN WCHAR const *pwszSerialNumber,
|
|
OPTIONAL IN WCHAR const *pwszHash,
|
|
IN OUT GETKEYSERIAL **ppksList)
|
|
{
|
|
HRESULT hr;
|
|
BOOL fConnectionFailed;
|
|
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(myLoadResourceString(IDS_FORMAT_QUERYING), pwszConfig);
|
|
wprintf(L"...");
|
|
}
|
|
if (NULL != pwszSerialNumber)
|
|
{
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPCERTIFICATESERIALNUMBER,
|
|
pwszSerialNumber,
|
|
NULL,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
if (S_OK != hr)
|
|
{
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATESERIALNUMBER);
|
|
if (fConnectionFailed)
|
|
{
|
|
goto error;
|
|
}
|
|
}
|
|
}
|
|
if (NULL != pwszHash)
|
|
{
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPCERTIFICATEHASH,
|
|
pwszHash,
|
|
NULL,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATEHASH);
|
|
}
|
|
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPCOMMONNAME,
|
|
pwszCommonName,
|
|
NULL,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME);
|
|
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPCOMMONNAME,
|
|
wszUSERSNL,
|
|
pwszCommonName,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME L"+" wszUSERS);
|
|
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPCOMMONNAME,
|
|
wszRECIPIENTSNL,
|
|
pwszCommonName,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME L"+" wszUSERS);
|
|
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPCOMMONNAME,
|
|
pwszCommonName,
|
|
wszNLRECIPIENTS,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPSUBJECTCOMMONNAME L"+" wszUSERS);
|
|
|
|
if (NULL != pwszRequesterName)
|
|
{
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPREQUESTERNAME,
|
|
pwszRequesterName,
|
|
NULL,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPREQUESTERNAME);
|
|
}
|
|
|
|
if (NULL != pwszUPN)
|
|
{
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(L"...");
|
|
}
|
|
hr = cuViewQuery(
|
|
pwszConfig,
|
|
wszPROPCERTIFICATEUPN,
|
|
pwszUPN,
|
|
NULL,
|
|
ppksList,
|
|
&fConnectionFailed);
|
|
_PrintIfErrorStr(hr, "cuViewQuery", wszPROPCERTIFICATEUPN);
|
|
}
|
|
|
|
if (!g_fQuiet)
|
|
{
|
|
wprintf(wszNewLine);
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
cuConvertEscapeSequences(
|
|
IN OUT WCHAR *pwsz)
|
|
{
|
|
WCHAR *pwszSrc = pwsz;
|
|
WCHAR *pwszDst = pwsz;
|
|
|
|
while (L'\0' != *pwszSrc)
|
|
{
|
|
WCHAR wc = *pwszSrc++;
|
|
|
|
if (L'\\' == wc)
|
|
{
|
|
switch (*pwszSrc)
|
|
{
|
|
case 'n':
|
|
wc = L'\n';
|
|
pwszSrc++;
|
|
break;
|
|
|
|
case 'r':
|
|
wc = L'\r';
|
|
pwszSrc++;
|
|
break;
|
|
|
|
case 't':
|
|
wc = L'\t';
|
|
pwszSrc++;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
*pwszDst++ = wc;
|
|
}
|
|
*pwszDst = L'\0';
|
|
}
|
|
|
|
|
|
WCHAR *
|
|
SplitToken(
|
|
IN OUT WCHAR **ppwszIn,
|
|
IN WCHAR *pwcSeparator)
|
|
{
|
|
WCHAR *pwszOut = NULL;
|
|
WCHAR *pwszNext = NULL;
|
|
WCHAR *pwszIn;
|
|
WCHAR *pwsz;
|
|
|
|
pwszIn = *ppwszIn;
|
|
if (NULL != pwszIn)
|
|
{
|
|
pwszOut = pwszIn;
|
|
pwsz = wcschr(pwszIn, *pwcSeparator);
|
|
if (NULL != pwsz)
|
|
{
|
|
*pwsz++ = L'\0';
|
|
pwszNext = pwsz;
|
|
}
|
|
}
|
|
*ppwszIn = pwszNext;
|
|
return(pwszOut);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SimplifyCommonName(
|
|
IN WCHAR const *pwszCommonName,
|
|
OUT WCHAR **ppwszSimpleName)
|
|
{
|
|
HRESULT hr;
|
|
WCHAR *pwszDup = NULL;
|
|
WCHAR *pwszRemain;
|
|
WCHAR const *pwszToken;
|
|
|
|
*ppwszSimpleName = NULL;
|
|
|
|
hr = myDupString(pwszCommonName, &pwszDup);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
pwszRemain = pwszDup;
|
|
while (TRUE)
|
|
{
|
|
pwszToken = SplitToken(&pwszRemain, wszNAMESEPARATORDEFAULT);
|
|
if (NULL == pwszToken)
|
|
{
|
|
pwszToken = pwszCommonName;
|
|
break;
|
|
}
|
|
if (0 != lstrcmpi(wszUSERS, pwszToken) &&
|
|
0 != lstrcmpi(wszRECIPIENTS, pwszToken))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
hr = myDupString(pwszToken, ppwszSimpleName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
error:
|
|
if (NULL != pwszDup)
|
|
{
|
|
LocalFree(pwszDup);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DumpGetRecoverMergeCommandLine(
|
|
OPTIONAL IN BSTR const strConfig, // NULL -> -RecoverKey command line
|
|
IN BOOL fRecoverKey,
|
|
IN GETKEYSERIAL const *pks,
|
|
OPTIONAL OUT WCHAR **ppwszSimpleName)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pcc = NULL;
|
|
CERT_INFO *pCertInfo;
|
|
BSTR strSerialNumber = NULL;
|
|
WCHAR *pwszSimpleName = NULL;
|
|
|
|
if (NULL != ppwszSimpleName)
|
|
{
|
|
*ppwszSimpleName = NULL;
|
|
}
|
|
pcc = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
(BYTE const *) pks->strCert,
|
|
SysStringByteLen(pks->strCert));
|
|
if (NULL == pcc)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
pCertInfo = pcc->pCertInfo;
|
|
|
|
// Convert serial number to string
|
|
|
|
hr = MultiByteIntegerToBstr(
|
|
FALSE,
|
|
pCertInfo->SerialNumber.cbData,
|
|
pCertInfo->SerialNumber.pbData,
|
|
&strSerialNumber);
|
|
_JumpIfError(hr, error, "MultiByteIntegerToBstr");
|
|
|
|
hr = SimplifyCommonName(pks->strCommonName, &pwszSimpleName);
|
|
_JumpIfError(hr, error, "SimplifyCommonName");
|
|
|
|
if (NULL != strConfig)
|
|
{
|
|
wprintf(
|
|
L"%ws -config \"%ws\" -getkey %ws \"%ws-%ws.rec\"\n\n",
|
|
g_pwszProg,
|
|
strConfig,
|
|
strSerialNumber,
|
|
pwszSimpleName,
|
|
strSerialNumber);
|
|
}
|
|
else if (fRecoverKey)
|
|
{
|
|
wprintf(
|
|
L"%ws -p password -recoverkey \"%ws-%ws.rec\" \"%ws-%ws.pfx\"\n\n",
|
|
g_pwszProg,
|
|
pwszSimpleName,
|
|
strSerialNumber,
|
|
pwszSimpleName,
|
|
strSerialNumber);
|
|
}
|
|
else // -MergePFX
|
|
{
|
|
wprintf(
|
|
L"%ws-%ws.pfx",
|
|
pwszSimpleName,
|
|
strSerialNumber);
|
|
}
|
|
if (NULL != ppwszSimpleName)
|
|
{
|
|
*ppwszSimpleName = pwszSimpleName;
|
|
pwszSimpleName = NULL;
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pcc)
|
|
{
|
|
CertFreeCertificateContext(pcc);
|
|
}
|
|
if (NULL != strSerialNumber)
|
|
{
|
|
SysFreeString(strSerialNumber);
|
|
}
|
|
if (NULL != pwszSimpleName)
|
|
{
|
|
LocalFree(pwszSimpleName);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
DumpRecoveryCandidate(
|
|
IN GETKEYSERIAL const *pks)
|
|
{
|
|
HRESULT hr;
|
|
CERT_CONTEXT const *pcc = NULL;
|
|
CERT_INFO *pCertInfo;
|
|
|
|
pcc = CertCreateCertificateContext(
|
|
X509_ASN_ENCODING,
|
|
(BYTE const *) pks->strCert,
|
|
SysStringByteLen(pks->strCert));
|
|
if (NULL == pcc)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertCreateCertificateContext");
|
|
}
|
|
pCertInfo = pcc->pCertInfo;
|
|
|
|
hr = cuDumpSerial(g_wszPad2, IDS_SERIAL, &pCertInfo->SerialNumber);
|
|
_JumpIfError(hr, error, "cuDumpSerial");
|
|
|
|
hr = cuDisplayCertName(
|
|
FALSE, // fMultiLine
|
|
g_wszPad2,
|
|
myLoadResourceString(IDS_SUBJECT), // "Subject"
|
|
g_wszPad2,
|
|
&pCertInfo->Subject);
|
|
_JumpIfError(hr, error, "cuDisplayCertName(Subject)");
|
|
|
|
if (NULL != pks->strUPN)
|
|
{
|
|
wprintf(g_wszPad2);
|
|
wprintf(myLoadResourceString(IDS_UPN_COLON)); // "UPN:"
|
|
wprintf(L"%ws\n", pks->strUPN);
|
|
}
|
|
|
|
wprintf(g_wszPad2);
|
|
hr = cuDumpFileTime(IDS_NOTBEFORE, NULL, &pCertInfo->NotBefore);
|
|
_JumpIfError(hr, error, "cuDumpFileTime");
|
|
|
|
wprintf(g_wszPad2);
|
|
hr = cuDumpFileTime(IDS_NOTAFTER, NULL, &pCertInfo->NotAfter);
|
|
_JumpIfError(hr, error, "cuDumpFileTime");
|
|
|
|
hr = cuDumpCertType(g_wszPad2, pCertInfo);
|
|
_PrintIfError(hr, "cuDumpCertType");
|
|
|
|
wprintf(g_wszPad2);
|
|
hr = cuDisplayHash(NULL, pcc, NULL, CERT_SHA1_HASH_PROP_ID, L"sha1");
|
|
_JumpIfError(hr, error, "cuDisplayHash");
|
|
|
|
error:
|
|
wprintf(wszNewLine);
|
|
if (NULL != pcc)
|
|
{
|
|
CertFreeCertificateContext(pcc);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbGetKey(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszUserNameOrSerialNumber,
|
|
OPTIONAL IN WCHAR const *pwszfnRecoveryBlob,
|
|
IN WCHAR const *pwszArg3,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
DISPATCHINTERFACE diConfig;
|
|
BOOL fMustRelease = FALSE;
|
|
WCHAR *pwszCommonName = NULL;
|
|
WCHAR *pwszSimpleName = NULL;
|
|
WCHAR const *pwszRequesterName = NULL;
|
|
WCHAR const *pwszUPN = NULL;
|
|
BSTR strConfig = NULL;
|
|
BSTR strSerialNumber = NULL;
|
|
BYTE *pbHash = NULL;
|
|
DWORD cbHash;
|
|
BSTR strHash = NULL;
|
|
GETKEYSERIAL *pksList = NULL;
|
|
GETKEYSERIAL *pksT;
|
|
DWORD cCandidate;
|
|
|
|
hr = myMakeSerialBstr(pwszUserNameOrSerialNumber, &strSerialNumber);
|
|
CSASSERT((S_OK != hr) ^ (NULL != strSerialNumber));
|
|
|
|
hr = WszToMultiByteInteger(
|
|
TRUE,
|
|
pwszUserNameOrSerialNumber,
|
|
&cbHash,
|
|
&pbHash);
|
|
_PrintIfError2(hr, "WszToMultiByteInteger", hr);
|
|
if (S_OK == hr)
|
|
{
|
|
hr = MultiByteIntegerToBstr(TRUE, cbHash, pbHash, &strHash);
|
|
_JumpIfError(hr, error, "MultiByteIntegerToBstr");
|
|
}
|
|
hr = myDupString(pwszUserNameOrSerialNumber, &pwszCommonName);
|
|
_JumpIfError(hr, error, "myDupString");
|
|
|
|
cuConvertEscapeSequences(pwszCommonName);
|
|
|
|
if (NULL != wcschr(pwszUserNameOrSerialNumber, L'\\'))
|
|
{
|
|
pwszRequesterName = pwszUserNameOrSerialNumber;
|
|
}
|
|
if (NULL != wcschr(pwszUserNameOrSerialNumber, L'@'))
|
|
{
|
|
pwszUPN = pwszUserNameOrSerialNumber;
|
|
}
|
|
|
|
if (NULL == g_pwszConfig)
|
|
{
|
|
LONG i;
|
|
LONG count;
|
|
LONG Index;
|
|
|
|
hr = Config_Init(g_DispatchFlags, &diConfig);
|
|
_JumpIfError(hr, error, "Config_Init");
|
|
|
|
fMustRelease = TRUE;
|
|
|
|
hr = Config_Reset(&diConfig, 0, &count);
|
|
_JumpIfError(hr, error, "Config_Reset");
|
|
|
|
Index = 0;
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
hr = Config_Next(&diConfig, &Index);
|
|
if (S_OK != hr && S_FALSE != hr)
|
|
{
|
|
_JumpError(hr, error, "Config_Next");
|
|
}
|
|
hr = S_OK;
|
|
if (-1 == Index)
|
|
{
|
|
break;
|
|
}
|
|
|
|
hr = Config_GetField(&diConfig, wszCONFIG_CONFIG, &strConfig);
|
|
_JumpIfError(hr, error, "Config_GetField");
|
|
|
|
hr = GetKey(
|
|
strConfig,
|
|
pwszCommonName,
|
|
pwszRequesterName,
|
|
pwszUPN,
|
|
strSerialNumber,
|
|
strHash,
|
|
&pksList);
|
|
_PrintIfError(hr, "GetKey"); // Ignore connection failures
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = GetKey(
|
|
g_pwszConfig,
|
|
pwszCommonName,
|
|
pwszRequesterName,
|
|
pwszUPN,
|
|
strSerialNumber,
|
|
strHash,
|
|
&pksList);
|
|
_JumpIfError(hr, error, "GetKey");
|
|
}
|
|
|
|
cCandidate = 0;
|
|
for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
|
|
{
|
|
if (NULL != pksT->strConfig)
|
|
{
|
|
wprintf(L"\n\"%ws\"\n", pksT->strConfig);
|
|
}
|
|
hr = DumpRecoveryCandidate(pksT);
|
|
_PrintIfError(hr, "DumpRecoveryCandidate");
|
|
|
|
cCandidate++;
|
|
}
|
|
if (NULL == pwszfnRecoveryBlob && 0 != cCandidate)
|
|
{
|
|
BSTR strConfigT;
|
|
DWORD cPFX;
|
|
|
|
strConfigT = NULL;
|
|
for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
|
|
{
|
|
if (NULL != pksT->strConfig)
|
|
{
|
|
strConfigT = pksT->strConfig;
|
|
}
|
|
DumpGetRecoverMergeCommandLine(strConfigT, FALSE, pksT, NULL);
|
|
}
|
|
for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
|
|
{
|
|
DumpGetRecoverMergeCommandLine(NULL, TRUE, pksT, NULL);
|
|
}
|
|
|
|
cPFX = 0;
|
|
wprintf(L"%ws -p \"password,password\" -MergePFX \"", g_pwszProg);
|
|
for (pksT = pksList; NULL != pksT; pksT = pksT->Next)
|
|
{
|
|
if (0 != cPFX)
|
|
{
|
|
wprintf(L",");
|
|
}
|
|
DumpGetRecoverMergeCommandLine(
|
|
NULL,
|
|
FALSE,
|
|
pksT,
|
|
0 == cPFX? &pwszSimpleName : NULL);
|
|
cPFX++;
|
|
}
|
|
wprintf(L"\" \"%ws.pfx\"\n\n", pwszSimpleName);
|
|
}
|
|
if (1 != cCandidate)
|
|
{
|
|
hr = 0 == cCandidate? CRYPT_E_NOT_FOUND : TYPE_E_AMBIGUOUSNAME;
|
|
_JumpError(hr, error, "GetKey");
|
|
}
|
|
hr = GetArchivedKey(
|
|
pksList->strConfig,
|
|
pksList->RequestId,
|
|
pwszfnRecoveryBlob);
|
|
_JumpIfError(hr, error, "GetArchivedKey");
|
|
|
|
error:
|
|
while (NULL != pksList)
|
|
{
|
|
pksT = pksList;
|
|
pksList = pksList->Next;
|
|
FreeKeySerialEntry(pksT);
|
|
}
|
|
if (fMustRelease)
|
|
{
|
|
Config_Release(&diConfig);
|
|
}
|
|
if (NULL != strConfig)
|
|
{
|
|
SysFreeString(strConfig);
|
|
}
|
|
if (NULL != pwszSimpleName)
|
|
{
|
|
LocalFree(pwszSimpleName);
|
|
}
|
|
if (NULL != pwszCommonName)
|
|
{
|
|
LocalFree(pwszCommonName);
|
|
}
|
|
if (NULL != pbHash)
|
|
{
|
|
LocalFree(pbHash);
|
|
}
|
|
if (NULL != strHash)
|
|
{
|
|
SysFreeString(strHash);
|
|
}
|
|
if (NULL != strSerialNumber)
|
|
{
|
|
SysFreeString(strSerialNumber);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
VOID
|
|
DeleteKey(
|
|
IN CRYPT_KEY_PROV_INFO const *pkpi)
|
|
{
|
|
HCRYPTPROV hProv;
|
|
|
|
CryptAcquireContext(
|
|
&hProv,
|
|
pkpi->pwszContainerName,
|
|
pkpi->pwszProvName,
|
|
pkpi->dwProvType,
|
|
CRYPT_DELETEKEYSET | pkpi->dwFlags);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
SaveRecoveredKey(
|
|
IN CERT_CONTEXT const *pccUser,
|
|
IN BYTE const *pbKey,
|
|
IN DWORD cbKey,
|
|
OPTIONAL IN WCHAR const *pwszfnPFX,
|
|
OPTIONAL IN WCHAR const *pwszPassword)
|
|
{
|
|
HRESULT hr;
|
|
HCERTSTORE hStoreMemory = NULL;
|
|
BOOL fMatchingKey;
|
|
WCHAR wszPassword[MAX_PATH];
|
|
CRYPT_KEY_PROV_INFO kpi;
|
|
CRYPT_DATA_BLOB pfx;
|
|
|
|
pfx.pbData = NULL;
|
|
ZeroMemory(&kpi, sizeof(kpi));
|
|
|
|
hr = myValidateKeyBlob(
|
|
pbKey,
|
|
cbKey,
|
|
&pccUser->pCertInfo->SubjectPublicKeyInfo,
|
|
CERT_V1 == pccUser->pCertInfo->dwVersion,
|
|
&kpi);
|
|
_JumpIfError(hr, error, "myValidateKeyBlob");
|
|
|
|
if (!CertSetCertificateContextProperty(
|
|
pccUser,
|
|
CERT_KEY_PROV_INFO_PROP_ID,
|
|
0,
|
|
&kpi))
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertSetCertificateContextProperty");
|
|
}
|
|
|
|
hStoreMemory = CertOpenStore(
|
|
CERT_STORE_PROV_MEMORY,
|
|
X509_ASN_ENCODING,
|
|
NULL,
|
|
0,
|
|
NULL);
|
|
if (NULL == hStoreMemory)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertOpenStore");
|
|
}
|
|
|
|
// Begin Chain Building
|
|
|
|
hr = myAddChainToMemoryStore(hStoreMemory, pccUser);
|
|
_JumpIfError(hr, error, "myAddChainToMemoryStore");
|
|
|
|
// End Chain Building
|
|
|
|
if (NULL != pwszfnPFX)
|
|
{
|
|
if (NULL == pwszPassword || 0 == wcscmp(L"*", pwszPassword))
|
|
{
|
|
hr = cuGetPassword(TRUE, wszPassword, ARRAYSIZE(wszPassword));
|
|
_JumpIfError(hr, error, "cuGetPassword");
|
|
|
|
pwszPassword = wszPassword;
|
|
}
|
|
}
|
|
hr = myPFXExportCertStore(
|
|
hStoreMemory,
|
|
&pfx,
|
|
pwszPassword,
|
|
EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY);
|
|
_JumpIfError(hr, error, "myPFXExportCertStore");
|
|
|
|
if (NULL != pwszfnPFX)
|
|
{
|
|
hr = EncodeToFileW(
|
|
pwszfnPFX,
|
|
pfx.pbData,
|
|
pfx.cbData,
|
|
CRYPT_STRING_BINARY | (g_fForce? DECF_FORCEOVERWRITE : 0));
|
|
_JumpIfError(hr, error, "EncodeToFileW");
|
|
}
|
|
|
|
error:
|
|
if (NULL != hStoreMemory)
|
|
{
|
|
CertCloseStore(hStoreMemory, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
if (NULL != kpi.pwszContainerName)
|
|
{
|
|
DeleteKey(&kpi);
|
|
LocalFree(kpi.pwszContainerName);
|
|
}
|
|
if (NULL != pfx.pbData)
|
|
{
|
|
LocalFree(pfx.pbData);
|
|
}
|
|
return(hr);
|
|
}
|
|
|
|
|
|
HRESULT
|
|
verbRecoverKey(
|
|
IN WCHAR const *pwszOption,
|
|
IN WCHAR const *pwszfnRecoveryBlob,
|
|
OPTIONAL IN WCHAR const *pwszfnPFX,
|
|
OPTIONAL IN WCHAR const *pwszRecipientIndex,
|
|
IN WCHAR const *pwszArg4)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pbIn = NULL;
|
|
DWORD cbIn;
|
|
BYTE *pbEncryptedPKCS7 = NULL;
|
|
DWORD cbEncryptedPKCS7;
|
|
DWORD cSigner;
|
|
DWORD cRecipient;
|
|
DWORD dwMsgType;
|
|
char *pszInnerContentObjId = NULL;
|
|
HCERTSTORE hStore = NULL;
|
|
HCRYPTMSG hMsg = NULL;
|
|
CERT_CONTEXT const *pccUser = NULL;
|
|
BYTE abHashUserCert[CBMAX_CRYPT_HASH_LEN];
|
|
CRYPT_HASH_BLOB BlobHash;
|
|
BYTE *pbKey = NULL;
|
|
DWORD cbKey;
|
|
DWORD RecipientIndex = MAXDWORD;
|
|
|
|
if (NULL != pwszRecipientIndex)
|
|
{
|
|
hr = cuGetLong(pwszRecipientIndex, (LONG *) &RecipientIndex);
|
|
_JumpIfError(hr, error, "RecipientIndex must be a number");
|
|
}
|
|
|
|
hr = DecodeFileW(pwszfnRecoveryBlob, &pbIn, &cbIn, CRYPT_STRING_ANY);
|
|
if (S_OK != hr)
|
|
{
|
|
cuPrintError(IDS_ERR_FORMAT_DECODEFILE, hr);
|
|
goto error;
|
|
}
|
|
|
|
// Decode outer PKCS 7 signed message, which contains all of the certs.
|
|
|
|
hr = myDecodePKCS7(
|
|
pbIn,
|
|
cbIn,
|
|
&pbEncryptedPKCS7,
|
|
&cbEncryptedPKCS7,
|
|
&dwMsgType,
|
|
&pszInnerContentObjId,
|
|
&cSigner,
|
|
&cRecipient,
|
|
&hStore,
|
|
&hMsg);
|
|
_JumpIfError(hr, error, "myDecodePKCS7(outer)");
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
if (CMSG_SIGNED != dwMsgType)
|
|
{
|
|
_JumpError(hr, error, "dwMsgType(outer)");
|
|
}
|
|
if (0 == cSigner)
|
|
{
|
|
_JumpError(hr, error, "cSigner(outer)");
|
|
}
|
|
if (0 != cRecipient)
|
|
{
|
|
_JumpError(hr, error, "cRecipient(outer)");
|
|
}
|
|
if (NULL == pszInnerContentObjId ||
|
|
0 != strcmp(szOID_RSA_data, pszInnerContentObjId))
|
|
{
|
|
_JumpError(hr, error, "pszInnerContentObjId(outer)");
|
|
}
|
|
CSASSERT(NULL != hMsg);
|
|
ZeroMemory(abHashUserCert, sizeof(abHashUserCert));
|
|
BlobHash.cbData = sizeof(abHashUserCert);
|
|
BlobHash.pbData = abHashUserCert;
|
|
hr = cuDumpSigners(
|
|
hMsg,
|
|
pszInnerContentObjId,
|
|
hStore,
|
|
cSigner,
|
|
NULL == pbEncryptedPKCS7, // fContentEmpty
|
|
TRUE, // fVerifyOnly
|
|
BlobHash.pbData,
|
|
&BlobHash.cbData);
|
|
_JumpIfError(hr, error, "cuDumpSigners(outer)");
|
|
|
|
pccUser = CertFindCertificateInStore(
|
|
hStore,
|
|
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
|
|
0, // dwFindFlags
|
|
CERT_FIND_HASH,
|
|
&BlobHash,
|
|
NULL);
|
|
if (NULL == pccUser)
|
|
{
|
|
hr = myHLastError();
|
|
_JumpError(hr, error, "CertFindCertificateInStore");
|
|
}
|
|
LocalFree(pszInnerContentObjId);
|
|
pszInnerContentObjId = NULL;
|
|
|
|
CryptMsgClose(hMsg);
|
|
hMsg = NULL;
|
|
|
|
// Decode inner PKCS 7 encrypted message, which contains the private key.
|
|
|
|
hr = myDecodePKCS7(
|
|
pbEncryptedPKCS7,
|
|
cbEncryptedPKCS7,
|
|
NULL, // ppbContents
|
|
NULL, // pcbContents
|
|
&dwMsgType,
|
|
&pszInnerContentObjId,
|
|
&cSigner,
|
|
&cRecipient,
|
|
NULL, // phStore
|
|
&hMsg);
|
|
_JumpIfError(hr, error, "myDecodePKCS7(inner)");
|
|
|
|
hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
|
|
if (CMSG_ENVELOPED != dwMsgType)
|
|
{
|
|
_JumpError(hr, error, "dwMsgType(inner)");
|
|
}
|
|
if (0 != cSigner)
|
|
{
|
|
_JumpError(hr, error, "cSigner(inner)");
|
|
}
|
|
if (0 == cRecipient)
|
|
{
|
|
_JumpError(hr, error, "cRecipient(inner)");
|
|
}
|
|
if (NULL == pszInnerContentObjId ||
|
|
0 != strcmp(szOID_RSA_data, pszInnerContentObjId))
|
|
{
|
|
_JumpError(hr, error, "pszInnerContentObjId(inner)");
|
|
}
|
|
CSASSERT(NULL != hMsg);
|
|
if (MAXDWORD != RecipientIndex && cRecipient <= RecipientIndex)
|
|
{
|
|
hr = E_INVALIDARG;
|
|
_JumpError(hr, error, "RecipientIndex too large");
|
|
}
|
|
|
|
hr = cuDumpEncryptedAsnBinary(
|
|
hMsg,
|
|
cRecipient,
|
|
RecipientIndex,
|
|
hStore,
|
|
NULL,
|
|
pbEncryptedPKCS7,
|
|
cbEncryptedPKCS7,
|
|
TRUE,
|
|
&pbKey,
|
|
&cbKey);
|
|
{
|
|
HRESULT hr2;
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_USER_CERT)); // "User Certificate:"
|
|
wprintf(wszNewLine);
|
|
|
|
hr2 = cuDumpIssuerSerialAndSubject(
|
|
&pccUser->pCertInfo->Issuer,
|
|
&pccUser->pCertInfo->SerialNumber,
|
|
&pccUser->pCertInfo->Subject,
|
|
NULL); // hStore
|
|
_PrintIfError(hr2, "cuDumpIssuerSerialAndSubject(user)");
|
|
}
|
|
|
|
if (CRYPT_E_NO_DECRYPT_CERT != hr)
|
|
{
|
|
_JumpIfError(hr, error, "cuDumpEncryptedAsnBinary");
|
|
|
|
if (g_fVerbose)
|
|
{
|
|
wprintf(wszNewLine);
|
|
hr = cuDumpPrivateKeyBlob(pbKey, cbKey, FALSE);
|
|
_JumpIfError(hr, error, "cuDumpPrivateKeyBlob");
|
|
}
|
|
|
|
// Verify the key matches the cert, then save in a PFX
|
|
|
|
hr = SaveRecoveredKey(
|
|
pccUser,
|
|
pbKey,
|
|
cbKey,
|
|
pwszfnPFX,
|
|
g_pwszPassword);
|
|
_JumpIfError(hr, error, "SaveRecoveredKey");
|
|
}
|
|
else
|
|
{
|
|
// Can't decrypt the private key, list Recipient cert info.
|
|
|
|
wprintf(myLoadResourceString(IDS_CANT_DECRYPT)); // "Cannot decrypt message content."
|
|
wprintf(wszNewLine);
|
|
}
|
|
if (CRYPT_E_NO_DECRYPT_CERT == hr || NULL == pwszfnPFX)
|
|
{
|
|
HRESULT hrDecrypt = hr;
|
|
|
|
wprintf(wszNewLine);
|
|
wprintf(myLoadResourceString(IDS_NEED_RECOVERY_CERT)); // "Key recovery requires one of the following certificates and its private key:"
|
|
wprintf(wszNewLine);
|
|
|
|
hr = cuDumpRecipients(hMsg, hStore, cRecipient, TRUE);
|
|
_JumpIfError(hr, error, "cuDumpRecipients");
|
|
|
|
hr = hrDecrypt;
|
|
_JumpIfError(hr, error, "Cannot decrypt");
|
|
}
|
|
hr = S_OK;
|
|
|
|
error:
|
|
if (NULL != pccUser)
|
|
{
|
|
CertFreeCertificateContext(pccUser);
|
|
}
|
|
if (NULL != pbKey)
|
|
{
|
|
LocalFree(pbKey);
|
|
}
|
|
if (NULL != pbIn)
|
|
{
|
|
LocalFree(pbIn);
|
|
}
|
|
if (NULL != pbEncryptedPKCS7)
|
|
{
|
|
LocalFree(pbEncryptedPKCS7);
|
|
}
|
|
if (NULL != pszInnerContentObjId)
|
|
{
|
|
LocalFree(pszInnerContentObjId);
|
|
}
|
|
if (NULL != hStore)
|
|
{
|
|
CertCloseStore(hStore, CERT_CLOSE_STORE_CHECK_FLAG);
|
|
}
|
|
if (NULL != hMsg)
|
|
{
|
|
CryptMsgClose(hMsg);
|
|
}
|
|
return(hr);
|
|
}
|