hidclass.sys: Pass sizeof(packet) as input for IOCTL_HID_SET_OUTPUT_REPORT.
[wine.git] / dlls / crypt32 / serialize.c
blob8fa24370b6559d1597da9de38a8dcc0f1801f839
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 = HeapAlloc(GetProcessHeap(), 0, 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, %08x, %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 = HeapAlloc(GetProcessHeap(), 0, 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,%u,%08x,%u,%p,%u\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_CERT_PROP_ID &&
409 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID)
411 /* Have to create a blob for most types, but not
412 * for all.. arghh.
414 switch (hdr->propID)
416 case CERT_AUTO_ENROLL_PROP_ID:
417 case CERT_CTL_USAGE_PROP_ID:
418 case CERT_DESCRIPTION_PROP_ID:
419 case CERT_FRIENDLY_NAME_PROP_ID:
420 case CERT_HASH_PROP_ID:
421 case CERT_KEY_IDENTIFIER_PROP_ID:
422 case CERT_MD5_HASH_PROP_ID:
423 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
424 case CERT_PUBKEY_ALG_PARA_PROP_ID:
425 case CERT_PVK_FILE_PROP_ID:
426 case CERT_SIGNATURE_HASH_PROP_ID:
427 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
428 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
429 case CERT_ENROLLMENT_PROP_ID:
430 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
431 case CERT_RENEWAL_PROP_ID:
433 CRYPT_DATA_BLOB blob = { hdr->cb,
434 (LPBYTE)pbElement };
436 ret = contextInterface->setProp(context,
437 hdr->propID, 0, &blob);
438 break;
440 case CERT_DATE_STAMP_PROP_ID:
441 ret = contextInterface->setProp(context,
442 hdr->propID, 0, pbElement);
443 break;
444 case CERT_KEY_PROV_INFO_PROP_ID:
446 CRYPT_KEY_PROV_INFO *info;
448 if (read_serialized_KeyProvInfoProperty((const struct store_CRYPT_KEY_PROV_INFO *)pbElement, &info))
450 ret = contextInterface->setProp(context, hdr->propID, 0, info);
451 CryptMemFree(info);
453 else
454 ret = FALSE;
455 break;
457 case CERT_KEY_CONTEXT_PROP_ID:
459 CERT_KEY_CONTEXT ctx;
460 CRYPT_ConvertKeyContext((struct store_CERT_KEY_CONTEXT *)pbElement, &ctx);
461 ret = contextInterface->setProp(context, hdr->propID, 0, &ctx);
462 break;
464 default:
465 ret = FALSE;
468 else
470 /* ignore the context itself */
471 ret = TRUE;
473 return ret;
476 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
477 DWORD dwContextTypeFlags, DWORD *pdwContentType)
479 const void *context;
481 TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags,
482 pdwContentType);
484 if (!cbElement)
486 SetLastError(ERROR_END_OF_MEDIA);
487 return NULL;
490 __TRY
492 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
493 const WINE_CERT_PROP_HEADER *hdr = NULL;
494 DWORD type = 0;
495 BOOL ret;
497 ret = TRUE;
498 context = NULL;
499 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
501 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
502 if (hdr)
503 type = CERT_STORE_CERTIFICATE_CONTEXT;
504 else
506 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
507 if (hdr)
508 type = CERT_STORE_CRL_CONTEXT;
509 else
511 hdr = CRYPT_findPropID(pbElement, cbElement,
512 CERT_CTL_PROP_ID);
513 if (hdr)
514 type = CERT_STORE_CTL_CONTEXT;
518 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
520 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
521 type = CERT_STORE_CERTIFICATE_CONTEXT;
523 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
525 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
526 type = CERT_STORE_CRL_CONTEXT;
528 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
530 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
531 type = CERT_STORE_CTL_CONTEXT;
534 switch (type)
536 case CERT_STORE_CERTIFICATE_CONTEXT:
537 contextInterface = pCertInterface;
538 break;
539 case CERT_STORE_CRL_CONTEXT:
540 contextInterface = pCRLInterface;
541 break;
542 case CERT_STORE_CTL_CONTEXT:
543 contextInterface = pCTLInterface;
544 break;
545 default:
546 SetLastError(E_INVALIDARG);
547 ret = FALSE;
549 if (!hdr)
550 ret = FALSE;
552 if (ret)
553 context = contextInterface->create(X509_ASN_ENCODING,
554 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
555 if (ret && context)
557 BOOL noMoreProps = FALSE;
559 while (!noMoreProps && ret)
561 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
562 ret = FALSE;
563 else
565 const WINE_CERT_PROP_HEADER *hdr =
566 (const WINE_CERT_PROP_HEADER *)pbElement;
568 TRACE("prop is %d\n", hdr->propID);
569 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
570 pbElement += sizeof(WINE_CERT_PROP_HEADER);
571 if (!hdr->propID)
573 /* Like in CRYPT_findPropID, stop if the propID is zero
575 noMoreProps = TRUE;
577 else
578 ret = CRYPT_ReadContextProp(contextInterface, context,
579 hdr, pbElement, cbElement);
580 pbElement += hdr->cb;
581 cbElement -= hdr->cb;
582 if (!cbElement)
583 noMoreProps = TRUE;
586 if (ret)
588 if (pdwContentType)
589 *pdwContentType = type;
591 else
593 Context_Release(context_from_ptr(context));
594 context = NULL;
598 __EXCEPT_PAGE_FAULT
600 SetLastError(STATUS_ACCESS_VIOLATION);
601 context = NULL;
603 __ENDTRY
604 return context;
607 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
609 typedef BOOL (*read_serialized_func)(void *handle, void *buffer,
610 DWORD bytesToRead, DWORD *bytesRead);
612 static BOOL CRYPT_ReadSerializedStore(void *handle,
613 read_serialized_func read_func, HCERTSTORE store)
615 BYTE fileHeaderBuf[sizeof(fileHeader)];
616 DWORD read;
617 BOOL ret;
619 /* Failure reading is non-critical, we'll leave the store empty */
620 ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read);
621 if (ret)
623 if (!read)
624 ; /* an empty file is okay */
625 else if (read != sizeof(fileHeaderBuf))
626 ret = FALSE;
627 else if (!memcmp(fileHeaderBuf, fileHeader, read))
629 WINE_CERT_PROP_HEADER propHdr;
630 const void *context = NULL;
631 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
632 LPBYTE buf = NULL;
633 DWORD bufSize = 0;
635 do {
636 ret = read_func(handle, &propHdr, sizeof(propHdr), &read);
637 if (ret && read == sizeof(propHdr))
639 if (contextInterface && context &&
640 (propHdr.propID == CERT_CERT_PROP_ID ||
641 propHdr.propID == CERT_CRL_PROP_ID ||
642 propHdr.propID == CERT_CTL_PROP_ID))
644 /* We have a new context, so free the existing one */
645 Context_Release(context_from_ptr(context));
647 if (propHdr.cb > bufSize)
649 /* Not reusing realloc, because the old data aren't
650 * needed any longer.
652 CryptMemFree(buf);
653 buf = CryptMemAlloc(propHdr.cb);
654 bufSize = propHdr.cb;
656 if (!propHdr.cb)
657 ; /* Property is empty, nothing to do */
658 else if (buf)
660 ret = read_func(handle, buf, propHdr.cb, &read);
661 if (ret && read == propHdr.cb)
663 if (propHdr.propID == CERT_CERT_PROP_ID)
665 contextInterface = pCertInterface;
666 ret = contextInterface->addEncodedToStore(store,
667 X509_ASN_ENCODING, buf, read,
668 CERT_STORE_ADD_NEW, &context);
670 else if (propHdr.propID == CERT_CRL_PROP_ID)
672 contextInterface = pCRLInterface;
673 ret = contextInterface->addEncodedToStore(store,
674 X509_ASN_ENCODING, buf, read,
675 CERT_STORE_ADD_NEW, &context);
677 else if (propHdr.propID == CERT_CTL_PROP_ID)
679 contextInterface = pCTLInterface;
680 ret = contextInterface->addEncodedToStore(store,
681 X509_ASN_ENCODING, buf, read,
682 CERT_STORE_ADD_NEW, &context);
684 else
686 if (!contextInterface)
688 WARN("prop id %d before a context id\n",
689 propHdr.propID);
690 ret = FALSE;
692 else
693 ret = CRYPT_ReadContextProp(
694 contextInterface, context, &propHdr, buf,
695 read);
699 else
700 ret = FALSE;
702 } while (ret && read > 0 && propHdr.cb);
703 if (contextInterface && context)
705 /* Free the last context added */
706 Context_Release(context_from_ptr(context));
708 CryptMemFree(buf);
709 ret = TRUE;
711 else
712 ret = FALSE;
714 else
715 ret = TRUE;
716 return ret;
719 static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead,
720 DWORD *bytesRead)
722 return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL);
725 BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
727 return CRYPT_ReadSerializedStore(file, read_file_wrapper, store);
730 struct BlobReader
732 const CRYPT_DATA_BLOB *blob;
733 DWORD current;
736 static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead,
737 DWORD *bytesRead)
739 struct BlobReader *reader = handle;
740 BOOL ret;
742 if (reader->current < reader->blob->cbData)
744 *bytesRead = min(bytesToRead, reader->blob->cbData - reader->current);
745 memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead);
746 reader->current += *bytesRead;
747 ret = TRUE;
749 else if (reader->current == reader->blob->cbData)
751 *bytesRead = 0;
752 ret = TRUE;
754 else
755 ret = FALSE;
756 return ret;
759 BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
760 HCERTSTORE store)
762 struct BlobReader reader = { blob, 0 };
764 return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store);
767 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
768 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
770 return CRYPT_SerializeStoreElement(pCertContext,
771 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
772 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
775 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
776 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
778 return CRYPT_SerializeStoreElement(pCrlContext,
779 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
780 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
783 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
784 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
786 return CRYPT_SerializeStoreElement(pCtlContext,
787 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
788 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
791 typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer,
792 DWORD size);
794 static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output,
795 void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
797 const void *context = NULL;
798 BOOL ret;
800 do {
801 context = contextInterface->enumContextsInStore(store, context);
802 if (context)
804 DWORD size = 0;
805 LPBYTE buf = NULL;
807 ret = contextInterface->serialize(context, 0, NULL, &size);
808 if (size)
809 buf = CryptMemAlloc(size);
810 if (buf)
812 ret = contextInterface->serialize(context, 0, buf, &size);
813 if (ret)
814 ret = output(handle, buf, size);
816 CryptMemFree(buf);
818 else
819 ret = TRUE;
820 } while (ret && context != NULL);
821 if (context)
822 Context_Release(context_from_ptr(context));
823 return ret;
826 static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store,
827 SerializedOutputFunc output, void *handle)
829 static const BYTE fileTrailer[12] = { 0 };
830 WINE_CONTEXT_INTERFACE interface;
831 BOOL ret;
833 ret = output(handle, fileHeader, sizeof(fileHeader));
834 if (ret)
836 interface = *pCertInterface;
837 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
838 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
839 store);
841 if (ret)
843 interface = *pCRLInterface;
844 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
845 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
846 store);
848 if (ret)
850 interface = *pCTLInterface;
851 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
852 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
853 store);
855 if (ret)
856 ret = output(handle, fileTrailer, sizeof(fileTrailer));
857 return ret;
860 static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size)
862 return WriteFile(handle, buffer, size, &size, NULL);
865 static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store)
867 SetFilePointer(file, 0, NULL, FILE_BEGIN);
868 return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc,
869 file);
872 static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store,
873 DWORD dwMsgAndCertEncodingType, void *handle)
875 CERT_BLOB *blob = handle;
876 CRYPT_SIGNED_INFO signedInfo = { 0 };
877 PCCERT_CONTEXT cert = NULL;
878 PCCRL_CONTEXT crl = NULL;
879 DWORD size;
880 BOOL ret = TRUE;
882 TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData);
884 do {
885 cert = CertEnumCertificatesInStore(store, cert);
886 if (cert)
887 signedInfo.cCertEncoded++;
888 } while (cert);
889 if (signedInfo.cCertEncoded)
891 signedInfo.rgCertEncoded = CryptMemAlloc(
892 signedInfo.cCertEncoded * sizeof(CERT_BLOB));
893 if (!signedInfo.rgCertEncoded)
895 SetLastError(ERROR_OUTOFMEMORY);
896 ret = FALSE;
898 else
900 DWORD i = 0;
902 do {
903 cert = CertEnumCertificatesInStore(store, cert);
904 if (cert)
906 signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded;
907 signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded;
908 i++;
910 } while (cert);
914 do {
915 crl = CertEnumCRLsInStore(store, crl);
916 if (crl)
917 signedInfo.cCrlEncoded++;
918 } while (crl);
919 if (signedInfo.cCrlEncoded)
921 signedInfo.rgCrlEncoded = CryptMemAlloc(
922 signedInfo.cCrlEncoded * sizeof(CERT_BLOB));
923 if (!signedInfo.rgCrlEncoded)
925 SetLastError(ERROR_OUTOFMEMORY);
926 ret = FALSE;
928 else
930 DWORD i = 0;
932 do {
933 crl = CertEnumCRLsInStore(store, crl);
934 if (crl)
936 signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded;
937 signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded;
938 i++;
940 } while (crl);
943 if (ret)
945 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, NULL, &size);
946 if (ret)
948 if (!blob->pbData)
949 blob->cbData = size;
950 else if (blob->cbData < size)
952 blob->cbData = size;
953 SetLastError(ERROR_MORE_DATA);
954 ret = FALSE;
956 else
958 blob->cbData = size;
959 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, blob->pbData,
960 &blob->cbData);
964 CryptMemFree(signedInfo.rgCertEncoded);
965 CryptMemFree(signedInfo.rgCrlEncoded);
966 TRACE("returning %d\n", ret);
967 return ret;
970 static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store,
971 DWORD dwMsgAndCertEncodingType, void *handle)
973 CERT_BLOB blob = { 0, NULL };
974 BOOL ret;
976 TRACE("(%p)\n", handle);
978 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
979 if (ret)
981 blob.pbData = CryptMemAlloc(blob.cbData);
982 if (blob.pbData)
984 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
985 if (ret)
986 ret = WriteFile(handle, blob.pbData, blob.cbData,
987 &blob.cbData, NULL);
989 else
991 SetLastError(ERROR_OUTOFMEMORY);
992 ret = FALSE;
995 TRACE("returning %d\n", ret);
996 return ret;
999 static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store,
1000 DWORD dwMsgAndCertEncodingType, void *handle)
1002 return CRYPT_WriteSerializedStoreToFile(handle, store);
1005 struct MemWrittenTracker
1007 DWORD cbData;
1008 BYTE *pbData;
1009 DWORD written;
1012 /* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */
1013 static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size)
1015 struct MemWrittenTracker *tracker = handle;
1016 BOOL ret;
1018 if (tracker->written + size > tracker->cbData)
1020 SetLastError(ERROR_MORE_DATA);
1021 /* Update written so caller can notify its caller of the required size
1023 tracker->written += size;
1024 ret = FALSE;
1026 else
1028 memcpy(tracker->pbData + tracker->written, buffer, size);
1029 tracker->written += size;
1030 ret = TRUE;
1032 return ret;
1035 static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer,
1036 DWORD size)
1038 *(DWORD *)handle += size;
1039 return TRUE;
1042 static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store,
1043 DWORD dwMsgAndCertEncodingType, void *handle)
1045 CERT_BLOB *blob = handle;
1046 DWORD size = 0;
1047 BOOL ret;
1049 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes,
1050 &size);
1051 if (ret)
1053 if (!blob->pbData)
1054 blob->cbData = size;
1055 else if (blob->cbData < size)
1057 SetLastError(ERROR_MORE_DATA);
1058 blob->cbData = size;
1059 ret = FALSE;
1061 else
1063 struct MemWrittenTracker tracker = { blob->cbData, blob->pbData,
1064 0 };
1066 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc,
1067 &tracker);
1068 if (!ret && GetLastError() == ERROR_MORE_DATA)
1069 blob->cbData = tracker.written;
1072 TRACE("returning %d\n", ret);
1073 return ret;
1076 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
1077 DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags)
1079 BOOL (*saveFunc)(HCERTSTORE, DWORD, void *);
1080 void *handle;
1081 BOOL ret, closeFile = TRUE;
1083 TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore,
1084 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
1086 switch (dwSaveAs)
1088 case CERT_STORE_SAVE_AS_STORE:
1089 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
1090 saveFunc = CRYPT_SaveSerializedToMem;
1091 else
1092 saveFunc = CRYPT_SaveSerializedToFile;
1093 break;
1094 case CERT_STORE_SAVE_AS_PKCS7:
1095 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
1096 saveFunc = CRYPT_SavePKCSToMem;
1097 else
1098 saveFunc = CRYPT_SavePKCSToFile;
1099 break;
1100 default:
1101 WARN("unimplemented for %d\n", dwSaveAs);
1102 SetLastError(ERROR_INVALID_PARAMETER);
1103 return FALSE;
1105 switch (dwSaveTo)
1107 case CERT_STORE_SAVE_TO_FILE:
1108 handle = pvSaveToPara;
1109 closeFile = FALSE;
1110 break;
1111 case CERT_STORE_SAVE_TO_FILENAME_A:
1112 handle = CreateFileA(pvSaveToPara, GENERIC_WRITE, 0, NULL,
1113 CREATE_ALWAYS, 0, NULL);
1114 break;
1115 case CERT_STORE_SAVE_TO_FILENAME_W:
1116 handle = CreateFileW(pvSaveToPara, GENERIC_WRITE, 0, NULL,
1117 CREATE_ALWAYS, 0, NULL);
1118 break;
1119 case CERT_STORE_SAVE_TO_MEMORY:
1120 handle = pvSaveToPara;
1121 break;
1122 default:
1123 WARN("unimplemented for %d\n", dwSaveTo);
1124 SetLastError(ERROR_INVALID_PARAMETER);
1125 return FALSE;
1127 ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle);
1128 if (closeFile)
1129 CloseHandle(handle);
1130 TRACE("returning %d\n", ret);
1131 return ret;
1134 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
1135 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
1136 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
1138 const void *context;
1139 DWORD type;
1140 BOOL ret;
1142 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore,
1143 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
1144 pdwContentType, ppvContext);
1146 /* Call the internal function, then delete the hashes. Tests show this
1147 * function uses real hash values, not whatever's stored in the hash
1148 * property.
1150 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
1151 dwContextTypeFlags, &type);
1152 if (context)
1154 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
1156 switch (type)
1158 case CERT_STORE_CERTIFICATE_CONTEXT:
1159 contextInterface = pCertInterface;
1160 break;
1161 case CERT_STORE_CRL_CONTEXT:
1162 contextInterface = pCRLInterface;
1163 break;
1164 case CERT_STORE_CTL_CONTEXT:
1165 contextInterface = pCTLInterface;
1166 break;
1167 default:
1168 SetLastError(E_INVALIDARG);
1170 if (contextInterface)
1172 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
1173 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
1174 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
1175 NULL);
1176 if (pdwContentType)
1177 *pdwContentType = type;
1178 ret = contextInterface->addContextToStore(hCertStore, context,
1179 dwAddDisposition, ppvContext);
1180 Context_Release(context_from_ptr(context));
1182 else
1183 ret = FALSE;
1185 else
1186 ret = FALSE;
1187 return ret;