kernelbase/tests: Use win_skip() for missing APIs.
[wine.git] / dlls / cryptdlg / main.c
blob1597dc2704ce6d1812b8a833332342615cb077c9
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, %ld, %p)\n", hinstDLL, fdwReason, lpvReserved);
44 switch (fdwReason)
46 case DLL_PROCESS_ATTACH:
47 DisableThreadLibraryCalls(hinstDLL);
48 hInstance = hinstDLL;
49 break;
51 return TRUE;
54 /***********************************************************************
55 * GetFriendlyNameOfCertA (CRYPTDLG.@)
57 DWORD WINAPI GetFriendlyNameOfCertA(PCCERT_CONTEXT pccert, LPSTR pchBuffer,
58 DWORD cchBuffer)
60 return CertGetNameStringA(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
61 pchBuffer, cchBuffer);
64 /***********************************************************************
65 * GetFriendlyNameOfCertW (CRYPTDLG.@)
67 DWORD WINAPI GetFriendlyNameOfCertW(PCCERT_CONTEXT pccert, LPWSTR pchBuffer,
68 DWORD cchBuffer)
70 return CertGetNameStringW(pccert, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL,
71 pchBuffer, cchBuffer);
74 /***********************************************************************
75 * CertTrustInit (CRYPTDLG.@)
77 HRESULT WINAPI CertTrustInit(CRYPT_PROVIDER_DATA *pProvData)
79 HRESULT ret = S_FALSE;
81 TRACE("(%p)\n", pProvData);
83 if (pProvData->padwTrustStepErrors &&
84 !pProvData->padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT])
85 ret = S_OK;
86 TRACE("returning %08lx\n", ret);
87 return ret;
90 /***********************************************************************
91 * CertTrustCertPolicy (CRYPTDLG.@)
93 BOOL WINAPI CertTrustCertPolicy(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSignerChain, DWORD idxCounterSigner)
95 FIXME("(%p, %ld, %s, %ld)\n", pProvData, idxSigner, fCounterSignerChain ? "TRUE" : "FALSE", idxCounterSigner);
96 return FALSE;
99 /***********************************************************************
100 * CertTrustCleanup (CRYPTDLG.@)
102 HRESULT WINAPI CertTrustCleanup(CRYPT_PROVIDER_DATA *pProvData)
104 FIXME("(%p)\n", pProvData);
105 return E_NOTIMPL;
108 static BOOL CRYPTDLG_CheckOnlineCRL(void)
110 HKEY key;
111 BOOL ret = FALSE;
113 if (!RegOpenKeyExW(HKEY_LOCAL_MACHINE,
114 L"Software\\Microsoft\\Cryptography\\{7801ebd0-cf4b-11d0-851f-0060979387ea}", 0, KEY_READ, &key))
116 DWORD type, flags, size = sizeof(flags);
118 if (!RegQueryValueExW(key, L"PolicyFlags", NULL, &type, (BYTE *)&flags,
119 &size) && type == REG_DWORD)
121 /* The flag values aren't defined in any header I'm aware of, but
122 * this value is well documented on the net.
124 if (flags & 0x00010000)
125 ret = TRUE;
127 RegCloseKey(key);
129 return ret;
132 /* Returns TRUE if pCert is not in the Disallowed system store, or FALSE if it
133 * is.
135 static BOOL CRYPTDLG_IsCertAllowed(PCCERT_CONTEXT pCert)
137 BOOL ret;
138 BYTE hash[20];
139 DWORD size = sizeof(hash);
141 if ((ret = CertGetCertificateContextProperty(pCert,
142 CERT_SIGNATURE_HASH_PROP_ID, hash, &size)))
144 HCERTSTORE disallowed = CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
145 X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"Disallowed");
147 if (disallowed)
149 PCCERT_CONTEXT found = CertFindCertificateInStore(disallowed,
150 X509_ASN_ENCODING, 0, CERT_FIND_SIGNATURE_HASH, hash, NULL);
152 if (found)
154 ret = FALSE;
155 CertFreeCertificateContext(found);
157 CertCloseStore(disallowed, 0);
160 return ret;
163 static DWORD CRYPTDLG_TrustStatusToConfidence(DWORD errorStatus)
165 DWORD confidence = 0;
167 confidence = 0;
168 if (!(errorStatus & CERT_TRUST_IS_NOT_SIGNATURE_VALID))
169 confidence |= CERT_CONFIDENCE_SIG;
170 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_VALID))
171 confidence |= CERT_CONFIDENCE_TIME;
172 if (!(errorStatus & CERT_TRUST_IS_NOT_TIME_NESTED))
173 confidence |= CERT_CONFIDENCE_TIMENEST;
174 return confidence;
177 static BOOL CRYPTDLG_CopyChain(CRYPT_PROVIDER_DATA *data,
178 PCCERT_CHAIN_CONTEXT chain)
180 BOOL ret;
181 CRYPT_PROVIDER_SGNR signer;
182 PCERT_SIMPLE_CHAIN simpleChain = chain->rgpChain[0];
183 DWORD i;
185 memset(&signer, 0, sizeof(signer));
186 signer.cbStruct = sizeof(signer);
187 ret = data->psPfns->pfnAddSgnr2Chain(data, FALSE, 0, &signer);
188 if (ret)
190 CRYPT_PROVIDER_SGNR *sgnr = WTHelperGetProvSignerFromChain(data, 0,
191 FALSE, 0);
193 if (sgnr)
195 sgnr->dwError = simpleChain->TrustStatus.dwErrorStatus;
196 sgnr->pChainContext = CertDuplicateCertificateChain(chain);
198 else
199 ret = FALSE;
200 for (i = 0; ret && i < simpleChain->cElement; i++)
202 ret = data->psPfns->pfnAddCert2Chain(data, 0, FALSE, 0,
203 simpleChain->rgpElement[i]->pCertContext);
204 if (ret)
206 CRYPT_PROVIDER_CERT *cert;
208 if ((cert = WTHelperGetProvCertFromChain(sgnr, i)))
210 CERT_CHAIN_ELEMENT *element = simpleChain->rgpElement[i];
212 cert->dwConfidence = CRYPTDLG_TrustStatusToConfidence(
213 element->TrustStatus.dwErrorStatus);
214 cert->dwError = element->TrustStatus.dwErrorStatus;
215 cert->pChainElement = element;
217 else
218 ret = FALSE;
222 return ret;
225 static CERT_VERIFY_CERTIFICATE_TRUST *CRYPTDLG_GetVerifyData(
226 CRYPT_PROVIDER_DATA *data)
228 CERT_VERIFY_CERTIFICATE_TRUST *pCert = NULL;
230 /* This should always be true, but just in case the calling function is
231 * called directly:
233 if (data->pWintrustData->dwUnionChoice == WTD_CHOICE_BLOB &&
234 data->pWintrustData->u.pBlob && data->pWintrustData->u.pBlob->cbMemObject ==
235 sizeof(CERT_VERIFY_CERTIFICATE_TRUST) &&
236 data->pWintrustData->u.pBlob->pbMemObject)
237 pCert = (CERT_VERIFY_CERTIFICATE_TRUST *)
238 data->pWintrustData->u.pBlob->pbMemObject;
239 return pCert;
242 static HCERTCHAINENGINE CRYPTDLG_MakeEngine(CERT_VERIFY_CERTIFICATE_TRUST *cert)
244 HCERTCHAINENGINE engine = NULL;
245 HCERTSTORE root = NULL, trust = NULL;
246 DWORD i;
248 if (cert->cRootStores)
250 root = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
251 CERT_STORE_CREATE_NEW_FLAG, NULL);
252 if (root)
254 for (i = 0; i < cert->cRootStores; i++)
255 CertAddStoreToCollection(root, cert->rghstoreRoots[i], 0, 0);
258 if (cert->cTrustStores)
260 trust = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0,
261 CERT_STORE_CREATE_NEW_FLAG, NULL);
262 if (trust)
264 for (i = 0; i < cert->cTrustStores; i++)
265 CertAddStoreToCollection(trust, cert->rghstoreTrust[i], 0, 0);
268 if (cert->cRootStores || cert->cStores || cert->cTrustStores)
270 CERT_CHAIN_ENGINE_CONFIG config;
272 memset(&config, 0, sizeof(config));
273 config.cbSize = sizeof(config);
274 config.hRestrictedRoot = root;
275 config.hRestrictedTrust = trust;
276 config.cAdditionalStore = cert->cStores;
277 config.rghAdditionalStore = cert->rghstoreCAs;
278 config.hRestrictedRoot = root;
279 CertCreateCertificateChainEngine(&config, &engine);
280 CertCloseStore(root, 0);
281 CertCloseStore(trust, 0);
283 return engine;
286 /***********************************************************************
287 * CertTrustFinalPolicy (CRYPTDLG.@)
289 HRESULT WINAPI CertTrustFinalPolicy(CRYPT_PROVIDER_DATA *data)
291 BOOL ret;
292 DWORD err = S_OK;
293 CERT_VERIFY_CERTIFICATE_TRUST *pCert = CRYPTDLG_GetVerifyData(data);
295 TRACE("(%p)\n", data);
297 if (data->pWintrustData->dwUIChoice != WTD_UI_NONE)
298 FIXME("unimplemented for UI choice %ld\n",
299 data->pWintrustData->dwUIChoice);
300 if (pCert)
302 DWORD flags = 0;
303 CERT_CHAIN_PARA chainPara;
304 HCERTCHAINENGINE engine;
306 memset(&chainPara, 0, sizeof(chainPara));
307 chainPara.cbSize = sizeof(chainPara);
308 if (CRYPTDLG_CheckOnlineCRL())
309 flags |= CERT_CHAIN_REVOCATION_CHECK_END_CERT;
310 engine = CRYPTDLG_MakeEngine(pCert);
311 GetSystemTimeAsFileTime(&data->sftSystemTime);
312 ret = CRYPTDLG_IsCertAllowed(pCert->pccert);
313 if (ret)
315 PCCERT_CHAIN_CONTEXT chain;
317 ret = CertGetCertificateChain(engine, pCert->pccert,
318 &data->sftSystemTime, NULL, &chainPara, flags, NULL, &chain);
319 if (ret)
321 if (chain->cChain != 1)
323 FIXME("unimplemented for more than 1 simple chain\n");
324 err = TRUST_E_SUBJECT_FORM_UNKNOWN;
325 ret = FALSE;
327 else if ((ret = CRYPTDLG_CopyChain(data, chain)))
329 if (CertVerifyTimeValidity(&data->sftSystemTime,
330 pCert->pccert->pCertInfo))
332 ret = FALSE;
333 err = CERT_E_EXPIRED;
336 else
337 err = TRUST_E_SYSTEM_ERROR;
338 CertFreeCertificateChain(chain);
340 else
341 err = TRUST_E_SUBJECT_NOT_TRUSTED;
343 CertFreeCertificateChainEngine(engine);
345 else
347 ret = FALSE;
348 err = TRUST_E_NOSIGNATURE;
350 /* Oddly, native doesn't set the error in the trust step error location,
351 * probably because this action is more advisory than anything else.
352 * Instead it stores it as the final error, but the function "succeeds" in
353 * any case.
355 if (!ret)
356 data->dwFinalError = err;
357 TRACE("returning %ld (%08lx)\n", S_OK, data->dwFinalError);
358 return S_OK;
361 /***********************************************************************
362 * CertViewPropertiesA (CRYPTDLG.@)
364 BOOL WINAPI CertViewPropertiesA(CERT_VIEWPROPERTIES_STRUCT_A *info)
366 CERT_VIEWPROPERTIES_STRUCT_W infoW;
367 LPWSTR title = NULL;
368 BOOL ret;
370 TRACE("(%p)\n", info);
372 memcpy(&infoW, info, sizeof(infoW));
373 if (info->szTitle)
375 int len = MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, NULL, 0);
377 title = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
378 if (title)
380 MultiByteToWideChar(CP_ACP, 0, info->szTitle, -1, title, len);
381 infoW.szTitle = title;
383 else
385 ret = FALSE;
386 goto error;
389 ret = CertViewPropertiesW(&infoW);
390 HeapFree(GetProcessHeap(), 0, title);
391 error:
392 return ret;
395 /***********************************************************************
396 * CertViewPropertiesW (CRYPTDLG.@)
398 BOOL WINAPI CertViewPropertiesW(CERT_VIEWPROPERTIES_STRUCT_W *info)
400 static GUID cert_action_verify = CERT_CERTIFICATE_ACTION_VERIFY;
401 CERT_VERIFY_CERTIFICATE_TRUST trust;
402 WINTRUST_BLOB_INFO blob;
403 WINTRUST_DATA wtd;
404 LONG err;
405 BOOL ret;
407 TRACE("(%p)\n", info);
409 memset(&trust, 0, sizeof(trust));
410 trust.cbSize = sizeof(trust);
411 trust.pccert = info->pCertContext;
412 trust.cRootStores = info->cRootStores;
413 trust.rghstoreRoots = info->rghstoreRoots;
414 trust.cStores = info->cStores;
415 trust.rghstoreCAs = info->rghstoreCAs;
416 trust.cTrustStores = info->cTrustStores;
417 trust.rghstoreTrust = info->rghstoreTrust;
418 memset(&blob, 0, sizeof(blob));
419 blob.cbStruct = sizeof(blob);
420 blob.cbMemObject = sizeof(trust);
421 blob.pbMemObject = (BYTE *)&trust;
422 memset(&wtd, 0, sizeof(wtd));
423 wtd.cbStruct = sizeof(wtd);
424 wtd.dwUIChoice = WTD_UI_NONE;
425 wtd.dwUnionChoice = WTD_CHOICE_BLOB;
426 wtd.u.pBlob = &blob;
427 wtd.dwStateAction = WTD_STATEACTION_VERIFY;
428 err = WinVerifyTrust(NULL, &cert_action_verify, &wtd);
429 if (err == ERROR_SUCCESS)
431 CRYPTUI_VIEWCERTIFICATE_STRUCTW uiInfo;
432 BOOL propsChanged = FALSE;
434 memset(&uiInfo, 0, sizeof(uiInfo));
435 uiInfo.dwSize = sizeof(uiInfo);
436 uiInfo.hwndParent = info->hwndParent;
437 uiInfo.dwFlags =
438 CRYPTUI_DISABLE_ADDTOSTORE | CRYPTUI_ENABLE_EDITPROPERTIES;
439 uiInfo.szTitle = info->szTitle;
440 uiInfo.pCertContext = info->pCertContext;
441 uiInfo.cPurposes = info->cArrayPurposes;
442 uiInfo.rgszPurposes = (LPCSTR *)info->arrayPurposes;
443 uiInfo.u.hWVTStateData = wtd.hWVTStateData;
444 uiInfo.fpCryptProviderDataTrustedUsage = TRUE;
445 uiInfo.cPropSheetPages = info->cArrayPropSheetPages;
446 uiInfo.rgPropSheetPages = info->arrayPropSheetPages;
447 uiInfo.nStartPage = info->nStartPage;
448 ret = CryptUIDlgViewCertificateW(&uiInfo, &propsChanged);
449 wtd.dwStateAction = WTD_STATEACTION_CLOSE;
450 WinVerifyTrust(NULL, &cert_action_verify, &wtd);
452 else
453 ret = FALSE;
454 return ret;
457 static BOOL CRYPT_FormatHexString(const BYTE *pbEncoded, DWORD cbEncoded,
458 WCHAR *str, DWORD *pcchStr)
460 BOOL ret;
461 DWORD charsNeeded;
463 if (cbEncoded)
464 charsNeeded = (cbEncoded * 3);
465 else
466 charsNeeded = 1;
467 if (!str)
469 *pcchStr = charsNeeded;
470 ret = TRUE;
472 else if (*pcchStr < charsNeeded)
474 *pcchStr = charsNeeded;
475 SetLastError(ERROR_MORE_DATA);
476 ret = FALSE;
478 else
480 DWORD i;
481 LPWSTR ptr = str;
483 *pcchStr = charsNeeded;
484 if (cbEncoded)
486 for (i = 0; i < cbEncoded; i++)
488 if (i < cbEncoded - 1)
489 ptr += swprintf(ptr, 4, L"%02x ", pbEncoded[i]);
490 else
491 ptr += swprintf(ptr, 3, L"%02x", pbEncoded[i]);
494 else
495 *ptr = 0;
496 ret = TRUE;
498 return ret;
501 static const WCHAR indent[] = L" ";
503 static BOOL CRYPT_FormatCPS(DWORD dwCertEncodingType,
504 DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded,
505 WCHAR *str, DWORD *pcchStr)
507 BOOL ret;
508 DWORD size, charsNeeded = 1;
509 CERT_NAME_VALUE *cpsValue;
511 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_UNICODE_ANY_STRING,
512 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &cpsValue, &size)))
514 LPCWSTR sep;
515 DWORD sepLen;
517 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
518 sep = L"\r\n";
519 else
520 sep = L", ";
522 sepLen = lstrlenW(sep);
524 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
526 charsNeeded += 3 * lstrlenW(indent);
527 if (str && *pcchStr >= charsNeeded)
529 lstrcpyW(str, indent);
530 str += lstrlenW(indent);
531 lstrcpyW(str, indent);
532 str += lstrlenW(indent);
533 lstrcpyW(str, indent);
534 str += lstrlenW(indent);
537 charsNeeded += cpsValue->Value.cbData / sizeof(WCHAR);
538 if (str && *pcchStr >= charsNeeded)
540 lstrcpyW(str, (LPWSTR)cpsValue->Value.pbData);
541 str += cpsValue->Value.cbData / sizeof(WCHAR);
543 charsNeeded += sepLen;
544 if (str && *pcchStr >= charsNeeded)
546 lstrcpyW(str, sep);
547 str += sepLen;
549 LocalFree(cpsValue);
550 if (!str)
551 *pcchStr = charsNeeded;
552 else if (*pcchStr < charsNeeded)
554 *pcchStr = charsNeeded;
555 SetLastError(ERROR_MORE_DATA);
556 ret = FALSE;
558 else
559 *pcchStr = charsNeeded;
561 return ret;
564 static BOOL CRYPT_FormatUserNotice(DWORD dwCertEncodingType,
565 DWORD dwFormatStrType, const BYTE *pbEncoded, DWORD cbEncoded,
566 WCHAR *str, DWORD *pcchStr)
568 BOOL ret;
569 DWORD size, charsNeeded = 1;
570 CERT_POLICY_QUALIFIER_USER_NOTICE *notice;
572 if ((ret = CryptDecodeObjectEx(dwCertEncodingType,
573 X509_PKIX_POLICY_QUALIFIER_USERNOTICE, pbEncoded, cbEncoded,
574 CRYPT_DECODE_ALLOC_FLAG, NULL, &notice, &size)))
576 CERT_POLICY_QUALIFIER_NOTICE_REFERENCE *pNoticeRef =
577 notice->pNoticeReference;
578 LPCWSTR headingSep, sep;
579 DWORD headingSepLen, sepLen;
580 LPWSTR noticeRef, organization, noticeNum, noticeText;
581 DWORD noticeRefLen, organizationLen, noticeNumLen, noticeTextLen;
582 WCHAR noticeNumStr[11];
584 noticeRefLen = LoadStringW(hInstance, IDS_NOTICE_REF,
585 (LPWSTR)&noticeRef, 0);
586 organizationLen = LoadStringW(hInstance, IDS_ORGANIZATION,
587 (LPWSTR)&organization, 0);
588 noticeNumLen = LoadStringW(hInstance, IDS_NOTICE_NUM,
589 (LPWSTR)&noticeNum, 0);
590 noticeTextLen = LoadStringW(hInstance, IDS_NOTICE_TEXT,
591 (LPWSTR)&noticeText, 0);
592 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
594 headingSep = L":\r\n";
595 sep = L"\r\n";
597 else
599 headingSep = L": ";
600 sep = L", ";
602 sepLen = lstrlenW(sep);
603 headingSepLen = lstrlenW(headingSep);
605 if (pNoticeRef)
607 DWORD k;
608 LPCSTR src;
610 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
612 charsNeeded += 3 * lstrlenW(indent);
613 if (str && *pcchStr >= charsNeeded)
615 lstrcpyW(str, indent);
616 str += lstrlenW(indent);
617 lstrcpyW(str, indent);
618 str += lstrlenW(indent);
619 lstrcpyW(str, indent);
620 str += lstrlenW(indent);
623 charsNeeded += noticeRefLen;
624 if (str && *pcchStr >= charsNeeded)
626 memcpy(str, noticeRef, noticeRefLen * sizeof(WCHAR));
627 str += noticeRefLen;
629 charsNeeded += headingSepLen;
630 if (str && *pcchStr >= charsNeeded)
632 lstrcpyW(str, headingSep);
633 str += headingSepLen;
635 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
637 charsNeeded += 4 * lstrlenW(indent);
638 if (str && *pcchStr >= charsNeeded)
640 lstrcpyW(str, indent);
641 str += lstrlenW(indent);
642 lstrcpyW(str, indent);
643 str += lstrlenW(indent);
644 lstrcpyW(str, indent);
645 str += lstrlenW(indent);
646 lstrcpyW(str, indent);
647 str += lstrlenW(indent);
650 charsNeeded += organizationLen;
651 if (str && *pcchStr >= charsNeeded)
653 memcpy(str, organization, organizationLen * sizeof(WCHAR));
654 str += organizationLen;
656 charsNeeded += strlen(pNoticeRef->pszOrganization);
657 if (str && *pcchStr >= charsNeeded)
658 for (src = pNoticeRef->pszOrganization; src && *src;
659 src++, str++)
660 *str = *src;
661 charsNeeded += sepLen;
662 if (str && *pcchStr >= charsNeeded)
664 lstrcpyW(str, sep);
665 str += sepLen;
667 for (k = 0; k < pNoticeRef->cNoticeNumbers; k++)
669 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
671 charsNeeded += 4 * lstrlenW(indent);
672 if (str && *pcchStr >= charsNeeded)
674 lstrcpyW(str, indent);
675 str += lstrlenW(indent);
676 lstrcpyW(str, indent);
677 str += lstrlenW(indent);
678 lstrcpyW(str, indent);
679 str += lstrlenW(indent);
680 lstrcpyW(str, indent);
681 str += lstrlenW(indent);
684 charsNeeded += noticeNumLen;
685 if (str && *pcchStr >= charsNeeded)
687 memcpy(str, noticeNum, noticeNumLen * sizeof(WCHAR));
688 str += noticeNumLen;
690 swprintf(noticeNumStr, ARRAY_SIZE(noticeNumStr), L"%d", k + 1);
691 charsNeeded += lstrlenW(noticeNumStr);
692 if (str && *pcchStr >= charsNeeded)
694 lstrcpyW(str, noticeNumStr);
695 str += lstrlenW(noticeNumStr);
697 charsNeeded += sepLen;
698 if (str && *pcchStr >= charsNeeded)
700 lstrcpyW(str, sep);
701 str += sepLen;
705 if (notice->pszDisplayText)
707 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
709 charsNeeded += 3 * lstrlenW(indent);
710 if (str && *pcchStr >= charsNeeded)
712 lstrcpyW(str, indent);
713 str += lstrlenW(indent);
714 lstrcpyW(str, indent);
715 str += lstrlenW(indent);
716 lstrcpyW(str, indent);
717 str += lstrlenW(indent);
720 charsNeeded += noticeTextLen;
721 if (str && *pcchStr >= charsNeeded)
723 memcpy(str, noticeText, noticeTextLen * sizeof(WCHAR));
724 str += noticeTextLen;
726 charsNeeded += lstrlenW(notice->pszDisplayText);
727 if (str && *pcchStr >= charsNeeded)
729 lstrcpyW(str, notice->pszDisplayText);
730 str += lstrlenW(notice->pszDisplayText);
732 charsNeeded += sepLen;
733 if (str && *pcchStr >= charsNeeded)
735 lstrcpyW(str, sep);
736 str += sepLen;
739 LocalFree(notice);
740 if (!str)
741 *pcchStr = charsNeeded;
742 else if (*pcchStr < charsNeeded)
744 *pcchStr = charsNeeded;
745 SetLastError(ERROR_MORE_DATA);
746 ret = FALSE;
748 else
749 *pcchStr = charsNeeded;
751 return ret;
754 /***********************************************************************
755 * FormatVerisignExtension (CRYPTDLG.@)
757 BOOL WINAPI FormatVerisignExtension(DWORD dwCertEncodingType,
758 DWORD dwFormatType, DWORD dwFormatStrType, void *pFormatStruct,
759 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, void *pbFormat,
760 DWORD *pcbFormat)
762 CERT_POLICIES_INFO *policies;
763 DWORD size;
764 BOOL ret = FALSE;
766 if (!cbEncoded)
768 SetLastError(E_INVALIDARG);
769 return FALSE;
771 if ((ret = CryptDecodeObjectEx(dwCertEncodingType, X509_CERT_POLICIES,
772 pbEncoded, cbEncoded, CRYPT_DECODE_ALLOC_FLAG, NULL, &policies, &size)))
774 DWORD charsNeeded = 1; /* space for NULL terminator */
775 LPCWSTR headingSep, sep;
776 DWORD headingSepLen, sepLen;
777 WCHAR policyNum[11], policyQualifierNum[11];
778 LPWSTR certPolicy, policyId, policyQualifierInfo, policyQualifierId;
779 LPWSTR cps, userNotice, qualifier;
780 DWORD certPolicyLen, policyIdLen, policyQualifierInfoLen;
781 DWORD policyQualifierIdLen, cpsLen, userNoticeLen, qualifierLen;
782 DWORD i;
783 LPWSTR str = pbFormat;
785 certPolicyLen = LoadStringW(hInstance, IDS_CERT_POLICY,
786 (LPWSTR)&certPolicy, 0);
787 policyIdLen = LoadStringW(hInstance, IDS_POLICY_ID, (LPWSTR)&policyId,
789 policyQualifierInfoLen = LoadStringW(hInstance,
790 IDS_POLICY_QUALIFIER_INFO, (LPWSTR)&policyQualifierInfo, 0);
791 policyQualifierIdLen = LoadStringW(hInstance, IDS_POLICY_QUALIFIER_ID,
792 (LPWSTR)&policyQualifierId, 0);
793 cpsLen = LoadStringW(hInstance, IDS_CPS, (LPWSTR)&cps, 0);
794 userNoticeLen = LoadStringW(hInstance, IDS_USER_NOTICE,
795 (LPWSTR)&userNotice, 0);
796 qualifierLen = LoadStringW(hInstance, IDS_QUALIFIER,
797 (LPWSTR)&qualifier, 0);
798 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
800 headingSep = L":\r\n";
801 sep = L"\r\n";
803 else
805 headingSep = L": ";
806 sep = L", ";
808 sepLen = lstrlenW(sep);
809 headingSepLen = lstrlenW(headingSep);
811 for (i = 0; ret && i < policies->cPolicyInfo; i++)
813 CERT_POLICY_INFO *policy = &policies->rgPolicyInfo[i];
814 DWORD j;
815 LPCSTR src;
817 charsNeeded += 1; /* '['*/
818 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
819 *str++ = '[';
820 swprintf(policyNum, ARRAY_SIZE(policyNum), L"%d", i + 1);
821 charsNeeded += lstrlenW(policyNum);
822 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
824 lstrcpyW(str, policyNum);
825 str += lstrlenW(policyNum);
827 charsNeeded += 1; /* ']'*/
828 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
829 *str++ = ']';
830 charsNeeded += certPolicyLen;
831 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
833 memcpy(str, certPolicy, certPolicyLen * sizeof(WCHAR));
834 str += certPolicyLen;
836 charsNeeded += headingSepLen;
837 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
839 lstrcpyW(str, headingSep);
840 str += headingSepLen;
842 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
844 charsNeeded += lstrlenW(indent);
845 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
847 lstrcpyW(str, indent);
848 str += lstrlenW(indent);
851 charsNeeded += policyIdLen;
852 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
854 memcpy(str, policyId, policyIdLen * sizeof(WCHAR));
855 str += policyIdLen;
857 charsNeeded += strlen(policy->pszPolicyIdentifier);
858 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
860 for (src = policy->pszPolicyIdentifier; src && *src;
861 src++, str++)
862 *str = *src;
864 charsNeeded += sepLen;
865 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
867 lstrcpyW(str, sep);
868 str += sepLen;
870 for (j = 0; j < policy->cPolicyQualifier; j++)
872 CERT_POLICY_QUALIFIER_INFO *qualifierInfo =
873 &policy->rgPolicyQualifier[j];
874 DWORD sizeRemaining;
876 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
878 charsNeeded += lstrlenW(indent);
879 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
881 lstrcpyW(str, indent);
882 str += lstrlenW(indent);
885 charsNeeded += 1; /* '['*/
886 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
887 *str++ = '[';
888 charsNeeded += lstrlenW(policyNum);
889 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
891 lstrcpyW(str, policyNum);
892 str += lstrlenW(policyNum);
894 charsNeeded += 1; /* ','*/
895 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
896 *str++ = ',';
897 swprintf(policyQualifierNum, ARRAY_SIZE(policyQualifierNum), L"%d", j + 1);
898 charsNeeded += lstrlenW(policyQualifierNum);
899 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
901 lstrcpyW(str, policyQualifierNum);
902 str += lstrlenW(policyQualifierNum);
904 charsNeeded += 1; /* ']'*/
905 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
906 *str++ = ']';
907 charsNeeded += policyQualifierInfoLen;
908 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
910 memcpy(str, policyQualifierInfo,
911 policyQualifierInfoLen * sizeof(WCHAR));
912 str += policyQualifierInfoLen;
914 charsNeeded += headingSepLen;
915 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
917 lstrcpyW(str, headingSep);
918 str += headingSepLen;
920 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
922 charsNeeded += 2 * lstrlenW(indent);
923 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
925 lstrcpyW(str, indent);
926 str += lstrlenW(indent);
927 lstrcpyW(str, indent);
928 str += lstrlenW(indent);
931 charsNeeded += policyQualifierIdLen;
932 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
934 memcpy(str, policyQualifierId,
935 policyQualifierIdLen * sizeof(WCHAR));
936 str += policyQualifierIdLen;
938 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
939 szOID_PKIX_POLICY_QUALIFIER_CPS))
941 charsNeeded += cpsLen;
942 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
944 memcpy(str, cps, cpsLen * sizeof(WCHAR));
945 str += cpsLen;
948 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
949 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
951 charsNeeded += userNoticeLen;
952 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
954 memcpy(str, userNotice, userNoticeLen * sizeof(WCHAR));
955 str += userNoticeLen;
958 else
960 charsNeeded += strlen(qualifierInfo->pszPolicyQualifierId);
961 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
963 for (src = qualifierInfo->pszPolicyQualifierId;
964 src && *src; src++, str++)
965 *str = *src;
968 charsNeeded += sepLen;
969 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
971 lstrcpyW(str, sep);
972 str += sepLen;
974 if (dwFormatStrType & CRYPT_FORMAT_STR_MULTI_LINE)
976 charsNeeded += 2 * lstrlenW(indent);
977 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
979 lstrcpyW(str, indent);
980 str += lstrlenW(indent);
981 lstrcpyW(str, indent);
982 str += lstrlenW(indent);
985 charsNeeded += qualifierLen;
986 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
988 memcpy(str, qualifier, qualifierLen * sizeof(WCHAR));
989 str += qualifierLen;
991 charsNeeded += headingSepLen;
992 if (str && *pcbFormat >= charsNeeded * sizeof(WCHAR))
994 lstrcpyW(str, headingSep);
995 str += headingSepLen;
997 /* This if block is deliberately redundant with the same if
998 * block above, in order to keep the code more readable (the
999 * code flow follows the order in which the strings are output.)
1001 if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1002 szOID_PKIX_POLICY_QUALIFIER_CPS))
1004 if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1006 /* Insufficient space, determine how much is needed. */
1007 ret = CRYPT_FormatCPS(dwCertEncodingType,
1008 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1009 qualifierInfo->Qualifier.cbData, NULL, &size);
1010 if (ret)
1011 charsNeeded += size - 1;
1013 else
1015 sizeRemaining = *pcbFormat / sizeof(WCHAR);
1016 sizeRemaining -= str - (LPWSTR)pbFormat;
1017 ret = CRYPT_FormatCPS(dwCertEncodingType,
1018 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1019 qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1020 if (ret || GetLastError() == ERROR_MORE_DATA)
1022 charsNeeded += sizeRemaining - 1;
1023 str += sizeRemaining - 1;
1027 else if (!strcmp(qualifierInfo->pszPolicyQualifierId,
1028 szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
1030 if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1032 /* Insufficient space, determine how much is needed. */
1033 ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1034 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1035 qualifierInfo->Qualifier.cbData, NULL, &size);
1036 if (ret)
1037 charsNeeded += size - 1;
1039 else
1041 sizeRemaining = *pcbFormat / sizeof(WCHAR);
1042 sizeRemaining -= str - (LPWSTR)pbFormat;
1043 ret = CRYPT_FormatUserNotice(dwCertEncodingType,
1044 dwFormatStrType, qualifierInfo->Qualifier.pbData,
1045 qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1046 if (ret || GetLastError() == ERROR_MORE_DATA)
1048 charsNeeded += sizeRemaining - 1;
1049 str += sizeRemaining - 1;
1053 else
1055 if (!str || *pcbFormat < charsNeeded * sizeof(WCHAR))
1057 /* Insufficient space, determine how much is needed. */
1058 ret = CRYPT_FormatHexString(
1059 qualifierInfo->Qualifier.pbData,
1060 qualifierInfo->Qualifier.cbData, NULL, &size);
1061 if (ret)
1062 charsNeeded += size - 1;
1064 else
1066 sizeRemaining = *pcbFormat / sizeof(WCHAR);
1067 sizeRemaining -= str - (LPWSTR)pbFormat;
1068 ret = CRYPT_FormatHexString(
1069 qualifierInfo->Qualifier.pbData,
1070 qualifierInfo->Qualifier.cbData, str, &sizeRemaining);
1071 if (ret || GetLastError() == ERROR_MORE_DATA)
1073 charsNeeded += sizeRemaining - 1;
1074 str += sizeRemaining - 1;
1080 LocalFree(policies);
1081 if (ret)
1083 if (!pbFormat)
1084 *pcbFormat = charsNeeded * sizeof(WCHAR);
1085 else if (*pcbFormat < charsNeeded * sizeof(WCHAR))
1087 *pcbFormat = charsNeeded * sizeof(WCHAR);
1088 SetLastError(ERROR_MORE_DATA);
1089 ret = FALSE;
1091 else
1092 *pcbFormat = charsNeeded * sizeof(WCHAR);
1095 return ret;
1098 #define szOID_MICROSOFT_Encryption_Key_Preference "1.3.6.1.4.1.311.16.4"
1100 /***********************************************************************
1101 * DllRegisterServer (CRYPTDLG.@)
1103 HRESULT WINAPI DllRegisterServer(void)
1105 static WCHAR cryptdlg[] = L"cryptdlg.dll";
1106 static WCHAR wintrust[] = L"wintrust.dll";
1107 static WCHAR certTrustInit[] = L"CertTrustInit";
1108 static WCHAR wintrustCertificateTrust[] = L"WintrustCertificateTrust";
1109 static WCHAR certTrustCertPolicy[] = L"CertTrustCertPolicy";
1110 static WCHAR certTrustFinalPolicy[] = L"CertTrustFinalPolicy";
1111 static WCHAR certTrustCleanup[] = L"CertTrustCleanup";
1112 CRYPT_REGISTER_ACTIONID reg;
1113 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1114 HRESULT hr = S_OK;
1116 memset(&reg, 0, sizeof(reg));
1117 reg.cbStruct = sizeof(reg);
1118 reg.sInitProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1119 reg.sInitProvider.pwszDLLName = cryptdlg;
1120 reg.sInitProvider.pwszFunctionName = certTrustInit;
1121 reg.sCertificateProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1122 reg.sCertificateProvider.pwszDLLName = wintrust;
1123 reg.sCertificateProvider.pwszFunctionName = wintrustCertificateTrust;
1124 reg.sCertificatePolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1125 reg.sCertificatePolicyProvider.pwszDLLName = cryptdlg;
1126 reg.sCertificatePolicyProvider.pwszFunctionName = certTrustCertPolicy;
1127 reg.sFinalPolicyProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1128 reg.sFinalPolicyProvider.pwszDLLName = cryptdlg;
1129 reg.sFinalPolicyProvider.pwszFunctionName = certTrustFinalPolicy;
1130 reg.sCleanupProvider.cbStruct = sizeof(CRYPT_TRUST_REG_ENTRY);
1131 reg.sCleanupProvider.pwszDLLName = cryptdlg;
1132 reg.sCleanupProvider.pwszFunctionName = certTrustCleanup;
1133 if (!WintrustAddActionID(&guid, WT_ADD_ACTION_ID_RET_RESULT_FLAG, &reg))
1134 hr = GetLastError();
1135 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1136 "1.3.6.1.4.1.311.16.1.1", L"cryptdlg.dll", "EncodeAttrSequence");
1137 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1138 szOID_MICROSOFT_Encryption_Key_Preference, L"cryptdlg.dll", "EncodeRecipientID");
1139 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1140 "1.3.6.1.4.1.311.16.1.1", L"cryptdlg.dll", "DecodeAttrSequence");
1141 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1142 szOID_MICROSOFT_Encryption_Key_Preference, L"cryptdlg.dll", "DecodeRecipientID");
1143 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1144 szOID_PKIX_KP_EMAIL_PROTECTION, L"cryptdlg.dll", "FormatPKIXEmailProtection");
1145 CryptRegisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1146 szOID_CERT_POLICIES, L"cryptdlg.dll", "FormatVerisignExtension");
1147 return hr;
1150 /***********************************************************************
1151 * DllUnregisterServer (CRYPTDLG.@)
1153 HRESULT WINAPI DllUnregisterServer(void)
1155 GUID guid = CERT_CERTIFICATE_ACTION_VERIFY;
1157 WintrustRemoveActionID(&guid);
1158 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1159 "1.3.6.1.4.1.311.16.1.1");
1160 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_ENCODE_OBJECT_FUNC,
1161 szOID_MICROSOFT_Encryption_Key_Preference);
1162 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1163 "1.3.6.1.4.1.311.16.1.1");
1164 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_DECODE_OBJECT_FUNC,
1165 szOID_MICROSOFT_Encryption_Key_Preference);
1166 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1167 szOID_PKIX_KP_EMAIL_PROTECTION);
1168 CryptUnregisterOIDFunction(X509_ASN_ENCODING, CRYPT_OID_FORMAT_OBJECT_FUNC,
1169 szOID_CERT_POLICIES);
1170 return S_OK;