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
22 #include "wine/debug.h"
23 #include "wine/exception.h"
24 #include "crypt32_private.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
28 /* An extended certificate property in serialized form is prefixed by this
31 typedef struct _WINE_CERT_PROP_HEADER
34 DWORD unknown; /* always 1 */
36 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
38 static BOOL CRYPT_SerializeStoreElement(const void *context,
39 const BYTE *encodedContext, DWORD cbEncodedContext, DWORD contextPropID,
40 PCWINE_CONTEXT_INTERFACE contextInterface, DWORD dwFlags, BOOL omitHashes,
41 BYTE *pbElement, DWORD *pcbElement)
45 TRACE("(%p, %p, %08x, %d, %p, %p)\n", context, contextInterface, dwFlags,
46 omitHashes, pbElement, pcbElement);
50 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
55 prop = contextInterface->enumProps(context, prop);
56 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
60 ret = contextInterface->getProp(context, prop, NULL, &propSize);
62 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
64 } while (ret && prop != 0);
68 *pcbElement = bytesNeeded;
71 else if (*pcbElement < bytesNeeded)
73 *pcbElement = bytesNeeded;
74 SetLastError(ERROR_MORE_DATA);
79 PWINE_CERT_PROP_HEADER hdr;
85 prop = contextInterface->enumProps(context, prop);
86 if (prop && (!omitHashes || !IS_CERT_HASH_PROP_ID(prop)))
90 ret = contextInterface->getProp(context, prop, NULL,
94 if (bufSize < propSize)
97 buf = CryptMemRealloc(buf, propSize);
99 buf = CryptMemAlloc(propSize);
104 ret = contextInterface->getProp(context, prop, buf,
108 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
112 pbElement += sizeof(WINE_CERT_PROP_HEADER);
115 memcpy(pbElement, buf, propSize);
116 pbElement += propSize;
124 } while (ret && prop != 0);
127 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
128 hdr->propID = contextPropID;
130 hdr->cb = cbEncodedContext;
131 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
132 encodedContext, cbEncodedContext);
140 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
141 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
143 return CRYPT_SerializeStoreElement(pCertContext,
144 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
145 CERT_CERT_PROP_ID, pCertInterface, dwFlags, FALSE, pbElement, pcbElement);
148 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
149 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
151 return CRYPT_SerializeStoreElement(pCrlContext,
152 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
153 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, FALSE, pbElement, pcbElement);
156 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
157 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
159 return CRYPT_SerializeStoreElement(pCtlContext,
160 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
161 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, FALSE, pbElement, pcbElement);
164 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
165 * to its header if a valid header is found, NULL if not. Valid means the
166 * length of thte property won't overrun buf, and the unknown field is 1.
168 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
169 DWORD size, DWORD propID)
171 const WINE_CERT_PROP_HEADER *ret = NULL;
174 while (size && !ret && !done)
176 if (size < sizeof(WINE_CERT_PROP_HEADER))
178 SetLastError(CRYPT_E_FILE_ERROR);
183 const WINE_CERT_PROP_HEADER *hdr =
184 (const WINE_CERT_PROP_HEADER *)buf;
186 size -= sizeof(WINE_CERT_PROP_HEADER);
187 buf += sizeof(WINE_CERT_PROP_HEADER);
190 SetLastError(E_INVALIDARG);
193 else if (!hdr->propID)
195 /* assume a zero prop ID means the data are uninitialized, so
200 else if (hdr->unknown != 1)
202 SetLastError(ERROR_FILE_NOT_FOUND);
205 else if (hdr->propID == propID)
217 static BOOL CRYPT_ReadContextProp(
218 const WINE_CONTEXT_INTERFACE *contextInterface, const void *context,
219 const WINE_CERT_PROP_HEADER *hdr, const BYTE *pbElement, DWORD cbElement)
223 if (cbElement < hdr->cb)
225 SetLastError(E_INVALIDARG);
228 else if (hdr->unknown != 1)
230 SetLastError(ERROR_FILE_NOT_FOUND);
233 else if (hdr->propID != CERT_CERT_PROP_ID &&
234 hdr->propID != CERT_CRL_PROP_ID && hdr->propID != CERT_CTL_PROP_ID)
236 /* Have to create a blob for most types, but not
241 case CERT_AUTO_ENROLL_PROP_ID:
242 case CERT_CTL_USAGE_PROP_ID:
243 case CERT_DESCRIPTION_PROP_ID:
244 case CERT_FRIENDLY_NAME_PROP_ID:
245 case CERT_HASH_PROP_ID:
246 case CERT_KEY_IDENTIFIER_PROP_ID:
247 case CERT_MD5_HASH_PROP_ID:
248 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
249 case CERT_PUBKEY_ALG_PARA_PROP_ID:
250 case CERT_PVK_FILE_PROP_ID:
251 case CERT_SIGNATURE_HASH_PROP_ID:
252 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
253 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
254 case CERT_ENROLLMENT_PROP_ID:
255 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
256 case CERT_RENEWAL_PROP_ID:
258 CRYPT_DATA_BLOB blob = { hdr->cb,
261 ret = contextInterface->setProp(context,
262 hdr->propID, 0, &blob);
265 case CERT_DATE_STAMP_PROP_ID:
266 ret = contextInterface->setProp(context,
267 hdr->propID, 0, pbElement);
269 case CERT_KEY_PROV_INFO_PROP_ID:
271 PCRYPT_KEY_PROV_INFO info =
272 (PCRYPT_KEY_PROV_INFO)pbElement;
274 CRYPT_FixKeyProvInfoPointers(info);
275 ret = contextInterface->setProp(context,
276 hdr->propID, 0, pbElement);
285 /* ignore the context itself */
291 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
292 DWORD dwContextTypeFlags, DWORD *pdwContentType)
296 TRACE("(%p, %d, %08x, %p)\n", pbElement, cbElement, dwContextTypeFlags,
301 SetLastError(ERROR_END_OF_MEDIA);
307 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
308 const WINE_CERT_PROP_HEADER *hdr = NULL;
314 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
316 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
318 type = CERT_STORE_CERTIFICATE_CONTEXT;
321 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
323 type = CERT_STORE_CRL_CONTEXT;
326 hdr = CRYPT_findPropID(pbElement, cbElement,
329 type = CERT_STORE_CTL_CONTEXT;
333 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
335 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
336 type = CERT_STORE_CERTIFICATE_CONTEXT;
338 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
340 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
341 type = CERT_STORE_CRL_CONTEXT;
343 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
345 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
346 type = CERT_STORE_CTL_CONTEXT;
351 case CERT_STORE_CERTIFICATE_CONTEXT:
352 contextInterface = pCertInterface;
354 case CERT_STORE_CRL_CONTEXT:
355 contextInterface = pCRLInterface;
357 case CERT_STORE_CTL_CONTEXT:
358 contextInterface = pCTLInterface;
361 SetLastError(E_INVALIDARG);
368 context = contextInterface->create(X509_ASN_ENCODING,
369 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
372 BOOL noMoreProps = FALSE;
374 while (!noMoreProps && ret)
376 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
380 const WINE_CERT_PROP_HEADER *hdr =
381 (const WINE_CERT_PROP_HEADER *)pbElement;
383 TRACE("prop is %d\n", hdr->propID);
384 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
385 pbElement += sizeof(WINE_CERT_PROP_HEADER);
388 /* Like in CRYPT_findPropID, stop if the propID is zero
393 ret = CRYPT_ReadContextProp(contextInterface, context,
394 hdr, pbElement, cbElement);
395 pbElement += hdr->cb;
396 cbElement -= hdr->cb;
404 *pdwContentType = type;
408 contextInterface->free(context);
415 SetLastError(STATUS_ACCESS_VIOLATION);
422 static const BYTE fileHeader[] = { 0, 0, 0, 0, 'C','E','R','T' };
424 BOOL CRYPT_ReadSerializedFile(HANDLE file, HCERTSTORE store)
426 BYTE fileHeaderBuf[sizeof(fileHeader)];
430 /* Failure reading is non-critical, we'll leave the store empty */
431 ret = ReadFile(file, fileHeaderBuf, sizeof(fileHeaderBuf), &read, NULL);
434 if (!memcmp(fileHeaderBuf, fileHeader, read))
436 WINE_CERT_PROP_HEADER propHdr;
437 const void *context = NULL;
438 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
443 ret = ReadFile(file, &propHdr, sizeof(propHdr), &read, NULL);
444 if (ret && read == sizeof(propHdr))
446 if (contextInterface && context &&
447 (propHdr.propID == CERT_CERT_PROP_ID ||
448 propHdr.propID == CERT_CRL_PROP_ID ||
449 propHdr.propID == CERT_CTL_PROP_ID))
451 /* We have a new context, so free the existing one */
452 contextInterface->free(context);
454 if (propHdr.cb > bufSize)
456 /* Not reusing realloc, because the old data aren't
460 buf = CryptMemAlloc(propHdr.cb);
461 bufSize = propHdr.cb;
465 ret = ReadFile(file, buf, propHdr.cb, &read, NULL);
466 if (ret && read == propHdr.cb)
468 if (propHdr.propID == CERT_CERT_PROP_ID)
470 contextInterface = pCertInterface;
471 ret = contextInterface->addEncodedToStore(store,
472 X509_ASN_ENCODING, buf, read,
473 CERT_STORE_ADD_NEW, &context);
475 else if (propHdr.propID == CERT_CRL_PROP_ID)
477 contextInterface = pCRLInterface;
478 ret = contextInterface->addEncodedToStore(store,
479 X509_ASN_ENCODING, buf, read,
480 CERT_STORE_ADD_NEW, &context);
482 else if (propHdr.propID == CERT_CTL_PROP_ID)
484 contextInterface = pCTLInterface;
485 ret = contextInterface->addEncodedToStore(store,
486 X509_ASN_ENCODING, buf, read,
487 CERT_STORE_ADD_NEW, &context);
490 ret = CRYPT_ReadContextProp(contextInterface,
491 context, &propHdr, buf, read);
497 } while (ret && read > 0);
498 if (contextInterface && context)
500 /* Free the last context added */
501 contextInterface->free(context);
512 static BOOL WINAPI CRYPT_SerializeCertNoHash(PCCERT_CONTEXT pCertContext,
513 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
515 return CRYPT_SerializeStoreElement(pCertContext,
516 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded,
517 CERT_CERT_PROP_ID, pCertInterface, dwFlags, TRUE, pbElement, pcbElement);
520 static BOOL WINAPI CRYPT_SerializeCRLNoHash(PCCRL_CONTEXT pCrlContext,
521 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
523 return CRYPT_SerializeStoreElement(pCrlContext,
524 pCrlContext->pbCrlEncoded, pCrlContext->cbCrlEncoded,
525 CERT_CRL_PROP_ID, pCRLInterface, dwFlags, TRUE, pbElement, pcbElement);
528 static BOOL WINAPI CRYPT_SerializeCTLNoHash(PCCTL_CONTEXT pCtlContext,
529 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
531 return CRYPT_SerializeStoreElement(pCtlContext,
532 pCtlContext->pbCtlEncoded, pCtlContext->cbCtlEncoded,
533 CERT_CTL_PROP_ID, pCTLInterface, dwFlags, TRUE, pbElement, pcbElement);
536 static BOOL CRYPT_SerializeContextsToFile(HANDLE file,
537 const WINE_CONTEXT_INTERFACE *contextInterface, HCERTSTORE store)
539 const void *context = NULL;
543 context = contextInterface->enumContextsInStore(store, context);
549 ret = contextInterface->serialize(context, 0, NULL, &size);
551 buf = CryptMemAlloc(size);
554 ret = contextInterface->serialize(context, 0, buf, &size);
556 ret = WriteFile(file, buf, size, &size, NULL);
562 } while (ret && context != NULL);
564 contextInterface->free(context);
568 BOOL CRYPT_WriteSerializedFile(HANDLE file, HCERTSTORE store)
570 static const BYTE fileTrailer[12] = { 0 };
571 WINE_CONTEXT_INTERFACE interface;
575 SetFilePointer(file, 0, NULL, FILE_BEGIN);
576 ret = WriteFile(file, fileHeader, sizeof(fileHeader), &size, NULL);
579 memcpy(&interface, pCertInterface, sizeof(interface));
580 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCertNoHash;
581 ret = CRYPT_SerializeContextsToFile(file, &interface, store);
585 memcpy(&interface, pCRLInterface, sizeof(interface));
586 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCRLNoHash;
587 ret = CRYPT_SerializeContextsToFile(file, &interface, store);
591 memcpy(&interface, pCTLInterface, sizeof(interface));
592 interface.serialize = (SerializeElementFunc)CRYPT_SerializeCTLNoHash;
593 ret = CRYPT_SerializeContextsToFile(file, &interface, store);
596 ret = WriteFile(file, fileTrailer, sizeof(fileTrailer), &size, NULL);
600 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
601 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
602 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
608 TRACE("(%p, %p, %d, %08x, %08x, %08x, %p, %p)\n", hCertStore,
609 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
610 pdwContentType, ppvContext);
612 /* Call the internal function, then delete the hashes. Tests show this
613 * function uses real hash values, not whatever's stored in the hash
616 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
617 dwContextTypeFlags, &type);
620 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
624 case CERT_STORE_CERTIFICATE_CONTEXT:
625 contextInterface = pCertInterface;
627 case CERT_STORE_CRL_CONTEXT:
628 contextInterface = pCRLInterface;
630 case CERT_STORE_CTL_CONTEXT:
631 contextInterface = pCTLInterface;
634 SetLastError(E_INVALIDARG);
636 if (contextInterface)
638 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
639 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
640 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
643 *pdwContentType = type;
644 ret = contextInterface->addContextToStore(hCertStore, context,
645 dwAddDisposition, ppvContext);
646 contextInterface->free(context);