| /* | |
| * 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 <assert.h> | |
| #include <stdarg.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wincrypt.h" | |
| #include "wine/debug.h" | |
| #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; | |
| } |