source: trunk/src/crypt32/serialize.c@ 21354

Last change on this file since 21354 was 21354, checked in by rlwalsh, 16 years ago

eliminate VACPP warning & info msgs - see Ticket #1

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