+++ /dev/null
-/*
- * Copyright 2008 Juan Lang
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- */
-
-#include "crypt32_private.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(crypt);
-
-static void CTL_free(context_t *context)
-{
- ctl_t *ctl = (ctl_t*)context;
-
- CryptMsgClose(ctl->ctx.hCryptMsg);
- CryptMemFree(ctl->ctx.pbCtlEncoded);
- CryptMemFree(ctl->ctx.pbCtlContext);
- LocalFree(ctl->ctx.pCtlInfo);
-}
-
-static context_t *CTL_clone(context_t *context, WINECRYPT_CERTSTORE *store, BOOL use_link)
-{
- ctl_t *ctl;
-
- if(!use_link) {
- FIXME("Only links supported\n");
- return NULL;
- }
-
- ctl = (ctl_t*)Context_CreateLinkContext(sizeof(CTL_CONTEXT), context, store);
- if(!ctl)
- return NULL;
-
- ctl->ctx.hCertStore = store;
- return &ctl->base;
-}
-
-static const context_vtbl_t ctl_vtbl = {
- CTL_free,
- CTL_clone
-};
-
-BOOL WINAPI CertAddCTLContextToStore(HCERTSTORE hCertStore,
- PCCTL_CONTEXT pCtlContext, DWORD dwAddDisposition,
- PCCTL_CONTEXT* ppStoreContext)
-{
- WINECRYPT_CERTSTORE *store = hCertStore;
- BOOL ret = TRUE;
- PCCTL_CONTEXT toAdd = NULL, existing = NULL;
-
- TRACE("(%p, %p, %08x, %p)\n", hCertStore, pCtlContext, dwAddDisposition,
- ppStoreContext);
-
- if (dwAddDisposition != CERT_STORE_ADD_ALWAYS)
- {
- existing = CertFindCTLInStore(hCertStore, 0, 0, CTL_FIND_EXISTING,
- pCtlContext, NULL);
- }
-
- switch (dwAddDisposition)
- {
- case CERT_STORE_ADD_ALWAYS:
- toAdd = CertDuplicateCTLContext(pCtlContext);
- break;
- case CERT_STORE_ADD_NEW:
- if (existing)
- {
- TRACE("found matching CTL, not adding\n");
- SetLastError(CRYPT_E_EXISTS);
- ret = FALSE;
- }
- else
- toAdd = CertDuplicateCTLContext(pCtlContext);
- break;
- case CERT_STORE_ADD_NEWER:
- if (existing)
- {
- LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
- &pCtlContext->pCtlInfo->ThisUpdate);
-
- if (newer < 0)
- toAdd = CertDuplicateCTLContext(pCtlContext);
- else
- {
- TRACE("existing CTL is newer, not adding\n");
- SetLastError(CRYPT_E_EXISTS);
- ret = FALSE;
- }
- }
- else
- toAdd = CertDuplicateCTLContext(pCtlContext);
- break;
- case CERT_STORE_ADD_NEWER_INHERIT_PROPERTIES:
- if (existing)
- {
- LONG newer = CompareFileTime(&existing->pCtlInfo->ThisUpdate,
- &pCtlContext->pCtlInfo->ThisUpdate);
-
- if (newer < 0)
- {
- toAdd = CertDuplicateCTLContext(pCtlContext);
- Context_CopyProperties(existing, pCtlContext);
- }
- else
- {
- TRACE("existing CTL is newer, not adding\n");
- SetLastError(CRYPT_E_EXISTS);
- ret = FALSE;
- }
- }
- else
- toAdd = CertDuplicateCTLContext(pCtlContext);
- break;
- case CERT_STORE_ADD_REPLACE_EXISTING:
- toAdd = CertDuplicateCTLContext(pCtlContext);
- break;
- case CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES:
- toAdd = CertDuplicateCTLContext(pCtlContext);
- if (existing)
- Context_CopyProperties(toAdd, existing);
- break;
- case CERT_STORE_ADD_USE_EXISTING:
- if (existing)
- {
- Context_CopyProperties(existing, pCtlContext);
- if (ppStoreContext)
- *ppStoreContext = CertDuplicateCTLContext(existing);
- }
- else
- toAdd = CertDuplicateCTLContext(pCtlContext);
- break;
- default:
- FIXME("Unimplemented add disposition %d\n", dwAddDisposition);
- ret = FALSE;
- }
-
- if (toAdd)
- {
- if (store) {
- context_t *ret_ctx;
-
- ret = store->vtbl->ctls.addContext(store, context_from_ptr(toAdd),
- existing ? context_from_ptr(existing) : NULL, ppStoreContext ? &ret_ctx : NULL, TRUE);
- if(ret && ppStoreContext)
- *ppStoreContext = context_ptr(ret_ctx);
- }else if (ppStoreContext) {
- *ppStoreContext = CertDuplicateCTLContext(toAdd);
- }
- CertFreeCTLContext(toAdd);
- }
- CertFreeCTLContext(existing);
-
- TRACE("returning %d\n", ret);
- return ret;
-}
-
-BOOL WINAPI CertAddEncodedCTLToStore(HCERTSTORE hCertStore,
- DWORD dwMsgAndCertEncodingType, const BYTE *pbCtlEncoded, DWORD cbCtlEncoded,
- DWORD dwAddDisposition, PCCTL_CONTEXT *ppCtlContext)
-{
- PCCTL_CONTEXT ctl = CertCreateCTLContext(dwMsgAndCertEncodingType,
- pbCtlEncoded, cbCtlEncoded);
- BOOL ret;
-
- TRACE("(%p, %08x, %p, %d, %08x, %p)\n", hCertStore,
- dwMsgAndCertEncodingType, pbCtlEncoded, cbCtlEncoded, dwAddDisposition,
- ppCtlContext);
-
- if (ctl)
- {
- ret = CertAddCTLContextToStore(hCertStore, ctl, dwAddDisposition,
- ppCtlContext);
- CertFreeCTLContext(ctl);
- }
- else
- ret = FALSE;
- return ret;
-}
-
-PCCTL_CONTEXT WINAPI CertEnumCTLsInStore(HCERTSTORE hCertStore, PCCTL_CONTEXT pPrev)
-{
- ctl_t *prev = pPrev ? ctl_from_ptr(pPrev) : NULL, *ret;
- WINECRYPT_CERTSTORE *hcs = hCertStore;
-
- TRACE("(%p, %p)\n", hCertStore, pPrev);
- if (!hCertStore)
- ret = NULL;
- else if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
- ret = NULL;
- else
- ret = (ctl_t*)hcs->vtbl->ctls.enumContext(hcs, prev ? &prev->base : NULL);
- return ret ? &ret->ctx : NULL;
-}
-
-typedef BOOL (*CtlCompareFunc)(PCCTL_CONTEXT pCtlContext, DWORD dwType,
- DWORD dwFlags, const void *pvPara);
-
-static BOOL compare_ctl_any(PCCTL_CONTEXT pCtlContext, DWORD dwType,
- DWORD dwFlags, const void *pvPara)
-{
- return TRUE;
-}
-
-static BOOL compare_ctl_by_md5_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
- DWORD dwFlags, const void *pvPara)
-{
- BOOL ret;
- BYTE hash[16];
- DWORD size = sizeof(hash);
-
- ret = CertGetCTLContextProperty(pCtlContext, CERT_MD5_HASH_PROP_ID, hash,
- &size);
- if (ret)
- {
- const CRYPT_HASH_BLOB *pHash = pvPara;
-
- if (size == pHash->cbData)
- ret = !memcmp(pHash->pbData, hash, size);
- else
- ret = FALSE;
- }
- return ret;
-}
-
-static BOOL compare_ctl_by_sha1_hash(PCCTL_CONTEXT pCtlContext, DWORD dwType,
- DWORD dwFlags, const void *pvPara)
-{
- BOOL ret;
- BYTE hash[20];
- DWORD size = sizeof(hash);
-
- ret = CertGetCTLContextProperty(pCtlContext, CERT_SHA1_HASH_PROP_ID, hash,
- &size);
- if (ret)
- {
- const CRYPT_HASH_BLOB *pHash = pvPara;
-
- if (size == pHash->cbData)
- ret = !memcmp(pHash->pbData, hash, size);
- else
- ret = FALSE;
- }
- return ret;
-}
-
-static BOOL compare_ctl_existing(PCCTL_CONTEXT pCtlContext, DWORD dwType,
- DWORD dwFlags, const void *pvPara)
-{
- BOOL ret;
-
- if (pvPara)
- {
- PCCTL_CONTEXT ctl = pvPara;
-
- if (pCtlContext->cbCtlContext == ctl->cbCtlContext)
- {
- if (ctl->cbCtlContext)
- ret = !memcmp(pCtlContext->pbCtlContext, ctl->pbCtlContext,
- ctl->cbCtlContext);
- else
- ret = TRUE;
- }
- else
- ret = FALSE;
- }
- else
- ret = FALSE;
- return ret;
-}
-
-PCCTL_CONTEXT WINAPI CertFindCTLInStore(HCERTSTORE hCertStore,
- DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType,
- const void *pvFindPara, PCCTL_CONTEXT pPrevCtlContext)
-{
- PCCTL_CONTEXT ret;
- CtlCompareFunc compare;
-
- TRACE("(%p, %d, %d, %d, %p, %p)\n", hCertStore, dwCertEncodingType,
- dwFindFlags, dwFindType, pvFindPara, pPrevCtlContext);
-
- switch (dwFindType)
- {
- case CTL_FIND_ANY:
- compare = compare_ctl_any;
- break;
- case CTL_FIND_SHA1_HASH:
- compare = compare_ctl_by_sha1_hash;
- break;
- case CTL_FIND_MD5_HASH:
- compare = compare_ctl_by_md5_hash;
- break;
- case CTL_FIND_EXISTING:
- compare = compare_ctl_existing;
- break;
- default:
- FIXME("find type %08x unimplemented\n", dwFindType);
- compare = NULL;
- }
-
- if (compare)
- {
- BOOL matches = FALSE;
-
- ret = pPrevCtlContext;
- do {
- ret = CertEnumCTLsInStore(hCertStore, ret);
- if (ret)
- matches = compare(ret, dwFindType, dwFindFlags, pvFindPara);
- } while (ret != NULL && !matches);
- if (!ret)
- SetLastError(CRYPT_E_NOT_FOUND);
- }
- else
- {
- SetLastError(CRYPT_E_NOT_FOUND);
- ret = NULL;
- }
- return ret;
-}
-
-BOOL WINAPI CertDeleteCTLFromStore(PCCTL_CONTEXT pCtlContext)
-{
- WINECRYPT_CERTSTORE *hcs;
- ctl_t *ctl = ctl_from_ptr(pCtlContext);
- BOOL ret;
-
- TRACE("(%p)\n", pCtlContext);
-
- if (!pCtlContext)
- return TRUE;
-
- hcs = pCtlContext->hCertStore;
-
- if (hcs->dwMagic != WINE_CRYPTCERTSTORE_MAGIC)
- return FALSE;
-
- ret = hcs->vtbl->ctls.delete(hcs, &ctl->base);
- if (ret)
- ret = CertFreeCTLContext(pCtlContext);
- return ret;
-}
-
-PCCTL_CONTEXT WINAPI CertCreateCTLContext(DWORD dwMsgAndCertEncodingType,
- const BYTE *pbCtlEncoded, DWORD cbCtlEncoded)
-{
- ctl_t *ctl = NULL;
- HCRYPTMSG msg;
- BOOL ret;
- BYTE *content = NULL;
- DWORD contentSize = 0, size;
- PCTL_INFO ctlInfo = NULL;
-
- TRACE("(%08x, %p, %d)\n", dwMsgAndCertEncodingType, pbCtlEncoded,
- cbCtlEncoded);
-
- if (GET_CERT_ENCODING_TYPE(dwMsgAndCertEncodingType) != X509_ASN_ENCODING)
- {
- SetLastError(E_INVALIDARG);
- return NULL;
- }
- if (!pbCtlEncoded || !cbCtlEncoded)
- {
- SetLastError(ERROR_INVALID_DATA);
- return NULL;
- }
- msg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0, 0,
- 0, NULL, NULL);
- if (!msg)
- return NULL;
- ret = CryptMsgUpdate(msg, pbCtlEncoded, cbCtlEncoded, TRUE);
- if (!ret)
- {
- SetLastError(ERROR_INVALID_DATA);
- goto end;
- }
- /* Check that it's really a CTL */
- ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0, NULL, &size);
- if (ret)
- {
- char *innerContent = CryptMemAlloc(size);
-
- if (innerContent)
- {
- ret = CryptMsgGetParam(msg, CMSG_INNER_CONTENT_TYPE_PARAM, 0,
- innerContent, &size);
- if (ret)
- {
- if (strcmp(innerContent, szOID_CTL))
- {
- SetLastError(ERROR_INVALID_DATA);
- ret = FALSE;
- }
- }
- CryptMemFree(innerContent);
- }
- else
- {
- SetLastError(ERROR_OUTOFMEMORY);
- ret = FALSE;
- }
- }
- if (!ret)
- goto end;
- ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, NULL, &contentSize);
- if (!ret)
- goto end;
- content = CryptMemAlloc(contentSize);
- if (content)
- {
- ret = CryptMsgGetParam(msg, CMSG_CONTENT_PARAM, 0, content,
- &contentSize);
- if (ret)
- {
- ret = CryptDecodeObjectEx(dwMsgAndCertEncodingType, PKCS_CTL,
- content, contentSize, CRYPT_DECODE_ALLOC_FLAG, NULL,
- &ctlInfo, &size);
- if (ret)
- {
- ctl = (ctl_t*)Context_CreateDataContext(sizeof(CTL_CONTEXT), &ctl_vtbl, &empty_store);
- if (ctl)
- {
- BYTE *data = CryptMemAlloc(cbCtlEncoded);
-
- if (data)
- {
- memcpy(data, pbCtlEncoded, cbCtlEncoded);
- ctl->ctx.dwMsgAndCertEncodingType =
- X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
- ctl->ctx.pbCtlEncoded = data;
- ctl->ctx.cbCtlEncoded = cbCtlEncoded;
- ctl->ctx.pCtlInfo = ctlInfo;
- ctl->ctx.hCertStore = &empty_store;
- ctl->ctx.hCryptMsg = msg;
- ctl->ctx.pbCtlContext = content;
- ctl->ctx.cbCtlContext = contentSize;
- }
- else
- {
- SetLastError(ERROR_OUTOFMEMORY);
- ret = FALSE;
- }
- }
- else
- {
- SetLastError(ERROR_OUTOFMEMORY);
- ret = FALSE;
- }
- }
- }
- }
- else
- {
- SetLastError(ERROR_OUTOFMEMORY);
- ret = FALSE;
- }
-
-end:
- if (!ret)
- {
- if(ctl)
- Context_Release(&ctl->base);
- ctl = NULL;
- LocalFree(ctlInfo);
- CryptMemFree(content);
- CryptMsgClose(msg);
- return NULL;
- }
- return &ctl->ctx;
-}
-
-PCCTL_CONTEXT WINAPI CertDuplicateCTLContext(PCCTL_CONTEXT pCtlContext)
-{
- TRACE("(%p)\n", pCtlContext);
- if (pCtlContext)
- Context_AddRef(&ctl_from_ptr(pCtlContext)->base);
- return pCtlContext;
-}
-
-BOOL WINAPI CertFreeCTLContext(PCCTL_CONTEXT pCTLContext)
-{
- TRACE("(%p)\n", pCTLContext);
-
- if (pCTLContext)
- Context_Release(&ctl_from_ptr(pCTLContext)->base);
- return TRUE;
-}
-
-DWORD WINAPI CertEnumCTLContextProperties(PCCTL_CONTEXT pCTLContext,
- DWORD dwPropId)
-{
- ctl_t *ctl = ctl_from_ptr(pCTLContext);
- DWORD ret;
-
- TRACE("(%p, %d)\n", pCTLContext, dwPropId);
-
- if (ctl->base.properties)
- ret = ContextPropertyList_EnumPropIDs(ctl->base.properties, dwPropId);
- else
- ret = 0;
- return ret;
-}
-
-static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId,
- DWORD dwFlags, const void *pvData);
-
-static BOOL CTLContext_GetHashProp(ctl_t *ctl, DWORD dwPropId,
- ALG_ID algID, const BYTE *toHash, DWORD toHashLen, void *pvData,
- DWORD *pcbData)
-{
- BOOL ret = CryptHashCertificate(0, algID, 0, toHash, toHashLen, pvData,
- pcbData);
- if (ret && pvData)
- {
- CRYPT_DATA_BLOB blob = { *pcbData, pvData };
-
- ret = CTLContext_SetProperty(ctl, dwPropId, 0, &blob);
- }
- return ret;
-}
-
-static BOOL CTLContext_GetProperty(ctl_t *ctl, DWORD dwPropId,
- void *pvData, DWORD *pcbData)
-{
- BOOL ret;
- CRYPT_DATA_BLOB blob;
-
- TRACE("(%p, %d, %p, %p)\n", ctl, dwPropId, pvData, pcbData);
-
- if (ctl->base.properties)
- ret = ContextPropertyList_FindProperty(ctl->base.properties, dwPropId, &blob);
- else
- ret = FALSE;
- if (ret)
- {
- if (!pvData)
- *pcbData = blob.cbData;
- else if (*pcbData < blob.cbData)
- {
- SetLastError(ERROR_MORE_DATA);
- *pcbData = blob.cbData;
- ret = FALSE;
- }
- else
- {
- memcpy(pvData, blob.pbData, blob.cbData);
- *pcbData = blob.cbData;
- }
- }
- else
- {
- /* Implicit properties */
- switch (dwPropId)
- {
- case CERT_SHA1_HASH_PROP_ID:
- ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_SHA1,
- ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData);
- break;
- case CERT_MD5_HASH_PROP_ID:
- ret = CTLContext_GetHashProp(ctl, dwPropId, CALG_MD5,
- ctl->ctx.pbCtlEncoded, ctl->ctx.cbCtlEncoded, pvData, pcbData);
- break;
- default:
- SetLastError(CRYPT_E_NOT_FOUND);
- }
- }
- TRACE("returning %d\n", ret);
- return ret;
-}
-
-BOOL WINAPI CertGetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
- DWORD dwPropId, void *pvData, DWORD *pcbData)
-{
- BOOL ret;
-
- TRACE("(%p, %d, %p, %p)\n", pCTLContext, dwPropId, pvData, pcbData);
-
- switch (dwPropId)
- {
- case 0:
- case CERT_CERT_PROP_ID:
- case CERT_CRL_PROP_ID:
- case CERT_CTL_PROP_ID:
- SetLastError(E_INVALIDARG);
- ret = FALSE;
- break;
- case CERT_ACCESS_STATE_PROP_ID:
- if (!pvData)
- {
- *pcbData = sizeof(DWORD);
- ret = TRUE;
- }
- else if (*pcbData < sizeof(DWORD))
- {
- SetLastError(ERROR_MORE_DATA);
- *pcbData = sizeof(DWORD);
- ret = FALSE;
- }
- else
- {
- ret = CertGetStoreProperty(pCTLContext->hCertStore, dwPropId, pvData, pcbData);
- }
- break;
- default:
- ret = CTLContext_GetProperty(ctl_from_ptr(pCTLContext), dwPropId, pvData,
- pcbData);
- }
- return ret;
-}
-
-static BOOL CTLContext_SetProperty(ctl_t *ctl, DWORD dwPropId,
- DWORD dwFlags, const void *pvData)
-{
- BOOL ret;
-
- TRACE("(%p, %d, %08x, %p)\n", ctl, dwPropId, dwFlags, pvData);
-
- if (!ctl->base.properties)
- ret = FALSE;
- else if (!pvData)
- {
- ContextPropertyList_RemoveProperty(ctl->base.properties, dwPropId);
- ret = TRUE;
- }
- else
- {
- switch (dwPropId)
- {
- case CERT_AUTO_ENROLL_PROP_ID:
- case CERT_CTL_USAGE_PROP_ID: /* same as CERT_ENHKEY_USAGE_PROP_ID */
- case CERT_DESCRIPTION_PROP_ID:
- case CERT_FRIENDLY_NAME_PROP_ID:
- case CERT_HASH_PROP_ID:
- case CERT_KEY_IDENTIFIER_PROP_ID:
- case CERT_MD5_HASH_PROP_ID:
- case CERT_NEXT_UPDATE_LOCATION_PROP_ID:
- case CERT_PUBKEY_ALG_PARA_PROP_ID:
- case CERT_PVK_FILE_PROP_ID:
- case CERT_SIGNATURE_HASH_PROP_ID:
- case CERT_ISSUER_PUBLIC_KEY_MD5_HASH_PROP_ID:
- case CERT_SUBJECT_NAME_MD5_HASH_PROP_ID:
- case CERT_SUBJECT_PUBLIC_KEY_MD5_HASH_PROP_ID:
- case CERT_ENROLLMENT_PROP_ID:
- case CERT_CROSS_CERT_DIST_POINTS_PROP_ID:
- case CERT_RENEWAL_PROP_ID:
- {
- PCRYPT_DATA_BLOB blob = (PCRYPT_DATA_BLOB)pvData;
-
- ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
- blob->pbData, blob->cbData);
- break;
- }
- case CERT_DATE_STAMP_PROP_ID:
- ret = ContextPropertyList_SetProperty(ctl->base.properties, dwPropId,
- pvData, sizeof(FILETIME));
- break;
- default:
- FIXME("%d: stub\n", dwPropId);
- ret = FALSE;
- }
- }
- TRACE("returning %d\n", ret);
- return ret;
-}
-
-BOOL WINAPI CertSetCTLContextProperty(PCCTL_CONTEXT pCTLContext,
- DWORD dwPropId, DWORD dwFlags, const void *pvData)
-{
- BOOL ret;
-
- TRACE("(%p, %d, %08x, %p)\n", pCTLContext, dwPropId, dwFlags, pvData);
-
- /* Handle special cases for "read-only"/invalid prop IDs. Windows just
- * crashes on most of these, I'll be safer.
- */
- switch (dwPropId)
- {
- case 0:
- case CERT_ACCESS_STATE_PROP_ID:
- case CERT_CERT_PROP_ID:
- case CERT_CRL_PROP_ID:
- case CERT_CTL_PROP_ID:
- SetLastError(E_INVALIDARG);
- return FALSE;
- }
- ret = CTLContext_SetProperty(ctl_from_ptr(pCTLContext), dwPropId, dwFlags, pvData);
- TRACE("returning %d\n", ret);
- return ret;
-}