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
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)
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)
42 blob->cbData = GetFileSize(file, NULL);
45 blob->pbData = CryptMemAlloc(blob->cbData);
50 ret = ReadFile(file, blob->pbData, blob->cbData, &read, NULL);
55 TRACE("returning %d\n", ret);
59 static BOOL CRYPT_QueryContextObject(DWORD dwObjectType, const void *pvObject,
60 DWORD dwExpectedContentTypeFlags, DWORD *pdwMsgAndCertEncodingType,
61 DWORD *pdwContentType, HCERTSTORE *phCertStore, const void **ppvContext)
64 const CERT_BLOB *blob;
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);
78 case CERT_QUERY_OBJECT_BLOB:
79 blob = (const CERT_BLOB *)pvObject;
83 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
89 store = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0,
90 CERT_STORE_CREATE_NEW_FLAG, NULL);
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);
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);
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);
111 contentType = CERT_QUERY_CONTENT_CTL;
115 if (pdwMsgAndCertEncodingType)
116 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
118 *pdwContentType = contentType;
120 *phCertStore = CertDuplicateStore(store);
122 CertCloseStore(store, 0);
123 if (blob == &fileBlob)
124 CryptMemFree(blob->pbData);
125 TRACE("returning %d\n", 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)
135 const CERT_BLOB *blob;
136 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
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);
150 case CERT_QUERY_OBJECT_BLOB:
151 blob = (const CERT_BLOB *)pvObject;
155 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
161 context = CRYPT_ReadSerializedElement(blob->pbData, blob->cbData,
162 CERT_STORE_ALL_CONTEXT_FLAG, &contextType);
165 DWORD contentType, certStoreOffset;
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);
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);
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);
207 SetLastError(ERROR_INVALID_DATA);
211 if (pdwMsgAndCertEncodingType)
212 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
214 *pdwContentType = contentType;
216 *phCertStore = CertDuplicateStore(
217 *(HCERTSTORE *)((const BYTE *)context + certStoreOffset));
219 *ppvContext = contextInterface->duplicate(context);
223 if (contextInterface && context)
224 contextInterface->free(context);
225 if (blob == &fileBlob)
226 CryptMemFree(blob->pbData);
227 TRACE("returning %d\n", 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;
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? */
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);
256 if (pdwMsgAndCertEncodingType)
257 *pdwMsgAndCertEncodingType = X509_ASN_ENCODING;
259 *pdwContentType = CERT_QUERY_CONTENT_SERIALIZED_STORE;
261 *phCertStore = CertDuplicateStore(store);
263 CertCloseStore(store, 0);
266 TRACE("returning %d\n", 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)
276 const CERT_BLOB *blob;
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
287 ret = CRYPT_ReadBlobFromFile((LPCWSTR)pvObject, &fileBlob);
290 case CERT_QUERY_OBJECT_BLOB:
291 blob = (const CERT_BLOB *)pvObject;
295 SetLastError(E_INVALIDARG); /* FIXME: is this the correct error? */
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);
309 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
312 DWORD type, len = sizeof(type);
314 ret = CryptMsgGetParam(msg, CMSG_TYPE_PARAM, 0, &type, &len);
317 if ((dwExpectedContentTypeFlags &
318 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
320 if (type != CMSG_SIGNED)
322 SetLastError(ERROR_INVALID_DATA);
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);
336 else if (pdwContentType)
337 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
348 /* Failing that, try explicitly typed messages */
350 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED))
352 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_SIGNED, 0, NULL, NULL);
355 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
362 if (msg && pdwContentType)
363 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_SIGNED;
366 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED))
368 msg = CryptMsgOpenToDecode(encodingType, 0, CMSG_DATA, 0, NULL, NULL);
371 ret = CryptMsgUpdate(msg, blob->pbData, blob->cbData, TRUE);
378 if (msg && pdwContentType)
379 *pdwContentType = CERT_QUERY_CONTENT_PKCS7_UNSIGNED;
381 if (pdwMsgAndCertEncodingType)
382 *pdwMsgAndCertEncodingType = encodingType;
388 *phCertStore = CertOpenStore(CERT_STORE_PROV_MSG, encodingType, 0,
391 if (blob == &fileBlob)
392 CryptMemFree(blob->pbData);
393 TRACE("returning %d\n", ret);
397 static BOOL CRYPT_QueryEmbeddedMessageObject(DWORD dwObjectType,
398 const void *pvObject, DWORD dwExpectedContentTypeFlags,
399 DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType,
400 HCERTSTORE *phCertStore, HCRYPTMSG *phMsg)
405 if (dwObjectType != CERT_QUERY_OBJECT_FILE)
407 FIXME("don't know what to do for type %d embedded signed messages\n",
409 SetLastError(E_INVALIDARG);
412 file = CreateFileW((LPCWSTR)pvObject, GENERIC_READ, FILE_SHARE_READ,
413 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
414 if (file != INVALID_HANDLE_VALUE)
418 ret = ImageGetCertificateData(file, 0, NULL, &len);
419 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
421 WIN_CERTIFICATE *winCert = HeapAlloc(GetProcessHeap(), 0, len);
425 ret = ImageGetCertificateData(file, 0, winCert, &len);
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);
442 TRACE("returning %d\n", 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;
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);
472 *pdwFormatType = CERT_QUERY_FORMAT_BINARY;
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);
491 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE))
493 ret = CRYPT_QuerySerializedStoreObject(dwObjectType, pvObject,
494 pdwMsgAndCertEncodingType, pdwContentType, phCertStore, phMsg);
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);
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,
514 (dwExpectedContentTypeFlags & CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED))
516 ret = CRYPT_QueryEmbeddedMessageObject(dwObjectType, pvObject,
517 dwExpectedContentTypeFlags, pdwMsgAndCertEncodingType, pdwContentType,
520 TRACE("returning %d\n", ret);