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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/debug.h"
24 #include "wine/exception.h"
25 #include "crypt32_private.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
29 /* Some typedefs that make it easier to abstract which type of context we're
32 typedef const void *(WINAPI *CreateContextFunc)(DWORD dwCertEncodingType,
33 const BYTE *pbCertEncoded, DWORD cbCertEncoded);
34 typedef BOOL (WINAPI *AddContextToStoreFunc)(HCERTSTORE hCertStore,
35 const void *context, DWORD dwAddDisposition, const void **ppStoreContext);
36 typedef BOOL (WINAPI *AddEncodedContextToStoreFunc)(HCERTSTORE hCertStore,
37 DWORD dwCertEncodingType, const BYTE *pbEncoded, DWORD cbEncoded,
38 DWORD dwAddDisposition, const void **ppContext);
39 typedef const void *(WINAPI *EnumContextsInStoreFunc)(HCERTSTORE hCertStore,
40 const void *pPrevContext);
41 typedef BOOL (WINAPI *GetContextPropertyFunc)(const void *context,
42 DWORD dwPropID, void *pvData, DWORD *pcbData);
43 typedef BOOL (WINAPI *SetContextPropertyFunc)(const void *context,
44 DWORD dwPropID, DWORD dwFlags, const void *pvData);
45 typedef BOOL (WINAPI *SerializeElementFunc)(const void *context, DWORD dwFlags,
46 BYTE *pbElement, DWORD *pcbElement);
47 typedef BOOL (WINAPI *FreeContextFunc)(const void *context);
48 typedef BOOL (WINAPI *DeleteContextFunc)(const void *context);
50 /* An abstract context (certificate, CRL, or CTL) interface */
51 typedef struct _WINE_CONTEXT_INTERFACE
53 CreateContextFunc create;
54 AddContextToStoreFunc addContextToStore;
55 AddEncodedContextToStoreFunc addEncodedToStore;
56 EnumContextsInStoreFunc enumContextsInStore;
57 GetContextPropertyFunc getProp;
58 SetContextPropertyFunc setProp;
59 SerializeElementFunc serialize;
61 DeleteContextFunc deleteFromStore;
62 } WINE_CONTEXT_INTERFACE, *PWINE_CONTEXT_INTERFACE;
64 static const WINE_CONTEXT_INTERFACE gCertInterface = {
65 (CreateContextFunc)CertCreateCertificateContext,
66 (AddContextToStoreFunc)CertAddCertificateContextToStore,
67 (AddEncodedContextToStoreFunc)CertAddEncodedCertificateToStore,
68 (EnumContextsInStoreFunc)CertEnumCertificatesInStore,
69 (GetContextPropertyFunc)CertGetCertificateContextProperty,
70 (SetContextPropertyFunc)CertSetCertificateContextProperty,
71 (SerializeElementFunc)CertSerializeCertificateStoreElement,
72 (FreeContextFunc)CertFreeCertificateContext,
73 (DeleteContextFunc)CertDeleteCertificateFromStore,
76 static const WINE_CONTEXT_INTERFACE gCRLInterface = {
77 (CreateContextFunc)CertCreateCRLContext,
78 (AddContextToStoreFunc)CertAddCRLContextToStore,
79 (AddEncodedContextToStoreFunc)CertAddEncodedCRLToStore,
80 (EnumContextsInStoreFunc)CertEnumCRLsInStore,
81 (GetContextPropertyFunc)CertGetCRLContextProperty,
82 (SetContextPropertyFunc)CertSetCRLContextProperty,
83 (SerializeElementFunc)CertSerializeCRLStoreElement,
84 (FreeContextFunc)CertFreeCRLContext,
85 (DeleteContextFunc)CertDeleteCRLFromStore,
88 static const WINE_CONTEXT_INTERFACE gCTLInterface = {
89 (CreateContextFunc)CertCreateCTLContext,
90 (AddContextToStoreFunc)CertAddCTLContextToStore,
91 (AddEncodedContextToStoreFunc)CertAddEncodedCTLToStore,
92 (EnumContextsInStoreFunc)CertEnumCTLsInStore,
93 (GetContextPropertyFunc)CertGetCTLContextProperty,
94 (SetContextPropertyFunc)CertSetCTLContextProperty,
95 (SerializeElementFunc)CertSerializeCTLStoreElement,
96 (FreeContextFunc)CertFreeCTLContext,
97 (DeleteContextFunc)CertDeleteCTLFromStore,
100 /* An extended certificate property in serialized form is prefixed by this
103 typedef struct _WINE_CERT_PROP_HEADER
106 DWORD unknown; /* always 1 */
108 } WINE_CERT_PROP_HEADER, *PWINE_CERT_PROP_HEADER;
110 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
111 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
113 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
118 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
119 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
121 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
126 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
127 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
131 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
136 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
137 pCertContext->cbCertEncoded;
142 prop = CertEnumCertificateContextProperties(pCertContext, prop);
147 ret = CertGetCertificateContextProperty(pCertContext,
148 prop, NULL, &propSize);
150 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
152 } while (ret && prop != 0);
156 *pcbElement = bytesNeeded;
159 else if (*pcbElement < bytesNeeded)
161 *pcbElement = bytesNeeded;
162 SetLastError(ERROR_MORE_DATA);
167 PWINE_CERT_PROP_HEADER hdr;
173 prop = CertEnumCertificateContextProperties(pCertContext, prop);
178 ret = CertGetCertificateContextProperty(pCertContext,
179 prop, NULL, &propSize);
182 if (bufSize < propSize)
185 buf = CryptMemRealloc(buf, propSize);
187 buf = CryptMemAlloc(propSize);
192 ret = CertGetCertificateContextProperty(
193 pCertContext, prop, buf, &propSize);
196 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
200 pbElement += sizeof(WINE_CERT_PROP_HEADER);
203 memcpy(pbElement, buf, propSize);
204 pbElement += propSize;
212 } while (ret && prop != 0);
215 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
216 hdr->propID = CERT_CERT_PROP_ID;
218 hdr->cb = pCertContext->cbCertEncoded;
219 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
220 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
228 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
229 * to its header if a valid header is found, NULL if not. Valid means the
230 * length of thte property won't overrun buf, and the unknown field is 1.
232 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
233 DWORD size, DWORD propID)
235 const WINE_CERT_PROP_HEADER *ret = NULL;
238 while (size && !ret && !done)
240 if (size < sizeof(WINE_CERT_PROP_HEADER))
242 SetLastError(CRYPT_E_FILE_ERROR);
247 const WINE_CERT_PROP_HEADER *hdr =
248 (const WINE_CERT_PROP_HEADER *)buf;
250 size -= sizeof(WINE_CERT_PROP_HEADER);
251 buf += sizeof(WINE_CERT_PROP_HEADER);
254 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
257 else if (!hdr->propID)
259 /* assume a zero prop ID means the data are uninitialized, so
264 else if (hdr->unknown != 1)
266 SetLastError(ERROR_FILE_NOT_FOUND);
269 else if (hdr->propID == propID)
281 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
282 DWORD dwContextTypeFlags, DWORD *pdwContentType)
286 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
291 SetLastError(ERROR_END_OF_MEDIA);
297 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
298 const WINE_CERT_PROP_HEADER *hdr = NULL;
304 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
306 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
308 type = CERT_STORE_CERTIFICATE_CONTEXT;
311 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
313 type = CERT_STORE_CRL_CONTEXT;
316 hdr = CRYPT_findPropID(pbElement, cbElement,
319 type = CERT_STORE_CTL_CONTEXT;
323 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
325 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
326 type = CERT_STORE_CERTIFICATE_CONTEXT;
328 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
330 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
331 type = CERT_STORE_CRL_CONTEXT;
333 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
335 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
336 type = CERT_STORE_CTL_CONTEXT;
341 case CERT_STORE_CERTIFICATE_CONTEXT:
342 contextInterface = &gCertInterface;
344 case CERT_STORE_CRL_CONTEXT:
345 contextInterface = &gCRLInterface;
347 case CERT_STORE_CTL_CONTEXT:
348 contextInterface = &gCTLInterface;
351 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
358 context = contextInterface->create(X509_ASN_ENCODING,
359 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
362 BOOL noMoreProps = FALSE;
364 while (!noMoreProps && ret)
366 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
370 const WINE_CERT_PROP_HEADER *hdr =
371 (const WINE_CERT_PROP_HEADER *)pbElement;
373 TRACE("prop is %ld\n", hdr->propID);
374 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
375 pbElement += sizeof(WINE_CERT_PROP_HEADER);
376 if (cbElement < hdr->cb)
378 SetLastError(HRESULT_FROM_WIN32(
379 ERROR_INVALID_PARAMETER));
382 else if (!hdr->propID)
384 /* Like in CRYPT_findPropID, stop if the propID is zero
388 else if (hdr->unknown != 1)
390 SetLastError(ERROR_FILE_NOT_FOUND);
393 else if (hdr->propID != CERT_CERT_PROP_ID &&
394 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
397 /* Have to create a blob for most types, but not
402 case CERT_AUTO_ENROLL_PROP_ID:
403 case CERT_CTL_USAGE_PROP_ID:
404 case CERT_DESCRIPTION_PROP_ID:
405 case CERT_FRIENDLY_NAME_PROP_ID:
406 case CERT_HASH_PROP_ID:
407 case CERT_KEY_IDENTIFIER_PROP_ID:
408 case CERT_MD5_HASH_PROP_ID:
409 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
410 case CERT_PUBKEY_ALG_PARA_PROP_ID:
411 case CERT_PVK_FILE_PROP_ID:
412 case CERT_SIGNATURE_HASH_PROP_ID:
413 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
414 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
415 case CERT_ENROLLMENT_PROP_ID:
416 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
417 case CERT_RENEWAL_PROP_ID:
419 CRYPT_DATA_BLOB blob = { hdr->cb,
422 ret = contextInterface->setProp(context,
423 hdr->propID, 0, &blob);
426 case CERT_DATE_STAMP_PROP_ID:
427 ret = contextInterface->setProp(context,
428 hdr->propID, 0, pbElement);
431 FIXME("prop ID %ld: stub\n", hdr->propID);
434 pbElement += hdr->cb;
435 cbElement -= hdr->cb;
443 *pdwContentType = type;
447 contextInterface->free(context);
454 SetLastError(STATUS_ACCESS_VIOLATION);
461 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
462 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
463 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
469 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
470 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
471 pdwContentType, ppvContext);
473 /* Call the internal function, then delete the hashes. Tests show this
474 * function uses real hash values, not whatever's stored in the hash
477 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
478 dwContextTypeFlags, &type);
481 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
485 case CERT_STORE_CERTIFICATE_CONTEXT:
486 contextInterface = &gCertInterface;
488 case CERT_STORE_CRL_CONTEXT:
489 contextInterface = &gCRLInterface;
491 case CERT_STORE_CTL_CONTEXT:
492 contextInterface = &gCTLInterface;
495 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
497 if (contextInterface)
499 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
500 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
501 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
504 *pdwContentType = type;
505 ret = contextInterface->addContextToStore(hCertStore, context,
506 dwAddDisposition, ppvContext);
507 contextInterface->free(context);