crypt32: Pass contexts as context_t to CONTEXT_FUNCS->delete.
[wine/multimedia.git] / dlls / crypt32 / ctl.c
blob26072abd6757a5c4892d93a16a7a16ce19a7124e
1 /*
2 * Copyright 2008 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
20 #include <assert.h>
21 #include <stdarg.h>
23 #define NONAMELESSUNION
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wincrypt.h"
27 #include "wine/debug.h"
28 #include "crypt32_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 static void CTL_free(context_t *context)
34 ctl_t *ctl = (ctl_t*)context;
36 CryptMsgClose(ctl->ctx.hCryptMsg);
37 CryptMemFree(ctl->ctx.pbCtlEncoded);
38 CryptMemFree(ctl->ctx.pbCtlContext);
39 LocalFree(ctl->ctx.pCtlInfo);
42 static const context_vtbl_t ctl_vtbl = {
43 CTL_free
46 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
47 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
48 PCCTL_CONTEXT* ppStoreContext)
50 WINECRYPT_CERTSTORE *store = hCertStore;
51 BOOL ret = TRUE;
52 PCCTL_CONTEXT toAdd = NULL, existing = NULL;
54 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition,
55 ppStoreContext);
57 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
59 existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING,
60 pCtlContext, NULL);
63 switch (dwAddDisposition)
65 case CERT_STORE_ADD_ALWAYS:
66 toAdd = CertDuplicateCTLContext(pCtlContext);
67 break;
68 case CERT_STORE_ADD_NEW:
69 if (existing)
71 TRACE("found matching CTL, not adding\n");
72 SetLastError(CRYPT_E_EXISTS);
73 ret = FALSE;
75 else
76 toAdd = CertDuplicateCTLContext(pCtlContext);
77 break;
78 case CERT_STORE_ADD_NEWER:
79 if (existing)
81 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
82 &pCtlContext->pCtlInfo->ThisUpdate);
84 if (newer < 0)
85 toAdd = CertDuplicateCTLContext(pCtlContext);
86 else
88 TRACE("existing CTL is newer, not adding\n");
89 SetLastError(CRYPT_E_EXISTS);
90 ret = FALSE;
93 else
94 toAdd = CertDuplicateCTLContext(pCtlContext);
95 break;
96 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
97 if (existing)
99 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
100 &pCtlContext->pCtlInfo->ThisUpdate);
102 if (newer < 0)
104 toAdd = CertDuplicateCTLContext(pCtlContext);
105 Context_CopyProperties(existing, pCtlContext);
107 else
109 TRACE("existing CTL is newer, not adding\n");
110 SetLastError(CRYPT_E_EXISTS);
111 ret = FALSE;
114 else
115 toAdd = CertDuplicateCTLContext(pCtlContext);
116 break;
117 case CERT_STORE_ADD_REPLACE_EXISTING:
118 toAdd = CertDuplicateCTLContext(pCtlContext);
119 break;
120 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
121 toAdd = CertDuplicateCTLContext(pCtlContext);
122 if (existing)
123 Context_CopyProperties(toAdd, existing);
124 break;
125 case CERT_STORE_ADD_USE_EXISTING:
126 if (existing)
128 Context_CopyProperties(existing, pCtlContext);
129 if (ppStoreContext)
130 *ppStoreContext = CertDuplicateCTLContext(existing);
132 else
133 toAdd = CertDuplicateCTLContext(pCtlContext);
134 break;
135 default:
136 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
137 ret = FALSE;
140 if (toAdd)
142 if (store)
143 ret = store->vtbl->ctls.addContext(store, (void *)toAdd,
144 (void *)existing, (const void **)ppStoreContext);
145 else if (ppStoreContext)
146 *ppStoreContext = CertDuplicateCTLContext(toAdd);
147 CertFreeCTLContext(toAdd);
149 CertFreeCTLContext(existing);
151 TRACE("returning %d\n", ret);
152 return ret;
155 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
156 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
157 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
159 PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType,
160 pbCtlEncoded, cbCtlEncoded);
161 BOOL ret;
163 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore,
164 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
165 ppCtlContext);
167 if (ctl)
169 ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition,
170 ppCtlContext);
171 CertFreeCTLContext(ctl);
173 else
174 ret = FALSE;
175 return ret;
178 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
179 PCCTL_CONTEXT pPrev)
181 WINECRYPT_CERTSTORE *hcs = hCertStore;
182 PCCTL_CONTEXT ret;
184 TRACE("(%p, %p)\n", hCertStore, pPrev);
185 if (!hCertStore)
186 ret = NULL;
187 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
188 ret = NULL;
189 else
190 ret = (PCCTL_CONTEXT)hcs->vtbl->ctls.enumContext(hcs, (void *)pPrev);
191 return ret;
194 typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType,
195 DWORD dwFlags, const void *pvPara);
197 static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType,
198 DWORD dwFlags, const void *pvPara)
200 return TRUE;
203 static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
204 DWORD dwFlags, const void *pvPara)
206 BOOL ret;
207 BYTE hash[16];
208 DWORD size = sizeof(hash);
210 ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_HASH_PROP_ID, hash,
211 &size);
212 if (ret)
214 const CRYPT_HASH_BLOB *pHash = pvPara;
216 if (size == pHash->cbData)
217 ret = !memcmp(pHash->pbData, hash, size);
218 else
219 ret = FALSE;
221 return ret;
224 static BOOL compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
225 DWORD dwFlags, const void *pvPara)
227 BOOL ret;
228 BYTE hash[20];
229 DWORD size = sizeof(hash);
231 ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash,
232 &size);
233 if (ret)
235 const CRYPT_HASH_BLOB *pHash = pvPara;
237 if (size == pHash->cbData)
238 ret = !memcmp(pHash->pbData, hash, size);
239 else
240 ret = FALSE;
242 return ret;
245 static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType,
246 DWORD dwFlags, const void *pvPara)
248 BOOL ret;
250 if (pvPara)
252 PCCTL_CONTEXT ctl = pvPara;
254 if (pCtlContext->cbCtlContext == ctl->cbCtlContext)
256 if (ctl->cbCtlContext)
257 ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext,
258 ctl->cbCtlContext);
259 else
260 ret = TRUE;
262 else
263 ret = FALSE;
265 else
266 ret = FALSE;
267 return ret;
270 PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore,
271 DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
272 const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext)
274 PCCTL_CONTEXT ret;
275 CtlCompareFunc compare;
277 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
278 dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext);
280 switch (dwFindType)
282 case CTL_FIND_ANY:
283 compare = compare_ctl_any;
284 break;
285 case CTL_FIND_SHA1_HASH:
286 compare = compare_ctl_by_sha1_hash;
287 break;
288 case CTL_FIND_MD5_HASH:
289 compare = compare_ctl_by_md5_hash;
290 break;
291 case CTL_FIND_EXISTING:
292 compare = compare_ctl_existing;
293 break;
294 default:
295 FIXME("find type %08x unimplemented\n", dwFindType);
296 compare = NULL;
299 if (compare)
301 BOOL matches = FALSE;
303 ret = pPrevCtlContext;
304 do {
305 ret = CertEnumCTLsInStore(hCertStore, ret);
306 if (ret)
307 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
308 } while (ret != NULL && !matches);
309 if (!ret)
310 SetLastError(CRYPT_E_NOT_FOUND);
312 else
314 SetLastError(CRYPT_E_NOT_FOUND);
315 ret = NULL;
317 return ret;
320 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
322 BOOL ret;
324 TRACE("(%p)\n", pCtlContext);
326 if (!pCtlContext)
327 ret = TRUE;
328 else if (!pCtlContext->hCertStore)
329 ret = CertFreeCTLContext(pCtlContext);
330 else
332 WINECRYPT_CERTSTORE *hcs = pCtlContext->hCertStore;
333 ctl_t *ctl = ctl_from_ptr(pCtlContext);
335 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
336 ret = FALSE;
337 else
338 ret = hcs->vtbl->ctls.delete(hcs, &ctl->base);
339 if (ret)
340 ret = CertFreeCTLContext(pCtlContext);
342 return ret;
345 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
346 const BYTE *pbCtlEncoded, DWORD cbCtlEncoded)
348 PCTL_CONTEXT ctl = NULL;
349 HCRYPTMSG msg;
350 BOOL ret;
351 BYTE *content = NULL;
352 DWORD contentSize = 0, size;
353 PCTL_INFO ctlInfo = NULL;
355 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType, pbCtlEncoded,
356 cbCtlEncoded);
358 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType) != X509_ASN_ENCODING)
360 SetLastError(E_INVALIDARG);
361 return NULL;
363 if (!pbCtlEncoded || !cbCtlEncoded)
365 SetLastError(ERROR_INVALID_DATA);
366 return NULL;
368 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0,
369 0, NULL, NULL);
370 if (!msg)
371 return NULL;
372 ret = CryptMsgUpdate(msg, pbCtlEncoded, cbCtlEncoded, TRUE);
373 if (!ret)
375 SetLastError(ERROR_INVALID_DATA);
376 goto end;
378 /* Check that it's really a CTL */
379 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size);
380 if (ret)
382 char *innerContent = CryptMemAlloc(size);
384 if (innerContent)
386 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0,
387 innerContent, &size);
388 if (ret)
390 if (strcmp(innerContent, szOID_CTL))
392 SetLastError(ERROR_INVALID_DATA);
393 ret = FALSE;
396 CryptMemFree(innerContent);
398 else
400 SetLastError(ERROR_OUTOFMEMORY);
401 ret = FALSE;
404 if (!ret)
405 goto end;
406 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &contentSize);
407 if (!ret)
408 goto end;
409 content = CryptMemAlloc(contentSize);
410 if (content)
412 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, content,
413 &contentSize);
414 if (ret)
416 ret = CryptDecodeObjectEx(dwMsgAndCertEncodingType, PKCS_CTL,
417 content, contentSize, CRYPT_DECODE_ALLOC_FLAG, NULL,
418 &ctlInfo, &size);
419 if (ret)
421 ctl = Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl);
422 if (ctl)
424 BYTE *data = CryptMemAlloc(cbCtlEncoded);
426 if (data)
428 memcpy(data, pbCtlEncoded, cbCtlEncoded);
429 ctl->dwMsgAndCertEncodingType =
430 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
431 ctl->pbCtlEncoded = data;
432 ctl->cbCtlEncoded = cbCtlEncoded;
433 ctl->pCtlInfo = ctlInfo;
434 ctl->hCertStore = NULL;
435 ctl->hCryptMsg = msg;
436 ctl->pbCtlContext = content;
437 ctl->cbCtlContext = contentSize;
439 else
441 SetLastError(ERROR_OUTOFMEMORY);
442 ret = FALSE;
445 else
447 SetLastError(ERROR_OUTOFMEMORY);
448 ret = FALSE;
453 else
455 SetLastError(ERROR_OUTOFMEMORY);
456 ret = FALSE;
459 end:
460 if (!ret)
462 CertFreeCTLContext(ctl);
463 ctl = NULL;
464 LocalFree(ctlInfo);
465 CryptMemFree(content);
466 CryptMsgClose(msg);
468 return ctl;
471 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
473 TRACE("(%p)\n", pCtlContext);
474 if (pCtlContext)
475 Context_AddRef(&ctl_from_ptr(pCtlContext)->base);
476 return pCtlContext;
479 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
481 BOOL ret = TRUE;
483 TRACE("(%p)\n", pCTLContext);
485 if (pCTLContext)
486 ret = Context_Release(&ctl_from_ptr(pCTLContext)->base);
487 return ret;
490 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
491 DWORD dwPropId)
493 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(pCTLContext);
494 DWORD ret;
496 TRACE("(%p, %d)\n", pCTLContext, dwPropId);
498 if (properties)
499 ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
500 else
501 ret = 0;
502 return ret;
505 static BOOL CTLContext_SetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
506 DWORD dwFlags, const void *pvData);
508 static BOOL CTLContext_GetHashProp(PCCTL_CONTEXT context, DWORD dwPropId,
509 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
510 DWORD *pcbData)
512 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
513 pcbData);
514 if (ret && pvData)
516 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
518 ret = CTLContext_SetProperty(context, dwPropId, 0, &blob);
520 return ret;
523 static BOOL CTLContext_GetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
524 void *pvData, DWORD *pcbData)
526 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(context);
527 BOOL ret;
528 CRYPT_DATA_BLOB blob;
530 TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
532 if (properties)
533 ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
534 else
535 ret = FALSE;
536 if (ret)
538 if (!pvData)
539 *pcbData = blob.cbData;
540 else if (*pcbData < blob.cbData)
542 SetLastError(ERROR_MORE_DATA);
543 *pcbData = blob.cbData;
544 ret = FALSE;
546 else
548 memcpy(pvData, blob.pbData, blob.cbData);
549 *pcbData = blob.cbData;
552 else
554 /* Implicit properties */
555 switch (dwPropId)
557 case CERT_SHA1_HASH_PROP_ID:
558 ret = CTLContext_GetHashProp(context, dwPropId, CALG_SHA1,
559 context->pbCtlEncoded, context->cbCtlEncoded, pvData, pcbData);
560 break;
561 case CERT_MD5_HASH_PROP_ID:
562 ret = CTLContext_GetHashProp(context, dwPropId, CALG_MD5,
563 context->pbCtlEncoded, context->cbCtlEncoded, pvData, pcbData);
564 break;
565 default:
566 SetLastError(CRYPT_E_NOT_FOUND);
569 TRACE("returning %d\n", ret);
570 return ret;
573 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
574 DWORD dwPropId, void *pvData, DWORD *pcbData)
576 BOOL ret;
578 TRACE("(%p, %d, %p, %p)\n", pCTLContext, dwPropId, pvData, pcbData);
580 switch (dwPropId)
582 case 0:
583 case CERT_CERT_PROP_ID:
584 case CERT_CRL_PROP_ID:
585 case CERT_CTL_PROP_ID:
586 SetLastError(E_INVALIDARG);
587 ret = FALSE;
588 break;
589 case CERT_ACCESS_STATE_PROP_ID:
590 if (!pvData)
592 *pcbData = sizeof(DWORD);
593 ret = TRUE;
595 else if (*pcbData < sizeof(DWORD))
597 SetLastError(ERROR_MORE_DATA);
598 *pcbData = sizeof(DWORD);
599 ret = FALSE;
601 else
603 if (pCTLContext->hCertStore)
604 ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId,
605 pvData, pcbData);
606 else
608 *(DWORD *)pvData = 0;
609 ret = TRUE;
612 break;
613 default:
614 ret = CTLContext_GetProperty(pCTLContext, dwPropId, pvData,
615 pcbData);
617 return ret;
620 static BOOL CTLContext_SetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
621 DWORD dwFlags, const void *pvData)
623 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(context);
624 BOOL ret;
626 TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
628 if (!properties)
629 ret = FALSE;
630 else if (!pvData)
632 ContextPropertyList_RemoveProperty(properties, dwPropId);
633 ret = TRUE;
635 else
637 switch (dwPropId)
639 case CERT_AUTO_ENROLL_PROP_ID:
640 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
641 case CERT_DESCRIPTION_PROP_ID:
642 case CERT_FRIENDLY_NAME_PROP_ID:
643 case CERT_HASH_PROP_ID:
644 case CERT_KEY_IDENTIFIER_PROP_ID:
645 case CERT_MD5_HASH_PROP_ID:
646 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
647 case CERT_PUBKEY_ALG_PARA_PROP_ID:
648 case CERT_PVK_FILE_PROP_ID:
649 case CERT_SIGNATURE_HASH_PROP_ID:
650 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
651 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
652 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
653 case CERT_ENROLLMENT_PROP_ID:
654 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
655 case CERT_RENEWAL_PROP_ID:
657 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
659 ret = ContextPropertyList_SetProperty(properties, dwPropId,
660 blob->pbData, blob->cbData);
661 break;
663 case CERT_DATE_STAMP_PROP_ID:
664 ret = ContextPropertyList_SetProperty(properties, dwPropId,
665 pvData, sizeof(FILETIME));
666 break;
667 default:
668 FIXME("%d: stub\n", dwPropId);
669 ret = FALSE;
672 TRACE("returning %d\n", ret);
673 return ret;
676 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
677 DWORD dwPropId, DWORD dwFlags, const void *pvData)
679 BOOL ret;
681 TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData);
683 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
684 * crashes on most of these, I'll be safer.
686 switch (dwPropId)
688 case 0:
689 case CERT_ACCESS_STATE_PROP_ID:
690 case CERT_CERT_PROP_ID:
691 case CERT_CRL_PROP_ID:
692 case CERT_CTL_PROP_ID:
693 SetLastError(E_INVALIDARG);
694 return FALSE;
696 ret = CTLContext_SetProperty(pCTLContext, dwPropId, dwFlags, pvData);
697 TRACE("returning %d\n", ret);
698 return ret;