| /* |
| * WinTrust Cryptography functions |
| * |
| * Copyright 2006 James Hawkins |
| * Copyright 2000-2002 Stuart Caie |
| * Copyright 2002 Patrik Stridvall |
| * Copyright 2003 Greg Turner |
| * Copyright 2008 Juan Lang |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wintrust.h" |
| #include "mscat.h" |
| #include "mssip.h" |
| #include "imagehlp.h" |
| #include "winternl.h" |
| |
| #include "wine/debug.h" |
| #include "wine/unicode.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(wintrust); |
| |
| #define CATADMIN_MAGIC 0x43415441 /* 'CATA' */ |
| #define CRYPTCAT_MAGIC 0x43415443 /* 'CATC' */ |
| #define CATINFO_MAGIC 0x43415449 /* 'CATI' */ |
| |
| struct cryptcat |
| { |
| DWORD magic; |
| HCRYPTMSG msg; |
| DWORD encoding; |
| CTL_INFO *inner; |
| DWORD inner_len; |
| GUID subject; |
| DWORD attr_count; |
| CRYPTCATATTRIBUTE *attr; |
| }; |
| |
| struct catadmin |
| { |
| DWORD magic; |
| WCHAR path[MAX_PATH]; |
| HANDLE find; |
| }; |
| |
| struct catinfo |
| { |
| DWORD magic; |
| WCHAR file[MAX_PATH]; |
| }; |
| |
| static HCATINFO create_catinfo(const WCHAR *filename) |
| { |
| struct catinfo *ci; |
| |
| if (!(ci = HeapAlloc(GetProcessHeap(), 0, sizeof(*ci)))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return INVALID_HANDLE_VALUE; |
| } |
| strcpyW(ci->file, filename); |
| ci->magic = CATINFO_MAGIC; |
| return ci; |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminAcquireContext (WINTRUST.@) |
| * |
| * Get a catalog administrator context handle. |
| * |
| * PARAMS |
| * catAdmin [O] Pointer to the context handle. |
| * sys [I] Pointer to a GUID for the needed subsystem. |
| * dwFlags [I] Reserved. |
| * |
| * RETURNS |
| * Success: TRUE. catAdmin contains the context handle. |
| * Failure: FALSE. |
| * |
| */ |
| BOOL WINAPI CryptCATAdminAcquireContext(HCATADMIN *catAdmin, |
| const GUID *sys, DWORD dwFlags) |
| { |
| static const WCHAR catroot[] = |
| {'\\','c','a','t','r','o','o','t',0}; |
| static const WCHAR fmt[] = |
| {'%','s','\\','{','%','0','8','x','-','%','0','4','x','-','%','0', |
| '4','x','-','%','0','2','x','%','0','2','x','-','%','0','2','x', |
| '%','0','2','x','%','0','2','x','%','0','2','x','%','0','2','x', |
| '%','0','2','x','}',0}; |
| static const GUID defsys = |
| {0x127d0a1d,0x4ef2,0x11d1,{0x86,0x08,0x00,0xc0,0x4f,0xc2,0x95,0xee}}; |
| |
| WCHAR catroot_dir[MAX_PATH]; |
| struct catadmin *ca; |
| |
| TRACE("%p %s %x\n", catAdmin, debugstr_guid(sys), dwFlags); |
| |
| if (!catAdmin || dwFlags) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| if (!(ca = HeapAlloc(GetProcessHeap(), 0, sizeof(*ca)))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return FALSE; |
| } |
| |
| GetSystemDirectoryW(catroot_dir, MAX_PATH); |
| strcatW(catroot_dir, catroot); |
| |
| /* create the directory if it doesn't exist */ |
| CreateDirectoryW(catroot_dir, NULL); |
| |
| if (!sys) sys = &defsys; |
| sprintfW(ca->path, fmt, catroot_dir, sys->Data1, sys->Data2, |
| sys->Data3, sys->Data4[0], sys->Data4[1], sys->Data4[2], |
| sys->Data4[3], sys->Data4[4], sys->Data4[5], sys->Data4[6], |
| sys->Data4[7]); |
| |
| /* create the directory if it doesn't exist */ |
| CreateDirectoryW(ca->path, NULL); |
| |
| ca->magic = CATADMIN_MAGIC; |
| ca->find = INVALID_HANDLE_VALUE; |
| |
| *catAdmin = ca; |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminAddCatalog (WINTRUST.@) |
| */ |
| HCATINFO WINAPI CryptCATAdminAddCatalog(HCATADMIN catAdmin, PWSTR catalogFile, |
| PWSTR selectBaseName, DWORD flags) |
| { |
| static const WCHAR slashW[] = {'\\',0}; |
| struct catadmin *ca = catAdmin; |
| struct catinfo *ci; |
| WCHAR *target; |
| DWORD len; |
| |
| TRACE("%p %s %s %d\n", catAdmin, debugstr_w(catalogFile), |
| debugstr_w(selectBaseName), flags); |
| |
| if (!selectBaseName) |
| { |
| FIXME("NULL basename not handled\n"); |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| if (!ca || ca->magic != CATADMIN_MAGIC || !catalogFile || flags) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| |
| len = strlenW(ca->path) + strlenW(selectBaseName) + 2; |
| if (!(target = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return NULL; |
| } |
| strcpyW(target, ca->path); |
| strcatW(target, slashW); |
| strcatW(target, selectBaseName); |
| |
| if (!CopyFileW(catalogFile, target, FALSE)) |
| { |
| HeapFree(GetProcessHeap(), 0, target); |
| return NULL; |
| } |
| SetFileAttributesW(target, FILE_ATTRIBUTE_SYSTEM); |
| |
| if (!(ci = HeapAlloc(GetProcessHeap(), 0, sizeof(*ci)))) |
| { |
| HeapFree(GetProcessHeap(), 0, target); |
| SetLastError(ERROR_OUTOFMEMORY); |
| return NULL; |
| } |
| ci->magic = CATINFO_MAGIC; |
| strcpyW(ci->file, target); |
| |
| HeapFree(GetProcessHeap(), 0, target); |
| return ci; |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminCalcHashFromFileHandle (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptCATAdminCalcHashFromFileHandle(HANDLE hFile, DWORD* pcbHash, |
| BYTE* pbHash, DWORD dwFlags ) |
| { |
| BOOL ret = FALSE; |
| |
| TRACE("%p %p %p %x\n", hFile, pcbHash, pbHash, dwFlags); |
| |
| if (!hFile || !pcbHash || dwFlags) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| if (*pcbHash < 20) |
| { |
| *pcbHash = 20; |
| SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| return TRUE; |
| } |
| |
| *pcbHash = 20; |
| if (pbHash) |
| { |
| HCRYPTPROV prov; |
| HCRYPTHASH hash; |
| DWORD bytes_read; |
| BYTE *buffer; |
| |
| if (!(buffer = HeapAlloc(GetProcessHeap(), 0, 4096))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return FALSE; |
| } |
| ret = CryptAcquireContextW(&prov, NULL, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); |
| if (!ret) |
| { |
| HeapFree(GetProcessHeap(), 0, buffer); |
| return FALSE; |
| } |
| ret = CryptCreateHash(prov, CALG_SHA1, 0, 0, &hash); |
| if (!ret) |
| { |
| HeapFree(GetProcessHeap(), 0, buffer); |
| CryptReleaseContext(prov, 0); |
| return FALSE; |
| } |
| while ((ret = ReadFile(hFile, buffer, 4096, &bytes_read, NULL)) && bytes_read) |
| { |
| CryptHashData(hash, buffer, bytes_read, 0); |
| } |
| if (ret) ret = CryptGetHashParam(hash, HP_HASHVAL, pbHash, pcbHash, 0); |
| |
| HeapFree(GetProcessHeap(), 0, buffer); |
| CryptDestroyHash(hash); |
| CryptReleaseContext(prov, 0); |
| } |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminEnumCatalogFromHash (WINTRUST.@) |
| */ |
| HCATINFO WINAPI CryptCATAdminEnumCatalogFromHash(HCATADMIN hCatAdmin, BYTE* pbHash, |
| DWORD cbHash, DWORD dwFlags, |
| HCATINFO* phPrevCatInfo ) |
| { |
| static const WCHAR slashW[] = {'\\',0}; |
| static const WCHAR globW[] = {'\\','*','.','c','a','t',0}; |
| |
| struct catadmin *ca = hCatAdmin; |
| WIN32_FIND_DATAW data; |
| HCATINFO prev = NULL; |
| HCRYPTPROV prov; |
| DWORD size; |
| BOOL ret; |
| |
| TRACE("%p %p %d %x %p\n", hCatAdmin, pbHash, cbHash, dwFlags, phPrevCatInfo); |
| |
| if (!ca || ca->magic != CATADMIN_MAGIC || !pbHash || cbHash != 20 || dwFlags) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| if (phPrevCatInfo) prev = *phPrevCatInfo; |
| |
| ret = CryptAcquireContextW(&prov, NULL, MS_DEF_PROV_W, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); |
| if (!ret) return NULL; |
| |
| if (!prev) |
| { |
| WCHAR *path; |
| |
| size = strlenW(ca->path) * sizeof(WCHAR) + sizeof(globW); |
| if (!(path = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| CryptReleaseContext(prov, 0); |
| SetLastError(ERROR_OUTOFMEMORY); |
| return NULL; |
| } |
| strcpyW(path, ca->path); |
| strcatW(path, globW); |
| |
| FindClose(ca->find); |
| ca->find = FindFirstFileW(path, &data); |
| |
| HeapFree(GetProcessHeap(), 0, path); |
| if (ca->find == INVALID_HANDLE_VALUE) |
| { |
| CryptReleaseContext(prov, 0); |
| return NULL; |
| } |
| } |
| else if (!FindNextFileW(ca->find, &data)) |
| { |
| CryptCATAdminReleaseCatalogContext(hCatAdmin, prev, 0); |
| CryptReleaseContext(prov, 0); |
| return NULL; |
| } |
| |
| while (1) |
| { |
| WCHAR *filename; |
| CRYPTCATMEMBER *member = NULL; |
| struct catinfo *ci; |
| HANDLE hcat; |
| |
| size = (strlenW(ca->path) + strlenW(data.cFileName) + 2) * sizeof(WCHAR); |
| if (!(filename = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return NULL; |
| } |
| strcpyW(filename, ca->path); |
| strcatW(filename, slashW); |
| strcatW(filename, data.cFileName); |
| |
| hcat = CryptCATOpen(filename, CRYPTCAT_OPEN_EXISTING, prov, 0, 0); |
| if (hcat == INVALID_HANDLE_VALUE) |
| { |
| WARN("couldn't open %s (%u)\n", debugstr_w(filename), GetLastError()); |
| continue; |
| } |
| while ((member = CryptCATEnumerateMember(hcat, member))) |
| { |
| if (member->pIndirectData->Digest.cbData != cbHash) |
| { |
| WARN("amount of hash bytes differs: %u/%u\n", member->pIndirectData->Digest.cbData, cbHash); |
| continue; |
| } |
| if (!memcmp(member->pIndirectData->Digest.pbData, pbHash, cbHash)) |
| { |
| TRACE("file %s matches\n", debugstr_w(data.cFileName)); |
| |
| CryptCATClose(hcat); |
| CryptReleaseContext(prov, 0); |
| if (!phPrevCatInfo) |
| { |
| FindClose(ca->find); |
| ca->find = INVALID_HANDLE_VALUE; |
| } |
| ci = create_catinfo(filename); |
| HeapFree(GetProcessHeap(), 0, filename); |
| return ci; |
| } |
| } |
| CryptCATClose(hcat); |
| HeapFree(GetProcessHeap(), 0, filename); |
| |
| if (!FindNextFileW(ca->find, &data)) |
| { |
| FindClose(ca->find); |
| ca->find = INVALID_HANDLE_VALUE; |
| CryptReleaseContext(prov, 0); |
| return NULL; |
| } |
| } |
| return NULL; |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminReleaseCatalogContext (WINTRUST.@) |
| * |
| * Release a catalog context handle. |
| * |
| * PARAMS |
| * hCatAdmin [I] Context handle. |
| * hCatInfo [I] Catalog handle. |
| * dwFlags [I] Reserved. |
| * |
| * RETURNS |
| * Success: TRUE. |
| * Failure: FALSE. |
| * |
| */ |
| BOOL WINAPI CryptCATAdminReleaseCatalogContext(HCATADMIN hCatAdmin, |
| HCATINFO hCatInfo, |
| DWORD dwFlags) |
| { |
| struct catinfo *ci = hCatInfo; |
| struct catadmin *ca = hCatAdmin; |
| |
| TRACE("%p %p %x\n", hCatAdmin, hCatInfo, dwFlags); |
| |
| if (!ca || ca->magic != CATADMIN_MAGIC || !ci || ci->magic != CATINFO_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| ci->magic = 0; |
| return HeapFree(GetProcessHeap(), 0, ci); |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminReleaseContext (WINTRUST.@) |
| * |
| * Release a catalog administrator context handle. |
| * |
| * PARAMS |
| * catAdmin [I] Context handle. |
| * dwFlags [I] Reserved. |
| * |
| * RETURNS |
| * Success: TRUE. |
| * Failure: FALSE. |
| * |
| */ |
| BOOL WINAPI CryptCATAdminReleaseContext(HCATADMIN hCatAdmin, DWORD dwFlags ) |
| { |
| struct catadmin *ca = hCatAdmin; |
| |
| TRACE("%p %x\n", hCatAdmin, dwFlags); |
| |
| if (!ca || ca->magic != CATADMIN_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| if (ca->find != INVALID_HANDLE_VALUE) FindClose(ca->find); |
| ca->magic = 0; |
| return HeapFree(GetProcessHeap(), 0, ca); |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminRemoveCatalog (WINTRUST.@) |
| * |
| * Remove a catalog file. |
| * |
| * PARAMS |
| * catAdmin [I] Context handle. |
| * pwszCatalogFile [I] Catalog file. |
| * dwFlags [I] Reserved. |
| * |
| * RETURNS |
| * Success: TRUE. |
| * Failure: FALSE. |
| * |
| */ |
| BOOL WINAPI CryptCATAdminRemoveCatalog(HCATADMIN hCatAdmin, LPCWSTR pwszCatalogFile, DWORD dwFlags) |
| { |
| struct catadmin *ca = hCatAdmin; |
| |
| TRACE("%p %s %x\n", hCatAdmin, debugstr_w(pwszCatalogFile), dwFlags); |
| |
| if (!ca || ca->magic != CATADMIN_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| |
| /* Only delete when there is a filename and no path */ |
| if (pwszCatalogFile && pwszCatalogFile[0] != 0 && |
| !strchrW(pwszCatalogFile, '\\') && !strchrW(pwszCatalogFile, '/') && |
| !strchrW(pwszCatalogFile, ':')) |
| { |
| static const WCHAR slashW[] = {'\\',0}; |
| WCHAR *target; |
| DWORD len; |
| |
| len = strlenW(ca->path) + strlenW(pwszCatalogFile) + 2; |
| if (!(target = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return FALSE; |
| } |
| strcpyW(target, ca->path); |
| strcatW(target, slashW); |
| strcatW(target, pwszCatalogFile); |
| |
| DeleteFileW(target); |
| |
| HeapFree(GetProcessHeap(), 0, target); |
| } |
| |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * CryptCATAdminResolveCatalogPath (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptCATAdminResolveCatalogPath(HCATADMIN hcatadmin, WCHAR *catalog_file, |
| CATALOG_INFO *info, DWORD flags) |
| { |
| static const WCHAR slashW[] = {'\\',0}; |
| struct catadmin *ca = hcatadmin; |
| |
| TRACE("%p %s %p %x\n", hcatadmin, debugstr_w(catalog_file), info, flags); |
| |
| if (!ca || ca->magic != CATADMIN_MAGIC || !info || info->cbStruct != sizeof(*info) || flags) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| strcpyW(info->wszCatalogFile, ca->path); |
| strcatW(info->wszCatalogFile, slashW); |
| strcatW(info->wszCatalogFile, catalog_file); |
| |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * CryptCATClose (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptCATClose(HANDLE hCatalog) |
| { |
| struct cryptcat *cc = hCatalog; |
| |
| TRACE("(%p)\n", hCatalog); |
| |
| if (!hCatalog || hCatalog == INVALID_HANDLE_VALUE || cc->magic != CRYPTCAT_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| HeapFree(GetProcessHeap(), 0, cc->attr); |
| HeapFree(GetProcessHeap(), 0, cc->inner); |
| CryptMsgClose(cc->msg); |
| |
| cc->magic = 0; |
| HeapFree(GetProcessHeap(), 0, cc); |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * CryptCATGetAttrInfo (WINTRUST.@) |
| */ |
| CRYPTCATATTRIBUTE * WINAPI CryptCATGetAttrInfo(HANDLE hCatalog, CRYPTCATMEMBER *member, LPWSTR tag) |
| { |
| struct cryptcat *cc = hCatalog; |
| |
| FIXME("%p, %p, %s\n", hCatalog, member, debugstr_w(tag)); |
| |
| if (!hCatalog || hCatalog == INVALID_HANDLE_VALUE || cc->magic != CRYPTCAT_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| SetLastError(CRYPT_E_NOT_FOUND); |
| return NULL; |
| } |
| |
| /*********************************************************************** |
| * CryptCATGetCatAttrInfo (WINTRUST.@) |
| */ |
| CRYPTCATATTRIBUTE * WINAPI CryptCATGetCatAttrInfo(HANDLE hCatalog, LPWSTR tag) |
| { |
| struct cryptcat *cc = hCatalog; |
| |
| FIXME("%p, %s\n", hCatalog, debugstr_w(tag)); |
| |
| if (!hCatalog || hCatalog == INVALID_HANDLE_VALUE || cc->magic != CRYPTCAT_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| SetLastError(CRYPT_E_NOT_FOUND); |
| return NULL; |
| } |
| |
| CRYPTCATMEMBER * WINAPI CryptCATGetMemberInfo(HANDLE hCatalog, LPWSTR tag) |
| { |
| struct cryptcat *cc = hCatalog; |
| |
| FIXME("%p, %s\n", hCatalog, debugstr_w(tag)); |
| |
| if (!hCatalog || hCatalog == INVALID_HANDLE_VALUE || cc->magic != CRYPTCAT_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| SetLastError(CRYPT_E_NOT_FOUND); |
| return NULL; |
| } |
| |
| /*********************************************************************** |
| * CryptCATEnumerateAttr (WINTRUST.@) |
| */ |
| CRYPTCATATTRIBUTE * WINAPI CryptCATEnumerateAttr(HANDLE hCatalog, CRYPTCATMEMBER *member, CRYPTCATATTRIBUTE *prev) |
| { |
| struct cryptcat *cc = hCatalog; |
| |
| FIXME("%p, %p, %p\n", hCatalog, member, prev); |
| |
| if (!hCatalog || hCatalog == INVALID_HANDLE_VALUE || cc->magic != CRYPTCAT_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| SetLastError(CRYPT_E_NOT_FOUND); |
| return NULL; |
| } |
| |
| /*********************************************************************** |
| * CryptCATEnumerateCatAttr (WINTRUST.@) |
| */ |
| CRYPTCATATTRIBUTE * WINAPI CryptCATEnumerateCatAttr(HANDLE hCatalog, CRYPTCATATTRIBUTE *prev) |
| { |
| struct cryptcat *cc = hCatalog; |
| |
| FIXME("%p, %p\n", hCatalog, prev); |
| |
| if (!hCatalog || hCatalog == INVALID_HANDLE_VALUE || cc->magic != CRYPTCAT_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| SetLastError(CRYPT_E_NOT_FOUND); |
| return NULL; |
| } |
| |
| /*********************************************************************** |
| * CryptCATEnumerateMember (WINTRUST.@) |
| */ |
| CRYPTCATMEMBER * WINAPI CryptCATEnumerateMember(HANDLE hCatalog, CRYPTCATMEMBER *prev) |
| { |
| struct cryptcat *cc = hCatalog; |
| CRYPTCATMEMBER *member = prev; |
| CTL_ENTRY *entry; |
| DWORD size, i; |
| |
| TRACE("%p, %p\n", hCatalog, prev); |
| |
| if (!hCatalog || hCatalog == INVALID_HANDLE_VALUE || cc->magic != CRYPTCAT_MAGIC) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return NULL; |
| } |
| |
| /* dumping the contents makes me think that dwReserved is the iteration number */ |
| if (!member) |
| { |
| if (!(member = HeapAlloc(GetProcessHeap(), 0, sizeof(*member)))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return NULL; |
| } |
| member->cbStruct = sizeof(*member); |
| member->pwszFileName = member->pwszReferenceTag = NULL; |
| member->dwReserved = 0; |
| member->hReserved = NULL; |
| member->gSubjectType = cc->subject; |
| member->fdwMemberFlags = 0; |
| member->pIndirectData = NULL; |
| member->dwCertVersion = cc->inner->dwVersion; |
| } |
| else member->dwReserved++; |
| |
| if (member->dwReserved >= cc->inner->cCTLEntry) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| goto error; |
| } |
| |
| /* list them backwards, like native */ |
| entry = &cc->inner->rgCTLEntry[cc->inner->cCTLEntry - member->dwReserved - 1]; |
| |
| member->sEncodedIndirectData.cbData = member->sEncodedMemberInfo.cbData = 0; |
| member->sEncodedIndirectData.pbData = member->sEncodedMemberInfo.pbData = NULL; |
| HeapFree(GetProcessHeap(), 0, member->pIndirectData); |
| member->pIndirectData = NULL; |
| |
| for (i = 0; i < entry->cAttribute; i++) |
| { |
| CRYPT_ATTRIBUTE *attr = entry->rgAttribute + i; |
| |
| if (attr->cValue != 1) |
| { |
| ERR("Can't handle attr->cValue of %u\n", attr->cValue); |
| continue; |
| } |
| if (!strcmp(attr->pszObjId, CAT_MEMBERINFO_OBJID)) |
| { |
| CAT_MEMBERINFO *mi; |
| BOOL ret; |
| |
| member->sEncodedMemberInfo.cbData = attr->rgValue->cbData; |
| member->sEncodedMemberInfo.pbData = attr->rgValue->pbData; |
| |
| CryptDecodeObject(cc->encoding, CAT_MEMBERINFO_OBJID, attr->rgValue->pbData, attr->rgValue->cbData, 0, NULL, &size); |
| |
| if (!(mi = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| goto error; |
| } |
| ret = CryptDecodeObject(cc->encoding, CAT_MEMBERINFO_OBJID, attr->rgValue->pbData, attr->rgValue->cbData, 0, mi, &size); |
| if (ret) |
| { |
| UNICODE_STRING guid; |
| |
| member->dwCertVersion = mi->dwCertVersion; |
| RtlInitUnicodeString(&guid, mi->pwszSubjGuid); |
| if (RtlGUIDFromString(&guid, &member->gSubjectType)) |
| { |
| HeapFree(GetProcessHeap(), 0, mi); |
| goto error; |
| } |
| } |
| HeapFree(GetProcessHeap(), 0, mi); |
| if (!ret) goto error; |
| } |
| else if (!strcmp(attr->pszObjId, SPC_INDIRECT_DATA_OBJID)) |
| { |
| /* SPC_INDIRECT_DATA_CONTENT is equal to SIP_INDIRECT_DATA */ |
| |
| member->sEncodedIndirectData.cbData = attr->rgValue->cbData; |
| member->sEncodedIndirectData.pbData = attr->rgValue->pbData; |
| |
| CryptDecodeObject(cc->encoding, SPC_INDIRECT_DATA_OBJID, attr->rgValue->pbData, attr->rgValue->cbData, 0, NULL, &size); |
| |
| if (!(member->pIndirectData = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| goto error; |
| } |
| CryptDecodeObject(cc->encoding, SPC_INDIRECT_DATA_OBJID, attr->rgValue->pbData, attr->rgValue->cbData, 0, member->pIndirectData, &size); |
| } |
| else |
| /* this object id should probably be handled in CryptCATEnumerateAttr */ |
| FIXME("unhandled object id \"%s\"\n", attr->pszObjId); |
| } |
| |
| if (!member->sEncodedMemberInfo.cbData || !member->sEncodedIndirectData.cbData) |
| { |
| ERR("Corrupted catalog entry?\n"); |
| SetLastError(CRYPT_E_ATTRIBUTES_MISSING); |
| goto error; |
| } |
| size = (2 * member->pIndirectData->Digest.cbData + 1) * sizeof(WCHAR); |
| if (member->pwszReferenceTag) |
| member->pwszReferenceTag = HeapReAlloc(GetProcessHeap(), 0, member->pwszReferenceTag, size); |
| else |
| member->pwszReferenceTag = HeapAlloc(GetProcessHeap(), 0, size); |
| |
| if (!member->pwszReferenceTag) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| goto error; |
| } |
| /* FIXME: reference tag is usually the file hash but doesn't have to be */ |
| for (i = 0; i < member->pIndirectData->Digest.cbData; i++) |
| { |
| DWORD sub; |
| |
| sub = member->pIndirectData->Digest.pbData[i] >> 4; |
| member->pwszReferenceTag[i * 2] = (sub < 10 ? '0' + sub : 'A' + sub - 10); |
| sub = member->pIndirectData->Digest.pbData[i] & 0xf; |
| member->pwszReferenceTag[i * 2 + 1] = (sub < 10 ? '0' + sub : 'A' + sub - 10); |
| } |
| member->pwszReferenceTag[i * 2] = 0; |
| return member; |
| |
| error: |
| HeapFree(GetProcessHeap(), 0, member->pIndirectData); |
| HeapFree(GetProcessHeap(), 0, member->pwszReferenceTag); |
| HeapFree(GetProcessHeap(), 0, member); |
| return NULL; |
| } |
| |
| static CTL_INFO *decode_inner_content(HANDLE hmsg, DWORD encoding, DWORD *len) |
| { |
| DWORD size; |
| LPSTR oid = NULL; |
| BYTE *buffer = NULL; |
| CTL_INFO *inner = NULL; |
| |
| if (!CryptMsgGetParam(hmsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size)) return NULL; |
| if (!(oid = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| return NULL; |
| } |
| if (!CryptMsgGetParam(hmsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, oid, &size)) goto out; |
| if (!CryptMsgGetParam(hmsg, CMSG_CONTENT_PARAM, 0, NULL, &size)) goto out; |
| if (!(buffer = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| goto out; |
| } |
| if (!CryptMsgGetParam(hmsg, CMSG_CONTENT_PARAM, 0, buffer, &size)) goto out; |
| if (!CryptDecodeObject(encoding, oid, buffer, size, 0, NULL, &size)) goto out; |
| if (!(inner = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| SetLastError(ERROR_OUTOFMEMORY); |
| goto out; |
| } |
| if (!CryptDecodeObject(encoding, oid, buffer, size, 0, inner, &size)) goto out; |
| *len = size; |
| |
| out: |
| HeapFree(GetProcessHeap(), 0, oid); |
| HeapFree(GetProcessHeap(), 0, buffer); |
| return inner; |
| } |
| |
| /*********************************************************************** |
| * CryptCATCatalogInfoFromContext (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptCATCatalogInfoFromContext(HCATINFO hcatinfo, CATALOG_INFO *info, DWORD flags) |
| { |
| struct catinfo *ci = hcatinfo; |
| |
| TRACE("%p, %p, %x\n", hcatinfo, info, flags); |
| |
| if (!hcatinfo || hcatinfo == INVALID_HANDLE_VALUE || ci->magic != CATINFO_MAGIC || |
| flags || !info || info->cbStruct != sizeof(*info)) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| strcpyW(info->wszCatalogFile, ci->file); |
| return TRUE; |
| } |
| |
| /*********************************************************************** |
| * CryptCATOpen (WINTRUST.@) |
| */ |
| HANDLE WINAPI CryptCATOpen(LPWSTR pwszFileName, DWORD fdwOpenFlags, HCRYPTPROV hProv, |
| DWORD dwPublicVersion, DWORD dwEncodingType) |
| { |
| HANDLE file, hmsg; |
| BYTE *buffer = NULL; |
| DWORD size, flags = OPEN_EXISTING; |
| struct cryptcat *cc; |
| |
| TRACE("%s, %x, %lx, %x, %x\n", debugstr_w(pwszFileName), fdwOpenFlags, |
| hProv, dwPublicVersion, dwEncodingType); |
| |
| if (!pwszFileName) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return INVALID_HANDLE_VALUE; |
| } |
| |
| if (!dwEncodingType) dwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| |
| if (fdwOpenFlags & CRYPTCAT_OPEN_ALWAYS) flags |= OPEN_ALWAYS; |
| if (fdwOpenFlags & CRYPTCAT_OPEN_CREATENEW) flags |= CREATE_NEW; |
| |
| file = CreateFileW(pwszFileName, GENERIC_READ, FILE_SHARE_READ, NULL, flags, 0, NULL); |
| if (file == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE; |
| |
| size = GetFileSize(file, NULL); |
| if (!(buffer = HeapAlloc(GetProcessHeap(), 0, size))) |
| { |
| CloseHandle(file); |
| SetLastError(ERROR_OUTOFMEMORY); |
| return INVALID_HANDLE_VALUE; |
| } |
| if (!(hmsg = CryptMsgOpenToDecode(dwEncodingType, 0, 0, hProv, NULL, NULL))) |
| { |
| CloseHandle(file); |
| HeapFree(GetProcessHeap(), 0, buffer); |
| return INVALID_HANDLE_VALUE; |
| } |
| if (!ReadFile(file, buffer, size, &size, NULL) || !CryptMsgUpdate(hmsg, buffer, size, TRUE)) |
| { |
| CloseHandle(file); |
| HeapFree(GetProcessHeap(), 0, buffer); |
| CryptMsgClose(hmsg); |
| return INVALID_HANDLE_VALUE; |
| } |
| HeapFree(GetProcessHeap(), 0, buffer); |
| CloseHandle(file); |
| |
| size = sizeof(DWORD); |
| if (!(cc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cc)))) |
| { |
| CryptMsgClose(hmsg); |
| SetLastError(ERROR_OUTOFMEMORY); |
| return INVALID_HANDLE_VALUE; |
| } |
| |
| cc->msg = hmsg; |
| cc->encoding = dwEncodingType; |
| if (CryptMsgGetParam(hmsg, CMSG_ATTR_CERT_COUNT_PARAM, 0, &cc->attr_count, &size)) |
| { |
| DWORD i, sum = 0; |
| BYTE *p; |
| |
| for (i = 0; i < cc->attr_count; i++) |
| { |
| if (!CryptMsgGetParam(hmsg, CMSG_ATTR_CERT_PARAM, i, NULL, &size)) |
| { |
| CryptMsgClose(hmsg); |
| HeapFree(GetProcessHeap(), 0, cc); |
| return INVALID_HANDLE_VALUE; |
| } |
| sum += size; |
| } |
| if (!(cc->attr = HeapAlloc(GetProcessHeap(), 0, sizeof(*cc->attr) * cc->attr_count + sum))) |
| { |
| CryptMsgClose(hmsg); |
| HeapFree(GetProcessHeap(), 0, cc); |
| SetLastError(ERROR_OUTOFMEMORY); |
| return INVALID_HANDLE_VALUE; |
| } |
| p = (BYTE *)(cc->attr + cc->attr_count); |
| for (i = 0; i < cc->attr_count; i++) |
| { |
| if (!CryptMsgGetParam(hmsg, CMSG_ATTR_CERT_PARAM, i, NULL, &size)) |
| { |
| CryptMsgClose(hmsg); |
| HeapFree(GetProcessHeap(), 0, cc->attr); |
| HeapFree(GetProcessHeap(), 0, cc); |
| return INVALID_HANDLE_VALUE; |
| } |
| if (!CryptMsgGetParam(hmsg, CMSG_ATTR_CERT_PARAM, i, p, &size)) |
| { |
| CryptMsgClose(hmsg); |
| HeapFree(GetProcessHeap(), 0, cc->attr); |
| HeapFree(GetProcessHeap(), 0, cc); |
| return INVALID_HANDLE_VALUE; |
| } |
| p += size; |
| } |
| cc->inner = decode_inner_content(hmsg, dwEncodingType, &cc->inner_len); |
| if (!cc->inner || !CryptSIPRetrieveSubjectGuid(pwszFileName, NULL, &cc->subject)) |
| { |
| CryptMsgClose(hmsg); |
| HeapFree(GetProcessHeap(), 0, cc->attr); |
| HeapFree(GetProcessHeap(), 0, cc->inner); |
| HeapFree(GetProcessHeap(), 0, cc); |
| return INVALID_HANDLE_VALUE; |
| } |
| cc->magic = CRYPTCAT_MAGIC; |
| return cc; |
| } |
| HeapFree(GetProcessHeap(), 0, cc); |
| return INVALID_HANDLE_VALUE; |
| } |
| |
| /*********************************************************************** |
| * CryptSIPCreateIndirectData (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptSIPCreateIndirectData(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pcbIndirectData, |
| SIP_INDIRECT_DATA* pIndirectData) |
| { |
| FIXME("(%p %p %p) stub\n", pSubjectInfo, pcbIndirectData, pIndirectData); |
| |
| return FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * CryptCATCDFClose (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptCATCDFClose(CRYPTCATCDF *pCDF) |
| { |
| FIXME("(%p) stub\n", pCDF); |
| |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * CryptCATCDFEnumCatAttributes (WINTRUST.@) |
| */ |
| CRYPTCATATTRIBUTE * WINAPI CryptCATCDFEnumCatAttributes(CRYPTCATCDF *pCDF, |
| CRYPTCATATTRIBUTE *pPrevAttr, |
| PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError) |
| { |
| FIXME("(%p %p %p) stub\n", pCDF, pPrevAttr, pfnParseError); |
| |
| return NULL; |
| } |
| |
| /*********************************************************************** |
| * CryptCATCDFEnumMembersByCDFTagEx (WINTRUST.@) |
| */ |
| LPWSTR WINAPI CryptCATCDFEnumMembersByCDFTagEx(CRYPTCATCDF *pCDF, LPWSTR pwszPrevCDFTag, |
| PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError, |
| CRYPTCATMEMBER **ppMember, BOOL fContinueOnError, |
| LPVOID pvReserved) |
| { |
| FIXME("(%p %s %p %p %d %p) stub\n", pCDF, debugstr_w(pwszPrevCDFTag), pfnParseError, |
| ppMember, fContinueOnError, pvReserved); |
| |
| return NULL; |
| } |
| |
| /*********************************************************************** |
| * CryptCATCDFOpen (WINTRUST.@) |
| */ |
| CRYPTCATCDF * WINAPI CryptCATCDFOpen(LPWSTR pwszFilePath, |
| PFN_CDF_PARSE_ERROR_CALLBACK pfnParseError) |
| { |
| FIXME("(%s %p) stub\n", debugstr_w(pwszFilePath), pfnParseError); |
| |
| return NULL; |
| } |
| |
| static BOOL WINTRUST_GetSignedMsgFromPEFile(SIP_SUBJECTINFO *pSubjectInfo, |
| DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg, |
| BYTE *pbSignedDataMsg) |
| { |
| BOOL ret; |
| WIN_CERTIFICATE *pCert = NULL; |
| HANDLE file; |
| |
| TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, |
| pcbSignedDataMsg, pbSignedDataMsg); |
| |
| if(pSubjectInfo->hFile && pSubjectInfo->hFile!=INVALID_HANDLE_VALUE) |
| file = pSubjectInfo->hFile; |
| else |
| { |
| file = CreateFileW(pSubjectInfo->pwsFileName, GENERIC_READ, |
| FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); |
| if(file == INVALID_HANDLE_VALUE) |
| return FALSE; |
| } |
| |
| if (!pbSignedDataMsg) |
| { |
| WIN_CERTIFICATE cert; |
| |
| /* app hasn't passed buffer, just get the length */ |
| ret = ImageGetCertificateHeader(file, dwIndex, &cert); |
| if (ret) |
| { |
| switch (cert.wCertificateType) |
| { |
| case WIN_CERT_TYPE_X509: |
| case WIN_CERT_TYPE_PKCS_SIGNED_DATA: |
| *pcbSignedDataMsg = cert.dwLength; |
| break; |
| default: |
| WARN("unknown certificate type %d\n", cert.wCertificateType); |
| ret = FALSE; |
| } |
| } |
| } |
| else |
| { |
| DWORD len = 0; |
| |
| ret = ImageGetCertificateData(file, dwIndex, NULL, &len); |
| if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) |
| goto error; |
| pCert = HeapAlloc(GetProcessHeap(), 0, len); |
| if (!pCert) |
| { |
| ret = FALSE; |
| goto error; |
| } |
| ret = ImageGetCertificateData(file, dwIndex, pCert, &len); |
| if (!ret) |
| goto error; |
| pCert->dwLength -= FIELD_OFFSET(WIN_CERTIFICATE, bCertificate); |
| if (*pcbSignedDataMsg < pCert->dwLength) |
| { |
| *pcbSignedDataMsg = pCert->dwLength; |
| SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| ret = FALSE; |
| } |
| else |
| { |
| memcpy(pbSignedDataMsg, pCert->bCertificate, pCert->dwLength); |
| *pcbSignedDataMsg = pCert->dwLength; |
| switch (pCert->wCertificateType) |
| { |
| case WIN_CERT_TYPE_X509: |
| *pdwEncodingType = X509_ASN_ENCODING; |
| break; |
| case WIN_CERT_TYPE_PKCS_SIGNED_DATA: |
| *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| break; |
| default: |
| WARN("don't know what to do for encoding type %d\n", |
| pCert->wCertificateType); |
| *pdwEncodingType = 0; |
| ret = FALSE; |
| } |
| } |
| } |
| error: |
| if(pSubjectInfo->hFile != file) |
| CloseHandle(file); |
| HeapFree(GetProcessHeap(), 0, pCert); |
| return ret; |
| } |
| |
| static BOOL WINTRUST_PutSignedMsgToPEFile(SIP_SUBJECTINFO* pSubjectInfo, DWORD pdwEncodingType, |
| DWORD* pdwIndex, DWORD cbSignedDataMsg, BYTE* pbSignedDataMsg) |
| { |
| WIN_CERTIFICATE *cert; |
| HANDLE file; |
| DWORD size; |
| BOOL ret; |
| |
| if(pSubjectInfo->hFile && pSubjectInfo->hFile!=INVALID_HANDLE_VALUE) |
| file = pSubjectInfo->hFile; |
| else |
| { |
| file = CreateFileW(pSubjectInfo->pwsFileName, GENERIC_READ|GENERIC_WRITE, |
| FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); |
| if(file == INVALID_HANDLE_VALUE) |
| return FALSE; |
| } |
| |
| /* int aligned WIN_CERTIFICATE structure with cbSignedDataMsg+1 bytes of data */ |
| size = FIELD_OFFSET(WIN_CERTIFICATE, bCertificate[cbSignedDataMsg+4]) & (~3); |
| cert = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); |
| if(!cert) |
| return FALSE; |
| |
| cert->dwLength = size; |
| cert->wRevision = WIN_CERT_REVISION_2_0; |
| cert->wCertificateType = WIN_CERT_TYPE_PKCS_SIGNED_DATA; |
| memcpy(cert->bCertificate, pbSignedDataMsg, cbSignedDataMsg); |
| ret = ImageAddCertificate(file, cert, pdwIndex); |
| |
| HeapFree(GetProcessHeap(), 0, cert); |
| if(file != pSubjectInfo->hFile) |
| CloseHandle(file); |
| return ret; |
| } |
| |
| /* structure offsets */ |
| #define cfhead_Signature (0x00) |
| #define cfhead_CabinetSize (0x08) |
| #define cfhead_MinorVersion (0x18) |
| #define cfhead_MajorVersion (0x19) |
| #define cfhead_Flags (0x1E) |
| #define cfhead_SIZEOF (0x24) |
| #define cfheadext_HeaderReserved (0x00) |
| #define cfheadext_SIZEOF (0x04) |
| #define cfsigninfo_CertOffset (0x04) |
| #define cfsigninfo_CertSize (0x08) |
| #define cfsigninfo_SIZEOF (0x0C) |
| |
| /* flags */ |
| #define cfheadRESERVE_PRESENT (0x0004) |
| |
| /* endian-neutral reading of little-endian data */ |
| #define EndGetI32(a) ((((a)[3])<<24)|(((a)[2])<<16)|(((a)[1])<<8)|((a)[0])) |
| #define EndGetI16(a) ((((a)[1])<<8)|((a)[0])) |
| |
| /* For documentation purposes only: this is the structure in the reserved |
| * area of a signed cabinet file. The cert offset indicates where in the |
| * cabinet file the signature resides, and the count indicates its size. |
| */ |
| typedef struct _CAB_SIGNINFO |
| { |
| WORD unk0; /* always 0? */ |
| WORD unk1; /* always 0x0010? */ |
| DWORD dwCertOffset; |
| DWORD cbCertBlock; |
| } CAB_SIGNINFO, *PCAB_SIGNINFO; |
| |
| static BOOL WINTRUST_GetSignedMsgFromCabFile(SIP_SUBJECTINFO *pSubjectInfo, |
| DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg, |
| BYTE *pbSignedDataMsg) |
| { |
| int header_resv; |
| LONG base_offset, cabsize; |
| USHORT flags; |
| BYTE buf[64]; |
| DWORD cert_offset, cert_size, dwRead; |
| |
| TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, |
| pcbSignedDataMsg, pbSignedDataMsg); |
| |
| /* get basic offset & size info */ |
| base_offset = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR); |
| |
| if (SetFilePointer(pSubjectInfo->hFile, 0, NULL, SEEK_END) == INVALID_SET_FILE_POINTER) |
| { |
| TRACE("seek error\n"); |
| return FALSE; |
| } |
| |
| cabsize = SetFilePointer(pSubjectInfo->hFile, 0L, NULL, SEEK_CUR); |
| if ((cabsize == -1) || (base_offset == -1) || |
| (SetFilePointer(pSubjectInfo->hFile, 0, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER)) |
| { |
| TRACE("seek error\n"); |
| return FALSE; |
| } |
| |
| /* read in the CFHEADER */ |
| if (!ReadFile(pSubjectInfo->hFile, buf, cfhead_SIZEOF, &dwRead, NULL) || |
| dwRead != cfhead_SIZEOF) |
| { |
| TRACE("reading header failed\n"); |
| return FALSE; |
| } |
| |
| /* check basic MSCF signature */ |
| if (EndGetI32(buf+cfhead_Signature) != 0x4643534d) |
| { |
| WARN("cabinet signature not present\n"); |
| return FALSE; |
| } |
| |
| /* Ignore the number of folders and files and the set and cabinet IDs */ |
| |
| /* check the header revision */ |
| if ((buf[cfhead_MajorVersion] > 1) || |
| (buf[cfhead_MajorVersion] == 1 && buf[cfhead_MinorVersion] > 3)) |
| { |
| WARN("cabinet format version > 1.3\n"); |
| return FALSE; |
| } |
| |
| /* pull the flags out */ |
| flags = EndGetI16(buf+cfhead_Flags); |
| |
| if (!(flags & cfheadRESERVE_PRESENT)) |
| { |
| TRACE("no header present, not signed\n"); |
| return FALSE; |
| } |
| |
| if (!ReadFile(pSubjectInfo->hFile, buf, cfheadext_SIZEOF, &dwRead, NULL) || |
| dwRead != cfheadext_SIZEOF) |
| { |
| ERR("bunk reserve-sizes?\n"); |
| return FALSE; |
| } |
| |
| header_resv = EndGetI16(buf+cfheadext_HeaderReserved); |
| if (!header_resv) |
| { |
| TRACE("no header_resv, not signed\n"); |
| return FALSE; |
| } |
| else if (header_resv < cfsigninfo_SIZEOF) |
| { |
| TRACE("header_resv too small, not signed\n"); |
| return FALSE; |
| } |
| |
| if (header_resv > 60000) |
| { |
| WARN("WARNING; header reserved space > 60000\n"); |
| } |
| |
| if (!ReadFile(pSubjectInfo->hFile, buf, cfsigninfo_SIZEOF, &dwRead, NULL) || |
| dwRead != cfsigninfo_SIZEOF) |
| { |
| ERR("couldn't read reserve\n"); |
| return FALSE; |
| } |
| |
| cert_offset = EndGetI32(buf+cfsigninfo_CertOffset); |
| TRACE("cert_offset: %d\n", cert_offset); |
| cert_size = EndGetI32(buf+cfsigninfo_CertSize); |
| TRACE("cert_size: %d\n", cert_size); |
| |
| /* The redundant checks are to avoid wraparound */ |
| if (cert_offset > cabsize || cert_size > cabsize || |
| cert_offset + cert_size > cabsize) |
| { |
| WARN("offset beyond file, not attempting to read\n"); |
| return FALSE; |
| } |
| |
| SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET); |
| if (!pbSignedDataMsg) |
| { |
| *pcbSignedDataMsg = cert_size; |
| return TRUE; |
| } |
| if (*pcbSignedDataMsg < cert_size) |
| { |
| *pcbSignedDataMsg = cert_size; |
| SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| return FALSE; |
| } |
| if (SetFilePointer(pSubjectInfo->hFile, cert_offset, NULL, SEEK_SET) == INVALID_SET_FILE_POINTER) |
| { |
| ERR("couldn't seek to cert location\n"); |
| return FALSE; |
| } |
| if (!ReadFile(pSubjectInfo->hFile, pbSignedDataMsg, cert_size, &dwRead, |
| NULL) || dwRead != cert_size) |
| { |
| ERR("couldn't read cert\n"); |
| SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET); |
| return FALSE; |
| } |
| /* The encoding of the files I've seen appears to be in ASN.1 |
| * format, and there isn't a field indicating the type, so assume it |
| * always is. |
| */ |
| *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| /* Restore base offset */ |
| SetFilePointer(pSubjectInfo->hFile, base_offset, NULL, SEEK_SET); |
| return TRUE; |
| } |
| |
| static BOOL WINTRUST_GetSignedMsgFromCatFile(SIP_SUBJECTINFO *pSubjectInfo, |
| DWORD *pdwEncodingType, DWORD dwIndex, DWORD *pcbSignedDataMsg, |
| BYTE *pbSignedDataMsg) |
| { |
| BOOL ret; |
| |
| TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, |
| pcbSignedDataMsg, pbSignedDataMsg); |
| |
| if (!pbSignedDataMsg) |
| { |
| *pcbSignedDataMsg = GetFileSize(pSubjectInfo->hFile, NULL); |
| ret = TRUE; |
| } |
| else |
| { |
| DWORD len = GetFileSize(pSubjectInfo->hFile, NULL); |
| |
| if (*pcbSignedDataMsg < len) |
| { |
| *pcbSignedDataMsg = len; |
| SetLastError(ERROR_INSUFFICIENT_BUFFER); |
| ret = FALSE; |
| } |
| else |
| { |
| ret = ReadFile(pSubjectInfo->hFile, pbSignedDataMsg, len, |
| pcbSignedDataMsg, NULL); |
| if (ret) |
| *pdwEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; |
| } |
| } |
| return ret; |
| } |
| |
| /* GUIDs used by CryptSIPGetSignedDataMsg and CryptSIPPutSignedDataMsg */ |
| static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47, |
| 0x00,0xC0,0x4F,0xC2,0x95,0xEE } }; |
| static const GUID cabGUID = { 0xC689AABA, 0x8E78, 0x11D0, { 0x8C,0x47, |
| 0x00,0xC0,0x4F,0xC2,0x95,0xEE } }; |
| static const GUID catGUID = { 0xDE351A43, 0x8E59, 0x11D0, { 0x8C,0x47, |
| 0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; |
| |
| /*********************************************************************** |
| * CryptSIPGetSignedDataMsg (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptSIPGetSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pdwEncodingType, |
| DWORD dwIndex, DWORD* pcbSignedDataMsg, BYTE* pbSignedDataMsg) |
| { |
| BOOL ret; |
| |
| TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, |
| pcbSignedDataMsg, pbSignedDataMsg); |
| |
| if(!pSubjectInfo) |
| { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| |
| if (!memcmp(pSubjectInfo->pgSubjectType, &unknown, sizeof(unknown))) |
| ret = WINTRUST_GetSignedMsgFromPEFile(pSubjectInfo, pdwEncodingType, |
| dwIndex, pcbSignedDataMsg, pbSignedDataMsg); |
| else if (!memcmp(pSubjectInfo->pgSubjectType, &cabGUID, sizeof(cabGUID))) |
| ret = WINTRUST_GetSignedMsgFromCabFile(pSubjectInfo, pdwEncodingType, |
| dwIndex, pcbSignedDataMsg, pbSignedDataMsg); |
| else if (!memcmp(pSubjectInfo->pgSubjectType, &catGUID, sizeof(catGUID))) |
| ret = WINTRUST_GetSignedMsgFromCatFile(pSubjectInfo, pdwEncodingType, |
| dwIndex, pcbSignedDataMsg, pbSignedDataMsg); |
| else |
| { |
| FIXME("unimplemented for subject type %s\n", |
| debugstr_guid(pSubjectInfo->pgSubjectType)); |
| ret = FALSE; |
| } |
| |
| TRACE("returning %d\n", ret); |
| return ret; |
| } |
| |
| /*********************************************************************** |
| * CryptSIPPutSignedDataMsg (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptSIPPutSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD pdwEncodingType, |
| DWORD* pdwIndex, DWORD cbSignedDataMsg, BYTE* pbSignedDataMsg) |
| { |
| TRACE("(%p %d %p %d %p)\n", pSubjectInfo, pdwEncodingType, pdwIndex, |
| cbSignedDataMsg, pbSignedDataMsg); |
| |
| if(!pSubjectInfo) { |
| SetLastError(ERROR_INVALID_PARAMETER); |
| return FALSE; |
| } |
| |
| if(!memcmp(pSubjectInfo->pgSubjectType, &unknown, sizeof(unknown))) |
| return WINTRUST_PutSignedMsgToPEFile(pSubjectInfo, pdwEncodingType, |
| pdwIndex, cbSignedDataMsg, pbSignedDataMsg); |
| else |
| FIXME("unimplemented for subject type %s\n", |
| debugstr_guid(pSubjectInfo->pgSubjectType)); |
| |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * CryptSIPRemoveSignedDataMsg (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptSIPRemoveSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, |
| DWORD dwIndex) |
| { |
| FIXME("(%p %d) stub\n", pSubjectInfo, dwIndex); |
| |
| return FALSE; |
| } |
| |
| /*********************************************************************** |
| * CryptSIPVerifyIndirectData (WINTRUST.@) |
| */ |
| BOOL WINAPI CryptSIPVerifyIndirectData(SIP_SUBJECTINFO* pSubjectInfo, |
| SIP_INDIRECT_DATA* pIndirectData) |
| { |
| FIXME("(%p %p) stub\n", pSubjectInfo, pIndirectData); |
| |
| return FALSE; |
| } |