| /* | |
| * 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; | |
| } |