wined3d: Report incorrect filtering settings in ValidateDevice.
[wine] / dlls / crypt32 / message.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
19 #include <stdarg.h>
20 #include "windef.h"
21 #include "winbase.h"
22 #include "wincrypt.h"
23
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
27
28 HCERTSTORE WINAPI CryptGetMessageCertificates(DWORD dwMsgAndCertEncodingType,
29  HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const BYTE* pbSignedBlob,
30  DWORD cbSignedBlob)
31 {
32     CRYPT_DATA_BLOB blob = { cbSignedBlob, (LPBYTE)pbSignedBlob };
33
34     TRACE("(%08x, %ld, %d08x %p, %d)\n", dwMsgAndCertEncodingType, hCryptProv,
35      dwFlags, pbSignedBlob, cbSignedBlob);
36
37     return CertOpenStore(CERT_STORE_PROV_PKCS7, dwMsgAndCertEncodingType,
38      hCryptProv, dwFlags, &blob);
39 }
40
41 LONG WINAPI CryptGetMessageSignerCount(DWORD dwMsgEncodingType,
42  const BYTE *pbSignedBlob, DWORD cbSignedBlob)
43 {
44     HCRYPTMSG msg;
45     LONG count = -1;
46
47     TRACE("(%08x, %p, %d)\n", dwMsgEncodingType, pbSignedBlob, cbSignedBlob);
48
49     msg = CryptMsgOpenToDecode(dwMsgEncodingType, 0, 0, 0, NULL, NULL);
50     if (msg)
51     {
52         if (CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE))
53         {
54             DWORD size = sizeof(count);
55
56             CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 0, &count, &size);
57         }
58         CryptMsgClose(msg);
59     }
60     return count;
61 }
62
63 static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src,
64  DWORD len)
65 {
66     BOOL ret = TRUE;
67
68     if (!pvData)
69         *pcbData = len;
70     else if (*pcbData < len)
71     {
72         *pcbData = len;
73         SetLastError(ERROR_MORE_DATA);
74         ret = FALSE;
75     }
76     else
77     {
78         *pcbData = len;
79         memcpy(pvData, src, len);
80     }
81     return ret;
82 }
83
84 static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
85  DWORD dwSignerIndex)
86 {
87     CERT_INFO *certInfo = NULL;
88     DWORD size;
89
90     if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
91      &size))
92     {
93         certInfo = CryptMemAlloc(size);
94         if (certInfo)
95         {
96             if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
97              dwSignerIndex, certInfo, &size))
98             {
99                 CryptMemFree(certInfo);
100                 certInfo = NULL;
101             }
102         }
103     }
104     return certInfo;
105 }
106
107 static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg,
108  DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore)
109 {
110     return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0,
111      CERT_FIND_SUBJECT_CERT, pSignerId, NULL);
112 }
113
114 static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg,
115  PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store)
116 {
117     PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert;
118
119     if (pVerifyPara->pfnGetSignerCertificate)
120         getCert = pVerifyPara->pfnGetSignerCertificate;
121     else
122         getCert = CRYPT_DefaultGetSignerCertificate;
123     return getCert(pVerifyPara->pvGetArg,
124      pVerifyPara->dwMsgAndCertEncodingType, certInfo, store);
125 }
126
127 BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
128  DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
129  BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
130 {
131     BOOL ret = FALSE;
132     DWORD size;
133     CRYPT_CONTENT_INFO *contentInfo;
134     HCRYPTMSG msg;
135
136     TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
137      pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
138      pbDecoded, pcbDecoded, ppSignerCert);
139
140     if (ppSignerCert)
141         *ppSignerCert = NULL;
142     if (pcbDecoded)
143         *pcbDecoded = 0;
144     if (!pVerifyPara ||
145      pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
146      GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
147      PKCS_7_ASN_ENCODING)
148     {
149         SetLastError(E_INVALIDARG);
150         return FALSE;
151     }
152
153     if (!CryptDecodeObjectEx(pVerifyPara->dwMsgAndCertEncodingType,
154      PKCS_CONTENT_INFO, pbSignedBlob, cbSignedBlob,
155      CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG, NULL,
156      (LPBYTE)&contentInfo, &size))
157         return FALSE;
158     if (strcmp(contentInfo->pszObjId, szOID_RSA_signedData))
159     {
160         LocalFree(contentInfo);
161         SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE);
162         return FALSE;
163     }
164     msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType, 0,
165      CMSG_SIGNED, pVerifyPara->hCryptProv, NULL, NULL);
166     if (msg)
167     {
168         ret = CryptMsgUpdate(msg, contentInfo->Content.pbData,
169          contentInfo->Content.cbData, TRUE);
170         if (ret && pcbDecoded)
171             ret = CRYPT_CopyParam(pbDecoded, pcbDecoded,
172              contentInfo->Content.pbData, contentInfo->Content.cbData);
173         if (ret)
174         {
175             CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
176              dwSignerIndex);
177
178             ret = FALSE;
179             if (certInfo)
180             {
181                 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
182                  pVerifyPara->dwMsgAndCertEncodingType,
183                  pVerifyPara->hCryptProv, 0, msg);
184
185                 if (store)
186                 {
187                     PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
188                      msg, pVerifyPara, certInfo, store);
189
190                     if (cert)
191                     {
192                         ret = CryptMsgControl(msg, 0,
193                          CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
194                         if (ret && ppSignerCert)
195                             *ppSignerCert = cert;
196                         else
197                             CertFreeCertificateContext(cert);
198                     }
199                     CertCloseStore(store, 0);
200                 }
201             }
202             CryptMemFree(certInfo);
203         }
204         CryptMsgClose(msg);
205     }
206     LocalFree(contentInfo);
207     TRACE("returning %d\n", ret);
208     return ret;
209 }
210
211 BOOL WINAPI CryptHashMessage(PCRYPT_HASH_MESSAGE_PARA pHashPara,
212  BOOL fDetachedHash, DWORD cToBeHashed, const BYTE *rgpbToBeHashed[],
213  DWORD rgcbToBeHashed[], BYTE *pbHashedBlob, DWORD *pcbHashedBlob,
214  BYTE *pbComputedHash, DWORD *pcbComputedHash)
215 {
216     DWORD i, flags;
217     BOOL ret = FALSE;
218     HCRYPTMSG msg;
219     CMSG_HASHED_ENCODE_INFO info;
220
221     TRACE("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n", pHashPara, fDetachedHash,
222      cToBeHashed, rgpbToBeHashed, rgcbToBeHashed, pbHashedBlob, pcbHashedBlob,
223      pbComputedHash, pcbComputedHash);
224
225     if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
226     {
227         SetLastError(E_INVALIDARG);
228         return FALSE;
229     }
230     /* Native seems to ignore any encoding type other than the expected
231      * PKCS_7_ASN_ENCODING
232      */
233     if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
234      PKCS_7_ASN_ENCODING)
235         return TRUE;
236     /* Native also seems to do nothing if the output parameter isn't given */
237     if (!pcbHashedBlob)
238         return TRUE;
239
240     flags = fDetachedHash ? CMSG_DETACHED_FLAG : 0;
241     memset(&info, 0, sizeof(info));
242     info.cbSize = sizeof(info);
243     info.hCryptProv = pHashPara->hCryptProv;
244     memcpy(&info.HashAlgorithm, &pHashPara->HashAlgorithm,
245      sizeof(info.HashAlgorithm));
246     info.pvHashAuxInfo = pHashPara->pvHashAuxInfo;
247     msg = CryptMsgOpenToEncode(pHashPara->dwMsgEncodingType, flags, CMSG_HASHED,
248      &info, NULL, NULL);
249     if (msg)
250     {
251         for (i = 0, ret = TRUE; ret && i < cToBeHashed; i++)
252             ret = CryptMsgUpdate(msg, rgpbToBeHashed[i], rgcbToBeHashed[i],
253              i == cToBeHashed - 1 ? TRUE : FALSE);
254         if (ret)
255         {
256             ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbHashedBlob,
257              pcbHashedBlob);
258             if (ret && pcbComputedHash)
259                 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
260                  pbComputedHash, pcbComputedHash);
261         }
262         CryptMsgClose(msg);
263     }
264     return ret;
265 }
266
267 BOOL WINAPI CryptVerifyDetachedMessageHash(PCRYPT_HASH_MESSAGE_PARA pHashPara,
268  BYTE *pbDetachedHashBlob, DWORD cbDetachedHashBlob, DWORD cToBeHashed,
269  const BYTE *rgpbToBeHashed[], DWORD rgcbToBeHashed[], BYTE *pbComputedHash,
270  DWORD *pcbComputedHash)
271 {
272     HCRYPTMSG msg;
273     BOOL ret = FALSE;
274
275     TRACE("(%p, %p, %d, %d, %p, %p, %p, %p)\n", pHashPara, pbDetachedHashBlob,
276      cbDetachedHashBlob, cToBeHashed, rgpbToBeHashed, rgcbToBeHashed,
277      pbComputedHash, pcbComputedHash);
278
279     if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
280     {
281         SetLastError(E_INVALIDARG);
282         return FALSE;
283     }
284     if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
285      PKCS_7_ASN_ENCODING)
286     {
287         SetLastError(E_INVALIDARG);
288         return FALSE;
289     }
290     msg = CryptMsgOpenToDecode(pHashPara->dwMsgEncodingType, CMSG_DETACHED_FLAG,
291      0, pHashPara->hCryptProv, NULL, NULL);
292     if (msg)
293     {
294         DWORD i;
295
296         ret = CryptMsgUpdate(msg, pbDetachedHashBlob, cbDetachedHashBlob, TRUE);
297         if (ret)
298         {
299             if (cToBeHashed)
300             {
301                 for (i = 0; ret && i < cToBeHashed; i++)
302                 {
303                     ret = CryptMsgUpdate(msg, rgpbToBeHashed[i],
304                      rgcbToBeHashed[i], i == cToBeHashed - 1 ? TRUE : FALSE);
305                 }
306             }
307             else
308                 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
309         }
310         if (ret)
311         {
312             ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL);
313             if (ret && pcbComputedHash)
314                 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
315                  pbComputedHash, pcbComputedHash);
316         }
317         CryptMsgClose(msg);
318     }
319     return ret;
320 }