2 * Copyright 2004-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
20 #include "wine/port.h"
26 #include "wine/debug.h"
27 #include "wine/exception.h"
28 #include "crypt32_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 /* An extended certificate property in serialized form is prefixed by this
35 typedef struct _WINE_CERT_PROP_HEADER
38 DWORD unknown; /* always 1 */
40 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
42 static BOOL CRYPT_SerializeStoreElement(const void *context,
43 const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
44 PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BOOL omitHashes,
45 BYTE *pbElement, DWORD *pcbElement)
49 TRACE("(%p, %p, %08x, %d, %p, %p)\n", context, contextInterface, dwFlags,
50 omitHashes, pbElement, pcbElement);
54 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
59 prop = contextInterface->enumProps(context, prop);
60 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
64 ret = contextInterface->getProp(context, prop, NULL, &propSize);
66 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
68 } while (ret && prop != 0);
72 *pcbElement = bytesNeeded;
75 else if (*pcbElement < bytesNeeded)
77 *pcbElement = bytesNeeded;
78 SetLastError(ERROR_MORE_DATA);
83 PWINE_CERT_PROP_HEADER hdr;
89 prop = contextInterface->enumProps(context, prop);
90 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
94 ret = contextInterface->getProp(context, prop, NULL,
98 if (bufSize < propSize)
101 buf = CryptMemRealloc(buf, propSize);
103 buf = CryptMemAlloc(propSize);
108 ret = contextInterface->getProp(context, prop, buf,
112 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
116 pbElement += sizeof(WINE_CERT_PROP_HEADER);
119 memcpy(pbElement, buf, propSize);
120 pbElement += propSize;
128 } while (ret && prop != 0);
131 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
132 hdr->propID = contextPropID;
134 hdr->cb = cbEncodedContext;
135 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
136 encodedContext, cbEncodedContext);
144 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
145 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
147 return CRYPT_SerializeStoreElement(pCertContext,
148 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
149 CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
152 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
153 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
155 return CRYPT_SerializeStoreElement(pCrlContext,
156 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
157 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
160 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
161 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
163 return CRYPT_SerializeStoreElement(pCtlContext,
164 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
165 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
168 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
169 * to its header if a valid header is found, NULL if not. Valid means the
170 * length of thte property won't overrun buf, and the unknown field is 1.
172 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
173 DWORD size, DWORD propID)
175 const WINE_CERT_PROP_HEADER *ret = NULL;
178 while (size && !ret && !done)
180 if (size < sizeof(WINE_CERT_PROP_HEADER))
182 SetLastError(CRYPT_E_FILE_ERROR);
187 const WINE_CERT_PROP_HEADER *hdr =
188 (const WINE_CERT_PROP_HEADER *)buf;
190 size -= sizeof(WINE_CERT_PROP_HEADER);
191 buf += sizeof(WINE_CERT_PROP_HEADER);
194 SetLastError(E_INVALIDARG);
197 else if (!hdr->propID)
199 /* assume a zero prop ID means the data are uninitialized, so
204 else if (hdr->unknown != 1)
206 SetLastError(ERROR_FILE_NOT_FOUND);
209 else if (hdr->propID == propID)
221 static BOOL CRYPT_ReadContextProp(
222 const WINE_CONTEXT_INTERFACE *contextInterface, const void *context,
223 const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement)
227 if (cbElement < hdr->cb)
229 SetLastError(E_INVALIDARG);
232 else if (hdr->unknown != 1)
234 SetLastError(ERROR_FILE_NOT_FOUND);
237 else if (hdr->propID != CERT_CERT_PROP_ID &&
238 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID)
240 /* Have to create a blob for most types, but not
245 case CERT_AUTO_ENROLL_PROP_ID:
246 case CERT_CTL_USAGE_PROP_ID:
247 case CERT_DESCRIPTION_PROP_ID:
248 case CERT_FRIENDLY_NAME_PROP_ID:
249 case CERT_HASH_PROP_ID:
250 case CERT_KEY_IDENTIFIER_PROP_ID:
251 case CERT_MD5_HASH_PROP_ID:
252 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
253 case CERT_PUBKEY_ALG_PARA_PROP_ID:
254 case CERT_PVK_FILE_PROP_ID:
255 case CERT_SIGNATURE_HASH_PROP_ID:
256 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
257 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
258 case CERT_ENROLLMENT_PROP_ID:
259 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
260 case CERT_RENEWAL_PROP_ID:
262 CRYPT_DATA_BLOB blob = { hdr->cb,
265 ret = contextInterface->setProp(context,
266 hdr->propID, 0, &blob);
269 case CERT_DATE_STAMP_PROP_ID:
270 ret = contextInterface->setProp(context,
271 hdr->propID, 0, pbElement);
273 case CERT_KEY_PROV_INFO_PROP_ID:
275 PCRYPT_KEY_PROV_INFO info =
276 (PCRYPT_KEY_PROV_INFO)pbElement;
278 CRYPT_FixKeyProvInfoPointers(info);
279 ret = contextInterface->setProp(context,
280 hdr->propID, 0, pbElement);
289 /* ignore the context itself */
295 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
296 DWORD dwContextTypeFlags, DWORD *pdwContentType)
300 TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags,
305 SetLastError(ERROR_END_OF_MEDIA);
311 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
312 const WINE_CERT_PROP_HEADER *hdr = NULL;
318 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
320 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
322 type = CERT_STORE_CERTIFICATE_CONTEXT;
325 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
327 type = CERT_STORE_CRL_CONTEXT;
330 hdr = CRYPT_findPropID(pbElement, cbElement,
333 type = CERT_STORE_CTL_CONTEXT;
337 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
339 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
340 type = CERT_STORE_CERTIFICATE_CONTEXT;
342 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
344 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
345 type = CERT_STORE_CRL_CONTEXT;
347 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
349 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
350 type = CERT_STORE_CTL_CONTEXT;
355 case CERT_STORE_CERTIFICATE_CONTEXT:
356 contextInterface = pCertInterface;
358 case CERT_STORE_CRL_CONTEXT:
359 contextInterface = pCRLInterface;
361 case CERT_STORE_CTL_CONTEXT:
362 contextInterface = pCTLInterface;
365 SetLastError(E_INVALIDARG);
372 context = contextInterface->create(X509_ASN_ENCODING,
373 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
376 BOOL noMoreProps = FALSE;
378 while (!noMoreProps && ret)
380 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
384 const WINE_CERT_PROP_HEADER *hdr =
385 (const WINE_CERT_PROP_HEADER *)pbElement;
387 TRACE("prop is %d\n", hdr->propID);
388 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
389 pbElement += sizeof(WINE_CERT_PROP_HEADER);
392 /* Like in CRYPT_findPropID, stop if the propID is zero
397 ret = CRYPT_ReadContextProp(contextInterface, context,
398 hdr, pbElement, cbElement);
399 pbElement += hdr->cb;
400 cbElement -= hdr->cb;
408 *pdwContentType = type;
412 contextInterface->free(context);
419 SetLastError(STATUS_ACCESS_VIOLATION);
426 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
428 typedef BOOL (*read_serialized_func)(void *handle, void *buffer,
429 DWORD bytesToRead, DWORD *bytesRead);
431 static BOOL CRYPT_ReadSerializedStore(void *handle,
432 read_serialized_func read_func, HCERTSTORE store)
434 BYTE fileHeaderBuf[sizeof(fileHeader)];
438 /* Failure reading is non-critical, we'll leave the store empty */
439 ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read);
443 ; /* an empty file is okay */
444 else if (read != sizeof(fileHeaderBuf))
446 else if (!memcmp(fileHeaderBuf, fileHeader, read))
448 WINE_CERT_PROP_HEADER propHdr;
449 const void *context = NULL;
450 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
455 ret = read_func(handle, &propHdr, sizeof(propHdr), &read);
456 if (ret && read == sizeof(propHdr))
458 if (contextInterface && context &&
459 (propHdr.propID == CERT_CERT_PROP_ID ||
460 propHdr.propID == CERT_CRL_PROP_ID ||
461 propHdr.propID == CERT_CTL_PROP_ID))
463 /* We have a new context, so free the existing one */
464 contextInterface->free(context);
466 if (propHdr.cb > bufSize)
468 /* Not reusing realloc, because the old data aren't
472 buf = CryptMemAlloc(propHdr.cb);
473 bufSize = propHdr.cb;
477 ret = read_func(handle, buf, propHdr.cb, &read);
478 if (ret && read == propHdr.cb)
480 if (propHdr.propID == CERT_CERT_PROP_ID)
482 contextInterface = pCertInterface;
483 ret = contextInterface->addEncodedToStore(store,
484 X509_ASN_ENCODING, buf, read,
485 CERT_STORE_ADD_NEW, &context);
487 else if (propHdr.propID == CERT_CRL_PROP_ID)
489 contextInterface = pCRLInterface;
490 ret = contextInterface->addEncodedToStore(store,
491 X509_ASN_ENCODING, buf, read,
492 CERT_STORE_ADD_NEW, &context);
494 else if (propHdr.propID == CERT_CTL_PROP_ID)
496 contextInterface = pCTLInterface;
497 ret = contextInterface->addEncodedToStore(store,
498 X509_ASN_ENCODING, buf, read,
499 CERT_STORE_ADD_NEW, &context);
502 ret = CRYPT_ReadContextProp(contextInterface,
503 context, &propHdr, buf, read);
509 } while (ret && read > 0);
510 if (contextInterface && context)
512 /* Free the last context added */
513 contextInterface->free(context);
526 static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead,
529 return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL);
532 BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
534 return CRYPT_ReadSerializedStore(file, read_file_wrapper, store);
539 const CRYPT_DATA_BLOB *blob;
543 static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead,
546 struct BlobReader *reader = handle;
549 if (reader->current < reader->blob->cbData)
551 *bytesRead = min(bytesToRead, reader->blob->cbData - reader->current);
552 memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead);
560 BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
563 struct BlobReader reader = { blob, 0 };
565 return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store);
568 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
569 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
571 return CRYPT_SerializeStoreElement(pCertContext,
572 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
573 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
576 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
577 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
579 return CRYPT_SerializeStoreElement(pCrlContext,
580 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
581 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
584 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
585 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
587 return CRYPT_SerializeStoreElement(pCtlContext,
588 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
589 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
592 typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer,
595 static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output,
596 void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
598 const void *context = NULL;
602 context = contextInterface->enumContextsInStore(store, context);
608 ret = contextInterface->serialize(context, 0, NULL, &size);
610 buf = CryptMemAlloc(size);
613 ret = contextInterface->serialize(context, 0, buf, &size);
615 ret = output(handle, buf, size);
621 } while (ret && context != NULL);
623 contextInterface->free(context);
627 static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store,
628 SerializedOutputFunc output, void *handle)
630 static const BYTE fileTrailer[12] = { 0 };
631 WINE_CONTEXT_INTERFACE interface;
634 ret = output(handle, fileHeader, sizeof(fileHeader));
637 memcpy(&interface, pCertInterface, sizeof(interface));
638 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
639 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
644 memcpy(&interface, pCRLInterface, sizeof(interface));
645 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
646 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
651 memcpy(&interface, pCTLInterface, sizeof(interface));
652 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
653 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
657 ret = output(handle, fileTrailer, sizeof(fileTrailer));
661 static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size)
663 return WriteFile(handle, buffer, size, &size, NULL);
666 static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store)
668 SetFilePointer(file, 0, NULL, FILE_BEGIN);
669 return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc,
673 static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store,
674 DWORD dwMsgAndCertEncodingType, void *handle)
676 CERT_BLOB *blob = handle;
677 CRYPT_SIGNED_INFO signedInfo = { 0 };
678 PCCERT_CONTEXT cert = NULL;
679 PCCRL_CONTEXT crl = NULL;
683 TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData);
686 cert = CertEnumCertificatesInStore(store, cert);
688 signedInfo.cCertEncoded++;
690 if (signedInfo.cCertEncoded)
692 signedInfo.rgCertEncoded = CryptMemAlloc(
693 signedInfo.cCertEncoded * sizeof(CERT_BLOB));
694 if (!signedInfo.rgCertEncoded)
696 SetLastError(ERROR_OUTOFMEMORY);
704 cert = CertEnumCertificatesInStore(store, cert);
707 signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded;
708 signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded;
716 crl = CertEnumCRLsInStore(store, crl);
718 signedInfo.cCrlEncoded++;
720 if (signedInfo.cCrlEncoded)
722 signedInfo.rgCrlEncoded = CryptMemAlloc(
723 signedInfo.cCrlEncoded * sizeof(CERT_BLOB));
724 if (!signedInfo.rgCrlEncoded)
726 SetLastError(ERROR_OUTOFMEMORY);
734 crl = CertEnumCRLsInStore(store, crl);
737 signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded;
738 signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded;
746 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, NULL, &size);
751 else if (blob->cbData < size)
754 SetLastError(ERROR_MORE_DATA);
760 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, blob->pbData,
765 CryptMemFree(signedInfo.rgCertEncoded);
766 CryptMemFree(signedInfo.rgCrlEncoded);
767 TRACE("returning %d\n", ret);
771 static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store,
772 DWORD dwMsgAndCertEncodingType, void *handle)
774 CERT_BLOB blob = { 0, NULL };
777 TRACE("(%p)\n", handle);
779 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
782 blob.pbData = CryptMemAlloc(blob.cbData);
785 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
787 ret = WriteFile(handle, blob.pbData, blob.cbData,
792 SetLastError(ERROR_OUTOFMEMORY);
796 TRACE("returning %d\n", ret);
800 static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store,
801 DWORD dwMsgAndCertEncodingType, void *handle)
803 return CRYPT_WriteSerializedStoreToFile(handle, store);
806 struct MemWrittenTracker
813 /* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */
814 static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size)
816 struct MemWrittenTracker *tracker = handle;
819 if (tracker->written + size > tracker->cbData)
821 SetLastError(ERROR_MORE_DATA);
822 /* Update written so caller can notify its caller of the required size
824 tracker->written += size;
829 memcpy(tracker->pbData + tracker->written, buffer, size);
830 tracker->written += size;
836 static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer,
839 *(DWORD *)handle += size;
843 static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store,
844 DWORD dwMsgAndCertEncodingType, void *handle)
846 CERT_BLOB *blob = handle;
850 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes,
856 else if (blob->cbData < size)
858 SetLastError(ERROR_MORE_DATA);
864 struct MemWrittenTracker tracker = { blob->cbData, blob->pbData,
867 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc,
869 if (!ret && GetLastError() == ERROR_MORE_DATA)
870 blob->cbData = tracker.written;
873 TRACE("returning %d\n", ret);
877 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
878 DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags)
880 BOOL (*saveFunc)(HCERTSTORE, DWORD, void *);
882 BOOL ret, closeFile = TRUE;
884 TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore,
885 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
889 case CERT_STORE_SAVE_AS_STORE:
890 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
891 saveFunc = CRYPT_SaveSerializedToMem;
893 saveFunc = CRYPT_SaveSerializedToFile;
895 case CERT_STORE_SAVE_AS_PKCS7:
896 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
897 saveFunc = CRYPT_SavePKCSToMem;
899 saveFunc = CRYPT_SavePKCSToFile;
902 WARN("unimplemented for %d\n", dwSaveAs);
903 SetLastError(ERROR_INVALID_PARAMETER);
908 case CERT_STORE_SAVE_TO_FILE:
909 handle = pvSaveToPara;
912 case CERT_STORE_SAVE_TO_FILENAME_A:
913 handle = CreateFileA(pvSaveToPara, GENERIC_WRITE, 0, NULL,
914 CREATE_ALWAYS, 0, NULL);
916 case CERT_STORE_SAVE_TO_FILENAME_W:
917 handle = CreateFileW(pvSaveToPara, GENERIC_WRITE, 0, NULL,
918 CREATE_ALWAYS, 0, NULL);
920 case CERT_STORE_SAVE_TO_MEMORY:
921 handle = pvSaveToPara;
924 WARN("unimplemented for %d\n", dwSaveTo);
925 SetLastError(ERROR_INVALID_PARAMETER);
928 ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle);
931 TRACE("returning %d\n", ret);
935 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
936 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
937 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
943 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore,
944 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
945 pdwContentType, ppvContext);
947 /* Call the internal function, then delete the hashes. Tests show this
948 * function uses real hash values, not whatever's stored in the hash
951 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
952 dwContextTypeFlags, &type);
955 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
959 case CERT_STORE_CERTIFICATE_CONTEXT:
960 contextInterface = pCertInterface;
962 case CERT_STORE_CRL_CONTEXT:
963 contextInterface = pCRLInterface;
965 case CERT_STORE_CTL_CONTEXT:
966 contextInterface = pCTLInterface;
969 SetLastError(E_INVALIDARG);
971 if (contextInterface)
973 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
974 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
975 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
978 *pdwContentType = type;
979 ret = contextInterface->addContextToStore(hCertStore, context,
980 dwAddDisposition, ppvContext);
981 contextInterface->free(context);