From ea715da1c6882ab89f20385cfb507c0388ff835c Mon Sep 17 00:00:00 2001 From: Juan Lang Date: Thu, 2 Sep 2010 18:26:28 -0700 Subject: [PATCH] wintrust/tests: Test CryptSIPCreateIndirectData. --- dlls/wintrust/tests/softpub.c | 268 +++++++++++++++++++++++++++++++--- 1 file changed, 250 insertions(+), 18 deletions(-) diff --git a/dlls/wintrust/tests/softpub.c b/dlls/wintrust/tests/softpub.c index e01a26ca288..dd12000f617 100644 --- a/dlls/wintrust/tests/softpub.c +++ b/dlls/wintrust/tests/softpub.c @@ -1,7 +1,8 @@ /* * wintrust softpub functions tests * - * Copyright 2007 Juan Lang + * Copyright 2007,2010 Juan Lang + * Copyright 2010 Andrey Turkin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -75,6 +76,35 @@ typedef struct _SAFE_PROVIDER_FUNCTIONS SAFE_PROVIDER_CLEANUP_CALL pfnCleanupPolicy; } SAFE_PROVIDER_FUNCTIONS; +static BOOL (WINAPI * pWTHelperGetKnownUsages)(DWORD action, PCCRYPT_OID_INFO **usages); +static BOOL (WINAPI * CryptSIPCreateIndirectData_p)(SIP_SUBJECTINFO *, DWORD *, SIP_INDIRECT_DATA *); + +static void InitFunctionPtrs(void) +{ + HMODULE hWintrust = GetModuleHandleA("wintrust.dll"); + HMODULE hCrypt32 = GetModuleHandleA("crypt32.dll"); + +#define WINTRUST_GET_PROC(func) \ + p ## func = (void*)GetProcAddress(hWintrust, #func); \ + if(!p ## func) { \ + trace("GetProcAddress(%s) failed\n", #func); \ + } + + WINTRUST_GET_PROC(WTHelperGetKnownUsages) + +#undef WINTRUST_GET_PROC + +#define CRYPT32_GET_PROC(func) \ + func ## _p = (void*)GetProcAddress(hCrypt32, #func); \ + if(!func ## _p) { \ + trace("GetProcAddress(%s) failed\n", #func); \ + } + + CRYPT32_GET_PROC(CryptSIPCreateIndirectData) + +#undef CRYPT32_GET_PROC +} + static const BYTE v1CertWithPubKey[] = { 0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30, 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61, @@ -464,6 +494,224 @@ static void test_provider_funcs(void) } } +/* minimal PE file image */ +#define VA_START 0x400000 +#define FILE_PE_START 0x50 +#define NUM_SECTIONS 3 +#define FILE_TEXT 0x200 +#define RVA_TEXT 0x1000 +#define RVA_BSS 0x2000 +#define FILE_IDATA 0x400 +#define RVA_IDATA 0x3000 +#define FILE_TOTAL 0x600 +#define RVA_TOTAL 0x4000 +#include +struct Imports { + IMAGE_IMPORT_DESCRIPTOR descriptors[2]; + IMAGE_THUNK_DATA32 original_thunks[2]; + IMAGE_THUNK_DATA32 thunks[2]; + struct __IMPORT_BY_NAME { + WORD hint; + char funcname[0x20]; + } ibn; + char dllname[0x10]; +}; +#define EXIT_PROCESS (VA_START+RVA_IDATA+FIELD_OFFSET(struct Imports, thunks[0])) + +static struct _PeImage { + IMAGE_DOS_HEADER dos_header; + char __alignment1[FILE_PE_START - sizeof(IMAGE_DOS_HEADER)]; + IMAGE_NT_HEADERS32 nt_headers; + IMAGE_SECTION_HEADER sections[NUM_SECTIONS]; + char __alignment2[FILE_TEXT - FILE_PE_START - sizeof(IMAGE_NT_HEADERS32) - + NUM_SECTIONS * sizeof(IMAGE_SECTION_HEADER)]; + unsigned char text_section[FILE_IDATA-FILE_TEXT]; + struct Imports idata_section; + char __alignment3[FILE_TOTAL-FILE_IDATA-sizeof(struct Imports)]; +} bin = { + /* dos header */ + {IMAGE_DOS_SIGNATURE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}, 0, 0, {}, FILE_PE_START}, + /* alignment before PE header */ + {}, + /* nt headers */ + {IMAGE_NT_SIGNATURE, + /* basic headers - 3 sections, no symbols, EXE file */ + {IMAGE_FILE_MACHINE_I386, NUM_SECTIONS, 0, 0, 0, sizeof(IMAGE_OPTIONAL_HEADER32), + IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE}, + /* optional header */ + {IMAGE_NT_OPTIONAL_HDR32_MAGIC, 4, 0, FILE_IDATA-FILE_TEXT, + FILE_TOTAL-FILE_IDATA + FILE_IDATA-FILE_TEXT, 0x400, + RVA_TEXT, RVA_TEXT, RVA_BSS, VA_START, 0x1000, 0x200, 4, 0, 1, 0, 4, 0, 0, + RVA_TOTAL, FILE_TEXT, 0, IMAGE_SUBSYSTEM_WINDOWS_GUI, 0, + 0x200000, 0x1000, 0x100000, 0x1000, 0, 0x10, + {{0, 0}, + {RVA_IDATA, sizeof(struct Imports)} + } + } + }, + /* sections */ + { + {".text", {0x100}, RVA_TEXT, FILE_IDATA-FILE_TEXT, FILE_TEXT, + 0, 0, 0, 0, IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ}, + {".bss", {0x400}, RVA_BSS, 0, 0, 0, 0, 0, 0, + IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE}, + {".idata", {sizeof(struct Imports)}, RVA_IDATA, FILE_TOTAL-FILE_IDATA, FILE_IDATA, 0, + 0, 0, 0, IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE} + }, + /* alignment before first section */ + {}, + /* .text section */ + { + 0x31, 0xC0, /* xor eax, eax */ + 0xFF, 0x25, EXIT_PROCESS&0xFF, (EXIT_PROCESS>>8)&0xFF, (EXIT_PROCESS>>16)&0xFF, + (EXIT_PROCESS>>24)&0xFF, /* jmp ExitProcess */ + 0 + }, + /* .idata section */ + { + { + {{RVA_IDATA + FIELD_OFFSET(struct Imports, original_thunks)}, 0, 0, + RVA_IDATA + FIELD_OFFSET(struct Imports, dllname), + RVA_IDATA + FIELD_OFFSET(struct Imports, thunks) + }, + {{0}, 0, 0, 0, 0} + }, + {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}}, + {{{RVA_IDATA+FIELD_OFFSET(struct Imports, ibn)}}, {{0}}}, + {0,"ExitProcess"}, + "KERNEL32.DLL" + }, + /* final alignment */ + {} +}; +#include + +/* Creates a test file and returns a handle to it. The file's path is returned + * in temp_file, which must be at least MAX_PATH characters in length. + */ +static HANDLE create_temp_file(char *temp_file) +{ + HANDLE file = INVALID_HANDLE_VALUE; + char temp_path[MAX_PATH]; + + if (GetTempPathA(sizeof(temp_path), temp_path)) + { + if (GetTempFileNameA(temp_path, "img", 0, temp_file)) + file = CreateFileA(temp_file, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + } + return file; +} + +static void test_sip_create_indirect_data(void) +{ + static GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47, + 0x00,0xC0,0x4F,0xC2,0x95,0xEE } }; + static char oid_sha1[] = szOID_OIWSEC_sha1; + BOOL ret; + SIP_SUBJECTINFO subjinfo = { 0 }; + char temp_file[MAX_PATH]; + HANDLE file; + DWORD count; + + if (!CryptSIPCreateIndirectData_p) + { + skip("Missing CryptSIPCreateIndirectData\n"); + return; + } +if (0) +{ + /* FIXME: crashes Wine */ + SetLastError(0xdeadbeef); + ret = CryptSIPCreateIndirectData_p(NULL, NULL, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); +} + /* FIXME: this assignment is only to avoid a crash in Wine, it isn't + * needed by native. + */ + subjinfo.pgSubjectType = &unknown; + SetLastError(0xdeadbeef); + ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + subjinfo.cbSize = sizeof(subjinfo); + SetLastError(0xdeadbeef); + ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + file = create_temp_file(temp_file); + if (file == INVALID_HANDLE_VALUE) + { + skip("couldn't create temp file\n"); + return; + } + WriteFile(file, &bin, sizeof(bin), &count, NULL); + FlushFileBuffers(file); + + subjinfo.hFile = file; + SetLastError(0xdeadbeef); + ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + subjinfo.pgSubjectType = &unknown; + SetLastError(0xdeadbeef); + ret = CryptSIPCreateIndirectData_p(&subjinfo, NULL, NULL); + todo_wine + ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER, + "expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + count = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL); + todo_wine + ok(!ret && (GetLastError() == NTE_BAD_ALGID || + GetLastError() == ERROR_INVALID_PARAMETER /* Win7 */), + "expected NTE_BAD_ALGID or ERROR_INVALID_PARAMETER, got %08x\n", + GetLastError()); + ok(count == 0xdeadbeef, "expected count to be unmodified, got %d\n", count); + subjinfo.DigestAlgorithm.pszObjId = oid_sha1; + count = 0xdeadbeef; + ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, NULL); + todo_wine + ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError()); + ok(count, "expected a positive count\n"); + if (ret) + { + SIP_INDIRECT_DATA *indirect = HeapAlloc(GetProcessHeap(), 0, count); + + count = 256; + ret = CryptSIPCreateIndirectData_p(&subjinfo, &count, indirect); + ok(ret, "CryptSIPCreateIndirectData failed: %d\n", GetLastError()); + /* If the count is larger than needed, it's unmodified */ + ok(count == 256, "unexpected count %d\n", count); + ok(!strcmp(indirect->Data.pszObjId, SPC_PE_IMAGE_DATA_OBJID), + "unexpected data oid %s\n", + indirect->Data.pszObjId); + ok(!strcmp(indirect->DigestAlgorithm.pszObjId, oid_sha1), + "unexpected digest algorithm oid %s\n", + indirect->DigestAlgorithm.pszObjId); + ok(indirect->Digest.cbData == 20, "unexpected hash size %d\n", + indirect->Digest.cbData); + if (indirect->Digest.cbData == 20) + { + const BYTE hash[20] = { + 0x8a,0xd5,0x45,0x53,0x3d,0x67,0xdf,0x2f,0x78,0xe0, + 0x55,0x0a,0xe0,0xd9,0x7a,0x28,0x3e,0xbf,0x45,0x2b }; + + ok(!memcmp(indirect->Digest.pbData, hash, 20), + "unexpected value\n"); + } + + HeapFree(GetProcessHeap(), 0, indirect); + } + CloseHandle(file); + DeleteFileA(temp_file); +} + static void test_wintrust(void) { static GUID generic_action_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; @@ -492,23 +740,6 @@ static void test_wintrust(void) "expected TRUST_E_NOSIGNATURE or CRYPT_E_FILE_ERROR, got %08x\n", hr); } -static BOOL (WINAPI * pWTHelperGetKnownUsages)(DWORD action, PCCRYPT_OID_INFO **usages); - -static void InitFunctionPtrs(void) -{ - HMODULE hWintrust = GetModuleHandleA("wintrust.dll"); - -#define WINTRUST_GET_PROC(func) \ - p ## func = (void*)GetProcAddress(hWintrust, #func); \ - if(!p ## func) { \ - trace("GetProcAddress(%s) failed\n", #func); \ - } - - WINTRUST_GET_PROC(WTHelperGetKnownUsages) - -#undef WINTRUST_GET_PROC -} - static void test_get_known_usages(void) { BOOL ret; @@ -577,6 +808,7 @@ START_TEST(softpub) { InitFunctionPtrs(); test_provider_funcs(); + test_sip_create_indirect_data(); test_wintrust(); test_get_known_usages(); }