crypt32: Store properties directly in link contexts and get rid of Context_GetProperties.
[wine.git] / dlls / crypt32 / ctl.c
blob2811260ee28734b92e8069464315cceb2ba8d516
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, BOOL use_link)
44 ctl_t *ctl;
46 if(!use_link) {
47 FIXME("Only links supported\n");
48 return NULL;
51 ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context);
52 if(!ctl)
53 return NULL;
55 ctl->ctx.hCertStore = store;
56 return &ctl->base;
59 static const context_vtbl_t ctl_vtbl = {
60 CTL_free,
61 CTL_clone
64 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
65 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
66 PCCTL_CONTEXT* ppStoreContext)
68 WINECRYPT_CERTSTORE *store = hCertStore;
69 BOOL ret = TRUE;
70 PCCTL_CONTEXT toAdd = NULL, existing = NULL;
72 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition,
73 ppStoreContext);
75 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
77 existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING,
78 pCtlContext, NULL);
81 switch (dwAddDisposition)
83 case CERT_STORE_ADD_ALWAYS:
84 toAdd = CertDuplicateCTLContext(pCtlContext);
85 break;
86 case CERT_STORE_ADD_NEW:
87 if (existing)
89 TRACE("found matching CTL, not adding\n");
90 SetLastError(CRYPT_E_EXISTS);
91 ret = FALSE;
93 else
94 toAdd = CertDuplicateCTLContext(pCtlContext);
95 break;
96 case CERT_STORE_ADD_NEWER:
97 if (existing)
99 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
100 &pCtlContext->pCtlInfo->ThisUpdate);
102 if (newer < 0)
103 toAdd = CertDuplicateCTLContext(pCtlContext);
104 else
106 TRACE("existing CTL is newer, not adding\n");
107 SetLastError(CRYPT_E_EXISTS);
108 ret = FALSE;
111 else
112 toAdd = CertDuplicateCTLContext(pCtlContext);
113 break;
114 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
115 if (existing)
117 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
118 &pCtlContext->pCtlInfo->ThisUpdate);
120 if (newer < 0)
122 toAdd = CertDuplicateCTLContext(pCtlContext);
123 Context_CopyProperties(existing, pCtlContext);
125 else
127 TRACE("existing CTL is newer, not adding\n");
128 SetLastError(CRYPT_E_EXISTS);
129 ret = FALSE;
132 else
133 toAdd = CertDuplicateCTLContext(pCtlContext);
134 break;
135 case CERT_STORE_ADD_REPLACE_EXISTING:
136 toAdd = CertDuplicateCTLContext(pCtlContext);
137 break;
138 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
139 toAdd = CertDuplicateCTLContext(pCtlContext);
140 if (existing)
141 Context_CopyProperties(toAdd, existing);
142 break;
143 case CERT_STORE_ADD_USE_EXISTING:
144 if (existing)
146 Context_CopyProperties(existing, pCtlContext);
147 if (ppStoreContext)
148 *ppStoreContext = CertDuplicateCTLContext(existing);
150 else
151 toAdd = CertDuplicateCTLContext(pCtlContext);
152 break;
153 default:
154 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
155 ret = FALSE;
158 if (toAdd)
160 if (store)
161 ret = store->vtbl->ctls.addContext(store, (void *)toAdd,
162 (void *)existing, (const void **)ppStoreContext, TRUE);
163 else if (ppStoreContext)
164 *ppStoreContext = CertDuplicateCTLContext(toAdd);
165 CertFreeCTLContext(toAdd);
167 CertFreeCTLContext(existing);
169 TRACE("returning %d\n", ret);
170 return ret;
173 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
174 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
175 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
177 PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType,
178 pbCtlEncoded, cbCtlEncoded);
179 BOOL ret;
181 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore,
182 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
183 ppCtlContext);
185 if (ctl)
187 ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition,
188 ppCtlContext);
189 CertFreeCTLContext(ctl);
191 else
192 ret = FALSE;
193 return ret;
196 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
197 PCCTL_CONTEXT pPrev)
199 WINECRYPT_CERTSTORE *hcs = hCertStore;
200 PCCTL_CONTEXT ret;
202 TRACE("(%p, %p)\n", hCertStore, pPrev);
203 if (!hCertStore)
204 ret = NULL;
205 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
206 ret = NULL;
207 else
208 ret = (PCCTL_CONTEXT)hcs->vtbl->ctls.enumContext(hcs, (void *)pPrev);
209 return ret;
212 typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType,
213 DWORD dwFlags, const void *pvPara);
215 static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType,
216 DWORD dwFlags, const void *pvPara)
218 return TRUE;
221 static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
222 DWORD dwFlags, const void *pvPara)
224 BOOL ret;
225 BYTE hash[16];
226 DWORD size = sizeof(hash);
228 ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_HASH_PROP_ID, hash,
229 &size);
230 if (ret)
232 const CRYPT_HASH_BLOB *pHash = pvPara;
234 if (size == pHash->cbData)
235 ret = !memcmp(pHash->pbData, hash, size);
236 else
237 ret = FALSE;
239 return ret;
242 static BOOL compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
243 DWORD dwFlags, const void *pvPara)
245 BOOL ret;
246 BYTE hash[20];
247 DWORD size = sizeof(hash);
249 ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash,
250 &size);
251 if (ret)
253 const CRYPT_HASH_BLOB *pHash = pvPara;
255 if (size == pHash->cbData)
256 ret = !memcmp(pHash->pbData, hash, size);
257 else
258 ret = FALSE;
260 return ret;
263 static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType,
264 DWORD dwFlags, const void *pvPara)
266 BOOL ret;
268 if (pvPara)
270 PCCTL_CONTEXT ctl = pvPara;
272 if (pCtlContext->cbCtlContext == ctl->cbCtlContext)
274 if (ctl->cbCtlContext)
275 ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext,
276 ctl->cbCtlContext);
277 else
278 ret = TRUE;
280 else
281 ret = FALSE;
283 else
284 ret = FALSE;
285 return ret;
288 PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore,
289 DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
290 const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext)
292 PCCTL_CONTEXT ret;
293 CtlCompareFunc compare;
295 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
296 dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext);
298 switch (dwFindType)
300 case CTL_FIND_ANY:
301 compare = compare_ctl_any;
302 break;
303 case CTL_FIND_SHA1_HASH:
304 compare = compare_ctl_by_sha1_hash;
305 break;
306 case CTL_FIND_MD5_HASH:
307 compare = compare_ctl_by_md5_hash;
308 break;
309 case CTL_FIND_EXISTING:
310 compare = compare_ctl_existing;
311 break;
312 default:
313 FIXME("find type %08x unimplemented\n", dwFindType);
314 compare = NULL;
317 if (compare)
319 BOOL matches = FALSE;
321 ret = pPrevCtlContext;
322 do {
323 ret = CertEnumCTLsInStore(hCertStore, ret);
324 if (ret)
325 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
326 } while (ret != NULL && !matches);
327 if (!ret)
328 SetLastError(CRYPT_E_NOT_FOUND);
330 else
332 SetLastError(CRYPT_E_NOT_FOUND);
333 ret = NULL;
335 return ret;
338 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
340 BOOL ret;
342 TRACE("(%p)\n", pCtlContext);
344 if (!pCtlContext)
345 ret = TRUE;
346 else if (!pCtlContext->hCertStore)
347 ret = CertFreeCTLContext(pCtlContext);
348 else
350 WINECRYPT_CERTSTORE *hcs = pCtlContext->hCertStore;
351 ctl_t *ctl = ctl_from_ptr(pCtlContext);
353 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
354 ret = FALSE;
355 else
356 ret = hcs->vtbl->ctls.delete(hcs, &ctl->base);
357 if (ret)
358 ret = CertFreeCTLContext(pCtlContext);
360 return ret;
363 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
364 const BYTE *pbCtlEncoded, DWORD cbCtlEncoded)
366 PCTL_CONTEXT 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 = Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl);
440 if (ctl)
442 BYTE *data = CryptMemAlloc(cbCtlEncoded);
444 if (data)
446 memcpy(data, pbCtlEncoded, cbCtlEncoded);
447 ctl->dwMsgAndCertEncodingType =
448 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
449 ctl->pbCtlEncoded = data;
450 ctl->cbCtlEncoded = cbCtlEncoded;
451 ctl->pCtlInfo = ctlInfo;
452 ctl->hCertStore = NULL;
453 ctl->hCryptMsg = msg;
454 ctl->pbCtlContext = content;
455 ctl->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 CertFreeCTLContext(ctl);
481 ctl = NULL;
482 LocalFree(ctlInfo);
483 CryptMemFree(content);
484 CryptMsgClose(msg);
486 return ctl;
489 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
491 TRACE("(%p)\n", pCtlContext);
492 if (pCtlContext)
493 Context_AddRef(&ctl_from_ptr(pCtlContext)->base);
494 return pCtlContext;
497 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
499 BOOL ret = TRUE;
501 TRACE("(%p)\n", pCTLContext);
503 if (pCTLContext)
504 ret = Context_Release(&ctl_from_ptr(pCTLContext)->base);
505 return ret;
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 if (pCTLContext->hCertStore)
621 ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId,
622 pvData, pcbData);
623 else
625 *(DWORD *)pvData = 0;
626 ret = TRUE;
629 break;
630 default:
631 ret = CTLContext_GetProperty(ctl_from_ptr(pCTLContext), dwPropId, pvData,
632 pcbData);
634 return ret;
637 static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId,
638 DWORD dwFlags, const void *pvData)
640 BOOL ret;
642 TRACE("(%p, %d, %08x, %p)\n", ctl, dwPropId, dwFlags, pvData);
644 if (!ctl->base.properties)
645 ret = FALSE;
646 else if (!pvData)
648 ContextPropertyList_RemoveProperty(ctl->base.properties, dwPropId);
649 ret = TRUE;
651 else
653 switch (dwPropId)
655 case CERT_AUTO_ENROLL_PROP_ID:
656 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
657 case CERT_DESCRIPTION_PROP_ID:
658 case CERT_FRIENDLY_NAME_PROP_ID:
659 case CERT_HASH_PROP_ID:
660 case CERT_KEY_IDENTIFIER_PROP_ID:
661 case CERT_MD5_HASH_PROP_ID:
662 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
663 case CERT_PUBKEY_ALG_PARA_PROP_ID:
664 case CERT_PVK_FILE_PROP_ID:
665 case CERT_SIGNATURE_HASH_PROP_ID:
666 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
667 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
668 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
669 case CERT_ENROLLMENT_PROP_ID:
670 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
671 case CERT_RENEWAL_PROP_ID:
673 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
675 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
676 blob->pbData, blob->cbData);
677 break;
679 case CERT_DATE_STAMP_PROP_ID:
680 ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
681 pvData, sizeof(FILETIME));
682 break;
683 default:
684 FIXME("%d: stub\n", dwPropId);
685 ret = FALSE;
688 TRACE("returning %d\n", ret);
689 return ret;
692 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
693 DWORD dwPropId, DWORD dwFlags, const void *pvData)
695 BOOL ret;
697 TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData);
699 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
700 * crashes on most of these, I'll be safer.
702 switch (dwPropId)
704 case 0:
705 case CERT_ACCESS_STATE_PROP_ID:
706 case CERT_CERT_PROP_ID:
707 case CERT_CRL_PROP_ID:
708 case CERT_CTL_PROP_ID:
709 SetLastError(E_INVALIDARG);
710 return FALSE;
712 ret = CTLContext_SetProperty(ctl_from_ptr(pCTLContext), dwPropId, dwFlags, pvData);
713 TRACE("returning %d\n", ret);
714 return ret;