advapi32: Implement and test SystemFunction026+027.
[wine/testsucceed.git] / dlls / crypt32 / serialize.c
blob0f28969198c0d08a6914e0087ef5043af7895ebc
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 BOOL WINAPI CertSerializeCRLStoreElement(PCCRL_CONTEXT pCrlContext,
40 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
42 FIXME("(%p, %08lx, %p, %p): stub\n", pCrlContext, dwFlags, pbElement,
43 pcbElement);
44 return FALSE;
47 BOOL WINAPI CertSerializeCTLStoreElement(PCCTL_CONTEXT pCtlContext,
48 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
50 FIXME("(%p, %08lx, %p, %p): stub\n", pCtlContext, dwFlags, pbElement,
51 pcbElement);
52 return FALSE;
55 BOOL WINAPI CertSerializeCertificateStoreElement(PCCERT_CONTEXT pCertContext,
56 DWORD dwFlags, BYTE *pbElement, DWORD *pcbElement)
58 BOOL ret;
60 TRACE("(%p, %08lx, %p, %p)\n", pCertContext, dwFlags, pbElement,
61 pcbElement);
63 if (pCertContext)
65 DWORD bytesNeeded = sizeof(WINE_CERT_PROP_HEADER) +
66 pCertContext->cbCertEncoded;
67 DWORD prop = 0;
69 ret = TRUE;
70 do {
71 prop = CertEnumCertificateContextProperties(pCertContext, prop);
72 if (prop)
74 DWORD propSize = 0;
76 ret = CertGetCertificateContextProperty(pCertContext,
77 prop, NULL, &propSize);
78 if (ret)
79 bytesNeeded += sizeof(WINE_CERT_PROP_HEADER) + propSize;
81 } while (ret && prop != 0);
83 if (!pbElement)
85 *pcbElement = bytesNeeded;
86 ret = TRUE;
88 else if (*pcbElement < bytesNeeded)
90 *pcbElement = bytesNeeded;
91 SetLastError(ERROR_MORE_DATA);
92 ret = FALSE;
94 else
96 PWINE_CERT_PROP_HEADER hdr;
97 DWORD bufSize = 0;
98 LPBYTE buf = NULL;
100 prop = 0;
101 do {
102 prop = CertEnumCertificateContextProperties(pCertContext, prop);
103 if (prop)
105 DWORD propSize = 0;
107 ret = CertGetCertificateContextProperty(pCertContext,
108 prop, NULL, &propSize);
109 if (ret)
111 if (bufSize < propSize)
113 if (buf)
114 buf = CryptMemRealloc(buf, propSize);
115 else
116 buf = CryptMemAlloc(propSize);
117 bufSize = propSize;
119 if (buf)
121 ret = CertGetCertificateContextProperty(
122 pCertContext, prop, buf, &propSize);
123 if (ret)
125 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
126 hdr->propID = prop;
127 hdr->unknown = 1;
128 hdr->cb = propSize;
129 pbElement += sizeof(WINE_CERT_PROP_HEADER);
130 if (propSize)
132 memcpy(pbElement, buf, propSize);
133 pbElement += propSize;
137 else
138 ret = FALSE;
141 } while (ret && prop != 0);
142 CryptMemFree(buf);
144 hdr = (PWINE_CERT_PROP_HEADER)pbElement;
145 hdr->propID = CERT_CERT_PROP_ID;
146 hdr->unknown = 1;
147 hdr->cb = pCertContext->cbCertEncoded;
148 memcpy(pbElement + sizeof(WINE_CERT_PROP_HEADER),
149 pCertContext->pbCertEncoded, pCertContext->cbCertEncoded);
152 else
153 ret = FALSE;
154 return ret;
157 /* Looks for the property with ID propID in the buffer buf. Returns a pointer
158 * to its header if a valid header is found, NULL if not. Valid means the
159 * length of thte property won't overrun buf, and the unknown field is 1.
161 static const WINE_CERT_PROP_HEADER *CRYPT_findPropID(const BYTE *buf,
162 DWORD size, DWORD propID)
164 const WINE_CERT_PROP_HEADER *ret = NULL;
165 BOOL done = FALSE;
167 while (size && !ret && !done)
169 if (size < sizeof(WINE_CERT_PROP_HEADER))
171 SetLastError(CRYPT_E_FILE_ERROR);
172 done = TRUE;
174 else
176 const WINE_CERT_PROP_HEADER *hdr =
177 (const WINE_CERT_PROP_HEADER *)buf;
179 size -= sizeof(WINE_CERT_PROP_HEADER);
180 buf += sizeof(WINE_CERT_PROP_HEADER);
181 if (size < hdr->cb)
183 SetLastError(E_INVALIDARG);
184 done = TRUE;
186 else if (!hdr->propID)
188 /* assume a zero prop ID means the data are uninitialized, so
189 * stop looking.
191 done = TRUE;
193 else if (hdr->unknown != 1)
195 SetLastError(ERROR_FILE_NOT_FOUND);
196 done = TRUE;
198 else if (hdr->propID == propID)
199 ret = hdr;
200 else
202 buf += hdr->cb;
203 size -= hdr->cb;
207 return ret;
210 const void *CRYPT_ReadSerializedElement(const BYTE *pbElement, DWORD cbElement,
211 DWORD dwContextTypeFlags, DWORD *pdwContentType)
213 const void *context;
215 TRACE("(%p, %ld, %08lx, %p)\n", pbElement, cbElement, dwContextTypeFlags,
216 pdwContentType);
218 if (!cbElement)
220 SetLastError(ERROR_END_OF_MEDIA);
221 return NULL;
224 __TRY
226 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
227 const WINE_CERT_PROP_HEADER *hdr = NULL;
228 DWORD type = 0;
229 BOOL ret;
231 ret = TRUE;
232 context = NULL;
233 if (dwContextTypeFlags == CERT_STORE_ALL_CONTEXT_FLAG)
235 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
236 if (hdr)
237 type = CERT_STORE_CERTIFICATE_CONTEXT;
238 else
240 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
241 if (hdr)
242 type = CERT_STORE_CRL_CONTEXT;
243 else
245 hdr = CRYPT_findPropID(pbElement, cbElement,
246 CERT_CTL_PROP_ID);
247 if (hdr)
248 type = CERT_STORE_CTL_CONTEXT;
252 else if (dwContextTypeFlags & CERT_STORE_CERTIFICATE_CONTEXT_FLAG)
254 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CERT_PROP_ID);
255 type = CERT_STORE_CERTIFICATE_CONTEXT;
257 else if (dwContextTypeFlags & CERT_STORE_CRL_CONTEXT_FLAG)
259 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CRL_PROP_ID);
260 type = CERT_STORE_CRL_CONTEXT;
262 else if (dwContextTypeFlags & CERT_STORE_CTL_CONTEXT_FLAG)
264 hdr = CRYPT_findPropID(pbElement, cbElement, CERT_CTL_PROP_ID);
265 type = CERT_STORE_CTL_CONTEXT;
268 switch (type)
270 case CERT_STORE_CERTIFICATE_CONTEXT:
271 contextInterface = pCertInterface;
272 break;
273 case CERT_STORE_CRL_CONTEXT:
274 contextInterface = pCRLInterface;
275 break;
276 case CERT_STORE_CTL_CONTEXT:
277 contextInterface = pCTLInterface;
278 break;
279 default:
280 SetLastError(E_INVALIDARG);
281 ret = FALSE;
283 if (!hdr)
284 ret = FALSE;
286 if (ret)
287 context = contextInterface->create(X509_ASN_ENCODING,
288 (BYTE *)hdr + sizeof(WINE_CERT_PROP_HEADER), hdr->cb);
289 if (ret && context)
291 BOOL noMoreProps = FALSE;
293 while (!noMoreProps && ret)
295 if (cbElement < sizeof(WINE_CERT_PROP_HEADER))
296 ret = FALSE;
297 else
299 const WINE_CERT_PROP_HEADER *hdr =
300 (const WINE_CERT_PROP_HEADER *)pbElement;
302 TRACE("prop is %ld\n", hdr->propID);
303 cbElement -= sizeof(WINE_CERT_PROP_HEADER);
304 pbElement += sizeof(WINE_CERT_PROP_HEADER);
305 if (cbElement < hdr->cb)
307 SetLastError(E_INVALIDARG);
308 ret = FALSE;
310 else if (!hdr->propID)
312 /* Like in CRYPT_findPropID, stop if the propID is zero
314 noMoreProps = TRUE;
316 else if (hdr->unknown != 1)
318 SetLastError(ERROR_FILE_NOT_FOUND);
319 ret = FALSE;
321 else if (hdr->propID != CERT_CERT_PROP_ID &&
322 hdr->propID != CERT_CRL_PROP_ID && hdr->propID !=
323 CERT_CTL_PROP_ID)
325 /* Have to create a blob for most types, but not
326 * for all.. arghh.
328 switch (hdr->propID)
330 case CERT_AUTO_ENROLL_PROP_ID:
331 case CERT_CTL_USAGE_PROP_ID:
332 case CERT_DESCRIPTION_PROP_ID:
333 case CERT_FRIENDLY_NAME_PROP_ID:
334 case CERT_HASH_PROP_ID:
335 case CERT_KEY_IDENTIFIER_PROP_ID:
336 case CERT_MD5_HASH_PROP_ID:
337 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
338 case CERT_PUBKEY_ALG_PARA_PROP_ID:
339 case CERT_PVK_FILE_PROP_ID:
340 case CERT_SIGNATURE_HASH_PROP_ID:
341 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
342 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
343 case CERT_ENROLLMENT_PROP_ID:
344 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
345 case CERT_RENEWAL_PROP_ID:
347 CRYPT_DATA_BLOB blob = { hdr->cb,
348 (LPBYTE)pbElement };
350 ret = contextInterface->setProp(context,
351 hdr->propID, 0, &blob);
352 break;
354 case CERT_DATE_STAMP_PROP_ID:
355 ret = contextInterface->setProp(context,
356 hdr->propID, 0, pbElement);
357 break;
358 default:
359 FIXME("prop ID %ld: stub\n", hdr->propID);
362 pbElement += hdr->cb;
363 cbElement -= hdr->cb;
364 if (!cbElement)
365 noMoreProps = TRUE;
368 if (ret)
370 if (pdwContentType)
371 *pdwContentType = type;
373 else
375 contextInterface->free(context);
376 context = NULL;
380 __EXCEPT_PAGE_FAULT
382 SetLastError(STATUS_ACCESS_VIOLATION);
383 context = NULL;
385 __ENDTRY
386 return context;
389 BOOL WINAPI CertAddSerializedElementToStore(HCERTSTORE hCertStore,
390 const BYTE *pbElement, DWORD cbElement, DWORD dwAddDisposition, DWORD dwFlags,
391 DWORD dwContextTypeFlags, DWORD *pdwContentType, const void **ppvContext)
393 const void *context;
394 DWORD type;
395 BOOL ret;
397 TRACE("(%p, %p, %ld, %08lx, %08lx, %08lx, %p, %p)\n", hCertStore,
398 pbElement, cbElement, dwAddDisposition, dwFlags, dwContextTypeFlags,
399 pdwContentType, ppvContext);
401 /* Call the internal function, then delete the hashes. Tests show this
402 * function uses real hash values, not whatever's stored in the hash
403 * property.
405 context = CRYPT_ReadSerializedElement(pbElement, cbElement,
406 dwContextTypeFlags, &type);
407 if (context)
409 const WINE_CONTEXT_INTERFACE *contextInterface = NULL;
411 switch (type)
413 case CERT_STORE_CERTIFICATE_CONTEXT:
414 contextInterface = pCertInterface;
415 break;
416 case CERT_STORE_CRL_CONTEXT:
417 contextInterface = pCRLInterface;
418 break;
419 case CERT_STORE_CTL_CONTEXT:
420 contextInterface = pCTLInterface;
421 break;
422 default:
423 SetLastError(E_INVALIDARG);
425 if (contextInterface)
427 contextInterface->setProp(context, CERT_HASH_PROP_ID, 0, NULL);
428 contextInterface->setProp(context, CERT_MD5_HASH_PROP_ID, 0, NULL);
429 contextInterface->setProp(context, CERT_SIGNATURE_HASH_PROP_ID, 0,
430 NULL);
431 if (pdwContentType)
432 *pdwContentType = type;
433 ret = contextInterface->addContextToStore(hCertStore, context,
434 dwAddDisposition, ppvContext);
435 contextInterface->free(context);
437 else
438 ret = FALSE;
440 else
441 ret = FALSE;
442 return ret;