1039 lines
30 KiB
C++
1039 lines
30 KiB
C++
//
|
|
// sip.cpp
|
|
//
|
|
// Subject Interface Package interface to trust functionality
|
|
//
|
|
|
|
#include "stdpch.h"
|
|
#include "common.h"
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// When adding a new subject type, add a local for it below,
|
|
// bump SUPPORTED_SUBJECTS, and add a line of code to initialize
|
|
// the next element in the SubjectForms array in WinTrustSipInitialize
|
|
// below. Also update the mapping routines found below
|
|
//
|
|
|
|
#define SUPPORTED_SUBJECTS 6
|
|
|
|
const GUID guidSubjectPeImage = WIN_TRUST_SUBJTYPE_PE_IMAGE;
|
|
const GUID guidSubjectJavaClass = WIN_TRUST_SUBJTYPE_JAVA_CLASS;
|
|
const GUID guidSubjectCabFile = WIN_TRUST_SUBJTYPE_CABINET;
|
|
|
|
const GUID guidSubjectPeImageEx = WIN_TRUST_SUBJTYPE_PE_IMAGEEX;
|
|
const GUID guidSubjectJavaClassEx = WIN_TRUST_SUBJTYPE_JAVA_CLASSEX;
|
|
const GUID guidSubjectCabFileEx = WIN_TRUST_SUBJTYPE_CABINETEX;
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Structure describing an individual SIP.
|
|
//
|
|
// This structure is passed back to WinTrust from a Subject Interface Package
|
|
// initialization call.
|
|
//
|
|
//typedef struct _WINTRUST_SIP_INFO {
|
|
// DWORD dwRevision;
|
|
// LPWINTRUST_SIP_DISPATCH_TABLE lpServices;
|
|
// DWORD dwSubjectTypeCount;
|
|
// GUID * lpSubjectTypeArray;
|
|
//} WINTRUST_SIP_INFO, *LPWINTRUST_SIP_INFO;
|
|
//
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Supporting routines
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG SubjTypeFromSubjectGuid(const GUID* pguid)
|
|
//
|
|
// Map a subject type that we know about into its corresponding
|
|
// subject form small integer that we can switch on
|
|
//
|
|
{
|
|
if (*pguid == guidSubjectPeImage
|
|
|| *pguid == guidSubjectJavaClass
|
|
|| *pguid == guidSubjectCabFile)
|
|
return SUBJTYPE_FILE;
|
|
|
|
if (*pguid == guidSubjectPeImageEx
|
|
|| *pguid == guidSubjectJavaClassEx
|
|
|| *pguid == guidSubjectCabFileEx)
|
|
return SUBJTYPE_FILEANDDISPLAY;
|
|
|
|
return SUBJTYPE_NONE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
#define NARROW(wsz,sz) \
|
|
int __cch = lstrlenW(wsz) + 1; \
|
|
int __cb = __cch * sizeof(WCHAR); \
|
|
LPSTR sz = (LPSTR)_alloca(__cb); \
|
|
if (sz) WideCharToMultiByte(CP_ACP,0,wsz,-1,sz,__cb,NULL,NULL)
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
//
|
|
HANDLE OpenFile(LPCWSTR wszFile)
|
|
//
|
|
// Open a file in the appropriate permissions / mode for doing
|
|
// our SIP work thereon
|
|
//
|
|
{
|
|
NARROW(wszFile, sz);
|
|
if (sz)
|
|
{
|
|
HANDLE hFile = CreateFile( sz,
|
|
GENERIC_READ, // bugbug may use something more restricted.
|
|
FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
return hFile;
|
|
}
|
|
else
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
LPWSTR OrBarHack(LPWSTR wszFile)
|
|
//
|
|
// Answers the display name; modifies the argument to zero
|
|
// terminate the file name
|
|
//
|
|
{
|
|
LPWSTR wszDisplay = wszFile;
|
|
|
|
WCHAR* pwch = wszFile;
|
|
while ( *pwch != 0 && *pwch != '|' )
|
|
++pwch;
|
|
|
|
if (*pwch!= 0)
|
|
{
|
|
// file-name is followed by display-name
|
|
*pwch = 0;
|
|
wszDisplay = pwch+1;
|
|
}
|
|
|
|
return wszDisplay;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
HRESULT FileHandleFromSubject(
|
|
//
|
|
// Return a file handle for accessing the given subject
|
|
//
|
|
IN LPWIN_TRUST_SIP_SUBJECT lpSubject, // pointer to subject info
|
|
OUT HANDLE* phFile, // returned file handle
|
|
OUT BOOL* pfClose // whether caller should close it or not
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
*phFile = INVALID_HANDLE_VALUE;
|
|
*pfClose = FALSE;
|
|
|
|
switch (SubjTypeFromSubjectGuid(lpSubject->SubjectType))
|
|
{
|
|
case SUBJTYPE_FILE:
|
|
{
|
|
WIN_TRUST_SUBJECT_FILE* pformFile = (WIN_TRUST_SUBJECT_FILE*)lpSubject->Subject;
|
|
if (pformFile->hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
*phFile = pformFile->hFile;
|
|
*pfClose = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Accomodate the '|' file name / display name hack
|
|
//
|
|
int cch = lstrlenW(pformFile->lpPath) + 1;
|
|
int cb = cch * sizeof(WCHAR);
|
|
LPWSTR wszPath = (LPWSTR)_alloca(cb);
|
|
if (wszPath)
|
|
{
|
|
memcpy(wszPath, pformFile->lpPath, cb);
|
|
OrBarHack(wszPath);
|
|
*phFile = OpenFile(pformFile->lpPath);
|
|
*pfClose = TRUE;
|
|
if (*phFile == INVALID_HANDLE_VALUE)
|
|
hr = HError();
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SUBJTYPE_FILEANDDISPLAY:
|
|
{
|
|
WIN_TRUST_SUBJECT_FILE_AND_DISPLAY* pformFile = (WIN_TRUST_SUBJECT_FILE_AND_DISPLAY*)lpSubject->Subject;
|
|
if (pformFile->hFile != INVALID_HANDLE_VALUE)
|
|
{
|
|
*phFile = pformFile->hFile;
|
|
*pfClose = FALSE;
|
|
}
|
|
else
|
|
{
|
|
*phFile = OpenFile(pformFile->lpPath);
|
|
*pfClose = TRUE;
|
|
if (*phFile == INVALID_HANDLE_VALUE)
|
|
hr = HError();
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hr = TRUST_E_SUBJECT_FORM_UNKNOWN;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT
|
|
GetCabSignerForSubject(
|
|
//
|
|
// Return a ISignable that does cabs for the given subjet
|
|
// REVIEW: In the future, we'd likely want to enhance this
|
|
// to allow for other than CAB files to be fetched
|
|
//
|
|
IN LPWIN_TRUST_SIP_SUBJECT lpSubject, // pointer to subject info
|
|
OUT ISignableDocument** ppSignable
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ISignableDocument* pSignable = NULL;
|
|
if ((pdigsig->CreateCABSigner)(NULL, IID_ISignableDocument, (LPVOID*)&pSignable))
|
|
{
|
|
IPersistFile* pPerFile;
|
|
hr = pSignable->QueryInterface(IID_IPersistFile, (LPVOID*)&pPerFile);
|
|
if (hr == S_OK)
|
|
{
|
|
switch (SubjTypeFromSubjectGuid(lpSubject->SubjectType))
|
|
{
|
|
case SUBJTYPE_FILE:
|
|
{
|
|
WIN_TRUST_SUBJECT_FILE* pformFile = (WIN_TRUST_SUBJECT_FILE*)lpSubject->Subject;
|
|
//
|
|
// Accomodate the '|' file name / display name hack
|
|
//
|
|
int cch = lstrlenW(pformFile->lpPath) + 1;
|
|
int cb = cch * sizeof(WCHAR);
|
|
LPWSTR wszPath = (LPWSTR)_alloca(cb);
|
|
if (wszPath)
|
|
{
|
|
memcpy(wszPath, pformFile->lpPath, cb);
|
|
OrBarHack(wszPath);
|
|
//
|
|
// Do the load
|
|
//
|
|
hr = pPerFile->Load(wszPath, 0);
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
break;
|
|
|
|
case SUBJTYPE_FILEANDDISPLAY:
|
|
{
|
|
WIN_TRUST_SUBJECT_FILE_AND_DISPLAY* pformFile = (WIN_TRUST_SUBJECT_FILE_AND_DISPLAY*)lpSubject->Subject;
|
|
//
|
|
// Do the load
|
|
//
|
|
hr = pPerFile->Load(pformFile->lpPath, 0);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hr = TRUST_E_SUBJECT_FORM_UNKNOWN;
|
|
}
|
|
|
|
pPerFile->Release();
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
pSignable->Release();
|
|
pSignable = NULL;
|
|
}
|
|
}
|
|
else
|
|
hr = HError();
|
|
|
|
*ppSignable = pSignable;
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Validate the content info of a subject. ONLY validate the content
|
|
// info itself; do not then go on to validate the signature on the
|
|
// SignedData.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
SubjectCheckContentInfo(
|
|
IN LPWIN_TRUST_SIP_SUBJECT lpSubject, // pointer to subject info
|
|
IN LPWIN_CERTIFICATE lpSignedData // PKCS #7 Signed Data
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
const GUID guidSubjectType = *lpSubject->SubjectType;
|
|
|
|
IPkcs7SignedData* pkcs7 = NULL;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
BOOL fClose = FALSE;
|
|
|
|
//
|
|
// Initialize a PCKS#7 from the passed certificate
|
|
//
|
|
if ((pdigsig->CreatePkcs7SignedData)(NULL,IID_IPkcs7SignedData,(LPVOID*)&pkcs7))
|
|
{
|
|
IPersistMemBlob* pPerBlob;
|
|
hr = pkcs7->QueryInterface(IID_IPersistMemBlob, (LPVOID*)&pPerBlob);
|
|
if (hr==S_OK)
|
|
{
|
|
BLOB b;
|
|
b.cbSize = lpSignedData->dwLength - OFFSETOF(WIN_CERTIFICATE,bCertificate);
|
|
b.pBlobData = (BYTE*)&lpSignedData->bCertificate;
|
|
hr = pPerBlob->Load(&b);
|
|
pPerBlob->Release();
|
|
}
|
|
}
|
|
else
|
|
hr = HError();
|
|
|
|
//
|
|
// Check the content info
|
|
//
|
|
if (hr==S_OK)
|
|
{
|
|
if (guidSubjectType == guidSubjectPeImage || guidSubjectType == guidSubjectPeImageEx)
|
|
{
|
|
//
|
|
// PE Images
|
|
//
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// Find out what part of the image file is actually signed and verify
|
|
// that in fact that matches
|
|
//
|
|
hr = pkcs7->VerifyImageFile(0, hFile, NULL, NULL, 0);
|
|
}
|
|
}
|
|
|
|
else if (guidSubjectType == guidSubjectJavaClass || guidSubjectType == guidSubjectJavaClassEx)
|
|
{
|
|
//
|
|
// Java files
|
|
//
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
hr = pkcs7->VerifyJavaClassFile(hFile, NULL, NULL, 0);
|
|
}
|
|
|
|
|
|
else if (guidSubjectType == guidSubjectCabFile || guidSubjectType == guidSubjectCabFileEx)
|
|
{
|
|
//
|
|
// CAB files
|
|
//
|
|
ISignableDocument* pSignable;
|
|
hr = GetCabSignerForSubject(lpSubject, &pSignable);
|
|
if (hr==S_OK)
|
|
{
|
|
hr = pkcs7->VerifySignableDocument(pSignable, NULL, 0);
|
|
pSignable->Release();
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
//
|
|
// Something we don't know
|
|
//
|
|
hr = TRUST_E_SUBJECT_FORM_UNKNOWN;
|
|
}
|
|
}
|
|
else
|
|
hr = HError();
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
if (pkcs7)
|
|
pkcs7->Release();
|
|
if (fClose)
|
|
CloseHandle(hFile);
|
|
|
|
SetLastError(hr);
|
|
return hr == S_OK;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT SevenFromJavaFile(HANDLE hFile, IPkcs7SignedData** ppseven)
|
|
//
|
|
// Return the #7 inside this file, if any
|
|
//
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IPkcs7SignedData* pseven = NULL;
|
|
if ((pdigsig->CreatePkcs7SignedData)(NULL, IID_IPkcs7SignedData, (LPVOID*)&pseven))
|
|
{
|
|
hr = pseven->LoadFromJavaClassFile(hFile, NULL);
|
|
}
|
|
else
|
|
hr = HError();
|
|
|
|
if (hr==S_OK)
|
|
*ppseven = pseven;
|
|
else
|
|
{
|
|
*ppseven = NULL;
|
|
if (pseven) pseven->Release();
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Enumerate the certificates in the subject
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
SubjectEnumCertificates(
|
|
IN LPWIN_TRUST_SIP_SUBJECT lpSubject, // pointer to subject info
|
|
IN DWORD dwTypeFilter, // 0 or WIN_CERT_TYPE_xxx
|
|
OUT LPDWORD lpCertificateCount,
|
|
IN OUT LPDWORD lpIndices, // Rcvs WIN_CERT_TYPE_
|
|
IN DWORD cIndicies
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
BOOL fClose = FALSE;
|
|
|
|
const GUID guidSubjectType = *lpSubject->SubjectType;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// PE Images
|
|
//
|
|
if (guidSubjectType == guidSubjectPeImage || guidSubjectType == guidSubjectPeImageEx)
|
|
{
|
|
ULONG cCertFound = 0;
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
{
|
|
int index = 0;
|
|
int iCert = 0;
|
|
do {
|
|
WIN_CERTIFICATE hdr;
|
|
if ((pimagehlp->ImageGetCertificateHeader)(hFile, iCert, &hdr))
|
|
{
|
|
if (dwTypeFilter == 0 || hdr.wCertificateType == dwTypeFilter)
|
|
{
|
|
cCertFound++;
|
|
if (cIndicies > 0)
|
|
{
|
|
lpIndices[index] = iCert;
|
|
index++;
|
|
cIndicies--;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
iCert++;
|
|
} while(TRUE);
|
|
}
|
|
*lpCertificateCount = cCertFound;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Java class files
|
|
//
|
|
// Java class files either have zero or one certificates, and the
|
|
// one certificate, if present, is always a SignedData.
|
|
//
|
|
else if (guidSubjectType == guidSubjectJavaClass)
|
|
{
|
|
ULONG cCertFound = 0;
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// SLOW.... wish we had a way to avoid the repeated loading...
|
|
//
|
|
IPkcs7SignedData* pseven;
|
|
hr = SevenFromJavaFile(hFile, &pseven);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// There is a signature present
|
|
//
|
|
if (dwTypeFilter == 0 || dwTypeFilter == WIN_CERT_TYPE_PKCS_SIGNED_DATA)
|
|
{
|
|
cCertFound++;
|
|
if (cIndicies > 0)
|
|
{
|
|
lpIndices[0] = 0;
|
|
}
|
|
}
|
|
pseven->Release();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Nothing there
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
*lpCertificateCount = cCertFound;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// CAB files
|
|
//
|
|
// CAB files have zero or one certificates, just like Java files
|
|
//
|
|
else if (guidSubjectType == guidSubjectCabFile)
|
|
{
|
|
int cCertFound = 0;
|
|
ISignableDocument* pSignable = NULL;
|
|
hr = GetCabSignerForSubject(lpSubject, &pSignable);
|
|
if (hr==S_OK)
|
|
{
|
|
BLOB b;
|
|
hr = pSignable->LoadSignature(&b);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// There is a signature present (it's ALWAYS a #7 for signables)
|
|
//
|
|
if (dwTypeFilter == 0 || dwTypeFilter == WIN_CERT_TYPE_PKCS_SIGNED_DATA)
|
|
{
|
|
cCertFound++;
|
|
if (cIndicies > 0)
|
|
{
|
|
lpIndices[0] = 0;
|
|
}
|
|
}
|
|
CoTaskMemFree(b.pBlobData);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Nothing there
|
|
//
|
|
hr = S_OK;
|
|
}
|
|
pSignable->Release();
|
|
}
|
|
*lpCertificateCount = cCertFound;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Unknown
|
|
//
|
|
else
|
|
{
|
|
hr = TRUST_E_SUBJECT_FORM_UNKNOWN;
|
|
}
|
|
|
|
if (fClose)
|
|
CloseHandle(hFile);
|
|
|
|
if (hr!=S_OK)
|
|
SetLastError(hr);
|
|
|
|
return hr == S_OK ? TRUE : FALSE;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
HRESULT WinCertHeaderFromBlob(BLOB& b, WORD wType, LPWIN_CERTIFICATE pCert)
|
|
//
|
|
// Fill in the header information of a to-be-constructed WIN_CERTIFICATE
|
|
//
|
|
{
|
|
ASSERT(pCert);
|
|
if (pCert)
|
|
{
|
|
ULONG cbNeeded = OFFSETOF(WIN_CERTIFICATE,bCertificate) + b.cbSize;
|
|
pCert->dwLength = cbNeeded;
|
|
pCert->wRevision = WIN_CERT_REVISION_1_0;
|
|
pCert->wCertificateType = wType;
|
|
return S_OK;
|
|
}
|
|
else
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
|
|
|
|
HRESULT WinCertFromBlob(BLOB& b, WORD wType, LPWIN_CERTIFICATE pCert, LPDWORD pcbNeeded)
|
|
//
|
|
// Return the BLOB as a WIN_CERTIFICATE, if there is enough room
|
|
//
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG cbNeeded = OFFSETOF(WIN_CERTIFICATE,bCertificate) + b.cbSize;
|
|
if (pCert && cbNeeded <= *pcbNeeded)
|
|
{
|
|
pCert->dwLength = cbNeeded;
|
|
pCert->wRevision = WIN_CERT_REVISION_1_0;
|
|
pCert->wCertificateType = wType;
|
|
memcpy(&pCert->bCertificate[0], b.pBlobData, b.cbSize);
|
|
}
|
|
else
|
|
hr = ERROR_INSUFFICIENT_BUFFER;
|
|
*pcbNeeded = cbNeeded;
|
|
return hr;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get the nth certificate from the subject
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
SubjectGetCertificate(
|
|
IN LPWIN_TRUST_SIP_SUBJECT lpSubject,
|
|
IN DWORD iCert,
|
|
OUT LPWIN_CERTIFICATE pCert,
|
|
IN OUT LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
BOOL fClose = FALSE;
|
|
|
|
const GUID guidSubjectType = *lpSubject->SubjectType;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// PE Images
|
|
//
|
|
if (guidSubjectType == guidSubjectPeImage || guidSubjectType == guidSubjectPeImageEx)
|
|
{
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
{
|
|
if ((pimagehlp->ImageGetCertificateData)(hFile, iCert, pCert, pcbNeeded))
|
|
{
|
|
}
|
|
else
|
|
hr = HError();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Java class files
|
|
//
|
|
// Java class files either have zero or one certificates, and the
|
|
// one certificate, if present, is always a SignedData.
|
|
//
|
|
else if (guidSubjectType == guidSubjectJavaClass || guidSubjectType == guidSubjectJavaClassEx)
|
|
{
|
|
if (iCert != 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// SLOW.... wish we had a way to avoid the repeated loading...
|
|
//
|
|
IPkcs7SignedData* pseven;
|
|
hr = SevenFromJavaFile(hFile, &pseven);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// A cert is there. Croft up a WINCERT
|
|
//
|
|
IPersistMemBlob* pPerMem;
|
|
hr = pseven->QueryInterface(IID_IPersistMemBlob, (LPVOID*)&pPerMem);
|
|
if (hr==S_OK)
|
|
{
|
|
BLOB b;
|
|
hr = pPerMem->Save(&b, FALSE);
|
|
if (hr==S_OK)
|
|
{
|
|
hr = WinCertFromBlob(b, WIN_CERT_TYPE_PKCS_SIGNED_DATA, pCert, pcbNeeded);
|
|
CoTaskMemFree(b.pBlobData);
|
|
}
|
|
pPerMem->Release();
|
|
}
|
|
pseven->Release();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Nothing there
|
|
//
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// CAB files
|
|
//
|
|
// CAB files have zero or one certificates, just like Java files
|
|
//
|
|
else if (guidSubjectType == guidSubjectCabFile || guidSubjectType == guidSubjectCabFileEx)
|
|
{
|
|
if (iCert != 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
ISignableDocument* pSignable = NULL;
|
|
hr = GetCabSignerForSubject(lpSubject, &pSignable);
|
|
if (hr==S_OK)
|
|
{
|
|
BLOB b;
|
|
hr = pSignable->LoadSignature(&b);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// There is a signature present (it's ALWAYS a #7 for signables)
|
|
//
|
|
hr = WinCertFromBlob(b, WIN_CERT_TYPE_PKCS_SIGNED_DATA, pCert, pcbNeeded);
|
|
CoTaskMemFree(b.pBlobData);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Nothing there
|
|
//
|
|
hr = E_INVALIDARG;
|
|
}
|
|
pSignable->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Unknown
|
|
//
|
|
else
|
|
{
|
|
hr = TRUST_E_SUBJECT_FORM_UNKNOWN;
|
|
}
|
|
|
|
if (fClose)
|
|
CloseHandle(hFile);
|
|
|
|
if (hr!=S_OK)
|
|
SetLastError(hr);
|
|
|
|
return hr == S_OK ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get the header of the nth certificate from the subject
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
SubjectGetCertHeader(
|
|
IN LPWIN_TRUST_SIP_SUBJECT lpSubject,
|
|
IN DWORD iCert,
|
|
OUT LPWIN_CERTIFICATE pCert
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
BOOL fClose = FALSE;
|
|
|
|
const GUID guidSubjectType = *lpSubject->SubjectType;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// PE Images
|
|
//
|
|
if (guidSubjectType == guidSubjectPeImage || guidSubjectType == guidSubjectPeImageEx)
|
|
{
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
{
|
|
if ((pimagehlp->ImageGetCertificateHeader)(hFile, iCert, pCert))
|
|
{
|
|
}
|
|
else
|
|
hr = HError();
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Java class files
|
|
//
|
|
// Java class files either have zero or one certificates, and the
|
|
// one certificate, if present, is always a SignedData.
|
|
//
|
|
else if (guidSubjectType == guidSubjectJavaClass || guidSubjectType == guidSubjectJavaClassEx)
|
|
{
|
|
if (iCert != 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
hr = FileHandleFromSubject(lpSubject, &hFile, &fClose);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// SLOW.... wish we had a way to avoid the repeated loading...
|
|
//
|
|
IPkcs7SignedData* pseven;
|
|
hr = SevenFromJavaFile(hFile, &pseven);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// A cert is there. Croft up a WINCERT header
|
|
//
|
|
IPersistMemBlob* pPerMem;
|
|
hr = pseven->QueryInterface(IID_IPersistMemBlob, (LPVOID*)&pPerMem);
|
|
if (hr==S_OK)
|
|
{
|
|
BLOB b;
|
|
hr = pPerMem->Save(&b, FALSE);
|
|
if (hr==S_OK)
|
|
{
|
|
hr = WinCertHeaderFromBlob(b, WIN_CERT_TYPE_PKCS_SIGNED_DATA, pCert);
|
|
CoTaskMemFree(b.pBlobData);
|
|
}
|
|
pPerMem->Release();
|
|
}
|
|
pseven->Release();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Nothing there
|
|
//
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// CAB files
|
|
//
|
|
// CAB files have zero or one certificates, just like Java files
|
|
//
|
|
else if (guidSubjectType == guidSubjectCabFile || guidSubjectType == guidSubjectCabFileEx)
|
|
{
|
|
if (iCert != 0)
|
|
hr = E_INVALIDARG;
|
|
else
|
|
{
|
|
ISignableDocument* pSignable = NULL;
|
|
hr = GetCabSignerForSubject(lpSubject, &pSignable);
|
|
if (hr==S_OK)
|
|
{
|
|
BLOB b;
|
|
hr = pSignable->LoadSignature(&b);
|
|
if (hr==S_OK)
|
|
{
|
|
//
|
|
// There is a signature present (it's ALWAYS a #7 for signables)
|
|
//
|
|
hr = WinCertHeaderFromBlob(b, WIN_CERT_TYPE_PKCS_SIGNED_DATA, pCert);
|
|
CoTaskMemFree(b.pBlobData);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Nothing there
|
|
//
|
|
hr = E_INVALIDARG;
|
|
}
|
|
pSignable->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// Unknown
|
|
//
|
|
else
|
|
{
|
|
hr = TRUST_E_SUBJECT_FORM_UNKNOWN;
|
|
}
|
|
|
|
if (fClose)
|
|
CloseHandle(hFile);
|
|
|
|
if (hr!=S_OK)
|
|
SetLastError(hr);
|
|
|
|
return hr == S_OK ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get the name of the subject from the content info
|
|
//
|
|
// The purpose of this string is to show to the user as some
|
|
// human recognizable representation of the subject. The string
|
|
// is ONLY good for showing to the user.
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
SubjectGetName(
|
|
IN LPWIN_TRUST_SIP_SUBJECT lpSubject,
|
|
IN LPWIN_CERTIFICATE lpSignedData,
|
|
IN OUT LPWSTR wszBuffer,
|
|
IN OUT LPDWORD pcbNeeded
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
const GUID guidSubjectType = *lpSubject->SubjectType;
|
|
|
|
//
|
|
// For now, we only ever look in the subject form itself
|
|
// to get a display string. In the future, if the subject
|
|
// form doesn't have something reasonable, we might
|
|
// choose to look inside the #7 SignedData to see if
|
|
// it has something reasonable.
|
|
//
|
|
switch (SubjTypeFromSubjectGuid(&guidSubjectType))
|
|
{
|
|
case SUBJTYPE_FILE:
|
|
{
|
|
WIN_TRUST_SUBJECT_FILE* pformFile = (WIN_TRUST_SUBJECT_FILE*)lpSubject->Subject;
|
|
ULONG cch = lstrlenW(pformFile->lpPath) + 1;
|
|
ULONG cb = cch * sizeof(WCHAR);
|
|
LPWSTR wszPath = (LPWSTR)_alloca(cb);
|
|
if (wszPath)
|
|
{
|
|
memcpy(wszPath, pformFile->lpPath, cb);
|
|
LPWSTR wszDisplayName = OrBarHack(wszPath);
|
|
cch = lstrlenW(wszDisplayName) + 1;
|
|
cb = cch * sizeof(WCHAR);
|
|
if (wszBuffer && cb <= *pcbNeeded)
|
|
{
|
|
memcpy(wszBuffer, wszDisplayName, cb);
|
|
}
|
|
else
|
|
hr = ERROR_INSUFFICIENT_BUFFER;
|
|
*pcbNeeded = cb;
|
|
}
|
|
else
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
break;
|
|
|
|
case SUBJTYPE_FILEANDDISPLAY:
|
|
{
|
|
WIN_TRUST_SUBJECT_FILE_AND_DISPLAY* pformFile = (WIN_TRUST_SUBJECT_FILE_AND_DISPLAY*)lpSubject->Subject;
|
|
ULONG cch = lstrlenW(pformFile->lpDisplayName) + 1;
|
|
ULONG cb = cch * sizeof(WCHAR);
|
|
if (wszBuffer && cb <= *pcbNeeded)
|
|
{
|
|
memcpy(wszBuffer, pformFile->lpDisplayName, cb);
|
|
}
|
|
else
|
|
hr = ERROR_INSUFFICIENT_BUFFER;
|
|
*pcbNeeded = cb;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
hr = TRUST_E_SUBJECT_FORM_UNKNOWN;
|
|
break;
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
SetLastError(hr);
|
|
|
|
return hr == S_OK ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Initialization code
|
|
//
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
WINTRUST_SIP_DISPATCH_TABLE rgpfnDispatchTable =
|
|
{
|
|
SubjectCheckContentInfo,
|
|
SubjectEnumCertificates,
|
|
SubjectGetCertificate,
|
|
SubjectGetCertHeader,
|
|
SubjectGetName
|
|
};
|
|
|
|
const GUID rgguidSubjectForms[] =
|
|
{
|
|
WIN_TRUST_SUBJTYPE_PE_IMAGE,
|
|
WIN_TRUST_SUBJTYPE_JAVA_CLASS,
|
|
WIN_TRUST_SUBJTYPE_CABINET,
|
|
WIN_TRUST_SUBJTYPE_PE_IMAGEEX,
|
|
WIN_TRUST_SUBJTYPE_JAVA_CLASSEX,
|
|
WIN_TRUST_SUBJTYPE_CABINETEX
|
|
};
|
|
|
|
const WINTRUST_SIP_INFO sipInfo =
|
|
{
|
|
1,
|
|
&rgpfnDispatchTable,
|
|
SUPPORTED_SUBJECTS,
|
|
(GUID*)&rgguidSubjectForms[0]
|
|
};
|
|
|
|
BOOL
|
|
WINAPI
|
|
WinTrustSipInitialize(
|
|
IN DWORD dwWinTrustRevision,
|
|
OUT LPWINTRUST_SIP_INFO *lpSipInfo
|
|
)
|
|
{
|
|
*lpSipInfo = (LPWINTRUST_SIP_INFO)&sipInfo;
|
|
return TRUE;
|
|
}
|