winhlp32: Update German translation.
[wine.git] / dlls / crypt32 / object.c
blob4184e6c0fa07c86adb94ffedec27330496fc2277
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_ReadSerializedStoreFromFile(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 /* Try it first as a PKCS content info */
303 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
304 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
306 msg = CryptMsgOpenToDecode(encodingType, 0, 0, 0, NULL, NULL);
307 if (msg)
309 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
310 if (ret)
312 DWORD type, len = sizeof(type);
314 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
315 if (ret)
317 if ((dwExpectedContentTypeFlags &
318 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
320 if (type != CMSG_SIGNED)
322 SetLastError(ERROR_INVALID_DATA);
323 ret = FALSE;
325 else if (pdwContentType)
326 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
328 else if ((dwExpectedContentTypeFlags &
329 CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
331 if (type != CMSG_DATA)
333 SetLastError(ERROR_INVALID_DATA);
334 ret = FALSE;
336 else if (pdwContentType)
337 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
341 if (!ret)
343 CryptMsgClose(msg);
344 msg = NULL;
348 /* Failing that, try explicitly typed messages */
349 if (!ret &&
350 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
352 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
353 if (msg)
355 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
356 if (!ret)
358 CryptMsgClose(msg);
359 msg = NULL;
362 if (msg && pdwContentType)
363 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
365 if (!ret &&
366 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
368 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
369 if (msg)
371 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
372 if (!ret)
374 CryptMsgClose(msg);
375 msg = NULL;
378 if (msg && pdwContentType)
379 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
381 if (pdwMsgAndCertEncodingType)
382 *pdwMsgAndCertEncodingType = encodingType;
383 if (msg)
385 if (phMsg)
386 *phMsg = msg;
387 if (phCertStore)
388 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
389 0, msg);
391 if (blob == &fileBlob)
392 CryptMemFree(blob->pbData);
393 TRACE("returning %d\n", ret);
394 return ret;
397 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
398 const void *pvObject, DWORD dwExpectedContentTypeFlags,
399 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
400 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
402 HANDLE file;
403 BOOL ret = FALSE;
405 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
407 FIXME("don't know what to do for type %d embedded signed messages\n",
408 dwObjectType);
409 SetLastError(E_INVALIDARG);
410 return FALSE;
412 file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ,
413 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
414 if (file != INVALID_HANDLE_VALUE)
416 DWORD len;
418 ret = ImageGetCertificateData(file, 0, NULL, &len);
419 if (ret)
421 WIN_CERTIFICATE *winCert = HeapAlloc(GetProcessHeap(), 0, len);
423 if (winCert)
425 ret = ImageGetCertificateData(file, 0, winCert, &len);
426 if (ret)
428 CERT_BLOB blob = { winCert->dwLength,
429 winCert->bCertificate };
431 ret = CRYPT_QueryMessageObject(CERT_QUERY_OBJECT_BLOB,
432 &blob, CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
433 pdwMsgAndCertEncodingType, NULL, phCertStore, phMsg);
434 if (ret && pdwContentType)
435 *pdwContentType = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED;
437 HeapFree(GetProcessHeap(), 0, winCert);
440 CloseHandle(file);
442 TRACE("returning %d\n", ret);
443 return ret;
446 BOOL WINAPI CryptQueryObject(DWORD dwObjectType, const void *pvObject,
447 DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags,
448 DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
449 DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg,
450 const void **ppvContext)
452 static const DWORD unimplementedTypes =
453 CERT_QUERY_CONTENT_FLAG_PKCS10 | CERT_QUERY_CONTENT_FLAG_PFX |
454 CERT_QUERY_CONTENT_FLAG_CERT_PAIR;
455 BOOL ret = TRUE;
457 TRACE("(%08x, %p, %08x, %08x, %08x, %p, %p, %p, %p, %p, %p)\n",
458 dwObjectType, pvObject, dwExpectedContentTypeFlags,
459 dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType,
460 pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext);
462 if (dwExpectedContentTypeFlags & unimplementedTypes)
463 WARN("unimplemented for types %08x\n",
464 dwExpectedContentTypeFlags & unimplementedTypes);
465 if (!(dwExpectedFormatTypeFlags & CERT_QUERY_FORMAT_FLAG_BINARY))
467 FIXME("unimplemented for anything but binary\n");
468 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
469 return FALSE;
471 if (pdwFormatType)
472 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
474 if (phCertStore)
475 *phCertStore = NULL;
476 if (phMsg)
477 *phMsg = NULL;
478 if (ppvContext)
479 *ppvContext = NULL;
481 ret = FALSE;
482 if ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CERT) ||
483 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CRL) ||
484 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_CTL))
486 ret = CRYPT_QueryContextObject(dwObjectType, pvObject,
487 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
488 phCertStore, ppvContext);
490 if (!ret &&
491 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
493 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
494 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
496 if (!ret &&
497 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CERT) ||
498 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CRL) ||
499 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_CTL)))
501 ret = CRYPT_QuerySerializedContextObject(dwObjectType, pvObject,
502 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
503 phCertStore, ppvContext);
505 if (!ret &&
506 ((dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED) ||
507 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED)))
509 ret = CRYPT_QueryMessageObject(dwObjectType, pvObject,
510 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
511 phCertStore, phMsg);
513 if (!ret &&
514 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
516 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
517 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
518 phCertStore, phMsg);
520 TRACE("returning %d\n", ret);
521 return ret;