* Sync up to trunk r55544.
[reactos.git] / dll / win32 / crypt32 / serialize.c
1 /*
2 * Copyright 2004-2007 Juan Lang
3 *
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.
8 *
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.
13 *
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
17 */
18
19 #include "config.h"
20 #include "wine/port.h"
21
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"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31
32 /* An extended certificate property in serialized form is prefixed by this
33 * header.
34 */
35 typedef struct _WINE_CERT_PROP_HEADER
36 {
37 DWORD propID;
38 DWORD unknown; /* always 1 */
39 DWORD cb;
40 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
41
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)
46 {
47 BOOL ret;
48
49 TRACE("(%p, %p, %08x, %d, %p, %p)\n", context, contextInterface, dwFlags,
50 omitHashes, pbElement, pcbElement);
51
52 if (context)
53 {
54 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
55 DWORD prop = 0;
56
57 ret = TRUE;
58 do {
59 prop = contextInterface->enumProps(context, prop);
60 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
61 {
62 DWORD propSize = 0;
63
64 ret = contextInterface->getProp(context, prop, NULL, &propSize);
65 if (ret)
66 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
67 }
68 } while (ret && prop != 0);
69
70 if (!pbElement)
71 {
72 *pcbElement = bytesNeeded;
73 ret = TRUE;
74 }
75 else if (*pcbElement < bytesNeeded)
76 {
77 *pcbElement = bytesNeeded;
78 SetLastError(ERROR_MORE_DATA);
79 ret = FALSE;
80 }
81 else
82 {
83 PWINE_CERT_PROP_HEADER hdr;
84 DWORD bufSize = 0;
85 LPBYTE buf = NULL;
86
87 prop = 0;
88 do {
89 prop = contextInterface->enumProps(context, prop);
90 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
91 {
92 DWORD propSize = 0;
93
94 ret = contextInterface->getProp(context, prop, NULL,
95 &propSize);
96 if (ret)
97 {
98 if (bufSize < propSize)
99 {
100 if (buf)
101 buf = CryptMemRealloc(buf, propSize);
102 else
103 buf = CryptMemAlloc(propSize);
104 bufSize = propSize;
105 }
106 if (buf)
107 {
108 ret = contextInterface->getProp(context, prop, buf,
109 &propSize);
110 if (ret)
111 {
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)
118 {
119 memcpy(pbElement, buf, propSize);
120 pbElement += propSize;
121 }
122 }
123 }
124 else
125 ret = FALSE;
126 }
127 }
128 } while (ret && prop != 0);
129 CryptMemFree(buf);
130
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);
137 }
138 }
139 else
140 ret = FALSE;
141 return ret;
142 }
143
144 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
145 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
146 {
147 return CRYPT_SerializeStoreElement(pCertContext,
148 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
149 CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
150 }
151
152 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
153 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
154 {
155 return CRYPT_SerializeStoreElement(pCrlContext,
156 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
157 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
158 }
159
160 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
161 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
162 {
163 return CRYPT_SerializeStoreElement(pCtlContext,
164 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
165 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
166 }
167
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 the property won't overrun buf, and the unknown field is 1.
171 */
172 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
173 DWORD size, DWORD propID)
174 {
175 const WINE_CERT_PROP_HEADER *ret = NULL;
176 BOOL done = FALSE;
177
178 while (size && !ret && !done)
179 {
180 if (size < sizeof(WINE_CERT_PROP_HEADER))
181 {
182 SetLastError(CRYPT_E_FILE_ERROR);
183 done = TRUE;
184 }
185 else
186 {
187 const WINE_CERT_PROP_HEADER *hdr =
188 (const WINE_CERT_PROP_HEADER *)buf;
189
190 size -= sizeof(WINE_CERT_PROP_HEADER);
191 buf += sizeof(WINE_CERT_PROP_HEADER);
192 if (size < hdr->cb)
193 {
194 SetLastError(E_INVALIDARG);
195 done = TRUE;
196 }
197 else if (!hdr->propID)
198 {
199 /* assume a zero prop ID means the data are uninitialized, so
200 * stop looking.
201 */
202 done = TRUE;
203 }
204 else if (hdr->unknown != 1)
205 {
206 SetLastError(ERROR_FILE_NOT_FOUND);
207 done = TRUE;
208 }
209 else if (hdr->propID == propID)
210 ret = hdr;
211 else
212 {
213 buf += hdr->cb;
214 size -= hdr->cb;
215 }
216 }
217 }
218 return ret;
219 }
220
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)
224 {
225 BOOL ret;
226
227 if (cbElement < hdr->cb)
228 {
229 SetLastError(E_INVALIDARG);
230 ret = FALSE;
231 }
232 else if (hdr->unknown != 1)
233 {
234 SetLastError(ERROR_FILE_NOT_FOUND);
235 ret = FALSE;
236 }
237 else if (hdr->propID != CERT_CERT_PROP_ID &&
238 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID)
239 {
240 /* Have to create a blob for most types, but not
241 * for all.. arghh.
242 */
243 switch (hdr->propID)
244 {
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:
261 {
262 CRYPT_DATA_BLOB blob = { hdr->cb,
263 (LPBYTE)pbElement };
264
265 ret = contextInterface->setProp(context,
266 hdr->propID, 0, &blob);
267 break;
268 }
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:
274 {
275 PCRYPT_KEY_PROV_INFO info =
276 (PCRYPT_KEY_PROV_INFO)pbElement;
277
278 CRYPT_FixKeyProvInfoPointers(info);
279 ret = contextInterface->setProp(context,
280 hdr->propID, 0, pbElement);
281 break;
282 }
283 default:
284 ret = FALSE;
285 }
286 }
287 else
288 {
289 /* ignore the context itself */
290 ret = TRUE;
291 }
292 return ret;
293 }
294
295 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
296 DWORD dwContextTypeFlags, DWORD *pdwContentType)
297 {
298 const void *context;
299
300 TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags,
301 pdwContentType);
302
303 if (!cbElement)
304 {
305 SetLastError(ERROR_END_OF_MEDIA);
306 return NULL;
307 }
308
309 __TRY
310 {
311 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
312 const WINE_CERT_PROP_HEADER *hdr = NULL;
313 DWORD type = 0;
314 BOOL ret;
315
316 ret = TRUE;
317 context = NULL;
318 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
319 {
320 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
321 if (hdr)
322 type = CERT_STORE_CERTIFICATE_CONTEXT;
323 else
324 {
325 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
326 if (hdr)
327 type = CERT_STORE_CRL_CONTEXT;
328 else
329 {
330 hdr = CRYPT_findPropID(pbElement, cbElement,
331 CERT_CTL_PROP_ID);
332 if (hdr)
333 type = CERT_STORE_CTL_CONTEXT;
334 }
335 }
336 }
337 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
338 {
339 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
340 type = CERT_STORE_CERTIFICATE_CONTEXT;
341 }
342 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
343 {
344 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
345 type = CERT_STORE_CRL_CONTEXT;
346 }
347 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
348 {
349 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
350 type = CERT_STORE_CTL_CONTEXT;
351 }
352
353 switch (type)
354 {
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;
367 }
368 if (!hdr)
369 ret = FALSE;
370
371 if (ret)
372 context = contextInterface->create(X509_ASN_ENCODING,
373 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
374 if (ret && context)
375 {
376 BOOL noMoreProps = FALSE;
377
378 while (!noMoreProps && ret)
379 {
380 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
381 ret = FALSE;
382 else
383 {
384 const WINE_CERT_PROP_HEADER *hdr =
385 (const WINE_CERT_PROP_HEADER *)pbElement;
386
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)
391 {
392 /* Like in CRYPT_findPropID, stop if the propID is zero
393 */
394 noMoreProps = TRUE;
395 }
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;
403 }
404 }
405 if (ret)
406 {
407 if (pdwContentType)
408 *pdwContentType = type;
409 }
410 else
411 {
412 contextInterface->free(context);
413 context = NULL;
414 }
415 }
416 }
417 __EXCEPT_PAGE_FAULT
418 {
419 SetLastError(STATUS_ACCESS_VIOLATION);
420 context = NULL;
421 }
422 __ENDTRY
423 return context;
424 }
425
426 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
427
428 typedef BOOL (*read_serialized_func)(void *handle, void *buffer,
429 DWORD bytesToRead, DWORD *bytesRead);
430
431 static BOOL CRYPT_ReadSerializedStore(void *handle,
432 read_serialized_func read_func, HCERTSTORE store)
433 {
434 BYTE fileHeaderBuf[sizeof(fileHeader)];
435 DWORD read;
436 BOOL ret;
437
438 /* Failure reading is non-critical, we'll leave the store empty */
439 ret = read_func(handle, fileHeaderBuf, sizeof(fileHeaderBuf), &read);
440 if (ret)
441 {
442 if (!read)
443 ; /* an empty file is okay */
444 else if (read != sizeof(fileHeaderBuf))
445 ret = FALSE;
446 else if (!memcmp(fileHeaderBuf, fileHeader, read))
447 {
448 WINE_CERT_PROP_HEADER propHdr;
449 const void *context = NULL;
450 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
451 LPBYTE buf = NULL;
452 DWORD bufSize = 0;
453
454 do {
455 ret = read_func(handle, &propHdr, sizeof(propHdr), &read);
456 if (ret && read == sizeof(propHdr))
457 {
458 if (contextInterface && context &&
459 (propHdr.propID == CERT_CERT_PROP_ID ||
460 propHdr.propID == CERT_CRL_PROP_ID ||
461 propHdr.propID == CERT_CTL_PROP_ID))
462 {
463 /* We have a new context, so free the existing one */
464 contextInterface->free(context);
465 }
466 if (propHdr.cb > bufSize)
467 {
468 /* Not reusing realloc, because the old data aren't
469 * needed any longer.
470 */
471 CryptMemFree(buf);
472 buf = CryptMemAlloc(propHdr.cb);
473 bufSize = propHdr.cb;
474 }
475 if (!propHdr.cb)
476 ; /* Property is empty, nothing to do */
477 else if (buf)
478 {
479 ret = read_func(handle, buf, propHdr.cb, &read);
480 if (ret && read == propHdr.cb)
481 {
482 if (propHdr.propID == CERT_CERT_PROP_ID)
483 {
484 contextInterface = pCertInterface;
485 ret = contextInterface->addEncodedToStore(store,
486 X509_ASN_ENCODING, buf, read,
487 CERT_STORE_ADD_NEW, &context);
488 }
489 else if (propHdr.propID == CERT_CRL_PROP_ID)
490 {
491 contextInterface = pCRLInterface;
492 ret = contextInterface->addEncodedToStore(store,
493 X509_ASN_ENCODING, buf, read,
494 CERT_STORE_ADD_NEW, &context);
495 }
496 else if (propHdr.propID == CERT_CTL_PROP_ID)
497 {
498 contextInterface = pCTLInterface;
499 ret = contextInterface->addEncodedToStore(store,
500 X509_ASN_ENCODING, buf, read,
501 CERT_STORE_ADD_NEW, &context);
502 }
503 else
504 {
505 if (!contextInterface)
506 {
507 WARN("prop id %d before a context id\n",
508 propHdr.propID);
509 ret = FALSE;
510 }
511 else
512 ret = CRYPT_ReadContextProp(
513 contextInterface, context, &propHdr, buf,
514 read);
515 }
516 }
517 }
518 else
519 ret = FALSE;
520 }
521 } while (ret && read > 0 && propHdr.cb);
522 if (contextInterface && context)
523 {
524 /* Free the last context added */
525 contextInterface->free(context);
526 }
527 CryptMemFree(buf);
528 ret = TRUE;
529 }
530 else
531 ret = FALSE;
532 }
533 else
534 ret = TRUE;
535 return ret;
536 }
537
538 static BOOL read_file_wrapper(void *handle, void *buffer, DWORD bytesToRead,
539 DWORD *bytesRead)
540 {
541 return ReadFile(handle, buffer, bytesToRead, bytesRead, NULL);
542 }
543
544 BOOL CRYPT_ReadSerializedStoreFromFile(HANDLE file, HCERTSTORE store)
545 {
546 return CRYPT_ReadSerializedStore(file, read_file_wrapper, store);
547 }
548
549 struct BlobReader
550 {
551 const CRYPT_DATA_BLOB *blob;
552 DWORD current;
553 };
554
555 static BOOL read_blob_wrapper(void *handle, void *buffer, DWORD bytesToRead,
556 DWORD *bytesRead)
557 {
558 struct BlobReader *reader = handle;
559 BOOL ret;
560
561 if (reader->current < reader->blob->cbData)
562 {
563 *bytesRead = min(bytesToRead, reader->blob->cbData - reader->current);
564 memcpy(buffer, reader->blob->pbData + reader->current, *bytesRead);
565 reader->current += *bytesRead;
566 ret = TRUE;
567 }
568 else if (reader->current == reader->blob->cbData)
569 {
570 *bytesRead = 0;
571 ret = TRUE;
572 }
573 else
574 ret = FALSE;
575 return ret;
576 }
577
578 BOOL CRYPT_ReadSerializedStoreFromBlob(const CRYPT_DATA_BLOB *blob,
579 HCERTSTORE store)
580 {
581 struct BlobReader reader = { blob, 0 };
582
583 return CRYPT_ReadSerializedStore(&reader, read_blob_wrapper, store);
584 }
585
586 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
587 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
588 {
589 return CRYPT_SerializeStoreElement(pCertContext,
590 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
591 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
592 }
593
594 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
595 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
596 {
597 return CRYPT_SerializeStoreElement(pCrlContext,
598 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
599 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
600 }
601
602 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
603 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
604 {
605 return CRYPT_SerializeStoreElement(pCtlContext,
606 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
607 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
608 }
609
610 typedef BOOL (*SerializedOutputFunc)(void *handle, const void *buffer,
611 DWORD size);
612
613 static BOOL CRYPT_SerializeContextsToStream(SerializedOutputFunc output,
614 void *handle, const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
615 {
616 const void *context = NULL;
617 BOOL ret;
618
619 do {
620 context = contextInterface->enumContextsInStore(store, context);
621 if (context)
622 {
623 DWORD size = 0;
624 LPBYTE buf = NULL;
625
626 ret = contextInterface->serialize(context, 0, NULL, &size);
627 if (size)
628 buf = CryptMemAlloc(size);
629 if (buf)
630 {
631 ret = contextInterface->serialize(context, 0, buf, &size);
632 if (ret)
633 ret = output(handle, buf, size);
634 }
635 CryptMemFree(buf);
636 }
637 else
638 ret = TRUE;
639 } while (ret && context != NULL);
640 if (context)
641 contextInterface->free(context);
642 return ret;
643 }
644
645 static BOOL CRYPT_WriteSerializedStoreToStream(HCERTSTORE store,
646 SerializedOutputFunc output, void *handle)
647 {
648 static const BYTE fileTrailer[12] = { 0 };
649 WINE_CONTEXT_INTERFACE interface;
650 BOOL ret;
651
652 ret = output(handle, fileHeader, sizeof(fileHeader));
653 if (ret)
654 {
655 memcpy(&interface, pCertInterface, sizeof(interface));
656 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
657 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
658 store);
659 }
660 if (ret)
661 {
662 memcpy(&interface, pCRLInterface, sizeof(interface));
663 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
664 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
665 store);
666 }
667 if (ret)
668 {
669 memcpy(&interface, pCTLInterface, sizeof(interface));
670 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
671 ret = CRYPT_SerializeContextsToStream(output, handle, &interface,
672 store);
673 }
674 if (ret)
675 ret = output(handle, fileTrailer, sizeof(fileTrailer));
676 return ret;
677 }
678
679 static BOOL CRYPT_FileOutputFunc(void *handle, const void *buffer, DWORD size)
680 {
681 return WriteFile(handle, buffer, size, &size, NULL);
682 }
683
684 static BOOL CRYPT_WriteSerializedStoreToFile(HANDLE file, HCERTSTORE store)
685 {
686 SetFilePointer(file, 0, NULL, FILE_BEGIN);
687 return CRYPT_WriteSerializedStoreToStream(store, CRYPT_FileOutputFunc,
688 file);
689 }
690
691 static BOOL CRYPT_SavePKCSToMem(HCERTSTORE store,
692 DWORD dwMsgAndCertEncodingType, void *handle)
693 {
694 CERT_BLOB *blob = handle;
695 CRYPT_SIGNED_INFO signedInfo = { 0 };
696 PCCERT_CONTEXT cert = NULL;
697 PCCRL_CONTEXT crl = NULL;
698 DWORD size;
699 BOOL ret = TRUE;
700
701 TRACE("(%d, %p)\n", blob->pbData ? blob->cbData : 0, blob->pbData);
702
703 do {
704 cert = CertEnumCertificatesInStore(store, cert);
705 if (cert)
706 signedInfo.cCertEncoded++;
707 } while (cert);
708 if (signedInfo.cCertEncoded)
709 {
710 signedInfo.rgCertEncoded = CryptMemAlloc(
711 signedInfo.cCertEncoded * sizeof(CERT_BLOB));
712 if (!signedInfo.rgCertEncoded)
713 {
714 SetLastError(ERROR_OUTOFMEMORY);
715 ret = FALSE;
716 }
717 else
718 {
719 DWORD i = 0;
720
721 do {
722 cert = CertEnumCertificatesInStore(store, cert);
723 if (cert)
724 {
725 signedInfo.rgCertEncoded[i].cbData = cert->cbCertEncoded;
726 signedInfo.rgCertEncoded[i].pbData = cert->pbCertEncoded;
727 i++;
728 }
729 } while (cert);
730 }
731 }
732
733 do {
734 crl = CertEnumCRLsInStore(store, crl);
735 if (crl)
736 signedInfo.cCrlEncoded++;
737 } while (crl);
738 if (signedInfo.cCrlEncoded)
739 {
740 signedInfo.rgCrlEncoded = CryptMemAlloc(
741 signedInfo.cCrlEncoded * sizeof(CERT_BLOB));
742 if (!signedInfo.rgCrlEncoded)
743 {
744 SetLastError(ERROR_OUTOFMEMORY);
745 ret = FALSE;
746 }
747 else
748 {
749 DWORD i = 0;
750
751 do {
752 crl = CertEnumCRLsInStore(store, crl);
753 if (crl)
754 {
755 signedInfo.rgCrlEncoded[i].cbData = crl->cbCrlEncoded;
756 signedInfo.rgCrlEncoded[i].pbData = crl->pbCrlEncoded;
757 i++;
758 }
759 } while (crl);
760 }
761 }
762 if (ret)
763 {
764 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, NULL, &size);
765 if (ret)
766 {
767 if (!blob->pbData)
768 blob->cbData = size;
769 else if (blob->cbData < size)
770 {
771 blob->cbData = size;
772 SetLastError(ERROR_MORE_DATA);
773 ret = FALSE;
774 }
775 else
776 {
777 blob->cbData = size;
778 ret = CRYPT_AsnEncodeCMSSignedInfo(&signedInfo, blob->pbData,
779 &blob->cbData);
780 }
781 }
782 }
783 CryptMemFree(signedInfo.rgCertEncoded);
784 CryptMemFree(signedInfo.rgCrlEncoded);
785 TRACE("returning %d\n", ret);
786 return ret;
787 }
788
789 static BOOL CRYPT_SavePKCSToFile(HCERTSTORE store,
790 DWORD dwMsgAndCertEncodingType, void *handle)
791 {
792 CERT_BLOB blob = { 0, NULL };
793 BOOL ret;
794
795 TRACE("(%p)\n", handle);
796
797 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
798 if (ret)
799 {
800 blob.pbData = CryptMemAlloc(blob.cbData);
801 if (blob.pbData)
802 {
803 ret = CRYPT_SavePKCSToMem(store, dwMsgAndCertEncodingType, &blob);
804 if (ret)
805 ret = WriteFile(handle, blob.pbData, blob.cbData,
806 &blob.cbData, NULL);
807 }
808 else
809 {
810 SetLastError(ERROR_OUTOFMEMORY);
811 ret = FALSE;
812 }
813 }
814 TRACE("returning %d\n", ret);
815 return ret;
816 }
817
818 static BOOL CRYPT_SaveSerializedToFile(HCERTSTORE store,
819 DWORD dwMsgAndCertEncodingType, void *handle)
820 {
821 return CRYPT_WriteSerializedStoreToFile(handle, store);
822 }
823
824 struct MemWrittenTracker
825 {
826 DWORD cbData;
827 BYTE *pbData;
828 DWORD written;
829 };
830
831 /* handle is a pointer to a MemWrittenTracker. Assumes its pointer is valid. */
832 static BOOL CRYPT_MemOutputFunc(void *handle, const void *buffer, DWORD size)
833 {
834 struct MemWrittenTracker *tracker = handle;
835 BOOL ret;
836
837 if (tracker->written + size > tracker->cbData)
838 {
839 SetLastError(ERROR_MORE_DATA);
840 /* Update written so caller can notify its caller of the required size
841 */
842 tracker->written += size;
843 ret = FALSE;
844 }
845 else
846 {
847 memcpy(tracker->pbData + tracker->written, buffer, size);
848 tracker->written += size;
849 ret = TRUE;
850 }
851 return ret;
852 }
853
854 static BOOL CRYPT_CountSerializedBytes(void *handle, const void *buffer,
855 DWORD size)
856 {
857 *(DWORD *)handle += size;
858 return TRUE;
859 }
860
861 static BOOL CRYPT_SaveSerializedToMem(HCERTSTORE store,
862 DWORD dwMsgAndCertEncodingType, void *handle)
863 {
864 CERT_BLOB *blob = handle;
865 DWORD size = 0;
866 BOOL ret;
867
868 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_CountSerializedBytes,
869 &size);
870 if (ret)
871 {
872 if (!blob->pbData)
873 blob->cbData = size;
874 else if (blob->cbData < size)
875 {
876 SetLastError(ERROR_MORE_DATA);
877 blob->cbData = size;
878 ret = FALSE;
879 }
880 else
881 {
882 struct MemWrittenTracker tracker = { blob->cbData, blob->pbData,
883 0 };
884
885 ret = CRYPT_WriteSerializedStoreToStream(store, CRYPT_MemOutputFunc,
886 &tracker);
887 if (!ret && GetLastError() == ERROR_MORE_DATA)
888 blob->cbData = tracker.written;
889 }
890 }
891 TRACE("returning %d\n", ret);
892 return ret;
893 }
894
895 BOOL WINAPI CertSaveStore(HCERTSTORE hCertStore, DWORD dwMsgAndCertEncodingType,
896 DWORD dwSaveAs, DWORD dwSaveTo, void *pvSaveToPara, DWORD dwFlags)
897 {
898 BOOL (*saveFunc)(HCERTSTORE, DWORD, void *);
899 void *handle;
900 BOOL ret, closeFile = TRUE;
901
902 TRACE("(%p, %08x, %d, %d, %p, %08x)\n", hCertStore,
903 dwMsgAndCertEncodingType, dwSaveAs, dwSaveTo, pvSaveToPara, dwFlags);
904
905 switch (dwSaveAs)
906 {
907 case CERT_STORE_SAVE_AS_STORE:
908 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
909 saveFunc = CRYPT_SaveSerializedToMem;
910 else
911 saveFunc = CRYPT_SaveSerializedToFile;
912 break;
913 case CERT_STORE_SAVE_AS_PKCS7:
914 if (dwSaveTo == CERT_STORE_SAVE_TO_MEMORY)
915 saveFunc = CRYPT_SavePKCSToMem;
916 else
917 saveFunc = CRYPT_SavePKCSToFile;
918 break;
919 default:
920 WARN("unimplemented for %d\n", dwSaveAs);
921 SetLastError(ERROR_INVALID_PARAMETER);
922 return FALSE;
923 }
924 switch (dwSaveTo)
925 {
926 case CERT_STORE_SAVE_TO_FILE:
927 handle = pvSaveToPara;
928 closeFile = FALSE;
929 break;
930 case CERT_STORE_SAVE_TO_FILENAME_A:
931 handle = CreateFileA(pvSaveToPara, GENERIC_WRITE, 0, NULL,
932 CREATE_ALWAYS, 0, NULL);
933 break;
934 case CERT_STORE_SAVE_TO_FILENAME_W:
935 handle = CreateFileW(pvSaveToPara, GENERIC_WRITE, 0, NULL,
936 CREATE_ALWAYS, 0, NULL);
937 break;
938 case CERT_STORE_SAVE_TO_MEMORY:
939 handle = pvSaveToPara;
940 break;
941 default:
942 WARN("unimplemented for %d\n", dwSaveTo);
943 SetLastError(ERROR_INVALID_PARAMETER);
944 return FALSE;
945 }
946 ret = saveFunc(hCertStore, dwMsgAndCertEncodingType, handle);
947 if (closeFile)
948 CloseHandle(handle);
949 TRACE("returning %d\n", ret);
950 return ret;
951 }
952
953 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
954 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
955 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
956 {
957 const void *context;
958 DWORD type;
959 BOOL ret;
960
961 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore,
962 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
963 pdwContentType, ppvContext);
964
965 /* Call the internal function, then delete the hashes. Tests show this
966 * function uses real hash values, not whatever's stored in the hash
967 * property.
968 */
969 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
970 dwContextTypeFlags, &type);
971 if (context)
972 {
973 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
974
975 switch (type)
976 {
977 case CERT_STORE_CERTIFICATE_CONTEXT:
978 contextInterface = pCertInterface;
979 break;
980 case CERT_STORE_CRL_CONTEXT:
981 contextInterface = pCRLInterface;
982 break;
983 case CERT_STORE_CTL_CONTEXT:
984 contextInterface = pCTLInterface;
985 break;
986 default:
987 SetLastError(E_INVALIDARG);
988 }
989 if (contextInterface)
990 {
991 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
992 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
993 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
994 NULL);
995 if (pdwContentType)
996 *pdwContentType = type;
997 ret = contextInterface->addContextToStore(hCertStore, context,
998 dwAddDisposition, ppvContext);
999 contextInterface->free(context);
1000 }
1001 else
1002 ret = FALSE;
1003 }
1004 else
1005 ret = FALSE;
1006 return ret;
1007 }