diff --git a/reactos/baseaddress.rbuild b/reactos/baseaddress.rbuild index 2cb66182e18..81666098901 100644 --- a/reactos/baseaddress.rbuild +++ b/reactos/baseaddress.rbuild @@ -3,6 +3,7 @@ + diff --git a/reactos/boot/bootdata/packages/reactos.dff b/reactos/boot/bootdata/packages/reactos.dff index a247e9814b4..1498c0c829a 100644 --- a/reactos/boot/bootdata/packages/reactos.dff +++ b/reactos/boot/bootdata/packages/reactos.dff @@ -248,6 +248,7 @@ dll\win32\compstui\compstui.dll 1 dll\win32\credui\credui.dll 1 dll\win32\crtdll\crtdll.dll 1 dll\win32\crypt32\crypt32.dll 1 +dll\win32\cryptdlg\cryptdlg.dll 1 dll\win32\cryptdll\cryptdll.dll 1 dll\win32\cryptnet\cryptnet.dll 1 dll\win32\cryptui\cryptui.dll 1 diff --git a/reactos/dll/win32/cryptdlg/cryptdlg.rbuild b/reactos/dll/win32/cryptdlg/cryptdlg.rbuild new file mode 100644 index 00000000000..cc86691a7fd --- /dev/null +++ b/reactos/dll/win32/cryptdlg/cryptdlg.rbuild @@ -0,0 +1,19 @@ + + + + + + . + include/reactos/wine + + wine + advapi32 + kernel32 + user32 + crypt32 + cryptui + wintrust + ntdll + main.c + cryptdlg.rc + diff --git a/reactos/dll/win32/cryptdlg/cryptdlg.rc b/reactos/dll/win32/cryptdlg/cryptdlg.rc new file mode 100644 index 00000000000..b56dd71685f --- /dev/null +++ b/reactos/dll/win32/cryptdlg/cryptdlg.rc @@ -0,0 +1,27 @@ +/* + * cryptdlg dll resources + * + * 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 "windef.h" +#include "winbase.h" +#include "winuser.h" +#include "cryptres.h" + +#include "cryptdlg_En.rc" +#include "cryptdlg_Fr.rc" +#include "cryptdlg_Ko.rc" diff --git a/reactos/dll/win32/cryptdlg/cryptdlg.spec b/reactos/dll/win32/cryptdlg/cryptdlg.spec new file mode 100644 index 00000000000..b417d0d8b80 --- /dev/null +++ b/reactos/dll/win32/cryptdlg/cryptdlg.spec @@ -0,0 +1,21 @@ +1 stub CertConfigureTrustA +2 stub CertConfigureTrustW +3 stdcall CertTrustCertPolicy(ptr long long long) +4 stdcall CertTrustCleanup(ptr) +5 stdcall CertTrustFinalPolicy(ptr) +6 stdcall CertTrustInit(ptr) +7 stub DecodeAttrSequence +8 stub DecodeRecipientID +9 stub EncodeAttrSequence +10 stub EncodeRecipientID +11 stub FormatPKIXEmailProtection +12 stdcall FormatVerisignExtension(long long long ptr str ptr long ptr ptr) +13 stub CertModifyCertificatesToTrust +14 stub CertSelectCertificateA +15 stub CertSelectCertificateW +16 stdcall CertViewPropertiesA(ptr) +17 stdcall CertViewPropertiesW(ptr) +18 stdcall -private DllRegisterServer() +19 stdcall -private DllUnregisterServer() +20 stdcall GetFriendlyNameOfCertA(ptr ptr long) +21 stdcall GetFriendlyNameOfCertW(ptr ptr long) diff --git a/reactos/dll/win32/cryptdlg/cryptdlg_En.rc b/reactos/dll/win32/cryptdlg/cryptdlg_En.rc new file mode 100644 index 00000000000..99126c42898 --- /dev/null +++ b/reactos/dll/win32/cryptdlg/cryptdlg_En.rc @@ -0,0 +1,36 @@ +/* + * cryptdlg dll resources + * + * 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 + */ + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_CERT_POLICY "Certificate Policy" + IDS_POLICY_ID "Policy Identifier: " + IDS_POLICY_QUALIFIER_INFO "Policy Qualifier Info" + IDS_POLICY_QUALIFIER_ID "Policy Qualifier Id=" + IDS_CPS "CPS" + IDS_USER_NOTICE "User Notice" + IDS_QUALIFIER "Qualifier" + IDS_NOTICE_REF "Notice Reference" + IDS_ORGANIZATION "Organization=" + IDS_NOTICE_NUM "Notice Number=" + IDS_NOTICE_TEXT "Notice Text=" +} diff --git a/reactos/dll/win32/cryptdlg/cryptdlg_Fr.rc b/reactos/dll/win32/cryptdlg/cryptdlg_Fr.rc new file mode 100644 index 00000000000..23de9ebd572 --- /dev/null +++ b/reactos/dll/win32/cryptdlg/cryptdlg_Fr.rc @@ -0,0 +1,36 @@ +/* + * cryptdlg dll French resources + * + * Copyright 2008 Jonathan Ernst + * + * 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 + */ + +LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL + +STRINGTABLE DISCARDABLE +{ + IDS_CERT_POLICY "Politique de certificat" + IDS_POLICY_ID "Identifiant de politique : " + IDS_POLICY_QUALIFIER_INFO "Policy Qualifier Info" + IDS_POLICY_QUALIFIER_ID "Policy Qualifier Id=" + IDS_CPS "CPS" + IDS_USER_NOTICE "User Notice" + IDS_QUALIFIER "Qualifier" + IDS_NOTICE_REF "Notice Reference" + IDS_ORGANIZATION "Organisation=" + IDS_NOTICE_NUM "Notice Number=" + IDS_NOTICE_TEXT "Notice Text=" +} diff --git a/reactos/dll/win32/cryptdlg/cryptdlg_Ko.rc b/reactos/dll/win32/cryptdlg/cryptdlg_Ko.rc new file mode 100644 index 00000000000..3778a57b71d --- /dev/null +++ b/reactos/dll/win32/cryptdlg/cryptdlg_Ko.rc @@ -0,0 +1,37 @@ +/* + * cryptdlg dll resources + * + * Copyright 2008 Juan Lang + * Copyright 2008 YunSong Hwang + * + * 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 + */ + +LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT + +STRINGTABLE DISCARDABLE +{ + IDS_CERT_POLICY "ÀÎÁõ Á¤Ã¥" + IDS_POLICY_ID "Á¤Ã¥ ½Äº°ÀÚ: " + IDS_POLICY_QUALIFIER_INFO "Á¤Ã¥ ±¸º°ÀÚ Á¤º¸" + IDS_POLICY_QUALIFIER_ID "Á¤Ã¥ ±¸º°ÀÚ ¾ÆÀ̵ð=" + IDS_CPS "CPS" + IDS_USER_NOTICE "»ç¿ëÀÚ ÅëÁö" + IDS_QUALIFIER "±¸º°ÀÚ" + IDS_NOTICE_REF "ÅëÁö ÂüÁ¶" + IDS_ORGANIZATION "±â°ü=" + IDS_NOTICE_NUM "ÅëÁö ¹øÈ£=" + IDS_NOTICE_TEXT "ÅëÁö ÅؽºÆ®=" +} diff --git a/reactos/dll/win32/cryptdlg/cryptres.h b/reactos/dll/win32/cryptdlg/cryptres.h new file mode 100644 index 00000000000..b64459aca78 --- /dev/null +++ b/reactos/dll/win32/cryptdlg/cryptres.h @@ -0,0 +1,33 @@ +/* + * 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 + */ +#ifndef __CRYPTRES_H__ +#define __CRYPTRES_H__ + +#define IDS_CERT_POLICY 100 +#define IDS_POLICY_ID 101 +#define IDS_POLICY_QUALIFIER_INFO 102 +#define IDS_POLICY_QUALIFIER_ID 103 +#define IDS_CPS 104 +#define IDS_USER_NOTICE 105 +#define IDS_QUALIFIER 106 +#define IDS_NOTICE_REF 107 +#define IDS_ORGANIZATION 108 +#define IDS_NOTICE_NUM 109 +#define IDS_NOTICE_TEXT 110 + +#endif /* ndef __CRYPTRES_H__ */ diff --git a/reactos/dll/win32/cryptdlg/main.c b/reactos/dll/win32/cryptdlg/main.c new file mode 100644 index 00000000000..1971578dbf5 --- /dev/null +++ b/reactos/dll/win32/cryptdlg/main.c @@ -0,0 +1,1211 @@ +/* + * Copyright 2008 Maarten Lankhorst + * + * 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 + */ + +#define NONAMELESSUNION + +#include "config.h" + +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winreg.h" +#include "wincrypt.h" +#include "wintrust.h" +#include "winuser.h" +#include "objbase.h" +#include "cryptdlg.h" +#include "cryptuiapi.h" +#include "cryptres.h" +#include "wine/unicode.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg); + +static HINSTANCE hInstance; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved); + + switch (fdwReason) + { + case DLL_WINE_PREATTACH: + return FALSE; /* prefer native version */ + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + hInstance = hinstDLL; + break; + case DLL_PROCESS_DETACH: + break; + default: + break; + } + return TRUE; +} + +/*********************************************************************** + * GetFriendlyNameOfCertA (CRYPTDLG.@) + */ +DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer, + DWORD cchBuffer) +{ + return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, + pchBuffer, cchBuffer); +} + +/*********************************************************************** + * GetFriendlyNameOfCertW (CRYPTDLG.@) + */ +DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer, + DWORD cchBuffer) +{ + return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, + pchBuffer, cchBuffer); +} + +/*********************************************************************** + * CertTrustInit (CRYPTDLG.@) + */ +HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData) +{ + HRESULT ret = S_FALSE; + + TRACE("(%p)\n", pProvData); + + if (pProvData->padwTrustStepErrors && + !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT]) + ret = S_OK; + TRACE("returning %08x\n", ret); + return ret; +} + +/*********************************************************************** + * CertTrustCertPolicy (CRYPTDLG.@) + */ +BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner) +{ + FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner); + return FALSE; +} + +/*********************************************************************** + * CertTrustCleanup (CRYPTDLG.@) + */ +HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData) +{ + FIXME("(%p)\n", pProvData); + return E_NOTIMPL; +} + +static BOOL CRYPTDLG_CheckOnlineCRL(void) +{ + static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e', + '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g', + 'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f', + '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9', + '7','9','3','8','7','e','a','}',0 }; + static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a', + 'g','s',0 }; + HKEY key; + BOOL ret = FALSE; + + if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key)) + { + DWORD type, flags, size = sizeof(flags); + + if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags, + &size) && type == REG_DWORD) + { + /* The flag values aren't defined in any header I'm aware of, but + * this value is well documented on the net. + */ + if (flags & 0x00010000) + ret = TRUE; + } + RegCloseKey(key); + } + return ret; +} + +/* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it + * is. + */ +static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert) +{ + BOOL ret; + BYTE hash[20]; + DWORD size = sizeof(hash); + + if ((ret = CertGetCertificateContextProperty(pCert, + CERT_SIGNATURE_HASH_PROP_ID, hash, &size))) + { + static const WCHAR disallowedW[] = + { 'D','i','s','a','l','l','o','w','e','d',0 }; + HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W, + X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW); + + if (disallowed) + { + PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed, + X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL); + + if (found) + { + ret = FALSE; + CertFreeCertificateContext(found); + } + CertCloseStore(disallowed, 0); + } + } + return ret; +} + +static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus) +{ + DWORD confidence = 0; + + confidence = 0; + if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID)) + confidence |= CERT_CONFIDENCE_SIG; + if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID)) + confidence |= CERT_CONFIDENCE_TIME; + if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED)) + confidence |= CERT_CONFIDENCE_TIMENEST; + return confidence; +} + +static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data, + PCCERT_CHAIN_CONTEXT chain) +{ + BOOL ret; + CRYPT_PROVIDER_SGNR signer; + PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0]; + DWORD i; + + memset(&signer, 0, sizeof(signer)); + signer.cbStruct = sizeof(signer); + ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer); + if (ret) + { + CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0, + FALSE, 0); + + if (sgnr) + { + sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus; + sgnr->pChainContext = CertDuplicateCertificateChain(chain); + } + else + ret = FALSE; + for (i = 0; ret && i < simpleChain->cElement; i++) + { + ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0, + simpleChain->rgpElement[i]->pCertContext); + if (ret) + { + CRYPT_PROVIDER_CERT *cert; + + if ((cert = WTHelperGetProvCertFromChain(sgnr, i))) + { + CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i]; + + cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence( + element->TrustStatus.dwErrorStatus); + cert->dwError = element->TrustStatus.dwErrorStatus; + cert->pChainElement = element; + } + else + ret = FALSE; + } + } + } + return ret; +} + +static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData( + CRYPT_PROVIDER_DATA *data) +{ + CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL; + + /* This should always be true, but just in case the calling function is + * called directly: + */ + if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB && + data->pWintrustData->u.pBlob && data->pWintrustData->u.pBlob->cbMemObject == + sizeof(CERT_VERIFY_CERTIFICATE_TRUST) && + data->pWintrustData->u.pBlob->pbMemObject) + pCert = (CERT_VERIFY_CERTIFICATE_TRUST *) + data->pWintrustData->u.pBlob->pbMemObject; + return pCert; +} + +static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert) +{ + HCERTCHAINENGINE engine = NULL; + HCERTSTORE root = NULL, trust = NULL; + DWORD i; + + if (cert->cRootStores) + { + root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (root) + { + for (i = 0; i < cert->cRootStores; i++) + CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0); + } + } + if (cert->cTrustStores) + { + trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, + CERT_STORE_CREATE_NEW_FLAG, NULL); + if (root) + { + for (i = 0; i < cert->cTrustStores; i++) + CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0); + } + } + if (cert->cRootStores || cert->cStores || cert->cTrustStores) + { + CERT_CHAIN_ENGINE_CONFIG config; + + memset(&config, 0, sizeof(config)); + config.cbSize = sizeof(config); + config.hRestrictedRoot = root; + config.hRestrictedTrust = trust; + config.cAdditionalStore = cert->cStores; + config.rghAdditionalStore = cert->rghstoreCAs; + config.hRestrictedRoot = root; + CertCreateCertificateChainEngine(&config, &engine); + CertCloseStore(root, 0); + CertCloseStore(trust, 0); + } + return engine; +} + +/*********************************************************************** + * CertTrustFinalPolicy (CRYPTDLG.@) + */ +HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data) +{ + BOOL ret; + DWORD err = S_OK; + CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data); + + TRACE("(%p)\n", data); + + if (data->pWintrustData->dwUIChoice != WTD_UI_NONE) + FIXME("unimplemented for UI choice %d\n", + data->pWintrustData->dwUIChoice); + if (pCert) + { + DWORD flags = 0; + CERT_CHAIN_PARA chainPara; + HCERTCHAINENGINE engine; + + memset(&chainPara, 0, sizeof(chainPara)); + chainPara.cbSize = sizeof(chainPara); + if (CRYPTDLG_CheckOnlineCRL()) + flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT; + engine = CRYPTDLG_MakeEngine(pCert); + GetSystemTimeAsFileTime(&data->sftSystemTime); + ret = CRYPTDLG_IsCertAllowed(pCert->pccert); + if (ret) + { + PCCERT_CHAIN_CONTEXT chain; + + ret = CertGetCertificateChain(engine, pCert->pccert, + &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain); + if (ret) + { + if (chain->cChain != 1) + { + FIXME("unimplemented for more than 1 simple chain\n"); + err = TRUST_E_SUBJECT_FORM_UNKNOWN; + ret = FALSE; + } + else if ((ret = CRYPTDLG_CopyChain(data, chain))) + { + if (CertVerifyTimeValidity(&data->sftSystemTime, + pCert->pccert->pCertInfo)) + { + ret = FALSE; + err = CERT_E_EXPIRED; + } + } + else + err = TRUST_E_SYSTEM_ERROR; + CertFreeCertificateChain(chain); + } + else + err = TRUST_E_SUBJECT_NOT_TRUSTED; + } + CertFreeCertificateChainEngine(engine); + } + else + { + ret = FALSE; + err = TRUST_E_NOSIGNATURE; + } + /* Oddly, native doesn't set the error in the trust step error location, + * probably because this action is more advisory than anything else. + * Instead it stores it as the final error, but the function "succeeds" in + * any case. + */ + if (!ret) + data->dwFinalError = err; + TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError); + return S_OK; +} + +/*********************************************************************** + * CertViewPropertiesA (CRYPTDLG.@) + */ +BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info) +{ + CERT_VIEWPROPERTIES_STRUCT_W infoW; + LPWSTR title = NULL; + BOOL ret; + + TRACE("(%p)\n", info); + + memcpy(&infoW, info, sizeof(infoW)); + if (info->szTitle) + { + int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0); + + title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if (title) + { + MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len); + infoW.szTitle = title; + } + else + { + ret = FALSE; + goto error; + } + } + ret = CertViewPropertiesW(&infoW); + HeapFree(GetProcessHeap(), 0, title); +error: + return ret; +} + +/*********************************************************************** + * CertViewPropertiesW (CRYPTDLG.@) + */ +BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info) +{ + static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY; + CERT_VERIFY_CERTIFICATE_TRUST trust; + WINTRUST_BLOB_INFO blob; + WINTRUST_DATA wtd; + LONG err; + BOOL ret; + + TRACE("(%p)\n", info); + + memset(&trust, 0, sizeof(trust)); + trust.cbSize = sizeof(trust); + trust.pccert = info->pCertContext; + trust.cRootStores = info->cRootStores; + trust.rghstoreRoots = info->rghstoreRoots; + trust.cStores = info->cStores; + trust.rghstoreCAs = info->rghstoreCAs; + trust.cTrustStores = info->cTrustStores; + trust.rghstoreTrust = info->rghstoreTrust; + memset(&blob, 0, sizeof(blob)); + blob.cbStruct = sizeof(blob); + blob.cbMemObject = sizeof(trust); + blob.pbMemObject = (BYTE *)&trust; + memset(&wtd, 0, sizeof(wtd)); + wtd.cbStruct = sizeof(wtd); + wtd.dwUIChoice = WTD_UI_NONE; + wtd.dwUnionChoice = WTD_CHOICE_BLOB; + wtd.u.pBlob = &blob; + wtd.dwStateAction = WTD_STATEACTION_VERIFY; + err = WinVerifyTrust(NULL, &cert_action_verify, &wtd); + if (err == ERROR_SUCCESS) + { + CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo; + BOOL propsChanged = FALSE; + + memset(&uiInfo, 0, sizeof(uiInfo)); + uiInfo.dwSize = sizeof(uiInfo); + uiInfo.hwndParent = info->hwndParent; + uiInfo.dwFlags = + CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES; + uiInfo.szTitle = info->szTitle; + uiInfo.pCertContext = info->pCertContext; + uiInfo.cPurposes = info->cArrayPurposes; + uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes; + uiInfo.u.hWVTStateData = wtd.hWVTStateData; + uiInfo.fpCryptProviderDataTrustedUsage = TRUE; + uiInfo.cPropSheetPages = info->cArrayPropSheetPages; + uiInfo.rgPropSheetPages = info->arrayPropSheetPages; + uiInfo.nStartPage = info->nStartPage; + ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged); + wtd.dwStateAction = WTD_STATEACTION_CLOSE; + WinVerifyTrust(NULL, &cert_action_verify, &wtd); + } + else + ret = FALSE; + return ret; +} + +static BOOL CRYPT_FormatHexString(const BYTE *pbEncoded, DWORD cbEncoded, + WCHAR *str, DWORD *pcchStr) +{ + BOOL ret; + DWORD charsNeeded; + + if (cbEncoded) + charsNeeded = (cbEncoded * 3); + else + charsNeeded = 1; + if (!str) + { + *pcchStr = charsNeeded; + ret = TRUE; + } + else if (*pcchStr < charsNeeded) + { + *pcchStr = charsNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + { + static const WCHAR fmt[] = { '%','0','2','x',' ',0 }; + static const WCHAR endFmt[] = { '%','0','2','x',0 }; + DWORD i; + LPWSTR ptr = str; + + *pcchStr = charsNeeded; + if (cbEncoded) + { + for (i = 0; i < cbEncoded; i++) + { + if (i < cbEncoded - 1) + ptr += sprintfW(ptr, fmt, pbEncoded[i]); + else + ptr += sprintfW(ptr, endFmt, pbEncoded[i]); + } + } + else + *ptr = 0; + ret = TRUE; + } + return ret; +} + +static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 }; +static const WCHAR colonCrlf[] = { ':','\r','\n',0 }; +static const WCHAR colonSpace[] = { ':',' ',0 }; +static const WCHAR crlf[] = { '\r','\n',0 }; +static const WCHAR commaSep[] = { ',',' ',0 }; + +static BOOL CRYPT_FormatCPS(DWORD dwCertEncodingType, + DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded, + WCHAR *str, DWORD *pcchStr) +{ + BOOL ret; + DWORD size, charsNeeded = 1; + CERT_NAME_VALUE *cpsValue; + + if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING, + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &cpsValue, &size))) + { + LPCWSTR headingSep, sep; + DWORD headingSepLen, sepLen; + + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + headingSep = colonCrlf; + sep = crlf; + } + else + { + headingSep = colonSpace; + sep = commaSep; + } + sepLen = strlenW(sep); + headingSepLen = strlenW(headingSep); + + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += 3 * strlenW(indent); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += cpsValue->Value.cbData / sizeof(WCHAR); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, (LPWSTR)cpsValue->Value.pbData); + str += cpsValue->Value.cbData / sizeof(WCHAR); + } + charsNeeded += sepLen; + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, sep); + str += sepLen; + } + LocalFree(cpsValue); + if (!str) + *pcchStr = charsNeeded; + else if (*pcchStr < charsNeeded) + { + *pcchStr = charsNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + *pcchStr = charsNeeded; + } + return ret; +} + +static BOOL CRYPT_FormatUserNotice(DWORD dwCertEncodingType, + DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded, + WCHAR *str, DWORD *pcchStr) +{ + BOOL ret; + DWORD size, charsNeeded = 1; + CERT_POLICY_QUALIFIER_USER_NOTICE *notice; + + if ((ret = CryptDecodeObjectEx(dwCertEncodingType, + X509_PKIX_POLICY_QUALIFIER_USERNOTICE, pbEncoded, cbEncoded, + CRYPT_DECODE_ALLOC_FLAG, NULL, ¬ice, &size))) + { + static const WCHAR numFmt[] = { '%','d',0 }; + CERT_POLICY_QUALIFIER_NOTICE_REFERENCE *pNoticeRef = + notice->pNoticeReference; + LPCWSTR headingSep, sep; + DWORD headingSepLen, sepLen; + LPWSTR noticeRef, organization, noticeNum, noticeText; + DWORD noticeRefLen, organizationLen, noticeNumLen, noticeTextLen; + WCHAR noticeNumStr[11]; + + noticeRefLen = LoadStringW(hInstance, IDS_NOTICE_REF, + (LPWSTR)¬iceRef, 0); + organizationLen = LoadStringW(hInstance, IDS_ORGANIZATION, + (LPWSTR)&organization, 0); + noticeNumLen = LoadStringW(hInstance, IDS_NOTICE_NUM, + (LPWSTR)¬iceNum, 0); + noticeTextLen = LoadStringW(hInstance, IDS_NOTICE_TEXT, + (LPWSTR)¬iceText, 0); + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + headingSep = colonCrlf; + sep = crlf; + } + else + { + headingSep = colonSpace; + sep = commaSep; + } + sepLen = strlenW(sep); + headingSepLen = strlenW(headingSep); + + if (pNoticeRef) + { + DWORD k; + LPCSTR src; + + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += 3 * strlenW(indent); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += noticeRefLen; + if (str && *pcchStr >= charsNeeded) + { + memcpy(str, noticeRef, noticeRefLen * sizeof(WCHAR)); + str += noticeRefLen; + } + charsNeeded += headingSepLen; + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, headingSep); + str += headingSepLen; + } + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += 4 * strlenW(indent); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += organizationLen; + if (str && *pcchStr >= charsNeeded) + { + memcpy(str, organization, organizationLen * sizeof(WCHAR)); + str += organizationLen; + } + charsNeeded += strlen(pNoticeRef->pszOrganization); + if (str && *pcchStr >= charsNeeded) + for (src = pNoticeRef->pszOrganization; src && *src; + src++, str++) + *str = *src; + charsNeeded += sepLen; + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, sep); + str += sepLen; + } + for (k = 0; k < pNoticeRef->cNoticeNumbers; k++) + { + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += 4 * strlenW(indent); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += noticeNumLen; + if (str && *pcchStr >= charsNeeded) + { + memcpy(str, noticeNum, noticeNumLen * sizeof(WCHAR)); + str += noticeNumLen; + } + sprintfW(noticeNumStr, numFmt, k + 1); + charsNeeded += strlenW(noticeNumStr); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, noticeNumStr); + str += strlenW(noticeNumStr); + } + charsNeeded += sepLen; + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, sep); + str += sepLen; + } + } + } + if (notice->pszDisplayText) + { + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += 3 * strlenW(indent); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += noticeTextLen; + if (str && *pcchStr >= charsNeeded) + { + memcpy(str, noticeText, noticeTextLen * sizeof(WCHAR)); + str += noticeTextLen; + } + charsNeeded += strlenW(notice->pszDisplayText); + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, notice->pszDisplayText); + str += strlenW(notice->pszDisplayText); + } + charsNeeded += sepLen; + if (str && *pcchStr >= charsNeeded) + { + strcpyW(str, sep); + str += sepLen; + } + } + LocalFree(notice); + if (!str) + *pcchStr = charsNeeded; + else if (*pcchStr < charsNeeded) + { + *pcchStr = charsNeeded; + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + *pcchStr = charsNeeded; + } + return ret; +} + +/*********************************************************************** + * FormatVerisignExtension (CRYPTDLG.@) + */ +BOOL WINAPI FormatVerisignExtension(DWORD dwCertEncodingType, + DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct, + LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat, + DWORD *pcbFormat) +{ + CERT_POLICIES_INFO *policies; + DWORD size; + BOOL ret = FALSE; + + if (!cbEncoded) + { + SetLastError(E_INVALIDARG); + return FALSE; + } + if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_POLICIES, + pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size))) + { + static const WCHAR numFmt[] = { '%','d',0 }; + DWORD charsNeeded = 1; /* space for NULL terminator */ + LPCWSTR headingSep, sep; + DWORD headingSepLen, sepLen; + WCHAR policyNum[11], policyQualifierNum[11]; + LPWSTR certPolicy, policyId, policyQualifierInfo, policyQualifierId; + LPWSTR cps, userNotice, qualifier; + DWORD certPolicyLen, policyIdLen, policyQualifierInfoLen; + DWORD policyQualifierIdLen, cpsLen, userNoticeLen, qualifierLen; + DWORD i; + LPWSTR str = pbFormat; + + certPolicyLen = LoadStringW(hInstance, IDS_CERT_POLICY, + (LPWSTR)&certPolicy, 0); + policyIdLen = LoadStringW(hInstance, IDS_POLICY_ID, (LPWSTR)&policyId, + 0); + policyQualifierInfoLen = LoadStringW(hInstance, + IDS_POLICY_QUALIFIER_INFO, (LPWSTR)&policyQualifierInfo, 0); + policyQualifierIdLen = LoadStringW(hInstance, IDS_POLICY_QUALIFIER_ID, + (LPWSTR)&policyQualifierId, 0); + cpsLen = LoadStringW(hInstance, IDS_CPS, (LPWSTR)&cps, 0); + userNoticeLen = LoadStringW(hInstance, IDS_USER_NOTICE, + (LPWSTR)&userNotice, 0); + qualifierLen = LoadStringW(hInstance, IDS_QUALIFIER, + (LPWSTR)&qualifier, 0); + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + headingSep = colonCrlf; + sep = crlf; + } + else + { + headingSep = colonSpace; + sep = commaSep; + } + sepLen = strlenW(sep); + headingSepLen = strlenW(headingSep); + + for (i = 0; ret && i < policies->cPolicyInfo; i++) + { + CERT_POLICY_INFO *policy = &policies->rgPolicyInfo[i]; + DWORD j; + LPCSTR src; + + charsNeeded += 1; /* '['*/ + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + *str++ = '['; + sprintfW(policyNum, numFmt, i + 1); + charsNeeded += strlenW(policyNum); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, policyNum); + str += strlenW(policyNum); + } + charsNeeded += 1; /* ']'*/ + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + *str++ = ']'; + charsNeeded += certPolicyLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + memcpy(str, certPolicy, certPolicyLen * sizeof(WCHAR)); + str += certPolicyLen; + } + charsNeeded += headingSepLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, headingSep); + str += headingSepLen; + } + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += strlenW(indent); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += policyIdLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + memcpy(str, policyId, policyIdLen * sizeof(WCHAR)); + str += policyIdLen; + } + charsNeeded += strlen(policy->pszPolicyIdentifier); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + for (src = policy->pszPolicyIdentifier; src && *src; + src++, str++) + *str = *src; + } + charsNeeded += sepLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, sep); + str += sepLen; + } + for (j = 0; j < policy->cPolicyQualifier; j++) + { + CERT_POLICY_QUALIFIER_INFO *qualifierInfo = + &policy->rgPolicyQualifier[j]; + DWORD sizeRemaining; + + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += strlenW(indent); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += 1; /* '['*/ + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + *str++ = '['; + charsNeeded += strlenW(policyNum); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, policyNum); + str += strlenW(policyNum); + } + charsNeeded += 1; /* ','*/ + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + *str++ = ','; + sprintfW(policyQualifierNum, numFmt, j + 1); + charsNeeded += strlenW(policyQualifierNum); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, policyQualifierNum); + str += strlenW(policyQualifierNum); + } + charsNeeded += 1; /* ']'*/ + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + *str++ = ']'; + charsNeeded += policyQualifierInfoLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + memcpy(str, policyQualifierInfo, + policyQualifierInfoLen * sizeof(WCHAR)); + str += policyQualifierInfoLen; + } + charsNeeded += headingSepLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, headingSep); + str += headingSepLen; + } + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += 2 * strlenW(indent); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += policyQualifierIdLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + memcpy(str, policyQualifierId, + policyQualifierIdLen * sizeof(WCHAR)); + str += policyQualifierIdLen; + } + if (!strcmp(qualifierInfo->pszPolicyQualifierId, + szOID_PKIX_POLICY_QUALIFIER_CPS)) + { + charsNeeded += cpsLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + memcpy(str, cps, cpsLen * sizeof(WCHAR)); + str += cpsLen; + } + } + else if (!strcmp(qualifierInfo->pszPolicyQualifierId, + szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)) + { + charsNeeded += userNoticeLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + memcpy(str, userNotice, userNoticeLen * sizeof(WCHAR)); + str += userNoticeLen; + } + } + else + { + charsNeeded += strlen(qualifierInfo->pszPolicyQualifierId); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + for (src = qualifierInfo->pszPolicyQualifierId; + src && *src; src++, str++) + *str = *src; + } + } + charsNeeded += sepLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, sep); + str += sepLen; + } + if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE) + { + charsNeeded += 2 * strlenW(indent); + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, indent); + str += strlenW(indent); + strcpyW(str, indent); + str += strlenW(indent); + } + } + charsNeeded += qualifierLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + memcpy(str, qualifier, qualifierLen * sizeof(WCHAR)); + str += qualifierLen; + } + charsNeeded += headingSepLen; + if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR)) + { + strcpyW(str, headingSep); + str += headingSepLen; + } + /* This if block is deliberately redundant with the same if + * block above, in order to keep the code more readable (the + * code flow follows the order in which the strings are output.) + */ + if (!strcmp(qualifierInfo->pszPolicyQualifierId, + szOID_PKIX_POLICY_QUALIFIER_CPS)) + { + if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR)) + { + /* Insufficient space, determine how much is needed. */ + ret = CRYPT_FormatCPS(dwCertEncodingType, + dwFormatStrType, qualifierInfo->Qualifier.pbData, + qualifierInfo->Qualifier.cbData, NULL, &size); + if (ret) + charsNeeded += size - 1; + } + else + { + sizeRemaining = *pcbFormat / sizeof(WCHAR); + sizeRemaining -= str - (LPWSTR)pbFormat; + ret = CRYPT_FormatCPS(dwCertEncodingType, + dwFormatStrType, qualifierInfo->Qualifier.pbData, + qualifierInfo->Qualifier.cbData, str, &sizeRemaining); + if (ret || GetLastError() == ERROR_MORE_DATA) + { + charsNeeded += sizeRemaining - 1; + str += sizeRemaining - 1; + } + } + } + else if (!strcmp(qualifierInfo->pszPolicyQualifierId, + szOID_PKIX_POLICY_QUALIFIER_USERNOTICE)) + { + if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR)) + { + /* Insufficient space, determine how much is needed. */ + ret = CRYPT_FormatUserNotice(dwCertEncodingType, + dwFormatStrType, qualifierInfo->Qualifier.pbData, + qualifierInfo->Qualifier.cbData, NULL, &size); + if (ret) + charsNeeded += size - 1; + } + else + { + sizeRemaining = *pcbFormat / sizeof(WCHAR); + sizeRemaining -= str - (LPWSTR)pbFormat; + ret = CRYPT_FormatUserNotice(dwCertEncodingType, + dwFormatStrType, qualifierInfo->Qualifier.pbData, + qualifierInfo->Qualifier.cbData, str, &sizeRemaining); + if (ret || GetLastError() == ERROR_MORE_DATA) + { + charsNeeded += sizeRemaining - 1; + str += sizeRemaining - 1; + } + } + } + else + { + if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR)) + { + /* Insufficient space, determine how much is needed. */ + ret = CRYPT_FormatHexString( + qualifierInfo->Qualifier.pbData, + qualifierInfo->Qualifier.cbData, NULL, &size); + if (ret) + charsNeeded += size - 1; + } + else + { + sizeRemaining = *pcbFormat / sizeof(WCHAR); + sizeRemaining -= str - (LPWSTR)pbFormat; + ret = CRYPT_FormatHexString( + qualifierInfo->Qualifier.pbData, + qualifierInfo->Qualifier.cbData, str, &sizeRemaining); + if (ret || GetLastError() == ERROR_MORE_DATA) + { + charsNeeded += sizeRemaining - 1; + str += sizeRemaining - 1; + } + } + } + } + } + LocalFree(policies); + if (ret) + { + if (!pbFormat) + *pcbFormat = charsNeeded * sizeof(WCHAR); + else if (*pcbFormat < charsNeeded * sizeof(WCHAR)) + { + *pcbFormat = charsNeeded * sizeof(WCHAR); + SetLastError(ERROR_MORE_DATA); + ret = FALSE; + } + else + *pcbFormat = charsNeeded * sizeof(WCHAR); + } + } + return ret; +} + +#define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4" + +/*********************************************************************** + * DllRegisterServer (CRYPTDLG.@) + */ +HRESULT WINAPI DllRegisterServer(void) +{ + static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.', + 'd','l','l',0 }; + static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.', + 'd','l','l',0 }; + static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t', + 'I','n','i','t',0 }; + static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t', + 'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 }; + static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t', + 'C','e','r','t','P','o','l','i','c','y',0 }; + static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t', + 'F','i','n','a','l','P','o','l','i','c','y',0 }; + static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t', + 'C','l','e','a','n','u','p',0 }; + static const WCHAR cryptDlg[] = { 'c','r','y','p','t','d','l','g','.', + 'd','l','l',0 }; + CRYPT_REGISTER_ACTIONID reg; + GUID guid = CERT_CERTIFICATE_ACTION_VERIFY; + HRESULT hr = S_OK; + + memset(®, 0, sizeof(reg)); + reg.cbStruct = sizeof(reg); + reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); + reg.sInitProvider.pwszDLLName = cryptdlg; + reg.sInitProvider.pwszFunctionName = certTrustInit; + reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); + reg.sCertificateProvider.pwszDLLName = wintrust; + reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust; + reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); + reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg; + reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy; + reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); + reg.sFinalPolicyProvider.pwszDLLName = cryptdlg; + reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy; + reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY); + reg.sCleanupProvider.pwszDLLName = cryptdlg; + reg.sCleanupProvider.pwszFunctionName = certTrustCleanup; + if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, ®)) + hr = GetLastError(); + CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, + "1.3.6.1.4.1.311.16.1.1", cryptDlg, "EncodeAttrSequence"); + CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, + szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "EncodeRecipientID"); + CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, + "1.3.6.1.4.1.311.16.1.1", cryptDlg, "DecodeAttrSequence"); + CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, + szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "DecodeRecipientID"); + CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, + szOID_PKIX_KP_EMAIL_PROTECTION, cryptDlg, "FormatPKIXEmailProtection"); + CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, + szOID_CERT_POLICIES, cryptDlg, "FormatVerisignExtension"); + return hr; +} + +/*********************************************************************** + * DllUnregisterServer (CRYPTDLG.@) + */ +HRESULT WINAPI DllUnregisterServer(void) +{ + GUID guid = CERT_CERTIFICATE_ACTION_VERIFY; + + WintrustRemoveActionID(&guid); + CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, + "1.3.6.1.4.1.311.16.1.1"); + CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC, + szOID_MICROSOFT_Encryption_Key_Preference); + CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, + "1.3.6.1.4.1.311.16.1.1"); + CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC, + szOID_MICROSOFT_Encryption_Key_Preference); + CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, + szOID_PKIX_KP_EMAIL_PROTECTION); + CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC, + szOID_CERT_POLICIES); + return S_OK; +} diff --git a/reactos/dll/win32/win32.rbuild b/reactos/dll/win32/win32.rbuild index 565898a37ff..18d5889f817 100644 --- a/reactos/dll/win32/win32.rbuild +++ b/reactos/dll/win32/win32.rbuild @@ -61,6 +61,9 @@ + + +