crypt32: Implement CryptVerifyDetachedMessageHash.
[wine.git] / dlls / crypt32 / message.c
blob9413dd6f2eda43583e904d1387f1680699ee1443
1 /*
2 * Copyright 2007 Juan Lang
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.
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.
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
19 #include <stdarg.h>
20 #include "windef.h"
21 #include "winbase.h"
22 #include "wincrypt.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28 HCERTSTORE WINAPI CryptGetMessageCertificates(DWORD dwMsgAndCertEncodingType,
29 HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const BYTE* pbSignedBlob,
30 DWORD cbSignedBlob)
32 CRYPT_DATA_BLOB blob = { cbSignedBlob, (LPBYTE)pbSignedBlob };
34 TRACE("(%08x, %ld, %d08x %p, %d)\n", dwMsgAndCertEncodingType, hCryptProv,
35 dwFlags, pbSignedBlob, cbSignedBlob);
37 return CertOpenStore(CERT_STORE_PROV_PKCS7, dwMsgAndCertEncodingType,
38 hCryptProv, dwFlags, &blob);
41 LONG WINAPI CryptGetMessageSignerCount(DWORD dwMsgEncodingType,
42 const BYTE *pbSignedBlob, DWORD cbSignedBlob)
44 HCRYPTMSG msg;
45 LONG count = -1;
47 TRACE("(%08x, %p, %d)\n", dwMsgEncodingType, pbSignedBlob, cbSignedBlob);
49 msg = CryptMsgOpenToDecode(dwMsgEncodingType, 0, 0, 0, NULL, NULL);
50 if (msg)
52 if (CryptMsgUpdate(msg, pbSignedBlob, cbSignedBlob, TRUE))
54 DWORD size = sizeof(count);
56 CryptMsgGetParam(msg, CMSG_SIGNER_COUNT_PARAM, 0, &count, &size);
58 CryptMsgClose(msg);
60 return count;
63 static BOOL CRYPT_CopyParam(void *pvData, DWORD *pcbData, const void *src,
64 DWORD len)
66 BOOL ret = TRUE;
68 if (!pvData)
69 *pcbData = len;
70 else if (*pcbData < len)
72 *pcbData = len;
73 SetLastError(ERROR_MORE_DATA);
74 ret = FALSE;
76 else
78 *pcbData = len;
79 memcpy(pvData, src, len);
81 return ret;
84 static CERT_INFO *CRYPT_GetSignerCertInfoFromMsg(HCRYPTMSG msg,
85 DWORD dwSignerIndex)
87 CERT_INFO *certInfo = NULL;
88 DWORD size;
90 if (CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM, dwSignerIndex, NULL,
91 &size))
93 certInfo = CryptMemAlloc(size);
94 if (certInfo)
96 if (!CryptMsgGetParam(msg, CMSG_SIGNER_CERT_INFO_PARAM,
97 dwSignerIndex, certInfo, &size))
99 CryptMemFree(certInfo);
100 certInfo = NULL;
104 return certInfo;
107 static PCCERT_CONTEXT WINAPI CRYPT_DefaultGetSignerCertificate(void *pvGetArg,
108 DWORD dwCertEncodingType, PCERT_INFO pSignerId, HCERTSTORE hMsgCertStore)
110 return CertFindCertificateInStore(hMsgCertStore, dwCertEncodingType, 0,
111 CERT_FIND_SUBJECT_CERT, pSignerId, NULL);
114 static inline PCCERT_CONTEXT CRYPT_GetSignerCertificate(HCRYPTMSG msg,
115 PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, PCERT_INFO certInfo, HCERTSTORE store)
117 PFN_CRYPT_GET_SIGNER_CERTIFICATE getCert;
119 if (pVerifyPara->pfnGetSignerCertificate)
120 getCert = pVerifyPara->pfnGetSignerCertificate;
121 else
122 getCert = CRYPT_DefaultGetSignerCertificate;
123 return getCert(pVerifyPara->pvGetArg,
124 pVerifyPara->dwMsgAndCertEncodingType, certInfo, store);
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)
131 BOOL ret = FALSE;
132 DWORD size;
133 CRYPT_CONTENT_INFO *contentInfo;
134 HCRYPTMSG msg;
136 TRACE("(%p, %d, %p, %d, %p, %p, %p)\n",
137 pVerifyPara, dwSignerIndex, pbSignedBlob, cbSignedBlob,
138 pbDecoded, pcbDecoded, ppSignerCert);
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)
149 SetLastError(E_INVALIDARG);
150 return FALSE;
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))
160 LocalFree(contentInfo);
161 SetLastError(CRYPT_E_UNEXPECTED_MSG_TYPE);
162 return FALSE;
164 msg = CryptMsgOpenToDecode(pVerifyPara->dwMsgAndCertEncodingType, 0,
165 CMSG_SIGNED, pVerifyPara->hCryptProv, NULL, NULL);
166 if (msg)
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)
175 CERT_INFO *certInfo = CRYPT_GetSignerCertInfoFromMsg(msg,
176 dwSignerIndex);
178 ret = FALSE;
179 if (certInfo)
181 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MSG,
182 pVerifyPara->dwMsgAndCertEncodingType,
183 pVerifyPara->hCryptProv, 0, msg);
185 if (store)
187 PCCERT_CONTEXT cert = CRYPT_GetSignerCertificate(
188 msg, pVerifyPara, certInfo, store);
190 if (cert)
192 ret = CryptMsgControl(msg, 0,
193 CMSG_CTRL_VERIFY_SIGNATURE, cert->pCertInfo);
194 if (ret && ppSignerCert)
195 *ppSignerCert = cert;
196 else
197 CertFreeCertificateContext(cert);
199 CertCloseStore(store, 0);
202 CryptMemFree(certInfo);
204 CryptMsgClose(msg);
206 LocalFree(contentInfo);
207 TRACE("returning %d\n", ret);
208 return ret;
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)
216 DWORD i, flags;
217 BOOL ret = FALSE;
218 HCRYPTMSG msg;
219 CMSG_HASHED_ENCODE_INFO info;
221 TRACE("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n", pHashPara, fDetachedHash,
222 cToBeHashed, rgpbToBeHashed, rgcbToBeHashed, pbHashedBlob, pcbHashedBlob,
223 pbComputedHash, pcbComputedHash);
225 if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
227 SetLastError(E_INVALIDARG);
228 return FALSE;
230 /* Native seems to ignore any encoding type other than the expected
231 * PKCS_7_ASN_ENCODING
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;
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)
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)
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);
262 CryptMsgClose(msg);
264 return ret;
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)
272 HCRYPTMSG msg;
273 BOOL ret = FALSE;
275 TRACE("(%p, %p, %d, %d, %p, %p, %p, %p)\n", pHashPara, pbDetachedHashBlob,
276 cbDetachedHashBlob, cToBeHashed, rgpbToBeHashed, rgcbToBeHashed,
277 pbComputedHash, pcbComputedHash);
279 if (pHashPara->cbSize != sizeof(CRYPT_HASH_MESSAGE_PARA))
281 SetLastError(E_INVALIDARG);
282 return FALSE;
284 if (GET_CMSG_ENCODING_TYPE(pHashPara->dwMsgEncodingType) !=
285 PKCS_7_ASN_ENCODING)
287 SetLastError(E_INVALIDARG);
288 return FALSE;
290 msg = CryptMsgOpenToDecode(pHashPara->dwMsgEncodingType, CMSG_DETACHED_FLAG,
291 0, pHashPara->hCryptProv, NULL, NULL);
292 if (msg)
294 DWORD i;
296 ret = CryptMsgUpdate(msg, pbDetachedHashBlob, cbDetachedHashBlob, TRUE);
297 if (ret)
299 if (cToBeHashed)
301 for (i = 0; ret && i < cToBeHashed; i++)
303 ret = CryptMsgUpdate(msg, rgpbToBeHashed[i],
304 rgcbToBeHashed[i], i == cToBeHashed - 1 ? TRUE : FALSE);
307 else
308 ret = CryptMsgUpdate(msg, NULL, 0, TRUE);
310 if (ret)
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);
317 CryptMsgClose(msg);
319 return ret;