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