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"
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
32 typedef struct _WINE_CERT_PROP_HEADER
35 DWORD unknown; /* always 1 */
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, BYTE *pbElement,
46 TRACE("(%p, %p, %08lx, %p, %p)\n", context, contextInterface, dwFlags,
47 pbElement, pcbElement);
51 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) + cbEncodedContext;
56 prop = contextInterface->enumProps(context, prop);
61 ret = contextInterface->getProp(context, prop, NULL, &propSize);
63 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
65 } while (ret && prop != 0);
69 *pcbElement = bytesNeeded;
72 else if (*pcbElement < bytesNeeded)
74 *pcbElement = bytesNeeded;
75 SetLastError(ERROR_MORE_DATA);
80 PWINE_CERT_PROP_HEADER hdr;
86 prop = contextInterface->enumProps(context, prop);
91 ret = contextInterface->getProp(context, prop, NULL,
95 if (bufSize < propSize)
98 buf = CryptMemRealloc(buf, propSize);
100 buf = CryptMemAlloc(propSize);
105 ret = contextInterface->getProp(context, prop, buf,
109 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
113 pbElement += sizeof(WINE_CERT_PROP_HEADER);
116 memcpy(pbElement, buf, propSize);
117 pbElement += propSize;
125 } while (ret && prop != 0);
128 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
129 hdr->propID = contextPropID;
131 hdr->cb = cbEncodedContext;
132 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
133 encodedContext, cbEncodedContext);
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, 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, 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, pCRLInterface, dwFlags, 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;
175 while (size && !ret && !done)
177 if (size < sizeof(WINE_CERT_PROP_HEADER))
179 SetLastError(CRYPT_E_FILE_ERROR);
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);
191 SetLastError(E_INVALIDARG);
194 else if (!hdr->propID)
196 /* assume a zero prop ID means the data are uninitialized, so
201 else if (hdr->unknown != 1)
203 SetLastError(ERROR_FILE_NOT_FOUND);
206 else if (hdr->propID == propID)
218 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
219 DWORD dwContextTypeFlags, DWORD *pdwContentType)
223 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
228 SetLastError(ERROR_END_OF_MEDIA);
234 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
235 const WINE_CERT_PROP_HEADER *hdr = NULL;
241 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
243 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
245 type = CERT_STORE_CERTIFICATE_CONTEXT;
248 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
250 type = CERT_STORE_CRL_CONTEXT;
253 hdr = CRYPT_findPropID(pbElement, cbElement,
256 type = CERT_STORE_CTL_CONTEXT;
260 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
262 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
263 type = CERT_STORE_CERTIFICATE_CONTEXT;
265 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
267 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
268 type = CERT_STORE_CRL_CONTEXT;
270 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
272 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
273 type = CERT_STORE_CTL_CONTEXT;
278 case CERT_STORE_CERTIFICATE_CONTEXT:
279 contextInterface = pCertInterface;
281 case CERT_STORE_CRL_CONTEXT:
282 contextInterface = pCRLInterface;
284 case CERT_STORE_CTL_CONTEXT:
285 contextInterface = pCTLInterface;
288 SetLastError(E_INVALIDARG);
295 context = contextInterface->create(X509_ASN_ENCODING,
296 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
299 BOOL noMoreProps = FALSE;
301 while (!noMoreProps && ret)
303 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
307 const WINE_CERT_PROP_HEADER *hdr =
308 (const WINE_CERT_PROP_HEADER *)pbElement;
310 TRACE("prop is %ld\n", hdr->propID);
311 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
312 pbElement += sizeof(WINE_CERT_PROP_HEADER);
313 if (cbElement < hdr->cb)
315 SetLastError(E_INVALIDARG);
318 else if (!hdr->propID)
320 /* Like in CRYPT_findPropID, stop if the propID is zero
324 else if (hdr->unknown != 1)
326 SetLastError(ERROR_FILE_NOT_FOUND);
329 else if (hdr->propID != CERT_CERT_PROP_ID &&
330 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
333 /* Have to create a blob for most types, but not
338 case CERT_AUTO_ENROLL_PROP_ID:
339 case CERT_CTL_USAGE_PROP_ID:
340 case CERT_DESCRIPTION_PROP_ID:
341 case CERT_FRIENDLY_NAME_PROP_ID:
342 case CERT_HASH_PROP_ID:
343 case CERT_KEY_IDENTIFIER_PROP_ID:
344 case CERT_MD5_HASH_PROP_ID:
345 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
346 case CERT_PUBKEY_ALG_PARA_PROP_ID:
347 case CERT_PVK_FILE_PROP_ID:
348 case CERT_SIGNATURE_HASH_PROP_ID:
349 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
350 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
351 case CERT_ENROLLMENT_PROP_ID:
352 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
353 case CERT_RENEWAL_PROP_ID:
355 CRYPT_DATA_BLOB blob = { hdr->cb,
358 ret = contextInterface->setProp(context,
359 hdr->propID, 0, &blob);
362 case CERT_DATE_STAMP_PROP_ID:
363 ret = contextInterface->setProp(context,
364 hdr->propID, 0, pbElement);
367 FIXME("prop ID %ld: stub\n", hdr->propID);
370 pbElement += hdr->cb;
371 cbElement -= hdr->cb;
379 *pdwContentType = type;
383 contextInterface->free(context);
390 SetLastError(STATUS_ACCESS_VIOLATION);
397 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
398 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
399 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
405 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
406 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
407 pdwContentType, ppvContext);
409 /* Call the internal function, then delete the hashes. Tests show this
410 * function uses real hash values, not whatever's stored in the hash
413 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
414 dwContextTypeFlags, &type);
417 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
421 case CERT_STORE_CERTIFICATE_CONTEXT:
422 contextInterface = pCertInterface;
424 case CERT_STORE_CRL_CONTEXT:
425 contextInterface = pCRLInterface;
427 case CERT_STORE_CTL_CONTEXT:
428 contextInterface = pCTLInterface;
431 SetLastError(E_INVALIDARG);
433 if (contextInterface)
435 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
436 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
437 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
440 *pdwContentType = type;
441 ret = contextInterface->addContextToStore(hCertStore, context,
442 dwAddDisposition, ppvContext);
443 contextInterface->free(context);