ntdll: Move a few file functions to the Unix library.
[wine.git] / dlls / cryptdlg / main.c
blob4812ac9e621a5119ef411c177d1ff2478065d05a
1 /*
2 * Copyright 2008 Maarten Lankhorst
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
19 #define NONAMELESSUNION
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "winnls.h"
26 #include "winreg.h"
27 #include "wincrypt.h"
28 #include "wintrust.h"
29 #include "winuser.h"
30 #include "objbase.h"
31 #include "cryptdlg.h"
32 #include "cryptuiapi.h"
33 #include "cryptres.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(cryptdlg);
38 static HINSTANCE hInstance;
40 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
42 TRACE("(0x%p, %d, %p)\n", hinstDLL, fdwReason, lpvReserved);
44 switch (fdwReason)
46 case DLL_WINE_PREATTACH:
47 return FALSE; /* prefer native version */
48 case DLL_PROCESS_ATTACH:
49 DisableThreadLibraryCalls(hinstDLL);
50 hInstance = hinstDLL;
51 break;
53 return TRUE;
56 /***********************************************************************
57 * GetFriendlyNameOfCertA (CRYPTDLG.@)
59 DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer,
60 DWORD cchBuffer)
62 return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
63 pchBuffer, cchBuffer);
66 /***********************************************************************
67 * GetFriendlyNameOfCertW (CRYPTDLG.@)
69 DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer,
70 DWORD cchBuffer)
72 return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
73 pchBuffer, cchBuffer);
76 /***********************************************************************
77 * CertTrustInit (CRYPTDLG.@)
79 HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData)
81 HRESULT ret = S_FALSE;
83 TRACE("(%p)\n", pProvData);
85 if (pProvData->padwTrustStepErrors &&
86 !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
87 ret = S_OK;
88 TRACE("returning %08x\n", ret);
89 return ret;
92 /***********************************************************************
93 * CertTrustCertPolicy (CRYPTDLG.@)
95 BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner)
97 FIXME("(%p, %d, %s, %d)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner);
98 return FALSE;
101 /***********************************************************************
102 * CertTrustCleanup (CRYPTDLG.@)
104 HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
106 FIXME("(%p)\n", pProvData);
107 return E_NOTIMPL;
110 static BOOL CRYPTDLG_CheckOnlineCRL(void)
112 static const WCHAR policyFlagsKey[] = { 'S','o','f','t','w','a','r','e',
113 '\\','M','i','c','r','o','s','o','f','t','\\','C','r','y','p','t','o','g',
114 'r','a','p','h','y','\\','{','7','8','0','1','e','b','d','0','-','c','f',
115 '4','b','-','1','1','d','0','-','8','5','1','f','-','0','0','6','0','9',
116 '7','9','3','8','7','e','a','}',0 };
117 static const WCHAR policyFlags[] = { 'P','o','l','i','c','y','F','l','a',
118 'g','s',0 };
119 HKEY key;
120 BOOL ret = FALSE;
122 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE, policyFlagsKey, 0, KEY_READ, &key))
124 DWORD type, flags, size = sizeof(flags);
126 if (!RegQueryValueExW(key, policyFlags, NULL, &type, (BYTE *)&flags,
127 &size) && type == REG_DWORD)
129 /* The flag values aren't defined in any header I'm aware of, but
130 * this value is well documented on the net.
132 if (flags & 0x00010000)
133 ret = TRUE;
135 RegCloseKey(key);
137 return ret;
140 /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
141 * is.
143 static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
145 BOOL ret;
146 BYTE hash[20];
147 DWORD size = sizeof(hash);
149 if ((ret = CertGetCertificateContextProperty(pCert,
150 CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
152 static const WCHAR disallowedW[] =
153 { 'D','i','s','a','l','l','o','w','e','d',0 };
154 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
155 X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, disallowedW);
157 if (disallowed)
159 PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
160 X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
162 if (found)
164 ret = FALSE;
165 CertFreeCertificateContext(found);
167 CertCloseStore(disallowed, 0);
170 return ret;
173 static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
175 DWORD confidence = 0;
177 confidence = 0;
178 if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
179 confidence |= CERT_CONFIDENCE_SIG;
180 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
181 confidence |= CERT_CONFIDENCE_TIME;
182 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
183 confidence |= CERT_CONFIDENCE_TIMENEST;
184 return confidence;
187 static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
188 PCCERT_CHAIN_CONTEXT chain)
190 BOOL ret;
191 CRYPT_PROVIDER_SGNR signer;
192 PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
193 DWORD i;
195 memset(&signer, 0, sizeof(signer));
196 signer.cbStruct = sizeof(signer);
197 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
198 if (ret)
200 CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
201 FALSE, 0);
203 if (sgnr)
205 sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
206 sgnr->pChainContext = CertDuplicateCertificateChain(chain);
208 else
209 ret = FALSE;
210 for (i = 0; ret && i < simpleChain->cElement; i++)
212 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
213 simpleChain->rgpElement[i]->pCertContext);
214 if (ret)
216 CRYPT_PROVIDER_CERT *cert;
218 if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
220 CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
222 cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
223 element->TrustStatus.dwErrorStatus);
224 cert->dwError = element->TrustStatus.dwErrorStatus;
225 cert->pChainElement = element;
227 else
228 ret = FALSE;
232 return ret;
235 static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
236 CRYPT_PROVIDER_DATA *data)
238 CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
240 /* This should always be true, but just in case the calling function is
241 * called directly:
243 if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB &&
244 data->pWintrustData->u.pBlob && data->pWintrustData->u.pBlob->cbMemObject ==
245 sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
246 data->pWintrustData->u.pBlob->pbMemObject)
247 pCert = (CERT_VERIFY_CERTIFICATE_TRUST *)
248 data->pWintrustData->u.pBlob->pbMemObject;
249 return pCert;
252 static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
254 HCERTCHAINENGINE engine = NULL;
255 HCERTSTORE root = NULL, trust = NULL;
256 DWORD i;
258 if (cert->cRootStores)
260 root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
261 CERT_STORE_CREATE_NEW_FLAG, NULL);
262 if (root)
264 for (i = 0; i < cert->cRootStores; i++)
265 CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
268 if (cert->cTrustStores)
270 trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
271 CERT_STORE_CREATE_NEW_FLAG, NULL);
272 if (trust)
274 for (i = 0; i < cert->cTrustStores; i++)
275 CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
278 if (cert->cRootStores || cert->cStores || cert->cTrustStores)
280 CERT_CHAIN_ENGINE_CONFIG config;
282 memset(&config, 0, sizeof(config));
283 config.cbSize = sizeof(config);
284 config.hRestrictedRoot = root;
285 config.hRestrictedTrust = trust;
286 config.cAdditionalStore = cert->cStores;
287 config.rghAdditionalStore = cert->rghstoreCAs;
288 config.hRestrictedRoot = root;
289 CertCreateCertificateChainEngine(&config, &engine);
290 CertCloseStore(root, 0);
291 CertCloseStore(trust, 0);
293 return engine;
296 /***********************************************************************
297 * CertTrustFinalPolicy (CRYPTDLG.@)
299 HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
301 BOOL ret;
302 DWORD err = S_OK;
303 CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
305 TRACE("(%p)\n", data);
307 if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
308 FIXME("unimplemented for UI choice %d\n",
309 data->pWintrustData->dwUIChoice);
310 if (pCert)
312 DWORD flags = 0;
313 CERT_CHAIN_PARA chainPara;
314 HCERTCHAINENGINE engine;
316 memset(&chainPara, 0, sizeof(chainPara));
317 chainPara.cbSize = sizeof(chainPara);
318 if (CRYPTDLG_CheckOnlineCRL())
319 flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
320 engine = CRYPTDLG_MakeEngine(pCert);
321 GetSystemTimeAsFileTime(&data->sftSystemTime);
322 ret = CRYPTDLG_IsCertAllowed(pCert->pccert);
323 if (ret)
325 PCCERT_CHAIN_CONTEXT chain;
327 ret = CertGetCertificateChain(engine, pCert->pccert,
328 &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
329 if (ret)
331 if (chain->cChain != 1)
333 FIXME("unimplemented for more than 1 simple chain\n");
334 err = TRUST_E_SUBJECT_FORM_UNKNOWN;
335 ret = FALSE;
337 else if ((ret = CRYPTDLG_CopyChain(data, chain)))
339 if (CertVerifyTimeValidity(&data->sftSystemTime,
340 pCert->pccert->pCertInfo))
342 ret = FALSE;
343 err = CERT_E_EXPIRED;
346 else
347 err = TRUST_E_SYSTEM_ERROR;
348 CertFreeCertificateChain(chain);
350 else
351 err = TRUST_E_SUBJECT_NOT_TRUSTED;
353 CertFreeCertificateChainEngine(engine);
355 else
357 ret = FALSE;
358 err = TRUST_E_NOSIGNATURE;
360 /* Oddly, native doesn't set the error in the trust step error location,
361 * probably because this action is more advisory than anything else.
362 * Instead it stores it as the final error, but the function "succeeds" in
363 * any case.
365 if (!ret)
366 data->dwFinalError = err;
367 TRACE("returning %d (%08x)\n", S_OK, data->dwFinalError);
368 return S_OK;
371 /***********************************************************************
372 * CertViewPropertiesA (CRYPTDLG.@)
374 BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info)
376 CERT_VIEWPROPERTIES_STRUCT_W infoW;
377 LPWSTR title = NULL;
378 BOOL ret;
380 TRACE("(%p)\n", info);
382 memcpy(&infoW, info, sizeof(infoW));
383 if (info->szTitle)
385 int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0);
387 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
388 if (title)
390 MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len);
391 infoW.szTitle = title;
393 else
395 ret = FALSE;
396 goto error;
399 ret = CertViewPropertiesW(&infoW);
400 HeapFree(GetProcessHeap(), 0, title);
401 error:
402 return ret;
405 /***********************************************************************
406 * CertViewPropertiesW (CRYPTDLG.@)
408 BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info)
410 static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY;
411 CERT_VERIFY_CERTIFICATE_TRUST trust;
412 WINTRUST_BLOB_INFO blob;
413 WINTRUST_DATA wtd;
414 LONG err;
415 BOOL ret;
417 TRACE("(%p)\n", info);
419 memset(&trust, 0, sizeof(trust));
420 trust.cbSize = sizeof(trust);
421 trust.pccert = info->pCertContext;
422 trust.cRootStores = info->cRootStores;
423 trust.rghstoreRoots = info->rghstoreRoots;
424 trust.cStores = info->cStores;
425 trust.rghstoreCAs = info->rghstoreCAs;
426 trust.cTrustStores = info->cTrustStores;
427 trust.rghstoreTrust = info->rghstoreTrust;
428 memset(&blob, 0, sizeof(blob));
429 blob.cbStruct = sizeof(blob);
430 blob.cbMemObject = sizeof(trust);
431 blob.pbMemObject = (BYTE *)&trust;
432 memset(&wtd, 0, sizeof(wtd));
433 wtd.cbStruct = sizeof(wtd);
434 wtd.dwUIChoice = WTD_UI_NONE;
435 wtd.dwUnionChoice = WTD_CHOICE_BLOB;
436 wtd.u.pBlob = &blob;
437 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
438 err = WinVerifyTrust(NULL, &cert_action_verify, &wtd);
439 if (err == ERROR_SUCCESS)
441 CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo;
442 BOOL propsChanged = FALSE;
444 memset(&uiInfo, 0, sizeof(uiInfo));
445 uiInfo.dwSize = sizeof(uiInfo);
446 uiInfo.hwndParent = info->hwndParent;
447 uiInfo.dwFlags =
448 CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES;
449 uiInfo.szTitle = info->szTitle;
450 uiInfo.pCertContext = info->pCertContext;
451 uiInfo.cPurposes = info->cArrayPurposes;
452 uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes;
453 uiInfo.u.hWVTStateData = wtd.hWVTStateData;
454 uiInfo.fpCryptProviderDataTrustedUsage = TRUE;
455 uiInfo.cPropSheetPages = info->cArrayPropSheetPages;
456 uiInfo.rgPropSheetPages = info->arrayPropSheetPages;
457 uiInfo.nStartPage = info->nStartPage;
458 ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged);
459 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
460 WinVerifyTrust(NULL, &cert_action_verify, &wtd);
462 else
463 ret = FALSE;
464 return ret;
467 static BOOL CRYPT_FormatHexString(const BYTE *pbEncoded, DWORD cbEncoded,
468 WCHAR *str, DWORD *pcchStr)
470 BOOL ret;
471 DWORD charsNeeded;
473 if (cbEncoded)
474 charsNeeded = (cbEncoded * 3);
475 else
476 charsNeeded = 1;
477 if (!str)
479 *pcchStr = charsNeeded;
480 ret = TRUE;
482 else if (*pcchStr < charsNeeded)
484 *pcchStr = charsNeeded;
485 SetLastError(ERROR_MORE_DATA);
486 ret = FALSE;
488 else
490 static const WCHAR fmt[] = { '%','0','2','x',' ',0 };
491 static const WCHAR endFmt[] = { '%','0','2','x',0 };
492 DWORD i;
493 LPWSTR ptr = str;
495 *pcchStr = charsNeeded;
496 if (cbEncoded)
498 for (i = 0; i < cbEncoded; i++)
500 if (i < cbEncoded - 1)
501 ptr += swprintf(ptr, 4, fmt, pbEncoded[i]);
502 else
503 ptr += swprintf(ptr, 3, endFmt, pbEncoded[i]);
506 else
507 *ptr = 0;
508 ret = TRUE;
510 return ret;
513 static const WCHAR indent[] = { ' ',' ',' ',' ',' ',0 };
514 static const WCHAR colonCrlf[] = { ':','\r','\n',0 };
515 static const WCHAR colonSpace[] = { ':',' ',0 };
516 static const WCHAR crlf[] = { '\r','\n',0 };
517 static const WCHAR commaSep[] = { ',',' ',0 };
519 static BOOL CRYPT_FormatCPS(DWORD dwCertEncodingType,
520 DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded,
521 WCHAR *str, DWORD *pcchStr)
523 BOOL ret;
524 DWORD size, charsNeeded = 1;
525 CERT_NAME_VALUE *cpsValue;
527 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
528 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &cpsValue, &size)))
530 LPCWSTR sep;
531 DWORD sepLen;
533 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
534 sep = crlf;
535 else
536 sep = commaSep;
538 sepLen = lstrlenW(sep);
540 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
542 charsNeeded += 3 * lstrlenW(indent);
543 if (str && *pcchStr >= charsNeeded)
545 lstrcpyW(str, indent);
546 str += lstrlenW(indent);
547 lstrcpyW(str, indent);
548 str += lstrlenW(indent);
549 lstrcpyW(str, indent);
550 str += lstrlenW(indent);
553 charsNeeded += cpsValue->Value.cbData / sizeof(WCHAR);
554 if (str && *pcchStr >= charsNeeded)
556 lstrcpyW(str, (LPWSTR)cpsValue->Value.pbData);
557 str += cpsValue->Value.cbData / sizeof(WCHAR);
559 charsNeeded += sepLen;
560 if (str && *pcchStr >= charsNeeded)
562 lstrcpyW(str, sep);
563 str += sepLen;
565 LocalFree(cpsValue);
566 if (!str)
567 *pcchStr = charsNeeded;
568 else if (*pcchStr < charsNeeded)
570 *pcchStr = charsNeeded;
571 SetLastError(ERROR_MORE_DATA);
572 ret = FALSE;
574 else
575 *pcchStr = charsNeeded;
577 return ret;
580 static BOOL CRYPT_FormatUserNotice(DWORD dwCertEncodingType,
581 DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded,
582 WCHAR *str, DWORD *pcchStr)
584 BOOL ret;
585 DWORD size, charsNeeded = 1;
586 CERT_POLICY_QUALIFIER_USER_NOTICE *notice;
588 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
589 X509_PKIX_POLICY_QUALIFIER_USERNOTICE, pbEncoded, cbEncoded,
590 CRYPT_DECODE_ALLOC_FLAG, NULL, &notice, &size)))
592 static const WCHAR numFmt[] = { '%','d',0 };
593 CERT_POLICY_QUALIFIER_NOTICE_REFERENCE *pNoticeRef =
594 notice->pNoticeReference;
595 LPCWSTR headingSep, sep;
596 DWORD headingSepLen, sepLen;
597 LPWSTR noticeRef, organization, noticeNum, noticeText;
598 DWORD noticeRefLen, organizationLen, noticeNumLen, noticeTextLen;
599 WCHAR noticeNumStr[11];
601 noticeRefLen = LoadStringW(hInstance, IDS_NOTICE_REF,
602 (LPWSTR)&noticeRef, 0);
603 organizationLen = LoadStringW(hInstance, IDS_ORGANIZATION,
604 (LPWSTR)&organization, 0);
605 noticeNumLen = LoadStringW(hInstance, IDS_NOTICE_NUM,
606 (LPWSTR)&noticeNum, 0);
607 noticeTextLen = LoadStringW(hInstance, IDS_NOTICE_TEXT,
608 (LPWSTR)&noticeText, 0);
609 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
611 headingSep = colonCrlf;
612 sep = crlf;
614 else
616 headingSep = colonSpace;
617 sep = commaSep;
619 sepLen = lstrlenW(sep);
620 headingSepLen = lstrlenW(headingSep);
622 if (pNoticeRef)
624 DWORD k;
625 LPCSTR src;
627 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
629 charsNeeded += 3 * lstrlenW(indent);
630 if (str && *pcchStr >= charsNeeded)
632 lstrcpyW(str, indent);
633 str += lstrlenW(indent);
634 lstrcpyW(str, indent);
635 str += lstrlenW(indent);
636 lstrcpyW(str, indent);
637 str += lstrlenW(indent);
640 charsNeeded += noticeRefLen;
641 if (str && *pcchStr >= charsNeeded)
643 memcpy(str, noticeRef, noticeRefLen * sizeof(WCHAR));
644 str += noticeRefLen;
646 charsNeeded += headingSepLen;
647 if (str && *pcchStr >= charsNeeded)
649 lstrcpyW(str, headingSep);
650 str += headingSepLen;
652 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
654 charsNeeded += 4 * lstrlenW(indent);
655 if (str && *pcchStr >= charsNeeded)
657 lstrcpyW(str, indent);
658 str += lstrlenW(indent);
659 lstrcpyW(str, indent);
660 str += lstrlenW(indent);
661 lstrcpyW(str, indent);
662 str += lstrlenW(indent);
663 lstrcpyW(str, indent);
664 str += lstrlenW(indent);
667 charsNeeded += organizationLen;
668 if (str && *pcchStr >= charsNeeded)
670 memcpy(str, organization, organizationLen * sizeof(WCHAR));
671 str += organizationLen;
673 charsNeeded += strlen(pNoticeRef->pszOrganization);
674 if (str && *pcchStr >= charsNeeded)
675 for (src = pNoticeRef->pszOrganization; src && *src;
676 src++, str++)
677 *str = *src;
678 charsNeeded += sepLen;
679 if (str && *pcchStr >= charsNeeded)
681 lstrcpyW(str, sep);
682 str += sepLen;
684 for (k = 0; k < pNoticeRef->cNoticeNumbers; k++)
686 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
688 charsNeeded += 4 * lstrlenW(indent);
689 if (str && *pcchStr >= charsNeeded)
691 lstrcpyW(str, indent);
692 str += lstrlenW(indent);
693 lstrcpyW(str, indent);
694 str += lstrlenW(indent);
695 lstrcpyW(str, indent);
696 str += lstrlenW(indent);
697 lstrcpyW(str, indent);
698 str += lstrlenW(indent);
701 charsNeeded += noticeNumLen;
702 if (str && *pcchStr >= charsNeeded)
704 memcpy(str, noticeNum, noticeNumLen * sizeof(WCHAR));
705 str += noticeNumLen;
707 swprintf(noticeNumStr, ARRAY_SIZE(noticeNumStr), numFmt, k + 1);
708 charsNeeded += lstrlenW(noticeNumStr);
709 if (str && *pcchStr >= charsNeeded)
711 lstrcpyW(str, noticeNumStr);
712 str += lstrlenW(noticeNumStr);
714 charsNeeded += sepLen;
715 if (str && *pcchStr >= charsNeeded)
717 lstrcpyW(str, sep);
718 str += sepLen;
722 if (notice->pszDisplayText)
724 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
726 charsNeeded += 3 * lstrlenW(indent);
727 if (str && *pcchStr >= charsNeeded)
729 lstrcpyW(str, indent);
730 str += lstrlenW(indent);
731 lstrcpyW(str, indent);
732 str += lstrlenW(indent);
733 lstrcpyW(str, indent);
734 str += lstrlenW(indent);
737 charsNeeded += noticeTextLen;
738 if (str && *pcchStr >= charsNeeded)
740 memcpy(str, noticeText, noticeTextLen * sizeof(WCHAR));
741 str += noticeTextLen;
743 charsNeeded += lstrlenW(notice->pszDisplayText);
744 if (str && *pcchStr >= charsNeeded)
746 lstrcpyW(str, notice->pszDisplayText);
747 str += lstrlenW(notice->pszDisplayText);
749 charsNeeded += sepLen;
750 if (str && *pcchStr >= charsNeeded)
752 lstrcpyW(str, sep);
753 str += sepLen;
756 LocalFree(notice);
757 if (!str)
758 *pcchStr = charsNeeded;
759 else if (*pcchStr < charsNeeded)
761 *pcchStr = charsNeeded;
762 SetLastError(ERROR_MORE_DATA);
763 ret = FALSE;
765 else
766 *pcchStr = charsNeeded;
768 return ret;
771 /***********************************************************************
772 * FormatVerisignExtension (CRYPTDLG.@)
774 BOOL WINAPI FormatVerisignExtension(DWORD dwCertEncodingType,
775 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
776 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
777 DWORD *pcbFormat)
779 CERT_POLICIES_INFO *policies;
780 DWORD size;
781 BOOL ret = FALSE;
783 if (!cbEncoded)
785 SetLastError(E_INVALIDARG);
786 return FALSE;
788 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_POLICIES,
789 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size)))
791 static const WCHAR numFmt[] = { '%','d',0 };
792 DWORD charsNeeded = 1; /* space for NULL terminator */
793 LPCWSTR headingSep, sep;
794 DWORD headingSepLen, sepLen;
795 WCHAR policyNum[11], policyQualifierNum[11];
796 LPWSTR certPolicy, policyId, policyQualifierInfo, policyQualifierId;
797 LPWSTR cps, userNotice, qualifier;
798 DWORD certPolicyLen, policyIdLen, policyQualifierInfoLen;
799 DWORD policyQualifierIdLen, cpsLen, userNoticeLen, qualifierLen;
800 DWORD i;
801 LPWSTR str = pbFormat;
803 certPolicyLen = LoadStringW(hInstance, IDS_CERT_POLICY,
804 (LPWSTR)&certPolicy, 0);
805 policyIdLen = LoadStringW(hInstance, IDS_POLICY_ID, (LPWSTR)&policyId,
807 policyQualifierInfoLen = LoadStringW(hInstance,
808 IDS_POLICY_QUALIFIER_INFO, (LPWSTR)&policyQualifierInfo, 0);
809 policyQualifierIdLen = LoadStringW(hInstance, IDS_POLICY_QUALIFIER_ID,
810 (LPWSTR)&policyQualifierId, 0);
811 cpsLen = LoadStringW(hInstance, IDS_CPS, (LPWSTR)&cps, 0);
812 userNoticeLen = LoadStringW(hInstance, IDS_USER_NOTICE,
813 (LPWSTR)&userNotice, 0);
814 qualifierLen = LoadStringW(hInstance, IDS_QUALIFIER,
815 (LPWSTR)&qualifier, 0);
816 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
818 headingSep = colonCrlf;
819 sep = crlf;
821 else
823 headingSep = colonSpace;
824 sep = commaSep;
826 sepLen = lstrlenW(sep);
827 headingSepLen = lstrlenW(headingSep);
829 for (i = 0; ret && i < policies->cPolicyInfo; i++)
831 CERT_POLICY_INFO *policy = &policies->rgPolicyInfo[i];
832 DWORD j;
833 LPCSTR src;
835 charsNeeded += 1; /* '['*/
836 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
837 *str++ = '[';
838 swprintf(policyNum, ARRAY_SIZE(policyNum), numFmt, i + 1);
839 charsNeeded += lstrlenW(policyNum);
840 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
842 lstrcpyW(str, policyNum);
843 str += lstrlenW(policyNum);
845 charsNeeded += 1; /* ']'*/
846 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
847 *str++ = ']';
848 charsNeeded += certPolicyLen;
849 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
851 memcpy(str, certPolicy, certPolicyLen * sizeof(WCHAR));
852 str += certPolicyLen;
854 charsNeeded += headingSepLen;
855 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
857 lstrcpyW(str, headingSep);
858 str += headingSepLen;
860 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
862 charsNeeded += lstrlenW(indent);
863 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
865 lstrcpyW(str, indent);
866 str += lstrlenW(indent);
869 charsNeeded += policyIdLen;
870 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
872 memcpy(str, policyId, policyIdLen * sizeof(WCHAR));
873 str += policyIdLen;
875 charsNeeded += strlen(policy->pszPolicyIdentifier);
876 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
878 for (src = policy->pszPolicyIdentifier; src && *src;
879 src++, str++)
880 *str = *src;
882 charsNeeded += sepLen;
883 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
885 lstrcpyW(str, sep);
886 str += sepLen;
888 for (j = 0; j < policy->cPolicyQualifier; j++)
890 CERT_POLICY_QUALIFIER_INFO *qualifierInfo =
891 &policy->rgPolicyQualifier[j];
892 DWORD sizeRemaining;
894 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
896 charsNeeded += lstrlenW(indent);
897 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
899 lstrcpyW(str, indent);
900 str += lstrlenW(indent);
903 charsNeeded += 1; /* '['*/
904 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
905 *str++ = '[';
906 charsNeeded += lstrlenW(policyNum);
907 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
909 lstrcpyW(str, policyNum);
910 str += lstrlenW(policyNum);
912 charsNeeded += 1; /* ','*/
913 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
914 *str++ = ',';
915 swprintf(policyQualifierNum, ARRAY_SIZE(policyQualifierNum), numFmt, j + 1);
916 charsNeeded += lstrlenW(policyQualifierNum);
917 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
919 lstrcpyW(str, policyQualifierNum);
920 str += lstrlenW(policyQualifierNum);
922 charsNeeded += 1; /* ']'*/
923 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
924 *str++ = ']';
925 charsNeeded += policyQualifierInfoLen;
926 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
928 memcpy(str, policyQualifierInfo,
929 policyQualifierInfoLen * sizeof(WCHAR));
930 str += policyQualifierInfoLen;
932 charsNeeded += headingSepLen;
933 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
935 lstrcpyW(str, headingSep);
936 str += headingSepLen;
938 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
940 charsNeeded += 2 * lstrlenW(indent);
941 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
943 lstrcpyW(str, indent);
944 str += lstrlenW(indent);
945 lstrcpyW(str, indent);
946 str += lstrlenW(indent);
949 charsNeeded += policyQualifierIdLen;
950 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
952 memcpy(str, policyQualifierId,
953 policyQualifierIdLen * sizeof(WCHAR));
954 str += policyQualifierIdLen;
956 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
957 szOID_PKIX_POLICY_QUALIFIER_CPS))
959 charsNeeded += cpsLen;
960 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
962 memcpy(str, cps, cpsLen * sizeof(WCHAR));
963 str += cpsLen;
966 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
967 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
969 charsNeeded += userNoticeLen;
970 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
972 memcpy(str, userNotice, userNoticeLen * sizeof(WCHAR));
973 str += userNoticeLen;
976 else
978 charsNeeded += strlen(qualifierInfo->pszPolicyQualifierId);
979 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
981 for (src = qualifierInfo->pszPolicyQualifierId;
982 src && *src; src++, str++)
983 *str = *src;
986 charsNeeded += sepLen;
987 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
989 lstrcpyW(str, sep);
990 str += sepLen;
992 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
994 charsNeeded += 2 * lstrlenW(indent);
995 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
997 lstrcpyW(str, indent);
998 str += lstrlenW(indent);
999 lstrcpyW(str, indent);
1000 str += lstrlenW(indent);
1003 charsNeeded += qualifierLen;
1004 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
1006 memcpy(str, qualifier, qualifierLen * sizeof(WCHAR));
1007 str += qualifierLen;
1009 charsNeeded += headingSepLen;
1010 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
1012 lstrcpyW(str, headingSep);
1013 str += headingSepLen;
1015 /* This if block is deliberately redundant with the same if
1016 * block above, in order to keep the code more readable (the
1017 * code flow follows the order in which the strings are output.)
1019 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1020 szOID_PKIX_POLICY_QUALIFIER_CPS))
1022 if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1024 /* Insufficient space, determine how much is needed. */
1025 ret = CRYPT_FormatCPS(dwCertEncodingType,
1026 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1027 qualifierInfo->Qualifier.cbData, NULL, &size);
1028 if (ret)
1029 charsNeeded += size - 1;
1031 else
1033 sizeRemaining = *pcbFormat / sizeof(WCHAR);
1034 sizeRemaining -= str - (LPWSTR)pbFormat;
1035 ret = CRYPT_FormatCPS(dwCertEncodingType,
1036 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1037 qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1038 if (ret || GetLastError() == ERROR_MORE_DATA)
1040 charsNeeded += sizeRemaining - 1;
1041 str += sizeRemaining - 1;
1045 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1046 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
1048 if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1050 /* Insufficient space, determine how much is needed. */
1051 ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1052 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1053 qualifierInfo->Qualifier.cbData, NULL, &size);
1054 if (ret)
1055 charsNeeded += size - 1;
1057 else
1059 sizeRemaining = *pcbFormat / sizeof(WCHAR);
1060 sizeRemaining -= str - (LPWSTR)pbFormat;
1061 ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1062 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1063 qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1064 if (ret || GetLastError() == ERROR_MORE_DATA)
1066 charsNeeded += sizeRemaining - 1;
1067 str += sizeRemaining - 1;
1071 else
1073 if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1075 /* Insufficient space, determine how much is needed. */
1076 ret = CRYPT_FormatHexString(
1077 qualifierInfo->Qualifier.pbData,
1078 qualifierInfo->Qualifier.cbData, NULL, &size);
1079 if (ret)
1080 charsNeeded += size - 1;
1082 else
1084 sizeRemaining = *pcbFormat / sizeof(WCHAR);
1085 sizeRemaining -= str - (LPWSTR)pbFormat;
1086 ret = CRYPT_FormatHexString(
1087 qualifierInfo->Qualifier.pbData,
1088 qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1089 if (ret || GetLastError() == ERROR_MORE_DATA)
1091 charsNeeded += sizeRemaining - 1;
1092 str += sizeRemaining - 1;
1098 LocalFree(policies);
1099 if (ret)
1101 if (!pbFormat)
1102 *pcbFormat = charsNeeded * sizeof(WCHAR);
1103 else if (*pcbFormat < charsNeeded * sizeof(WCHAR))
1105 *pcbFormat = charsNeeded * sizeof(WCHAR);
1106 SetLastError(ERROR_MORE_DATA);
1107 ret = FALSE;
1109 else
1110 *pcbFormat = charsNeeded * sizeof(WCHAR);
1113 return ret;
1116 #define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4"
1118 /***********************************************************************
1119 * DllRegisterServer (CRYPTDLG.@)
1121 HRESULT WINAPI DllRegisterServer(void)
1123 static WCHAR cryptdlg[] = { 'c','r','y','p','t','d','l','g','.',
1124 'd','l','l',0 };
1125 static WCHAR wintrust[] = { 'w','i','n','t','r','u','s','t','.',
1126 'd','l','l',0 };
1127 static WCHAR certTrustInit[] = { 'C','e','r','t','T','r','u','s','t',
1128 'I','n','i','t',0 };
1129 static WCHAR wintrustCertificateTrust[] = { 'W','i','n','t','r','u','s','t',
1130 'C','e','r','t','i','f','i','c','a','t','e','T','r','u','s','t',0 };
1131 static WCHAR certTrustCertPolicy[] = { 'C','e','r','t','T','r','u','s','t',
1132 'C','e','r','t','P','o','l','i','c','y',0 };
1133 static WCHAR certTrustFinalPolicy[] = { 'C','e','r','t','T','r','u','s','t',
1134 'F','i','n','a','l','P','o','l','i','c','y',0 };
1135 static WCHAR certTrustCleanup[] = { 'C','e','r','t','T','r','u','s','t',
1136 'C','l','e','a','n','u','p',0 };
1137 static const WCHAR cryptDlg[] = { 'c','r','y','p','t','d','l','g','.',
1138 'd','l','l',0 };
1139 CRYPT_REGISTER_ACTIONID reg;
1140 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1141 HRESULT hr = S_OK;
1143 memset(&reg, 0, sizeof(reg));
1144 reg.cbStruct = sizeof(reg);
1145 reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1146 reg.sInitProvider.pwszDLLName = cryptdlg;
1147 reg.sInitProvider.pwszFunctionName = certTrustInit;
1148 reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1149 reg.sCertificateProvider.pwszDLLName = wintrust;
1150 reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
1151 reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1152 reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
1153 reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
1154 reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1155 reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
1156 reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
1157 reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1158 reg.sCleanupProvider.pwszDLLName = cryptdlg;
1159 reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
1160 if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, &reg))
1161 hr = GetLastError();
1162 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1163 "1.3.6.1.4.1.311.16.1.1", cryptDlg, "EncodeAttrSequence");
1164 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1165 szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "EncodeRecipientID");
1166 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1167 "1.3.6.1.4.1.311.16.1.1", cryptDlg, "DecodeAttrSequence");
1168 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1169 szOID_MICROSOFT_Encryption_Key_Preference, cryptDlg, "DecodeRecipientID");
1170 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1171 szOID_PKIX_KP_EMAIL_PROTECTION, cryptDlg, "FormatPKIXEmailProtection");
1172 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1173 szOID_CERT_POLICIES, cryptDlg, "FormatVerisignExtension");
1174 return hr;
1177 /***********************************************************************
1178 * DllUnregisterServer (CRYPTDLG.@)
1180 HRESULT WINAPI DllUnregisterServer(void)
1182 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1184 WintrustRemoveActionID(&guid);
1185 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1186 "1.3.6.1.4.1.311.16.1.1");
1187 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1188 szOID_MICROSOFT_Encryption_Key_Preference);
1189 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1190 "1.3.6.1.4.1.311.16.1.1");
1191 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1192 szOID_MICROSOFT_Encryption_Key_Preference);
1193 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1194 szOID_PKIX_KP_EMAIL_PROTECTION);
1195 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1196 szOID_CERT_POLICIES);
1197 return S_OK;