wintrust: Use a helper function to get a signer's cert info from a message.
[wine] / dlls / wintrust / softpub.c
1 /*
2  * Copyright 2007 Juan Lang
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wintrust.h"
22 #include "mssip.h"
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
26
27 HRESULT WINAPI SoftpubInitialize(CRYPT_PROVIDER_DATA *data)
28 {
29     HRESULT ret = S_FALSE;
30
31     TRACE("(%p)\n", data);
32
33     if (data->padwTrustStepErrors &&
34      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
35         ret = S_OK;
36     TRACE("returning %08x\n", ret);
37     return ret;
38 }
39
40 /* Assumes data->pWintrustData->pFile exists.  Makes sure a file handle is
41  * open for the file.
42  */
43 static BOOL SOFTPUB_OpenFile(CRYPT_PROVIDER_DATA *data)
44 {
45     BOOL ret = TRUE;
46
47     /* PSDK implies that all values should be initialized to NULL, so callers
48      * typically have hFile as NULL rather than INVALID_HANDLE_VALUE.  Check
49      * for both.
50      */
51     if (!data->pWintrustData->pFile->hFile ||
52      data->pWintrustData->pFile->hFile == INVALID_HANDLE_VALUE)
53     {
54         data->pWintrustData->pFile->hFile =
55          CreateFileW(data->pWintrustData->pFile->pcwszFilePath, GENERIC_READ,
56           FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
57         if (data->pWintrustData->pFile->hFile != INVALID_HANDLE_VALUE)
58             data->fOpenedFile = TRUE;
59         else
60             ret = FALSE;
61     }
62     TRACE("returning %d\n", ret);
63     return ret;
64 }
65
66 /* Assumes data->pWintrustData->pFile exists.  Sets data->pPDSip->gSubject to
67  * the file's subject GUID.
68  */
69 static BOOL SOFTPUB_GetFileSubject(CRYPT_PROVIDER_DATA *data)
70 {
71     BOOL ret;
72
73     if (!data->pWintrustData->pFile->pgKnownSubject)
74     {
75         ret = CryptSIPRetrieveSubjectGuid(
76          data->pWintrustData->pFile->pcwszFilePath,
77          data->pWintrustData->pFile->hFile,
78          &data->pPDSip->gSubject);
79     }
80     else
81     {
82         memcpy(&data->pPDSip->gSubject,
83          data->pWintrustData->pFile->pgKnownSubject, sizeof(GUID));
84         ret = TRUE;
85     }
86     TRACE("returning %d\n", ret);
87     return ret;
88 }
89
90 /* Assumes data->pPDSip exists, and its gSubject member set.
91  * Allocates data->pPDSip->pSip and loads it, if possible.
92  */
93 static BOOL SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA *data)
94 {
95     BOOL ret;
96
97     data->pPDSip->pSip = data->psPfns->pfnAlloc(sizeof(SIP_DISPATCH_INFO));
98     if (data->pPDSip->pSip)
99         ret = CryptSIPLoad(&data->pPDSip->gSubject, 0, data->pPDSip->pSip);
100     else
101     {
102         SetLastError(ERROR_OUTOFMEMORY);
103         ret = FALSE;
104     }
105     TRACE("returning %d\n", ret);
106     return ret;
107 }
108
109 /* Assumes data->pPDSip has been loaded, and data->pPDSip->pSip allocated.
110  * Calls data->pPDSip->pSip->pfGet to construct data->hMsg.
111  */
112 static BOOL SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data)
113 {
114     BOOL ret;
115     LPBYTE buf = NULL;
116     DWORD size = 0;
117
118     data->pPDSip->psSipSubjectInfo =
119      data->psPfns->pfnAlloc(sizeof(SIP_SUBJECTINFO));
120     if (!data->pPDSip->psSipSubjectInfo)
121     {
122         SetLastError(ERROR_OUTOFMEMORY);
123         return FALSE;
124     }
125
126     data->pPDSip->psSipSubjectInfo->cbSize = sizeof(SIP_SUBJECTINFO);
127     data->pPDSip->psSipSubjectInfo->pgSubjectType = &data->pPDSip->gSubject;
128     data->pPDSip->psSipSubjectInfo->hFile = data->pWintrustData->pFile->hFile;
129     data->pPDSip->psSipSubjectInfo->pwsFileName =
130      data->pWintrustData->pFile->pcwszFilePath;
131     data->pPDSip->psSipSubjectInfo->hProv = data->hProv;
132     ret = data->pPDSip->pSip->pfGet(data->pPDSip->psSipSubjectInfo,
133      &data->dwEncoding, 0, &size, 0);
134     if (!ret)
135     {
136         SetLastError(TRUST_E_NOSIGNATURE);
137         return FALSE;
138     }
139
140     buf = data->psPfns->pfnAlloc(size);
141     if (!buf)
142     {
143         SetLastError(ERROR_OUTOFMEMORY);
144         return FALSE;
145     }
146
147     ret = data->pPDSip->pSip->pfGet(data->pPDSip->psSipSubjectInfo,
148      &data->dwEncoding, 0, &size, buf);
149     if (ret)
150     {
151         data->hMsg = CryptMsgOpenToDecode(data->dwEncoding, 0, 0, data->hProv,
152          NULL, NULL);
153         if (data->hMsg)
154             ret = CryptMsgUpdate(data->hMsg, buf, size, TRUE);
155     }
156
157     data->psPfns->pfnFree(buf);
158     TRACE("returning %d\n", ret);
159     return ret;
160 }
161
162 static BOOL SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data)
163 {
164     BOOL ret = FALSE;
165     HCERTSTORE store;
166
167     store = CertOpenStore(CERT_STORE_PROV_MSG, data->dwEncoding,
168      data->hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, data->hMsg);
169     if (store)
170     {
171         ret = data->psPfns->pfnAddStore2Chain(data, store);
172         CertCloseStore(store, 0);
173     }
174     TRACE("returning %d\n", ret);
175     return ret;
176 }
177
178 static DWORD SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA *data)
179 {
180     BOOL ret;
181     DWORD size;
182     LPBYTE buf = NULL;
183
184     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL,
185      &size);
186     if (!ret)
187         goto error;
188     buf = data->psPfns->pfnAlloc(size);
189     if (!buf)
190     {
191         SetLastError(ERROR_OUTOFMEMORY);
192         ret = FALSE;
193         goto error;
194     }
195     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, buf,
196      &size);
197     if (!ret)
198         goto error;
199     if (!strcmp((LPCSTR)buf, SPC_INDIRECT_DATA_OBJID))
200     {
201         data->psPfns->pfnFree(buf);
202         buf = NULL;
203         ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, NULL, &size);
204         if (!ret)
205             goto error;
206         buf = data->psPfns->pfnAlloc(size);
207         if (!buf)
208         {
209             SetLastError(ERROR_OUTOFMEMORY);
210             ret = FALSE;
211             goto error;
212         }
213         ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, buf, &size);
214         if (!ret)
215             goto error;
216         ret = CryptDecodeObject(data->dwEncoding,
217          SPC_INDIRECT_DATA_CONTENT_STRUCT, buf, size, 0, NULL, &size);
218         if (!ret)
219             goto error;
220         data->pPDSip->psIndirectData = data->psPfns->pfnAlloc(size);
221         if (!data->pPDSip->psIndirectData)
222         {
223             SetLastError(ERROR_OUTOFMEMORY);
224             ret = FALSE;
225             goto error;
226         }
227         ret = CryptDecodeObject(data->dwEncoding,
228          SPC_INDIRECT_DATA_CONTENT_STRUCT, buf, size, 0,
229          data->pPDSip->psIndirectData, &size);
230     }
231     else
232     {
233         FIXME("unimplemented for OID %s\n", (LPCSTR)buf);
234         SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN);
235         ret = FALSE;
236     }
237
238 error:
239     TRACE("returning %d\n", ret);
240     return ret;
241 }
242
243 HRESULT WINAPI SoftpubLoadMessage(CRYPT_PROVIDER_DATA *data)
244 {
245     BOOL ret;
246
247     TRACE("(%p)\n", data);
248
249     if (!data->padwTrustStepErrors)
250         return S_FALSE;
251
252     switch (data->pWintrustData->dwUnionChoice)
253     {
254     case WTD_CHOICE_CERT:
255         /* Do nothing!?  See the tests */
256         ret = TRUE;
257         break;
258     case WTD_CHOICE_FILE:
259         if (!data->pWintrustData->pFile)
260         {
261             SetLastError(ERROR_INVALID_PARAMETER);
262             ret = FALSE;
263             goto error;
264         }
265         ret = SOFTPUB_OpenFile(data);
266         if (!ret)
267             goto error;
268         ret = SOFTPUB_GetFileSubject(data);
269         if (!ret)
270             goto error;
271         ret = SOFTPUB_GetSIP(data);
272         if (!ret)
273             goto error;
274         ret = SOFTPUB_GetMessageFromFile(data);
275         if (!ret)
276             goto error;
277         ret = SOFTPUB_CreateStoreFromMessage(data);
278         if (!ret)
279             goto error;
280         ret = SOFTPUB_DecodeInnerContent(data);
281         break;
282     default:
283         FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice);
284         SetLastError(ERROR_INVALID_PARAMETER);
285         ret = FALSE;
286     }
287
288 error:
289     if (!ret)
290         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
291          GetLastError();
292     return ret ? S_OK : S_FALSE;
293 }
294
295 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data,
296  DWORD signerIdx)
297 {
298     BOOL ret;
299     CERT_INFO *certInfo = NULL;
300     DWORD size;
301
302     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx,
303      NULL, &size);
304     if (ret)
305     {
306         certInfo = data->psPfns->pfnAlloc(size);
307         if (certInfo)
308         {
309             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM,
310              signerIdx, certInfo, &size);
311             if (!ret)
312             {
313                 data->psPfns->pfnFree(certInfo);
314                 certInfo = NULL;
315             }
316         }
317         else
318             SetLastError(ERROR_OUTOFMEMORY);
319     }
320     return certInfo;
321 }
322
323 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
324 {
325     BOOL ret;
326     DWORD signerCount, size;
327
328     TRACE("(%p)\n", data);
329
330     if (!data->padwTrustStepErrors)
331         return S_FALSE;
332
333     size = sizeof(signerCount);
334     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0,
335      &signerCount, &size);
336     if (ret)
337     {
338         DWORD i;
339
340         for (i = 0; ret && i < signerCount; i++)
341         {
342             CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, i);
343
344             if (certInfo)
345             {
346                 CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0, i,
347                  CMSG_VERIFY_SIGNER_CERT, NULL };
348
349                 para.pvSigner = (LPVOID)CertGetSubjectCertificateFromStore(
350                  data->pahStores[0], data->dwEncoding, certInfo);
351                 if (para.pvSigner)
352                 {
353                     ret = CryptMsgControl(data->hMsg, 0,
354                      CMSG_CTRL_VERIFY_SIGNATURE_EX, &para);
355                     if (!ret)
356                         SetLastError(TRUST_E_CERT_SIGNATURE);
357                 }
358                 else
359                 {
360                     SetLastError(TRUST_E_NO_SIGNER_CERT);
361                     ret = FALSE;
362                 }
363                 data->psPfns->pfnFree(certInfo);
364             }
365             else
366                 ret = FALSE;
367         }
368     }
369     else
370         SetLastError(TRUST_E_NOSIGNATURE);
371     if (!ret)
372         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
373          GetLastError();
374     return ret ? S_OK : S_FALSE;
375 }