shdocvw: Constify some variables.
[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 CMSG_SIGNER_INFO *WINTRUST_GetSigner(CRYPT_PROVIDER_DATA *data,
296  DWORD signerIdx)
297 {
298     BOOL ret;
299     CMSG_SIGNER_INFO *signerInfo = NULL;
300     DWORD size;
301
302     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, signerIdx,
303      NULL, &size);
304     if (ret)
305     {
306         signerInfo = data->psPfns->pfnAlloc(size);
307         if (signerInfo)
308         {
309             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM,
310              signerIdx, signerInfo, &size);
311             if (!ret)
312             {
313                 data->psPfns->pfnFree(signerInfo);
314                 signerInfo = NULL;
315             }
316         }
317         else
318             SetLastError(ERROR_OUTOFMEMORY);
319     }
320     return signerInfo;
321 }
322
323 static BOOL WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
324 {
325     BOOL ret;
326     CMSG_SIGNER_INFO *signerInfo = WINTRUST_GetSigner(data, signerIdx);
327
328     if (signerInfo)
329     {
330         CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
331
332         sgnr.psSigner = signerInfo;
333         ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, signerIdx, &sgnr);
334     }
335     else
336         ret = FALSE;
337     return ret;
338 }
339
340 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data,
341  DWORD signerIdx)
342 {
343     BOOL ret;
344     CERT_INFO *certInfo = NULL;
345     DWORD size;
346
347     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx,
348      NULL, &size);
349     if (ret)
350     {
351         certInfo = data->psPfns->pfnAlloc(size);
352         if (certInfo)
353         {
354             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM,
355              signerIdx, certInfo, &size);
356             if (!ret)
357             {
358                 data->psPfns->pfnFree(certInfo);
359                 certInfo = NULL;
360             }
361         }
362         else
363             SetLastError(ERROR_OUTOFMEMORY);
364     }
365     return certInfo;
366 }
367
368 static BOOL WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
369 {
370     BOOL ret;
371     CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, signerIdx);
372
373     if (certInfo)
374     {
375         CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0, signerIdx,
376          CMSG_VERIFY_SIGNER_CERT, NULL };
377
378         para.pvSigner = (LPVOID)CertGetSubjectCertificateFromStore(
379          data->pahStores[0], data->dwEncoding, certInfo);
380         if (para.pvSigner)
381         {
382             ret = CryptMsgControl(data->hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX,
383              &para);
384             if (!ret)
385                 SetLastError(TRUST_E_CERT_SIGNATURE);
386         }
387         else
388         {
389             SetLastError(TRUST_E_NO_SIGNER_CERT);
390             ret = FALSE;
391         }
392         data->psPfns->pfnFree(certInfo);
393     }
394     else
395         ret = FALSE;
396     return ret;
397 }
398
399 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
400 {
401     BOOL ret;
402     DWORD signerCount, size;
403
404     TRACE("(%p)\n", data);
405
406     if (!data->padwTrustStepErrors)
407         return S_FALSE;
408
409     size = sizeof(signerCount);
410     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0,
411      &signerCount, &size);
412     if (ret)
413     {
414         DWORD i;
415
416         for (i = 0; ret && i < signerCount; i++)
417         {
418             if ((ret = WINTRUST_SaveSigner(data, i)))
419                 ret = WINTRUST_VerifySigner(data, i);
420         }
421     }
422     else
423         SetLastError(TRUST_E_NOSIGNATURE);
424     if (!ret)
425         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
426          GetLastError();
427     return ret ? S_OK : S_FALSE;
428 }
429
430 BOOL WINAPI SoftpubCheckCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
431  BOOL fCounterSignerChain, DWORD idxCounterSigner)
432 {
433     BOOL ret;
434
435     TRACE("(%p, %d, %d, %d)\n", data, idxSigner, fCounterSignerChain,
436      idxCounterSigner);
437
438     if (fCounterSignerChain)
439     {
440         FIXME("unimplemented for counter signers\n");
441         ret = FALSE;
442     }
443     else
444     {
445         PCERT_SIMPLE_CHAIN simpleChain =
446          data->pasSigners[idxSigner].pChainContext->rgpChain[0];
447         DWORD i;
448
449         ret = TRUE;
450         for (i = 0; i < simpleChain->cElement; i++)
451         {
452             /* Set confidence */
453             data->pasSigners[idxSigner].pasCertChain[i].dwConfidence = 0;
454             /* The last element in the chain doesn't have an issuer, so it
455              * can't have a valid time (with respect to its issuer)
456              */
457             if (i != simpleChain->cElement - 1 &&
458              !(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
459              CERT_TRUST_IS_NOT_TIME_VALID))
460                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
461                  |= CERT_CONFIDENCE_TIME;
462             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
463              CERT_TRUST_IS_NOT_TIME_NESTED))
464                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
465                  |= CERT_CONFIDENCE_TIMENEST;
466             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
467              CERT_TRUST_IS_NOT_SIGNATURE_VALID))
468                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
469                  |= CERT_CONFIDENCE_SIG;
470             /* Set additional flags */
471             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
472              CERT_TRUST_IS_UNTRUSTED_ROOT))
473                 data->pasSigners[idxSigner].pasCertChain[i].fTrustedRoot = TRUE;
474             if (simpleChain->rgpElement[i]->TrustStatus.dwInfoStatus &
475              CERT_TRUST_IS_SELF_SIGNED)
476                 data->pasSigners[idxSigner].pasCertChain[i].fSelfSigned = TRUE;
477             if (simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
478              CERT_TRUST_IS_CYCLIC)
479                 data->pasSigners[idxSigner].pasCertChain[i].fIsCyclic = TRUE;
480         }
481     }
482     return ret;
483 }
484
485 static BOOL WINTRUST_CopyChain(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
486 {
487     BOOL ret;
488     PCERT_SIMPLE_CHAIN simpleChain =
489      data->pasSigners[signerIdx].pChainContext->rgpChain[0];
490     DWORD i;
491
492     data->pasSigners[signerIdx].pasCertChain[0].pChainElement =
493      simpleChain->rgpElement[0];
494     ret = TRUE;
495     for (i = 1; ret && i < simpleChain->cElement; i++)
496     {
497         ret = data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
498          simpleChain->rgpElement[i]->pCertContext);
499         if (ret)
500             data->pasSigners[signerIdx].pasCertChain[i].pChainElement =
501              simpleChain->rgpElement[i];
502     }
503     return ret;
504 }
505
506 HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *data)
507 {
508     BOOL ret;
509
510     if (!data->csSigners)
511     {
512         ret = FALSE;
513         SetLastError(TRUST_E_NOSIGNATURE);
514     }
515     else
516     {
517         DWORD i;
518
519         ret = TRUE;
520         for (i = 0; i < data->csSigners; i++)
521         {
522             CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
523             DWORD flags;
524
525             if (data->pRequestUsage)
526                 memcpy(&chainPara.RequestedUsage, data->pRequestUsage,
527                  sizeof(CERT_USAGE_MATCH));
528             if (data->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT)
529                 flags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
530             else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN)
531                 flags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
532             else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
533                 flags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
534             else
535                 flags = 0;
536             /* Expect the end certificate for each signer to be the only
537              * cert in the chain:
538              */
539             if (data->pasSigners[i].csCertChain)
540             {
541                 /* Create a certificate chain for each signer */
542                 ret = CertGetCertificateChain(NULL,
543                  data->pasSigners[i].pasCertChain[0].pCert,
544                  NULL, /* FIXME: use data->pasSigners[i].sftVerifyAsOf? */
545                  data->chStores ? data->pahStores[0] : NULL,
546                  &chainPara, flags, NULL, &data->pasSigners[i].pChainContext);
547                 if (ret)
548                 {
549                     if (data->pasSigners[i].pChainContext->cChain != 1)
550                     {
551                         FIXME("unimplemented for more than 1 simple chain\n");
552                         ret = FALSE;
553                     }
554                     else
555                     {
556                         if ((ret = WINTRUST_CopyChain(data, i)))
557                             ret = data->psPfns->pfnCertCheckPolicy(data, i,
558                              FALSE, 0);
559                     }
560                 }
561             }
562         }
563     }
564     if (!ret)
565         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
566          GetLastError();
567     return ret ? S_OK : S_FALSE;
568 }