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
23 #define NONAMELESSUNION
27 #include "wine/debug.h"
28 #include "crypt32_private.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
32 #define CtlContext_CopyProperties(to, from) \
33 Context_CopyProperties((to), (from), sizeof(CTL_CONTEXT))
35 BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
36 PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
37 PCCTL_CONTEXT* ppStoreContext)
39 PWINECRYPT_CERTSTORE store = hCertStore;
41 PCCTL_CONTEXT toAdd = NULL, existing = NULL;
43 TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition,
46 if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
48 existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING,
52 switch (dwAddDisposition)
54 case CERT_STORE_ADD_ALWAYS:
55 toAdd = CertDuplicateCTLContext(pCtlContext);
57 case CERT_STORE_ADD_NEW:
60 TRACE("found matching CTL, not adding\n");
61 SetLastError(CRYPT_E_EXISTS);
65 toAdd = CertDuplicateCTLContext(pCtlContext);
67 case CERT_STORE_ADD_NEWER:
70 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
71 &pCtlContext->pCtlInfo->ThisUpdate);
74 toAdd = CertDuplicateCTLContext(pCtlContext);
77 TRACE("existing CTL is newer, not adding\n");
78 SetLastError(CRYPT_E_EXISTS);
83 toAdd = CertDuplicateCTLContext(pCtlContext);
85 case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
88 LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
89 &pCtlContext->pCtlInfo->ThisUpdate);
93 toAdd = CertDuplicateCTLContext(pCtlContext);
94 CtlContext_CopyProperties(existing, pCtlContext);
98 TRACE("existing CTL is newer, not adding\n");
99 SetLastError(CRYPT_E_EXISTS);
104 toAdd = CertDuplicateCTLContext(pCtlContext);
106 case CERT_STORE_ADD_REPLACE_EXISTING:
107 toAdd = CertDuplicateCTLContext(pCtlContext);
109 case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
110 toAdd = CertDuplicateCTLContext(pCtlContext);
112 CtlContext_CopyProperties(toAdd, existing);
114 case CERT_STORE_ADD_USE_EXISTING:
116 CtlContext_CopyProperties(existing, pCtlContext);
119 FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
126 ret = store->ctls.addContext(store, (void *)toAdd,
127 (void *)existing, (const void **)ppStoreContext);
128 else if (ppStoreContext)
129 *ppStoreContext = CertDuplicateCTLContext(toAdd);
130 CertFreeCTLContext(toAdd);
132 CertFreeCTLContext(existing);
134 TRACE("returning %d\n", ret);
138 BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
139 DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
140 DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
142 PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType,
143 pbCtlEncoded, cbCtlEncoded);
146 TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore,
147 dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
152 ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition,
154 CertFreeCTLContext(ctl);
161 PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore,
164 WINECRYPT_CERTSTORE *hcs = hCertStore;
167 TRACE("(%p, %p)\n", hCertStore, pPrev);
170 else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
173 ret = (PCCTL_CONTEXT)hcs->ctls.enumContext(hcs, (void *)pPrev);
177 typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType,
178 DWORD dwFlags, const void *pvPara);
180 static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType,
181 DWORD dwFlags, const void *pvPara)
186 static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
187 DWORD dwFlags, const void *pvPara)
191 DWORD size = sizeof(hash);
193 ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_HASH_PROP_ID, hash,
197 const CRYPT_HASH_BLOB *pHash = pvPara;
199 if (size == pHash->cbData)
200 ret = !memcmp(pHash->pbData, hash, size);
207 static BOOL compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
208 DWORD dwFlags, const void *pvPara)
212 DWORD size = sizeof(hash);
214 ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash,
218 const CRYPT_HASH_BLOB *pHash = pvPara;
220 if (size == pHash->cbData)
221 ret = !memcmp(pHash->pbData, hash, size);
228 static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType,
229 DWORD dwFlags, const void *pvPara)
235 PCCTL_CONTEXT ctl = pvPara;
237 if (pCtlContext->cbCtlContext == ctl->cbCtlContext)
239 if (ctl->cbCtlContext)
240 ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext,
253 PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore,
254 DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
255 const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext)
258 CtlCompareFunc compare;
260 TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
261 dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext);
266 compare = compare_ctl_any;
268 case CTL_FIND_SHA1_HASH:
269 compare = compare_ctl_by_sha1_hash;
271 case CTL_FIND_MD5_HASH:
272 compare = compare_ctl_by_md5_hash;
274 case CTL_FIND_EXISTING:
275 compare = compare_ctl_existing;
278 FIXME("find type %08x unimplemented\n", dwFindType);
284 BOOL matches = FALSE;
286 ret = pPrevCtlContext;
288 ret = CertEnumCTLsInStore(hCertStore, ret);
290 matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
291 } while (ret != NULL && !matches);
293 SetLastError(CRYPT_E_NOT_FOUND);
297 SetLastError(CRYPT_E_NOT_FOUND);
303 BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
307 TRACE("(%p)\n", pCtlContext);
311 else if (!pCtlContext->hCertStore)
312 ret = CertFreeCTLContext(pCtlContext);
315 PWINECRYPT_CERTSTORE hcs = pCtlContext->hCertStore;
317 if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
320 ret = hcs->ctls.deleteContext(hcs, (void *)pCtlContext);
322 ret = CertFreeCTLContext(pCtlContext);
327 PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
328 const BYTE *pbCtlEncoded, DWORD cbCtlEncoded)
330 PCTL_CONTEXT ctl = NULL;
333 BYTE *content = NULL;
334 DWORD contentSize = 0, size;
335 PCTL_INFO ctlInfo = NULL;
337 TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType, pbCtlEncoded,
340 if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType) != X509_ASN_ENCODING)
342 SetLastError(E_INVALIDARG);
345 if (!pbCtlEncoded || !cbCtlEncoded)
347 SetLastError(ERROR_INVALID_DATA);
350 msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0,
354 ret = CryptMsgUpdate(msg, pbCtlEncoded, cbCtlEncoded, TRUE);
357 SetLastError(ERROR_INVALID_DATA);
360 /* Check that it's really a CTL */
361 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size);
364 char *innerContent = CryptMemAlloc(size);
368 ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0,
369 innerContent, &size);
372 if (strcmp(innerContent, szOID_CTL))
374 SetLastError(ERROR_INVALID_DATA);
378 CryptMemFree(innerContent);
382 SetLastError(ERROR_OUTOFMEMORY);
388 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &contentSize);
391 content = CryptMemAlloc(contentSize);
394 ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, content,
398 ret = CryptDecodeObjectEx(dwMsgAndCertEncodingType, PKCS_CTL,
399 content, contentSize, CRYPT_DECODE_ALLOC_FLAG, NULL,
403 ctl = Context_CreateDataContext(sizeof(CTL_CONTEXT));
406 BYTE *data = CryptMemAlloc(cbCtlEncoded);
410 memcpy(data, pbCtlEncoded, cbCtlEncoded);
411 ctl->dwMsgAndCertEncodingType =
412 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
413 ctl->pbCtlEncoded = data;
414 ctl->cbCtlEncoded = cbCtlEncoded;
415 ctl->pCtlInfo = ctlInfo;
416 ctl->hCertStore = NULL;
417 ctl->hCryptMsg = msg;
418 ctl->pbCtlContext = content;
419 ctl->cbCtlContext = contentSize;
423 SetLastError(ERROR_OUTOFMEMORY);
429 SetLastError(ERROR_OUTOFMEMORY);
437 SetLastError(ERROR_OUTOFMEMORY);
447 CryptMemFree(content);
453 PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
455 TRACE("(%p)\n", pCtlContext);
457 Context_AddRef((void *)pCtlContext, sizeof(CTL_CONTEXT));
461 static void CTLDataContext_Free(void *context)
463 PCTL_CONTEXT ctlContext = context;
465 CryptMsgClose(ctlContext->hCryptMsg);
466 CryptMemFree(ctlContext->pbCtlEncoded);
467 CryptMemFree(ctlContext->pbCtlContext);
468 LocalFree(ctlContext->pCtlInfo);
471 BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
475 TRACE("(%p)\n", pCTLContext);
478 ret = Context_Release((void *)pCTLContext, sizeof(CTL_CONTEXT),
479 CTLDataContext_Free);
483 DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
486 PCONTEXT_PROPERTY_LIST properties = Context_GetProperties(
487 pCTLContext, sizeof(CTL_CONTEXT));
490 TRACE("(%p, %d)\n", pCTLContext, dwPropId);
493 ret = ContextPropertyList_EnumPropIDs(properties, dwPropId);
499 static BOOL CTLContext_SetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
500 DWORD dwFlags, const void *pvData);
502 static BOOL CTLContext_GetHashProp(PCCTL_CONTEXT context, DWORD dwPropId,
503 ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
506 BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
510 CRYPT_DATA_BLOB blob = { *pcbData, pvData };
512 ret = CTLContext_SetProperty(context, dwPropId, 0, &blob);
517 static BOOL CTLContext_GetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
518 void *pvData, DWORD *pcbData)
520 PCONTEXT_PROPERTY_LIST properties =
521 Context_GetProperties(context, sizeof(CTL_CONTEXT));
523 CRYPT_DATA_BLOB blob;
525 TRACE("(%p, %d, %p, %p)\n", context, dwPropId, pvData, pcbData);
528 ret = ContextPropertyList_FindProperty(properties, dwPropId, &blob);
534 *pcbData = blob.cbData;
535 else if (*pcbData < blob.cbData)
537 SetLastError(ERROR_MORE_DATA);
538 *pcbData = blob.cbData;
543 memcpy(pvData, blob.pbData, blob.cbData);
544 *pcbData = blob.cbData;
549 /* Implicit properties */
552 case CERT_SHA1_HASH_PROP_ID:
553 ret = CTLContext_GetHashProp(context, dwPropId, CALG_SHA1,
554 context->pbCtlEncoded, context->cbCtlEncoded, pvData, pcbData);
556 case CERT_MD5_HASH_PROP_ID:
557 ret = CTLContext_GetHashProp(context, dwPropId, CALG_MD5,
558 context->pbCtlEncoded, context->cbCtlEncoded, pvData, pcbData);
561 SetLastError(CRYPT_E_NOT_FOUND);
564 TRACE("returning %d\n", ret);
568 BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
569 DWORD dwPropId, void *pvData, DWORD *pcbData)
573 TRACE("(%p, %d, %p, %p)\n", pCTLContext, dwPropId, pvData, pcbData);
578 case CERT_CERT_PROP_ID:
579 case CERT_CRL_PROP_ID:
580 case CERT_CTL_PROP_ID:
581 SetLastError(E_INVALIDARG);
584 case CERT_ACCESS_STATE_PROP_ID:
587 *pcbData = sizeof(DWORD);
590 else if (*pcbData < sizeof(DWORD))
592 SetLastError(ERROR_MORE_DATA);
593 *pcbData = sizeof(DWORD);
598 if (pCTLContext->hCertStore)
599 ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId,
602 *(DWORD *)pvData = 0;
607 ret = CTLContext_GetProperty(pCTLContext, dwPropId, pvData,
613 static BOOL CTLContext_SetProperty(PCCTL_CONTEXT context, DWORD dwPropId,
614 DWORD dwFlags, const void *pvData)
616 PCONTEXT_PROPERTY_LIST properties =
617 Context_GetProperties(context, sizeof(CTL_CONTEXT));
620 TRACE("(%p, %d, %08x, %p)\n", context, dwPropId, dwFlags, pvData);
626 ContextPropertyList_RemoveProperty(properties, dwPropId);
633 case CERT_AUTO_ENROLL_PROP_ID:
634 case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
635 case CERT_DESCRIPTION_PROP_ID:
636 case CERT_FRIENDLY_NAME_PROP_ID:
637 case CERT_HASH_PROP_ID:
638 case CERT_KEY_IDENTIFIER_PROP_ID:
639 case CERT_MD5_HASH_PROP_ID:
640 case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
641 case CERT_PUBKEY_ALG_PARA_PROP_ID:
642 case CERT_PVK_FILE_PROP_ID:
643 case CERT_SIGNATURE_HASH_PROP_ID:
644 case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
645 case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
646 case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
647 case CERT_ENROLLMENT_PROP_ID:
648 case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
649 case CERT_RENEWAL_PROP_ID:
651 PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
653 ret = ContextPropertyList_SetProperty(properties, dwPropId,
654 blob->pbData, blob->cbData);
657 case CERT_DATE_STAMP_PROP_ID:
658 ret = ContextPropertyList_SetProperty(properties, dwPropId,
659 pvData, sizeof(FILETIME));
662 FIXME("%d: stub\n", dwPropId);
666 TRACE("returning %d\n", ret);
670 BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
671 DWORD dwPropId, DWORD dwFlags, const void *pvData)
675 TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData);
677 /* Handle special cases for "read-only"/invalid prop IDs. Windows just
678 * crashes on most of these, I'll be safer.
683 case CERT_ACCESS_STATE_PROP_ID:
684 case CERT_CERT_PROP_ID:
685 case CERT_CRL_PROP_ID:
686 case CERT_CTL_PROP_ID:
687 SetLastError(E_INVALIDARG);
690 ret = CTLContext_SetProperty(pCTLContext, dwPropId, dwFlags, pvData);
691 TRACE("returning %d\n", ret);