crypt32: Added cloning logic to context's vtbl.
[wine.git] / dlls / crypt32 / ctl.c
blobed92f9022b9538ea0be2de09e3326a3276adae4f
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 context_t *CTL_clone(context_t *context, WINECRYPT_CERTSTORE *store)
44 ctl_t *ctl;
46 ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context);
47 if(!ctl)
48 return NULL;
50 ctl->ctx.hCertStore = store;
51 return &ctl->base;
54 static const context_vtbl_t ctl_vtbl = {
55 CTL_free,
56 CTL_clone
59 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
60 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
61 PCCTL_CONTEXT* ppStoreContext)
63 WINECRYPT_CERTSTORE *store = hCertStore;
64 BOOL ret = TRUE;
65 PCCTL_CONTEXT toAdd = NULL, existing = NULL;
67 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition,
68 ppStoreContext);
70 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
72 existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING,
73 pCtlContext, NULL);
76 switch (dwAddDisposition)
78 case CERT_STORE_ADD_ALWAYS:
79 toAdd = CertDuplicateCTLContext(pCtlContext);
80 break;
81 case CERT_STORE_ADD_NEW:
82 if (existing)
84 TRACE("found matching CTL, not adding\n");
85 SetLastError(CRYPT_E_EXISTS);
86 ret = FALSE;
88 else
89 toAdd = CertDuplicateCTLContext(pCtlContext);
90 break;
91 case CERT_STORE_ADD_NEWER:
92 if (existing)
94 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
95 &pCtlContext->pCtlInfo->ThisUpdate);
97 if (newer < 0)
98 toAdd = CertDuplicateCTLContext(pCtlContext);
99 else
101 TRACE("existing CTL is newer, not adding\n");
102 SetLastError(CRYPT_E_EXISTS);
103 ret = FALSE;
106 else
107 toAdd = CertDuplicateCTLContext(pCtlContext);
108 break;
109 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
110 if (existing)
112 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
113 &pCtlContext->pCtlInfo->ThisUpdate);
115 if (newer < 0)
117 toAdd = CertDuplicateCTLContext(pCtlContext);
118 Context_CopyProperties(existing, pCtlContext);
120 else
122 TRACE("existing CTL is newer, not adding\n");
123 SetLastError(CRYPT_E_EXISTS);
124 ret = FALSE;
127 else
128 toAdd = CertDuplicateCTLContext(pCtlContext);
129 break;
130 case CERT_STORE_ADD_REPLACE_EXISTING:
131 toAdd = CertDuplicateCTLContext(pCtlContext);
132 break;
133 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
134 toAdd = CertDuplicateCTLContext(pCtlContext);
135 if (existing)
136 Context_CopyProperties(toAdd, existing);
137 break;
138 case CERT_STORE_ADD_USE_EXISTING:
139 if (existing)
141 Context_CopyProperties(existing, pCtlContext);
142 if (ppStoreContext)
143 *ppStoreContext = CertDuplicateCTLContext(existing);
145 else
146 toAdd = CertDuplicateCTLContext(pCtlContext);
147 break;
148 default:
149 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
150 ret = FALSE;
153 if (toAdd)
155 if (store)
156 ret = store->vtbl->ctls.addContext(store, (void *)toAdd,
157 (void *)existing, (const void **)ppStoreContext);
158 else if (ppStoreContext)
159 *ppStoreContext = CertDuplicateCTLContext(toAdd);
160 CertFreeCTLContext(toAdd);
162 CertFreeCTLContext(existing);
164 TRACE("returning %d\n", ret);
165 return ret;
168 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
169 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
170 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
172 PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType,
173 pbCtlEncoded, cbCtlEncoded);
174 BOOL ret;
176 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore,
177 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
178 ppCtlContext);
180 if (ctl)
182 ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition,
183 ppCtlContext);
184 CertFreeCTLContext(ctl);
186 else
187 ret = FALSE;
188 return ret;
191 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
192 PCCTL_CONTEXT pPrev)
194 WINECRYPT_CERTSTORE *hcs = hCertStore;
195 PCCTL_CONTEXT ret;
197 TRACE("(%p, %p)\n", hCertStore, pPrev);
198 if (!hCertStore)
199 ret = NULL;
200 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
201 ret = NULL;
202 else
203 ret = (PCCTL_CONTEXT)hcs->vtbl->ctls.enumContext(hcs, (void *)pPrev);
204 return ret;
207 typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType,
208 DWORD dwFlags, const void *pvPara);
210 static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType,
211 DWORD dwFlags, const void *pvPara)
213 return TRUE;
216 static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
217 DWORD dwFlags, const void *pvPara)
219 BOOL ret;
220 BYTE hash[16];
221 DWORD size = sizeof(hash);
223 ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_HASH_PROP_ID, hash,
224 &size);
225 if (ret)
227 const CRYPT_HASH_BLOB *pHash = pvPara;
229 if (size == pHash->cbData)
230 ret = !memcmp(pHash->pbData, hash, size);
231 else
232 ret = FALSE;
234 return ret;
237 static BOOL compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
238 DWORD dwFlags, const void *pvPara)
240 BOOL ret;
241 BYTE hash[20];
242 DWORD size = sizeof(hash);
244 ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash,
245 &size);
246 if (ret)
248 const CRYPT_HASH_BLOB *pHash = pvPara;
250 if (size == pHash->cbData)
251 ret = !memcmp(pHash->pbData, hash, size);
252 else
253 ret = FALSE;
255 return ret;
258 static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType,
259 DWORD dwFlags, const void *pvPara)
261 BOOL ret;
263 if (pvPara)
265 PCCTL_CONTEXT ctl = pvPara;
267 if (pCtlContext->cbCtlContext == ctl->cbCtlContext)
269 if (ctl->cbCtlContext)
270 ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext,
271 ctl->cbCtlContext);
272 else
273 ret = TRUE;
275 else
276 ret = FALSE;
278 else
279 ret = FALSE;
280 return ret;
283 PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore,
284 DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
285 const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext)
287 PCCTL_CONTEXT ret;
288 CtlCompareFunc compare;
290 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
291 dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext);
293 switch (dwFindType)
295 case CTL_FIND_ANY:
296 compare = compare_ctl_any;
297 break;
298 case CTL_FIND_SHA1_HASH:
299 compare = compare_ctl_by_sha1_hash;
300 break;
301 case CTL_FIND_MD5_HASH:
302 compare = compare_ctl_by_md5_hash;
303 break;
304 case CTL_FIND_EXISTING:
305 compare = compare_ctl_existing;
306 break;
307 default:
308 FIXME("find type %08x unimplemented\n", dwFindType);
309 compare = NULL;
312 if (compare)
314 BOOL matches = FALSE;
316 ret = pPrevCtlContext;
317 do {
318 ret = CertEnumCTLsInStore(hCertStore, ret);
319 if (ret)
320 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
321 } while (ret != NULL && !matches);
322 if (!ret)
323 SetLastError(CRYPT_E_NOT_FOUND);
325 else
327 SetLastError(CRYPT_E_NOT_FOUND);
328 ret = NULL;
330 return ret;
333 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
335 BOOL ret;
337 TRACE("(%p)\n", pCtlContext);
339 if (!pCtlContext)
340 ret = TRUE;
341 else if (!pCtlContext->hCertStore)
342 ret = CertFreeCTLContext(pCtlContext);
343 else
345 WINECRYPT_CERTSTORE *hcs = pCtlContext->hCertStore;
346 ctl_t *ctl = ctl_from_ptr(pCtlContext);
348 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
349 ret = FALSE;
350 else
351 ret = hcs->vtbl->ctls.delete(hcs, &ctl->base);
352 if (ret)
353 ret = CertFreeCTLContext(pCtlContext);
355 return ret;
358 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
359 const BYTE *pbCtlEncoded, DWORD cbCtlEncoded)
361 PCTL_CONTEXT ctl = NULL;
362 HCRYPTMSG msg;
363 BOOL ret;
364 BYTE *content = NULL;
365 DWORD contentSize = 0, size;
366 PCTL_INFO ctlInfo = NULL;
368 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType, pbCtlEncoded,
369 cbCtlEncoded);
371 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType) != X509_ASN_ENCODING)
373 SetLastError(E_INVALIDARG);
374 return NULL;
376 if (!pbCtlEncoded || !cbCtlEncoded)
378 SetLastError(ERROR_INVALID_DATA);
379 return NULL;
381 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0,
382 0, NULL, NULL);
383 if (!msg)
384 return NULL;
385 ret = CryptMsgUpdate(msg, pbCtlEncoded, cbCtlEncoded, TRUE);
386 if (!ret)
388 SetLastError(ERROR_INVALID_DATA);
389 goto end;
391 /* Check that it's really a CTL */
392 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size);
393 if (ret)
395 char *innerContent = CryptMemAlloc(size);
397 if (innerContent)
399 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0,
400 innerContent, &size);
401 if (ret)
403 if (strcmp(innerContent, szOID_CTL))
405 SetLastError(ERROR_INVALID_DATA);
406 ret = FALSE;
409 CryptMemFree(innerContent);
411 else
413 SetLastError(ERROR_OUTOFMEMORY);
414 ret = FALSE;
417 if (!ret)
418 goto end;
419 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &contentSize);
420 if (!ret)
421 goto end;
422 content = CryptMemAlloc(contentSize);
423 if (content)
425 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, content,
426 &contentSize);
427 if (ret)
429 ret = CryptDecodeObjectEx(dwMsgAndCertEncodingType, PKCS_CTL,
430 content, contentSize, CRYPT_DECODE_ALLOC_FLAG, NULL,
431 &ctlInfo, &size);
432 if (ret)
434 ctl = Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl);
435 if (ctl)
437 BYTE *data = CryptMemAlloc(cbCtlEncoded);
439 if (data)
441 memcpy(data, pbCtlEncoded, cbCtlEncoded);
442 ctl->dwMsgAndCertEncodingType =
443 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
444 ctl->pbCtlEncoded = data;
445 ctl->cbCtlEncoded = cbCtlEncoded;
446 ctl->pCtlInfo = ctlInfo;
447 ctl->hCertStore = NULL;
448 ctl->hCryptMsg = msg;
449 ctl->pbCtlContext = content;
450 ctl->cbCtlContext = contentSize;
452 else
454 SetLastError(ERROR_OUTOFMEMORY);
455 ret = FALSE;
458 else
460 SetLastError(ERROR_OUTOFMEMORY);
461 ret = FALSE;
466 else
468 SetLastError(ERROR_OUTOFMEMORY);
469 ret = FALSE;
472 end:
473 if (!ret)
475 CertFreeCTLContext(ctl);
476 ctl = NULL;
477 LocalFree(ctlInfo);
478 CryptMemFree(content);
479 CryptMsgClose(msg);
481 return ctl;
484 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
486 TRACE("(%p)\n", pCtlContext);
487 if (pCtlContext)
488 Context_AddRef(&ctl_from_ptr(pCtlContext)->base);
489 return pCtlContext;
492 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
494 BOOL ret = TRUE;
496 TRACE("(%p)\n", pCTLContext);
498 if (pCTLContext)
499 ret = Context_Release(&ctl_from_ptr(pCTLContext)->base);
500 return ret;
503 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
504 DWORD dwPropId)
506 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(pCTLContext);
507 DWORD ret;
509 TRACE("(%p, %d)\n", pCTLContext, dwPropId);
511 if (properties)
512 ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
513 else
514 ret = 0;
515 return ret;
518 static BOOL CTLContext_SetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
519 DWORD dwFlags, const void *pvData);
521 static BOOL CTLContext_GetHashProp(PCCTL_CONTEXT context, DWORD dwPropId,
522 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
523 DWORD *pcbData)
525 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
526 pcbData);
527 if (ret && pvData)
529 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
531 ret = CTLContext_SetProperty(context, dwPropId, 0, &blob);
533 return ret;
536 static BOOL CTLContext_GetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
537 void *pvData, DWORD *pcbData)
539 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(context);
540 BOOL ret;
541 CRYPT_DATA_BLOB blob;
543 TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
545 if (properties)
546 ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
547 else
548 ret = FALSE;
549 if (ret)
551 if (!pvData)
552 *pcbData = blob.cbData;
553 else if (*pcbData < blob.cbData)
555 SetLastError(ERROR_MORE_DATA);
556 *pcbData = blob.cbData;
557 ret = FALSE;
559 else
561 memcpy(pvData, blob.pbData, blob.cbData);
562 *pcbData = blob.cbData;
565 else
567 /* Implicit properties */
568 switch (dwPropId)
570 case CERT_SHA1_HASH_PROP_ID:
571 ret = CTLContext_GetHashProp(context, dwPropId, CALG_SHA1,
572 context->pbCtlEncoded, context->cbCtlEncoded, pvData, pcbData);
573 break;
574 case CERT_MD5_HASH_PROP_ID:
575 ret = CTLContext_GetHashProp(context, dwPropId, CALG_MD5,
576 context->pbCtlEncoded, context->cbCtlEncoded, pvData, pcbData);
577 break;
578 default:
579 SetLastError(CRYPT_E_NOT_FOUND);
582 TRACE("returning %d\n", ret);
583 return ret;
586 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
587 DWORD dwPropId, void *pvData, DWORD *pcbData)
589 BOOL ret;
591 TRACE("(%p, %d, %p, %p)\n", pCTLContext, dwPropId, pvData, pcbData);
593 switch (dwPropId)
595 case 0:
596 case CERT_CERT_PROP_ID:
597 case CERT_CRL_PROP_ID:
598 case CERT_CTL_PROP_ID:
599 SetLastError(E_INVALIDARG);
600 ret = FALSE;
601 break;
602 case CERT_ACCESS_STATE_PROP_ID:
603 if (!pvData)
605 *pcbData = sizeof(DWORD);
606 ret = TRUE;
608 else if (*pcbData < sizeof(DWORD))
610 SetLastError(ERROR_MORE_DATA);
611 *pcbData = sizeof(DWORD);
612 ret = FALSE;
614 else
616 if (pCTLContext->hCertStore)
617 ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId,
618 pvData, pcbData);
619 else
621 *(DWORD *)pvData = 0;
622 ret = TRUE;
625 break;
626 default:
627 ret = CTLContext_GetProperty(pCTLContext, dwPropId, pvData,
628 pcbData);
630 return ret;
633 static BOOL CTLContext_SetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
634 DWORD dwFlags, const void *pvData)
636 CONTEXT_PROPERTY_LIST *properties = Context_GetProperties(context);
637 BOOL ret;
639 TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
641 if (!properties)
642 ret = FALSE;
643 else if (!pvData)
645 ContextPropertyList_RemoveProperty(properties, dwPropId);
646 ret = TRUE;
648 else
650 switch (dwPropId)
652 case CERT_AUTO_ENROLL_PROP_ID:
653 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
654 case CERT_DESCRIPTION_PROP_ID:
655 case CERT_FRIENDLY_NAME_PROP_ID:
656 case CERT_HASH_PROP_ID:
657 case CERT_KEY_IDENTIFIER_PROP_ID:
658 case CERT_MD5_HASH_PROP_ID:
659 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
660 case CERT_PUBKEY_ALG_PARA_PROP_ID:
661 case CERT_PVK_FILE_PROP_ID:
662 case CERT_SIGNATURE_HASH_PROP_ID:
663 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
664 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
665 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
666 case CERT_ENROLLMENT_PROP_ID:
667 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
668 case CERT_RENEWAL_PROP_ID:
670 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
672 ret = ContextPropertyList_SetProperty(properties, dwPropId,
673 blob->pbData, blob->cbData);
674 break;
676 case CERT_DATE_STAMP_PROP_ID:
677 ret = ContextPropertyList_SetProperty(properties, dwPropId,
678 pvData, sizeof(FILETIME));
679 break;
680 default:
681 FIXME("%d: stub\n", dwPropId);
682 ret = FALSE;
685 TRACE("returning %d\n", ret);
686 return ret;
689 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
690 DWORD dwPropId, DWORD dwFlags, const void *pvData)
692 BOOL ret;
694 TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData);
696 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
697 * crashes on most of these, I'll be safer.
699 switch (dwPropId)
701 case 0:
702 case CERT_ACCESS_STATE_PROP_ID:
703 case CERT_CERT_PROP_ID:
704 case CERT_CRL_PROP_ID:
705 case CERT_CTL_PROP_ID:
706 SetLastError(E_INVALIDARG);
707 return FALSE;
709 ret = CTLContext_SetProperty(pCTLContext, dwPropId, dwFlags, pvData);
710 TRACE("returning %d\n", ret);
711 return ret;