crypt32: Fix CryptQueryObject for embedded PKCS7 signatures.
[wine/multimedia.git] / dlls / crypt32 / object.c
blob156b3dff54df5e2daa18b3ef9b6b8aef78ff86a2
1 /*
2 * crypt32 Crypt*Object functions
4 * Copyright 2007 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wincrypt.h"
24 #include "imagehlp.h"
25 #include "crypt32_private.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30 static BOOL CRYPT_ReadBlobFromFile(LPCWSTR fileName, PCERT_BLOB blob)
32 BOOL ret = FALSE;
33 HANDLE file;
35 TRACE("%s\n", debugstr_w(fileName));
37 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
38 OPEN_EXISTING, 0, NULL);
39 if (file != INVALID_HANDLE_VALUE)
41 ret = TRUE;
42 blob->cbData = GetFileSize(file, NULL);
43 if (blob->cbData)
45 blob->pbData = CryptMemAlloc(blob->cbData);
46 if (blob->pbData)
48 DWORD read;
50 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
53 CloseHandle(file);
55 TRACE("returning %d\n", ret);
56 return ret;
59 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
60 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
61 DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext)
63 CERT_BLOB fileBlob;
64 const CERT_BLOB *blob;
65 HCERTSTORE store;
66 DWORD contentType;
67 BOOL ret;
69 switch (dwObjectType)
71 case CERT_QUERY_OBJECT_FILE:
72 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
73 * just read the file directly
75 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
76 blob = &fileBlob;
77 break;
78 case CERT_QUERY_OBJECT_BLOB:
79 blob = (const CERT_BLOB *)pvObject;
80 ret = TRUE;
81 break;
82 default:
83 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
84 ret = FALSE;
86 if (!ret)
87 return FALSE;
89 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
90 CERT_STORE_CREATE_NEW_FLAG, NULL);
91 ret = FALSE;
92 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT)
94 ret = pCertInterface->addEncodedToStore(store, X509_ASN_ENCODING,
95 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
96 if (ret)
97 contentType = CERT_QUERY_CONTENT_CERT;
99 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL))
101 ret = pCRLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
102 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
103 if (ret)
104 contentType = CERT_QUERY_CONTENT_CRL;
106 if (!ret && (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
108 ret = pCTLInterface->addEncodedToStore(store, X509_ASN_ENCODING,
109 blob->pbData, blob->cbData, CERT_STORE_ADD_ALWAYS, ppvContext);
110 if (ret)
111 contentType = CERT_QUERY_CONTENT_CTL;
113 if (ret)
115 if (pdwMsgAndCertEncodingType)
116 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
117 if (pdwContentType)
118 *pdwContentType = contentType;
119 if (phCertStore)
120 *phCertStore = CertDuplicateStore(store);
122 CertCloseStore(store, 0);
123 if (blob == &fileBlob)
124 CryptMemFree(blob->pbData);
125 TRACE("returning %d\n", ret);
126 return ret;
129 static BOOL CRYPT_QuerySerializedContextObject(DWORD dwObjectType,
130 const void *pvObject, DWORD dwExpectedContentTypeFlags,
131 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
132 HCERTSTORE *phCertStore, const void **ppvContext)
134 CERT_BLOB fileBlob;
135 const CERT_BLOB *blob;
136 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
137 const void *context;
138 DWORD contextType;
139 BOOL ret;
141 switch (dwObjectType)
143 case CERT_QUERY_OBJECT_FILE:
144 /* Cert, CRL, and CTL contexts can't be "embedded" in a file, so
145 * just read the file directly
147 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
148 blob = &fileBlob;
149 break;
150 case CERT_QUERY_OBJECT_BLOB:
151 blob = (const CERT_BLOB *)pvObject;
152 ret = TRUE;
153 break;
154 default:
155 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
156 ret = FALSE;
158 if (!ret)
159 return FALSE;
161 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
162 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
163 if (context)
165 DWORD contentType, certStoreOffset;
167 ret = TRUE;
168 switch (contextType)
170 case CERT_STORE_CERTIFICATE_CONTEXT:
171 contextInterface = pCertInterface;
172 contentType = CERT_QUERY_CONTENT_SERIALIZED_CERT;
173 certStoreOffset = offsetof(CERT_CONTEXT, hCertStore);
174 if (!(dwExpectedContentTypeFlags &
175 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT))
177 SetLastError(ERROR_INVALID_DATA);
178 ret = FALSE;
179 goto end;
181 break;
182 case CERT_STORE_CRL_CONTEXT:
183 contextInterface = pCRLInterface;
184 contentType = CERT_QUERY_CONTENT_SERIALIZED_CRL;
185 certStoreOffset = offsetof(CRL_CONTEXT, hCertStore);
186 if (!(dwExpectedContentTypeFlags &
187 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL))
189 SetLastError(ERROR_INVALID_DATA);
190 ret = FALSE;
191 goto end;
193 break;
194 case CERT_STORE_CTL_CONTEXT:
195 contextInterface = pCTLInterface;
196 contentType = CERT_QUERY_CONTENT_SERIALIZED_CTL;
197 certStoreOffset = offsetof(CTL_CONTEXT, hCertStore);
198 if (!(dwExpectedContentTypeFlags &
199 CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL))
201 SetLastError(ERROR_INVALID_DATA);
202 ret = FALSE;
203 goto end;
205 break;
206 default:
207 SetLastError(ERROR_INVALID_DATA);
208 ret = FALSE;
209 goto end;
211 if (pdwMsgAndCertEncodingType)
212 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
213 if (pdwContentType)
214 *pdwContentType = contentType;
215 if (phCertStore)
216 *phCertStore = CertDuplicateStore(
217 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
218 if (ppvContext)
219 *ppvContext = contextInterface->duplicate(context);
222 end:
223 if (contextInterface && context)
224 contextInterface->free(context);
225 if (blob == &fileBlob)
226 CryptMemFree(blob->pbData);
227 TRACE("returning %d\n", ret);
228 return ret;
231 static BOOL CRYPT_QuerySerializedStoreObject(DWORD dwObjectType,
232 const void *pvObject, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
233 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
235 LPCWSTR fileName = (LPCWSTR)pvObject;
236 HANDLE file;
237 BOOL ret = FALSE;
239 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
241 FIXME("unimplemented for non-file type %d\n", dwObjectType);
242 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
243 return FALSE;
245 TRACE("%s\n", debugstr_w(fileName));
246 file = CreateFileW(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
247 OPEN_EXISTING, 0, NULL);
248 if (file != INVALID_HANDLE_VALUE)
250 HCERTSTORE store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
251 CERT_STORE_CREATE_NEW_FLAG, NULL);
253 ret = CRYPT_ReadSerializedFile(file, store);
254 if (ret)
256 if (pdwMsgAndCertEncodingType)
257 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
258 if (pdwContentType)
259 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
260 if (phCertStore)
261 *phCertStore = CertDuplicateStore(store);
263 CertCloseStore(store, 0);
264 CloseHandle(file);
266 TRACE("returning %d\n", ret);
267 return ret;
270 /* Used to decode non-embedded messages */
271 static BOOL CRYPT_QueryMessageObject(DWORD dwObjectType, const void *pvObject,
272 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
273 DWORD *pdwContentType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
275 CERT_BLOB fileBlob;
276 const CERT_BLOB *blob;
277 BOOL ret;
278 HCRYPTMSG msg = NULL;
279 DWORD encodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
281 switch (dwObjectType)
283 case CERT_QUERY_OBJECT_FILE:
284 /* This isn't an embedded PKCS7 message, so just read the file
285 * directly
287 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
288 blob = &fileBlob;
289 break;
290 case CERT_QUERY_OBJECT_BLOB:
291 blob = (const CERT_BLOB *)pvObject;
292 ret = TRUE;
293 break;
294 default:
295 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
296 ret = FALSE;
298 if (!ret)
299 return FALSE;
301 ret = FALSE;
302 if (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED)
304 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
305 if (msg)
307 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
308 if (!ret)
310 CryptMsgClose(msg);
311 msg = NULL;
314 if (msg && pdwContentType)
315 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
317 if (!ret &&
318 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
320 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
321 if (msg)
323 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
324 if (!ret)
326 CryptMsgClose(msg);
327 msg = NULL;
330 if (msg && pdwContentType)
331 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
333 if (pdwMsgAndCertEncodingType)
334 *pdwMsgAndCertEncodingType = encodingType;
335 if (msg)
337 if (phMsg)
338 *phMsg = msg;
339 if (phCertStore)
340 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
341 0, msg);
343 if (blob == &fileBlob)
344 CryptMemFree(blob->pbData);
345 TRACE("returning %d\n", ret);
346 return ret;
349 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
350 const void *pvObject, DWORD dwExpectedContentTypeFlags,
351 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
352 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
354 HANDLE file;
355 BOOL ret = FALSE;
357 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
359 FIXME("don't know what to do for type %d embedded signed messages\n",
360 dwObjectType);
361 SetLastError(E_INVALIDARG);
362 return FALSE;
364 file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ,
365 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
366 if (file != INVALID_HANDLE_VALUE)
368 DWORD len;
370 ret = ImageGetCertificateData(file, 0, NULL, &len);
371 if (ret)
373 WIN_CERTIFICATE *winCert = HeapAlloc(GetProcessHeap(), 0, len);
375 if (winCert)
377 ret = ImageGetCertificateData(file, 0, winCert, &len);
378 if (ret)
380 CERT_BLOB blob = { winCert->dwLength,
381 winCert->bCertificate };
383 ret = CRYPT_QueryMessageObject(CERT_QUERY_OBJECT_BLOB,
384 &blob, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
385 pdwMsgAndCertEncodingType, NULL, phCertStore, phMsg);
386 if (ret && pdwContentType)
387 *pdwContentType = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
389 HeapFree(GetProcessHeap(), 0, winCert);
392 CloseHandle(file);
394 TRACE("returning %d\n", ret);
395 return ret;
398 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
399 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
400 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
401 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
402 const void **ppvContext)
404 static const DWORD unimplementedTypes =
405 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
406 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
407 BOOL ret = TRUE;
409 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
410 dwObjectType, pvObject, dwExpectedContentTypeFlags,
411 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
412 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
414 if (dwExpectedContentTypeFlags & unimplementedTypes)
415 WARN("unimplemented for types %08x\n",
416 dwExpectedContentTypeFlags & unimplementedTypes);
417 if (!(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY))
419 FIXME("unimplemented for anything but binary\n");
420 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
421 return FALSE;
423 if (pdwFormatType)
424 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
426 if (phCertStore)
427 *phCertStore = NULL;
428 if (phMsg)
429 *phMsg = NULL;
430 if (ppvContext)
431 *ppvContext = NULL;
433 ret = FALSE;
434 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
435 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
436 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
438 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
439 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
440 phCertStore, ppvContext);
442 if (!ret &&
443 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
445 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
446 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
448 if (!ret &&
449 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
450 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
451 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
453 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
454 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
455 phCertStore, ppvContext);
457 if (!ret &&
458 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
459 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
461 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
462 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
463 phCertStore, phMsg);
465 if (!ret &&
466 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
468 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
469 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
470 phCertStore, phMsg);
472 TRACE("returning %d\n", ret);
473 return ret;