ntdll/tests: Add tests for RtlIpv4AddressToString / RtlIpv4AddressToStringEx.
[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 CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
64  DWORD dwSignerIndex)
65 {
66     CERT_INFO *certInfo = NULL;
67     DWORD size;
68
69     if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
70      &size))
71     {
72         certInfo = CryptMemAlloc(size);
73         if (certInfo)
74         {
75             if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
76              dwSignerIndex, certInfo, &size))
77             {
78                 CryptMemFree(certInfo);
79                 certInfo = NULL;
80             }
81         }
82     }
83     else
84         SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE);
85     return certInfo;
86 }
87
88 static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg,
89  DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore)
90 {
91     return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0,
92      CERT_FIND_SUBJECT_CERT, pSignerId, NULL);
93 }
94
95 static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg,
96  PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store)
97 {
98     PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert;
99
100     if (pVerifyPara->pfnGetSignerCertificate)
101         getCert = pVerifyPara->pfnGetSignerCertificate;
102     else
103         getCert = CRYPT_DefaultGetSignerCertificate;
104     return getCert(pVerifyPara->pvGetArg,
105      pVerifyPara->dwMsgAndCertEncodingType, certInfo, store);
106 }
107
108 BOOL WINAPI CryptVerifyDetachedMessageSignature(
109  PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, DWORD dwSignerIndex,
110  const BYTE *pbDetachedSignBlob, DWORD cbDetachedSignBlob, DWORD cToBeSigned,
111  const BYTE *rgpbToBeSigned[], DWORD rgcbToBeSigned[],
112  PCCERT_CONTEXT *ppSignerCert)
113 {
114     BOOL ret = FALSE;
115     HCRYPTMSG msg;
116
117     TRACE("(%p, %d, %p, %d, %d, %p, %p, %p)\n", pVerifyPara, dwSignerIndex,
118      pbDetachedSignBlob, cbDetachedSignBlob, cToBeSigned, rgpbToBeSigned,
119      rgcbToBeSigned, ppSignerCert);
120
121     if (ppSignerCert)
122         *ppSignerCert = NULL;
123     if (!pVerifyPara ||
124      pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
125      GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
126      PKCS_7_ASN_ENCODING)
127     {
128         SetLastError(E_INVALIDARG);
129         return FALSE;
130     }
131
132     msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType,
133      CMSG_DETACHED_FLAG, 0, pVerifyPara->hCryptProv, NULL, NULL);
134     if (msg)
135     {
136         ret = CryptMsgUpdate(msg, pbDetachedSignBlob, cbDetachedSignBlob, TRUE);
137         if (ret)
138         {
139             DWORD i;
140
141             for (i = 0; ret && i < cToBeSigned; i++)
142                 ret = CryptMsgUpdate(msg, rgpbToBeSigned[i], rgcbToBeSigned[i],
143                  i == cToBeSigned - 1 ? TRUE : FALSE);
144         }
145         if (ret)
146         {
147             CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
148              dwSignerIndex);
149
150             ret = FALSE;
151             if (certInfo)
152             {
153                 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
154                  pVerifyPara->dwMsgAndCertEncodingType,
155                  pVerifyPara->hCryptProv, 0, msg);
156
157                 if (store)
158                 {
159                     PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
160                      msg, pVerifyPara, certInfo, store);
161
162                     if (cert)
163                     {
164                         ret = CryptMsgControl(msg, 0,
165                          CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
166                         if (ret && ppSignerCert)
167                             *ppSignerCert = cert;
168                         else
169                             CertFreeCertificateContext(cert);
170                     }
171                     else
172                         SetLastError(CRYPT_E_NOT_FOUND);
173                     CertCloseStore(store, 0);
174                 }
175                 CryptMemFree(certInfo);
176             }
177         }
178         CryptMsgClose(msg);
179     }
180     TRACE("returning %d\n", ret);
181     return ret;
182 }
183
184 BOOL WINAPI CryptVerifyMessageSignature(PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara,
185  DWORD dwSignerIndex, const BYTE* pbSignedBlob, DWORD cbSignedBlob,
186  BYTE* pbDecoded, DWORD* pcbDecoded, PCCERT_CONTEXT* ppSignerCert)
187 {
188     BOOL ret = FALSE;
189     HCRYPTMSG msg;
190
191     TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
192      pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
193      pbDecoded, pcbDecoded, ppSignerCert);
194
195     if (ppSignerCert)
196         *ppSignerCert = NULL;
197     if (!pVerifyPara ||
198      pVerifyPara->cbSize != sizeof(CRYPT_VERIFY_MESSAGE_PARA) ||
199      GET_CMSG_ENCODING_TYPE(pVerifyPara->dwMsgAndCertEncodingType) !=
200      PKCS_7_ASN_ENCODING)
201     {
202         if(pcbDecoded)
203             *pcbDecoded = 0;
204         SetLastError(E_INVALIDARG);
205         return FALSE;
206     }
207
208     msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType, 0, 0,
209      pVerifyPara->hCryptProv, NULL, NULL);
210     if (msg)
211     {
212         ret = CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE);
213         if (ret && pcbDecoded)
214             ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbDecoded,
215              pcbDecoded);
216         if (ret)
217         {
218             CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
219              dwSignerIndex);
220
221             ret = FALSE;
222             if (certInfo)
223             {
224                 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
225                  pVerifyPara->dwMsgAndCertEncodingType,
226                  pVerifyPara->hCryptProv, 0, msg);
227
228                 if (store)
229                 {
230                     PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
231                      msg, pVerifyPara, certInfo, store);
232
233                     if (cert)
234                     {
235                         ret = CryptMsgControl(msg, 0,
236                          CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
237                         if (ret && ppSignerCert)
238                             *ppSignerCert = cert;
239                         else
240                             CertFreeCertificateContext(cert);
241                     }
242                     CertCloseStore(store, 0);
243                 }
244             }
245             CryptMemFree(certInfo);
246         }
247         CryptMsgClose(msg);
248     }
249     if(!ret && pcbDecoded)
250         *pcbDecoded = 0;
251     TRACE("returning %d\n", ret);
252     return ret;
253 }
254
255 BOOL WINAPI CryptHashMessage(PCRYPT_HASH_MESSAGE_PARA pHashPara,
256  BOOL fDetachedHash, DWORD cToBeHashed, const BYTE *rgpbToBeHashed[],
257  DWORD rgcbToBeHashed[], BYTE *pbHashedBlob, DWORD *pcbHashedBlob,
258  BYTE *pbComputedHash, DWORD *pcbComputedHash)
259 {
260     DWORD i, flags;
261     BOOL ret = FALSE;
262     HCRYPTMSG msg;
263     CMSG_HASHED_ENCODE_INFO info;
264
265     TRACE("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n", pHashPara, fDetachedHash,
266      cToBeHashed, rgpbToBeHashed, rgcbToBeHashed, pbHashedBlob, pcbHashedBlob,
267      pbComputedHash, pcbComputedHash);
268
269     if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
270     {
271         SetLastError(E_INVALIDARG);
272         return FALSE;
273     }
274     /* Native seems to ignore any encoding type other than the expected
275      * PKCS_7_ASN_ENCODING
276      */
277     if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
278      PKCS_7_ASN_ENCODING)
279         return TRUE;
280     /* Native also seems to do nothing if the output parameter isn't given */
281     if (!pcbHashedBlob)
282         return TRUE;
283
284     flags = fDetachedHash ? CMSG_DETACHED_FLAG : 0;
285     memset(&info, 0, sizeof(info));
286     info.cbSize = sizeof(info);
287     info.hCryptProv = pHashPara->hCryptProv;
288     memcpy(&info.HashAlgorithm, &pHashPara->HashAlgorithm,
289      sizeof(info.HashAlgorithm));
290     info.pvHashAuxInfo = pHashPara->pvHashAuxInfo;
291     msg = CryptMsgOpenToEncode(pHashPara->dwMsgEncodingType, flags, CMSG_HASHED,
292      &info, NULL, NULL);
293     if (msg)
294     {
295         for (i = 0, ret = TRUE; ret && i < cToBeHashed; i++)
296             ret = CryptMsgUpdate(msg, rgpbToBeHashed[i], rgcbToBeHashed[i],
297              i == cToBeHashed - 1 ? TRUE : FALSE);
298         if (ret)
299         {
300             ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, pbHashedBlob,
301              pcbHashedBlob);
302             if (ret && pcbComputedHash)
303                 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
304                  pbComputedHash, pcbComputedHash);
305         }
306         CryptMsgClose(msg);
307     }
308     return ret;
309 }
310
311 BOOL WINAPI CryptVerifyDetachedMessageHash(PCRYPT_HASH_MESSAGE_PARA pHashPara,
312  BYTE *pbDetachedHashBlob, DWORD cbDetachedHashBlob, DWORD cToBeHashed,
313  const BYTE *rgpbToBeHashed[], DWORD rgcbToBeHashed[], BYTE *pbComputedHash,
314  DWORD *pcbComputedHash)
315 {
316     HCRYPTMSG msg;
317     BOOL ret = FALSE;
318
319     TRACE("(%p, %p, %d, %d, %p, %p, %p, %p)\n", pHashPara, pbDetachedHashBlob,
320      cbDetachedHashBlob, cToBeHashed, rgpbToBeHashed, rgcbToBeHashed,
321      pbComputedHash, pcbComputedHash);
322
323     if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
324     {
325         SetLastError(E_INVALIDARG);
326         return FALSE;
327     }
328     if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
329      PKCS_7_ASN_ENCODING)
330     {
331         SetLastError(E_INVALIDARG);
332         return FALSE;
333     }
334     msg = CryptMsgOpenToDecode(pHashPara->dwMsgEncodingType, CMSG_DETACHED_FLAG,
335      0, pHashPara->hCryptProv, NULL, NULL);
336     if (msg)
337     {
338         DWORD i;
339
340         ret = CryptMsgUpdate(msg, pbDetachedHashBlob, cbDetachedHashBlob, TRUE);
341         if (ret)
342         {
343             if (cToBeHashed)
344             {
345                 for (i = 0; ret && i < cToBeHashed; i++)
346                 {
347                     ret = CryptMsgUpdate(msg, rgpbToBeHashed[i],
348                      rgcbToBeHashed[i], i == cToBeHashed - 1 ? TRUE : FALSE);
349                 }
350             }
351             else
352                 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
353         }
354         if (ret)
355         {
356             ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL);
357             if (ret && pcbComputedHash)
358                 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
359                  pbComputedHash, pcbComputedHash);
360         }
361         CryptMsgClose(msg);
362     }
363     return ret;
364 }
365
366 BOOL WINAPI CryptVerifyMessageHash(PCRYPT_HASH_MESSAGE_PARA pHashPara,
367  BYTE *pbHashedBlob, DWORD cbHashedBlob, BYTE *pbToBeHashed,
368  DWORD *pcbToBeHashed, BYTE *pbComputedHash, DWORD *pcbComputedHash)
369 {
370     HCRYPTMSG msg;
371     BOOL ret = FALSE;
372
373     TRACE("(%p, %p, %d, %p, %p, %p, %p)\n", pHashPara, pbHashedBlob,
374      cbHashedBlob, pbToBeHashed, pcbToBeHashed, pbComputedHash,
375      pcbComputedHash);
376
377     if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
378     {
379         SetLastError(E_INVALIDARG);
380         return FALSE;
381     }
382     if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
383      PKCS_7_ASN_ENCODING)
384     {
385         SetLastError(E_INVALIDARG);
386         return FALSE;
387     }
388     msg = CryptMsgOpenToDecode(pHashPara->dwMsgEncodingType, 0, 0,
389      pHashPara->hCryptProv, NULL, NULL);
390     if (msg)
391     {
392         ret = CryptMsgUpdate(msg, pbHashedBlob, cbHashedBlob, TRUE);
393         if (ret)
394         {
395             ret = CryptMsgControl(msg, 0, CMSG_CTRL_VERIFY_HASH, NULL);
396             if (ret && pcbToBeHashed)
397                 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0,
398                  pbToBeHashed, pcbToBeHashed);
399             if (ret && pcbComputedHash)
400                 ret = CryptMsgGetParam(msg, CMSG_COMPUTED_HASH_PARAM, 0,
401                  pbComputedHash, pcbComputedHash);
402         }
403         CryptMsgClose(msg);
404     }
405     return ret;
406 }