wintrust: Fix compilation on systems that don't support nameless unions.
[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
20 #define NONAMELESSUNION
21
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wintrust.h"
25 #include "mssip.h"
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(wintrust);
29
30 HRESULT WINAPI SoftpubInitialize(CRYPT_PROVIDER_DATA *data)
31 {
32     HRESULT ret = S_FALSE;
33
34     TRACE("(%p)\n", data);
35
36     if (data->padwTrustStepErrors &&
37      !data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
38         ret = S_OK;
39     TRACE("returning %08x\n", ret);
40     return ret;
41 }
42
43 /* Assumes data->pWintrustData->u.pFile exists.  Makes sure a file handle is
44  * open for the file.
45  */
46 static BOOL SOFTPUB_OpenFile(CRYPT_PROVIDER_DATA *data)
47 {
48     BOOL ret = TRUE;
49
50     /* PSDK implies that all values should be initialized to NULL, so callers
51      * typically have hFile as NULL rather than INVALID_HANDLE_VALUE.  Check
52      * for both.
53      */
54     if (!data->pWintrustData->u.pFile->hFile ||
55      data->pWintrustData->u.pFile->hFile == INVALID_HANDLE_VALUE)
56     {
57         data->pWintrustData->u.pFile->hFile =
58             CreateFileW(data->pWintrustData->u.pFile->pcwszFilePath, GENERIC_READ,
59           FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
60         if (data->pWintrustData->u.pFile->hFile != INVALID_HANDLE_VALUE)
61             data->fOpenedFile = TRUE;
62         else
63             ret = FALSE;
64     }
65     TRACE("returning %d\n", ret);
66     return ret;
67 }
68
69 /* Assumes data->pWintrustData->u.pFile exists.  Sets data->pPDSip->gSubject to
70  * the file's subject GUID.
71  */
72 static BOOL SOFTPUB_GetFileSubject(CRYPT_PROVIDER_DATA *data)
73 {
74     BOOL ret;
75
76     if (!data->pWintrustData->u.pFile->pgKnownSubject)
77     {
78         ret = CryptSIPRetrieveSubjectGuid(
79          data->pWintrustData->u.pFile->pcwszFilePath,
80          data->pWintrustData->u.pFile->hFile,
81          &data->u.pPDSip->gSubject);
82     }
83     else
84     {
85         memcpy(&data->u.pPDSip->gSubject,
86          data->pWintrustData->u.pFile->pgKnownSubject, sizeof(GUID));
87         ret = TRUE;
88     }
89     TRACE("returning %d\n", ret);
90     return ret;
91 }
92
93 /* Assumes data->u.pPDSip exists, and its gSubject member set.
94  * Allocates data->u.pPDSip->pSip and loads it, if possible.
95  */
96 static BOOL SOFTPUB_GetSIP(CRYPT_PROVIDER_DATA *data)
97 {
98     BOOL ret;
99
100     data->u.pPDSip->pSip = data->psPfns->pfnAlloc(sizeof(SIP_DISPATCH_INFO));
101     if (data->u.pPDSip->pSip)
102         ret = CryptSIPLoad(&data->u.pPDSip->gSubject, 0, data->u.pPDSip->pSip);
103     else
104     {
105         SetLastError(ERROR_OUTOFMEMORY);
106         ret = FALSE;
107     }
108     TRACE("returning %d\n", ret);
109     return ret;
110 }
111
112 /* Assumes data->u.pPDSip has been loaded, and data->u.pPDSip->pSip allocated.
113  * Calls data->u.pPDSip->pSip->pfGet to construct data->hMsg.
114  */
115 static BOOL SOFTPUB_GetMessageFromFile(CRYPT_PROVIDER_DATA *data)
116 {
117     BOOL ret;
118     LPBYTE buf = NULL;
119     DWORD size = 0;
120
121     data->u.pPDSip->psSipSubjectInfo =
122      data->psPfns->pfnAlloc(sizeof(SIP_SUBJECTINFO));
123     if (!data->u.pPDSip->psSipSubjectInfo)
124     {
125         SetLastError(ERROR_OUTOFMEMORY);
126         return FALSE;
127     }
128
129     data->u.pPDSip->psSipSubjectInfo->cbSize = sizeof(SIP_SUBJECTINFO);
130     data->u.pPDSip->psSipSubjectInfo->pgSubjectType = &data->u.pPDSip->gSubject;
131     data->u.pPDSip->psSipSubjectInfo->hFile = data->pWintrustData->u.pFile->hFile;
132     data->u.pPDSip->psSipSubjectInfo->pwsFileName =
133      data->pWintrustData->u.pFile->pcwszFilePath;
134     data->u.pPDSip->psSipSubjectInfo->hProv = data->hProv;
135     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
136      &data->dwEncoding, 0, &size, 0);
137     if (!ret)
138     {
139         SetLastError(TRUST_E_NOSIGNATURE);
140         return FALSE;
141     }
142
143     buf = data->psPfns->pfnAlloc(size);
144     if (!buf)
145     {
146         SetLastError(ERROR_OUTOFMEMORY);
147         return FALSE;
148     }
149
150     ret = data->u.pPDSip->pSip->pfGet(data->u.pPDSip->psSipSubjectInfo,
151      &data->dwEncoding, 0, &size, buf);
152     if (ret)
153     {
154         data->hMsg = CryptMsgOpenToDecode(data->dwEncoding, 0, 0, data->hProv,
155          NULL, NULL);
156         if (data->hMsg)
157             ret = CryptMsgUpdate(data->hMsg, buf, size, TRUE);
158     }
159
160     data->psPfns->pfnFree(buf);
161     TRACE("returning %d\n", ret);
162     return ret;
163 }
164
165 static BOOL SOFTPUB_CreateStoreFromMessage(CRYPT_PROVIDER_DATA *data)
166 {
167     BOOL ret = FALSE;
168     HCERTSTORE store;
169
170     store = CertOpenStore(CERT_STORE_PROV_MSG, data->dwEncoding,
171      data->hProv, CERT_STORE_NO_CRYPT_RELEASE_FLAG, data->hMsg);
172     if (store)
173     {
174         ret = data->psPfns->pfnAddStore2Chain(data, store);
175         CertCloseStore(store, 0);
176     }
177     TRACE("returning %d\n", ret);
178     return ret;
179 }
180
181 static DWORD SOFTPUB_DecodeInnerContent(CRYPT_PROVIDER_DATA *data)
182 {
183     BOOL ret;
184     DWORD size;
185     LPBYTE buf = NULL;
186
187     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL,
188      &size);
189     if (!ret)
190         goto error;
191     buf = data->psPfns->pfnAlloc(size);
192     if (!buf)
193     {
194         SetLastError(ERROR_OUTOFMEMORY);
195         ret = FALSE;
196         goto error;
197     }
198     ret = CryptMsgGetParam(data->hMsg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, buf,
199      &size);
200     if (!ret)
201         goto error;
202     if (!strcmp((LPCSTR)buf, SPC_INDIRECT_DATA_OBJID))
203     {
204         data->psPfns->pfnFree(buf);
205         buf = NULL;
206         ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, NULL, &size);
207         if (!ret)
208             goto error;
209         buf = data->psPfns->pfnAlloc(size);
210         if (!buf)
211         {
212             SetLastError(ERROR_OUTOFMEMORY);
213             ret = FALSE;
214             goto error;
215         }
216         ret = CryptMsgGetParam(data->hMsg, CMSG_CONTENT_PARAM, 0, buf, &size);
217         if (!ret)
218             goto error;
219         ret = CryptDecodeObject(data->dwEncoding,
220          SPC_INDIRECT_DATA_CONTENT_STRUCT, buf, size, 0, NULL, &size);
221         if (!ret)
222             goto error;
223         data->u.pPDSip->psIndirectData = data->psPfns->pfnAlloc(size);
224         if (!data->u.pPDSip->psIndirectData)
225         {
226             SetLastError(ERROR_OUTOFMEMORY);
227             ret = FALSE;
228             goto error;
229         }
230         ret = CryptDecodeObject(data->dwEncoding,
231          SPC_INDIRECT_DATA_CONTENT_STRUCT, buf, size, 0,
232          data->u.pPDSip->psIndirectData, &size);
233     }
234     else
235     {
236         FIXME("unimplemented for OID %s\n", (LPCSTR)buf);
237         SetLastError(TRUST_E_SUBJECT_FORM_UNKNOWN);
238         ret = FALSE;
239     }
240
241 error:
242     TRACE("returning %d\n", ret);
243     return ret;
244 }
245
246 HRESULT WINAPI SoftpubLoadMessage(CRYPT_PROVIDER_DATA *data)
247 {
248     BOOL ret;
249
250     TRACE("(%p)\n", data);
251
252     if (!data->padwTrustStepErrors)
253         return S_FALSE;
254
255     switch (data->pWintrustData->dwUnionChoice)
256     {
257     case WTD_CHOICE_CERT:
258         /* Do nothing!?  See the tests */
259         ret = TRUE;
260         break;
261     case WTD_CHOICE_FILE:
262         if (!data->pWintrustData->u.pFile)
263         {
264             SetLastError(ERROR_INVALID_PARAMETER);
265             ret = FALSE;
266             goto error;
267         }
268         ret = SOFTPUB_OpenFile(data);
269         if (!ret)
270             goto error;
271         ret = SOFTPUB_GetFileSubject(data);
272         if (!ret)
273             goto error;
274         ret = SOFTPUB_GetSIP(data);
275         if (!ret)
276             goto error;
277         ret = SOFTPUB_GetMessageFromFile(data);
278         if (!ret)
279             goto error;
280         ret = SOFTPUB_CreateStoreFromMessage(data);
281         if (!ret)
282             goto error;
283         ret = SOFTPUB_DecodeInnerContent(data);
284         break;
285     default:
286         FIXME("unimplemented for %d\n", data->pWintrustData->dwUnionChoice);
287         SetLastError(ERROR_INVALID_PARAMETER);
288         ret = FALSE;
289     }
290
291 error:
292     if (!ret)
293         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
294          GetLastError();
295     return ret ? S_OK : S_FALSE;
296 }
297
298 static CMSG_SIGNER_INFO *WINTRUST_GetSigner(CRYPT_PROVIDER_DATA *data,
299  DWORD signerIdx)
300 {
301     BOOL ret;
302     CMSG_SIGNER_INFO *signerInfo = NULL;
303     DWORD size;
304
305     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM, signerIdx,
306      NULL, &size);
307     if (ret)
308     {
309         signerInfo = data->psPfns->pfnAlloc(size);
310         if (signerInfo)
311         {
312             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_INFO_PARAM,
313              signerIdx, signerInfo, &size);
314             if (!ret)
315             {
316                 data->psPfns->pfnFree(signerInfo);
317                 signerInfo = NULL;
318             }
319         }
320         else
321             SetLastError(ERROR_OUTOFMEMORY);
322     }
323     return signerInfo;
324 }
325
326 static BOOL WINTRUST_SaveSigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
327 {
328     BOOL ret;
329     CMSG_SIGNER_INFO *signerInfo = WINTRUST_GetSigner(data, signerIdx);
330
331     if (signerInfo)
332     {
333         CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
334
335         sgnr.psSigner = signerInfo;
336         ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, signerIdx, &sgnr);
337     }
338     else
339         ret = FALSE;
340     return ret;
341 }
342
343 static CERT_INFO *WINTRUST_GetSignerCertInfo(CRYPT_PROVIDER_DATA *data,
344  DWORD signerIdx)
345 {
346     BOOL ret;
347     CERT_INFO *certInfo = NULL;
348     DWORD size;
349
350     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM, signerIdx,
351      NULL, &size);
352     if (ret)
353     {
354         certInfo = data->psPfns->pfnAlloc(size);
355         if (certInfo)
356         {
357             ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_CERT_INFO_PARAM,
358              signerIdx, certInfo, &size);
359             if (!ret)
360             {
361                 data->psPfns->pfnFree(certInfo);
362                 certInfo = NULL;
363             }
364         }
365         else
366             SetLastError(ERROR_OUTOFMEMORY);
367     }
368     return certInfo;
369 }
370
371 static BOOL WINTRUST_VerifySigner(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
372 {
373     BOOL ret;
374     CERT_INFO *certInfo = WINTRUST_GetSignerCertInfo(data, signerIdx);
375
376     if (certInfo)
377     {
378         CMSG_CTRL_VERIFY_SIGNATURE_EX_PARA para = { sizeof(para), 0, signerIdx,
379          CMSG_VERIFY_SIGNER_CERT, NULL };
380
381         para.pvSigner = (LPVOID)CertGetSubjectCertificateFromStore(
382          data->pahStores[0], data->dwEncoding, certInfo);
383         if (para.pvSigner)
384         {
385             ret = CryptMsgControl(data->hMsg, 0, CMSG_CTRL_VERIFY_SIGNATURE_EX,
386              &para);
387             if (!ret)
388                 SetLastError(TRUST_E_CERT_SIGNATURE);
389         }
390         else
391         {
392             SetLastError(TRUST_E_NO_SIGNER_CERT);
393             ret = FALSE;
394         }
395         data->psPfns->pfnFree(certInfo);
396     }
397     else
398         ret = FALSE;
399     return ret;
400 }
401
402 HRESULT WINAPI SoftpubLoadSignature(CRYPT_PROVIDER_DATA *data)
403 {
404     BOOL ret;
405     DWORD signerCount, size;
406
407     TRACE("(%p)\n", data);
408
409     if (!data->padwTrustStepErrors)
410         return S_FALSE;
411
412     size = sizeof(signerCount);
413     ret = CryptMsgGetParam(data->hMsg, CMSG_SIGNER_COUNT_PARAM, 0,
414      &signerCount, &size);
415     if (ret)
416     {
417         DWORD i;
418
419         for (i = 0; ret && i < signerCount; i++)
420         {
421             if ((ret = WINTRUST_SaveSigner(data, i)))
422                 ret = WINTRUST_VerifySigner(data, i);
423         }
424     }
425     else
426         SetLastError(TRUST_E_NOSIGNATURE);
427     if (!ret)
428         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] =
429          GetLastError();
430     return ret ? S_OK : S_FALSE;
431 }
432
433 BOOL WINAPI SoftpubCheckCert(CRYPT_PROVIDER_DATA *data, DWORD idxSigner,
434  BOOL fCounterSignerChain, DWORD idxCounterSigner)
435 {
436     BOOL ret;
437
438     TRACE("(%p, %d, %d, %d)\n", data, idxSigner, fCounterSignerChain,
439      idxCounterSigner);
440
441     if (fCounterSignerChain)
442     {
443         FIXME("unimplemented for counter signers\n");
444         ret = FALSE;
445     }
446     else
447     {
448         PCERT_SIMPLE_CHAIN simpleChain =
449          data->pasSigners[idxSigner].pChainContext->rgpChain[0];
450         DWORD i;
451
452         ret = TRUE;
453         for (i = 0; i < simpleChain->cElement; i++)
454         {
455             /* Set confidence */
456             data->pasSigners[idxSigner].pasCertChain[i].dwConfidence = 0;
457             /* The last element in the chain doesn't have an issuer, so it
458              * can't have a valid time (with respect to its issuer)
459              */
460             if (i != simpleChain->cElement - 1 &&
461              !(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
462              CERT_TRUST_IS_NOT_TIME_VALID))
463                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
464                  |= CERT_CONFIDENCE_TIME;
465             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
466              CERT_TRUST_IS_NOT_TIME_NESTED))
467                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
468                  |= CERT_CONFIDENCE_TIMENEST;
469             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
470              CERT_TRUST_IS_NOT_SIGNATURE_VALID))
471                 data->pasSigners[idxSigner].pasCertChain[i].dwConfidence
472                  |= CERT_CONFIDENCE_SIG;
473             /* Set additional flags */
474             if (!(simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
475              CERT_TRUST_IS_UNTRUSTED_ROOT))
476                 data->pasSigners[idxSigner].pasCertChain[i].fTrustedRoot = TRUE;
477             if (simpleChain->rgpElement[i]->TrustStatus.dwInfoStatus &
478              CERT_TRUST_IS_SELF_SIGNED)
479                 data->pasSigners[idxSigner].pasCertChain[i].fSelfSigned = TRUE;
480             if (simpleChain->rgpElement[i]->TrustStatus.dwErrorStatus &
481              CERT_TRUST_IS_CYCLIC)
482                 data->pasSigners[idxSigner].pasCertChain[i].fIsCyclic = TRUE;
483         }
484     }
485     return ret;
486 }
487
488 static BOOL WINTRUST_CopyChain(CRYPT_PROVIDER_DATA *data, DWORD signerIdx)
489 {
490     BOOL ret;
491     PCERT_SIMPLE_CHAIN simpleChain =
492      data->pasSigners[signerIdx].pChainContext->rgpChain[0];
493     DWORD i;
494
495     data->pasSigners[signerIdx].pasCertChain[0].pChainElement =
496      simpleChain->rgpElement[0];
497     ret = TRUE;
498     for (i = 1; ret && i < simpleChain->cElement; i++)
499     {
500         ret = data->psPfns->pfnAddCert2Chain(data, signerIdx, FALSE, 0,
501          simpleChain->rgpElement[i]->pCertContext);
502         if (ret)
503             data->pasSigners[signerIdx].pasCertChain[i].pChainElement =
504              simpleChain->rgpElement[i];
505     }
506     return ret;
507 }
508
509 HRESULT WINAPI WintrustCertificateTrust(CRYPT_PROVIDER_DATA *data)
510 {
511     BOOL ret;
512
513     if (!data->csSigners)
514     {
515         ret = FALSE;
516         SetLastError(TRUST_E_NOSIGNATURE);
517     }
518     else
519     {
520         DWORD i;
521
522         ret = TRUE;
523         for (i = 0; i < data->csSigners; i++)
524         {
525             CERT_CHAIN_PARA chainPara = { sizeof(chainPara), { 0 } };
526             DWORD flags;
527
528             if (data->pRequestUsage)
529                 memcpy(&chainPara.RequestedUsage, data->pRequestUsage,
530                  sizeof(CERT_USAGE_MATCH));
531             if (data->dwProvFlags & CPD_REVOCATION_CHECK_END_CERT)
532                 flags = CERT_CHAIN_REVOCATION_CHECK_END_CERT;
533             else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN)
534                 flags = CERT_CHAIN_REVOCATION_CHECK_CHAIN;
535             else if (data->dwProvFlags & CPD_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT)
536                 flags = CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT;
537             else
538                 flags = 0;
539             /* Expect the end certificate for each signer to be the only
540              * cert in the chain:
541              */
542             if (data->pasSigners[i].csCertChain)
543             {
544                 /* Create a certificate chain for each signer */
545                 ret = CertGetCertificateChain(NULL,
546                  data->pasSigners[i].pasCertChain[0].pCert,
547                  NULL, /* FIXME: use data->pasSigners[i].sftVerifyAsOf? */
548                  data->chStores ? data->pahStores[0] : NULL,
549                  &chainPara, flags, NULL, &data->pasSigners[i].pChainContext);
550                 if (ret)
551                 {
552                     if (data->pasSigners[i].pChainContext->cChain != 1)
553                     {
554                         FIXME("unimplemented for more than 1 simple chain\n");
555                         ret = FALSE;
556                     }
557                     else
558                     {
559                         if ((ret = WINTRUST_CopyChain(data, i)))
560                             ret = data->psPfns->pfnCertCheckPolicy(data, i,
561                              FALSE, 0);
562                     }
563                 }
564             }
565         }
566     }
567     if (!ret)
568         data->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] =
569          GetLastError();
570     return ret ? S_OK : S_FALSE;
571 }