makefiles: Generate the dependencies line to avoid some code duplication.
[wine.git] / dlls / crypt32 / serialize.c
blob8d25eaa06e8472500e68e7c1e225881154c9d197
1 /*
2 * Copyright 2004-2006 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
18 #include <stdarg.h>
19 #include "windef.h"
20 #include "winbase.h"
21 #include "wincrypt.h"
22 #include "wine/debug.h"
23 #include "excpt.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, *PWINE_CERT_PROP_HEADER;
39 static BOOL CRYPT_SerializeStoreElement(const void *context,
40 const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
41 PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BOOL omitHashes,
42 BYTE *pbElement, DWORD *pcbElement)
44 BOOL ret;
46 TRACE("(%p, %p, %08lx, %d, %p, %p)\n", context, contextInterface, dwFlags,
47 omitHashes, pbElement, pcbElement);
49 if (context)
51 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
52 DWORD prop = 0;
54 ret = TRUE;
55 do {
56 prop = contextInterface->enumProps(context, prop);
57 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
59 DWORD propSize = 0;
61 ret = contextInterface->getProp(context, prop, NULL, &propSize);
62 if (ret)
63 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
65 } while (ret && prop != 0);
67 if (!pbElement)
69 *pcbElement = bytesNeeded;
70 ret = TRUE;
72 else if (*pcbElement < bytesNeeded)
74 *pcbElement = bytesNeeded;
75 SetLastError(ERROR_MORE_DATA);
76 ret = FALSE;
78 else
80 PWINE_CERT_PROP_HEADER hdr;
81 DWORD bufSize = 0;
82 LPBYTE buf = NULL;
84 prop = 0;
85 do {
86 prop = contextInterface->enumProps(context, prop);
87 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
89 DWORD propSize = 0;
91 ret = contextInterface->getProp(context, prop, NULL,
92 &propSize);
93 if (ret)
95 if (bufSize < propSize)
97 if (buf)
98 buf = CryptMemRealloc(buf, propSize);
99 else
100 buf = CryptMemAlloc(propSize);
101 bufSize = propSize;
103 if (buf)
105 ret = contextInterface->getProp(context, prop, buf,
106 &propSize);
107 if (ret)
109 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
110 hdr->propID = prop;
111 hdr->unknown = 1;
112 hdr->cb = propSize;
113 pbElement += sizeof(WINE_CERT_PROP_HEADER);
114 if (propSize)
116 memcpy(pbElement, buf, propSize);
117 pbElement += propSize;
121 else
122 ret = FALSE;
125 } while (ret && prop != 0);
126 CryptMemFree(buf);
128 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
129 hdr->propID = contextPropID;
130 hdr->unknown = 1;
131 hdr->cb = cbEncodedContext;
132 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
133 encodedContext, cbEncodedContext);
136 else
137 ret = FALSE;
138 return ret;
141 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
142 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
144 return CRYPT_SerializeStoreElement(pCertContext,
145 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
146 CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
149 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
150 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
152 return CRYPT_SerializeStoreElement(pCrlContext,
153 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
154 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
157 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
158 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
160 return CRYPT_SerializeStoreElement(pCtlContext,
161 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
162 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
165 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
166 * to its header if a valid header is found, NULL if not. Valid means the
167 * length of thte property won't overrun buf, and the unknown field is 1.
169 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
170 DWORD size, DWORD propID)
172 const WINE_CERT_PROP_HEADER *ret = NULL;
173 BOOL done = FALSE;
175 while (size && !ret && !done)
177 if (size < sizeof(WINE_CERT_PROP_HEADER))
179 SetLastError(CRYPT_E_FILE_ERROR);
180 done = TRUE;
182 else
184 const WINE_CERT_PROP_HEADER *hdr =
185 (const WINE_CERT_PROP_HEADER *)buf;
187 size -= sizeof(WINE_CERT_PROP_HEADER);
188 buf += sizeof(WINE_CERT_PROP_HEADER);
189 if (size < hdr->cb)
191 SetLastError(E_INVALIDARG);
192 done = TRUE;
194 else if (!hdr->propID)
196 /* assume a zero prop ID means the data are uninitialized, so
197 * stop looking.
199 done = TRUE;
201 else if (hdr->unknown != 1)
203 SetLastError(ERROR_FILE_NOT_FOUND);
204 done = TRUE;
206 else if (hdr->propID == propID)
207 ret = hdr;
208 else
210 buf += hdr->cb;
211 size -= hdr->cb;
215 return ret;
218 static BOOL CRYPT_ReadContextProp(
219 const WINE_CONTEXT_INTERFACE *contextInterface, const void *context,
220 const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement)
222 BOOL ret;
224 if (cbElement < hdr->cb)
226 SetLastError(E_INVALIDARG);
227 ret = FALSE;
229 else if (hdr->unknown != 1)
231 SetLastError(ERROR_FILE_NOT_FOUND);
232 ret = FALSE;
234 else if (hdr->propID != CERT_CERT_PROP_ID &&
235 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID)
237 /* Have to create a blob for most types, but not
238 * for all.. arghh.
240 switch (hdr->propID)
242 case CERT_AUTO_ENROLL_PROP_ID:
243 case CERT_CTL_USAGE_PROP_ID:
244 case CERT_DESCRIPTION_PROP_ID:
245 case CERT_FRIENDLY_NAME_PROP_ID:
246 case CERT_HASH_PROP_ID:
247 case CERT_KEY_IDENTIFIER_PROP_ID:
248 case CERT_MD5_HASH_PROP_ID:
249 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
250 case CERT_PUBKEY_ALG_PARA_PROP_ID:
251 case CERT_PVK_FILE_PROP_ID:
252 case CERT_SIGNATURE_HASH_PROP_ID:
253 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
254 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
255 case CERT_ENROLLMENT_PROP_ID:
256 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
257 case CERT_RENEWAL_PROP_ID:
259 CRYPT_DATA_BLOB blob = { hdr->cb,
260 (LPBYTE)pbElement };
262 ret = contextInterface->setProp(context,
263 hdr->propID, 0, &blob);
264 break;
266 case CERT_DATE_STAMP_PROP_ID:
267 ret = contextInterface->setProp(context,
268 hdr->propID, 0, pbElement);
269 break;
270 case CERT_KEY_PROV_INFO_PROP_ID:
272 PCRYPT_KEY_PROV_INFO info =
273 (PCRYPT_KEY_PROV_INFO)pbElement;
275 CRYPT_FixKeyProvInfoPointers(info);
276 ret = contextInterface->setProp(context,
277 hdr->propID, 0, pbElement);
278 break;
280 default:
281 ret = FALSE;
284 else
286 /* ignore the context itself */
287 ret = TRUE;
289 return ret;
292 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
293 DWORD dwContextTypeFlags, DWORD *pdwContentType)
295 const void *context;
297 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
298 pdwContentType);
300 if (!cbElement)
302 SetLastError(ERROR_END_OF_MEDIA);
303 return NULL;
306 __TRY
308 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
309 const WINE_CERT_PROP_HEADER *hdr = NULL;
310 DWORD type = 0;
311 BOOL ret;
313 ret = TRUE;
314 context = NULL;
315 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
317 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
318 if (hdr)
319 type = CERT_STORE_CERTIFICATE_CONTEXT;
320 else
322 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
323 if (hdr)
324 type = CERT_STORE_CRL_CONTEXT;
325 else
327 hdr = CRYPT_findPropID(pbElement, cbElement,
328 CERT_CTL_PROP_ID);
329 if (hdr)
330 type = CERT_STORE_CTL_CONTEXT;
334 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
336 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
337 type = CERT_STORE_CERTIFICATE_CONTEXT;
339 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
341 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
342 type = CERT_STORE_CRL_CONTEXT;
344 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
346 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
347 type = CERT_STORE_CTL_CONTEXT;
350 switch (type)
352 case CERT_STORE_CERTIFICATE_CONTEXT:
353 contextInterface = pCertInterface;
354 break;
355 case CERT_STORE_CRL_CONTEXT:
356 contextInterface = pCRLInterface;
357 break;
358 case CERT_STORE_CTL_CONTEXT:
359 contextInterface = pCTLInterface;
360 break;
361 default:
362 SetLastError(E_INVALIDARG);
363 ret = FALSE;
365 if (!hdr)
366 ret = FALSE;
368 if (ret)
369 context = contextInterface->create(X509_ASN_ENCODING,
370 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
371 if (ret && context)
373 BOOL noMoreProps = FALSE;
375 while (!noMoreProps && ret)
377 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
378 ret = FALSE;
379 else
381 const WINE_CERT_PROP_HEADER *hdr =
382 (const WINE_CERT_PROP_HEADER *)pbElement;
384 TRACE("prop is %ld\n", hdr->propID);
385 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
386 pbElement += sizeof(WINE_CERT_PROP_HEADER);
387 if (!hdr->propID)
389 /* Like in CRYPT_findPropID, stop if the propID is zero
391 noMoreProps = TRUE;
393 else
394 ret = CRYPT_ReadContextProp(contextInterface, context,
395 hdr, pbElement, cbElement);
396 pbElement += hdr->cb;
397 cbElement -= hdr->cb;
398 if (!cbElement)
399 noMoreProps = TRUE;
402 if (ret)
404 if (pdwContentType)
405 *pdwContentType = type;
407 else
409 contextInterface->free(context);
410 context = NULL;
414 __EXCEPT_PAGE_FAULT
416 SetLastError(STATUS_ACCESS_VIOLATION);
417 context = NULL;
419 __ENDTRY
420 return context;
423 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
425 BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store)
427 BYTE fileHeaderBuf[sizeof(fileHeader)];
428 DWORD read;
429 BOOL ret;
431 /* Failure reading is non-critical, we'll leave the store empty */
432 ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL);
433 if (ret)
435 if (!memcmp(fileHeaderBuf, fileHeader, read))
437 WINE_CERT_PROP_HEADER propHdr;
438 const void *context = NULL;
439 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
440 LPBYTE buf = NULL;
441 DWORD bufSize = 0;
443 do {
444 ret = ReadFile(file, &propHdr, sizeof(propHdr), &read, NULL);
445 if (ret && read == sizeof(propHdr))
447 if (contextInterface && context &&
448 (propHdr.propID == CERT_CERT_PROP_ID ||
449 propHdr.propID == CERT_CRL_PROP_ID ||
450 propHdr.propID == CERT_CTL_PROP_ID))
452 /* We have a new context, so free the existing one */
453 contextInterface->free(context);
455 if (propHdr.cb > bufSize)
457 /* Not reusing realloc, because the old data aren't
458 * needed any longer.
460 CryptMemFree(buf);
461 buf = CryptMemAlloc(propHdr.cb);
462 bufSize = propHdr.cb;
464 if (buf)
466 ret = ReadFile(file, buf, propHdr.cb, &read, NULL);
467 if (ret && read == propHdr.cb)
469 if (propHdr.propID == CERT_CERT_PROP_ID)
471 contextInterface = pCertInterface;
472 ret = contextInterface->addEncodedToStore(store,
473 X509_ASN_ENCODING, buf, read,
474 CERT_STORE_ADD_NEW, &context);
476 else if (propHdr.propID == CERT_CRL_PROP_ID)
478 contextInterface = pCRLInterface;
479 ret = contextInterface->addEncodedToStore(store,
480 X509_ASN_ENCODING, buf, read,
481 CERT_STORE_ADD_NEW, &context);
483 else if (propHdr.propID == CERT_CTL_PROP_ID)
485 contextInterface = pCTLInterface;
486 ret = contextInterface->addEncodedToStore(store,
487 X509_ASN_ENCODING, buf, read,
488 CERT_STORE_ADD_NEW, &context);
490 else
491 ret = CRYPT_ReadContextProp(contextInterface,
492 context, &propHdr, buf, read);
495 else
496 ret = FALSE;
498 } while (ret && read > 0);
499 if (contextInterface && context)
501 /* Free the last context added */
502 contextInterface->free(context);
504 CryptMemFree(buf);
505 ret = TRUE;
508 else
509 ret = TRUE;
510 return ret;
513 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
514 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
516 return CRYPT_SerializeStoreElement(pCertContext,
517 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
518 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
521 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
522 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
524 return CRYPT_SerializeStoreElement(pCrlContext,
525 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
526 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
529 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
530 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
532 return CRYPT_SerializeStoreElement(pCtlContext,
533 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
534 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
537 static BOOL CRYPT_SerializeContextsToFile(HANDLE file,
538 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
540 const void *context = NULL;
541 BOOL ret;
543 do {
544 context = contextInterface->enumContextsInStore(store, context);
545 if (context)
547 DWORD size = 0;
548 LPBYTE buf = NULL;
550 ret = contextInterface->serialize(context, 0, NULL, &size);
551 if (size)
552 buf = CryptMemAlloc(size);
553 if (buf)
555 ret = contextInterface->serialize(context, 0, buf, &size);
556 if (ret)
557 ret = WriteFile(file, buf, size, &size, NULL);
559 CryptMemFree(buf);
561 else
562 ret = TRUE;
563 } while (ret && context != NULL);
564 if (context)
565 contextInterface->free(context);
566 return ret;
569 BOOL CRYPT_WriteSerializedFile(HANDLE file, HCERTSTORE store)
571 static const BYTE fileTrailer[12] = { 0 };
572 WINE_CONTEXT_INTERFACE interface;
573 BOOL ret;
574 DWORD size;
576 SetFilePointer(file, 0, NULL, FILE_BEGIN);
577 ret = WriteFile(file, fileHeader, sizeof(fileHeader), &size, NULL);
578 if (ret)
580 memcpy(&interface, pCertInterface, sizeof(interface));
581 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
582 ret = CRYPT_SerializeContextsToFile(file, &interface, store);
584 if (ret)
586 memcpy(&interface, pCRLInterface, sizeof(interface));
587 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
588 ret = CRYPT_SerializeContextsToFile(file, &interface, store);
590 if (ret)
592 memcpy(&interface, pCTLInterface, sizeof(interface));
593 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
594 ret = CRYPT_SerializeContextsToFile(file, &interface, store);
596 if (ret)
597 ret = WriteFile(file, fileTrailer, sizeof(fileTrailer), &size, NULL);
598 return ret;
601 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
602 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
603 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
605 const void *context;
606 DWORD type;
607 BOOL ret;
609 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
610 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
611 pdwContentType, ppvContext);
613 /* Call the internal function, then delete the hashes. Tests show this
614 * function uses real hash values, not whatever's stored in the hash
615 * property.
617 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
618 dwContextTypeFlags, &type);
619 if (context)
621 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
623 switch (type)
625 case CERT_STORE_CERTIFICATE_CONTEXT:
626 contextInterface = pCertInterface;
627 break;
628 case CERT_STORE_CRL_CONTEXT:
629 contextInterface = pCRLInterface;
630 break;
631 case CERT_STORE_CTL_CONTEXT:
632 contextInterface = pCTLInterface;
633 break;
634 default:
635 SetLastError(E_INVALIDARG);
637 if (contextInterface)
639 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
640 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
641 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
642 NULL);
643 if (pdwContentType)
644 *pdwContentType = type;
645 ret = contextInterface->addContextToStore(hCertStore, context,
646 dwAddDisposition, ppvContext);
647 contextInterface->free(context);
649 else
650 ret = FALSE;
652 else
653 ret = FALSE;
654 return ret;