push 7311fd3e948f012366fba1db2337ac857becfc4c
[wine/hacks.git] / dlls / crypt32 / serialize.c
blob281ac3fefd9bf23dce5547fdac6a5afface23617
1 /*
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
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "wine/debug.h"
23 #include "wine/exception.h"
24 #include "crypt32_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28 /* An extended certificate property in serialized form is prefixed by this
29 * header.
31 typedef struct _WINE_CERT_PROP_HEADER
33 DWORD propID;
34 DWORD unknown; /* always 1 */
35 DWORD cb;
36 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
38 static BOOL CRYPT_SerializeStoreElement(const void *context,
39 const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
40 PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BOOL omitHashes,
41 BYTE *pbElement, DWORD *pcbElement)
43 BOOL ret;
45 TRACE("(%p, %p, %08x, %d, %p, %p)\n", context, contextInterface, dwFlags,
46 omitHashes, pbElement, pcbElement);
48 if (context)
50 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
51 DWORD prop = 0;
53 ret = TRUE;
54 do {
55 prop = contextInterface->enumProps(context, prop);
56 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
58 DWORD propSize = 0;
60 ret = contextInterface->getProp(context, prop, NULL, &propSize);
61 if (ret)
62 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
64 } while (ret && prop != 0);
66 if (!pbElement)
68 *pcbElement = bytesNeeded;
69 ret = TRUE;
71 else if (*pcbElement < bytesNeeded)
73 *pcbElement = bytesNeeded;
74 SetLastError(ERROR_MORE_DATA);
75 ret = FALSE;
77 else
79 PWINE_CERT_PROP_HEADER hdr;
80 DWORD bufSize = 0;
81 LPBYTE buf = NULL;
83 prop = 0;
84 do {
85 prop = contextInterface->enumProps(context, prop);
86 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
88 DWORD propSize = 0;
90 ret = contextInterface->getProp(context, prop, NULL,
91 &propSize);
92 if (ret)
94 if (bufSize < propSize)
96 if (buf)
97 buf = CryptMemRealloc(buf, propSize);
98 else
99 buf = CryptMemAlloc(propSize);
100 bufSize = propSize;
102 if (buf)
104 ret = contextInterface->getProp(context, prop, buf,
105 &propSize);
106 if (ret)
108 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
109 hdr->propID = prop;
110 hdr->unknown = 1;
111 hdr->cb = propSize;
112 pbElement += sizeof(WINE_CERT_PROP_HEADER);
113 if (propSize)
115 memcpy(pbElement, buf, propSize);
116 pbElement += propSize;
120 else
121 ret = FALSE;
124 } while (ret && prop != 0);
125 CryptMemFree(buf);
127 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
128 hdr->propID = contextPropID;
129 hdr->unknown = 1;
130 hdr->cb = cbEncodedContext;
131 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
132 encodedContext, cbEncodedContext);
135 else
136 ret = FALSE;
137 return ret;
140 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
141 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
143 return CRYPT_SerializeStoreElement(pCertContext,
144 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
145 CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
148 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
149 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
151 return CRYPT_SerializeStoreElement(pCrlContext,
152 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
153 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
156 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
157 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
159 return CRYPT_SerializeStoreElement(pCtlContext,
160 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
161 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
164 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
165 * to its header if a valid header is found, NULL if not. Valid means the
166 * length of thte property won't overrun buf, and the unknown field is 1.
168 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
169 DWORD size, DWORD propID)
171 const WINE_CERT_PROP_HEADER *ret = NULL;
172 BOOL done = FALSE;
174 while (size && !ret && !done)
176 if (size < sizeof(WINE_CERT_PROP_HEADER))
178 SetLastError(CRYPT_E_FILE_ERROR);
179 done = TRUE;
181 else
183 const WINE_CERT_PROP_HEADER *hdr =
184 (const WINE_CERT_PROP_HEADER *)buf;
186 size -= sizeof(WINE_CERT_PROP_HEADER);
187 buf += sizeof(WINE_CERT_PROP_HEADER);
188 if (size < hdr->cb)
190 SetLastError(E_INVALIDARG);
191 done = TRUE;
193 else if (!hdr->propID)
195 /* assume a zero prop ID means the data are uninitialized, so
196 * stop looking.
198 done = TRUE;
200 else if (hdr->unknown != 1)
202 SetLastError(ERROR_FILE_NOT_FOUND);
203 done = TRUE;
205 else if (hdr->propID == propID)
206 ret = hdr;
207 else
209 buf += hdr->cb;
210 size -= hdr->cb;
214 return ret;
217 static BOOL CRYPT_ReadContextProp(
218 const WINE_CONTEXT_INTERFACE *contextInterface, const void *context,
219 const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement)
221 BOOL ret;
223 if (cbElement < hdr->cb)
225 SetLastError(E_INVALIDARG);
226 ret = FALSE;
228 else if (hdr->unknown != 1)
230 SetLastError(ERROR_FILE_NOT_FOUND);
231 ret = FALSE;
233 else if (hdr->propID != CERT_CERT_PROP_ID &&
234 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID)
236 /* Have to create a blob for most types, but not
237 * for all.. arghh.
239 switch (hdr->propID)
241 case CERT_AUTO_ENROLL_PROP_ID:
242 case CERT_CTL_USAGE_PROP_ID:
243 case CERT_DESCRIPTION_PROP_ID:
244 case CERT_FRIENDLY_NAME_PROP_ID:
245 case CERT_HASH_PROP_ID:
246 case CERT_KEY_IDENTIFIER_PROP_ID:
247 case CERT_MD5_HASH_PROP_ID:
248 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
249 case CERT_PUBKEY_ALG_PARA_PROP_ID:
250 case CERT_PVK_FILE_PROP_ID:
251 case CERT_SIGNATURE_HASH_PROP_ID:
252 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
253 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
254 case CERT_ENROLLMENT_PROP_ID:
255 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
256 case CERT_RENEWAL_PROP_ID:
258 CRYPT_DATA_BLOB blob = { hdr->cb,
259 (LPBYTE)pbElement };
261 ret = contextInterface->setProp(context,
262 hdr->propID, 0, &blob);
263 break;
265 case CERT_DATE_STAMP_PROP_ID:
266 ret = contextInterface->setProp(context,
267 hdr->propID, 0, pbElement);
268 break;
269 case CERT_KEY_PROV_INFO_PROP_ID:
271 PCRYPT_KEY_PROV_INFO info =
272 (PCRYPT_KEY_PROV_INFO)pbElement;
274 CRYPT_FixKeyProvInfoPointers(info);
275 ret = contextInterface->setProp(context,
276 hdr->propID, 0, pbElement);
277 break;
279 default:
280 ret = FALSE;
283 else
285 /* ignore the context itself */
286 ret = TRUE;
288 return ret;
291 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
292 DWORD dwContextTypeFlags, DWORD *pdwContentType)
294 const void *context;
296 TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags,
297 pdwContentType);
299 if (!cbElement)
301 SetLastError(ERROR_END_OF_MEDIA);
302 return NULL;
305 __TRY
307 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
308 const WINE_CERT_PROP_HEADER *hdr = NULL;
309 DWORD type = 0;
310 BOOL ret;
312 ret = TRUE;
313 context = NULL;
314 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
316 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
317 if (hdr)
318 type = CERT_STORE_CERTIFICATE_CONTEXT;
319 else
321 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
322 if (hdr)
323 type = CERT_STORE_CRL_CONTEXT;
324 else
326 hdr = CRYPT_findPropID(pbElement, cbElement,
327 CERT_CTL_PROP_ID);
328 if (hdr)
329 type = CERT_STORE_CTL_CONTEXT;
333 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
335 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
336 type = CERT_STORE_CERTIFICATE_CONTEXT;
338 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
340 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
341 type = CERT_STORE_CRL_CONTEXT;
343 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
345 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
346 type = CERT_STORE_CTL_CONTEXT;
349 switch (type)
351 case CERT_STORE_CERTIFICATE_CONTEXT:
352 contextInterface = pCertInterface;
353 break;
354 case CERT_STORE_CRL_CONTEXT:
355 contextInterface = pCRLInterface;
356 break;
357 case CERT_STORE_CTL_CONTEXT:
358 contextInterface = pCTLInterface;
359 break;
360 default:
361 SetLastError(E_INVALIDARG);
362 ret = FALSE;
364 if (!hdr)
365 ret = FALSE;
367 if (ret)
368 context = contextInterface->create(X509_ASN_ENCODING,
369 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
370 if (ret && context)
372 BOOL noMoreProps = FALSE;
374 while (!noMoreProps && ret)
376 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
377 ret = FALSE;
378 else
380 const WINE_CERT_PROP_HEADER *hdr =
381 (const WINE_CERT_PROP_HEADER *)pbElement;
383 TRACE("prop is %d\n", hdr->propID);
384 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
385 pbElement += sizeof(WINE_CERT_PROP_HEADER);
386 if (!hdr->propID)
388 /* Like in CRYPT_findPropID, stop if the propID is zero
390 noMoreProps = TRUE;
392 else
393 ret = CRYPT_ReadContextProp(contextInterface, context,
394 hdr, pbElement, cbElement);
395 pbElement += hdr->cb;
396 cbElement -= hdr->cb;
397 if (!cbElement)
398 noMoreProps = TRUE;
401 if (ret)
403 if (pdwContentType)
404 *pdwContentType = type;
406 else
408 contextInterface->free(context);
409 context = NULL;
413 __EXCEPT_PAGE_FAULT
415 SetLastError(STATUS_ACCESS_VIOLATION);
416 context = NULL;
418 __ENDTRY
419 return context;
422 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
424 BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
426 BYTE fileHeaderBuf[sizeof(fileHeader)];
427 DWORD read;
428 BOOL ret;
430 /* Failure reading is non-critical, we'll leave the store empty */
431 ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL);
432 if (ret)
434 if (!read)
435 ; /* an empty file is okay */
436 else if (read != sizeof(fileHeaderBuf))
437 ret = FALSE;
438 else if (!memcmp(fileHeaderBuf, fileHeader, read))
440 WINE_CERT_PROP_HEADER propHdr;
441 const void *context = NULL;
442 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
443 LPBYTE buf = NULL;
444 DWORD bufSize = 0;
446 do {
447 ret = ReadFile(file, &propHdr, sizeof(propHdr), &read, NULL);
448 if (ret && read == sizeof(propHdr))
450 if (contextInterface && context &&
451 (propHdr.propID == CERT_CERT_PROP_ID ||
452 propHdr.propID == CERT_CRL_PROP_ID ||
453 propHdr.propID == CERT_CTL_PROP_ID))
455 /* We have a new context, so free the existing one */
456 contextInterface->free(context);
458 if (propHdr.cb > bufSize)
460 /* Not reusing realloc, because the old data aren't
461 * needed any longer.
463 CryptMemFree(buf);
464 buf = CryptMemAlloc(propHdr.cb);
465 bufSize = propHdr.cb;
467 if (buf)
469 ret = ReadFile(file, buf, propHdr.cb, &read, NULL);
470 if (ret && read == propHdr.cb)
472 if (propHdr.propID == CERT_CERT_PROP_ID)
474 contextInterface = pCertInterface;
475 ret = contextInterface->addEncodedToStore(store,
476 X509_ASN_ENCODING, buf, read,
477 CERT_STORE_ADD_NEW, &context);
479 else if (propHdr.propID == CERT_CRL_PROP_ID)
481 contextInterface = pCRLInterface;
482 ret = contextInterface->addEncodedToStore(store,
483 X509_ASN_ENCODING, buf, read,
484 CERT_STORE_ADD_NEW, &context);
486 else if (propHdr.propID == CERT_CTL_PROP_ID)
488 contextInterface = pCTLInterface;
489 ret = contextInterface->addEncodedToStore(store,
490 X509_ASN_ENCODING, buf, read,
491 CERT_STORE_ADD_NEW, &context);
493 else
494 ret = CRYPT_ReadContextProp(contextInterface,
495 context, &propHdr, buf, read);
498 else
499 ret = FALSE;
501 } while (ret && read > 0);
502 if (contextInterface && context)
504 /* Free the last context added */
505 contextInterface->free(context);
507 CryptMemFree(buf);
508 ret = TRUE;
510 else
511 ret = FALSE;
513 else
514 ret = TRUE;
515 return ret;
518 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
519 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
521 return CRYPT_SerializeStoreElement(pCertContext,
522 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
523 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
526 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
527 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
529 return CRYPT_SerializeStoreElement(pCrlContext,
530 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
531 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
534 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
535 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
537 return CRYPT_SerializeStoreElement(pCtlContext,
538 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
539 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
542 typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer,
543 DWORD size);
545 static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output,
546 void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
548 const void *context = NULL;
549 BOOL ret;
551 do {
552 context = contextInterface->enumContextsInStore(store, context);
553 if (context)
555 DWORD size = 0;
556 LPBYTE buf = NULL;
558 ret = contextInterface->serialize(context, 0, NULL, &size);
559 if (size)
560 buf = CryptMemAlloc(size);
561 if (buf)
563 ret = contextInterface->serialize(context, 0, buf, &size);
564 if (ret)
565 ret = output(handle, buf, size);
567 CryptMemFree(buf);
569 else
570 ret = TRUE;
571 } while (ret && context != NULL);
572 if (context)
573 contextInterface->free(context);
574 return ret;
577 static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store,
578 SerializedOutputFunc output, void *handle)
580 static const BYTE fileTrailer[12] = { 0 };
581 WINE_CONTEXT_INTERFACE interface;
582 BOOL ret;
584 ret = output(handle, fileHeader, sizeof(fileHeader));
585 if (ret)
587 memcpy(&interface, pCertInterface, sizeof(interface));
588 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
589 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
590 store);
592 if (ret)
594 memcpy(&interface, pCRLInterface, sizeof(interface));
595 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
596 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
597 store);
599 if (ret)
601 memcpy(&interface, pCTLInterface, sizeof(interface));
602 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
603 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
604 store);
606 if (ret)
607 ret = output(handle, fileTrailer, sizeof(fileTrailer));
608 return ret;
611 static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size)
613 return WriteFile(handle, buffer, size, &size, NULL);
616 static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store)
618 SetFilePointer(file, 0, NULL, FILE_BEGIN);
619 return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc,
620 file);
623 static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store,
624 DWORD dwMsgAndCertEncodingType, void *handle)
626 CERT_BLOB *blob = (CERT_BLOB *)handle;
627 CRYPT_SIGNED_INFO signedInfo = { 0 };
628 PCCERT_CONTEXT cert = NULL;
629 PCCRL_CONTEXT crl = NULL;
630 DWORD size;
631 BOOL ret = TRUE;
633 TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData);
635 do {
636 cert = CertEnumCertificatesInStore(store, cert);
637 if (cert)
638 signedInfo.cCertEncoded++;
639 } while (cert);
640 if (signedInfo.cCertEncoded)
642 signedInfo.rgCertEncoded = CryptMemAlloc(
643 signedInfo.cCertEncoded * sizeof(CERT_BLOB));
644 if (!signedInfo.rgCertEncoded)
646 SetLastError(ERROR_OUTOFMEMORY);
647 ret = FALSE;
649 else
651 DWORD i = 0;
653 do {
654 cert = CertEnumCertificatesInStore(store, cert);
655 if (cert)
657 signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded;
658 signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded;
659 i++;
661 } while (cert);
665 do {
666 crl = CertEnumCRLsInStore(store, crl);
667 if (crl)
668 signedInfo.cCrlEncoded++;
669 } while (crl);
670 if (signedInfo.cCrlEncoded)
672 signedInfo.rgCrlEncoded = CryptMemAlloc(
673 signedInfo.cCrlEncoded * sizeof(CERT_BLOB));
674 if (!signedInfo.rgCrlEncoded)
676 SetLastError(ERROR_OUTOFMEMORY);
677 ret = FALSE;
679 else
681 DWORD i = 0;
683 do {
684 crl = CertEnumCRLsInStore(store, crl);
685 if (crl)
687 signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded;
688 signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded;
689 i++;
691 } while (crl);
694 if (ret)
696 ret = CRYPT_AsnEncodePKCSSignedInfo(&signedInfo, NULL, &size);
697 if (ret)
699 if (!blob->pbData)
700 blob->cbData = size;
701 else if (blob->cbData < size)
703 blob->cbData = size;
704 SetLastError(ERROR_MORE_DATA);
705 ret = FALSE;
707 else
709 blob->cbData = size;
710 ret = CRYPT_AsnEncodePKCSSignedInfo(&signedInfo, blob->pbData,
711 &blob->cbData);
715 CryptMemFree(signedInfo.rgCertEncoded);
716 CryptMemFree(signedInfo.rgCrlEncoded);
717 TRACE("returning %d\n", ret);
718 return ret;
721 static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store,
722 DWORD dwMsgAndCertEncodingType, void *handle)
724 CERT_BLOB blob = { 0, NULL };
725 BOOL ret;
727 TRACE("(%p)\n", handle);
729 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
730 if (ret)
732 blob.pbData = CryptMemAlloc(blob.cbData);
733 if (blob.pbData)
735 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
736 if (ret)
737 ret = WriteFile((HANDLE)handle, blob.pbData, blob.cbData,
738 &blob.cbData, NULL);
740 else
742 SetLastError(ERROR_OUTOFMEMORY);
743 ret = FALSE;
746 TRACE("returning %d\n", ret);
747 return ret;
750 static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store,
751 DWORD dwMsgAndCertEncodingType, void *handle)
753 return CRYPT_WriteSerializedStoreToFile((HANDLE)handle, store);
756 struct MemWrittenTracker
758 DWORD cbData;
759 BYTE *pbData;
760 DWORD written;
763 /* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */
764 static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size)
766 struct MemWrittenTracker *tracker = (struct MemWrittenTracker *)handle;
767 BOOL ret;
769 if (tracker->written + size > tracker->cbData)
771 SetLastError(ERROR_MORE_DATA);
772 /* Update written so caller can notify its caller of the required size
774 tracker->written += size;
775 ret = FALSE;
777 else
779 memcpy(tracker->pbData + tracker->written, buffer, size);
780 tracker->written += size;
781 ret = TRUE;
783 return ret;
786 static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer,
787 DWORD size)
789 *(DWORD *)handle += size;
790 return TRUE;
793 static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store,
794 DWORD dwMsgAndCertEncodingType, void *handle)
796 CERT_BLOB *blob = (CERT_BLOB *)handle;
797 DWORD size;
798 BOOL ret;
800 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes,
801 &size);
802 if (ret)
804 if (!blob->pbData)
805 blob->cbData = size;
806 else if (blob->cbData < size)
808 SetLastError(ERROR_MORE_DATA);
809 blob->cbData = size;
810 ret = FALSE;
812 else
814 struct MemWrittenTracker tracker = { blob->cbData, blob->pbData,
815 0 };
817 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc,
818 &tracker);
819 if (!ret && GetLastError() == ERROR_MORE_DATA)
820 blob->cbData = tracker.written;
823 TRACE("returning %d\n", ret);
824 return ret;
827 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
828 DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags)
830 BOOL (*saveFunc)(HCERTSTORE, DWORD, void *);
831 void *handle;
832 BOOL ret;
834 TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore,
835 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
837 switch (dwSaveAs)
839 case CERT_STORE_SAVE_AS_STORE:
840 case CERT_STORE_SAVE_AS_PKCS7:
841 break;
842 default:
843 WARN("unimplemented for %d\n", dwSaveAs);
844 SetLastError(ERROR_INVALID_PARAMETER);
845 return FALSE;
847 switch (dwSaveTo)
849 case CERT_STORE_SAVE_TO_FILE:
850 handle = (HANDLE)pvSaveToPara;
851 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
852 CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile;
853 break;
854 case CERT_STORE_SAVE_TO_FILENAME_A:
855 handle = CreateFileA((LPCSTR)pvSaveToPara, GENERIC_WRITE, 0, NULL,
856 CREATE_ALWAYS, 0, NULL);
857 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
858 CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile;
859 break;
860 case CERT_STORE_SAVE_TO_FILENAME_W:
861 handle = CreateFileW((LPCWSTR)pvSaveToPara, GENERIC_WRITE, 0, NULL,
862 CREATE_ALWAYS, 0, NULL);
863 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
864 CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile;
865 break;
866 case CERT_STORE_SAVE_TO_MEMORY:
867 handle = pvSaveToPara;
868 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
869 CRYPT_SaveSerializedToMem : CRYPT_SavePKCSToMem;
870 break;
871 default:
872 WARN("unimplemented for %d\n", dwSaveTo);
873 SetLastError(ERROR_INVALID_PARAMETER);
874 return FALSE;
876 ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle);
877 TRACE("returning %d\n", ret);
878 return ret;
881 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
882 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
883 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
885 const void *context;
886 DWORD type;
887 BOOL ret;
889 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore,
890 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
891 pdwContentType, ppvContext);
893 /* Call the internal function, then delete the hashes. Tests show this
894 * function uses real hash values, not whatever's stored in the hash
895 * property.
897 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
898 dwContextTypeFlags, &type);
899 if (context)
901 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
903 switch (type)
905 case CERT_STORE_CERTIFICATE_CONTEXT:
906 contextInterface = pCertInterface;
907 break;
908 case CERT_STORE_CRL_CONTEXT:
909 contextInterface = pCRLInterface;
910 break;
911 case CERT_STORE_CTL_CONTEXT:
912 contextInterface = pCTLInterface;
913 break;
914 default:
915 SetLastError(E_INVALIDARG);
917 if (contextInterface)
919 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
920 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
921 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
922 NULL);
923 if (pdwContentType)
924 *pdwContentType = type;
925 ret = contextInterface->addContextToStore(hCertStore, context,
926 dwAddDisposition, ppvContext);
927 contextInterface->free(context);
929 else
930 ret = FALSE;
932 else
933 ret = FALSE;
934 return ret;