| 1 | /* | 
|---|
| 2 | * Copyright 2002 Mike McCormack for CodeWeavers | 
|---|
| 3 | * Copyright 2005-2008 Juan Lang | 
|---|
| 4 | * Copyright 2006 Paul Vriens | 
|---|
| 5 | * | 
|---|
| 6 | * This library is free software; you can redistribute it and/or | 
|---|
| 7 | * modify it under the terms of the GNU Lesser General Public | 
|---|
| 8 | * License as published by the Free Software Foundation; either | 
|---|
| 9 | * version 2.1 of the License, or (at your option) any later version. | 
|---|
| 10 | * | 
|---|
| 11 | * This library is distributed in the hope that it will be useful, | 
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 14 | * Lesser General Public License for more details. | 
|---|
| 15 | * | 
|---|
| 16 | * You should have received a copy of the GNU Lesser General Public | 
|---|
| 17 | * License along with this library; if not, write to the Free Software | 
|---|
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|---|
| 19 | */ | 
|---|
| 20 |  | 
|---|
| 21 | #include <stdarg.h> | 
|---|
| 22 | #include <stdio.h> | 
|---|
| 23 | #include <string.h> | 
|---|
| 24 |  | 
|---|
| 25 | #define WINE_LARGE_INTEGER /* for QuadPart in LARGE_INTEGER */ | 
|---|
| 26 |  | 
|---|
| 27 | #include "windef.h" | 
|---|
| 28 | #include "winbase.h" | 
|---|
| 29 | #include "winerror.h" | 
|---|
| 30 | #include "wincrypt.h" | 
|---|
| 31 | #include "winreg.h" | 
|---|
| 32 | #include "winnls.h" | 
|---|
| 33 | #include "mssip.h" | 
|---|
| 34 | #include "winuser.h" | 
|---|
| 35 |  | 
|---|
| 36 | #include "wine/debug.h" | 
|---|
| 37 | #include "wine/list.h" | 
|---|
| 38 | #include "win32type.h" | 
|---|
| 39 |  | 
|---|
| 40 | WINE_DEFAULT_DEBUG_CHANNEL(crypt); | 
|---|
| 41 |  | 
|---|
| 42 | static const WCHAR szOID[] = { | 
|---|
| 43 | 'S','o','f','t','w','a','r','e','\\', | 
|---|
| 44 | 'M','i','c','r','o','s','o','f','t','\\', | 
|---|
| 45 | 'C','r','y','p','t','o','g','r','a','p','h','y','\\', | 
|---|
| 46 | 'O','I','D','\\', | 
|---|
| 47 | 'E','n','c','o','d','i','n','g','T','y','p','e',' ','0','\\', | 
|---|
| 48 | 'C','r','y','p','t','S','I','P','D','l','l', 0 }; | 
|---|
| 49 |  | 
|---|
| 50 | static const WCHAR szPutSigned[] = { | 
|---|
| 51 | 'P','u','t','S','i','g','n','e','d','D','a','t','a','M','s','g','\\',0}; | 
|---|
| 52 | static const WCHAR szGetSigned[] = { | 
|---|
| 53 | 'G','e','t','S','i','g','n','e','d','D','a','t','a','M','s','g','\\',0}; | 
|---|
| 54 | static const WCHAR szRemoveSigned[] = { | 
|---|
| 55 | 'R','e','m','o','v','e','S','i','g','n','e','d','D','a','t','a','M','s','g','\\',0}; | 
|---|
| 56 | static const WCHAR szCreate[] = { | 
|---|
| 57 | 'C','r','e','a','t','e','I','n','d','i','r','e','c','t','D','a','t','a','\\',0}; | 
|---|
| 58 | static const WCHAR szVerify[] = { | 
|---|
| 59 | 'V','e','r','i','f','y','I','n','d','i','r','e','c','t','D','a','t','a','\\',0}; | 
|---|
| 60 | static const WCHAR szIsMyFile[] = { | 
|---|
| 61 | 'I','s','M','y','F','i','l','e','T','y','p','e','\\',0}; | 
|---|
| 62 | static const WCHAR szIsMyFile2[] = { | 
|---|
| 63 | 'I','s','M','y','F','i','l','e','T','y','p','e','2','\\',0}; | 
|---|
| 64 |  | 
|---|
| 65 | static const WCHAR szDllName[] = { 'D','l','l',0 }; | 
|---|
| 66 | static const WCHAR szFuncName[] = { 'F','u','n','c','N','a','m','e',0 }; | 
|---|
| 67 |  | 
|---|
| 68 | /* convert a guid to a wide character string */ | 
|---|
| 69 | static void CRYPT_guid2wstr( const GUID *guid, LPWSTR wstr ) | 
|---|
| 70 | { | 
|---|
| 71 | char str[40]; | 
|---|
| 72 |  | 
|---|
| 73 | sprintf(str, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", | 
|---|
| 74 | guid->Data1, guid->Data2, guid->Data3, | 
|---|
| 75 | guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3], | 
|---|
| 76 | guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7] ); | 
|---|
| 77 | MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, 40 ); | 
|---|
| 78 | } | 
|---|
| 79 |  | 
|---|
| 80 | /*********************************************************************** | 
|---|
| 81 | *              CRYPT_SIPDeleteFunction | 
|---|
| 82 | * | 
|---|
| 83 | * Helper function for CryptSIPRemoveProvider | 
|---|
| 84 | */ | 
|---|
| 85 | static LONG CRYPT_SIPDeleteFunction( const GUID *guid, LPCWSTR szKey ) | 
|---|
| 86 | { | 
|---|
| 87 | WCHAR szFullKey[ 0x100 ]; | 
|---|
| 88 | LONG r = ERROR_SUCCESS; | 
|---|
| 89 |  | 
|---|
| 90 | /* max length of szFullKey depends on our code only, so we won't overrun */ | 
|---|
| 91 | lstrcpyW( szFullKey, szOID ); | 
|---|
| 92 | lstrcatW( szFullKey, szKey ); | 
|---|
| 93 | CRYPT_guid2wstr( guid, &szFullKey[ lstrlenW( szFullKey ) ] ); | 
|---|
| 94 |  | 
|---|
| 95 | r = RegDeleteKeyW(HKEY_LOCAL_MACHINE, szFullKey); | 
|---|
| 96 |  | 
|---|
| 97 | return r; | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | /*********************************************************************** | 
|---|
| 101 | *             CryptSIPRemoveProvider (CRYPT32.@) | 
|---|
| 102 | * | 
|---|
| 103 | * Remove a SIP provider and its functions from the registry. | 
|---|
| 104 | * | 
|---|
| 105 | * PARAMS | 
|---|
| 106 | *  pgProv     [I] Pointer to a GUID for this SIP provider | 
|---|
| 107 | * | 
|---|
| 108 | * RETURNS | 
|---|
| 109 | *  Success: TRUE. | 
|---|
| 110 | *  Failure: FALSE. (Look at GetLastError()). | 
|---|
| 111 | * | 
|---|
| 112 | * NOTES | 
|---|
| 113 | *  Registry errors are always reported via SetLastError(). Every registry | 
|---|
| 114 | *  deletion will be tried. | 
|---|
| 115 | */ | 
|---|
| 116 | BOOL WINAPI CryptSIPRemoveProvider(GUID *pgProv) | 
|---|
| 117 | { | 
|---|
| 118 | LONG r = ERROR_SUCCESS; | 
|---|
| 119 | LONG remove_error = ERROR_SUCCESS; | 
|---|
| 120 |  | 
|---|
| 121 | TRACE("%s\n", debugstr_guid(pgProv)); | 
|---|
| 122 |  | 
|---|
| 123 | if (!pgProv) | 
|---|
| 124 | { | 
|---|
| 125 | SetLastError(ERROR_INVALID_PARAMETER); | 
|---|
| 126 | return FALSE; | 
|---|
| 127 | } | 
|---|
| 128 |  | 
|---|
| 129 |  | 
|---|
| 130 | #define CRYPT_SIPREMOVEPROV( key ) \ | 
|---|
| 131 | r = CRYPT_SIPDeleteFunction( pgProv, key); \ | 
|---|
| 132 | if (r != ERROR_SUCCESS) remove_error = r | 
|---|
| 133 |  | 
|---|
| 134 | CRYPT_SIPREMOVEPROV( szPutSigned); | 
|---|
| 135 | CRYPT_SIPREMOVEPROV( szGetSigned); | 
|---|
| 136 | CRYPT_SIPREMOVEPROV( szRemoveSigned); | 
|---|
| 137 | CRYPT_SIPREMOVEPROV( szCreate); | 
|---|
| 138 | CRYPT_SIPREMOVEPROV( szVerify); | 
|---|
| 139 | CRYPT_SIPREMOVEPROV( szIsMyFile); | 
|---|
| 140 | CRYPT_SIPREMOVEPROV( szIsMyFile2); | 
|---|
| 141 |  | 
|---|
| 142 | #undef CRYPT_SIPREMOVEPROV | 
|---|
| 143 |  | 
|---|
| 144 | if (remove_error != ERROR_SUCCESS) | 
|---|
| 145 | { | 
|---|
| 146 | SetLastError(remove_error); | 
|---|
| 147 | return FALSE; | 
|---|
| 148 | } | 
|---|
| 149 |  | 
|---|
| 150 | return TRUE; | 
|---|
| 151 | } | 
|---|
| 152 |  | 
|---|
| 153 | /* | 
|---|
| 154 | * Helper for CryptSIPAddProvider | 
|---|
| 155 | * | 
|---|
| 156 | * Add a registry key containing a dll name and function under | 
|---|
| 157 | *  "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\<func>\\<guid>" | 
|---|
| 158 | */ | 
|---|
| 159 | static LONG CRYPT_SIPWriteFunction( const GUID *guid, LPCWSTR szKey, | 
|---|
| 160 | LPCWSTR szDll, LPCWSTR szFunction ) | 
|---|
| 161 | { | 
|---|
| 162 | WCHAR szFullKey[ 0x100 ]; | 
|---|
| 163 | LONG r = ERROR_SUCCESS; | 
|---|
| 164 | HKEY hKey; | 
|---|
| 165 |  | 
|---|
| 166 | if( !szFunction ) | 
|---|
| 167 | return ERROR_SUCCESS; | 
|---|
| 168 |  | 
|---|
| 169 | /* max length of szFullKey depends on our code only, so we won't overrun */ | 
|---|
| 170 | lstrcpyW( szFullKey, szOID ); | 
|---|
| 171 | lstrcatW( szFullKey, szKey ); | 
|---|
| 172 | CRYPT_guid2wstr( guid, &szFullKey[ lstrlenW( szFullKey ) ] ); | 
|---|
| 173 |  | 
|---|
| 174 | TRACE("key is %s\n", debugstr_w( szFullKey ) ); | 
|---|
| 175 |  | 
|---|
| 176 | r = RegCreateKeyW( HKEY_LOCAL_MACHINE, szFullKey, &hKey ); | 
|---|
| 177 | if( r != ERROR_SUCCESS ) goto error_close_key; | 
|---|
| 178 |  | 
|---|
| 179 | /* write the values */ | 
|---|
| 180 | r = RegSetValueExW( hKey, szFuncName, 0, REG_SZ, (BYTE*) szFunction, | 
|---|
| 181 | ( lstrlenW( szFunction ) + 1 ) * sizeof (WCHAR) ); | 
|---|
| 182 | if( r != ERROR_SUCCESS ) goto error_close_key; | 
|---|
| 183 | r = RegSetValueExW( hKey, szDllName, 0, REG_SZ, (BYTE*) szDll, | 
|---|
| 184 | ( lstrlenW( szDll ) + 1) * sizeof (WCHAR) ); | 
|---|
| 185 |  | 
|---|
| 186 | error_close_key: | 
|---|
| 187 |  | 
|---|
| 188 | RegCloseKey( hKey ); | 
|---|
| 189 |  | 
|---|
| 190 | return r; | 
|---|
| 191 | } | 
|---|
| 192 |  | 
|---|
| 193 | /*********************************************************************** | 
|---|
| 194 | *             CryptSIPAddProvider (CRYPT32.@) | 
|---|
| 195 | * | 
|---|
| 196 | * Add a SIP provider and its functions to the registry. | 
|---|
| 197 | * | 
|---|
| 198 | * PARAMS | 
|---|
| 199 | *  psNewProv       [I] Pointer to a structure with information about | 
|---|
| 200 | *                      the functions this SIP provider can perform. | 
|---|
| 201 | * | 
|---|
| 202 | * RETURNS | 
|---|
| 203 | *  Success: TRUE. | 
|---|
| 204 | *  Failure: FALSE. (Look at GetLastError()). | 
|---|
| 205 | * | 
|---|
| 206 | * NOTES | 
|---|
| 207 | *  Registry errors are always reported via SetLastError(). If a | 
|---|
| 208 | *  registry error occurs the rest of the registry write operations | 
|---|
| 209 | *  will be skipped. | 
|---|
| 210 | */ | 
|---|
| 211 | BOOL WINAPI CryptSIPAddProvider(SIP_ADD_NEWPROVIDER *psNewProv) | 
|---|
| 212 | { | 
|---|
| 213 | LONG r = ERROR_SUCCESS; | 
|---|
| 214 |  | 
|---|
| 215 | TRACE("%p\n", psNewProv); | 
|---|
| 216 |  | 
|---|
| 217 | if (!psNewProv || | 
|---|
| 218 | psNewProv->cbStruct != sizeof(SIP_ADD_NEWPROVIDER) || | 
|---|
| 219 | !psNewProv->pwszGetFuncName || | 
|---|
| 220 | !psNewProv->pwszPutFuncName || | 
|---|
| 221 | !psNewProv->pwszCreateFuncName || | 
|---|
| 222 | !psNewProv->pwszVerifyFuncName || | 
|---|
| 223 | !psNewProv->pwszRemoveFuncName) | 
|---|
| 224 | { | 
|---|
| 225 | SetLastError(ERROR_INVALID_PARAMETER); | 
|---|
| 226 | return FALSE; | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | TRACE("%s %s %s %s %s\n", | 
|---|
| 230 | debugstr_guid( psNewProv->pgSubject ), | 
|---|
| 231 | debugstr_w( psNewProv->pwszDLLFileName ), | 
|---|
| 232 | debugstr_w( psNewProv->pwszMagicNumber ), | 
|---|
| 233 | debugstr_w( psNewProv->pwszIsFunctionName ), | 
|---|
| 234 | debugstr_w( psNewProv->pwszIsFunctionNameFmt2 ) ); | 
|---|
| 235 |  | 
|---|
| 236 | #define CRYPT_SIPADDPROV( key, field ) \ | 
|---|
| 237 | r = CRYPT_SIPWriteFunction( psNewProv->pgSubject, key, \ | 
|---|
| 238 | psNewProv->pwszDLLFileName, psNewProv->field); \ | 
|---|
| 239 | if (r != ERROR_SUCCESS) goto end_function | 
|---|
| 240 |  | 
|---|
| 241 | CRYPT_SIPADDPROV( szPutSigned, pwszPutFuncName ); | 
|---|
| 242 | CRYPT_SIPADDPROV( szGetSigned, pwszGetFuncName ); | 
|---|
| 243 | CRYPT_SIPADDPROV( szRemoveSigned, pwszRemoveFuncName ); | 
|---|
| 244 | CRYPT_SIPADDPROV( szCreate, pwszCreateFuncName ); | 
|---|
| 245 | CRYPT_SIPADDPROV( szVerify, pwszVerifyFuncName ); | 
|---|
| 246 | CRYPT_SIPADDPROV( szIsMyFile, pwszIsFunctionName ); | 
|---|
| 247 | CRYPT_SIPADDPROV( szIsMyFile2, pwszIsFunctionNameFmt2 ); | 
|---|
| 248 |  | 
|---|
| 249 | #undef CRYPT_SIPADDPROV | 
|---|
| 250 |  | 
|---|
| 251 | end_function: | 
|---|
| 252 |  | 
|---|
| 253 | if (r != ERROR_SUCCESS) | 
|---|
| 254 | { | 
|---|
| 255 | SetLastError(r); | 
|---|
| 256 | return FALSE; | 
|---|
| 257 | } | 
|---|
| 258 |  | 
|---|
| 259 | return TRUE; | 
|---|
| 260 | } | 
|---|
| 261 |  | 
|---|
| 262 | static void *CRYPT_LoadSIPFuncFromKey(HKEY key, HMODULE *pLib) | 
|---|
| 263 | { | 
|---|
| 264 | LONG r; | 
|---|
| 265 | DWORD size; | 
|---|
| 266 | WCHAR dllName[MAX_PATH]; | 
|---|
| 267 | char functionName[MAX_PATH]; | 
|---|
| 268 | HMODULE lib; | 
|---|
| 269 | void *func = NULL; | 
|---|
| 270 |  | 
|---|
| 271 | /* Read the DLL entry */ | 
|---|
| 272 | size = sizeof(dllName); | 
|---|
| 273 | r = RegQueryValueExW(key, szDllName, NULL, NULL, (LPBYTE)dllName, &size); | 
|---|
| 274 | if (r) goto end; | 
|---|
| 275 |  | 
|---|
| 276 | /* Read the Function entry */ | 
|---|
| 277 | size = sizeof(functionName); | 
|---|
| 278 | r = RegQueryValueExA(key, "FuncName", NULL, NULL, (LPBYTE)functionName, | 
|---|
| 279 | &size); | 
|---|
| 280 | if (r) goto end; | 
|---|
| 281 |  | 
|---|
| 282 | lib = LoadLibraryW(dllName); | 
|---|
| 283 | if (!lib) | 
|---|
| 284 | goto end; | 
|---|
| 285 | func = (void*)GetProcAddress(lib, functionName); | 
|---|
| 286 | if (func) | 
|---|
| 287 | *pLib = lib; | 
|---|
| 288 | else | 
|---|
| 289 | FreeLibrary(lib); | 
|---|
| 290 |  | 
|---|
| 291 | end: | 
|---|
| 292 | return func; | 
|---|
| 293 | } | 
|---|
| 294 |  | 
|---|
| 295 | /*********************************************************************** | 
|---|
| 296 | *             CryptSIPRetrieveSubjectGuid (CRYPT32.@) | 
|---|
| 297 | * | 
|---|
| 298 | * Determine the right SIP GUID for the given file. | 
|---|
| 299 | * | 
|---|
| 300 | * PARAMS | 
|---|
| 301 | *  FileName   [I] Filename. | 
|---|
| 302 | *  hFileIn    [I] Optional handle to the file. | 
|---|
| 303 | *  pgSubject  [O] The SIP's GUID. | 
|---|
| 304 | * | 
|---|
| 305 | * RETURNS | 
|---|
| 306 | *  Success: TRUE. pgSubject contains the SIP GUID. | 
|---|
| 307 | *  Failure: FALSE. (Look at GetLastError()). | 
|---|
| 308 | * | 
|---|
| 309 | * NOTES | 
|---|
| 310 | *  On failure pgSubject will contain a NULL GUID. | 
|---|
| 311 | *  The handle is always preferred above the filename. | 
|---|
| 312 | */ | 
|---|
| 313 | BOOL WINAPI CryptSIPRetrieveSubjectGuid | 
|---|
| 314 | (LPCWSTR FileName, HANDLE hFileIn, GUID *pgSubject) | 
|---|
| 315 | { | 
|---|
| 316 | HANDLE hFile; | 
|---|
| 317 | BOOL   bRet = FALSE; | 
|---|
| 318 | DWORD  count; | 
|---|
| 319 | LARGE_INTEGER zero, oldPos; | 
|---|
| 320 | /* FIXME, find out if there is a name for this GUID */ | 
|---|
| 321 | static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; | 
|---|
| 322 | static const GUID cabGUID = { 0xc689aaba, 0x8e78, 0x11d0, {0x8c,0x47,0x00,0xc0,0x4f,0xc2,0x95,0xee }}; | 
|---|
| 323 | static const GUID catGUID = { 0xDE351A43, 0x8E59, 0x11D0, { 0x8C,0x47,0x00,0xC0,0x4F,0xC2,0x95,0xEE }}; | 
|---|
| 324 | static const WORD dosHdr = IMAGE_DOS_SIGNATURE; | 
|---|
| 325 | static const BYTE cabHdr[] = { 'M','S','C','F' }; | 
|---|
| 326 | BYTE hdr[SIP_MAX_MAGIC_NUMBER]; | 
|---|
| 327 | WCHAR szFullKey[ 0x100 ]; | 
|---|
| 328 | LONG r = ERROR_SUCCESS; | 
|---|
| 329 | HKEY key; | 
|---|
| 330 |  | 
|---|
| 331 | TRACE("(%s %p %p)\n", FileName, hFileIn, pgSubject); | 
|---|
| 332 |  | 
|---|
| 333 | if (!pgSubject || (!FileName && !hFileIn)) | 
|---|
| 334 | { | 
|---|
| 335 | SetLastError(ERROR_INVALID_PARAMETER); | 
|---|
| 336 | return FALSE; | 
|---|
| 337 | } | 
|---|
| 338 |  | 
|---|
| 339 | /* Set pgSubject to zero's */ | 
|---|
| 340 | memset(pgSubject, 0 , sizeof(GUID)); | 
|---|
| 341 |  | 
|---|
| 342 | if (hFileIn) | 
|---|
| 343 | /* Use the given handle, make sure not to close this one ourselves */ | 
|---|
| 344 | hFile = hFileIn; | 
|---|
| 345 | else | 
|---|
| 346 | { | 
|---|
| 347 | hFile = CreateFileW(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | 
|---|
| 348 | /* Last error is set by CreateFile */ | 
|---|
| 349 | if (hFile == INVALID_HANDLE_VALUE) return FALSE; | 
|---|
| 350 | } | 
|---|
| 351 |  | 
|---|
| 352 | zero.QuadPart = 0; | 
|---|
| 353 | SetFilePointerEx(hFile, zero, &oldPos, FILE_CURRENT); | 
|---|
| 354 | SetFilePointer(hFile, 0, NULL, FILE_BEGIN); | 
|---|
| 355 | if (!ReadFile(hFile, hdr, sizeof(hdr), &count, NULL)) | 
|---|
| 356 | goto cleanup; | 
|---|
| 357 |  | 
|---|
| 358 | if (count < SIP_MAX_MAGIC_NUMBER) | 
|---|
| 359 | { | 
|---|
| 360 | SetLastError(ERROR_INVALID_PARAMETER); | 
|---|
| 361 | goto cleanup; | 
|---|
| 362 | } | 
|---|
| 363 |  | 
|---|
| 364 | TRACE("file magic = 0x%02x%02x%02x%02x\n", hdr[0], hdr[1], hdr[2], hdr[3]); | 
|---|
| 365 | /* As everything is in place now we start looking at the file header */ | 
|---|
| 366 | if (!memcmp(hdr, &dosHdr, sizeof(dosHdr))) | 
|---|
| 367 | { | 
|---|
| 368 | *pgSubject = unknown; | 
|---|
| 369 | SetLastError(S_OK); | 
|---|
| 370 | bRet = TRUE; | 
|---|
| 371 | goto cleanup; | 
|---|
| 372 | } | 
|---|
| 373 | /* Quick-n-dirty check for a cab file. */ | 
|---|
| 374 | if (!memcmp(hdr, cabHdr, sizeof(cabHdr))) | 
|---|
| 375 | { | 
|---|
| 376 | *pgSubject = cabGUID; | 
|---|
| 377 | SetLastError(S_OK); | 
|---|
| 378 | bRet = TRUE; | 
|---|
| 379 | goto cleanup; | 
|---|
| 380 | } | 
|---|
| 381 | /* If it's asn.1-encoded, it's probably a .cat file. */ | 
|---|
| 382 | if (hdr[0] == 0x30) | 
|---|
| 383 | { | 
|---|
| 384 | DWORD fileLen = GetFileSize(hFile, NULL); | 
|---|
| 385 |  | 
|---|
| 386 | TRACE("fileLen = %d\n", fileLen); | 
|---|
| 387 | /* Sanity-check length */ | 
|---|
| 388 | if (hdr[1] < 0x80 && fileLen == 2 + hdr[1]) | 
|---|
| 389 | { | 
|---|
| 390 | *pgSubject = catGUID; | 
|---|
| 391 | SetLastError(S_OK); | 
|---|
| 392 | bRet = TRUE; | 
|---|
| 393 | goto cleanup; | 
|---|
| 394 | } | 
|---|
| 395 | else if (hdr[1] == 0x80) | 
|---|
| 396 | { | 
|---|
| 397 | /* Indefinite length, can't verify with just the header, assume it | 
|---|
| 398 | * is. | 
|---|
| 399 | */ | 
|---|
| 400 | *pgSubject = catGUID; | 
|---|
| 401 | SetLastError(S_OK); | 
|---|
| 402 | bRet = TRUE; | 
|---|
| 403 | goto cleanup; | 
|---|
| 404 | } | 
|---|
| 405 | else | 
|---|
| 406 | { | 
|---|
| 407 | BYTE lenBytes = hdr[1] & 0x7f; | 
|---|
| 408 |  | 
|---|
| 409 | if (lenBytes == 1 && fileLen == 2 + lenBytes + hdr[2]) | 
|---|
| 410 | { | 
|---|
| 411 | *pgSubject = catGUID; | 
|---|
| 412 | SetLastError(S_OK); | 
|---|
| 413 | bRet = TRUE; | 
|---|
| 414 | goto cleanup; | 
|---|
| 415 | } | 
|---|
| 416 | else if (lenBytes == 2 && fileLen == 2 + lenBytes + | 
|---|
| 417 | (hdr[2] << 8 | hdr[3])) | 
|---|
| 418 | { | 
|---|
| 419 | *pgSubject = catGUID; | 
|---|
| 420 | SetLastError(S_OK); | 
|---|
| 421 | bRet = TRUE; | 
|---|
| 422 | goto cleanup; | 
|---|
| 423 | } | 
|---|
| 424 | else if (fileLen > 0xffff) | 
|---|
| 425 | { | 
|---|
| 426 | /* The file size must be greater than 2 bytes in length, so | 
|---|
| 427 | * assume it is a .cat file | 
|---|
| 428 | */ | 
|---|
| 429 | *pgSubject = catGUID; | 
|---|
| 430 | SetLastError(S_OK); | 
|---|
| 431 | bRet = TRUE; | 
|---|
| 432 | goto cleanup; | 
|---|
| 433 | } | 
|---|
| 434 | } | 
|---|
| 435 | } | 
|---|
| 436 |  | 
|---|
| 437 | /* Check for supported functions using CryptSIPDllIsMyFileType */ | 
|---|
| 438 | /* max length of szFullKey depends on our code only, so we won't overrun */ | 
|---|
| 439 | lstrcpyW(szFullKey, szOID); | 
|---|
| 440 | lstrcatW(szFullKey, szIsMyFile); | 
|---|
| 441 | r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &key); | 
|---|
| 442 | if (r == ERROR_SUCCESS) | 
|---|
| 443 | { | 
|---|
| 444 | DWORD index = 0, size; | 
|---|
| 445 | WCHAR subKeyName[MAX_PATH]; | 
|---|
| 446 |  | 
|---|
| 447 | do { | 
|---|
| 448 | size = sizeof(subKeyName) / sizeof(subKeyName[0]); | 
|---|
| 449 | r = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, | 
|---|
| 450 | NULL, NULL); | 
|---|
| 451 | if (r == ERROR_SUCCESS) | 
|---|
| 452 | { | 
|---|
| 453 | HKEY subKey; | 
|---|
| 454 |  | 
|---|
| 455 | r = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); | 
|---|
| 456 | if (r == ERROR_SUCCESS) | 
|---|
| 457 | { | 
|---|
| 458 | HMODULE lib; | 
|---|
| 459 | pfnIsFileSupported isMy = | 
|---|
| 460 | (pfnIsFileSupported)CRYPT_LoadSIPFuncFromKey(subKey, &lib); | 
|---|
| 461 |  | 
|---|
| 462 | if (isMy) | 
|---|
| 463 | { | 
|---|
| 464 | bRet = isMy(hFile, pgSubject); | 
|---|
| 465 | FreeLibrary(lib); | 
|---|
| 466 | } | 
|---|
| 467 | RegCloseKey(subKey); | 
|---|
| 468 | } | 
|---|
| 469 | } | 
|---|
| 470 | } while (!bRet && r == ERROR_SUCCESS); | 
|---|
| 471 | RegCloseKey(key); | 
|---|
| 472 | } | 
|---|
| 473 |  | 
|---|
| 474 | /* Check for supported functions using CryptSIPDllIsMyFileType2 */ | 
|---|
| 475 | if (!bRet) | 
|---|
| 476 | { | 
|---|
| 477 | lstrcpyW(szFullKey, szOID); | 
|---|
| 478 | lstrcatW(szFullKey, szIsMyFile2); | 
|---|
| 479 | r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, &key); | 
|---|
| 480 | if (r == ERROR_SUCCESS) | 
|---|
| 481 | { | 
|---|
| 482 | DWORD index = 0, size; | 
|---|
| 483 | WCHAR subKeyName[MAX_PATH]; | 
|---|
| 484 |  | 
|---|
| 485 | do { | 
|---|
| 486 | size = sizeof(subKeyName) / sizeof(subKeyName[0]); | 
|---|
| 487 | r = RegEnumKeyExW(key, index++, subKeyName, &size, NULL, NULL, | 
|---|
| 488 | NULL, NULL); | 
|---|
| 489 | if (r == ERROR_SUCCESS) | 
|---|
| 490 | { | 
|---|
| 491 | HKEY subKey; | 
|---|
| 492 |  | 
|---|
| 493 | r = RegOpenKeyExW(key, subKeyName, 0, KEY_READ, &subKey); | 
|---|
| 494 | if (r == ERROR_SUCCESS) | 
|---|
| 495 | { | 
|---|
| 496 | HMODULE lib; | 
|---|
| 497 | pfnIsFileSupportedName isMy2 = (pfnIsFileSupportedName) | 
|---|
| 498 | CRYPT_LoadSIPFuncFromKey(subKey, &lib); | 
|---|
| 499 |  | 
|---|
| 500 | if (isMy2) | 
|---|
| 501 | { | 
|---|
| 502 | bRet = isMy2((LPWSTR)FileName, pgSubject); | 
|---|
| 503 | FreeLibrary(lib); | 
|---|
| 504 | } | 
|---|
| 505 | RegCloseKey(subKey); | 
|---|
| 506 | } | 
|---|
| 507 | } | 
|---|
| 508 | } while (!bRet && r == ERROR_SUCCESS); | 
|---|
| 509 | RegCloseKey(key); | 
|---|
| 510 | } | 
|---|
| 511 | } | 
|---|
| 512 |  | 
|---|
| 513 | if (!bRet) | 
|---|
| 514 | SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN); | 
|---|
| 515 |  | 
|---|
| 516 | cleanup: | 
|---|
| 517 | /* If we didn't open this one we shouldn't close it (hFile is a copy), | 
|---|
| 518 | * but we should reset the file pointer to its original position. | 
|---|
| 519 | */ | 
|---|
| 520 | if (!hFileIn) | 
|---|
| 521 | CloseHandle(hFile); | 
|---|
| 522 | else | 
|---|
| 523 | SetFilePointerEx(hFile, oldPos, NULL, FILE_BEGIN); | 
|---|
| 524 |  | 
|---|
| 525 | return bRet; | 
|---|
| 526 | } | 
|---|
| 527 |  | 
|---|
| 528 | static LONG CRYPT_OpenSIPFunctionKey(const GUID *guid, LPCWSTR function, | 
|---|
| 529 | HKEY *key) | 
|---|
| 530 | { | 
|---|
| 531 | WCHAR szFullKey[ 0x100 ]; | 
|---|
| 532 |  | 
|---|
| 533 | lstrcpyW(szFullKey, szOID); | 
|---|
| 534 | lstrcatW(szFullKey, function); | 
|---|
| 535 | CRYPT_guid2wstr(guid, &szFullKey[lstrlenW(szFullKey)]); | 
|---|
| 536 | return RegOpenKeyExW(HKEY_LOCAL_MACHINE, szFullKey, 0, KEY_READ, key); | 
|---|
| 537 | } | 
|---|
| 538 |  | 
|---|
| 539 | /* Loads the function named function for the SIP specified by pgSubject, and | 
|---|
| 540 | * returns it if found.  Returns NULL on error.  If the function is loaded, | 
|---|
| 541 | * *pLib is set to the library in which it is found. | 
|---|
| 542 | */ | 
|---|
| 543 | static void *CRYPT_LoadSIPFunc(const GUID *pgSubject, LPCWSTR function, | 
|---|
| 544 | HMODULE *pLib) | 
|---|
| 545 | { | 
|---|
| 546 | LONG r; | 
|---|
| 547 | HKEY key; | 
|---|
| 548 | void *func = NULL; | 
|---|
| 549 |  | 
|---|
| 550 | TRACE("(%s, %s)\n", debugstr_guid(pgSubject), debugstr_w(function)); | 
|---|
| 551 |  | 
|---|
| 552 | r = CRYPT_OpenSIPFunctionKey(pgSubject, function, &key); | 
|---|
| 553 | if (!r) | 
|---|
| 554 | { | 
|---|
| 555 | func = CRYPT_LoadSIPFuncFromKey(key, pLib); | 
|---|
| 556 | RegCloseKey(key); | 
|---|
| 557 | } | 
|---|
| 558 | TRACE("returning %p\n", func); | 
|---|
| 559 | return func; | 
|---|
| 560 | } | 
|---|
| 561 |  | 
|---|
| 562 | typedef struct _WINE_SIP_PROVIDER { | 
|---|
| 563 | GUID              subject; | 
|---|
| 564 | SIP_DISPATCH_INFO info; | 
|---|
| 565 | struct list       entry; | 
|---|
| 566 | } WINE_SIP_PROVIDER; | 
|---|
| 567 |  | 
|---|
| 568 | static struct list providers = { &providers, &providers }; | 
|---|
| 569 | static RTL_CRITICAL_SECTION providers_cs; | 
|---|
| 570 | static RTL_CRITICAL_SECTION_DEBUG providers_cs_debug = | 
|---|
| 571 | { | 
|---|
| 572 | 0, 0, &providers_cs, | 
|---|
| 573 | { &providers_cs_debug.ProcessLocksList, | 
|---|
| 574 | &providers_cs_debug.ProcessLocksList }, | 
|---|
| 575 | 0, 0, { (DWORD)(DWORD_PTR)(__FILE__ ": providers_cs") } | 
|---|
| 576 | }; | 
|---|
| 577 | static RTL_CRITICAL_SECTION providers_cs = { &providers_cs_debug, -1, 0, 0, 0, 0 }; | 
|---|
| 578 |  | 
|---|
| 579 | static void CRYPT_CacheSIP(const GUID *pgSubject, SIP_DISPATCH_INFO *info) | 
|---|
| 580 | { | 
|---|
| 581 | WINE_SIP_PROVIDER *prov = CryptMemAlloc(sizeof(WINE_SIP_PROVIDER)); | 
|---|
| 582 |  | 
|---|
| 583 | if (prov) | 
|---|
| 584 | { | 
|---|
| 585 | prov->subject = *pgSubject; | 
|---|
| 586 | prov->info = *info; | 
|---|
| 587 | EnterCriticalSection((CRITICAL_SECTION*)&providers_cs); | 
|---|
| 588 | list_add_tail(&providers, &prov->entry); | 
|---|
| 589 | LeaveCriticalSection((CRITICAL_SECTION*)&providers_cs); | 
|---|
| 590 | } | 
|---|
| 591 | } | 
|---|
| 592 |  | 
|---|
| 593 | static WINE_SIP_PROVIDER *CRYPT_GetCachedSIP(const GUID *pgSubject) | 
|---|
| 594 | { | 
|---|
| 595 | WINE_SIP_PROVIDER *provider = NULL, *ret = NULL; | 
|---|
| 596 |  | 
|---|
| 597 | EnterCriticalSection((CRITICAL_SECTION*)&providers_cs); | 
|---|
| 598 | LIST_FOR_EACH_ENTRY(provider, &providers, WINE_SIP_PROVIDER, entry) | 
|---|
| 599 | { | 
|---|
| 600 | if (IsEqualGUID(pgSubject, &provider->subject)) | 
|---|
| 601 | break; | 
|---|
| 602 | } | 
|---|
| 603 | if (provider && IsEqualGUID(pgSubject, &provider->subject)) | 
|---|
| 604 | ret = provider; | 
|---|
| 605 | LeaveCriticalSection((CRITICAL_SECTION*)&providers_cs); | 
|---|
| 606 | return ret; | 
|---|
| 607 | } | 
|---|
| 608 |  | 
|---|
| 609 | static inline BOOL CRYPT_IsSIPCached(const GUID *pgSubject) | 
|---|
| 610 | { | 
|---|
| 611 | return CRYPT_GetCachedSIP(pgSubject) != NULL; | 
|---|
| 612 | } | 
|---|
| 613 |  | 
|---|
| 614 | void crypt_sip_free(void) | 
|---|
| 615 | { | 
|---|
| 616 | WINE_SIP_PROVIDER *prov, *next; | 
|---|
| 617 |  | 
|---|
| 618 | LIST_FOR_EACH_ENTRY_SAFE(prov, next, &providers, WINE_SIP_PROVIDER, entry) | 
|---|
| 619 | { | 
|---|
| 620 | list_remove(&prov->entry); | 
|---|
| 621 | FreeLibrary(prov->info.hSIP); | 
|---|
| 622 | CryptMemFree(prov); | 
|---|
| 623 | } | 
|---|
| 624 | } | 
|---|
| 625 |  | 
|---|
| 626 | /* Loads the SIP for pgSubject into the global cache.  Returns FALSE if the | 
|---|
| 627 | * SIP isn't registered or is invalid. | 
|---|
| 628 | */ | 
|---|
| 629 | static BOOL CRYPT_LoadSIP(const GUID *pgSubject) | 
|---|
| 630 | { | 
|---|
| 631 | SIP_DISPATCH_INFO sip = { 0 }; | 
|---|
| 632 | HMODULE lib = NULL, temp = NULL; | 
|---|
| 633 |  | 
|---|
| 634 | sip.pfGet = (pCryptSIPGetSignedDataMsg)CRYPT_LoadSIPFunc(pgSubject, szGetSigned, &lib); | 
|---|
| 635 | if (!sip.pfGet) | 
|---|
| 636 | goto error; | 
|---|
| 637 | sip.pfPut = (pCryptSIPPutSignedDataMsg)CRYPT_LoadSIPFunc(pgSubject, szPutSigned, &temp); | 
|---|
| 638 | if (!sip.pfPut || temp != lib) | 
|---|
| 639 | goto error; | 
|---|
| 640 | FreeLibrary(temp); | 
|---|
| 641 | sip.pfCreate = (pCryptSIPCreateIndirectData)CRYPT_LoadSIPFunc(pgSubject, szCreate, &temp); | 
|---|
| 642 | if (!sip.pfCreate || temp != lib) | 
|---|
| 643 | goto error; | 
|---|
| 644 | FreeLibrary(temp); | 
|---|
| 645 | sip.pfVerify = (pCryptSIPVerifyIndirectData)CRYPT_LoadSIPFunc(pgSubject, szVerify, &temp); | 
|---|
| 646 | if (!sip.pfVerify || temp != lib) | 
|---|
| 647 | goto error; | 
|---|
| 648 | FreeLibrary(temp); | 
|---|
| 649 | sip.pfRemove = (pCryptSIPRemoveSignedDataMsg)CRYPT_LoadSIPFunc(pgSubject, szRemoveSigned, &temp); | 
|---|
| 650 | if (!sip.pfRemove || temp != lib) | 
|---|
| 651 | goto error; | 
|---|
| 652 | FreeLibrary(temp); | 
|---|
| 653 | sip.hSIP = lib; | 
|---|
| 654 | CRYPT_CacheSIP(pgSubject, &sip); | 
|---|
| 655 | return TRUE; | 
|---|
| 656 |  | 
|---|
| 657 | error: | 
|---|
| 658 | FreeLibrary(lib); | 
|---|
| 659 | FreeLibrary(temp); | 
|---|
| 660 | SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN); | 
|---|
| 661 | return FALSE; | 
|---|
| 662 | } | 
|---|
| 663 |  | 
|---|
| 664 | /*********************************************************************** | 
|---|
| 665 | *             CryptSIPLoad (CRYPT32.@) | 
|---|
| 666 | * | 
|---|
| 667 | * Load some internal crypt32 functions into a SIP_DISPATCH_INFO structure. | 
|---|
| 668 | * | 
|---|
| 669 | * PARAMS | 
|---|
| 670 | *  pgSubject    [I] The GUID. | 
|---|
| 671 | *  dwFlags      [I] Flags. | 
|---|
| 672 | *  pSipDispatch [I] The loaded functions. | 
|---|
| 673 | * | 
|---|
| 674 | * RETURNS | 
|---|
| 675 | *  Success: TRUE. pSipDispatch contains the functions. | 
|---|
| 676 | *  Failure: FALSE. (Look at GetLastError()). | 
|---|
| 677 | * | 
|---|
| 678 | * NOTES | 
|---|
| 679 | *  CryptSIPLoad uses caching for the list of GUIDs and whether a SIP is | 
|---|
| 680 | *  already loaded. | 
|---|
| 681 | * | 
|---|
| 682 | *  An application calls CryptSipLoad which will return a structure with the | 
|---|
| 683 | *  function addresses of some internal crypt32 functions. The application will | 
|---|
| 684 | *  then call these functions which will be forwarded to the appropriate SIP. | 
|---|
| 685 | * | 
|---|
| 686 | *  CryptSIPLoad will load the needed SIP but doesn't unload this dll. The unloading | 
|---|
| 687 | *  is done when crypt32 is unloaded. | 
|---|
| 688 | */ | 
|---|
| 689 | BOOL WINAPI CryptSIPLoad | 
|---|
| 690 | (const GUID *pgSubject, DWORD dwFlags, SIP_DISPATCH_INFO *pSipDispatch) | 
|---|
| 691 | { | 
|---|
| 692 | TRACE("(%s %d %p)\n", debugstr_guid(pgSubject), dwFlags, pSipDispatch); | 
|---|
| 693 |  | 
|---|
| 694 | if (!pgSubject || dwFlags != 0 || !pSipDispatch) | 
|---|
| 695 | { | 
|---|
| 696 | SetLastError(ERROR_INVALID_PARAMETER); | 
|---|
| 697 | return FALSE; | 
|---|
| 698 | } | 
|---|
| 699 | if (!CRYPT_IsSIPCached(pgSubject) && !CRYPT_LoadSIP(pgSubject)) | 
|---|
| 700 | return FALSE; | 
|---|
| 701 |  | 
|---|
| 702 | pSipDispatch->hSIP = NULL; | 
|---|
| 703 | pSipDispatch->pfGet = CryptSIPGetSignedDataMsg; | 
|---|
| 704 | pSipDispatch->pfPut = CryptSIPPutSignedDataMsg; | 
|---|
| 705 | pSipDispatch->pfCreate = CryptSIPCreateIndirectData; | 
|---|
| 706 | pSipDispatch->pfVerify = CryptSIPVerifyIndirectData; | 
|---|
| 707 | pSipDispatch->pfRemove = CryptSIPRemoveSignedDataMsg; | 
|---|
| 708 |  | 
|---|
| 709 | return TRUE; | 
|---|
| 710 | } | 
|---|
| 711 |  | 
|---|
| 712 | /*********************************************************************** | 
|---|
| 713 | *             CryptSIPCreateIndirectData (CRYPT32.@) | 
|---|
| 714 | */ | 
|---|
| 715 | BOOL WINAPI CryptSIPCreateIndirectData(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pcbIndirectData, | 
|---|
| 716 | SIP_INDIRECT_DATA* pIndirectData) | 
|---|
| 717 | { | 
|---|
| 718 | WINE_SIP_PROVIDER *sip; | 
|---|
| 719 | BOOL ret = FALSE; | 
|---|
| 720 |  | 
|---|
| 721 | TRACE("(%p %p %p)\n", pSubjectInfo, pcbIndirectData, pIndirectData); | 
|---|
| 722 |  | 
|---|
| 723 | if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType)) != NULL) | 
|---|
| 724 | ret = sip->info.pfCreate(pSubjectInfo, pcbIndirectData, pIndirectData); | 
|---|
| 725 | TRACE("returning %d\n", ret); | 
|---|
| 726 | return ret; | 
|---|
| 727 | } | 
|---|
| 728 |  | 
|---|
| 729 | /*********************************************************************** | 
|---|
| 730 | *             CryptSIPGetSignedDataMsg (CRYPT32.@) | 
|---|
| 731 | */ | 
|---|
| 732 | BOOL WINAPI CryptSIPGetSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD* pdwEncodingType, | 
|---|
| 733 | DWORD dwIndex, DWORD* pcbSignedDataMsg, BYTE* pbSignedDataMsg) | 
|---|
| 734 | { | 
|---|
| 735 | WINE_SIP_PROVIDER *sip; | 
|---|
| 736 | BOOL ret = FALSE; | 
|---|
| 737 |  | 
|---|
| 738 | TRACE("(%p %p %d %p %p)\n", pSubjectInfo, pdwEncodingType, dwIndex, | 
|---|
| 739 | pcbSignedDataMsg, pbSignedDataMsg); | 
|---|
| 740 |  | 
|---|
| 741 | if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType)) != NULL) | 
|---|
| 742 | ret = sip->info.pfGet(pSubjectInfo, pdwEncodingType, dwIndex, | 
|---|
| 743 | pcbSignedDataMsg, pbSignedDataMsg); | 
|---|
| 744 | TRACE("returning %d\n", ret); | 
|---|
| 745 | return ret; | 
|---|
| 746 | } | 
|---|
| 747 |  | 
|---|
| 748 | /*********************************************************************** | 
|---|
| 749 | *             CryptSIPPutSignedDataMsg (CRYPT32.@) | 
|---|
| 750 | */ | 
|---|
| 751 | BOOL WINAPI CryptSIPPutSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, DWORD pdwEncodingType, | 
|---|
| 752 | DWORD* pdwIndex, DWORD cbSignedDataMsg, BYTE* pbSignedDataMsg) | 
|---|
| 753 | { | 
|---|
| 754 | WINE_SIP_PROVIDER *sip; | 
|---|
| 755 | BOOL ret = FALSE; | 
|---|
| 756 |  | 
|---|
| 757 | TRACE("(%p %d %p %d %p)\n", pSubjectInfo, pdwEncodingType, pdwIndex, | 
|---|
| 758 | cbSignedDataMsg, pbSignedDataMsg); | 
|---|
| 759 |  | 
|---|
| 760 | if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType)) != NULL) | 
|---|
| 761 | ret = sip->info.pfPut(pSubjectInfo, pdwEncodingType, pdwIndex, | 
|---|
| 762 | cbSignedDataMsg, pbSignedDataMsg); | 
|---|
| 763 | TRACE("returning %d\n", ret); | 
|---|
| 764 | return ret; | 
|---|
| 765 | } | 
|---|
| 766 |  | 
|---|
| 767 | /*********************************************************************** | 
|---|
| 768 | *             CryptSIPRemoveSignedDataMsg (CRYPT32.@) | 
|---|
| 769 | */ | 
|---|
| 770 | BOOL WINAPI CryptSIPRemoveSignedDataMsg(SIP_SUBJECTINFO* pSubjectInfo, | 
|---|
| 771 | DWORD dwIndex) | 
|---|
| 772 | { | 
|---|
| 773 | WINE_SIP_PROVIDER *sip; | 
|---|
| 774 | BOOL ret = FALSE; | 
|---|
| 775 |  | 
|---|
| 776 | TRACE("(%p %d)\n", pSubjectInfo, dwIndex); | 
|---|
| 777 |  | 
|---|
| 778 | if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType)) != NULL) | 
|---|
| 779 | ret = sip->info.pfRemove(pSubjectInfo, dwIndex); | 
|---|
| 780 | TRACE("returning %d\n", ret); | 
|---|
| 781 | return ret; | 
|---|
| 782 | } | 
|---|
| 783 |  | 
|---|
| 784 | /*********************************************************************** | 
|---|
| 785 | *             CryptSIPVerifyIndirectData (CRYPT32.@) | 
|---|
| 786 | */ | 
|---|
| 787 | BOOL WINAPI CryptSIPVerifyIndirectData(SIP_SUBJECTINFO* pSubjectInfo, | 
|---|
| 788 | SIP_INDIRECT_DATA* pIndirectData) | 
|---|
| 789 | { | 
|---|
| 790 | WINE_SIP_PROVIDER *sip; | 
|---|
| 791 | BOOL ret = FALSE; | 
|---|
| 792 |  | 
|---|
| 793 | TRACE("(%p %p)\n", pSubjectInfo, pIndirectData); | 
|---|
| 794 |  | 
|---|
| 795 | if ((sip = CRYPT_GetCachedSIP(pSubjectInfo->pgSubjectType)) != NULL) | 
|---|
| 796 | ret = sip->info.pfVerify(pSubjectInfo, pIndirectData); | 
|---|
| 797 | TRACE("returning %d\n", ret); | 
|---|
| 798 | return ret; | 
|---|
| 799 | } | 
|---|