jscript: Fix the lexicographical order of the String class properties array.
[wine/multimedia.git] / dlls / crypt32 / serialize.c
blob32a9ca0006fac0cf1f5a046955328d2f0ee41630
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
19 #include "config.h"
20 #include "wine/port.h"
22 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wincrypt.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
33 * header.
35 typedef struct _WINE_CERT_PROP_HEADER
37 DWORD propID;
38 DWORD unknown; /* always 1 */
39 DWORD cb;
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)
47 BOOL ret;
49 TRACE("(%p, %p, %08x, %d, %p, %p)\n", context, contextInterface, dwFlags,
50 omitHashes, pbElement, pcbElement);
52 if (context)
54 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
55 DWORD prop = 0;
57 ret = TRUE;
58 do {
59 prop = contextInterface->enumProps(context, prop);
60 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
62 DWORD propSize = 0;
64 ret = contextInterface->getProp(context, prop, NULL, &propSize);
65 if (ret)
66 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
68 } while (ret && prop != 0);
70 if (!pbElement)
72 *pcbElement = bytesNeeded;
73 ret = TRUE;
75 else if (*pcbElement < bytesNeeded)
77 *pcbElement = bytesNeeded;
78 SetLastError(ERROR_MORE_DATA);
79 ret = FALSE;
81 else
83 PWINE_CERT_PROP_HEADER hdr;
84 DWORD bufSize = 0;
85 LPBYTE buf = NULL;
87 prop = 0;
88 do {
89 prop = contextInterface->enumProps(context, prop);
90 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
92 DWORD propSize = 0;
94 ret = contextInterface->getProp(context, prop, NULL,
95 &propSize);
96 if (ret)
98 if (bufSize < propSize)
100 if (buf)
101 buf = CryptMemRealloc(buf, propSize);
102 else
103 buf = CryptMemAlloc(propSize);
104 bufSize = propSize;
106 if (buf)
108 ret = contextInterface->getProp(context, prop, buf,
109 &propSize);
110 if (ret)
112 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
113 hdr->propID = prop;
114 hdr->unknown = 1;
115 hdr->cb = propSize;
116 pbElement += sizeof(WINE_CERT_PROP_HEADER);
117 if (propSize)
119 memcpy(pbElement, buf, propSize);
120 pbElement += propSize;
124 else
125 ret = FALSE;
128 } while (ret && prop != 0);
129 CryptMemFree(buf);
131 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
132 hdr->propID = contextPropID;
133 hdr->unknown = 1;
134 hdr->cb = cbEncodedContext;
135 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
136 encodedContext, cbEncodedContext);
139 else
140 ret = FALSE;
141 return ret;
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;
176 BOOL done = FALSE;
178 while (size && !ret && !done)
180 if (size < sizeof(WINE_CERT_PROP_HEADER))
182 SetLastError(CRYPT_E_FILE_ERROR);
183 done = TRUE;
185 else
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);
192 if (size < hdr->cb)
194 SetLastError(E_INVALIDARG);
195 done = TRUE;
197 else if (!hdr->propID)
199 /* assume a zero prop ID means the data are uninitialized, so
200 * stop looking.
202 done = TRUE;
204 else if (hdr->unknown != 1)
206 SetLastError(ERROR_FILE_NOT_FOUND);
207 done = TRUE;
209 else if (hdr->propID == propID)
210 ret = hdr;
211 else
213 buf += hdr->cb;
214 size -= hdr->cb;
218 return ret;
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)
225 BOOL ret;
227 if (cbElement < hdr->cb)
229 SetLastError(E_INVALIDARG);
230 ret = FALSE;
232 else if (hdr->unknown != 1)
234 SetLastError(ERROR_FILE_NOT_FOUND);
235 ret = FALSE;
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
241 * for all.. arghh.
243 switch (hdr->propID)
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,
263 (LPBYTE)pbElement };
265 ret = contextInterface->setProp(context,
266 hdr->propID, 0, &blob);
267 break;
269 case CERT_DATE_STAMP_PROP_ID:
270 ret = contextInterface->setProp(context,
271 hdr->propID, 0, pbElement);
272 break;
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);
281 break;
283 default:
284 ret = FALSE;
287 else
289 /* ignore the context itself */
290 ret = TRUE;
292 return ret;
295 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
296 DWORD dwContextTypeFlags, DWORD *pdwContentType)
298 const void *context;
300 TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags,
301 pdwContentType);
303 if (!cbElement)
305 SetLastError(ERROR_END_OF_MEDIA);
306 return NULL;
309 __TRY
311 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
312 const WINE_CERT_PROP_HEADER *hdr = NULL;
313 DWORD type = 0;
314 BOOL ret;
316 ret = TRUE;
317 context = NULL;
318 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
320 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
321 if (hdr)
322 type = CERT_STORE_CERTIFICATE_CONTEXT;
323 else
325 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
326 if (hdr)
327 type = CERT_STORE_CRL_CONTEXT;
328 else
330 hdr = CRYPT_findPropID(pbElement, cbElement,
331 CERT_CTL_PROP_ID);
332 if (hdr)
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;
353 switch (type)
355 case CERT_STORE_CERTIFICATE_CONTEXT:
356 contextInterface = pCertInterface;
357 break;
358 case CERT_STORE_CRL_CONTEXT:
359 contextInterface = pCRLInterface;
360 break;
361 case CERT_STORE_CTL_CONTEXT:
362 contextInterface = pCTLInterface;
363 break;
364 default:
365 SetLastError(E_INVALIDARG);
366 ret = FALSE;
368 if (!hdr)
369 ret = FALSE;
371 if (ret)
372 context = contextInterface->create(X509_ASN_ENCODING,
373 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
374 if (ret && context)
376 BOOL noMoreProps = FALSE;
378 while (!noMoreProps && ret)
380 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
381 ret = FALSE;
382 else
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);
390 if (!hdr->propID)
392 /* Like in CRYPT_findPropID, stop if the propID is zero
394 noMoreProps = TRUE;
396 else
397 ret = CRYPT_ReadContextProp(contextInterface, context,
398 hdr, pbElement, cbElement);
399 pbElement += hdr->cb;
400 cbElement -= hdr->cb;
401 if (!cbElement)
402 noMoreProps = TRUE;
405 if (ret)
407 if (pdwContentType)
408 *pdwContentType = type;
410 else
412 contextInterface->free(context);
413 context = NULL;
417 __EXCEPT_PAGE_FAULT
419 SetLastError(STATUS_ACCESS_VIOLATION);
420 context = NULL;
422 __ENDTRY
423 return context;
426 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
428 BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
430 BYTE fileHeaderBuf[sizeof(fileHeader)];
431 DWORD read;
432 BOOL ret;
434 /* Failure reading is non-critical, we'll leave the store empty */
435 ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL);
436 if (ret)
438 if (!read)
439 ; /* an empty file is okay */
440 else if (read != sizeof(fileHeaderBuf))
441 ret = FALSE;
442 else if (!memcmp(fileHeaderBuf, fileHeader, read))
444 WINE_CERT_PROP_HEADER propHdr;
445 const void *context = NULL;
446 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
447 LPBYTE buf = NULL;
448 DWORD bufSize = 0;
450 do {
451 ret = ReadFile(file, &propHdr, sizeof(propHdr), &read, NULL);
452 if (ret && read == sizeof(propHdr))
454 if (contextInterface && context &&
455 (propHdr.propID == CERT_CERT_PROP_ID ||
456 propHdr.propID == CERT_CRL_PROP_ID ||
457 propHdr.propID == CERT_CTL_PROP_ID))
459 /* We have a new context, so free the existing one */
460 contextInterface->free(context);
462 if (propHdr.cb > bufSize)
464 /* Not reusing realloc, because the old data aren't
465 * needed any longer.
467 CryptMemFree(buf);
468 buf = CryptMemAlloc(propHdr.cb);
469 bufSize = propHdr.cb;
471 if (buf)
473 ret = ReadFile(file, buf, propHdr.cb, &read, NULL);
474 if (ret && read == propHdr.cb)
476 if (propHdr.propID == CERT_CERT_PROP_ID)
478 contextInterface = pCertInterface;
479 ret = contextInterface->addEncodedToStore(store,
480 X509_ASN_ENCODING, buf, read,
481 CERT_STORE_ADD_NEW, &context);
483 else if (propHdr.propID == CERT_CRL_PROP_ID)
485 contextInterface = pCRLInterface;
486 ret = contextInterface->addEncodedToStore(store,
487 X509_ASN_ENCODING, buf, read,
488 CERT_STORE_ADD_NEW, &context);
490 else if (propHdr.propID == CERT_CTL_PROP_ID)
492 contextInterface = pCTLInterface;
493 ret = contextInterface->addEncodedToStore(store,
494 X509_ASN_ENCODING, buf, read,
495 CERT_STORE_ADD_NEW, &context);
497 else
498 ret = CRYPT_ReadContextProp(contextInterface,
499 context, &propHdr, buf, read);
502 else
503 ret = FALSE;
505 } while (ret && read > 0);
506 if (contextInterface && context)
508 /* Free the last context added */
509 contextInterface->free(context);
511 CryptMemFree(buf);
512 ret = TRUE;
514 else
515 ret = FALSE;
517 else
518 ret = TRUE;
519 return ret;
522 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
523 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
525 return CRYPT_SerializeStoreElement(pCertContext,
526 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
527 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
530 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
531 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
533 return CRYPT_SerializeStoreElement(pCrlContext,
534 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
535 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
538 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
539 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
541 return CRYPT_SerializeStoreElement(pCtlContext,
542 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
543 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
546 typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer,
547 DWORD size);
549 static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output,
550 void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
552 const void *context = NULL;
553 BOOL ret;
555 do {
556 context = contextInterface->enumContextsInStore(store, context);
557 if (context)
559 DWORD size = 0;
560 LPBYTE buf = NULL;
562 ret = contextInterface->serialize(context, 0, NULL, &size);
563 if (size)
564 buf = CryptMemAlloc(size);
565 if (buf)
567 ret = contextInterface->serialize(context, 0, buf, &size);
568 if (ret)
569 ret = output(handle, buf, size);
571 CryptMemFree(buf);
573 else
574 ret = TRUE;
575 } while (ret && context != NULL);
576 if (context)
577 contextInterface->free(context);
578 return ret;
581 static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store,
582 SerializedOutputFunc output, void *handle)
584 static const BYTE fileTrailer[12] = { 0 };
585 WINE_CONTEXT_INTERFACE interface;
586 BOOL ret;
588 ret = output(handle, fileHeader, sizeof(fileHeader));
589 if (ret)
591 memcpy(&interface, pCertInterface, sizeof(interface));
592 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
593 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
594 store);
596 if (ret)
598 memcpy(&interface, pCRLInterface, sizeof(interface));
599 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
600 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
601 store);
603 if (ret)
605 memcpy(&interface, pCTLInterface, sizeof(interface));
606 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
607 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
608 store);
610 if (ret)
611 ret = output(handle, fileTrailer, sizeof(fileTrailer));
612 return ret;
615 static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size)
617 return WriteFile(handle, buffer, size, &size, NULL);
620 static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store)
622 SetFilePointer(file, 0, NULL, FILE_BEGIN);
623 return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc,
624 file);
627 static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store,
628 DWORD dwMsgAndCertEncodingType, void *handle)
630 CERT_BLOB *blob = (CERT_BLOB *)handle;
631 CRYPT_SIGNED_INFO signedInfo = { 0 };
632 PCCERT_CONTEXT cert = NULL;
633 PCCRL_CONTEXT crl = NULL;
634 DWORD size;
635 BOOL ret = TRUE;
637 TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData);
639 do {
640 cert = CertEnumCertificatesInStore(store, cert);
641 if (cert)
642 signedInfo.cCertEncoded++;
643 } while (cert);
644 if (signedInfo.cCertEncoded)
646 signedInfo.rgCertEncoded = CryptMemAlloc(
647 signedInfo.cCertEncoded * sizeof(CERT_BLOB));
648 if (!signedInfo.rgCertEncoded)
650 SetLastError(ERROR_OUTOFMEMORY);
651 ret = FALSE;
653 else
655 DWORD i = 0;
657 do {
658 cert = CertEnumCertificatesInStore(store, cert);
659 if (cert)
661 signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded;
662 signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded;
663 i++;
665 } while (cert);
669 do {
670 crl = CertEnumCRLsInStore(store, crl);
671 if (crl)
672 signedInfo.cCrlEncoded++;
673 } while (crl);
674 if (signedInfo.cCrlEncoded)
676 signedInfo.rgCrlEncoded = CryptMemAlloc(
677 signedInfo.cCrlEncoded * sizeof(CERT_BLOB));
678 if (!signedInfo.rgCrlEncoded)
680 SetLastError(ERROR_OUTOFMEMORY);
681 ret = FALSE;
683 else
685 DWORD i = 0;
687 do {
688 crl = CertEnumCRLsInStore(store, crl);
689 if (crl)
691 signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded;
692 signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded;
693 i++;
695 } while (crl);
698 if (ret)
700 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, NULL, &size);
701 if (ret)
703 if (!blob->pbData)
704 blob->cbData = size;
705 else if (blob->cbData < size)
707 blob->cbData = size;
708 SetLastError(ERROR_MORE_DATA);
709 ret = FALSE;
711 else
713 blob->cbData = size;
714 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, blob->pbData,
715 &blob->cbData);
719 CryptMemFree(signedInfo.rgCertEncoded);
720 CryptMemFree(signedInfo.rgCrlEncoded);
721 TRACE("returning %d\n", ret);
722 return ret;
725 static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store,
726 DWORD dwMsgAndCertEncodingType, void *handle)
728 CERT_BLOB blob = { 0, NULL };
729 BOOL ret;
731 TRACE("(%p)\n", handle);
733 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
734 if (ret)
736 blob.pbData = CryptMemAlloc(blob.cbData);
737 if (blob.pbData)
739 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
740 if (ret)
741 ret = WriteFile(handle, blob.pbData, blob.cbData,
742 &blob.cbData, NULL);
744 else
746 SetLastError(ERROR_OUTOFMEMORY);
747 ret = FALSE;
750 TRACE("returning %d\n", ret);
751 return ret;
754 static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store,
755 DWORD dwMsgAndCertEncodingType, void *handle)
757 return CRYPT_WriteSerializedStoreToFile(handle, store);
760 struct MemWrittenTracker
762 DWORD cbData;
763 BYTE *pbData;
764 DWORD written;
767 /* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */
768 static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size)
770 struct MemWrittenTracker *tracker = (struct MemWrittenTracker *)handle;
771 BOOL ret;
773 if (tracker->written + size > tracker->cbData)
775 SetLastError(ERROR_MORE_DATA);
776 /* Update written so caller can notify its caller of the required size
778 tracker->written += size;
779 ret = FALSE;
781 else
783 memcpy(tracker->pbData + tracker->written, buffer, size);
784 tracker->written += size;
785 ret = TRUE;
787 return ret;
790 static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer,
791 DWORD size)
793 *(DWORD *)handle += size;
794 return TRUE;
797 static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store,
798 DWORD dwMsgAndCertEncodingType, void *handle)
800 CERT_BLOB *blob = (CERT_BLOB *)handle;
801 DWORD size = 0;
802 BOOL ret;
804 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes,
805 &size);
806 if (ret)
808 if (!blob->pbData)
809 blob->cbData = size;
810 else if (blob->cbData < size)
812 SetLastError(ERROR_MORE_DATA);
813 blob->cbData = size;
814 ret = FALSE;
816 else
818 struct MemWrittenTracker tracker = { blob->cbData, blob->pbData,
819 0 };
821 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc,
822 &tracker);
823 if (!ret && GetLastError() == ERROR_MORE_DATA)
824 blob->cbData = tracker.written;
827 TRACE("returning %d\n", ret);
828 return ret;
831 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
832 DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags)
834 BOOL (*saveFunc)(HCERTSTORE, DWORD, void *);
835 void *handle;
836 BOOL ret;
838 TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore,
839 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
841 switch (dwSaveAs)
843 case CERT_STORE_SAVE_AS_STORE:
844 case CERT_STORE_SAVE_AS_PKCS7:
845 break;
846 default:
847 WARN("unimplemented for %d\n", dwSaveAs);
848 SetLastError(ERROR_INVALID_PARAMETER);
849 return FALSE;
851 switch (dwSaveTo)
853 case CERT_STORE_SAVE_TO_FILE:
854 handle = pvSaveToPara;
855 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
856 CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile;
857 break;
858 case CERT_STORE_SAVE_TO_FILENAME_A:
859 handle = CreateFileA((LPCSTR)pvSaveToPara, GENERIC_WRITE, 0, NULL,
860 CREATE_ALWAYS, 0, NULL);
861 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
862 CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile;
863 break;
864 case CERT_STORE_SAVE_TO_FILENAME_W:
865 handle = CreateFileW((LPCWSTR)pvSaveToPara, GENERIC_WRITE, 0, NULL,
866 CREATE_ALWAYS, 0, NULL);
867 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
868 CRYPT_SaveSerializedToFile : CRYPT_SavePKCSToFile;
869 break;
870 case CERT_STORE_SAVE_TO_MEMORY:
871 handle = pvSaveToPara;
872 saveFunc = dwSaveAs == CERT_STORE_SAVE_AS_STORE ?
873 CRYPT_SaveSerializedToMem : CRYPT_SavePKCSToMem;
874 break;
875 default:
876 WARN("unimplemented for %d\n", dwSaveTo);
877 SetLastError(ERROR_INVALID_PARAMETER);
878 return FALSE;
880 ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle);
881 TRACE("returning %d\n", ret);
882 return ret;
885 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
886 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
887 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
889 const void *context;
890 DWORD type;
891 BOOL ret;
893 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore,
894 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
895 pdwContentType, ppvContext);
897 /* Call the internal function, then delete the hashes. Tests show this
898 * function uses real hash values, not whatever's stored in the hash
899 * property.
901 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
902 dwContextTypeFlags, &type);
903 if (context)
905 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
907 switch (type)
909 case CERT_STORE_CERTIFICATE_CONTEXT:
910 contextInterface = pCertInterface;
911 break;
912 case CERT_STORE_CRL_CONTEXT:
913 contextInterface = pCRLInterface;
914 break;
915 case CERT_STORE_CTL_CONTEXT:
916 contextInterface = pCTLInterface;
917 break;
918 default:
919 SetLastError(E_INVALIDARG);
921 if (contextInterface)
923 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
924 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
925 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
926 NULL);
927 if (pdwContentType)
928 *pdwContentType = type;
929 ret = contextInterface->addContextToStore(hCertStore, context,
930 dwAddDisposition, ppvContext);
931 contextInterface->free(context);
933 else
934 ret = FALSE;
936 else
937 ret = FALSE;
938 return ret;