cmd: DIR command outputs free space for the path.
[wine.git] / dlls / crypt32 / serialize.c
blob11d39188880fe659436597f1c143dc7b341c8543
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 <stdarg.h>
20 #include "windef.h"
21 #include "winbase.h"
22 #include "wincrypt.h"
23 #include "wine/debug.h"
24 #include "wine/exception.h"
25 #include "crypt32_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
29 /* An extended certificate property in serialized form is prefixed by this
30 * header.
32 typedef struct _WINE_CERT_PROP_HEADER
34 DWORD propID;
35 DWORD unknown; /* always 1 */
36 DWORD cb;
37 } WINE_CERT_PROP_HEADER;
39 struct store_CRYPT_KEY_PROV_INFO
41 DWORD pwszContainerName;
42 DWORD pwszProvName;
43 DWORD dwProvType;
44 DWORD dwFlags;
45 DWORD cProvParam;
46 DWORD rgProvParam;
47 DWORD dwKeySpec;
50 struct store_CRYPT_KEY_PROV_PARAM
52 DWORD dwParam;
53 DWORD pbData;
54 DWORD cbData;
55 DWORD dwFlags;
58 static DWORD serialize_KeyProvInfoProperty(const CRYPT_KEY_PROV_INFO *info, struct store_CRYPT_KEY_PROV_INFO **ret)
60 struct store_CRYPT_KEY_PROV_INFO *store;
61 struct store_CRYPT_KEY_PROV_PARAM *param;
62 DWORD size = sizeof(struct store_CRYPT_KEY_PROV_INFO), i;
63 BYTE *data;
65 if (info->pwszContainerName)
66 size += (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
67 if (info->pwszProvName)
68 size += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
70 for (i = 0; i < info->cProvParam; i++)
71 size += sizeof(struct store_CRYPT_KEY_PROV_PARAM) + info->rgProvParam[i].cbData;
73 if (!ret) return size;
75 store = CryptMemAlloc(size);
76 if (!store) return 0;
78 param = (struct store_CRYPT_KEY_PROV_PARAM *)(store + 1);
79 data = (BYTE *)param + sizeof(struct store_CRYPT_KEY_PROV_PARAM) * info->cProvParam;
81 if (info->pwszContainerName)
83 store->pwszContainerName = data - (BYTE *)store;
84 lstrcpyW((LPWSTR)data, info->pwszContainerName);
85 data += (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
87 else
88 store->pwszContainerName = 0;
90 if (info->pwszProvName)
92 store->pwszProvName = data - (BYTE *)store;
93 lstrcpyW((LPWSTR)data, info->pwszProvName);
94 data += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
96 else
97 store->pwszProvName = 0;
99 store->dwProvType = info->dwProvType;
100 store->dwFlags = info->dwFlags;
101 store->cProvParam = info->cProvParam;
102 store->rgProvParam = info->cProvParam ? (BYTE *)param - (BYTE *)store : 0;
103 store->dwKeySpec = info->dwKeySpec;
105 for (i = 0; i < info->cProvParam; i++)
107 param[i].dwParam = info->rgProvParam[i].dwParam;
108 param[i].dwFlags = info->rgProvParam[i].dwFlags;
109 param[i].cbData = info->rgProvParam[i].cbData;
110 param[i].pbData = param[i].cbData ? data - (BYTE *)store : 0;
111 memcpy(data, info->rgProvParam[i].pbData, info->rgProvParam[i].cbData);
112 data += info->rgProvParam[i].cbData;
115 *ret = store;
116 return size;
119 static BOOL CRYPT_SerializeStoreElement(const void *context,
120 const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
121 const WINE_CONTEXT_INTERFACE *contextInterface, DWORD dwFlags, BOOL omitHashes,
122 BYTE *pbElement, DWORD *pcbElement)
124 BOOL ret;
126 TRACE("(%p, %p, %08lx, %d, %p, %p)\n", context, contextInterface, dwFlags,
127 omitHashes, pbElement, pcbElement);
129 if (context)
131 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
132 DWORD prop = 0;
134 ret = TRUE;
135 do {
136 prop = contextInterface->enumProps(context, prop);
137 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
139 DWORD propSize = 0;
141 ret = contextInterface->getProp(context, prop, NULL, &propSize);
142 if (ret)
144 if (prop == CERT_KEY_PROV_INFO_PROP_ID)
146 BYTE *info = CryptMemAlloc(propSize);
147 contextInterface->getProp(context, prop, info, &propSize);
148 propSize = serialize_KeyProvInfoProperty((const CRYPT_KEY_PROV_INFO *)info, NULL);
149 CryptMemFree(info);
151 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
154 } while (ret && prop != 0);
156 if (!pbElement)
158 *pcbElement = bytesNeeded;
159 ret = TRUE;
161 else if (*pcbElement < bytesNeeded)
163 *pcbElement = bytesNeeded;
164 SetLastError(ERROR_MORE_DATA);
165 ret = FALSE;
167 else
169 WINE_CERT_PROP_HEADER *hdr;
170 DWORD bufSize = 0;
171 LPBYTE buf = NULL;
173 prop = 0;
174 do {
175 prop = contextInterface->enumProps(context, prop);
176 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
178 DWORD propSize = 0;
180 ret = contextInterface->getProp(context, prop, NULL,
181 &propSize);
182 if (ret)
184 if (bufSize < propSize)
186 if (buf)
187 buf = CryptMemRealloc(buf, propSize);
188 else
189 buf = CryptMemAlloc(propSize);
190 bufSize = propSize;
192 if (buf)
194 ret = contextInterface->getProp(context, prop, buf,
195 &propSize);
196 if (ret)
198 if (prop == CERT_KEY_PROV_INFO_PROP_ID)
200 struct store_CRYPT_KEY_PROV_INFO *store;
201 propSize = serialize_KeyProvInfoProperty((const CRYPT_KEY_PROV_INFO *)buf, &store);
202 CryptMemFree(buf);
203 buf = (BYTE *)store;
206 hdr = (WINE_CERT_PROP_HEADER*)pbElement;
207 hdr->propID = prop;
208 hdr->unknown = 1;
209 hdr->cb = propSize;
210 pbElement += sizeof(WINE_CERT_PROP_HEADER);
211 if (propSize)
213 memcpy(pbElement, buf, propSize);
214 pbElement += propSize;
218 else
219 ret = FALSE;
222 } while (ret && prop != 0);
223 CryptMemFree(buf);
225 hdr = (WINE_CERT_PROP_HEADER*)pbElement;
226 hdr->propID = contextPropID;
227 hdr->unknown = 1;
228 hdr->cb = cbEncodedContext;
229 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
230 encodedContext, cbEncodedContext);
233 else
234 ret = FALSE;
235 return ret;
238 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
239 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
241 return CRYPT_SerializeStoreElement(pCertContext,
242 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
243 CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
246 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
247 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
249 return CRYPT_SerializeStoreElement(pCrlContext,
250 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
251 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
254 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
255 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
257 return CRYPT_SerializeStoreElement(pCtlContext,
258 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
259 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
262 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
263 * to its header if a valid header is found, NULL if not. Valid means the
264 * length of the property won't overrun buf, and the unknown field is 1.
266 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
267 DWORD size, DWORD propID)
269 const WINE_CERT_PROP_HEADER *ret = NULL;
270 BOOL done = FALSE;
272 while (size && !ret && !done)
274 if (size < sizeof(WINE_CERT_PROP_HEADER))
276 SetLastError(CRYPT_E_FILE_ERROR);
277 done = TRUE;
279 else
281 const WINE_CERT_PROP_HEADER *hdr =
282 (const WINE_CERT_PROP_HEADER *)buf;
284 size -= sizeof(WINE_CERT_PROP_HEADER);
285 buf += sizeof(WINE_CERT_PROP_HEADER);
286 if (size < hdr->cb)
288 SetLastError(E_INVALIDARG);
289 done = TRUE;
291 else if (!hdr->propID)
293 /* assume a zero prop ID means the data are uninitialized, so
294 * stop looking.
296 done = TRUE;
298 else if (hdr->unknown != 1)
300 SetLastError(ERROR_FILE_NOT_FOUND);
301 done = TRUE;
303 else if (hdr->propID == propID)
304 ret = hdr;
305 else
307 buf += hdr->cb;
308 size -= hdr->cb;
312 return ret;
315 static DWORD read_serialized_KeyProvInfoProperty(const struct store_CRYPT_KEY_PROV_INFO *store, CRYPT_KEY_PROV_INFO **ret)
317 const struct store_CRYPT_KEY_PROV_PARAM *param;
318 CRYPT_KEY_PROV_INFO *info;
319 DWORD size = sizeof(CRYPT_KEY_PROV_INFO), i;
320 const BYTE *base;
321 BYTE *data;
323 base = (const BYTE *)store;
324 param = (const struct store_CRYPT_KEY_PROV_PARAM *)(base + store->rgProvParam);
326 if (store->pwszContainerName)
327 size += (lstrlenW((LPCWSTR)(base + store->pwszContainerName)) + 1) * sizeof(WCHAR);
328 if (store->pwszProvName)
329 size += (lstrlenW((LPCWSTR)(base + store->pwszProvName)) + 1) * sizeof(WCHAR);
331 for (i = 0; i < store->cProvParam; i++)
332 size += sizeof(CRYPT_KEY_PROV_PARAM) + param[i].cbData;
334 info = CryptMemAlloc(size);
335 if (!info)
337 SetLastError(ERROR_OUTOFMEMORY);
338 return 0;
341 data = (BYTE *)(info + 1) + sizeof(CRYPT_KEY_PROV_PARAM) * store->cProvParam;
343 if (store->pwszContainerName)
345 info->pwszContainerName = (LPWSTR)data;
346 lstrcpyW(info->pwszContainerName, (LPCWSTR)((const BYTE *)store + store->pwszContainerName));
347 data += (lstrlenW(info->pwszContainerName) + 1) * sizeof(WCHAR);
349 else
350 info->pwszContainerName = NULL;
352 if (store->pwszProvName)
354 info->pwszProvName = (LPWSTR)data;
355 lstrcpyW(info->pwszProvName, (LPCWSTR)((const BYTE *)store + store->pwszProvName));
356 data += (lstrlenW(info->pwszProvName) + 1) * sizeof(WCHAR);
358 else
359 info->pwszProvName = NULL;
361 info->dwProvType = store->dwProvType;
362 info->dwFlags = store->dwFlags;
363 info->dwKeySpec = store->dwKeySpec;
364 info->cProvParam = store->cProvParam;
366 if (info->cProvParam)
368 DWORD i;
370 info->rgProvParam = (CRYPT_KEY_PROV_PARAM *)(info + 1);
372 for (i = 0; i < info->cProvParam; i++)
374 info->rgProvParam[i].dwParam = param[i].dwParam;
375 info->rgProvParam[i].dwFlags = param[i].dwFlags;
376 info->rgProvParam[i].cbData = param[i].cbData;
377 info->rgProvParam[i].pbData = param[i].cbData ? data : NULL;
378 memcpy(info->rgProvParam[i].pbData, base + param[i].pbData, param[i].cbData);
379 data += param[i].cbData;
382 else
383 info->rgProvParam = NULL;
385 TRACE("%s,%s,%lu,%08lx,%lu,%p,%lu\n", debugstr_w(info->pwszContainerName), debugstr_w(info->pwszProvName),
386 info->dwProvType, info->dwFlags, info->cProvParam, info->rgProvParam, info->dwKeySpec);
388 *ret = info;
389 return size;
392 static BOOL CRYPT_ReadContextProp(
393 const WINE_CONTEXT_INTERFACE *contextInterface, const void *context,
394 const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement)
396 BOOL ret;
398 if (cbElement < hdr->cb)
400 SetLastError(E_INVALIDARG);
401 ret = FALSE;
403 else if (hdr->unknown != 1)
405 SetLastError(ERROR_FILE_NOT_FOUND);
406 ret = FALSE;
408 else if (hdr->propID >= CERT_FIRST_USER_PROP_ID && hdr->propID <= CERT_LAST_USER_PROP_ID)
410 CRYPT_DATA_BLOB blob = { hdr->cb, (LPBYTE)pbElement };
412 ret = contextInterface->setProp(context, hdr->propID, 0, &blob);
414 else if (hdr->propID != CERT_CERT_PROP_ID &&
415 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID)
417 /* Have to create a blob for most types, but not
418 * for all.. arghh.
420 switch (hdr->propID)
422 case CERT_AUTO_ENROLL_PROP_ID:
423 case CERT_CTL_USAGE_PROP_ID:
424 case CERT_DESCRIPTION_PROP_ID:
425 case CERT_FRIENDLY_NAME_PROP_ID:
426 case CERT_HASH_PROP_ID:
427 case CERT_KEY_IDENTIFIER_PROP_ID:
428 case CERT_MD5_HASH_PROP_ID:
429 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
430 case CERT_PUBKEY_ALG_PARA_PROP_ID:
431 case CERT_PVK_FILE_PROP_ID:
432 case CERT_SIGNATURE_HASH_PROP_ID:
433 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
434 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
435 case CERT_ENROLLMENT_PROP_ID:
436 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
437 case CERT_RENEWAL_PROP_ID:
439 CRYPT_DATA_BLOB blob = { hdr->cb,
440 (LPBYTE)pbElement };
442 ret = contextInterface->setProp(context,
443 hdr->propID, 0, &blob);
444 break;
446 case CERT_DATE_STAMP_PROP_ID:
447 ret = contextInterface->setProp(context,
448 hdr->propID, 0, pbElement);
449 break;
450 case CERT_KEY_PROV_INFO_PROP_ID:
452 CRYPT_KEY_PROV_INFO *info;
454 if (read_serialized_KeyProvInfoProperty((const struct store_CRYPT_KEY_PROV_INFO *)pbElement, &info))
456 ret = contextInterface->setProp(context, hdr->propID, 0, info);
457 CryptMemFree(info);
459 else
460 ret = FALSE;
461 break;
463 case CERT_KEY_CONTEXT_PROP_ID:
465 CERT_KEY_CONTEXT ctx;
466 CRYPT_ConvertKeyContext((struct store_CERT_KEY_CONTEXT *)pbElement, &ctx);
467 ret = contextInterface->setProp(context, hdr->propID, 0, &ctx);
468 break;
470 default:
471 ret = FALSE;
474 else
476 /* ignore the context itself */
477 ret = TRUE;
479 return ret;
482 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
483 DWORD dwContextTypeFlags, DWORD *pdwContentType)
485 const void *context;
487 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
488 pdwContentType);
490 if (!cbElement)
492 SetLastError(ERROR_END_OF_MEDIA);
493 return NULL;
496 __TRY
498 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
499 const WINE_CERT_PROP_HEADER *hdr = NULL;
500 DWORD type = 0;
501 BOOL ret;
503 ret = TRUE;
504 context = NULL;
505 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
507 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
508 if (hdr)
509 type = CERT_STORE_CERTIFICATE_CONTEXT;
510 else
512 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
513 if (hdr)
514 type = CERT_STORE_CRL_CONTEXT;
515 else
517 hdr = CRYPT_findPropID(pbElement, cbElement,
518 CERT_CTL_PROP_ID);
519 if (hdr)
520 type = CERT_STORE_CTL_CONTEXT;
524 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
526 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
527 type = CERT_STORE_CERTIFICATE_CONTEXT;
529 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
531 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
532 type = CERT_STORE_CRL_CONTEXT;
534 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
536 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
537 type = CERT_STORE_CTL_CONTEXT;
540 switch (type)
542 case CERT_STORE_CERTIFICATE_CONTEXT:
543 contextInterface = pCertInterface;
544 break;
545 case CERT_STORE_CRL_CONTEXT:
546 contextInterface = pCRLInterface;
547 break;
548 case CERT_STORE_CTL_CONTEXT:
549 contextInterface = pCTLInterface;
550 break;
551 default:
552 SetLastError(E_INVALIDARG);
553 ret = FALSE;
555 if (!hdr)
556 ret = FALSE;
558 if (ret)
559 context = contextInterface->create(X509_ASN_ENCODING,
560 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
561 if (ret && context)
563 BOOL noMoreProps = FALSE;
565 while (!noMoreProps && ret)
567 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
568 ret = FALSE;
569 else
571 const WINE_CERT_PROP_HEADER *hdr =
572 (const WINE_CERT_PROP_HEADER *)pbElement;
574 TRACE("prop is %ld\n", hdr->propID);
575 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
576 pbElement += sizeof(WINE_CERT_PROP_HEADER);
577 if (!hdr->propID)
579 /* Like in CRYPT_findPropID, stop if the propID is zero
581 noMoreProps = TRUE;
583 else
584 ret = CRYPT_ReadContextProp(contextInterface, context,
585 hdr, pbElement, cbElement);
586 pbElement += hdr->cb;
587 cbElement -= hdr->cb;
588 if (!cbElement)
589 noMoreProps = TRUE;
592 if (ret)
594 if (pdwContentType)
595 *pdwContentType = type;
597 else
599 Context_Release(context_from_ptr(context));
600 context = NULL;
604 __EXCEPT_PAGE_FAULT
606 SetLastError(STATUS_ACCESS_VIOLATION);
607 context = NULL;
609 __ENDTRY
610 return context;
613 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
615 typedef BOOL (*read_serialized_func)(void *handle, void *buffer,
616 DWORD bytesToRead, DWORD *bytesRead);
618 static BOOL CRYPT_ReadSerializedStore(void *handle,
619 read_serialized_func read_func, HCERTSTORE store)
621 BYTE fileHeaderBuf[sizeof(fileHeader)];
622 DWORD read;
623 BOOL ret;
625 /* Failure reading is non-critical, we'll leave the store empty */
626 ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read);
627 if (ret)
629 if (!read)
630 ; /* an empty file is okay */
631 else if (read != sizeof(fileHeaderBuf))
632 ret = FALSE;
633 else if (!memcmp(fileHeaderBuf, fileHeader, read))
635 WINE_CERT_PROP_HEADER propHdr;
636 const void *context = NULL;
637 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
638 LPBYTE buf = NULL;
639 DWORD bufSize = 0;
641 do {
642 ret = read_func(handle, &propHdr, sizeof(propHdr), &read);
643 if (ret && read == sizeof(propHdr))
645 if (contextInterface && context &&
646 (propHdr.propID == CERT_CERT_PROP_ID ||
647 propHdr.propID == CERT_CRL_PROP_ID ||
648 propHdr.propID == CERT_CTL_PROP_ID))
650 /* We have a new context, so free the existing one */
651 Context_Release(context_from_ptr(context));
653 if (propHdr.cb > bufSize)
655 /* Not reusing realloc, because the old data aren't
656 * needed any longer.
658 CryptMemFree(buf);
659 buf = CryptMemAlloc(propHdr.cb);
660 bufSize = propHdr.cb;
662 if (!propHdr.cb)
663 ; /* Property is empty, nothing to do */
664 else if (buf)
666 ret = read_func(handle, buf, propHdr.cb, &read);
667 if (ret && read == propHdr.cb)
669 if (propHdr.propID == CERT_CERT_PROP_ID)
671 contextInterface = pCertInterface;
672 ret = contextInterface->addEncodedToStore(store,
673 X509_ASN_ENCODING, buf, read,
674 CERT_STORE_ADD_NEW, &context);
676 else if (propHdr.propID == CERT_CRL_PROP_ID)
678 contextInterface = pCRLInterface;
679 ret = contextInterface->addEncodedToStore(store,
680 X509_ASN_ENCODING, buf, read,
681 CERT_STORE_ADD_NEW, &context);
683 else if (propHdr.propID == CERT_CTL_PROP_ID)
685 contextInterface = pCTLInterface;
686 ret = contextInterface->addEncodedToStore(store,
687 X509_ASN_ENCODING, buf, read,
688 CERT_STORE_ADD_NEW, &context);
690 else
692 if (!contextInterface)
694 WARN("prop id %ld before a context id\n",
695 propHdr.propID);
696 ret = FALSE;
698 else
699 ret = CRYPT_ReadContextProp(
700 contextInterface, context, &propHdr, buf,
701 read);
705 else
706 ret = FALSE;
708 } while (ret && read > 0 && propHdr.cb);
709 if (contextInterface && context)
711 /* Free the last context added */
712 Context_Release(context_from_ptr(context));
714 CryptMemFree(buf);
715 ret = TRUE;
717 else
718 ret = FALSE;
720 else
721 ret = TRUE;
722 return ret;
725 static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead,
726 DWORD *bytesRead)
728 return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL);
731 BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
733 return CRYPT_ReadSerializedStore(file, read_file_wrapper, store);
736 struct BlobReader
738 const CRYPT_DATA_BLOB *blob;
739 DWORD current;
742 static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead,
743 DWORD *bytesRead)
745 struct BlobReader *reader = handle;
746 BOOL ret;
748 if (reader->current < reader->blob->cbData)
750 *bytesRead = min(bytesToRead, reader->blob->cbData - reader->current);
751 memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead);
752 reader->current += *bytesRead;
753 ret = TRUE;
755 else if (reader->current == reader->blob->cbData)
757 *bytesRead = 0;
758 ret = TRUE;
760 else
761 ret = FALSE;
762 return ret;
765 BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
766 HCERTSTORE store)
768 struct BlobReader reader = { blob, 0 };
770 return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store);
773 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
774 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
776 return CRYPT_SerializeStoreElement(pCertContext,
777 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
778 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
781 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
782 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
784 return CRYPT_SerializeStoreElement(pCrlContext,
785 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
786 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
789 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
790 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
792 return CRYPT_SerializeStoreElement(pCtlContext,
793 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
794 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
797 typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer,
798 DWORD size);
800 static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output,
801 void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
803 const void *context = NULL;
804 BOOL ret;
806 do {
807 context = contextInterface->enumContextsInStore(store, context);
808 if (context)
810 DWORD size = 0;
811 LPBYTE buf = NULL;
813 ret = contextInterface->serialize(context, 0, NULL, &size);
814 if (size)
815 buf = CryptMemAlloc(size);
816 if (buf)
818 ret = contextInterface->serialize(context, 0, buf, &size);
819 if (ret)
820 ret = output(handle, buf, size);
822 CryptMemFree(buf);
824 else
825 ret = TRUE;
826 } while (ret && context != NULL);
827 if (context)
828 Context_Release(context_from_ptr(context));
829 return ret;
832 static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store,
833 SerializedOutputFunc output, void *handle)
835 static const BYTE fileTrailer[12] = { 0 };
836 WINE_CONTEXT_INTERFACE interface;
837 BOOL ret;
839 ret = output(handle, fileHeader, sizeof(fileHeader));
840 if (ret)
842 interface = *pCertInterface;
843 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
844 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
845 store);
847 if (ret)
849 interface = *pCRLInterface;
850 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
851 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
852 store);
854 if (ret)
856 interface = *pCTLInterface;
857 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
858 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
859 store);
861 if (ret)
862 ret = output(handle, fileTrailer, sizeof(fileTrailer));
863 return ret;
866 static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size)
868 return WriteFile(handle, buffer, size, &size, NULL);
871 static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store)
873 SetFilePointer(file, 0, NULL, FILE_BEGIN);
874 return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc,
875 file);
878 static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store,
879 DWORD dwMsgAndCertEncodingType, void *handle)
881 CERT_BLOB *blob = handle;
882 CRYPT_SIGNED_INFO signedInfo = { 0 };
883 PCCERT_CONTEXT cert = NULL;
884 PCCRL_CONTEXT crl = NULL;
885 DWORD size;
886 BOOL ret = TRUE;
888 TRACE("(%ld, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData);
890 do {
891 cert = CertEnumCertificatesInStore(store, cert);
892 if (cert)
893 signedInfo.cCertEncoded++;
894 } while (cert);
895 if (signedInfo.cCertEncoded)
897 signedInfo.rgCertEncoded = CryptMemAlloc(
898 signedInfo.cCertEncoded * sizeof(CERT_BLOB));
899 if (!signedInfo.rgCertEncoded)
901 SetLastError(ERROR_OUTOFMEMORY);
902 ret = FALSE;
904 else
906 DWORD i = 0;
908 do {
909 cert = CertEnumCertificatesInStore(store, cert);
910 if (cert)
912 signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded;
913 signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded;
914 i++;
916 } while (cert);
920 do {
921 crl = CertEnumCRLsInStore(store, crl);
922 if (crl)
923 signedInfo.cCrlEncoded++;
924 } while (crl);
925 if (signedInfo.cCrlEncoded)
927 signedInfo.rgCrlEncoded = CryptMemAlloc(
928 signedInfo.cCrlEncoded * sizeof(CERT_BLOB));
929 if (!signedInfo.rgCrlEncoded)
931 SetLastError(ERROR_OUTOFMEMORY);
932 ret = FALSE;
934 else
936 DWORD i = 0;
938 do {
939 crl = CertEnumCRLsInStore(store, crl);
940 if (crl)
942 signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded;
943 signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded;
944 i++;
946 } while (crl);
949 if (ret)
951 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, NULL, &size);
952 if (ret)
954 if (!blob->pbData)
955 blob->cbData = size;
956 else if (blob->cbData < size)
958 blob->cbData = size;
959 SetLastError(ERROR_MORE_DATA);
960 ret = FALSE;
962 else
964 blob->cbData = size;
965 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, blob->pbData,
966 &blob->cbData);
970 CryptMemFree(signedInfo.rgCertEncoded);
971 CryptMemFree(signedInfo.rgCrlEncoded);
972 TRACE("returning %d\n", ret);
973 return ret;
976 static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store,
977 DWORD dwMsgAndCertEncodingType, void *handle)
979 CERT_BLOB blob = { 0, NULL };
980 BOOL ret;
982 TRACE("(%p)\n", handle);
984 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
985 if (ret)
987 blob.pbData = CryptMemAlloc(blob.cbData);
988 if (blob.pbData)
990 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
991 if (ret)
992 ret = WriteFile(handle, blob.pbData, blob.cbData,
993 &blob.cbData, NULL);
995 else
997 SetLastError(ERROR_OUTOFMEMORY);
998 ret = FALSE;
1001 TRACE("returning %d\n", ret);
1002 return ret;
1005 static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store,
1006 DWORD dwMsgAndCertEncodingType, void *handle)
1008 return CRYPT_WriteSerializedStoreToFile(handle, store);
1011 struct MemWrittenTracker
1013 DWORD cbData;
1014 BYTE *pbData;
1015 DWORD written;
1018 /* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */
1019 static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size)
1021 struct MemWrittenTracker *tracker = handle;
1022 BOOL ret;
1024 if (tracker->written + size > tracker->cbData)
1026 SetLastError(ERROR_MORE_DATA);
1027 /* Update written so caller can notify its caller of the required size
1029 tracker->written += size;
1030 ret = FALSE;
1032 else
1034 memcpy(tracker->pbData + tracker->written, buffer, size);
1035 tracker->written += size;
1036 ret = TRUE;
1038 return ret;
1041 static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer,
1042 DWORD size)
1044 *(DWORD *)handle += size;
1045 return TRUE;
1048 static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store,
1049 DWORD dwMsgAndCertEncodingType, void *handle)
1051 CERT_BLOB *blob = handle;
1052 DWORD size = 0;
1053 BOOL ret;
1055 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes,
1056 &size);
1057 if (ret)
1059 if (!blob->pbData)
1060 blob->cbData = size;
1061 else if (blob->cbData < size)
1063 SetLastError(ERROR_MORE_DATA);
1064 blob->cbData = size;
1065 ret = FALSE;
1067 else
1069 struct MemWrittenTracker tracker = { blob->cbData, blob->pbData,
1070 0 };
1072 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc,
1073 &tracker);
1074 if (!ret && GetLastError() == ERROR_MORE_DATA)
1075 blob->cbData = tracker.written;
1078 TRACE("returning %d\n", ret);
1079 return ret;
1082 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1083 DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags)
1085 BOOL (*saveFunc)(HCERTSTORE, DWORD, void *);
1086 void *handle;
1087 BOOL ret, closeFile = TRUE;
1089 TRACE("(%p, %08lx, %ld, %ld, %p, %08lx)\n", hCertStore,
1090 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1092 switch (dwSaveAs)
1094 case CERT_STORE_SAVE_AS_STORE:
1095 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
1096 saveFunc = CRYPT_SaveSerializedToMem;
1097 else
1098 saveFunc = CRYPT_SaveSerializedToFile;
1099 break;
1100 case CERT_STORE_SAVE_AS_PKCS7:
1101 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
1102 saveFunc = CRYPT_SavePKCSToMem;
1103 else
1104 saveFunc = CRYPT_SavePKCSToFile;
1105 break;
1106 default:
1107 WARN("unimplemented for %ld\n", dwSaveAs);
1108 SetLastError(ERROR_INVALID_PARAMETER);
1109 return FALSE;
1111 switch (dwSaveTo)
1113 case CERT_STORE_SAVE_TO_FILE:
1114 handle = pvSaveToPara;
1115 closeFile = FALSE;
1116 break;
1117 case CERT_STORE_SAVE_TO_FILENAME_A:
1118 handle = CreateFileA(pvSaveToPara, GENERIC_WRITE, 0, NULL,
1119 CREATE_ALWAYS, 0, NULL);
1120 break;
1121 case CERT_STORE_SAVE_TO_FILENAME_W:
1122 handle = CreateFileW(pvSaveToPara, GENERIC_WRITE, 0, NULL,
1123 CREATE_ALWAYS, 0, NULL);
1124 break;
1125 case CERT_STORE_SAVE_TO_MEMORY:
1126 handle = pvSaveToPara;
1127 break;
1128 default:
1129 WARN("unimplemented for %ld\n", dwSaveTo);
1130 SetLastError(ERROR_INVALID_PARAMETER);
1131 return FALSE;
1133 ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle);
1134 if (closeFile)
1135 CloseHandle(handle);
1136 TRACE("returning %d\n", ret);
1137 return ret;
1140 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
1141 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
1142 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
1144 const void *context;
1145 DWORD type;
1146 BOOL ret;
1148 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
1149 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
1150 pdwContentType, ppvContext);
1152 /* Call the internal function, then delete the hashes. Tests show this
1153 * function uses real hash values, not whatever's stored in the hash
1154 * property.
1156 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
1157 dwContextTypeFlags, &type);
1158 if (context)
1160 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
1162 switch (type)
1164 case CERT_STORE_CERTIFICATE_CONTEXT:
1165 contextInterface = pCertInterface;
1166 break;
1167 case CERT_STORE_CRL_CONTEXT:
1168 contextInterface = pCRLInterface;
1169 break;
1170 case CERT_STORE_CTL_CONTEXT:
1171 contextInterface = pCTLInterface;
1172 break;
1173 default:
1174 SetLastError(E_INVALIDARG);
1176 if (contextInterface)
1178 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
1179 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
1180 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
1181 NULL);
1182 if (pdwContentType)
1183 *pdwContentType = type;
1184 ret = contextInterface->addContextToStore(hCertStore, context,
1185 dwAddDisposition, ppvContext);
1186 Context_Release(context_from_ptr(context));
1188 else
1189 ret = FALSE;
1191 else
1192 ret = FALSE;
1193 return ret;