msvcrtd: Fix _CrtDbgReport calling convention.
[wine.git] / dlls / crypt32 / ctl.c
blobb8b728f387cd21f9035453601e4ae8eb000c8555
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 #include "windef.h"
24 #include "winbase.h"
25 #include "wincrypt.h"
26 #include "wine/debug.h"
27 #include "crypt32_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
31 static void CTL_free(context_t *context)
33 ctl_t *ctl = (ctl_t*)context;
35 CryptMsgClose(ctl->ctx.hCryptMsg);
36 CryptMemFree(ctl->ctx.pbCtlEncoded);
37 CryptMemFree(ctl->ctx.pbCtlContext);
38 LocalFree(ctl->ctx.pCtlInfo);
41 static context_t *CTL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
43 ctl_t *ctl;
45 if(!use_link) {
46 FIXME("Only links supported\n");
47 return NULL;
50 ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context, store);
51 if(!ctl)
52 return NULL;
54 ctl->ctx.hCertStore = store;
55 return &ctl->base;
58 static const context_vtbl_t ctl_vtbl = {
59 CTL_free,
60 CTL_clone
63 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
64 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
65 PCCTL_CONTEXT* ppStoreContext)
67 WINECRYPT_CERTSTORE *store = hCertStore;
68 BOOL ret = TRUE;
69 PCCTL_CONTEXT toAdd = NULL, existing = NULL;
71 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition,
72 ppStoreContext);
74 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
76 existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING,
77 pCtlContext, NULL);
80 switch (dwAddDisposition)
82 case CERT_STORE_ADD_ALWAYS:
83 toAdd = CertDuplicateCTLContext(pCtlContext);
84 break;
85 case CERT_STORE_ADD_NEW:
86 if (existing)
88 TRACE("found matching CTL, not adding\n");
89 SetLastError(CRYPT_E_EXISTS);
90 ret = FALSE;
92 else
93 toAdd = CertDuplicateCTLContext(pCtlContext);
94 break;
95 case CERT_STORE_ADD_NEWER:
96 if (existing)
98 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
99 &pCtlContext->pCtlInfo->ThisUpdate);
101 if (newer < 0)
102 toAdd = CertDuplicateCTLContext(pCtlContext);
103 else
105 TRACE("existing CTL is newer, not adding\n");
106 SetLastError(CRYPT_E_EXISTS);
107 ret = FALSE;
110 else
111 toAdd = CertDuplicateCTLContext(pCtlContext);
112 break;
113 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
114 if (existing)
116 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
117 &pCtlContext->pCtlInfo->ThisUpdate);
119 if (newer < 0)
121 toAdd = CertDuplicateCTLContext(pCtlContext);
122 Context_CopyProperties(existing, pCtlContext);
124 else
126 TRACE("existing CTL is newer, not adding\n");
127 SetLastError(CRYPT_E_EXISTS);
128 ret = FALSE;
131 else
132 toAdd = CertDuplicateCTLContext(pCtlContext);
133 break;
134 case CERT_STORE_ADD_REPLACE_EXISTING:
135 toAdd = CertDuplicateCTLContext(pCtlContext);
136 break;
137 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
138 toAdd = CertDuplicateCTLContext(pCtlContext);
139 if (existing)
140 Context_CopyProperties(toAdd, existing);
141 break;
142 case CERT_STORE_ADD_USE_EXISTING:
143 if (existing)
145 Context_CopyProperties(existing, pCtlContext);
146 if (ppStoreContext)
147 *ppStoreContext = CertDuplicateCTLContext(existing);
149 else
150 toAdd = CertDuplicateCTLContext(pCtlContext);
151 break;
152 default:
153 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
154 ret = FALSE;
157 if (toAdd)
159 if (store) {
160 context_t *ret_ctx;
162 ret = store->vtbl->ctls.addContext(store, context_from_ptr(toAdd),
163 existing ? context_from_ptr(existing) : NULL, ppStoreContext ? &ret_ctx : NULL, TRUE);
164 if(ret && ppStoreContext)
165 *ppStoreContext = context_ptr(ret_ctx);
166 }else if (ppStoreContext) {
167 *ppStoreContext = CertDuplicateCTLContext(toAdd);
169 CertFreeCTLContext(toAdd);
171 CertFreeCTLContext(existing);
173 TRACE("returning %d\n", ret);
174 return ret;
177 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
178 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
179 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
181 PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType,
182 pbCtlEncoded, cbCtlEncoded);
183 BOOL ret;
185 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore,
186 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
187 ppCtlContext);
189 if (ctl)
191 ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition,
192 ppCtlContext);
193 CertFreeCTLContext(ctl);
195 else
196 ret = FALSE;
197 return ret;
200 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore, PCCTL_CONTEXT pPrev)
202 ctl_t *prev = pPrev ? ctl_from_ptr(pPrev) : NULL, *ret;
203 WINECRYPT_CERTSTORE *hcs = hCertStore;
205 TRACE("(%p, %p)\n", hCertStore, pPrev);
206 if (!hCertStore)
207 ret = NULL;
208 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
209 ret = NULL;
210 else
211 ret = (ctl_t*)hcs->vtbl->ctls.enumContext(hcs, prev ? &prev->base : NULL);
212 return ret ? &ret->ctx : NULL;
215 typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType,
216 DWORD dwFlags, const void *pvPara);
218 static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType,
219 DWORD dwFlags, const void *pvPara)
221 return TRUE;
224 static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
225 DWORD dwFlags, const void *pvPara)
227 BOOL ret;
228 BYTE hash[16];
229 DWORD size = sizeof(hash);
231 ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_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_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
246 DWORD dwFlags, const void *pvPara)
248 BOOL ret;
249 BYTE hash[20];
250 DWORD size = sizeof(hash);
252 ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash,
253 &size);
254 if (ret)
256 const CRYPT_HASH_BLOB *pHash = pvPara;
258 if (size == pHash->cbData)
259 ret = !memcmp(pHash->pbData, hash, size);
260 else
261 ret = FALSE;
263 return ret;
266 static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType,
267 DWORD dwFlags, const void *pvPara)
269 BOOL ret;
271 if (pvPara)
273 PCCTL_CONTEXT ctl = pvPara;
275 if (pCtlContext->cbCtlContext == ctl->cbCtlContext)
277 if (ctl->cbCtlContext)
278 ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext,
279 ctl->cbCtlContext);
280 else
281 ret = TRUE;
283 else
284 ret = FALSE;
286 else
287 ret = FALSE;
288 return ret;
291 PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore,
292 DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
293 const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext)
295 PCCTL_CONTEXT ret;
296 CtlCompareFunc compare;
298 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
299 dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext);
301 switch (dwFindType)
303 case CTL_FIND_ANY:
304 compare = compare_ctl_any;
305 break;
306 case CTL_FIND_SHA1_HASH:
307 compare = compare_ctl_by_sha1_hash;
308 break;
309 case CTL_FIND_MD5_HASH:
310 compare = compare_ctl_by_md5_hash;
311 break;
312 case CTL_FIND_EXISTING:
313 compare = compare_ctl_existing;
314 break;
315 default:
316 FIXME("find type %08x unimplemented\n", dwFindType);
317 compare = NULL;
320 if (compare)
322 BOOL matches = FALSE;
324 ret = pPrevCtlContext;
325 do {
326 ret = CertEnumCTLsInStore(hCertStore, ret);
327 if (ret)
328 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
329 } while (ret != NULL && !matches);
330 if (!ret)
331 SetLastError(CRYPT_E_NOT_FOUND);
333 else
335 SetLastError(CRYPT_E_NOT_FOUND);
336 ret = NULL;
338 return ret;
341 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
343 WINECRYPT_CERTSTORE *hcs;
344 ctl_t *ctl = ctl_from_ptr(pCtlContext);
345 BOOL ret;
347 TRACE("(%p)\n", pCtlContext);
349 if (!pCtlContext)
350 return TRUE;
352 hcs = pCtlContext->hCertStore;
354 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
355 return FALSE;
357 ret = hcs->vtbl->ctls.delete(hcs, &ctl->base);
358 if (ret)
359 ret = CertFreeCTLContext(pCtlContext);
360 return ret;
363 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
364 const BYTE *pbCtlEncoded, DWORD cbCtlEncoded)
366 ctl_t *ctl = NULL;
367 HCRYPTMSG msg;
368 BOOL ret;
369 BYTE *content = NULL;
370 DWORD contentSize = 0, size;
371 PCTL_INFO ctlInfo = NULL;
373 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType, pbCtlEncoded,
374 cbCtlEncoded);
376 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType) != X509_ASN_ENCODING)
378 SetLastError(E_INVALIDARG);
379 return NULL;
381 if (!pbCtlEncoded || !cbCtlEncoded)
383 SetLastError(ERROR_INVALID_DATA);
384 return NULL;
386 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0,
387 0, NULL, NULL);
388 if (!msg)
389 return NULL;
390 ret = CryptMsgUpdate(msg, pbCtlEncoded, cbCtlEncoded, TRUE);
391 if (!ret)
393 SetLastError(ERROR_INVALID_DATA);
394 goto end;
396 /* Check that it's really a CTL */
397 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size);
398 if (ret)
400 char *innerContent = CryptMemAlloc(size);
402 if (innerContent)
404 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0,
405 innerContent, &size);
406 if (ret)
408 if (strcmp(innerContent, szOID_CTL))
410 SetLastError(ERROR_INVALID_DATA);
411 ret = FALSE;
414 CryptMemFree(innerContent);
416 else
418 SetLastError(ERROR_OUTOFMEMORY);
419 ret = FALSE;
422 if (!ret)
423 goto end;
424 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &contentSize);
425 if (!ret)
426 goto end;
427 content = CryptMemAlloc(contentSize);
428 if (content)
430 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, content,
431 &contentSize);
432 if (ret)
434 ret = CryptDecodeObjectEx(dwMsgAndCertEncodingType, PKCS_CTL,
435 content, contentSize, CRYPT_DECODE_ALLOC_FLAG, NULL,
436 &ctlInfo, &size);
437 if (ret)
439 ctl = (ctl_t*)Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl, &empty_store);
440 if (ctl)
442 BYTE *data = CryptMemAlloc(cbCtlEncoded);
444 if (data)
446 memcpy(data, pbCtlEncoded, cbCtlEncoded);
447 ctl->ctx.dwMsgAndCertEncodingType =
448 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
449 ctl->ctx.pbCtlEncoded = data;
450 ctl->ctx.cbCtlEncoded = cbCtlEncoded;
451 ctl->ctx.pCtlInfo = ctlInfo;
452 ctl->ctx.hCertStore = &empty_store;
453 ctl->ctx.hCryptMsg = msg;
454 ctl->ctx.pbCtlContext = content;
455 ctl->ctx.cbCtlContext = contentSize;
457 else
459 SetLastError(ERROR_OUTOFMEMORY);
460 ret = FALSE;
463 else
465 SetLastError(ERROR_OUTOFMEMORY);
466 ret = FALSE;
471 else
473 SetLastError(ERROR_OUTOFMEMORY);
474 ret = FALSE;
477 end:
478 if (!ret)
480 if(ctl)
481 Context_Release(&ctl->base);
482 ctl = NULL;
483 LocalFree(ctlInfo);
484 CryptMemFree(content);
485 CryptMsgClose(msg);
486 return NULL;
488 return &ctl->ctx;
491 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
493 TRACE("(%p)\n", pCtlContext);
494 if (pCtlContext)
495 Context_AddRef(&ctl_from_ptr(pCtlContext)->base);
496 return pCtlContext;
499 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
501 TRACE("(%p)\n", pCTLContext);
503 if (pCTLContext)
504 Context_Release(&ctl_from_ptr(pCTLContext)->base);
505 return TRUE;
508 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
509 DWORD dwPropId)
511 ctl_t *ctl = ctl_from_ptr(pCTLContext);
512 DWORD ret;
514 TRACE("(%p, %d)\n", pCTLContext, dwPropId);
516 if (ctl->base.properties)
517 ret = ContextPropertyList_EnumPropIDs(ctl->base.properties, dwPropId);
518 else
519 ret = 0;
520 return ret;
523 static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId,
524 DWORD dwFlags, const void *pvData);
526 static BOOL CTLContext_GetHashProp(ctl_t *ctl, DWORD dwPropId,
527 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
528 DWORD *pcbData)
530 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
531 pcbData);
532 if (ret && pvData)
534 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
536 ret = CTLContext_SetProperty(ctl, dwPropId, 0, &blob);
538 return ret;
541 static BOOL CTLContext_GetProperty(ctl_t *ctl, DWORD dwPropId,
542 void *pvData, DWORD *pcbData)
544 BOOL ret;
545 CRYPT_DATA_BLOB blob;
547 TRACE("(%p, %d, %p, %p)\n", ctl, dwPropId, pvData, pcbData);
549 if (ctl->base.properties)
550 ret = ContextPropertyList_FindProperty(ctl->base.properties, dwPropId, &blob);
551 else
552 ret = FALSE;
553 if (ret)
555 if (!pvData)
556 *pcbData = blob.cbData;
557 else if (*pcbData < blob.cbData)
559 SetLastError(ERROR_MORE_DATA);
560 *pcbData = blob.cbData;
561 ret = FALSE;
563 else
565 memcpy(pvData, blob.pbData, blob.cbData);
566 *pcbData = blob.cbData;
569 else
571 /* Implicit properties */
572 switch (dwPropId)
574 case CERT_SHA1_HASH_PROP_ID:
575 ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_SHA1,
576 ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData);
577 break;
578 case CERT_MD5_HASH_PROP_ID:
579 ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_MD5,
580 ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData);
581 break;
582 default:
583 SetLastError(CRYPT_E_NOT_FOUND);
586 TRACE("returning %d\n", ret);
587 return ret;
590 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
591 DWORD dwPropId, void *pvData, DWORD *pcbData)
593 BOOL ret;
595 TRACE("(%p, %d, %p, %p)\n", pCTLContext, dwPropId, pvData, pcbData);
597 switch (dwPropId)
599 case 0:
600 case CERT_CERT_PROP_ID:
601 case CERT_CRL_PROP_ID:
602 case CERT_CTL_PROP_ID:
603 SetLastError(E_INVALIDARG);
604 ret = FALSE;
605 break;
606 case CERT_ACCESS_STATE_PROP_ID:
607 if (!pvData)
609 *pcbData = sizeof(DWORD);
610 ret = TRUE;
612 else if (*pcbData < sizeof(DWORD))
614 SetLastError(ERROR_MORE_DATA);
615 *pcbData = sizeof(DWORD);
616 ret = FALSE;
618 else
620 ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId, pvData, pcbData);
622 break;
623 default:
624 ret = CTLContext_GetProperty(ctl_from_ptr(pCTLContext), dwPropId, pvData,
625 pcbData);
627 return ret;
630 static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId,
631 DWORD dwFlags, const void *pvData)
633 BOOL ret;
635 TRACE("(%p, %d, %08x, %p)\n", ctl, dwPropId, dwFlags, pvData);
637 if (!ctl->base.properties)
638 ret = FALSE;
639 else if (!pvData)
641 ContextPropertyList_RemoveProperty(ctl->base.properties, dwPropId);
642 ret = TRUE;
644 else
646 switch (dwPropId)
648 case CERT_AUTO_ENROLL_PROP_ID:
649 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
650 case CERT_DESCRIPTION_PROP_ID:
651 case CERT_FRIENDLY_NAME_PROP_ID:
652 case CERT_HASH_PROP_ID:
653 case CERT_KEY_IDENTIFIER_PROP_ID:
654 case CERT_MD5_HASH_PROP_ID:
655 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
656 case CERT_PUBKEY_ALG_PARA_PROP_ID:
657 case CERT_PVK_FILE_PROP_ID:
658 case CERT_SIGNATURE_HASH_PROP_ID:
659 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
660 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
661 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
662 case CERT_ENROLLMENT_PROP_ID:
663 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
664 case CERT_RENEWAL_PROP_ID:
666 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
668 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
669 blob->pbData, blob->cbData);
670 break;
672 case CERT_DATE_STAMP_PROP_ID:
673 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
674 pvData, sizeof(FILETIME));
675 break;
676 default:
677 FIXME("%d: stub\n", dwPropId);
678 ret = FALSE;
681 TRACE("returning %d\n", ret);
682 return ret;
685 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
686 DWORD dwPropId, DWORD dwFlags, const void *pvData)
688 BOOL ret;
690 TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData);
692 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
693 * crashes on most of these, I'll be safer.
695 switch (dwPropId)
697 case 0:
698 case CERT_ACCESS_STATE_PROP_ID:
699 case CERT_CERT_PROP_ID:
700 case CERT_CRL_PROP_ID:
701 case CERT_CTL_PROP_ID:
702 SetLastError(E_INVALIDARG);
703 return FALSE;
705 ret = CTLContext_SetProperty(ctl_from_ptr(pCTLContext), dwPropId, dwFlags, pvData);
706 TRACE("returning %d\n", ret);
707 return ret;